xref: /openbsd-src/sys/dev/cardbus/if_atw_cardbus.c (revision c7101648ccc694093c4a805ebde0f53056d1a24c)
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