1 /*
2 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /*
7 * Copyright (c) 2007-2009 Sam Leffler, Errno Consulting
8 * Copyright (c) 2007-2008 Marvell Semiconductor, Inc.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
19 * redistribution must be conditioned upon including a substantially
20 * similar Disclaimer requirement for further binary redistribution.
21 *
22 * NO WARRANTY
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
26 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
27 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
28 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
31 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33 * THE POSSIBILITY OF SUCH DAMAGES.
34 */
35
36 /*
37 * Driver for the Marvell 88W8363 Wireless LAN controller.
38 */
39 #include <sys/stat.h>
40 #include <sys/dlpi.h>
41 #include <inet/common.h>
42 #include <inet/mi.h>
43 #include <sys/stream.h>
44 #include <sys/errno.h>
45 #include <sys/stropts.h>
46 #include <sys/stat.h>
47 #include <sys/sunddi.h>
48 #include <sys/strsubr.h>
49 #include <sys/strsun.h>
50 #include <sys/pci.h>
51 #include <sys/mac_provider.h>
52 #include <sys/mac_wifi.h>
53 #include <sys/net80211.h>
54 #include <inet/wifi_ioctl.h>
55
56 #include "mwl_var.h"
57
58 static int mwl_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd);
59 static int mwl_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd);
60 static int mwl_quiesce(dev_info_t *devinfo);
61
62 DDI_DEFINE_STREAM_OPS(mwl_dev_ops, nulldev, nulldev, mwl_attach, mwl_detach,
63 nodev, NULL, D_MP, NULL, mwl_quiesce);
64
65 static struct modldrv mwl_modldrv = {
66 &mod_driverops, /* Type of module. This one is a driver */
67 "Marvell 88W8363 WiFi driver v1.1", /* short description */
68 &mwl_dev_ops /* driver specific ops */
69 };
70
71 static struct modlinkage modlinkage = {
72 MODREV_1, (void *)&mwl_modldrv, NULL
73 };
74
75 static void *mwl_soft_state_p = NULL;
76
77 static int mwl_m_stat(void *, uint_t, uint64_t *);
78 static int mwl_m_start(void *);
79 static void mwl_m_stop(void *);
80 static int mwl_m_promisc(void *, boolean_t);
81 static int mwl_m_multicst(void *, boolean_t, const uint8_t *);
82 static int mwl_m_unicst(void *, const uint8_t *);
83 static mblk_t *mwl_m_tx(void *, mblk_t *);
84 static void mwl_m_ioctl(void *, queue_t *, mblk_t *);
85 static int mwl_m_setprop(void *arg, const char *pr_name,
86 mac_prop_id_t wldp_pr_num,
87 uint_t wldp_length, const void *wldp_buf);
88 static int mwl_m_getprop(void *arg, const char *pr_name,
89 mac_prop_id_t wldp_pr_num, uint_t wldp_length,
90 void *wldp_buf);
91 static void mwl_m_propinfo(void *, const char *, mac_prop_id_t,
92 mac_prop_info_handle_t);
93
94 static mac_callbacks_t mwl_m_callbacks = {
95 MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
96 mwl_m_stat,
97 mwl_m_start,
98 mwl_m_stop,
99 mwl_m_promisc,
100 mwl_m_multicst,
101 mwl_m_unicst,
102 mwl_m_tx,
103 NULL,
104 mwl_m_ioctl,
105 NULL,
106 NULL,
107 NULL,
108 mwl_m_setprop,
109 mwl_m_getprop,
110 mwl_m_propinfo
111 };
112
113 #define MWL_DBG_ATTACH (1 << 0)
114 #define MWL_DBG_DMA (1 << 1)
115 #define MWL_DBG_FW (1 << 2)
116 #define MWL_DBG_HW (1 << 3)
117 #define MWL_DBG_INTR (1 << 4)
118 #define MWL_DBG_RX (1 << 5)
119 #define MWL_DBG_TX (1 << 6)
120 #define MWL_DBG_CMD (1 << 7)
121 #define MWL_DBG_CRYPTO (1 << 8)
122 #define MWL_DBG_SR (1 << 9)
123 #define MWL_DBG_MSG (1 << 10)
124
125 uint32_t mwl_dbg_flags = 0x0;
126
127 #ifdef DEBUG
128 #define MWL_DBG \
129 mwl_debug
130 #else
131 #define MWL_DBG
132 #endif
133
134 /*
135 * PIO access attributes for registers
136 */
137 static ddi_device_acc_attr_t mwl_reg_accattr = {
138 DDI_DEVICE_ATTR_V0,
139 DDI_STRUCTURE_LE_ACC,
140 DDI_STRICTORDER_ACC,
141 DDI_DEFAULT_ACC
142 };
143
144 static ddi_device_acc_attr_t mwl_cmdbuf_accattr = {
145 DDI_DEVICE_ATTR_V0,
146 DDI_NEVERSWAP_ACC,
147 DDI_STRICTORDER_ACC,
148 DDI_DEFAULT_ACC
149 };
150
151 /*
152 * DMA access attributes for descriptors and bufs: NOT to be byte swapped.
153 */
154 static ddi_device_acc_attr_t mwl_desc_accattr = {
155 DDI_DEVICE_ATTR_V0,
156 DDI_NEVERSWAP_ACC,
157 DDI_STRICTORDER_ACC,
158 DDI_DEFAULT_ACC
159 };
160
161 static ddi_device_acc_attr_t mwl_buf_accattr = {
162 DDI_DEVICE_ATTR_V0,
163 DDI_NEVERSWAP_ACC,
164 DDI_STRICTORDER_ACC,
165 DDI_DEFAULT_ACC
166 };
167
168 /*
169 * Describes the chip's DMA engine
170 */
171 static ddi_dma_attr_t mwl_dma_attr = {
172 DMA_ATTR_V0, /* dma_attr version */
173 0x0000000000000000ull, /* dma_attr_addr_lo */
174 0xFFFFFFFF, /* dma_attr_addr_hi */
175 0x00000000FFFFFFFFull, /* dma_attr_count_max */
176 0x0000000000000001ull, /* dma_attr_align */
177 0x00000FFF, /* dma_attr_burstsizes */
178 0x00000001, /* dma_attr_minxfer */
179 0x000000000000FFFFull, /* dma_attr_maxxfer */
180 0xFFFFFFFFFFFFFFFFull, /* dma_attr_seg */
181 1, /* dma_attr_sgllen */
182 0x00000001, /* dma_attr_granular */
183 0 /* dma_attr_flags */
184 };
185
186 /*
187 * Supported rates for 802.11a/b/g modes (in 500Kbps unit).
188 */
189 static const struct ieee80211_rateset mwl_rateset_11b =
190 { 4, { 2, 4, 11, 22 } };
191
192 static const struct ieee80211_rateset mwl_rateset_11g =
193 { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
194
195 static int mwl_alloc_dma_mem(dev_info_t *, ddi_dma_attr_t *, size_t,
196 ddi_device_acc_attr_t *, uint_t, uint_t,
197 struct dma_area *);
198 static void mwl_free_dma_mem(struct dma_area *);
199 static int mwl_alloc_cmdbuf(struct mwl_softc *);
200 static void mwl_free_cmdbuf(struct mwl_softc *);
201 static int mwl_alloc_rx_ring(struct mwl_softc *, int);
202 static void mwl_free_rx_ring(struct mwl_softc *);
203 static int mwl_alloc_tx_ring(struct mwl_softc *, struct mwl_tx_ring *,
204 int);
205 static void mwl_free_tx_ring(struct mwl_softc *, struct mwl_tx_ring *);
206 static int mwl_setupdma(struct mwl_softc *);
207 static void mwl_txq_init(struct mwl_softc *, struct mwl_tx_ring *, int);
208 static int mwl_tx_setup(struct mwl_softc *, int, int);
209 static int mwl_setup_txq(struct mwl_softc *);
210 static int mwl_fwload(struct mwl_softc *, void *);
211 static int mwl_loadsym(ddi_modhandle_t, char *, char **, size_t *);
212 static void mwlFwReset(struct mwl_softc *);
213 static void mwlPokeSdramController(struct mwl_softc *, int);
214 static void mwlTriggerPciCmd(struct mwl_softc *);
215 static int mwlWaitFor(struct mwl_softc *, uint32_t);
216 static int mwlSendBlock(struct mwl_softc *, int, const void *, size_t);
217 static int mwlSendBlock2(struct mwl_softc *, const void *, size_t);
218 static void mwlSendCmd(struct mwl_softc *);
219 static int mwlExecuteCmd(struct mwl_softc *, unsigned short);
220 static int mwlWaitForCmdComplete(struct mwl_softc *, uint16_t);
221 static void dumpresult(struct mwl_softc *, int);
222 static int mwlResetHalState(struct mwl_softc *);
223 static int mwlGetPwrCalTable(struct mwl_softc *);
224 static int mwlGetCalTable(struct mwl_softc *, uint8_t, uint8_t);
225 static int mwlGetPwrCalTable(struct mwl_softc *);
226 static void dumpcaldata(const char *, const uint8_t *, int);
227 static void get2Ghz(MWL_HAL_CHANNELINFO *, const uint8_t *, int);
228 static void get5Ghz(MWL_HAL_CHANNELINFO *, const uint8_t *, int);
229 static void setmaxtxpow(struct mwl_hal_channel *, int, int);
230 static uint16_t ieee2mhz(int);
231 static const char *
232 mwlcmdname(int);
233 static int mwl_gethwspecs(struct mwl_softc *);
234 static int mwl_getchannels(struct mwl_softc *);
235 static void getchannels(struct mwl_softc *, int, int *,
236 struct mwl_channel *);
237 static void addchannels(struct mwl_channel *, int, int *,
238 const MWL_HAL_CHANNELINFO *, int);
239 static void addht40channels(struct mwl_channel *, int, int *,
240 const MWL_HAL_CHANNELINFO *, int);
241 static const struct mwl_channel *
242 findchannel(const struct mwl_channel *, int,
243 int, int);
244 static void addchan(struct mwl_channel *, int, int, int, int);
245
246 static int mwl_chan_set(struct mwl_softc *, struct mwl_channel *);
247 static void mwl_mapchan(MWL_HAL_CHANNEL *, const struct mwl_channel *);
248 static int mwl_setcurchanrates(struct mwl_softc *);
249 const struct ieee80211_rateset *
250 mwl_get_suprates(struct ieee80211com *,
251 const struct mwl_channel *);
252 static uint32_t cvtChannelFlags(const MWL_HAL_CHANNEL *);
253 static const struct mwl_hal_channel *
254 findhalchannel(const struct mwl_softc *,
255 const MWL_HAL_CHANNEL *);
256 enum ieee80211_phymode
257 mwl_chan2mode(const struct mwl_channel *);
258 static int mwl_map2regioncode(const struct mwl_regdomain *);
259 static int mwl_startrecv(struct mwl_softc *);
260 static int mwl_mode_init(struct mwl_softc *);
261 static void mwl_hal_intrset(struct mwl_softc *, uint32_t);
262 static void mwl_hal_getisr(struct mwl_softc *, uint32_t *);
263 static int mwl_hal_sethwdma(struct mwl_softc *,
264 const struct mwl_hal_txrxdma *);
265 static int mwl_hal_getchannelinfo(struct mwl_softc *, int, int,
266 const MWL_HAL_CHANNELINFO **);
267 static int mwl_hal_setmac_locked(struct mwl_softc *, const uint8_t *);
268 static int mwl_hal_keyreset(struct mwl_softc *, const MWL_HAL_KEYVAL *,
269 const uint8_t mac[IEEE80211_ADDR_LEN]);
270 static int mwl_hal_keyset(struct mwl_softc *, const MWL_HAL_KEYVAL *,
271 const uint8_t mac[IEEE80211_ADDR_LEN]);
272 static int mwl_hal_newstation(struct mwl_softc *, const uint8_t *,
273 uint16_t, uint16_t, const MWL_HAL_PEERINFO *, int, int);
274 static int mwl_hal_setantenna(struct mwl_softc *, MWL_HAL_ANTENNA, int);
275 static int mwl_hal_setradio(struct mwl_softc *, int, MWL_HAL_PREAMBLE);
276 static int mwl_hal_setwmm(struct mwl_softc *, int);
277 static int mwl_hal_setchannel(struct mwl_softc *, const MWL_HAL_CHANNEL *);
278 static int mwl_hal_settxpower(struct mwl_softc *, const MWL_HAL_CHANNEL *,
279 uint8_t);
280 static int mwl_hal_settxrate(struct mwl_softc *, MWL_HAL_TXRATE_HANDLING,
281 const MWL_HAL_TXRATE *);
282 static int mwl_hal_settxrate_auto(struct mwl_softc *,
283 const MWL_HAL_TXRATE *);
284 static int mwl_hal_setrateadaptmode(struct mwl_softc *, uint16_t);
285 static int mwl_hal_setoptimizationlevel(struct mwl_softc *, int);
286 static int mwl_hal_setregioncode(struct mwl_softc *, int);
287 static int mwl_hal_setassocid(struct mwl_softc *, const uint8_t *,
288 uint16_t);
289 static int mwl_setrates(struct ieee80211com *);
290 static int mwl_hal_setrtsthreshold(struct mwl_softc *, int);
291 static int mwl_hal_setcsmode(struct mwl_softc *, MWL_HAL_CSMODE);
292 static int mwl_hal_setpromisc(struct mwl_softc *, int);
293 static int mwl_hal_start(struct mwl_softc *);
294 static int mwl_hal_setinframode(struct mwl_softc *);
295 static int mwl_hal_stop(struct mwl_softc *);
296 static struct ieee80211_node *
297 mwl_node_alloc(struct ieee80211com *);
298 static void mwl_node_free(struct ieee80211_node *);
299 static int mwl_key_alloc(struct ieee80211com *,
300 const struct ieee80211_key *,
301 ieee80211_keyix *, ieee80211_keyix *);
302 static int mwl_key_delete(struct ieee80211com *,
303 const struct ieee80211_key *);
304 static int mwl_key_set(struct ieee80211com *, const struct ieee80211_key *,
305 const uint8_t mac[IEEE80211_ADDR_LEN]);
306 static void mwl_setanywepkey(struct ieee80211com *, const uint8_t *);
307 static void mwl_setglobalkeys(struct ieee80211com *c);
308 static int addgroupflags(MWL_HAL_KEYVAL *, const struct ieee80211_key *);
309 static void mwl_hal_txstart(struct mwl_softc *, int);
310 static int mwl_send(ieee80211com_t *, mblk_t *, uint8_t);
311 static void mwl_next_scan(void *);
312 static MWL_HAL_PEERINFO *
313 mkpeerinfo(MWL_HAL_PEERINFO *, const struct ieee80211_node *);
314 static uint32_t get_rate_bitmap(const struct ieee80211_rateset *);
315 static int mwl_newstate(struct ieee80211com *, enum ieee80211_state, int);
316 static int cvtrssi(uint8_t);
317 static uint_t mwl_intr(caddr_t, caddr_t);
318 static uint_t mwl_softintr(caddr_t, caddr_t);
319 static void mwl_tx_intr(struct mwl_softc *);
320 static void mwl_rx_intr(struct mwl_softc *);
321 static int mwl_init(struct mwl_softc *);
322 static void mwl_stop(struct mwl_softc *);
323 static int mwl_resume(struct mwl_softc *);
324
325
326 #ifdef DEBUG
327 static void
328 mwl_debug(uint32_t dbg_flags, const int8_t *fmt, ...)
329 {
330 va_list args;
331
332 if (dbg_flags & mwl_dbg_flags) {
333 va_start(args, fmt);
334 vcmn_err(CE_CONT, fmt, args);
335 va_end(args);
336 }
337 }
338 #endif
339
340 /*
341 * Allocate an DMA memory and a DMA handle for accessing it
342 */
343 static int
344 mwl_alloc_dma_mem(dev_info_t *devinfo, ddi_dma_attr_t *dma_attr,
345 size_t memsize, ddi_device_acc_attr_t *attr_p, uint_t alloc_flags,
346 uint_t bind_flags, struct dma_area *dma_p)
347 {
348 int err;
349
350 /*
351 * Allocate handle
352 */
353 err = ddi_dma_alloc_handle(devinfo, dma_attr,
354 DDI_DMA_SLEEP, NULL, &dma_p->dma_hdl);
355 if (err != DDI_SUCCESS) {
356 MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_dma_mem(): "
357 "failed to alloc handle\n");
358 goto fail1;
359 }
360
361 /*
362 * Allocate memory
363 */
364 err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p,
365 alloc_flags, DDI_DMA_SLEEP, NULL, &dma_p->mem_va,
366 &dma_p->alength, &dma_p->acc_hdl);
367 if (err != DDI_SUCCESS) {
368 MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_dma_mem(): "
369 "failed to alloc mem\n");
370 goto fail2;
371 }
372
373 /*
374 * Bind the two together
375 */
376 err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL,
377 dma_p->mem_va, dma_p->alength, bind_flags,
378 DDI_DMA_SLEEP, NULL, &dma_p->cookie, &dma_p->ncookies);
379 if (err != DDI_DMA_MAPPED) {
380 MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_dma_mem(): "
381 "failed to bind handle\n");
382 goto fail3;
383 }
384
385 if (dma_p->ncookies != 1) {
386 MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_dma_mem(): "
387 "failed to alloc cookies\n");
388 goto fail4;
389 }
390
391 dma_p->nslots = ~0U;
392 dma_p->size = ~0U;
393 dma_p->token = ~0U;
394 dma_p->offset = 0;
395
396 return (DDI_SUCCESS);
397
398 fail4:
399 (void) ddi_dma_unbind_handle(dma_p->dma_hdl);
400 fail3:
401 ddi_dma_mem_free(&dma_p->acc_hdl);
402 fail2:
403 ddi_dma_free_handle(&dma_p->dma_hdl);
404 fail1:
405 return (err);
406 }
407
408 static void
409 mwl_free_dma_mem(struct dma_area *dma_p)
410 {
411 if (dma_p->dma_hdl != NULL) {
412 (void) ddi_dma_unbind_handle(dma_p->dma_hdl);
413 if (dma_p->acc_hdl != NULL) {
414 ddi_dma_mem_free(&dma_p->acc_hdl);
415 dma_p->acc_hdl = NULL;
416 }
417 ddi_dma_free_handle(&dma_p->dma_hdl);
418 dma_p->ncookies = 0;
419 dma_p->dma_hdl = NULL;
420 }
421 }
422
423 static int
424 mwl_alloc_cmdbuf(struct mwl_softc *sc)
425 {
426 int err;
427 size_t size;
428
429 size = MWL_CMDBUF_SIZE;
430
431 err = mwl_alloc_dma_mem(sc->sc_dev, &mwl_dma_attr, size,
432 &mwl_cmdbuf_accattr, DDI_DMA_CONSISTENT,
433 DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
434 &sc->sc_cmd_dma);
435 if (err != DDI_SUCCESS) {
436 MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_cmdbuf(): "
437 "failed to alloc dma mem\n");
438 return (DDI_FAILURE);
439 }
440
441 sc->sc_cmd_mem = (uint16_t *)sc->sc_cmd_dma.mem_va;
442 sc->sc_cmd_dmaaddr = sc->sc_cmd_dma.cookie.dmac_address;
443
444 return (DDI_SUCCESS);
445 }
446
447 static void
448 mwl_free_cmdbuf(struct mwl_softc *sc)
449 {
450 if (sc->sc_cmd_mem != NULL)
451 mwl_free_dma_mem(&sc->sc_cmd_dma);
452 }
453
454 static int
455 mwl_alloc_rx_ring(struct mwl_softc *sc, int count)
456 {
457 struct mwl_rx_ring *ring;
458 struct mwl_rxdesc *ds;
459 struct mwl_rxbuf *bf;
460 int i, err, datadlen;
461
462 ring = &sc->sc_rxring;
463 ring->count = count;
464 ring->cur = ring->next = 0;
465 err = mwl_alloc_dma_mem(sc->sc_dev, &mwl_dma_attr,
466 count * sizeof (struct mwl_rxdesc),
467 &mwl_desc_accattr,
468 DDI_DMA_CONSISTENT, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
469 &ring->rxdesc_dma);
470 if (err) {
471 MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_rxring(): "
472 "alloc tx ring failed, size %d\n",
473 (uint32_t)(count * sizeof (struct mwl_rxdesc)));
474 return (DDI_FAILURE);
475 }
476
477 MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_rx_ring(): "
478 "dma len = %d\n", (uint32_t)(ring->rxdesc_dma.alength));
479 ring->desc = (struct mwl_rxdesc *)ring->rxdesc_dma.mem_va;
480 ring->physaddr = ring->rxdesc_dma.cookie.dmac_address;
481 bzero(ring->desc, count * sizeof (struct mwl_rxdesc));
482
483 datadlen = count * sizeof (struct mwl_rxbuf);
484 ring->buf = (struct mwl_rxbuf *)kmem_zalloc(datadlen, KM_SLEEP);
485 if (ring->buf == NULL) {
486 MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_rxring(): "
487 "could not alloc rx ring data buffer\n");
488 return (DDI_FAILURE);
489 }
490 bzero(ring->buf, count * sizeof (struct mwl_rxbuf));
491
492 /*
493 * Pre-allocate Rx buffers and populate Rx ring.
494 */
495 for (i = 0; i < count; i++) {
496 ds = &ring->desc[i];
497 bf = &ring->buf[i];
498 /* alloc DMA memory */
499 (void) mwl_alloc_dma_mem(sc->sc_dev, &mwl_dma_attr,
500 sc->sc_dmabuf_size,
501 &mwl_buf_accattr,
502 DDI_DMA_STREAMING,
503 DDI_DMA_READ | DDI_DMA_STREAMING,
504 &bf->rxbuf_dma);
505 bf->bf_mem = (uint8_t *)(bf->rxbuf_dma.mem_va);
506 bf->bf_baddr = bf->rxbuf_dma.cookie.dmac_address;
507 bf->bf_desc = ds;
508 bf->bf_daddr = ring->physaddr + _PTRDIFF(ds, ring->desc);
509 }
510
511 (void) ddi_dma_sync(ring->rxdesc_dma.dma_hdl,
512 0,
513 ring->rxdesc_dma.alength,
514 DDI_DMA_SYNC_FORDEV);
515
516 return (0);
517 }
518
519 static void
520 mwl_free_rx_ring(struct mwl_softc *sc)
521 {
522 struct mwl_rx_ring *ring;
523 struct mwl_rxbuf *bf;
524 int i;
525
526 ring = &sc->sc_rxring;
527
528 if (ring->desc != NULL) {
529 mwl_free_dma_mem(&ring->rxdesc_dma);
530 }
531
532 if (ring->buf != NULL) {
533 for (i = 0; i < ring->count; i++) {
534 bf = &ring->buf[i];
535 mwl_free_dma_mem(&bf->rxbuf_dma);
536 }
537 kmem_free(ring->buf,
538 (ring->count * sizeof (struct mwl_rxbuf)));
539 }
540 }
541
542 static int
543 mwl_alloc_tx_ring(struct mwl_softc *sc, struct mwl_tx_ring *ring,
544 int count)
545 {
546 struct mwl_txdesc *ds;
547 struct mwl_txbuf *bf;
548 int i, err, datadlen;
549
550 ring->count = count;
551 ring->queued = 0;
552 ring->cur = ring->next = ring->stat = 0;
553 err = mwl_alloc_dma_mem(sc->sc_dev, &mwl_dma_attr,
554 count * sizeof (struct mwl_txdesc), &mwl_desc_accattr,
555 DDI_DMA_CONSISTENT, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
556 &ring->txdesc_dma);
557 if (err) {
558 MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_tx_ring(): "
559 "alloc tx ring failed, size %d\n",
560 (uint32_t)(count * sizeof (struct mwl_txdesc)));
561 return (DDI_FAILURE);
562 }
563
564 MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_tx_ring(): "
565 "dma len = %d\n", (uint32_t)(ring->txdesc_dma.alength));
566 ring->desc = (struct mwl_txdesc *)ring->txdesc_dma.mem_va;
567 ring->physaddr = ring->txdesc_dma.cookie.dmac_address;
568 bzero(ring->desc, count * sizeof (struct mwl_txdesc));
569
570 datadlen = count * sizeof (struct mwl_txbuf);
571 ring->buf = kmem_zalloc(datadlen, KM_SLEEP);
572 bzero(ring->buf, count * sizeof (struct mwl_txbuf));
573
574 for (i = 0; i < count; i++) {
575 ds = &ring->desc[i];
576 bf = &ring->buf[i];
577 /* alloc DMA memory */
578 (void) mwl_alloc_dma_mem(sc->sc_dev, &mwl_dma_attr,
579 sc->sc_dmabuf_size,
580 &mwl_buf_accattr,
581 DDI_DMA_STREAMING,
582 DDI_DMA_WRITE | DDI_DMA_STREAMING,
583 &bf->txbuf_dma);
584 bf->bf_baddr = bf->txbuf_dma.cookie.dmac_address;
585 bf->bf_mem = (uint8_t *)(bf->txbuf_dma.mem_va);
586 bf->bf_daddr = ring->physaddr + _PTRDIFF(ds, ring->desc);
587 bf->bf_desc = ds;
588 }
589
590 (void) ddi_dma_sync(ring->txdesc_dma.dma_hdl,
591 0,
592 ring->txdesc_dma.alength,
593 DDI_DMA_SYNC_FORDEV);
594
595 return (0);
596 }
597
598 /* ARGSUSED */
599 static void
600 mwl_free_tx_ring(struct mwl_softc *sc, struct mwl_tx_ring *ring)
601 {
602 struct mwl_txbuf *bf;
603 int i;
604
605 if (ring->desc != NULL) {
606 mwl_free_dma_mem(&ring->txdesc_dma);
607 }
608
609 if (ring->buf != NULL) {
610 for (i = 0; i < ring->count; i++) {
611 bf = &ring->buf[i];
612 mwl_free_dma_mem(&bf->txbuf_dma);
613 }
614 kmem_free(ring->buf,
615 (ring->count * sizeof (struct mwl_txbuf)));
616 }
617 }
618
619 /*
620 * Inform the f/w about location of the tx/rx dma data structures
621 * and related state. This cmd must be done immediately after a
622 * mwl_hal_gethwspecs call or the f/w will lockup.
623 */
624 static int
625 mwl_hal_sethwdma(struct mwl_softc *sc, const struct mwl_hal_txrxdma *dma)
626 {
627 HostCmd_DS_SET_HW_SPEC *pCmd;
628 int retval;
629
630 _CMD_SETUP(pCmd, HostCmd_DS_SET_HW_SPEC, HostCmd_CMD_SET_HW_SPEC);
631 pCmd->WcbBase[0] = LE_32(dma->wcbBase[0]);
632 pCmd->WcbBase[1] = LE_32(dma->wcbBase[1]);
633 pCmd->WcbBase[2] = LE_32(dma->wcbBase[2]);
634 pCmd->WcbBase[3] = LE_32(dma->wcbBase[3]);
635 pCmd->TxWcbNumPerQueue = LE_32(dma->maxNumTxWcb);
636 pCmd->NumTxQueues = LE_32(dma->maxNumWCB);
637 pCmd->TotalRxWcb = LE_32(1); /* XXX */
638 pCmd->RxPdWrPtr = LE_32(dma->rxDescRead);
639 /*
640 * pCmd->Flags = LE_32(SET_HW_SPEC_HOSTFORM_BEACON
641 * #ifdef MWL_HOST_PS_SUPPORT
642 * | SET_HW_SPEC_HOST_POWERSAVE
643 * #endif
644 * | SET_HW_SPEC_HOSTFORM_PROBERESP);
645 */
646 pCmd->Flags = 0;
647 /* disable multi-bss operation for A1-A4 parts */
648 if (sc->sc_revs.mh_macRev < 5)
649 pCmd->Flags |= LE_32(SET_HW_SPEC_DISABLEMBSS);
650
651 retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_HW_SPEC);
652 if (retval == 0) {
653 if (pCmd->Flags & LE_32(SET_HW_SPEC_DISABLEMBSS))
654 sc->sc_hw_flags &= ~MHF_MBSS;
655 else
656 sc->sc_hw_flags |= MHF_MBSS;
657 }
658
659 return (retval);
660 }
661
662 /*
663 * Inform firmware of our tx/rx dma setup. The BAR 0
664 * writes below are for compatibility with older firmware.
665 * For current firmware we send this information with a
666 * cmd block via mwl_hal_sethwdma.
667 */
668 static int
669 mwl_setupdma(struct mwl_softc *sc)
670 {
671 int i, err;
672
673 sc->sc_hwdma.rxDescRead = sc->sc_rxring.physaddr;
674 mwl_mem_write4(sc, sc->sc_hwspecs.rxDescRead, sc->sc_hwdma.rxDescRead);
675 mwl_mem_write4(sc, sc->sc_hwspecs.rxDescWrite, sc->sc_hwdma.rxDescRead);
676
677 for (i = 0; i < MWL_NUM_TX_QUEUES - MWL_NUM_ACK_QUEUES; i++) {
678 struct mwl_tx_ring *txring = &sc->sc_txring[i];
679 sc->sc_hwdma.wcbBase[i] = txring->physaddr;
680 mwl_mem_write4(sc, sc->sc_hwspecs.wcbBase[i],
681 sc->sc_hwdma.wcbBase[i]);
682 }
683 sc->sc_hwdma.maxNumTxWcb = MWL_TX_RING_COUNT;
684 sc->sc_hwdma.maxNumWCB = MWL_NUM_TX_QUEUES - MWL_NUM_ACK_QUEUES;
685
686 err = mwl_hal_sethwdma(sc, &sc->sc_hwdma);
687 if (err != 0) {
688 MWL_DBG(MWL_DBG_DMA, "mwl: mwl_setupdma(): "
689 "unable to setup tx/rx dma; hal status %u\n", err);
690 /* XXX */
691 }
692
693 return (err);
694 }
695
696 /* ARGSUSED */
697 static void
698 mwl_txq_init(struct mwl_softc *sc, struct mwl_tx_ring *txring, int qnum)
699 {
700 struct mwl_txbuf *bf;
701 struct mwl_txdesc *ds;
702 int i;
703
704 txring->qnum = qnum;
705 txring->txpri = 0; /* XXX */
706
707 bf = txring->buf;
708 ds = txring->desc;
709 for (i = 0; i < MWL_TX_RING_COUNT - 1; i++) {
710 bf++;
711 ds->pPhysNext = bf->bf_daddr;
712 ds++;
713 }
714 bf = txring->buf;
715 ds->pPhysNext = LE_32(bf->bf_daddr);
716 }
717
718 /*
719 * Setup a hardware data transmit queue for the specified
720 * access control. We record the mapping from ac's
721 * to h/w queues for use by mwl_tx_start.
722 */
723 static int
724 mwl_tx_setup(struct mwl_softc *sc, int ac, int mvtype)
725 {
726 #define N(a) (sizeof (a)/sizeof (a[0]))
727 struct mwl_tx_ring *txring;
728
729 if (ac >= N(sc->sc_ac2q)) {
730 MWL_DBG(MWL_DBG_DMA, "mwl: mwl_tx_setup(): "
731 "AC %u out of range, max %u!\n",
732 ac, (uint_t)N(sc->sc_ac2q));
733 return (0);
734 }
735 if (mvtype >= MWL_NUM_TX_QUEUES) {
736 MWL_DBG(MWL_DBG_DMA, "mwl: mwl_tx_setup(): "
737 "mvtype %u out of range, max %u!\n",
738 mvtype, MWL_NUM_TX_QUEUES);
739 return (0);
740 }
741 txring = &sc->sc_txring[mvtype];
742 mwl_txq_init(sc, txring, mvtype);
743 sc->sc_ac2q[ac] = txring;
744 return (1);
745 #undef N
746 }
747
748 static int
749 mwl_setup_txq(struct mwl_softc *sc)
750 {
751 int err = 0;
752
753 /* NB: insure BK queue is the lowest priority h/w queue */
754 if (!mwl_tx_setup(sc, WME_AC_BK, MWL_WME_AC_BK)) {
755 MWL_DBG(MWL_DBG_DMA, "mwl: mwl_setup_txq(): "
756 "unable to setup xmit queue for %s traffic!\n",
757 mwl_wme_acnames[WME_AC_BK]);
758 err = EIO;
759 return (err);
760 }
761 if (!mwl_tx_setup(sc, WME_AC_BE, MWL_WME_AC_BE) ||
762 !mwl_tx_setup(sc, WME_AC_VI, MWL_WME_AC_VI) ||
763 !mwl_tx_setup(sc, WME_AC_VO, MWL_WME_AC_VO)) {
764 /*
765 * Not enough hardware tx queues to properly do WME;
766 * just punt and assign them all to the same h/w queue.
767 * We could do a better job of this if, for example,
768 * we allocate queues when we switch from station to
769 * AP mode.
770 */
771 sc->sc_ac2q[WME_AC_BE] = sc->sc_ac2q[WME_AC_BK];
772 sc->sc_ac2q[WME_AC_VI] = sc->sc_ac2q[WME_AC_BK];
773 sc->sc_ac2q[WME_AC_VO] = sc->sc_ac2q[WME_AC_BK];
774 }
775
776 return (err);
777 }
778
779 /*
780 * find mwl firmware module's "_start" "_end" symbols
781 * and get its size.
782 */
783 static int
784 mwl_loadsym(ddi_modhandle_t modp, char *sym, char **start, size_t *len)
785 {
786 char start_sym[64];
787 char end_sym[64];
788 char *p, *end;
789 int rv;
790 size_t n;
791
792 (void) snprintf(start_sym, sizeof (start_sym), "%s_start", sym);
793 (void) snprintf(end_sym, sizeof (end_sym), "%s_end", sym);
794
795 p = (char *)ddi_modsym(modp, start_sym, &rv);
796 if (p == NULL || rv != 0) {
797 MWL_DBG(MWL_DBG_FW, "mwl: mwl_loadsym(): "
798 "mod %s: symbol %s not found\n", sym, start_sym);
799 return (-1);
800 }
801
802 end = (char *)ddi_modsym(modp, end_sym, &rv);
803 if (end == NULL || rv != 0) {
804 MWL_DBG(MWL_DBG_FW, "mwl: mwl_loadsym(): "
805 "mod %s: symbol %s not found\n", sym, end_sym);
806 return (-1);
807 }
808
809 n = _PTRDIFF(end, p);
810 *start = p;
811 *len = n;
812
813 return (0);
814 }
815
816 static void
817 mwlFwReset(struct mwl_softc *sc)
818 {
819 if (mwl_ctl_read4(sc, MACREG_REG_INT_CODE) == 0xffffffff) {
820 MWL_DBG(MWL_DBG_FW, "mwl: mwlFWReset(): "
821 "device not present!\n");
822 return;
823 }
824
825 mwl_ctl_write4(sc, MACREG_REG_H2A_INTERRUPT_EVENTS, ISR_RESET);
826 sc->sc_hw_flags &= ~MHF_FWHANG;
827 }
828
829 static void
830 mwlPokeSdramController(struct mwl_softc *sc, int SDRAMSIZE_Addr)
831 {
832 /* Set up sdram controller for superflyv2 */
833 mwl_ctl_write4(sc, 0x00006014, 0x33);
834 mwl_ctl_write4(sc, 0x00006018, 0xa3a2632);
835 mwl_ctl_write4(sc, 0x00006010, SDRAMSIZE_Addr);
836 }
837
838 static void
839 mwlTriggerPciCmd(struct mwl_softc *sc)
840 {
841 (void) ddi_dma_sync(sc->sc_cmd_dma.dma_hdl,
842 0,
843 sc->sc_cmd_dma.alength,
844 DDI_DMA_SYNC_FORDEV);
845
846 mwl_ctl_write4(sc, MACREG_REG_GEN_PTR, sc->sc_cmd_dmaaddr);
847 (void) mwl_ctl_read4(sc, MACREG_REG_INT_CODE);
848
849 mwl_ctl_write4(sc, MACREG_REG_INT_CODE, 0x00);
850 (void) mwl_ctl_read4(sc, MACREG_REG_INT_CODE);
851
852 mwl_ctl_write4(sc, MACREG_REG_H2A_INTERRUPT_EVENTS,
853 MACREG_H2ARIC_BIT_DOOR_BELL);
854 (void) mwl_ctl_read4(sc, MACREG_REG_INT_CODE);
855 }
856
857 static int
858 mwlWaitFor(struct mwl_softc *sc, uint32_t val)
859 {
860 int i;
861
862 for (i = 0; i < FW_MAX_NUM_CHECKS; i++) {
863 DELAY(FW_CHECK_USECS);
864 if (mwl_ctl_read4(sc, MACREG_REG_INT_CODE) == val)
865 return (1);
866 }
867 return (0);
868 }
869
870 /*
871 * Firmware block xmit when talking to the boot-rom.
872 */
873 static int
874 mwlSendBlock(struct mwl_softc *sc, int bsize, const void *data, size_t dsize)
875 {
876 sc->sc_cmd_mem[0] = LE_16(HostCmd_CMD_CODE_DNLD);
877 sc->sc_cmd_mem[1] = LE_16(bsize);
878 (void) memcpy(&sc->sc_cmd_mem[4], data, dsize);
879 mwlTriggerPciCmd(sc);
880 /* XXX 2000 vs 200 */
881 if (mwlWaitFor(sc, MACREG_INT_CODE_CMD_FINISHED)) {
882 mwl_ctl_write4(sc, MACREG_REG_INT_CODE, 0);
883 return (1);
884 }
885
886 MWL_DBG(MWL_DBG_FW, "mwl: mwlSendBlock(): "
887 "timeout waiting for CMD_FINISHED, INT_CODE 0x%x\n",
888 mwl_ctl_read4(sc, MACREG_REG_INT_CODE));
889 return (0);
890 }
891
892 /*
893 * Firmware block xmit when talking to the 1st-stage loader.
894 */
895 static int
896 mwlSendBlock2(struct mwl_softc *sc, const void *data, size_t dsize)
897 {
898 (void) memcpy(&sc->sc_cmd_mem[0], data, dsize);
899 mwlTriggerPciCmd(sc);
900 if (mwlWaitFor(sc, MACREG_INT_CODE_CMD_FINISHED)) {
901 mwl_ctl_write4(sc, MACREG_REG_INT_CODE, 0);
902 return (1);
903 }
904
905 MWL_DBG(MWL_DBG_FW, "mwl: mwlSendBlock2(): "
906 "timeout waiting for CMD_FINISHED, INT_CODE 0x%x\n",
907 mwl_ctl_read4(sc, MACREG_REG_INT_CODE));
908 return (0);
909 }
910
911 /* ARGSUSED */
912 static int
913 mwl_fwload(struct mwl_softc *sc, void *fwargs)
914 {
915 char *fwname = "mwlfw";
916 char *fwbootname = "mwlboot";
917 char *fwbinname = "mw88W8363fw";
918 char *fwboot_index, *fw_index;
919 uint8_t *fw, *fwboot;
920 ddi_modhandle_t modfw;
921 /* XXX get from firmware header */
922 uint32_t FwReadySignature = HostCmd_SOFTAP_FWRDY_SIGNATURE;
923 uint32_t OpMode = HostCmd_SOFTAP_MODE;
924 const uint8_t *fp, *ep;
925 size_t fw_size, fwboot_size;
926 uint32_t blocksize, nbytes;
927 int i, rv, err, ntries;
928
929 rv = err = 0;
930 fw = fwboot = NULL;
931 fw_index = fwboot_index = NULL;
932
933 modfw = ddi_modopen(fwname, KRTLD_MODE_FIRST, &rv);
934 if (modfw == NULL) {
935 MWL_DBG(MWL_DBG_FW, "mwl: mwl_fwload(): "
936 "module %s not found\n", fwname);
937 err = -1;
938 goto bad2;
939 }
940
941 err = mwl_loadsym(modfw, fwbootname, &fwboot_index, &fwboot_size);
942 if (err != 0) {
943 MWL_DBG(MWL_DBG_FW, "mwl: mwl_fwload(): "
944 "could not get boot firmware\n");
945 err = -1;
946 goto bad2;
947 }
948
949 err = mwl_loadsym(modfw, fwbinname, &fw_index, &fw_size);
950 if (err != 0) {
951 MWL_DBG(MWL_DBG_FW, "mwl: mwl_fwload(): "
952 "could not get firmware\n");
953 err = -1;
954 goto bad2;
955 }
956
957 fwboot = (uint8_t *)kmem_alloc(fwboot_size, KM_SLEEP);
958 if (fwboot == NULL) {
959 MWL_DBG(MWL_DBG_FW, "mwl: mwl_loadfirmware(): "
960 "failed to alloc boot firmware memory\n");
961 err = -1;
962 goto bad2;
963 }
964 (void) memcpy(fwboot, fwboot_index, fwboot_size);
965
966 fw = (uint8_t *)kmem_alloc(fw_size, KM_SLEEP);
967 if (fw == NULL) {
968 MWL_DBG(MWL_DBG_FW, "mwl: mwl_loadfirmware(): "
969 "failed to alloc firmware memory\n");
970 err = -1;
971 goto bad2;
972 }
973 (void) memcpy(fw, fw_index, fw_size);
974
975 if (modfw != NULL)
976 (void) ddi_modclose(modfw);
977
978 if (fw_size < 4) {
979 MWL_DBG(MWL_DBG_FW, "mwl: mwl_fwload(): "
980 "could not load firmware image %s\n",
981 fwname);
982 err = ENXIO;
983 goto bad2;
984 }
985
986 if (fw[0] == 0x01 && fw[1] == 0x00 &&
987 fw[2] == 0x00 && fw[3] == 0x00) {
988 /*
989 * 2-stage load, get the boot firmware.
990 */
991 if (fwboot == NULL) {
992 MWL_DBG(MWL_DBG_FW, "mwl: mwl_fwload(): "
993 "could not load firmware image %s\n",
994 fwbootname);
995 err = ENXIO;
996 goto bad2;
997 }
998 } else
999 fwboot = NULL;
1000
1001 mwlFwReset(sc);
1002
1003 mwl_ctl_write4(sc, MACREG_REG_A2H_INTERRUPT_CLEAR_SEL,
1004 MACREG_A2HRIC_BIT_MASK);
1005 mwl_ctl_write4(sc, MACREG_REG_A2H_INTERRUPT_CAUSE, 0x00);
1006 mwl_ctl_write4(sc, MACREG_REG_A2H_INTERRUPT_MASK, 0x00);
1007 mwl_ctl_write4(sc, MACREG_REG_A2H_INTERRUPT_STATUS_MASK,
1008 MACREG_A2HRIC_BIT_MASK);
1009 if (sc->sc_SDRAMSIZE_Addr != 0) {
1010 /* Set up sdram controller for superflyv2 */
1011 mwlPokeSdramController(sc, sc->sc_SDRAMSIZE_Addr);
1012 }
1013
1014 MWL_DBG(MWL_DBG_FW, "mwl: mwl_fwload(): "
1015 "load %s firmware image (%u bytes)\n",
1016 fwname, (unsigned int)fw_size);
1017
1018 if (fwboot != NULL) {
1019 /*
1020 * Do 2-stage load. The 1st stage loader is setup
1021 * with the bootrom loader then we load the real
1022 * image using a different handshake. With this
1023 * mechanism the firmware is segmented into chunks
1024 * that have a CRC. If a chunk is incorrect we'll
1025 * be told to retransmit.
1026 */
1027 /* XXX assumes hlpimage fits in a block */
1028 /* NB: zero size block indicates download is finished */
1029 if (!mwlSendBlock(sc, fwboot_size, fwboot, fwboot_size) ||
1030 !mwlSendBlock(sc, 0, NULL, 0)) {
1031 err = ETIMEDOUT;
1032 goto bad;
1033 }
1034 DELAY(200 * FW_CHECK_USECS);
1035 if (sc->sc_SDRAMSIZE_Addr != 0) {
1036 /* Set up sdram controller for superflyv2 */
1037 mwlPokeSdramController(sc, sc->sc_SDRAMSIZE_Addr);
1038 }
1039 nbytes = ntries = 0; /* NB: silence compiler */
1040 for (fp = fw, ep = fp + fw_size; fp < ep; ) {
1041 mwl_ctl_write4(sc, MACREG_REG_INT_CODE, 0);
1042 blocksize = mwl_ctl_read4(sc, MACREG_REG_SCRATCH);
1043 if (blocksize == 0) /* download complete */
1044 break;
1045 if (blocksize > 0x00000c00) {
1046 err = EINVAL;
1047 goto bad;
1048 }
1049 if ((blocksize & 0x1) == 0) {
1050 /* block successfully downloaded, advance */
1051 fp += nbytes;
1052 ntries = 0;
1053 } else {
1054 if (++ntries > 2) {
1055 /*
1056 * Guard against f/w telling us to
1057 * retry infinitely.
1058 */
1059 err = ELOOP;
1060 goto bad;
1061 }
1062 /* clear NAK bit/flag */
1063 blocksize &= ~0x1;
1064 }
1065 if (blocksize > _PTRDIFF(ep, fp)) {
1066 /* XXX this should not happen, what to do? */
1067 blocksize = _PTRDIFF(ep, fp);
1068 }
1069 nbytes = blocksize;
1070 if (!mwlSendBlock2(sc, fp, nbytes)) {
1071 err = ETIMEDOUT;
1072 goto bad;
1073 }
1074 }
1075 } else {
1076 for (fp = fw, ep = fp + fw_size; fp < ep; ) {
1077 nbytes = _PTRDIFF(ep, fp);
1078 if (nbytes > FW_DOWNLOAD_BLOCK_SIZE)
1079 nbytes = FW_DOWNLOAD_BLOCK_SIZE;
1080 if (!mwlSendBlock(sc, FW_DOWNLOAD_BLOCK_SIZE, fp,
1081 nbytes)) {
1082 err = EIO;
1083 goto bad;
1084 }
1085 fp += nbytes;
1086 }
1087 }
1088
1089 /*
1090 * Wait for firmware to startup; we monitor the
1091 * INT_CODE register waiting for a signature to
1092 * written back indicating it's ready to go.
1093 */
1094 sc->sc_cmd_mem[1] = 0;
1095 /*
1096 * XXX WAR for mfg fw download
1097 */
1098 if (OpMode != HostCmd_STA_MODE)
1099 mwlTriggerPciCmd(sc);
1100 for (i = 0; i < FW_MAX_NUM_CHECKS; i++) {
1101 mwl_ctl_write4(sc, MACREG_REG_GEN_PTR, OpMode);
1102 DELAY(FW_CHECK_USECS);
1103 if (mwl_ctl_read4(sc, MACREG_REG_INT_CODE) ==
1104 FwReadySignature) {
1105 mwl_ctl_write4(sc, MACREG_REG_INT_CODE, 0x00);
1106 return (mwlResetHalState(sc));
1107 }
1108 }
1109 MWL_DBG(MWL_DBG_FW, "mwl: mwl_fwload(): "
1110 "firmware download timeout\n");
1111 return (ETIMEDOUT);
1112 bad:
1113 mwlFwReset(sc);
1114 bad2:
1115 if (fw != NULL)
1116 kmem_free(fw, fw_size);
1117 if (fwboot != NULL)
1118 kmem_free(fwboot, fwboot_size);
1119 fwboot = fw = NULL;
1120 fwboot_index = fw_index = NULL;
1121 if (modfw != NULL)
1122 (void) ddi_modclose(modfw);
1123 return (err);
1124 }
1125
1126 /*
1127 * Low level firmware cmd block handshake support.
1128 */
1129 static void
1130 mwlSendCmd(struct mwl_softc *sc)
1131 {
1132 (void) ddi_dma_sync(sc->sc_cmd_dma.dma_hdl,
1133 0,
1134 sc->sc_cmd_dma.alength,
1135 DDI_DMA_SYNC_FORDEV);
1136
1137 mwl_ctl_write4(sc, MACREG_REG_GEN_PTR, sc->sc_cmd_dmaaddr);
1138 (void) mwl_ctl_read4(sc, MACREG_REG_INT_CODE);
1139
1140 mwl_ctl_write4(sc, MACREG_REG_H2A_INTERRUPT_EVENTS,
1141 MACREG_H2ARIC_BIT_DOOR_BELL);
1142 }
1143
1144 static int
1145 mwlExecuteCmd(struct mwl_softc *sc, unsigned short cmd)
1146 {
1147 if (mwl_ctl_read4(sc, MACREG_REG_INT_CODE) == 0xffffffff) {
1148 MWL_DBG(MWL_DBG_CMD, "mwl: mwlExecuteCmd(): "
1149 "device not present!\n");
1150 return (EIO);
1151 }
1152 mwlSendCmd(sc);
1153 if (!mwlWaitForCmdComplete(sc, 0x8000 | cmd)) {
1154 MWL_DBG(MWL_DBG_CMD, "mwl: mwlExecuteCmd(): "
1155 "timeout waiting for f/w cmd %s\n", mwlcmdname(cmd));
1156 return (ETIMEDOUT);
1157 }
1158 (void) ddi_dma_sync(sc->sc_cmd_dma.dma_hdl,
1159 0,
1160 sc->sc_cmd_dma.alength,
1161 DDI_DMA_SYNC_FORDEV);
1162
1163 MWL_DBG(MWL_DBG_CMD, "mwl: mwlExecuteCmd(): "
1164 "send cmd %s\n", mwlcmdname(cmd));
1165
1166 if (mwl_dbg_flags & MWL_DBG_CMD)
1167 dumpresult(sc, 1);
1168
1169 return (0);
1170 }
1171
1172 static int
1173 mwlWaitForCmdComplete(struct mwl_softc *sc, uint16_t cmdCode)
1174 {
1175 #define MAX_WAIT_FW_COMPLETE_ITERATIONS 10000
1176 int i;
1177
1178 for (i = 0; i < MAX_WAIT_FW_COMPLETE_ITERATIONS; i++) {
1179 if (sc->sc_cmd_mem[0] == LE_16(cmdCode))
1180 return (1);
1181 DELAY(1 * 1000);
1182 }
1183 return (0);
1184 #undef MAX_WAIT_FW_COMPLETE_ITERATIONS
1185 }
1186
1187 static const char *
1188 mwlcmdname(int cmd)
1189 {
1190 static char buf[12];
1191 #define CMD(x) case HostCmd_CMD_##x: return #x
1192 switch (cmd) {
1193 CMD(CODE_DNLD);
1194 CMD(GET_HW_SPEC);
1195 CMD(SET_HW_SPEC);
1196 CMD(MAC_MULTICAST_ADR);
1197 CMD(802_11_GET_STAT);
1198 CMD(MAC_REG_ACCESS);
1199 CMD(BBP_REG_ACCESS);
1200 CMD(RF_REG_ACCESS);
1201 CMD(802_11_RADIO_CONTROL);
1202 CMD(802_11_RF_TX_POWER);
1203 CMD(802_11_RF_ANTENNA);
1204 CMD(SET_BEACON);
1205 CMD(SET_RF_CHANNEL);
1206 CMD(SET_AID);
1207 CMD(SET_INFRA_MODE);
1208 CMD(SET_G_PROTECT_FLAG);
1209 CMD(802_11_RTS_THSD);
1210 CMD(802_11_SET_SLOT);
1211 CMD(SET_EDCA_PARAMS);
1212 CMD(802_11H_DETECT_RADAR);
1213 CMD(SET_WMM_MODE);
1214 CMD(HT_GUARD_INTERVAL);
1215 CMD(SET_FIXED_RATE);
1216 CMD(SET_LINKADAPT_CS_MODE);
1217 CMD(SET_MAC_ADDR);
1218 CMD(SET_RATE_ADAPT_MODE);
1219 CMD(BSS_START);
1220 CMD(SET_NEW_STN);
1221 CMD(SET_KEEP_ALIVE);
1222 CMD(SET_APMODE);
1223 CMD(SET_SWITCH_CHANNEL);
1224 CMD(UPDATE_ENCRYPTION);
1225 CMD(BASTREAM);
1226 CMD(SET_RIFS);
1227 CMD(SET_N_PROTECT_FLAG);
1228 CMD(SET_N_PROTECT_OPMODE);
1229 CMD(SET_OPTIMIZATION_LEVEL);
1230 CMD(GET_CALTABLE);
1231 CMD(SET_MIMOPSHT);
1232 CMD(GET_BEACON);
1233 CMD(SET_REGION_CODE);
1234 CMD(SET_POWERSAVESTATION);
1235 CMD(SET_TIM);
1236 CMD(GET_TIM);
1237 CMD(GET_SEQNO);
1238 CMD(DWDS_ENABLE);
1239 CMD(AMPDU_RETRY_RATEDROP_MODE);
1240 CMD(CFEND_ENABLE);
1241 }
1242 (void) snprintf(buf, sizeof (buf), "0x%x", cmd);
1243 return (buf);
1244 #undef CMD
1245 }
1246
1247 static void
1248 dumpresult(struct mwl_softc *sc, int showresult)
1249 {
1250 const FWCmdHdr *h = (const FWCmdHdr *)sc->sc_cmd_mem;
1251 int len;
1252
1253 len = LE_16(h->Length);
1254 #ifdef MWL_MBSS_SUPPORT
1255 MWL_DBG(MWL_DBG_CMD, "mwl: mwl_dumpresult(): "
1256 "Cmd %s Length %d SeqNum %d MacId %d",
1257 mwlcmdname(LE_16(h->Cmd) & ~0x8000), len, h->SeqNum, h->MacId);
1258 #else
1259 MWL_DBG(MWL_DBG_CMD, "mwl: mwl_dumpresult(): "
1260 "Cmd %s Length %d SeqNum %d",
1261 mwlcmdname(LE_16(h->Cmd) & ~0x8000), len, LE_16(h->SeqNum));
1262 #endif
1263 if (showresult) {
1264 const char *results[] =
1265 { "OK", "ERROR", "NOT_SUPPORT", "PENDING", "BUSY",
1266 "PARTIAL_DATA" };
1267 int result = LE_16(h->Result);
1268
1269 if (result <= HostCmd_RESULT_PARTIAL_DATA)
1270 MWL_DBG(MWL_DBG_CMD, "mwl: dumpresult(): "
1271 "Result %s", results[result]);
1272 else
1273 MWL_DBG(MWL_DBG_CMD, "mwl: dumpresult(): "
1274 "Result %d", result);
1275 }
1276 }
1277
1278 static int
1279 mwlGetCalTable(struct mwl_softc *sc, uint8_t annex, uint8_t index)
1280 {
1281 HostCmd_FW_GET_CALTABLE *pCmd;
1282 int retval;
1283
1284 _CMD_SETUP(pCmd, HostCmd_FW_GET_CALTABLE, HostCmd_CMD_GET_CALTABLE);
1285 pCmd->annex = annex;
1286 pCmd->index = index;
1287 (void) memset(pCmd->calTbl, 0, sizeof (pCmd->calTbl));
1288
1289 retval = mwlExecuteCmd(sc, HostCmd_CMD_GET_CALTABLE);
1290 if (retval == 0 &&
1291 pCmd->calTbl[0] != annex && annex != 0 && annex != 255)
1292 retval = EIO;
1293 return (retval);
1294 }
1295
1296 /*
1297 * Construct channel info for 2.4GHz channels from cal data.
1298 */
1299 static void
1300 get2Ghz(MWL_HAL_CHANNELINFO *ci, const uint8_t table[], int len)
1301 {
1302 int i, j;
1303
1304 j = 0;
1305 for (i = 0; i < len; i += 4) {
1306 struct mwl_hal_channel *hc = &ci->channels[j];
1307 hc->ieee = 1+j;
1308 hc->freq = ieee2mhz(1+j);
1309 (void) memcpy(hc->targetPowers, &table[i], 4);
1310 setmaxtxpow(hc, 0, 4);
1311 j++;
1312 }
1313 ci->nchannels = j;
1314 ci->freqLow = ieee2mhz(1);
1315 ci->freqHigh = ieee2mhz(j);
1316 }
1317
1318 /*
1319 * Construct channel info for 5GHz channels from cal data.
1320 */
1321 static void
1322 get5Ghz(MWL_HAL_CHANNELINFO *ci, const uint8_t table[], int len)
1323 {
1324 int i, j, f, l, h;
1325
1326 l = 32000;
1327 h = 0;
1328 j = 0;
1329 for (i = 0; i < len; i += 4) {
1330 struct mwl_hal_channel *hc;
1331
1332 if (table[i] == 0)
1333 continue;
1334 f = 5000 + 5*table[i];
1335 if (f < l)
1336 l = f;
1337 if (f > h)
1338 h = f;
1339 hc = &ci->channels[j];
1340 hc->freq = (uint16_t)f;
1341 hc->ieee = table[i];
1342 (void) memcpy(hc->targetPowers, &table[i], 4);
1343 setmaxtxpow(hc, 1, 4); /* NB: col 1 is the freq, skip */
1344 j++;
1345 }
1346 ci->nchannels = j;
1347 ci->freqLow = (uint16_t)((l == 32000) ? 0 : l);
1348 ci->freqHigh = (uint16_t)h;
1349 }
1350
1351 /*
1352 * Calculate the max tx power from the channel's cal data.
1353 */
1354 static void
1355 setmaxtxpow(struct mwl_hal_channel *hc, int i, int maxix)
1356 {
1357 hc->maxTxPow = hc->targetPowers[i];
1358 for (i++; i < maxix; i++)
1359 if (hc->targetPowers[i] > hc->maxTxPow)
1360 hc->maxTxPow = hc->targetPowers[i];
1361 }
1362
1363 static uint16_t
1364 ieee2mhz(int chan)
1365 {
1366 if (chan == 14)
1367 return (2484);
1368 if (chan < 14)
1369 return (2407 + chan * 5);
1370 return (2512 + (chan - 15) * 20);
1371 }
1372
1373 static void
1374 dumpcaldata(const char *name, const uint8_t *table, int n)
1375 {
1376 int i;
1377 MWL_DBG(MWL_DBG_HW, "\n%s:\n", name);
1378 for (i = 0; i < n; i += 4)
1379 MWL_DBG(MWL_DBG_HW, "[%2d] %3d %3d %3d %3d\n",
1380 i/4, table[i+0], table[i+1], table[i+2], table[i+3]);
1381 }
1382
1383 static int
1384 mwlGetPwrCalTable(struct mwl_softc *sc)
1385 {
1386 const uint8_t *data;
1387 MWL_HAL_CHANNELINFO *ci;
1388 int len;
1389
1390 /* NB: we hold the lock so it's ok to use cmdbuf */
1391 data = ((const HostCmd_FW_GET_CALTABLE *) sc->sc_cmd_mem)->calTbl;
1392 if (mwlGetCalTable(sc, 33, 0) == 0) {
1393 len = (data[2] | (data[3] << 8)) - 12;
1394 if (len > PWTAGETRATETABLE20M)
1395 len = PWTAGETRATETABLE20M;
1396 dumpcaldata("2.4G 20M", &data[12], len);
1397 get2Ghz(&sc->sc_20M, &data[12], len);
1398 }
1399 if (mwlGetCalTable(sc, 34, 0) == 0) {
1400 len = (data[2] | (data[3] << 8)) - 12;
1401 if (len > PWTAGETRATETABLE40M)
1402 len = PWTAGETRATETABLE40M;
1403 dumpcaldata("2.4G 40M", &data[12], len);
1404 ci = &sc->sc_40M;
1405 get2Ghz(ci, &data[12], len);
1406 }
1407 if (mwlGetCalTable(sc, 35, 0) == 0) {
1408 len = (data[2] | (data[3] << 8)) - 20;
1409 if (len > PWTAGETRATETABLE20M_5G)
1410 len = PWTAGETRATETABLE20M_5G;
1411 dumpcaldata("5G 20M", &data[20], len);
1412 get5Ghz(&sc->sc_20M_5G, &data[20], len);
1413 }
1414 if (mwlGetCalTable(sc, 36, 0) == 0) {
1415 len = (data[2] | (data[3] << 8)) - 20;
1416 if (len > PWTAGETRATETABLE40M_5G)
1417 len = PWTAGETRATETABLE40M_5G;
1418 dumpcaldata("5G 40M", &data[20], len);
1419 ci = &sc->sc_40M_5G;
1420 get5Ghz(ci, &data[20], len);
1421 }
1422 sc->sc_hw_flags |= MHF_CALDATA;
1423 return (0);
1424 }
1425
1426 /*
1427 * Reset internal state after a firmware download.
1428 */
1429 static int
1430 mwlResetHalState(struct mwl_softc *sc)
1431 {
1432 int err = 0;
1433
1434 /*
1435 * Fetch cal data for later use.
1436 * XXX may want to fetch other stuff too.
1437 */
1438 /* XXX check return */
1439 if ((sc->sc_hw_flags & MHF_CALDATA) == 0)
1440 err = mwlGetPwrCalTable(sc);
1441 return (err);
1442 }
1443
1444 #define IEEE80211_CHAN_HTG (IEEE80211_CHAN_HT|IEEE80211_CHAN_G)
1445 #define IEEE80211_CHAN_HTA (IEEE80211_CHAN_HT|IEEE80211_CHAN_A)
1446
1447 static void
1448 addchan(struct mwl_channel *c, int freq, int flags, int ieee, int txpow)
1449 {
1450 c->ic_freq = (uint16_t)freq;
1451 c->ic_flags = flags;
1452 c->ic_ieee = (uint8_t)ieee;
1453 c->ic_minpower = 0;
1454 c->ic_maxpower = 2*txpow;
1455 c->ic_maxregpower = (uint8_t)txpow;
1456 }
1457
1458 static const struct mwl_channel *
1459 findchannel(const struct mwl_channel chans[], int nchans,
1460 int freq, int flags)
1461 {
1462 const struct mwl_channel *c;
1463 int i;
1464
1465 for (i = 0; i < nchans; i++) {
1466 c = &chans[i];
1467 if (c->ic_freq == freq && c->ic_flags == flags)
1468 return (c);
1469 }
1470 return (NULL);
1471 }
1472
1473 static void
1474 addht40channels(struct mwl_channel chans[], int maxchans, int *nchans,
1475 const MWL_HAL_CHANNELINFO *ci, int flags)
1476 {
1477 struct mwl_channel *c;
1478 const struct mwl_channel *extc;
1479 const struct mwl_hal_channel *hc;
1480 int i;
1481
1482 c = &chans[*nchans];
1483
1484 flags &= ~IEEE80211_CHAN_HT;
1485 for (i = 0; i < ci->nchannels; i++) {
1486 /*
1487 * Each entry defines an HT40 channel pair; find the
1488 * extension channel above and the insert the pair.
1489 */
1490 hc = &ci->channels[i];
1491 extc = findchannel(chans, *nchans, hc->freq+20,
1492 flags | IEEE80211_CHAN_HT20);
1493 if (extc != NULL) {
1494 if (*nchans >= maxchans)
1495 break;
1496 addchan(c, hc->freq, flags | IEEE80211_CHAN_HT40U,
1497 hc->ieee, hc->maxTxPow);
1498 c->ic_extieee = extc->ic_ieee;
1499 c++, (*nchans)++;
1500 if (*nchans >= maxchans)
1501 break;
1502 addchan(c, extc->ic_freq, flags | IEEE80211_CHAN_HT40D,
1503 extc->ic_ieee, hc->maxTxPow);
1504 c->ic_extieee = hc->ieee;
1505 c++, (*nchans)++;
1506 }
1507 }
1508 }
1509
1510 static void
1511 addchannels(struct mwl_channel chans[], int maxchans, int *nchans,
1512 const MWL_HAL_CHANNELINFO *ci, int flags)
1513 {
1514 struct mwl_channel *c;
1515 int i;
1516
1517 c = &chans[*nchans];
1518
1519 for (i = 0; i < ci->nchannels; i++) {
1520 const struct mwl_hal_channel *hc;
1521
1522 hc = &ci->channels[i];
1523 if (*nchans >= maxchans)
1524 break;
1525 addchan(c, hc->freq, flags, hc->ieee, hc->maxTxPow);
1526 c++, (*nchans)++;
1527
1528 if (flags == IEEE80211_CHAN_G || flags == IEEE80211_CHAN_HTG) {
1529 /* g channel have a separate b-only entry */
1530 if (*nchans >= maxchans)
1531 break;
1532 c[0] = c[-1];
1533 c[-1].ic_flags = IEEE80211_CHAN_B;
1534 c++, (*nchans)++;
1535 }
1536 if (flags == IEEE80211_CHAN_HTG) {
1537 /* HT g channel have a separate g-only entry */
1538 if (*nchans >= maxchans)
1539 break;
1540 c[-1].ic_flags = IEEE80211_CHAN_G;
1541 c[0] = c[-1];
1542 c[0].ic_flags &= ~IEEE80211_CHAN_HT;
1543 c[0].ic_flags |= IEEE80211_CHAN_HT20; /* HT20 */
1544 c++, (*nchans)++;
1545 }
1546 if (flags == IEEE80211_CHAN_HTA) {
1547 /* HT a channel have a separate a-only entry */
1548 if (*nchans >= maxchans)
1549 break;
1550 c[-1].ic_flags = IEEE80211_CHAN_A;
1551 c[0] = c[-1];
1552 c[0].ic_flags &= ~IEEE80211_CHAN_HT;
1553 c[0].ic_flags |= IEEE80211_CHAN_HT20; /* HT20 */
1554 c++, (*nchans)++;
1555 }
1556 }
1557 }
1558
1559 static int
1560 mwl_hal_getchannelinfo(struct mwl_softc *sc, int band, int chw,
1561 const MWL_HAL_CHANNELINFO **ci)
1562 {
1563 switch (band) {
1564 case MWL_FREQ_BAND_2DOT4GHZ:
1565 *ci = (chw == MWL_CH_20_MHz_WIDTH) ? &sc->sc_20M : &sc->sc_40M;
1566 break;
1567 case MWL_FREQ_BAND_5GHZ:
1568 *ci = (chw == MWL_CH_20_MHz_WIDTH) ?
1569 &sc->sc_20M_5G : &sc->sc_40M_5G;
1570 break;
1571 default:
1572 return (EINVAL);
1573 }
1574 return (((*ci)->freqLow == (*ci)->freqHigh) ? EINVAL : 0);
1575 }
1576
1577 static void
1578 getchannels(struct mwl_softc *sc, int maxchans, int *nchans,
1579 struct mwl_channel chans[])
1580 {
1581 const MWL_HAL_CHANNELINFO *ci;
1582
1583 /*
1584 * Use the channel info from the hal to craft the
1585 * channel list. Note that we pass back an unsorted
1586 * list; the caller is required to sort it for us
1587 * (if desired).
1588 */
1589 *nchans = 0;
1590 if (mwl_hal_getchannelinfo(sc,
1591 MWL_FREQ_BAND_2DOT4GHZ, MWL_CH_20_MHz_WIDTH, &ci) == 0)
1592 addchannels(chans, maxchans, nchans, ci, IEEE80211_CHAN_HTG);
1593 if (mwl_hal_getchannelinfo(sc,
1594 MWL_FREQ_BAND_5GHZ, MWL_CH_20_MHz_WIDTH, &ci) == 0)
1595 addchannels(chans, maxchans, nchans, ci, IEEE80211_CHAN_HTA);
1596 if (mwl_hal_getchannelinfo(sc,
1597 MWL_FREQ_BAND_2DOT4GHZ, MWL_CH_40_MHz_WIDTH, &ci) == 0)
1598 addht40channels(chans, maxchans, nchans, ci,
1599 IEEE80211_CHAN_HTG);
1600 if (mwl_hal_getchannelinfo(sc,
1601 MWL_FREQ_BAND_5GHZ, MWL_CH_40_MHz_WIDTH, &ci) == 0)
1602 addht40channels(chans, maxchans, nchans, ci,
1603 IEEE80211_CHAN_HTA);
1604 }
1605
1606 static int
1607 mwl_getchannels(struct mwl_softc *sc)
1608 {
1609 /*
1610 * Use the channel info from the hal to craft the
1611 * channel list for net80211. Note that we pass up
1612 * an unsorted list; net80211 will sort it for us.
1613 */
1614 (void) memset(sc->sc_channels, 0, sizeof (sc->sc_channels));
1615 sc->sc_nchans = 0;
1616 getchannels(sc, IEEE80211_CHAN_MAX, &sc->sc_nchans, sc->sc_channels);
1617
1618 sc->sc_regdomain.regdomain = SKU_DEBUG;
1619 sc->sc_regdomain.country = CTRY_DEFAULT;
1620 sc->sc_regdomain.location = 'I';
1621 sc->sc_regdomain.isocc[0] = ' '; /* XXX? */
1622 sc->sc_regdomain.isocc[1] = ' ';
1623 return (sc->sc_nchans == 0 ? EIO : 0);
1624 }
1625
1626 #undef IEEE80211_CHAN_HTA
1627 #undef IEEE80211_CHAN_HTG
1628
1629 /*
1630 * Return "hw specs". Note this must be the first
1631 * cmd MUST be done after a firmware download or the
1632 * f/w will lockup.
1633 * XXX move into the hal so driver doesn't need to be responsible
1634 */
1635 static int
1636 mwl_gethwspecs(struct mwl_softc *sc)
1637 {
1638 struct mwl_hal_hwspec *hw;
1639 HostCmd_DS_GET_HW_SPEC *pCmd;
1640 int retval;
1641
1642 hw = &sc->sc_hwspecs;
1643 _CMD_SETUP(pCmd, HostCmd_DS_GET_HW_SPEC, HostCmd_CMD_GET_HW_SPEC);
1644 (void) memset(&pCmd->PermanentAddr[0], 0xff, IEEE80211_ADDR_LEN);
1645 pCmd->ulFwAwakeCookie = LE_32((unsigned int)sc->sc_cmd_dmaaddr + 2048);
1646
1647 retval = mwlExecuteCmd(sc, HostCmd_CMD_GET_HW_SPEC);
1648 if (retval == 0) {
1649 IEEE80211_ADDR_COPY(hw->macAddr, pCmd->PermanentAddr);
1650 hw->wcbBase[0] = LE_32(pCmd->WcbBase0) & 0x0000ffff;
1651 hw->wcbBase[1] = LE_32(pCmd->WcbBase1[0]) & 0x0000ffff;
1652 hw->wcbBase[2] = LE_32(pCmd->WcbBase1[1]) & 0x0000ffff;
1653 hw->wcbBase[3] = LE_32(pCmd->WcbBase1[2]) & 0x0000ffff;
1654 hw->rxDescRead = LE_32(pCmd->RxPdRdPtr)& 0x0000ffff;
1655 hw->rxDescWrite = LE_32(pCmd->RxPdWrPtr)& 0x0000ffff;
1656 hw->regionCode = LE_16(pCmd->RegionCode) & 0x00ff;
1657 hw->fwReleaseNumber = LE_32(pCmd->FWReleaseNumber);
1658 hw->maxNumWCB = LE_16(pCmd->NumOfWCB);
1659 hw->maxNumMCAddr = LE_16(pCmd->NumOfMCastAddr);
1660 hw->numAntennas = LE_16(pCmd->NumberOfAntenna);
1661 hw->hwVersion = pCmd->Version;
1662 hw->hostInterface = pCmd->HostIf;
1663
1664 sc->sc_revs.mh_macRev = hw->hwVersion; /* XXX */
1665 sc->sc_revs.mh_phyRev = hw->hostInterface; /* XXX */
1666 }
1667
1668 return (retval);
1669 }
1670
1671 static int
1672 mwl_hal_setmac_locked(struct mwl_softc *sc,
1673 const uint8_t addr[IEEE80211_ADDR_LEN])
1674 {
1675 HostCmd_DS_SET_MAC *pCmd;
1676
1677 _VCMD_SETUP(pCmd, HostCmd_DS_SET_MAC, HostCmd_CMD_SET_MAC_ADDR);
1678 IEEE80211_ADDR_COPY(&pCmd->MacAddr[0], addr);
1679 #ifdef MWL_MBSS_SUPPORT
1680 /* NB: already byte swapped */
1681 pCmd->MacType = WL_MAC_TYPE_PRIMARY_CLIENT;
1682 #endif
1683 return (mwlExecuteCmd(sc, HostCmd_CMD_SET_MAC_ADDR));
1684 }
1685
1686 static void
1687 cvtPeerInfo(PeerInfo_t *to, const MWL_HAL_PEERINFO *from)
1688 {
1689 to->LegacyRateBitMap = LE_32(from->LegacyRateBitMap);
1690 to->HTRateBitMap = LE_32(from->HTRateBitMap);
1691 to->CapInfo = LE_16(from->CapInfo);
1692 to->HTCapabilitiesInfo = LE_16(from->HTCapabilitiesInfo);
1693 to->MacHTParamInfo = from->MacHTParamInfo;
1694 to->AddHtInfo.ControlChan = from->AddHtInfo.ControlChan;
1695 to->AddHtInfo.AddChan = from->AddHtInfo.AddChan;
1696 to->AddHtInfo.OpMode = LE_16(from->AddHtInfo.OpMode);
1697 to->AddHtInfo.stbc = LE_16(from->AddHtInfo.stbc);
1698 }
1699
1700 /* XXX station id must be in [0..63] */
1701 static int
1702 mwl_hal_newstation(struct mwl_softc *sc,
1703 const uint8_t addr[IEEE80211_ADDR_LEN], uint16_t aid, uint16_t sid,
1704 const MWL_HAL_PEERINFO *peer, int isQosSta, int wmeInfo)
1705 {
1706 HostCmd_FW_SET_NEW_STN *pCmd;
1707 int retval;
1708
1709 _VCMD_SETUP(pCmd, HostCmd_FW_SET_NEW_STN, HostCmd_CMD_SET_NEW_STN);
1710 pCmd->AID = LE_16(aid);
1711 pCmd->StnId = LE_16(sid);
1712 pCmd->Action = LE_16(0); /* SET */
1713 if (peer != NULL) {
1714 /* NB: must fix up byte order */
1715 cvtPeerInfo(&pCmd->PeerInfo, peer);
1716 }
1717 IEEE80211_ADDR_COPY(&pCmd->MacAddr[0], addr);
1718 pCmd->Qosinfo = (uint8_t)wmeInfo;
1719 pCmd->isQosSta = (isQosSta != 0);
1720
1721 MWL_DBG(MWL_DBG_HW, "mwl: mwl_hal_newstation(): "
1722 "LegacyRateBitMap %x, CapInfo %x\n",
1723 pCmd->PeerInfo.LegacyRateBitMap, pCmd->PeerInfo.CapInfo);
1724
1725 retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_NEW_STN);
1726 return (retval);
1727 }
1728
1729 /*
1730 * Configure antenna use.
1731 * Takes effect immediately.
1732 * XXX tx antenna setting ignored
1733 * XXX rx antenna setting should always be 3 (for now)
1734 */
1735 static int
1736 mwl_hal_setantenna(struct mwl_softc *sc, MWL_HAL_ANTENNA dirSet, int ant)
1737 {
1738 HostCmd_DS_802_11_RF_ANTENNA *pCmd;
1739 int retval;
1740
1741 if (!(dirSet == WL_ANTENNATYPE_RX || dirSet == WL_ANTENNATYPE_TX))
1742 return (EINVAL);
1743
1744 _CMD_SETUP(pCmd, HostCmd_DS_802_11_RF_ANTENNA,
1745 HostCmd_CMD_802_11_RF_ANTENNA);
1746 pCmd->Action = LE_16(dirSet);
1747 if (ant == 0) /* default to all/both antennae */
1748 ant = 3;
1749 pCmd->AntennaMode = LE_16(ant);
1750
1751 retval = mwlExecuteCmd(sc, HostCmd_CMD_802_11_RF_ANTENNA);
1752 return (retval);
1753 }
1754
1755 /*
1756 * Configure radio.
1757 * Takes effect immediately.
1758 * XXX preamble installed after set fixed rate cmd
1759 */
1760 static int
1761 mwl_hal_setradio(struct mwl_softc *sc, int onoff, MWL_HAL_PREAMBLE preamble)
1762 {
1763 HostCmd_DS_802_11_RADIO_CONTROL *pCmd;
1764 int retval;
1765
1766 _CMD_SETUP(pCmd, HostCmd_DS_802_11_RADIO_CONTROL,
1767 HostCmd_CMD_802_11_RADIO_CONTROL);
1768 pCmd->Action = LE_16(HostCmd_ACT_GEN_SET);
1769 if (onoff == 0)
1770 pCmd->Control = 0;
1771 else
1772 pCmd->Control = LE_16(preamble);
1773 pCmd->RadioOn = LE_16(onoff);
1774
1775 retval = mwlExecuteCmd(sc, HostCmd_CMD_802_11_RADIO_CONTROL);
1776 return (retval);
1777 }
1778
1779 static int
1780 mwl_hal_setwmm(struct mwl_softc *sc, int onoff)
1781 {
1782 HostCmd_FW_SetWMMMode *pCmd;
1783 int retval;
1784
1785 _CMD_SETUP(pCmd, HostCmd_FW_SetWMMMode,
1786 HostCmd_CMD_SET_WMM_MODE);
1787 pCmd->Action = LE_16(onoff);
1788
1789 retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_WMM_MODE);
1790 return (retval);
1791 }
1792
1793 /*
1794 * Convert public channel flags definition to a
1795 * value suitable for feeding to the firmware.
1796 * Note this includes byte swapping.
1797 */
1798 static uint32_t
1799 cvtChannelFlags(const MWL_HAL_CHANNEL *chan)
1800 {
1801 uint32_t w;
1802
1803 /*
1804 * NB: f/w only understands FREQ_BAND_5GHZ, supplying the more
1805 * precise band info causes it to lockup (sometimes).
1806 */
1807 w = (chan->channelFlags.FreqBand == MWL_FREQ_BAND_2DOT4GHZ) ?
1808 FREQ_BAND_2DOT4GHZ : FREQ_BAND_5GHZ;
1809 switch (chan->channelFlags.ChnlWidth) {
1810 case MWL_CH_10_MHz_WIDTH:
1811 w |= CH_10_MHz_WIDTH;
1812 break;
1813 case MWL_CH_20_MHz_WIDTH:
1814 w |= CH_20_MHz_WIDTH;
1815 break;
1816 case MWL_CH_40_MHz_WIDTH:
1817 default:
1818 w |= CH_40_MHz_WIDTH;
1819 break;
1820 }
1821 switch (chan->channelFlags.ExtChnlOffset) {
1822 case MWL_EXT_CH_NONE:
1823 w |= EXT_CH_NONE;
1824 break;
1825 case MWL_EXT_CH_ABOVE_CTRL_CH:
1826 w |= EXT_CH_ABOVE_CTRL_CH;
1827 break;
1828 case MWL_EXT_CH_BELOW_CTRL_CH:
1829 w |= EXT_CH_BELOW_CTRL_CH;
1830 break;
1831 }
1832 return (LE_32(w));
1833 }
1834
1835 static int
1836 mwl_hal_setchannel(struct mwl_softc *sc, const MWL_HAL_CHANNEL *chan)
1837 {
1838 HostCmd_FW_SET_RF_CHANNEL *pCmd;
1839 int retval;
1840
1841 _CMD_SETUP(pCmd, HostCmd_FW_SET_RF_CHANNEL, HostCmd_CMD_SET_RF_CHANNEL);
1842 pCmd->Action = LE_16(HostCmd_ACT_GEN_SET);
1843 pCmd->CurrentChannel = chan->channel;
1844 pCmd->ChannelFlags = cvtChannelFlags(chan); /* NB: byte-swapped */
1845
1846 retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_RF_CHANNEL);
1847 return (retval);
1848 }
1849
1850 static int
1851 mwl_hal_settxpower(struct mwl_softc *sc,
1852 const MWL_HAL_CHANNEL *c, uint8_t maxtxpow)
1853 {
1854 HostCmd_DS_802_11_RF_TX_POWER *pCmd;
1855 const struct mwl_hal_channel *hc;
1856 int i = 0, retval;
1857
1858 hc = findhalchannel(sc, c);
1859 if (hc == NULL) {
1860 /* XXX temp while testing */
1861 MWL_DBG(MWL_DBG_HW, "mwl: mwl_hal_settxpower(): "
1862 "no cal data for channel %u band %u width %u ext %u\n",
1863 c->channel, c->channelFlags.FreqBand,
1864 c->channelFlags.ChnlWidth, c->channelFlags.ExtChnlOffset);
1865 return (EINVAL);
1866 }
1867
1868 _CMD_SETUP(pCmd, HostCmd_DS_802_11_RF_TX_POWER,
1869 HostCmd_CMD_802_11_RF_TX_POWER);
1870 pCmd->Action = LE_16(HostCmd_ACT_GEN_SET_LIST);
1871 /* NB: 5Ghz cal data have the channel # in [0]; don't truncate */
1872 if (c->channelFlags.FreqBand == MWL_FREQ_BAND_5GHZ)
1873 pCmd->PowerLevelList[i++] = LE_16(hc->targetPowers[0]);
1874 for (; i < 4; i++) {
1875 uint16_t pow = hc->targetPowers[i];
1876 if (pow > maxtxpow)
1877 pow = maxtxpow;
1878 pCmd->PowerLevelList[i] = LE_16(pow);
1879 }
1880 retval = mwlExecuteCmd(sc, HostCmd_CMD_802_11_RF_TX_POWER);
1881 return (retval);
1882 }
1883
1884 #define RATEVAL(r) ((r) &~ RATE_MCS)
1885 #define RATETYPE(r) (((r) & RATE_MCS) ? HT_RATE_TYPE : LEGACY_RATE_TYPE)
1886
1887 static int
1888 mwl_hal_settxrate(struct mwl_softc *sc, MWL_HAL_TXRATE_HANDLING handling,
1889 const MWL_HAL_TXRATE *rate)
1890 {
1891 HostCmd_FW_USE_FIXED_RATE *pCmd;
1892 FIXED_RATE_ENTRY *fp;
1893 int retval, i, n;
1894
1895 _VCMD_SETUP(pCmd, HostCmd_FW_USE_FIXED_RATE,
1896 HostCmd_CMD_SET_FIXED_RATE);
1897
1898 pCmd->MulticastRate = RATEVAL(rate->McastRate);
1899 pCmd->MultiRateTxType = RATETYPE(rate->McastRate);
1900 /* NB: no rate type field */
1901 pCmd->ManagementRate = RATEVAL(rate->MgtRate);
1902 (void) memset(pCmd->FixedRateTable, 0, sizeof (pCmd->FixedRateTable));
1903 if (handling == RATE_FIXED) {
1904 pCmd->Action = LE_32(HostCmd_ACT_GEN_SET);
1905 pCmd->AllowRateDrop = LE_32(FIXED_RATE_WITHOUT_AUTORATE_DROP);
1906 fp = pCmd->FixedRateTable;
1907 fp->FixedRate =
1908 LE_32(RATEVAL(rate->RateSeries[0].Rate));
1909 fp->FixRateTypeFlags.FixRateType =
1910 LE_32(RATETYPE(rate->RateSeries[0].Rate));
1911 pCmd->EntryCount = LE_32(1);
1912 } else if (handling == RATE_FIXED_DROP) {
1913 pCmd->Action = LE_32(HostCmd_ACT_GEN_SET);
1914 pCmd->AllowRateDrop = LE_32(FIXED_RATE_WITH_AUTO_RATE_DROP);
1915 n = 0;
1916 fp = pCmd->FixedRateTable;
1917 for (i = 0; i < 4; i++) {
1918 if (rate->RateSeries[0].TryCount == 0)
1919 break;
1920 fp->FixRateTypeFlags.FixRateType =
1921 LE_32(RATETYPE(rate->RateSeries[i].Rate));
1922 fp->FixedRate =
1923 LE_32(RATEVAL(rate->RateSeries[i].Rate));
1924 fp->FixRateTypeFlags.RetryCountValid =
1925 LE_32(RETRY_COUNT_VALID);
1926 fp->RetryCount =
1927 LE_32(rate->RateSeries[i].TryCount-1);
1928 n++;
1929 }
1930 pCmd->EntryCount = LE_32(n);
1931 } else
1932 pCmd->Action = LE_32(HostCmd_ACT_NOT_USE_FIXED_RATE);
1933
1934 retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_FIXED_RATE);
1935 return (retval);
1936 }
1937
1938 static int
1939 mwl_hal_settxrate_auto(struct mwl_softc *sc, const MWL_HAL_TXRATE *rate)
1940 {
1941 HostCmd_FW_USE_FIXED_RATE *pCmd;
1942 int retval;
1943
1944 _CMD_SETUP(pCmd, HostCmd_FW_USE_FIXED_RATE,
1945 HostCmd_CMD_SET_FIXED_RATE);
1946
1947 pCmd->MulticastRate = RATEVAL(rate->McastRate);
1948 pCmd->MultiRateTxType = RATETYPE(rate->McastRate);
1949 /* NB: no rate type field */
1950 pCmd->ManagementRate = RATEVAL(rate->MgtRate);
1951 (void) memset(pCmd->FixedRateTable, 0, sizeof (pCmd->FixedRateTable));
1952 pCmd->Action = LE_32(HostCmd_ACT_NOT_USE_FIXED_RATE);
1953
1954 retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_FIXED_RATE);
1955 return (retval);
1956 }
1957
1958 #undef RATEVAL
1959 #undef RATETYPE
1960
1961 /* XXX 0 = indoor, 1 = outdoor */
1962 static int
1963 mwl_hal_setrateadaptmode(struct mwl_softc *sc, uint16_t mode)
1964 {
1965 HostCmd_DS_SET_RATE_ADAPT_MODE *pCmd;
1966 int retval;
1967
1968 _CMD_SETUP(pCmd, HostCmd_DS_SET_RATE_ADAPT_MODE,
1969 HostCmd_CMD_SET_RATE_ADAPT_MODE);
1970 pCmd->Action = LE_16(HostCmd_ACT_GEN_SET);
1971 pCmd->RateAdaptMode = LE_16(mode);
1972
1973 retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_RATE_ADAPT_MODE);
1974 return (retval);
1975 }
1976
1977 static int
1978 mwl_hal_setoptimizationlevel(struct mwl_softc *sc, int level)
1979 {
1980 HostCmd_FW_SET_OPTIMIZATION_LEVEL *pCmd;
1981 int retval;
1982
1983 _CMD_SETUP(pCmd, HostCmd_FW_SET_OPTIMIZATION_LEVEL,
1984 HostCmd_CMD_SET_OPTIMIZATION_LEVEL);
1985 pCmd->OptLevel = (uint8_t)level;
1986
1987 retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_OPTIMIZATION_LEVEL);
1988 return (retval);
1989 }
1990
1991 /*
1992 * Set the region code that selects the radar bin'ing agorithm.
1993 */
1994 static int
1995 mwl_hal_setregioncode(struct mwl_softc *sc, int regionCode)
1996 {
1997 HostCmd_SET_REGIONCODE_INFO *pCmd;
1998 int retval;
1999
2000 _CMD_SETUP(pCmd, HostCmd_SET_REGIONCODE_INFO,
2001 HostCmd_CMD_SET_REGION_CODE);
2002 /* XXX map pseudo-codes to fw codes */
2003 switch (regionCode) {
2004 case DOMAIN_CODE_ETSI_131:
2005 pCmd->regionCode = LE_16(DOMAIN_CODE_ETSI);
2006 break;
2007 default:
2008 pCmd->regionCode = LE_16(regionCode);
2009 break;
2010 }
2011
2012 retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_REGION_CODE);
2013 return (retval);
2014 }
2015
2016 static int
2017 mwl_hal_setassocid(struct mwl_softc *sc,
2018 const uint8_t bssId[IEEE80211_ADDR_LEN], uint16_t assocId)
2019 {
2020 HostCmd_FW_SET_AID *pCmd = (HostCmd_FW_SET_AID *) &sc->sc_cmd_mem[0];
2021 int retval;
2022
2023 _VCMD_SETUP(pCmd, HostCmd_FW_SET_AID, HostCmd_CMD_SET_AID);
2024 pCmd->AssocID = LE_16(assocId);
2025 IEEE80211_ADDR_COPY(&pCmd->MacAddr[0], bssId);
2026
2027 retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_AID);
2028 return (retval);
2029 }
2030
2031 /*
2032 * Inform firmware of tx rate parameters. Called whenever
2033 * user-settable params change and after a channel change.
2034 */
2035 static int
2036 mwl_setrates(struct ieee80211com *ic)
2037 {
2038 struct mwl_softc *sc = (struct mwl_softc *)ic;
2039 MWL_HAL_TXRATE rates;
2040
2041 const struct ieee80211_rateset *rs;
2042 rs = &ic->ic_bss->in_rates;
2043
2044 /*
2045 * Update the h/w rate map.
2046 * NB: 0x80 for MCS is passed through unchanged
2047 */
2048 (void) memset(&rates, 0, sizeof (rates));
2049 /* rate used to send management frames */
2050 rates.MgtRate = rs->ir_rates[0] & IEEE80211_RATE_VAL;
2051 /* rate used to send multicast frames */
2052 rates.McastRate = rates.MgtRate;
2053
2054 return (mwl_hal_settxrate(sc, RATE_AUTO, &rates));
2055 }
2056
2057 /*
2058 * Set packet size threshold for implicit use of RTS.
2059 * Takes effect immediately.
2060 * XXX packet length > threshold =>'s RTS
2061 */
2062 static int
2063 mwl_hal_setrtsthreshold(struct mwl_softc *sc, int threshold)
2064 {
2065 HostCmd_DS_802_11_RTS_THSD *pCmd;
2066 int retval;
2067
2068 _VCMD_SETUP(pCmd, HostCmd_DS_802_11_RTS_THSD,
2069 HostCmd_CMD_802_11_RTS_THSD);
2070 pCmd->Action = LE_16(HostCmd_ACT_GEN_SET);
2071 pCmd->Threshold = LE_16(threshold);
2072
2073 retval = mwlExecuteCmd(sc, HostCmd_CMD_802_11_RTS_THSD);
2074 return (retval);
2075 }
2076
2077 static int
2078 mwl_hal_setcsmode(struct mwl_softc *sc, MWL_HAL_CSMODE csmode)
2079 {
2080 HostCmd_DS_SET_LINKADAPT_CS_MODE *pCmd;
2081 int retval;
2082
2083 _CMD_SETUP(pCmd, HostCmd_DS_SET_LINKADAPT_CS_MODE,
2084 HostCmd_CMD_SET_LINKADAPT_CS_MODE);
2085 pCmd->Action = LE_16(HostCmd_ACT_GEN_SET);
2086 pCmd->CSMode = LE_16(csmode);
2087
2088 retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_LINKADAPT_CS_MODE);
2089 return (retval);
2090 }
2091
2092 static int
2093 mwl_hal_setpromisc(struct mwl_softc *sc, int ena)
2094 {
2095 uint32_t v;
2096
2097 v = mwl_ctl_read4(sc, MACREG_REG_PROMISCUOUS);
2098 mwl_ctl_write4(sc, MACREG_REG_PROMISCUOUS, ena ? v | 1 : v & ~1);
2099
2100 return (0);
2101 }
2102
2103 static int
2104 mwl_hal_start(struct mwl_softc *sc)
2105 {
2106 HostCmd_DS_BSS_START *pCmd;
2107 int retval;
2108
2109 _VCMD_SETUP(pCmd, HostCmd_DS_BSS_START, HostCmd_CMD_BSS_START);
2110 pCmd->Enable = LE_32(HostCmd_ACT_GEN_ON);
2111
2112 retval = mwlExecuteCmd(sc, HostCmd_CMD_BSS_START);
2113 return (retval);
2114 }
2115
2116 /*
2117 * Enable sta-mode operation (disables beacon frame xmit).
2118 */
2119 static int
2120 mwl_hal_setinframode(struct mwl_softc *sc)
2121 {
2122 HostCmd_FW_SET_INFRA_MODE *pCmd;
2123 int retval;
2124
2125 _VCMD_SETUP(pCmd, HostCmd_FW_SET_INFRA_MODE,
2126 HostCmd_CMD_SET_INFRA_MODE);
2127
2128 retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_INFRA_MODE);
2129 return (retval);
2130 }
2131
2132 static int
2133 mwl_hal_stop(struct mwl_softc *sc)
2134 {
2135 HostCmd_DS_BSS_START *pCmd;
2136 int retval;
2137
2138 _VCMD_SETUP(pCmd, HostCmd_DS_BSS_START,
2139 HostCmd_CMD_BSS_START);
2140 pCmd->Enable = LE_32(HostCmd_ACT_GEN_OFF);
2141 retval = mwlExecuteCmd(sc, HostCmd_CMD_BSS_START);
2142
2143 return (retval);
2144 }
2145
2146 static int
2147 mwl_hal_keyset(struct mwl_softc *sc, const MWL_HAL_KEYVAL *kv,
2148 const uint8_t mac[IEEE80211_ADDR_LEN])
2149 {
2150 HostCmd_FW_UPDATE_ENCRYPTION_SET_KEY *pCmd;
2151 int retval;
2152
2153 _VCMD_SETUP(pCmd, HostCmd_FW_UPDATE_ENCRYPTION_SET_KEY,
2154 HostCmd_CMD_UPDATE_ENCRYPTION);
2155 if (kv->keyFlags & (KEY_FLAG_TXGROUPKEY|KEY_FLAG_RXGROUPKEY))
2156 pCmd->ActionType = LE_32(EncrActionTypeSetGroupKey);
2157 else
2158 pCmd->ActionType = LE_32(EncrActionTypeSetKey);
2159 pCmd->KeyParam.Length = LE_16(sizeof (pCmd->KeyParam));
2160 pCmd->KeyParam.KeyTypeId = LE_16(kv->keyTypeId);
2161 pCmd->KeyParam.KeyInfo = LE_32(kv->keyFlags);
2162 pCmd->KeyParam.KeyIndex = LE_32(kv->keyIndex);
2163 /* NB: includes TKIP MIC keys */
2164 (void) memcpy(&pCmd->KeyParam.Key, &kv->key, kv->keyLen);
2165 switch (kv->keyTypeId) {
2166 case KEY_TYPE_ID_WEP:
2167 pCmd->KeyParam.KeyLen = LE_16(kv->keyLen);
2168 break;
2169 case KEY_TYPE_ID_TKIP:
2170 pCmd->KeyParam.KeyLen = LE_16(sizeof (TKIP_TYPE_KEY));
2171 pCmd->KeyParam.Key.TkipKey.TkipRsc.low =
2172 LE_16(kv->key.tkip.rsc.low);
2173 pCmd->KeyParam.Key.TkipKey.TkipRsc.high =
2174 LE_32(kv->key.tkip.rsc.high);
2175 pCmd->KeyParam.Key.TkipKey.TkipTsc.low =
2176 LE_16(kv->key.tkip.tsc.low);
2177 pCmd->KeyParam.Key.TkipKey.TkipTsc.high =
2178 LE_32(kv->key.tkip.tsc.high);
2179 break;
2180 case KEY_TYPE_ID_AES:
2181 pCmd->KeyParam.KeyLen = LE_16(sizeof (AES_TYPE_KEY));
2182 break;
2183 }
2184 #ifdef MWL_MBSS_SUPPORT
2185 IEEE80211_ADDR_COPY(pCmd->KeyParam.Macaddr, mac);
2186 #else
2187 IEEE80211_ADDR_COPY(pCmd->Macaddr, mac);
2188 #endif
2189
2190 retval = mwlExecuteCmd(sc, HostCmd_CMD_UPDATE_ENCRYPTION);
2191 return (retval);
2192 }
2193
2194 static int
2195 mwl_hal_keyreset(struct mwl_softc *sc, const MWL_HAL_KEYVAL *kv,
2196 const uint8_t mac[IEEE80211_ADDR_LEN])
2197 {
2198 HostCmd_FW_UPDATE_ENCRYPTION_SET_KEY *pCmd;
2199 int retval;
2200
2201 _VCMD_SETUP(pCmd, HostCmd_FW_UPDATE_ENCRYPTION_SET_KEY,
2202 HostCmd_CMD_UPDATE_ENCRYPTION);
2203 pCmd->ActionType = LE_16(EncrActionTypeRemoveKey);
2204 pCmd->KeyParam.Length = LE_16(sizeof (pCmd->KeyParam));
2205 pCmd->KeyParam.KeyTypeId = LE_16(kv->keyTypeId);
2206 pCmd->KeyParam.KeyInfo = LE_32(kv->keyFlags);
2207 pCmd->KeyParam.KeyIndex = LE_32(kv->keyIndex);
2208 #ifdef MWL_MBSS_SUPPORT
2209 IEEE80211_ADDR_COPY(pCmd->KeyParam.Macaddr, mac);
2210 #else
2211 IEEE80211_ADDR_COPY(pCmd->Macaddr, mac);
2212 #endif
2213 retval = mwlExecuteCmd(sc, HostCmd_CMD_UPDATE_ENCRYPTION);
2214 return (retval);
2215 }
2216
2217 /* ARGSUSED */
2218 static struct ieee80211_node *
2219 mwl_node_alloc(struct ieee80211com *ic)
2220 {
2221 struct mwl_node *mn;
2222
2223 mn = kmem_zalloc(sizeof (struct mwl_node), KM_SLEEP);
2224 return (&mn->mn_node);
2225 }
2226
2227 static void
2228 mwl_node_free(struct ieee80211_node *ni)
2229 {
2230 struct ieee80211com *ic = ni->in_ic;
2231 struct mwl_node *mn = MWL_NODE(ni);
2232
2233 if (mn->mn_staid != 0) {
2234 // mwl_hal_delstation(mn->mn_hvap, vap->iv_myaddr);
2235 // delstaid(sc, mn->mn_staid);
2236 mn->mn_staid = 0;
2237 }
2238 ic->ic_node_cleanup(ni);
2239 kmem_free(ni, sizeof (struct mwl_node));
2240 }
2241
2242 /*
2243 * Allocate a key cache slot for a unicast key. The
2244 * firmware handles key allocation and every station is
2245 * guaranteed key space so we are always successful.
2246 */
2247 static int
2248 mwl_key_alloc(struct ieee80211com *ic, const struct ieee80211_key *k,
2249 ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
2250 {
2251 if (k->wk_keyix != IEEE80211_KEYIX_NONE ||
2252 (k->wk_flags & IEEE80211_KEY_GROUP)) {
2253 if (!(&ic->ic_nw_keys[0] <= k &&
2254 k < &ic->ic_nw_keys[IEEE80211_WEP_NKID])) {
2255 /* should not happen */
2256 MWL_DBG(MWL_DBG_CRYPTO, "mwl: mwl_key_alloc(): "
2257 "bogus group key\n");
2258 return (0);
2259 }
2260 /* give the caller what they requested */
2261 *keyix = *rxkeyix = k - ic->ic_nw_keys;
2262 MWL_DBG(MWL_DBG_CRYPTO, "mwl: mwl_key_alloc(): "
2263 "alloc GROUP key keyix %x, rxkeyix %x\n",
2264 *keyix, *rxkeyix);
2265 } else {
2266 /*
2267 * Firmware handles key allocation.
2268 */
2269 *keyix = *rxkeyix = 0;
2270 MWL_DBG(MWL_DBG_CRYPTO, "mwl: mwl_key_alloc(): "
2271 "reset key index in key allocation\n");
2272 }
2273
2274 return (1);
2275 }
2276
2277 /*
2278 * Delete a key entry allocated by mwl_key_alloc.
2279 */
2280 static int
2281 mwl_key_delete(struct ieee80211com *ic, const struct ieee80211_key *k)
2282 {
2283 struct mwl_softc *sc = (struct mwl_softc *)ic;
2284 MWL_HAL_KEYVAL hk;
2285 const uint8_t bcastaddr[IEEE80211_ADDR_LEN] =
2286 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
2287
2288 (void) memset(&hk, 0, sizeof (hk));
2289 hk.keyIndex = k->wk_keyix;
2290 switch (k->wk_cipher->ic_cipher) {
2291 case IEEE80211_CIPHER_WEP:
2292 hk.keyTypeId = KEY_TYPE_ID_WEP;
2293 break;
2294 case IEEE80211_CIPHER_TKIP:
2295 hk.keyTypeId = KEY_TYPE_ID_TKIP;
2296 break;
2297 case IEEE80211_CIPHER_AES_CCM:
2298 hk.keyTypeId = KEY_TYPE_ID_AES;
2299 break;
2300 default:
2301 /* XXX should not happen */
2302 MWL_DBG(MWL_DBG_CRYPTO, "mwl: mwl_key_delete(): "
2303 "unknown cipher %d\n", k->wk_cipher->ic_cipher);
2304 return (0);
2305 }
2306 return (mwl_hal_keyreset(sc, &hk, bcastaddr) == 0);
2307 }
2308
2309 /*
2310 * Set the key cache contents for the specified key. Key cache
2311 * slot(s) must already have been allocated by mwl_key_alloc.
2312 */
2313 /* ARGSUSED */
2314 static int
2315 mwl_key_set(struct ieee80211com *ic, const struct ieee80211_key *k,
2316 const uint8_t mac[IEEE80211_ADDR_LEN])
2317 {
2318 #define GRPXMIT (IEEE80211_KEY_XMIT | IEEE80211_KEY_GROUP)
2319 /* NB: static wep keys are marked GROUP+tx/rx; GTK will be tx or rx */
2320 #define IEEE80211_IS_STATICKEY(k) \
2321 (((k)->wk_flags & (GRPXMIT|IEEE80211_KEY_RECV)) == \
2322 (GRPXMIT|IEEE80211_KEY_RECV))
2323 struct mwl_softc *sc = (struct mwl_softc *)ic;
2324 const struct ieee80211_cipher *cip = k->wk_cipher;
2325 const uint8_t *macaddr;
2326 MWL_HAL_KEYVAL hk;
2327
2328 (void) memset(&hk, 0, sizeof (hk));
2329 hk.keyIndex = k->wk_keyix;
2330 switch (cip->ic_cipher) {
2331 case IEEE80211_CIPHER_WEP:
2332 hk.keyTypeId = KEY_TYPE_ID_WEP;
2333 hk.keyLen = k->wk_keylen;
2334 if (k->wk_keyix == ic->ic_def_txkey)
2335 hk.keyFlags = KEY_FLAG_WEP_TXKEY;
2336 if (!IEEE80211_IS_STATICKEY(k)) {
2337 /* NB: WEP is never used for the PTK */
2338 (void) addgroupflags(&hk, k);
2339 }
2340 break;
2341 case IEEE80211_CIPHER_TKIP:
2342 hk.keyTypeId = KEY_TYPE_ID_TKIP;
2343 hk.key.tkip.tsc.high = (uint32_t)(k->wk_keytsc >> 16);
2344 hk.key.tkip.tsc.low = (uint16_t)k->wk_keytsc;
2345 hk.keyFlags = KEY_FLAG_TSC_VALID | KEY_FLAG_MICKEY_VALID;
2346 hk.keyLen = k->wk_keylen + IEEE80211_MICBUF_SIZE;
2347 if (!addgroupflags(&hk, k))
2348 hk.keyFlags |= KEY_FLAG_PAIRWISE;
2349 break;
2350 case IEEE80211_CIPHER_AES_CCM:
2351 hk.keyTypeId = KEY_TYPE_ID_AES;
2352 hk.keyLen = k->wk_keylen;
2353 if (!addgroupflags(&hk, k))
2354 hk.keyFlags |= KEY_FLAG_PAIRWISE;
2355 break;
2356 default:
2357 /* XXX should not happen */
2358 MWL_DBG(MWL_DBG_CRYPTO, "mwl: mwl_key_set(): "
2359 "unknown cipher %d\n",
2360 k->wk_cipher->ic_cipher);
2361 return (0);
2362 }
2363 /*
2364 * NB: tkip mic keys get copied here too; the layout
2365 * just happens to match that in ieee80211_key.
2366 */
2367 (void) memcpy(hk.key.aes, k->wk_key, hk.keyLen);
2368
2369 /*
2370 * Locate address of sta db entry for writing key;
2371 * the convention unfortunately is somewhat different
2372 * than how net80211, hostapd, and wpa_supplicant think.
2373 */
2374
2375 /*
2376 * NB: keys plumbed before the sta reaches AUTH state
2377 * will be discarded or written to the wrong sta db
2378 * entry because iv_bss is meaningless. This is ok
2379 * (right now) because we handle deferred plumbing of
2380 * WEP keys when the sta reaches AUTH state.
2381 */
2382 macaddr = ic->ic_bss->in_bssid;
2383 if (k->wk_flags & IEEE80211_KEY_XMIT) {
2384 /* XXX plumb to local sta db too for static key wep */
2385 (void) mwl_hal_keyset(sc, &hk, ic->ic_macaddr);
2386 }
2387 return (mwl_hal_keyset(sc, &hk, macaddr) == 0);
2388 #undef IEEE80211_IS_STATICKEY
2389 #undef GRPXMIT
2390 }
2391
2392 /*
2393 * Plumb any static WEP key for the station. This is
2394 * necessary as we must propagate the key from the
2395 * global key table of the vap to each sta db entry.
2396 */
2397 static void
2398 mwl_setanywepkey(struct ieee80211com *ic, const uint8_t mac[IEEE80211_ADDR_LEN])
2399 {
2400 if ((ic->ic_flags & (IEEE80211_F_PRIVACY|IEEE80211_F_WPA)) ==
2401 IEEE80211_F_PRIVACY &&
2402 ic->ic_def_txkey != IEEE80211_KEYIX_NONE &&
2403 ic->ic_nw_keys[ic->ic_def_txkey].wk_keyix != IEEE80211_KEYIX_NONE)
2404 (void) mwl_key_set(ic, &ic->ic_nw_keys[ic->ic_def_txkey], mac);
2405 }
2406
2407 static void
2408 mwl_setglobalkeys(struct ieee80211com *ic)
2409 {
2410 struct ieee80211_key *wk;
2411
2412 wk = &ic->ic_nw_keys[0];
2413 for (; wk < &ic->ic_nw_keys[IEEE80211_WEP_NKID]; wk++)
2414 if (wk->wk_keyix != IEEE80211_KEYIX_NONE)
2415 (void) mwl_key_set(ic, wk, ic->ic_macaddr);
2416 }
2417
2418 static int
2419 addgroupflags(MWL_HAL_KEYVAL *hk, const struct ieee80211_key *k)
2420 {
2421 if (k->wk_flags & IEEE80211_KEY_GROUP) {
2422 if (k->wk_flags & IEEE80211_KEY_XMIT)
2423 hk->keyFlags |= KEY_FLAG_TXGROUPKEY;
2424 if (k->wk_flags & IEEE80211_KEY_RECV)
2425 hk->keyFlags |= KEY_FLAG_RXGROUPKEY;
2426 return (1);
2427 } else
2428 return (0);
2429 }
2430
2431 /*
2432 * Set/change channels.
2433 */
2434 static int
2435 mwl_chan_set(struct mwl_softc *sc, struct mwl_channel *chan)
2436 {
2437 MWL_HAL_CHANNEL hchan;
2438 int maxtxpow;
2439
2440 MWL_DBG(MWL_DBG_HW, "mwl: mwl_chan_set(): "
2441 "chan %u MHz/flags 0x%x\n",
2442 chan->ic_freq, chan->ic_flags);
2443
2444 /*
2445 * Convert to a HAL channel description with
2446 * the flags constrained to reflect the current
2447 * operating mode.
2448 */
2449 mwl_mapchan(&hchan, chan);
2450 mwl_hal_intrset(sc, 0); /* disable interrupts */
2451
2452 (void) mwl_hal_setchannel(sc, &hchan);
2453 /*
2454 * Tx power is cap'd by the regulatory setting and
2455 * possibly a user-set limit. We pass the min of
2456 * these to the hal to apply them to the cal data
2457 * for this channel.
2458 * XXX min bound?
2459 */
2460 maxtxpow = 2 * chan->ic_maxregpower;
2461 if (maxtxpow > 100)
2462 maxtxpow = 100;
2463 (void) mwl_hal_settxpower(sc, &hchan, maxtxpow / 2);
2464 /* NB: potentially change mcast/mgt rates */
2465 (void) mwl_setcurchanrates(sc);
2466
2467 sc->sc_curchan = hchan;
2468 mwl_hal_intrset(sc, sc->sc_imask);
2469
2470 return (0);
2471 }
2472
2473 /*
2474 * Convert net80211 channel to a HAL channel.
2475 */
2476 static void
2477 mwl_mapchan(MWL_HAL_CHANNEL *hc, const struct mwl_channel *chan)
2478 {
2479 hc->channel = chan->ic_ieee;
2480
2481 *(uint32_t *)&hc->channelFlags = 0;
2482 if (((chan)->ic_flags & IEEE80211_CHAN_2GHZ) != 0)
2483 hc->channelFlags.FreqBand = MWL_FREQ_BAND_2DOT4GHZ;
2484 else if (((chan)->ic_flags & IEEE80211_CHAN_5GHZ) != 0)
2485 hc->channelFlags.FreqBand = MWL_FREQ_BAND_5GHZ;
2486 if (((chan)->ic_flags & IEEE80211_CHAN_HT40) != 0) {
2487 hc->channelFlags.ChnlWidth = MWL_CH_40_MHz_WIDTH;
2488 if (((chan)->ic_flags & IEEE80211_CHAN_HT40U) != 0)
2489 hc->channelFlags.ExtChnlOffset =
2490 MWL_EXT_CH_ABOVE_CTRL_CH;
2491 else
2492 hc->channelFlags.ExtChnlOffset =
2493 MWL_EXT_CH_BELOW_CTRL_CH;
2494 } else
2495 hc->channelFlags.ChnlWidth = MWL_CH_20_MHz_WIDTH;
2496 /* XXX 10MHz channels */
2497 }
2498
2499 /*
2500 * Return the phy mode for with the specified channel.
2501 */
2502 enum ieee80211_phymode
2503 mwl_chan2mode(const struct mwl_channel *chan)
2504 {
2505
2506 if (IEEE80211_IS_CHAN_HTA(chan))
2507 return (IEEE80211_MODE_11NA);
2508 else if (IEEE80211_IS_CHAN_HTG(chan))
2509 return (IEEE80211_MODE_11NG);
2510 else if (IEEE80211_IS_CHAN_108G(chan))
2511 return (IEEE80211_MODE_TURBO_G);
2512 else if (IEEE80211_IS_CHAN_ST(chan))
2513 return (IEEE80211_MODE_STURBO_A);
2514 else if (IEEE80211_IS_CHAN_TURBO(chan))
2515 return (IEEE80211_MODE_TURBO_A);
2516 else if (IEEE80211_IS_CHAN_HALF(chan))
2517 return (IEEE80211_MODE_HALF);
2518 else if (IEEE80211_IS_CHAN_QUARTER(chan))
2519 return (IEEE80211_MODE_QUARTER);
2520 else if (IEEE80211_IS_CHAN_A(chan))
2521 return (IEEE80211_MODE_11A);
2522 else if (IEEE80211_IS_CHAN_ANYG(chan))
2523 return (IEEE80211_MODE_11G);
2524 else if (IEEE80211_IS_CHAN_B(chan))
2525 return (IEEE80211_MODE_11B);
2526 else if (IEEE80211_IS_CHAN_FHSS(chan))
2527 return (IEEE80211_MODE_FH);
2528
2529 /* NB: should not get here */
2530 MWL_DBG(MWL_DBG_HW, "mwl: mwl_chan2mode(): "
2531 "cannot map channel to mode; freq %u flags 0x%x\n",
2532 chan->ic_freq, chan->ic_flags);
2533 return (IEEE80211_MODE_11B);
2534 }
2535
2536 /* XXX inline or eliminate? */
2537 const struct ieee80211_rateset *
2538 mwl_get_suprates(struct ieee80211com *ic, const struct mwl_channel *c)
2539 {
2540 /* XXX does this work for 11ng basic rates? */
2541 return (&ic->ic_sup_rates[mwl_chan2mode(c)]);
2542 }
2543
2544 /*
2545 * Inform firmware of tx rate parameters.
2546 * Called after a channel change.
2547 */
2548 static int
2549 mwl_setcurchanrates(struct mwl_softc *sc)
2550 {
2551 struct ieee80211com *ic = &sc->sc_ic;
2552 const struct ieee80211_rateset *rs;
2553 MWL_HAL_TXRATE rates;
2554
2555 (void) memset(&rates, 0, sizeof (rates));
2556 rs = mwl_get_suprates(ic, sc->sc_cur_chan);
2557 /* rate used to send management frames */
2558 rates.MgtRate = rs->ir_rates[0] & IEEE80211_RATE_VAL;
2559 /* rate used to send multicast frames */
2560 rates.McastRate = rates.MgtRate;
2561
2562 return (mwl_hal_settxrate_auto(sc, &rates));
2563 }
2564
2565 static const struct mwl_hal_channel *
2566 findhalchannel(const struct mwl_softc *sc, const MWL_HAL_CHANNEL *c)
2567 {
2568 const struct mwl_hal_channel *hc;
2569 const MWL_HAL_CHANNELINFO *ci;
2570 int chan = c->channel, i;
2571
2572 if (c->channelFlags.FreqBand == MWL_FREQ_BAND_2DOT4GHZ) {
2573 i = chan - 1;
2574 if (c->channelFlags.ChnlWidth == MWL_CH_40_MHz_WIDTH) {
2575 ci = &sc->sc_40M;
2576 if (c->channelFlags.ExtChnlOffset ==
2577 MWL_EXT_CH_BELOW_CTRL_CH)
2578 i -= 4;
2579 } else
2580 ci = &sc->sc_20M;
2581 /* 2.4G channel table is directly indexed */
2582 hc = ((unsigned)i < ci->nchannels) ? &ci->channels[i] : NULL;
2583 } else if (c->channelFlags.FreqBand == MWL_FREQ_BAND_5GHZ) {
2584 if (c->channelFlags.ChnlWidth == MWL_CH_40_MHz_WIDTH) {
2585 ci = &sc->sc_40M_5G;
2586 if (c->channelFlags.ExtChnlOffset ==
2587 MWL_EXT_CH_BELOW_CTRL_CH)
2588 chan -= 4;
2589 } else
2590 ci = &sc->sc_20M_5G;
2591 /* 5GHz channel table is sparse and must be searched */
2592 for (i = 0; i < ci->nchannels; i++)
2593 if (ci->channels[i].ieee == chan)
2594 break;
2595 hc = (i < ci->nchannels) ? &ci->channels[i] : NULL;
2596 } else
2597 hc = NULL;
2598 return (hc);
2599 }
2600
2601 /*
2602 * Map SKU+country code to region code for radar bin'ing.
2603 */
2604 static int
2605 mwl_map2regioncode(const struct mwl_regdomain *rd)
2606 {
2607 switch (rd->regdomain) {
2608 case SKU_FCC:
2609 case SKU_FCC3:
2610 return (DOMAIN_CODE_FCC);
2611 case SKU_CA:
2612 return (DOMAIN_CODE_IC);
2613 case SKU_ETSI:
2614 case SKU_ETSI2:
2615 case SKU_ETSI3:
2616 if (rd->country == CTRY_SPAIN)
2617 return (DOMAIN_CODE_SPAIN);
2618 if (rd->country == CTRY_FRANCE || rd->country == CTRY_FRANCE2)
2619 return (DOMAIN_CODE_FRANCE);
2620 /* XXX force 1.3.1 radar type */
2621 return (DOMAIN_CODE_ETSI_131);
2622 case SKU_JAPAN:
2623 return (DOMAIN_CODE_MKK);
2624 case SKU_ROW:
2625 return (DOMAIN_CODE_DGT); /* Taiwan */
2626 case SKU_APAC:
2627 case SKU_APAC2:
2628 case SKU_APAC3:
2629 return (DOMAIN_CODE_AUS); /* Australia */
2630 }
2631 /* XXX KOREA? */
2632 return (DOMAIN_CODE_FCC); /* XXX? */
2633 }
2634
2635 /*
2636 * Setup the rx data structures. This should only be
2637 * done once or we may get out of sync with the firmware.
2638 */
2639 static int
2640 mwl_startrecv(struct mwl_softc *sc)
2641 {
2642 struct mwl_rx_ring *ring;
2643 struct mwl_rxdesc *ds;
2644 struct mwl_rxbuf *bf, *prev;
2645
2646 int i;
2647
2648 ring = &sc->sc_rxring;
2649 bf = ring->buf;
2650
2651 prev = NULL;
2652 for (i = 0; i < MWL_RX_RING_COUNT; i++, bf++) {
2653 ds = bf->bf_desc;
2654 /*
2655 * NB: DMA buffer contents is known to be unmodified
2656 * so there's no need to flush the data cache.
2657 */
2658
2659 /*
2660 * Setup descriptor.
2661 */
2662 ds->QosCtrl = 0;
2663 ds->RSSI = 0;
2664 ds->Status = EAGLE_RXD_STATUS_IDLE;
2665 ds->Channel = 0;
2666 ds->PktLen = LE_16(MWL_AGGR_SIZE);
2667 ds->SQ2 = 0;
2668 ds->pPhysBuffData = LE_32(bf->bf_baddr);
2669 /* NB: don't touch pPhysNext, set once */
2670 ds->RxControl = EAGLE_RXD_CTRL_DRIVER_OWN;
2671
2672 (void) ddi_dma_sync(ring->rxdesc_dma.dma_hdl,
2673 i * sizeof (struct mwl_rxdesc),
2674 sizeof (struct mwl_rxdesc),
2675 DDI_DMA_SYNC_FORDEV);
2676
2677 if (prev != NULL) {
2678 ds = prev->bf_desc;
2679 ds->pPhysNext = LE_32(bf->bf_daddr);
2680 }
2681 prev = bf;
2682 }
2683
2684 if (prev != NULL) {
2685 ds = prev->bf_desc;
2686 ds->pPhysNext = ring->physaddr;
2687 }
2688
2689 /* set filters, etc. */
2690 (void) mwl_mode_init(sc);
2691
2692 return (0);
2693 }
2694
2695 static int
2696 mwl_mode_init(struct mwl_softc *sc)
2697 {
2698 /*
2699 * NB: Ignore promisc in hostap mode; it's set by the
2700 * bridge. This is wrong but we have no way to
2701 * identify internal requests (from the bridge)
2702 * versus external requests such as for tcpdump.
2703 */
2704 /* mwl_setmcastfilter - not support now */
2705 (void) mwl_hal_setpromisc(sc, 0);
2706
2707 return (0);
2708 }
2709
2710 /*
2711 * Kick the firmware to tell it there are new tx descriptors
2712 * for processing. The driver says what h/w q has work in
2713 * case the f/w ever gets smarter.
2714 */
2715 /* ARGSUSED */
2716 static void
2717 mwl_hal_txstart(struct mwl_softc *sc, int qnum)
2718 {
2719
2720 mwl_ctl_write4(sc, MACREG_REG_H2A_INTERRUPT_EVENTS,
2721 MACREG_H2ARIC_BIT_PPA_READY);
2722 (void) mwl_ctl_read4(sc, MACREG_REG_INT_CODE);
2723 }
2724
2725 static int
2726 mwl_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type)
2727 {
2728 struct mwl_softc *sc = (struct mwl_softc *)ic;
2729 struct mwl_tx_ring *ring;
2730 struct mwl_txdesc *ds;
2731 struct mwl_txbuf *bf;
2732 struct ieee80211_frame *wh, *wh1;
2733 struct ieee80211_node *ni = NULL;
2734
2735 int err, off;
2736 int mblen, pktlen, hdrlen;
2737 mblk_t *m, *m0;
2738 uint8_t *addr_4, *txbuf;
2739 uint16_t *pfwlen;
2740
2741 MWL_TXLOCK(sc);
2742
2743 err = DDI_SUCCESS;
2744 if (!MWL_IS_RUNNING(sc) || MWL_IS_SUSPEND(sc)) {
2745 err = ENXIO;
2746 goto fail1;
2747 }
2748
2749 ring = &sc->sc_txring[1];
2750 if (ring->queued > 15) {
2751 MWL_DBG(MWL_DBG_TX, "mwl: mwl_send(): "
2752 "no txbuf, %d\n", ring->queued);
2753 sc->sc_need_sched = 1;
2754 sc->sc_tx_nobuf++;
2755 err = ENOMEM;
2756 goto fail1;
2757 }
2758
2759 m = allocb(msgdsize(mp) + 32, BPRI_MED);
2760 if (m == NULL) {
2761 MWL_DBG(MWL_DBG_TX, "mwl: mwl_send():"
2762 "can't alloc mblk.\n");
2763 err = DDI_FAILURE;
2764 goto fail1;
2765 }
2766
2767 for (off = 0, m0 = mp; m0 != NULL; m0 = m0->b_cont) {
2768 mblen = MBLKL(m0);
2769 (void) bcopy(m0->b_rptr, m->b_rptr + off, mblen);
2770 off += mblen;
2771 }
2772 m->b_wptr += off;
2773
2774 wh = (struct ieee80211_frame *)m->b_rptr;
2775 ni = ieee80211_find_txnode(ic, wh->i_addr1);
2776 if (ni == NULL) {
2777 err = DDI_FAILURE;
2778 sc->sc_tx_err++;
2779 goto fail2;
2780 }
2781
2782 hdrlen = sizeof (*wh);
2783 pktlen = msgdsize(m);
2784
2785 (void) ieee80211_encap(ic, m, ni);
2786
2787 if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
2788 const struct ieee80211_cipher *cip;
2789 struct ieee80211_key *k;
2790 k = ieee80211_crypto_encap(ic, m);
2791 if (k == NULL) {
2792 sc->sc_tx_err++;
2793 err = DDI_FAILURE;
2794 goto fail3;
2795 }
2796
2797 /*
2798 * Adjust the packet length for the crypto additions
2799 * done during encap and any other bits that the f/w
2800 * will add later on.
2801 */
2802 cip = k->wk_cipher;
2803 pktlen += cip->ic_header + cip->ic_miclen + cip->ic_trailer;
2804 /* packet header may have moved, reset our local pointer */
2805 wh = (struct ieee80211_frame *)m->b_rptr;
2806 }
2807
2808 ds = &ring->desc[ring->cur];
2809 bf = &ring->buf[ring->cur];
2810
2811 bf->bf_node = ieee80211_ref_node(ni);
2812 txbuf = (uint8_t *)bf->bf_mem;
2813
2814 /*
2815 * inject FW specific fields into the 802.11 frame
2816 *
2817 * 2 bytes FW len (inject)
2818 * 24 bytes 802.11 frame header
2819 * 6 bytes addr4 (inject)
2820 * n bytes 802.11 frame body
2821 */
2822 pfwlen = (uint16_t *)txbuf;
2823 *pfwlen = pktlen - hdrlen;
2824 wh1 = (struct ieee80211_frame *)(txbuf + 2);
2825 bcopy(wh, wh1, sizeof (struct ieee80211_frame));
2826 addr_4 = txbuf + (sizeof (struct ieee80211_frame) + sizeof (uint16_t));
2827 (void) memset(addr_4, 0, 6);
2828 bcopy(m->b_rptr + sizeof (struct ieee80211_frame), txbuf + 32, *pfwlen);
2829 pktlen += 8;
2830
2831 (void) ddi_dma_sync(bf->txbuf_dma.dma_hdl,
2832 0,
2833 pktlen,
2834 DDI_DMA_SYNC_FORDEV);
2835
2836 ds->QosCtrl = 0;
2837 ds->PktLen = (uint16_t)pktlen;
2838 ds->PktPtr = bf->bf_baddr;
2839 ds->Status = LE_32(EAGLE_TXD_STATUS_FW_OWNED);
2840 ds->Format = 0;
2841 ds->pad = 0;
2842 ds->ack_wcb_addr = 0;
2843 ds->TxPriority = 1;
2844
2845 MWL_DBG(MWL_DBG_TX, "mwl: mwl_send(): "
2846 "tx desc Status %x, DataRate %x, TxPriority %x, QosCtrl %x, "
2847 "PktLen %x, SapPktInfo %x, Format %x, Pad %x, ack_wcb_addr %x\n",
2848 ds->Status, ds->DataRate, ds->TxPriority, ds->QosCtrl, ds->PktLen,
2849 ds->SapPktInfo, ds->Format, ds->pad, ds->ack_wcb_addr);
2850
2851 (void) ddi_dma_sync(ring->txdesc_dma.dma_hdl,
2852 ring->cur * sizeof (struct mwl_txdesc),
2853 sizeof (struct mwl_txdesc),
2854 DDI_DMA_SYNC_FORDEV);
2855
2856 MWL_DBG(MWL_DBG_TX, "mwl: mwl_send(): "
2857 "pktlen = %u, slot = %u, queued = %x\n",
2858 mblen, ring->cur, ring->queued);
2859
2860 ring->queued++;
2861 ring->cur = (ring->cur + 1) % MWL_TX_RING_COUNT;
2862
2863 /*
2864 * NB: We don't need to lock against tx done because
2865 * this just prods the firmware to check the transmit
2866 * descriptors. The firmware will also start fetching
2867 * descriptors by itself if it notices new ones are
2868 * present when it goes to deliver a tx done interrupt
2869 * to the host. So if we race with tx done processing
2870 * it's ok. Delivering the kick here rather than in
2871 * mwl_tx_start is an optimization to avoid poking the
2872 * firmware for each packet.
2873 *
2874 * NB: the queue id isn't used so 0 is ok.
2875 */
2876 mwl_hal_txstart(sc, 0);
2877
2878 ic->ic_stats.is_tx_frags++;
2879 ic->ic_stats.is_tx_bytes += pktlen;
2880
2881 fail3:
2882 ieee80211_free_node(ni);
2883 fail2:
2884 freemsg(m);
2885 fail1:
2886 if ((type & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA ||
2887 err == DDI_SUCCESS)
2888 freemsg(mp);
2889 MWL_TXUNLOCK(sc);
2890 return (err);
2891 }
2892
2893 /*
2894 * This function is called periodically (every 200ms) during scanning to
2895 * switch from one channel to another.
2896 */
2897 static void
2898 mwl_next_scan(void *arg)
2899 {
2900 struct mwl_softc *sc = (struct mwl_softc *)arg;
2901 struct ieee80211com *ic = &sc->sc_ic;
2902
2903 if (ic->ic_state == IEEE80211_S_SCAN)
2904 (void) ieee80211_next_scan(ic);
2905
2906 sc->sc_scan_id = 0;
2907 }
2908
2909 /*
2910 * Convert a legacy rate set to a firmware bitmask.
2911 */
2912 static uint32_t
2913 get_rate_bitmap(const struct ieee80211_rateset *rs)
2914 {
2915 uint32_t rates;
2916 int i;
2917
2918 rates = 0;
2919 for (i = 0; i < rs->ir_nrates; i++)
2920 switch (rs->ir_rates[i] & IEEE80211_RATE_VAL) {
2921 case 2: rates |= 0x001; break;
2922 case 4: rates |= 0x002; break;
2923 case 11: rates |= 0x004; break;
2924 case 22: rates |= 0x008; break;
2925 case 44: rates |= 0x010; break;
2926 case 12: rates |= 0x020; break;
2927 case 18: rates |= 0x040; break;
2928 case 24: rates |= 0x080; break;
2929 case 36: rates |= 0x100; break;
2930 case 48: rates |= 0x200; break;
2931 case 72: rates |= 0x400; break;
2932 case 96: rates |= 0x800; break;
2933 case 108: rates |= 0x1000; break;
2934 }
2935 return (rates);
2936 }
2937
2938 /*
2939 * Craft station database entry for station.
2940 * NB: use host byte order here, the hal handles byte swapping.
2941 */
2942 static MWL_HAL_PEERINFO *
2943 mkpeerinfo(MWL_HAL_PEERINFO *pi, const struct ieee80211_node *ni)
2944 {
2945 (void) memset(pi, 0, sizeof (*pi));
2946 pi->LegacyRateBitMap = get_rate_bitmap(&ni->in_rates);
2947 pi->CapInfo = ni->in_capinfo;
2948 return (pi);
2949 }
2950
2951 static int
2952 mwl_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
2953 {
2954 struct mwl_softc *sc = (struct mwl_softc *)ic;
2955 enum ieee80211_state ostate;
2956 struct ieee80211_channel *ic_chan;
2957 struct ieee80211_node *ni = NULL;
2958 MWL_HAL_PEERINFO pi;
2959 uint32_t chan;
2960
2961 if (sc->sc_scan_id != 0) {
2962 (void) untimeout(sc->sc_scan_id);
2963 sc->sc_scan_id = 0;
2964 }
2965
2966 MWL_GLOCK(sc);
2967
2968 ostate = ic->ic_state;
2969 MWL_DBG(MWL_DBG_MSG, "mwl: mwl_newstate(): "
2970 "ostate %x -> nstate %x\n",
2971 ostate, nstate);
2972
2973 switch (nstate) {
2974 case IEEE80211_S_INIT:
2975 break;
2976 case IEEE80211_S_SCAN:
2977 if (ostate != IEEE80211_S_INIT) {
2978 ic_chan = ic->ic_curchan;
2979 chan = ieee80211_chan2ieee(ic, ic_chan);
2980 if (chan != 0 && chan != IEEE80211_CHAN_ANY) {
2981 sc->sc_cur_chan =
2982 &sc->sc_channels[3 * chan - 2];
2983 MWL_DBG(MWL_DBG_MSG, "mwl: mwl_newstate(): "
2984 "chan num is %u, sc chan is %u\n",
2985 chan, sc->sc_cur_chan->ic_ieee);
2986 (void) mwl_chan_set(sc, sc->sc_cur_chan);
2987 }
2988 }
2989 sc->sc_scan_id = timeout(mwl_next_scan, (void *)sc,
2990 drv_usectohz(250000));
2991 break;
2992 case IEEE80211_S_AUTH:
2993 ic_chan = ic->ic_curchan;
2994 chan = ieee80211_chan2ieee(ic, ic_chan);
2995 sc->sc_cur_chan = &sc->sc_channels[3 * chan - 2];
2996 MWL_DBG(MWL_DBG_MSG, "mwl: mwl_newstate(): "
2997 "chan num is %u, sc chan is %u\n",
2998 chan, sc->sc_cur_chan->ic_ieee);
2999 (void) mwl_chan_set(sc, sc->sc_cur_chan);
3000 ni = ic->ic_bss;
3001 (void) mwl_hal_newstation(sc, ic->ic_macaddr, 0, 0, NULL, 0, 0);
3002 mwl_setanywepkey(ic, ni->in_macaddr);
3003 break;
3004 case IEEE80211_S_ASSOC:
3005 break;
3006 case IEEE80211_S_RUN:
3007 ni = ic->ic_bss;
3008 (void) mwl_hal_newstation(sc,
3009 ic->ic_macaddr, 0, 0, mkpeerinfo(&pi, ni), 0, 0);
3010 mwl_setglobalkeys(ic);
3011 (void) mwl_hal_setassocid(sc,
3012 ic->ic_bss->in_bssid, ic->ic_bss->in_associd);
3013 (void) mwl_setrates(ic);
3014 (void) mwl_hal_setrtsthreshold(sc, ic->ic_rtsthreshold);
3015 (void) mwl_hal_setcsmode(sc, CSMODE_AUTO_ENA);
3016 break;
3017 default:
3018 break;
3019 }
3020
3021 MWL_GUNLOCK(sc);
3022
3023 return (sc->sc_newstate(ic, nstate, arg));
3024 }
3025
3026 /*
3027 * Set the interrupt mask.
3028 */
3029 static void
3030 mwl_hal_intrset(struct mwl_softc *sc, uint32_t mask)
3031 {
3032 mwl_ctl_write4(sc, MACREG_REG_A2H_INTERRUPT_MASK, 0);
3033 (void) mwl_ctl_read4(sc, MACREG_REG_INT_CODE);
3034
3035 sc->sc_hal_imask = mask;
3036 mwl_ctl_write4(sc, MACREG_REG_A2H_INTERRUPT_MASK, mask);
3037 (void) mwl_ctl_read4(sc, MACREG_REG_INT_CODE);
3038 }
3039
3040 /*
3041 * Return the current ISR setting and clear the cause.
3042 */
3043 static void
3044 mwl_hal_getisr(struct mwl_softc *sc, uint32_t *status)
3045 {
3046 uint32_t cause;
3047
3048 cause = mwl_ctl_read4(sc, MACREG_REG_A2H_INTERRUPT_CAUSE);
3049 if (cause == 0xffffffff) { /* card removed */
3050 cause = 0;
3051 } else if (cause != 0) {
3052 /* clear cause bits */
3053 mwl_ctl_write4(sc, MACREG_REG_A2H_INTERRUPT_CAUSE,
3054 cause & ~sc->sc_hal_imask);
3055 (void) mwl_ctl_read4(sc, MACREG_REG_INT_CODE);
3056 cause &= sc->sc_hal_imask;
3057 }
3058 *status = cause;
3059 }
3060
3061 static void
3062 mwl_tx_intr(struct mwl_softc *sc)
3063 {
3064 struct ieee80211com *ic = &sc->sc_ic;
3065 struct mwl_tx_ring *ring;
3066 struct mwl_txdesc *ds;
3067
3068 uint32_t status;
3069
3070 MWL_TXLOCK(sc);
3071
3072 ring = &sc->sc_txring[1];
3073
3074 if (!(ring->queued)) {
3075 MWL_TXUNLOCK(sc);
3076 return;
3077 }
3078
3079 (void) ddi_dma_sync(ring->txdesc_dma.dma_hdl,
3080 0,
3081 ring->txdesc_dma.alength,
3082 DDI_DMA_SYNC_FORCPU);
3083
3084 for (;;) {
3085 ds = &ring->desc[ring->next];
3086
3087 status = LE_32(ds->Status);
3088
3089 if (status & LE_32(EAGLE_TXD_STATUS_FW_OWNED)) {
3090 break;
3091 }
3092
3093 if (status == LE_32(EAGLE_TXD_STATUS_IDLE)) {
3094 break;
3095 }
3096
3097 MWL_DBG(MWL_DBG_TX, "mwl: mwl_tx_intr(): "
3098 "recv tx desc status %x, datarate %x, txpriority %x, "
3099 "QosCtrl %x, pktLen %x, SapPktInfo %x, Format %x, "
3100 "pad %x, ack_wcb_addr %x\n",
3101 ds->Status, ds->DataRate, ds->TxPriority,
3102 ds->QosCtrl, ds->PktLen, ds->SapPktInfo,
3103 ds->Format, ds->pad, ds->ack_wcb_addr);
3104
3105 /* descriptor is no longer valid */
3106 ds->Status = LE_32(EAGLE_TXD_STATUS_IDLE);
3107
3108 (void) ddi_dma_sync(ring->txdesc_dma.dma_hdl,
3109 ring->next * sizeof (struct mwl_txdesc),
3110 sizeof (struct mwl_txdesc),
3111 DDI_DMA_SYNC_FORDEV);
3112
3113 ring->queued--;
3114 ring->next = (ring->next + 1) % MWL_TX_RING_COUNT;
3115 MWL_DBG(MWL_DBG_TX, "mwl: mwl_tx_intr(): "
3116 " tx done idx=%u, queued= %d\n",
3117 ring->next, ring->queued);
3118
3119 if (sc->sc_need_sched &&
3120 (ring->queued < MWL_TX_RING_COUNT)) {
3121 sc->sc_need_sched = 0;
3122 mac_tx_update(ic->ic_mach);
3123 }
3124
3125 }
3126
3127 MWL_TXUNLOCK(sc);
3128 }
3129
3130 /*
3131 * Convert hardware signal strength to rssi. The value
3132 * provided by the device has the noise floor added in;
3133 * we need to compensate for this but we don't have that
3134 * so we use a fixed value.
3135 *
3136 * The offset of 8 is good for both 2.4 and 5GHz. The LNA
3137 * offset is already set as part of the initial gain. This
3138 * will give at least +/- 3dB for 2.4GHz and +/- 5dB for 5GHz.
3139 */
3140 static int
3141 cvtrssi(uint8_t ssi)
3142 {
3143 int rssi = (int)ssi + 8;
3144 /* XXX hack guess until we have a real noise floor */
3145 rssi = 2 * (87 - rssi); /* NB: .5 dBm units */
3146 return (rssi < 0 ? 0 : rssi > 127 ? 127 : rssi);
3147 }
3148
3149 static void
3150 mwl_rx_intr(struct mwl_softc *sc)
3151 {
3152 struct ieee80211com *ic = &sc->sc_ic;
3153 struct mwl_rx_ring *ring;
3154 struct ieee80211_node *ni;
3155 struct ieee80211_frame *wh;
3156
3157 struct mwl_rxbuf *bf;
3158 struct mwl_rxdesc *ds;
3159 mblk_t *mp0;
3160
3161 int ntodo, len, rssi;
3162 uint8_t *data, status;
3163
3164 MWL_RXLOCK(sc);
3165
3166 ring = &sc->sc_rxring;
3167 for (ntodo = MWL_RX_RING_COUNT; ntodo > 0; ntodo--) {
3168 bf = &ring->buf[ring->cur];
3169 ds = bf->bf_desc;
3170 data = bf->bf_mem;
3171
3172 (void) ddi_dma_sync(ring->rxdesc_dma.dma_hdl,
3173 ring->cur * sizeof (struct mwl_rxdesc),
3174 sizeof (struct mwl_rxdesc),
3175 DDI_DMA_SYNC_FORCPU);
3176
3177 if (ds->RxControl != EAGLE_RXD_CTRL_DMA_OWN)
3178 break;
3179
3180 status = ds->Status;
3181 if (status & EAGLE_RXD_STATUS_DECRYPT_ERR_MASK) {
3182 MWL_DBG(MWL_DBG_CRYPTO, "mwl: mwl_rx_intr(): "
3183 "rx decrypt error\n");
3184 sc->sc_rx_err++;
3185 }
3186
3187 /*
3188 * Sync the data buffer.
3189 */
3190 len = LE_16(ds->PktLen);
3191
3192 (void) ddi_dma_sync(bf->rxbuf_dma.dma_hdl,
3193 0,
3194 bf->rxbuf_dma.alength,
3195 DDI_DMA_SYNC_FORCPU);
3196
3197 if (len < 32 || len > sc->sc_dmabuf_size) {
3198 MWL_DBG(MWL_DBG_RX, "mwl: mwl_rx_intr(): "
3199 "packet len error %d\n", len);
3200 sc->sc_rx_err++;
3201 goto rxnext;
3202 }
3203
3204 mp0 = allocb(sc->sc_dmabuf_size, BPRI_MED);
3205 if (mp0 == NULL) {
3206 MWL_DBG(MWL_DBG_RX, "mwl: mwl_rx_intr(): "
3207 "alloc mblk error\n");
3208 sc->sc_rx_nobuf++;
3209 goto rxnext;
3210 }
3211 bcopy(data+ 2, mp0->b_wptr, 24);
3212 mp0->b_wptr += 24;
3213 bcopy(data + 32, mp0->b_wptr, len - 32);
3214 mp0->b_wptr += (len - 32);
3215
3216 wh = (struct ieee80211_frame *)mp0->b_rptr;
3217 if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
3218 IEEE80211_FC0_TYPE_CTL) {
3219 freemsg(mp0);
3220 goto rxnext;
3221 }
3222
3223 /*
3224 * The f/w strips WEP header but doesn't clear
3225 * the WEP bit; mark the packet with M_WEP so
3226 * net80211 will treat the data as decrypted.
3227 * While here also clear the PWR_MGT bit since
3228 * power save is handled by the firmware and
3229 * passing this up will potentially cause the
3230 * upper layer to put a station in power save
3231 * (except when configured with MWL_HOST_PS_SUPPORT).
3232 */
3233 #ifdef MWL_HOST_PS_SUPPORT
3234 wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
3235 #else
3236 wh->i_fc[1] &= ~(IEEE80211_FC1_WEP | IEEE80211_FC1_PWR_MGT);
3237 #endif
3238
3239 /* calculate rssi early so we can re-use for each aggregate */
3240 rssi = cvtrssi(ds->RSSI);
3241
3242 ni = ieee80211_find_rxnode(ic, wh);
3243
3244 /* send the frame to the 802.11 layer */
3245 (void) ieee80211_input(ic, mp0, ni, rssi, 0);
3246 ieee80211_free_node(ni);
3247 rxnext:
3248 /*
3249 * Setup descriptor.
3250 */
3251 ds->QosCtrl = 0;
3252 ds->RSSI = 0;
3253 ds->Status = EAGLE_RXD_STATUS_IDLE;
3254 ds->Channel = 0;
3255 ds->PktLen = LE_16(MWL_AGGR_SIZE);
3256 ds->SQ2 = 0;
3257 ds->pPhysBuffData = bf->bf_baddr;
3258 /* NB: don't touch pPhysNext, set once */
3259 ds->RxControl = EAGLE_RXD_CTRL_DRIVER_OWN;
3260
3261 (void) ddi_dma_sync(ring->rxdesc_dma.dma_hdl,
3262 ring->cur * sizeof (struct mwl_rxdesc),
3263 sizeof (struct mwl_rxdesc),
3264 DDI_DMA_SYNC_FORDEV);
3265
3266 /* NB: ignore ENOMEM so we process more descriptors */
3267 ring->cur = (ring->cur + 1) % MWL_RX_RING_COUNT;
3268 }
3269
3270 MWL_RXUNLOCK(sc);
3271 }
3272
3273 /*ARGSUSED*/
3274 static uint_t
3275 mwl_softintr(caddr_t data, caddr_t unused)
3276 {
3277 struct mwl_softc *sc = (struct mwl_softc *)data;
3278
3279 /*
3280 * Check if the soft interrupt is triggered by another
3281 * driver at the same level.
3282 */
3283 MWL_GLOCK(sc);
3284 if (sc->sc_rx_pend) {
3285 sc->sc_rx_pend = 0;
3286 MWL_GUNLOCK(sc);
3287 mwl_rx_intr(sc);
3288 return (DDI_INTR_CLAIMED);
3289 }
3290 MWL_GUNLOCK(sc);
3291
3292 return (DDI_INTR_UNCLAIMED);
3293 }
3294
3295 /*ARGSUSED*/
3296 static uint_t
3297 mwl_intr(caddr_t arg, caddr_t unused)
3298 {
3299 struct mwl_softc *sc = (struct mwl_softc *)arg;
3300 uint32_t status;
3301
3302 MWL_GLOCK(sc);
3303
3304 if (!MWL_IS_RUNNING(sc) || MWL_IS_SUSPEND(sc)) {
3305 MWL_GUNLOCK(sc);
3306 return (DDI_INTR_UNCLAIMED);
3307 }
3308
3309 /*
3310 * Figure out the reason(s) for the interrupt.
3311 */
3312 mwl_hal_getisr(sc, &status); /* NB: clears ISR too */
3313 if (status == 0) {
3314 MWL_GUNLOCK(sc);
3315 return (DDI_INTR_UNCLAIMED);
3316 }
3317
3318 if (status & MACREG_A2HRIC_BIT_RX_RDY) {
3319 sc->sc_rx_pend = 1;
3320 (void) ddi_intr_trigger_softint(sc->sc_softintr_hdl, NULL);
3321 }
3322 if (status & MACREG_A2HRIC_BIT_TX_DONE) {
3323 mwl_tx_intr(sc);
3324 }
3325 if (status & MACREG_A2HRIC_BIT_BA_WATCHDOG) {
3326 MWL_DBG(MWL_DBG_INTR, "mwl: mwl_intr(): "
3327 "ba watchdog\n");
3328 }
3329 if (status & MACREG_A2HRIC_BIT_OPC_DONE) {
3330 MWL_DBG(MWL_DBG_INTR, "mwl: mwl_intr(): "
3331 "opc done\n");
3332 }
3333 if (status & MACREG_A2HRIC_BIT_MAC_EVENT) {
3334 MWL_DBG(MWL_DBG_INTR, "mwl: mwl_intr(): "
3335 "mac event\n");
3336 }
3337 if (status & MACREG_A2HRIC_BIT_ICV_ERROR) {
3338 MWL_DBG(MWL_DBG_INTR, "mwl: mwl_intr(): "
3339 "ICV error\n");
3340 }
3341 if (status & MACREG_A2HRIC_BIT_QUEUE_EMPTY) {
3342 MWL_DBG(MWL_DBG_INTR, "mwl: mwl_intr(): "
3343 "queue empty\n");
3344 }
3345 if (status & MACREG_A2HRIC_BIT_QUEUE_FULL) {
3346 MWL_DBG(MWL_DBG_INTR, "mwl: mwl_intr(): "
3347 "queue full\n");
3348 }
3349 if (status & MACREG_A2HRIC_BIT_RADAR_DETECT) {
3350 MWL_DBG(MWL_DBG_INTR, "mwl: mwl_intr(): "
3351 "radar detect\n");
3352 }
3353 if (status & MACREG_A2HRIC_BIT_CHAN_SWITCH) {
3354 MWL_DBG(MWL_DBG_INTR, "mwl: mwl_intr(): "
3355 "chan switch\n");
3356 }
3357
3358 MWL_GUNLOCK(sc);
3359
3360 return (DDI_INTR_CLAIMED);
3361 }
3362
3363 static int
3364 mwl_init(struct mwl_softc *sc)
3365 {
3366 struct ieee80211com *ic = &sc->sc_ic;
3367 int err = 0;
3368
3369 mwl_hal_intrset(sc, 0);
3370
3371 sc->sc_txantenna = 0; /* h/w default */
3372 sc->sc_rxantenna = 0; /* h/w default */
3373
3374 err = mwl_hal_setantenna(sc, WL_ANTENNATYPE_RX, sc->sc_rxantenna);
3375 if (err != 0) {
3376 MWL_DBG(MWL_DBG_HW, "mwl: mwl_init(): "
3377 "could not set rx antenna\n");
3378 goto fail;
3379 }
3380
3381 err = mwl_hal_setantenna(sc, WL_ANTENNATYPE_TX, sc->sc_txantenna);
3382 if (err != 0) {
3383 MWL_DBG(MWL_DBG_HW, "mwl: init(): "
3384 "could not set tx antenna\n");
3385 goto fail;
3386 }
3387
3388 err = mwl_hal_setradio(sc, 1, WL_AUTO_PREAMBLE);
3389 if (err != 0) {
3390 MWL_DBG(MWL_DBG_HW, "mwl: init(): "
3391 "could not set radio\n");
3392 goto fail;
3393 }
3394
3395 err = mwl_hal_setwmm(sc, (ic->ic_flags & IEEE80211_F_WME) != 0);
3396 if (err != 0) {
3397 MWL_DBG(MWL_DBG_HW, "mwl: init(): "
3398 "could not set wme\n");
3399 goto fail;
3400 }
3401
3402 /* select default channel */
3403 ic->ic_ibss_chan = &ic->ic_sup_channels[0];
3404 ic->ic_curchan = ic->ic_ibss_chan;
3405 sc->sc_cur_chan = &sc->sc_channels[1];
3406
3407 err = mwl_chan_set(sc, sc->sc_cur_chan);
3408 if (err != 0) {
3409 MWL_DBG(MWL_DBG_HW, "mwl: init(): "
3410 "could not set wme\n");
3411 goto fail;
3412 }
3413
3414 err = mwl_hal_setrateadaptmode(sc, 0);
3415 if (err != 0) {
3416 MWL_DBG(MWL_DBG_HW, "mwl: init(): "
3417 "could not set rate adapt mode\n");
3418 goto fail;
3419 }
3420
3421 err = mwl_hal_setoptimizationlevel(sc,
3422 (ic->ic_flags & IEEE80211_F_BURST) != 0);
3423 if (err != 0) {
3424 MWL_DBG(MWL_DBG_HW, "mwl: init(): "
3425 "could not set optimization level\n");
3426 goto fail;
3427 }
3428
3429 err = mwl_hal_setregioncode(sc, mwl_map2regioncode(&sc->sc_regdomain));
3430 if (err != 0) {
3431 MWL_DBG(MWL_DBG_HW, "mwl: init(): "
3432 "could not set regioncode\n");
3433 goto fail;
3434 }
3435
3436 err = mwl_startrecv(sc);
3437 if (err != 0) {
3438 MWL_DBG(MWL_DBG_HW, "mwl: init(): "
3439 "could not set start recv logic\n");
3440 goto fail;
3441 }
3442
3443 /*
3444 * Enable interrupts.
3445 */
3446 sc->sc_imask = MACREG_A2HRIC_BIT_RX_RDY
3447 | MACREG_A2HRIC_BIT_TX_DONE
3448 | MACREG_A2HRIC_BIT_OPC_DONE
3449 | MACREG_A2HRIC_BIT_ICV_ERROR
3450 | MACREG_A2HRIC_BIT_RADAR_DETECT
3451 | MACREG_A2HRIC_BIT_CHAN_SWITCH
3452 | MACREG_A2HRIC_BIT_BA_WATCHDOG
3453 | MACREQ_A2HRIC_BIT_TX_ACK;
3454
3455 mwl_hal_intrset(sc, sc->sc_imask);
3456
3457 err = mwl_hal_start(sc);
3458 if (err != 0) {
3459 MWL_DBG(MWL_DBG_HW, "mwl: init(): "
3460 "could not get hal start\n");
3461 goto fail;
3462 }
3463
3464 err = mwl_hal_setinframode(sc);
3465 if (err != 0) {
3466 MWL_DBG(MWL_DBG_HW, "mwl: init(): "
3467 "could not set infra mode\n");
3468 goto fail;
3469 }
3470
3471 fail:
3472 return (err);
3473 }
3474
3475 static int
3476 mwl_resume(struct mwl_softc *sc)
3477 {
3478 int qid, err = 0;
3479
3480 err = mwl_fwload(sc, NULL);
3481 if (err != 0) {
3482 MWL_DBG(MWL_DBG_SR, "mwl: mwl_resume(): "
3483 "failed to load fw\n");
3484 goto fail;
3485 }
3486
3487 err = mwl_gethwspecs(sc);
3488 if (err != 0) {
3489 MWL_DBG(MWL_DBG_SR, "mwl: mwl_resume(): "
3490 "failed to get hw spec\n");
3491 goto fail;
3492 }
3493
3494 err = mwl_alloc_rx_ring(sc, MWL_RX_RING_COUNT);
3495 if (err != 0) {
3496 MWL_DBG(MWL_DBG_SR, "mwl: mwl_resume(): "
3497 "could not alloc cmd dma buffer\n");
3498 goto fail;
3499 }
3500
3501 for (qid = 0; qid < MWL_NUM_TX_QUEUES; qid++) {
3502 err = mwl_alloc_tx_ring(sc,
3503 &sc->sc_txring[qid], MWL_TX_RING_COUNT);
3504 if (err != 0) {
3505 MWL_DBG(MWL_DBG_SR, "mwl: mwl_resume(): "
3506 "could not alloc tx ring %d\n", qid);
3507 goto fail;
3508 }
3509 }
3510
3511 err = mwl_setupdma(sc);
3512 if (err != 0) {
3513 MWL_DBG(MWL_DBG_SR, "mwl: mwl_resume(): "
3514 "could not setup dma\n");
3515 goto fail;
3516 }
3517
3518 err = mwl_setup_txq(sc);
3519 if (err != 0) {
3520 MWL_DBG(MWL_DBG_SR, "mwl: mwl_resume(): "
3521 "could not setup txq\n");
3522 goto fail;
3523 }
3524
3525 fail:
3526 return (err);
3527 }
3528
3529 static void
3530 mwl_stop(struct mwl_softc *sc)
3531 {
3532 int err;
3533
3534 /* by pass if it's quiesced */
3535 if (!MWL_IS_QUIESCE(sc))
3536 MWL_GLOCK(sc);
3537
3538 err = mwl_hal_stop(sc);
3539 if (err != 0) {
3540 MWL_DBG(MWL_DBG_HW, "mwl: mwl_stop(): "
3541 "could not stop hw\n");
3542 }
3543
3544 /* by pass if it's quiesced */
3545 if (!MWL_IS_QUIESCE(sc))
3546 MWL_GUNLOCK(sc);
3547 }
3548
3549 static int
3550 mwl_m_stat(void *arg, uint_t stat, uint64_t *val)
3551 {
3552 struct mwl_softc *sc = (struct mwl_softc *)arg;
3553 struct ieee80211com *ic = &sc->sc_ic;
3554 struct ieee80211_node *ni = NULL;
3555 struct ieee80211_rateset *rs = NULL;
3556
3557 MWL_GLOCK(sc);
3558 switch (stat) {
3559 case MAC_STAT_IFSPEED:
3560 ni = ic->ic_bss;
3561 rs = &ni->in_rates;
3562 *val = ((ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) ?
3563 (rs->ir_rates[ni->in_txrate] & IEEE80211_RATE_VAL)
3564 : ic->ic_fixed_rate) / 2 * 1000000;
3565 break;
3566 case MAC_STAT_NOXMTBUF:
3567 *val = sc->sc_tx_nobuf;
3568 break;
3569 case MAC_STAT_NORCVBUF:
3570 *val = sc->sc_rx_nobuf;
3571 break;
3572 case MAC_STAT_IERRORS:
3573 *val = sc->sc_rx_err;
3574 break;
3575 case MAC_STAT_RBYTES:
3576 *val = ic->ic_stats.is_rx_bytes;
3577 break;
3578 case MAC_STAT_IPACKETS:
3579 *val = ic->ic_stats.is_rx_frags;
3580 break;
3581 case MAC_STAT_OBYTES:
3582 *val = ic->ic_stats.is_tx_bytes;
3583 break;
3584 case MAC_STAT_OPACKETS:
3585 *val = ic->ic_stats.is_tx_frags;
3586 break;
3587 case MAC_STAT_OERRORS:
3588 case WIFI_STAT_TX_FAILED:
3589 *val = sc->sc_tx_err;
3590 break;
3591 case WIFI_STAT_TX_RETRANS:
3592 *val = sc->sc_tx_retries;
3593 break;
3594 case WIFI_STAT_FCS_ERRORS:
3595 case WIFI_STAT_WEP_ERRORS:
3596 case WIFI_STAT_TX_FRAGS:
3597 case WIFI_STAT_MCAST_TX:
3598 case WIFI_STAT_RTS_SUCCESS:
3599 case WIFI_STAT_RTS_FAILURE:
3600 case WIFI_STAT_ACK_FAILURE:
3601 case WIFI_STAT_RX_FRAGS:
3602 case WIFI_STAT_MCAST_RX:
3603 case WIFI_STAT_RX_DUPS:
3604 MWL_GUNLOCK(sc);
3605 return (ieee80211_stat(ic, stat, val));
3606 default:
3607 MWL_GUNLOCK(sc);
3608 return (ENOTSUP);
3609 }
3610
3611 MWL_GUNLOCK(sc);
3612 return (0);
3613 }
3614
3615 static int
3616 mwl_m_start(void *arg)
3617 {
3618 struct mwl_softc *sc = (struct mwl_softc *)arg;
3619 struct ieee80211com *ic = &sc->sc_ic;
3620 int err;
3621
3622 err = mwl_init(sc);
3623 if (err != DDI_SUCCESS) {
3624 MWL_DBG(MWL_DBG_HW, "mwl: mwl_m_start():"
3625 "Hardware initialization failed\n");
3626 goto fail1;
3627 }
3628
3629 ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
3630
3631 MWL_GLOCK(sc);
3632 sc->sc_flags |= MWL_F_RUNNING;
3633 MWL_GUNLOCK(sc);
3634
3635 return (0);
3636 fail1:
3637 mwl_stop(sc);
3638 return (err);
3639 }
3640
3641 static void
3642 mwl_m_stop(void *arg)
3643 {
3644 struct mwl_softc *sc = (struct mwl_softc *)arg;
3645
3646 mwl_stop(sc);
3647
3648 ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
3649
3650 MWL_GLOCK(sc);
3651 sc->sc_flags &= ~MWL_F_RUNNING;
3652 MWL_GUNLOCK(sc);
3653 }
3654
3655 /*ARGSUSED*/
3656 static int
3657 mwl_m_promisc(void *arg, boolean_t on)
3658 {
3659 struct mwl_softc *sc = (struct mwl_softc *)arg;
3660 int err;
3661
3662 err = mwl_hal_setpromisc(sc, on);
3663
3664 return (err);
3665 }
3666
3667 /*ARGSUSED*/
3668 static int
3669 mwl_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
3670 {
3671 return (ENOTSUP);
3672 }
3673
3674 /*ARGSUSED*/
3675 static int
3676 mwl_m_unicst(void *arg, const uint8_t *macaddr)
3677 {
3678 return (ENOTSUP);
3679 }
3680
3681 static mblk_t *
3682 mwl_m_tx(void *arg, mblk_t *mp)
3683 {
3684 struct mwl_softc *sc = (struct mwl_softc *)arg;
3685 struct ieee80211com *ic = &sc->sc_ic;
3686 mblk_t *next;
3687
3688 if (MWL_IS_SUSPEND(sc)) {
3689 freemsgchain(mp);
3690 return (NULL);
3691 }
3692
3693 /*
3694 * No data frames go out unless we're associated; this
3695 * should not happen as the 802.11 layer does not enable
3696 * the xmit queue until we enter the RUN state.
3697 */
3698 if (ic->ic_state != IEEE80211_S_RUN) {
3699 MWL_DBG(MWL_DBG_TX, "mwl: mwl_m_tx(): "
3700 "discard, state %u\n", ic->ic_state);
3701 freemsgchain(mp);
3702 return (NULL);
3703 }
3704
3705 while (mp != NULL) {
3706 next = mp->b_next;
3707 mp->b_next = NULL;
3708 if (mwl_send(ic, mp, IEEE80211_FC0_TYPE_DATA) !=
3709 DDI_SUCCESS) {
3710 mp->b_next = next;
3711 break;
3712 }
3713 mp = next;
3714 }
3715 return (mp);
3716 }
3717
3718 static void
3719 mwl_m_ioctl(void* arg, queue_t *wq, mblk_t *mp)
3720 {
3721 struct mwl_softc *sc = (struct mwl_softc *)arg;
3722 struct ieee80211com *ic = &sc->sc_ic;
3723 int err;
3724
3725 err = ieee80211_ioctl(ic, wq, mp);
3726 if (err == ENETRESET) {
3727 if (ic->ic_des_esslen) {
3728 if (MWL_IS_RUNNING(sc)) {
3729 (void) mwl_init(sc);
3730 (void) ieee80211_new_state(ic,
3731 IEEE80211_S_SCAN, -1);
3732 }
3733 }
3734 }
3735 }
3736
3737 /*
3738 * Call back function for get/set proporty
3739 */
3740 static int
3741 mwl_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
3742 uint_t wldp_length, void *wldp_buf)
3743 {
3744 struct mwl_softc *sc = (struct mwl_softc *)arg;
3745 int err = 0;
3746
3747 err = ieee80211_getprop(&sc->sc_ic, pr_name, wldp_pr_num,
3748 wldp_length, wldp_buf);
3749
3750 return (err);
3751 }
3752
3753 static void
3754 mwl_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
3755 mac_prop_info_handle_t prh)
3756 {
3757 struct mwl_softc *sc = (struct mwl_softc *)arg;
3758
3759 ieee80211_propinfo(&sc->sc_ic, pr_name, wldp_pr_num, prh);
3760 }
3761
3762 static int
3763 mwl_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
3764 uint_t wldp_length, const void *wldp_buf)
3765 {
3766 struct mwl_softc *sc = (struct mwl_softc *)arg;
3767 ieee80211com_t *ic = &sc->sc_ic;
3768 int err;
3769
3770 err = ieee80211_setprop(ic, pr_name, wldp_pr_num, wldp_length,
3771 wldp_buf);
3772 if (err == ENETRESET) {
3773 if (ic->ic_des_esslen) {
3774 if (MWL_IS_RUNNING(sc)) {
3775 (void) mwl_init(sc);
3776 (void) ieee80211_new_state(ic,
3777 IEEE80211_S_SCAN, -1);
3778 }
3779 }
3780 err = 0;
3781 }
3782 return (err);
3783 }
3784
3785 static int
3786 mwl_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
3787 {
3788 struct mwl_softc *sc;
3789 struct ieee80211com *ic;
3790 int i, err, qid, instance;
3791 int intr_type, intr_count, intr_actual;
3792 char strbuf[32];
3793 uint8_t csz;
3794 uint16_t vendor_id, device_id, command;
3795
3796 wifi_data_t wd = { 0 };
3797 mac_register_t *macp;
3798
3799 switch (cmd) {
3800 case DDI_ATTACH:
3801 break;
3802 case DDI_RESUME:
3803 sc = ddi_get_soft_state(mwl_soft_state_p,
3804 ddi_get_instance(devinfo));
3805 ASSERT(sc != NULL);
3806 MWL_GLOCK(sc);
3807 sc->sc_flags &= ~MWL_F_SUSPEND;
3808 MWL_GUNLOCK(sc);
3809 if (mwl_resume(sc) != 0) {
3810 MWL_DBG(MWL_DBG_SR, "mwl: mwl_attach(): "
3811 "failed to resume\n");
3812 return (DDI_FAILURE);
3813 }
3814 if (MWL_IS_RUNNING(sc)) {
3815 (void) mwl_init(sc);
3816 ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
3817 }
3818 MWL_DBG(MWL_DBG_SR, "mwl: mwl_attach(): "
3819 "resume now\n");
3820 return (DDI_SUCCESS);
3821 default:
3822 return (DDI_FAILURE);
3823 }
3824
3825 instance = ddi_get_instance(devinfo);
3826 if (ddi_soft_state_zalloc(mwl_soft_state_p,
3827 ddi_get_instance(devinfo)) != DDI_SUCCESS) {
3828 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3829 "Unable to alloc soft state\n");
3830 return (DDI_FAILURE);
3831 }
3832
3833 sc = ddi_get_soft_state(mwl_soft_state_p, ddi_get_instance(devinfo));
3834 ic = &sc->sc_ic;
3835 sc->sc_dev = devinfo;
3836
3837 /* PCI configuration space */
3838 err = ddi_regs_map_setup(devinfo, 0, (caddr_t *)&sc->sc_cfg_base, 0, 0,
3839 &mwl_reg_accattr, &sc->sc_cfg_handle);
3840 if (err != DDI_SUCCESS) {
3841 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3842 "ddi_regs_map_setup() failed");
3843 goto attach_fail0;
3844 }
3845 csz = ddi_get8(sc->sc_cfg_handle,
3846 (uint8_t *)(sc->sc_cfg_base + PCI_CONF_CACHE_LINESZ));
3847 if (!csz)
3848 csz = 16;
3849 sc->sc_cachelsz = csz << 2;
3850 sc->sc_dmabuf_size = roundup(IEEE80211_MAX_LEN, sc->sc_cachelsz);
3851 vendor_id = ddi_get16(sc->sc_cfg_handle,
3852 (uint16_t *)(sc->sc_cfg_base + PCI_CONF_VENID));
3853 device_id = ddi_get16(sc->sc_cfg_handle,
3854 (uint16_t *)(sc->sc_cfg_base + PCI_CONF_DEVID));
3855 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3856 "vendor 0x%x, device id 0x%x, cache size %d\n",
3857 vendor_id, device_id, csz);
3858
3859 /*
3860 * Enable response to memory space accesses,
3861 * and enabe bus master.
3862 */
3863 command = PCI_COMM_MAE | PCI_COMM_ME;
3864 ddi_put16(sc->sc_cfg_handle,
3865 (uint16_t *)((uintptr_t)(sc->sc_cfg_base) + PCI_CONF_COMM),
3866 command);
3867 ddi_put8(sc->sc_cfg_handle,
3868 (uint8_t *)(sc->sc_cfg_base + PCI_CONF_LATENCY_TIMER), 0xa8);
3869 ddi_put8(sc->sc_cfg_handle,
3870 (uint8_t *)(sc->sc_cfg_base + PCI_CONF_ILINE), 0x10);
3871
3872 /* BAR0 */
3873 err = ddi_regs_map_setup(devinfo, 1,
3874 &sc->sc_mem_base, 0, 0, &mwl_reg_accattr, &sc->sc_mem_handle);
3875 if (err != DDI_SUCCESS) {
3876 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3877 "i/o space failed");
3878 goto attach_fail1;
3879 }
3880
3881 /* BAR1 */
3882 err = ddi_regs_map_setup(devinfo, 2,
3883 &sc->sc_io_base, 0, 0, &mwl_reg_accattr, &sc->sc_io_handle);
3884 if (err != DDI_SUCCESS) {
3885 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3886 "memory space failed");
3887 goto attach_fail2;
3888 }
3889
3890 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3891 "PCI configuration is done successfully\n");
3892
3893 /*
3894 * Alloc cmd DMA buffer for firmware download
3895 */
3896 err = mwl_alloc_cmdbuf(sc);
3897 if (err != 0) {
3898 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3899 "could not alloc cmd dma buffer\n");
3900 goto attach_fail3;
3901 }
3902
3903 sc->sc_imask = 0;
3904 sc->sc_hw_flags = 0;
3905 sc->sc_flags = 0;
3906
3907 /*
3908 * Some cards have SDRAM. When loading firmware we need
3909 * to reset the SDRAM controller prior to doing this.
3910 * When the SDRAMSIZE is non-zero we do that work in
3911 * mwl_hal_fwload.
3912 */
3913 switch (device_id) {
3914 case 0x2a02: /* CB82 */
3915 case 0x2a03: /* CB85 */
3916 case 0x2a08: /* MC85_B1 */
3917 case 0x2a0b: /* CB85AP */
3918 case 0x2a24:
3919 sc->sc_SDRAMSIZE_Addr = 0x40fe70b7; /* 8M SDRAM */
3920 break;
3921 case 0x2a04: /* MC85 */
3922 sc->sc_SDRAMSIZE_Addr = 0x40fc70b7; /* 16M SDRAM */
3923 break;
3924 default:
3925 break;
3926 }
3927
3928 err = mwl_fwload(sc, NULL);
3929 if (err != 0) {
3930 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3931 "firmware download failed\n");
3932 goto attach_fail4;
3933 }
3934
3935 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3936 "firmware download successfully\n");
3937
3938 err = mwl_gethwspecs(sc);
3939 if (err != 0) {
3940 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3941 "failed to get hw spec\n");
3942 goto attach_fail4;
3943 }
3944
3945 err = mwl_getchannels(sc);
3946 if (err != 0) {
3947 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3948 "failed to get channels\n");
3949 goto attach_fail4;
3950 }
3951
3952 /*
3953 * Alloc rx DMA buffer
3954 */
3955 err = mwl_alloc_rx_ring(sc, MWL_RX_RING_COUNT);
3956 if (err != 0) {
3957 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3958 "could not alloc cmd dma buffer\n");
3959 goto attach_fail5;
3960 }
3961
3962 /*
3963 * Alloc rx DMA buffer
3964 */
3965 for (qid = 0; qid < MWL_NUM_TX_QUEUES; qid++) {
3966 err = mwl_alloc_tx_ring(sc,
3967 &sc->sc_txring[qid], MWL_TX_RING_COUNT);
3968 if (err != 0) {
3969 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3970 "could not alloc tx ring %d\n", qid);
3971 goto attach_fail6;
3972 }
3973 }
3974
3975 err = mwl_setupdma(sc);
3976 if (err != 0) {
3977 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3978 "could not setup dma\n");
3979 goto attach_fail6;
3980 }
3981
3982 err = mwl_setup_txq(sc);
3983 if (err != 0) {
3984 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3985 "could not setup txq\n");
3986 goto attach_fail6;
3987 }
3988
3989 IEEE80211_ADDR_COPY(ic->ic_macaddr, sc->sc_hwspecs.macAddr);
3990 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3991 "mwl MAC:%2x:%2x:%2x:%2x:%2x:%2x\n",
3992 ic->ic_macaddr[0],
3993 ic->ic_macaddr[1],
3994 ic->ic_macaddr[2],
3995 ic->ic_macaddr[3],
3996 ic->ic_macaddr[4],
3997 ic->ic_macaddr[5]);
3998
3999 err = mwl_hal_setmac_locked(sc, ic->ic_macaddr);
4000 if (err != 0) { /* NB: mwl_setupdma prints msg */
4001 MWL_DBG(MWL_DBG_ATTACH, "mwl: attach(): "
4002 "could not set mac\n");
4003 goto attach_fail6;
4004 }
4005
4006 mutex_init(&sc->sc_glock, NULL, MUTEX_DRIVER, NULL);
4007 mutex_init(&sc->sc_rxlock, NULL, MUTEX_DRIVER, NULL);
4008 mutex_init(&sc->sc_txlock, NULL, MUTEX_DRIVER, NULL);
4009
4010
4011 /* set supported rates */
4012 ic->ic_sup_rates[IEEE80211_MODE_11B] = mwl_rateset_11b;
4013 ic->ic_sup_rates[IEEE80211_MODE_11G] = mwl_rateset_11g;
4014
4015 /* set supported .11b and .11g channels (1 through 14) */
4016 for (i = 1; i <= 14; i++) {
4017 ic->ic_sup_channels[i].ich_freq =
4018 ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
4019 ic->ic_sup_channels[i].ich_flags =
4020 IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
4021 }
4022
4023 ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
4024 ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */
4025 ic->ic_state = IEEE80211_S_INIT;
4026
4027 /* set device capabilities */
4028 ic->ic_caps =
4029 IEEE80211_C_TXPMGT | /* tx power management */
4030 IEEE80211_C_SHPREAMBLE | /* short preamble supported */
4031 IEEE80211_C_SHSLOT; /* short slot time supported */
4032
4033 /* WPA/WPA2 support */
4034 ic->ic_caps |= IEEE80211_C_WPA; /* Support WPA/WPA2 */
4035
4036 /* Enable hardware encryption */
4037 ic->ic_caps |= IEEE80211_C_WEP | IEEE80211_C_TKIP | IEEE80211_C_AES_CCM;
4038
4039 ic->ic_xmit = mwl_send;
4040
4041 ieee80211_attach(ic);
4042
4043 /* register WPA door */
4044 ieee80211_register_door(ic, ddi_driver_name(devinfo),
4045 ddi_get_instance(devinfo));
4046
4047 /* override state transition machine */
4048 sc->sc_newstate = ic->ic_newstate;
4049 ic->ic_newstate = mwl_newstate;
4050 ic->ic_node_alloc = mwl_node_alloc;
4051 ic->ic_node_free = mwl_node_free;
4052 ic->ic_crypto.cs_max_keyix = 0;
4053 ic->ic_crypto.cs_key_alloc = mwl_key_alloc;
4054 ic->ic_crypto.cs_key_delete = mwl_key_delete;
4055 ic->ic_crypto.cs_key_set = mwl_key_set;
4056
4057 ieee80211_media_init(ic);
4058
4059 ic->ic_def_txkey = 0;
4060
4061 err = mwl_hal_newstation(sc, ic->ic_macaddr, 0, 0, NULL, 0, 0);
4062 if (err != 0) {
4063 MWL_DBG(MWL_DBG_ATTACH, "mwl: attach(): "
4064 "could not create new station\n");
4065 goto attach_fail7;
4066 }
4067
4068 IEEE80211_ADDR_COPY(ic->ic_bss->in_bssid, ic->ic_macaddr);
4069 // mwl_setglobalkeys(ic);
4070
4071 err = ddi_intr_get_supported_types(devinfo, &intr_type);
4072 if ((err != DDI_SUCCESS) || (!(intr_type & DDI_INTR_TYPE_FIXED))) {
4073 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
4074 "fixed type interrupt is not supported\n");
4075 goto attach_fail7;
4076 }
4077
4078 err = ddi_intr_get_nintrs(devinfo, DDI_INTR_TYPE_FIXED, &intr_count);
4079 if ((err != DDI_SUCCESS) || (intr_count != 1)) {
4080 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
4081 "no fixed interrupts\n");
4082 goto attach_fail7;
4083 }
4084
4085 sc->sc_intr_htable = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_SLEEP);
4086
4087 err = ddi_intr_alloc(devinfo, sc->sc_intr_htable,
4088 DDI_INTR_TYPE_FIXED, 0, intr_count, &intr_actual, 0);
4089 if ((err != DDI_SUCCESS) || (intr_actual != 1)) {
4090 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
4091 "ddi_intr_alloc() failed 0x%x\n", err);
4092 goto attach_fail8;
4093 }
4094
4095 err = ddi_intr_get_pri(sc->sc_intr_htable[0], &sc->sc_intr_pri);
4096 if (err != DDI_SUCCESS) {
4097 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
4098 "ddi_intr_get_pri() failed 0x%x\n", err);
4099 goto attach_fail9;
4100 }
4101
4102 err = ddi_intr_add_softint(devinfo, &sc->sc_softintr_hdl,
4103 DDI_INTR_SOFTPRI_MAX, mwl_softintr, (caddr_t)sc);
4104 if (err != DDI_SUCCESS) {
4105 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
4106 "ddi_add_softintr() failed");
4107 goto attach_fail9;
4108 }
4109
4110 err = ddi_intr_add_handler(sc->sc_intr_htable[0], mwl_intr,
4111 (caddr_t)sc, NULL);
4112 if (err != DDI_SUCCESS) {
4113 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
4114 "ddi_intr_addr_handle() failed\n");
4115 goto attach_fail10;
4116 }
4117
4118 err = ddi_intr_enable(sc->sc_intr_htable[0]);
4119 if (err != DDI_SUCCESS) {
4120 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
4121 "ddi_intr_enable() failed\n");
4122 goto attach_fail11;
4123 }
4124
4125 /*
4126 * Provide initial settings for the WiFi plugin; whenever this
4127 * information changes, we need to call mac_plugindata_update()
4128 */
4129 wd.wd_opmode = ic->ic_opmode;
4130 wd.wd_secalloc = WIFI_SEC_NONE;
4131 IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid);
4132
4133 if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
4134 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
4135 "MAC version mismatch\n");
4136 goto attach_fail12;
4137 }
4138
4139 macp->m_type_ident = MAC_PLUGIN_IDENT_WIFI;
4140 macp->m_driver = sc;
4141 macp->m_dip = devinfo;
4142 macp->m_src_addr = ic->ic_macaddr;
4143 macp->m_callbacks = &mwl_m_callbacks;
4144 macp->m_min_sdu = 0;
4145 macp->m_max_sdu = IEEE80211_MTU;
4146 macp->m_pdata = &wd;
4147 macp->m_pdata_size = sizeof (wd);
4148
4149 err = mac_register(macp, &ic->ic_mach);
4150 mac_free(macp);
4151 if (err != 0) {
4152 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
4153 "mac_register err %x\n", err);
4154 goto attach_fail12;
4155 }
4156
4157 /*
4158 * Create minor node of type DDI_NT_NET_WIFI
4159 */
4160 (void) snprintf(strbuf, sizeof (strbuf), "%s%d",
4161 "mwl", instance);
4162 err = ddi_create_minor_node(devinfo, strbuf, S_IFCHR,
4163 instance + 1, DDI_NT_NET_WIFI, 0);
4164 if (err != 0) {
4165 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
4166 "create minor node error\n");
4167 goto attach_fail13;
4168 }
4169
4170 /*
4171 * Notify link is down now
4172 */
4173 mac_link_update(ic->ic_mach, LINK_STATE_DOWN);
4174
4175 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
4176 "driver attach successfully\n");
4177 return (DDI_SUCCESS);
4178
4179 attach_fail13:
4180 (void) mac_disable(ic->ic_mach);
4181 (void) mac_unregister(ic->ic_mach);
4182 attach_fail12:
4183 (void) ddi_intr_disable(sc->sc_intr_htable[0]);
4184 attach_fail11:
4185 (void) ddi_intr_remove_handler(sc->sc_intr_htable[0]);
4186 attach_fail10:
4187 (void) ddi_intr_remove_softint(sc->sc_softintr_hdl);
4188 sc->sc_softintr_hdl = NULL;
4189 attach_fail9:
4190 (void) ddi_intr_free(sc->sc_intr_htable[0]);
4191 attach_fail8:
4192 kmem_free(sc->sc_intr_htable, sizeof (ddi_intr_handle_t));
4193 attach_fail7:
4194 mutex_destroy(&sc->sc_txlock);
4195 mutex_destroy(&sc->sc_rxlock);
4196 mutex_destroy(&sc->sc_glock);
4197 attach_fail6:
4198 while (--qid >= 0)
4199 mwl_free_tx_ring(sc, &sc->sc_txring[qid]);
4200 attach_fail5:
4201 mwl_free_rx_ring(sc);
4202 attach_fail4:
4203 mwl_free_cmdbuf(sc);
4204 attach_fail3:
4205 ddi_regs_map_free(&sc->sc_mem_handle);
4206 attach_fail2:
4207 ddi_regs_map_free(&sc->sc_io_handle);
4208 attach_fail1:
4209 ddi_regs_map_free(&sc->sc_cfg_handle);
4210 attach_fail0:
4211 ddi_soft_state_free(mwl_soft_state_p, ddi_get_instance(devinfo));
4212 return (DDI_FAILURE);
4213 }
4214
4215 static int32_t
4216 mwl_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
4217 {
4218 struct mwl_softc *sc;
4219 int qid;
4220
4221 sc = ddi_get_soft_state(mwl_soft_state_p, ddi_get_instance(devinfo));
4222 ASSERT(sc != NULL);
4223
4224 switch (cmd) {
4225 case DDI_DETACH:
4226 break;
4227 case DDI_SUSPEND:
4228 if (MWL_IS_RUNNING(sc))
4229 mwl_stop(sc);
4230 for (qid = 0; qid < MWL_NUM_TX_QUEUES; qid++)
4231 mwl_free_tx_ring(sc, &sc->sc_txring[qid]);
4232 mwl_free_rx_ring(sc);
4233 MWL_GLOCK(sc);
4234 sc->sc_flags |= MWL_F_SUSPEND;
4235 MWL_GUNLOCK(sc);
4236 MWL_DBG(MWL_DBG_SR, "mwl: mwl_detach(): "
4237 "suspend now\n");
4238 return (DDI_SUCCESS);
4239 default:
4240 return (DDI_FAILURE);
4241 }
4242
4243 if (mac_disable(sc->sc_ic.ic_mach) != 0)
4244 return (DDI_FAILURE);
4245
4246 /*
4247 * Unregister from the MAC layer subsystem
4248 */
4249 (void) mac_unregister(sc->sc_ic.ic_mach);
4250
4251 (void) ddi_intr_remove_softint(sc->sc_softintr_hdl);
4252 sc->sc_softintr_hdl = NULL;
4253 (void) ddi_intr_disable(sc->sc_intr_htable[0]);
4254 (void) ddi_intr_remove_handler(sc->sc_intr_htable[0]);
4255 (void) ddi_intr_free(sc->sc_intr_htable[0]);
4256 kmem_free(sc->sc_intr_htable, sizeof (ddi_intr_handle_t));
4257
4258 /*
4259 * detach ieee80211 layer
4260 */
4261 ieee80211_detach(&sc->sc_ic);
4262
4263
4264 for (qid = 0; qid < MWL_NUM_TX_QUEUES; qid++)
4265 mwl_free_tx_ring(sc, &sc->sc_txring[qid]);
4266 mwl_free_rx_ring(sc);
4267 mwl_free_cmdbuf(sc);
4268
4269 mutex_destroy(&sc->sc_txlock);
4270 mutex_destroy(&sc->sc_rxlock);
4271 mutex_destroy(&sc->sc_glock);
4272
4273 ddi_regs_map_free(&sc->sc_mem_handle);
4274 ddi_regs_map_free(&sc->sc_io_handle);
4275 ddi_regs_map_free(&sc->sc_cfg_handle);
4276
4277 ddi_remove_minor_node(devinfo, NULL);
4278 ddi_soft_state_free(mwl_soft_state_p, ddi_get_instance(devinfo));
4279
4280 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_detach(): "
4281 "detach successfully\n");
4282 return (DDI_SUCCESS);
4283 }
4284
4285 /*
4286 * quiesce(9E) entry point.
4287 *
4288 * This function is called when the system is single-threaded at high
4289 * PIL with preemption disabled. Therefore, this function must not be
4290 * blocked.
4291 *
4292 * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
4293 * DDI_FAILURE indicates an error condition and should almost never happen.
4294 */
4295 int
4296 mwl_quiesce(dev_info_t *dip)
4297 {
4298 struct mwl_softc *sc;
4299
4300 sc = ddi_get_soft_state(mwl_soft_state_p, ddi_get_instance(dip));
4301 if (sc == NULL)
4302 return (DDI_FAILURE);
4303
4304 #ifdef DEBUG
4305 mwl_dbg_flags = 0;
4306 #endif
4307
4308 /*
4309 * No more blocking is allowed while we are in quiesce(9E) entry point
4310 */
4311 sc->sc_flags |= MWL_F_QUIESCE;
4312
4313 /*
4314 * Disable all interrupts
4315 */
4316 mwl_stop(sc);
4317 return (DDI_SUCCESS);
4318 }
4319
4320 int
4321 _init(void)
4322 {
4323 int status;
4324
4325 status = ddi_soft_state_init(&mwl_soft_state_p,
4326 sizeof (struct mwl_softc), 1);
4327 if (status != 0)
4328 return (status);
4329
4330 mac_init_ops(&mwl_dev_ops, "mwl");
4331 status = mod_install(&modlinkage);
4332 if (status != 0) {
4333 mac_fini_ops(&mwl_dev_ops);
4334 ddi_soft_state_fini(&mwl_soft_state_p);
4335 }
4336 return (status);
4337 }
4338
4339 int
4340 _info(struct modinfo *modinfop)
4341 {
4342 return (mod_info(&modlinkage, modinfop));
4343 }
4344
4345 int
4346 _fini(void)
4347 {
4348 int status;
4349
4350 status = mod_remove(&modlinkage);
4351 if (status == 0) {
4352 mac_fini_ops(&mwl_dev_ops);
4353 ddi_soft_state_fini(&mwl_soft_state_p);
4354 }
4355 return (status);
4356 }