1191762Simp/*
2191762Simp * Copyright (c) 2007 The DragonFly Project.  All rights reserved.
3191762Simp *
4191762Simp * This code is derived from software contributed to The DragonFly Project
5191762Simp * by Sepherosa Ziehau <sepherosa@gmail.com>
6191762Simp *
7191762Simp * Redistribution and use in source and binary forms, with or without
8191762Simp * modification, are permitted provided that the following conditions
9191762Simp * are met:
10191762Simp *
11191762Simp * 1. Redistributions of source code must retain the above copyright
12191762Simp *    notice, this list of conditions and the following disclaimer.
13191762Simp * 2. Redistributions in binary form must reproduce the above copyright
14191762Simp *    notice, this list of conditions and the following disclaimer in
15191762Simp *    the documentation and/or other materials provided with the
16191762Simp *    distribution.
17191762Simp * 3. Neither the name of The DragonFly Project nor the names of its
18191762Simp *    contributors may be used to endorse or promote products derived
19191762Simp *    from this software without specific, prior written permission.
20191762Simp *
21191762Simp * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22191762Simp * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23191762Simp * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24191762Simp * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25191762Simp * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26191762Simp * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27191762Simp * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28191762Simp * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29191762Simp * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30191762Simp * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31191762Simp * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32191762Simp * SUCH DAMAGE.
33191762Simp *
34191762Simp * $DragonFly: src/sys/dev/netif/bwi/if_bwi.c,v 1.19 2008/02/15 11:15:38 sephe Exp $
35191762Simp */
36191762Simp
37191762Simp#include <sys/cdefs.h>
38191762Simp__FBSDID("$FreeBSD: stable/10/sys/dev/bwi/if_bwi.c 308367 2016-11-06 13:50:54Z avos $");
39191762Simp
40191762Simp#include "opt_inet.h"
41191762Simp#include "opt_bwi.h"
42235338Sadrian#include "opt_wlan.h"
43191762Simp
44191762Simp#include <sys/param.h>
45191762Simp#include <sys/endian.h>
46191762Simp#include <sys/kernel.h>
47191762Simp#include <sys/bus.h>
48191762Simp#include <sys/malloc.h>
49191762Simp#include <sys/proc.h>
50191762Simp#include <sys/rman.h>
51191762Simp#include <sys/socket.h>
52191762Simp#include <sys/sockio.h>
53191762Simp#include <sys/sysctl.h>
54191762Simp#include <sys/systm.h>
55191762Simp#include <sys/taskqueue.h>
56191762Simp
57191762Simp#include <net/if.h>
58191762Simp#include <net/if_dl.h>
59191762Simp#include <net/if_media.h>
60191762Simp#include <net/if_types.h>
61191762Simp#include <net/if_arp.h>
62191762Simp#include <net/ethernet.h>
63191762Simp#include <net/if_llc.h>
64191762Simp
65191762Simp#include <net80211/ieee80211_var.h>
66191762Simp#include <net80211/ieee80211_radiotap.h>
67191762Simp#include <net80211/ieee80211_regdomain.h>
68191762Simp#include <net80211/ieee80211_phy.h>
69206358Srpaulo#include <net80211/ieee80211_ratectl.h>
70191762Simp
71191762Simp#include <net/bpf.h>
72191762Simp
73191762Simp#ifdef INET
74191762Simp#include <netinet/in.h>
75191762Simp#include <netinet/if_ether.h>
76191762Simp#endif
77191762Simp
78191762Simp#include <machine/bus.h>
79191762Simp
80191762Simp#include <dev/pci/pcivar.h>
81191762Simp#include <dev/pci/pcireg.h>
82191762Simp
83191762Simp#include <dev/bwi/bitops.h>
84191762Simp#include <dev/bwi/if_bwireg.h>
85191762Simp#include <dev/bwi/if_bwivar.h>
86191762Simp#include <dev/bwi/bwimac.h>
87191762Simp#include <dev/bwi/bwirf.h>
88191762Simp
89191762Simpstruct bwi_clock_freq {
90191762Simp	u_int		clkfreq_min;
91191762Simp	u_int		clkfreq_max;
92191762Simp};
93191762Simp
94191762Simpstruct bwi_myaddr_bssid {
95191762Simp	uint8_t		myaddr[IEEE80211_ADDR_LEN];
96191762Simp	uint8_t		bssid[IEEE80211_ADDR_LEN];
97191762Simp} __packed;
98191762Simp
99191762Simpstatic struct ieee80211vap *bwi_vap_create(struct ieee80211com *,
100228621Sbschmidt		    const char [IFNAMSIZ], int, enum ieee80211_opmode, int,
101228621Sbschmidt		    const uint8_t [IEEE80211_ADDR_LEN],
102228621Sbschmidt		    const uint8_t [IEEE80211_ADDR_LEN]);
103191762Simpstatic void	bwi_vap_delete(struct ieee80211vap *);
104191762Simpstatic void	bwi_init(void *);
105191762Simpstatic int	bwi_ioctl(struct ifnet *, u_long, caddr_t);
106191762Simpstatic void	bwi_start(struct ifnet *);
107191762Simpstatic void	bwi_start_locked(struct ifnet *);
108191762Simpstatic int	bwi_raw_xmit(struct ieee80211_node *, struct mbuf *,
109191762Simp			const struct ieee80211_bpf_params *);
110199197Sjhbstatic void	bwi_watchdog(void *);
111191762Simpstatic void	bwi_scan_start(struct ieee80211com *);
112191762Simpstatic void	bwi_set_channel(struct ieee80211com *);
113191762Simpstatic void	bwi_scan_end(struct ieee80211com *);
114191762Simpstatic int	bwi_newstate(struct ieee80211vap *, enum ieee80211_state, int);
115191762Simpstatic void	bwi_updateslot(struct ifnet *);
116191762Simpstatic int	bwi_media_change(struct ifnet *);
117191762Simp
118191762Simpstatic void	bwi_calibrate(void *);
119191762Simp
120191762Simpstatic int	bwi_calc_rssi(struct bwi_softc *, const struct bwi_rxbuf_hdr *);
121191762Simpstatic int	bwi_calc_noise(struct bwi_softc *);
122228621Sbschmidtstatic __inline uint8_t bwi_plcp2rate(uint32_t, enum ieee80211_phytype);
123192468Ssamstatic void	bwi_rx_radiotap(struct bwi_softc *, struct mbuf *,
124191762Simp			struct bwi_rxbuf_hdr *, const void *, int, int, int);
125191762Simp
126191762Simpstatic void	bwi_restart(void *, int);
127191762Simpstatic void	bwi_init_statechg(struct bwi_softc *, int);
128191762Simpstatic void	bwi_stop(struct bwi_softc *, int);
129191762Simpstatic void	bwi_stop_locked(struct bwi_softc *, int);
130191762Simpstatic int	bwi_newbuf(struct bwi_softc *, int, int);
131191762Simpstatic int	bwi_encap(struct bwi_softc *, int, struct mbuf *,
132191762Simp			  struct ieee80211_node *);
133191762Simpstatic int	bwi_encap_raw(struct bwi_softc *, int, struct mbuf *,
134191762Simp			  struct ieee80211_node *,
135191762Simp			  const struct ieee80211_bpf_params *);
136191762Simp
137191762Simpstatic void	bwi_init_rxdesc_ring32(struct bwi_softc *, uint32_t,
138191762Simp				       bus_addr_t, int, int);
139191762Simpstatic void	bwi_reset_rx_ring32(struct bwi_softc *, uint32_t);
140191762Simp
141191762Simpstatic int	bwi_init_tx_ring32(struct bwi_softc *, int);
142191762Simpstatic int	bwi_init_rx_ring32(struct bwi_softc *);
143191762Simpstatic int	bwi_init_txstats32(struct bwi_softc *);
144191762Simpstatic void	bwi_free_tx_ring32(struct bwi_softc *, int);
145191762Simpstatic void	bwi_free_rx_ring32(struct bwi_softc *);
146191762Simpstatic void	bwi_free_txstats32(struct bwi_softc *);
147191762Simpstatic void	bwi_setup_rx_desc32(struct bwi_softc *, int, bus_addr_t, int);
148191762Simpstatic void	bwi_setup_tx_desc32(struct bwi_softc *, struct bwi_ring_data *,
149191762Simp				    int, bus_addr_t, int);
150191762Simpstatic int	bwi_rxeof32(struct bwi_softc *);
151191762Simpstatic void	bwi_start_tx32(struct bwi_softc *, uint32_t, int);
152191762Simpstatic void	bwi_txeof_status32(struct bwi_softc *);
153191762Simp
154191762Simpstatic int	bwi_init_tx_ring64(struct bwi_softc *, int);
155191762Simpstatic int	bwi_init_rx_ring64(struct bwi_softc *);
156191762Simpstatic int	bwi_init_txstats64(struct bwi_softc *);
157191762Simpstatic void	bwi_free_tx_ring64(struct bwi_softc *, int);
158191762Simpstatic void	bwi_free_rx_ring64(struct bwi_softc *);
159191762Simpstatic void	bwi_free_txstats64(struct bwi_softc *);
160191762Simpstatic void	bwi_setup_rx_desc64(struct bwi_softc *, int, bus_addr_t, int);
161191762Simpstatic void	bwi_setup_tx_desc64(struct bwi_softc *, struct bwi_ring_data *,
162191762Simp				    int, bus_addr_t, int);
163191762Simpstatic int	bwi_rxeof64(struct bwi_softc *);
164191762Simpstatic void	bwi_start_tx64(struct bwi_softc *, uint32_t, int);
165191762Simpstatic void	bwi_txeof_status64(struct bwi_softc *);
166191762Simp
167191762Simpstatic int	bwi_rxeof(struct bwi_softc *, int);
168191762Simpstatic void	_bwi_txeof(struct bwi_softc *, uint16_t, int, int);
169191762Simpstatic void	bwi_txeof(struct bwi_softc *);
170191762Simpstatic void	bwi_txeof_status(struct bwi_softc *, int);
171191762Simpstatic void	bwi_enable_intrs(struct bwi_softc *, uint32_t);
172191762Simpstatic void	bwi_disable_intrs(struct bwi_softc *, uint32_t);
173191762Simp
174191762Simpstatic int	bwi_dma_alloc(struct bwi_softc *);
175191762Simpstatic void	bwi_dma_free(struct bwi_softc *);
176191762Simpstatic int	bwi_dma_ring_alloc(struct bwi_softc *, bus_dma_tag_t,
177191762Simp				   struct bwi_ring_data *, bus_size_t,
178191762Simp				   uint32_t);
179191762Simpstatic int	bwi_dma_mbuf_create(struct bwi_softc *);
180191762Simpstatic void	bwi_dma_mbuf_destroy(struct bwi_softc *, int, int);
181191762Simpstatic int	bwi_dma_txstats_alloc(struct bwi_softc *, uint32_t, bus_size_t);
182191762Simpstatic void	bwi_dma_txstats_free(struct bwi_softc *);
183191762Simpstatic void	bwi_dma_ring_addr(void *, bus_dma_segment_t *, int, int);
184191762Simpstatic void	bwi_dma_buf_addr(void *, bus_dma_segment_t *, int,
185191762Simp				 bus_size_t, int);
186191762Simp
187191762Simpstatic void	bwi_power_on(struct bwi_softc *, int);
188191762Simpstatic int	bwi_power_off(struct bwi_softc *, int);
189191762Simpstatic int	bwi_set_clock_mode(struct bwi_softc *, enum bwi_clock_mode);
190191762Simpstatic int	bwi_set_clock_delay(struct bwi_softc *);
191191762Simpstatic void	bwi_get_clock_freq(struct bwi_softc *, struct bwi_clock_freq *);
192191762Simpstatic int	bwi_get_pwron_delay(struct bwi_softc *sc);
193191762Simpstatic void	bwi_set_addr_filter(struct bwi_softc *, uint16_t,
194191762Simp				    const uint8_t *);
195191762Simpstatic void	bwi_set_bssid(struct bwi_softc *, const uint8_t *);
196191762Simp
197191762Simpstatic void	bwi_get_card_flags(struct bwi_softc *);
198191762Simpstatic void	bwi_get_eaddr(struct bwi_softc *, uint16_t, uint8_t *);
199191762Simp
200191762Simpstatic int	bwi_bus_attach(struct bwi_softc *);
201191762Simpstatic int	bwi_bbp_attach(struct bwi_softc *);
202191762Simpstatic int	bwi_bbp_power_on(struct bwi_softc *, enum bwi_clock_mode);
203191762Simpstatic void	bwi_bbp_power_off(struct bwi_softc *);
204191762Simp
205191762Simpstatic const char *bwi_regwin_name(const struct bwi_regwin *);
206191762Simpstatic uint32_t	bwi_regwin_disable_bits(struct bwi_softc *);
207191762Simpstatic void	bwi_regwin_info(struct bwi_softc *, uint16_t *, uint8_t *);
208191762Simpstatic int	bwi_regwin_select(struct bwi_softc *, int);
209191762Simp
210191762Simpstatic void	bwi_led_attach(struct bwi_softc *);
211191762Simpstatic void	bwi_led_newstate(struct bwi_softc *, enum ieee80211_state);
212191762Simpstatic void	bwi_led_event(struct bwi_softc *, int);
213191762Simpstatic void	bwi_led_blink_start(struct bwi_softc *, int, int);
214191762Simpstatic void	bwi_led_blink_next(void *);
215191762Simpstatic void	bwi_led_blink_end(void *);
216191762Simp
217191762Simpstatic const struct {
218191762Simp	uint16_t	did_min;
219191762Simp	uint16_t	did_max;
220191762Simp	uint16_t	bbp_id;
221191762Simp} bwi_bbpid_map[] = {
222191762Simp	{ 0x4301, 0x4301, 0x4301 },
223191762Simp	{ 0x4305, 0x4307, 0x4307 },
224226181Sadrian	{ 0x4402, 0x4403, 0x4402 },
225191762Simp	{ 0x4610, 0x4615, 0x4610 },
226191762Simp	{ 0x4710, 0x4715, 0x4710 },
227191762Simp	{ 0x4720, 0x4725, 0x4309 }
228191762Simp};
229191762Simp
230191762Simpstatic const struct {
231191762Simp	uint16_t	bbp_id;
232191762Simp	int		nregwin;
233191762Simp} bwi_regwin_count[] = {
234191762Simp	{ 0x4301, 5 },
235191762Simp	{ 0x4306, 6 },
236191762Simp	{ 0x4307, 5 },
237191762Simp	{ 0x4310, 8 },
238191762Simp	{ 0x4401, 3 },
239191762Simp	{ 0x4402, 3 },
240191762Simp	{ 0x4610, 9 },
241191762Simp	{ 0x4704, 9 },
242191762Simp	{ 0x4710, 9 },
243191762Simp	{ 0x5365, 7 }
244191762Simp};
245191762Simp
246191762Simp#define CLKSRC(src) 				\
247191762Simp[BWI_CLKSRC_ ## src] = {			\
248191762Simp	.freq_min = BWI_CLKSRC_ ##src## _FMIN,	\
249191762Simp	.freq_max = BWI_CLKSRC_ ##src## _FMAX	\
250191762Simp}
251191762Simp
252191762Simpstatic const struct {
253191762Simp	u_int	freq_min;
254191762Simp	u_int	freq_max;
255191762Simp} bwi_clkfreq[BWI_CLKSRC_MAX] = {
256191762Simp	CLKSRC(LP_OSC),
257191762Simp	CLKSRC(CS_OSC),
258191762Simp	CLKSRC(PCI)
259191762Simp};
260191762Simp
261191762Simp#undef CLKSRC
262191762Simp
263191762Simp#define VENDOR_LED_ACT(vendor)				\
264191762Simp{							\
265191762Simp	.vid = PCI_VENDOR_##vendor,			\
266191762Simp	.led_act = { BWI_VENDOR_LED_ACT_##vendor }	\
267191762Simp}
268191762Simp
269191762Simpstatic const struct {
270191762Simp#define	PCI_VENDOR_COMPAQ	0x0e11
271191762Simp#define	PCI_VENDOR_LINKSYS	0x1737
272191762Simp	uint16_t	vid;
273191762Simp	uint8_t		led_act[BWI_LED_MAX];
274191762Simp} bwi_vendor_led_act[] = {
275191762Simp	VENDOR_LED_ACT(COMPAQ),
276191762Simp	VENDOR_LED_ACT(LINKSYS)
277191762Simp#undef PCI_VENDOR_LINKSYS
278191762Simp#undef PCI_VENDOR_COMPAQ
279191762Simp};
280191762Simp
281191762Simpstatic const uint8_t bwi_default_led_act[BWI_LED_MAX] =
282191762Simp	{ BWI_VENDOR_LED_ACT_DEFAULT };
283191762Simp
284191762Simp#undef VENDOR_LED_ACT
285191762Simp
286191762Simpstatic const struct {
287191762Simp	int	on_dur;
288191762Simp	int	off_dur;
289191762Simp} bwi_led_duration[109] = {
290191762Simp	[0]	= { 400, 100 },
291191762Simp	[2]	= { 150, 75 },
292191762Simp	[4]	= { 90, 45 },
293191762Simp	[11]	= { 66, 34 },
294191762Simp	[12]	= { 53, 26 },
295191762Simp	[18]	= { 42, 21 },
296191762Simp	[22]	= { 35, 17 },
297191762Simp	[24]	= { 32, 16 },
298191762Simp	[36]	= { 21, 10 },
299191762Simp	[48]	= { 16, 8 },
300191762Simp	[72]	= { 11, 5 },
301191762Simp	[96]	= { 9, 4 },
302191762Simp	[108]	= { 7, 3 }
303191762Simp};
304191762Simp
305191762Simp#ifdef BWI_DEBUG
306191762Simp#ifdef BWI_DEBUG_VERBOSE
307191762Simpstatic uint32_t bwi_debug = BWI_DBG_ATTACH | BWI_DBG_INIT | BWI_DBG_TXPOWER;
308191762Simp#else
309191762Simpstatic uint32_t	bwi_debug;
310191762Simp#endif
311191762SimpTUNABLE_INT("hw.bwi.debug", (int *)&bwi_debug);
312191762Simp#endif	/* BWI_DEBUG */
313191762Simp
314191762Simpstatic const uint8_t bwi_zero_addr[IEEE80211_ADDR_LEN];
315191762Simp
316191762Simpuint16_t
317191762Simpbwi_read_sprom(struct bwi_softc *sc, uint16_t ofs)
318191762Simp{
319191762Simp	return CSR_READ_2(sc, ofs + BWI_SPROM_START);
320191762Simp}
321191762Simp
322191762Simpstatic __inline void
323191762Simpbwi_setup_desc32(struct bwi_softc *sc, struct bwi_desc32 *desc_array,
324191762Simp		 int ndesc, int desc_idx, bus_addr_t paddr, int buf_len,
325191762Simp		 int tx)
326191762Simp{
327191762Simp	struct bwi_desc32 *desc = &desc_array[desc_idx];
328191762Simp	uint32_t ctrl, addr, addr_hi, addr_lo;
329191762Simp
330191762Simp	addr_lo = __SHIFTOUT(paddr, BWI_DESC32_A_ADDR_MASK);
331191762Simp	addr_hi = __SHIFTOUT(paddr, BWI_DESC32_A_FUNC_MASK);
332191762Simp
333191762Simp	addr = __SHIFTIN(addr_lo, BWI_DESC32_A_ADDR_MASK) |
334191762Simp	       __SHIFTIN(BWI_DESC32_A_FUNC_TXRX, BWI_DESC32_A_FUNC_MASK);
335191762Simp
336191762Simp	ctrl = __SHIFTIN(buf_len, BWI_DESC32_C_BUFLEN_MASK) |
337191762Simp	       __SHIFTIN(addr_hi, BWI_DESC32_C_ADDRHI_MASK);
338191762Simp	if (desc_idx == ndesc - 1)
339191762Simp		ctrl |= BWI_DESC32_C_EOR;
340191762Simp	if (tx) {
341191762Simp		/* XXX */
342191762Simp		ctrl |= BWI_DESC32_C_FRAME_START |
343191762Simp			BWI_DESC32_C_FRAME_END |
344191762Simp			BWI_DESC32_C_INTR;
345191762Simp	}
346191762Simp
347191762Simp	desc->addr = htole32(addr);
348191762Simp	desc->ctrl = htole32(ctrl);
349191762Simp}
350191762Simp
351191762Simpint
352191762Simpbwi_attach(struct bwi_softc *sc)
353191762Simp{
354191762Simp	struct ieee80211com *ic;
355191762Simp	device_t dev = sc->sc_dev;
356191762Simp	struct ifnet *ifp;
357191762Simp	struct bwi_mac *mac;
358191762Simp	struct bwi_phy *phy;
359191762Simp	int i, error;
360191762Simp	uint8_t bands;
361191762Simp	uint8_t macaddr[IEEE80211_ADDR_LEN];
362191762Simp
363191762Simp	BWI_LOCK_INIT(sc);
364191762Simp
365191762Simp	/*
366191762Simp	 * Initialize taskq and various tasks
367191762Simp	 */
368191762Simp	sc->sc_tq = taskqueue_create("bwi_taskq", M_NOWAIT | M_ZERO,
369191762Simp		taskqueue_thread_enqueue, &sc->sc_tq);
370191762Simp	taskqueue_start_threads(&sc->sc_tq, 1, PI_NET, "%s taskq",
371191762Simp		device_get_nameunit(dev));
372191762Simp	TASK_INIT(&sc->sc_restart_task, 0, bwi_restart, sc);
373191762Simp
374191762Simp	callout_init_mtx(&sc->sc_calib_ch, &sc->sc_mtx, 0);
375191762Simp
376191762Simp	/*
377191762Simp	 * Initialize sysctl variables
378191762Simp	 */
379191762Simp	sc->sc_fw_version = BWI_FW_VERSION3;
380191762Simp	sc->sc_led_idle = (2350 * hz) / 1000;
381191762Simp	sc->sc_led_blink = 1;
382191762Simp	sc->sc_txpwr_calib = 1;
383191762Simp#ifdef BWI_DEBUG
384191762Simp	sc->sc_debug = bwi_debug;
385191762Simp#endif
386191762Simp	bwi_power_on(sc, 1);
387191762Simp
388191762Simp	error = bwi_bbp_attach(sc);
389191762Simp	if (error)
390191762Simp		goto fail;
391191762Simp
392191762Simp	error = bwi_bbp_power_on(sc, BWI_CLOCK_MODE_FAST);
393191762Simp	if (error)
394191762Simp		goto fail;
395191762Simp
396191762Simp	if (BWI_REGWIN_EXIST(&sc->sc_com_regwin)) {
397191762Simp		error = bwi_set_clock_delay(sc);
398191762Simp		if (error)
399191762Simp			goto fail;
400191762Simp
401191762Simp		error = bwi_set_clock_mode(sc, BWI_CLOCK_MODE_FAST);
402191762Simp		if (error)
403191762Simp			goto fail;
404191762Simp
405191762Simp		error = bwi_get_pwron_delay(sc);
406191762Simp		if (error)
407191762Simp			goto fail;
408191762Simp	}
409191762Simp
410191762Simp	error = bwi_bus_attach(sc);
411191762Simp	if (error)
412191762Simp		goto fail;
413191762Simp
414191762Simp	bwi_get_card_flags(sc);
415191762Simp
416191762Simp	bwi_led_attach(sc);
417191762Simp
418191762Simp	for (i = 0; i < sc->sc_nmac; ++i) {
419191762Simp		struct bwi_regwin *old;
420191762Simp
421191762Simp		mac = &sc->sc_mac[i];
422191762Simp		error = bwi_regwin_switch(sc, &mac->mac_regwin, &old);
423191762Simp		if (error)
424191762Simp			goto fail;
425191762Simp
426191762Simp		error = bwi_mac_lateattach(mac);
427191762Simp		if (error)
428191762Simp			goto fail;
429191762Simp
430191762Simp		error = bwi_regwin_switch(sc, old, NULL);
431191762Simp		if (error)
432191762Simp			goto fail;
433191762Simp	}
434191762Simp
435191762Simp	/*
436191762Simp	 * XXX First MAC is known to exist
437191762Simp	 * TODO2
438191762Simp	 */
439191762Simp	mac = &sc->sc_mac[0];
440191762Simp	phy = &mac->mac_phy;
441191762Simp
442191762Simp	bwi_bbp_power_off(sc);
443191762Simp
444191762Simp	error = bwi_dma_alloc(sc);
445191762Simp	if (error)
446191762Simp		goto fail;
447191762Simp
448191762Simp	ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211);
449191762Simp	if (ifp == NULL) {
450191762Simp		device_printf(dev, "can not if_alloc()\n");
451191762Simp		error = ENOSPC;
452191762Simp		goto fail;
453191762Simp	}
454191762Simp	ic = ifp->if_l2com;
455191762Simp
456191762Simp	/* set these up early for if_printf use */
457191762Simp	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
458191762Simp
459191762Simp	ifp->if_softc = sc;
460191762Simp	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
461191762Simp	ifp->if_init = bwi_init;
462191762Simp	ifp->if_ioctl = bwi_ioctl;
463191762Simp	ifp->if_start = bwi_start;
464207554Ssobomax	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
465207554Ssobomax	ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
466191762Simp	IFQ_SET_READY(&ifp->if_snd);
467199197Sjhb	callout_init_mtx(&sc->sc_watchdog_timer, &sc->sc_mtx, 0);
468191762Simp
469191762Simp	/*
470191762Simp	 * Setup ratesets, phytype, channels and get MAC address
471191762Simp	 */
472191762Simp	bands = 0;
473191762Simp	if (phy->phy_mode == IEEE80211_MODE_11B ||
474191762Simp	    phy->phy_mode == IEEE80211_MODE_11G) {
475191762Simp		setbit(&bands, IEEE80211_MODE_11B);
476191762Simp		if (phy->phy_mode == IEEE80211_MODE_11B) {
477191762Simp			ic->ic_phytype = IEEE80211_T_DS;
478191762Simp		} else {
479191762Simp			ic->ic_phytype = IEEE80211_T_OFDM;
480191762Simp			setbit(&bands, IEEE80211_MODE_11G);
481191762Simp		}
482191762Simp
483191762Simp		bwi_get_eaddr(sc, BWI_SPROM_11BG_EADDR, macaddr);
484191762Simp		if (IEEE80211_IS_MULTICAST(macaddr)) {
485191762Simp			bwi_get_eaddr(sc, BWI_SPROM_11A_EADDR, macaddr);
486191762Simp			if (IEEE80211_IS_MULTICAST(macaddr)) {
487191762Simp				device_printf(dev,
488191762Simp				    "invalid MAC address: %6D\n",
489191762Simp				    macaddr, ":");
490191762Simp			}
491191762Simp		}
492191762Simp	} else if (phy->phy_mode == IEEE80211_MODE_11A) {
493191762Simp		/* TODO:11A */
494191762Simp		setbit(&bands, IEEE80211_MODE_11A);
495191762Simp		error = ENXIO;
496191762Simp		goto fail;
497191762Simp	} else {
498191762Simp		panic("unknown phymode %d\n", phy->phy_mode);
499191762Simp	}
500191762Simp
501191762Simp	/* Get locale */
502191762Simp	sc->sc_locale = __SHIFTOUT(bwi_read_sprom(sc, BWI_SPROM_CARD_INFO),
503191762Simp				   BWI_SPROM_CARD_INFO_LOCALE);
504191762Simp	DPRINTF(sc, BWI_DBG_ATTACH, "locale: %d\n", sc->sc_locale);
505191762Simp	/* XXX use locale */
506191762Simp	ieee80211_init_channels(ic, NULL, &bands);
507191762Simp
508191762Simp	ic->ic_ifp = ifp;
509191762Simp	ic->ic_caps = IEEE80211_C_STA |
510191762Simp		      IEEE80211_C_SHSLOT |
511191762Simp		      IEEE80211_C_SHPREAMBLE |
512191762Simp		      IEEE80211_C_WPA |
513191762Simp		      IEEE80211_C_BGSCAN |
514214894Sbschmidt		      IEEE80211_C_MONITOR;
515191762Simp	ic->ic_opmode = IEEE80211_M_STA;
516191762Simp	ieee80211_ifattach(ic, macaddr);
517191762Simp
518191762Simp	ic->ic_headroom = sizeof(struct bwi_txbuf_hdr);
519191762Simp
520191762Simp	/* override default methods */
521191762Simp	ic->ic_vap_create = bwi_vap_create;
522191762Simp	ic->ic_vap_delete = bwi_vap_delete;
523191762Simp	ic->ic_raw_xmit = bwi_raw_xmit;
524191762Simp	ic->ic_updateslot = bwi_updateslot;
525191762Simp	ic->ic_scan_start = bwi_scan_start;
526191762Simp	ic->ic_scan_end = bwi_scan_end;
527191762Simp	ic->ic_set_channel = bwi_set_channel;
528191762Simp
529191762Simp	sc->sc_rates = ieee80211_get_ratetable(ic->ic_curchan);
530191762Simp
531192468Ssam	ieee80211_radiotap_attach(ic,
532192468Ssam	    &sc->sc_tx_th.wt_ihdr, sizeof(sc->sc_tx_th),
533192468Ssam		BWI_TX_RADIOTAP_PRESENT,
534192468Ssam	    &sc->sc_rx_th.wr_ihdr, sizeof(sc->sc_rx_th),
535192468Ssam		BWI_RX_RADIOTAP_PRESENT);
536191762Simp
537191762Simp	/*
538191762Simp	 * Add sysctl nodes
539191762Simp	 */
540217323Smdf	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
541191762Simp		        SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
542191762Simp		        "fw_version", CTLFLAG_RD, &sc->sc_fw_version, 0,
543191762Simp		        "Firmware version");
544217323Smdf	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
545191762Simp		        SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
546191762Simp		        "led_idle", CTLFLAG_RW, &sc->sc_led_idle, 0,
547191762Simp		        "# ticks before LED enters idle state");
548191762Simp	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
549191762Simp		       SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
550191762Simp		       "led_blink", CTLFLAG_RW, &sc->sc_led_blink, 0,
551191762Simp		       "Allow LED to blink");
552191762Simp	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
553191762Simp		       SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
554191762Simp		       "txpwr_calib", CTLFLAG_RW, &sc->sc_txpwr_calib, 0,
555191762Simp		       "Enable software TX power calibration");
556191762Simp#ifdef BWI_DEBUG
557191762Simp	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
558191762Simp		        SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
559191762Simp		        "debug", CTLFLAG_RW, &sc->sc_debug, 0, "Debug flags");
560191762Simp#endif
561191762Simp	if (bootverbose)
562191762Simp		ieee80211_announce(ic);
563191762Simp
564191762Simp	return (0);
565191762Simpfail:
566191762Simp	BWI_LOCK_DESTROY(sc);
567191762Simp	return (error);
568191762Simp}
569191762Simp
570191762Simpint
571191762Simpbwi_detach(struct bwi_softc *sc)
572191762Simp{
573191762Simp	struct ifnet *ifp = sc->sc_ifp;
574191762Simp	struct ieee80211com *ic = ifp->if_l2com;
575191762Simp	int i;
576191762Simp
577191762Simp	bwi_stop(sc, 1);
578193237Simp	callout_drain(&sc->sc_led_blink_ch);
579191762Simp	callout_drain(&sc->sc_calib_ch);
580199197Sjhb	callout_drain(&sc->sc_watchdog_timer);
581191762Simp	ieee80211_ifdetach(ic);
582191762Simp
583191762Simp	for (i = 0; i < sc->sc_nmac; ++i)
584191762Simp		bwi_mac_detach(&sc->sc_mac[i]);
585191762Simp	bwi_dma_free(sc);
586191762Simp	if_free(ifp);
587191762Simp	taskqueue_free(sc->sc_tq);
588191762Simp
589191762Simp	BWI_LOCK_DESTROY(sc);
590191762Simp
591191762Simp	return (0);
592191762Simp}
593191762Simp
594191762Simpstatic struct ieee80211vap *
595228621Sbschmidtbwi_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
596228621Sbschmidt    enum ieee80211_opmode opmode, int flags,
597228621Sbschmidt    const uint8_t bssid[IEEE80211_ADDR_LEN],
598228621Sbschmidt    const uint8_t mac[IEEE80211_ADDR_LEN])
599191762Simp{
600191762Simp	struct bwi_vap *bvp;
601191762Simp	struct ieee80211vap *vap;
602191762Simp
603191762Simp	if (!TAILQ_EMPTY(&ic->ic_vaps))		/* only one at a time */
604191762Simp		return NULL;
605191762Simp	bvp = (struct bwi_vap *) malloc(sizeof(struct bwi_vap),
606191762Simp	    M_80211_VAP, M_WAITOK | M_ZERO);
607191762Simp	if (bvp == NULL)
608191762Simp		return NULL;
609191762Simp	vap = &bvp->bv_vap;
610191762Simp	/* enable s/w bmiss handling for sta mode */
611191762Simp	ieee80211_vap_setup(ic, vap, name, unit, opmode,
612191762Simp	    flags | IEEE80211_CLONE_NOBEACONS, bssid, mac);
613191762Simp
614191762Simp	/* override default methods */
615191762Simp	bvp->bv_newstate = vap->iv_newstate;
616191762Simp	vap->iv_newstate = bwi_newstate;
617191762Simp#if 0
618191762Simp	vap->iv_update_beacon = bwi_beacon_update;
619191762Simp#endif
620206358Srpaulo	ieee80211_ratectl_init(vap);
621191762Simp
622191762Simp	/* complete setup */
623191762Simp	ieee80211_vap_attach(vap, bwi_media_change, ieee80211_media_status);
624191762Simp	ic->ic_opmode = opmode;
625191762Simp	return vap;
626191762Simp}
627191762Simp
628191762Simpstatic void
629191762Simpbwi_vap_delete(struct ieee80211vap *vap)
630191762Simp{
631191762Simp	struct bwi_vap *bvp = BWI_VAP(vap);
632191762Simp
633206358Srpaulo	ieee80211_ratectl_deinit(vap);
634191762Simp	ieee80211_vap_detach(vap);
635191762Simp	free(bvp, M_80211_VAP);
636191762Simp}
637191762Simp
638191762Simpvoid
639191762Simpbwi_suspend(struct bwi_softc *sc)
640191762Simp{
641191762Simp	bwi_stop(sc, 1);
642191762Simp}
643191762Simp
644191762Simpvoid
645191762Simpbwi_resume(struct bwi_softc *sc)
646191762Simp{
647191762Simp	struct ifnet *ifp = sc->sc_ifp;
648191762Simp
649191762Simp	if (ifp->if_flags & IFF_UP)
650191762Simp		bwi_init(sc);
651191762Simp}
652191762Simp
653191762Simpint
654191762Simpbwi_shutdown(struct bwi_softc *sc)
655191762Simp{
656191762Simp	bwi_stop(sc, 1);
657191762Simp	return 0;
658191762Simp}
659191762Simp
660191762Simpstatic void
661191762Simpbwi_power_on(struct bwi_softc *sc, int with_pll)
662191762Simp{
663191762Simp	uint32_t gpio_in, gpio_out, gpio_en;
664191762Simp	uint16_t status;
665191762Simp
666191762Simp	gpio_in = pci_read_config(sc->sc_dev, BWI_PCIR_GPIO_IN, 4);
667191762Simp	if (gpio_in & BWI_PCIM_GPIO_PWR_ON)
668191762Simp		goto back;
669191762Simp
670191762Simp	gpio_out = pci_read_config(sc->sc_dev, BWI_PCIR_GPIO_OUT, 4);
671191762Simp	gpio_en = pci_read_config(sc->sc_dev, BWI_PCIR_GPIO_ENABLE, 4);
672191762Simp
673191762Simp	gpio_out |= BWI_PCIM_GPIO_PWR_ON;
674191762Simp	gpio_en |= BWI_PCIM_GPIO_PWR_ON;
675191762Simp	if (with_pll) {
676191762Simp		/* Turn off PLL first */
677191762Simp		gpio_out |= BWI_PCIM_GPIO_PLL_PWR_OFF;
678191762Simp		gpio_en |= BWI_PCIM_GPIO_PLL_PWR_OFF;
679191762Simp	}
680191762Simp
681191762Simp	pci_write_config(sc->sc_dev, BWI_PCIR_GPIO_OUT, gpio_out, 4);
682191762Simp	pci_write_config(sc->sc_dev, BWI_PCIR_GPIO_ENABLE, gpio_en, 4);
683191762Simp	DELAY(1000);
684191762Simp
685191762Simp	if (with_pll) {
686191762Simp		/* Turn on PLL */
687191762Simp		gpio_out &= ~BWI_PCIM_GPIO_PLL_PWR_OFF;
688191762Simp		pci_write_config(sc->sc_dev, BWI_PCIR_GPIO_OUT, gpio_out, 4);
689191762Simp		DELAY(5000);
690191762Simp	}
691191762Simp
692191762Simpback:
693191762Simp	/* Clear "Signaled Target Abort" */
694191762Simp	status = pci_read_config(sc->sc_dev, PCIR_STATUS, 2);
695191762Simp	status &= ~PCIM_STATUS_STABORT;
696191762Simp	pci_write_config(sc->sc_dev, PCIR_STATUS, status, 2);
697191762Simp}
698191762Simp
699191762Simpstatic int
700191762Simpbwi_power_off(struct bwi_softc *sc, int with_pll)
701191762Simp{
702191762Simp	uint32_t gpio_out, gpio_en;
703191762Simp
704191762Simp	pci_read_config(sc->sc_dev, BWI_PCIR_GPIO_IN, 4); /* dummy read */
705191762Simp	gpio_out = pci_read_config(sc->sc_dev, BWI_PCIR_GPIO_OUT, 4);
706191762Simp	gpio_en = pci_read_config(sc->sc_dev, BWI_PCIR_GPIO_ENABLE, 4);
707191762Simp
708191762Simp	gpio_out &= ~BWI_PCIM_GPIO_PWR_ON;
709191762Simp	gpio_en |= BWI_PCIM_GPIO_PWR_ON;
710191762Simp	if (with_pll) {
711191762Simp		gpio_out |= BWI_PCIM_GPIO_PLL_PWR_OFF;
712191762Simp		gpio_en |= BWI_PCIM_GPIO_PLL_PWR_OFF;
713191762Simp	}
714191762Simp
715191762Simp	pci_write_config(sc->sc_dev, BWI_PCIR_GPIO_OUT, gpio_out, 4);
716191762Simp	pci_write_config(sc->sc_dev, BWI_PCIR_GPIO_ENABLE, gpio_en, 4);
717191762Simp	return 0;
718191762Simp}
719191762Simp
720191762Simpint
721191762Simpbwi_regwin_switch(struct bwi_softc *sc, struct bwi_regwin *rw,
722191762Simp		  struct bwi_regwin **old_rw)
723191762Simp{
724191762Simp	int error;
725191762Simp
726191762Simp	if (old_rw != NULL)
727191762Simp		*old_rw = NULL;
728191762Simp
729191762Simp	if (!BWI_REGWIN_EXIST(rw))
730191762Simp		return EINVAL;
731191762Simp
732191762Simp	if (sc->sc_cur_regwin != rw) {
733191762Simp		error = bwi_regwin_select(sc, rw->rw_id);
734191762Simp		if (error) {
735191762Simp			device_printf(sc->sc_dev, "can't select regwin %d\n",
736191762Simp				  rw->rw_id);
737191762Simp			return error;
738191762Simp		}
739191762Simp	}
740191762Simp
741191762Simp	if (old_rw != NULL)
742191762Simp		*old_rw = sc->sc_cur_regwin;
743191762Simp	sc->sc_cur_regwin = rw;
744191762Simp	return 0;
745191762Simp}
746191762Simp
747191762Simpstatic int
748191762Simpbwi_regwin_select(struct bwi_softc *sc, int id)
749191762Simp{
750191762Simp	uint32_t win = BWI_PCIM_REGWIN(id);
751191762Simp	int i;
752191762Simp
753191762Simp#define RETRY_MAX	50
754191762Simp	for (i = 0; i < RETRY_MAX; ++i) {
755191762Simp		pci_write_config(sc->sc_dev, BWI_PCIR_SEL_REGWIN, win, 4);
756191762Simp		if (pci_read_config(sc->sc_dev, BWI_PCIR_SEL_REGWIN, 4) == win)
757191762Simp			return 0;
758191762Simp		DELAY(10);
759191762Simp	}
760191762Simp#undef RETRY_MAX
761191762Simp
762191762Simp	return ENXIO;
763191762Simp}
764191762Simp
765191762Simpstatic void
766191762Simpbwi_regwin_info(struct bwi_softc *sc, uint16_t *type, uint8_t *rev)
767191762Simp{
768191762Simp	uint32_t val;
769191762Simp
770191762Simp	val = CSR_READ_4(sc, BWI_ID_HI);
771191762Simp	*type = BWI_ID_HI_REGWIN_TYPE(val);
772191762Simp	*rev = BWI_ID_HI_REGWIN_REV(val);
773191762Simp
774191762Simp	DPRINTF(sc, BWI_DBG_ATTACH, "regwin: type 0x%03x, rev %d, "
775191762Simp		"vendor 0x%04x\n", *type, *rev,
776191762Simp		__SHIFTOUT(val, BWI_ID_HI_REGWIN_VENDOR_MASK));
777191762Simp}
778191762Simp
779191762Simpstatic int
780191762Simpbwi_bbp_attach(struct bwi_softc *sc)
781191762Simp{
782191762Simp#define N(arr)	(int)(sizeof(arr) / sizeof(arr[0]))
783191762Simp	uint16_t bbp_id, rw_type;
784191762Simp	uint8_t rw_rev;
785191762Simp	uint32_t info;
786191762Simp	int error, nregwin, i;
787191762Simp
788191762Simp	/*
789191762Simp	 * Get 0th regwin information
790191762Simp	 * NOTE: 0th regwin should exist
791191762Simp	 */
792191762Simp	error = bwi_regwin_select(sc, 0);
793191762Simp	if (error) {
794191762Simp		device_printf(sc->sc_dev, "can't select regwin 0\n");
795191762Simp		return error;
796191762Simp	}
797191762Simp	bwi_regwin_info(sc, &rw_type, &rw_rev);
798191762Simp
799191762Simp	/*
800191762Simp	 * Find out BBP id
801191762Simp	 */
802191762Simp	bbp_id = 0;
803191762Simp	info = 0;
804191762Simp	if (rw_type == BWI_REGWIN_T_COM) {
805191762Simp		info = CSR_READ_4(sc, BWI_INFO);
806191762Simp		bbp_id = __SHIFTOUT(info, BWI_INFO_BBPID_MASK);
807191762Simp
808191762Simp		BWI_CREATE_REGWIN(&sc->sc_com_regwin, 0, rw_type, rw_rev);
809191762Simp
810191762Simp		sc->sc_cap = CSR_READ_4(sc, BWI_CAPABILITY);
811191762Simp	} else {
812191762Simp		for (i = 0; i < N(bwi_bbpid_map); ++i) {
813191762Simp			if (sc->sc_pci_did >= bwi_bbpid_map[i].did_min &&
814191762Simp			    sc->sc_pci_did <= bwi_bbpid_map[i].did_max) {
815191762Simp				bbp_id = bwi_bbpid_map[i].bbp_id;
816191762Simp				break;
817191762Simp			}
818191762Simp		}
819191762Simp		if (bbp_id == 0) {
820191762Simp			device_printf(sc->sc_dev, "no BBP id for device id "
821191762Simp				      "0x%04x\n", sc->sc_pci_did);
822191762Simp			return ENXIO;
823191762Simp		}
824191762Simp
825191762Simp		info = __SHIFTIN(sc->sc_pci_revid, BWI_INFO_BBPREV_MASK) |
826191762Simp		       __SHIFTIN(0, BWI_INFO_BBPPKG_MASK);
827191762Simp	}
828191762Simp
829191762Simp	/*
830191762Simp	 * Find out number of regwins
831191762Simp	 */
832191762Simp	nregwin = 0;
833191762Simp	if (rw_type == BWI_REGWIN_T_COM && rw_rev >= 4) {
834191762Simp		nregwin = __SHIFTOUT(info, BWI_INFO_NREGWIN_MASK);
835191762Simp	} else {
836191762Simp		for (i = 0; i < N(bwi_regwin_count); ++i) {
837191762Simp			if (bwi_regwin_count[i].bbp_id == bbp_id) {
838191762Simp				nregwin = bwi_regwin_count[i].nregwin;
839191762Simp				break;
840191762Simp			}
841191762Simp		}
842191762Simp		if (nregwin == 0) {
843191762Simp			device_printf(sc->sc_dev, "no number of win for "
844191762Simp				      "BBP id 0x%04x\n", bbp_id);
845191762Simp			return ENXIO;
846191762Simp		}
847191762Simp	}
848191762Simp
849191762Simp	/* Record BBP id/rev for later using */
850191762Simp	sc->sc_bbp_id = bbp_id;
851191762Simp	sc->sc_bbp_rev = __SHIFTOUT(info, BWI_INFO_BBPREV_MASK);
852191762Simp	sc->sc_bbp_pkg = __SHIFTOUT(info, BWI_INFO_BBPPKG_MASK);
853191762Simp	device_printf(sc->sc_dev, "BBP: id 0x%04x, rev 0x%x, pkg %d\n",
854191762Simp		      sc->sc_bbp_id, sc->sc_bbp_rev, sc->sc_bbp_pkg);
855191762Simp
856191762Simp	DPRINTF(sc, BWI_DBG_ATTACH, "nregwin %d, cap 0x%08x\n",
857191762Simp		nregwin, sc->sc_cap);
858191762Simp
859191762Simp	/*
860191762Simp	 * Create rest of the regwins
861191762Simp	 */
862191762Simp
863191762Simp	/* Don't re-create common regwin, if it is already created */
864191762Simp	i = BWI_REGWIN_EXIST(&sc->sc_com_regwin) ? 1 : 0;
865191762Simp
866191762Simp	for (; i < nregwin; ++i) {
867191762Simp		/*
868191762Simp		 * Get regwin information
869191762Simp		 */
870191762Simp		error = bwi_regwin_select(sc, i);
871191762Simp		if (error) {
872191762Simp			device_printf(sc->sc_dev,
873191762Simp				      "can't select regwin %d\n", i);
874191762Simp			return error;
875191762Simp		}
876191762Simp		bwi_regwin_info(sc, &rw_type, &rw_rev);
877191762Simp
878191762Simp		/*
879191762Simp		 * Try attach:
880191762Simp		 * 1) Bus (PCI/PCIE) regwin
881191762Simp		 * 2) MAC regwin
882191762Simp		 * Ignore rest types of regwin
883191762Simp		 */
884191762Simp		if (rw_type == BWI_REGWIN_T_BUSPCI ||
885191762Simp		    rw_type == BWI_REGWIN_T_BUSPCIE) {
886191762Simp			if (BWI_REGWIN_EXIST(&sc->sc_bus_regwin)) {
887191762Simp				device_printf(sc->sc_dev,
888191762Simp					      "bus regwin already exists\n");
889191762Simp			} else {
890191762Simp				BWI_CREATE_REGWIN(&sc->sc_bus_regwin, i,
891191762Simp						  rw_type, rw_rev);
892191762Simp			}
893191762Simp		} else if (rw_type == BWI_REGWIN_T_MAC) {
894191762Simp			/* XXX ignore return value */
895191762Simp			bwi_mac_attach(sc, i, rw_rev);
896191762Simp		}
897191762Simp	}
898191762Simp
899191762Simp	/* At least one MAC shold exist */
900191762Simp	if (!BWI_REGWIN_EXIST(&sc->sc_mac[0].mac_regwin)) {
901191762Simp		device_printf(sc->sc_dev, "no MAC was found\n");
902191762Simp		return ENXIO;
903191762Simp	}
904191762Simp	KASSERT(sc->sc_nmac > 0, ("no mac's"));
905191762Simp
906191762Simp	/* Bus regwin must exist */
907191762Simp	if (!BWI_REGWIN_EXIST(&sc->sc_bus_regwin)) {
908191762Simp		device_printf(sc->sc_dev, "no bus regwin was found\n");
909191762Simp		return ENXIO;
910191762Simp	}
911191762Simp
912191762Simp	/* Start with first MAC */
913191762Simp	error = bwi_regwin_switch(sc, &sc->sc_mac[0].mac_regwin, NULL);
914191762Simp	if (error)
915191762Simp		return error;
916191762Simp
917191762Simp	return 0;
918191762Simp#undef N
919191762Simp}
920191762Simp
921191762Simpint
922191762Simpbwi_bus_init(struct bwi_softc *sc, struct bwi_mac *mac)
923191762Simp{
924191762Simp	struct bwi_regwin *old, *bus;
925191762Simp	uint32_t val;
926191762Simp	int error;
927191762Simp
928191762Simp	bus = &sc->sc_bus_regwin;
929191762Simp	KASSERT(sc->sc_cur_regwin == &mac->mac_regwin, ("not cur regwin"));
930191762Simp
931191762Simp	/*
932191762Simp	 * Tell bus to generate requested interrupts
933191762Simp	 */
934191762Simp	if (bus->rw_rev < 6 && bus->rw_type == BWI_REGWIN_T_BUSPCI) {
935191762Simp		/*
936191762Simp		 * NOTE: Read BWI_FLAGS from MAC regwin
937191762Simp		 */
938191762Simp		val = CSR_READ_4(sc, BWI_FLAGS);
939191762Simp
940191762Simp		error = bwi_regwin_switch(sc, bus, &old);
941191762Simp		if (error)
942191762Simp			return error;
943191762Simp
944191762Simp		CSR_SETBITS_4(sc, BWI_INTRVEC, (val & BWI_FLAGS_INTR_MASK));
945191762Simp	} else {
946191762Simp		uint32_t mac_mask;
947191762Simp
948191762Simp		mac_mask = 1 << mac->mac_id;
949191762Simp
950191762Simp		error = bwi_regwin_switch(sc, bus, &old);
951191762Simp		if (error)
952191762Simp			return error;
953191762Simp
954191762Simp		val = pci_read_config(sc->sc_dev, BWI_PCIR_INTCTL, 4);
955191762Simp		val |= mac_mask << 8;
956191762Simp		pci_write_config(sc->sc_dev, BWI_PCIR_INTCTL, val, 4);
957191762Simp	}
958191762Simp
959191762Simp	if (sc->sc_flags & BWI_F_BUS_INITED)
960191762Simp		goto back;
961191762Simp
962191762Simp	if (bus->rw_type == BWI_REGWIN_T_BUSPCI) {
963191762Simp		/*
964191762Simp		 * Enable prefetch and burst
965191762Simp		 */
966191762Simp		CSR_SETBITS_4(sc, BWI_BUS_CONFIG,
967191762Simp			      BWI_BUS_CONFIG_PREFETCH | BWI_BUS_CONFIG_BURST);
968191762Simp
969191762Simp		if (bus->rw_rev < 5) {
970191762Simp			struct bwi_regwin *com = &sc->sc_com_regwin;
971191762Simp
972191762Simp			/*
973191762Simp			 * Configure timeouts for bus operation
974191762Simp			 */
975191762Simp
976191762Simp			/*
977191762Simp			 * Set service timeout and request timeout
978191762Simp			 */
979191762Simp			CSR_SETBITS_4(sc, BWI_CONF_LO,
980191762Simp			__SHIFTIN(BWI_CONF_LO_SERVTO, BWI_CONF_LO_SERVTO_MASK) |
981191762Simp			__SHIFTIN(BWI_CONF_LO_REQTO, BWI_CONF_LO_REQTO_MASK));
982191762Simp
983191762Simp			/*
984191762Simp			 * If there is common regwin, we switch to that regwin
985191762Simp			 * and switch back to bus regwin once we have done.
986191762Simp			 */
987191762Simp			if (BWI_REGWIN_EXIST(com)) {
988191762Simp				error = bwi_regwin_switch(sc, com, NULL);
989191762Simp				if (error)
990191762Simp					return error;
991191762Simp			}
992191762Simp
993191762Simp			/* Let bus know what we have changed */
994191762Simp			CSR_WRITE_4(sc, BWI_BUS_ADDR, BWI_BUS_ADDR_MAGIC);
995191762Simp			CSR_READ_4(sc, BWI_BUS_ADDR); /* Flush */
996191762Simp			CSR_WRITE_4(sc, BWI_BUS_DATA, 0);
997191762Simp			CSR_READ_4(sc, BWI_BUS_DATA); /* Flush */
998191762Simp
999191762Simp			if (BWI_REGWIN_EXIST(com)) {
1000191762Simp				error = bwi_regwin_switch(sc, bus, NULL);
1001191762Simp				if (error)
1002191762Simp					return error;
1003191762Simp			}
1004191762Simp		} else if (bus->rw_rev >= 11) {
1005191762Simp			/*
1006191762Simp			 * Enable memory read multiple
1007191762Simp			 */
1008191762Simp			CSR_SETBITS_4(sc, BWI_BUS_CONFIG, BWI_BUS_CONFIG_MRM);
1009191762Simp		}
1010191762Simp	} else {
1011191762Simp		/* TODO:PCIE */
1012191762Simp	}
1013191762Simp
1014191762Simp	sc->sc_flags |= BWI_F_BUS_INITED;
1015191762Simpback:
1016191762Simp	return bwi_regwin_switch(sc, old, NULL);
1017191762Simp}
1018191762Simp
1019191762Simpstatic void
1020191762Simpbwi_get_card_flags(struct bwi_softc *sc)
1021191762Simp{
1022191762Simp#define	PCI_VENDOR_APPLE 0x106b
1023191762Simp#define	PCI_VENDOR_DELL  0x1028
1024191762Simp	sc->sc_card_flags = bwi_read_sprom(sc, BWI_SPROM_CARD_FLAGS);
1025191762Simp	if (sc->sc_card_flags == 0xffff)
1026191762Simp		sc->sc_card_flags = 0;
1027191762Simp
1028191762Simp	if (sc->sc_pci_subvid == PCI_VENDOR_DELL &&
1029191762Simp	    sc->sc_bbp_id == BWI_BBPID_BCM4301 &&
1030191762Simp	    sc->sc_pci_revid == 0x74)
1031191762Simp		sc->sc_card_flags |= BWI_CARD_F_BT_COEXIST;
1032191762Simp
1033191762Simp	if (sc->sc_pci_subvid == PCI_VENDOR_APPLE &&
1034191762Simp	    sc->sc_pci_subdid == 0x4e && /* XXX */
1035191762Simp	    sc->sc_pci_revid > 0x40)
1036191762Simp		sc->sc_card_flags |= BWI_CARD_F_PA_GPIO9;
1037191762Simp
1038191762Simp	DPRINTF(sc, BWI_DBG_ATTACH, "card flags 0x%04x\n", sc->sc_card_flags);
1039191762Simp#undef PCI_VENDOR_DELL
1040191762Simp#undef PCI_VENDOR_APPLE
1041191762Simp}
1042191762Simp
1043191762Simpstatic void
1044191762Simpbwi_get_eaddr(struct bwi_softc *sc, uint16_t eaddr_ofs, uint8_t *eaddr)
1045191762Simp{
1046191762Simp	int i;
1047191762Simp
1048191762Simp	for (i = 0; i < 3; ++i) {
1049191762Simp		*((uint16_t *)eaddr + i) =
1050191762Simp			htobe16(bwi_read_sprom(sc, eaddr_ofs + 2 * i));
1051191762Simp	}
1052191762Simp}
1053191762Simp
1054191762Simpstatic void
1055191762Simpbwi_get_clock_freq(struct bwi_softc *sc, struct bwi_clock_freq *freq)
1056191762Simp{
1057191762Simp	struct bwi_regwin *com;
1058191762Simp	uint32_t val;
1059191762Simp	u_int div;
1060191762Simp	int src;
1061191762Simp
1062191762Simp	bzero(freq, sizeof(*freq));
1063191762Simp	com = &sc->sc_com_regwin;
1064191762Simp
1065191762Simp	KASSERT(BWI_REGWIN_EXIST(com), ("regwin does not exist"));
1066191762Simp	KASSERT(sc->sc_cur_regwin == com, ("wrong regwin"));
1067191762Simp	KASSERT(sc->sc_cap & BWI_CAP_CLKMODE, ("wrong clock mode"));
1068191762Simp
1069191762Simp	/*
1070191762Simp	 * Calculate clock frequency
1071191762Simp	 */
1072191762Simp	src = -1;
1073191762Simp	div = 0;
1074191762Simp	if (com->rw_rev < 6) {
1075191762Simp		val = pci_read_config(sc->sc_dev, BWI_PCIR_GPIO_OUT, 4);
1076191762Simp		if (val & BWI_PCIM_GPIO_OUT_CLKSRC) {
1077191762Simp			src = BWI_CLKSRC_PCI;
1078191762Simp			div = 64;
1079191762Simp		} else {
1080191762Simp			src = BWI_CLKSRC_CS_OSC;
1081191762Simp			div = 32;
1082191762Simp		}
1083191762Simp	} else if (com->rw_rev < 10) {
1084191762Simp		val = CSR_READ_4(sc, BWI_CLOCK_CTRL);
1085191762Simp
1086191762Simp		src = __SHIFTOUT(val, BWI_CLOCK_CTRL_CLKSRC);
1087191762Simp		if (src == BWI_CLKSRC_LP_OSC) {
1088191762Simp			div = 1;
1089191762Simp		} else {
1090191762Simp			div = (__SHIFTOUT(val, BWI_CLOCK_CTRL_FDIV) + 1) << 2;
1091191762Simp
1092191762Simp			/* Unknown source */
1093191762Simp			if (src >= BWI_CLKSRC_MAX)
1094191762Simp				src = BWI_CLKSRC_CS_OSC;
1095191762Simp		}
1096191762Simp	} else {
1097191762Simp		val = CSR_READ_4(sc, BWI_CLOCK_INFO);
1098191762Simp
1099191762Simp		src = BWI_CLKSRC_CS_OSC;
1100191762Simp		div = (__SHIFTOUT(val, BWI_CLOCK_INFO_FDIV) + 1) << 2;
1101191762Simp	}
1102191762Simp
1103191762Simp	KASSERT(src >= 0 && src < BWI_CLKSRC_MAX, ("bad src %d", src));
1104191762Simp	KASSERT(div != 0, ("div zero"));
1105191762Simp
1106191762Simp	DPRINTF(sc, BWI_DBG_ATTACH, "clksrc %s\n",
1107191762Simp		src == BWI_CLKSRC_PCI ? "PCI" :
1108191762Simp		(src == BWI_CLKSRC_LP_OSC ? "LP_OSC" : "CS_OSC"));
1109191762Simp
1110191762Simp	freq->clkfreq_min = bwi_clkfreq[src].freq_min / div;
1111191762Simp	freq->clkfreq_max = bwi_clkfreq[src].freq_max / div;
1112191762Simp
1113191762Simp	DPRINTF(sc, BWI_DBG_ATTACH, "clkfreq min %u, max %u\n",
1114191762Simp		freq->clkfreq_min, freq->clkfreq_max);
1115191762Simp}
1116191762Simp
1117191762Simpstatic int
1118191762Simpbwi_set_clock_mode(struct bwi_softc *sc, enum bwi_clock_mode clk_mode)
1119191762Simp{
1120191762Simp	struct bwi_regwin *old, *com;
1121191762Simp	uint32_t clk_ctrl, clk_src;
1122191762Simp	int error, pwr_off = 0;
1123191762Simp
1124191762Simp	com = &sc->sc_com_regwin;
1125191762Simp	if (!BWI_REGWIN_EXIST(com))
1126191762Simp		return 0;
1127191762Simp
1128191762Simp	if (com->rw_rev >= 10 || com->rw_rev < 6)
1129191762Simp		return 0;
1130191762Simp
1131191762Simp	/*
1132191762Simp	 * For common regwin whose rev is [6, 10), the chip
1133191762Simp	 * must be capable to change clock mode.
1134191762Simp	 */
1135191762Simp	if ((sc->sc_cap & BWI_CAP_CLKMODE) == 0)
1136191762Simp		return 0;
1137191762Simp
1138191762Simp	error = bwi_regwin_switch(sc, com, &old);
1139191762Simp	if (error)
1140191762Simp		return error;
1141191762Simp
1142191762Simp	if (clk_mode == BWI_CLOCK_MODE_FAST)
1143191762Simp		bwi_power_on(sc, 0);	/* Don't turn on PLL */
1144191762Simp
1145191762Simp	clk_ctrl = CSR_READ_4(sc, BWI_CLOCK_CTRL);
1146191762Simp	clk_src = __SHIFTOUT(clk_ctrl, BWI_CLOCK_CTRL_CLKSRC);
1147191762Simp
1148191762Simp	switch (clk_mode) {
1149191762Simp	case BWI_CLOCK_MODE_FAST:
1150191762Simp		clk_ctrl &= ~BWI_CLOCK_CTRL_SLOW;
1151191762Simp		clk_ctrl |= BWI_CLOCK_CTRL_IGNPLL;
1152191762Simp		break;
1153191762Simp	case BWI_CLOCK_MODE_SLOW:
1154191762Simp		clk_ctrl |= BWI_CLOCK_CTRL_SLOW;
1155191762Simp		break;
1156191762Simp	case BWI_CLOCK_MODE_DYN:
1157191762Simp		clk_ctrl &= ~(BWI_CLOCK_CTRL_SLOW |
1158191762Simp			      BWI_CLOCK_CTRL_IGNPLL |
1159191762Simp			      BWI_CLOCK_CTRL_NODYN);
1160191762Simp		if (clk_src != BWI_CLKSRC_CS_OSC) {
1161191762Simp			clk_ctrl |= BWI_CLOCK_CTRL_NODYN;
1162191762Simp			pwr_off = 1;
1163191762Simp		}
1164191762Simp		break;
1165191762Simp	}
1166191762Simp	CSR_WRITE_4(sc, BWI_CLOCK_CTRL, clk_ctrl);
1167191762Simp
1168191762Simp	if (pwr_off)
1169191762Simp		bwi_power_off(sc, 0);	/* Leave PLL as it is */
1170191762Simp
1171191762Simp	return bwi_regwin_switch(sc, old, NULL);
1172191762Simp}
1173191762Simp
1174191762Simpstatic int
1175191762Simpbwi_set_clock_delay(struct bwi_softc *sc)
1176191762Simp{
1177191762Simp	struct bwi_regwin *old, *com;
1178191762Simp	int error;
1179191762Simp
1180191762Simp	com = &sc->sc_com_regwin;
1181191762Simp	if (!BWI_REGWIN_EXIST(com))
1182191762Simp		return 0;
1183191762Simp
1184191762Simp	error = bwi_regwin_switch(sc, com, &old);
1185191762Simp	if (error)
1186191762Simp		return error;
1187191762Simp
1188191762Simp	if (sc->sc_bbp_id == BWI_BBPID_BCM4321) {
1189191762Simp		if (sc->sc_bbp_rev == 0)
1190191762Simp			CSR_WRITE_4(sc, BWI_CONTROL, BWI_CONTROL_MAGIC0);
1191191762Simp		else if (sc->sc_bbp_rev == 1)
1192191762Simp			CSR_WRITE_4(sc, BWI_CONTROL, BWI_CONTROL_MAGIC1);
1193191762Simp	}
1194191762Simp
1195191762Simp	if (sc->sc_cap & BWI_CAP_CLKMODE) {
1196191762Simp		if (com->rw_rev >= 10) {
1197191762Simp			CSR_FILT_SETBITS_4(sc, BWI_CLOCK_INFO, 0xffff, 0x40000);
1198191762Simp		} else {
1199191762Simp			struct bwi_clock_freq freq;
1200191762Simp
1201191762Simp			bwi_get_clock_freq(sc, &freq);
1202191762Simp			CSR_WRITE_4(sc, BWI_PLL_ON_DELAY,
1203191762Simp				howmany(freq.clkfreq_max * 150, 1000000));
1204191762Simp			CSR_WRITE_4(sc, BWI_FREQ_SEL_DELAY,
1205191762Simp				howmany(freq.clkfreq_max * 15, 1000000));
1206191762Simp		}
1207191762Simp	}
1208191762Simp
1209191762Simp	return bwi_regwin_switch(sc, old, NULL);
1210191762Simp}
1211191762Simp
1212191762Simpstatic void
1213191762Simpbwi_init(void *xsc)
1214191762Simp{
1215191762Simp	struct bwi_softc *sc = xsc;
1216191762Simp	struct ifnet *ifp = sc->sc_ifp;
1217191762Simp	struct ieee80211com *ic = ifp->if_l2com;
1218191762Simp
1219191762Simp	BWI_LOCK(sc);
1220191762Simp	bwi_init_statechg(sc, 1);
1221191762Simp	BWI_UNLOCK(sc);
1222191762Simp
1223191762Simp	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1224191762Simp		ieee80211_start_all(ic);		/* start all vap's */
1225191762Simp}
1226191762Simp
1227191762Simpstatic void
1228191762Simpbwi_init_statechg(struct bwi_softc *sc, int statechg)
1229191762Simp{
1230191762Simp	struct ifnet *ifp = sc->sc_ifp;
1231191762Simp	struct bwi_mac *mac;
1232191762Simp	int error;
1233191762Simp
1234191762Simp	bwi_stop_locked(sc, statechg);
1235191762Simp
1236191762Simp	bwi_bbp_power_on(sc, BWI_CLOCK_MODE_FAST);
1237191762Simp
1238191762Simp	/* TODO: 2 MAC */
1239191762Simp
1240191762Simp	mac = &sc->sc_mac[0];
1241191762Simp	error = bwi_regwin_switch(sc, &mac->mac_regwin, NULL);
1242191762Simp	if (error) {
1243191762Simp		if_printf(ifp, "%s: error %d on regwin switch\n",
1244191762Simp		    __func__, error);
1245191762Simp		goto bad;
1246191762Simp	}
1247191762Simp	error = bwi_mac_init(mac);
1248191762Simp	if (error) {
1249191762Simp		if_printf(ifp, "%s: error %d on MAC init\n", __func__, error);
1250191762Simp		goto bad;
1251191762Simp	}
1252191762Simp
1253191762Simp	bwi_bbp_power_on(sc, BWI_CLOCK_MODE_DYN);
1254191762Simp
1255191762Simp	bwi_set_bssid(sc, bwi_zero_addr);	/* Clear BSSID */
1256191762Simp	bwi_set_addr_filter(sc, BWI_ADDR_FILTER_MYADDR, IF_LLADDR(ifp));
1257191762Simp
1258191762Simp	bwi_mac_reset_hwkeys(mac);
1259191762Simp
1260191762Simp	if ((mac->mac_flags & BWI_MAC_F_HAS_TXSTATS) == 0) {
1261191762Simp		int i;
1262191762Simp
1263191762Simp#define NRETRY	1000
1264191762Simp		/*
1265191762Simp		 * Drain any possible pending TX status
1266191762Simp		 */
1267191762Simp		for (i = 0; i < NRETRY; ++i) {
1268191762Simp			if ((CSR_READ_4(sc, BWI_TXSTATUS0) &
1269191762Simp			     BWI_TXSTATUS0_VALID) == 0)
1270191762Simp				break;
1271191762Simp			CSR_READ_4(sc, BWI_TXSTATUS1);
1272191762Simp		}
1273191762Simp		if (i == NRETRY)
1274191762Simp			if_printf(ifp, "%s: can't drain TX status\n", __func__);
1275191762Simp#undef NRETRY
1276191762Simp	}
1277191762Simp
1278191762Simp	if (mac->mac_phy.phy_mode == IEEE80211_MODE_11G)
1279191762Simp		bwi_mac_updateslot(mac, 1);
1280191762Simp
1281191762Simp	/* Start MAC */
1282191762Simp	error = bwi_mac_start(mac);
1283191762Simp	if (error) {
1284191762Simp		if_printf(ifp, "%s: error %d starting MAC\n", __func__, error);
1285191762Simp		goto bad;
1286191762Simp	}
1287191762Simp
1288191762Simp	/* Clear stop flag before enabling interrupt */
1289191762Simp	sc->sc_flags &= ~BWI_F_STOP;
1290191762Simp
1291191762Simp	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1292199197Sjhb	callout_reset(&sc->sc_watchdog_timer, hz, bwi_watchdog, sc);
1293191762Simp
1294191762Simp	/* Enable intrs */
1295191762Simp	bwi_enable_intrs(sc, BWI_INIT_INTRS);
1296191762Simp	return;
1297191762Simpbad:
1298191762Simp	bwi_stop_locked(sc, 1);
1299191762Simp}
1300191762Simp
1301191762Simpstatic int
1302191762Simpbwi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1303191762Simp{
1304191762Simp#define	IS_RUNNING(ifp) \
1305191762Simp	((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING))
1306191762Simp	struct bwi_softc *sc = ifp->if_softc;
1307191762Simp	struct ieee80211com *ic = ifp->if_l2com;
1308191762Simp	struct ifreq *ifr = (struct ifreq *) data;
1309191762Simp	int error = 0, startall = 0;
1310191762Simp
1311191762Simp	switch (cmd) {
1312191762Simp	case SIOCSIFFLAGS:
1313191762Simp		BWI_LOCK(sc);
1314191762Simp		if (IS_RUNNING(ifp)) {
1315191762Simp			struct bwi_mac *mac;
1316191762Simp			int promisc = -1;
1317191762Simp
1318191762Simp			KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC,
1319191762Simp			    ("current regwin type %d",
1320191762Simp			    sc->sc_cur_regwin->rw_type));
1321191762Simp			mac = (struct bwi_mac *)sc->sc_cur_regwin;
1322191762Simp
1323191762Simp			if ((ifp->if_flags & IFF_PROMISC) &&
1324191762Simp			    (sc->sc_flags & BWI_F_PROMISC) == 0) {
1325191762Simp				promisc = 1;
1326191762Simp				sc->sc_flags |= BWI_F_PROMISC;
1327191762Simp			} else if ((ifp->if_flags & IFF_PROMISC) == 0 &&
1328191762Simp				   (sc->sc_flags & BWI_F_PROMISC)) {
1329191762Simp				promisc = 0;
1330191762Simp				sc->sc_flags &= ~BWI_F_PROMISC;
1331191762Simp			}
1332191762Simp
1333191762Simp			if (promisc >= 0)
1334191762Simp				bwi_mac_set_promisc(mac, promisc);
1335191762Simp		}
1336191762Simp
1337191762Simp		if (ifp->if_flags & IFF_UP) {
1338191762Simp			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
1339191762Simp				bwi_init_statechg(sc, 1);
1340191762Simp				startall = 1;
1341191762Simp			}
1342191762Simp		} else {
1343191762Simp			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1344191762Simp				bwi_stop_locked(sc, 1);
1345191762Simp		}
1346191762Simp		BWI_UNLOCK(sc);
1347191762Simp		if (startall)
1348191762Simp			ieee80211_start_all(ic);
1349191762Simp		break;
1350191762Simp	case SIOCGIFMEDIA:
1351191762Simp		error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
1352191762Simp		break;
1353191762Simp	case SIOCGIFADDR:
1354191762Simp		error = ether_ioctl(ifp, cmd, data);
1355191762Simp		break;
1356191762Simp	default:
1357191762Simp		error = EINVAL;
1358191762Simp		break;
1359191762Simp	}
1360191762Simp	return error;
1361191762Simp#undef IS_RUNNING
1362191762Simp}
1363191762Simp
1364191762Simpstatic void
1365191762Simpbwi_start(struct ifnet *ifp)
1366191762Simp{
1367191762Simp	struct bwi_softc *sc = ifp->if_softc;
1368191762Simp
1369191762Simp	BWI_LOCK(sc);
1370191762Simp	bwi_start_locked(ifp);
1371191762Simp	BWI_UNLOCK(sc);
1372191762Simp}
1373191762Simp
1374191762Simpstatic void
1375191762Simpbwi_start_locked(struct ifnet *ifp)
1376191762Simp{
1377191762Simp	struct bwi_softc *sc = ifp->if_softc;
1378191762Simp	struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[BWI_TX_DATA_RING];
1379191762Simp	struct ieee80211_frame *wh;
1380191762Simp	struct ieee80211_node *ni;
1381191762Simp	struct ieee80211_key *k;
1382191762Simp	struct mbuf *m;
1383191762Simp	int trans, idx;
1384191762Simp
1385191762Simp	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
1386191762Simp		return;
1387191762Simp
1388191762Simp	trans = 0;
1389191762Simp	idx = tbd->tbd_idx;
1390191762Simp
1391191762Simp	while (tbd->tbd_buf[idx].tb_mbuf == NULL) {
1392191762Simp		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);	/* XXX: LOCK */
1393191762Simp		if (m == NULL)
1394191762Simp			break;
1395191762Simp
1396191762Simp		ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
1397191762Simp		wh = mtod(m, struct ieee80211_frame *);
1398262007Skevlo		if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
1399191762Simp			k = ieee80211_crypto_encap(ni, m);
1400191762Simp			if (k == NULL) {
1401191762Simp				ieee80211_free_node(ni);
1402191762Simp				m_freem(m);
1403191762Simp				ifp->if_oerrors++;
1404191762Simp				continue;
1405191762Simp			}
1406191762Simp		}
1407191762Simp		wh = NULL;	/* Catch any invalid use */
1408191762Simp
1409191762Simp		if (bwi_encap(sc, idx, m, ni) != 0) {
1410191762Simp			/* 'm' is freed in bwi_encap() if we reach here */
1411191762Simp			if (ni != NULL)
1412191762Simp				ieee80211_free_node(ni);
1413191762Simp			ifp->if_oerrors++;
1414191762Simp			continue;
1415191762Simp		}
1416191762Simp
1417191762Simp		trans = 1;
1418191762Simp		tbd->tbd_used++;
1419191762Simp		idx = (idx + 1) % BWI_TX_NDESC;
1420191762Simp
1421191762Simp		ifp->if_opackets++;
1422191762Simp
1423191762Simp		if (tbd->tbd_used + BWI_TX_NSPRDESC >= BWI_TX_NDESC) {
1424191762Simp			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1425191762Simp			break;
1426191762Simp		}
1427191762Simp	}
1428191762Simp	tbd->tbd_idx = idx;
1429191762Simp
1430191762Simp	if (trans)
1431199197Sjhb		sc->sc_tx_timer = 5;
1432191762Simp}
1433191762Simp
1434191762Simpstatic int
1435191762Simpbwi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
1436191762Simp	const struct ieee80211_bpf_params *params)
1437191762Simp{
1438191762Simp	struct ieee80211com *ic = ni->ni_ic;
1439191762Simp	struct ifnet *ifp = ic->ic_ifp;
1440191762Simp	struct bwi_softc *sc = ifp->if_softc;
1441191762Simp	/* XXX wme? */
1442191762Simp	struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[BWI_TX_DATA_RING];
1443191762Simp	int idx, error;
1444191762Simp
1445191762Simp	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
1446191762Simp		ieee80211_free_node(ni);
1447191762Simp		m_freem(m);
1448191762Simp		return ENETDOWN;
1449191762Simp	}
1450191762Simp
1451191762Simp	BWI_LOCK(sc);
1452191762Simp	idx = tbd->tbd_idx;
1453191762Simp	KASSERT(tbd->tbd_buf[idx].tb_mbuf == NULL, ("slot %d not empty", idx));
1454191762Simp	if (params == NULL) {
1455191762Simp		/*
1456191762Simp		 * Legacy path; interpret frame contents to decide
1457191762Simp		 * precisely how to send the frame.
1458191762Simp		 */
1459191762Simp		error = bwi_encap(sc, idx, m, ni);
1460191762Simp	} else {
1461191762Simp		/*
1462191762Simp		 * Caller supplied explicit parameters to use in
1463191762Simp		 * sending the frame.
1464191762Simp		 */
1465191762Simp		error = bwi_encap_raw(sc, idx, m, ni, params);
1466191762Simp	}
1467191762Simp	if (error == 0) {
1468191762Simp		ifp->if_opackets++;
1469191762Simp		if (++tbd->tbd_used + BWI_TX_NSPRDESC >= BWI_TX_NDESC)
1470191762Simp			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1471191762Simp		tbd->tbd_idx = (idx + 1) % BWI_TX_NDESC;
1472199197Sjhb		sc->sc_tx_timer = 5;
1473191762Simp	} else {
1474191762Simp		/* NB: m is reclaimed on encap failure */
1475191762Simp		ieee80211_free_node(ni);
1476191762Simp		ifp->if_oerrors++;
1477191762Simp	}
1478191762Simp	BWI_UNLOCK(sc);
1479191762Simp	return error;
1480191762Simp}
1481191762Simp
1482191762Simpstatic void
1483199197Sjhbbwi_watchdog(void *arg)
1484191762Simp{
1485199197Sjhb	struct bwi_softc *sc;
1486199197Sjhb	struct ifnet *ifp;
1487191762Simp
1488199197Sjhb	sc = arg;
1489199197Sjhb	ifp = sc->sc_ifp;
1490199197Sjhb	BWI_ASSERT_LOCKED(sc);
1491199197Sjhb	if (sc->sc_tx_timer != 0 && --sc->sc_tx_timer == 0) {
1492191762Simp		if_printf(ifp, "watchdog timeout\n");
1493191762Simp		ifp->if_oerrors++;
1494191762Simp		taskqueue_enqueue(sc->sc_tq, &sc->sc_restart_task);
1495191762Simp	}
1496199197Sjhb	callout_reset(&sc->sc_watchdog_timer, hz, bwi_watchdog, sc);
1497191762Simp}
1498191762Simp
1499191762Simpstatic void
1500191762Simpbwi_stop(struct bwi_softc *sc, int statechg)
1501191762Simp{
1502191762Simp	BWI_LOCK(sc);
1503191762Simp	bwi_stop_locked(sc, statechg);
1504191762Simp	BWI_UNLOCK(sc);
1505191762Simp}
1506191762Simp
1507191762Simpstatic void
1508191762Simpbwi_stop_locked(struct bwi_softc *sc, int statechg)
1509191762Simp{
1510191762Simp	struct ifnet *ifp = sc->sc_ifp;
1511191762Simp	struct bwi_mac *mac;
1512191762Simp	int i, error, pwr_off = 0;
1513191762Simp
1514191762Simp	BWI_ASSERT_LOCKED(sc);
1515191762Simp
1516191762Simp	callout_stop(&sc->sc_calib_ch);
1517191762Simp	callout_stop(&sc->sc_led_blink_ch);
1518191762Simp	sc->sc_led_blinking = 0;
1519191762Simp	sc->sc_flags |= BWI_F_STOP;
1520191762Simp
1521191762Simp	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1522191762Simp		KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC,
1523191762Simp		    ("current regwin type %d", sc->sc_cur_regwin->rw_type));
1524191762Simp		mac = (struct bwi_mac *)sc->sc_cur_regwin;
1525191762Simp
1526191762Simp		bwi_disable_intrs(sc, BWI_ALL_INTRS);
1527191762Simp		CSR_READ_4(sc, BWI_MAC_INTR_MASK);
1528191762Simp		bwi_mac_stop(mac);
1529191762Simp	}
1530191762Simp
1531191762Simp	for (i = 0; i < sc->sc_nmac; ++i) {
1532191762Simp		struct bwi_regwin *old_rw;
1533191762Simp
1534191762Simp		mac = &sc->sc_mac[i];
1535191762Simp		if ((mac->mac_flags & BWI_MAC_F_INITED) == 0)
1536191762Simp			continue;
1537191762Simp
1538191762Simp		error = bwi_regwin_switch(sc, &mac->mac_regwin, &old_rw);
1539191762Simp		if (error)
1540191762Simp			continue;
1541191762Simp
1542191762Simp		bwi_mac_shutdown(mac);
1543191762Simp		pwr_off = 1;
1544191762Simp
1545191762Simp		bwi_regwin_switch(sc, old_rw, NULL);
1546191762Simp	}
1547191762Simp
1548191762Simp	if (pwr_off)
1549191762Simp		bwi_bbp_power_off(sc);
1550191762Simp
1551191762Simp	sc->sc_tx_timer = 0;
1552199197Sjhb	callout_stop(&sc->sc_watchdog_timer);
1553191762Simp	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
1554191762Simp}
1555191762Simp
1556191762Simpvoid
1557191762Simpbwi_intr(void *xsc)
1558191762Simp{
1559191762Simp	struct bwi_softc *sc = xsc;
1560191762Simp	struct ifnet *ifp = sc->sc_ifp;
1561191762Simp	struct bwi_mac *mac;
1562191762Simp	uint32_t intr_status;
1563191762Simp	uint32_t txrx_intr_status[BWI_TXRX_NRING];
1564191762Simp	int i, txrx_error, tx = 0, rx_data = -1;
1565191762Simp
1566191762Simp	BWI_LOCK(sc);
1567191762Simp
1568191762Simp	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
1569191762Simp	    (sc->sc_flags & BWI_F_STOP)) {
1570191762Simp		BWI_UNLOCK(sc);
1571191762Simp		return;
1572191762Simp	}
1573191762Simp	/*
1574191762Simp	 * Get interrupt status
1575191762Simp	 */
1576191762Simp	intr_status = CSR_READ_4(sc, BWI_MAC_INTR_STATUS);
1577191762Simp	if (intr_status == 0xffffffff) {	/* Not for us */
1578191762Simp		BWI_UNLOCK(sc);
1579191762Simp		return;
1580191762Simp	}
1581191762Simp
1582191762Simp	DPRINTF(sc, BWI_DBG_INTR, "intr status 0x%08x\n", intr_status);
1583191762Simp
1584191762Simp	intr_status &= CSR_READ_4(sc, BWI_MAC_INTR_MASK);
1585191762Simp	if (intr_status == 0) {		/* Nothing is interesting */
1586191762Simp		BWI_UNLOCK(sc);
1587191762Simp		return;
1588191762Simp	}
1589191762Simp
1590191762Simp	KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC,
1591191762Simp	    ("current regwin type %d", sc->sc_cur_regwin->rw_type));
1592191762Simp	mac = (struct bwi_mac *)sc->sc_cur_regwin;
1593191762Simp
1594191762Simp	txrx_error = 0;
1595191762Simp	DPRINTF(sc, BWI_DBG_INTR, "%s\n", "TX/RX intr");
1596191762Simp	for (i = 0; i < BWI_TXRX_NRING; ++i) {
1597191762Simp		uint32_t mask;
1598191762Simp
1599191762Simp		if (BWI_TXRX_IS_RX(i))
1600191762Simp			mask = BWI_TXRX_RX_INTRS;
1601191762Simp		else
1602191762Simp			mask = BWI_TXRX_TX_INTRS;
1603191762Simp
1604191762Simp		txrx_intr_status[i] =
1605191762Simp		CSR_READ_4(sc, BWI_TXRX_INTR_STATUS(i)) & mask;
1606191762Simp
1607191762Simp		_DPRINTF(sc, BWI_DBG_INTR, ", %d 0x%08x",
1608191762Simp			 i, txrx_intr_status[i]);
1609191762Simp
1610191762Simp		if (txrx_intr_status[i] & BWI_TXRX_INTR_ERROR) {
1611191762Simp			if_printf(ifp,
1612191762Simp			    "%s: intr fatal TX/RX (%d) error 0x%08x\n",
1613191762Simp			    __func__, i, txrx_intr_status[i]);
1614191762Simp			txrx_error = 1;
1615191762Simp		}
1616191762Simp	}
1617191762Simp	_DPRINTF(sc, BWI_DBG_INTR, "%s\n", "");
1618191762Simp
1619191762Simp	/*
1620191762Simp	 * Acknowledge interrupt
1621191762Simp	 */
1622191762Simp	CSR_WRITE_4(sc, BWI_MAC_INTR_STATUS, intr_status);
1623191762Simp
1624191762Simp	for (i = 0; i < BWI_TXRX_NRING; ++i)
1625191762Simp		CSR_WRITE_4(sc, BWI_TXRX_INTR_STATUS(i), txrx_intr_status[i]);
1626191762Simp
1627191762Simp	/* Disable all interrupts */
1628191762Simp	bwi_disable_intrs(sc, BWI_ALL_INTRS);
1629191762Simp
1630193236Simp	/*
1631193236Simp	 * http://bcm-specs.sipsolutions.net/Interrupts
1632193236Simp	 * Says for this bit (0x800):
1633193236Simp	 * "Fatal Error
1634193236Simp	 *
1635193236Simp	 * We got this one while testing things when by accident the
1636193236Simp	 * template ram wasn't set to big endian when it should have
1637193236Simp	 * been after writing the initial values. It keeps on being
1638193236Simp	 * triggered, the only way to stop it seems to shut down the
1639193236Simp	 * chip."
1640193236Simp	 *
1641193236Simp	 * Suggesting that we should never get it and if we do we're not
1642193236Simp	 * feeding TX packets into the MAC correctly if we do...  Apparently,
1643193236Simp	 * it is valid only on mac version 5 and higher, but I couldn't
1644193236Simp	 * find a reference for that...  Since I see them from time to time
1645193236Simp	 * on my card, this suggests an error in the tx path still...
1646193236Simp	 */
1647191762Simp	if (intr_status & BWI_INTR_PHY_TXERR) {
1648191762Simp		if (mac->mac_flags & BWI_MAC_F_PHYE_RESET) {
1649191762Simp			if_printf(ifp, "%s: intr PHY TX error\n", __func__);
1650191762Simp			taskqueue_enqueue(sc->sc_tq, &sc->sc_restart_task);
1651191762Simp			BWI_UNLOCK(sc);
1652191762Simp			return;
1653191762Simp		}
1654191762Simp	}
1655191762Simp
1656191762Simp	if (txrx_error) {
1657191762Simp		/* TODO: reset device */
1658191762Simp	}
1659191762Simp
1660191762Simp	if (intr_status & BWI_INTR_TBTT)
1661191762Simp		bwi_mac_config_ps(mac);
1662191762Simp
1663191762Simp	if (intr_status & BWI_INTR_EO_ATIM)
1664191762Simp		if_printf(ifp, "EO_ATIM\n");
1665191762Simp
1666191762Simp	if (intr_status & BWI_INTR_PMQ) {
1667191762Simp		for (;;) {
1668191762Simp			if ((CSR_READ_4(sc, BWI_MAC_PS_STATUS) & 0x8) == 0)
1669191762Simp				break;
1670191762Simp		}
1671191762Simp		CSR_WRITE_2(sc, BWI_MAC_PS_STATUS, 0x2);
1672191762Simp	}
1673191762Simp
1674191762Simp	if (intr_status & BWI_INTR_NOISE)
1675191762Simp		if_printf(ifp, "intr noise\n");
1676191762Simp
1677191762Simp	if (txrx_intr_status[0] & BWI_TXRX_INTR_RX) {
1678191762Simp		rx_data = sc->sc_rxeof(sc);
1679191762Simp		if (sc->sc_flags & BWI_F_STOP) {
1680191762Simp			BWI_UNLOCK(sc);
1681191762Simp			return;
1682191762Simp		}
1683191762Simp	}
1684191762Simp
1685191762Simp	if (txrx_intr_status[3] & BWI_TXRX_INTR_RX) {
1686191762Simp		sc->sc_txeof_status(sc);
1687191762Simp		tx = 1;
1688191762Simp	}
1689191762Simp
1690191762Simp	if (intr_status & BWI_INTR_TX_DONE) {
1691191762Simp		bwi_txeof(sc);
1692191762Simp		tx = 1;
1693191762Simp	}
1694191762Simp
1695191762Simp	/* Re-enable interrupts */
1696191762Simp	bwi_enable_intrs(sc, BWI_INIT_INTRS);
1697191762Simp
1698191762Simp	if (sc->sc_blink_led != NULL && sc->sc_led_blink) {
1699191762Simp		int evt = BWI_LED_EVENT_NONE;
1700191762Simp
1701191762Simp		if (tx && rx_data > 0) {
1702191762Simp			if (sc->sc_rx_rate > sc->sc_tx_rate)
1703191762Simp				evt = BWI_LED_EVENT_RX;
1704191762Simp			else
1705191762Simp				evt = BWI_LED_EVENT_TX;
1706191762Simp		} else if (tx) {
1707191762Simp			evt = BWI_LED_EVENT_TX;
1708191762Simp		} else if (rx_data > 0) {
1709191762Simp			evt = BWI_LED_EVENT_RX;
1710191762Simp		} else if (rx_data == 0) {
1711191762Simp			evt = BWI_LED_EVENT_POLL;
1712191762Simp		}
1713191762Simp
1714191762Simp		if (evt != BWI_LED_EVENT_NONE)
1715191762Simp			bwi_led_event(sc, evt);
1716191762Simp	}
1717191762Simp
1718191762Simp	BWI_UNLOCK(sc);
1719191762Simp}
1720191762Simp
1721191762Simpstatic void
1722191762Simpbwi_scan_start(struct ieee80211com *ic)
1723191762Simp{
1724191762Simp	struct bwi_softc *sc = ic->ic_ifp->if_softc;
1725191762Simp
1726191762Simp	BWI_LOCK(sc);
1727191762Simp	/* Enable MAC beacon promiscuity */
1728191762Simp	CSR_SETBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_PASS_BCN);
1729191762Simp	BWI_UNLOCK(sc);
1730191762Simp}
1731191762Simp
1732191762Simpstatic void
1733191762Simpbwi_set_channel(struct ieee80211com *ic)
1734191762Simp{
1735191762Simp	struct bwi_softc *sc = ic->ic_ifp->if_softc;
1736191762Simp	struct ieee80211_channel *c = ic->ic_curchan;
1737191762Simp	struct bwi_mac *mac;
1738191762Simp
1739191762Simp	BWI_LOCK(sc);
1740191762Simp	KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC,
1741191762Simp	    ("current regwin type %d", sc->sc_cur_regwin->rw_type));
1742191762Simp	mac = (struct bwi_mac *)sc->sc_cur_regwin;
1743191762Simp	bwi_rf_set_chan(mac, ieee80211_chan2ieee(ic, c), 0);
1744191762Simp
1745191762Simp	sc->sc_rates = ieee80211_get_ratetable(c);
1746191762Simp
1747191762Simp	/*
1748191762Simp	 * Setup radio tap channel freq and flags
1749191762Simp	 */
1750191762Simp	sc->sc_tx_th.wt_chan_freq = sc->sc_rx_th.wr_chan_freq =
1751191762Simp		htole16(c->ic_freq);
1752191762Simp	sc->sc_tx_th.wt_chan_flags = sc->sc_rx_th.wr_chan_flags =
1753191762Simp		htole16(c->ic_flags & 0xffff);
1754191762Simp
1755191762Simp	BWI_UNLOCK(sc);
1756191762Simp}
1757191762Simp
1758191762Simpstatic void
1759191762Simpbwi_scan_end(struct ieee80211com *ic)
1760191762Simp{
1761191762Simp	struct bwi_softc *sc = ic->ic_ifp->if_softc;
1762191762Simp
1763191762Simp	BWI_LOCK(sc);
1764191762Simp	CSR_CLRBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_PASS_BCN);
1765191762Simp	BWI_UNLOCK(sc);
1766191762Simp}
1767191762Simp
1768191762Simpstatic int
1769191762Simpbwi_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
1770191762Simp{
1771191762Simp	struct bwi_vap *bvp = BWI_VAP(vap);
1772193310Simp	struct ieee80211com *ic= vap->iv_ic;
1773193310Simp	struct ifnet *ifp = ic->ic_ifp;
1774193310Simp	enum ieee80211_state ostate = vap->iv_state;
1775191762Simp	struct bwi_softc *sc = ifp->if_softc;
1776191762Simp	struct bwi_mac *mac;
1777191762Simp	int error;
1778191762Simp
1779191762Simp	BWI_LOCK(sc);
1780191762Simp
1781191762Simp	callout_stop(&sc->sc_calib_ch);
1782191762Simp
1783191762Simp	if (nstate == IEEE80211_S_INIT)
1784191762Simp		sc->sc_txpwrcb_type = BWI_TXPWR_INIT;
1785191762Simp
1786191762Simp	bwi_led_newstate(sc, nstate);
1787191762Simp
1788191762Simp	error = bvp->bv_newstate(vap, nstate, arg);
1789191762Simp	if (error != 0)
1790191762Simp		goto back;
1791191762Simp
1792193310Simp	/*
1793193310Simp	 * Clear the BSSID when we stop a STA
1794193310Simp	 */
1795193310Simp	if (vap->iv_opmode == IEEE80211_M_STA) {
1796193310Simp		if (ostate == IEEE80211_S_RUN && nstate != IEEE80211_S_RUN) {
1797193310Simp			/*
1798193310Simp			 * Clear out the BSSID.  If we reassociate to
1799193310Simp			 * the same AP, this will reinialize things
1800193310Simp			 * correctly...
1801193310Simp			 */
1802193310Simp			if (ic->ic_opmode == IEEE80211_M_STA &&
1803193310Simp			    !(sc->sc_flags & BWI_F_STOP))
1804193310Simp				bwi_set_bssid(sc, bwi_zero_addr);
1805193310Simp		}
1806193310Simp	}
1807193310Simp
1808191762Simp	if (vap->iv_opmode == IEEE80211_M_MONITOR) {
1809191762Simp		/* Nothing to do */
1810191762Simp	} else if (nstate == IEEE80211_S_RUN) {
1811191762Simp		bwi_set_bssid(sc, vap->iv_bss->ni_bssid);
1812191762Simp
1813191762Simp		KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC,
1814191762Simp		    ("current regwin type %d", sc->sc_cur_regwin->rw_type));
1815191762Simp		mac = (struct bwi_mac *)sc->sc_cur_regwin;
1816191762Simp
1817191762Simp		/* Initial TX power calibration */
1818191762Simp		bwi_mac_calibrate_txpower(mac, BWI_TXPWR_INIT);
1819191762Simp#ifdef notyet
1820191762Simp		sc->sc_txpwrcb_type = BWI_TXPWR_FORCE;
1821191762Simp#else
1822191762Simp		sc->sc_txpwrcb_type = BWI_TXPWR_CALIB;
1823191762Simp#endif
1824191762Simp
1825191762Simp		callout_reset(&sc->sc_calib_ch, hz, bwi_calibrate, sc);
1826191762Simp	}
1827191762Simpback:
1828191762Simp	BWI_UNLOCK(sc);
1829191762Simp
1830191762Simp	return error;
1831191762Simp}
1832191762Simp
1833191762Simpstatic int
1834191762Simpbwi_media_change(struct ifnet *ifp)
1835191762Simp{
1836191762Simp	int error = ieee80211_media_change(ifp);
1837191762Simp	/* NB: only the fixed rate can change and that doesn't need a reset */
1838191762Simp	return (error == ENETRESET ? 0 : error);
1839191762Simp}
1840191762Simp
1841191762Simpstatic int
1842191762Simpbwi_dma_alloc(struct bwi_softc *sc)
1843191762Simp{
1844191762Simp	int error, i, has_txstats;
1845191762Simp	bus_addr_t lowaddr = 0;
1846191762Simp	bus_size_t tx_ring_sz, rx_ring_sz, desc_sz = 0;
1847191762Simp	uint32_t txrx_ctrl_step = 0;
1848191762Simp
1849191762Simp	has_txstats = 0;
1850191762Simp	for (i = 0; i < sc->sc_nmac; ++i) {
1851191762Simp		if (sc->sc_mac[i].mac_flags & BWI_MAC_F_HAS_TXSTATS) {
1852191762Simp			has_txstats = 1;
1853191762Simp			break;
1854191762Simp		}
1855191762Simp	}
1856191762Simp
1857191762Simp	switch (sc->sc_bus_space) {
1858191762Simp	case BWI_BUS_SPACE_30BIT:
1859191762Simp	case BWI_BUS_SPACE_32BIT:
1860191762Simp		if (sc->sc_bus_space == BWI_BUS_SPACE_30BIT)
1861191762Simp			lowaddr = BWI_BUS_SPACE_MAXADDR;
1862191762Simp		else
1863191762Simp			lowaddr = BUS_SPACE_MAXADDR_32BIT;
1864191762Simp		desc_sz = sizeof(struct bwi_desc32);
1865191762Simp		txrx_ctrl_step = 0x20;
1866191762Simp
1867191762Simp		sc->sc_init_tx_ring = bwi_init_tx_ring32;
1868191762Simp		sc->sc_free_tx_ring = bwi_free_tx_ring32;
1869191762Simp		sc->sc_init_rx_ring = bwi_init_rx_ring32;
1870191762Simp		sc->sc_free_rx_ring = bwi_free_rx_ring32;
1871191762Simp		sc->sc_setup_rxdesc = bwi_setup_rx_desc32;
1872191762Simp		sc->sc_setup_txdesc = bwi_setup_tx_desc32;
1873191762Simp		sc->sc_rxeof = bwi_rxeof32;
1874191762Simp		sc->sc_start_tx = bwi_start_tx32;
1875191762Simp		if (has_txstats) {
1876191762Simp			sc->sc_init_txstats = bwi_init_txstats32;
1877191762Simp			sc->sc_free_txstats = bwi_free_txstats32;
1878191762Simp			sc->sc_txeof_status = bwi_txeof_status32;
1879191762Simp		}
1880191762Simp		break;
1881191762Simp
1882191762Simp	case BWI_BUS_SPACE_64BIT:
1883191762Simp		lowaddr = BUS_SPACE_MAXADDR;	/* XXX */
1884191762Simp		desc_sz = sizeof(struct bwi_desc64);
1885191762Simp		txrx_ctrl_step = 0x40;
1886191762Simp
1887191762Simp		sc->sc_init_tx_ring = bwi_init_tx_ring64;
1888191762Simp		sc->sc_free_tx_ring = bwi_free_tx_ring64;
1889191762Simp		sc->sc_init_rx_ring = bwi_init_rx_ring64;
1890191762Simp		sc->sc_free_rx_ring = bwi_free_rx_ring64;
1891191762Simp		sc->sc_setup_rxdesc = bwi_setup_rx_desc64;
1892191762Simp		sc->sc_setup_txdesc = bwi_setup_tx_desc64;
1893191762Simp		sc->sc_rxeof = bwi_rxeof64;
1894191762Simp		sc->sc_start_tx = bwi_start_tx64;
1895191762Simp		if (has_txstats) {
1896191762Simp			sc->sc_init_txstats = bwi_init_txstats64;
1897191762Simp			sc->sc_free_txstats = bwi_free_txstats64;
1898191762Simp			sc->sc_txeof_status = bwi_txeof_status64;
1899191762Simp		}
1900191762Simp		break;
1901191762Simp	}
1902191762Simp
1903191762Simp	KASSERT(lowaddr != 0, ("lowaddr zero"));
1904191762Simp	KASSERT(desc_sz != 0, ("desc_sz zero"));
1905191762Simp	KASSERT(txrx_ctrl_step != 0, ("txrx_ctrl_step zero"));
1906191762Simp
1907191762Simp	tx_ring_sz = roundup(desc_sz * BWI_TX_NDESC, BWI_RING_ALIGN);
1908191762Simp	rx_ring_sz = roundup(desc_sz * BWI_RX_NDESC, BWI_RING_ALIGN);
1909191762Simp
1910191762Simp	/*
1911191762Simp	 * Create top level DMA tag
1912191762Simp	 */
1913191762Simp	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev),	/* parent */
1914191762Simp			       BWI_ALIGN, 0,		/* alignment, bounds */
1915191762Simp			       lowaddr,			/* lowaddr */
1916191762Simp			       BUS_SPACE_MAXADDR,	/* highaddr */
1917191762Simp			       NULL, NULL,		/* filter, filterarg */
1918281826Smav			       BUS_SPACE_MAXSIZE,	/* maxsize */
1919191762Simp			       BUS_SPACE_UNRESTRICTED,	/* nsegments */
1920191762Simp			       BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
1921308367Savos			       0,			/* flags */
1922191762Simp			       NULL, NULL,		/* lockfunc, lockarg */
1923191762Simp			       &sc->sc_parent_dtag);
1924191762Simp	if (error) {
1925191762Simp		device_printf(sc->sc_dev, "can't create parent DMA tag\n");
1926191762Simp		return error;
1927191762Simp	}
1928191762Simp
1929191762Simp#define TXRX_CTRL(idx)	(BWI_TXRX_CTRL_BASE + (idx) * txrx_ctrl_step)
1930191762Simp
1931191762Simp	/*
1932191762Simp	 * Create TX ring DMA stuffs
1933191762Simp	 */
1934191762Simp	error = bus_dma_tag_create(sc->sc_parent_dtag,
1935191762Simp				BWI_RING_ALIGN, 0,
1936191762Simp				BUS_SPACE_MAXADDR,
1937191762Simp				BUS_SPACE_MAXADDR,
1938191762Simp				NULL, NULL,
1939191762Simp				tx_ring_sz,
1940191762Simp				1,
1941191762Simp				BUS_SPACE_MAXSIZE_32BIT,
1942308367Savos				0,
1943191762Simp				NULL, NULL,
1944191762Simp				&sc->sc_txring_dtag);
1945191762Simp	if (error) {
1946191762Simp		device_printf(sc->sc_dev, "can't create TX ring DMA tag\n");
1947191762Simp		return error;
1948191762Simp	}
1949191762Simp
1950191762Simp	for (i = 0; i < BWI_TX_NRING; ++i) {
1951191762Simp		error = bwi_dma_ring_alloc(sc, sc->sc_txring_dtag,
1952191762Simp					   &sc->sc_tx_rdata[i], tx_ring_sz,
1953191762Simp					   TXRX_CTRL(i));
1954191762Simp		if (error) {
1955191762Simp			device_printf(sc->sc_dev, "%dth TX ring "
1956191762Simp				      "DMA alloc failed\n", i);
1957191762Simp			return error;
1958191762Simp		}
1959191762Simp	}
1960191762Simp
1961191762Simp	/*
1962191762Simp	 * Create RX ring DMA stuffs
1963191762Simp	 */
1964191762Simp	error = bus_dma_tag_create(sc->sc_parent_dtag,
1965191762Simp				BWI_RING_ALIGN, 0,
1966191762Simp				BUS_SPACE_MAXADDR,
1967191762Simp				BUS_SPACE_MAXADDR,
1968191762Simp				NULL, NULL,
1969191762Simp				rx_ring_sz,
1970191762Simp				1,
1971191762Simp				BUS_SPACE_MAXSIZE_32BIT,
1972308367Savos				0,
1973191762Simp				NULL, NULL,
1974191762Simp				&sc->sc_rxring_dtag);
1975191762Simp	if (error) {
1976191762Simp		device_printf(sc->sc_dev, "can't create RX ring DMA tag\n");
1977191762Simp		return error;
1978191762Simp	}
1979191762Simp
1980191762Simp	error = bwi_dma_ring_alloc(sc, sc->sc_rxring_dtag, &sc->sc_rx_rdata,
1981191762Simp				   rx_ring_sz, TXRX_CTRL(0));
1982191762Simp	if (error) {
1983191762Simp		device_printf(sc->sc_dev, "RX ring DMA alloc failed\n");
1984191762Simp		return error;
1985191762Simp	}
1986191762Simp
1987191762Simp	if (has_txstats) {
1988191762Simp		error = bwi_dma_txstats_alloc(sc, TXRX_CTRL(3), desc_sz);
1989191762Simp		if (error) {
1990191762Simp			device_printf(sc->sc_dev,
1991191762Simp				      "TX stats DMA alloc failed\n");
1992191762Simp			return error;
1993191762Simp		}
1994191762Simp	}
1995191762Simp
1996191762Simp#undef TXRX_CTRL
1997191762Simp
1998191762Simp	return bwi_dma_mbuf_create(sc);
1999191762Simp}
2000191762Simp
2001191762Simpstatic void
2002191762Simpbwi_dma_free(struct bwi_softc *sc)
2003191762Simp{
2004191762Simp	if (sc->sc_txring_dtag != NULL) {
2005191762Simp		int i;
2006191762Simp
2007191762Simp		for (i = 0; i < BWI_TX_NRING; ++i) {
2008191762Simp			struct bwi_ring_data *rd = &sc->sc_tx_rdata[i];
2009191762Simp
2010191762Simp			if (rd->rdata_desc != NULL) {
2011191762Simp				bus_dmamap_unload(sc->sc_txring_dtag,
2012191762Simp						  rd->rdata_dmap);
2013191762Simp				bus_dmamem_free(sc->sc_txring_dtag,
2014191762Simp						rd->rdata_desc,
2015191762Simp						rd->rdata_dmap);
2016191762Simp			}
2017191762Simp		}
2018191762Simp		bus_dma_tag_destroy(sc->sc_txring_dtag);
2019191762Simp	}
2020191762Simp
2021191762Simp	if (sc->sc_rxring_dtag != NULL) {
2022191762Simp		struct bwi_ring_data *rd = &sc->sc_rx_rdata;
2023191762Simp
2024191762Simp		if (rd->rdata_desc != NULL) {
2025191762Simp			bus_dmamap_unload(sc->sc_rxring_dtag, rd->rdata_dmap);
2026191762Simp			bus_dmamem_free(sc->sc_rxring_dtag, rd->rdata_desc,
2027191762Simp					rd->rdata_dmap);
2028191762Simp		}
2029191762Simp		bus_dma_tag_destroy(sc->sc_rxring_dtag);
2030191762Simp	}
2031191762Simp
2032191762Simp	bwi_dma_txstats_free(sc);
2033191762Simp	bwi_dma_mbuf_destroy(sc, BWI_TX_NRING, 1);
2034191762Simp
2035191762Simp	if (sc->sc_parent_dtag != NULL)
2036191762Simp		bus_dma_tag_destroy(sc->sc_parent_dtag);
2037191762Simp}
2038191762Simp
2039191762Simpstatic int
2040191762Simpbwi_dma_ring_alloc(struct bwi_softc *sc, bus_dma_tag_t dtag,
2041191762Simp		   struct bwi_ring_data *rd, bus_size_t size,
2042191762Simp		   uint32_t txrx_ctrl)
2043191762Simp{
2044191762Simp	int error;
2045191762Simp
2046191762Simp	error = bus_dmamem_alloc(dtag, &rd->rdata_desc,
2047191762Simp				 BUS_DMA_WAITOK | BUS_DMA_ZERO,
2048191762Simp				 &rd->rdata_dmap);
2049191762Simp	if (error) {
2050191762Simp		device_printf(sc->sc_dev, "can't allocate DMA mem\n");
2051191762Simp		return error;
2052191762Simp	}
2053191762Simp
2054191762Simp	error = bus_dmamap_load(dtag, rd->rdata_dmap, rd->rdata_desc, size,
2055191762Simp				bwi_dma_ring_addr, &rd->rdata_paddr,
2056191762Simp				BUS_DMA_NOWAIT);
2057191762Simp	if (error) {
2058191762Simp		device_printf(sc->sc_dev, "can't load DMA mem\n");
2059191762Simp		bus_dmamem_free(dtag, rd->rdata_desc, rd->rdata_dmap);
2060191762Simp		rd->rdata_desc = NULL;
2061191762Simp		return error;
2062191762Simp	}
2063191762Simp
2064191762Simp	rd->rdata_txrx_ctrl = txrx_ctrl;
2065191762Simp	return 0;
2066191762Simp}
2067191762Simp
2068191762Simpstatic int
2069191762Simpbwi_dma_txstats_alloc(struct bwi_softc *sc, uint32_t ctrl_base,
2070191762Simp		      bus_size_t desc_sz)
2071191762Simp{
2072191762Simp	struct bwi_txstats_data *st;
2073191762Simp	bus_size_t dma_size;
2074191762Simp	int error;
2075191762Simp
2076191762Simp	st = malloc(sizeof(*st), M_DEVBUF, M_NOWAIT | M_ZERO);
2077191762Simp	if (st == NULL) {
2078191762Simp		device_printf(sc->sc_dev, "can't allocate txstats data\n");
2079191762Simp		return ENOMEM;
2080191762Simp	}
2081191762Simp	sc->sc_txstats = st;
2082191762Simp
2083191762Simp	/*
2084191762Simp	 * Create TX stats descriptor DMA stuffs
2085191762Simp	 */
2086191762Simp	dma_size = roundup(desc_sz * BWI_TXSTATS_NDESC, BWI_RING_ALIGN);
2087191762Simp
2088191762Simp	error = bus_dma_tag_create(sc->sc_parent_dtag,
2089191762Simp				BWI_RING_ALIGN,
2090191762Simp				0,
2091191762Simp				BUS_SPACE_MAXADDR,
2092191762Simp				BUS_SPACE_MAXADDR,
2093191762Simp				NULL, NULL,
2094191762Simp				dma_size,
2095191762Simp				1,
2096191762Simp				BUS_SPACE_MAXSIZE_32BIT,
2097308367Savos				0,
2098191762Simp				NULL, NULL,
2099191762Simp				&st->stats_ring_dtag);
2100191762Simp	if (error) {
2101191762Simp		device_printf(sc->sc_dev, "can't create txstats ring "
2102191762Simp			      "DMA tag\n");
2103191762Simp		return error;
2104191762Simp	}
2105191762Simp
2106191762Simp	error = bus_dmamem_alloc(st->stats_ring_dtag, &st->stats_ring,
2107191762Simp				 BUS_DMA_WAITOK | BUS_DMA_ZERO,
2108191762Simp				 &st->stats_ring_dmap);
2109191762Simp	if (error) {
2110191762Simp		device_printf(sc->sc_dev, "can't allocate txstats ring "
2111191762Simp			      "DMA mem\n");
2112191762Simp		bus_dma_tag_destroy(st->stats_ring_dtag);
2113191762Simp		st->stats_ring_dtag = NULL;
2114191762Simp		return error;
2115191762Simp	}
2116191762Simp
2117191762Simp	error = bus_dmamap_load(st->stats_ring_dtag, st->stats_ring_dmap,
2118191762Simp				st->stats_ring, dma_size,
2119191762Simp				bwi_dma_ring_addr, &st->stats_ring_paddr,
2120191762Simp				BUS_DMA_NOWAIT);
2121191762Simp	if (error) {
2122191762Simp		device_printf(sc->sc_dev, "can't load txstats ring DMA mem\n");
2123191762Simp		bus_dmamem_free(st->stats_ring_dtag, st->stats_ring,
2124191762Simp				st->stats_ring_dmap);
2125191762Simp		bus_dma_tag_destroy(st->stats_ring_dtag);
2126191762Simp		st->stats_ring_dtag = NULL;
2127191762Simp		return error;
2128191762Simp	}
2129191762Simp
2130191762Simp	/*
2131191762Simp	 * Create TX stats DMA stuffs
2132191762Simp	 */
2133191762Simp	dma_size = roundup(sizeof(struct bwi_txstats) * BWI_TXSTATS_NDESC,
2134191762Simp			   BWI_ALIGN);
2135191762Simp
2136191762Simp	error = bus_dma_tag_create(sc->sc_parent_dtag,
2137191762Simp				BWI_ALIGN,
2138191762Simp				0,
2139191762Simp				BUS_SPACE_MAXADDR,
2140191762Simp				BUS_SPACE_MAXADDR,
2141191762Simp				NULL, NULL,
2142191762Simp				dma_size,
2143191762Simp				1,
2144191762Simp				BUS_SPACE_MAXSIZE_32BIT,
2145308367Savos				0,
2146191762Simp				NULL, NULL,
2147191762Simp				&st->stats_dtag);
2148191762Simp	if (error) {
2149191762Simp		device_printf(sc->sc_dev, "can't create txstats DMA tag\n");
2150191762Simp		return error;
2151191762Simp	}
2152191762Simp
2153191762Simp	error = bus_dmamem_alloc(st->stats_dtag, (void **)&st->stats,
2154191762Simp				 BUS_DMA_WAITOK | BUS_DMA_ZERO,
2155191762Simp				 &st->stats_dmap);
2156191762Simp	if (error) {
2157191762Simp		device_printf(sc->sc_dev, "can't allocate txstats DMA mem\n");
2158191762Simp		bus_dma_tag_destroy(st->stats_dtag);
2159191762Simp		st->stats_dtag = NULL;
2160191762Simp		return error;
2161191762Simp	}
2162191762Simp
2163191762Simp	error = bus_dmamap_load(st->stats_dtag, st->stats_dmap, st->stats,
2164191762Simp				dma_size, bwi_dma_ring_addr, &st->stats_paddr,
2165191762Simp				BUS_DMA_NOWAIT);
2166191762Simp	if (error) {
2167191762Simp		device_printf(sc->sc_dev, "can't load txstats DMA mem\n");
2168191762Simp		bus_dmamem_free(st->stats_dtag, st->stats, st->stats_dmap);
2169191762Simp		bus_dma_tag_destroy(st->stats_dtag);
2170191762Simp		st->stats_dtag = NULL;
2171191762Simp		return error;
2172191762Simp	}
2173191762Simp
2174191762Simp	st->stats_ctrl_base = ctrl_base;
2175191762Simp	return 0;
2176191762Simp}
2177191762Simp
2178191762Simpstatic void
2179191762Simpbwi_dma_txstats_free(struct bwi_softc *sc)
2180191762Simp{
2181191762Simp	struct bwi_txstats_data *st;
2182191762Simp
2183191762Simp	if (sc->sc_txstats == NULL)
2184191762Simp		return;
2185191762Simp	st = sc->sc_txstats;
2186191762Simp
2187191762Simp	if (st->stats_ring_dtag != NULL) {
2188191762Simp		bus_dmamap_unload(st->stats_ring_dtag, st->stats_ring_dmap);
2189191762Simp		bus_dmamem_free(st->stats_ring_dtag, st->stats_ring,
2190191762Simp				st->stats_ring_dmap);
2191191762Simp		bus_dma_tag_destroy(st->stats_ring_dtag);
2192191762Simp	}
2193191762Simp
2194191762Simp	if (st->stats_dtag != NULL) {
2195191762Simp		bus_dmamap_unload(st->stats_dtag, st->stats_dmap);
2196191762Simp		bus_dmamem_free(st->stats_dtag, st->stats, st->stats_dmap);
2197191762Simp		bus_dma_tag_destroy(st->stats_dtag);
2198191762Simp	}
2199191762Simp
2200191762Simp	free(st, M_DEVBUF);
2201191762Simp}
2202191762Simp
2203191762Simpstatic void
2204191762Simpbwi_dma_ring_addr(void *arg, bus_dma_segment_t *seg, int nseg, int error)
2205191762Simp{
2206191762Simp	KASSERT(nseg == 1, ("too many segments\n"));
2207191762Simp	*((bus_addr_t *)arg) = seg->ds_addr;
2208191762Simp}
2209191762Simp
2210191762Simpstatic int
2211191762Simpbwi_dma_mbuf_create(struct bwi_softc *sc)
2212191762Simp{
2213191762Simp	struct bwi_rxbuf_data *rbd = &sc->sc_rx_bdata;
2214191762Simp	int i, j, k, ntx, error;
2215191762Simp
2216191762Simp	/*
2217191762Simp	 * Create TX/RX mbuf DMA tag
2218191762Simp	 */
2219191762Simp	error = bus_dma_tag_create(sc->sc_parent_dtag,
2220191762Simp				1,
2221191762Simp				0,
2222191762Simp				BUS_SPACE_MAXADDR,
2223191762Simp				BUS_SPACE_MAXADDR,
2224191762Simp				NULL, NULL,
2225191762Simp				MCLBYTES,
2226191762Simp				1,
2227308367Savos				MCLBYTES,
2228191762Simp				BUS_DMA_ALLOCNOW,
2229191762Simp				NULL, NULL,
2230191762Simp				&sc->sc_buf_dtag);
2231191762Simp	if (error) {
2232191762Simp		device_printf(sc->sc_dev, "can't create mbuf DMA tag\n");
2233191762Simp		return error;
2234191762Simp	}
2235191762Simp
2236191762Simp	ntx = 0;
2237191762Simp
2238191762Simp	/*
2239191762Simp	 * Create TX mbuf DMA map
2240191762Simp	 */
2241191762Simp	for (i = 0; i < BWI_TX_NRING; ++i) {
2242191762Simp		struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[i];
2243191762Simp
2244191762Simp		for (j = 0; j < BWI_TX_NDESC; ++j) {
2245191762Simp			error = bus_dmamap_create(sc->sc_buf_dtag, 0,
2246191762Simp						  &tbd->tbd_buf[j].tb_dmap);
2247191762Simp			if (error) {
2248191762Simp				device_printf(sc->sc_dev, "can't create "
2249191762Simp					      "%dth tbd, %dth DMA map\n", i, j);
2250191762Simp
2251191762Simp				ntx = i;
2252191762Simp				for (k = 0; k < j; ++k) {
2253191762Simp					bus_dmamap_destroy(sc->sc_buf_dtag,
2254191762Simp						tbd->tbd_buf[k].tb_dmap);
2255191762Simp				}
2256191762Simp				goto fail;
2257191762Simp			}
2258191762Simp		}
2259191762Simp	}
2260191762Simp	ntx = BWI_TX_NRING;
2261191762Simp
2262191762Simp	/*
2263191762Simp	 * Create RX mbuf DMA map and a spare DMA map
2264191762Simp	 */
2265191762Simp	error = bus_dmamap_create(sc->sc_buf_dtag, 0,
2266191762Simp				  &rbd->rbd_tmp_dmap);
2267191762Simp	if (error) {
2268191762Simp		device_printf(sc->sc_dev,
2269191762Simp			      "can't create spare RX buf DMA map\n");
2270191762Simp		goto fail;
2271191762Simp	}
2272191762Simp
2273191762Simp	for (j = 0; j < BWI_RX_NDESC; ++j) {
2274191762Simp		error = bus_dmamap_create(sc->sc_buf_dtag, 0,
2275191762Simp					  &rbd->rbd_buf[j].rb_dmap);
2276191762Simp		if (error) {
2277191762Simp			device_printf(sc->sc_dev, "can't create %dth "
2278191762Simp				      "RX buf DMA map\n", j);
2279191762Simp
2280191762Simp			for (k = 0; k < j; ++k) {
2281191762Simp				bus_dmamap_destroy(sc->sc_buf_dtag,
2282191762Simp					rbd->rbd_buf[j].rb_dmap);
2283191762Simp			}
2284191762Simp			bus_dmamap_destroy(sc->sc_buf_dtag,
2285191762Simp					   rbd->rbd_tmp_dmap);
2286191762Simp			goto fail;
2287191762Simp		}
2288191762Simp	}
2289191762Simp
2290191762Simp	return 0;
2291191762Simpfail:
2292191762Simp	bwi_dma_mbuf_destroy(sc, ntx, 0);
2293191762Simp	return error;
2294191762Simp}
2295191762Simp
2296191762Simpstatic void
2297191762Simpbwi_dma_mbuf_destroy(struct bwi_softc *sc, int ntx, int nrx)
2298191762Simp{
2299191762Simp	int i, j;
2300191762Simp
2301191762Simp	if (sc->sc_buf_dtag == NULL)
2302191762Simp		return;
2303191762Simp
2304191762Simp	for (i = 0; i < ntx; ++i) {
2305191762Simp		struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[i];
2306191762Simp
2307191762Simp		for (j = 0; j < BWI_TX_NDESC; ++j) {
2308191762Simp			struct bwi_txbuf *tb = &tbd->tbd_buf[j];
2309191762Simp
2310191762Simp			if (tb->tb_mbuf != NULL) {
2311191762Simp				bus_dmamap_unload(sc->sc_buf_dtag,
2312191762Simp						  tb->tb_dmap);
2313191762Simp				m_freem(tb->tb_mbuf);
2314191762Simp			}
2315191762Simp			if (tb->tb_ni != NULL)
2316191762Simp				ieee80211_free_node(tb->tb_ni);
2317191762Simp			bus_dmamap_destroy(sc->sc_buf_dtag, tb->tb_dmap);
2318191762Simp		}
2319191762Simp	}
2320191762Simp
2321191762Simp	if (nrx) {
2322191762Simp		struct bwi_rxbuf_data *rbd = &sc->sc_rx_bdata;
2323191762Simp
2324191762Simp		bus_dmamap_destroy(sc->sc_buf_dtag, rbd->rbd_tmp_dmap);
2325191762Simp		for (j = 0; j < BWI_RX_NDESC; ++j) {
2326191762Simp			struct bwi_rxbuf *rb = &rbd->rbd_buf[j];
2327191762Simp
2328191762Simp			if (rb->rb_mbuf != NULL) {
2329191762Simp				bus_dmamap_unload(sc->sc_buf_dtag,
2330191762Simp						  rb->rb_dmap);
2331191762Simp				m_freem(rb->rb_mbuf);
2332191762Simp			}
2333191762Simp			bus_dmamap_destroy(sc->sc_buf_dtag, rb->rb_dmap);
2334191762Simp		}
2335191762Simp	}
2336191762Simp
2337191762Simp	bus_dma_tag_destroy(sc->sc_buf_dtag);
2338191762Simp	sc->sc_buf_dtag = NULL;
2339191762Simp}
2340191762Simp
2341191762Simpstatic void
2342191762Simpbwi_enable_intrs(struct bwi_softc *sc, uint32_t enable_intrs)
2343191762Simp{
2344191762Simp	CSR_SETBITS_4(sc, BWI_MAC_INTR_MASK, enable_intrs);
2345191762Simp}
2346191762Simp
2347191762Simpstatic void
2348191762Simpbwi_disable_intrs(struct bwi_softc *sc, uint32_t disable_intrs)
2349191762Simp{
2350191762Simp	CSR_CLRBITS_4(sc, BWI_MAC_INTR_MASK, disable_intrs);
2351191762Simp}
2352191762Simp
2353191762Simpstatic int
2354191762Simpbwi_init_tx_ring32(struct bwi_softc *sc, int ring_idx)
2355191762Simp{
2356191762Simp	struct bwi_ring_data *rd;
2357191762Simp	struct bwi_txbuf_data *tbd;
2358191762Simp	uint32_t val, addr_hi, addr_lo;
2359191762Simp
2360191762Simp	KASSERT(ring_idx < BWI_TX_NRING, ("ring_idx %d", ring_idx));
2361191762Simp	rd = &sc->sc_tx_rdata[ring_idx];
2362191762Simp	tbd = &sc->sc_tx_bdata[ring_idx];
2363191762Simp
2364191762Simp	tbd->tbd_idx = 0;
2365191762Simp	tbd->tbd_used = 0;
2366191762Simp
2367191762Simp	bzero(rd->rdata_desc, sizeof(struct bwi_desc32) * BWI_TX_NDESC);
2368191762Simp	bus_dmamap_sync(sc->sc_txring_dtag, rd->rdata_dmap,
2369191762Simp			BUS_DMASYNC_PREWRITE);
2370191762Simp
2371191762Simp	addr_lo = __SHIFTOUT(rd->rdata_paddr, BWI_TXRX32_RINGINFO_ADDR_MASK);
2372191762Simp	addr_hi = __SHIFTOUT(rd->rdata_paddr, BWI_TXRX32_RINGINFO_FUNC_MASK);
2373191762Simp
2374191762Simp	val = __SHIFTIN(addr_lo, BWI_TXRX32_RINGINFO_ADDR_MASK) |
2375191762Simp	      __SHIFTIN(BWI_TXRX32_RINGINFO_FUNC_TXRX,
2376191762Simp	      		BWI_TXRX32_RINGINFO_FUNC_MASK);
2377191762Simp	CSR_WRITE_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_RINGINFO, val);
2378191762Simp
2379191762Simp	val = __SHIFTIN(addr_hi, BWI_TXRX32_CTRL_ADDRHI_MASK) |
2380191762Simp	      BWI_TXRX32_CTRL_ENABLE;
2381191762Simp	CSR_WRITE_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_CTRL, val);
2382191762Simp
2383191762Simp	return 0;
2384191762Simp}
2385191762Simp
2386191762Simpstatic void
2387191762Simpbwi_init_rxdesc_ring32(struct bwi_softc *sc, uint32_t ctrl_base,
2388191762Simp		       bus_addr_t paddr, int hdr_size, int ndesc)
2389191762Simp{
2390191762Simp	uint32_t val, addr_hi, addr_lo;
2391191762Simp
2392191762Simp	addr_lo = __SHIFTOUT(paddr, BWI_TXRX32_RINGINFO_ADDR_MASK);
2393191762Simp	addr_hi = __SHIFTOUT(paddr, BWI_TXRX32_RINGINFO_FUNC_MASK);
2394191762Simp
2395191762Simp	val = __SHIFTIN(addr_lo, BWI_TXRX32_RINGINFO_ADDR_MASK) |
2396191762Simp	      __SHIFTIN(BWI_TXRX32_RINGINFO_FUNC_TXRX,
2397191762Simp	      		BWI_TXRX32_RINGINFO_FUNC_MASK);
2398191762Simp	CSR_WRITE_4(sc, ctrl_base + BWI_RX32_RINGINFO, val);
2399191762Simp
2400191762Simp	val = __SHIFTIN(hdr_size, BWI_RX32_CTRL_HDRSZ_MASK) |
2401191762Simp	      __SHIFTIN(addr_hi, BWI_TXRX32_CTRL_ADDRHI_MASK) |
2402191762Simp	      BWI_TXRX32_CTRL_ENABLE;
2403191762Simp	CSR_WRITE_4(sc, ctrl_base + BWI_RX32_CTRL, val);
2404191762Simp
2405191762Simp	CSR_WRITE_4(sc, ctrl_base + BWI_RX32_INDEX,
2406191762Simp		    (ndesc - 1) * sizeof(struct bwi_desc32));
2407191762Simp}
2408191762Simp
2409191762Simpstatic int
2410191762Simpbwi_init_rx_ring32(struct bwi_softc *sc)
2411191762Simp{
2412191762Simp	struct bwi_ring_data *rd = &sc->sc_rx_rdata;
2413191762Simp	int i, error;
2414191762Simp
2415191762Simp	sc->sc_rx_bdata.rbd_idx = 0;
2416191762Simp
2417191762Simp	for (i = 0; i < BWI_RX_NDESC; ++i) {
2418191762Simp		error = bwi_newbuf(sc, i, 1);
2419191762Simp		if (error) {
2420191762Simp			device_printf(sc->sc_dev,
2421191762Simp				  "can't allocate %dth RX buffer\n", i);
2422191762Simp			return error;
2423191762Simp		}
2424191762Simp	}
2425191762Simp	bus_dmamap_sync(sc->sc_rxring_dtag, rd->rdata_dmap,
2426191762Simp			BUS_DMASYNC_PREWRITE);
2427191762Simp
2428191762Simp	bwi_init_rxdesc_ring32(sc, rd->rdata_txrx_ctrl, rd->rdata_paddr,
2429191762Simp			       sizeof(struct bwi_rxbuf_hdr), BWI_RX_NDESC);
2430191762Simp	return 0;
2431191762Simp}
2432191762Simp
2433191762Simpstatic int
2434191762Simpbwi_init_txstats32(struct bwi_softc *sc)
2435191762Simp{
2436191762Simp	struct bwi_txstats_data *st = sc->sc_txstats;
2437191762Simp	bus_addr_t stats_paddr;
2438191762Simp	int i;
2439191762Simp
2440191762Simp	bzero(st->stats, BWI_TXSTATS_NDESC * sizeof(struct bwi_txstats));
2441191762Simp	bus_dmamap_sync(st->stats_dtag, st->stats_dmap, BUS_DMASYNC_PREWRITE);
2442191762Simp
2443191762Simp	st->stats_idx = 0;
2444191762Simp
2445191762Simp	stats_paddr = st->stats_paddr;
2446191762Simp	for (i = 0; i < BWI_TXSTATS_NDESC; ++i) {
2447191762Simp		bwi_setup_desc32(sc, st->stats_ring, BWI_TXSTATS_NDESC, i,
2448191762Simp				 stats_paddr, sizeof(struct bwi_txstats), 0);
2449191762Simp		stats_paddr += sizeof(struct bwi_txstats);
2450191762Simp	}
2451191762Simp	bus_dmamap_sync(st->stats_ring_dtag, st->stats_ring_dmap,
2452191762Simp			BUS_DMASYNC_PREWRITE);
2453191762Simp
2454191762Simp	bwi_init_rxdesc_ring32(sc, st->stats_ctrl_base,
2455191762Simp			       st->stats_ring_paddr, 0, BWI_TXSTATS_NDESC);
2456191762Simp	return 0;
2457191762Simp}
2458191762Simp
2459191762Simpstatic void
2460191762Simpbwi_setup_rx_desc32(struct bwi_softc *sc, int buf_idx, bus_addr_t paddr,
2461191762Simp		    int buf_len)
2462191762Simp{
2463191762Simp	struct bwi_ring_data *rd = &sc->sc_rx_rdata;
2464191762Simp
2465191762Simp	KASSERT(buf_idx < BWI_RX_NDESC, ("buf_idx %d", buf_idx));
2466191762Simp	bwi_setup_desc32(sc, rd->rdata_desc, BWI_RX_NDESC, buf_idx,
2467191762Simp			 paddr, buf_len, 0);
2468191762Simp}
2469191762Simp
2470191762Simpstatic void
2471191762Simpbwi_setup_tx_desc32(struct bwi_softc *sc, struct bwi_ring_data *rd,
2472191762Simp		    int buf_idx, bus_addr_t paddr, int buf_len)
2473191762Simp{
2474191762Simp	KASSERT(buf_idx < BWI_TX_NDESC, ("buf_idx %d", buf_idx));
2475191762Simp	bwi_setup_desc32(sc, rd->rdata_desc, BWI_TX_NDESC, buf_idx,
2476191762Simp			 paddr, buf_len, 1);
2477191762Simp}
2478191762Simp
2479191762Simpstatic int
2480191762Simpbwi_init_tx_ring64(struct bwi_softc *sc, int ring_idx)
2481191762Simp{
2482191762Simp	/* TODO:64 */
2483191762Simp	return EOPNOTSUPP;
2484191762Simp}
2485191762Simp
2486191762Simpstatic int
2487191762Simpbwi_init_rx_ring64(struct bwi_softc *sc)
2488191762Simp{
2489191762Simp	/* TODO:64 */
2490191762Simp	return EOPNOTSUPP;
2491191762Simp}
2492191762Simp
2493191762Simpstatic int
2494191762Simpbwi_init_txstats64(struct bwi_softc *sc)
2495191762Simp{
2496191762Simp	/* TODO:64 */
2497191762Simp	return EOPNOTSUPP;
2498191762Simp}
2499191762Simp
2500191762Simpstatic void
2501191762Simpbwi_setup_rx_desc64(struct bwi_softc *sc, int buf_idx, bus_addr_t paddr,
2502191762Simp		    int buf_len)
2503191762Simp{
2504191762Simp	/* TODO:64 */
2505191762Simp}
2506191762Simp
2507191762Simpstatic void
2508191762Simpbwi_setup_tx_desc64(struct bwi_softc *sc, struct bwi_ring_data *rd,
2509191762Simp		    int buf_idx, bus_addr_t paddr, int buf_len)
2510191762Simp{
2511191762Simp	/* TODO:64 */
2512191762Simp}
2513191762Simp
2514191762Simpstatic void
2515191762Simpbwi_dma_buf_addr(void *arg, bus_dma_segment_t *seg, int nseg,
2516191762Simp		 bus_size_t mapsz __unused, int error)
2517191762Simp{
2518191762Simp        if (!error) {
2519191762Simp		KASSERT(nseg == 1, ("too many segments(%d)\n", nseg));
2520191762Simp		*((bus_addr_t *)arg) = seg->ds_addr;
2521191762Simp	}
2522191762Simp}
2523191762Simp
2524191762Simpstatic int
2525191762Simpbwi_newbuf(struct bwi_softc *sc, int buf_idx, int init)
2526191762Simp{
2527191762Simp	struct bwi_rxbuf_data *rbd = &sc->sc_rx_bdata;
2528191762Simp	struct bwi_rxbuf *rxbuf = &rbd->rbd_buf[buf_idx];
2529191762Simp	struct bwi_rxbuf_hdr *hdr;
2530191762Simp	bus_dmamap_t map;
2531191762Simp	bus_addr_t paddr;
2532191762Simp	struct mbuf *m;
2533191762Simp	int error;
2534191762Simp
2535191762Simp	KASSERT(buf_idx < BWI_RX_NDESC, ("buf_idx %d", buf_idx));
2536191762Simp
2537243857Sglebius	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
2538191762Simp	if (m == NULL) {
2539191762Simp		error = ENOBUFS;
2540191762Simp
2541191762Simp		/*
2542191762Simp		 * If the NIC is up and running, we need to:
2543191762Simp		 * - Clear RX buffer's header.
2544191762Simp		 * - Restore RX descriptor settings.
2545191762Simp		 */
2546191762Simp		if (init)
2547191762Simp			return error;
2548191762Simp		else
2549191762Simp			goto back;
2550191762Simp	}
2551191762Simp	m->m_len = m->m_pkthdr.len = MCLBYTES;
2552191762Simp
2553191762Simp	/*
2554191762Simp	 * Try to load RX buf into temporary DMA map
2555191762Simp	 */
2556191762Simp	error = bus_dmamap_load_mbuf(sc->sc_buf_dtag, rbd->rbd_tmp_dmap, m,
2557191762Simp				     bwi_dma_buf_addr, &paddr, BUS_DMA_NOWAIT);
2558191762Simp	if (error) {
2559191762Simp		m_freem(m);
2560191762Simp
2561191762Simp		/*
2562191762Simp		 * See the comment above
2563191762Simp		 */
2564191762Simp		if (init)
2565191762Simp			return error;
2566191762Simp		else
2567191762Simp			goto back;
2568191762Simp	}
2569191762Simp
2570191762Simp	if (!init)
2571191762Simp		bus_dmamap_unload(sc->sc_buf_dtag, rxbuf->rb_dmap);
2572191762Simp	rxbuf->rb_mbuf = m;
2573191762Simp	rxbuf->rb_paddr = paddr;
2574191762Simp
2575191762Simp	/*
2576191762Simp	 * Swap RX buf's DMA map with the loaded temporary one
2577191762Simp	 */
2578191762Simp	map = rxbuf->rb_dmap;
2579191762Simp	rxbuf->rb_dmap = rbd->rbd_tmp_dmap;
2580191762Simp	rbd->rbd_tmp_dmap = map;
2581191762Simp
2582191762Simpback:
2583191762Simp	/*
2584191762Simp	 * Clear RX buf header
2585191762Simp	 */
2586191762Simp	hdr = mtod(rxbuf->rb_mbuf, struct bwi_rxbuf_hdr *);
2587191762Simp	bzero(hdr, sizeof(*hdr));
2588191762Simp	bus_dmamap_sync(sc->sc_buf_dtag, rxbuf->rb_dmap, BUS_DMASYNC_PREWRITE);
2589191762Simp
2590191762Simp	/*
2591191762Simp	 * Setup RX buf descriptor
2592191762Simp	 */
2593191762Simp	sc->sc_setup_rxdesc(sc, buf_idx, rxbuf->rb_paddr,
2594191762Simp			    rxbuf->rb_mbuf->m_len - sizeof(*hdr));
2595191762Simp	return error;
2596191762Simp}
2597191762Simp
2598191762Simpstatic void
2599191762Simpbwi_set_addr_filter(struct bwi_softc *sc, uint16_t addr_ofs,
2600191762Simp		    const uint8_t *addr)
2601191762Simp{
2602191762Simp	int i;
2603191762Simp
2604191762Simp	CSR_WRITE_2(sc, BWI_ADDR_FILTER_CTRL,
2605191762Simp		    BWI_ADDR_FILTER_CTRL_SET | addr_ofs);
2606191762Simp
2607191762Simp	for (i = 0; i < (IEEE80211_ADDR_LEN / 2); ++i) {
2608191762Simp		uint16_t addr_val;
2609191762Simp
2610191762Simp		addr_val = (uint16_t)addr[i * 2] |
2611191762Simp			   (((uint16_t)addr[(i * 2) + 1]) << 8);
2612191762Simp		CSR_WRITE_2(sc, BWI_ADDR_FILTER_DATA, addr_val);
2613191762Simp	}
2614191762Simp}
2615191762Simp
2616191762Simpstatic int
2617191762Simpbwi_rxeof(struct bwi_softc *sc, int end_idx)
2618191762Simp{
2619191762Simp	struct bwi_ring_data *rd = &sc->sc_rx_rdata;
2620191762Simp	struct bwi_rxbuf_data *rbd = &sc->sc_rx_bdata;
2621191762Simp	struct ifnet *ifp = sc->sc_ifp;
2622191762Simp	struct ieee80211com *ic = ifp->if_l2com;
2623191762Simp	int idx, rx_data = 0;
2624191762Simp
2625191762Simp	idx = rbd->rbd_idx;
2626191762Simp	while (idx != end_idx) {
2627191762Simp		struct bwi_rxbuf *rb = &rbd->rbd_buf[idx];
2628191762Simp		struct bwi_rxbuf_hdr *hdr;
2629191762Simp		struct ieee80211_frame_min *wh;
2630191762Simp		struct ieee80211_node *ni;
2631191762Simp		struct mbuf *m;
2632225941Sadrian		uint32_t plcp;
2633191762Simp		uint16_t flags2;
2634191762Simp		int buflen, wh_ofs, hdr_extra, rssi, noise, type, rate;
2635191762Simp
2636191762Simp		m = rb->rb_mbuf;
2637191762Simp		bus_dmamap_sync(sc->sc_buf_dtag, rb->rb_dmap,
2638191762Simp				BUS_DMASYNC_POSTREAD);
2639191762Simp
2640191762Simp		if (bwi_newbuf(sc, idx, 0)) {
2641191762Simp			ifp->if_ierrors++;
2642191762Simp			goto next;
2643191762Simp		}
2644191762Simp
2645191762Simp		hdr = mtod(m, struct bwi_rxbuf_hdr *);
2646191762Simp		flags2 = le16toh(hdr->rxh_flags2);
2647191762Simp
2648191762Simp		hdr_extra = 0;
2649191762Simp		if (flags2 & BWI_RXH_F2_TYPE2FRAME)
2650191762Simp			hdr_extra = 2;
2651191762Simp		wh_ofs = hdr_extra + 6;	/* XXX magic number */
2652191762Simp
2653191762Simp		buflen = le16toh(hdr->rxh_buflen);
2654191762Simp		if (buflen < BWI_FRAME_MIN_LEN(wh_ofs)) {
2655191762Simp			if_printf(ifp, "%s: zero length data, hdr_extra %d\n",
2656191762Simp				  __func__, hdr_extra);
2657191762Simp			ifp->if_ierrors++;
2658191762Simp			m_freem(m);
2659191762Simp			goto next;
2660191762Simp		}
2661191762Simp
2662225941Sadrian	        bcopy((uint8_t *)(hdr + 1) + hdr_extra, &plcp, sizeof(plcp));
2663191762Simp		rssi = bwi_calc_rssi(sc, hdr);
2664191762Simp		noise = bwi_calc_noise(sc);
2665191762Simp
2666191762Simp		m->m_pkthdr.rcvif = ifp;
2667191762Simp		m->m_len = m->m_pkthdr.len = buflen + sizeof(*hdr);
2668191762Simp		m_adj(m, sizeof(*hdr) + wh_ofs);
2669191762Simp
2670191762Simp		if (htole16(hdr->rxh_flags1) & BWI_RXH_F1_OFDM)
2671228621Sbschmidt			rate = bwi_plcp2rate(plcp, IEEE80211_T_OFDM);
2672191762Simp		else
2673228621Sbschmidt			rate = bwi_plcp2rate(plcp, IEEE80211_T_CCK);
2674191762Simp
2675191762Simp		/* RX radio tap */
2676192468Ssam		if (ieee80211_radiotap_active(ic))
2677225941Sadrian			bwi_rx_radiotap(sc, m, hdr, &plcp, rate, rssi, noise);
2678191762Simp
2679191762Simp		m_adj(m, -IEEE80211_CRC_LEN);
2680191762Simp
2681191762Simp		BWI_UNLOCK(sc);
2682191762Simp
2683191762Simp		wh = mtod(m, struct ieee80211_frame_min *);
2684191762Simp		ni = ieee80211_find_rxnode(ic, wh);
2685191762Simp		if (ni != NULL) {
2686192468Ssam			type = ieee80211_input(ni, m, rssi - noise, noise);
2687191762Simp			ieee80211_free_node(ni);
2688191762Simp		} else
2689192468Ssam			type = ieee80211_input_all(ic, m, rssi - noise, noise);
2690191762Simp		if (type == IEEE80211_FC0_TYPE_DATA) {
2691191762Simp			rx_data = 1;
2692191762Simp			sc->sc_rx_rate = rate;
2693191762Simp		}
2694191762Simp
2695191762Simp		BWI_LOCK(sc);
2696191762Simpnext:
2697191762Simp		idx = (idx + 1) % BWI_RX_NDESC;
2698191762Simp
2699191762Simp		if (sc->sc_flags & BWI_F_STOP) {
2700191762Simp			/*
2701191762Simp			 * Take the fast lane, don't do
2702191762Simp			 * any damage to softc
2703191762Simp			 */
2704191762Simp			return -1;
2705191762Simp		}
2706191762Simp	}
2707191762Simp
2708191762Simp	rbd->rbd_idx = idx;
2709191762Simp	bus_dmamap_sync(sc->sc_rxring_dtag, rd->rdata_dmap,
2710191762Simp			BUS_DMASYNC_PREWRITE);
2711191762Simp
2712191762Simp	return rx_data;
2713191762Simp}
2714191762Simp
2715191762Simpstatic int
2716191762Simpbwi_rxeof32(struct bwi_softc *sc)
2717191762Simp{
2718191762Simp	uint32_t val, rx_ctrl;
2719191762Simp	int end_idx, rx_data;
2720191762Simp
2721191762Simp	rx_ctrl = sc->sc_rx_rdata.rdata_txrx_ctrl;
2722191762Simp
2723191762Simp	val = CSR_READ_4(sc, rx_ctrl + BWI_RX32_STATUS);
2724191762Simp	end_idx = __SHIFTOUT(val, BWI_RX32_STATUS_INDEX_MASK) /
2725191762Simp		  sizeof(struct bwi_desc32);
2726191762Simp
2727191762Simp	rx_data = bwi_rxeof(sc, end_idx);
2728191762Simp	if (rx_data >= 0) {
2729191762Simp		CSR_WRITE_4(sc, rx_ctrl + BWI_RX32_INDEX,
2730191762Simp			    end_idx * sizeof(struct bwi_desc32));
2731191762Simp	}
2732191762Simp	return rx_data;
2733191762Simp}
2734191762Simp
2735191762Simpstatic int
2736191762Simpbwi_rxeof64(struct bwi_softc *sc)
2737191762Simp{
2738191762Simp	/* TODO:64 */
2739191762Simp	return 0;
2740191762Simp}
2741191762Simp
2742191762Simpstatic void
2743191762Simpbwi_reset_rx_ring32(struct bwi_softc *sc, uint32_t rx_ctrl)
2744191762Simp{
2745191762Simp	int i;
2746191762Simp
2747191762Simp	CSR_WRITE_4(sc, rx_ctrl + BWI_RX32_CTRL, 0);
2748191762Simp
2749191762Simp#define NRETRY 10
2750191762Simp
2751191762Simp	for (i = 0; i < NRETRY; ++i) {
2752191762Simp		uint32_t status;
2753191762Simp
2754191762Simp		status = CSR_READ_4(sc, rx_ctrl + BWI_RX32_STATUS);
2755191762Simp		if (__SHIFTOUT(status, BWI_RX32_STATUS_STATE_MASK) ==
2756191762Simp		    BWI_RX32_STATUS_STATE_DISABLED)
2757191762Simp			break;
2758191762Simp
2759191762Simp		DELAY(1000);
2760191762Simp	}
2761191762Simp	if (i == NRETRY)
2762191762Simp		device_printf(sc->sc_dev, "reset rx ring timedout\n");
2763191762Simp
2764191762Simp#undef NRETRY
2765191762Simp
2766191762Simp	CSR_WRITE_4(sc, rx_ctrl + BWI_RX32_RINGINFO, 0);
2767191762Simp}
2768191762Simp
2769191762Simpstatic void
2770191762Simpbwi_free_txstats32(struct bwi_softc *sc)
2771191762Simp{
2772191762Simp	bwi_reset_rx_ring32(sc, sc->sc_txstats->stats_ctrl_base);
2773191762Simp}
2774191762Simp
2775191762Simpstatic void
2776191762Simpbwi_free_rx_ring32(struct bwi_softc *sc)
2777191762Simp{
2778191762Simp	struct bwi_ring_data *rd = &sc->sc_rx_rdata;
2779191762Simp	struct bwi_rxbuf_data *rbd = &sc->sc_rx_bdata;
2780191762Simp	int i;
2781191762Simp
2782191762Simp	bwi_reset_rx_ring32(sc, rd->rdata_txrx_ctrl);
2783191762Simp
2784191762Simp	for (i = 0; i < BWI_RX_NDESC; ++i) {
2785191762Simp		struct bwi_rxbuf *rb = &rbd->rbd_buf[i];
2786191762Simp
2787191762Simp		if (rb->rb_mbuf != NULL) {
2788191762Simp			bus_dmamap_unload(sc->sc_buf_dtag, rb->rb_dmap);
2789191762Simp			m_freem(rb->rb_mbuf);
2790191762Simp			rb->rb_mbuf = NULL;
2791191762Simp		}
2792191762Simp	}
2793191762Simp}
2794191762Simp
2795191762Simpstatic void
2796191762Simpbwi_free_tx_ring32(struct bwi_softc *sc, int ring_idx)
2797191762Simp{
2798191762Simp	struct bwi_ring_data *rd;
2799191762Simp	struct bwi_txbuf_data *tbd;
2800191762Simp	struct ifnet *ifp = sc->sc_ifp;
2801191762Simp	uint32_t state, val;
2802191762Simp	int i;
2803191762Simp
2804191762Simp	KASSERT(ring_idx < BWI_TX_NRING, ("ring_idx %d", ring_idx));
2805191762Simp	rd = &sc->sc_tx_rdata[ring_idx];
2806191762Simp	tbd = &sc->sc_tx_bdata[ring_idx];
2807191762Simp
2808191762Simp#define NRETRY 10
2809191762Simp
2810191762Simp	for (i = 0; i < NRETRY; ++i) {
2811191762Simp		val = CSR_READ_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_STATUS);
2812191762Simp		state = __SHIFTOUT(val, BWI_TX32_STATUS_STATE_MASK);
2813191762Simp		if (state == BWI_TX32_STATUS_STATE_DISABLED ||
2814191762Simp		    state == BWI_TX32_STATUS_STATE_IDLE ||
2815191762Simp		    state == BWI_TX32_STATUS_STATE_STOPPED)
2816191762Simp			break;
2817191762Simp
2818191762Simp		DELAY(1000);
2819191762Simp	}
2820191762Simp	if (i == NRETRY) {
2821191762Simp		if_printf(ifp, "%s: wait for TX ring(%d) stable timed out\n",
2822191762Simp			  __func__, ring_idx);
2823191762Simp	}
2824191762Simp
2825191762Simp	CSR_WRITE_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_CTRL, 0);
2826191762Simp	for (i = 0; i < NRETRY; ++i) {
2827191762Simp		val = CSR_READ_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_STATUS);
2828191762Simp		state = __SHIFTOUT(val, BWI_TX32_STATUS_STATE_MASK);
2829191762Simp		if (state == BWI_TX32_STATUS_STATE_DISABLED)
2830191762Simp			break;
2831191762Simp
2832191762Simp		DELAY(1000);
2833191762Simp	}
2834191762Simp	if (i == NRETRY)
2835191762Simp		if_printf(ifp, "%s: reset TX ring (%d) timed out\n",
2836191762Simp		     __func__, ring_idx);
2837191762Simp
2838191762Simp#undef NRETRY
2839191762Simp
2840191762Simp	DELAY(1000);
2841191762Simp
2842191762Simp	CSR_WRITE_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_RINGINFO, 0);
2843191762Simp
2844191762Simp	for (i = 0; i < BWI_TX_NDESC; ++i) {
2845191762Simp		struct bwi_txbuf *tb = &tbd->tbd_buf[i];
2846191762Simp
2847191762Simp		if (tb->tb_mbuf != NULL) {
2848191762Simp			bus_dmamap_unload(sc->sc_buf_dtag, tb->tb_dmap);
2849191762Simp			m_freem(tb->tb_mbuf);
2850191762Simp			tb->tb_mbuf = NULL;
2851191762Simp		}
2852191762Simp		if (tb->tb_ni != NULL) {
2853191762Simp			ieee80211_free_node(tb->tb_ni);
2854191762Simp			tb->tb_ni = NULL;
2855191762Simp		}
2856191762Simp	}
2857191762Simp}
2858191762Simp
2859191762Simpstatic void
2860191762Simpbwi_free_txstats64(struct bwi_softc *sc)
2861191762Simp{
2862191762Simp	/* TODO:64 */
2863191762Simp}
2864191762Simp
2865191762Simpstatic void
2866191762Simpbwi_free_rx_ring64(struct bwi_softc *sc)
2867191762Simp{
2868191762Simp	/* TODO:64 */
2869191762Simp}
2870191762Simp
2871191762Simpstatic void
2872191762Simpbwi_free_tx_ring64(struct bwi_softc *sc, int ring_idx)
2873191762Simp{
2874191762Simp	/* TODO:64 */
2875191762Simp}
2876191762Simp
2877191762Simp/* XXX does not belong here */
2878191762Simp#define IEEE80211_OFDM_PLCP_RATE_MASK	__BITS(3, 0)
2879191762Simp#define IEEE80211_OFDM_PLCP_LEN_MASK	__BITS(16, 5)
2880191762Simp
2881191762Simpstatic __inline void
2882191762Simpbwi_ofdm_plcp_header(uint32_t *plcp0, int pkt_len, uint8_t rate)
2883191762Simp{
2884191762Simp	uint32_t plcp;
2885191762Simp
2886191762Simp	plcp = __SHIFTIN(ieee80211_rate2plcp(rate, IEEE80211_T_OFDM),
2887191762Simp		    IEEE80211_OFDM_PLCP_RATE_MASK) |
2888191762Simp	       __SHIFTIN(pkt_len, IEEE80211_OFDM_PLCP_LEN_MASK);
2889191762Simp	*plcp0 = htole32(plcp);
2890191762Simp}
2891191762Simp
2892191762Simpstatic __inline void
2893191762Simpbwi_ds_plcp_header(struct ieee80211_ds_plcp_hdr *plcp, int pkt_len,
2894191762Simp		   uint8_t rate)
2895191762Simp{
2896191762Simp	int len, service, pkt_bitlen;
2897191762Simp
2898191762Simp	pkt_bitlen = pkt_len * NBBY;
2899191762Simp	len = howmany(pkt_bitlen * 2, rate);
2900191762Simp
2901191762Simp	service = IEEE80211_PLCP_SERVICE_LOCKED;
2902191762Simp	if (rate == (11 * 2)) {
2903191762Simp		int pkt_bitlen1;
2904191762Simp
2905191762Simp		/*
2906191762Simp		 * PLCP service field needs to be adjusted,
2907191762Simp		 * if TX rate is 11Mbytes/s
2908191762Simp		 */
2909191762Simp		pkt_bitlen1 = len * 11;
2910191762Simp		if (pkt_bitlen1 - pkt_bitlen >= NBBY)
2911191762Simp			service |= IEEE80211_PLCP_SERVICE_LENEXT7;
2912191762Simp	}
2913191762Simp
2914191762Simp	plcp->i_signal = ieee80211_rate2plcp(rate, IEEE80211_T_CCK);
2915191762Simp	plcp->i_service = service;
2916191762Simp	plcp->i_length = htole16(len);
2917191762Simp	/* NOTE: do NOT touch i_crc */
2918191762Simp}
2919191762Simp
2920191762Simpstatic __inline void
2921191762Simpbwi_plcp_header(const struct ieee80211_rate_table *rt,
2922191762Simp	void *plcp, int pkt_len, uint8_t rate)
2923191762Simp{
2924191762Simp	enum ieee80211_phytype modtype;
2925191762Simp
2926191762Simp	/*
2927191762Simp	 * Assume caller has zeroed 'plcp'
2928191762Simp	 */
2929191762Simp	modtype = ieee80211_rate2phytype(rt, rate);
2930191762Simp	if (modtype == IEEE80211_T_OFDM)
2931191762Simp		bwi_ofdm_plcp_header(plcp, pkt_len, rate);
2932191762Simp	else if (modtype == IEEE80211_T_DS)
2933191762Simp		bwi_ds_plcp_header(plcp, pkt_len, rate);
2934191762Simp	else
2935191762Simp		panic("unsupport modulation type %u\n", modtype);
2936191762Simp}
2937191762Simp
2938191762Simpstatic int
2939191762Simpbwi_encap(struct bwi_softc *sc, int idx, struct mbuf *m,
2940191762Simp	  struct ieee80211_node *ni)
2941191762Simp{
2942191762Simp	struct ieee80211vap *vap = ni->ni_vap;
2943191762Simp	struct ifnet *ifp = sc->sc_ifp;
2944191762Simp	struct ieee80211com *ic = ifp->if_l2com;
2945191762Simp	struct bwi_ring_data *rd = &sc->sc_tx_rdata[BWI_TX_DATA_RING];
2946191762Simp	struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[BWI_TX_DATA_RING];
2947191762Simp	struct bwi_txbuf *tb = &tbd->tbd_buf[idx];
2948191762Simp	struct bwi_mac *mac;
2949191762Simp	struct bwi_txbuf_hdr *hdr;
2950191762Simp	struct ieee80211_frame *wh;
2951191762Simp	const struct ieee80211_txparam *tp;
2952191762Simp	uint8_t rate, rate_fb;
2953191762Simp	uint32_t mac_ctrl;
2954191762Simp	uint16_t phy_ctrl;
2955191762Simp	bus_addr_t paddr;
2956191762Simp	int type, ismcast, pkt_len, error, rix;
2957191762Simp#if 0
2958191762Simp	const uint8_t *p;
2959191762Simp	int i;
2960191762Simp#endif
2961191762Simp
2962191762Simp	KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC,
2963191762Simp	    ("current regwin type %d", sc->sc_cur_regwin->rw_type));
2964191762Simp	mac = (struct bwi_mac *)sc->sc_cur_regwin;
2965191762Simp
2966191762Simp	wh = mtod(m, struct ieee80211_frame *);
2967191762Simp	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
2968191762Simp	ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
2969191762Simp
2970191762Simp	/* Get 802.11 frame len before prepending TX header */
2971191762Simp	pkt_len = m->m_pkthdr.len + IEEE80211_CRC_LEN;
2972191762Simp
2973191762Simp	/*
2974191762Simp	 * Find TX rate
2975191762Simp	 */
2976191762Simp	tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
2977191762Simp	if (type != IEEE80211_FC0_TYPE_DATA || (m->m_flags & M_EAPOL)) {
2978191762Simp		rate = rate_fb = tp->mgmtrate;
2979191762Simp	} else if (ismcast) {
2980191762Simp		rate = rate_fb = tp->mcastrate;
2981191762Simp	} else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) {
2982191762Simp		rate = rate_fb = tp->ucastrate;
2983191762Simp	} else {
2984206358Srpaulo		rix = ieee80211_ratectl_rate(ni, NULL, pkt_len);
2985191762Simp		rate = ni->ni_txrate;
2986191762Simp
2987191762Simp		if (rix > 0) {
2988191762Simp			rate_fb = ni->ni_rates.rs_rates[rix-1] &
2989191762Simp				  IEEE80211_RATE_VAL;
2990191762Simp		} else {
2991191762Simp			rate_fb = rate;
2992191762Simp		}
2993191762Simp	}
2994191762Simp	tb->tb_rate[0] = rate;
2995191762Simp	tb->tb_rate[1] = rate_fb;
2996191762Simp	sc->sc_tx_rate = rate;
2997191762Simp
2998191762Simp	/*
2999191762Simp	 * TX radio tap
3000191762Simp	 */
3001192468Ssam	if (ieee80211_radiotap_active_vap(vap)) {
3002191762Simp		sc->sc_tx_th.wt_flags = 0;
3003262007Skevlo		if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED)
3004191762Simp			sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP;
3005191762Simp		if (ieee80211_rate2phytype(sc->sc_rates, rate) == IEEE80211_T_DS &&
3006191762Simp		    (ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
3007191762Simp		    rate != (1 * 2)) {
3008191762Simp			sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
3009191762Simp		}
3010191762Simp		sc->sc_tx_th.wt_rate = rate;
3011191762Simp
3012192468Ssam		ieee80211_radiotap_tx(vap, m);
3013191762Simp	}
3014191762Simp
3015191762Simp	/*
3016191762Simp	 * Setup the embedded TX header
3017191762Simp	 */
3018243857Sglebius	M_PREPEND(m, sizeof(*hdr), M_NOWAIT);
3019191762Simp	if (m == NULL) {
3020191762Simp		if_printf(ifp, "%s: prepend TX header failed\n", __func__);
3021191762Simp		return ENOBUFS;
3022191762Simp	}
3023191762Simp	hdr = mtod(m, struct bwi_txbuf_hdr *);
3024191762Simp
3025191762Simp	bzero(hdr, sizeof(*hdr));
3026191762Simp
3027191762Simp	bcopy(wh->i_fc, hdr->txh_fc, sizeof(hdr->txh_fc));
3028191762Simp	bcopy(wh->i_addr1, hdr->txh_addr1, sizeof(hdr->txh_addr1));
3029191762Simp
3030191762Simp	if (!ismcast) {
3031191762Simp		uint16_t dur;
3032191762Simp
3033191762Simp		dur = ieee80211_ack_duration(sc->sc_rates, rate,
3034191762Simp		    ic->ic_flags & ~IEEE80211_F_SHPREAMBLE);
3035191762Simp
3036191762Simp		hdr->txh_fb_duration = htole16(dur);
3037191762Simp	}
3038191762Simp
3039191762Simp	hdr->txh_id = __SHIFTIN(BWI_TX_DATA_RING, BWI_TXH_ID_RING_MASK) |
3040191762Simp		      __SHIFTIN(idx, BWI_TXH_ID_IDX_MASK);
3041191762Simp
3042191762Simp	bwi_plcp_header(sc->sc_rates, hdr->txh_plcp, pkt_len, rate);
3043191762Simp	bwi_plcp_header(sc->sc_rates, hdr->txh_fb_plcp, pkt_len, rate_fb);
3044191762Simp
3045191762Simp	phy_ctrl = __SHIFTIN(mac->mac_rf.rf_ant_mode,
3046191762Simp			     BWI_TXH_PHY_C_ANTMODE_MASK);
3047191762Simp	if (ieee80211_rate2phytype(sc->sc_rates, rate) == IEEE80211_T_OFDM)
3048191762Simp		phy_ctrl |= BWI_TXH_PHY_C_OFDM;
3049191762Simp	else if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && rate != (2 * 1))
3050191762Simp		phy_ctrl |= BWI_TXH_PHY_C_SHPREAMBLE;
3051191762Simp
3052191762Simp	mac_ctrl = BWI_TXH_MAC_C_HWSEQ | BWI_TXH_MAC_C_FIRST_FRAG;
3053191762Simp	if (!ismcast)
3054191762Simp		mac_ctrl |= BWI_TXH_MAC_C_ACK;
3055191762Simp	if (ieee80211_rate2phytype(sc->sc_rates, rate_fb) == IEEE80211_T_OFDM)
3056191762Simp		mac_ctrl |= BWI_TXH_MAC_C_FB_OFDM;
3057191762Simp
3058191762Simp	hdr->txh_mac_ctrl = htole32(mac_ctrl);
3059191762Simp	hdr->txh_phy_ctrl = htole16(phy_ctrl);
3060191762Simp
3061191762Simp	/* Catch any further usage */
3062191762Simp	hdr = NULL;
3063191762Simp	wh = NULL;
3064191762Simp
3065191762Simp	/* DMA load */
3066191762Simp	error = bus_dmamap_load_mbuf(sc->sc_buf_dtag, tb->tb_dmap, m,
3067191762Simp				     bwi_dma_buf_addr, &paddr, BUS_DMA_NOWAIT);
3068191762Simp	if (error && error != EFBIG) {
3069191762Simp		if_printf(ifp, "%s: can't load TX buffer (1) %d\n",
3070191762Simp		    __func__, error);
3071191762Simp		goto back;
3072191762Simp	}
3073191762Simp
3074191762Simp	if (error) {	/* error == EFBIG */
3075191762Simp		struct mbuf *m_new;
3076191762Simp
3077243857Sglebius		m_new = m_defrag(m, M_NOWAIT);
3078191762Simp		if (m_new == NULL) {
3079191762Simp			if_printf(ifp, "%s: can't defrag TX buffer\n",
3080191762Simp			    __func__);
3081191762Simp			error = ENOBUFS;
3082191762Simp			goto back;
3083191762Simp		} else {
3084191762Simp			m = m_new;
3085191762Simp		}
3086191762Simp
3087191762Simp		error = bus_dmamap_load_mbuf(sc->sc_buf_dtag, tb->tb_dmap, m,
3088191762Simp					     bwi_dma_buf_addr, &paddr,
3089191762Simp					     BUS_DMA_NOWAIT);
3090191762Simp		if (error) {
3091191762Simp			if_printf(ifp, "%s: can't load TX buffer (2) %d\n",
3092191762Simp			    __func__, error);
3093191762Simp			goto back;
3094191762Simp		}
3095191762Simp	}
3096191762Simp	error = 0;
3097191762Simp
3098191762Simp	bus_dmamap_sync(sc->sc_buf_dtag, tb->tb_dmap, BUS_DMASYNC_PREWRITE);
3099191762Simp
3100191762Simp	tb->tb_mbuf = m;
3101191762Simp	tb->tb_ni = ni;
3102191762Simp
3103191762Simp#if 0
3104191762Simp	p = mtod(m, const uint8_t *);
3105191762Simp	for (i = 0; i < m->m_pkthdr.len; ++i) {
3106191762Simp		if (i != 0 && i % 8 == 0)
3107191762Simp			printf("\n");
3108191762Simp		printf("%02x ", p[i]);
3109191762Simp	}
3110191762Simp	printf("\n");
3111191762Simp#endif
3112191762Simp	DPRINTF(sc, BWI_DBG_TX, "idx %d, pkt_len %d, buflen %d\n",
3113191762Simp		idx, pkt_len, m->m_pkthdr.len);
3114191762Simp
3115191762Simp	/* Setup TX descriptor */
3116191762Simp	sc->sc_setup_txdesc(sc, rd, idx, paddr, m->m_pkthdr.len);
3117191762Simp	bus_dmamap_sync(sc->sc_txring_dtag, rd->rdata_dmap,
3118191762Simp			BUS_DMASYNC_PREWRITE);
3119191762Simp
3120191762Simp	/* Kick start */
3121191762Simp	sc->sc_start_tx(sc, rd->rdata_txrx_ctrl, idx);
3122191762Simp
3123191762Simpback:
3124191762Simp	if (error)
3125191762Simp		m_freem(m);
3126191762Simp	return error;
3127191762Simp}
3128191762Simp
3129191762Simpstatic int
3130191762Simpbwi_encap_raw(struct bwi_softc *sc, int idx, struct mbuf *m,
3131191762Simp	  struct ieee80211_node *ni, const struct ieee80211_bpf_params *params)
3132191762Simp{
3133191762Simp	struct ifnet *ifp = sc->sc_ifp;
3134192468Ssam	struct ieee80211vap *vap = ni->ni_vap;
3135193073Ssam	struct ieee80211com *ic = ni->ni_ic;
3136191762Simp	struct bwi_ring_data *rd = &sc->sc_tx_rdata[BWI_TX_DATA_RING];
3137191762Simp	struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[BWI_TX_DATA_RING];
3138191762Simp	struct bwi_txbuf *tb = &tbd->tbd_buf[idx];
3139191762Simp	struct bwi_mac *mac;
3140191762Simp	struct bwi_txbuf_hdr *hdr;
3141191762Simp	struct ieee80211_frame *wh;
3142191762Simp	uint8_t rate, rate_fb;
3143191762Simp	uint32_t mac_ctrl;
3144191762Simp	uint16_t phy_ctrl;
3145191762Simp	bus_addr_t paddr;
3146191762Simp	int ismcast, pkt_len, error;
3147191762Simp
3148191762Simp	KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC,
3149191762Simp	    ("current regwin type %d", sc->sc_cur_regwin->rw_type));
3150191762Simp	mac = (struct bwi_mac *)sc->sc_cur_regwin;
3151191762Simp
3152191762Simp	wh = mtod(m, struct ieee80211_frame *);
3153191762Simp	ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
3154191762Simp
3155191762Simp	/* Get 802.11 frame len before prepending TX header */
3156191762Simp	pkt_len = m->m_pkthdr.len + IEEE80211_CRC_LEN;
3157191762Simp
3158191762Simp	/*
3159191762Simp	 * Find TX rate
3160191762Simp	 */
3161191762Simp	rate = params->ibp_rate0;
3162193073Ssam	if (!ieee80211_isratevalid(ic->ic_rt, rate)) {
3163193073Ssam		/* XXX fall back to mcast/mgmt rate? */
3164193079Ssam		m_freem(m);
3165193073Ssam		return EINVAL;
3166193073Ssam	}
3167193073Ssam	if (params->ibp_try1 != 0) {
3168193073Ssam		rate_fb = params->ibp_rate1;
3169193073Ssam		if (!ieee80211_isratevalid(ic->ic_rt, rate_fb)) {
3170193073Ssam			/* XXX fall back to rate0? */
3171193079Ssam			m_freem(m);
3172193073Ssam			return EINVAL;
3173193073Ssam		}
3174193073Ssam	} else
3175193073Ssam		rate_fb = rate;
3176191762Simp	tb->tb_rate[0] = rate;
3177191762Simp	tb->tb_rate[1] = rate_fb;
3178191762Simp	sc->sc_tx_rate = rate;
3179191762Simp
3180191762Simp	/*
3181191762Simp	 * TX radio tap
3182191762Simp	 */
3183192468Ssam	if (ieee80211_radiotap_active_vap(vap)) {
3184191762Simp		sc->sc_tx_th.wt_flags = 0;
3185191762Simp		/* XXX IEEE80211_BPF_CRYPTO */
3186262007Skevlo		if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED)
3187191762Simp			sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP;
3188191762Simp		if (params->ibp_flags & IEEE80211_BPF_SHORTPRE)
3189191762Simp			sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
3190191762Simp		sc->sc_tx_th.wt_rate = rate;
3191191762Simp
3192192468Ssam		ieee80211_radiotap_tx(vap, m);
3193191762Simp	}
3194191762Simp
3195191762Simp	/*
3196191762Simp	 * Setup the embedded TX header
3197191762Simp	 */
3198243857Sglebius	M_PREPEND(m, sizeof(*hdr), M_NOWAIT);
3199191762Simp	if (m == NULL) {
3200191762Simp		if_printf(ifp, "%s: prepend TX header failed\n", __func__);
3201191762Simp		return ENOBUFS;
3202191762Simp	}
3203191762Simp	hdr = mtod(m, struct bwi_txbuf_hdr *);
3204191762Simp
3205191762Simp	bzero(hdr, sizeof(*hdr));
3206191762Simp
3207191762Simp	bcopy(wh->i_fc, hdr->txh_fc, sizeof(hdr->txh_fc));
3208191762Simp	bcopy(wh->i_addr1, hdr->txh_addr1, sizeof(hdr->txh_addr1));
3209191762Simp
3210191762Simp	mac_ctrl = BWI_TXH_MAC_C_HWSEQ | BWI_TXH_MAC_C_FIRST_FRAG;
3211191762Simp	if (!ismcast && (params->ibp_flags & IEEE80211_BPF_NOACK) == 0) {
3212191762Simp		uint16_t dur;
3213191762Simp
3214191762Simp		dur = ieee80211_ack_duration(sc->sc_rates, rate_fb, 0);
3215191762Simp
3216191762Simp		hdr->txh_fb_duration = htole16(dur);
3217191762Simp		mac_ctrl |= BWI_TXH_MAC_C_ACK;
3218191762Simp	}
3219191762Simp
3220191762Simp	hdr->txh_id = __SHIFTIN(BWI_TX_DATA_RING, BWI_TXH_ID_RING_MASK) |
3221191762Simp		      __SHIFTIN(idx, BWI_TXH_ID_IDX_MASK);
3222191762Simp
3223191762Simp	bwi_plcp_header(sc->sc_rates, hdr->txh_plcp, pkt_len, rate);
3224191762Simp	bwi_plcp_header(sc->sc_rates, hdr->txh_fb_plcp, pkt_len, rate_fb);
3225191762Simp
3226191762Simp	phy_ctrl = __SHIFTIN(mac->mac_rf.rf_ant_mode,
3227191762Simp			     BWI_TXH_PHY_C_ANTMODE_MASK);
3228191762Simp	if (ieee80211_rate2phytype(sc->sc_rates, rate) == IEEE80211_T_OFDM) {
3229191762Simp		phy_ctrl |= BWI_TXH_PHY_C_OFDM;
3230191762Simp		mac_ctrl |= BWI_TXH_MAC_C_FB_OFDM;
3231191762Simp	} else if (params->ibp_flags & IEEE80211_BPF_SHORTPRE)
3232191762Simp		phy_ctrl |= BWI_TXH_PHY_C_SHPREAMBLE;
3233191762Simp
3234191762Simp	hdr->txh_mac_ctrl = htole32(mac_ctrl);
3235191762Simp	hdr->txh_phy_ctrl = htole16(phy_ctrl);
3236191762Simp
3237191762Simp	/* Catch any further usage */
3238191762Simp	hdr = NULL;
3239191762Simp	wh = NULL;
3240191762Simp
3241191762Simp	/* DMA load */
3242191762Simp	error = bus_dmamap_load_mbuf(sc->sc_buf_dtag, tb->tb_dmap, m,
3243191762Simp				     bwi_dma_buf_addr, &paddr, BUS_DMA_NOWAIT);
3244191762Simp	if (error != 0) {
3245191762Simp		struct mbuf *m_new;
3246191762Simp
3247191762Simp		if (error != EFBIG) {
3248191762Simp			if_printf(ifp, "%s: can't load TX buffer (1) %d\n",
3249191762Simp			    __func__, error);
3250191762Simp			goto back;
3251191762Simp		}
3252243857Sglebius		m_new = m_defrag(m, M_NOWAIT);
3253191762Simp		if (m_new == NULL) {
3254191762Simp			if_printf(ifp, "%s: can't defrag TX buffer\n",
3255191762Simp			    __func__);
3256191762Simp			error = ENOBUFS;
3257191762Simp			goto back;
3258191762Simp		}
3259191762Simp		m = m_new;
3260191762Simp		error = bus_dmamap_load_mbuf(sc->sc_buf_dtag, tb->tb_dmap, m,
3261191762Simp					     bwi_dma_buf_addr, &paddr,
3262191762Simp					     BUS_DMA_NOWAIT);
3263191762Simp		if (error) {
3264191762Simp			if_printf(ifp, "%s: can't load TX buffer (2) %d\n",
3265191762Simp			    __func__, error);
3266191762Simp			goto back;
3267191762Simp		}
3268191762Simp	}
3269191762Simp
3270191762Simp	bus_dmamap_sync(sc->sc_buf_dtag, tb->tb_dmap, BUS_DMASYNC_PREWRITE);
3271191762Simp
3272191762Simp	tb->tb_mbuf = m;
3273191762Simp	tb->tb_ni = ni;
3274191762Simp
3275191762Simp	DPRINTF(sc, BWI_DBG_TX, "idx %d, pkt_len %d, buflen %d\n",
3276191762Simp		idx, pkt_len, m->m_pkthdr.len);
3277191762Simp
3278191762Simp	/* Setup TX descriptor */
3279191762Simp	sc->sc_setup_txdesc(sc, rd, idx, paddr, m->m_pkthdr.len);
3280191762Simp	bus_dmamap_sync(sc->sc_txring_dtag, rd->rdata_dmap,
3281191762Simp			BUS_DMASYNC_PREWRITE);
3282191762Simp
3283191762Simp	/* Kick start */
3284191762Simp	sc->sc_start_tx(sc, rd->rdata_txrx_ctrl, idx);
3285191762Simpback:
3286191762Simp	if (error)
3287191762Simp		m_freem(m);
3288191762Simp	return error;
3289191762Simp}
3290191762Simp
3291191762Simpstatic void
3292191762Simpbwi_start_tx32(struct bwi_softc *sc, uint32_t tx_ctrl, int idx)
3293191762Simp{
3294191762Simp	idx = (idx + 1) % BWI_TX_NDESC;
3295191762Simp	CSR_WRITE_4(sc, tx_ctrl + BWI_TX32_INDEX,
3296191762Simp		    idx * sizeof(struct bwi_desc32));
3297191762Simp}
3298191762Simp
3299191762Simpstatic void
3300191762Simpbwi_start_tx64(struct bwi_softc *sc, uint32_t tx_ctrl, int idx)
3301191762Simp{
3302191762Simp	/* TODO:64 */
3303191762Simp}
3304191762Simp
3305191762Simpstatic void
3306191762Simpbwi_txeof_status32(struct bwi_softc *sc)
3307191762Simp{
3308191762Simp	struct ifnet *ifp = sc->sc_ifp;
3309191762Simp	uint32_t val, ctrl_base;
3310191762Simp	int end_idx;
3311191762Simp
3312191762Simp	ctrl_base = sc->sc_txstats->stats_ctrl_base;
3313191762Simp
3314191762Simp	val = CSR_READ_4(sc, ctrl_base + BWI_RX32_STATUS);
3315191762Simp	end_idx = __SHIFTOUT(val, BWI_RX32_STATUS_INDEX_MASK) /
3316191762Simp		  sizeof(struct bwi_desc32);
3317191762Simp
3318191762Simp	bwi_txeof_status(sc, end_idx);
3319191762Simp
3320191762Simp	CSR_WRITE_4(sc, ctrl_base + BWI_RX32_INDEX,
3321191762Simp		    end_idx * sizeof(struct bwi_desc32));
3322191762Simp
3323191762Simp	if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0)
3324191762Simp		ifp->if_start(ifp);
3325191762Simp}
3326191762Simp
3327191762Simpstatic void
3328191762Simpbwi_txeof_status64(struct bwi_softc *sc)
3329191762Simp{
3330191762Simp	/* TODO:64 */
3331191762Simp}
3332191762Simp
3333191762Simpstatic void
3334191762Simp_bwi_txeof(struct bwi_softc *sc, uint16_t tx_id, int acked, int data_txcnt)
3335191762Simp{
3336191762Simp	struct ifnet *ifp = sc->sc_ifp;
3337191762Simp	struct bwi_txbuf_data *tbd;
3338191762Simp	struct bwi_txbuf *tb;
3339191762Simp	int ring_idx, buf_idx;
3340191762Simp	struct ieee80211_node *ni;
3341206358Srpaulo	struct ieee80211vap *vap;
3342191762Simp
3343191762Simp	if (tx_id == 0) {
3344191762Simp		if_printf(ifp, "%s: zero tx id\n", __func__);
3345191762Simp		return;
3346191762Simp	}
3347191762Simp
3348191762Simp	ring_idx = __SHIFTOUT(tx_id, BWI_TXH_ID_RING_MASK);
3349191762Simp	buf_idx = __SHIFTOUT(tx_id, BWI_TXH_ID_IDX_MASK);
3350191762Simp
3351191762Simp	KASSERT(ring_idx == BWI_TX_DATA_RING, ("ring_idx %d", ring_idx));
3352191762Simp	KASSERT(buf_idx < BWI_TX_NDESC, ("buf_idx %d", buf_idx));
3353191762Simp
3354191762Simp	tbd = &sc->sc_tx_bdata[ring_idx];
3355191762Simp	KASSERT(tbd->tbd_used > 0, ("tbd_used %d", tbd->tbd_used));
3356191762Simp	tbd->tbd_used--;
3357191762Simp
3358191762Simp	tb = &tbd->tbd_buf[buf_idx];
3359191762Simp	DPRINTF(sc, BWI_DBG_TXEOF, "txeof idx %d, "
3360191762Simp		"acked %d, data_txcnt %d, ni %p\n",
3361191762Simp		buf_idx, acked, data_txcnt, tb->tb_ni);
3362191762Simp
3363191762Simp	bus_dmamap_unload(sc->sc_buf_dtag, tb->tb_dmap);
3364191762Simp
3365191762Simp	ni = tb->tb_ni;
3366191762Simp	if (tb->tb_ni != NULL) {
3367191762Simp		const struct bwi_txbuf_hdr *hdr =
3368191762Simp		    mtod(tb->tb_mbuf, const struct bwi_txbuf_hdr *);
3369206370Srpaulo		vap = ni->ni_vap;
3370191762Simp
3371191762Simp		/* NB: update rate control only for unicast frames */
3372191762Simp		if (hdr->txh_mac_ctrl & htole32(BWI_TXH_MAC_C_ACK)) {
3373191762Simp			/*
3374191762Simp			 * Feed back 'acked and data_txcnt'.  Note that the
3375191762Simp			 * generic AMRR code only understands one tx rate
3376191762Simp			 * and the estimator doesn't handle real retry counts
3377191762Simp			 * well so to avoid over-aggressive downshifting we
3378191762Simp			 * treat any number of retries as "1".
3379191762Simp			 */
3380206358Srpaulo			ieee80211_ratectl_tx_complete(vap, ni,
3381206358Srpaulo			    (data_txcnt > 1) ? IEEE80211_RATECTL_TX_SUCCESS :
3382206358Srpaulo			        IEEE80211_RATECTL_TX_FAILURE, &acked, NULL);
3383191762Simp		}
3384191762Simp
3385191762Simp		/*
3386191762Simp		 * Do any tx complete callback.  Note this must
3387191762Simp		 * be done before releasing the node reference.
3388191762Simp		 */
3389191762Simp		if (tb->tb_mbuf->m_flags & M_TXCB)
3390191762Simp			ieee80211_process_callback(ni, tb->tb_mbuf, !acked);
3391191762Simp
3392191762Simp		ieee80211_free_node(tb->tb_ni);
3393191762Simp		tb->tb_ni = NULL;
3394191762Simp	}
3395191762Simp	m_freem(tb->tb_mbuf);
3396191762Simp	tb->tb_mbuf = NULL;
3397191762Simp
3398191762Simp	if (tbd->tbd_used == 0)
3399199197Sjhb		sc->sc_tx_timer = 0;
3400191762Simp
3401191762Simp	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
3402191762Simp}
3403191762Simp
3404191762Simpstatic void
3405191762Simpbwi_txeof_status(struct bwi_softc *sc, int end_idx)
3406191762Simp{
3407191762Simp	struct bwi_txstats_data *st = sc->sc_txstats;
3408191762Simp	int idx;
3409191762Simp
3410191762Simp	bus_dmamap_sync(st->stats_dtag, st->stats_dmap, BUS_DMASYNC_POSTREAD);
3411191762Simp
3412191762Simp	idx = st->stats_idx;
3413191762Simp	while (idx != end_idx) {
3414191762Simp		const struct bwi_txstats *stats = &st->stats[idx];
3415191762Simp
3416191762Simp		if ((stats->txs_flags & BWI_TXS_F_PENDING) == 0) {
3417191762Simp			int data_txcnt;
3418191762Simp
3419191762Simp			data_txcnt = __SHIFTOUT(stats->txs_txcnt,
3420191762Simp						BWI_TXS_TXCNT_DATA);
3421191762Simp			_bwi_txeof(sc, le16toh(stats->txs_id),
3422191762Simp				   stats->txs_flags & BWI_TXS_F_ACKED,
3423191762Simp				   data_txcnt);
3424191762Simp		}
3425191762Simp		idx = (idx + 1) % BWI_TXSTATS_NDESC;
3426191762Simp	}
3427191762Simp	st->stats_idx = idx;
3428191762Simp}
3429191762Simp
3430191762Simpstatic void
3431191762Simpbwi_txeof(struct bwi_softc *sc)
3432191762Simp{
3433191762Simp	struct ifnet *ifp = sc->sc_ifp;
3434191762Simp
3435191762Simp	for (;;) {
3436191762Simp		uint32_t tx_status0, tx_status1;
3437191762Simp		uint16_t tx_id;
3438191762Simp		int data_txcnt;
3439191762Simp
3440191762Simp		tx_status0 = CSR_READ_4(sc, BWI_TXSTATUS0);
3441191762Simp		if ((tx_status0 & BWI_TXSTATUS0_VALID) == 0)
3442191762Simp			break;
3443191762Simp		tx_status1 = CSR_READ_4(sc, BWI_TXSTATUS1);
3444191762Simp
3445191762Simp		tx_id = __SHIFTOUT(tx_status0, BWI_TXSTATUS0_TXID_MASK);
3446191762Simp		data_txcnt = __SHIFTOUT(tx_status0,
3447191762Simp				BWI_TXSTATUS0_DATA_TXCNT_MASK);
3448191762Simp
3449191762Simp		if (tx_status0 & (BWI_TXSTATUS0_AMPDU | BWI_TXSTATUS0_PENDING))
3450191762Simp			continue;
3451191762Simp
3452191762Simp		_bwi_txeof(sc, le16toh(tx_id), tx_status0 & BWI_TXSTATUS0_ACKED,
3453191762Simp		    data_txcnt);
3454191762Simp	}
3455191762Simp
3456191762Simp	if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0)
3457191762Simp		ifp->if_start(ifp);
3458191762Simp}
3459191762Simp
3460191762Simpstatic int
3461191762Simpbwi_bbp_power_on(struct bwi_softc *sc, enum bwi_clock_mode clk_mode)
3462191762Simp{
3463191762Simp	bwi_power_on(sc, 1);
3464191762Simp	return bwi_set_clock_mode(sc, clk_mode);
3465191762Simp}
3466191762Simp
3467191762Simpstatic void
3468191762Simpbwi_bbp_power_off(struct bwi_softc *sc)
3469191762Simp{
3470191762Simp	bwi_set_clock_mode(sc, BWI_CLOCK_MODE_SLOW);
3471191762Simp	bwi_power_off(sc, 1);
3472191762Simp}
3473191762Simp
3474191762Simpstatic int
3475191762Simpbwi_get_pwron_delay(struct bwi_softc *sc)
3476191762Simp{
3477191762Simp	struct bwi_regwin *com, *old;
3478191762Simp	struct bwi_clock_freq freq;
3479191762Simp	uint32_t val;
3480191762Simp	int error;
3481191762Simp
3482191762Simp	com = &sc->sc_com_regwin;
3483191762Simp	KASSERT(BWI_REGWIN_EXIST(com), ("no regwin"));
3484191762Simp
3485191762Simp	if ((sc->sc_cap & BWI_CAP_CLKMODE) == 0)
3486191762Simp		return 0;
3487191762Simp
3488191762Simp	error = bwi_regwin_switch(sc, com, &old);
3489191762Simp	if (error)
3490191762Simp		return error;
3491191762Simp
3492191762Simp	bwi_get_clock_freq(sc, &freq);
3493191762Simp
3494191762Simp	val = CSR_READ_4(sc, BWI_PLL_ON_DELAY);
3495191762Simp	sc->sc_pwron_delay = howmany((val + 2) * 1000000, freq.clkfreq_min);
3496191762Simp	DPRINTF(sc, BWI_DBG_ATTACH, "power on delay %u\n", sc->sc_pwron_delay);
3497191762Simp
3498191762Simp	return bwi_regwin_switch(sc, old, NULL);
3499191762Simp}
3500191762Simp
3501191762Simpstatic int
3502191762Simpbwi_bus_attach(struct bwi_softc *sc)
3503191762Simp{
3504191762Simp	struct bwi_regwin *bus, *old;
3505191762Simp	int error;
3506191762Simp
3507191762Simp	bus = &sc->sc_bus_regwin;
3508191762Simp
3509191762Simp	error = bwi_regwin_switch(sc, bus, &old);
3510191762Simp	if (error)
3511191762Simp		return error;
3512191762Simp
3513191762Simp	if (!bwi_regwin_is_enabled(sc, bus))
3514191762Simp		bwi_regwin_enable(sc, bus, 0);
3515191762Simp
3516191762Simp	/* Disable interripts */
3517191762Simp	CSR_WRITE_4(sc, BWI_INTRVEC, 0);
3518191762Simp
3519191762Simp	return bwi_regwin_switch(sc, old, NULL);
3520191762Simp}
3521191762Simp
3522191762Simpstatic const char *
3523191762Simpbwi_regwin_name(const struct bwi_regwin *rw)
3524191762Simp{
3525191762Simp	switch (rw->rw_type) {
3526191762Simp	case BWI_REGWIN_T_COM:
3527191762Simp		return "COM";
3528191762Simp	case BWI_REGWIN_T_BUSPCI:
3529191762Simp		return "PCI";
3530191762Simp	case BWI_REGWIN_T_MAC:
3531191762Simp		return "MAC";
3532191762Simp	case BWI_REGWIN_T_BUSPCIE:
3533191762Simp		return "PCIE";
3534191762Simp	}
3535191762Simp	panic("unknown regwin type 0x%04x\n", rw->rw_type);
3536191762Simp	return NULL;
3537191762Simp}
3538191762Simp
3539191762Simpstatic uint32_t
3540191762Simpbwi_regwin_disable_bits(struct bwi_softc *sc)
3541191762Simp{
3542191762Simp	uint32_t busrev;
3543191762Simp
3544191762Simp	/* XXX cache this */
3545191762Simp	busrev = __SHIFTOUT(CSR_READ_4(sc, BWI_ID_LO), BWI_ID_LO_BUSREV_MASK);
3546191762Simp	DPRINTF(sc, BWI_DBG_ATTACH | BWI_DBG_INIT | BWI_DBG_MISC,
3547191762Simp		"bus rev %u\n", busrev);
3548191762Simp
3549191762Simp	if (busrev == BWI_BUSREV_0)
3550191762Simp		return BWI_STATE_LO_DISABLE1;
3551191762Simp	else if (busrev == BWI_BUSREV_1)
3552191762Simp		return BWI_STATE_LO_DISABLE2;
3553191762Simp	else
3554191762Simp		return (BWI_STATE_LO_DISABLE1 | BWI_STATE_LO_DISABLE2);
3555191762Simp}
3556191762Simp
3557191762Simpint
3558191762Simpbwi_regwin_is_enabled(struct bwi_softc *sc, struct bwi_regwin *rw)
3559191762Simp{
3560191762Simp	uint32_t val, disable_bits;
3561191762Simp
3562191762Simp	disable_bits = bwi_regwin_disable_bits(sc);
3563191762Simp	val = CSR_READ_4(sc, BWI_STATE_LO);
3564191762Simp
3565191762Simp	if ((val & (BWI_STATE_LO_CLOCK |
3566191762Simp		    BWI_STATE_LO_RESET |
3567191762Simp		    disable_bits)) == BWI_STATE_LO_CLOCK) {
3568191762Simp		DPRINTF(sc, BWI_DBG_ATTACH | BWI_DBG_INIT, "%s is enabled\n",
3569191762Simp			bwi_regwin_name(rw));
3570191762Simp		return 1;
3571191762Simp	} else {
3572191762Simp		DPRINTF(sc, BWI_DBG_ATTACH | BWI_DBG_INIT, "%s is disabled\n",
3573191762Simp			bwi_regwin_name(rw));
3574191762Simp		return 0;
3575191762Simp	}
3576191762Simp}
3577191762Simp
3578191762Simpvoid
3579191762Simpbwi_regwin_disable(struct bwi_softc *sc, struct bwi_regwin *rw, uint32_t flags)
3580191762Simp{
3581191762Simp	uint32_t state_lo, disable_bits;
3582191762Simp	int i;
3583191762Simp
3584191762Simp	state_lo = CSR_READ_4(sc, BWI_STATE_LO);
3585191762Simp
3586191762Simp	/*
3587191762Simp	 * If current regwin is in 'reset' state, it was already disabled.
3588191762Simp	 */
3589191762Simp	if (state_lo & BWI_STATE_LO_RESET) {
3590191762Simp		DPRINTF(sc, BWI_DBG_ATTACH | BWI_DBG_INIT,
3591191762Simp			"%s was already disabled\n", bwi_regwin_name(rw));
3592191762Simp		return;
3593191762Simp	}
3594191762Simp
3595191762Simp	disable_bits = bwi_regwin_disable_bits(sc);
3596191762Simp
3597191762Simp	/*
3598191762Simp	 * Disable normal clock
3599191762Simp	 */
3600191762Simp	state_lo = BWI_STATE_LO_CLOCK | disable_bits;
3601191762Simp	CSR_WRITE_4(sc, BWI_STATE_LO, state_lo);
3602191762Simp
3603191762Simp	/*
3604191762Simp	 * Wait until normal clock is disabled
3605191762Simp	 */
3606191762Simp#define NRETRY	1000
3607191762Simp	for (i = 0; i < NRETRY; ++i) {
3608191762Simp		state_lo = CSR_READ_4(sc, BWI_STATE_LO);
3609191762Simp		if (state_lo & disable_bits)
3610191762Simp			break;
3611191762Simp		DELAY(10);
3612191762Simp	}
3613191762Simp	if (i == NRETRY) {
3614191762Simp		device_printf(sc->sc_dev, "%s disable clock timeout\n",
3615191762Simp			      bwi_regwin_name(rw));
3616191762Simp	}
3617191762Simp
3618191762Simp	for (i = 0; i < NRETRY; ++i) {
3619191762Simp		uint32_t state_hi;
3620191762Simp
3621191762Simp		state_hi = CSR_READ_4(sc, BWI_STATE_HI);
3622191762Simp		if ((state_hi & BWI_STATE_HI_BUSY) == 0)
3623191762Simp			break;
3624191762Simp		DELAY(10);
3625191762Simp	}
3626191762Simp	if (i == NRETRY) {
3627191762Simp		device_printf(sc->sc_dev, "%s wait BUSY unset timeout\n",
3628191762Simp			      bwi_regwin_name(rw));
3629191762Simp	}
3630191762Simp#undef NRETRY
3631191762Simp
3632191762Simp	/*
3633191762Simp	 * Reset and disable regwin with gated clock
3634191762Simp	 */
3635191762Simp	state_lo = BWI_STATE_LO_RESET | disable_bits |
3636191762Simp		   BWI_STATE_LO_CLOCK | BWI_STATE_LO_GATED_CLOCK |
3637191762Simp		   __SHIFTIN(flags, BWI_STATE_LO_FLAGS_MASK);
3638191762Simp	CSR_WRITE_4(sc, BWI_STATE_LO, state_lo);
3639191762Simp
3640191762Simp	/* Flush pending bus write */
3641191762Simp	CSR_READ_4(sc, BWI_STATE_LO);
3642191762Simp	DELAY(1);
3643191762Simp
3644191762Simp	/* Reset and disable regwin */
3645191762Simp	state_lo = BWI_STATE_LO_RESET | disable_bits |
3646191762Simp		   __SHIFTIN(flags, BWI_STATE_LO_FLAGS_MASK);
3647191762Simp	CSR_WRITE_4(sc, BWI_STATE_LO, state_lo);
3648191762Simp
3649191762Simp	/* Flush pending bus write */
3650191762Simp	CSR_READ_4(sc, BWI_STATE_LO);
3651191762Simp	DELAY(1);
3652191762Simp}
3653191762Simp
3654191762Simpvoid
3655191762Simpbwi_regwin_enable(struct bwi_softc *sc, struct bwi_regwin *rw, uint32_t flags)
3656191762Simp{
3657191762Simp	uint32_t state_lo, state_hi, imstate;
3658191762Simp
3659191762Simp	bwi_regwin_disable(sc, rw, flags);
3660191762Simp
3661191762Simp	/* Reset regwin with gated clock */
3662191762Simp	state_lo = BWI_STATE_LO_RESET |
3663191762Simp		   BWI_STATE_LO_CLOCK |
3664191762Simp		   BWI_STATE_LO_GATED_CLOCK |
3665191762Simp		   __SHIFTIN(flags, BWI_STATE_LO_FLAGS_MASK);
3666191762Simp	CSR_WRITE_4(sc, BWI_STATE_LO, state_lo);
3667191762Simp
3668191762Simp	/* Flush pending bus write */
3669191762Simp	CSR_READ_4(sc, BWI_STATE_LO);
3670191762Simp	DELAY(1);
3671191762Simp
3672191762Simp	state_hi = CSR_READ_4(sc, BWI_STATE_HI);
3673191762Simp	if (state_hi & BWI_STATE_HI_SERROR)
3674191762Simp		CSR_WRITE_4(sc, BWI_STATE_HI, 0);
3675191762Simp
3676191762Simp	imstate = CSR_READ_4(sc, BWI_IMSTATE);
3677191762Simp	if (imstate & (BWI_IMSTATE_INBAND_ERR | BWI_IMSTATE_TIMEOUT)) {
3678191762Simp		imstate &= ~(BWI_IMSTATE_INBAND_ERR | BWI_IMSTATE_TIMEOUT);
3679191762Simp		CSR_WRITE_4(sc, BWI_IMSTATE, imstate);
3680191762Simp	}
3681191762Simp
3682191762Simp	/* Enable regwin with gated clock */
3683191762Simp	state_lo = BWI_STATE_LO_CLOCK |
3684191762Simp		   BWI_STATE_LO_GATED_CLOCK |
3685191762Simp		   __SHIFTIN(flags, BWI_STATE_LO_FLAGS_MASK);
3686191762Simp	CSR_WRITE_4(sc, BWI_STATE_LO, state_lo);
3687191762Simp
3688191762Simp	/* Flush pending bus write */
3689191762Simp	CSR_READ_4(sc, BWI_STATE_LO);
3690191762Simp	DELAY(1);
3691191762Simp
3692191762Simp	/* Enable regwin with normal clock */
3693191762Simp	state_lo = BWI_STATE_LO_CLOCK |
3694191762Simp		   __SHIFTIN(flags, BWI_STATE_LO_FLAGS_MASK);
3695191762Simp	CSR_WRITE_4(sc, BWI_STATE_LO, state_lo);
3696191762Simp
3697191762Simp	/* Flush pending bus write */
3698191762Simp	CSR_READ_4(sc, BWI_STATE_LO);
3699191762Simp	DELAY(1);
3700191762Simp}
3701191762Simp
3702191762Simpstatic void
3703191762Simpbwi_set_bssid(struct bwi_softc *sc, const uint8_t *bssid)
3704191762Simp{
3705191762Simp	struct ifnet *ifp = sc->sc_ifp;
3706191762Simp	struct bwi_mac *mac;
3707191762Simp	struct bwi_myaddr_bssid buf;
3708191762Simp	const uint8_t *p;
3709191762Simp	uint32_t val;
3710191762Simp	int n, i;
3711191762Simp
3712191762Simp	KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC,
3713191762Simp	    ("current regwin type %d", sc->sc_cur_regwin->rw_type));
3714191762Simp	mac = (struct bwi_mac *)sc->sc_cur_regwin;
3715191762Simp
3716191762Simp	bwi_set_addr_filter(sc, BWI_ADDR_FILTER_BSSID, bssid);
3717191762Simp
3718191762Simp	bcopy(IF_LLADDR(ifp), buf.myaddr, sizeof(buf.myaddr));
3719191762Simp	bcopy(bssid, buf.bssid, sizeof(buf.bssid));
3720191762Simp
3721191762Simp	n = sizeof(buf) / sizeof(val);
3722191762Simp	p = (const uint8_t *)&buf;
3723191762Simp	for (i = 0; i < n; ++i) {
3724191762Simp		int j;
3725191762Simp
3726191762Simp		val = 0;
3727191762Simp		for (j = 0; j < sizeof(val); ++j)
3728191762Simp			val |= ((uint32_t)(*p++)) << (j * 8);
3729191762Simp
3730191762Simp		TMPLT_WRITE_4(mac, 0x20 + (i * sizeof(val)), val);
3731191762Simp	}
3732191762Simp}
3733191762Simp
3734191762Simpstatic void
3735191762Simpbwi_updateslot(struct ifnet *ifp)
3736191762Simp{
3737191762Simp	struct bwi_softc *sc = ifp->if_softc;
3738191762Simp	struct ieee80211com *ic = ifp->if_l2com;
3739191762Simp	struct bwi_mac *mac;
3740191762Simp
3741191762Simp	BWI_LOCK(sc);
3742191762Simp	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
3743191762Simp		DPRINTF(sc, BWI_DBG_80211, "%s\n", __func__);
3744191762Simp
3745191762Simp		KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC,
3746191762Simp		    ("current regwin type %d", sc->sc_cur_regwin->rw_type));
3747191762Simp		mac = (struct bwi_mac *)sc->sc_cur_regwin;
3748191762Simp
3749191762Simp		bwi_mac_updateslot(mac, (ic->ic_flags & IEEE80211_F_SHSLOT));
3750191762Simp	}
3751191762Simp	BWI_UNLOCK(sc);
3752191762Simp}
3753191762Simp
3754191762Simpstatic void
3755191762Simpbwi_calibrate(void *xsc)
3756191762Simp{
3757191762Simp	struct bwi_softc *sc = xsc;
3758191762Simp#ifdef INVARIANTS
3759191762Simp	struct ifnet *ifp = sc->sc_ifp;
3760191762Simp	struct ieee80211com *ic = ifp->if_l2com;
3761191762Simp#endif
3762191762Simp	struct bwi_mac *mac;
3763191762Simp
3764191762Simp	BWI_ASSERT_LOCKED(sc);
3765191762Simp
3766191762Simp	KASSERT(ic->ic_opmode != IEEE80211_M_MONITOR,
3767191762Simp	    ("opmode %d", ic->ic_opmode));
3768191762Simp
3769191762Simp	KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC,
3770191762Simp	    ("current regwin type %d", sc->sc_cur_regwin->rw_type));
3771191762Simp	mac = (struct bwi_mac *)sc->sc_cur_regwin;
3772191762Simp
3773191762Simp	bwi_mac_calibrate_txpower(mac, sc->sc_txpwrcb_type);
3774191762Simp	sc->sc_txpwrcb_type = BWI_TXPWR_CALIB;
3775191762Simp
3776191762Simp	/* XXX 15 seconds */
3777191762Simp	callout_reset(&sc->sc_calib_ch, hz * 15, bwi_calibrate, sc);
3778191762Simp}
3779191762Simp
3780191762Simpstatic int
3781191762Simpbwi_calc_rssi(struct bwi_softc *sc, const struct bwi_rxbuf_hdr *hdr)
3782191762Simp{
3783191762Simp	struct bwi_mac *mac;
3784191762Simp
3785191762Simp	KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC,
3786191762Simp	    ("current regwin type %d", sc->sc_cur_regwin->rw_type));
3787191762Simp	mac = (struct bwi_mac *)sc->sc_cur_regwin;
3788191762Simp
3789191762Simp	return bwi_rf_calc_rssi(mac, hdr);
3790191762Simp}
3791191762Simp
3792191762Simpstatic int
3793191762Simpbwi_calc_noise(struct bwi_softc *sc)
3794191762Simp{
3795191762Simp	struct bwi_mac *mac;
3796191762Simp
3797191762Simp	KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC,
3798191762Simp	    ("current regwin type %d", sc->sc_cur_regwin->rw_type));
3799191762Simp	mac = (struct bwi_mac *)sc->sc_cur_regwin;
3800191762Simp
3801191762Simp	return bwi_rf_calc_noise(mac);
3802191762Simp}
3803191762Simp
3804191762Simpstatic __inline uint8_t
3805228621Sbschmidtbwi_plcp2rate(const uint32_t plcp0, enum ieee80211_phytype type)
3806191762Simp{
3807228621Sbschmidt	uint32_t plcp = le32toh(plcp0) & IEEE80211_OFDM_PLCP_RATE_MASK;
3808228621Sbschmidt	return (ieee80211_plcp2rate(plcp, type));
3809191762Simp}
3810191762Simp
3811191762Simpstatic void
3812192468Ssambwi_rx_radiotap(struct bwi_softc *sc, struct mbuf *m,
3813191762Simp    struct bwi_rxbuf_hdr *hdr, const void *plcp, int rate, int rssi, int noise)
3814191762Simp{
3815191762Simp	const struct ieee80211_frame_min *wh;
3816191762Simp
3817191762Simp	sc->sc_rx_th.wr_flags = IEEE80211_RADIOTAP_F_FCS;
3818191762Simp	if (htole16(hdr->rxh_flags1) & BWI_RXH_F1_SHPREAMBLE)
3819191762Simp		sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
3820191762Simp
3821191762Simp	wh = mtod(m, const struct ieee80211_frame_min *);
3822262007Skevlo	if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED)
3823191762Simp		sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_WEP;
3824191762Simp
3825191762Simp	sc->sc_rx_th.wr_tsf = hdr->rxh_tsf; /* No endian convertion */
3826191762Simp	sc->sc_rx_th.wr_rate = rate;
3827191762Simp	sc->sc_rx_th.wr_antsignal = rssi;
3828191762Simp	sc->sc_rx_th.wr_antnoise = noise;
3829191762Simp}
3830191762Simp
3831191762Simpstatic void
3832191762Simpbwi_led_attach(struct bwi_softc *sc)
3833191762Simp{
3834191762Simp	const uint8_t *led_act = NULL;
3835191762Simp	uint16_t gpio, val[BWI_LED_MAX];
3836191762Simp	int i;
3837191762Simp
3838191762Simp#define N(arr)	(int)(sizeof(arr) / sizeof(arr[0]))
3839191762Simp
3840191762Simp	for (i = 0; i < N(bwi_vendor_led_act); ++i) {
3841191762Simp		if (sc->sc_pci_subvid == bwi_vendor_led_act[i].vid) {
3842191762Simp			led_act = bwi_vendor_led_act[i].led_act;
3843191762Simp			break;
3844191762Simp		}
3845191762Simp	}
3846191762Simp	if (led_act == NULL)
3847191762Simp		led_act = bwi_default_led_act;
3848191762Simp
3849191762Simp#undef N
3850191762Simp
3851191762Simp	gpio = bwi_read_sprom(sc, BWI_SPROM_GPIO01);
3852191762Simp	val[0] = __SHIFTOUT(gpio, BWI_SPROM_GPIO_0);
3853191762Simp	val[1] = __SHIFTOUT(gpio, BWI_SPROM_GPIO_1);
3854191762Simp
3855191762Simp	gpio = bwi_read_sprom(sc, BWI_SPROM_GPIO23);
3856191762Simp	val[2] = __SHIFTOUT(gpio, BWI_SPROM_GPIO_2);
3857191762Simp	val[3] = __SHIFTOUT(gpio, BWI_SPROM_GPIO_3);
3858191762Simp
3859191762Simp	for (i = 0; i < BWI_LED_MAX; ++i) {
3860191762Simp		struct bwi_led *led = &sc->sc_leds[i];
3861191762Simp
3862191762Simp		if (val[i] == 0xff) {
3863191762Simp			led->l_act = led_act[i];
3864191762Simp		} else {
3865191762Simp			if (val[i] & BWI_LED_ACT_LOW)
3866191762Simp				led->l_flags |= BWI_LED_F_ACTLOW;
3867191762Simp			led->l_act = __SHIFTOUT(val[i], BWI_LED_ACT_MASK);
3868191762Simp		}
3869191762Simp		led->l_mask = (1 << i);
3870191762Simp
3871191762Simp		if (led->l_act == BWI_LED_ACT_BLINK_SLOW ||
3872191762Simp		    led->l_act == BWI_LED_ACT_BLINK_POLL ||
3873191762Simp		    led->l_act == BWI_LED_ACT_BLINK) {
3874191762Simp			led->l_flags |= BWI_LED_F_BLINK;
3875191762Simp			if (led->l_act == BWI_LED_ACT_BLINK_POLL)
3876191762Simp				led->l_flags |= BWI_LED_F_POLLABLE;
3877191762Simp			else if (led->l_act == BWI_LED_ACT_BLINK_SLOW)
3878191762Simp				led->l_flags |= BWI_LED_F_SLOW;
3879191762Simp
3880191762Simp			if (sc->sc_blink_led == NULL) {
3881191762Simp				sc->sc_blink_led = led;
3882191762Simp				if (led->l_flags & BWI_LED_F_SLOW)
3883191762Simp					BWI_LED_SLOWDOWN(sc->sc_led_idle);
3884191762Simp			}
3885191762Simp		}
3886191762Simp
3887191762Simp		DPRINTF(sc, BWI_DBG_LED | BWI_DBG_ATTACH,
3888191762Simp			"%dth led, act %d, lowact %d\n", i,
3889191762Simp			led->l_act, led->l_flags & BWI_LED_F_ACTLOW);
3890191762Simp	}
3891199197Sjhb	callout_init_mtx(&sc->sc_led_blink_ch, &sc->sc_mtx, 0);
3892191762Simp}
3893191762Simp
3894191762Simpstatic __inline uint16_t
3895191762Simpbwi_led_onoff(const struct bwi_led *led, uint16_t val, int on)
3896191762Simp{
3897191762Simp	if (led->l_flags & BWI_LED_F_ACTLOW)
3898191762Simp		on = !on;
3899191762Simp	if (on)
3900191762Simp		val |= led->l_mask;
3901191762Simp	else
3902191762Simp		val &= ~led->l_mask;
3903191762Simp	return val;
3904191762Simp}
3905191762Simp
3906191762Simpstatic void
3907191762Simpbwi_led_newstate(struct bwi_softc *sc, enum ieee80211_state nstate)
3908191762Simp{
3909191762Simp	struct ifnet *ifp = sc->sc_ifp;
3910191762Simp	struct ieee80211com *ic = ifp->if_l2com;
3911191762Simp	uint16_t val;
3912191762Simp	int i;
3913191762Simp
3914191762Simp	if (nstate == IEEE80211_S_INIT) {
3915191762Simp		callout_stop(&sc->sc_led_blink_ch);
3916191762Simp		sc->sc_led_blinking = 0;
3917191762Simp	}
3918191762Simp
3919191762Simp	if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
3920191762Simp		return;
3921191762Simp
3922191762Simp	val = CSR_READ_2(sc, BWI_MAC_GPIO_CTRL);
3923191762Simp	for (i = 0; i < BWI_LED_MAX; ++i) {
3924191762Simp		struct bwi_led *led = &sc->sc_leds[i];
3925191762Simp		int on;
3926191762Simp
3927191762Simp		if (led->l_act == BWI_LED_ACT_UNKN ||
3928191762Simp		    led->l_act == BWI_LED_ACT_NULL)
3929191762Simp			continue;
3930191762Simp
3931191762Simp		if ((led->l_flags & BWI_LED_F_BLINK) &&
3932191762Simp		    nstate != IEEE80211_S_INIT)
3933191762Simp		    	continue;
3934191762Simp
3935191762Simp		switch (led->l_act) {
3936191762Simp		case BWI_LED_ACT_ON:	/* Always on */
3937191762Simp			on = 1;
3938191762Simp			break;
3939191762Simp		case BWI_LED_ACT_OFF:	/* Always off */
3940191762Simp		case BWI_LED_ACT_5GHZ:	/* TODO: 11A */
3941191762Simp			on = 0;
3942191762Simp			break;
3943191762Simp		default:
3944191762Simp			on = 1;
3945191762Simp			switch (nstate) {
3946191762Simp			case IEEE80211_S_INIT:
3947191762Simp				on = 0;
3948191762Simp				break;
3949191762Simp			case IEEE80211_S_RUN:
3950191762Simp				if (led->l_act == BWI_LED_ACT_11G &&
3951191762Simp				    ic->ic_curmode != IEEE80211_MODE_11G)
3952191762Simp					on = 0;
3953191762Simp				break;
3954191762Simp			default:
3955191762Simp				if (led->l_act == BWI_LED_ACT_ASSOC)
3956191762Simp					on = 0;
3957191762Simp				break;
3958191762Simp			}
3959191762Simp			break;
3960191762Simp		}
3961191762Simp
3962191762Simp		val = bwi_led_onoff(led, val, on);
3963191762Simp	}
3964191762Simp	CSR_WRITE_2(sc, BWI_MAC_GPIO_CTRL, val);
3965191762Simp}
3966191762Simpstatic void
3967191762Simpbwi_led_event(struct bwi_softc *sc, int event)
3968191762Simp{
3969191762Simp	struct bwi_led *led = sc->sc_blink_led;
3970191762Simp	int rate;
3971191762Simp
3972191762Simp	if (event == BWI_LED_EVENT_POLL) {
3973191762Simp		if ((led->l_flags & BWI_LED_F_POLLABLE) == 0)
3974191762Simp			return;
3975191762Simp		if (ticks - sc->sc_led_ticks < sc->sc_led_idle)
3976191762Simp			return;
3977191762Simp	}
3978191762Simp
3979191762Simp	sc->sc_led_ticks = ticks;
3980191762Simp	if (sc->sc_led_blinking)
3981191762Simp		return;
3982191762Simp
3983191762Simp	switch (event) {
3984191762Simp	case BWI_LED_EVENT_RX:
3985191762Simp		rate = sc->sc_rx_rate;
3986191762Simp		break;
3987191762Simp	case BWI_LED_EVENT_TX:
3988191762Simp		rate = sc->sc_tx_rate;
3989191762Simp		break;
3990191762Simp	case BWI_LED_EVENT_POLL:
3991191762Simp		rate = 0;
3992191762Simp		break;
3993191762Simp	default:
3994191762Simp		panic("unknown LED event %d\n", event);
3995191762Simp		break;
3996191762Simp	}
3997191762Simp	bwi_led_blink_start(sc, bwi_led_duration[rate].on_dur,
3998191762Simp	    bwi_led_duration[rate].off_dur);
3999191762Simp}
4000191762Simp
4001191762Simpstatic void
4002191762Simpbwi_led_blink_start(struct bwi_softc *sc, int on_dur, int off_dur)
4003191762Simp{
4004191762Simp	struct bwi_led *led = sc->sc_blink_led;
4005191762Simp	uint16_t val;
4006191762Simp
4007191762Simp	val = CSR_READ_2(sc, BWI_MAC_GPIO_CTRL);
4008191762Simp	val = bwi_led_onoff(led, val, 1);
4009191762Simp	CSR_WRITE_2(sc, BWI_MAC_GPIO_CTRL, val);
4010191762Simp
4011191762Simp	if (led->l_flags & BWI_LED_F_SLOW) {
4012191762Simp		BWI_LED_SLOWDOWN(on_dur);
4013191762Simp		BWI_LED_SLOWDOWN(off_dur);
4014191762Simp	}
4015191762Simp
4016191762Simp	sc->sc_led_blinking = 1;
4017191762Simp	sc->sc_led_blink_offdur = off_dur;
4018191762Simp
4019191762Simp	callout_reset(&sc->sc_led_blink_ch, on_dur, bwi_led_blink_next, sc);
4020191762Simp}
4021191762Simp
4022191762Simpstatic void
4023191762Simpbwi_led_blink_next(void *xsc)
4024191762Simp{
4025191762Simp	struct bwi_softc *sc = xsc;
4026191762Simp	uint16_t val;
4027191762Simp
4028191762Simp	val = CSR_READ_2(sc, BWI_MAC_GPIO_CTRL);
4029191762Simp	val = bwi_led_onoff(sc->sc_blink_led, val, 0);
4030191762Simp	CSR_WRITE_2(sc, BWI_MAC_GPIO_CTRL, val);
4031191762Simp
4032191762Simp	callout_reset(&sc->sc_led_blink_ch, sc->sc_led_blink_offdur,
4033191762Simp	    bwi_led_blink_end, sc);
4034191762Simp}
4035191762Simp
4036191762Simpstatic void
4037191762Simpbwi_led_blink_end(void *xsc)
4038191762Simp{
4039191762Simp	struct bwi_softc *sc = xsc;
4040191762Simp	sc->sc_led_blinking = 0;
4041191762Simp}
4042191762Simp
4043191762Simpstatic void
4044191762Simpbwi_restart(void *xsc, int pending)
4045191762Simp{
4046191762Simp	struct bwi_softc *sc = xsc;
4047191762Simp	struct ifnet *ifp = sc->sc_ifp;
4048191762Simp
4049191762Simp	if_printf(ifp, "%s begin, help!\n", __func__);
4050191762Simp	BWI_LOCK(sc);
4051191762Simp	bwi_init_statechg(xsc, 0);
4052191762Simp#if 0
4053191762Simp	bwi_start_locked(ifp);
4054191762Simp#endif
4055193238Simp	BWI_UNLOCK(sc);
4056191762Simp}
4057