Home | History | Annotate | Line # | Download | only in pci
if_rtw_pci.c revision 1.16.2.1
      1 /*	$NetBSD: if_rtw_pci.c,v 1.16.2.1 2010/04/30 14:43:37 uebayasi Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1998, 1999, 2000, 2002 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
      9  * NASA Ames Research Center; Charles M. Hannum; and David Young.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  * 2. Redistributions in binary form must reproduce the above copyright
     17  *    notice, this list of conditions and the following disclaimer in the
     18  *    documentation and/or other materials provided with the distribution.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30  * POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 /*
     34  * PCI bus front-end for the Realtek RTL8180 802.11 MAC/BBP chip.
     35  *
     36  * Derived from the ADMtek ADM8211 PCI bus front-end.
     37  *
     38  * Derived from the ``Tulip'' PCI bus front-end.
     39  */
     40 
     41 #include <sys/cdefs.h>
     42 __KERNEL_RCSID(0, "$NetBSD: if_rtw_pci.c,v 1.16.2.1 2010/04/30 14:43:37 uebayasi Exp $");
     43 
     44 #include <sys/param.h>
     45 #include <sys/systm.h>
     46 #include <sys/mbuf.h>
     47 #include <sys/malloc.h>
     48 #include <sys/kernel.h>
     49 #include <sys/socket.h>
     50 #include <sys/ioctl.h>
     51 #include <sys/errno.h>
     52 #include <sys/device.h>
     53 
     54 #include <machine/endian.h>
     55 
     56 #include <net/if.h>
     57 #include <net/if_dl.h>
     58 #include <net/if_media.h>
     59 #include <net/if_ether.h>
     60 
     61 #include <net80211/ieee80211_netbsd.h>
     62 #include <net80211/ieee80211_radiotap.h>
     63 #include <net80211/ieee80211_var.h>
     64 
     65 #include <sys/bus.h>
     66 #include <sys/intr.h>
     67 
     68 #include <dev/ic/rtwreg.h>
     69 #include <dev/ic/rtwvar.h>
     70 
     71 #include <dev/pci/pcivar.h>
     72 #include <dev/pci/pcireg.h>
     73 #include <dev/pci/pcidevs.h>
     74 
     75 /*
     76  * PCI configuration space registers used by the RTL8180.
     77  */
     78 #define	RTW_PCI_IOBA		0x10	/* i/o mapped base */
     79 #define	RTW_PCI_MMBA		0x14	/* memory mapped base */
     80 
     81 struct rtw_pci_softc {
     82 	struct rtw_softc	psc_rtw;	/* real RTL8180 softc */
     83 
     84 	pci_intr_handle_t	psc_ih;		/* interrupt handle */
     85 	void			*psc_intrcookie;
     86 
     87 	pci_chipset_tag_t	psc_pc;		/* our PCI chipset */
     88 	pcitag_t		psc_pcitag;	/* our PCI tag */
     89 };
     90 
     91 static int	rtw_pci_match(device_t, cfdata_t, void *);
     92 static void	rtw_pci_attach(device_t, device_t, void *);
     93 static int	rtw_pci_detach(device_t, int);
     94 
     95 CFATTACH_DECL_NEW(rtw_pci, sizeof(struct rtw_pci_softc),
     96     rtw_pci_match, rtw_pci_attach, rtw_pci_detach, NULL);
     97 
     98 static bool rtw_pci_resume(device_t, const pmf_qual_t *);
     99 static bool rtw_pci_suspend(device_t, const pmf_qual_t *);
    100 
    101 static const struct rtw_pci_product {
    102 	u_int32_t	app_vendor;	/* PCI vendor ID */
    103 	u_int32_t	app_product;	/* PCI product ID */
    104 	const char	*app_product_name;
    105 } rtw_pci_products[] = {
    106 	{ PCI_VENDOR_REALTEK,		PCI_PRODUCT_REALTEK_RT8180,
    107 	  "Realtek RTL8180 802.11 MAC/BBP" },
    108 	{ PCI_VENDOR_BELKIN,		PCI_PRODUCT_BELKIN_F5D6001,
    109 	  "Belkin F5D6001" },
    110 
    111 	{ 0,				0,				NULL },
    112 };
    113 
    114 static const struct rtw_pci_product *
    115 rtw_pci_lookup(const struct pci_attach_args *pa)
    116 {
    117 	const struct rtw_pci_product *app;
    118 
    119 	for (app = rtw_pci_products;
    120 	     app->app_product_name != NULL;
    121 	     app++) {
    122 		if (PCI_VENDOR(pa->pa_id) == app->app_vendor &&
    123 		    PCI_PRODUCT(pa->pa_id) == app->app_product)
    124 			return (app);
    125 	}
    126 	return (NULL);
    127 }
    128 
    129 static int
    130 rtw_pci_match(device_t parent, cfdata_t match, void *aux)
    131 {
    132 	struct pci_attach_args *pa = aux;
    133 
    134 	if (rtw_pci_lookup(pa) != NULL)
    135 		return (1);
    136 
    137 	return (0);
    138 }
    139 
    140 static void
    141 rtw_pci_attach(device_t parent, device_t self, void *aux)
    142 {
    143 	struct rtw_pci_softc *psc = device_private(self);
    144 	struct rtw_softc *sc = &psc->psc_rtw;
    145 	struct rtw_regs *regs = &sc->sc_regs;
    146 	struct pci_attach_args *pa = aux;
    147 	pci_chipset_tag_t pc = pa->pa_pc;
    148 	const char *intrstr = NULL;
    149 	const struct rtw_pci_product *app;
    150 	int error;
    151 
    152 	sc->sc_dev = self;
    153 	psc->psc_pc = pa->pa_pc;
    154 	psc->psc_pcitag = pa->pa_tag;
    155 
    156 	app = rtw_pci_lookup(pa);
    157 	if (app == NULL) {
    158 		printf("\n");
    159 		panic("rtw_pci_attach: impossible");
    160 	}
    161 
    162 	/*
    163 	 * Get revision info, and set some chip-specific variables.
    164 	 */
    165 	sc->sc_rev = PCI_REVISION(pa->pa_class);
    166 	aprint_normal(": %s, revision %d.%d\n", app->app_product_name,
    167 	    (sc->sc_rev >> 4) & 0xf, sc->sc_rev & 0xf);
    168 
    169 	/* power up chip */
    170 	if ((error = pci_activate(pa->pa_pc, pa->pa_tag, self, NULL)) != 0 &&
    171 	    error != EOPNOTSUPP) {
    172 		aprint_error_dev(self, "cannot activate %d\n", error);
    173 		return;
    174 	}
    175 
    176 	/*
    177 	 * Map the device.
    178 	 */
    179 	if (pci_mapreg_map(pa, RTW_PCI_MMBA,
    180 	    PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT, 0,
    181 	    &regs->r_bt, &regs->r_bh, NULL, &regs->r_sz) == 0)
    182 		;
    183 	else if (pci_mapreg_map(pa, RTW_PCI_IOBA, PCI_MAPREG_TYPE_IO, 0,
    184 	    &regs->r_bt, &regs->r_bh, NULL, &regs->r_sz) == 0)
    185 		;
    186 	else {
    187 		aprint_error_dev(self, "unable to map device registers\n");
    188 		return;
    189 	}
    190 
    191 	sc->sc_dmat = pa->pa_dmat;
    192 
    193 	/*
    194 	 * Make sure bus mastering is enabled.
    195 	 */
    196 	pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
    197 	    pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG) |
    198 	    PCI_COMMAND_MASTER_ENABLE);
    199 
    200 	/*
    201 	 * Map and establish our interrupt.
    202 	 */
    203 	if (pci_intr_map(pa, &psc->psc_ih)) {
    204 		aprint_error_dev(self, "unable to map interrupt\n");
    205 		return;
    206 	}
    207 	intrstr = pci_intr_string(pc, psc->psc_ih);
    208 	psc->psc_intrcookie = pci_intr_establish(pc, psc->psc_ih, IPL_NET,
    209 	    rtw_intr, sc);
    210 	if (psc->psc_intrcookie == NULL) {
    211 		aprint_error_dev(self, "unable to establish interrupt");
    212 		if (intrstr != NULL)
    213 			aprint_error(" at %s", intrstr);
    214 		aprint_error("\n");
    215 		return;
    216 	}
    217 
    218 	aprint_normal_dev(self, "interrupting at %s\n", intrstr);
    219 
    220 	/*
    221 	 * Finish off the attach.
    222 	 */
    223 	rtw_attach(sc);
    224 
    225 	if (pmf_device_register(sc->sc_dev, rtw_pci_suspend, rtw_pci_resume)) {
    226 		pmf_class_network_register(self, &sc->sc_if);
    227 		/*
    228 		 * Power down the socket.
    229 		 */
    230 		pmf_device_suspend(sc->sc_dev, &sc->sc_qual);
    231 	} else
    232 		aprint_error_dev(sc->sc_dev,
    233 		    "couldn't establish power handler\n");
    234 }
    235 
    236 static int
    237 rtw_pci_detach(device_t self, int flags)
    238 {
    239 	struct rtw_pci_softc *psc = device_private(self);
    240 	struct rtw_softc *sc = &psc->psc_rtw;
    241 	struct rtw_regs *regs = &sc->sc_regs;
    242 	int rc;
    243 
    244 	if ((rc = rtw_detach(sc)) != 0)
    245 		return rc;
    246 	if (psc->psc_intrcookie != NULL)
    247 		pci_intr_disestablish(psc->psc_pc, psc->psc_intrcookie);
    248 	bus_space_unmap(regs->r_bt, regs->r_bh, regs->r_sz);
    249 
    250 	return 0;
    251 }
    252 
    253 static bool
    254 rtw_pci_resume(device_t self, const pmf_qual_t *qual)
    255 {
    256 	struct rtw_pci_softc *psc = device_private(self);
    257 	struct rtw_softc *sc = &psc->psc_rtw;
    258 
    259 	/* Establish the interrupt. */
    260 	psc->psc_intrcookie = pci_intr_establish(psc->psc_pc, psc->psc_ih,
    261 	    IPL_NET, rtw_intr, sc);
    262 	if (psc->psc_intrcookie == NULL) {
    263 		aprint_error_dev(sc->sc_dev, "unable to establish interrupt\n");
    264 		return false;
    265 	}
    266 
    267 	return rtw_resume(self, qual);
    268 }
    269 
    270 static bool
    271 rtw_pci_suspend(device_t self, const pmf_qual_t *qual)
    272 {
    273 	struct rtw_pci_softc *psc = device_private(self);
    274 
    275 	if (!rtw_suspend(self, qual))
    276 		return false;
    277 
    278 	/* Unhook the interrupt handler. */
    279 	pci_intr_disestablish(psc->psc_pc, psc->psc_intrcookie);
    280 	psc->psc_intrcookie = NULL;
    281 	return true;
    282 }
    283