xref: /freebsd/sys/dev/malo/if_malohal.c (revision b1866dfea3f3f142697f8e325db49b8e668fba35)
1 /*-
2  * Copyright (c) 2007 Marvell Semiconductor, Inc.
3  * Copyright (c) 2007 Sam Leffler, Errno Consulting
4  * Copyright (c) 2008 Weongyo Jeong <weongyo@freebsd.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer,
12  *    without modification.
13  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
14  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
15  *    redistribution must be conditioned upon including a substantially
16  *    similar Disclaimer requirement for further binary redistribution.
17  *
18  * NO WARRANTY
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
22  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
23  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
24  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
27  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
29  * THE POSSIBILITY OF SUCH DAMAGES.
30  */
31 
32 #include <sys/cdefs.h>
33 #ifdef __FreeBSD__
34 __FBSDID("$FreeBSD$");
35 #endif
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/endian.h>
40 #include <sys/kernel.h>
41 #include <sys/firmware.h>
42 #include <sys/socket.h>
43 
44 #include <machine/bus.h>
45 #include <sys/bus.h>
46 
47 #include <net/if.h>
48 #include <net/if_dl.h>
49 #include <net/if_media.h>
50 
51 #include <net80211/ieee80211_var.h>
52 
53 #include <dev/malo/if_malo.h>
54 
55 #define MALO_WAITOK				1
56 #define MALO_NOWAIT				0
57 
58 #define	_CMD_SETUP(pCmd, _type, _cmd) do {				\
59 	pCmd = (_type *)&mh->mh_cmdbuf[0];				\
60 	memset(pCmd, 0, sizeof(_type));					\
61 	pCmd->cmdhdr.cmd = htole16(_cmd);				\
62 	pCmd->cmdhdr.length = htole16(sizeof(_type));			\
63 } while (0)
64 
65 static __inline uint32_t
66 malo_hal_read4(struct malo_hal *mh, bus_size_t off)
67 {
68 	return bus_space_read_4(mh->mh_iot, mh->mh_ioh, off);
69 }
70 
71 static __inline void
72 malo_hal_write4(struct malo_hal *mh, bus_size_t off, uint32_t val)
73 {
74 	bus_space_write_4(mh->mh_iot, mh->mh_ioh, off, val);
75 }
76 
77 static void
78 malo_hal_load_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
79 {
80 	bus_addr_t *paddr = (bus_addr_t*) arg;
81 
82 	KASSERT(error == 0, ("error %u on bus_dma callback", error));
83 	*paddr = segs->ds_addr;
84 }
85 
86 /*
87  * Setup for communication with the device.  We allocate
88  * a command buffer and map it for bus dma use.  The pci
89  * device id is used to identify whether the device has
90  * SRAM on it (in which case f/w download must include a
91  * memory controller reset).  All bus i/o operations happen
92  * in BAR 1; the driver passes in the tag and handle we need.
93  */
94 struct malo_hal *
95 malo_hal_attach(device_t dev, uint16_t devid,
96     bus_space_handle_t ioh, bus_space_tag_t iot, bus_dma_tag_t tag)
97 {
98 	int error;
99 	struct malo_hal *mh;
100 
101 	mh = malloc(sizeof(struct malo_hal), M_DEVBUF, M_NOWAIT | M_ZERO);
102 	if (mh == NULL)
103 		return NULL;
104 
105 	mh->mh_dev = dev;
106 	mh->mh_ioh = ioh;
107 	mh->mh_iot = iot;
108 
109 	snprintf(mh->mh_mtxname, sizeof(mh->mh_mtxname),
110 	    "%s_hal", device_get_nameunit(dev));
111 	mtx_init(&mh->mh_mtx, mh->mh_mtxname, NULL, MTX_DEF);
112 
113 	/*
114 	 * Allocate the command buffer and map into the address
115 	 * space of the h/w.  We request "coherent" memory which
116 	 * will be uncached on some architectures.
117 	 */
118 	error = bus_dma_tag_create(tag,		/* parent */
119 		       PAGE_SIZE, 0,		/* alignment, bounds */
120 		       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
121 		       BUS_SPACE_MAXADDR,	/* highaddr */
122 		       NULL, NULL,		/* filter, filterarg */
123 		       MALO_CMDBUF_SIZE,	/* maxsize */
124 		       1,			/* nsegments */
125 		       MALO_CMDBUF_SIZE,	/* maxsegsize */
126 		       BUS_DMA_ALLOCNOW,	/* flags */
127 		       NULL,			/* lockfunc */
128 		       NULL,			/* lockarg */
129 		       &mh->mh_dmat);
130 	if (error != 0) {
131 		device_printf(dev, "unable to allocate memory for cmd tag, "
132 			"error %u\n", error);
133 		goto fail;
134 	}
135 
136 	/* allocate descriptors */
137 	error = bus_dmamap_create(mh->mh_dmat, BUS_DMA_NOWAIT, &mh->mh_dmamap);
138 	if (error != 0) {
139 		device_printf(dev, "unable to create dmamap for cmd buffers, "
140 			"error %u\n", error);
141 		goto fail;
142 	}
143 
144 	error = bus_dmamem_alloc(mh->mh_dmat, (void**) &mh->mh_cmdbuf,
145 				 BUS_DMA_NOWAIT | BUS_DMA_COHERENT,
146 				 &mh->mh_dmamap);
147 	if (error != 0) {
148 		device_printf(dev, "unable to allocate memory for cmd buffer, "
149 			"error %u\n", error);
150 		goto fail;
151 	}
152 
153 	error = bus_dmamap_load(mh->mh_dmat, mh->mh_dmamap,
154 				mh->mh_cmdbuf, MALO_CMDBUF_SIZE,
155 				malo_hal_load_cb, &mh->mh_cmdaddr,
156 				BUS_DMA_NOWAIT);
157 	if (error != 0) {
158 		device_printf(dev, "unable to load cmd buffer, error %u\n",
159 			error);
160 		goto fail;
161 	}
162 
163 	return (mh);
164 
165 fail:
166 	if (mh->mh_dmamap != NULL) {
167 		bus_dmamap_unload(mh->mh_dmat, mh->mh_dmamap);
168 		if (mh->mh_cmdbuf != NULL)
169 			bus_dmamem_free(mh->mh_dmat, mh->mh_cmdbuf,
170 			    mh->mh_dmamap);
171 		bus_dmamap_destroy(mh->mh_dmat, mh->mh_dmamap);
172 	}
173 	if (mh->mh_dmat)
174 		bus_dma_tag_destroy(mh->mh_dmat);
175 	free(mh, M_DEVBUF);
176 
177 	return (NULL);
178 }
179 
180 /*
181  * Low level firmware cmd block handshake support.
182  */
183 
184 static void
185 malo_hal_send_cmd(struct malo_hal *mh)
186 {
187 	uint32_t dummy;
188 
189 	bus_dmamap_sync(mh->mh_dmat, mh->mh_dmamap,
190 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
191 
192 	malo_hal_write4(mh, MALO_REG_GEN_PTR, mh->mh_cmdaddr);
193 	dummy = malo_hal_read4(mh, MALO_REG_INT_CODE);
194 
195 	malo_hal_write4(mh, MALO_REG_H2A_INTERRUPT_EVENTS,
196 	    MALO_H2ARIC_BIT_DOOR_BELL);
197 }
198 
199 static int
200 malo_hal_waitforcmd(struct malo_hal *mh, uint16_t cmd)
201 {
202 #define MAX_WAIT_FW_COMPLETE_ITERATIONS 10000
203 	int i;
204 
205 	for (i = 0; i < MAX_WAIT_FW_COMPLETE_ITERATIONS; i++) {
206 		if (mh->mh_cmdbuf[0] == le16toh(cmd))
207 			return 1;
208 
209 		DELAY(1 * 1000);
210 	}
211 
212 	return 0;
213 #undef MAX_WAIT_FW_COMPLETE_ITERATIONS
214 }
215 
216 static int
217 malo_hal_execute_cmd(struct malo_hal *mh, unsigned short cmd)
218 {
219 	MALO_HAL_LOCK_ASSERT(mh);
220 
221 	if ((mh->mh_flags & MHF_FWHANG) &&
222 	    (mh->mh_debug & MALO_HAL_DEBUG_IGNHANG) == 0) {
223 		device_printf(mh->mh_dev, "firmware hung, skipping cmd 0x%x\n",
224 			cmd);
225 		return ENXIO;
226 	}
227 
228 	if (malo_hal_read4(mh, MALO_REG_INT_CODE) == 0xffffffff) {
229 		device_printf(mh->mh_dev, "%s: device not present!\n",
230 		    __func__);
231 		return EIO;
232 	}
233 
234 	malo_hal_send_cmd(mh);
235 	if (!malo_hal_waitforcmd(mh, cmd | 0x8000)) {
236 		device_printf(mh->mh_dev,
237 		    "timeout waiting for f/w cmd 0x%x\n", cmd);
238 		mh->mh_flags |= MHF_FWHANG;
239 		return ETIMEDOUT;
240 	}
241 
242 	bus_dmamap_sync(mh->mh_dmat, mh->mh_dmamap,
243 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
244 
245 	return 0;
246 }
247 
248 static int
249 malo_hal_get_cal_table(struct malo_hal *mh, uint8_t annex, uint8_t index)
250 {
251 	struct malo_cmd_caltable *cmd;
252 	int ret;
253 
254 	MALO_HAL_LOCK_ASSERT(mh);
255 
256 	_CMD_SETUP(cmd, struct malo_cmd_caltable, MALO_HOSTCMD_GET_CALTABLE);
257 	cmd->annex = annex;
258 	cmd->index = index;
259 
260 	ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_GET_CALTABLE);
261 	if (ret == 0 && cmd->caltbl[0] != annex && annex != 0 && annex != 255)
262 		ret = EIO;
263 	return ret;
264 }
265 
266 static int
267 malo_hal_get_pwrcal_table(struct malo_hal *mh, struct malo_hal_caldata *cal)
268 {
269 	const uint8_t *data;
270 	int len;
271 
272 	MALO_HAL_LOCK(mh);
273 	/* NB: we hold the lock so it's ok to use cmdbuf */
274 	data = ((const struct malo_cmd_caltable *) mh->mh_cmdbuf)->caltbl;
275 	if (malo_hal_get_cal_table(mh, 33, 0) == 0) {
276 		len = (data[2] | (data[3] << 8)) - 12;
277 		/* XXX validate len */
278 		memcpy(cal->pt_ratetable_20m, &data[12], len);
279 	}
280 	mh->mh_flags |= MHF_CALDATA;
281 	MALO_HAL_UNLOCK(mh);
282 
283 	return 0;
284 }
285 
286 /*
287  * Reset internal state after a firmware download.
288  */
289 static int
290 malo_hal_resetstate(struct malo_hal *mh)
291 {
292 	/*
293 	 * Fetch cal data for later use.
294 	 * XXX may want to fetch other stuff too.
295 	 */
296 	if ((mh->mh_flags & MHF_CALDATA) == 0)
297 		malo_hal_get_pwrcal_table(mh, &mh->mh_caldata);
298 	return 0;
299 }
300 
301 static void
302 malo_hal_fw_reset(struct malo_hal *mh)
303 {
304 
305 	if (malo_hal_read4(mh,  MALO_REG_INT_CODE) == 0xffffffff) {
306 		device_printf(mh->mh_dev, "%s: device not present!\n",
307 		    __func__);
308 		return;
309 	}
310 
311 	malo_hal_write4(mh, MALO_REG_H2A_INTERRUPT_EVENTS, MALO_ISR_RESET);
312 	mh->mh_flags &= ~MHF_FWHANG;
313 }
314 
315 static void
316 malo_hal_trigger_pcicmd(struct malo_hal *mh)
317 {
318 	uint32_t dummy;
319 
320 	bus_dmamap_sync(mh->mh_dmat, mh->mh_dmamap, BUS_DMASYNC_PREWRITE);
321 
322 	malo_hal_write4(mh, MALO_REG_GEN_PTR, mh->mh_cmdaddr);
323 	dummy = malo_hal_read4(mh, MALO_REG_INT_CODE);
324 
325 	malo_hal_write4(mh, MALO_REG_INT_CODE, 0x00);
326 	dummy = malo_hal_read4(mh, MALO_REG_INT_CODE);
327 
328 	malo_hal_write4(mh, MALO_REG_H2A_INTERRUPT_EVENTS,
329 	    MALO_H2ARIC_BIT_DOOR_BELL);
330 	dummy = malo_hal_read4(mh, MALO_REG_INT_CODE);
331 }
332 
333 static int
334 malo_hal_waitfor(struct malo_hal *mh, uint32_t val)
335 {
336 	int i;
337 
338 	for (i = 0; i < MALO_FW_MAX_NUM_CHECKS; i++) {
339 		DELAY(MALO_FW_CHECK_USECS);
340 		if (malo_hal_read4(mh, MALO_REG_INT_CODE) == val)
341 			return 0;
342 	}
343 
344 	return -1;
345 }
346 
347 /*
348  * Firmware block xmit when talking to the boot-rom.
349  */
350 static int
351 malo_hal_send_helper(struct malo_hal *mh, int bsize,
352     const void *data, size_t dsize, int waitfor)
353 {
354 	mh->mh_cmdbuf[0] = htole16(MALO_HOSTCMD_CODE_DNLD);
355 	mh->mh_cmdbuf[1] = htole16(bsize);
356 	memcpy(&mh->mh_cmdbuf[4], data , dsize);
357 
358 	malo_hal_trigger_pcicmd(mh);
359 
360 	if (waitfor == MALO_NOWAIT)
361 		goto pass;
362 
363 	/* XXX 2000 vs 200 */
364 	if (malo_hal_waitfor(mh, MALO_INT_CODE_CMD_FINISHED) != 0) {
365 		device_printf(mh->mh_dev,
366 		    "%s: timeout waiting for CMD_FINISHED, INT_CODE 0x%x\n",
367 		    __func__, malo_hal_read4(mh, MALO_REG_INT_CODE));
368 
369 		return ETIMEDOUT;
370 	}
371 
372 pass:
373 	malo_hal_write4(mh, MALO_REG_INT_CODE, 0);
374 
375 	return (0);
376 }
377 
378 static int
379 malo_hal_fwload_helper(struct malo_hal *mh, char *helper)
380 {
381 	const struct firmware *fw;
382 	int error;
383 
384 	fw = firmware_get(helper);
385 	if (fw == NULL) {
386 		device_printf(mh->mh_dev, "could not read microcode %s!\n",
387 		    helper);
388 		return (EIO);
389 	}
390 
391 	device_printf(mh->mh_dev, "load %s firmware image (%zu bytes)\n",
392 	    helper, fw->datasize);
393 
394 	error = malo_hal_send_helper(mh, fw->datasize, fw->data, fw->datasize,
395 		MALO_WAITOK);
396 	if (error != 0)
397 		goto fail;
398 
399 	/* tell the card we're done and... */
400 	error = malo_hal_send_helper(mh, 0, NULL, 0, MALO_NOWAIT);
401 
402 fail:
403 	firmware_put(fw, FIRMWARE_UNLOAD);
404 
405 	return (error);
406 }
407 
408 /*
409  * Firmware block xmit when talking to the 1st-stage loader.
410  */
411 static int
412 malo_hal_send_main(struct malo_hal *mh, const void *data, size_t dsize,
413     uint16_t seqnum, int waitfor)
414 {
415 	mh->mh_cmdbuf[0] = htole16(MALO_HOSTCMD_CODE_DNLD);
416 	mh->mh_cmdbuf[1] = htole16(dsize);
417 	mh->mh_cmdbuf[2] = htole16(seqnum);
418 	mh->mh_cmdbuf[3] = 0;
419 	memcpy(&mh->mh_cmdbuf[4], data, dsize);
420 
421 	malo_hal_trigger_pcicmd(mh);
422 
423 	if (waitfor == MALO_NOWAIT)
424 		goto pass;
425 
426 	if (malo_hal_waitfor(mh, MALO_INT_CODE_CMD_FINISHED) != 0) {
427 		device_printf(mh->mh_dev,
428 		    "%s: timeout waiting for CMD_FINISHED, INT_CODE 0x%x\n",
429 		    __func__, malo_hal_read4(mh, MALO_REG_INT_CODE));
430 
431 		return ETIMEDOUT;
432 	}
433 
434 pass:
435 	malo_hal_write4(mh, MALO_REG_INT_CODE, 0);
436 
437 	return 0;
438 }
439 
440 static int
441 malo_hal_fwload_main(struct malo_hal *mh, char *firmware)
442 {
443 	const struct firmware *fw;
444 	const uint8_t *fp;
445 	int error;
446 	size_t count;
447 	uint16_t seqnum;
448 	uint32_t blocksize;
449 
450 	error = 0;
451 
452 	fw = firmware_get(firmware);
453 	if (fw == NULL) {
454 		device_printf(mh->mh_dev, "could not read firmware %s!\n",
455 		    firmware);
456 		return (EIO);
457 	}
458 
459 	device_printf(mh->mh_dev, "load %s firmware image (%zu bytes)\n",
460 	    firmware, fw->datasize);
461 
462 	seqnum = 1;
463 	for (count = 0; count < fw->datasize; count += blocksize) {
464 		blocksize = MIN(256, fw->datasize - count);
465 		fp = (const uint8_t *)fw->data + count;
466 
467 		error = malo_hal_send_main(mh, fp, blocksize, seqnum++,
468 		    MALO_NOWAIT);
469 		if (error != 0)
470 			goto fail;
471 		DELAY(500);
472 	}
473 
474 	/*
475 	 * send a command with size 0 to tell that the firmware has been
476 	 * uploaded
477 	 */
478 	error = malo_hal_send_main(mh, NULL, 0, seqnum++, MALO_NOWAIT);
479 	DELAY(100);
480 
481 fail:
482 	firmware_put(fw, FIRMWARE_UNLOAD);
483 
484 	return (error);
485 }
486 
487 int
488 malo_hal_fwload(struct malo_hal *mh, char *helper, char *firmware)
489 {
490 	int error, i;
491 	uint32_t fwreadysig, opmode;
492 
493 	/*
494 	 * NB: now malo(4) supports only STA mode.  It will be better if it
495 	 * supports AP mode.
496 	 */
497 	fwreadysig = MALO_HOSTCMD_STA_FWRDY_SIGNATURE;
498 	opmode = MALO_HOSTCMD_STA_MODE;
499 
500 	malo_hal_fw_reset(mh);
501 
502 	malo_hal_write4(mh, MALO_REG_A2H_INTERRUPT_CLEAR_SEL,
503 	    MALO_A2HRIC_BIT_MASK);
504 	malo_hal_write4(mh, MALO_REG_A2H_INTERRUPT_CAUSE, 0x00);
505 	malo_hal_write4(mh, MALO_REG_A2H_INTERRUPT_MASK, 0x00);
506 	malo_hal_write4(mh, MALO_REG_A2H_INTERRUPT_STATUS_MASK,
507 	    MALO_A2HRIC_BIT_MASK);
508 
509 	error = malo_hal_fwload_helper(mh, helper);
510 	if (error != 0) {
511 		device_printf(mh->mh_dev, "failed to load bootrom loader.\n");
512 		goto fail;
513 	}
514 
515 	DELAY(200 * MALO_FW_CHECK_USECS);
516 
517 	error = malo_hal_fwload_main(mh, firmware);
518 	if (error != 0) {
519 		device_printf(mh->mh_dev, "failed to load firmware.\n");
520 		goto fail;
521 	}
522 
523 	/*
524 	 * Wait for firmware to startup; we monitor the INT_CODE register
525 	 * waiting for a signature to written back indicating it's ready to go.
526 	 */
527 	mh->mh_cmdbuf[1] = 0;
528 
529 	if (opmode != MALO_HOSTCMD_STA_MODE)
530 		malo_hal_trigger_pcicmd(mh);
531 
532 	for (i = 0; i < MALO_FW_MAX_NUM_CHECKS; i++) {
533 		malo_hal_write4(mh, MALO_REG_GEN_PTR, opmode);
534 		DELAY(MALO_FW_CHECK_USECS);
535 		if (malo_hal_read4(mh, MALO_REG_INT_CODE) == fwreadysig) {
536 			malo_hal_write4(mh, MALO_REG_INT_CODE, 0x00);
537 			return malo_hal_resetstate(mh);
538 		}
539 	}
540 
541 	return ETIMEDOUT;
542 fail:
543 	malo_hal_fw_reset(mh);
544 
545 	return (error);
546 }
547 
548 /*
549  * Return "hw specs".  Note this must be the first cmd MUST be done after
550  * a firmware download or the f/w will lockup.
551  */
552 int
553 malo_hal_gethwspecs(struct malo_hal *mh, struct malo_hal_hwspec *hw)
554 {
555 	struct malo_cmd_get_hwspec *cmd;
556 	int ret;
557 
558 	MALO_HAL_LOCK(mh);
559 
560 	_CMD_SETUP(cmd, struct malo_cmd_get_hwspec, MALO_HOSTCMD_GET_HW_SPEC);
561 	memset(&cmd->permaddr[0], 0xff, IEEE80211_ADDR_LEN);
562 	cmd->ul_fw_awakecookie = htole32((unsigned int)mh->mh_cmdaddr + 2048);
563 
564 	ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_GET_HW_SPEC);
565 	if (ret == 0) {
566 		IEEE80211_ADDR_COPY(hw->macaddr, cmd->permaddr);
567 		hw->wcbbase[0] = le32toh(cmd->wcbbase0) & 0x0000ffff;
568 		hw->wcbbase[1] = le32toh(cmd->wcbbase1) & 0x0000ffff;
569 		hw->wcbbase[2] = le32toh(cmd->wcbbase2) & 0x0000ffff;
570 		hw->wcbbase[3] = le32toh(cmd->wcbbase3) & 0x0000ffff;
571 		hw->rxdesc_read = le32toh(cmd->rxpdrd_ptr)& 0x0000ffff;
572 		hw->rxdesc_write = le32toh(cmd->rxpdwr_ptr)& 0x0000ffff;
573 		hw->regioncode = le16toh(cmd->regioncode) & 0x00ff;
574 		hw->fw_releasenum = le32toh(cmd->fw_releasenum);
575 		hw->maxnum_wcb = le16toh(cmd->num_wcb);
576 		hw->maxnum_mcaddr = le16toh(cmd->num_mcastaddr);
577 		hw->num_antenna = le16toh(cmd->num_antenna);
578 		hw->hwversion = cmd->version;
579 		hw->hostinterface = cmd->hostif;
580 	}
581 
582 	MALO_HAL_UNLOCK(mh);
583 
584 	return ret;
585 }
586 
587 void
588 malo_hal_detach(struct malo_hal *mh)
589 {
590 
591 	bus_dmamem_free(mh->mh_dmat, mh->mh_cmdbuf, mh->mh_dmamap);
592 	bus_dmamap_destroy(mh->mh_dmat, mh->mh_dmamap);
593 	bus_dma_tag_destroy(mh->mh_dmat);
594 	mtx_destroy(&mh->mh_mtx);
595 	free(mh, M_DEVBUF);
596 }
597 
598 /*
599  * Configure antenna use.  Takes effect immediately.
600  *
601  * XXX tx antenna setting ignored
602  * XXX rx antenna setting should always be 3 (for now)
603  */
604 int
605 malo_hal_setantenna(struct malo_hal *mh, enum malo_hal_antenna dirset, int ant)
606 {
607 	struct malo_cmd_rf_antenna *cmd;
608 	int ret;
609 
610 	if (!(dirset == MHA_ANTENNATYPE_RX || dirset == MHA_ANTENNATYPE_TX))
611 		return EINVAL;
612 
613 	MALO_HAL_LOCK(mh);
614 
615 	_CMD_SETUP(cmd, struct malo_cmd_rf_antenna,
616 	    MALO_HOSTCMD_802_11_RF_ANTENNA);
617 	cmd->action = htole16(dirset);
618 	if (ant == 0) {			/* default to all/both antennae */
619 		/* XXX never reach now.  */
620 		ant = 3;
621 	}
622 	cmd->mode = htole16(ant);
623 
624 	ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_802_11_RF_ANTENNA);
625 
626 	MALO_HAL_UNLOCK(mh);
627 
628 	return ret;
629 }
630 
631 /*
632  * Configure radio.  Takes effect immediately.
633  *
634  * XXX preamble installed after set fixed rate cmd
635  */
636 int
637 malo_hal_setradio(struct malo_hal *mh, int onoff,
638     enum malo_hal_preamble preamble)
639 {
640 	struct malo_cmd_radio_control *cmd;
641 	int ret;
642 
643 	MALO_HAL_LOCK(mh);
644 
645 	_CMD_SETUP(cmd, struct malo_cmd_radio_control,
646 	    MALO_HOSTCMD_802_11_RADIO_CONTROL);
647 	cmd->action = htole16(MALO_HOSTCMD_ACT_GEN_SET);
648 	if (onoff == 0)
649 		cmd->control = 0;
650 	else
651 		cmd->control = htole16(preamble);
652 	cmd->radio_on = htole16(onoff);
653 
654 	ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_802_11_RADIO_CONTROL);
655 
656 	MALO_HAL_UNLOCK(mh);
657 
658 	return ret;
659 }
660 
661 /*
662  * Set the interrupt mask.
663  */
664 void
665 malo_hal_intrset(struct malo_hal *mh, uint32_t mask)
666 {
667 
668 	malo_hal_write4(mh, MALO_REG_A2H_INTERRUPT_MASK, 0);
669 	(void)malo_hal_read4(mh, MALO_REG_INT_CODE);
670 
671 	mh->mh_imask = mask;
672 	malo_hal_write4(mh, MALO_REG_A2H_INTERRUPT_MASK, mask);
673 	(void)malo_hal_read4(mh, MALO_REG_INT_CODE);
674 }
675 
676 int
677 malo_hal_setchannel(struct malo_hal *mh, const struct malo_hal_channel *chan)
678 {
679 	struct malo_cmd_fw_set_rf_channel *cmd;
680 	int ret;
681 
682 	MALO_HAL_LOCK(mh);
683 
684 	_CMD_SETUP(cmd, struct malo_cmd_fw_set_rf_channel,
685 	    MALO_HOSTCMD_SET_RF_CHANNEL);
686 	cmd->action = htole16(MALO_HOSTCMD_ACT_GEN_SET);
687 	cmd->cur_channel = chan->channel;
688 
689 	ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_SET_RF_CHANNEL);
690 
691 	MALO_HAL_UNLOCK(mh);
692 
693 	return ret;
694 }
695 
696 int
697 malo_hal_settxpower(struct malo_hal *mh, const struct malo_hal_channel *c)
698 {
699 	struct malo_cmd_rf_tx_power *cmd;
700 	const struct malo_hal_caldata *cal = &mh->mh_caldata;
701 	uint8_t chan = c->channel;
702 	uint16_t pow;
703 	int i, idx, ret;
704 
705 	MALO_HAL_LOCK(mh);
706 
707 	_CMD_SETUP(cmd, struct malo_cmd_rf_tx_power,
708 	    MALO_HOSTCMD_802_11_RF_TX_POWER);
709 	cmd->action = htole16(MALO_HOSTCMD_ACT_GEN_SET_LIST);
710 	for (i = 0; i < 4; i++) {
711 		idx = (chan - 1) * 4 + i;
712 		pow = cal->pt_ratetable_20m[idx];
713 		cmd->power_levellist[i] = htole16(pow);
714 	}
715 	ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_802_11_RF_TX_POWER);
716 
717 	MALO_HAL_UNLOCK(mh);
718 
719 	return ret;
720 }
721 
722 int
723 malo_hal_setpromisc(struct malo_hal *mh, int enable)
724 {
725 	/* XXX need host cmd */
726 	return 0;
727 }
728 
729 int
730 malo_hal_setassocid(struct malo_hal *mh,
731     const uint8_t bssid[IEEE80211_ADDR_LEN], uint16_t associd)
732 {
733 	struct malo_cmd_fw_set_aid *cmd;
734 	int ret;
735 
736 	MALO_HAL_LOCK(mh);
737 
738 	_CMD_SETUP(cmd, struct malo_cmd_fw_set_aid,
739 	    MALO_HOSTCMD_SET_AID);
740 	cmd->cmdhdr.seqnum = 1;
741 	cmd->associd = htole16(associd);
742 	IEEE80211_ADDR_COPY(&cmd->macaddr[0], bssid);
743 
744 	ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_SET_AID);
745 	MALO_HAL_UNLOCK(mh);
746 	return ret;
747 }
748 
749 /*
750  * Kick the firmware to tell it there are new tx descriptors
751  * for processing.  The driver says what h/w q has work in
752  * case the f/w ever gets smarter.
753  */
754 void
755 malo_hal_txstart(struct malo_hal *mh, int qnum)
756 {
757 	bus_space_write_4(mh->mh_iot, mh->mh_ioh,
758 	    MALO_REG_H2A_INTERRUPT_EVENTS, MALO_H2ARIC_BIT_PPA_READY);
759 	(void) bus_space_read_4(mh->mh_iot, mh->mh_ioh, MALO_REG_INT_CODE);
760 }
761 
762 /*
763  * Return the current ISR setting and clear the cause.
764  */
765 void
766 malo_hal_getisr(struct malo_hal *mh, uint32_t *status)
767 {
768 	uint32_t cause;
769 
770 	cause = bus_space_read_4(mh->mh_iot, mh->mh_ioh,
771 	    MALO_REG_A2H_INTERRUPT_CAUSE);
772 	if (cause == 0xffffffff) {	/* card removed */
773 		cause = 0;
774 	} else if (cause != 0) {
775 		/* clear cause bits */
776 		bus_space_write_4(mh->mh_iot, mh->mh_ioh,
777 		    MALO_REG_A2H_INTERRUPT_CAUSE, cause &~ mh->mh_imask);
778 		(void) bus_space_read_4(mh->mh_iot, mh->mh_ioh,
779 		    MALO_REG_INT_CODE);
780 		cause &= mh->mh_imask;
781 	}
782 
783 	*status = cause;
784 }
785 
786 /*
787  * Callback from the driver on a cmd done interrupt.  Nothing to do right
788  * now as we spin waiting for cmd completion.
789  */
790 void
791 malo_hal_cmddone(struct malo_hal *mh)
792 {
793 	/* NB : do nothing.  */
794 }
795 
796 int
797 malo_hal_prescan(struct malo_hal *mh)
798 {
799 	struct malo_cmd_prescan *cmd;
800 	int ret;
801 
802 	MALO_HAL_LOCK(mh);
803 
804 	_CMD_SETUP(cmd, struct malo_cmd_prescan, MALO_HOSTCMD_SET_PRE_SCAN);
805 	cmd->cmdhdr.seqnum = 1;
806 
807 	ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_SET_PRE_SCAN);
808 
809 	MALO_HAL_UNLOCK(mh);
810 
811 	return ret;
812 }
813 
814 int
815 malo_hal_postscan(struct malo_hal *mh, uint8_t *macaddr, uint8_t ibsson)
816 {
817 	struct malo_cmd_postscan *cmd;
818 	int ret;
819 
820 	MALO_HAL_LOCK(mh);
821 
822 	_CMD_SETUP(cmd, struct malo_cmd_postscan, MALO_HOSTCMD_SET_POST_SCAN);
823 	cmd->cmdhdr.seqnum = 1;
824 	cmd->isibss = htole32(ibsson);
825 	IEEE80211_ADDR_COPY(&cmd->bssid[0], macaddr);
826 
827 	ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_SET_POST_SCAN);
828 
829 	MALO_HAL_UNLOCK(mh);
830 
831 	return ret;
832 }
833 
834 int
835 malo_hal_set_slot(struct malo_hal *mh, int is_short)
836 {
837 	int ret;
838 	struct malo_cmd_fw_setslot *cmd;
839 
840 	MALO_HAL_LOCK(mh);
841 
842 	_CMD_SETUP(cmd, struct malo_cmd_fw_setslot, MALO_HOSTCMD_SET_SLOT);
843 	cmd->action = htole16(MALO_HOSTCMD_ACT_GEN_SET);
844 	cmd->slot = (is_short == 1 ? 1 : 0);
845 
846 	ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_SET_SLOT);
847 
848 	MALO_HAL_UNLOCK(mh);
849 
850 	return ret;
851 }
852 
853 int
854 malo_hal_set_rate(struct malo_hal *mh, uint16_t curmode, uint8_t rate)
855 {
856 	int i, ret;
857 	struct malo_cmd_set_rate *cmd;
858 
859 	MALO_HAL_LOCK(mh);
860 
861 	_CMD_SETUP(cmd, struct malo_cmd_set_rate, MALO_HOSTCMD_SET_RATE);
862 	cmd->aprates[0] = 2;
863 	cmd->aprates[1] = 4;
864 	cmd->aprates[2] = 11;
865 	cmd->aprates[3] = 22;
866 	if (curmode == IEEE80211_MODE_11G) {
867 		cmd->aprates[4] = 0;		/* XXX reserved?  */
868 		cmd->aprates[5] = 12;
869 		cmd->aprates[6] = 18;
870 		cmd->aprates[7] = 24;
871 		cmd->aprates[8] = 36;
872 		cmd->aprates[9] = 48;
873 		cmd->aprates[10] = 72;
874 		cmd->aprates[11] = 96;
875 		cmd->aprates[12] = 108;
876 	}
877 
878 	if (rate != 0) {
879 		/* fixed rate */
880 		for (i = 0; i < 13; i++) {
881 			if (cmd->aprates[i] == rate) {
882 				cmd->rateindex = i;
883 				cmd->dataratetype = 1;
884 				break;
885 			}
886 		}
887 	}
888 
889 	ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_SET_RATE);
890 
891 	MALO_HAL_UNLOCK(mh);
892 
893 	return ret;
894 }
895 
896 int
897 malo_hal_setmcast(struct malo_hal *mh, int nmc, const uint8_t macs[])
898 {
899 	struct malo_cmd_mcast *cmd;
900 	int ret;
901 
902 	if (nmc > MALO_HAL_MCAST_MAX)
903 		return EINVAL;
904 
905 	MALO_HAL_LOCK(mh);
906 
907 	_CMD_SETUP(cmd, struct malo_cmd_mcast, MALO_HOSTCMD_MAC_MULTICAST_ADR);
908 	memcpy(cmd->maclist, macs, nmc * IEEE80211_ADDR_LEN);
909 	cmd->numaddr = htole16(nmc);
910 	cmd->action = htole16(0xffff);
911 
912 	ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_MAC_MULTICAST_ADR);
913 
914 	MALO_HAL_UNLOCK(mh);
915 
916 	return ret;
917 }
918