1 /* $NetBSD: if_ath_pci.c,v 1.35 2009/09/16 16:34:50 dyoung Exp $ */
4 * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
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.
39 #include <sys/cdefs.h>
41 __FBSDID("$FreeBSD: src/sys/dev/ath/if_ath_pci.c,v 1.11 2005/01/18 18:08:16 sam Exp $");
44 __KERNEL_RCSID(0, "$NetBSD: if_ath_pci.c,v 1.35 2009/09/16 16:34:50 dyoung Exp $");
48 * PCI/Cardbus front-end for the Atheros Wireless LAN controller driver.
51 #include <sys/param.h>
52 #include <sys/systm.h>
54 #include <sys/malloc.h>
55 #include <sys/kernel.h>
56 #include <sys/socket.h>
57 #include <sys/errno.h>
58 #include <sys/device.h>
61 #include <net/if_media.h>
62 #include <net/if_ether.h>
64 #include <net80211/ieee80211_netbsd.h>
65 #include <net80211/ieee80211_var.h>
68 #include <netinet/in.h>
71 #include <external/isc/atheros_hal/dist/ah.h>
73 #include <dev/ic/ath_netbsd.h>
74 #include <dev/ic/athvar.h>
76 #include <dev/pci/pcivar.h>
77 #include <dev/pci/pcireg.h>
78 #include <dev/pci/pcidevs.h>
84 struct ath_pci_softc
{
85 struct ath_softc sc_sc
;
86 pci_chipset_tag_t sc_pc
;
88 pci_intr_handle_t sc_pih
;
89 void *sc_ih
; /* interrupt handler */
90 bus_space_tag_t sc_iot
;
91 bus_space_handle_t sc_ioh
;
97 static void ath_pci_attach(device_t
, device_t
, void *);
98 static int ath_pci_detach(device_t
, int);
99 static int ath_pci_match(device_t
, cfdata_t
, void *);
101 CFATTACH_DECL_NEW(ath_pci
,
102 sizeof(struct ath_pci_softc
),
109 ath_pci_match(device_t parent
, cfdata_t match
, void *aux
)
112 struct pci_attach_args
*pa
= aux
;
114 devname
= ath_hal_probe(PCI_VENDOR(pa
->pa_id
), PCI_PRODUCT(pa
->pa_id
));
121 ath_pci_suspend(device_t self
, pmf_qual_t qual
)
123 struct ath_pci_softc
*sc
= device_private(self
);
125 ath_suspend(&sc
->sc_sc
);
126 pci_intr_disestablish(sc
->sc_pc
, sc
->sc_ih
);
133 ath_pci_resume(device_t self
, pmf_qual_t qual
)
135 struct ath_pci_softc
*sc
= device_private(self
);
137 sc
->sc_ih
= pci_intr_establish(sc
->sc_pc
, sc
->sc_pih
, IPL_NET
, ath_intr
,
139 if (sc
->sc_ih
== NULL
) {
140 aprint_error_dev(self
, "couldn't map interrupt\n");
143 return ath_resume(&sc
->sc_sc
);
147 ath_pci_setup(struct ath_pci_softc
*sc
)
149 pcireg_t bhlc
, csr
, icr
, lattimer
;
151 * Enable memory mapping and bus mastering.
153 csr
= pci_conf_read(sc
->sc_pc
, sc
->sc_pcitag
, PCI_COMMAND_STATUS_REG
);
154 csr
|= PCI_COMMAND_MASTER_ENABLE
| PCI_COMMAND_MEM_ENABLE
;
155 pci_conf_write(sc
->sc_pc
, sc
->sc_pcitag
, PCI_COMMAND_STATUS_REG
, csr
);
156 csr
= pci_conf_read(sc
->sc_pc
, sc
->sc_pcitag
, PCI_COMMAND_STATUS_REG
);
158 if ((csr
& PCI_COMMAND_MEM_ENABLE
) == 0) {
159 aprint_error("couldn't enable memory mapping\n");
162 if ((csr
& PCI_COMMAND_MASTER_ENABLE
) == 0) {
163 aprint_error("couldn't enable bus mastering\n");
168 * XXX Both this comment and code are replicated in
169 * XXX cardbus_rescan().
171 * Make sure the latency timer is set to some reasonable
174 * I will set the initial value of the Latency Timer here.
176 * While a PCI device owns the bus, its Latency Timer counts
177 * down bus cycles from its initial value to 0. Minimum
178 * Grant tells for how long the device wants to own the
179 * bus once it gets access, in units of 250ns.
181 * On a 33 MHz bus, there are 8 cycles per 250ns. So I
182 * multiply the Minimum Grant by 8 to find out the initial
183 * value of the Latency Timer.
185 * I never set a Latency Timer less than 0x10, since that
186 * is what the old code did.
188 bhlc
= pci_conf_read(sc
->sc_pc
, sc
->sc_pcitag
, PCI_BHLC_REG
);
189 icr
= pci_conf_read(sc
->sc_pc
, sc
->sc_pcitag
, PCI_INTERRUPT_REG
);
190 lattimer
= MAX(0x10, MIN(0xf8, 8 * PCI_MIN_GNT(icr
)));
191 if (PCI_LATTIMER(bhlc
) < lattimer
) {
192 bhlc
&= ~(PCI_LATTIMER_MASK
<< PCI_LATTIMER_SHIFT
);
193 bhlc
|= (lattimer
<< PCI_LATTIMER_SHIFT
);
194 pci_conf_write(sc
->sc_pc
, sc
->sc_pcitag
, PCI_BHLC_REG
, bhlc
);
200 ath_pci_attach(device_t parent
, device_t self
, void *aux
)
202 struct ath_pci_softc
*psc
= device_private(self
);
203 struct ath_softc
*sc
= &psc
->sc_sc
;
204 struct pci_attach_args
*pa
= aux
;
205 pci_chipset_tag_t pc
= pa
->pa_pc
;
207 const char *intrstr
= NULL
;
212 psc
->sc_pcitag
= pa
->pa_tag
;
214 if (!ath_pci_setup(psc
))
218 * Setup memory-mapping of PCI registers.
220 mem_type
= pci_mapreg_type(pc
, pa
->pa_tag
, BS_BAR
);
221 if (mem_type
!= PCI_MAPREG_TYPE_MEM
&&
222 mem_type
!= PCI_MAPREG_MEM_TYPE_64BIT
) {
223 aprint_error("bad pci register type %d\n", (int)mem_type
);
226 if (pci_mapreg_map(pa
, BS_BAR
, mem_type
, 0, &psc
->sc_iot
,
227 &psc
->sc_ioh
, NULL
, &psc
->sc_mapsz
)) {
228 aprint_error("cannot map register space\n");
232 sc
->sc_st
= HALTAG(psc
->sc_iot
);
233 sc
->sc_sh
= HALHANDLE(psc
->sc_ioh
);
236 * Arrange interrupt line.
238 if (pci_intr_map(pa
, &psc
->sc_pih
)) {
239 aprint_error("couldn't map interrupt\n");
243 intrstr
= pci_intr_string(pc
, psc
->sc_pih
);
244 psc
->sc_ih
= pci_intr_establish(pc
, psc
->sc_pih
, IPL_NET
, ath_intr
, sc
);
245 if (psc
->sc_ih
== NULL
) {
246 aprint_error("couldn't map interrupt\n");
251 aprint_verbose_dev(self
, "interrupting at %s\n", intrstr
);
253 sc
->sc_dmat
= pa
->pa_dmat
;
257 if (ath_attach(PCI_PRODUCT(pa
->pa_id
), sc
) != 0)
260 if (pmf_device_register(self
, ath_pci_suspend
, ath_pci_resume
)) {
261 pmf_class_network_register(self
, &sc
->sc_if
);
262 pmf_device_suspend(self
, &sc
->sc_qual
);
264 aprint_error_dev(self
, "couldn't establish power handler\n");
267 ATH_LOCK_DESTROY(sc
);
269 pci_intr_disestablish(pc
, psc
->sc_ih
);
272 bus_space_unmap(psc
->sc_iot
, psc
->sc_ioh
, psc
->sc_mapsz
);
278 ath_pci_detach(device_t self
, int flags
)
280 struct ath_pci_softc
*psc
= device_private(self
);
282 ath_detach(&psc
->sc_sc
);
283 pmf_device_deregister(self
);
284 if (psc
->sc_ih
!= NULL
)
285 pci_intr_disestablish(psc
->sc_pc
, psc
->sc_ih
);
286 bus_space_unmap(psc
->sc_iot
, psc
->sc_ioh
, psc
->sc_mapsz
);
288 ATH_LOCK_DESTROY(&psc
->sc_sc
);