1*d2dd70acSstsp /* $OpenBSD: athn.c,v 1.111 2021/04/15 18:25:43 stsp Exp $ */
2498e8a28Sdamien
3498e8a28Sdamien /*-
4498e8a28Sdamien * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
5bd6ea91dSdamien * Copyright (c) 2008-2010 Atheros Communications Inc.
6498e8a28Sdamien *
7498e8a28Sdamien * Permission to use, copy, modify, and/or distribute this software for any
8498e8a28Sdamien * purpose with or without fee is hereby granted, provided that the above
9498e8a28Sdamien * copyright notice and this permission notice appear in all copies.
10498e8a28Sdamien *
11498e8a28Sdamien * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12498e8a28Sdamien * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13498e8a28Sdamien * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14498e8a28Sdamien * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15498e8a28Sdamien * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16498e8a28Sdamien * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17498e8a28Sdamien * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18498e8a28Sdamien */
19498e8a28Sdamien
20498e8a28Sdamien /*
21498e8a28Sdamien * Driver for Atheros 802.11a/g/n chipsets.
22498e8a28Sdamien */
23498e8a28Sdamien
2413236e8dSdamien #include "athn_usb.h"
25498e8a28Sdamien #include "bpfilter.h"
26498e8a28Sdamien
27498e8a28Sdamien #include <sys/param.h>
28498e8a28Sdamien #include <sys/sockio.h>
29498e8a28Sdamien #include <sys/mbuf.h>
30498e8a28Sdamien #include <sys/kernel.h>
31498e8a28Sdamien #include <sys/socket.h>
32498e8a28Sdamien #include <sys/systm.h>
33498e8a28Sdamien #include <sys/malloc.h>
34498e8a28Sdamien #include <sys/queue.h>
35498e8a28Sdamien #include <sys/timeout.h>
36498e8a28Sdamien #include <sys/conf.h>
37498e8a28Sdamien #include <sys/device.h>
38498e8a28Sdamien #include <sys/stdint.h> /* uintptr_t */
399b18ffb8Sguenther #include <sys/endian.h>
40498e8a28Sdamien
41498e8a28Sdamien #include <machine/bus.h>
42498e8a28Sdamien #include <machine/intr.h>
43498e8a28Sdamien
44498e8a28Sdamien #if NBPFILTER > 0
45498e8a28Sdamien #include <net/bpf.h>
46498e8a28Sdamien #endif
47498e8a28Sdamien #include <net/if.h>
48498e8a28Sdamien #include <net/if_dl.h>
49498e8a28Sdamien #include <net/if_media.h>
50498e8a28Sdamien
51498e8a28Sdamien #include <netinet/in.h>
52498e8a28Sdamien #include <netinet/if_ether.h>
53498e8a28Sdamien
54498e8a28Sdamien #include <net80211/ieee80211_var.h>
55498e8a28Sdamien #include <net80211/ieee80211_amrr.h>
56*d2dd70acSstsp #include <net80211/ieee80211_ra.h>
57498e8a28Sdamien #include <net80211/ieee80211_radiotap.h>
58498e8a28Sdamien
59498e8a28Sdamien #include <dev/ic/athnreg.h>
60498e8a28Sdamien #include <dev/ic/athnvar.h>
61498e8a28Sdamien
62498e8a28Sdamien #ifdef ATHN_DEBUG
634d610262Sdamien int athn_debug = 0;
64498e8a28Sdamien #endif
65498e8a28Sdamien
66498e8a28Sdamien void athn_radiotap_attach(struct athn_softc *);
67498e8a28Sdamien void athn_get_chanlist(struct athn_softc *);
68498e8a28Sdamien const char * athn_get_mac_name(struct athn_softc *);
69498e8a28Sdamien const char * athn_get_rf_name(struct athn_softc *);
70653e45e5Sdamien void athn_led_init(struct athn_softc *);
715632af28Sdamien void athn_set_led(struct athn_softc *, int);
72498e8a28Sdamien void athn_btcoex_init(struct athn_softc *);
73498e8a28Sdamien void athn_btcoex_enable(struct athn_softc *);
74498e8a28Sdamien void athn_btcoex_disable(struct athn_softc *);
75498e8a28Sdamien void athn_set_rxfilter(struct athn_softc *, uint32_t);
76498e8a28Sdamien void athn_get_chipid(struct athn_softc *);
77498e8a28Sdamien int athn_reset_power_on(struct athn_softc *);
78498e8a28Sdamien int athn_reset(struct athn_softc *, int);
79498e8a28Sdamien void athn_init_pll(struct athn_softc *,
80498e8a28Sdamien const struct ieee80211_channel *);
81498e8a28Sdamien int athn_set_power_awake(struct athn_softc *);
82498e8a28Sdamien void athn_set_power_sleep(struct athn_softc *);
83328b15b2Skettenis void athn_write_serdes(struct athn_softc *,
84328b15b2Skettenis const struct athn_serdes *);
85498e8a28Sdamien void athn_config_pcie(struct athn_softc *);
86498e8a28Sdamien void athn_config_nonpcie(struct athn_softc *);
87498e8a28Sdamien int athn_set_chan(struct athn_softc *, struct ieee80211_channel *,
88498e8a28Sdamien struct ieee80211_channel *);
89498e8a28Sdamien int athn_switch_chan(struct athn_softc *,
90498e8a28Sdamien struct ieee80211_channel *, struct ieee80211_channel *);
91498e8a28Sdamien void athn_get_delta_slope(uint32_t, uint32_t *, uint32_t *);
92498e8a28Sdamien void athn_reset_key(struct athn_softc *, int);
93498e8a28Sdamien int athn_set_key(struct ieee80211com *, struct ieee80211_node *,
94498e8a28Sdamien struct ieee80211_key *);
95498e8a28Sdamien void athn_delete_key(struct ieee80211com *, struct ieee80211_node *,
96498e8a28Sdamien struct ieee80211_key *);
977363c99eSstsp void athn_iter_calib(void *, struct ieee80211_node *);
989d1f2812Sstsp int athn_cap_noisefloor(struct athn_softc *, int);
999d1f2812Sstsp int athn_nf_hist_mid(int *, int);
1009d1f2812Sstsp void athn_filter_noisefloor(struct athn_softc *);
1019d1f2812Sstsp void athn_start_noisefloor_calib(struct athn_softc *, int);
102498e8a28Sdamien void athn_calib_to(void *);
103498e8a28Sdamien int athn_init_calib(struct athn_softc *,
104498e8a28Sdamien struct ieee80211_channel *, struct ieee80211_channel *);
105bd6ea91dSdamien uint8_t athn_chan2fbin(struct ieee80211_channel *);
106498e8a28Sdamien int athn_interpolate(int, int, int, int, int);
107bd6ea91dSdamien void athn_get_pier_ival(uint8_t, const uint8_t *, int, int *,
108bd6ea91dSdamien int *);
109498e8a28Sdamien void athn_init_dma(struct athn_softc *);
110bd6ea91dSdamien void athn_rx_start(struct athn_softc *);
111498e8a28Sdamien void athn_inc_tx_trigger_level(struct athn_softc *);
112498e8a28Sdamien int athn_stop_rx_dma(struct athn_softc *);
113498e8a28Sdamien int athn_rx_abort(struct athn_softc *);
114bd6ea91dSdamien void athn_tx_reclaim(struct athn_softc *, int);
115498e8a28Sdamien int athn_tx_pending(struct athn_softc *, int);
116498e8a28Sdamien void athn_stop_tx_dma(struct athn_softc *, int);
117498e8a28Sdamien int athn_txtime(struct athn_softc *, int, int, u_int);
118eff5798eSdamien void athn_set_sta_timers(struct athn_softc *);
119eff5798eSdamien void athn_set_hostap_timers(struct athn_softc *);
120498e8a28Sdamien void athn_set_opmode(struct athn_softc *);
121498e8a28Sdamien void athn_set_bss(struct athn_softc *, struct ieee80211_node *);
122498e8a28Sdamien void athn_enable_interrupts(struct athn_softc *);
123498e8a28Sdamien void athn_disable_interrupts(struct athn_softc *);
124498e8a28Sdamien void athn_init_qos(struct athn_softc *);
125498e8a28Sdamien int athn_hw_reset(struct athn_softc *, struct ieee80211_channel *,
12613236e8dSdamien struct ieee80211_channel *, int);
127498e8a28Sdamien struct ieee80211_node *athn_node_alloc(struct ieee80211com *);
128498e8a28Sdamien void athn_newassoc(struct ieee80211com *, struct ieee80211_node *,
129498e8a28Sdamien int);
130498e8a28Sdamien int athn_media_change(struct ifnet *);
131498e8a28Sdamien void athn_next_scan(void *);
132498e8a28Sdamien int athn_newstate(struct ieee80211com *, enum ieee80211_state,
133498e8a28Sdamien int);
134498e8a28Sdamien void athn_updateedca(struct ieee80211com *);
135186e7a92Sdamien int athn_clock_rate(struct athn_softc *);
1367c3c6bd5Sstsp int athn_chan_sifs(struct ieee80211_channel *);
1377c3c6bd5Sstsp void athn_setsifs(struct athn_softc *);
1387c3c6bd5Sstsp int athn_acktimeout(struct ieee80211_channel *, int);
1397c3c6bd5Sstsp void athn_setacktimeout(struct athn_softc *,
1407c3c6bd5Sstsp struct ieee80211_channel *, int);
1417c3c6bd5Sstsp void athn_setctstimeout(struct athn_softc *,
1427c3c6bd5Sstsp struct ieee80211_channel *, int);
1437c3c6bd5Sstsp void athn_setclockrate(struct athn_softc *);
144498e8a28Sdamien void athn_updateslot(struct ieee80211com *);
145498e8a28Sdamien void athn_start(struct ifnet *);
146498e8a28Sdamien void athn_watchdog(struct ifnet *);
147277846c0Sdamien void athn_set_multi(struct athn_softc *);
148498e8a28Sdamien int athn_ioctl(struct ifnet *, u_long, caddr_t);
149498e8a28Sdamien int athn_init(struct ifnet *);
150498e8a28Sdamien void athn_stop(struct ifnet *, int);
151498e8a28Sdamien void athn_init_tx_queues(struct athn_softc *);
152498e8a28Sdamien int32_t athn_ani_get_rssi(struct athn_softc *);
153498e8a28Sdamien void athn_ani_ofdm_err_trigger(struct athn_softc *);
154498e8a28Sdamien void athn_ani_cck_err_trigger(struct athn_softc *);
155498e8a28Sdamien void athn_ani_lower_immunity(struct athn_softc *);
156498e8a28Sdamien void athn_ani_restart(struct athn_softc *);
157498e8a28Sdamien void athn_ani_monitor(struct athn_softc *);
158498e8a28Sdamien
159bd6ea91dSdamien /* Extern functions. */
160bd6ea91dSdamien int ar5416_attach(struct athn_softc *);
161bd6ea91dSdamien int ar9280_attach(struct athn_softc *);
162bd6ea91dSdamien int ar9285_attach(struct athn_softc *);
163bd6ea91dSdamien int ar9287_attach(struct athn_softc *);
164bd6ea91dSdamien int ar9380_attach(struct athn_softc *);
165bd6ea91dSdamien int ar5416_init_calib(struct athn_softc *,
166bd6ea91dSdamien struct ieee80211_channel *, struct ieee80211_channel *);
16791defb09Sdamien int ar9285_init_calib(struct athn_softc *,
168bd6ea91dSdamien struct ieee80211_channel *, struct ieee80211_channel *);
169bd6ea91dSdamien int ar9003_init_calib(struct athn_softc *);
170bd6ea91dSdamien void ar9285_pa_calib(struct athn_softc *);
1717a911050Sdamien void ar9271_pa_calib(struct athn_softc *);
1721c1c6997Sdamien void ar9287_1_3_enable_async_fifo(struct athn_softc *);
1731c1c6997Sdamien void ar9287_1_3_setup_async_fifo(struct athn_softc *);
174bd6ea91dSdamien void ar9003_reset_txsring(struct athn_softc *);
175bd6ea91dSdamien
176498e8a28Sdamien struct cfdriver athn_cd = {
177498e8a28Sdamien NULL, "athn", DV_IFNET
178498e8a28Sdamien };
179498e8a28Sdamien
180a5564b58Sstsp void
athn_config_ht(struct athn_softc * sc)181a5564b58Sstsp athn_config_ht(struct athn_softc *sc)
182a5564b58Sstsp {
183a5564b58Sstsp struct ieee80211com *ic = &sc->sc_ic;
184a5564b58Sstsp int i, ntxstreams, nrxstreams;
185a5564b58Sstsp
186a5564b58Sstsp if ((sc->flags & ATHN_FLAG_11N) == 0)
187a5564b58Sstsp return;
188a5564b58Sstsp
189a5564b58Sstsp /* Set HT capabilities. */
190a5564b58Sstsp ic->ic_htcaps = (IEEE80211_HTCAP_SMPS_DIS <<
191a5564b58Sstsp IEEE80211_HTCAP_SMPS_SHIFT);
192a5564b58Sstsp #ifdef notyet
193a5564b58Sstsp ic->ic_htcaps |= IEEE80211_HTCAP_CBW20_40 |
194a5564b58Sstsp IEEE80211_HTCAP_SGI40 |
195a5564b58Sstsp IEEE80211_HTCAP_DSSSCCK40;
196a5564b58Sstsp #endif
197a5564b58Sstsp ic->ic_htxcaps = 0;
198a5564b58Sstsp #ifdef notyet
199a5564b58Sstsp if (AR_SREV_9271(sc) || AR_SREV_9287_10_OR_LATER(sc))
200a5564b58Sstsp ic->ic_htcaps |= IEEE80211_HTCAP_SGI20;
201a5564b58Sstsp if (AR_SREV_9380_10_OR_LATER(sc))
202a5564b58Sstsp ic->ic_htcaps |= IEEE80211_HTCAP_LDPC;
203a5564b58Sstsp if (AR_SREV_9280_10_OR_LATER(sc)) {
204a5564b58Sstsp ic->ic_htcaps |= IEEE80211_HTCAP_TXSTBC;
205a5564b58Sstsp ic->ic_htcaps |= 1 << IEEE80211_HTCAP_RXSTBC_SHIFT;
206a5564b58Sstsp }
207a5564b58Sstsp #endif
208a5564b58Sstsp ntxstreams = sc->ntxchains;
209a5564b58Sstsp nrxstreams = sc->nrxchains;
210a5564b58Sstsp if (!AR_SREV_9380_10_OR_LATER(sc)) {
211a5564b58Sstsp ntxstreams = MIN(ntxstreams, 2);
212a5564b58Sstsp nrxstreams = MIN(nrxstreams, 2);
213a5564b58Sstsp }
214a5564b58Sstsp /* Set supported HT rates. */
215a5564b58Sstsp if (ic->ic_userflags & IEEE80211_F_NOMIMO)
216a5564b58Sstsp ntxstreams = nrxstreams = 1;
217a5564b58Sstsp memset(ic->ic_sup_mcs, 0, sizeof(ic->ic_sup_mcs));
218a5564b58Sstsp for (i = 0; i < nrxstreams; i++)
219a5564b58Sstsp ic->ic_sup_mcs[i] = 0xff;
220a5564b58Sstsp ic->ic_tx_mcs_set = IEEE80211_TX_MCS_SET_DEFINED;
221a5564b58Sstsp if (ntxstreams != nrxstreams) {
222a5564b58Sstsp ic->ic_tx_mcs_set |= IEEE80211_TX_RX_MCS_NOT_EQUAL;
223a5564b58Sstsp ic->ic_tx_mcs_set |= (ntxstreams - 1) << 2;
224a5564b58Sstsp }
225a5564b58Sstsp }
226a5564b58Sstsp
227498e8a28Sdamien int
athn_attach(struct athn_softc * sc)228498e8a28Sdamien athn_attach(struct athn_softc *sc)
229498e8a28Sdamien {
230498e8a28Sdamien struct ieee80211com *ic = &sc->sc_ic;
231498e8a28Sdamien struct ifnet *ifp = &ic->ic_if;
232653e45e5Sdamien int error;
233498e8a28Sdamien
23439034321Sdamien /* Read hardware revision. */
23539034321Sdamien athn_get_chipid(sc);
23639034321Sdamien
237498e8a28Sdamien if ((error = athn_reset_power_on(sc)) != 0) {
2383951028aSdamien printf("%s: could not reset chip\n", sc->sc_dev.dv_xname);
239498e8a28Sdamien return (error);
240498e8a28Sdamien }
241498e8a28Sdamien
242498e8a28Sdamien if ((error = athn_set_power_awake(sc)) != 0) {
2433951028aSdamien printf("%s: could not wakeup chip\n", sc->sc_dev.dv_xname);
244498e8a28Sdamien return (error);
245498e8a28Sdamien }
246498e8a28Sdamien
247bd6ea91dSdamien if (AR_SREV_5416(sc) || AR_SREV_9160(sc))
248bd6ea91dSdamien error = ar5416_attach(sc);
249bd6ea91dSdamien else if (AR_SREV_9280(sc))
250bd6ea91dSdamien error = ar9280_attach(sc);
25113236e8dSdamien else if (AR_SREV_9285(sc))
252bd6ea91dSdamien error = ar9285_attach(sc);
25313236e8dSdamien #if NATHN_USB > 0
25413236e8dSdamien else if (AR_SREV_9271(sc))
25513236e8dSdamien error = ar9285_attach(sc);
25613236e8dSdamien #endif
257bd6ea91dSdamien else if (AR_SREV_9287(sc))
258bd6ea91dSdamien error = ar9287_attach(sc);
2597a911050Sdamien else if (AR_SREV_9380(sc) || AR_SREV_9485(sc))
260bd6ea91dSdamien error = ar9380_attach(sc);
2613951028aSdamien else
2623951028aSdamien error = ENOTSUP;
263bd6ea91dSdamien if (error != 0) {
2643951028aSdamien printf("%s: could not attach chip\n", sc->sc_dev.dv_xname);
265498e8a28Sdamien return (error);
266498e8a28Sdamien }
267498e8a28Sdamien
2686fe0fa47Sdamien /* We can put the chip in sleep state now. */
2696fe0fa47Sdamien athn_set_power_sleep(sc);
2706fe0fa47Sdamien
2717a911050Sdamien if (!(sc->flags & ATHN_FLAG_USB)) {
272bd6ea91dSdamien error = sc->ops.dma_alloc(sc);
273bd6ea91dSdamien if (error != 0) {
274bd6ea91dSdamien printf("%s: could not allocate DMA resources\n",
275bd6ea91dSdamien sc->sc_dev.dv_xname);
276bd6ea91dSdamien return (error);
277653e45e5Sdamien }
278eff5798eSdamien /* Steal one Tx buffer for beacons. */
279eff5798eSdamien sc->bcnbuf = SIMPLEQ_FIRST(&sc->txbufs);
280eff5798eSdamien SIMPLEQ_REMOVE_HEAD(&sc->txbufs, bf_list);
2817a911050Sdamien }
282bd6ea91dSdamien
283bd6ea91dSdamien if (sc->flags & ATHN_FLAG_RFSILENT) {
284bd6ea91dSdamien DPRINTF(("found RF switch connected to GPIO pin %d\n",
285bd6ea91dSdamien sc->rfsilent_pin));
286bd6ea91dSdamien }
287498e8a28Sdamien DPRINTF(("%d key cache entries\n", sc->kc_entries));
288498e8a28Sdamien /*
289498e8a28Sdamien * In HostAP mode, the number of STAs that we can handle is
290498e8a28Sdamien * limited by the number of entries in the HW key cache.
291ff1dd4b7Sstsp * TKIP keys would consume 2 entries in this cache but we
292ff1dd4b7Sstsp * only use the hardware crypto engine for CCMP.
293498e8a28Sdamien */
294ff1dd4b7Sstsp ic->ic_max_nnodes = sc->kc_entries - IEEE80211_WEP_NKID;
29506f8da2dSdamien if (ic->ic_max_nnodes > IEEE80211_CACHE_SIZE)
29606f8da2dSdamien ic->ic_max_nnodes = IEEE80211_CACHE_SIZE;
297498e8a28Sdamien
298498e8a28Sdamien DPRINTF(("using %s loop power control\n",
299498e8a28Sdamien (sc->flags & ATHN_FLAG_OLPC) ? "open" : "closed"));
300498e8a28Sdamien
301498e8a28Sdamien DPRINTF(("txchainmask=0x%x rxchainmask=0x%x\n",
302498e8a28Sdamien sc->txchainmask, sc->rxchainmask));
303498e8a28Sdamien /* Count the number of bits set (in lowest 3 bits). */
304498e8a28Sdamien sc->ntxchains =
305498e8a28Sdamien ((sc->txchainmask >> 2) & 1) +
306498e8a28Sdamien ((sc->txchainmask >> 1) & 1) +
307498e8a28Sdamien ((sc->txchainmask >> 0) & 1);
308498e8a28Sdamien sc->nrxchains =
309498e8a28Sdamien ((sc->rxchainmask >> 2) & 1) +
310498e8a28Sdamien ((sc->rxchainmask >> 1) & 1) +
311498e8a28Sdamien ((sc->rxchainmask >> 0) & 1);
312498e8a28Sdamien
313498e8a28Sdamien if (AR_SINGLE_CHIP(sc)) {
3143951028aSdamien printf("%s: %s rev %d (%dT%dR), ROM rev %d, address %s\n",
315498e8a28Sdamien sc->sc_dev.dv_xname, athn_get_mac_name(sc), sc->mac_rev,
3163951028aSdamien sc->ntxchains, sc->nrxchains, sc->eep_rev,
3173951028aSdamien ether_sprintf(ic->ic_myaddr));
318498e8a28Sdamien } else {
3193951028aSdamien printf("%s: MAC %s rev %d, RF %s (%dT%dR), ROM rev %d, "
3203951028aSdamien "address %s\n",
321498e8a28Sdamien sc->sc_dev.dv_xname, athn_get_mac_name(sc), sc->mac_rev,
322498e8a28Sdamien athn_get_rf_name(sc), sc->ntxchains, sc->nrxchains,
3233951028aSdamien sc->eep_rev, ether_sprintf(ic->ic_myaddr));
324498e8a28Sdamien }
325498e8a28Sdamien
326498e8a28Sdamien timeout_set(&sc->scan_to, athn_next_scan, sc);
327498e8a28Sdamien timeout_set(&sc->calib_to, athn_calib_to, sc);
328498e8a28Sdamien
329498e8a28Sdamien sc->amrr.amrr_min_success_threshold = 1;
330498e8a28Sdamien sc->amrr.amrr_max_success_threshold = 15;
331498e8a28Sdamien
332498e8a28Sdamien ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
333498e8a28Sdamien ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */
334498e8a28Sdamien ic->ic_state = IEEE80211_S_INIT;
335498e8a28Sdamien
336498e8a28Sdamien /* Set device capabilities. */
337498e8a28Sdamien ic->ic_caps =
338eff5798eSdamien IEEE80211_C_WEP | /* WEP. */
339eff5798eSdamien IEEE80211_C_RSN | /* WPA/RSN. */
340eff5798eSdamien #ifndef IEEE80211_STA_ONLY
3415dde5fe4Skettenis IEEE80211_C_HOSTAP | /* Host AP mode supported. */
3425dde5fe4Skettenis IEEE80211_C_APPMGT | /* Host AP power saving supported. */
343eff5798eSdamien #endif
344eff5798eSdamien IEEE80211_C_MONITOR | /* Monitor mode supported. */
345eff5798eSdamien IEEE80211_C_SHSLOT | /* Short slot time supported. */
346eff5798eSdamien IEEE80211_C_SHPREAMBLE | /* Short preamble supported. */
347eff5798eSdamien IEEE80211_C_PMGT; /* Power saving supported. */
348498e8a28Sdamien
349a5564b58Sstsp athn_config_ht(sc);
350498e8a28Sdamien
351498e8a28Sdamien /* Set supported rates. */
352bd6ea91dSdamien if (sc->flags & ATHN_FLAG_11G) {
353498e8a28Sdamien ic->ic_sup_rates[IEEE80211_MODE_11B] =
354498e8a28Sdamien ieee80211_std_rateset_11b;
355498e8a28Sdamien ic->ic_sup_rates[IEEE80211_MODE_11G] =
356498e8a28Sdamien ieee80211_std_rateset_11g;
357498e8a28Sdamien }
358bd6ea91dSdamien if (sc->flags & ATHN_FLAG_11A) {
359498e8a28Sdamien ic->ic_sup_rates[IEEE80211_MODE_11A] =
360498e8a28Sdamien ieee80211_std_rateset_11a;
361498e8a28Sdamien }
362498e8a28Sdamien
36332250b29Sray /* Get the list of authorized/supported channels. */
364498e8a28Sdamien athn_get_chanlist(sc);
365498e8a28Sdamien
366498e8a28Sdamien /* IBSS channel undefined for now. */
367498e8a28Sdamien ic->ic_ibss_chan = &ic->ic_channels[0];
368498e8a28Sdamien
369498e8a28Sdamien ifp->if_softc = sc;
370498e8a28Sdamien ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
371498e8a28Sdamien ifp->if_ioctl = athn_ioctl;
372498e8a28Sdamien ifp->if_start = athn_start;
373498e8a28Sdamien ifp->if_watchdog = athn_watchdog;
374498e8a28Sdamien memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
375498e8a28Sdamien
376498e8a28Sdamien if_attach(ifp);
377498e8a28Sdamien ieee80211_ifattach(ifp);
378498e8a28Sdamien ic->ic_node_alloc = athn_node_alloc;
379498e8a28Sdamien ic->ic_newassoc = athn_newassoc;
380498e8a28Sdamien ic->ic_updateslot = athn_updateslot;
381498e8a28Sdamien ic->ic_updateedca = athn_updateedca;
382498e8a28Sdamien ic->ic_set_key = athn_set_key;
383498e8a28Sdamien ic->ic_delete_key = athn_delete_key;
384498e8a28Sdamien
385498e8a28Sdamien /* Override 802.11 state transition machine. */
386498e8a28Sdamien sc->sc_newstate = ic->ic_newstate;
387498e8a28Sdamien ic->ic_newstate = athn_newstate;
388498e8a28Sdamien ieee80211_media_init(ifp, athn_media_change, ieee80211_media_status);
389498e8a28Sdamien
390498e8a28Sdamien #if NBPFILTER > 0
391498e8a28Sdamien athn_radiotap_attach(sc);
392498e8a28Sdamien #endif
393498e8a28Sdamien
394498e8a28Sdamien return (0);
395498e8a28Sdamien }
396498e8a28Sdamien
397498e8a28Sdamien void
athn_detach(struct athn_softc * sc)398498e8a28Sdamien athn_detach(struct athn_softc *sc)
399498e8a28Sdamien {
400498e8a28Sdamien struct ifnet *ifp = &sc->sc_ic.ic_if;
401498e8a28Sdamien int qid;
402498e8a28Sdamien
403498e8a28Sdamien timeout_del(&sc->scan_to);
404498e8a28Sdamien timeout_del(&sc->calib_to);
405498e8a28Sdamien
4067a911050Sdamien if (!(sc->flags & ATHN_FLAG_USB)) {
407498e8a28Sdamien for (qid = 0; qid < ATHN_QID_COUNT; qid++)
408498e8a28Sdamien athn_tx_reclaim(sc, qid);
409bd6ea91dSdamien
410bd6ea91dSdamien /* Free Tx/Rx DMA resources. */
411bd6ea91dSdamien sc->ops.dma_free(sc);
4127a911050Sdamien }
413498e8a28Sdamien /* Free ROM copy. */
414498e8a28Sdamien if (sc->eep != NULL)
415aa3cabd0Stedu free(sc->eep, M_DEVBUF, 0);
416498e8a28Sdamien
417498e8a28Sdamien ieee80211_ifdetach(ifp);
418498e8a28Sdamien if_detach(ifp);
419498e8a28Sdamien }
420498e8a28Sdamien
421498e8a28Sdamien #if NBPFILTER > 0
422498e8a28Sdamien /*
423498e8a28Sdamien * Attach the interface to 802.11 radiotap.
424498e8a28Sdamien */
425498e8a28Sdamien void
athn_radiotap_attach(struct athn_softc * sc)426498e8a28Sdamien athn_radiotap_attach(struct athn_softc *sc)
427498e8a28Sdamien {
428498e8a28Sdamien bpfattach(&sc->sc_drvbpf, &sc->sc_ic.ic_if, DLT_IEEE802_11_RADIO,
429498e8a28Sdamien sizeof(struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN);
430498e8a28Sdamien
43106f8da2dSdamien sc->sc_rxtap_len = sizeof(sc->sc_rxtapu);
432498e8a28Sdamien sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len);
433498e8a28Sdamien sc->sc_rxtap.wr_ihdr.it_present = htole32(ATHN_RX_RADIOTAP_PRESENT);
434498e8a28Sdamien
43506f8da2dSdamien sc->sc_txtap_len = sizeof(sc->sc_txtapu);
436498e8a28Sdamien sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
437498e8a28Sdamien sc->sc_txtap.wt_ihdr.it_present = htole32(ATHN_TX_RADIOTAP_PRESENT);
438498e8a28Sdamien }
439498e8a28Sdamien #endif
440498e8a28Sdamien
441498e8a28Sdamien void
athn_get_chanlist(struct athn_softc * sc)442498e8a28Sdamien athn_get_chanlist(struct athn_softc *sc)
443498e8a28Sdamien {
444498e8a28Sdamien struct ieee80211com *ic = &sc->sc_ic;
445498e8a28Sdamien uint8_t chan;
446498e8a28Sdamien int i;
447498e8a28Sdamien
448bd6ea91dSdamien if (sc->flags & ATHN_FLAG_11G) {
449498e8a28Sdamien for (i = 1; i <= 14; i++) {
450498e8a28Sdamien chan = i;
451498e8a28Sdamien ic->ic_channels[chan].ic_freq =
452498e8a28Sdamien ieee80211_ieee2mhz(chan, IEEE80211_CHAN_2GHZ);
453498e8a28Sdamien ic->ic_channels[chan].ic_flags =
454498e8a28Sdamien IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
455498e8a28Sdamien IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
4567363c99eSstsp if (sc->flags & ATHN_FLAG_11N)
4577363c99eSstsp ic->ic_channels[chan].ic_flags |=
4587363c99eSstsp IEEE80211_CHAN_HT;
459498e8a28Sdamien }
460498e8a28Sdamien }
461bd6ea91dSdamien if (sc->flags & ATHN_FLAG_11A) {
462498e8a28Sdamien for (i = 0; i < nitems(athn_5ghz_chans); i++) {
463498e8a28Sdamien chan = athn_5ghz_chans[i];
464498e8a28Sdamien ic->ic_channels[chan].ic_freq =
465498e8a28Sdamien ieee80211_ieee2mhz(chan, IEEE80211_CHAN_5GHZ);
466498e8a28Sdamien ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_A;
4677363c99eSstsp if (sc->flags & ATHN_FLAG_11N)
4687363c99eSstsp ic->ic_channels[chan].ic_flags |=
4697363c99eSstsp IEEE80211_CHAN_HT;
470498e8a28Sdamien }
471498e8a28Sdamien }
472498e8a28Sdamien }
473498e8a28Sdamien
474498e8a28Sdamien void
athn_rx_start(struct athn_softc * sc)475498e8a28Sdamien athn_rx_start(struct athn_softc *sc)
476498e8a28Sdamien {
477498e8a28Sdamien struct ieee80211com *ic = &sc->sc_ic;
478498e8a28Sdamien uint32_t rfilt;
479498e8a28Sdamien
480bd6ea91dSdamien /* Setup Rx DMA descriptors. */
481bd6ea91dSdamien sc->ops.rx_enable(sc);
482498e8a28Sdamien
483498e8a28Sdamien /* Set Rx filter. */
484498e8a28Sdamien rfilt = AR_RX_FILTER_UCAST | AR_RX_FILTER_BCAST | AR_RX_FILTER_MCAST;
485498e8a28Sdamien /* Want Compressed Block Ack Requests. */
486498e8a28Sdamien rfilt |= AR_RX_FILTER_COMPR_BAR;
487b32386bfSdamien rfilt |= AR_RX_FILTER_BEACON;
488498e8a28Sdamien if (ic->ic_opmode != IEEE80211_M_STA) {
489498e8a28Sdamien rfilt |= AR_RX_FILTER_PROBEREQ;
490498e8a28Sdamien if (ic->ic_opmode == IEEE80211_M_MONITOR)
491498e8a28Sdamien rfilt |= AR_RX_FILTER_PROM;
492498e8a28Sdamien #ifndef IEEE80211_STA_ONLY
493498e8a28Sdamien if (AR_SREV_9280_10_OR_LATER(sc) &&
494498e8a28Sdamien ic->ic_opmode == IEEE80211_M_HOSTAP)
495498e8a28Sdamien rfilt |= AR_RX_FILTER_PSPOLL;
496498e8a28Sdamien #endif
497b32386bfSdamien }
498498e8a28Sdamien athn_set_rxfilter(sc, rfilt);
499498e8a28Sdamien
500498e8a28Sdamien /* Set BSSID mask. */
501498e8a28Sdamien AR_WRITE(sc, AR_BSSMSKL, 0xffffffff);
502498e8a28Sdamien AR_WRITE(sc, AR_BSSMSKU, 0xffff);
503498e8a28Sdamien
504498e8a28Sdamien athn_set_opmode(sc);
505498e8a28Sdamien
506498e8a28Sdamien /* Set multicast filter. */
507498e8a28Sdamien AR_WRITE(sc, AR_MCAST_FIL0, 0xffffffff);
508498e8a28Sdamien AR_WRITE(sc, AR_MCAST_FIL1, 0xffffffff);
509498e8a28Sdamien
510498e8a28Sdamien AR_WRITE(sc, AR_FILT_OFDM, 0);
511498e8a28Sdamien AR_WRITE(sc, AR_FILT_CCK, 0);
512498e8a28Sdamien AR_WRITE(sc, AR_MIBC, 0);
513498e8a28Sdamien AR_WRITE(sc, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
514498e8a28Sdamien AR_WRITE(sc, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
515498e8a28Sdamien
516498e8a28Sdamien /* XXX ANI. */
517498e8a28Sdamien AR_WRITE(sc, AR_PHY_ERR_1, 0);
518498e8a28Sdamien AR_WRITE(sc, AR_PHY_ERR_2, 0);
519498e8a28Sdamien
520498e8a28Sdamien /* Disable HW crypto for now. */
521498e8a28Sdamien AR_SETBITS(sc, AR_DIAG_SW, AR_DIAG_ENCRYPT_DIS | AR_DIAG_DECRYPT_DIS);
522498e8a28Sdamien
523498e8a28Sdamien /* Start PCU Rx. */
524498e8a28Sdamien AR_CLRBITS(sc, AR_DIAG_SW, AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT);
525c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
526498e8a28Sdamien }
527498e8a28Sdamien
528498e8a28Sdamien void
athn_set_rxfilter(struct athn_softc * sc,uint32_t rfilt)529498e8a28Sdamien athn_set_rxfilter(struct athn_softc *sc, uint32_t rfilt)
530498e8a28Sdamien {
531498e8a28Sdamien AR_WRITE(sc, AR_RX_FILTER, rfilt);
532498e8a28Sdamien
533498e8a28Sdamien #ifdef notyet
534498e8a28Sdamien reg = AR_READ(sc, AR_PHY_ERR);
535498e8a28Sdamien reg &= (AR_PHY_ERR_RADAR | AR_PHY_ERR_OFDM_TIMING |
536498e8a28Sdamien AR_PHY_ERR_CCK_TIMING);
537498e8a28Sdamien AR_WRITE(sc, AR_PHY_ERR, reg);
538498e8a28Sdamien if (reg != 0)
539498e8a28Sdamien AR_SETBITS(sc, AR_RXCFG, AR_RXCFG_ZLFDMA);
540498e8a28Sdamien else
541498e8a28Sdamien AR_CLRBITS(sc, AR_RXCFG, AR_RXCFG_ZLFDMA);
542498e8a28Sdamien #else
543498e8a28Sdamien AR_WRITE(sc, AR_PHY_ERR, 0);
544498e8a28Sdamien AR_CLRBITS(sc, AR_RXCFG, AR_RXCFG_ZLFDMA);
545498e8a28Sdamien #endif
546c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
547498e8a28Sdamien }
548498e8a28Sdamien
549498e8a28Sdamien int
athn_intr(void * xsc)550498e8a28Sdamien athn_intr(void *xsc)
551498e8a28Sdamien {
552498e8a28Sdamien struct athn_softc *sc = xsc;
553498e8a28Sdamien struct ifnet *ifp = &sc->sc_ic.ic_if;
554498e8a28Sdamien
555498e8a28Sdamien if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) !=
556498e8a28Sdamien (IFF_UP | IFF_RUNNING))
55746115ddbSkettenis return (0);
558498e8a28Sdamien
559bd6ea91dSdamien return (sc->ops.intr(sc));
560498e8a28Sdamien }
561498e8a28Sdamien
562498e8a28Sdamien void
athn_get_chipid(struct athn_softc * sc)563498e8a28Sdamien athn_get_chipid(struct athn_softc *sc)
564498e8a28Sdamien {
565498e8a28Sdamien uint32_t reg;
566498e8a28Sdamien
567498e8a28Sdamien reg = AR_READ(sc, AR_SREV);
568498e8a28Sdamien if (MS(reg, AR_SREV_ID) == 0xff) {
569498e8a28Sdamien sc->mac_ver = MS(reg, AR_SREV_VERSION2);
570498e8a28Sdamien sc->mac_rev = MS(reg, AR_SREV_REVISION2);
571498e8a28Sdamien if (!(reg & AR_SREV_TYPE2_HOST_MODE))
572498e8a28Sdamien sc->flags |= ATHN_FLAG_PCIE;
573498e8a28Sdamien } else {
574498e8a28Sdamien sc->mac_ver = MS(reg, AR_SREV_VERSION);
575498e8a28Sdamien sc->mac_rev = MS(reg, AR_SREV_REVISION);
576498e8a28Sdamien if (sc->mac_ver == AR_SREV_VERSION_5416_PCIE)
577498e8a28Sdamien sc->flags |= ATHN_FLAG_PCIE;
578498e8a28Sdamien }
579498e8a28Sdamien }
580498e8a28Sdamien
581498e8a28Sdamien const char *
athn_get_mac_name(struct athn_softc * sc)582498e8a28Sdamien athn_get_mac_name(struct athn_softc *sc)
583498e8a28Sdamien {
584498e8a28Sdamien switch (sc->mac_ver) {
585498e8a28Sdamien case AR_SREV_VERSION_5416_PCI:
586498e8a28Sdamien return ("AR5416");
587498e8a28Sdamien case AR_SREV_VERSION_5416_PCIE:
588498e8a28Sdamien return ("AR5418");
589498e8a28Sdamien case AR_SREV_VERSION_9160:
590498e8a28Sdamien return ("AR9160");
591498e8a28Sdamien case AR_SREV_VERSION_9280:
592498e8a28Sdamien return ("AR9280");
593498e8a28Sdamien case AR_SREV_VERSION_9285:
594498e8a28Sdamien return ("AR9285");
5957a911050Sdamien case AR_SREV_VERSION_9271:
5967a911050Sdamien return ("AR9271");
597498e8a28Sdamien case AR_SREV_VERSION_9287:
598498e8a28Sdamien return ("AR9287");
599bd6ea91dSdamien case AR_SREV_VERSION_9380:
600bd6ea91dSdamien return ("AR9380");
6017a911050Sdamien case AR_SREV_VERSION_9485:
6027a911050Sdamien return ("AR9485");
603498e8a28Sdamien }
604498e8a28Sdamien return ("unknown");
605498e8a28Sdamien }
606498e8a28Sdamien
607bd6ea91dSdamien /*
6087a911050Sdamien * Return RF chip name (not for single-chip solutions).
609bd6ea91dSdamien */
610498e8a28Sdamien const char *
athn_get_rf_name(struct athn_softc * sc)611498e8a28Sdamien athn_get_rf_name(struct athn_softc *sc)
612498e8a28Sdamien {
613bd6ea91dSdamien KASSERT(!AR_SINGLE_CHIP(sc));
614bd6ea91dSdamien
615498e8a28Sdamien switch (sc->rf_rev) {
616498e8a28Sdamien case AR_RAD5133_SREV_MAJOR: /* Dual-band 3T3R. */
617498e8a28Sdamien return ("AR5133");
618498e8a28Sdamien case AR_RAD2133_SREV_MAJOR: /* Single-band 3T3R. */
619498e8a28Sdamien return ("AR2133");
620498e8a28Sdamien case AR_RAD5122_SREV_MAJOR: /* Dual-band 2T2R. */
621498e8a28Sdamien return ("AR5122");
622498e8a28Sdamien case AR_RAD2122_SREV_MAJOR: /* Single-band 2T2R. */
623498e8a28Sdamien return ("AR2122");
624498e8a28Sdamien }
625498e8a28Sdamien return ("unknown");
626498e8a28Sdamien }
627498e8a28Sdamien
628498e8a28Sdamien int
athn_reset_power_on(struct athn_softc * sc)629498e8a28Sdamien athn_reset_power_on(struct athn_softc *sc)
630498e8a28Sdamien {
631498e8a28Sdamien int ntries;
632498e8a28Sdamien
633498e8a28Sdamien /* Set force wake. */
634498e8a28Sdamien AR_WRITE(sc, AR_RTC_FORCE_WAKE,
635498e8a28Sdamien AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);
636498e8a28Sdamien
637bd6ea91dSdamien if (!AR_SREV_9380_10_OR_LATER(sc)) {
638498e8a28Sdamien /* Make sure no DMA is active by doing an AHB reset. */
639498e8a28Sdamien AR_WRITE(sc, AR_RC, AR_RC_AHB);
640bd6ea91dSdamien }
641498e8a28Sdamien /* RTC reset and clear. */
642498e8a28Sdamien AR_WRITE(sc, AR_RTC_RESET, 0);
643c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
644498e8a28Sdamien DELAY(2);
645bd6ea91dSdamien if (!AR_SREV_9380_10_OR_LATER(sc))
646498e8a28Sdamien AR_WRITE(sc, AR_RC, 0);
647498e8a28Sdamien AR_WRITE(sc, AR_RTC_RESET, 1);
648498e8a28Sdamien
649498e8a28Sdamien /* Poll until RTC is ON. */
650498e8a28Sdamien for (ntries = 0; ntries < 1000; ntries++) {
651498e8a28Sdamien if ((AR_READ(sc, AR_RTC_STATUS) & AR_RTC_STATUS_M) ==
652498e8a28Sdamien AR_RTC_STATUS_ON)
653498e8a28Sdamien break;
654498e8a28Sdamien DELAY(10);
655498e8a28Sdamien }
656498e8a28Sdamien if (ntries == 1000) {
657498e8a28Sdamien DPRINTF(("RTC not waking up\n"));
658498e8a28Sdamien return (ETIMEDOUT);
659498e8a28Sdamien }
660498e8a28Sdamien return (athn_reset(sc, 0));
661498e8a28Sdamien }
662498e8a28Sdamien
663498e8a28Sdamien int
athn_reset(struct athn_softc * sc,int cold)664498e8a28Sdamien athn_reset(struct athn_softc *sc, int cold)
665498e8a28Sdamien {
666498e8a28Sdamien int ntries;
667498e8a28Sdamien
668498e8a28Sdamien /* Set force wake. */
669498e8a28Sdamien AR_WRITE(sc, AR_RTC_FORCE_WAKE,
670498e8a28Sdamien AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);
671498e8a28Sdamien
672498e8a28Sdamien if (AR_READ(sc, AR_INTR_SYNC_CAUSE) &
673498e8a28Sdamien (AR_INTR_SYNC_LOCAL_TIMEOUT | AR_INTR_SYNC_RADM_CPL_TIMEOUT)) {
674498e8a28Sdamien AR_WRITE(sc, AR_INTR_SYNC_ENABLE, 0);
675bd6ea91dSdamien AR_WRITE(sc, AR_RC, AR_RC_HOSTIF |
676bd6ea91dSdamien (!AR_SREV_9380_10_OR_LATER(sc) ? AR_RC_AHB : 0));
677bd6ea91dSdamien } else if (!AR_SREV_9380_10_OR_LATER(sc))
678498e8a28Sdamien AR_WRITE(sc, AR_RC, AR_RC_AHB);
679498e8a28Sdamien
680498e8a28Sdamien AR_WRITE(sc, AR_RTC_RC, AR_RTC_RC_MAC_WARM |
681498e8a28Sdamien (cold ? AR_RTC_RC_MAC_COLD : 0));
682c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
683498e8a28Sdamien DELAY(50);
684498e8a28Sdamien AR_WRITE(sc, AR_RTC_RC, 0);
685498e8a28Sdamien for (ntries = 0; ntries < 1000; ntries++) {
686498e8a28Sdamien if (!(AR_READ(sc, AR_RTC_RC) &
687498e8a28Sdamien (AR_RTC_RC_MAC_WARM | AR_RTC_RC_MAC_COLD)))
688498e8a28Sdamien break;
689498e8a28Sdamien DELAY(10);
690498e8a28Sdamien }
691498e8a28Sdamien if (ntries == 1000) {
692498e8a28Sdamien DPRINTF(("RTC stuck in MAC reset\n"));
693498e8a28Sdamien return (ETIMEDOUT);
694498e8a28Sdamien }
695498e8a28Sdamien AR_WRITE(sc, AR_RC, 0);
696c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
697498e8a28Sdamien return (0);
698498e8a28Sdamien }
699498e8a28Sdamien
700498e8a28Sdamien int
athn_set_power_awake(struct athn_softc * sc)701498e8a28Sdamien athn_set_power_awake(struct athn_softc *sc)
702498e8a28Sdamien {
703498e8a28Sdamien int ntries, error;
704498e8a28Sdamien
705498e8a28Sdamien /* Do a Power-On-Reset if shutdown. */
706498e8a28Sdamien if ((AR_READ(sc, AR_RTC_STATUS) & AR_RTC_STATUS_M) ==
707498e8a28Sdamien AR_RTC_STATUS_SHUTDOWN) {
708498e8a28Sdamien if ((error = athn_reset_power_on(sc)) != 0)
709498e8a28Sdamien return (error);
710bd6ea91dSdamien if (!AR_SREV_9380_10_OR_LATER(sc))
711498e8a28Sdamien athn_init_pll(sc, NULL);
712498e8a28Sdamien }
713498e8a28Sdamien AR_SETBITS(sc, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN);
714c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
715498e8a28Sdamien DELAY(50); /* Give chip the chance to awake. */
716498e8a28Sdamien
717498e8a28Sdamien /* Poll until RTC is ON. */
718498e8a28Sdamien for (ntries = 0; ntries < 4000; ntries++) {
719498e8a28Sdamien if ((AR_READ(sc, AR_RTC_STATUS) & AR_RTC_STATUS_M) ==
720498e8a28Sdamien AR_RTC_STATUS_ON)
721498e8a28Sdamien break;
722498e8a28Sdamien DELAY(50);
723498e8a28Sdamien AR_SETBITS(sc, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN);
724498e8a28Sdamien }
725498e8a28Sdamien if (ntries == 4000) {
726498e8a28Sdamien DPRINTF(("RTC not waking up\n"));
727498e8a28Sdamien return (ETIMEDOUT);
728498e8a28Sdamien }
729498e8a28Sdamien
730498e8a28Sdamien AR_CLRBITS(sc, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
731c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
732498e8a28Sdamien return (0);
733498e8a28Sdamien }
734498e8a28Sdamien
735498e8a28Sdamien void
athn_set_power_sleep(struct athn_softc * sc)736498e8a28Sdamien athn_set_power_sleep(struct athn_softc *sc)
737498e8a28Sdamien {
738498e8a28Sdamien AR_SETBITS(sc, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
739bd6ea91dSdamien /* Allow the MAC to go to sleep. */
740498e8a28Sdamien AR_CLRBITS(sc, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN);
741bd6ea91dSdamien if (!AR_SREV_9380_10_OR_LATER(sc))
742498e8a28Sdamien AR_WRITE(sc, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
743498e8a28Sdamien /*
744498e8a28Sdamien * NB: Clearing RTC_RESET_EN when setting the chip to sleep mode
745498e8a28Sdamien * results in high power consumption on AR5416 chipsets.
746498e8a28Sdamien */
7477a911050Sdamien if (!AR_SREV_5416(sc) && !AR_SREV_9271(sc))
748498e8a28Sdamien AR_CLRBITS(sc, AR_RTC_RESET, AR_RTC_RESET_EN);
749c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
750498e8a28Sdamien }
751498e8a28Sdamien
752498e8a28Sdamien void
athn_init_pll(struct athn_softc * sc,const struct ieee80211_channel * c)753498e8a28Sdamien athn_init_pll(struct athn_softc *sc, const struct ieee80211_channel *c)
754498e8a28Sdamien {
755498e8a28Sdamien uint32_t pll;
756498e8a28Sdamien
757bd6ea91dSdamien if (AR_SREV_9380_10_OR_LATER(sc)) {
7587a911050Sdamien if (AR_SREV_9485(sc))
7597a911050Sdamien AR_WRITE(sc, AR_RTC_PLL_CONTROL2, 0x886666);
760bd6ea91dSdamien pll = SM(AR_RTC_9160_PLL_REFDIV, 0x5);
761bd6ea91dSdamien pll |= SM(AR_RTC_9160_PLL_DIV, 0x2c);
762bd6ea91dSdamien } else if (AR_SREV_9280_10_OR_LATER(sc)) {
763498e8a28Sdamien pll = SM(AR_RTC_9160_PLL_REFDIV, 0x05);
764498e8a28Sdamien if (c != NULL && IEEE80211_IS_CHAN_5GHZ(c)) {
76597bf8fdcSdamien if (sc->flags & ATHN_FLAG_FAST_PLL_CLOCK)
76697bf8fdcSdamien pll = 0x142c;
76797bf8fdcSdamien else if (AR_SREV_9280_20(sc))
768498e8a28Sdamien pll = 0x2850;
769498e8a28Sdamien else
770498e8a28Sdamien pll |= SM(AR_RTC_9160_PLL_DIV, 0x28);
771498e8a28Sdamien } else
772498e8a28Sdamien pll |= SM(AR_RTC_9160_PLL_DIV, 0x2c);
773498e8a28Sdamien } else if (AR_SREV_9160_10_OR_LATER(sc)) {
774498e8a28Sdamien pll = SM(AR_RTC_9160_PLL_REFDIV, 0x05);
775498e8a28Sdamien if (c != NULL && IEEE80211_IS_CHAN_5GHZ(c))
776498e8a28Sdamien pll |= SM(AR_RTC_9160_PLL_DIV, 0x50);
777498e8a28Sdamien else
778498e8a28Sdamien pll |= SM(AR_RTC_9160_PLL_DIV, 0x58);
779498e8a28Sdamien } else {
780498e8a28Sdamien pll = AR_RTC_PLL_REFDIV_5 | AR_RTC_PLL_DIV2;
781498e8a28Sdamien if (c != NULL && IEEE80211_IS_CHAN_5GHZ(c))
782498e8a28Sdamien pll |= SM(AR_RTC_PLL_DIV, 0x0a);
783498e8a28Sdamien else
784498e8a28Sdamien pll |= SM(AR_RTC_PLL_DIV, 0x0b);
785498e8a28Sdamien }
786498e8a28Sdamien DPRINTFN(5, ("AR_RTC_PLL_CONTROL=0x%08x\n", pll));
787498e8a28Sdamien AR_WRITE(sc, AR_RTC_PLL_CONTROL, pll);
7887a911050Sdamien if (AR_SREV_9271(sc)) {
7897a911050Sdamien /* Switch core clock to 117MHz. */
7907a911050Sdamien AR_WRITE_BARRIER(sc);
7917a911050Sdamien DELAY(500);
792caf92146Skevlo AR_WRITE(sc, AR9271_CLOCK_CONTROL, 0x304);
7937a911050Sdamien }
794c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
795498e8a28Sdamien DELAY(100);
796498e8a28Sdamien AR_WRITE(sc, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK);
797c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
798498e8a28Sdamien }
799498e8a28Sdamien
800498e8a28Sdamien void
athn_write_serdes(struct athn_softc * sc,const struct athn_serdes * serdes)801328b15b2Skettenis athn_write_serdes(struct athn_softc *sc, const struct athn_serdes *serdes)
802498e8a28Sdamien {
803498e8a28Sdamien int i;
804498e8a28Sdamien
805328b15b2Skettenis /* Write sequence to Serializer/Deserializer. */
806328b15b2Skettenis for (i = 0; i < serdes->nvals; i++)
807c8971d2aSstsp AR_WRITE(sc, serdes->regs[i], serdes->vals[i]);
808c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
809498e8a28Sdamien }
810498e8a28Sdamien
811498e8a28Sdamien void
athn_config_pcie(struct athn_softc * sc)812498e8a28Sdamien athn_config_pcie(struct athn_softc *sc)
813498e8a28Sdamien {
814498e8a28Sdamien /* Disable PLL when in L0s as well as receiver clock when in L1. */
815498e8a28Sdamien athn_write_serdes(sc, sc->serdes);
816498e8a28Sdamien
817498e8a28Sdamien DELAY(1000);
818498e8a28Sdamien /* Allow forcing of PCIe core into L1 state. */
819498e8a28Sdamien AR_SETBITS(sc, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
820498e8a28Sdamien
821498e8a28Sdamien #ifndef ATHN_PCIE_WAEN
822498e8a28Sdamien AR_WRITE(sc, AR_WA, sc->workaround);
823498e8a28Sdamien #else
824498e8a28Sdamien AR_WRITE(sc, AR_WA, ATHN_PCIE_WAEN);
825498e8a28Sdamien #endif
826c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
827498e8a28Sdamien }
828498e8a28Sdamien
829328b15b2Skettenis /*
830328b15b2Skettenis * Serializer/Deserializer programming for non-PCIe devices.
831328b15b2Skettenis */
832c8971d2aSstsp static const uint32_t ar_nonpcie_serdes_regs[] = {
833c8971d2aSstsp AR_PCIE_SERDES,
834c8971d2aSstsp AR_PCIE_SERDES,
835c8971d2aSstsp AR_PCIE_SERDES,
836c8971d2aSstsp AR_PCIE_SERDES,
837c8971d2aSstsp AR_PCIE_SERDES,
838c8971d2aSstsp AR_PCIE_SERDES,
839c8971d2aSstsp AR_PCIE_SERDES,
840c8971d2aSstsp AR_PCIE_SERDES,
841c8971d2aSstsp AR_PCIE_SERDES,
842c8971d2aSstsp AR_PCIE_SERDES2,
843c8971d2aSstsp };
844c8971d2aSstsp
845328b15b2Skettenis static const uint32_t ar_nonpcie_serdes_vals[] = {
846328b15b2Skettenis 0x9248fc00,
847328b15b2Skettenis 0x24924924,
848328b15b2Skettenis 0x28000029,
849328b15b2Skettenis 0x57160824,
850328b15b2Skettenis 0x25980579,
851328b15b2Skettenis 0x00000000,
852328b15b2Skettenis 0x1aaabe40,
853328b15b2Skettenis 0xbe105554,
854c8971d2aSstsp 0x000e1007,
855c8971d2aSstsp 0x00000000
856328b15b2Skettenis };
857328b15b2Skettenis
858328b15b2Skettenis static const struct athn_serdes ar_nonpcie_serdes = {
859328b15b2Skettenis nitems(ar_nonpcie_serdes_vals),
860c8971d2aSstsp ar_nonpcie_serdes_regs,
861328b15b2Skettenis ar_nonpcie_serdes_vals
862328b15b2Skettenis };
863328b15b2Skettenis
864498e8a28Sdamien void
athn_config_nonpcie(struct athn_softc * sc)865498e8a28Sdamien athn_config_nonpcie(struct athn_softc *sc)
866498e8a28Sdamien {
867328b15b2Skettenis athn_write_serdes(sc, &ar_nonpcie_serdes);
868498e8a28Sdamien }
869498e8a28Sdamien
870498e8a28Sdamien int
athn_set_chan(struct athn_softc * sc,struct ieee80211_channel * c,struct ieee80211_channel * extc)871498e8a28Sdamien athn_set_chan(struct athn_softc *sc, struct ieee80211_channel *c,
872498e8a28Sdamien struct ieee80211_channel *extc)
873498e8a28Sdamien {
874498e8a28Sdamien struct athn_ops *ops = &sc->ops;
875bd6ea91dSdamien int error, qid;
876498e8a28Sdamien
877498e8a28Sdamien /* Check that Tx is stopped, otherwise RF Bus grant will not work. */
878498e8a28Sdamien for (qid = 0; qid < ATHN_QID_COUNT; qid++)
879498e8a28Sdamien if (athn_tx_pending(sc, qid))
880498e8a28Sdamien return (EBUSY);
881498e8a28Sdamien
882498e8a28Sdamien /* Request RF Bus grant. */
883bd6ea91dSdamien if ((error = ops->rf_bus_request(sc)) != 0)
884bd6ea91dSdamien return (error);
885498e8a28Sdamien
886bd6ea91dSdamien ops->set_phy(sc, c, extc);
887498e8a28Sdamien
888498e8a28Sdamien /* Change the synthesizer. */
889498e8a28Sdamien if ((error = ops->set_synth(sc, c, extc)) != 0)
890498e8a28Sdamien return (error);
891498e8a28Sdamien
892aca706e9Sdamien sc->curchan = c;
893aca706e9Sdamien sc->curchanext = extc;
894aca706e9Sdamien
895498e8a28Sdamien /* Set transmit power values for new channel. */
896498e8a28Sdamien ops->set_txpower(sc, c, extc);
897498e8a28Sdamien
898498e8a28Sdamien /* Release the RF Bus grant. */
899bd6ea91dSdamien ops->rf_bus_release(sc);
900498e8a28Sdamien
901498e8a28Sdamien /* Write delta slope coeffs for modes where OFDM may be used. */
902498e8a28Sdamien if (sc->sc_ic.ic_curmode != IEEE80211_MODE_11B)
903bd6ea91dSdamien ops->set_delta_slope(sc, c, extc);
904498e8a28Sdamien
905498e8a28Sdamien ops->spur_mitigate(sc, c, extc);
906498e8a28Sdamien
907498e8a28Sdamien return (0);
908498e8a28Sdamien }
909498e8a28Sdamien
910498e8a28Sdamien int
athn_switch_chan(struct athn_softc * sc,struct ieee80211_channel * c,struct ieee80211_channel * extc)911498e8a28Sdamien athn_switch_chan(struct athn_softc *sc, struct ieee80211_channel *c,
912498e8a28Sdamien struct ieee80211_channel *extc)
913498e8a28Sdamien {
914498e8a28Sdamien int error, qid;
915498e8a28Sdamien
916498e8a28Sdamien /* Disable interrupts. */
917498e8a28Sdamien athn_disable_interrupts(sc);
918498e8a28Sdamien
919498e8a28Sdamien /* Stop all Tx queues. */
920498e8a28Sdamien for (qid = 0; qid < ATHN_QID_COUNT; qid++)
921498e8a28Sdamien athn_stop_tx_dma(sc, qid);
922498e8a28Sdamien for (qid = 0; qid < ATHN_QID_COUNT; qid++)
923498e8a28Sdamien athn_tx_reclaim(sc, qid);
924498e8a28Sdamien
925498e8a28Sdamien /* Stop Rx. */
92613a6db0dSdamien AR_SETBITS(sc, AR_DIAG_SW, AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT);
927498e8a28Sdamien AR_WRITE(sc, AR_MIBC, AR_MIBC_FMC);
928498e8a28Sdamien AR_WRITE(sc, AR_MIBC, AR_MIBC_CMC);
929498e8a28Sdamien AR_WRITE(sc, AR_FILT_OFDM, 0);
930498e8a28Sdamien AR_WRITE(sc, AR_FILT_CCK, 0);
931498e8a28Sdamien athn_set_rxfilter(sc, 0);
932498e8a28Sdamien error = athn_stop_rx_dma(sc);
933498e8a28Sdamien if (error != 0)
934498e8a28Sdamien goto reset;
935498e8a28Sdamien
9367a911050Sdamien #ifdef notyet
9375632af28Sdamien /* AR9280 needs a full reset. */
9385632af28Sdamien if (AR_SREV_9280(sc))
9397a911050Sdamien #endif
940498e8a28Sdamien goto reset;
941498e8a28Sdamien
942498e8a28Sdamien /* If band or bandwidth changes, we need to do a full reset. */
943aca706e9Sdamien if (c->ic_flags != sc->curchan->ic_flags ||
944aca706e9Sdamien ((extc != NULL) ^ (sc->curchanext != NULL))) {
945a67c32bdSdamien DPRINTFN(2, ("channel band switch\n"));
946498e8a28Sdamien goto reset;
947498e8a28Sdamien }
948498e8a28Sdamien error = athn_set_power_awake(sc);
949498e8a28Sdamien if (error != 0)
950498e8a28Sdamien goto reset;
951498e8a28Sdamien
952498e8a28Sdamien error = athn_set_chan(sc, c, extc);
953498e8a28Sdamien if (error != 0) {
954498e8a28Sdamien reset: /* Error found, try a full reset. */
955a67c32bdSdamien DPRINTFN(3, ("needs a full reset\n"));
95613236e8dSdamien error = athn_hw_reset(sc, c, extc, 0);
957498e8a28Sdamien if (error != 0) /* Hopeless case. */
958498e8a28Sdamien return (error);
959498e8a28Sdamien }
960498e8a28Sdamien athn_rx_start(sc);
961498e8a28Sdamien
962498e8a28Sdamien /* Re-enable interrupts. */
963498e8a28Sdamien athn_enable_interrupts(sc);
964498e8a28Sdamien return (0);
965498e8a28Sdamien }
966498e8a28Sdamien
967498e8a28Sdamien void
athn_get_delta_slope(uint32_t coeff,uint32_t * exponent,uint32_t * mantissa)968498e8a28Sdamien athn_get_delta_slope(uint32_t coeff, uint32_t *exponent, uint32_t *mantissa)
969498e8a28Sdamien {
970498e8a28Sdamien #define COEFF_SCALE_SHIFT 24
971498e8a28Sdamien uint32_t exp, man;
972498e8a28Sdamien
973498e8a28Sdamien /* exponent = 14 - floor(log2(coeff)) */
974498e8a28Sdamien for (exp = 31; exp > 0; exp--)
975498e8a28Sdamien if (coeff & (1 << exp))
976498e8a28Sdamien break;
977498e8a28Sdamien exp = 14 - (exp - COEFF_SCALE_SHIFT);
978498e8a28Sdamien
979498e8a28Sdamien /* mantissa = floor(coeff * 2^exponent + 0.5) */
980498e8a28Sdamien man = coeff + (1 << (COEFF_SCALE_SHIFT - exp - 1));
981498e8a28Sdamien
982498e8a28Sdamien *mantissa = man >> (COEFF_SCALE_SHIFT - exp);
983498e8a28Sdamien *exponent = exp - 16;
984498e8a28Sdamien #undef COEFF_SCALE_SHIFT
985498e8a28Sdamien }
986498e8a28Sdamien
987498e8a28Sdamien void
athn_reset_key(struct athn_softc * sc,int entry)988498e8a28Sdamien athn_reset_key(struct athn_softc *sc, int entry)
989498e8a28Sdamien {
990498e8a28Sdamien /*
991498e8a28Sdamien * NB: Key cache registers access special memory area that requires
992498e8a28Sdamien * two 32-bit writes to actually update the values in the internal
993498e8a28Sdamien * memory. Consequently, writes must be grouped by pair.
994ff1dd4b7Sstsp *
995ff1dd4b7Sstsp * All writes to registers with an offset of 0x0 or 0x8 write to a
996ff1dd4b7Sstsp * temporary register. A write to a register with an offset of 0x4
997ff1dd4b7Sstsp * or 0xc writes concatenates the written value with the value in
998ff1dd4b7Sstsp * the temporary register and writes the result to key cache memory.
999ff1dd4b7Sstsp * The actual written memory area is 50 bits wide.
1000498e8a28Sdamien */
1001498e8a28Sdamien AR_WRITE(sc, AR_KEYTABLE_KEY0(entry), 0);
1002498e8a28Sdamien AR_WRITE(sc, AR_KEYTABLE_KEY1(entry), 0);
1003498e8a28Sdamien
1004498e8a28Sdamien AR_WRITE(sc, AR_KEYTABLE_KEY2(entry), 0);
1005498e8a28Sdamien AR_WRITE(sc, AR_KEYTABLE_KEY3(entry), 0);
1006498e8a28Sdamien
1007498e8a28Sdamien AR_WRITE(sc, AR_KEYTABLE_KEY4(entry), 0);
1008498e8a28Sdamien AR_WRITE(sc, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR);
1009498e8a28Sdamien
1010498e8a28Sdamien AR_WRITE(sc, AR_KEYTABLE_MAC0(entry), 0);
1011498e8a28Sdamien AR_WRITE(sc, AR_KEYTABLE_MAC1(entry), 0);
1012c0a11cf8Sdamien
1013c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
1014498e8a28Sdamien }
1015498e8a28Sdamien
1016498e8a28Sdamien int
athn_set_key(struct ieee80211com * ic,struct ieee80211_node * ni,struct ieee80211_key * k)1017498e8a28Sdamien athn_set_key(struct ieee80211com *ic, struct ieee80211_node *ni,
1018498e8a28Sdamien struct ieee80211_key *k)
1019498e8a28Sdamien {
1020498e8a28Sdamien struct athn_softc *sc = ic->ic_softc;
1021ff1dd4b7Sstsp const uint8_t *key, *addr;
1022ff1dd4b7Sstsp uintptr_t entry;
1023ff1dd4b7Sstsp uint32_t lo, hi, unicast;
1024498e8a28Sdamien
1025ff1dd4b7Sstsp if (k->k_cipher != IEEE80211_CIPHER_CCMP) {
1026ff1dd4b7Sstsp /* Use software crypto for ciphers other than CCMP. */
1027ff1dd4b7Sstsp return ieee80211_set_key(ic, ni, k);
1028498e8a28Sdamien }
1029498e8a28Sdamien
1030ff1dd4b7Sstsp if (!(k->k_flags & IEEE80211_KEY_GROUP)) {
1031797d2c3eSstsp #ifndef IEEE80211_STA_ONLY
1032797d2c3eSstsp if (ic->ic_opmode == IEEE80211_M_HOSTAP)
103306f8da2dSdamien entry = IEEE80211_WEP_NKID + IEEE80211_AID(ni->ni_associd);
1034797d2c3eSstsp else
1035797d2c3eSstsp #endif
1036797d2c3eSstsp entry = IEEE80211_WEP_NKID;
1037ff1dd4b7Sstsp if (entry >= sc->kc_entries - IEEE80211_WEP_NKID)
1038ff1dd4b7Sstsp return ENOSPC;
1039ff1dd4b7Sstsp } else {
104065d92793Sdamien entry = k->k_id;
1041797d2c3eSstsp if (entry >= IEEE80211_WEP_NKID)
1042ff1dd4b7Sstsp return ENOSPC;
1043ff1dd4b7Sstsp }
1044498e8a28Sdamien k->k_priv = (void *)entry;
1045498e8a28Sdamien
1046498e8a28Sdamien /* NB: See note about key cache registers access above. */
10476c0255d5Sdamien key = k->k_key;
10486c0255d5Sdamien
10496c0255d5Sdamien AR_WRITE(sc, AR_KEYTABLE_KEY0(entry), LE_READ_4(&key[ 0]));
10506c0255d5Sdamien AR_WRITE(sc, AR_KEYTABLE_KEY1(entry), LE_READ_2(&key[ 4]));
10516c0255d5Sdamien
10526c0255d5Sdamien AR_WRITE(sc, AR_KEYTABLE_KEY2(entry), LE_READ_4(&key[ 6]));
10536c0255d5Sdamien AR_WRITE(sc, AR_KEYTABLE_KEY3(entry), LE_READ_2(&key[10]));
10546c0255d5Sdamien
10556c0255d5Sdamien AR_WRITE(sc, AR_KEYTABLE_KEY4(entry), LE_READ_4(&key[12]));
1056ff1dd4b7Sstsp AR_WRITE(sc, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CCM);
1057498e8a28Sdamien
1058ff1dd4b7Sstsp unicast = AR_KEYTABLE_VALID;
105965d92793Sdamien if (!(k->k_flags & IEEE80211_KEY_GROUP)) {
1060498e8a28Sdamien addr = ni->ni_macaddr;
1061f2b96a87Sdamien lo = LE_READ_4(&addr[0]);
1062f2b96a87Sdamien hi = LE_READ_2(&addr[4]);
1063498e8a28Sdamien lo = lo >> 1 | hi << 31;
1064498e8a28Sdamien hi = hi >> 1;
1065ff1dd4b7Sstsp } else {
1066ff1dd4b7Sstsp #ifndef IEEE80211_STA_ONLY
1067ff1dd4b7Sstsp if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
1068ff1dd4b7Sstsp uint8_t groupaddr[ETHER_ADDR_LEN];
1069ff1dd4b7Sstsp IEEE80211_ADDR_COPY(groupaddr, ic->ic_myaddr);
1070ff1dd4b7Sstsp groupaddr[0] |= 0x01;
1071ff1dd4b7Sstsp lo = LE_READ_4(&groupaddr[0]);
1072ff1dd4b7Sstsp hi = LE_READ_2(&groupaddr[4]);
1073ff1dd4b7Sstsp lo = lo >> 1 | hi << 31;
1074ff1dd4b7Sstsp hi = hi >> 1;
1075ff1dd4b7Sstsp /*
1076ff1dd4b7Sstsp * KEYTABLE_VALID indicates that the address
1077ff1dd4b7Sstsp * is a unicast address which must match the
1078ff1dd4b7Sstsp * transmitter address when decrypting frames.
1079ff1dd4b7Sstsp * Not setting KEYTABLE_VALID allows hardware to
1080ff1dd4b7Sstsp * use this key for multicast frame decryption.
1081ff1dd4b7Sstsp */
1082ff1dd4b7Sstsp unicast = 0;
108365d92793Sdamien } else
1084ff1dd4b7Sstsp #endif
108565d92793Sdamien lo = hi = 0;
1086ff1dd4b7Sstsp }
1087498e8a28Sdamien AR_WRITE(sc, AR_KEYTABLE_MAC0(entry), lo);
1088ff1dd4b7Sstsp AR_WRITE(sc, AR_KEYTABLE_MAC1(entry), hi | unicast);
1089ff1dd4b7Sstsp
1090ff1dd4b7Sstsp AR_WRITE_BARRIER(sc);
1091ff1dd4b7Sstsp
1092ff1dd4b7Sstsp /* Enable HW crypto. */
1093ff1dd4b7Sstsp AR_CLRBITS(sc, AR_DIAG_SW, AR_DIAG_ENCRYPT_DIS | AR_DIAG_DECRYPT_DIS);
1094ff1dd4b7Sstsp
1095c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
1096498e8a28Sdamien return (0);
1097498e8a28Sdamien }
1098498e8a28Sdamien
1099498e8a28Sdamien void
athn_delete_key(struct ieee80211com * ic,struct ieee80211_node * ni,struct ieee80211_key * k)1100498e8a28Sdamien athn_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni,
1101498e8a28Sdamien struct ieee80211_key *k)
1102498e8a28Sdamien {
1103498e8a28Sdamien struct athn_softc *sc = ic->ic_softc;
1104498e8a28Sdamien uintptr_t entry;
1105498e8a28Sdamien
1106ff1dd4b7Sstsp if (k->k_cipher == IEEE80211_CIPHER_CCMP) {
1107498e8a28Sdamien entry = (uintptr_t)k->k_priv;
1108498e8a28Sdamien athn_reset_key(sc, entry);
1109ff1dd4b7Sstsp explicit_bzero(k, sizeof(*k));
1110ff1dd4b7Sstsp } else
1111498e8a28Sdamien ieee80211_delete_key(ic, ni, k);
1112498e8a28Sdamien }
1113498e8a28Sdamien
1114653e45e5Sdamien void
athn_led_init(struct athn_softc * sc)1115653e45e5Sdamien athn_led_init(struct athn_softc *sc)
1116653e45e5Sdamien {
1117bd6ea91dSdamien struct athn_ops *ops = &sc->ops;
1118bd6ea91dSdamien
1119bd6ea91dSdamien ops->gpio_config_output(sc, sc->led_pin, AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
1120653e45e5Sdamien /* LED off, active low. */
11215632af28Sdamien athn_set_led(sc, 0);
11225632af28Sdamien }
11235632af28Sdamien
11245632af28Sdamien void
athn_set_led(struct athn_softc * sc,int on)11255632af28Sdamien athn_set_led(struct athn_softc *sc, int on)
11265632af28Sdamien {
11275632af28Sdamien struct athn_ops *ops = &sc->ops;
11285632af28Sdamien
11295632af28Sdamien sc->led_state = on;
11305632af28Sdamien ops->gpio_write(sc, sc->led_pin, !sc->led_state);
1131653e45e5Sdamien }
1132653e45e5Sdamien
1133498e8a28Sdamien #ifdef ATHN_BT_COEXISTENCE
1134498e8a28Sdamien void
athn_btcoex_init(struct athn_softc * sc)1135498e8a28Sdamien athn_btcoex_init(struct athn_softc *sc)
1136498e8a28Sdamien {
1137bd6ea91dSdamien struct athn_ops *ops = &sc->ops;
1138498e8a28Sdamien uint32_t reg;
1139498e8a28Sdamien
1140498e8a28Sdamien if (sc->flags & ATHN_FLAG_BTCOEX2WIRE) {
1141498e8a28Sdamien /* Connect bt_active to baseband. */
1142bd6ea91dSdamien AR_CLRBITS(sc, sc->gpio_input_en_off,
1143498e8a28Sdamien AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF |
1144498e8a28Sdamien AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF);
1145bd6ea91dSdamien AR_SETBITS(sc, sc->gpio_input_en_off,
1146498e8a28Sdamien AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB);
1147498e8a28Sdamien
1148498e8a28Sdamien reg = AR_READ(sc, AR_GPIO_INPUT_MUX1);
1149498e8a28Sdamien reg = RW(reg, AR_GPIO_INPUT_MUX1_BT_ACTIVE,
1150498e8a28Sdamien AR_GPIO_BTACTIVE_PIN);
1151498e8a28Sdamien AR_WRITE(sc, AR_GPIO_INPUT_MUX1, reg);
1152c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
1153498e8a28Sdamien
1154bd6ea91dSdamien ops->gpio_config_input(sc, AR_GPIO_BTACTIVE_PIN);
1155498e8a28Sdamien } else { /* 3-wire. */
1156bd6ea91dSdamien AR_SETBITS(sc, sc->gpio_input_en_off,
1157498e8a28Sdamien AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB |
1158498e8a28Sdamien AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB);
1159498e8a28Sdamien
1160498e8a28Sdamien reg = AR_READ(sc, AR_GPIO_INPUT_MUX1);
1161498e8a28Sdamien reg = RW(reg, AR_GPIO_INPUT_MUX1_BT_ACTIVE,
1162498e8a28Sdamien AR_GPIO_BTACTIVE_PIN);
1163498e8a28Sdamien reg = RW(reg, AR_GPIO_INPUT_MUX1_BT_PRIORITY,
1164498e8a28Sdamien AR_GPIO_BTPRIORITY_PIN);
1165498e8a28Sdamien AR_WRITE(sc, AR_GPIO_INPUT_MUX1, reg);
1166c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
1167498e8a28Sdamien
1168bd6ea91dSdamien ops->gpio_config_input(sc, AR_GPIO_BTACTIVE_PIN);
1169bd6ea91dSdamien ops->gpio_config_input(sc, AR_GPIO_BTPRIORITY_PIN);
1170498e8a28Sdamien }
1171498e8a28Sdamien }
1172498e8a28Sdamien
1173498e8a28Sdamien void
athn_btcoex_enable(struct athn_softc * sc)1174498e8a28Sdamien athn_btcoex_enable(struct athn_softc *sc)
1175498e8a28Sdamien {
1176bd6ea91dSdamien struct athn_ops *ops = &sc->ops;
1177498e8a28Sdamien uint32_t reg;
1178498e8a28Sdamien
1179498e8a28Sdamien if (sc->flags & ATHN_FLAG_BTCOEX3WIRE) {
1180498e8a28Sdamien AR_WRITE(sc, AR_BT_COEX_MODE,
1181498e8a28Sdamien SM(AR_BT_MODE, AR_BT_MODE_SLOTTED) |
1182498e8a28Sdamien SM(AR_BT_PRIORITY_TIME, 2) |
1183498e8a28Sdamien SM(AR_BT_FIRST_SLOT_TIME, 5) |
1184498e8a28Sdamien SM(AR_BT_QCU_THRESH, ATHN_QID_AC_BE) |
1185498e8a28Sdamien AR_BT_TXSTATE_EXTEND | AR_BT_TX_FRAME_EXTEND |
1186498e8a28Sdamien AR_BT_QUIET | AR_BT_RX_CLEAR_POLARITY);
1187498e8a28Sdamien AR_WRITE(sc, AR_BT_COEX_WEIGHT,
1188498e8a28Sdamien SM(AR_BTCOEX_BT_WGHT, AR_STOMP_LOW_BT_WGHT) |
1189498e8a28Sdamien SM(AR_BTCOEX_WL_WGHT, AR_STOMP_LOW_WL_WGHT));
1190498e8a28Sdamien AR_WRITE(sc, AR_BT_COEX_MODE2,
1191498e8a28Sdamien SM(AR_BT_BCN_MISS_THRESH, 50) |
1192498e8a28Sdamien AR_BT_HOLD_RX_CLEAR | AR_BT_DISABLE_BT_ANT);
1193498e8a28Sdamien
1194498e8a28Sdamien AR_SETBITS(sc, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE);
1195498e8a28Sdamien AR_CLRBITS(sc, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX);
1196c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
1197498e8a28Sdamien
1198bd6ea91dSdamien ops->gpio_config_output(sc, AR_GPIO_WLANACTIVE_PIN,
1199498e8a28Sdamien AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL);
1200498e8a28Sdamien
1201498e8a28Sdamien } else { /* 2-wire. */
1202bd6ea91dSdamien ops->gpio_config_output(sc, AR_GPIO_WLANACTIVE_PIN,
1203498e8a28Sdamien AR_GPIO_OUTPUT_MUX_AS_TX_FRAME);
1204498e8a28Sdamien }
1205498e8a28Sdamien reg = AR_READ(sc, AR_GPIO_PDPU);
1206498e8a28Sdamien reg &= ~(0x3 << (AR_GPIO_WLANACTIVE_PIN * 2));
1207498e8a28Sdamien reg |= 0x2 << (AR_GPIO_WLANACTIVE_PIN * 2);
1208498e8a28Sdamien AR_WRITE(sc, AR_GPIO_PDPU, reg);
1209c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
1210498e8a28Sdamien
1211498e8a28Sdamien /* Disable PCIe Active State Power Management (ASPM). */
1212498e8a28Sdamien if (sc->sc_disable_aspm != NULL)
1213498e8a28Sdamien sc->sc_disable_aspm(sc);
1214498e8a28Sdamien
1215498e8a28Sdamien /* XXX Start periodic timer. */
1216498e8a28Sdamien }
1217498e8a28Sdamien
1218498e8a28Sdamien void
athn_btcoex_disable(struct athn_softc * sc)1219498e8a28Sdamien athn_btcoex_disable(struct athn_softc *sc)
1220498e8a28Sdamien {
1221bd6ea91dSdamien struct athn_ops *ops = &sc->ops;
1222498e8a28Sdamien
1223bd6ea91dSdamien ops->gpio_write(sc, AR_GPIO_WLANACTIVE_PIN, 0);
1224bd6ea91dSdamien
1225bd6ea91dSdamien ops->gpio_config_output(sc, AR_GPIO_WLANACTIVE_PIN,
1226498e8a28Sdamien AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
1227498e8a28Sdamien
1228498e8a28Sdamien if (sc->flags & ATHN_FLAG_BTCOEX3WIRE) {
1229498e8a28Sdamien AR_WRITE(sc, AR_BT_COEX_MODE,
1230498e8a28Sdamien SM(AR_BT_MODE, AR_BT_MODE_DISABLED) | AR_BT_QUIET);
1231498e8a28Sdamien AR_WRITE(sc, AR_BT_COEX_WEIGHT, 0);
1232498e8a28Sdamien AR_WRITE(sc, AR_BT_COEX_MODE2, 0);
1233498e8a28Sdamien /* XXX Stop periodic timer. */
1234498e8a28Sdamien }
1235c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
1236498e8a28Sdamien /* XXX Restore ASPM setting? */
1237498e8a28Sdamien }
1238498e8a28Sdamien #endif
1239498e8a28Sdamien
1240498e8a28Sdamien void
athn_iter_calib(void * arg,struct ieee80211_node * ni)12417363c99eSstsp athn_iter_calib(void *arg, struct ieee80211_node *ni)
1242498e8a28Sdamien {
1243498e8a28Sdamien struct athn_softc *sc = arg;
1244498e8a28Sdamien struct athn_node *an = (struct athn_node *)ni;
1245498e8a28Sdamien
12467363c99eSstsp if ((ni->ni_flags & IEEE80211_NODE_HT) == 0)
1247498e8a28Sdamien ieee80211_amrr_choose(&sc->amrr, ni, &an->amn);
1248498e8a28Sdamien }
1249498e8a28Sdamien
12509d1f2812Sstsp int
athn_cap_noisefloor(struct athn_softc * sc,int nf)12519d1f2812Sstsp athn_cap_noisefloor(struct athn_softc *sc, int nf)
12529d1f2812Sstsp {
12539d1f2812Sstsp int16_t min, max;
12549d1f2812Sstsp
12559d1f2812Sstsp if (nf == 0 || nf == -1) /* invalid measurement */
12569d1f2812Sstsp return AR_DEFAULT_NOISE_FLOOR;
12579d1f2812Sstsp
12589d1f2812Sstsp if (IEEE80211_IS_CHAN_2GHZ(sc->sc_ic.ic_bss->ni_chan)) {
12599d1f2812Sstsp min = sc->cca_min_2g;
12609d1f2812Sstsp max = sc->cca_max_2g;
12619d1f2812Sstsp } else {
12629d1f2812Sstsp min = sc->cca_min_5g;
12639d1f2812Sstsp max = sc->cca_max_5g;
12649d1f2812Sstsp }
12659d1f2812Sstsp
12669d1f2812Sstsp if (nf < min)
12679d1f2812Sstsp return min;
12689d1f2812Sstsp if (nf > max)
12699d1f2812Sstsp return max;
12709d1f2812Sstsp
12719d1f2812Sstsp return nf;
12729d1f2812Sstsp }
12739d1f2812Sstsp
12749d1f2812Sstsp int
athn_nf_hist_mid(int * nf_vals,int nvalid)12759d1f2812Sstsp athn_nf_hist_mid(int *nf_vals, int nvalid)
12769d1f2812Sstsp {
12779d1f2812Sstsp int nf_sorted[ATHN_NF_CAL_HIST_MAX];
12789d1f2812Sstsp int i, j, nf;
12799d1f2812Sstsp
12809d1f2812Sstsp if (nvalid <= 1)
12819d1f2812Sstsp return nf_vals[0];
12829d1f2812Sstsp
12839d1f2812Sstsp for (i = 0; i < nvalid; i++)
12849d1f2812Sstsp nf_sorted[i] = nf_vals[i];
12859d1f2812Sstsp
12869d1f2812Sstsp for (i = 0; i < nvalid; i++) {
12879d1f2812Sstsp for (j = 1; j < nvalid - i; j++) {
12889d1f2812Sstsp if (nf_sorted[j] > nf_sorted[j - 1]) {
12899d1f2812Sstsp nf = nf_sorted[j];
12909d1f2812Sstsp nf_sorted[j] = nf_sorted[j - 1];
12919d1f2812Sstsp nf_sorted[j - 1] = nf;
12929d1f2812Sstsp }
12939d1f2812Sstsp }
12949d1f2812Sstsp }
12959d1f2812Sstsp
12969d1f2812Sstsp return nf_sorted[nvalid / 2];
12979d1f2812Sstsp }
12989d1f2812Sstsp
12999d1f2812Sstsp void
athn_filter_noisefloor(struct athn_softc * sc)13009d1f2812Sstsp athn_filter_noisefloor(struct athn_softc *sc)
13019d1f2812Sstsp {
13029d1f2812Sstsp int nf_vals[ATHN_NF_CAL_HIST_MAX];
13039d1f2812Sstsp int nf_ext_vals[ATHN_NF_CAL_HIST_MAX];
13049d1f2812Sstsp int i, cur, n;
13059d1f2812Sstsp
13064042d3b5Sstsp for (i = 0; i < sc->nrxchains; i++) {
13079d1f2812Sstsp if (sc->nf_hist_cur > 0)
13089d1f2812Sstsp cur = sc->nf_hist_cur - 1;
13099d1f2812Sstsp else
13109d1f2812Sstsp cur = ATHN_NF_CAL_HIST_MAX - 1;
13119d1f2812Sstsp for (n = 0; n < sc->nf_hist_nvalid; n++) {
13129d1f2812Sstsp nf_vals[n] = sc->nf_hist[cur].nf[i];
13139d1f2812Sstsp nf_ext_vals[n] = sc->nf_hist[cur].nf_ext[i];
13149d1f2812Sstsp if (++cur >= ATHN_NF_CAL_HIST_MAX)
13159d1f2812Sstsp cur = 0;
13169d1f2812Sstsp }
13179d1f2812Sstsp sc->nf_priv[i] = athn_cap_noisefloor(sc,
13189d1f2812Sstsp athn_nf_hist_mid(nf_vals, sc->nf_hist_nvalid));
13199d1f2812Sstsp sc->nf_ext_priv[i] = athn_cap_noisefloor(sc,
13209d1f2812Sstsp athn_nf_hist_mid(nf_ext_vals, sc->nf_hist_nvalid));
13219d1f2812Sstsp }
13229d1f2812Sstsp }
13239d1f2812Sstsp
13249d1f2812Sstsp void
athn_start_noisefloor_calib(struct athn_softc * sc,int reset_history)13259d1f2812Sstsp athn_start_noisefloor_calib(struct athn_softc *sc, int reset_history)
13269d1f2812Sstsp {
13279d1f2812Sstsp extern int ticks;
13289d1f2812Sstsp
13299d1f2812Sstsp if (reset_history)
13309d1f2812Sstsp sc->nf_hist_nvalid = 0;
13319d1f2812Sstsp
13329d1f2812Sstsp sc->nf_calib_pending = 1;
13339d1f2812Sstsp sc->nf_calib_ticks = ticks;
13349d1f2812Sstsp
13359d1f2812Sstsp sc->ops.noisefloor_calib(sc);
13369d1f2812Sstsp }
13379d1f2812Sstsp
1338498e8a28Sdamien void
athn_calib_to(void * arg)1339498e8a28Sdamien athn_calib_to(void *arg)
1340498e8a28Sdamien {
1341b46f6896Sdamien extern int ticks;
1342498e8a28Sdamien struct athn_softc *sc = arg;
1343b46f6896Sdamien struct athn_ops *ops = &sc->ops;
1344498e8a28Sdamien struct ieee80211com *ic = &sc->sc_ic;
1345498e8a28Sdamien int s;
1346498e8a28Sdamien
1347498e8a28Sdamien s = splnet();
1348b46f6896Sdamien
13494116fd83Sdamien /* Do periodic (every 4 minutes) PA calibration. */
13504116fd83Sdamien if (AR_SREV_9285_11_OR_LATER(sc) &&
1351b32386bfSdamien !AR_SREV_9380_10_OR_LATER(sc) &&
1352baaf627aSkrw (ticks - (sc->pa_calib_ticks + 240 * hz)) >= 0) {
13534116fd83Sdamien sc->pa_calib_ticks = ticks;
13547a911050Sdamien if (AR_SREV_9271(sc))
13557a911050Sdamien ar9271_pa_calib(sc);
13567a911050Sdamien else
13574116fd83Sdamien ar9285_pa_calib(sc);
13584116fd83Sdamien }
13594116fd83Sdamien
13609d1f2812Sstsp /* Do periodic (every 4 minutes) NF calibration. */
13619d1f2812Sstsp if (sc->nf_calib_pending && ops->get_noisefloor(sc)) {
13629d1f2812Sstsp if (sc->nf_hist_nvalid < ATHN_NF_CAL_HIST_MAX)
13639d1f2812Sstsp sc->nf_hist_nvalid++;
13649d1f2812Sstsp athn_filter_noisefloor(sc);
13659d1f2812Sstsp ops->apply_noisefloor(sc);
13669d1f2812Sstsp sc->nf_calib_pending = 0;
13679d1f2812Sstsp }
13689d1f2812Sstsp if (ticks - (sc->nf_calib_ticks + 240 * hz) >= 0)
13699d1f2812Sstsp athn_start_noisefloor_calib(sc, 0);
13709d1f2812Sstsp
13714116fd83Sdamien /* Do periodic (every 30 seconds) temperature compensation. */
1372b46f6896Sdamien if ((sc->flags & ATHN_FLAG_OLPC) &&
1373b32386bfSdamien ticks >= sc->olpc_ticks + 30 * hz) {
1374b46f6896Sdamien sc->olpc_ticks = ticks;
1375b46f6896Sdamien ops->olpc_temp_compensation(sc);
1376b46f6896Sdamien }
1377b46f6896Sdamien
1378498e8a28Sdamien #ifdef notyet
1379498e8a28Sdamien /* XXX ANI. */
1380bd6ea91dSdamien athn_ani_monitor(sc);
1381498e8a28Sdamien #endif
1382cc6e2d0bSstsp
1383cc6e2d0bSstsp /* Do periodic (every 30 seconds) ADC/IQ calibration. */
1384cc6e2d0bSstsp if (sc->cur_calib_mask != 0) {
1385cc6e2d0bSstsp ops->next_calib(sc);
1386cc6e2d0bSstsp sc->iqcal_ticks = ticks;
1387cc6e2d0bSstsp } else if (sc->sup_calib_mask != 0 &&
1388cc6e2d0bSstsp ticks >= sc->iqcal_ticks + 30 * hz) {
1389cc6e2d0bSstsp memset(&sc->calib, 0, sizeof(sc->calib));
1390cc6e2d0bSstsp sc->cur_calib_mask = sc->sup_calib_mask;
1391cc6e2d0bSstsp ops->do_calib(sc);
1392cc6e2d0bSstsp sc->iqcal_ticks = ticks;
1393cc6e2d0bSstsp }
1394cc6e2d0bSstsp
1395498e8a28Sdamien if (ic->ic_fixed_rate == -1) {
1396498e8a28Sdamien if (ic->ic_opmode == IEEE80211_M_STA)
13977363c99eSstsp athn_iter_calib(sc, ic->ic_bss);
1398498e8a28Sdamien else
13997363c99eSstsp ieee80211_iterate_nodes(ic, athn_iter_calib, sc);
1400498e8a28Sdamien }
1401498e8a28Sdamien timeout_add_msec(&sc->calib_to, 500);
1402498e8a28Sdamien splx(s);
1403498e8a28Sdamien }
1404498e8a28Sdamien
1405498e8a28Sdamien int
athn_init_calib(struct athn_softc * sc,struct ieee80211_channel * c,struct ieee80211_channel * extc)1406498e8a28Sdamien athn_init_calib(struct athn_softc *sc, struct ieee80211_channel *c,
1407498e8a28Sdamien struct ieee80211_channel *extc)
1408498e8a28Sdamien {
1409bd6ea91dSdamien struct athn_ops *ops = &sc->ops;
1410498e8a28Sdamien int error;
1411498e8a28Sdamien
1412bd6ea91dSdamien if (AR_SREV_9380_10_OR_LATER(sc))
1413bd6ea91dSdamien error = ar9003_init_calib(sc);
141491defb09Sdamien else if (AR_SREV_9285_10_OR_LATER(sc))
141591defb09Sdamien error = ar9285_init_calib(sc, c, extc);
1416498e8a28Sdamien else
1417498e8a28Sdamien error = ar5416_init_calib(sc, c, extc);
1418498e8a28Sdamien if (error != 0)
1419498e8a28Sdamien return (error);
1420498e8a28Sdamien
142126bcd0d6Sdamien if (!AR_SREV_9380_10_OR_LATER(sc)) {
1422498e8a28Sdamien /* Do PA calibration. */
14234116fd83Sdamien if (AR_SREV_9285_11_OR_LATER(sc)) {
14244116fd83Sdamien extern int ticks;
14254116fd83Sdamien sc->pa_calib_ticks = ticks;
14267a911050Sdamien if (AR_SREV_9271(sc))
14277a911050Sdamien ar9271_pa_calib(sc);
14287a911050Sdamien else
1429498e8a28Sdamien ar9285_pa_calib(sc);
14304116fd83Sdamien }
1431498e8a28Sdamien }
14329d1f2812Sstsp
14339d1f2812Sstsp /* Do noisefloor calibration. */
14349d1f2812Sstsp ops->init_noisefloor_calib(sc);
14359d1f2812Sstsp
143626bcd0d6Sdamien if (AR_SREV_9160_10_OR_LATER(sc)) {
143726bcd0d6Sdamien /* Support IQ calibration. */
143826bcd0d6Sdamien sc->sup_calib_mask = ATHN_CAL_IQ;
143926bcd0d6Sdamien if (AR_SREV_9380_10_OR_LATER(sc)) {
144026bcd0d6Sdamien /* Support temperature compensation calibration. */
144126bcd0d6Sdamien sc->sup_calib_mask |= ATHN_CAL_TEMP;
144226bcd0d6Sdamien } else if (IEEE80211_IS_CHAN_5GHZ(c) || extc != NULL) {
144313236e8dSdamien /*
144413236e8dSdamien * ADC gain calibration causes uplink throughput
144513236e8dSdamien * drops in HT40 mode on AR9287.
144613236e8dSdamien */
144713236e8dSdamien if (!AR_SREV_9287(sc)) {
144826bcd0d6Sdamien /* Support ADC gain calibration. */
144926bcd0d6Sdamien sc->sup_calib_mask |= ATHN_CAL_ADC_GAIN;
145013236e8dSdamien }
145126bcd0d6Sdamien /* Support ADC DC offset calibration. */
145226bcd0d6Sdamien sc->sup_calib_mask |= ATHN_CAL_ADC_DC;
145326bcd0d6Sdamien }
145426bcd0d6Sdamien }
1455498e8a28Sdamien return (0);
1456498e8a28Sdamien }
1457498e8a28Sdamien
1458498e8a28Sdamien /*
1459bd6ea91dSdamien * Adaptive noise immunity.
1460498e8a28Sdamien */
1461498e8a28Sdamien int32_t
athn_ani_get_rssi(struct athn_softc * sc)1462498e8a28Sdamien athn_ani_get_rssi(struct athn_softc *sc)
1463498e8a28Sdamien {
1464498e8a28Sdamien return (0); /* XXX */
1465498e8a28Sdamien }
1466498e8a28Sdamien
1467498e8a28Sdamien void
athn_ani_ofdm_err_trigger(struct athn_softc * sc)1468498e8a28Sdamien athn_ani_ofdm_err_trigger(struct athn_softc *sc)
1469498e8a28Sdamien {
1470498e8a28Sdamien struct athn_ani *ani = &sc->ani;
1471bd6ea91dSdamien struct athn_ops *ops = &sc->ops;
1472498e8a28Sdamien int32_t rssi;
1473498e8a28Sdamien
1474498e8a28Sdamien /* First, raise noise immunity level, up to max. */
1475498e8a28Sdamien if (ani->noise_immunity_level < 4) {
1476bd6ea91dSdamien ani->noise_immunity_level++;
1477bd6ea91dSdamien ops->set_noise_immunity_level(sc, ani->noise_immunity_level);
1478498e8a28Sdamien return;
1479498e8a28Sdamien }
1480498e8a28Sdamien
1481498e8a28Sdamien /* Then, raise our spur immunity level, up to max. */
1482498e8a28Sdamien if (ani->spur_immunity_level < 7) {
1483bd6ea91dSdamien ani->spur_immunity_level++;
1484bd6ea91dSdamien ops->set_spur_immunity_level(sc, ani->spur_immunity_level);
1485498e8a28Sdamien return;
1486498e8a28Sdamien }
1487498e8a28Sdamien
1488498e8a28Sdamien #ifndef IEEE80211_STA_ONLY
1489498e8a28Sdamien if (sc->sc_ic.ic_opmode == IEEE80211_M_HOSTAP) {
1490bd6ea91dSdamien if (ani->firstep_level < 2) {
1491bd6ea91dSdamien ani->firstep_level++;
1492bd6ea91dSdamien ops->set_firstep_level(sc, ani->firstep_level);
1493bd6ea91dSdamien }
1494498e8a28Sdamien return;
1495498e8a28Sdamien }
1496498e8a28Sdamien #endif
1497498e8a28Sdamien rssi = athn_ani_get_rssi(sc);
1498498e8a28Sdamien if (rssi > ATHN_ANI_RSSI_THR_HIGH) {
1499498e8a28Sdamien /*
1500498e8a28Sdamien * Beacon RSSI is high, turn off OFDM weak signal detection
1501498e8a28Sdamien * or raise first step level as last resort.
1502498e8a28Sdamien */
1503498e8a28Sdamien if (ani->ofdm_weak_signal) {
1504bd6ea91dSdamien ani->ofdm_weak_signal = 0;
1505bd6ea91dSdamien ops->disable_ofdm_weak_signal(sc);
1506bd6ea91dSdamien ani->spur_immunity_level = 0;
1507bd6ea91dSdamien ops->set_spur_immunity_level(sc, 0);
1508498e8a28Sdamien } else if (ani->firstep_level < 2) {
1509bd6ea91dSdamien ani->firstep_level++;
1510bd6ea91dSdamien ops->set_firstep_level(sc, ani->firstep_level);
1511498e8a28Sdamien }
1512498e8a28Sdamien } else if (rssi > ATHN_ANI_RSSI_THR_LOW) {
1513498e8a28Sdamien /*
1514498e8a28Sdamien * Beacon RSSI is in mid range, we need OFDM weak signal
1515498e8a28Sdamien * detection but we can raise first step level.
1516498e8a28Sdamien */
1517bd6ea91dSdamien if (!ani->ofdm_weak_signal) {
1518bd6ea91dSdamien ani->ofdm_weak_signal = 1;
1519bd6ea91dSdamien ops->enable_ofdm_weak_signal(sc);
1520bd6ea91dSdamien }
1521498e8a28Sdamien if (ani->firstep_level < 2) {
1522bd6ea91dSdamien ani->firstep_level++;
1523bd6ea91dSdamien ops->set_firstep_level(sc, ani->firstep_level);
1524498e8a28Sdamien }
15257363c99eSstsp } else if (IEEE80211_IS_CHAN_2GHZ(sc->sc_ic.ic_bss->ni_chan)) {
1526498e8a28Sdamien /*
1527498e8a28Sdamien * Beacon RSSI is low, if in b/g mode, turn off OFDM weak
1528498e8a28Sdamien * signal detection and zero first step level to maximize
1529498e8a28Sdamien * CCK sensitivity.
1530498e8a28Sdamien */
1531bd6ea91dSdamien if (ani->ofdm_weak_signal) {
1532bd6ea91dSdamien ani->ofdm_weak_signal = 0;
1533bd6ea91dSdamien ops->disable_ofdm_weak_signal(sc);
1534bd6ea91dSdamien }
1535bd6ea91dSdamien if (ani->firstep_level > 0) {
1536bd6ea91dSdamien ani->firstep_level = 0;
1537bd6ea91dSdamien ops->set_firstep_level(sc, 0);
1538bd6ea91dSdamien }
1539498e8a28Sdamien }
1540498e8a28Sdamien }
1541498e8a28Sdamien
1542498e8a28Sdamien void
athn_ani_cck_err_trigger(struct athn_softc * sc)1543498e8a28Sdamien athn_ani_cck_err_trigger(struct athn_softc *sc)
1544498e8a28Sdamien {
1545498e8a28Sdamien struct athn_ani *ani = &sc->ani;
1546bd6ea91dSdamien struct athn_ops *ops = &sc->ops;
1547498e8a28Sdamien int32_t rssi;
1548498e8a28Sdamien
1549498e8a28Sdamien /* Raise noise immunity level, up to max. */
1550498e8a28Sdamien if (ani->noise_immunity_level < 4) {
1551bd6ea91dSdamien ani->noise_immunity_level++;
1552bd6ea91dSdamien ops->set_noise_immunity_level(sc, ani->noise_immunity_level);
1553498e8a28Sdamien return;
1554498e8a28Sdamien }
1555498e8a28Sdamien
1556498e8a28Sdamien #ifndef IEEE80211_STA_ONLY
1557498e8a28Sdamien if (sc->sc_ic.ic_opmode == IEEE80211_M_HOSTAP) {
1558bd6ea91dSdamien if (ani->firstep_level < 2) {
1559bd6ea91dSdamien ani->firstep_level++;
1560bd6ea91dSdamien ops->set_firstep_level(sc, ani->firstep_level);
1561bd6ea91dSdamien }
1562498e8a28Sdamien return;
1563498e8a28Sdamien }
1564498e8a28Sdamien #endif
1565498e8a28Sdamien rssi = athn_ani_get_rssi(sc);
1566498e8a28Sdamien if (rssi > ATHN_ANI_RSSI_THR_LOW) {
1567498e8a28Sdamien /*
1568498e8a28Sdamien * Beacon RSSI is in mid or high range, raise first step
1569498e8a28Sdamien * level.
1570498e8a28Sdamien */
1571bd6ea91dSdamien if (ani->firstep_level < 2) {
1572bd6ea91dSdamien ani->firstep_level++;
1573bd6ea91dSdamien ops->set_firstep_level(sc, ani->firstep_level);
1574bd6ea91dSdamien }
15757363c99eSstsp } else if (IEEE80211_IS_CHAN_2GHZ(sc->sc_ic.ic_bss->ni_chan)) {
1576498e8a28Sdamien /*
1577498e8a28Sdamien * Beacon RSSI is low, zero first step level to maximize
1578498e8a28Sdamien * CCK sensitivity.
1579498e8a28Sdamien */
1580bd6ea91dSdamien if (ani->firstep_level > 0) {
1581bd6ea91dSdamien ani->firstep_level = 0;
1582bd6ea91dSdamien ops->set_firstep_level(sc, 0);
1583bd6ea91dSdamien }
1584498e8a28Sdamien }
1585498e8a28Sdamien }
1586498e8a28Sdamien
1587498e8a28Sdamien void
athn_ani_lower_immunity(struct athn_softc * sc)1588498e8a28Sdamien athn_ani_lower_immunity(struct athn_softc *sc)
1589498e8a28Sdamien {
1590498e8a28Sdamien struct athn_ani *ani = &sc->ani;
1591bd6ea91dSdamien struct athn_ops *ops = &sc->ops;
1592498e8a28Sdamien int32_t rssi;
1593498e8a28Sdamien
1594498e8a28Sdamien #ifndef IEEE80211_STA_ONLY
1595498e8a28Sdamien if (sc->sc_ic.ic_opmode == IEEE80211_M_HOSTAP) {
1596bd6ea91dSdamien if (ani->firstep_level > 0) {
1597bd6ea91dSdamien ani->firstep_level--;
1598bd6ea91dSdamien ops->set_firstep_level(sc, ani->firstep_level);
1599bd6ea91dSdamien }
1600498e8a28Sdamien return;
1601498e8a28Sdamien }
1602498e8a28Sdamien #endif
1603498e8a28Sdamien rssi = athn_ani_get_rssi(sc);
1604498e8a28Sdamien if (rssi > ATHN_ANI_RSSI_THR_HIGH) {
1605498e8a28Sdamien /*
1606498e8a28Sdamien * Beacon RSSI is high, leave OFDM weak signal detection
1607498e8a28Sdamien * off or it may oscillate.
1608498e8a28Sdamien */
1609498e8a28Sdamien } else if (rssi > ATHN_ANI_RSSI_THR_LOW) {
1610498e8a28Sdamien /*
1611498e8a28Sdamien * Beacon RSSI is in mid range, turn on OFDM weak signal
1612498e8a28Sdamien * detection or lower first step level.
1613498e8a28Sdamien */
1614498e8a28Sdamien if (!ani->ofdm_weak_signal) {
1615bd6ea91dSdamien ani->ofdm_weak_signal = 1;
1616bd6ea91dSdamien ops->enable_ofdm_weak_signal(sc);
1617498e8a28Sdamien return;
1618498e8a28Sdamien }
1619498e8a28Sdamien if (ani->firstep_level > 0) {
1620bd6ea91dSdamien ani->firstep_level--;
1621bd6ea91dSdamien ops->set_firstep_level(sc, ani->firstep_level);
1622498e8a28Sdamien return;
1623498e8a28Sdamien }
1624498e8a28Sdamien } else {
1625498e8a28Sdamien /* Beacon RSSI is low, lower first step level. */
1626498e8a28Sdamien if (ani->firstep_level > 0) {
1627bd6ea91dSdamien ani->firstep_level--;
1628bd6ea91dSdamien ops->set_firstep_level(sc, ani->firstep_level);
1629498e8a28Sdamien return;
1630498e8a28Sdamien }
1631498e8a28Sdamien }
1632498e8a28Sdamien /*
1633498e8a28Sdamien * Lower spur immunity level down to zero, or if all else fails,
1634498e8a28Sdamien * lower noise immunity level down to zero.
1635498e8a28Sdamien */
1636bd6ea91dSdamien if (ani->spur_immunity_level > 0) {
1637bd6ea91dSdamien ani->spur_immunity_level--;
1638bd6ea91dSdamien ops->set_spur_immunity_level(sc, ani->spur_immunity_level);
1639bd6ea91dSdamien } else if (ani->noise_immunity_level > 0) {
1640bd6ea91dSdamien ani->noise_immunity_level--;
1641bd6ea91dSdamien ops->set_noise_immunity_level(sc, ani->noise_immunity_level);
1642bd6ea91dSdamien }
1643498e8a28Sdamien }
1644498e8a28Sdamien
1645498e8a28Sdamien void
athn_ani_restart(struct athn_softc * sc)1646498e8a28Sdamien athn_ani_restart(struct athn_softc *sc)
1647498e8a28Sdamien {
1648498e8a28Sdamien struct athn_ani *ani = &sc->ani;
1649498e8a28Sdamien
1650498e8a28Sdamien AR_WRITE(sc, AR_PHY_ERR_1, 0);
1651498e8a28Sdamien AR_WRITE(sc, AR_PHY_ERR_2, 0);
1652498e8a28Sdamien AR_WRITE(sc, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
1653498e8a28Sdamien AR_WRITE(sc, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
1654c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
1655498e8a28Sdamien
1656498e8a28Sdamien ani->listen_time = 0;
1657498e8a28Sdamien ani->ofdm_phy_err_count = 0;
1658498e8a28Sdamien ani->cck_phy_err_count = 0;
1659498e8a28Sdamien }
1660498e8a28Sdamien
1661498e8a28Sdamien void
athn_ani_monitor(struct athn_softc * sc)1662498e8a28Sdamien athn_ani_monitor(struct athn_softc *sc)
1663498e8a28Sdamien {
1664498e8a28Sdamien struct athn_ani *ani = &sc->ani;
1665498e8a28Sdamien uint32_t cyccnt, txfcnt, rxfcnt, phy1, phy2;
1666498e8a28Sdamien int32_t cycdelta, txfdelta, rxfdelta;
1667498e8a28Sdamien int32_t listen_time;
1668498e8a28Sdamien
1669498e8a28Sdamien txfcnt = AR_READ(sc, AR_TFCNT); /* Tx frame count. */
1670498e8a28Sdamien rxfcnt = AR_READ(sc, AR_RFCNT); /* Rx frame count. */
1671498e8a28Sdamien cyccnt = AR_READ(sc, AR_CCCNT); /* Cycle count. */
1672498e8a28Sdamien
1673498e8a28Sdamien if (ani->cyccnt != 0 && ani->cyccnt <= cyccnt) {
1674498e8a28Sdamien cycdelta = cyccnt - ani->cyccnt;
1675498e8a28Sdamien txfdelta = txfcnt - ani->txfcnt;
1676498e8a28Sdamien rxfdelta = rxfcnt - ani->rxfcnt;
1677186e7a92Sdamien
1678186e7a92Sdamien listen_time = (cycdelta - txfdelta - rxfdelta) /
1679186e7a92Sdamien (athn_clock_rate(sc) * 1000);
1680498e8a28Sdamien } else
1681498e8a28Sdamien listen_time = 0;
1682498e8a28Sdamien
1683498e8a28Sdamien ani->cyccnt = cyccnt;
1684498e8a28Sdamien ani->txfcnt = txfcnt;
1685498e8a28Sdamien ani->rxfcnt = rxfcnt;
1686498e8a28Sdamien
1687498e8a28Sdamien if (listen_time < 0) {
1688498e8a28Sdamien athn_ani_restart(sc);
1689498e8a28Sdamien return;
1690498e8a28Sdamien }
1691498e8a28Sdamien ani->listen_time += listen_time;
1692498e8a28Sdamien
1693498e8a28Sdamien phy1 = AR_READ(sc, AR_PHY_ERR_1);
1694498e8a28Sdamien phy2 = AR_READ(sc, AR_PHY_ERR_2);
1695498e8a28Sdamien
1696498e8a28Sdamien if (phy1 < ani->ofdm_phy_err_base) {
1697498e8a28Sdamien AR_WRITE(sc, AR_PHY_ERR_1, ani->ofdm_phy_err_base);
1698498e8a28Sdamien AR_WRITE(sc, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
1699498e8a28Sdamien }
1700498e8a28Sdamien if (phy2 < ani->cck_phy_err_base) {
1701498e8a28Sdamien AR_WRITE(sc, AR_PHY_ERR_2, ani->cck_phy_err_base);
1702498e8a28Sdamien AR_WRITE(sc, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
1703498e8a28Sdamien }
1704c0a11cf8Sdamien if (phy1 < ani->ofdm_phy_err_base || phy2 < ani->cck_phy_err_base) {
1705c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
1706498e8a28Sdamien return;
1707c0a11cf8Sdamien }
1708498e8a28Sdamien ani->ofdm_phy_err_count = phy1 - ani->ofdm_phy_err_base;
1709498e8a28Sdamien ani->cck_phy_err_count = phy2 - ani->cck_phy_err_base;
1710498e8a28Sdamien
1711498e8a28Sdamien if (ani->listen_time > 5 * ATHN_ANI_PERIOD) {
1712498e8a28Sdamien /* Check to see if we need to lower immunity. */
1713498e8a28Sdamien if (ani->ofdm_phy_err_count <=
1714498e8a28Sdamien ani->listen_time * ani->ofdm_trig_low / 1000 &&
1715498e8a28Sdamien ani->cck_phy_err_count <=
1716498e8a28Sdamien ani->listen_time * ani->cck_trig_low / 1000)
1717498e8a28Sdamien athn_ani_lower_immunity(sc);
1718498e8a28Sdamien athn_ani_restart(sc);
1719498e8a28Sdamien
1720498e8a28Sdamien } else if (ani->listen_time > ATHN_ANI_PERIOD) {
1721498e8a28Sdamien /* Check to see if we need to raise immunity. */
1722498e8a28Sdamien if (ani->ofdm_phy_err_count >
1723498e8a28Sdamien ani->listen_time * ani->ofdm_trig_high / 1000) {
1724498e8a28Sdamien athn_ani_ofdm_err_trigger(sc);
1725498e8a28Sdamien athn_ani_restart(sc);
1726498e8a28Sdamien } else if (ani->cck_phy_err_count >
1727498e8a28Sdamien ani->listen_time * ani->cck_trig_high / 1000) {
1728498e8a28Sdamien athn_ani_cck_err_trigger(sc);
1729498e8a28Sdamien athn_ani_restart(sc);
1730498e8a28Sdamien }
1731498e8a28Sdamien }
1732498e8a28Sdamien }
1733498e8a28Sdamien
1734498e8a28Sdamien uint8_t
athn_chan2fbin(struct ieee80211_channel * c)1735498e8a28Sdamien athn_chan2fbin(struct ieee80211_channel *c)
1736498e8a28Sdamien {
1737498e8a28Sdamien if (IEEE80211_IS_CHAN_2GHZ(c))
1738498e8a28Sdamien return (c->ic_freq - 2300);
1739498e8a28Sdamien else
1740498e8a28Sdamien return ((c->ic_freq - 4800) / 5);
1741498e8a28Sdamien }
1742498e8a28Sdamien
1743bd6ea91dSdamien int
athn_interpolate(int x,int x1,int y1,int x2,int y2)1744bd6ea91dSdamien athn_interpolate(int x, int x1, int y1, int x2, int y2)
1745498e8a28Sdamien {
1746bd6ea91dSdamien if (x1 == x2) /* Prevents division by zero. */
1747bd6ea91dSdamien return (y1);
1748bd6ea91dSdamien /* Linear interpolation. */
1749bd6ea91dSdamien return (y1 + ((x - x1) * (y2 - y1)) / (x2 - x1));
1750498e8a28Sdamien }
1751498e8a28Sdamien
1752498e8a28Sdamien void
athn_get_pier_ival(uint8_t fbin,const uint8_t * pierfreq,int npiers,int * lo,int * hi)1753498e8a28Sdamien athn_get_pier_ival(uint8_t fbin, const uint8_t *pierfreq, int npiers,
1754498e8a28Sdamien int *lo, int *hi)
1755498e8a28Sdamien {
1756498e8a28Sdamien int i;
1757498e8a28Sdamien
1758498e8a28Sdamien for (i = 0; i < npiers; i++)
1759498e8a28Sdamien if (pierfreq[i] == AR_BCHAN_UNUSED ||
1760498e8a28Sdamien pierfreq[i] > fbin)
1761498e8a28Sdamien break;
1762498e8a28Sdamien *hi = i;
1763498e8a28Sdamien *lo = *hi - 1;
1764498e8a28Sdamien if (*lo == -1)
1765498e8a28Sdamien *lo = *hi;
1766498e8a28Sdamien else if (*hi == npiers || pierfreq[*hi] == AR_BCHAN_UNUSED)
1767498e8a28Sdamien *hi = *lo;
1768498e8a28Sdamien }
1769498e8a28Sdamien
1770498e8a28Sdamien void
athn_init_dma(struct athn_softc * sc)1771498e8a28Sdamien athn_init_dma(struct athn_softc *sc)
1772498e8a28Sdamien {
1773498e8a28Sdamien uint32_t reg;
1774498e8a28Sdamien
1775bd6ea91dSdamien if (!AR_SREV_9380_10_OR_LATER(sc)) {
1776498e8a28Sdamien /* Set AHB not to do cacheline prefetches. */
1777498e8a28Sdamien AR_SETBITS(sc, AR_AHB_MODE, AR_AHB_PREFETCH_RD_EN);
1778bd6ea91dSdamien }
1779498e8a28Sdamien reg = AR_READ(sc, AR_TXCFG);
1780498e8a28Sdamien /* Let MAC DMA reads be in 128-byte chunks. */
1781498e8a28Sdamien reg = RW(reg, AR_TXCFG_DMASZ, AR_DMASZ_128B);
1782498e8a28Sdamien
1783498e8a28Sdamien /* Set initial Tx trigger level. */
17847a911050Sdamien if (AR_SREV_9285(sc) || AR_SREV_9271(sc))
1785498e8a28Sdamien reg = RW(reg, AR_TXCFG_FTRIG, AR_TXCFG_FTRIG_256B);
1786bd6ea91dSdamien else if (!AR_SREV_9380_10_OR_LATER(sc))
1787498e8a28Sdamien reg = RW(reg, AR_TXCFG_FTRIG, AR_TXCFG_FTRIG_512B);
1788498e8a28Sdamien AR_WRITE(sc, AR_TXCFG, reg);
1789498e8a28Sdamien
1790498e8a28Sdamien /* Let MAC DMA writes be in 128-byte chunks. */
1791498e8a28Sdamien reg = AR_READ(sc, AR_RXCFG);
1792498e8a28Sdamien reg = RW(reg, AR_RXCFG_DMASZ, AR_DMASZ_128B);
1793498e8a28Sdamien AR_WRITE(sc, AR_RXCFG, reg);
1794498e8a28Sdamien
1795498e8a28Sdamien /* Setup Rx FIFO threshold to hold off Tx activities. */
1796498e8a28Sdamien AR_WRITE(sc, AR_RXFIFO_CFG, 512);
1797498e8a28Sdamien
1798498e8a28Sdamien /* Reduce the number of entries in PCU TXBUF to avoid wrap around. */
17997a911050Sdamien if (AR_SREV_9285(sc)) {
18007a911050Sdamien AR_WRITE(sc, AR_PCU_TXBUF_CTRL,
18017a911050Sdamien AR9285_PCU_TXBUF_CTRL_USABLE_SIZE);
18027a911050Sdamien } else if (!AR_SREV_9271(sc)) {
18037a911050Sdamien AR_WRITE(sc, AR_PCU_TXBUF_CTRL,
1804498e8a28Sdamien AR_PCU_TXBUF_CTRL_USABLE_SIZE);
18057a911050Sdamien }
1806c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
1807bd6ea91dSdamien
1808bd6ea91dSdamien /* Reset Tx status ring. */
1809bd6ea91dSdamien if (AR_SREV_9380_10_OR_LATER(sc))
1810bd6ea91dSdamien ar9003_reset_txsring(sc);
1811498e8a28Sdamien }
1812498e8a28Sdamien
1813498e8a28Sdamien void
athn_inc_tx_trigger_level(struct athn_softc * sc)1814498e8a28Sdamien athn_inc_tx_trigger_level(struct athn_softc *sc)
1815498e8a28Sdamien {
1816e38920afSdamien uint32_t reg, ftrig;
1817498e8a28Sdamien
1818498e8a28Sdamien reg = AR_READ(sc, AR_TXCFG);
1819e38920afSdamien ftrig = MS(reg, AR_TXCFG_FTRIG);
1820e38920afSdamien /*
1821e38920afSdamien * NB: The AR9285 and all single-stream parts have an issue that
1822e38920afSdamien * limits the size of the PCU Tx FIFO to 2KB instead of 4KB.
1823e38920afSdamien */
182413236e8dSdamien if (ftrig == ((AR_SREV_9285(sc) || AR_SREV_9271(sc)) ? 0x1f : 0x3f))
1825e38920afSdamien return; /* Already at max. */
1826e38920afSdamien reg = RW(reg, AR_TXCFG_FTRIG, ftrig + 1);
1827498e8a28Sdamien AR_WRITE(sc, AR_TXCFG, reg);
1828c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
1829498e8a28Sdamien }
1830498e8a28Sdamien
1831498e8a28Sdamien int
athn_stop_rx_dma(struct athn_softc * sc)1832498e8a28Sdamien athn_stop_rx_dma(struct athn_softc *sc)
1833498e8a28Sdamien {
1834498e8a28Sdamien int ntries;
1835498e8a28Sdamien
1836498e8a28Sdamien AR_WRITE(sc, AR_CR, AR_CR_RXD);
1837498e8a28Sdamien /* Wait for Rx enable bit to go low. */
1838498e8a28Sdamien for (ntries = 0; ntries < 100; ntries++) {
1839498e8a28Sdamien if (!(AR_READ(sc, AR_CR) & AR_CR_RXE))
1840498e8a28Sdamien return (0);
1841498e8a28Sdamien DELAY(100);
1842498e8a28Sdamien }
1843498e8a28Sdamien DPRINTF(("Rx DMA failed to stop\n"));
1844498e8a28Sdamien return (ETIMEDOUT);
1845498e8a28Sdamien }
1846498e8a28Sdamien
1847498e8a28Sdamien int
athn_rx_abort(struct athn_softc * sc)1848498e8a28Sdamien athn_rx_abort(struct athn_softc *sc)
1849498e8a28Sdamien {
1850498e8a28Sdamien int ntries;
1851498e8a28Sdamien
1852498e8a28Sdamien AR_SETBITS(sc, AR_DIAG_SW, AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT);
1853498e8a28Sdamien for (ntries = 0; ntries < 1000; ntries++) {
1854498e8a28Sdamien if (MS(AR_READ(sc, AR_OBS_BUS_1), AR_OBS_BUS_1_RX_STATE) == 0)
1855498e8a28Sdamien return (0);
1856498e8a28Sdamien DELAY(10);
1857498e8a28Sdamien }
1858498e8a28Sdamien DPRINTF(("Rx failed to go idle in 10ms\n"));
1859498e8a28Sdamien AR_CLRBITS(sc, AR_DIAG_SW, AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT);
1860c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
1861498e8a28Sdamien return (ETIMEDOUT);
1862498e8a28Sdamien }
1863498e8a28Sdamien
1864bd6ea91dSdamien void
athn_tx_reclaim(struct athn_softc * sc,int qid)1865bd6ea91dSdamien athn_tx_reclaim(struct athn_softc *sc, int qid)
1866bd6ea91dSdamien {
1867bd6ea91dSdamien struct athn_txq *txq = &sc->txq[qid];
1868bd6ea91dSdamien struct athn_tx_buf *bf;
1869bd6ea91dSdamien
1870bd6ea91dSdamien /* Reclaim all buffers queued in the specified Tx queue. */
1871bd6ea91dSdamien /* NB: Tx DMA must be stopped. */
1872bd6ea91dSdamien while ((bf = SIMPLEQ_FIRST(&txq->head)) != NULL) {
1873bd6ea91dSdamien SIMPLEQ_REMOVE_HEAD(&txq->head, bf_list);
1874bd6ea91dSdamien
1875bd6ea91dSdamien bus_dmamap_sync(sc->sc_dmat, bf->bf_map, 0,
1876bd6ea91dSdamien bf->bf_map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
1877bd6ea91dSdamien bus_dmamap_unload(sc->sc_dmat, bf->bf_map);
1878bd6ea91dSdamien m_freem(bf->bf_m);
1879bd6ea91dSdamien bf->bf_m = NULL;
1880bd6ea91dSdamien bf->bf_ni = NULL; /* Nodes already freed! */
1881bd6ea91dSdamien
1882bd6ea91dSdamien /* Link Tx buffer back to global free list. */
1883bd6ea91dSdamien SIMPLEQ_INSERT_TAIL(&sc->txbufs, bf, bf_list);
1884bd6ea91dSdamien }
1885bd6ea91dSdamien }
1886bd6ea91dSdamien
1887498e8a28Sdamien int
athn_tx_pending(struct athn_softc * sc,int qid)1888498e8a28Sdamien athn_tx_pending(struct athn_softc *sc, int qid)
1889498e8a28Sdamien {
1890498e8a28Sdamien return (MS(AR_READ(sc, AR_QSTS(qid)), AR_Q_STS_PEND_FR_CNT) != 0 ||
1891498e8a28Sdamien (AR_READ(sc, AR_Q_TXE) & (1 << qid)) != 0);
1892498e8a28Sdamien }
1893498e8a28Sdamien
1894498e8a28Sdamien void
athn_stop_tx_dma(struct athn_softc * sc,int qid)1895498e8a28Sdamien athn_stop_tx_dma(struct athn_softc *sc, int qid)
1896498e8a28Sdamien {
1897498e8a28Sdamien uint32_t tsflo;
1898498e8a28Sdamien int ntries, i;
1899498e8a28Sdamien
1900498e8a28Sdamien AR_WRITE(sc, AR_Q_TXD, 1 << qid);
1901498e8a28Sdamien for (ntries = 0; ntries < 40; ntries++) {
190215d1d028Sdamien if (!athn_tx_pending(sc, qid))
1903498e8a28Sdamien break;
1904498e8a28Sdamien DELAY(100);
1905498e8a28Sdamien }
1906498e8a28Sdamien if (ntries == 40) {
1907498e8a28Sdamien for (i = 0; i < 2; i++) {
1908498e8a28Sdamien tsflo = AR_READ(sc, AR_TSF_L32) / 1024;
1909498e8a28Sdamien AR_WRITE(sc, AR_QUIET2,
1910498e8a28Sdamien SM(AR_QUIET2_QUIET_DUR, 10));
1911498e8a28Sdamien AR_WRITE(sc, AR_QUIET_PERIOD, 100);
1912498e8a28Sdamien AR_WRITE(sc, AR_NEXT_QUIET_TIMER, tsflo);
1913498e8a28Sdamien AR_SETBITS(sc, AR_TIMER_MODE, AR_QUIET_TIMER_EN);
1914bc3f8240Sdamien if (AR_READ(sc, AR_TSF_L32) / 1024 == tsflo)
1915498e8a28Sdamien break;
1916498e8a28Sdamien }
1917498e8a28Sdamien AR_SETBITS(sc, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
1918c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
1919498e8a28Sdamien DELAY(200);
1920498e8a28Sdamien AR_CLRBITS(sc, AR_TIMER_MODE, AR_QUIET_TIMER_EN);
1921c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
1922498e8a28Sdamien
1923498e8a28Sdamien for (ntries = 0; ntries < 40; ntries++) {
192415d1d028Sdamien if (!athn_tx_pending(sc, qid))
1925498e8a28Sdamien break;
1926498e8a28Sdamien DELAY(100);
1927498e8a28Sdamien }
1928498e8a28Sdamien
1929498e8a28Sdamien AR_CLRBITS(sc, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
1930498e8a28Sdamien }
1931498e8a28Sdamien AR_WRITE(sc, AR_Q_TXD, 0);
1932c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
1933498e8a28Sdamien }
1934498e8a28Sdamien
1935498e8a28Sdamien int
athn_txtime(struct athn_softc * sc,int len,int ridx,u_int flags)1936498e8a28Sdamien athn_txtime(struct athn_softc *sc, int len, int ridx, u_int flags)
1937498e8a28Sdamien {
19387363c99eSstsp struct ieee80211com *ic = &sc->sc_ic;
1939498e8a28Sdamien #define divround(a, b) (((a) + (b) - 1) / (b))
1940498e8a28Sdamien int txtime;
1941498e8a28Sdamien
19427363c99eSstsp if (athn_rates[ridx].hwrate & 0x80) { /* MCS */
19437363c99eSstsp /* Assumes a 20MHz channel, HT-mixed frame format, no STBC. */
19447363c99eSstsp txtime = 8 + 8 + 4 + 4 + 4 * 4 + 8 /* HT PLCP */
19457363c99eSstsp + 4 * ((8 * len + 16 + 6) / (athn_rates[ridx].rate * 2));
19467363c99eSstsp if (IEEE80211_IS_CHAN_2GHZ(ic->ic_bss->ni_chan))
19477363c99eSstsp txtime += 6; /* aSignalExtension */
19487363c99eSstsp } else if (athn_rates[ridx].phy == IEEE80211_T_OFDM) {
1949498e8a28Sdamien txtime = divround(8 + 4 * len + 3, athn_rates[ridx].rate);
19508f9a2877Sdamien /* SIFS is 10us for 11g but Signal Extension adds 6us. */
19518f9a2877Sdamien txtime = 16 + 4 + 4 * txtime + 16;
1952498e8a28Sdamien } else {
1953498e8a28Sdamien txtime = divround(16 * len, athn_rates[ridx].rate);
1954498e8a28Sdamien if (ridx != ATHN_RIDX_CCK1 && (flags & IEEE80211_F_SHPREAMBLE))
1955498e8a28Sdamien txtime += 72 + 24;
1956498e8a28Sdamien else
1957498e8a28Sdamien txtime += 144 + 48;
19588f9a2877Sdamien txtime += 10; /* 10us SIFS. */
1959498e8a28Sdamien }
1960498e8a28Sdamien return (txtime);
1961498e8a28Sdamien #undef divround
1962498e8a28Sdamien }
1963498e8a28Sdamien
1964498e8a28Sdamien void
athn_init_tx_queues(struct athn_softc * sc)1965498e8a28Sdamien athn_init_tx_queues(struct athn_softc *sc)
1966498e8a28Sdamien {
1967498e8a28Sdamien int qid;
1968498e8a28Sdamien
1969498e8a28Sdamien for (qid = 0; qid < ATHN_QID_COUNT; qid++) {
1970498e8a28Sdamien SIMPLEQ_INIT(&sc->txq[qid].head);
1971498e8a28Sdamien sc->txq[qid].lastds = NULL;
19726c0255d5Sdamien sc->txq[qid].wait = NULL;
19736c0255d5Sdamien sc->txq[qid].queued = 0;
1974498e8a28Sdamien
1975498e8a28Sdamien AR_WRITE(sc, AR_DRETRY_LIMIT(qid),
1976498e8a28Sdamien SM(AR_D_RETRY_LIMIT_STA_SH, 32) |
1977498e8a28Sdamien SM(AR_D_RETRY_LIMIT_STA_LG, 32) |
1978498e8a28Sdamien SM(AR_D_RETRY_LIMIT_FR_SH, 10));
1979498e8a28Sdamien AR_WRITE(sc, AR_QMISC(qid),
1980498e8a28Sdamien AR_Q_MISC_DCU_EARLY_TERM_REQ);
1981498e8a28Sdamien AR_WRITE(sc, AR_DMISC(qid),
1982498e8a28Sdamien SM(AR_D_MISC_BKOFF_THRESH, 2) |
1983498e8a28Sdamien AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN);
1984498e8a28Sdamien }
1985498e8a28Sdamien
1986498e8a28Sdamien /* Init beacon queue. */
1987498e8a28Sdamien AR_SETBITS(sc, AR_QMISC(ATHN_QID_BEACON),
1988498e8a28Sdamien AR_Q_MISC_FSP_DBA_GATED | AR_Q_MISC_BEACON_USE |
1989498e8a28Sdamien AR_Q_MISC_CBR_INCR_DIS1);
1990498e8a28Sdamien AR_SETBITS(sc, AR_DMISC(ATHN_QID_BEACON),
1991498e8a28Sdamien SM(AR_D_MISC_ARB_LOCKOUT_CNTRL,
1992498e8a28Sdamien AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL) |
1993498e8a28Sdamien AR_D_MISC_BEACON_USE |
1994498e8a28Sdamien AR_D_MISC_POST_FR_BKOFF_DIS);
1995eff5798eSdamien AR_WRITE(sc, AR_DLCL_IFS(ATHN_QID_BEACON),
1996eff5798eSdamien SM(AR_D_LCL_IFS_CWMIN, 0) |
1997eff5798eSdamien SM(AR_D_LCL_IFS_CWMAX, 0) |
1998eff5798eSdamien SM(AR_D_LCL_IFS_AIFS, 1));
1999498e8a28Sdamien
2000bd6ea91dSdamien /* Init CAB (Content After Beacon) queue. */
2001498e8a28Sdamien AR_SETBITS(sc, AR_QMISC(ATHN_QID_CAB),
2002498e8a28Sdamien AR_Q_MISC_FSP_DBA_GATED | AR_Q_MISC_CBR_INCR_DIS1 |
2003498e8a28Sdamien AR_Q_MISC_CBR_INCR_DIS0);
2004498e8a28Sdamien AR_SETBITS(sc, AR_DMISC(ATHN_QID_CAB),
2005498e8a28Sdamien SM(AR_D_MISC_ARB_LOCKOUT_CNTRL,
2006498e8a28Sdamien AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL));
2007498e8a28Sdamien
2008498e8a28Sdamien /* Init PS-Poll queue. */
2009498e8a28Sdamien AR_SETBITS(sc, AR_QMISC(ATHN_QID_PSPOLL),
2010498e8a28Sdamien AR_Q_MISC_CBR_INCR_DIS1);
2011498e8a28Sdamien
2012498e8a28Sdamien /* Init UAPSD queue. */
2013498e8a28Sdamien AR_SETBITS(sc, AR_DMISC(ATHN_QID_UAPSD),
2014498e8a28Sdamien AR_D_MISC_POST_FR_BKOFF_DIS);
2015498e8a28Sdamien
2016bd6ea91dSdamien if (AR_SREV_9380_10_OR_LATER(sc)) {
2017bd6ea91dSdamien /* Enable MAC descriptor CRC check. */
2018bd6ea91dSdamien AR_WRITE(sc, AR_Q_DESC_CRCCHK, AR_Q_DESC_CRCCHK_EN);
2019bd6ea91dSdamien }
2020498e8a28Sdamien /* Enable DESC interrupts for all Tx queues. */
2021498e8a28Sdamien AR_WRITE(sc, AR_IMR_S0, 0x00ff0000);
2022498e8a28Sdamien /* Enable EOL interrupts for all Tx queues except UAPSD. */
2023498e8a28Sdamien AR_WRITE(sc, AR_IMR_S1, 0x00df0000);
2024c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
2025498e8a28Sdamien }
2026498e8a28Sdamien
2027498e8a28Sdamien void
athn_set_sta_timers(struct athn_softc * sc)2028eff5798eSdamien athn_set_sta_timers(struct athn_softc *sc)
2029498e8a28Sdamien {
2030498e8a28Sdamien struct ieee80211com *ic = &sc->sc_ic;
2031498e8a28Sdamien uint32_t tsfhi, tsflo, tsftu, reg;
2032498e8a28Sdamien uint32_t intval, next_tbtt, next_dtim;
2033498e8a28Sdamien int dtim_period, dtim_count, rem_dtim_count;
2034498e8a28Sdamien
2035498e8a28Sdamien tsfhi = AR_READ(sc, AR_TSF_U32);
2036498e8a28Sdamien tsflo = AR_READ(sc, AR_TSF_L32);
2037498e8a28Sdamien tsftu = AR_TSF_TO_TU(tsfhi, tsflo) + AR_FUDGE;
2038498e8a28Sdamien
2039498e8a28Sdamien /* Beacon interval in TU. */
2040eff5798eSdamien intval = ic->ic_bss->ni_intval;
2041498e8a28Sdamien
2042498e8a28Sdamien next_tbtt = roundup(tsftu, intval);
2043498e8a28Sdamien #ifdef notyet
2044498e8a28Sdamien dtim_period = ic->ic_dtim_period;
2045498e8a28Sdamien if (dtim_period <= 0)
2046498e8a28Sdamien #endif
2047498e8a28Sdamien dtim_period = 1; /* Assume all TIMs are DTIMs. */
2048498e8a28Sdamien
2049498e8a28Sdamien #ifdef notyet
2050498e8a28Sdamien dtim_count = ic->ic_dtim_count;
2051498e8a28Sdamien if (dtim_count >= dtim_period) /* Should not happen. */
2052498e8a28Sdamien #endif
2053498e8a28Sdamien dtim_count = 0; /* Assume last TIM was a DTIM. */
2054498e8a28Sdamien
2055498e8a28Sdamien /* Compute number of remaining TIMs until next DTIM. */
2056498e8a28Sdamien rem_dtim_count = 0; /* XXX */
2057498e8a28Sdamien next_dtim = next_tbtt + rem_dtim_count * intval;
2058498e8a28Sdamien
2059498e8a28Sdamien AR_WRITE(sc, AR_NEXT_TBTT_TIMER, next_tbtt * IEEE80211_DUR_TU);
2060498e8a28Sdamien AR_WRITE(sc, AR_BEACON_PERIOD, intval * IEEE80211_DUR_TU);
2061498e8a28Sdamien AR_WRITE(sc, AR_DMA_BEACON_PERIOD, intval * IEEE80211_DUR_TU);
2062498e8a28Sdamien
2063498e8a28Sdamien /*
2064498e8a28Sdamien * Set the number of consecutive beacons to miss before raising
2065498e8a28Sdamien * a BMISS interrupt to 10.
2066498e8a28Sdamien */
2067498e8a28Sdamien reg = AR_READ(sc, AR_RSSI_THR);
2068498e8a28Sdamien reg = RW(reg, AR_RSSI_THR_BM_THR, 10);
2069498e8a28Sdamien AR_WRITE(sc, AR_RSSI_THR, reg);
2070498e8a28Sdamien
2071498e8a28Sdamien AR_WRITE(sc, AR_NEXT_DTIM,
2072498e8a28Sdamien (next_dtim - AR_SLEEP_SLOP) * IEEE80211_DUR_TU);
2073498e8a28Sdamien AR_WRITE(sc, AR_NEXT_TIM,
2074498e8a28Sdamien (next_tbtt - AR_SLEEP_SLOP) * IEEE80211_DUR_TU);
2075498e8a28Sdamien
2076498e8a28Sdamien /* CAB timeout is in 1/8 TU. */
2077498e8a28Sdamien AR_WRITE(sc, AR_SLEEP1,
2078498e8a28Sdamien SM(AR_SLEEP1_CAB_TIMEOUT, AR_CAB_TIMEOUT_VAL * 8) |
2079498e8a28Sdamien AR_SLEEP1_ASSUME_DTIM);
2080498e8a28Sdamien AR_WRITE(sc, AR_SLEEP2,
2081498e8a28Sdamien SM(AR_SLEEP2_BEACON_TIMEOUT, AR_MIN_BEACON_TIMEOUT_VAL));
2082498e8a28Sdamien
2083498e8a28Sdamien AR_WRITE(sc, AR_TIM_PERIOD, intval * IEEE80211_DUR_TU);
20841116b6b9Sdamien AR_WRITE(sc, AR_DTIM_PERIOD, dtim_period * intval * IEEE80211_DUR_TU);
2085498e8a28Sdamien
2086498e8a28Sdamien AR_SETBITS(sc, AR_TIMER_MODE,
2087498e8a28Sdamien AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN | AR_DTIM_TIMER_EN);
2088498e8a28Sdamien
2089498e8a28Sdamien /* Set TSF out-of-range threshold (fixed at 16k us). */
2090498e8a28Sdamien AR_WRITE(sc, AR_TSFOOR_THRESHOLD, 0x4240);
2091c0a11cf8Sdamien
2092c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
2093498e8a28Sdamien }
2094498e8a28Sdamien
2095eff5798eSdamien #ifndef IEEE80211_STA_ONLY
2096eff5798eSdamien void
athn_set_hostap_timers(struct athn_softc * sc)2097eff5798eSdamien athn_set_hostap_timers(struct athn_softc *sc)
2098eff5798eSdamien {
2099eff5798eSdamien struct ieee80211com *ic = &sc->sc_ic;
2100eff5798eSdamien uint32_t intval, next_tbtt;
2101eff5798eSdamien
2102eff5798eSdamien /* Beacon interval in TU. */
2103eff5798eSdamien intval = ic->ic_bss->ni_intval;
2104eff5798eSdamien next_tbtt = intval;
2105eff5798eSdamien
2106eff5798eSdamien AR_WRITE(sc, AR_NEXT_TBTT_TIMER, next_tbtt * IEEE80211_DUR_TU);
2107eff5798eSdamien AR_WRITE(sc, AR_NEXT_DMA_BEACON_ALERT,
2108eff5798eSdamien (next_tbtt - AR_BEACON_DMA_DELAY) * IEEE80211_DUR_TU);
2109eff5798eSdamien AR_WRITE(sc, AR_NEXT_CFP,
2110eff5798eSdamien (next_tbtt - AR_SWBA_DELAY) * IEEE80211_DUR_TU);
2111eff5798eSdamien
2112eff5798eSdamien AR_WRITE(sc, AR_BEACON_PERIOD, intval * IEEE80211_DUR_TU);
2113eff5798eSdamien AR_WRITE(sc, AR_DMA_BEACON_PERIOD, intval * IEEE80211_DUR_TU);
2114eff5798eSdamien AR_WRITE(sc, AR_SWBA_PERIOD, intval * IEEE80211_DUR_TU);
2115eff5798eSdamien AR_WRITE(sc, AR_NDP_PERIOD, intval * IEEE80211_DUR_TU);
2116eff5798eSdamien
2117eff5798eSdamien AR_WRITE(sc, AR_TIMER_MODE,
2118eff5798eSdamien AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN);
2119c0a11cf8Sdamien
2120c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
2121eff5798eSdamien }
2122eff5798eSdamien #endif
2123eff5798eSdamien
2124498e8a28Sdamien void
athn_set_opmode(struct athn_softc * sc)2125498e8a28Sdamien athn_set_opmode(struct athn_softc *sc)
2126498e8a28Sdamien {
2127498e8a28Sdamien uint32_t reg;
2128498e8a28Sdamien
2129498e8a28Sdamien switch (sc->sc_ic.ic_opmode) {
2130498e8a28Sdamien #ifndef IEEE80211_STA_ONLY
2131498e8a28Sdamien case IEEE80211_M_HOSTAP:
2132498e8a28Sdamien reg = AR_READ(sc, AR_STA_ID1);
2133498e8a28Sdamien reg &= ~AR_STA_ID1_ADHOC;
2134498e8a28Sdamien reg |= AR_STA_ID1_STA_AP | AR_STA_ID1_KSRCH_MODE;
2135498e8a28Sdamien AR_WRITE(sc, AR_STA_ID1, reg);
2136498e8a28Sdamien
2137498e8a28Sdamien AR_CLRBITS(sc, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
2138498e8a28Sdamien break;
2139498e8a28Sdamien case IEEE80211_M_IBSS:
2140498e8a28Sdamien case IEEE80211_M_AHDEMO:
2141498e8a28Sdamien reg = AR_READ(sc, AR_STA_ID1);
2142498e8a28Sdamien reg &= ~AR_STA_ID1_STA_AP;
2143498e8a28Sdamien reg |= AR_STA_ID1_ADHOC | AR_STA_ID1_KSRCH_MODE;
2144498e8a28Sdamien AR_WRITE(sc, AR_STA_ID1, reg);
2145498e8a28Sdamien
2146498e8a28Sdamien AR_SETBITS(sc, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
2147498e8a28Sdamien break;
2148498e8a28Sdamien #endif
2149498e8a28Sdamien default:
2150498e8a28Sdamien reg = AR_READ(sc, AR_STA_ID1);
2151498e8a28Sdamien reg &= ~(AR_STA_ID1_ADHOC | AR_STA_ID1_STA_AP);
2152498e8a28Sdamien reg |= AR_STA_ID1_KSRCH_MODE;
2153498e8a28Sdamien AR_WRITE(sc, AR_STA_ID1, reg);
2154498e8a28Sdamien break;
2155498e8a28Sdamien }
2156c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
2157498e8a28Sdamien }
2158498e8a28Sdamien
2159498e8a28Sdamien void
athn_set_bss(struct athn_softc * sc,struct ieee80211_node * ni)2160498e8a28Sdamien athn_set_bss(struct athn_softc *sc, struct ieee80211_node *ni)
2161498e8a28Sdamien {
2162498e8a28Sdamien const uint8_t *bssid = ni->ni_bssid;
2163498e8a28Sdamien
21646c0255d5Sdamien AR_WRITE(sc, AR_BSS_ID0, LE_READ_4(&bssid[0]));
21656c0255d5Sdamien AR_WRITE(sc, AR_BSS_ID1, LE_READ_2(&bssid[4]) |
2166498e8a28Sdamien SM(AR_BSS_ID1_AID, IEEE80211_AID(ni->ni_associd)));
2167c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
2168498e8a28Sdamien }
2169498e8a28Sdamien
2170498e8a28Sdamien void
athn_enable_interrupts(struct athn_softc * sc)2171498e8a28Sdamien athn_enable_interrupts(struct athn_softc *sc)
2172498e8a28Sdamien {
217346ad6ef1Sdamien uint32_t mask2;
2174498e8a28Sdamien
2175498e8a28Sdamien athn_disable_interrupts(sc); /* XXX */
2176498e8a28Sdamien
217746ad6ef1Sdamien AR_WRITE(sc, AR_IMR, sc->imask);
2178498e8a28Sdamien
2179498e8a28Sdamien mask2 = AR_READ(sc, AR_IMR_S2);
2180498e8a28Sdamien mask2 &= ~(AR_IMR_S2_TIM | AR_IMR_S2_DTIM | AR_IMR_S2_DTIMSYNC |
21817f0116d0Sdamien AR_IMR_S2_CABEND | AR_IMR_S2_CABTO | AR_IMR_S2_TSFOOR);
2182498e8a28Sdamien mask2 |= AR_IMR_S2_GTT | AR_IMR_S2_CST;
2183498e8a28Sdamien AR_WRITE(sc, AR_IMR_S2, mask2);
2184498e8a28Sdamien
2185498e8a28Sdamien AR_CLRBITS(sc, AR_IMR_S5, AR_IMR_S5_TIM_TIMER);
2186498e8a28Sdamien
2187498e8a28Sdamien AR_WRITE(sc, AR_IER, AR_IER_ENABLE);
2188498e8a28Sdamien
2189498e8a28Sdamien AR_WRITE(sc, AR_INTR_ASYNC_ENABLE, AR_INTR_MAC_IRQ);
2190498e8a28Sdamien AR_WRITE(sc, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ);
2191498e8a28Sdamien
21927f0116d0Sdamien AR_WRITE(sc, AR_INTR_SYNC_ENABLE, sc->isync);
21937f0116d0Sdamien AR_WRITE(sc, AR_INTR_SYNC_MASK, sc->isync);
2194c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
2195498e8a28Sdamien }
2196498e8a28Sdamien
2197498e8a28Sdamien void
athn_disable_interrupts(struct athn_softc * sc)2198498e8a28Sdamien athn_disable_interrupts(struct athn_softc *sc)
2199498e8a28Sdamien {
2200498e8a28Sdamien AR_WRITE(sc, AR_IER, 0);
2201498e8a28Sdamien (void)AR_READ(sc, AR_IER);
2202498e8a28Sdamien
2203498e8a28Sdamien AR_WRITE(sc, AR_INTR_ASYNC_ENABLE, 0);
2204498e8a28Sdamien (void)AR_READ(sc, AR_INTR_ASYNC_ENABLE);
2205498e8a28Sdamien
2206498e8a28Sdamien AR_WRITE(sc, AR_INTR_SYNC_ENABLE, 0);
2207498e8a28Sdamien (void)AR_READ(sc, AR_INTR_SYNC_ENABLE);
2208498e8a28Sdamien
2209498e8a28Sdamien AR_WRITE(sc, AR_IMR, 0);
2210498e8a28Sdamien
22118afda177Sdamien AR_CLRBITS(sc, AR_IMR_S2, AR_IMR_S2_TIM | AR_IMR_S2_DTIM |
2212498e8a28Sdamien AR_IMR_S2_DTIMSYNC | AR_IMR_S2_CABEND | AR_IMR_S2_CABTO |
2213498e8a28Sdamien AR_IMR_S2_TSFOOR | AR_IMR_S2_GTT | AR_IMR_S2_CST);
2214498e8a28Sdamien
2215498e8a28Sdamien AR_CLRBITS(sc, AR_IMR_S5, AR_IMR_S5_TIM_TIMER);
2216c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
2217498e8a28Sdamien }
2218498e8a28Sdamien
2219498e8a28Sdamien void
athn_init_qos(struct athn_softc * sc)2220498e8a28Sdamien athn_init_qos(struct athn_softc *sc)
2221498e8a28Sdamien {
2222498e8a28Sdamien /* Initialize QoS settings. */
2223498e8a28Sdamien AR_WRITE(sc, AR_MIC_QOS_CONTROL, 0x100aa);
2224498e8a28Sdamien AR_WRITE(sc, AR_MIC_QOS_SELECT, 0x3210);
2225498e8a28Sdamien AR_WRITE(sc, AR_QOS_NO_ACK,
2226498e8a28Sdamien SM(AR_QOS_NO_ACK_TWO_BIT, 2) |
2227498e8a28Sdamien SM(AR_QOS_NO_ACK_BIT_OFF, 5) |
2228498e8a28Sdamien SM(AR_QOS_NO_ACK_BYTE_OFF, 0));
2229498e8a28Sdamien AR_WRITE(sc, AR_TXOP_X, AR_TXOP_X_VAL);
2230498e8a28Sdamien /* Initialize TXOP for all TIDs. */
2231498e8a28Sdamien AR_WRITE(sc, AR_TXOP_0_3, 0xffffffff);
2232498e8a28Sdamien AR_WRITE(sc, AR_TXOP_4_7, 0xffffffff);
2233498e8a28Sdamien AR_WRITE(sc, AR_TXOP_8_11, 0xffffffff);
2234498e8a28Sdamien AR_WRITE(sc, AR_TXOP_12_15, 0xffffffff);
2235c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
2236498e8a28Sdamien }
2237498e8a28Sdamien
2238498e8a28Sdamien int
athn_hw_reset(struct athn_softc * sc,struct ieee80211_channel * c,struct ieee80211_channel * extc,int init)2239498e8a28Sdamien athn_hw_reset(struct athn_softc *sc, struct ieee80211_channel *c,
224013236e8dSdamien struct ieee80211_channel *extc, int init)
2241498e8a28Sdamien {
2242498e8a28Sdamien struct ieee80211com *ic = &sc->sc_ic;
2243498e8a28Sdamien struct athn_ops *ops = &sc->ops;
2244498e8a28Sdamien uint32_t reg, def_ant, sta_id1, cfg_led, tsflo, tsfhi;
2245498e8a28Sdamien int i, error;
2246498e8a28Sdamien
2247498e8a28Sdamien /* XXX not if already awake */
2248498e8a28Sdamien if ((error = athn_set_power_awake(sc)) != 0) {
2249498e8a28Sdamien printf("%s: could not wakeup chip\n", sc->sc_dev.dv_xname);
2250498e8a28Sdamien return (error);
2251498e8a28Sdamien }
2252498e8a28Sdamien
2253498e8a28Sdamien /* Preserve the antenna on a channel switch. */
2254498e8a28Sdamien if ((def_ant = AR_READ(sc, AR_DEF_ANTENNA)) == 0)
2255498e8a28Sdamien def_ant = 1;
2256498e8a28Sdamien /* Preserve other registers. */
2257498e8a28Sdamien sta_id1 = AR_READ(sc, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B;
2258498e8a28Sdamien cfg_led = AR_READ(sc, AR_CFG_LED) & (AR_CFG_LED_ASSOC_CTL_M |
2259498e8a28Sdamien AR_CFG_LED_MODE_SEL_M | AR_CFG_LED_BLINK_THRESH_SEL_M |
2260498e8a28Sdamien AR_CFG_LED_BLINK_SLOW);
2261498e8a28Sdamien
2262498e8a28Sdamien /* Mark PHY as inactive. */
2263bd6ea91dSdamien ops->disable_phy(sc);
2264498e8a28Sdamien
226513236e8dSdamien if (init && AR_SREV_9271(sc)) {
226613236e8dSdamien AR_WRITE(sc, AR9271_RESET_POWER_DOWN_CONTROL,
226713236e8dSdamien AR9271_RADIO_RF_RST);
226813236e8dSdamien DELAY(50);
226913236e8dSdamien }
2270498e8a28Sdamien if (AR_SREV_9280(sc) && (sc->flags & ATHN_FLAG_OLPC)) {
2271498e8a28Sdamien /* Save TSF before it gets cleared. */
2272498e8a28Sdamien tsfhi = AR_READ(sc, AR_TSF_U32);
2273498e8a28Sdamien tsflo = AR_READ(sc, AR_TSF_L32);
2274498e8a28Sdamien
2275498e8a28Sdamien /* NB: RTC reset clears TSF. */
2276498e8a28Sdamien error = athn_reset_power_on(sc);
2277498e8a28Sdamien } else
2278498e8a28Sdamien error = athn_reset(sc, 0);
2279498e8a28Sdamien if (error != 0) {
2280498e8a28Sdamien printf("%s: could not reset chip (error=%d)\n",
2281e6c7f3bcSjsg sc->sc_dev.dv_xname, error);
2282498e8a28Sdamien return (error);
2283498e8a28Sdamien }
2284498e8a28Sdamien
2285498e8a28Sdamien /* XXX not if already awake */
2286498e8a28Sdamien if ((error = athn_set_power_awake(sc)) != 0) {
2287498e8a28Sdamien printf("%s: could not wakeup chip\n", sc->sc_dev.dv_xname);
2288498e8a28Sdamien return (error);
2289498e8a28Sdamien }
2290498e8a28Sdamien
2291498e8a28Sdamien athn_init_pll(sc, c);
2292bd6ea91dSdamien ops->set_rf_mode(sc, c);
2293498e8a28Sdamien
2294498e8a28Sdamien if (sc->flags & ATHN_FLAG_RFSILENT) {
2295498e8a28Sdamien /* Check that the radio is not disabled by hardware switch. */
2296bd6ea91dSdamien reg = ops->gpio_read(sc, sc->rfsilent_pin);
2297498e8a28Sdamien if (sc->flags & ATHN_FLAG_RFSILENT_REVERSED)
2298498e8a28Sdamien reg = !reg;
2299498e8a28Sdamien if (!reg) {
2300498e8a28Sdamien printf("%s: radio is disabled by hardware switch\n",
2301498e8a28Sdamien sc->sc_dev.dv_xname);
2302498e8a28Sdamien return (EPERM);
2303498e8a28Sdamien }
2304498e8a28Sdamien }
230513236e8dSdamien if (init && AR_SREV_9271(sc)) {
230613236e8dSdamien AR_WRITE(sc, AR9271_RESET_POWER_DOWN_CONTROL,
230713236e8dSdamien AR9271_GATE_MAC_CTL);
230813236e8dSdamien DELAY(50);
230913236e8dSdamien }
2310498e8a28Sdamien if (AR_SREV_9280(sc) && (sc->flags & ATHN_FLAG_OLPC)) {
2311498e8a28Sdamien /* Restore TSF if it got cleared. */
2312498e8a28Sdamien AR_WRITE(sc, AR_TSF_L32, tsflo);
2313498e8a28Sdamien AR_WRITE(sc, AR_TSF_U32, tsfhi);
2314498e8a28Sdamien }
2315498e8a28Sdamien
2316498e8a28Sdamien if (AR_SREV_9280_10_OR_LATER(sc))
2317bd6ea91dSdamien AR_SETBITS(sc, sc->gpio_input_en_off, AR_GPIO_JTAG_DISABLE);
2318498e8a28Sdamien
23191c1c6997Sdamien if (AR_SREV_9287_13_OR_LATER(sc) && !AR_SREV_9380_10_OR_LATER(sc))
23201c1c6997Sdamien ar9287_1_3_enable_async_fifo(sc);
2321498e8a28Sdamien
2322498e8a28Sdamien /* Write init values to hardware. */
2323bd6ea91dSdamien ops->hw_init(sc, c, extc);
2324498e8a28Sdamien
2325498e8a28Sdamien /*
2326498e8a28Sdamien * Only >=AR9280 2.0 parts are capable of encrypting unicast
2327498e8a28Sdamien * management frames using CCMP.
2328498e8a28Sdamien */
2329498e8a28Sdamien if (AR_SREV_9280_20_OR_LATER(sc)) {
2330498e8a28Sdamien reg = AR_READ(sc, AR_AES_MUTE_MASK1);
2331498e8a28Sdamien /* Do not mask the subtype field in management frames. */
2332498e8a28Sdamien reg = RW(reg, AR_AES_MUTE_MASK1_FC0_MGMT, 0xff);
2333498e8a28Sdamien reg = RW(reg, AR_AES_MUTE_MASK1_FC1_MGMT,
2334498e8a28Sdamien ~(IEEE80211_FC1_RETRY | IEEE80211_FC1_PWR_MGT |
2335498e8a28Sdamien IEEE80211_FC1_MORE_DATA));
2336498e8a28Sdamien AR_WRITE(sc, AR_AES_MUTE_MASK1, reg);
2337498e8a28Sdamien } else if (AR_SREV_9160_10_OR_LATER(sc)) {
2338498e8a28Sdamien /* Disable hardware crypto for management frames. */
2339498e8a28Sdamien AR_CLRBITS(sc, AR_PCU_MISC_MODE2,
2340498e8a28Sdamien AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE);
2341498e8a28Sdamien AR_SETBITS(sc, AR_PCU_MISC_MODE2,
2342498e8a28Sdamien AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT);
2343498e8a28Sdamien }
2344498e8a28Sdamien
2345498e8a28Sdamien if (ic->ic_curmode != IEEE80211_MODE_11B)
2346bd6ea91dSdamien ops->set_delta_slope(sc, c, extc);
2347498e8a28Sdamien
2348498e8a28Sdamien ops->spur_mitigate(sc, c, extc);
2349498e8a28Sdamien ops->init_from_rom(sc, c, extc);
2350498e8a28Sdamien
2351498e8a28Sdamien /* XXX */
23526c0255d5Sdamien AR_WRITE(sc, AR_STA_ID0, LE_READ_4(&ic->ic_myaddr[0]));
23536c0255d5Sdamien AR_WRITE(sc, AR_STA_ID1, LE_READ_2(&ic->ic_myaddr[4]) |
2354498e8a28Sdamien sta_id1 | AR_STA_ID1_RTS_USE_DEF | AR_STA_ID1_CRPT_MIC_ENABLE);
2355498e8a28Sdamien
2356498e8a28Sdamien athn_set_opmode(sc);
2357498e8a28Sdamien
2358498e8a28Sdamien AR_WRITE(sc, AR_BSSMSKL, 0xffffffff);
2359498e8a28Sdamien AR_WRITE(sc, AR_BSSMSKU, 0xffff);
2360498e8a28Sdamien
2361498e8a28Sdamien /* Restore previous antenna. */
2362498e8a28Sdamien AR_WRITE(sc, AR_DEF_ANTENNA, def_ant);
2363498e8a28Sdamien
2364498e8a28Sdamien AR_WRITE(sc, AR_BSS_ID0, 0);
2365498e8a28Sdamien AR_WRITE(sc, AR_BSS_ID1, 0);
2366498e8a28Sdamien
2367498e8a28Sdamien AR_WRITE(sc, AR_ISR, 0xffffffff);
2368498e8a28Sdamien
2369498e8a28Sdamien AR_WRITE(sc, AR_RSSI_THR, SM(AR_RSSI_THR_BM_THR, 7));
2370498e8a28Sdamien
23712c4d03c8Sdamien if ((error = ops->set_synth(sc, c, extc)) != 0) {
2372498e8a28Sdamien printf("%s: could not set channel\n", sc->sc_dev.dv_xname);
2373498e8a28Sdamien return (error);
2374498e8a28Sdamien }
23752c4d03c8Sdamien sc->curchan = c;
23762c4d03c8Sdamien sc->curchanext = extc;
2377498e8a28Sdamien
2378498e8a28Sdamien for (i = 0; i < AR_NUM_DCU; i++)
2379498e8a28Sdamien AR_WRITE(sc, AR_DQCUMASK(i), 1 << i);
2380498e8a28Sdamien
2381498e8a28Sdamien athn_init_tx_queues(sc);
2382498e8a28Sdamien
2383498e8a28Sdamien /* Initialize interrupt mask. */
238446ad6ef1Sdamien sc->imask =
238546ad6ef1Sdamien AR_IMR_TXDESC | AR_IMR_TXEOL |
238646ad6ef1Sdamien AR_IMR_RXERR | AR_IMR_RXEOL | AR_IMR_RXORN |
238746ad6ef1Sdamien AR_IMR_RXMINTR | AR_IMR_RXINTM |
238846ad6ef1Sdamien AR_IMR_GENTMR | AR_IMR_BCNMISC;
2389bd6ea91dSdamien if (AR_SREV_9380_10_OR_LATER(sc))
239046ad6ef1Sdamien sc->imask |= AR_IMR_RXERR | AR_IMR_HP_RXOK;
2391498e8a28Sdamien #ifndef IEEE80211_STA_ONLY
239246ad6ef1Sdamien if (0 && ic->ic_opmode == IEEE80211_M_HOSTAP)
23937f0116d0Sdamien sc->imask |= AR_IMR_MIB;
2394498e8a28Sdamien #endif
23957f0116d0Sdamien AR_WRITE(sc, AR_IMR, sc->imask);
23968afda177Sdamien AR_SETBITS(sc, AR_IMR_S2, AR_IMR_S2_GTT);
2397498e8a28Sdamien AR_WRITE(sc, AR_INTR_SYNC_CAUSE, 0xffffffff);
23987f0116d0Sdamien sc->isync = AR_INTR_SYNC_DEFAULT;
23997f0116d0Sdamien if (sc->flags & ATHN_FLAG_RFSILENT)
24007f0116d0Sdamien sc->isync |= AR_INTR_SYNC_GPIO_PIN(sc->rfsilent_pin);
24017f0116d0Sdamien AR_WRITE(sc, AR_INTR_SYNC_ENABLE, sc->isync);
2402498e8a28Sdamien AR_WRITE(sc, AR_INTR_SYNC_MASK, 0);
2403bd6ea91dSdamien if (AR_SREV_9380_10_OR_LATER(sc)) {
2404bd6ea91dSdamien AR_WRITE(sc, AR_INTR_PRIO_ASYNC_ENABLE, 0);
2405bd6ea91dSdamien AR_WRITE(sc, AR_INTR_PRIO_ASYNC_MASK, 0);
2406bd6ea91dSdamien AR_WRITE(sc, AR_INTR_PRIO_SYNC_ENABLE, 0);
2407bd6ea91dSdamien AR_WRITE(sc, AR_INTR_PRIO_SYNC_MASK, 0);
2408bd6ea91dSdamien }
2409498e8a28Sdamien
2410498e8a28Sdamien athn_init_qos(sc);
2411498e8a28Sdamien
2412498e8a28Sdamien AR_SETBITS(sc, AR_PCU_MISC, AR_PCU_MIC_NEW_LOC_ENA);
2413498e8a28Sdamien
24147c3c6bd5Sstsp athn_setsifs(sc);
24157c3c6bd5Sstsp athn_updateslot(ic);
24167c3c6bd5Sstsp athn_setclockrate(sc);
24171c1c6997Sdamien if (AR_SREV_9287_13_OR_LATER(sc) && !AR_SREV_9380_10_OR_LATER(sc))
24181c1c6997Sdamien ar9287_1_3_setup_async_fifo(sc);
2419498e8a28Sdamien
2420498e8a28Sdamien /* Disable sequence number generation in hardware. */
2421498e8a28Sdamien AR_SETBITS(sc, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM);
2422498e8a28Sdamien
2423498e8a28Sdamien athn_init_dma(sc);
2424498e8a28Sdamien
242597bf8fdcSdamien /* Program observation bus to see MAC interrupts. */
2426bd6ea91dSdamien AR_WRITE(sc, sc->obs_off, 8);
2427498e8a28Sdamien
242897bf8fdcSdamien /* Setup Rx interrupt mitigation. */
2429498e8a28Sdamien AR_WRITE(sc, AR_RIMT, SM(AR_RIMT_FIRST, 2000) | SM(AR_RIMT_LAST, 500));
2430498e8a28Sdamien
24316ab8d4f7Sstsp /* Setup Tx interrupt mitigation. */
24326ab8d4f7Sstsp AR_WRITE(sc, AR_TIMT, SM(AR_TIMT_FIRST, 2000) | SM(AR_TIMT_LAST, 500));
24336ab8d4f7Sstsp
24346ab8d4f7Sstsp /* Set maximum interrupt rate threshold (in micro seconds). */
24356ab8d4f7Sstsp AR_WRITE(sc, AR_MIRT, SM(AR_MIRT_RATE_THRES, 2000));
24366ab8d4f7Sstsp
2437bd6ea91dSdamien ops->init_baseband(sc);
2438498e8a28Sdamien
2439498e8a28Sdamien if ((error = athn_init_calib(sc, c, extc)) != 0) {
2440498e8a28Sdamien printf("%s: could not initialize calibration\n",
2441498e8a28Sdamien sc->sc_dev.dv_xname);
2442498e8a28Sdamien return (error);
2443498e8a28Sdamien }
2444498e8a28Sdamien
2445bd6ea91dSdamien ops->set_rxchains(sc);
2446498e8a28Sdamien
2447498e8a28Sdamien AR_WRITE(sc, AR_CFG_LED, cfg_led | AR_CFG_SCLK_32KHZ);
2448498e8a28Sdamien
244913236e8dSdamien if (sc->flags & ATHN_FLAG_USB) {
245013236e8dSdamien if (AR_SREV_9271(sc))
245113236e8dSdamien AR_WRITE(sc, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB);
245213236e8dSdamien else
2453498e8a28Sdamien AR_WRITE(sc, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
245413236e8dSdamien }
245513236e8dSdamien #if BYTE_ORDER == BIG_ENDIAN
245613236e8dSdamien else {
245713236e8dSdamien /* Default is LE, turn on swapping for BE. */
245813236e8dSdamien AR_WRITE(sc, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
245913236e8dSdamien }
2460498e8a28Sdamien #endif
2461c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
2462c0a11cf8Sdamien
2463498e8a28Sdamien return (0);
2464498e8a28Sdamien }
2465498e8a28Sdamien
2466498e8a28Sdamien struct ieee80211_node *
athn_node_alloc(struct ieee80211com * ic)2467498e8a28Sdamien athn_node_alloc(struct ieee80211com *ic)
2468498e8a28Sdamien {
24697363c99eSstsp struct athn_node *an;
24707363c99eSstsp
24717363c99eSstsp an = malloc(sizeof(struct athn_node), M_DEVBUF, M_NOWAIT | M_ZERO);
2472f8fd8e72Sstsp if (an && (ic->ic_flags & IEEE80211_F_HTON))
2473*d2dd70acSstsp ieee80211_ra_node_init(&an->rn);
24747363c99eSstsp return (struct ieee80211_node *)an;
2475498e8a28Sdamien }
2476498e8a28Sdamien
2477498e8a28Sdamien void
athn_newassoc(struct ieee80211com * ic,struct ieee80211_node * ni,int isnew)2478498e8a28Sdamien athn_newassoc(struct ieee80211com *ic, struct ieee80211_node *ni, int isnew)
2479498e8a28Sdamien {
2480498e8a28Sdamien struct athn_softc *sc = ic->ic_softc;
2481498e8a28Sdamien struct athn_node *an = (void *)ni;
2482498e8a28Sdamien struct ieee80211_rateset *rs = &ni->ni_rates;
2483498e8a28Sdamien uint8_t rate;
2484498e8a28Sdamien int ridx, i, j;
2485498e8a28Sdamien
24867363c99eSstsp if ((ni->ni_flags & IEEE80211_NODE_HT) == 0)
2487498e8a28Sdamien ieee80211_amrr_node_init(&sc->amrr, &an->amn);
24887363c99eSstsp else if (ic->ic_opmode == IEEE80211_M_STA)
2489*d2dd70acSstsp ieee80211_ra_node_init(&an->rn);
24907363c99eSstsp
2491498e8a28Sdamien /* Start at lowest available bit-rate, AMRR will raise. */
2492498e8a28Sdamien ni->ni_txrate = 0;
2493498e8a28Sdamien
2494498e8a28Sdamien for (i = 0; i < rs->rs_nrates; i++) {
2495498e8a28Sdamien rate = rs->rs_rates[i] & IEEE80211_RATE_VAL;
2496498e8a28Sdamien
2497498e8a28Sdamien /* Map 802.11 rate to HW rate index. */
2498498e8a28Sdamien for (ridx = 0; ridx <= ATHN_RIDX_MAX; ridx++)
2499498e8a28Sdamien if (athn_rates[ridx].rate == rate)
2500498e8a28Sdamien break;
2501498e8a28Sdamien an->ridx[i] = ridx;
25028f9a2877Sdamien DPRINTFN(2, ("rate %d index %d\n", rate, ridx));
2503498e8a28Sdamien
2504498e8a28Sdamien /* Compute fallback rate for retries. */
2505498e8a28Sdamien an->fallback[i] = i;
2506498e8a28Sdamien for (j = i - 1; j >= 0; j--) {
2507498e8a28Sdamien if (athn_rates[an->ridx[j]].phy ==
2508498e8a28Sdamien athn_rates[an->ridx[i]].phy) {
2509498e8a28Sdamien an->fallback[i] = j;
2510498e8a28Sdamien break;
2511498e8a28Sdamien }
2512498e8a28Sdamien }
25138f9a2877Sdamien DPRINTFN(2, ("%d fallbacks to %d\n", i, an->fallback[i]));
2514498e8a28Sdamien }
25157363c99eSstsp
25167363c99eSstsp /* In 11n mode, start at lowest available bit-rate, MiRA will raise. */
25177363c99eSstsp ni->ni_txmcs = 0;
25187363c99eSstsp
25197363c99eSstsp for (i = 0; i <= ATHN_MCS_MAX; i++) {
25207363c99eSstsp /* Map MCS index to HW rate index. */
25217363c99eSstsp ridx = ATHN_NUM_LEGACY_RATES + i;
25227363c99eSstsp an->ridx[ridx] = ATHN_RIDX_MCS0 + i;
25237363c99eSstsp
25247363c99eSstsp DPRINTFN(2, ("mcs %d index %d ", i, ridx));
25257363c99eSstsp /* Compute fallback rate for retries. */
25267363c99eSstsp if (i == 0 || i == 8) {
25277363c99eSstsp /* MCS 0 and 8 fall back to the lowest legacy rate. */
25287363c99eSstsp if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan))
25297363c99eSstsp an->fallback[ridx] = ATHN_RIDX_OFDM6;
25307363c99eSstsp else
25317363c99eSstsp an->fallback[ridx] = ATHN_RIDX_CCK1;
25327363c99eSstsp } else {
25337363c99eSstsp /* Other MCS fall back to next supported lower MCS. */
25347363c99eSstsp an->fallback[ridx] = ATHN_NUM_LEGACY_RATES + i;
25357363c99eSstsp for (j = i - 1; j >= 0; j--) {
25367363c99eSstsp if (!isset(ni->ni_rxmcs, j))
25377363c99eSstsp continue;
25387363c99eSstsp an->fallback[ridx] = ATHN_NUM_LEGACY_RATES + j;
25397363c99eSstsp break;
2540498e8a28Sdamien }
25417363c99eSstsp }
25427363c99eSstsp DPRINTFN(2, (" fallback to %d\n", an->fallback[ridx]));
25437363c99eSstsp }
25447363c99eSstsp }
25457363c99eSstsp
2546498e8a28Sdamien int
athn_media_change(struct ifnet * ifp)2547498e8a28Sdamien athn_media_change(struct ifnet *ifp)
2548498e8a28Sdamien {
2549498e8a28Sdamien struct athn_softc *sc = ifp->if_softc;
2550498e8a28Sdamien struct ieee80211com *ic = &sc->sc_ic;
2551498e8a28Sdamien uint8_t rate, ridx;
2552498e8a28Sdamien int error;
2553498e8a28Sdamien
2554498e8a28Sdamien error = ieee80211_media_change(ifp);
2555498e8a28Sdamien if (error != ENETRESET)
2556498e8a28Sdamien return (error);
2557498e8a28Sdamien
2558498e8a28Sdamien if (ic->ic_fixed_rate != -1) {
2559498e8a28Sdamien rate = ic->ic_sup_rates[ic->ic_curmode].
2560498e8a28Sdamien rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
2561498e8a28Sdamien /* Map 802.11 rate to HW rate index. */
2562498e8a28Sdamien for (ridx = 0; ridx <= ATHN_RIDX_MAX; ridx++)
2563498e8a28Sdamien if (athn_rates[ridx].rate == rate)
2564498e8a28Sdamien break;
2565498e8a28Sdamien sc->fixed_ridx = ridx;
2566498e8a28Sdamien }
2567498e8a28Sdamien if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
2568498e8a28Sdamien (IFF_UP | IFF_RUNNING)) {
2569498e8a28Sdamien athn_stop(ifp, 0);
2570498e8a28Sdamien error = athn_init(ifp);
2571498e8a28Sdamien }
2572498e8a28Sdamien return (error);
2573498e8a28Sdamien }
2574498e8a28Sdamien
2575498e8a28Sdamien void
athn_next_scan(void * arg)2576498e8a28Sdamien athn_next_scan(void *arg)
2577498e8a28Sdamien {
2578498e8a28Sdamien struct athn_softc *sc = arg;
2579498e8a28Sdamien struct ieee80211com *ic = &sc->sc_ic;
2580498e8a28Sdamien int s;
2581498e8a28Sdamien
2582498e8a28Sdamien s = splnet();
2583498e8a28Sdamien if (ic->ic_state == IEEE80211_S_SCAN)
2584498e8a28Sdamien ieee80211_next_scan(&ic->ic_if);
2585498e8a28Sdamien splx(s);
2586498e8a28Sdamien }
2587498e8a28Sdamien
2588498e8a28Sdamien int
athn_newstate(struct ieee80211com * ic,enum ieee80211_state nstate,int arg)2589498e8a28Sdamien athn_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
2590498e8a28Sdamien {
2591498e8a28Sdamien struct ifnet *ifp = &ic->ic_if;
2592498e8a28Sdamien struct athn_softc *sc = ifp->if_softc;
2593b32386bfSdamien uint32_t reg;
2594498e8a28Sdamien int error;
2595498e8a28Sdamien
2596498e8a28Sdamien timeout_del(&sc->calib_to);
2597498e8a28Sdamien
2598498e8a28Sdamien switch (nstate) {
2599498e8a28Sdamien case IEEE80211_S_INIT:
26005632af28Sdamien athn_set_led(sc, 0);
2601498e8a28Sdamien break;
2602498e8a28Sdamien case IEEE80211_S_SCAN:
26030d6cd39fSdamien /* Make the LED blink while scanning. */
26045632af28Sdamien athn_set_led(sc, !sc->led_state);
2605498e8a28Sdamien error = athn_switch_chan(sc, ic->ic_bss->ni_chan, NULL);
2606498e8a28Sdamien if (error != 0)
2607498e8a28Sdamien return (error);
2608498e8a28Sdamien timeout_add_msec(&sc->scan_to, 200);
2609498e8a28Sdamien break;
2610498e8a28Sdamien case IEEE80211_S_AUTH:
26115632af28Sdamien athn_set_led(sc, 0);
2612498e8a28Sdamien error = athn_switch_chan(sc, ic->ic_bss->ni_chan, NULL);
2613498e8a28Sdamien if (error != 0)
2614498e8a28Sdamien return (error);
2615498e8a28Sdamien break;
2616498e8a28Sdamien case IEEE80211_S_ASSOC:
2617498e8a28Sdamien break;
2618498e8a28Sdamien case IEEE80211_S_RUN:
26195632af28Sdamien athn_set_led(sc, 1);
26205f8ede55Sstsp #ifndef IEEE80211_STA_ONLY
26215f8ede55Sstsp if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
26225f8ede55Sstsp error = athn_switch_chan(sc, ic->ic_bss->ni_chan, NULL);
26235f8ede55Sstsp if (error != 0)
26245f8ede55Sstsp return (error);
26255f8ede55Sstsp } else
26265f8ede55Sstsp #endif
26275f8ede55Sstsp if (ic->ic_opmode == IEEE80211_M_MONITOR) {
26285f8ede55Sstsp error = athn_switch_chan(sc, ic->ic_ibss_chan, NULL);
26295f8ede55Sstsp if (error != 0)
26305f8ede55Sstsp return (error);
2631498e8a28Sdamien break;
26325f8ede55Sstsp }
2633498e8a28Sdamien
2634498e8a28Sdamien /* Fake a join to initialize the Tx rate. */
2635498e8a28Sdamien athn_newassoc(ic, ic->ic_bss, 1);
2636498e8a28Sdamien
2637498e8a28Sdamien athn_set_bss(sc, ic->ic_bss);
2638498e8a28Sdamien athn_disable_interrupts(sc);
2639eff5798eSdamien #ifndef IEEE80211_STA_ONLY
2640eff5798eSdamien if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
2641eff5798eSdamien athn_set_hostap_timers(sc);
2642ead380efSjsing /* Enable software beacon alert interrupts. */
2643eff5798eSdamien sc->imask |= AR_IMR_SWBA;
2644eff5798eSdamien } else
2645eff5798eSdamien #endif
2646eff5798eSdamien {
2647eff5798eSdamien athn_set_sta_timers(sc);
264846ad6ef1Sdamien /* Enable beacon miss interrupts. */
264946ad6ef1Sdamien sc->imask |= AR_IMR_BMISS;
2650b32386bfSdamien
2651b32386bfSdamien /* Stop receiving beacons from other BSS. */
2652b32386bfSdamien reg = AR_READ(sc, AR_RX_FILTER);
2653b32386bfSdamien reg = (reg & ~AR_RX_FILTER_BEACON) |
2654b32386bfSdamien AR_RX_FILTER_MYBEACON;
2655b32386bfSdamien AR_WRITE(sc, AR_RX_FILTER, reg);
2656c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
2657eff5798eSdamien }
2658498e8a28Sdamien athn_enable_interrupts(sc);
265926bcd0d6Sdamien
266026bcd0d6Sdamien if (sc->sup_calib_mask != 0) {
266126bcd0d6Sdamien memset(&sc->calib, 0, sizeof(sc->calib));
266226bcd0d6Sdamien sc->cur_calib_mask = sc->sup_calib_mask;
2663cc6e2d0bSstsp sc->ops.do_calib(sc);
266426bcd0d6Sdamien }
2665498e8a28Sdamien /* XXX Start ANI. */
2666498e8a28Sdamien
26679d1f2812Sstsp athn_start_noisefloor_calib(sc, 1);
2668498e8a28Sdamien timeout_add_msec(&sc->calib_to, 500);
2669498e8a28Sdamien break;
2670498e8a28Sdamien }
2671498e8a28Sdamien
2672498e8a28Sdamien return (sc->sc_newstate(ic, nstate, arg));
2673498e8a28Sdamien }
2674498e8a28Sdamien
2675498e8a28Sdamien void
athn_updateedca(struct ieee80211com * ic)2676498e8a28Sdamien athn_updateedca(struct ieee80211com *ic)
2677498e8a28Sdamien {
2678498e8a28Sdamien #define ATHN_EXP2(x) ((1 << (x)) - 1) /* CWmin = 2^ECWmin - 1 */
2679498e8a28Sdamien struct athn_softc *sc = ic->ic_softc;
2680498e8a28Sdamien const struct ieee80211_edca_ac_params *ac;
2681498e8a28Sdamien int aci, qid;
2682498e8a28Sdamien
2683498e8a28Sdamien for (aci = 0; aci < EDCA_NUM_AC; aci++) {
2684498e8a28Sdamien ac = &ic->ic_edca_ac[aci];
2685498e8a28Sdamien qid = athn_ac2qid[aci];
2686498e8a28Sdamien
2687498e8a28Sdamien AR_WRITE(sc, AR_DLCL_IFS(qid),
2688498e8a28Sdamien SM(AR_D_LCL_IFS_CWMIN, ATHN_EXP2(ac->ac_ecwmin)) |
2689498e8a28Sdamien SM(AR_D_LCL_IFS_CWMAX, ATHN_EXP2(ac->ac_ecwmax)) |
2690498e8a28Sdamien SM(AR_D_LCL_IFS_AIFS, ac->ac_aifsn));
2691498e8a28Sdamien if (ac->ac_txoplimit != 0) {
2692498e8a28Sdamien AR_WRITE(sc, AR_DCHNTIME(qid),
2693498e8a28Sdamien SM(AR_D_CHNTIME_DUR,
2694498e8a28Sdamien IEEE80211_TXOP_TO_US(ac->ac_txoplimit)) |
2695498e8a28Sdamien AR_D_CHNTIME_EN);
2696498e8a28Sdamien } else
2697498e8a28Sdamien AR_WRITE(sc, AR_DCHNTIME(qid), 0);
2698498e8a28Sdamien }
2699c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
2700498e8a28Sdamien #undef ATHN_EXP2
2701498e8a28Sdamien }
2702498e8a28Sdamien
2703186e7a92Sdamien int
athn_clock_rate(struct athn_softc * sc)2704186e7a92Sdamien athn_clock_rate(struct athn_softc *sc)
2705186e7a92Sdamien {
2706186e7a92Sdamien struct ieee80211com *ic = &sc->sc_ic;
2707186e7a92Sdamien int clockrate; /* MHz. */
2708186e7a92Sdamien
27097c3c6bd5Sstsp /*
27107c3c6bd5Sstsp * AR9287 v1.3+ MAC runs at 117MHz (instead of 88/44MHz) when
27117c3c6bd5Sstsp * ASYNC FIFO is enabled.
27127c3c6bd5Sstsp */
27137c3c6bd5Sstsp if (AR_SREV_9287_13_OR_LATER(sc) && !AR_SREV_9380_10_OR_LATER(sc))
27147c3c6bd5Sstsp clockrate = 117;
27157c3c6bd5Sstsp else if (ic->ic_bss->ni_chan != IEEE80211_CHAN_ANYC &&
271696952bbeSstsp IEEE80211_IS_CHAN_5GHZ(ic->ic_bss->ni_chan)) {
2717186e7a92Sdamien if (sc->flags & ATHN_FLAG_FAST_PLL_CLOCK)
2718186e7a92Sdamien clockrate = AR_CLOCK_RATE_FAST_5GHZ_OFDM;
2719186e7a92Sdamien else
2720186e7a92Sdamien clockrate = AR_CLOCK_RATE_5GHZ_OFDM;
2721186e7a92Sdamien } else if (ic->ic_curmode == IEEE80211_MODE_11B) {
2722186e7a92Sdamien clockrate = AR_CLOCK_RATE_CCK;
2723186e7a92Sdamien } else
2724186e7a92Sdamien clockrate = AR_CLOCK_RATE_2GHZ_OFDM;
2725186e7a92Sdamien if (sc->curchanext != NULL)
2726186e7a92Sdamien clockrate *= 2;
27275e32cd22Sstsp
2728186e7a92Sdamien return (clockrate);
2729186e7a92Sdamien }
2730186e7a92Sdamien
27317c3c6bd5Sstsp int
athn_chan_sifs(struct ieee80211_channel * c)27327c3c6bd5Sstsp athn_chan_sifs(struct ieee80211_channel *c)
27337c3c6bd5Sstsp {
27347c3c6bd5Sstsp return IEEE80211_IS_CHAN_2GHZ(c) ? IEEE80211_DUR_DS_SIFS : 16;
27357c3c6bd5Sstsp }
27367c3c6bd5Sstsp
27377c3c6bd5Sstsp void
athn_setsifs(struct athn_softc * sc)27387c3c6bd5Sstsp athn_setsifs(struct athn_softc *sc)
27397c3c6bd5Sstsp {
27407c3c6bd5Sstsp int sifs = athn_chan_sifs(sc->sc_ic.ic_bss->ni_chan);
27417c3c6bd5Sstsp AR_WRITE(sc, AR_D_GBL_IFS_SIFS, (sifs - 2) * athn_clock_rate(sc));
27427c3c6bd5Sstsp AR_WRITE_BARRIER(sc);
27437c3c6bd5Sstsp }
27447c3c6bd5Sstsp
27457c3c6bd5Sstsp int
athn_acktimeout(struct ieee80211_channel * c,int slot)27467c3c6bd5Sstsp athn_acktimeout(struct ieee80211_channel *c, int slot)
27477c3c6bd5Sstsp {
27487c3c6bd5Sstsp int sifs = athn_chan_sifs(c);
27497c3c6bd5Sstsp int ackto = sifs + slot;
27507c3c6bd5Sstsp
27517c3c6bd5Sstsp /* Workaround for early ACK timeouts. */
27527c3c6bd5Sstsp if (IEEE80211_IS_CHAN_2GHZ(c))
27537c3c6bd5Sstsp ackto += 64 - sifs - slot;
27547c3c6bd5Sstsp
27557c3c6bd5Sstsp return ackto;
27567c3c6bd5Sstsp }
27577c3c6bd5Sstsp
27587c3c6bd5Sstsp void
athn_setacktimeout(struct athn_softc * sc,struct ieee80211_channel * c,int slot)27597c3c6bd5Sstsp athn_setacktimeout(struct athn_softc *sc, struct ieee80211_channel *c, int slot)
27607c3c6bd5Sstsp {
27617c3c6bd5Sstsp int ackto = athn_acktimeout(c, slot);
27627c3c6bd5Sstsp uint32_t reg = AR_READ(sc, AR_TIME_OUT);
27637c3c6bd5Sstsp reg = RW(reg, AR_TIME_OUT_ACK, ackto * athn_clock_rate(sc));
27647c3c6bd5Sstsp AR_WRITE(sc, AR_TIME_OUT, reg);
27657c3c6bd5Sstsp AR_WRITE_BARRIER(sc);
27667c3c6bd5Sstsp }
27677c3c6bd5Sstsp
27687c3c6bd5Sstsp void
athn_setctstimeout(struct athn_softc * sc,struct ieee80211_channel * c,int slot)27697c3c6bd5Sstsp athn_setctstimeout(struct athn_softc *sc, struct ieee80211_channel *c, int slot)
27707c3c6bd5Sstsp {
27717c3c6bd5Sstsp int ctsto = athn_acktimeout(c, slot);
27727c3c6bd5Sstsp int sifs = athn_chan_sifs(c);
27737c3c6bd5Sstsp uint32_t reg = AR_READ(sc, AR_TIME_OUT);
27747c3c6bd5Sstsp
27757c3c6bd5Sstsp /* Workaround for early CTS timeouts. */
27767c3c6bd5Sstsp if (IEEE80211_IS_CHAN_2GHZ(c))
27777c3c6bd5Sstsp ctsto += 48 - sifs - slot;
27787c3c6bd5Sstsp
27797c3c6bd5Sstsp reg = RW(reg, AR_TIME_OUT_CTS, ctsto * athn_clock_rate(sc));
27807c3c6bd5Sstsp AR_WRITE(sc, AR_TIME_OUT, reg);
27817c3c6bd5Sstsp AR_WRITE_BARRIER(sc);
27827c3c6bd5Sstsp }
27837c3c6bd5Sstsp
27847c3c6bd5Sstsp void
athn_setclockrate(struct athn_softc * sc)27857c3c6bd5Sstsp athn_setclockrate(struct athn_softc *sc)
27867c3c6bd5Sstsp {
27877c3c6bd5Sstsp int clockrate = athn_clock_rate(sc);
27887c3c6bd5Sstsp uint32_t reg = AR_READ(sc, AR_USEC);
27897c3c6bd5Sstsp reg = RW(reg, AR_USEC_USEC, clockrate - 1);
27907c3c6bd5Sstsp AR_WRITE(sc, AR_USEC, reg);
27917c3c6bd5Sstsp AR_WRITE_BARRIER(sc);
27927c3c6bd5Sstsp }
27937c3c6bd5Sstsp
2794498e8a28Sdamien void
athn_updateslot(struct ieee80211com * ic)2795498e8a28Sdamien athn_updateslot(struct ieee80211com *ic)
2796498e8a28Sdamien {
2797498e8a28Sdamien struct athn_softc *sc = ic->ic_softc;
2798186e7a92Sdamien int slot;
2799498e8a28Sdamien
28008443256dSkevlo slot = (ic->ic_flags & IEEE80211_F_SHSLOT) ?
28018443256dSkevlo IEEE80211_DUR_DS_SHSLOT : IEEE80211_DUR_DS_SLOT;
2802186e7a92Sdamien AR_WRITE(sc, AR_D_GBL_IFS_SLOT, slot * athn_clock_rate(sc));
2803c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
28047c3c6bd5Sstsp
28057c3c6bd5Sstsp athn_setacktimeout(sc, ic->ic_bss->ni_chan, slot);
28067c3c6bd5Sstsp athn_setctstimeout(sc, ic->ic_bss->ni_chan, slot);
2807498e8a28Sdamien }
2808498e8a28Sdamien
2809498e8a28Sdamien void
athn_start(struct ifnet * ifp)2810498e8a28Sdamien athn_start(struct ifnet *ifp)
2811498e8a28Sdamien {
2812498e8a28Sdamien struct athn_softc *sc = ifp->if_softc;
2813498e8a28Sdamien struct ieee80211com *ic = &sc->sc_ic;
2814498e8a28Sdamien struct ieee80211_node *ni;
2815498e8a28Sdamien struct mbuf *m;
2816498e8a28Sdamien
2817de6cd8fbSdlg if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd))
2818498e8a28Sdamien return;
2819498e8a28Sdamien
2820498e8a28Sdamien for (;;) {
2821498e8a28Sdamien if (SIMPLEQ_EMPTY(&sc->txbufs)) {
2822de6cd8fbSdlg ifq_set_oactive(&ifp->if_snd);
2823498e8a28Sdamien break;
2824498e8a28Sdamien }
2825498e8a28Sdamien /* Send pending management frames first. */
2826351e1934Sdlg m = mq_dequeue(&ic->ic_mgtq);
2827498e8a28Sdamien if (m != NULL) {
28286da4b19dSmpi ni = m->m_pkthdr.ph_cookie;
2829498e8a28Sdamien goto sendit;
2830498e8a28Sdamien }
2831498e8a28Sdamien if (ic->ic_state != IEEE80211_S_RUN)
2832498e8a28Sdamien break;
2833498e8a28Sdamien
2834351e1934Sdlg m = mq_dequeue(&ic->ic_pwrsaveq);
28355dde5fe4Skettenis if (m != NULL) {
28366da4b19dSmpi ni = m->m_pkthdr.ph_cookie;
28375dde5fe4Skettenis goto sendit;
28385dde5fe4Skettenis }
28395dde5fe4Skettenis if (ic->ic_state != IEEE80211_S_RUN)
28405dde5fe4Skettenis break;
28415dde5fe4Skettenis
2842498e8a28Sdamien /* Encapsulate and send data frames. */
284363bcfa73Spatrick m = ifq_dequeue(&ifp->if_snd);
2844498e8a28Sdamien if (m == NULL)
2845498e8a28Sdamien break;
2846498e8a28Sdamien #if NBPFILTER > 0
2847498e8a28Sdamien if (ifp->if_bpf != NULL)
2848498e8a28Sdamien bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
2849498e8a28Sdamien #endif
2850498e8a28Sdamien if ((m = ieee80211_encap(ifp, m, &ni)) == NULL)
2851498e8a28Sdamien continue;
2852498e8a28Sdamien sendit:
2853498e8a28Sdamien #if NBPFILTER > 0
2854498e8a28Sdamien if (ic->ic_rawbpf != NULL)
2855498e8a28Sdamien bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_OUT);
2856498e8a28Sdamien #endif
2857436170c5Sdamien if (sc->ops.tx(sc, m, ni, 0) != 0) {
2858498e8a28Sdamien ieee80211_release_node(ic, ni);
2859498e8a28Sdamien ifp->if_oerrors++;
2860498e8a28Sdamien continue;
2861498e8a28Sdamien }
2862498e8a28Sdamien
2863498e8a28Sdamien sc->sc_tx_timer = 5;
2864498e8a28Sdamien ifp->if_timer = 1;
2865498e8a28Sdamien }
2866498e8a28Sdamien }
2867498e8a28Sdamien
2868498e8a28Sdamien void
athn_watchdog(struct ifnet * ifp)2869498e8a28Sdamien athn_watchdog(struct ifnet *ifp)
2870498e8a28Sdamien {
2871498e8a28Sdamien struct athn_softc *sc = ifp->if_softc;
2872498e8a28Sdamien
2873498e8a28Sdamien ifp->if_timer = 0;
2874498e8a28Sdamien
2875498e8a28Sdamien if (sc->sc_tx_timer > 0) {
2876498e8a28Sdamien if (--sc->sc_tx_timer == 0) {
2877498e8a28Sdamien printf("%s: device timeout\n", sc->sc_dev.dv_xname);
2878498e8a28Sdamien athn_stop(ifp, 1);
2879498e8a28Sdamien (void)athn_init(ifp);
2880498e8a28Sdamien ifp->if_oerrors++;
2881498e8a28Sdamien return;
2882498e8a28Sdamien }
2883498e8a28Sdamien ifp->if_timer = 1;
2884498e8a28Sdamien }
2885498e8a28Sdamien
2886498e8a28Sdamien ieee80211_watchdog(ifp);
2887498e8a28Sdamien }
2888498e8a28Sdamien
2889277846c0Sdamien void
athn_set_multi(struct athn_softc * sc)2890277846c0Sdamien athn_set_multi(struct athn_softc *sc)
2891277846c0Sdamien {
2892277846c0Sdamien struct arpcom *ac = &sc->sc_ic.ic_ac;
2893277846c0Sdamien struct ifnet *ifp = &ac->ac_if;
2894277846c0Sdamien struct ether_multi *enm;
2895277846c0Sdamien struct ether_multistep step;
2896277846c0Sdamien const uint8_t *addr;
2897277846c0Sdamien uint32_t val, lo, hi;
2898277846c0Sdamien uint8_t bit;
2899277846c0Sdamien
2900f2e23e59Smpi if (ac->ac_multirangecnt > 0)
2901f2e23e59Smpi ifp->if_flags |= IFF_ALLMULTI;
2902f2e23e59Smpi
2903277846c0Sdamien if ((ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) != 0) {
2904277846c0Sdamien lo = hi = 0xffffffff;
2905277846c0Sdamien goto done;
2906277846c0Sdamien }
2907277846c0Sdamien lo = hi = 0;
2908277846c0Sdamien ETHER_FIRST_MULTI(step, ac, enm);
2909277846c0Sdamien while (enm != NULL) {
2910277846c0Sdamien addr = enm->enm_addrlo;
2911277846c0Sdamien /* Calculate the XOR value of all eight 6-bit words. */
2912277846c0Sdamien val = addr[0] | addr[1] << 8 | addr[2] << 16;
291341b3497aSdamien bit = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
2914277846c0Sdamien val = addr[3] | addr[4] << 8 | addr[5] << 16;
291541b3497aSdamien bit ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
291641b3497aSdamien bit &= 0x3f;
2917277846c0Sdamien if (bit < 32)
2918277846c0Sdamien lo |= 1 << bit;
2919277846c0Sdamien else
2920277846c0Sdamien hi |= 1 << (bit - 32);
2921277846c0Sdamien ETHER_NEXT_MULTI(step, enm);
2922277846c0Sdamien }
2923277846c0Sdamien done:
2924277846c0Sdamien AR_WRITE(sc, AR_MCAST_FIL0, lo);
2925277846c0Sdamien AR_WRITE(sc, AR_MCAST_FIL1, hi);
2926c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
2927277846c0Sdamien }
2928277846c0Sdamien
2929498e8a28Sdamien int
athn_ioctl(struct ifnet * ifp,u_long cmd,caddr_t data)2930498e8a28Sdamien athn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
2931498e8a28Sdamien {
2932498e8a28Sdamien struct athn_softc *sc = ifp->if_softc;
2933498e8a28Sdamien struct ieee80211com *ic = &sc->sc_ic;
2934498e8a28Sdamien struct ifreq *ifr;
2935498e8a28Sdamien int s, error = 0;
2936498e8a28Sdamien
2937498e8a28Sdamien s = splnet();
2938498e8a28Sdamien
2939498e8a28Sdamien switch (cmd) {
2940498e8a28Sdamien case SIOCSIFADDR:
2941498e8a28Sdamien ifp->if_flags |= IFF_UP;
2942498e8a28Sdamien /* FALLTHROUGH */
2943498e8a28Sdamien case SIOCSIFFLAGS:
2944498e8a28Sdamien if (ifp->if_flags & IFF_UP) {
2945277846c0Sdamien if ((ifp->if_flags & IFF_RUNNING) &&
2946277846c0Sdamien ((ifp->if_flags ^ sc->sc_if_flags) &
2947277846c0Sdamien (IFF_ALLMULTI | IFF_PROMISC)) != 0) {
2948277846c0Sdamien athn_set_multi(sc);
2949277846c0Sdamien } else if (!(ifp->if_flags & IFF_RUNNING))
2950498e8a28Sdamien error = athn_init(ifp);
2951498e8a28Sdamien } else {
2952498e8a28Sdamien if (ifp->if_flags & IFF_RUNNING)
2953498e8a28Sdamien athn_stop(ifp, 1);
2954498e8a28Sdamien }
2955277846c0Sdamien sc->sc_if_flags = ifp->if_flags;
2956498e8a28Sdamien break;
2957498e8a28Sdamien
2958498e8a28Sdamien case SIOCADDMULTI:
2959498e8a28Sdamien case SIOCDELMULTI:
2960498e8a28Sdamien ifr = (struct ifreq *)data;
2961498e8a28Sdamien error = (cmd == SIOCADDMULTI) ?
2962498e8a28Sdamien ether_addmulti(ifr, &ic->ic_ac) :
2963498e8a28Sdamien ether_delmulti(ifr, &ic->ic_ac);
296455c9e353Sdamien if (error == ENETRESET) {
296555c9e353Sdamien athn_set_multi(sc);
2966498e8a28Sdamien error = 0;
296755c9e353Sdamien }
296855c9e353Sdamien break;
296955c9e353Sdamien
297055c9e353Sdamien case SIOCS80211CHANNEL:
297155c9e353Sdamien error = ieee80211_ioctl(ifp, cmd, data);
297255c9e353Sdamien if (error == ENETRESET &&
297355c9e353Sdamien ic->ic_opmode == IEEE80211_M_MONITOR) {
297455c9e353Sdamien if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
297555c9e353Sdamien (IFF_UP | IFF_RUNNING))
297655c9e353Sdamien athn_switch_chan(sc, ic->ic_ibss_chan, NULL);
297755c9e353Sdamien error = 0;
297855c9e353Sdamien }
2979498e8a28Sdamien break;
2980498e8a28Sdamien
2981498e8a28Sdamien default:
2982498e8a28Sdamien error = ieee80211_ioctl(ifp, cmd, data);
2983498e8a28Sdamien }
2984498e8a28Sdamien
2985498e8a28Sdamien if (error == ENETRESET) {
2986498e8a28Sdamien error = 0;
2987498e8a28Sdamien if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
2988498e8a28Sdamien (IFF_UP | IFF_RUNNING)) {
2989498e8a28Sdamien athn_stop(ifp, 0);
2990498e8a28Sdamien error = athn_init(ifp);
2991498e8a28Sdamien }
2992498e8a28Sdamien }
2993498e8a28Sdamien
2994498e8a28Sdamien splx(s);
2995498e8a28Sdamien return (error);
2996498e8a28Sdamien }
2997498e8a28Sdamien
2998498e8a28Sdamien int
athn_init(struct ifnet * ifp)2999498e8a28Sdamien athn_init(struct ifnet *ifp)
3000498e8a28Sdamien {
3001498e8a28Sdamien struct athn_softc *sc = ifp->if_softc;
3002bd6ea91dSdamien struct athn_ops *ops = &sc->ops;
3003498e8a28Sdamien struct ieee80211com *ic = &sc->sc_ic;
3004498e8a28Sdamien struct ieee80211_channel *c, *extc;
3005653e45e5Sdamien int i, error;
3006498e8a28Sdamien
30072c4d03c8Sdamien c = ic->ic_bss->ni_chan = ic->ic_ibss_chan;
30082c4d03c8Sdamien extc = NULL;
3009498e8a28Sdamien
3010498e8a28Sdamien /* In case a new MAC address has been configured. */
3011498e8a28Sdamien IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl));
3012498e8a28Sdamien
3013498e8a28Sdamien /* For CardBus, power on the socket. */
3014498e8a28Sdamien if (sc->sc_enable != NULL) {
3015498e8a28Sdamien if ((error = sc->sc_enable(sc)) != 0) {
3016498e8a28Sdamien printf("%s: could not enable device\n",
3017498e8a28Sdamien sc->sc_dev.dv_xname);
3018498e8a28Sdamien goto fail;
3019498e8a28Sdamien }
3020498e8a28Sdamien if ((error = athn_reset_power_on(sc)) != 0) {
3021498e8a28Sdamien printf("%s: could not power on device\n",
3022498e8a28Sdamien sc->sc_dev.dv_xname);
3023498e8a28Sdamien goto fail;
3024498e8a28Sdamien }
3025498e8a28Sdamien }
3026653e45e5Sdamien if (!(sc->flags & ATHN_FLAG_PCIE))
3027653e45e5Sdamien athn_config_nonpcie(sc);
3028653e45e5Sdamien else
3029653e45e5Sdamien athn_config_pcie(sc);
3030653e45e5Sdamien
3031bd6ea91dSdamien ops->enable_antenna_diversity(sc);
3032653e45e5Sdamien
3033653e45e5Sdamien #ifdef ATHN_BT_COEXISTENCE
3034653e45e5Sdamien /* Configure bluetooth coexistence for combo chips. */
3035653e45e5Sdamien if (sc->flags & ATHN_FLAG_BTCOEX)
3036653e45e5Sdamien athn_btcoex_init(sc);
3037498e8a28Sdamien #endif
3038498e8a28Sdamien
3039653e45e5Sdamien /* Configure LED. */
3040653e45e5Sdamien athn_led_init(sc);
3041653e45e5Sdamien
3042653e45e5Sdamien /* Configure hardware radio switch. */
3043653e45e5Sdamien if (sc->flags & ATHN_FLAG_RFSILENT)
3044bd6ea91dSdamien ops->rfsilent_init(sc);
3045498e8a28Sdamien
304613236e8dSdamien if ((error = athn_hw_reset(sc, c, extc, 1)) != 0) {
3047498e8a28Sdamien printf("%s: unable to reset hardware; reset status %d\n",
3048498e8a28Sdamien sc->sc_dev.dv_xname, error);
3049498e8a28Sdamien goto fail;
3050498e8a28Sdamien }
3051498e8a28Sdamien
3052a5564b58Sstsp athn_config_ht(sc);
3053a5564b58Sstsp
3054498e8a28Sdamien /* Enable Rx. */
3055498e8a28Sdamien athn_rx_start(sc);
3056498e8a28Sdamien
3057797d2c3eSstsp /* Reset HW key cache entries. */
3058797d2c3eSstsp for (i = 0; i < sc->kc_entries; i++)
3059797d2c3eSstsp athn_reset_key(sc, i);
3060797d2c3eSstsp
3061498e8a28Sdamien /* Enable interrupts. */
3062498e8a28Sdamien athn_enable_interrupts(sc);
3063498e8a28Sdamien
3064498e8a28Sdamien #ifdef ATHN_BT_COEXISTENCE
3065498e8a28Sdamien /* Enable bluetooth coexistence for combo chips. */
3066498e8a28Sdamien if (sc->flags & ATHN_FLAG_BTCOEX)
3067498e8a28Sdamien athn_btcoex_enable(sc);
3068498e8a28Sdamien #endif
3069498e8a28Sdamien
3070de6cd8fbSdlg ifq_clr_oactive(&ifp->if_snd);
3071498e8a28Sdamien ifp->if_flags |= IFF_RUNNING;
3072498e8a28Sdamien
3073f0c8d713Sdamien #ifdef notyet
3074498e8a28Sdamien if (ic->ic_flags & IEEE80211_F_WEPON) {
3075498e8a28Sdamien /* Configure WEP keys. */
3076498e8a28Sdamien for (i = 0; i < IEEE80211_WEP_NKID; i++)
30776c0255d5Sdamien athn_set_key(ic, NULL, &ic->ic_nw_keys[i]);
3078498e8a28Sdamien }
3079f0c8d713Sdamien #endif
3080498e8a28Sdamien if (ic->ic_opmode == IEEE80211_M_MONITOR)
3081498e8a28Sdamien ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
3082498e8a28Sdamien else
3083498e8a28Sdamien ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
3084498e8a28Sdamien
3085498e8a28Sdamien return (0);
3086498e8a28Sdamien fail:
3087498e8a28Sdamien athn_stop(ifp, 1);
3088498e8a28Sdamien return (error);
3089498e8a28Sdamien }
3090498e8a28Sdamien
3091498e8a28Sdamien void
athn_stop(struct ifnet * ifp,int disable)3092498e8a28Sdamien athn_stop(struct ifnet *ifp, int disable)
3093498e8a28Sdamien {
3094498e8a28Sdamien struct athn_softc *sc = ifp->if_softc;
3095498e8a28Sdamien struct ieee80211com *ic = &sc->sc_ic;
3096797d2c3eSstsp int qid, i;
3097498e8a28Sdamien
3098498e8a28Sdamien ifp->if_timer = sc->sc_tx_timer = 0;
3099de6cd8fbSdlg ifp->if_flags &= ~IFF_RUNNING;
3100de6cd8fbSdlg ifq_clr_oactive(&ifp->if_snd);
3101498e8a28Sdamien
3102498e8a28Sdamien timeout_del(&sc->scan_to);
3103498e8a28Sdamien
3104498e8a28Sdamien ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
3105498e8a28Sdamien
3106498e8a28Sdamien #ifdef ATHN_BT_COEXISTENCE
3107498e8a28Sdamien /* Disable bluetooth coexistence for combo chips. */
3108498e8a28Sdamien if (sc->flags & ATHN_FLAG_BTCOEX)
3109498e8a28Sdamien athn_btcoex_disable(sc);
3110498e8a28Sdamien #endif
3111498e8a28Sdamien
3112498e8a28Sdamien /* Disable interrupts. */
3113498e8a28Sdamien athn_disable_interrupts(sc);
31147a911050Sdamien /* Acknowledge interrupts (avoids interrupt storms). */
31150deed36dSdamien AR_WRITE(sc, AR_INTR_SYNC_CAUSE, 0xffffffff);
31160deed36dSdamien AR_WRITE(sc, AR_INTR_SYNC_MASK, 0);
3117498e8a28Sdamien
3118498e8a28Sdamien for (qid = 0; qid < ATHN_QID_COUNT; qid++)
3119498e8a28Sdamien athn_stop_tx_dma(sc, qid);
3120498e8a28Sdamien /* XXX call athn_hw_reset if Tx still pending? */
3121498e8a28Sdamien for (qid = 0; qid < ATHN_QID_COUNT; qid++)
3122498e8a28Sdamien athn_tx_reclaim(sc, qid);
3123498e8a28Sdamien
3124498e8a28Sdamien /* Stop Rx. */
312513a6db0dSdamien AR_SETBITS(sc, AR_DIAG_SW, AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT);
3126498e8a28Sdamien AR_WRITE(sc, AR_MIBC, AR_MIBC_FMC);
3127498e8a28Sdamien AR_WRITE(sc, AR_MIBC, AR_MIBC_CMC);
3128498e8a28Sdamien AR_WRITE(sc, AR_FILT_OFDM, 0);
3129498e8a28Sdamien AR_WRITE(sc, AR_FILT_CCK, 0);
3130c0a11cf8Sdamien AR_WRITE_BARRIER(sc);
3131498e8a28Sdamien athn_set_rxfilter(sc, 0);
3132498e8a28Sdamien athn_stop_rx_dma(sc);
3133498e8a28Sdamien
3134797d2c3eSstsp /* Reset HW key cache entries. */
3135797d2c3eSstsp for (i = 0; i < sc->kc_entries; i++)
3136797d2c3eSstsp athn_reset_key(sc, i);
3137797d2c3eSstsp
3138498e8a28Sdamien athn_reset(sc, 0);
3139498e8a28Sdamien athn_init_pll(sc, NULL);
3140498e8a28Sdamien athn_set_power_awake(sc);
3141498e8a28Sdamien athn_reset(sc, 1);
3142498e8a28Sdamien athn_init_pll(sc, NULL);
3143498e8a28Sdamien
3144498e8a28Sdamien athn_set_power_sleep(sc);
3145498e8a28Sdamien
3146498e8a28Sdamien /* For CardBus, power down the socket. */
3147498e8a28Sdamien if (disable && sc->sc_disable != NULL)
3148498e8a28Sdamien sc->sc_disable(sc);
3149498e8a28Sdamien }
315095d74b5fSkettenis
315195d74b5fSkettenis void
athn_suspend(struct athn_softc * sc)315295d74b5fSkettenis athn_suspend(struct athn_softc *sc)
315395d74b5fSkettenis {
315495d74b5fSkettenis struct ifnet *ifp = &sc->sc_ic.ic_if;
315595d74b5fSkettenis
3156d90ceb78Skettenis if (ifp->if_flags & IFF_RUNNING)
315795d74b5fSkettenis athn_stop(ifp, 1);
315895d74b5fSkettenis }
315995d74b5fSkettenis
316095d74b5fSkettenis void
athn_wakeup(struct athn_softc * sc)316137ecb596Sderaadt athn_wakeup(struct athn_softc *sc)
316295d74b5fSkettenis {
316395d74b5fSkettenis struct ifnet *ifp = &sc->sc_ic.ic_if;
316495d74b5fSkettenis
3165378df906Skettenis if (ifp->if_flags & IFF_UP)
316695d74b5fSkettenis athn_init(ifp);
316795d74b5fSkettenis }
3168