if_atw_cardbus.c revision 1.3 1 /* $NetBSD: if_atw_cardbus.c,v 1.3 2003/11/16 09:02:42 dyoung Exp $ */
2
3 /*-
4 * Copyright (c) 1999, 2000, 2003 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center. This code was adapted for the ADMtek ADM8211
10 * by David Young.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the NetBSD
23 * Foundation, Inc. and its contributors.
24 * 4. Neither the name of The NetBSD Foundation nor the names of its
25 * contributors may be used to endorse or promote products derived
26 * from this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 */
40
41 /*
42 * CardBus bus front-end for the ADMtek ADM8211 802.11 MAC/BBP driver.
43 */
44
45 #include <sys/cdefs.h>
46 __KERNEL_RCSID(0, "$NetBSD: if_atw_cardbus.c,v 1.3 2003/11/16 09:02:42 dyoung Exp $");
47
48 #include "opt_inet.h"
49 #include "opt_ns.h"
50 #include "bpfilter.h"
51
52 #include <sys/param.h>
53 #include <sys/systm.h>
54 #include <sys/mbuf.h>
55 #include <sys/malloc.h>
56 #include <sys/kernel.h>
57 #include <sys/socket.h>
58 #include <sys/ioctl.h>
59 #include <sys/errno.h>
60 #include <sys/device.h>
61
62 #include <machine/endian.h>
63
64 #include <net/if.h>
65 #include <net/if_dl.h>
66 #include <net/if_media.h>
67 #include <net/if_ether.h>
68
69 #include <net80211/ieee80211_compat.h>
70 #include <net80211/ieee80211_radiotap.h>
71 #include <net80211/ieee80211_var.h>
72
73 #if NBPFILTER > 0
74 #include <net/bpf.h>
75 #endif
76
77 #ifdef INET
78 #include <netinet/in.h>
79 #include <netinet/if_inarp.h>
80 #endif
81
82 #ifdef NS
83 #include <netns/ns.h>
84 #include <netns/ns_if.h>
85 #endif
86
87 #include <machine/bus.h>
88 #include <machine/intr.h>
89
90 #include <dev/mii/miivar.h>
91 #include <dev/mii/mii_bitbang.h>
92
93 #include <dev/ic/atwreg.h>
94 #include <dev/ic/atwvar.h>
95
96 #include <dev/pci/pcivar.h>
97 #include <dev/pci/pcireg.h>
98 #include <dev/pci/pcidevs.h>
99
100 #include <dev/cardbus/cardbusvar.h>
101 #include <dev/cardbus/cardbusdevs.h>
102
103 /*
104 * PCI configuration space registers used by the ADM8211.
105 */
106 #define ATW_PCI_IOBA 0x10 /* i/o mapped base */
107 #define ATW_PCI_MMBA 0x14 /* memory mapped base */
108
109 struct atw_cardbus_softc {
110 struct atw_softc sc_atw; /* real ADM8211 softc */
111
112 /* CardBus-specific goo. */
113 void *sc_ih; /* interrupt handle */
114 cardbus_devfunc_t sc_ct; /* our CardBus devfuncs */
115 cardbustag_t sc_tag; /* our CardBus tag */
116 int sc_csr; /* CSR bits */
117 bus_size_t sc_mapsize; /* the size of mapped bus space
118 region */
119
120 int sc_cben; /* CardBus enables */
121 int sc_bar_reg; /* which BAR to use */
122 pcireg_t sc_bar_val; /* value of the BAR */
123
124 int sc_intrline; /* interrupt line */
125 };
126
127 int atw_cardbus_match __P((struct device *, struct cfdata *, void *));
128 void atw_cardbus_attach __P((struct device *, struct device *, void *));
129 int atw_cardbus_detach __P((struct device *, int));
130
131 CFATTACH_DECL(atw_cardbus, sizeof(struct atw_cardbus_softc),
132 atw_cardbus_match, atw_cardbus_attach, atw_cardbus_detach, atw_activate);
133
134 void atw_cardbus_setup __P((struct atw_cardbus_softc *));
135
136 int atw_cardbus_enable __P((struct atw_softc *));
137 void atw_cardbus_disable __P((struct atw_softc *));
138 void atw_cardbus_power __P((struct atw_softc *, int));
139
140 static void atw_cardbus_intr_ack(struct atw_softc *);
141
142 const struct atw_cardbus_product *atw_cardbus_lookup
143 __P((const struct cardbus_attach_args *));
144
145 const struct atw_cardbus_product {
146 u_int32_t acp_vendor; /* PCI vendor ID */
147 u_int32_t acp_product; /* PCI product ID */
148 const char *acp_product_name;
149 } atw_cardbus_products[] = {
150 { PCI_VENDOR_ADMTEK, PCI_PRODUCT_ADMTEK_ADM8211,
151 "ADMtek ADM8211 802.11 MAC/BBP" },
152
153 { 0, 0, NULL },
154 };
155
156 const struct atw_cardbus_product *
157 atw_cardbus_lookup(ca)
158 const struct cardbus_attach_args *ca;
159 {
160 const struct atw_cardbus_product *acp;
161
162 for (acp = atw_cardbus_products;
163 acp->acp_product_name != NULL;
164 acp++) {
165 if (PCI_VENDOR(ca->ca_id) == acp->acp_vendor &&
166 PCI_PRODUCT(ca->ca_id) == acp->acp_product)
167 return (acp);
168 }
169 return (NULL);
170 }
171
172 int
173 atw_cardbus_match(parent, match, aux)
174 struct device *parent;
175 struct cfdata *match;
176 void *aux;
177 {
178 struct cardbus_attach_args *ca = aux;
179
180 if (atw_cardbus_lookup(ca) != NULL)
181 return (1);
182
183 return (0);
184 }
185
186 void
187 atw_cardbus_attach(parent, self, aux)
188 struct device *parent, *self;
189 void *aux;
190 {
191 struct atw_cardbus_softc *csc = (void *)self;
192 struct atw_softc *sc = &csc->sc_atw;
193 struct cardbus_attach_args *ca = aux;
194 cardbus_devfunc_t ct = ca->ca_ct;
195 const struct atw_cardbus_product *acp;
196 bus_addr_t adr;
197 int rev;
198
199 sc->sc_dmat = ca->ca_dmat;
200 csc->sc_ct = ct;
201 csc->sc_tag = ca->ca_tag;
202
203 acp = atw_cardbus_lookup(ca);
204 if (acp == NULL) {
205 printf("\n");
206 panic("atw_cardbus_attach: impossible");
207 }
208
209 /*
210 * Power management hooks.
211 */
212 sc->sc_enable = atw_cardbus_enable;
213 sc->sc_disable = atw_cardbus_disable;
214 sc->sc_power = atw_cardbus_power;
215
216 sc->sc_intr_ack = atw_cardbus_intr_ack;
217
218 /* Get revision info. */
219 rev = PCI_REVISION(ca->ca_class);
220
221 printf(": %s\n", acp->acp_product_name);
222
223 #if 0
224 printf("%s: pass %d.%d signature %08x\n", sc->sc_dev.dv_xname,
225 (rev >> 4) & 0xf, rev & 0xf,
226 cardbus_conf_read(ct->ct_cc, ct->ct_cf, csc->sc_tag, 0x80));
227 #endif
228
229 /*
230 * Map the device.
231 */
232 csc->sc_csr = CARDBUS_COMMAND_MASTER_ENABLE;
233 if (Cardbus_mapreg_map(ct, ATW_PCI_MMBA,
234 CARDBUS_MAPREG_TYPE_MEM, 0, &sc->sc_st, &sc->sc_sh, &adr,
235 &csc->sc_mapsize) == 0) {
236 #if 0
237 printf("%s: atw_cardbus_attach mapped %d bytes mem space\n",
238 sc->sc_dev.dv_xname, csc->sc_mapsize);
239 #endif
240 #if rbus
241 #else
242 (*ct->ct_cf->cardbus_mem_open)(cc, 0, adr, adr+csc->sc_mapsize);
243 #endif
244 csc->sc_cben = CARDBUS_MEM_ENABLE;
245 csc->sc_csr |= CARDBUS_COMMAND_MEM_ENABLE;
246 csc->sc_bar_reg = ATW_PCI_MMBA;
247 csc->sc_bar_val = adr | CARDBUS_MAPREG_TYPE_MEM;
248 } else if (Cardbus_mapreg_map(ct, ATW_PCI_IOBA,
249 CARDBUS_MAPREG_TYPE_IO, 0, &sc->sc_st, &sc->sc_sh, &adr,
250 &csc->sc_mapsize) == 0) {
251 #if 0
252 printf("%s: atw_cardbus_attach mapped %d bytes I/O space\n",
253 sc->sc_dev.dv_xname, csc->sc_mapsize);
254 #endif
255 #if rbus
256 #else
257 (*ct->ct_cf->cardbus_io_open)(cc, 0, adr, adr+csc->sc_mapsize);
258 #endif
259 csc->sc_cben = CARDBUS_IO_ENABLE;
260 csc->sc_csr |= CARDBUS_COMMAND_IO_ENABLE;
261 csc->sc_bar_reg = ATW_PCI_IOBA;
262 csc->sc_bar_val = adr | CARDBUS_MAPREG_TYPE_IO;
263 } else {
264 printf("%s: unable to map device registers\n",
265 sc->sc_dev.dv_xname);
266 return;
267 }
268
269 /*
270 * Bring the chip out of powersave mode and initialize the
271 * configuration registers.
272 */
273 atw_cardbus_setup(csc);
274
275 /* Remember which interrupt line. */
276 csc->sc_intrline = ca->ca_intrline;
277
278 printf("%s: interrupting at %d\n", sc->sc_dev.dv_xname,
279 csc->sc_intrline);
280 #if 0
281 /*
282 * The CardBus cards will make it to store-and-forward mode as
283 * soon as you put them under any kind of load, so just start
284 * out there.
285 */
286 sc->sc_txthresh = 3; /* TBD name constant */
287 #endif
288
289 /*
290 * Finish off the attach.
291 */
292 atw_attach(sc);
293
294 ATW_WRITE(sc, ATW_FER, ATW_FER_INTR);
295
296 /*
297 * Power down the socket.
298 */
299 Cardbus_function_disable(csc->sc_ct);
300 }
301
302 static void
303 atw_cardbus_intr_ack(sc)
304 struct atw_softc *sc;
305 {
306 ATW_WRITE(sc, ATW_FER, ATW_FER_INTR);
307 }
308
309 int
310 atw_cardbus_detach(self, flags)
311 struct device *self;
312 int flags;
313 {
314 struct atw_cardbus_softc *csc = (void *)self;
315 struct atw_softc *sc = &csc->sc_atw;
316 struct cardbus_devfunc *ct = csc->sc_ct;
317 int rv;
318
319 #if defined(DIAGNOSTIC)
320 if (ct == NULL)
321 panic("%s: data structure lacks", sc->sc_dev.dv_xname);
322 #endif
323
324 rv = atw_detach(sc);
325 if (rv)
326 return (rv);
327
328 /*
329 * Unhook the interrupt handler.
330 */
331 if (csc->sc_ih != NULL)
332 cardbus_intr_disestablish(ct->ct_cc, ct->ct_cf, csc->sc_ih);
333
334 /*
335 * Release bus space and close window.
336 */
337 if (csc->sc_bar_reg != 0)
338 Cardbus_mapreg_unmap(ct, csc->sc_bar_reg,
339 sc->sc_st, sc->sc_sh, csc->sc_mapsize);
340
341 return (0);
342 }
343
344 int
345 atw_cardbus_enable(sc)
346 struct atw_softc *sc;
347 {
348 struct atw_cardbus_softc *csc = (void *) sc;
349 cardbus_devfunc_t ct = csc->sc_ct;
350 cardbus_chipset_tag_t cc = ct->ct_cc;
351 cardbus_function_tag_t cf = ct->ct_cf;
352
353 /*
354 * Power on the socket.
355 */
356 Cardbus_function_enable(ct);
357
358 /*
359 * Set up the PCI configuration registers.
360 */
361 atw_cardbus_setup(csc);
362
363 /*
364 * Map and establish the interrupt.
365 */
366 csc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline, IPL_NET,
367 atw_intr, sc);
368 if (csc->sc_ih == NULL) {
369 printf("%s: unable to establish interrupt at %d\n",
370 sc->sc_dev.dv_xname, csc->sc_intrline);
371 Cardbus_function_disable(csc->sc_ct);
372 return (1);
373 }
374
375 return (0);
376 }
377
378 void
379 atw_cardbus_disable(sc)
380 struct atw_softc *sc;
381 {
382 struct atw_cardbus_softc *csc = (void *) sc;
383 cardbus_devfunc_t ct = csc->sc_ct;
384 cardbus_chipset_tag_t cc = ct->ct_cc;
385 cardbus_function_tag_t cf = ct->ct_cf;
386
387 /* Unhook the interrupt handler. */
388 cardbus_intr_disestablish(cc, cf, csc->sc_ih);
389 csc->sc_ih = NULL;
390
391 /* Power down the socket. */
392 Cardbus_function_disable(ct);
393 }
394
395 void
396 atw_cardbus_power(sc, why)
397 struct atw_softc *sc;
398 int why;
399 {
400 struct atw_cardbus_softc *csc = (void *) sc;
401
402 printf("%s: atw_cardbus_power\n", sc->sc_dev.dv_xname);
403
404 if (why == PWR_RESUME) {
405 /*
406 * Give the PCI configuration registers a kick
407 * in the head.
408 */
409 #ifdef DIAGNOSTIC
410 if (ATW_IS_ENABLED(sc) == 0)
411 panic("atw_cardbus_power");
412 #endif
413 atw_cardbus_setup(csc);
414 }
415 }
416
417 void
418 atw_cardbus_setup(csc)
419 struct atw_cardbus_softc *csc;
420 {
421 struct atw_softc *sc = &csc->sc_atw;
422 cardbus_devfunc_t ct = csc->sc_ct;
423 cardbus_chipset_tag_t cc = ct->ct_cc;
424 cardbus_function_tag_t cf = ct->ct_cf;
425 pcireg_t reg;
426 int pmreg;
427
428 if (cardbus_get_capability(cc, cf, csc->sc_tag,
429 PCI_CAP_PWRMGMT, &pmreg, 0)) {
430 reg = cardbus_conf_read(cc, cf, csc->sc_tag, pmreg + 4) & 0x03;
431 #if 1 /* XXX Probably not right for CardBus. */
432 if (reg == 3) {
433 /*
434 * The card has lost all configuration data in
435 * this state, so punt.
436 */
437 printf("%s: unable to wake up from power state D3\n",
438 sc->sc_dev.dv_xname);
439 return;
440 }
441 #endif
442 if (reg != 0) {
443 printf("%s: waking up from power state D%d\n",
444 sc->sc_dev.dv_xname, reg);
445 cardbus_conf_write(cc, cf, csc->sc_tag,
446 pmreg + 4, 0);
447 }
448 }
449
450 /* Make sure the right access type is on the CardBus bridge. */
451 (*ct->ct_cf->cardbus_ctrl)(cc, csc->sc_cben);
452 (*ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);
453
454 /* Program the BAR. */
455 cardbus_conf_write(cc, cf, csc->sc_tag, csc->sc_bar_reg,
456 csc->sc_bar_val);
457
458 /* Enable the appropriate bits in the PCI CSR. */
459 reg = cardbus_conf_read(cc, cf, csc->sc_tag,
460 CARDBUS_COMMAND_STATUS_REG);
461 reg &= ~(CARDBUS_COMMAND_IO_ENABLE|CARDBUS_COMMAND_MEM_ENABLE);
462 reg |= csc->sc_csr;
463 cardbus_conf_write(cc, cf, csc->sc_tag, CARDBUS_COMMAND_STATUS_REG,
464 reg);
465
466 /*
467 * Make sure the latency timer is set to some reasonable
468 * value.
469 */
470 reg = cardbus_conf_read(cc, cf, csc->sc_tag, CARDBUS_BHLC_REG);
471 if (CARDBUS_LATTIMER(reg) < 0x20) {
472 reg &= ~(CARDBUS_LATTIMER_MASK << CARDBUS_LATTIMER_SHIFT);
473 reg |= (0x20 << CARDBUS_LATTIMER_SHIFT);
474 cardbus_conf_write(cc, cf, csc->sc_tag, CARDBUS_BHLC_REG, reg);
475 }
476 }
477
478