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