if_en_pci.c revision 114018
1/* $NetBSD: if_en_pci.c,v 1.1 1996/06/22 02:00:31 chuck Exp $ */ 2 3/* 4 * 5 * Copyright (c) 1996 Charles D. Cranor and Washington University. 6 * All rights reserved. 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 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Charles D. Cranor and 19 * Washington University. 20 * 4. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 * 34 * $FreeBSD: head/sys/dev/en/if_en_pci.c 114018 2003-04-25 16:14:03Z harti $ 35 */ 36 37/* 38 * 39 * i f _ e n _ p c i . c 40 * 41 * author: Chuck Cranor <chuck@ccrc.wustl.edu> 42 * started: spring, 1996. 43 * 44 * FreeBSD PCI glue for the eni155p card. 45 * thanks to Matt Thomas for figuring out FreeBSD vs NetBSD vs etc.. diffs. 46 */ 47#include <sys/param.h> 48#include <sys/kernel.h> 49#include <sys/systm.h> 50#include <sys/socket.h> 51#include <sys/sysctl.h> 52 53#include <sys/bus.h> 54#include <machine/bus.h> 55#include <sys/rman.h> 56#include <machine/resource.h> 57 58#include <vm/uma.h> 59 60#include <net/if.h> 61#include <net/if_atm.h> 62 63#include <pci/pcivar.h> 64#include <pci/pcireg.h> 65 66#include <dev/en/midwayreg.h> 67#include <dev/en/midwayvar.h> 68 69/* 70 * local structures 71 */ 72struct en_pci_softc { 73 /* bus independent stuff */ 74 struct en_softc esc; /* includes "device" structure */ 75 76 /* freebsd newbus glue */ 77 struct resource *res; /* resource descriptor for registers */ 78 struct resource *irq; /* resource descriptor for interrupt */ 79 void *ih; /* interrupt handle */ 80}; 81 82static void eni_get_macaddr(device_t, struct en_pci_softc *); 83static void adp_get_macaddr(struct en_pci_softc *); 84 85/* 86 * address of config base memory address register in PCI config space 87 * (this is card specific) 88 */ 89#define PCI_CBMA 0x10 90 91/* 92 * tonga (pci bridge). ENI cards only! 93 */ 94#define EN_TONGA 0x60 /* PCI config addr of tonga reg */ 95 96#define TONGA_SWAP_DMA 0x80 /* endian swap control */ 97#define TONGA_SWAP_BYTE 0x40 98#define TONGA_SWAP_WORD 0x20 99#define TONGA_READ_MULT 0x00 100#define TONGA_READ_MEM 0x04 101#define TONGA_READ_IVAN 0x08 102#define TONGA_READ_KEN 0x0C 103 104/* 105 * adaptec pci bridge. ADP cards only! 106 */ 107#define ADP_PCIREG 0x050040 /* PCI control register */ 108 109#define ADP_PCIREG_RESET 0x1 /* reset card */ 110#define ADP_PCIREG_IENABLE 0x2 /* interrupt enable */ 111#define ADP_PCIREG_SWAP_WORD 0x4 /* swap byte on slave access */ 112#define ADP_PCIREG_SWAP_DMA 0x8 /* swap byte on DMA */ 113 114#define PCI_VENDOR_EFFICIENTNETS 0x111a /* Efficent Networks */ 115#define PCI_PRODUCT_EFFICIENTNETS_ENI155PF 0x0000 /* ENI-155P ATM */ 116#define PCI_PRODUCT_EFFICIENTNETS_ENI155PA 0x0002 /* ENI-155P ATM */ 117#define PCI_VENDOR_ADP 0x9004 /* adaptec */ 118#define PCI_PRODUCT_ADP_AIC5900 0x5900 119#define PCI_PRODUCT_ADP_AIC5905 0x5905 120#define PCI_VENDOR(x) ((x) & 0xFFFF) 121#define PCI_CHIPID(x) (((x) >> 16) & 0xFFFF) 122 123/* 124 * bus specific reset function [ADP only!] 125 */ 126static void 127adp_busreset(void *v) 128{ 129 struct en_softc *sc = (struct en_softc *)v; 130 uint32_t dummy; 131 132 bus_space_write_4(sc->en_memt, sc->en_base, ADP_PCIREG, 133 ADP_PCIREG_RESET); 134 DELAY(1000); /* let it reset */ 135 dummy = bus_space_read_4(sc->en_memt, sc->en_base, ADP_PCIREG); 136 bus_space_write_4(sc->en_memt, sc->en_base, ADP_PCIREG, 137 (ADP_PCIREG_SWAP_DMA | ADP_PCIREG_IENABLE)); 138 dummy = bus_space_read_4(sc->en_memt, sc->en_base, ADP_PCIREG); 139 if ((dummy & (ADP_PCIREG_SWAP_WORD | ADP_PCIREG_SWAP_DMA)) != 140 ADP_PCIREG_SWAP_DMA) 141 if_printf(&sc->enif, "adp_busreset: Adaptec ATM did " 142 "NOT reset!\n"); 143} 144 145/***********************************************************************/ 146 147/* 148 * autoconfig stuff 149 */ 150static int 151en_pci_probe(device_t dev) 152{ 153 switch (pci_get_vendor(dev)) { 154 155 case PCI_VENDOR_EFFICIENTNETS: 156 switch (pci_get_device(dev)) { 157 158 case PCI_PRODUCT_EFFICIENTNETS_ENI155PF: 159 case PCI_PRODUCT_EFFICIENTNETS_ENI155PA: 160 device_set_desc(dev, "Efficient Networks ENI-155p"); 161 return (0); 162 } 163 break; 164 165 case PCI_VENDOR_ADP: 166 switch (pci_get_device(dev)) { 167 168 case PCI_PRODUCT_ADP_AIC5900: 169 case PCI_PRODUCT_ADP_AIC5905: 170 device_set_desc(dev, "Adaptec 155 ATM"); 171 return (0); 172 } 173 break; 174 } 175 return (ENXIO); 176} 177 178static int 179en_pci_attach(device_t dev) 180{ 181 struct en_softc *sc; 182 struct en_pci_softc *scp; 183 u_long val; 184 int rid, unit, error = 0; 185 186 sc = device_get_softc(dev); 187 scp = (struct en_pci_softc *)sc; 188 189 unit = device_get_unit(dev); 190 sc->enif.if_unit = unit; 191 sc->enif.if_name = "en"; 192 193 /* 194 * Enable bus mastering. 195 */ 196 val = pci_read_config(dev, PCIR_COMMAND, 2); 197 val |= (PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); 198 pci_write_config(dev, PCIR_COMMAND, val, 2); 199 200 /* 201 * Map control/status registers. 202 */ 203 rid = PCI_CBMA; 204 scp->res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 205 0, ~0, 1, RF_ACTIVE); 206 if (scp->res == NULL) { 207 device_printf(dev, "could not map memory\n"); 208 error = ENXIO; 209 goto fail; 210 } 211 212 sc->dev = dev; 213 sc->en_memt = rman_get_bustag(scp->res); 214 sc->en_base = rman_get_bushandle(scp->res); 215 216 /* 217 * Allocate our interrupt. 218 */ 219 rid = 0; 220 scp->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, 221 RF_SHAREABLE | RF_ACTIVE); 222 if (scp->irq == NULL) { 223 device_printf(dev, "could not map interrupt\n"); 224 bus_release_resource(dev, SYS_RES_MEMORY, PCI_CBMA, scp->res); 225 error = ENXIO; 226 goto fail; 227 } 228 229 sc->ipl = 1; /* XXX (required to enable interrupt on midway) */ 230 231 /* figure out if we are an adaptec card or not */ 232 sc->is_adaptec = (pci_get_vendor(dev) == PCI_VENDOR_ADP) ? 1 : 0; 233 234 /* 235 * set up pci bridge 236 */ 237 if (sc->is_adaptec) { 238 adp_get_macaddr(scp); 239 sc->en_busreset = adp_busreset; 240 adp_busreset(sc); 241 } else { 242 eni_get_macaddr(dev, scp); 243 sc->en_busreset = NULL; 244 pci_write_config(dev, EN_TONGA, TONGA_SWAP_DMA | TONGA_READ_IVAN, 4); 245 } 246 247 /* 248 * Common attach stuff 249 */ 250 if ((error = en_attach(sc)) != 0) { 251 device_printf(dev, "attach failed\n"); 252 bus_teardown_intr(dev, scp->irq, scp->ih); 253 bus_release_resource(dev, SYS_RES_IRQ, 0, scp->irq); 254 bus_release_resource(dev, SYS_RES_MEMORY, PCI_CBMA, scp->res); 255 goto fail; 256 } 257 258 /* 259 * Do the interrupt SETUP last just before returning 260 */ 261 error = bus_setup_intr(dev, scp->irq, INTR_TYPE_NET, 262 en_intr, sc, &scp->ih); 263 if (error) { 264 en_reset(sc); 265 if_detach(&sc->enif); 266 device_printf(dev, "could not setup irq\n"); 267 bus_release_resource(dev, SYS_RES_IRQ, 0, scp->irq); 268 bus_release_resource(dev, SYS_RES_MEMORY, PCI_CBMA, scp->res); 269 en_destroy(sc); 270 goto fail; 271 } 272 273 return (0); 274 275 fail: 276 return (error); 277} 278 279/* 280 * Detach the adapter 281 */ 282static int 283en_pci_detach(device_t dev) 284{ 285 struct en_softc *sc = device_get_softc(dev); 286 struct en_pci_softc *scp = (struct en_pci_softc *)sc; 287 288 /* 289 * Stop DMA and drop transmit queue. 290 */ 291 if ((sc->enif.if_flags & IFF_RUNNING)) { 292 if_printf(&sc->enif, "still running\n"); 293 sc->enif.if_flags &= ~IFF_RUNNING; 294 } 295 296 /* 297 * Close down routes etc. 298 */ 299 en_reset(sc); 300 if_detach(&sc->enif); 301 302 /* 303 * Deallocate resources. 304 */ 305 bus_teardown_intr(dev, scp->irq, scp->ih); 306 bus_release_resource(dev, SYS_RES_IRQ, 0, scp->irq); 307 bus_release_resource(dev, SYS_RES_MEMORY, PCI_CBMA, scp->res); 308 309 /* 310 * Free all the driver internal resources 311 */ 312 en_destroy(sc); 313 314 return (0); 315} 316 317static int 318en_pci_shutdown(device_t dev) 319{ 320 struct en_pci_softc *psc = device_get_softc(dev); 321 322 en_reset(&psc->esc); 323 DELAY(10); /* is this necessary? */ 324 325 return (0); 326} 327 328/* 329 * Get the MAC address from an Adaptec board. No idea how to get 330 * serial number or other stuff, because I have no documentation for that 331 * card. 332 */ 333static void 334adp_get_macaddr(struct en_pci_softc *scp) 335{ 336 struct en_softc * sc = (struct en_softc *)scp; 337 int lcv; 338 339 for (lcv = 0; lcv < sizeof(sc->macaddr); lcv++) 340 sc->macaddr[lcv] = bus_space_read_1(sc->en_memt, sc->en_base, 341 MID_ADPMACOFF + lcv); 342} 343 344/* 345 * Read station (MAC) address from serial EEPROM. 346 * derived from linux drivers/atm/eni.c by Werner Almesberger, EPFL LRC. 347 */ 348#define EN_PROM_MAGIC 0x0c 349#define EN_PROM_DATA 0x02 350#define EN_PROM_CLK 0x01 351#define EN_ESI 64 352#define EN_SERIAL 112 353 354/* 355 * Read a byte from the given address in the EEPROM 356 */ 357static uint8_t 358eni_get_byte(device_t dev, uint32_t *data, u_int address) 359{ 360 int j; 361 uint8_t tmp; 362 363 address = (address << 1) + 1; 364 365 /* start operation */ 366 *data |= EN_PROM_DATA ; 367 pci_write_config(dev, EN_TONGA, *data, 4); 368 *data |= EN_PROM_CLK ; 369 pci_write_config(dev, EN_TONGA, *data, 4); 370 *data &= ~EN_PROM_DATA ; 371 pci_write_config(dev, EN_TONGA, *data, 4); 372 *data &= ~EN_PROM_CLK ; 373 pci_write_config(dev, EN_TONGA, *data, 4); 374 /* send address with serial line */ 375 for ( j = 7 ; j >= 0 ; j --) { 376 *data = ((address >> j) & 1) ? (*data | EN_PROM_DATA) : 377 (*data & ~EN_PROM_DATA); 378 pci_write_config(dev, EN_TONGA, *data, 4); 379 *data |= EN_PROM_CLK ; 380 pci_write_config(dev, EN_TONGA, *data, 4); 381 *data &= ~EN_PROM_CLK ; 382 pci_write_config(dev, EN_TONGA, *data, 4); 383 } 384 /* get ack */ 385 *data |= EN_PROM_DATA ; 386 pci_write_config(dev, EN_TONGA, *data, 4); 387 *data |= EN_PROM_CLK ; 388 pci_write_config(dev, EN_TONGA, *data, 4); 389 *data = pci_read_config(dev, EN_TONGA, 4); 390 *data &= ~EN_PROM_CLK ; 391 pci_write_config(dev, EN_TONGA, *data, 4); 392 *data |= EN_PROM_DATA ; 393 pci_write_config(dev, EN_TONGA, *data, 4); 394 395 tmp = 0; 396 397 for ( j = 7 ; j >= 0 ; j --) { 398 tmp <<= 1; 399 *data |= EN_PROM_DATA ; 400 pci_write_config(dev, EN_TONGA, *data, 4); 401 *data |= EN_PROM_CLK ; 402 pci_write_config(dev, EN_TONGA, *data, 4); 403 *data = pci_read_config(dev, EN_TONGA, 4); 404 if(*data & EN_PROM_DATA) tmp |= 1; 405 *data &= ~EN_PROM_CLK ; 406 pci_write_config(dev, EN_TONGA, *data, 4); 407 *data |= EN_PROM_DATA ; 408 pci_write_config(dev, EN_TONGA, *data, 4); 409 } 410 /* get ack */ 411 *data |= EN_PROM_DATA ; 412 pci_write_config(dev, EN_TONGA, *data, 4); 413 *data |= EN_PROM_CLK ; 414 pci_write_config(dev, EN_TONGA, *data, 4); 415 *data = pci_read_config(dev, EN_TONGA, 4); 416 *data &= ~EN_PROM_CLK ; 417 pci_write_config(dev, EN_TONGA, *data, 4); 418 *data |= EN_PROM_DATA ; 419 pci_write_config(dev, EN_TONGA, *data, 4); 420 421 return (tmp); 422} 423 424/* 425 * Get MAC address and other stuff from the EEPROM 426 */ 427static void 428eni_get_macaddr(device_t dev, struct en_pci_softc *scp) 429{ 430 struct en_softc * sc = (struct en_softc *)scp; 431 int i; 432 uint32_t data, t_data; 433 434 t_data = pci_read_config(dev, EN_TONGA, 4) & 0xffffff00; 435 436 data = EN_PROM_MAGIC | EN_PROM_DATA | EN_PROM_CLK; 437 pci_write_config(dev, EN_TONGA, data, 4); 438 439 for (i = 0; i < sizeof(sc->macaddr); i ++) 440 sc->macaddr[i] = eni_get_byte(dev, &data, i + EN_ESI); 441 442 sc->serial = 0; 443 for (i = 0; i < 4; i++) { 444 sc->serial <<= 8; 445 sc->serial |= eni_get_byte(dev, &data, i + EN_SERIAL); 446 } 447 /* stop operation */ 448 data &= ~EN_PROM_DATA; 449 pci_write_config(dev, EN_TONGA, data, 4); 450 data |= EN_PROM_CLK; 451 pci_write_config(dev, EN_TONGA, data, 4); 452 data |= EN_PROM_DATA; 453 pci_write_config(dev, EN_TONGA, data, 4); 454 pci_write_config(dev, EN_TONGA, t_data, 4); 455} 456 457/* 458 * Driver infrastructure 459 */ 460static device_method_t en_methods[] = { 461 /* Device interface */ 462 DEVMETHOD(device_probe, en_pci_probe), 463 DEVMETHOD(device_attach, en_pci_attach), 464 DEVMETHOD(device_detach, en_pci_detach), 465 DEVMETHOD(device_shutdown, en_pci_shutdown), 466 467 { 0, 0 } 468}; 469 470static driver_t en_driver = { 471 "en", 472 en_methods, 473 sizeof(struct en_pci_softc), 474}; 475 476static devclass_t en_devclass; 477 478DRIVER_MODULE(en, pci, en_driver, en_devclass, 0, 0); 479