1 /* $OpenBSD: if_atw_cardbus.c,v 1.25 2022/04/06 18:59:28 naddy Exp $ */
2 /* $NetBSD: if_atw_cardbus.c,v 1.9 2004/07/23 07:07:55 dyoung Exp $ */
3
4 /*-
5 * Copyright (c) 1999, 2000, 2003 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10 * NASA Ames Research Center. This code was adapted for the ADMtek ADM8211
11 * by David Young.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 /*
36 * CardBus bus front-end for the ADMtek ADM8211 802.11 MAC/BBP driver.
37 */
38
39 #include "bpfilter.h"
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/mbuf.h>
44 #include <sys/malloc.h>
45 #include <sys/kernel.h>
46 #include <sys/socket.h>
47 #include <sys/ioctl.h>
48 #include <sys/errno.h>
49 #include <sys/device.h>
50 #include <sys/endian.h>
51
52 #include <net/if.h>
53 #include <net/if_media.h>
54
55 #include <netinet/in.h>
56 #include <netinet/if_ether.h>
57
58 #include <net80211/ieee80211_radiotap.h>
59 #include <net80211/ieee80211_var.h>
60
61 #if NBPFILTER > 0
62 #include <net/bpf.h>
63 #endif
64
65 #include <machine/bus.h>
66 #include <machine/intr.h>
67
68 #include <dev/ic/atwreg.h>
69 #include <dev/ic/si4136reg.h>
70 #include <dev/ic/atwvar.h>
71
72 #include <dev/pci/pcivar.h>
73 #include <dev/pci/pcireg.h>
74 #include <dev/pci/pcidevs.h>
75
76 #include <dev/cardbus/cardbusvar.h>
77
78 /*
79 * PCI configuration space registers used by the ADM8211.
80 */
81 #define ATW_PCI_IOBA 0x10 /* i/o mapped base */
82 #define ATW_PCI_MMBA 0x14 /* memory mapped base */
83
84 struct atw_cardbus_softc {
85 struct atw_softc sc_atw; /* real ADM8211 softc */
86
87 /* CardBus-specific goo. */
88 void *sc_ih; /* interrupt handle */
89 cardbus_devfunc_t sc_ct; /* our CardBus devfuncs */
90 pcitag_t sc_tag; /* our CardBus tag */
91 int sc_csr; /* CSR bits */
92 bus_size_t sc_mapsize; /* the size of mapped bus space
93 region */
94
95 int sc_cben; /* CardBus enables */
96 int sc_bar_reg; /* which BAR to use */
97 pcireg_t sc_bar_val; /* value of the BAR */
98
99 int sc_intrline; /* interrupt line */
100 pci_chipset_tag_t sc_pc;
101 };
102
103 int atw_cardbus_match(struct device *, void *, void *);
104 void atw_cardbus_attach(struct device *, struct device *, void *);
105 int atw_cardbus_detach(struct device *, int);
106
107 const struct cfattach atw_cardbus_ca = {
108 sizeof(struct atw_cardbus_softc), atw_cardbus_match, atw_cardbus_attach,
109 atw_cardbus_detach
110 };
111
112 void atw_cardbus_setup(struct atw_cardbus_softc *);
113
114 int atw_cardbus_enable(struct atw_softc *);
115 void atw_cardbus_disable(struct atw_softc *);
116 void atw_cardbus_power(struct atw_softc *, int);
117
118 const struct pci_matchid atw_cardbus_devices[] = {
119 { PCI_VENDOR_ADMTEK, PCI_PRODUCT_ADMTEK_ADM8211 },
120 { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3CRSHPW796 },
121 };
122
123 int
124 atw_cardbus_match(struct device *parent, void *match, void *aux)
125 {
126 return (cardbus_matchbyid((struct cardbus_attach_args *)aux,
127 atw_cardbus_devices, nitems(atw_cardbus_devices)));
128 }
129
130 void
131 atw_cardbus_attach(struct device *parent, struct device *self, void *aux)
132 {
133 struct atw_cardbus_softc *csc = (void *)self;
134 struct atw_softc *sc = &csc->sc_atw;
135 struct cardbus_attach_args *ca = aux;
136 cardbus_devfunc_t ct = ca->ca_ct;
137 bus_addr_t adr;
138
139 sc->sc_dmat = ca->ca_dmat;
140 csc->sc_ct = ct;
141 csc->sc_tag = ca->ca_tag;
142 csc->sc_pc = ca->ca_pc;
143
144 /*
145 * Power management hooks.
146 */
147 sc->sc_enable = atw_cardbus_enable;
148 sc->sc_disable = atw_cardbus_disable;
149 sc->sc_power = atw_cardbus_power;
150
151 /* Get revision info. */
152 sc->sc_rev = PCI_REVISION(ca->ca_class);
153
154 #if 0
155 printf(": signature %08x\n%s",
156 pci_conf_read(ca->ca_pc, csc->sc_tag, 0x80),
157 sc->sc_dev.dv_xname);
158 #endif
159
160 /*
161 * Map the device.
162 */
163 csc->sc_csr = PCI_COMMAND_MASTER_ENABLE;
164 if (Cardbus_mapreg_map(ct, ATW_PCI_MMBA,
165 PCI_MAPREG_TYPE_MEM, 0, &sc->sc_st, &sc->sc_sh, &adr,
166 &csc->sc_mapsize) == 0) {
167 #if 0
168 printf(": atw_cardbus_attach mapped %d bytes mem space\n%s",
169 csc->sc_mapsize, sc->sc_dev.dv_xname);
170 #endif
171 csc->sc_cben = CARDBUS_MEM_ENABLE;
172 csc->sc_csr |= PCI_COMMAND_MEM_ENABLE;
173 csc->sc_bar_reg = ATW_PCI_MMBA;
174 csc->sc_bar_val = adr | PCI_MAPREG_TYPE_MEM;
175 } else if (Cardbus_mapreg_map(ct, ATW_PCI_IOBA,
176 PCI_MAPREG_TYPE_IO, 0, &sc->sc_st, &sc->sc_sh, &adr,
177 &csc->sc_mapsize) == 0) {
178 #if 0
179 printf(": atw_cardbus_attach mapped %d bytes I/O space\n%s",
180 csc->sc_mapsize, sc->sc_dev.dv_xname);
181 #endif
182 csc->sc_cben = CARDBUS_IO_ENABLE;
183 csc->sc_csr |= PCI_COMMAND_IO_ENABLE;
184 csc->sc_bar_reg = ATW_PCI_IOBA;
185 csc->sc_bar_val = adr | PCI_MAPREG_TYPE_IO;
186 } else {
187 printf(": unable to map device registers\n");
188 return;
189 }
190
191 /*
192 * Bring the chip out of powersave mode and initialize the
193 * configuration registers.
194 */
195 atw_cardbus_setup(csc);
196
197 /* Remember which interrupt line. */
198 csc->sc_intrline = ca->ca_intrline;
199
200 printf(": revision %d.%d: irq %d\n",
201 (sc->sc_rev >> 4) & 0xf, sc->sc_rev & 0xf, csc->sc_intrline);
202 #if 0
203 /*
204 * The CardBus cards will make it to store-and-forward mode as
205 * soon as you put them under any kind of load, so just start
206 * out there.
207 */
208 sc->sc_txthresh = 3; /* TBD name constant */
209 #endif
210
211 /*
212 * Finish off the attach.
213 */
214 atw_attach(sc);
215
216 ATW_WRITE(sc, ATW_FER, ATW_FER_INTR);
217
218 /*
219 * Power down the socket.
220 */
221 Cardbus_function_disable(csc->sc_ct);
222 }
223
224 int
225 atw_cardbus_detach(struct device *self, int flags)
226 {
227 struct atw_cardbus_softc *csc = (void *)self;
228 struct atw_softc *sc = &csc->sc_atw;
229 struct cardbus_devfunc *ct = csc->sc_ct;
230 int rv;
231
232 #if defined(DIAGNOSTIC)
233 if (ct == NULL)
234 panic("%s: data structure lacks", sc->sc_dev.dv_xname);
235 #endif
236
237 rv = atw_detach(sc);
238 if (rv)
239 return (rv);
240
241 /*
242 * Unhook the interrupt handler.
243 */
244 if (csc->sc_ih != NULL)
245 cardbus_intr_disestablish(ct->ct_cc, ct->ct_cf, csc->sc_ih);
246
247 /*
248 * Release bus space and close window.
249 */
250 if (csc->sc_bar_reg != 0)
251 Cardbus_mapreg_unmap(ct, csc->sc_bar_reg,
252 sc->sc_st, sc->sc_sh, csc->sc_mapsize);
253
254 return (0);
255 }
256
257 int
258 atw_cardbus_enable(struct atw_softc *sc)
259 {
260 struct atw_cardbus_softc *csc = (void *) sc;
261 cardbus_devfunc_t ct = csc->sc_ct;
262 cardbus_chipset_tag_t cc = ct->ct_cc;
263 cardbus_function_tag_t cf = ct->ct_cf;
264
265 /*
266 * Power on the socket.
267 */
268 Cardbus_function_enable(ct);
269
270 /*
271 * Set up the PCI configuration registers.
272 */
273 atw_cardbus_setup(csc);
274
275 /*
276 * Map and establish the interrupt.
277 */
278 csc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline, IPL_NET,
279 atw_intr, sc, sc->sc_dev.dv_xname);
280 if (csc->sc_ih == NULL) {
281 printf("%s: unable to establish interrupt at %d\n",
282 sc->sc_dev.dv_xname, csc->sc_intrline);
283 Cardbus_function_disable(csc->sc_ct);
284 return (1);
285 }
286
287 return (0);
288 }
289
290 void
291 atw_cardbus_disable(struct atw_softc *sc)
292 {
293 struct atw_cardbus_softc *csc = (void *) sc;
294 cardbus_devfunc_t ct = csc->sc_ct;
295 cardbus_chipset_tag_t cc = ct->ct_cc;
296 cardbus_function_tag_t cf = ct->ct_cf;
297
298 /* Unhook the interrupt handler. */
299 cardbus_intr_disestablish(cc, cf, csc->sc_ih);
300 csc->sc_ih = NULL;
301
302 /* Power down the socket. */
303 Cardbus_function_disable(ct);
304 }
305
306 void
307 atw_cardbus_power(struct atw_softc *sc, int why)
308 {
309 if (why == DVACT_RESUME)
310 atw_enable(sc);
311 }
312
313 void
314 atw_cardbus_setup(struct atw_cardbus_softc *csc)
315 {
316 #ifdef notyet
317 struct atw_softc *sc = &csc->sc_atw;
318 #endif
319 cardbus_devfunc_t ct = csc->sc_ct;
320 cardbus_chipset_tag_t cc = ct->ct_cc;
321 pci_chipset_tag_t pc = csc->sc_pc;
322 pcireg_t reg;
323
324 #ifdef notyet
325 (void)cardbus_setpowerstate(sc->sc_dev.dv_xname, ct, csc->sc_tag,
326 PCI_PWR_D0);
327 #endif
328
329 /* Program the BAR. */
330 pci_conf_write(pc, csc->sc_tag, csc->sc_bar_reg,
331 csc->sc_bar_val);
332
333 /* Make sure the right access type is on the CardBus bridge. */
334 (*ct->ct_cf->cardbus_ctrl)(cc, csc->sc_cben);
335 (*ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);
336
337 /* Enable the appropriate bits in the PCI CSR. */
338 reg = pci_conf_read(pc, csc->sc_tag,
339 PCI_COMMAND_STATUS_REG);
340 reg &= ~(PCI_COMMAND_IO_ENABLE|PCI_COMMAND_MEM_ENABLE);
341 reg |= csc->sc_csr;
342 pci_conf_write(pc, csc->sc_tag, PCI_COMMAND_STATUS_REG,
343 reg);
344
345 /*
346 * Make sure the latency timer is set to some reasonable
347 * value.
348 */
349 reg = pci_conf_read(pc, csc->sc_tag, PCI_BHLC_REG);
350 if (PCI_LATTIMER(reg) < 0x20) {
351 reg &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT);
352 reg |= (0x20 << PCI_LATTIMER_SHIFT);
353 pci_conf_write(pc, csc->sc_tag, PCI_BHLC_REG, reg);
354 }
355 }
Cache object: 66c0a526eb09a317312f2ca8bd6f219e
|