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