]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/malo/if_malohal.c
Update libucl to 2014-03-03
[FreeBSD/FreeBSD.git] / sys / dev / malo / if_malohal.c
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 }