Home | History | Annotate | Line # | Download | only in pci
if_ne_pci.c revision 1.12
      1 /*	$NetBSD: if_ne_pci.c,v 1.12 1998/10/31 00:27:41 thorpej Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1997, 1998 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.
     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  * 3. All advertising materials mentioning features or use of this software
     20  *    must display the following acknowledgement:
     21  *	This product includes software developed by the NetBSD
     22  *	Foundation, Inc. and its contributors.
     23  * 4. Neither the name of The NetBSD Foundation nor the names of its
     24  *    contributors may be used to endorse or promote products derived
     25  *    from this software without specific prior written permission.
     26  *
     27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     37  * POSSIBILITY OF SUCH DAMAGE.
     38  */
     39 
     40 #include "opt_inet.h"
     41 #include "bpfilter.h"
     42 
     43 #include <sys/param.h>
     44 #include <sys/systm.h>
     45 #include <sys/mbuf.h>
     46 #include <sys/syslog.h>
     47 #include <sys/socket.h>
     48 #include <sys/device.h>
     49 
     50 #include <net/if.h>
     51 #include <net/if_ether.h>
     52 #include <net/if_media.h>
     53 
     54 #ifdef INET
     55 #include <netinet/in.h>
     56 #include <netinet/if_inarp.h>
     57 #endif
     58 
     59 #include <machine/bus.h>
     60 #include <machine/intr.h>
     61 
     62 #include <dev/pci/pcireg.h>
     63 #include <dev/pci/pcivar.h>
     64 #include <dev/pci/pcidevs.h>
     65 
     66 #include <dev/ic/dp8390reg.h>
     67 #include <dev/ic/dp8390var.h>
     68 
     69 #include <dev/ic/ne2000reg.h>
     70 #include <dev/ic/ne2000var.h>
     71 
     72 #include <dev/ic/rtl80x9reg.h>
     73 
     74 struct ne_pci_softc {
     75 	struct ne2000_softc sc_ne2000;		/* real "ne2000" softc */
     76 
     77 	/* PCI-specific goo */
     78 	void *sc_ih;				/* interrupt handle */
     79 };
     80 
     81 int ne_pci_match __P((struct device *, struct cfdata *, void *));
     82 void ne_pci_attach __P((struct device *, struct device *, void *));
     83 
     84 struct cfattach ne_pci_ca = {
     85 	sizeof(struct ne_pci_softc), ne_pci_match, ne_pci_attach
     86 };
     87 
     88 /*
     89  * RealTek 8029 media support
     90  */
     91 int	ne_pci_rtl8029_mediachange __P((struct dp8390_softc *));
     92 void	ne_pci_rtl8029_mediastatus __P((struct dp8390_softc *,
     93 	    struct ifmediareq *));
     94 void	ne_pci_rtl8029_init_card __P((struct dp8390_softc *));
     95 void	ne_pci_rtl8029_init_media __P((struct ne_pci_softc *, int **,
     96 	    int *, int *));
     97 
     98 const struct ne_pci_product {
     99 	pci_vendor_id_t npp_vendor;
    100 	pci_product_id_t npp_product;
    101 	int (*npp_mediachange) __P((struct dp8390_softc *));
    102 	void (*npp_mediastatus) __P((struct dp8390_softc *,
    103 	    struct ifmediareq *));
    104 	void (*npp_init_card) __P((struct dp8390_softc *));
    105 	void (*npp_init_media) __P((struct ne_pci_softc *, int **,
    106 	    int *, int *));
    107 	const char *npp_name;
    108 } ne_pci_products[] = {
    109 	{ PCI_VENDOR_REALTEK,		PCI_PRODUCT_REALTEK_RT8029,
    110 	  ne_pci_rtl8029_mediachange,	ne_pci_rtl8029_mediastatus,
    111 	  ne_pci_rtl8029_init_card,	ne_pci_rtl8029_init_media,
    112 	  "RealTek 8029" },
    113 
    114 	{ PCI_VENDOR_WINBOND,		PCI_PRODUCT_WINBOND_W89C940F,
    115 	  NULL,				NULL,
    116 	  NULL,				NULL,
    117 	  "Winbond 89C940F" },
    118 
    119 	{ PCI_VENDOR_VIATECH,		PCI_PRODUCT_VIATECH_VT86C926,
    120 	  NULL,				NULL,
    121 	  NULL,				NULL,
    122 	  "VIA Technologies VT86C926" },
    123 
    124 	{ PCI_VENDOR_SURECOM,		PCI_PRODUCT_SURECOM_NE34,
    125 	  NULL,				NULL,
    126 	  NULL,				NULL,
    127 	  "Surecom NE-34" },
    128 
    129 	{ PCI_VENDOR_NETVIN,		PCI_PRODUCT_NETVIN_5000,
    130 	  NULL,				NULL,
    131 	  NULL,				NULL,
    132 	  "NetVin 5000" },
    133 
    134 	/* XXX The following entries need sanity checking in pcidevs */
    135 	{ PCI_VENDOR_COMPEX,		PCI_PRODUCT_COMPEX_NE2KETHER,
    136 	  NULL,				NULL,
    137 	  NULL,				NULL,
    138 	  "Compex" },
    139 
    140 	{ PCI_VENDOR_PROLAN,		PCI_PRODUCT_PROLAN_NE2KETHER,
    141 	  NULL,				NULL,
    142 	  NULL,				NULL,
    143 	  "ProLAN" },
    144 
    145 	{ PCI_VENDOR_KTI,		PCI_PRODUCT_KTI_NE2KETHER,
    146 	  NULL,				NULL,
    147 	  NULL,				NULL,
    148 	  "KTI" },
    149 
    150 	{ 0,				0,
    151 	  NULL,				NULL,
    152 	  NULL,				NULL,
    153 	  NULL },
    154 };
    155 
    156 const struct ne_pci_product *ne_pci_lookup __P((struct pci_attach_args *));
    157 
    158 const struct ne_pci_product *
    159 ne_pci_lookup(pa)
    160 	struct pci_attach_args *pa;
    161 {
    162 	const struct ne_pci_product *npp;
    163 
    164 	for (npp = ne_pci_products; npp->npp_name != NULL; npp++) {
    165 		if (PCI_VENDOR(pa->pa_id) == npp->npp_vendor &&
    166 		    PCI_PRODUCT(pa->pa_id) == npp->npp_product)
    167 			return (npp);
    168 	}
    169 	return (NULL);
    170 }
    171 
    172 /*
    173  * PCI constants.
    174  * XXX These should be in a common file!
    175  */
    176 #define PCI_CBIO	0x10		/* Configuration Base IO Address */
    177 
    178 int
    179 ne_pci_match(parent, match, aux)
    180 	struct device *parent;
    181 	struct cfdata *match;
    182 	void *aux;
    183 {
    184 	struct pci_attach_args *pa = aux;
    185 
    186 	if (ne_pci_lookup(pa) != NULL)
    187 		return (1);
    188 
    189 	return (0);
    190 }
    191 
    192 void
    193 ne_pci_attach(parent, self, aux)
    194 	struct device *parent, *self;
    195 	void *aux;
    196 {
    197 	struct ne_pci_softc *psc = (struct ne_pci_softc *)self;
    198 	struct ne2000_softc *nsc = &psc->sc_ne2000;
    199 	struct dp8390_softc *dsc = &nsc->sc_dp8390;
    200 	struct pci_attach_args *pa = aux;
    201 	pci_chipset_tag_t pc = pa->pa_pc;
    202 	bus_space_tag_t nict;
    203 	bus_space_handle_t nich;
    204 	bus_space_tag_t asict;
    205 	bus_space_handle_t asich;
    206 	const char *intrstr;
    207 	const struct ne_pci_product *npp;
    208 	pci_intr_handle_t ih;
    209 	pcireg_t csr;
    210 	int *media, nmedia, defmedia;
    211 
    212 	npp = ne_pci_lookup(pa);
    213 	if (npp == NULL) {
    214 		printf("\n");
    215 		panic("ne_pci_attach: impossible");
    216 	}
    217 
    218 	printf(": %s Ethernet\n", npp->npp_name);
    219 
    220 	if (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0,
    221 	    &nict, &nich, NULL, NULL)) {
    222 		printf("%s: can't map i/o space\n", dsc->sc_dev.dv_xname);
    223 		return;
    224 	}
    225 
    226 	asict = nict;
    227 	if (bus_space_subregion(nict, nich, NE2000_ASIC_OFFSET,
    228 	    NE2000_ASIC_NPORTS, &asich)) {
    229 		printf("%s: can't subregion i/o space\n", dsc->sc_dev.dv_xname);
    230 		return;
    231 	}
    232 
    233 	dsc->sc_regt = nict;
    234 	dsc->sc_regh = nich;
    235 
    236 	nsc->sc_asict = asict;
    237 	nsc->sc_asich = asich;
    238 
    239 	/* Enable the card. */
    240 	csr = pci_conf_read(pc, pa->pa_tag,
    241 	    PCI_COMMAND_STATUS_REG);
    242 	pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
    243 	    csr | PCI_COMMAND_MASTER_ENABLE);
    244 
    245 	/* This interface is always enabled. */
    246 	dsc->sc_enabled = 1;
    247 
    248 	if (npp->npp_init_media != NULL) {
    249 		(*npp->npp_init_media)(psc, &media, &nmedia, &defmedia);
    250 		dsc->sc_mediachange = npp->npp_mediachange;
    251 		dsc->sc_mediastatus = npp->npp_mediastatus;
    252 	} else {
    253 		media = NULL;
    254 		nmedia = 0;
    255 		defmedia = 0;
    256 	}
    257 
    258 	/* Always fill in init_card; it might be used for non-media stuff. */
    259 	dsc->init_card = npp->npp_init_card;
    260 
    261 	/*
    262 	 * Do generic NE2000 attach.  This will read the station address
    263 	 * from the EEPROM.
    264 	 */
    265 	ne2000_attach(nsc, NULL, media, nmedia, defmedia);
    266 
    267 	/* Map and establish the interrupt. */
    268 	if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin,
    269 	    pa->pa_intrline, &ih)) {
    270 		printf("%s: couldn't map interrupt\n", dsc->sc_dev.dv_xname);
    271 		return;
    272 	}
    273 	intrstr = pci_intr_string(pc, ih);
    274 	psc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, dp8390_intr, dsc);
    275 	if (psc->sc_ih == NULL) {
    276 		printf("%s: couldn't establish interrupt",
    277 		    dsc->sc_dev.dv_xname);
    278 		if (intrstr != NULL)
    279 			printf(" at %s", intrstr);
    280 		printf("\n");
    281 		return;
    282 	}
    283 	printf("%s: interrupting at %s\n", dsc->sc_dev.dv_xname, intrstr);
    284 }
    285 
    286 /*
    287  * RealTek 8029 media support
    288  */
    289 
    290 int
    291 ne_pci_rtl8029_mediachange(dsc)
    292 	struct dp8390_softc *dsc;
    293 {
    294 
    295 	/*
    296 	 * Current media is already set up.  Just reset the interface
    297 	 * to let the new value take hold.  The new media will be
    298 	 * set up in ne_pci_rtl8029_init_card() called via dp8390_init().
    299 	 */
    300 	dp8390_reset(dsc);
    301 	return (0);
    302 }
    303 
    304 void
    305 ne_pci_rtl8029_mediastatus(sc, ifmr)
    306 	struct dp8390_softc *sc;
    307 	struct ifmediareq *ifmr;
    308 {
    309 	struct ifnet *ifp = &sc->sc_ec.ec_if;
    310 	u_int8_t cr_proto = sc->cr_proto |
    311 	    ((ifp->if_flags & IFF_RUNNING) ? ED_CR_STA : ED_CR_STP);
    312 
    313 	/*
    314 	 * Sigh, can detect which media is being used, but can't
    315 	 * detect if we have link or not.
    316 	 */
    317 
    318 	/* Set NIC to page 3 registers. */
    319 	NIC_PUT(sc->sc_regt, sc->sc_regh, ED_P0_CR, cr_proto | ED_CR_PAGE_3);
    320 
    321 	if (NIC_GET(sc->sc_regt, sc->sc_regh, NERTL_RTL3_CONFIG0) &
    322 	    RTL3_CONFIG0_BNC)
    323 		ifmr->ifm_active = IFM_ETHER|IFM_10_2;
    324 	else {
    325 		ifmr->ifm_active = IFM_ETHER|IFM_10_T;
    326 		if (NIC_GET(sc->sc_regt, sc->sc_regh, NERTL_RTL3_CONFIG3) &
    327 		    RTL3_CONFIG3_FUDUP)
    328 			ifmr->ifm_active |= IFM_FDX;
    329 	}
    330 
    331 	/* Set NIC to page 0 registers. */
    332 	NIC_PUT(sc->sc_regt, sc->sc_regh, ED_P0_CR, cr_proto | ED_CR_PAGE_0);
    333 }
    334 
    335 void
    336 ne_pci_rtl8029_init_card(sc)
    337 	struct dp8390_softc *sc;
    338 {
    339 	struct ifmedia *ifm = &sc->sc_media;
    340 	struct ifnet *ifp = &sc->sc_ec.ec_if;
    341 	u_int8_t cr_proto = sc->cr_proto |
    342 	    ((ifp->if_flags & IFF_RUNNING) ? ED_CR_STA : ED_CR_STP);
    343 	u_int8_t reg;
    344 
    345 	/* Set NIC to page 3 registers. */
    346 	NIC_PUT(sc->sc_regt, sc->sc_regh, ED_P0_CR, cr_proto | ED_CR_PAGE_3);
    347 
    348 	/* First, set basic media type. */
    349 	reg = NIC_GET(sc->sc_regt, sc->sc_regh, NERTL_RTL3_CONFIG2);
    350 	reg &= ~(RTL3_CONFIG2_PL1|RTL3_CONFIG2_PL0);
    351 	switch (IFM_SUBTYPE(ifm->ifm_cur->ifm_media)) {
    352 	case IFM_AUTO:
    353 		/* Nothing to do; both bits clear == auto-detect. */
    354 		break;
    355 
    356 	case IFM_10_T:
    357 		reg |= RTL3_CONFIG2_PL0;
    358 		break;
    359 
    360 	case IFM_10_2:
    361 		reg |= RTL3_CONFIG2_PL1|RTL3_CONFIG2_PL0;
    362 		break;
    363 	}
    364 	NIC_PUT(sc->sc_regt, sc->sc_regh, NERTL_RTL3_CONFIG2, reg);
    365 
    366 	/* Now, set duplex mode. */
    367 	reg = NIC_GET(sc->sc_regt, sc->sc_regh, NERTL_RTL3_CONFIG3);
    368 	if (ifm->ifm_cur->ifm_media & IFM_FDX)
    369 		reg |= RTL3_CONFIG3_FUDUP;
    370 	else
    371 		reg &= ~RTL3_CONFIG3_FUDUP;
    372 	NIC_PUT(sc->sc_regt, sc->sc_regh, NERTL_RTL3_CONFIG3, reg);
    373 
    374 	/* Set NIC to page 0 registers. */
    375 	NIC_PUT(sc->sc_regt, sc->sc_regh, ED_P0_CR, cr_proto | ED_CR_PAGE_0);
    376 }
    377 
    378 void
    379 ne_pci_rtl8029_init_media(psc, mediap, nmediap, defmediap)
    380 	struct ne_pci_softc *psc;
    381 	int **mediap, *nmediap, *defmediap;
    382 {
    383 	static int rtl8029_media[] = {
    384 		IFM_ETHER|IFM_AUTO,
    385 		IFM_ETHER|IFM_10_T,
    386 		IFM_ETHER|IFM_10_T|IFM_FDX,
    387 		IFM_ETHER|IFM_10_2,
    388 	};
    389 
    390 	printf("%s: 10base2, 10baseT, 10baseT-FDX, auto, default auto\n",
    391 	    psc->sc_ne2000.sc_dp8390.sc_dev.dv_xname);
    392 
    393 	*mediap = rtl8029_media;
    394 	*nmediap = sizeof(rtl8029_media) / sizeof(rtl8029_media[0]);
    395 	*defmediap = IFM_ETHER|IFM_AUTO;
    396 }
    397