1 /*
2 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /*
7 * Copyright (c) 2009, Intel Corporation
8 * All rights reserved.
9 */
10
11 /*
12 * Copyright (c) 2006
13 * Copyright (c) 2007
14 * Damien Bergamini <damien.bergamini@free.fr>
15 *
16 * Permission to use, copy, modify, and distribute this software for any
17 * purpose with or without fee is hereby granted, provided that the above
18 * copyright notice and this permission notice appear in all copies.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
21 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
22 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
23 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
24 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
25 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
26 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
27 */
28
29 /*
30 * Intel(R) WiFi Link 5100/5300 Driver
31 */
32
33 #include <sys/types.h>
34 #include <sys/byteorder.h>
35 #include <sys/conf.h>
36 #include <sys/cmn_err.h>
37 #include <sys/stat.h>
38 #include <sys/ddi.h>
39 #include <sys/sunddi.h>
40 #include <sys/strsubr.h>
41 #include <sys/ethernet.h>
42 #include <inet/common.h>
43 #include <inet/nd.h>
44 #include <inet/mi.h>
45 #include <sys/note.h>
46 #include <sys/stream.h>
47 #include <sys/strsun.h>
48 #include <sys/modctl.h>
49 #include <sys/devops.h>
50 #include <sys/dlpi.h>
51 #include <sys/mac_provider.h>
52 #include <sys/mac_wifi.h>
53 #include <sys/net80211.h>
54 #include <sys/net80211_proto.h>
55 #include <sys/net80211_ht.h>
56 #include <sys/varargs.h>
57 #include <sys/policy.h>
58 #include <sys/pci.h>
59
60 #include "iwh_calibration.h"
61 #include "iwh_hw.h"
62 #include "iwh_eeprom.h"
63 #include "iwh_var.h"
64 #include <inet/wifi_ioctl.h>
65
66 #ifdef DEBUG
67 #define IWH_DEBUG_80211 (1 << 0)
68 #define IWH_DEBUG_CMD (1 << 1)
69 #define IWH_DEBUG_DMA (1 << 2)
70 #define IWH_DEBUG_EEPROM (1 << 3)
71 #define IWH_DEBUG_FW (1 << 4)
72 #define IWH_DEBUG_HW (1 << 5)
73 #define IWH_DEBUG_INTR (1 << 6)
74 #define IWH_DEBUG_MRR (1 << 7)
75 #define IWH_DEBUG_PIO (1 << 8)
76 #define IWH_DEBUG_RX (1 << 9)
77 #define IWH_DEBUG_SCAN (1 << 10)
78 #define IWH_DEBUG_TX (1 << 11)
79 #define IWH_DEBUG_RATECTL (1 << 12)
80 #define IWH_DEBUG_RADIO (1 << 13)
81 #define IWH_DEBUG_RESUME (1 << 14)
82 #define IWH_DEBUG_CALIBRATION (1 << 15)
83 #define IWH_DEBUG_BA (1 << 16)
84 #define IWH_DEBUG_RXON (1 << 17)
85 #define IWH_DEBUG_HWRATE (1 << 18)
86 #define IWH_DEBUG_HTRATE (1 << 19)
87 #define IWH_DEBUG_QOS (1 << 20)
88 /*
89 * if want to see debug message of a given section,
90 * please set this flag to one of above values
91 */
92 uint32_t iwh_dbg_flags = 0;
93 #define IWH_DBG(x) \
94 iwh_dbg x
95 #else
96 #define IWH_DBG(x)
97 #endif
98
99 #define MS(v, f) (((v) & f) >> f##_S)
100
101 static void *iwh_soft_state_p = NULL;
102
103 /*
104 * ucode will be compiled into driver image
105 */
106 static uint8_t iwh_fw_5000_bin[] = {
107 #include "fw-iw/fw_5000/iwh_5000.ucode"
108 };
109
110 static uint8_t iwh_fw_5150_bin[] = {
111 #include "fw-iw/fw_5150/iwh_5150.ucode"
112 };
113
114 /*
115 * DMA attributes for a shared page
116 */
117 static ddi_dma_attr_t sh_dma_attr = {
118 DMA_ATTR_V0, /* version of this structure */
119 0, /* lowest usable address */
120 0xffffffffU, /* highest usable address */
121 0xffffffffU, /* maximum DMAable byte count */
122 0x1000, /* alignment in bytes */
123 0x1000, /* burst sizes (any?) */
124 1, /* minimum transfer */
125 0xffffffffU, /* maximum transfer */
126 0xffffffffU, /* maximum segment length */
127 1, /* maximum number of segments */
128 1, /* granularity */
129 0, /* flags (reserved) */
130 };
131
132 /*
133 * DMA attributes for a keep warm DRAM descriptor
134 */
135 static ddi_dma_attr_t kw_dma_attr = {
136 DMA_ATTR_V0, /* version of this structure */
137 0, /* lowest usable address */
138 0xffffffffU, /* highest usable address */
139 0xffffffffU, /* maximum DMAable byte count */
140 0x1000, /* alignment in bytes */
141 0x1000, /* burst sizes (any?) */
142 1, /* minimum transfer */
143 0xffffffffU, /* maximum transfer */
144 0xffffffffU, /* maximum segment length */
145 1, /* maximum number of segments */
146 1, /* granularity */
147 0, /* flags (reserved) */
148 };
149
150 /*
151 * DMA attributes for a ring descriptor
152 */
153 static ddi_dma_attr_t ring_desc_dma_attr = {
154 DMA_ATTR_V0, /* version of this structure */
155 0, /* lowest usable address */
156 0xffffffffU, /* highest usable address */
157 0xffffffffU, /* maximum DMAable byte count */
158 0x100, /* alignment in bytes */
159 0x100, /* burst sizes (any?) */
160 1, /* minimum transfer */
161 0xffffffffU, /* maximum transfer */
162 0xffffffffU, /* maximum segment length */
163 1, /* maximum number of segments */
164 1, /* granularity */
165 0, /* flags (reserved) */
166 };
167
168 /*
169 * DMA attributes for a cmd
170 */
171 static ddi_dma_attr_t cmd_dma_attr = {
172 DMA_ATTR_V0, /* version of this structure */
173 0, /* lowest usable address */
174 0xffffffffU, /* highest usable address */
175 0xffffffffU, /* maximum DMAable byte count */
176 4, /* alignment in bytes */
177 0x100, /* burst sizes (any?) */
178 1, /* minimum transfer */
179 0xffffffffU, /* maximum transfer */
180 0xffffffffU, /* maximum segment length */
181 1, /* maximum number of segments */
182 1, /* granularity */
183 0, /* flags (reserved) */
184 };
185
186 /*
187 * DMA attributes for a rx buffer
188 */
189 static ddi_dma_attr_t rx_buffer_dma_attr = {
190 DMA_ATTR_V0, /* version of this structure */
191 0, /* lowest usable address */
192 0xffffffffU, /* highest usable address */
193 0xffffffffU, /* maximum DMAable byte count */
194 0x100, /* alignment in bytes */
195 0x100, /* burst sizes (any?) */
196 1, /* minimum transfer */
197 0xffffffffU, /* maximum transfer */
198 0xffffffffU, /* maximum segment length */
199 1, /* maximum number of segments */
200 1, /* granularity */
201 0, /* flags (reserved) */
202 };
203
204 /*
205 * DMA attributes for a tx buffer.
206 * the maximum number of segments is 4 for the hardware.
207 * now all the wifi drivers put the whole frame in a single
208 * descriptor, so we define the maximum number of segments 1,
209 * just the same as the rx_buffer. we consider leverage the HW
210 * ability in the future, that is why we don't define rx and tx
211 * buffer_dma_attr as the same.
212 */
213 static ddi_dma_attr_t tx_buffer_dma_attr = {
214 DMA_ATTR_V0, /* version of this structure */
215 0, /* lowest usable address */
216 0xffffffffU, /* highest usable address */
217 0xffffffffU, /* maximum DMAable byte count */
218 4, /* alignment in bytes */
219 0x100, /* burst sizes (any?) */
220 1, /* minimum transfer */
221 0xffffffffU, /* maximum transfer */
222 0xffffffffU, /* maximum segment length */
223 1, /* maximum number of segments */
224 1, /* granularity */
225 0, /* flags (reserved) */
226 };
227
228 /*
229 * DMA attributes for text and data part in the firmware
230 */
231 static ddi_dma_attr_t fw_dma_attr = {
232 DMA_ATTR_V0, /* version of this structure */
233 0, /* lowest usable address */
234 0xffffffffU, /* highest usable address */
235 0x7fffffff, /* maximum DMAable byte count */
236 0x10, /* alignment in bytes */
237 0x100, /* burst sizes (any?) */
238 1, /* minimum transfer */
239 0xffffffffU, /* maximum transfer */
240 0xffffffffU, /* maximum segment length */
241 1, /* maximum number of segments */
242 1, /* granularity */
243 0, /* flags (reserved) */
244 };
245
246 /*
247 * regs access attributes
248 */
249 static ddi_device_acc_attr_t iwh_reg_accattr = {
250 DDI_DEVICE_ATTR_V0,
251 DDI_STRUCTURE_LE_ACC,
252 DDI_STRICTORDER_ACC,
253 DDI_DEFAULT_ACC
254 };
255
256 /*
257 * DMA access attributes for descriptor
258 */
259 static ddi_device_acc_attr_t iwh_dma_descattr = {
260 DDI_DEVICE_ATTR_V0,
261 DDI_STRUCTURE_LE_ACC,
262 DDI_STRICTORDER_ACC,
263 DDI_DEFAULT_ACC
264 };
265
266 /*
267 * DMA access attributes
268 */
269 static ddi_device_acc_attr_t iwh_dma_accattr = {
270 DDI_DEVICE_ATTR_V0,
271 DDI_NEVERSWAP_ACC,
272 DDI_STRICTORDER_ACC,
273 DDI_DEFAULT_ACC
274 };
275
276 static int iwh_ring_init(iwh_sc_t *);
277 static void iwh_ring_free(iwh_sc_t *);
278 static int iwh_alloc_shared(iwh_sc_t *);
279 static void iwh_free_shared(iwh_sc_t *);
280 static int iwh_alloc_kw(iwh_sc_t *);
281 static void iwh_free_kw(iwh_sc_t *);
282 static int iwh_alloc_fw_dma(iwh_sc_t *);
283 static void iwh_free_fw_dma(iwh_sc_t *);
284 static int iwh_alloc_rx_ring(iwh_sc_t *);
285 static void iwh_reset_rx_ring(iwh_sc_t *);
286 static void iwh_free_rx_ring(iwh_sc_t *);
287 static int iwh_alloc_tx_ring(iwh_sc_t *, iwh_tx_ring_t *,
288 int, int);
289 static void iwh_reset_tx_ring(iwh_sc_t *, iwh_tx_ring_t *);
290 static void iwh_free_tx_ring(iwh_tx_ring_t *);
291 static ieee80211_node_t *iwh_node_alloc(ieee80211com_t *);
292 static void iwh_node_free(ieee80211_node_t *);
293 static int iwh_newstate(ieee80211com_t *, enum ieee80211_state, int);
294 static void iwh_mac_access_enter(iwh_sc_t *);
295 static void iwh_mac_access_exit(iwh_sc_t *);
296 static uint32_t iwh_reg_read(iwh_sc_t *, uint32_t);
297 static void iwh_reg_write(iwh_sc_t *, uint32_t, uint32_t);
298 static int iwh_load_init_firmware(iwh_sc_t *);
299 static int iwh_load_run_firmware(iwh_sc_t *);
300 static void iwh_tx_intr(iwh_sc_t *, iwh_rx_desc_t *);
301 static void iwh_cmd_intr(iwh_sc_t *, iwh_rx_desc_t *);
302 static uint_t iwh_intr(caddr_t, caddr_t);
303 static int iwh_eep_load(iwh_sc_t *);
304 static void iwh_get_mac_from_eep(iwh_sc_t *);
305 static int iwh_eep_sem_down(iwh_sc_t *);
306 static void iwh_eep_sem_up(iwh_sc_t *);
307 static uint_t iwh_rx_softintr(caddr_t, caddr_t);
308 static uint8_t iwh_rate_to_plcp(int);
309 static int iwh_cmd(iwh_sc_t *, int, const void *, int, int);
310 static void iwh_set_led(iwh_sc_t *, uint8_t, uint8_t, uint8_t);
311 static int iwh_hw_set_before_auth(iwh_sc_t *);
312 static int iwh_scan(iwh_sc_t *);
313 static int iwh_config(iwh_sc_t *);
314 static void iwh_stop_master(iwh_sc_t *);
315 static int iwh_power_up(iwh_sc_t *);
316 static int iwh_preinit(iwh_sc_t *);
317 static int iwh_init(iwh_sc_t *);
318 static void iwh_stop(iwh_sc_t *);
319 static int iwh_quiesce(dev_info_t *t);
320 static void iwh_amrr_init(iwh_amrr_t *);
321 static void iwh_amrr_timeout(iwh_sc_t *);
322 static void iwh_amrr_ratectl(void *, ieee80211_node_t *);
323 static void iwh_ucode_alive(iwh_sc_t *, iwh_rx_desc_t *);
324 static void iwh_rx_phy_intr(iwh_sc_t *, iwh_rx_desc_t *);
325 static void iwh_rx_mpdu_intr(iwh_sc_t *, iwh_rx_desc_t *);
326 static void iwh_release_calib_buffer(iwh_sc_t *);
327 static int iwh_init_common(iwh_sc_t *);
328 static uint8_t *iwh_eep_addr_trans(iwh_sc_t *, uint32_t);
329 static int iwh_put_seg_fw(iwh_sc_t *, uint32_t, uint32_t, uint32_t);
330 static int iwh_alive_common(iwh_sc_t *);
331 static void iwh_save_calib_result(iwh_sc_t *, iwh_rx_desc_t *);
332 static int iwh_tx_power_table(iwh_sc_t *, int);
333 static int iwh_attach(dev_info_t *, ddi_attach_cmd_t);
334 static int iwh_detach(dev_info_t *, ddi_detach_cmd_t);
335 static void iwh_destroy_locks(iwh_sc_t *);
336 static int iwh_send(ieee80211com_t *, mblk_t *, uint8_t);
337 static void iwh_thread(iwh_sc_t *);
338 static int iwh_run_state_config(iwh_sc_t *);
339 static int iwh_fast_recover(iwh_sc_t *);
340 static int iwh_wme_update(ieee80211com_t *);
341 static int iwh_qosparam_to_hw(iwh_sc_t *, int);
342 static int iwh_wme_to_qos_ac(int);
343 static uint16_t iwh_cw_e_to_cw(uint8_t);
344 static int iwh_wmeparam_check(struct wmeParams *);
345 static inline int iwh_wme_tid_qos_ac(int);
346 static inline int iwh_qos_ac_to_txq(int);
347 static int iwh_wme_tid_to_txq(int);
348 static void iwh_init_ht_conf(iwh_sc_t *);
349 static void iwh_overwrite_11n_rateset(iwh_sc_t *);
350 static void iwh_overwrite_ic_default(iwh_sc_t *);
351 static void iwh_config_rxon_chain(iwh_sc_t *);
352 static int iwh_add_ap_sta(iwh_sc_t *);
353 static int iwh_ap_lq(iwh_sc_t *);
354 static void iwh_recv_action(struct ieee80211_node *,
355 const uint8_t *, const uint8_t *);
356 static int iwh_send_action(struct ieee80211_node *,
357 int, int, uint16_t[4]);
358 static int iwh_is_max_rate(ieee80211_node_t *);
359 static int iwh_is_min_rate(ieee80211_node_t *);
360 static void iwh_increase_rate(ieee80211_node_t *);
361 static void iwh_decrease_rate(ieee80211_node_t *);
362 static int iwh_alloc_dma_mem(iwh_sc_t *, size_t,
363 ddi_dma_attr_t *, ddi_device_acc_attr_t *,
364 uint_t, iwh_dma_t *);
365 static void iwh_free_dma_mem(iwh_dma_t *);
366 static int iwh_reset_hw(iwh_sc_t *);
367
368 /*
369 * GLD specific operations
370 */
371 static int iwh_m_stat(void *, uint_t, uint64_t *);
372 static int iwh_m_start(void *);
373 static void iwh_m_stop(void *);
374 static int iwh_m_unicst(void *, const uint8_t *);
375 static int iwh_m_multicst(void *, boolean_t, const uint8_t *);
376 static int iwh_m_promisc(void *, boolean_t);
377 static mblk_t *iwh_m_tx(void *, mblk_t *);
378 static void iwh_m_ioctl(void *, queue_t *, mblk_t *);
379 static int iwh_m_setprop(void *arg, const char *pr_name,
380 mac_prop_id_t wldp_pr_num, uint_t wldp_length, const void *wldp_buf);
381 static int iwh_m_getprop(void *arg, const char *pr_name,
382 mac_prop_id_t wldp_pr_num, uint_t wldp_length,
383 void *wldp_buf);
384 static void iwh_m_propinfo(void *arg, const char *pr_name,
385 mac_prop_id_t wldp_pr_num, mac_prop_info_handle_t mph);
386
387 /*
388 * Supported rates for 802.11b/g modes (in 500Kbps unit).
389 */
390 static const struct ieee80211_rateset iwh_rateset_11b =
391 { 4, { 2, 4, 11, 22 } };
392
393 static const struct ieee80211_rateset iwh_rateset_11g =
394 { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
395
396 /*
397 * Default 11n reates supported by this station.
398 */
399 extern struct ieee80211_htrateset ieee80211_rateset_11n;
400
401 /*
402 * For mfthread only
403 */
404 extern pri_t minclsyspri;
405
406 #define DRV_NAME_SP "iwh"
407
408 /*
409 * Module Loading Data & Entry Points
410 */
411 DDI_DEFINE_STREAM_OPS(iwh_devops, nulldev, nulldev, iwh_attach,
412 iwh_detach, nodev, NULL, D_MP, NULL, iwh_quiesce);
413
414 static struct modldrv iwh_modldrv = {
415 &mod_driverops,
416 "Intel(R) ShirleyPeak/EchoPeak driver(N)",
417 &iwh_devops
418 };
419
420 static struct modlinkage iwh_modlinkage = {
421 MODREV_1,
422 &iwh_modldrv,
423 NULL
424 };
425
426 int
427 _init(void)
428 {
429 int status;
430
431 status = ddi_soft_state_init(&iwh_soft_state_p,
432 sizeof (iwh_sc_t), 1);
433 if (status != DDI_SUCCESS) {
434 return (status);
435 }
436
437 mac_init_ops(&iwh_devops, DRV_NAME_SP);
438 status = mod_install(&iwh_modlinkage);
439 if (status != DDI_SUCCESS) {
440 mac_fini_ops(&iwh_devops);
441 ddi_soft_state_fini(&iwh_soft_state_p);
442 }
443
444 return (status);
445 }
446
447 int
448 _fini(void)
449 {
450 int status;
451
452 status = mod_remove(&iwh_modlinkage);
453 if (DDI_SUCCESS == status) {
454 mac_fini_ops(&iwh_devops);
455 ddi_soft_state_fini(&iwh_soft_state_p);
456 }
457
458 return (status);
459 }
460
461 int
462 _info(struct modinfo *mip)
463 {
464 return (mod_info(&iwh_modlinkage, mip));
465 }
466
467 /*
468 * Mac Call Back entries
469 */
470 mac_callbacks_t iwh_m_callbacks = {
471 MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
472 iwh_m_stat,
473 iwh_m_start,
474 iwh_m_stop,
475 iwh_m_promisc,
476 iwh_m_multicst,
477 iwh_m_unicst,
478 iwh_m_tx,
479 NULL,
480 iwh_m_ioctl,
481 NULL,
482 NULL,
483 NULL,
484 iwh_m_setprop,
485 iwh_m_getprop,
486 iwh_m_propinfo
487 };
488
489 #ifdef DEBUG
490 void
491 iwh_dbg(uint32_t flags, const char *fmt, ...)
492 {
493 va_list ap;
494
495 if (flags & iwh_dbg_flags) {
496 va_start(ap, fmt);
497 vcmn_err(CE_NOTE, fmt, ap);
498 va_end(ap);
499 }
500 }
501 #endif /* DEBUG */
502
503 /*
504 * device operations
505 */
506 int
507 iwh_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
508 {
509 iwh_sc_t *sc;
510 ieee80211com_t *ic;
511 int instance, i;
512 char strbuf[32];
513 wifi_data_t wd = { 0 };
514 mac_register_t *macp;
515 int intr_type;
516 int intr_count;
517 int intr_actual;
518 int err = DDI_FAILURE;
519
520 switch (cmd) {
521 case DDI_ATTACH:
522 break;
523
524 case DDI_RESUME:
525 instance = ddi_get_instance(dip);
526 sc = ddi_get_soft_state(iwh_soft_state_p,
527 instance);
528 ASSERT(sc != NULL);
529
530 if (sc->sc_flags & IWH_F_RUNNING) {
531 (void) iwh_init(sc);
532 }
533
534 atomic_and_32(&sc->sc_flags, ~IWH_F_SUSPEND);
535
536 IWH_DBG((IWH_DEBUG_RESUME, "iwh_attach(): "
537 "resume\n"));
538 return (DDI_SUCCESS);
539
540 default:
541 goto attach_fail1;
542 }
543
544 instance = ddi_get_instance(dip);
545 err = ddi_soft_state_zalloc(iwh_soft_state_p, instance);
546 if (err != DDI_SUCCESS) {
547 cmn_err(CE_WARN, "iwh_attach(): "
548 "failed to allocate soft state\n");
549 goto attach_fail1;
550 }
551
552 sc = ddi_get_soft_state(iwh_soft_state_p, instance);
553 ASSERT(sc != NULL);
554
555 sc->sc_dip = dip;
556
557 /*
558 * map configure space
559 */
560 err = ddi_regs_map_setup(dip, 0, &sc->sc_cfg_base, 0, 0,
561 &iwh_reg_accattr, &sc->sc_cfg_handle);
562 if (err != DDI_SUCCESS) {
563 cmn_err(CE_WARN, "iwh_attach(): "
564 "failed to map config spaces regs\n");
565 goto attach_fail2;
566 }
567
568 sc->sc_dev_id = ddi_get16(sc->sc_cfg_handle,
569 (uint16_t *)(sc->sc_cfg_base + PCI_CONF_DEVID));
570 if ((sc->sc_dev_id != 0x4232) &&
571 (sc->sc_dev_id != 0x4235) &&
572 (sc->sc_dev_id != 0x4236) &&
573 (sc->sc_dev_id != 0x4237) &&
574 (sc->sc_dev_id != 0x423a) &&
575 (sc->sc_dev_id != 0x423b) &&
576 (sc->sc_dev_id != 0x423c) &&
577 (sc->sc_dev_id != 0x423d)) {
578 cmn_err(CE_WARN, "iwh_attach(): "
579 "Do not support this device\n");
580 goto attach_fail3;
581 }
582
583 iwh_init_ht_conf(sc);
584 iwh_overwrite_11n_rateset(sc);
585
586 sc->sc_rev = ddi_get8(sc->sc_cfg_handle,
587 (uint8_t *)(sc->sc_cfg_base + PCI_CONF_REVID));
588
589 /*
590 * keep from disturbing C3 state of CPU
591 */
592 ddi_put8(sc->sc_cfg_handle, (uint8_t *)(sc->sc_cfg_base +
593 PCI_CFG_RETRY_TIMEOUT), 0);
594
595 /*
596 * determine the size of buffer for frame and command to ucode
597 */
598 sc->sc_clsz = ddi_get16(sc->sc_cfg_handle,
599 (uint16_t *)(sc->sc_cfg_base + PCI_CONF_CACHE_LINESZ));
600 if (!sc->sc_clsz) {
601 sc->sc_clsz = 16;
602 }
603 sc->sc_clsz = (sc->sc_clsz << 2);
604
605 sc->sc_dmabuf_sz = roundup(0x2000 + sizeof (struct ieee80211_frame) +
606 IEEE80211_MTU + IEEE80211_CRC_LEN +
607 (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
608 IEEE80211_WEP_CRCLEN), sc->sc_clsz);
609
610 /*
611 * Map operating registers
612 */
613 err = ddi_regs_map_setup(dip, 1, &sc->sc_base,
614 0, 0, &iwh_reg_accattr, &sc->sc_handle);
615 if (err != DDI_SUCCESS) {
616 cmn_err(CE_WARN, "iwh_attach(): "
617 "failed to map device regs\n");
618 goto attach_fail3;
619 }
620
621 /*
622 * this is used to differentiate type of hardware
623 */
624 sc->sc_hw_rev = IWH_READ(sc, CSR_HW_REV);
625
626 err = ddi_intr_get_supported_types(dip, &intr_type);
627 if ((err != DDI_SUCCESS) || (!(intr_type & DDI_INTR_TYPE_FIXED))) {
628 cmn_err(CE_WARN, "iwh_attach(): "
629 "fixed type interrupt is not supported\n");
630 goto attach_fail4;
631 }
632
633 err = ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_FIXED, &intr_count);
634 if ((err != DDI_SUCCESS) || (intr_count != 1)) {
635 cmn_err(CE_WARN, "iwh_attach(): "
636 "no fixed interrupts\n");
637 goto attach_fail4;
638 }
639
640 sc->sc_intr_htable = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_SLEEP);
641
642 err = ddi_intr_alloc(dip, sc->sc_intr_htable, DDI_INTR_TYPE_FIXED, 0,
643 intr_count, &intr_actual, 0);
644 if ((err != DDI_SUCCESS) || (intr_actual != 1)) {
645 cmn_err(CE_WARN, "iwh_attach(): "
646 "ddi_intr_alloc() failed 0x%x\n", err);
647 goto attach_fail5;
648 }
649
650 err = ddi_intr_get_pri(sc->sc_intr_htable[0], &sc->sc_intr_pri);
651 if (err != DDI_SUCCESS) {
652 cmn_err(CE_WARN, "iwh_attach(): "
653 "ddi_intr_get_pri() failed 0x%x\n", err);
654 goto attach_fail6;
655 }
656
657 mutex_init(&sc->sc_glock, NULL, MUTEX_DRIVER,
658 DDI_INTR_PRI(sc->sc_intr_pri));
659 mutex_init(&sc->sc_tx_lock, NULL, MUTEX_DRIVER,
660 DDI_INTR_PRI(sc->sc_intr_pri));
661 mutex_init(&sc->sc_mt_lock, NULL, MUTEX_DRIVER,
662 DDI_INTR_PRI(sc->sc_intr_pri));
663
664 cv_init(&sc->sc_cmd_cv, NULL, CV_DRIVER, NULL);
665 cv_init(&sc->sc_put_seg_cv, NULL, CV_DRIVER, NULL);
666 cv_init(&sc->sc_ucode_cv, NULL, CV_DRIVER, NULL);
667
668 /*
669 * initialize the mfthread
670 */
671 cv_init(&sc->sc_mt_cv, NULL, CV_DRIVER, NULL);
672 sc->sc_mf_thread = NULL;
673 sc->sc_mf_thread_switch = 0;
674
675 /*
676 * Allocate shared buffer for communication between driver and ucode.
677 */
678 err = iwh_alloc_shared(sc);
679 if (err != DDI_SUCCESS) {
680 cmn_err(CE_WARN, "iwh_attach(): "
681 "failed to allocate shared page\n");
682 goto attach_fail7;
683 }
684
685 (void) memset(sc->sc_shared, 0, sizeof (iwh_shared_t));
686
687 /*
688 * Allocate keep warm page.
689 */
690 err = iwh_alloc_kw(sc);
691 if (err != DDI_SUCCESS) {
692 cmn_err(CE_WARN, "iwh_attach(): "
693 "failed to allocate keep warm page\n");
694 goto attach_fail8;
695 }
696
697 err = iwh_reset_hw(sc);
698 if (err != IWH_SUCCESS) {
699 cmn_err(CE_WARN, "iwh_attach(): "
700 "failed to reset hardware\n");
701 goto attach_fail9;
702 }
703
704 /*
705 * Do some necessary hardware initializations.
706 */
707 err = iwh_preinit(sc);
708 if (err != IWH_SUCCESS) {
709 cmn_err(CE_WARN, "iwh_attach(): "
710 "failed to initialize hardware\n");
711 goto attach_fail9;
712 }
713
714 /*
715 * get hardware configurations from eeprom
716 */
717 err = iwh_eep_load(sc);
718 if (err != IWH_SUCCESS) {
719 cmn_err(CE_WARN, "iwh_attach(): "
720 "failed to load eeprom\n");
721 goto attach_fail9;
722 }
723
724 if (IWH_READ_EEP_SHORT(sc, EEP_VERSION) < 0x011a) {
725 IWH_DBG((IWH_DEBUG_EEPROM, "iwh_attach(): "
726 "unsupported eeprom detected\n"));
727 goto attach_fail9;
728 }
729
730 /*
731 * get MAC address of this chipset
732 */
733 iwh_get_mac_from_eep(sc);
734
735 /*
736 * calibration information from EEPROM
737 */
738 sc->sc_eep_calib = (struct iwh_eep_calibration *)
739 iwh_eep_addr_trans(sc, EEP_CALIBRATION);
740
741 /*
742 * initialize TX and RX ring buffers
743 */
744 err = iwh_ring_init(sc);
745 if (err != DDI_SUCCESS) {
746 cmn_err(CE_WARN, "iwh_attach(): "
747 "failed to allocate and initialize ring\n");
748 goto attach_fail9;
749 }
750
751 if ((0x423c == sc->sc_dev_id) || (0x423d == sc->sc_dev_id)) {
752 sc->sc_hdr = (iwh_firmware_hdr_t *)iwh_fw_5150_bin;
753 } else {
754 sc->sc_hdr = (iwh_firmware_hdr_t *)iwh_fw_5000_bin;
755 }
756
757 /*
758 * copy ucode to dma buffer
759 */
760 err = iwh_alloc_fw_dma(sc);
761 if (err != DDI_SUCCESS) {
762 cmn_err(CE_WARN, "iwh_attach(): "
763 "failed to allocate firmware dma\n");
764 goto attach_fail10;
765 }
766
767 /*
768 * Initialize the wifi part, which will be used by
769 * 802.11 module
770 */
771 ic = &sc->sc_ic;
772 ic->ic_phytype = IEEE80211_T_HT;
773 ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */
774 ic->ic_state = IEEE80211_S_INIT;
775 ic->ic_maxrssi = 100; /* experimental number */
776 ic->ic_caps = IEEE80211_C_SHPREAMBLE | IEEE80211_C_TXPMGT |
777 IEEE80211_C_PMGT | IEEE80211_C_SHSLOT;
778
779 /*
780 * Support WPA/WPA2
781 */
782 ic->ic_caps |= IEEE80211_C_WPA;
783
784 /*
785 * Support QoS/WME
786 */
787 ic->ic_caps |= IEEE80211_C_WME;
788 ic->ic_wme.wme_update = iwh_wme_update;
789
790 /*
791 * Support 802.11n/HT
792 */
793 if (sc->sc_ht_conf.ht_support) {
794 ic->ic_htcaps = IEEE80211_HTC_HT |
795 IEEE80211_HTC_AMSDU;
796 ic->ic_htcaps |= IEEE80211_HTCAP_MAXAMSDU_7935;
797 }
798
799 /*
800 * set supported .11b and .11g rates
801 */
802 ic->ic_sup_rates[IEEE80211_MODE_11B] = iwh_rateset_11b;
803 ic->ic_sup_rates[IEEE80211_MODE_11G] = iwh_rateset_11g;
804
805 /*
806 * set supported .11b and .11g channels (1 through 11)
807 */
808 for (i = 1; i <= 11; i++) {
809 ic->ic_sup_channels[i].ich_freq =
810 ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
811 ic->ic_sup_channels[i].ich_flags =
812 IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
813 IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ |
814 IEEE80211_CHAN_PASSIVE;
815
816 if (sc->sc_ht_conf.cap & HT_CAP_SUP_WIDTH) {
817 ic->ic_sup_channels[i].ich_flags |=
818 IEEE80211_CHAN_HT40;
819 } else {
820 ic->ic_sup_channels[i].ich_flags |=
821 IEEE80211_CHAN_HT20;
822 }
823 }
824
825 ic->ic_ibss_chan = &ic->ic_sup_channels[0];
826 ic->ic_xmit = iwh_send;
827
828 /*
829 * attach to 802.11 module
830 */
831 ieee80211_attach(ic);
832
833 /*
834 * different instance has different WPA door
835 */
836 (void) snprintf(ic->ic_wpadoor, MAX_IEEE80211STR, "%s_%s%d", WPA_DOOR,
837 ddi_driver_name(dip),
838 ddi_get_instance(dip));
839
840 /*
841 * Overwrite 80211 default configurations.
842 */
843 iwh_overwrite_ic_default(sc);
844
845 /*
846 * initialize 802.11 module
847 */
848 ieee80211_media_init(ic);
849
850 /*
851 * initialize default tx key
852 */
853 ic->ic_def_txkey = 0;
854
855 err = ddi_intr_add_softint(dip, &sc->sc_soft_hdl, DDI_INTR_SOFTPRI_MAX,
856 iwh_rx_softintr, (caddr_t)sc);
857 if (err != DDI_SUCCESS) {
858 cmn_err(CE_WARN, "iwh_attach(): "
859 "add soft interrupt failed\n");
860 goto attach_fail12;
861 }
862
863 err = ddi_intr_add_handler(sc->sc_intr_htable[0], iwh_intr,
864 (caddr_t)sc, NULL);
865 if (err != DDI_SUCCESS) {
866 cmn_err(CE_WARN, "iwh_attach(): "
867 "ddi_intr_add_handle() failed\n");
868 goto attach_fail13;
869 }
870
871 err = ddi_intr_enable(sc->sc_intr_htable[0]);
872 if (err != DDI_SUCCESS) {
873 cmn_err(CE_WARN, "iwh_attach(): "
874 "ddi_intr_enable() failed\n");
875 goto attach_fail14;
876 }
877
878 /*
879 * Initialize pointer to device specific functions
880 */
881 wd.wd_secalloc = WIFI_SEC_NONE;
882 wd.wd_opmode = ic->ic_opmode;
883 IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_macaddr);
884
885 /*
886 * create relation to GLD
887 */
888 macp = mac_alloc(MAC_VERSION);
889 if (NULL == macp) {
890 cmn_err(CE_WARN, "iwh_attach(): "
891 "failed to do mac_alloc()\n");
892 goto attach_fail15;
893 }
894
895 macp->m_type_ident = MAC_PLUGIN_IDENT_WIFI;
896 macp->m_driver = sc;
897 macp->m_dip = dip;
898 macp->m_src_addr = ic->ic_macaddr;
899 macp->m_callbacks = &iwh_m_callbacks;
900 macp->m_min_sdu = 0;
901 macp->m_max_sdu = IEEE80211_MTU;
902 macp->m_pdata = &wd;
903 macp->m_pdata_size = sizeof (wd);
904
905 /*
906 * Register the macp to mac
907 */
908 err = mac_register(macp, &ic->ic_mach);
909 mac_free(macp);
910 if (err != DDI_SUCCESS) {
911 cmn_err(CE_WARN, "iwh_attach(): "
912 "failed to do mac_register()\n");
913 goto attach_fail15;
914 }
915
916 /*
917 * Create minor node of type DDI_NT_NET_WIFI
918 */
919 (void) snprintf(strbuf, sizeof (strbuf), DRV_NAME_SP"%d", instance);
920 err = ddi_create_minor_node(dip, strbuf, S_IFCHR,
921 instance + 1, DDI_NT_NET_WIFI, 0);
922 if (err != DDI_SUCCESS) {
923 cmn_err(CE_WARN, "iwh_attach(): "
924 "failed to do ddi_create_minor_node()\n");
925 }
926
927 /*
928 * Notify link is down now
929 */
930 mac_link_update(ic->ic_mach, LINK_STATE_DOWN);
931
932 /*
933 * create the mf thread to handle the link status,
934 * recovery fatal error, etc.
935 */
936 sc->sc_mf_thread_switch = 1;
937 if (NULL == sc->sc_mf_thread) {
938 sc->sc_mf_thread = thread_create((caddr_t)NULL, 0,
939 iwh_thread, sc, 0, &p0, TS_RUN, minclsyspri);
940 }
941
942 atomic_or_32(&sc->sc_flags, IWH_F_ATTACHED);
943
944 return (DDI_SUCCESS);
945
946 attach_fail15:
947 (void) ddi_intr_disable(sc->sc_intr_htable[0]);
948
949 attach_fail14:
950 (void) ddi_intr_remove_handler(sc->sc_intr_htable[0]);
951
952 attach_fail13:
953 (void) ddi_intr_remove_softint(sc->sc_soft_hdl);
954 sc->sc_soft_hdl = NULL;
955
956 attach_fail12:
957 ieee80211_detach(ic);
958
959 attach_fail11:
960 iwh_free_fw_dma(sc);
961
962 attach_fail10:
963 iwh_ring_free(sc);
964
965 attach_fail9:
966 iwh_free_kw(sc);
967
968 attach_fail8:
969 iwh_free_shared(sc);
970
971 attach_fail7:
972 iwh_destroy_locks(sc);
973
974 attach_fail6:
975 (void) ddi_intr_free(sc->sc_intr_htable[0]);
976
977 attach_fail5:
978 kmem_free(sc->sc_intr_htable, sizeof (ddi_intr_handle_t));
979
980 attach_fail4:
981 ddi_regs_map_free(&sc->sc_handle);
982
983 attach_fail3:
984 ddi_regs_map_free(&sc->sc_cfg_handle);
985
986 attach_fail2:
987 ddi_soft_state_free(iwh_soft_state_p, instance);
988
989 attach_fail1:
990 return (DDI_FAILURE);
991 }
992
993 int
994 iwh_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
995 {
996 iwh_sc_t *sc;
997 ieee80211com_t *ic;
998 int err;
999
1000 sc = ddi_get_soft_state(iwh_soft_state_p, ddi_get_instance(dip));
1001 ASSERT(sc != NULL);
1002 ic = &sc->sc_ic;
1003
1004 switch (cmd) {
1005 case DDI_DETACH:
1006 break;
1007
1008 case DDI_SUSPEND:
1009 atomic_and_32(&sc->sc_flags, ~IWH_F_HW_ERR_RECOVER);
1010 atomic_and_32(&sc->sc_flags, ~IWH_F_RATE_AUTO_CTL);
1011
1012 atomic_or_32(&sc->sc_flags, IWH_F_SUSPEND);
1013
1014 if (sc->sc_flags & IWH_F_RUNNING) {
1015 ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
1016 iwh_stop(sc);
1017 }
1018
1019 IWH_DBG((IWH_DEBUG_RESUME, "iwh_detach(): "
1020 "suspend\n"));
1021 return (DDI_SUCCESS);
1022
1023 default:
1024 return (DDI_FAILURE);
1025 }
1026
1027 if (!(sc->sc_flags & IWH_F_ATTACHED)) {
1028 return (DDI_FAILURE);
1029 }
1030
1031 /*
1032 * Destroy the mf_thread
1033 */
1034 sc->sc_mf_thread_switch = 0;
1035
1036 mutex_enter(&sc->sc_mt_lock);
1037 while (sc->sc_mf_thread != NULL) {
1038 if (cv_wait_sig(&sc->sc_mt_cv, &sc->sc_mt_lock) == 0) {
1039 break;
1040 }
1041 }
1042 mutex_exit(&sc->sc_mt_lock);
1043
1044 err = mac_disable(sc->sc_ic.ic_mach);
1045 if (err != DDI_SUCCESS) {
1046 return (err);
1047 }
1048
1049 /*
1050 * stop chipset
1051 */
1052 iwh_stop(sc);
1053
1054 DELAY(500000);
1055
1056 /*
1057 * release buffer for calibration
1058 */
1059 iwh_release_calib_buffer(sc);
1060
1061 /*
1062 * Unregiste from GLD
1063 */
1064 (void) mac_unregister(sc->sc_ic.ic_mach);
1065
1066 mutex_enter(&sc->sc_glock);
1067 iwh_free_fw_dma(sc);
1068 iwh_ring_free(sc);
1069 iwh_free_kw(sc);
1070 iwh_free_shared(sc);
1071 mutex_exit(&sc->sc_glock);
1072
1073 (void) ddi_intr_disable(sc->sc_intr_htable[0]);
1074 (void) ddi_intr_remove_handler(sc->sc_intr_htable[0]);
1075 (void) ddi_intr_free(sc->sc_intr_htable[0]);
1076 kmem_free(sc->sc_intr_htable, sizeof (ddi_intr_handle_t));
1077
1078 (void) ddi_intr_remove_softint(sc->sc_soft_hdl);
1079 sc->sc_soft_hdl = NULL;
1080
1081 /*
1082 * detach from 80211 module
1083 */
1084 ieee80211_detach(&sc->sc_ic);
1085
1086 iwh_destroy_locks(sc);
1087
1088 ddi_regs_map_free(&sc->sc_handle);
1089 ddi_regs_map_free(&sc->sc_cfg_handle);
1090 ddi_remove_minor_node(dip, NULL);
1091 ddi_soft_state_free(iwh_soft_state_p, ddi_get_instance(dip));
1092
1093 return (DDI_SUCCESS);
1094 }
1095
1096 /*
1097 * destroy all locks
1098 */
1099 static void
1100 iwh_destroy_locks(iwh_sc_t *sc)
1101 {
1102 cv_destroy(&sc->sc_mt_cv);
1103 cv_destroy(&sc->sc_cmd_cv);
1104 cv_destroy(&sc->sc_put_seg_cv);
1105 cv_destroy(&sc->sc_ucode_cv);
1106 mutex_destroy(&sc->sc_mt_lock);
1107 mutex_destroy(&sc->sc_tx_lock);
1108 mutex_destroy(&sc->sc_glock);
1109 }
1110
1111 /*
1112 * Allocate an area of memory and a DMA handle for accessing it
1113 */
1114 static int
1115 iwh_alloc_dma_mem(iwh_sc_t *sc, size_t memsize,
1116 ddi_dma_attr_t *dma_attr_p, ddi_device_acc_attr_t *acc_attr_p,
1117 uint_t dma_flags, iwh_dma_t *dma_p)
1118 {
1119 caddr_t vaddr;
1120 int err = DDI_FAILURE;
1121
1122 /*
1123 * Allocate handle
1124 */
1125 err = ddi_dma_alloc_handle(sc->sc_dip, dma_attr_p,
1126 DDI_DMA_SLEEP, NULL, &dma_p->dma_hdl);
1127 if (err != DDI_SUCCESS) {
1128 dma_p->dma_hdl = NULL;
1129 return (DDI_FAILURE);
1130 }
1131
1132 /*
1133 * Allocate memory
1134 */
1135 err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, acc_attr_p,
1136 dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING),
1137 DDI_DMA_SLEEP, NULL, &vaddr, &dma_p->alength, &dma_p->acc_hdl);
1138 if (err != DDI_SUCCESS) {
1139 ddi_dma_free_handle(&dma_p->dma_hdl);
1140 dma_p->dma_hdl = NULL;
1141 dma_p->acc_hdl = NULL;
1142 return (DDI_FAILURE);
1143 }
1144
1145 /*
1146 * Bind the two together
1147 */
1148 dma_p->mem_va = vaddr;
1149 err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL,
1150 vaddr, dma_p->alength, dma_flags, DDI_DMA_SLEEP, NULL,
1151 &dma_p->cookie, &dma_p->ncookies);
1152 if (err != DDI_DMA_MAPPED) {
1153 ddi_dma_mem_free(&dma_p->acc_hdl);
1154 ddi_dma_free_handle(&dma_p->dma_hdl);
1155 dma_p->acc_hdl = NULL;
1156 dma_p->dma_hdl = NULL;
1157 return (DDI_FAILURE);
1158 }
1159
1160 dma_p->nslots = ~0U;
1161 dma_p->size = ~0U;
1162 dma_p->token = ~0U;
1163 dma_p->offset = 0;
1164 return (DDI_SUCCESS);
1165 }
1166
1167 /*
1168 * Free one allocated area of DMAable memory
1169 */
1170 static void
1171 iwh_free_dma_mem(iwh_dma_t *dma_p)
1172 {
1173 if (dma_p->dma_hdl != NULL) {
1174 if (dma_p->ncookies) {
1175 (void) ddi_dma_unbind_handle(dma_p->dma_hdl);
1176 dma_p->ncookies = 0;
1177 }
1178 ddi_dma_free_handle(&dma_p->dma_hdl);
1179 dma_p->dma_hdl = NULL;
1180 }
1181
1182 if (dma_p->acc_hdl != NULL) {
1183 ddi_dma_mem_free(&dma_p->acc_hdl);
1184 dma_p->acc_hdl = NULL;
1185 }
1186 }
1187
1188 /*
1189 * copy ucode into dma buffers
1190 */
1191 static int
1192 iwh_alloc_fw_dma(iwh_sc_t *sc)
1193 {
1194 int err = DDI_FAILURE;
1195 iwh_dma_t *dma_p;
1196 char *t;
1197
1198 /*
1199 * firmware image layout:
1200 * |HDR|<-TEXT->|<-DATA->|<-INIT_TEXT->|<-INIT_DATA->|<-BOOT->|
1201 */
1202
1203 /*
1204 * copy text of runtime ucode
1205 */
1206 t = (char *)(sc->sc_hdr + 1);
1207 err = iwh_alloc_dma_mem(sc, LE_32(sc->sc_hdr->textsz),
1208 &fw_dma_attr, &iwh_dma_accattr,
1209 DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1210 &sc->sc_dma_fw_text);
1211 if (err != DDI_SUCCESS) {
1212 cmn_err(CE_WARN, "iwh_alloc_fw_dma(): "
1213 "failed to allocate text dma memory.\n");
1214 goto fail;
1215 }
1216
1217 dma_p = &sc->sc_dma_fw_text;
1218
1219 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_fw_dma(): "
1220 "text[ncookies:%d addr:%lx size:%lx]\n",
1221 dma_p->ncookies, dma_p->cookie.dmac_address,
1222 dma_p->cookie.dmac_size));
1223
1224 bcopy(t, dma_p->mem_va, LE_32(sc->sc_hdr->textsz));
1225
1226 /*
1227 * copy data and bak-data of runtime ucode
1228 */
1229 t += LE_32(sc->sc_hdr->textsz);
1230 err = iwh_alloc_dma_mem(sc, LE_32(sc->sc_hdr->datasz),
1231 &fw_dma_attr, &iwh_dma_accattr,
1232 DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1233 &sc->sc_dma_fw_data);
1234 if (err != DDI_SUCCESS) {
1235 cmn_err(CE_WARN, "iwh_alloc_fw_dma(): "
1236 "failed to allocate data dma memory\n");
1237 goto fail;
1238 }
1239
1240 dma_p = &sc->sc_dma_fw_data;
1241
1242 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_fw_dma(): "
1243 "data[ncookies:%d addr:%lx size:%lx]\n",
1244 dma_p->ncookies, dma_p->cookie.dmac_address,
1245 dma_p->cookie.dmac_size));
1246
1247 bcopy(t, dma_p->mem_va, LE_32(sc->sc_hdr->datasz));
1248
1249 err = iwh_alloc_dma_mem(sc, LE_32(sc->sc_hdr->datasz),
1250 &fw_dma_attr, &iwh_dma_accattr,
1251 DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1252 &sc->sc_dma_fw_data_bak);
1253 if (err != DDI_SUCCESS) {
1254 cmn_err(CE_WARN, "iwh_alloc_fw_dma(): "
1255 "failed to allocate data bakup dma memory\n");
1256 goto fail;
1257 }
1258
1259 dma_p = &sc->sc_dma_fw_data_bak;
1260
1261 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_fw_dma(): "
1262 "data_bak[ncookies:%d addr:%lx "
1263 "size:%lx]\n",
1264 dma_p->ncookies, dma_p->cookie.dmac_address,
1265 dma_p->cookie.dmac_size));
1266
1267 bcopy(t, dma_p->mem_va, LE_32(sc->sc_hdr->datasz));
1268
1269 /*
1270 * copy text of init ucode
1271 */
1272 t += LE_32(sc->sc_hdr->datasz);
1273 err = iwh_alloc_dma_mem(sc, LE_32(sc->sc_hdr->init_textsz),
1274 &fw_dma_attr, &iwh_dma_accattr,
1275 DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1276 &sc->sc_dma_fw_init_text);
1277 if (err != DDI_SUCCESS) {
1278 cmn_err(CE_WARN, "iwh_alloc_fw_dma(): "
1279 "failed to allocate init text dma memory\n");
1280 goto fail;
1281 }
1282
1283 dma_p = &sc->sc_dma_fw_init_text;
1284
1285 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_fw_dma(): "
1286 "init_text[ncookies:%d addr:%lx "
1287 "size:%lx]\n",
1288 dma_p->ncookies, dma_p->cookie.dmac_address,
1289 dma_p->cookie.dmac_size));
1290
1291 bcopy(t, dma_p->mem_va, LE_32(sc->sc_hdr->init_textsz));
1292
1293 /*
1294 * copy data of init ucode
1295 */
1296 t += LE_32(sc->sc_hdr->init_textsz);
1297 err = iwh_alloc_dma_mem(sc, LE_32(sc->sc_hdr->init_datasz),
1298 &fw_dma_attr, &iwh_dma_accattr,
1299 DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1300 &sc->sc_dma_fw_init_data);
1301 if (err != DDI_SUCCESS) {
1302 cmn_err(CE_WARN, "iwh_alloc_fw_dma(): "
1303 "failed to allocate init data dma memory\n");
1304 goto fail;
1305 }
1306
1307 dma_p = &sc->sc_dma_fw_init_data;
1308
1309 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_fw_dma(): "
1310 "init_data[ncookies:%d addr:%lx "
1311 "size:%lx]\n",
1312 dma_p->ncookies, dma_p->cookie.dmac_address,
1313 dma_p->cookie.dmac_size));
1314
1315 bcopy(t, dma_p->mem_va, LE_32(sc->sc_hdr->init_datasz));
1316
1317 sc->sc_boot = t + LE_32(sc->sc_hdr->init_datasz);
1318
1319 fail:
1320 return (err);
1321 }
1322
1323 static void
1324 iwh_free_fw_dma(iwh_sc_t *sc)
1325 {
1326 iwh_free_dma_mem(&sc->sc_dma_fw_text);
1327 iwh_free_dma_mem(&sc->sc_dma_fw_data);
1328 iwh_free_dma_mem(&sc->sc_dma_fw_data_bak);
1329 iwh_free_dma_mem(&sc->sc_dma_fw_init_text);
1330 iwh_free_dma_mem(&sc->sc_dma_fw_init_data);
1331 }
1332
1333 /*
1334 * Allocate a shared buffer between host and NIC.
1335 */
1336 static int
1337 iwh_alloc_shared(iwh_sc_t *sc)
1338 {
1339 #ifdef DEBUG
1340 iwh_dma_t *dma_p;
1341 #endif
1342 int err = DDI_FAILURE;
1343
1344 /*
1345 * must be aligned on a 4K-page boundary
1346 */
1347 err = iwh_alloc_dma_mem(sc, sizeof (iwh_shared_t),
1348 &sh_dma_attr, &iwh_dma_descattr,
1349 DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1350 &sc->sc_dma_sh);
1351 if (err != DDI_SUCCESS) {
1352 goto fail;
1353 }
1354
1355 sc->sc_shared = (iwh_shared_t *)sc->sc_dma_sh.mem_va;
1356
1357 #ifdef DEBUG
1358 dma_p = &sc->sc_dma_sh;
1359 #endif
1360 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_shared(): "
1361 "sh[ncookies:%d addr:%lx size:%lx]\n",
1362 dma_p->ncookies, dma_p->cookie.dmac_address,
1363 dma_p->cookie.dmac_size));
1364
1365 return (err);
1366
1367 fail:
1368 iwh_free_shared(sc);
1369 return (err);
1370 }
1371
1372 static void
1373 iwh_free_shared(iwh_sc_t *sc)
1374 {
1375 iwh_free_dma_mem(&sc->sc_dma_sh);
1376 }
1377
1378 /*
1379 * Allocate a keep warm page.
1380 */
1381 static int
1382 iwh_alloc_kw(iwh_sc_t *sc)
1383 {
1384 #ifdef DEBUG
1385 iwh_dma_t *dma_p;
1386 #endif
1387 int err = DDI_FAILURE;
1388
1389 /*
1390 * must be aligned on a 4K-page boundary
1391 */
1392 err = iwh_alloc_dma_mem(sc, IWH_KW_SIZE,
1393 &kw_dma_attr, &iwh_dma_descattr,
1394 DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1395 &sc->sc_dma_kw);
1396 if (err != DDI_SUCCESS) {
1397 goto fail;
1398 }
1399
1400 #ifdef DEBUG
1401 dma_p = &sc->sc_dma_kw;
1402 #endif
1403 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_kw(): "
1404 "kw[ncookies:%d addr:%lx size:%lx]\n",
1405 dma_p->ncookies, dma_p->cookie.dmac_address,
1406 dma_p->cookie.dmac_size));
1407
1408 return (err);
1409
1410 fail:
1411 iwh_free_kw(sc);
1412 return (err);
1413 }
1414
1415 static void
1416 iwh_free_kw(iwh_sc_t *sc)
1417 {
1418 iwh_free_dma_mem(&sc->sc_dma_kw);
1419 }
1420
1421 /*
1422 * initialize RX ring buffers
1423 */
1424 static int
1425 iwh_alloc_rx_ring(iwh_sc_t *sc)
1426 {
1427 iwh_rx_ring_t *ring;
1428 iwh_rx_data_t *data;
1429 #ifdef DEBUG
1430 iwh_dma_t *dma_p;
1431 #endif
1432 int i, err = DDI_FAILURE;
1433
1434 ring = &sc->sc_rxq;
1435 ring->cur = 0;
1436
1437 /*
1438 * allocate RX description ring buffer
1439 */
1440 err = iwh_alloc_dma_mem(sc, RX_QUEUE_SIZE * sizeof (uint32_t),
1441 &ring_desc_dma_attr, &iwh_dma_descattr,
1442 DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1443 &ring->dma_desc);
1444 if (err != DDI_SUCCESS) {
1445 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_rx_ring(): "
1446 "dma alloc rx ring desc "
1447 "failed\n"));
1448 goto fail;
1449 }
1450
1451 ring->desc = (uint32_t *)ring->dma_desc.mem_va;
1452 #ifdef DEBUG
1453 dma_p = &ring->dma_desc;
1454 #endif
1455 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_rx_ring(): "
1456 "rx bd[ncookies:%d addr:%lx size:%lx]\n",
1457 dma_p->ncookies, dma_p->cookie.dmac_address,
1458 dma_p->cookie.dmac_size));
1459
1460 /*
1461 * Allocate Rx frame buffers.
1462 */
1463 for (i = 0; i < RX_QUEUE_SIZE; i++) {
1464 data = &ring->data[i];
1465 err = iwh_alloc_dma_mem(sc, sc->sc_dmabuf_sz,
1466 &rx_buffer_dma_attr, &iwh_dma_accattr,
1467 DDI_DMA_READ | DDI_DMA_STREAMING,
1468 &data->dma_data);
1469 if (err != DDI_SUCCESS) {
1470 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_rx_ring(): "
1471 "dma alloc rx ring "
1472 "buf[%d] failed\n", i));
1473 goto fail;
1474 }
1475 /*
1476 * the physical address bit [8-36] are used,
1477 * instead of bit [0-31] in 3945.
1478 */
1479 ring->desc[i] = (uint32_t)
1480 (data->dma_data.cookie.dmac_address >> 8);
1481 }
1482
1483 #ifdef DEBUG
1484 dma_p = &ring->data[0].dma_data;
1485 #endif
1486 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_rx_ring(): "
1487 "rx buffer[0][ncookies:%d addr:%lx "
1488 "size:%lx]\n",
1489 dma_p->ncookies, dma_p->cookie.dmac_address,
1490 dma_p->cookie.dmac_size));
1491
1492 IWH_DMA_SYNC(ring->dma_desc, DDI_DMA_SYNC_FORDEV);
1493
1494 return (err);
1495
1496 fail:
1497 iwh_free_rx_ring(sc);
1498 return (err);
1499 }
1500
1501 /*
1502 * disable RX ring
1503 */
1504 static void
1505 iwh_reset_rx_ring(iwh_sc_t *sc)
1506 {
1507 int n;
1508
1509 iwh_mac_access_enter(sc);
1510 IWH_WRITE(sc, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
1511 for (n = 0; n < 2000; n++) {
1512 if (IWH_READ(sc, FH_MEM_RSSR_RX_STATUS_REG) & (1 << 24)) {
1513 break;
1514 }
1515 DELAY(1000);
1516 }
1517 #ifdef DEBUG
1518 if (2000 == n) {
1519 IWH_DBG((IWH_DEBUG_DMA, "iwh_reset_rx_ring(): "
1520 "timeout resetting Rx ring\n"));
1521 }
1522 #endif
1523 iwh_mac_access_exit(sc);
1524
1525 sc->sc_rxq.cur = 0;
1526 }
1527
1528 static void
1529 iwh_free_rx_ring(iwh_sc_t *sc)
1530 {
1531 int i;
1532
1533 for (i = 0; i < RX_QUEUE_SIZE; i++) {
1534 if (sc->sc_rxq.data[i].dma_data.dma_hdl) {
1535 IWH_DMA_SYNC(sc->sc_rxq.data[i].dma_data,
1536 DDI_DMA_SYNC_FORCPU);
1537 }
1538
1539 iwh_free_dma_mem(&sc->sc_rxq.data[i].dma_data);
1540 }
1541
1542 if (sc->sc_rxq.dma_desc.dma_hdl) {
1543 IWH_DMA_SYNC(sc->sc_rxq.dma_desc, DDI_DMA_SYNC_FORDEV);
1544 }
1545
1546 iwh_free_dma_mem(&sc->sc_rxq.dma_desc);
1547 }
1548
1549 /*
1550 * initialize TX ring buffers
1551 */
1552 static int
1553 iwh_alloc_tx_ring(iwh_sc_t *sc, iwh_tx_ring_t *ring,
1554 int slots, int qid)
1555 {
1556 iwh_tx_data_t *data;
1557 iwh_tx_desc_t *desc_h;
1558 uint32_t paddr_desc_h;
1559 iwh_cmd_t *cmd_h;
1560 uint32_t paddr_cmd_h;
1561 #ifdef DEBUG
1562 iwh_dma_t *dma_p;
1563 #endif
1564 int i, err = DDI_FAILURE;
1565
1566 ring->qid = qid;
1567 ring->count = TFD_QUEUE_SIZE_MAX;
1568 ring->window = slots;
1569 ring->queued = 0;
1570 ring->cur = 0;
1571 ring->desc_cur = 0;
1572
1573 /*
1574 * allocate buffer for TX descriptor ring
1575 */
1576 err = iwh_alloc_dma_mem(sc,
1577 TFD_QUEUE_SIZE_MAX * sizeof (iwh_tx_desc_t),
1578 &ring_desc_dma_attr, &iwh_dma_descattr,
1579 DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1580 &ring->dma_desc);
1581 if (err != DDI_SUCCESS) {
1582 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_tx_ring(): "
1583 "dma alloc tx ring desc[%d] "
1584 "failed\n", qid));
1585 goto fail;
1586 }
1587
1588 #ifdef DEBUG
1589 dma_p = &ring->dma_desc;
1590 #endif
1591 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_tx_ring(): "
1592 "tx bd[ncookies:%d addr:%lx size:%lx]\n",
1593 dma_p->ncookies, dma_p->cookie.dmac_address,
1594 dma_p->cookie.dmac_size));
1595
1596 desc_h = (iwh_tx_desc_t *)ring->dma_desc.mem_va;
1597 paddr_desc_h = ring->dma_desc.cookie.dmac_address;
1598
1599 /*
1600 * allocate buffer for ucode command
1601 */
1602 err = iwh_alloc_dma_mem(sc,
1603 TFD_QUEUE_SIZE_MAX * sizeof (iwh_cmd_t),
1604 &cmd_dma_attr, &iwh_dma_accattr,
1605 DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1606 &ring->dma_cmd);
1607 if (err != DDI_SUCCESS) {
1608 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_tx_ring(): "
1609 "dma alloc tx ring cmd[%d]"
1610 " failed\n", qid));
1611 goto fail;
1612 }
1613
1614 #ifdef DEBUG
1615 dma_p = &ring->dma_cmd;
1616 #endif
1617 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_tx_ring(): "
1618 "tx cmd[ncookies:%d addr:%lx size:%lx]\n",
1619 dma_p->ncookies, dma_p->cookie.dmac_address,
1620 dma_p->cookie.dmac_size));
1621
1622 cmd_h = (iwh_cmd_t *)ring->dma_cmd.mem_va;
1623 paddr_cmd_h = ring->dma_cmd.cookie.dmac_address;
1624
1625 /*
1626 * Allocate Tx frame buffers.
1627 */
1628 ring->data = kmem_zalloc(sizeof (iwh_tx_data_t) * TFD_QUEUE_SIZE_MAX,
1629 KM_NOSLEEP);
1630 if (NULL == ring->data) {
1631 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_tx_ring(): "
1632 "could not allocate "
1633 "tx data slots\n"));
1634 goto fail;
1635 }
1636
1637 for (i = 0; i < TFD_QUEUE_SIZE_MAX; i++) {
1638 data = &ring->data[i];
1639 err = iwh_alloc_dma_mem(sc, sc->sc_dmabuf_sz,
1640 &tx_buffer_dma_attr, &iwh_dma_accattr,
1641 DDI_DMA_WRITE | DDI_DMA_STREAMING,
1642 &data->dma_data);
1643 if (err != DDI_SUCCESS) {
1644 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_tx_ring(): "
1645 "dma alloc tx "
1646 "ring buf[%d] failed\n", i));
1647 goto fail;
1648 }
1649
1650 data->desc = desc_h + i;
1651 data->paddr_desc = paddr_desc_h +
1652 _PTRDIFF(data->desc, desc_h);
1653 data->cmd = cmd_h + i;
1654 data->paddr_cmd = paddr_cmd_h +
1655 _PTRDIFF(data->cmd, cmd_h);
1656 }
1657 #ifdef DEBUG
1658 dma_p = &ring->data[0].dma_data;
1659 #endif
1660 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_tx_ring(): "
1661 "tx buffer[0][ncookies:%d addr:%lx "
1662 "size:%lx]\n",
1663 dma_p->ncookies, dma_p->cookie.dmac_address,
1664 dma_p->cookie.dmac_size));
1665
1666 return (err);
1667
1668 fail:
1669 iwh_free_tx_ring(ring);
1670
1671 return (err);
1672 }
1673
1674 /*
1675 * disable TX ring
1676 */
1677 static void
1678 iwh_reset_tx_ring(iwh_sc_t *sc, iwh_tx_ring_t *ring)
1679 {
1680 iwh_tx_data_t *data;
1681 int i, n;
1682
1683 iwh_mac_access_enter(sc);
1684
1685 IWH_WRITE(sc, IWH_FH_TCSR_CHNL_TX_CONFIG_REG(ring->qid), 0);
1686 for (n = 0; n < 200; n++) {
1687 if (IWH_READ(sc, IWH_FH_TSSR_TX_STATUS_REG) &
1688 IWH_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ring->qid)) {
1689 break;
1690 }
1691 DELAY(10);
1692 }
1693
1694 #ifdef DEBUG
1695 if (200 == n) {
1696 IWH_DBG((IWH_DEBUG_DMA, "iwh_reset_tx_ring(): "
1697 "timeout reset tx ring %d\n",
1698 ring->qid));
1699 }
1700 #endif
1701
1702 iwh_mac_access_exit(sc);
1703
1704 /*
1705 * by pass, if it's quiesce
1706 */
1707 if (!(sc->sc_flags & IWH_F_QUIESCED)) {
1708 for (i = 0; i < ring->count; i++) {
1709 data = &ring->data[i];
1710 IWH_DMA_SYNC(data->dma_data, DDI_DMA_SYNC_FORDEV);
1711 }
1712 }
1713
1714 ring->queued = 0;
1715 ring->cur = 0;
1716 ring->desc_cur = 0;
1717 }
1718
1719 static void
1720 iwh_free_tx_ring(iwh_tx_ring_t *ring)
1721 {
1722 int i;
1723
1724 if (ring->dma_desc.dma_hdl != NULL) {
1725 IWH_DMA_SYNC(ring->dma_desc, DDI_DMA_SYNC_FORDEV);
1726 }
1727 iwh_free_dma_mem(&ring->dma_desc);
1728
1729 if (ring->dma_cmd.dma_hdl != NULL) {
1730 IWH_DMA_SYNC(ring->dma_cmd, DDI_DMA_SYNC_FORDEV);
1731 }
1732 iwh_free_dma_mem(&ring->dma_cmd);
1733
1734 if (ring->data != NULL) {
1735 for (i = 0; i < ring->count; i++) {
1736 if (ring->data[i].dma_data.dma_hdl) {
1737 IWH_DMA_SYNC(ring->data[i].dma_data,
1738 DDI_DMA_SYNC_FORDEV);
1739 }
1740 iwh_free_dma_mem(&ring->data[i].dma_data);
1741 }
1742 kmem_free(ring->data, ring->count * sizeof (iwh_tx_data_t));
1743 }
1744 }
1745
1746 /*
1747 * initialize TX and RX ring
1748 */
1749 static int
1750 iwh_ring_init(iwh_sc_t *sc)
1751 {
1752 int i, err = DDI_FAILURE;
1753
1754 for (i = 0; i < IWH_NUM_QUEUES; i++) {
1755 if (IWH_CMD_QUEUE_NUM == i) {
1756 continue;
1757 }
1758
1759 err = iwh_alloc_tx_ring(sc, &sc->sc_txq[i], TFD_TX_CMD_SLOTS,
1760 i);
1761 if (err != DDI_SUCCESS) {
1762 goto fail;
1763 }
1764 }
1765
1766 /*
1767 * initialize command queue
1768 */
1769 err = iwh_alloc_tx_ring(sc, &sc->sc_txq[IWH_CMD_QUEUE_NUM],
1770 TFD_CMD_SLOTS, IWH_CMD_QUEUE_NUM);
1771 if (err != DDI_SUCCESS) {
1772 goto fail;
1773 }
1774
1775 err = iwh_alloc_rx_ring(sc);
1776 if (err != DDI_SUCCESS) {
1777 goto fail;
1778 }
1779
1780 fail:
1781 return (err);
1782 }
1783
1784 static void
1785 iwh_ring_free(iwh_sc_t *sc)
1786 {
1787 int i = IWH_NUM_QUEUES;
1788
1789 iwh_free_rx_ring(sc);
1790 while (--i >= 0) {
1791 iwh_free_tx_ring(&sc->sc_txq[i]);
1792 }
1793 }
1794
1795 /* ARGSUSED */
1796 static ieee80211_node_t *
1797 iwh_node_alloc(ieee80211com_t *ic)
1798 {
1799 iwh_amrr_t *amrr;
1800
1801 amrr = kmem_zalloc(sizeof (iwh_amrr_t), KM_SLEEP);
1802
1803 iwh_amrr_init(amrr);
1804
1805 return (&amrr->in);
1806 }
1807
1808 static void
1809 iwh_node_free(ieee80211_node_t *in)
1810 {
1811 ieee80211com_t *ic;
1812
1813 if ((NULL == in) ||
1814 (NULL == in->in_ic)) {
1815 cmn_err(CE_WARN, "iwh_node_free() "
1816 "Got a NULL point from Net80211 module\n");
1817 return;
1818 }
1819 ic = in->in_ic;
1820
1821 if (ic->ic_node_cleanup != NULL) {
1822 ic->ic_node_cleanup(in);
1823 }
1824
1825 if (in->in_wpa_ie != NULL) {
1826 ieee80211_free(in->in_wpa_ie);
1827 }
1828
1829 if (in->in_wme_ie != NULL) {
1830 ieee80211_free(in->in_wme_ie);
1831 }
1832
1833 if (in->in_htcap_ie != NULL) {
1834 ieee80211_free(in->in_htcap_ie);
1835 }
1836
1837 kmem_free(in, sizeof (iwh_amrr_t));
1838 }
1839
1840 /*
1841 * change station's state. this function will be invoked by 80211 module
1842 * when need to change staton's state.
1843 */
1844 static int
1845 iwh_newstate(ieee80211com_t *ic, enum ieee80211_state nstate, int arg)
1846 {
1847 iwh_sc_t *sc;
1848 ieee80211_node_t *in;
1849 enum ieee80211_state ostate;
1850 iwh_add_sta_t node;
1851 iwh_amrr_t *amrr;
1852 uint8_t r;
1853 int i, err = IWH_FAIL;
1854
1855 if (NULL == ic) {
1856 return (err);
1857 }
1858 sc = (iwh_sc_t *)ic;
1859 in = ic->ic_bss;
1860 ostate = ic->ic_state;
1861
1862 mutex_enter(&sc->sc_glock);
1863
1864 switch (nstate) {
1865 case IEEE80211_S_SCAN:
1866 switch (ostate) {
1867 case IEEE80211_S_INIT:
1868 atomic_or_32(&sc->sc_flags, IWH_F_SCANNING);
1869 iwh_set_led(sc, 2, 10, 2);
1870
1871 /*
1872 * clear association to receive beacons from
1873 * all BSS'es
1874 */
1875 sc->sc_config.assoc_id = 0;
1876 sc->sc_config.filter_flags &=
1877 ~LE_32(RXON_FILTER_ASSOC_MSK);
1878
1879 IWH_DBG((IWH_DEBUG_80211, "iwh_newstate(): "
1880 "config chan %d "
1881 "flags %x filter_flags %x\n",
1882 LE_16(sc->sc_config.chan),
1883 LE_32(sc->sc_config.flags),
1884 LE_32(sc->sc_config.filter_flags)));
1885
1886 err = iwh_cmd(sc, REPLY_RXON, &sc->sc_config,
1887 sizeof (iwh_rxon_cmd_t), 1);
1888 if (err != IWH_SUCCESS) {
1889 cmn_err(CE_WARN, "iwh_newstate(): "
1890 "could not clear association\n");
1891 atomic_and_32(&sc->sc_flags, ~IWH_F_SCANNING);
1892 mutex_exit(&sc->sc_glock);
1893 return (err);
1894 }
1895
1896 /*
1897 * add broadcast node to send probe request
1898 */
1899 (void) memset(&node, 0, sizeof (node));
1900 (void) memset(&node.sta.addr, 0xff, IEEE80211_ADDR_LEN);
1901 node.sta.sta_id = IWH_BROADCAST_ID;
1902 err = iwh_cmd(sc, REPLY_ADD_STA, &node,
1903 sizeof (node), 1);
1904 if (err != IWH_SUCCESS) {
1905 cmn_err(CE_WARN, "iwh_newstate(): "
1906 "could not add broadcast node\n");
1907 atomic_and_32(&sc->sc_flags, ~IWH_F_SCANNING);
1908 mutex_exit(&sc->sc_glock);
1909 return (err);
1910 }
1911 break;
1912 case IEEE80211_S_SCAN:
1913 mutex_exit(&sc->sc_glock);
1914 /* step to next channel before actual FW scan */
1915 err = sc->sc_newstate(ic, nstate, arg);
1916 mutex_enter(&sc->sc_glock);
1917 if ((err != 0) || ((err = iwh_scan(sc)) != 0)) {
1918 cmn_err(CE_WARN, "iwh_newstate(): "
1919 "could not initiate scan\n");
1920 atomic_and_32(&sc->sc_flags, ~IWH_F_SCANNING);
1921 ieee80211_cancel_scan(ic);
1922 }
1923 mutex_exit(&sc->sc_glock);
1924 return (err);
1925 default:
1926 break;
1927 }
1928 sc->sc_clk = 0;
1929 break;
1930
1931 case IEEE80211_S_AUTH:
1932 if (ostate == IEEE80211_S_SCAN) {
1933 atomic_and_32(&sc->sc_flags, ~IWH_F_SCANNING);
1934 }
1935
1936 /*
1937 * reset state to handle reassociations correctly
1938 */
1939 sc->sc_config.assoc_id = 0;
1940 sc->sc_config.filter_flags &= ~LE_32(RXON_FILTER_ASSOC_MSK);
1941
1942 /*
1943 * before sending authentication and association request frame,
1944 * we need do something in the hardware, such as setting the
1945 * channel same to the target AP...
1946 */
1947 if ((err = iwh_hw_set_before_auth(sc)) != 0) {
1948 IWH_DBG((IWH_DEBUG_80211, "iwh_newstate(): "
1949 "could not send authentication request\n"));
1950 mutex_exit(&sc->sc_glock);
1951 return (err);
1952 }
1953 break;
1954
1955 case IEEE80211_S_RUN:
1956 if (ostate == IEEE80211_S_SCAN) {
1957 atomic_and_32(&sc->sc_flags, ~IWH_F_SCANNING);
1958 }
1959
1960 if (IEEE80211_M_MONITOR == ic->ic_opmode) {
1961 /*
1962 * let LED blink when monitoring
1963 */
1964 iwh_set_led(sc, 2, 10, 10);
1965 break;
1966 }
1967
1968 IWH_DBG((IWH_DEBUG_80211, "iwh_newstate(): "
1969 "associated.\n"));
1970
1971 err = iwh_run_state_config(sc);
1972 if (err != IWH_SUCCESS) {
1973 cmn_err(CE_WARN, "iwh_newstate(): "
1974 "failed to set up association\n");
1975 mutex_exit(&sc->sc_glock);
1976 return (err);
1977 }
1978
1979 /*
1980 * start automatic rate control
1981 */
1982 if ((in->in_flags & IEEE80211_NODE_HT) &&
1983 (sc->sc_ht_conf.ht_support) &&
1984 (in->in_htrates.rs_nrates > 0) &&
1985 (in->in_htrates.rs_nrates <= IEEE80211_HTRATE_MAXSIZE)) {
1986 amrr = (iwh_amrr_t *)in;
1987
1988 for (i = in->in_htrates.rs_nrates - 1; i > 0; i--) {
1989
1990 r = in->in_htrates.rs_rates[i] &
1991 IEEE80211_RATE_VAL;
1992 if ((r != 0) && (r <= 0xd) &&
1993 (sc->sc_ht_conf.tx_support_mcs[r/8] &
1994 (1 << (r%8)))) {
1995 amrr->ht_mcs_idx = r;
1996 atomic_or_32(&sc->sc_flags,
1997 IWH_F_RATE_AUTO_CTL);
1998 break;
1999 }
2000 }
2001 } else {
2002 if (IEEE80211_FIXED_RATE_NONE == ic->ic_fixed_rate) {
2003 atomic_or_32(&sc->sc_flags,
2004 IWH_F_RATE_AUTO_CTL);
2005
2006 /*
2007 * set rate to some reasonable initial value
2008 */
2009 i = in->in_rates.ir_nrates - 1;
2010 while (i > 0 && IEEE80211_RATE(i) > 72) {
2011 i--;
2012 }
2013 in->in_txrate = i;
2014
2015 } else {
2016 atomic_and_32(&sc->sc_flags,
2017 ~IWH_F_RATE_AUTO_CTL);
2018 }
2019 }
2020
2021 /*
2022 * set LED on after associated
2023 */
2024 iwh_set_led(sc, 2, 0, 1);
2025 break;
2026
2027 case IEEE80211_S_INIT:
2028 if (ostate == IEEE80211_S_SCAN) {
2029 atomic_and_32(&sc->sc_flags, ~IWH_F_SCANNING);
2030 }
2031 /*
2032 * set LED off after init
2033 */
2034 iwh_set_led(sc, 2, 1, 0);
2035 break;
2036
2037 case IEEE80211_S_ASSOC:
2038 if (ostate == IEEE80211_S_SCAN) {
2039 atomic_and_32(&sc->sc_flags, ~IWH_F_SCANNING);
2040 }
2041 break;
2042 }
2043
2044 mutex_exit(&sc->sc_glock);
2045
2046 return (sc->sc_newstate(ic, nstate, arg));
2047 }
2048
2049 /*
2050 * exclusive access to mac begin.
2051 */
2052 static void
2053 iwh_mac_access_enter(iwh_sc_t *sc)
2054 {
2055 uint32_t tmp;
2056 int n;
2057
2058 tmp = IWH_READ(sc, CSR_GP_CNTRL);
2059 IWH_WRITE(sc, CSR_GP_CNTRL,
2060 tmp | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
2061
2062 /*
2063 * wait until we succeed
2064 */
2065 for (n = 0; n < 1000; n++) {
2066 if ((IWH_READ(sc, CSR_GP_CNTRL) &
2067 (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
2068 CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP)) ==
2069 CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN) {
2070 break;
2071 }
2072 DELAY(10);
2073 }
2074
2075 #ifdef DEBUG
2076 if (1000 == n) {
2077 IWH_DBG((IWH_DEBUG_PIO, "iwh_mac_access_enter(): "
2078 "could not lock memory\n"));
2079 }
2080 #endif
2081 }
2082
2083 /*
2084 * exclusive access to mac end.
2085 */
2086 static void
2087 iwh_mac_access_exit(iwh_sc_t *sc)
2088 {
2089 uint32_t tmp = IWH_READ(sc, CSR_GP_CNTRL);
2090 IWH_WRITE(sc, CSR_GP_CNTRL,
2091 tmp & ~CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
2092 }
2093
2094 /*
2095 * this function defined here for future use.
2096 * static uint32_t
2097 * iwh_mem_read(iwh_sc_t *sc, uint32_t addr)
2098 * {
2099 * IWH_WRITE(sc, HBUS_TARG_MEM_RADDR, addr);
2100 * return (IWH_READ(sc, HBUS_TARG_MEM_RDAT));
2101 * }
2102 */
2103
2104 /*
2105 * write mac memory
2106 */
2107 static void
2108 iwh_mem_write(iwh_sc_t *sc, uint32_t addr, uint32_t data)
2109 {
2110 IWH_WRITE(sc, HBUS_TARG_MEM_WADDR, addr);
2111 IWH_WRITE(sc, HBUS_TARG_MEM_WDAT, data);
2112 }
2113
2114 /*
2115 * read mac register
2116 */
2117 static uint32_t
2118 iwh_reg_read(iwh_sc_t *sc, uint32_t addr)
2119 {
2120 IWH_WRITE(sc, HBUS_TARG_PRPH_RADDR, addr | (3 << 24));
2121 return (IWH_READ(sc, HBUS_TARG_PRPH_RDAT));
2122 }
2123
2124 /*
2125 * write mac register
2126 */
2127 static void
2128 iwh_reg_write(iwh_sc_t *sc, uint32_t addr, uint32_t data)
2129 {
2130 IWH_WRITE(sc, HBUS_TARG_PRPH_WADDR, addr | (3 << 24));
2131 IWH_WRITE(sc, HBUS_TARG_PRPH_WDAT, data);
2132 }
2133
2134
2135 /*
2136 * steps of loading ucode:
2137 * load init ucode=>init alive=>calibrate=>
2138 * receive calibration result=>reinitialize NIC=>
2139 * load runtime ucode=>runtime alive=>
2140 * send calibration result=>running.
2141 */
2142 static int
2143 iwh_load_init_firmware(iwh_sc_t *sc)
2144 {
2145 int err = IWH_FAIL;
2146 clock_t clk;
2147
2148 atomic_and_32(&sc->sc_flags, ~IWH_F_PUT_SEG);
2149
2150 /*
2151 * load init_text section of uCode to hardware
2152 */
2153 err = iwh_put_seg_fw(sc, sc->sc_dma_fw_init_text.cookie.dmac_address,
2154 RTC_INST_LOWER_BOUND, sc->sc_dma_fw_init_text.cookie.dmac_size);
2155 if (err != IWH_SUCCESS) {
2156 cmn_err(CE_WARN, "iwh_load_init_firmware(): "
2157 "failed to write init uCode.\n");
2158 return (err);
2159 }
2160
2161 clk = ddi_get_lbolt() + drv_usectohz(1000000);
2162
2163 /*
2164 * wait loading init_text until completed or timeout
2165 */
2166 while (!(sc->sc_flags & IWH_F_PUT_SEG)) {
2167 if (cv_timedwait(&sc->sc_put_seg_cv, &sc->sc_glock, clk) < 0) {
2168 break;
2169 }
2170 }
2171
2172 if (!(sc->sc_flags & IWH_F_PUT_SEG)) {
2173 cmn_err(CE_WARN, "iwh_load_init_firmware(): "
2174 "timeout waiting for init uCode load.\n");
2175 return (IWH_FAIL);
2176 }
2177
2178 atomic_and_32(&sc->sc_flags, ~IWH_F_PUT_SEG);
2179
2180 /*
2181 * load init_data section of uCode to hardware
2182 */
2183 err = iwh_put_seg_fw(sc, sc->sc_dma_fw_init_data.cookie.dmac_address,
2184 RTC_DATA_LOWER_BOUND, sc->sc_dma_fw_init_data.cookie.dmac_size);
2185 if (err != IWH_SUCCESS) {
2186 cmn_err(CE_WARN, "iwh_load_init_firmware(): "
2187 "failed to write init_data uCode.\n");
2188 return (err);
2189 }
2190
2191 clk = ddi_get_lbolt() + drv_usectohz(1000000);
2192
2193 /*
2194 * wait loading init_data until completed or timeout
2195 */
2196 while (!(sc->sc_flags & IWH_F_PUT_SEG)) {
2197 if (cv_timedwait(&sc->sc_put_seg_cv, &sc->sc_glock, clk) < 0) {
2198 break;
2199 }
2200 }
2201
2202 if (!(sc->sc_flags & IWH_F_PUT_SEG)) {
2203 cmn_err(CE_WARN, "iwh_load_init_firmware(): "
2204 "timeout waiting for init_data uCode load.\n");
2205 return (IWH_FAIL);
2206 }
2207
2208 atomic_and_32(&sc->sc_flags, ~IWH_F_PUT_SEG);
2209
2210 return (err);
2211 }
2212
2213 static int
2214 iwh_load_run_firmware(iwh_sc_t *sc)
2215 {
2216 int err = IWH_FAIL;
2217 clock_t clk;
2218
2219 atomic_and_32(&sc->sc_flags, ~IWH_F_PUT_SEG);
2220
2221 /*
2222 * load init_text section of uCode to hardware
2223 */
2224 err = iwh_put_seg_fw(sc, sc->sc_dma_fw_text.cookie.dmac_address,
2225 RTC_INST_LOWER_BOUND, sc->sc_dma_fw_text.cookie.dmac_size);
2226 if (err != IWH_SUCCESS) {
2227 cmn_err(CE_WARN, "iwh_load_run_firmware(): "
2228 "failed to write run uCode.\n");
2229 return (err);
2230 }
2231
2232 clk = ddi_get_lbolt() + drv_usectohz(1000000);
2233
2234 /*
2235 * wait loading run_text until completed or timeout
2236 */
2237 while (!(sc->sc_flags & IWH_F_PUT_SEG)) {
2238 if (cv_timedwait(&sc->sc_put_seg_cv, &sc->sc_glock, clk) < 0) {
2239 break;
2240 }
2241 }
2242
2243 if (!(sc->sc_flags & IWH_F_PUT_SEG)) {
2244 cmn_err(CE_WARN, "iwh_load_run_firmware(): "
2245 "timeout waiting for run uCode load.\n");
2246 return (IWH_FAIL);
2247 }
2248
2249 atomic_and_32(&sc->sc_flags, ~IWH_F_PUT_SEG);
2250
2251 /*
2252 * load run_data section of uCode to hardware
2253 */
2254 err = iwh_put_seg_fw(sc, sc->sc_dma_fw_data_bak.cookie.dmac_address,
2255 RTC_DATA_LOWER_BOUND, sc->sc_dma_fw_data.cookie.dmac_size);
2256 if (err != IWH_SUCCESS) {
2257 cmn_err(CE_WARN, "iwh_load_run_firmware(): "
2258 "failed to write run_data uCode.\n");
2259 return (err);
2260 }
2261
2262 clk = ddi_get_lbolt() + drv_usectohz(1000000);
2263
2264 /*
2265 * wait loading run_data until completed or timeout
2266 */
2267 while (!(sc->sc_flags & IWH_F_PUT_SEG)) {
2268 if (cv_timedwait(&sc->sc_put_seg_cv, &sc->sc_glock, clk) < 0) {
2269 break;
2270 }
2271 }
2272
2273 if (!(sc->sc_flags & IWH_F_PUT_SEG)) {
2274 cmn_err(CE_WARN, "iwh_load_run_firmware(): "
2275 "timeout waiting for run_data uCode load.\n");
2276 return (IWH_FAIL);
2277 }
2278
2279 atomic_and_32(&sc->sc_flags, ~IWH_F_PUT_SEG);
2280
2281 return (err);
2282 }
2283
2284 /*
2285 * this function will be invoked to receive phy information
2286 * when a frame is received.
2287 */
2288 static void
2289 iwh_rx_phy_intr(iwh_sc_t *sc, iwh_rx_desc_t *desc)
2290 {
2291
2292 sc->sc_rx_phy_res.flag = 1;
2293
2294 bcopy((uint8_t *)(desc + 1), sc->sc_rx_phy_res.buf,
2295 sizeof (iwh_rx_phy_res_t));
2296 }
2297
2298 /*
2299 * this function will be invoked to receive body of frame when
2300 * a frame is received.
2301 */
2302 static void
2303 iwh_rx_mpdu_intr(iwh_sc_t *sc, iwh_rx_desc_t *desc)
2304 {
2305 ieee80211com_t *ic = &sc->sc_ic;
2306 #ifdef DEBUG
2307 iwh_rx_ring_t *ring = &sc->sc_rxq;
2308 #endif
2309 struct ieee80211_frame *wh;
2310 struct iwh_rx_non_cfg_phy *phyinfo;
2311 struct iwh_rx_mpdu_body_size *mpdu_size;
2312 mblk_t *mp;
2313 int16_t t;
2314 uint16_t len, rssi, agc;
2315 uint32_t temp, crc, *tail;
2316 uint32_t arssi, brssi, crssi, mrssi;
2317 iwh_rx_phy_res_t *stat;
2318 ieee80211_node_t *in;
2319
2320 /*
2321 * assuming not 11n here. cope with 11n in phase-II
2322 */
2323 mpdu_size = (struct iwh_rx_mpdu_body_size *)(desc + 1);
2324 stat = (iwh_rx_phy_res_t *)sc->sc_rx_phy_res.buf;
2325 if (stat->cfg_phy_cnt > 20) {
2326 return;
2327 }
2328
2329 phyinfo = (struct iwh_rx_non_cfg_phy *)stat->non_cfg_phy;
2330 temp = LE_32(phyinfo->non_cfg_phy[IWH_RX_RES_AGC_IDX]);
2331 agc = (temp & IWH_OFDM_AGC_MSK) >> IWH_OFDM_AGC_BIT_POS;
2332
2333 temp = LE_32(phyinfo->non_cfg_phy[IWH_RX_RES_RSSI_AB_IDX]);
2334 arssi = (temp & IWH_OFDM_RSSI_A_MSK) >> IWH_OFDM_RSSI_A_BIT_POS;
2335 brssi = (temp & IWH_OFDM_RSSI_B_MSK) >> IWH_OFDM_RSSI_B_BIT_POS;
2336
2337 temp = LE_32(phyinfo->non_cfg_phy[IWH_RX_RES_RSSI_C_IDX]);
2338 crssi = (temp & IWH_OFDM_RSSI_C_MSK) >> IWH_OFDM_RSSI_C_BIT_POS;
2339
2340 mrssi = MAX(arssi, brssi);
2341 mrssi = MAX(mrssi, crssi);
2342
2343 t = mrssi - agc - IWH_RSSI_OFFSET;
2344 /*
2345 * convert dBm to percentage
2346 */
2347 rssi = (100 * 75 * 75 - (-20 - t) * (15 * 75 + 62 * (-20 - t)))
2348 / (75 * 75);
2349 if (rssi > 100) {
2350 rssi = 100;
2351 }
2352 if (rssi < 1) {
2353 rssi = 1;
2354 }
2355
2356 /*
2357 * size of frame, not include FCS
2358 */
2359 len = LE_16(mpdu_size->byte_count);
2360 tail = (uint32_t *)((uint8_t *)(desc + 1) +
2361 sizeof (struct iwh_rx_mpdu_body_size) + len);
2362 bcopy(tail, &crc, 4);
2363
2364 IWH_DBG((IWH_DEBUG_RX, "iwh_rx_mpdu_intr(): "
2365 "rx intr: idx=%d phy_len=%x len=%d "
2366 "rate=%x chan=%d tstamp=%x non_cfg_phy_count=%x "
2367 "cfg_phy_count=%x tail=%x", ring->cur, sizeof (*stat),
2368 len, stat->rate.r.s.rate, stat->channel,
2369 LE_32(stat->timestampl), stat->non_cfg_phy_cnt,
2370 stat->cfg_phy_cnt, LE_32(crc)));
2371
2372 if ((len < 16) || (len > sc->sc_dmabuf_sz)) {
2373 IWH_DBG((IWH_DEBUG_RX, "iwh_rx_mpdu_intr(): "
2374 "rx frame oversize\n"));
2375 return;
2376 }
2377
2378 /*
2379 * discard Rx frames with bad CRC
2380 */
2381 if ((LE_32(crc) &
2382 (RX_RES_STATUS_NO_CRC32_ERROR | RX_RES_STATUS_NO_RXE_OVERFLOW)) !=
2383 (RX_RES_STATUS_NO_CRC32_ERROR | RX_RES_STATUS_NO_RXE_OVERFLOW)) {
2384 IWH_DBG((IWH_DEBUG_RX, "iwh_rx_mpdu_intr(): "
2385 "rx crc error tail: %x\n",
2386 LE_32(crc)));
2387 sc->sc_rx_err++;
2388 return;
2389 }
2390
2391 wh = (struct ieee80211_frame *)
2392 ((uint8_t *)(desc + 1)+ sizeof (struct iwh_rx_mpdu_body_size));
2393
2394 if (IEEE80211_FC0_SUBTYPE_ASSOC_RESP == *(uint8_t *)wh) {
2395 sc->sc_assoc_id = *((uint16_t *)(wh + 1) + 2);
2396 IWH_DBG((IWH_DEBUG_RX, "iwh_rx_mpdu_intr(): "
2397 "rx : association id = %x\n",
2398 sc->sc_assoc_id));
2399 }
2400
2401 #ifdef DEBUG
2402 if (iwh_dbg_flags & IWH_DEBUG_RX) {
2403 ieee80211_dump_pkt((uint8_t *)wh, len, 0, 0);
2404 }
2405 #endif
2406
2407 in = ieee80211_find_rxnode(ic, wh);
2408 mp = allocb(len, BPRI_MED);
2409 if (mp) {
2410 bcopy(wh, mp->b_wptr, len);
2411 mp->b_wptr += len;
2412
2413 /*
2414 * send the frame to the 802.11 layer
2415 */
2416 (void) ieee80211_input(ic, mp, in, rssi, 0);
2417 } else {
2418 sc->sc_rx_nobuf++;
2419 IWH_DBG((IWH_DEBUG_RX, "iwh_rx_mpdu_intr(): "
2420 "alloc rx buf failed\n"));
2421 }
2422
2423 /*
2424 * release node reference
2425 */
2426 ieee80211_free_node(in);
2427 }
2428
2429 /*
2430 * process correlative affairs after a frame is sent.
2431 */
2432 static void
2433 iwh_tx_intr(iwh_sc_t *sc, iwh_rx_desc_t *desc)
2434 {
2435 ieee80211com_t *ic = &sc->sc_ic;
2436 iwh_tx_ring_t *ring = &sc->sc_txq[desc->hdr.qid & 0x3];
2437 iwh_tx_stat_t *stat = (iwh_tx_stat_t *)(desc + 1);
2438 iwh_amrr_t *amrr;
2439
2440 if (NULL == ic->ic_bss) {
2441 return;
2442 }
2443
2444 amrr = (iwh_amrr_t *)ic->ic_bss;
2445
2446 amrr->txcnt++;
2447 IWH_DBG((IWH_DEBUG_RATECTL, "iwh_tx_intr(): "
2448 "tx: %d cnt\n", amrr->txcnt));
2449
2450 if (stat->ntries > 0) {
2451 amrr->retrycnt++;
2452 sc->sc_tx_retries++;
2453 IWH_DBG((IWH_DEBUG_TX, "iwh_tx_intr(): "
2454 "tx: %d retries\n",
2455 sc->sc_tx_retries));
2456 }
2457
2458 mutex_enter(&sc->sc_mt_lock);
2459 sc->sc_tx_timer = 0;
2460 mutex_exit(&sc->sc_mt_lock);
2461
2462 mutex_enter(&sc->sc_tx_lock);
2463
2464 ring->queued--;
2465 if (ring->queued < 0) {
2466 ring->queued = 0;
2467 }
2468
2469 if ((sc->sc_need_reschedule) && (ring->queued <= (ring->count >> 3))) {
2470 sc->sc_need_reschedule = 0;
2471 mutex_exit(&sc->sc_tx_lock);
2472 mac_tx_update(ic->ic_mach);
2473 mutex_enter(&sc->sc_tx_lock);
2474 }
2475
2476 mutex_exit(&sc->sc_tx_lock);
2477 }
2478
2479 /*
2480 * inform a given command has been executed
2481 */
2482 static void
2483 iwh_cmd_intr(iwh_sc_t *sc, iwh_rx_desc_t *desc)
2484 {
2485 if ((desc->hdr.qid & 7) != 4) {
2486 return;
2487 }
2488
2489 if (sc->sc_cmd_accum > 0) {
2490 sc->sc_cmd_accum--;
2491 return;
2492 }
2493
2494 mutex_enter(&sc->sc_glock);
2495
2496 sc->sc_cmd_flag = SC_CMD_FLG_DONE;
2497
2498 cv_signal(&sc->sc_cmd_cv);
2499
2500 mutex_exit(&sc->sc_glock);
2501
2502 IWH_DBG((IWH_DEBUG_CMD, "iwh_cmd_intr(): "
2503 "qid=%x idx=%d flags=%x type=0x%x\n",
2504 desc->hdr.qid, desc->hdr.idx, desc->hdr.flags,
2505 desc->hdr.type));
2506 }
2507
2508 /*
2509 * this function will be invoked when alive notification occur.
2510 */
2511 static void
2512 iwh_ucode_alive(iwh_sc_t *sc, iwh_rx_desc_t *desc)
2513 {
2514 uint32_t rv;
2515 struct iwh_calib_cfg_cmd cmd;
2516 struct iwh_alive_resp *ar =
2517 (struct iwh_alive_resp *)(desc + 1);
2518 struct iwh_calib_results *res_p = &sc->sc_calib_results;
2519
2520 /*
2521 * the microcontroller is ready
2522 */
2523 IWH_DBG((IWH_DEBUG_FW, "iwh_ucode_alive(): "
2524 "microcode alive notification minor: %x major: %x type: "
2525 "%x subtype: %x\n",
2526 ar->ucode_minor, ar->ucode_minor, ar->ver_type, ar->ver_subtype));
2527
2528 #ifdef DEBUG
2529 if (LE_32(ar->is_valid) != UCODE_VALID_OK) {
2530 IWH_DBG((IWH_DEBUG_FW, "iwh_ucode_alive(): "
2531 "microcontroller initialization failed\n"));
2532 }
2533 #endif
2534
2535 /*
2536 * determine if init alive or runtime alive.
2537 */
2538 if (INITIALIZE_SUBTYPE == ar->ver_subtype) {
2539 IWH_DBG((IWH_DEBUG_FW, "iwh_ucode_alive(): "
2540 "initialization alive received.\n"));
2541
2542 bcopy(ar, &sc->sc_card_alive_init,
2543 sizeof (struct iwh_init_alive_resp));
2544
2545 /*
2546 * necessary configuration to NIC
2547 */
2548 mutex_enter(&sc->sc_glock);
2549
2550 rv = iwh_alive_common(sc);
2551 if (rv != IWH_SUCCESS) {
2552 cmn_err(CE_WARN, "iwh_ucode_alive(): "
2553 "common alive process failed in init alive.\n");
2554 mutex_exit(&sc->sc_glock);
2555 return;
2556 }
2557
2558 (void) memset(&cmd, 0, sizeof (cmd));
2559
2560 cmd.ucd_calib_cfg.once.is_enable = IWH_CALIB_INIT_CFG_ALL;
2561 cmd.ucd_calib_cfg.once.start = IWH_CALIB_INIT_CFG_ALL;
2562 cmd.ucd_calib_cfg.once.send_res = IWH_CALIB_INIT_CFG_ALL;
2563 cmd.ucd_calib_cfg.flags = IWH_CALIB_INIT_CFG_ALL;
2564
2565 /*
2566 * require ucode execute calibration
2567 */
2568 rv = iwh_cmd(sc, CALIBRATION_CFG_CMD, &cmd, sizeof (cmd), 1);
2569 if (rv != IWH_SUCCESS) {
2570 cmn_err(CE_WARN, "iwh_ucode_alive(): "
2571 "failed to send calibration configure command.\n");
2572 mutex_exit(&sc->sc_glock);
2573 return;
2574 }
2575
2576 mutex_exit(&sc->sc_glock);
2577
2578 } else { /* runtime alive */
2579
2580 IWH_DBG((IWH_DEBUG_FW, "iwh_ucode_alive(): "
2581 "runtime alive received.\n"));
2582
2583 bcopy(ar, &sc->sc_card_alive_run,
2584 sizeof (struct iwh_alive_resp));
2585
2586 mutex_enter(&sc->sc_glock);
2587
2588 /*
2589 * necessary configuration to NIC
2590 */
2591 rv = iwh_alive_common(sc);
2592 if (rv != IWH_SUCCESS) {
2593 cmn_err(CE_WARN, "iwh_ucode_alive(): "
2594 "common alive process failed in run alive.\n");
2595 mutex_exit(&sc->sc_glock);
2596 return;
2597 }
2598
2599 /*
2600 * send the result of local oscilator calibration to uCode.
2601 */
2602 if (res_p->lo_res != NULL) {
2603 rv = iwh_cmd(sc, REPLY_PHY_CALIBRATION_CMD,
2604 res_p->lo_res, res_p->lo_res_len, 1);
2605 if (rv != IWH_SUCCESS) {
2606 cmn_err(CE_WARN, "iwh_ucode_alive(): "
2607 "failed to send local"
2608 "oscilator calibration command.\n");
2609 mutex_exit(&sc->sc_glock);
2610 return;
2611 }
2612
2613 DELAY(1000);
2614 }
2615
2616 /*
2617 * send the result of TX IQ calibration to uCode.
2618 */
2619 if (res_p->tx_iq_res != NULL) {
2620 rv = iwh_cmd(sc, REPLY_PHY_CALIBRATION_CMD,
2621 res_p->tx_iq_res, res_p->tx_iq_res_len, 1);
2622 if (rv != IWH_SUCCESS) {
2623 cmn_err(CE_WARN, "iwh_ucode_alive(): "
2624 "failed to send TX IQ"
2625 "calibration command.\n");
2626 mutex_exit(&sc->sc_glock);
2627 return;
2628 }
2629
2630 DELAY(1000);
2631 }
2632
2633 /*
2634 * sned the result of TX IQ perd calibration to uCode.
2635 */
2636 if (res_p->tx_iq_perd_res != NULL) {
2637 rv = iwh_cmd(sc, REPLY_PHY_CALIBRATION_CMD,
2638 res_p->tx_iq_perd_res,
2639 res_p->tx_iq_perd_res_len, 1);
2640 if (rv != IWH_SUCCESS) {
2641 cmn_err(CE_WARN, "iwh_ucode_alive(): "
2642 "failed to send TX IQ perd"
2643 "calibration command.\n");
2644 mutex_exit(&sc->sc_glock);
2645 return;
2646 }
2647
2648 DELAY(1000);
2649 }
2650
2651 /*
2652 * send the result of DC calibration to uCode.
2653 */
2654 if (res_p->dc_res != NULL) {
2655 rv = iwh_cmd(sc, REPLY_PHY_CALIBRATION_CMD,
2656 res_p->dc_res,
2657 res_p->dc_res_len, 1);
2658 if (rv != IWH_SUCCESS) {
2659 cmn_err(CE_WARN, "iwh_ucode_alive(): "
2660 "failed to send DC"
2661 "calibration command.\n");
2662 mutex_exit(&sc->sc_glock);
2663 return;
2664 }
2665
2666 DELAY(1000);
2667 }
2668
2669 /*
2670 * send the result of BASE BAND calibration to uCode.
2671 */
2672 if (res_p->base_band_res != NULL) {
2673 rv = iwh_cmd(sc, REPLY_PHY_CALIBRATION_CMD,
2674 res_p->base_band_res,
2675 res_p->base_band_res_len, 1);
2676 if (rv != IWH_SUCCESS) {
2677 cmn_err(CE_WARN, "iwh_ucode_alive(): "
2678 "failed to send BASE BAND"
2679 "calibration command.\n");
2680 mutex_exit(&sc->sc_glock);
2681 return;
2682 }
2683
2684 DELAY(1000);
2685 }
2686
2687 atomic_or_32(&sc->sc_flags, IWH_F_FW_INIT);
2688 cv_signal(&sc->sc_ucode_cv);
2689
2690 mutex_exit(&sc->sc_glock);
2691 }
2692
2693 }
2694
2695 /*
2696 * deal with receiving frames, command response
2697 * and all notifications from ucode.
2698 */
2699 /* ARGSUSED */
2700 static uint_t
2701 iwh_rx_softintr(caddr_t arg, caddr_t unused)
2702 {
2703 iwh_sc_t *sc;
2704 ieee80211com_t *ic;
2705 iwh_rx_desc_t *desc;
2706 iwh_rx_data_t *data;
2707 uint32_t index;
2708
2709 if (NULL == arg) {
2710 return (DDI_INTR_UNCLAIMED);
2711 }
2712 sc = (iwh_sc_t *)arg;
2713 ic = &sc->sc_ic;
2714
2715 /*
2716 * firmware has moved the index of the rx queue, driver get it,
2717 * and deal with it.
2718 */
2719 index = (sc->sc_shared->val0) & 0xfff;
2720
2721 while (sc->sc_rxq.cur != index) {
2722 data = &sc->sc_rxq.data[sc->sc_rxq.cur];
2723 desc = (iwh_rx_desc_t *)data->dma_data.mem_va;
2724
2725 IWH_DBG((IWH_DEBUG_INTR, "iwh_rx_softintr(): "
2726 "rx notification index = %d"
2727 " cur = %d qid=%x idx=%d flags=%x type=%x len=%d\n",
2728 index, sc->sc_rxq.cur, desc->hdr.qid, desc->hdr.idx,
2729 desc->hdr.flags, desc->hdr.type, LE_32(desc->len)));
2730
2731 /*
2732 * a command other than a tx need to be replied
2733 */
2734 if (!(desc->hdr.qid & 0x80) &&
2735 (desc->hdr.type != REPLY_SCAN_CMD) &&
2736 (desc->hdr.type != REPLY_TX)) {
2737 iwh_cmd_intr(sc, desc);
2738 }
2739
2740 switch (desc->hdr.type) {
2741 case REPLY_RX_PHY_CMD:
2742 iwh_rx_phy_intr(sc, desc);
2743 break;
2744
2745 case REPLY_RX_MPDU_CMD:
2746 iwh_rx_mpdu_intr(sc, desc);
2747 break;
2748
2749 case REPLY_TX:
2750 iwh_tx_intr(sc, desc);
2751 break;
2752
2753 case REPLY_ALIVE:
2754 iwh_ucode_alive(sc, desc);
2755 break;
2756
2757 case CARD_STATE_NOTIFICATION:
2758 {
2759 uint32_t *status = (uint32_t *)(desc + 1);
2760
2761 IWH_DBG((IWH_DEBUG_RADIO, "iwh_rx_softintr(): "
2762 "state changed to %x\n",
2763 LE_32(*status)));
2764
2765 if (LE_32(*status) & 1) {
2766 /*
2767 * the radio button has to be pushed(OFF). It
2768 * is considered as a hw error, the
2769 * iwh_thread() tries to recover it after the
2770 * button is pushed again(ON)
2771 */
2772 cmn_err(CE_NOTE, "iwh_rx_softintr(): "
2773 "radio transmitter is off\n");
2774 sc->sc_ostate = sc->sc_ic.ic_state;
2775 ieee80211_new_state(&sc->sc_ic,
2776 IEEE80211_S_INIT, -1);
2777 atomic_or_32(&sc->sc_flags,
2778 (IWH_F_HW_ERR_RECOVER | IWH_F_RADIO_OFF));
2779 }
2780
2781 break;
2782 }
2783
2784 case SCAN_START_NOTIFICATION:
2785 {
2786 iwh_start_scan_t *scan =
2787 (iwh_start_scan_t *)(desc + 1);
2788
2789 IWH_DBG((IWH_DEBUG_SCAN, "iwh_rx_softintr(): "
2790 "scanning channel %d status %x\n",
2791 scan->chan, LE_32(scan->status)));
2792
2793 ic->ic_curchan = &ic->ic_sup_channels[scan->chan];
2794 break;
2795 }
2796
2797 case SCAN_COMPLETE_NOTIFICATION:
2798 {
2799 #ifdef DEBUG
2800 iwh_stop_scan_t *scan =
2801 (iwh_stop_scan_t *)(desc + 1);
2802
2803 IWH_DBG((IWH_DEBUG_SCAN, "iwh_rx_softintr(): "
2804 "completed channel %d (burst of %d) status %02x\n",
2805 scan->chan, scan->nchan, scan->status));
2806 #endif
2807
2808 sc->sc_scan_pending++;
2809 break;
2810 }
2811
2812 case STATISTICS_NOTIFICATION:
2813 {
2814 /*
2815 * handle statistics notification
2816 */
2817 break;
2818 }
2819
2820 case CALIBRATION_RES_NOTIFICATION:
2821 iwh_save_calib_result(sc, desc);
2822 break;
2823
2824 case CALIBRATION_COMPLETE_NOTIFICATION:
2825 mutex_enter(&sc->sc_glock);
2826 atomic_or_32(&sc->sc_flags, IWH_F_FW_INIT);
2827 cv_signal(&sc->sc_ucode_cv);
2828 mutex_exit(&sc->sc_glock);
2829 break;
2830
2831 case MISSED_BEACONS_NOTIFICATION:
2832 /* handle beacon miss by software mechanism */
2833 break;
2834 }
2835
2836 sc->sc_rxq.cur = (sc->sc_rxq.cur + 1) % RX_QUEUE_SIZE;
2837 }
2838
2839 /*
2840 * driver dealt with what received in rx queue and tell the information
2841 * to the firmware.
2842 */
2843 index = (0 == index) ? RX_QUEUE_SIZE - 1 : index - 1;
2844 IWH_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, index & (~7));
2845
2846 /*
2847 * re-enable interrupts
2848 */
2849 IWH_WRITE(sc, CSR_INT_MASK, CSR_INI_SET_MASK);
2850
2851 return (DDI_INTR_CLAIMED);
2852 }
2853
2854 /*
2855 * the handle of interrupt
2856 */
2857 /* ARGSUSED */
2858 static uint_t
2859 iwh_intr(caddr_t arg, caddr_t unused)
2860 {
2861 iwh_sc_t *sc;
2862 uint32_t r, rfh;
2863
2864 if (NULL == arg) {
2865 return (DDI_INTR_UNCLAIMED);
2866 }
2867 sc = (iwh_sc_t *)arg;
2868
2869 r = IWH_READ(sc, CSR_INT);
2870 if (0 == r || 0xffffffff == r) {
2871 return (DDI_INTR_UNCLAIMED);
2872 }
2873
2874 IWH_DBG((IWH_DEBUG_INTR, "iwh_intr(): "
2875 "interrupt reg %x\n", r));
2876
2877 rfh = IWH_READ(sc, CSR_FH_INT_STATUS);
2878
2879 IWH_DBG((IWH_DEBUG_INTR, "iwh_intr(): "
2880 "FH interrupt reg %x\n", rfh));
2881
2882 /*
2883 * disable interrupts
2884 */
2885 IWH_WRITE(sc, CSR_INT_MASK, 0);
2886
2887 /*
2888 * ack interrupts
2889 */
2890 IWH_WRITE(sc, CSR_INT, r);
2891 IWH_WRITE(sc, CSR_FH_INT_STATUS, rfh);
2892
2893 if (r & (BIT_INT_SWERROR | BIT_INT_ERR)) {
2894 IWH_DBG((IWH_DEBUG_FW, "iwh_intr(): "
2895 "fatal firmware error\n"));
2896 iwh_stop(sc);
2897 sc->sc_ostate = sc->sc_ic.ic_state;
2898
2899 /*
2900 * notify upper layer
2901 */
2902 if (!IWH_CHK_FAST_RECOVER(sc)) {
2903 ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
2904 }
2905
2906 atomic_or_32(&sc->sc_flags, IWH_F_HW_ERR_RECOVER);
2907 return (DDI_INTR_CLAIMED);
2908 }
2909
2910 if (r & BIT_INT_RF_KILL) {
2911 uint32_t tmp = IWH_READ(sc, CSR_GP_CNTRL);
2912 if (tmp & (1 << 27)) {
2913 cmn_err(CE_NOTE, "RF switch: radio on\n");
2914 }
2915 }
2916
2917 if ((r & (BIT_INT_FH_RX | BIT_INT_SW_RX)) ||
2918 (rfh & FH_INT_RX_MASK)) {
2919 (void) ddi_intr_trigger_softint(sc->sc_soft_hdl, NULL);
2920 return (DDI_INTR_CLAIMED);
2921 }
2922
2923 if (r & BIT_INT_FH_TX) {
2924 mutex_enter(&sc->sc_glock);
2925 atomic_or_32(&sc->sc_flags, IWH_F_PUT_SEG);
2926 cv_signal(&sc->sc_put_seg_cv);
2927 mutex_exit(&sc->sc_glock);
2928 }
2929
2930 #ifdef DEBUG
2931 if (r & BIT_INT_ALIVE) {
2932 IWH_DBG((IWH_DEBUG_FW, "iwh_intr(): "
2933 "firmware initialized.\n"));
2934 }
2935 #endif
2936
2937 /*
2938 * re-enable interrupts
2939 */
2940 IWH_WRITE(sc, CSR_INT_MASK, CSR_INI_SET_MASK);
2941
2942 return (DDI_INTR_CLAIMED);
2943 }
2944
2945 static uint8_t
2946 iwh_rate_to_plcp(int rate)
2947 {
2948 uint8_t ret;
2949
2950 switch (rate) {
2951 /*
2952 * CCK rates
2953 */
2954 case 2:
2955 ret = 0xa;
2956 break;
2957
2958 case 4:
2959 ret = 0x14;
2960 break;
2961
2962 case 11:
2963 ret = 0x37;
2964 break;
2965
2966 case 22:
2967 ret = 0x6e;
2968 break;
2969
2970 /*
2971 * OFDM rates
2972 */
2973 case 12:
2974 ret = 0xd;
2975 break;
2976
2977 case 18:
2978 ret = 0xf;
2979 break;
2980
2981 case 24:
2982 ret = 0x5;
2983 break;
2984
2985 case 36:
2986 ret = 0x7;
2987 break;
2988
2989 case 48:
2990 ret = 0x9;
2991 break;
2992
2993 case 72:
2994 ret = 0xb;
2995 break;
2996
2997 case 96:
2998 ret = 0x1;
2999 break;
3000
3001 case 108:
3002 ret = 0x3;
3003 break;
3004
3005 default:
3006 ret = 0;
3007 break;
3008 }
3009
3010 return (ret);
3011 }
3012
3013 /*
3014 * invoked by GLD send frames
3015 */
3016 static mblk_t *
3017 iwh_m_tx(void *arg, mblk_t *mp)
3018 {
3019 iwh_sc_t *sc;
3020 ieee80211com_t *ic;
3021 mblk_t *next;
3022
3023 if (NULL == arg) {
3024 return (NULL);
3025 }
3026 sc = (iwh_sc_t *)arg;
3027 ic = &sc->sc_ic;
3028
3029 if (sc->sc_flags & IWH_F_SUSPEND) {
3030 freemsgchain(mp);
3031 return (NULL);
3032 }
3033
3034 if (ic->ic_state != IEEE80211_S_RUN) {
3035 freemsgchain(mp);
3036 return (NULL);
3037 }
3038
3039 if ((sc->sc_flags & IWH_F_HW_ERR_RECOVER) &&
3040 IWH_CHK_FAST_RECOVER(sc)) {
3041 IWH_DBG((IWH_DEBUG_FW, "iwh_m_tx(): "
3042 "hold queue\n"));
3043 return (mp);
3044 }
3045
3046 while (mp != NULL) {
3047 next = mp->b_next;
3048 mp->b_next = NULL;
3049 if (iwh_send(ic, mp, IEEE80211_FC0_TYPE_DATA) != 0) {
3050 mp->b_next = next;
3051 break;
3052 }
3053 mp = next;
3054 }
3055
3056 return (mp);
3057 }
3058
3059 /*
3060 * send frames
3061 */
3062 static int
3063 iwh_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type)
3064 {
3065 iwh_sc_t *sc;
3066 iwh_tx_ring_t *ring;
3067 iwh_tx_desc_t *desc;
3068 iwh_tx_data_t *data;
3069 iwh_tx_data_t *desc_data;
3070 iwh_cmd_t *cmd;
3071 iwh_tx_cmd_t *tx;
3072 ieee80211_node_t *in;
3073 struct ieee80211_frame *wh, *mp_wh;
3074 struct ieee80211_key *k = NULL;
3075 mblk_t *m, *m0;
3076 int hdrlen, len, len0, mblen, off, err = IWH_SUCCESS;
3077 uint16_t masks = 0;
3078 uint32_t rate, s_id = 0;
3079 int txq_id = NON_QOS_TXQ;
3080 struct ieee80211_qosframe *qwh = NULL;
3081 int tid = WME_TID_INVALID;
3082
3083 if (NULL == ic) {
3084 return (IWH_FAIL);
3085 }
3086 sc = (iwh_sc_t *)ic;
3087
3088 if (sc->sc_flags & IWH_F_SUSPEND) {
3089 if ((type & IEEE80211_FC0_TYPE_MASK) !=
3090 IEEE80211_FC0_TYPE_DATA) {
3091 freemsg(mp);
3092 }
3093 err = IWH_FAIL;
3094 goto exit;
3095 }
3096
3097 if ((NULL == mp) || (MBLKL(mp) <= 0)) {
3098 return (IWH_FAIL);
3099 }
3100
3101 mp_wh = (struct ieee80211_frame *)mp->b_rptr;
3102
3103 /*
3104 * Determine send which AP or station in IBSS
3105 */
3106 in = ieee80211_find_txnode(ic, mp_wh->i_addr1);
3107 if (NULL == in) {
3108 cmn_err(CE_WARN, "iwh_send(): "
3109 "failed to find tx node\n");
3110 freemsg(mp);
3111 sc->sc_tx_err++;
3112 err = IWH_SUCCESS;
3113 goto exit;
3114 }
3115
3116 /*
3117 * Determine TX queue according to traffic ID in frame
3118 * if working in QoS mode.
3119 */
3120 if (in->in_flags & IEEE80211_NODE_QOS) {
3121
3122 if ((type & IEEE80211_FC0_TYPE_MASK) ==
3123 IEEE80211_FC0_TYPE_DATA) {
3124
3125 if (mp_wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) {
3126 qwh = (struct ieee80211_qosframe *)mp_wh;
3127
3128 tid = qwh->i_qos[0] & IEEE80211_QOS_TID;
3129 txq_id = iwh_wme_tid_to_txq(tid);
3130
3131 if (txq_id < TXQ_FOR_AC_MIN ||
3132 (txq_id > TXQ_FOR_AC_MAX)) {
3133 freemsg(mp);
3134 sc->sc_tx_err++;
3135 err = IWH_SUCCESS;
3136 goto exit;
3137 }
3138
3139 } else {
3140 txq_id = NON_QOS_TXQ;
3141 }
3142
3143 } else if ((type & IEEE80211_FC0_TYPE_MASK) ==
3144 IEEE80211_FC0_TYPE_MGT) {
3145 txq_id = QOS_TXQ_FOR_MGT;
3146 } else {
3147 txq_id = NON_QOS_TXQ;
3148 }
3149
3150 } else {
3151 txq_id = NON_QOS_TXQ;
3152 }
3153
3154 mutex_enter(&sc->sc_tx_lock);
3155 ring = &sc->sc_txq[txq_id];
3156 data = &ring->data[ring->cur];
3157 cmd = data->cmd;
3158 bzero(cmd, sizeof (*cmd));
3159
3160 ring->cur = (ring->cur + 1) % ring->count;
3161
3162 /*
3163 * Need reschedule TX if TX buffer is full.
3164 */
3165 if (ring->queued > ring->count - IWH_MAX_WIN_SIZE) {
3166 IWH_DBG((IWH_DEBUG_TX, "iwh_send(): "
3167 "no txbuf\n"));
3168
3169 sc->sc_need_reschedule = 1;
3170 mutex_exit(&sc->sc_tx_lock);
3171
3172 if ((type & IEEE80211_FC0_TYPE_MASK) !=
3173 IEEE80211_FC0_TYPE_DATA) {
3174 freemsg(mp);
3175 }
3176 sc->sc_tx_nobuf++;
3177 err = IWH_FAIL;
3178 goto exit;
3179 }
3180
3181 ring->queued++;
3182
3183 mutex_exit(&sc->sc_tx_lock);
3184
3185 hdrlen = ieee80211_hdrspace(ic, mp->b_rptr);
3186
3187 m = allocb(msgdsize(mp) + 32, BPRI_MED);
3188 if (NULL == m) { /* can not alloc buf, drop this package */
3189 cmn_err(CE_WARN, "iwh_send(): "
3190 "failed to allocate msgbuf\n");
3191 freemsg(mp);
3192
3193 mutex_enter(&sc->sc_tx_lock);
3194 ring->queued--;
3195 if ((sc->sc_need_reschedule) && (ring->queued <= 0)) {
3196 sc->sc_need_reschedule = 0;
3197 mutex_exit(&sc->sc_tx_lock);
3198 mac_tx_update(ic->ic_mach);
3199 mutex_enter(&sc->sc_tx_lock);
3200 }
3201 mutex_exit(&sc->sc_tx_lock);
3202
3203 err = IWH_SUCCESS;
3204 goto exit;
3205 }
3206
3207 for (off = 0, m0 = mp; m0 != NULL; m0 = m0->b_cont) {
3208 mblen = MBLKL(m0);
3209 bcopy(m0->b_rptr, m->b_rptr + off, mblen);
3210 off += mblen;
3211 }
3212
3213 m->b_wptr += off;
3214
3215 wh = (struct ieee80211_frame *)m->b_rptr;
3216
3217 /*
3218 * Net80211 module encapsulate outbound data frames.
3219 * Add some feilds of 80211 frame.
3220 */
3221 if ((type & IEEE80211_FC0_TYPE_MASK) ==
3222 IEEE80211_FC0_TYPE_DATA) {
3223 (void) ieee80211_encap(ic, m, in);
3224 }
3225
3226 freemsg(mp);
3227
3228 cmd->hdr.type = REPLY_TX;
3229 cmd->hdr.flags = 0;
3230 cmd->hdr.qid = ring->qid;
3231
3232 tx = (iwh_tx_cmd_t *)cmd->data;
3233 tx->tx_flags = 0;
3234
3235 if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
3236 tx->tx_flags &= ~(LE_32(TX_CMD_FLG_ACK_MSK));
3237 } else {
3238 tx->tx_flags |= LE_32(TX_CMD_FLG_ACK_MSK);
3239 }
3240
3241 if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
3242 k = ieee80211_crypto_encap(ic, m);
3243 if (NULL == k) {
3244 freemsg(m);
3245 sc->sc_tx_err++;
3246
3247 mutex_enter(&sc->sc_tx_lock);
3248 ring->queued--;
3249 if ((sc->sc_need_reschedule) && (ring->queued <= 0)) {
3250 sc->sc_need_reschedule = 0;
3251 mutex_exit(&sc->sc_tx_lock);
3252 mac_tx_update(ic->ic_mach);
3253 mutex_enter(&sc->sc_tx_lock);
3254 }
3255 mutex_exit(&sc->sc_tx_lock);
3256
3257 err = IWH_SUCCESS;
3258 goto exit;
3259 }
3260
3261 /*
3262 * packet header may have moved, reset our local pointer
3263 */
3264 wh = (struct ieee80211_frame *)m->b_rptr;
3265 }
3266
3267 len = msgdsize(m);
3268
3269 #ifdef DEBUG
3270 if (iwh_dbg_flags & IWH_DEBUG_TX) {
3271 ieee80211_dump_pkt((uint8_t *)wh, hdrlen, 0, 0);
3272 }
3273 #endif
3274
3275 tx->rts_retry_limit = IWH_TX_RTS_RETRY_LIMIT;
3276 tx->data_retry_limit = IWH_TX_DATA_RETRY_LIMIT;
3277
3278 /*
3279 * specific TX parameters for management frames
3280 */
3281 if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
3282 IEEE80211_FC0_TYPE_MGT) {
3283 /*
3284 * mgmt frames are sent at 1M
3285 */
3286 if ((in->in_rates.ir_rates[0] &
3287 IEEE80211_RATE_VAL) != 0) {
3288 rate = in->in_rates.ir_rates[0] & IEEE80211_RATE_VAL;
3289 } else {
3290 rate = 2;
3291 }
3292
3293 tx->tx_flags |= LE_32(TX_CMD_FLG_SEQ_CTL_MSK);
3294
3295 /*
3296 * tell h/w to set timestamp in probe responses
3297 */
3298 if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
3299 IEEE80211_FC0_SUBTYPE_PROBE_RESP) {
3300 tx->tx_flags |= LE_32(TX_CMD_FLG_TSF_MSK);
3301
3302 tx->data_retry_limit = 3;
3303 if (tx->data_retry_limit < tx->rts_retry_limit) {
3304 tx->rts_retry_limit = tx->data_retry_limit;
3305 }
3306 }
3307
3308 if (((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
3309 IEEE80211_FC0_SUBTYPE_ASSOC_REQ) ||
3310 ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
3311 IEEE80211_FC0_SUBTYPE_REASSOC_REQ)) {
3312 tx->timeout.pm_frame_timeout = LE_16(3);
3313 } else {
3314 tx->timeout.pm_frame_timeout = LE_16(2);
3315 }
3316
3317 } else {
3318 /*
3319 * do it here for the software way rate scaling.
3320 * later for rate scaling in hardware.
3321 *
3322 * now the txrate is determined in tx cmd flags, set to the
3323 * max value 54M for 11g and 11M for 11b and 96M for 11n
3324 * originally.
3325 */
3326 if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) {
3327 rate = ic->ic_fixed_rate;
3328 } else {
3329 if ((in->in_flags & IEEE80211_NODE_HT) &&
3330 (sc->sc_ht_conf.ht_support)) {
3331 iwh_amrr_t *amrr = (iwh_amrr_t *)in;
3332 rate = amrr->ht_mcs_idx;
3333 } else {
3334 if ((in->in_rates.ir_rates[in->in_txrate] &
3335 IEEE80211_RATE_VAL) != 0) {
3336 rate = in->in_rates.
3337 ir_rates[in->in_txrate] &
3338 IEEE80211_RATE_VAL;
3339 }
3340 }
3341 }
3342
3343 if (tid != WME_TID_INVALID) {
3344 tx->tid_tspec = (uint8_t)tid;
3345 tx->tx_flags &= LE_32(~TX_CMD_FLG_SEQ_CTL_MSK);
3346 } else {
3347 tx->tx_flags |= LE_32(TX_CMD_FLG_SEQ_CTL_MSK);
3348 }
3349
3350 tx->timeout.pm_frame_timeout = 0;
3351 }
3352
3353 IWH_DBG((IWH_DEBUG_TX, "iwh_send(): "
3354 "tx rate[%d of %d] = %x",
3355 in->in_txrate, in->in_rates.ir_nrates, rate));
3356
3357 len0 = roundup(4 + sizeof (iwh_tx_cmd_t) + hdrlen, 4);
3358 if (len0 != (4 + sizeof (iwh_tx_cmd_t) + hdrlen)) {
3359 tx->tx_flags |= LE_32(TX_CMD_FLG_MH_PAD_MSK);
3360 }
3361
3362 /*
3363 * retrieve destination node's id
3364 */
3365 if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
3366 tx->sta_id = IWH_BROADCAST_ID;
3367 } else {
3368 tx->sta_id = IWH_AP_ID;
3369 }
3370
3371 if ((in->in_flags & IEEE80211_NODE_HT) &&
3372 (sc->sc_ht_conf.ht_support) &&
3373 ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
3374 IEEE80211_FC0_TYPE_DATA)) {
3375 if (rate >= HT_2CHAIN_RATE_MIN_IDX) {
3376 rate |= LE_32(RATE_MCS_ANT_AB_MSK);
3377 } else {
3378 rate |= LE_32(RATE_MCS_ANT_B_MSK);
3379 }
3380
3381 rate |= LE_32((1 << RATE_MCS_HT_POS));
3382
3383 tx->rate.r.rate_n_flags = rate;
3384
3385 } else {
3386 if (2 == rate || 4 == rate || 11 == rate || 22 == rate) {
3387 masks |= RATE_MCS_CCK_MSK;
3388 }
3389
3390 masks |= RATE_MCS_ANT_B_MSK;
3391 tx->rate.r.rate_n_flags = LE_32(iwh_rate_to_plcp(rate) | masks);
3392 }
3393
3394 IWH_DBG((IWH_DEBUG_TX, "iwh_send(): "
3395 "tx flag = %x",
3396 tx->tx_flags));
3397
3398 tx->stop_time.life_time = LE_32(0xffffffff);
3399
3400 tx->len = LE_16(len);
3401
3402 tx->dram_lsb_ptr =
3403 LE_32(data->paddr_cmd + 4 + offsetof(iwh_tx_cmd_t, scratch));
3404 tx->dram_msb_ptr = 0;
3405 tx->driver_txop = 0;
3406 tx->next_frame_len = 0;
3407
3408 bcopy(m->b_rptr, tx + 1, hdrlen);
3409 m->b_rptr += hdrlen;
3410 bcopy(m->b_rptr, data->dma_data.mem_va, (len - hdrlen));
3411
3412 IWH_DBG((IWH_DEBUG_TX, "iwh_send(): "
3413 "sending data: qid=%d idx=%d len=%d",
3414 ring->qid, ring->cur, len));
3415
3416 /*
3417 * first segment includes the tx cmd plus the 802.11 header,
3418 * the second includes the remaining of the 802.11 frame.
3419 */
3420
3421 mutex_enter(&sc->sc_tx_lock);
3422 cmd->hdr.idx = ring->desc_cur;
3423 desc_data = &ring->data[ring->desc_cur];
3424 desc = desc_data->desc;
3425 bzero(desc, sizeof (*desc));
3426 desc->val0 = 2 << 24;
3427 desc->pa[0].tb1_addr = data->paddr_cmd;
3428 desc->pa[0].val1 = ((len0 << 4) & 0xfff0) |
3429 ((data->dma_data.cookie.dmac_address & 0xffff) << 16);
3430 desc->pa[0].val2 =
3431 ((data->dma_data.cookie.dmac_address & 0xffff0000) >> 16) |
3432 ((len - hdrlen) << 20);
3433 IWH_DBG((IWH_DEBUG_TX, "iwh_send(): "
3434 "phy addr1 = 0x%x phy addr2 = 0x%x "
3435 "len1 = 0x%x, len2 = 0x%x val1 = 0x%x val2 = 0x%x",
3436 data->paddr_cmd, data->dma_data.cookie.dmac_address,
3437 len0, len - hdrlen, desc->pa[0].val1, desc->pa[0].val2));
3438
3439 /*
3440 * kick ring
3441 */
3442 s_id = tx->sta_id;
3443
3444 sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
3445 tfd_offset[ring->desc_cur].val =
3446 (8 + len) | (s_id << 12);
3447 if (ring->desc_cur < IWH_MAX_WIN_SIZE) {
3448 sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
3449 tfd_offset[IWH_QUEUE_SIZE + ring->desc_cur].val =
3450 (8 + len) | (s_id << 12);
3451 }
3452
3453 IWH_DMA_SYNC(data->dma_data, DDI_DMA_SYNC_FORDEV);
3454 IWH_DMA_SYNC(ring->dma_desc, DDI_DMA_SYNC_FORDEV);
3455
3456 ring->desc_cur = (ring->desc_cur + 1) % ring->count;
3457 IWH_WRITE(sc, HBUS_TARG_WRPTR, ring->qid << 8 | ring->desc_cur);
3458
3459 mutex_exit(&sc->sc_tx_lock);
3460 freemsg(m);
3461
3462 /*
3463 * release node reference
3464 */
3465 ieee80211_free_node(in);
3466
3467 ic->ic_stats.is_tx_bytes += len;
3468 ic->ic_stats.is_tx_frags++;
3469
3470 mutex_enter(&sc->sc_mt_lock);
3471 if (0 == sc->sc_tx_timer) {
3472 sc->sc_tx_timer = 4;
3473 }
3474 mutex_exit(&sc->sc_mt_lock);
3475
3476 exit:
3477 return (err);
3478 }
3479
3480 /*
3481 * invoked by GLD to deal with IOCTL affaires
3482 */
3483 static void
3484 iwh_m_ioctl(void* arg, queue_t *wq, mblk_t *mp)
3485 {
3486 iwh_sc_t *sc;
3487 ieee80211com_t *ic;
3488 int err = EINVAL;
3489
3490 if (NULL == arg) {
3491 return;
3492 }
3493 sc = (iwh_sc_t *)arg;
3494 ic = &sc->sc_ic;
3495
3496 err = ieee80211_ioctl(ic, wq, mp);
3497 if (ENETRESET == err) {
3498 /*
3499 * This is special for the hidden AP connection.
3500 * In any case, we should make sure only one 'scan'
3501 * in the driver for a 'connect' CLI command. So
3502 * when connecting to a hidden AP, the scan is just
3503 * sent out to the air when we know the desired
3504 * essid of the AP we want to connect.
3505 */
3506 if (ic->ic_des_esslen) {
3507 if (sc->sc_flags & IWH_F_RUNNING) {
3508 iwh_m_stop(sc);
3509 (void) iwh_m_start(sc);
3510 (void) ieee80211_new_state(ic,
3511 IEEE80211_S_SCAN, -1);
3512 }
3513 }
3514 }
3515 }
3516
3517 /*
3518 * Call back functions for get/set proporty
3519 */
3520 static int
3521 iwh_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
3522 uint_t wldp_length, void *wldp_buf)
3523 {
3524 iwh_sc_t *sc;
3525 int err = EINVAL;
3526
3527 if (NULL == arg) {
3528 return (EINVAL);
3529 }
3530 sc = (iwh_sc_t *)arg;
3531
3532 err = ieee80211_getprop(&sc->sc_ic, pr_name, wldp_pr_num,
3533 wldp_length, wldp_buf);
3534
3535 return (err);
3536 }
3537
3538 static void
3539 iwh_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
3540 mac_prop_info_handle_t mph)
3541 {
3542 iwh_sc_t *sc = (iwh_sc_t *)arg;
3543
3544 ieee80211_propinfo(&sc->sc_ic, pr_name, wldp_pr_num, mph);
3545 }
3546
3547 static int
3548 iwh_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
3549 uint_t wldp_length, const void *wldp_buf)
3550 {
3551 iwh_sc_t *sc;
3552 ieee80211com_t *ic;
3553 int err = EINVAL;
3554
3555 if (NULL == arg) {
3556 return (EINVAL);
3557 }
3558 sc = (iwh_sc_t *)arg;
3559 ic = &sc->sc_ic;
3560
3561 err = ieee80211_setprop(ic, pr_name, wldp_pr_num, wldp_length,
3562 wldp_buf);
3563
3564 if (err == ENETRESET) {
3565 if (ic->ic_des_esslen) {
3566 if (sc->sc_flags & IWH_F_RUNNING) {
3567 iwh_m_stop(sc);
3568 (void) iwh_m_start(sc);
3569 (void) ieee80211_new_state(ic,
3570 IEEE80211_S_SCAN, -1);
3571 }
3572 }
3573 err = 0;
3574 }
3575 return (err);
3576 }
3577
3578 /*
3579 * invoked by GLD supply statistics NIC and driver
3580 */
3581 static int
3582 iwh_m_stat(void *arg, uint_t stat, uint64_t *val)
3583 {
3584 iwh_sc_t *sc;
3585 ieee80211com_t *ic;
3586 ieee80211_node_t *in;
3587
3588 if (NULL == arg) {
3589 return (EINVAL);
3590 }
3591 sc = (iwh_sc_t *)arg;
3592 ic = &sc->sc_ic;
3593
3594 mutex_enter(&sc->sc_glock);
3595
3596 switch (stat) {
3597 case MAC_STAT_IFSPEED:
3598 in = ic->ic_bss;
3599 *val = ((IEEE80211_FIXED_RATE_NONE == ic->ic_fixed_rate) ?
3600 IEEE80211_RATE(in->in_txrate) :
3601 ic->ic_fixed_rate) / 2 * 1000000;
3602 break;
3603
3604 case MAC_STAT_NOXMTBUF:
3605 *val = sc->sc_tx_nobuf;
3606 break;
3607
3608 case MAC_STAT_NORCVBUF:
3609 *val = sc->sc_rx_nobuf;
3610 break;
3611
3612 case MAC_STAT_IERRORS:
3613 *val = sc->sc_rx_err;
3614 break;
3615
3616 case MAC_STAT_RBYTES:
3617 *val = ic->ic_stats.is_rx_bytes;
3618 break;
3619
3620 case MAC_STAT_IPACKETS:
3621 *val = ic->ic_stats.is_rx_frags;
3622 break;
3623
3624 case MAC_STAT_OBYTES:
3625 *val = ic->ic_stats.is_tx_bytes;
3626 break;
3627
3628 case MAC_STAT_OPACKETS:
3629 *val = ic->ic_stats.is_tx_frags;
3630 break;
3631
3632 case MAC_STAT_OERRORS:
3633 case WIFI_STAT_TX_FAILED:
3634 *val = sc->sc_tx_err;
3635 break;
3636
3637 case WIFI_STAT_TX_RETRANS:
3638 *val = sc->sc_tx_retries;
3639 break;
3640
3641 case WIFI_STAT_FCS_ERRORS:
3642 case WIFI_STAT_WEP_ERRORS:
3643 case WIFI_STAT_TX_FRAGS:
3644 case WIFI_STAT_MCAST_TX:
3645 case WIFI_STAT_RTS_SUCCESS:
3646 case WIFI_STAT_RTS_FAILURE:
3647 case WIFI_STAT_ACK_FAILURE:
3648 case WIFI_STAT_RX_FRAGS:
3649 case WIFI_STAT_MCAST_RX:
3650 case WIFI_STAT_RX_DUPS:
3651 mutex_exit(&sc->sc_glock);
3652 return (ieee80211_stat(ic, stat, val));
3653
3654 default:
3655 mutex_exit(&sc->sc_glock);
3656 return (ENOTSUP);
3657 }
3658
3659 mutex_exit(&sc->sc_glock);
3660
3661 return (IWH_SUCCESS);
3662 }
3663
3664 /*
3665 * invoked by GLD to start or open NIC
3666 */
3667 static int
3668 iwh_m_start(void *arg)
3669 {
3670 iwh_sc_t *sc;
3671 ieee80211com_t *ic;
3672 int err = IWH_FAIL;
3673
3674 if (NULL == arg) {
3675 return (EINVAL);
3676 }
3677 sc = (iwh_sc_t *)arg;
3678 ic = &sc->sc_ic;
3679
3680 err = iwh_init(sc);
3681 if (err != IWH_SUCCESS) {
3682 /*
3683 * The hw init err(eg. RF is OFF). Return Success to make
3684 * the 'plumb' succeed. The iwh_thread() tries to re-init
3685 * background.
3686 */
3687 atomic_or_32(&sc->sc_flags, IWH_F_HW_ERR_RECOVER);
3688 return (IWH_SUCCESS);
3689 }
3690
3691 ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
3692
3693 atomic_or_32(&sc->sc_flags, IWH_F_RUNNING);
3694
3695 return (IWH_SUCCESS);
3696 }
3697
3698 /*
3699 * invoked by GLD to stop or down NIC
3700 */
3701 static void
3702 iwh_m_stop(void *arg)
3703 {
3704 iwh_sc_t *sc;
3705 ieee80211com_t *ic;
3706
3707 if (NULL == arg) {
3708 return;
3709 }
3710 sc = (iwh_sc_t *)arg;
3711 ic = &sc->sc_ic;
3712
3713 iwh_stop(sc);
3714
3715 /*
3716 * release buffer for calibration
3717 */
3718 iwh_release_calib_buffer(sc);
3719
3720 ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
3721
3722 atomic_and_32(&sc->sc_flags, ~IWH_F_HW_ERR_RECOVER);
3723 atomic_and_32(&sc->sc_flags, ~IWH_F_RATE_AUTO_CTL);
3724
3725 atomic_and_32(&sc->sc_flags, ~IWH_F_RUNNING);
3726 atomic_and_32(&sc->sc_flags, ~IWH_F_SCANNING);
3727 }
3728
3729 /*
3730 * invoked by GLD to configure NIC
3731 */
3732 static int
3733 iwh_m_unicst(void *arg, const uint8_t *macaddr)
3734 {
3735 iwh_sc_t *sc;
3736 ieee80211com_t *ic;
3737 int err = IWH_SUCCESS;
3738
3739 if (NULL == arg) {
3740 return (EINVAL);
3741 }
3742 sc = (iwh_sc_t *)arg;
3743 ic = &sc->sc_ic;
3744
3745 if (!IEEE80211_ADDR_EQ(ic->ic_macaddr, macaddr)) {
3746 IEEE80211_ADDR_COPY(ic->ic_macaddr, macaddr);
3747 mutex_enter(&sc->sc_glock);
3748 err = iwh_config(sc);
3749 mutex_exit(&sc->sc_glock);
3750 if (err != IWH_SUCCESS) {
3751 cmn_err(CE_WARN, "iwh_m_unicst(): "
3752 "failed to configure device\n");
3753 goto fail;
3754 }
3755 }
3756
3757 fail:
3758 return (err);
3759 }
3760
3761 /* ARGSUSED */
3762 static int
3763 iwh_m_multicst(void *arg, boolean_t add, const uint8_t *m)
3764 {
3765 return (IWH_SUCCESS);
3766 }
3767
3768 /* ARGSUSED */
3769 static int
3770 iwh_m_promisc(void *arg, boolean_t on)
3771 {
3772 return (IWH_SUCCESS);
3773 }
3774
3775 /*
3776 * kernel thread to deal with exceptional situation
3777 */
3778 static void
3779 iwh_thread(iwh_sc_t *sc)
3780 {
3781 ieee80211com_t *ic = &sc->sc_ic;
3782 clock_t clk;
3783 int err, n = 0, timeout = 0;
3784 uint32_t tmp;
3785 #ifdef DEBUG
3786 int times = 0;
3787 #endif
3788
3789 while (sc->sc_mf_thread_switch) {
3790 tmp = IWH_READ(sc, CSR_GP_CNTRL);
3791 if (tmp & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) {
3792 atomic_and_32(&sc->sc_flags, ~IWH_F_RADIO_OFF);
3793 } else {
3794 atomic_or_32(&sc->sc_flags, IWH_F_RADIO_OFF);
3795 }
3796
3797 /*
3798 * If in SUSPEND or the RF is OFF, do nothing.
3799 */
3800 if (sc->sc_flags & IWH_F_RADIO_OFF) {
3801 delay(drv_usectohz(100000));
3802 continue;
3803 }
3804
3805 /*
3806 * recovery fatal error
3807 */
3808 if (ic->ic_mach &&
3809 (sc->sc_flags & IWH_F_HW_ERR_RECOVER)) {
3810
3811 IWH_DBG((IWH_DEBUG_FW, "iwh_thread(): "
3812 "try to recover fatal hw error: %d\n", times++));
3813
3814 iwh_stop(sc);
3815
3816 if (IWH_CHK_FAST_RECOVER(sc)) {
3817 /*
3818 * save runtime configuration
3819 */
3820 bcopy(&sc->sc_config, &sc->sc_config_save,
3821 sizeof (sc->sc_config));
3822 } else {
3823 ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
3824 delay(drv_usectohz(2000000 + n*500000));
3825 }
3826
3827 err = iwh_init(sc);
3828 if (err != IWH_SUCCESS) {
3829 n++;
3830 if (n < 20) {
3831 continue;
3832 }
3833 }
3834
3835 n = 0;
3836 if (!err) {
3837 atomic_or_32(&sc->sc_flags, IWH_F_RUNNING);
3838 }
3839
3840
3841 if (!IWH_CHK_FAST_RECOVER(sc) ||
3842 iwh_fast_recover(sc) != IWH_SUCCESS) {
3843 atomic_and_32(&sc->sc_flags,
3844 ~IWH_F_HW_ERR_RECOVER);
3845
3846 delay(drv_usectohz(2000000));
3847 if (sc->sc_ostate != IEEE80211_S_INIT) {
3848 ieee80211_new_state(ic,
3849 IEEE80211_S_SCAN, 0);
3850 }
3851 }
3852 }
3853
3854 if (ic->ic_mach &&
3855 (sc->sc_flags & IWH_F_SCANNING) && sc->sc_scan_pending) {
3856 IWH_DBG((IWH_DEBUG_SCAN, "iwh_thread(): "
3857 "wait for probe response\n"));
3858
3859 sc->sc_scan_pending--;
3860 delay(drv_usectohz(200000));
3861 ieee80211_next_scan(ic);
3862 }
3863
3864 /*
3865 * rate ctl
3866 */
3867 if (ic->ic_mach &&
3868 (sc->sc_flags & IWH_F_RATE_AUTO_CTL)) {
3869 clk = ddi_get_lbolt();
3870 if (clk > sc->sc_clk + drv_usectohz(1000000)) {
3871 iwh_amrr_timeout(sc);
3872 }
3873 }
3874
3875 if ((ic->ic_state == IEEE80211_S_RUN) &&
3876 (ic->ic_beaconmiss++ > 100)) { /* 10 seconds */
3877 cmn_err(CE_WARN, "iwh: beacon missed for 10 seconds\n");
3878 (void) ieee80211_new_state(ic,
3879 IEEE80211_S_INIT, -1);
3880 }
3881
3882 delay(drv_usectohz(100000));
3883
3884 mutex_enter(&sc->sc_mt_lock);
3885 if (sc->sc_tx_timer) {
3886 timeout++;
3887 if (10 == timeout) {
3888 sc->sc_tx_timer--;
3889 if (0 == sc->sc_tx_timer) {
3890 atomic_or_32(&sc->sc_flags,
3891 IWH_F_HW_ERR_RECOVER);
3892 sc->sc_ostate = IEEE80211_S_RUN;
3893 IWH_DBG((IWH_DEBUG_FW, "iwh_thread(): "
3894 "try to recover from "
3895 "send fail\n"));
3896 }
3897 timeout = 0;
3898 }
3899 }
3900 mutex_exit(&sc->sc_mt_lock);
3901 }
3902
3903 mutex_enter(&sc->sc_mt_lock);
3904 sc->sc_mf_thread = NULL;
3905 cv_signal(&sc->sc_mt_cv);
3906 mutex_exit(&sc->sc_mt_lock);
3907 }
3908
3909 /*
3910 * Send a command to the ucode.
3911 */
3912 static int
3913 iwh_cmd(iwh_sc_t *sc, int code, const void *buf, int size, int async)
3914 {
3915 iwh_tx_ring_t *ring = &sc->sc_txq[IWH_CMD_QUEUE_NUM];
3916 iwh_tx_desc_t *desc;
3917 iwh_cmd_t *cmd;
3918
3919 ASSERT(size <= sizeof (cmd->data));
3920 ASSERT(mutex_owned(&sc->sc_glock));
3921
3922 IWH_DBG((IWH_DEBUG_CMD, "iwh_cmd() "
3923 "code[%d]", code));
3924 desc = ring->data[ring->cur].desc;
3925 cmd = ring->data[ring->cur].cmd;
3926
3927 cmd->hdr.type = (uint8_t)code;
3928 cmd->hdr.flags = 0;
3929 cmd->hdr.qid = ring->qid;
3930 cmd->hdr.idx = ring->cur;
3931 bcopy(buf, cmd->data, size);
3932 (void) memset(desc, 0, sizeof (*desc));
3933
3934 desc->val0 = 1 << 24;
3935 desc->pa[0].tb1_addr =
3936 (uint32_t)(ring->data[ring->cur].paddr_cmd & 0xffffffff);
3937 desc->pa[0].val1 = ((4 + size) << 4) & 0xfff0;
3938
3939 if (async) {
3940 sc->sc_cmd_accum++;
3941 }
3942
3943 /*
3944 * kick cmd ring XXX
3945 */
3946 sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
3947 tfd_offset[ring->cur].val = 8;
3948 if (ring->cur < IWH_MAX_WIN_SIZE) {
3949 sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
3950 tfd_offset[IWH_QUEUE_SIZE + ring->cur].val = 8;
3951 }
3952 ring->cur = (ring->cur + 1) % ring->count;
3953 IWH_WRITE(sc, HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur);
3954
3955 if (async) {
3956 return (IWH_SUCCESS);
3957 } else {
3958 clock_t clk;
3959
3960 clk = ddi_get_lbolt() + drv_usectohz(2000000);
3961 while (sc->sc_cmd_flag != SC_CMD_FLG_DONE) {
3962 if (cv_timedwait(&sc->sc_cmd_cv,
3963 &sc->sc_glock, clk) < 0) {
3964 break;
3965 }
3966 }
3967
3968 if (SC_CMD_FLG_DONE == sc->sc_cmd_flag) {
3969 sc->sc_cmd_flag = SC_CMD_FLG_NONE;
3970 return (IWH_SUCCESS);
3971 } else {
3972 sc->sc_cmd_flag = SC_CMD_FLG_NONE;
3973 return (IWH_FAIL);
3974 }
3975 }
3976 }
3977
3978 /*
3979 * require ucode seting led of NIC
3980 */
3981 static void
3982 iwh_set_led(iwh_sc_t *sc, uint8_t id, uint8_t off, uint8_t on)
3983 {
3984 iwh_led_cmd_t led;
3985
3986 led.interval = LE_32(100000); /* unit: 100ms */
3987 led.id = id;
3988 led.off = off;
3989 led.on = on;
3990
3991 (void) iwh_cmd(sc, REPLY_LEDS_CMD, &led, sizeof (led), 1);
3992 }
3993
3994 /*
3995 * necessary setting to NIC before authentication
3996 */
3997 static int
3998 iwh_hw_set_before_auth(iwh_sc_t *sc)
3999 {
4000 ieee80211com_t *ic = &sc->sc_ic;
4001 ieee80211_node_t *in = ic->ic_bss;
4002 int err = IWH_FAIL;
4003
4004 /*
4005 * update adapter's configuration according
4006 * the info of target AP
4007 */
4008 IEEE80211_ADDR_COPY(sc->sc_config.bssid, in->in_bssid);
4009 sc->sc_config.chan = LE_16(ieee80211_chan2ieee(ic, in->in_chan));
4010
4011 if (ic->ic_curmode != IEEE80211_MODE_11NG) {
4012
4013 sc->sc_config.ofdm_ht_triple_stream_basic_rates = 0;
4014 sc->sc_config.ofdm_ht_dual_stream_basic_rates = 0;
4015 sc->sc_config.ofdm_ht_single_stream_basic_rates = 0;
4016
4017 if (IEEE80211_MODE_11B == ic->ic_curmode) {
4018 sc->sc_config.cck_basic_rates = 0x03;
4019 sc->sc_config.ofdm_basic_rates = 0;
4020 } else if ((in->in_chan != IEEE80211_CHAN_ANYC) &&
4021 (IEEE80211_IS_CHAN_5GHZ(in->in_chan))) {
4022 sc->sc_config.cck_basic_rates = 0;
4023 sc->sc_config.ofdm_basic_rates = 0x15;
4024 } else { /* assume 802.11b/g */
4025 sc->sc_config.cck_basic_rates = 0x0f;
4026 sc->sc_config.ofdm_basic_rates = 0xff;
4027 }
4028 }
4029
4030 sc->sc_config.flags &= ~LE_32(RXON_FLG_SHORT_PREAMBLE_MSK |
4031 RXON_FLG_SHORT_SLOT_MSK);
4032
4033 if (ic->ic_flags & IEEE80211_F_SHSLOT) {
4034 sc->sc_config.flags |= LE_32(RXON_FLG_SHORT_SLOT_MSK);
4035 } else {
4036 sc->sc_config.flags &= LE_32(~RXON_FLG_SHORT_SLOT_MSK);
4037 }
4038
4039 if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) {
4040 sc->sc_config.flags |= LE_32(RXON_FLG_SHORT_PREAMBLE_MSK);
4041 } else {
4042 sc->sc_config.flags &= LE_32(~RXON_FLG_SHORT_PREAMBLE_MSK);
4043 }
4044
4045 IWH_DBG((IWH_DEBUG_80211, "iwh_hw_set_before_auth(): "
4046 "config chan %d flags %x "
4047 "filter_flags %x cck %x ofdm %x"
4048 " bssid:%02x:%02x:%02x:%02x:%02x:%2x\n",
4049 LE_16(sc->sc_config.chan), LE_32(sc->sc_config.flags),
4050 LE_32(sc->sc_config.filter_flags),
4051 sc->sc_config.cck_basic_rates, sc->sc_config.ofdm_basic_rates,
4052 sc->sc_config.bssid[0], sc->sc_config.bssid[1],
4053 sc->sc_config.bssid[2], sc->sc_config.bssid[3],
4054 sc->sc_config.bssid[4], sc->sc_config.bssid[5]));
4055
4056 err = iwh_cmd(sc, REPLY_RXON, &sc->sc_config,
4057 sizeof (iwh_rxon_cmd_t), 1);
4058 if (err != IWH_SUCCESS) {
4059 cmn_err(CE_WARN, "iwh_hw_set_before_auth(): "
4060 "failed to config chan%d\n", sc->sc_config.chan);
4061 return (err);
4062 }
4063
4064 if ((sc->sc_dev_id != 0x423c) &&
4065 (sc->sc_dev_id != 0x423d)) {
4066 err = iwh_tx_power_table(sc, 1);
4067 if (err != IWH_SUCCESS) {
4068 return (err);
4069 }
4070 }
4071
4072 /*
4073 * add default AP node
4074 */
4075 err = iwh_add_ap_sta(sc);
4076 if (err != IWH_SUCCESS) {
4077 return (err);
4078 }
4079
4080 if ((sc->sc_dev_id != 0x423c) &&
4081 (sc->sc_dev_id != 0x423d)) {
4082 /*
4083 * set up retry rate table for AP node
4084 */
4085 err = iwh_ap_lq(sc);
4086 if (err != IWH_SUCCESS) {
4087 return (err);
4088 }
4089 }
4090
4091 return (err);
4092 }
4093
4094 /*
4095 * Send a scan request(assembly scan cmd) to the firmware.
4096 */
4097 static int
4098 iwh_scan(iwh_sc_t *sc)
4099 {
4100 ieee80211com_t *ic = &sc->sc_ic;
4101 iwh_tx_ring_t *ring = &sc->sc_txq[IWH_CMD_QUEUE_NUM];
4102 iwh_tx_desc_t *desc;
4103 iwh_tx_data_t *data;
4104 iwh_cmd_t *cmd;
4105 iwh_scan_hdr_t *hdr;
4106 iwh_scan_chan_t chan;
4107 struct ieee80211_frame *wh;
4108 ieee80211_node_t *in = ic->ic_bss;
4109 uint8_t essid[IEEE80211_NWID_LEN+1];
4110 struct ieee80211_rateset *rs;
4111 enum ieee80211_phymode mode;
4112 uint8_t *frm;
4113 int i, pktlen, nrates;
4114
4115 data = &ring->data[ring->cur];
4116 desc = data->desc;
4117 cmd = (iwh_cmd_t *)data->dma_data.mem_va;
4118
4119 cmd->hdr.type = REPLY_SCAN_CMD;
4120 cmd->hdr.flags = 0;
4121 cmd->hdr.qid = ring->qid;
4122 cmd->hdr.idx = ring->cur | 0x40;
4123
4124 hdr = (iwh_scan_hdr_t *)cmd->data;
4125 (void) memset(hdr, 0, sizeof (iwh_scan_hdr_t));
4126 hdr->nchan = 1;
4127 hdr->quiet_time = LE_16(50);
4128 hdr->quiet_plcp_th = LE_16(1);
4129
4130 hdr->flags = LE_32(RXON_FLG_BAND_24G_MSK);
4131 hdr->rx_chain = LE_16(RXON_RX_CHAIN_DRIVER_FORCE_MSK |
4132 (0x7 << RXON_RX_CHAIN_VALID_POS) |
4133 (0x2 << RXON_RX_CHAIN_FORCE_SEL_POS) |
4134 (0x2 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS));
4135
4136 hdr->tx_cmd.tx_flags = LE_32(TX_CMD_FLG_SEQ_CTL_MSK);
4137 hdr->tx_cmd.sta_id = IWH_BROADCAST_ID;
4138 hdr->tx_cmd.stop_time.life_time = LE_32(0xffffffff);
4139 hdr->tx_cmd.rate.r.rate_n_flags = LE_32(iwh_rate_to_plcp(2));
4140 hdr->tx_cmd.rate.r.rate_n_flags |=
4141 LE_32(RATE_MCS_ANT_B_MSK |RATE_MCS_CCK_MSK);
4142 hdr->direct_scan[0].len = ic->ic_des_esslen;
4143 hdr->direct_scan[0].id = IEEE80211_ELEMID_SSID;
4144
4145 hdr->filter_flags = LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
4146 RXON_FILTER_BCON_AWARE_MSK);
4147
4148 if (ic->ic_des_esslen) {
4149 bcopy(ic->ic_des_essid, essid, ic->ic_des_esslen);
4150 essid[ic->ic_des_esslen] = '\0';
4151 IWH_DBG((IWH_DEBUG_SCAN, "iwh_scan(): "
4152 "directed scan %s\n", essid));
4153
4154 bcopy(ic->ic_des_essid, hdr->direct_scan[0].ssid,
4155 ic->ic_des_esslen);
4156 } else {
4157 bzero(hdr->direct_scan[0].ssid,
4158 sizeof (hdr->direct_scan[0].ssid));
4159 }
4160
4161 /*
4162 * a probe request frame is required after the REPLY_SCAN_CMD
4163 */
4164 wh = (struct ieee80211_frame *)(hdr + 1);
4165 wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
4166 IEEE80211_FC0_SUBTYPE_PROBE_REQ;
4167 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
4168 (void) memset(wh->i_addr1, 0xff, 6);
4169 IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_macaddr);
4170 (void) memset(wh->i_addr3, 0xff, 6);
4171 *(uint16_t *)&wh->i_dur[0] = 0;
4172 *(uint16_t *)&wh->i_seq[0] = 0;
4173
4174 frm = (uint8_t *)(wh + 1);
4175
4176 /*
4177 * essid IE
4178 */
4179 if (in->in_esslen) {
4180 bcopy(in->in_essid, essid, in->in_esslen);
4181 essid[in->in_esslen] = '\0';
4182 IWH_DBG((IWH_DEBUG_SCAN, "iwh_scan(): "
4183 "probe with ESSID %s\n",
4184 essid));
4185 }
4186 *frm++ = IEEE80211_ELEMID_SSID;
4187 *frm++ = in->in_esslen;
4188 bcopy(in->in_essid, frm, in->in_esslen);
4189 frm += in->in_esslen;
4190
4191 mode = ieee80211_chan2mode(ic, ic->ic_curchan);
4192 rs = &ic->ic_sup_rates[mode];
4193
4194 /*
4195 * supported rates IE
4196 */
4197 *frm++ = IEEE80211_ELEMID_RATES;
4198 nrates = rs->ir_nrates;
4199 if (nrates > IEEE80211_RATE_SIZE) {
4200 nrates = IEEE80211_RATE_SIZE;
4201 }
4202
4203 *frm++ = (uint8_t)nrates;
4204 bcopy(rs->ir_rates, frm, nrates);
4205 frm += nrates;
4206
4207 /*
4208 * supported xrates IE
4209 */
4210 if (rs->ir_nrates > IEEE80211_RATE_SIZE) {
4211 nrates = rs->ir_nrates - IEEE80211_RATE_SIZE;
4212 *frm++ = IEEE80211_ELEMID_XRATES;
4213 *frm++ = (uint8_t)nrates;
4214 bcopy(rs->ir_rates + IEEE80211_RATE_SIZE, frm, nrates);
4215 frm += nrates;
4216 }
4217
4218 /*
4219 * optionnal IE (usually for wpa)
4220 */
4221 if (ic->ic_opt_ie != NULL) {
4222 bcopy(ic->ic_opt_ie, frm, ic->ic_opt_ie_len);
4223 frm += ic->ic_opt_ie_len;
4224 }
4225
4226 /* setup length of probe request */
4227 hdr->tx_cmd.len = LE_16(_PTRDIFF(frm, wh));
4228 hdr->len = LE_16(hdr->nchan * sizeof (iwh_scan_chan_t) +
4229 LE_16(hdr->tx_cmd.len) + sizeof (iwh_scan_hdr_t));
4230
4231 /*
4232 * the attribute of the scan channels are required after the probe
4233 * request frame.
4234 */
4235 for (i = 1; i <= hdr->nchan; i++) {
4236 if (ic->ic_des_esslen) {
4237 chan.type = LE_32(3);
4238 } else {
4239 chan.type = LE_32(1);
4240 }
4241
4242 chan.chan = LE_16(ieee80211_chan2ieee(ic, ic->ic_curchan));
4243 chan.tpc.tx_gain = 0x28;
4244 chan.tpc.dsp_atten = 110;
4245 chan.active_dwell = LE_16(50);
4246 chan.passive_dwell = LE_16(120);
4247
4248 bcopy(&chan, frm, sizeof (iwh_scan_chan_t));
4249 frm += sizeof (iwh_scan_chan_t);
4250 }
4251
4252 pktlen = _PTRDIFF(frm, cmd);
4253
4254 (void) memset(desc, 0, sizeof (*desc));
4255 desc->val0 = 1 << 24;
4256 desc->pa[0].tb1_addr =
4257 (uint32_t)(data->dma_data.cookie.dmac_address & 0xffffffff);
4258 desc->pa[0].val1 = (pktlen << 4) & 0xfff0;
4259
4260 /*
4261 * maybe for cmd, filling the byte cnt table is not necessary.
4262 * anyway, we fill it here.
4263 */
4264 sc->sc_shared->queues_byte_cnt_tbls[ring->qid]
4265 .tfd_offset[ring->cur].val = 8;
4266 if (ring->cur < IWH_MAX_WIN_SIZE) {
4267 sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
4268 tfd_offset[IWH_QUEUE_SIZE + ring->cur].val = 8;
4269 }
4270
4271 /*
4272 * kick cmd ring
4273 */
4274 ring->cur = (ring->cur + 1) % ring->count;
4275 IWH_WRITE(sc, HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur);
4276
4277 return (IWH_SUCCESS);
4278 }
4279
4280 /*
4281 * configure NIC by using ucode commands after loading ucode.
4282 */
4283 static int
4284 iwh_config(iwh_sc_t *sc)
4285 {
4286 ieee80211com_t *ic = &sc->sc_ic;
4287 iwh_powertable_cmd_t powertable;
4288 iwh_bt_cmd_t bt;
4289 iwh_add_sta_t node;
4290 iwh_rem_sta_t rm_sta;
4291 const uint8_t bcast[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
4292 iwh_link_quality_cmd_t link_quality;
4293 int i, err = IWH_FAIL;
4294 uint16_t masks = 0;
4295
4296 /*
4297 * set power mode. Disable power management at present, do it later
4298 */
4299 (void) memset(&powertable, 0, sizeof (powertable));
4300 powertable.flags = LE_16(0x8);
4301 err = iwh_cmd(sc, POWER_TABLE_CMD, &powertable,
4302 sizeof (powertable), 0);
4303 if (err != IWH_SUCCESS) {
4304 cmn_err(CE_WARN, "iwh_config(): "
4305 "failed to set power mode\n");
4306 return (err);
4307 }
4308
4309 /*
4310 * configure bt coexistence
4311 */
4312 (void) memset(&bt, 0, sizeof (bt));
4313 bt.flags = 3;
4314 bt.lead_time = 0xaa;
4315 bt.max_kill = 1;
4316 err = iwh_cmd(sc, REPLY_BT_CONFIG, &bt,
4317 sizeof (bt), 0);
4318 if (err != IWH_SUCCESS) {
4319 cmn_err(CE_WARN, "iwh_config(): "
4320 "failed to configurate bt coexistence\n");
4321 return (err);
4322 }
4323
4324 /*
4325 * configure rxon
4326 */
4327 (void) memset(&sc->sc_config, 0, sizeof (iwh_rxon_cmd_t));
4328 IEEE80211_ADDR_COPY(sc->sc_config.node_addr, ic->ic_macaddr);
4329 IEEE80211_ADDR_COPY(sc->sc_config.wlap_bssid, ic->ic_macaddr);
4330 sc->sc_config.chan = LE_16(ieee80211_chan2ieee(ic, ic->ic_curchan));
4331 sc->sc_config.flags = LE_32(RXON_FLG_BAND_24G_MSK);
4332 sc->sc_config.flags &= LE_32(~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
4333 RXON_FLG_CHANNEL_MODE_PURE_40_MSK));
4334
4335 switch (ic->ic_opmode) {
4336 case IEEE80211_M_STA:
4337 sc->sc_config.dev_type = RXON_DEV_TYPE_ESS;
4338 sc->sc_config.filter_flags |= LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
4339 RXON_FILTER_DIS_DECRYPT_MSK |
4340 RXON_FILTER_DIS_GRP_DECRYPT_MSK);
4341 break;
4342
4343 case IEEE80211_M_IBSS:
4344 case IEEE80211_M_AHDEMO:
4345 sc->sc_config.dev_type = RXON_DEV_TYPE_IBSS;
4346
4347 sc->sc_config.flags |= LE_32(RXON_FLG_SHORT_PREAMBLE_MSK);
4348 sc->sc_config.filter_flags = LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
4349 RXON_FILTER_DIS_DECRYPT_MSK |
4350 RXON_FILTER_DIS_GRP_DECRYPT_MSK);
4351 break;
4352
4353 case IEEE80211_M_HOSTAP:
4354 sc->sc_config.dev_type = RXON_DEV_TYPE_AP;
4355 break;
4356
4357 case IEEE80211_M_MONITOR:
4358 sc->sc_config.dev_type = RXON_DEV_TYPE_SNIFFER;
4359 sc->sc_config.filter_flags |= LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
4360 RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK);
4361 break;
4362 }
4363
4364 /*
4365 * Support all CCK rates.
4366 */
4367 sc->sc_config.cck_basic_rates = 0x0f;
4368
4369 /*
4370 * Support all OFDM rates.
4371 */
4372 sc->sc_config.ofdm_basic_rates = 0xff;
4373
4374 /*
4375 * Determine HT supported rates.
4376 */
4377 switch (sc->sc_ht_conf.rx_stream_count) {
4378 case 3:
4379 sc->sc_config.ofdm_ht_triple_stream_basic_rates = 0xff;
4380 sc->sc_config.ofdm_ht_dual_stream_basic_rates = 0xff;
4381 sc->sc_config.ofdm_ht_single_stream_basic_rates = 0xff;
4382 break;
4383 case 2:
4384 sc->sc_config.ofdm_ht_dual_stream_basic_rates = 0xff;
4385 sc->sc_config.ofdm_ht_single_stream_basic_rates = 0xff;
4386 break;
4387 case 1:
4388 sc->sc_config.ofdm_ht_single_stream_basic_rates = 0xff;
4389 break;
4390 default:
4391 cmn_err(CE_WARN, "iwh_config(): "
4392 "RX stream count %d is not in suitable range\n",
4393 sc->sc_ht_conf.rx_stream_count);
4394 return (IWH_FAIL);
4395 }
4396
4397 /*
4398 * set RX chains/antennas.
4399 */
4400 iwh_config_rxon_chain(sc);
4401
4402 err = iwh_cmd(sc, REPLY_RXON, &sc->sc_config,
4403 sizeof (iwh_rxon_cmd_t), 0);
4404 if (err != IWH_SUCCESS) {
4405 cmn_err(CE_WARN, "iwh_config(): "
4406 "failed to set configure command\n");
4407 return (err);
4408 }
4409
4410 /*
4411 * remove all nodes in NIC
4412 */
4413 (void) memset(&rm_sta, 0, sizeof (rm_sta));
4414 rm_sta.num_sta = 1;
4415 bcopy(bcast, rm_sta.addr, 6);
4416
4417 err = iwh_cmd(sc, REPLY_REMOVE_STA, &rm_sta, sizeof (iwh_rem_sta_t), 0);
4418 if (err != IWH_SUCCESS) {
4419 cmn_err(CE_WARN, "iwh_config(): "
4420 "failed to remove broadcast node in hardware.\n");
4421 return (err);
4422 }
4423
4424 if ((sc->sc_dev_id != 0x423c) &&
4425 (sc->sc_dev_id != 0x423d)) {
4426 /*
4427 * configure TX power table
4428 */
4429 err = iwh_tx_power_table(sc, 0);
4430 if (err != IWH_SUCCESS) {
4431 return (err);
4432 }
4433 }
4434
4435 /*
4436 * add broadcast node so that we can send broadcast frame
4437 */
4438 (void) memset(&node, 0, sizeof (node));
4439 (void) memset(node.sta.addr, 0xff, 6);
4440 node.mode = 0;
4441 node.sta.sta_id = IWH_BROADCAST_ID;
4442 node.station_flags = 0;
4443
4444 err = iwh_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 0);
4445 if (err != IWH_SUCCESS) {
4446 cmn_err(CE_WARN, "iwh_config(): "
4447 "failed to add broadcast node\n");
4448 return (err);
4449 }
4450
4451 if ((sc->sc_dev_id != 0x423c) &&
4452 (sc->sc_dev_id != 0x423d)) {
4453 /*
4454 * TX_LINK_QUALITY cmd
4455 */
4456 (void) memset(&link_quality, 0, sizeof (link_quality));
4457 for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
4458 masks |= RATE_MCS_CCK_MSK;
4459 masks |= RATE_MCS_ANT_B_MSK;
4460 masks &= ~RATE_MCS_ANT_A_MSK;
4461 link_quality.rate_n_flags[i] =
4462 LE_32(iwh_rate_to_plcp(2) | masks);
4463 }
4464
4465 link_quality.general_params.single_stream_ant_msk = 2;
4466 link_quality.general_params.dual_stream_ant_msk = 3;
4467 link_quality.agg_params.agg_dis_start_th = 3;
4468 link_quality.agg_params.agg_time_limit = LE_16(4000);
4469 link_quality.sta_id = IWH_BROADCAST_ID;
4470 err = iwh_cmd(sc, REPLY_TX_LINK_QUALITY_CMD, &link_quality,
4471 sizeof (link_quality), 0);
4472 if (err != IWH_SUCCESS) {
4473 cmn_err(CE_WARN, "iwh_config(): "
4474 "failed to config link quality table\n");
4475 return (err);
4476 }
4477 }
4478
4479 return (err);
4480 }
4481
4482 /*
4483 * quiesce(9E) entry point.
4484 * This function is called when the system is single-threaded at high
4485 * PIL with preemption disabled. Therefore, this function must not be
4486 * blocked.
4487 * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
4488 * DDI_FAILURE indicates an error condition and should almost never happen.
4489 */
4490 static int
4491 iwh_quiesce(dev_info_t *dip)
4492 {
4493 iwh_sc_t *sc;
4494
4495 sc = ddi_get_soft_state(iwh_soft_state_p, ddi_get_instance(dip));
4496 if (sc == NULL) {
4497 return (DDI_FAILURE);
4498 }
4499
4500 #ifdef DEBUG
4501 /*
4502 * by pass any messages, if it's quiesce
4503 */
4504 iwh_dbg_flags = 0;
4505 #endif
4506
4507 /*
4508 * No more blocking is allowed while we are in the
4509 * quiesce(9E) entry point.
4510 */
4511 atomic_or_32(&sc->sc_flags, IWH_F_QUIESCED);
4512
4513 /*
4514 * Disable and mask all interrupts.
4515 */
4516 iwh_stop(sc);
4517
4518 return (DDI_SUCCESS);
4519 }
4520
4521 static void
4522 iwh_stop_master(iwh_sc_t *sc)
4523 {
4524 uint32_t tmp;
4525 int n;
4526
4527 tmp = IWH_READ(sc, CSR_RESET);
4528 IWH_WRITE(sc, CSR_RESET, tmp | CSR_RESET_REG_FLAG_STOP_MASTER);
4529
4530 tmp = IWH_READ(sc, CSR_GP_CNTRL);
4531 if ((tmp & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE) ==
4532 CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE) {
4533 return;
4534 }
4535
4536 for (n = 0; n < 2000; n++) {
4537 if (IWH_READ(sc, CSR_RESET) &
4538 CSR_RESET_REG_FLAG_MASTER_DISABLED) {
4539 break;
4540 }
4541 DELAY(1000);
4542 }
4543
4544 #ifdef DEBUG
4545 if (2000 == n) {
4546 IWH_DBG((IWH_DEBUG_HW, "iwh_stop_master(): "
4547 "timeout waiting for master stop\n"));
4548 }
4549 #endif
4550 }
4551
4552 static int
4553 iwh_power_up(iwh_sc_t *sc)
4554 {
4555 uint32_t tmp;
4556
4557 iwh_mac_access_enter(sc);
4558 tmp = iwh_reg_read(sc, ALM_APMG_PS_CTL);
4559 tmp &= ~APMG_PS_CTRL_REG_MSK_POWER_SRC;
4560 tmp |= APMG_PS_CTRL_REG_VAL_POWER_SRC_VMAIN;
4561 iwh_reg_write(sc, ALM_APMG_PS_CTL, tmp);
4562 iwh_mac_access_exit(sc);
4563
4564 DELAY(5000);
4565 return (IWH_SUCCESS);
4566 }
4567
4568 /*
4569 * hardware initialization
4570 */
4571 static int
4572 iwh_preinit(iwh_sc_t *sc)
4573 {
4574 int n;
4575 uint8_t vlink;
4576 uint16_t radio_cfg;
4577 uint32_t tmp;
4578
4579 /*
4580 * clear any pending interrupts
4581 */
4582 IWH_WRITE(sc, CSR_INT, 0xffffffff);
4583
4584 tmp = IWH_READ(sc, CSR_GIO_CHICKEN_BITS);
4585 IWH_WRITE(sc, CSR_GIO_CHICKEN_BITS,
4586 tmp | CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
4587
4588 tmp = IWH_READ(sc, CSR_ANA_PLL_CFG);
4589 IWH_WRITE(sc, CSR_ANA_PLL_CFG, tmp | IWH_CSR_ANA_PLL_CFG);
4590
4591 tmp = IWH_READ(sc, CSR_GP_CNTRL);
4592 IWH_WRITE(sc, CSR_GP_CNTRL, tmp | CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
4593
4594 /*
4595 * wait for clock ready
4596 */
4597 for (n = 0; n < 1000; n++) {
4598 if (IWH_READ(sc, CSR_GP_CNTRL) &
4599 CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY) {
4600 break;
4601 }
4602 DELAY(10);
4603 }
4604
4605 if (1000 == n) {
4606 return (ETIMEDOUT);
4607 }
4608
4609 iwh_mac_access_enter(sc);
4610
4611 iwh_reg_write(sc, ALM_APMG_CLK_EN, APMG_CLK_REG_VAL_DMA_CLK_RQT);
4612
4613 DELAY(20);
4614 tmp = iwh_reg_read(sc, ALM_APMG_PCIDEV_STT);
4615 iwh_reg_write(sc, ALM_APMG_PCIDEV_STT, tmp |
4616 APMG_DEV_STATE_REG_VAL_L1_ACTIVE_DISABLE);
4617 iwh_mac_access_exit(sc);
4618
4619 radio_cfg = IWH_READ_EEP_SHORT(sc, EEP_SP_RADIO_CONFIGURATION);
4620 if (SP_RADIO_TYPE_MSK(radio_cfg) < SP_RADIO_TYPE_MAX) {
4621 tmp = IWH_READ(sc, CSR_HW_IF_CONFIG_REG);
4622 IWH_WRITE(sc, CSR_HW_IF_CONFIG_REG,
4623 tmp | SP_RADIO_TYPE_MSK(radio_cfg) |
4624 SP_RADIO_STEP_MSK(radio_cfg) |
4625 SP_RADIO_DASH_MSK(radio_cfg));
4626 } else {
4627 cmn_err(CE_WARN, "iwh_preinit(): "
4628 "radio configuration information in eeprom is wrong\n");
4629 return (IWH_FAIL);
4630 }
4631
4632
4633 IWH_WRITE(sc, CSR_INT_COALESCING, 512 / 32);
4634
4635 (void) iwh_power_up(sc);
4636
4637 if ((sc->sc_rev & 0x80) == 0x80 && (sc->sc_rev & 0x7f) < 8) {
4638 tmp = ddi_get32(sc->sc_cfg_handle,
4639 (uint32_t *)(sc->sc_cfg_base + 0xe8));
4640 ddi_put32(sc->sc_cfg_handle,
4641 (uint32_t *)(sc->sc_cfg_base + 0xe8),
4642 tmp & ~(1 << 11));
4643 }
4644
4645 vlink = ddi_get8(sc->sc_cfg_handle,
4646 (uint8_t *)(sc->sc_cfg_base + 0xf0));
4647 ddi_put8(sc->sc_cfg_handle, (uint8_t *)(sc->sc_cfg_base + 0xf0),
4648 vlink & ~2);
4649
4650 tmp = IWH_READ(sc, CSR_HW_IF_CONFIG_REG);
4651 tmp |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
4652 CSR_HW_IF_CONFIG_REG_BIT_MAC_SI;
4653 IWH_WRITE(sc, CSR_SW_VER, tmp);
4654
4655 /*
4656 * make sure power supply on each part of the hardware
4657 */
4658 iwh_mac_access_enter(sc);
4659 tmp = iwh_reg_read(sc, ALM_APMG_PS_CTL);
4660 tmp |= APMG_PS_CTRL_REG_VAL_ALM_R_RESET_REQ;
4661 iwh_reg_write(sc, ALM_APMG_PS_CTL, tmp);
4662 DELAY(5);
4663
4664 tmp = iwh_reg_read(sc, ALM_APMG_PS_CTL);
4665 tmp &= ~APMG_PS_CTRL_REG_VAL_ALM_R_RESET_REQ;
4666 iwh_reg_write(sc, ALM_APMG_PS_CTL, tmp);
4667 iwh_mac_access_exit(sc);
4668
4669 return (IWH_SUCCESS);
4670 }
4671
4672 /*
4673 * set up semphore flag to own EEPROM
4674 */
4675 static int
4676 iwh_eep_sem_down(iwh_sc_t *sc)
4677 {
4678 int count1, count2;
4679 uint32_t tmp;
4680
4681 for (count1 = 0; count1 < 1000; count1++) {
4682 tmp = IWH_READ(sc, CSR_HW_IF_CONFIG_REG);
4683 IWH_WRITE(sc, CSR_HW_IF_CONFIG_REG,
4684 tmp | CSR_HW_IF_CONFIG_REG_EEP_SEM);
4685
4686 for (count2 = 0; count2 < 2; count2++) {
4687 if (IWH_READ(sc, CSR_HW_IF_CONFIG_REG) &
4688 CSR_HW_IF_CONFIG_REG_EEP_SEM) {
4689 return (IWH_SUCCESS);
4690 }
4691 DELAY(10000);
4692 }
4693 }
4694
4695 return (IWH_FAIL);
4696 }
4697
4698 /*
4699 * reset semphore flag to release EEPROM
4700 */
4701 static void
4702 iwh_eep_sem_up(iwh_sc_t *sc)
4703 {
4704 uint32_t tmp;
4705
4706 tmp = IWH_READ(sc, CSR_HW_IF_CONFIG_REG);
4707 IWH_WRITE(sc, CSR_HW_IF_CONFIG_REG,
4708 tmp & (~CSR_HW_IF_CONFIG_REG_EEP_SEM));
4709 }
4710
4711 /*
4712 * This function read all infomation from eeprom
4713 */
4714 static int
4715 iwh_eep_load(iwh_sc_t *sc)
4716 {
4717 int i, rr;
4718 uint32_t rv, tmp, eep_gp;
4719 uint16_t addr, eep_sz = sizeof (sc->sc_eep_map);
4720 uint16_t *eep_p = (uint16_t *)&sc->sc_eep_map;
4721
4722 /*
4723 * read eeprom gp register in CSR
4724 */
4725 eep_gp = IWH_READ(sc, CSR_EEPROM_GP);
4726 if ((eep_gp & CSR_EEPROM_GP_VALID_MSK) ==
4727 CSR_EEPROM_GP_BAD_SIGNATURE) {
4728 IWH_DBG((IWH_DEBUG_EEPROM, "iwh_eep_load(): "
4729 "not find eeprom\n"));
4730 return (IWH_FAIL);
4731 }
4732
4733 rr = iwh_eep_sem_down(sc);
4734 if (rr != 0) {
4735 IWH_DBG((IWH_DEBUG_EEPROM, "iwh_eep_load(): "
4736 "driver failed to own EEPROM\n"));
4737 return (IWH_FAIL);
4738 }
4739
4740 for (addr = 0; addr < eep_sz; addr += 2) {
4741 IWH_WRITE(sc, CSR_EEPROM_REG, addr<<1);
4742 tmp = IWH_READ(sc, CSR_EEPROM_REG);
4743 IWH_WRITE(sc, CSR_EEPROM_REG, tmp & ~(0x2));
4744
4745 for (i = 0; i < 10; i++) {
4746 rv = IWH_READ(sc, CSR_EEPROM_REG);
4747 if (rv & 1) {
4748 break;
4749 }
4750 DELAY(10);
4751 }
4752
4753 if (!(rv & 1)) {
4754 IWH_DBG((IWH_DEBUG_EEPROM, "iwh_eep_load(): "
4755 "time out when read eeprome\n"));
4756 iwh_eep_sem_up(sc);
4757 return (IWH_FAIL);
4758 }
4759
4760 eep_p[addr/2] = LE_16(rv >> 16);
4761 }
4762
4763 iwh_eep_sem_up(sc);
4764 return (IWH_SUCCESS);
4765 }
4766
4767 /*
4768 * initialize mac address in ieee80211com_t struct
4769 */
4770 static void
4771 iwh_get_mac_from_eep(iwh_sc_t *sc)
4772 {
4773 ieee80211com_t *ic = &sc->sc_ic;
4774
4775 IEEE80211_ADDR_COPY(ic->ic_macaddr, &sc->sc_eep_map[EEP_MAC_ADDRESS]);
4776
4777 IWH_DBG((IWH_DEBUG_EEPROM, "iwh_get_mac_from_eep(): "
4778 "mac:%2x:%2x:%2x:%2x:%2x:%2x\n",
4779 ic->ic_macaddr[0], ic->ic_macaddr[1], ic->ic_macaddr[2],
4780 ic->ic_macaddr[3], ic->ic_macaddr[4], ic->ic_macaddr[5]));
4781 }
4782
4783 /*
4784 * main initialization function
4785 */
4786 static int
4787 iwh_init(iwh_sc_t *sc)
4788 {
4789 int err = IWH_FAIL;
4790 clock_t clk;
4791
4792 /*
4793 * release buffer for calibration
4794 */
4795 iwh_release_calib_buffer(sc);
4796
4797 mutex_enter(&sc->sc_glock);
4798 atomic_and_32(&sc->sc_flags, ~IWH_F_FW_INIT);
4799
4800 err = iwh_init_common(sc);
4801 if (err != IWH_SUCCESS) {
4802 mutex_exit(&sc->sc_glock);
4803 return (IWH_FAIL);
4804 }
4805
4806 /*
4807 * backup ucode data part for future use.
4808 */
4809 bcopy(sc->sc_dma_fw_data.mem_va,
4810 sc->sc_dma_fw_data_bak.mem_va,
4811 sc->sc_dma_fw_data.alength);
4812
4813 /* load firmware init segment into NIC */
4814 err = iwh_load_init_firmware(sc);
4815 if (err != IWH_SUCCESS) {
4816 cmn_err(CE_WARN, "iwh_init(): "
4817 "failed to setup init firmware\n");
4818 mutex_exit(&sc->sc_glock);
4819 return (IWH_FAIL);
4820 }
4821
4822 /*
4823 * now press "execute" start running
4824 */
4825 IWH_WRITE(sc, CSR_RESET, 0);
4826
4827 clk = ddi_get_lbolt() + drv_usectohz(1000000);
4828 while (!(sc->sc_flags & IWH_F_FW_INIT)) {
4829 if (cv_timedwait(&sc->sc_ucode_cv,
4830 &sc->sc_glock, clk) < 0) {
4831 break;
4832 }
4833 }
4834
4835 if (!(sc->sc_flags & IWH_F_FW_INIT)) {
4836 cmn_err(CE_WARN, "iwh_init(): "
4837 "failed to process init alive.\n");
4838 mutex_exit(&sc->sc_glock);
4839 return (IWH_FAIL);
4840 }
4841
4842 mutex_exit(&sc->sc_glock);
4843
4844 /*
4845 * stop chipset for initializing chipset again
4846 */
4847 iwh_stop(sc);
4848
4849 mutex_enter(&sc->sc_glock);
4850 atomic_and_32(&sc->sc_flags, ~IWH_F_FW_INIT);
4851
4852 err = iwh_init_common(sc);
4853 if (err != IWH_SUCCESS) {
4854 mutex_exit(&sc->sc_glock);
4855 return (IWH_FAIL);
4856 }
4857
4858 /*
4859 * load firmware run segment into NIC
4860 */
4861 err = iwh_load_run_firmware(sc);
4862 if (err != IWH_SUCCESS) {
4863 cmn_err(CE_WARN, "iwh_init(): "
4864 "failed to setup run firmware\n");
4865 mutex_exit(&sc->sc_glock);
4866 return (IWH_FAIL);
4867 }
4868
4869 /*
4870 * now press "execute" start running
4871 */
4872 IWH_WRITE(sc, CSR_RESET, 0);
4873
4874 clk = ddi_get_lbolt() + drv_usectohz(1000000);
4875 while (!(sc->sc_flags & IWH_F_FW_INIT)) {
4876 if (cv_timedwait(&sc->sc_ucode_cv,
4877 &sc->sc_glock, clk) < 0) {
4878 break;
4879 }
4880 }
4881
4882 if (!(sc->sc_flags & IWH_F_FW_INIT)) {
4883 cmn_err(CE_WARN, "iwh_init(): "
4884 "failed to process runtime alive.\n");
4885 mutex_exit(&sc->sc_glock);
4886 return (IWH_FAIL);
4887 }
4888
4889 mutex_exit(&sc->sc_glock);
4890
4891 DELAY(1000);
4892
4893 mutex_enter(&sc->sc_glock);
4894 atomic_and_32(&sc->sc_flags, ~IWH_F_FW_INIT);
4895
4896 /*
4897 * at this point, the firmware is loaded OK, then config the hardware
4898 * with the ucode API, including rxon, txpower, etc.
4899 */
4900 err = iwh_config(sc);
4901 if (err) {
4902 cmn_err(CE_WARN, "iwh_init(): "
4903 "failed to configure device\n");
4904 mutex_exit(&sc->sc_glock);
4905 return (IWH_FAIL);
4906 }
4907
4908 /*
4909 * at this point, hardware may receive beacons :)
4910 */
4911 mutex_exit(&sc->sc_glock);
4912 return (IWH_SUCCESS);
4913 }
4914
4915 /*
4916 * stop or disable NIC
4917 */
4918 static void
4919 iwh_stop(iwh_sc_t *sc)
4920 {
4921 uint32_t tmp;
4922 int i;
4923
4924 /*
4925 * by pass if it's quiesced
4926 */
4927 if (!(sc->sc_flags & IWH_F_QUIESCED)) {
4928 mutex_enter(&sc->sc_glock);
4929 }
4930
4931 IWH_WRITE(sc, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
4932 /*
4933 * disable interrupts
4934 */
4935 IWH_WRITE(sc, CSR_INT_MASK, 0);
4936 IWH_WRITE(sc, CSR_INT, CSR_INI_SET_MASK);
4937 IWH_WRITE(sc, CSR_FH_INT_STATUS, 0xffffffff);
4938
4939 /*
4940 * reset all Tx rings
4941 */
4942 for (i = 0; i < IWH_NUM_QUEUES; i++) {
4943 iwh_reset_tx_ring(sc, &sc->sc_txq[i]);
4944 }
4945
4946 /*
4947 * reset Rx ring
4948 */
4949 iwh_reset_rx_ring(sc);
4950
4951 iwh_mac_access_enter(sc);
4952 iwh_reg_write(sc, ALM_APMG_CLK_DIS, APMG_CLK_REG_VAL_DMA_CLK_RQT);
4953 iwh_mac_access_exit(sc);
4954
4955 DELAY(5);
4956
4957 iwh_stop_master(sc);
4958
4959 mutex_enter(&sc->sc_mt_lock);
4960 sc->sc_tx_timer = 0;
4961 mutex_exit(&sc->sc_mt_lock);
4962
4963 tmp = IWH_READ(sc, CSR_RESET);
4964 IWH_WRITE(sc, CSR_RESET, tmp | CSR_RESET_REG_FLAG_SW_RESET);
4965
4966 /*
4967 * by pass if it's quiesced
4968 */
4969 if (!(sc->sc_flags & IWH_F_QUIESCED)) {
4970 mutex_exit(&sc->sc_glock);
4971 }
4972 }
4973
4974 /*
4975 * Naive implementation of the Adaptive Multi Rate Retry algorithm:
4976 * "IEEE 802.11 Rate Adaptation: A Practical Approach"
4977 * Mathieu Lacage, Hossein Manshaei, Thierry Turletti
4978 * INRIA Sophia - Projet Planete
4979 * http://www-sop.inria.fr/rapports/sophia/RR-5208.html
4980 */
4981 #define is_success(amrr) \
4982 ((amrr)->retrycnt < (amrr)->txcnt / 10)
4983 #define is_failure(amrr) \
4984 ((amrr)->retrycnt > (amrr)->txcnt / 3)
4985 #define is_enough(amrr) \
4986 ((amrr)->txcnt > 200)
4987 #define not_very_few(amrr) \
4988 ((amrr)->txcnt > 40)
4989 #define is_min_rate(in) \
4990 (0 == (in)->in_txrate)
4991 #define is_max_rate(in) \
4992 ((in)->in_rates.ir_nrates - 1 == (in)->in_txrate)
4993 #define increase_rate(in) \
4994 ((in)->in_txrate++)
4995 #define decrease_rate(in) \
4996 ((in)->in_txrate--)
4997 #define reset_cnt(amrr) \
4998 { (amrr)->txcnt = (amrr)->retrycnt = 0; }
4999
5000 #define IWH_AMRR_MIN_SUCCESS_THRESHOLD 1
5001 #define IWH_AMRR_MAX_SUCCESS_THRESHOLD 15
5002
5003 static void
5004 iwh_amrr_init(iwh_amrr_t *amrr)
5005 {
5006 amrr->success = 0;
5007 amrr->recovery = 0;
5008 amrr->txcnt = amrr->retrycnt = 0;
5009 amrr->success_threshold = IWH_AMRR_MIN_SUCCESS_THRESHOLD;
5010 amrr->ht_mcs_idx = 0; /* 6Mbps */
5011 }
5012
5013 static void
5014 iwh_amrr_timeout(iwh_sc_t *sc)
5015 {
5016 ieee80211com_t *ic = &sc->sc_ic;
5017
5018 IWH_DBG((IWH_DEBUG_RATECTL, "iwh_amrr_timeout(): "
5019 "enter\n"));
5020
5021 if (IEEE80211_M_STA == ic->ic_opmode) {
5022 iwh_amrr_ratectl(NULL, ic->ic_bss);
5023 } else {
5024 ieee80211_iterate_nodes(&ic->ic_sta, iwh_amrr_ratectl, NULL);
5025 }
5026
5027 sc->sc_clk = ddi_get_lbolt();
5028 }
5029
5030 static int
5031 iwh_is_max_rate(ieee80211_node_t *in)
5032 {
5033 int i;
5034 iwh_amrr_t *amrr = (iwh_amrr_t *)in;
5035 uint8_t r = (uint8_t)amrr->ht_mcs_idx;
5036 ieee80211com_t *ic = in->in_ic;
5037 iwh_sc_t *sc = (iwh_sc_t *)ic;
5038
5039 if (in->in_flags & IEEE80211_NODE_HT) {
5040 for (i = in->in_htrates.rs_nrates - 1; i >= 0; i--) {
5041 r = in->in_htrates.rs_rates[i] &
5042 IEEE80211_RATE_VAL;
5043 if (sc->sc_ht_conf.tx_support_mcs[r/8] &
5044 (1 << (r%8))) {
5045 break;
5046 }
5047 }
5048
5049 return (r == (uint8_t)amrr->ht_mcs_idx);
5050 } else {
5051 return (is_max_rate(in));
5052 }
5053 }
5054
5055 static int
5056 iwh_is_min_rate(ieee80211_node_t *in)
5057 {
5058 int i;
5059 uint8_t r = 0;
5060 iwh_amrr_t *amrr = (iwh_amrr_t *)in;
5061 ieee80211com_t *ic = in->in_ic;
5062 iwh_sc_t *sc = (iwh_sc_t *)ic;
5063
5064 if (in->in_flags & IEEE80211_NODE_HT) {
5065 for (i = 0; i < in->in_htrates.rs_nrates; i++) {
5066 r = in->in_htrates.rs_rates[i] &
5067 IEEE80211_RATE_VAL;
5068 if (sc->sc_ht_conf.tx_support_mcs[r/8] &
5069 (1 << (r%8))) {
5070 break;
5071 }
5072 }
5073
5074 return (r == (uint8_t)amrr->ht_mcs_idx);
5075 } else {
5076 return (is_min_rate(in));
5077 }
5078 }
5079
5080 static void
5081 iwh_increase_rate(ieee80211_node_t *in)
5082 {
5083 int i;
5084 uint8_t r;
5085 iwh_amrr_t *amrr = (iwh_amrr_t *)in;
5086 ieee80211com_t *ic = in->in_ic;
5087 iwh_sc_t *sc = (iwh_sc_t *)ic;
5088
5089 if (in->in_flags & IEEE80211_NODE_HT) {
5090 again:
5091 amrr->ht_mcs_idx++;
5092
5093 for (i = 0; i < in->in_htrates.rs_nrates; i++) {
5094 r = in->in_htrates.rs_rates[i] &
5095 IEEE80211_RATE_VAL;
5096 if ((r == (uint8_t)amrr->ht_mcs_idx) &&
5097 (sc->sc_ht_conf.tx_support_mcs[r/8] &
5098 (1 << (r%8)))) {
5099 break;
5100 }
5101 }
5102
5103 if (i >= in->in_htrates.rs_nrates) {
5104 goto again;
5105 }
5106 } else {
5107 increase_rate(in);
5108 }
5109 }
5110
5111 static void
5112 iwh_decrease_rate(ieee80211_node_t *in)
5113 {
5114 int i;
5115 uint8_t r;
5116 iwh_amrr_t *amrr = (iwh_amrr_t *)in;
5117 ieee80211com_t *ic = in->in_ic;
5118 iwh_sc_t *sc = (iwh_sc_t *)ic;
5119
5120 if (in->in_flags & IEEE80211_NODE_HT) {
5121 again:
5122 amrr->ht_mcs_idx--;
5123
5124 for (i = 0; i < in->in_htrates.rs_nrates; i++) {
5125 r = in->in_htrates.rs_rates[i] &
5126 IEEE80211_RATE_VAL;
5127 if ((r == (uint8_t)amrr->ht_mcs_idx) &&
5128 (sc->sc_ht_conf.tx_support_mcs[r/8] &
5129 (1 << (r%8)))) {
5130 break;
5131 }
5132 }
5133
5134 if (i >= in->in_htrates.rs_nrates) {
5135 goto again;
5136 }
5137 } else {
5138 decrease_rate(in);
5139 }
5140 }
5141
5142 /* ARGSUSED */
5143 static void
5144 iwh_amrr_ratectl(void *arg, ieee80211_node_t *in)
5145 {
5146 iwh_amrr_t *amrr = (iwh_amrr_t *)in;
5147 int need_change = 0;
5148
5149 if (is_success(amrr) && is_enough(amrr)) {
5150 amrr->success++;
5151 if (amrr->success >= amrr->success_threshold &&
5152 !iwh_is_max_rate(in)) {
5153 amrr->recovery = 1;
5154 amrr->success = 0;
5155 iwh_increase_rate(in);
5156 IWH_DBG((IWH_DEBUG_RATECTL, "iwh_amrr_ratectl(): "
5157 "AMRR increasing rate %d "
5158 "(txcnt=%d retrycnt=%d), mcs_idx=%d\n",
5159 in->in_txrate, amrr->txcnt,
5160 amrr->retrycnt, amrr->ht_mcs_idx));
5161 need_change = 1;
5162 } else {
5163 amrr->recovery = 0;
5164 }
5165 } else if (not_very_few(amrr) && is_failure(amrr)) {
5166 amrr->success = 0;
5167 if (!iwh_is_min_rate(in)) {
5168 if (amrr->recovery) {
5169 amrr->success_threshold++;
5170 if (amrr->success_threshold >
5171 IWH_AMRR_MAX_SUCCESS_THRESHOLD) {
5172 amrr->success_threshold =
5173 IWH_AMRR_MAX_SUCCESS_THRESHOLD;
5174 }
5175 } else {
5176 amrr->success_threshold =
5177 IWH_AMRR_MIN_SUCCESS_THRESHOLD;
5178 }
5179 iwh_decrease_rate(in);
5180 IWH_DBG((IWH_DEBUG_RATECTL, "iwh_amrr_ratectl(): "
5181 "AMRR decreasing rate %d "
5182 "(txcnt=%d retrycnt=%d), mcs_idx=%d\n",
5183 in->in_txrate, amrr->txcnt,
5184 amrr->retrycnt, amrr->ht_mcs_idx));
5185 need_change = 1;
5186 }
5187 amrr->recovery = 0; /* paper is incorrect */
5188 }
5189
5190 if (is_enough(amrr) || need_change) {
5191 reset_cnt(amrr);
5192 }
5193 }
5194
5195 /*
5196 * translate indirect address in eeprom to direct address
5197 * in eeprom and return address of entry whos indirect address
5198 * is indi_addr
5199 */
5200 static uint8_t *
5201 iwh_eep_addr_trans(iwh_sc_t *sc, uint32_t indi_addr)
5202 {
5203 uint32_t di_addr;
5204 uint16_t temp;
5205
5206 if (!(indi_addr & INDIRECT_ADDRESS)) {
5207 di_addr = indi_addr;
5208 return (&sc->sc_eep_map[di_addr]);
5209 }
5210
5211 switch (indi_addr & INDIRECT_TYPE_MSK) {
5212 case INDIRECT_GENERAL:
5213 temp = IWH_READ_EEP_SHORT(sc, EEP_LINK_GENERAL);
5214 break;
5215
5216 case INDIRECT_HOST:
5217 temp = IWH_READ_EEP_SHORT(sc, EEP_LINK_HOST);
5218 break;
5219
5220 case INDIRECT_REGULATORY:
5221 temp = IWH_READ_EEP_SHORT(sc, EEP_LINK_REGULATORY);
5222 break;
5223
5224 case INDIRECT_CALIBRATION:
5225 temp = IWH_READ_EEP_SHORT(sc, EEP_LINK_CALIBRATION);
5226 break;
5227
5228 case INDIRECT_PROCESS_ADJST:
5229 temp = IWH_READ_EEP_SHORT(sc, EEP_LINK_PROCESS_ADJST);
5230 break;
5231
5232 case INDIRECT_OTHERS:
5233 temp = IWH_READ_EEP_SHORT(sc, EEP_LINK_OTHERS);
5234 break;
5235
5236 default:
5237 temp = 0;
5238 cmn_err(CE_WARN, "iwh_eep_addr_trans(): "
5239 "incorrect indirect eeprom address.\n");
5240 break;
5241 }
5242
5243 di_addr = (indi_addr & ADDRESS_MSK) + (temp << 1);
5244
5245 return (&sc->sc_eep_map[di_addr]);
5246 }
5247
5248 /*
5249 * loade a section of ucode into NIC
5250 */
5251 static int
5252 iwh_put_seg_fw(iwh_sc_t *sc, uint32_t addr_s, uint32_t addr_d, uint32_t len)
5253 {
5254
5255 iwh_mac_access_enter(sc);
5256
5257 IWH_WRITE(sc, IWH_FH_TCSR_CHNL_TX_CONFIG_REG(IWH_FH_SRVC_CHNL),
5258 IWH_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
5259
5260 IWH_WRITE(sc, IWH_FH_SRVC_CHNL_SRAM_ADDR_REG(IWH_FH_SRVC_CHNL), addr_d);
5261
5262 IWH_WRITE(sc, IWH_FH_TFDIB_CTRL0_REG(IWH_FH_SRVC_CHNL),
5263 (addr_s & FH_MEM_TFDIB_DRAM_ADDR_LSB_MASK));
5264
5265 IWH_WRITE(sc, IWH_FH_TFDIB_CTRL1_REG(IWH_FH_SRVC_CHNL), len);
5266
5267 IWH_WRITE(sc, IWH_FH_TCSR_CHNL_TX_BUF_STS_REG(IWH_FH_SRVC_CHNL),
5268 (1 << IWH_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM) |
5269 (1 << IWH_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX) |
5270 IWH_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID);
5271
5272 IWH_WRITE(sc, IWH_FH_TCSR_CHNL_TX_CONFIG_REG(IWH_FH_SRVC_CHNL),
5273 IWH_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
5274 IWH_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL |
5275 IWH_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
5276
5277 iwh_mac_access_exit(sc);
5278
5279 return (IWH_SUCCESS);
5280 }
5281
5282 /*
5283 * necessary setting during alive notification
5284 */
5285 static int
5286 iwh_alive_common(iwh_sc_t *sc)
5287 {
5288 uint32_t base;
5289 uint32_t i;
5290 iwh_wimax_coex_cmd_t w_cmd;
5291 iwh_calibration_crystal_cmd_t c_cmd;
5292 uint32_t rv = IWH_FAIL;
5293
5294 /*
5295 * initialize SCD related registers to make TX work.
5296 */
5297 iwh_mac_access_enter(sc);
5298
5299 /*
5300 * read sram address of data base.
5301 */
5302 sc->sc_scd_base = iwh_reg_read(sc, IWH_SCD_SRAM_BASE_ADDR);
5303
5304 for (base = sc->sc_scd_base + IWH_SCD_CONTEXT_DATA_OFFSET;
5305 base < sc->sc_scd_base + IWH_SCD_TX_STTS_BITMAP_OFFSET;
5306 base += 4) {
5307 iwh_mem_write(sc, base, 0);
5308 }
5309
5310 for (; base < sc->sc_scd_base + IWH_SCD_TRANSLATE_TBL_OFFSET;
5311 base += 4) {
5312 iwh_mem_write(sc, base, 0);
5313 }
5314
5315 for (i = 0; i < sizeof (uint16_t) * IWH_NUM_QUEUES; i += 4) {
5316 iwh_mem_write(sc, base + i, 0);
5317 }
5318
5319 iwh_reg_write(sc, IWH_SCD_DRAM_BASE_ADDR,
5320 sc->sc_dma_sh.cookie.dmac_address >> 10);
5321
5322 iwh_reg_write(sc, IWH_SCD_QUEUECHAIN_SEL,
5323 IWH_SCD_QUEUECHAIN_SEL_ALL(IWH_NUM_QUEUES));
5324
5325 iwh_reg_write(sc, IWH_SCD_AGGR_SEL, 0);
5326
5327 for (i = 0; i < IWH_NUM_QUEUES; i++) {
5328 iwh_reg_write(sc, IWH_SCD_QUEUE_RDPTR(i), 0);
5329 IWH_WRITE(sc, HBUS_TARG_WRPTR, 0 | (i << 8));
5330 iwh_mem_write(sc, sc->sc_scd_base +
5331 IWH_SCD_CONTEXT_QUEUE_OFFSET(i), 0);
5332 iwh_mem_write(sc, sc->sc_scd_base +
5333 IWH_SCD_CONTEXT_QUEUE_OFFSET(i) +
5334 sizeof (uint32_t),
5335 ((SCD_WIN_SIZE << IWH_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
5336 IWH_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
5337 ((SCD_FRAME_LIMIT <<
5338 IWH_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
5339 IWH_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
5340 }
5341
5342 iwh_reg_write(sc, IWH_SCD_INTERRUPT_MASK, (1 << IWH_NUM_QUEUES) - 1);
5343
5344 iwh_reg_write(sc, (IWH_SCD_BASE + 0x10),
5345 SCD_TXFACT_REG_TXFIFO_MASK(0, 7));
5346
5347 IWH_WRITE(sc, HBUS_TARG_WRPTR, (IWH_CMD_QUEUE_NUM << 8));
5348 iwh_reg_write(sc, IWH_SCD_QUEUE_RDPTR(IWH_CMD_QUEUE_NUM), 0);
5349
5350 /*
5351 * queue 0-7 map to FIFO 0-7 and
5352 * all queues work under FIFO mode(none-scheduler_ack)
5353 */
5354 for (i = 0; i < 4; i++) {
5355 iwh_reg_write(sc, IWH_SCD_QUEUE_STATUS_BITS(i),
5356 (1 << IWH_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
5357 ((3-i) << IWH_SCD_QUEUE_STTS_REG_POS_TXF) |
5358 (1 << IWH_SCD_QUEUE_STTS_REG_POS_WSL) |
5359 IWH_SCD_QUEUE_STTS_REG_MSK);
5360 }
5361
5362 iwh_reg_write(sc, IWH_SCD_QUEUE_STATUS_BITS(IWH_CMD_QUEUE_NUM),
5363 (1 << IWH_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
5364 (IWH_CMD_FIFO_NUM << IWH_SCD_QUEUE_STTS_REG_POS_TXF) |
5365 (1 << IWH_SCD_QUEUE_STTS_REG_POS_WSL) |
5366 IWH_SCD_QUEUE_STTS_REG_MSK);
5367
5368 for (i = 5; i < 7; i++) {
5369 iwh_reg_write(sc, IWH_SCD_QUEUE_STATUS_BITS(i),
5370 (1 << IWH_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
5371 (i << IWH_SCD_QUEUE_STTS_REG_POS_TXF) |
5372 (1 << IWH_SCD_QUEUE_STTS_REG_POS_WSL) |
5373 IWH_SCD_QUEUE_STTS_REG_MSK);
5374 }
5375
5376 iwh_mac_access_exit(sc);
5377
5378 (void) memset(&w_cmd, 0, sizeof (w_cmd));
5379
5380 rv = iwh_cmd(sc, COEX_PRIORITY_TABLE_CMD, &w_cmd, sizeof (w_cmd), 1);
5381 if (rv != IWH_SUCCESS) {
5382 cmn_err(CE_WARN, "iwh_alive_common(): "
5383 "failed to send wimax coexist command.\n");
5384 return (rv);
5385 }
5386
5387 if ((sc->sc_dev_id != 0x423c) &&
5388 (sc->sc_dev_id != 0x423d)) {
5389 (void) memset(&c_cmd, 0, sizeof (c_cmd));
5390
5391 c_cmd.opCode = PHY_CALIBRATE_CRYSTAL_FRQ_CMD;
5392 c_cmd.data.cap_pin1 = LE_16(sc->sc_eep_calib->xtal_calib[0]);
5393 c_cmd.data.cap_pin2 = LE_16(sc->sc_eep_calib->xtal_calib[1]);
5394
5395 rv = iwh_cmd(sc, REPLY_PHY_CALIBRATION_CMD,
5396 &c_cmd, sizeof (c_cmd), 1);
5397 if (rv != IWH_SUCCESS) {
5398 cmn_err(CE_WARN, "iwh_alive_common(): "
5399 "failed to send crystal"
5400 "frq calibration command.\n");
5401 return (rv);
5402 }
5403
5404 /*
5405 * make sure crystal frequency calibration ready
5406 * before next operations.
5407 */
5408 DELAY(1000);
5409 }
5410
5411 return (IWH_SUCCESS);
5412 }
5413
5414 /*
5415 * save results of calibration from ucode
5416 */
5417 static void
5418 iwh_save_calib_result(iwh_sc_t *sc, iwh_rx_desc_t *desc)
5419 {
5420 struct iwh_calib_results *res_p = &sc->sc_calib_results;
5421 struct iwh_calib_hdr *calib_hdr = (struct iwh_calib_hdr *)(desc + 1);
5422 int len = LE_32(desc->len);
5423
5424 /*
5425 * ensure the size of buffer is not too big
5426 */
5427 len = (len & FH_RSCSR_FRAME_SIZE_MASK) - 4;
5428
5429 switch (calib_hdr->op_code) {
5430 case PHY_CALIBRATE_LO_CMD:
5431 if (NULL == res_p->lo_res) {
5432 res_p->lo_res = kmem_alloc(len, KM_NOSLEEP);
5433 }
5434
5435 if (NULL == res_p->lo_res) {
5436 cmn_err(CE_WARN, "iwh_save_calib_result(): "
5437 "failed to allocate memory.\n");
5438 return;
5439 }
5440
5441 res_p->lo_res_len = len;
5442 bcopy(calib_hdr, res_p->lo_res, len);
5443 break;
5444
5445 case PHY_CALIBRATE_TX_IQ_CMD:
5446 if (NULL == res_p->tx_iq_res) {
5447 res_p->tx_iq_res = kmem_alloc(len, KM_NOSLEEP);
5448 }
5449
5450 if (NULL == res_p->tx_iq_res) {
5451 cmn_err(CE_WARN, "iwh_save_calib_result(): "
5452 "failed to allocate memory.\n");
5453 return;
5454 }
5455
5456 res_p->tx_iq_res_len = len;
5457 bcopy(calib_hdr, res_p->tx_iq_res, len);
5458 break;
5459
5460 case PHY_CALIBRATE_TX_IQ_PERD_CMD:
5461 if (NULL == res_p->tx_iq_perd_res) {
5462 res_p->tx_iq_perd_res = kmem_alloc(len, KM_NOSLEEP);
5463 }
5464
5465 if (NULL == res_p->tx_iq_perd_res) {
5466 cmn_err(CE_WARN, "iwh_save_calib_result(): "
5467 "failed to allocate memory.\n");
5468 return;
5469 }
5470
5471 res_p->tx_iq_perd_res_len = len;
5472 bcopy(calib_hdr, res_p->tx_iq_perd_res, len);
5473 break;
5474
5475 case PHY_CALIBRATE_DC_CMD:
5476 if (NULL == res_p->dc_res) {
5477 res_p->dc_res = kmem_alloc(len, KM_NOSLEEP);
5478 }
5479
5480 if (NULL == res_p->dc_res) {
5481 cmn_err(CE_WARN, "iwh_save_calib_result(): "
5482 "failed to allocate memory.\n");
5483 return;
5484 }
5485
5486 res_p->dc_res_len = len;
5487 bcopy(calib_hdr, res_p->dc_res, len);
5488 break;
5489
5490 case PHY_CALIBRATE_BASE_BAND_CMD:
5491 if (NULL == res_p->base_band_res) {
5492 res_p->base_band_res = kmem_alloc(len, KM_NOSLEEP);
5493 }
5494
5495 if (NULL == res_p->base_band_res) {
5496 cmn_err(CE_WARN, "iwh_save_calib_result(): "
5497 "failed to allocate memory.\n");
5498 return;
5499 }
5500
5501 res_p->base_band_res_len = len;
5502 bcopy(calib_hdr, res_p->base_band_res, len);
5503 break;
5504
5505 default:
5506 cmn_err(CE_WARN, "iwh_save_calib_result(): "
5507 "incorrect calibration type(%d).\n", calib_hdr->op_code);
5508 break;
5509 }
5510
5511 }
5512
5513 /*
5514 * configure TX pwoer table
5515 */
5516 static int
5517 iwh_tx_power_table(iwh_sc_t *sc, int async)
5518 {
5519 iwh_tx_power_table_cmd_t txpower;
5520 int i, err = IWH_FAIL;
5521
5522 (void) memset(&txpower, 0, sizeof (txpower));
5523
5524 txpower.band = 1; /* for 2.4G */
5525 txpower.channel = (uint8_t)LE_16(sc->sc_config.chan);
5526 txpower.pa_measurements = 1;
5527 txpower.max_mcs = 23;
5528
5529 for (i = 0; i < 24; i++) {
5530 txpower.db.ht_ofdm_power[i].s.radio_tx_gain[0] = 0x16;
5531 txpower.db.ht_ofdm_power[i].s.radio_tx_gain[1] = 0x16;
5532 txpower.db.ht_ofdm_power[i].s.radio_tx_gain[2] = 0x16;
5533 txpower.db.ht_ofdm_power[i].s.dsp_predis_atten[0] = 0x6E;
5534 txpower.db.ht_ofdm_power[i].s.dsp_predis_atten[1] = 0x6E;
5535 txpower.db.ht_ofdm_power[i].s.dsp_predis_atten[2] = 0x6E;
5536 }
5537
5538 for (i = 0; i < 2; i++) {
5539 txpower.db.cck_power[i].s.radio_tx_gain[0] = 0x16;
5540 txpower.db.cck_power[i].s.radio_tx_gain[1] = 0x16;
5541 txpower.db.cck_power[i].s.radio_tx_gain[2] = 0x16;
5542 txpower.db.cck_power[i].s.dsp_predis_atten[0] = 0x6E;
5543 txpower.db.cck_power[i].s.dsp_predis_atten[1] = 0x6E;
5544 txpower.db.cck_power[i].s.dsp_predis_atten[2] = 0x6E;
5545 }
5546
5547 err = iwh_cmd(sc, REPLY_TX_PWR_TABLE_CMD, &txpower,
5548 sizeof (txpower), async);
5549 if (err != IWH_SUCCESS) {
5550 cmn_err(CE_WARN, "iwh_tx_power_table(): "
5551 "failed to set tx power table.\n");
5552 return (err);
5553 }
5554
5555 return (err);
5556 }
5557
5558 static void
5559 iwh_release_calib_buffer(iwh_sc_t *sc)
5560 {
5561 if (sc->sc_calib_results.lo_res != NULL) {
5562 kmem_free(sc->sc_calib_results.lo_res,
5563 sc->sc_calib_results.lo_res_len);
5564 sc->sc_calib_results.lo_res = NULL;
5565 }
5566
5567 if (sc->sc_calib_results.tx_iq_res != NULL) {
5568 kmem_free(sc->sc_calib_results.tx_iq_res,
5569 sc->sc_calib_results.tx_iq_res_len);
5570 sc->sc_calib_results.tx_iq_res = NULL;
5571 }
5572
5573 if (sc->sc_calib_results.tx_iq_perd_res != NULL) {
5574 kmem_free(sc->sc_calib_results.tx_iq_perd_res,
5575 sc->sc_calib_results.tx_iq_perd_res_len);
5576 sc->sc_calib_results.tx_iq_perd_res = NULL;
5577 }
5578
5579 if (sc->sc_calib_results.dc_res != NULL) {
5580 kmem_free(sc->sc_calib_results.dc_res,
5581 sc->sc_calib_results.dc_res_len);
5582 sc->sc_calib_results.dc_res = NULL;
5583 }
5584
5585 if (sc->sc_calib_results.base_band_res != NULL) {
5586 kmem_free(sc->sc_calib_results.base_band_res,
5587 sc->sc_calib_results.base_band_res_len);
5588 sc->sc_calib_results.base_band_res = NULL;
5589 }
5590 }
5591
5592 /*
5593 * common section of intialization
5594 */
5595 static int
5596 iwh_init_common(iwh_sc_t *sc)
5597 {
5598 int32_t qid;
5599 uint32_t tmp;
5600
5601 if (iwh_reset_hw(sc) != IWH_SUCCESS) {
5602 cmn_err(CE_WARN, "iwh_init_common(): "
5603 "failed to reset hardware\n");
5604 return (IWH_FAIL);
5605 }
5606
5607 (void) iwh_preinit(sc);
5608
5609 tmp = IWH_READ(sc, CSR_GP_CNTRL);
5610 if (!(tmp & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) {
5611 cmn_err(CE_NOTE, "iwh_init_common(): "
5612 "radio transmitter is off\n");
5613 return (IWH_FAIL);
5614 }
5615
5616 /*
5617 * init Rx ring
5618 */
5619 iwh_mac_access_enter(sc);
5620 IWH_WRITE(sc, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
5621
5622 IWH_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
5623 IWH_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
5624 sc->sc_rxq.dma_desc.cookie.dmac_address >> 8);
5625
5626 IWH_WRITE(sc, FH_RSCSR_CHNL0_STTS_WPTR_REG,
5627 ((uint32_t)(sc->sc_dma_sh.cookie.dmac_address +
5628 offsetof(struct iwh_shared, val0)) >> 4));
5629
5630 IWH_WRITE(sc, FH_MEM_RCSR_CHNL0_CONFIG_REG,
5631 FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
5632 FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
5633 IWH_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K |
5634 (RX_QUEUE_SIZE_LOG <<
5635 FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT));
5636 iwh_mac_access_exit(sc);
5637 IWH_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_WPTR_REG,
5638 (RX_QUEUE_SIZE - 1) & ~0x7);
5639
5640 /*
5641 * init Tx rings
5642 */
5643 iwh_mac_access_enter(sc);
5644 iwh_reg_write(sc, IWH_SCD_TXFACT, 0);
5645
5646 /*
5647 * keep warm page
5648 */
5649 IWH_WRITE(sc, IWH_FH_KW_MEM_ADDR_REG,
5650 sc->sc_dma_kw.cookie.dmac_address >> 4);
5651
5652 for (qid = 0; qid < IWH_NUM_QUEUES; qid++) {
5653 IWH_WRITE(sc, FH_MEM_CBBC_QUEUE(qid),
5654 sc->sc_txq[qid].dma_desc.cookie.dmac_address >> 8);
5655 IWH_WRITE(sc, IWH_FH_TCSR_CHNL_TX_CONFIG_REG(qid),
5656 IWH_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
5657 IWH_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL);
5658 }
5659
5660 iwh_mac_access_exit(sc);
5661
5662 /*
5663 * clear "radio off" and "disable command" bits
5664 */
5665 IWH_WRITE(sc, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
5666 IWH_WRITE(sc, CSR_UCODE_DRV_GP1_CLR,
5667 CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
5668
5669 /*
5670 * clear any pending interrupts
5671 */
5672 IWH_WRITE(sc, CSR_INT, 0xffffffff);
5673
5674 /*
5675 * enable interrupts
5676 */
5677 IWH_WRITE(sc, CSR_INT_MASK, CSR_INI_SET_MASK);
5678
5679 IWH_WRITE(sc, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
5680 IWH_WRITE(sc, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
5681
5682 return (IWH_SUCCESS);
5683 }
5684
5685 static int
5686 iwh_fast_recover(iwh_sc_t *sc)
5687 {
5688 ieee80211com_t *ic = &sc->sc_ic;
5689 int err = IWH_FAIL;
5690
5691 mutex_enter(&sc->sc_glock);
5692
5693 /*
5694 * restore runtime configuration
5695 */
5696 bcopy(&sc->sc_config_save, &sc->sc_config,
5697 sizeof (sc->sc_config));
5698
5699 sc->sc_config.assoc_id = 0;
5700 sc->sc_config.filter_flags &= ~LE_32(RXON_FILTER_ASSOC_MSK);
5701
5702 if ((err = iwh_hw_set_before_auth(sc)) != IWH_SUCCESS) {
5703 cmn_err(CE_WARN, "iwh_fast_recover(): "
5704 "could not setup authentication\n");
5705 mutex_exit(&sc->sc_glock);
5706 return (err);
5707 }
5708
5709 bcopy(&sc->sc_config_save, &sc->sc_config,
5710 sizeof (sc->sc_config));
5711
5712 /*
5713 * update adapter's configuration
5714 */
5715 err = iwh_run_state_config(sc);
5716 if (err != IWH_SUCCESS) {
5717 cmn_err(CE_WARN, "iwh_fast_recover(): "
5718 "failed to setup association\n");
5719 mutex_exit(&sc->sc_glock);
5720 return (err);
5721 }
5722
5723 /*
5724 * set LED on
5725 */
5726 iwh_set_led(sc, 2, 0, 1);
5727
5728 mutex_exit(&sc->sc_glock);
5729
5730 atomic_and_32(&sc->sc_flags, ~IWH_F_HW_ERR_RECOVER);
5731
5732 /*
5733 * start queue
5734 */
5735 IWH_DBG((IWH_DEBUG_FW, "iwh_fast_recover(): "
5736 "resume xmit\n"));
5737 mac_tx_update(ic->ic_mach);
5738
5739 return (IWH_SUCCESS);
5740 }
5741
5742 static int
5743 iwh_run_state_config(iwh_sc_t *sc)
5744 {
5745 struct ieee80211com *ic = &sc->sc_ic;
5746 ieee80211_node_t *in = ic->ic_bss;
5747 uint32_t ht_protec = (uint32_t)(-1);
5748 int err = IWH_FAIL;
5749
5750 /*
5751 * update adapter's configuration
5752 */
5753 sc->sc_config.assoc_id = in->in_associd & 0x3fff;
5754
5755 /*
5756 * short preamble/slot time are
5757 * negotiated when associating
5758 */
5759 sc->sc_config.flags &=
5760 ~LE_32(RXON_FLG_SHORT_PREAMBLE_MSK |
5761 RXON_FLG_SHORT_SLOT_MSK);
5762
5763 if (ic->ic_flags & IEEE80211_F_SHSLOT) {
5764 sc->sc_config.flags |=
5765 LE_32(RXON_FLG_SHORT_SLOT_MSK);
5766 }
5767
5768 if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) {
5769 sc->sc_config.flags |=
5770 LE_32(RXON_FLG_SHORT_PREAMBLE_MSK);
5771 }
5772
5773 if (in->in_flags & IEEE80211_NODE_HT) {
5774 ht_protec = in->in_htopmode;
5775 if (ht_protec > 3) {
5776 cmn_err(CE_WARN, "iwh_run_state_config(): "
5777 "HT protection mode is not correct.\n");
5778 return (IWH_FAIL);
5779 } else if (NO_HT_PROT == ht_protec) {
5780 ht_protec = sc->sc_ht_conf.ht_protection;
5781 }
5782
5783 sc->sc_config.flags |=
5784 LE_32(ht_protec << RXON_FLG_HT_OPERATING_MODE_POS);
5785 }
5786
5787 /*
5788 * set RX chains/antennas.
5789 */
5790 iwh_config_rxon_chain(sc);
5791
5792 sc->sc_config.filter_flags |=
5793 LE_32(RXON_FILTER_ASSOC_MSK);
5794
5795 if (ic->ic_opmode != IEEE80211_M_STA) {
5796 sc->sc_config.filter_flags |=
5797 LE_32(RXON_FILTER_BCON_AWARE_MSK);
5798 }
5799
5800 IWH_DBG((IWH_DEBUG_80211, "iwh_run_state_config(): "
5801 "config chan %d flags %x"
5802 " filter_flags %x\n",
5803 sc->sc_config.chan, sc->sc_config.flags,
5804 sc->sc_config.filter_flags));
5805
5806 err = iwh_cmd(sc, REPLY_RXON, &sc->sc_config,
5807 sizeof (iwh_rxon_cmd_t), 1);
5808 if (err != IWH_SUCCESS) {
5809 cmn_err(CE_WARN, "iwh_run_state_config(): "
5810 "could not update configuration\n");
5811 return (err);
5812 }
5813
5814 if ((sc->sc_dev_id != 0x423c) &&
5815 (sc->sc_dev_id != 0x423d)) {
5816 /*
5817 * send tx power table command
5818 */
5819 err = iwh_tx_power_table(sc, 1);
5820 if (err != IWH_SUCCESS) {
5821 return (err);
5822 }
5823 }
5824
5825 /*
5826 * Not need to update retry rate table for AP node
5827 */
5828 err = iwh_qosparam_to_hw(sc, 1);
5829 if (err != IWH_SUCCESS) {
5830 return (err);
5831 }
5832
5833 return (err);
5834 }
5835
5836 /*
5837 * This function is only for compatibility with Net80211 module.
5838 * iwh_qosparam_to_hw() is the actual function updating EDCA
5839 * parameters to hardware.
5840 */
5841 /* ARGSUSED */
5842 static int
5843 iwh_wme_update(ieee80211com_t *ic)
5844 {
5845 return (0);
5846 }
5847
5848 static int
5849 iwh_wme_to_qos_ac(int wme_ac)
5850 {
5851 int qos_ac = QOS_AC_INVALID;
5852
5853 if (wme_ac < WME_AC_BE || wme_ac > WME_AC_VO) {
5854 cmn_err(CE_WARN, "iwh_wme_to_qos_ac(): "
5855 "WME AC index is not in suitable range.\n");
5856 return (qos_ac);
5857 }
5858
5859 switch (wme_ac) {
5860 case WME_AC_BE:
5861 qos_ac = QOS_AC_BK;
5862 break;
5863 case WME_AC_BK:
5864 qos_ac = QOS_AC_BE;
5865 break;
5866 case WME_AC_VI:
5867 qos_ac = QOS_AC_VI;
5868 break;
5869 case WME_AC_VO:
5870 qos_ac = QOS_AC_VO;
5871 break;
5872 }
5873
5874 return (qos_ac);
5875 }
5876
5877 static uint16_t
5878 iwh_cw_e_to_cw(uint8_t cw_e)
5879 {
5880 uint16_t cw = 1;
5881
5882 while (cw_e > 0) {
5883 cw <<= 1;
5884 cw_e--;
5885 }
5886
5887 cw -= 1;
5888 return (cw);
5889 }
5890
5891 static int
5892 iwh_wmeparam_check(struct wmeParams *wmeparam)
5893 {
5894 int i;
5895
5896 for (i = 0; i < WME_NUM_AC; i++) {
5897
5898 if ((wmeparam[i].wmep_logcwmax > QOS_CW_RANGE_MAX) ||
5899 (wmeparam[i].wmep_logcwmin >= wmeparam[i].wmep_logcwmax)) {
5900 cmn_err(CE_WARN, "iwh_wmeparam_check(): "
5901 "Contention window is not in suitable range.\n");
5902 return (IWH_FAIL);
5903 }
5904
5905 if ((wmeparam[i].wmep_aifsn < QOS_AIFSN_MIN) ||
5906 (wmeparam[i].wmep_aifsn > QOS_AIFSN_MAX)) {
5907 cmn_err(CE_WARN, "iwh_wmeparam_check(): "
5908 "Arbitration interframe space number"
5909 "is not in suitable range.\n");
5910 return (IWH_FAIL);
5911 }
5912 }
5913
5914 return (IWH_SUCCESS);
5915 }
5916
5917 /*
5918 * This function updates EDCA parameters into hardware.
5919 * FIFO0-background, FIFO1-best effort, FIFO2-viedo, FIFO3-voice.
5920 */
5921 static int
5922 iwh_qosparam_to_hw(iwh_sc_t *sc, int async)
5923 {
5924 ieee80211com_t *ic = &sc->sc_ic;
5925 ieee80211_node_t *in = ic->ic_bss;
5926 struct wmeParams *wmeparam;
5927 iwh_qos_param_cmd_t qosparam_cmd;
5928 int i, j;
5929 int err = IWH_FAIL;
5930
5931 if ((in->in_flags & IEEE80211_NODE_QOS) &&
5932 (IEEE80211_M_STA == ic->ic_opmode)) {
5933 wmeparam = ic->ic_wme.wme_chanParams.cap_wmeParams;
5934 } else {
5935 return (IWH_SUCCESS);
5936 }
5937
5938 (void) memset(&qosparam_cmd, 0, sizeof (qosparam_cmd));
5939
5940 err = iwh_wmeparam_check(wmeparam);
5941 if (err != IWH_SUCCESS) {
5942 return (err);
5943 }
5944
5945 if (in->in_flags & IEEE80211_NODE_QOS) {
5946 qosparam_cmd.flags |= QOS_PARAM_FLG_UPDATE_EDCA;
5947 }
5948
5949 if (in->in_flags & (IEEE80211_NODE_QOS | IEEE80211_NODE_HT)) {
5950 qosparam_cmd.flags |= QOS_PARAM_FLG_TGN;
5951 }
5952
5953 for (i = 0; i < WME_NUM_AC; i++) {
5954
5955 j = iwh_wme_to_qos_ac(i);
5956 if (j < QOS_AC_BK || j > QOS_AC_VO) {
5957 return (IWH_FAIL);
5958 }
5959
5960 qosparam_cmd.ac[j].cw_min =
5961 iwh_cw_e_to_cw(wmeparam[i].wmep_logcwmin);
5962 qosparam_cmd.ac[j].cw_max =
5963 iwh_cw_e_to_cw(wmeparam[i].wmep_logcwmax);
5964 qosparam_cmd.ac[j].aifsn =
5965 wmeparam[i].wmep_aifsn;
5966 qosparam_cmd.ac[j].txop =
5967 (uint16_t)(wmeparam[i].wmep_txopLimit * 32);
5968 }
5969
5970 err = iwh_cmd(sc, REPLY_QOS_PARAM, &qosparam_cmd,
5971 sizeof (qosparam_cmd), async);
5972 if (err != IWH_SUCCESS) {
5973 cmn_err(CE_WARN, "iwh_qosparam_to_hw(): "
5974 "failed to update QoS parameters into hardware.\n");
5975 return (err);
5976 }
5977
5978 #ifdef DEBUG
5979 IWH_DBG((IWH_DEBUG_QOS, "iwh_qosparam_to_hw(): "
5980 "EDCA parameters are as follows:\n"));
5981
5982 IWH_DBG((IWH_DEBUG_QOS, "BK parameters are: "
5983 "cw_min = %d, cw_max = %d, aifsn = %d, txop = %d\n",
5984 qosparam_cmd.ac[0].cw_min, qosparam_cmd.ac[0].cw_max,
5985 qosparam_cmd.ac[0].aifsn, qosparam_cmd.ac[0].txop));
5986
5987 IWH_DBG((IWH_DEBUG_QOS, "BE parameters are: "
5988 "cw_min = %d, cw_max = %d, aifsn = %d, txop = %d\n",
5989 qosparam_cmd.ac[1].cw_min, qosparam_cmd.ac[1].cw_max,
5990 qosparam_cmd.ac[1].aifsn, qosparam_cmd.ac[1].txop));
5991
5992 IWH_DBG((IWH_DEBUG_QOS, "VI parameters are: "
5993 "cw_min = %d, cw_max = %d, aifsn = %d, txop = %d\n",
5994 qosparam_cmd.ac[2].cw_min, qosparam_cmd.ac[2].cw_max,
5995 qosparam_cmd.ac[2].aifsn, qosparam_cmd.ac[2].txop));
5996
5997 IWH_DBG((IWH_DEBUG_QOS, "VO parameters are: "
5998 "cw_min = %d, cw_max = %d, aifsn = %d, txop = %d\n",
5999 qosparam_cmd.ac[3].cw_min, qosparam_cmd.ac[3].cw_max,
6000 qosparam_cmd.ac[3].aifsn, qosparam_cmd.ac[3].txop));
6001 #endif
6002 return (err);
6003 }
6004
6005 static inline int
6006 iwh_wme_tid_qos_ac(int tid)
6007 {
6008 switch (tid) {
6009 case 1:
6010 case 2:
6011 return (QOS_AC_BK);
6012 case 0:
6013 case 3:
6014 return (QOS_AC_BE);
6015 case 4:
6016 case 5:
6017 return (QOS_AC_VI);
6018 case 6:
6019 case 7:
6020 return (QOS_AC_VO);
6021 }
6022
6023 return (QOS_AC_BE);
6024 }
6025
6026 static inline int
6027 iwh_qos_ac_to_txq(int qos_ac)
6028 {
6029 switch (qos_ac) {
6030 case QOS_AC_BK:
6031 return (QOS_AC_BK_TO_TXQ);
6032 case QOS_AC_BE:
6033 return (QOS_AC_BE_TO_TXQ);
6034 case QOS_AC_VI:
6035 return (QOS_AC_VI_TO_TXQ);
6036 case QOS_AC_VO:
6037 return (QOS_AC_VO_TO_TXQ);
6038 }
6039
6040 return (QOS_AC_BE_TO_TXQ);
6041 }
6042
6043 static int
6044 iwh_wme_tid_to_txq(int tid)
6045 {
6046 int queue_n = TXQ_FOR_AC_INVALID;
6047 int qos_ac;
6048
6049 if (tid < WME_TID_MIN ||
6050 tid > WME_TID_MAX) {
6051 cmn_err(CE_WARN, "wme_tid_to_txq(): "
6052 "TID is not in suitable range.\n");
6053 return (queue_n);
6054 }
6055
6056 qos_ac = iwh_wme_tid_qos_ac(tid);
6057 queue_n = iwh_qos_ac_to_txq(qos_ac);
6058
6059 return (queue_n);
6060 }
6061
6062 /*
6063 * This function is used for intializing HT relevant configurations.
6064 */
6065 static void
6066 iwh_init_ht_conf(iwh_sc_t *sc)
6067 {
6068 (void) memset(&sc->sc_ht_conf, 0, sizeof (iwh_ht_conf_t));
6069
6070 if ((0x4235 == sc->sc_dev_id) ||
6071 (0x4236 == sc->sc_dev_id) ||
6072 (0x423a == sc->sc_dev_id)) {
6073 sc->sc_ht_conf.ht_support = 1;
6074
6075 sc->sc_ht_conf.valid_chains = 3;
6076 sc->sc_ht_conf.tx_stream_count = 2;
6077 sc->sc_ht_conf.rx_stream_count = 2;
6078
6079 sc->sc_ht_conf.tx_support_mcs[0] = 0xff;
6080 sc->sc_ht_conf.tx_support_mcs[1] = 0xff;
6081 sc->sc_ht_conf.rx_support_mcs[0] = 0xff;
6082 sc->sc_ht_conf.rx_support_mcs[1] = 0xff;
6083 } else {
6084 sc->sc_ht_conf.ht_support = 1;
6085
6086 sc->sc_ht_conf.valid_chains = 2;
6087 sc->sc_ht_conf.tx_stream_count = 1;
6088 sc->sc_ht_conf.rx_stream_count = 2;
6089
6090 sc->sc_ht_conf.tx_support_mcs[0] = 0xff;
6091 sc->sc_ht_conf.rx_support_mcs[0] = 0xff;
6092 sc->sc_ht_conf.rx_support_mcs[1] = 0xff;
6093 }
6094
6095 if (sc->sc_ht_conf.ht_support) {
6096 sc->sc_ht_conf.cap |= HT_CAP_GRN_FLD;
6097 sc->sc_ht_conf.cap |= HT_CAP_SGI_20;
6098 sc->sc_ht_conf.cap |= HT_CAP_MAX_AMSDU;
6099 /* should disable MIMO */
6100 sc->sc_ht_conf.cap |= HT_CAP_MIMO_PS;
6101
6102 sc->sc_ht_conf.ampdu_p.factor = HT_RX_AMPDU_FACTOR;
6103 sc->sc_ht_conf.ampdu_p.density = HT_MPDU_DENSITY;
6104
6105 sc->sc_ht_conf.ht_protection = HT_PROT_CHAN_NON_HT;
6106 }
6107 }
6108
6109 /*
6110 * This function overwrites default ieee80211_rateset_11n struc.
6111 */
6112 static void
6113 iwh_overwrite_11n_rateset(iwh_sc_t *sc)
6114 {
6115 uint8_t *ht_rs = sc->sc_ht_conf.rx_support_mcs;
6116 int mcs_idx, mcs_count = 0;
6117 int i, j;
6118
6119 for (i = 0; i < HT_RATESET_NUM; i++) {
6120 for (j = 0; j < 8; j++) {
6121 if (ht_rs[i] & (1 << j)) {
6122 mcs_idx = i * 8 + j;
6123 if (mcs_idx >= IEEE80211_HTRATE_MAXSIZE) {
6124 break;
6125 }
6126
6127 ieee80211_rateset_11n.rs_rates[mcs_idx] =
6128 (uint8_t)mcs_idx;
6129 mcs_count++;
6130 }
6131 }
6132 }
6133
6134 ieee80211_rateset_11n.rs_nrates = (uint8_t)mcs_count;
6135
6136 #ifdef DEBUG
6137 IWH_DBG((IWH_DEBUG_HTRATE, "iwh_overwrite_11n_rateset(): "
6138 "HT rates supported by this station is as follows:\n"));
6139
6140 for (i = 0; i < ieee80211_rateset_11n.rs_nrates; i++) {
6141 IWH_DBG((IWH_DEBUG_HTRATE, "Rate %d is %d\n",
6142 i, ieee80211_rateset_11n.rs_rates[i]));
6143 }
6144 #endif
6145 }
6146
6147 /*
6148 * This function overwrites default configurations of
6149 * ieee80211com structure in Net80211 module.
6150 */
6151 static void
6152 iwh_overwrite_ic_default(iwh_sc_t *sc)
6153 {
6154 ieee80211com_t *ic = &sc->sc_ic;
6155
6156 sc->sc_newstate = ic->ic_newstate;
6157 ic->ic_newstate = iwh_newstate;
6158 ic->ic_node_alloc = iwh_node_alloc;
6159 ic->ic_node_free = iwh_node_free;
6160
6161 if (sc->sc_ht_conf.ht_support) {
6162 sc->sc_recv_action = ic->ic_recv_action;
6163 ic->ic_recv_action = iwh_recv_action;
6164 sc->sc_send_action = ic->ic_send_action;
6165 ic->ic_send_action = iwh_send_action;
6166
6167 ic->ic_ampdu_rxmax = sc->sc_ht_conf.ampdu_p.factor;
6168 ic->ic_ampdu_density = sc->sc_ht_conf.ampdu_p.density;
6169 ic->ic_ampdu_limit = ic->ic_ampdu_rxmax;
6170 }
6171 }
6172
6173 /*
6174 * This function sets "RX chain selection" feild
6175 * in RXON command during plumb driver.
6176 */
6177 static void
6178 iwh_config_rxon_chain(iwh_sc_t *sc)
6179 {
6180 ieee80211com_t *ic = &sc->sc_ic;
6181 ieee80211_node_t *in = ic->ic_bss;
6182
6183 if (3 == sc->sc_ht_conf.valid_chains) {
6184 sc->sc_config.rx_chain = LE_16((RXON_RX_CHAIN_A_MSK |
6185 RXON_RX_CHAIN_B_MSK | RXON_RX_CHAIN_C_MSK) <<
6186 RXON_RX_CHAIN_VALID_POS);
6187
6188 sc->sc_config.rx_chain |= LE_16((RXON_RX_CHAIN_A_MSK |
6189 RXON_RX_CHAIN_B_MSK | RXON_RX_CHAIN_C_MSK) <<
6190 RXON_RX_CHAIN_FORCE_SEL_POS);
6191
6192 sc->sc_config.rx_chain |= LE_16((RXON_RX_CHAIN_A_MSK |
6193 RXON_RX_CHAIN_B_MSK | RXON_RX_CHAIN_C_MSK) <<
6194 RXON_RX_CHAIN_FORCE_MIMO_SEL_POS);
6195 } else {
6196 sc->sc_config.rx_chain = LE_16((RXON_RX_CHAIN_A_MSK |
6197 RXON_RX_CHAIN_B_MSK) << RXON_RX_CHAIN_VALID_POS);
6198
6199 sc->sc_config.rx_chain |= LE_16((RXON_RX_CHAIN_A_MSK |
6200 RXON_RX_CHAIN_B_MSK) << RXON_RX_CHAIN_FORCE_SEL_POS);
6201
6202 sc->sc_config.rx_chain |= LE_16((RXON_RX_CHAIN_A_MSK |
6203 RXON_RX_CHAIN_B_MSK) <<
6204 RXON_RX_CHAIN_FORCE_MIMO_SEL_POS);
6205 }
6206
6207 sc->sc_config.rx_chain |= LE_16(RXON_RX_CHAIN_DRIVER_FORCE_MSK);
6208
6209 if ((in != NULL) &&
6210 (in->in_flags & IEEE80211_NODE_HT) &&
6211 sc->sc_ht_conf.ht_support) {
6212 if (3 == sc->sc_ht_conf.valid_chains) {
6213 sc->sc_config.rx_chain |= LE_16(3 <<
6214 RXON_RX_CHAIN_CNT_POS);
6215 sc->sc_config.rx_chain |= LE_16(3 <<
6216 RXON_RX_CHAIN_MIMO_CNT_POS);
6217 } else {
6218 sc->sc_config.rx_chain |= LE_16(2 <<
6219 RXON_RX_CHAIN_CNT_POS);
6220 sc->sc_config.rx_chain |= LE_16(2 <<
6221 RXON_RX_CHAIN_MIMO_CNT_POS);
6222 }
6223
6224 sc->sc_config.rx_chain |= LE_16(1 <<
6225 RXON_RX_CHAIN_MIMO_FORCE_POS);
6226 }
6227
6228 IWH_DBG((IWH_DEBUG_RXON, "iwh_config_rxon_chain(): "
6229 "rxon->rx_chain = %x\n", sc->sc_config.rx_chain));
6230 }
6231
6232 /*
6233 * This function adds AP station into hardware.
6234 */
6235 static int
6236 iwh_add_ap_sta(iwh_sc_t *sc)
6237 {
6238 ieee80211com_t *ic = &sc->sc_ic;
6239 ieee80211_node_t *in = ic->ic_bss;
6240 iwh_add_sta_t node;
6241 uint32_t ampdu_factor, ampdu_density;
6242 int err = IWH_FAIL;
6243
6244 /*
6245 * Add AP node into hardware.
6246 */
6247 (void) memset(&node, 0, sizeof (node));
6248 IEEE80211_ADDR_COPY(node.sta.addr, in->in_bssid);
6249 node.mode = STA_MODE_ADD_MSK;
6250 node.sta.sta_id = IWH_AP_ID;
6251
6252 if (sc->sc_ht_conf.ht_support &&
6253 (in->in_htcap_ie != NULL) &&
6254 (in->in_htcap != 0) &&
6255 (in->in_htparam != 0)) {
6256
6257 if (((in->in_htcap & HT_CAP_MIMO_PS) >> 2)
6258 == HT_CAP_MIMO_PS_DYNAMIC) {
6259 node.station_flags |= LE_32(STA_FLG_RTS_MIMO_PROT);
6260 }
6261
6262 ampdu_factor = in->in_htparam & HT_RX_AMPDU_FACTOR_MSK;
6263 node.station_flags |=
6264 LE_32(ampdu_factor << STA_FLG_MAX_AMPDU_POS);
6265
6266 ampdu_density = (in->in_htparam & HT_MPDU_DENSITY_MSK) >>
6267 HT_MPDU_DENSITY_POS;
6268 node.station_flags |=
6269 LE_32(ampdu_density << STA_FLG_AMPDU_DENSITY_POS);
6270
6271 if (in->in_htcap & LE_16(HT_CAP_SUP_WIDTH)) {
6272 node.station_flags |=
6273 LE_32(STA_FLG_FAT_EN);
6274 }
6275 }
6276
6277 err = iwh_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 1);
6278 if (err != IWH_SUCCESS) {
6279 cmn_err(CE_WARN, "iwh_add_ap_lq(): "
6280 "failed to add AP node\n");
6281 return (err);
6282 }
6283
6284 return (err);
6285 }
6286
6287 /*
6288 * Each station in the Shirley Peak's internal station table has
6289 * its own table of 16 TX rates and modulation modes for retrying
6290 * TX when an ACK is not received. This function replaces the entire
6291 * table for one station.Station must already be in Shirley Peak's
6292 * station talbe.
6293 */
6294 static int
6295 iwh_ap_lq(iwh_sc_t *sc)
6296 {
6297 ieee80211com_t *ic = &sc->sc_ic;
6298 ieee80211_node_t *in = ic->ic_bss;
6299 iwh_link_quality_cmd_t link_quality;
6300 const struct ieee80211_rateset *rs_sup = NULL;
6301 uint32_t masks = 0, rate;
6302 int i, err = IWH_FAIL;
6303
6304 /*
6305 * TX_LINK_QUALITY cmd
6306 */
6307 (void) memset(&link_quality, 0, sizeof (link_quality));
6308 if (in->in_chan == IEEE80211_CHAN_ANYC) /* skip null node */
6309 return (err);
6310 rs_sup = ieee80211_get_suprates(ic, in->in_chan);
6311
6312 for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
6313 if (i < rs_sup->ir_nrates) {
6314 rate = rs_sup->ir_rates[rs_sup->ir_nrates - i] &
6315 IEEE80211_RATE_VAL;
6316 } else {
6317 rate = 2;
6318 }
6319
6320 if (2 == rate || 4 == rate ||
6321 11 == rate || 22 == rate) {
6322 masks |= LE_32(RATE_MCS_CCK_MSK);
6323 }
6324
6325 masks |= LE_32(RATE_MCS_ANT_B_MSK);
6326
6327 link_quality.rate_n_flags[i] =
6328 LE_32(iwh_rate_to_plcp(rate) | masks);
6329 }
6330
6331 link_quality.general_params.single_stream_ant_msk = LINK_QUAL_ANT_B_MSK;
6332 link_quality.general_params.dual_stream_ant_msk = LINK_QUAL_ANT_MSK;
6333 link_quality.agg_params.agg_dis_start_th = 3;
6334 link_quality.agg_params.agg_time_limit = LE_16(4000);
6335 link_quality.sta_id = IWH_AP_ID;
6336 err = iwh_cmd(sc, REPLY_TX_LINK_QUALITY_CMD, &link_quality,
6337 sizeof (link_quality), 1);
6338 if (err != IWH_SUCCESS) {
6339 cmn_err(CE_WARN, "iwh_ap_lq(): "
6340 "failed to config link quality table\n");
6341 return (err);
6342 }
6343
6344 #ifdef DEBUG
6345 IWH_DBG((IWH_DEBUG_HWRATE, "iwh_ap_lq(): "
6346 "Rates in HW are as follows:\n"));
6347
6348 for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
6349 IWH_DBG((IWH_DEBUG_HWRATE,
6350 "Rate %d in HW is %x\n", i, link_quality.rate_n_flags[i]));
6351 }
6352 #endif
6353
6354 return (err);
6355 }
6356
6357 /*
6358 * When block ACK agreement has been set up between station and AP,
6359 * Net80211 module will call this function to inform hardware about
6360 * informations of this BA agreement.
6361 * When AP wants to delete BA agreement that was originated by it,
6362 * Net80211 modele will call this function to clean up relevant
6363 * information in hardware.
6364 */
6365 static void
6366 iwh_recv_action(struct ieee80211_node *in,
6367 const uint8_t *frm, const uint8_t *efrm)
6368 {
6369 struct ieee80211com *ic;
6370 iwh_sc_t *sc;
6371 const struct ieee80211_action *ia;
6372 uint16_t baparamset, baseqctl;
6373 uint32_t tid, ssn;
6374 iwh_add_sta_t node;
6375 int err = IWH_FAIL;
6376
6377 if ((NULL == in) || (NULL == frm)) {
6378 return;
6379 }
6380
6381 ic = in->in_ic;
6382 if (NULL == ic) {
6383 return;
6384 }
6385
6386 sc = (iwh_sc_t *)ic;
6387
6388 sc->sc_recv_action(in, frm, efrm);
6389
6390 ia = (const struct ieee80211_action *)frm;
6391 if (ia->ia_category != IEEE80211_ACTION_CAT_BA) {
6392 return;
6393 }
6394
6395 switch (ia->ia_action) {
6396 case IEEE80211_ACTION_BA_ADDBA_REQUEST:
6397 baparamset = *(uint16_t *)(frm + 3);
6398 baseqctl = *(uint16_t *)(frm + 7);
6399
6400 tid = MS(baparamset, IEEE80211_BAPS_TID);
6401 ssn = MS(baseqctl, IEEE80211_BASEQ_START);
6402
6403 (void) memset(&node, 0, sizeof (node));
6404 IEEE80211_ADDR_COPY(node.sta.addr, in->in_bssid);
6405 node.mode = STA_MODE_MODIFY_MSK;
6406 node.sta.sta_id = IWH_AP_ID;
6407
6408 node.station_flags_msk = 0;
6409 node.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK;
6410 node.add_immediate_ba_tid = (uint8_t)tid;
6411 node.add_immediate_ba_ssn = LE_16(ssn);
6412
6413 mutex_enter(&sc->sc_glock);
6414 err = iwh_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 1);
6415 if (err != IWH_SUCCESS) {
6416 cmn_err(CE_WARN, "iwh_recv_action(): "
6417 "failed to setup RX block ACK\n");
6418 mutex_exit(&sc->sc_glock);
6419 return;
6420 }
6421 mutex_exit(&sc->sc_glock);
6422
6423 IWH_DBG((IWH_DEBUG_BA, "iwh_recv_action(): "
6424 "RX block ACK "
6425 "was setup on TID %d and SSN is %d.\n", tid, ssn));
6426
6427 return;
6428
6429 case IEEE80211_ACTION_BA_DELBA:
6430 baparamset = *(uint16_t *)(frm + 2);
6431
6432 if ((baparamset & IEEE80211_DELBAPS_INIT) == 0) {
6433 return;
6434 }
6435
6436 tid = MS(baparamset, IEEE80211_DELBAPS_TID);
6437
6438 (void) memset(&node, 0, sizeof (node));
6439 IEEE80211_ADDR_COPY(node.sta.addr, in->in_bssid);
6440 node.mode = STA_MODE_MODIFY_MSK;
6441 node.sta.sta_id = IWH_AP_ID;
6442
6443 node.station_flags_msk = 0;
6444 node.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK;
6445 node.add_immediate_ba_tid = (uint8_t)tid;
6446
6447 mutex_enter(&sc->sc_glock);
6448 err = iwh_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 1);
6449 if (err != IWH_SUCCESS) {
6450 cmn_err(CE_WARN, "iwh_recv_action(): "
6451 "failed to delete RX block ACK\n");
6452 mutex_exit(&sc->sc_glock);
6453 return;
6454 }
6455 mutex_exit(&sc->sc_glock);
6456
6457 IWH_DBG((IWH_DEBUG_BA, "iwh_recv_action(): "
6458 "RX block ACK "
6459 "was deleted on TID %d.\n", tid));
6460
6461 return;
6462 }
6463 }
6464
6465 /*
6466 * When local station wants to delete BA agreement that was originated by AP,
6467 * Net80211 module will call this function to clean up relevant information
6468 * in hardware.
6469 */
6470 static int
6471 iwh_send_action(struct ieee80211_node *in,
6472 int category, int action, uint16_t args[4])
6473 {
6474 struct ieee80211com *ic;
6475 iwh_sc_t *sc;
6476 uint32_t tid;
6477 iwh_add_sta_t node;
6478 int ret = EIO;
6479 int err = IWH_FAIL;
6480
6481
6482 if (NULL == in) {
6483 return (ret);
6484 }
6485
6486 ic = in->in_ic;
6487 if (NULL == ic) {
6488 return (ret);
6489 }
6490
6491 sc = (iwh_sc_t *)ic;
6492
6493 ret = sc->sc_send_action(in, category, action, args);
6494
6495 if (category != IEEE80211_ACTION_CAT_BA) {
6496 return (ret);
6497 }
6498
6499 switch (action) {
6500 case IEEE80211_ACTION_BA_DELBA:
6501 if (IEEE80211_DELBAPS_INIT == args[1]) {
6502 return (ret);
6503 }
6504
6505 tid = args[0];
6506
6507 (void) memset(&node, 0, sizeof (node));
6508 IEEE80211_ADDR_COPY(node.sta.addr, in->in_bssid);
6509 node.mode = STA_MODE_MODIFY_MSK;
6510 node.sta.sta_id = IWH_AP_ID;
6511
6512 node.station_flags_msk = 0;
6513 node.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK;
6514 node.add_immediate_ba_tid = (uint8_t)tid;
6515
6516 mutex_enter(&sc->sc_glock);
6517 err = iwh_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 1);
6518 if (err != IWH_SUCCESS) {
6519 cmn_err(CE_WARN, "iwh_send_action(): "
6520 "failed to delete RX balock ACK\n");
6521 mutex_exit(&sc->sc_glock);
6522 return (EIO);
6523 }
6524 mutex_exit(&sc->sc_glock);
6525
6526 IWH_DBG((IWH_DEBUG_BA, "iwh_send_action(): "
6527 "RX block ACK "
6528 "was deleted on TID %d.\n", tid));
6529
6530 break;
6531 }
6532
6533 return (ret);
6534 }
6535
6536 static int
6537 iwh_reset_hw(iwh_sc_t *sc)
6538 {
6539 uint32_t tmp;
6540 int n;
6541
6542 tmp = IWH_READ(sc, CSR_HW_IF_CONFIG_REG);
6543 IWH_WRITE(sc, CSR_HW_IF_CONFIG_REG,
6544 tmp | CSR_HW_IF_CONFIG_REG_BITS_NIC_READY);
6545
6546 /*
6547 * wait for HW ready
6548 */
6549 for (n = 0; n < 5; n++) {
6550 if (IWH_READ(sc, CSR_HW_IF_CONFIG_REG) &
6551 CSR_HW_IF_CONFIG_REG_BITS_NIC_READY) {
6552 break;
6553 }
6554 DELAY(10);
6555 }
6556
6557 if (n != 5) {
6558 return (IWH_SUCCESS);
6559 }
6560
6561 tmp = IWH_READ(sc, CSR_HW_IF_CONFIG_REG);
6562 IWH_WRITE(sc, CSR_HW_IF_CONFIG_REG,
6563 tmp | CSR_HW_IF_CONFIG_REG_BITS_PREPARE);
6564
6565 for (n = 0; n < 15000; n++) {
6566 if (0 == (IWH_READ(sc, CSR_HW_IF_CONFIG_REG) &
6567 CSR_HW_IF_CONFIG_REG_BITS_NIC_PREPARE_DONE)) {
6568 break;
6569 }
6570 DELAY(10);
6571 }
6572
6573 if (15000 == n) {
6574 return (ETIMEDOUT);
6575 }
6576
6577 tmp = IWH_READ(sc, CSR_HW_IF_CONFIG_REG);
6578 IWH_WRITE(sc, CSR_HW_IF_CONFIG_REG,
6579 tmp | CSR_HW_IF_CONFIG_REG_BITS_NIC_READY);
6580
6581 /*
6582 * wait for HW ready
6583 */
6584 for (n = 0; n < 5; n++) {
6585 if (IWH_READ(sc, CSR_HW_IF_CONFIG_REG) &
6586 CSR_HW_IF_CONFIG_REG_BITS_NIC_READY) {
6587 break;
6588 }
6589 DELAY(10);
6590 }
6591
6592 if (n != 5) {
6593 return (IWH_SUCCESS);
6594 } else {
6595 return (ETIMEDOUT);
6596 }
6597 }