Line data Source code
1 : /* $OpenBSD: if_acx_cardbus.c,v 1.22 2015/11/24 17:11:39 mpi Exp $ */
2 :
3 : /*
4 : * Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org>
5 : * Copyright (c) 2005, 2006
6 : * Damien Bergamini <damien.bergamini@free.fr>
7 : *
8 : * Permission to use, copy, modify, and distribute this software for any
9 : * purpose with or without fee is hereby granted, provided that the above
10 : * copyright notice and this permission notice appear in all copies.
11 : *
12 : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 : * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 : * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 : */
20 :
21 : /*
22 : * CardBus front-end for the Texas Instruments ACX driver
23 : */
24 :
25 : #include "bpfilter.h"
26 :
27 : #include <sys/param.h>
28 : #include <sys/sockio.h>
29 : #include <sys/mbuf.h>
30 : #include <sys/kernel.h>
31 : #include <sys/socket.h>
32 : #include <sys/systm.h>
33 : #include <sys/malloc.h>
34 : #include <sys/timeout.h>
35 : #include <sys/device.h>
36 :
37 : #include <machine/bus.h>
38 : #include <machine/intr.h>
39 :
40 : #include <net/if.h>
41 : #include <net/if_media.h>
42 :
43 : #include <netinet/in.h>
44 : #include <netinet/if_ether.h>
45 :
46 : #include <net80211/ieee80211_var.h>
47 : #include <net80211/ieee80211_amrr.h>
48 : #include <net80211/ieee80211_radiotap.h>
49 :
50 : #include <dev/ic/acxvar.h>
51 :
52 : #include <dev/pci/pcireg.h>
53 : #include <dev/pci/pcivar.h>
54 : #include <dev/pci/pcidevs.h>
55 :
56 : #include <dev/cardbus/cardbusvar.h>
57 :
58 : struct acx_cardbus_softc {
59 : struct acx_softc sc_acx;
60 :
61 : /* cardbus specific goo */
62 : cardbus_devfunc_t sc_ct;
63 : pcitag_t sc_tag;
64 : void *sc_ih;
65 : bus_size_t sc_mapsize1;
66 : bus_size_t sc_mapsize2;
67 : pcireg_t sc_iobar_val; /* acx100 only */
68 : pcireg_t sc_bar1_val;
69 : pcireg_t sc_bar2_val;
70 : int sc_intrline;
71 :
72 : /* hack for ACX100A */
73 : bus_space_tag_t sc_io_bt;
74 : bus_space_handle_t sc_io_bh;
75 : bus_size_t sc_iomapsize;
76 :
77 : int sc_acx_attached;
78 : pci_chipset_tag_t sc_pc;
79 : };
80 :
81 : int acx_cardbus_match(struct device *, void *, void *);
82 : void acx_cardbus_attach(struct device *, struct device *, void *);
83 : int acx_cardbus_detach(struct device *, int);
84 :
85 : struct cfattach acx_cardbus_ca = {
86 : sizeof (struct acx_cardbus_softc), acx_cardbus_match,
87 : acx_cardbus_attach, acx_cardbus_detach
88 : };
89 :
90 : static const struct pci_matchid acx_cardbus_devices[] = {
91 : { PCI_VENDOR_TI, PCI_PRODUCT_TI_ACX100A },
92 : { PCI_VENDOR_TI, PCI_PRODUCT_TI_ACX100B },
93 : { PCI_VENDOR_TI, PCI_PRODUCT_TI_ACX111 },
94 : };
95 :
96 : int acx_cardbus_enable(struct acx_softc *);
97 : void acx_cardbus_disable(struct acx_softc *);
98 : void acx_cardbus_power(struct acx_softc *, int);
99 : void acx_cardbus_setup(struct acx_cardbus_softc *);
100 :
101 : int
102 0 : acx_cardbus_match(struct device *parent, void *match, void *aux)
103 : {
104 0 : return (cardbus_matchbyid((struct cardbus_attach_args *)aux,
105 : acx_cardbus_devices,
106 : sizeof (acx_cardbus_devices) / sizeof (acx_cardbus_devices[0])));
107 : }
108 :
109 : void
110 0 : acx_cardbus_attach(struct device *parent, struct device *self, void *aux)
111 : {
112 0 : struct acx_cardbus_softc *csc = (struct acx_cardbus_softc *)self;
113 0 : struct acx_softc *sc = &csc->sc_acx;
114 0 : struct cardbus_attach_args *ca = aux;
115 0 : cardbus_devfunc_t ct = ca->ca_ct;
116 0 : bus_addr_t base;
117 : int error, b1 = CARDBUS_BASE0_REG, b2 = CARDBUS_BASE1_REG;
118 :
119 0 : sc->sc_dmat = ca->ca_dmat;
120 0 : csc->sc_ct = ct;
121 0 : csc->sc_tag = ca->ca_tag;
122 0 : csc->sc_intrline = ca->ca_intrline;
123 0 : csc->sc_pc = ca->ca_pc;
124 :
125 : /* power management hooks */
126 0 : sc->sc_enable = acx_cardbus_enable;
127 0 : sc->sc_disable = acx_cardbus_disable;
128 0 : sc->sc_power = acx_cardbus_power;
129 :
130 0 : if (PCI_PRODUCT(ca->ca_id) == PCI_PRODUCT_TI_ACX100A) {
131 : /* first map I/O space as seen in the dragonfly code */
132 0 : error = Cardbus_mapreg_map(ct, CARDBUS_BASE0_REG,
133 : PCI_MAPREG_TYPE_IO, 0, &csc->sc_io_bt, &csc->sc_io_bh,
134 : &base, &csc->sc_iomapsize);
135 0 : if (error != 0) {
136 0 : printf(": can't map i/o space\n");
137 0 : return;
138 : }
139 0 : csc->sc_iobar_val = base | PCI_MAPREG_TYPE_IO;
140 : b1 = CARDBUS_BASE1_REG;
141 : b2 = CARDBUS_BASE2_REG;
142 0 : }
143 :
144 : /* map control/status registers */
145 0 : error = Cardbus_mapreg_map(ct, b1, PCI_MAPREG_TYPE_MEM, 0,
146 : &sc->sc_mem1_bt, &sc->sc_mem1_bh, &base, &csc->sc_mapsize1);
147 0 : if (error != 0) {
148 0 : printf(": can't map mem1 space\n");
149 0 : return;
150 : }
151 :
152 0 : csc->sc_bar1_val = base | PCI_MAPREG_TYPE_MEM;
153 :
154 : /* map the other memory region */
155 0 : error = Cardbus_mapreg_map(ct, b2, PCI_MAPREG_TYPE_MEM, 0,
156 : &sc->sc_mem2_bt, &sc->sc_mem2_bh, &base, &csc->sc_mapsize2);
157 0 : if (error != 0) {
158 0 : printf(": can't map mem2 space\n");
159 0 : return;
160 : }
161 :
162 0 : csc->sc_bar2_val = base | PCI_MAPREG_TYPE_MEM;
163 :
164 : /* set up the PCI configuration registers */
165 0 : acx_cardbus_setup(csc);
166 :
167 0 : printf(": irq %d\n", csc->sc_intrline);
168 :
169 0 : if (PCI_PRODUCT(ca->ca_id) == PCI_PRODUCT_TI_ACX111)
170 0 : acx111_set_param(sc);
171 : else
172 0 : acx100_set_param(sc);
173 :
174 0 : error = acx_attach(sc);
175 0 : csc->sc_acx_attached = error == 0;
176 :
177 0 : Cardbus_function_disable(ct);
178 0 : }
179 :
180 : int
181 0 : acx_cardbus_detach(struct device *self, int flags)
182 : {
183 0 : struct acx_cardbus_softc *csc = (struct acx_cardbus_softc *)self;
184 0 : struct acx_softc *sc = &csc->sc_acx;
185 0 : cardbus_devfunc_t ct = csc->sc_ct;
186 0 : cardbus_chipset_tag_t cc = ct->ct_cc;
187 0 : cardbus_function_tag_t cf = ct->ct_cf;
188 : int error, b1 = CARDBUS_BASE0_REG, b2 = CARDBUS_BASE1_REG;
189 :
190 0 : if (csc->sc_acx_attached) {
191 0 : error = acx_detach(sc);
192 0 : if (error != 0)
193 0 : return (error);
194 : }
195 :
196 : /* unhook the interrupt handler */
197 0 : if (csc->sc_ih != NULL) {
198 0 : cardbus_intr_disestablish(cc, cf, csc->sc_ih);
199 0 : csc->sc_ih = NULL;
200 0 : }
201 :
202 : /* release bus space and close window */
203 0 : if (csc->sc_iomapsize) {
204 : b1 = CARDBUS_BASE1_REG;
205 : b2 = CARDBUS_BASE2_REG;
206 0 : }
207 0 : Cardbus_mapreg_unmap(ct, b1, sc->sc_mem1_bt,
208 : sc->sc_mem1_bh, csc->sc_mapsize1);
209 0 : Cardbus_mapreg_unmap(ct, b2, sc->sc_mem2_bt,
210 : sc->sc_mem2_bh, csc->sc_mapsize2);
211 0 : if (csc->sc_iomapsize)
212 0 : Cardbus_mapreg_unmap(ct, CARDBUS_BASE0_REG, csc->sc_io_bt,
213 : csc->sc_io_bh, csc->sc_iomapsize);
214 :
215 0 : return (0);
216 0 : }
217 :
218 : int
219 0 : acx_cardbus_enable(struct acx_softc *sc)
220 : {
221 : struct acx_cardbus_softc *csc;
222 : int error;
223 :
224 0 : csc = (struct acx_cardbus_softc *)sc;
225 0 : cardbus_devfunc_t ct = csc->sc_ct;
226 0 : cardbus_chipset_tag_t cc = ct->ct_cc;
227 0 : cardbus_function_tag_t cf = ct->ct_cf;
228 :
229 : /* power on the socket */
230 0 : error = Cardbus_function_enable(ct);
231 0 : if (error)
232 0 : return error;
233 :
234 : /* setup the PCI configuration registers */
235 0 : acx_cardbus_setup(csc);
236 :
237 : /* map and establish the interrupt handler */
238 0 : csc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline, IPL_NET,
239 0 : acx_intr, sc, sc->sc_dev.dv_xname);
240 0 : if (csc->sc_ih == NULL) {
241 0 : printf("%s: could not establish interrupt at %d\n",
242 0 : sc->sc_dev.dv_xname, csc->sc_intrline);
243 0 : Cardbus_function_disable(ct);
244 0 : return (1);
245 : }
246 :
247 0 : return (0);
248 0 : }
249 :
250 : void
251 0 : acx_cardbus_disable(struct acx_softc *sc)
252 : {
253 0 : struct acx_cardbus_softc *csc = (struct acx_cardbus_softc *)sc;
254 0 : cardbus_devfunc_t ct = csc->sc_ct;
255 0 : cardbus_chipset_tag_t cc = ct->ct_cc;
256 0 : cardbus_function_tag_t cf = ct->ct_cf;
257 :
258 : /* unhook the interrupt handler */
259 0 : cardbus_intr_disestablish(cc, cf, csc->sc_ih);
260 0 : csc->sc_ih = NULL;
261 :
262 : /* power down the socket */
263 0 : Cardbus_function_disable(ct);
264 0 : }
265 :
266 : void
267 0 : acx_cardbus_power(struct acx_softc *sc, int why)
268 : {
269 0 : struct acx_cardbus_softc *csc = (struct acx_cardbus_softc *)sc;
270 :
271 0 : if (why == DVACT_RESUME) {
272 : /* kick the PCI configuration registers */
273 0 : acx_cardbus_setup(csc);
274 0 : }
275 0 : }
276 :
277 : void
278 0 : acx_cardbus_setup(struct acx_cardbus_softc *csc)
279 : {
280 0 : cardbus_devfunc_t ct = csc->sc_ct;
281 0 : cardbus_chipset_tag_t cc = ct->ct_cc;
282 0 : pci_chipset_tag_t pc = csc->sc_pc;
283 0 : cardbus_function_tag_t cf = ct->ct_cf;
284 : pcireg_t reg;
285 : int b1 = CARDBUS_BASE0_REG, b2 = CARDBUS_BASE1_REG;
286 :
287 0 : if (csc->sc_iobar_val) {
288 0 : pci_conf_write(pc, csc->sc_tag, CARDBUS_BASE0_REG,
289 : csc->sc_iobar_val);
290 : b1 = CARDBUS_BASE1_REG;
291 : b2 = CARDBUS_BASE2_REG;
292 : /* (*cf->cardbus_ctrl)(cc, CARDBUS_IO_ENABLE); */
293 0 : }
294 :
295 : /* program the BAR */
296 0 : pci_conf_write(pc, csc->sc_tag, b1, csc->sc_bar1_val);
297 0 : pci_conf_write(pc, csc->sc_tag, b2, csc->sc_bar2_val);
298 :
299 : /* make sure the right access type is on the cardbus bridge */
300 0 : (*cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE);
301 0 : (*cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);
302 :
303 : /* enable the appropriate bits in the PCI CSR */
304 0 : reg = pci_conf_read(pc, csc->sc_tag,
305 : PCI_COMMAND_STATUS_REG);
306 0 : reg |= PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_MEM_ENABLE;
307 : #if 0
308 : if (csc->sc_iobar_val)
309 : reg |= PCI_COMMAND_IO_ENABLE;
310 : #endif
311 0 : pci_conf_write(pc, csc->sc_tag, PCI_COMMAND_STATUS_REG,
312 : reg);
313 0 : }
|