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