1/* $NetBSD: if_ne_pci.c,v 1.35 2011/05/17 17:34:54 dyoung 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 * 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#include <sys/cdefs.h> 34__KERNEL_RCSID(0, "$NetBSD: if_ne_pci.c,v 1.35 2011/05/17 17:34:54 dyoung Exp $"); 35 36#include "opt_ipkdb.h" 37 38#include <sys/param.h> 39#include <sys/systm.h> 40#include <sys/mbuf.h> 41#include <sys/syslog.h> 42#include <sys/socket.h> 43#include <sys/device.h> 44 45#include <net/if.h> 46#include <net/if_ether.h> 47#include <net/if_media.h> 48 49#include <sys/bus.h> 50#include <sys/intr.h> 51 52#ifdef IPKDB_NE_PCI 53#include <ipkdb/ipkdb.h> 54#endif 55 56#include <dev/pci/pcireg.h> 57#include <dev/pci/pcivar.h> 58#include <dev/pci/pcidevs.h> 59 60#include <dev/ic/dp8390reg.h> 61#include <dev/ic/dp8390var.h> 62 63#include <dev/ic/ne2000reg.h> 64#include <dev/ic/ne2000var.h> 65 66#include <dev/ic/rtl80x9reg.h> 67#include <dev/ic/rtl80x9var.h> 68 69struct ne_pci_softc { 70 struct ne2000_softc sc_ne2000; /* real "ne2000" softc */ 71 72 /* PCI-specific goo */ 73 void *sc_ih; /* interrupt handle */ 74}; 75 76static int ne_pci_match(device_t, cfdata_t, void *); 77static void ne_pci_attach(device_t, device_t, void *); 78 79CFATTACH_DECL_NEW(ne_pci, sizeof(struct ne_pci_softc), 80 ne_pci_match, ne_pci_attach, NULL, NULL); 81 82#ifdef IPKDB_NE_PCI 83static struct ne_pci_softc ipkdb_softc; 84static pci_chipset_tag_t ipkdb_pc; 85static pcitag_t ipkdb_tag; 86static struct ipkdb_if *ne_kip; 87 88int ne_pci_ipkdb_attach(struct ipkdb_if *, bus_space_tag_t, /* XXX */ 89 pci_chipset_tag_t, int, int); 90 91static int ne_pci_isipkdb(pci_chipset_tag_t, pcitag_t); 92#endif 93 94static const struct ne_pci_product { 95 pci_vendor_id_t npp_vendor; 96 pci_product_id_t npp_product; 97 int (*npp_mediachange)(struct dp8390_softc *); 98 void (*npp_mediastatus)(struct dp8390_softc *, struct ifmediareq *); 99 void (*npp_init_card)(struct dp8390_softc *); 100 void (*npp_media_init)(struct dp8390_softc *); 101 const char *npp_name; 102} ne_pci_products[] = { 103 { PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8029, 104 rtl80x9_mediachange, rtl80x9_mediastatus, 105 rtl80x9_init_card, rtl80x9_media_init, 106 "Realtek 8029" }, 107 108 { PCI_VENDOR_WINBOND, PCI_PRODUCT_WINBOND_W89C940F, 109 NULL, NULL, 110 NULL, NULL, 111 "Winbond 89C940F" }, 112 113 { PCI_VENDOR_WINBOND, PCI_PRODUCT_WINBOND_W89C940F_1, 114 NULL, NULL, 115 NULL, NULL, 116 "Winbond 89C940F" }, 117 118 { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT86C926, 119 NULL, NULL, 120 NULL, NULL, 121 "VIA Technologies VT86C926" }, 122 123 { PCI_VENDOR_SURECOM, PCI_PRODUCT_SURECOM_NE34, 124 NULL, NULL, 125 NULL, NULL, 126 "Surecom NE-34" }, 127 128 { PCI_VENDOR_NETVIN, PCI_PRODUCT_NETVIN_5000, 129 NULL, NULL, 130 NULL, NULL, 131 "NetVin 5000" }, 132 133 /* XXX The following entries need sanity checking in pcidevs */ 134 { PCI_VENDOR_COMPEX, PCI_PRODUCT_COMPEX_NE2KETHER, 135 NULL, NULL, 136 NULL, NULL, 137 "Compex" }, 138 139 { PCI_VENDOR_PROLAN, PCI_PRODUCT_PROLAN_NE2KETHER, 140 NULL, NULL, 141 NULL, NULL, 142 "ProLAN" }, 143 144 { PCI_VENDOR_KTI, PCI_PRODUCT_KTI_NE2KETHER, 145 NULL, NULL, 146 NULL, NULL, 147 "KTI" }, 148 149 { 0, 0, 150 NULL, NULL, 151 NULL, NULL, 152 NULL }, 153}; 154 155static const struct ne_pci_product * 156ne_pci_lookup(const struct pci_attach_args *pa) 157{ 158 const struct ne_pci_product *npp; 159 160 for (npp = ne_pci_products; npp->npp_name != NULL; npp++) { 161 if (PCI_VENDOR(pa->pa_id) == npp->npp_vendor && 162 PCI_PRODUCT(pa->pa_id) == npp->npp_product) 163 return (npp); 164 } 165 return (NULL); 166} 167 168/* 169 * PCI constants. 170 * XXX These should be in a common file! 171 */ 172#define PCI_CBIO PCI_BAR(0) /* Configuration Base IO Address */ 173 174static int 175ne_pci_match(device_t parent, cfdata_t match, void *aux) 176{ 177 struct pci_attach_args *pa = aux; 178 179 if (ne_pci_lookup(pa) != NULL) 180 return (1); 181 182 return (0); 183} 184 185static void 186ne_pci_attach(device_t parent, device_t self, void *aux) 187{ 188 struct ne_pci_softc *psc = device_private(self); 189 struct ne2000_softc *nsc = &psc->sc_ne2000; 190 struct dp8390_softc *dsc = &nsc->sc_dp8390; 191 struct pci_attach_args *pa = aux; 192 pci_chipset_tag_t pc = pa->pa_pc; 193 bus_space_tag_t nict; 194 bus_space_handle_t nich; 195 bus_space_tag_t asict; 196 bus_space_handle_t asich; 197 const char *intrstr; 198 const struct ne_pci_product *npp; 199 pci_intr_handle_t ih; 200 pcireg_t csr; 201 202 npp = ne_pci_lookup(pa); 203 if (npp == NULL) { 204 printf("\n"); 205 panic("ne_pci_attach: impossible"); 206 } 207 208 dsc->sc_dev = self; 209 210 printf(": %s Ethernet\n", npp->npp_name); 211 212#ifdef IPKDB_NE_PCI 213 if (ne_pci_isipkdb(pc, pa->pa_tag)) { 214 nict = ipkdb_softc.sc_ne2000.sc_dp8390.sc_regt; 215 nich = ipkdb_softc.sc_ne2000.sc_dp8390.sc_regh; 216 ne_kip->port = nsc; 217 } else 218#endif 219 if (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0, 220 &nict, &nich, NULL, NULL)) { 221 aprint_error_dev(dsc->sc_dev, "can't map i/o space\n"); 222 return; 223 } 224 225 asict = nict; 226 if (bus_space_subregion(nict, nich, NE2000_ASIC_OFFSET, 227 NE2000_ASIC_NPORTS, &asich)) { 228 aprint_error_dev(dsc->sc_dev, "can't subregion i/o space\n"); 229 return; 230 } 231 232 dsc->sc_regt = nict; 233 dsc->sc_regh = nich; 234 235 nsc->sc_asict = asict; 236 nsc->sc_asich = asich; 237 238 /* Enable the card. */ 239 csr = pci_conf_read(pc, pa->pa_tag, 240 PCI_COMMAND_STATUS_REG); 241 pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, 242 csr | PCI_COMMAND_MASTER_ENABLE); 243 244 /* This interface is always enabled. */ 245 dsc->sc_enabled = 1; 246 247 dsc->sc_mediachange = npp->npp_mediachange; 248 dsc->sc_mediastatus = npp->npp_mediastatus; 249 dsc->sc_media_init = npp->npp_media_init; 250 dsc->init_card = npp->npp_init_card; 251 252 /* 253 * Do generic NE2000 attach. This will read the station address 254 * from the EEPROM. 255 */ 256 ne2000_attach(nsc, NULL); 257 258 /* Map and establish the interrupt. */ 259 if (pci_intr_map(pa, &ih)) { 260 aprint_error_dev(dsc->sc_dev, "couldn't map interrupt\n"); 261 return; 262 } 263 intrstr = pci_intr_string(pc, ih); 264 psc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, dp8390_intr, dsc); 265 if (psc->sc_ih == NULL) { 266 aprint_error_dev(dsc->sc_dev, "couldn't establish interrupt"); 267 if (intrstr != NULL) 268 aprint_error(" at %s", intrstr); 269 aprint_error("\n"); 270 return; 271 } 272 aprint_normal_dev(dsc->sc_dev, "interrupting at %s\n", intrstr); 273} 274 275#ifdef IPKDB_NE_PCI 276static int 277ne_pci_isipkdb(pci_chipset_tag_t pc, pcitag_t tag) 278{ 279 return !memcmp(&pc, &ipkdb_pc, sizeof pc) 280 && !memcmp(&tag, &ipkdb_tag, sizeof tag); 281} 282 283int 284ne_pci_ipkdb_attach(struct ipkdb_if *kip, bus_space_tag_t iot, 285 pci_chipset_tag_t pc, int bus, int dev) 286{ 287 struct pci_attach_args pa; 288 bus_space_tag_t nict, asict; 289 bus_space_handle_t nich, asich; 290 u_int32_t csr; 291 292 pa.pa_iot = iot; 293 pa.pa_pc = pc; 294 pa.pa_device = dev; 295 pa.pa_function = 0; 296 pa.pa_flags = PCI_FLAGS_IO_OKAY; 297 pa.pa_tag = pci_make_tag(pc, bus, dev, /*func*/0); 298 pa.pa_id = pci_conf_read(pc, pa.pa_tag, PCI_ID_REG); 299 pa.pa_class = pci_conf_read(pc, pa.pa_tag, PCI_CLASS_REG); 300 if (ne_pci_lookup(&pa) == NULL) 301 return -1; 302 303 if (pci_mapreg_map(&pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0, 304 &nict, &nich, NULL, NULL)) 305 return -1; 306 307 asict = nict; 308 if (bus_space_subregion(nict, nich, NE2000_ASIC_OFFSET, 309 NE2000_ASIC_NPORTS, &asich)) { 310 bus_space_unmap(nict, nich, NE2000_NPORTS); 311 return -1; 312 } 313 314 /* Enable card */ 315 csr = pci_conf_read(pc, pa.pa_tag, PCI_COMMAND_STATUS_REG); 316 pci_conf_write(pc, pa.pa_tag, PCI_COMMAND_STATUS_REG, 317 csr | PCI_COMMAND_MASTER_ENABLE); 318 319 ipkdb_softc.sc_ne2000.sc_dp8390.sc_regt = nict; 320 ipkdb_softc.sc_ne2000.sc_dp8390.sc_regh = nich; 321 ipkdb_softc.sc_ne2000.sc_asict = asict; 322 ipkdb_softc.sc_ne2000.sc_asich = asich; 323 324 kip->port = &ipkdb_softc; 325 ipkdb_pc = pc; 326 ipkdb_tag = pa.pa_tag; 327 ne_kip = kip; 328 329 if (ne2000_ipkdb_attach(kip) < 0) { 330 bus_space_unmap(nict, nich, NE2000_NPORTS); 331 return -1; 332 } 333 334 return 0; 335} 336#endif /* IPKDB_NE_PCI */ 337