From c6ee22c3d77ebc1f3dbe3414c172691c39932b35 Mon Sep 17 00:00:00 2001 From: Maximilian Attems Date: Sun, 6 Jan 2008 23:52:40 +0000 Subject: [PATCH] Add and enable ath5k.patch wireless driver for Atheros 5xxx cards. tested by Stephen Gran svn path=/dists/trunk/linux-2.6/; revision=10061 --- debian/changelog | 3 +- debian/config/config | 1 + debian/patches/features/ath5k.patch | 17466 +++++++++++++++++++++++ debian/patches/series/1~experimental.1 | 1 + 4 files changed, 17470 insertions(+), 1 deletion(-) create mode 100644 debian/patches/features/ath5k.patch diff --git a/debian/changelog b/debian/changelog index 7cf67f91c..a86aea1ae 100644 --- a/debian/changelog +++ b/debian/changelog @@ -31,6 +31,7 @@ linux-2.6 (2.6.24~rc7-1~experimental.1) UNRELEASED; urgency=low * [amd64, i386] Enable CPU_IDLE for software-controlled idle pm. * [amd64, i386] Enable IT8712F_WDT, FB_EFI. * Add and enable at76.patch wireless driver for Atmel USB cards. + * Add and enable ath5k.patch wireless driver for Atheros 5xxx cards. [ Bastian Blank ] * [amd64, i386]: Set kernel architecture to x86. @@ -51,7 +52,7 @@ linux-2.6 (2.6.24~rc7-1~experimental.1) UNRELEASED; urgency=low [ Frederik Schüler ] * Add GFS2 locking symbols export patch. - -- maximilian attems Mon, 07 Jan 2008 00:46:11 +0100 + -- maximilian attems Mon, 07 Jan 2008 00:49:41 +0100 linux-2.6 (2.6.23-1~experimental.1) UNRELEASED; urgency=low diff --git a/debian/config/config b/debian/config/config index bcb319bb4..1fc5fbb14 100644 --- a/debian/config/config +++ b/debian/config/config @@ -939,6 +939,7 @@ CONFIG_P54_COMMON=m CONFIG_P54_USB=m CONFIG_P54_PCI=m CONFIG_USB_ATMEL=m +CONFIG_ATH5K=m CONFIG_IWLWIFI=y # CONFIG_IWLWIFI_DEBUG is not set CONFIG_IWLWIFI_SENSITIVITY=y diff --git a/debian/patches/features/ath5k.patch b/debian/patches/features/ath5k.patch new file mode 100644 index 000000000..d626b8c67 --- /dev/null +++ b/debian/patches/features/ath5k.patch @@ -0,0 +1,17466 @@ +commit a09d1e8fd6aaea60578d2cee852ec476da3e6b66 +Author: Nick Kossifidis +Date: Sun Dec 16 03:11:48 2007 +0200 + + ath5k: Minor cleanups + + * Call set_txpower_limit directly + * Remove "partialy supported" mesage + + Changes-licensed-under: ISC + Signed-off-by: Nick Kossifidis + Signed-off-by: John W. Linville + +commit b46b4130750fd0e37c677a12382ec679845b07ff +Author: Nick Kossifidis +Date: Sun Dec 16 03:10:27 2007 +0200 + + ath5k: Update initvals.c from recent regdumps + + * Update initvals.c from recent regdumps. + * RF5413 and later have a different base address for pcdac table so update reg.h. + * Remove static pcdac tables, we'll come up with a better solution (works for me). + + Changes-licensed-under: ISC + Signed-off-by: Nick Kossifidis + Signed-off-by: John W. Linville + +commit 8d91d68029b494bbcc242633e5ce3fcfbcf10f0a +Author: Nick Kossifidis +Date: Sun Dec 16 03:07:33 2007 +0200 + + ath5k: Fix support for RF2112A based b/g only cards + + * Fix support for 2112A based b/g only cards (turbog needs review). + * Enable a part of rf5112_rfregs code that commits x_gain for testing. + + Thanx to John who gave me his b/g card ;-) + + Changes-licensed-under: ISC + Signed-off-by: Nick Kossifidis + Signed-off-by: John W. Linville + +commit 3077d9ecc53b14d946cedd87317a5163e2a66dc9 +Author: Nick Kossifidis +Date: Sun Dec 16 03:03:01 2007 +0200 + + ath5k: Skip non-data queues for 5210 for now + + * Skip non-data tx queues on 5210, don't return -EINVAL since it breaks ifup. This is a temp mesure until we review tx queues etc in base.c. Note that 5210 will wake up and may even scan but needs some more work. + + Changes-licensed-under: ISC + Signed-off-by: Nick Kossifidis + Signed-off-by: John W. Linville + +commit 528f1b9fa5d46d35ee076ec41860a74fb4d0a801 +Author: Nick Kossifidis +Date: Sun Dec 16 03:01:04 2007 +0200 + + ath5k: Reorder reset function to match regdumps + + * Modify reset function to match regdumps, we still have some things to fix. + + Changes-licensed-under: ISC + Signed-off-by: Nick Kossifidis + Signed-off-by: John W. Linville + +commit 41cb0aa95ce0fcade56d267f3804284092360d24 +Author: Nick Kossifidis +Date: Sun Dec 16 02:58:57 2007 +0200 + + ath5k: Implement per-queue interrupts + + * Implement per-queue interrupt handling. For now treat TXDESC and TXEOL as INT_TX so we can handle them in base.c. + + Changes-licensed-under: ISC + Signed-off-by: Nick Kossifidis + Signed-off-by: John W. Linville + +commit 8fb46b91e6ed72ccfefa6c3f4850b9b58c1463d1 +Author: Nick Kossifidis +Date: Sun Dec 16 02:55:52 2007 +0200 + + ath5k: Fix diversity + + * Fix diversity support + + We have to write all antenna information on AR5K_PHY_ANT_SWITCH_TABLE if antenna mode is not fixed. + + Changes-licensed-under: ISC + Signed-off-by: Nick Kossifidis + Signed-off-by: John W. Linville + +commit b6aa459673f61c1288acebec013905a7256f3a5a +Author: Nick Kossifidis +Date: Sun Dec 16 02:53:18 2007 +0200 + + ath5k: Fix nic_wakeup for 5210 + + * Reset PCI after chip reset for 5210 at nic_wakeup. This fixes the system hang during 5210 attach. + + Changes-licensed-under: ISC + Signed-off-by: Nick Kossifidis + Signed-off-by: John W. Linville + +commit a7da8f9d4b256c6014edfe63079c4220e9430e68 +Author: Nick Kossifidis +Date: Sun Dec 16 02:47:55 2007 +0200 + + ath5k: Minor fixes inside base.c + + * Reorder some inline functions to silence compiler + * Stop passing 0xff.. for txpower during tx descriptor setup. Txpower is written in hw in 0.5dbm steps. + + Changes-licensed-under: 3-clause-BSD + Signed-off-by: Nick Kossifidis + Signed-off-by: John W. Linville + +commit 8e685b758aea2c0e82f41813690e229543af9622 +Author: Bruno Randolf +Date: Fri Dec 14 18:48:57 2007 +0900 + + ath5k: avoid zero rates + + setting up tx descriptors with a rate of zero will put the HW into a mode where + it continously sends noise on the channel, thus blocking the whole channel. + since it is important to avoid this situation, add a WARN_ON in these cases, + even if we hope to never get bad rates from the rate control module. + + Changes-licensed-under: ISC + Signed-off-by: Bruno Randolf + Signed-off-by: John W. Linville + +commit fc0374171b9f750790b88b795aac3becf4524a92 +Author: Bruno Randolf +Date: Mon Dec 10 19:21:17 2007 +0900 + + ath5k: add debugfs entries for registers, tsf, beacon, reset + + i resend this patch to address jiris comments and with some small improvements. + this hopefully last version now returns NULL instead of 0 in reg_start() and + reg_next(). + + 'registers' prints the name and value of some registers. this should be adapted + to what we actually need later and is supposed to replace the hwdump facility i + removed in my earlier debugging changes. + + 'tsf' prints the current HW TSF. writing "reset" into the file will reset the + TSF. + + 'beacon' shows beacon relevant registers. it is good for watching the beacon + timers with something like "watch -n0 cat /dbg/ath5k/phy0/beacon". writing + "enable" into the file will try to enable beacons by setting the flag + AR5K_BEACON_ENABLE, "disable" will disable that bit. + + 'reset' can be used to trigger a HW reset, by writing "reset" into it. + + Changes-licensed-under: GPL + + Signed-off-by: Bruno Randolf + Acked-by: Luis R. Rodriguez + Acked-by: Jiri Slaby + Signed-off-by: John W. Linville + +commit 73a8222564a86bf9e38470dbfe44a4826c5d3a0a +Author: Dave Young +Date: Fri Dec 7 10:12:58 2007 +0800 + + ath5k: fix 'static inline' build issues + + 2.6.24-rc4-mm1 build failed at drivers/net/wireless/ath5k/base.c for some inline functions like this: + drivers/net/wireless/ath5k/base.c:292: sorry, unimplemented: inlining failed in call to 'ath5k_extend_tsf': function body not available + + fix it with adjust the order of inline function body. + + Signed-off-by: Dave Young + Signed-off-by: John W. Linville + +commit 1a54daf7f3963bd1c04cc28500f48280d6c8dcf3 +Author: Francesco Gringoli +Date: Thu Nov 29 21:39:51 2007 +0100 + + ath5k: fix rx filters set up + + Hello, + + This simple patch adds pcap compatibility to ath5k code. In base.c + rx_filters are never refreshed when the state of the interface + changes. Now tcpdump captures everything in monitor mode when iface + is set to promisc. + + Signed-off-by: Francesco Gringoli + Signed-off-by: John W. Linville + +commit 04f840943842a4870fd1ddd735140dd0ba73f984 +Author: Bruno Randolf +Date: Fri Nov 30 11:26:37 2007 +0900 + + ath5k: export signal quality values + + store the last noise floor in ath5k_hw and report signal, noise and link + quality values to mac80211, which in turn makes them show up in iwconfig. + + ath5k.h, phy.c: + Changes-licensed-under: ISC + + base.c: + Changes-licensed-under: 3-clause-BSD + + Signed-off-by: Bruno Randolf + Acked-by: Nick Kossifidis + Acked-by: Luis R. Rodriguez + Signed-off-by: John W. Linville + +commit 8003ffec8e1dca7224fd9e2a8adf8e887197c32c +Author: Bruno Randolf +Date: Fri Nov 30 11:26:36 2007 +0900 + + ath5k: full noise calibration also for rf511x + + also perform full noise calibration in ath5k_hw_rf511x_calibrate() instead of + just writing the bit. + + Changes-licensed-under: ISC + Signed-off-by: Bruno Randolf + Acked-by: Nick Kossifidis + Acked-by: Luis R. Rodriguez + Signed-off-by: John W. Linville + +commit 335223282459681668ebb0247530020e777d84f5 +Author: Bruno Randolf +Date: Fri Nov 30 11:26:35 2007 +0900 + + ath5k: fix noise floor calibration + + fix noise floor calibration by applying AR5K_PHY_NF_AVAL after + AR5K_PHY_NF_RVAL. that way the XORed mask and value have the same length and + we get a reasonable noise value in -dBm. + + move duplicate noise floor calibration code from two different places into one + function ath5k_hw_noise_floor_calibration(). + + the check for accepted noise_floor values (<= AR5K_TUNE_NOISE_FLOOR) should + only happen when we have an active reading and a converted value, so move it up + into the first if. + + Changes-licensed-under: ISC + Signed-off-by: Bruno Randolf + Acked-by: Nick Kossifidis + Acked-by: Luis R. Rodriguez + Signed-off-by: John W. Linville + +commit 93be8761d08247a45a095b4d9ebdf16ba0c66b68 +Author: Bruno Randolf +Date: Fri Nov 30 11:26:34 2007 +0900 + + ath5k: more consistent debugging + + * move all debugging functions to new files debug.c and debug.h. + + * consistently use ATH5K_DEBUG instead of AR_DEBUG and AR5K_DEBUG defines. + ATH5K_DEBUG can be set from outside the Makefile via KCFLAGS. + + * rename DPRINTF to ATH5K_DBG to be consistent with the other logging + functions. ATH5K_DBG honors the debug level set on module load or by debugfs + and is limited by net_ratelimit(). another define ATH5K_DBG_UNLIMIT can be + used specifically when we do not want the output to be rate limited. + + * move all instances where the debugging output was controlled by additional + defines (ATH_DEBUG_MODES, ATH_DUMP_SKB) to use the debug level too. + + * make ATH5K_TRACE honor the debug level as well. + + * remove ath5k_hw_dump_state(). + + * rename all debugging functions to ath5k_debug_xxx. these are static inline {} + when ATH5K_DEBUG is 0. + + * make ath5k_debug_dump_skb distinguish between RX and TX, so we can choose + wether we want to see RX or TX packets. also prepend the "phyX" name. + + * added debugfs entry (ath5k/phyX/debug) to control the debug level for each + device. + + * add kerneldoc for debugging levels. + + base.[ch]: + Changes-licensed-under: 3-clause-BSD + + hw.c, ath5k.h, phy.c: + Changes-licensed-under: ISC + + debug.[ch]: + Changes-licensed-under: GPL + + Signed-off-by: Bruno Randolf + Acked-by: Luis R. Rodriguez + Acked-by: Nick Kossifidis + Signed-off-by: John W. Linville + +commit 07700ba6c1fe652f0c0b9ad5b9d6525664740cf4 +Author: Bruno Randolf +Date: Fri Nov 30 11:26:33 2007 +0900 + + ath5k: more consistent info and error logging + + added new macros ATH5K_INFO, ATH5K_WARN and ATH5K_ERR for more consistent + logging inside ath5k. they prepend "ath5k phyX:" to all lines so we can + distinguish between different cards in multi-card setups. ATH5K_WARN and + ATH5K_ERR use net_ratelimit(), so they can be used anywhere without having to + check net_ratelimit() seperately. + + the macros get a reference to sc, so we can automatically add additional + information: right now it is used to get the phy name, but having this in one + central place gived us the flexibility to switch to dev_info/warn/... or others + instead too. i think using "phyX" makes the output most readable and easier to + match with the output from mac80211. in cases where we don't have sc available + we still use ATH5K_PRINTF. + + changed all printk, most dev_info and most AR5K_PRINTF lines to use these + macros instead. deleted AR5K_PRINT because it's easy to use ATH5K_PRINTF + instead. + + for base.c + Changes-licensed-under: 3-clause-BSD + + for all others... + Changes-licensed-under: ISC + + Signed-off-by: Bruno Randolf + Acked-by: Luis R. Rodriguez + Acked-by: Nick Kossifidis + Signed-off-by: John W. Linville + +commit fd5be00a58244ffd045c5b5fa1eb4e2279d8c5b3 +Author: Nick Kossifidis +Date: Wed Nov 14 19:49:49 2007 +0200 + + ath5k: Add myself to MAINTAINERS and rewrite module description on Kconfig + + *Add better description in Kconfig + *Add myself to MAINTAINERS + + Signed-off-by: Nick Kossifidis + Signed-off-by: John W. Linville + +commit e856715ffedc6b73c546d5f472e4cd876703091d +Author: Nick Kossifidis +Date: Wed Nov 14 18:23:59 2007 +0200 + + ath5k: Fix calinterval and add more RF5413/5414 inivals + + *Fix calinterval to be 10secs for now. + *Add some more initial settings i got for RF5413/5414 + + Still no fix for poor 802.11a performance (probably tx power related) ;-( + Leave it as "partialy supported" until this issue is resolved... + + for base.c + Changes-licensed-under: 3-clause-BSD + + for all others... + Changes-licensed-under: ISC + + Signed-off-by: Nick Kossifidis + Signed-off-by: John W. Linville + +commit 838904d60eeab7d4206451a5503d80a0ef8a2884 +Author: Nick Kossifidis +Date: Wed Nov 14 18:17:37 2007 +0200 + + ath5k: Add RF5413/5414 support + + *Add support for RF5413/5414 single-chip solutions + + This needs testing (also on 5424/2424) before we declare that's fully supported. + It works for me and the RF5413 i got ;-) + + Changes-licensed-under: ISC + Signed-Off-by: Nick Kossifidis + + Signed-off-by: John W. Linville + +commit 93e5669cf00f5323f65303c4ef096e0c8919d292 +Author: Nick Kossifidis +Date: Wed Nov 14 18:14:40 2007 +0200 + + ath5k: Fix device info reporting + + *Fix device info code + + Changes-licensed-under: 3-clause-BSD + Signed-Off-by: Nick Kossifidis + + Signed-off-by: John W. Linville + +commit 41bf49ef5be651dfe06e597389a0237ce5298d20 +Author: Nick Kossifidis +Date: Wed Nov 14 18:11:40 2007 +0200 + + ath5k: Fix another faulty channel flag check + + *Fix another faulty channel flags check + + Don't check channel->val against CHANNEL_A/B/G flags because they have common flags set + eg. doing AND between CHANNEL_A and CHANNEL_G always returns true because they have + CHANNEL_OFDM, same goes for CHANNEL_B and CHANNEL_G that have CHANNEL_2GHZ in common. + + Instead check against CHANNEL_CCK/OFDM/2GHZ/5GHZ... + + Changes-licensed-under: ISC + Signed-off-by: Nick Kossifidis + Signed-off-by: John W. Linville + +commit 1ce29f8277f8d9e44995f81e5986361fbdd87615 +Author: Luis R. Rodriguez +Date: Fri Nov 2 16:46:38 2007 -0400 + + ath5k: Set ACK to user lower bit rates + + Sorry, forgot this last hunk in my patch series... This applies on top + of my series. + + This sets the ACK bitrate to the lower rates. Without this I get + about 70% packet loss when using the 11M rate. Not sure exactly what rates + this is setting the HW to send the ACKs in but it sure does help. + + I'll be poking more with this and trying to fix rates for g. We'll figure + this out ;) + + Note: our higher rates are still pretty unusable, something is still + wrong with those. + + Changes to base.c + Changes-licensed-under: 3-clause-BSD + + Changes to ath5k.h, hw.c + Changes-licensed-under: ISC + + Signed-off-by: Luis R. Rodriguez + Signed-off-by: John W. Linville + +commit 01584d2b0e88eea833c378d4da292f8a7e2a4a49 +Author: Luis R. Rodriguez +Date: Thu Nov 1 23:11:31 2007 -0400 + + ath5k: Add documentation for struct ath5k_rate + + This adds documentation for struct ath5k_rate. This also removes + some unused variables, lp_ack_duration and sp_ack_duration which + are simply unnecessary. + + We're now just missing information about rate hw values: + + 3-5 + 16 + 17-23 + 28-32 + + If anyone knows what those are, please let us know. + + Changes to ath5k.h + Changes-licensed-under: ISC + + Signed-off-by: Luis R. Rodriguez + Signed-off-by: John W. Linville + +commit 2e046652afab548b98ceee3043173e17cf7f7145 +Author: Luis R. Rodriguez +Date: Thu Nov 1 17:55:53 2007 -0400 + + ath5k: Clear up settings of AR5K_RSSI_THR register settings + + Clear up settings of AR5K_RSSI_THR register settings. These are split between + AR5K_TUNE_BMISS_THRES and AR5K_TUNE_RSSI_THRES. + + Changes to ath5k.h, hw.c + Changes-licensed-under: ISC + + Signed-off-by: Luis R. Rodriguez + Signed-off-by: John W. Linville + +commit 9b83892f2c0a16f087dc45d7b8a6353c69c0fcfb +Author: Luis R. Rodriguez +Date: Thu Nov 1 17:53:18 2007 -0400 + + ath5k: Move OFDM timings into a helper routine + + This move the OFDM timings on ath5k_hw_reset() onto a helper, + ath5k_hw_write_ofdm_timings() to make code cleaner. + + Changes to ath5k.h, hw.c + Changes-licensed-under: ISC + + Signed-off-by: Luis R. Rodriguez + Signed-off-by: John W. Linville + +commit f75a5a95a1fc5287143afbeb99c0e238ef4cbd79 +Author: Luis R. Rodriguez +Date: Thu Nov 1 00:38:16 2007 -0400 + + ath5k: Fix clock on OFDM timing computation + + We were setting the clock to the turbo sampling rate always, lets fix this + for plain OFDM sampling rate at 40 MHz. I believe this tunes the PLL to + the desired frequency, by setting the mantissa and the exponent. + + Changes to hw.c + Changes-licensed-under: ISC + + Signed-off-by: Luis R. Rodriguez + Signed-off-by: John W. Linville + +commit 6f95039ebee8f0d79b940f06bcde1e0711334a83 +Author: Luis R. Rodriguez +Date: Thu Nov 1 17:50:30 2007 -0400 + + ath5k: Clean up ath5k rate duration settings + + Replace ath5k's rate duration computations for one using + mac80211's internals. Another consideration here is to simply + remove these and put them into initval values. They seem to be + static values based only on mode. We can do this later though once + we can physically confirm by trial and error these are indeed just + used for ACK timeout. The next puzzle is figuring out which registers + are actually setting the control rates. + + Changes to ath5k.h, hw.c + Changes-licensed-under: ISC + + Signed-off-by: Luis R. Rodriguez + Signed-off-by: John W. Linville + +commit 012198ddffdb66120528823c73318379b6a59a77 +Author: Luis R. Rodriguez +Date: Thu Nov 1 00:35:20 2007 -0400 + + ath5k: Remove opaque pointers from ath5k_hw_attach() + + Since we don't have a HAL anymore there is no point to use opaque pointers + in ath5k_hw_attach(). This will also give hw.c access to ath5k_softc + structure now when needed. While we're at it, lets also give some ah_sh + a reasonable name, ah_sh --> ah_iobase. + + Changes to base.c + Changes-licensed-under: 3-clause-BSD + + Changes to ath5k.h, hw.c + Changes-licensed-under: ISC + + Signed-off-by: Luis R. Rodriguez + Signed-off-by: John W. Linville + +commit e23be3f08baf10d7ded7eab076b68dc6696d230e +Author: Luis R. Rodriguez +Date: Thu Nov 1 00:34:24 2007 -0400 + + ath5k: Fix initval/eeprom/IQ calibration for G mode + + ath5k_hw_reset() was always setting initval and eeprom settings for B mode + when using G mode. This is because a B channel was being picked up first. We + should first instead check for G channel. This patch also introduces a + driver_mode variable which should be used instead for determing + more reliably the mode we're in. + + This fixing another bug where IQ calibration was not being run for + G mode as CHANNEL_B was always being picked up first. We now instead + check for driver_mode. + + Similar problem was occurring in ath5k_hw_rf5112_rfregs(), we fix this + there too. + + Changes to phy.c, hw.c + Changes-licensed-under: ISC + + Signed-off-by: Luis R. Rodriguez + Signed-off-by: John W. Linville + +commit 45cededd2df27b8c2a4b7c37a02c7f3830d1d243 +Author: Ulrich Meis +Date: Tue Oct 30 22:20:56 2007 +0100 + + ath5k: 4word tx descriptor setup doesn't set BUF_LEN + + This line got lost when the descriptor setup and fill functions were + merged. Applies ontop of Nick's patches. + + Changes-licensed-under: ISC + Signed-off-by: Ulrich Meis + Signed-off-by: John W. Linville + +commit 168048516dbf42ca2deb3cd36101f9b76ecdb030 +Author: Nick Kossifidis +Date: Sun Oct 28 02:58:27 2007 +0300 + + ath5k: Remove fill_tx_desc + + fill_tx_desc is used for fast frames operation, since + we don't support fast frames (and since fill_tx_desc + had a bug -thanx to Ulrich Meis for finding that out-) + these functions are not needed (+ they are misleading + because they don't "fill" any tx descriptor). + + I couldn't test this patch much so plz someone ACK it... + + It applies on top of my previous patches (i just thought + that [PATCH 8/7] won't look nice ;-) ). + + Changes-licensed-under: ISC + Signed-off-by: Ulrich Meis + Signed-Off-by: Nick Kossifidis + Signed-off-by: John W. Linville + +commit 7ed69f54e345a9897b0b4617311858303e781aff +Author: Nick Kossifidis +Date: Sun Oct 28 02:44:18 2007 +0300 + + ath5k: Warn on partially supported chips + + *Warn on partially supported chips (eg. 5414/5424) + + These chips need work on PHY part, recently Reyk posted + a workaround so that they can work on 2GHz but i believe + that the problem is related to PHY initialization. Plz + we need help with these... + + I did some tests on a 5414 at 5GHz and it seemed to work + but i didn't test it at 2GHz. + + I'll try to find one of these and play with. + + Changes-licensed-under: ISC + Signed-Off-by: Nick Kossifidis + + Signed-off-by: John W. Linville + +commit 24d2eab68057de8e63d262e84c0ba3a12a69f0c1 +Author: Nick Kossifidis +Date: Sun Oct 28 02:31:13 2007 +0300 + + ath5k: Add PCI IDs for newer chips + + *Add PCI IDs for 5416/5418. + + *Print a message during attach that + these chips are not yet supported. + + for base.c + Changes-licensed-under: 3-clause-BSD + + for ath5k.h + Changes-licensed-under: ISC + + Signed-Off-by: Nick Kossifidis + + Signed-off-by: John W. Linville + +commit d17a1cea1bfc35c735f3ebcf1ef823f06389748d +Author: Nick Kossifidis +Date: Sun Oct 28 02:24:59 2007 +0300 + + athk: Use SREV to identify single-chip solutions + + Use SREV instead of pci id to identify single chip solutions. + + Srev is more accurate info to identify the chip + this makes + it possible to identify some 5424 chips found on thinkpads with + faulty 5212 pci id. + + Changes-licensed-under: ISC + Signed-Off-by: Nick Kossifidis + + Signed-off-by: John W. Linville + +commit 85364fdd0649d1590e9ae18d1961c6861b7b9288 +Author: Nick Kossifidis +Date: Sun Oct 28 02:20:33 2007 +0300 + + ath5k: Add SREV values for newer chips + + * Add new Silicon Revision values (hex values written on chip) to be able to identify them. + + * Give more infos about mac/phy/radio revision during attach. + + for ath5k.h + Changes-licensed-under: ISC + + for base.c + Changes-licensed-under: 3-clause-BSD + + Signed-Off-by: Nick Kossifidis + + Signed-off-by: John W. Linville + +commit 73a0794c3746635652f10bcfe99821b3526163b5 +Author: Nick Kossifidis +Date: Sun Oct 28 02:13:32 2007 +0300 + + ath5k: Remove obsolete sysctl stuff + + Remove sysctl tables. + + We shouldn't use /proc to configure things. + + Changes-licensed-under: 3-clause-BSD + Signed-Off-by: Nick Kossifidis + + Signed-off-by: John W. Linville + +commit e05ef94a6f9a5b2c485f552e46e334a2a4d17d85 +Author: Nick Kossifidis +Date: Sun Oct 28 02:06:42 2007 +0300 + + ath5k: Rename some functions + + I've renamed some functions for better maintainability... + + ath5k_mode_init -> ath5k_mode_setup + ath5k_rxbuf_init -> ath5k_rxbuf_setup + Because it's not just initialization + we use + "setup" on the rest of the code (eg. beacon_setup). + + ath5k_tx_bf -> ath5k_txbuf_setup + Obvious + + ath5k_cleanup_txbuf -> ath5k_txbuf_free + Previous name is misleading because someone might + think that it cleans all tx buffers, we use "free" + to declare that it only cleans one given buffer. + + ath5k_tx_draintxq -> ath5k_txq_drainq + ath5k_draintxq -> ath5k_txq_cleanup + Same here ath5k_draintxq seems to refer to only + one queue when in fact it drains all queues, so + we use "cleanup" as above. + + ath5k_tx_cleanup -> ath5k_txq_release + This one doesn't do any cleanup, it just calls + hw_release for each queue. + + ath5k_startrecv -> ath5k_rx_start + ath5k_stoprecv -> ath5k_rx_stop + As above i try to maintain a naming scheme that links + with the sorting i've done. Eg. ath5k_desc for descriptor + related funcions, ath5k_rx/tx for general rx/tx functions, + ath5k_txq for tx queues, ath5k_hw (inside hw.c and rest) for + hw related functions and so on. This helps us track down things + more easily. + + Changes-licensed-under: 3-clause-BSD + Signed-Off-by: Nick Kossifidis + + Signed-off-by: John W. Linville + +commit 4528852951e6ad64171f584f6b685eb802f6293f +Author: Nick Kossifidis +Date: Sun Oct 28 02:04:25 2007 +0300 + + ath5k: Maintain coding style + + * Sort functions in segments like we do on the rest of the code (eg. + hw.c). This improves readability and maintainability. + + * Add myself as module author (a patch for this was submited some time + ago as part of SFLC's changes but wasn't applied) + + * Declare that this driver is or 5xxx chipset series only in + MODULE_SUPPORTED_DEVICE and MODULE_DESCRIPTION. + + Changes-licensed-under: 3-clause-BSD + Signed-Off-by: Nick Kossifidis + + Signed-off-by: John W. Linville + +commit 1f480e2920877d373e2a547cf53509fc513e02a9 +Author: Jiri Slaby +Date: Fri Oct 19 18:57:13 2007 -0400 + + [PATCH] Net: ath5k, minor fixes + + ath5k, minor fixes + + - some -W compiler warnings fixes (signedness) + - make ath_stop static + - add BUG to ath5k_register_mode when passing supported but not filled mode + and move the supported modes check into this function to simplify the + macro + + Signed-off-by: Jiri Slaby + Signed-off-by: John W. Linville + +commit 96a596f082e92fcdf6308b6224104f93e8916394 +Author: John W. Linville +Date: Tue Oct 23 13:41:37 2007 -0400 + + [PATCH] ath5k: undo overzealous hunk of "ath5k: avoid oops when..." + + The first hunk of "ath5k: avoid oops when ah_capabilities.cap_mode not + set" was ill-advised. It can cause its loop to abort prematurely. + + Signed-off-by: John W. Linville + +commit 05a920250b6385c7eb23a94f0532f94dbd4b6160 +Author: Bruno Randolf +Date: Fri Oct 19 23:57:27 2007 +0900 + + [PATCH] ath5k: mac revision fixes + + this are two small fixes: + + 1) actually print the mac revision when we say so + + 2) better check for mac revisions when putting device to sleep: this is + important with newer mac revisions (>=7.8) which will freeze the whole system + when put to sleep + + Signed-off-by: Bruno Randolf + Signed-off-by: John W. Linville + +commit 14ca910b99e3dc5a1082e7e7b13a2957ffe44fe0 +Author: Nick Kossifidis +Date: Fri Oct 19 13:56:19 2007 +0000 + + [PATCH] ath5k: Maintain naming scheme + + Use "ath5k_" instead of "ath_" and "ah" instead of "hal" + + Changes to base.c, base.h + Changes-licensed-under: 3-clause-BSD + + Changes to ath5k.h, hw.c, hw.h, reg.h + Changes-licensed-under: ISC + + Signed-Off-by: Nick Kossifidis + + Signed-off-by: John W. Linville + +commit 34edd82ca97a76b921ac52c99f07dbfe324feaae +Author: mick@ics.forth.gr +Date: Thu Oct 18 00:18:43 2007 +0300 + + [PATCH] ath5k: Clean up unused definitions in base.h + + Get rid of some definitions that are not used anywhere... + + Changes-licensed-under: 3-clause-BSD + + Signed-Off-by: Nick Kossifidis + + Signed-off-by: John W. Linville + +commit 4c367a11d4502a6e54fa64514cee61c67be9b411 +Author: mick@ics.forth.gr +Date: Thu Oct 18 00:17:12 2007 +0300 + + [PATCH] ath5k: Only one tx descriptor per buffer, no need for ATH_TXDESC + + Since we don't (and probably won't) support fast frames we'll have + only one descriptor for each buffer so there is no need for + ATH_TXDESC. + + Changes-licensed-under: 3-clause-BSD + + Signed-Off-by: Nick Kossifidis + + Signed-off-by: John W. Linville + +commit 4472d002f92b4365184acd6d38e4e417afd5b857 +Author: mick@ics.forth.gr +Date: Thu Oct 18 00:13:26 2007 +0300 + + [PATCH] ath5k: Get rid of unused channel list parameters used in binary HAL + + There are some parameters left in the code that were used by binary + HAL to generate the channel list. Since we don't use binary HAL and + channel list is handled differently, they are out. + + Changes to base.c + Changes-licensed-under: 3-clause-BSD + + Changes to ath5k.h, hw.c + Changes-licensed-under: ISC + + Signed-off-by: Nick Kossifidis + Signed-off-by: John W. Linville + +commit 9d0d2389d863cc3ef433e5103bd6d37f7a5bc983 +Author: John W. Linville +Date: Wed Oct 17 15:01:48 2007 -0400 + + [PATCH] ath5k: avoid oops when ah_capabilities.cap_mode not set + + ah_capabilities.cap_mode doesn't get set for some cards, causing the + kernel to oops when these unknown/unsupported cards are inserted. + Add some NULL checks to avoid this. + + Signed-off-by: John W. Linville + +commit 4cdfeb9398897c3969f89a8d32ad7632ead0fc6a +Author: Bruno Randolf +Date: Tue Oct 16 22:20:37 2007 +0900 + + [PATCH] ath5k: better readability for skb dumps + + print "RX " and "TX " in front of hexdump + + Signed-off-by: Bruno Randolf + Acked-by: Luis R. Rodriguez + Signed-off-by: John W. Linville + +commit 75b99ae66c33cfd5664102c2588ebd505577fc7e +Author: Jiri Slaby +Date: Sun Oct 14 10:45:54 2007 -0400 + + [PATCH] Net: ath5k, change set_bit to nonatomic __set_bit + + ath5k, change set_bit to nonatomic __set_bit + + We don't need to have atomic set_bit function, so use __set_bit instead. + + Changes-licensed-under: ISC + Signed-off-by: Jiri Slaby + Signed-off-by: John W. Linville + +commit 2ad8cab5071e6059c7333cac965f2b7e7a3342a5 +Author: Luis R. Rodriguez +Date: Sat Oct 13 16:08:29 2007 -0400 + + [PATCH] ath5k: Fix and clean mode initialization, prefer G for AR5212 + + Currently you get locked on B mode with AR5212s. This could be partly + mac80211's fault with a recent regression introduced but ath5k mode + initialization right now is pretty sloppy. For AR5212s we also currently + start scanning in 5GHz. I've made the mode initialization on ath5k a bit + clearer and only am registering G mode now instead of both B and G for + AR5212s. We now also check eeprom reading for capabilities before registering + a specific mode. For AR5212 I get reliable rates only up to 18Mbps for a + throughput of up to 5 Mbits/sec. At least now we can work and test the + other rates again. + + Also use a static driver specific NUM_DRIVER_MODES instead of mac80211's + NUM_IEEE80211_MODES. + + This patch has been tested on AR5210, AR5211 and AR5212. + + Note: mac80211 simple rate algo throws us to 1Mbps after assoc, this is by + design. I recommend users to set rate to 11M for now after assoc. + + Changes to base.[ch] + Changes-licensed-under: 3-clause-BSD + + Changes to ath5k.h + Changes-licensed-under: ISC + + Signed-off-by: Luis R. Rodriguez + Signed-off-by: John W. Linville + +commit 33e9ca7f21695f2f285833cd296f70a2cd345730 +Author: Luis R. Rodriguez +Date: Fri Oct 12 11:07:09 2007 -0400 + + [PATCH] Add extensive documenation for the atheros bssid_mask + + Add extensive documenation for the atheros bssid_mask. + Credit to David Kimdon for figuring this out. I am + just documenting it. + + No need to check for ath5k_hw_hasbssidmask() as + ath5k_hw_set_bssid_mask() will do the check itself. + + Also add link to Atheros patent 6677779 B1 about buffer + registers and control registers. Hope this helps. + + Changes to base.c + Changes-licensed-under: 3-clause-BSD + + Changes to hw.c, reg.h + Changes-licensed-under: ISC + + Signed-off-by: Luis R. Rodriguez + Signed-off-by: John W. Linville + +commit 953389189d1790b4346a43309719893400a31fc5 +Author: Luis R. Rodriguez +Date: Fri Oct 12 11:05:43 2007 -0400 + + [PATCH] Don't read AR5K_RAC_PISR on AR5210, document ath5k_int + + AR5210 does not have AR5K_RAC_PISR so do not read it. Also lets start + trying to document all hardware interrupts. + + Changes-licensed-under: ISC + Signed-off-by: Luis R. Rodriguez + Signed-off-by: John W. Linville + +commit 8462b5d694f20a522ba4dfbb153648ba332b5627 +Author: Luis R. Rodriguez +Date: Fri Oct 12 11:04:38 2007 -0400 + + [PATCH] Add proper support for multicast + + There seems to be several ways to enable multicast. We choose right now + MadWifi's old implementation. We can later try + ath5k_hw_set_mcast_filterindex() as well. + + ath5k_hw_get_rx_filter() may enable AR5K_RX_FILTER_RADARERR or + AR5K_RX_FILTER_PHYERR. We choose to respect only AR5K_RX_FILTER_PHYERR + for now because: + + a. Most radars don't seem to work on 5GHz band now + b. Some have reported a lot of unnecessary noise is captured + when trying to filter for radar + c. When and if someone wants to work on DFS for ath5k later + this can be enabled then + + Changes-licensed-under: 3-clause-BSD + Signed-off-by: Luis R. Rodriguez + Signed-off-by: John W. Linville + +commit ad134b6e277058f4ce929fb4903bac8f2ffa2565 +Author: Luis R. Rodriguez +Date: Fri Oct 12 11:03:49 2007 -0400 + + [PATCH] ath5k: Fix a bug which pushed us to enable promiscuous + + Fix a bug which pushed us to enable the promiscuous filter + all the time during normal operation. The real problem was caused + becuase we were reseting the bssid to the broadcast during + ath5k_hw_reset(). We now cache the bssid value and set the + bssid again during resets. This gives the driver considerably + more stability. + + Known issue: if your DHCP server doesn't ACK your IP via the broadcast but + instead sends it to the IP it gives you (Cisco seems to do this) you + may not get the reply. Work is in progress to figure this issue out. + This issue was present before this patch. + + Changes to base.c + Changes-licensed-under: 3-clause-BSD + + Changes to ath5k.h, hw.c + Changes-licensed-under: ISC + + Signed-off-by: Luis R. Rodriguez + Signed-off-by: John W. Linville + +commit cc79ada2dc67857c1fd922e16ca3769a302f0b06 +Author: Bruno Randolf +Date: Mon Oct 15 21:30:38 2007 +0900 + + [PATCH] ath5k: atheros hardware needs header padding + + handle padding between header and data + + Atheros hardware requires the header to be padded to 4 byte (32 bit) + boundaries. It expects the payload data to start at multiples of 4 byte for TX + frames and will add the padding for received frames. For most headers there is + no need for padding, since they are multiples of 4 already - except QoS and 4 + address headers. + + Changes-licensed-under: 3-clause-BSD + Signed-off-by: Bruno Randolf + Signed-off-by: John W. Linville + +commit 1c4a64df662171bf85081aea39d155c683966a56 +Author: John W. Linville +Date: Tue Oct 2 19:56:29 2007 -0400 + + [PATCH] ath5k: remove reference to ALG_NONE + + Signed-off-by: John W. Linville + +commit ac82c3d69dca0977ad408153109311faabaa73d3 +Author: Luis R. Rodriguez +Date: Fri Sep 28 11:26:16 2007 -0400 + + [PATCH] ath5k: Fix a few typos in copyright + + This patch fixes a few typos overseen by the introduction of + two new files, intvals.c and phy.c. It also adds the missing + warranty on base.c and removes the the last CVS tag from base.h + + Changes to base.[ch] + Changes-licensed-under: 3-clause-BSD + + Changes to phy.c, initvals.c + Changes-licensed-under: ISC + + Signed-off-by: Luis R. Rodriguez + Signed-off-by: John W. Linville + +commit a1f0e21e5ba549ae9208faf9076b0c807adca7c6 +Author: Luis R. Rodriguez +Date: Thu Sep 27 21:04:19 2007 -0400 + + [PATCH] ath5k: add new configure_filter, compile fix on wireless-2.6 + + This patch: + + * removes the old ath_calcrxfilter() and ath_set_multicast_list() + * adds new required required configure_filter() ops, this one + just stores the filter value in cache for later use. + * introduces a cached sc->filter_flags for hw filter flags + * moves the driver to mac80211's new required start()/stop() + * initializes at add_interface() sc->bintval to a common value, + this will later be updated as per mac80211's preference. + * Fix compile bug on ath_set_key() (adds enum for set_key_cmd) + + We'll later port some driver-specific filter stuff onto mac80211. + + This has been tested. This patch applies to the wireless-2.6 everything branch, + after the new ath5k directory move and file renames. + + Changes-licensed-under: 3-clause-BSD + Signed-off-by: Luis R. Rodriguez + Signed-off-by: John W. Linville + +commit 6a0f742dac6bd0c396eb24c021c6c048f496af6e +Author: Bradley M. Kuhn +Date: Thu Sep 27 18:58:24 2007 -0400 + + [PATCH] ath5k: final correction of copyright notices + + The patch below is for application to the wireless-2.6 ath5k branch, and + takes into account the latest driver directory move and file renames. I + believe this patch handles all copyright notice issues that SFLC is + currently aware of. Based on our extensive research (which is summarized + in http://www.softwarefreedom.org/resources/2007/ath5k-code-analysis.html) + we found that the copyright holders below also have a copyright on some + files; the patch below adds their copyright notices. + + We encourage future patchers to add their copyright notice (and any + appropriate additional licensing notices as needed) into the files when + they make patches. We also refer developers to our paper at + http://www.softwarefreedom.org/resources/2007/gpl-non-gpl-collaboration.html + that recommends ways to incorporate permissive-licensed code like this in + a GPL-licensed project like Linux. + + We at SFLC were all very happy to do this work for the Linux Wireless team + and are glad that a favorable outcome for all was reached. + + I believe I've used all the patch-submission tags correctly based on + previous discussions and email exchanges with everyone involved, but I + obviously don't patch the kernel often (er, at all :), so if I've made a + mistake, please let me know. + + Changes-licensed-under: ISC + Signed-off-by: Richard Fontana + Signed-off-by: Bradley M. Kuhn + Signed-off-by: Matt Norwood + Signed-off-by: Karen Sandler + Acked-by: Matthew W. S. Bell + Acked-by: Pavel Roskin + Acked-by: Nick Kossifidis + Acked-by: Jiri Slaby + Acked-by: Luis Rodriguez + Acked-by: Michael Taylor + Signed-off-by: John W. Linville + +commit 4adaee6d7ab1bfd4d9709495a2cb97df4b5afed8 +Author: Andrew Morton +Date: Thu Sep 20 14:02:31 2007 -0700 + + [PATCH] ath5k: Remove pointless empty CVS ID string. + + Cc: Jeff Garzik + Cc: Jiri Slaby + Signed-off-by: Andrew Morton + Signed-off-by: John W. Linville + +commit 260dea31422e4c97b88b2f26474eac3b20ee76a4 +Author: Stephen Hemminger +Date: Tue Sep 18 10:06:47 2007 -0700 + + [PATCH] ath5k: msi support + + The atheros on my Fujitsu b6210 supports MSI. + + Signed-off-by: Stephen Hemminger + Signed-off-by: John W. Linville + +commit 6ebc3f5df03a301a173e10dd72b513fe23ecbbce +Author: Luis R. Rodriguez +Date: Thu Sep 20 17:13:26 2007 -0400 + + [PATCH] ath5k - Fix filters for AR5212, correct return values for WEP + + I was not get getting DHCP replies back with ath5k on a AR5212. Turns + out out of all filter flags if I enable AR5K_RX_FILTER_PROM I get my + replies back. I've tested enabling AR5K_RX_FILTER_BCAST and + AR5K_RX_FILTER_MCAST but AR5K_RX_FILTER_PROM only does the trick. This + may fix this for other cards if you are not getting DHCP replies + please let us know. For now we can enable AR5K_RX_FILTER_PROM on STA + and Ad-hoc only for AR5212 until we sort out the filter flags + properly. This patch also takes into account new changes to mac80211 + for ieee80211_ops's set_key(). + + Filter API changes to come soon. + + In summary this patch has these changes: + + * AR5212 now receives broadcasts (DHCP works now) + * ath5k_hw_set_key() was checking against key table size against + key->keyid -- this can only be 0, 1, 2 or 3. Check against key->keylen + and divide the table size by 8. + * return proper values for WEP setting as per mac80211 documenation + + This patch applies to the ath5k branch of wireless-dev. + + Changes to ath5k_base.c + Changes-licensed-under: 3-clause-BSD + + Changes to ath5k_hw.c, ath5k_reg.h + Changes-licensed-under: ISC + + Signed-off-by: Luis R. Rodriguez + Signed-off-by: John W. Linville + +commit eae99b799ce2aff97ad9016cac834405678c3d6b +Author: Jiri Slaby +Date: Wed Sep 26 14:04:10 2007 -0400 + + [PATCH] Net: ath5k, remove unused/dead code + + ath5k, remove unused/dead code + + Remove ifdeffed code, which is currently (and might not be in the future too) + unused. If it was ever really needed, it could be easily ported back from the + madwifi-old-openhal repository. + + Signed-off-by: Jiri Slaby + Cc: Luis R. Rodriguez + Signed-off-by: John W. Linville + +commit 9ab409d9f834472b2fdf9705cde52f8b4bc2436e +Author: Jiri Slaby +Date: Wed Sep 26 14:03:27 2007 -0400 + + [PATCH] Net: ath5k, use int as retval + + ath5k, use int as retval + + Changes-licensed-under: ISC + Signed-off-by: Jiri Slaby + Cc: Luis R. Rodriguez + Signed-off-by: John W. Linville + +commit 5034f1e5e0610667a77e8ac991255162e5fe9982 +Author: Nick Kossifidis +Date: Wed Sep 26 14:02:50 2007 -0400 + + [PATCH] Net: ath5k, split hw into hw, phy and initvals + + ath5k, split hw into hw, phy and initvals + + Separate the hw code into logical pieces hw, phy and initvals for better + readability and maintainability. + + This includes suggested file renames (_hw removal). + + Changes-licensed-under: ISC + Signed-off-by: Nick Kossifidis + Signed-off-by: Jiri Slaby + Cc: Luis R. Rodriguez + Signed-off-by: John W. Linville + +commit c0a7d16f73da9c33bd71ec8b303bc735f604350c +Author: Jiri Slaby +Date: Wed Sep 26 14:02:11 2007 -0400 + + [PATCH] Net: ath5k, make its own directory + + ath5k, make its own directory + + also remove ath5_ prefix from the filenames + + Changes-licensed-under: ISC + Signed-off-by: Jiri Slaby + Cc: Luis R. Rodriguez + Signed-off-by: John W. Linville + +commit 71b0b4547745b849f1a2535d37e02cff91cb83ad +Author: Luis R. Rodriguez +Date: Mon Sep 17 17:31:51 2007 -0400 + + [PATCH] ath5k: Internalize Atheros Turbo modes + + This patch: + + * Internalizes Atheros Turbo modes (MODE_ATHEROS_TURBO, + MODE_ATHEROS_TURBOG) + + * Internatizes Turbo modulation (MODULATION_TURBO) + + * Adds documention for Atheros Turbo modes (MODE_ATHEROS_TURBO, + MODE_ATHEROS_TURBOG), Turbo modulation (MODULATION_TURBO) and XR + modulation (MODULATION_XR) + + Changes-licensed-under: BSD + Signed-off-by: Luis R. Rodriguez + Signed-off-by: John W. Linville + +commit aa03e9134b6aca4522e8f0a772f4509a5cfe4b13 +Author: John W. Linville +Date: Mon Sep 17 17:11:29 2007 -0400 + + [PATCH] ath5k: remove HW_KEY_IDX_INVALID + + Signed-off-by: John W. Linville + +commit a05767ddbfb1138042b5f08c822a54610bd7d437 +Author: Luis R. Rodriguez +Date: Mon Sep 17 00:48:27 2007 -0400 + + [PATCH] Correct ath5k Kconfig depends + + This patch correct's ath5k's Kconfig depends line by making it depend + on WLAN_80211 and also for now marks it EXPERIMENTAL. This patch + applies to the ath5k branch of wireless-dev. + + Signed-off-by: Luis R. Rodriguez + +commit fb31173e6ccfbcadd9d7645a384c9add3ce7be4f +Author: Luis R. Rodriguez +Date: Mon Sep 17 00:01:09 2007 -0400 + + [PATCH] Add Luis to MAINTAINERS for ath5k + + This patch adds me to the MAINTAINERS entry for ath5k. It applies to + the ath5k branch on wireless-dev. + + Signed-off-by: Luis R. Rodriguez + Signed-off-by: John W. Linville + +commit 5bc68c49c1bdbb92cfcbbea4a57a77b7067350fb +Author: Krzysztof Halasa +Date: Mon Sep 3 20:35:52 2007 +0200 + + [PATCH] Ath5k panic fix + + Ath5k panics on ath_open() because sc->pdev is never set, fixed. + + Signed-off-by: Krzysztof Halasa + Signed-off-by: John W. Linville + +commit 967ee4db879de997e8aadb397317c691480cc9d9 +Author: John W. Linville +Date: Sat Sep 15 11:05:32 2007 -0400 + + [PATCH] ath5k: remove use of IEEE80211_HW_WEP_INCLUDE_IV + + Signed-off-by: John W. Linville + +commit 847a9375af07c677f74934e24f779d90bcc9a7c7 +Author: Luis R. Rodriguez +Date: Mon Sep 10 16:00:38 2007 -0400 + + [PATCH] ath5k: more license corrections (ath5k_reg.h) + + This patch corrects the copyright and license on ath5k_reg.h. + + Specifically, this patch: + + * Removes the GPL license and restores the ISC license from + ath5k_reg.h as Nick indicated. + + * Adds Reyk's Copyright to ath5k_reg.h + + Changes-licensed-under: ISC + Signed-off-by: Luis R. Rodriguez + Signed-off-by: John W. Linville + +commit 4ac1d5eb15b9f5a31568d06d38326059bacee642 +Author: Luis R. Rodriguez +Date: Thu Sep 6 10:18:22 2007 -0400 + + [PATCH] ath5k: correct some license damage + + The attached patch fixes copyright notice for 3 files which need to be + corrected regardless of the outcome of the license of the other files. + + This patch: + + * Adds warranty notices back to ath5k_regdom.[ch] + + * Adds Devicescape Copyright to ath5k_base.c + + Signed-off-by: Luis R. Rodriguez + Changes-licensed-under: ISC + Signed-off-by: John W. Linville + +commit 82f2f4094eddd1993b9f2bc0d53f26def57c3fae +Author: Jiri Slaby +Date: Tue Aug 28 11:59:54 2007 -0400 + + [PATCH] Net: ath5k, switch to ioread/iowrite + + ath5k, switch to ioread/iowrite + + Do not use readl/writel, since iomap retval is platform dependent and + needn't be virtual address awaited by readl/writel. + + Signed-off-by: Jiri Slaby + Signed-off-by: John W. Linville + +commit c2877048ec6f854d417e9141bb18cf4ae15f7b33 +Author: Jiri Slaby +Date: Sat Aug 25 03:59:28 2007 -0400 + + [PATCH] Net: ath5k, remove some ieee80211 re-defines + + ath5k, remove some ieee80211 re-defines + + use mac80211 defines directly instead. this means MODULATION_* to + IEEE80211_RATE_* switch. + + Signed-off-by: Jiri Slaby + Cc: + Signed-off-by: John W. Linville + +commit 9d6c3cef55cbbd6f4358d9bd7a59a2b7655eaaa3 +Author: Jiri Slaby +Date: Sat Aug 25 03:58:47 2007 -0400 + + [PATCH] Net: ath5k, use short preamble for some rates + + ath5k, use short preamble for some rates + + 2, 5.5 and 11 in b/g are now in short preamble mode + + Jiri Slaby wrote: + > Johannes Berg wrote: + > > umm, mac80211 needs to be able to choose depending on the network. + + Hmm, misleading log comment. It should be 'can now be in SP mode'. + + Signed-off-by: Jiri Slaby + Cc: + Signed-off-by: John W. Linville + +commit 8695faaeffc78924829afb21fd7602dc3a4d81b9 +Author: Jiri Slaby +Date: Sat Aug 25 03:51:51 2007 -0400 + + [PATCH] Net: ath5k, initial write cleanup + + ath5k, initial write cleanup + + The final step of initial writing cleanup. ar5211_rf is going away. + + Signed-off-by: Jiri Slaby + Cc: + Signed-off-by: John W. Linville + +commit 5f56d31da11ddf176e313828d168365662ee7b19 +Author: Jiri Slaby +Date: Sat Aug 25 03:57:26 2007 -0400 + + [PATCH] Net: ath5k, comment some EEPROM registers + + ath5k, comment some EEPROM registers + + make some registers meaning clear + + Signed-off-by: Jiri Slaby + Cc: + Signed-off-by: John W. Linville + +commit f2854f11abaef57d219103380ab8410eda6a4c83 +Author: John W. Linville +Date: Thu Aug 23 15:23:30 2007 -0400 + + [PATCH] ath5k: fix build breakage from recent mac80211 changes + + Signed-off-by: John W. Linville + +commit 042c3bcd643fc46949ddd1e71d16ec1dcc0dcf18 +Author: Jiri Slaby +Date: Wed Aug 22 22:54:07 2007 +0200 + + [PATCH] Net: ath5k, remove sysctls + + ath5k, remove sysctls + + Syscalls were buggy and defunct in later kernels (due to sysctl check). + + Signed-off-by: Jiri Slaby + Signed-off-by: John W. Linville + +commit 1fea1eeb34e4092d45e94e6c3e9f2c93b3bc268a +Author: Jiri Slaby +Date: Wed Aug 22 22:53:25 2007 +0200 + + [PATCH] Net: ath5k, no printk after STA->IBSS switch + + ath5k, no printk after STA->IBSS switch + + If STA->IBSS switch was done, but beacon_update weas not called so far, do + not emit a warning about non-existent skbuf. + + Signed-off-by: Jiri Slaby + Signed-off-by: John W. Linville + +commit 88ee097caeeb0561c293296c03da47d3b6e688fb +Author: akpm@linux-foundation.org +Date: Tue Aug 21 16:53:53 2007 -0700 + + [PATCH] ath5k: needs PCI + + drivers/net/wireless/ath5k_base.c: In function `ath_pci_probe': + drivers/net/wireless/ath5k_base.c:2279: error: implicit declaration of function `pci_request_region' + drivers/net/wireless/ath5k_base.c:2359: error: implicit declaration of function `pci_release_region' + + Cc: Jiri Slaby + Signed-off-by: Andrew Morton + Signed-off-by: John W. Linville + +commit 8ddf75b76f0b704971cb0df635557b5cad84ed7d +Author: akpm@linux-foundation.org +Date: Tue Aug 21 00:51:20 2007 -0700 + + [PATCH] ath5k: kconfig fix + + It needs stuff from net/mac80211/ieee80211.c + + Cc: Jiri Slaby + Signed-off-by: Andrew Morton + Signed-off-by: John W. Linville + +commit cd59338a9249ea6f216ba291167fa9728f8bc1ce +Author: akpm@linux-foundation.org +Date: Tue Aug 21 00:42:32 2007 -0700 + + [PATCH] ath5k: printk fix + + drivers/net/wireless/ath5k_base.c: In function 'ath_txq_setup': + drivers/net/wireless/ath5k_base.c:2033: warning: format '%u' expects type 'unsigned int', but argument 3 has type 'long unsigned int' + + Cc: Jiri Slaby + Signed-off-by: Andrew Morton + Signed-off-by: John W. Linville + +commit d58bf444cd868ce93b29501c013b2c057007eed5 +Author: Jiri Slaby +Date: Sun Aug 12 17:33:16 2007 +0200 + + [PATCH] Net: add ath5k wireless driver + + add ath5k wireless driver + + Signed-off-by: Jiri Slaby + Signed-off-by: John W. Linville + +diff -up linux-2.6.23.noarch/MAINTAINERS.orig linux-2.6.23.noarch/MAINTAINERS +--- linux-2.6.23.noarch/MAINTAINERS.orig 2007-12-21 12:15:17.000000000 -0500 ++++ linux-2.6.23.noarch/MAINTAINERS 2007-12-21 12:18:50.000000000 -0500 +@@ -646,6 +646,17 @@ M: ecashin@coraid.com + W: http://www.coraid.com/support/linux + S: Supported + ++ATHEROS ATH5K WIRELESS DRIVER ++P: Jiri Slaby ++M: jirislaby@gmail.com ++P: Nick Kossifidis ++M: mickflemm@gmail.com ++P: Luis R. Rodriguez ++M: mcgrof@gmail.com ++L: linux-wireless@vger.kernel.org ++L: ath5k-devel@lists.ath5k.org ++S: Maintained ++ + ATL1 ETHERNET DRIVER + P: Jay Cliburn + M: jcliburn@gmail.com +diff -up linux-2.6.23.noarch/drivers/net/wireless/Makefile.orig linux-2.6.23.noarch/drivers/net/wireless/Makefile +--- linux-2.6.23.noarch/drivers/net/wireless/Makefile.orig 2007-12-21 12:15:17.000000000 -0500 ++++ linux-2.6.23.noarch/drivers/net/wireless/Makefile 2007-12-21 12:18:50.000000000 -0500 +@@ -61,3 +61,5 @@ obj-$(CONFIG_RT2X00) += rt2x00/ + obj-$(CONFIG_P54_COMMON) += p54common.o + obj-$(CONFIG_P54_USB) += p54usb.o + obj-$(CONFIG_P54_PCI) += p54pci.o ++ ++obj-$(CONFIG_ATH5K) += ath5k/ +diff -up linux-2.6.23.noarch/drivers/net/wireless/Kconfig.orig linux-2.6.23.noarch/drivers/net/wireless/Kconfig +--- linux-2.6.23.noarch/drivers/net/wireless/Kconfig.orig 2007-12-21 12:15:17.000000000 -0500 ++++ linux-2.6.23.noarch/drivers/net/wireless/Kconfig 2007-12-21 12:18:50.000000000 -0500 +@@ -656,6 +656,24 @@ config P54_PCI + tristate "Prism54 PCI support" + depends on P54_COMMON && PCI + ++config ATH5K ++ tristate "Atheros 5xxx wireless cards support" ++ depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL ++ default m ++ ---help--- ++ This module adds support for wireless adapters based on ++ Atheros 5xxx chipset. ++ ++ Currently the following chip versions are supported: ++ ++ MAC: AR5211 AR5212 ++ PHY: RF5111/2111 RF5112/2112 RF5413/2413 ++ ++ This driver uses the kernel's mac80211 subsystem. ++ ++ If you choose to build a module, it'll be called ath5k. Say M if ++ unsure. ++ + source "drivers/net/wireless/iwlwifi/Kconfig" + source "drivers/net/wireless/hostap/Kconfig" + source "drivers/net/wireless/bcm43xx/Kconfig" +diff -up /dev/null linux-2.6.23.noarch/drivers/net/wireless/ath5k/phy.c +--- /dev/null 2007-12-21 08:33:07.834165456 -0500 ++++ linux-2.6.23.noarch/drivers/net/wireless/ath5k/phy.c 2007-12-21 12:18:50.000000000 -0500 +@@ -0,0 +1,2071 @@ ++/* ++ * PHY functions ++ * ++ * Copyright (c) 2004, 2005, 2006, 2007 Reyk Floeter ++ * Copyright (c) 2006, 2007 Nick Kossifidis ++ * Copyright (c) 2007 Jiri Slaby ++ * ++ * Permission to use, copy, modify, and 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 ++ ++#include "ath5k.h" ++#include "reg.h" ++#include "base.h" ++ ++/* Struct to hold initial RF register values (RF Banks) */ ++struct ath5k_ini_rf { ++ u8 rf_bank; /* check out ath5k_reg.h */ ++ u16 rf_register; /* register address */ ++ u32 rf_value[5]; /* register value for different modes (above) */ ++}; ++ ++/* ++ * Mode-specific RF Gain table (64bytes) for RF5111/5112 ++ * (RF5110 only comes with AR5210 and only supports a/turbo a mode so initial ++ * RF Gain values are included in AR5K_AR5210_INI) ++ */ ++struct ath5k_ini_rfgain { ++ u16 rfg_register; /* RF Gain register address */ ++ u32 rfg_value[2]; /* [freq (see below)] */ ++}; ++ ++struct ath5k_gain_opt { ++ u32 go_default; ++ u32 go_steps_count; ++ const struct ath5k_gain_opt_step go_step[AR5K_GAIN_STEP_COUNT]; ++}; ++ ++/* RF5111 mode-specific init registers */ ++static const struct ath5k_ini_rf rfregs_5111[] = { ++ { 0, 0x989c, ++ /* mode a/XR mode aTurbo mode b mode g mode gTurbo */ ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0, 0x989c, ++ { 0x00380000, 0x00380000, 0x00380000, 0x00380000, 0x00380000 } }, ++ { 0, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0, 0x989c, ++ { 0x00000000, 0x00000000, 0x000000c0, 0x00000080, 0x00000080 } }, ++ { 0, 0x989c, ++ { 0x000400f9, 0x000400f9, 0x000400ff, 0x000400fd, 0x000400fd } }, ++ { 0, 0x98d4, ++ { 0x00000000, 0x00000000, 0x00000004, 0x00000004, 0x00000004 } }, ++ { 1, 0x98d4, ++ { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } }, ++ { 2, 0x98d4, ++ { 0x00000010, 0x00000014, 0x00000010, 0x00000010, 0x00000014 } }, ++ { 3, 0x98d8, ++ { 0x00601068, 0x00601068, 0x00601068, 0x00601068, 0x00601068 } }, ++ { 6, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 6, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 6, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 6, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 6, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 6, 0x989c, ++ { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } }, ++ { 6, 0x989c, ++ { 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000 } }, ++ { 6, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 6, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 6, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 6, 0x989c, ++ { 0x00000000, 0x00000000, 0x0a000000, 0x00000000, 0x00000000 } }, ++ { 6, 0x989c, ++ { 0x003800c0, 0x00380080, 0x023800c0, 0x003800c0, 0x003800c0 } }, ++ { 6, 0x989c, ++ { 0x00020006, 0x00020006, 0x00000006, 0x00020006, 0x00020006 } }, ++ { 6, 0x989c, ++ { 0x00000089, 0x00000089, 0x00000089, 0x00000089, 0x00000089 } }, ++ { 6, 0x989c, ++ { 0x000000a0, 0x000000a0, 0x000000a0, 0x000000a0, 0x000000a0 } }, ++ { 6, 0x989c, ++ { 0x00040007, 0x00040007, 0x00040007, 0x00040007, 0x00040007 } }, ++ { 6, 0x98d4, ++ { 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a } }, ++ { 7, 0x989c, ++ { 0x00000040, 0x00000048, 0x00000040, 0x00000040, 0x00000040 } }, ++ { 7, 0x989c, ++ { 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 } }, ++ { 7, 0x989c, ++ { 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008 } }, ++ { 7, 0x989c, ++ { 0x0000004f, 0x0000004f, 0x0000004f, 0x0000004f, 0x0000004f } }, ++ { 7, 0x989c, ++ { 0x000000f1, 0x000000f1, 0x00000061, 0x000000f1, 0x000000f1 } }, ++ { 7, 0x989c, ++ { 0x0000904f, 0x0000904f, 0x0000904c, 0x0000904f, 0x0000904f } }, ++ { 7, 0x989c, ++ { 0x0000125a, 0x0000125a, 0x0000129a, 0x0000125a, 0x0000125a } }, ++ { 7, 0x98cc, ++ { 0x0000000e, 0x0000000e, 0x0000000f, 0x0000000e, 0x0000000e } }, ++}; ++ ++/* Initial RF Gain settings for RF5111 */ ++static const struct ath5k_ini_rfgain rfgain_5111[] = { ++ /* 5Ghz 2Ghz */ ++ { AR5K_RF_GAIN(0), { 0x000001a9, 0x00000000 } }, ++ { AR5K_RF_GAIN(1), { 0x000001e9, 0x00000040 } }, ++ { AR5K_RF_GAIN(2), { 0x00000029, 0x00000080 } }, ++ { AR5K_RF_GAIN(3), { 0x00000069, 0x00000150 } }, ++ { AR5K_RF_GAIN(4), { 0x00000199, 0x00000190 } }, ++ { AR5K_RF_GAIN(5), { 0x000001d9, 0x000001d0 } }, ++ { AR5K_RF_GAIN(6), { 0x00000019, 0x00000010 } }, ++ { AR5K_RF_GAIN(7), { 0x00000059, 0x00000044 } }, ++ { AR5K_RF_GAIN(8), { 0x00000099, 0x00000084 } }, ++ { AR5K_RF_GAIN(9), { 0x000001a5, 0x00000148 } }, ++ { AR5K_RF_GAIN(10), { 0x000001e5, 0x00000188 } }, ++ { AR5K_RF_GAIN(11), { 0x00000025, 0x000001c8 } }, ++ { AR5K_RF_GAIN(12), { 0x000001c8, 0x00000014 } }, ++ { AR5K_RF_GAIN(13), { 0x00000008, 0x00000042 } }, ++ { AR5K_RF_GAIN(14), { 0x00000048, 0x00000082 } }, ++ { AR5K_RF_GAIN(15), { 0x00000088, 0x00000178 } }, ++ { AR5K_RF_GAIN(16), { 0x00000198, 0x000001b8 } }, ++ { AR5K_RF_GAIN(17), { 0x000001d8, 0x000001f8 } }, ++ { AR5K_RF_GAIN(18), { 0x00000018, 0x00000012 } }, ++ { AR5K_RF_GAIN(19), { 0x00000058, 0x00000052 } }, ++ { AR5K_RF_GAIN(20), { 0x00000098, 0x00000092 } }, ++ { AR5K_RF_GAIN(21), { 0x000001a4, 0x0000017c } }, ++ { AR5K_RF_GAIN(22), { 0x000001e4, 0x000001bc } }, ++ { AR5K_RF_GAIN(23), { 0x00000024, 0x000001fc } }, ++ { AR5K_RF_GAIN(24), { 0x00000064, 0x0000000a } }, ++ { AR5K_RF_GAIN(25), { 0x000000a4, 0x0000004a } }, ++ { AR5K_RF_GAIN(26), { 0x000000e4, 0x0000008a } }, ++ { AR5K_RF_GAIN(27), { 0x0000010a, 0x0000015a } }, ++ { AR5K_RF_GAIN(28), { 0x0000014a, 0x0000019a } }, ++ { AR5K_RF_GAIN(29), { 0x0000018a, 0x000001da } }, ++ { AR5K_RF_GAIN(30), { 0x000001ca, 0x0000000e } }, ++ { AR5K_RF_GAIN(31), { 0x0000000a, 0x0000004e } }, ++ { AR5K_RF_GAIN(32), { 0x0000004a, 0x0000008e } }, ++ { AR5K_RF_GAIN(33), { 0x0000008a, 0x0000015e } }, ++ { AR5K_RF_GAIN(34), { 0x000001ba, 0x0000019e } }, ++ { AR5K_RF_GAIN(35), { 0x000001fa, 0x000001de } }, ++ { AR5K_RF_GAIN(36), { 0x0000003a, 0x00000009 } }, ++ { AR5K_RF_GAIN(37), { 0x0000007a, 0x00000049 } }, ++ { AR5K_RF_GAIN(38), { 0x00000186, 0x00000089 } }, ++ { AR5K_RF_GAIN(39), { 0x000001c6, 0x00000179 } }, ++ { AR5K_RF_GAIN(40), { 0x00000006, 0x000001b9 } }, ++ { AR5K_RF_GAIN(41), { 0x00000046, 0x000001f9 } }, ++ { AR5K_RF_GAIN(42), { 0x00000086, 0x00000039 } }, ++ { AR5K_RF_GAIN(43), { 0x000000c6, 0x00000079 } }, ++ { AR5K_RF_GAIN(44), { 0x000000c6, 0x000000b9 } }, ++ { AR5K_RF_GAIN(45), { 0x000000c6, 0x000001bd } }, ++ { AR5K_RF_GAIN(46), { 0x000000c6, 0x000001fd } }, ++ { AR5K_RF_GAIN(47), { 0x000000c6, 0x0000003d } }, ++ { AR5K_RF_GAIN(48), { 0x000000c6, 0x0000007d } }, ++ { AR5K_RF_GAIN(49), { 0x000000c6, 0x000000bd } }, ++ { AR5K_RF_GAIN(50), { 0x000000c6, 0x000000fd } }, ++ { AR5K_RF_GAIN(51), { 0x000000c6, 0x000000fd } }, ++ { AR5K_RF_GAIN(52), { 0x000000c6, 0x000000fd } }, ++ { AR5K_RF_GAIN(53), { 0x000000c6, 0x000000fd } }, ++ { AR5K_RF_GAIN(54), { 0x000000c6, 0x000000fd } }, ++ { AR5K_RF_GAIN(55), { 0x000000c6, 0x000000fd } }, ++ { AR5K_RF_GAIN(56), { 0x000000c6, 0x000000fd } }, ++ { AR5K_RF_GAIN(57), { 0x000000c6, 0x000000fd } }, ++ { AR5K_RF_GAIN(58), { 0x000000c6, 0x000000fd } }, ++ { AR5K_RF_GAIN(59), { 0x000000c6, 0x000000fd } }, ++ { AR5K_RF_GAIN(60), { 0x000000c6, 0x000000fd } }, ++ { AR5K_RF_GAIN(61), { 0x000000c6, 0x000000fd } }, ++ { AR5K_RF_GAIN(62), { 0x000000c6, 0x000000fd } }, ++ { AR5K_RF_GAIN(63), { 0x000000c6, 0x000000fd } }, ++}; ++ ++static const struct ath5k_gain_opt rfgain_opt_5111 = { ++ 4, ++ 9, ++ { ++ { { 4, 1, 1, 1 }, 6 }, ++ { { 4, 0, 1, 1 }, 4 }, ++ { { 3, 1, 1, 1 }, 3 }, ++ { { 4, 0, 0, 1 }, 1 }, ++ { { 4, 1, 1, 0 }, 0 }, ++ { { 4, 0, 1, 0 }, -2 }, ++ { { 3, 1, 1, 0 }, -3 }, ++ { { 4, 0, 0, 0 }, -4 }, ++ { { 2, 1, 1, 0 }, -6 } ++ } ++}; ++ ++/* RF5112 mode-specific init registers */ ++static const struct ath5k_ini_rf rfregs_5112[] = { ++ { 1, 0x98d4, ++ /* mode a/XR mode aTurbo mode b mode g mode gTurbo */ ++ { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } }, ++ { 2, 0x98d0, ++ { 0x03060408, 0x03070408, 0x03060408, 0x03060408, 0x03070408 } }, ++ { 3, 0x98dc, ++ { 0x00a0c0c0, 0x00a0c0c0, 0x00e0c0c0, 0x00e0c0c0, 0x00e0c0c0 } }, ++ { 6, 0x989c, ++ { 0x00a00000, 0x00a00000, 0x00a00000, 0x00a00000, 0x00a00000 } }, ++ { 6, 0x989c, ++ { 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000 } }, ++ { 6, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 6, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 6, 0x989c, ++ { 0x00660000, 0x00660000, 0x00660000, 0x00660000, 0x00660000 } }, ++ { 6, 0x989c, ++ { 0x00db0000, 0x00db0000, 0x00db0000, 0x00db0000, 0x00db0000 } }, ++ { 6, 0x989c, ++ { 0x00f10000, 0x00f10000, 0x00f10000, 0x00f10000, 0x00f10000 } }, ++ { 6, 0x989c, ++ { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } }, ++ { 6, 0x989c, ++ { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } }, ++ { 6, 0x989c, ++ { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } }, ++ { 6, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 6, 0x989c, ++ { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } }, ++ { 6, 0x989c, ++ { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } }, ++ { 6, 0x989c, ++ { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } }, ++ { 6, 0x989c, ++ { 0x008b0000, 0x008b0000, 0x008b0000, 0x008b0000, 0x008b0000 } }, ++ { 6, 0x989c, ++ { 0x00600000, 0x00600000, 0x00600000, 0x00600000, 0x00600000 } }, ++ { 6, 0x989c, ++ { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } }, ++ { 6, 0x989c, ++ { 0x00840000, 0x00840000, 0x00840000, 0x00840000, 0x00840000 } }, ++ { 6, 0x989c, ++ { 0x00640000, 0x00640000, 0x00640000, 0x00640000, 0x00640000 } }, ++ { 6, 0x989c, ++ { 0x00200000, 0x00200000, 0x00200000, 0x00200000, 0x00200000 } }, ++ { 6, 0x989c, ++ { 0x00240000, 0x00240000, 0x00240000, 0x00240000, 0x00240000 } }, ++ { 6, 0x989c, ++ { 0x00250000, 0x00250000, 0x00250000, 0x00250000, 0x00250000 } }, ++ { 6, 0x989c, ++ { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } }, ++ { 6, 0x989c, ++ { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } }, ++ { 6, 0x989c, ++ { 0x00510000, 0x00510000, 0x00510000, 0x00510000, 0x00510000 } }, ++ { 6, 0x989c, ++ { 0x1c040000, 0x1c040000, 0x1c040000, 0x1c040000, 0x1c040000 } }, ++ { 6, 0x989c, ++ { 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000 } }, ++ { 6, 0x989c, ++ { 0x00a10000, 0x00a10000, 0x00a10000, 0x00a10000, 0x00a10000 } }, ++ { 6, 0x989c, ++ { 0x00400000, 0x00400000, 0x00400000, 0x00400000, 0x00400000 } }, ++ { 6, 0x989c, ++ { 0x03090000, 0x03090000, 0x03090000, 0x03090000, 0x03090000 } }, ++ { 6, 0x989c, ++ { 0x06000000, 0x06000000, 0x06000000, 0x06000000, 0x06000000 } }, ++ { 6, 0x989c, ++ { 0x000000b0, 0x000000b0, 0x000000a8, 0x000000a8, 0x000000a8 } }, ++ { 6, 0x989c, ++ { 0x0000002e, 0x0000002e, 0x0000002e, 0x0000002e, 0x0000002e } }, ++ { 6, 0x989c, ++ { 0x006c4a41, 0x006c4a41, 0x006c4af1, 0x006c4a61, 0x006c4a61 } }, ++ { 6, 0x989c, ++ { 0x0050892a, 0x0050892a, 0x0050892b, 0x0050892b, 0x0050892b } }, ++ { 6, 0x989c, ++ { 0x00842400, 0x00842400, 0x00842400, 0x00842400, 0x00842400 } }, ++ { 6, 0x989c, ++ { 0x00c69200, 0x00c69200, 0x00c69200, 0x00c69200, 0x00c69200 } }, ++ { 6, 0x98d0, ++ { 0x0002000c, 0x0002000c, 0x0002000c, 0x0002000c, 0x0002000c } }, ++ { 7, 0x989c, ++ { 0x00000094, 0x00000094, 0x00000094, 0x00000094, 0x00000094 } }, ++ { 7, 0x989c, ++ { 0x00000091, 0x00000091, 0x00000091, 0x00000091, 0x00000091 } }, ++ { 7, 0x989c, ++ { 0x0000000a, 0x0000000a, 0x00000012, 0x00000012, 0x00000012 } }, ++ { 7, 0x989c, ++ { 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080 } }, ++ { 7, 0x989c, ++ { 0x000000c1, 0x000000c1, 0x000000c1, 0x000000c1, 0x000000c1 } }, ++ { 7, 0x989c, ++ { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } }, ++ { 7, 0x989c, ++ { 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0 } }, ++ { 7, 0x989c, ++ { 0x00000022, 0x00000022, 0x00000022, 0x00000022, 0x00000022 } }, ++ { 7, 0x989c, ++ { 0x00000092, 0x00000092, 0x00000092, 0x00000092, 0x00000092 } }, ++ { 7, 0x989c, ++ { 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4 } }, ++ { 7, 0x989c, ++ { 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc } }, ++ { 7, 0x989c, ++ { 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c } }, ++ { 7, 0x98c4, ++ { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } }, ++}; ++ ++/* RF5112A mode-specific init registers */ ++static const struct ath5k_ini_rf rfregs_5112a[] = { ++ { 1, 0x98d4, ++ /* mode a/XR mode aTurbo mode b mode g mode gTurbo */ ++ { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } }, ++ { 2, 0x98d0, ++ { 0x03060408, 0x03070408, 0x03060408, 0x03060408, 0x03070408 } }, ++ { 3, 0x98dc, ++ { 0x00a0c0c0, 0x00a0c0c0, 0x00e0c0c0, 0x00e0c0c0, 0x00e0c0c0 } }, ++ { 6, 0x989c, ++ { 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000 } }, ++ { 6, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 6, 0x989c, ++ { 0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000 } }, ++ { 6, 0x989c, ++ { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } }, ++ { 6, 0x989c, ++ { 0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00010000 } }, ++ { 6, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 6, 0x989c, ++ { 0x00180000, 0x00180000, 0x00180000, 0x00180000, 0x00180000 } }, ++ { 6, 0x989c, ++ { 0x00600000, 0x00600000, 0x006e0000, 0x006e0000, 0x006e0000 } }, ++ { 6, 0x989c, ++ { 0x00c70000, 0x00c70000, 0x00c70000, 0x00c70000, 0x00c70000 } }, ++ { 6, 0x989c, ++ { 0x004b0000, 0x004b0000, 0x004b0000, 0x004b0000, 0x004b0000 } }, ++ { 6, 0x989c, ++ { 0x04480000, 0x04480000, 0x04480000, 0x04480000, 0x04480000 } }, ++ { 6, 0x989c, ++ { 0x00220000, 0x00220000, 0x00220000, 0x00220000, 0x00220000 } }, ++ { 6, 0x989c, ++ { 0x00e40000, 0x00e40000, 0x00e40000, 0x00e40000, 0x00e40000 } }, ++ { 6, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 6, 0x989c, ++ { 0x00fc0000, 0x00fc0000, 0x00fc0000, 0x00fc0000, 0x00fc0000 } }, ++ { 6, 0x989c, ++ { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } }, ++ { 6, 0x989c, ++ { 0x043f0000, 0x043f0000, 0x043f0000, 0x043f0000, 0x043f0000 } }, ++ { 6, 0x989c, ++ { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } }, ++ { 6, 0x989c, ++ { 0x00190000, 0x00190000, 0x00190000, 0x00190000, 0x00190000 } }, ++ { 6, 0x989c, ++ { 0x00240000, 0x00240000, 0x00240000, 0x00240000, 0x00240000 } }, ++ { 6, 0x989c, ++ { 0x00b40000, 0x00b40000, 0x00b40000, 0x00b40000, 0x00b40000 } }, ++ { 6, 0x989c, ++ { 0x00990000, 0x00990000, 0x00990000, 0x00990000, 0x00990000 } }, ++ { 6, 0x989c, ++ { 0x00500000, 0x00500000, 0x00500000, 0x00500000, 0x00500000 } }, ++ { 6, 0x989c, ++ { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } }, ++ { 6, 0x989c, ++ { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } }, ++ { 6, 0x989c, ++ { 0xc0320000, 0xc0320000, 0xc0320000, 0xc0320000, 0xc0320000 } }, ++ { 6, 0x989c, ++ { 0x01740000, 0x01740000, 0x01740000, 0x01740000, 0x01740000 } }, ++ { 6, 0x989c, ++ { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } }, ++ { 6, 0x989c, ++ { 0x86280000, 0x86280000, 0x86280000, 0x86280000, 0x86280000 } }, ++ { 6, 0x989c, ++ { 0x31840000, 0x31840000, 0x31840000, 0x31840000, 0x31840000 } }, ++ { 6, 0x989c, ++ { 0x00020080, 0x00020080, 0x00020080, 0x00020080, 0x00020080 } }, ++ { 6, 0x989c, ++ { 0x00080009, 0x00080009, 0x00080009, 0x00080009, 0x00080009 } }, ++ { 6, 0x989c, ++ { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } }, ++ { 6, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 6, 0x989c, ++ { 0x000000b2, 0x000000b2, 0x000000b2, 0x000000b2, 0x000000b2 } }, ++ { 6, 0x989c, ++ { 0x00b02084, 0x00b02084, 0x00b02084, 0x00b02084, 0x00b02084 } }, ++ { 6, 0x989c, ++ { 0x004125a4, 0x004125a4, 0x004125a4, 0x004125a4, 0x004125a4 } }, ++ { 6, 0x989c, ++ { 0x00119220, 0x00119220, 0x00119220, 0x00119220, 0x00119220 } }, ++ { 6, 0x989c, ++ { 0x001a4800, 0x001a4800, 0x001a4800, 0x001a4800, 0x001a4800 } }, ++ { 6, 0x98d8, ++ { 0x000b0230, 0x000b0230, 0x000b0230, 0x000b0230, 0x000b0230 } }, ++ { 7, 0x989c, ++ { 0x00000094, 0x00000094, 0x00000094, 0x00000094, 0x00000094 } }, ++ { 7, 0x989c, ++ { 0x00000091, 0x00000091, 0x00000091, 0x00000091, 0x00000091 } }, ++ { 7, 0x989c, ++ { 0x00000012, 0x00000012, 0x00000012, 0x00000012, 0x00000012 } }, ++ { 7, 0x989c, ++ { 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080 } }, ++ { 7, 0x989c, ++ { 0x000000d9, 0x000000d9, 0x000000d9, 0x000000d9, 0x000000d9 } }, ++ { 7, 0x989c, ++ { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } }, ++ { 7, 0x989c, ++ { 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0 } }, ++ { 7, 0x989c, ++ { 0x000000a2, 0x000000a2, 0x000000a2, 0x000000a2, 0x000000a2 } }, ++ { 7, 0x989c, ++ { 0x00000052, 0x00000052, 0x00000052, 0x00000052, 0x00000052 } }, ++ { 7, 0x989c, ++ { 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4 } }, ++ { 7, 0x989c, ++ { 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc } }, ++ { 7, 0x989c, ++ { 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c } }, ++ { 7, 0x98c4, ++ { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } }, ++}; ++ ++ ++static const struct ath5k_ini_rf rfregs_2112a[] = { ++ { 1, AR5K_RF_BUFFER_CONTROL_4, ++ /* mode b mode g mode gTurbo */ ++ { 0x00000020, 0x00000020, 0x00000020 } }, ++ { 2, AR5K_RF_BUFFER_CONTROL_3, ++ { 0x03060408, 0x03060408, 0x03070408 } }, ++ { 3, AR5K_RF_BUFFER_CONTROL_6, ++ { 0x00e020c0, 0x00e020c0, 0x00e020c0 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x0a000000, 0x0a000000, 0x0a000000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x00000000, 0x00000000, 0x00000000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x00800000, 0x00800000, 0x00800000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x002a0000, 0x002a0000, 0x002a0000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x00010000, 0x00010000, 0x00010000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x00000000, 0x00000000, 0x00000000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x00180000, 0x00180000, 0x00180000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x006e0000, 0x006e0000, 0x006e0000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x00c70000, 0x00c70000, 0x00c70000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x004b0000, 0x004b0000, 0x004b0000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x04480000, 0x04480000, 0x04480000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x002a0000, 0x002a0000, 0x002a0000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x00e40000, 0x00e40000, 0x00e40000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x00000000, 0x00000000, 0x00000000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x00fc0000, 0x00fc0000, 0x00fc0000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x00ff0000, 0x00ff0000, 0x00ff0000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x043f0000, 0x043f0000, 0x043f0000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x0c0c0000, 0x0c0c0000, 0x0c0c0000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x02190000, 0x02190000, 0x02190000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x00240000, 0x00240000, 0x00240000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x00b40000, 0x00b40000, 0x00b40000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x00990000, 0x00990000, 0x00990000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x00500000, 0x00500000, 0x00500000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x002a0000, 0x002a0000, 0x002a0000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x00120000, 0x00120000, 0x00120000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0xc0320000, 0xc0320000, 0xc0320000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x01740000, 0x01740000, 0x01740000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x00110000, 0x00110000, 0x00110000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x86280000, 0x86280000, 0x86280000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x31840000, 0x31840000, 0x31840000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x00f20080, 0x00f20080, 0x00f20080 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x00070019, 0x00070019, 0x00070019 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x00000000, 0x00000000, 0x00000000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x00000000, 0x00000000, 0x00000000 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x000000b2, 0x000000b2, 0x000000b2 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x00b02184, 0x00b02184, 0x00b02184 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x004125a4, 0x004125a4, 0x004125a4 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x00119220, 0x00119220, 0x00119220 } }, ++ { 6, AR5K_RF_BUFFER, ++ { 0x001a4800, 0x001a4800, 0x001a4800 } }, ++ { 6, AR5K_RF_BUFFER_CONTROL_5, ++ { 0x000b0230, 0x000b0230, 0x000b0230 } }, ++ { 7, AR5K_RF_BUFFER, ++ { 0x00000094, 0x00000094, 0x00000094 } }, ++ { 7, AR5K_RF_BUFFER, ++ { 0x00000091, 0x00000091, 0x00000091 } }, ++ { 7, AR5K_RF_BUFFER, ++ { 0x00000012, 0x00000012, 0x00000012 } }, ++ { 7, AR5K_RF_BUFFER, ++ { 0x00000080, 0x00000080, 0x00000080 } }, ++ { 7, AR5K_RF_BUFFER, ++ { 0x000000d9, 0x000000d9, 0x000000d9 } }, ++ { 7, AR5K_RF_BUFFER, ++ { 0x00000060, 0x00000060, 0x00000060 } }, ++ { 7, AR5K_RF_BUFFER, ++ { 0x000000f0, 0x000000f0, 0x000000f0 } }, ++ { 7, AR5K_RF_BUFFER, ++ { 0x000000a2, 0x000000a2, 0x000000a2 } }, ++ { 7, AR5K_RF_BUFFER, ++ { 0x00000052, 0x00000052, 0x00000052 } }, ++ { 7, AR5K_RF_BUFFER, ++ { 0x000000d4, 0x000000d4, 0x000000d4 } }, ++ { 7, AR5K_RF_BUFFER, ++ { 0x000014cc, 0x000014cc, 0x000014cc } }, ++ { 7, AR5K_RF_BUFFER, ++ { 0x0000048c, 0x0000048c, 0x0000048c } }, ++ { 7, AR5K_RF_BUFFER_CONTROL_1, ++ { 0x00000003, 0x00000003, 0x00000003 } }, ++}; ++ ++/* RF5413/5414 mode-specific init registers */ ++static const struct ath5k_ini_rf rfregs_5413[] = { ++ { 1, 0x98d4, ++ /* mode a/XR mode aTurbo mode b mode g mode gTurbo */ ++ { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } }, ++ { 2, 0x98d0, ++ { 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008 } }, ++ { 3, 0x98dc, ++ { 0x00a000c0, 0x00a000c0, 0x00e000c0, 0x00e000c0, 0x00e000c0 } }, ++ { 6, 0x989c, ++ { 0x33000000, 0x33000000, 0x33000000, 0x33000000, 0x33000000 } }, ++ { 6, 0x989c, ++ { 0x01000000, 0x01000000, 0x01000000, 0x01000000, 0x01000000 } }, ++ { 6, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 6, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 6, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 6, 0x989c, ++ { 0x1f000000, 0x1f000000, 0x1f000000, 0x1f000000, 0x1f000000 } }, ++ { 6, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 6, 0x989c, ++ { 0x00b80000, 0x00b80000, 0x00b80000, 0x00b80000, 0x00b80000 } }, ++ { 6, 0x989c, ++ { 0x00b70000, 0x00b70000, 0x00b70000, 0x00b70000, 0x00b70000 } }, ++ { 6, 0x989c, ++ { 0x00840000, 0x00840000, 0x00840000, 0x00840000, 0x00840000 } }, ++ { 6, 0x989c, ++ { 0x00980000, 0x00980000, 0x00980000, 0x00980000, 0x00980000 } }, ++ { 6, 0x989c, ++ { 0x00c00000, 0x00c00000, 0x00c00000, 0x00c00000, 0x00c00000 } }, ++ { 6, 0x989c, ++ { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } }, ++ { 6, 0x989c, ++ { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } }, ++ { 6, 0x989c, ++ { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } }, ++ { 6, 0x989c, ++ { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } }, ++ { 6, 0x989c, ++ { 0x00d70000, 0x00d70000, 0x00d70000, 0x00d70000, 0x00d70000 } }, ++ { 6, 0x989c, ++ { 0x00610000, 0x00610000, 0x00610000, 0x00610000, 0x00610000 } }, ++ { 6, 0x989c, ++ { 0x00fe0000, 0x00fe0000, 0x00fe0000, 0x00fe0000, 0x00fe0000 } }, ++ { 6, 0x989c, ++ { 0x00de0000, 0x00de0000, 0x00de0000, 0x00de0000, 0x00de0000 } }, ++ { 6, 0x989c, ++ { 0x007f0000, 0x007f0000, 0x007f0000, 0x007f0000, 0x007f0000 } }, ++ { 6, 0x989c, ++ { 0x043d0000, 0x043d0000, 0x043d0000, 0x043d0000, 0x043d0000 } }, ++ { 6, 0x989c, ++ { 0x00770000, 0x00770000, 0x00770000, 0x00770000, 0x00770000 } }, ++ { 6, 0x989c, ++ { 0x00440000, 0x00440000, 0x00440000, 0x00440000, 0x00440000 } }, ++ { 6, 0x989c, ++ { 0x00980000, 0x00980000, 0x00980000, 0x00980000, 0x00980000 } }, ++ { 6, 0x989c, ++ { 0x00100080, 0x00100080, 0x00100080, 0x00100080, 0x00100080 } }, ++ { 6, 0x989c, ++ { 0x0005c034, 0x0005c034, 0x0005c034, 0x0005c034, 0x0005c034 } }, ++ { 6, 0x989c, ++ { 0x003100f0, 0x003100f0, 0x003100f0, 0x003100f0, 0x003100f0 } }, ++ { 6, 0x989c, ++ { 0x000c011f, 0x000c011f, 0x000c011f, 0x000c011f, 0x000c011f } }, ++ { 6, 0x989c, ++ { 0x00510040, 0x00510040, 0x005100a0, 0x005100a0, 0x005100a0 } }, ++ { 6, 0x989c, ++ { 0x0050006a, 0x0050006a, 0x005000dd, 0x005000dd, 0x005000dd } }, ++ { 6, 0x989c, ++ { 0x00000001, 0x00000001, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 6, 0x989c, ++ { 0x00004044, 0x00004044, 0x00004044, 0x00004044, 0x00004044 } }, ++ { 6, 0x989c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 6, 0x989c, ++ { 0x000060c0, 0x000060c0, 0x000060c0, 0x000060c0, 0x000060c0 } }, ++ { 6, 0x989c, ++ { 0x00002c00, 0x00002c00, 0x00003600, 0x00003600, 0x00003600 } }, ++ { 6, 0x98c8, ++ { 0x00000403, 0x00000403, 0x00040403, 0x00040403, 0x00040403 } }, ++ { 7, 0x989c, ++ { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } }, ++ { 7, 0x989c, ++ { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } }, ++ { 7, 0x98cc, ++ { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } }, ++}; ++ ++ ++/* Initial RF Gain settings for RF5112 */ ++static const struct ath5k_ini_rfgain rfgain_5112[] = { ++ /* 5Ghz 2Ghz */ ++ { AR5K_RF_GAIN(0), { 0x00000007, 0x00000007 } }, ++ { AR5K_RF_GAIN(1), { 0x00000047, 0x00000047 } }, ++ { AR5K_RF_GAIN(2), { 0x00000087, 0x00000087 } }, ++ { AR5K_RF_GAIN(3), { 0x000001a0, 0x000001a0 } }, ++ { AR5K_RF_GAIN(4), { 0x000001e0, 0x000001e0 } }, ++ { AR5K_RF_GAIN(5), { 0x00000020, 0x00000020 } }, ++ { AR5K_RF_GAIN(6), { 0x00000060, 0x00000060 } }, ++ { AR5K_RF_GAIN(7), { 0x000001a1, 0x000001a1 } }, ++ { AR5K_RF_GAIN(8), { 0x000001e1, 0x000001e1 } }, ++ { AR5K_RF_GAIN(9), { 0x00000021, 0x00000021 } }, ++ { AR5K_RF_GAIN(10), { 0x00000061, 0x00000061 } }, ++ { AR5K_RF_GAIN(11), { 0x00000162, 0x00000162 } }, ++ { AR5K_RF_GAIN(12), { 0x000001a2, 0x000001a2 } }, ++ { AR5K_RF_GAIN(13), { 0x000001e2, 0x000001e2 } }, ++ { AR5K_RF_GAIN(14), { 0x00000022, 0x00000022 } }, ++ { AR5K_RF_GAIN(15), { 0x00000062, 0x00000062 } }, ++ { AR5K_RF_GAIN(16), { 0x00000163, 0x00000163 } }, ++ { AR5K_RF_GAIN(17), { 0x000001a3, 0x000001a3 } }, ++ { AR5K_RF_GAIN(18), { 0x000001e3, 0x000001e3 } }, ++ { AR5K_RF_GAIN(19), { 0x00000023, 0x00000023 } }, ++ { AR5K_RF_GAIN(20), { 0x00000063, 0x00000063 } }, ++ { AR5K_RF_GAIN(21), { 0x00000184, 0x00000184 } }, ++ { AR5K_RF_GAIN(22), { 0x000001c4, 0x000001c4 } }, ++ { AR5K_RF_GAIN(23), { 0x00000004, 0x00000004 } }, ++ { AR5K_RF_GAIN(24), { 0x000001ea, 0x0000000b } }, ++ { AR5K_RF_GAIN(25), { 0x0000002a, 0x0000004b } }, ++ { AR5K_RF_GAIN(26), { 0x0000006a, 0x0000008b } }, ++ { AR5K_RF_GAIN(27), { 0x000000aa, 0x000001ac } }, ++ { AR5K_RF_GAIN(28), { 0x000001ab, 0x000001ec } }, ++ { AR5K_RF_GAIN(29), { 0x000001eb, 0x0000002c } }, ++ { AR5K_RF_GAIN(30), { 0x0000002b, 0x00000012 } }, ++ { AR5K_RF_GAIN(31), { 0x0000006b, 0x00000052 } }, ++ { AR5K_RF_GAIN(32), { 0x000000ab, 0x00000092 } }, ++ { AR5K_RF_GAIN(33), { 0x000001ac, 0x00000193 } }, ++ { AR5K_RF_GAIN(34), { 0x000001ec, 0x000001d3 } }, ++ { AR5K_RF_GAIN(35), { 0x0000002c, 0x00000013 } }, ++ { AR5K_RF_GAIN(36), { 0x0000003a, 0x00000053 } }, ++ { AR5K_RF_GAIN(37), { 0x0000007a, 0x00000093 } }, ++ { AR5K_RF_GAIN(38), { 0x000000ba, 0x00000194 } }, ++ { AR5K_RF_GAIN(39), { 0x000001bb, 0x000001d4 } }, ++ { AR5K_RF_GAIN(40), { 0x000001fb, 0x00000014 } }, ++ { AR5K_RF_GAIN(41), { 0x0000003b, 0x0000003a } }, ++ { AR5K_RF_GAIN(42), { 0x0000007b, 0x0000007a } }, ++ { AR5K_RF_GAIN(43), { 0x000000bb, 0x000000ba } }, ++ { AR5K_RF_GAIN(44), { 0x000001bc, 0x000001bb } }, ++ { AR5K_RF_GAIN(45), { 0x000001fc, 0x000001fb } }, ++ { AR5K_RF_GAIN(46), { 0x0000003c, 0x0000003b } }, ++ { AR5K_RF_GAIN(47), { 0x0000007c, 0x0000007b } }, ++ { AR5K_RF_GAIN(48), { 0x000000bc, 0x000000bb } }, ++ { AR5K_RF_GAIN(49), { 0x000000fc, 0x000001bc } }, ++ { AR5K_RF_GAIN(50), { 0x000000fc, 0x000001fc } }, ++ { AR5K_RF_GAIN(51), { 0x000000fc, 0x0000003c } }, ++ { AR5K_RF_GAIN(52), { 0x000000fc, 0x0000007c } }, ++ { AR5K_RF_GAIN(53), { 0x000000fc, 0x000000bc } }, ++ { AR5K_RF_GAIN(54), { 0x000000fc, 0x000000fc } }, ++ { AR5K_RF_GAIN(55), { 0x000000fc, 0x000000fc } }, ++ { AR5K_RF_GAIN(56), { 0x000000fc, 0x000000fc } }, ++ { AR5K_RF_GAIN(57), { 0x000000fc, 0x000000fc } }, ++ { AR5K_RF_GAIN(58), { 0x000000fc, 0x000000fc } }, ++ { AR5K_RF_GAIN(59), { 0x000000fc, 0x000000fc } }, ++ { AR5K_RF_GAIN(60), { 0x000000fc, 0x000000fc } }, ++ { AR5K_RF_GAIN(61), { 0x000000fc, 0x000000fc } }, ++ { AR5K_RF_GAIN(62), { 0x000000fc, 0x000000fc } }, ++ { AR5K_RF_GAIN(63), { 0x000000fc, 0x000000fc } }, ++}; ++ ++/* Initial RF Gain settings for RF5413 */ ++static const struct ath5k_ini_rfgain rfgain_5413[] = { ++ /* 5Ghz 2Ghz */ ++ { AR5K_RF_GAIN(0), { 0x00000000, 0x00000000 } }, ++ { AR5K_RF_GAIN(1), { 0x00000040, 0x00000040 } }, ++ { AR5K_RF_GAIN(2), { 0x00000080, 0x00000080 } }, ++ { AR5K_RF_GAIN(3), { 0x000001a1, 0x00000161 } }, ++ { AR5K_RF_GAIN(4), { 0x000001e1, 0x000001a1 } }, ++ { AR5K_RF_GAIN(5), { 0x00000021, 0x000001e1 } }, ++ { AR5K_RF_GAIN(6), { 0x00000061, 0x00000021 } }, ++ { AR5K_RF_GAIN(7), { 0x00000188, 0x00000061 } }, ++ { AR5K_RF_GAIN(8), { 0x000001c8, 0x00000188 } }, ++ { AR5K_RF_GAIN(9), { 0x00000008, 0x000001c8 } }, ++ { AR5K_RF_GAIN(10), { 0x00000048, 0x00000008 } }, ++ { AR5K_RF_GAIN(11), { 0x00000088, 0x00000048 } }, ++ { AR5K_RF_GAIN(12), { 0x000001a9, 0x00000088 } }, ++ { AR5K_RF_GAIN(13), { 0x000001e9, 0x00000169 } }, ++ { AR5K_RF_GAIN(14), { 0x00000029, 0x000001a9 } }, ++ { AR5K_RF_GAIN(15), { 0x00000069, 0x000001e9 } }, ++ { AR5K_RF_GAIN(16), { 0x000001d0, 0x00000029 } }, ++ { AR5K_RF_GAIN(17), { 0x00000010, 0x00000069 } }, ++ { AR5K_RF_GAIN(18), { 0x00000050, 0x00000190 } }, ++ { AR5K_RF_GAIN(19), { 0x00000090, 0x000001d0 } }, ++ { AR5K_RF_GAIN(20), { 0x000001b1, 0x00000010 } }, ++ { AR5K_RF_GAIN(21), { 0x000001f1, 0x00000050 } }, ++ { AR5K_RF_GAIN(22), { 0x00000031, 0x00000090 } }, ++ { AR5K_RF_GAIN(23), { 0x00000071, 0x00000171 } }, ++ { AR5K_RF_GAIN(24), { 0x000001b8, 0x000001b1 } }, ++ { AR5K_RF_GAIN(25), { 0x000001f8, 0x000001f1 } }, ++ { AR5K_RF_GAIN(26), { 0x00000038, 0x00000031 } }, ++ { AR5K_RF_GAIN(27), { 0x00000078, 0x00000071 } }, ++ { AR5K_RF_GAIN(28), { 0x00000199, 0x00000198 } }, ++ { AR5K_RF_GAIN(29), { 0x000001d9, 0x000001d8 } }, ++ { AR5K_RF_GAIN(30), { 0x00000019, 0x00000018 } }, ++ { AR5K_RF_GAIN(31), { 0x00000059, 0x00000058 } }, ++ { AR5K_RF_GAIN(32), { 0x00000099, 0x00000098 } }, ++ { AR5K_RF_GAIN(33), { 0x000000d9, 0x00000179 } }, ++ { AR5K_RF_GAIN(34), { 0x000000f9, 0x000001b9 } }, ++ { AR5K_RF_GAIN(35), { 0x000000f9, 0x000001f9 } }, ++ { AR5K_RF_GAIN(36), { 0x000000f9, 0x00000039 } }, ++ { AR5K_RF_GAIN(37), { 0x000000f9, 0x00000079 } }, ++ { AR5K_RF_GAIN(38), { 0x000000f9, 0x000000b9 } }, ++ { AR5K_RF_GAIN(39), { 0x000000f9, 0x000000f9 } }, ++ { AR5K_RF_GAIN(40), { 0x000000f9, 0x000000f9 } }, ++ { AR5K_RF_GAIN(41), { 0x000000f9, 0x000000f9 } }, ++ { AR5K_RF_GAIN(42), { 0x000000f9, 0x000000f9 } }, ++ { AR5K_RF_GAIN(43), { 0x000000f9, 0x000000f9 } }, ++ { AR5K_RF_GAIN(44), { 0x000000f9, 0x000000f9 } }, ++ { AR5K_RF_GAIN(45), { 0x000000f9, 0x000000f9 } }, ++ { AR5K_RF_GAIN(46), { 0x000000f9, 0x000000f9 } }, ++ { AR5K_RF_GAIN(47), { 0x000000f9, 0x000000f9 } }, ++ { AR5K_RF_GAIN(48), { 0x000000f9, 0x000000f9 } }, ++ { AR5K_RF_GAIN(49), { 0x000000f9, 0x000000f9 } }, ++ { AR5K_RF_GAIN(50), { 0x000000f9, 0x000000f9 } }, ++ { AR5K_RF_GAIN(51), { 0x000000f9, 0x000000f9 } }, ++ { AR5K_RF_GAIN(52), { 0x000000f9, 0x000000f9 } }, ++ { AR5K_RF_GAIN(53), { 0x000000f9, 0x000000f9 } }, ++ { AR5K_RF_GAIN(54), { 0x000000f9, 0x000000f9 } }, ++ { AR5K_RF_GAIN(55), { 0x000000f9, 0x000000f9 } }, ++ { AR5K_RF_GAIN(56), { 0x000000f9, 0x000000f9 } }, ++ { AR5K_RF_GAIN(57), { 0x000000f9, 0x000000f9 } }, ++ { AR5K_RF_GAIN(58), { 0x000000f9, 0x000000f9 } }, ++ { AR5K_RF_GAIN(59), { 0x000000f9, 0x000000f9 } }, ++ { AR5K_RF_GAIN(60), { 0x000000f9, 0x000000f9 } }, ++ { AR5K_RF_GAIN(61), { 0x000000f9, 0x000000f9 } }, ++ { AR5K_RF_GAIN(62), { 0x000000f9, 0x000000f9 } }, ++ { AR5K_RF_GAIN(63), { 0x000000f9, 0x000000f9 } }, ++}; ++ ++static const struct ath5k_gain_opt rfgain_opt_5112 = { ++ 1, ++ 8, ++ { ++ { { 3, 0, 0, 0, 0, 0, 0 }, 6 }, ++ { { 2, 0, 0, 0, 0, 0, 0 }, 0 }, ++ { { 1, 0, 0, 0, 0, 0, 0 }, -3 }, ++ { { 0, 0, 0, 0, 0, 0, 0 }, -6 }, ++ { { 0, 1, 1, 0, 0, 0, 0 }, -8 }, ++ { { 0, 1, 1, 0, 1, 1, 0 }, -10 }, ++ { { 0, 1, 0, 1, 1, 1, 0 }, -13 }, ++ { { 0, 1, 0, 1, 1, 0, 1 }, -16 }, ++ } ++}; ++ ++/* ++ * Used to modify RF Banks before writing them to AR5K_RF_BUFFER ++ */ ++static unsigned int ath5k_hw_rfregs_op(u32 *rf, u32 offset, u32 reg, u32 bits, ++ u32 first, u32 col, bool set) ++{ ++ u32 mask, entry, last, data, shift, position; ++ s32 left; ++ int i; ++ ++ data = 0; ++ ++ if (rf == NULL) ++ /* should not happen */ ++ return 0; ++ ++ if (!(col <= 3 && bits <= 32 && first + bits <= 319)) { ++ ATH5K_PRINTF("invalid values at offset %u\n", offset); ++ return 0; ++ } ++ ++ entry = ((first - 1) / 8) + offset; ++ position = (first - 1) % 8; ++ ++ if (set == true) ++ data = ath5k_hw_bitswap(reg, bits); ++ ++ for (i = shift = 0, left = bits; left > 0; position = 0, entry++, i++) { ++ last = (position + left > 8) ? 8 : position + left; ++ mask = (((1 << last) - 1) ^ ((1 << position) - 1)) << (col * 8); ++ ++ if (set == true) { ++ rf[entry] &= ~mask; ++ rf[entry] |= ((data << position) << (col * 8)) & mask; ++ data >>= (8 - position); ++ } else { ++ data = (((rf[entry] & mask) >> (col * 8)) >> position) ++ << shift; ++ shift += last - position; ++ } ++ ++ left -= 8 - position; ++ } ++ ++ data = set == true ? 1 : ath5k_hw_bitswap(data, bits); ++ ++ return data; ++} ++ ++static u32 ath5k_hw_rfregs_gainf_corr(struct ath5k_hw *ah) ++{ ++ u32 mix, step; ++ u32 *rf; ++ ++ if (ah->ah_rf_banks == NULL) ++ return 0; ++ ++ rf = ah->ah_rf_banks; ++ ah->ah_gain.g_f_corr = 0; ++ ++ if (ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 1, 36, 0, false) != 1) ++ return 0; ++ ++ step = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 4, 32, 0, false); ++ mix = ah->ah_gain.g_step->gos_param[0]; ++ ++ switch (mix) { ++ case 3: ++ ah->ah_gain.g_f_corr = step * 2; ++ break; ++ case 2: ++ ah->ah_gain.g_f_corr = (step - 5) * 2; ++ break; ++ case 1: ++ ah->ah_gain.g_f_corr = step; ++ break; ++ default: ++ ah->ah_gain.g_f_corr = 0; ++ break; ++ } ++ ++ return ah->ah_gain.g_f_corr; ++} ++ ++static bool ath5k_hw_rfregs_gain_readback(struct ath5k_hw *ah) ++{ ++ u32 step, mix, level[4]; ++ u32 *rf; ++ ++ if (ah->ah_rf_banks == NULL) ++ return false; ++ ++ rf = ah->ah_rf_banks; ++ ++ if (ah->ah_radio == AR5K_RF5111) { ++ step = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 6, 37, 0, ++ false); ++ level[0] = 0; ++ level[1] = (step == 0x3f) ? 0x32 : step + 4; ++ level[2] = (step != 0x3f) ? 0x40 : level[0]; ++ level[3] = level[2] + 0x32; ++ ++ ah->ah_gain.g_high = level[3] - ++ (step == 0x3f ? AR5K_GAIN_DYN_ADJUST_HI_MARGIN : -5); ++ ah->ah_gain.g_low = level[0] + ++ (step == 0x3f ? AR5K_GAIN_DYN_ADJUST_LO_MARGIN : 0); ++ } else { ++ mix = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 1, 36, 0, ++ false); ++ level[0] = level[2] = 0; ++ ++ if (mix == 1) { ++ level[1] = level[3] = 83; ++ } else { ++ level[1] = level[3] = 107; ++ ah->ah_gain.g_high = 55; ++ } ++ } ++ ++ return (ah->ah_gain.g_current >= level[0] && ++ ah->ah_gain.g_current <= level[1]) || ++ (ah->ah_gain.g_current >= level[2] && ++ ah->ah_gain.g_current <= level[3]); ++} ++ ++static s32 ath5k_hw_rfregs_gain_adjust(struct ath5k_hw *ah) ++{ ++ const struct ath5k_gain_opt *go; ++ int ret = 0; ++ ++ switch (ah->ah_radio) { ++ case AR5K_RF5111: ++ go = &rfgain_opt_5111; ++ break; ++ case AR5K_RF5112: ++ case AR5K_RF5413: /* ??? */ ++ go = &rfgain_opt_5112; ++ break; ++ default: ++ return 0; ++ } ++ ++ ah->ah_gain.g_step = &go->go_step[ah->ah_gain.g_step_idx]; ++ ++ if (ah->ah_gain.g_current >= ah->ah_gain.g_high) { ++ if (ah->ah_gain.g_step_idx == 0) ++ return -1; ++ for (ah->ah_gain.g_target = ah->ah_gain.g_current; ++ ah->ah_gain.g_target >= ah->ah_gain.g_high && ++ ah->ah_gain.g_step_idx > 0; ++ ah->ah_gain.g_step = ++ &go->go_step[ah->ah_gain.g_step_idx]) ++ ah->ah_gain.g_target -= 2 * ++ (go->go_step[--(ah->ah_gain.g_step_idx)].gos_gain - ++ ah->ah_gain.g_step->gos_gain); ++ ++ ret = 1; ++ goto done; ++ } ++ ++ if (ah->ah_gain.g_current <= ah->ah_gain.g_low) { ++ if (ah->ah_gain.g_step_idx == (go->go_steps_count - 1)) ++ return -2; ++ for (ah->ah_gain.g_target = ah->ah_gain.g_current; ++ ah->ah_gain.g_target <= ah->ah_gain.g_low && ++ ah->ah_gain.g_step_idx < go->go_steps_count-1; ++ ah->ah_gain.g_step = ++ &go->go_step[ah->ah_gain.g_step_idx]) ++ ah->ah_gain.g_target -= 2 * ++ (go->go_step[++ah->ah_gain.g_step_idx].gos_gain - ++ ah->ah_gain.g_step->gos_gain); ++ ++ ret = 2; ++ goto done; ++ } ++ ++done: ++ ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE, ++ "ret %d, gain step %u, current gain %u, target gain %u\n", ++ ret, ah->ah_gain.g_step_idx, ah->ah_gain.g_current, ++ ah->ah_gain.g_target); ++ ++ return ret; ++} ++ ++/* ++ * Read EEPROM Calibration data, modify RF Banks and Initialize RF5111 ++ */ ++static int ath5k_hw_rf5111_rfregs(struct ath5k_hw *ah, ++ struct ieee80211_channel *channel, unsigned int mode) ++{ ++ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; ++ u32 *rf; ++ const unsigned int rf_size = ARRAY_SIZE(rfregs_5111); ++ unsigned int i; ++ int obdb = -1, bank = -1; ++ u32 ee_mode; ++ ++ AR5K_ASSERT_ENTRY(mode, AR5K_INI_VAL_MAX); ++ ++ rf = ah->ah_rf_banks; ++ ++ /* Copy values to modify them */ ++ for (i = 0; i < rf_size; i++) { ++ if (rfregs_5111[i].rf_bank >= AR5K_RF5111_INI_RF_MAX_BANKS) { ++ ATH5K_ERR(ah->ah_sc, "invalid bank\n"); ++ return -EINVAL; ++ } ++ ++ if (bank != rfregs_5111[i].rf_bank) { ++ bank = rfregs_5111[i].rf_bank; ++ ah->ah_offset[bank] = i; ++ } ++ ++ rf[i] = rfregs_5111[i].rf_value[mode]; ++ } ++ ++ /* Modify bank 0 */ ++ if (channel->val & CHANNEL_2GHZ) { ++ if (channel->val & CHANNEL_CCK) ++ ee_mode = AR5K_EEPROM_MODE_11B; ++ else ++ ee_mode = AR5K_EEPROM_MODE_11G; ++ obdb = 0; ++ ++ if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[0], ++ ee->ee_ob[ee_mode][obdb], 3, 119, 0, true)) ++ return -EINVAL; ++ ++ if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[0], ++ ee->ee_ob[ee_mode][obdb], 3, 122, 0, true)) ++ return -EINVAL; ++ ++ obdb = 1; ++ /* Modify bank 6 */ ++ } else { ++ /* For 11a, Turbo and XR */ ++ ee_mode = AR5K_EEPROM_MODE_11A; ++ obdb = channel->freq >= 5725 ? 3 : ++ (channel->freq >= 5500 ? 2 : ++ (channel->freq >= 5260 ? 1 : ++ (channel->freq > 4000 ? 0 : -1))); ++ ++ if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], ++ ee->ee_pwd_84, 1, 51, 3, true)) ++ return -EINVAL; ++ ++ if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], ++ ee->ee_pwd_90, 1, 45, 3, true)) ++ return -EINVAL; ++ } ++ ++ if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], ++ !ee->ee_xpd[ee_mode], 1, 95, 0, true)) ++ return -EINVAL; ++ ++ if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], ++ ee->ee_x_gain[ee_mode], 4, 96, 0, true)) ++ return -EINVAL; ++ ++ if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], obdb >= 0 ? ++ ee->ee_ob[ee_mode][obdb] : 0, 3, 104, 0, true)) ++ return -EINVAL; ++ ++ if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], obdb >= 0 ? ++ ee->ee_db[ee_mode][obdb] : 0, 3, 107, 0, true)) ++ return -EINVAL; ++ ++ /* Modify bank 7 */ ++ if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[7], ++ ee->ee_i_gain[ee_mode], 6, 29, 0, true)) ++ return -EINVAL; ++ ++ if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[7], ++ ee->ee_xpd[ee_mode], 1, 4, 0, true)) ++ return -EINVAL; ++ ++ /* Write RF values */ ++ for (i = 0; i < rf_size; i++) { ++ AR5K_REG_WAIT(i); ++ ath5k_hw_reg_write(ah, rf[i], rfregs_5111[i].rf_register); ++ } ++ ++ return 0; ++} ++ ++/* ++ * Read EEPROM Calibration data, modify RF Banks and Initialize RF5112 ++ */ ++static int ath5k_hw_rf5112_rfregs(struct ath5k_hw *ah, ++ struct ieee80211_channel *channel, unsigned int mode) ++{ ++ const struct ath5k_ini_rf *rf_ini; ++ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; ++ u32 *rf; ++ unsigned int rf_size, i; ++ int obdb = -1, bank = -1; ++ u32 ee_mode; ++ ++ AR5K_ASSERT_ENTRY(mode, AR5K_INI_VAL_MAX); ++ ++ rf = ah->ah_rf_banks; ++ ++ if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_2112A ++ && !test_bit(MODE_IEEE80211A, ah->ah_capabilities.cap_mode)){ ++ rf_ini = rfregs_2112a; ++ rf_size = ARRAY_SIZE(rfregs_5112a); ++ if (mode < 2) { ++ ATH5K_ERR(ah->ah_sc,"invalid channel mode: %i\n",mode); ++ return -EINVAL; ++ } ++ mode = mode - 2; /*no a/turboa modes for 2112*/ ++ } else if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) { ++ rf_ini = rfregs_5112a; ++ rf_size = ARRAY_SIZE(rfregs_5112a); ++ } else { ++ rf_ini = rfregs_5112; ++ rf_size = ARRAY_SIZE(rfregs_5112); ++ } ++ ++ /* Copy values to modify them */ ++ for (i = 0; i < rf_size; i++) { ++ if (rf_ini[i].rf_bank >= AR5K_RF5112_INI_RF_MAX_BANKS) { ++ ATH5K_ERR(ah->ah_sc, "invalid bank\n"); ++ return -EINVAL; ++ } ++ ++ if (bank != rf_ini[i].rf_bank) { ++ bank = rf_ini[i].rf_bank; ++ ah->ah_offset[bank] = i; ++ } ++ ++ rf[i] = rf_ini[i].rf_value[mode]; ++ } ++ ++ /* Modify bank 6 */ ++ if (channel->val & CHANNEL_2GHZ) { ++ if (channel->val & CHANNEL_OFDM) ++ ee_mode = AR5K_EEPROM_MODE_11G; ++ else ++ ee_mode = AR5K_EEPROM_MODE_11B; ++ obdb = 0; ++ ++ if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], ++ ee->ee_ob[ee_mode][obdb], 3, 287, 0, true)) ++ return -EINVAL; ++ ++ if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], ++ ee->ee_ob[ee_mode][obdb], 3, 290, 0, true)) ++ return -EINVAL; ++ } else { ++ /* For 11a, Turbo and XR */ ++ ee_mode = AR5K_EEPROM_MODE_11A; ++ obdb = channel->freq >= 5725 ? 3 : ++ (channel->freq >= 5500 ? 2 : ++ (channel->freq >= 5260 ? 1 : ++ (channel->freq > 4000 ? 0 : -1))); ++ ++ if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], ++ ee->ee_ob[ee_mode][obdb], 3, 279, 0, true)) ++ return -EINVAL; ++ ++ if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], ++ ee->ee_ob[ee_mode][obdb], 3, 282, 0, true)) ++ return -EINVAL; ++ } ++ ++ ath5k_hw_rfregs_op(rf, ah->ah_offset[6], ++ ee->ee_x_gain[ee_mode], 2, 270, 0, true); ++ ath5k_hw_rfregs_op(rf, ah->ah_offset[6], ++ ee->ee_x_gain[ee_mode], 2, 257, 0, true); ++ ++ if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], ++ ee->ee_xpd[ee_mode], 1, 302, 0, true)) ++ return -EINVAL; ++ ++ /* Modify bank 7 */ ++ if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[7], ++ ee->ee_i_gain[ee_mode], 6, 14, 0, true)) ++ return -EINVAL; ++ ++ /* Write RF values */ ++ for (i = 0; i < rf_size; i++) ++ ath5k_hw_reg_write(ah, rf[i], rf_ini[i].rf_register); ++ ++ return 0; ++} ++ ++/* ++ * Initialize RF5413/5414 ++ */ ++static int ath5k_hw_rf5413_rfregs(struct ath5k_hw *ah, ++ struct ieee80211_channel *channel, unsigned int mode) ++{ ++ const struct ath5k_ini_rf *rf_ini; ++ u32 *rf; ++ unsigned int rf_size, i; ++ int bank = -1; ++ ++ AR5K_ASSERT_ENTRY(mode, AR5K_INI_VAL_MAX); ++ ++ rf = ah->ah_rf_banks; ++ ++ rf_ini = rfregs_5413; ++ rf_size = ARRAY_SIZE(rfregs_5413); ++ ++ /* Copy values to modify them */ ++ for (i = 0; i < rf_size; i++) { ++ if (rf_ini[i].rf_bank >= AR5K_RF5112_INI_RF_MAX_BANKS) { ++ ATH5K_ERR(ah->ah_sc, "invalid bank\n"); ++ return -EINVAL; ++ } ++ ++ if (bank != rf_ini[i].rf_bank) { ++ bank = rf_ini[i].rf_bank; ++ ah->ah_offset[bank] = i; ++ } ++ ++ rf[i] = rf_ini[i].rf_value[mode]; ++ } ++ ++ /* ++ * After compairing dumps from different cards ++ * we get the same RF_BUFFER settings (diff returns ++ * 0 lines). It seems that RF_BUFFER settings are static ++ * and are written unmodified (no EEPROM stuff ++ * is used because calibration data would be ++ * different between different cards and would result ++ * different RF_BUFFER settings) ++ */ ++ ++ /* Write RF values */ ++ for (i = 0; i < rf_size; i++) ++ ath5k_hw_reg_write(ah, rf[i], rf_ini[i].rf_register); ++ ++ return 0; ++} ++ ++/* ++ * Initialize RF ++ */ ++int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel, ++ unsigned int mode) ++{ ++ int (*func)(struct ath5k_hw *, struct ieee80211_channel *, unsigned int); ++ int ret; ++ ++ switch (ah->ah_radio) { ++ case AR5K_RF5111: ++ ah->ah_rf_banks_size = sizeof(rfregs_5111); ++ func = ath5k_hw_rf5111_rfregs; ++ break; ++ case AR5K_RF5112: ++ if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) ++ ah->ah_rf_banks_size = sizeof(rfregs_5112a); ++ else ++ ah->ah_rf_banks_size = sizeof(rfregs_5112); ++ func = ath5k_hw_rf5112_rfregs; ++ break; ++ case AR5K_RF5413: ++ ah->ah_rf_banks_size = sizeof(rfregs_5413); ++ func = ath5k_hw_rf5413_rfregs; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (ah->ah_rf_banks == NULL) { ++ /* XXX do extra checks? */ ++ ah->ah_rf_banks = kmalloc(ah->ah_rf_banks_size, GFP_KERNEL); ++ if (ah->ah_rf_banks == NULL) { ++ ATH5K_ERR(ah->ah_sc, "out of memory\n"); ++ return -ENOMEM; ++ } ++ } ++ ++ ret = func(ah, channel, mode); ++ if (!ret) ++ ah->ah_rf_gain = AR5K_RFGAIN_INACTIVE; ++ ++ return ret; ++} ++ ++int ath5k_hw_rfgain(struct ath5k_hw *ah, unsigned int freq) ++{ ++ const struct ath5k_ini_rfgain *ath5k_rfg; ++ unsigned int i, size; ++ ++ switch (ah->ah_radio) { ++ case AR5K_RF5111: ++ ath5k_rfg = rfgain_5111; ++ size = ARRAY_SIZE(rfgain_5111); ++ break; ++ case AR5K_RF5112: ++ ath5k_rfg = rfgain_5112; ++ size = ARRAY_SIZE(rfgain_5112); ++ break; ++ case AR5K_RF5413: ++ ath5k_rfg = rfgain_5413; ++ size = ARRAY_SIZE(rfgain_5413); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ switch (freq) { ++ case AR5K_INI_RFGAIN_2GHZ: ++ case AR5K_INI_RFGAIN_5GHZ: ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < size; i++) { ++ AR5K_REG_WAIT(i); ++ ath5k_hw_reg_write(ah, ath5k_rfg[i].rfg_value[freq], ++ (u32)ath5k_rfg[i].rfg_register); ++ } ++ ++ return 0; ++} ++ ++enum ath5k_rfgain ath5k_hw_get_rf_gain(struct ath5k_hw *ah) ++{ ++ u32 data, type; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ ++ if (ah->ah_rf_banks == NULL || !ah->ah_gain.g_active || ++ ah->ah_version <= AR5K_AR5211) ++ return AR5K_RFGAIN_INACTIVE; ++ ++ if (ah->ah_rf_gain != AR5K_RFGAIN_READ_REQUESTED) ++ goto done; ++ ++ data = ath5k_hw_reg_read(ah, AR5K_PHY_PAPD_PROBE); ++ ++ if (!(data & AR5K_PHY_PAPD_PROBE_TX_NEXT)) { ++ ah->ah_gain.g_current = data >> AR5K_PHY_PAPD_PROBE_GAINF_S; ++ type = AR5K_REG_MS(data, AR5K_PHY_PAPD_PROBE_TYPE); ++ ++ if (type == AR5K_PHY_PAPD_PROBE_TYPE_CCK) ++ ah->ah_gain.g_current += AR5K_GAIN_CCK_PROBE_CORR; ++ ++ if (ah->ah_radio >= AR5K_RF5112) { ++ ath5k_hw_rfregs_gainf_corr(ah); ++ ah->ah_gain.g_current = ++ ah->ah_gain.g_current>=ah->ah_gain.g_f_corr ? ++ (ah->ah_gain.g_current-ah->ah_gain.g_f_corr) : ++ 0; ++ } ++ ++ if (ath5k_hw_rfregs_gain_readback(ah) && ++ AR5K_GAIN_CHECK_ADJUST(&ah->ah_gain) && ++ ath5k_hw_rfregs_gain_adjust(ah)) ++ ah->ah_rf_gain = AR5K_RFGAIN_NEED_CHANGE; ++ } ++ ++done: ++ return ah->ah_rf_gain; ++} ++ ++int ath5k_hw_set_rfgain_opt(struct ath5k_hw *ah) ++{ ++ /* Initialize the gain optimization values */ ++ switch (ah->ah_radio) { ++ case AR5K_RF5111: ++ ah->ah_gain.g_step_idx = rfgain_opt_5111.go_default; ++ ah->ah_gain.g_step = ++ &rfgain_opt_5111.go_step[ah->ah_gain.g_step_idx]; ++ ah->ah_gain.g_low = 20; ++ ah->ah_gain.g_high = 35; ++ ah->ah_gain.g_active = 1; ++ break; ++ case AR5K_RF5112: ++ case AR5K_RF5413: /* ??? */ ++ ah->ah_gain.g_step_idx = rfgain_opt_5112.go_default; ++ ah->ah_gain.g_step = ++ &rfgain_opt_5112.go_step[ah->ah_gain.g_step_idx]; ++ ah->ah_gain.g_low = 20; ++ ah->ah_gain.g_high = 85; ++ ah->ah_gain.g_active = 1; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++/**************************\ ++ PHY/RF channel functions ++\**************************/ ++ ++/* ++ * Check if a channel is supported ++ */ ++bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags) ++{ ++ /* Check if the channel is in our supported range */ ++ if (flags & CHANNEL_2GHZ) { ++ if ((freq >= ah->ah_capabilities.cap_range.range_2ghz_min) && ++ (freq <= ah->ah_capabilities.cap_range.range_2ghz_max)) ++ return true; ++ } else if (flags & CHANNEL_5GHZ) ++ if ((freq >= ah->ah_capabilities.cap_range.range_5ghz_min) && ++ (freq <= ah->ah_capabilities.cap_range.range_5ghz_max)) ++ return true; ++ ++ return false; ++} ++ ++/* ++ * Convertion needed for RF5110 ++ */ ++static u32 ath5k_hw_rf5110_chan2athchan(struct ieee80211_channel *channel) ++{ ++ u32 athchan; ++ ++ /* ++ * Convert IEEE channel/MHz to an internal channel value used ++ * by the AR5210 chipset. This has not been verified with ++ * newer chipsets like the AR5212A who have a completely ++ * different RF/PHY part. ++ */ ++ athchan = (ath5k_hw_bitswap((channel->chan - 24) / 2, 5) << 1) | ++ (1 << 6) | 0x1; ++ ++ return athchan; ++} ++ ++/* ++ * Set channel on RF5110 ++ */ ++static int ath5k_hw_rf5110_channel(struct ath5k_hw *ah, ++ struct ieee80211_channel *channel) ++{ ++ u32 data; ++ ++ /* ++ * Set the channel and wait ++ */ ++ data = ath5k_hw_rf5110_chan2athchan(channel); ++ ath5k_hw_reg_write(ah, data, AR5K_RF_BUFFER); ++ ath5k_hw_reg_write(ah, 0, AR5K_RF_BUFFER_CONTROL_0); ++ mdelay(1); ++ ++ return 0; ++} ++ ++/* ++ * Convertion needed for 5111 ++ */ ++static int ath5k_hw_rf5111_chan2athchan(unsigned int ieee, ++ struct ath5k_athchan_2ghz *athchan) ++{ ++ int channel; ++ ++ /* Cast this value to catch negative channel numbers (>= -19) */ ++ channel = (int)ieee; ++ ++ /* ++ * Map 2GHz IEEE channel to 5GHz Atheros channel ++ */ ++ if (channel <= 13) { ++ athchan->a2_athchan = 115 + channel; ++ athchan->a2_flags = 0x46; ++ } else if (channel == 14) { ++ athchan->a2_athchan = 124; ++ athchan->a2_flags = 0x44; ++ } else if (channel >= 15 && channel <= 26) { ++ athchan->a2_athchan = ((channel - 14) * 4) + 132; ++ athchan->a2_flags = 0x46; ++ } else ++ return -EINVAL; ++ ++ return 0; ++} ++ ++/* ++ * Set channel on 5111 ++ */ ++static int ath5k_hw_rf5111_channel(struct ath5k_hw *ah, ++ struct ieee80211_channel *channel) ++{ ++ struct ath5k_athchan_2ghz ath5k_channel_2ghz; ++ unsigned int ath5k_channel = channel->chan; ++ u32 data0, data1, clock; ++ int ret; ++ ++ /* ++ * Set the channel on the RF5111 radio ++ */ ++ data0 = data1 = 0; ++ ++ if (channel->val & CHANNEL_2GHZ) { ++ /* Map 2GHz channel to 5GHz Atheros channel ID */ ++ ret = ath5k_hw_rf5111_chan2athchan(channel->chan, ++ &ath5k_channel_2ghz); ++ if (ret) ++ return ret; ++ ++ ath5k_channel = ath5k_channel_2ghz.a2_athchan; ++ data0 = ((ath5k_hw_bitswap(ath5k_channel_2ghz.a2_flags, 8) & 0xff) ++ << 5) | (1 << 4); ++ } ++ ++ if (ath5k_channel < 145 || !(ath5k_channel & 1)) { ++ clock = 1; ++ data1 = ((ath5k_hw_bitswap(ath5k_channel - 24, 8) & 0xff) << 2) | ++ (clock << 1) | (1 << 10) | 1; ++ } else { ++ clock = 0; ++ data1 = ((ath5k_hw_bitswap((ath5k_channel - 24) / 2, 8) & 0xff) ++ << 2) | (clock << 1) | (1 << 10) | 1; ++ } ++ ++ ath5k_hw_reg_write(ah, (data1 & 0xff) | ((data0 & 0xff) << 8), ++ AR5K_RF_BUFFER); ++ ath5k_hw_reg_write(ah, ((data1 >> 8) & 0xff) | (data0 & 0xff00), ++ AR5K_RF_BUFFER_CONTROL_3); ++ ++ return 0; ++} ++ ++/* ++ * Set channel on 5112 and newer ++ */ ++static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah, ++ struct ieee80211_channel *channel) ++{ ++ u32 data, data0, data1, data2; ++ u16 c; ++ ++ data = data0 = data1 = data2 = 0; ++ c = channel->freq; ++ ++ /* ++ * Set the channel on the RF5112 or newer ++ */ ++ if (c < 4800) { ++ if (!((c - 2224) % 5)) { ++ data0 = ((2 * (c - 704)) - 3040) / 10; ++ data1 = 1; ++ } else if (!((c - 2192) % 5)) { ++ data0 = ((2 * (c - 672)) - 3040) / 10; ++ data1 = 0; ++ } else ++ return -EINVAL; ++ ++ data0 = ath5k_hw_bitswap((data0 << 2) & 0xff, 8); ++ } else { ++ if (!(c % 20) && c >= 5120) { ++ data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8); ++ data2 = ath5k_hw_bitswap(3, 2); ++ } else if (!(c % 10)) { ++ data0 = ath5k_hw_bitswap(((c - 4800) / 10 << 1), 8); ++ data2 = ath5k_hw_bitswap(2, 2); ++ } else if (!(c % 5)) { ++ data0 = ath5k_hw_bitswap((c - 4800) / 5, 8); ++ data2 = ath5k_hw_bitswap(1, 2); ++ } else ++ return -EINVAL; ++ } ++ ++ data = (data0 << 4) | (data1 << 1) | (data2 << 2) | 0x1001; ++ ++ ath5k_hw_reg_write(ah, data & 0xff, AR5K_RF_BUFFER); ++ ath5k_hw_reg_write(ah, (data >> 8) & 0x7f, AR5K_RF_BUFFER_CONTROL_5); ++ ++ return 0; ++} ++ ++/* ++ * Set a channel on the radio chip ++ */ ++int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) ++{ ++ int ret; ++ ++ /* ++ * Check bounds supported by the PHY ++ * (don't care about regulation restrictions at this point) ++ */ ++ if ((channel->freq < ah->ah_capabilities.cap_range.range_2ghz_min || ++ channel->freq > ah->ah_capabilities.cap_range.range_2ghz_max) && ++ (channel->freq < ah->ah_capabilities.cap_range.range_5ghz_min || ++ channel->freq > ah->ah_capabilities.cap_range.range_5ghz_max)) { ++ ATH5K_ERR(ah->ah_sc, ++ "channel out of supported range (%u MHz)\n", ++ channel->freq); ++ return -EINVAL; ++ } ++ ++ /* ++ * Set the channel and wait ++ */ ++ switch (ah->ah_radio) { ++ case AR5K_RF5110: ++ ret = ath5k_hw_rf5110_channel(ah, channel); ++ break; ++ case AR5K_RF5111: ++ ret = ath5k_hw_rf5111_channel(ah, channel); ++ break; ++ default: ++ ret = ath5k_hw_rf5112_channel(ah, channel); ++ break; ++ } ++ ++ if (ret) ++ return ret; ++ ++ ah->ah_current_channel.freq = channel->freq; ++ ah->ah_current_channel.val = channel->val; ++ ah->ah_turbo = channel->val == CHANNEL_T ? true : false; ++ ++ return 0; ++} ++ ++/*****************\ ++ PHY calibration ++\*****************/ ++ ++/** ++ * ath5k_hw_noise_floor_calibration - perform PHY noise floor calibration ++ * ++ * @ah: struct ath5k_hw pointer we are operating on ++ * @freq: the channel frequency, just used for error logging ++ * ++ * This function performs a noise floor calibration of the PHY and waits for ++ * it to complete. Then the noise floor value is compared to some maximum ++ * noise floor we consider valid. ++ * ++ * Note that this is different from what the madwifi HAL does: it reads the ++ * noise floor and afterwards initiates the calibration. Since the noise floor ++ * calibration can take some time to finish, depending on the current channel ++ * use, that avoids the occasional timeout warnings we are seeing now. ++ * ++ * See the following link for an Atheros patent on noise floor calibration: ++ * http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&Sect2=HITOFF&d=PALL \ ++ * &p=1&u=%2Fnetahtml%2FPTO%2Fsrchnum.htm&r=1&f=G&l=50&s1=7245893.PN.&OS=PN/7 ++ * ++ */ ++int ++ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq) ++{ ++ int ret; ++ unsigned int i; ++ s32 noise_floor; ++ ++ /* ++ * Enable noise floor calibration and wait until completion ++ */ ++ AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, ++ AR5K_PHY_AGCCTL_NF); ++ ++ ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, ++ AR5K_PHY_AGCCTL_NF, 0, false); ++ if (ret) { ++ ATH5K_ERR(ah->ah_sc, ++ "noise floor calibration timeout (%uMHz)\n", freq); ++ return ret; ++ } ++ ++ /* Wait until the noise floor is calibrated and read the value */ ++ for (i = 20; i > 0; i--) { ++ mdelay(1); ++ noise_floor = ath5k_hw_reg_read(ah, AR5K_PHY_NF); ++ noise_floor = AR5K_PHY_NF_RVAL(noise_floor); ++ if (noise_floor & AR5K_PHY_NF_ACTIVE) { ++ noise_floor = AR5K_PHY_NF_AVAL(noise_floor); ++ ++ if (noise_floor <= AR5K_TUNE_NOISE_FLOOR) ++ break; ++ } ++ } ++ ++ ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE, ++ "noise floor %d\n", noise_floor); ++ ++ if (noise_floor > AR5K_TUNE_NOISE_FLOOR) { ++ ATH5K_ERR(ah->ah_sc, ++ "noise floor calibration failed (%uMHz)\n", freq); ++ return -EIO; ++ } ++ ++ ah->ah_noise_floor = noise_floor; ++ ++ return 0; ++} ++ ++/* ++ * Perform a PHY calibration on RF5110 ++ * -Fix BPSK/QAM Constellation (I/Q correction) ++ * -Calculate Noise Floor ++ */ ++static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, ++ struct ieee80211_channel *channel) ++{ ++ u32 phy_sig, phy_agc, phy_sat, beacon; ++ int ret; ++ ++ /* ++ * Disable beacons and RX/TX queues, wait ++ */ ++ AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5210, ++ AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210); ++ beacon = ath5k_hw_reg_read(ah, AR5K_BEACON_5210); ++ ath5k_hw_reg_write(ah, beacon & ~AR5K_BEACON_ENABLE, AR5K_BEACON_5210); ++ ++ udelay(2300); ++ ++ /* ++ * Set the channel (with AGC turned off) ++ */ ++ AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); ++ udelay(10); ++ ret = ath5k_hw_channel(ah, channel); ++ ++ /* ++ * Activate PHY and wait ++ */ ++ ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT); ++ mdelay(1); ++ ++ AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); ++ ++ if (ret) ++ return ret; ++ ++ /* ++ * Calibrate the radio chip ++ */ ++ ++ /* Remember normal state */ ++ phy_sig = ath5k_hw_reg_read(ah, AR5K_PHY_SIG); ++ phy_agc = ath5k_hw_reg_read(ah, AR5K_PHY_AGCCOARSE); ++ phy_sat = ath5k_hw_reg_read(ah, AR5K_PHY_ADCSAT); ++ ++ /* Update radio registers */ ++ ath5k_hw_reg_write(ah, (phy_sig & ~(AR5K_PHY_SIG_FIRPWR)) | ++ AR5K_REG_SM(-1, AR5K_PHY_SIG_FIRPWR), AR5K_PHY_SIG); ++ ++ ath5k_hw_reg_write(ah, (phy_agc & ~(AR5K_PHY_AGCCOARSE_HI | ++ AR5K_PHY_AGCCOARSE_LO)) | ++ AR5K_REG_SM(-1, AR5K_PHY_AGCCOARSE_HI) | ++ AR5K_REG_SM(-127, AR5K_PHY_AGCCOARSE_LO), AR5K_PHY_AGCCOARSE); ++ ++ ath5k_hw_reg_write(ah, (phy_sat & ~(AR5K_PHY_ADCSAT_ICNT | ++ AR5K_PHY_ADCSAT_THR)) | ++ AR5K_REG_SM(2, AR5K_PHY_ADCSAT_ICNT) | ++ AR5K_REG_SM(12, AR5K_PHY_ADCSAT_THR), AR5K_PHY_ADCSAT); ++ ++ udelay(20); ++ ++ AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); ++ udelay(10); ++ ath5k_hw_reg_write(ah, AR5K_PHY_RFSTG_DISABLE, AR5K_PHY_RFSTG); ++ AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); ++ ++ mdelay(1); ++ ++ /* ++ * Enable calibration and wait until completion ++ */ ++ AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_CAL); ++ ++ ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, ++ AR5K_PHY_AGCCTL_CAL, 0, false); ++ ++ /* Reset to normal state */ ++ ath5k_hw_reg_write(ah, phy_sig, AR5K_PHY_SIG); ++ ath5k_hw_reg_write(ah, phy_agc, AR5K_PHY_AGCCOARSE); ++ ath5k_hw_reg_write(ah, phy_sat, AR5K_PHY_ADCSAT); ++ ++ if (ret) { ++ ATH5K_ERR(ah->ah_sc, "calibration timeout (%uMHz)\n", ++ channel->freq); ++ return ret; ++ } ++ ++ ret = ath5k_hw_noise_floor_calibration(ah, channel->freq); ++ if (ret) ++ return ret; ++ ++ /* ++ * Re-enable RX/TX and beacons ++ */ ++ AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5210, ++ AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210); ++ ath5k_hw_reg_write(ah, beacon, AR5K_BEACON_5210); ++ ++ return 0; ++} ++ ++/* ++ * Perform a PHY calibration on RF5111/5112 ++ */ ++static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah, ++ struct ieee80211_channel *channel) ++{ ++ u32 i_pwr, q_pwr; ++ s32 iq_corr, i_coff, i_coffd, q_coff, q_coffd; ++ ATH5K_TRACE(ah->ah_sc); ++ ++ if (ah->ah_calibration == false || ++ ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN) ++ goto done; ++ ++ ah->ah_calibration = false; ++ ++ iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR); ++ i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I); ++ q_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_Q); ++ i_coffd = ((i_pwr >> 1) + (q_pwr >> 1)) >> 7; ++ q_coffd = q_pwr >> 6; ++ ++ if (i_coffd == 0 || q_coffd == 0) ++ goto done; ++ ++ i_coff = ((-iq_corr) / i_coffd) & 0x3f; ++ q_coff = (((s32)i_pwr / q_coffd) - 64) & 0x1f; ++ ++ /* Commit new IQ value */ ++ AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE | ++ ((u32)q_coff) | ((u32)i_coff << AR5K_PHY_IQ_CORR_Q_I_COFF_S)); ++ ++done: ++ ath5k_hw_noise_floor_calibration(ah, channel->freq); ++ ++ /* Request RF gain */ ++ if (channel->val & CHANNEL_5GHZ) { ++ ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txpower.txp_max, ++ AR5K_PHY_PAPD_PROBE_TXPOWER) | ++ AR5K_PHY_PAPD_PROBE_TX_NEXT, AR5K_PHY_PAPD_PROBE); ++ ah->ah_rf_gain = AR5K_RFGAIN_READ_REQUESTED; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Perform a PHY calibration ++ */ ++int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, ++ struct ieee80211_channel *channel) ++{ ++ int ret; ++ ++ if (ah->ah_radio == AR5K_RF5110) ++ ret = ath5k_hw_rf5110_calibrate(ah, channel); ++ else ++ ret = ath5k_hw_rf511x_calibrate(ah, channel); ++ ++ return ret; ++} ++ ++int ath5k_hw_phy_disable(struct ath5k_hw *ah) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ /*Just a try M.F.*/ ++ ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT); ++ ++ return 0; ++} ++ ++/********************\ ++ Misc PHY functions ++\********************/ ++ ++/* ++ * Get the PHY Chip revision ++ */ ++u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan) ++{ ++ unsigned int i; ++ u32 srev; ++ u16 ret; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ ++ /* ++ * Set the radio chip access register ++ */ ++ switch (chan) { ++ case CHANNEL_2GHZ: ++ ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_2GHZ, AR5K_PHY(0)); ++ break; ++ case CHANNEL_5GHZ: ++ ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0)); ++ break; ++ default: ++ return 0; ++ } ++ ++ mdelay(2); ++ ++ /* ...wait until PHY is ready and read the selected radio revision */ ++ ath5k_hw_reg_write(ah, 0x00001c16, AR5K_PHY(0x34)); ++ ++ for (i = 0; i < 8; i++) ++ ath5k_hw_reg_write(ah, 0x00010000, AR5K_PHY(0x20)); ++ ++ if (ah->ah_version == AR5K_AR5210) { ++ srev = ath5k_hw_reg_read(ah, AR5K_PHY(256) >> 28) & 0xf; ++ ret = (u16)ath5k_hw_bitswap(srev, 4) + 1; ++ } else { ++ srev = (ath5k_hw_reg_read(ah, AR5K_PHY(0x100)) >> 24) & 0xff; ++ ret = (u16)ath5k_hw_bitswap(((srev & 0xf0) >> 4) | ++ ((srev & 0x0f) << 4), 8); ++ } ++ ++ /* Reset to the 5GHz mode */ ++ ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0)); ++ ++ return ret; ++} ++ ++void /*TODO:Boundary check*/ ++ath5k_hw_set_def_antenna(struct ath5k_hw *ah, unsigned int ant) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ /*Just a try M.F.*/ ++ if (ah->ah_version != AR5K_AR5210) ++ ath5k_hw_reg_write(ah, ant, AR5K_DEFAULT_ANTENNA); ++} ++ ++unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ /*Just a try M.F.*/ ++ if (ah->ah_version != AR5K_AR5210) ++ return ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA); ++ ++ return false; /*XXX: What do we return for 5210 ?*/ ++} ++ ++/* ++ * TX power setup ++ */ ++ ++/* ++ * Initialize the tx power table (not fully implemented) ++ */ ++static void ath5k_txpower_table(struct ath5k_hw *ah, ++ struct ieee80211_channel *channel, s16 max_power) ++{ ++ unsigned int i, min, max, n; ++ u16 txpower, *rates; ++ ++ rates = ah->ah_txpower.txp_rates; ++ ++ txpower = AR5K_TUNE_DEFAULT_TXPOWER * 2; ++ if (max_power > txpower) ++ txpower = max_power > AR5K_TUNE_MAX_TXPOWER ? ++ AR5K_TUNE_MAX_TXPOWER : max_power; ++ ++ for (i = 0; i < AR5K_MAX_RATES; i++) ++ rates[i] = txpower; ++ ++ /* XXX setup target powers by rate */ ++ ++ ah->ah_txpower.txp_min = rates[7]; ++ ah->ah_txpower.txp_max = rates[0]; ++ ah->ah_txpower.txp_ofdm = rates[0]; ++ ++ /* Calculate the power table */ ++ n = ARRAY_SIZE(ah->ah_txpower.txp_pcdac); ++ min = AR5K_EEPROM_PCDAC_START; ++ max = AR5K_EEPROM_PCDAC_STOP; ++ for (i = 0; i < n; i += AR5K_EEPROM_PCDAC_STEP) ++ ah->ah_txpower.txp_pcdac[i] = ++#ifdef notyet ++ min + ((i * (max - min)) / n); ++#else ++ min; ++#endif ++} ++ ++/* ++ * Set transmition power ++ */ ++int /*O.K. - txpower_table is unimplemented so this doesn't work*/ ++ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, ++ unsigned int txpower) ++{ ++ bool tpc = ah->ah_txpower.txp_tpc; ++ unsigned int i; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ if (txpower > AR5K_TUNE_MAX_TXPOWER) { ++ ATH5K_ERR(ah->ah_sc, "invalid tx power: %u\n", txpower); ++ return -EINVAL; ++ } ++ ++ /* Reset TX power values */ ++ memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower)); ++ ah->ah_txpower.txp_tpc = tpc; ++ ++ /* Initialize TX power table */ ++ ath5k_txpower_table(ah, channel, txpower); ++ ++ /* ++ * Write TX power values ++ */ ++ for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) { ++ ath5k_hw_reg_write(ah, ++ ((((ah->ah_txpower.txp_pcdac[(i << 1) + 1] << 8) | 0xff) & 0xffff) << 16) | ++ (((ah->ah_txpower.txp_pcdac[(i << 1) ] << 8) | 0xff) & 0xffff), ++ AR5K_PHY_PCDAC_TXPOWER(i)); ++ } ++ ++ ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(3, 24) | ++ AR5K_TXPOWER_OFDM(2, 16) | AR5K_TXPOWER_OFDM(1, 8) | ++ AR5K_TXPOWER_OFDM(0, 0), AR5K_PHY_TXPOWER_RATE1); ++ ++ ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(7, 24) | ++ AR5K_TXPOWER_OFDM(6, 16) | AR5K_TXPOWER_OFDM(5, 8) | ++ AR5K_TXPOWER_OFDM(4, 0), AR5K_PHY_TXPOWER_RATE2); ++ ++ ath5k_hw_reg_write(ah, AR5K_TXPOWER_CCK(10, 24) | ++ AR5K_TXPOWER_CCK(9, 16) | AR5K_TXPOWER_CCK(15, 8) | ++ AR5K_TXPOWER_CCK(8, 0), AR5K_PHY_TXPOWER_RATE3); ++ ++ ath5k_hw_reg_write(ah, AR5K_TXPOWER_CCK(14, 24) | ++ AR5K_TXPOWER_CCK(13, 16) | AR5K_TXPOWER_CCK(12, 8) | ++ AR5K_TXPOWER_CCK(11, 0), AR5K_PHY_TXPOWER_RATE4); ++ ++ if (ah->ah_txpower.txp_tpc == true) ++ ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE | ++ AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX); ++ else ++ ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX | ++ AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX); ++ ++ return 0; ++} ++ ++int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, unsigned int power) ++{ ++ /*Just a try M.F.*/ ++ struct ieee80211_channel *channel = &ah->ah_current_channel; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_TXPOWER, ++ "changing txpower to %d\n", power); ++ ++ return ath5k_hw_txpower(ah, channel, power); ++} +diff -up /dev/null linux-2.6.23.noarch/drivers/net/wireless/ath5k/ath5k.h +--- /dev/null 2007-12-21 08:33:07.834165456 -0500 ++++ linux-2.6.23.noarch/drivers/net/wireless/ath5k/ath5k.h 2007-12-21 12:18:50.000000000 -0500 +@@ -0,0 +1,1153 @@ ++/* ++ * Copyright (c) 2004-2007 Reyk Floeter ++ * Copyright (c) 2006-2007 Nick Kossifidis ++ * ++ * Permission to use, copy, modify, and 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 _ATH5K_H ++#define _ATH5K_H ++ ++/* Set this to 1 to disable regulatory domain restrictions for channel tests. ++ * WARNING: This is for debuging only and has side effects (eg. scan takes too ++ * long and results timeouts). It's also illegal to tune to some of the ++ * supported frequencies in some countries, so use this at your own risk, ++ * you've been warned. */ ++#define CHAN_DEBUG 0 ++ ++#include ++#include ++#include ++ ++#include "hw.h" ++#include "regdom.h" ++ ++/* PCI IDs */ ++#define PCI_DEVICE_ID_ATHEROS_AR5210 0x0007 /* AR5210 */ ++#define PCI_DEVICE_ID_ATHEROS_AR5311 0x0011 /* AR5311 */ ++#define PCI_DEVICE_ID_ATHEROS_AR5211 0x0012 /* AR5211 */ ++#define PCI_DEVICE_ID_ATHEROS_AR5212 0x0013 /* AR5212 */ ++#define PCI_DEVICE_ID_3COM_3CRDAG675 0x0013 /* 3CRDAG675 (Atheros AR5212) */ ++#define PCI_DEVICE_ID_3COM_2_3CRPAG175 0x0013 /* 3CRPAG175 (Atheros AR5212) */ ++#define PCI_DEVICE_ID_ATHEROS_AR5210_AP 0x0207 /* AR5210 (Early) */ ++#define PCI_DEVICE_ID_ATHEROS_AR5212_IBM 0x1014 /* AR5212 (IBM MiniPCI) */ ++#define PCI_DEVICE_ID_ATHEROS_AR5210_DEFAULT 0x1107 /* AR5210 (no eeprom) */ ++#define PCI_DEVICE_ID_ATHEROS_AR5212_DEFAULT 0x1113 /* AR5212 (no eeprom) */ ++#define PCI_DEVICE_ID_ATHEROS_AR5211_DEFAULT 0x1112 /* AR5211 (no eeprom) */ ++#define PCI_DEVICE_ID_ATHEROS_AR5212_FPGA 0xf013 /* AR5212 (emulation board) */ ++#define PCI_DEVICE_ID_ATHEROS_AR5211_LEGACY 0xff12 /* AR5211 (emulation board) */ ++#define PCI_DEVICE_ID_ATHEROS_AR5211_FPGA11B 0xf11b /* AR5211 (emulation board) */ ++#define PCI_DEVICE_ID_ATHEROS_AR5312_REV2 0x0052 /* AR5312 WMAC (AP31) */ ++#define PCI_DEVICE_ID_ATHEROS_AR5312_REV7 0x0057 /* AR5312 WMAC (AP30-040) */ ++#define PCI_DEVICE_ID_ATHEROS_AR5312_REV8 0x0058 /* AR5312 WMAC (AP43-030) */ ++#define PCI_DEVICE_ID_ATHEROS_AR5212_0014 0x0014 /* AR5212 compatible */ ++#define PCI_DEVICE_ID_ATHEROS_AR5212_0015 0x0015 /* AR5212 compatible */ ++#define PCI_DEVICE_ID_ATHEROS_AR5212_0016 0x0016 /* AR5212 compatible */ ++#define PCI_DEVICE_ID_ATHEROS_AR5212_0017 0x0017 /* AR5212 compatible */ ++#define PCI_DEVICE_ID_ATHEROS_AR5212_0018 0x0018 /* AR5212 compatible */ ++#define PCI_DEVICE_ID_ATHEROS_AR5212_0019 0x0019 /* AR5212 compatible */ ++#define PCI_DEVICE_ID_ATHEROS_AR2413 0x001a /* AR2413 (Griffin-lite) */ ++#define PCI_DEVICE_ID_ATHEROS_AR5413 0x001b /* AR5413 (Eagle) */ ++#define PCI_DEVICE_ID_ATHEROS_AR5424 0x001c /* AR5424 (Condor PCI-E) */ ++#define PCI_DEVICE_ID_ATHEROS_AR5416 0x0023 /* AR5416 */ ++#define PCI_DEVICE_ID_ATHEROS_AR5418 0x0024 /* AR5418 */ ++ ++/****************************\ ++ GENERIC DRIVER DEFINITIONS ++\****************************/ ++ ++#define ATH5K_PRINTF(fmt, ...) printk("%s: " fmt, __func__, ##__VA_ARGS__) ++ ++#define ATH5K_PRINTK(_sc, _level, _fmt, ...) \ ++ printk(_level "ath5k %s: " _fmt, \ ++ ((_sc) && (_sc)->hw) ? wiphy_name((_sc)->hw->wiphy) : "", \ ++ ##__VA_ARGS__) ++ ++#define ATH5K_PRINTK_LIMIT(_sc, _level, _fmt, ...) do { \ ++ if (net_ratelimit()) \ ++ ATH5K_PRINTK(_sc, _level, _fmt, ##__VA_ARGS__); \ ++ } while (0) ++ ++#define ATH5K_INFO(_sc, _fmt, ...) \ ++ ATH5K_PRINTK(_sc, KERN_INFO, _fmt, ##__VA_ARGS__) ++ ++#define ATH5K_WARN(_sc, _fmt, ...) \ ++ ATH5K_PRINTK_LIMIT(_sc, KERN_WARNING, _fmt, ##__VA_ARGS__) ++ ++#define ATH5K_ERR(_sc, _fmt, ...) \ ++ ATH5K_PRINTK_LIMIT(_sc, KERN_ERR, _fmt, ##__VA_ARGS__) ++ ++/* ++ * Some tuneable values (these should be changeable by the user) ++ */ ++#define AR5K_TUNE_DMA_BEACON_RESP 2 ++#define AR5K_TUNE_SW_BEACON_RESP 10 ++#define AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF 0 ++#define AR5K_TUNE_RADAR_ALERT false ++#define AR5K_TUNE_MIN_TX_FIFO_THRES 1 ++#define AR5K_TUNE_MAX_TX_FIFO_THRES ((IEEE80211_MAX_LEN / 64) + 1) ++#define AR5K_TUNE_REGISTER_TIMEOUT 20000 ++/* Register for RSSI threshold has a mask of 0xff, so 255 seems to ++ * be the max value. */ ++#define AR5K_TUNE_RSSI_THRES 129 ++/* This must be set when setting the RSSI threshold otherwise it can ++ * prevent a reset. If AR5K_RSSI_THR is read after writing to it ++ * the BMISS_THRES will be seen as 0, seems harware doesn't keep ++ * track of it. Max value depends on harware. For AR5210 this is just 7. ++ * For AR5211+ this seems to be up to 255. */ ++#define AR5K_TUNE_BMISS_THRES 7 ++#define AR5K_TUNE_REGISTER_DWELL_TIME 20000 ++#define AR5K_TUNE_BEACON_INTERVAL 100 ++#define AR5K_TUNE_AIFS 2 ++#define AR5K_TUNE_AIFS_11B 2 ++#define AR5K_TUNE_AIFS_XR 0 ++#define AR5K_TUNE_CWMIN 15 ++#define AR5K_TUNE_CWMIN_11B 31 ++#define AR5K_TUNE_CWMIN_XR 3 ++#define AR5K_TUNE_CWMAX 1023 ++#define AR5K_TUNE_CWMAX_11B 1023 ++#define AR5K_TUNE_CWMAX_XR 7 ++#define AR5K_TUNE_NOISE_FLOOR -72 ++#define AR5K_TUNE_MAX_TXPOWER 60 ++#define AR5K_TUNE_DEFAULT_TXPOWER 30 ++#define AR5K_TUNE_TPC_TXPOWER true ++#define AR5K_TUNE_ANT_DIVERSITY true ++#define AR5K_TUNE_HWTXTRIES 4 ++ ++/* token to use for aifs, cwmin, cwmax in MadWiFi */ ++#define AR5K_TXQ_USEDEFAULT ((u32) -1) ++ ++/* GENERIC CHIPSET DEFINITIONS */ ++ ++/* MAC Chips */ ++enum ath5k_version { ++ AR5K_AR5210 = 0, ++ AR5K_AR5211 = 1, ++ AR5K_AR5212 = 2, ++}; ++ ++/* PHY Chips */ ++enum ath5k_radio { ++ AR5K_RF5110 = 0, ++ AR5K_RF5111 = 1, ++ AR5K_RF5112 = 2, ++ AR5K_RF5413 = 3, ++}; ++ ++/* ++ * Common silicon revision/version values ++ */ ++ ++enum ath5k_srev_type { ++ AR5K_VERSION_VER, ++ AR5K_VERSION_RAD, ++}; ++ ++struct ath5k_srev_name { ++ const char *sr_name; ++ enum ath5k_srev_type sr_type; ++ u_int sr_val; ++}; ++ ++#define AR5K_SREV_UNKNOWN 0xffff ++ ++#define AR5K_SREV_VER_AR5210 0x00 ++#define AR5K_SREV_VER_AR5311 0x10 ++#define AR5K_SREV_VER_AR5311A 0x20 ++#define AR5K_SREV_VER_AR5311B 0x30 ++#define AR5K_SREV_VER_AR5211 0x40 ++#define AR5K_SREV_VER_AR5212 0x50 ++#define AR5K_SREV_VER_AR5213 0x55 ++#define AR5K_SREV_VER_AR5213A 0x59 ++#define AR5K_SREV_VER_AR2424 0xa0 ++#define AR5K_SREV_VER_AR5424 0xa3 ++#define AR5K_SREV_VER_AR5413 0xa4 ++#define AR5K_SREV_VER_AR5414 0xa5 ++#define AR5K_SREV_VER_AR5416 0xc0 /* ? */ ++#define AR5K_SREV_VER_AR5418 0xca ++ ++#define AR5K_SREV_RAD_5110 0x00 ++#define AR5K_SREV_RAD_5111 0x10 ++#define AR5K_SREV_RAD_5111A 0x15 ++#define AR5K_SREV_RAD_2111 0x20 ++#define AR5K_SREV_RAD_5112 0x30 ++#define AR5K_SREV_RAD_5112A 0x35 ++#define AR5K_SREV_RAD_2112 0x40 ++#define AR5K_SREV_RAD_2112A 0x45 ++#define AR5K_SREV_RAD_SC1 0x63 /* Found on 5413/5414 */ ++#define AR5K_SREV_RAD_SC2 0xa2 /* Found on 2424/5424 */ ++#define AR5K_SREV_RAD_5133 0xc0 /* MIMO found on 5418 */ ++ ++/* IEEE defs */ ++ ++#define IEEE80211_MAX_LEN 2500 ++ ++/* TODO add support to mac80211 for vendor-specific rates and modes */ ++ ++/* ++ * Some of this information is based on Documentation from: ++ * ++ * http://madwifi.org/wiki/ChipsetFeatures/SuperAG ++ * ++ * Modulation for Atheros' eXtended Range - range enhancing extension that is ++ * supposed to double the distance an Atheros client device can keep a ++ * connection with an Atheros access point. This is achieved by increasing ++ * the receiver sensitivity up to, -105dBm, which is about 20dB above what ++ * the 802.11 specifications demand. In addition, new (proprietary) data rates ++ * are introduced: 3, 2, 1, 0.5 and 0.25 MBit/s. ++ * ++ * Please note that can you either use XR or TURBO but you cannot use both, ++ * they are exclusive. ++ * ++ */ ++#define MODULATION_XR 0x00000200 ++/* ++ * Modulation for Atheros' Turbo G and Turbo A, its supposed to provide a ++ * throughput transmission speed up to 40Mbit/s-60Mbit/s at a 108Mbit/s ++ * signaling rate achieved through the bonding of two 54Mbit/s 802.11g ++ * channels. To use this feature your Access Point must also suport it. ++ * There is also a distinction between "static" and "dynamic" turbo modes: ++ * ++ * - Static: is the dumb version: devices set to this mode stick to it until ++ * the mode is turned off. ++ * - Dynamic: is the intelligent version, the network decides itself if it ++ * is ok to use turbo. As soon as traffic is detected on adjacent channels ++ * (which would get used in turbo mode), or when a non-turbo station joins ++ * the network, turbo mode won't be used until the situation changes again. ++ * Dynamic mode is achieved by Atheros' Adaptive Radio (AR) feature which ++ * monitors the used radio band in order to decide whether turbo mode may ++ * be used or not. ++ * ++ * This article claims Super G sticks to bonding of channels 5 and 6 for ++ * USA: ++ * ++ * http://www.pcworld.com/article/id,113428-page,1/article.html ++ * ++ * The channel bonding seems to be driver specific though. In addition to ++ * deciding what channels will be used, these "Turbo" modes are accomplished ++ * by also enabling the following features: ++ * ++ * - Bursting: allows multiple frames to be sent at once, rather than pausing ++ * after each frame. Bursting is a standards-compliant feature that can be ++ * used with any Access Point. ++ * - Fast frames: increases the amount of information that can be sent per ++ * frame, also resulting in a reduction of transmission overhead. It is a ++ * proprietary feature that needs to be supported by the Access Point. ++ * - Compression: data frames are compressed in real time using a Lempel Ziv ++ * algorithm. This is done transparently. Once this feature is enabled, ++ * compression and decompression takes place inside the chipset, without ++ * putting additional load on the host CPU. ++ * ++ */ ++#define MODULATION_TURBO 0x00000080 ++ ++enum ath5k_vendor_mode { ++ MODE_ATHEROS_TURBO = NUM_IEEE80211_MODES+1, ++ MODE_ATHEROS_TURBOG ++}; ++ ++/* Number of supported mac80211 enum ieee80211_phymode modes by this driver */ ++#define NUM_DRIVER_MODES 3 ++ ++/* adding this flag to rate_code enables short preamble, see ar5212_reg.h */ ++#define AR5K_SET_SHORT_PREAMBLE 0x04 ++ ++#define HAS_SHPREAMBLE(_ix) (rt->rates[_ix].modulation == IEEE80211_RATE_CCK_2) ++#define SHPREAMBLE_FLAG(_ix) (HAS_SHPREAMBLE(_ix) ? AR5K_SET_SHORT_PREAMBLE : 0) ++ ++/****************\ ++ TX DEFINITIONS ++\****************/ ++ ++/* ++ * Tx Descriptor ++ */ ++struct ath5k_tx_status { ++ u16 ts_seqnum; ++ u16 ts_tstamp; ++ u8 ts_status; ++ u8 ts_rate; ++ s8 ts_rssi; ++ u8 ts_shortretry; ++ u8 ts_longretry; ++ u8 ts_virtcol; ++ u8 ts_antenna; ++}; ++ ++#define AR5K_TXSTAT_ALTRATE 0x80 ++#define AR5K_TXERR_XRETRY 0x01 ++#define AR5K_TXERR_FILT 0x02 ++#define AR5K_TXERR_FIFO 0x04 ++ ++/* ++ * Queue types used to classify tx queues. ++ */ ++enum ath5k_tx_queue { ++ AR5K_TX_QUEUE_INACTIVE = 0, /* q is unused -- see ath5k_hw_release_tx_queue */ ++ AR5K_TX_QUEUE_DATA, /*A normal data queue*/ ++ AR5K_TX_QUEUE_XR_DATA, /*An XR-data queue*/ ++ AR5K_TX_QUEUE_BEACON, /*The beacon queue*/ ++ AR5K_TX_QUEUE_CAB, /*The ater-beacon queue*/ ++ AR5K_TX_QUEUE_UAPSD, /*Unscheduled Automatic Power Save Delivery queue*/ ++}; ++ ++#define AR5K_NUM_TX_QUEUES 10 ++#define AR5K_NUM_TX_QUEUES_NOQCU 2 ++ ++/* ++ * Queue syb-types to classify normal data queues. ++ * These are the 4 Access Categories as defined in ++ * WME spec. 0 is the lowest priority and 4 is the ++ * highest. Normal data that hasn't been classified ++ * goes to the Best Effort AC. ++ */ ++enum ath5k_tx_queue_subtype { ++ AR5K_WME_AC_BK = 0, /*Background traffic*/ ++ AR5K_WME_AC_BE, /*Best-effort (normal) traffic)*/ ++ AR5K_WME_AC_VI, /*Video traffic*/ ++ AR5K_WME_AC_VO, /*Voice traffic*/ ++}; ++ ++/* ++ * Queue ID numbers as returned by the hw functions, each number ++ * represents a hw queue. If hw does not support hw queues ++ * (eg 5210) all data goes in one queue. These match ++ * d80211 definitions (net80211/MadWiFi don't use them). ++ */ ++enum ath5k_tx_queue_id { ++ AR5K_TX_QUEUE_ID_NOQCU_DATA = 0, ++ AR5K_TX_QUEUE_ID_NOQCU_BEACON = 1, ++ AR5K_TX_QUEUE_ID_DATA_MIN = 0, /*IEEE80211_TX_QUEUE_DATA0*/ ++ AR5K_TX_QUEUE_ID_DATA_MAX = 4, /*IEEE80211_TX_QUEUE_DATA4*/ ++ AR5K_TX_QUEUE_ID_DATA_SVP = 5, /*IEEE80211_TX_QUEUE_SVP - Spectralink Voice Protocol*/ ++ AR5K_TX_QUEUE_ID_CAB = 6, /*IEEE80211_TX_QUEUE_AFTER_BEACON*/ ++ AR5K_TX_QUEUE_ID_BEACON = 7, /*IEEE80211_TX_QUEUE_BEACON*/ ++ AR5K_TX_QUEUE_ID_UAPSD = 8, ++ AR5K_TX_QUEUE_ID_XR_DATA = 9, ++}; ++ ++ ++/* ++ * Flags to set hw queue's parameters... ++ */ ++#define AR5K_TXQ_FLAG_TXOKINT_ENABLE 0x0001 /* Enable TXOK interrupt */ ++#define AR5K_TXQ_FLAG_TXERRINT_ENABLE 0x0002 /* Enable TXERR interrupt */ ++#define AR5K_TXQ_FLAG_TXEOLINT_ENABLE 0x0004 /* Enable TXEOL interrupt -not used- */ ++#define AR5K_TXQ_FLAG_TXDESCINT_ENABLE 0x0008 /* Enable TXDESC interrupt -not used- */ ++#define AR5K_TXQ_FLAG_TXURNINT_ENABLE 0x0010 /* Enable TXURN interrupt */ ++#define AR5K_TXQ_FLAG_BACKOFF_DISABLE 0x0020 /* Disable random post-backoff */ ++#define AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE 0x0040 /* Enable ready time expiry policy (?)*/ ++#define AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE 0x0080 /* Enable backoff while bursting */ ++#define AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS 0x0100 /* Disable backoff while bursting */ ++#define AR5K_TXQ_FLAG_COMPRESSION_ENABLE 0x0200 /* Enable hw compression -not implemented-*/ ++ ++/* ++ * A struct to hold tx queue's parameters ++ */ ++struct ath5k_txq_info { ++ enum ath5k_tx_queue tqi_type; ++ enum ath5k_tx_queue_subtype tqi_subtype; ++ u16 tqi_flags; /* Tx queue flags (see above) */ ++ u32 tqi_aifs; /* Arbitrated Interframe Space */ ++ s32 tqi_cw_min; /* Minimum Contention Window */ ++ s32 tqi_cw_max; /* Maximum Contention Window */ ++ u32 tqi_cbr_period; /* Constant bit rate period */ ++ u32 tqi_cbr_overflow_limit; ++ u32 tqi_burst_time; ++ u32 tqi_ready_time; /* Not used */ ++}; ++ ++/* ++ * Transmit packet types. ++ * These are not fully used inside OpenHAL yet ++ */ ++enum ath5k_pkt_type { ++ AR5K_PKT_TYPE_NORMAL = 0, ++ AR5K_PKT_TYPE_ATIM = 1, ++ AR5K_PKT_TYPE_PSPOLL = 2, ++ AR5K_PKT_TYPE_BEACON = 3, ++ AR5K_PKT_TYPE_PROBE_RESP = 4, ++ AR5K_PKT_TYPE_PIFS = 5, ++}; ++ ++/* ++ * TX power and TPC settings ++ */ ++#define AR5K_TXPOWER_OFDM(_r, _v) ( \ ++ ((0 & 1) << ((_v) + 6)) | \ ++ (((ah->ah_txpower.txp_rates[(_r)]) & 0x3f) << (_v)) \ ++) ++ ++#define AR5K_TXPOWER_CCK(_r, _v) ( \ ++ (ah->ah_txpower.txp_rates[(_r)] & 0x3f) << (_v) \ ++) ++ ++/* ++ * DMA size definitions (2^n+2) ++ */ ++enum ath5k_dmasize { ++ AR5K_DMASIZE_4B = 0, ++ AR5K_DMASIZE_8B, ++ AR5K_DMASIZE_16B, ++ AR5K_DMASIZE_32B, ++ AR5K_DMASIZE_64B, ++ AR5K_DMASIZE_128B, ++ AR5K_DMASIZE_256B, ++ AR5K_DMASIZE_512B ++}; ++ ++ ++/****************\ ++ RX DEFINITIONS ++\****************/ ++ ++/* ++ * Rx Descriptor ++ */ ++struct ath5k_rx_status { ++ u16 rs_datalen; ++ u16 rs_tstamp; ++ u8 rs_status; ++ u8 rs_phyerr; ++ s8 rs_rssi; ++ u8 rs_keyix; ++ u8 rs_rate; ++ u8 rs_antenna; ++ u8 rs_more; ++}; ++ ++#define AR5K_RXERR_CRC 0x01 ++#define AR5K_RXERR_PHY 0x02 ++#define AR5K_RXERR_FIFO 0x04 ++#define AR5K_RXERR_DECRYPT 0x08 ++#define AR5K_RXERR_MIC 0x10 ++#define AR5K_RXKEYIX_INVALID ((u8) - 1) ++#define AR5K_TXKEYIX_INVALID ((u32) - 1) ++ ++struct ath5k_mib_stats { ++ u32 ackrcv_bad; ++ u32 rts_bad; ++ u32 rts_good; ++ u32 fcs_bad; ++ u32 beacons; ++}; ++ ++ ++ ++ ++/**************************\ ++ BEACON TIMERS DEFINITIONS ++\**************************/ ++ ++#define AR5K_BEACON_PERIOD 0x0000ffff ++#define AR5K_BEACON_ENA 0x00800000 /*enable beacon xmit*/ ++#define AR5K_BEACON_RESET_TSF 0x01000000 /*force a TSF reset*/ ++ ++/* ++ * Per-station beacon timer state. ++ */ ++struct ath5k_beacon_state { ++ u32 bs_next_beacon; ++ u32 bs_next_dtim; ++ u32 bs_interval; /*in TU's -see net80211/ieee80211_var.h- ++ can also include the above flags*/ ++ u8 bs_dtim_period; ++ u8 bs_cfp_period; ++ u16 bs_cfp_max_duration; /*if non-zero hw is setup to coexist with ++ a Point Coordination Function capable AP*/ ++ u16 bs_cfp_du_remain; ++ u16 bs_tim_offset; ++ u16 bs_sleep_duration; ++ u16 bs_bmiss_threshold; ++ u32 bs_cfp_next; ++}; ++ ++ ++ ++ ++/********************\ ++ COMMON DEFINITIONS ++\********************/ ++ ++/* ++ * Atheros descriptor ++ */ ++struct ath5k_desc { ++ u32 ds_link; ++ u32 ds_data; ++ u32 ds_ctl0; ++ u32 ds_ctl1; ++ u32 ds_hw[4]; ++ ++ union { ++ struct ath5k_rx_status rx; ++ struct ath5k_tx_status tx; ++ } ds_us; ++ ++#define ds_rxstat ds_us.rx ++#define ds_txstat ds_us.tx ++ ++} __packed; ++ ++#define AR5K_RXDESC_INTREQ 0x0020 ++ ++#define AR5K_TXDESC_CLRDMASK 0x0001 ++#define AR5K_TXDESC_NOACK 0x0002 /*[5211+]*/ ++#define AR5K_TXDESC_RTSENA 0x0004 ++#define AR5K_TXDESC_CTSENA 0x0008 ++#define AR5K_TXDESC_INTREQ 0x0010 ++#define AR5K_TXDESC_VEOL 0x0020 /*[5211+]*/ ++ ++#define AR5K_SLOT_TIME_9 396 ++#define AR5K_SLOT_TIME_20 880 ++#define AR5K_SLOT_TIME_MAX 0xffff ++ ++/* channel_flags */ ++#define CHANNEL_CW_INT 0x0008 /* Contention Window interference detected */ ++#define CHANNEL_TURBO 0x0010 /* Turbo Channel */ ++#define CHANNEL_CCK 0x0020 /* CCK channel */ ++#define CHANNEL_OFDM 0x0040 /* OFDM channel */ ++#define CHANNEL_2GHZ 0x0080 /* 2GHz channel. */ ++#define CHANNEL_5GHZ 0x0100 /* 5GHz channel */ ++#define CHANNEL_PASSIVE 0x0200 /* Only passive scan allowed */ ++#define CHANNEL_DYN 0x0400 /* Dynamic CCK-OFDM channel (for g operation) */ ++#define CHANNEL_XR 0x0800 /* XR channel */ ++ ++#define CHANNEL_A (CHANNEL_5GHZ|CHANNEL_OFDM) ++#define CHANNEL_B (CHANNEL_2GHZ|CHANNEL_CCK) ++#define CHANNEL_G (CHANNEL_2GHZ|CHANNEL_OFDM) ++#define CHANNEL_T (CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_TURBO) ++#define CHANNEL_TG (CHANNEL_2GHZ|CHANNEL_OFDM|CHANNEL_TURBO) ++#define CHANNEL_108A CHANNEL_T ++#define CHANNEL_108G CHANNEL_TG ++#define CHANNEL_X (CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_XR) ++ ++#define CHANNEL_ALL (CHANNEL_OFDM|CHANNEL_CCK|CHANNEL_2GHZ|CHANNEL_5GHZ| \ ++ CHANNEL_TURBO) ++ ++#define CHANNEL_ALL_NOTURBO (CHANNEL_ALL & ~CHANNEL_TURBO) ++#define CHANNEL_MODES CHANNEL_ALL ++ ++/* ++ * Used internaly in OpenHAL (ar5211.c/ar5212.c ++ * for reset_tx_queue). Also see struct struct ieee80211_channel. ++ */ ++#define IS_CHAN_XR(_c) ((_c.val & CHANNEL_XR) != 0) ++#define IS_CHAN_B(_c) ((_c.val & CHANNEL_B) != 0) ++ ++/* ++ * The following structure will be used to map 2GHz channels to ++ * 5GHz Atheros channels. ++ */ ++struct ath5k_athchan_2ghz { ++ u32 a2_flags; ++ u16 a2_athchan; ++}; ++ ++/* ++ * Rate definitions ++ * TODO: Clean them up or move them on mac80211 -most of these infos are ++ * used by the rate control algorytm on MadWiFi. ++ */ ++ ++/* Max number of rates on the rate table and what it seems ++ * Atheros hardware supports */ ++#define AR5K_MAX_RATES 32 ++ ++/** ++ * struct ath5k_rate - rate structure ++ * @valid: is this a valid rate for the current mode ++ * @modulation: respective mac80211 modulation ++ * @rate_kbps: rate in kbit/s ++ * @rate_code: hardware rate value, used in &struct ath5k_desc, on RX on ++ * &struct ath5k_rx_status.rs_rate and on TX on ++ * &struct ath5k_tx_status.ts_rate. Seems the ar5xxx harware supports ++ * up to 32 rates, indexed by 1-32. This means we really only need ++ * 6 bits for the rate_code. ++ * @dot11_rate: respective IEEE-802.11 rate value ++ * @control_rate: index of rate assumed to be used to send control frames. ++ * This can be used to set override the value on the rate duration ++ * registers. This is only useful if we can override in the harware at ++ * what rate we want to send control frames at. Note that IEEE-802.11 ++ * Ch. 9.6 (after IEEE 802.11g changes) defines the rate at which we ++ * should send ACK/CTS, if we change this value we can be breaking ++ * the spec. ++ * ++ * This structure is used to get the RX rate or set the TX rate on the ++ * hardware descriptors. It is also used for internal modulation control ++ * and settings. ++ * ++ * On RX after the &struct ath5k_desc is parsed by the appropriate ++ * ah_proc_rx_desc() the respective hardware rate value is set in ++ * &struct ath5k_rx_status.rs_rate. On TX the desired rate is set in ++ * &struct ath5k_tx_status.ts_rate which is later used to setup the ++ * &struct ath5k_desc correctly. This is the hardware rate map we are ++ * aware of: ++ * ++ * rate_code 1 2 3 4 5 6 7 8 ++ * rate_kbps 3000 1000 ? ? ? 2000 500 48000 ++ * ++ * rate_code 9 10 11 12 13 14 15 16 ++ * rate_kbps 24000 12000 6000 54000 36000 18000 9000 ? ++ * ++ * rate_code 17 18 19 20 21 22 23 24 ++ * rate_kbps ? ? ? ? ? ? ? 11000 ++ * ++ * rate_code 25 26 27 28 29 30 31 32 ++ * rate_kbps 5500 2000 1000 ? ? ? ? ? ++ * ++ */ ++struct ath5k_rate { ++ u8 valid; ++ u32 modulation; ++ u16 rate_kbps; ++ u8 rate_code; ++ u8 dot11_rate; ++ u8 control_rate; ++}; ++ ++/* XXX: GRR all this stuff to get leds blinking ??? (check out setcurmode) */ ++struct ath5k_rate_table { ++ u16 rate_count; ++ u8 rate_code_to_index[AR5K_MAX_RATES]; /* Back-mapping */ ++ struct ath5k_rate rates[AR5K_MAX_RATES]; ++}; ++ ++/* ++ * Rate tables... ++ */ ++#define AR5K_RATES_11A { 8, { \ ++ 255, 255, 255, 255, 255, 255, 255, 255, 6, 4, 2, 0, \ ++ 7, 5, 3, 1, 255, 255, 255, 255, 255, 255, 255, 255, \ ++ 255, 255, 255, 255, 255, 255, 255, 255 }, { \ ++ { 1, IEEE80211_RATE_OFDM, 6000, 11, 140, 0 }, \ ++ { 1, IEEE80211_RATE_OFDM, 9000, 15, 18, 0 }, \ ++ { 1, IEEE80211_RATE_OFDM, 12000, 10, 152, 2 }, \ ++ { 1, IEEE80211_RATE_OFDM, 18000, 14, 36, 2 }, \ ++ { 1, IEEE80211_RATE_OFDM, 24000, 9, 176, 4 }, \ ++ { 1, IEEE80211_RATE_OFDM, 36000, 13, 72, 4 }, \ ++ { 1, IEEE80211_RATE_OFDM, 48000, 8, 96, 4 }, \ ++ { 1, IEEE80211_RATE_OFDM, 54000, 12, 108, 4 } } \ ++} ++ ++#define AR5K_RATES_11B { 4, { \ ++ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, \ ++ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, \ ++ 3, 2, 1, 0, 255, 255, 255, 255 }, { \ ++ { 1, IEEE80211_RATE_CCK, 1000, 27, 130, 0 }, \ ++ { 1, IEEE80211_RATE_CCK_2, 2000, 26, 132, 1 }, \ ++ { 1, IEEE80211_RATE_CCK_2, 5500, 25, 139, 1 }, \ ++ { 1, IEEE80211_RATE_CCK_2, 11000, 24, 150, 1 } } \ ++} ++ ++#define AR5K_RATES_11G { 12, { \ ++ 255, 255, 255, 255, 255, 255, 255, 255, 10, 8, 6, 4, \ ++ 11, 9, 7, 5, 255, 255, 255, 255, 255, 255, 255, 255, \ ++ 3, 2, 1, 0, 255, 255, 255, 255 }, { \ ++ { 1, IEEE80211_RATE_CCK, 1000, 27, 2, 0 }, \ ++ { 1, IEEE80211_RATE_CCK_2, 2000, 26, 4, 1 }, \ ++ { 1, IEEE80211_RATE_CCK_2, 5500, 25, 11, 1 }, \ ++ { 1, IEEE80211_RATE_CCK_2, 11000, 24, 22, 1 }, \ ++ { 0, IEEE80211_RATE_OFDM, 6000, 11, 12, 4 }, \ ++ { 0, IEEE80211_RATE_OFDM, 9000, 15, 18, 4 }, \ ++ { 1, IEEE80211_RATE_OFDM, 12000, 10, 24, 6 }, \ ++ { 1, IEEE80211_RATE_OFDM, 18000, 14, 36, 6 }, \ ++ { 1, IEEE80211_RATE_OFDM, 24000, 9, 48, 8 }, \ ++ { 1, IEEE80211_RATE_OFDM, 36000, 13, 72, 8 }, \ ++ { 1, IEEE80211_RATE_OFDM, 48000, 8, 96, 8 }, \ ++ { 1, IEEE80211_RATE_OFDM, 54000, 12, 108, 8 } } \ ++} ++ ++#define AR5K_RATES_TURBO { 8, { \ ++ 255, 255, 255, 255, 255, 255, 255, 255, 6, 4, 2, 0, \ ++ 7, 5, 3, 1, 255, 255, 255, 255, 255, 255, 255, 255, \ ++ 255, 255, 255, 255, 255, 255, 255, 255 }, { \ ++ { 1, MODULATION_TURBO, 6000, 11, 140, 0 }, \ ++ { 1, MODULATION_TURBO, 9000, 15, 18, 0 }, \ ++ { 1, MODULATION_TURBO, 12000, 10, 152, 2 }, \ ++ { 1, MODULATION_TURBO, 18000, 14, 36, 2 }, \ ++ { 1, MODULATION_TURBO, 24000, 9, 176, 4 }, \ ++ { 1, MODULATION_TURBO, 36000, 13, 72, 4 }, \ ++ { 1, MODULATION_TURBO, 48000, 8, 96, 4 }, \ ++ { 1, MODULATION_TURBO, 54000, 12, 108, 4 } } \ ++} ++ ++#define AR5K_RATES_XR { 12, { \ ++ 255, 3, 1, 255, 255, 255, 2, 0, 10, 8, 6, 4, \ ++ 11, 9, 7, 5, 255, 255, 255, 255, 255, 255, 255, 255, \ ++ 255, 255, 255, 255, 255, 255, 255, 255 }, { \ ++ { 1, MODULATION_XR, 500, 7, 129, 0 }, \ ++ { 1, MODULATION_XR, 1000, 2, 139, 1 }, \ ++ { 1, MODULATION_XR, 2000, 6, 150, 2 }, \ ++ { 1, MODULATION_XR, 3000, 1, 150, 3 }, \ ++ { 1, IEEE80211_RATE_OFDM, 6000, 11, 140, 4 }, \ ++ { 1, IEEE80211_RATE_OFDM, 9000, 15, 18, 4 }, \ ++ { 1, IEEE80211_RATE_OFDM, 12000, 10, 152, 6 }, \ ++ { 1, IEEE80211_RATE_OFDM, 18000, 14, 36, 6 }, \ ++ { 1, IEEE80211_RATE_OFDM, 24000, 9, 176, 8 }, \ ++ { 1, IEEE80211_RATE_OFDM, 36000, 13, 72, 8 }, \ ++ { 1, IEEE80211_RATE_OFDM, 48000, 8, 96, 8 }, \ ++ { 1, IEEE80211_RATE_OFDM, 54000, 12, 108, 8 } } \ ++} ++ ++/* ++ * Crypto definitions ++ */ ++ ++#define AR5K_KEYCACHE_SIZE 8 ++ ++/***********************\ ++ HW RELATED DEFINITIONS ++\***********************/ ++ ++/* ++ * Misc definitions ++ */ ++#define AR5K_RSSI_EP_MULTIPLIER (1<<7) ++ ++#define AR5K_ASSERT_ENTRY(_e, _s) do { \ ++ if (_e >= _s) \ ++ return (false); \ ++} while (0) ++ ++ ++enum ath5k_ant_setting { ++ AR5K_ANT_VARIABLE = 0, /* variable by programming */ ++ AR5K_ANT_FIXED_A = 1, /* fixed to 11a frequencies */ ++ AR5K_ANT_FIXED_B = 2, /* fixed to 11b frequencies */ ++ AR5K_ANT_MAX = 3, ++}; ++ ++/* ++ * Hardware interrupt abstraction ++ */ ++ ++/** ++ * enum ath5k_int - Hardware interrupt masks helpers ++ * ++ * @AR5K_INT_RX: mask to identify received frame interrupts, of type ++ * AR5K_ISR_RXOK or AR5K_ISR_RXERR ++ * @AR5K_INT_RXDESC: Request RX descriptor/Read RX descriptor (?) ++ * @AR5K_INT_RXNOFRM: No frame received (?) ++ * @AR5K_INT_RXEOL: received End Of List for VEOL (Virtual End Of List). The ++ * Queue Control Unit (QCU) signals an EOL interrupt only if a descriptor's ++ * LinkPtr is NULL. For more details, refer to: ++ * http://www.freepatentsonline.com/20030225739.html ++ * @AR5K_INT_RXORN: Indicates we got RX overrun (eg. no more descriptors). ++ * Note that Rx overrun is not always fatal, on some chips we can continue ++ * operation without reseting the card, that's why int_fatal is not ++ * common for all chips. ++ * @AR5K_INT_TX: mask to identify received frame interrupts, of type ++ * AR5K_ISR_TXOK or AR5K_ISR_TXERR ++ * @AR5K_INT_TXDESC: Request TX descriptor/Read TX status descriptor (?) ++ * @AR5K_INT_TXURN: received when we should increase the TX trigger threshold ++ * We currently do increments on interrupt by ++ * (AR5K_TUNE_MAX_TX_FIFO_THRES - current_trigger_level) / 2 ++ * @AR5K_INT_MIB: Indicates the Management Information Base counters should be ++ * checked. We should do this with ath5k_hw_update_mib_counters() but ++ * it seems we should also then do some noise immunity work. ++ * @AR5K_INT_RXPHY: RX PHY Error ++ * @AR5K_INT_RXKCM: ?? ++ * @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a ++ * beacon that must be handled in software. The alternative is if you ++ * have VEOL support, in that case you let the hardware deal with things. ++ * @AR5K_INT_BMISS: If in STA mode this indicates we have stopped seeing ++ * beacons from the AP have associated with, we should probably try to ++ * reassociate. When in IBSS mode this might mean we have not received ++ * any beacons from any local stations. Note that every station in an ++ * IBSS schedules to send beacons at the Target Beacon Transmission Time ++ * (TBTT) with a random backoff. ++ * @AR5K_INT_BNR: Beacon Not Ready interrupt - ?? ++ * @AR5K_INT_GPIO: GPIO interrupt is used for RF Kill, disabled for now ++ * until properly handled ++ * @AR5K_INT_FATAL: Fatal errors were encountered, typically caused by DMA ++ * errors. These types of errors we can enable seem to be of type ++ * AR5K_SIMR2_MCABT, AR5K_SIMR2_SSERR and AR5K_SIMR2_DPERR. ++ * @AR5K_INT_GLOBAL: Seems to be used to clear and set the IER ++ * @AR5K_INT_NOCARD: signals the card has been removed ++ * @AR5K_INT_COMMON: common interrupts shared amogst MACs with the same ++ * bit value ++ * ++ * These are mapped to take advantage of some common bits ++ * between the MACs, to be able to set intr properties ++ * easier. Some of them are not used yet inside hw.c. Most map ++ * to the respective hw interrupt value as they are common amogst different ++ * MACs. ++ */ ++enum ath5k_int { ++ AR5K_INT_RX = 0x00000001, /* Not common */ ++ AR5K_INT_RXDESC = 0x00000002, ++ AR5K_INT_RXNOFRM = 0x00000008, ++ AR5K_INT_RXEOL = 0x00000010, ++ AR5K_INT_RXORN = 0x00000020, ++ AR5K_INT_TX = 0x00000040, /* Not common */ ++ AR5K_INT_TXDESC = 0x00000080, ++ AR5K_INT_TXURN = 0x00000800, ++ AR5K_INT_MIB = 0x00001000, ++ AR5K_INT_RXPHY = 0x00004000, ++ AR5K_INT_RXKCM = 0x00008000, ++ AR5K_INT_SWBA = 0x00010000, ++ AR5K_INT_BMISS = 0x00040000, ++ AR5K_INT_BNR = 0x00100000, /* Not common */ ++ AR5K_INT_GPIO = 0x01000000, ++ AR5K_INT_FATAL = 0x40000000, /* Not common */ ++ AR5K_INT_GLOBAL = 0x80000000, ++ ++ AR5K_INT_COMMON = AR5K_INT_RXNOFRM ++ | AR5K_INT_RXDESC ++ | AR5K_INT_RXEOL ++ | AR5K_INT_RXORN ++ | AR5K_INT_TXURN ++ | AR5K_INT_TXDESC ++ | AR5K_INT_MIB ++ | AR5K_INT_RXPHY ++ | AR5K_INT_RXKCM ++ | AR5K_INT_SWBA ++ | AR5K_INT_BMISS ++ | AR5K_INT_GPIO, ++ AR5K_INT_NOCARD = 0xffffffff ++}; ++ ++/* ++ * Power management ++ */ ++enum ath5k_power_mode { ++ AR5K_PM_UNDEFINED = 0, ++ AR5K_PM_AUTO, ++ AR5K_PM_AWAKE, ++ AR5K_PM_FULL_SLEEP, ++ AR5K_PM_NETWORK_SLEEP, ++}; ++ ++/* ++ * These match net80211 definitions (not used in ++ * d80211). ++ */ ++#define AR5K_LED_INIT 0 /*IEEE80211_S_INIT*/ ++#define AR5K_LED_SCAN 1 /*IEEE80211_S_SCAN*/ ++#define AR5K_LED_AUTH 2 /*IEEE80211_S_AUTH*/ ++#define AR5K_LED_ASSOC 3 /*IEEE80211_S_ASSOC*/ ++#define AR5K_LED_RUN 4 /*IEEE80211_S_RUN*/ ++ ++/* GPIO-controlled software LED */ ++#define AR5K_SOFTLED_PIN 0 ++#define AR5K_SOFTLED_ON 0 ++#define AR5K_SOFTLED_OFF 1 ++ ++/* ++ * Chipset capabilities -see ath5k_hw_get_capability- ++ * get_capability function is not yet fully implemented ++ * in OpenHAL so most of these don't work yet... ++ */ ++enum ath5k_capability_type { ++ AR5K_CAP_REG_DMN = 0, /* Used to get current reg. domain id */ ++ AR5K_CAP_TKIP_MIC = 2, /* Can handle TKIP MIC in hardware */ ++ AR5K_CAP_TKIP_SPLIT = 3, /* TKIP uses split keys */ ++ AR5K_CAP_PHYCOUNTERS = 4, /* PHY error counters */ ++ AR5K_CAP_DIVERSITY = 5, /* Supports fast diversity */ ++ AR5K_CAP_NUM_TXQUEUES = 6, /* Used to get max number of hw txqueues */ ++ AR5K_CAP_VEOL = 7, /* Supports virtual EOL */ ++ AR5K_CAP_COMPRESSION = 8, /* Supports compression */ ++ AR5K_CAP_BURST = 9, /* Supports packet bursting */ ++ AR5K_CAP_FASTFRAME = 10, /* Supports fast frames */ ++ AR5K_CAP_TXPOW = 11, /* Used to get global tx power limit */ ++ AR5K_CAP_TPC = 12, /* Can do per-packet tx power control (needed for 802.11a) */ ++ AR5K_CAP_BSSIDMASK = 13, /* Supports bssid mask */ ++ AR5K_CAP_MCAST_KEYSRCH = 14, /* Supports multicast key search */ ++ AR5K_CAP_TSF_ADJUST = 15, /* Supports beacon tsf adjust */ ++ AR5K_CAP_XR = 16, /* Supports XR mode */ ++ AR5K_CAP_WME_TKIPMIC = 17, /* Supports TKIP MIC when using WMM */ ++ AR5K_CAP_CHAN_HALFRATE = 18, /* Supports half rate channels */ ++ AR5K_CAP_CHAN_QUARTERRATE = 19, /* Supports quarter rate channels */ ++ AR5K_CAP_RFSILENT = 20, /* Supports RFsilent */ ++}; ++ ++struct ath5k_capabilities { ++ /* ++ * Supported PHY modes ++ * (ie. CHANNEL_A, CHANNEL_B, ...) ++ */ ++ DECLARE_BITMAP(cap_mode, NUM_DRIVER_MODES); ++ ++ /* ++ * Frequency range (without regulation restrictions) ++ */ ++ struct { ++ u16 range_2ghz_min; ++ u16 range_2ghz_max; ++ u16 range_5ghz_min; ++ u16 range_5ghz_max; ++ } cap_range; ++ ++ /* ++ * Active regulation domain settings ++ */ ++ struct { ++ enum ath5k_regdom reg_current; ++ enum ath5k_regdom reg_hw; ++ } cap_regdomain; ++ ++ /* ++ * Values stored in the EEPROM (some of them...) ++ */ ++ struct ath5k_eeprom_info cap_eeprom; ++ ++ /* ++ * Queue information ++ */ ++ struct { ++ u8 q_tx_num; ++ } cap_queues; ++}; ++ ++ ++/***************************************\ ++ HARDWARE ABSTRACTION LAYER STRUCTURE ++\***************************************/ ++ ++/* ++ * Misc defines ++ */ ++ ++#define AR5K_MAX_GPIO 10 ++#define AR5K_MAX_RF_BANKS 8 ++ ++struct ath5k_hw { ++ u32 ah_magic; ++ ++ struct ath5k_softc *ah_sc; ++ void __iomem *ah_iobase; ++ ++ enum ath5k_int ah_imr; ++ ++ enum ieee80211_if_types ah_op_mode; ++ enum ath5k_power_mode ah_power_mode; ++ struct ieee80211_channel ah_current_channel; ++ /* Current BSSID we are trying to assoc to / creating, this ++ * comes from ieee80211_if_conf. This is passed by mac80211 on ++ * config_interface() */ ++ u8 bssid[ETH_ALEN]; ++ bool ah_turbo; ++ bool ah_calibration; ++ bool ah_running; ++ bool ah_single_chip; ++ enum ath5k_rfgain ah_rf_gain; ++ ++ u32 ah_mac_srev; ++ u16 ah_mac_version; ++ u16 ah_mac_revision; ++ u16 ah_phy_revision; ++ 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_regdomain ah_capabilities.cap_regdomain.reg_current ++#define ah_regdomain_hw ah_capabilities.cap_regdomain.reg_hw ++#define ah_modes ah_capabilities.cap_mode ++#define ah_ee_version ah_capabilities.cap_eeprom.ee_version ++ ++ u32 ah_atim_window; ++ u32 ah_aifs; ++ u32 ah_cw_min; ++ u32 ah_cw_max; ++ bool ah_software_retry; ++ u32 ah_limit_tx_retries; ++ ++ u32 ah_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX]; ++ bool ah_ant_diversity; ++ ++ u8 ah_sta_id[ETH_ALEN]; ++ u8 ah_bssid[ETH_ALEN]; ++ ++ u32 ah_gpio[AR5K_MAX_GPIO]; ++ int ah_gpio_npins; ++ ++ struct ath5k_capabilities ah_capabilities; ++ ++ struct ath5k_txq_info ah_txq[AR5K_NUM_TX_QUEUES]; ++ u32 ah_txq_status; ++ u32 ah_txq_imr_txok; ++ u32 ah_txq_imr_txerr; ++ u32 ah_txq_imr_txurn; ++ u32 ah_txq_imr_txdesc; ++ u32 ah_txq_imr_txeol; ++ u32 *ah_rf_banks; ++ size_t ah_rf_banks_size; ++ struct ath5k_gain ah_gain; ++ u32 ah_offset[AR5K_MAX_RF_BANKS]; ++ ++ struct { ++ u16 txp_pcdac[AR5K_EEPROM_POWER_TABLE_SIZE]; ++ u16 txp_rates[AR5K_MAX_RATES]; ++ s16 txp_min; ++ s16 txp_max; ++ bool txp_tpc; ++ s16 txp_ofdm; ++ } ah_txpower; ++ ++ struct { ++ bool r_enabled; ++ int r_last_alert; ++ struct ieee80211_channel r_last_channel; ++ } ah_radar; ++ ++ /* noise floor from last periodic calibration */ ++ s32 ah_noise_floor; ++ ++ /* ++ * Function pointers ++ */ ++ int (*ah_setup_tx_desc)(struct ath5k_hw *, struct ath5k_desc *, ++ unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int, ++ unsigned int, unsigned int, unsigned int, unsigned int, ++ unsigned int, unsigned int, unsigned int); ++ bool (*ah_setup_xtx_desc)(struct ath5k_hw *, struct ath5k_desc *, ++ unsigned int, unsigned int, unsigned int, unsigned int, ++ unsigned int, unsigned int); ++ int (*ah_proc_tx_desc)(struct ath5k_hw *, struct ath5k_desc *); ++ int (*ah_proc_rx_desc)(struct ath5k_hw *, struct ath5k_desc *); ++}; ++ ++/* ++ * Prototypes ++ */ ++ ++/* General Functions */ ++extern int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val, bool is_set); ++/* Attach/Detach Functions */ ++extern struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version); ++extern const struct ath5k_rate_table *ath5k_hw_get_rate_table(struct ath5k_hw *ah, unsigned int mode); ++extern void ath5k_hw_detach(struct ath5k_hw *ah); ++/* Reset Functions */ ++extern int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types 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); ++/* DMA Related Functions */ ++extern void ath5k_hw_start_rx(struct ath5k_hw *ah); ++extern int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah); ++extern u32 ath5k_hw_get_rx_buf(struct ath5k_hw *ah); ++extern void ath5k_hw_put_rx_buf(struct ath5k_hw *ah, u32 phys_addr); ++extern int ath5k_hw_tx_start(struct ath5k_hw *ah, unsigned int queue); ++extern int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue); ++extern u32 ath5k_hw_get_tx_buf(struct ath5k_hw *ah, unsigned int queue); ++extern int ath5k_hw_put_tx_buf(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr); ++extern int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase); ++/* Interrupt handling */ ++extern bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah); ++extern int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask); ++extern enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask); ++/* EEPROM access functions */ ++extern int ath5k_hw_set_regdomain(struct ath5k_hw *ah, u16 regdomain); ++/* Protocol Control Unit Functions */ ++extern int ath5k_hw_set_opmode(struct ath5k_hw *ah); ++/* BSSID Functions */ ++extern void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac); ++extern int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac); ++extern void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id); ++extern int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask); ++/* Receive start/stop functions */ ++extern void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah); ++extern void ath5k_hw_stop_pcu_recv(struct ath5k_hw *ah); ++/* RX Filter functions */ ++extern void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1); ++extern int ath5k_hw_set_mcast_filterindex(struct ath5k_hw *ah, u32 index); ++extern int ath5k_hw_clear_mcast_filter_idx(struct ath5k_hw *ah, u32 index); ++extern u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah); ++extern void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter); ++/* Beacon related functions */ ++extern u32 ath5k_hw_get_tsf32(struct ath5k_hw *ah); ++extern u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah); ++extern void ath5k_hw_reset_tsf(struct ath5k_hw *ah); ++extern void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval); ++extern int ath5k_hw_set_beacon_timers(struct ath5k_hw *ah, const struct ath5k_beacon_state *state); ++extern void ath5k_hw_reset_beacon(struct ath5k_hw *ah); ++extern int ath5k_hw_wait_for_beacon(struct ath5k_hw *ah, unsigned long phys_addr); ++extern void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, struct ath5k_mib_stats *statistics); ++/* ACK bit rate */ ++void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high); ++/* ACK/CTS Timeouts */ ++extern int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout); ++extern unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah); ++extern int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout); ++extern unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah); ++/* Key table (WEP) functions */ ++extern int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry); ++extern int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry); ++extern int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, const struct ieee80211_key_conf *key, const u8 *mac); ++extern int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac); ++/* Queue Control Unit, DFS Control Unit Functions */ ++extern int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, struct ath5k_txq_info *queue_info); ++extern int ath5k_hw_setup_tx_queueprops(struct ath5k_hw *ah, int queue, const struct ath5k_txq_info *queue_info); ++extern int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, struct ath5k_txq_info *queue_info); ++extern void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue); ++extern int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue); ++extern u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue); ++extern int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time); ++extern unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah); ++/* Hardware Descriptor Functions */ ++extern int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, u32 size, unsigned int flags); ++/* GPIO Functions */ ++extern void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state); ++extern int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio); ++extern int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio); ++extern u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio); ++extern int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val); ++extern void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, u32 interrupt_level); ++/* Regulatory Domain/Channels Setup */ ++extern u16 ath5k_get_regdomain(struct ath5k_hw *ah); ++/* Misc functions */ ++extern int ath5k_hw_get_capability(struct ath5k_hw *ah, enum ath5k_capability_type cap_type, u32 capability, u32 *result); ++ ++ ++/* Initial register settings functions */ ++extern int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel); ++/* Initialize RF */ ++extern int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel, unsigned int mode); ++extern int ath5k_hw_rfgain(struct ath5k_hw *ah, unsigned int freq); ++extern enum ath5k_rfgain ath5k_hw_get_rf_gain(struct ath5k_hw *ah); ++extern int ath5k_hw_set_rfgain_opt(struct ath5k_hw *ah); ++ ++ ++/* PHY/RF channel functions */ ++extern bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags); ++extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel); ++/* PHY calibration */ ++extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel); ++extern int ath5k_hw_phy_disable(struct ath5k_hw *ah); ++/* Misc PHY functions */ ++extern u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan); ++extern void ath5k_hw_set_def_antenna(struct ath5k_hw *ah, unsigned int ant); ++extern unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah); ++extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq); ++/* TX power setup */ ++extern int ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, unsigned int txpower); ++extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, unsigned int power); ++ ++ ++static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg) ++{ ++ return ioread32(ah->ah_iobase + reg); ++} ++ ++static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg) ++{ ++ iowrite32(val, ah->ah_iobase + reg); ++} ++ ++#endif +diff -up /dev/null linux-2.6.23.noarch/drivers/net/wireless/ath5k/Makefile +--- /dev/null 2007-12-21 08:33:07.834165456 -0500 ++++ linux-2.6.23.noarch/drivers/net/wireless/ath5k/Makefile 2007-12-21 12:18:50.000000000 -0500 +@@ -0,0 +1,2 @@ ++ath5k-objs = base.o hw.o regdom.o initvals.o phy.o debug.o ++obj-$(CONFIG_ATH5K) += ath5k.o +diff -up /dev/null linux-2.6.23.noarch/drivers/net/wireless/ath5k/reg.h +--- /dev/null 2007-12-21 08:33:07.834165456 -0500 ++++ linux-2.6.23.noarch/drivers/net/wireless/ath5k/reg.h 2007-12-21 12:18:50.000000000 -0500 +@@ -0,0 +1,1987 @@ ++/* ++ * Copyright (c) 2007 Nick Kossifidis ++ * Copyright (c) 2004, 2005, 2006, 2007 Reyk Floeter ++ * Copyright (c) 2007 Michael Taylor ++ * ++ * Permission to use, copy, modify, and 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. ++ * ++ */ ++ ++/* ++ * Register values for Atheros 5210/5211/5212 cards from OpenBSD's ar5k ++ * maintained by Reyk Floeter ++ * ++ * I tried to document those registers by looking at ar5k code, some ++ * 802.11 (802.11e mostly) papers and by reading various public available ++ * Atheros presentations and papers like these: ++ * ++ * 5210 - http://nova.stanford.edu/~bbaas/ps/isscc2002_slides.pdf ++ * http://www.it.iitb.ac.in/~janak/wifire/01222734.pdf ++ * ++ * 5211 - http://www.hotchips.org/archives/hc14/3_Tue/16_mcfarland.pdf ++ */ ++ ++ ++ ++/*====MAC DMA REGISTERS====*/ ++ ++/* ++ * AR5210-Specific TXDP registers ++ * 5210 has only 2 transmit queues so no DCU/QCU, just ++ * 2 transmit descriptor pointers... ++ */ ++#define AR5K_NOQCU_TXDP0 0x0000 /* Queue 0 - data */ ++#define AR5K_NOQCU_TXDP1 0x0004 /* Queue 1 - beacons */ ++ ++/* ++ * Mac Control Register ++ */ ++#define AR5K_CR 0x0008 /* Register Address */ ++#define AR5K_CR_TXE0 0x00000001 /* TX Enable for queue 0 on 5210 */ ++#define AR5K_CR_TXE1 0x00000002 /* TX Enable for queue 1 on 5210 */ ++#define AR5K_CR_RXE 0x00000004 /* RX Enable */ ++#define AR5K_CR_TXD0 0x00000008 /* TX Disable for queue 0 on 5210 */ ++#define AR5K_CR_TXD1 0x00000010 /* TX Disable for queue 1 on 5210 */ ++#define AR5K_CR_RXD 0x00000020 /* RX Disable */ ++#define AR5K_CR_SWI 0x00000040 ++ ++/* ++ * RX Descriptor Pointer register ++ */ ++#define AR5K_RXDP 0x000c ++ ++/* ++ * Configuration and status register ++ */ ++#define AR5K_CFG 0x0014 /* Register Address */ ++#define AR5K_CFG_SWTD 0x00000001 /* Byte-swap TX descriptor (for big endian archs) */ ++#define AR5K_CFG_SWTB 0x00000002 /* Byte-swap TX buffer (?) */ ++#define AR5K_CFG_SWRD 0x00000004 /* Byte-swap RX descriptor */ ++#define AR5K_CFG_SWRB 0x00000008 /* Byte-swap RX buffer (?) */ ++#define AR5K_CFG_SWRG 0x00000010 /* Byte-swap Register values (?) */ ++#define AR5K_CFG_ADHOC 0x00000020 /* [5211+] */ ++#define AR5K_CFG_PHY_OK 0x00000100 /* [5211+] */ ++#define AR5K_CFG_EEBS 0x00000200 /* EEPROM is busy */ ++#define AR5K_CFG_CLKGD 0x00000400 /* Clock gated (?) */ ++#define AR5K_CFG_TXCNT 0x00007800 /* Tx frame count (?) [5210] */ ++#define AR5K_CFG_TXCNT_S 11 ++#define AR5K_CFG_TXFSTAT 0x00008000 /* Tx frame status (?) [5210] */ ++#define AR5K_CFG_TXFSTRT 0x00010000 /* [5210] */ ++#define AR5K_CFG_PCI_THRES 0x00060000 /* [5211+] */ ++#define AR5K_CFG_PCI_THRES_S 17 ++ ++/* ++ * Interrupt enable register ++ */ ++#define AR5K_IER 0x0024 /* Register Address */ ++#define AR5K_IER_DISABLE 0x00000000 /* Disable card interrupts */ ++#define AR5K_IER_ENABLE 0x00000001 /* Enable card interrupts */ ++ ++ ++/* ++ * 0x0028 is Beacon Control Register on 5210 ++ * and first RTS duration register on 5211 ++ */ ++ ++/* ++ * Beacon control register [5210] ++ */ ++#define AR5K_BCR 0x0028 /* Register Address */ ++#define AR5K_BCR_AP 0x00000000 /* AP mode */ ++#define AR5K_BCR_ADHOC 0x00000001 /* Ad-Hoc mode */ ++#define AR5K_BCR_BDMAE 0x00000002 /* DMA enable */ ++#define AR5K_BCR_TQ1FV 0x00000004 /* Use Queue1 for CAB traffic */ ++#define AR5K_BCR_TQ1V 0x00000008 /* Use Queue1 for Beacon traffic */ ++#define AR5K_BCR_BCGET 0x00000010 ++ ++/* ++ * First RTS duration register [5211] ++ */ ++#define AR5K_RTSD0 0x0028 /* Register Address */ ++#define AR5K_RTSD0_6 0x000000ff /* 6Mb RTS duration mask (?) */ ++#define AR5K_RTSD0_6_S 0 /* 6Mb RTS duration shift (?) */ ++#define AR5K_RTSD0_9 0x0000ff00 /* 9Mb*/ ++#define AR5K_RTSD0_9_S 8 ++#define AR5K_RTSD0_12 0x00ff0000 /* 12Mb*/ ++#define AR5K_RTSD0_12_S 16 ++#define AR5K_RTSD0_18 0xff000000 /* 16Mb*/ ++#define AR5K_RTSD0_18_S 24 ++ ++ ++/* ++ * 0x002c is Beacon Status Register on 5210 ++ * and second RTS duration register on 5211 ++ */ ++ ++/* ++ * Beacon status register [5210] ++ * ++ * As i can see in ar5k_ar5210_tx_start Reyk uses some of the values of BCR ++ * for this register, so i guess TQ1V,TQ1FV and BDMAE have the same meaning ++ * here and SNP/SNAP means "snapshot" (so this register gets synced with BCR). ++ * So SNAPPEDBCRVALID sould also stand for "snapped BCR -values- valid", so i ++ * renamed it to SNAPSHOTSVALID to make more sense. I realy have no idea what ++ * else can it be. I also renamed SNPBCMD to SNPADHOC to match BCR. ++ */ ++#define AR5K_BSR 0x002c /* Register Address */ ++#define AR5K_BSR_BDLYSW 0x00000001 /* SW Beacon delay (?) */ ++#define AR5K_BSR_BDLYDMA 0x00000002 /* DMA Beacon delay (?) */ ++#define AR5K_BSR_TXQ1F 0x00000004 /* Beacon queue (1) finished */ ++#define AR5K_BSR_ATIMDLY 0x00000008 /* ATIM delay (?) */ ++#define AR5K_BSR_SNPADHOC 0x00000100 /* Ad-hoc mode set (?) */ ++#define AR5K_BSR_SNPBDMAE 0x00000200 /* Beacon DMA enabled (?) */ ++#define AR5K_BSR_SNPTQ1FV 0x00000400 /* Queue1 is used for CAB traffic (?) */ ++#define AR5K_BSR_SNPTQ1V 0x00000800 /* Queue1 is used for Beacon traffic (?) */ ++#define AR5K_BSR_SNAPSHOTSVALID 0x00001000 /* BCR snapshots are valid (?) */ ++#define AR5K_BSR_SWBA_CNT 0x00ff0000 ++ ++/* ++ * Second RTS duration register [5211] ++ */ ++#define AR5K_RTSD1 0x002c /* Register Address */ ++#define AR5K_RTSD1_24 0x000000ff /* 24Mb */ ++#define AR5K_RTSD1_24_S 0 ++#define AR5K_RTSD1_36 0x0000ff00 /* 36Mb */ ++#define AR5K_RTSD1_36_S 8 ++#define AR5K_RTSD1_48 0x00ff0000 /* 48Mb */ ++#define AR5K_RTSD1_48_S 16 ++#define AR5K_RTSD1_54 0xff000000 /* 54Mb */ ++#define AR5K_RTSD1_54_S 24 ++ ++ ++/* ++ * Transmit configuration register ++ */ ++#define AR5K_TXCFG 0x0030 /* Register Address */ ++#define AR5K_TXCFG_SDMAMR 0x00000007 /* DMA size */ ++#define AR5K_TXCFG_SDMAMR_S 0 ++#define AR5K_TXCFG_B_MODE 0x00000008 /* Set b mode for 5111 (enable 2111) */ ++#define AR5K_TXCFG_TXFSTP 0x00000008 /* TX DMA full Stop [5210] */ ++#define AR5K_TXCFG_TXFULL 0x000003f0 /* TX Triger level mask */ ++#define AR5K_TXCFG_TXFULL_S 4 ++#define AR5K_TXCFG_TXFULL_0B 0x00000000 ++#define AR5K_TXCFG_TXFULL_64B 0x00000010 ++#define AR5K_TXCFG_TXFULL_128B 0x00000020 ++#define AR5K_TXCFG_TXFULL_192B 0x00000030 ++#define AR5K_TXCFG_TXFULL_256B 0x00000040 ++#define AR5K_TXCFG_TXCONT_EN 0x00000080 ++#define AR5K_TXCFG_DMASIZE 0x00000100 /* Flag for passing DMA size [5210] */ ++#define AR5K_TXCFG_JUMBO_TXE 0x00000400 /* Enable jumbo frames transmition (?) [5211+] */ ++#define AR5K_TXCFG_RTSRND 0x00001000 /* [5211+] */ ++#define AR5K_TXCFG_FRMPAD_DIS 0x00002000 /* [5211+] */ ++#define AR5K_TXCFG_RDY_DIS 0x00004000 /* [5211+] */ ++ ++/* ++ * Receive configuration register ++ */ ++#define AR5K_RXCFG 0x0034 /* Register Address */ ++#define AR5K_RXCFG_SDMAMW 0x00000007 /* DMA size */ ++#define AR5K_RXCFG_SDMAMW_S 0 ++#define AR5K_RXCFG_DEF_ANTENNA 0x00000008 /* Default antenna */ ++#define AR5K_RXCFG_ZLFDMA 0x00000010 /* Zero-length DMA */ ++#define AR5K_RXCFG_JUMBO_RXE 0x00000020 /* Enable jumbo frames reception (?) [5211+] */ ++#define AR5K_RXCFG_JUMBO_WRAP 0x00000040 /* Wrap jumbo frames (?) [5211+] */ ++ ++/* ++ * Receive jumbo descriptor last address register ++ * Only found in 5211 (?) ++ */ ++#define AR5K_RXJLA 0x0038 ++ ++/* ++ * MIB control register ++ */ ++#define AR5K_MIBC 0x0040 /* Register Address */ ++#define AR5K_MIBC_COW 0x00000001 ++#define AR5K_MIBC_FMC 0x00000002 /* Freeze Mib Counters (?) */ ++#define AR5K_MIBC_CMC 0x00000004 /* Clean Mib Counters (?) */ ++#define AR5K_MIBC_MCS 0x00000008 ++ ++/* ++ * Timeout prescale register ++ */ ++#define AR5K_TOPS 0x0044 ++#define AR5K_TOPS_M 0x0000ffff /* [5211+] (?) */ ++ ++/* ++ * Receive timeout register (no frame received) ++ */ ++#define AR5K_RXNOFRM 0x0048 ++#define AR5K_RXNOFRM_M 0x000003ff /* [5211+] (?) */ ++ ++/* ++ * Transmit timeout register (no frame sent) ++ */ ++#define AR5K_TXNOFRM 0x004c ++#define AR5K_TXNOFRM_M 0x000003ff /* [5211+] (?) */ ++#define AR5K_TXNOFRM_QCU 0x000ffc00 /* [5211+] (?) */ ++ ++/* ++ * Receive frame gap timeout register ++ */ ++#define AR5K_RPGTO 0x0050 ++#define AR5K_RPGTO_M 0x000003ff /* [5211+] (?) */ ++ ++/* ++ * Receive frame count limit register ++ */ ++#define AR5K_RFCNT 0x0054 ++#define AR5K_RFCNT_M 0x0000001f /* [5211+] (?) */ ++#define AR5K_RFCNT_RFCL 0x0000000f /* [5210] */ ++ ++/* ++ * Misc settings register ++ */ ++#define AR5K_MISC 0x0058 /* Register Address */ ++#define AR5K_MISC_DMA_OBS_M 0x000001e0 ++#define AR5K_MISC_DMA_OBS_S 5 ++#define AR5K_MISC_MISC_OBS_M 0x00000e00 ++#define AR5K_MISC_MISC_OBS_S 9 ++#define AR5K_MISC_MAC_OBS_LSB_M 0x00007000 ++#define AR5K_MISC_MAC_OBS_LSB_S 12 ++#define AR5K_MISC_MAC_OBS_MSB_M 0x00038000 ++#define AR5K_MISC_MAC_OBS_MSB_S 15 ++#define AR5K_MISC_LED_DECAY 0x001c0000 /* [5210] */ ++#define AR5K_MISC_LED_BLINK 0x00e00000 /* [5210] */ ++ ++/* ++ * QCU/DCU clock gating register (5311) ++ */ ++#define AR5K_QCUDCU_CLKGT 0x005c /* Register Address (?) */ ++#define AR5K_QCUDCU_CLKGT_QCU 0x0000ffff /* Mask for QCU clock */ ++#define AR5K_QCUDCU_CLKGT_DCU 0x07ff0000 /* Mask for DCU clock */ ++ ++/* ++ * Interrupt Status Registers ++ * ++ * For 5210 there is only one status register but for ++ * 5211/5212 we have one primary and 4 secondary registers. ++ * So we have AR5K_ISR for 5210 and AR5K_PISR /SISRx for 5211/5212. ++ * Most of these bits are common for all chipsets. ++ */ ++#define AR5K_ISR 0x001c /* Register Address [5210] */ ++#define AR5K_PISR 0x0080 /* Register Address [5211+] */ ++#define AR5K_ISR_RXOK 0x00000001 /* Frame successfuly recieved */ ++#define AR5K_ISR_RXDESC 0x00000002 /* RX descriptor request */ ++#define AR5K_ISR_RXERR 0x00000004 /* Receive error */ ++#define AR5K_ISR_RXNOFRM 0x00000008 /* No frame received (receive timeout) */ ++#define AR5K_ISR_RXEOL 0x00000010 /* Empty RX descriptor */ ++#define AR5K_ISR_RXORN 0x00000020 /* Receive FIFO overrun */ ++#define AR5K_ISR_TXOK 0x00000040 /* Frame successfuly transmited */ ++#define AR5K_ISR_TXDESC 0x00000080 /* TX descriptor request */ ++#define AR5K_ISR_TXERR 0x00000100 /* Transmit error */ ++#define AR5K_ISR_TXNOFRM 0x00000200 /* No frame transmited (transmit timeout) */ ++#define AR5K_ISR_TXEOL 0x00000400 /* Empty TX descriptor */ ++#define AR5K_ISR_TXURN 0x00000800 /* Transmit FIFO underrun */ ++#define AR5K_ISR_MIB 0x00001000 /* Update MIB counters */ ++#define AR5K_ISR_SWI 0x00002000 /* Software interrupt (?) */ ++#define AR5K_ISR_RXPHY 0x00004000 /* PHY error */ ++#define AR5K_ISR_RXKCM 0x00008000 ++#define AR5K_ISR_SWBA 0x00010000 /* Software beacon alert */ ++#define AR5K_ISR_BRSSI 0x00020000 ++#define AR5K_ISR_BMISS 0x00040000 /* Beacon missed */ ++#define AR5K_ISR_HIUERR 0x00080000 /* Host Interface Unit error [5211+] */ ++#define AR5K_ISR_BNR 0x00100000 /* Beacon not ready [5211+] */ ++#define AR5K_ISR_MCABT 0x00100000 /* [5210] */ ++#define AR5K_ISR_RXCHIRP 0x00200000 /* [5212+] */ ++#define AR5K_ISR_SSERR 0x00200000 /* [5210] */ ++#define AR5K_ISR_DPERR 0x00400000 /* [5210] */ ++#define AR5K_ISR_TIM 0x00800000 /* [5210] */ ++#define AR5K_ISR_BCNMISC 0x00800000 /* [5212+] */ ++#define AR5K_ISR_GPIO 0x01000000 /* GPIO (rf kill)*/ ++#define AR5K_ISR_QCBRORN 0x02000000 /* CBR overrun (?) [5211+] */ ++#define AR5K_ISR_QCBRURN 0x04000000 /* CBR underrun (?) [5211+] */ ++#define AR5K_ISR_QTRIG 0x08000000 /* [5211+] */ ++ ++/* ++ * Secondary status registers [5211+] (0 - 4) ++ * ++ * I guess from the names that these give the status for each ++ * queue, that's why only masks are defined here, haven't got ++ * any info about them (couldn't find them anywhere in ar5k code). ++ */ ++#define AR5K_SISR0 0x0084 /* Register Address [5211+] */ ++#define AR5K_SISR0_QCU_TXOK 0x000003ff /* Mask for QCU_TXOK */ ++#define AR5K_SISR0_QCU_TXDESC 0x03ff0000 /* Mask for QCU_TXDESC */ ++ ++#define AR5K_SISR1 0x0088 /* Register Address [5211+] */ ++#define AR5K_SISR1_QCU_TXERR 0x000003ff /* Mask for QCU_TXERR */ ++#define AR5K_SISR1_QCU_TXEOL 0x03ff0000 /* Mask for QCU_TXEOL */ ++ ++#define AR5K_SISR2 0x008c /* Register Address [5211+] */ ++#define AR5K_SISR2_QCU_TXURN 0x000003ff /* Mask for QCU_TXURN */ ++#define AR5K_SISR2_MCABT 0x00100000 ++#define AR5K_SISR2_SSERR 0x00200000 ++#define AR5K_SISR2_DPERR 0x00400000 ++#define AR5K_SISR2_TIM 0x01000000 /* [5212+] */ ++#define AR5K_SISR2_CAB_END 0x02000000 /* [5212+] */ ++#define AR5K_SISR2_DTIM_SYNC 0x04000000 /* [5212+] */ ++#define AR5K_SISR2_BCN_TIMEOUT 0x08000000 /* [5212+] */ ++#define AR5K_SISR2_CAB_TIMEOUT 0x10000000 /* [5212+] */ ++#define AR5K_SISR2_DTIM 0x20000000 /* [5212+] */ ++ ++#define AR5K_SISR3 0x0090 /* Register Address [5211+] */ ++#define AR5K_SISR3_QCBRORN 0x000003ff /* Mask for QCBRORN */ ++#define AR5K_SISR3_QCBRURN 0x03ff0000 /* Mask for QCBRURN */ ++ ++#define AR5K_SISR4 0x0094 /* Register Address [5211+] */ ++#define AR5K_SISR4_QTRIG 0x000003ff /* Mask for QTRIG */ ++ ++/* ++ * Shadow read-and-clear interrupt status registers [5211+] ++ */ ++#define AR5K_RAC_PISR 0x00c0 /* Read and clear PISR */ ++#define AR5K_RAC_SISR0 0x00c4 /* Read and clear SISR0 */ ++#define AR5K_RAC_SISR1 0x00c8 /* Read and clear SISR1 */ ++#define AR5K_RAC_SISR2 0x00cc /* Read and clear SISR2 */ ++#define AR5K_RAC_SISR3 0x00d0 /* Read and clear SISR3 */ ++#define AR5K_RAC_SISR4 0x00d4 /* Read and clear SISR4 */ ++ ++/* ++ * Interrupt Mask Registers ++ * ++ * As whith ISRs 5210 has one IMR (AR5K_IMR) and 5211/5212 has one primary ++ * (AR5K_PIMR) and 4 secondary IMRs (AR5K_SIMRx). Note that ISR/IMR flags match. ++ */ ++#define AR5K_IMR 0x0020 /* Register Address [5210] */ ++#define AR5K_PIMR 0x00a0 /* Register Address [5211+] */ ++#define AR5K_IMR_RXOK 0x00000001 /* Frame successfuly recieved*/ ++#define AR5K_IMR_RXDESC 0x00000002 /* RX descriptor request*/ ++#define AR5K_IMR_RXERR 0x00000004 /* Receive error*/ ++#define AR5K_IMR_RXNOFRM 0x00000008 /* No frame received (receive timeout)*/ ++#define AR5K_IMR_RXEOL 0x00000010 /* Empty RX descriptor*/ ++#define AR5K_IMR_RXORN 0x00000020 /* Receive FIFO overrun*/ ++#define AR5K_IMR_TXOK 0x00000040 /* Frame successfuly transmited*/ ++#define AR5K_IMR_TXDESC 0x00000080 /* TX descriptor request*/ ++#define AR5K_IMR_TXERR 0x00000100 /* Transmit error*/ ++#define AR5K_IMR_TXNOFRM 0x00000200 /* No frame transmited (transmit timeout)*/ ++#define AR5K_IMR_TXEOL 0x00000400 /* Empty TX descriptor*/ ++#define AR5K_IMR_TXURN 0x00000800 /* Transmit FIFO underrun*/ ++#define AR5K_IMR_MIB 0x00001000 /* Update MIB counters*/ ++#define AR5K_IMR_SWI 0x00002000 ++#define AR5K_IMR_RXPHY 0x00004000 /* PHY error*/ ++#define AR5K_IMR_RXKCM 0x00008000 ++#define AR5K_IMR_SWBA 0x00010000 /* Software beacon alert*/ ++#define AR5K_IMR_BRSSI 0x00020000 ++#define AR5K_IMR_BMISS 0x00040000 /* Beacon missed*/ ++#define AR5K_IMR_HIUERR 0x00080000 /* Host Interface Unit error [5211+] */ ++#define AR5K_IMR_BNR 0x00100000 /* Beacon not ready [5211+] */ ++#define AR5K_IMR_MCABT 0x00100000 /* [5210] */ ++#define AR5K_IMR_RXCHIRP 0x00200000 /* [5212+]*/ ++#define AR5K_IMR_SSERR 0x00200000 /* [5210] */ ++#define AR5K_IMR_DPERR 0x00400000 /* [5210] */ ++#define AR5K_IMR_TIM 0x00800000 /* [5211+] */ ++#define AR5K_IMR_BCNMISC 0x00800000 /* [5212+] */ ++#define AR5K_IMR_GPIO 0x01000000 /* GPIO (rf kill)*/ ++#define AR5K_IMR_QCBRORN 0x02000000 /* CBR overrun (?) [5211+] */ ++#define AR5K_IMR_QCBRURN 0x04000000 /* CBR underrun (?) [5211+] */ ++#define AR5K_IMR_QTRIG 0x08000000 /* [5211+] */ ++ ++/* ++ * Secondary interrupt mask registers [5211+] (0 - 4) ++ */ ++#define AR5K_SIMR0 0x00a4 /* Register Address [5211+] */ ++#define AR5K_SIMR0_QCU_TXOK 0x000003ff /* Mask for QCU_TXOK */ ++#define AR5K_SIMR0_QCU_TXOK_S 0 ++#define AR5K_SIMR0_QCU_TXDESC 0x03ff0000 /* Mask for QCU_TXDESC */ ++#define AR5K_SIMR0_QCU_TXDESC_S 16 ++ ++#define AR5K_SIMR1 0x00a8 /* Register Address [5211+] */ ++#define AR5K_SIMR1_QCU_TXERR 0x000003ff /* Mask for QCU_TXERR */ ++#define AR5K_SIMR1_QCU_TXERR_S 0 ++#define AR5K_SIMR1_QCU_TXEOL 0x03ff0000 /* Mask for QCU_TXEOL */ ++#define AR5K_SIMR1_QCU_TXEOL_S 16 ++ ++#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 ++#define AR5K_SIMR2_SSERR 0x00200000 ++#define AR5K_SIMR2_DPERR 0x00400000 ++#define AR5K_SIMR2_TIM 0x01000000 /* [5212+] */ ++#define AR5K_SIMR2_CAB_END 0x02000000 /* [5212+] */ ++#define AR5K_SIMR2_DTIM_SYNC 0x04000000 /* [5212+] */ ++#define AR5K_SIMR2_BCN_TIMEOUT 0x08000000 /* [5212+] */ ++#define AR5K_SIMR2_CAB_TIMEOUT 0x10000000 /* [5212+] */ ++#define AR5K_SIMR2_DTIM 0x20000000 /* [5212+] */ ++ ++#define AR5K_SIMR3 0x00b0 /* Register Address [5211+] */ ++#define AR5K_SIMR3_QCBRORN 0x000003ff /* Mask for QCBRORN */ ++#define AR5K_SIMR3_QCBRORN_S 0 ++#define AR5K_SIMR3_QCBRURN 0x03ff0000 /* Mask for QCBRURN */ ++#define AR5K_SIMR3_QCBRURN_S 16 ++ ++#define AR5K_SIMR4 0x00b4 /* Register Address [5211+] */ ++#define AR5K_SIMR4_QTRIG 0x000003ff /* Mask for QTRIG */ ++#define AR5K_SIMR4_QTRIG_S 0 ++ ++ ++/* ++ * Decompression mask registers [5212+] ++ */ ++#define AR5K_DCM_ADDR 0x0400 /*Decompression mask address (?)*/ ++#define AR5K_DCM_DATA 0x0404 /*Decompression mask data (?)*/ ++ ++/* ++ * Decompression configuration registers [5212+] ++ */ ++#define AR5K_DCCFG 0x0420 ++ ++/* ++ * Compression configuration registers [5212+] ++ */ ++#define AR5K_CCFG 0x0600 ++#define AR5K_CCFG_CUP 0x0604 ++ ++/* ++ * Compression performance counter registers [5212+] ++ */ ++#define AR5K_CPC0 0x0610 /* Compression performance counter 0 */ ++#define AR5K_CPC1 0x0614 /* Compression performance counter 1*/ ++#define AR5K_CPC2 0x0618 /* Compression performance counter 2 */ ++#define AR5K_CPC3 0x061c /* Compression performance counter 3 */ ++#define AR5K_CPCORN 0x0620 /* Compression performance overrun (?) */ ++ ++ ++/* ++ * Queue control unit (QCU) registers [5211+] ++ * ++ * Card has 12 TX Queues but i see that only 0-9 are used (?) ++ * both in binary HAL (see ah.h) and ar5k. Each queue has it's own ++ * TXDP at addresses 0x0800 - 0x082c, a CBR (Constant Bit Rate) ++ * configuration register (0x08c0 - 0x08ec), a ready time configuration ++ * register (0x0900 - 0x092c), a misc configuration register (0x09c0 - ++ * 0x09ec) and a status register (0x0a00 - 0x0a2c). We also have some ++ * global registers, QCU transmit enable/disable and "one shot arm (?)" ++ * set/clear, which contain status for all queues (we shift by 1 for each ++ * queue). To access these registers easily we define some macros here ++ * that are used inside HAL. For more infos check out *_tx_queue functs. ++ * ++ * TODO: Boundary checking on macros (here?) ++ */ ++ ++/* ++ * Generic QCU Register access macros ++ */ ++#define AR5K_QUEUE_REG(_r, _q) (((_q) << 2) + _r) ++#define AR5K_QCU_GLOBAL_READ(_r, _q) (AR5K_REG_READ(_r) & (1 << _q)) ++#define AR5K_QCU_GLOBAL_WRITE(_r, _q) AR5K_REG_WRITE(_r, (1 << _q)) ++ ++/* ++ * QCU Transmit descriptor pointer registers ++ */ ++#define AR5K_QCU_TXDP_BASE 0x0800 /* Register Address - Queue0 TXDP */ ++#define AR5K_QUEUE_TXDP(_q) AR5K_QUEUE_REG(AR5K_QCU_TXDP_BASE, _q) ++ ++/* ++ * QCU Transmit enable register ++ */ ++#define AR5K_QCU_TXE 0x0840 ++#define AR5K_ENABLE_QUEUE(_q) AR5K_QCU_GLOBAL_WRITE(AR5K_QCU_TXE, _q) ++#define AR5K_QUEUE_ENABLED(_q) AR5K_QCU_GLOBAL_READ(AR5K_QCU_TXE, _q) ++ ++/* ++ * QCU Transmit disable register ++ */ ++#define AR5K_QCU_TXD 0x0880 ++#define AR5K_DISABLE_QUEUE(_q) AR5K_QCU_GLOBAL_WRITE(AR5K_QCU_TXD, _q) ++#define AR5K_QUEUE_DISABLED(_q) AR5K_QCU_GLOBAL_READ(AR5K_QCU_TXD, _q) ++ ++/* ++ * QCU Constant Bit Rate configuration registers ++ */ ++#define AR5K_QCU_CBRCFG_BASE 0x08c0 /* Register Address - Queue0 CBRCFG */ ++#define AR5K_QCU_CBRCFG_INTVAL 0x00ffffff /* CBR Interval mask */ ++#define AR5K_QCU_CBRCFG_INTVAL_S 0 ++#define AR5K_QCU_CBRCFG_ORN_THRES 0xff000000 /* CBR overrun threshold mask */ ++#define AR5K_QCU_CBRCFG_ORN_THRES_S 24 ++#define AR5K_QUEUE_CBRCFG(_q) AR5K_QUEUE_REG(AR5K_QCU_CBRCFG_BASE, _q) ++ ++/* ++ * QCU Ready time configuration registers ++ */ ++#define AR5K_QCU_RDYTIMECFG_BASE 0x0900 /* Register Address - Queue0 RDYTIMECFG */ ++#define AR5K_QCU_RDYTIMECFG_INTVAL 0x00ffffff /* Ready time interval mask */ ++#define AR5K_QCU_RDYTIMECFG_INTVAL_S 0 ++#define AR5K_QCU_RDYTIMECFG_DURATION 0x00ffffff /* Ready time duration mask */ ++#define AR5K_QCU_RDYTIMECFG_ENABLE 0x01000000 /* Ready time enable mask */ ++#define AR5K_QUEUE_RDYTIMECFG(_q) AR5K_QUEUE_REG(AR5K_QCU_RDYTIMECFG_BASE, _q) ++ ++/* ++ * QCU one shot arm set registers ++ */ ++#define AR5K_QCU_ONESHOTARM_SET 0x0940 /* Register Address -QCU "one shot arm set (?)" */ ++#define AR5K_QCU_ONESHOTARM_SET_M 0x0000ffff ++ ++/* ++ * QCU one shot arm clear registers ++ */ ++#define AR5K_QCU_ONESHOTARM_CLEAR 0x0980 /* Register Address -QCU "one shot arm clear (?)" */ ++#define AR5K_QCU_ONESHOTARM_CLEAR_M 0x0000ffff ++ ++/* ++ * QCU misc registers ++ */ ++#define AR5K_QCU_MISC_BASE 0x09c0 /* Register Address -Queue0 MISC */ ++#define AR5K_QCU_MISC_FRSHED_M 0x0000000f /* Frame sheduling mask */ ++#define AR5K_QCU_MISC_FRSHED_ASAP 0 /* ASAP */ ++#define AR5K_QCU_MISC_FRSHED_CBR 1 /* Constant Bit Rate */ ++#define AR5K_QCU_MISC_FRSHED_DBA_GT 2 /* DMA Beacon alert gated (?) */ ++#define AR5K_QCU_MISC_FRSHED_TIM_GT 3 /* Time gated (?) */ ++#define AR5K_QCU_MISC_FRSHED_BCN_SENT_GT 4 /* Beacon sent gated (?) */ ++#define AR5K_QCU_MISC_ONESHOT_ENABLE 0x00000010 /* Oneshot enable */ ++#define AR5K_QCU_MISC_CBREXP 0x00000020 /* CBR expired (normal queue) */ ++#define AR5K_QCU_MISC_CBREXP_BCN 0x00000040 /* CBR expired (beacon queue) */ ++#define AR5K_QCU_MISC_BCN_ENABLE 0x00000080 /* Beacons enabled */ ++#define AR5K_QCU_MISC_CBR_THRES_ENABLE 0x00000100 /* CBR threshold enabled (?) */ ++#define AR5K_QCU_MISC_TXE 0x00000200 /* TXE reset when RDYTIME enalbed (?) */ ++#define AR5K_QCU_MISC_CBR 0x00000400 /* CBR threshold reset (?) */ ++#define AR5K_QCU_MISC_DCU_EARLY 0x00000800 /* DCU reset (?) */ ++#define AR5K_QUEUE_MISC(_q) AR5K_QUEUE_REG(AR5K_QCU_MISC_BASE, _q) ++ ++ ++/* ++ * QCU status registers ++ */ ++#define AR5K_QCU_STS_BASE 0x0a00 /* Register Address - Queue0 STS */ ++#define AR5K_QCU_STS_FRMPENDCNT 0x00000003 /* Frames pending counter */ ++#define AR5K_QCU_STS_CBREXPCNT 0x0000ff00 /* CBR expired counter (?) */ ++#define AR5K_QUEUE_STATUS(_q) AR5K_QUEUE_REG(AR5K_QCU_STS_BASE, _q) ++ ++/* ++ * QCU ready time shutdown register ++ */ ++#define AR5K_QCU_RDYTIMESHDN 0x0a40 ++#define AR5K_QCU_RDYTIMESHDN_M 0x000003ff ++ ++/* ++ * QCU compression buffer base registers [5212+] ++ */ ++#define AR5K_QCU_CBB_SELECT 0x0b00 ++#define AR5K_QCU_CBB_ADDR 0x0b04 ++ ++/* ++ * QCU compression buffer configuration register [5212+] ++ */ ++#define AR5K_QCU_CBCFG 0x0b08 ++ ++ ++ ++/* ++ * Distributed Coordination Function (DCF) control unit (DCU) ++ * registers [5211+] ++ * ++ * These registers control the various characteristics of each queue ++ * for 802.11e (WME) combatibility so they go together with ++ * QCU registers in pairs. For each queue we have a QCU mask register, ++ * (0x1000 - 0x102c), a local-IFS settings register (0x1040 - 0x106c), ++ * a retry limit register (0x1080 - 0x10ac), a channel time register ++ * (0x10c0 - 0x10ec), a misc-settings register (0x1100 - 0x112c) and ++ * a sequence number register (0x1140 - 0x116c). It seems that "global" ++ * registers here afect all queues (see use of DCU_GBL_IFS_SLOT in ar5k). ++ * We use the same macros here for easier register access. ++ * ++ */ ++ ++/* ++ * DCU QCU mask registers ++ */ ++#define AR5K_DCU_QCUMASK_BASE 0x1000 /* Register Address -Queue0 DCU_QCUMASK */ ++#define AR5K_DCU_QCUMASK_M 0x000003ff ++#define AR5K_QUEUE_QCUMASK(_q) AR5K_QUEUE_REG(AR5K_DCU_QCUMASK_BASE, _q) ++ ++/* ++ * DCU local Inter Frame Space settings register ++ */ ++#define AR5K_DCU_LCL_IFS_BASE 0x1040 /* Register Address -Queue0 DCU_LCL_IFS */ ++#define AR5K_DCU_LCL_IFS_CW_MIN 0x000003ff /* Minimum Contention Window */ ++#define AR5K_DCU_LCL_IFS_CW_MIN_S 0 ++#define AR5K_DCU_LCL_IFS_CW_MAX 0x000ffc00 /* Maximum Contention Window */ ++#define AR5K_DCU_LCL_IFS_CW_MAX_S 10 ++#define AR5K_DCU_LCL_IFS_AIFS 0x0ff00000 /* Arbitrated Interframe Space */ ++#define AR5K_DCU_LCL_IFS_AIFS_S 20 ++#define AR5K_QUEUE_DFS_LOCAL_IFS(_q) AR5K_QUEUE_REG(AR5K_DCU_LCL_IFS_BASE, _q) ++ ++/* ++ * DCU retry limit registers ++ */ ++#define AR5K_DCU_RETRY_LMT_BASE 0x1080 /* Register Address -Queue0 DCU_RETRY_LMT */ ++#define AR5K_DCU_RETRY_LMT_SH_RETRY 0x0000000f /* Short retry limit mask */ ++#define AR5K_DCU_RETRY_LMT_SH_RETRY_S 0 ++#define AR5K_DCU_RETRY_LMT_LG_RETRY 0x000000f0 /* Long retry limit mask */ ++#define AR5K_DCU_RETRY_LMT_LG_RETRY_S 4 ++#define AR5K_DCU_RETRY_LMT_SSH_RETRY 0x00003f00 /* Station short retry limit mask (?) */ ++#define AR5K_DCU_RETRY_LMT_SSH_RETRY_S 8 ++#define AR5K_DCU_RETRY_LMT_SLG_RETRY 0x000fc000 /* Station long retry limit mask (?) */ ++#define AR5K_DCU_RETRY_LMT_SLG_RETRY_S 14 ++#define AR5K_QUEUE_DFS_RETRY_LIMIT(_q) AR5K_QUEUE_REG(AR5K_DCU_RETRY_LMT_BASE, _q) ++ ++/* ++ * DCU channel time registers ++ */ ++#define AR5K_DCU_CHAN_TIME_BASE 0x10c0 /* Register Address -Queue0 DCU_CHAN_TIME */ ++#define AR5K_DCU_CHAN_TIME_DUR 0x000fffff /* Channel time duration */ ++#define AR5K_DCU_CHAN_TIME_DUR_S 0 ++#define AR5K_DCU_CHAN_TIME_ENABLE 0x00100000 /* Enable channel time */ ++#define AR5K_QUEUE_DFS_CHANNEL_TIME(_q) AR5K_QUEUE_REG(AR5K_DCU_CHAN_TIME_BASE, _q) ++ ++/* ++ * DCU misc registers [5211+] ++ * ++ * For some of the registers i couldn't find in the code ++ * (only backoff stuff is there realy) i tried to match the ++ * names with 802.11e parameters etc, so i guess VIRTCOL here ++ * means Virtual Collision and HCFPOLL means Hybrid Coordination ++ * factor Poll (CF- Poll). Arbiter lockout control controls the ++ * behaviour on low priority queues when we have multiple queues ++ * with pending frames. Intra-frame lockout means we wait until ++ * the queue's current frame transmits (with post frame backoff and bursting) ++ * before we transmit anything else and global lockout means we ++ * wait for the whole queue to finish before higher priority queues ++ * can transmit (this is used on beacon and CAB queues). ++ * No lockout means there is no special handling. ++ */ ++#define AR5K_DCU_MISC_BASE 0x1100 /* Register Address -Queue0 DCU_MISC */ ++#define AR5K_DCU_MISC_BACKOFF 0x000007ff /* Mask for backoff setting (?) */ ++#define AR5K_DCU_MISC_BACKOFF_FRAG 0x00000200 /* Enable backoff while bursting */ ++#define AR5K_DCU_MISC_HCFPOLL_ENABLE 0x00000800 /* CF - Poll (?) */ ++#define AR5K_DCU_MISC_BACKOFF_PERSIST 0x00001000 /* Persistent backoff (?) */ ++#define AR5K_DCU_MISC_FRMPRFTCH_ENABLE 0x00002000 /* Enable frame pre-fetch (?) */ ++#define AR5K_DCU_MISC_VIRTCOL 0x0000c000 /* Mask for Virtual Collision (?) */ ++#define AR5K_DCU_MISC_VIRTCOL_NORMAL 0 ++#define AR5K_DCU_MISC_VIRTCOL_MODIFIED 1 ++#define AR5K_DCU_MISC_VIRTCOL_IGNORE 2 ++#define AR5K_DCU_MISC_BCN_ENABLE 0x00010000 /* Beacon enable (?) */ ++#define AR5K_DCU_MISC_ARBLOCK_CTL 0x00060000 /* Arbiter lockout control mask */ ++#define AR5K_DCU_MISC_ARBLOCK_CTL_S 17 ++#define AR5K_DCU_MISC_ARBLOCK_CTL_NONE 0 /* No arbiter lockout */ ++#define AR5K_DCU_MISC_ARBLOCK_CTL_INTFRM 1 /* Intra-frame lockout */ ++#define AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL 2 /* Global lockout */ ++#define AR5K_DCU_MISC_ARBLOCK_IGNORE 0x00080000 ++#define AR5K_DCU_MISC_SEQ_NUM_INCR_DIS 0x00100000 /* Disable sequence number increment (?) */ ++#define AR5K_DCU_MISC_POST_FR_BKOFF_DIS 0x00200000 /* Disable post-frame backoff (?) */ ++#define AR5K_DCU_MISC_VIRT_COLL_POLICY 0x00400000 /* Virtual Collision policy (?) */ ++#define AR5K_DCU_MISC_BLOWN_IFS_POLICY 0x00800000 ++#define AR5K_DCU_MISC_SEQNUM_CTL 0x01000000 /* Sequence number control (?) */ ++#define AR5K_QUEUE_DFS_MISC(_q) AR5K_QUEUE_REG(AR5K_DCU_MISC_BASE, _q) ++ ++/* ++ * DCU frame sequence number registers ++ */ ++#define AR5K_DCU_SEQNUM_BASE 0x1140 ++#define AR5K_DCU_SEQNUM_M 0x00000fff ++#define AR5K_QUEUE_DFS_SEQNUM(_q) AR5K_QUEUE_REG(AR5K_DCU_SEQNUM_BASE, _q) ++ ++/* ++ * DCU global IFS SIFS registers ++ */ ++#define AR5K_DCU_GBL_IFS_SIFS 0x1030 ++#define AR5K_DCU_GBL_IFS_SIFS_M 0x0000ffff ++ ++/* ++ * DCU global IFS slot interval registers ++ */ ++#define AR5K_DCU_GBL_IFS_SLOT 0x1070 ++#define AR5K_DCU_GBL_IFS_SLOT_M 0x0000ffff ++ ++/* ++ * DCU global IFS EIFS registers ++ */ ++#define AR5K_DCU_GBL_IFS_EIFS 0x10b0 ++#define AR5K_DCU_GBL_IFS_EIFS_M 0x0000ffff ++ ++/* ++ * DCU global IFS misc registers ++ */ ++#define AR5K_DCU_GBL_IFS_MISC 0x10f0 /* Register Address */ ++#define AR5K_DCU_GBL_IFS_MISC_LFSR_SLICE 0x00000007 ++#define AR5K_DCU_GBL_IFS_MISC_TURBO_MODE 0x00000008 /* Turbo mode (?) */ ++#define AR5K_DCU_GBL_IFS_MISC_SIFS_DUR_USEC 0x000003f0 /* SIFS Duration mask (?) */ ++#define AR5K_DCU_GBL_IFS_MISC_USEC_DUR 0x000ffc00 ++#define AR5K_DCU_GBL_IFS_MISC_DCU_ARB_DELAY 0x00300000 ++ ++/* ++ * DCU frame prefetch control register ++ */ ++#define AR5K_DCU_FP 0x1230 ++ ++/* ++ * DCU transmit pause control/status register ++ */ ++#define AR5K_DCU_TXP 0x1270 /* Register Address */ ++#define AR5K_DCU_TXP_M 0x000003ff /* Tx pause mask (?) */ ++#define AR5K_DCU_TXP_STATUS 0x00010000 /* Tx pause status (?) */ ++ ++/* ++ * DCU transmit filter register ++ */ ++#define AR5K_DCU_TX_FILTER 0x1038 ++ ++/* ++ * DCU clear transmit filter register ++ */ ++#define AR5K_DCU_TX_FILTER_CLR 0x143c ++ ++/* ++ * DCU set transmit filter register ++ */ ++#define AR5K_DCU_TX_FILTER_SET 0x147c ++ ++/* ++ * Reset control register ++ * ++ * 4 and 8 are not used in 5211/5212 and ++ * 2 means "baseband reset" on 5211/5212. ++ */ ++#define AR5K_RESET_CTL 0x4000 /* Register Address */ ++#define AR5K_RESET_CTL_PCU 0x00000001 /* Protocol Control Unit reset */ ++#define AR5K_RESET_CTL_DMA 0x00000002 /* DMA (Rx/Tx) reset [5210] */ ++#define AR5K_RESET_CTL_BASEBAND 0x00000002 /* Baseband reset [5211+] */ ++#define AR5K_RESET_CTL_MAC 0x00000004 /* MAC reset (PCU+Baseband ?) [5210] */ ++#define AR5K_RESET_CTL_PHY 0x00000008 /* PHY reset [5210] */ ++#define AR5K_RESET_CTL_PCI 0x00000010 /* PCI Core reset (interrupts etc) */ ++#define AR5K_RESET_CTL_CHIP (AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA | \ ++ AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY) ++ ++/* ++ * Sleep control register ++ */ ++#define AR5K_SLEEP_CTL 0x4004 /* Register Address */ ++#define AR5K_SLEEP_CTL_SLDUR 0x0000ffff /* Sleep duration mask */ ++#define AR5K_SLEEP_CTL_SLDUR_S 0 ++#define AR5K_SLEEP_CTL_SLE 0x00030000 /* Sleep enable mask */ ++#define AR5K_SLEEP_CTL_SLE_S 16 ++#define AR5K_SLEEP_CTL_SLE_WAKE 0x00000000 /* Force chip awake */ ++#define AR5K_SLEEP_CTL_SLE_SLP 0x00010000 /* Force chip sleep */ ++#define AR5K_SLEEP_CTL_SLE_ALLOW 0x00020000 ++#define AR5K_SLEEP_CTL_SLE_UNITS 0x00000008 /* [5211+] */ ++ ++/* ++ * Interrupt pending register ++ */ ++#define AR5K_INTPEND 0x4008 ++#define AR5K_INTPEND_M 0x00000001 ++ ++/* ++ * Sleep force register ++ */ ++#define AR5K_SFR 0x400c ++#define AR5K_SFR_M 0x00000001 ++ ++/* ++ * PCI configuration register ++ */ ++#define AR5K_PCICFG 0x4010 /* Register Address */ ++#define AR5K_PCICFG_EEAE 0x00000001 /* Eeprom access enable [5210] */ ++#define AR5K_PCICFG_CLKRUNEN 0x00000004 /* CLKRUN enable [5211+] */ ++#define AR5K_PCICFG_EESIZE 0x00000018 /* Mask for EEPROM size [5211+] */ ++#define AR5K_PCICFG_EESIZE_S 3 ++#define AR5K_PCICFG_EESIZE_4K 0 /* 4K */ ++#define AR5K_PCICFG_EESIZE_8K 1 /* 8K */ ++#define AR5K_PCICFG_EESIZE_16K 2 /* 16K */ ++#define AR5K_PCICFG_EESIZE_FAIL 3 /* Failed to get size (?) [5211+] */ ++#define AR5K_PCICFG_LED 0x00000060 /* Led status [5211+] */ ++#define AR5K_PCICFG_LED_NONE 0x00000000 /* Default [5211+] */ ++#define AR5K_PCICFG_LED_PEND 0x00000020 /* Scan / Auth pending */ ++#define AR5K_PCICFG_LED_ASSOC 0x00000040 /* Associated */ ++#define AR5K_PCICFG_BUS_SEL 0x00000380 /* Mask for "bus select" [5211+] (?) */ ++#define AR5K_PCICFG_CBEFIX_DIS 0x00000400 /* Disable CBE fix (?) */ ++#define AR5K_PCICFG_SL_INTEN 0x00000800 /* Enable interrupts when asleep (?) */ ++#define AR5K_PCICFG_LED_BCTL 0x00001000 /* Led blink (?) [5210] */ ++#define AR5K_PCICFG_SL_INPEN 0x00002800 /* Sleep even whith pending interrupts (?) */ ++#define AR5K_PCICFG_SPWR_DN 0x00010000 /* Mask for power status */ ++#define AR5K_PCICFG_LEDMODE 0x000e0000 /* Ledmode [5211+] */ ++#define AR5K_PCICFG_LEDMODE_PROP 0x00000000 /* Blink on standard traffic [5211+] */ ++#define AR5K_PCICFG_LEDMODE_PROM 0x00020000 /* Default mode (blink on any traffic) [5211+] */ ++#define AR5K_PCICFG_LEDMODE_PWR 0x00040000 /* Some other blinking mode (?) [5211+] */ ++#define AR5K_PCICFG_LEDMODE_RAND 0x00060000 /* Random blinking (?) [5211+] */ ++#define AR5K_PCICFG_LEDBLINK 0x00700000 ++#define AR5K_PCICFG_LEDBLINK_S 20 ++#define AR5K_PCICFG_LEDSLOW 0x00800000 /* Slow led blink rate (?) [5211+] */ ++#define AR5K_PCICFG_LEDSTATE \ ++ (AR5K_PCICFG_LED | AR5K_PCICFG_LEDMODE | \ ++ AR5K_PCICFG_LEDBLINK | AR5K_PCICFG_LEDSLOW) ++ ++/* ++ * "General Purpose Input/Output" (GPIO) control register ++ * ++ * I'm not sure about this but after looking at the code ++ * for all chipsets here is what i got. ++ * ++ * We have 6 GPIOs (pins), each GPIO has 4 modes (2 bits) ++ * Mode 0 -> always input ++ * Mode 1 -> output when GPIODO for this GPIO is set to 0 ++ * Mode 2 -> output when GPIODO for this GPIO is set to 1 ++ * Mode 3 -> always output ++ * ++ * For more infos check out get_gpio/set_gpio and ++ * set_gpio_input/set_gpio_output functs. ++ * For more infos on gpio interrupt check out set_gpio_intr. ++ */ ++#define AR5K_NUM_GPIO 6 ++ ++#define AR5K_GPIOCR 0x4014 /* Register Address */ ++#define AR5K_GPIOCR_INT_ENA 0x00008000 /* Enable GPIO interrupt */ ++#define AR5K_GPIOCR_INT_SELL 0x00000000 /* Generate interrupt when pin is off (?) */ ++#define AR5K_GPIOCR_INT_SELH 0x00010000 /* Generate interrupt when pin is on */ ++#define AR5K_GPIOCR_IN(n) (0 << ((n) * 2)) /* Mode 0 for pin n */ ++#define AR5K_GPIOCR_OUT0(n) (1 << ((n) * 2)) /* Mode 1 for pin n */ ++#define AR5K_GPIOCR_OUT1(n) (2 << ((n) * 2)) /* Mode 2 for pin n */ ++#define AR5K_GPIOCR_OUT(n) (3 << ((n) * 2)) /* Mode 3 for pin n */ ++#define AR5K_GPIOCR_INT_SEL(n) ((n) << 12) /* Interrupt for GPIO pin n */ ++ ++/* ++ * "General Purpose Input/Output" (GPIO) data output register ++ */ ++#define AR5K_GPIODO 0x4018 ++ ++/* ++ * "General Purpose Input/Output" (GPIO) data input register ++ */ ++#define AR5K_GPIODI 0x401c ++#define AR5K_GPIODI_M 0x0000002f ++ ++ ++/* ++ * Silicon revision register ++ */ ++#define AR5K_SREV 0x4020 /* Register Address */ ++#define AR5K_SREV_REV 0x0000000f /* Mask for revision */ ++#define AR5K_SREV_REV_S 0 ++#define AR5K_SREV_VER 0x000000ff /* Mask for version */ ++#define AR5K_SREV_VER_S 4 ++ ++ ++ ++/*====EEPROM REGISTERS====*/ ++ ++/* ++ * EEPROM access registers ++ * ++ * Here we got a difference between 5210/5211-12 ++ * read data register for 5210 is at 0x6800 and ++ * status register is at 0x6c00. There is also ++ * no eeprom command register on 5210 and the ++ * offsets are different. ++ * ++ * To read eeprom data for a specific offset: ++ * 5210 - enable eeprom access (AR5K_PCICFG_EEAE) ++ * read AR5K_EEPROM_BASE +(4 * offset) ++ * check the eeprom status register ++ * and read eeprom data register. ++ * ++ * 5211 - write offset to AR5K_EEPROM_BASE ++ * 5212 write AR5K_EEPROM_CMD_READ on AR5K_EEPROM_CMD ++ * check the eeprom status register ++ * and read eeprom data register. ++ * ++ * To write eeprom data for a specific offset: ++ * 5210 - enable eeprom access (AR5K_PCICFG_EEAE) ++ * write data to AR5K_EEPROM_BASE +(4 * offset) ++ * check the eeprom status register ++ * 5211 - write AR5K_EEPROM_CMD_RESET on AR5K_EEPROM_CMD ++ * 5212 write offset to AR5K_EEPROM_BASE ++ * write data to data register ++ * write AR5K_EEPROM_CMD_WRITE on AR5K_EEPROM_CMD ++ * check the eeprom status register ++ * ++ * For more infos check eeprom_* functs and the ar5k.c ++ * file posted in madwifi-devel mailing list. ++ * http://sourceforge.net/mailarchive/message.php?msg_id=8966525 ++ * ++ */ ++#define AR5K_EEPROM_BASE 0x6000 ++ ++/* ++ * Common ar5xxx EEPROM data offsets (set these on AR5K_EEPROM_BASE) ++ */ ++#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 */ ++#define AR5K_EEPROM_MAGIC_5211 0x0000145b /* 5211 */ ++#define AR5K_EEPROM_MAGIC_5210 0x0000145a /* 5210 */ ++ ++#define AR5K_EEPROM_PROTECT 0x003f /* EEPROM protect status */ ++#define AR5K_EEPROM_PROTECT_RD_0_31 0x0001 /* Read protection bit for offsets 0x0 - 0x1f */ ++#define AR5K_EEPROM_PROTECT_WR_0_31 0x0002 /* Write protection bit for offsets 0x0 - 0x1f */ ++#define AR5K_EEPROM_PROTECT_RD_32_63 0x0004 /* 0x20 - 0x3f */ ++#define AR5K_EEPROM_PROTECT_WR_32_63 0x0008 ++#define AR5K_EEPROM_PROTECT_RD_64_127 0x0010 /* 0x40 - 0x7f */ ++#define AR5K_EEPROM_PROTECT_WR_64_127 0x0020 ++#define AR5K_EEPROM_PROTECT_RD_128_191 0x0040 /* 0x80 - 0xbf (regdom) */ ++#define AR5K_EEPROM_PROTECT_WR_128_191 0x0080 ++#define AR5K_EEPROM_PROTECT_RD_192_207 0x0100 /* 0xc0 - 0xcf */ ++#define AR5K_EEPROM_PROTECT_WR_192_207 0x0200 ++#define AR5K_EEPROM_PROTECT_RD_208_223 0x0400 /* 0xd0 - 0xdf */ ++#define AR5K_EEPROM_PROTECT_WR_208_223 0x0800 ++#define AR5K_EEPROM_PROTECT_RD_224_239 0x1000 /* 0xe0 - 0xef */ ++#define AR5K_EEPROM_PROTECT_WR_224_239 0x2000 ++#define AR5K_EEPROM_PROTECT_RD_240_255 0x4000 /* 0xf0 - 0xff */ ++#define AR5K_EEPROM_PROTECT_WR_240_255 0x8000 ++#define AR5K_EEPROM_REG_DOMAIN 0x00bf /* EEPROM regdom */ ++#define AR5K_EEPROM_INFO_BASE 0x00c0 /* EEPROM header */ ++#define AR5K_EEPROM_INFO_MAX (0x400 - AR5K_EEPROM_INFO_BASE) ++#define AR5K_EEPROM_INFO_CKSUM 0xffff ++#define AR5K_EEPROM_INFO(_n) (AR5K_EEPROM_INFO_BASE + (_n)) ++ ++#define AR5K_EEPROM_VERSION AR5K_EEPROM_INFO(1) /* EEPROM Version */ ++#define AR5K_EEPROM_VERSION_3_0 0x3000 /* No idea what's going on before this version */ ++#define AR5K_EEPROM_VERSION_3_1 0x3001 /* ob/db values for 2Ghz (ar5211_rfregs) */ ++#define AR5K_EEPROM_VERSION_3_2 0x3002 /* different frequency representation (eeprom_bin2freq) */ ++#define AR5K_EEPROM_VERSION_3_3 0x3003 /* offsets changed, has 32 CTLs (see below) and ee_false_detect (eeprom_read_modes) */ ++#define AR5K_EEPROM_VERSION_3_4 0x3004 /* has ee_i_gain ee_cck_ofdm_power_delta (eeprom_read_modes) */ ++#define AR5K_EEPROM_VERSION_4_0 0x4000 /* has ee_misc*, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */ ++#define AR5K_EEPROM_VERSION_4_1 0x4001 /* has ee_margin_tx_rx (eeprom_init) */ ++#define AR5K_EEPROM_VERSION_4_2 0x4002 /* has ee_cck_ofdm_gain_delta (eeprom_init) */ ++#define AR5K_EEPROM_VERSION_4_3 0x4003 ++#define AR5K_EEPROM_VERSION_4_4 0x4004 ++#define AR5K_EEPROM_VERSION_4_5 0x4005 ++#define AR5K_EEPROM_VERSION_4_6 0x4006 /* has ee_scaled_cck_delta */ ++#define AR5K_EEPROM_VERSION_4_7 0x3007 ++ ++#define AR5K_EEPROM_MODE_11A 0 ++#define AR5K_EEPROM_MODE_11B 1 ++#define AR5K_EEPROM_MODE_11G 2 ++ ++#define AR5K_EEPROM_HDR AR5K_EEPROM_INFO(2) /* Header that contains the device caps */ ++#define AR5K_EEPROM_HDR_11A(_v) (((_v) >> AR5K_EEPROM_MODE_11A) & 0x1) ++#define AR5K_EEPROM_HDR_11B(_v) (((_v) >> AR5K_EEPROM_MODE_11B) & 0x1) ++#define AR5K_EEPROM_HDR_11G(_v) (((_v) >> AR5K_EEPROM_MODE_11G) & 0x1) ++#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v) (((_v) >> 3) & 0x1) /* Disable turbo for 2Ghz (?) */ ++#define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v) (((_v) >> 4) & 0x7f) /* Max turbo power for a/XR mode (eeprom_init) */ ++#define AR5K_EEPROM_HDR_DEVICE(_v) (((_v) >> 11) & 0x7) ++#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v) (((_v) >> 15) & 0x1) /* Disable turbo for 5Ghz (?) */ ++#define AR5K_EEPROM_HDR_RFKILL(_v) (((_v) >> 14) & 0x1) /* Device has RFKill support */ ++ ++#define AR5K_EEPROM_RFKILL_GPIO_SEL 0x0000001c ++#define AR5K_EEPROM_RFKILL_GPIO_SEL_S 2 ++#define AR5K_EEPROM_RFKILL_POLARITY 0x00000002 ++#define AR5K_EEPROM_RFKILL_POLARITY_S 1 ++ ++/* Newer EEPROMs are using a different offset */ ++#define AR5K_EEPROM_OFF(_v, _v3_0, _v3_3) \ ++ (((_v) >= AR5K_EEPROM_VERSION_3_3) ? _v3_3 : _v3_0) ++ ++#define AR5K_EEPROM_ANT_GAIN(_v) AR5K_EEPROM_OFF(_v, 0x00c4, 0x00c3) ++#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v) ((int8_t)(((_v) >> 8) & 0xff)) ++#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v) ((int8_t)((_v) & 0xff)) ++ ++/* calibration settings */ ++#define AR5K_EEPROM_MODES_11A(_v) AR5K_EEPROM_OFF(_v, 0x00c5, 0x00d4) ++#define AR5K_EEPROM_MODES_11B(_v) AR5K_EEPROM_OFF(_v, 0x00d0, 0x00f2) ++#define AR5K_EEPROM_MODES_11G(_v) AR5K_EEPROM_OFF(_v, 0x00da, 0x010d) ++#define AR5K_EEPROM_CTL(_v) AR5K_EEPROM_OFF(_v, 0x00e4, 0x0128) /* Conformance test limits */ ++ ++/* [3.1 - 3.3] */ ++#define AR5K_EEPROM_OBDB0_2GHZ 0x00ec ++#define AR5K_EEPROM_OBDB1_2GHZ 0x00ed ++ ++/* Misc values available since EEPROM 4.0 */ ++#define AR5K_EEPROM_MISC0 0x00c4 ++#define AR5K_EEPROM_EARSTART(_v) ((_v) & 0xfff) ++#define AR5K_EEPROM_EEMAP(_v) (((_v) >> 14) & 0x3) ++#define AR5K_EEPROM_MISC1 0x00c5 ++#define AR5K_EEPROM_TARGET_PWRSTART(_v) ((_v) & 0xfff) ++#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v) (((_v) >> 14) & 0x1) ++ ++/* ++ * EEPROM data register ++ */ ++#define AR5K_EEPROM_DATA_5211 0x6004 ++#define AR5K_EEPROM_DATA_5210 0x6800 ++#define AR5K_EEPROM_DATA (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_EEPROM_DATA_5210 : AR5K_EEPROM_DATA_5211) ++ ++/* ++ * EEPROM command register ++ */ ++#define AR5K_EEPROM_CMD 0x6008 /* Register Addres */ ++#define AR5K_EEPROM_CMD_READ 0x00000001 /* EEPROM read */ ++#define AR5K_EEPROM_CMD_WRITE 0x00000002 /* EEPROM write */ ++#define AR5K_EEPROM_CMD_RESET 0x00000004 /* EEPROM reset */ ++ ++/* ++ * EEPROM status register ++ */ ++#define AR5K_EEPROM_STAT_5210 0x6c00 /* Register Address [5210] */ ++#define AR5K_EEPROM_STAT_5211 0x600c /* Register Address [5211+] */ ++#define AR5K_EEPROM_STATUS (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_EEPROM_STAT_5210 : AR5K_EEPROM_STAT_5211) ++#define AR5K_EEPROM_STAT_RDERR 0x00000001 /* EEPROM read failed */ ++#define AR5K_EEPROM_STAT_RDDONE 0x00000002 /* EEPROM read successful */ ++#define AR5K_EEPROM_STAT_WRERR 0x00000004 /* EEPROM write failed */ ++#define AR5K_EEPROM_STAT_WRDONE 0x00000008 /* EEPROM write successful */ ++ ++/* ++ * EEPROM config register (?) ++ */ ++#define AR5K_EEPROM_CFG 0x6010 ++ ++ ++ ++/* ++ * Protocol Control Unit (PCU) registers ++ */ ++/* ++ * Used for checking initial register writes ++ * during channel reset (see reset func) ++ */ ++#define AR5K_PCU_MIN 0x8000 ++#define AR5K_PCU_MAX 0x8fff ++ ++/* ++ * First station id register (MAC address in lower 32 bits) ++ */ ++#define AR5K_STA_ID0 0x8000 ++ ++/* ++ * Second station id register (MAC address in upper 16 bits) ++ */ ++#define AR5K_STA_ID1 0x8004 /* Register Address */ ++#define AR5K_STA_ID1_AP 0x00010000 /* Set AP mode */ ++#define AR5K_STA_ID1_ADHOC 0x00020000 /* Set Ad-Hoc mode */ ++#define AR5K_STA_ID1_PWR_SV 0x00040000 /* Power save reporting (?) */ ++#define AR5K_STA_ID1_NO_KEYSRCH 0x00080000 /* No key search */ ++#define AR5K_STA_ID1_NO_PSPOLL 0x00100000 /* No power save polling [5210] */ ++#define AR5K_STA_ID1_PCF_5211 0x00100000 /* Enable PCF on [5211+] */ ++#define AR5K_STA_ID1_PCF_5210 0x00200000 /* Enable PCF on [5210]*/ ++#define AR5K_STA_ID1_PCF (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_STA_ID1_PCF_5210 : AR5K_STA_ID1_PCF_5211) ++#define AR5K_STA_ID1_DEFAULT_ANTENNA 0x00200000 /* Use default antenna */ ++#define AR5K_STA_ID1_DESC_ANTENNA 0x00400000 /* Update antenna from descriptor */ ++#define AR5K_STA_ID1_RTS_DEF_ANTENNA 0x00800000 /* Use default antenna for RTS (?) */ ++#define AR5K_STA_ID1_ACKCTS_6MB 0x01000000 /* Use 6Mbit/s for ACK/CTS (?) */ ++#define AR5K_STA_ID1_BASE_RATE_11B 0x02000000 /* Use 11b base rate (for ACK/CTS ?) [5211+] */ ++ ++/* ++ * First BSSID register (MAC address, lower 32bits) ++ */ ++#define AR5K_BSS_ID0 0x8008 ++ ++/* ++ * Second BSSID register (MAC address in upper 16 bits) ++ * ++ * AID: Association ID ++ */ ++#define AR5K_BSS_ID1 0x800c ++#define AR5K_BSS_ID1_AID 0xffff0000 ++#define AR5K_BSS_ID1_AID_S 16 ++ ++/* ++ * Backoff slot time register ++ */ ++#define AR5K_SLOT_TIME 0x8010 ++ ++/* ++ * ACK/CTS timeout register ++ */ ++#define AR5K_TIME_OUT 0x8014 /* Register Address */ ++#define AR5K_TIME_OUT_ACK 0x00001fff /* ACK timeout mask */ ++#define AR5K_TIME_OUT_ACK_S 0 ++#define AR5K_TIME_OUT_CTS 0x1fff0000 /* CTS timeout mask */ ++#define AR5K_TIME_OUT_CTS_S 16 ++ ++/* ++ * RSSI threshold register ++ */ ++#define AR5K_RSSI_THR 0x8018 /* Register Address */ ++#define AR5K_RSSI_THR_M 0x000000ff /* Mask for RSSI threshold [5211+] */ ++#define AR5K_RSSI_THR_BMISS_5210 0x00000700 /* Mask for Beacon Missed threshold [5210] */ ++#define AR5K_RSSI_THR_BMISS_5210_S 8 ++#define AR5K_RSSI_THR_BMISS_5211 0x0000ff00 /* Mask for Beacon Missed threshold [5211+] */ ++#define AR5K_RSSI_THR_BMISS_5211_S 8 ++#define AR5K_RSSI_THR_BMISS (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_RSSI_THR_BMISS_5210 : AR5K_RSSI_THR_BMISS_5211) ++#define AR5K_RSSI_THR_BMISS_S 8 ++ ++/* ++ * 5210 has more PCU registers because there is no QCU/DCU ++ * so queue parameters are set here, this way a lot common ++ * registers have different address for 5210. To make things ++ * easier we define a macro based on ah->ah_version for common ++ * registers with different addresses and common flags. ++ */ ++ ++/* ++ * Retry limit register ++ * ++ * Retry limit register for 5210 (no QCU/DCU so it's done in PCU) ++ */ ++#define AR5K_NODCU_RETRY_LMT 0x801c /*Register Address */ ++#define AR5K_NODCU_RETRY_LMT_SH_RETRY 0x0000000f /* Short retry limit mask */ ++#define AR5K_NODCU_RETRY_LMT_SH_RETRY_S 0 ++#define AR5K_NODCU_RETRY_LMT_LG_RETRY 0x000000f0 /* Long retry mask */ ++#define AR5K_NODCU_RETRY_LMT_LG_RETRY_S 4 ++#define AR5K_NODCU_RETRY_LMT_SSH_RETRY 0x00003f00 /* Station short retry limit mask */ ++#define AR5K_NODCU_RETRY_LMT_SSH_RETRY_S 8 ++#define AR5K_NODCU_RETRY_LMT_SLG_RETRY 0x000fc000 /* Station long retry limit mask */ ++#define AR5K_NODCU_RETRY_LMT_SLG_RETRY_S 14 ++#define AR5K_NODCU_RETRY_LMT_CW_MIN 0x3ff00000 /* Minimum contention window mask */ ++#define AR5K_NODCU_RETRY_LMT_CW_MIN_S 20 ++ ++/* ++ * Transmit latency register ++ */ ++#define AR5K_USEC_5210 0x8020 /* Register Address [5210] */ ++#define AR5K_USEC_5211 0x801c /* Register Address [5211+] */ ++#define AR5K_USEC (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_USEC_5210 : AR5K_USEC_5211) ++#define AR5K_USEC_1 0x0000007f ++#define AR5K_USEC_1_S 0 ++#define AR5K_USEC_32 0x00003f80 ++#define AR5K_USEC_32_S 7 ++#define AR5K_USEC_TX_LATENCY_5211 0x007fc000 ++#define AR5K_USEC_TX_LATENCY_5211_S 14 ++#define AR5K_USEC_RX_LATENCY_5211 0x1f800000 ++#define AR5K_USEC_RX_LATENCY_5211_S 23 ++#define AR5K_USEC_TX_LATENCY_5210 0x000fc000 /* also for 5311 */ ++#define AR5K_USEC_TX_LATENCY_5210_S 14 ++#define AR5K_USEC_RX_LATENCY_5210 0x03f00000 /* also for 5311 */ ++#define AR5K_USEC_RX_LATENCY_5210_S 20 ++ ++/* ++ * PCU beacon control register ++ */ ++#define AR5K_BEACON_5210 0x8024 ++#define AR5K_BEACON_5211 0x8020 ++#define AR5K_BEACON (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_BEACON_5210 : AR5K_BEACON_5211) ++#define AR5K_BEACON_PERIOD 0x0000ffff ++#define AR5K_BEACON_PERIOD_S 0 ++#define AR5K_BEACON_TIM 0x007f0000 ++#define AR5K_BEACON_TIM_S 16 ++#define AR5K_BEACON_ENABLE 0x00800000 ++#define AR5K_BEACON_RESET_TSF 0x01000000 ++ ++/* ++ * CFP period register ++ */ ++#define AR5K_CFP_PERIOD_5210 0x8028 ++#define AR5K_CFP_PERIOD_5211 0x8024 ++#define AR5K_CFP_PERIOD (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_CFP_PERIOD_5210 : AR5K_CFP_PERIOD_5211) ++ ++/* ++ * Next beacon time register ++ */ ++#define AR5K_TIMER0_5210 0x802c ++#define AR5K_TIMER0_5211 0x8028 ++#define AR5K_TIMER0 (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_TIMER0_5210 : AR5K_TIMER0_5211) ++ ++/* ++ * Next DMA beacon alert register ++ */ ++#define AR5K_TIMER1_5210 0x8030 ++#define AR5K_TIMER1_5211 0x802c ++#define AR5K_TIMER1 (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_TIMER1_5210 : AR5K_TIMER1_5211) ++ ++/* ++ * Next software beacon alert register ++ */ ++#define AR5K_TIMER2_5210 0x8034 ++#define AR5K_TIMER2_5211 0x8030 ++#define AR5K_TIMER2 (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_TIMER2_5210 : AR5K_TIMER2_5211) ++ ++/* ++ * Next ATIM window time register ++ */ ++#define AR5K_TIMER3_5210 0x8038 ++#define AR5K_TIMER3_5211 0x8034 ++#define AR5K_TIMER3 (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_TIMER3_5210 : AR5K_TIMER3_5211) ++ ++ ++/* ++ * 5210 First inter frame spacing register (IFS) ++ */ ++#define AR5K_IFS0 0x8040 ++#define AR5K_IFS0_SIFS 0x000007ff ++#define AR5K_IFS0_SIFS_S 0 ++#define AR5K_IFS0_DIFS 0x007ff800 ++#define AR5K_IFS0_DIFS_S 11 ++ ++/* ++ * 5210 Second inter frame spacing register (IFS) ++ */ ++#define AR5K_IFS1 0x8044 ++#define AR5K_IFS1_PIFS 0x00000fff ++#define AR5K_IFS1_PIFS_S 0 ++#define AR5K_IFS1_EIFS 0x03fff000 ++#define AR5K_IFS1_EIFS_S 12 ++#define AR5K_IFS1_CS_EN 0x04000000 ++ ++ ++/* ++ * CFP duration register ++ */ ++#define AR5K_CFP_DUR_5210 0x8048 ++#define AR5K_CFP_DUR_5211 0x8038 ++#define AR5K_CFP_DUR (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_CFP_DUR_5210 : AR5K_CFP_DUR_5211) ++ ++/* ++ * Receive filter register ++ * TODO: Get these out of ar5xxx.h on ath5k ++ */ ++#define AR5K_RX_FILTER_5210 0x804c /* Register Address [5210] */ ++#define AR5K_RX_FILTER_5211 0x803c /* Register Address [5211+] */ ++#define AR5K_RX_FILTER (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_RX_FILTER_5210 : AR5K_RX_FILTER_5211) ++#define AR5K_RX_FILTER_UCAST 0x00000001 /* Don't filter unicast frames */ ++#define AR5K_RX_FILTER_MCAST 0x00000002 /* Don't filter multicast frames */ ++#define AR5K_RX_FILTER_BCAST 0x00000004 /* Don't filter broadcast frames */ ++#define AR5K_RX_FILTER_CONTROL 0x00000008 /* Don't filter control frames */ ++#define AR5K_RX_FILTER_BEACON 0x00000010 /* Don't filter beacon frames */ ++#define AR5K_RX_FILTER_PROM 0x00000020 /* Set promiscuous mode */ ++#define AR5K_RX_FILTER_XRPOLL 0x00000040 /* Don't filter XR poll frame [5212+] */ ++#define AR5K_RX_FILTER_PROBEREQ 0x00000080 /* Don't filter probe requests [5212+] */ ++#define AR5K_RX_FILTER_PHYERR_5212 0x00000100 /* Don't filter phy errors [5212+] */ ++#define AR5K_RX_FILTER_RADARERR_5212 0x00000200 /* Don't filter phy radar errors [5212+] */ ++#define AR5K_RX_FILTER_PHYERR_5211 0x00000040 /* [5211] */ ++#define AR5K_RX_FILTER_RADARERR_5211 0x00000080 /* [5211] */ ++#define AR5K_RX_FILTER_PHYERR \ ++ ((ah->ah_version == AR5K_AR5211 ? \ ++ AR5K_RX_FILTER_PHYERR_5211 : AR5K_RX_FILTER_PHYERR_5212)) ++#define AR5K_RX_FILTER_RADARERR \ ++ ((ah->ah_version == AR5K_AR5211 ? \ ++ AR5K_RX_FILTER_RADARERR_5211 : AR5K_RX_FILTER_RADARERR_5212)) ++ ++/* ++ * Multicast filter register (lower 32 bits) ++ */ ++#define AR5K_MCAST_FILTER0_5210 0x8050 ++#define AR5K_MCAST_FILTER0_5211 0x8040 ++#define AR5K_MCAST_FILTER0 (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_MCAST_FILTER0_5210 : AR5K_MCAST_FILTER0_5211) ++ ++/* ++ * Multicast filter register (higher 16 bits) ++ */ ++#define AR5K_MCAST_FILTER1_5210 0x8054 ++#define AR5K_MCAST_FILTER1_5211 0x8044 ++#define AR5K_MCAST_FILTER1 (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_MCAST_FILTER1_5210 : AR5K_MCAST_FILTER1_5211) ++ ++ ++/* ++ * Transmit mask register (lower 32 bits) [5210] ++ */ ++#define AR5K_TX_MASK0 0x8058 ++ ++/* ++ * Transmit mask register (higher 16 bits) [5210] ++ */ ++#define AR5K_TX_MASK1 0x805c ++ ++/* ++ * Clear transmit mask [5210] ++ */ ++#define AR5K_CLR_TMASK 0x8060 ++ ++/* ++ * Trigger level register (before transmission) [5210] ++ */ ++#define AR5K_TRIG_LVL 0x8064 ++ ++ ++/* ++ * PCU control register ++ * ++ * Only DIS_RX is used in the code, the rest i guess are ++ * for tweaking/diagnostics. ++ */ ++#define AR5K_DIAG_SW_5210 0x8068 /* Register Address [5210] */ ++#define AR5K_DIAG_SW_5211 0x8048 /* Register Address [5211+] */ ++#define AR5K_DIAG_SW (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_DIAG_SW_5210 : AR5K_DIAG_SW_5211) ++#define AR5K_DIAG_SW_DIS_WEP_ACK 0x00000001 ++#define AR5K_DIAG_SW_DIS_ACK 0x00000002 /* Disable ACKs (?) */ ++#define AR5K_DIAG_SW_DIS_CTS 0x00000004 /* Disable CTSs (?) */ ++#define AR5K_DIAG_SW_DIS_ENC 0x00000008 /* Disable encryption (?) */ ++#define AR5K_DIAG_SW_DIS_DEC 0x00000010 /* Disable decryption (?) */ ++#define AR5K_DIAG_SW_DIS_TX 0x00000020 /* Disable transmit [5210] */ ++#define AR5K_DIAG_SW_DIS_RX_5210 0x00000040 /* Disable recieve */ ++#define AR5K_DIAG_SW_DIS_RX_5211 0x00000020 ++#define AR5K_DIAG_SW_DIS_RX (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_DIAG_SW_DIS_RX_5210 : AR5K_DIAG_SW_DIS_RX_5211) ++#define AR5K_DIAG_SW_LOOP_BACK_5210 0x00000080 /* Loopback (i guess it goes with DIS_TX) [5210] */ ++#define AR5K_DIAG_SW_LOOP_BACK_5211 0x00000040 ++#define AR5K_DIAG_SW_LOOP_BACK (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_DIAG_SW_LOOP_BACK_5210 : AR5K_DIAG_SW_LOOP_BACK_5211) ++#define AR5K_DIAG_SW_CORR_FCS_5210 0x00000100 ++#define AR5K_DIAG_SW_CORR_FCS_5211 0x00000080 ++#define AR5K_DIAG_SW_CORR_FCS (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_DIAG_SW_CORR_FCS_5210 : AR5K_DIAG_SW_CORR_FCS_5211) ++#define AR5K_DIAG_SW_CHAN_INFO_5210 0x00000200 ++#define AR5K_DIAG_SW_CHAN_INFO_5211 0x00000100 ++#define AR5K_DIAG_SW_CHAN_INFO (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_DIAG_SW_CHAN_INFO_5210 : AR5K_DIAG_SW_CHAN_INFO_5211) ++#define AR5K_DIAG_SW_EN_SCRAM_SEED_5211 0x00000200 /* Scrambler seed (?) */ ++#define AR5K_DIAG_SW_EN_SCRAM_SEED_5210 0x00000400 ++#define AR5K_DIAG_SW_EN_SCRAM_SEED (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_DIAG_SW_EN_SCRAM_SEED_5210 : AR5K_DIAG_SW_EN_SCRAM_SEED_5211) ++#define AR5K_DIAG_SW_ECO_ENABLE 0x00000400 /* [5211+] */ ++#define AR5K_DIAG_SW_SCVRAM_SEED 0x0003f800 /* [5210] */ ++#define AR5K_DIAG_SW_SCRAM_SEED_M 0x0001fc00 /* Scrambler seed mask (?) */ ++#define AR5K_DIAG_SW_SCRAM_SEED_S 10 ++#define AR5K_DIAG_SW_DIS_SEQ_INC 0x00040000 /* Disable seqnum increment (?)[5210] */ ++#define AR5K_DIAG_SW_FRAME_NV0_5210 0x00080000 ++#define AR5K_DIAG_SW_FRAME_NV0_5211 0x00020000 ++#define AR5K_DIAG_SW_FRAME_NV0 (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_DIAG_SW_FRAME_NV0_5210 : AR5K_DIAG_SW_FRAME_NV0_5211) ++#define AR5K_DIAG_SW_OBSPT_M 0x000c0000 ++#define AR5K_DIAG_SW_OBSPT_S 18 ++ ++/* ++ * TSF (clock) register (lower 32 bits) ++ */ ++#define AR5K_TSF_L32_5210 0x806c ++#define AR5K_TSF_L32_5211 0x804c ++#define AR5K_TSF_L32 (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_TSF_L32_5210 : AR5K_TSF_L32_5211) ++ ++/* ++ * TSF (clock) register (higher 32 bits) ++ */ ++#define AR5K_TSF_U32_5210 0x8070 ++#define AR5K_TSF_U32_5211 0x8050 ++#define AR5K_TSF_U32 (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_TSF_U32_5210 : AR5K_TSF_U32_5211) ++ ++/* ++ * Last beacon timestamp register ++ */ ++#define AR5K_LAST_TSTP 0x8080 ++ ++/* ++ * ADDAC test register [5211+] ++ */ ++#define AR5K_ADDAC_TEST 0x8054 ++#define AR5K_ADDAC_TEST_TXCONT 0x00000001 ++ ++/* ++ * Default antenna register [5211+] ++ */ ++#define AR5K_DEFAULT_ANTENNA 0x8058 ++ ++ ++ ++/* ++ * Retry count register [5210] ++ */ ++#define AR5K_RETRY_CNT 0x8084 /* Register Address [5210] */ ++#define AR5K_RETRY_CNT_SSH 0x0000003f /* Station short retry count (?) */ ++#define AR5K_RETRY_CNT_SLG 0x00000fc0 /* Station long retry count (?) */ ++ ++/* ++ * Back-off status register [5210] ++ */ ++#define AR5K_BACKOFF 0x8088 /* Register Address [5210] */ ++#define AR5K_BACKOFF_CW 0x000003ff /* Backoff Contention Window (?) */ ++#define AR5K_BACKOFF_CNT 0x03ff0000 /* Backoff count (?) */ ++ ++ ++ ++/* ++ * NAV register (current) ++ */ ++#define AR5K_NAV_5210 0x808c ++#define AR5K_NAV_5211 0x8084 ++#define AR5K_NAV (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_NAV_5210 : AR5K_NAV_5211) ++ ++/* ++ * RTS success register ++ */ ++#define AR5K_RTS_OK_5210 0x8090 ++#define AR5K_RTS_OK_5211 0x8088 ++#define AR5K_RTS_OK (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_RTS_OK_5210 : AR5K_RTS_OK_5211) ++ ++/* ++ * RTS failure register ++ */ ++#define AR5K_RTS_FAIL_5210 0x8094 ++#define AR5K_RTS_FAIL_5211 0x808c ++#define AR5K_RTS_FAIL (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_RTS_FAIL_5210 : AR5K_RTS_FAIL_5211) ++ ++/* ++ * ACK failure register ++ */ ++#define AR5K_ACK_FAIL_5210 0x8098 ++#define AR5K_ACK_FAIL_5211 0x8090 ++#define AR5K_ACK_FAIL (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_ACK_FAIL_5210 : AR5K_ACK_FAIL_5211) ++ ++/* ++ * FCS failure register ++ */ ++#define AR5K_FCS_FAIL_5210 0x809c ++#define AR5K_FCS_FAIL_5211 0x8094 ++#define AR5K_FCS_FAIL (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_FCS_FAIL_5210 : AR5K_FCS_FAIL_5211) ++ ++/* ++ * Beacon count register ++ */ ++#define AR5K_BEACON_CNT_5210 0x80a0 ++#define AR5K_BEACON_CNT_5211 0x8098 ++#define AR5K_BEACON_CNT (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_BEACON_CNT_5210 : AR5K_BEACON_CNT_5211) ++ ++ ++/*===5212 Specific PCU registers===*/ ++ ++/* ++ * XR (eXtended Range) mode register ++ */ ++#define AR5K_XRMODE 0x80c0 ++#define AR5K_XRMODE_POLL_TYPE_M 0x0000003f ++#define AR5K_XRMODE_POLL_TYPE_S 0 ++#define AR5K_XRMODE_POLL_SUBTYPE_M 0x0000003c ++#define AR5K_XRMODE_POLL_SUBTYPE_S 2 ++#define AR5K_XRMODE_POLL_WAIT_ALL 0x00000080 ++#define AR5K_XRMODE_SIFS_DELAY 0x000fff00 ++#define AR5K_XRMODE_FRAME_HOLD_M 0xfff00000 ++#define AR5K_XRMODE_FRAME_HOLD_S 20 ++ ++/* ++ * XR delay register ++ */ ++#define AR5K_XRDELAY 0x80c4 ++#define AR5K_XRDELAY_SLOT_DELAY_M 0x0000ffff ++#define AR5K_XRDELAY_SLOT_DELAY_S 0 ++#define AR5K_XRDELAY_CHIRP_DELAY_M 0xffff0000 ++#define AR5K_XRDELAY_CHIRP_DELAY_S 16 ++ ++/* ++ * XR timeout register ++ */ ++#define AR5K_XRTIMEOUT 0x80c8 ++#define AR5K_XRTIMEOUT_CHIRP_M 0x0000ffff ++#define AR5K_XRTIMEOUT_CHIRP_S 0 ++#define AR5K_XRTIMEOUT_POLL_M 0xffff0000 ++#define AR5K_XRTIMEOUT_POLL_S 16 ++ ++/* ++ * XR chirp register ++ */ ++#define AR5K_XRCHIRP 0x80cc ++#define AR5K_XRCHIRP_SEND 0x00000001 ++#define AR5K_XRCHIRP_GAP 0xffff0000 ++ ++/* ++ * XR stomp register ++ */ ++#define AR5K_XRSTOMP 0x80d0 ++#define AR5K_XRSTOMP_TX 0x00000001 ++#define AR5K_XRSTOMP_RX_ABORT 0x00000002 ++#define AR5K_XRSTOMP_RSSI_THRES 0x0000ff00 ++ ++/* ++ * First enhanced sleep register ++ */ ++#define AR5K_SLEEP0 0x80d4 ++#define AR5K_SLEEP0_NEXT_DTIM 0x0007ffff ++#define AR5K_SLEEP0_NEXT_DTIM_S 0 ++#define AR5K_SLEEP0_ASSUME_DTIM 0x00080000 ++#define AR5K_SLEEP0_ENH_SLEEP_EN 0x00100000 ++#define AR5K_SLEEP0_CABTO 0xff000000 ++#define AR5K_SLEEP0_CABTO_S 24 ++ ++/* ++ * Second enhanced sleep register ++ */ ++#define AR5K_SLEEP1 0x80d8 ++#define AR5K_SLEEP1_NEXT_TIM 0x0007ffff ++#define AR5K_SLEEP1_NEXT_TIM_S 0 ++#define AR5K_SLEEP1_BEACON_TO 0xff000000 ++#define AR5K_SLEEP1_BEACON_TO_S 24 ++ ++/* ++ * Third enhanced sleep register ++ */ ++#define AR5K_SLEEP2 0x80dc ++#define AR5K_SLEEP2_TIM_PER 0x0000ffff ++#define AR5K_SLEEP2_TIM_PER_S 0 ++#define AR5K_SLEEP2_DTIM_PER 0xffff0000 ++#define AR5K_SLEEP2_DTIM_PER_S 16 ++ ++/* ++ * BSSID mask registers ++ */ ++#define AR5K_BSS_IDM0 0x80e0 ++#define AR5K_BSS_IDM1 0x80e4 ++ ++/* ++ * TX power control (TPC) register ++ */ ++#define AR5K_TXPC 0x80e8 ++#define AR5K_TXPC_ACK_M 0x0000003f ++#define AR5K_TXPC_ACK_S 0 ++#define AR5K_TXPC_CTS_M 0x00003f00 ++#define AR5K_TXPC_CTS_S 8 ++#define AR5K_TXPC_CHIRP_M 0x003f0000 ++#define AR5K_TXPC_CHIRP_S 22 ++ ++/* ++ * Profile count registers ++ */ ++#define AR5K_PROFCNT_TX 0x80ec ++#define AR5K_PROFCNT_RX 0x80f0 ++#define AR5K_PROFCNT_RXCLR 0x80f4 ++#define AR5K_PROFCNT_CYCLE 0x80f8 ++ ++/* ++ * TSF parameter register ++ */ ++#define AR5K_TSF_PARM 0x8104 ++#define AR5K_TSF_PARM_INC_M 0x000000ff ++#define AR5K_TSF_PARM_INC_S 0 ++ ++/* ++ * PHY error filter register ++ */ ++#define AR5K_PHY_ERR_FIL 0x810c ++#define AR5K_PHY_ERR_FIL_RADAR 0x00000020 ++#define AR5K_PHY_ERR_FIL_OFDM 0x00020000 ++#define AR5K_PHY_ERR_FIL_CCK 0x02000000 ++ ++/* ++ * Rate duration register ++ */ ++#define AR5K_RATE_DUR_BASE 0x8700 ++#define AR5K_RATE_DUR(_n) (AR5K_RATE_DUR_BASE + ((_n) << 2)) ++ ++/*===5212 end===*/ ++ ++/* ++ * Key table (WEP) register ++ */ ++#define AR5K_KEYTABLE_0_5210 0x9000 ++#define AR5K_KEYTABLE_0_5211 0x8800 ++#define AR5K_KEYTABLE_5210(_n) (AR5K_KEYTABLE_0_5210 + ((_n) << 5)) ++#define AR5K_KEYTABLE_5211(_n) (AR5K_KEYTABLE_0_5211 + ((_n) << 5)) ++#define AR5K_KEYTABLE(_n) (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_KEYTABLE_5210(_n) : AR5K_KEYTABLE_5211(_n)) ++#define AR5K_KEYTABLE_OFF(_n, x) (AR5K_KEYTABLE(_n) + (x << 2)) ++#define AR5K_KEYTABLE_TYPE(_n) AR5K_KEYTABLE_OFF(_n, 5) ++#define AR5K_KEYTABLE_TYPE_40 0x00000000 ++#define AR5K_KEYTABLE_TYPE_104 0x00000001 ++#define AR5K_KEYTABLE_TYPE_128 0x00000003 ++#define AR5K_KEYTABLE_TYPE_TKIP 0x00000004 /* [5212+] */ ++#define AR5K_KEYTABLE_TYPE_AES 0x00000005 /* [5211+] */ ++#define AR5K_KEYTABLE_TYPE_CCM 0x00000006 /* [5212+] */ ++#define AR5K_KEYTABLE_TYPE_NULL 0x00000007 /* [5211+] */ ++#define AR5K_KEYTABLE_ANTENNA 0x00000008 /* [5212+] */ ++#define AR5K_KEYTABLE_MAC0(_n) AR5K_KEYTABLE_OFF(_n, 6) ++#define AR5K_KEYTABLE_MAC1(_n) AR5K_KEYTABLE_OFF(_n, 7) ++#define AR5K_KEYTABLE_VALID 0x00008000 ++ ++/* WEP 40-bit = 40-bit entered key + 24 bit IV = 64-bit ++ * WEP 104-bit = 104-bit entered key + 24-bit IV = 128-bit ++ * WEP 128-bit = 128-bit entered key + 24 bit IV = 152-bit ++ * ++ * Some vendors have introduced bigger WEP keys to address ++ * security vulnerabilities in WEP. This includes: ++ * ++ * WEP 232-bit = 232-bit entered key + 24 bit IV = 256-bit ++ * ++ * We can expand this if we find ar5k Atheros cards with a larger ++ * key table size. ++ */ ++#define AR5K_KEYTABLE_SIZE_5210 64 ++#define AR5K_KEYTABLE_SIZE_5211 128 ++#define AR5K_KEYTABLE_SIZE (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211) ++ ++ ++/*===PHY REGISTERS===*/ ++ ++/* ++ * PHY register ++ */ ++#define AR5K_PHY_BASE 0x9800 ++#define AR5K_PHY(_n) (AR5K_PHY_BASE + ((_n) << 2)) ++#define AR5K_PHY_SHIFT_2GHZ 0x00004007 ++#define AR5K_PHY_SHIFT_5GHZ 0x00000007 ++ ++/* ++ * PHY frame control register [5110] /turbo mode register [5111+] ++ * ++ * There is another frame control register for [5111+] ++ * at address 0x9944 (see below) but the 2 first flags ++ * are common here between 5110 frame control register ++ * and [5111+] turbo mode register, so this also works as ++ * a "turbo mode register" for 5110. We treat this one as ++ * a frame control register for 5110 below. ++ */ ++#define AR5K_PHY_TURBO 0x9804 ++#define AR5K_PHY_TURBO_MODE 0x00000001 ++#define AR5K_PHY_TURBO_SHORT 0x00000002 ++ ++/* ++ * PHY agility command register ++ */ ++#define AR5K_PHY_AGC 0x9808 ++#define AR5K_PHY_AGC_DISABLE 0x08000000 ++ ++/* ++ * PHY timing register [5112+] ++ */ ++#define AR5K_PHY_TIMING_3 0x9814 ++#define AR5K_PHY_TIMING_3_DSC_MAN 0xfffe0000 ++#define AR5K_PHY_TIMING_3_DSC_MAN_S 17 ++#define AR5K_PHY_TIMING_3_DSC_EXP 0x0001e000 ++#define AR5K_PHY_TIMING_3_DSC_EXP_S 13 ++ ++/* ++ * PHY chip revision register ++ */ ++#define AR5K_PHY_CHIP_ID 0x9818 ++ ++/* ++ * PHY activation register ++ */ ++#define AR5K_PHY_ACT 0x981c ++#define AR5K_PHY_ACT_ENABLE 0x00000001 ++#define AR5K_PHY_ACT_DISABLE 0x00000002 ++ ++/* ++ * PHY signal register ++ */ ++#define AR5K_PHY_SIG 0x9858 ++#define AR5K_PHY_SIG_FIRSTEP 0x0003f000 ++#define AR5K_PHY_SIG_FIRSTEP_S 12 ++#define AR5K_PHY_SIG_FIRPWR 0x03fc0000 ++#define AR5K_PHY_SIG_FIRPWR_S 18 ++ ++/* ++ * PHY coarse agility control register ++ */ ++#define AR5K_PHY_AGCCOARSE 0x985c ++#define AR5K_PHY_AGCCOARSE_LO 0x00007f80 ++#define AR5K_PHY_AGCCOARSE_LO_S 7 ++#define AR5K_PHY_AGCCOARSE_HI 0x003f8000 ++#define AR5K_PHY_AGCCOARSE_HI_S 15 ++ ++/* ++ * PHY agility control register ++ */ ++#define AR5K_PHY_AGCCTL 0x9860 /* Register address */ ++#define AR5K_PHY_AGCCTL_CAL 0x00000001 /* Enable PHY calibration */ ++#define AR5K_PHY_AGCCTL_NF 0x00000002 /* Enable Noise Floor calibration */ ++ ++/* ++ * PHY noise floor status register ++ */ ++#define AR5K_PHY_NF 0x9864 ++#define AR5K_PHY_NF_M 0x000001ff ++#define AR5K_PHY_NF_ACTIVE 0x00000100 ++#define AR5K_PHY_NF_RVAL(_n) (((_n) >> 19) & AR5K_PHY_NF_M) ++#define AR5K_PHY_NF_AVAL(_n) (-((_n) ^ AR5K_PHY_NF_M) + 1) ++#define AR5K_PHY_NF_SVAL(_n) (((_n) & AR5K_PHY_NF_M) | (1 << 9)) ++ ++/* ++ * PHY ADC saturation register [5110] ++ */ ++#define AR5K_PHY_ADCSAT 0x9868 ++#define AR5K_PHY_ADCSAT_ICNT 0x0001f800 ++#define AR5K_PHY_ADCSAT_ICNT_S 11 ++#define AR5K_PHY_ADCSAT_THR 0x000007e0 ++#define AR5K_PHY_ADCSAT_THR_S 5 ++ ++/* ++ * PHY sleep registers [5112+] ++ */ ++#define AR5K_PHY_SCR 0x9870 ++#define AR5K_PHY_SCR_32MHZ 0x0000001f ++#define AR5K_PHY_SLMT 0x9874 ++#define AR5K_PHY_SLMT_32MHZ 0x0000007f ++#define AR5K_PHY_SCAL 0x9878 ++#define AR5K_PHY_SCAL_32MHZ 0x0000000e ++ ++/* ++ * PHY PLL (Phase Locked Loop) control register ++ */ ++#define AR5K_PHY_PLL 0x987c ++#define AR5K_PHY_PLL_20MHZ 0x13 /* For half rate (?) [5111+] */ ++#define AR5K_PHY_PLL_40MHZ_5211 0x18 /* For 802.11a */ ++#define AR5K_PHY_PLL_40MHZ_5212 0x000000aa ++#define AR5K_PHY_PLL_40MHZ (ah->ah_version == AR5K_AR5211 ? \ ++ AR5K_PHY_PLL_40MHZ_5211 : AR5K_PHY_PLL_40MHZ_5212) ++#define AR5K_PHY_PLL_44MHZ_5211 0x19 /* For 802.11b/g */ ++#define AR5K_PHY_PLL_44MHZ_5212 0x000000ab ++#define AR5K_PHY_PLL_44MHZ (ah->ah_version == AR5K_AR5211 ? \ ++ AR5K_PHY_PLL_44MHZ_5211 : AR5K_PHY_PLL_44MHZ_5212) ++#define AR5K_PHY_PLL_RF5111 0x00000000 ++#define AR5K_PHY_PLL_RF5112 0x00000040 ++ ++/* ++ * RF Buffer register ++ * ++ * There are some special control registers on the RF chip ++ * that hold various operation settings related mostly to ++ * the analog parts (channel, gain adjustment etc). ++ * ++ * We don't write on those registers directly but ++ * we send a data packet on the buffer register and ++ * then write on another special register to notify hw ++ * to apply the settings. This is done so that control registers ++ * can be dynamicaly programmed during operation and the settings ++ * are applied faster on the hw. ++ * ++ * We sent such data packets during rf initialization and channel change ++ * through ath5k_hw_rf*_rfregs and ath5k_hw_rf*_channel functions. ++ * ++ * The data packets we send during initializadion are inside ath5k_ini_rf ++ * struct (see ath5k_hw.h) and each one is related to an "rf register bank". ++ * We use *rfregs functions to modify them acording to current operation ++ * mode and eeprom values and pass them all together to the chip. ++ * ++ * It's obvious from the code that 0x989c is the buffer register but ++ * for the other special registers that we write to after sending each ++ * packet, i have no idea. So i'll name them BUFFER_CONTROL_X registers ++ * for now. It's interesting that they are also used for some other operations. ++ * ++ * Also check out hw.h and U.S. Patent 6677779 B1 (about buffer ++ * registers and control registers): ++ * ++ * http://www.google.com/patents?id=qNURAAAAEBAJ ++ */ ++ ++#define AR5K_RF_BUFFER 0x989c ++#define AR5K_RF_BUFFER_CONTROL_0 0x98c0 /* Channel on 5110 */ ++#define AR5K_RF_BUFFER_CONTROL_1 0x98c4 /* Bank 7 on 5112 */ ++#define AR5K_RF_BUFFER_CONTROL_2 0x98cc /* Bank 7 on 5111 */ ++ ++#define AR5K_RF_BUFFER_CONTROL_3 0x98d0 /* Bank 2 on 5112 */ ++ /* Channel set on 5111 */ ++ /* Used to read radio revision*/ ++ ++#define AR5K_RF_BUFFER_CONTROL_4 0x98d4 /* RF Stage register on 5110 */ ++ /* Bank 0,1,2,6 on 5111 */ ++ /* Bank 1 on 5112 */ ++ /* Used during activation on 5111 */ ++ ++#define AR5K_RF_BUFFER_CONTROL_5 0x98d8 /* Bank 3 on 5111 */ ++ /* Used during activation on 5111 */ ++ /* Channel on 5112 */ ++ /* Bank 6 on 5112 */ ++ ++#define AR5K_RF_BUFFER_CONTROL_6 0x98dc /* Bank 3 on 5112 */ ++ ++/* ++ * PHY RF stage register [5210] ++ */ ++#define AR5K_PHY_RFSTG 0x98d4 ++#define AR5K_PHY_RFSTG_DISABLE 0x00000021 ++ ++/* ++ * PHY receiver delay register [5111+] ++ */ ++#define AR5K_PHY_RX_DELAY 0x9914 ++#define AR5K_PHY_RX_DELAY_M 0x00003fff ++ ++/* ++ * PHY timing I(nphase) Q(adrature) control register [5111+] ++ */ ++#define AR5K_PHY_IQ 0x9920 /* Register address */ ++#define AR5K_PHY_IQ_CORR_Q_Q_COFF 0x0000001f /* Mask for q correction info */ ++#define AR5K_PHY_IQ_CORR_Q_I_COFF 0x000007e0 /* Mask for i correction info */ ++#define AR5K_PHY_IQ_CORR_Q_I_COFF_S 5 ++#define AR5K_PHY_IQ_CORR_ENABLE 0x00000800 /* Enable i/q correction */ ++#define AR5K_PHY_IQ_CAL_NUM_LOG_MAX 0x0000f000 ++#define AR5K_PHY_IQ_CAL_NUM_LOG_MAX_S 12 ++#define AR5K_PHY_IQ_RUN 0x00010000 /* Run i/q calibration */ ++ ++ ++/* ++ * PHY PAPD probe register [5111+ (?)] ++ * Is this only present in 5212 ? ++ * Because it's always 0 in 5211 initialization code ++ */ ++#define AR5K_PHY_PAPD_PROBE 0x9930 ++#define AR5K_PHY_PAPD_PROBE_TXPOWER 0x00007e00 ++#define AR5K_PHY_PAPD_PROBE_TXPOWER_S 9 ++#define AR5K_PHY_PAPD_PROBE_TX_NEXT 0x00008000 ++#define AR5K_PHY_PAPD_PROBE_TYPE 0x01800000 /* [5112+] */ ++#define AR5K_PHY_PAPD_PROBE_TYPE_S 23 ++#define AR5K_PHY_PAPD_PROBE_TYPE_OFDM 0 ++#define AR5K_PHY_PAPD_PROBE_TYPE_XR 1 ++#define AR5K_PHY_PAPD_PROBE_TYPE_CCK 2 ++#define AR5K_PHY_PAPD_PROBE_GAINF 0xfe000000 ++#define AR5K_PHY_PAPD_PROBE_GAINF_S 25 ++#define AR5K_PHY_PAPD_PROBE_INI_5111 0x00004883 /* [5212+] */ ++#define AR5K_PHY_PAPD_PROBE_INI_5112 0x00004882 /* [5212+] */ ++ ++ ++/* ++ * PHY TX rate power registers [5112+] ++ */ ++#define AR5K_PHY_TXPOWER_RATE1 0x9934 ++#define AR5K_PHY_TXPOWER_RATE2 0x9938 ++#define AR5K_PHY_TXPOWER_RATE_MAX 0x993c ++#define AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE 0x00000040 ++#define AR5K_PHY_TXPOWER_RATE3 0xa234 ++#define AR5K_PHY_TXPOWER_RATE4 0xa238 ++ ++/* ++ * PHY frame control register [5111+] ++ */ ++#define AR5K_PHY_FRAME_CTL_5210 0x9804 ++#define AR5K_PHY_FRAME_CTL_5211 0x9944 ++#define AR5K_PHY_FRAME_CTL (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_PHY_FRAME_CTL_5210 : AR5K_PHY_FRAME_CTL_5211) ++/*---[5111+]---*/ ++#define AR5K_PHY_FRAME_CTL_TX_CLIP 0x00000038 ++#define AR5K_PHY_FRAME_CTL_TX_CLIP_S 3 ++/*---[5110/5111]---*/ ++#define AR5K_PHY_FRAME_CTL_TIMING_ERR 0x01000000 ++#define AR5K_PHY_FRAME_CTL_PARITY_ERR 0x02000000 ++#define AR5K_PHY_FRAME_CTL_ILLRATE_ERR 0x04000000 /* illegal rate */ ++#define AR5K_PHY_FRAME_CTL_ILLLEN_ERR 0x08000000 /* illegal length */ ++#define AR5K_PHY_FRAME_CTL_SERVICE_ERR 0x20000000 ++#define AR5K_PHY_FRAME_CTL_TXURN_ERR 0x40000000 /* tx underrun */ ++#define AR5K_PHY_FRAME_CTL_INI AR5K_PHY_FRAME_CTL_SERVICE_ERR | \ ++ AR5K_PHY_FRAME_CTL_TXURN_ERR | \ ++ AR5K_PHY_FRAME_CTL_ILLLEN_ERR | \ ++ AR5K_PHY_FRAME_CTL_ILLRATE_ERR | \ ++ AR5K_PHY_FRAME_CTL_PARITY_ERR | \ ++ AR5K_PHY_FRAME_CTL_TIMING_ERR ++ ++/* ++ * PHY radar detection register [5111+] ++ */ ++#define AR5K_PHY_RADAR 0x9954 ++ ++/* Radar enable ........ ........ ........ .......1 */ ++#define AR5K_PHY_RADAR_ENABLE 0x00000001 ++#define AR5K_PHY_RADAR_DISABLE 0x00000000 ++#define AR5K_PHY_RADAR_ENABLE_S 0 ++ ++/* This is the value found on the card .1.111.1 .1.1.... 111....1 1...1... ++at power on. */ ++#define AR5K_PHY_RADAR_PWONDEF_AR5213 0x5d50e188 ++ ++/* This is the value found on the card .1.1.111 ..11...1 .1...1.1 1...11.1 ++after DFS is enabled */ ++#define AR5K_PHY_RADAR_ENABLED_AR5213 0x5731458d ++ ++/* Finite Impulse Response (FIR) filter .1111111 ........ ........ ........ ++ * power out threshold. ++ * 7-bits, standard power range {0..127} in 1/2 dBm units. */ ++#define AR5K_PHY_RADAR_FIRPWROUTTHR 0x7f000000 ++#define AR5K_PHY_RADAR_FIRPWROUTTHR_S 24 ++ ++/* Radar RSSI/SNR threshold. ........ 111111.. ........ ........ ++ * 6-bits, dBm range {0..63} in dBm units. */ ++#define AR5K_PHY_RADAR_RADARRSSITHR 0x00fc0000 ++#define AR5K_PHY_RADAR_RADARRSSITHR_S 18 ++ ++/* Pulse height threshold ........ ......11 1111.... ........ ++ * 6-bits, dBm range {0..63} in dBm units. */ ++#define AR5K_PHY_RADAR_PULSEHEIGHTTHR 0x0003f000 ++#define AR5K_PHY_RADAR_PULSEHEIGHTTHR_S 12 ++ ++/* Pulse RSSI/SNR threshold ........ ........ ....1111 11...... ++ * 6-bits, dBm range {0..63} in dBm units. */ ++#define AR5K_PHY_RADAR_PULSERSSITHR 0x00000fc0 ++#define AR5K_PHY_RADAR_PULSERSSITHR_S 6 ++ ++/* Inband threshold ........ ........ ........ ..11111. ++ * 5-bits, units unknown {0..31} (? MHz ?) */ ++#define AR5K_PHY_RADAR_INBANDTHR 0x0000003e ++#define AR5K_PHY_RADAR_INBANDTHR_S 1 ++ ++/* ++ * PHY antenna switch table registers [5110] ++ */ ++#define AR5K_PHY_ANT_SWITCH_TABLE_0 0x9960 ++#define AR5K_PHY_ANT_SWITCH_TABLE_1 0x9964 ++ ++/* ++ * PHY clock sleep registers [5112+] ++ */ ++#define AR5K_PHY_SCLOCK 0x99f0 ++#define AR5K_PHY_SCLOCK_32MHZ 0x0000000c ++#define AR5K_PHY_SDELAY 0x99f4 ++#define AR5K_PHY_SDELAY_32MHZ 0x000000ff ++#define AR5K_PHY_SPENDING 0x99f8 ++#define AR5K_PHY_SPENDING_RF5111 0x00000018 ++#define AR5K_PHY_SPENDING_RF5112 0x00000014 ++ ++/* ++ * Misc PHY/radio registers [5110 - 5111] ++ */ ++#define AR5K_BB_GAIN_BASE 0x9b00 /* BaseBand Amplifier Gain table base address */ ++#define AR5K_BB_GAIN(_n) (AR5K_BB_GAIN_BASE + ((_n) << 2)) ++#define AR5K_RF_GAIN_BASE 0x9a00 /* RF Amplrifier Gain table base address */ ++#define AR5K_RF_GAIN(_n) (AR5K_RF_GAIN_BASE + ((_n) << 2)) ++ ++/* ++ * PHY timing IQ calibration result register [5111+] ++ */ ++#define AR5K_PHY_IQRES_CAL_PWR_I 0x9c10 /* I (Inphase) power value */ ++#define AR5K_PHY_IQRES_CAL_PWR_Q 0x9c14 /* Q (Quadrature) power value */ ++#define AR5K_PHY_IQRES_CAL_CORR 0x9c18 /* I/Q Correlation */ ++ ++/* ++ * PHY current RSSI register [5111+] ++ */ ++#define AR5K_PHY_CURRENT_RSSI 0x9c1c ++ ++/* ++ * PHY PCDAC TX power table ++ */ ++#define AR5K_PHY_PCDAC_TXPOWER_BASE_5211 0xa180 ++#define AR5K_PHY_PCDAC_TXPOWER_BASE_5413 0xa280 ++#define AR5K_PHY_PCDAC_TXPOWER_BASE (ah->ah_radio >= AR5K_RF5413 ? \ ++ AR5K_PHY_PCDAC_TXPOWER_BASE_5413 :\ ++ AR5K_PHY_PCDAC_TXPOWER_BASE_5211) ++#define AR5K_PHY_PCDAC_TXPOWER(_n) (AR5K_PHY_PCDAC_TXPOWER_BASE + ((_n) << 2)) ++ ++/* ++ * PHY mode register [5111+] ++ */ ++#define AR5K_PHY_MODE 0x0a200 /* Register address */ ++#define AR5K_PHY_MODE_MOD 0x00000001 /* PHY Modulation mask*/ ++#define AR5K_PHY_MODE_MOD_OFDM 0 ++#define AR5K_PHY_MODE_MOD_CCK 1 ++#define AR5K_PHY_MODE_FREQ 0x00000002 /* Freq mode mask */ ++#define AR5K_PHY_MODE_FREQ_5GHZ 0 ++#define AR5K_PHY_MODE_FREQ_2GHZ 2 ++#define AR5K_PHY_MODE_MOD_DYN 0x00000004 /* Dynamic OFDM/CCK mode mask [5112+] */ ++#define AR5K_PHY_MODE_RAD 0x00000008 /* [5212+] */ ++#define AR5K_PHY_MODE_RAD_RF5111 0 ++#define AR5K_PHY_MODE_RAD_RF5112 8 ++#define AR5K_PHY_MODE_XR 0x00000010 /* [5112+] */ ++ ++/* ++ * PHY CCK transmit control register [5111+ (?)] ++ */ ++#define AR5K_PHY_CCKTXCTL 0xa204 ++#define AR5K_PHY_CCKTXCTL_WORLD 0x00000000 ++#define AR5K_PHY_CCKTXCTL_JAPAN 0x00000010 ++ ++/* ++ * PHY 2GHz gain register [5111+] ++ */ ++#define AR5K_PHY_GAIN_2GHZ 0xa20c ++#define AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX 0x00fc0000 ++#define AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX_S 18 ++#define AR5K_PHY_GAIN_2GHZ_INI_5111 0x6480416c +diff -up /dev/null linux-2.6.23.noarch/drivers/net/wireless/ath5k/regdom.h +--- /dev/null 2007-12-21 08:33:07.834165456 -0500 ++++ linux-2.6.23.noarch/drivers/net/wireless/ath5k/regdom.h 2007-12-21 12:18:50.000000000 -0500 +@@ -0,0 +1,500 @@ ++/* ++ * Copyright (c) 2004, 2005 Reyk Floeter ++ * ++ * Permission to use, copy, modify, and 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 _IEEE80211_REGDOMAIN_H_ ++#define _IEEE80211_REGDOMAIN_H_ ++ ++#include ++ ++/* Default regulation domain if stored value EEPROM value is invalid */ ++#define AR5K_TUNE_REGDOMAIN DMN_FCC2_FCCA /* Canada */ ++#define AR5K_TUNE_CTRY CTRY_DEFAULT ++ ++ ++enum ath5k_regdom { ++ DMN_DEFAULT = 0x00, ++ DMN_NULL_WORLD = 0x03, ++ DMN_NULL_ETSIB = 0x07, ++ DMN_NULL_ETSIC = 0x08, ++ DMN_FCC1_FCCA = 0x10, ++ DMN_FCC1_WORLD = 0x11, ++ DMN_FCC2_FCCA = 0x20, ++ DMN_FCC2_WORLD = 0x21, ++ DMN_FCC2_ETSIC = 0x22, ++ DMN_FRANCE_NULL = 0x31, ++ DMN_FCC3_FCCA = 0x3A, ++ DMN_ETSI1_WORLD = 0x37, ++ DMN_ETSI3_ETSIA = 0x32, ++ DMN_ETSI2_WORLD = 0x35, ++ DMN_ETSI3_WORLD = 0x36, ++ DMN_ETSI4_WORLD = 0x30, ++ DMN_ETSI4_ETSIC = 0x38, ++ DMN_ETSI5_WORLD = 0x39, ++ DMN_ETSI6_WORLD = 0x34, ++ DMN_ETSI_NULL = 0x33, ++ DMN_MKK1_MKKA = 0x40, ++ DMN_MKK1_MKKB = 0x41, ++ DMN_APL4_WORLD = 0x42, ++ DMN_MKK2_MKKA = 0x43, ++ DMN_APL_NULL = 0x44, ++ DMN_APL2_WORLD = 0x45, ++ DMN_APL2_APLC = 0x46, ++ DMN_APL3_WORLD = 0x47, ++ DMN_MKK1_FCCA = 0x48, ++ DMN_APL2_APLD = 0x49, ++ DMN_MKK1_MKKA1 = 0x4A, ++ DMN_MKK1_MKKA2 = 0x4B, ++ DMN_APL1_WORLD = 0x52, ++ DMN_APL1_FCCA = 0x53, ++ DMN_APL1_APLA = 0x54, ++ DMN_APL1_ETSIC = 0x55, ++ DMN_APL2_ETSIC = 0x56, ++ DMN_APL5_WORLD = 0x58, ++ DMN_WOR0_WORLD = 0x60, ++ DMN_WOR1_WORLD = 0x61, ++ DMN_WOR2_WORLD = 0x62, ++ DMN_WOR3_WORLD = 0x63, ++ DMN_WOR4_WORLD = 0x64, ++ DMN_WOR5_ETSIC = 0x65, ++ DMN_WOR01_WORLD = 0x66, ++ DMN_WOR02_WORLD = 0x67, ++ DMN_EU1_WORLD = 0x68, ++ DMN_WOR9_WORLD = 0x69, ++ DMN_WORA_WORLD = 0x6A, ++ ++ DMN_APL1 = 0xf0000001, ++ DMN_APL2 = 0xf0000002, ++ DMN_APL3 = 0xf0000004, ++ DMN_APL4 = 0xf0000008, ++ DMN_APL5 = 0xf0000010, ++ DMN_ETSI1 = 0xf0000020, ++ DMN_ETSI2 = 0xf0000040, ++ DMN_ETSI3 = 0xf0000080, ++ DMN_ETSI4 = 0xf0000100, ++ DMN_ETSI5 = 0xf0000200, ++ DMN_ETSI6 = 0xf0000400, ++ DMN_ETSIA = 0xf0000800, ++ DMN_ETSIB = 0xf0001000, ++ DMN_ETSIC = 0xf0002000, ++ DMN_FCC1 = 0xf0004000, ++ DMN_FCC2 = 0xf0008000, ++ DMN_FCC3 = 0xf0010000, ++ DMN_FCCA = 0xf0020000, ++ DMN_APLD = 0xf0040000, ++ DMN_MKK1 = 0xf0080000, ++ DMN_MKK2 = 0xf0100000, ++ DMN_MKKA = 0xf0200000, ++ DMN_NULL = 0xf0400000, ++ DMN_WORLD = 0xf0800000, ++ DMN_DEBUG = 0xf1000000 /* used for debugging */ ++}; ++ ++#define IEEE80211_DMN(_d) ((_d) & ~0xf0000000) ++ ++enum ath5k_countrycode { ++ CTRY_DEFAULT = 0, /* Default domain (NA) */ ++ CTRY_ALBANIA = 8, /* Albania */ ++ CTRY_ALGERIA = 12, /* Algeria */ ++ CTRY_ARGENTINA = 32, /* Argentina */ ++ CTRY_ARMENIA = 51, /* Armenia */ ++ CTRY_AUSTRALIA = 36, /* Australia */ ++ CTRY_AUSTRIA = 40, /* Austria */ ++ CTRY_AZERBAIJAN = 31, /* Azerbaijan */ ++ CTRY_BAHRAIN = 48, /* Bahrain */ ++ CTRY_BELARUS = 112, /* Belarus */ ++ CTRY_BELGIUM = 56, /* Belgium */ ++ CTRY_BELIZE = 84, /* Belize */ ++ CTRY_BOLIVIA = 68, /* Bolivia */ ++ CTRY_BRAZIL = 76, /* Brazil */ ++ CTRY_BRUNEI_DARUSSALAM = 96, /* Brunei Darussalam */ ++ CTRY_BULGARIA = 100, /* Bulgaria */ ++ CTRY_CANADA = 124, /* Canada */ ++ CTRY_CHILE = 152, /* Chile */ ++ CTRY_CHINA = 156, /* People's Republic of China */ ++ CTRY_COLOMBIA = 170, /* Colombia */ ++ CTRY_COSTA_RICA = 188, /* Costa Rica */ ++ CTRY_CROATIA = 191, /* Croatia */ ++ CTRY_CYPRUS = 196, /* Cyprus */ ++ CTRY_CZECH = 203, /* Czech Republic */ ++ CTRY_DENMARK = 208, /* Denmark */ ++ CTRY_DOMINICAN_REPUBLIC = 214, /* Dominican Republic */ ++ CTRY_ECUADOR = 218, /* Ecuador */ ++ CTRY_EGYPT = 818, /* Egypt */ ++ CTRY_EL_SALVADOR = 222, /* El Salvador */ ++ CTRY_ESTONIA = 233, /* Estonia */ ++ CTRY_FAEROE_ISLANDS = 234, /* Faeroe Islands */ ++ CTRY_FINLAND = 246, /* Finland */ ++ CTRY_FRANCE = 250, /* France */ ++ CTRY_FRANCE2 = 255, /* France2 */ ++ CTRY_GEORGIA = 268, /* Georgia */ ++ CTRY_GERMANY = 276, /* Germany */ ++ CTRY_GREECE = 300, /* Greece */ ++ CTRY_GUATEMALA = 320, /* Guatemala */ ++ CTRY_HONDURAS = 340, /* Honduras */ ++ CTRY_HONG_KONG = 344, /* Hong Kong S.A.R., P.R.C. */ ++ CTRY_HUNGARY = 348, /* Hungary */ ++ CTRY_ICELAND = 352, /* Iceland */ ++ CTRY_INDIA = 356, /* India */ ++ CTRY_INDONESIA = 360, /* Indonesia */ ++ CTRY_IRAN = 364, /* Iran */ ++ CTRY_IRAQ = 368, /* Iraq */ ++ CTRY_IRELAND = 372, /* Ireland */ ++ CTRY_ISRAEL = 376, /* Israel */ ++ CTRY_ITALY = 380, /* Italy */ ++ CTRY_JAMAICA = 388, /* Jamaica */ ++ CTRY_JAPAN = 392, /* Japan */ ++ CTRY_JAPAN1 = 393, /* Japan (JP1) */ ++ CTRY_JAPAN2 = 394, /* Japan (JP0) */ ++ CTRY_JAPAN3 = 395, /* Japan (JP1-1) */ ++ CTRY_JAPAN4 = 396, /* Japan (JE1) */ ++ CTRY_JAPAN5 = 397, /* Japan (JE2) */ ++ CTRY_JORDAN = 400, /* Jordan */ ++ CTRY_KAZAKHSTAN = 398, /* Kazakhstan */ ++ CTRY_KENYA = 404, /* Kenya */ ++ CTRY_KOREA_NORTH = 408, /* North Korea */ ++ CTRY_KOREA_ROC = 410, /* South Korea */ ++ CTRY_KOREA_ROC2 = 411, /* South Korea */ ++ CTRY_KUWAIT = 414, /* Kuwait */ ++ CTRY_LATVIA = 428, /* Latvia */ ++ CTRY_LEBANON = 422, /* Lebanon */ ++ CTRY_LIBYA = 434, /* Libya */ ++ CTRY_LIECHTENSTEIN = 438, /* Liechtenstein */ ++ CTRY_LITHUANIA = 440, /* Lithuania */ ++ CTRY_LUXEMBOURG = 442, /* Luxembourg */ ++ CTRY_MACAU = 446, /* Macau */ ++ CTRY_MACEDONIA = 807, /* Republic of Macedonia */ ++ CTRY_MALAYSIA = 458, /* Malaysia */ ++ CTRY_MEXICO = 484, /* Mexico */ ++ CTRY_MONACO = 492, /* Principality of Monaco */ ++ CTRY_MOROCCO = 504, /* Morocco */ ++ CTRY_NETHERLANDS = 528, /* Netherlands */ ++ CTRY_NEW_ZEALAND = 554, /* New Zealand */ ++ CTRY_NICARAGUA = 558, /* Nicaragua */ ++ CTRY_NORWAY = 578, /* Norway */ ++ CTRY_OMAN = 512, /* Oman */ ++ CTRY_PAKISTAN = 586, /* Islamic Republic of Pakistan */ ++ CTRY_PANAMA = 591, /* Panama */ ++ CTRY_PARAGUAY = 600, /* Paraguay */ ++ CTRY_PERU = 604, /* Peru */ ++ CTRY_PHILIPPINES = 608, /* Republic of the Philippines */ ++ CTRY_POLAND = 616, /* Poland */ ++ CTRY_PORTUGAL = 620, /* Portugal */ ++ CTRY_PUERTO_RICO = 630, /* Puerto Rico */ ++ CTRY_QATAR = 634, /* Qatar */ ++ CTRY_ROMANIA = 642, /* Romania */ ++ CTRY_RUSSIA = 643, /* Russia */ ++ CTRY_SAUDI_ARABIA = 682, /* Saudi Arabia */ ++ CTRY_SINGAPORE = 702, /* Singapore */ ++ CTRY_SLOVAKIA = 703, /* Slovak Republic */ ++ CTRY_SLOVENIA = 705, /* Slovenia */ ++ CTRY_SOUTH_AFRICA = 710, /* South Africa */ ++ CTRY_SPAIN = 724, /* Spain */ ++ CTRY_SRI_LANKA = 728, /* Sri Lanka */ ++ CTRY_SWEDEN = 752, /* Sweden */ ++ CTRY_SWITZERLAND = 756, /* Switzerland */ ++ CTRY_SYRIA = 760, /* Syria */ ++ CTRY_TAIWAN = 158, /* Taiwan */ ++ CTRY_THAILAND = 764, /* Thailand */ ++ CTRY_TRINIDAD_Y_TOBAGO = 780, /* Trinidad y Tobago */ ++ CTRY_TUNISIA = 788, /* Tunisia */ ++ CTRY_TURKEY = 792, /* Turkey */ ++ CTRY_UAE = 784, /* U.A.E. */ ++ CTRY_UKRAINE = 804, /* Ukraine */ ++ CTRY_UNITED_KINGDOM = 826, /* United Kingdom */ ++ CTRY_UNITED_STATES = 840, /* United States */ ++ CTRY_URUGUAY = 858, /* Uruguay */ ++ CTRY_UZBEKISTAN = 860, /* Uzbekistan */ ++ CTRY_VENEZUELA = 862, /* Venezuela */ ++ CTRY_VIET_NAM = 704, /* Viet Nam */ ++ CTRY_YEMEN = 887, /* Yemen */ ++ CTRY_ZIMBABWE = 716, /* Zimbabwe */ ++}; ++ ++#define IEEE80211_CHANNELS_2GHZ_MIN 2412 /* 2GHz channel 1 */ ++#define IEEE80211_CHANNELS_2GHZ_MAX 2732 /* 2GHz channel 26 */ ++#define IEEE80211_CHANNELS_5GHZ_MIN 5005 /* 5GHz channel 1 */ ++#define IEEE80211_CHANNELS_5GHZ_MAX 6100 /* 5GHz channel 220 */ ++ ++struct ath5k_regchannel { ++ u16 chan; ++ enum ath5k_regdom domain; ++ u32 mode; ++}; ++ ++#define IEEE80211_CHANNELS_2GHZ { \ ++/*2412*/ { 1, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2417*/ { 2, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2422*/ { 3, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2427*/ { 4, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2432*/ { 5, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2437*/ { 6, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2442*/ { 7, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2447*/ { 8, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2452*/ { 9, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2457*/ { 10, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2462*/ { 11, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2467*/ { 12, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2472*/ { 13, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \ ++ \ ++/*2432*/ { 5, DMN_ETSIB, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2437*/ { 6, DMN_ETSIB, CHANNEL_CCK|CHANNEL_OFDM|CHANNEL_TURBO }, \ ++/*2442*/ { 7, DMN_ETSIB, CHANNEL_CCK|CHANNEL_OFDM }, \ ++ \ ++/*2412*/ { 1, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2417*/ { 2, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2422*/ { 3, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2427*/ { 4, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2432*/ { 5, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2437*/ { 6, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM|CHANNEL_TURBO }, \ ++/*2442*/ { 7, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2447*/ { 8, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2452*/ { 9, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2457*/ { 10, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2462*/ { 11, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2467*/ { 12, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2472*/ { 13, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \ ++ \ ++/*2412*/ { 1, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2417*/ { 2, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2422*/ { 3, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2427*/ { 4, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2432*/ { 5, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2437*/ { 6, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM|CHANNEL_TURBO }, \ ++/*2442*/ { 7, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2447*/ { 8, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2452*/ { 9, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2457*/ { 10, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2462*/ { 11, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM }, \ ++ \ ++/*2412*/ { 1, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2417*/ { 2, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2422*/ { 3, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2427*/ { 4, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2432*/ { 5, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2437*/ { 6, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2442*/ { 7, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2447*/ { 8, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2452*/ { 9, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2457*/ { 10, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2462*/ { 11, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2467*/ { 12, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2472*/ { 13, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2484*/ { 14, DMN_MKKA, CHANNEL_CCK }, \ ++ \ ++/*2412*/ { 1, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2417*/ { 2, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2422*/ { 3, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2427*/ { 4, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2432*/ { 5, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2437*/ { 6, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM|CHANNEL_TURBO }, \ ++/*2442*/ { 7, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2447*/ { 8, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2452*/ { 9, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2457*/ { 10, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2462*/ { 11, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2467*/ { 12, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \ ++/*2472*/ { 13, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \ ++} ++ ++#define IEEE80211_CHANNELS_5GHZ { \ ++/*5745*/ { 149, DMN_APL1, CHANNEL_OFDM }, \ ++/*5765*/ { 153, DMN_APL1, CHANNEL_OFDM }, \ ++/*5785*/ { 157, DMN_APL1, CHANNEL_OFDM }, \ ++/*5805*/ { 161, DMN_APL1, CHANNEL_OFDM }, \ ++/*5825*/ { 165, DMN_APL1, CHANNEL_OFDM }, \ ++ \ ++/*5745*/ { 149, DMN_APL2, CHANNEL_OFDM }, \ ++/*5765*/ { 153, DMN_APL2, CHANNEL_OFDM }, \ ++/*5785*/ { 157, DMN_APL2, CHANNEL_OFDM }, \ ++/*5805*/ { 161, DMN_APL2, CHANNEL_OFDM }, \ ++ \ ++/*5280*/ { 56, DMN_APL3, CHANNEL_OFDM }, \ ++/*5300*/ { 60, DMN_APL3, CHANNEL_OFDM }, \ ++/*5320*/ { 64, DMN_APL3, CHANNEL_OFDM }, \ ++/*5745*/ { 149, DMN_APL3, CHANNEL_OFDM }, \ ++/*5765*/ { 153, DMN_APL3, CHANNEL_OFDM }, \ ++/*5785*/ { 157, DMN_APL3, CHANNEL_OFDM }, \ ++/*5805*/ { 161, DMN_APL3, CHANNEL_OFDM }, \ ++ \ ++/*5180*/ { 36, DMN_APL4, CHANNEL_OFDM }, \ ++/*5200*/ { 40, DMN_APL4, CHANNEL_OFDM }, \ ++/*5220*/ { 44, DMN_APL4, CHANNEL_OFDM }, \ ++/*5240*/ { 48, DMN_APL4, CHANNEL_OFDM }, \ ++/*5745*/ { 149, DMN_APL4, CHANNEL_OFDM }, \ ++/*5765*/ { 153, DMN_APL4, CHANNEL_OFDM }, \ ++/*5785*/ { 157, DMN_APL4, CHANNEL_OFDM }, \ ++/*5805*/ { 161, DMN_APL4, CHANNEL_OFDM }, \ ++/*5825*/ { 165, DMN_APL4, CHANNEL_OFDM }, \ ++ \ ++/*5745*/ { 149, DMN_APL5, CHANNEL_OFDM }, \ ++/*5765*/ { 153, DMN_APL5, CHANNEL_OFDM }, \ ++/*5785*/ { 157, DMN_APL5, CHANNEL_OFDM }, \ ++/*5805*/ { 161, DMN_APL5, CHANNEL_OFDM }, \ ++/*5825*/ { 165, DMN_APL5, CHANNEL_OFDM }, \ ++ \ ++/*5180*/ { 36, DMN_ETSI1, CHANNEL_OFDM }, \ ++/*5200*/ { 40, DMN_ETSI1, CHANNEL_OFDM }, \ ++/*5220*/ { 44, DMN_ETSI1, CHANNEL_OFDM }, \ ++/*5240*/ { 48, DMN_ETSI1, CHANNEL_OFDM }, \ ++/*5260*/ { 52, DMN_ETSI1, CHANNEL_OFDM }, \ ++/*5280*/ { 56, DMN_ETSI1, CHANNEL_OFDM }, \ ++/*5300*/ { 60, DMN_ETSI1, CHANNEL_OFDM }, \ ++/*5320*/ { 64, DMN_ETSI1, CHANNEL_OFDM }, \ ++/*5500*/ { 100, DMN_ETSI1, CHANNEL_OFDM }, \ ++/*5520*/ { 104, DMN_ETSI1, CHANNEL_OFDM }, \ ++/*5540*/ { 108, DMN_ETSI1, CHANNEL_OFDM }, \ ++/*5560*/ { 112, DMN_ETSI1, CHANNEL_OFDM }, \ ++/*5580*/ { 116, DMN_ETSI1, CHANNEL_OFDM }, \ ++/*5600*/ { 120, DMN_ETSI1, CHANNEL_OFDM }, \ ++/*5620*/ { 124, DMN_ETSI1, CHANNEL_OFDM }, \ ++/*5640*/ { 128, DMN_ETSI1, CHANNEL_OFDM }, \ ++/*5660*/ { 132, DMN_ETSI1, CHANNEL_OFDM }, \ ++/*5680*/ { 136, DMN_ETSI1, CHANNEL_OFDM }, \ ++/*5700*/ { 140, DMN_ETSI1, CHANNEL_OFDM }, \ ++ \ ++/*5180*/ { 36, DMN_ETSI2, CHANNEL_OFDM }, \ ++/*5200*/ { 40, DMN_ETSI2, CHANNEL_OFDM }, \ ++/*5220*/ { 44, DMN_ETSI2, CHANNEL_OFDM }, \ ++/*5240*/ { 48, DMN_ETSI2, CHANNEL_OFDM }, \ ++ \ ++/*5180*/ { 36, DMN_ETSI3, CHANNEL_OFDM }, \ ++/*5200*/ { 40, DMN_ETSI3, CHANNEL_OFDM }, \ ++/*5220*/ { 44, DMN_ETSI3, CHANNEL_OFDM }, \ ++/*5240*/ { 48, DMN_ETSI3, CHANNEL_OFDM }, \ ++/*5260*/ { 52, DMN_ETSI3, CHANNEL_OFDM }, \ ++/*5280*/ { 56, DMN_ETSI3, CHANNEL_OFDM }, \ ++/*5300*/ { 60, DMN_ETSI3, CHANNEL_OFDM }, \ ++/*5320*/ { 64, DMN_ETSI3, CHANNEL_OFDM }, \ ++ \ ++/*5180*/ { 36, DMN_ETSI4, CHANNEL_OFDM }, \ ++/*5200*/ { 40, DMN_ETSI4, CHANNEL_OFDM }, \ ++/*5220*/ { 44, DMN_ETSI4, CHANNEL_OFDM }, \ ++/*5240*/ { 48, DMN_ETSI4, CHANNEL_OFDM }, \ ++/*5260*/ { 52, DMN_ETSI4, CHANNEL_OFDM }, \ ++/*5280*/ { 56, DMN_ETSI4, CHANNEL_OFDM }, \ ++/*5300*/ { 60, DMN_ETSI4, CHANNEL_OFDM }, \ ++/*5320*/ { 64, DMN_ETSI4, CHANNEL_OFDM }, \ ++ \ ++/*5180*/ { 36, DMN_ETSI5, CHANNEL_OFDM }, \ ++/*5200*/ { 40, DMN_ETSI5, CHANNEL_OFDM }, \ ++/*5220*/ { 44, DMN_ETSI5, CHANNEL_OFDM }, \ ++/*5240*/ { 48, DMN_ETSI5, CHANNEL_OFDM }, \ ++ \ ++/*5180*/ { 36, DMN_ETSI6, CHANNEL_OFDM }, \ ++/*5200*/ { 40, DMN_ETSI6, CHANNEL_OFDM }, \ ++/*5220*/ { 44, DMN_ETSI6, CHANNEL_OFDM }, \ ++/*5240*/ { 48, DMN_ETSI6, CHANNEL_OFDM }, \ ++/*5260*/ { 52, DMN_ETSI6, CHANNEL_OFDM }, \ ++/*5280*/ { 56, DMN_ETSI6, CHANNEL_OFDM }, \ ++/*5500*/ { 100, DMN_ETSI6, CHANNEL_OFDM }, \ ++/*5520*/ { 104, DMN_ETSI6, CHANNEL_OFDM }, \ ++/*5540*/ { 108, DMN_ETSI6, CHANNEL_OFDM }, \ ++/*5560*/ { 112, DMN_ETSI6, CHANNEL_OFDM }, \ ++/*5580*/ { 116, DMN_ETSI6, CHANNEL_OFDM }, \ ++/*5600*/ { 120, DMN_ETSI6, CHANNEL_OFDM }, \ ++/*5620*/ { 124, DMN_ETSI6, CHANNEL_OFDM }, \ ++/*5640*/ { 128, DMN_ETSI6, CHANNEL_OFDM }, \ ++/*5660*/ { 132, DMN_ETSI6, CHANNEL_OFDM }, \ ++/*5680*/ { 136, DMN_ETSI6, CHANNEL_OFDM }, \ ++/*5700*/ { 140, DMN_ETSI6, CHANNEL_OFDM }, \ ++ \ ++/*5180*/ { 36, DMN_FCC1, CHANNEL_OFDM }, \ ++/*5200*/ { 40, DMN_FCC1, CHANNEL_OFDM }, \ ++/*5210*/ { 42, DMN_FCC1, CHANNEL_OFDM|CHANNEL_TURBO }, \ ++/*5220*/ { 44, DMN_FCC1, CHANNEL_OFDM }, \ ++/*5240*/ { 48, DMN_FCC1, CHANNEL_OFDM }, \ ++/*5250*/ { 50, DMN_FCC1, CHANNEL_OFDM|CHANNEL_TURBO }, \ ++/*5260*/ { 52, DMN_FCC1, CHANNEL_OFDM }, \ ++/*5280*/ { 56, DMN_FCC1, CHANNEL_OFDM }, \ ++/*5290*/ { 58, DMN_FCC1, CHANNEL_OFDM|CHANNEL_TURBO }, \ ++/*5300*/ { 60, DMN_FCC1, CHANNEL_OFDM }, \ ++/*5320*/ { 64, DMN_FCC1, CHANNEL_OFDM }, \ ++/*5745*/ { 149, DMN_FCC1, CHANNEL_OFDM }, \ ++/*5760*/ { 152, DMN_FCC1, CHANNEL_OFDM|CHANNEL_TURBO }, \ ++/*5765*/ { 153, DMN_FCC1, CHANNEL_OFDM }, \ ++/*5785*/ { 157, DMN_FCC1, CHANNEL_OFDM }, \ ++/*5800*/ { 160, DMN_FCC1, CHANNEL_OFDM|CHANNEL_TURBO }, \ ++/*5805*/ { 161, DMN_FCC1, CHANNEL_OFDM }, \ ++/*5825*/ { 165, DMN_FCC1, CHANNEL_OFDM }, \ ++ \ ++/*5180*/ { 36, DMN_FCC2, CHANNEL_OFDM }, \ ++/*5200*/ { 40, DMN_FCC2, CHANNEL_OFDM }, \ ++/*5220*/ { 44, DMN_FCC2, CHANNEL_OFDM }, \ ++/*5240*/ { 48, DMN_FCC2, CHANNEL_OFDM }, \ ++/*5260*/ { 52, DMN_FCC2, CHANNEL_OFDM }, \ ++/*5280*/ { 56, DMN_FCC2, CHANNEL_OFDM }, \ ++/*5300*/ { 60, DMN_FCC2, CHANNEL_OFDM }, \ ++/*5320*/ { 64, DMN_FCC2, CHANNEL_OFDM }, \ ++/*5745*/ { 149, DMN_FCC2, CHANNEL_OFDM }, \ ++/*5765*/ { 153, DMN_FCC2, CHANNEL_OFDM }, \ ++/*5785*/ { 157, DMN_FCC2, CHANNEL_OFDM }, \ ++/*5805*/ { 161, DMN_FCC2, CHANNEL_OFDM }, \ ++/*5825*/ { 165, DMN_FCC2, CHANNEL_OFDM }, \ ++ \ ++/*5180*/ { 36, DMN_FCC3, CHANNEL_OFDM }, \ ++/*5200*/ { 40, DMN_FCC3, CHANNEL_OFDM }, \ ++/*5210*/ { 42, DMN_FCC3, CHANNEL_OFDM|CHANNEL_TURBO }, \ ++/*5220*/ { 44, DMN_FCC3, CHANNEL_OFDM }, \ ++/*5240*/ { 48, DMN_FCC3, CHANNEL_OFDM }, \ ++/*5250*/ { 50, DMN_FCC3, CHANNEL_OFDM|CHANNEL_TURBO }, \ ++/*5260*/ { 52, DMN_FCC3, CHANNEL_OFDM }, \ ++/*5280*/ { 56, DMN_FCC3, CHANNEL_OFDM }, \ ++/*5290*/ { 58, DMN_FCC3, CHANNEL_OFDM|CHANNEL_TURBO }, \ ++/*5300*/ { 60, DMN_FCC3, CHANNEL_OFDM }, \ ++/*5320*/ { 64, DMN_FCC3, CHANNEL_OFDM }, \ ++/*5500*/ { 100, DMN_FCC3, CHANNEL_OFDM }, \ ++/*5520*/ { 104, DMN_FCC3, CHANNEL_OFDM }, \ ++/*5540*/ { 108, DMN_FCC3, CHANNEL_OFDM }, \ ++/*5560*/ { 112, DMN_FCC3, CHANNEL_OFDM }, \ ++/*5580*/ { 116, DMN_FCC3, CHANNEL_OFDM }, \ ++/*5600*/ { 120, DMN_FCC3, CHANNEL_OFDM }, \ ++/*5620*/ { 124, DMN_FCC3, CHANNEL_OFDM }, \ ++/*5640*/ { 128, DMN_FCC3, CHANNEL_OFDM }, \ ++/*5660*/ { 132, DMN_FCC3, CHANNEL_OFDM }, \ ++/*5680*/ { 136, DMN_FCC3, CHANNEL_OFDM }, \ ++/*5700*/ { 140, DMN_FCC3, CHANNEL_OFDM }, \ ++/*5745*/ { 149, DMN_FCC3, CHANNEL_OFDM }, \ ++/*5760*/ { 152, DMN_FCC3, CHANNEL_OFDM|CHANNEL_TURBO }, \ ++/*5765*/ { 153, DMN_FCC3, CHANNEL_OFDM }, \ ++/*5785*/ { 157, DMN_FCC3, CHANNEL_OFDM }, \ ++/*5800*/ { 160, DMN_FCC3, CHANNEL_OFDM|CHANNEL_TURBO }, \ ++/*5805*/ { 161, DMN_FCC3, CHANNEL_OFDM }, \ ++/*5825*/ { 165, DMN_FCC3, CHANNEL_OFDM }, \ ++ \ ++/*5170*/ { 34, DMN_MKK1, CHANNEL_OFDM }, \ ++/*5190*/ { 38, DMN_MKK1, CHANNEL_OFDM }, \ ++/*5210*/ { 42, DMN_MKK1, CHANNEL_OFDM }, \ ++/*5230*/ { 46, DMN_MKK1, CHANNEL_OFDM }, \ ++ \ ++/*5040*/ { 8, DMN_MKK2, CHANNEL_OFDM }, \ ++/*5060*/ { 12, DMN_MKK2, CHANNEL_OFDM }, \ ++/*5080*/ { 16, DMN_MKK2, CHANNEL_OFDM }, \ ++/*5170*/ { 34, DMN_MKK2, CHANNEL_OFDM }, \ ++/*5190*/ { 38, DMN_MKK2, CHANNEL_OFDM }, \ ++/*5210*/ { 42, DMN_MKK2, CHANNEL_OFDM }, \ ++/*5230*/ { 46, DMN_MKK2, CHANNEL_OFDM }, \ ++ \ ++/*5180*/ { 36, DMN_WORLD, CHANNEL_OFDM }, \ ++/*5200*/ { 40, DMN_WORLD, CHANNEL_OFDM }, \ ++/*5220*/ { 44, DMN_WORLD, CHANNEL_OFDM }, \ ++/*5240*/ { 48, DMN_WORLD, CHANNEL_OFDM }, \ ++} ++ ++enum ath5k_regdom ath5k_regdom2flag(enum ath5k_regdom, u16); ++u16 ath5k_regdom_from_ieee(enum ath5k_regdom ieee); ++enum ath5k_regdom ath5k_regdom_to_ieee(u16 regdomain); ++ ++#endif +diff -up /dev/null linux-2.6.23.noarch/drivers/net/wireless/ath5k/debug.h +--- /dev/null 2007-12-21 08:33:07.834165456 -0500 ++++ linux-2.6.23.noarch/drivers/net/wireless/ath5k/debug.h 2007-12-21 12:18:50.000000000 -0500 +@@ -0,0 +1,216 @@ ++/* ++ * Copyright (c) 2007 Bruno Randolf ++ * ++ * This file is free software: you may copy, redistribute 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 file 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, see . ++ * ++ * ++ * This file incorporates work covered by the following copyright and ++ * permission notice: ++ * ++ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting ++ * Copyright (c) 2004-2005 Atheros Communications, Inc. ++ * Copyright (c) 2006 Devicescape Software, Inc. ++ * Copyright (c) 2007 Jiri Slaby ++ * Copyright (c) 2007 Luis R. Rodriguez ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer, ++ * without modification. ++ * 2. Redistributions in binary form must reproduce at minimum a disclaimer ++ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any ++ * redistribution must be conditioned upon including a substantially ++ * similar Disclaimer requirement for further binary redistribution. ++ * 3. Neither the names of the above-listed copyright holders nor the names ++ * of any contributors may be used to endorse or promote products derived ++ * from this software without specific prior written permission. ++ * ++ * Alternatively, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") version 2 as published by the Free ++ * Software Foundation. ++ * ++ * NO WARRANTY ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY ++ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, ++ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER ++ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF ++ * THE POSSIBILITY OF SUCH DAMAGES. ++ */ ++ ++#ifndef _ATH5K_DEBUG_H ++#define _ATH5K_DEBUG_H ++ ++/* set this to 1 for debugging output */ ++#ifndef ATH5K_DEBUG ++#define ATH5K_DEBUG 0 ++#endif ++ ++struct ath5k_softc; ++struct ath5k_hw; ++struct ieee80211_hw_mode; ++struct sk_buff; ++struct ath5k_buf; ++ ++struct ath5k_dbg_info { ++ unsigned int level; /* debug level */ ++ /* debugfs entries */ ++ struct dentry *debugfs_phydir; ++ struct dentry *debugfs_debug; ++ struct dentry *debugfs_registers; ++ struct dentry *debugfs_tsf; ++ struct dentry *debugfs_beacon; ++ struct dentry *debugfs_reset; ++}; ++ ++/** ++ * enum ath5k_debug_level - ath5k debug level ++ * ++ * @ATH5K_DEBUG_RESET: reset processing ++ * @ATH5K_DEBUG_INTR: interrupt handling ++ * @ATH5K_DEBUG_MODE: mode init/setup ++ * @ATH5K_DEBUG_XMIT: basic xmit operation ++ * @ATH5K_DEBUG_BEACON: beacon handling ++ * @ATH5K_DEBUG_BEACON_PROC: beacon ISR proc ++ * @ATH5K_DEBUG_CALIBRATE: periodic calibration ++ * @ATH5K_DEBUG_TXPOWER: transmit power setting ++ * @ATH5K_DEBUG_LED: led management ++ * @ATH5K_DEBUG_DUMP_RX: print received skb content ++ * @ATH5K_DEBUG_DUMP_TX: print transmit skb content ++ * @ATH5K_DEBUG_DUMPMODES: dump modes ++ * @ATH5K_DEBUG_TRACE: trace function calls ++ * @ATH5K_DEBUG_FATAL: fatal errors ++ * @ATH5K_DEBUG_ANY: show at any debug level ++ * ++ * The debug level is used to control the amount and type of debugging output ++ * we want to see. The debug level is given in calls to ATH5K_DBG to specify ++ * where the message should appear, and the user can control the debugging ++ * messages he wants to see, either by the module parameter 'debug' on module ++ * load, or dynamically by using debugfs 'ath5k/phyX/debug'. these levels can ++ * be combined together by bitwise OR. ++ */ ++enum ath5k_debug_level { ++ ATH5K_DEBUG_RESET = 0x00000001, ++ ATH5K_DEBUG_INTR = 0x00000002, ++ ATH5K_DEBUG_MODE = 0x00000004, ++ ATH5K_DEBUG_XMIT = 0x00000008, ++ ATH5K_DEBUG_BEACON = 0x00000010, ++ ATH5K_DEBUG_BEACON_PROC = 0x00000020, ++ ATH5K_DEBUG_CALIBRATE = 0x00000100, ++ ATH5K_DEBUG_TXPOWER = 0x00000200, ++ ATH5K_DEBUG_LED = 0x00000400, ++ ATH5K_DEBUG_DUMP_RX = 0x00001000, ++ ATH5K_DEBUG_DUMP_TX = 0x00002000, ++ ATH5K_DEBUG_DUMPMODES = 0x00004000, ++ ATH5K_DEBUG_TRACE = 0x00010000, ++ ATH5K_DEBUG_FATAL = 0x80000000, ++ ATH5K_DEBUG_ANY = 0xffffffff ++}; ++ ++#if ATH5K_DEBUG ++ ++#define ATH5K_TRACE(_sc) do { \ ++ if (unlikely((_sc)->debug.level & ATH5K_DEBUG_TRACE)) \ ++ printk(KERN_DEBUG "ath5k trace %s:%d\n", __func__, __LINE__); \ ++ } while (0) ++ ++#define ATH5K_DBG(_sc, _m, _fmt, ...) do { \ ++ if (unlikely((_sc)->debug.level & (_m) && net_ratelimit())) \ ++ ATH5K_PRINTK(_sc, KERN_DEBUG, "(%s:%d): " _fmt, \ ++ __func__, __LINE__, ##__VA_ARGS__); \ ++ } while (0) ++ ++#define ATH5K_DBG_UNLIMIT(_sc, _m, _fmt, ...) do { \ ++ if (unlikely((_sc)->debug.level & (_m))) \ ++ ATH5K_PRINTK(_sc, KERN_DEBUG, "(%s:%d): " _fmt, \ ++ __func__, __LINE__, ##__VA_ARGS__); \ ++ } while (0) ++ ++void ++ath5k_debug_init(void); ++ ++void ++ath5k_debug_init_device(struct ath5k_softc *sc); ++ ++void ++ath5k_debug_finish(void); ++ ++void ++ath5k_debug_finish_device(struct ath5k_softc *sc); ++ ++void ++ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah); ++ ++void ++ath5k_debug_dump_modes(struct ath5k_softc *sc, ++ struct ieee80211_hw_mode *modes); ++ ++void ++ath5k_debug_dump_skb(struct ath5k_softc *sc, ++ struct sk_buff *skb, const char *prefix, int tx); ++ ++void ++ath5k_debug_printtxbuf(struct ath5k_softc *sc, ++ struct ath5k_buf *bf, int done); ++ ++#else /* no debugging */ ++ ++#define ATH5K_TRACE(_sc) /* empty */ ++ ++static inline void __attribute__ ((format (printf, 3, 4))) ++ATH5K_DBG(struct ath5k_softc *sc, unsigned int m, const char *fmt, ...) {} ++ ++static inline void __attribute__ ((format (printf, 3, 4))) ++ATH5K_DBG_UNLIMIT(struct ath5k_softc *sc, unsigned int m, const char *fmt, ...) ++{} ++ ++static inline void ++ath5k_debug_init(void) {} ++ ++static inline void ++ath5k_debug_init_device(struct ath5k_softc *sc) {} ++ ++static inline void ++ath5k_debug_finish(void) {} ++ ++static inline void ++ath5k_debug_finish_device(struct ath5k_softc *sc) {} ++ ++static inline void ++ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) {} ++ ++static inline void ++ath5k_debug_dump_modes(struct ath5k_softc *sc, ++ struct ieee80211_hw_mode *modes) {} ++ ++static inline void ++ath5k_debug_dump_skb(struct ath5k_softc *sc, ++ struct sk_buff *skb, const char *prefix, int tx) {} ++ ++static inline void ++ath5k_debug_printtxbuf(struct ath5k_softc *sc, ++ struct ath5k_buf *bf, int done) {} ++ ++#endif /* if ATH5K_DEBUG */ ++ ++#endif /* ifndef _ATH5K_DEBUG_H */ +diff -up /dev/null linux-2.6.23.noarch/drivers/net/wireless/ath5k/hw.c +--- /dev/null 2007-12-21 08:33:07.834165456 -0500 ++++ linux-2.6.23.noarch/drivers/net/wireless/ath5k/hw.c 2007-12-21 12:18:50.000000000 -0500 +@@ -0,0 +1,4349 @@ ++ /* ++ * Copyright (c) 2004-2007 Reyk Floeter ++ * Copyright (c) 2006-2007 Nick Kossifidis ++ * Copyright (c) 2007 Matthew W. S. Bell ++ * Copyright (c) 2007 Luis Rodriguez ++ * Copyright (c) 2007 Pavel Roskin ++ * Copyright (c) 2007 Jiri Slaby ++ * ++ * Permission to use, copy, modify, and 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. ++ * ++ */ ++ ++/* ++ * HW related functions for Atheros Wireless LAN devices. ++ */ ++ ++#include ++#include ++ ++#include "reg.h" ++#include "base.h" ++#include "debug.h" ++ ++/*Rate tables*/ ++static const struct ath5k_rate_table ath5k_rt_11a = AR5K_RATES_11A; ++static const struct ath5k_rate_table ath5k_rt_11b = AR5K_RATES_11B; ++static const struct ath5k_rate_table ath5k_rt_11g = AR5K_RATES_11G; ++static const struct ath5k_rate_table ath5k_rt_turbo = AR5K_RATES_TURBO; ++static const struct ath5k_rate_table ath5k_rt_xr = AR5K_RATES_XR; ++ ++/*Prototypes*/ ++static int ath5k_hw_nic_reset(struct ath5k_hw *, u32); ++static int ath5k_hw_nic_wakeup(struct ath5k_hw *, int, bool); ++static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *, struct ath5k_desc *, ++ unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int, ++ unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, ++ unsigned int, unsigned int); ++static bool ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *, struct ath5k_desc *, ++ unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, ++ unsigned int); ++static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *, struct ath5k_desc *); ++static int ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *, struct ath5k_desc *, ++ unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int, ++ unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, ++ unsigned int, unsigned int); ++static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *, struct ath5k_desc *); ++static int ath5k_hw_proc_new_rx_status(struct ath5k_hw *, struct ath5k_desc *); ++static int ath5k_hw_proc_old_rx_status(struct ath5k_hw *, struct ath5k_desc *); ++static int ath5k_hw_get_capabilities(struct ath5k_hw *); ++ ++static int ath5k_eeprom_init(struct ath5k_hw *); ++static int ath5k_eeprom_read_mac(struct ath5k_hw *, u8 *); ++ ++static int ath5k_hw_enable_pspoll(struct ath5k_hw *, u8 *, u16); ++static int ath5k_hw_disable_pspoll(struct ath5k_hw *); ++ ++/* ++ * Enable to overwrite the country code (use "00" for debug) ++ */ ++#if 0 ++#define COUNTRYCODE "00" ++#endif ++ ++/*******************\ ++ General Functions ++\*******************/ ++ ++/* ++ * Functions used internaly ++ */ ++ ++static inline unsigned int ath5k_hw_htoclock(unsigned int usec, bool turbo) ++{ ++ return turbo == true ? (usec * 80) : (usec * 40); ++} ++ ++static inline unsigned int ath5k_hw_clocktoh(unsigned int clock, bool turbo) ++{ ++ return turbo == true ? (clock / 80) : (clock / 40); ++} ++ ++/* ++ * Check if a register write has been completed ++ */ ++int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val, ++ bool is_set) ++{ ++ int i; ++ u32 data; ++ ++ for (i = AR5K_TUNE_REGISTER_TIMEOUT; i > 0; i--) { ++ data = ath5k_hw_reg_read(ah, reg); ++ if ((is_set == true) && (data & flag)) ++ break; ++ else if ((data & flag) == val) ++ break; ++ udelay(15); ++ } ++ ++ return (i <= 0) ? -EAGAIN : 0; ++} ++ ++ ++/***************************************\ ++ Attach/Detach Functions ++\***************************************/ ++ ++/* ++ * Check if the device is supported and initialize the needed structs ++ */ ++struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) ++{ ++ struct ath5k_hw *ah; ++ u8 mac[ETH_ALEN]; ++ int ret; ++ u32 srev; ++ ++ /*If we passed the test malloc a ath5k_hw struct*/ ++ ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL); ++ if (ah == NULL) { ++ ret = -ENOMEM; ++ ATH5K_ERR(sc, "out of memory\n"); ++ goto err; ++ } ++ ++ ah->ah_sc = sc; ++ ah->ah_iobase = sc->iobase; ++ ++ /* ++ * HW information ++ */ ++ ++ /* Get reg domain from eeprom */ ++ ath5k_get_regdomain(ah); ++ ++ ah->ah_op_mode = IEEE80211_IF_TYPE_STA; ++ ah->ah_radar.r_enabled = AR5K_TUNE_RADAR_ALERT; ++ ah->ah_turbo = false; ++ ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER; ++ ah->ah_imr = 0; ++ ah->ah_atim_window = 0; ++ ah->ah_aifs = AR5K_TUNE_AIFS; ++ ah->ah_cw_min = AR5K_TUNE_CWMIN; ++ ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY; ++ ah->ah_software_retry = false; ++ ah->ah_ant_diversity = AR5K_TUNE_ANT_DIVERSITY; ++ ++ /* ++ * Set the mac revision based on the pci id ++ */ ++ ah->ah_version = mac_version; ++ ++ /*Fill the ath5k_hw struct with the needed functions*/ ++ if (ah->ah_version == AR5K_AR5212) ++ ah->ah_magic = AR5K_EEPROM_MAGIC_5212; ++ else if (ah->ah_version == AR5K_AR5211) ++ ah->ah_magic = AR5K_EEPROM_MAGIC_5211; ++ ++ if (ah->ah_version == AR5K_AR5212) { ++ ah->ah_setup_tx_desc = ath5k_hw_setup_4word_tx_desc; ++ ah->ah_setup_xtx_desc = ath5k_hw_setup_xr_tx_desc; ++ ah->ah_proc_tx_desc = ath5k_hw_proc_4word_tx_status; ++ } else { ++ ah->ah_setup_tx_desc = ath5k_hw_setup_2word_tx_desc; ++ ah->ah_setup_xtx_desc = ath5k_hw_setup_xr_tx_desc; ++ ah->ah_proc_tx_desc = ath5k_hw_proc_2word_tx_status; ++ } ++ ++ if (ah->ah_version == AR5K_AR5212) ++ ah->ah_proc_rx_desc = ath5k_hw_proc_new_rx_status; ++ else if (ah->ah_version <= AR5K_AR5211) ++ ah->ah_proc_rx_desc = ath5k_hw_proc_old_rx_status; ++ ++ /* Bring device out of sleep and reset it's units */ ++ ret = ath5k_hw_nic_wakeup(ah, AR5K_INIT_MODE, 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); ++ ah->ah_phy_revision = ath5k_hw_reg_read(ah, AR5K_PHY_CHIP_ID) & ++ 0xffffffff; ++ ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah, ++ CHANNEL_5GHZ); ++ ++ if (ah->ah_version == AR5K_AR5210) ++ ah->ah_radio_2ghz_revision = 0; ++ else ++ ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah, ++ CHANNEL_2GHZ); ++ ++ /* Return on unsuported chips (unsupported eeprom etc) */ ++ if(srev >= AR5K_SREV_VER_AR5416){ ++ ATH5K_ERR(sc, "Device not yet supported.\n"); ++ ret = -ENODEV; ++ goto err_free; ++ } ++ ++ /* Identify single chip solutions */ ++ if((srev <= AR5K_SREV_VER_AR5414) && ++ (srev >= AR5K_SREV_VER_AR2424)) { ++ ah->ah_single_chip = true; ++ } else { ++ ah->ah_single_chip = false; ++ } ++ ++ /* Single chip radio */ ++ if (ah->ah_radio_2ghz_revision == ah->ah_radio_5ghz_revision) ++ ah->ah_radio_2ghz_revision = 0; ++ ++ /* Identify the radio chip*/ ++ if (ah->ah_version == AR5K_AR5210) { ++ ah->ah_radio = AR5K_RF5110; ++ } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112) { ++ ah->ah_radio = AR5K_RF5111; ++ } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC1) { ++ ah->ah_radio = AR5K_RF5112; ++ } else { ++ ah->ah_radio = AR5K_RF5413; ++ } ++ ++ ah->ah_phy = AR5K_PHY(0); ++ ++ /* ++ * Get card capabilities, values, ... ++ */ ++ ++ ret = ath5k_eeprom_init(ah); ++ if (ret) { ++ ATH5K_ERR(sc, "unable to init EEPROM\n"); ++ goto err_free; ++ } ++ ++ /* Get misc capabilities */ ++ ret = ath5k_hw_get_capabilities(ah); ++ if (ret) { ++ ATH5K_ERR(sc, "unable to get device capabilities: 0x%04x\n", ++ sc->pdev->device); ++ goto err_free; ++ } ++ ++ /* Get MAC address */ ++ ret = ath5k_eeprom_read_mac(ah, mac); ++ if (ret) { ++ ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n", ++ sc->pdev->device); ++ goto err_free; ++ } ++ ++ ath5k_hw_set_lladdr(ah, mac); ++ /* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */ ++ memset(ah->bssid, 0xff, ETH_ALEN); ++ ath5k_hw_set_associd(ah, ah->bssid, 0); ++ ath5k_hw_set_opmode(ah); ++ ++ ath5k_hw_set_rfgain_opt(ah); ++ ++ return ah; ++err_free: ++ kfree(ah); ++err: ++ return ERR_PTR(ret); ++} ++ ++/* ++ * Bring up MAC + PHY Chips ++ */ ++static int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) ++{ ++ u32 turbo, mode, clock; ++ int ret; ++ ++ turbo = 0; ++ mode = 0; ++ clock = 0; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ ++ /* Wakeup the device */ ++ 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; ++ } ++ ++ if (ah->ah_version != AR5K_AR5210) { ++ /* ++ * Get channel mode flags ++ */ ++ ++ if (ah->ah_radio >= AR5K_RF5112) { ++ mode = AR5K_PHY_MODE_RAD_RF5112; ++ clock = AR5K_PHY_PLL_RF5112; ++ } else { ++ mode = AR5K_PHY_MODE_RAD_RF5111; /*Zero*/ ++ clock = AR5K_PHY_PLL_RF5111; /*Zero*/ ++ } ++ ++ if (flags & CHANNEL_2GHZ) { ++ mode |= AR5K_PHY_MODE_FREQ_2GHZ; ++ clock |= AR5K_PHY_PLL_44MHZ; ++ ++ if (flags & CHANNEL_CCK) { ++ mode |= AR5K_PHY_MODE_MOD_CCK; ++ } else if (flags & CHANNEL_OFDM) { ++ /* XXX Dynamic OFDM/CCK is not supported by the ++ * AR5211 so we set MOD_OFDM for plain g (no ++ * CCK headers) operation. We need to test ++ * this, 5211 might support ofdm-only g after ++ * all, there are also initial register values ++ * in the code for g mode (see initvals.c). */ ++ if (ah->ah_version == AR5K_AR5211) ++ mode |= AR5K_PHY_MODE_MOD_OFDM; ++ else ++ mode |= AR5K_PHY_MODE_MOD_DYN; ++ } else { ++ ATH5K_ERR(ah->ah_sc, ++ "invalid radio modulation mode\n"); ++ return -EINVAL; ++ } ++ } else if (flags & CHANNEL_5GHZ) { ++ mode |= AR5K_PHY_MODE_FREQ_5GHZ; ++ clock |= AR5K_PHY_PLL_40MHZ; ++ ++ if (flags & CHANNEL_OFDM) ++ mode |= AR5K_PHY_MODE_MOD_OFDM; ++ else { ++ ATH5K_ERR(ah->ah_sc, ++ "invalid radio modulation mode\n"); ++ return -EINVAL; ++ } ++ } else { ++ ATH5K_ERR(ah->ah_sc, "invalid radio frequency mode\n"); ++ return -EINVAL; ++ } ++ ++ if (flags & CHANNEL_TURBO) ++ turbo = AR5K_PHY_TURBO_MODE | AR5K_PHY_TURBO_SHORT; ++ } else { /* Reset the device */ ++ ++ /* ...enable Atheros turbo mode if requested */ ++ if (flags & CHANNEL_TURBO) ++ ath5k_hw_reg_write(ah, AR5K_PHY_TURBO_MODE, ++ AR5K_PHY_TURBO); ++ } ++ ++ /* ...reset chipset and PCI device */ ++ if (ah->ah_single_chip == false && ath5k_hw_nic_reset(ah, ++ AR5K_RESET_CTL_CHIP | AR5K_RESET_CTL_PCI)) { ++ ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip + PCI\n"); ++ return -EIO; ++ } ++ ++ if (ah->ah_version == AR5K_AR5210) ++ udelay(2300); ++ ++ /* ...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) { ++ /* ...set the PHY operating mode */ ++ ath5k_hw_reg_write(ah, clock, AR5K_PHY_PLL); ++ udelay(300); ++ ++ ath5k_hw_reg_write(ah, mode, AR5K_PHY_MODE); ++ ath5k_hw_reg_write(ah, turbo, AR5K_PHY_TURBO); ++ } ++ ++ return 0; ++} ++ ++/* ++ * Get the rate table for a specific operation mode ++ */ ++const struct ath5k_rate_table *ath5k_hw_get_rate_table(struct ath5k_hw *ah, ++ unsigned int mode) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ ++ if (!test_bit(mode, ah->ah_capabilities.cap_mode)) ++ return NULL; ++ ++ /* Get rate tables */ ++ switch (mode) { ++ case MODE_IEEE80211A: ++ return &ath5k_rt_11a; ++ case MODE_ATHEROS_TURBO: ++ return &ath5k_rt_turbo; ++ case MODE_IEEE80211B: ++ return &ath5k_rt_11b; ++ case MODE_IEEE80211G: ++ return &ath5k_rt_11g; ++ case MODE_ATHEROS_TURBOG: ++ return &ath5k_rt_xr; ++ } ++ ++ return NULL; ++} ++ ++/* ++ * Free the ath5k_hw struct ++ */ ++void ath5k_hw_detach(struct ath5k_hw *ah) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ ++ if (ah->ah_rf_banks != NULL) ++ kfree(ah->ah_rf_banks); ++ ++ /* assume interrupts are down */ ++ kfree(ah); ++} ++ ++/****************************\ ++ Reset function and helpers ++\****************************/ ++ ++/** ++ * ath5k_hw_write_ofdm_timings - set OFDM timings on AR5212 ++ * ++ * @ah: the &struct ath5k_hw ++ * @channel: the currently set channel upon reset ++ * ++ * Write the OFDM timings for the AR5212 upon reset. This is a helper for ++ * ath5k_hw_reset(). This seems to tune the PLL a specified frequency ++ * depending on the bandwidth of the channel. ++ * ++ */ ++static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah, ++ struct ieee80211_channel *channel) ++{ ++ /* Get exponent and mantissa and set it */ ++ u32 coef_scaled, coef_exp, coef_man, ++ ds_coef_exp, ds_coef_man, clock; ++ ++ if (!(ah->ah_version == AR5K_AR5212) || ++ !(channel->val & CHANNEL_OFDM)) ++ BUG(); ++ ++ /* Seems there are two PLLs, one for baseband sampling and one ++ * for tuning. Tuning basebands are 40 MHz or 80MHz when in ++ * turbo. */ ++ clock = channel->val & CHANNEL_TURBO ? 80 : 40; ++ coef_scaled = ((5 * (clock << 24)) / 2) / ++ channel->freq; ++ ++ for (coef_exp = 31; coef_exp > 0; coef_exp--) ++ if ((coef_scaled >> coef_exp) & 0x1) ++ break; ++ ++ if (!coef_exp) ++ return -EINVAL; ++ ++ coef_exp = 14 - (coef_exp - 24); ++ coef_man = coef_scaled + ++ (1 << (24 - coef_exp - 1)); ++ ds_coef_man = coef_man >> (24 - coef_exp); ++ ds_coef_exp = coef_exp - 16; ++ ++ AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3, ++ AR5K_PHY_TIMING_3_DSC_MAN, ds_coef_man); ++ AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3, ++ AR5K_PHY_TIMING_3_DSC_EXP, ds_coef_exp); ++ ++ return 0; ++} ++ ++/** ++ * ath5k_hw_write_rate_duration - set rate duration during hw resets ++ * ++ * @ah: the &struct ath5k_hw ++ * @driver_mode: one of enum ieee80211_phymode or our one of our own ++ * vendor modes ++ * ++ * Write the rate duration table for the current mode upon hw reset. This ++ * is a helper for ath5k_hw_reset(). It seems all this is doing is setting ++ * an ACK timeout for the hardware for the current mode for each rate. The ++ * rates which are capable of short preamble (802.11b rates 2Mbps, 5.5Mbps, ++ * and 11Mbps) have another register for the short preamble ACK timeout ++ * calculation. ++ * ++ */ ++static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah, ++ unsigned int driver_mode) ++{ ++ struct ath5k_softc *sc = ah->ah_sc; ++ const struct ath5k_rate_table *rt; ++ unsigned int i; ++ ++ /* Get rate table for the current operating mode */ ++ rt = ath5k_hw_get_rate_table(ah, ++ driver_mode); ++ ++ /* Write rate duration table */ ++ for (i = 0; i < rt->rate_count; i++) { ++ const struct ath5k_rate *rate, *control_rate; ++ u32 reg; ++ u16 tx_time; ++ ++ rate = &rt->rates[i]; ++ control_rate = &rt->rates[rate->control_rate]; ++ ++ /* Set ACK timeout */ ++ reg = AR5K_RATE_DUR(rate->rate_code); ++ ++ /* An ACK frame consists of 10 bytes. If you add the FCS, ++ * which ieee80211_generic_frame_duration() adds, ++ * its 14 bytes. Note we use the control rate and not the ++ * actual rate for this rate. See mac80211 tx.c ++ * ieee80211_duration() for a brief description of ++ * what rate we should choose to TX ACKs. */ ++ tx_time = ieee80211_generic_frame_duration(sc->hw, ++ sc->iface_id, 10, control_rate->rate_kbps/100); ++ ++ ath5k_hw_reg_write(ah, tx_time, reg); ++ ++ if (!HAS_SHPREAMBLE(i)) ++ continue; ++ ++ /* ++ * We're not distinguishing short preamble here, ++ * This is true, all we'll get is a longer value here ++ * which is not necessarilly bad. We could use ++ * export ieee80211_frame_duration() but that needs to be ++ * fixed first to be properly used by mac802111 drivers: ++ * ++ * - remove erp stuff and let the routine figure ofdm ++ * erp rates ++ * - remove passing argument ieee80211_local as ++ * drivers don't have access to it ++ * - move drivers using ieee80211_generic_frame_duration() ++ * to this ++ */ ++ ath5k_hw_reg_write(ah, tx_time, ++ reg + (AR5K_SET_SHORT_PREAMBLE << 2)); ++ } ++} ++ ++/* ++ * Main reset function ++ */ ++int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, ++ struct ieee80211_channel *channel, bool change_channel) ++{ ++ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; ++ u32 data, s_seq, s_ant, s_led[3]; ++ unsigned int i, mode, freq, ee_mode, ant[2], driver_mode = -1; ++ int ret; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ ++ s_seq = 0; ++ s_ant = 0; ++ ee_mode = 0; ++ freq = 0; ++ mode = 0; ++ ++ /* ++ * Save some registers before a reset ++ */ ++ /*DCU/Antenna selection not available on 5210*/ ++ if (ah->ah_version != AR5K_AR5210) { ++ if (change_channel == true) { ++ /* Seq number for queue 0 -do this for all queues ? */ ++ s_seq = ath5k_hw_reg_read(ah, ++ AR5K_QUEUE_DFS_SEQNUM(0)); ++ /*Default antenna*/ ++ s_ant = ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA); ++ } ++ } ++ ++ /*GPIOs*/ ++ s_led[0] = ath5k_hw_reg_read(ah, AR5K_PCICFG) & AR5K_PCICFG_LEDSTATE; ++ s_led[1] = ath5k_hw_reg_read(ah, AR5K_GPIOCR); ++ s_led[2] = ath5k_hw_reg_read(ah, AR5K_GPIODO); ++ ++ if (change_channel == true && ah->ah_rf_banks != NULL) ++ ath5k_hw_get_rf_gain(ah); ++ ++ ++ /*Wakeup the device*/ ++ ret = ath5k_hw_nic_wakeup(ah, channel->val, false); ++ if (ret) ++ return ret; ++ ++ /* ++ * Initialize operating mode ++ */ ++ ah->ah_op_mode = op_mode; ++ ++ /* ++ * 5111/5112 Settings ++ * 5210 only comes with RF5110 ++ */ ++ if (ah->ah_version != AR5K_AR5210) { ++ if (ah->ah_radio != AR5K_RF5111 && ++ ah->ah_radio != AR5K_RF5112 && ++ ah->ah_radio != AR5K_RF5413) { ++ ATH5K_ERR(ah->ah_sc, ++ "invalid phy radio: %u\n", ah->ah_radio); ++ return -EINVAL; ++ } ++ ++ switch (channel->val & CHANNEL_MODES) { ++ case CHANNEL_A: ++ mode = AR5K_INI_VAL_11A; ++ freq = AR5K_INI_RFGAIN_5GHZ; ++ ee_mode = AR5K_EEPROM_MODE_11A; ++ driver_mode = MODE_IEEE80211A; ++ break; ++ case CHANNEL_G: ++ mode = AR5K_INI_VAL_11G; ++ freq = AR5K_INI_RFGAIN_2GHZ; ++ ee_mode = AR5K_EEPROM_MODE_11G; ++ driver_mode = MODE_IEEE80211G; ++ break; ++ case CHANNEL_B: ++ mode = AR5K_INI_VAL_11B; ++ freq = AR5K_INI_RFGAIN_2GHZ; ++ ee_mode = AR5K_EEPROM_MODE_11B; ++ driver_mode = MODE_IEEE80211B; ++ break; ++ case CHANNEL_T: ++ mode = AR5K_INI_VAL_11A_TURBO; ++ freq = AR5K_INI_RFGAIN_5GHZ; ++ ee_mode = AR5K_EEPROM_MODE_11A; ++ driver_mode = MODE_ATHEROS_TURBO; ++ break; ++ /*Is this ok on 5211 too ?*/ ++ case CHANNEL_TG: ++ mode = AR5K_INI_VAL_11G_TURBO; ++ freq = AR5K_INI_RFGAIN_2GHZ; ++ ee_mode = AR5K_EEPROM_MODE_11G; ++ driver_mode = MODE_ATHEROS_TURBOG; ++ break; ++ case CHANNEL_XR: ++ if (ah->ah_version == AR5K_AR5211) { ++ ATH5K_ERR(ah->ah_sc, ++ "XR mode not available on 5211"); ++ return -EINVAL; ++ } ++ mode = AR5K_INI_VAL_XR; ++ freq = AR5K_INI_RFGAIN_5GHZ; ++ ee_mode = AR5K_EEPROM_MODE_11A; ++ driver_mode = MODE_IEEE80211A; ++ break; ++ default: ++ ATH5K_ERR(ah->ah_sc, ++ "invalid channel: %d\n", channel->freq); ++ return -EINVAL; ++ } ++ ++ /* PHY access enable */ ++ ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0)); ++ ++ } ++ ++ ret = ath5k_hw_write_initvals(ah, mode, change_channel); ++ if (ret) ++ return ret; ++ ++ /* ++ * 5211/5212 Specific ++ */ ++ if (ah->ah_version != AR5K_AR5210) { ++ /* ++ * Write initial RF gain settings ++ * This should work for both 5111/5112 ++ */ ++ ret = ath5k_hw_rfgain(ah, freq); ++ if (ret) ++ return ret; ++ ++ mdelay(1); ++ ++ /* ++ * Write some more initial register settings ++ */ ++ if (ah->ah_version > AR5K_AR5211){ /* found on 5213+ */ ++ ath5k_hw_reg_write(ah, 0x0002a002, AR5K_PHY(11)); ++ ++ if (channel->val == CHANNEL_G) ++ ath5k_hw_reg_write(ah, 0x00f80d80, AR5K_PHY(83)); /* 0x00fc0ec0 */ ++ else ++ ath5k_hw_reg_write(ah, 0x00000000, AR5K_PHY(83)); ++ ++ ath5k_hw_reg_write(ah, 0x000001b5, 0xa228); /* 0x000009b5 */ ++ ath5k_hw_reg_write(ah, 0x000009b5, 0xa228); ++ ath5k_hw_reg_write(ah, 0x0000000f, 0x8060); ++ ath5k_hw_reg_write(ah, 0x00000000, 0xa254); ++ ath5k_hw_reg_write(ah, 0x0000000e, AR5K_PHY_SCAL); ++ } ++ ++ /* Fix for first revision of the RF5112 RF chipset */ ++ if (ah->ah_radio >= AR5K_RF5112 && ++ ah->ah_radio_5ghz_revision < ++ AR5K_SREV_RAD_5112A) { ++ ath5k_hw_reg_write(ah, AR5K_PHY_CCKTXCTL_WORLD, ++ AR5K_PHY_CCKTXCTL); ++ if (channel->val & CHANNEL_5GHZ) ++ data = 0xffb81020; ++ else ++ data = 0xffb80d20; ++ ath5k_hw_reg_write(ah, data, AR5K_PHY_FRAME_CTL); ++ } ++ ++ /* ++ * Set TX power (FIXME) ++ */ ++ ret = ath5k_hw_txpower(ah, channel, AR5K_TUNE_DEFAULT_TXPOWER); ++ if (ret) ++ return ret; ++ ++ /* Write rate duration table */ ++ if (ah->ah_version == AR5K_AR5212) ++ ath5k_hw_write_rate_duration(ah, driver_mode); ++ ++ /* ++ * Write RF registers ++ * TODO:Does this work on 5211 (5111) ? ++ */ ++ ret = ath5k_hw_rfregs(ah, channel, mode); ++ if (ret) ++ return ret; ++ ++ /* ++ * Configure additional registers ++ */ ++ ++ /* Write OFDM timings on 5212*/ ++ if (ah->ah_version == AR5K_AR5212 && ++ channel->val & CHANNEL_OFDM) { ++ ret = ath5k_hw_write_ofdm_timings(ah, channel); ++ if (ret) ++ return ret; ++ } ++ ++ /*Enable/disable 802.11b mode on 5111 ++ (enable 2111 frequency converter + CCK)*/ ++ if (ah->ah_radio == AR5K_RF5111) { ++ if (driver_mode == MODE_IEEE80211B) ++ AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG, ++ AR5K_TXCFG_B_MODE); ++ else ++ AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG, ++ AR5K_TXCFG_B_MODE); ++ } ++ ++ /* ++ * Set channel and calibrate the PHY ++ */ ++ ret = ath5k_hw_channel(ah, channel); ++ if (ret) ++ return ret; ++ ++ /* Set antenna mode */ ++ AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x44), ++ ah->ah_antenna[ee_mode][0], 0xfffffc06); ++ ++ /* ++ * In case a fixed antenna was set as default ++ * write the same settings on both AR5K_PHY_ANT_SWITCH_TABLE ++ * registers. ++ */ ++ if (s_ant != 0){ ++ if (s_ant == AR5K_ANT_FIXED_A) /* 1 - Main */ ++ ant[0] = ant[1] = AR5K_ANT_FIXED_A; ++ else /* 2 - Aux */ ++ ant[0] = ant[1] = AR5K_ANT_FIXED_B; ++ } else { ++ ant[0] = AR5K_ANT_FIXED_A; ++ ant[1] = AR5K_ANT_FIXED_B; ++ } ++ ++ ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[0]], ++ AR5K_PHY_ANT_SWITCH_TABLE_0); ++ ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[1]], ++ AR5K_PHY_ANT_SWITCH_TABLE_1); ++ ++ /* Commit values from EEPROM */ ++ if (ah->ah_radio == AR5K_RF5111) ++ AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL, ++ AR5K_PHY_FRAME_CTL_TX_CLIP, ee->ee_tx_clip); ++ ++ ath5k_hw_reg_write(ah, ++ AR5K_PHY_NF_SVAL(ee->ee_noise_floor_thr[ee_mode]), ++ AR5K_PHY(0x5a)); ++ ++ AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x11), ++ (ee->ee_switch_settling[ee_mode] << 7) & 0x3f80, ++ 0xffffc07f); ++ AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x12), ++ (ee->ee_ant_tx_rx[ee_mode] << 12) & 0x3f000, ++ 0xfffc0fff); ++ AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x14), ++ (ee->ee_adc_desired_size[ee_mode] & 0x00ff) | ++ ((ee->ee_pga_desired_size[ee_mode] << 8) & 0xff00), ++ 0xffff0000); ++ ++ ath5k_hw_reg_write(ah, ++ (ee->ee_tx_end2xpa_disable[ee_mode] << 24) | ++ (ee->ee_tx_end2xpa_disable[ee_mode] << 16) | ++ (ee->ee_tx_frm2xpa_enable[ee_mode] << 8) | ++ (ee->ee_tx_frm2xpa_enable[ee_mode]), AR5K_PHY(0x0d)); ++ ++ AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x0a), ++ ee->ee_tx_end2xlna_enable[ee_mode] << 8, 0xffff00ff); ++ AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x19), ++ (ee->ee_thr_62[ee_mode] << 12) & 0x7f000, 0xfff80fff); ++ AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x49), 4, 0xffffff01); ++ ++ AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, ++ AR5K_PHY_IQ_CORR_ENABLE | ++ (ee->ee_i_cal[ee_mode] << AR5K_PHY_IQ_CORR_Q_I_COFF_S) | ++ ee->ee_q_cal[ee_mode]); ++ ++ if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) ++ AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN_2GHZ, ++ AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX, ++ ee->ee_margin_tx_rx[ee_mode]); ++ ++ } else { ++ mdelay(1); ++ /* Disable phy and wait */ ++ ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT); ++ mdelay(1); ++ } ++ ++ /* ++ * Restore saved values ++ */ ++ /*DCU/Antenna selection not available on 5210*/ ++ if (ah->ah_version != AR5K_AR5210) { ++ ath5k_hw_reg_write(ah, s_seq, AR5K_QUEUE_DFS_SEQNUM(0)); ++ ath5k_hw_reg_write(ah, s_ant, AR5K_DEFAULT_ANTENNA); ++ } ++ AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, s_led[0]); ++ ath5k_hw_reg_write(ah, s_led[1], AR5K_GPIOCR); ++ ath5k_hw_reg_write(ah, s_led[2], AR5K_GPIODO); ++ ++ /* ++ * Misc ++ */ ++ /* XXX: add ah->aid once mac80211 gives this to us */ ++ ath5k_hw_set_associd(ah, ah->bssid, 0); ++ ++ ath5k_hw_set_opmode(ah); ++ /*PISR/SISR Not available on 5210*/ ++ if (ah->ah_version != AR5K_AR5210) { ++ ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR); ++ /* If we later allow tuning for this, store into sc structure */ ++ data = AR5K_TUNE_RSSI_THRES | ++ AR5K_TUNE_BMISS_THRES << AR5K_RSSI_THR_BMISS_S; ++ ath5k_hw_reg_write(ah, data, AR5K_RSSI_THR); ++ } ++ ++ /* ++ * Set Rx/Tx DMA Configuration ++ *(passing dma size not available on 5210) ++ */ ++ if (ah->ah_version != AR5K_AR5210) { ++ AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, AR5K_TXCFG_SDMAMR, ++ AR5K_DMASIZE_512B | AR5K_TXCFG_DMASIZE); ++ AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_SDMAMW, ++ AR5K_DMASIZE_512B); ++ } ++ ++ /* ++ * Enable the PHY and wait until completion ++ */ ++ ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT); ++ ++ /* ++ * 5111/5112 Specific ++ */ ++ if (ah->ah_version != AR5K_AR5210) { ++ data = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) & ++ AR5K_PHY_RX_DELAY_M; ++ data = (channel->val & CHANNEL_CCK) ? ++ ((data << 2) / 22) : (data / 10); ++ ++ udelay(100 + data); ++ } else { ++ mdelay(1); ++ } ++ ++ /* ++ * Enable calibration and wait until completion ++ */ ++ AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, ++ AR5K_PHY_AGCCTL_CAL); ++ ++ if (ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, ++ AR5K_PHY_AGCCTL_CAL, 0, false)) { ++ ATH5K_ERR(ah->ah_sc, "calibration timeout (%uMHz)\n", ++ channel->freq); ++ return -EAGAIN; ++ } ++ ++ ret = ath5k_hw_noise_floor_calibration(ah, channel->freq); ++ if (ret) ++ return ret; ++ ++ ah->ah_calibration = false; ++ ++ /* A and G modes can use QAM modulation which requires enabling ++ * I and Q calibration. Don't bother in B mode. */ ++ if (!(driver_mode == MODE_IEEE80211B)) { ++ ah->ah_calibration = true; ++ AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, ++ AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15); ++ AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, ++ AR5K_PHY_IQ_RUN); ++ } ++ ++ /* ++ * Reset queues and start beacon timers at the end of the reset routine ++ */ ++ for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++) { ++ /*No QCU on 5210*/ ++ if (ah->ah_version != AR5K_AR5210) ++ AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(i), i); ++ ++ ret = ath5k_hw_reset_tx_queue(ah, i); ++ if (ret) { ++ ATH5K_ERR(ah->ah_sc, ++ "failed to reset TX queue #%d\n", i); ++ return ret; ++ } ++ } ++ ++ /* Pre-enable interrupts on 5211/5212*/ ++ if (ah->ah_version != AR5K_AR5210) ++ ath5k_hw_set_intr(ah, AR5K_INT_RX | AR5K_INT_TX | ++ AR5K_INT_FATAL); ++ ++ /* ++ * Set RF kill flags if supported by the device (read from the EEPROM) ++ * Disable gpio_intr for now since it results system hang. ++ * TODO: Handle this in ath5k_intr ++ */ ++#if 0 ++ if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) { ++ ath5k_hw_set_gpio_input(ah, 0); ++ ah->ah_gpio[0] = ath5k_hw_get_gpio(ah, 0); ++ if (ah->ah_gpio[0] == 0) ++ ath5k_hw_set_gpio_intr(ah, 0, 1); ++ else ++ ath5k_hw_set_gpio_intr(ah, 0, 0); ++ } ++#endif ++ ++ /* ++ * Set the 32MHz reference clock on 5212 phy clock sleep register ++ */ ++ if (ah->ah_version == AR5K_AR5212) { ++ ath5k_hw_reg_write(ah, AR5K_PHY_SCR_32MHZ, AR5K_PHY_SCR); ++ ath5k_hw_reg_write(ah, AR5K_PHY_SLMT_32MHZ, AR5K_PHY_SLMT); ++ ath5k_hw_reg_write(ah, AR5K_PHY_SCAL_32MHZ, AR5K_PHY_SCAL); ++ ath5k_hw_reg_write(ah, AR5K_PHY_SCLOCK_32MHZ, AR5K_PHY_SCLOCK); ++ ath5k_hw_reg_write(ah, AR5K_PHY_SDELAY_32MHZ, AR5K_PHY_SDELAY); ++ ath5k_hw_reg_write(ah, ah->ah_radio == AR5K_RF5111 ? ++ AR5K_PHY_SPENDING_RF5111 : AR5K_PHY_SPENDING_RF5112, ++ AR5K_PHY_SPENDING); ++ } ++ ++ /* ++ * Disable beacons and reset the register ++ */ ++ AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE | ++ AR5K_BEACON_RESET_TSF); ++ ++ return 0; ++} ++ ++/* ++ * Reset chipset ++ */ ++static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val) ++{ ++ int ret; ++ u32 mask = val ? val : ~0U; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ ++ /* Read-and-clear RX Descriptor Pointer*/ ++ ath5k_hw_reg_read(ah, AR5K_RXDP); ++ ++ /* ++ * Reset the device and wait until success ++ */ ++ ath5k_hw_reg_write(ah, val, AR5K_RESET_CTL); ++ ++ /* Wait at least 128 PCI clocks */ ++ udelay(15); ++ ++ if (ah->ah_version == AR5K_AR5210) { ++ val &= AR5K_RESET_CTL_CHIP; ++ mask &= AR5K_RESET_CTL_CHIP; ++ } else { ++ val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND; ++ mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND; ++ } ++ ++ ret = ath5k_hw_register_timeout(ah, AR5K_RESET_CTL, mask, val, false); ++ ++ /* ++ * Reset configuration register (for hw byte-swap). Note that this ++ * is only set for big endian. We do the necessary magic in ++ * AR5K_INIT_CFG. ++ */ ++ if ((val & AR5K_RESET_CTL_PCU) == 0) ++ ath5k_hw_reg_write(ah, AR5K_INIT_CFG, AR5K_CFG); ++ ++ return ret; ++} ++ ++/* ++ * Power management functions ++ */ ++ ++/* ++ * Sleep control ++ */ ++int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, ++ bool set_chip, u16 sleep_duration) ++{ ++ unsigned int i; ++ u32 staid; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ staid = ath5k_hw_reg_read(ah, AR5K_STA_ID1); ++ ++ switch (mode) { ++ case AR5K_PM_AUTO: ++ staid &= ~AR5K_STA_ID1_DEFAULT_ANTENNA; ++ /* fallthrough */ ++ case AR5K_PM_NETWORK_SLEEP: ++ if (set_chip == true) ++ ath5k_hw_reg_write(ah, ++ AR5K_SLEEP_CTL_SLE | sleep_duration, ++ AR5K_SLEEP_CTL); ++ ++ staid |= AR5K_STA_ID1_PWR_SV; ++ break; ++ ++ case AR5K_PM_FULL_SLEEP: ++ if (set_chip == true) ++ ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_SLP, ++ AR5K_SLEEP_CTL); ++ ++ staid |= AR5K_STA_ID1_PWR_SV; ++ break; ++ ++ case AR5K_PM_AWAKE: ++ if (set_chip == false) ++ goto commit; ++ ++ ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_WAKE, ++ AR5K_SLEEP_CTL); ++ ++ for (i = 5000; 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, AR5K_SLEEP_CTL_SLE_WAKE, ++ AR5K_SLEEP_CTL); ++ } ++ ++ /* Fail if the chip didn't wake up */ ++ if (i <= 0) ++ return -EIO; ++ ++ staid &= ~AR5K_STA_ID1_PWR_SV; ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++commit: ++ ah->ah_power_mode = mode; ++ ath5k_hw_reg_write(ah, staid, AR5K_STA_ID1); ++ ++ return 0; ++} ++ ++/***********************\ ++ DMA Related Functions ++\***********************/ ++ ++/* ++ * Receive functions ++ */ ++ ++/* ++ * Start DMA receive ++ */ ++void ath5k_hw_start_rx(struct ath5k_hw *ah) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR); ++} ++ ++/* ++ * Stop DMA receive ++ */ ++int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah) ++{ ++ unsigned int i; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ ath5k_hw_reg_write(ah, AR5K_CR_RXD, AR5K_CR); ++ ++ /* ++ * It may take some time to disable the DMA receive unit ++ */ ++ for (i = 2000; i > 0 && ++ (ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) != 0; ++ i--) ++ udelay(10); ++ ++ return i ? 0 : -EBUSY; ++} ++ ++/* ++ * Get the address of the RX Descriptor ++ */ ++u32 ath5k_hw_get_rx_buf(struct ath5k_hw *ah) ++{ ++ return ath5k_hw_reg_read(ah, AR5K_RXDP); ++} ++ ++/* ++ * Set the address of the RX Descriptor ++ */ ++void ath5k_hw_put_rx_buf(struct ath5k_hw *ah, u32 phys_addr) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ ++ /*TODO:Shouldn't we check if RX is enabled first ?*/ ++ ath5k_hw_reg_write(ah, phys_addr, AR5K_RXDP); ++} ++ ++/* ++ * Transmit functions ++ */ ++ ++/* ++ * Start DMA transmit for a specific queue ++ * (see also QCU/DCU functions) ++ */ ++int ath5k_hw_tx_start(struct ath5k_hw *ah, unsigned int queue) ++{ ++ u32 tx_queue; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); ++ ++ /* Return if queue is declared inactive */ ++ if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) ++ return -EIO; ++ ++ if (ah->ah_version == AR5K_AR5210) { ++ tx_queue = ath5k_hw_reg_read(ah, AR5K_CR); ++ ++ /* ++ * Set the queue by type on 5210 ++ */ ++ switch (ah->ah_txq[queue].tqi_type) { ++ case AR5K_TX_QUEUE_DATA: ++ tx_queue |= AR5K_CR_TXE0 & ~AR5K_CR_TXD0; ++ break; ++ case AR5K_TX_QUEUE_BEACON: ++ tx_queue |= AR5K_CR_TXE1 & ~AR5K_CR_TXD1; ++ ath5k_hw_reg_write(ah, AR5K_BCR_TQ1V | AR5K_BCR_BDMAE, ++ AR5K_BSR); ++ break; ++ case AR5K_TX_QUEUE_CAB: ++ tx_queue |= AR5K_CR_TXE1 & ~AR5K_CR_TXD1; ++ ath5k_hw_reg_write(ah, AR5K_BCR_TQ1FV | AR5K_BCR_TQ1V | ++ AR5K_BCR_BDMAE, AR5K_BSR); ++ break; ++ default: ++ return -EINVAL; ++ } ++ /* Start queue */ ++ ath5k_hw_reg_write(ah, tx_queue, AR5K_CR); ++ } else { ++ /* Return if queue is disabled */ ++ if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXD, queue)) ++ return -EIO; ++ ++ /* Start queue */ ++ AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXE, queue); ++ } ++ ++ return 0; ++} ++ ++/* ++ * Stop DMA transmit for a specific queue ++ * (see also QCU/DCU functions) ++ */ ++int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) ++{ ++ unsigned int i = 100; ++ u32 tx_queue, pending; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); ++ ++ /* Return if queue is declared inactive */ ++ if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) ++ return -EIO; ++ ++ if (ah->ah_version == AR5K_AR5210) { ++ tx_queue = ath5k_hw_reg_read(ah, AR5K_CR); ++ ++ /* ++ * Set by queue type ++ */ ++ switch (ah->ah_txq[queue].tqi_type) { ++ case AR5K_TX_QUEUE_DATA: ++ tx_queue |= AR5K_CR_TXD0 & ~AR5K_CR_TXE0; ++ break; ++ case AR5K_TX_QUEUE_BEACON: ++ case AR5K_TX_QUEUE_CAB: ++ /* XXX Fix me... */ ++ tx_queue |= AR5K_CR_TXD1 & ~AR5K_CR_TXD1; ++ ath5k_hw_reg_write(ah, 0, AR5K_BSR); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ /* Stop queue */ ++ ath5k_hw_reg_write(ah, tx_queue, AR5K_CR); ++ } else { ++ /* ++ * Schedule TX disable and wait until queue is empty ++ */ ++ AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXD, queue); ++ ++ /*Check for pending frames*/ ++ do { ++ pending = ath5k_hw_reg_read(ah, ++ AR5K_QUEUE_STATUS(queue)) & ++ AR5K_QCU_STS_FRMPENDCNT; ++ udelay(100); ++ } while (--i && pending); ++ ++ /* Clear register */ ++ ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD); ++ } ++ ++ /* TODO: Check for success else return error */ ++ return 0; ++} ++ ++/* ++ * Get the address of the TX Descriptor for a specific queue ++ * (see also QCU/DCU functions) ++ */ ++u32 ath5k_hw_get_tx_buf(struct ath5k_hw *ah, unsigned int queue) ++{ ++ u16 tx_reg; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); ++ ++ /* ++ * Get the transmit queue descriptor pointer from the selected queue ++ */ ++ /*5210 doesn't have QCU*/ ++ if (ah->ah_version == AR5K_AR5210) { ++ switch (ah->ah_txq[queue].tqi_type) { ++ case AR5K_TX_QUEUE_DATA: ++ tx_reg = AR5K_NOQCU_TXDP0; ++ break; ++ case AR5K_TX_QUEUE_BEACON: ++ case AR5K_TX_QUEUE_CAB: ++ tx_reg = AR5K_NOQCU_TXDP1; ++ break; ++ default: ++ return 0xffffffff; ++ } ++ } else { ++ tx_reg = AR5K_QUEUE_TXDP(queue); ++ } ++ ++ return ath5k_hw_reg_read(ah, tx_reg); ++} ++ ++/* ++ * Set the address of the TX Descriptor for a specific queue ++ * (see also QCU/DCU functions) ++ */ ++int ath5k_hw_put_tx_buf(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr) ++{ ++ u16 tx_reg; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); ++ ++ /* ++ * Set the transmit queue descriptor pointer register by type ++ * on 5210 ++ */ ++ if (ah->ah_version == AR5K_AR5210) { ++ switch (ah->ah_txq[queue].tqi_type) { ++ case AR5K_TX_QUEUE_DATA: ++ tx_reg = AR5K_NOQCU_TXDP0; ++ break; ++ case AR5K_TX_QUEUE_BEACON: ++ case AR5K_TX_QUEUE_CAB: ++ tx_reg = AR5K_NOQCU_TXDP1; ++ break; ++ default: ++ return -EINVAL; ++ } ++ } else { ++ /* ++ * Set the transmit queue descriptor pointer for ++ * the selected queue on QCU for 5211+ ++ * (this won't work if the queue is still active) ++ */ ++ if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue)) ++ return -EIO; ++ ++ tx_reg = AR5K_QUEUE_TXDP(queue); ++ } ++ ++ /* Set descriptor pointer */ ++ ath5k_hw_reg_write(ah, phys_addr, tx_reg); ++ ++ return 0; ++} ++ ++/* ++ * Update tx trigger level ++ */ ++int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase) ++{ ++ u32 trigger_level, imr; ++ int ret = -EIO; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ ++ /* ++ * Disable interrupts by setting the mask ++ */ ++ imr = ath5k_hw_set_intr(ah, ah->ah_imr & ~AR5K_INT_GLOBAL); ++ ++ /*TODO: Boundary check on trigger_level*/ ++ trigger_level = AR5K_REG_MS(ath5k_hw_reg_read(ah, AR5K_TXCFG), ++ AR5K_TXCFG_TXFULL); ++ ++ if (increase == false) { ++ if (--trigger_level < AR5K_TUNE_MIN_TX_FIFO_THRES) ++ goto done; ++ } else ++ trigger_level += ++ ((AR5K_TUNE_MAX_TX_FIFO_THRES - trigger_level) / 2); ++ ++ /* ++ * Update trigger level on success ++ */ ++ if (ah->ah_version == AR5K_AR5210) ++ ath5k_hw_reg_write(ah, trigger_level, AR5K_TRIG_LVL); ++ else ++ AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, ++ AR5K_TXCFG_TXFULL, trigger_level); ++ ++ ret = 0; ++ ++done: ++ /* ++ * Restore interrupt mask ++ */ ++ ath5k_hw_set_intr(ah, imr); ++ ++ return ret; ++} ++ ++/* ++ * Interrupt handling ++ */ ++ ++/* ++ * Check if we have pending interrupts ++ */ ++bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ return ath5k_hw_reg_read(ah, AR5K_INTPEND); ++} ++ ++/* ++ * Get interrupt mask (ISR) ++ */ ++int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) ++{ ++ u32 data; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ ++ /* ++ * Read interrupt status from the Interrupt Status register ++ * on 5210 ++ */ ++ if (ah->ah_version == AR5K_AR5210) { ++ data = ath5k_hw_reg_read(ah, AR5K_ISR); ++ if (unlikely(data == AR5K_INT_NOCARD)) { ++ *interrupt_mask = data; ++ return -ENODEV; ++ } ++ } else { ++ /* ++ * Read interrupt status from the Read-And-Clear shadow register ++ * Note: PISR/SISR Not available on 5210 ++ */ ++ data = ath5k_hw_reg_read(ah, AR5K_RAC_PISR); ++ } ++ ++ /* ++ * Get abstract interrupt mask (driver-compatible) ++ */ ++ *interrupt_mask = (data & AR5K_INT_COMMON) & ah->ah_imr; ++ ++ if (unlikely(data == AR5K_INT_NOCARD)) ++ return -ENODEV; ++ ++ if (data & (AR5K_ISR_RXOK | AR5K_ISR_RXERR)) ++ *interrupt_mask |= AR5K_INT_RX; ++ ++ if (data & (AR5K_ISR_TXOK | AR5K_ISR_TXERR ++ | AR5K_ISR_TXDESC | AR5K_ISR_TXEOL)) ++ *interrupt_mask |= AR5K_INT_TX; ++ ++ if (ah->ah_version != AR5K_AR5210) { ++ /*HIU = Host Interface Unit (PCI etc)*/ ++ if (unlikely(data & (AR5K_ISR_HIUERR))) ++ *interrupt_mask |= AR5K_INT_FATAL; ++ ++ /*Beacon Not Ready*/ ++ if (unlikely(data & (AR5K_ISR_BNR))) ++ *interrupt_mask |= AR5K_INT_BNR; ++ } ++ ++ /* ++ * XXX: BMISS interrupts may occur after association. ++ * I found this on 5210 code but it needs testing. If this is ++ * true we should disable them before assoc and re-enable them ++ * after a successfull assoc + some jiffies. ++ */ ++#if 0 ++ interrupt_mask &= ~AR5K_INT_BMISS; ++#endif ++ ++ /* ++ * In case we didn't handle anything, ++ * print the register value. ++ */ ++ if (unlikely(*interrupt_mask == 0 && net_ratelimit())) ++ ATH5K_PRINTF("0x%08x\n", data); ++ ++ return 0; ++} ++ ++/* ++ * Set interrupt mask ++ */ ++enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask) ++{ ++ enum ath5k_int old_mask, int_mask; ++ ++ /* ++ * Disable card interrupts to prevent any race conditions ++ * (they will be re-enabled afterwards). ++ */ ++ ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER); ++ ++ old_mask = ah->ah_imr; ++ ++ /* ++ * Add additional, chipset-dependent interrupt mask flags ++ * and write them to the IMR (interrupt mask register). ++ */ ++ int_mask = new_mask & AR5K_INT_COMMON; ++ ++ if (new_mask & AR5K_INT_RX) ++ int_mask |= AR5K_IMR_RXOK | AR5K_IMR_RXERR | AR5K_IMR_RXORN | ++ AR5K_IMR_RXDESC; ++ ++ if (new_mask & AR5K_INT_TX) ++ int_mask |= AR5K_IMR_TXOK | AR5K_IMR_TXERR | AR5K_IMR_TXDESC | ++ AR5K_IMR_TXURN; ++ ++ if (ah->ah_version != AR5K_AR5210) { ++ if (new_mask & AR5K_INT_FATAL) { ++ int_mask |= AR5K_IMR_HIUERR; ++ AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_MCABT | ++ AR5K_SIMR2_SSERR | AR5K_SIMR2_DPERR); ++ } ++ } ++ ++ ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR); ++ ++ /* Store new interrupt mask */ ++ ah->ah_imr = new_mask; ++ ++ /* ..re-enable interrupts */ ++ ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER); ++ ++ return old_mask; ++} ++ ++ ++/*************************\ ++ EEPROM access functions ++\*************************/ ++ ++/* ++ * Read from eeprom ++ */ ++static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data) ++{ ++ u32 status, timeout; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ /* ++ * Initialize EEPROM access ++ */ ++ if (ah->ah_version == AR5K_AR5210) { ++ AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE); ++ (void)ath5k_hw_reg_read(ah, AR5K_EEPROM_BASE + (4 * offset)); ++ } else { ++ ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE); ++ AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD, ++ AR5K_EEPROM_CMD_READ); ++ } ++ ++ for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) { ++ status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS); ++ if (status & AR5K_EEPROM_STAT_RDDONE) { ++ if (status & AR5K_EEPROM_STAT_RDERR) ++ return -EIO; ++ *data = (u16)(ath5k_hw_reg_read(ah, AR5K_EEPROM_DATA) & ++ 0xffff); ++ return 0; ++ } ++ udelay(15); ++ } ++ ++ return -ETIMEDOUT; ++} ++ ++/* ++ * Write to eeprom - currently disabled, use at your own risk ++ */ ++static int ath5k_hw_eeprom_write(struct ath5k_hw *ah, u32 offset, u16 data) ++{ ++#if 0 ++ u32 status, timeout; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ ++ /* ++ * Initialize eeprom access ++ */ ++ ++ if (ah->ah_version == AR5K_AR5210) { ++ AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE); ++ } else { ++ AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD, ++ AR5K_EEPROM_CMD_RESET); ++ } ++ ++ /* ++ * Write data to data register ++ */ ++ ++ if (ah->ah_version == AR5K_AR5210) { ++ ath5k_hw_reg_write(ah, data, AR5K_EEPROM_BASE + (4 * offset)); ++ } else { ++ ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE); ++ ath5k_hw_reg_write(ah, data, AR5K_EEPROM_DATA); ++ AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD, ++ AR5K_EEPROM_CMD_WRITE); ++ } ++ ++ /* ++ * Check status ++ */ ++ ++ for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) { ++ status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS); ++ if (status & AR5K_EEPROM_STAT_WRDONE) { ++ if (status & AR5K_EEPROM_STAT_WRERR) ++ return EIO; ++ return 0; ++ } ++ udelay(15); ++ } ++#endif ++ ATH5K_ERR(ah->ah_sc, "EEPROM Write is disabled!"); ++ return -EIO; ++} ++ ++/* ++ * Translate binary channel representation in EEPROM to frequency ++ */ ++static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin, unsigned int mode) ++{ ++ u16 val; ++ ++ if (bin == AR5K_EEPROM_CHANNEL_DIS) ++ return bin; ++ ++ if (mode == AR5K_EEPROM_MODE_11A) { ++ if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2) ++ val = (5 * bin) + 4800; ++ else ++ val = bin > 62 ? (10 * 62) + (5 * (bin - 62)) + 5100 : ++ (bin * 10) + 5100; ++ } else { ++ if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2) ++ val = bin + 2300; ++ else ++ val = bin + 2400; ++ } ++ ++ return val; ++} ++ ++/* ++ * Read antenna infos from eeprom ++ */ ++static int ath5k_eeprom_read_ants(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, i = 0; ++ ++ AR5K_EEPROM_READ(o++, val); ++ ee->ee_switch_settling[mode] = (val >> 8) & 0x7f; ++ ee->ee_ant_tx_rx[mode] = (val >> 2) & 0x3f; ++ ee->ee_ant_control[mode][i] = (val << 4) & 0x3f; ++ ++ AR5K_EEPROM_READ(o++, val); ++ ee->ee_ant_control[mode][i++] |= (val >> 12) & 0xf; ++ ee->ee_ant_control[mode][i++] = (val >> 6) & 0x3f; ++ ee->ee_ant_control[mode][i++] = val & 0x3f; ++ ++ AR5K_EEPROM_READ(o++, val); ++ ee->ee_ant_control[mode][i++] = (val >> 10) & 0x3f; ++ ee->ee_ant_control[mode][i++] = (val >> 4) & 0x3f; ++ ee->ee_ant_control[mode][i] = (val << 2) & 0x3f; ++ ++ AR5K_EEPROM_READ(o++, val); ++ ee->ee_ant_control[mode][i++] |= (val >> 14) & 0x3; ++ ee->ee_ant_control[mode][i++] = (val >> 8) & 0x3f; ++ ee->ee_ant_control[mode][i++] = (val >> 2) & 0x3f; ++ ee->ee_ant_control[mode][i] = (val << 4) & 0x3f; ++ ++ AR5K_EEPROM_READ(o++, val); ++ ee->ee_ant_control[mode][i++] |= (val >> 12) & 0xf; ++ ee->ee_ant_control[mode][i++] = (val >> 6) & 0x3f; ++ ee->ee_ant_control[mode][i++] = val & 0x3f; ++ ++ /* Get antenna modes */ ++ ah->ah_antenna[mode][0] = ++ (ee->ee_ant_control[mode][0] << 4) | 0x1; ++ ah->ah_antenna[mode][AR5K_ANT_FIXED_A] = ++ ee->ee_ant_control[mode][1] | ++ (ee->ee_ant_control[mode][2] << 6) | ++ (ee->ee_ant_control[mode][3] << 12) | ++ (ee->ee_ant_control[mode][4] << 18) | ++ (ee->ee_ant_control[mode][5] << 24); ++ ah->ah_antenna[mode][AR5K_ANT_FIXED_B] = ++ ee->ee_ant_control[mode][6] | ++ (ee->ee_ant_control[mode][7] << 6) | ++ (ee->ee_ant_control[mode][8] << 12) | ++ (ee->ee_ant_control[mode][9] << 18) | ++ (ee->ee_ant_control[mode][10] << 24); ++ ++ /* return new offset */ ++ *offset = o; ++ ++ return 0; ++} ++ ++/* ++ * Read supported modes from eeprom ++ */ ++static int ath5k_eeprom_read_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; ++ ++ AR5K_EEPROM_READ(o++, val); ++ ee->ee_tx_end2xlna_enable[mode] = (val >> 8) & 0xff; ++ ee->ee_thr_62[mode] = val & 0xff; ++ ++ if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2) ++ ee->ee_thr_62[mode] = mode == AR5K_EEPROM_MODE_11A ? 15 : 28; ++ ++ AR5K_EEPROM_READ(o++, val); ++ ee->ee_tx_end2xpa_disable[mode] = (val >> 8) & 0xff; ++ ee->ee_tx_frm2xpa_enable[mode] = val & 0xff; ++ ++ AR5K_EEPROM_READ(o++, val); ++ ee->ee_pga_desired_size[mode] = (val >> 8) & 0xff; ++ ++ if ((val & 0xff) & 0x80) ++ ee->ee_noise_floor_thr[mode] = -((((val & 0xff) ^ 0xff)) + 1); ++ else ++ ee->ee_noise_floor_thr[mode] = val & 0xff; ++ ++ if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2) ++ ee->ee_noise_floor_thr[mode] = ++ mode == AR5K_EEPROM_MODE_11A ? -54 : -1; ++ ++ AR5K_EEPROM_READ(o++, val); ++ ee->ee_xlna_gain[mode] = (val >> 5) & 0xff; ++ ee->ee_x_gain[mode] = (val >> 1) & 0xf; ++ ee->ee_xpd[mode] = val & 0x1; ++ ++ if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) ++ ee->ee_fixed_bias[mode] = (val >> 13) & 0x1; ++ ++ if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_3) { ++ AR5K_EEPROM_READ(o++, val); ++ ee->ee_false_detect[mode] = (val >> 6) & 0x7f; ++ ++ if (mode == AR5K_EEPROM_MODE_11A) ++ ee->ee_xr_power[mode] = val & 0x3f; ++ else { ++ ee->ee_ob[mode][0] = val & 0x7; ++ ee->ee_db[mode][0] = (val >> 3) & 0x7; ++ } ++ } ++ ++ if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_4) { ++ ee->ee_i_gain[mode] = AR5K_EEPROM_I_GAIN; ++ ee->ee_cck_ofdm_power_delta = AR5K_EEPROM_CCK_OFDM_DELTA; ++ } else { ++ ee->ee_i_gain[mode] = (val >> 13) & 0x7; ++ ++ AR5K_EEPROM_READ(o++, val); ++ ee->ee_i_gain[mode] |= (val << 3) & 0x38; ++ ++ if (mode == AR5K_EEPROM_MODE_11G) ++ ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff; ++ } ++ ++ if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 && ++ mode == AR5K_EEPROM_MODE_11A) { ++ ee->ee_i_cal[mode] = (val >> 8) & 0x3f; ++ ee->ee_q_cal[mode] = (val >> 3) & 0x1f; ++ } ++ ++ if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_6 && ++ mode == AR5K_EEPROM_MODE_11G) ++ ee->ee_scaled_cck_delta = (val >> 11) & 0x1f; ++ ++ /* return new offset */ ++ *offset = o; ++ ++ return 0; ++} ++ ++/* ++ * Initialize eeprom & capabilities structs ++ */ ++static int ath5k_eeprom_init(struct ath5k_hw *ah) ++{ ++ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; ++ unsigned int mode, i; ++ int ret; ++ u32 offset; ++ u16 val; ++ ++ /* Initial TX thermal adjustment values */ ++ ee->ee_tx_clip = 4; ++ ee->ee_pwd_84 = ee->ee_pwd_90 = 1; ++ ee->ee_gain_select = 1; ++ ++ /* ++ * Read values from EEPROM and store them in the capability structure ++ */ ++ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic); ++ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect); ++ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain); ++ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version); ++ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header); ++ ++ /* Return if we have an old EEPROM */ ++ if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0) ++ return 0; ++ ++#ifdef notyet ++ /* ++ * Validate the checksum of the EEPROM date. There are some ++ * devices with invalid EEPROMs. ++ */ ++ for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) { ++ AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val); ++ cksum ^= val; ++ } ++ if (cksum != AR5K_EEPROM_INFO_CKSUM) { ++ ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum); ++ return -EIO; ++ } ++#endif ++ ++ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version), ++ ee_ant_gain); ++ ++ if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { ++ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0); ++ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1); ++ } ++ ++ if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) { ++ AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val); ++ ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7; ++ ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7; ++ ++ AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val); ++ ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7; ++ ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7; ++ } ++ ++ /* ++ * Get conformance test limit values ++ */ ++ offset = AR5K_EEPROM_CTL(ah->ah_ee_version); ++ ee->ee_ctls = AR5K_EEPROM_N_CTLS(ah->ah_ee_version); ++ ++ for (i = 0; i < ee->ee_ctls; i++) { ++ AR5K_EEPROM_READ(offset++, val); ++ ee->ee_ctl[i] = (val >> 8) & 0xff; ++ ee->ee_ctl[i + 1] = val & 0xff; ++ } ++ ++ /* ++ * Get values for 802.11a (5GHz) ++ */ ++ mode = AR5K_EEPROM_MODE_11A; ++ ++ ee->ee_turbo_max_power[mode] = ++ AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header); ++ ++ offset = AR5K_EEPROM_MODES_11A(ah->ah_ee_version); ++ ++ ret = ath5k_eeprom_read_ants(ah, &offset, mode); ++ if (ret) ++ return ret; ++ ++ AR5K_EEPROM_READ(offset++, val); ++ ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); ++ ee->ee_ob[mode][3] = (val >> 5) & 0x7; ++ ee->ee_db[mode][3] = (val >> 2) & 0x7; ++ ee->ee_ob[mode][2] = (val << 1) & 0x7; ++ ++ AR5K_EEPROM_READ(offset++, val); ++ ee->ee_ob[mode][2] |= (val >> 15) & 0x1; ++ ee->ee_db[mode][2] = (val >> 12) & 0x7; ++ ee->ee_ob[mode][1] = (val >> 9) & 0x7; ++ ee->ee_db[mode][1] = (val >> 6) & 0x7; ++ ee->ee_ob[mode][0] = (val >> 3) & 0x7; ++ ee->ee_db[mode][0] = val & 0x7; ++ ++ ret = ath5k_eeprom_read_modes(ah, &offset, mode); ++ if (ret) ++ return ret; ++ ++ if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) { ++ AR5K_EEPROM_READ(offset++, val); ++ ee->ee_margin_tx_rx[mode] = val & 0x3f; ++ } ++ ++ /* ++ * Get values for 802.11b (2.4GHz) ++ */ ++ mode = AR5K_EEPROM_MODE_11B; ++ offset = AR5K_EEPROM_MODES_11B(ah->ah_ee_version); ++ ++ ret = ath5k_eeprom_read_ants(ah, &offset, mode); ++ if (ret) ++ return ret; ++ ++ AR5K_EEPROM_READ(offset++, val); ++ ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); ++ ee->ee_ob[mode][1] = (val >> 4) & 0x7; ++ ee->ee_db[mode][1] = val & 0x7; ++ ++ ret = ath5k_eeprom_read_modes(ah, &offset, mode); ++ if (ret) ++ return ret; ++ ++ if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { ++ AR5K_EEPROM_READ(offset++, val); ++ ee->ee_cal_pier[mode][0] = ++ ath5k_eeprom_bin2freq(ah, val & 0xff, mode); ++ ee->ee_cal_pier[mode][1] = ++ ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode); ++ ++ AR5K_EEPROM_READ(offset++, val); ++ ee->ee_cal_pier[mode][2] = ++ ath5k_eeprom_bin2freq(ah, val & 0xff, mode); ++ } ++ ++ if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) ++ ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; ++ ++ /* ++ * Get values for 802.11g (2.4GHz) ++ */ ++ mode = AR5K_EEPROM_MODE_11G; ++ offset = AR5K_EEPROM_MODES_11G(ah->ah_ee_version); ++ ++ ret = ath5k_eeprom_read_ants(ah, &offset, mode); ++ if (ret) ++ return ret; ++ ++ AR5K_EEPROM_READ(offset++, val); ++ ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); ++ ee->ee_ob[mode][1] = (val >> 4) & 0x7; ++ ee->ee_db[mode][1] = val & 0x7; ++ ++ ret = ath5k_eeprom_read_modes(ah, &offset, mode); ++ if (ret) ++ return ret; ++ ++ if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { ++ AR5K_EEPROM_READ(offset++, val); ++ ee->ee_cal_pier[mode][0] = ++ ath5k_eeprom_bin2freq(ah, val & 0xff, mode); ++ ee->ee_cal_pier[mode][1] = ++ ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode); ++ ++ AR5K_EEPROM_READ(offset++, val); ++ ee->ee_turbo_max_power[mode] = val & 0x7f; ++ ee->ee_xr_power[mode] = (val >> 7) & 0x3f; ++ ++ AR5K_EEPROM_READ(offset++, val); ++ ee->ee_cal_pier[mode][2] = ++ ath5k_eeprom_bin2freq(ah, val & 0xff, mode); ++ ++ if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) ++ ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; ++ ++ AR5K_EEPROM_READ(offset++, val); ++ ee->ee_i_cal[mode] = (val >> 8) & 0x3f; ++ ee->ee_q_cal[mode] = (val >> 3) & 0x1f; ++ ++ if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) { ++ AR5K_EEPROM_READ(offset++, val); ++ ee->ee_cck_ofdm_gain_delta = val & 0xff; ++ } ++ } ++ ++ /* ++ * Read 5GHz EEPROM channels ++ */ ++ ++ return 0; ++} ++ ++/* ++ * Read the MAC address from eeprom ++ */ ++static int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac) ++{ ++ u8 mac_d[ETH_ALEN]; ++ u32 total, offset; ++ u16 data; ++ int octet, ret; ++ ++ memset(mac, 0, ETH_ALEN); ++ memset(mac_d, 0, ETH_ALEN); ++ ++ ret = ath5k_hw_eeprom_read(ah, 0x20, &data); ++ if (ret) ++ return ret; ++ ++ for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) { ++ ret = ath5k_hw_eeprom_read(ah, offset, &data); ++ if (ret) ++ return ret; ++ ++ total += data; ++ mac_d[octet + 1] = data & 0xff; ++ mac_d[octet] = data >> 8; ++ octet += 2; ++ } ++ ++ memcpy(mac, mac_d, ETH_ALEN); ++ ++ if (!total || total == 3 * 0xffff) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++/* ++ * Read/Write regulatory domain ++ */ ++static bool ath5k_eeprom_regulation_domain(struct ath5k_hw *ah, bool write, ++ enum ath5k_regdom *regdomain) ++{ ++ u16 ee_regdomain; ++ ++ /* Read current value */ ++ if (write != true) { ++ ee_regdomain = ah->ah_capabilities.cap_eeprom.ee_regdomain; ++ *regdomain = ath5k_regdom_to_ieee(ee_regdomain); ++ return true; ++ } ++ ++ ee_regdomain = ath5k_regdom_from_ieee(*regdomain); ++ ++ /* Try to write a new value */ ++ if (ah->ah_capabilities.cap_eeprom.ee_protect & ++ AR5K_EEPROM_PROTECT_WR_128_191) ++ return false; ++ if (ath5k_hw_eeprom_write(ah, AR5K_EEPROM_REG_DOMAIN, ee_regdomain)!=0) ++ return false; ++ ++ ah->ah_capabilities.cap_eeprom.ee_regdomain = ee_regdomain; ++ ++ return true; ++} ++ ++/* ++ * Use the above to write a new regulatory domain ++ */ ++int ath5k_hw_set_regdomain(struct ath5k_hw *ah, u16 regdomain) ++{ ++ enum ath5k_regdom ieee_regdomain; ++ ++ ieee_regdomain = ath5k_regdom_to_ieee(regdomain); ++ ++ if (ath5k_eeprom_regulation_domain(ah, true, &ieee_regdomain) == true) ++ return 0; ++ ++ return -EIO; ++} ++ ++/* ++ * Fill the capabilities struct ++ */ ++static int ath5k_hw_get_capabilities(struct ath5k_hw *ah) ++{ ++ u16 ee_header; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ /* Capabilities stored in the EEPROM */ ++ ee_header = ah->ah_capabilities.cap_eeprom.ee_header; ++ ++ if (ah->ah_version == AR5K_AR5210) { ++ /* ++ * Set radio capabilities ++ * (The AR5110 only supports the middle 5GHz band) ++ */ ++ ah->ah_capabilities.cap_range.range_5ghz_min = 5120; ++ ah->ah_capabilities.cap_range.range_5ghz_max = 5430; ++ ah->ah_capabilities.cap_range.range_2ghz_min = 0; ++ ah->ah_capabilities.cap_range.range_2ghz_max = 0; ++ ++ /* Set supported modes */ ++ __set_bit(MODE_IEEE80211A, ah->ah_capabilities.cap_mode); ++ __set_bit(MODE_ATHEROS_TURBO, ah->ah_capabilities.cap_mode); ++ } else { ++ /* ++ * XXX The tranceiver supports frequencies from 4920 to 6100GHz ++ * XXX and from 2312 to 2732GHz. There are problems with the ++ * XXX current ieee80211 implementation because the IEEE ++ * XXX channel mapping does not support negative channel ++ * XXX numbers (2312MHz is channel -19). Of course, this ++ * XXX doesn't matter because these channels are out of range ++ * XXX but some regulation domains like MKK (Japan) will ++ * XXX support frequencies somewhere around 4.8GHz. ++ */ ++ ++ /* ++ * Set radio capabilities ++ */ ++ ++ if (AR5K_EEPROM_HDR_11A(ee_header)) { ++ ah->ah_capabilities.cap_range.range_5ghz_min = 5005; /* 4920 */ ++ ah->ah_capabilities.cap_range.range_5ghz_max = 6100; ++ ++ /* Set supported modes */ ++ __set_bit(MODE_IEEE80211A, ++ ah->ah_capabilities.cap_mode); ++ __set_bit(MODE_ATHEROS_TURBO, ++ ah->ah_capabilities.cap_mode); ++ if (ah->ah_version == AR5K_AR5212) ++ __set_bit(MODE_ATHEROS_TURBOG, ++ ah->ah_capabilities.cap_mode); ++ } ++ ++ /* Enable 802.11b if a 2GHz capable radio (2111/5112) is ++ * connected */ ++ if (AR5K_EEPROM_HDR_11B(ee_header) || ++ AR5K_EEPROM_HDR_11G(ee_header)) { ++ ah->ah_capabilities.cap_range.range_2ghz_min = 2412; /* 2312 */ ++ ah->ah_capabilities.cap_range.range_2ghz_max = 2732; ++ ++ if (AR5K_EEPROM_HDR_11B(ee_header)) ++ __set_bit(MODE_IEEE80211B, ++ ah->ah_capabilities.cap_mode); ++ ++ if (AR5K_EEPROM_HDR_11G(ee_header)) ++ __set_bit(MODE_IEEE80211G, ++ ah->ah_capabilities.cap_mode); ++ } ++ } ++ ++ /* GPIO */ ++ ah->ah_gpio_npins = AR5K_NUM_GPIO; ++ ++ /* Set number of supported TX queues */ ++ if (ah->ah_version == AR5K_AR5210) ++ ah->ah_capabilities.cap_queues.q_tx_num = ++ AR5K_NUM_TX_QUEUES_NOQCU; ++ else ++ ah->ah_capabilities.cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES; ++ ++ return 0; ++} ++ ++/*********************************\ ++ Protocol Control Unit Functions ++\*********************************/ ++ ++/* ++ * Set Operation mode ++ */ ++int ath5k_hw_set_opmode(struct ath5k_hw *ah) ++{ ++ u32 pcu_reg, beacon_reg, low_id, high_id; ++ ++ pcu_reg = 0; ++ beacon_reg = 0; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ ++ switch (ah->ah_op_mode) { ++ case IEEE80211_IF_TYPE_IBSS: ++ pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_DESC_ANTENNA | ++ (ah->ah_version == AR5K_AR5210 ? ++ AR5K_STA_ID1_NO_PSPOLL : 0); ++ beacon_reg |= AR5K_BCR_ADHOC; ++ break; ++ ++ case IEEE80211_IF_TYPE_AP: ++ pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_RTS_DEF_ANTENNA | ++ (ah->ah_version == AR5K_AR5210 ? ++ AR5K_STA_ID1_NO_PSPOLL : 0); ++ beacon_reg |= AR5K_BCR_AP; ++ break; ++ ++ case IEEE80211_IF_TYPE_STA: ++ pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA | ++ (ah->ah_version == AR5K_AR5210 ? ++ AR5K_STA_ID1_PWR_SV : 0); ++ case IEEE80211_IF_TYPE_MNTR: ++ pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA | ++ (ah->ah_version == AR5K_AR5210 ? ++ AR5K_STA_ID1_NO_PSPOLL : 0); ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ /* ++ * Set PCU registers ++ */ ++ low_id = AR5K_LOW_ID(ah->ah_sta_id); ++ high_id = AR5K_HIGH_ID(ah->ah_sta_id); ++ ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); ++ ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); ++ ++ /* ++ * Set Beacon Control Register on 5210 ++ */ ++ if (ah->ah_version == AR5K_AR5210) ++ ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR); ++ ++ return 0; ++} ++ ++/* ++ * BSSID Functions ++ */ ++ ++/* ++ * Get station id ++ */ ++void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ memcpy(mac, ah->ah_sta_id, ETH_ALEN); ++} ++ ++/* ++ * Set station id ++ */ ++int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) ++{ ++ u32 low_id, high_id; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ /* Set new station ID */ ++ memcpy(ah->ah_sta_id, mac, ETH_ALEN); ++ ++ low_id = AR5K_LOW_ID(mac); ++ high_id = AR5K_HIGH_ID(mac); ++ ++ ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); ++ ath5k_hw_reg_write(ah, high_id, AR5K_STA_ID1); ++ ++ return 0; ++} ++ ++/* ++ * Set BSSID ++ */ ++void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) ++{ ++ u32 low_id, high_id; ++ u16 tim_offset = 0; ++ ++ /* ++ * Set simple BSSID mask on 5212 ++ */ ++ if (ah->ah_version == AR5K_AR5212) { ++ ath5k_hw_reg_write(ah, 0xfffffff, AR5K_BSS_IDM0); ++ ath5k_hw_reg_write(ah, 0xfffffff, AR5K_BSS_IDM1); ++ } ++ ++ /* ++ * Set BSSID which triggers the "SME Join" operation ++ */ ++ low_id = AR5K_LOW_ID(bssid); ++ high_id = AR5K_HIGH_ID(bssid); ++ ath5k_hw_reg_write(ah, low_id, AR5K_BSS_ID0); ++ ath5k_hw_reg_write(ah, high_id | ((assoc_id & 0x3fff) << ++ AR5K_BSS_ID1_AID_S), AR5K_BSS_ID1); ++ memcpy(&ah->ah_bssid, bssid, ETH_ALEN); ++ ++ if (assoc_id == 0) { ++ ath5k_hw_disable_pspoll(ah); ++ return; ++ } ++ ++ AR5K_REG_WRITE_BITS(ah, AR5K_BEACON, AR5K_BEACON_TIM, ++ tim_offset ? tim_offset + 4 : 0); ++ ++ ath5k_hw_enable_pspoll(ah, NULL, 0); ++} ++/** ++ * ath5k_hw_set_bssid_mask - set common bits we should listen to ++ * ++ * The bssid_mask is a utility used by AR5212 hardware to inform the hardware ++ * which bits of the interface's MAC address should be looked at when trying ++ * to decide which packets to ACK. In station mode every bit matters. In AP ++ * mode with a single BSS every bit matters as well. In AP mode with ++ * multiple BSSes not every bit matters. ++ * ++ * @ah: the &struct ath5k_hw ++ * @mask: the bssid_mask, a u8 array of size ETH_ALEN ++ * ++ * Note that this is a simple filter and *does* not filter out all ++ * relevant frames. Some non-relevant frames will get through, probability ++ * jocks are welcomed to compute. ++ * ++ * When handling multiple BSSes (or VAPs) you can get the BSSID mask by ++ * computing the set of: ++ * ++ * ~ ( MAC XOR BSSID ) ++ * ++ * When you do this you are essentially computing the common bits. Later it ++ * is assumed the harware will "and" (&) the BSSID mask with the MAC address ++ * to obtain the relevant bits which should match on the destination frame. ++ * ++ * Simple example: on your card you have have two BSSes you have created with ++ * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address. ++ * There is another BSSID-03 but you are not part of it. For simplicity's sake, ++ * assuming only 4 bits for a mac address and for BSSIDs you can then have: ++ * ++ * \ ++ * MAC: 0001 | ++ * BSSID-01: 0100 | --> Belongs to us ++ * BSSID-02: 1001 | ++ * / ++ * ------------------- ++ * BSSID-03: 0110 | --> External ++ * ------------------- ++ * ++ * Our bssid_mask would then be: ++ * ++ * On loop iteration for BSSID-01: ++ * ~(0001 ^ 0100) -> ~(0101) ++ * -> 1010 ++ * bssid_mask = 1010 ++ * ++ * On loop iteration for BSSID-02: ++ * bssid_mask &= ~(0001 ^ 1001) ++ * bssid_mask = (1010) & ~(0001 ^ 1001) ++ * bssid_mask = (1010) & ~(1001) ++ * bssid_mask = (1010) & (0110) ++ * bssid_mask = 0010 ++ * ++ * A bssid_mask of 0010 means "only pay attention to the second least ++ * significant bit". This is because its the only bit common ++ * amongst the MAC and all BSSIDs we support. To findout what the real ++ * common bit is we can simply "&" the bssid_mask now with any BSSID we have ++ * or our MAC address (we assume the hardware uses the MAC address). ++ * ++ * Now, suppose there's an incoming frame for BSSID-03: ++ * ++ * IFRAME-01: 0110 ++ * ++ * An easy eye-inspeciton of this already should tell you that this frame ++ * will not pass our check. This is beacuse the bssid_mask tells the ++ * hardware to only look at the second least significant bit and the ++ * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB ++ * as 1, which does not match 0. ++ * ++ * So with IFRAME-01 we *assume* the hardware will do: ++ * ++ * allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0; ++ * --> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0; ++ * --> allow = (0010) == 0000 ? 1 : 0; ++ * --> allow = 0 ++ * ++ * Lets now test a frame that should work: ++ * ++ * IFRAME-02: 0001 (we should allow) ++ * ++ * allow = (0001 & 1010) == 1010 ++ * ++ * allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0; ++ * --> allow = (0001 & 0010) == (0010 & 0001) ? 1 :0; ++ * --> allow = (0010) == (0010) ++ * --> allow = 1 ++ * ++ * Other examples: ++ * ++ * IFRAME-03: 0100 --> allowed ++ * IFRAME-04: 1001 --> allowed ++ * IFRAME-05: 1101 --> allowed but its not for us!!! ++ * ++ */ ++int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) ++{ ++ u32 low_id, high_id; ++ ATH5K_TRACE(ah->ah_sc); ++ ++ if (ah->ah_version == AR5K_AR5212) { ++ low_id = AR5K_LOW_ID(mask); ++ high_id = AR5K_HIGH_ID(mask); ++ ++ ath5k_hw_reg_write(ah, low_id, AR5K_BSS_IDM0); ++ ath5k_hw_reg_write(ah, high_id, AR5K_BSS_IDM1); ++ ++ return 0; ++ } ++ ++ return -EIO; ++} ++ ++/* ++ * Receive start/stop functions ++ */ ++ ++/* ++ * Start receive on PCU ++ */ ++void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); ++} ++ ++/* ++ * Stop receive on PCU ++ */ ++void ath5k_hw_stop_pcu_recv(struct ath5k_hw *ah) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); ++} ++ ++/* ++ * RX Filter functions ++ */ ++ ++/* ++ * Set multicast filter ++ */ ++void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ /* Set the multicat filter */ ++ ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0); ++ ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1); ++} ++ ++/* ++ * Set multicast filter by index ++ */ ++int ath5k_hw_set_mcast_filterindex(struct ath5k_hw *ah, u32 index) ++{ ++ ++ ATH5K_TRACE(ah->ah_sc); ++ if (index >= 64) ++ return -EINVAL; ++ else if (index >= 32) ++ AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER1, ++ (1 << (index - 32))); ++ else ++ AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index)); ++ ++ return 0; ++} ++ ++/* ++ * Clear Multicast filter by index ++ */ ++int ath5k_hw_clear_mcast_filter_idx(struct ath5k_hw *ah, u32 index) ++{ ++ ++ ATH5K_TRACE(ah->ah_sc); ++ if (index >= 64) ++ return -EINVAL; ++ else if (index >= 32) ++ AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER1, ++ (1 << (index - 32))); ++ else ++ AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index)); ++ ++ return 0; ++} ++ ++/* ++ * Get current rx filter ++ */ ++u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah) ++{ ++ u32 data, filter = 0; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ filter = ath5k_hw_reg_read(ah, AR5K_RX_FILTER); ++ ++ /*Radar detection for 5212*/ ++ if (ah->ah_version == AR5K_AR5212) { ++ data = ath5k_hw_reg_read(ah, AR5K_PHY_ERR_FIL); ++ ++ if (data & AR5K_PHY_ERR_FIL_RADAR) ++ filter |= AR5K_RX_FILTER_RADARERR; ++ if (data & (AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK)) ++ filter |= AR5K_RX_FILTER_PHYERR; ++ } ++ ++ return filter; ++} ++ ++/* ++ * Set rx filter ++ */ ++void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter) ++{ ++ u32 data = 0; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ ++ /* Set PHY error filter register on 5212*/ ++ if (ah->ah_version == AR5K_AR5212) { ++ if (filter & AR5K_RX_FILTER_RADARERR) ++ data |= AR5K_PHY_ERR_FIL_RADAR; ++ if (filter & AR5K_RX_FILTER_PHYERR) ++ data |= AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK; ++ } ++ ++ /* ++ * The AR5210 uses promiscous mode to detect radar activity ++ */ ++ if (ah->ah_version == AR5K_AR5210 && ++ (filter & AR5K_RX_FILTER_RADARERR)) { ++ filter &= ~AR5K_RX_FILTER_RADARERR; ++ filter |= AR5K_RX_FILTER_PROM; ++ } ++ ++ /*Zero length DMA*/ ++ if (data) ++ AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA); ++ else ++ AR5K_REG_DISABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA); ++ ++ /*Write RX Filter register*/ ++ ath5k_hw_reg_write(ah, filter & 0xff, AR5K_RX_FILTER); ++ ++ /*Write PHY error filter register on 5212*/ ++ if (ah->ah_version == AR5K_AR5212) ++ ath5k_hw_reg_write(ah, data, AR5K_PHY_ERR_FIL); ++ ++} ++ ++/* ++ * Beacon related functions ++ */ ++ ++/* ++ * Get a 32bit TSF ++ */ ++u32 ath5k_hw_get_tsf32(struct ath5k_hw *ah) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ return ath5k_hw_reg_read(ah, AR5K_TSF_L32); ++} ++ ++/* ++ * Get the full 64bit TSF ++ */ ++u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah) ++{ ++ u64 tsf = ath5k_hw_reg_read(ah, AR5K_TSF_U32); ++ ATH5K_TRACE(ah->ah_sc); ++ ++ return ath5k_hw_reg_read(ah, AR5K_TSF_L32) | (tsf << 32); ++} ++ ++/* ++ * Force a TSF reset ++ */ ++void ath5k_hw_reset_tsf(struct ath5k_hw *ah) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ AR5K_REG_ENABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_RESET_TSF); ++} ++ ++/* ++ * Initialize beacon timers ++ */ ++void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval) ++{ ++ u32 timer1, timer2, timer3; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ /* ++ * Set the additional timers by mode ++ */ ++ switch (ah->ah_op_mode) { ++ case IEEE80211_IF_TYPE_STA: ++ if (ah->ah_version == AR5K_AR5210) { ++ timer1 = 0xffffffff; ++ timer2 = 0xffffffff; ++ } else { ++ timer1 = 0x0000ffff; ++ timer2 = 0x0007ffff; ++ } ++ break; ++ ++ default: ++ timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << ++ 0x00000003; ++ timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << ++ 0x00000003; ++ } ++ ++ timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1); ++ ++ /* ++ * Set the beacon register and enable all timers. ++ * (next beacon, DMA beacon, software beacon, ATIM window time) ++ */ ++ ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0); ++ ath5k_hw_reg_write(ah, timer1, AR5K_TIMER1); ++ ath5k_hw_reg_write(ah, timer2, AR5K_TIMER2); ++ ath5k_hw_reg_write(ah, timer3, AR5K_TIMER3); ++ ++ ath5k_hw_reg_write(ah, interval & (AR5K_BEACON_PERIOD | ++ AR5K_BEACON_RESET_TSF | AR5K_BEACON_ENABLE), ++ AR5K_BEACON); ++} ++ ++/* ++ * Set beacon timers ++ */ ++int ath5k_hw_set_beacon_timers(struct ath5k_hw *ah, ++ const struct ath5k_beacon_state *state) ++{ ++ u32 cfp_period, next_cfp, dtim, interval, next_beacon; ++ ++ /* ++ * TODO: should be changed through *state ++ * review struct ath5k_beacon_state struct ++ * ++ * XXX: These are used for cfp period bellow, are they ++ * ok ? Is it O.K. for tsf here to be 0 or should we use ++ * get_tsf ? ++ */ ++ u32 dtim_count = 0; /* XXX */ ++ u32 cfp_count = 0; /* XXX */ ++ u32 tsf = 0; /* XXX */ ++ ++ ATH5K_TRACE(ah->ah_sc); ++ /* Return on an invalid beacon state */ ++ if (state->bs_interval < 1) ++ return -EINVAL; ++ ++ interval = state->bs_interval; ++ dtim = state->bs_dtim_period; ++ ++ /* ++ * PCF support? ++ */ ++ if (state->bs_cfp_period > 0) { ++ /* ++ * Enable PCF mode and set the CFP ++ * (Contention Free Period) and timer registers ++ */ ++ cfp_period = state->bs_cfp_period * state->bs_dtim_period * ++ state->bs_interval; ++ next_cfp = (cfp_count * state->bs_dtim_period + dtim_count) * ++ state->bs_interval; ++ ++ AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, ++ AR5K_STA_ID1_DEFAULT_ANTENNA | ++ AR5K_STA_ID1_PCF); ++ ath5k_hw_reg_write(ah, cfp_period, AR5K_CFP_PERIOD); ++ ath5k_hw_reg_write(ah, state->bs_cfp_max_duration, ++ AR5K_CFP_DUR); ++ ath5k_hw_reg_write(ah, (tsf + (next_cfp == 0 ? cfp_period : ++ next_cfp)) << 3, AR5K_TIMER2); ++ } else { ++ /* Disable PCF mode */ ++ AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, ++ AR5K_STA_ID1_DEFAULT_ANTENNA | ++ AR5K_STA_ID1_PCF); ++ } ++ ++ /* ++ * Enable the beacon timer register ++ */ ++ ath5k_hw_reg_write(ah, state->bs_next_beacon, AR5K_TIMER0); ++ ++ /* ++ * Start the beacon timers ++ */ ++ ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_BEACON) &~ ++ (AR5K_BEACON_PERIOD | AR5K_BEACON_TIM)) | ++ AR5K_REG_SM(state->bs_tim_offset ? state->bs_tim_offset + 4 : 0, ++ AR5K_BEACON_TIM) | AR5K_REG_SM(state->bs_interval, ++ AR5K_BEACON_PERIOD), AR5K_BEACON); ++ ++ /* ++ * Write new beacon miss threshold, if it appears to be valid ++ * XXX: Figure out right values for min <= bs_bmiss_threshold <= max ++ * and return if its not in range. We can test this by reading value and ++ * setting value to a largest value and seeing which values register. ++ */ ++ ++ AR5K_REG_WRITE_BITS(ah, AR5K_RSSI_THR, AR5K_RSSI_THR_BMISS, ++ state->bs_bmiss_threshold); ++ ++ /* ++ * Set sleep control register ++ * XXX: Didn't find this in 5210 code but since this register ++ * exists also in ar5k's 5210 headers i leave it as common code. ++ */ ++ AR5K_REG_WRITE_BITS(ah, AR5K_SLEEP_CTL, AR5K_SLEEP_CTL_SLDUR, ++ (state->bs_sleep_duration - 3) << 3); ++ ++ /* ++ * Set enhanced sleep registers on 5212 ++ */ ++ if (ah->ah_version == AR5K_AR5212) { ++ if (state->bs_sleep_duration > state->bs_interval && ++ roundup(state->bs_sleep_duration, interval) == ++ state->bs_sleep_duration) ++ interval = state->bs_sleep_duration; ++ ++ if (state->bs_sleep_duration > dtim && (dtim == 0 || ++ roundup(state->bs_sleep_duration, dtim) == ++ state->bs_sleep_duration)) ++ dtim = state->bs_sleep_duration; ++ ++ if (interval > dtim) ++ return -EINVAL; ++ ++ next_beacon = interval == dtim ? state->bs_next_dtim : ++ state->bs_next_beacon; ++ ++ ath5k_hw_reg_write(ah, ++ AR5K_REG_SM((state->bs_next_dtim - 3) << 3, ++ AR5K_SLEEP0_NEXT_DTIM) | ++ AR5K_REG_SM(10, AR5K_SLEEP0_CABTO) | ++ AR5K_SLEEP0_ENH_SLEEP_EN | ++ AR5K_SLEEP0_ASSUME_DTIM, AR5K_SLEEP0); ++ ++ ath5k_hw_reg_write(ah, AR5K_REG_SM((next_beacon - 3) << 3, ++ AR5K_SLEEP1_NEXT_TIM) | ++ AR5K_REG_SM(10, AR5K_SLEEP1_BEACON_TO), AR5K_SLEEP1); ++ ++ ath5k_hw_reg_write(ah, ++ AR5K_REG_SM(interval, AR5K_SLEEP2_TIM_PER) | ++ AR5K_REG_SM(dtim, AR5K_SLEEP2_DTIM_PER), AR5K_SLEEP2); ++ } ++ ++ return 0; ++} ++ ++/* ++ * Reset beacon timers ++ */ ++void ath5k_hw_reset_beacon(struct ath5k_hw *ah) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ /* ++ * Disable beacon timer ++ */ ++ ath5k_hw_reg_write(ah, 0, AR5K_TIMER0); ++ ++ /* ++ * Disable some beacon register values ++ */ ++ AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, ++ AR5K_STA_ID1_DEFAULT_ANTENNA | AR5K_STA_ID1_PCF); ++ ath5k_hw_reg_write(ah, AR5K_BEACON_PERIOD, AR5K_BEACON); ++} ++ ++/* ++ * Wait for beacon queue to finish ++ * TODO: This function's name is misleading, rename ++ */ ++int ath5k_hw_wait_for_beacon(struct ath5k_hw *ah, unsigned long phys_addr) ++{ ++ unsigned int i; ++ int ret; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ ++ /* 5210 doesn't have QCU*/ ++ if (ah->ah_version == AR5K_AR5210) { ++ /* ++ * Wait for beaconn queue to finish by checking ++ * Control Register and Beacon Status Register. ++ */ ++ for (i = AR5K_TUNE_BEACON_INTERVAL / 2; i > 0; i--) { ++ if (!(ath5k_hw_reg_read(ah, AR5K_BSR) & AR5K_BSR_TXQ1F) ++ || ++ !(ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_BSR_TXQ1F)) ++ break; ++ udelay(10); ++ } ++ ++ /* Timeout... */ ++ if (i <= 0) { ++ /* ++ * Re-schedule the beacon queue ++ */ ++ ath5k_hw_reg_write(ah, phys_addr, AR5K_NOQCU_TXDP1); ++ ath5k_hw_reg_write(ah, AR5K_BCR_TQ1V | AR5K_BCR_BDMAE, ++ AR5K_BCR); ++ ++ return -EIO; ++ } ++ ret = 0; ++ } else { ++ /*5211/5212*/ ++ ret = ath5k_hw_register_timeout(ah, ++ AR5K_QUEUE_STATUS(AR5K_TX_QUEUE_ID_BEACON), ++ AR5K_QCU_STS_FRMPENDCNT, 0, false); ++ ++ if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, AR5K_TX_QUEUE_ID_BEACON)) ++ return -EIO; ++ } ++ ++ return ret; ++} ++ ++/* ++ * Update mib counters (statistics) ++ */ ++void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, ++ struct ath5k_mib_stats *statistics) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ /* Read-And-Clear */ ++ statistics->ackrcv_bad += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL); ++ statistics->rts_bad += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL); ++ statistics->rts_good += ath5k_hw_reg_read(ah, AR5K_RTS_OK); ++ statistics->fcs_bad += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL); ++ statistics->beacons += ath5k_hw_reg_read(ah, AR5K_BEACON_CNT); ++ ++ /* Reset profile count registers on 5212*/ ++ if (ah->ah_version == AR5K_AR5212) { ++ ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_TX); ++ ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RX); ++ ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR); ++ ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE); ++ } ++} ++ ++/** ath5k_hw_set_ack_bitrate - set bitrate for ACKs ++ * ++ * @ah: the &struct ath5k_hw ++ * @high: determines if to use low bit rate or now ++ */ ++void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high) ++{ ++ if (ah->ah_version != AR5K_AR5212) ++ return; ++ else { ++ u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB; ++ if (high) ++ AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val); ++ else ++ AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val); ++ } ++} ++ ++ ++/* ++ * ACK/CTS Timeouts ++ */ ++ ++/* ++ * Set ACK timeout on PCU ++ */ ++int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK), ++ ah->ah_turbo) <= timeout) ++ return -EINVAL; ++ ++ AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK, ++ ath5k_hw_htoclock(timeout, ah->ah_turbo)); ++ ++ return 0; ++} ++ ++/* ++ * Read the ACK timeout from PCU ++ */ ++unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ ++ return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah, ++ AR5K_TIME_OUT), AR5K_TIME_OUT_ACK), ah->ah_turbo); ++} ++ ++/* ++ * Set CTS timeout on PCU ++ */ ++int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS), ++ ah->ah_turbo) <= timeout) ++ return -EINVAL; ++ ++ AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS, ++ ath5k_hw_htoclock(timeout, ah->ah_turbo)); ++ ++ return 0; ++} ++ ++/* ++ * Read CTS timeout from PCU ++ */ ++unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah, ++ AR5K_TIME_OUT), AR5K_TIME_OUT_CTS), ah->ah_turbo); ++} ++ ++/* ++ * Key table (WEP) functions ++ */ ++ ++int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry) ++{ ++ unsigned int i; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); ++ ++ for (i = 0; i < AR5K_KEYCACHE_SIZE; i++) ++ ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i)); ++ ++ /* Set NULL encryption on non-5210*/ ++ if (ah->ah_version != AR5K_AR5210) ++ ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, ++ AR5K_KEYTABLE_TYPE(entry)); ++ ++ return 0; ++} ++ ++int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); ++ ++ /* Check the validation flag at the end of the entry */ ++ return ath5k_hw_reg_read(ah, AR5K_KEYTABLE_MAC1(entry)) & ++ AR5K_KEYTABLE_VALID; ++} ++ ++int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, ++ const struct ieee80211_key_conf *key, const u8 *mac) ++{ ++ unsigned int i; ++ __le32 key_v[5] = {}; ++ u32 keytype; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ ++ /* key->keylen comes in from mac80211 in bytes */ ++ ++ if (key->keylen > AR5K_KEYTABLE_SIZE / 8) ++ return -EOPNOTSUPP; ++ ++ switch (key->keylen) { ++ /* WEP 40-bit = 40-bit entered key + 24 bit IV = 64-bit */ ++ case 40 / 8: ++ memcpy(&key_v[0], key->key, 5); ++ keytype = AR5K_KEYTABLE_TYPE_40; ++ break; ++ ++ /* WEP 104-bit = 104-bit entered key + 24-bit IV = 128-bit */ ++ case 104 / 8: ++ memcpy(&key_v[0], &key->key[0], 6); ++ memcpy(&key_v[2], &key->key[6], 6); ++ memcpy(&key_v[4], &key->key[12], 1); ++ keytype = AR5K_KEYTABLE_TYPE_104; ++ break; ++ /* WEP 128-bit = 128-bit entered key + 24 bit IV = 152-bit */ ++ case 128 / 8: ++ memcpy(&key_v[0], &key->key[0], 6); ++ memcpy(&key_v[2], &key->key[6], 6); ++ memcpy(&key_v[4], &key->key[12], 4); ++ keytype = AR5K_KEYTABLE_TYPE_128; ++ break; ++ ++ default: ++ return -EINVAL; /* shouldn't happen */ ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(key_v); i++) ++ ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]), ++ AR5K_KEYTABLE_OFF(entry, i)); ++ ++ ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry)); ++ ++ return ath5k_hw_set_key_lladdr(ah, entry, mac); ++} ++ ++int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac) ++{ ++ u32 low_id, high_id; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ /* Invalid entry (key table overflow) */ ++ AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); ++ ++ /* MAC may be NULL if it's a broadcast key. In this case no need to ++ * to compute AR5K_LOW_ID and AR5K_HIGH_ID as we already know it. */ ++ if (unlikely(mac == NULL)) { ++ low_id = 0xffffffff; ++ high_id = 0xffff | AR5K_KEYTABLE_VALID; ++ } else { ++ low_id = AR5K_LOW_ID(mac); ++ high_id = AR5K_HIGH_ID(mac) | AR5K_KEYTABLE_VALID; ++ } ++ ++ ath5k_hw_reg_write(ah, low_id, AR5K_KEYTABLE_MAC0(entry)); ++ ath5k_hw_reg_write(ah, high_id, AR5K_KEYTABLE_MAC1(entry)); ++ ++ return 0; ++} ++ ++ ++/********************************************\ ++Queue Control Unit, DFS Control Unit Functions ++\********************************************/ ++ ++/* ++ * Initialize a transmit queue ++ */ ++int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, ++ struct ath5k_txq_info *queue_info) ++{ ++ unsigned int queue; ++ int ret; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ ++ /* ++ * Get queue by type ++ */ ++ /*5210 only has 2 queues*/ ++ if (ah->ah_version == AR5K_AR5210) { ++ switch (queue_type) { ++ case AR5K_TX_QUEUE_DATA: ++ queue = AR5K_TX_QUEUE_ID_NOQCU_DATA; ++ break; ++ case AR5K_TX_QUEUE_BEACON: ++ case AR5K_TX_QUEUE_CAB: ++ queue = AR5K_TX_QUEUE_ID_NOQCU_BEACON; ++ break; ++ default: ++ return -EINVAL; ++ } ++ } else { ++ switch (queue_type) { ++ case AR5K_TX_QUEUE_DATA: ++ for (queue = AR5K_TX_QUEUE_ID_DATA_MIN; ++ ah->ah_txq[queue].tqi_type != ++ AR5K_TX_QUEUE_INACTIVE; queue++) { ++ ++ if (queue > AR5K_TX_QUEUE_ID_DATA_MAX) ++ return -EINVAL; ++ } ++ break; ++ case AR5K_TX_QUEUE_UAPSD: ++ queue = AR5K_TX_QUEUE_ID_UAPSD; ++ break; ++ case AR5K_TX_QUEUE_BEACON: ++ queue = AR5K_TX_QUEUE_ID_BEACON; ++ break; ++ case AR5K_TX_QUEUE_CAB: ++ queue = AR5K_TX_QUEUE_ID_CAB; ++ break; ++ case AR5K_TX_QUEUE_XR_DATA: ++ if (ah->ah_version != AR5K_AR5212) ++ ATH5K_ERR(ah->ah_sc, ++ "XR data queues only supported in" ++ " 5212!\n"); ++ queue = AR5K_TX_QUEUE_ID_XR_DATA; ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ ++ /* ++ * Setup internal queue structure ++ */ ++ memset(&ah->ah_txq[queue], 0, sizeof(struct ath5k_txq_info)); ++ ah->ah_txq[queue].tqi_type = queue_type; ++ ++ if (queue_info != NULL) { ++ queue_info->tqi_type = queue_type; ++ ret = ath5k_hw_setup_tx_queueprops(ah, queue, queue_info); ++ if (ret) ++ return ret; ++ } ++ /* ++ * We use ah_txq_status to hold a temp value for ++ * the Secondary interrupt mask registers on 5211+ ++ * check out ath5k_hw_reset_tx_queue ++ */ ++ AR5K_Q_ENABLE_BITS(ah->ah_txq_status, queue); ++ ++ return queue; ++} ++ ++/* ++ * Setup a transmit queue ++ */ ++int ath5k_hw_setup_tx_queueprops(struct ath5k_hw *ah, int queue, ++ const struct ath5k_txq_info *queue_info) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); ++ ++ if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) ++ return -EIO; ++ ++ memcpy(&ah->ah_txq[queue], queue_info, sizeof(struct ath5k_txq_info)); ++ ++ /*XXX: Is this supported on 5210 ?*/ ++ if ((queue_info->tqi_type == AR5K_TX_QUEUE_DATA && ++ ((queue_info->tqi_subtype == AR5K_WME_AC_VI) || ++ (queue_info->tqi_subtype == AR5K_WME_AC_VO))) || ++ queue_info->tqi_type == AR5K_TX_QUEUE_UAPSD) ++ ah->ah_txq[queue].tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS; ++ ++ return 0; ++} ++ ++/* ++ * Get properties for a specific transmit queue ++ */ ++int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, ++ struct ath5k_txq_info *queue_info) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info)); ++ return 0; ++} ++ ++/* ++ * Set a transmit queue inactive ++ */ ++void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num)) ++ return; ++ ++ /* This queue will be skipped in further operations */ ++ ah->ah_txq[queue].tqi_type = AR5K_TX_QUEUE_INACTIVE; ++ /*For SIMR setup*/ ++ AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue); ++} ++ ++/* ++ * Set DFS params for a transmit queue ++ */ ++int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) ++{ ++ u32 cw_min, cw_max, retry_lg, retry_sh; ++ struct ath5k_txq_info *tq = &ah->ah_txq[queue]; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); ++ ++ tq = &ah->ah_txq[queue]; ++ ++ if (tq->tqi_type == AR5K_TX_QUEUE_INACTIVE) ++ return 0; ++ ++ if (ah->ah_version == AR5K_AR5210) { ++ /* Only handle data queues, others will be ignored */ ++ if (tq->tqi_type != AR5K_TX_QUEUE_DATA) ++ return 0; ++ ++ /* Set Slot time */ ++ ath5k_hw_reg_write(ah, ah->ah_turbo == true ? ++ AR5K_INIT_SLOT_TIME_TURBO : AR5K_INIT_SLOT_TIME, ++ AR5K_SLOT_TIME); ++ /* Set ACK_CTS timeout */ ++ ath5k_hw_reg_write(ah, ah->ah_turbo == true ? ++ AR5K_INIT_ACK_CTS_TIMEOUT_TURBO : ++ AR5K_INIT_ACK_CTS_TIMEOUT, AR5K_SLOT_TIME); ++ /* Set Transmit Latency */ ++ ath5k_hw_reg_write(ah, ah->ah_turbo == true ? ++ AR5K_INIT_TRANSMIT_LATENCY_TURBO : ++ AR5K_INIT_TRANSMIT_LATENCY, AR5K_USEC_5210); ++ /* Set IFS0 */ ++ if (ah->ah_turbo == true) ++ ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS_TURBO + ++ (ah->ah_aifs + tq->tqi_aifs) * ++ AR5K_INIT_SLOT_TIME_TURBO) << ++ AR5K_IFS0_DIFS_S) | AR5K_INIT_SIFS_TURBO, ++ AR5K_IFS0); ++ else ++ ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS + ++ (ah->ah_aifs + tq->tqi_aifs) * ++ AR5K_INIT_SLOT_TIME) << AR5K_IFS0_DIFS_S) | ++ AR5K_INIT_SIFS, AR5K_IFS0); ++ ++ /* Set IFS1 */ ++ ath5k_hw_reg_write(ah, ah->ah_turbo == true ? ++ AR5K_INIT_PROTO_TIME_CNTRL_TURBO : ++ AR5K_INIT_PROTO_TIME_CNTRL, AR5K_IFS1); ++ /* Set PHY register 0x9844 (??) */ ++ ath5k_hw_reg_write(ah, ah->ah_turbo == true ? ++ (ath5k_hw_reg_read(ah, AR5K_PHY(17)) & ~0x7F) | 0x38 : ++ (ath5k_hw_reg_read(ah, AR5K_PHY(17)) & ~0x7F) | 0x1C, ++ AR5K_PHY(17)); ++ /* Set Frame Control Register */ ++ ath5k_hw_reg_write(ah, ah->ah_turbo == true ? ++ (AR5K_PHY_FRAME_CTL_INI | AR5K_PHY_TURBO_MODE | ++ AR5K_PHY_TURBO_SHORT | 0x2020) : ++ (AR5K_PHY_FRAME_CTL_INI | 0x1020), ++ AR5K_PHY_FRAME_CTL_5210); ++ } ++ ++ /* ++ * Calculate cwmin/max by channel mode ++ */ ++ cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN; ++ cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX; ++ ah->ah_aifs = AR5K_TUNE_AIFS; ++ /*XR is only supported on 5212*/ ++ if (IS_CHAN_XR(ah->ah_current_channel) && ++ ah->ah_version == AR5K_AR5212) { ++ cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_XR; ++ cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_XR; ++ ah->ah_aifs = AR5K_TUNE_AIFS_XR; ++ /*B mode is not supported on 5210*/ ++ } else if (IS_CHAN_B(ah->ah_current_channel) && ++ ah->ah_version != AR5K_AR5210) { ++ cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_11B; ++ cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_11B; ++ ah->ah_aifs = AR5K_TUNE_AIFS_11B; ++ } ++ ++ cw_min = 1; ++ while (cw_min < ah->ah_cw_min) ++ cw_min = (cw_min << 1) | 1; ++ ++ cw_min = tq->tqi_cw_min < 0 ? (cw_min >> (-tq->tqi_cw_min)) : ++ ((cw_min << tq->tqi_cw_min) + (1 << tq->tqi_cw_min) - 1); ++ cw_max = tq->tqi_cw_max < 0 ? (cw_max >> (-tq->tqi_cw_max)) : ++ ((cw_max << tq->tqi_cw_max) + (1 << tq->tqi_cw_max) - 1); ++ ++ /* ++ * Calculate and set retry limits ++ */ ++ if (ah->ah_software_retry == true) { ++ /* XXX Need to test this */ ++ retry_lg = ah->ah_limit_tx_retries; ++ retry_sh = retry_lg = retry_lg > AR5K_DCU_RETRY_LMT_SH_RETRY ? ++ AR5K_DCU_RETRY_LMT_SH_RETRY : retry_lg; ++ } else { ++ retry_lg = AR5K_INIT_LG_RETRY; ++ retry_sh = AR5K_INIT_SH_RETRY; ++ } ++ ++ /*No QCU/DCU [5210]*/ ++ if (ah->ah_version == AR5K_AR5210) { ++ ath5k_hw_reg_write(ah, ++ (cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S) ++ | AR5K_REG_SM(AR5K_INIT_SLG_RETRY, ++ AR5K_NODCU_RETRY_LMT_SLG_RETRY) ++ | AR5K_REG_SM(AR5K_INIT_SSH_RETRY, ++ AR5K_NODCU_RETRY_LMT_SSH_RETRY) ++ | AR5K_REG_SM(retry_lg, AR5K_NODCU_RETRY_LMT_LG_RETRY) ++ | AR5K_REG_SM(retry_sh, AR5K_NODCU_RETRY_LMT_SH_RETRY), ++ AR5K_NODCU_RETRY_LMT); ++ } else { ++ /*QCU/DCU [5211+]*/ ++ ath5k_hw_reg_write(ah, ++ AR5K_REG_SM(AR5K_INIT_SLG_RETRY, ++ AR5K_DCU_RETRY_LMT_SLG_RETRY) | ++ AR5K_REG_SM(AR5K_INIT_SSH_RETRY, ++ AR5K_DCU_RETRY_LMT_SSH_RETRY) | ++ AR5K_REG_SM(retry_lg, AR5K_DCU_RETRY_LMT_LG_RETRY) | ++ AR5K_REG_SM(retry_sh, AR5K_DCU_RETRY_LMT_SH_RETRY), ++ AR5K_QUEUE_DFS_RETRY_LIMIT(queue)); ++ ++ /*===Rest is also for QCU/DCU only [5211+]===*/ ++ ++ /* ++ * Set initial content window (cw_min/cw_max) ++ * and arbitrated interframe space (aifs)... ++ */ ++ ath5k_hw_reg_write(ah, ++ AR5K_REG_SM(cw_min, AR5K_DCU_LCL_IFS_CW_MIN) | ++ AR5K_REG_SM(cw_max, AR5K_DCU_LCL_IFS_CW_MAX) | ++ AR5K_REG_SM(ah->ah_aifs + tq->tqi_aifs, ++ AR5K_DCU_LCL_IFS_AIFS), ++ AR5K_QUEUE_DFS_LOCAL_IFS(queue)); ++ ++ /* ++ * Set misc registers ++ */ ++ ath5k_hw_reg_write(ah, AR5K_QCU_MISC_DCU_EARLY, ++ AR5K_QUEUE_MISC(queue)); ++ ++ if (tq->tqi_cbr_period) { ++ ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period, ++ AR5K_QCU_CBRCFG_INTVAL) | ++ AR5K_REG_SM(tq->tqi_cbr_overflow_limit, ++ AR5K_QCU_CBRCFG_ORN_THRES), ++ AR5K_QUEUE_CBRCFG(queue)); ++ AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), ++ AR5K_QCU_MISC_FRSHED_CBR); ++ if (tq->tqi_cbr_overflow_limit) ++ AR5K_REG_ENABLE_BITS(ah, ++ AR5K_QUEUE_MISC(queue), ++ AR5K_QCU_MISC_CBR_THRES_ENABLE); ++ } ++ ++ if (tq->tqi_ready_time) ++ ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time, ++ AR5K_QCU_RDYTIMECFG_INTVAL) | ++ AR5K_QCU_RDYTIMECFG_ENABLE, ++ AR5K_QUEUE_RDYTIMECFG(queue)); ++ ++ if (tq->tqi_burst_time) { ++ ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time, ++ AR5K_DCU_CHAN_TIME_DUR) | ++ AR5K_DCU_CHAN_TIME_ENABLE, ++ AR5K_QUEUE_DFS_CHANNEL_TIME(queue)); ++ ++ if (tq->tqi_flags & AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE) ++ AR5K_REG_ENABLE_BITS(ah, ++ AR5K_QUEUE_MISC(queue), ++ AR5K_QCU_MISC_TXE); ++ } ++ ++ if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE) ++ ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS, ++ AR5K_QUEUE_DFS_MISC(queue)); ++ ++ if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) ++ ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG, ++ AR5K_QUEUE_DFS_MISC(queue)); ++ ++ /* ++ * Set registers by queue type ++ */ ++ switch (tq->tqi_type) { ++ case AR5K_TX_QUEUE_BEACON: ++ AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), ++ AR5K_QCU_MISC_FRSHED_DBA_GT | ++ AR5K_QCU_MISC_CBREXP_BCN | ++ AR5K_QCU_MISC_BCN_ENABLE); ++ ++ AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), ++ (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL << ++ AR5K_DCU_MISC_ARBLOCK_CTL_S) | ++ AR5K_DCU_MISC_POST_FR_BKOFF_DIS | ++ AR5K_DCU_MISC_BCN_ENABLE); ++ ++ ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL - ++ (AR5K_TUNE_SW_BEACON_RESP - ++ AR5K_TUNE_DMA_BEACON_RESP) - ++ AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) | ++ AR5K_QCU_RDYTIMECFG_ENABLE, ++ AR5K_QUEUE_RDYTIMECFG(queue)); ++ break; ++ ++ case AR5K_TX_QUEUE_CAB: ++ AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), ++ AR5K_QCU_MISC_FRSHED_DBA_GT | ++ AR5K_QCU_MISC_CBREXP | ++ AR5K_QCU_MISC_CBREXP_BCN); ++ ++ AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), ++ (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL << ++ AR5K_DCU_MISC_ARBLOCK_CTL_S)); ++ break; ++ ++ case AR5K_TX_QUEUE_UAPSD: ++ AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), ++ AR5K_QCU_MISC_CBREXP); ++ break; ++ ++ case AR5K_TX_QUEUE_DATA: ++ default: ++ break; ++ } ++ ++ /* ++ * Enable interrupts for this tx queue ++ * in the secondary interrupt mask registers ++ */ ++ if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE) ++ AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue); ++ ++ if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE) ++ AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue); ++ ++ if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE) ++ AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue); ++ ++ if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE) ++ AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, queue); ++ ++ if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE) ++ AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue); ++ ++ ++ /* Update secondary interrupt mask registers */ ++ ah->ah_txq_imr_txok &= ah->ah_txq_status; ++ ah->ah_txq_imr_txerr &= ah->ah_txq_status; ++ ah->ah_txq_imr_txurn &= ah->ah_txq_status; ++ ah->ah_txq_imr_txdesc &= ah->ah_txq_status; ++ ah->ah_txq_imr_txeol &= ah->ah_txq_status; ++ ++ ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok, ++ AR5K_SIMR0_QCU_TXOK) | ++ AR5K_REG_SM(ah->ah_txq_imr_txdesc, ++ AR5K_SIMR0_QCU_TXDESC), AR5K_SIMR0); ++ ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr, ++ AR5K_SIMR1_QCU_TXERR) | ++ AR5K_REG_SM(ah->ah_txq_imr_txeol, ++ AR5K_SIMR1_QCU_TXEOL), AR5K_SIMR1); ++ ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txurn, ++ AR5K_SIMR2_QCU_TXURN), AR5K_SIMR2); ++ } ++ ++ return 0; ++} ++ ++/* ++ * Get number of pending frames ++ * for a specific queue [5211+] ++ */ ++u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue) { ++ ATH5K_TRACE(ah->ah_sc); ++ AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); ++ ++ /* Return if queue is declared inactive */ ++ if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) ++ return false; ++ ++ /* XXX: How about AR5K_CFG_TXCNT ? */ ++ if (ah->ah_version == AR5K_AR5210) ++ return false; ++ ++ return AR5K_QUEUE_STATUS(queue) & AR5K_QCU_STS_FRMPENDCNT; ++} ++ ++/* ++ * Set slot time ++ */ ++int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ if (slot_time < AR5K_SLOT_TIME_9 || slot_time > AR5K_SLOT_TIME_MAX) ++ return -EINVAL; ++ ++ if (ah->ah_version == AR5K_AR5210) ++ ath5k_hw_reg_write(ah, ath5k_hw_htoclock(slot_time, ++ ah->ah_turbo), AR5K_SLOT_TIME); ++ else ++ ath5k_hw_reg_write(ah, slot_time, AR5K_DCU_GBL_IFS_SLOT); ++ ++ return 0; ++} ++ ++/* ++ * Get slot time ++ */ ++unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ if (ah->ah_version == AR5K_AR5210) ++ return ath5k_hw_clocktoh(ath5k_hw_reg_read(ah, ++ AR5K_SLOT_TIME) & 0xffff, ah->ah_turbo); ++ else ++ return ath5k_hw_reg_read(ah, AR5K_DCU_GBL_IFS_SLOT) & 0xffff; ++} ++ ++ ++/******************************\ ++ Hardware Descriptor Functions ++\******************************/ ++ ++/* ++ * TX Descriptor ++ */ ++ ++/* ++ * Initialize the 2-word tx descriptor on 5210/5211 ++ */ ++static int ++ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, ++ unsigned int pkt_len, unsigned int hdr_len, enum ath5k_pkt_type type, ++ unsigned int tx_power, unsigned int tx_rate0, unsigned int tx_tries0, ++ unsigned int key_index, unsigned int antenna_mode, unsigned int flags, ++ unsigned int rtscts_rate, unsigned int rtscts_duration) ++{ ++ u32 frame_type; ++ struct ath5k_hw_2w_tx_desc *tx_desc; ++ unsigned int buff_len; ++ ++ tx_desc = (struct ath5k_hw_2w_tx_desc *)&desc->ds_ctl0; ++ ++ /* ++ * Validate input ++ * - Zero retries don't make sense. ++ * - A zero rate will put the HW into a mode where it continously sends ++ * noise on the channel, so it is important to avoid this. ++ */ ++ if (unlikely(tx_tries0 == 0)) { ++ ATH5K_ERR(ah->ah_sc, "zero retries\n"); ++ WARN_ON(1); ++ return -EINVAL; ++ } ++ if (unlikely(tx_rate0 == 0)) { ++ ATH5K_ERR(ah->ah_sc, "zero rate\n"); ++ WARN_ON(1); ++ return -EINVAL; ++ } ++ ++ /* Clear status descriptor */ ++ memset(desc->ds_hw, 0, sizeof(struct ath5k_hw_tx_status)); ++ ++ /* Initialize control descriptor */ ++ tx_desc->tx_control_0 = 0; ++ tx_desc->tx_control_1 = 0; ++ ++ /* Setup control descriptor */ ++ ++ /* Verify and set frame length */ ++ if (pkt_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN) ++ return -EINVAL; ++ ++ tx_desc->tx_control_0 = pkt_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN; ++ ++ /* Verify and set buffer length */ ++ buff_len = pkt_len - FCS_LEN; ++ ++ /* NB: beacon's BufLen must be a multiple of 4 bytes */ ++ if(type == AR5K_PKT_TYPE_BEACON) ++ buff_len = roundup(buff_len, 4); ++ ++ if (buff_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN) ++ return -EINVAL; ++ ++ tx_desc->tx_control_1 = buff_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN; ++ ++ /* ++ * Verify and set header length ++ * XXX: I only found that on 5210 code, does it work on 5211 ? ++ */ ++ if (ah->ah_version == AR5K_AR5210) { ++ if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN) ++ return -EINVAL; ++ tx_desc->tx_control_0 |= ++ AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN); ++ } ++ ++ /*Diferences between 5210-5211*/ ++ if (ah->ah_version == AR5K_AR5210) { ++ switch (type) { ++ case AR5K_PKT_TYPE_BEACON: ++ case AR5K_PKT_TYPE_PROBE_RESP: ++ frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY; ++ case AR5K_PKT_TYPE_PIFS: ++ frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS; ++ default: ++ frame_type = type /*<< 2 ?*/; ++ } ++ ++ tx_desc->tx_control_0 |= ++ AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE) | ++ AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE); ++ } else { ++ tx_desc->tx_control_0 |= ++ AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE) | ++ AR5K_REG_SM(antenna_mode, AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT); ++ tx_desc->tx_control_1 |= ++ AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE); ++ } ++#define _TX_FLAGS(_c, _flag) \ ++ if (flags & AR5K_TXDESC_##_flag) \ ++ tx_desc->tx_control_##_c |= \ ++ AR5K_2W_TX_DESC_CTL##_c##_##_flag ++ ++ _TX_FLAGS(0, CLRDMASK); ++ _TX_FLAGS(0, VEOL); ++ _TX_FLAGS(0, INTREQ); ++ _TX_FLAGS(0, RTSENA); ++ _TX_FLAGS(1, NOACK); ++ ++#undef _TX_FLAGS ++ ++ /* ++ * WEP crap ++ */ ++ if (key_index != AR5K_TXKEYIX_INVALID) { ++ tx_desc->tx_control_0 |= ++ AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; ++ tx_desc->tx_control_1 |= ++ AR5K_REG_SM(key_index, ++ AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX); ++ } ++ ++ /* ++ * RTS/CTS Duration [5210 ?] ++ */ ++ if ((ah->ah_version == AR5K_AR5210) && ++ (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA))) ++ tx_desc->tx_control_1 |= rtscts_duration & ++ AR5K_2W_TX_DESC_CTL1_RTS_DURATION; ++ ++ return 0; ++} ++ ++/* ++ * Initialize the 4-word tx descriptor on 5212 ++ */ ++static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, ++ struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len, ++ enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0, ++ unsigned int tx_tries0, unsigned int key_index, ++ unsigned int antenna_mode, unsigned int flags, unsigned int rtscts_rate, ++ unsigned int rtscts_duration) ++{ ++ struct ath5k_hw_4w_tx_desc *tx_desc; ++ struct ath5k_hw_tx_status *tx_status; ++ unsigned int buff_len; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ tx_desc = (struct ath5k_hw_4w_tx_desc *)&desc->ds_ctl0; ++ tx_status = (struct ath5k_hw_tx_status *)&desc->ds_hw[2]; ++ ++ /* ++ * Validate input ++ * - Zero retries don't make sense. ++ * - A zero rate will put the HW into a mode where it continously sends ++ * noise on the channel, so it is important to avoid this. ++ */ ++ if (unlikely(tx_tries0 == 0)) { ++ ATH5K_ERR(ah->ah_sc, "zero retries\n"); ++ WARN_ON(1); ++ return -EINVAL; ++ } ++ if (unlikely(tx_rate0 == 0)) { ++ ATH5K_ERR(ah->ah_sc, "zero rate\n"); ++ WARN_ON(1); ++ return -EINVAL; ++ } ++ ++ /* Clear status descriptor */ ++ memset(tx_status, 0, sizeof(struct ath5k_hw_tx_status)); ++ ++ /* Initialize control descriptor */ ++ tx_desc->tx_control_0 = 0; ++ tx_desc->tx_control_1 = 0; ++ tx_desc->tx_control_2 = 0; ++ tx_desc->tx_control_3 = 0; ++ ++ /* Setup control descriptor */ ++ ++ /* Verify and set frame length */ ++ if (pkt_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN) ++ return -EINVAL; ++ ++ tx_desc->tx_control_0 = pkt_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN; ++ ++ /* Verify and set buffer length */ ++ buff_len = pkt_len - FCS_LEN; ++ ++ /* NB: beacon's BufLen must be a multiple of 4 bytes */ ++ if(type == AR5K_PKT_TYPE_BEACON) ++ buff_len = roundup(buff_len, 4); ++ ++ if (buff_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN) ++ return -EINVAL; ++ ++ tx_desc->tx_control_1 = buff_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN; ++ ++ tx_desc->tx_control_0 |= ++ AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) | ++ AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT); ++ tx_desc->tx_control_1 |= AR5K_REG_SM(type, ++ AR5K_4W_TX_DESC_CTL1_FRAME_TYPE); ++ tx_desc->tx_control_2 = AR5K_REG_SM(tx_tries0 + AR5K_TUNE_HWTXTRIES, ++ AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0); ++ tx_desc->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; ++ ++#define _TX_FLAGS(_c, _flag) \ ++ if (flags & AR5K_TXDESC_##_flag) \ ++ tx_desc->tx_control_##_c |= \ ++ AR5K_4W_TX_DESC_CTL##_c##_##_flag ++ ++ _TX_FLAGS(0, CLRDMASK); ++ _TX_FLAGS(0, VEOL); ++ _TX_FLAGS(0, INTREQ); ++ _TX_FLAGS(0, RTSENA); ++ _TX_FLAGS(0, CTSENA); ++ _TX_FLAGS(1, NOACK); ++ ++#undef _TX_FLAGS ++ ++ /* ++ * WEP crap ++ */ ++ if (key_index != AR5K_TXKEYIX_INVALID) { ++ tx_desc->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; ++ tx_desc->tx_control_1 |= AR5K_REG_SM(key_index, ++ AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX); ++ } ++ ++ /* ++ * RTS/CTS ++ */ ++ if (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)) { ++ if ((flags & AR5K_TXDESC_RTSENA) && ++ (flags & AR5K_TXDESC_CTSENA)) ++ return -EINVAL; ++ tx_desc->tx_control_2 |= rtscts_duration & ++ AR5K_4W_TX_DESC_CTL2_RTS_DURATION; ++ tx_desc->tx_control_3 |= AR5K_REG_SM(rtscts_rate, ++ AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE); ++ } ++ ++ return 0; ++} ++ ++/* ++ * Initialize a 4-word multirate tx descriptor on 5212 ++ */ ++static bool ++ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, ++ unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2, u_int tx_tries2, ++ unsigned int tx_rate3, u_int tx_tries3) ++{ ++ struct ath5k_hw_4w_tx_desc *tx_desc; ++ ++ /* ++ * Rates can be 0 as long as the retry count is 0 too. ++ * A zero rate and nonzero retry count will put the HW into a mode where ++ * it continously sends noise on the channel, so it is important to ++ * avoid this. ++ */ ++ if (unlikely((tx_rate1 == 0 && tx_tries1 != 0) || ++ (tx_rate2 == 0 && tx_tries2 != 0) || ++ (tx_rate3 == 0 && tx_tries3 != 0))) { ++ ATH5K_ERR(ah->ah_sc, "zero rate\n"); ++ WARN_ON(1); ++ return -EINVAL; ++ } ++ ++ if (ah->ah_version == AR5K_AR5212) { ++ tx_desc = (struct ath5k_hw_4w_tx_desc *)&desc->ds_ctl0; ++ ++#define _XTX_TRIES(_n) \ ++ if (tx_tries##_n) { \ ++ tx_desc->tx_control_2 |= \ ++ AR5K_REG_SM(tx_tries##_n, \ ++ AR5K_4W_TX_DESC_CTL2_XMIT_TRIES##_n); \ ++ tx_desc->tx_control_3 |= \ ++ AR5K_REG_SM(tx_rate##_n, \ ++ AR5K_4W_TX_DESC_CTL3_XMIT_RATE##_n); \ ++ } ++ ++ _XTX_TRIES(1); ++ _XTX_TRIES(2); ++ _XTX_TRIES(3); ++ ++#undef _XTX_TRIES ++ ++ return true; ++ } ++ ++ return false; ++} ++ ++/* ++ * Proccess the tx status descriptor on 5210/5211 ++ */ ++static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, ++ struct ath5k_desc *desc) ++{ ++ struct ath5k_hw_tx_status *tx_status; ++ struct ath5k_hw_2w_tx_desc *tx_desc; ++ ++ tx_desc = (struct ath5k_hw_2w_tx_desc *)&desc->ds_ctl0; ++ tx_status = (struct ath5k_hw_tx_status *)&desc->ds_hw[0]; ++ ++ /* No frame has been send or error */ ++ if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0)) ++ return -EINPROGRESS; ++ ++ /* ++ * Get descriptor status ++ */ ++ desc->ds_us.tx.ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0, ++ AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); ++ desc->ds_us.tx.ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, ++ AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); ++ desc->ds_us.tx.ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, ++ AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); ++ /*TODO: desc->ds_us.tx.ts_virtcol + test*/ ++ desc->ds_us.tx.ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, ++ AR5K_DESC_TX_STATUS1_SEQ_NUM); ++ desc->ds_us.tx.ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, ++ AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); ++ desc->ds_us.tx.ts_antenna = 1; ++ desc->ds_us.tx.ts_status = 0; ++ desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_0, ++ AR5K_2W_TX_DESC_CTL0_XMIT_RATE); ++ ++ if ((tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK) == 0){ ++ if (tx_status->tx_status_0 & ++ AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) ++ desc->ds_us.tx.ts_status |= AR5K_TXERR_XRETRY; ++ ++ if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) ++ desc->ds_us.tx.ts_status |= AR5K_TXERR_FIFO; ++ ++ if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED) ++ desc->ds_us.tx.ts_status |= AR5K_TXERR_FILT; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Proccess a tx descriptor on 5212 ++ */ ++static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, ++ struct ath5k_desc *desc) ++{ ++ struct ath5k_hw_tx_status *tx_status; ++ struct ath5k_hw_4w_tx_desc *tx_desc; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ tx_desc = (struct ath5k_hw_4w_tx_desc *)&desc->ds_ctl0; ++ tx_status = (struct ath5k_hw_tx_status *)&desc->ds_hw[2]; ++ ++ /* No frame has been send or error */ ++ if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0)) ++ return -EINPROGRESS; ++ ++ /* ++ * Get descriptor status ++ */ ++ desc->ds_us.tx.ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0, ++ AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); ++ desc->ds_us.tx.ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, ++ AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); ++ desc->ds_us.tx.ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, ++ AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); ++ desc->ds_us.tx.ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, ++ AR5K_DESC_TX_STATUS1_SEQ_NUM); ++ desc->ds_us.tx.ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, ++ AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); ++ desc->ds_us.tx.ts_antenna = (tx_status->tx_status_1 & ++ AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1; ++ desc->ds_us.tx.ts_status = 0; ++ ++ switch (AR5K_REG_MS(tx_status->tx_status_1, ++ AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX)) { ++ case 0: ++ desc->ds_us.tx.ts_rate = tx_desc->tx_control_3 & ++ AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; ++ break; ++ case 1: ++ desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_3, ++ AR5K_4W_TX_DESC_CTL3_XMIT_RATE1); ++ desc->ds_us.tx.ts_longretry +=AR5K_REG_MS(tx_desc->tx_control_2, ++ AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); ++ break; ++ case 2: ++ desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_3, ++ AR5K_4W_TX_DESC_CTL3_XMIT_RATE2); ++ desc->ds_us.tx.ts_longretry +=AR5K_REG_MS(tx_desc->tx_control_2, ++ AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2); ++ break; ++ case 3: ++ desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_3, ++ AR5K_4W_TX_DESC_CTL3_XMIT_RATE3); ++ desc->ds_us.tx.ts_longretry +=AR5K_REG_MS(tx_desc->tx_control_2, ++ AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3); ++ break; ++ } ++ ++ if ((tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK) == 0){ ++ if (tx_status->tx_status_0 & ++ AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) ++ desc->ds_us.tx.ts_status |= AR5K_TXERR_XRETRY; ++ ++ if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) ++ desc->ds_us.tx.ts_status |= AR5K_TXERR_FIFO; ++ ++ if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED) ++ desc->ds_us.tx.ts_status |= AR5K_TXERR_FILT; ++ } ++ ++ return 0; ++} ++ ++/* ++ * RX Descriptor ++ */ ++ ++/* ++ * Initialize an rx descriptor ++ */ ++int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, ++ u32 size, unsigned int flags) ++{ ++ struct ath5k_rx_desc *rx_desc; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ rx_desc = (struct ath5k_rx_desc *)&desc->ds_ctl0; ++ ++ /* ++ *Clear ds_hw ++ * If we don't clean the status descriptor, ++ * while scanning we get too many results, ++ * most of them virtual, after some secs ++ * of scanning system hangs. M.F. ++ */ ++ memset(desc->ds_hw, 0, sizeof(desc->ds_hw)); ++ ++ /*Initialize rx descriptor*/ ++ rx_desc->rx_control_0 = 0; ++ rx_desc->rx_control_1 = 0; ++ ++ /* Setup descriptor */ ++ rx_desc->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN; ++ if (unlikely(rx_desc->rx_control_1 != size)) ++ return -EINVAL; ++ ++ if (flags & AR5K_RXDESC_INTREQ) ++ rx_desc->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ; ++ ++ return 0; ++} ++ ++/* ++ * Proccess the rx status descriptor on 5210/5211 ++ */ ++static int ath5k_hw_proc_old_rx_status(struct ath5k_hw *ah, ++ struct ath5k_desc *desc) ++{ ++ struct ath5k_hw_old_rx_status *rx_status; ++ ++ rx_status = (struct ath5k_hw_old_rx_status *)&desc->ds_hw[0]; ++ ++ /* No frame received / not ready */ ++ if (unlikely((rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_DONE) ++ == 0)) ++ return -EINPROGRESS; ++ ++ /* ++ * Frame receive status ++ */ ++ desc->ds_us.rx.rs_datalen = rx_status->rx_status_0 & ++ AR5K_OLD_RX_DESC_STATUS0_DATA_LEN; ++ desc->ds_us.rx.rs_rssi = AR5K_REG_MS(rx_status->rx_status_0, ++ AR5K_OLD_RX_DESC_STATUS0_RECEIVE_SIGNAL); ++ desc->ds_us.rx.rs_rate = AR5K_REG_MS(rx_status->rx_status_0, ++ AR5K_OLD_RX_DESC_STATUS0_RECEIVE_RATE); ++ desc->ds_us.rx.rs_antenna = rx_status->rx_status_0 & ++ AR5K_OLD_RX_DESC_STATUS0_RECEIVE_ANTENNA; ++ desc->ds_us.rx.rs_more = rx_status->rx_status_0 & ++ AR5K_OLD_RX_DESC_STATUS0_MORE; ++ desc->ds_us.rx.rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, ++ AR5K_OLD_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); ++ desc->ds_us.rx.rs_status = 0; ++ ++ /* ++ * Key table status ++ */ ++ if (rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX_VALID) ++ desc->ds_us.rx.rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, ++ AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX); ++ else ++ desc->ds_us.rx.rs_keyix = AR5K_RXKEYIX_INVALID; ++ ++ /* ++ * Receive/descriptor errors ++ */ ++ if ((rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_FRAME_RECEIVE_OK) ++ == 0) { ++ if (rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_CRC_ERROR) ++ desc->ds_us.rx.rs_status |= AR5K_RXERR_CRC; ++ ++ if (rx_status->rx_status_1 & ++ AR5K_OLD_RX_DESC_STATUS1_FIFO_OVERRUN) ++ desc->ds_us.rx.rs_status |= AR5K_RXERR_FIFO; ++ ++ if (rx_status->rx_status_1 & ++ AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR) { ++ desc->ds_us.rx.rs_status |= AR5K_RXERR_PHY; ++ desc->ds_us.rx.rs_phyerr = ++ AR5K_REG_MS(rx_status->rx_status_1, ++ AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR); ++ } ++ ++ if (rx_status->rx_status_1 & ++ AR5K_OLD_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) ++ desc->ds_us.rx.rs_status |= AR5K_RXERR_DECRYPT; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Proccess the rx status descriptor on 5212 ++ */ ++static int ath5k_hw_proc_new_rx_status(struct ath5k_hw *ah, ++ struct ath5k_desc *desc) ++{ ++ struct ath5k_hw_new_rx_status *rx_status; ++ struct ath5k_hw_rx_error *rx_err; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ rx_status = (struct ath5k_hw_new_rx_status *)&desc->ds_hw[0]; ++ ++ /* Overlay on error */ ++ rx_err = (struct ath5k_hw_rx_error *)&desc->ds_hw[0]; ++ ++ /* No frame received / not ready */ ++ if (unlikely((rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_DONE) ++ == 0)) ++ return -EINPROGRESS; ++ ++ /* ++ * Frame receive status ++ */ ++ desc->ds_us.rx.rs_datalen = rx_status->rx_status_0 & ++ AR5K_NEW_RX_DESC_STATUS0_DATA_LEN; ++ desc->ds_us.rx.rs_rssi = AR5K_REG_MS(rx_status->rx_status_0, ++ AR5K_NEW_RX_DESC_STATUS0_RECEIVE_SIGNAL); ++ desc->ds_us.rx.rs_rate = AR5K_REG_MS(rx_status->rx_status_0, ++ AR5K_NEW_RX_DESC_STATUS0_RECEIVE_RATE); ++ desc->ds_us.rx.rs_antenna = rx_status->rx_status_0 & ++ AR5K_NEW_RX_DESC_STATUS0_RECEIVE_ANTENNA; ++ desc->ds_us.rx.rs_more = rx_status->rx_status_0 & ++ AR5K_NEW_RX_DESC_STATUS0_MORE; ++ desc->ds_us.rx.rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, ++ AR5K_NEW_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); ++ desc->ds_us.rx.rs_status = 0; ++ ++ /* ++ * Key table status ++ */ ++ if (rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX_VALID) ++ desc->ds_us.rx.rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, ++ AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX); ++ else ++ desc->ds_us.rx.rs_keyix = AR5K_RXKEYIX_INVALID; ++ ++ /* ++ * Receive/descriptor errors ++ */ ++ if ((rx_status->rx_status_1 & ++ AR5K_NEW_RX_DESC_STATUS1_FRAME_RECEIVE_OK) == 0) { ++ if (rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_CRC_ERROR) ++ desc->ds_us.rx.rs_status |= AR5K_RXERR_CRC; ++ ++ if (rx_status->rx_status_1 & ++ AR5K_NEW_RX_DESC_STATUS1_PHY_ERROR) { ++ desc->ds_us.rx.rs_status |= AR5K_RXERR_PHY; ++ desc->ds_us.rx.rs_phyerr = ++ AR5K_REG_MS(rx_err->rx_error_1, ++ AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE); ++ } ++ ++ if (rx_status->rx_status_1 & ++ AR5K_NEW_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) ++ desc->ds_us.rx.rs_status |= AR5K_RXERR_DECRYPT; ++ ++ if (rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_MIC_ERROR) ++ desc->ds_us.rx.rs_status |= AR5K_RXERR_MIC; ++ } ++ ++ return 0; ++} ++ ++ ++/****************\ ++ GPIO Functions ++\****************/ ++ ++/* ++ * Set led state ++ */ ++void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state) ++{ ++ u32 led; ++ /*5210 has different led mode handling*/ ++ u32 led_5210; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ ++ /*Reset led status*/ ++ if (ah->ah_version != AR5K_AR5210) ++ AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG, ++ AR5K_PCICFG_LEDMODE | AR5K_PCICFG_LED); ++ else ++ AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_LED); ++ ++ /* ++ * Some blinking values, define at your wish ++ */ ++ switch (state) { ++ case AR5K_LED_SCAN: ++ case AR5K_LED_AUTH: ++ led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_PEND; ++ led_5210 = AR5K_PCICFG_LED_PEND | AR5K_PCICFG_LED_BCTL; ++ break; ++ ++ case AR5K_LED_INIT: ++ led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_NONE; ++ led_5210 = AR5K_PCICFG_LED_PEND; ++ break; ++ ++ case AR5K_LED_ASSOC: ++ case AR5K_LED_RUN: ++ led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_ASSOC; ++ led_5210 = AR5K_PCICFG_LED_ASSOC; ++ break; ++ ++ default: ++ led = AR5K_PCICFG_LEDMODE_PROM | AR5K_PCICFG_LED_NONE; ++ led_5210 = AR5K_PCICFG_LED_PEND; ++ break; ++ } ++ ++ /*Write new status to the register*/ ++ if (ah->ah_version != AR5K_AR5210) ++ AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led); ++ else ++ AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led_5210); ++} ++ ++/* ++ * Set GPIO outputs ++ */ ++int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ if (gpio > AR5K_NUM_GPIO) ++ return -EINVAL; ++ ++ ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_GPIOCR) &~ ++ AR5K_GPIOCR_OUT(gpio)) | AR5K_GPIOCR_OUT(gpio), AR5K_GPIOCR); ++ ++ return 0; ++} ++ ++/* ++ * Set GPIO inputs ++ */ ++int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ if (gpio > AR5K_NUM_GPIO) ++ return -EINVAL; ++ ++ ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_GPIOCR) &~ ++ AR5K_GPIOCR_OUT(gpio)) | AR5K_GPIOCR_IN(gpio), AR5K_GPIOCR); ++ ++ return 0; ++} ++ ++/* ++ * Get GPIO state ++ */ ++u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ if (gpio > AR5K_NUM_GPIO) ++ return 0xffffffff; ++ ++ /* GPIO input magic */ ++ return ((ath5k_hw_reg_read(ah, AR5K_GPIODI) & AR5K_GPIODI_M) >> gpio) & ++ 0x1; ++} ++ ++/* ++ * Set GPIO state ++ */ ++int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val) ++{ ++ u32 data; ++ ATH5K_TRACE(ah->ah_sc); ++ ++ if (gpio > AR5K_NUM_GPIO) ++ return -EINVAL; ++ ++ /* GPIO output magic */ ++ data = ath5k_hw_reg_read(ah, AR5K_GPIODO); ++ ++ data &= ~(1 << gpio); ++ data |= (val & 1) << gpio; ++ ++ ath5k_hw_reg_write(ah, data, AR5K_GPIODO); ++ ++ return 0; ++} ++ ++/* ++ * Initialize the GPIO interrupt (RFKill switch) ++ */ ++void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, ++ u32 interrupt_level) ++{ ++ u32 data; ++ ++ ATH5K_TRACE(ah->ah_sc); ++ if (gpio > AR5K_NUM_GPIO) ++ return; ++ ++ /* ++ * Set the GPIO interrupt ++ */ ++ data = (ath5k_hw_reg_read(ah, AR5K_GPIOCR) & ++ ~(AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_SELH | ++ AR5K_GPIOCR_INT_ENA | AR5K_GPIOCR_OUT(gpio))) | ++ (AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_ENA); ++ ++ ath5k_hw_reg_write(ah, interrupt_level ? data : ++ (data | AR5K_GPIOCR_INT_SELH), AR5K_GPIOCR); ++ ++ ah->ah_imr |= AR5K_IMR_GPIO; ++ ++ /* Enable GPIO interrupts */ ++ AR5K_REG_ENABLE_BITS(ah, AR5K_PIMR, AR5K_IMR_GPIO); ++} ++ ++ ++/*********************************\ ++ Regulatory Domain/Channels Setup ++\*********************************/ ++ ++u16 ath5k_get_regdomain(struct ath5k_hw *ah) ++{ ++ u16 regdomain; ++ enum ath5k_regdom ieee_regdomain; ++#ifdef COUNTRYCODE ++ u16 code; ++#endif ++ ++ ath5k_eeprom_regulation_domain(ah, false, &ieee_regdomain); ++ ah->ah_capabilities.cap_regdomain.reg_hw = ieee_regdomain; ++ ++#ifdef COUNTRYCODE ++ /* ++ * Get the regulation domain by country code. This will ignore ++ * the settings found in the EEPROM. ++ */ ++ code = ieee80211_name2countrycode(COUNTRYCODE); ++ ieee_regdomain = ieee80211_countrycode2regdomain(code); ++#endif ++ ++ regdomain = ath5k_regdom_from_ieee(ieee_regdomain); ++ ah->ah_capabilities.cap_regdomain.reg_current = regdomain; ++ ++ return regdomain; ++} ++ ++ ++/****************\ ++ Misc functions ++\****************/ ++ ++int ath5k_hw_get_capability(struct ath5k_hw *ah, ++ enum ath5k_capability_type cap_type, ++ u32 capability, u32 *result) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ ++ switch (cap_type) { ++ case AR5K_CAP_NUM_TXQUEUES: ++ if (result) { ++ if (ah->ah_version == AR5K_AR5210) ++ *result = AR5K_NUM_TX_QUEUES_NOQCU; ++ else ++ *result = AR5K_NUM_TX_QUEUES; ++ goto yes; ++ } ++ case AR5K_CAP_VEOL: ++ goto yes; ++ case AR5K_CAP_COMPRESSION: ++ if (ah->ah_version == AR5K_AR5212) ++ goto yes; ++ else ++ goto no; ++ case AR5K_CAP_BURST: ++ goto yes; ++ case AR5K_CAP_TPC: ++ goto yes; ++ case AR5K_CAP_BSSIDMASK: ++ if (ah->ah_version == AR5K_AR5212) ++ goto yes; ++ else ++ goto no; ++ case AR5K_CAP_XR: ++ if (ah->ah_version == AR5K_AR5212) ++ goto yes; ++ else ++ goto no; ++ default: ++ goto no; ++ } ++ ++no: ++ return -EINVAL; ++yes: ++ return 0; ++} ++ ++static int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid, ++ u16 assoc_id) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ ++ if (ah->ah_version == AR5K_AR5210) { ++ AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, ++ AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA); ++ return 0; ++ } ++ ++ return -EIO; ++} ++ ++static int ath5k_hw_disable_pspoll(struct ath5k_hw *ah) ++{ ++ ATH5K_TRACE(ah->ah_sc); ++ ++ if (ah->ah_version == AR5K_AR5210) { ++ AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, ++ AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA); ++ return 0; ++ } ++ ++ return -EIO; ++} +diff -up /dev/null linux-2.6.23.noarch/drivers/net/wireless/ath5k/hw.h +--- /dev/null 2007-12-21 08:33:07.834165456 -0500 ++++ linux-2.6.23.noarch/drivers/net/wireless/ath5k/hw.h 2007-12-21 12:18:50.000000000 -0500 +@@ -0,0 +1,588 @@ ++/* ++ * Copyright (c) 2004-2007 Reyk Floeter ++ * Copyright (c) 2006-2007 Nick Kossifidis ++ * Copyright (c) 2007 Matthew W. S. Bell ++ * Copyright (c) 2007 Luis Rodriguez ++ * ++ * Permission to use, copy, modify, and 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 ++ ++/* ++ * Gain settings ++ */ ++ ++enum ath5k_rfgain { ++ AR5K_RFGAIN_INACTIVE = 0, ++ AR5K_RFGAIN_READ_REQUESTED, ++ AR5K_RFGAIN_NEED_CHANGE, ++}; ++ ++#define AR5K_GAIN_CRN_FIX_BITS_5111 4 ++#define AR5K_GAIN_CRN_FIX_BITS_5112 7 ++#define AR5K_GAIN_CRN_MAX_FIX_BITS AR5K_GAIN_CRN_FIX_BITS_5112 ++#define AR5K_GAIN_DYN_ADJUST_HI_MARGIN 15 ++#define AR5K_GAIN_DYN_ADJUST_LO_MARGIN 20 ++#define AR5K_GAIN_CCK_PROBE_CORR 5 ++#define AR5K_GAIN_CCK_OFDM_GAIN_DELTA 15 ++#define AR5K_GAIN_STEP_COUNT 10 ++#define AR5K_GAIN_PARAM_TX_CLIP 0 ++#define AR5K_GAIN_PARAM_PD_90 1 ++#define AR5K_GAIN_PARAM_PD_84 2 ++#define AR5K_GAIN_PARAM_GAIN_SEL 3 ++#define AR5K_GAIN_PARAM_MIX_ORN 0 ++#define AR5K_GAIN_PARAM_PD_138 1 ++#define AR5K_GAIN_PARAM_PD_137 2 ++#define AR5K_GAIN_PARAM_PD_136 3 ++#define AR5K_GAIN_PARAM_PD_132 4 ++#define AR5K_GAIN_PARAM_PD_131 5 ++#define AR5K_GAIN_PARAM_PD_130 6 ++#define AR5K_GAIN_CHECK_ADJUST(_g) \ ++ ((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high) ++ ++struct ath5k_gain_opt_step { ++ s16 gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS]; ++ s32 gos_gain; ++}; ++ ++struct ath5k_gain { ++ u32 g_step_idx; ++ u32 g_current; ++ u32 g_target; ++ u32 g_low; ++ u32 g_high; ++ u32 g_f_corr; ++ u32 g_active; ++ const struct ath5k_gain_opt_step *g_step; ++}; ++ ++ ++/* ++ * HW SPECIFIC STRUCTS ++ */ ++ ++/* Some EEPROM defines */ ++#define AR5K_EEPROM_EEP_SCALE 100 ++#define AR5K_EEPROM_EEP_DELTA 10 ++#define AR5K_EEPROM_N_MODES 3 ++#define AR5K_EEPROM_N_5GHZ_CHAN 10 ++#define AR5K_EEPROM_N_2GHZ_CHAN 3 ++#define AR5K_EEPROM_MAX_CHAN 10 ++#define AR5K_EEPROM_N_PCDAC 11 ++#define AR5K_EEPROM_N_TEST_FREQ 8 ++#define AR5K_EEPROM_N_EDGES 8 ++#define AR5K_EEPROM_N_INTERCEPTS 11 ++#define AR5K_EEPROM_FREQ_M(_v) AR5K_EEPROM_OFF(_v, 0x7f, 0xff) ++#define AR5K_EEPROM_PCDAC_M 0x3f ++#define AR5K_EEPROM_PCDAC_START 1 ++#define AR5K_EEPROM_PCDAC_STOP 63 ++#define AR5K_EEPROM_PCDAC_STEP 1 ++#define AR5K_EEPROM_NON_EDGE_M 0x40 ++#define AR5K_EEPROM_CHANNEL_POWER 8 ++#define AR5K_EEPROM_N_OBDB 4 ++#define AR5K_EEPROM_OBDB_DIS 0xffff ++#define AR5K_EEPROM_CHANNEL_DIS 0xff ++#define AR5K_EEPROM_SCALE_OC_DELTA(_x) (((_x) * 2) / 10) ++#define AR5K_EEPROM_N_CTLS(_v) AR5K_EEPROM_OFF(_v, 16, 32) ++#define AR5K_EEPROM_MAX_CTLS 32 ++#define AR5K_EEPROM_N_XPD_PER_CHANNEL 4 ++#define AR5K_EEPROM_N_XPD0_POINTS 4 ++#define AR5K_EEPROM_N_XPD3_POINTS 3 ++#define AR5K_EEPROM_N_INTERCEPT_10_2GHZ 35 ++#define AR5K_EEPROM_N_INTERCEPT_10_5GHZ 55 ++#define AR5K_EEPROM_POWER_M 0x3f ++#define AR5K_EEPROM_POWER_MIN 0 ++#define AR5K_EEPROM_POWER_MAX 3150 ++#define AR5K_EEPROM_POWER_STEP 50 ++#define AR5K_EEPROM_POWER_TABLE_SIZE 64 ++#define AR5K_EEPROM_N_POWER_LOC_11B 4 ++#define AR5K_EEPROM_N_POWER_LOC_11G 6 ++#define AR5K_EEPROM_I_GAIN 10 ++#define AR5K_EEPROM_CCK_OFDM_DELTA 15 ++#define AR5K_EEPROM_N_IQ_CAL 2 ++ ++/* Struct to hold EEPROM calibration data */ ++struct ath5k_eeprom_info { ++ u16 ee_magic; ++ u16 ee_protect; ++ u16 ee_regdomain; ++ u16 ee_version; ++ u16 ee_header; ++ u16 ee_ant_gain; ++ u16 ee_misc0; ++ u16 ee_misc1; ++ u16 ee_cck_ofdm_gain_delta; ++ u16 ee_cck_ofdm_power_delta; ++ u16 ee_scaled_cck_delta; ++ ++ /* Used for tx thermal adjustment (eeprom_init, rfregs) */ ++ u16 ee_tx_clip; ++ u16 ee_pwd_84; ++ u16 ee_pwd_90; ++ u16 ee_gain_select; ++ ++ /* RF Calibration settings (reset, rfregs) */ ++ u16 ee_i_cal[AR5K_EEPROM_N_MODES]; ++ u16 ee_q_cal[AR5K_EEPROM_N_MODES]; ++ u16 ee_fixed_bias[AR5K_EEPROM_N_MODES]; ++ u16 ee_turbo_max_power[AR5K_EEPROM_N_MODES]; ++ u16 ee_xr_power[AR5K_EEPROM_N_MODES]; ++ u16 ee_switch_settling[AR5K_EEPROM_N_MODES]; ++ u16 ee_ant_tx_rx[AR5K_EEPROM_N_MODES]; ++ u16 ee_ant_control[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PCDAC]; ++ u16 ee_ob[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB]; ++ u16 ee_db[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB]; ++ u16 ee_tx_end2xlna_enable[AR5K_EEPROM_N_MODES]; ++ u16 ee_tx_end2xpa_disable[AR5K_EEPROM_N_MODES]; ++ u16 ee_tx_frm2xpa_enable[AR5K_EEPROM_N_MODES]; ++ u16 ee_thr_62[AR5K_EEPROM_N_MODES]; ++ u16 ee_xlna_gain[AR5K_EEPROM_N_MODES]; ++ u16 ee_xpd[AR5K_EEPROM_N_MODES]; ++ u16 ee_x_gain[AR5K_EEPROM_N_MODES]; ++ u16 ee_i_gain[AR5K_EEPROM_N_MODES]; ++ u16 ee_margin_tx_rx[AR5K_EEPROM_N_MODES]; ++ ++ /* Unused */ ++ u16 ee_false_detect[AR5K_EEPROM_N_MODES]; ++ u16 ee_cal_pier[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_2GHZ_CHAN]; ++ u16 ee_channel[AR5K_EEPROM_N_MODES][AR5K_EEPROM_MAX_CHAN]; /*empty*/ ++ ++ /* Conformance test limits (Unused) */ ++ u16 ee_ctls; ++ u16 ee_ctl[AR5K_EEPROM_MAX_CTLS]; ++ ++ /* Noise Floor Calibration settings */ ++ s16 ee_noise_floor_thr[AR5K_EEPROM_N_MODES]; ++ s8 ee_adc_desired_size[AR5K_EEPROM_N_MODES]; ++ s8 ee_pga_desired_size[AR5K_EEPROM_N_MODES]; ++}; ++ ++/* ++ * Internal RX/TX descriptor structures ++ * (rX: reserved fields possibily used by future versions of the ar5k chipset) ++ */ ++ ++struct ath5k_rx_desc { ++ u32 rx_control_0; /* RX control word 0 */ ++ ++#define AR5K_DESC_RX_CTL0 0x00000000 ++ ++ u32 rx_control_1; /* RX control word 1 */ ++ ++#define AR5K_DESC_RX_CTL1_BUF_LEN 0x00000fff ++#define AR5K_DESC_RX_CTL1_INTREQ 0x00002000 ++} __packed; ++ ++/* ++ * 5210/5211 rx status descriptor ++ */ ++struct ath5k_hw_old_rx_status { ++ u32 rx_status_0; /* RX status word 0 */ ++ ++#define AR5K_OLD_RX_DESC_STATUS0_DATA_LEN 0x00000fff ++#define AR5K_OLD_RX_DESC_STATUS0_MORE 0x00001000 ++#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_RATE 0x00078000 ++#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_RATE_S 15 ++#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x07f80000 ++#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_SIGNAL_S 19 ++#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_ANTENNA 0x38000000 ++#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_ANTENNA_S 27 ++ ++ u32 rx_status_1; /* RX status word 1 */ ++ ++#define AR5K_OLD_RX_DESC_STATUS1_DONE 0x00000001 ++#define AR5K_OLD_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002 ++#define AR5K_OLD_RX_DESC_STATUS1_CRC_ERROR 0x00000004 ++#define AR5K_OLD_RX_DESC_STATUS1_FIFO_OVERRUN 0x00000008 ++#define AR5K_OLD_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000010 ++#define AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR 0x000000e0 ++#define AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR_S 5 ++#define AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100 ++#define AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX 0x00007e00 ++#define AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX_S 9 ++#define AR5K_OLD_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x0fff8000 ++#define AR5K_OLD_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S 15 ++#define AR5K_OLD_RX_DESC_STATUS1_KEY_CACHE_MISS 0x10000000 ++} __packed; ++ ++/* ++ * 5212 rx status descriptor ++ */ ++struct ath5k_hw_new_rx_status { ++ u32 rx_status_0; /* RX status word 0 */ ++ ++#define AR5K_NEW_RX_DESC_STATUS0_DATA_LEN 0x00000fff ++#define AR5K_NEW_RX_DESC_STATUS0_MORE 0x00001000 ++#define AR5K_NEW_RX_DESC_STATUS0_DECOMP_CRC_ERROR 0x00002000 ++#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_RATE 0x000f8000 ++#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_RATE_S 15 ++#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x0ff00000 ++#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_SIGNAL_S 20 ++#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_ANTENNA 0xf0000000 ++#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_ANTENNA_S 28 ++ ++ u32 rx_status_1; /* RX status word 1 */ ++ ++#define AR5K_NEW_RX_DESC_STATUS1_DONE 0x00000001 ++#define AR5K_NEW_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002 ++#define AR5K_NEW_RX_DESC_STATUS1_CRC_ERROR 0x00000004 ++#define AR5K_NEW_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000008 ++#define AR5K_NEW_RX_DESC_STATUS1_PHY_ERROR 0x00000010 ++#define AR5K_NEW_RX_DESC_STATUS1_MIC_ERROR 0x00000020 ++#define AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100 ++#define AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX 0x0000fe00 ++#define AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX_S 9 ++#define AR5K_NEW_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x7fff0000 ++#define AR5K_NEW_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S 16 ++#define AR5K_NEW_RX_DESC_STATUS1_KEY_CACHE_MISS 0x80000000 ++} __packed; ++ ++struct ath5k_hw_rx_error { ++ u32 rx_error_0; /* RX error word 0 */ ++ ++#define AR5K_RX_DESC_ERROR0 0x00000000 ++ ++ u32 rx_error_1; /* RX error word 1 */ ++ ++#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE 0x0000ff00 ++#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE_S 8 ++} __packed; ++ ++#define AR5K_DESC_RX_PHY_ERROR_NONE 0x00 ++#define AR5K_DESC_RX_PHY_ERROR_TIMING 0x20 ++#define AR5K_DESC_RX_PHY_ERROR_PARITY 0x40 ++#define AR5K_DESC_RX_PHY_ERROR_RATE 0x60 ++#define AR5K_DESC_RX_PHY_ERROR_LENGTH 0x80 ++#define AR5K_DESC_RX_PHY_ERROR_64QAM 0xa0 ++#define AR5K_DESC_RX_PHY_ERROR_SERVICE 0xc0 ++#define AR5K_DESC_RX_PHY_ERROR_TRANSMITOVR 0xe0 ++ ++struct ath5k_hw_2w_tx_desc { ++ u32 tx_control_0; /* TX control word 0 */ ++ ++#define AR5K_2W_TX_DESC_CTL0_FRAME_LEN 0x00000fff ++#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN 0x0003f000 /*[5210 ?]*/ ++#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN_S 12 ++#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE 0x003c0000 ++#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE_S 18 ++#define AR5K_2W_TX_DESC_CTL0_RTSENA 0x00400000 ++#define AR5K_2W_TX_DESC_CTL0_CLRDMASK 0x01000000 ++#define AR5K_2W_TX_DESC_CTL0_LONG_PACKET 0x00800000 /*[5210]*/ ++#define AR5K_2W_TX_DESC_CTL0_VEOL 0x00800000 /*[5211]*/ ++#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE 0x1c000000 /*[5210]*/ ++#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_S 26 ++#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210 0x02000000 ++#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211 0x1e000000 ++#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210 : \ ++ AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211) ++#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_S 25 ++#define AR5K_2W_TX_DESC_CTL0_INTREQ 0x20000000 ++#define AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID 0x40000000 ++ ++ u32 tx_control_1; /* TX control word 1 */ ++ ++#define AR5K_2W_TX_DESC_CTL1_BUF_LEN 0x00000fff ++#define AR5K_2W_TX_DESC_CTL1_MORE 0x00001000 ++#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210 0x0007e000 ++#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211 0x000fe000 ++#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX (ah->ah_version == AR5K_AR5210 ? \ ++ AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210 : \ ++ AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211) ++#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S 13 ++#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE 0x00700000 /*[5211]*/ ++#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_S 20 ++#define AR5K_2W_TX_DESC_CTL1_NOACK 0x00800000 /*[5211]*/ ++#define AR5K_2W_TX_DESC_CTL1_RTS_DURATION 0xfff80000 /*[5210 ?]*/ ++} __packed; ++ ++#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NORMAL 0x00 ++#define AR5K_AR5210_TX_DESC_FRAME_TYPE_ATIM 0x04 ++#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PSPOLL 0x08 ++#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY 0x0c ++#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS 0x10 ++ ++/* ++ * 5212 4-word tx control descriptor ++ */ ++struct ath5k_hw_4w_tx_desc { ++ u32 tx_control_0; /* TX control word 0 */ ++ ++#define AR5K_4W_TX_DESC_CTL0_FRAME_LEN 0x00000fff ++#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER 0x003f0000 ++#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER_S 16 ++#define AR5K_4W_TX_DESC_CTL0_RTSENA 0x00400000 ++#define AR5K_4W_TX_DESC_CTL0_VEOL 0x00800000 ++#define AR5K_4W_TX_DESC_CTL0_CLRDMASK 0x01000000 ++#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT 0x1e000000 ++#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT_S 25 ++#define AR5K_4W_TX_DESC_CTL0_INTREQ 0x20000000 ++#define AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID 0x40000000 ++#define AR5K_4W_TX_DESC_CTL0_CTSENA 0x80000000 ++ ++ u32 tx_control_1; /* TX control word 1 */ ++ ++#define AR5K_4W_TX_DESC_CTL1_BUF_LEN 0x00000fff ++#define AR5K_4W_TX_DESC_CTL1_MORE 0x00001000 ++#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX 0x000fe000 ++#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S 13 ++#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE 0x00f00000 ++#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE_S 20 ++#define AR5K_4W_TX_DESC_CTL1_NOACK 0x01000000 ++#define AR5K_4W_TX_DESC_CTL1_COMP_PROC 0x06000000 ++#define AR5K_4W_TX_DESC_CTL1_COMP_PROC_S 25 ++#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN 0x18000000 ++#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN_S 27 ++#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN 0x60000000 ++#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN_S 29 ++ ++ u32 tx_control_2; /* TX control word 2 */ ++ ++#define AR5K_4W_TX_DESC_CTL2_RTS_DURATION 0x00007fff ++#define AR5K_4W_TX_DESC_CTL2_DURATION_UPDATE_ENABLE 0x00008000 ++#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0 0x000f0000 ++#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0_S 16 ++#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1 0x00f00000 ++#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1_S 20 ++#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2 0x0f000000 ++#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2_S 24 ++#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3 0xf0000000 ++#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3_S 28 ++ ++ u32 tx_control_3; /* TX control word 3 */ ++ ++#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE0 0x0000001f ++#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1 0x000003e0 ++#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1_S 5 ++#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2 0x00007c00 ++#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2_S 10 ++#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3 0x000f8000 ++#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3_S 15 ++#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE 0x01f00000 ++#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE_S 20 ++} __packed; ++ ++/* ++ * Common tx status descriptor ++ */ ++struct ath5k_hw_tx_status { ++ u32 tx_status_0; /* TX status word 0 */ ++ ++#define AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK 0x00000001 ++#define AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES 0x00000002 ++#define AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN 0x00000004 ++#define AR5K_DESC_TX_STATUS0_FILTERED 0x00000008 ++/*??? ++#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT 0x000000f0 ++#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT_S 4 ++*/ ++#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT 0x000000f0 ++#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT_S 4 ++/*??? ++#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT 0x00000f00 ++#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT_S 8 ++*/ ++#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT 0x00000f00 ++#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT_S 8 ++#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT 0x0000f000 ++#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT_S 12 ++#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP 0xffff0000 ++#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP_S 16 ++ ++ u32 tx_status_1; /* TX status word 1 */ ++ ++#define AR5K_DESC_TX_STATUS1_DONE 0x00000001 ++#define AR5K_DESC_TX_STATUS1_SEQ_NUM 0x00001ffe ++#define AR5K_DESC_TX_STATUS1_SEQ_NUM_S 1 ++#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH 0x001fe000 ++#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH_S 13 ++#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX 0x00600000 ++#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX_S 21 ++#define AR5K_DESC_TX_STATUS1_COMP_SUCCESS 0x00800000 ++#define AR5K_DESC_TX_STATUS1_XMIT_ANTENNA 0x01000000 ++} __packed; ++ ++ ++/* ++ * AR5K REGISTER ACCESS ++ */ ++ ++/*Swap RX/TX Descriptor for big endian archs*/ ++#if defined(__BIG_ENDIAN) ++#define AR5K_INIT_CFG ( \ ++ AR5K_CFG_SWTD | AR5K_CFG_SWRD \ ++) ++#else ++#define AR5K_INIT_CFG 0x00000000 ++#endif ++ ++/*#define AR5K_REG_READ(_reg) ath5k_hw_reg_read(ah, _reg) ++ ++#define AR5K_REG_WRITE(_reg, _val) ath5k_hw_reg_write(ah, _val, _reg)*/ ++ ++#define AR5K_REG_SM(_val, _flags) \ ++ (((_val) << _flags##_S) & (_flags)) ++ ++#define AR5K_REG_MS(_val, _flags) \ ++ (((_val) & (_flags)) >> _flags##_S) ++ ++/* Some registers can hold multiple values of interest. For this ++ * reason when we want to write to these registers we must first ++ * retrieve the values which we do not want to clear (lets call this ++ * old_data) and then set the register with this and our new_value: ++ * ( old_data | new_value) */ ++#define AR5K_REG_WRITE_BITS(ah, _reg, _flags, _val) \ ++ ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) & ~(_flags)) | \ ++ (((_val) << _flags##_S) & (_flags)), _reg) ++ ++#define AR5K_REG_MASKED_BITS(ah, _reg, _flags, _mask) \ ++ ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) & \ ++ (_mask)) | (_flags), _reg) ++ ++#define AR5K_REG_ENABLE_BITS(ah, _reg, _flags) \ ++ ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) | (_flags), _reg) ++ ++#define AR5K_REG_DISABLE_BITS(ah, _reg, _flags) \ ++ ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) & ~(_flags), _reg) ++ ++#define AR5K_PHY_WRITE(ah, _reg, _val) \ ++ ath5k_hw_reg_write(ah, _val, (ah)->ah_phy + ((_reg) << 2)) ++ ++#define AR5K_PHY_READ(ah, _reg) \ ++ ath5k_hw_reg_read(ah, (ah)->ah_phy + ((_reg) << 2)) ++ ++#define AR5K_REG_WAIT(_i) do { \ ++ if (_i % 64) \ ++ udelay(1); \ ++} while (0) ++ ++#define AR5K_EEPROM_READ(_o, _v) do { \ ++ if ((ret = ath5k_hw_eeprom_read(ah, (_o), &(_v))) != 0) \ ++ return (ret); \ ++} while (0) ++ ++#define AR5K_EEPROM_READ_HDR(_o, _v) \ ++ AR5K_EEPROM_READ(_o, ah->ah_capabilities.cap_eeprom._v); \ ++ ++/* Read status of selected queue */ ++#define AR5K_REG_READ_Q(ah, _reg, _queue) \ ++ (ath5k_hw_reg_read(ah, _reg) & (1 << _queue)) \ ++ ++#define AR5K_REG_WRITE_Q(ah, _reg, _queue) \ ++ ath5k_hw_reg_write(ah, (1 << _queue), _reg) ++ ++#define AR5K_Q_ENABLE_BITS(_reg, _queue) do { \ ++ _reg |= 1 << _queue; \ ++} while (0) ++ ++#define AR5K_Q_DISABLE_BITS(_reg, _queue) do { \ ++ _reg &= ~(1 << _queue); \ ++} while (0) ++ ++#define AR5K_LOW_ID(_a)( \ ++(_a)[0] | (_a)[1] << 8 | (_a)[2] << 16 | (_a)[3] << 24 \ ++) ++ ++#define AR5K_HIGH_ID(_a) ((_a)[4] | (_a)[5] << 8) ++ ++/* ++ * Initial register values ++ */ ++ ++/* ++ * Common initial register values ++ */ ++#define AR5K_INIT_MODE CHANNEL_B ++ ++#define AR5K_INIT_TX_LATENCY 502 ++#define AR5K_INIT_USEC 39 ++#define AR5K_INIT_USEC_TURBO 79 ++#define AR5K_INIT_USEC_32 31 ++#define AR5K_INIT_CARR_SENSE_EN 1 ++#define AR5K_INIT_PROG_IFS 920 ++#define AR5K_INIT_PROG_IFS_TURBO 960 ++#define AR5K_INIT_EIFS 3440 ++#define AR5K_INIT_EIFS_TURBO 6880 ++#define AR5K_INIT_SLOT_TIME 396 ++#define AR5K_INIT_SLOT_TIME_TURBO 480 ++#define AR5K_INIT_ACK_CTS_TIMEOUT 1024 ++#define AR5K_INIT_ACK_CTS_TIMEOUT_TURBO 0x08000800 ++#define AR5K_INIT_SIFS 560 ++#define AR5K_INIT_SIFS_TURBO 480 ++#define AR5K_INIT_SH_RETRY 10 ++#define AR5K_INIT_LG_RETRY AR5K_INIT_SH_RETRY ++#define AR5K_INIT_SSH_RETRY 32 ++#define AR5K_INIT_SLG_RETRY AR5K_INIT_SSH_RETRY ++#define AR5K_INIT_TX_RETRY 10 ++#define AR5K_INIT_TOPS 8 ++#define AR5K_INIT_RXNOFRM 8 ++#define AR5K_INIT_RPGTO 0 ++#define AR5K_INIT_TXNOFRM 0 ++#define AR5K_INIT_BEACON_PERIOD 65535 ++#define AR5K_INIT_TIM_OFFSET 0 ++#define AR5K_INIT_BEACON_EN 0 ++#define AR5K_INIT_RESET_TSF 0 ++ ++#define AR5K_INIT_TRANSMIT_LATENCY ( \ ++ (AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) | \ ++ (AR5K_INIT_USEC) \ ++) ++#define AR5K_INIT_TRANSMIT_LATENCY_TURBO ( \ ++ (AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) | \ ++ (AR5K_INIT_USEC_TURBO) \ ++) ++#define AR5K_INIT_PROTO_TIME_CNTRL ( \ ++ (AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS << 12) | \ ++ (AR5K_INIT_PROG_IFS) \ ++) ++#define AR5K_INIT_PROTO_TIME_CNTRL_TURBO ( \ ++ (AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS_TURBO << 12) | \ ++ (AR5K_INIT_PROG_IFS_TURBO) \ ++) ++#define AR5K_INIT_BEACON_CONTROL ( \ ++ (AR5K_INIT_RESET_TSF << 24) | (AR5K_INIT_BEACON_EN << 23) | \ ++ (AR5K_INIT_TIM_OFFSET << 16) | (AR5K_INIT_BEACON_PERIOD) \ ++) ++ ++/* ++ * Non-common initial register values which have to be loaded into the ++ * card at boot time and after each reset. ++ */ ++ ++/* Register dumps are done per operation mode */ ++#define AR5K_INI_RFGAIN_5GHZ 0 ++#define AR5K_INI_RFGAIN_2GHZ 1 ++ ++#define AR5K_INI_VAL_11A 0 ++#define AR5K_INI_VAL_11A_TURBO 1 ++#define AR5K_INI_VAL_11B 2 ++#define AR5K_INI_VAL_11G 3 ++#define AR5K_INI_VAL_11G_TURBO 4 ++#define AR5K_INI_VAL_XR 0 ++#define AR5K_INI_VAL_MAX 5 ++ ++#define AR5K_RF5111_INI_RF_MAX_BANKS AR5K_MAX_RF_BANKS ++#define AR5K_RF5112_INI_RF_MAX_BANKS AR5K_MAX_RF_BANKS ++ ++static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits) ++{ ++ u32 retval = 0, bit, i; ++ ++ for (i = 0; i < bits; i++) { ++ bit = (val >> i) & 1; ++ retval = (retval << 1) | bit; ++ } ++ ++ return retval; ++} +diff -up /dev/null linux-2.6.23.noarch/drivers/net/wireless/ath5k/initvals.c +--- /dev/null 2007-12-21 08:33:07.834165456 -0500 ++++ linux-2.6.23.noarch/drivers/net/wireless/ath5k/initvals.c 2007-12-21 12:18:50.000000000 -0500 +@@ -0,0 +1,1347 @@ ++/* ++ * Initial register settings functions ++ * ++ * Copyright (c) 2004, 2005, 2006, 2007 Reyk Floeter ++ * Copyright (c) 2006, 2007 Nick Kossifidis ++ * Copyright (c) 2007 Jiri Slaby ++ * ++ * Permission to use, copy, modify, and 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 "ath5k.h" ++#include "base.h" ++#include "reg.h" ++ ++/* ++ * MAC/PHY REGISTERS ++ */ ++ ++ ++/* ++ * Mode-independent initial register writes ++ */ ++ ++struct ath5k_ini { ++ u16 ini_register; ++ u32 ini_value; ++ ++ enum { ++ AR5K_INI_WRITE = 0, /* Default */ ++ AR5K_INI_READ = 1, /* Cleared on read */ ++ } ini_mode; ++}; ++ ++/* ++ * Mode specific initial register values ++ */ ++ ++struct ath5k_ini_mode { ++ u16 mode_register; ++ u32 mode_value[5]; ++}; ++ ++/* Initial register settings for AR5210 */ ++static const struct ath5k_ini ar5210_ini[] = { ++ /* PCU and MAC registers */ ++ { AR5K_NOQCU_TXDP0, 0 }, ++ { AR5K_NOQCU_TXDP1, 0 }, ++ { AR5K_RXDP, 0 }, ++ { AR5K_CR, 0 }, ++ { AR5K_ISR, 0, AR5K_INI_READ }, ++ { AR5K_IMR, 0 }, ++ { AR5K_IER, AR5K_IER_DISABLE }, ++ { AR5K_BSR, 0, AR5K_INI_READ }, ++ { AR5K_TXCFG, AR5K_DMASIZE_128B }, ++ { AR5K_RXCFG, AR5K_DMASIZE_128B }, ++ { AR5K_CFG, AR5K_INIT_CFG }, ++ { AR5K_TOPS, AR5K_INIT_TOPS }, ++ { AR5K_RXNOFRM, AR5K_INIT_RXNOFRM }, ++ { AR5K_RPGTO, AR5K_INIT_RPGTO }, ++ { AR5K_TXNOFRM, AR5K_INIT_TXNOFRM }, ++ { AR5K_SFR, 0 }, ++ { AR5K_MIBC, 0 }, ++ { AR5K_MISC, 0 }, ++ { AR5K_RX_FILTER_5210, 0 }, ++ { AR5K_MCAST_FILTER0_5210, 0 }, ++ { AR5K_MCAST_FILTER1_5210, 0 }, ++ { AR5K_TX_MASK0, 0 }, ++ { AR5K_TX_MASK1, 0 }, ++ { AR5K_CLR_TMASK, 0 }, ++ { AR5K_TRIG_LVL, AR5K_TUNE_MIN_TX_FIFO_THRES }, ++ { AR5K_DIAG_SW_5210, 0 }, ++ { AR5K_RSSI_THR, AR5K_TUNE_RSSI_THRES }, ++ { AR5K_TSF_L32_5210, 0 }, ++ { AR5K_TIMER0_5210, 0 }, ++ { AR5K_TIMER1_5210, 0xffffffff }, ++ { AR5K_TIMER2_5210, 0xffffffff }, ++ { AR5K_TIMER3_5210, 1 }, ++ { AR5K_CFP_DUR_5210, 0 }, ++ { AR5K_CFP_PERIOD_5210, 0 }, ++ /* PHY registers */ ++ { AR5K_PHY(0), 0x00000047 }, ++ { AR5K_PHY_AGC, 0x00000000 }, ++ { AR5K_PHY(3), 0x09848ea6 }, ++ { AR5K_PHY(4), 0x3d32e000 }, ++ { AR5K_PHY(5), 0x0000076b }, ++ { AR5K_PHY_ACT, AR5K_PHY_ACT_DISABLE }, ++ { AR5K_PHY(8), 0x02020200 }, ++ { AR5K_PHY(9), 0x00000e0e }, ++ { AR5K_PHY(10), 0x0a020201 }, ++ { AR5K_PHY(11), 0x00036ffc }, ++ { AR5K_PHY(12), 0x00000000 }, ++ { AR5K_PHY(13), 0x00000e0e }, ++ { AR5K_PHY(14), 0x00000007 }, ++ { AR5K_PHY(15), 0x00020100 }, ++ { AR5K_PHY(16), 0x89630000 }, ++ { AR5K_PHY(17), 0x1372169c }, ++ { AR5K_PHY(18), 0x0018b633 }, ++ { AR5K_PHY(19), 0x1284613c }, ++ { AR5K_PHY(20), 0x0de8b8e0 }, ++ { AR5K_PHY(21), 0x00074859 }, ++ { AR5K_PHY(22), 0x7e80beba }, ++ { AR5K_PHY(23), 0x313a665e }, ++ { AR5K_PHY_AGCCTL, 0x00001d08 }, ++ { AR5K_PHY(25), 0x0001ce00 }, ++ { AR5K_PHY(26), 0x409a4190 }, ++ { AR5K_PHY(28), 0x0000000f }, ++ { AR5K_PHY(29), 0x00000080 }, ++ { AR5K_PHY(30), 0x00000004 }, ++ { AR5K_PHY(31), 0x00000018 }, /* 0x987c */ ++ { AR5K_PHY(64), 0x00000000 }, /* 0x9900 */ ++ { AR5K_PHY(65), 0x00000000 }, ++ { AR5K_PHY(66), 0x00000000 }, ++ { AR5K_PHY(67), 0x00800000 }, ++ { AR5K_PHY(68), 0x00000003 }, ++ /* BB gain table (64bytes) */ ++ { AR5K_BB_GAIN(0), 0x00000000 }, ++ { AR5K_BB_GAIN(1), 0x00000020 }, ++ { AR5K_BB_GAIN(2), 0x00000010 }, ++ { AR5K_BB_GAIN(3), 0x00000030 }, ++ { AR5K_BB_GAIN(4), 0x00000008 }, ++ { AR5K_BB_GAIN(5), 0x00000028 }, ++ { AR5K_BB_GAIN(6), 0x00000028 }, ++ { AR5K_BB_GAIN(7), 0x00000004 }, ++ { AR5K_BB_GAIN(8), 0x00000024 }, ++ { AR5K_BB_GAIN(9), 0x00000014 }, ++ { AR5K_BB_GAIN(10), 0x00000034 }, ++ { AR5K_BB_GAIN(11), 0x0000000c }, ++ { AR5K_BB_GAIN(12), 0x0000002c }, ++ { AR5K_BB_GAIN(13), 0x00000002 }, ++ { AR5K_BB_GAIN(14), 0x00000022 }, ++ { AR5K_BB_GAIN(15), 0x00000012 }, ++ { AR5K_BB_GAIN(16), 0x00000032 }, ++ { AR5K_BB_GAIN(17), 0x0000000a }, ++ { AR5K_BB_GAIN(18), 0x0000002a }, ++ { AR5K_BB_GAIN(19), 0x00000001 }, ++ { AR5K_BB_GAIN(20), 0x00000021 }, ++ { AR5K_BB_GAIN(21), 0x00000011 }, ++ { AR5K_BB_GAIN(22), 0x00000031 }, ++ { AR5K_BB_GAIN(23), 0x00000009 }, ++ { AR5K_BB_GAIN(24), 0x00000029 }, ++ { AR5K_BB_GAIN(25), 0x00000005 }, ++ { AR5K_BB_GAIN(26), 0x00000025 }, ++ { AR5K_BB_GAIN(27), 0x00000015 }, ++ { AR5K_BB_GAIN(28), 0x00000035 }, ++ { AR5K_BB_GAIN(29), 0x0000000d }, ++ { AR5K_BB_GAIN(30), 0x0000002d }, ++ { AR5K_BB_GAIN(31), 0x00000003 }, ++ { AR5K_BB_GAIN(32), 0x00000023 }, ++ { AR5K_BB_GAIN(33), 0x00000013 }, ++ { AR5K_BB_GAIN(34), 0x00000033 }, ++ { AR5K_BB_GAIN(35), 0x0000000b }, ++ { AR5K_BB_GAIN(36), 0x0000002b }, ++ { AR5K_BB_GAIN(37), 0x00000007 }, ++ { AR5K_BB_GAIN(38), 0x00000027 }, ++ { AR5K_BB_GAIN(39), 0x00000017 }, ++ { AR5K_BB_GAIN(40), 0x00000037 }, ++ { AR5K_BB_GAIN(41), 0x0000000f }, ++ { AR5K_BB_GAIN(42), 0x0000002f }, ++ { AR5K_BB_GAIN(43), 0x0000002f }, ++ { AR5K_BB_GAIN(44), 0x0000002f }, ++ { AR5K_BB_GAIN(45), 0x0000002f }, ++ { AR5K_BB_GAIN(46), 0x0000002f }, ++ { AR5K_BB_GAIN(47), 0x0000002f }, ++ { AR5K_BB_GAIN(48), 0x0000002f }, ++ { AR5K_BB_GAIN(49), 0x0000002f }, ++ { AR5K_BB_GAIN(50), 0x0000002f }, ++ { AR5K_BB_GAIN(51), 0x0000002f }, ++ { AR5K_BB_GAIN(52), 0x0000002f }, ++ { AR5K_BB_GAIN(53), 0x0000002f }, ++ { AR5K_BB_GAIN(54), 0x0000002f }, ++ { AR5K_BB_GAIN(55), 0x0000002f }, ++ { AR5K_BB_GAIN(56), 0x0000002f }, ++ { AR5K_BB_GAIN(57), 0x0000002f }, ++ { AR5K_BB_GAIN(58), 0x0000002f }, ++ { AR5K_BB_GAIN(59), 0x0000002f }, ++ { AR5K_BB_GAIN(60), 0x0000002f }, ++ { AR5K_BB_GAIN(61), 0x0000002f }, ++ { AR5K_BB_GAIN(62), 0x0000002f }, ++ { AR5K_BB_GAIN(63), 0x0000002f }, ++ /* 5110 RF gain table (64btes) */ ++ { AR5K_RF_GAIN(0), 0x0000001d }, ++ { AR5K_RF_GAIN(1), 0x0000005d }, ++ { AR5K_RF_GAIN(2), 0x0000009d }, ++ { AR5K_RF_GAIN(3), 0x000000dd }, ++ { AR5K_RF_GAIN(4), 0x0000011d }, ++ { AR5K_RF_GAIN(5), 0x00000021 }, ++ { AR5K_RF_GAIN(6), 0x00000061 }, ++ { AR5K_RF_GAIN(7), 0x000000a1 }, ++ { AR5K_RF_GAIN(8), 0x000000e1 }, ++ { AR5K_RF_GAIN(9), 0x00000031 }, ++ { AR5K_RF_GAIN(10), 0x00000071 }, ++ { AR5K_RF_GAIN(11), 0x000000b1 }, ++ { AR5K_RF_GAIN(12), 0x0000001c }, ++ { AR5K_RF_GAIN(13), 0x0000005c }, ++ { AR5K_RF_GAIN(14), 0x00000029 }, ++ { AR5K_RF_GAIN(15), 0x00000069 }, ++ { AR5K_RF_GAIN(16), 0x000000a9 }, ++ { AR5K_RF_GAIN(17), 0x00000020 }, ++ { AR5K_RF_GAIN(18), 0x00000019 }, ++ { AR5K_RF_GAIN(19), 0x00000059 }, ++ { AR5K_RF_GAIN(20), 0x00000099 }, ++ { AR5K_RF_GAIN(21), 0x00000030 }, ++ { AR5K_RF_GAIN(22), 0x00000005 }, ++ { AR5K_RF_GAIN(23), 0x00000025 }, ++ { AR5K_RF_GAIN(24), 0x00000065 }, ++ { AR5K_RF_GAIN(25), 0x000000a5 }, ++ { AR5K_RF_GAIN(26), 0x00000028 }, ++ { AR5K_RF_GAIN(27), 0x00000068 }, ++ { AR5K_RF_GAIN(28), 0x0000001f }, ++ { AR5K_RF_GAIN(29), 0x0000001e }, ++ { AR5K_RF_GAIN(30), 0x00000018 }, ++ { AR5K_RF_GAIN(31), 0x00000058 }, ++ { AR5K_RF_GAIN(32), 0x00000098 }, ++ { AR5K_RF_GAIN(33), 0x00000003 }, ++ { AR5K_RF_GAIN(34), 0x00000004 }, ++ { AR5K_RF_GAIN(35), 0x00000044 }, ++ { AR5K_RF_GAIN(36), 0x00000084 }, ++ { AR5K_RF_GAIN(37), 0x00000013 }, ++ { AR5K_RF_GAIN(38), 0x00000012 }, ++ { AR5K_RF_GAIN(39), 0x00000052 }, ++ { AR5K_RF_GAIN(40), 0x00000092 }, ++ { AR5K_RF_GAIN(41), 0x000000d2 }, ++ { AR5K_RF_GAIN(42), 0x0000002b }, ++ { AR5K_RF_GAIN(43), 0x0000002a }, ++ { AR5K_RF_GAIN(44), 0x0000006a }, ++ { AR5K_RF_GAIN(45), 0x000000aa }, ++ { AR5K_RF_GAIN(46), 0x0000001b }, ++ { AR5K_RF_GAIN(47), 0x0000001a }, ++ { AR5K_RF_GAIN(48), 0x0000005a }, ++ { AR5K_RF_GAIN(49), 0x0000009a }, ++ { AR5K_RF_GAIN(50), 0x000000da }, ++ { AR5K_RF_GAIN(51), 0x00000006 }, ++ { AR5K_RF_GAIN(52), 0x00000006 }, ++ { AR5K_RF_GAIN(53), 0x00000006 }, ++ { AR5K_RF_GAIN(54), 0x00000006 }, ++ { AR5K_RF_GAIN(55), 0x00000006 }, ++ { AR5K_RF_GAIN(56), 0x00000006 }, ++ { AR5K_RF_GAIN(57), 0x00000006 }, ++ { AR5K_RF_GAIN(58), 0x00000006 }, ++ { AR5K_RF_GAIN(59), 0x00000006 }, ++ { AR5K_RF_GAIN(60), 0x00000006 }, ++ { AR5K_RF_GAIN(61), 0x00000006 }, ++ { AR5K_RF_GAIN(62), 0x00000006 }, ++ { AR5K_RF_GAIN(63), 0x00000006 }, ++ /* PHY activation */ ++ { AR5K_PHY(53), 0x00000020 }, ++ { AR5K_PHY(51), 0x00000004 }, ++ { AR5K_PHY(50), 0x00060106 }, ++ { AR5K_PHY(39), 0x0000006d }, ++ { AR5K_PHY(48), 0x00000000 }, ++ { AR5K_PHY(52), 0x00000014 }, ++ { AR5K_PHY_ACT, AR5K_PHY_ACT_ENABLE }, ++}; ++ ++/* Initial register settings for AR5211 */ ++static const struct ath5k_ini ar5211_ini[] = { ++ { AR5K_RXDP, 0x00000000 }, ++ { AR5K_RTSD0, 0x84849c9c }, ++ { AR5K_RTSD1, 0x7c7c7c7c }, ++ { AR5K_RXCFG, 0x00000005 }, ++ { AR5K_MIBC, 0x00000000 }, ++ { AR5K_TOPS, 0x00000008 }, ++ { AR5K_RXNOFRM, 0x00000008 }, ++ { AR5K_TXNOFRM, 0x00000010 }, ++ { AR5K_RPGTO, 0x00000000 }, ++ { AR5K_RFCNT, 0x0000001f }, ++ { AR5K_QUEUE_TXDP(0), 0x00000000 }, ++ { AR5K_QUEUE_TXDP(1), 0x00000000 }, ++ { AR5K_QUEUE_TXDP(2), 0x00000000 }, ++ { AR5K_QUEUE_TXDP(3), 0x00000000 }, ++ { AR5K_QUEUE_TXDP(4), 0x00000000 }, ++ { AR5K_QUEUE_TXDP(5), 0x00000000 }, ++ { AR5K_QUEUE_TXDP(6), 0x00000000 }, ++ { AR5K_QUEUE_TXDP(7), 0x00000000 }, ++ { AR5K_QUEUE_TXDP(8), 0x00000000 }, ++ { AR5K_QUEUE_TXDP(9), 0x00000000 }, ++ { AR5K_DCU_FP, 0x00000000 }, ++ { AR5K_STA_ID1, 0x00000000 }, ++ { AR5K_BSS_ID0, 0x00000000 }, ++ { AR5K_BSS_ID1, 0x00000000 }, ++ { AR5K_RSSI_THR, 0x00000000 }, ++ { AR5K_CFP_PERIOD_5211, 0x00000000 }, ++ { AR5K_TIMER0_5211, 0x00000030 }, ++ { AR5K_TIMER1_5211, 0x0007ffff }, ++ { AR5K_TIMER2_5211, 0x01ffffff }, ++ { AR5K_TIMER3_5211, 0x00000031 }, ++ { AR5K_CFP_DUR_5211, 0x00000000 }, ++ { AR5K_RX_FILTER_5211, 0x00000000 }, ++ { AR5K_MCAST_FILTER0_5211, 0x00000000 }, ++ { AR5K_MCAST_FILTER1_5211, 0x00000002 }, ++ { AR5K_DIAG_SW_5211, 0x00000000 }, ++ { AR5K_ADDAC_TEST, 0x00000000 }, ++ { AR5K_DEFAULT_ANTENNA, 0x00000000 }, ++ /* PHY registers */ ++ { AR5K_PHY_AGC, 0x00000000 }, ++ { AR5K_PHY(3), 0x2d849093 }, ++ { AR5K_PHY(4), 0x7d32e000 }, ++ { AR5K_PHY(5), 0x00000f6b }, ++ { AR5K_PHY_ACT, 0x00000000 }, ++ { AR5K_PHY(11), 0x00026ffe }, ++ { AR5K_PHY(12), 0x00000000 }, ++ { AR5K_PHY(15), 0x00020100 }, ++ { AR5K_PHY(16), 0x206a017a }, ++ { AR5K_PHY(19), 0x1284613c }, ++ { AR5K_PHY(21), 0x00000859 }, ++ { AR5K_PHY(26), 0x409a4190 }, /* 0x9868 */ ++ { AR5K_PHY(27), 0x050cb081 }, ++ { AR5K_PHY(28), 0x0000000f }, ++ { AR5K_PHY(29), 0x00000080 }, ++ { AR5K_PHY(30), 0x0000000c }, ++ { AR5K_PHY(64), 0x00000000 }, ++ { AR5K_PHY(65), 0x00000000 }, ++ { AR5K_PHY(66), 0x00000000 }, ++ { AR5K_PHY(67), 0x00800000 }, ++ { AR5K_PHY(68), 0x00000001 }, ++ { AR5K_PHY(71), 0x0000092a }, ++ { AR5K_PHY_IQ, 0x00000000 }, ++ { AR5K_PHY(73), 0x00058a05 }, ++ { AR5K_PHY(74), 0x00000001 }, ++ { AR5K_PHY(75), 0x00000000 }, ++ { AR5K_PHY_PAPD_PROBE, 0x00000000 }, ++ { AR5K_PHY(77), 0x00000000 }, /* 0x9934 */ ++ { AR5K_PHY(78), 0x00000000 }, /* 0x9938 */ ++ { AR5K_PHY(79), 0x0000003f }, /* 0x993c */ ++ { AR5K_PHY(80), 0x00000004 }, ++ { AR5K_PHY(82), 0x00000000 }, ++ { AR5K_PHY(83), 0x00000000 }, ++ { AR5K_PHY(84), 0x00000000 }, ++ { AR5K_PHY_RADAR, 0x5d50f14c }, ++ { AR5K_PHY(86), 0x00000018 }, ++ { AR5K_PHY(87), 0x004b6a8e }, ++ /* Initial Power table (32bytes) ++ * common on all cards/modes. ++ * Note: Table is rewritten during ++ * txpower setup later using calibration ++ * data etc. so next write is non-common ++ { AR5K_PHY_PCDAC_TXPOWER(1), 0x06ff05ff }, ++ { AR5K_PHY_PCDAC_TXPOWER(2), 0x07ff07ff }, ++ { AR5K_PHY_PCDAC_TXPOWER(3), 0x08ff08ff }, ++ { AR5K_PHY_PCDAC_TXPOWER(4), 0x09ff09ff }, ++ { AR5K_PHY_PCDAC_TXPOWER(5), 0x0aff0aff }, ++ { AR5K_PHY_PCDAC_TXPOWER(6), 0x0bff0bff }, ++ { AR5K_PHY_PCDAC_TXPOWER(7), 0x0cff0cff }, ++ { AR5K_PHY_PCDAC_TXPOWER(8), 0x0dff0dff }, ++ { AR5K_PHY_PCDAC_TXPOWER(9), 0x0fff0eff }, ++ { AR5K_PHY_PCDAC_TXPOWER(10), 0x12ff12ff }, ++ { AR5K_PHY_PCDAC_TXPOWER(11), 0x14ff13ff }, ++ { AR5K_PHY_PCDAC_TXPOWER(12), 0x16ff15ff }, ++ { AR5K_PHY_PCDAC_TXPOWER(13), 0x19ff17ff }, ++ { AR5K_PHY_PCDAC_TXPOWER(14), 0x1bff1aff }, ++ { AR5K_PHY_PCDAC_TXPOWER(15), 0x1eff1dff }, ++ { AR5K_PHY_PCDAC_TXPOWER(16), 0x23ff20ff }, ++ { AR5K_PHY_PCDAC_TXPOWER(17), 0x27ff25ff }, ++ { AR5K_PHY_PCDAC_TXPOWER(18), 0x2cff29ff }, ++ { AR5K_PHY_PCDAC_TXPOWER(19), 0x31ff2fff }, ++ { AR5K_PHY_PCDAC_TXPOWER(20), 0x37ff34ff }, ++ { AR5K_PHY_PCDAC_TXPOWER(21), 0x3aff3aff }, ++ { AR5K_PHY_PCDAC_TXPOWER(22), 0x3aff3aff }, ++ { AR5K_PHY_PCDAC_TXPOWER(23), 0x3aff3aff }, ++ { AR5K_PHY_PCDAC_TXPOWER(24), 0x3aff3aff }, ++ { AR5K_PHY_PCDAC_TXPOWER(25), 0x3aff3aff }, ++ { AR5K_PHY_PCDAC_TXPOWER(26), 0x3aff3aff }, ++ { AR5K_PHY_PCDAC_TXPOWER(27), 0x3aff3aff }, ++ { AR5K_PHY_PCDAC_TXPOWER(28), 0x3aff3aff }, ++ { AR5K_PHY_PCDAC_TXPOWER(29), 0x3aff3aff }, ++ { AR5K_PHY_PCDAC_TXPOWER(30), 0x3aff3aff }, ++ { AR5K_PHY_PCDAC_TXPOWER(31), 0x3aff3aff },*/ ++ { AR5K_PHY_CCKTXCTL, 0x00000000 }, ++ { AR5K_PHY(642), 0x503e4646 }, ++ { AR5K_PHY_GAIN_2GHZ, 0x6480416c }, ++ { AR5K_PHY(644), 0x0199a003 }, ++ { AR5K_PHY(645), 0x044cd610 }, ++ { AR5K_PHY(646), 0x13800040 }, ++ { AR5K_PHY(647), 0x1be00060 }, ++ { AR5K_PHY(648), 0x0c53800a }, ++ { AR5K_PHY(649), 0x0014df3b }, ++ { AR5K_PHY(650), 0x000001b5 }, ++ { AR5K_PHY(651), 0x00000020 }, ++}; ++ ++/* Initial mode-specific settings for AR5211 ++ * XXX: how about g / gTurbo ? RF5111 supports it, how about AR5211 ? ++ * Maybe 5211 supports OFDM-only g but we need to test it ! ++ */ ++static const struct ath5k_ini_mode ar5211_ini_mode[] = { ++ { AR5K_TXCFG, ++ /* a aTurbo b */ ++ { 0x00000015, 0x00000015, 0x0000001d } }, ++ { AR5K_QUEUE_DFS_LOCAL_IFS(0), ++ { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } }, ++ { AR5K_QUEUE_DFS_LOCAL_IFS(1), ++ { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } }, ++ { AR5K_QUEUE_DFS_LOCAL_IFS(2), ++ { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } }, ++ { AR5K_QUEUE_DFS_LOCAL_IFS(3), ++ { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } }, ++ { AR5K_QUEUE_DFS_LOCAL_IFS(4), ++ { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } }, ++ { AR5K_QUEUE_DFS_LOCAL_IFS(5), ++ { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } }, ++ { AR5K_QUEUE_DFS_LOCAL_IFS(6), ++ { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } }, ++ { AR5K_QUEUE_DFS_LOCAL_IFS(7), ++ { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } }, ++ { AR5K_QUEUE_DFS_LOCAL_IFS(8), ++ { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } }, ++ { AR5K_QUEUE_DFS_LOCAL_IFS(9), ++ { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } }, ++ { AR5K_DCU_GBL_IFS_SLOT, ++ { 0x00000168, 0x000001e0, 0x000001b8 } }, ++ { AR5K_DCU_GBL_IFS_SIFS, ++ { 0x00000230, 0x000001e0, 0x000000b0 } }, ++ { AR5K_DCU_GBL_IFS_EIFS, ++ { 0x00000d98, 0x00001180, 0x00001f48 } }, ++ { AR5K_DCU_GBL_IFS_MISC, ++ { 0x0000a0e0, 0x00014068, 0x00005880 } }, ++ { AR5K_TIME_OUT, ++ { 0x04000400, 0x08000800, 0x20003000 } }, ++ { AR5K_USEC_5211, ++ { 0x0e8d8fa7, 0x0e8d8fcf, 0x01608f95 } }, ++ { AR5K_PHY_TURBO, ++ { 0x00000000, 0x00000003, 0x00000000 } }, ++ { AR5K_PHY(8), ++ { 0x02020200, 0x02020200, 0x02010200 } }, ++ { AR5K_PHY(9), ++ { 0x00000e0e, 0x00000e0e, 0x00000707 } }, ++ { AR5K_PHY(10), ++ { 0x0a020001, 0x0a020001, 0x05010000 } }, ++ { AR5K_PHY(13), ++ { 0x00000e0e, 0x00000e0e, 0x00000e0e } }, ++ { AR5K_PHY(14), ++ { 0x00000007, 0x00000007, 0x0000000b } }, ++ { AR5K_PHY(17), ++ { 0x1372169c, 0x137216a5, 0x137216a8 } }, ++ { AR5K_PHY(18), ++ { 0x0018ba67, 0x0018ba67, 0x0018ba69 } }, ++ { AR5K_PHY(20), ++ { 0x0c28b4e0, 0x0c28b4e0, 0x0c28b4e0 } }, ++ { AR5K_PHY_SIG, ++ { 0x7e800d2e, 0x7e800d2e, 0x7ec00d2e } }, ++ { AR5K_PHY_AGCCOARSE, ++ { 0x31375d5e, 0x31375d5e, 0x313a5d5e } }, ++ { AR5K_PHY_AGCCTL, ++ { 0x0000bd10, 0x0000bd10, 0x0000bd38 } }, ++ { AR5K_PHY_NF, ++ { 0x0001ce00, 0x0001ce00, 0x0001ce00 } }, ++ { AR5K_PHY_RX_DELAY, ++ { 0x00002710, 0x00002710, 0x0000157c } }, ++ { AR5K_PHY(70), ++ { 0x00000190, 0x00000190, 0x00000084 } }, ++ { AR5K_PHY_FRAME_CTL_5211, ++ { 0x6fe01020, 0x6fe01020, 0x6fe00920 } }, ++ { AR5K_PHY_PCDAC_TXPOWER_BASE_5211, ++ { 0x05ff14ff, 0x05ff14ff, 0x05ff14ff } }, ++ { AR5K_RF_BUFFER_CONTROL_4, ++ { 0x00000010, 0x00000014, 0x00000010 } }, ++}; ++ ++/* Initial register settings for AR5212 */ ++static const struct ath5k_ini ar5212_ini[] = { ++ { AR5K_RXDP, 0x00000000 }, ++ { AR5K_RXCFG, 0x00000005 }, ++ { AR5K_MIBC, 0x00000000 }, ++ { AR5K_TOPS, 0x00000008 }, ++ { AR5K_RXNOFRM, 0x00000008 }, ++ { AR5K_TXNOFRM, 0x00000010 }, ++ { AR5K_RPGTO, 0x00000000 }, ++ { AR5K_RFCNT, 0x0000001f }, ++ { AR5K_QUEUE_TXDP(0), 0x00000000 }, ++ { AR5K_QUEUE_TXDP(1), 0x00000000 }, ++ { AR5K_QUEUE_TXDP(2), 0x00000000 }, ++ { AR5K_QUEUE_TXDP(3), 0x00000000 }, ++ { AR5K_QUEUE_TXDP(4), 0x00000000 }, ++ { AR5K_QUEUE_TXDP(5), 0x00000000 }, ++ { AR5K_QUEUE_TXDP(6), 0x00000000 }, ++ { AR5K_QUEUE_TXDP(7), 0x00000000 }, ++ { AR5K_QUEUE_TXDP(8), 0x00000000 }, ++ { AR5K_QUEUE_TXDP(9), 0x00000000 }, ++ { AR5K_DCU_FP, 0x00000000 }, ++ { AR5K_DCU_TXP, 0x00000000 }, ++ { AR5K_DCU_TX_FILTER, 0x00000000 }, ++ /* Unknown table */ ++ { 0x1078, 0x00000000 }, ++ { 0x10b8, 0x00000000 }, ++ { 0x10f8, 0x00000000 }, ++ { 0x1138, 0x00000000 }, ++ { 0x1178, 0x00000000 }, ++ { 0x11b8, 0x00000000 }, ++ { 0x11f8, 0x00000000 }, ++ { 0x1238, 0x00000000 }, ++ { 0x1278, 0x00000000 }, ++ { 0x12b8, 0x00000000 }, ++ { 0x12f8, 0x00000000 }, ++ { 0x1338, 0x00000000 }, ++ { 0x1378, 0x00000000 }, ++ { 0x13b8, 0x00000000 }, ++ { 0x13f8, 0x00000000 }, ++ { 0x1438, 0x00000000 }, ++ { 0x1478, 0x00000000 }, ++ { 0x14b8, 0x00000000 }, ++ { 0x14f8, 0x00000000 }, ++ { 0x1538, 0x00000000 }, ++ { 0x1578, 0x00000000 }, ++ { 0x15b8, 0x00000000 }, ++ { 0x15f8, 0x00000000 }, ++ { 0x1638, 0x00000000 }, ++ { 0x1678, 0x00000000 }, ++ { 0x16b8, 0x00000000 }, ++ { 0x16f8, 0x00000000 }, ++ { 0x1738, 0x00000000 }, ++ { 0x1778, 0x00000000 }, ++ { 0x17b8, 0x00000000 }, ++ { 0x17f8, 0x00000000 }, ++ { 0x103c, 0x00000000 }, ++ { 0x107c, 0x00000000 }, ++ { 0x10bc, 0x00000000 }, ++ { 0x10fc, 0x00000000 }, ++ { 0x113c, 0x00000000 }, ++ { 0x117c, 0x00000000 }, ++ { 0x11bc, 0x00000000 }, ++ { 0x11fc, 0x00000000 }, ++ { 0x123c, 0x00000000 }, ++ { 0x127c, 0x00000000 }, ++ { 0x12bc, 0x00000000 }, ++ { 0x12fc, 0x00000000 }, ++ { 0x133c, 0x00000000 }, ++ { 0x137c, 0x00000000 }, ++ { 0x13bc, 0x00000000 }, ++ { 0x13fc, 0x00000000 }, ++ { 0x143c, 0x00000000 }, ++ { 0x147c, 0x00000000 }, ++ { AR5K_DCU_TX_FILTER_CLR, 0x00000000 }, ++ { AR5K_DCU_TX_FILTER_SET, 0x00000000 }, ++ { AR5K_STA_ID1, 0x00000000 }, ++ { AR5K_BSS_ID0, 0x00000000 }, ++ { AR5K_BSS_ID1, 0x00000000 }, ++ /*{ AR5K_RSSI_THR, 0x00000000 },*/ /* Found on SuperAG cards */ ++ { AR5K_BEACON_5211, 0x00000000 }, /* Found on SuperAG cards */ ++ { AR5K_CFP_PERIOD_5211, 0x00000000 }, /* Found on SuperAG cards */ ++ { AR5K_TIMER0_5211, 0x00000030 }, /* Found on SuperAG cards */ ++ { AR5K_TIMER1_5211, 0x0007ffff }, /* Found on SuperAG cards */ ++ { AR5K_TIMER2_5211, 0x01ffffff }, /* Found on SuperAG cards */ ++ { AR5K_TIMER3_5211, 0x00000031 }, /* Found on SuperAG cards */ ++ { AR5K_CFP_DUR_5211, 0x00000000 }, /* Found on SuperAG cards */ ++ { AR5K_RX_FILTER_5211, 0x00000000 }, ++ { AR5K_DIAG_SW_5211, 0x00000000 }, ++ { AR5K_ADDAC_TEST, 0x00000000 }, ++ { AR5K_DEFAULT_ANTENNA, 0x00000000 }, ++ { 0x8080, 0x00000000 }, ++ /*{ 0x805c, 0xffffc7ff },*/ /* Old value */ ++ { 0x805c, 0x000fc78f }, ++ { AR5K_NAV_5211, 0x00000000 }, /* Not found on recent */ ++ { AR5K_RTS_OK_5211, 0x00000000 }, /* dumps but it makes */ ++ { AR5K_RTS_FAIL_5211, 0x00000000 }, /* sense to reset counters */ ++ { AR5K_ACK_FAIL_5211, 0x00000000 }, /* since pcu registers */ ++ { AR5K_FCS_FAIL_5211, 0x00000000 }, /* are skiped during chan*/ ++ { AR5K_BEACON_CNT_5211, 0x00000000 }, /* change */ ++ { AR5K_XRMODE, 0x2a82301a }, ++ { AR5K_XRDELAY, 0x05dc01e0 }, ++ { AR5K_XRTIMEOUT, 0x1f402710 }, ++ { AR5K_XRCHIRP, 0x01f40000 }, ++ { AR5K_XRSTOMP, 0x00001e1c }, ++ { AR5K_SLEEP0, 0x0002aaaa }, /* Found on SuperAG cards */ ++ { AR5K_SLEEP1, 0x02005555 }, /* Found on SuperAG cards */ ++ { AR5K_SLEEP2, 0x00000000 }, /* Found on SuperAG cards */ ++ { AR5K_BSS_IDM0, 0xffffffff }, ++ { AR5K_BSS_IDM1, 0x0000ffff }, ++ { AR5K_TXPC, 0x00000000 }, ++ { AR5K_PROFCNT_TX, 0x00000000 }, ++ { AR5K_PROFCNT_RX, 0x00000000 }, ++ { AR5K_PROFCNT_RXCLR, 0x00000000 }, ++ { AR5K_PROFCNT_CYCLE, 0x00000000 }, ++ { 0x80fc, 0x00000088 }, ++ { AR5K_RATE_DUR(0), 0x00000000 }, ++ { AR5K_RATE_DUR(1), 0x0000008c }, ++ { AR5K_RATE_DUR(2), 0x000000e4 }, ++ { AR5K_RATE_DUR(3), 0x000002d5 }, ++ { AR5K_RATE_DUR(4), 0x00000000 }, ++ { AR5K_RATE_DUR(5), 0x00000000 }, ++ { AR5K_RATE_DUR(6), 0x000000a0 }, ++ { AR5K_RATE_DUR(7), 0x000001c9 }, ++ { AR5K_RATE_DUR(8), 0x0000002c }, ++ { AR5K_RATE_DUR(9), 0x0000002c }, ++ { AR5K_RATE_DUR(10), 0x00000030 }, ++ { AR5K_RATE_DUR(11), 0x0000003c }, ++ { AR5K_RATE_DUR(12), 0x0000002c }, ++ { AR5K_RATE_DUR(13), 0x0000002c }, ++ { AR5K_RATE_DUR(14), 0x00000030 }, ++ { AR5K_RATE_DUR(15), 0x0000003c }, ++ { AR5K_RATE_DUR(16), 0x00000000 }, ++ { AR5K_RATE_DUR(17), 0x00000000 }, ++ { AR5K_RATE_DUR(18), 0x00000000 }, ++ { AR5K_RATE_DUR(19), 0x00000000 }, ++ { AR5K_RATE_DUR(20), 0x00000000 }, ++ { AR5K_RATE_DUR(21), 0x00000000 }, ++ { AR5K_RATE_DUR(22), 0x00000000 }, ++ { AR5K_RATE_DUR(23), 0x00000000 }, ++ { AR5K_RATE_DUR(24), 0x000000d5 }, ++ { AR5K_RATE_DUR(25), 0x000000df }, ++ { AR5K_RATE_DUR(26), 0x00000102 }, ++ { AR5K_RATE_DUR(27), 0x0000013a }, ++ { AR5K_RATE_DUR(28), 0x00000075 }, ++ { AR5K_RATE_DUR(29), 0x0000007f }, ++ { AR5K_RATE_DUR(30), 0x000000a2 }, ++ { AR5K_RATE_DUR(31), 0x00000000 }, ++ { 0x8100, 0x00010002}, ++ { AR5K_TSF_PARM, 0x00000001 }, ++ { 0x8108, 0x000000c0 }, ++ { AR5K_PHY_ERR_FIL, 0x00000000 }, ++ { 0x8110, 0x00000168 }, ++ { 0x8114, 0x00000000 }, ++ /* Some kind of table ++ * also notice ...03<-02<-01<-00) */ ++ { 0x87c0, 0x03020100 }, ++ { 0x87c4, 0x07060504 }, ++ { 0x87c8, 0x0b0a0908 }, ++ { 0x87cc, 0x0f0e0d0c }, ++ { 0x87d0, 0x13121110 }, ++ { 0x87d4, 0x17161514 }, ++ { 0x87d8, 0x1b1a1918 }, ++ { 0x87dc, 0x1f1e1d1c }, ++ /* loop ? */ ++ { 0x87e0, 0x03020100 }, ++ { 0x87e4, 0x07060504 }, ++ { 0x87e8, 0x0b0a0908 }, ++ { 0x87ec, 0x0f0e0d0c }, ++ { 0x87f0, 0x13121110 }, ++ { 0x87f4, 0x17161514 }, ++ { 0x87f8, 0x1b1a1918 }, ++ { 0x87fc, 0x1f1e1d1c }, ++ /* PHY registers */ ++ /*{ AR5K_PHY_AGC, 0x00000000 },*/ ++ { AR5K_PHY(3), 0xad848e19 }, ++ { AR5K_PHY(4), 0x7d28e000 }, ++ { AR5K_PHY_TIMING_3, 0x9c0a9f6b }, ++ { AR5K_PHY_ACT, 0x00000000 }, ++ /*{ AR5K_PHY(11), 0x00022ffe },*/ ++ /*{ AR5K_PHY(15), 0x00020100 },*/ ++ { AR5K_PHY(16), 0x206a017a }, ++ /*{ AR5K_PHY(19), 0x1284613c },*/ ++ { AR5K_PHY(21), 0x00000859 }, ++ { AR5K_PHY(64), 0x00000000 }, ++ { AR5K_PHY(65), 0x00000000 }, ++ { AR5K_PHY(66), 0x00000000 }, ++ { AR5K_PHY(67), 0x00800000 }, ++ { AR5K_PHY(68), 0x00000001 }, ++ /*{ AR5K_PHY(71), 0x0000092a },*/ /* Old value */ ++ { AR5K_PHY(71), 0x00000c80 }, ++ { AR5K_PHY_IQ, 0x05100000 }, ++ { AR5K_PHY(74), 0x00000001 }, ++ { AR5K_PHY(75), 0x00000004 }, ++ { AR5K_PHY_TXPOWER_RATE1, 0x1e1f2022 }, ++ { AR5K_PHY_TXPOWER_RATE2, 0x0a0b0c0d }, ++ { AR5K_PHY_TXPOWER_RATE_MAX, 0x0000003f }, ++ /*{ AR5K_PHY(80), 0x00000004 },*/ ++ { AR5K_PHY(82), 0x9280b212 }, ++ { AR5K_PHY_RADAR, 0x5d50e188 }, ++ /*{ AR5K_PHY(86), 0x000000ff },*/ ++ { AR5K_PHY(87), 0x004b6a8e }, ++ { AR5K_PHY(90), 0x000003ce }, ++ { AR5K_PHY(92), 0x192fb515 }, ++ /*{ AR5K_PHY(93), 0x00000000 },*/ ++ { AR5K_PHY(94), 0x00000001 }, ++ { AR5K_PHY(95), 0x00000000 }, ++ /*{ AR5K_PHY(644), 0x0080a333 },*/ /* Old value */ ++ /*{ AR5K_PHY(645), 0x00206c10 },*/ /* Old value */ ++ { AR5K_PHY(644), 0x00806333 }, ++ { AR5K_PHY(645), 0x00106c10 }, ++ { AR5K_PHY(646), 0x009c4060 }, ++ /*{ AR5K_PHY(647), 0x1483800a },*/ /* Old value */ ++ { AR5K_PHY(647), 0x1483800a }, ++ { AR5K_PHY(648), 0x01831061 }, ++ { AR5K_PHY(649), 0x00000400 }, ++ /*{ AR5K_PHY(650), 0x000001b5 },*/ ++ { AR5K_PHY(651), 0x00000000 }, ++ { AR5K_PHY_TXPOWER_RATE3, 0x20202020 }, ++ { AR5K_PHY_TXPOWER_RATE2, 0x20202020 }, ++ /*{ AR5K_PHY(655), 0x13c889af },*/ ++ { AR5K_PHY(656), 0x38490a20 }, ++ { AR5K_PHY(657), 0x00007bb6 }, ++ { AR5K_PHY(658), 0x0fff3ffc }, ++ /*{ AR5K_PHY_CCKTXCTL, 0x00000000 },*/ ++}; ++ ++/* Initial mode-specific settings for AR5212 (Written before ar5212_ini) */ ++static const struct ath5k_ini_mode ar5212_ini_mode_start[] = { ++ { AR5K_PHY(640), ++ /* a/XR aTurbo b g (DYN) gTurbo */ ++ { 0x00000008, 0x00000008, 0x0000000b, 0x0000000e, 0x0000000e } }, ++ { AR5K_PHY(0), ++ { 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 } }, ++ { AR5K_QUEUE_DFS_LOCAL_IFS(0), ++ { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, ++ { AR5K_QUEUE_DFS_LOCAL_IFS(1), ++ { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, ++ { AR5K_QUEUE_DFS_LOCAL_IFS(2), ++ { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, ++ { AR5K_QUEUE_DFS_LOCAL_IFS(3), ++ { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, ++ { AR5K_QUEUE_DFS_LOCAL_IFS(4), ++ { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, ++ { AR5K_QUEUE_DFS_LOCAL_IFS(5), ++ { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, ++ { AR5K_QUEUE_DFS_LOCAL_IFS(6), ++ { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, ++ { AR5K_QUEUE_DFS_LOCAL_IFS(7), ++ { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, ++ { AR5K_QUEUE_DFS_LOCAL_IFS(8), ++ { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, ++ { AR5K_QUEUE_DFS_LOCAL_IFS(9), ++ { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, ++ { AR5K_DCU_GBL_IFS_SIFS, ++ { 0x00000230, 0x000001e0, 0x000000b0, 0x00000160, 0x000001e0 } }, ++ { AR5K_DCU_GBL_IFS_SLOT, ++ { 0x00000168, 0x000001e0, 0x000001b8, 0x0000018c, 0x000001e0 } }, ++ { AR5K_DCU_GBL_IFS_EIFS, ++ { 0x00000e60, 0x00001180, 0x00001f1c, 0x00003e38, 0x00001180 } }, ++ { AR5K_DCU_GBL_IFS_MISC, ++ { 0x0000a0e0, 0x00014068, 0x00005880, 0x0000b0e0, 0x00014068 } }, ++ { AR5K_TIME_OUT, ++ { 0x03e803e8, 0x06e006e0, 0x04200420, 0x08400840, 0x06e006e0 } }, ++ { AR5K_PHY_TURBO, ++ { 0x00000000, 0x00000003, 0x00000000, 0x00000000, 0x00000003 } }, ++ { AR5K_PHY(8), ++ { 0x02020200, 0x02020200, 0x02010200, 0x02020200, 0x02020200 } }, ++ { AR5K_PHY(9), ++ { 0x00000e0e, 0x00000e0e, 0x00000707, 0x00000e0e, 0x00000e0e } }, ++ { AR5K_PHY(17), ++ { 0x1372161c, 0x13721c25, 0x13721722, 0x137216a2, 0x13721c25 } }, ++ { AR5K_PHY_AGCCTL, ++ { 0x00009d10, 0x00009d10, 0x00009d18, 0x00009d18, 0x00009d18 } }, ++ { AR5K_PHY_NF, ++ { 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 } }, ++ { AR5K_PHY(26), ++ { 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 } }, ++ { AR5K_PHY(70), ++ { 0x000001b8, 0x000001b8, 0x00000084, 0x00000108, 0x000001b8 } }, ++ { AR5K_PHY(73), ++ { 0x10058a05, 0x10058a05, 0x10058a05, 0x10058a05, 0x10058a05 } }, ++ { 0xa230, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000108, 0x00000000 } }, ++}; ++ ++/* Initial mode-specific settings for AR5212 + RF5111 (Written after ar5212_ini) */ ++/* New dump pending */ ++static const struct ath5k_ini_mode ar5212_rf5111_ini_mode_end[] = { ++ { AR5K_PHY(640), /* This one differs from ar5212_ini_mode_start ! */ ++ /* a/XR aTurbo b g (DYN) gTurbo */ ++ { 0x00000000, 0x00000000, 0x00000003, 0x00000006, 0x00000006 } }, ++ { AR5K_TXCFG, ++ { 0x00008015, 0x00008015, 0x00008015, 0x00008015, 0x00008015 } }, ++ { AR5K_USEC_5211, ++ { 0x128d8fa7, 0x09880fcf, 0x04e00f95, 0x12e00fab, 0x09880fcf } }, ++ { AR5K_PHY(10), ++ { 0x0a020001, 0x0a020001, 0x05010100, 0x0a020001, 0x0a020001 } }, ++ { AR5K_PHY(13), ++ { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } }, ++ { AR5K_PHY(14), ++ { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } }, ++ { AR5K_PHY(18), ++ { 0x0018da5a, 0x0018da5a, 0x0018ca69, 0x0018ca69, 0x0018ca69 } }, ++ { AR5K_PHY(20), ++ { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } }, ++ { AR5K_PHY_SIG, ++ { 0x7e800d2e, 0x7e800d2e, 0x7ee84d2e, 0x7ee84d2e, 0x7e800d2e } }, ++ { AR5K_PHY_AGCCOARSE, ++ { 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137615e } }, ++ { AR5K_PHY(27), ++ { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb080, 0x050cb080 } }, ++ { AR5K_PHY_RX_DELAY, ++ { 0x00002710, 0x00002710, 0x0000157c, 0x00002af8, 0x00002710 } }, ++ { AR5K_PHY_FRAME_CTL_5211, ++ { 0xf7b81020, 0xf7b81020, 0xf7b80d20, 0xf7b81020, 0xf7b81020 } }, ++ { AR5K_PHY_GAIN_2GHZ, ++ { 0x642c416a, 0x642c416a, 0x6440416a, 0x6440416a, 0x6440416a } }, ++ { 0xa21c, ++ { 0x1883800a, 0x1883800a, 0x1873800a, 0x1883800a, 0x1883800a } }, ++ { AR5K_DCU_FP, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { AR5K_PHY_AGC, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { AR5K_PHY(11), ++ { 0x00022ffe, 0x00022ffe, 0x00022ffe, 0x00022ffe, 0x00022ffe } }, ++ { AR5K_PHY(15), ++ { 0x00020100, 0x00020100, 0x00020100, 0x00020100, 0x00020100 } }, ++ { AR5K_PHY(19), ++ { 0x1284613c, 0x1284613c, 0x1284613c, 0x1284613c, 0x1284613c } }, ++ { AR5K_PHY_PAPD_PROBE, ++ { 0x00004883, 0x00004883, 0x00004883, 0x00004883, 0x00004883 } }, ++ { AR5K_PHY(80), ++ { 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 } }, ++ { AR5K_PHY(86), ++ { 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff } }, ++ { AR5K_PHY(93), ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { AR5K_PHY_SPENDING, ++ { 0x00000018, 0x00000018, 0x00000018, 0x00000018, 0x00000018 } }, ++ { AR5K_PHY_CCKTXCTL, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { AR5K_PHY(642), ++ { 0xd03e6788, 0xd03e6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } }, ++ { 0xa23c, ++ { 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af } }, ++}; ++ ++/* Initial mode-specific settings for AR5212 + RF5112 (Written after ar5212_ini) */ ++/* XXX: No dumps for turbog yet, but i found settings from old values so it should be ok */ ++static const struct ath5k_ini_mode ar5212_rf5112_ini_mode_end[] = { ++ { AR5K_TXCFG, ++ /* a/XR aTurbo b g (DYN) gTurbo */ ++ { 0x00008015, 0x00008015, 0x00008015, 0x00008015, 0x00008015 } }, ++ { AR5K_USEC_5211, ++ { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } }, ++ { AR5K_PHY(10), ++ { 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } }, ++ { AR5K_PHY(13), ++ { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } }, ++ { AR5K_PHY(14), ++ { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } }, ++ { AR5K_PHY(18), ++ { 0x0018da6d, 0x0018da6d, 0x0018ca75, 0x0018ca75, 0x0018ca75 } }, ++ { AR5K_PHY(20), ++ { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } }, ++ { AR5K_PHY_SIG, ++ { 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ee80d2e, 0x7ee80d2e } }, ++ { AR5K_PHY_AGCCOARSE, ++ { 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e } }, ++ { AR5K_PHY(27), ++ { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } }, ++ { AR5K_PHY_RX_DELAY, ++ { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } }, ++ { AR5K_PHY_FRAME_CTL_5211, ++ { 0xf7b81020, 0xf7b81020, 0xf7b80d10, 0xf7b81010, 0xf7b81010 } }, ++ { AR5K_PHY_CCKTXCTL, ++ { 0x00000000, 0x00000000, 0x00000008, 0x00000008, 0x00000008 } }, ++ { AR5K_PHY(642), ++ { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } }, ++ { AR5K_PHY_GAIN_2GHZ, ++ { 0x642c0140, 0x642c0140, 0x6442c160, 0x6442c160, 0x6442c160 } }, ++ { 0xa21c, ++ { 0x1883800a, 0x1883800a, 0x1873800a, 0x1883800a, 0x1883800a } }, ++ { AR5K_DCU_FP, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { AR5K_PHY_AGC, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { AR5K_PHY(11), ++ { 0x00022ffe, 0x00022ffe, 0x00022ffe, 0x00022ffe, 0x00022ffe } }, ++ { AR5K_PHY(15), ++ { 0x00020100, 0x00020100, 0x00020100, 0x00020100, 0x00020100 } }, ++ { AR5K_PHY(19), ++ { 0x1284613c, 0x1284613c, 0x1284613c, 0x1284613c, 0x1284613c } }, ++ { AR5K_PHY_PAPD_PROBE, ++ { 0x00004882, 0x00004882, 0x00004882, 0x00004882, 0x00004882 } }, ++ { AR5K_PHY(80), ++ { 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 } }, ++ { AR5K_PHY(86), ++ { 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff } }, ++ { AR5K_PHY(93), ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0xa228, ++ { 0x000001b5, 0x000001b5, 0x000001b5, 0x000001b5, 0x000001b5 } }, ++ { 0xa23c, ++ { 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af } }, ++}; ++ ++/* Initial mode-specific settings for RF5413/5414 (Written after ar5212_ini) */ ++/* XXX: No dumps for turbog yet, so turbog is the same with g here with some ++ * minor tweaking based on dumps from other chips */ ++static const struct ath5k_ini_mode rf5413_ini_mode_end[] = { ++ { AR5K_TXCFG, ++ /* a/XR aTurbo b g gTurbo */ ++ { 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 } }, ++ { AR5K_USEC_5211, ++ { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } }, ++ { AR5K_PHY(10), ++ { 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } }, ++ { AR5K_PHY(13), ++ { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } }, ++ { AR5K_PHY(14), ++ { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } }, ++ { AR5K_PHY(18), ++ { 0x0018fa61, 0x0018fa61, 0x001a1a63, 0x001a1a63, 0x001a1a63 } }, ++ { AR5K_PHY(20), ++ { 0x0c98b4e0, 0x0c98b4e0, 0x0c98b0da, 0x0c98b0da, 0x0c98b0da } }, ++ { AR5K_PHY_SIG, ++ { 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e } }, ++ { AR5K_PHY_AGCCOARSE, ++ { 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e } }, ++ { AR5K_PHY(27), ++ { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } }, ++ { AR5K_PHY_RX_DELAY, ++ { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } }, ++ { AR5K_PHY_FRAME_CTL_5211, ++ { 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 } }, ++ { AR5K_PHY_CCKTXCTL, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { AR5K_PHY(642), ++ { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } }, ++ { AR5K_PHY_GAIN_2GHZ, ++ { 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 } }, ++ { 0xa21c, ++ { 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a } }, ++ { 0xa300, ++ { 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 } }, ++ { 0xa304, ++ { 0x30032602, 0x30032602, 0x30032602, 0x30032602, 0x30032602 } }, ++ { 0xa308, ++ { 0x48073e06, 0x48073e06, 0x48073e06, 0x48073e06, 0x48073e06 } }, ++ { 0xa30c, ++ { 0x560b4c0a, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a } }, ++ { 0xa310, ++ { 0x641a600f, 0x641a600f, 0x641a600f, 0x641a600f, 0x641a600f } }, ++ { 0xa314, ++ { 0x784f6e1b, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b } }, ++ { 0xa318, ++ { 0x868f7c5a, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a } }, ++ { 0xa31c, ++ { 0x90cf865b, 0x90cf865b, 0x8ecf865b, 0x8ecf865b, 0x8ecf865b } }, ++ { 0xa320, ++ { 0x9d4f970f, 0x9d4f970f, 0x9b4f970f, 0x9b4f970f, 0x9b4f970f } }, ++ { 0xa324, ++ { 0xa7cfa38f, 0xa7cfa38f, 0xa3cf9f8f, 0xa3cf9f8f, 0xa3cf9f8f } }, ++ { 0xa328, ++ { 0xb55faf1f, 0xb55faf1f, 0xb35faf1f, 0xb35faf1f, 0xb35faf1f } }, ++ { 0xa32c, ++ { 0xbddfb99f, 0xbddfb99f, 0xbbdfb99f, 0xbbdfb99f, 0xbbdfb99f } }, ++ { 0xa330, ++ { 0xcb7fc53f, 0xcb7fc53f, 0xcb7fc73f, 0xcb7fc73f, 0xcb7fc73f } }, ++ { 0xa334, ++ { 0xd5ffd1bf, 0xd5ffd1bf, 0xd3ffd1bf, 0xd3ffd1bf, 0xd3ffd1bf } }, ++ { AR5K_DCU_FP, ++ { 0x000003e0, 0x000003e0, 0x000003e0, 0x000003e0, 0x000003e0 } }, ++ { 0x4068, ++ { 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 } }, ++ { 0x8060, ++ { 0x0000000f, 0x0000000f, 0x0000000f, 0x0000000f, 0x0000000f } }, ++ { 0x809c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0x80a0, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0x8118, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0x811c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0x8120, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0x8124, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0x8128, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0x812c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0x8130, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0x8134, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0x8138, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0x813c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0x8140, ++ { 0x800003f9, 0x800003f9, 0x800003f9, 0x800003f9, 0x800003f9 } }, ++ { 0x8144, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { AR5K_PHY_AGC, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { AR5K_PHY(11), ++ { 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000 } }, ++ { AR5K_PHY(15), ++ { 0x00200400, 0x00200400, 0x00200400, 0x00200400, 0x00200400 } }, ++ { AR5K_PHY(19), ++ { 0x1284233c, 0x1284233c, 0x1284233c, 0x1284233c, 0x1284233c } }, ++ { AR5K_PHY_SCR, ++ { 0x0000001f, 0x0000001f, 0x0000001f, 0x0000001f, 0x0000001f } }, ++ { AR5K_PHY_SLMT, ++ { 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080 } }, ++ { AR5K_PHY_SCAL, ++ { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } }, ++ { AR5K_PHY(86), ++ { 0x00081fff, 0x00081fff, 0x00081fff, 0x00081fff, 0x00081fff } }, ++ { AR5K_PHY(96), ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { AR5K_PHY(97), ++ { 0x02800000, 0x02800000, 0x02800000, 0x02800000, 0x02800000 } }, ++ { AR5K_PHY(104), ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { AR5K_PHY(120), ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { AR5K_PHY(121), ++ { 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa } }, ++ { AR5K_PHY(122), ++ { 0x3c466478, 0x3c466478, 0x3c466478, 0x3c466478, 0x3c466478 } }, ++ { AR5K_PHY(123), ++ { 0x000000aa, 0x000000aa, 0x000000aa, 0x000000aa, 0x000000aa } }, ++ { AR5K_PHY_SCLOCK, ++ { 0x0000000c, 0x0000000c, 0x0000000c, 0x0000000c, 0x0000000c } }, ++ { AR5K_PHY_SDELAY, ++ { 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff } }, ++ { AR5K_PHY_SPENDING, ++ { 0x00000014, 0x00000014, 0x00000014, 0x00000014, 0x00000014 } }, ++ { 0xa228, ++ { 0x000009b5, 0x000009b5, 0x000009b5, 0x000009b5, 0x000009b5 } }, ++ { 0xa23c, ++ { 0x93c889af, 0x93c889af, 0x93c889af, 0x93c889af, 0x93c889af } }, ++ { 0xa24c, ++ { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } }, ++ { 0xa250, ++ { 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000 } }, ++ { 0xa254, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0xa258, ++ { 0x0cc75380, 0x0cc75380, 0x0cc75380, 0x0cc75380, 0x0cc75380 } }, ++ { 0xa25c, ++ { 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01 } }, ++ { 0xa260, ++ { 0x5f690f01, 0x5f690f01, 0x5f690f01, 0x5f690f01, 0x5f690f01 } }, ++ { 0xa264, ++ { 0x00418a11, 0x00418a11, 0x00418a11, 0x00418a11, 0x00418a11 } }, ++ { 0xa268, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0xa26c, ++ { 0x0c30c16a, 0x0c30c16a, 0x0c30c16a, 0x0c30c16a, 0x0c30c16a } }, ++ { 0xa270, ++ { 0x00820820, 0x00820820, 0x00820820, 0x00820820, 0x00820820 } }, ++ { 0xa274, ++ { 0x081b7caa, 0x081b7caa, 0x081b7caa, 0x081b7caa, 0x081b7caa } }, ++ { 0xa278, ++ { 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce } }, ++ { 0xa27c, ++ { 0x051701ce, 0x051701ce, 0x051701ce, 0x051701ce, 0x051701ce } }, ++ { 0xa338, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0xa33c, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0xa340, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0xa344, ++ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, ++ { 0xa348, ++ { 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff } }, ++ { 0xa34c, ++ { 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff } }, ++ { 0xa350, ++ { 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff } }, ++ { 0xa354, ++ { 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff } }, ++ { 0xa358, ++ { 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f } }, ++ { 0xa35c, ++ { 0x066c420f, 0x066c420f, 0x066c420f, 0x066c420f, 0x066c420f } }, ++ { 0xa360, ++ { 0x0f282207, 0x0f282207, 0x0f282207, 0x0f282207, 0x0f282207 } }, ++ { 0xa364, ++ { 0x17601685, 0x17601685, 0x17601685, 0x17601685, 0x17601685 } }, ++ { 0xa368, ++ { 0x1f801104, 0x1f801104, 0x1f801104, 0x1f801104, 0x1f801104 } }, ++ { 0xa36c, ++ { 0x37a00c03, 0x37a00c03, 0x37a00c03, 0x37a00c03, 0x37a00c03 } }, ++ { 0xa370, ++ { 0x3fc40883, 0x3fc40883, 0x3fc40883, 0x3fc40883, 0x3fc40883 } }, ++ { 0xa374, ++ { 0x57c00803, 0x57c00803, 0x57c00803, 0x57c00803, 0x57c00803 } }, ++ { 0xa378, ++ { 0x5fd80682, 0x5fd80682, 0x5fd80682, 0x5fd80682, 0x5fd80682 } }, ++ { 0xa37c, ++ { 0x7fe00482, 0x7fe00482, 0x7fe00482, 0x7fe00482, 0x7fe00482 } }, ++ { 0xa380, ++ { 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba } }, ++ { 0xa384, ++ { 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0 } }, ++}; ++ ++/* ++ * Initial BaseBand Gain settings for RF5111/5112 (AR5210 comes with ++ * RF5110 only so initial BB Gain settings are included in AR5K_AR5210_INI) ++ */ ++ ++/* RF5111 Initial BaseBand Gain settings */ ++static const struct ath5k_ini rf5111_ini_bbgain[] = { ++ { AR5K_BB_GAIN(0), 0x00000000 }, ++ { AR5K_BB_GAIN(1), 0x00000020 }, ++ { AR5K_BB_GAIN(2), 0x00000010 }, ++ { AR5K_BB_GAIN(3), 0x00000030 }, ++ { AR5K_BB_GAIN(4), 0x00000008 }, ++ { AR5K_BB_GAIN(5), 0x00000028 }, ++ { AR5K_BB_GAIN(6), 0x00000004 }, ++ { AR5K_BB_GAIN(7), 0x00000024 }, ++ { AR5K_BB_GAIN(8), 0x00000014 }, ++ { AR5K_BB_GAIN(9), 0x00000034 }, ++ { AR5K_BB_GAIN(10), 0x0000000c }, ++ { AR5K_BB_GAIN(11), 0x0000002c }, ++ { AR5K_BB_GAIN(12), 0x00000002 }, ++ { AR5K_BB_GAIN(13), 0x00000022 }, ++ { AR5K_BB_GAIN(14), 0x00000012 }, ++ { AR5K_BB_GAIN(15), 0x00000032 }, ++ { AR5K_BB_GAIN(16), 0x0000000a }, ++ { AR5K_BB_GAIN(17), 0x0000002a }, ++ { AR5K_BB_GAIN(18), 0x00000006 }, ++ { AR5K_BB_GAIN(19), 0x00000026 }, ++ { AR5K_BB_GAIN(20), 0x00000016 }, ++ { AR5K_BB_GAIN(21), 0x00000036 }, ++ { AR5K_BB_GAIN(22), 0x0000000e }, ++ { AR5K_BB_GAIN(23), 0x0000002e }, ++ { AR5K_BB_GAIN(24), 0x00000001 }, ++ { AR5K_BB_GAIN(25), 0x00000021 }, ++ { AR5K_BB_GAIN(26), 0x00000011 }, ++ { AR5K_BB_GAIN(27), 0x00000031 }, ++ { AR5K_BB_GAIN(28), 0x00000009 }, ++ { AR5K_BB_GAIN(29), 0x00000029 }, ++ { AR5K_BB_GAIN(30), 0x00000005 }, ++ { AR5K_BB_GAIN(31), 0x00000025 }, ++ { AR5K_BB_GAIN(32), 0x00000015 }, ++ { AR5K_BB_GAIN(33), 0x00000035 }, ++ { AR5K_BB_GAIN(34), 0x0000000d }, ++ { AR5K_BB_GAIN(35), 0x0000002d }, ++ { AR5K_BB_GAIN(36), 0x00000003 }, ++ { AR5K_BB_GAIN(37), 0x00000023 }, ++ { AR5K_BB_GAIN(38), 0x00000013 }, ++ { AR5K_BB_GAIN(39), 0x00000033 }, ++ { AR5K_BB_GAIN(40), 0x0000000b }, ++ { AR5K_BB_GAIN(41), 0x0000002b }, ++ { AR5K_BB_GAIN(42), 0x0000002b }, ++ { AR5K_BB_GAIN(43), 0x0000002b }, ++ { AR5K_BB_GAIN(44), 0x0000002b }, ++ { AR5K_BB_GAIN(45), 0x0000002b }, ++ { AR5K_BB_GAIN(46), 0x0000002b }, ++ { AR5K_BB_GAIN(47), 0x0000002b }, ++ { AR5K_BB_GAIN(48), 0x0000002b }, ++ { AR5K_BB_GAIN(49), 0x0000002b }, ++ { AR5K_BB_GAIN(50), 0x0000002b }, ++ { AR5K_BB_GAIN(51), 0x0000002b }, ++ { AR5K_BB_GAIN(52), 0x0000002b }, ++ { AR5K_BB_GAIN(53), 0x0000002b }, ++ { AR5K_BB_GAIN(54), 0x0000002b }, ++ { AR5K_BB_GAIN(55), 0x0000002b }, ++ { AR5K_BB_GAIN(56), 0x0000002b }, ++ { AR5K_BB_GAIN(57), 0x0000002b }, ++ { AR5K_BB_GAIN(58), 0x0000002b }, ++ { AR5K_BB_GAIN(59), 0x0000002b }, ++ { AR5K_BB_GAIN(60), 0x0000002b }, ++ { AR5K_BB_GAIN(61), 0x0000002b }, ++ { AR5K_BB_GAIN(62), 0x00000002 }, ++ { AR5K_BB_GAIN(63), 0x00000016 }, ++}; ++ ++/* RF5112 Initial BaseBand Gain settings (Same for RF5413/5414) */ ++static const struct ath5k_ini rf5112_ini_bbgain[] = { ++ { AR5K_BB_GAIN(0), 0x00000000 }, ++ { AR5K_BB_GAIN(1), 0x00000001 }, ++ { AR5K_BB_GAIN(2), 0x00000002 }, ++ { AR5K_BB_GAIN(3), 0x00000003 }, ++ { AR5K_BB_GAIN(4), 0x00000004 }, ++ { AR5K_BB_GAIN(5), 0x00000005 }, ++ { AR5K_BB_GAIN(6), 0x00000008 }, ++ { AR5K_BB_GAIN(7), 0x00000009 }, ++ { AR5K_BB_GAIN(8), 0x0000000a }, ++ { AR5K_BB_GAIN(9), 0x0000000b }, ++ { AR5K_BB_GAIN(10), 0x0000000c }, ++ { AR5K_BB_GAIN(11), 0x0000000d }, ++ { AR5K_BB_GAIN(12), 0x00000010 }, ++ { AR5K_BB_GAIN(13), 0x00000011 }, ++ { AR5K_BB_GAIN(14), 0x00000012 }, ++ { AR5K_BB_GAIN(15), 0x00000013 }, ++ { AR5K_BB_GAIN(16), 0x00000014 }, ++ { AR5K_BB_GAIN(17), 0x00000015 }, ++ { AR5K_BB_GAIN(18), 0x00000018 }, ++ { AR5K_BB_GAIN(19), 0x00000019 }, ++ { AR5K_BB_GAIN(20), 0x0000001a }, ++ { AR5K_BB_GAIN(21), 0x0000001b }, ++ { AR5K_BB_GAIN(22), 0x0000001c }, ++ { AR5K_BB_GAIN(23), 0x0000001d }, ++ { AR5K_BB_GAIN(24), 0x00000020 }, ++ { AR5K_BB_GAIN(25), 0x00000021 }, ++ { AR5K_BB_GAIN(26), 0x00000022 }, ++ { AR5K_BB_GAIN(27), 0x00000023 }, ++ { AR5K_BB_GAIN(28), 0x00000024 }, ++ { AR5K_BB_GAIN(29), 0x00000025 }, ++ { AR5K_BB_GAIN(30), 0x00000028 }, ++ { AR5K_BB_GAIN(31), 0x00000029 }, ++ { AR5K_BB_GAIN(32), 0x0000002a }, ++ { AR5K_BB_GAIN(33), 0x0000002b }, ++ { AR5K_BB_GAIN(34), 0x0000002c }, ++ { AR5K_BB_GAIN(35), 0x0000002d }, ++ { AR5K_BB_GAIN(36), 0x00000030 }, ++ { AR5K_BB_GAIN(37), 0x00000031 }, ++ { AR5K_BB_GAIN(38), 0x00000032 }, ++ { AR5K_BB_GAIN(39), 0x00000033 }, ++ { AR5K_BB_GAIN(40), 0x00000034 }, ++ { AR5K_BB_GAIN(41), 0x00000035 }, ++ { AR5K_BB_GAIN(42), 0x00000035 }, ++ { AR5K_BB_GAIN(43), 0x00000035 }, ++ { AR5K_BB_GAIN(44), 0x00000035 }, ++ { AR5K_BB_GAIN(45), 0x00000035 }, ++ { AR5K_BB_GAIN(46), 0x00000035 }, ++ { AR5K_BB_GAIN(47), 0x00000035 }, ++ { AR5K_BB_GAIN(48), 0x00000035 }, ++ { AR5K_BB_GAIN(49), 0x00000035 }, ++ { AR5K_BB_GAIN(50), 0x00000035 }, ++ { AR5K_BB_GAIN(51), 0x00000035 }, ++ { AR5K_BB_GAIN(52), 0x00000035 }, ++ { AR5K_BB_GAIN(53), 0x00000035 }, ++ { AR5K_BB_GAIN(54), 0x00000035 }, ++ { AR5K_BB_GAIN(55), 0x00000035 }, ++ { AR5K_BB_GAIN(56), 0x00000035 }, ++ { AR5K_BB_GAIN(57), 0x00000035 }, ++ { AR5K_BB_GAIN(58), 0x00000035 }, ++ { AR5K_BB_GAIN(59), 0x00000035 }, ++ { AR5K_BB_GAIN(60), 0x00000035 }, ++ { AR5K_BB_GAIN(61), 0x00000035 }, ++ { AR5K_BB_GAIN(62), 0x00000010 }, ++ { AR5K_BB_GAIN(63), 0x0000001a }, ++}; ++ ++ ++/* ++ * Write initial register dump ++ */ ++static void ath5k_hw_ini_registers(struct ath5k_hw *ah, unsigned int size, ++ const struct ath5k_ini *ini_regs, bool change_channel) ++{ ++ unsigned int i; ++ ++ /* Write initial registers */ ++ for (i = 0; i < size; i++) { ++ /* On channel change there is ++ * no need to mess with PCU */ ++ if (change_channel && ++ ini_regs[i].ini_register >= AR5K_PCU_MIN && ++ ini_regs[i].ini_register <= AR5K_PCU_MAX) ++ continue; ++ ++ switch (ini_regs[i].ini_mode) { ++ case AR5K_INI_READ: ++ /* Cleared on read */ ++ ath5k_hw_reg_read(ah, ini_regs[i].ini_register); ++ break; ++ case AR5K_INI_WRITE: ++ default: ++ AR5K_REG_WAIT(i); ++ ath5k_hw_reg_write(ah, ini_regs[i].ini_value, ++ ini_regs[i].ini_register); ++ } ++ } ++} ++ ++static void ath5k_hw_ini_mode_registers(struct ath5k_hw *ah, ++ unsigned int size, const struct ath5k_ini_mode *ini_mode, ++ u8 mode) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < size; i++) { ++ AR5K_REG_WAIT(i); ++ ath5k_hw_reg_write(ah, ini_mode[i].mode_value[mode], ++ (u32)ini_mode[i].mode_register); ++ } ++ ++} ++ ++int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel) ++{ ++ /* ++ * Write initial register settings ++ */ ++ ++ /* For AR5212 and combatible */ ++ if (ah->ah_version == AR5K_AR5212){ ++ ++ /* First set of mode-specific settings */ ++ ath5k_hw_ini_mode_registers(ah, ++ ARRAY_SIZE(ar5212_ini_mode_start), ++ ar5212_ini_mode_start, mode); ++ ++ /* ++ * Write initial settings common for all modes ++ */ ++ ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5212_ini), ++ ar5212_ini, change_channel); ++ ++ /* Second set of mode-specific settings */ ++ if (ah->ah_radio == AR5K_RF5111){ ++ ath5k_hw_ini_mode_registers(ah, ++ ARRAY_SIZE(ar5212_rf5111_ini_mode_end), ++ ar5212_rf5111_ini_mode_end, mode); ++ /* Baseband gain table */ ++ ath5k_hw_ini_registers(ah, ++ ARRAY_SIZE(rf5111_ini_bbgain), ++ rf5111_ini_bbgain, change_channel); ++ } else if (ah->ah_radio == AR5K_RF5112){ ++ ath5k_hw_ini_mode_registers(ah, ++ ARRAY_SIZE(ar5212_rf5112_ini_mode_end), ++ ar5212_rf5112_ini_mode_end, mode); ++ /* Baseband gain table */ ++ ath5k_hw_ini_registers(ah, ++ ARRAY_SIZE(rf5112_ini_bbgain), ++ rf5112_ini_bbgain, change_channel); ++ } else if (ah->ah_radio == AR5K_RF5413){ ++ ath5k_hw_ini_mode_registers(ah, ++ ARRAY_SIZE(rf5413_ini_mode_end), ++ rf5413_ini_mode_end, mode); ++ /* Baseband gain table */ ++ ath5k_hw_ini_registers(ah, ++ ARRAY_SIZE(rf5112_ini_bbgain), ++ rf5112_ini_bbgain, change_channel); ++ } ++ /* For AR5211 */ ++ } else if (ah->ah_version == AR5K_AR5211) { ++ ++ if(mode > 2){ /* AR5K_INI_VAL_11B */ ++ ATH5K_ERR(ah->ah_sc,"unsupported channel mode: %d\n", mode); ++ return -EINVAL; ++ } ++ ++ /* Mode-specific settings */ ++ ath5k_hw_ini_mode_registers(ah, ARRAY_SIZE(ar5211_ini_mode), ++ ar5211_ini_mode, mode); ++ ++ /* ++ * Write initial settings common for all modes ++ */ ++ ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5211_ini), ++ ar5211_ini, change_channel); ++ ++ /* AR5211 only comes with 5111 */ ++ ++ /* Baseband gain table */ ++ ath5k_hw_ini_registers(ah, ARRAY_SIZE(rf5111_ini_bbgain), ++ rf5111_ini_bbgain, change_channel); ++ /* For AR5210 (for mode settings check out ath5k_hw_reset_tx_queue) */ ++ } else if (ah->ah_version == AR5K_AR5210) { ++ ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5210_ini), ++ ar5210_ini, change_channel); ++ } ++ ++ return 0; ++} +diff -up /dev/null linux-2.6.23.noarch/drivers/net/wireless/ath5k/base.c +--- /dev/null 2007-12-21 08:33:07.834165456 -0500 ++++ linux-2.6.23.noarch/drivers/net/wireless/ath5k/base.c 2007-12-21 12:18:50.000000000 -0500 +@@ -0,0 +1,2822 @@ ++/*- ++ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting ++ * Copyright (c) 2004-2005 Atheros Communications, Inc. ++ * Copyright (c) 2006 Devicescape Software, Inc. ++ * Copyright (c) 2007 Jiri Slaby ++ * Copyright (c) 2007 Luis R. Rodriguez ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer, ++ * without modification. ++ * 2. Redistributions in binary form must reproduce at minimum a disclaimer ++ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any ++ * redistribution must be conditioned upon including a substantially ++ * similar Disclaimer requirement for further binary redistribution. ++ * 3. Neither the names of the above-listed copyright holders nor the names ++ * of any contributors may be used to endorse or promote products derived ++ * from this software without specific prior written permission. ++ * ++ * Alternatively, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") version 2 as published by the Free ++ * Software Foundation. ++ * ++ * NO WARRANTY ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY ++ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, ++ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER ++ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF ++ * THE POSSIBILITY OF SUCH DAMAGES. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++ ++#include "base.h" ++#include "reg.h" ++#include "debug.h" ++ ++/* unaligned little endian access */ ++#define LE_READ_2(_p) (le16_to_cpu(get_unaligned((__le16 *)(_p)))) ++#define LE_READ_4(_p) (le32_to_cpu(get_unaligned((__le32 *)(_p)))) ++ ++enum { ++ ATH_LED_TX, ++ ATH_LED_RX, ++}; ++ ++static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */ ++ ++ ++/******************\ ++* Internal defines * ++\******************/ ++ ++/* Module info */ ++MODULE_AUTHOR("Jiri Slaby"); ++MODULE_AUTHOR("Nick Kossifidis"); ++MODULE_DESCRIPTION("Support for 5xxx series of Atheros 802.11 wireless LAN cards."); ++MODULE_SUPPORTED_DEVICE("Atheros 5xxx WLAN cards"); ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_VERSION("0.1.1 (EXPERIMENTAL)"); ++ ++ ++/* Known PCI ids */ ++static struct pci_device_id ath5k_pci_id_table[] __devinitdata = { ++ { 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 }, /* 5424 Condor (PCI-E)*/ ++ { PCI_VDEVICE(ATHEROS, 0x0023), .driver_data = AR5K_AR5212 }, /* 5416 */ ++ { PCI_VDEVICE(ATHEROS, 0x0024), .driver_data = AR5K_AR5212 }, /* 5418 */ ++ { 0 } ++}; ++MODULE_DEVICE_TABLE(pci, ath5k_pci_id_table); ++ ++/* Known SREVs */ ++static struct ath5k_srev_name srev_names[] = { ++ { "5210", AR5K_VERSION_VER, AR5K_SREV_VER_AR5210 }, ++ { "5311", AR5K_VERSION_VER, AR5K_SREV_VER_AR5311 }, ++ { "5311A", AR5K_VERSION_VER, AR5K_SREV_VER_AR5311A }, ++ { "5311B", AR5K_VERSION_VER, AR5K_SREV_VER_AR5311B }, ++ { "5211", AR5K_VERSION_VER, AR5K_SREV_VER_AR5211 }, ++ { "5212", AR5K_VERSION_VER, AR5K_SREV_VER_AR5212 }, ++ { "5213", AR5K_VERSION_VER, AR5K_SREV_VER_AR5213 }, ++ { "5213A", AR5K_VERSION_VER, AR5K_SREV_VER_AR5213A }, ++ { "2424", AR5K_VERSION_VER, AR5K_SREV_VER_AR2424 }, ++ { "5424", AR5K_VERSION_VER, AR5K_SREV_VER_AR5424 }, ++ { "5413", AR5K_VERSION_VER, AR5K_SREV_VER_AR5413 }, ++ { "5414", AR5K_VERSION_VER, AR5K_SREV_VER_AR5414 }, ++ { "5416", AR5K_VERSION_VER, AR5K_SREV_VER_AR5416 }, ++ { "5418", AR5K_VERSION_VER, AR5K_SREV_VER_AR5418 }, ++ { "xxxxx", AR5K_VERSION_VER, AR5K_SREV_UNKNOWN }, ++ { "5110", AR5K_VERSION_RAD, AR5K_SREV_RAD_5110 }, ++ { "5111", AR5K_VERSION_RAD, AR5K_SREV_RAD_5111 }, ++ { "2111", AR5K_VERSION_RAD, AR5K_SREV_RAD_2111 }, ++ { "5112", AR5K_VERSION_RAD, AR5K_SREV_RAD_5112 }, ++ { "5112A", AR5K_VERSION_RAD, AR5K_SREV_RAD_5112A }, ++ { "2112", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112 }, ++ { "2112A", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112A }, ++ { "SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC1 }, ++ { "SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC2 }, ++ { "5133", AR5K_VERSION_RAD, AR5K_SREV_RAD_5133 }, ++ { "xxxxx", AR5K_VERSION_RAD, AR5K_SREV_UNKNOWN }, ++}; ++ ++/* ++ * Prototypes - PCI stack related functions ++ */ ++static int __devinit ath5k_pci_probe(struct pci_dev *pdev, ++ const struct pci_device_id *id); ++static void __devexit ath5k_pci_remove(struct pci_dev *pdev); ++#ifdef CONFIG_PM ++static int ath5k_pci_suspend(struct pci_dev *pdev, ++ pm_message_t state); ++static int ath5k_pci_resume(struct pci_dev *pdev); ++#else ++#define ath5k_pci_suspend NULL ++#define ath5k_pci_resume NULL ++#endif /* CONFIG_PM */ ++ ++static struct pci_driver ath5k_pci_drv_id = { ++ .name = "ath5k_pci", ++ .id_table = ath5k_pci_id_table, ++ .probe = ath5k_pci_probe, ++ .remove = __devexit_p(ath5k_pci_remove), ++ .suspend = ath5k_pci_suspend, ++ .resume = ath5k_pci_resume, ++}; ++ ++ ++ ++/* ++ * Prototypes - MAC 802.11 stack related functions ++ */ ++static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb, ++ struct ieee80211_tx_control *ctl); ++static int ath5k_reset(struct ieee80211_hw *hw); ++static int ath5k_start(struct ieee80211_hw *hw); ++static void ath5k_stop(struct ieee80211_hw *hw); ++static int ath5k_add_interface(struct ieee80211_hw *hw, ++ struct ieee80211_if_init_conf *conf); ++static void ath5k_remove_interface(struct ieee80211_hw *hw, ++ struct ieee80211_if_init_conf *conf); ++static int ath5k_config(struct ieee80211_hw *hw, ++ struct ieee80211_conf *conf); ++static int ath5k_config_interface(struct ieee80211_hw *hw, int if_id, ++ struct ieee80211_if_conf *conf); ++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); ++static int ath5k_set_key(struct ieee80211_hw *hw, ++ enum set_key_cmd cmd, ++ const u8 *local_addr, const u8 *addr, ++ struct ieee80211_key_conf *key); ++static int ath5k_get_stats(struct ieee80211_hw *hw, ++ struct ieee80211_low_level_stats *stats); ++static int ath5k_get_tx_stats(struct ieee80211_hw *hw, ++ struct ieee80211_tx_queue_stats *stats); ++static u64 ath5k_get_tsf(struct ieee80211_hw *hw); ++static void ath5k_reset_tsf(struct ieee80211_hw *hw); ++static int ath5k_beacon_update(struct ieee80211_hw *hw, ++ struct sk_buff *skb, ++ struct ieee80211_tx_control *ctl); ++ ++static struct ieee80211_ops ath5k_hw_ops = { ++ .tx = ath5k_tx, ++ .start = ath5k_start, ++ .stop = ath5k_stop, ++ .add_interface = ath5k_add_interface, ++ .remove_interface = ath5k_remove_interface, ++ .config = ath5k_config, ++ .config_interface = ath5k_config_interface, ++ .configure_filter = ath5k_configure_filter, ++ .set_key = ath5k_set_key, ++ .get_stats = ath5k_get_stats, ++ .conf_tx = NULL, ++ .get_tx_stats = ath5k_get_tx_stats, ++ .get_tsf = ath5k_get_tsf, ++ .reset_tsf = ath5k_reset_tsf, ++ .beacon_update = ath5k_beacon_update, ++}; ++ ++/* ++ * Prototypes - Internal functions ++ */ ++/* Attach detach */ ++static int ath5k_attach(struct pci_dev *pdev, ++ struct ieee80211_hw *hw); ++static void ath5k_detach(struct pci_dev *pdev, ++ struct ieee80211_hw *hw); ++/* Channel/mode setup */ ++static inline short ath5k_ieee2mhz(short chan); ++static unsigned int ath5k_copy_rates(struct ieee80211_rate *rates, ++ const struct ath5k_rate_table *rt, ++ unsigned int max); ++static unsigned int ath5k_copy_channels(struct ath5k_hw *ah, ++ struct ieee80211_channel *channels, ++ unsigned int mode, ++ unsigned int max); ++static int ath5k_getchannels(struct ieee80211_hw *hw); ++static int ath5k_chan_set(struct ath5k_softc *sc, ++ struct ieee80211_channel *chan); ++static void ath5k_setcurmode(struct ath5k_softc *sc, ++ unsigned int mode); ++static void ath5k_mode_setup(struct ath5k_softc *sc); ++/* Descriptor setup */ ++static int ath5k_desc_alloc(struct ath5k_softc *sc, ++ struct pci_dev *pdev); ++static void ath5k_desc_free(struct ath5k_softc *sc, ++ struct pci_dev *pdev); ++/* Buffers setup */ ++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 ieee80211_tx_control *ctl); ++ ++static inline void ath5k_txbuf_free(struct ath5k_softc *sc, ++ struct ath5k_buf *bf) ++{ ++ BUG_ON(!bf); ++ if (!bf->skb) ++ return; ++ pci_unmap_single(sc->pdev, bf->skbaddr, bf->skb->len, ++ PCI_DMA_TODEVICE); ++ dev_kfree_skb(bf->skb); ++ bf->skb = NULL; ++} ++ ++/* Queues setup */ ++static struct ath5k_txq *ath5k_txq_setup(struct ath5k_softc *sc, ++ int qtype, int subtype); ++static int ath5k_beaconq_setup(struct ath5k_hw *ah); ++static int ath5k_beaconq_config(struct ath5k_softc *sc); ++static void ath5k_txq_drainq(struct ath5k_softc *sc, ++ struct ath5k_txq *txq); ++static void ath5k_txq_cleanup(struct ath5k_softc *sc); ++static void ath5k_txq_release(struct ath5k_softc *sc); ++/* Rx handling */ ++static int ath5k_rx_start(struct ath5k_softc *sc); ++static void ath5k_rx_stop(struct ath5k_softc *sc); ++static unsigned int ath5k_rx_decrypted(struct ath5k_softc *sc, ++ struct ath5k_desc *ds, ++ struct sk_buff *skb); ++static void ath5k_tasklet_rx(unsigned long data); ++/* Tx handling */ ++static void ath5k_tx_processq(struct ath5k_softc *sc, ++ struct ath5k_txq *txq); ++static void ath5k_tasklet_tx(unsigned long data); ++/* Beacon handling */ ++static int ath5k_beacon_setup(struct ath5k_softc *sc, ++ struct ath5k_buf *bf, ++ struct ieee80211_tx_control *ctl); ++static void ath5k_beacon_send(struct ath5k_softc *sc); ++static void ath5k_beacon_config(struct ath5k_softc *sc); ++ ++static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp) ++{ ++ u64 tsf = ath5k_hw_get_tsf64(ah); ++ ++ if ((tsf & 0x7fff) < rstamp) ++ tsf -= 0x8000; ++ ++ return (tsf & ~0x7fff) | rstamp; ++} ++ ++/* Interrupt handling */ ++static int ath5k_init(struct ath5k_softc *sc); ++static int ath5k_stop_locked(struct ath5k_softc *sc); ++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); ++/* LED functions */ ++static void ath5k_led_off(unsigned long data); ++static void ath5k_led_blink(struct ath5k_softc *sc, ++ unsigned int on, ++ unsigned int off); ++static void ath5k_led_event(struct ath5k_softc *sc, ++ int event); ++ ++ ++/* ++ * Module init/exit functions ++ */ ++static int __init ++init_ath5k_pci(void) ++{ ++ int ret; ++ ++ ath5k_debug_init(); ++ ++ ret = pci_register_driver(&ath5k_pci_drv_id); ++ if (ret) { ++ printk(KERN_ERR "ath5k_pci: can't register pci driver\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void __exit ++exit_ath5k_pci(void) ++{ ++ pci_unregister_driver(&ath5k_pci_drv_id); ++ ++ ath5k_debug_finish(); ++} ++ ++module_init(init_ath5k_pci); ++module_exit(exit_ath5k_pci); ++ ++ ++/********************\ ++* PCI Initialization * ++\********************/ ++ ++static const char * ++ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val) ++{ ++ const char *name = "xxxxx"; ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(srev_names); i++) { ++ if (srev_names[i].sr_type != type) ++ continue; ++ if ((val & 0xff) < srev_names[i + 1].sr_val) { ++ name = srev_names[i].sr_name; ++ break; ++ } ++ } ++ ++ return name; ++} ++ ++static int __devinit ++ath5k_pci_probe(struct pci_dev *pdev, ++ const struct pci_device_id *id) ++{ ++ void __iomem *mem; ++ struct ath5k_softc *sc; ++ struct ieee80211_hw *hw; ++ int ret; ++ u8 csz; ++ ++ ret = pci_enable_device(pdev); ++ if (ret) { ++ dev_err(&pdev->dev, "can't enable device\n"); ++ goto err; ++ } ++ ++ /* XXX 32-bit addressing only */ ++ ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK); ++ if (ret) { ++ dev_err(&pdev->dev, "32-bit DMA not available\n"); ++ goto err_dis; ++ } ++ ++ /* ++ * Cache line size is used to size and align various ++ * structures used to communicate with the hardware. ++ */ ++ pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz); ++ if (csz == 0) { ++ /* ++ * Linux 2.4.18 (at least) writes the cache line size ++ * register as a 16-bit wide register which is wrong. ++ * We must have this setup properly for rx buffer ++ * DMA to work so force a reasonable value here if it ++ * comes up zero. ++ */ ++ csz = L1_CACHE_BYTES / sizeof(u32); ++ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz); ++ } ++ /* ++ * The default setting of latency timer yields poor results, ++ * set it to the value used by other systems. It may be worth ++ * tweaking this setting more. ++ */ ++ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8); ++ ++ /* Enable bus mastering */ ++ pci_set_master(pdev); ++ ++ /* ++ * Disable the RETRY_TIMEOUT register (0x41) to keep ++ * PCI Tx retries from interfering with C3 CPU state. ++ */ ++ pci_write_config_byte(pdev, 0x41, 0); ++ ++ ret = pci_request_region(pdev, 0, "ath5k"); ++ if (ret) { ++ dev_err(&pdev->dev, "cannot reserve PCI memory region\n"); ++ goto err_dis; ++ } ++ ++ mem = pci_iomap(pdev, 0, 0); ++ if (!mem) { ++ dev_err(&pdev->dev, "cannot remap PCI memory region\n") ; ++ ret = -EIO; ++ goto err_reg; ++ } ++ ++ /* ++ * Allocate hw (mac80211 main struct) ++ * and hw->priv (driver private data) ++ */ ++ hw = ieee80211_alloc_hw(sizeof(*sc), &ath5k_hw_ops); ++ if (hw == NULL) { ++ dev_err(&pdev->dev, "cannot allocate ieee80211_hw\n"); ++ ret = -ENOMEM; ++ goto err_map; ++ } ++ ++ dev_info(&pdev->dev, "registered as '%s'\n", wiphy_name(hw->wiphy)); ++ ++ /* Initialize driver private data */ ++ SET_IEEE80211_DEV(hw, &pdev->dev); ++ hw->flags = IEEE80211_HW_RX_INCLUDES_FCS; ++ hw->extra_tx_headroom = 2; ++ hw->channel_change_time = 5000; ++ /* these names are misleading */ ++ hw->max_rssi = -110; /* signal in dBm */ ++ hw->max_noise = -110; /* noise in dBm */ ++ hw->max_signal = 100; /* we will provide a percentage based on rssi */ ++ sc = hw->priv; ++ sc->hw = hw; ++ sc->pdev = pdev; ++ ++ ath5k_debug_init_device(sc); ++ ++ /* ++ * Mark the device as detached to avoid processing ++ * interrupts until setup is complete. ++ */ ++ __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->opmode = IEEE80211_IF_TYPE_STA; ++ mutex_init(&sc->lock); ++ spin_lock_init(&sc->rxbuflock); ++ spin_lock_init(&sc->txbuflock); ++ ++ /* Set private data */ ++ pci_set_drvdata(pdev, hw); ++ ++ /* Enable msi for devices that support it */ ++ pci_enable_msi(pdev); ++ ++ /* Setup interrupt handler */ ++ ret = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc); ++ if (ret) { ++ ATH5K_ERR(sc, "request_irq failed\n"); ++ goto err_free; ++ } ++ ++ /* Initialize device */ ++ sc->ah = ath5k_hw_attach(sc, id->driver_data); ++ if (IS_ERR(sc->ah)) { ++ ret = PTR_ERR(sc->ah); ++ goto err_irq; ++ } ++ ++ /* Finish private driver data initialization */ ++ ret = ath5k_attach(pdev, hw); ++ if (ret) ++ goto err_ah; ++ ++ ATH5K_INFO(sc, "Atheros AR%s chip found (MAC: 0x%x, PHY: 0x%x)\n", ++ ath5k_chip_name(AR5K_VERSION_VER,sc->ah->ah_mac_srev), ++ sc->ah->ah_mac_srev, ++ sc->ah->ah_phy_revision); ++ ++ if(!sc->ah->ah_single_chip){ ++ /* Single chip radio (!RF5111) */ ++ if(sc->ah->ah_radio_5ghz_revision && !sc->ah->ah_radio_2ghz_revision) { ++ /* No 5GHz support -> report 2GHz radio */ ++ if(!test_bit(MODE_IEEE80211A, sc->ah->ah_capabilities.cap_mode)){ ++ ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n", ++ ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_5ghz_revision), ++ sc->ah->ah_radio_5ghz_revision); ++ /* No 2GHz support (5110 and some 5Ghz only cards) -> report 5Ghz radio */ ++ } else if(!test_bit(MODE_IEEE80211B, sc->ah->ah_capabilities.cap_mode)){ ++ ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n", ++ ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_5ghz_revision), ++ sc->ah->ah_radio_5ghz_revision); ++ /* Multiband radio */ ++ } else { ++ ATH5K_INFO(sc, "RF%s multiband radio found" ++ " (0x%x)\n", ++ ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_5ghz_revision), ++ sc->ah->ah_radio_5ghz_revision); ++ } ++ } ++ /* Multi chip radio (RF5111 - RF2111) -> report both 2GHz/5GHz radios */ ++ else if(sc->ah->ah_radio_5ghz_revision && sc->ah->ah_radio_2ghz_revision){ ++ ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n", ++ ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_5ghz_revision), ++ sc->ah->ah_radio_5ghz_revision); ++ ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n", ++ ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_2ghz_revision), ++ sc->ah->ah_radio_2ghz_revision); ++ } ++ } ++ ++ ++ /* ready to process interrupts */ ++ __clear_bit(ATH_STAT_INVALID, sc->status); ++ ++ return 0; ++err_ah: ++ ath5k_hw_detach(sc->ah); ++err_irq: ++ free_irq(pdev->irq, sc); ++err_free: ++ pci_disable_msi(pdev); ++ ieee80211_free_hw(hw); ++err_map: ++ pci_iounmap(pdev, mem); ++err_reg: ++ pci_release_region(pdev, 0); ++err_dis: ++ pci_disable_device(pdev); ++err: ++ return ret; ++} ++ ++static void __devexit ++ath5k_pci_remove(struct pci_dev *pdev) ++{ ++ struct ieee80211_hw *hw = pci_get_drvdata(pdev); ++ struct ath5k_softc *sc = hw->priv; ++ ++ ath5k_debug_finish_device(sc); ++ ath5k_detach(pdev, hw); ++ ath5k_hw_detach(sc->ah); ++ free_irq(pdev->irq, sc); ++ pci_disable_msi(pdev); ++ pci_iounmap(pdev, sc->iobase); ++ pci_release_region(pdev, 0); ++ pci_disable_device(pdev); ++ ieee80211_free_hw(hw); ++} ++ ++#ifdef CONFIG_PM ++static int ++ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state) ++{ ++ struct ieee80211_hw *hw = pci_get_drvdata(pdev); ++ struct ath5k_softc *sc = hw->priv; ++ ++ if (test_bit(ATH_STAT_LEDSOFT, sc->status)) ++ ath5k_hw_set_gpio(sc->ah, sc->led_pin, 1); ++ ++ ath5k_stop_hw(sc); ++ pci_save_state(pdev); ++ pci_disable_device(pdev); ++ pci_set_power_state(pdev, PCI_D3hot); ++ ++ return 0; ++} ++ ++static int ++ath5k_pci_resume(struct pci_dev *pdev) ++{ ++ struct ieee80211_hw *hw = pci_get_drvdata(pdev); ++ struct ath5k_softc *sc = hw->priv; ++ int err; ++ ++ err = pci_set_power_state(pdev, PCI_D0); ++ if (err) ++ return err; ++ ++ 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 ++ * PCI Tx retries from interfering with C3 CPU state ++ */ ++ pci_write_config_byte(pdev, 0x41, 0); ++ ++ ath5k_init(sc); ++ if (test_bit(ATH_STAT_LEDSOFT, sc->status)) { ++ ath5k_hw_set_gpio_output(sc->ah, sc->led_pin); ++ ath5k_hw_set_gpio(sc->ah, sc->led_pin, 0); ++ } ++ ++ return 0; ++} ++#endif /* CONFIG_PM */ ++ ++ ++ ++/***********************\ ++* Driver Initialization * ++\***********************/ ++ ++static int ++ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) ++{ ++ struct ath5k_softc *sc = hw->priv; ++ struct ath5k_hw *ah = sc->ah; ++ u8 mac[ETH_ALEN]; ++ unsigned int i; ++ int ret; ++ ++ ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "devid 0x%x\n", pdev->device); ++ ++ /* ++ * Check if the MAC has multi-rate retry support. ++ * We do this by trying to setup a fake extended ++ * descriptor. MAC's that don't have support will ++ * return false w/o doing anything. MAC's that do ++ * support it will return true w/o doing anything. ++ */ ++ if (ah->ah_setup_xtx_desc(ah, NULL, 0, 0, 0, 0, 0, 0)) ++ __set_bit(ATH_STAT_MRRETRY, sc->status); ++ ++ /* ++ * Reset the key cache since some parts do not ++ * reset the contents on initial power up. ++ */ ++ for (i = 0; i < AR5K_KEYCACHE_SIZE; i++) ++ ath5k_hw_reset_key(ah, i); ++ ++ /* ++ * Collect the channel list. The 802.11 layer ++ * is resposible for filtering this list based ++ * on settings like the phy mode and regulatory ++ * domain restrictions. ++ */ ++ ret = ath5k_getchannels(hw); ++ if (ret) { ++ ATH5K_ERR(sc, "can't get channels\n"); ++ goto err; ++ } ++ ++ /* NB: setup here so ath5k_rate_update is happy */ ++ if (test_bit(MODE_IEEE80211A, ah->ah_modes)) ++ ath5k_setcurmode(sc, MODE_IEEE80211A); ++ else ++ ath5k_setcurmode(sc, MODE_IEEE80211B); ++ ++ /* ++ * Allocate tx+rx descriptors and populate the lists. ++ */ ++ ret = ath5k_desc_alloc(sc, pdev); ++ if (ret) { ++ ATH5K_ERR(sc, "can't allocate descriptors\n"); ++ goto err; ++ } ++ ++ /* ++ * Allocate hardware transmit queues: one queue for ++ * beacon frames and one data queue for each QoS ++ * priority. Note that hw functions handle reseting ++ * these queues at the needed time. ++ */ ++ ret = ath5k_beaconq_setup(ah); ++ if (ret < 0) { ++ ATH5K_ERR(sc, "can't setup a beacon xmit queue\n"); ++ goto err_desc; ++ } ++ sc->bhalq = ret; ++ ++ 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; ++ } ++ ++ 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); ++ setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc); ++ setup_timer(&sc->led_tim, ath5k_led_off, (unsigned long)sc); ++ ++ sc->led_on = 0; /* low true */ ++ /* ++ * Auto-enable soft led processing for IBM cards and for ++ * 5211 minipci cards. ++ */ ++ if (pdev->device == PCI_DEVICE_ID_ATHEROS_AR5212_IBM || ++ pdev->device == PCI_DEVICE_ID_ATHEROS_AR5211) { ++ __set_bit(ATH_STAT_LEDSOFT, sc->status); ++ sc->led_pin = 0; ++ } ++ /* Enable softled on PIN1 on HP Compaq nc6xx, nc4000 & nx5000 laptops */ ++ if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ) { ++ __set_bit(ATH_STAT_LEDSOFT, sc->status); ++ sc->led_pin = 0; ++ } ++ if (test_bit(ATH_STAT_LEDSOFT, sc->status)) { ++ ath5k_hw_set_gpio_output(ah, sc->led_pin); ++ ath5k_hw_set_gpio(ah, sc->led_pin, !sc->led_on); ++ } ++ ++ ath5k_hw_get_lladdr(ah, mac); ++ SET_IEEE80211_PERM_ADDR(hw, mac); ++ /* All MAC address bits matter for ACKs */ ++ memset(sc->bssidmask, 0xff, ETH_ALEN); ++ ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask); ++ ++ ret = ieee80211_register_hw(hw); ++ if (ret) { ++ ATH5K_ERR(sc, "can't register ieee80211 hw\n"); ++ goto err_queues; ++ } ++ ++ return 0; ++err_queues: ++ ath5k_txq_release(sc); ++err_bhal: ++ ath5k_hw_release_tx_queue(ah, sc->bhalq); ++err_desc: ++ ath5k_desc_free(sc, pdev); ++err: ++ return ret; ++} ++ ++static void ++ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw) ++{ ++ struct ath5k_softc *sc = hw->priv; ++ ++ /* ++ * NB: the order of these is important: ++ * o call the 802.11 layer before detaching ath5k_hw to ++ * insure callbacks into the driver to delete global ++ * key cache entries can be handled ++ * o reclaim the tx queue data structures after calling ++ * the 802.11 layer as we'll get called back to reclaim ++ * node state and potentially want to use them ++ * o to cleanup the tx queues the hal is called, so detach ++ * it last ++ * XXX: ??? detach ath5k_hw ??? ++ * Other than that, it's straightforward... ++ */ ++ ieee80211_unregister_hw(hw); ++ ath5k_desc_free(sc, pdev); ++ ath5k_txq_release(sc); ++ ath5k_hw_release_tx_queue(sc->ah, sc->bhalq); ++ ++ /* ++ * NB: can't reclaim these until after ieee80211_ifdetach ++ * returns because we'll get called back to reclaim node ++ * state and potentially want to use them. ++ */ ++} ++ ++ ++ ++ ++/********************\ ++* Channel/mode setup * ++\********************/ ++ ++/* ++ * Convert IEEE channel number to MHz frequency. ++ */ ++static inline short ++ath5k_ieee2mhz(short chan) ++{ ++ if (chan <= 14 || chan >= 27) ++ return ieee80211chan2mhz(chan); ++ else ++ return 2212 + chan * 20; ++} ++ ++static unsigned int ++ath5k_copy_rates(struct ieee80211_rate *rates, ++ const struct ath5k_rate_table *rt, ++ unsigned int max) ++{ ++ unsigned int i, count; ++ ++ if (rt == NULL) ++ return 0; ++ ++ for (i = 0, count = 0; i < rt->rate_count && max > 0; i++) { ++ if (!rt->rates[i].valid) ++ continue; ++ rates->rate = rt->rates[i].rate_kbps / 100; ++ rates->val = rt->rates[i].rate_code; ++ rates->flags = rt->rates[i].modulation; ++ rates++; ++ count++; ++ max--; ++ } ++ ++ return count; ++} ++ ++static unsigned int ++ath5k_copy_channels(struct ath5k_hw *ah, ++ struct ieee80211_channel *channels, ++ unsigned int mode, ++ unsigned int max) ++{ ++ static const struct { unsigned int mode, mask, chan; } map[] = { ++ [MODE_IEEE80211A] = { CHANNEL_OFDM, CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_A }, ++ [MODE_ATHEROS_TURBO] = { CHANNEL_OFDM|CHANNEL_TURBO, CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_T }, ++ [MODE_IEEE80211B] = { CHANNEL_CCK, CHANNEL_CCK, CHANNEL_B }, ++ [MODE_IEEE80211G] = { CHANNEL_OFDM, CHANNEL_OFDM, CHANNEL_G }, ++ [MODE_ATHEROS_TURBOG] = { CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_TG }, ++ }; ++ static const struct ath5k_regchannel chans_2ghz[] = ++ IEEE80211_CHANNELS_2GHZ; ++ static const struct ath5k_regchannel chans_5ghz[] = ++ IEEE80211_CHANNELS_5GHZ; ++ const struct ath5k_regchannel *chans; ++ enum ath5k_regdom dmn; ++ unsigned int i, count, size, chfreq, all, f, ch; ++ ++ if (!test_bit(mode, ah->ah_modes)) ++ return 0; ++ ++ all = ah->ah_regdomain == DMN_DEFAULT || CHAN_DEBUG == 1; ++ ++ switch (mode) { ++ case MODE_IEEE80211A: ++ case MODE_ATHEROS_TURBO: ++ /* 1..220, but 2GHz frequencies are filtered by check_channel */ ++ size = all ? 220 : ARRAY_SIZE(chans_5ghz); ++ chans = chans_5ghz; ++ dmn = ath5k_regdom2flag(ah->ah_regdomain, ++ IEEE80211_CHANNELS_5GHZ_MIN); ++ chfreq = CHANNEL_5GHZ; ++ break; ++ case MODE_IEEE80211B: ++ case MODE_IEEE80211G: ++ case MODE_ATHEROS_TURBOG: ++ size = all ? 26 : ARRAY_SIZE(chans_2ghz); ++ chans = chans_2ghz; ++ dmn = ath5k_regdom2flag(ah->ah_regdomain, ++ IEEE80211_CHANNELS_2GHZ_MIN); ++ chfreq = CHANNEL_2GHZ; ++ break; ++ default: ++ ATH5K_WARN(ah->ah_sc, "bad mode, not copying channels\n"); ++ return 0; ++ } ++ ++ for (i = 0, count = 0; i < size && max > 0; i++) { ++ ch = all ? i + 1 : chans[i].chan; ++ f = ath5k_ieee2mhz(ch); ++ /* Check if channel is supported by the chipset */ ++ if (!ath5k_channel_ok(ah, f, chfreq)) ++ continue; ++ ++ /* Match regulation domain */ ++ if (!all && !(IEEE80211_DMN(chans[i].domain) & ++ IEEE80211_DMN(dmn))) ++ continue; ++ ++ if (!all && (chans[i].mode & map[mode].mask) != map[mode].mode) ++ continue; ++ ++ /* Write channel and increment counter */ ++ channels->chan = ch; ++ channels->freq = f; ++ channels->val = map[mode].chan; ++ channels++; ++ count++; ++ max--; ++ } ++ ++ return count; ++} ++ ++/* Only tries to register modes our EEPROM says it can support */ ++#define REGISTER_MODE(m) do { \ ++ ret = ath5k_register_mode(hw, m); \ ++ if (ret) \ ++ return ret; \ ++} while (0) \ ++ ++static inline int ++ath5k_register_mode(struct ieee80211_hw *hw, u8 m) ++{ ++ struct ath5k_softc *sc = hw->priv; ++ struct ieee80211_hw_mode *modes = sc->modes; ++ unsigned int i; ++ int ret; ++ ++ if (!test_bit(m, sc->ah->ah_capabilities.cap_mode)) ++ return 0; ++ ++ for (i = 0; i < NUM_DRIVER_MODES; i++) { ++ if (modes[i].mode != m || !modes[i].num_channels) ++ continue; ++ ret = ieee80211_register_hwmode(hw, &modes[i]); ++ if (ret) { ++ ATH5K_ERR(sc, "can't register hwmode %u\n", m); ++ return ret; ++ } ++ return 0; ++ } ++ BUG(); ++} ++ ++static int ++ath5k_getchannels(struct ieee80211_hw *hw) ++{ ++ struct ath5k_softc *sc = hw->priv; ++ struct ath5k_hw *ah = sc->ah; ++ struct ieee80211_hw_mode *modes = sc->modes; ++ unsigned int i, max_r, max_c; ++ int ret; ++ ++ BUILD_BUG_ON(ARRAY_SIZE(sc->modes) < 3); ++ ++ /* The order here does not matter */ ++ modes[0].mode = MODE_IEEE80211G; ++ modes[1].mode = MODE_IEEE80211B; ++ modes[2].mode = MODE_IEEE80211A; ++ ++ max_r = ARRAY_SIZE(sc->rates); ++ max_c = ARRAY_SIZE(sc->channels); ++ ++ for (i = 0; i < NUM_DRIVER_MODES; i++) { ++ struct ieee80211_hw_mode *mode = &modes[i]; ++ const struct ath5k_rate_table *hw_rates; ++ ++ if (i == 0) { ++ modes[0].rates = sc->rates; ++ modes->channels = sc->channels; ++ } else { ++ struct ieee80211_hw_mode *prev_mode = &modes[i-1]; ++ int prev_num_r = prev_mode->num_rates; ++ int prev_num_c = prev_mode->num_channels; ++ mode->rates = &prev_mode->rates[prev_num_r]; ++ mode->channels = &prev_mode->channels[prev_num_c]; ++ } ++ ++ hw_rates = ath5k_hw_get_rate_table(ah, mode->mode); ++ mode->num_rates = ath5k_copy_rates(mode->rates, hw_rates, ++ max_r); ++ mode->num_channels = ath5k_copy_channels(ah, mode->channels, ++ mode->mode, max_c); ++ max_r -= mode->num_rates; ++ max_c -= mode->num_channels; ++ } ++ ++ /* We try to register all modes this driver supports. We don't bother ++ * with MODE_IEEE80211B for AR5212 as MODE_IEEE80211G already accounts ++ * for that as per mac80211. Then, REGISTER_MODE() will will actually ++ * check the eeprom reading for more reliable capability information. ++ * Order matters here as per mac80211's latest preference. This will ++ * all hopefullly soon go away. */ ++ ++ REGISTER_MODE(MODE_IEEE80211G); ++ if (ah->ah_version != AR5K_AR5212) ++ REGISTER_MODE(MODE_IEEE80211B); ++ REGISTER_MODE(MODE_IEEE80211A); ++ ++ ath5k_debug_dump_modes(sc, modes); ++ ++ return ret; ++} ++ ++/* ++ * 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. ++ */ ++static int ++ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan) ++{ ++ struct ath5k_hw *ah = sc->ah; ++ int ret; ++ ++ ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "%u (%u MHz) -> %u (%u MHz)\n", ++ sc->curchan->chan, sc->curchan->freq, ++ chan->chan, chan->freq); ++ ++ if (chan->freq != sc->curchan->freq || chan->val != sc->curchan->val) { ++ /* ++ * 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. ++ */ ++ ath5k_hw_set_intr(ah, 0); /* disable interrupts */ ++ ath5k_txq_cleanup(sc); /* clear pending tx frames */ ++ ath5k_rx_stop(sc); /* turn off frame recv */ ++ ret = ath5k_hw_reset(ah, sc->opmode, chan, true); ++ if (ret) { ++ ATH5K_ERR(sc, "%s: unable to reset channel %u " ++ "(%u Mhz)\n", __func__, chan->chan, chan->freq); ++ return ret; ++ } ++ sc->curchan = chan; ++ ath5k_hw_set_txpower_limit(sc->ah, 0); ++ ++ /* ++ * Re-enable rx framework. ++ */ ++ ret = ath5k_rx_start(sc); ++ if (ret) { ++ ATH5K_ERR(sc, "%s: unable to restart recv logic\n", ++ __func__); ++ return ret; ++ } ++ ++ /* ++ * Change channels and update the h/w rate map ++ * if we're switching; e.g. 11a to 11b/g. ++ * ++ * XXX needed? ++ */ ++/* ath5k_chan_change(sc, chan); */ ++ ++ /* ++ * Re-enable interrupts. ++ */ ++ ath5k_hw_set_intr(ah, sc->imask); ++ } ++ ++ return 0; ++} ++ ++static void ++ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode) ++{ ++ if (unlikely(test_bit(ATH_STAT_LEDSOFT, sc->status))) { ++ /* from Atheros NDIS driver, w/ permission */ ++ static const struct { ++ u16 rate; /* tx/rx 802.11 rate */ ++ u16 timeOn; /* LED on time (ms) */ ++ u16 timeOff; /* LED off time (ms) */ ++ } blinkrates[] = { ++ { 108, 40, 10 }, ++ { 96, 44, 11 }, ++ { 72, 50, 13 }, ++ { 48, 57, 14 }, ++ { 36, 67, 16 }, ++ { 24, 80, 20 }, ++ { 22, 100, 25 }, ++ { 18, 133, 34 }, ++ { 12, 160, 40 }, ++ { 10, 200, 50 }, ++ { 6, 240, 58 }, ++ { 4, 267, 66 }, ++ { 2, 400, 100 }, ++ { 0, 500, 130 } ++ }; ++ const struct ath5k_rate_table *rt = ++ ath5k_hw_get_rate_table(sc->ah, mode); ++ unsigned int i, j; ++ ++ BUG_ON(rt == NULL); ++ ++ memset(sc->hwmap, 0, sizeof(sc->hwmap)); ++ for (i = 0; i < 32; i++) { ++ u8 ix = rt->rate_code_to_index[i]; ++ if (ix == 0xff) { ++ sc->hwmap[i].ledon = msecs_to_jiffies(500); ++ sc->hwmap[i].ledoff = msecs_to_jiffies(130); ++ continue; ++ } ++ sc->hwmap[i].txflags = IEEE80211_RADIOTAP_F_DATAPAD; ++ if (SHPREAMBLE_FLAG(ix) || rt->rates[ix].modulation == ++ IEEE80211_RATE_OFDM) ++ sc->hwmap[i].txflags |= ++ IEEE80211_RADIOTAP_F_SHORTPRE; ++ /* receive frames include FCS */ ++ sc->hwmap[i].rxflags = sc->hwmap[i].txflags | ++ IEEE80211_RADIOTAP_F_FCS; ++ /* setup blink rate table to avoid per-packet lookup */ ++ for (j = 0; j < ARRAY_SIZE(blinkrates) - 1; j++) ++ if (blinkrates[j].rate == /* XXX why 7f? */ ++ (rt->rates[ix].dot11_rate&0x7f)) ++ break; ++ ++ sc->hwmap[i].ledon = msecs_to_jiffies(blinkrates[j]. ++ timeOn); ++ sc->hwmap[i].ledoff = msecs_to_jiffies(blinkrates[j]. ++ timeOff); ++ } ++ } ++ ++ sc->curmode = mode; ++} ++ ++static void ++ath5k_mode_setup(struct ath5k_softc *sc) ++{ ++ struct ath5k_hw *ah = sc->ah; ++ u32 rfilt; ++ ++ /* configure rx filter */ ++ rfilt = sc->filter_flags; ++ ath5k_hw_set_rx_filter(ah, rfilt); ++ ++ if (ath5k_hw_hasbssidmask(ah)) ++ ath5k_hw_set_bssid_mask(ah, sc->bssidmask); ++ ++ /* configure operational mode */ ++ ath5k_hw_set_opmode(ah); ++ ++ ath5k_hw_set_mcast_filter(ah, 0, 0); ++ ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "RX filter 0x%x\n", rfilt); ++} ++ ++ ++ ++ ++/***************\ ++* Buffers setup * ++\***************/ ++ ++static int ++ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) ++{ ++ struct ath5k_hw *ah = sc->ah; ++ struct sk_buff *skb = bf->skb; ++ struct ath5k_desc *ds; ++ ++ if (likely(skb == NULL)) { ++ 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); ++ if (unlikely(skb == NULL)) { ++ ATH5K_ERR(sc, "can't alloc skbuff of size %u\n", ++ sc->rxbufsize + sc->cachelsz - 1); ++ return -ENOMEM; ++ } ++ /* ++ * 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); ++ ++ bf->skb = skb; ++ bf->skbaddr = pci_map_single(sc->pdev, ++ skb->data, sc->rxbufsize, PCI_DMA_FROMDEVICE); ++ if (unlikely(pci_dma_mapping_error(bf->skbaddr))) { ++ ATH5K_ERR(sc, "%s: DMA mapping failed\n", __func__); ++ dev_kfree_skb(skb); ++ bf->skb = NULL; ++ return -ENOMEM; ++ } ++ } ++ ++ /* ++ * Setup descriptors. For receive we always terminate ++ * the descriptor list with a self-linked entry so we'll ++ * not get overrun under high load (as can happen with a ++ * 5212 when ANI processing enables PHY error frames). ++ * ++ * To insure the last descriptor is self-linked we create ++ * each descriptor as self-linked and add it to the end. As ++ * each additional descriptor is added the previous self-linked ++ * entry is ``fixed'' naturally. This should be safe even ++ * if DMA is happening. When processing RX interrupts we ++ * never remove/process the last, self-linked, entry on the ++ * descriptor list. This insures the hardware always has ++ * someplace to write a new frame. ++ */ ++ ds = bf->desc; ++ ds->ds_link = bf->daddr; /* link to self */ ++ ds->ds_data = bf->skbaddr; ++ ath5k_hw_setup_rx_desc(ah, ds, ++ skb_tailroom(skb), /* buffer size */ ++ 0); ++ ++ if (sc->rxlink != NULL) ++ *sc->rxlink = bf->daddr; ++ sc->rxlink = &ds->ds_link; ++ return 0; ++} ++ ++static int ++ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, ++ struct ieee80211_tx_control *ctl) ++{ ++ struct ath5k_hw *ah = sc->ah; ++ struct ath5k_txq *txq = sc->txq; ++ struct ath5k_desc *ds = bf->desc; ++ struct sk_buff *skb = bf->skb; ++ unsigned int pktlen, flags, keyidx = AR5K_TXKEYIX_INVALID; ++ int ret; ++ ++ flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK; ++ bf->ctl = *ctl; ++ /* XXX endianness */ ++ bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len, ++ PCI_DMA_TODEVICE); ++ ++ if (ctl->flags & IEEE80211_TXCTL_NO_ACK) ++ flags |= AR5K_TXDESC_NOACK; ++ ++ pktlen = skb->len + FCS_LEN; ++ ++ if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) { ++ keyidx = ctl->key_idx; ++ pktlen += ctl->icv_len; ++ } ++ ++ ret = ah->ah_setup_tx_desc(ah, ds, pktlen, ++ ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, ++ (ctl->power_level * 2), ctl->tx_rate, ctl->retry_limit, keyidx, 0, flags, 0, 0); ++ if (ret) ++ goto err_unmap; ++ ++ ds->ds_link = 0; ++ ds->ds_data = bf->skbaddr; ++ ++ spin_lock_bh(&txq->lock); ++ list_add_tail(&bf->list, &txq->q); ++ sc->tx_stats.data[txq->qnum].len++; ++ if (txq->link == NULL) /* is this first packet? */ ++ ath5k_hw_put_tx_buf(ah, txq->qnum, bf->daddr); ++ else /* no, so only link it */ ++ *txq->link = bf->daddr; ++ ++ txq->link = &ds->ds_link; ++ ath5k_hw_tx_start(ah, txq->qnum); ++ spin_unlock_bh(&txq->lock); ++ ++ return 0; ++err_unmap: ++ pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE); ++ return ret; ++} ++ ++/*******************\ ++* Descriptors setup * ++\*******************/ ++ ++static int ++ath5k_desc_alloc(struct ath5k_softc *sc, struct pci_dev *pdev) ++{ ++ struct ath5k_desc *ds; ++ struct ath5k_buf *bf; ++ dma_addr_t da; ++ unsigned int i; ++ int ret; ++ ++ /* allocate descriptors */ ++ sc->desc_len = sizeof(struct ath5k_desc) * ++ (ATH_TXBUF + ATH_RXBUF + ATH_BCBUF + 1); ++ sc->desc = pci_alloc_consistent(pdev, sc->desc_len, &sc->desc_daddr); ++ if (sc->desc == NULL) { ++ ATH5K_ERR(sc, "can't allocate descriptors\n"); ++ ret = -ENOMEM; ++ goto err; ++ } ++ ds = sc->desc; ++ da = sc->desc_daddr; ++ ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "DMA map: %p (%zu) -> %llx\n", ++ ds, sc->desc_len, (unsigned long long)sc->desc_daddr); ++ ++ bf = kcalloc(1 + ATH_TXBUF + ATH_RXBUF + ATH_BCBUF, ++ sizeof(struct ath5k_buf), GFP_KERNEL); ++ if (bf == NULL) { ++ ATH5K_ERR(sc, "can't allocate bufptr\n"); ++ ret = -ENOMEM; ++ goto err_free; ++ } ++ sc->bufptr = bf; ++ ++ INIT_LIST_HEAD(&sc->rxbuf); ++ for (i = 0; i < ATH_RXBUF; i++, bf++, ds++, da += sizeof(*ds)) { ++ bf->desc = ds; ++ bf->daddr = da; ++ list_add_tail(&bf->list, &sc->rxbuf); ++ } ++ ++ INIT_LIST_HEAD(&sc->txbuf); ++ sc->txbuf_len = ATH_TXBUF; ++ for (i = 0; i < ATH_TXBUF; i++, bf++, ds++, ++ da += sizeof(*ds)) { ++ bf->desc = ds; ++ bf->daddr = da; ++ list_add_tail(&bf->list, &sc->txbuf); ++ } ++ ++ /* beacon buffer */ ++ bf->desc = ds; ++ bf->daddr = da; ++ sc->bbuf = bf; ++ ++ return 0; ++err_free: ++ pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr); ++err: ++ sc->desc = NULL; ++ return ret; ++} ++ ++static void ++ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev) ++{ ++ struct ath5k_buf *bf; ++ ++ ath5k_txbuf_free(sc, sc->bbuf); ++ list_for_each_entry(bf, &sc->txbuf, list) ++ ath5k_txbuf_free(sc, bf); ++ list_for_each_entry(bf, &sc->rxbuf, list) ++ ath5k_txbuf_free(sc, bf); ++ ++ /* Free memory associated with all descriptors */ ++ pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr); ++ ++ kfree(sc->bufptr); ++ sc->bufptr = NULL; ++} ++ ++ ++ ++ ++ ++/**************\ ++* Queues setup * ++\**************/ ++ ++static struct ath5k_txq * ++ath5k_txq_setup(struct ath5k_softc *sc, ++ int qtype, int subtype) ++{ ++ struct ath5k_hw *ah = sc->ah; ++ struct ath5k_txq *txq; ++ struct ath5k_txq_info qi = { ++ .tqi_subtype = subtype, ++ .tqi_aifs = AR5K_TXQ_USEDEFAULT, ++ .tqi_cw_min = AR5K_TXQ_USEDEFAULT, ++ .tqi_cw_max = AR5K_TXQ_USEDEFAULT ++ }; ++ int qnum; ++ ++ /* ++ * Enable interrupts only for EOL and DESC conditions. ++ * We mark tx descriptors to receive a DESC interrupt ++ * when a tx queue gets deep; otherwise waiting for the ++ * EOL to reap descriptors. Note that this is done to ++ * reduce interrupt load and this only defers reaping ++ * descriptors, never transmitting frames. Aside from ++ * reducing interrupts this also permits more concurrency. ++ * The only potential downside is if the tx queue backs ++ * up in which case the top half of the kernel may backup ++ * due to a lack of tx descriptors. ++ */ ++ qi.tqi_flags = AR5K_TXQ_FLAG_TXEOLINT_ENABLE | ++ AR5K_TXQ_FLAG_TXDESCINT_ENABLE; ++ qnum = ath5k_hw_setup_tx_queue(ah, qtype, &qi); ++ if (qnum < 0) { ++ /* ++ * NB: don't print a message, this happens ++ * normally on parts with too few tx queues ++ */ ++ return ERR_PTR(qnum); ++ } ++ if (qnum >= ARRAY_SIZE(sc->txqs)) { ++ ATH5K_ERR(sc, "hw qnum %u out of range, max %tu!\n", ++ qnum, ARRAY_SIZE(sc->txqs)); ++ ath5k_hw_release_tx_queue(ah, qnum); ++ return ERR_PTR(-EINVAL); ++ } ++ txq = &sc->txqs[qnum]; ++ if (!txq->setup) { ++ txq->qnum = qnum; ++ txq->link = NULL; ++ INIT_LIST_HEAD(&txq->q); ++ spin_lock_init(&txq->lock); ++ txq->setup = true; ++ } ++ return &sc->txqs[qnum]; ++} ++ ++static int ++ath5k_beaconq_setup(struct ath5k_hw *ah) ++{ ++ struct ath5k_txq_info qi = { ++ .tqi_aifs = AR5K_TXQ_USEDEFAULT, ++ .tqi_cw_min = AR5K_TXQ_USEDEFAULT, ++ .tqi_cw_max = AR5K_TXQ_USEDEFAULT, ++ /* NB: for dynamic turbo, don't enable any other interrupts */ ++ .tqi_flags = AR5K_TXQ_FLAG_TXDESCINT_ENABLE ++ }; ++ ++ return ath5k_hw_setup_tx_queue(ah, AR5K_TX_QUEUE_BEACON, &qi); ++} ++ ++static int ++ath5k_beaconq_config(struct ath5k_softc *sc) ++{ ++ struct ath5k_hw *ah = sc->ah; ++ struct ath5k_txq_info qi; ++ int ret; ++ ++ ret = ath5k_hw_get_tx_queueprops(ah, sc->bhalq, &qi); ++ if (ret) ++ return ret; ++ if (sc->opmode == IEEE80211_IF_TYPE_AP || ++ sc->opmode == IEEE80211_IF_TYPE_IBSS) { ++ /* ++ * Always burst out beacon and CAB traffic ++ * (aifs = cwmin = cwmax = 0) ++ */ ++ qi.tqi_aifs = 0; ++ qi.tqi_cw_min = 0; ++ qi.tqi_cw_max = 0; ++ } ++ ++ ret = ath5k_hw_setup_tx_queueprops(ah, sc->bhalq, &qi); ++ if (ret) { ++ ATH5K_ERR(sc, "%s: unable to update parameters for beacon " ++ "hardware queue!\n", __func__); ++ return ret; ++ } ++ ++ return ath5k_hw_reset_tx_queue(ah, sc->bhalq); /* push to h/w */; ++} ++ ++static void ++ath5k_txq_drainq(struct ath5k_softc *sc, struct ath5k_txq *txq) ++{ ++ struct ath5k_buf *bf, *bf0; ++ ++ /* ++ * NB: this assumes output has been stopped and ++ * we do not need to block ath5k_tx_tasklet ++ */ ++ spin_lock_bh(&txq->lock); ++ list_for_each_entry_safe(bf, bf0, &txq->q, list) { ++ ath5k_debug_printtxbuf(sc, bf, !sc->ah->ah_proc_tx_desc(sc->ah, ++ bf->desc)); ++ ++ ath5k_txbuf_free(sc, bf); ++ ++ spin_lock_bh(&sc->txbuflock); ++ sc->tx_stats.data[txq->qnum].len--; ++ list_move_tail(&bf->list, &sc->txbuf); ++ sc->txbuf_len++; ++ spin_unlock_bh(&sc->txbuflock); ++ } ++ txq->link = NULL; ++ spin_unlock_bh(&txq->lock); ++} ++ ++/* ++ * Drain the transmit queues and reclaim resources. ++ */ ++static void ++ath5k_txq_cleanup(struct ath5k_softc *sc) ++{ ++ struct ath5k_hw *ah = sc->ah; ++ unsigned int i; ++ ++ /* XXX return value */ ++ if (likely(!test_bit(ATH_STAT_INVALID, sc->status))) { ++ /* don't touch the hardware if marked invalid */ ++ (void)ath5k_hw_stop_tx_dma(ah, sc->bhalq); ++ ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "beacon queue %x\n", ++ ath5k_hw_get_tx_buf(ah, sc->bhalq)); ++ for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) ++ if (sc->txqs[i].setup) { ++ ath5k_hw_stop_tx_dma(ah, sc->txqs[i].qnum); ++ ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "txq [%u] %x, " ++ "link %p\n", ++ sc->txqs[i].qnum, ++ ath5k_hw_get_tx_buf(ah, ++ sc->txqs[i].qnum), ++ sc->txqs[i].link); ++ } ++ } ++ ieee80211_start_queues(sc->hw); /* XXX move to callers */ ++ ++ for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) ++ if (sc->txqs[i].setup) ++ ath5k_txq_drainq(sc, &sc->txqs[i]); ++} ++ ++static void ++ath5k_txq_release(struct ath5k_softc *sc) ++{ ++ struct ath5k_txq *txq = sc->txqs; ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(sc->txqs); i++, txq++) ++ if (txq->setup) { ++ ath5k_hw_release_tx_queue(sc->ah, txq->qnum); ++ txq->setup = false; ++ } ++} ++ ++ ++ ++ ++/*************\ ++* RX Handling * ++\*************/ ++ ++/* ++ * Enable the receive h/w following a reset. ++ */ ++static int ++ath5k_rx_start(struct ath5k_softc *sc) ++{ ++ struct ath5k_hw *ah = sc->ah; ++ struct ath5k_buf *bf; ++ int ret; ++ ++ sc->rxbufsize = roundup(IEEE80211_MAX_LEN, sc->cachelsz); ++ ++ ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rxbufsize %u\n", ++ sc->cachelsz, sc->rxbufsize); ++ ++ sc->rxlink = NULL; ++ ++ spin_lock_bh(&sc->rxbuflock); ++ list_for_each_entry(bf, &sc->rxbuf, list) { ++ ret = ath5k_rxbuf_setup(sc, bf); ++ if (ret != 0) { ++ spin_unlock_bh(&sc->rxbuflock); ++ goto err; ++ } ++ } ++ bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list); ++ spin_unlock_bh(&sc->rxbuflock); ++ ++ ath5k_hw_put_rx_buf(ah, bf->daddr); ++ ath5k_hw_start_rx(ah); /* enable recv descriptors */ ++ ath5k_mode_setup(sc); /* set filters, etc. */ ++ ath5k_hw_start_rx_pcu(ah); /* re-enable PCU/DMA engine */ ++ ++ return 0; ++err: ++ return ret; ++} ++ ++/* ++ * Disable the receive h/w in preparation for a reset. ++ */ ++static void ++ath5k_rx_stop(struct ath5k_softc *sc) ++{ ++ struct ath5k_hw *ah = sc->ah; ++ ++ ath5k_hw_stop_pcu_recv(ah); /* disable PCU */ ++ ath5k_hw_set_rx_filter(ah, 0); /* clear recv filter */ ++ ath5k_hw_stop_rx_dma(ah); /* disable DMA engine */ ++ mdelay(3); /* 3ms is long enough for 1 frame */ ++ ++ ath5k_debug_printrxbuffs(sc, ah); ++ ++ sc->rxlink = NULL; /* just in case */ ++} ++ ++static unsigned int ++ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds, ++ struct sk_buff *skb) ++{ ++ struct ieee80211_hdr *hdr = (void *)skb->data; ++ unsigned int keyix, hlen = ieee80211_get_hdrlen_from_skb(skb); ++ ++ if (!(ds->ds_rxstat.rs_status & AR5K_RXERR_DECRYPT) && ++ ds->ds_rxstat.rs_keyix != AR5K_RXKEYIX_INVALID) ++ return RX_FLAG_DECRYPTED; ++ ++ /* Apparently when a default key is used to decrypt the packet ++ the hw does not set the index used to decrypt. In such cases ++ get the index from the packet. */ ++ if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED) && ++ !(ds->ds_rxstat.rs_status & AR5K_RXERR_DECRYPT) && ++ skb->len >= hlen + 4) { ++ keyix = skb->data[hlen + 3] >> 6; ++ ++ if (test_bit(keyix, sc->keymap)) ++ return RX_FLAG_DECRYPTED; ++ } ++ ++ return 0; ++} ++ ++static void ++ath5k_tasklet_rx(unsigned long data) ++{ ++ struct ieee80211_rx_status rxs = {}; ++ struct sk_buff *skb; ++ struct ath5k_softc *sc = (void *)data; ++ struct ath5k_buf *bf; ++ struct ath5k_desc *ds; ++ u16 len; ++ u8 stat; ++ int ret; ++ int hdrlen; ++ int pad; ++ ++ spin_lock(&sc->rxbuflock); ++ do { ++ if (unlikely(list_empty(&sc->rxbuf))) { ++ ATH5K_WARN(sc, "empty rx buf pool\n"); ++ break; ++ } ++ bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list); ++ BUG_ON(bf->skb == NULL); ++ skb = bf->skb; ++ ds = bf->desc; ++ ++ /* TODO only one segment */ ++ pci_dma_sync_single_for_cpu(sc->pdev, sc->desc_daddr, ++ sc->desc_len, PCI_DMA_FROMDEVICE); ++ ++ if (unlikely(ds->ds_link == bf->daddr)) /* this is the end */ ++ break; ++ ++ ret = sc->ah->ah_proc_rx_desc(sc->ah, ds); ++ if (unlikely(ret == -EINPROGRESS)) ++ break; ++ else if (unlikely(ret)) { ++ ATH5K_ERR(sc, "error in processing rx descriptor\n"); ++ return; ++ } ++ ++ if (unlikely(ds->ds_rxstat.rs_more)) { ++ ATH5K_WARN(sc, "unsupported jumbo\n"); ++ goto next; ++ } ++ ++ stat = ds->ds_rxstat.rs_status; ++ if (unlikely(stat)) { ++ if (stat & AR5K_RXERR_PHY) ++ goto next; ++ if (stat & AR5K_RXERR_DECRYPT) { ++ /* ++ * Decrypt error. If the error occurred ++ * because there was no hardware key, then ++ * let the frame through so the upper layers ++ * can process it. This is necessary for 5210 ++ * parts which have no way to setup a ``clear'' ++ * key cache entry. ++ * ++ * XXX do key cache faulting ++ */ ++ if (ds->ds_rxstat.rs_keyix == ++ AR5K_RXKEYIX_INVALID && ++ !(stat & AR5K_RXERR_CRC)) ++ goto accept; ++ } ++ if (stat & AR5K_RXERR_MIC) { ++ rxs.flag |= RX_FLAG_MMIC_ERROR; ++ goto accept; ++ } ++ ++ /* let crypto-error packets fall through in MNTR */ ++ if ((stat & ~(AR5K_RXERR_DECRYPT|AR5K_RXERR_MIC)) || ++ sc->opmode != IEEE80211_IF_TYPE_MNTR) ++ goto next; ++ } ++accept: ++ len = ds->ds_rxstat.rs_datalen; ++ pci_dma_sync_single_for_cpu(sc->pdev, bf->skbaddr, len, ++ PCI_DMA_FROMDEVICE); ++ pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize, ++ PCI_DMA_FROMDEVICE); ++ bf->skb = NULL; ++ ++ skb_put(skb, len); ++ ++ /* ++ * the hardware adds a padding to 4 byte boundaries between ++ * the header and the payload data if the header length is ++ * not multiples of 4 - remove it ++ */ ++ hdrlen = ieee80211_get_hdrlen_from_skb(skb); ++ if (hdrlen & 3) { ++ pad = hdrlen % 4; ++ memmove(skb->data + pad, skb->data, hdrlen); ++ skb_pull(skb, pad); ++ } ++ ++ if (sc->opmode == IEEE80211_IF_TYPE_MNTR) ++ rxs.mactime = ath5k_extend_tsf(sc->ah, ++ ds->ds_rxstat.rs_tstamp); ++ else ++ rxs.mactime = ds->ds_rxstat.rs_tstamp; ++ rxs.freq = sc->curchan->freq; ++ rxs.channel = sc->curchan->chan; ++ rxs.phymode = sc->curmode; ++ ++ /* ++ * signal quality: ++ * the names here are misleading and the usage of these ++ * values by iwconfig makes it even worse ++ */ ++ /* noise floor in dBm, from the last noise calibration */ ++ rxs.noise = sc->ah->ah_noise_floor; ++ /* signal level in dBm */ ++ rxs.ssi = rxs.noise + ds->ds_rxstat.rs_rssi; ++ /* ++ * "signal" is actually displayed as Link Quality by iwconfig ++ * we provide a percentage based on rssi (assuming max rssi 64) ++ */ ++ rxs.signal = ds->ds_rxstat.rs_rssi * 100 / 64; ++ ++ rxs.antenna = ds->ds_rxstat.rs_antenna; ++ rxs.rate = ds->ds_rxstat.rs_rate; ++ rxs.flag |= ath5k_rx_decrypted(sc, ds, skb); ++ ++ ath5k_debug_dump_skb(sc, skb, "RX ", 0); ++ ++ __ieee80211_rx(sc->hw, skb, &rxs); ++ sc->led_rxrate = ds->ds_rxstat.rs_rate; ++ ath5k_led_event(sc, ATH_LED_RX); ++next: ++ list_move_tail(&bf->list, &sc->rxbuf); ++ } while (ath5k_rxbuf_setup(sc, bf) == 0); ++ spin_unlock(&sc->rxbuflock); ++} ++ ++ ++ ++ ++/*************\ ++* TX Handling * ++\*************/ ++ ++static void ++ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) ++{ ++ struct ieee80211_tx_status txs = {}; ++ struct ath5k_buf *bf, *bf0; ++ struct ath5k_desc *ds; ++ struct sk_buff *skb; ++ int ret; ++ ++ spin_lock(&txq->lock); ++ list_for_each_entry_safe(bf, bf0, &txq->q, list) { ++ ds = bf->desc; ++ ++ /* TODO only one segment */ ++ pci_dma_sync_single_for_cpu(sc->pdev, sc->desc_daddr, ++ sc->desc_len, PCI_DMA_FROMDEVICE); ++ ret = sc->ah->ah_proc_tx_desc(sc->ah, ds); ++ if (unlikely(ret == -EINPROGRESS)) ++ break; ++ else if (unlikely(ret)) { ++ ATH5K_ERR(sc, "error %d while processing queue %u\n", ++ ret, txq->qnum); ++ break; ++ } ++ ++ skb = bf->skb; ++ bf->skb = NULL; ++ pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, ++ PCI_DMA_TODEVICE); ++ ++ txs.control = bf->ctl; ++ txs.retry_count = ds->ds_txstat.ts_shortretry + ++ ds->ds_txstat.ts_longretry / 6; ++ if (unlikely(ds->ds_txstat.ts_status)) { ++ sc->ll_stats.dot11ACKFailureCount++; ++ if (ds->ds_txstat.ts_status & AR5K_TXERR_XRETRY) ++ txs.excessive_retries = 1; ++ else if (ds->ds_txstat.ts_status & AR5K_TXERR_FILT) ++ txs.flags |= IEEE80211_TX_STATUS_TX_FILTERED; ++ } else { ++ txs.flags |= IEEE80211_TX_STATUS_ACK; ++ txs.ack_signal = ds->ds_txstat.ts_rssi; ++ } ++ ++ ieee80211_tx_status(sc->hw, skb, &txs); ++ sc->tx_stats.data[txq->qnum].count++; ++ ++ spin_lock(&sc->txbuflock); ++ sc->tx_stats.data[txq->qnum].len--; ++ list_move_tail(&bf->list, &sc->txbuf); ++ sc->txbuf_len++; ++ spin_unlock(&sc->txbuflock); ++ } ++ if (likely(list_empty(&txq->q))) ++ txq->link = NULL; ++ spin_unlock(&txq->lock); ++ if (sc->txbuf_len > ATH_TXBUF / 5) ++ ieee80211_wake_queues(sc->hw); ++} ++ ++static void ++ath5k_tasklet_tx(unsigned long data) ++{ ++ struct ath5k_softc *sc = (void *)data; ++ ++ ath5k_tx_processq(sc, sc->txq); ++ ++ ath5k_led_event(sc, ATH_LED_TX); ++} ++ ++ ++ ++ ++/*****************\ ++* Beacon handling * ++\*****************/ ++ ++/* ++ * Setup the beacon frame for transmit. ++ */ ++static int ++ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, ++ struct ieee80211_tx_control *ctl) ++{ ++ struct sk_buff *skb = bf->skb; ++ struct ath5k_hw *ah = sc->ah; ++ struct ath5k_desc *ds; ++ int ret, antenna = 0; ++ u32 flags; ++ ++ bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len, ++ PCI_DMA_TODEVICE); ++ ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "skb %p [data %p len %u] " ++ "skbaddr %llx\n", skb, skb->data, skb->len, ++ (unsigned long long)bf->skbaddr); ++ if (pci_dma_mapping_error(bf->skbaddr)) { ++ ATH5K_ERR(sc, "beacon DMA mapping failed\n"); ++ return -EIO; ++ } ++ ++ ds = bf->desc; ++ ++ flags = AR5K_TXDESC_NOACK; ++ if (sc->opmode == IEEE80211_IF_TYPE_IBSS && ath5k_hw_hasveol(ah)) { ++ ds->ds_link = bf->daddr; /* self-linked */ ++ flags |= AR5K_TXDESC_VEOL; ++ /* ++ * Let hardware handle antenna switching if txantenna is not set ++ */ ++ } else { ++ ds->ds_link = 0; ++ /* ++ * Switch antenna every 4 beacons if txantenna is not set ++ * XXX assumes two antennas ++ */ ++ if (antenna == 0) ++ antenna = sc->bsent & 4 ? 2 : 1; ++ } ++ ++ ds->ds_data = bf->skbaddr; ++ ret = ah->ah_setup_tx_desc(ah, ds, skb->len + FCS_LEN, ++ ieee80211_get_hdrlen_from_skb(skb), ++ AR5K_PKT_TYPE_BEACON, (ctl->power_level * 2), ctl->tx_rate, 1, ++ AR5K_TXKEYIX_INVALID, antenna, flags, 0, 0); ++ if (ret) ++ goto err_unmap; ++ ++ return 0; ++err_unmap: ++ pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE); ++ return ret; ++} ++ ++/* ++ * Transmit a beacon frame at SWBA. Dynamic updates to the ++ * frame contents are done as needed and the slot time is ++ * also adjusted based on current state. ++ * ++ * this is usually called from interrupt context (ath5k_intr()) ++ * but also from ath5k_beacon_config() in IBSS mode which in turn ++ * can be called from a tasklet and user context ++ */ ++static void ++ath5k_beacon_send(struct ath5k_softc *sc) ++{ ++ struct ath5k_buf *bf = sc->bbuf; ++ struct ath5k_hw *ah = sc->ah; ++ ++ ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC, "in beacon_send\n"); ++ ++ if (unlikely(bf->skb == NULL || sc->opmode == IEEE80211_IF_TYPE_STA || ++ sc->opmode == IEEE80211_IF_TYPE_MNTR)) { ++ ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL); ++ return; ++ } ++ /* ++ * Check if the previous beacon has gone out. If ++ * not don't don't try to post another, skip this ++ * period and wait for the next. Missed beacons ++ * indicate a problem and should not occur. If we ++ * miss too many consecutive beacons reset the device. ++ */ ++ if (unlikely(ath5k_hw_num_tx_pending(ah, sc->bhalq) != 0)) { ++ sc->bmisscount++; ++ ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC, ++ "missed %u consecutive beacons\n", sc->bmisscount); ++ if (sc->bmisscount > 3) { /* NB: 3 is a guess */ ++ ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC, ++ "stuck beacon time (%u missed)\n", ++ sc->bmisscount); ++ tasklet_schedule(&sc->restq); ++ } ++ return; ++ } ++ if (unlikely(sc->bmisscount != 0)) { ++ ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC, ++ "resume beacon xmit after %u misses\n", ++ sc->bmisscount); ++ sc->bmisscount = 0; ++ } ++ ++ /* ++ * Stop any current dma and put the new frame on the queue. ++ * This should never fail since we check above that no frames ++ * are still pending on the queue. ++ */ ++ if (unlikely(ath5k_hw_stop_tx_dma(ah, sc->bhalq))) { ++ ATH5K_WARN(sc, "beacon queue %u didn't stop?\n", sc->bhalq); ++ /* NB: hw still stops DMA, so proceed */ ++ } ++ pci_dma_sync_single_for_cpu(sc->pdev, bf->skbaddr, bf->skb->len, ++ PCI_DMA_TODEVICE); ++ ++ ath5k_hw_put_tx_buf(ah, sc->bhalq, bf->daddr); ++ ath5k_hw_tx_start(ah, sc->bhalq); ++ ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC, "TXDP[%u] = %llx (%p)\n", ++ sc->bhalq, (unsigned long long)bf->daddr, bf->desc); ++ ++ sc->bsent++; ++} ++ ++/* ++ * Configure the beacon and sleep timers. ++ * ++ * When operating as an AP this resets the TSF and sets ++ * up the hardware to notify us when we need to issue beacons. ++ * ++ * When operating in station mode this sets up the beacon ++ * timers according to the timestamp of the last received ++ * beacon and the current TSF, configures PCF and DTIM ++ * handling, programs the sleep registers so the hardware ++ * will wakeup in time to receive beacons, and configures ++ * the beacon miss handling so we'll receive a BMISS ++ * interrupt when we stop seeing beacons from the AP ++ * we've associated with. ++ */ ++static void ++ath5k_beacon_config(struct ath5k_softc *sc) ++{ ++#define TSF_TO_TU(_h, _l) (((_h) << 22) | ((_l) >> 10)) ++ struct ath5k_hw *ah = sc->ah; ++ u32 uninitialized_var(nexttbtt), intval, tsftu; ++ u64 tsf; ++ ++ intval = sc->bintval & AR5K_BEACON_PERIOD; ++ if (WARN_ON(!intval)) ++ return; ++ ++ /* current TSF converted to TU */ ++ tsf = ath5k_hw_get_tsf64(ah); ++ tsftu = TSF_TO_TU((u32)(tsf >> 32), (u32)tsf); ++ ++ ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "intval %u hw tsftu %u\n", ++ intval, tsftu); ++ ++ if (sc->opmode == IEEE80211_IF_TYPE_STA || ++ (sc->opmode == IEEE80211_IF_TYPE_IBSS && ++ !sc->bbuf->skb)) { ++ ath5k_hw_set_intr(ah, 0); ++ sc->imask |= AR5K_INT_BMISS; ++ sc->bmisscount = 0; ++ ath5k_hw_set_intr(ah, sc->imask); ++ } else if (sc->opmode == IEEE80211_IF_TYPE_IBSS /* TODO || AP */) { ++ ath5k_hw_set_intr(ah, 0); ++ if (sc->opmode == IEEE80211_IF_TYPE_IBSS) { ++ /* ++ * Pull nexttbtt forward to reflect the current ++ * TSF. Add one intval otherwise the timespan ++ * can be too short for ibss merges. ++ */ ++ nexttbtt = tsftu + 2 * intval; ++ ++ ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "nexttbtt %u " ++ "intval %u\n", nexttbtt, intval); ++ ++ /* ++ * In IBSS mode enable the beacon timers but only ++ * enable SWBA interrupts if we need to manually ++ * prepare beacon frames. Otherwise we use a ++ * self-linked tx descriptor and let the hardware ++ * deal with things. ++ */ ++ if (!ath5k_hw_hasveol(ah)) ++ sc->imask |= AR5K_INT_SWBA; ++ } /* TODO else AP */ ++ ++ intval |= AR5K_BEACON_ENA; ++ ++ ath5k_beaconq_config(sc); ++ ath5k_hw_init_beacon(ah, nexttbtt, intval); ++ ++ sc->bmisscount = 0; ++ ath5k_hw_set_intr(ah, sc->imask); ++ /* ++ * When using a self-linked beacon descriptor in ++ * ibss mode load it once here. ++ */ ++ if (sc->opmode == IEEE80211_IF_TYPE_IBSS && ++ ath5k_hw_hasveol(ah)) ++ ath5k_beacon_send(sc); ++ } ++#undef TSF_TO_TU ++} ++ ++/********************\ ++* Interrupt handling * ++\********************/ ++ ++static int ++ath5k_init(struct ath5k_softc *sc) ++{ ++ int ret; ++ ++ mutex_lock(&sc->lock); ++ ++ ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mode %d\n", sc->opmode); ++ ++ /* ++ * Stop anything previously setup. This is safe ++ * no matter this is the first time through or not. ++ */ ++ ath5k_stop_locked(sc); ++ ++ /* ++ * The basic interface to setting the hardware in a good ++ * state is ``reset''. On return the hardware is known to ++ * be powered up and with interrupts disabled. This must ++ * be followed by initialization of the appropriate bits ++ * and then setup of the interrupt mask. ++ */ ++ sc->curchan = sc->hw->conf.chan; ++ ret = ath5k_hw_reset(sc->ah, sc->opmode, sc->curchan, false); ++ if (ret) { ++ ATH5K_ERR(sc, "unable to reset hardware: %d\n", ret); ++ goto done; ++ } ++ /* ++ * This is needed only to setup initial state ++ * but it's best done after a reset. ++ */ ++ ath5k_hw_set_txpower_limit(sc->ah, 0); ++ ++ /* ++ * Setup the hardware after reset: the key cache ++ * is filled as needed and the receive engine is ++ * set going. Frame transmit is handled entirely ++ * in the frame output path; there's nothing to do ++ * here except setup the interrupt mask. ++ */ ++ ret = ath5k_rx_start(sc); ++ if (ret) ++ goto done; ++ ++ /* ++ * Enable interrupts. ++ */ ++ sc->imask = AR5K_INT_RX | AR5K_INT_TX | AR5K_INT_RXEOL | ++ AR5K_INT_RXORN | AR5K_INT_FATAL | AR5K_INT_GLOBAL; ++ ++ ath5k_hw_set_intr(sc->ah, sc->imask); ++ /* Set ack to be sent at low bit-rates */ ++ ath5k_hw_set_ack_bitrate_high(sc->ah, false); ++ ++ mod_timer(&sc->calib_tim, round_jiffies(jiffies + ++ msecs_to_jiffies(ath5k_calinterval * 1000))); ++ ++ ret = 0; ++done: ++ mutex_unlock(&sc->lock); ++ return ret; ++} ++ ++static int ++ath5k_stop_locked(struct ath5k_softc *sc) ++{ ++ struct ath5k_hw *ah = sc->ah; ++ ++ ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "invalid %u\n", ++ test_bit(ATH_STAT_INVALID, sc->status)); ++ ++ /* ++ * Shutdown the hardware and driver: ++ * stop output from above ++ * disable interrupts ++ * turn off timers ++ * turn off the radio ++ * clear transmit machinery ++ * clear receive machinery ++ * drain and release tx queues ++ * reclaim beacon resources ++ * power down hardware ++ * ++ * Note that some of this work is not possible if the ++ * hardware is gone (invalid). ++ */ ++ ieee80211_stop_queues(sc->hw); ++ ++ if (!test_bit(ATH_STAT_INVALID, sc->status)) { ++ if (test_bit(ATH_STAT_LEDSOFT, sc->status)) { ++ del_timer_sync(&sc->led_tim); ++ ath5k_hw_set_gpio(ah, sc->led_pin, !sc->led_on); ++ __clear_bit(ATH_STAT_LEDBLINKING, sc->status); ++ } ++ ath5k_hw_set_intr(ah, 0); ++ } ++ ath5k_txq_cleanup(sc); ++ if (!test_bit(ATH_STAT_INVALID, sc->status)) { ++ ath5k_rx_stop(sc); ++ ath5k_hw_phy_disable(ah); ++ } else ++ sc->rxlink = NULL; ++ ++ return 0; ++} ++ ++/* ++ * Stop the device, grabbing the top-level lock to protect ++ * against concurrent entry through ath5k_init (which can happen ++ * if another thread does a system call and the thread doing the ++ * stop is preempted). ++ */ ++static int ++ath5k_stop_hw(struct ath5k_softc *sc) ++{ ++ int ret; ++ ++ mutex_lock(&sc->lock); ++ 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); ++ } ++ } ++ ath5k_txbuf_free(sc, sc->bbuf); ++ mutex_unlock(&sc->lock); ++ ++ del_timer_sync(&sc->calib_tim); ++ ++ return ret; ++} ++ ++static irqreturn_t ++ath5k_intr(int irq, void *dev_id) ++{ ++ struct ath5k_softc *sc = dev_id; ++ struct ath5k_hw *ah = sc->ah; ++ enum ath5k_int status; ++ unsigned int counter = 1000; ++ ++ if (unlikely(test_bit(ATH_STAT_INVALID, sc->status) || ++ !ath5k_hw_is_intr_pending(ah))) ++ return IRQ_NONE; ++ ++ do { ++ /* ++ * Figure out the reason(s) for the interrupt. Note ++ * that get_isr returns a pseudo-ISR that may include ++ * bits we haven't explicitly enabled so we mask the ++ * value to insure we only process bits we requested. ++ */ ++ ath5k_hw_get_isr(ah, &status); /* NB: clears IRQ too */ ++ ATH5K_DBG(sc, ATH5K_DEBUG_INTR, "status 0x%x/0x%x\n", ++ status, sc->imask); ++ status &= sc->imask; /* discard unasked for bits */ ++ if (unlikely(status & AR5K_INT_FATAL)) { ++ /* ++ * Fatal errors are unrecoverable. ++ * Typically these are caused by DMA errors. ++ */ ++ tasklet_schedule(&sc->restq); ++ } else if (unlikely(status & AR5K_INT_RXORN)) { ++ tasklet_schedule(&sc->restq); ++ } else { ++ if (status & AR5K_INT_SWBA) { ++ /* ++ * Software beacon alert--time to send a beacon. ++ * Handle beacon transmission directly; deferring ++ * this is too slow to meet timing constraints ++ * under load. ++ */ ++ ath5k_beacon_send(sc); ++ } ++ if (status & AR5K_INT_RXEOL) { ++ /* ++ * NB: the hardware should re-read the link when ++ * RXE bit is written, but it doesn't work at ++ * least on older hardware revs. ++ */ ++ sc->rxlink = NULL; ++ } ++ if (status & AR5K_INT_TXURN) { ++ /* bump tx trigger level */ ++ ath5k_hw_update_tx_triglevel(ah, true); ++ } ++ if (status & AR5K_INT_RX) ++ tasklet_schedule(&sc->rxtq); ++ if (status & AR5K_INT_TX) ++ tasklet_schedule(&sc->txtq); ++ if (status & AR5K_INT_BMISS) { ++ } ++ if (status & AR5K_INT_MIB) { ++ /* TODO */ ++ } ++ } ++ } while (ath5k_hw_is_intr_pending(ah) && counter-- > 0); ++ ++ if (unlikely(!counter)) ++ ATH5K_WARN(sc, "too many interrupts, giving up for now\n"); ++ ++ return IRQ_HANDLED; ++} ++ ++static void ++ath5k_tasklet_reset(unsigned long data) ++{ ++ struct ath5k_softc *sc = (void *)data; ++ ++ ath5k_reset(sc->hw); ++} ++ ++/* ++ * Periodically recalibrate the PHY to account ++ * for temperature/environment changes. ++ */ ++static void ++ath5k_calibrate(unsigned long data) ++{ ++ struct ath5k_softc *sc = (void *)data; ++ struct ath5k_hw *ah = sc->ah; ++ ++ ATH5K_DBG(sc, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n", ++ sc->curchan->chan, sc->curchan->val); ++ ++ if (ath5k_hw_get_rf_gain(ah) == AR5K_RFGAIN_NEED_CHANGE) { ++ /* ++ * Rfgain is out of bounds, reset the chip ++ * to load new gain values. ++ */ ++ ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "calibration, resetting\n"); ++ ath5k_reset(sc->hw); ++ } ++ if (ath5k_hw_phy_calibrate(ah, sc->curchan)) ++ ATH5K_ERR(sc, "calibration of channel %u failed\n", ++ sc->curchan->chan); ++ ++ mod_timer(&sc->calib_tim, round_jiffies(jiffies + ++ msecs_to_jiffies(ath5k_calinterval * 1000))); ++} ++ ++ ++ ++/***************\ ++* LED functions * ++\***************/ ++ ++static void ++ath5k_led_off(unsigned long data) ++{ ++ struct ath5k_softc *sc = (void *)data; ++ ++ if (test_bit(ATH_STAT_LEDENDBLINK, sc->status)) ++ __clear_bit(ATH_STAT_LEDBLINKING, sc->status); ++ else { ++ __set_bit(ATH_STAT_LEDENDBLINK, sc->status); ++ ath5k_hw_set_gpio(sc->ah, sc->led_pin, !sc->led_on); ++ mod_timer(&sc->led_tim, jiffies + sc->led_off); ++ } ++} ++ ++/* ++ * Blink the LED according to the specified on/off times. ++ */ ++static void ++ath5k_led_blink(struct ath5k_softc *sc, unsigned int on, ++ unsigned int off) ++{ ++ ATH5K_DBG(sc, ATH5K_DEBUG_LED, "on %u off %u\n", on, off); ++ ath5k_hw_set_gpio(sc->ah, sc->led_pin, sc->led_on); ++ __set_bit(ATH_STAT_LEDBLINKING, sc->status); ++ __clear_bit(ATH_STAT_LEDENDBLINK, sc->status); ++ sc->led_off = off; ++ mod_timer(&sc->led_tim, jiffies + on); ++} ++ ++static void ++ath5k_led_event(struct ath5k_softc *sc, int event) ++{ ++ if (likely(!test_bit(ATH_STAT_LEDSOFT, sc->status))) ++ return; ++ if (unlikely(test_bit(ATH_STAT_LEDBLINKING, sc->status))) ++ return; /* don't interrupt active blink */ ++ switch (event) { ++ case ATH_LED_TX: ++ ath5k_led_blink(sc, sc->hwmap[sc->led_txrate].ledon, ++ sc->hwmap[sc->led_txrate].ledoff); ++ break; ++ case ATH_LED_RX: ++ ath5k_led_blink(sc, sc->hwmap[sc->led_rxrate].ledon, ++ sc->hwmap[sc->led_rxrate].ledoff); ++ break; ++ } ++} ++ ++ ++ ++ ++/********************\ ++* Mac80211 functions * ++\********************/ ++ ++static int ++ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb, ++ struct ieee80211_tx_control *ctl) ++{ ++ struct ath5k_softc *sc = hw->priv; ++ struct ath5k_buf *bf; ++ unsigned long flags; ++ int hdrlen; ++ int pad; ++ ++ ath5k_debug_dump_skb(sc, skb, "TX ", 1); ++ ++ if (sc->opmode == IEEE80211_IF_TYPE_MNTR) ++ ATH5K_DBG(sc, ATH5K_DEBUG_XMIT, "tx in monitor (scan?)\n"); ++ ++ /* ++ * the hardware expects the header padded to 4 byte boundaries ++ * if this is not the case we add the padding after the header ++ */ ++ hdrlen = ieee80211_get_hdrlen_from_skb(skb); ++ if (hdrlen & 3) { ++ pad = hdrlen % 4; ++ if (skb_headroom(skb) < pad) { ++ ATH5K_ERR(sc, "tx hdrlen not %%4: %d not enough" ++ " headroom to pad %d\n", hdrlen, pad); ++ return -1; ++ } ++ skb_push(skb, pad); ++ memmove(skb->data, skb->data+pad, hdrlen); ++ } ++ ++ sc->led_txrate = ctl->tx_rate; ++ ++ spin_lock_irqsave(&sc->txbuflock, flags); ++ if (list_empty(&sc->txbuf)) { ++ ATH5K_ERR(sc, "no further txbuf available, dropping packet\n"); ++ spin_unlock_irqrestore(&sc->txbuflock, flags); ++ ieee80211_stop_queue(hw, ctl->queue); ++ return -1; ++ } ++ bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list); ++ list_del(&bf->list); ++ sc->txbuf_len--; ++ if (list_empty(&sc->txbuf)) ++ ieee80211_stop_queues(hw); ++ spin_unlock_irqrestore(&sc->txbuflock, flags); ++ ++ bf->skb = skb; ++ ++ if (ath5k_txbuf_setup(sc, bf, ctl)) { ++ bf->skb = NULL; ++ spin_lock_irqsave(&sc->txbuflock, flags); ++ list_add_tail(&bf->list, &sc->txbuf); ++ sc->txbuf_len++; ++ spin_unlock_irqrestore(&sc->txbuflock, flags); ++ dev_kfree_skb_any(skb); ++ return 0; ++ } ++ ++ return 0; ++} ++ ++static int ++ath5k_reset(struct ieee80211_hw *hw) ++{ ++ struct ath5k_softc *sc = hw->priv; ++ struct ath5k_hw *ah = sc->ah; ++ int ret; ++ ++ ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "resetting\n"); ++ /* ++ * Convert to a hw channel description with the flags ++ * constrained to reflect the current operating mode. ++ */ ++ sc->curchan = hw->conf.chan; ++ ++ ath5k_hw_set_intr(ah, 0); ++ ath5k_txq_cleanup(sc); ++ ath5k_rx_stop(sc); ++ ++ ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, true); ++ if (unlikely(ret)) { ++ ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret); ++ goto err; ++ } ++ ath5k_hw_set_txpower_limit(sc->ah, 0); ++ ++ ret = ath5k_rx_start(sc); ++ if (unlikely(ret)) { ++ ATH5K_ERR(sc, "can't start recv logic\n"); ++ goto err; ++ } ++ /* ++ * We may be doing a reset in response to an ioctl ++ * that changes the channel so update any state that ++ * might change as a result. ++ * ++ * XXX needed? ++ */ ++/* ath5k_chan_change(sc, c); */ ++ ath5k_beacon_config(sc); ++ /* intrs are started by ath5k_beacon_config */ ++ ++ ieee80211_wake_queues(hw); ++ ++ return 0; ++err: ++ return ret; ++} ++ ++static int ath5k_start(struct ieee80211_hw *hw) ++{ ++ return ath5k_init(hw->priv); ++} ++ ++static void ath5k_stop(struct ieee80211_hw *hw) ++{ ++ ath5k_stop_hw(hw->priv); ++} ++ ++static int ath5k_add_interface(struct ieee80211_hw *hw, ++ struct ieee80211_if_init_conf *conf) ++{ ++ struct ath5k_softc *sc = hw->priv; ++ int ret; ++ ++ mutex_lock(&sc->lock); ++ if (sc->iface_id) { ++ ret = 0; ++ goto end; ++ } ++ ++ sc->iface_id = conf->if_id; ++ ++ switch (conf->type) { ++ case IEEE80211_IF_TYPE_STA: ++ case IEEE80211_IF_TYPE_IBSS: ++ case IEEE80211_IF_TYPE_MNTR: ++ sc->opmode = conf->type; ++ break; ++ default: ++ ret = -EOPNOTSUPP; ++ goto end; ++ } ++ ret = 0; ++end: ++ mutex_unlock(&sc->lock); ++ return ret; ++} ++ ++static void ++ath5k_remove_interface(struct ieee80211_hw *hw, ++ struct ieee80211_if_init_conf *conf) ++{ ++ struct ath5k_softc *sc = hw->priv; ++ ++ mutex_lock(&sc->lock); ++ if (sc->iface_id != conf->if_id) ++ goto end; ++ ++ sc->iface_id = 0; ++end: ++ mutex_unlock(&sc->lock); ++} ++ ++static int ++ath5k_config(struct ieee80211_hw *hw, ++ struct ieee80211_conf *conf) ++{ ++ struct ath5k_softc *sc = hw->priv; ++ ++ sc->bintval = conf->beacon_int * 1000 / 1024; ++ ath5k_setcurmode(sc, conf->phymode); ++ ++ return ath5k_chan_set(sc, conf->chan); ++} ++ ++static int ++ath5k_config_interface(struct ieee80211_hw *hw, int if_id, ++ struct ieee80211_if_conf *conf) ++{ ++ struct ath5k_softc *sc = hw->priv; ++ struct ath5k_hw *ah = sc->ah; ++ int ret; ++ ++ /* Set to a reasonable value. Note that this will ++ * be set to mac80211's value at ath5k_config(). */ ++ sc->bintval = 1000 * 1000 / 1024; ++ mutex_lock(&sc->lock); ++ if (sc->iface_id != if_id) { ++ ret = -EIO; ++ goto unlock; ++ } ++ if (conf->bssid) { ++ /* Cache for later use during resets */ ++ memcpy(ah->bssid, conf->bssid, ETH_ALEN); ++ /* XXX: assoc id is set to 0 for now, mac80211 doesn't have ++ * a clean way of letting us retrieve this yet. */ ++ ath5k_hw_set_associd(ah, ah->bssid, 0); ++ } ++ mutex_unlock(&sc->lock); ++ ++ return ath5k_reset(hw); ++unlock: ++ mutex_unlock(&sc->lock); ++ return ret; ++} ++ ++#define SUPPORTED_FIF_FLAGS \ ++ FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | \ ++ FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \ ++ FIF_BCN_PRBRESP_PROMISC ++/* ++ * o always accept unicast, broadcast, and multicast traffic ++ * o multicast traffic for all BSSIDs will be enabled if mac80211 ++ * says it should be ++ * o maintain current state of phy ofdm or phy cck error reception. ++ * If the hardware detects any of these type of errors then ++ * ath5k_hw_get_rx_filter() will pass to us the respective ++ * hardware filters to be able to receive these type of frames. ++ * o probe request frames are accepted only when operating in ++ * hostap, adhoc, or monitor modes ++ * o enable promiscuous mode according to the interface state ++ * o accept beacons: ++ * - when operating in adhoc mode so the 802.11 layer creates ++ * node table entries for peers, ++ * - when operating in station mode for collecting rssi data when ++ * the station is otherwise quiet, or ++ * - when scanning ++ */ ++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) ++{ ++ struct ath5k_softc *sc = hw->priv; ++ struct ath5k_hw *ah = sc->ah; ++ u32 mfilt[2], val, rfilt; ++ u8 pos; ++ int i; ++ ++ mfilt[0] = 0; ++ mfilt[1] = 0; ++ ++ /* Only deal with supported flags */ ++ changed_flags &= SUPPORTED_FIF_FLAGS; ++ *new_flags &= SUPPORTED_FIF_FLAGS; ++ ++ /* If HW detects any phy or radar errors, leave those filters on. ++ * Also, always enable Unicast, Broadcasts and Multicast ++ * XXX: move unicast, bssid broadcasts and multicast to mac80211 */ ++ rfilt = (ath5k_hw_get_rx_filter(ah) & (AR5K_RX_FILTER_PHYERR)) | ++ (AR5K_RX_FILTER_UCAST | AR5K_RX_FILTER_BCAST | ++ AR5K_RX_FILTER_MCAST); ++ ++ if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) { ++ if (*new_flags & FIF_PROMISC_IN_BSS) { ++ rfilt |= AR5K_RX_FILTER_PROM; ++ __set_bit(ATH_STAT_PROMISC, sc->status); ++ } ++ else ++ __clear_bit(ATH_STAT_PROMISC, sc->status); ++ } ++ ++ /* Note, AR5K_RX_FILTER_MCAST is already enabled */ ++ 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 = LE_READ_4(mclist->dmi_addr + 0); ++ pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; ++ val = LE_READ_4(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 */ ++ if (*new_flags & (FIF_FCSFAIL | FIF_PLCPFAIL)) ++ rfilt |= AR5K_RX_FILTER_PHYERR; ++ ++ /* FIF_BCN_PRBRESP_PROMISC really means to enable beacons ++ * and probes for any BSSID, this needs testing */ ++ if (*new_flags & FIF_BCN_PRBRESP_PROMISC) ++ rfilt |= AR5K_RX_FILTER_BEACON | AR5K_RX_FILTER_PROBEREQ; ++ ++ /* FIF_CONTROL doc says that if FIF_PROMISC_IN_BSS is not ++ * set we should only pass on control frames for this ++ * station. This needs testing. I believe right now this ++ * enables *all* control frames, which is OK.. but ++ * but we should see if we can improve on granularity */ ++ if (*new_flags & FIF_CONTROL) ++ rfilt |= AR5K_RX_FILTER_CONTROL; ++ ++ /* Additional settings per mode -- this is per ath5k */ ++ ++ /* XXX move these to mac80211, and add a beacon IFF flag to mac80211 */ ++ ++ if (sc->opmode == IEEE80211_IF_TYPE_MNTR) ++ rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON | ++ AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM; ++ if (sc->opmode != IEEE80211_IF_TYPE_STA) ++ rfilt |= AR5K_RX_FILTER_PROBEREQ; ++ if (sc->opmode != IEEE80211_IF_TYPE_AP && ++ test_bit(ATH_STAT_PROMISC, sc->status)) ++ rfilt |= AR5K_RX_FILTER_PROM; ++ if (sc->opmode == IEEE80211_IF_TYPE_STA || ++ sc->opmode == IEEE80211_IF_TYPE_IBSS) { ++ rfilt |= AR5K_RX_FILTER_BEACON; ++ } ++ ++ /* Set filters */ ++ ath5k_hw_set_rx_filter(ah,rfilt); ++ ++ /* Set multicast bits */ ++ ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]); ++ /* Set the cached hw filter flags, this will alter actually ++ * be set in HW */ ++ sc->filter_flags = rfilt; ++} ++ ++static int ++ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ++ const u8 *local_addr, const u8 *addr, ++ struct ieee80211_key_conf *key) ++{ ++ struct ath5k_softc *sc = hw->priv; ++ int ret = 0; ++ ++ switch(key->alg) { ++ case ALG_WEP: ++ break; ++ case ALG_TKIP: ++ case ALG_CCMP: ++ return -EOPNOTSUPP; ++ default: ++ WARN_ON(1); ++ return -EINVAL; ++ } ++ ++ mutex_lock(&sc->lock); ++ ++ switch (cmd) { ++ case SET_KEY: ++ ret = ath5k_hw_set_key(sc->ah, key->keyidx, key, addr); ++ if (ret) { ++ ATH5K_ERR(sc, "can't set the key\n"); ++ goto unlock; ++ } ++ __set_bit(key->keyidx, sc->keymap); ++ key->hw_key_idx = key->keyidx; ++ break; ++ case DISABLE_KEY: ++ ath5k_hw_reset_key(sc->ah, key->keyidx); ++ __clear_bit(key->keyidx, sc->keymap); ++ break; ++ default: ++ ret = -EINVAL; ++ goto unlock; ++ } ++ ++unlock: ++ mutex_unlock(&sc->lock); ++ return ret; ++} ++ ++static int ++ath5k_get_stats(struct ieee80211_hw *hw, ++ struct ieee80211_low_level_stats *stats) ++{ ++ struct ath5k_softc *sc = hw->priv; ++ ++ memcpy(stats, &sc->ll_stats, sizeof(sc->ll_stats)); ++ ++ return 0; ++} ++ ++static int ++ath5k_get_tx_stats(struct ieee80211_hw *hw, ++ struct ieee80211_tx_queue_stats *stats) ++{ ++ struct ath5k_softc *sc = hw->priv; ++ ++ memcpy(stats, &sc->tx_stats, sizeof(sc->tx_stats)); ++ ++ return 0; ++} ++ ++static u64 ++ath5k_get_tsf(struct ieee80211_hw *hw) ++{ ++ struct ath5k_softc *sc = hw->priv; ++ ++ return ath5k_hw_get_tsf64(sc->ah); ++} ++ ++static void ++ath5k_reset_tsf(struct ieee80211_hw *hw) ++{ ++ struct ath5k_softc *sc = hw->priv; ++ ++ ath5k_hw_reset_tsf(sc->ah); ++} ++ ++static int ++ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, ++ struct ieee80211_tx_control *ctl) ++{ ++ struct ath5k_softc *sc = hw->priv; ++ int ret; ++ ++ ath5k_debug_dump_skb(sc, skb, "BC ", 1); ++ ++ mutex_lock(&sc->lock); ++ ++ if (sc->opmode != IEEE80211_IF_TYPE_IBSS) { ++ ret = -EIO; ++ goto end; ++ } ++ ++ ath5k_txbuf_free(sc, sc->bbuf); ++ sc->bbuf->skb = skb; ++ ret = ath5k_beacon_setup(sc, sc->bbuf, ctl); ++ if (ret) ++ sc->bbuf->skb = NULL; ++ ++end: ++ mutex_unlock(&sc->lock); ++ return ret; ++} ++ +diff -up /dev/null linux-2.6.23.noarch/drivers/net/wireless/ath5k/debug.c +--- /dev/null 2007-12-21 08:33:07.834165456 -0500 ++++ linux-2.6.23.noarch/drivers/net/wireless/ath5k/debug.c 2007-12-21 12:18:50.000000000 -0500 +@@ -0,0 +1,469 @@ ++/* ++ * Copyright (c) 2007 Bruno Randolf ++ * ++ * This file is free software: you may copy, redistribute 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 file 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, see . ++ * ++ * ++ * This file incorporates work covered by the following copyright and ++ * permission notice: ++ * ++ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting ++ * Copyright (c) 2004-2005 Atheros Communications, Inc. ++ * Copyright (c) 2006 Devicescape Software, Inc. ++ * Copyright (c) 2007 Jiri Slaby ++ * Copyright (c) 2007 Luis R. Rodriguez ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer, ++ * without modification. ++ * 2. Redistributions in binary form must reproduce at minimum a disclaimer ++ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any ++ * redistribution must be conditioned upon including a substantially ++ * similar Disclaimer requirement for further binary redistribution. ++ * 3. Neither the names of the above-listed copyright holders nor the names ++ * of any contributors may be used to endorse or promote products derived ++ * from this software without specific prior written permission. ++ * ++ * Alternatively, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") version 2 as published by the Free ++ * Software Foundation. ++ * ++ * NO WARRANTY ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY ++ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, ++ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER ++ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF ++ * THE POSSIBILITY OF SUCH DAMAGES. ++ */ ++ ++#include "debug.h" ++#include "base.h" ++ ++static unsigned int ath5k_debug; ++module_param_named(debug, ath5k_debug, uint, 0); ++ ++ ++#if ATH5K_DEBUG ++ ++#include ++#include "reg.h" ++ ++static struct dentry *ath5k_global_debugfs; ++ ++static int ath5k_debugfs_open(struct inode *inode, struct file *file) ++{ ++ file->private_data = inode->i_private; ++ return 0; ++} ++ ++ ++/* debugfs: registers */ ++ ++struct reg { ++ char *name; ++ int addr; ++}; ++ ++#define REG_STRUCT_INIT(r) { #r, r } ++ ++/* just a few random registers, might want to add more */ ++static struct reg regs[] = { ++ REG_STRUCT_INIT(AR5K_CR), ++ REG_STRUCT_INIT(AR5K_RXDP), ++ REG_STRUCT_INIT(AR5K_CFG), ++ REG_STRUCT_INIT(AR5K_IER), ++ REG_STRUCT_INIT(AR5K_BCR), ++ REG_STRUCT_INIT(AR5K_RTSD0), ++ REG_STRUCT_INIT(AR5K_RTSD1), ++ REG_STRUCT_INIT(AR5K_TXCFG), ++ REG_STRUCT_INIT(AR5K_RXCFG), ++ REG_STRUCT_INIT(AR5K_RXJLA), ++ REG_STRUCT_INIT(AR5K_MIBC), ++ REG_STRUCT_INIT(AR5K_TOPS), ++ REG_STRUCT_INIT(AR5K_RXNOFRM), ++ REG_STRUCT_INIT(AR5K_TXNOFRM), ++ REG_STRUCT_INIT(AR5K_RPGTO), ++ REG_STRUCT_INIT(AR5K_RFCNT), ++ REG_STRUCT_INIT(AR5K_MISC), ++ REG_STRUCT_INIT(AR5K_QCUDCU_CLKGT), ++ REG_STRUCT_INIT(AR5K_ISR), ++ REG_STRUCT_INIT(AR5K_PISR), ++ REG_STRUCT_INIT(AR5K_SISR0), ++ REG_STRUCT_INIT(AR5K_SISR1), ++ REG_STRUCT_INIT(AR5K_SISR2), ++ REG_STRUCT_INIT(AR5K_SISR3), ++ REG_STRUCT_INIT(AR5K_SISR4), ++ REG_STRUCT_INIT(AR5K_IMR), ++ REG_STRUCT_INIT(AR5K_PIMR), ++ REG_STRUCT_INIT(AR5K_SIMR0), ++ REG_STRUCT_INIT(AR5K_SIMR1), ++ REG_STRUCT_INIT(AR5K_SIMR2), ++ REG_STRUCT_INIT(AR5K_SIMR3), ++ REG_STRUCT_INIT(AR5K_SIMR4), ++ REG_STRUCT_INIT(AR5K_DCM_ADDR), ++ REG_STRUCT_INIT(AR5K_DCCFG), ++ REG_STRUCT_INIT(AR5K_CCFG), ++ REG_STRUCT_INIT(AR5K_CPC0), ++ REG_STRUCT_INIT(AR5K_CPC1), ++ REG_STRUCT_INIT(AR5K_CPC2), ++ REG_STRUCT_INIT(AR5K_CPC3), ++ REG_STRUCT_INIT(AR5K_CPCORN), ++ REG_STRUCT_INIT(AR5K_RESET_CTL), ++ REG_STRUCT_INIT(AR5K_SLEEP_CTL), ++ REG_STRUCT_INIT(AR5K_INTPEND), ++ REG_STRUCT_INIT(AR5K_SFR), ++ REG_STRUCT_INIT(AR5K_PCICFG), ++ REG_STRUCT_INIT(AR5K_GPIOCR), ++ REG_STRUCT_INIT(AR5K_GPIODO), ++ REG_STRUCT_INIT(AR5K_SREV), ++}; ++ ++static void *reg_start(struct seq_file *seq, loff_t *pos) ++{ ++ return *pos < ARRAY_SIZE(regs) ? ®s[*pos] : NULL; ++} ++ ++static void reg_stop(struct seq_file *seq, void *p) ++{ ++ /* nothing to do */ ++} ++ ++static void *reg_next(struct seq_file *seq, void *p, loff_t *pos) ++{ ++ ++*pos; ++ return *pos < ARRAY_SIZE(regs) ? ®s[*pos] : NULL; ++} ++ ++static int reg_show(struct seq_file *seq, void *p) ++{ ++ struct ath5k_softc *sc = seq->private; ++ struct reg *r = p; ++ seq_printf(seq, "%-25s0x%08x\n", r->name, ++ ath5k_hw_reg_read(sc->ah, r->addr)); ++ return 0; ++} ++ ++static struct seq_operations register_seq_ops = { ++ .start = reg_start, ++ .next = reg_next, ++ .stop = reg_stop, ++ .show = reg_show ++}; ++ ++static int open_file_registers(struct inode *inode, struct file *file) ++{ ++ struct seq_file *s; ++ int res; ++ res = seq_open(file, ®ister_seq_ops); ++ if (res == 0) { ++ s = file->private_data; ++ s->private = inode->i_private; ++ } ++ return res; ++} ++ ++static const struct file_operations fops_registers = { ++ .open = open_file_registers, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = seq_release, ++ .owner = THIS_MODULE, ++}; ++ ++ ++/* debugfs: TSF */ ++ ++static ssize_t read_file_tsf(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath5k_softc *sc = file->private_data; ++ char buf[100]; ++ snprintf(buf, 100, "0x%016llx\n", ath5k_hw_get_tsf64(sc->ah)); ++ return simple_read_from_buffer(user_buf, count, ppos, buf, 19); ++} ++ ++static ssize_t write_file_tsf(struct file *file, ++ const char __user *userbuf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath5k_softc *sc = file->private_data; ++ if (strncmp(userbuf, "reset", 5) == 0) { ++ ath5k_hw_reset_tsf(sc->ah); ++ printk(KERN_INFO "debugfs reset TSF\n"); ++ } ++ return count; ++} ++ ++static const struct file_operations fops_tsf = { ++ .read = read_file_tsf, ++ .write = write_file_tsf, ++ .open = ath5k_debugfs_open, ++ .owner = THIS_MODULE, ++}; ++ ++ ++/* debugfs: beacons */ ++ ++static ssize_t read_file_beacon(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath5k_softc *sc = file->private_data; ++ struct ath5k_hw *ah = sc->ah; ++ char buf[1000]; ++ int len = 0; ++ unsigned int v; ++ u64 tsf; ++ ++ v = ath5k_hw_reg_read(sc->ah, AR5K_BEACON); ++ len += snprintf(buf+len, sizeof(buf)-len, ++ "%-24s0x%08x\tintval: %d\tTIM: 0x%x\n", ++ "AR5K_BEACON", v, v & AR5K_BEACON_PERIOD, ++ (v & AR5K_BEACON_TIM) >> AR5K_BEACON_TIM_S); ++ ++ len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\n", ++ "AR5K_LAST_TSTP", ath5k_hw_reg_read(sc->ah, AR5K_LAST_TSTP)); ++ ++ len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\n\n", ++ "AR5K_BEACON_CNT", ath5k_hw_reg_read(sc->ah, AR5K_BEACON_CNT)); ++ ++ v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER0); ++ len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n", ++ "AR5K_TIMER0 (TBTT)", v, v); ++ ++ v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER1); ++ len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n", ++ "AR5K_TIMER1 (DMA)", v, v >> 3); ++ ++ v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER2); ++ len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n", ++ "AR5K_TIMER2 (SWBA)", v, v >> 3); ++ ++ v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER3); ++ len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n", ++ "AR5K_TIMER3 (ATIM)", v, v); ++ ++ tsf = ath5k_hw_get_tsf64(sc->ah); ++ len += snprintf(buf+len, sizeof(buf)-len, ++ "TSF\t\t0x%016llx\tTU: %08x\n", tsf, (u32)(tsf >> 10)); ++ ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); ++} ++ ++static ssize_t write_file_beacon(struct file *file, ++ const char __user *userbuf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath5k_softc *sc = file->private_data; ++ struct ath5k_hw *ah = sc->ah; ++ ++ if (strncmp(userbuf, "disable", 7) == 0) { ++ AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE); ++ printk(KERN_INFO "debugfs disable beacons\n"); ++ } else if (strncmp(userbuf, "enable", 6) == 0) { ++ AR5K_REG_ENABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE); ++ printk(KERN_INFO "debugfs enable beacons\n"); ++ } ++ return count; ++} ++ ++static const struct file_operations fops_beacon = { ++ .read = read_file_beacon, ++ .write = write_file_beacon, ++ .open = ath5k_debugfs_open, ++ .owner = THIS_MODULE, ++}; ++ ++ ++/* debugfs: reset */ ++ ++static ssize_t write_file_reset(struct file *file, ++ const char __user *userbuf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath5k_softc *sc = file->private_data; ++ tasklet_schedule(&sc->restq); ++ return count; ++} ++ ++static const struct file_operations fops_reset = { ++ .write = write_file_reset, ++ .open = ath5k_debugfs_open, ++ .owner = THIS_MODULE, ++}; ++ ++ ++/* init */ ++ ++void ++ath5k_debug_init(void) ++{ ++ ath5k_global_debugfs = debugfs_create_dir("ath5k", NULL); ++} ++ ++void ++ath5k_debug_init_device(struct ath5k_softc *sc) ++{ ++ sc->debug.level = ath5k_debug; ++ sc->debug.debugfs_phydir = debugfs_create_dir(wiphy_name(sc->hw->wiphy), ++ ath5k_global_debugfs); ++ sc->debug.debugfs_debug = debugfs_create_u32("debug", ++ 0666, sc->debug.debugfs_phydir, &sc->debug.level); ++ ++ sc->debug.debugfs_registers = debugfs_create_file("registers", 0444, ++ sc->debug.debugfs_phydir, ++ sc, &fops_registers); ++ ++ sc->debug.debugfs_tsf = debugfs_create_file("tsf", 0666, ++ sc->debug.debugfs_phydir, ++ sc, &fops_tsf); ++ ++ sc->debug.debugfs_beacon = debugfs_create_file("beacon", 0666, ++ sc->debug.debugfs_phydir, ++ sc, &fops_beacon); ++ ++ sc->debug.debugfs_reset = debugfs_create_file("reset", 0222, ++ sc->debug.debugfs_phydir, ++ sc, &fops_reset); ++} ++ ++void ++ath5k_debug_finish(void) ++{ ++ debugfs_remove(ath5k_global_debugfs); ++} ++ ++void ++ath5k_debug_finish_device(struct ath5k_softc *sc) ++{ ++ debugfs_remove(sc->debug.debugfs_debug); ++ debugfs_remove(sc->debug.debugfs_registers); ++ debugfs_remove(sc->debug.debugfs_tsf); ++ debugfs_remove(sc->debug.debugfs_beacon); ++ debugfs_remove(sc->debug.debugfs_reset); ++ debugfs_remove(sc->debug.debugfs_phydir); ++} ++ ++ ++/* functions used in other places */ ++ ++void ++ath5k_debug_dump_modes(struct ath5k_softc *sc, struct ieee80211_hw_mode *modes) ++{ ++ unsigned int m, i; ++ ++ if (likely(!(sc->debug.level & ATH5K_DEBUG_DUMPMODES))) ++ return; ++ ++ for (m = 0; m < NUM_DRIVER_MODES; m++) { ++ printk(KERN_DEBUG "Mode %u: channels %d, rates %d\n", m, ++ modes[m].num_channels, modes[m].num_rates); ++ printk(KERN_DEBUG " channels:\n"); ++ for (i = 0; i < modes[m].num_channels; i++) ++ printk(KERN_DEBUG " %3d %d %.4x %.4x\n", ++ modes[m].channels[i].chan, ++ modes[m].channels[i].freq, ++ modes[m].channels[i].val, ++ modes[m].channels[i].flag); ++ printk(KERN_DEBUG " rates:\n"); ++ for (i = 0; i < modes[m].num_rates; i++) ++ printk(KERN_DEBUG " %4d %.4x %.4x %.4x\n", ++ modes[m].rates[i].rate, ++ modes[m].rates[i].val, ++ modes[m].rates[i].flags, ++ modes[m].rates[i].val2); ++ } ++} ++ ++static inline void ++ath5k_debug_printrxbuf(struct ath5k_buf *bf, int done) ++{ ++ struct ath5k_desc *ds = bf->desc; ++ ++ printk(KERN_DEBUG "R (%p %llx) %08x %08x %08x %08x %08x %08x %c\n", ++ ds, (unsigned long long)bf->daddr, ++ ds->ds_link, ds->ds_data, ds->ds_ctl0, ds->ds_ctl1, ++ ds->ds_hw[0], ds->ds_hw[1], ++ !done ? ' ' : (ds->ds_rxstat.rs_status == 0) ? '*' : '!'); ++} ++ ++void ++ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) ++{ ++ struct ath5k_desc *ds; ++ struct ath5k_buf *bf; ++ int status; ++ ++ if (likely(!(sc->debug.level & ++ (ATH5K_DEBUG_RESET | ATH5K_DEBUG_FATAL)))) ++ return; ++ ++ printk(KERN_DEBUG "rx queue %x, link %p\n", ++ ath5k_hw_get_rx_buf(ah), sc->rxlink); ++ ++ spin_lock_bh(&sc->rxbuflock); ++ list_for_each_entry(bf, &sc->rxbuf, list) { ++ ds = bf->desc; ++ status = ah->ah_proc_rx_desc(ah, ds); ++ if (!status || (sc->debug.level & ATH5K_DEBUG_FATAL)) ++ ath5k_debug_printrxbuf(bf, status == 0); ++ } ++ spin_unlock_bh(&sc->rxbuflock); ++} ++ ++void ++ath5k_debug_dump_skb(struct ath5k_softc *sc, ++ struct sk_buff *skb, const char *prefix, int tx) ++{ ++ char buf[16]; ++ ++ if (likely(!((tx && (sc->debug.level & ATH5K_DEBUG_DUMP_TX)) || ++ (!tx && (sc->debug.level & ATH5K_DEBUG_DUMP_RX))))) ++ return; ++ ++ snprintf(buf, sizeof(buf), "%s %s", wiphy_name(sc->hw->wiphy), prefix); ++ ++ print_hex_dump_bytes(buf, DUMP_PREFIX_NONE, skb->data, ++ min(200U, skb->len)); ++ ++ printk(KERN_DEBUG "\n"); ++} ++ ++void ++ath5k_debug_printtxbuf(struct ath5k_softc *sc, ++ struct ath5k_buf *bf, int done) ++{ ++ struct ath5k_desc *ds = bf->desc; ++ ++ if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET))) ++ return; ++ ++ printk(KERN_DEBUG "T (%p %llx) %08x %08x %08x %08x %08x %08x %08x " ++ "%08x %c\n", ds, (unsigned long long)bf->daddr, ds->ds_link, ++ ds->ds_data, ds->ds_ctl0, ds->ds_ctl1, ++ ds->ds_hw[0], ds->ds_hw[1], ds->ds_hw[2], ds->ds_hw[3], ++ !done ? ' ' : (ds->ds_txstat.ts_status == 0) ? '*' : '!'); ++} ++ ++#endif /* if ATH5K_DEBUG */ +diff -up /dev/null linux-2.6.23.noarch/drivers/net/wireless/ath5k/base.h +--- /dev/null 2007-12-21 08:33:07.834165456 -0500 ++++ linux-2.6.23.noarch/drivers/net/wireless/ath5k/base.h 2007-12-21 12:18:50.000000000 -0500 +@@ -0,0 +1,178 @@ ++/*- ++ * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer, ++ * without modification. ++ * 2. Redistributions in binary form must reproduce at minimum a disclaimer ++ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any ++ * redistribution must be conditioned upon including a substantially ++ * similar Disclaimer requirement for further binary redistribution. ++ * 3. Neither the names of the above-listed copyright holders nor the names ++ * of any contributors may be used to endorse or promote products derived ++ * from this software without specific prior written permission. ++ * ++ * Alternatively, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") version 2 as published by the Free ++ * Software Foundation. ++ * ++ * NO WARRANTY ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY ++ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, ++ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER ++ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF ++ * THE POSSIBILITY OF SUCH DAMAGES. ++ * ++ */ ++ ++/* ++ * Defintions for the Atheros Wireless LAN controller driver. ++ */ ++#ifndef _DEV_ATH_ATHVAR_H ++#define _DEV_ATH_ATHVAR_H ++ ++#include ++#include ++#include ++#include ++ ++#include "ath5k.h" ++#include "debug.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 */ ++ ++struct ath5k_buf { ++ struct list_head list; ++ unsigned int flags; /* tx descriptor flags */ ++ struct ath5k_desc *desc; /* virtual addr of desc */ ++ dma_addr_t daddr; /* physical addr of desc */ ++ struct sk_buff *skb; /* skbuff for buf */ ++ dma_addr_t skbaddr;/* physical addr of skb data */ ++ struct ieee80211_tx_control ctl; ++}; ++ ++/* ++ * Data transmit queue state. One of these exists for each ++ * hardware transmit queue. Packets sent to us from above ++ * are assigned to queues based on their priority. Not all ++ * devices support a complete set of hardware transmit queues. ++ * For those devices the array sc_ac2q will map multiple ++ * priorities to fewer hardware queues (typically all to one ++ * hardware queue). ++ */ ++struct ath5k_txq { ++ unsigned int qnum; /* hardware q number */ ++ u32 *link; /* link ptr in last TX desc */ ++ struct list_head q; /* transmit queue */ ++ spinlock_t lock; /* lock on q and link */ ++ bool setup; ++}; ++ ++#if CHAN_DEBUG ++#define ATH_CHAN_MAX (26+26+26+200+200) ++#else ++#define ATH_CHAN_MAX (14+14+14+252+20) /* XXX what's the max? */ ++#endif ++ ++/* Software Carrier, keeps track of the driver state ++ * associated with an instance of a device */ ++struct ath5k_softc { ++ struct pci_dev *pdev; /* for dma mapping */ ++ void __iomem *iobase; /* address of the device */ ++ struct mutex lock; /* dev-level lock */ ++ struct ieee80211_tx_queue_stats tx_stats; ++ struct ieee80211_low_level_stats ll_stats; ++ struct ieee80211_hw *hw; /* IEEE 802.11 common */ ++ struct ieee80211_hw_mode modes[NUM_DRIVER_MODES]; ++ struct ieee80211_channel channels[ATH_CHAN_MAX]; ++ struct ieee80211_rate rates[AR5K_MAX_RATES * NUM_DRIVER_MODES]; ++ enum ieee80211_if_types opmode; ++ struct ath5k_hw *ah; /* Atheros HW */ ++ ++#if ATH5K_DEBUG ++ struct ath5k_dbg_info debug; /* debug info */ ++#endif ++ ++ struct ath5k_buf *bufptr; /* allocated buffer ptr */ ++ 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, 6); ++#define ATH_STAT_INVALID 0 /* disable hardware accesses */ ++#define ATH_STAT_MRRETRY 1 /* multi-rate retry support */ ++#define ATH_STAT_PROMISC 2 ++#define ATH_STAT_LEDBLINKING 3 /* LED blink operation active */ ++#define ATH_STAT_LEDENDBLINK 4 /* finish LED blink operation */ ++#define ATH_STAT_LEDSOFT 5 /* enable LED gpio status */ ++ ++ unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */ ++ unsigned int curmode; /* current phy mode */ ++ struct ieee80211_channel *curchan; /* current h/w channel */ ++ ++ int iface_id; /* add/remove_interface id */ ++ ++ struct { ++ u8 rxflags; /* radiotap rx flags */ ++ u8 txflags; /* radiotap tx flags */ ++ u16 ledon; /* softled on time */ ++ u16 ledoff; /* softled off time */ ++ } hwmap[32]; /* h/w rate ix mappings */ ++ ++ enum ath5k_int imask; /* interrupt mask copy */ ++ ++ DECLARE_BITMAP(keymap, AR5K_KEYCACHE_SIZE); /* key use bit map */ ++ ++ u8 bssidmask[ETH_ALEN]; ++ ++ unsigned int led_pin, /* GPIO pin for driving LED */ ++ led_on, /* pin setting for LED on */ ++ led_off; /* off time for current blink */ ++ struct timer_list led_tim; /* led off timer */ ++ u8 led_rxrate; /* current rx rate for LED */ ++ u8 led_txrate; /* current tx rate for LED */ ++ ++ struct tasklet_struct restq; /* reset tasklet */ ++ ++ unsigned int rxbufsize; /* rx size based on mtu */ ++ struct list_head rxbuf; /* receive buffer */ ++ spinlock_t rxbuflock; ++ u32 *rxlink; /* link ptr in last RX desc */ ++ struct tasklet_struct rxtq; /* rx intr tasklet */ ++ ++ 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 tasklet_struct txtq; /* tx intr tasklet */ ++ ++ struct ath5k_buf *bbuf; /* beacon buffer */ ++ unsigned int bhalq, /* SW q for outgoing beacons */ ++ bmisscount, /* missed beacon transmits */ ++ bintval, /* beacon interval */ ++ bsent; ++ ++ struct timer_list calib_tim; /* calibration timer */ ++}; ++ ++#define ath5k_hw_hasbssidmask(_ah) \ ++ (ath5k_hw_get_capability(_ah, AR5K_CAP_BSSIDMASK, 0, NULL) == 0) ++#define ath5k_hw_hasveol(_ah) \ ++ (ath5k_hw_get_capability(_ah, AR5K_CAP_VEOL, 0, NULL) == 0) ++ ++#endif +diff -up /dev/null linux-2.6.23.noarch/drivers/net/wireless/ath5k/regdom.c +--- /dev/null 2007-12-21 08:33:07.834165456 -0500 ++++ linux-2.6.23.noarch/drivers/net/wireless/ath5k/regdom.c 2007-12-21 12:18:50.000000000 -0500 +@@ -0,0 +1,121 @@ ++/* ++ * Copyright (c) 2004, 2005 Reyk Floeter ++ * ++ * Permission to use, copy, modify, and 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. ++ */ ++ ++/* ++ * Basic regulation domain extensions for the IEEE 802.11 stack ++ */ ++ ++#include ++#include ++ ++#include "regdom.h" ++ ++static const struct ath5k_regdommap { ++ enum ath5k_regdom dmn; ++ enum ath5k_regdom dmn5; ++ enum ath5k_regdom dmn2; ++} r_map[] = { ++ { DMN_DEFAULT, DMN_DEBUG, DMN_DEBUG }, ++ { DMN_NULL_WORLD, DMN_NULL, DMN_WORLD }, ++ { DMN_NULL_ETSIB, DMN_NULL, DMN_ETSIB }, ++ { DMN_NULL_ETSIC, DMN_NULL, DMN_ETSIC }, ++ { DMN_FCC1_FCCA, DMN_FCC1, DMN_FCCA }, ++ { DMN_FCC1_WORLD, DMN_FCC1, DMN_WORLD }, ++ { DMN_FCC2_FCCA, DMN_FCC2, DMN_FCCA }, ++ { DMN_FCC2_WORLD, DMN_FCC2, DMN_WORLD }, ++ { DMN_FCC2_ETSIC, DMN_FCC2, DMN_ETSIC }, ++ { DMN_FRANCE_NULL, DMN_ETSI3, DMN_ETSI3 }, ++ { DMN_FCC3_FCCA, DMN_FCC3, DMN_WORLD }, ++ { DMN_ETSI1_WORLD, DMN_ETSI1, DMN_WORLD }, ++ { DMN_ETSI3_ETSIA, DMN_ETSI3, DMN_WORLD }, ++ { DMN_ETSI2_WORLD, DMN_ETSI2, DMN_WORLD }, ++ { DMN_ETSI3_WORLD, DMN_ETSI3, DMN_WORLD }, ++ { DMN_ETSI4_WORLD, DMN_ETSI4, DMN_WORLD }, ++ { DMN_ETSI4_ETSIC, DMN_ETSI4, DMN_ETSIC }, ++ { DMN_ETSI5_WORLD, DMN_ETSI5, DMN_WORLD }, ++ { DMN_ETSI6_WORLD, DMN_ETSI6, DMN_WORLD }, ++ { DMN_ETSI_NULL, DMN_ETSI1, DMN_ETSI1 }, ++ { DMN_MKK1_MKKA, DMN_MKK1, DMN_MKKA }, ++ { DMN_MKK1_MKKB, DMN_MKK1, DMN_MKKA }, ++ { DMN_APL4_WORLD, DMN_APL4, DMN_WORLD }, ++ { DMN_MKK2_MKKA, DMN_MKK2, DMN_MKKA }, ++ { DMN_APL_NULL, DMN_APL1, DMN_NULL }, ++ { DMN_APL2_WORLD, DMN_APL2, DMN_WORLD }, ++ { DMN_APL2_APLC, DMN_APL2, DMN_WORLD }, ++ { DMN_APL3_WORLD, DMN_APL3, DMN_WORLD }, ++ { DMN_MKK1_FCCA, DMN_MKK1, DMN_FCCA }, ++ { DMN_APL2_APLD, DMN_APL2, DMN_APLD }, ++ { DMN_MKK1_MKKA1, DMN_MKK1, DMN_MKKA }, ++ { DMN_MKK1_MKKA2, DMN_MKK1, DMN_MKKA }, ++ { DMN_APL1_WORLD, DMN_APL1, DMN_WORLD }, ++ { DMN_APL1_FCCA, DMN_APL1, DMN_FCCA }, ++ { DMN_APL1_APLA, DMN_APL1, DMN_WORLD }, ++ { DMN_APL1_ETSIC, DMN_APL1, DMN_ETSIC }, ++ { DMN_APL2_ETSIC, DMN_APL2, DMN_ETSIC }, ++ { DMN_APL5_WORLD, DMN_APL5, DMN_WORLD }, ++ { DMN_WOR0_WORLD, DMN_WORLD, DMN_WORLD }, ++ { DMN_WOR1_WORLD, DMN_WORLD, DMN_WORLD }, ++ { DMN_WOR2_WORLD, DMN_WORLD, DMN_WORLD }, ++ { DMN_WOR3_WORLD, DMN_WORLD, DMN_WORLD }, ++ { DMN_WOR4_WORLD, DMN_WORLD, DMN_WORLD }, ++ { DMN_WOR5_ETSIC, DMN_WORLD, DMN_WORLD }, ++ { DMN_WOR01_WORLD, DMN_WORLD, DMN_WORLD }, ++ { DMN_WOR02_WORLD, DMN_WORLD, DMN_WORLD }, ++ { DMN_EU1_WORLD, DMN_ETSI1, DMN_WORLD }, ++ { DMN_WOR9_WORLD, DMN_WORLD, DMN_WORLD }, ++ { DMN_WORA_WORLD, DMN_WORLD, DMN_WORLD }, ++}; ++ ++enum ath5k_regdom ath5k_regdom2flag(enum ath5k_regdom dmn, u16 mhz) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(r_map); i++) { ++ if (r_map[i].dmn == dmn) { ++ if (mhz >= 2000 && mhz <= 3000) ++ return r_map[i].dmn2; ++ if (mhz >= IEEE80211_CHANNELS_5GHZ_MIN && ++ mhz <= IEEE80211_CHANNELS_5GHZ_MAX) ++ return r_map[i].dmn5; ++ } ++ } ++ ++ return DMN_DEBUG; ++} ++ ++u16 ath5k_regdom_from_ieee(enum ath5k_regdom ieee) ++{ ++ u32 regdomain = (u32)ieee; ++ ++ /* ++ * Use the default regulation domain if the value is empty ++ * or not supported by the net80211 regulation code. ++ */ ++ if (ath5k_regdom2flag(regdomain, IEEE80211_CHANNELS_5GHZ_MIN) == ++ DMN_DEBUG) ++ return (u16)AR5K_TUNE_REGDOMAIN; ++ ++ /* It is supported, just return the value */ ++ return regdomain; ++} ++ ++enum ath5k_regdom ath5k_regdom_to_ieee(u16 regdomain) ++{ ++ enum ath5k_regdom ieee = (enum ath5k_regdom)regdomain; ++ ++ return ieee; ++} ++ diff --git a/debian/patches/series/1~experimental.1 b/debian/patches/series/1~experimental.1 index 4a5a29b47..39d7ecaf7 100644 --- a/debian/patches/series/1~experimental.1 +++ b/debian/patches/series/1~experimental.1 @@ -40,3 +40,4 @@ + bugfix/arm/disable-scsi_acard.patch + bugfix/all/git-ieee1394.patch + features/at76.patch ++ features/ath5k.patch