xref: /freebsd/sys/dev/mwl/mwlhal.c (revision 0572ccaa4543b0abef8ef81e384c1d04de9f3da1)
1 /*-
2  * Copyright (c) 2007-2009 Sam Leffler, Errno Consulting
3  * Copyright (c) 2007-2009 Marvell Semiconductor, Inc.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer,
11  *    without modification.
12  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
13  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
14  *    redistribution must be conditioned upon including a substantially
15  *    similar Disclaimer requirement for further binary redistribution.
16  *
17  * NO WARRANTY
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
21  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
22  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
23  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
26  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28  * THE POSSIBILITY OF SUCH DAMAGES.
29  *
30  * $FreeBSD$
31  */
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/sysctl.h>
36 #include <sys/malloc.h>
37 #include <sys/lock.h>
38 #include <sys/mutex.h>
39 #include <sys/kernel.h>
40 #include <sys/errno.h>
41 #include <sys/bus.h>
42 #include <sys/endian.h>
43 
44 #include <sys/linker.h>
45 #include <sys/firmware.h>
46 
47 #include <machine/bus.h>
48 
49 #include <dev/mwl/mwlhal.h>
50 #include <dev/mwl/mwlreg.h>
51 
52 #include <sys/socket.h>
53 #include <sys/sockio.h>
54 #include <net/if.h>
55 #include <dev/mwl/mwldiag.h>
56 
57 #define	MWLHAL_DEBUG			/* debug msgs */
58 
59 typedef enum {
60     WL_ANTENNAMODE_RX = 0xffff,
61     WL_ANTENNAMODE_TX = 2,
62 } wlantennamode_e;
63 
64 typedef enum {
65     WL_TX_POWERLEVEL_LOW = 5,
66     WL_TX_POWERLEVEL_MEDIUM = 10,
67     WL_TX_POWERLEVEL_HIGH = 15,
68 } wltxpowerlevel_e;
69 
70 #define	MWL_CMDBUF_SIZE	0x4000		/* size of f/w command buffer */
71 #define	MWL_BASTREAMS_MAX	7	/* max BA streams (NB: fw >3.3.5.9) */
72 #define	MWL_BAQID_MAX		8	/* max BA Q id's (NB: fw >3.3.5.9) */
73 #define	MWL_MBSS_AP_MAX		8	/* max ap vap's */
74 #define	MWL_MBSS_STA_MAX	24	/* max station/client vap's */
75 #define	MWL_MBSS_MAX	(MWL_MBSS_AP_MAX+MWL_MBSS_STA_MAX)
76 
77 /*
78  * BA stream -> queue ID mapping
79  *
80  * The first 2 streams map to h/w; the remaining streams are
81  * implemented in firmware.
82  */
83 static const int ba2qid[MWL_BASTREAMS_MAX] = {
84 	5, 6				/* h/w supported */
85 #if MWL_BASTREAMS_MAX == 7
86 	, 7, 0, 1, 2, 3 		/* f/w supported */
87 #endif
88 };
89 static int qid2ba[MWL_BAQID_MAX];
90 
91 #define	IEEE80211_ADDR_LEN	6	/* XXX */
92 #define	IEEE80211_ADDR_COPY(_dst, _src) \
93 	memcpy(_dst, _src, IEEE80211_ADDR_LEN)
94 #define	IEEE80211_ADDR_EQ(_dst, _src) \
95 	(memcmp(_dst, _src, IEEE80211_ADDR_LEN) == 0)
96 
97 #define	_CMD_SETUP(pCmd, type, cmd) do {				\
98 	pCmd = (type *)&mh->mh_cmdbuf[0];				\
99 	memset(pCmd, 0, sizeof(type));					\
100 	pCmd->CmdHdr.Cmd = htole16(cmd);				\
101 	pCmd->CmdHdr.Length = htole16(sizeof(type));			\
102 } while (0)
103 
104 #define	_VCMD_SETUP(vap, pCmd, type, cmd) do {				\
105 	_CMD_SETUP(pCmd, type, cmd);					\
106 	pCmd->CmdHdr.MacId = vap->macid;				\
107 } while (0)
108 
109 #define	PWTAGETRATETABLE20M	14*4
110 #define	PWTAGETRATETABLE40M	9*4
111 #define	PWTAGETRATETABLE20M_5G	35*4
112 #define	PWTAGETRATETABLE40M_5G	16*4
113 
114 struct mwl_hal_bastream {
115 	MWL_HAL_BASTREAM public;	/* public state */
116 	uint8_t	stream;			/* stream # */
117 	uint8_t	setup;			/* f/w cmd sent */
118 	uint8_t ba_policy;		/* direct/delayed BA policy */
119 	uint8_t	tid;
120 	uint8_t	paraminfo;
121 	uint8_t macaddr[IEEE80211_ADDR_LEN];
122 };
123 
124 struct mwl_hal_priv;
125 
126 struct mwl_hal_vap {
127 	struct mwl_hal_priv *mh;	/* back pointer */
128 	uint16_t bss_type;		/* f/w type */
129 	uint8_t vap_type;		/* MWL_HAL_BSSTYPE */
130 	uint8_t	macid;			/* for passing to f/w */
131 	uint8_t flags;
132 #define	MVF_RUNNING	0x01		/* BSS_START issued */
133 #define	MVF_STATION	0x02		/* sta db entry created */
134 	uint8_t mac[IEEE80211_ADDR_LEN];/* mac address */
135 };
136 #define	MWLVAP(_vap)	((_vap)->mh)
137 
138 /*
139  * Per-device state.  We allocate a single cmd buffer for
140  * submitting operations to the firmware.  Access to this
141  * buffer (and the f/w) are single-threaded.  At present
142  * we spin waiting for cmds to complete which is bad.  Not
143  * sure if it's possible to submit multiple requests or
144  * control when we get cmd done interrupts.  There's no
145  * documentation and no example code to indicate what can
146  * or cannot be done so all we can do right now is follow the
147  * linux driver logic.  This falls apart when the f/w fails;
148  * the system comes to a crawl as we spin waiting for operations
149  * to finish.
150  */
151 struct mwl_hal_priv {
152 	struct mwl_hal	public;		/* public area */
153 	device_t	mh_dev;
154 	char		mh_mtxname[12];
155 	struct mtx	mh_mtx;
156 	bus_dma_tag_t	mh_dmat;	/* bus DMA tag for cmd buffer */
157 	bus_dma_segment_t mh_seg;	/* segment for cmd buffer */
158 	bus_dmamap_t	mh_dmamap;	/* DMA map for cmd buffer */
159 	uint16_t	*mh_cmdbuf;	/* f/w cmd buffer */
160 	bus_addr_t	mh_cmdaddr;	/* physaddr of cmd buffer */
161 	int		mh_flags;
162 #define	MHF_CALDATA	0x0001		/* cal data retrieved */
163 #define	MHF_FWHANG	0x0002		/* fw appears hung */
164 #define	MHF_MBSS	0x0004		/* mbss enabled */
165 	struct mwl_hal_vap mh_vaps[MWL_MBSS_MAX+1];
166 	int		mh_bastreams;	/* bit mask of available BA streams */
167 	int		mh_regioncode;	/* XXX last region code sent to fw */
168 	struct mwl_hal_bastream mh_streams[MWL_BASTREAMS_MAX];
169 	int		mh_debug;
170 	MWL_HAL_CHANNELINFO mh_20M;
171 	MWL_HAL_CHANNELINFO mh_40M;
172 	MWL_HAL_CHANNELINFO mh_20M_5G;
173 	MWL_HAL_CHANNELINFO mh_40M_5G;
174 	int		mh_SDRAMSIZE_Addr;
175 	uint32_t	mh_RTSSuccesses;/* cumulative stats for read-on-clear */
176 	uint32_t	mh_RTSFailures;
177 	uint32_t	mh_RxDuplicateFrames;
178 	uint32_t	mh_FCSErrorCount;
179 	MWL_DIAG_REVS	mh_revs;
180 };
181 #define	MWLPRIV(_mh)	((struct mwl_hal_priv *)(_mh))
182 
183 static int mwl_hal_setmac_locked(struct mwl_hal_vap *,
184 	const uint8_t addr[IEEE80211_ADDR_LEN]);
185 static int mwlExecuteCmd(struct mwl_hal_priv *, unsigned short cmd);
186 static int mwlGetPwrCalTable(struct mwl_hal_priv *);
187 #ifdef MWLHAL_DEBUG
188 static const char *mwlcmdname(int cmd);
189 static void dumpresult(struct mwl_hal_priv *, int showresult);
190 #endif /* MWLHAL_DEBUG */
191 
192 SYSCTL_DECL(_hw_mwl);
193 static SYSCTL_NODE(_hw_mwl, OID_AUTO, hal, CTLFLAG_RD, 0,
194     "Marvell HAL parameters");
195 
196 static __inline void
197 MWL_HAL_LOCK(struct mwl_hal_priv *mh)
198 {
199 	mtx_lock(&mh->mh_mtx);
200 }
201 
202 static __inline void
203 MWL_HAL_LOCK_ASSERT(struct mwl_hal_priv *mh)
204 {
205 	mtx_assert(&mh->mh_mtx, MA_OWNED);
206 }
207 
208 static __inline void
209 MWL_HAL_UNLOCK(struct mwl_hal_priv *mh)
210 {
211 	mtx_unlock(&mh->mh_mtx);
212 }
213 
214 static __inline uint32_t
215 RD4(struct mwl_hal_priv *mh, bus_size_t off)
216 {
217 	return bus_space_read_4(mh->public.mh_iot, mh->public.mh_ioh, off);
218 }
219 
220 static __inline void
221 WR4(struct mwl_hal_priv *mh, bus_size_t off, uint32_t val)
222 {
223 	bus_space_write_4(mh->public.mh_iot, mh->public.mh_ioh, off, val);
224 }
225 
226 static void
227 mwl_hal_load_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
228 {
229 	bus_addr_t *paddr = (bus_addr_t*) arg;
230 	KASSERT(error == 0, ("error %u on bus_dma callback", error));
231 	*paddr = segs->ds_addr;
232 }
233 
234 /*
235  * Setup for communication with the device.  We allocate
236  * a command buffer and map it for bus dma use.  The pci
237  * device id is used to identify whether the device has
238  * SRAM on it (in which case f/w download must include a
239  * memory controller reset).  All bus i/o operations happen
240  * in BAR 1; the driver passes in the tag and handle we need.
241  */
242 struct mwl_hal *
243 mwl_hal_attach(device_t dev, uint16_t devid,
244     bus_space_handle_t ioh, bus_space_tag_t iot, bus_dma_tag_t tag)
245 {
246 	struct mwl_hal_priv *mh;
247 	struct mwl_hal_vap *hvap;
248 	int error, i;
249 
250 	mh = malloc(sizeof(struct mwl_hal_priv), M_DEVBUF, M_NOWAIT | M_ZERO);
251 	if (mh == NULL)
252 		return NULL;
253 	mh->mh_dev = dev;
254 	mh->public.mh_ioh = ioh;
255 	mh->public.mh_iot = iot;
256 	for (i = 0; i < MWL_BASTREAMS_MAX; i++) {
257 		mh->mh_streams[i].public.txq = ba2qid[i];
258 		mh->mh_streams[i].stream = i;
259 		/* construct back-mapping while we're at it */
260 		if (mh->mh_streams[i].public.txq < MWL_BAQID_MAX)
261 			qid2ba[mh->mh_streams[i].public.txq] = i;
262 		else
263 			device_printf(dev, "unexpected BA tx qid %d for "
264 			    "stream %d\n", mh->mh_streams[i].public.txq, i);
265 	}
266 	/* setup constant portion of vap state */
267 	/* XXX should get max ap/client vap's from f/w */
268 	i = 0;
269 	hvap = &mh->mh_vaps[i];
270 	hvap->vap_type = MWL_HAL_AP;
271 	hvap->bss_type = htole16(WL_MAC_TYPE_PRIMARY_AP);
272 	hvap->macid = 0;
273 	for (i++; i < MWL_MBSS_AP_MAX; i++) {
274 		hvap = &mh->mh_vaps[i];
275 		hvap->vap_type = MWL_HAL_AP;
276 		hvap->bss_type = htole16(WL_MAC_TYPE_SECONDARY_AP);
277 		hvap->macid = i;
278 	}
279 	hvap = &mh->mh_vaps[i];
280 	hvap->vap_type = MWL_HAL_STA;
281 	hvap->bss_type = htole16(WL_MAC_TYPE_PRIMARY_CLIENT);
282 	hvap->macid = i;
283 	for (i++; i < MWL_MBSS_MAX; i++) {
284 		hvap = &mh->mh_vaps[i];
285 		hvap->vap_type = MWL_HAL_STA;
286 		hvap->bss_type = htole16(WL_MAC_TYPE_SECONDARY_CLIENT);
287 		hvap->macid = i;
288 	}
289 	mh->mh_revs.mh_devid = devid;
290 	snprintf(mh->mh_mtxname, sizeof(mh->mh_mtxname),
291 	    "%s_hal", device_get_nameunit(dev));
292 	mtx_init(&mh->mh_mtx, mh->mh_mtxname, NULL, MTX_DEF);
293 
294 	/*
295 	 * Allocate the command buffer and map into the address
296 	 * space of the h/w.  We request "coherent" memory which
297 	 * will be uncached on some architectures.
298 	 */
299 	error = bus_dma_tag_create(tag,		/* parent */
300 		       PAGE_SIZE, 0,		/* alignment, bounds */
301 		       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
302 		       BUS_SPACE_MAXADDR,	/* highaddr */
303 		       NULL, NULL,		/* filter, filterarg */
304 		       MWL_CMDBUF_SIZE,		/* maxsize */
305 		       1,			/* nsegments */
306 		       MWL_CMDBUF_SIZE,		/* maxsegsize */
307 		       BUS_DMA_ALLOCNOW,	/* flags */
308 		       NULL,			/* lockfunc */
309 		       NULL,			/* lockarg */
310 		       &mh->mh_dmat);
311 	if (error != 0) {
312 		device_printf(dev, "unable to allocate memory for cmd buffer, "
313 			"error %u\n", error);
314 		goto fail0;
315 	}
316 
317 	/* allocate descriptors */
318 	error = bus_dmamap_create(mh->mh_dmat, BUS_DMA_NOWAIT, &mh->mh_dmamap);
319 	if (error != 0) {
320 		device_printf(dev, "unable to create dmamap for cmd buffers, "
321 			"error %u\n", error);
322 		goto fail0;
323 	}
324 
325 	error = bus_dmamem_alloc(mh->mh_dmat, (void**) &mh->mh_cmdbuf,
326 				 BUS_DMA_NOWAIT | BUS_DMA_COHERENT,
327 				 &mh->mh_dmamap);
328 	if (error != 0) {
329 		device_printf(dev, "unable to allocate memory for cmd buffer, "
330 			"error %u\n", error);
331 		goto fail1;
332 	}
333 
334 	error = bus_dmamap_load(mh->mh_dmat, mh->mh_dmamap,
335 				mh->mh_cmdbuf, MWL_CMDBUF_SIZE,
336 				mwl_hal_load_cb, &mh->mh_cmdaddr,
337 				BUS_DMA_NOWAIT);
338 	if (error != 0) {
339 		device_printf(dev, "unable to load cmd buffer, error %u\n",
340 			error);
341 		goto fail2;
342 	}
343 
344 	/*
345 	 * Some cards have SDRAM.  When loading firmware we need
346 	 * to reset the SDRAM controller prior to doing this.
347 	 * When the SDRAMSIZE is non-zero we do that work in
348 	 * mwl_hal_fwload.
349 	 */
350 	switch (devid) {
351 	case 0x2a02:		/* CB82 */
352 	case 0x2a03:		/* CB85 */
353 	case 0x2a08:		/* MC85_B1 */
354 	case 0x2a0b:		/* CB85AP */
355 	case 0x2a24:
356 		mh->mh_SDRAMSIZE_Addr = 0x40fe70b7;	/* 8M SDRAM */
357 		break;
358 	case 0x2a04:		/* MC85 */
359 		mh->mh_SDRAMSIZE_Addr = 0x40fc70b7;	/* 16M SDRAM */
360 		break;
361 	default:
362 		break;
363 	}
364 	return &mh->public;
365 fail2:
366 	bus_dmamem_free(mh->mh_dmat, mh->mh_cmdbuf, mh->mh_dmamap);
367 fail1:
368 	bus_dmamap_destroy(mh->mh_dmat, mh->mh_dmamap);
369 fail0:
370 	bus_dma_tag_destroy(mh->mh_dmat);
371 	mtx_destroy(&mh->mh_mtx);
372 	free(mh, M_DEVBUF);
373 	return NULL;
374 }
375 
376 void
377 mwl_hal_detach(struct mwl_hal *mh0)
378 {
379 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
380 
381 	bus_dmamem_free(mh->mh_dmat, mh->mh_cmdbuf, mh->mh_dmamap);
382 	bus_dmamap_destroy(mh->mh_dmat, mh->mh_dmamap);
383 	bus_dma_tag_destroy(mh->mh_dmat);
384 	mtx_destroy(&mh->mh_mtx);
385 	free(mh, M_DEVBUF);
386 }
387 
388 /*
389  * Reset internal state after a firmware download.
390  */
391 static int
392 mwlResetHalState(struct mwl_hal_priv *mh)
393 {
394 	int i;
395 
396 	/* XXX get from f/w */
397 	mh->mh_bastreams = (1<<MWL_BASTREAMS_MAX)-1;
398 	for (i = 0; i < MWL_MBSS_MAX; i++)
399 		mh->mh_vaps[i].mh = NULL;
400 	/*
401 	 * Clear cumulative stats.
402 	 */
403 	mh->mh_RTSSuccesses = 0;
404 	mh->mh_RTSFailures = 0;
405 	mh->mh_RxDuplicateFrames = 0;
406 	mh->mh_FCSErrorCount = 0;
407 	/*
408 	 * Fetch cal data for later use.
409 	 * XXX may want to fetch other stuff too.
410 	 */
411 	/* XXX check return */
412 	if ((mh->mh_flags & MHF_CALDATA) == 0)
413 		mwlGetPwrCalTable(mh);
414 	return 0;
415 }
416 
417 struct mwl_hal_vap *
418 mwl_hal_newvap(struct mwl_hal *mh0, MWL_HAL_BSSTYPE type,
419 	const uint8_t mac[IEEE80211_ADDR_LEN])
420 {
421 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
422 	struct mwl_hal_vap *vap;
423 	int i;
424 
425 	MWL_HAL_LOCK(mh);
426 	/* NB: could optimize but not worth it w/ max 32 bss */
427 	for (i = 0; i < MWL_MBSS_MAX; i++) {
428 		vap = &mh->mh_vaps[i];
429 		if (vap->vap_type == type && vap->mh == NULL) {
430 			vap->mh = mh;
431 			mwl_hal_setmac_locked(vap, mac);
432 			break;
433 		}
434 	}
435 	MWL_HAL_UNLOCK(mh);
436 	return (i < MWL_MBSS_MAX) ? vap : NULL;
437 }
438 
439 void
440 mwl_hal_delvap(struct mwl_hal_vap *vap)
441 {
442 	/* NB: locking not needed for single write */
443 	vap->mh = NULL;
444 }
445 
446 /*
447  * Manipulate the debug mask.  Note debug
448  * msgs are only provided when this code is
449  * compiled with MWLHAL_DEBUG defined.
450  */
451 
452 void
453 mwl_hal_setdebug(struct mwl_hal *mh, int debug)
454 {
455 	MWLPRIV(mh)->mh_debug = debug;
456 }
457 
458 int
459 mwl_hal_getdebug(struct mwl_hal *mh)
460 {
461 	return MWLPRIV(mh)->mh_debug;
462 }
463 
464 void
465 mwl_hal_setbastreams(struct mwl_hal *mh, int mask)
466 {
467 	MWLPRIV(mh)->mh_bastreams = mask & ((1<<MWL_BASTREAMS_MAX)-1);
468 }
469 
470 int
471 mwl_hal_getbastreams(struct mwl_hal *mh)
472 {
473 	return MWLPRIV(mh)->mh_bastreams;
474 }
475 
476 int
477 mwl_hal_ismbsscapable(struct mwl_hal *mh)
478 {
479 	return (MWLPRIV(mh)->mh_flags & MHF_MBSS) != 0;
480 }
481 
482 #if 0
483 /* XXX inlined */
484 /*
485  * Return the current ISR setting and clear the cause.
486  * XXX maybe make inline
487  */
488 void
489 mwl_hal_getisr(struct mwl_hal *mh0, uint32_t *status)
490 {
491 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
492 	uint32_t cause;
493 
494 	cause = RD4(mh, MACREG_REG_A2H_INTERRUPT_CAUSE);
495 	if (cause == 0xffffffff) {	/* card removed */
496 device_printf(mh->mh_dev, "%s: cause 0x%x\n", __func__, cause);
497 		cause = 0;
498 	} else if (cause != 0) {
499 		/* clear cause bits */
500 		WR4(mh, MACREG_REG_A2H_INTERRUPT_CAUSE,
501 		    cause &~ mh->public.mh_imask);
502 		RD4(mh, MACREG_REG_INT_CODE);	/* XXX flush write? */
503 	}
504 	*status = cause;
505 }
506 #endif
507 
508 /*
509  * Set the interrupt mask.
510  */
511 void
512 mwl_hal_intrset(struct mwl_hal *mh0, uint32_t mask)
513 {
514 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
515 
516 	WR4(mh, MACREG_REG_A2H_INTERRUPT_MASK, 0);
517 	RD4(mh, MACREG_REG_INT_CODE);
518 
519 	mh->public.mh_imask = mask;
520 	WR4(mh, MACREG_REG_A2H_INTERRUPT_MASK, mask);
521 	RD4(mh, MACREG_REG_INT_CODE);
522 }
523 
524 #if 0
525 /* XXX inlined */
526 /*
527  * Kick the firmware to tell it there are new tx descriptors
528  * for processing.  The driver says what h/w q has work in
529  * case the f/w ever gets smarter.
530  */
531 void
532 mwl_hal_txstart(struct mwl_hal *mh0, int qnum)
533 {
534 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
535 	uint32_t dummy;
536 
537 	WR4(mh, MACREG_REG_H2A_INTERRUPT_EVENTS, MACREG_H2ARIC_BIT_PPA_READY);
538 	dummy = RD4(mh, MACREG_REG_INT_CODE);
539 }
540 #endif
541 
542 /*
543  * Callback from the driver on a cmd done interrupt.
544  * Nothing to do right now as we spin waiting for
545  * cmd completion.
546  */
547 void
548 mwl_hal_cmddone(struct mwl_hal *mh0)
549 {
550 #if 0
551 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
552 
553 	if (mh->mh_debug & MWL_HAL_DEBUG_CMDDONE) {
554 		device_printf(mh->mh_dev, "cmd done interrupt:\n");
555 		dumpresult(mh, 1);
556 	}
557 #endif
558 }
559 
560 /*
561  * Return "hw specs".  Note this must be the first
562  * cmd MUST be done after a firmware download or the
563  * f/w will lockup.
564  * XXX move into the hal so driver doesn't need to be responsible
565  */
566 int
567 mwl_hal_gethwspecs(struct mwl_hal *mh0, struct mwl_hal_hwspec *hw)
568 {
569 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
570 	HostCmd_DS_GET_HW_SPEC *pCmd;
571 	int retval, minrev;
572 
573 	MWL_HAL_LOCK(mh);
574 	_CMD_SETUP(pCmd, HostCmd_DS_GET_HW_SPEC, HostCmd_CMD_GET_HW_SPEC);
575 	memset(&pCmd->PermanentAddr[0], 0xff, IEEE80211_ADDR_LEN);
576 	pCmd->ulFwAwakeCookie = htole32((unsigned int)mh->mh_cmdaddr+2048);
577 
578 	retval = mwlExecuteCmd(mh, HostCmd_CMD_GET_HW_SPEC);
579 	if (retval == 0) {
580 		IEEE80211_ADDR_COPY(hw->macAddr, pCmd->PermanentAddr);
581 		hw->wcbBase[0] = le32toh(pCmd->WcbBase0) & 0x0000ffff;
582 		hw->wcbBase[1] = le32toh(pCmd->WcbBase1[0]) & 0x0000ffff;
583 		hw->wcbBase[2] = le32toh(pCmd->WcbBase1[1]) & 0x0000ffff;
584 		hw->wcbBase[3] = le32toh(pCmd->WcbBase1[2]) & 0x0000ffff;
585 		hw->rxDescRead = le32toh(pCmd->RxPdRdPtr)& 0x0000ffff;
586 		hw->rxDescWrite = le32toh(pCmd->RxPdWrPtr)& 0x0000ffff;
587 		hw->regionCode = le16toh(pCmd->RegionCode) & 0x00ff;
588 		hw->fwReleaseNumber = le32toh(pCmd->FWReleaseNumber);
589 		hw->maxNumWCB = le16toh(pCmd->NumOfWCB);
590 		hw->maxNumMCAddr = le16toh(pCmd->NumOfMCastAddr);
591 		hw->numAntennas = le16toh(pCmd->NumberOfAntenna);
592 		hw->hwVersion = pCmd->Version;
593 		hw->hostInterface = pCmd->HostIf;
594 
595 		mh->mh_revs.mh_macRev = hw->hwVersion;		/* XXX */
596 		mh->mh_revs.mh_phyRev = hw->hostInterface;	/* XXX */
597 
598 		minrev = ((hw->fwReleaseNumber) >> 16) & 0xff;
599 		if (minrev >= 4) {
600 			/* starting with 3.4.x.x s/w BA streams supported */
601 			mh->mh_bastreams &= (1<<MWL_BASTREAMS_MAX)-1;
602 		} else
603 			mh->mh_bastreams &= (1<<2)-1;
604 	}
605 	MWL_HAL_UNLOCK(mh);
606 	return retval;
607 }
608 
609 /*
610  * Inform the f/w about location of the tx/rx dma data structures
611  * and related state.  This cmd must be done immediately after a
612  * mwl_hal_gethwspecs call or the f/w will lockup.
613  */
614 int
615 mwl_hal_sethwdma(struct mwl_hal *mh0, const struct mwl_hal_txrxdma *dma)
616 {
617 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
618 	HostCmd_DS_SET_HW_SPEC *pCmd;
619 	int retval;
620 
621 	MWL_HAL_LOCK(mh);
622 	_CMD_SETUP(pCmd, HostCmd_DS_SET_HW_SPEC, HostCmd_CMD_SET_HW_SPEC);
623 	pCmd->WcbBase[0] = htole32(dma->wcbBase[0]);
624 	pCmd->WcbBase[1] = htole32(dma->wcbBase[1]);
625 	pCmd->WcbBase[2] = htole32(dma->wcbBase[2]);
626 	pCmd->WcbBase[3] = htole32(dma->wcbBase[3]);
627 	pCmd->TxWcbNumPerQueue = htole32(dma->maxNumTxWcb);
628 	pCmd->NumTxQueues = htole32(dma->maxNumWCB);
629 	pCmd->TotalRxWcb = htole32(1);		/* XXX */
630 	pCmd->RxPdWrPtr = htole32(dma->rxDescRead);
631 	pCmd->Flags = htole32(SET_HW_SPEC_HOSTFORM_BEACON
632 #ifdef MWL_HOST_PS_SUPPORT
633 		    | SET_HW_SPEC_HOST_POWERSAVE
634 #endif
635 		    | SET_HW_SPEC_HOSTFORM_PROBERESP);
636 	/* disable multi-bss operation for A1-A4 parts */
637 	if (mh->mh_revs.mh_macRev < 5)
638 		pCmd->Flags |= htole32(SET_HW_SPEC_DISABLEMBSS);
639 
640 	retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_HW_SPEC);
641 	if (retval == 0) {
642 		if (pCmd->Flags & htole32(SET_HW_SPEC_DISABLEMBSS))
643 			mh->mh_flags &= ~MHF_MBSS;
644 		else
645 			mh->mh_flags |= MHF_MBSS;
646 	}
647 	MWL_HAL_UNLOCK(mh);
648 	return retval;
649 }
650 
651 /*
652  * Retrieve statistics from the f/w.
653  * XXX should be in memory shared w/ driver
654  */
655 int
656 mwl_hal_gethwstats(struct mwl_hal *mh0, struct mwl_hal_hwstats *stats)
657 {
658 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
659 	HostCmd_DS_802_11_GET_STAT *pCmd;
660 	int retval;
661 
662 	MWL_HAL_LOCK(mh);
663 	_CMD_SETUP(pCmd, HostCmd_DS_802_11_GET_STAT,
664 		HostCmd_CMD_802_11_GET_STAT);
665 
666 	retval = mwlExecuteCmd(mh, HostCmd_CMD_802_11_GET_STAT);
667 	if (retval == 0) {
668 		const uint32_t *sp = (const uint32_t *)&pCmd->TxRetrySuccesses;
669 		uint32_t *dp = (uint32_t *)&stats->TxRetrySuccesses;
670 		int i;
671 
672 		for (i = 0; i < sizeof(*stats)/sizeof(uint32_t); i++)
673 			dp[i] = le32toh(sp[i]);
674 		/*
675 		 * Update stats not returned by f/w but available
676 		 * through public registers.  Note these registers
677 		 * are "clear on read" so we maintain cumulative data.
678 		 * XXX register defines
679 		 */
680 		mh->mh_RTSSuccesses += RD4(mh, 0xa834);
681 		mh->mh_RTSFailures += RD4(mh, 0xa830);
682 		mh->mh_RxDuplicateFrames += RD4(mh, 0xa84c);
683 		mh->mh_FCSErrorCount += RD4(mh, 0xa840);
684 	}
685 	MWL_HAL_UNLOCK(mh);
686 
687 	stats->RTSSuccesses = mh->mh_RTSSuccesses;
688 	stats->RTSFailures = mh->mh_RTSFailures;
689 	stats->RxDuplicateFrames = mh->mh_RxDuplicateFrames;
690 	stats->FCSErrorCount = mh->mh_FCSErrorCount;
691 	return retval;
692 }
693 
694 /*
695  * Set HT guard interval handling.
696  * Takes effect immediately.
697  */
698 int
699 mwl_hal_sethtgi(struct mwl_hal_vap *vap, int GIType)
700 {
701 	struct mwl_hal_priv *mh = MWLVAP(vap);
702 	HostCmd_FW_HT_GUARD_INTERVAL *pCmd;
703 	int retval;
704 
705 	MWL_HAL_LOCK(mh);
706 	_VCMD_SETUP(vap, pCmd, HostCmd_FW_HT_GUARD_INTERVAL,
707 		HostCmd_CMD_HT_GUARD_INTERVAL);
708 	pCmd->Action = htole32(HostCmd_ACT_GEN_SET);
709 
710 	if (GIType == 0) {
711 		pCmd->GIType = htole32(GI_TYPE_LONG);
712 	} else if (GIType == 1) {
713 		pCmd->GIType = htole32(GI_TYPE_LONG | GI_TYPE_SHORT);
714 	} else {
715 		pCmd->GIType = htole32(GI_TYPE_LONG);
716 	}
717 
718 	retval = mwlExecuteCmd(mh, HostCmd_CMD_HT_GUARD_INTERVAL);
719 	MWL_HAL_UNLOCK(mh);
720 	return retval;
721 }
722 
723 /*
724  * Configure radio.
725  * Takes effect immediately.
726  * XXX preamble installed after set fixed rate cmd
727  */
728 int
729 mwl_hal_setradio(struct mwl_hal *mh0, int onoff, MWL_HAL_PREAMBLE preamble)
730 {
731 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
732 	HostCmd_DS_802_11_RADIO_CONTROL *pCmd;
733 	int retval;
734 
735 	MWL_HAL_LOCK(mh);
736 	_CMD_SETUP(pCmd, HostCmd_DS_802_11_RADIO_CONTROL,
737 		HostCmd_CMD_802_11_RADIO_CONTROL);
738 	pCmd->Action = htole16(HostCmd_ACT_GEN_SET);
739 	if (onoff == 0)
740 		pCmd->Control = 0;
741 	else
742 		pCmd->Control = htole16(preamble);
743 	pCmd->RadioOn = htole16(onoff);
744 
745 	retval = mwlExecuteCmd(mh, HostCmd_CMD_802_11_RADIO_CONTROL);
746 	MWL_HAL_UNLOCK(mh);
747 	return retval;
748 }
749 
750 /*
751  * Configure antenna use.
752  * Takes effect immediately.
753  * XXX tx antenna setting ignored
754  * XXX rx antenna setting should always be 3 (for now)
755  */
756 int
757 mwl_hal_setantenna(struct mwl_hal *mh0, MWL_HAL_ANTENNA dirSet, int ant)
758 {
759 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
760 	HostCmd_DS_802_11_RF_ANTENNA *pCmd;
761 	int retval;
762 
763 	if (!(dirSet == WL_ANTENNATYPE_RX || dirSet == WL_ANTENNATYPE_TX))
764 		return EINVAL;
765 
766 	MWL_HAL_LOCK(mh);
767 	_CMD_SETUP(pCmd, HostCmd_DS_802_11_RF_ANTENNA,
768 		HostCmd_CMD_802_11_RF_ANTENNA);
769 	pCmd->Action = htole16(dirSet);
770 	if (ant == 0)			/* default to all/both antennae */
771 		ant = 3;
772 	pCmd->AntennaMode = htole16(ant);
773 
774 	retval = mwlExecuteCmd(mh, HostCmd_CMD_802_11_RF_ANTENNA);
775 	MWL_HAL_UNLOCK(mh);
776 	return retval;
777 }
778 
779 /*
780  * Set packet size threshold for implicit use of RTS.
781  * Takes effect immediately.
782  * XXX packet length > threshold =>'s RTS
783  */
784 int
785 mwl_hal_setrtsthreshold(struct mwl_hal_vap *vap, int threshold)
786 {
787 	struct mwl_hal_priv *mh = MWLVAP(vap);
788 	HostCmd_DS_802_11_RTS_THSD *pCmd;
789 	int retval;
790 
791 	MWL_HAL_LOCK(mh);
792 	_VCMD_SETUP(vap, pCmd, HostCmd_DS_802_11_RTS_THSD,
793 		HostCmd_CMD_802_11_RTS_THSD);
794 	pCmd->Action  = htole16(HostCmd_ACT_GEN_SET);
795 	pCmd->Threshold = htole16(threshold);
796 
797 	retval = mwlExecuteCmd(mh, HostCmd_CMD_802_11_RTS_THSD);
798 	MWL_HAL_UNLOCK(mh);
799 	return retval;
800 }
801 
802 /*
803  * Enable sta-mode operation (disables beacon frame xmit).
804  */
805 int
806 mwl_hal_setinframode(struct mwl_hal_vap *vap)
807 {
808 	struct mwl_hal_priv *mh = MWLVAP(vap);
809 	HostCmd_FW_SET_INFRA_MODE *pCmd;
810 	int retval;
811 
812 	MWL_HAL_LOCK(mh);
813 	_VCMD_SETUP(vap, pCmd, HostCmd_FW_SET_INFRA_MODE,
814 		HostCmd_CMD_SET_INFRA_MODE);
815 
816 	retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_INFRA_MODE);
817 	MWL_HAL_UNLOCK(mh);
818 	return retval;
819 }
820 
821 /*
822  * Configure radar detection in support of 802.11h.
823  */
824 int
825 mwl_hal_setradardetection(struct mwl_hal *mh0, MWL_HAL_RADAR action)
826 {
827 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
828 	HostCmd_802_11h_Detect_Radar *pCmd;
829 	int retval;
830 
831 	MWL_HAL_LOCK(mh);
832 	_CMD_SETUP(pCmd, HostCmd_802_11h_Detect_Radar,
833 		HostCmd_CMD_802_11H_DETECT_RADAR);
834 	pCmd->CmdHdr.Length = htole16(sizeof(HostCmd_802_11h_Detect_Radar));
835 	pCmd->Action = htole16(action);
836 	if (mh->mh_regioncode == DOMAIN_CODE_ETSI_131)
837 		pCmd->RadarTypeCode = htole16(131);
838 
839 	retval = mwlExecuteCmd(mh, HostCmd_CMD_802_11H_DETECT_RADAR);
840 	MWL_HAL_UNLOCK(mh);
841 	return retval;
842 }
843 
844 /*
845  * Convert public channel flags definition to a
846  * value suitable for feeding to the firmware.
847  * Note this includes byte swapping.
848  */
849 static uint32_t
850 cvtChannelFlags(const MWL_HAL_CHANNEL *chan)
851 {
852 	uint32_t w;
853 
854 	/*
855 	 * NB: f/w only understands FREQ_BAND_5GHZ, supplying the more
856 	 *     precise band info causes it to lockup (sometimes).
857 	 */
858 	w = (chan->channelFlags.FreqBand == MWL_FREQ_BAND_2DOT4GHZ) ?
859 		FREQ_BAND_2DOT4GHZ : FREQ_BAND_5GHZ;
860 	switch (chan->channelFlags.ChnlWidth) {
861 	case MWL_CH_10_MHz_WIDTH:
862 		w |= CH_10_MHz_WIDTH;
863 		break;
864 	case MWL_CH_20_MHz_WIDTH:
865 		w |= CH_20_MHz_WIDTH;
866 		break;
867 	case MWL_CH_40_MHz_WIDTH:
868 	default:
869 		w |= CH_40_MHz_WIDTH;
870 		break;
871 	}
872 	switch (chan->channelFlags.ExtChnlOffset) {
873 	case MWL_EXT_CH_NONE:
874 		w |= EXT_CH_NONE;
875 		break;
876 	case MWL_EXT_CH_ABOVE_CTRL_CH:
877 		w |= EXT_CH_ABOVE_CTRL_CH;
878 		break;
879 	case MWL_EXT_CH_BELOW_CTRL_CH:
880 		w |= EXT_CH_BELOW_CTRL_CH;
881 		break;
882 	}
883 	return htole32(w);
884 }
885 
886 /*
887  * Start a channel switch announcement countdown.  The IE
888  * in the beacon frame is allowed to go out and the firmware
889  * counts down and notifies the host when it's time to switch
890  * channels.
891  */
892 int
893 mwl_hal_setchannelswitchie(struct mwl_hal *mh0,
894 	const MWL_HAL_CHANNEL *nextchan, uint32_t mode, uint32_t count)
895 {
896 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
897 	HostCmd_SET_SWITCH_CHANNEL *pCmd;
898 	int retval;
899 
900 	MWL_HAL_LOCK(mh);
901 	_CMD_SETUP(pCmd, HostCmd_SET_SWITCH_CHANNEL,
902 		HostCmd_CMD_SET_SWITCH_CHANNEL);
903 	pCmd->Next11hChannel = htole32(nextchan->channel);
904 	pCmd->Mode = htole32(mode);
905 	pCmd->InitialCount = htole32(count+1);
906 	pCmd->ChannelFlags = cvtChannelFlags(nextchan);
907 
908 	retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_SWITCH_CHANNEL);
909 	MWL_HAL_UNLOCK(mh);
910 	return retval;
911 }
912 
913 /*
914  * Set the region code that selects the radar bin'ing agorithm.
915  */
916 int
917 mwl_hal_setregioncode(struct mwl_hal *mh0, int regionCode)
918 {
919 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
920 	HostCmd_SET_REGIONCODE_INFO *pCmd;
921 	int retval;
922 
923 	MWL_HAL_LOCK(mh);
924 	_CMD_SETUP(pCmd, HostCmd_SET_REGIONCODE_INFO,
925 		HostCmd_CMD_SET_REGION_CODE);
926 	/* XXX map pseudo-codes to fw codes */
927 	switch (regionCode) {
928 	case DOMAIN_CODE_ETSI_131:
929 		pCmd->regionCode = htole16(DOMAIN_CODE_ETSI);
930 		break;
931 	default:
932 		pCmd->regionCode = htole16(regionCode);
933 		break;
934 	}
935 
936 	retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_REGION_CODE);
937 	if (retval == 0)
938 		mh->mh_regioncode = regionCode;
939 	MWL_HAL_UNLOCK(mh);
940 	return retval;
941 }
942 
943 #define	RATEVAL(r)	((r) &~ RATE_MCS)
944 #define	RATETYPE(r)	(((r) & RATE_MCS) ? HT_RATE_TYPE : LEGACY_RATE_TYPE)
945 
946 int
947 mwl_hal_settxrate(struct mwl_hal_vap *vap, MWL_HAL_TXRATE_HANDLING handling,
948 	const MWL_HAL_TXRATE *rate)
949 {
950 	struct mwl_hal_priv *mh = MWLVAP(vap);
951 	HostCmd_FW_USE_FIXED_RATE *pCmd;
952 	FIXED_RATE_ENTRY *fp;
953 	int retval, i, n;
954 
955 	MWL_HAL_LOCK(mh);
956 	_VCMD_SETUP(vap, pCmd, HostCmd_FW_USE_FIXED_RATE,
957 		HostCmd_CMD_SET_FIXED_RATE);
958 
959 	pCmd->MulticastRate = RATEVAL(rate->McastRate);
960 	pCmd->MultiRateTxType = RATETYPE(rate->McastRate);
961 	/* NB: no rate type field */
962 	pCmd->ManagementRate = RATEVAL(rate->MgtRate);
963 	memset(pCmd->FixedRateTable, 0, sizeof(pCmd->FixedRateTable));
964 	if (handling == RATE_FIXED) {
965 		pCmd->Action = htole32(HostCmd_ACT_GEN_SET);
966 		pCmd->AllowRateDrop = htole32(FIXED_RATE_WITHOUT_AUTORATE_DROP);
967 		fp = pCmd->FixedRateTable;
968 		fp->FixedRate =
969 		    htole32(RATEVAL(rate->RateSeries[0].Rate));
970 		fp->FixRateTypeFlags.FixRateType =
971 		    htole32(RATETYPE(rate->RateSeries[0].Rate));
972 		pCmd->EntryCount = htole32(1);
973 	} else if (handling == RATE_FIXED_DROP) {
974 		pCmd->Action = htole32(HostCmd_ACT_GEN_SET);
975 		pCmd->AllowRateDrop = htole32(FIXED_RATE_WITH_AUTO_RATE_DROP);
976 		n = 0;
977 		fp = pCmd->FixedRateTable;
978 		for (i = 0; i < 4; i++) {
979 			if (rate->RateSeries[0].TryCount == 0)
980 				break;
981 			fp->FixRateTypeFlags.FixRateType =
982 			    htole32(RATETYPE(rate->RateSeries[i].Rate));
983 			fp->FixedRate =
984 			    htole32(RATEVAL(rate->RateSeries[i].Rate));
985 			fp->FixRateTypeFlags.RetryCountValid =
986 			    htole32(RETRY_COUNT_VALID);
987 			fp->RetryCount =
988 			    htole32(rate->RateSeries[i].TryCount-1);
989 			n++;
990 		}
991 		pCmd->EntryCount = htole32(n);
992 	} else
993 		pCmd->Action = htole32(HostCmd_ACT_NOT_USE_FIXED_RATE);
994 
995 	retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_FIXED_RATE);
996 	MWL_HAL_UNLOCK(mh);
997 	return retval;
998 }
999 
1000 int
1001 mwl_hal_settxrate_auto(struct mwl_hal *mh0, const MWL_HAL_TXRATE *rate)
1002 {
1003 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
1004 	HostCmd_FW_USE_FIXED_RATE *pCmd;
1005 	int retval;
1006 
1007 	MWL_HAL_LOCK(mh);
1008 	_CMD_SETUP(pCmd, HostCmd_FW_USE_FIXED_RATE,
1009 		HostCmd_CMD_SET_FIXED_RATE);
1010 
1011 	pCmd->MulticastRate = RATEVAL(rate->McastRate);
1012 	pCmd->MultiRateTxType = RATETYPE(rate->McastRate);
1013 	/* NB: no rate type field */
1014 	pCmd->ManagementRate = RATEVAL(rate->MgtRate);
1015 	memset(pCmd->FixedRateTable, 0, sizeof(pCmd->FixedRateTable));
1016 	pCmd->Action = htole32(HostCmd_ACT_NOT_USE_FIXED_RATE);
1017 
1018 	retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_FIXED_RATE);
1019 	MWL_HAL_UNLOCK(mh);
1020 	return retval;
1021 }
1022 
1023 #undef RATEVAL
1024 #undef RATETYPE
1025 
1026 int
1027 mwl_hal_setslottime(struct mwl_hal *mh0, int usecs)
1028 {
1029 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
1030 	HostCmd_FW_SET_SLOT *pCmd;
1031 	int retval;
1032 
1033 	if (usecs != 9 && usecs != 20)
1034 		return EINVAL;
1035 
1036 	MWL_HAL_LOCK(mh);
1037 	_CMD_SETUP(pCmd, HostCmd_FW_SET_SLOT,
1038 	    HostCmd_CMD_802_11_SET_SLOT);
1039 	pCmd->Action = htole16(HostCmd_ACT_GEN_SET);
1040 	pCmd->Slot = (usecs == 9 ? 1 : 0);
1041 
1042 	retval = mwlExecuteCmd(mh, HostCmd_CMD_802_11_SET_SLOT);
1043 	MWL_HAL_UNLOCK(mh);
1044 	return retval;
1045 }
1046 
1047 int
1048 mwl_hal_adjusttxpower(struct mwl_hal *mh0, uint32_t level)
1049 {
1050 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
1051 	HostCmd_DS_802_11_RF_TX_POWER *pCmd;
1052 	int retval;
1053 
1054 	MWL_HAL_LOCK(mh);
1055 	_CMD_SETUP(pCmd, HostCmd_DS_802_11_RF_TX_POWER,
1056 	    HostCmd_CMD_802_11_RF_TX_POWER);
1057 	pCmd->Action = htole16(HostCmd_ACT_GEN_SET);
1058 
1059 	if (level < 30) {
1060 		pCmd->SupportTxPowerLevel = htole16(WL_TX_POWERLEVEL_LOW);
1061 	} else if (level >= 30 && level < 60) {
1062 		pCmd->SupportTxPowerLevel = htole16(WL_TX_POWERLEVEL_MEDIUM);
1063 	} else {
1064 		pCmd->SupportTxPowerLevel = htole16(WL_TX_POWERLEVEL_HIGH);
1065 	}
1066 
1067 	retval = mwlExecuteCmd(mh, HostCmd_CMD_802_11_RF_TX_POWER);
1068 	MWL_HAL_UNLOCK(mh);
1069 	return retval;
1070 }
1071 
1072 static const struct mwl_hal_channel *
1073 findchannel(const struct mwl_hal_priv *mh, const MWL_HAL_CHANNEL *c)
1074 {
1075 	const struct mwl_hal_channel *hc;
1076 	const MWL_HAL_CHANNELINFO *ci;
1077 	int chan = c->channel, i;
1078 
1079 	if (c->channelFlags.FreqBand == MWL_FREQ_BAND_2DOT4GHZ) {
1080 		i = chan - 1;
1081 		if (c->channelFlags.ChnlWidth == MWL_CH_40_MHz_WIDTH) {
1082 			ci = &mh->mh_40M;
1083 			if (c->channelFlags.ExtChnlOffset == MWL_EXT_CH_BELOW_CTRL_CH)
1084 				i -= 4;
1085 		} else
1086 			ci = &mh->mh_20M;
1087 		/* 2.4G channel table is directly indexed */
1088 		hc = ((unsigned)i < ci->nchannels) ? &ci->channels[i] : NULL;
1089 	} else if (c->channelFlags.FreqBand == MWL_FREQ_BAND_5GHZ) {
1090 		if (c->channelFlags.ChnlWidth == MWL_CH_40_MHz_WIDTH) {
1091 			ci = &mh->mh_40M_5G;
1092 			if (c->channelFlags.ExtChnlOffset == MWL_EXT_CH_BELOW_CTRL_CH)
1093 				chan -= 4;
1094 		} else
1095 			ci = &mh->mh_20M_5G;
1096 		/* 5GHz channel table is sparse and must be searched */
1097 		for (i = 0; i < ci->nchannels; i++)
1098 			if (ci->channels[i].ieee == chan)
1099 				break;
1100 		hc = (i < ci->nchannels) ? &ci->channels[i] : NULL;
1101 	} else
1102 		hc = NULL;
1103 	return hc;
1104 }
1105 
1106 int
1107 mwl_hal_settxpower(struct mwl_hal *mh0, const MWL_HAL_CHANNEL *c, uint8_t maxtxpow)
1108 {
1109 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
1110 	HostCmd_DS_802_11_RF_TX_POWER *pCmd;
1111 	const struct mwl_hal_channel *hc;
1112 	int i, retval;
1113 
1114 	hc = findchannel(mh, c);
1115 	if (hc == NULL) {
1116 		/* XXX temp while testing */
1117 		device_printf(mh->mh_dev,
1118 		    "%s: no cal data for channel %u band %u width %u ext %u\n",
1119 		    __func__, c->channel, c->channelFlags.FreqBand,
1120 		    c->channelFlags.ChnlWidth, c->channelFlags.ExtChnlOffset);
1121 		return EINVAL;
1122 	}
1123 
1124 	MWL_HAL_LOCK(mh);
1125 	_CMD_SETUP(pCmd, HostCmd_DS_802_11_RF_TX_POWER,
1126 	    HostCmd_CMD_802_11_RF_TX_POWER);
1127 	pCmd->Action = htole16(HostCmd_ACT_GEN_SET_LIST);
1128 	i = 0;
1129 	/* NB: 5Ghz cal data have the channel # in [0]; don't truncate */
1130 	if (c->channelFlags.FreqBand == MWL_FREQ_BAND_5GHZ)
1131 		pCmd->PowerLevelList[i++] = htole16(hc->targetPowers[0]);
1132 	for (; i < 4; i++) {
1133 		uint16_t pow = hc->targetPowers[i];
1134 		if (pow > maxtxpow)
1135 			pow = maxtxpow;
1136 		pCmd->PowerLevelList[i] = htole16(pow);
1137 	}
1138 	retval = mwlExecuteCmd(mh, HostCmd_CMD_802_11_RF_TX_POWER);
1139 	MWL_HAL_UNLOCK(mh);
1140 	return retval;
1141 }
1142 
1143 int
1144 mwl_hal_getchannelinfo(struct mwl_hal *mh0, int band, int chw,
1145 	const MWL_HAL_CHANNELINFO **ci)
1146 {
1147 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
1148 
1149 	switch (band) {
1150 	case MWL_FREQ_BAND_2DOT4GHZ:
1151 		*ci = (chw == MWL_CH_20_MHz_WIDTH) ? &mh->mh_20M : &mh->mh_40M;
1152 		break;
1153 	case MWL_FREQ_BAND_5GHZ:
1154 		*ci = (chw == MWL_CH_20_MHz_WIDTH) ?
1155 		     &mh->mh_20M_5G : &mh->mh_40M_5G;
1156 		break;
1157 	default:
1158 		return EINVAL;
1159 	}
1160 	return ((*ci)->freqLow == (*ci)->freqHigh) ? EINVAL : 0;
1161 }
1162 
1163 int
1164 mwl_hal_setmcast(struct mwl_hal *mh0, int nmc, const uint8_t macs[])
1165 {
1166 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
1167 	HostCmd_DS_MAC_MULTICAST_ADR *pCmd;
1168 	int retval;
1169 
1170 	if (nmc > MWL_HAL_MCAST_MAX)
1171 		return EINVAL;
1172 
1173 	MWL_HAL_LOCK(mh);
1174 	_CMD_SETUP(pCmd, HostCmd_DS_MAC_MULTICAST_ADR,
1175 		HostCmd_CMD_MAC_MULTICAST_ADR);
1176 	memcpy(pCmd->MACList, macs, nmc*IEEE80211_ADDR_LEN);
1177 	pCmd->NumOfAdrs = htole16(nmc);
1178 	pCmd->Action = htole16(0xffff);
1179 
1180 	retval = mwlExecuteCmd(mh, HostCmd_CMD_MAC_MULTICAST_ADR);
1181 	MWL_HAL_UNLOCK(mh);
1182 	return retval;
1183 }
1184 
1185 int
1186 mwl_hal_keyset(struct mwl_hal_vap *vap, const MWL_HAL_KEYVAL *kv,
1187 	const uint8_t mac[IEEE80211_ADDR_LEN])
1188 {
1189 	struct mwl_hal_priv *mh = MWLVAP(vap);
1190 	HostCmd_FW_UPDATE_ENCRYPTION_SET_KEY *pCmd;
1191 	int retval;
1192 
1193 	MWL_HAL_LOCK(mh);
1194 	_VCMD_SETUP(vap, pCmd, HostCmd_FW_UPDATE_ENCRYPTION_SET_KEY,
1195 		HostCmd_CMD_UPDATE_ENCRYPTION);
1196 	if (kv->keyFlags & (KEY_FLAG_TXGROUPKEY|KEY_FLAG_RXGROUPKEY))
1197 		pCmd->ActionType = htole32(EncrActionTypeSetGroupKey);
1198 	else
1199 		pCmd->ActionType = htole32(EncrActionTypeSetKey);
1200 	pCmd->KeyParam.Length = htole16(sizeof(pCmd->KeyParam));
1201 	pCmd->KeyParam.KeyTypeId = htole16(kv->keyTypeId);
1202 	pCmd->KeyParam.KeyInfo = htole32(kv->keyFlags);
1203 	pCmd->KeyParam.KeyIndex = htole32(kv->keyIndex);
1204 	/* NB: includes TKIP MIC keys */
1205 	memcpy(&pCmd->KeyParam.Key, &kv->key, kv->keyLen);
1206 	switch (kv->keyTypeId) {
1207 	case KEY_TYPE_ID_WEP:
1208 		pCmd->KeyParam.KeyLen = htole16(kv->keyLen);
1209 		break;
1210 	case KEY_TYPE_ID_TKIP:
1211 		pCmd->KeyParam.KeyLen = htole16(sizeof(TKIP_TYPE_KEY));
1212 		pCmd->KeyParam.Key.TkipKey.TkipRsc.low =
1213 			htole16(kv->key.tkip.rsc.low);
1214 		pCmd->KeyParam.Key.TkipKey.TkipRsc.high =
1215 			htole32(kv->key.tkip.rsc.high);
1216 		pCmd->KeyParam.Key.TkipKey.TkipTsc.low =
1217 			htole16(kv->key.tkip.tsc.low);
1218 		pCmd->KeyParam.Key.TkipKey.TkipTsc.high =
1219 			htole32(kv->key.tkip.tsc.high);
1220 		break;
1221 	case KEY_TYPE_ID_AES:
1222 		pCmd->KeyParam.KeyLen = htole16(sizeof(AES_TYPE_KEY));
1223 		break;
1224 	}
1225 #ifdef MWL_MBSS_SUPPORT
1226 	IEEE80211_ADDR_COPY(pCmd->KeyParam.Macaddr, mac);
1227 #else
1228 	IEEE80211_ADDR_COPY(pCmd->Macaddr, mac);
1229 #endif
1230 	retval = mwlExecuteCmd(mh, HostCmd_CMD_UPDATE_ENCRYPTION);
1231 	MWL_HAL_UNLOCK(mh);
1232 	return retval;
1233 }
1234 
1235 int
1236 mwl_hal_keyreset(struct mwl_hal_vap *vap, const MWL_HAL_KEYVAL *kv, const uint8_t mac[IEEE80211_ADDR_LEN])
1237 {
1238 	struct mwl_hal_priv *mh = MWLVAP(vap);
1239 	HostCmd_FW_UPDATE_ENCRYPTION_SET_KEY *pCmd;
1240 	int retval;
1241 
1242 	MWL_HAL_LOCK(mh);
1243 	_VCMD_SETUP(vap, pCmd, HostCmd_FW_UPDATE_ENCRYPTION_SET_KEY,
1244 		HostCmd_CMD_UPDATE_ENCRYPTION);
1245 	pCmd->ActionType = htole16(EncrActionTypeRemoveKey);
1246 	pCmd->KeyParam.Length = htole16(sizeof(pCmd->KeyParam));
1247 	pCmd->KeyParam.KeyTypeId = htole16(kv->keyTypeId);
1248 	pCmd->KeyParam.KeyInfo = htole32(kv->keyFlags);
1249 	pCmd->KeyParam.KeyIndex = htole32(kv->keyIndex);
1250 #ifdef MWL_MBSS_SUPPORT
1251 	IEEE80211_ADDR_COPY(pCmd->KeyParam.Macaddr, mac);
1252 #else
1253 	IEEE80211_ADDR_COPY(pCmd->Macaddr, mac);
1254 #endif
1255 	retval = mwlExecuteCmd(mh, HostCmd_CMD_UPDATE_ENCRYPTION);
1256 	MWL_HAL_UNLOCK(mh);
1257 	return retval;
1258 }
1259 
1260 static int
1261 mwl_hal_setmac_locked(struct mwl_hal_vap *vap,
1262 	const uint8_t addr[IEEE80211_ADDR_LEN])
1263 {
1264 	struct mwl_hal_priv *mh = MWLVAP(vap);
1265 	HostCmd_DS_SET_MAC *pCmd;
1266 
1267 	_VCMD_SETUP(vap, pCmd, HostCmd_DS_SET_MAC, HostCmd_CMD_SET_MAC_ADDR);
1268 	IEEE80211_ADDR_COPY(&pCmd->MacAddr[0], addr);
1269 #ifdef MWL_MBSS_SUPPORT
1270 	pCmd->MacType = vap->bss_type;		/* NB: already byte swapped */
1271 	IEEE80211_ADDR_COPY(vap->mac, addr);	/* XXX do only if success */
1272 #endif
1273 	return mwlExecuteCmd(mh, HostCmd_CMD_SET_MAC_ADDR);
1274 }
1275 
1276 int
1277 mwl_hal_setmac(struct mwl_hal_vap *vap, const uint8_t addr[IEEE80211_ADDR_LEN])
1278 {
1279 	struct mwl_hal_priv *mh = MWLVAP(vap);
1280 	int retval;
1281 
1282 	MWL_HAL_LOCK(mh);
1283 	retval = mwl_hal_setmac_locked(vap, addr);
1284 	MWL_HAL_UNLOCK(mh);
1285 	return retval;
1286 }
1287 
1288 int
1289 mwl_hal_setbeacon(struct mwl_hal_vap *vap, const void *frame, size_t frameLen)
1290 {
1291 	struct mwl_hal_priv *mh = MWLVAP(vap);
1292 	HostCmd_DS_SET_BEACON *pCmd;
1293 	int retval;
1294 
1295 	/* XXX verify frameLen fits */
1296 	MWL_HAL_LOCK(mh);
1297 	_VCMD_SETUP(vap, pCmd, HostCmd_DS_SET_BEACON, HostCmd_CMD_SET_BEACON);
1298 	/* XXX override _VCMD_SETUP */
1299 	pCmd->CmdHdr.Length = htole16(sizeof(HostCmd_DS_SET_BEACON)-1+frameLen);
1300 	pCmd->FrmBodyLen = htole16(frameLen);
1301 	memcpy(pCmd->FrmBody, frame, frameLen);
1302 
1303 	retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_BEACON);
1304 	MWL_HAL_UNLOCK(mh);
1305 	return retval;
1306 }
1307 
1308 int
1309 mwl_hal_setpowersave_bss(struct mwl_hal_vap *vap, uint8_t nsta)
1310 {
1311 	struct mwl_hal_priv *mh = MWLVAP(vap);
1312 	HostCmd_SET_POWERSAVESTATION *pCmd;
1313 	int retval;
1314 
1315 	MWL_HAL_LOCK(mh);
1316 	_VCMD_SETUP(vap, pCmd, HostCmd_SET_POWERSAVESTATION,
1317 		HostCmd_CMD_SET_POWERSAVESTATION);
1318 	pCmd->NumberOfPowersave = nsta;
1319 
1320 	retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_POWERSAVESTATION);
1321 	MWL_HAL_UNLOCK(mh);
1322 	return retval;
1323 }
1324 
1325 int
1326 mwl_hal_setpowersave_sta(struct mwl_hal_vap *vap, uint16_t aid, int ena)
1327 {
1328 	struct mwl_hal_priv *mh = MWLVAP(vap);
1329 	HostCmd_SET_TIM *pCmd;
1330 	int retval;
1331 
1332 	MWL_HAL_LOCK(mh);
1333 	_VCMD_SETUP(vap, pCmd, HostCmd_SET_TIM, HostCmd_CMD_SET_TIM);
1334 	pCmd->Aid = htole16(aid);
1335 	pCmd->Set = htole32(ena);
1336 
1337 	retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_TIM);
1338 	MWL_HAL_UNLOCK(mh);
1339 	return retval;
1340 }
1341 
1342 int
1343 mwl_hal_setassocid(struct mwl_hal_vap *vap,
1344 	const uint8_t bssId[IEEE80211_ADDR_LEN], uint16_t assocId)
1345 {
1346 	struct mwl_hal_priv *mh = MWLVAP(vap);
1347 	HostCmd_FW_SET_AID *pCmd = (HostCmd_FW_SET_AID *) &mh->mh_cmdbuf[0];
1348 	int retval;
1349 
1350 	MWL_HAL_LOCK(mh);
1351 	_VCMD_SETUP(vap, pCmd, HostCmd_FW_SET_AID, HostCmd_CMD_SET_AID);
1352 	pCmd->AssocID = htole16(assocId);
1353 	IEEE80211_ADDR_COPY(&pCmd->MacAddr[0], bssId);
1354 
1355 	retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_AID);
1356 	MWL_HAL_UNLOCK(mh);
1357 	return retval;
1358 }
1359 
1360 int
1361 mwl_hal_setchannel(struct mwl_hal *mh0, const MWL_HAL_CHANNEL *chan)
1362 {
1363 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
1364 	HostCmd_FW_SET_RF_CHANNEL *pCmd;
1365 	int retval;
1366 
1367 	MWL_HAL_LOCK(mh);
1368 	_CMD_SETUP(pCmd, HostCmd_FW_SET_RF_CHANNEL, HostCmd_CMD_SET_RF_CHANNEL);
1369 	pCmd->Action = htole16(HostCmd_ACT_GEN_SET);
1370 	pCmd->CurrentChannel = chan->channel;
1371 	pCmd->ChannelFlags = cvtChannelFlags(chan);	/* NB: byte-swapped */
1372 
1373 	retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_RF_CHANNEL);
1374 	MWL_HAL_UNLOCK(mh);
1375 	return retval;
1376 }
1377 
1378 static int
1379 bastream_check_available(struct mwl_hal_vap *vap, int qid,
1380 	const uint8_t Macaddr[IEEE80211_ADDR_LEN],
1381 	uint8_t Tid, uint8_t ParamInfo)
1382 {
1383 	struct mwl_hal_priv *mh = MWLVAP(vap);
1384 	HostCmd_FW_BASTREAM *pCmd;
1385 	int retval;
1386 
1387 	MWL_HAL_LOCK_ASSERT(mh);
1388 
1389 	_VCMD_SETUP(vap, pCmd, HostCmd_FW_BASTREAM, HostCmd_CMD_BASTREAM);
1390 	pCmd->ActionType = htole32(BaCheckCreateStream);
1391 	pCmd->BaInfo.CreateParams.BarThrs = htole32(63);
1392 	pCmd->BaInfo.CreateParams.WindowSize = htole32(64);
1393 	pCmd->BaInfo.CreateParams.IdleThrs = htole32(0x22000);
1394 	IEEE80211_ADDR_COPY(&pCmd->BaInfo.CreateParams.PeerMacAddr[0], Macaddr);
1395 	pCmd->BaInfo.CreateParams.DialogToken = 10;
1396 	pCmd->BaInfo.CreateParams.Tid = Tid;
1397 	pCmd->BaInfo.CreateParams.QueueId = qid;
1398 	pCmd->BaInfo.CreateParams.ParamInfo = (uint8_t) ParamInfo;
1399 #if 0
1400 	cvtBAFlags(&pCmd->BaInfo.CreateParams.Flags, sp->ba_policy, 0);
1401 #else
1402 	pCmd->BaInfo.CreateParams.Flags =
1403 			  htole32(BASTREAM_FLAG_IMMEDIATE_TYPE)
1404 			| htole32(BASTREAM_FLAG_DIRECTION_UPSTREAM)
1405 			;
1406 #endif
1407 
1408 	retval = mwlExecuteCmd(mh, HostCmd_CMD_BASTREAM);
1409 	if (retval == 0) {
1410 		/*
1411 		 * NB: BA stream create may fail when the stream is
1412 		 * h/w backed under some (as yet not understood) conditions.
1413 		 * Check the result code to catch this.
1414 		 */
1415 		if (le16toh(pCmd->CmdHdr.Result) != HostCmd_RESULT_OK)
1416 			retval = EIO;
1417 	}
1418 	return retval;
1419 }
1420 
1421 const MWL_HAL_BASTREAM *
1422 mwl_hal_bastream_alloc(struct mwl_hal_vap *vap, int ba_policy,
1423 	const uint8_t Macaddr[IEEE80211_ADDR_LEN],
1424 	uint8_t Tid, uint8_t ParamInfo, void *a1, void *a2)
1425 {
1426 	struct mwl_hal_priv *mh = MWLVAP(vap);
1427 	struct mwl_hal_bastream *sp;
1428 	int s;
1429 
1430 	MWL_HAL_LOCK(mh);
1431 	if (mh->mh_bastreams == 0) {
1432 		/* no streams available */
1433 		MWL_HAL_UNLOCK(mh);
1434 		return NULL;
1435 	}
1436 	for (s = 0; (mh->mh_bastreams & (1<<s)) == 0; s++)
1437 		;
1438 	if (bastream_check_available(vap, s, Macaddr, Tid, ParamInfo)) {
1439 		MWL_HAL_UNLOCK(mh);
1440 		return NULL;
1441 	}
1442 	sp = &mh->mh_streams[s];
1443 	mh->mh_bastreams &= ~(1<<s);
1444 	sp->public.data[0] = a1;
1445 	sp->public.data[1] = a2;
1446 	IEEE80211_ADDR_COPY(sp->macaddr, Macaddr);
1447 	sp->tid = Tid;
1448 	sp->paraminfo = ParamInfo;
1449 	sp->setup = 0;
1450 	sp->ba_policy = ba_policy;
1451 	MWL_HAL_UNLOCK(mh);
1452 	return sp != NULL ? &sp->public : NULL;
1453 }
1454 
1455 const MWL_HAL_BASTREAM *
1456 mwl_hal_bastream_lookup(struct mwl_hal *mh0, int s)
1457 {
1458 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
1459 
1460 	if (!(0 <= s && s < MWL_BASTREAMS_MAX))
1461 		return NULL;
1462 	if (mh->mh_bastreams & (1<<s))
1463 		return NULL;
1464 	return &mh->mh_streams[s].public;
1465 }
1466 
1467 #ifndef	__DECONST
1468 #define	__DECONST(type, var)	((type)(uintptr_t)(const void *)(var))
1469 #endif
1470 
1471 int
1472 mwl_hal_bastream_create(struct mwl_hal_vap *vap,
1473 	const MWL_HAL_BASTREAM *s, int BarThrs, int WindowSize, uint16_t seqno)
1474 {
1475 	struct mwl_hal_priv *mh = MWLVAP(vap);
1476 	struct mwl_hal_bastream *sp = __DECONST(struct mwl_hal_bastream *, s);
1477 	HostCmd_FW_BASTREAM *pCmd;
1478 	int retval;
1479 
1480 	MWL_HAL_LOCK(mh);
1481 	_VCMD_SETUP(vap, pCmd, HostCmd_FW_BASTREAM, HostCmd_CMD_BASTREAM);
1482 	pCmd->ActionType = htole32(BaCreateStream);
1483 	pCmd->BaInfo.CreateParams.BarThrs = htole32(BarThrs);
1484 	pCmd->BaInfo.CreateParams.WindowSize = htole32(WindowSize);
1485 	pCmd->BaInfo.CreateParams.IdleThrs = htole32(0x22000);
1486 	IEEE80211_ADDR_COPY(&pCmd->BaInfo.CreateParams.PeerMacAddr[0],
1487 	    sp->macaddr);
1488 	/* XXX proxy STA */
1489 	memset(&pCmd->BaInfo.CreateParams.StaSrcMacAddr, 0, IEEE80211_ADDR_LEN);
1490 #if 0
1491 	pCmd->BaInfo.CreateParams.DialogToken = DialogToken;
1492 #else
1493 	pCmd->BaInfo.CreateParams.DialogToken = 10;
1494 #endif
1495 	pCmd->BaInfo.CreateParams.Tid = sp->tid;
1496 	pCmd->BaInfo.CreateParams.QueueId = sp->stream;
1497 	pCmd->BaInfo.CreateParams.ParamInfo = sp->paraminfo;
1498 	/* NB: ResetSeqNo known to be zero */
1499 	pCmd->BaInfo.CreateParams.StartSeqNo = htole16(seqno);
1500 #if 0
1501 	cvtBAFlags(&pCmd->BaInfo.CreateParams.Flags, sp->ba_policy, 0);
1502 #else
1503 	pCmd->BaInfo.CreateParams.Flags =
1504 			  htole32(BASTREAM_FLAG_IMMEDIATE_TYPE)
1505 			| htole32(BASTREAM_FLAG_DIRECTION_UPSTREAM)
1506 			;
1507 #endif
1508 
1509 	retval = mwlExecuteCmd(mh, HostCmd_CMD_BASTREAM);
1510 	if (retval == 0) {
1511 		/*
1512 		 * NB: BA stream create may fail when the stream is
1513 		 * h/w backed under some (as yet not understood) conditions.
1514 		 * Check the result code to catch this.
1515 		 */
1516 		if (le16toh(pCmd->CmdHdr.Result) != HostCmd_RESULT_OK)
1517 			retval = EIO;
1518 		else
1519 			sp->setup = 1;
1520 	}
1521 	MWL_HAL_UNLOCK(mh);
1522 	return retval;
1523 }
1524 
1525 int
1526 mwl_hal_bastream_destroy(struct mwl_hal *mh0, const MWL_HAL_BASTREAM *s)
1527 {
1528 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
1529 	struct mwl_hal_bastream *sp = __DECONST(struct mwl_hal_bastream *, s);
1530 	HostCmd_FW_BASTREAM *pCmd;
1531 	int retval;
1532 
1533 	if (sp->stream >= MWL_BASTREAMS_MAX) {
1534 		/* XXX */
1535 		return EINVAL;
1536 	}
1537 	MWL_HAL_LOCK(mh);
1538 	if (sp->setup) {
1539 		_CMD_SETUP(pCmd, HostCmd_FW_BASTREAM, HostCmd_CMD_BASTREAM);
1540 		pCmd->ActionType = htole32(BaDestroyStream);
1541 		pCmd->BaInfo.DestroyParams.FwBaContext.Context =
1542 		    htole32(sp->stream);
1543 
1544 		retval = mwlExecuteCmd(mh, HostCmd_CMD_BASTREAM);
1545 	} else
1546 		retval = 0;
1547 	/* NB: always reclaim stream */
1548 	mh->mh_bastreams |= 1<<sp->stream;
1549 	sp->public.data[0] = NULL;
1550 	sp->public.data[1] = NULL;
1551 	sp->setup = 0;
1552 	MWL_HAL_UNLOCK(mh);
1553 	return retval;
1554 }
1555 
1556 int
1557 mwl_hal_bastream_get_seqno(struct mwl_hal *mh0,
1558 	const MWL_HAL_BASTREAM *s, const uint8_t Macaddr[IEEE80211_ADDR_LEN],
1559 	uint16_t *pseqno)
1560 {
1561 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
1562 	struct mwl_hal_bastream *sp = __DECONST(struct mwl_hal_bastream *, s);
1563 	HostCmd_GET_SEQNO *pCmd;
1564 	int retval;
1565 
1566 	MWL_HAL_LOCK(mh);
1567 	_CMD_SETUP(pCmd, HostCmd_GET_SEQNO, HostCmd_CMD_GET_SEQNO);
1568 	IEEE80211_ADDR_COPY(pCmd->MacAddr, Macaddr);
1569 	pCmd->TID = sp->tid;
1570 
1571 	retval = mwlExecuteCmd(mh, HostCmd_CMD_GET_SEQNO);
1572 	if (retval == 0)
1573 		*pseqno = le16toh(pCmd->SeqNo);
1574 	MWL_HAL_UNLOCK(mh);
1575 	return retval;
1576 }
1577 
1578 int
1579 mwl_hal_getwatchdogbitmap(struct mwl_hal *mh0, uint8_t bitmap[1])
1580 {
1581 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
1582 	HostCmd_FW_GET_WATCHDOG_BITMAP *pCmd;
1583 	int retval;
1584 
1585 	MWL_HAL_LOCK(mh);
1586 	_CMD_SETUP(pCmd, HostCmd_FW_GET_WATCHDOG_BITMAP,
1587 		HostCmd_CMD_GET_WATCHDOG_BITMAP);
1588 
1589 	retval = mwlExecuteCmd(mh, HostCmd_CMD_GET_WATCHDOG_BITMAP);
1590 	if (retval == 0) {
1591 		bitmap[0] = pCmd->Watchdogbitmap;
1592 		/* fw returns qid, map it to BA stream */
1593 		if (bitmap[0] < MWL_BAQID_MAX)
1594 			bitmap[0] = qid2ba[bitmap[0]];
1595 	}
1596 	MWL_HAL_UNLOCK(mh);
1597 	return retval;
1598 }
1599 
1600 /*
1601  * Configure aggressive Ampdu rate mode.
1602  */
1603 int
1604 mwl_hal_setaggampduratemode(struct mwl_hal *mh0, int mode, int threshold)
1605 {
1606 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
1607 	HostCmd_FW_AMPDU_RETRY_RATEDROP_MODE *pCmd;
1608 	int retval;
1609 
1610 	MWL_HAL_LOCK(mh);
1611 	_CMD_SETUP(pCmd, HostCmd_FW_AMPDU_RETRY_RATEDROP_MODE,
1612 		HostCmd_CMD_AMPDU_RETRY_RATEDROP_MODE);
1613 	pCmd->Action = htole16(1);
1614 	pCmd->Option = htole32(mode);
1615 	pCmd->Threshold = htole32(threshold);
1616 
1617 	retval = mwlExecuteCmd(mh, HostCmd_CMD_AMPDU_RETRY_RATEDROP_MODE);
1618 	MWL_HAL_UNLOCK(mh);
1619 	return retval;
1620 }
1621 
1622 int
1623 mwl_hal_getaggampduratemode(struct mwl_hal *mh0, int *mode, int *threshold)
1624 {
1625 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
1626 	HostCmd_FW_AMPDU_RETRY_RATEDROP_MODE *pCmd;
1627 	int retval;
1628 
1629 	MWL_HAL_LOCK(mh);
1630 	_CMD_SETUP(pCmd, HostCmd_FW_AMPDU_RETRY_RATEDROP_MODE,
1631 		HostCmd_CMD_AMPDU_RETRY_RATEDROP_MODE);
1632 	pCmd->Action = htole16(0);
1633 
1634 	retval = mwlExecuteCmd(mh, HostCmd_CMD_AMPDU_RETRY_RATEDROP_MODE);
1635 	MWL_HAL_UNLOCK(mh);
1636 	*mode =  le32toh(pCmd->Option);
1637 	*threshold = le32toh(pCmd->Threshold);
1638 	return retval;
1639 }
1640 
1641 /*
1642  * Set CFEND status Enable/Disable
1643  */
1644 int
1645 mwl_hal_setcfend(struct mwl_hal *mh0, int ena)
1646 {
1647 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
1648 	HostCmd_CFEND_ENABLE *pCmd;
1649 	int retval;
1650 
1651 	MWL_HAL_LOCK(mh);
1652 	_CMD_SETUP(pCmd, HostCmd_CFEND_ENABLE,
1653 		HostCmd_CMD_CFEND_ENABLE);
1654 	pCmd->Enable = htole32(ena);
1655 
1656 	retval = mwlExecuteCmd(mh, HostCmd_CMD_CFEND_ENABLE);
1657 	MWL_HAL_UNLOCK(mh);
1658 	return retval;
1659 }
1660 
1661 int
1662 mwl_hal_setdwds(struct mwl_hal *mh0, int ena)
1663 {
1664 	HostCmd_DWDS_ENABLE *pCmd;
1665 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
1666    	int retval;
1667 
1668 	MWL_HAL_LOCK(mh);
1669 	_CMD_SETUP(pCmd, HostCmd_DWDS_ENABLE, HostCmd_CMD_DWDS_ENABLE);
1670 	pCmd->Enable = htole32(ena);
1671 	retval = mwlExecuteCmd(mh, HostCmd_CMD_DWDS_ENABLE);
1672   	MWL_HAL_UNLOCK(mh);
1673 	return retval;
1674 }
1675 
1676 static void
1677 cvtPeerInfo(PeerInfo_t *to, const MWL_HAL_PEERINFO *from)
1678 {
1679 	to->LegacyRateBitMap = htole32(from->LegacyRateBitMap);
1680 	to->HTRateBitMap = htole32(from->HTRateBitMap);
1681 	to->CapInfo = htole16(from->CapInfo);
1682 	to->HTCapabilitiesInfo = htole16(from->HTCapabilitiesInfo);
1683 	to->MacHTParamInfo = from->MacHTParamInfo;
1684 	to->AddHtInfo.ControlChan = from->AddHtInfo.ControlChan;
1685 	to->AddHtInfo.AddChan = from->AddHtInfo.AddChan;
1686 	to->AddHtInfo.OpMode = htole16(from->AddHtInfo.OpMode);
1687 	to->AddHtInfo.stbc = htole16(from->AddHtInfo.stbc);
1688 }
1689 
1690 /* XXX station id must be in [0..63] */
1691 int
1692 mwl_hal_newstation(struct mwl_hal_vap *vap,
1693 	const uint8_t addr[IEEE80211_ADDR_LEN], uint16_t aid, uint16_t sid,
1694 	const MWL_HAL_PEERINFO *peer, int isQosSta, int wmeInfo)
1695 {
1696 	struct mwl_hal_priv *mh = MWLVAP(vap);
1697 	HostCmd_FW_SET_NEW_STN *pCmd;
1698 	int retval;
1699 
1700 	MWL_HAL_LOCK(mh);
1701 	_VCMD_SETUP(vap, pCmd, HostCmd_FW_SET_NEW_STN, HostCmd_CMD_SET_NEW_STN);
1702 	pCmd->AID = htole16(aid);
1703 	pCmd->StnId = htole16(sid);
1704 	pCmd->Action = htole16(0);	/* SET */
1705 	if (peer != NULL) {
1706 		/* NB: must fix up byte order */
1707 		cvtPeerInfo(&pCmd->PeerInfo, peer);
1708 	}
1709 	IEEE80211_ADDR_COPY(&pCmd->MacAddr[0], addr);
1710 	pCmd->Qosinfo = wmeInfo;
1711 	pCmd->isQosSta = (isQosSta != 0);
1712 
1713 	retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_NEW_STN);
1714 	if (retval == 0 && IEEE80211_ADDR_EQ(vap->mac, addr))
1715 		vap->flags |= MVF_STATION;
1716 	MWL_HAL_UNLOCK(mh);
1717 	return retval;
1718 }
1719 
1720 int
1721 mwl_hal_delstation(struct mwl_hal_vap *vap,
1722 	const uint8_t addr[IEEE80211_ADDR_LEN])
1723 {
1724 	struct mwl_hal_priv *mh = MWLVAP(vap);
1725 	HostCmd_FW_SET_NEW_STN *pCmd;
1726 	int retval, islocal;
1727 
1728 	MWL_HAL_LOCK(mh);
1729 	islocal = IEEE80211_ADDR_EQ(vap->mac, addr);
1730 	if (!islocal || (vap->flags & MVF_STATION)) {
1731 		_VCMD_SETUP(vap, pCmd, HostCmd_FW_SET_NEW_STN,
1732 		    HostCmd_CMD_SET_NEW_STN);
1733 		pCmd->Action = htole16(2);	/* REMOVE */
1734 		IEEE80211_ADDR_COPY(&pCmd->MacAddr[0], addr);
1735 		retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_NEW_STN);
1736 		if (islocal)
1737 			vap->flags &= ~MVF_STATION;
1738 	} else
1739 		retval = 0;
1740 	MWL_HAL_UNLOCK(mh);
1741 	return retval;
1742 }
1743 
1744 /*
1745  * Prod the firmware to age packets on station power
1746  * save queues and reap frames on the tx aggregation q's.
1747  */
1748 int
1749 mwl_hal_setkeepalive(struct mwl_hal *mh0)
1750 {
1751 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
1752 	HostCmd_FW_SET_KEEP_ALIVE_TICK *pCmd;
1753 	int retval;
1754 
1755 	MWL_HAL_LOCK(mh);
1756 	_CMD_SETUP(pCmd, HostCmd_FW_SET_KEEP_ALIVE_TICK,
1757 		HostCmd_CMD_SET_KEEP_ALIVE);
1758 	/*
1759 	 * NB: tick must be 0 to prod the f/w;
1760 	 *     a non-zero value is a noop.
1761 	 */
1762 	pCmd->tick = 0;
1763 
1764 	retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_KEEP_ALIVE);
1765 	MWL_HAL_UNLOCK(mh);
1766 	return retval;
1767 }
1768 
1769 int
1770 mwl_hal_setapmode(struct mwl_hal_vap *vap, MWL_HAL_APMODE ApMode)
1771 {
1772 	struct mwl_hal_priv *mh = MWLVAP(vap);
1773 	HostCmd_FW_SET_APMODE *pCmd;
1774 	int retval;
1775 
1776 	/* XXX validate ApMode? */
1777 
1778 	MWL_HAL_LOCK(mh);
1779 	_VCMD_SETUP(vap, pCmd, HostCmd_FW_SET_APMODE, HostCmd_CMD_SET_APMODE);
1780 	pCmd->ApMode = ApMode;
1781 
1782 	retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_APMODE);
1783 	MWL_HAL_UNLOCK(mh);
1784 	return retval;
1785 }
1786 
1787 int
1788 mwl_hal_stop(struct mwl_hal_vap *vap)
1789 {
1790 	struct mwl_hal_priv *mh = MWLVAP(vap);
1791 	HostCmd_DS_BSS_START *pCmd;
1792 	int retval;
1793 
1794 	MWL_HAL_LOCK(mh);
1795 	if (vap->flags & MVF_RUNNING) {
1796 		_VCMD_SETUP(vap, pCmd, HostCmd_DS_BSS_START,
1797 		    HostCmd_CMD_BSS_START);
1798 		pCmd->Enable = htole32(HostCmd_ACT_GEN_OFF);
1799 		retval = mwlExecuteCmd(mh, HostCmd_CMD_BSS_START);
1800 	} else
1801 		retval = 0;
1802 	/* NB: mark !running regardless */
1803 	vap->flags &= ~MVF_RUNNING;
1804 	MWL_HAL_UNLOCK(mh);
1805 	return retval;
1806 }
1807 
1808 int
1809 mwl_hal_start(struct mwl_hal_vap *vap)
1810 {
1811 	struct mwl_hal_priv *mh = MWLVAP(vap);
1812 	HostCmd_DS_BSS_START *pCmd;
1813 	int retval;
1814 
1815 	MWL_HAL_LOCK(mh);
1816 	_VCMD_SETUP(vap, pCmd, HostCmd_DS_BSS_START, HostCmd_CMD_BSS_START);
1817 	pCmd->Enable = htole32(HostCmd_ACT_GEN_ON);
1818 
1819 	retval = mwlExecuteCmd(mh, HostCmd_CMD_BSS_START);
1820 	if (retval == 0)
1821 		vap->flags |= MVF_RUNNING;
1822 	MWL_HAL_UNLOCK(mh);
1823 	return retval;
1824 }
1825 
1826 int
1827 mwl_hal_setgprot(struct mwl_hal *mh0, int prot)
1828 {
1829 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
1830 	HostCmd_FW_SET_G_PROTECT_FLAG *pCmd;
1831 	int retval;
1832 
1833 	MWL_HAL_LOCK(mh);
1834 	_CMD_SETUP(pCmd, HostCmd_FW_SET_G_PROTECT_FLAG,
1835 		HostCmd_CMD_SET_G_PROTECT_FLAG);
1836 	pCmd->GProtectFlag  = htole32(prot);
1837 
1838 	retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_G_PROTECT_FLAG);
1839 	MWL_HAL_UNLOCK(mh);
1840 	return retval;
1841 }
1842 
1843 int
1844 mwl_hal_setwmm(struct mwl_hal *mh0, int onoff)
1845 {
1846 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
1847 	HostCmd_FW_SetWMMMode *pCmd;
1848 	int retval;
1849 
1850 	MWL_HAL_LOCK(mh);
1851 	_CMD_SETUP(pCmd, HostCmd_FW_SetWMMMode,
1852 		HostCmd_CMD_SET_WMM_MODE);
1853 	pCmd->Action = htole16(onoff);
1854 
1855 	retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_WMM_MODE);
1856 	MWL_HAL_UNLOCK(mh);
1857 	return retval;
1858 }
1859 
1860 int
1861 mwl_hal_setedcaparams(struct mwl_hal *mh0, uint8_t qnum,
1862 	uint32_t CWmin, uint32_t CWmax, uint8_t AIFSN,  uint16_t TXOPLimit)
1863 {
1864 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
1865 	HostCmd_FW_SET_EDCA_PARAMS *pCmd;
1866 	int retval;
1867 
1868 	MWL_HAL_LOCK(mh);
1869 	_CMD_SETUP(pCmd, HostCmd_FW_SET_EDCA_PARAMS,
1870 		HostCmd_CMD_SET_EDCA_PARAMS);
1871 	/*
1872 	 * NB: CWmin and CWmax are always set.
1873 	 *     TxOpLimit is set if bit 0x2 is marked in Action
1874 	 *     AIFSN is set if bit 0x4 is marked in Action
1875 	 */
1876 	pCmd->Action = htole16(0xffff);	/* NB: set everything */
1877 	pCmd->TxOP = htole16(TXOPLimit);
1878 	pCmd->CWMax = htole32(CWmax);
1879 	pCmd->CWMin = htole32(CWmin);
1880 	pCmd->AIFSN = AIFSN;
1881 	pCmd->TxQNum = qnum;		/* XXX check */
1882 
1883 	retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_EDCA_PARAMS);
1884 	MWL_HAL_UNLOCK(mh);
1885 	return retval;
1886 }
1887 
1888 /* XXX 0 = indoor, 1 = outdoor */
1889 int
1890 mwl_hal_setrateadaptmode(struct mwl_hal *mh0, uint16_t mode)
1891 {
1892 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
1893 	HostCmd_DS_SET_RATE_ADAPT_MODE *pCmd;
1894 	int retval;
1895 
1896 	MWL_HAL_LOCK(mh);
1897 	_CMD_SETUP(pCmd, HostCmd_DS_SET_RATE_ADAPT_MODE,
1898 		HostCmd_CMD_SET_RATE_ADAPT_MODE);
1899 	pCmd->Action = htole16(HostCmd_ACT_GEN_SET);
1900 	pCmd->RateAdaptMode = htole16(mode);
1901 
1902 	retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_RATE_ADAPT_MODE);
1903 	MWL_HAL_UNLOCK(mh);
1904 	return retval;
1905 }
1906 
1907 int
1908 mwl_hal_setcsmode(struct mwl_hal *mh0, MWL_HAL_CSMODE csmode)
1909 {
1910 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
1911 	HostCmd_DS_SET_LINKADAPT_CS_MODE *pCmd;
1912 	int retval;
1913 
1914 	MWL_HAL_LOCK(mh);
1915 	_CMD_SETUP(pCmd, HostCmd_DS_SET_LINKADAPT_CS_MODE,
1916 		HostCmd_CMD_SET_LINKADAPT_CS_MODE);
1917 	pCmd->Action = htole16(HostCmd_ACT_GEN_SET);
1918 	pCmd->CSMode = htole16(csmode);
1919 
1920 	retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_LINKADAPT_CS_MODE);
1921 	MWL_HAL_UNLOCK(mh);
1922 	return retval;
1923 }
1924 
1925 int
1926 mwl_hal_setnprot(struct mwl_hal_vap *vap, MWL_HAL_HTPROTECT mode)
1927 {
1928 	struct mwl_hal_priv *mh = MWLVAP(vap);
1929 	HostCmd_FW_SET_N_PROTECT_FLAG *pCmd;
1930 	int retval;
1931 
1932 	/* XXX validate mode */
1933 	MWL_HAL_LOCK(mh);
1934 	_VCMD_SETUP(vap, pCmd, HostCmd_FW_SET_N_PROTECT_FLAG,
1935 		HostCmd_CMD_SET_N_PROTECT_FLAG);
1936 	pCmd->NProtectFlag  = htole32(mode);
1937 
1938 	retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_N_PROTECT_FLAG);
1939 	MWL_HAL_UNLOCK(mh);
1940 	return retval;
1941 }
1942 
1943 int
1944 mwl_hal_setnprotmode(struct mwl_hal_vap *vap, uint8_t mode)
1945 {
1946 	struct mwl_hal_priv *mh = MWLVAP(vap);
1947 	HostCmd_FW_SET_N_PROTECT_OPMODE *pCmd;
1948 	int retval;
1949 
1950 	MWL_HAL_LOCK(mh);
1951 	_VCMD_SETUP(vap, pCmd, HostCmd_FW_SET_N_PROTECT_OPMODE,
1952 		HostCmd_CMD_SET_N_PROTECT_OPMODE);
1953 	pCmd->NProtectOpMode = mode;
1954 
1955 	retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_N_PROTECT_OPMODE);
1956 	MWL_HAL_UNLOCK(mh);
1957 	return retval;
1958 }
1959 
1960 int
1961 mwl_hal_setoptimizationlevel(struct mwl_hal *mh0, int level)
1962 {
1963 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
1964 	HostCmd_FW_SET_OPTIMIZATION_LEVEL *pCmd;
1965 	int retval;
1966 
1967 	MWL_HAL_LOCK(mh);
1968 	_CMD_SETUP(pCmd, HostCmd_FW_SET_OPTIMIZATION_LEVEL,
1969 		HostCmd_CMD_SET_OPTIMIZATION_LEVEL);
1970 	pCmd->OptLevel = level;
1971 
1972 	retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_OPTIMIZATION_LEVEL);
1973 	MWL_HAL_UNLOCK(mh);
1974 	return retval;
1975 }
1976 
1977 int
1978 mwl_hal_setmimops(struct mwl_hal *mh0, const uint8_t addr[IEEE80211_ADDR_LEN],
1979 	uint8_t enable, uint8_t mode)
1980 {
1981 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
1982 	HostCmd_FW_SET_MIMOPSHT *pCmd;
1983 	int retval;
1984 
1985 	MWL_HAL_LOCK(mh);
1986 	_CMD_SETUP(pCmd, HostCmd_FW_SET_MIMOPSHT, HostCmd_CMD_SET_MIMOPSHT);
1987 	IEEE80211_ADDR_COPY(pCmd->Addr, addr);
1988 	pCmd->Enable = enable;
1989 	pCmd->Mode = mode;
1990 
1991 	retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_MIMOPSHT);
1992 	MWL_HAL_UNLOCK(mh);
1993 	return retval;
1994 }
1995 
1996 static int
1997 mwlGetCalTable(struct mwl_hal_priv *mh, uint8_t annex, uint8_t index)
1998 {
1999 	HostCmd_FW_GET_CALTABLE *pCmd;
2000 	int retval;
2001 
2002 	MWL_HAL_LOCK_ASSERT(mh);
2003 
2004 	_CMD_SETUP(pCmd, HostCmd_FW_GET_CALTABLE, HostCmd_CMD_GET_CALTABLE);
2005 	pCmd->annex = annex;
2006 	pCmd->index = index;
2007 	memset(pCmd->calTbl, 0, sizeof(pCmd->calTbl));
2008 
2009 	retval = mwlExecuteCmd(mh, HostCmd_CMD_GET_CALTABLE);
2010 	if (retval == 0 &&
2011 	    pCmd->calTbl[0] != annex && annex != 0 && annex != 255)
2012 		retval = EIO;
2013 	return retval;
2014 }
2015 
2016 /*
2017  * Calculate the max tx power from the channel's cal data.
2018  */
2019 static void
2020 setmaxtxpow(struct mwl_hal_channel *hc, int i, int maxix)
2021 {
2022 	hc->maxTxPow = hc->targetPowers[i];
2023 	for (i++; i < maxix; i++)
2024 		if (hc->targetPowers[i] > hc->maxTxPow)
2025 			hc->maxTxPow = hc->targetPowers[i];
2026 }
2027 
2028 /*
2029  * Construct channel info for 5GHz channels from cal data.
2030  */
2031 static void
2032 get5Ghz(MWL_HAL_CHANNELINFO *ci, const uint8_t table[], int len)
2033 {
2034 	int i, j, f, l, h;
2035 
2036 	l = 32000;
2037 	h = 0;
2038 	j = 0;
2039 	for (i = 0; i < len; i += 4) {
2040 		struct mwl_hal_channel *hc;
2041 
2042 		if (table[i] == 0)
2043 			continue;
2044 		f = 5000 + 5*table[i];
2045 		if (f < l)
2046 			l = f;
2047 		if (f > h)
2048 			h = f;
2049 		hc = &ci->channels[j];
2050 		hc->freq = f;
2051 		hc->ieee = table[i];
2052 		memcpy(hc->targetPowers, &table[i], 4);
2053 		setmaxtxpow(hc, 1, 4);		/* NB: col 1 is the freq, skip*/
2054 		j++;
2055 	}
2056 	ci->nchannels = j;
2057 	ci->freqLow = (l == 32000) ? 0 : l;
2058 	ci->freqHigh = h;
2059 }
2060 
2061 static uint16_t
2062 ieee2mhz(int chan)
2063 {
2064 	if (chan == 14)
2065 		return 2484;
2066 	if (chan < 14)
2067 		return 2407 + chan*5;
2068 	return 2512 + (chan-15)*20;
2069 }
2070 
2071 /*
2072  * Construct channel info for 2.4GHz channels from cal data.
2073  */
2074 static void
2075 get2Ghz(MWL_HAL_CHANNELINFO *ci, const uint8_t table[], int len)
2076 {
2077 	int i, j;
2078 
2079 	j = 0;
2080 	for (i = 0; i < len; i += 4) {
2081 		struct mwl_hal_channel *hc = &ci->channels[j];
2082 		hc->ieee = 1+j;
2083 		hc->freq = ieee2mhz(1+j);
2084 		memcpy(hc->targetPowers, &table[i], 4);
2085 		setmaxtxpow(hc, 0, 4);
2086 		j++;
2087 	}
2088 	ci->nchannels = j;
2089 	ci->freqLow = ieee2mhz(1);
2090 	ci->freqHigh = ieee2mhz(j);
2091 }
2092 
2093 #undef DUMPCALDATA
2094 #ifdef DUMPCALDATA
2095 static void
2096 dumpcaldata(const char *name, const uint8_t *table, int n)
2097 {
2098 	int i;
2099 	printf("\n%s:\n", name);
2100 	for (i = 0; i < n; i += 4)
2101 		printf("[%2d] %3d %3d %3d %3d\n", i/4, table[i+0], table[i+1], table[i+2], table[i+3]);
2102 }
2103 #endif
2104 
2105 static int
2106 mwlGetPwrCalTable(struct mwl_hal_priv *mh)
2107 {
2108 	const uint8_t *data;
2109 	MWL_HAL_CHANNELINFO *ci;
2110 	int len;
2111 
2112 	MWL_HAL_LOCK(mh);
2113 	/* NB: we hold the lock so it's ok to use cmdbuf */
2114 	data = ((const HostCmd_FW_GET_CALTABLE *) mh->mh_cmdbuf)->calTbl;
2115 	if (mwlGetCalTable(mh, 33, 0) == 0) {
2116 		len = (data[2] | (data[3] << 8)) - 12;
2117 		if (len > PWTAGETRATETABLE20M)
2118 			len = PWTAGETRATETABLE20M;
2119 #ifdef DUMPCALDATA
2120 dumpcaldata("2.4G 20M", &data[12], len);/*XXX*/
2121 #endif
2122 		get2Ghz(&mh->mh_20M, &data[12], len);
2123 	}
2124 	if (mwlGetCalTable(mh, 34, 0) == 0) {
2125 		len = (data[2] | (data[3] << 8)) - 12;
2126 		if (len > PWTAGETRATETABLE40M)
2127 			len = PWTAGETRATETABLE40M;
2128 #ifdef DUMPCALDATA
2129 dumpcaldata("2.4G 40M", &data[12], len);/*XXX*/
2130 #endif
2131 		ci = &mh->mh_40M;
2132 		get2Ghz(ci, &data[12], len);
2133 	}
2134 	if (mwlGetCalTable(mh, 35, 0) == 0) {
2135 		len = (data[2] | (data[3] << 8)) - 20;
2136 		if (len > PWTAGETRATETABLE20M_5G)
2137 			len = PWTAGETRATETABLE20M_5G;
2138 #ifdef DUMPCALDATA
2139 dumpcaldata("5G 20M", &data[20], len);/*XXX*/
2140 #endif
2141 		get5Ghz(&mh->mh_20M_5G, &data[20], len);
2142 	}
2143 	if (mwlGetCalTable(mh, 36, 0) == 0) {
2144 		len = (data[2] | (data[3] << 8)) - 20;
2145 		if (len > PWTAGETRATETABLE40M_5G)
2146 			len = PWTAGETRATETABLE40M_5G;
2147 #ifdef DUMPCALDATA
2148 dumpcaldata("5G 40M", &data[20], len);/*XXX*/
2149 #endif
2150 		ci = &mh->mh_40M_5G;
2151 		get5Ghz(ci, &data[20], len);
2152 	}
2153 	mh->mh_flags |= MHF_CALDATA;
2154 	MWL_HAL_UNLOCK(mh);
2155 	return 0;
2156 }
2157 
2158 int
2159 mwl_hal_getregioncode(struct mwl_hal *mh0, uint8_t *countryCode)
2160 {
2161 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
2162 	int retval;
2163 
2164 	MWL_HAL_LOCK(mh);
2165 	retval = mwlGetCalTable(mh, 0, 0);
2166 	if (retval == 0) {
2167 		const HostCmd_FW_GET_CALTABLE *pCmd =
2168 		    (const HostCmd_FW_GET_CALTABLE *) mh->mh_cmdbuf;
2169 		*countryCode = pCmd->calTbl[16];
2170 	}
2171 	MWL_HAL_UNLOCK(mh);
2172 	return retval;
2173 }
2174 
2175 int
2176 mwl_hal_setpromisc(struct mwl_hal *mh0, int ena)
2177 {
2178 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
2179 	uint32_t v;
2180 
2181 	MWL_HAL_LOCK(mh);
2182 	v = RD4(mh, MACREG_REG_PROMISCUOUS);
2183 	WR4(mh, MACREG_REG_PROMISCUOUS, ena ? v | 1 : v &~ 1);
2184 	MWL_HAL_UNLOCK(mh);
2185 	return 0;
2186 }
2187 
2188 int
2189 mwl_hal_getpromisc(struct mwl_hal *mh0)
2190 {
2191 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
2192 	uint32_t v;
2193 
2194 	MWL_HAL_LOCK(mh);
2195 	v = RD4(mh, MACREG_REG_PROMISCUOUS);
2196 	MWL_HAL_UNLOCK(mh);
2197 	return (v & 1) != 0;
2198 }
2199 
2200 int
2201 mwl_hal_GetBeacon(struct mwl_hal *mh0, uint8_t *pBcn, uint16_t *pLen)
2202 {
2203 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
2204 	HostCmd_FW_GET_BEACON *pCmd;
2205 	int retval;
2206 
2207 	MWL_HAL_LOCK(mh);
2208 	_CMD_SETUP(pCmd, HostCmd_FW_GET_BEACON, HostCmd_CMD_GET_BEACON);
2209 	pCmd->Bcnlen = htole16(0);
2210 
2211 	retval = mwlExecuteCmd(mh, HostCmd_CMD_GET_BEACON);
2212 	if (retval == 0) {
2213 		/* XXX bounds check */
2214 		memcpy(pBcn, &pCmd->Bcn, pCmd->Bcnlen);
2215 		*pLen = pCmd->Bcnlen;
2216 	}
2217 	MWL_HAL_UNLOCK(mh);
2218 	return retval;
2219 }
2220 
2221 int
2222 mwl_hal_SetRifs(struct mwl_hal *mh0, uint8_t QNum)
2223 {
2224 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
2225 	HostCmd_FW_SET_RIFS  *pCmd;
2226 	int retval;
2227 
2228 	MWL_HAL_LOCK(mh);
2229 	_CMD_SETUP(pCmd, HostCmd_FW_SET_RIFS, HostCmd_CMD_SET_RIFS);
2230 	pCmd->QNum = QNum;
2231 
2232 	retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_RIFS);
2233 	MWL_HAL_UNLOCK(mh);
2234 	return retval;
2235 }
2236 
2237 /*
2238  * Diagnostic api's for set/get registers.
2239  */
2240 
2241 static int
2242 getRFReg(struct mwl_hal_priv *mh, int flag, uint32_t reg, uint32_t *val)
2243 {
2244 	HostCmd_DS_RF_REG_ACCESS *pCmd;
2245 	int retval;
2246 
2247 	MWL_HAL_LOCK(mh);
2248 	_CMD_SETUP(pCmd, HostCmd_DS_RF_REG_ACCESS, HostCmd_CMD_RF_REG_ACCESS);
2249 	pCmd->Offset =  htole16(reg);
2250 	pCmd->Action = htole16(flag);
2251 	pCmd->Value = htole32(*val);
2252 
2253 	retval = mwlExecuteCmd(mh, HostCmd_CMD_RF_REG_ACCESS);
2254 	if (retval == 0)
2255 		*val = pCmd->Value;
2256 	MWL_HAL_UNLOCK(mh);
2257 	return retval;
2258 }
2259 
2260 static int
2261 getBBReg(struct mwl_hal_priv *mh, int flag, uint32_t reg, uint32_t *val)
2262 {
2263 	HostCmd_DS_BBP_REG_ACCESS *pCmd;
2264 	int retval;
2265 
2266 	MWL_HAL_LOCK(mh);
2267 	_CMD_SETUP(pCmd, HostCmd_DS_BBP_REG_ACCESS, HostCmd_CMD_BBP_REG_ACCESS);
2268 	pCmd->Offset =  htole16(reg);
2269 	pCmd->Action = htole16(flag);
2270 	pCmd->Value = htole32(*val);
2271 
2272 	retval = mwlExecuteCmd(mh, HostCmd_CMD_BBP_REG_ACCESS);
2273 	if (retval == 0)
2274 		*val = pCmd->Value;
2275 	MWL_HAL_UNLOCK(mh);
2276 	return retval;
2277 }
2278 
2279 static u_int
2280 mwl_hal_getregdump(struct mwl_hal_priv *mh, const MWL_DIAG_REGRANGE *regs,
2281 	void *dstbuf, int space)
2282 {
2283 	uint32_t *dp = dstbuf;
2284 	int i;
2285 
2286 	for (i = 0; space >= 2*sizeof(uint32_t); i++) {
2287 		u_int r = regs[i].start;
2288 		u_int e = regs[i].end;
2289 		*dp++ = (r<<16) | e;
2290 		space -= sizeof(uint32_t);
2291 		do {
2292 			if (MWL_DIAG_ISMAC(r))
2293 				*dp = RD4(mh, r);
2294 			else if (MWL_DIAG_ISBB(r))
2295 				getBBReg(mh, HostCmd_ACT_GEN_READ,
2296 				    r - MWL_DIAG_BASE_BB, dp);
2297 			else if (MWL_DIAG_ISRF(r))
2298 				getRFReg(mh, HostCmd_ACT_GEN_READ,
2299 				    r - MWL_DIAG_BASE_RF, dp);
2300 			else if (r < 0x1000 || r == MACREG_REG_FW_PRESENT)
2301 				*dp = RD4(mh, r);
2302 			else
2303 				*dp = 0xffffffff;
2304 			dp++;
2305 			r += sizeof(uint32_t);
2306 			space -= sizeof(uint32_t);
2307 		} while (r <= e && space >= sizeof(uint32_t));
2308 	}
2309 	return (char *) dp - (char *) dstbuf;
2310 }
2311 
2312 int
2313 mwl_hal_getdiagstate(struct mwl_hal *mh0, int request,
2314 	const void *args, uint32_t argsize,
2315 	void **result, uint32_t *resultsize)
2316 {
2317 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
2318 
2319 	switch (request) {
2320 	case MWL_DIAG_CMD_REVS:
2321 		*result = &mh->mh_revs;
2322 		*resultsize = sizeof(mh->mh_revs);
2323 		return 1;
2324 	case MWL_DIAG_CMD_REGS:
2325 		*resultsize = mwl_hal_getregdump(mh, args, *result, *resultsize);
2326 		return 1;
2327 	case MWL_DIAG_CMD_HOSTCMD: {
2328 		FWCmdHdr *pCmd = (FWCmdHdr *) &mh->mh_cmdbuf[0];
2329 		int retval;
2330 
2331 		MWL_HAL_LOCK(mh);
2332 		memcpy(pCmd, args, argsize);
2333 		retval = mwlExecuteCmd(mh, le16toh(pCmd->Cmd));
2334 		*result = (*resultsize != 0) ? pCmd : NULL;
2335 		MWL_HAL_UNLOCK(mh);
2336 		return (retval == 0);
2337 	}
2338 	case MWL_DIAG_CMD_FWLOAD:
2339 		if (mwl_hal_fwload(mh0, __DECONST(void *, args))) {
2340 			device_printf(mh->mh_dev, "problem loading fw image\n");
2341 			return 0;
2342 		}
2343 		return 1;
2344 	}
2345 	return 0;
2346 }
2347 
2348 /*
2349  * Low level firmware cmd block handshake support.
2350  */
2351 
2352 static void
2353 mwlSendCmd(struct mwl_hal_priv *mh)
2354 {
2355 	uint32_t dummy;
2356 
2357 	bus_dmamap_sync(mh->mh_dmat, mh->mh_dmamap,
2358 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2359 
2360 	WR4(mh, MACREG_REG_GEN_PTR, mh->mh_cmdaddr);
2361 	dummy = RD4(mh, MACREG_REG_INT_CODE);
2362 
2363 	WR4(mh, MACREG_REG_H2A_INTERRUPT_EVENTS, MACREG_H2ARIC_BIT_DOOR_BELL);
2364 }
2365 
2366 static int
2367 mwlWaitForCmdComplete(struct mwl_hal_priv *mh, uint16_t cmdCode)
2368 {
2369 #define MAX_WAIT_FW_COMPLETE_ITERATIONS 10000
2370 	int i;
2371 
2372 	for (i = 0; i < MAX_WAIT_FW_COMPLETE_ITERATIONS; i++) {
2373 		if (mh->mh_cmdbuf[0] == le16toh(cmdCode))
2374 			return 1;
2375 		DELAY(1*1000);
2376 	}
2377 	return 0;
2378 #undef MAX_WAIT_FW_COMPLETE_ITERATIONS
2379 }
2380 
2381 static int
2382 mwlExecuteCmd(struct mwl_hal_priv *mh, unsigned short cmd)
2383 {
2384 
2385 	MWL_HAL_LOCK_ASSERT(mh);
2386 
2387 	if ((mh->mh_flags & MHF_FWHANG) &&
2388 	    (mh->mh_debug & MWL_HAL_DEBUG_IGNHANG) == 0) {
2389 #ifdef MWLHAL_DEBUG
2390 		device_printf(mh->mh_dev, "firmware hung, skipping cmd %s\n",
2391 			mwlcmdname(cmd));
2392 #else
2393 		device_printf(mh->mh_dev, "firmware hung, skipping cmd 0x%x\n",
2394 			cmd);
2395 #endif
2396 		return ENXIO;
2397 	}
2398 	if (RD4(mh,  MACREG_REG_INT_CODE) == 0xffffffff) {
2399 		device_printf(mh->mh_dev, "%s: device not present!\n",
2400 		    __func__);
2401 		return EIO;
2402 	}
2403 #ifdef MWLHAL_DEBUG
2404 	if (mh->mh_debug & MWL_HAL_DEBUG_SENDCMD)
2405 		dumpresult(mh, 0);
2406 #endif
2407 	mwlSendCmd(mh);
2408 	if (!mwlWaitForCmdComplete(mh, 0x8000 | cmd)) {
2409 #ifdef MWLHAL_DEBUG
2410 		device_printf(mh->mh_dev,
2411 		    "timeout waiting for f/w cmd %s\n", mwlcmdname(cmd));
2412 #else
2413 		device_printf(mh->mh_dev,
2414 		    "timeout waiting for f/w cmd 0x%x\n", cmd);
2415 #endif
2416 		mh->mh_flags |= MHF_FWHANG;
2417 		return ETIMEDOUT;
2418 	}
2419 	bus_dmamap_sync(mh->mh_dmat, mh->mh_dmamap,
2420 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
2421 #ifdef MWLHAL_DEBUG
2422 	if (mh->mh_debug & MWL_HAL_DEBUG_CMDDONE)
2423 		dumpresult(mh, 1);
2424 #endif
2425 	return 0;
2426 }
2427 
2428 /*
2429  * Firmware download support.
2430  */
2431 #define FW_DOWNLOAD_BLOCK_SIZE	256
2432 #define FW_CHECK_USECS		(5*1000)	/* 5ms */
2433 #define FW_MAX_NUM_CHECKS	200
2434 
2435 #if 0
2436 /* XXX read f/w from file */
2437 #include <dev/mwl/mwlbootfw.h>
2438 #include <dev/mwl/mwl88W8363fw.h>
2439 #endif
2440 
2441 static void
2442 mwlFwReset(struct mwl_hal_priv *mh)
2443 {
2444 	if (RD4(mh,  MACREG_REG_INT_CODE) == 0xffffffff) {
2445 		device_printf(mh->mh_dev, "%s: device not present!\n",
2446 		    __func__);
2447 		return;
2448 	}
2449 	WR4(mh, MACREG_REG_H2A_INTERRUPT_EVENTS, ISR_RESET);
2450 	mh->mh_flags &= ~MHF_FWHANG;
2451 }
2452 
2453 static void
2454 mwlTriggerPciCmd(struct mwl_hal_priv *mh)
2455 {
2456 	uint32_t dummy;
2457 
2458 	bus_dmamap_sync(mh->mh_dmat, mh->mh_dmamap, BUS_DMASYNC_PREWRITE);
2459 
2460 	WR4(mh, MACREG_REG_GEN_PTR, mh->mh_cmdaddr);
2461 	dummy = RD4(mh, MACREG_REG_INT_CODE);
2462 
2463 	WR4(mh, MACREG_REG_INT_CODE, 0x00);
2464 	dummy = RD4(mh, MACREG_REG_INT_CODE);
2465 
2466 	WR4(mh, MACREG_REG_H2A_INTERRUPT_EVENTS, MACREG_H2ARIC_BIT_DOOR_BELL);
2467 	dummy = RD4(mh, MACREG_REG_INT_CODE);
2468 }
2469 
2470 static int
2471 mwlWaitFor(struct mwl_hal_priv *mh, uint32_t val)
2472 {
2473 	int i;
2474 
2475 	for (i = 0; i < FW_MAX_NUM_CHECKS; i++) {
2476 		DELAY(FW_CHECK_USECS);
2477 		if (RD4(mh, MACREG_REG_INT_CODE) == val)
2478 			return 1;
2479 	}
2480 	return 0;
2481 }
2482 
2483 /*
2484  * Firmware block xmit when talking to the boot-rom.
2485  */
2486 static int
2487 mwlSendBlock(struct mwl_hal_priv *mh, int bsize, const void *data, size_t dsize)
2488 {
2489 	mh->mh_cmdbuf[0] = htole16(HostCmd_CMD_CODE_DNLD);
2490 	mh->mh_cmdbuf[1] = htole16(bsize);
2491 	memcpy(&mh->mh_cmdbuf[4], data , dsize);
2492 	mwlTriggerPciCmd(mh);
2493 	/* XXX 2000 vs 200 */
2494 	if (mwlWaitFor(mh, MACREG_INT_CODE_CMD_FINISHED)) {
2495 		WR4(mh, MACREG_REG_INT_CODE, 0);
2496 		return 1;
2497 	}
2498 	device_printf(mh->mh_dev,
2499 	    "%s: timeout waiting for CMD_FINISHED, INT_CODE 0x%x\n",
2500 	    __func__, RD4(mh, MACREG_REG_INT_CODE));
2501 	return 0;
2502 }
2503 
2504 /*
2505  * Firmware block xmit when talking to the 1st-stage loader.
2506  */
2507 static int
2508 mwlSendBlock2(struct mwl_hal_priv *mh, const void *data, size_t dsize)
2509 {
2510 	memcpy(&mh->mh_cmdbuf[0], data, dsize);
2511 	mwlTriggerPciCmd(mh);
2512 	if (mwlWaitFor(mh, MACREG_INT_CODE_CMD_FINISHED)) {
2513 		WR4(mh, MACREG_REG_INT_CODE, 0);
2514 		return 1;
2515 	}
2516 	device_printf(mh->mh_dev,
2517 	    "%s: timeout waiting for CMD_FINISHED, INT_CODE 0x%x\n",
2518 	    __func__, RD4(mh, MACREG_REG_INT_CODE));
2519 	return 0;
2520 }
2521 
2522 static void
2523 mwlPokeSdramController(struct mwl_hal_priv *mh, int SDRAMSIZE_Addr)
2524 {
2525 	/** Set up sdram controller for superflyv2 **/
2526 	WR4(mh, 0x00006014, 0x33);
2527 	WR4(mh, 0x00006018, 0xa3a2632);
2528 	WR4(mh, 0x00006010, SDRAMSIZE_Addr);
2529 }
2530 
2531 int
2532 mwl_hal_fwload(struct mwl_hal *mh0, void *fwargs)
2533 {
2534 	struct mwl_hal_priv *mh = MWLPRIV(mh0);
2535 	const char *fwname = "mw88W8363fw";
2536 	const char *fwbootname = "mwlboot";
2537 	const struct firmware *fwboot = NULL;
2538 	const struct firmware *fw;
2539 	/* XXX get from firmware header */
2540 	uint32_t FwReadySignature = HostCmd_SOFTAP_FWRDY_SIGNATURE;
2541 	uint32_t OpMode = HostCmd_SOFTAP_MODE;
2542 	const uint8_t *fp, *ep;
2543 	const uint8_t *fmdata;
2544 	uint32_t blocksize, nbytes, fmsize;
2545 	int i, error, ntries;
2546 
2547 	fw = firmware_get(fwname);
2548 	if (fw == NULL) {
2549 		device_printf(mh->mh_dev,
2550 		    "could not load firmware image %s\n", fwname);
2551 		return ENXIO;
2552 	}
2553 	fmdata = fw->data;
2554 	fmsize = fw->datasize;
2555 	if (fmsize < 4) {
2556 		device_printf(mh->mh_dev, "firmware image %s too small\n",
2557 		    fwname);
2558 		error = ENXIO;
2559 		goto bad2;
2560 	}
2561 	if (fmdata[0] == 0x01 && fmdata[1] == 0x00 &&
2562 	    fmdata[2] == 0x00 && fmdata[3] == 0x00) {
2563 		/*
2564 		 * 2-stage load, get the boot firmware.
2565 		 */
2566 		fwboot = firmware_get(fwbootname);
2567 		if (fwboot == NULL) {
2568 			device_printf(mh->mh_dev,
2569 			    "could not load firmware image %s\n", fwbootname);
2570 			error = ENXIO;
2571 			goto bad2;
2572 		}
2573 	} else
2574 		fwboot = NULL;
2575 
2576 	mwlFwReset(mh);
2577 
2578 	WR4(mh, MACREG_REG_A2H_INTERRUPT_CLEAR_SEL, MACREG_A2HRIC_BIT_MASK);
2579 	WR4(mh, MACREG_REG_A2H_INTERRUPT_CAUSE, 0x00);
2580 	WR4(mh, MACREG_REG_A2H_INTERRUPT_MASK, 0x00);
2581 	WR4(mh, MACREG_REG_A2H_INTERRUPT_STATUS_MASK, MACREG_A2HRIC_BIT_MASK);
2582 	if (mh->mh_SDRAMSIZE_Addr != 0) {
2583 		/** Set up sdram controller for superflyv2 **/
2584 		mwlPokeSdramController(mh, mh->mh_SDRAMSIZE_Addr);
2585 	}
2586 	device_printf(mh->mh_dev, "load %s firmware image (%u bytes)\n",
2587 	    fwname, fmsize);
2588 	if (fwboot != NULL) {
2589 		/*
2590 		 * Do 2-stage load.  The 1st stage loader is setup
2591 		 * with the bootrom loader then we load the real
2592 		 * image using a different handshake. With this
2593 		 * mechanism the firmware is segmented into chunks
2594 		 * that have a CRC.  If a chunk is incorrect we'll
2595 		 * be told to retransmit.
2596 		 */
2597 		/* XXX assumes hlpimage fits in a block */
2598 		/* NB: zero size block indicates download is finished */
2599 		if (!mwlSendBlock(mh, fwboot->datasize, fwboot->data, fwboot->datasize) ||
2600 		    !mwlSendBlock(mh, 0, NULL, 0)) {
2601 			error = ETIMEDOUT;
2602 			goto bad;
2603 		}
2604 		DELAY(200*FW_CHECK_USECS);
2605 		if (mh->mh_SDRAMSIZE_Addr != 0) {
2606 			/** Set up sdram controller for superflyv2 **/
2607 			mwlPokeSdramController(mh, mh->mh_SDRAMSIZE_Addr);
2608 		}
2609 		nbytes = ntries = 0;		/* NB: silence compiler */
2610 		for (fp = fmdata, ep = fp + fmsize; fp < ep; ) {
2611 			WR4(mh, MACREG_REG_INT_CODE, 0);
2612 			blocksize = RD4(mh, MACREG_REG_SCRATCH);
2613 			if (blocksize == 0)	/* download complete */
2614 				break;
2615 			if (blocksize > 0x00000c00) {
2616 				error = EINVAL;
2617 				goto bad;
2618 			}
2619 			if ((blocksize & 0x1) == 0) {
2620 				/* block successfully downloaded, advance */
2621 				fp += nbytes;
2622 				ntries = 0;
2623 			} else {
2624 				if (++ntries > 2) {
2625 					/*
2626 					 * Guard against f/w telling us to
2627 					 * retry infinitely.
2628 					 */
2629 					error = ELOOP;
2630 					goto bad;
2631 				}
2632 				/* clear NAK bit/flag */
2633 				blocksize &= ~0x1;
2634 			}
2635 			if (blocksize > ep - fp) {
2636 				/* XXX this should not happen, what to do? */
2637 				blocksize = ep - fp;
2638 			}
2639 			nbytes = blocksize;
2640 			if (!mwlSendBlock2(mh, fp, nbytes)) {
2641 				error = ETIMEDOUT;
2642 				goto bad;
2643 			}
2644 		}
2645 	} else {
2646 		for (fp = fmdata, ep = fp + fmsize; fp < ep;) {
2647 			nbytes = ep - fp;
2648 			if (nbytes > FW_DOWNLOAD_BLOCK_SIZE)
2649 				nbytes = FW_DOWNLOAD_BLOCK_SIZE;
2650 			if (!mwlSendBlock(mh, FW_DOWNLOAD_BLOCK_SIZE, fp, nbytes)) {
2651 				error = EIO;
2652 				goto bad;
2653 			}
2654 			fp += nbytes;
2655 		}
2656 	}
2657 	/* done with firmware... */
2658 	if (fwboot != NULL)
2659 		firmware_put(fwboot, FIRMWARE_UNLOAD);
2660 	firmware_put(fw, FIRMWARE_UNLOAD);
2661 	/*
2662 	 * Wait for firmware to startup; we monitor the
2663 	 * INT_CODE register waiting for a signature to
2664 	 * written back indicating it's ready to go.
2665 	 */
2666 	mh->mh_cmdbuf[1] = 0;
2667 	/*
2668 	 * XXX WAR for mfg fw download
2669 	 */
2670 	if (OpMode != HostCmd_STA_MODE)
2671 		mwlTriggerPciCmd(mh);
2672 	for (i = 0; i < FW_MAX_NUM_CHECKS; i++) {
2673 		WR4(mh, MACREG_REG_GEN_PTR, OpMode);
2674 		DELAY(FW_CHECK_USECS);
2675 		if (RD4(mh, MACREG_REG_INT_CODE) == FwReadySignature) {
2676 			WR4(mh, MACREG_REG_INT_CODE, 0x00);
2677 			return mwlResetHalState(mh);
2678 		}
2679 	}
2680 	return ETIMEDOUT;
2681 bad:
2682 	mwlFwReset(mh);
2683 bad2:
2684 	/* done with firmware... */
2685 	if (fwboot != NULL)
2686 		firmware_put(fwboot, FIRMWARE_UNLOAD);
2687 	firmware_put(fw, FIRMWARE_UNLOAD);
2688 	return error;
2689 }
2690 
2691 #ifdef MWLHAL_DEBUG
2692 static const char *
2693 mwlcmdname(int cmd)
2694 {
2695 	static char buf[12];
2696 #define	CMD(x)	case HostCmd_CMD_##x: return #x
2697 	switch (cmd) {
2698 	CMD(CODE_DNLD);
2699 	CMD(GET_HW_SPEC);
2700 	CMD(SET_HW_SPEC);
2701 	CMD(MAC_MULTICAST_ADR);
2702 	CMD(802_11_GET_STAT);
2703 	CMD(MAC_REG_ACCESS);
2704 	CMD(BBP_REG_ACCESS);
2705 	CMD(RF_REG_ACCESS);
2706 	CMD(802_11_RADIO_CONTROL);
2707 	CMD(802_11_RF_TX_POWER);
2708 	CMD(802_11_RF_ANTENNA);
2709 	CMD(SET_BEACON);
2710 	CMD(SET_RF_CHANNEL);
2711 	CMD(SET_AID);
2712 	CMD(SET_INFRA_MODE);
2713 	CMD(SET_G_PROTECT_FLAG);
2714 	CMD(802_11_RTS_THSD);
2715 	CMD(802_11_SET_SLOT);
2716 	CMD(SET_EDCA_PARAMS);
2717 	CMD(802_11H_DETECT_RADAR);
2718 	CMD(SET_WMM_MODE);
2719 	CMD(HT_GUARD_INTERVAL);
2720 	CMD(SET_FIXED_RATE);
2721 	CMD(SET_LINKADAPT_CS_MODE);
2722 	CMD(SET_MAC_ADDR);
2723 	CMD(SET_RATE_ADAPT_MODE);
2724 	CMD(BSS_START);
2725 	CMD(SET_NEW_STN);
2726 	CMD(SET_KEEP_ALIVE);
2727 	CMD(SET_APMODE);
2728 	CMD(SET_SWITCH_CHANNEL);
2729 	CMD(UPDATE_ENCRYPTION);
2730 	CMD(BASTREAM);
2731 	CMD(SET_RIFS);
2732 	CMD(SET_N_PROTECT_FLAG);
2733 	CMD(SET_N_PROTECT_OPMODE);
2734 	CMD(SET_OPTIMIZATION_LEVEL);
2735 	CMD(GET_CALTABLE);
2736 	CMD(SET_MIMOPSHT);
2737 	CMD(GET_BEACON);
2738 	CMD(SET_REGION_CODE);
2739 	CMD(SET_POWERSAVESTATION);
2740 	CMD(SET_TIM);
2741 	CMD(GET_TIM);
2742 	CMD(GET_SEQNO);
2743 	CMD(DWDS_ENABLE);
2744 	CMD(AMPDU_RETRY_RATEDROP_MODE);
2745 	CMD(CFEND_ENABLE);
2746 	}
2747 	snprintf(buf, sizeof(buf), "0x%x", cmd);
2748 	return buf;
2749 #undef CMD
2750 }
2751 
2752 static void
2753 dumpresult(struct mwl_hal_priv *mh, int showresult)
2754 {
2755 	const FWCmdHdr *h = (const FWCmdHdr *)mh->mh_cmdbuf;
2756 	const uint8_t *cp;
2757 	int len, i;
2758 
2759 	len = le16toh(h->Length);
2760 #ifdef MWL_MBSS_SUPPORT
2761 	device_printf(mh->mh_dev, "Cmd %s Length %d SeqNum %d MacId %d",
2762 	    mwlcmdname(le16toh(h->Cmd) &~ 0x8000), len, h->SeqNum, h->MacId);
2763 #else
2764 	device_printf(mh->mh_dev, "Cmd %s Length %d SeqNum %d",
2765 	    mwlcmdname(le16toh(h->Cmd) &~ 0x8000), len, le16toh(h->SeqNum));
2766 #endif
2767 	if (showresult) {
2768 		const char *results[] =
2769 		    { "OK", "ERROR", "NOT_SUPPORT", "PENDING", "BUSY",
2770 		      "PARTIAL_DATA" };
2771 		int result = le16toh(h->Result);
2772 
2773 		if (result <= HostCmd_RESULT_PARTIAL_DATA)
2774 			printf(" Result %s", results[result]);
2775 		else
2776 			printf(" Result %d", result);
2777 	}
2778 	cp = (const uint8_t *)h;
2779 	for (i = 0; i < len; i++) {
2780 		if ((i % 16) == 0)
2781 			printf("\n%02x", cp[i]);
2782 		else
2783 			printf(" %02x", cp[i]);
2784 	}
2785 	printf("\n");
2786 }
2787 #endif /* MWLHAL_DEBUG */
2788