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