xref: /netbsd-src/sys/dev/pci/if_ath_pci.c (revision 23c8222edbfb0f0932d88a8351d3a0cf817dfb9e)
1 /*	$NetBSD: if_ath_pci.c,v 1.7 2004/06/30 05:58:17 mycroft Exp $	*/
2 
3 /*-
4  * Copyright (c) 2002-2004 Sam Leffler, Errno Consulting
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer,
12  *    without modification.
13  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
14  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
15  *    redistribution must be conditioned upon including a substantially
16  *    similar Disclaimer requirement for further binary redistribution.
17  * 3. Neither the names of the above-listed copyright holders nor the names
18  *    of any contributors may be used to endorse or promote products derived
19  *    from this software without specific prior written permission.
20  *
21  * Alternatively, this software may be distributed under the terms of the
22  * GNU General Public License ("GPL") version 2 as published by the Free
23  * Software Foundation.
24  *
25  * NO WARRANTY
26  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
29  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
30  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
31  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
34  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
36  * THE POSSIBILITY OF SUCH DAMAGES.
37  */
38 
39 #include <sys/cdefs.h>
40 #ifdef __FreeBSD__
41 __FBSDID("$FreeBSD: src/sys/dev/ath/if_ath_pci.c,v 1.8 2004/04/02 23:57:10 sam Exp $");
42 #endif
43 #ifdef __NetBSD__
44 __KERNEL_RCSID(0, "$NetBSD: if_ath_pci.c,v 1.7 2004/06/30 05:58:17 mycroft Exp $");
45 #endif
46 
47 /*
48  * PCI/Cardbus front-end for the Atheros Wireless LAN controller driver.
49  */
50 
51 #include "opt_inet.h"
52 
53 #include <sys/param.h>
54 #include <sys/systm.h>
55 #include <sys/mbuf.h>
56 #include <sys/malloc.h>
57 #include <sys/kernel.h>
58 #include <sys/lock.h>
59 #include <sys/socket.h>
60 #include <sys/sockio.h>
61 #include <sys/errno.h>
62 
63 #include <machine/bus.h>
64 
65 #include <net/if.h>
66 #include <net/if_dl.h>
67 #include <net/if_media.h>
68 #include <net/if_ether.h>
69 #include <net/if_llc.h>
70 #include <net/if_arp.h>
71 
72 #include <net80211/ieee80211_compat.h>
73 #include <net80211/ieee80211_var.h>
74 
75 #ifdef INET
76 #include <netinet/in.h>
77 #endif
78 
79 #include <dev/ic/athcompat.h>
80 #include <dev/ic/athvar.h>
81 #include <../contrib/sys/dev/ic/athhal.h>
82 
83 #include <dev/pci/pcivar.h>
84 #include <dev/pci/pcireg.h>
85 #include <dev/pci/pcidevs.h>
86 
87 #include <sys/device.h>
88 
89 /*
90  * PCI glue.
91  */
92 
93 struct ath_pci_softc {
94 	struct ath_softc	sc_sc;
95 #ifdef __FreeBSD__
96 	struct resource		*sc_sr;		/* memory resource */
97 	struct resource		*sc_irq;	/* irq resource */
98 #else
99 	pci_chipset_tag_t	sc_pc;
100 #endif
101 	void			*sc_ih;		/* intererupt handler */
102 	u_int8_t		sc_saved_intline;
103 	u_int8_t		sc_saved_cachelinesz;
104 	u_int8_t		sc_saved_lattimer;
105 };
106 
107 #define	BS_BAR	0x10
108 
109 static int ath_pci_match(struct device *, struct cfdata *, void *);
110 static void ath_pci_attach(struct device *, struct device *, void *);
111 static void ath_pci_shutdown(void *);
112 static int ath_pci_detach(struct device *, int);
113 
114 CFATTACH_DECL(ath_pci,
115     sizeof(struct ath_pci_softc),
116     ath_pci_match,
117     ath_pci_attach,
118     ath_pci_detach,
119     NULL);
120 
121 /*
122  * translate some product code.  it is a workaround until HAL gets updated.
123  */
124 static u_int16_t
125 ath_product(pcireg_t pa_id)
126 {
127 	u_int16_t prodid;
128 
129 	prodid = PCI_PRODUCT(pa_id);
130 	switch (prodid) {
131 	case 0x1014:	/* IBM 31P9702 minipci a/b/g card */
132 		prodid = PCI_PRODUCT_ATHEROS_AR5212;
133 		break;
134 	default:
135 		break;
136 	}
137 	return prodid;
138 }
139 
140 static int
141 ath_pci_match(struct device *parent, struct cfdata *match, void *aux)
142 {
143 	const char* devname;
144 	struct pci_attach_args *pa = aux;
145 	pci_vendor_id_t vendor;
146 
147 	vendor = PCI_VENDOR(pa->pa_id);
148 	/* XXX HACK until HAL is updated. */
149 	if (vendor == 0x128c)
150 		vendor = PCI_VENDOR_ATHEROS;
151 	devname = ath_hal_probe(vendor, ath_product(pa->pa_id));
152 	if (devname)
153 		return 1;
154 
155 	return 0;
156 }
157 
158 static void
159 ath_pci_attach(struct device *parent, struct device *self, void *aux)
160 {
161 	struct ath_pci_softc *psc = (struct ath_pci_softc *)self;
162 	struct ath_softc *sc = &psc->sc_sc;
163 	u_int32_t res;
164 	struct pci_attach_args *pa = aux;
165 	pci_chipset_tag_t pc = pa->pa_pc;
166 	bus_space_tag_t iot;
167 	bus_space_handle_t ioh;
168 	pci_intr_handle_t ih;
169 	void *hook;
170 	const char *intrstr = NULL;
171 
172 	psc->sc_pc = pc;
173 
174 	pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
175 	    pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG) |
176 	        PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_MEM_ENABLE);
177 	res = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
178 
179 	if ((res & PCI_COMMAND_MEM_ENABLE) == 0) {
180 		aprint_error("couldn't enable memory mapping\n");
181 		goto bad;
182 	}
183 
184 	if ((res & PCI_COMMAND_MASTER_ENABLE) == 0) {
185 		aprint_error("couldn't enable bus mastering\n");
186 		goto bad;
187 	}
188 
189 	/*
190 	 * Setup memory-mapping of PCI registers.
191 	 */
192 	if (pci_mapreg_map(pa, BS_BAR, PCI_MAPREG_TYPE_MEM, 0, &iot, &ioh,
193 	    NULL, NULL)) {
194 		aprint_error("cannot map register space\n");
195 		goto bad;
196 	}
197 	sc->sc_st = iot;
198 	sc->sc_sh = ioh;
199 
200 	sc->sc_invalid = 1;
201 
202 	/*
203 	 * Arrange interrupt line.
204 	 */
205 	if (pci_intr_map(pa, &ih)) {
206 		aprint_error("couldn't map interrupt\n");
207 		goto bad1;
208 	}
209 
210 	intrstr = pci_intr_string(pc, ih);
211 	psc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, ath_intr, sc);
212 	if (psc->sc_ih == NULL) {
213 		aprint_error("couldn't map interrupt\n");
214 		goto bad2;
215 	}
216 
217 	printf("\n");
218 	printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr);
219 
220 	sc->sc_dmat = pa->pa_dmat;
221 
222 	hook = shutdownhook_establish(ath_pci_shutdown, psc);
223 	if (hook == NULL) {
224 		aprint_error("couldn't make shutdown hook\n");
225 		goto bad3;
226 	}
227 
228 	if (ath_attach(ath_product(pa->pa_id), sc) == 0)
229 		return;
230 
231 	shutdownhook_disestablish(hook);
232 
233 bad3:	pci_intr_disestablish(pc, psc->sc_ih);
234 bad2:	/* XXX */
235 bad1:	/* XXX */
236 bad:
237 	return;
238 }
239 
240 static int
241 ath_pci_detach(struct device *self, int flags)
242 {
243 	struct ath_pci_softc *psc = (struct ath_pci_softc *)self;
244 
245 	ath_detach(&psc->sc_sc);
246 	pci_intr_disestablish(psc->sc_pc, psc->sc_ih);
247 
248 	return (0);
249 }
250 
251 static void
252 ath_pci_shutdown(void *self)
253 {
254 	struct ath_pci_softc *psc = (struct ath_pci_softc *)self;
255 
256 	ath_shutdown(&psc->sc_sc);
257 }
258