Print this page
5253 kmem_alloc/kmem_zalloc won't fail with KM_SLEEP
5254 getrbuf won't fail with KM_SLEEP
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/rtw/rtw.c
+++ new/usr/src/uts/common/io/rtw/rtw.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) 2004 David Young. All rights reserved.
8 8 *
9 9 * This code was written by David Young.
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 * 2. Redistributions in binary form must reproduce the above copyright
17 17 * notice, this list of conditions and the following disclaimer in the
18 18 * documentation and/or other materials provided with the distribution.
19 19 * 3. Neither the name of the author nor the names of any co-contributors
20 20 * may be used to endorse or promote products derived from this software
21 21 * without specific prior written permission.
22 22 *
23 23 * THIS SOFTWARE IS PROVIDED BY David Young ``AS IS'' AND ANY
24 24 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
25 25 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
26 26 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL David
27 27 * Young BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29 29 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
34 34 * OF SUCH DAMAGE.
35 35 */
36 36 #include <sys/sysmacros.h>
37 37 #include <sys/pci.h>
38 38 #include <sys/stat.h>
39 39 #include <sys/strsubr.h>
40 40 #include <sys/strsun.h>
41 41 #include <sys/mac_provider.h>
42 42 #include <sys/mac_wifi.h>
43 43 #include <sys/net80211.h>
44 44 #include <sys/byteorder.h>
45 45 #include "rtwreg.h"
46 46 #include "rtwvar.h"
47 47 #include "smc93cx6var.h"
48 48 #include "rtwphy.h"
49 49 #include "rtwphyio.h"
50 50
51 51 /*
52 52 * PIO access attributes for registers
53 53 */
54 54 static ddi_device_acc_attr_t rtw_reg_accattr = {
55 55 DDI_DEVICE_ATTR_V0,
56 56 DDI_STRUCTURE_LE_ACC,
57 57 DDI_STRICTORDER_ACC,
58 58 DDI_DEFAULT_ACC
59 59 };
60 60
61 61 /*
62 62 * DMA access attributes for descriptors and bufs: NOT to be byte swapped.
63 63 */
64 64 static ddi_device_acc_attr_t rtw_desc_accattr = {
65 65 DDI_DEVICE_ATTR_V0,
66 66 DDI_NEVERSWAP_ACC,
67 67 DDI_STRICTORDER_ACC,
68 68 DDI_DEFAULT_ACC
69 69 };
70 70 static ddi_device_acc_attr_t rtw_buf_accattr = {
71 71 DDI_DEVICE_ATTR_V0,
72 72 DDI_NEVERSWAP_ACC,
73 73 DDI_STRICTORDER_ACC,
74 74 DDI_DEFAULT_ACC
75 75 };
76 76
77 77 /*
78 78 * Describes the chip's DMA engine
79 79 */
80 80 static ddi_dma_attr_t dma_attr_desc = {
81 81 DMA_ATTR_V0, /* dma_attr version */
82 82 0x0000000000000000ull, /* dma_attr_addr_lo */
83 83 0xFFFFFFFF, /* dma_attr_addr_hi */
84 84 0x00000000FFFFFFFFull, /* dma_attr_count_max */
85 85 0x100, /* dma_attr_align */
86 86 0xFFFFFFFF, /* dma_attr_burstsizes */
87 87 0x00000001, /* dma_attr_minxfer */
88 88 0x00000000FFFFull, /* dma_attr_maxxfer */
89 89 0xFFFFFFFFFFFFFFFFull, /* dma_attr_seg */
90 90 1, /* dma_attr_sgllen */
91 91 1, /* dma_attr_granular */
92 92 0 /* dma_attr_flags */
93 93 };
94 94
95 95 static ddi_dma_attr_t dma_attr_rxbuf = {
96 96 DMA_ATTR_V0, /* dma_attr version */
97 97 0x0000000000000000ull, /* dma_attr_addr_lo */
98 98 0xFFFFFFFF, /* dma_attr_addr_hi */
99 99 0x00000000FFFFFFFFull, /* dma_attr_count_max */
100 100 (uint32_t)16, /* dma_attr_align */
101 101 0xFFFFFFFF, /* dma_attr_burstsizes */
102 102 0x00000001, /* dma_attr_minxfer */
103 103 0x00000000FFFFull, /* dma_attr_maxxfer */
104 104 0xFFFFFFFFFFFFFFFFull, /* dma_attr_seg */
105 105 1, /* dma_attr_sgllen */
106 106 1, /* dma_attr_granular */
107 107 0 /* dma_attr_flags */
108 108 };
109 109
110 110 static ddi_dma_attr_t dma_attr_txbuf = {
111 111 DMA_ATTR_V0, /* dma_attr version */
112 112 0x0000000000000000ull, /* dma_attr_addr_lo */
113 113 0xFFFFFFFF, /* dma_attr_addr_hi */
114 114 0x00000000FFFFFFFFull, /* dma_attr_count_max */
115 115 (uint32_t)16, /* dma_attr_align */
116 116 0xFFFFFFFF, /* dma_attr_burstsizes */
117 117 0x00000001, /* dma_attr_minxfer */
118 118 0x00000000FFFFull, /* dma_attr_maxxfer */
119 119 0xFFFFFFFFFFFFFFFFull, /* dma_attr_seg */
120 120 1, /* dma_attr_sgllen */
121 121 1, /* dma_attr_granular */
122 122 0 /* dma_attr_flags */
123 123 };
124 124
125 125
126 126 static void *rtw_soft_state_p = NULL;
127 127
128 128 static void rtw_stop(void *);
129 129 static int rtw_attach(dev_info_t *, ddi_attach_cmd_t);
130 130 static int rtw_detach(dev_info_t *, ddi_detach_cmd_t);
131 131 static int rtw_quiesce(dev_info_t *);
132 132 static int rtw_m_stat(void *, uint_t, uint64_t *);
133 133 static int rtw_m_start(void *);
134 134 static void rtw_m_stop(void *);
135 135 static int rtw_m_promisc(void *, boolean_t);
136 136 static int rtw_m_multicst(void *, boolean_t, const uint8_t *);
137 137 static int rtw_m_unicst(void *, const uint8_t *);
138 138 static mblk_t *rtw_m_tx(void *, mblk_t *);
139 139 static void rtw_m_ioctl(void *, queue_t *, mblk_t *);
140 140 static int rtw_m_setprop(void *, const char *, mac_prop_id_t,
141 141 uint_t, const void *);
142 142 static int rtw_m_getprop(void *, const char *, mac_prop_id_t,
143 143 uint_t, void *);
144 144 static void rtw_m_propinfo(void *, const char *, mac_prop_id_t,
145 145 mac_prop_info_handle_t);
146 146
147 147 static mac_callbacks_t rtw_m_callbacks = {
148 148 MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
149 149 rtw_m_stat,
150 150 rtw_m_start,
151 151 rtw_m_stop,
152 152 rtw_m_promisc,
153 153 rtw_m_multicst,
154 154 rtw_m_unicst,
155 155 rtw_m_tx,
156 156 NULL,
157 157 rtw_m_ioctl,
158 158 NULL, /* mc_getcapab */
159 159 NULL,
160 160 NULL,
161 161 rtw_m_setprop,
162 162 rtw_m_getprop,
163 163 rtw_m_propinfo
164 164 };
165 165
166 166 DDI_DEFINE_STREAM_OPS(rtw_dev_ops, nulldev, nulldev, rtw_attach, rtw_detach,
167 167 nodev, NULL, D_MP, NULL, rtw_quiesce);
168 168
169 169 static struct modldrv rtw_modldrv = {
170 170 &mod_driverops, /* Type of module. This one is a driver */
171 171 "realtek 8180L driver 1.7", /* short description */
172 172 &rtw_dev_ops /* driver specific ops */
173 173 };
174 174
175 175 static struct modlinkage modlinkage = {
176 176 MODREV_1, (void *)&rtw_modldrv, NULL
177 177 };
178 178
179 179 static uint32_t rtw_qlen[RTW_NTXPRI] = {
180 180 RTW_TXQLENLO,
181 181 RTW_TXQLENMD,
182 182 RTW_TXQLENHI,
183 183 RTW_TXQLENBCN
184 184 };
185 185
186 186 uint32_t rtw_dbg_flags = 0;
187 187 /*
188 188 * RTW_DEBUG_ATTACH | RTW_DEBUG_TUNE |
189 189 * RTW_DEBUG_ACCESS | RTW_DEBUG_INIT | RTW_DEBUG_PKTFILT |
190 190 * RTW_DEBUG_RECV | RTW_DEBUG_XMIT | RTW_DEBUG_80211 | RTW_DEBUG_INTR |
191 191 * RTW_DEBUG_PKTDUMP;
192 192 */
193 193
194 194 /*
195 195 * Supported rates for 802.11b modes (in 500Kbps unit).
196 196 */
197 197 static const struct ieee80211_rateset rtw_rateset_11b =
198 198 { 4, { 2, 4, 11, 22 } };
199 199
200 200 int
201 201 _info(struct modinfo *modinfop)
202 202 {
203 203 return (mod_info(&modlinkage, modinfop));
204 204 }
205 205
206 206 int
207 207 _init(void)
208 208 {
209 209 int status;
210 210
211 211 status = ddi_soft_state_init(&rtw_soft_state_p,
212 212 sizeof (rtw_softc_t), 1);
213 213 if (status != 0)
214 214 return (status);
215 215
216 216 mac_init_ops(&rtw_dev_ops, "rtw");
217 217 status = mod_install(&modlinkage);
218 218 if (status != 0) {
219 219 mac_fini_ops(&rtw_dev_ops);
220 220 ddi_soft_state_fini(&rtw_soft_state_p);
221 221 }
222 222 return (status);
223 223 }
224 224
225 225 int
226 226 _fini(void)
227 227 {
228 228 int status;
229 229
230 230 status = mod_remove(&modlinkage);
231 231 if (status == 0) {
232 232 mac_fini_ops(&rtw_dev_ops);
233 233 ddi_soft_state_fini(&rtw_soft_state_p);
234 234 }
235 235 return (status);
236 236 }
237 237
238 238 void
239 239 rtw_dbg(uint32_t dbg_flags, const int8_t *fmt, ...)
240 240 {
241 241 va_list args;
242 242
243 243 if (dbg_flags & rtw_dbg_flags) {
244 244 va_start(args, fmt);
245 245 vcmn_err(CE_CONT, fmt, args);
246 246 va_end(args);
247 247 }
248 248 }
249 249
250 250 #ifdef DEBUG
251 251 static void
252 252 rtw_print_regs(struct rtw_regs *regs, const char *dvname, const char *where)
253 253 {
254 254 #define PRINTREG32(sc, reg) \
255 255 RTW_DPRINTF(RTW_DEBUG_REGDUMP, \
256 256 "%s: reg[ " #reg " / %03x ] = %08x\n", \
257 257 dvname, reg, RTW_READ(regs, reg))
258 258
259 259 #define PRINTREG16(sc, reg) \
260 260 RTW_DPRINTF(RTW_DEBUG_REGDUMP, \
261 261 "%s: reg[ " #reg " / %03x ] = %04x\n", \
262 262 dvname, reg, RTW_READ16(regs, reg))
263 263
264 264 #define PRINTREG8(sc, reg) \
265 265 RTW_DPRINTF(RTW_DEBUG_REGDUMP, \
266 266 "%s: reg[ " #reg " / %03x ] = %02x\n", \
267 267 dvname, reg, RTW_READ8(regs, reg))
268 268
269 269 RTW_DPRINTF(RTW_DEBUG_REGDUMP, "%s: %s\n", dvname, where);
270 270
271 271 PRINTREG32(regs, RTW_IDR0);
272 272 PRINTREG32(regs, RTW_IDR1);
273 273 PRINTREG32(regs, RTW_MAR0);
274 274 PRINTREG32(regs, RTW_MAR1);
275 275 PRINTREG32(regs, RTW_TSFTRL);
276 276 PRINTREG32(regs, RTW_TSFTRH);
277 277 PRINTREG32(regs, RTW_TLPDA);
278 278 PRINTREG32(regs, RTW_TNPDA);
279 279 PRINTREG32(regs, RTW_THPDA);
280 280 PRINTREG32(regs, RTW_TCR);
281 281 PRINTREG32(regs, RTW_RCR);
282 282 PRINTREG32(regs, RTW_TINT);
283 283 PRINTREG32(regs, RTW_TBDA);
284 284 PRINTREG32(regs, RTW_ANAPARM);
285 285 PRINTREG32(regs, RTW_BB);
286 286 PRINTREG32(regs, RTW_PHYCFG);
287 287 PRINTREG32(regs, RTW_WAKEUP0L);
288 288 PRINTREG32(regs, RTW_WAKEUP0H);
289 289 PRINTREG32(regs, RTW_WAKEUP1L);
290 290 PRINTREG32(regs, RTW_WAKEUP1H);
291 291 PRINTREG32(regs, RTW_WAKEUP2LL);
292 292 PRINTREG32(regs, RTW_WAKEUP2LH);
293 293 PRINTREG32(regs, RTW_WAKEUP2HL);
294 294 PRINTREG32(regs, RTW_WAKEUP2HH);
295 295 PRINTREG32(regs, RTW_WAKEUP3LL);
296 296 PRINTREG32(regs, RTW_WAKEUP3LH);
297 297 PRINTREG32(regs, RTW_WAKEUP3HL);
298 298 PRINTREG32(regs, RTW_WAKEUP3HH);
299 299 PRINTREG32(regs, RTW_WAKEUP4LL);
300 300 PRINTREG32(regs, RTW_WAKEUP4LH);
301 301 PRINTREG32(regs, RTW_WAKEUP4HL);
302 302 PRINTREG32(regs, RTW_WAKEUP4HH);
303 303 PRINTREG32(regs, RTW_DK0);
304 304 PRINTREG32(regs, RTW_DK1);
305 305 PRINTREG32(regs, RTW_DK2);
306 306 PRINTREG32(regs, RTW_DK3);
307 307 PRINTREG32(regs, RTW_RETRYCTR);
308 308 PRINTREG32(regs, RTW_RDSAR);
309 309 PRINTREG32(regs, RTW_FER);
310 310 PRINTREG32(regs, RTW_FEMR);
311 311 PRINTREG32(regs, RTW_FPSR);
312 312 PRINTREG32(regs, RTW_FFER);
313 313
314 314 /* 16-bit registers */
315 315 PRINTREG16(regs, RTW_BRSR);
316 316 PRINTREG16(regs, RTW_IMR);
317 317 PRINTREG16(regs, RTW_ISR);
318 318 PRINTREG16(regs, RTW_BCNITV);
319 319 PRINTREG16(regs, RTW_ATIMWND);
320 320 PRINTREG16(regs, RTW_BINTRITV);
321 321 PRINTREG16(regs, RTW_ATIMTRITV);
322 322 PRINTREG16(regs, RTW_CRC16ERR);
323 323 PRINTREG16(regs, RTW_CRC0);
324 324 PRINTREG16(regs, RTW_CRC1);
325 325 PRINTREG16(regs, RTW_CRC2);
326 326 PRINTREG16(regs, RTW_CRC3);
327 327 PRINTREG16(regs, RTW_CRC4);
328 328 PRINTREG16(regs, RTW_CWR);
329 329
330 330 /* 8-bit registers */
331 331 PRINTREG8(regs, RTW_CR);
332 332 PRINTREG8(regs, RTW_9346CR);
333 333 PRINTREG8(regs, RTW_CONFIG0);
334 334 PRINTREG8(regs, RTW_CONFIG1);
335 335 PRINTREG8(regs, RTW_CONFIG2);
336 336 PRINTREG8(regs, RTW_MSR);
337 337 PRINTREG8(regs, RTW_CONFIG3);
338 338 PRINTREG8(regs, RTW_CONFIG4);
339 339 PRINTREG8(regs, RTW_TESTR);
340 340 PRINTREG8(regs, RTW_PSR);
341 341 PRINTREG8(regs, RTW_SCR);
342 342 PRINTREG8(regs, RTW_PHYDELAY);
343 343 PRINTREG8(regs, RTW_CRCOUNT);
344 344 PRINTREG8(regs, RTW_PHYADDR);
345 345 PRINTREG8(regs, RTW_PHYDATAW);
346 346 PRINTREG8(regs, RTW_PHYDATAR);
347 347 PRINTREG8(regs, RTW_CONFIG5);
348 348 PRINTREG8(regs, RTW_TPPOLL);
349 349
350 350 PRINTREG16(regs, RTW_BSSID16);
351 351 PRINTREG32(regs, RTW_BSSID32);
352 352 #undef PRINTREG32
353 353 #undef PRINTREG16
354 354 #undef PRINTREG8
355 355 }
356 356
357 357 #endif /* DEBUG */
358 358 static const char *
359 359 rtw_access_string(enum rtw_access access)
360 360 {
361 361 switch (access) {
362 362 case RTW_ACCESS_NONE:
363 363 return ("none");
364 364 case RTW_ACCESS_CONFIG:
365 365 return ("config");
366 366 case RTW_ACCESS_ANAPARM:
367 367 return ("anaparm");
368 368 default:
369 369 return ("unknown");
370 370 }
371 371 }
372 372
373 373 /*
374 374 * Enable registers, switch register banks.
375 375 */
376 376 void
377 377 rtw_config0123_enable(struct rtw_regs *regs, int enable)
378 378 {
379 379 uint8_t ecr;
380 380 ecr = RTW_READ8(regs, RTW_9346CR);
381 381 ecr &= ~(RTW_9346CR_EEM_MASK | RTW_9346CR_EECS | RTW_9346CR_EESK);
382 382 if (enable)
383 383 ecr |= RTW_9346CR_EEM_CONFIG;
384 384 else {
385 385 RTW_WBW(regs, RTW_9346CR, MAX(RTW_CONFIG0, RTW_CONFIG3));
386 386 ecr |= RTW_9346CR_EEM_NORMAL;
387 387 }
388 388 RTW_WRITE8(regs, RTW_9346CR, ecr);
389 389 RTW_SYNC(regs, RTW_9346CR, RTW_9346CR);
390 390 }
391 391
392 392 /*
393 393 * requires rtw_config0123_enable(, 1)
394 394 */
395 395 void
396 396 rtw_anaparm_enable(struct rtw_regs *regs, int enable)
397 397 {
398 398 uint8_t cfg3;
399 399
400 400 cfg3 = RTW_READ8(regs, RTW_CONFIG3);
401 401 cfg3 |= RTW_CONFIG3_CLKRUNEN;
402 402 if (enable)
403 403 cfg3 |= RTW_CONFIG3_PARMEN;
404 404 else
405 405 cfg3 &= ~RTW_CONFIG3_PARMEN;
406 406 RTW_WRITE8(regs, RTW_CONFIG3, cfg3);
407 407 RTW_SYNC(regs, RTW_CONFIG3, RTW_CONFIG3);
408 408 }
409 409
410 410 /*
411 411 * requires rtw_anaparm_enable(, 1)
412 412 */
413 413 void
414 414 rtw_txdac_enable(rtw_softc_t *rsc, int enable)
415 415 {
416 416 uint32_t anaparm;
417 417 struct rtw_regs *regs = &rsc->sc_regs;
418 418
419 419 anaparm = RTW_READ(regs, RTW_ANAPARM);
420 420 if (enable)
421 421 anaparm &= ~RTW_ANAPARM_TXDACOFF;
422 422 else
423 423 anaparm |= RTW_ANAPARM_TXDACOFF;
424 424 RTW_WRITE(regs, RTW_ANAPARM, anaparm);
425 425 RTW_SYNC(regs, RTW_ANAPARM, RTW_ANAPARM);
426 426 }
427 427
428 428 static void
429 429 rtw_set_access1(struct rtw_regs *regs, enum rtw_access naccess)
430 430 {
431 431 ASSERT(naccess >= RTW_ACCESS_NONE && naccess <= RTW_ACCESS_ANAPARM);
432 432 ASSERT(regs->r_access >= RTW_ACCESS_NONE &&
433 433 regs->r_access <= RTW_ACCESS_ANAPARM);
434 434
435 435 if (naccess == regs->r_access)
436 436 return;
437 437
438 438 switch (naccess) {
439 439 case RTW_ACCESS_NONE:
440 440 switch (regs->r_access) {
441 441 case RTW_ACCESS_ANAPARM:
442 442 rtw_anaparm_enable(regs, 0);
443 443 /*FALLTHROUGH*/
444 444 case RTW_ACCESS_CONFIG:
445 445 rtw_config0123_enable(regs, 0);
446 446 /*FALLTHROUGH*/
447 447 case RTW_ACCESS_NONE:
448 448 break;
449 449 }
450 450 break;
451 451 case RTW_ACCESS_CONFIG:
452 452 switch (regs->r_access) {
453 453 case RTW_ACCESS_NONE:
454 454 rtw_config0123_enable(regs, 1);
455 455 /*FALLTHROUGH*/
456 456 case RTW_ACCESS_CONFIG:
457 457 break;
458 458 case RTW_ACCESS_ANAPARM:
459 459 rtw_anaparm_enable(regs, 0);
460 460 break;
461 461 }
462 462 break;
463 463 case RTW_ACCESS_ANAPARM:
464 464 switch (regs->r_access) {
465 465 case RTW_ACCESS_NONE:
466 466 rtw_config0123_enable(regs, 1);
467 467 /*FALLTHROUGH*/
468 468 case RTW_ACCESS_CONFIG:
469 469 rtw_anaparm_enable(regs, 1);
470 470 /*FALLTHROUGH*/
471 471 case RTW_ACCESS_ANAPARM:
472 472 break;
473 473 }
474 474 break;
475 475 }
476 476 }
477 477
478 478 void
479 479 rtw_set_access(struct rtw_regs *regs, enum rtw_access access)
480 480 {
481 481 rtw_set_access1(regs, access);
482 482 RTW_DPRINTF(RTW_DEBUG_ACCESS,
483 483 "%s: access %s -> %s\n", __func__,
484 484 rtw_access_string(regs->r_access),
485 485 rtw_access_string(access));
486 486 regs->r_access = access;
487 487 }
488 488
489 489
490 490 void
491 491 rtw_continuous_tx_enable(rtw_softc_t *rsc, int enable)
492 492 {
493 493 struct rtw_regs *regs = &rsc->sc_regs;
494 494
495 495 uint32_t tcr;
496 496 tcr = RTW_READ(regs, RTW_TCR);
497 497 tcr &= ~RTW_TCR_LBK_MASK;
498 498 if (enable)
499 499 tcr |= RTW_TCR_LBK_CONT;
500 500 else
501 501 tcr |= RTW_TCR_LBK_NORMAL;
502 502 RTW_WRITE(regs, RTW_TCR, tcr);
503 503 RTW_SYNC(regs, RTW_TCR, RTW_TCR);
504 504 rtw_set_access(regs, RTW_ACCESS_ANAPARM);
505 505 rtw_txdac_enable(rsc, !enable);
506 506 rtw_set_access(regs, RTW_ACCESS_ANAPARM);
507 507 rtw_set_access(regs, RTW_ACCESS_NONE);
508 508 }
509 509
510 510 static int
511 511 rtw_chip_reset1(struct rtw_regs *regs, const char *dvname)
512 512 {
513 513 uint8_t cr;
514 514 int i;
515 515
516 516 RTW_WRITE8(regs, RTW_CR, RTW_CR_RST);
517 517
518 518 RTW_WBR(regs, RTW_CR, RTW_CR);
519 519
520 520 for (i = 0; i < 1000; i++) {
521 521 cr = RTW_READ8(regs, RTW_CR);
522 522 if ((cr & RTW_CR_RST) == 0) {
523 523 RTW_DPRINTF(RTW_DEBUG_RESET,
524 524 "%s: reset in %dus\n", dvname, i);
525 525 return (0);
526 526 }
527 527 RTW_RBR(regs, RTW_CR, RTW_CR);
528 528 DELAY(10); /* 10us */
529 529 }
530 530
531 531 cmn_err(CE_WARN, "%s: reset failed\n", dvname);
532 532 return (ETIMEDOUT);
533 533 }
534 534
535 535 static int
536 536 rtw_chip_reset(struct rtw_regs *regs, const char *dvname)
537 537 {
538 538 RTW_WBW(regs, RTW_CR, RTW_TCR);
539 539 return (rtw_chip_reset1(regs, dvname));
540 540 }
541 541
542 542 static void
543 543 rtw_disable_interrupts(struct rtw_regs *regs)
544 544 {
545 545 RTW_WRITE16(regs, RTW_IMR, 0);
546 546 RTW_WRITE16(regs, RTW_ISR, 0xffff);
547 547 (void) RTW_READ16(regs, RTW_IMR);
548 548 }
549 549
550 550 static void
551 551 rtw_enable_interrupts(rtw_softc_t *rsc)
552 552 {
553 553 struct rtw_regs *regs = &rsc->sc_regs;
554 554
555 555 rsc->sc_inten = RTW_INTR_RX | RTW_INTR_TX | RTW_INTR_IOERROR;
556 556
557 557 RTW_WRITE16(regs, RTW_IMR, rsc->sc_inten);
558 558 RTW_WRITE16(regs, RTW_ISR, 0xffff);
559 559
560 560 /* XXX necessary? */
561 561 if (rsc->sc_intr_ack != NULL)
562 562 (*rsc->sc_intr_ack)(regs);
563 563 }
564 564
565 565 static int
566 566 rtw_recall_eeprom(struct rtw_regs *regs, const char *dvname)
567 567 {
568 568 int i;
569 569 uint8_t ecr;
570 570
571 571 ecr = RTW_READ8(regs, RTW_9346CR);
572 572 ecr = (ecr & ~RTW_9346CR_EEM_MASK) | RTW_9346CR_EEM_AUTOLOAD;
573 573 RTW_WRITE8(regs, RTW_9346CR, ecr);
574 574
575 575 RTW_WBR(regs, RTW_9346CR, RTW_9346CR);
576 576
577 577 /* wait 25ms for completion */
578 578 for (i = 0; i < 250; i++) {
579 579 ecr = RTW_READ8(regs, RTW_9346CR);
580 580 if ((ecr & RTW_9346CR_EEM_MASK) == RTW_9346CR_EEM_NORMAL) {
581 581 RTW_DPRINTF(RTW_DEBUG_RESET,
582 582 "%s: recall EEPROM in %dus\n", dvname, i * 100);
583 583 return (0);
584 584 }
585 585 RTW_RBR(regs, RTW_9346CR, RTW_9346CR);
586 586 DELAY(100);
587 587 }
588 588 cmn_err(CE_WARN, "%s: recall EEPROM failed\n", dvname);
589 589 return (ETIMEDOUT);
590 590 }
591 591
592 592 static int
593 593 rtw_reset(rtw_softc_t *rsc)
594 594 {
595 595 int rc;
596 596
597 597 rc = rtw_chip_reset(&rsc->sc_regs, "rtw");
598 598 if (rc != 0)
599 599 return (rc);
600 600
601 601 (void) rtw_recall_eeprom(&rsc->sc_regs, "rtw");
602 602 return (0);
603 603 }
604 604
605 605 void
606 606 rtw_set_mode(struct rtw_regs *regs, int mode)
607 607 {
608 608 uint8_t command;
609 609 command = RTW_READ8(regs, RTW_9346CR);
610 610 command = command &~ RTW_EPROM_CMD_OPERATING_MODE_MASK;
611 611 command = command | (mode<<RTW_EPROM_CMD_OPERATING_MODE_SHIFT);
612 612 command = command &~ (1<<RTW_EPROM_CS_SHIFT);
613 613 command = command &~ (1<<RTW_EPROM_CK_SHIFT);
614 614 RTW_WRITE8(regs, RTW_9346CR, command);
615 615 }
616 616
617 617 void
618 618 rtw_dma_start(struct rtw_regs *regs, int priority)
619 619 {
620 620 uint8_t check = 0;
621 621
622 622 check = RTW_READ8(regs, RTW_TPPOLL);
623 623 switch (priority) {
624 624 case (0):
625 625 RTW_WRITE8(regs, RTW_TPPOLL,
626 626 (1<< RTW_TX_DMA_POLLING_LOWPRIORITY_SHIFT) | check);
627 627 break;
628 628 case (1):
629 629 RTW_WRITE8(regs, RTW_TPPOLL,
630 630 (1<< RTW_TX_DMA_POLLING_NORMPRIORITY_SHIFT) | check);
631 631 break;
632 632 case (2):
633 633 RTW_WRITE8(regs, RTW_TPPOLL,
634 634 (1<< RTW_TX_DMA_POLLING_HIPRIORITY_SHIFT) | check);
635 635 break;
636 636 }
637 637 (void) RTW_READ8(regs, RTW_TPPOLL);
638 638 }
639 639
640 640 void
641 641 rtw_beacon_tx_disable(struct rtw_regs *regs)
642 642 {
643 643 uint8_t mask = 0;
644 644 mask |= (1 << RTW_TX_DMA_STOP_BEACON_SHIFT);
645 645 rtw_set_mode(regs, RTW_EPROM_CMD_CONFIG);
646 646 RTW_WRITE8(regs, RTW_TPPOLL, mask);
647 647 rtw_set_mode(regs, RTW_EPROM_CMD_NORMAL);
648 648 }
649 649
650 650 static void
651 651 rtw_io_enable(rtw_softc_t *rsc, uint8_t flags, int enable);
652 652
653 653 void
654 654 rtw_rtx_disable(rtw_softc_t *rsc)
655 655 {
656 656 struct rtw_regs *regs = &rsc->sc_regs;
657 657
658 658 rtw_io_enable(rsc, RTW_CR_RE|RTW_CR_TE, 0);
659 659 (void) RTW_READ8(regs, RTW_CR);
660 660 }
661 661
662 662 static void
663 663 rtw_srom_free(struct rtw_srom *sr)
664 664 {
665 665 if (sr->sr_content == NULL)
666 666 return;
667 667 kmem_free(sr->sr_content, sr->sr_size);
668 668 sr->sr_size = 0;
669 669 sr->sr_content = NULL;
670 670 }
671 671
672 672 /*ARGSUSED*/
673 673 static void
674 674 rtw_srom_defaults(struct rtw_srom *sr, uint32_t *flags, uint8_t *cs_threshold,
675 675 enum rtw_rfchipid *rfchipid, uint32_t *rcr)
676 676 {
677 677 *flags |= (RTW_F_DIGPHY|RTW_F_ANTDIV);
678 678 *cs_threshold = RTW_SR_ENERGYDETTHR_DEFAULT;
679 679 *rcr |= RTW_RCR_ENCS1;
680 680 *rfchipid = RTW_RFCHIPID_PHILIPS;
681 681 }
682 682
683 683 static int
684 684 rtw_srom_parse(struct rtw_srom *sr, uint32_t *flags, uint8_t *cs_threshold,
685 685 enum rtw_rfchipid *rfchipid, uint32_t *rcr, enum rtw_locale *locale,
686 686 const char *dvname)
687 687 {
688 688 int i;
689 689 const char *rfname, *paname;
690 690 char scratch[sizeof ("unknown 0xXX")];
691 691 uint16_t version;
692 692 uint8_t mac[IEEE80211_ADDR_LEN];
693 693
694 694 *flags &= ~(RTW_F_DIGPHY|RTW_F_DFLANTB|RTW_F_ANTDIV);
695 695 *rcr &= ~(RTW_RCR_ENCS1 | RTW_RCR_ENCS2);
696 696
697 697 version = RTW_SR_GET16(sr, RTW_SR_VERSION);
698 698 RTW_DPRINTF(RTW_DEBUG_IOSTATE, "%s: SROM version %d.%d", dvname,
699 699 version >> 8, version & 0xff);
700 700
701 701 if (version <= 0x0101) {
702 702 cmn_err(CE_NOTE, " is not understood, limping along "
703 703 "with defaults\n");
704 704 rtw_srom_defaults(sr, flags, cs_threshold, rfchipid, rcr);
705 705 return (0);
706 706 }
707 707
708 708 for (i = 0; i < IEEE80211_ADDR_LEN; i++)
709 709 mac[i] = RTW_SR_GET(sr, RTW_SR_MAC + i);
710 710
711 711 RTW_DPRINTF(RTW_DEBUG_ATTACH,
712 712 "%s: EEPROM MAC %s\n", dvname, mac);
713 713
714 714 *cs_threshold = RTW_SR_GET(sr, RTW_SR_ENERGYDETTHR);
715 715
716 716 if ((RTW_SR_GET(sr, RTW_SR_CONFIG2) & RTW_CONFIG2_ANT) != 0)
717 717 *flags |= RTW_F_ANTDIV;
718 718
719 719 /*
720 720 * Note well: the sense of the RTW_SR_RFPARM_DIGPHY bit seems
721 721 * to be reversed.
722 722 */
723 723 if ((RTW_SR_GET(sr, RTW_SR_RFPARM) & RTW_SR_RFPARM_DIGPHY) == 0)
724 724 *flags |= RTW_F_DIGPHY;
725 725 if ((RTW_SR_GET(sr, RTW_SR_RFPARM) & RTW_SR_RFPARM_DFLANTB) != 0)
726 726 *flags |= RTW_F_DFLANTB;
727 727
728 728 *rcr |= LSHIFT(MASK_AND_RSHIFT(RTW_SR_GET(sr, RTW_SR_RFPARM),
729 729 RTW_SR_RFPARM_CS_MASK), RTW_RCR_ENCS1);
730 730
731 731 *rfchipid = RTW_SR_GET(sr, RTW_SR_RFCHIPID);
732 732 switch (*rfchipid) {
733 733 case RTW_RFCHIPID_GCT: /* this combo seen in the wild */
734 734 rfname = "GCT GRF5101";
735 735 paname = "Winspring WS9901";
736 736 break;
737 737 case RTW_RFCHIPID_MAXIM:
738 738 rfname = "Maxim MAX2820"; /* guess */
739 739 paname = "Maxim MAX2422"; /* guess */
740 740 break;
741 741 case RTW_RFCHIPID_INTERSIL:
742 742 rfname = "Intersil HFA3873"; /* guess */
743 743 paname = "Intersil <unknown>";
744 744 break;
745 745 case RTW_RFCHIPID_PHILIPS: /* this combo seen in the wild */
746 746 rfname = "Philips SA2400A";
747 747 paname = "Philips SA2411";
748 748 break;
749 749 case RTW_RFCHIPID_RFMD:
750 750 /*
751 751 * this is the same front-end as an atw(4)!
752 752 */
753 753 rfname = "RFMD RF2948B, " /* mentioned in Realtek docs */
754 754 "LNA: RFMD RF2494, " /* mentioned in Realtek docs */
755 755 "SYN: Silicon Labs Si4126";
756 756 paname = "RFMD RF2189"; /* mentioned in Realtek docs */
757 757 break;
758 758 case RTW_RFCHIPID_RESERVED:
759 759 rfname = paname = "reserved";
760 760 break;
761 761 default:
762 762 (void) snprintf(scratch, sizeof (scratch),
763 763 "unknown 0x%02x", *rfchipid);
764 764 rfname = paname = scratch;
765 765 }
766 766 RTW_DPRINTF(RTW_DEBUG_PHY, "%s: RF: %s, PA: %s\n",
767 767 dvname, rfname, paname);
768 768
769 769 switch (RTW_SR_GET(sr, RTW_SR_CONFIG0) & RTW_CONFIG0_GL_MASK) {
770 770 case RTW_CONFIG0_GL_USA:
771 771 *locale = RTW_LOCALE_USA;
772 772 break;
773 773 case RTW_CONFIG0_GL_EUROPE:
774 774 *locale = RTW_LOCALE_EUROPE;
775 775 break;
776 776 case RTW_CONFIG0_GL_JAPAN:
777 777 *locale = RTW_LOCALE_JAPAN;
778 778 break;
779 779 default:
780 780 *locale = RTW_LOCALE_UNKNOWN;
781 781 break;
782 782 }
783 783 return (0);
784 784 }
785 785
786 786 /*
787 787 * Returns -1 on failure.
788 788 */
789 789 static int
790 790 rtw_srom_read(struct rtw_regs *regs, uint32_t flags, struct rtw_srom *sr,
791 791 const char *dvname)
792 792 {
793 793 int rc;
794 794 struct seeprom_descriptor sd;
795 795 uint8_t ecr;
796 796
797 797 (void) memset(&sd, 0, sizeof (sd));
798 798
799 799 ecr = RTW_READ8(regs, RTW_9346CR);
800 800
801 801 if ((flags & RTW_F_9356SROM) != 0) {
802 802 RTW_DPRINTF(RTW_DEBUG_ATTACH, "%s: 93c56 SROM\n", dvname);
803 803 sr->sr_size = 256;
804 804 sd.sd_chip = C56_66;
805 805 } else {
806 806 RTW_DPRINTF(RTW_DEBUG_ATTACH, "%s: 93c46 SROM\n", dvname);
807 807 sr->sr_size = 128;
808 808 sd.sd_chip = C46;
↓ open down ↓ |
808 lines elided |
↑ open up ↑ |
809 809 }
810 810
811 811 ecr &= ~(RTW_9346CR_EEDI | RTW_9346CR_EEDO | RTW_9346CR_EESK |
812 812 RTW_9346CR_EEM_MASK | RTW_9346CR_EECS);
813 813 ecr |= RTW_9346CR_EEM_PROGRAM;
814 814
815 815 RTW_WRITE8(regs, RTW_9346CR, ecr);
816 816
817 817 sr->sr_content = kmem_zalloc(sr->sr_size, KM_SLEEP);
818 818
819 - if (sr->sr_content == NULL) {
820 - cmn_err(CE_WARN, "%s: unable to allocate SROM buffer\n",
821 - dvname);
822 - return (ENOMEM);
823 - }
824 -
825 819 (void) memset(sr->sr_content, 0, sr->sr_size);
826 820
827 821 /*
828 822 * RTL8180 has a single 8-bit register for controlling the
829 823 * 93cx6 SROM. There is no "ready" bit. The RTL8180
830 824 * input/output sense is the reverse of read_seeprom's.
831 825 */
832 826 sd.sd_handle = regs->r_handle;
833 827 sd.sd_base = regs->r_base;
834 828 sd.sd_regsize = 1;
835 829 sd.sd_control_offset = RTW_9346CR;
836 830 sd.sd_status_offset = RTW_9346CR;
837 831 sd.sd_dataout_offset = RTW_9346CR;
838 832 sd.sd_CK = RTW_9346CR_EESK;
839 833 sd.sd_CS = RTW_9346CR_EECS;
840 834 sd.sd_DI = RTW_9346CR_EEDO;
841 835 sd.sd_DO = RTW_9346CR_EEDI;
842 836 /*
843 837 * make read_seeprom enter EEPROM read/write mode
844 838 */
845 839 sd.sd_MS = ecr;
846 840 sd.sd_RDY = 0;
847 841
848 842 /*
849 843 * TBD bus barriers
850 844 */
851 845 if (!read_seeprom(&sd, sr->sr_content, 0, sr->sr_size/2)) {
852 846 cmn_err(CE_WARN, "%s: could not read SROM\n", dvname);
853 847 kmem_free(sr->sr_content, sr->sr_size);
854 848 sr->sr_content = NULL;
855 849 return (-1); /* XXX */
856 850 }
857 851
858 852 /*
859 853 * end EEPROM read/write mode
860 854 */
861 855 RTW_WRITE8(regs, RTW_9346CR,
862 856 (ecr & ~RTW_9346CR_EEM_MASK) | RTW_9346CR_EEM_NORMAL);
863 857 RTW_WBRW(regs, RTW_9346CR, RTW_9346CR);
864 858
865 859 if ((rc = rtw_recall_eeprom(regs, dvname)) != 0)
866 860 return (rc);
867 861
868 862 #ifdef SROM_DEBUG
869 863 {
870 864 int i;
871 865 RTW_DPRINTF(RTW_DEBUG_ATTACH,
872 866 "\n%s: serial ROM:\n\t", dvname);
873 867 for (i = 0; i < sr->sr_size/2; i++) {
874 868 RTW_DPRINTF(RTW_DEBUG_ATTACH,
875 869 "offset-0x%x: %04x", 2*i, sr->sr_content[i]);
876 870 }
877 871 }
878 872 #endif /* DEBUG */
879 873 return (0);
880 874 }
881 875
882 876 static void
883 877 rtw_set_rfprog(struct rtw_regs *regs, enum rtw_rfchipid rfchipid,
884 878 const char *dvname)
885 879 {
886 880 uint8_t cfg4;
887 881 const char *method;
888 882
889 883 cfg4 = RTW_READ8(regs, RTW_CONFIG4) & ~RTW_CONFIG4_RFTYPE_MASK;
890 884
891 885 switch (rfchipid) {
892 886 default:
893 887 cfg4 |= LSHIFT(0, RTW_CONFIG4_RFTYPE_MASK);
894 888 method = "fallback";
895 889 break;
896 890 case RTW_RFCHIPID_INTERSIL:
897 891 cfg4 |= RTW_CONFIG4_RFTYPE_INTERSIL;
898 892 method = "Intersil";
899 893 break;
900 894 case RTW_RFCHIPID_PHILIPS:
901 895 cfg4 |= RTW_CONFIG4_RFTYPE_PHILIPS;
902 896 method = "Philips";
903 897 break;
904 898 case RTW_RFCHIPID_GCT: /* XXX a guess */
905 899 case RTW_RFCHIPID_RFMD:
906 900 cfg4 |= RTW_CONFIG4_RFTYPE_RFMD;
907 901 method = "RFMD";
908 902 break;
909 903 }
910 904
911 905 RTW_WRITE8(regs, RTW_CONFIG4, cfg4);
912 906
913 907 RTW_WBR(regs, RTW_CONFIG4, RTW_CONFIG4);
914 908
915 909 RTW_DPRINTF(RTW_DEBUG_INIT,
916 910 "%s: %s RF programming method, %02x\n", dvname, method,
917 911 RTW_READ8(regs, RTW_CONFIG4));
918 912 }
919 913
920 914 static void
921 915 rtw_init_channels(enum rtw_locale locale,
922 916 struct ieee80211_channel (*chans)[IEEE80211_CHAN_MAX+1],
923 917 const char *dvname)
924 918 {
925 919 int i;
926 920 const char *name = NULL;
927 921 #define ADD_CHANNEL(_chans, _chan) { \
928 922 (*_chans)[_chan].ich_flags = IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK;\
929 923 (*_chans)[_chan].ich_freq = \
930 924 ieee80211_ieee2mhz(_chan, (*_chans)[_chan].ich_flags);\
931 925 }
932 926
933 927 switch (locale) {
934 928 case RTW_LOCALE_USA: /* 1-11 */
935 929 name = "USA";
936 930 for (i = 1; i <= 11; i++)
937 931 ADD_CHANNEL(chans, i);
938 932 break;
939 933 case RTW_LOCALE_JAPAN: /* 1-14 */
940 934 name = "Japan";
941 935 ADD_CHANNEL(chans, 14);
942 936 for (i = 1; i <= 14; i++)
943 937 ADD_CHANNEL(chans, i);
944 938 break;
945 939 case RTW_LOCALE_EUROPE: /* 1-13 */
946 940 name = "Europe";
947 941 for (i = 1; i <= 13; i++)
948 942 ADD_CHANNEL(chans, i);
949 943 break;
950 944 default: /* 10-11 allowed by most countries */
951 945 name = "<unknown>";
952 946 for (i = 10; i <= 11; i++)
953 947 ADD_CHANNEL(chans, i);
954 948 break;
955 949 }
956 950 RTW_DPRINTF(RTW_DEBUG_ATTACH, "%s: Geographic Location %s\n",
957 951 dvname, name);
958 952 #undef ADD_CHANNEL
959 953 }
960 954
961 955 static void
962 956 rtw_set80211props(struct ieee80211com *ic)
963 957 {
964 958 ic->ic_phytype = IEEE80211_T_DS;
965 959 ic->ic_opmode = IEEE80211_M_STA;
966 960 ic->ic_caps = IEEE80211_C_PMGT | IEEE80211_C_IBSS |
967 961 IEEE80211_C_SHPREAMBLE;
968 962 /* IEEE80211_C_HOSTAP | IEEE80211_C_MONITOR | IEEE80211_C_WEP */
969 963
970 964 ic->ic_sup_rates[IEEE80211_MODE_11B] = rtw_rateset_11b;
971 965 }
972 966
973 967 /*ARGSUSED*/
974 968 static void
975 969 rtw_identify_country(struct rtw_regs *regs, enum rtw_locale *locale,
976 970 const char *dvname)
977 971 {
978 972 uint8_t cfg0 = RTW_READ8(regs, RTW_CONFIG0);
979 973
980 974 switch (cfg0 & RTW_CONFIG0_GL_MASK) {
981 975 case RTW_CONFIG0_GL_USA:
982 976 *locale = RTW_LOCALE_USA;
983 977 break;
984 978 case RTW_CONFIG0_GL_JAPAN:
985 979 *locale = RTW_LOCALE_JAPAN;
986 980 break;
987 981 case RTW_CONFIG0_GL_EUROPE:
988 982 *locale = RTW_LOCALE_EUROPE;
989 983 break;
990 984 default:
991 985 *locale = RTW_LOCALE_UNKNOWN;
992 986 break;
993 987 }
994 988 }
995 989
996 990 static int
997 991 rtw_identify_sta(struct rtw_regs *regs, uint8_t *addr,
998 992 const char *dvname)
999 993 {
1000 994 uint32_t idr0 = RTW_READ(regs, RTW_IDR0),
1001 995 idr1 = RTW_READ(regs, RTW_IDR1);
1002 996
1003 997 *addr = MASK_AND_RSHIFT(idr0, BITS(0, 7));
1004 998 *(addr + 1) = MASK_AND_RSHIFT(idr0, BITS(8, 15));
1005 999 *(addr + 2) = MASK_AND_RSHIFT(idr0, BITS(16, 23));
1006 1000 *(addr + 3) = MASK_AND_RSHIFT(idr0, BITS(24, 31));
1007 1001
1008 1002 *(addr + 4) = MASK_AND_RSHIFT(idr1, BITS(0, 7));
1009 1003 *(addr + 5) = MASK_AND_RSHIFT(idr1, BITS(8, 15));
1010 1004
1011 1005 RTW_DPRINTF(RTW_DEBUG_ATTACH,
1012 1006 "%s: 802.11mac address %x:%x:%x:%x:%x:%x\n", dvname,
1013 1007 *addr, *(addr+1), *(addr+2), *(addr+3), *(addr+4), *(addr+5));
1014 1008
1015 1009 return (0);
1016 1010 }
1017 1011
1018 1012 static uint8_t
1019 1013 rtw_chan2txpower(struct rtw_srom *sr, struct ieee80211com *ic,
1020 1014 struct ieee80211_channel *chan)
1021 1015 {
1022 1016 uint32_t idx = RTW_SR_TXPOWER1 + ieee80211_chan2ieee(ic, chan) - 1;
1023 1017 return (RTW_SR_GET(sr, idx));
1024 1018 }
1025 1019
1026 1020 static void
1027 1021 rtw_rxdesc_init(rtw_softc_t *rsc, struct rtw_rxbuf *rbf, int idx, int is_last)
1028 1022 {
1029 1023 uint32_t ctl = 0;
1030 1024 uint8_t *buf = (uint8_t *)rbf->bf_dma.mem_va;
1031 1025
1032 1026 ASSERT(rbf != NULL);
1033 1027 rbf->rxdesc->rd_buf = (rbf->bf_dma.cookie.dmac_address);
1034 1028 bzero(buf, rbf->bf_dma.alength);
1035 1029 RTW_DMA_SYNC(rbf->bf_dma, DDI_DMA_SYNC_FORDEV);
1036 1030
1037 1031 ctl = (rbf->bf_dma.alength & 0xfff) | RTW_RXCTL_OWN;
1038 1032
1039 1033 if (is_last)
1040 1034 ctl |= RTW_RXCTL_EOR;
1041 1035
1042 1036 rbf->rxdesc->rd_ctl = (ctl);
1043 1037 /* sync the mbuf */
1044 1038
1045 1039 /* sync the descriptor */
1046 1040 RTW_DMA_SYNC_DESC(rsc->sc_desc_dma,
1047 1041 RTW_DESC_OFFSET(hd_rx, idx),
1048 1042 sizeof (struct rtw_rxdesc),
1049 1043 DDI_DMA_SYNC_FORDEV);
1050 1044 }
1051 1045
1052 1046 static void
1053 1047 rtw_idle(struct rtw_regs *regs)
1054 1048 {
1055 1049 int active;
1056 1050
1057 1051 /* request stop DMA; wait for packets to stop transmitting. */
1058 1052
1059 1053 RTW_WRITE8(regs, RTW_TPPOLL, RTW_TPPOLL_SALL);
1060 1054
1061 1055 for (active = 0; active < 300 &&
1062 1056 (RTW_READ8(regs, RTW_TPPOLL) & RTW_TPPOLL_ALL) != 0; active++)
1063 1057 drv_usecwait(10);
1064 1058 }
1065 1059
1066 1060 static void
1067 1061 rtw_io_enable(rtw_softc_t *rsc, uint8_t flags, int enable)
1068 1062 {
1069 1063 uint8_t cr;
1070 1064 struct rtw_regs *regs = &rsc->sc_regs;
1071 1065
1072 1066 RTW_DPRINTF(RTW_DEBUG_IOSTATE, "%s: %s 0x%02x\n", __func__,
1073 1067 enable ? "enable" : "disable", flags);
1074 1068
1075 1069 cr = RTW_READ8(regs, RTW_CR);
1076 1070
1077 1071 /* The receive engine will always start at RDSAR. */
1078 1072 if (enable && (flags & ~cr & RTW_CR_RE)) {
1079 1073 RTW_DMA_SYNC_DESC(rsc->sc_desc_dma,
1080 1074 RTW_DESC_OFFSET(hd_rx, 0),
1081 1075 sizeof (struct rtw_rxdesc),
1082 1076 DDI_DMA_SYNC_FORCPU);
1083 1077 rsc->rx_next = 0;
1084 1078 rtw_rxdesc_init(rsc, rsc->rxbuf_h, 0, 0);
1085 1079 }
1086 1080
1087 1081 if (enable)
1088 1082 cr |= flags;
1089 1083 else
1090 1084 cr &= ~flags;
1091 1085 RTW_WRITE8(regs, RTW_CR, cr);
1092 1086 (void) RTW_READ8(regs, RTW_CR);
1093 1087 }
1094 1088
1095 1089 /*
1096 1090 * Allocate an area of memory and a DMA handle for accessing it
1097 1091 */
1098 1092 static int
1099 1093 rtw_alloc_dma_mem(dev_info_t *devinfo, ddi_dma_attr_t *dma_attr,
1100 1094 size_t memsize, ddi_device_acc_attr_t *attr_p, uint_t alloc_flags,
1101 1095 uint_t bind_flags, dma_area_t *dma_p)
1102 1096 {
1103 1097 int err;
1104 1098
1105 1099 /*
1106 1100 * Allocate handle
1107 1101 */
1108 1102 err = ddi_dma_alloc_handle(devinfo, dma_attr,
1109 1103 DDI_DMA_SLEEP, NULL, &dma_p->dma_hdl);
1110 1104 if (err != DDI_SUCCESS)
1111 1105 return (DDI_FAILURE);
1112 1106
1113 1107 /*
1114 1108 * Allocate memory
1115 1109 */
1116 1110 err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p,
1117 1111 alloc_flags, DDI_DMA_SLEEP, NULL, &dma_p->mem_va,
1118 1112 &dma_p->alength, &dma_p->acc_hdl);
1119 1113 if (err != DDI_SUCCESS)
1120 1114 return (DDI_FAILURE);
1121 1115
1122 1116 /*
1123 1117 * Bind the two together
1124 1118 */
1125 1119 err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL,
1126 1120 dma_p->mem_va, dma_p->alength, bind_flags,
1127 1121 DDI_DMA_SLEEP, NULL, &dma_p->cookie, &dma_p->ncookies);
1128 1122 if ((dma_p->ncookies != 1) || (err != DDI_DMA_MAPPED))
1129 1123 return (DDI_FAILURE);
1130 1124
1131 1125 dma_p->nslots = ~0U;
1132 1126 dma_p->size = ~0U;
1133 1127 dma_p->token = ~0U;
1134 1128 dma_p->offset = 0;
1135 1129 return (DDI_SUCCESS);
1136 1130 }
1137 1131
1138 1132 /*
1139 1133 * Free one allocated area of DMAable memory
1140 1134 */
1141 1135 static void
1142 1136 rtw_free_dma_mem(dma_area_t *dma_p)
1143 1137 {
1144 1138 if (dma_p->dma_hdl != NULL) {
1145 1139 (void) ddi_dma_unbind_handle(dma_p->dma_hdl);
1146 1140 if (dma_p->acc_hdl != NULL) {
1147 1141 ddi_dma_mem_free(&dma_p->acc_hdl);
1148 1142 dma_p->acc_hdl = NULL;
1149 1143 }
1150 1144 ddi_dma_free_handle(&dma_p->dma_hdl);
1151 1145 dma_p->ncookies = 0;
1152 1146 dma_p->dma_hdl = NULL;
1153 1147 }
1154 1148 }
1155 1149
1156 1150 static void
1157 1151 rtw_dma_free(rtw_softc_t *rsc)
1158 1152 {
1159 1153 struct rtw_txbuf *txbf;
1160 1154 struct rtw_rxbuf *rxbf;
1161 1155 int i, j;
1162 1156
1163 1157 /* Free TX DMA buffer */
1164 1158 for (i = 0; i < RTW_NTXPRI; i++) {
1165 1159 txbf = list_head(&rsc->sc_txq[i].tx_free_list);
1166 1160 while (txbf != NULL) {
1167 1161 rtw_free_dma_mem(&txbf->bf_dma);
1168 1162 list_remove(&rsc->sc_txq[i].tx_free_list, txbf);
1169 1163 txbf = list_head(&rsc->sc_txq[i].tx_free_list);
1170 1164 }
1171 1165 list_destroy(&rsc->sc_txq[i].tx_free_list);
1172 1166 txbf = list_head(&rsc->sc_txq[i].tx_dirty_list);
1173 1167 while (txbf != NULL) {
1174 1168 rtw_free_dma_mem(&txbf->bf_dma);
1175 1169 list_remove(&rsc->sc_txq[i].tx_dirty_list, txbf);
1176 1170 txbf = list_head(&rsc->sc_txq[i].tx_dirty_list);
1177 1171 }
1178 1172 list_destroy(&rsc->sc_txq[i].tx_dirty_list);
1179 1173
1180 1174 if (rsc->sc_txq[i].txbuf_h != NULL) {
1181 1175 kmem_free(rsc->sc_txq[i].txbuf_h,
1182 1176 sizeof (struct rtw_txbuf) * rtw_qlen[i]);
1183 1177 rsc->sc_txq[i].txbuf_h = NULL;
1184 1178 }
1185 1179 }
1186 1180
1187 1181 /* Free RX DMA buffer */
1188 1182 rxbf = rsc->rxbuf_h;
1189 1183 for (j = 0; j < RTW_RXQLEN; j++) {
1190 1184 rtw_free_dma_mem(&rxbf->bf_dma);
1191 1185 rxbf++;
1192 1186 }
1193 1187
1194 1188 if (rsc->rxbuf_h != NULL) {
1195 1189 kmem_free(rsc->rxbuf_h,
1196 1190 sizeof (struct rtw_rxbuf) * RTW_RXQLEN);
1197 1191 rsc->rxbuf_h = NULL;
1198 1192 }
1199 1193
1200 1194 rtw_free_dma_mem(&rsc->sc_desc_dma);
1201 1195 }
1202 1196
1203 1197 static int
1204 1198 rtw_dma_init(dev_info_t *devinfo, rtw_softc_t *rsc)
1205 1199 {
1206 1200 int i, j, err;
1207 1201 size_t size;
1208 1202 uint32_t buflen;
1209 1203 struct rtw_txdesc *txds;
1210 1204 struct rtw_rxdesc *rxds;
1211 1205 struct rtw_txbuf *txbf;
1212 1206 struct rtw_rxbuf *rxbf;
1213 1207 uint32_t phybaseaddr, ptx[RTW_NTXPRI], prx;
1214 1208 caddr_t virbaseaddr, vtx[RTW_NTXPRI], vrx;
1215 1209
1216 1210 /* DMA buffer size for each TX/RX packet */
1217 1211 rsc->sc_dmabuf_size = roundup(sizeof (struct ieee80211_frame) + 0x100 +
1218 1212 IEEE80211_MTU + IEEE80211_CRC_LEN + sizeof (struct ieee80211_llc) +
1219 1213 (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
1220 1214 IEEE80211_WEP_CRCLEN), rsc->sc_cachelsz);
1221 1215 size = sizeof (struct rtw_descs);
1222 1216 err = rtw_alloc_dma_mem(devinfo, &dma_attr_desc, size,
1223 1217 &rtw_desc_accattr,
1224 1218 DDI_DMA_CONSISTENT, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1225 1219 &rsc->sc_desc_dma);
1226 1220 if (err != DDI_SUCCESS)
1227 1221 goto error;
1228 1222 phybaseaddr = rsc->sc_desc_dma.cookie.dmac_address;
1229 1223 virbaseaddr = rsc->sc_desc_dma.mem_va;
1230 1224 ptx[0] = RTW_RING_BASE(phybaseaddr, hd_txlo);
1231 1225 ptx[1] = RTW_RING_BASE(phybaseaddr, hd_txmd);
1232 1226 ptx[2] = RTW_RING_BASE(phybaseaddr, hd_txhi);
1233 1227 ptx[3] = RTW_RING_BASE(phybaseaddr, hd_bcn);
1234 1228 vtx[0] = (caddr_t)(RTW_RING_BASE(virbaseaddr, hd_txlo));
1235 1229 vtx[1] = (caddr_t)(RTW_RING_BASE(virbaseaddr, hd_txmd));
1236 1230 vtx[2] = (caddr_t)(RTW_RING_BASE(virbaseaddr, hd_txhi));
1237 1231 vtx[3] = (caddr_t)(RTW_RING_BASE(virbaseaddr, hd_bcn));
1238 1232 for (i = 0; i < RTW_NTXPRI; i++) {
1239 1233 RTW_DPRINTF(RTW_DEBUG_DMA, "p[%d]=%x, v[%d]=%x", i, ptx[i],
1240 1234 i, vtx[i]);
1241 1235 RTW_DPRINTF(RTW_DEBUG_DMA, "ring%d:", i);
1242 1236 list_create(&rsc->sc_txq[i].tx_free_list,
1243 1237 sizeof (struct rtw_txbuf),
1244 1238 offsetof(struct rtw_txbuf, bf_node));
1245 1239 list_create(&rsc->sc_txq[i].tx_dirty_list,
1246 1240 sizeof (struct rtw_txbuf),
1247 1241 offsetof(struct rtw_txbuf, bf_node));
1248 1242 /* virtual address of the first descriptor */
1249 1243 rsc->sc_txq[i].txdesc_h =
1250 1244 (struct rtw_txdesc *)(uintptr_t)vtx[i];
1251 1245
1252 1246 txds = rsc->sc_txq[i].txdesc_h;
1253 1247 /* allocate data structures to describe TX DMA buffers */
1254 1248 buflen = sizeof (struct rtw_txbuf) * rtw_qlen[i];
1255 1249 txbf = (struct rtw_txbuf *)kmem_zalloc(buflen, KM_SLEEP);
1256 1250 rsc->sc_txq[i].txbuf_h = txbf;
1257 1251 for (j = 0; j < rtw_qlen[i]; j++, txbf++, txds++) {
1258 1252 txbf->txdesc = txds;
1259 1253 txbf->bf_daddr = ptx[i] + ((uintptr_t)txds -
1260 1254 (uintptr_t)rsc->sc_txq[i].txdesc_h);
1261 1255 list_insert_tail(&rsc->sc_txq[i].tx_free_list, txbf);
1262 1256
1263 1257 /* alloc DMA memory */
1264 1258 err = rtw_alloc_dma_mem(devinfo, &dma_attr_txbuf,
1265 1259 rsc->sc_dmabuf_size,
1266 1260 &rtw_buf_accattr,
1267 1261 DDI_DMA_STREAMING,
1268 1262 DDI_DMA_WRITE | DDI_DMA_STREAMING,
1269 1263 &txbf->bf_dma);
1270 1264 if (err != DDI_SUCCESS)
1271 1265 goto error;
1272 1266 RTW_DPRINTF(RTW_DEBUG_DMA, "pbufaddr[%d]=%x",
1273 1267 j, txbf->bf_dma.cookie.dmac_address);
1274 1268 }
1275 1269 }
1276 1270 prx = RTW_RING_BASE(phybaseaddr, hd_rx);
1277 1271 vrx = (caddr_t)(RTW_RING_BASE(virbaseaddr, hd_rx));
1278 1272 /* virtual address of the first descriptor */
1279 1273 rsc->rxdesc_h = (struct rtw_rxdesc *)(uintptr_t)vrx;
1280 1274 rxds = rsc->rxdesc_h;
1281 1275
1282 1276 /* allocate data structures to describe RX DMA buffers */
1283 1277 buflen = sizeof (struct rtw_rxbuf) * RTW_RXQLEN;
1284 1278 rxbf = (struct rtw_rxbuf *)kmem_zalloc(buflen, KM_SLEEP);
1285 1279 rsc->rxbuf_h = rxbf;
1286 1280
1287 1281 for (j = 0; j < RTW_RXQLEN; j++, rxbf++, rxds++) {
1288 1282 rxbf->rxdesc = rxds;
1289 1283 rxbf->bf_daddr =
1290 1284 prx + ((uintptr_t)rxds - (uintptr_t)rsc->rxdesc_h);
1291 1285
1292 1286 /* alloc DMA memory */
1293 1287 err = rtw_alloc_dma_mem(devinfo, &dma_attr_rxbuf,
1294 1288 rsc->sc_dmabuf_size,
1295 1289 &rtw_buf_accattr,
1296 1290 DDI_DMA_STREAMING, DDI_DMA_READ | DDI_DMA_STREAMING,
1297 1291 &rxbf->bf_dma);
1298 1292 if (err != DDI_SUCCESS)
1299 1293 goto error;
1300 1294 }
1301 1295
1302 1296 return (DDI_SUCCESS);
1303 1297 error:
1304 1298 return (DDI_FAILURE);
1305 1299 }
1306 1300
1307 1301 static void
1308 1302 rtw_hwring_setup(rtw_softc_t *rsc)
1309 1303 {
1310 1304 struct rtw_regs *regs = &rsc->sc_regs;
1311 1305 uint32_t phybaseaddr;
1312 1306
1313 1307 phybaseaddr = rsc->sc_desc_dma.cookie.dmac_address;
1314 1308
1315 1309 RTW_WRITE(regs, RTW_RDSAR, RTW_RING_BASE(phybaseaddr, hd_rx));
1316 1310 RTW_WRITE(regs, RTW_TLPDA, RTW_RING_BASE(phybaseaddr, hd_txlo));
1317 1311 RTW_WRITE(regs, RTW_TNPDA, RTW_RING_BASE(phybaseaddr, hd_txmd));
1318 1312 RTW_WRITE(regs, RTW_THPDA, RTW_RING_BASE(phybaseaddr, hd_txhi));
1319 1313 RTW_WRITE(regs, RTW_TBDA, RTW_RING_BASE(phybaseaddr, hd_bcn));
1320 1314 rsc->hw_start = RTW_READ(regs, RTW_TNPDA);
1321 1315 rsc->hw_go = RTW_READ(regs, RTW_TNPDA);
1322 1316 }
1323 1317
1324 1318 static void
1325 1319 rtw_swring_setup(rtw_softc_t *rsc, int flag)
1326 1320 {
1327 1321 int i, j;
1328 1322 int is_last;
1329 1323 struct rtw_txbuf *txbf;
1330 1324 struct rtw_rxbuf *rxbf;
1331 1325 uint32_t phybaseaddr, ptx[RTW_NTXPRI], baddr_desc, taddr_desc;
1332 1326
1333 1327 phybaseaddr = rsc->sc_desc_dma.cookie.dmac_address;
1334 1328 ptx[0] = RTW_RING_BASE(phybaseaddr, hd_txlo);
1335 1329 ptx[1] = RTW_RING_BASE(phybaseaddr, hd_txmd);
1336 1330 ptx[2] = RTW_RING_BASE(phybaseaddr, hd_txhi);
1337 1331 ptx[3] = RTW_RING_BASE(phybaseaddr, hd_bcn);
1338 1332 RTW_DMA_SYNC(rsc->sc_desc_dma, DDI_DMA_SYNC_FORDEV);
1339 1333 /* sync tx desc and tx buf */
1340 1334 for (i = 0; i < RTW_NTXPRI; i++) {
1341 1335 rsc->sc_txq[i].tx_prod = rsc->sc_txq[i].tx_cons = 0;
1342 1336 rsc->sc_txq[i].tx_nfree = rtw_qlen[i];
1343 1337 txbf = list_head(&rsc->sc_txq[i].tx_free_list);
1344 1338 while (txbf != NULL) {
1345 1339 list_remove(&rsc->sc_txq[i].tx_free_list, txbf);
1346 1340 txbf = list_head(&rsc->sc_txq[i].tx_free_list);
1347 1341 }
1348 1342 txbf = list_head(&rsc->sc_txq[i].tx_dirty_list);
1349 1343 while (txbf != NULL) {
1350 1344 list_remove(&rsc->sc_txq[i].tx_dirty_list, txbf);
1351 1345 txbf = list_head(&rsc->sc_txq[i].tx_dirty_list);
1352 1346 }
1353 1347 txbf = rsc->sc_txq[i].txbuf_h;
1354 1348 baddr_desc = ptx[i];
1355 1349 taddr_desc = baddr_desc + sizeof (struct rtw_txdesc);
1356 1350 for (j = 0; j < rtw_qlen[i]; j++) {
1357 1351 list_insert_tail(&rsc->sc_txq[i].tx_free_list, txbf);
1358 1352 if (j == (rtw_qlen[i] - 1)) {
1359 1353 is_last = 1;
1360 1354 } else {
1361 1355 is_last = 0;
1362 1356 }
1363 1357
1364 1358 if (is_last) {
1365 1359 txbf->txdesc->td_next = baddr_desc;
1366 1360 } else {
1367 1361 txbf->txdesc->td_next = taddr_desc;
1368 1362 }
1369 1363 txbf->next_bf_daddr = txbf->txdesc->td_next;
1370 1364 RTW_DMA_SYNC(txbf->bf_dma, DDI_DMA_SYNC_FORDEV);
1371 1365 txbf->order = j;
1372 1366 txbf++;
1373 1367 taddr_desc += sizeof (struct rtw_txdesc);
1374 1368 }
1375 1369 }
1376 1370 if (!flag)
1377 1371 return;
1378 1372
1379 1373 /* sync rx desc and rx buf */
1380 1374 rsc->rx_next = 0;
1381 1375 rxbf = rsc->rxbuf_h;
1382 1376 for (j = 0; j < RTW_RXQLEN; j++) {
1383 1377 RTW_DMA_SYNC(rxbf->bf_dma, DDI_DMA_SYNC_FORCPU);
1384 1378 if (j == (RTW_RXQLEN - 1))
1385 1379 is_last = 1;
1386 1380 else
1387 1381 is_last = 0;
1388 1382 rtw_rxdesc_init(rsc, rxbf, j, is_last);
1389 1383 rxbf++;
1390 1384 }
1391 1385 }
1392 1386
1393 1387 static void
1394 1388 rtw_resume_ticks(rtw_softc_t *rsc)
1395 1389 {
1396 1390 RTW_WRITE(&rsc->sc_regs, RTW_TINT, 0xffffffff);
1397 1391 }
1398 1392
1399 1393 const char *
1400 1394 rtw_pwrstate_string(enum rtw_pwrstate power)
1401 1395 {
1402 1396 switch (power) {
1403 1397 case RTW_ON:
1404 1398 return ("on");
1405 1399 case RTW_SLEEP:
1406 1400 return ("sleep");
1407 1401 case RTW_OFF:
1408 1402 return ("off");
1409 1403 default:
1410 1404 return ("unknown");
1411 1405 }
1412 1406 }
1413 1407
1414 1408 /*
1415 1409 * XXX For Maxim, I am using the RFMD settings gleaned from the
1416 1410 * reference driver, plus a magic Maxim "ON" value that comes from
1417 1411 * the Realtek document "Windows PG for Rtl8180."
1418 1412 */
1419 1413 /*ARGSUSED*/
1420 1414 static void
1421 1415 rtw_maxim_pwrstate(struct rtw_regs *regs, enum rtw_pwrstate power,
1422 1416 int before_rf, int digphy)
1423 1417 {
1424 1418 uint32_t anaparm;
1425 1419
1426 1420 anaparm = RTW_READ(regs, RTW_ANAPARM);
1427 1421 anaparm &= ~(RTW_ANAPARM_RFPOW_MASK | RTW_ANAPARM_TXDACOFF);
1428 1422
1429 1423 switch (power) {
1430 1424 case RTW_OFF:
1431 1425 if (before_rf)
1432 1426 return;
1433 1427 anaparm |= RTW_ANAPARM_RFPOW_MAXIM_OFF;
1434 1428 anaparm |= RTW_ANAPARM_TXDACOFF;
1435 1429 break;
1436 1430 case RTW_SLEEP:
1437 1431 if (!before_rf)
1438 1432 return;
1439 1433 anaparm |= RTW_ANAPARM_RFPOW_MAXIM_SLEEP;
1440 1434 anaparm |= RTW_ANAPARM_TXDACOFF;
1441 1435 break;
1442 1436 case RTW_ON:
1443 1437 if (!before_rf)
1444 1438 return;
1445 1439 anaparm |= RTW_ANAPARM_RFPOW_MAXIM_ON;
1446 1440 break;
1447 1441 }
1448 1442 RTW_DPRINTF(RTW_DEBUG_PWR,
1449 1443 "%s: power state %s, %s RF, reg[ANAPARM] <- %08x\n",
1450 1444 __func__, rtw_pwrstate_string(power),
1451 1445 (before_rf) ? "before" : "after", anaparm);
1452 1446
1453 1447 RTW_WRITE(regs, RTW_ANAPARM, anaparm);
1454 1448 RTW_SYNC(regs, RTW_ANAPARM, RTW_ANAPARM);
1455 1449 }
1456 1450
1457 1451 /*
1458 1452 * XXX I am using the RFMD settings gleaned from the reference
1459 1453 * driver. They agree
1460 1454 */
1461 1455 /*ARGSUSED*/
1462 1456 static void
1463 1457 rtw_rfmd_pwrstate(struct rtw_regs *regs, enum rtw_pwrstate power,
1464 1458 int before_rf, int digphy)
1465 1459 {
1466 1460 uint32_t anaparm;
1467 1461
1468 1462 anaparm = RTW_READ(regs, RTW_ANAPARM);
1469 1463 anaparm &= ~(RTW_ANAPARM_RFPOW_MASK | RTW_ANAPARM_TXDACOFF);
1470 1464
1471 1465 switch (power) {
1472 1466 case RTW_OFF:
1473 1467 if (before_rf)
1474 1468 return;
1475 1469 anaparm |= RTW_ANAPARM_RFPOW_RFMD_OFF;
1476 1470 anaparm |= RTW_ANAPARM_TXDACOFF;
1477 1471 break;
1478 1472 case RTW_SLEEP:
1479 1473 if (!before_rf)
1480 1474 return;
1481 1475 anaparm |= RTW_ANAPARM_RFPOW_RFMD_SLEEP;
1482 1476 anaparm |= RTW_ANAPARM_TXDACOFF;
1483 1477 break;
1484 1478 case RTW_ON:
1485 1479 if (!before_rf)
1486 1480 return;
1487 1481 anaparm |= RTW_ANAPARM_RFPOW_RFMD_ON;
1488 1482 break;
1489 1483 }
1490 1484 RTW_DPRINTF(RTW_DEBUG_PWR,
1491 1485 "%s: power state %s, %s RF, reg[ANAPARM] <- %08x\n",
1492 1486 __func__, rtw_pwrstate_string(power),
1493 1487 (before_rf) ? "before" : "after", anaparm);
1494 1488
1495 1489 RTW_WRITE(regs, RTW_ANAPARM, anaparm);
1496 1490 RTW_SYNC(regs, RTW_ANAPARM, RTW_ANAPARM);
1497 1491 }
1498 1492
1499 1493 static void
1500 1494 rtw_philips_pwrstate(struct rtw_regs *regs, enum rtw_pwrstate power,
1501 1495 int before_rf, int digphy)
1502 1496 {
1503 1497 uint32_t anaparm;
1504 1498
1505 1499 anaparm = RTW_READ(regs, RTW_ANAPARM);
1506 1500 anaparm &= ~(RTW_ANAPARM_RFPOW_MASK | RTW_ANAPARM_TXDACOFF);
1507 1501
1508 1502 switch (power) {
1509 1503 case RTW_OFF:
1510 1504 if (before_rf)
1511 1505 return;
1512 1506 anaparm |= RTW_ANAPARM_RFPOW_PHILIPS_OFF;
1513 1507 anaparm |= RTW_ANAPARM_TXDACOFF;
1514 1508 break;
1515 1509 case RTW_SLEEP:
1516 1510 if (!before_rf)
1517 1511 return;
1518 1512 anaparm |= RTW_ANAPARM_RFPOW_PHILIPS_SLEEP;
1519 1513 anaparm |= RTW_ANAPARM_TXDACOFF;
1520 1514 break;
1521 1515 case RTW_ON:
1522 1516 if (!before_rf)
1523 1517 return;
1524 1518 if (digphy) {
1525 1519 anaparm |= RTW_ANAPARM_RFPOW_DIG_PHILIPS_ON;
1526 1520 /* XXX guess */
1527 1521 anaparm |= RTW_ANAPARM_TXDACOFF;
1528 1522 } else
1529 1523 anaparm |= RTW_ANAPARM_RFPOW_ANA_PHILIPS_ON;
1530 1524 break;
1531 1525 }
1532 1526 RTW_DPRINTF(RTW_DEBUG_PWR,
1533 1527 "%s: power state %s, %s RF, reg[ANAPARM] <- %08x\n",
1534 1528 __func__, rtw_pwrstate_string(power),
1535 1529 (before_rf) ? "before" : "after", anaparm);
1536 1530
1537 1531 RTW_WRITE(regs, RTW_ANAPARM, anaparm);
1538 1532 RTW_SYNC(regs, RTW_ANAPARM, RTW_ANAPARM);
1539 1533 }
1540 1534
1541 1535 static void
1542 1536 rtw_pwrstate0(rtw_softc_t *rsc, enum rtw_pwrstate power, int before_rf,
1543 1537 int digphy)
1544 1538 {
1545 1539 struct rtw_regs *regs = &rsc->sc_regs;
1546 1540
1547 1541 rtw_set_access(regs, RTW_ACCESS_ANAPARM);
1548 1542
1549 1543 (*rsc->sc_pwrstate_cb)(regs, power, before_rf, digphy);
1550 1544
1551 1545 rtw_set_access(regs, RTW_ACCESS_NONE);
1552 1546 }
1553 1547
1554 1548 static void
1555 1549 rtw_rf_destroy(struct rtw_rf *rf)
1556 1550 {
1557 1551 (*rf->rf_destroy)(rf);
1558 1552 }
1559 1553
1560 1554 static int
1561 1555 rtw_rf_pwrstate(struct rtw_rf *rf, enum rtw_pwrstate power)
1562 1556 {
1563 1557 return (*rf->rf_pwrstate)(rf, power);
1564 1558 }
1565 1559
1566 1560 static int
1567 1561 rtw_pwrstate(rtw_softc_t *rsc, enum rtw_pwrstate power)
1568 1562 {
1569 1563 int rc;
1570 1564
1571 1565 RTW_DPRINTF(RTW_DEBUG_PWR,
1572 1566 "%s: %s->%s\n", __func__,
1573 1567 rtw_pwrstate_string(rsc->sc_pwrstate), rtw_pwrstate_string(power));
1574 1568
1575 1569 if (rsc->sc_pwrstate == power)
1576 1570 return (0);
1577 1571
1578 1572 rtw_pwrstate0(rsc, power, 1, rsc->sc_flags & RTW_F_DIGPHY);
1579 1573 rc = rtw_rf_pwrstate(rsc->sc_rf, power);
1580 1574 rtw_pwrstate0(rsc, power, 0, rsc->sc_flags & RTW_F_DIGPHY);
1581 1575
1582 1576 switch (power) {
1583 1577 case RTW_ON:
1584 1578 /* TBD set LEDs */
1585 1579 break;
1586 1580 case RTW_SLEEP:
1587 1581 /* TBD */
1588 1582 break;
1589 1583 case RTW_OFF:
1590 1584 /* TBD */
1591 1585 break;
1592 1586 }
1593 1587 if (rc == 0)
1594 1588 rsc->sc_pwrstate = power;
1595 1589 else
1596 1590 rsc->sc_pwrstate = RTW_OFF;
1597 1591 return (rc);
1598 1592 }
1599 1593
1600 1594 void
1601 1595 rtw_disable(rtw_softc_t *rsc)
1602 1596 {
1603 1597 int rc;
1604 1598
1605 1599 if ((rsc->sc_flags & RTW_F_ENABLED) == 0)
1606 1600 return;
1607 1601
1608 1602 /* turn off PHY */
1609 1603 if ((rsc->sc_flags & RTW_F_INVALID) == 0 &&
1610 1604 (rc = rtw_pwrstate(rsc, RTW_OFF)) != 0) {
1611 1605 cmn_err(CE_WARN, "failed to turn off PHY (%d)\n", rc);
1612 1606 }
1613 1607
1614 1608 if (rsc->sc_disable != NULL)
1615 1609 (*rsc->sc_disable)(rsc);
1616 1610
1617 1611 rsc->sc_flags &= ~RTW_F_ENABLED;
1618 1612 }
1619 1613
1620 1614 int
1621 1615 rtw_enable(rtw_softc_t *rsc)
1622 1616 {
1623 1617 if ((rsc->sc_flags & RTW_F_ENABLED) == 0) {
1624 1618 if (rsc->sc_enable != NULL && (*rsc->sc_enable)(rsc) != 0) {
1625 1619 cmn_err(CE_WARN, "device enable failed\n");
1626 1620 return (EIO);
1627 1621 }
1628 1622 rsc->sc_flags |= RTW_F_ENABLED;
1629 1623 if (rtw_pwrstate(rsc, RTW_ON) != 0)
1630 1624 cmn_err(CE_WARN, "PHY turn on failed\n");
1631 1625 }
1632 1626 return (0);
1633 1627 }
1634 1628
1635 1629 static void
1636 1630 rtw_set_nettype(rtw_softc_t *rsc, enum ieee80211_opmode opmode)
1637 1631 {
1638 1632 uint8_t msr;
1639 1633
1640 1634 /* I'm guessing that MSR is protected as CONFIG[0123] are. */
1641 1635 rtw_set_access(&rsc->sc_regs, RTW_ACCESS_CONFIG);
1642 1636
1643 1637 msr = RTW_READ8(&rsc->sc_regs, RTW_MSR) & ~RTW_MSR_NETYPE_MASK;
1644 1638
1645 1639 switch (opmode) {
1646 1640 case IEEE80211_M_AHDEMO:
1647 1641 case IEEE80211_M_IBSS:
1648 1642 msr |= RTW_MSR_NETYPE_ADHOC_OK;
1649 1643 break;
1650 1644 case IEEE80211_M_HOSTAP:
1651 1645 msr |= RTW_MSR_NETYPE_AP_OK;
1652 1646 break;
1653 1647 case IEEE80211_M_STA:
1654 1648 msr |= RTW_MSR_NETYPE_INFRA_OK;
1655 1649 break;
1656 1650 }
1657 1651 RTW_WRITE8(&rsc->sc_regs, RTW_MSR, msr);
1658 1652
1659 1653 rtw_set_access(&rsc->sc_regs, RTW_ACCESS_NONE);
1660 1654 }
1661 1655
1662 1656 static void
1663 1657 rtw_pktfilt_load(rtw_softc_t *rsc)
1664 1658 {
1665 1659 struct rtw_regs *regs = &rsc->sc_regs;
1666 1660 struct ieee80211com *ic = &rsc->sc_ic;
1667 1661
1668 1662 /* XXX might be necessary to stop Rx/Tx engines while setting filters */
1669 1663 rsc->sc_rcr &= ~RTW_RCR_PKTFILTER_MASK;
1670 1664 rsc->sc_rcr &= ~(RTW_RCR_MXDMA_MASK | RTW_RCR_RXFTH_MASK);
1671 1665
1672 1666 rsc->sc_rcr |= RTW_RCR_PKTFILTER_DEFAULT;
1673 1667 /* MAC auto-reset PHY (huh?) */
1674 1668 rsc->sc_rcr |= RTW_RCR_ENMARP;
1675 1669 /* DMA whole Rx packets, only. Set Tx DMA burst size to 1024 bytes. */
1676 1670 rsc->sc_rcr |= RTW_RCR_RXFTH_WHOLE |RTW_RCR_MXDMA_1024;
1677 1671
1678 1672 switch (ic->ic_opmode) {
1679 1673 case IEEE80211_M_AHDEMO:
1680 1674 case IEEE80211_M_IBSS:
1681 1675 /* receive broadcasts in our BSS */
1682 1676 rsc->sc_rcr |= RTW_RCR_ADD3;
1683 1677 break;
1684 1678 default:
1685 1679 break;
1686 1680 }
1687 1681 #if 0
1688 1682 /* XXX accept all broadcast if scanning */
1689 1683 rsc->sc_rcr |= RTW_RCR_AB; /* accept all broadcast */
1690 1684 #endif
1691 1685 RTW_WRITE(regs, RTW_MAR0, 0xffffffff);
1692 1686 RTW_WRITE(regs, RTW_MAR1, 0xffffffff);
1693 1687 rsc->sc_rcr |= RTW_RCR_AM;
1694 1688 RTW_WRITE(regs, RTW_RCR, rsc->sc_rcr);
1695 1689 RTW_SYNC(regs, RTW_MAR0, RTW_RCR); /* RTW_MAR0 < RTW_MAR1 < RTW_RCR */
1696 1690
1697 1691 RTW_DPRINTF(RTW_DEBUG_PKTFILT,
1698 1692 "RTW_MAR0 %08x RTW_MAR1 %08x RTW_RCR %08x\n",
1699 1693 RTW_READ(regs, RTW_MAR0),
1700 1694 RTW_READ(regs, RTW_MAR1), RTW_READ(regs, RTW_RCR));
1701 1695 RTW_WRITE(regs, RTW_RCR, rsc->sc_rcr);
1702 1696 }
1703 1697
1704 1698 static void
1705 1699 rtw_transmit_config(struct rtw_regs *regs)
1706 1700 {
1707 1701 uint32_t tcr;
1708 1702
1709 1703 tcr = RTW_READ(regs, RTW_TCR);
1710 1704
1711 1705 tcr |= RTW_TCR_CWMIN;
1712 1706 tcr &= ~RTW_TCR_MXDMA_MASK;
1713 1707 tcr |= RTW_TCR_MXDMA_1024;
1714 1708 tcr |= RTW_TCR_SAT; /* send ACK as fast as possible */
1715 1709 tcr &= ~RTW_TCR_LBK_MASK;
1716 1710 tcr |= RTW_TCR_LBK_NORMAL; /* normal operating mode */
1717 1711
1718 1712 /* set short/long retry limits */
1719 1713 tcr &= ~(RTW_TCR_SRL_MASK|RTW_TCR_LRL_MASK);
1720 1714 tcr |= LSHIFT(0x4, RTW_TCR_SRL_MASK) | LSHIFT(0x4, RTW_TCR_LRL_MASK);
1721 1715
1722 1716 tcr &= ~RTW_TCR_CRC; /* NIC appends CRC32 */
1723 1717 RTW_WRITE(regs, RTW_TCR, tcr);
1724 1718 RTW_SYNC(regs, RTW_TCR, RTW_TCR);
1725 1719 }
1726 1720
1727 1721 int
1728 1722 rtw_refine_setting(rtw_softc_t *rsc)
1729 1723 {
1730 1724 struct rtw_regs *regs;
1731 1725 int rc = 0;
1732 1726
1733 1727 regs = &rsc->sc_regs;
1734 1728 rc = rtw_reset(rsc);
1735 1729 if (rc != 0)
1736 1730 return (-1);
1737 1731
1738 1732 rtw_beacon_tx_disable(regs);
1739 1733 rtw_io_enable(rsc, RTW_CR_RE|RTW_CR_TE, 1);
1740 1734 rtw_set_mode(regs, RTW_EPROM_CMD_CONFIG);
1741 1735
1742 1736 rtw_transmit_config(regs);
1743 1737 rtw_pktfilt_load(rsc);
1744 1738 rtw_set_access(regs, RTW_ACCESS_CONFIG);
1745 1739 RTW_WRITE(regs, RTW_TINT, 0xffffffff);
1746 1740 RTW_WRITE8(regs, RTW_MSR, 0x0); /* no link */
1747 1741 RTW_WRITE16(regs, RTW_BRSR, 0);
1748 1742
1749 1743 rtw_set_access(regs, RTW_ACCESS_ANAPARM);
1750 1744 rtw_set_access(regs, RTW_ACCESS_NONE);
1751 1745 RTW_WRITE(regs, RTW_FEMR, 0xffff);
1752 1746 RTW_SYNC(regs, RTW_FEMR, RTW_FEMR);
1753 1747 rtw_set_rfprog(regs, rsc->sc_rfchipid, "rtw");
1754 1748
1755 1749 RTW_WRITE8(regs, RTW_PHYDELAY, rsc->sc_phydelay);
1756 1750 RTW_WRITE8(regs, RTW_CRCOUNT, RTW_CRCOUNT_MAGIC);
1757 1751 rtw_set_mode(regs, RTW_EPROM_CMD_NORMAL);
1758 1752 return (0);
1759 1753 }
1760 1754
1761 1755 static int
1762 1756 rtw_tune(rtw_softc_t *rsc)
1763 1757 {
1764 1758 struct ieee80211com *ic = &rsc->sc_ic;
1765 1759 uint32_t chan;
1766 1760 int rc;
1767 1761 int antdiv = rsc->sc_flags & RTW_F_ANTDIV,
1768 1762 dflantb = rsc->sc_flags & RTW_F_DFLANTB;
1769 1763
1770 1764 ASSERT(ic->ic_curchan != NULL);
1771 1765
1772 1766 chan = ieee80211_chan2ieee(ic, ic->ic_curchan);
1773 1767 RTW_DPRINTF(RTW_DEBUG_TUNE, "rtw: chan no = %x", chan);
1774 1768
1775 1769 if (chan == IEEE80211_CHAN_ANY) {
1776 1770 cmn_err(CE_WARN, "%s: chan == IEEE80211_CHAN_ANY\n", __func__);
1777 1771 return (-1);
1778 1772 }
1779 1773
1780 1774 if (chan == rsc->sc_cur_chan) {
1781 1775 RTW_DPRINTF(RTW_DEBUG_TUNE,
1782 1776 "%s: already tuned chan %d\n", __func__, chan);
1783 1777 return (0);
1784 1778 }
1785 1779 rtw_idle(&rsc->sc_regs);
1786 1780 rtw_io_enable(rsc, RTW_CR_RE | RTW_CR_TE, 0);
1787 1781 ASSERT((rsc->sc_flags & RTW_F_ENABLED) != 0);
1788 1782
1789 1783 if ((rc = rtw_phy_init(&rsc->sc_regs, rsc->sc_rf,
1790 1784 rtw_chan2txpower(&rsc->sc_srom, ic, ic->ic_curchan),
1791 1785 rsc->sc_csthr, ic->ic_curchan->ich_freq, antdiv,
1792 1786 dflantb, RTW_ON)) != 0) {
1793 1787 /* XXX condition on powersaving */
1794 1788 cmn_err(CE_NOTE, "phy init failed\n");
1795 1789 }
1796 1790 rtw_io_enable(rsc, RTW_CR_RE | RTW_CR_TE, 1);
1797 1791 rtw_resume_ticks(rsc);
1798 1792 rsc->sc_cur_chan = chan;
1799 1793 return (rc);
1800 1794 }
1801 1795
1802 1796 static int
1803 1797 rtw_init(rtw_softc_t *rsc)
1804 1798 {
1805 1799 struct ieee80211com *ic = &rsc->sc_ic;
1806 1800 int rc = 0;
1807 1801
1808 1802 rtw_stop(rsc);
1809 1803 mutex_enter(&rsc->sc_genlock);
1810 1804 if ((rc = rtw_enable(rsc)) != 0)
1811 1805 goto out;
1812 1806 rc = rtw_refine_setting(rsc);
1813 1807 if (rc != 0) {
1814 1808 mutex_exit(&rsc->sc_genlock);
1815 1809 return (rc);
1816 1810 }
1817 1811 rtw_swring_setup(rsc, 1);
1818 1812 rtw_hwring_setup(rsc);
1819 1813 RTW_WRITE16(&rsc->sc_regs, RTW_BSSID16, 0x0);
1820 1814 RTW_WRITE(&rsc->sc_regs, RTW_BSSID32, 0x0);
1821 1815 rtw_enable_interrupts(rsc);
1822 1816
1823 1817 ic->ic_ibss_chan = &ic->ic_sup_channels[1];
1824 1818 ic->ic_curchan = ic->ic_ibss_chan;
1825 1819 RTW_DPRINTF(RTW_DEBUG_TUNE, "%s: channel %d freq %d flags 0x%04x\n",
1826 1820 __func__, ieee80211_chan2ieee(ic, ic->ic_curchan),
1827 1821 ic->ic_curchan->ich_freq, ic->ic_curchan->ich_flags);
1828 1822 rsc->sc_invalid = 0;
1829 1823 out:
1830 1824 mutex_exit(&rsc->sc_genlock);
1831 1825 return (rc);
1832 1826 }
1833 1827
1834 1828 static struct rtw_rf *
1835 1829 rtw_rf_attach(rtw_softc_t *rsc, enum rtw_rfchipid rfchipid, int digphy)
1836 1830 {
1837 1831 rtw_rf_write_t rf_write;
1838 1832 struct rtw_rf *rf;
1839 1833 int rtw_host_rfio;
1840 1834
1841 1835 switch (rfchipid) {
1842 1836 default:
1843 1837 rf_write = rtw_rf_hostwrite;
1844 1838 break;
1845 1839 case RTW_RFCHIPID_INTERSIL:
1846 1840 case RTW_RFCHIPID_PHILIPS:
1847 1841 case RTW_RFCHIPID_GCT: /* XXX a guess */
1848 1842 case RTW_RFCHIPID_RFMD:
1849 1843 rtw_host_rfio = 1;
1850 1844 rf_write = (rtw_host_rfio) ? rtw_rf_hostwrite : rtw_rf_macwrite;
1851 1845 break;
1852 1846 }
1853 1847
1854 1848 switch (rfchipid) {
1855 1849 case RTW_RFCHIPID_MAXIM:
1856 1850 rf = rtw_max2820_create(&rsc->sc_regs, rf_write, 0);
1857 1851 rsc->sc_pwrstate_cb = rtw_maxim_pwrstate;
1858 1852 break;
1859 1853 case RTW_RFCHIPID_PHILIPS:
1860 1854 rf = rtw_sa2400_create(&rsc->sc_regs, rf_write, digphy);
1861 1855 rsc->sc_pwrstate_cb = rtw_philips_pwrstate;
1862 1856 break;
1863 1857 case RTW_RFCHIPID_RFMD:
1864 1858 /* XXX RFMD has no RF constructor */
1865 1859 rsc->sc_pwrstate_cb = rtw_rfmd_pwrstate;
1866 1860 /*FALLTHROUGH*/
1867 1861 default:
1868 1862 return (NULL);
1869 1863 }
1870 1864 if (rf != NULL) {
1871 1865 rf->rf_continuous_tx_cb =
1872 1866 (rtw_continuous_tx_cb_t)rtw_continuous_tx_enable;
1873 1867 rf->rf_continuous_tx_arg = (void *)rsc;
1874 1868 }
1875 1869 return (rf);
1876 1870 }
1877 1871
1878 1872 /*
1879 1873 * Revision C and later use a different PHY delay setting than
1880 1874 * revisions A and B.
1881 1875 */
1882 1876 static uint8_t
1883 1877 rtw_check_phydelay(struct rtw_regs *regs, uint32_t rcr0)
1884 1878 {
1885 1879 #define REVAB (RTW_RCR_MXDMA_UNLIMITED | RTW_RCR_AICV)
1886 1880 #define REVC (REVAB | RTW_RCR_RXFTH_WHOLE)
1887 1881
1888 1882 uint8_t phydelay = LSHIFT(0x6, RTW_PHYDELAY_PHYDELAY);
1889 1883
1890 1884 RTW_WRITE(regs, RTW_RCR, REVAB);
1891 1885 RTW_WBW(regs, RTW_RCR, RTW_RCR);
1892 1886 RTW_WRITE(regs, RTW_RCR, REVC);
1893 1887
1894 1888 RTW_WBR(regs, RTW_RCR, RTW_RCR);
1895 1889 if ((RTW_READ(regs, RTW_RCR) & REVC) == REVC)
1896 1890 phydelay |= RTW_PHYDELAY_REVC_MAGIC;
1897 1891
1898 1892 RTW_WRITE(regs, RTW_RCR, rcr0); /* restore RCR */
1899 1893 RTW_SYNC(regs, RTW_RCR, RTW_RCR);
1900 1894
1901 1895 return (phydelay);
1902 1896 #undef REVC
1903 1897 }
1904 1898
1905 1899 static void rtw_intr_rx(rtw_softc_t *rsc);
1906 1900 static void rtw_ring_recycling(rtw_softc_t *rsc, uint16_t isr, uint32_t pri);
1907 1901
1908 1902 static int
1909 1903 rtw_get_rate(struct ieee80211com *ic)
1910 1904 {
1911 1905 uint8_t (*rates)[IEEE80211_RATE_MAXSIZE];
1912 1906 int rate;
1913 1907
1914 1908 rates = &ic->ic_bss->in_rates.ir_rates;
1915 1909
1916 1910 if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE)
1917 1911 rate = ic->ic_fixed_rate;
1918 1912 else if (ic->ic_state == IEEE80211_S_RUN)
1919 1913 rate = (*rates)[ic->ic_bss->in_txrate];
1920 1914 else
1921 1915 rate = 0;
1922 1916 return (rate & IEEE80211_RATE_VAL);
1923 1917 }
1924 1918
1925 1919 /*
1926 1920 * Arguments in:
1927 1921 *
1928 1922 * paylen: payload length (no FCS, no WEP header)
1929 1923 *
1930 1924 * hdrlen: header length
1931 1925 *
1932 1926 * rate: MSDU speed, units 500kb/s
1933 1927 *
1934 1928 * flags: IEEE80211_F_SHPREAMBLE (use short preamble),
1935 1929 * IEEE80211_F_SHSLOT (use short slot length)
1936 1930 *
1937 1931 * Arguments out:
1938 1932 *
1939 1933 * d: 802.11 Duration field for RTS,
1940 1934 * 802.11 Duration field for data frame,
1941 1935 * PLCP Length for data frame,
1942 1936 * residual octets at end of data slot
1943 1937 */
1944 1938 static int
1945 1939 rtw_compute_duration1(int len, int use_ack, uint32_t flags, int rate,
1946 1940 struct rtw_ieee80211_duration *d)
1947 1941 {
1948 1942 int pre, ctsrate;
1949 1943 uint16_t ack, bitlen, data_dur, remainder;
1950 1944
1951 1945 /*
1952 1946 * RTS reserves medium for SIFS | CTS | SIFS | (DATA) | SIFS | ACK
1953 1947 * DATA reserves medium for SIFS | ACK
1954 1948 *
1955 1949 * XXXMYC: no ACK on multicast/broadcast or control packets
1956 1950 */
1957 1951
1958 1952 bitlen = len * 8;
1959 1953
1960 1954 pre = IEEE80211_DUR_DS_SIFS;
1961 1955 if ((flags & IEEE80211_F_SHPREAMBLE) != 0)
1962 1956 pre += IEEE80211_DUR_DS_SHORT_PREAMBLE +
1963 1957 IEEE80211_DUR_DS_FAST_PLCPHDR;
1964 1958 else
1965 1959 pre += IEEE80211_DUR_DS_LONG_PREAMBLE +
1966 1960 IEEE80211_DUR_DS_SLOW_PLCPHDR;
1967 1961
1968 1962 d->d_residue = 0;
1969 1963 data_dur = (bitlen * 2) / rate;
1970 1964 remainder = (bitlen * 2) % rate;
1971 1965 if (remainder != 0) {
1972 1966 if (rate == 22)
1973 1967 d->d_residue = (rate - remainder) / 16;
1974 1968 data_dur++;
1975 1969 }
1976 1970
1977 1971 switch (rate) {
1978 1972 case 2: /* 1 Mb/s */
1979 1973 case 4: /* 2 Mb/s */
1980 1974 /* 1 - 2 Mb/s WLAN: send ACK/CTS at 1 Mb/s */
1981 1975 ctsrate = 2;
1982 1976 break;
1983 1977 case 11: /* 5.5 Mb/s */
1984 1978 case 22: /* 11 Mb/s */
1985 1979 case 44: /* 22 Mb/s */
1986 1980 /* 5.5 - 11 Mb/s WLAN: send ACK/CTS at 2 Mb/s */
1987 1981 ctsrate = 4;
1988 1982 break;
1989 1983 default:
1990 1984 /* TBD */
1991 1985 return (-1);
1992 1986 }
1993 1987
1994 1988 d->d_plcp_len = data_dur;
1995 1989
1996 1990 ack = (use_ack) ? pre + (IEEE80211_DUR_DS_SLOW_ACK * 2) / ctsrate : 0;
1997 1991
1998 1992 d->d_rts_dur =
1999 1993 pre + (IEEE80211_DUR_DS_SLOW_CTS * 2) / ctsrate +
2000 1994 pre + data_dur +
2001 1995 ack;
2002 1996
2003 1997 d->d_data_dur = ack;
2004 1998
2005 1999 return (0);
2006 2000 }
2007 2001
2008 2002 /*
2009 2003 * Arguments in:
2010 2004 *
2011 2005 * wh: 802.11 header
2012 2006 *
2013 2007 * paylen: payload length (no FCS, no WEP header)
2014 2008 *
2015 2009 * rate: MSDU speed, units 500kb/s
2016 2010 *
2017 2011 * fraglen: fragment length, set to maximum (or higher) for no
2018 2012 * fragmentation
2019 2013 *
2020 2014 * flags: IEEE80211_F_PRIVACY (hardware adds WEP),
2021 2015 * IEEE80211_F_SHPREAMBLE (use short preamble),
2022 2016 * IEEE80211_F_SHSLOT (use short slot length)
2023 2017 *
2024 2018 * Arguments out:
2025 2019 *
2026 2020 * d0: 802.11 Duration fields (RTS/Data), PLCP Length, Service fields
2027 2021 * of first/only fragment
2028 2022 *
2029 2023 * dn: 802.11 Duration fields (RTS/Data), PLCP Length, Service fields
2030 2024 * of first/only fragment
2031 2025 */
2032 2026 static int
2033 2027 rtw_compute_duration(struct ieee80211_frame *wh, int len,
2034 2028 uint32_t flags, int fraglen, int rate, struct rtw_ieee80211_duration *d0,
2035 2029 struct rtw_ieee80211_duration *dn, int *npktp)
2036 2030 {
2037 2031 int ack, rc;
2038 2032 int firstlen, hdrlen, lastlen, lastlen0, npkt, overlen, paylen;
2039 2033
2040 2034 /* don't think about addr4 here */
2041 2035 hdrlen = sizeof (struct ieee80211_frame);
2042 2036
2043 2037 paylen = len - hdrlen;
2044 2038
2045 2039 if ((wh->i_fc[1] & IEEE80211_FC1_WEP) != 0) {
2046 2040 overlen = 8 + IEEE80211_CRC_LEN;
2047 2041 paylen -= 8;
2048 2042 } else
2049 2043 overlen = IEEE80211_CRC_LEN;
2050 2044
2051 2045 npkt = paylen / fraglen;
2052 2046 lastlen0 = paylen % fraglen;
2053 2047
2054 2048 if (npkt == 0) /* no fragments */
2055 2049 lastlen = paylen + overlen;
2056 2050 else if (lastlen0 != 0) { /* a short "tail" fragment */
2057 2051 lastlen = lastlen0 + overlen;
2058 2052 npkt++;
2059 2053 } else /* full-length "tail" fragment */
2060 2054 lastlen = fraglen + overlen;
2061 2055
2062 2056 if (npktp != NULL)
2063 2057 *npktp = npkt;
2064 2058
2065 2059 if (npkt > 1)
2066 2060 firstlen = fraglen + overlen;
2067 2061 else
2068 2062 firstlen = paylen + overlen;
2069 2063
2070 2064 ack = !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
2071 2065 (wh->i_fc[1] & IEEE80211_FC0_TYPE_MASK) !=
2072 2066 IEEE80211_FC0_TYPE_CTL;
2073 2067
2074 2068 rc = rtw_compute_duration1(firstlen + hdrlen,
2075 2069 ack, flags, rate, d0);
2076 2070 if (rc == -1)
2077 2071 return (rc);
2078 2072
2079 2073 if (npkt <= 1) {
2080 2074 *dn = *d0;
2081 2075 return (0);
2082 2076 }
2083 2077 return (rtw_compute_duration1(lastlen + hdrlen, ack, flags,
2084 2078 rate, dn));
2085 2079 }
2086 2080
2087 2081 static int
2088 2082 rtw_assembly_80211(rtw_softc_t *rsc, struct rtw_txbuf *bf,
2089 2083 mblk_t *mp)
2090 2084 {
2091 2085 ieee80211com_t *ic;
2092 2086 struct rtw_txdesc *ds;
2093 2087 struct ieee80211_frame *wh;
2094 2088 uint8_t *buf;
2095 2089 uint32_t ctl0 = 0, ctl1 = 0;
2096 2090 int npkt, rate;
2097 2091 struct rtw_ieee80211_duration d0, dn;
2098 2092 int32_t iswep, pktlen, mblen;
2099 2093 mblk_t *mp0;
2100 2094
2101 2095 ic = &rsc->sc_ic;
2102 2096 ds = bf->txdesc;
2103 2097 buf = (uint8_t *)bf->bf_dma.mem_va;
2104 2098 bzero(buf, bf->bf_dma.alength);
2105 2099 bzero((uint8_t *)ds, sizeof (struct rtw_txdesc));
2106 2100 wh = (struct ieee80211_frame *)mp->b_rptr;
2107 2101 iswep = wh->i_fc[1] & IEEE80211_FC1_WEP;
2108 2102
2109 2103 /* ieee80211_crypto_encap() needs a single mblk */
2110 2104 mp0 = allocb(bf->bf_dma.alength, BPRI_MED);
2111 2105 if (mp0 == NULL) {
2112 2106 cmn_err(CE_WARN, "%s: allocb(mp) error", __func__);
2113 2107 return (-1);
2114 2108 }
2115 2109 for (; mp != NULL; mp = mp->b_cont) {
2116 2110 mblen = (uintptr_t)mp->b_wptr - (uintptr_t)mp->b_rptr;
2117 2111 bcopy(mp->b_rptr, mp0->b_wptr, mblen);
2118 2112 mp0->b_wptr += mblen;
2119 2113 }
2120 2114
2121 2115 if (iswep) {
2122 2116 struct ieee80211_key *k;
2123 2117
2124 2118 k = ieee80211_crypto_encap(ic, mp0);
2125 2119 if (k == NULL) {
2126 2120 cmn_err(CE_WARN, "%s: ieee80211_crypto_encap() error",
2127 2121 __func__);
2128 2122 freemsg(mp0);
2129 2123 return (-1);
2130 2124 }
2131 2125 }
2132 2126 pktlen = msgdsize(mp0);
2133 2127
2134 2128 #if 0
2135 2129 RTW_DPRINTF(RTW_DEBUG_XMIT, "-----------send------begin--------");
2136 2130 ieee80211_dump_pkt((uint8_t *)(mp0->b_rptr), pktlen, 0, 0);
2137 2131 RTW_DPRINTF(RTW_DEBUG_XMIT, "-----------send------end--------");
2138 2132 #endif
2139 2133 /* RTW_DMA_SYNC(bf->bf_dma, DDI_DMA_SYNC_FORDEV); */
2140 2134 if (pktlen > bf->bf_dma.alength) {
2141 2135 cmn_err(CE_WARN, "%s: overlength packet pktlen = %d\n",
2142 2136 __func__, pktlen);
2143 2137 freemsg(mp0);
2144 2138 return (-1);
2145 2139 }
2146 2140 bcopy(mp0->b_rptr, buf, pktlen);
2147 2141 RTW_DMA_SYNC(bf->bf_dma, DDI_DMA_SYNC_FORDEV);
2148 2142
2149 2143 /* setup descriptor */
2150 2144 ctl0 = RTW_TXCTL0_RTSRATE_1MBPS;
2151 2145
2152 2146 if (((ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0) &&
2153 2147 (ic->ic_bss->in_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)) {
2154 2148 ctl0 |= RTW_TXCTL0_SPLCP;
2155 2149 }
2156 2150 /* XXX do real rate control */
2157 2151 if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
2158 2152 IEEE80211_FC0_TYPE_MGT)
2159 2153 rate = 2;
2160 2154 else {
2161 2155 rate = MAX(2, rtw_get_rate(ic));
2162 2156 }
2163 2157 ctl0 = ctl0 |
2164 2158 LSHIFT(pktlen, RTW_TXCTL0_TPKTSIZE_MASK);
2165 2159
2166 2160 RTW_DPRINTF(RTW_DEBUG_XMIT, "%s: rate = %d", __func__, rate);
2167 2161
2168 2162 switch (rate) {
2169 2163 default:
2170 2164 case 2:
2171 2165 ctl0 |= RTW_TXCTL0_RATE_1MBPS;
2172 2166 break;
2173 2167 case 4:
2174 2168 ctl0 |= RTW_TXCTL0_RATE_2MBPS;
2175 2169 break;
2176 2170 case 11:
2177 2171 ctl0 |= RTW_TXCTL0_RATE_5MBPS;
2178 2172 break;
2179 2173 case 22:
2180 2174 ctl0 |= RTW_TXCTL0_RATE_11MBPS;
2181 2175 break;
2182 2176 }
2183 2177
2184 2178 /* XXX >= ? Compare after fragmentation? */
2185 2179 if (pktlen > ic->ic_rtsthreshold) {
2186 2180 ctl0 |= RTW_TXCTL0_RTSEN;
2187 2181 cmn_err(CE_NOTE, "%s: fragmentation: pktlen = %d",
2188 2182 __func__, pktlen);
2189 2183 }
2190 2184
2191 2185 if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
2192 2186 IEEE80211_FC0_TYPE_MGT) {
2193 2187 ctl0 &= ~(RTW_TXCTL0_SPLCP | RTW_TXCTL0_RTSEN);
2194 2188 if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
2195 2189 IEEE80211_FC0_SUBTYPE_BEACON)
2196 2190 ctl0 |= RTW_TXCTL0_BEACON;
2197 2191 }
2198 2192
2199 2193 if (rtw_compute_duration(wh, pktlen,
2200 2194 ic->ic_flags, ic->ic_fragthreshold,
2201 2195 rate, &d0, &dn, &npkt) == -1) {
2202 2196 RTW_DPRINTF(RTW_DEBUG_XMIT,
2203 2197 "%s: fail compute duration\n", __func__);
2204 2198 freemsg(mp0);
2205 2199 return (-1);
2206 2200 }
2207 2201 *(uint16_t *)(uintptr_t)wh->i_dur = (d0.d_data_dur);
2208 2202
2209 2203 ctl1 = LSHIFT(d0.d_plcp_len, RTW_TXCTL1_LENGTH_MASK) |
2210 2204 LSHIFT(d0.d_rts_dur, RTW_TXCTL1_RTSDUR_MASK);
2211 2205
2212 2206 if (d0.d_residue)
2213 2207 ctl1 |= RTW_TXCTL1_LENGEXT;
2214 2208
2215 2209 RTW_DPRINTF(RTW_DEBUG_XMIT, "%s: duration=%x, ctl1=%x", __func__,
2216 2210 *(uint16_t *)(uintptr_t)wh->i_dur, ctl1);
2217 2211
2218 2212 if (bf->bf_dma.alength > RTW_TXLEN_LENGTH_MASK) {
2219 2213 RTW_DPRINTF(RTW_DEBUG_XMIT,
2220 2214 "%s: seg too long\n", __func__);
2221 2215 freemsg(mp0);
2222 2216 return (-1);
2223 2217 }
2224 2218 ds->td_ctl0 = ctl0;
2225 2219 ds->td_ctl0 |= RTW_TXCTL0_OWN | RTW_TXCTL0_LS | RTW_TXCTL0_FS;
2226 2220 ds->td_ctl1 = ctl1;
2227 2221 ds->td_buf = bf->bf_dma.cookie.dmac_address;
2228 2222 ds->td_len = pktlen & 0xfff;
2229 2223 ds->td_next = bf->next_bf_daddr;
2230 2224
2231 2225 RTW_DMA_SYNC_DESC(rsc->sc_desc_dma,
2232 2226 RTW_DESC_OFFSET(hd_txmd, bf->order),
2233 2227 sizeof (struct rtw_txdesc),
2234 2228 DDI_DMA_SYNC_FORDEV);
2235 2229
2236 2230 RTW_DPRINTF(RTW_DEBUG_XMIT,
2237 2231 "descriptor: order = %d, phy_addr=%x, ctl0=%x,"
2238 2232 " ctl1=%x, buf=%x, len=%x, next=%x", bf->order,
2239 2233 bf->bf_daddr, ds->td_ctl0, ds->td_ctl1,
2240 2234 ds->td_buf, ds->td_len, ds->td_next);
2241 2235 rsc->sc_pktxmt64++;
2242 2236 rsc->sc_bytexmt64 += pktlen;
2243 2237
2244 2238 freemsg(mp0);
2245 2239 return (0);
2246 2240 }
2247 2241
2248 2242 static int
2249 2243 rtw_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type)
2250 2244 {
2251 2245 rtw_softc_t *rsc = (rtw_softc_t *)ic;
2252 2246 struct ieee80211_node *in = ic->ic_bss;
2253 2247 struct rtw_txbuf *bf = NULL;
2254 2248 int ret, i = RTW_TXPRIMD;
2255 2249
2256 2250 mutex_enter(&rsc->sc_txlock);
2257 2251 mutex_enter(&rsc->sc_txq[i].txbuf_lock);
2258 2252 bf = list_head(&rsc->sc_txq[i].tx_free_list);
2259 2253
2260 2254 if ((bf == NULL) || (rsc->sc_txq[i].tx_nfree <= 4)) {
2261 2255 RTW_DPRINTF(RTW_DEBUG_XMIT, "%s: no tx buf\n", __func__);
2262 2256 rsc->sc_noxmtbuf++;
2263 2257 if ((type & IEEE80211_FC0_TYPE_MASK) ==
2264 2258 IEEE80211_FC0_TYPE_DATA) {
2265 2259 RTW_DPRINTF(RTW_DEBUG_XMIT, "%s: need reschedule\n",
2266 2260 __func__);
2267 2261 rsc->sc_need_reschedule = 1;
2268 2262 } else {
2269 2263 freemsg(mp);
2270 2264 }
2271 2265 mutex_exit(&rsc->sc_txq[i].txbuf_lock);
2272 2266 mutex_exit(&rsc->sc_txlock);
2273 2267 return (1);
2274 2268 }
2275 2269 list_remove(&rsc->sc_txq[i].tx_free_list, bf);
2276 2270 rsc->sc_txq[i].tx_nfree--;
2277 2271
2278 2272 /* assemble 802.11 frame here */
2279 2273 ret = rtw_assembly_80211(rsc, bf, mp);
2280 2274 if (ret != 0) {
2281 2275 cmn_err(CE_WARN, "%s assembly frame error\n", __func__);
2282 2276 mutex_exit(&rsc->sc_txq[i].txbuf_lock);
2283 2277 mutex_exit(&rsc->sc_txlock);
2284 2278 if ((type & IEEE80211_FC0_TYPE_MASK) !=
2285 2279 IEEE80211_FC0_TYPE_DATA) {
2286 2280 freemsg(mp);
2287 2281 }
2288 2282 return (1);
2289 2283 }
2290 2284 list_insert_tail(&rsc->sc_txq[i].tx_dirty_list, bf);
2291 2285 bf->bf_in = in;
2292 2286 rtw_dma_start(&rsc->sc_regs, i);
2293 2287
2294 2288 mutex_exit(&rsc->sc_txq[i].txbuf_lock);
2295 2289 mutex_exit(&rsc->sc_txlock);
2296 2290
2297 2291 freemsg(mp);
2298 2292 return (0);
2299 2293 }
2300 2294
2301 2295 static mblk_t *
2302 2296 rtw_m_tx(void *arg, mblk_t *mp)
2303 2297 {
2304 2298 rtw_softc_t *rsc = arg;
2305 2299 ieee80211com_t *ic = (ieee80211com_t *)rsc;
2306 2300 mblk_t *next;
2307 2301
2308 2302 if (ic->ic_state != IEEE80211_S_RUN) {
2309 2303 freemsgchain(mp);
2310 2304 return (NULL);
2311 2305 }
2312 2306
2313 2307 while (mp != NULL) {
2314 2308 next = mp->b_next;
2315 2309 mp->b_next = NULL;
2316 2310
2317 2311 if (rtw_send(ic, mp, IEEE80211_FC0_TYPE_DATA)) {
2318 2312 mp->b_next = next;
2319 2313 break;
2320 2314 }
2321 2315 mp = next;
2322 2316 }
2323 2317
2324 2318 return (mp);
2325 2319
2326 2320 }
2327 2321
2328 2322 static void
2329 2323 rtw_next_scan(void *arg)
2330 2324 {
2331 2325 ieee80211com_t *ic = arg;
2332 2326 rtw_softc_t *rsc = (rtw_softc_t *)arg;
2333 2327
2334 2328 rsc->sc_scan_id = 0;
2335 2329 if (ic->ic_state == IEEE80211_S_SCAN) {
2336 2330 RTW_DPRINTF(RTW_DEBUG_TUNE, "rtw_next_scan\n");
2337 2331 (void) ieee80211_next_scan(ic);
2338 2332 }
2339 2333
2340 2334 }
2341 2335
2342 2336 static void
2343 2337 rtw_join_bss(rtw_softc_t *rsc, uint8_t *bssid, uint16_t intval0)
2344 2338 {
2345 2339 uint16_t bcnitv, intval;
2346 2340 int i;
2347 2341 struct rtw_regs *regs = &rsc->sc_regs;
2348 2342
2349 2343 for (i = 0; i < IEEE80211_ADDR_LEN; i++)
2350 2344 RTW_WRITE8(regs, RTW_BSSID + i, bssid[i]);
2351 2345
2352 2346 RTW_SYNC(regs, RTW_BSSID16, RTW_BSSID32);
2353 2347 rtw_set_access(regs, RTW_ACCESS_CONFIG);
2354 2348
2355 2349 RTW_WRITE8(regs, RTW_MSR, 0x8); /* sta mode link ok */
2356 2350 intval = MIN(intval0, PRESHIFT(RTW_BCNITV_BCNITV_MASK));
2357 2351
2358 2352 bcnitv = RTW_READ16(regs, RTW_BCNITV) & ~RTW_BCNITV_BCNITV_MASK;
2359 2353 bcnitv |= LSHIFT(intval, RTW_BCNITV_BCNITV_MASK);
2360 2354 RTW_WRITE16(regs, RTW_BCNITV, bcnitv);
2361 2355 RTW_WRITE16(regs, RTW_ATIMWND, LSHIFT(1, RTW_ATIMWND_ATIMWND));
2362 2356 RTW_WRITE16(regs, RTW_ATIMTRITV, LSHIFT(2, RTW_ATIMTRITV_ATIMTRITV));
2363 2357
2364 2358 rtw_set_access(regs, RTW_ACCESS_NONE);
2365 2359
2366 2360 /* TBD WEP */
2367 2361 /* RTW_WRITE8(regs, RTW_SCR, 0); */
2368 2362
2369 2363 rtw_io_enable(rsc, RTW_CR_RE | RTW_CR_TE, 1);
2370 2364 }
2371 2365
2372 2366 /*
2373 2367 * Set the starting transmit rate for a node.
2374 2368 */
2375 2369 static void
2376 2370 rtw_rate_ctl_start(rtw_softc_t *rsc, struct ieee80211_node *in)
2377 2371 {
2378 2372 ieee80211com_t *ic = (ieee80211com_t *)rsc;
2379 2373 int32_t srate;
2380 2374
2381 2375 if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) {
2382 2376 /*
2383 2377 * No fixed rate is requested. For 11b start with
2384 2378 * the highest negotiated rate; otherwise, for 11g
2385 2379 * and 11a, we start "in the middle" at 24Mb or 36Mb.
2386 2380 */
2387 2381 srate = in->in_rates.ir_nrates - 1;
2388 2382 if (ic->ic_curmode != IEEE80211_MODE_11B) {
2389 2383 /*
2390 2384 * Scan the negotiated rate set to find the
2391 2385 * closest rate.
2392 2386 */
2393 2387 /* NB: the rate set is assumed sorted */
2394 2388 for (; srate >= 0 && IEEE80211_RATE(srate) > 72;
2395 2389 srate--)
2396 2390 ;
2397 2391 }
2398 2392 } else {
2399 2393 /*
2400 2394 * A fixed rate is to be used; We know the rate is
2401 2395 * there because the rate set is checked when the
2402 2396 * station associates.
2403 2397 */
2404 2398 /* NB: the rate set is assumed sorted */
2405 2399 srate = in->in_rates.ir_nrates - 1;
2406 2400 for (; srate >= 0 && IEEE80211_RATE(srate) != ic->ic_fixed_rate;
2407 2401 srate--)
2408 2402 ;
2409 2403 }
2410 2404 in->in_txrate = srate;
2411 2405 }
2412 2406
2413 2407
2414 2408 /*
2415 2409 * Reset the rate control state for each 802.11 state transition.
2416 2410 */
2417 2411 static void
2418 2412 rtw_rate_ctl_reset(rtw_softc_t *rsc, enum ieee80211_state state)
2419 2413 {
2420 2414 ieee80211com_t *ic = &rsc->sc_ic;
2421 2415 ieee80211_node_t *in;
2422 2416
2423 2417 if (ic->ic_opmode == IEEE80211_M_STA) {
2424 2418 /*
2425 2419 * Reset local xmit state; this is really only
2426 2420 * meaningful when operating in station mode.
2427 2421 */
2428 2422 in = (struct ieee80211_node *)ic->ic_bss;
2429 2423
2430 2424 if (state == IEEE80211_S_RUN) {
2431 2425 rtw_rate_ctl_start(rsc, in);
2432 2426 } else {
2433 2427 in->in_txrate = 0;
2434 2428 }
2435 2429 }
2436 2430 }
2437 2431
2438 2432 /*
2439 2433 * Examine and potentially adjust the transmit rate.
2440 2434 */
2441 2435 static void
2442 2436 rtw_rate_ctl(void *arg)
2443 2437 {
2444 2438 ieee80211com_t *ic = (ieee80211com_t *)arg;
2445 2439 rtw_softc_t *rsc = (rtw_softc_t *)ic;
2446 2440 struct ieee80211_node *in = ic->ic_bss;
2447 2441 struct ieee80211_rateset *rs = &in->in_rates;
2448 2442 int32_t mod = 1, nrate, enough;
2449 2443
2450 2444 mutex_enter(&rsc->sc_genlock);
2451 2445 enough = (rsc->sc_tx_ok + rsc->sc_tx_err) >= 600? 1 : 0;
2452 2446
2453 2447 /* err ratio is high -> down */
2454 2448 if (enough && rsc->sc_tx_ok < rsc->sc_tx_err)
2455 2449 mod = -1;
2456 2450
2457 2451 nrate = in->in_txrate;
2458 2452 switch (mod) {
2459 2453 case -1:
2460 2454 if (nrate > 0) {
2461 2455 nrate--;
2462 2456 }
2463 2457 break;
2464 2458 case 1:
2465 2459 if (nrate + 1 < rs->ir_nrates) {
2466 2460 nrate++;
2467 2461 }
2468 2462 break;
2469 2463 }
2470 2464
2471 2465 if (nrate != in->in_txrate)
2472 2466 in->in_txrate = nrate;
2473 2467 rsc->sc_tx_ok = rsc->sc_tx_err = rsc->sc_tx_retr = 0;
2474 2468 mutex_exit(&rsc->sc_genlock);
2475 2469 if (ic->ic_state == IEEE80211_S_RUN)
2476 2470 rsc->sc_ratectl_id = timeout(rtw_rate_ctl, ic,
2477 2471 drv_usectohz(1000000));
2478 2472 }
2479 2473
2480 2474 static int32_t
2481 2475 rtw_new_state(ieee80211com_t *ic, enum ieee80211_state nstate, int arg)
2482 2476 {
2483 2477 rtw_softc_t *rsc = (rtw_softc_t *)ic;
2484 2478 int error;
2485 2479 enum ieee80211_state ostate;
2486 2480
2487 2481 ostate = ic->ic_state;
2488 2482
2489 2483 RTW_DPRINTF(RTW_DEBUG_ATTACH,
2490 2484 "rtw_new_state: ostate:0x%x, nstate:0x%x, opmode:0x%x\n",
2491 2485 ostate, nstate, ic->ic_opmode);
2492 2486
2493 2487
2494 2488 mutex_enter(&rsc->sc_genlock);
2495 2489 if (rsc->sc_scan_id != 0) {
2496 2490 (void) untimeout(rsc->sc_scan_id);
2497 2491 rsc->sc_scan_id = 0;
2498 2492 }
2499 2493 if (rsc->sc_ratectl_id != 0) {
2500 2494 (void) untimeout(rsc->sc_ratectl_id);
2501 2495 rsc->sc_ratectl_id = 0;
2502 2496 }
2503 2497 rtw_rate_ctl_reset(rsc, nstate);
2504 2498 if (ostate == IEEE80211_S_INIT && nstate != IEEE80211_S_INIT)
2505 2499 (void) rtw_pwrstate(rsc, RTW_ON);
2506 2500 if (nstate != IEEE80211_S_INIT) {
2507 2501 if ((error = rtw_tune(rsc)) != 0) {
2508 2502 mutex_exit(&rsc->sc_genlock);
2509 2503 return (error);
2510 2504 }
2511 2505 }
2512 2506 switch (nstate) {
2513 2507 case IEEE80211_S_INIT:
2514 2508 RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw_new_state: S_INIT\n");
2515 2509 break;
2516 2510 case IEEE80211_S_SCAN:
2517 2511 RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw_new_state: S_SCAN\n");
2518 2512 rsc->sc_scan_id = timeout(rtw_next_scan, ic,
2519 2513 drv_usectohz(200000));
2520 2514 rtw_set_nettype(rsc, IEEE80211_M_MONITOR);
2521 2515 break;
2522 2516 case IEEE80211_S_RUN:
2523 2517 RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw_new_state: S_RUN\n");
2524 2518 switch (ic->ic_opmode) {
2525 2519 case IEEE80211_M_HOSTAP:
2526 2520 case IEEE80211_M_IBSS:
2527 2521 rtw_set_nettype(rsc, IEEE80211_M_MONITOR);
2528 2522 /* TBD */
2529 2523 /*FALLTHROUGH*/
2530 2524 case IEEE80211_M_AHDEMO:
2531 2525 case IEEE80211_M_STA:
2532 2526 RTW_DPRINTF(RTW_DEBUG_ATTACH,
2533 2527 "rtw_new_state: sta\n");
2534 2528 rtw_join_bss(rsc, ic->ic_bss->in_bssid, 0);
2535 2529 rsc->sc_ratectl_id = timeout(rtw_rate_ctl, ic,
2536 2530 drv_usectohz(1000000));
2537 2531 break;
2538 2532 case IEEE80211_M_MONITOR:
2539 2533 break;
2540 2534 }
2541 2535 rtw_set_nettype(rsc, ic->ic_opmode);
2542 2536 break;
2543 2537 case IEEE80211_S_ASSOC:
2544 2538 case IEEE80211_S_AUTH:
2545 2539 break;
2546 2540 }
2547 2541
2548 2542 mutex_exit(&rsc->sc_genlock);
2549 2543 /*
2550 2544 * Invoke the parent method to complete the work.
2551 2545 */
2552 2546 error = rsc->sc_newstate(ic, nstate, arg);
2553 2547
2554 2548 return (error);
2555 2549 }
2556 2550
2557 2551 static void
2558 2552 rtw_intr_rx(rtw_softc_t *rsc)
2559 2553 {
2560 2554 #define IS_BEACON(__fc0) \
2561 2555 ((__fc0 & (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) ==\
2562 2556 (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_BEACON))
2563 2557 /*
2564 2558 * ratetbl[4] = {2, 4, 11, 22};
2565 2559 */
2566 2560 struct rtw_rxbuf *bf;
2567 2561 struct rtw_rxdesc *ds;
2568 2562 int hwrate, len, rssi;
2569 2563 uint32_t hstat, hrssi, htsftl;
2570 2564 int is_last, next, n = 0, i;
2571 2565 struct ieee80211_frame *wh;
2572 2566 ieee80211com_t *ic = (ieee80211com_t *)rsc;
2573 2567 mblk_t *mp;
2574 2568
2575 2569 RTW_DPRINTF(RTW_DEBUG_RECV, "%s rtw_intr_rx: enter ic_state=%x\n",
2576 2570 __func__, rsc->sc_ic.ic_state);
2577 2571 mutex_enter(&rsc->rxbuf_lock);
2578 2572 next = rsc->rx_next;
2579 2573 mutex_exit(&rsc->rxbuf_lock);
2580 2574 for (i = 0; i < RTW_RXQLEN; i++) {
2581 2575 RTW_DMA_SYNC_DESC(rsc->sc_desc_dma,
2582 2576 RTW_DESC_OFFSET(hd_rx, next),
2583 2577 sizeof (struct rtw_rxdesc),
2584 2578 DDI_DMA_SYNC_FORKERNEL);
2585 2579 n++;
2586 2580 bf = rsc->rxbuf_h + next;
2587 2581 ds = bf->rxdesc;
2588 2582 hstat = (ds->rd_stat);
2589 2583 hrssi = ds->rd_rssi;
2590 2584 htsftl = ds->rd_tsftl;
2591 2585 /* htsfth = ds->rd_tsfth; */
2592 2586 RTW_DPRINTF(RTW_DEBUG_RECV, "%s: stat=%x\n", __func__, hstat);
2593 2587 /* still belongs to NIC */
2594 2588 if ((hstat & RTW_RXSTAT_OWN) != 0) {
2595 2589 if (n > 1) {
2596 2590 RTW_DPRINTF(RTW_DEBUG_RECV,
2597 2591 "%s: n > 1\n", __func__);
2598 2592 break;
2599 2593 }
2600 2594 RTW_DMA_SYNC_DESC(rsc->sc_desc_dma,
2601 2595 RTW_DESC_OFFSET(hd_rx, 0),
2602 2596 sizeof (struct rtw_rxdesc),
2603 2597 DDI_DMA_SYNC_FORCPU);
2604 2598 bf = rsc->rxbuf_h;
2605 2599 ds = bf->rxdesc;
2606 2600 hstat = (ds->rd_stat);
2607 2601 if ((hstat & RTW_RXSTAT_OWN) != 0)
2608 2602 break;
2609 2603 next = 0 /* RTW_RXQLEN - 1 */;
2610 2604 continue;
2611 2605 }
2612 2606
2613 2607 rsc->sc_pktrcv64++;
2614 2608 if ((hstat & RTW_RXSTAT_IOERROR) != 0) {
2615 2609 RTW_DPRINTF(RTW_DEBUG_RECV,
2616 2610 "rtw: DMA error/FIFO overflow %08x, "
2617 2611 "rx descriptor %d\n",
2618 2612 hstat & RTW_RXSTAT_IOERROR, next);
2619 2613 goto next;
2620 2614 }
2621 2615
2622 2616 len = MASK_AND_RSHIFT(hstat, RTW_RXSTAT_LENGTH_MASK);
2623 2617 rsc->sc_bytercv64 += len;
2624 2618
2625 2619 /* CRC is included with the packet; trim it off. */
2626 2620 /* len -= IEEE80211_CRC_LEN; */
2627 2621
2628 2622 hwrate = MASK_AND_RSHIFT(hstat, RTW_RXSTAT_RATE_MASK);
2629 2623 if (hwrate >= 4) {
2630 2624 goto next;
2631 2625 }
2632 2626
2633 2627 if ((hstat & RTW_RXSTAT_RES) != 0 &&
2634 2628 rsc->sc_ic.ic_opmode != IEEE80211_M_MONITOR) {
2635 2629 goto next;
2636 2630 }
2637 2631
2638 2632 /* if bad flags, skip descriptor */
2639 2633 if ((hstat & RTW_RXSTAT_ONESEG) != RTW_RXSTAT_ONESEG) {
2640 2634 RTW_DPRINTF(RTW_DEBUG_RECV,
2641 2635 "rtw too many rx segments\n");
2642 2636 goto next;
2643 2637 }
2644 2638
2645 2639 if (rsc->sc_rfchipid == RTW_RFCHIPID_PHILIPS)
2646 2640 rssi = MASK_AND_RSHIFT(hrssi, RTW_RXRSSI_RSSI);
2647 2641 else {
2648 2642 rssi = MASK_AND_RSHIFT(hrssi, RTW_RXRSSI_IMR_RSSI);
2649 2643 /*
2650 2644 * TBD find out each front-end's LNA gain in the
2651 2645 * front-end's units
2652 2646 */
2653 2647 if ((hrssi & RTW_RXRSSI_IMR_LNA) == 0)
2654 2648 rssi |= 0x80;
2655 2649 }
2656 2650 /* sq = MASK_AND_RSHIFT(hrssi, RTW_RXRSSI_SQ); */
2657 2651
2658 2652
2659 2653 /* deal with the frame itself here */
2660 2654 mp = allocb(rsc->sc_dmabuf_size, BPRI_MED);
2661 2655 if (mp == NULL) {
2662 2656 cmn_err(CE_WARN, "rtw: alloc mblk error");
2663 2657 rsc->sc_norcvbuf++;
2664 2658 return;
2665 2659 }
2666 2660 len -= IEEE80211_CRC_LEN;
2667 2661 RTW_DMA_SYNC(bf->bf_dma, DDI_DMA_SYNC_FORKERNEL);
2668 2662 bcopy(bf->bf_dma.mem_va, mp->b_rptr, len);
2669 2663 mp->b_wptr += len;
2670 2664 wh = (struct ieee80211_frame *)mp->b_rptr;
2671 2665 if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
2672 2666 IEEE80211_FC0_TYPE_CTL) {
2673 2667 cmn_err(CE_WARN, "TYPE CTL !!\n");
2674 2668 freemsg(mp);
2675 2669 goto next;
2676 2670 }
2677 2671 (void) ieee80211_input(ic, mp, ic->ic_bss, rssi, htsftl);
2678 2672 next:
2679 2673 if (next == 63)
2680 2674 is_last = 1;
2681 2675 else
2682 2676 is_last = 0;
2683 2677 rtw_rxdesc_init(rsc, bf, next, is_last);
2684 2678
2685 2679 next = (next + 1)%RTW_RXQLEN;
2686 2680 RTW_DPRINTF(RTW_DEBUG_RECV, "%s: next = %d\n", __func__, next);
2687 2681 }
2688 2682 mutex_enter(&rsc->rxbuf_lock);
2689 2683 rsc->rx_next = next;
2690 2684 mutex_exit(&rsc->rxbuf_lock);
2691 2685 }
2692 2686
2693 2687 static void
2694 2688 rtw_ring_recycling(rtw_softc_t *rsc, uint16_t isr, uint32_t pri)
2695 2689 {
2696 2690 struct rtw_txbuf *bf;
2697 2691 struct rtw_txdesc *ds;
2698 2692 uint32_t hstat;
2699 2693 uint32_t head = 0;
2700 2694 uint32_t cnt = 0, idx = 0;
2701 2695
2702 2696 mutex_enter(&rsc->sc_txq[pri].txbuf_lock);
2703 2697 head = RTW_READ(&rsc->sc_regs, RTW_TNPDA);
2704 2698 if (head == rsc->hw_go) {
2705 2699 mutex_exit(&rsc->sc_txq[pri].txbuf_lock);
2706 2700 return;
2707 2701 }
2708 2702 RTW_DPRINTF(RTW_DEBUG_XMIT, "rtw_ring_recycling: enter ic_state=%x\n",
2709 2703 rsc->sc_ic.ic_state);
2710 2704
2711 2705 bf = list_head(&rsc->sc_txq[pri].tx_dirty_list);
2712 2706 if (bf == NULL) {
2713 2707 RTW_DPRINTF(RTW_DEBUG_XMIT,
2714 2708 "rtw_ring_recycling: dirty bf[%d] NULL\n", pri);
2715 2709 mutex_exit(&rsc->sc_txq[pri].txbuf_lock);
2716 2710 return;
2717 2711 }
2718 2712
2719 2713 while ((bf != NULL) && (rsc->hw_go != head)) {
2720 2714 cnt++;
2721 2715 idx = (rsc->hw_go - rsc->hw_start) / sizeof (struct rtw_txdesc);
2722 2716 if (idx == 63)
2723 2717 rsc->hw_go = rsc->hw_start;
2724 2718 else
2725 2719 rsc->hw_go += sizeof (struct rtw_txdesc);
2726 2720 RTW_DMA_SYNC_DESC(rsc->sc_desc_dma,
2727 2721 RTW_DESC_OFFSET(hd_txmd, idx),
2728 2722 sizeof (struct rtw_txdesc),
2729 2723 DDI_DMA_SYNC_FORCPU);
2730 2724
2731 2725 RTW_DPRINTF(RTW_DEBUG_XMIT, "Head = 0x%x\n", head);
2732 2726 ds = bf->txdesc;
2733 2727 hstat = (ds->td_stat);
2734 2728 ds->td_len = ds->td_len & 0xfff;
2735 2729 RTW_DPRINTF(RTW_DEBUG_XMIT,
2736 2730 "%s rtw_ring_recycling: stat=%x, pri=%x\n",
2737 2731 __func__, hstat, pri);
2738 2732 if (hstat & RTW_TXSTAT_TOK)
2739 2733 rsc->sc_tx_ok++;
2740 2734 else {
2741 2735 RTW_DPRINTF(RTW_DEBUG_XMIT,
2742 2736 "TX err @%d, o %d, retry[%d], isr[0x%x], cnt %d\n",
2743 2737 idx, (hstat & RTW_TXSTAT_OWN)?1:0,
2744 2738 (hstat & RTW_TXSTAT_DRC_MASK), isr, cnt);
2745 2739 if ((hstat & RTW_TXSTAT_DRC_MASK) <= 4) {
2746 2740 rsc->sc_tx_ok++;
2747 2741 } else {
2748 2742 rsc->sc_tx_err++;
2749 2743 }
2750 2744 }
2751 2745 rsc->sc_tx_retr +=
2752 2746 (hstat & RTW_TXSTAT_DRC_MASK);
2753 2747 rsc->sc_xmtretry +=
2754 2748 (hstat & RTW_TXSTAT_DRC_MASK);
2755 2749 list_remove(&rsc->sc_txq[pri].tx_dirty_list, bf);
2756 2750 list_insert_tail(&rsc->sc_txq[pri].tx_free_list,
2757 2751 bf);
2758 2752 (rsc->sc_txq[pri].tx_nfree)++;
2759 2753 if (rsc->sc_need_reschedule == 1) {
2760 2754 mac_tx_update(rsc->sc_ic.ic_mach);
2761 2755 rsc->sc_need_reschedule = 0;
2762 2756 }
2763 2757 RTW_DPRINTF(RTW_DEBUG_XMIT,
2764 2758 "rtw_ring_recycling: nfree[%d]=%d\n",
2765 2759 pri, rsc->sc_txq[pri].tx_nfree);
2766 2760 bzero((uint8_t *)ds, sizeof (struct rtw_txdesc));
2767 2761 RTW_DMA_SYNC_DESC(rsc->sc_desc_dma,
2768 2762 RTW_DESC_OFFSET(hd_txmd, idx),
2769 2763 sizeof (struct rtw_txdesc),
2770 2764 DDI_DMA_SYNC_FORDEV);
2771 2765 bf = list_head(&rsc->sc_txq[pri].tx_dirty_list);
2772 2766 }
2773 2767 mutex_exit(&rsc->sc_txq[pri].txbuf_lock);
2774 2768 }
2775 2769
2776 2770 static void
2777 2771 rtw_intr_timeout(rtw_softc_t *rsc)
2778 2772 {
2779 2773 rtw_resume_ticks(rsc);
2780 2774 }
2781 2775
2782 2776 static uint_t
2783 2777 rtw_intr(caddr_t arg)
2784 2778 {
2785 2779 /* LINTED E_BAD_PTR_CAST_ALIGN */
2786 2780 rtw_softc_t *rsc = (rtw_softc_t *)arg;
2787 2781 struct rtw_regs *regs = &rsc->sc_regs;
2788 2782 uint16_t isr = 0;
2789 2783
2790 2784 mutex_enter(&rsc->sc_genlock);
2791 2785 isr = RTW_READ16(regs, RTW_ISR);
2792 2786 RTW_WRITE16(regs, RTW_ISR, isr);
2793 2787
2794 2788 if (isr == 0) {
2795 2789 mutex_exit(&rsc->sc_genlock);
2796 2790 return (DDI_INTR_UNCLAIMED);
2797 2791 }
2798 2792
2799 2793 #ifdef DEBUG
2800 2794 #define PRINTINTR(flag) { \
2801 2795 if ((isr & flag) != 0) { \
2802 2796 RTW_DPRINTF(RTW_DEBUG_INTR, "|" #flag); \
2803 2797 } \
2804 2798 }
2805 2799
2806 2800 if ((rtw_dbg_flags & RTW_DEBUG_INTR) != 0 && isr != 0) {
2807 2801
2808 2802 RTW_DPRINTF(RTW_DEBUG_INTR, "rtw: reg[ISR] = %x", isr);
2809 2803
2810 2804 PRINTINTR(RTW_INTR_TXFOVW);
2811 2805 PRINTINTR(RTW_INTR_TIMEOUT);
2812 2806 PRINTINTR(RTW_INTR_BCNINT);
2813 2807 PRINTINTR(RTW_INTR_ATIMINT);
2814 2808 PRINTINTR(RTW_INTR_TBDER);
2815 2809 PRINTINTR(RTW_INTR_TBDOK);
2816 2810 PRINTINTR(RTW_INTR_THPDER);
2817 2811 PRINTINTR(RTW_INTR_THPDOK);
2818 2812 PRINTINTR(RTW_INTR_TNPDER);
2819 2813 PRINTINTR(RTW_INTR_TNPDOK);
2820 2814 PRINTINTR(RTW_INTR_RXFOVW);
2821 2815 PRINTINTR(RTW_INTR_RDU);
2822 2816 PRINTINTR(RTW_INTR_TLPDER);
2823 2817 PRINTINTR(RTW_INTR_TLPDOK);
2824 2818 PRINTINTR(RTW_INTR_RER);
2825 2819 PRINTINTR(RTW_INTR_ROK);
2826 2820 }
2827 2821 #undef PRINTINTR
2828 2822 #endif /* DEBUG */
2829 2823
2830 2824 rsc->sc_intr++;
2831 2825
2832 2826 if ((isr & RTW_INTR_RX) != 0) {
2833 2827 mutex_exit(&rsc->sc_genlock);
2834 2828 rtw_intr_rx(rsc);
2835 2829 mutex_enter(&rsc->sc_genlock);
2836 2830 }
2837 2831 if ((isr & RTW_INTR_TIMEOUT) != 0)
2838 2832 rtw_intr_timeout(rsc);
2839 2833
2840 2834 if ((isr & RTW_INTR_TX) != 0)
2841 2835 rtw_ring_recycling(rsc, isr, 1);
2842 2836 mutex_exit(&rsc->sc_genlock);
2843 2837 return (DDI_INTR_CLAIMED);
2844 2838 }
2845 2839
2846 2840 static void
2847 2841 rtw_stop(void *arg)
2848 2842 {
2849 2843 rtw_softc_t *rsc = (rtw_softc_t *)arg;
2850 2844 struct rtw_regs *regs = &rsc->sc_regs;
2851 2845
2852 2846 mutex_enter(&rsc->sc_genlock);
2853 2847 rtw_disable_interrupts(regs);
2854 2848 rtw_io_enable(rsc, RTW_CR_RE | RTW_CR_TE, 0);
2855 2849 RTW_WRITE8(regs, RTW_TPPOLL, RTW_TPPOLL_SALL);
2856 2850 rsc->sc_invalid = 1;
2857 2851 mutex_exit(&rsc->sc_genlock);
2858 2852 }
2859 2853
2860 2854 static void
2861 2855 rtw_m_stop(void *arg)
2862 2856 {
2863 2857 rtw_softc_t *rsc = (rtw_softc_t *)arg;
2864 2858
2865 2859 (void) ieee80211_new_state(&rsc->sc_ic, IEEE80211_S_INIT, -1);
2866 2860 rtw_stop(rsc);
2867 2861 }
2868 2862
2869 2863 /*
2870 2864 * quiesce(9E) entry point.
2871 2865 *
2872 2866 * This function is called when the system is single-threaded at high
2873 2867 * PIL with preemption disabled. Therefore, this function must not be
2874 2868 * blocked.
2875 2869 *
2876 2870 * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
2877 2871 * DDI_FAILURE indicates an error condition and should almost never happen.
2878 2872 */
2879 2873 int
2880 2874 rtw_quiesce(dev_info_t *dip)
2881 2875 {
2882 2876 rtw_softc_t *rsc = NULL;
2883 2877 struct rtw_regs *regs;
2884 2878
2885 2879 rsc = ddi_get_soft_state(rtw_soft_state_p, ddi_get_instance(dip));
2886 2880 ASSERT(rsc != NULL);
2887 2881 regs = &rsc->sc_regs;
2888 2882
2889 2883 rtw_dbg_flags = 0;
2890 2884 rtw_disable_interrupts(regs);
2891 2885 rtw_io_enable(rsc, RTW_CR_RE | RTW_CR_TE, 0);
2892 2886 RTW_WRITE8(regs, RTW_TPPOLL, RTW_TPPOLL_SALL);
2893 2887
2894 2888 return (DDI_SUCCESS);
2895 2889 }
2896 2890
2897 2891 /*
2898 2892 * callback functions for /get/set properties
2899 2893 */
2900 2894 static int
2901 2895 rtw_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
2902 2896 uint_t wldp_length, const void *wldp_buf)
2903 2897 {
2904 2898 rtw_softc_t *rsc = (rtw_softc_t *)arg;
2905 2899 struct ieee80211com *ic = &rsc->sc_ic;
2906 2900 int err;
2907 2901
2908 2902 err = ieee80211_setprop(ic, pr_name, wldp_pr_num,
2909 2903 wldp_length, wldp_buf);
2910 2904 if (err == ENETRESET) {
2911 2905 if (ic->ic_des_esslen && (rsc->sc_invalid == 0)) {
2912 2906 (void) rtw_init(rsc);
2913 2907 (void) ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
2914 2908 }
2915 2909 err = 0;
2916 2910 }
2917 2911 return (err);
2918 2912 }
2919 2913
2920 2914 static int
2921 2915 rtw_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
2922 2916 uint_t wldp_length, void *wldp_buf)
2923 2917 {
2924 2918 rtw_softc_t *rsc = arg;
2925 2919 int err;
2926 2920
2927 2921 err = ieee80211_getprop(&rsc->sc_ic, pr_name, wldp_pr_num,
2928 2922 wldp_length, wldp_buf);
2929 2923
2930 2924 return (err);
2931 2925 }
2932 2926
2933 2927 static void
2934 2928 rtw_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
2935 2929 mac_prop_info_handle_t prh)
2936 2930 {
2937 2931 rtw_softc_t *rsc = arg;
2938 2932
2939 2933 ieee80211_propinfo(&rsc->sc_ic, pr_name, wldp_pr_num, prh);
2940 2934 }
2941 2935
2942 2936 static int
2943 2937 rtw_m_start(void *arg)
2944 2938 {
2945 2939 rtw_softc_t *rsc = (rtw_softc_t *)arg;
2946 2940 ieee80211com_t *ic = (ieee80211com_t *)rsc;
2947 2941 int ret;
2948 2942 #ifdef DEBUG
2949 2943 rtw_print_regs(&rsc->sc_regs, "rtw", "rtw_start");
2950 2944 #endif
2951 2945
2952 2946 ret = rtw_init(rsc);
2953 2947 if (ret) {
2954 2948 cmn_err(CE_WARN, "rtw: failed to do rtw_init\n");
2955 2949 return (EIO);
2956 2950 }
2957 2951 (void) ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
2958 2952 return (0);
2959 2953 }
2960 2954
2961 2955
2962 2956 static int
2963 2957 rtw_m_unicst(void *arg, const uint8_t *macaddr)
2964 2958 {
2965 2959 rtw_softc_t *rsc = (rtw_softc_t *)arg;
2966 2960 ieee80211com_t *ic = (ieee80211com_t *)rsc;
2967 2961 struct rtw_regs *regs = &rsc->sc_regs;
2968 2962 uint32_t t;
2969 2963
2970 2964 mutex_enter(&rsc->sc_genlock);
2971 2965 bcopy(macaddr, ic->ic_macaddr, 6);
2972 2966 t = ((*macaddr)<<24) | ((*(macaddr + 1))<<16) |
2973 2967 ((*(macaddr + 2))<<8) | (*(macaddr + 3));
2974 2968 RTW_WRITE(regs, RTW_IDR0, ntohl(t));
2975 2969 t = ((*(macaddr + 4))<<24) | ((*(macaddr + 5))<<16);
2976 2970 RTW_WRITE(regs, RTW_IDR1, ntohl(t));
2977 2971 mutex_exit(&rsc->sc_genlock);
2978 2972 return (0);
2979 2973 }
2980 2974
2981 2975 static int
2982 2976 rtw_m_promisc(void *arg, boolean_t on)
2983 2977 {
2984 2978 rtw_softc_t *rsc = (rtw_softc_t *)arg;
2985 2979 struct rtw_regs *regs = &rsc->sc_regs;
2986 2980
2987 2981 mutex_enter(&rsc->sc_genlock);
2988 2982
2989 2983 if (on)
2990 2984 rsc->sc_rcr |= RTW_RCR_PROMIC;
2991 2985 else
2992 2986 rsc->sc_rcr &= ~RTW_RCR_PROMIC;
2993 2987
2994 2988 RTW_WRITE(regs, RTW_RCR, rsc->sc_rcr);
2995 2989
2996 2990 mutex_exit(&rsc->sc_genlock);
2997 2991 return (0);
2998 2992 }
2999 2993
3000 2994 static int
3001 2995 rtw_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr)
3002 2996 {
3003 2997 rtw_softc_t *rsc = (rtw_softc_t *)arg;
3004 2998 struct rtw_regs *regs = &rsc->sc_regs;
3005 2999 uint32_t t;
3006 3000
3007 3001 mutex_enter(&rsc->sc_genlock);
3008 3002 if (add) {
3009 3003 rsc->sc_rcr |= RTW_RCR_AM;
3010 3004 t = ((*macaddr)<<24) | ((*(macaddr + 1))<<16) |
3011 3005 ((*(macaddr + 2))<<8) | (*(macaddr + 3));
3012 3006 RTW_WRITE(regs, RTW_MAR0, ntohl(t));
3013 3007 t = ((*(macaddr + 4))<<24) | ((*(macaddr + 5))<<16);
3014 3008 RTW_WRITE(regs, RTW_MAR1, ntohl(t));
3015 3009 RTW_WRITE(regs, RTW_RCR, rsc->sc_rcr);
3016 3010 RTW_SYNC(regs, RTW_MAR0, RTW_RCR);
3017 3011 } else {
3018 3012 rsc->sc_rcr &= ~RTW_RCR_AM;
3019 3013 RTW_WRITE(regs, RTW_MAR0, 0);
3020 3014 RTW_WRITE(regs, RTW_MAR1, 0);
3021 3015 RTW_WRITE(regs, RTW_RCR, rsc->sc_rcr);
3022 3016 RTW_SYNC(regs, RTW_MAR0, RTW_RCR);
3023 3017 }
3024 3018 mutex_exit(&rsc->sc_genlock);
3025 3019 return (0);
3026 3020 }
3027 3021
3028 3022 static void
3029 3023 rtw_m_ioctl(void* arg, queue_t *wq, mblk_t *mp)
3030 3024 {
3031 3025 rtw_softc_t *rsc = arg;
3032 3026 struct ieee80211com *ic = &rsc->sc_ic;
3033 3027 int err;
3034 3028
3035 3029 err = ieee80211_ioctl(ic, wq, mp);
3036 3030 if (err == ENETRESET) {
3037 3031 if (ic->ic_des_esslen && (rsc->sc_invalid == 0)) {
3038 3032 (void) rtw_init(rsc);
3039 3033 (void) ieee80211_new_state(ic,
3040 3034 IEEE80211_S_SCAN, -1);
3041 3035 }
3042 3036 }
3043 3037 }
3044 3038
3045 3039 static int
3046 3040 rtw_m_stat(void *arg, uint_t stat, uint64_t *val)
3047 3041 {
3048 3042 rtw_softc_t *rsc = (rtw_softc_t *)arg;
3049 3043 ieee80211com_t *ic = &rsc->sc_ic;
3050 3044 struct ieee80211_node *in = 0;
3051 3045 struct ieee80211_rateset *rs = 0;
3052 3046
3053 3047 mutex_enter(&rsc->sc_genlock);
3054 3048 switch (stat) {
3055 3049 case MAC_STAT_IFSPEED:
3056 3050 in = ic->ic_bss;
3057 3051 rs = &in->in_rates;
3058 3052 *val = ((ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) ?
3059 3053 (rs->ir_rates[in->in_txrate] & IEEE80211_RATE_VAL)
3060 3054 : ic->ic_fixed_rate) / 2 * 1000000;
3061 3055 break;
3062 3056 case MAC_STAT_NOXMTBUF:
3063 3057 *val = rsc->sc_noxmtbuf;
3064 3058 break;
3065 3059 case MAC_STAT_NORCVBUF:
3066 3060 *val = rsc->sc_norcvbuf;
3067 3061 break;
3068 3062 case MAC_STAT_RBYTES:
3069 3063 *val = rsc->sc_bytercv64;
3070 3064 break;
3071 3065 case MAC_STAT_IPACKETS:
3072 3066 *val = rsc->sc_pktrcv64;
3073 3067 break;
3074 3068 case MAC_STAT_OBYTES:
3075 3069 *val = rsc->sc_bytexmt64;
3076 3070 break;
3077 3071 case MAC_STAT_OPACKETS:
3078 3072 *val = rsc->sc_pktxmt64;
3079 3073 break;
3080 3074 case WIFI_STAT_TX_RETRANS:
3081 3075 *val = rsc->sc_xmtretry;
3082 3076 break;
3083 3077 case WIFI_STAT_TX_FRAGS:
3084 3078 case WIFI_STAT_MCAST_TX:
3085 3079 case WIFI_STAT_RTS_SUCCESS:
3086 3080 case WIFI_STAT_RTS_FAILURE:
3087 3081 case WIFI_STAT_ACK_FAILURE:
3088 3082 case WIFI_STAT_RX_FRAGS:
3089 3083 case WIFI_STAT_MCAST_RX:
3090 3084 case WIFI_STAT_RX_DUPS:
3091 3085 mutex_exit(&rsc->sc_genlock);
3092 3086 return (ieee80211_stat(ic, stat, val));
3093 3087 default:
3094 3088 *val = 0;
3095 3089 break;
3096 3090 }
3097 3091 mutex_exit(&rsc->sc_genlock);
3098 3092
3099 3093 return (0);
3100 3094 }
3101 3095
3102 3096
3103 3097 static void
3104 3098 rtw_mutex_destroy(rtw_softc_t *rsc)
3105 3099 {
3106 3100 int i;
3107 3101
3108 3102 mutex_destroy(&rsc->rxbuf_lock);
3109 3103 mutex_destroy(&rsc->sc_txlock);
3110 3104 for (i = 0; i < RTW_NTXPRI; i++) {
3111 3105 mutex_destroy(&rsc->sc_txq[RTW_NTXPRI - 1 - i].txbuf_lock);
3112 3106 }
3113 3107 mutex_destroy(&rsc->sc_genlock);
3114 3108 }
3115 3109
3116 3110 static int
3117 3111 rtw_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
3118 3112 {
3119 3113 rtw_softc_t *rsc;
3120 3114 ieee80211com_t *ic;
3121 3115 uint8_t csz;
3122 3116 uint32_t i;
3123 3117 uint16_t vendor_id, device_id, command;
3124 3118 int32_t err;
3125 3119 char strbuf[32];
3126 3120 wifi_data_t wd = { 0 };
3127 3121 mac_register_t *macp;
3128 3122 int instance = ddi_get_instance(devinfo);
3129 3123
3130 3124 switch (cmd) {
3131 3125 case DDI_ATTACH:
3132 3126 break;
3133 3127 case DDI_RESUME:
3134 3128 rsc = ddi_get_soft_state(rtw_soft_state_p,
3135 3129 ddi_get_instance(devinfo));
3136 3130 ASSERT(rsc != NULL);
3137 3131 mutex_enter(&rsc->sc_genlock);
3138 3132 rsc->sc_flags &= ~RTW_F_SUSPEND;
3139 3133 mutex_exit(&rsc->sc_genlock);
3140 3134 if ((rsc->sc_flags & RTW_F_PLUMBED)) {
3141 3135 err = rtw_init(rsc);
3142 3136 if (err == 0) {
3143 3137 mutex_enter(&rsc->sc_genlock);
3144 3138 rsc->sc_flags &= ~RTW_F_PLUMBED;
3145 3139 mutex_exit(&rsc->sc_genlock);
3146 3140 }
3147 3141 }
3148 3142 return (DDI_SUCCESS);
3149 3143 default:
3150 3144 return (DDI_FAILURE);
3151 3145 }
3152 3146
3153 3147 if (ddi_soft_state_zalloc(rtw_soft_state_p,
3154 3148 ddi_get_instance(devinfo)) != DDI_SUCCESS) {
3155 3149 RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): "
3156 3150 "Unable to alloc softstate\n");
3157 3151 return (DDI_FAILURE);
3158 3152 }
3159 3153
3160 3154 rsc = ddi_get_soft_state(rtw_soft_state_p, ddi_get_instance(devinfo));
3161 3155 ic = &rsc->sc_ic;
3162 3156 rsc->sc_dev = devinfo;
3163 3157
3164 3158 err = ddi_regs_map_setup(devinfo, 0, (caddr_t *)&rsc->sc_cfg_base, 0, 0,
3165 3159 &rtw_reg_accattr, &rsc->sc_cfg_handle);
3166 3160 if (err != DDI_SUCCESS) {
3167 3161 RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): "
3168 3162 "ddi_regs_map_setup() failed");
3169 3163 goto attach_fail0;
3170 3164 }
3171 3165 csz = ddi_get8(rsc->sc_cfg_handle,
3172 3166 (uint8_t *)(rsc->sc_cfg_base + PCI_CONF_CACHE_LINESZ));
3173 3167 if (!csz)
3174 3168 csz = 16;
3175 3169 rsc->sc_cachelsz = csz << 2;
3176 3170 vendor_id = ddi_get16(rsc->sc_cfg_handle,
3177 3171 (uint16_t *)((uintptr_t)rsc->sc_cfg_base + PCI_CONF_VENID));
3178 3172 device_id = ddi_get16(rsc->sc_cfg_handle,
3179 3173 (uint16_t *)((uintptr_t)rsc->sc_cfg_base + PCI_CONF_DEVID));
3180 3174 RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): vendor 0x%x, "
3181 3175 "device id 0x%x, cache size %d\n", vendor_id, device_id, csz);
3182 3176
3183 3177 /*
3184 3178 * Enable response to memory space accesses,
3185 3179 * and enabe bus master.
3186 3180 */
3187 3181 command = PCI_COMM_MAE | PCI_COMM_ME;
3188 3182 ddi_put16(rsc->sc_cfg_handle,
3189 3183 (uint16_t *)((uintptr_t)rsc->sc_cfg_base + PCI_CONF_COMM), command);
3190 3184 RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): "
3191 3185 "set command reg to 0x%x \n", command);
3192 3186
3193 3187 ddi_put8(rsc->sc_cfg_handle,
3194 3188 (uint8_t *)(rsc->sc_cfg_base + PCI_CONF_LATENCY_TIMER), 0xa8);
3195 3189
3196 3190 ddi_regs_map_free(&rsc->sc_cfg_handle);
3197 3191
3198 3192 err = ddi_regs_map_setup(devinfo, 2, (caddr_t *)&rsc->sc_regs.r_base,
3199 3193 0, 0, &rtw_reg_accattr, &rsc->sc_regs.r_handle);
3200 3194 if (err != DDI_SUCCESS) {
3201 3195 RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): "
3202 3196 "ddi_regs_map_setup() failed");
3203 3197 goto attach_fail0;
3204 3198 }
3205 3199 RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: r_base=%x, r_handle=%x\n",
3206 3200 rsc->sc_regs.r_base, rsc->sc_regs.r_handle);
3207 3201
3208 3202 err = rtw_dma_init(devinfo, rsc);
3209 3203 if (err != DDI_SUCCESS) {
3210 3204 RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): "
3211 3205 "failed to init dma: %d\n", err);
3212 3206 goto attach_fail1;
3213 3207 }
3214 3208
3215 3209 /*
3216 3210 * Stop the transmit and receive processes. First stop DMA,
3217 3211 * then disable receiver and transmitter.
3218 3212 */
3219 3213 RTW_WRITE8(&rsc->sc_regs, RTW_TPPOLL, RTW_TPPOLL_SALL);
3220 3214 rtw_io_enable(rsc, RTW_CR_RE | RTW_CR_TE, 0);
3221 3215
3222 3216 /* Reset the chip to a known state. */
3223 3217 if (rtw_reset(rsc) != 0) {
3224 3218 RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): "
3225 3219 "failed to reset\n");
3226 3220 goto attach_fail2;
3227 3221 }
3228 3222 rsc->sc_rcr = RTW_READ(&rsc->sc_regs, RTW_RCR);
3229 3223
3230 3224 if ((rsc->sc_rcr & RTW_RCR_9356SEL) != 0)
3231 3225 rsc->sc_flags |= RTW_F_9356SROM;
3232 3226
3233 3227 if (rtw_srom_read(&rsc->sc_regs, rsc->sc_flags, &rsc->sc_srom,
3234 3228 "rtw") != 0) {
3235 3229 RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): "
3236 3230 "failed to read srom\n");
3237 3231 goto attach_fail2;
3238 3232 }
3239 3233
3240 3234 if (rtw_srom_parse(&rsc->sc_srom, &rsc->sc_flags, &rsc->sc_csthr,
3241 3235 &rsc->sc_rfchipid, &rsc->sc_rcr, &rsc->sc_locale,
3242 3236 "rtw") != 0) {
3243 3237 RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw_attach():"
3244 3238 " malformed serial ROM\n");
3245 3239 goto attach_fail3;
3246 3240 }
3247 3241
3248 3242 RTW_DPRINTF(RTW_DEBUG_PHY, "rtw: %s PHY\n",
3249 3243 ((rsc->sc_flags & RTW_F_DIGPHY) != 0) ? "digital" : "analog");
3250 3244
3251 3245
3252 3246 rsc->sc_rf = rtw_rf_attach(rsc, rsc->sc_rfchipid,
3253 3247 rsc->sc_flags & RTW_F_DIGPHY);
3254 3248
3255 3249 if (rsc->sc_rf == NULL) {
3256 3250 cmn_err(CE_WARN, "rtw: rtw_attach(): could not attach RF\n");
3257 3251 goto attach_fail3;
3258 3252 }
3259 3253 rsc->sc_phydelay = rtw_check_phydelay(&rsc->sc_regs, rsc->sc_rcr);
3260 3254
3261 3255 RTW_DPRINTF(RTW_DEBUG_ATTACH,
3262 3256 "rtw: PHY delay %d\n", rsc->sc_phydelay);
3263 3257
3264 3258 if (rsc->sc_locale == RTW_LOCALE_UNKNOWN)
3265 3259 rtw_identify_country(&rsc->sc_regs, &rsc->sc_locale,
3266 3260 "rtw");
3267 3261
3268 3262 rtw_init_channels(rsc->sc_locale, &rsc->sc_ic.ic_sup_channels,
3269 3263 "rtw");
3270 3264
3271 3265 rtw_set80211props(ic);
3272 3266
3273 3267 if (rtw_identify_sta(&rsc->sc_regs, ic->ic_macaddr,
3274 3268 "rtw") != 0)
3275 3269 goto attach_fail4;
3276 3270
3277 3271 ic->ic_xmit = rtw_send;
3278 3272 ieee80211_attach(ic);
3279 3273
3280 3274 rsc->sc_newstate = ic->ic_newstate;
3281 3275 ic->ic_newstate = rtw_new_state;
3282 3276 ieee80211_media_init(ic);
3283 3277 ic->ic_def_txkey = 0;
3284 3278
3285 3279 if (ddi_get_iblock_cookie(devinfo, 0, &(rsc->sc_iblock))
3286 3280 != DDI_SUCCESS) {
3287 3281 RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): "
3288 3282 "Can not get iblock cookie for INT\n");
3289 3283 goto attach_fail5;
3290 3284 }
3291 3285
3292 3286 mutex_init(&rsc->sc_genlock, NULL, MUTEX_DRIVER, rsc->sc_iblock);
3293 3287 for (i = 0; i < RTW_NTXPRI; i++) {
3294 3288 mutex_init(&rsc->sc_txq[i].txbuf_lock, NULL, MUTEX_DRIVER,
3295 3289 rsc->sc_iblock);
3296 3290 }
3297 3291 mutex_init(&rsc->rxbuf_lock, NULL, MUTEX_DRIVER, rsc->sc_iblock);
3298 3292 mutex_init(&rsc->sc_txlock, NULL, MUTEX_DRIVER, rsc->sc_iblock);
3299 3293
3300 3294 if (ddi_add_intr(devinfo, 0, &rsc->sc_iblock, NULL, rtw_intr,
3301 3295 (caddr_t)(rsc)) != DDI_SUCCESS) {
3302 3296 RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): "
3303 3297 "Can not add intr for rtw driver\n");
3304 3298 goto attach_fail7;
3305 3299 }
3306 3300
3307 3301 /*
3308 3302 * Provide initial settings for the WiFi plugin; whenever this
3309 3303 * information changes, we need to call mac_plugindata_update()
3310 3304 */
3311 3305 wd.wd_opmode = ic->ic_opmode;
3312 3306 wd.wd_secalloc = WIFI_SEC_NONE;
3313 3307 IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid);
3314 3308
3315 3309 if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
3316 3310 RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): "
3317 3311 "MAC version mismatch\n");
3318 3312 goto attach_fail8;
3319 3313 }
3320 3314
3321 3315 macp->m_type_ident = MAC_PLUGIN_IDENT_WIFI;
3322 3316 macp->m_driver = rsc;
3323 3317 macp->m_dip = devinfo;
3324 3318 macp->m_src_addr = ic->ic_macaddr;
3325 3319 macp->m_callbacks = &rtw_m_callbacks;
3326 3320 macp->m_min_sdu = 0;
3327 3321 macp->m_max_sdu = IEEE80211_MTU;
3328 3322 macp->m_pdata = &wd;
3329 3323 macp->m_pdata_size = sizeof (wd);
3330 3324
3331 3325 err = mac_register(macp, &ic->ic_mach);
3332 3326 mac_free(macp);
3333 3327 if (err != 0) {
3334 3328 RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): "
3335 3329 "mac_register err %x\n", err);
3336 3330 goto attach_fail8;
3337 3331 }
3338 3332
3339 3333 /* Create minor node of type DDI_NT_NET_WIFI */
3340 3334 (void) snprintf(strbuf, sizeof (strbuf), "%s%d",
3341 3335 "rtw", instance);
3342 3336 err = ddi_create_minor_node(devinfo, strbuf, S_IFCHR,
3343 3337 instance + 1, DDI_NT_NET_WIFI, 0);
3344 3338 if (err != DDI_SUCCESS) {
3345 3339 RTW_DPRINTF(RTW_DEBUG_ATTACH, "WARN: rtw: rtw_attach(): "
3346 3340 "Create minor node failed - %d\n", err);
3347 3341 goto attach_fail9;
3348 3342 }
3349 3343 mac_link_update(ic->ic_mach, LINK_STATE_DOWN);
3350 3344 rsc->sc_flags |= RTW_F_ATTACHED;
3351 3345 rsc->sc_need_reschedule = 0;
3352 3346 rsc->sc_invalid = 1;
3353 3347 return (DDI_SUCCESS);
3354 3348 attach_fail9:
3355 3349 (void) mac_disable(ic->ic_mach);
3356 3350 (void) mac_unregister(ic->ic_mach);
3357 3351 attach_fail8:
3358 3352 ddi_remove_intr(devinfo, 0, rsc->sc_iblock);
3359 3353 attach_fail7:
3360 3354 attach_fail6:
3361 3355 rtw_mutex_destroy(rsc);
3362 3356 attach_fail5:
3363 3357 ieee80211_detach(ic);
3364 3358 attach_fail4:
3365 3359 rtw_rf_destroy(rsc->sc_rf);
3366 3360 attach_fail3:
3367 3361 rtw_srom_free(&rsc->sc_srom);
3368 3362 attach_fail2:
3369 3363 rtw_dma_free(rsc);
3370 3364 attach_fail1:
3371 3365 ddi_regs_map_free(&rsc->sc_regs.r_handle);
3372 3366 attach_fail0:
3373 3367 ddi_soft_state_free(rtw_soft_state_p, ddi_get_instance(devinfo));
3374 3368 return (DDI_FAILURE);
3375 3369 }
3376 3370
3377 3371 static int32_t
3378 3372 rtw_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
3379 3373 {
3380 3374 rtw_softc_t *rsc;
3381 3375
3382 3376 rsc = ddi_get_soft_state(rtw_soft_state_p, ddi_get_instance(devinfo));
3383 3377 ASSERT(rsc != NULL);
3384 3378
3385 3379 switch (cmd) {
3386 3380 case DDI_DETACH:
3387 3381 break;
3388 3382 case DDI_SUSPEND:
3389 3383 ieee80211_new_state(&rsc->sc_ic, IEEE80211_S_INIT, -1);
3390 3384 mutex_enter(&rsc->sc_genlock);
3391 3385 rsc->sc_flags |= RTW_F_SUSPEND;
3392 3386 mutex_exit(&rsc->sc_genlock);
3393 3387 if (rsc->sc_invalid == 0) {
3394 3388 rtw_stop(rsc);
3395 3389 mutex_enter(&rsc->sc_genlock);
3396 3390 rsc->sc_flags |= RTW_F_PLUMBED;
3397 3391 mutex_exit(&rsc->sc_genlock);
3398 3392 }
3399 3393 return (DDI_SUCCESS);
3400 3394 default:
3401 3395 return (DDI_FAILURE);
3402 3396 }
3403 3397 if (!(rsc->sc_flags & RTW_F_ATTACHED))
3404 3398 return (DDI_FAILURE);
3405 3399
3406 3400 if (mac_disable(rsc->sc_ic.ic_mach) != 0)
3407 3401 return (DDI_FAILURE);
3408 3402
3409 3403 /* free intterrupt resources */
3410 3404 ddi_remove_intr(devinfo, 0, rsc->sc_iblock);
3411 3405
3412 3406 rtw_mutex_destroy(rsc);
3413 3407 ieee80211_detach((ieee80211com_t *)rsc);
3414 3408 /*
3415 3409 * Unregister from the MAC layer subsystem
3416 3410 */
3417 3411 (void) mac_unregister(rsc->sc_ic.ic_mach);
3418 3412
3419 3413 rtw_rf_destroy(rsc->sc_rf);
3420 3414 rtw_srom_free(&rsc->sc_srom);
3421 3415 rtw_dma_free(rsc);
3422 3416 ddi_remove_minor_node(devinfo, NULL);
3423 3417 ddi_regs_map_free(&rsc->sc_regs.r_handle);
3424 3418
3425 3419 ddi_soft_state_free(rtw_soft_state_p, ddi_get_instance(devinfo));
3426 3420
3427 3421 return (DDI_SUCCESS);
3428 3422 }
↓ open down ↓ |
2594 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX