1/* $NetBSD: if_rtw_pci.c,v 1.23 2014/03/29 19:28:25 christos Exp $ */
2
3/*-
4 * Copyright (c) 2004, 2005, 2010 David Young. All rights reserved.
5 *
6 * Adapted for the RTL8180 by David Young.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY David Young ``AS IS'' AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL David
21 * Young BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
23 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
28 * OF SUCH DAMAGE.
29 */
30/*-
31 * Copyright (c) 1998, 1999, 2000, 2002 The NetBSD Foundation, Inc.
32 * All rights reserved.
33 *
34 * This code is derived from software contributed to The NetBSD Foundation
35 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
36 * NASA Ames Research Center; Charles M. Hannum; and David Young.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
48 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
49 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
50 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
51 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
52 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
53 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
54 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
55 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
56 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
57 * POSSIBILITY OF SUCH DAMAGE.
58 */
59
60/*
61 * PCI bus front-end for the Realtek RTL8180 802.11 MAC/BBP chip.
62 *
63 * Derived from the ADMtek ADM8211 PCI bus front-end.
64 *
65 * Derived from the ``Tulip'' PCI bus front-end.
66 */
67
68#include <sys/cdefs.h>
69__KERNEL_RCSID(0, "$NetBSD: if_rtw_pci.c,v 1.23 2014/03/29 19:28:25 christos Exp $");
70
71#include <sys/param.h>
72#include <sys/systm.h>
73#include <sys/mbuf.h>
74#include <sys/malloc.h>
75#include <sys/kernel.h>
76#include <sys/socket.h>
77#include <sys/ioctl.h>
78#include <sys/errno.h>
79#include <sys/device.h>
80
81#include <machine/endian.h>
82
83#include <net/if.h>
84#include <net/if_dl.h>
85#include <net/if_media.h>
86#include <net/if_ether.h>
87
88#include <net80211/ieee80211_netbsd.h>
89#include <net80211/ieee80211_radiotap.h>
90#include <net80211/ieee80211_var.h>
91
92#include <sys/bus.h>
93#include <sys/intr.h>
94
95#include <dev/ic/rtwreg.h>
96#include <dev/ic/rtwvar.h>
97
98#include <dev/pci/pcivar.h>
99#include <dev/pci/pcireg.h>
100#include <dev/pci/pcidevs.h>
101
102/*
103 * PCI configuration space registers used by the RTL8180.
104 */
105#define RTW_PCI_IOBA PCI_BAR(0) /* i/o mapped base */
106#define RTW_PCI_MMBA PCI_BAR(1) /* memory mapped base */
107
108struct rtw_pci_softc {
109 struct rtw_softc psc_rtw;
110
111 pcireg_t psc_csr;
112 void *psc_ih;
113 pci_chipset_tag_t psc_pc;
114 pci_intr_handle_t psc_pih;
115 pcitag_t psc_tag;
116};
117
118static void rtw_pci_attach(device_t, device_t, void *);
119static int rtw_pci_detach(device_t, int);
120#if 0
121static void rtw_pci_funcregen(struct rtw_regs *, int);
122#endif
123static const struct rtw_pci_product *
124 rtw_pci_lookup(const struct pci_attach_args *);
125static int rtw_pci_match(device_t, cfdata_t, void *);
126static bool rtw_pci_resume(device_t, const pmf_qual_t *);
127static int rtw_pci_setup(struct rtw_pci_softc *);
128static bool rtw_pci_suspend(device_t, const pmf_qual_t *);
129
130CFATTACH_DECL3_NEW(rtw_pci, sizeof(struct rtw_pci_softc),
131 rtw_pci_match, rtw_pci_attach, rtw_pci_detach, NULL, NULL, NULL,
132 DVF_DETACH_SHUTDOWN);
133
134static const struct rtw_pci_product {
135 u_int32_t rpp_vendor; /* PCI vendor ID */
136 u_int32_t rpp_product; /* PCI product ID */
137 const char *rpp_product_name;
138} rtw_pci_products[] = {
139 { PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8180,
140 "Realtek RTL8180 802.11 MAC/BBP" },
141#ifdef RTW_DEBUG
142#if 0 /* These came from openbsd, netbsd doesn't have the definitions. */
143 { PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8185,
144 "Realtek RTL8185 802.11 MAC/BBP" },
145 { PCI_VENDOR_BELKIN2, PCI_PRODUCT_BELKIN2_F5D7010,
146 "Belkin F5D7010" },
147#endif
148#endif
149 { PCI_VENDOR_BELKIN, PCI_PRODUCT_BELKIN_F5D6001,
150 "Belkin F5D6001" },
151 { PCI_VENDOR_BELKIN, PCI_PRODUCT_BELKIN_F5D6020V3,
152 "Belkin F5D6020v3" },
153 {PCI_VENDOR_DLINK, PCI_PRODUCT_DLINK_DWL610,
154 "DWL-610 D-Link Air 802.11b (RTL8180 MAC/BBP)"},
155 { 0, 0, NULL },
156};
157
158static const struct rtw_pci_product *
159rtw_pci_lookup(const struct pci_attach_args *pa)
160{
161 const struct rtw_pci_product *rpp;
162
163 for (rpp = rtw_pci_products; rpp->rpp_product_name != NULL; rpp++) {
164 if (PCI_VENDOR(pa->pa_id) == rpp->rpp_vendor &&
165 PCI_PRODUCT(pa->pa_id) == rpp->rpp_product)
166 return rpp;
167 }
168 return NULL;
169}
170
171static int
172rtw_pci_match(device_t parent, cfdata_t match, void *aux)
173{
174 struct pci_attach_args *pa = aux;
175
176 if (rtw_pci_lookup(pa) != NULL)
177 return 1;
178
179 return 0;
180}
181
182static void
183rtw_pci_attach(device_t parent, device_t self, void *aux)
184{
185 struct rtw_pci_softc *psc = device_private(self);
186 struct rtw_softc *sc = &psc->psc_rtw;
187 struct rtw_regs *regs = &sc->sc_regs;
188 struct pci_attach_args *pa = aux;
189 const char *intrstr = NULL;
190 const struct rtw_pci_product *rpp;
191 char intrbuf[PCI_INTRSTR_LEN];
192
193 sc->sc_dev = self;
194 sc->sc_dmat = pa->pa_dmat;
195 psc->psc_pc = pa->pa_pc;
196 psc->psc_tag = pa->pa_tag;
197
198 rpp = rtw_pci_lookup(pa);
199 if (rpp == NULL) {
200 printf("\n");
201 panic("rtw_pci_attach: impossible");
202 }
203
204 /*
205 * Get revision info, and set some chip-specific variables.
206 */
207 sc->sc_rev = PCI_REVISION(pa->pa_class);
208 aprint_normal(": %s, revision %d.%d signature %08x\n",
209 rpp->rpp_product_name,
210 (sc->sc_rev >> 4) & 0xf, sc->sc_rev & 0xf,
211 pci_conf_read(psc->psc_pc, psc->psc_tag, 0x80));
212
213 /*
214 * Map the device.
215 */
216 psc->psc_csr = PCI_COMMAND_MASTER_ENABLE |
217 PCI_COMMAND_PARITY_ENABLE |
218 PCI_COMMAND_SERR_ENABLE;
219 if (pci_mapreg_map(pa, RTW_PCI_MMBA, PCI_MAPREG_TYPE_MEM, 0,
220 &regs->r_bt, &regs->r_bh, NULL, &regs->r_sz) == 0) {
221 RTW_DPRINTF(RTW_DEBUG_ATTACH,
222 ("%s: %s mapped %" PRIuMAX " bytes mem space\n",
223 device_xname(self), __func__, (uintmax_t)regs->r_sz));
224 psc->psc_csr |= PCI_COMMAND_MEM_ENABLE;
225 } else if (pci_mapreg_map(pa, RTW_PCI_IOBA, PCI_MAPREG_TYPE_IO, 0,
226 &regs->r_bt, &regs->r_bh, NULL, &regs->r_sz) == 0) {
227 RTW_DPRINTF(RTW_DEBUG_ATTACH,
228 ("%s: %s mapped %" PRIuMAX " bytes I/O space\n",
229 device_xname(self), __func__, (uintmax_t)regs->r_sz));
230 psc->psc_csr |= PCI_COMMAND_IO_ENABLE;
231 } else {
232 aprint_error_dev(self, "unable to map device registers\n");
233 return;
234 }
235
236 /*
237 * Bring the chip out of powersave mode and initialize the
238 * configuration registers.
239 */
240 if (rtw_pci_setup(psc) != 0)
241 return;
242
243 /*
244 * Map and establish our interrupt.
245 */
246 if (pci_intr_map(pa, &psc->psc_pih)) {
247 aprint_error_dev(self, "unable to map interrupt\n");
248 return;
249 }
250 intrstr = pci_intr_string(psc->psc_pc, psc->psc_pih, intrbuf, sizeof(intrbuf));
251 psc->psc_ih = pci_intr_establish(psc->psc_pc, psc->psc_pih, IPL_NET,
252 rtw_intr, sc);
253 if (psc->psc_ih == NULL) {
254 aprint_error_dev(self, "unable to establish interrupt");
255 if (intrstr != NULL)
256 aprint_error(" at %s", intrstr);
257 aprint_error("\n");
258 return;
259 }
260
261 aprint_normal_dev(self, "interrupting at %s\n", intrstr);
262
263 /*
264 * Finish off the attach.
265 */
266 rtw_attach(sc);
267
268 if (pmf_device_register(self, rtw_pci_suspend, rtw_pci_resume)) {
269 pmf_class_network_register(self, &sc->sc_if);
270 /*
271 * Power down the socket.
272 */
273 pmf_device_suspend(self, &sc->sc_qual);
274 } else
275 aprint_error_dev(self, "couldn't establish power handler\n");
276}
277
278static int
279rtw_pci_detach(device_t self, int flags)
280{
281 struct rtw_pci_softc *psc = device_private(self);
282 struct rtw_softc *sc = &psc->psc_rtw;
283 struct rtw_regs *regs = &sc->sc_regs;
284 int rc;
285
286 if ((rc = rtw_detach(sc)) != 0)
287 return rc;
288 if (psc->psc_ih != NULL)
289 pci_intr_disestablish(psc->psc_pc, psc->psc_ih);
290 bus_space_unmap(regs->r_bt, regs->r_bh, regs->r_sz);
291
292 return 0;
293}
294
295static bool
296rtw_pci_resume(device_t self, const pmf_qual_t *qual)
297{
298 struct rtw_pci_softc *psc = device_private(self);
299 struct rtw_softc *sc = &psc->psc_rtw;
300
301 /* Establish the interrupt. */
302 psc->psc_ih = pci_intr_establish(psc->psc_pc, psc->psc_pih, IPL_NET,
303 rtw_intr, sc);
304 if (psc->psc_ih == NULL) {
305 aprint_error_dev(sc->sc_dev, "unable to establish interrupt\n");
306 return false;
307 }
308
309 return rtw_resume(self, qual);
310}
311
312static bool
313rtw_pci_suspend(device_t self, const pmf_qual_t *qual)
314{
315 struct rtw_pci_softc *psc = device_private(self);
316
317 if (!rtw_suspend(self, qual))
318 return false;
319
320 /* Unhook the interrupt handler. */
321 pci_intr_disestablish(psc->psc_pc, psc->psc_ih);
322 psc->psc_ih = NULL;
323 return true;
324}
325
326static int
327rtw_pci_setup(struct rtw_pci_softc *psc)
328{
329 pcitag_t tag = psc->psc_tag;
330 pcireg_t bhlc, csr, lattimer;
331 device_t self = psc->psc_rtw.sc_dev;
332 int rc;
333
334 /* power up chip */
335 rc = pci_activate(psc->psc_pc, psc->psc_tag, self, NULL);
336
337 if (rc != 0 && rc != EOPNOTSUPP) {
338 aprint_error_dev(self, "cannot activate (%d)\n", rc);
339 return rc;
340 }
341
342 /* I believe the datasheet tries to warn us that the RTL8180
343 * wants for 16 (0x10) to divide the latency timer.
344 */
345 bhlc = pci_conf_read(psc->psc_pc, tag, PCI_BHLC_REG);
346 lattimer = rounddown(PCI_LATTIMER(bhlc), 0x10);
347 if (PCI_LATTIMER(bhlc) != lattimer) {
348 bhlc &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT);
349 bhlc |= (lattimer << PCI_LATTIMER_SHIFT);
350 pci_conf_write(psc->psc_pc, tag, PCI_BHLC_REG, bhlc);
351 }
352
353 /* Enable the appropriate bits in the PCI CSR. */
354 csr = pci_conf_read(psc->psc_pc, tag, PCI_COMMAND_STATUS_REG);
355 csr &= ~(PCI_COMMAND_IO_ENABLE|PCI_COMMAND_MEM_ENABLE);
356 csr |= psc->psc_csr;
357 pci_conf_write(psc->psc_pc, tag, PCI_COMMAND_STATUS_REG, csr);
358
359 return 0;
360}
361