Line data Source code
1 : /* $OpenBSD: if_athn_cardbus.c,v 1.15 2017/01/12 16:32:28 stsp Exp $ */
2 :
3 : /*-
4 : * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
5 : *
6 : * Permission to use, copy, modify, and distribute this software for any
7 : * purpose with or without fee is hereby granted, provided that the above
8 : * copyright notice and this permission notice appear in all copies.
9 : *
10 : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 : * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 : * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 : */
18 :
19 : /*
20 : * CardBus front-end for Atheros 802.11a/g/n chipsets.
21 : */
22 :
23 : #include "bpfilter.h"
24 :
25 : #include <sys/param.h>
26 : #include <sys/sockio.h>
27 : #include <sys/mbuf.h>
28 : #include <sys/kernel.h>
29 : #include <sys/socket.h>
30 : #include <sys/systm.h>
31 : #include <sys/malloc.h>
32 : #include <sys/timeout.h>
33 : #include <sys/device.h>
34 :
35 : #include <machine/bus.h>
36 : #include <machine/intr.h>
37 :
38 : #include <net/if.h>
39 : #include <net/if_media.h>
40 :
41 : #include <netinet/in.h>
42 : #include <netinet/if_ether.h>
43 :
44 : #include <net80211/ieee80211_var.h>
45 : #include <net80211/ieee80211_amrr.h>
46 : #include <net80211/ieee80211_mira.h>
47 : #include <net80211/ieee80211_radiotap.h>
48 :
49 : #include <dev/ic/athnreg.h>
50 : #include <dev/ic/athnvar.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 athn_cardbus_softc {
59 : struct athn_softc sc_sc;
60 :
61 : /* CardBus specific goo. */
62 : cardbus_devfunc_t sc_ct;
63 : pcitag_t sc_tag;
64 : void *sc_ih;
65 : bus_space_tag_t sc_st;
66 : bus_space_handle_t sc_sh;
67 : bus_size_t sc_mapsize;
68 : pcireg_t sc_bar_val;
69 : int sc_intrline;
70 : pci_chipset_tag_t sc_pc;
71 : };
72 :
73 : int athn_cardbus_match(struct device *, void *, void *);
74 : void athn_cardbus_attach(struct device *, struct device *, void *);
75 : int athn_cardbus_detach(struct device *, int);
76 : int athn_cardbus_enable(struct athn_softc *);
77 : void athn_cardbus_disable(struct athn_softc *);
78 : void athn_cardbus_power(struct athn_softc *, int);
79 : void athn_cardbus_setup(struct athn_cardbus_softc *);
80 : uint32_t athn_cardbus_read(struct athn_softc *, uint32_t);
81 : void athn_cardbus_write(struct athn_softc *, uint32_t, uint32_t);
82 : void athn_cardbus_write_barrier(struct athn_softc *);
83 :
84 : struct cfattach athn_cardbus_ca = {
85 : sizeof (struct athn_cardbus_softc),
86 : athn_cardbus_match,
87 : athn_cardbus_attach,
88 : athn_cardbus_detach
89 : };
90 :
91 : static const struct pci_matchid athn_cardbus_devices[] = {
92 : { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5416 },
93 : { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5418 },
94 : { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9160 },
95 : { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9280 },
96 : { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9281 },
97 : { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9285 },
98 : { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR2427 },
99 : { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9227 },
100 : { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9287 },
101 : { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9300 }
102 : };
103 :
104 : int
105 0 : athn_cardbus_match(struct device *parent, void *match, void *aux)
106 : {
107 0 : return (cardbus_matchbyid(aux, athn_cardbus_devices,
108 : nitems(athn_cardbus_devices)));
109 : }
110 :
111 : void
112 0 : athn_cardbus_attach(struct device *parent, struct device *self, void *aux)
113 : {
114 0 : struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)self;
115 0 : struct athn_softc *sc = &csc->sc_sc;
116 0 : struct cardbus_attach_args *ca = aux;
117 0 : cardbus_devfunc_t ct = ca->ca_ct;
118 0 : bus_addr_t base;
119 : int error;
120 :
121 0 : sc->sc_dmat = ca->ca_dmat;
122 0 : csc->sc_ct = ct;
123 0 : csc->sc_tag = ca->ca_tag;
124 0 : csc->sc_intrline = ca->ca_intrline;
125 0 : csc->sc_pc = ca->ca_pc;
126 :
127 : /* Power management hooks. */
128 0 : sc->sc_enable = athn_cardbus_enable;
129 0 : sc->sc_disable = athn_cardbus_disable;
130 0 : sc->sc_power = athn_cardbus_power;
131 :
132 0 : sc->ops.read = athn_cardbus_read;
133 0 : sc->ops.write = athn_cardbus_write;
134 0 : sc->ops.write_barrier = athn_cardbus_write_barrier;
135 :
136 : /* Map control/status registers. */
137 0 : error = Cardbus_mapreg_map(ct, CARDBUS_BASE0_REG,
138 : PCI_MAPREG_TYPE_MEM, 0, &csc->sc_st, &csc->sc_sh, &base,
139 : &csc->sc_mapsize);
140 0 : if (error != 0) {
141 0 : printf(": can't map mem space\n");
142 0 : return;
143 : }
144 0 : csc->sc_bar_val = base | PCI_MAPREG_TYPE_MEM;
145 :
146 : /* Set up the PCI configuration registers. */
147 0 : athn_cardbus_setup(csc);
148 :
149 0 : printf(": irq %d\n", csc->sc_intrline);
150 :
151 0 : athn_attach(sc);
152 0 : Cardbus_function_disable(ct);
153 0 : }
154 :
155 : int
156 0 : athn_cardbus_detach(struct device *self, int flags)
157 : {
158 0 : struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)self;
159 0 : struct athn_softc *sc = &csc->sc_sc;
160 0 : cardbus_devfunc_t ct = csc->sc_ct;
161 0 : cardbus_chipset_tag_t cc = ct->ct_cc;
162 0 : cardbus_function_tag_t cf = ct->ct_cf;
163 :
164 0 : athn_detach(sc);
165 :
166 : /* Unhook the interrupt handler. */
167 0 : if (csc->sc_ih != NULL)
168 0 : cardbus_intr_disestablish(cc, cf, csc->sc_ih);
169 :
170 : /* Release bus space and close window. */
171 0 : Cardbus_mapreg_unmap(ct, CARDBUS_BASE0_REG, csc->sc_st, csc->sc_sh,
172 : csc->sc_mapsize);
173 :
174 0 : return (0);
175 : }
176 :
177 : int
178 0 : athn_cardbus_enable(struct athn_softc *sc)
179 : {
180 0 : struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)sc;
181 0 : cardbus_devfunc_t ct = csc->sc_ct;
182 0 : cardbus_chipset_tag_t cc = ct->ct_cc;
183 0 : cardbus_function_tag_t cf = ct->ct_cf;
184 :
185 : /* Power on the socket. */
186 0 : Cardbus_function_enable(ct);
187 :
188 : /* Setup the PCI configuration registers. */
189 0 : athn_cardbus_setup(csc);
190 :
191 : /* Map and establish the interrupt handler. */
192 0 : csc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline, IPL_NET,
193 0 : athn_intr, sc, sc->sc_dev.dv_xname);
194 0 : if (csc->sc_ih == NULL) {
195 0 : printf("%s: could not establish interrupt at %d\n",
196 0 : sc->sc_dev.dv_xname, csc->sc_intrline);
197 0 : Cardbus_function_disable(ct);
198 0 : return (1);
199 : }
200 0 : return (0);
201 0 : }
202 :
203 : void
204 0 : athn_cardbus_disable(struct athn_softc *sc)
205 : {
206 0 : struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)sc;
207 0 : cardbus_devfunc_t ct = csc->sc_ct;
208 0 : cardbus_chipset_tag_t cc = ct->ct_cc;
209 0 : cardbus_function_tag_t cf = ct->ct_cf;
210 :
211 : /* Unhook the interrupt handler. */
212 0 : cardbus_intr_disestablish(cc, cf, csc->sc_ih);
213 0 : csc->sc_ih = NULL;
214 :
215 : /* Power down the socket. */
216 0 : Cardbus_function_disable(ct);
217 0 : }
218 :
219 : void
220 0 : athn_cardbus_power(struct athn_softc *sc, int why)
221 : {
222 0 : struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)sc;
223 :
224 0 : if (why == DVACT_RESUME) {
225 : /* Restore the PCI configuration registers. */
226 0 : athn_cardbus_setup(csc);
227 0 : }
228 0 : }
229 :
230 : void
231 0 : athn_cardbus_setup(struct athn_cardbus_softc *csc)
232 : {
233 0 : cardbus_devfunc_t ct = csc->sc_ct;
234 0 : cardbus_chipset_tag_t cc = ct->ct_cc;
235 0 : pci_chipset_tag_t pc = csc->sc_pc;
236 0 : cardbus_function_tag_t cf = ct->ct_cf;
237 : pcireg_t reg;
238 :
239 : /* Program the BAR. */
240 0 : pci_conf_write(pc, csc->sc_tag, CARDBUS_BASE0_REG,
241 0 : csc->sc_bar_val);
242 :
243 : /* Make sure the right access type is on the cardbus bridge. */
244 0 : (*cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE);
245 0 : (*cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);
246 :
247 : /* Enable the appropriate bits in the PCI CSR. */
248 0 : reg = pci_conf_read(pc, csc->sc_tag,
249 : PCI_COMMAND_STATUS_REG);
250 0 : reg |= PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_MEM_ENABLE;
251 0 : pci_conf_write(pc, csc->sc_tag, PCI_COMMAND_STATUS_REG,
252 : reg);
253 :
254 : /*
255 : * Noone knows why this shit is necessary but there are claims that
256 : * not doing this may cause very frequent PCI FATAL interrupts from
257 : * the card: http://bugzilla.kernel.org/show_bug.cgi?id=13483
258 : */
259 0 : reg = pci_conf_read(pc, csc->sc_tag, 0x40);
260 0 : if (reg & 0xff00)
261 0 : pci_conf_write(pc, csc->sc_tag, 0x40, reg & ~0xff00);
262 :
263 : /* Change latency timer; default value yields poor results. */
264 0 : reg = pci_conf_read(pc, csc->sc_tag, PCI_BHLC_REG);
265 0 : reg &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT);
266 0 : reg |= 168 << PCI_LATTIMER_SHIFT;
267 0 : pci_conf_write(pc, csc->sc_tag, PCI_BHLC_REG, reg);
268 0 : }
269 :
270 : uint32_t
271 0 : athn_cardbus_read(struct athn_softc *sc, uint32_t addr)
272 : {
273 0 : struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)sc;
274 :
275 0 : return (bus_space_read_4(csc->sc_st, csc->sc_sh, addr));
276 : }
277 :
278 : void
279 0 : athn_cardbus_write(struct athn_softc *sc, uint32_t addr, uint32_t val)
280 : {
281 0 : struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)sc;
282 :
283 0 : bus_space_write_4(csc->sc_st, csc->sc_sh, addr, val);
284 0 : }
285 :
286 : void
287 0 : athn_cardbus_write_barrier(struct athn_softc *sc)
288 : {
289 0 : struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)sc;
290 :
291 0 : bus_space_barrier(csc->sc_st, csc->sc_sh, 0, csc->sc_mapsize,
292 : BUS_SPACE_BARRIER_WRITE);
293 0 : }
|