1 /* $OpenBSD: if_atw_cardbus.c,v 1.26 2024/05/24 06:26:47 jsg 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/device.h>
44
45 #include <net/if.h>
46 #include <net/if_media.h>
47
48 #include <netinet/in.h>
49 #include <netinet/if_ether.h>
50
51 #include <net80211/ieee80211_radiotap.h>
52 #include <net80211/ieee80211_var.h>
53
54 #include <machine/bus.h>
55
56 #include <dev/ic/atwreg.h>
57 #include <dev/ic/atwvar.h>
58
59 #include <dev/pci/pcivar.h>
60 #include <dev/pci/pcireg.h>
61 #include <dev/pci/pcidevs.h>
62
63 #include <dev/cardbus/cardbusvar.h>
64
65 /*
66 * PCI configuration space registers used by the ADM8211.
67 */
68 #define ATW_PCI_IOBA 0x10 /* i/o mapped base */
69 #define ATW_PCI_MMBA 0x14 /* memory mapped base */
70
71 struct atw_cardbus_softc {
72 struct atw_softc sc_atw; /* real ADM8211 softc */
73
74 /* CardBus-specific goo. */
75 void *sc_ih; /* interrupt handle */
76 cardbus_devfunc_t sc_ct; /* our CardBus devfuncs */
77 pcitag_t sc_tag; /* our CardBus tag */
78 int sc_csr; /* CSR bits */
79 bus_size_t sc_mapsize; /* the size of mapped bus space
80 region */
81
82 int sc_cben; /* CardBus enables */
83 int sc_bar_reg; /* which BAR to use */
84 pcireg_t sc_bar_val; /* value of the BAR */
85
86 int sc_intrline; /* interrupt line */
87 pci_chipset_tag_t sc_pc;
88 };
89
90 int atw_cardbus_match(struct device *, void *, void *);
91 void atw_cardbus_attach(struct device *, struct device *, void *);
92 int atw_cardbus_detach(struct device *, int);
93
94 const struct cfattach atw_cardbus_ca = {
95 sizeof(struct atw_cardbus_softc), atw_cardbus_match, atw_cardbus_attach,
96 atw_cardbus_detach
97 };
98
99 void atw_cardbus_setup(struct atw_cardbus_softc *);
100
101 int atw_cardbus_enable(struct atw_softc *);
102 void atw_cardbus_disable(struct atw_softc *);
103 void atw_cardbus_power(struct atw_softc *, int);
104
105 const struct pci_matchid atw_cardbus_devices[] = {
106 { PCI_VENDOR_ADMTEK, PCI_PRODUCT_ADMTEK_ADM8211 },
107 { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3CRSHPW796 },
108 };
109
110 int
atw_cardbus_match(struct device * parent,void * match,void * aux)111 atw_cardbus_match(struct device *parent, void *match, void *aux)
112 {
113 return (cardbus_matchbyid((struct cardbus_attach_args *)aux,
114 atw_cardbus_devices, nitems(atw_cardbus_devices)));
115 }
116
117 void
atw_cardbus_attach(struct device * parent,struct device * self,void * aux)118 atw_cardbus_attach(struct device *parent, struct device *self, void *aux)
119 {
120 struct atw_cardbus_softc *csc = (void *)self;
121 struct atw_softc *sc = &csc->sc_atw;
122 struct cardbus_attach_args *ca = aux;
123 cardbus_devfunc_t ct = ca->ca_ct;
124 bus_addr_t adr;
125
126 sc->sc_dmat = ca->ca_dmat;
127 csc->sc_ct = ct;
128 csc->sc_tag = ca->ca_tag;
129 csc->sc_pc = ca->ca_pc;
130
131 /*
132 * Power management hooks.
133 */
134 sc->sc_enable = atw_cardbus_enable;
135 sc->sc_disable = atw_cardbus_disable;
136 sc->sc_power = atw_cardbus_power;
137
138 /* Get revision info. */
139 sc->sc_rev = PCI_REVISION(ca->ca_class);
140
141 #if 0
142 printf(": signature %08x\n%s",
143 pci_conf_read(ca->ca_pc, csc->sc_tag, 0x80),
144 sc->sc_dev.dv_xname);
145 #endif
146
147 /*
148 * Map the device.
149 */
150 csc->sc_csr = PCI_COMMAND_MASTER_ENABLE;
151 if (Cardbus_mapreg_map(ct, ATW_PCI_MMBA,
152 PCI_MAPREG_TYPE_MEM, 0, &sc->sc_st, &sc->sc_sh, &adr,
153 &csc->sc_mapsize) == 0) {
154 #if 0
155 printf(": atw_cardbus_attach mapped %d bytes mem space\n%s",
156 csc->sc_mapsize, sc->sc_dev.dv_xname);
157 #endif
158 csc->sc_cben = CARDBUS_MEM_ENABLE;
159 csc->sc_csr |= PCI_COMMAND_MEM_ENABLE;
160 csc->sc_bar_reg = ATW_PCI_MMBA;
161 csc->sc_bar_val = adr | PCI_MAPREG_TYPE_MEM;
162 } else if (Cardbus_mapreg_map(ct, ATW_PCI_IOBA,
163 PCI_MAPREG_TYPE_IO, 0, &sc->sc_st, &sc->sc_sh, &adr,
164 &csc->sc_mapsize) == 0) {
165 #if 0
166 printf(": atw_cardbus_attach mapped %d bytes I/O space\n%s",
167 csc->sc_mapsize, sc->sc_dev.dv_xname);
168 #endif
169 csc->sc_cben = CARDBUS_IO_ENABLE;
170 csc->sc_csr |= PCI_COMMAND_IO_ENABLE;
171 csc->sc_bar_reg = ATW_PCI_IOBA;
172 csc->sc_bar_val = adr | PCI_MAPREG_TYPE_IO;
173 } else {
174 printf(": unable to map device registers\n");
175 return;
176 }
177
178 /*
179 * Bring the chip out of powersave mode and initialize the
180 * configuration registers.
181 */
182 atw_cardbus_setup(csc);
183
184 /* Remember which interrupt line. */
185 csc->sc_intrline = ca->ca_intrline;
186
187 printf(": revision %d.%d: irq %d\n",
188 (sc->sc_rev >> 4) & 0xf, sc->sc_rev & 0xf, csc->sc_intrline);
189 #if 0
190 /*
191 * The CardBus cards will make it to store-and-forward mode as
192 * soon as you put them under any kind of load, so just start
193 * out there.
194 */
195 sc->sc_txthresh = 3; /* TBD name constant */
196 #endif
197
198 /*
199 * Finish off the attach.
200 */
201 atw_attach(sc);
202
203 ATW_WRITE(sc, ATW_FER, ATW_FER_INTR);
204
205 /*
206 * Power down the socket.
207 */
208 Cardbus_function_disable(csc->sc_ct);
209 }
210
211 int
atw_cardbus_detach(struct device * self,int flags)212 atw_cardbus_detach(struct device *self, int flags)
213 {
214 struct atw_cardbus_softc *csc = (void *)self;
215 struct atw_softc *sc = &csc->sc_atw;
216 struct cardbus_devfunc *ct = csc->sc_ct;
217 int rv;
218
219 #if defined(DIAGNOSTIC)
220 if (ct == NULL)
221 panic("%s: data structure lacks", sc->sc_dev.dv_xname);
222 #endif
223
224 rv = atw_detach(sc);
225 if (rv)
226 return (rv);
227
228 /*
229 * Unhook the interrupt handler.
230 */
231 if (csc->sc_ih != NULL)
232 cardbus_intr_disestablish(ct->ct_cc, ct->ct_cf, csc->sc_ih);
233
234 /*
235 * Release bus space and close window.
236 */
237 if (csc->sc_bar_reg != 0)
238 Cardbus_mapreg_unmap(ct, csc->sc_bar_reg,
239 sc->sc_st, sc->sc_sh, csc->sc_mapsize);
240
241 return (0);
242 }
243
244 int
atw_cardbus_enable(struct atw_softc * sc)245 atw_cardbus_enable(struct atw_softc *sc)
246 {
247 struct atw_cardbus_softc *csc = (void *) sc;
248 cardbus_devfunc_t ct = csc->sc_ct;
249 cardbus_chipset_tag_t cc = ct->ct_cc;
250 cardbus_function_tag_t cf = ct->ct_cf;
251
252 /*
253 * Power on the socket.
254 */
255 Cardbus_function_enable(ct);
256
257 /*
258 * Set up the PCI configuration registers.
259 */
260 atw_cardbus_setup(csc);
261
262 /*
263 * Map and establish the interrupt.
264 */
265 csc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline, IPL_NET,
266 atw_intr, sc, sc->sc_dev.dv_xname);
267 if (csc->sc_ih == NULL) {
268 printf("%s: unable to establish interrupt at %d\n",
269 sc->sc_dev.dv_xname, csc->sc_intrline);
270 Cardbus_function_disable(csc->sc_ct);
271 return (1);
272 }
273
274 return (0);
275 }
276
277 void
atw_cardbus_disable(struct atw_softc * sc)278 atw_cardbus_disable(struct atw_softc *sc)
279 {
280 struct atw_cardbus_softc *csc = (void *) sc;
281 cardbus_devfunc_t ct = csc->sc_ct;
282 cardbus_chipset_tag_t cc = ct->ct_cc;
283 cardbus_function_tag_t cf = ct->ct_cf;
284
285 /* Unhook the interrupt handler. */
286 cardbus_intr_disestablish(cc, cf, csc->sc_ih);
287 csc->sc_ih = NULL;
288
289 /* Power down the socket. */
290 Cardbus_function_disable(ct);
291 }
292
293 void
atw_cardbus_power(struct atw_softc * sc,int why)294 atw_cardbus_power(struct atw_softc *sc, int why)
295 {
296 if (why == DVACT_RESUME)
297 atw_enable(sc);
298 }
299
300 void
atw_cardbus_setup(struct atw_cardbus_softc * csc)301 atw_cardbus_setup(struct atw_cardbus_softc *csc)
302 {
303 #ifdef notyet
304 struct atw_softc *sc = &csc->sc_atw;
305 #endif
306 cardbus_devfunc_t ct = csc->sc_ct;
307 cardbus_chipset_tag_t cc = ct->ct_cc;
308 pci_chipset_tag_t pc = csc->sc_pc;
309 pcireg_t reg;
310
311 #ifdef notyet
312 (void)cardbus_setpowerstate(sc->sc_dev.dv_xname, ct, csc->sc_tag,
313 PCI_PWR_D0);
314 #endif
315
316 /* Program the BAR. */
317 pci_conf_write(pc, csc->sc_tag, csc->sc_bar_reg,
318 csc->sc_bar_val);
319
320 /* Make sure the right access type is on the CardBus bridge. */
321 (*ct->ct_cf->cardbus_ctrl)(cc, csc->sc_cben);
322 (*ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);
323
324 /* Enable the appropriate bits in the PCI CSR. */
325 reg = pci_conf_read(pc, csc->sc_tag,
326 PCI_COMMAND_STATUS_REG);
327 reg &= ~(PCI_COMMAND_IO_ENABLE|PCI_COMMAND_MEM_ENABLE);
328 reg |= csc->sc_csr;
329 pci_conf_write(pc, csc->sc_tag, PCI_COMMAND_STATUS_REG,
330 reg);
331
332 /*
333 * Make sure the latency timer is set to some reasonable
334 * value.
335 */
336 reg = pci_conf_read(pc, csc->sc_tag, PCI_BHLC_REG);
337 if (PCI_LATTIMER(reg) < 0x20) {
338 reg &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT);
339 reg |= (0x20 << PCI_LATTIMER_SHIFT);
340 pci_conf_write(pc, csc->sc_tag, PCI_BHLC_REG, reg);
341 }
342 }
343