|
|
1.1 ! root 1: /* rtl8139.c - etherboot driver for the Realtek 8139 chipset ! 2: ! 3: ported from the linux driver written by Donald Becker ! 4: by Rainer Bawidamann ([email protected]) 1999 ! 5: ! 6: This software may be used and distributed according to the terms ! 7: of the GNU Public License, incorporated herein by reference. ! 8: ! 9: changes to the original driver: ! 10: - removed support for interrupts, switching to polling mode (yuck!) ! 11: - removed support for the 8129 chip (external MII) ! 12: ! 13: */ ! 14: ! 15: FILE_LICENCE ( GPL_ANY ); ! 16: ! 17: /*********************************************************************/ ! 18: /* Revision History */ ! 19: /*********************************************************************/ ! 20: ! 21: /* ! 22: 27 May 2006 [email protected] (Michael Brown) ! 23: Rewrote to use the new net driver API, the updated PCI API, and ! 24: the generic three-wire serial device support for EEPROM access. ! 25: ! 26: 28 Dec 2002 [email protected] (Ken Yap) ! 27: Put in virt_to_bus calls to allow Etherboot relocation. ! 28: ! 29: 06 Apr 2001 [email protected] (Ken Yap) ! 30: Following email from Hyun-Joon Cha, added a disable routine, otherwise ! 31: NIC remains live and can crash the kernel later. ! 32: ! 33: 4 Feb 2000 [email protected] (Klaus Espenlaub) ! 34: Shuffled things around, removed the leftovers from the 8129 support ! 35: that was in the Linux driver and added a bit more 8139 definitions. ! 36: Moved the 8K receive buffer to a fixed, available address outside the ! 37: 0x98000-0x9ffff range. This is a bit of a hack, but currently the only ! 38: way to make room for the Etherboot features that need substantial amounts ! 39: of code like the ANSI console support. Currently the buffer is just below ! 40: 0x10000, so this even conforms to the tagged boot image specification, ! 41: which reserves the ranges 0x00000-0x10000 and 0x98000-0xA0000. My ! 42: interpretation of this "reserved" is that Etherboot may do whatever it ! 43: likes, as long as its environment is kept intact (like the BIOS ! 44: variables). Hopefully fixed rtl_poll() once and for all. The symptoms ! 45: were that if Etherboot was left at the boot menu for several minutes, the ! 46: first eth_poll failed. Seems like I am the only person who does this. ! 47: First of all I fixed the debugging code and then set out for a long bug ! 48: hunting session. It took me about a week full time work - poking around ! 49: various places in the driver, reading Don Becker's and Jeff Garzik's Linux ! 50: driver and even the FreeBSD driver (what a piece of crap!) - and ! 51: eventually spotted the nasty thing: the transmit routine was acknowledging ! 52: each and every interrupt pending, including the RxOverrun and RxFIFIOver ! 53: interrupts. This confused the RTL8139 thoroughly. It destroyed the ! 54: Rx ring contents by dumping the 2K FIFO contents right where we wanted to ! 55: get the next packet. Oh well, what fun. ! 56: ! 57: 18 Jan 2000 [email protected] (Marty Connor) ! 58: Drastically simplified error handling. Basically, if any error ! 59: in transmission or reception occurs, the card is reset. ! 60: Also, pointed all transmit descriptors to the same buffer to ! 61: save buffer space. This should decrease driver size and avoid ! 62: corruption because of exceeding 32K during runtime. ! 63: ! 64: 28 Jul 1999 (Matthias Meixner - [email protected]) ! 65: rtl_poll was quite broken: it used the RxOK interrupt flag instead ! 66: of the RxBufferEmpty flag which often resulted in very bad ! 67: transmission performace - below 1kBytes/s. ! 68: ! 69: */ ! 70: ! 71: #include <stdint.h> ! 72: #include <stdlib.h> ! 73: #include <stdio.h> ! 74: #include <string.h> ! 75: #include <ipxe/io.h> ! 76: #include <errno.h> ! 77: #include <unistd.h> ! 78: #include <byteswap.h> ! 79: #include <ipxe/pci.h> ! 80: #include <ipxe/if_ether.h> ! 81: #include <ipxe/ethernet.h> ! 82: #include <ipxe/iobuf.h> ! 83: #include <ipxe/netdevice.h> ! 84: #include <ipxe/spi_bit.h> ! 85: #include <ipxe/threewire.h> ! 86: #include <ipxe/nvo.h> ! 87: ! 88: #define TX_RING_SIZE 4 ! 89: #define TX_MAX_LEN 8192 ! 90: ! 91: struct rtl8139_tx { ! 92: unsigned int next; ! 93: struct io_buffer *iobuf[TX_RING_SIZE]; ! 94: }; ! 95: ! 96: struct rtl8139_rx { ! 97: void *ring; ! 98: unsigned int offset; ! 99: }; ! 100: ! 101: struct rtl8139_nic { ! 102: unsigned short ioaddr; ! 103: struct rtl8139_tx tx; ! 104: struct rtl8139_rx rx; ! 105: struct spi_bit_basher spibit; ! 106: struct spi_device eeprom; ! 107: struct nvo_block nvo; ! 108: }; ! 109: ! 110: /* Tuning Parameters */ ! 111: #define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */ ! 112: #define RX_FIFO_THRESH 4 /* Rx buffer level before first PCI xfer. */ ! 113: #define RX_DMA_BURST 4 /* Maximum PCI burst, '4' is 256 bytes */ ! 114: #define TX_DMA_BURST 4 /* Calculate as 16<<val. */ ! 115: #define TX_IPG 3 /* This is the only valid value */ ! 116: #define RX_BUF_LEN_IDX 0 /* 0, 1, 2 is allowed - 8,16,32K rx buffer */ ! 117: #define RX_BUF_LEN ( (8192 << RX_BUF_LEN_IDX) ) ! 118: #define RX_BUF_PAD 4 ! 119: ! 120: /* Symbolic offsets to registers. */ ! 121: enum RTL8139_registers { ! 122: MAC0=0, /* Ethernet hardware address. */ ! 123: MAR0=8, /* Multicast filter. */ ! 124: TxStatus0=0x10, /* Transmit status (four 32bit registers). */ ! 125: TxAddr0=0x20, /* Tx descriptors (also four 32bit). */ ! 126: RxBuf=0x30, RxEarlyCnt=0x34, RxEarlyStatus=0x36, ! 127: ChipCmd=0x37, RxBufPtr=0x38, RxBufAddr=0x3A, ! 128: IntrMask=0x3C, IntrStatus=0x3E, ! 129: TxConfig=0x40, RxConfig=0x44, ! 130: Timer=0x48, /* general-purpose counter. */ ! 131: RxMissed=0x4C, /* 24 bits valid, write clears. */ ! 132: Cfg9346=0x50, Config0=0x51, Config1=0x52, ! 133: TimerIntrReg=0x54, /* intr if gp counter reaches this value */ ! 134: MediaStatus=0x58, ! 135: Config3=0x59, ! 136: MultiIntr=0x5C, ! 137: RevisionID=0x5E, /* revision of the RTL8139 chip */ ! 138: TxSummary=0x60, ! 139: MII_BMCR=0x62, MII_BMSR=0x64, NWayAdvert=0x66, NWayLPAR=0x68, ! 140: NWayExpansion=0x6A, ! 141: DisconnectCnt=0x6C, FalseCarrierCnt=0x6E, ! 142: NWayTestReg=0x70, ! 143: RxCnt=0x72, /* packet received counter */ ! 144: CSCR=0x74, /* chip status and configuration register */ ! 145: PhyParm1=0x78,TwisterParm=0x7c,PhyParm2=0x80, /* undocumented */ ! 146: /* from 0x84 onwards are a number of power management/wakeup frame ! 147: * definitions we will probably never need to know about. */ ! 148: }; ! 149: ! 150: enum RxEarlyStatusBits { ! 151: ERGood=0x08, ERBad=0x04, EROVW=0x02, EROK=0x01 ! 152: }; ! 153: ! 154: enum ChipCmdBits { ! 155: CmdReset=0x10, CmdRxEnb=0x08, CmdTxEnb=0x04, RxBufEmpty=0x01, }; ! 156: ! 157: enum IntrMaskBits { ! 158: SERR=0x8000, TimeOut=0x4000, LenChg=0x2000, ! 159: FOVW=0x40, PUN_LinkChg=0x20, RXOVW=0x10, ! 160: TER=0x08, TOK=0x04, RER=0x02, ROK=0x01 ! 161: }; ! 162: ! 163: /* Interrupt register bits, using my own meaningful names. */ ! 164: enum IntrStatusBits { ! 165: PCIErr=0x8000, PCSTimeout=0x4000, CableLenChange= 0x2000, ! 166: RxFIFOOver=0x40, RxUnderrun=0x20, RxOverflow=0x10, ! 167: TxErr=0x08, TxOK=0x04, RxErr=0x02, RxOK=0x01, ! 168: }; ! 169: enum TxStatusBits { ! 170: TxHostOwns=0x2000, TxUnderrun=0x4000, TxStatOK=0x8000, ! 171: TxOutOfWindow=0x20000000, TxAborted=0x40000000, ! 172: TxCarrierLost=0x80000000, ! 173: }; ! 174: enum RxStatusBits { ! 175: RxMulticast=0x8000, RxPhysical=0x4000, RxBroadcast=0x2000, ! 176: RxBadSymbol=0x0020, RxRunt=0x0010, RxTooLong=0x0008, RxCRCErr=0x0004, ! 177: RxBadAlign=0x0002, RxStatusOK=0x0001, ! 178: }; ! 179: ! 180: enum MediaStatusBits { ! 181: MSRTxFlowEnable=0x80, MSRRxFlowEnable=0x40, MSRSpeed10=0x08, ! 182: MSRLinkFail=0x04, MSRRxPauseFlag=0x02, MSRTxPauseFlag=0x01, ! 183: }; ! 184: ! 185: enum MIIBMCRBits { ! 186: BMCRReset=0x8000, BMCRSpeed100=0x2000, BMCRNWayEnable=0x1000, ! 187: BMCRRestartNWay=0x0200, BMCRDuplex=0x0100, ! 188: }; ! 189: ! 190: enum CSCRBits { ! 191: CSCR_LinkOKBit=0x0400, CSCR_LinkChangeBit=0x0800, ! 192: CSCR_LinkStatusBits=0x0f000, CSCR_LinkDownOffCmd=0x003c0, ! 193: CSCR_LinkDownCmd=0x0f3c0, ! 194: }; ! 195: ! 196: enum RxConfigBits { ! 197: RxCfgWrap=0x80, ! 198: Eeprom9356=0x40, ! 199: AcceptErr=0x20, AcceptRunt=0x10, AcceptBroadcast=0x08, ! 200: AcceptMulticast=0x04, AcceptMyPhys=0x02, AcceptAllPhys=0x01, ! 201: }; ! 202: ! 203: enum Config1Bits { ! 204: VPDEnable=0x02, ! 205: }; ! 206: ! 207: /* EEPROM access */ ! 208: #define EE_M1 0x80 /* Mode select bit 1 */ ! 209: #define EE_M0 0x40 /* Mode select bit 0 */ ! 210: #define EE_CS 0x08 /* EEPROM chip select */ ! 211: #define EE_SK 0x04 /* EEPROM shift clock */ ! 212: #define EE_DI 0x02 /* Data in */ ! 213: #define EE_DO 0x01 /* Data out */ ! 214: ! 215: /* Offsets within EEPROM (these are word offsets) */ ! 216: #define EE_MAC 7 ! 217: ! 218: static const uint8_t rtl_ee_bits[] = { ! 219: [SPI_BIT_SCLK] = EE_SK, ! 220: [SPI_BIT_MOSI] = EE_DI, ! 221: [SPI_BIT_MISO] = EE_DO, ! 222: [SPI_BIT_SS(0)] = ( EE_CS | EE_M1 ), ! 223: }; ! 224: ! 225: static int rtl_spi_read_bit ( struct bit_basher *basher, ! 226: unsigned int bit_id ) { ! 227: struct rtl8139_nic *rtl = container_of ( basher, struct rtl8139_nic, ! 228: spibit.basher ); ! 229: uint8_t mask = rtl_ee_bits[bit_id]; ! 230: uint8_t eereg; ! 231: ! 232: eereg = inb ( rtl->ioaddr + Cfg9346 ); ! 233: return ( eereg & mask ); ! 234: } ! 235: ! 236: static void rtl_spi_write_bit ( struct bit_basher *basher, ! 237: unsigned int bit_id, unsigned long data ) { ! 238: struct rtl8139_nic *rtl = container_of ( basher, struct rtl8139_nic, ! 239: spibit.basher ); ! 240: uint8_t mask = rtl_ee_bits[bit_id]; ! 241: uint8_t eereg; ! 242: ! 243: eereg = inb ( rtl->ioaddr + Cfg9346 ); ! 244: eereg &= ~mask; ! 245: eereg |= ( data & mask ); ! 246: outb ( eereg, rtl->ioaddr + Cfg9346 ); ! 247: } ! 248: ! 249: static struct bit_basher_operations rtl_basher_ops = { ! 250: .read = rtl_spi_read_bit, ! 251: .write = rtl_spi_write_bit, ! 252: }; ! 253: ! 254: /** ! 255: * Set up for EEPROM access ! 256: * ! 257: * @v netdev Net device ! 258: */ ! 259: static void rtl_init_eeprom ( struct net_device *netdev ) { ! 260: struct rtl8139_nic *rtl = netdev->priv; ! 261: int ee9356; ! 262: int vpd; ! 263: ! 264: /* Initialise three-wire bus */ ! 265: rtl->spibit.basher.op = &rtl_basher_ops; ! 266: rtl->spibit.bus.mode = SPI_MODE_THREEWIRE; ! 267: init_spi_bit_basher ( &rtl->spibit ); ! 268: ! 269: /* Detect EEPROM type and initialise three-wire device */ ! 270: ee9356 = ( inw ( rtl->ioaddr + RxConfig ) & Eeprom9356 ); ! 271: if ( ee9356 ) { ! 272: DBGC ( rtl, "rtl8139 %p EEPROM is an AT93C56\n", rtl ); ! 273: init_at93c56 ( &rtl->eeprom, 16 ); ! 274: } else { ! 275: DBGC ( rtl, "rtl8139 %p EEPROM is an AT93C46\n", rtl ); ! 276: init_at93c46 ( &rtl->eeprom, 16 ); ! 277: } ! 278: rtl->eeprom.bus = &rtl->spibit.bus; ! 279: ! 280: /* Initialise space for non-volatile options, if available ! 281: * ! 282: * We use offset 0x40 (i.e. address 0x20), length 0x40. This ! 283: * block is marked as VPD in the rtl8139 datasheets, so we use ! 284: * it only if we detect that the card is not supporting VPD. ! 285: */ ! 286: vpd = ( inw ( rtl->ioaddr + Config1 ) & VPDEnable ); ! 287: if ( vpd ) { ! 288: DBGC ( rtl, "rtl8139 %p EEPROM in use for VPD; cannot use " ! 289: "for options\n", rtl ); ! 290: } else { ! 291: nvo_init ( &rtl->nvo, &rtl->eeprom.nvs, 0x20, 0x40, NULL, ! 292: &netdev->refcnt ); ! 293: } ! 294: } ! 295: ! 296: /** ! 297: * Reset NIC ! 298: * ! 299: * @v netdev Net device ! 300: * ! 301: * Issues a hardware reset and waits for the reset to complete. ! 302: */ ! 303: static void rtl_reset ( struct net_device *netdev ) { ! 304: struct rtl8139_nic *rtl = netdev->priv; ! 305: ! 306: /* Reset chip */ ! 307: outb ( CmdReset, rtl->ioaddr + ChipCmd ); ! 308: mdelay ( 10 ); ! 309: memset ( &rtl->tx, 0, sizeof ( rtl->tx ) ); ! 310: rtl->rx.offset = 0; ! 311: } ! 312: ! 313: /** ! 314: * Open NIC ! 315: * ! 316: * @v netdev Net device ! 317: * @ret rc Return status code ! 318: */ ! 319: static int rtl_open ( struct net_device *netdev ) { ! 320: struct rtl8139_nic *rtl = netdev->priv; ! 321: int i; ! 322: ! 323: /* Program the MAC address */ ! 324: for ( i = 0 ; i < ETH_ALEN ; i++ ) ! 325: outb ( netdev->ll_addr[i], rtl->ioaddr + MAC0 + i ); ! 326: ! 327: /* Set up RX ring */ ! 328: rtl->rx.ring = malloc ( RX_BUF_LEN + RX_BUF_PAD ); ! 329: if ( ! rtl->rx.ring ) ! 330: return -ENOMEM; ! 331: outl ( virt_to_bus ( rtl->rx.ring ), rtl->ioaddr + RxBuf ); ! 332: DBGC ( rtl, "rtl8139 %p RX ring at %lx\n", ! 333: rtl, virt_to_bus ( rtl->rx.ring ) ); ! 334: ! 335: /* Enable TX and RX */ ! 336: outb ( ( CmdRxEnb | CmdTxEnb ), rtl->ioaddr + ChipCmd ); ! 337: outl ( ( ( RX_FIFO_THRESH << 13 ) | ( RX_BUF_LEN_IDX << 11 ) | ! 338: ( RX_DMA_BURST << 8 ) | AcceptBroadcast | AcceptMulticast | ! 339: AcceptMyPhys | AcceptAllPhys ), rtl->ioaddr + RxConfig ); ! 340: outl ( 0xffffffffUL, rtl->ioaddr + MAR0 + 0 ); ! 341: outl ( 0xffffffffUL, rtl->ioaddr + MAR0 + 4 ); ! 342: outl ( ( ( TX_DMA_BURST << 8 ) | ( TX_IPG << 24 ) ), ! 343: rtl->ioaddr + TxConfig ); ! 344: ! 345: return 0; ! 346: } ! 347: ! 348: /** ! 349: * Close NIC ! 350: * ! 351: * @v netdev Net device ! 352: */ ! 353: static void rtl_close ( struct net_device *netdev ) { ! 354: struct rtl8139_nic *rtl = netdev->priv; ! 355: ! 356: /* Reset the hardware to disable everything in one go */ ! 357: rtl_reset ( netdev ); ! 358: ! 359: /* Free RX ring */ ! 360: free ( rtl->rx.ring ); ! 361: rtl->rx.ring = NULL; ! 362: } ! 363: ! 364: /** ! 365: * Transmit packet ! 366: * ! 367: * @v netdev Network device ! 368: * @v iobuf I/O buffer ! 369: * @ret rc Return status code ! 370: */ ! 371: static int rtl_transmit ( struct net_device *netdev, ! 372: struct io_buffer *iobuf ) { ! 373: struct rtl8139_nic *rtl = netdev->priv; ! 374: ! 375: /* Check for space in TX ring */ ! 376: if ( rtl->tx.iobuf[rtl->tx.next] != NULL ) { ! 377: DBGC ( rtl, "rtl8139 %p TX overflow\n", rtl ); ! 378: return -ENOBUFS; ! 379: } ! 380: ! 381: /* Check for oversized packets */ ! 382: if ( iob_len ( iobuf ) >= TX_MAX_LEN ) { ! 383: DBGC ( rtl, "rtl8139 %p TX too large (%zd bytes)\n", ! 384: rtl, iob_len ( iobuf ) ); ! 385: return -ERANGE; ! 386: } ! 387: ! 388: /* Pad and align packet */ ! 389: iob_pad ( iobuf, ETH_ZLEN ); ! 390: ! 391: /* Add to TX ring */ ! 392: DBGC2 ( rtl, "rtl8139 %p TX id %d at %lx+%zx\n", rtl, rtl->tx.next, ! 393: virt_to_bus ( iobuf->data ), iob_len ( iobuf ) ); ! 394: rtl->tx.iobuf[rtl->tx.next] = iobuf; ! 395: outl ( virt_to_bus ( iobuf->data ), ! 396: rtl->ioaddr + TxAddr0 + 4 * rtl->tx.next ); ! 397: outl ( ( ( ( TX_FIFO_THRESH & 0x7e0 ) << 11 ) | iob_len ( iobuf ) ), ! 398: rtl->ioaddr + TxStatus0 + 4 * rtl->tx.next ); ! 399: rtl->tx.next = ( rtl->tx.next + 1 ) % TX_RING_SIZE; ! 400: ! 401: return 0; ! 402: } ! 403: ! 404: /** ! 405: * Poll for received packets ! 406: * ! 407: * @v netdev Network device ! 408: */ ! 409: static void rtl_poll ( struct net_device *netdev ) { ! 410: struct rtl8139_nic *rtl = netdev->priv; ! 411: unsigned int status; ! 412: unsigned int tsad; ! 413: unsigned int rx_status; ! 414: unsigned int rx_len; ! 415: struct io_buffer *rx_iob; ! 416: int wrapped_len; ! 417: int i; ! 418: ! 419: /* Acknowledge interrupts */ ! 420: status = inw ( rtl->ioaddr + IntrStatus ); ! 421: if ( ! status ) ! 422: return; ! 423: outw ( status, rtl->ioaddr + IntrStatus ); ! 424: ! 425: /* Handle TX completions */ ! 426: tsad = inw ( rtl->ioaddr + TxSummary ); ! 427: for ( i = 0 ; i < TX_RING_SIZE ; i++ ) { ! 428: if ( ( rtl->tx.iobuf[i] != NULL ) && ( tsad & ( 1 << i ) ) ) { ! 429: DBGC2 ( rtl, "rtl8139 %p TX id %d complete\n", ! 430: rtl, i ); ! 431: netdev_tx_complete ( netdev, rtl->tx.iobuf[i] ); ! 432: rtl->tx.iobuf[i] = NULL; ! 433: } ! 434: } ! 435: ! 436: /* Handle received packets */ ! 437: while ( ! ( inw ( rtl->ioaddr + ChipCmd ) & RxBufEmpty ) ) { ! 438: rx_status = * ( ( uint16_t * ) ! 439: ( rtl->rx.ring + rtl->rx.offset ) ); ! 440: rx_len = * ( ( uint16_t * ) ! 441: ( rtl->rx.ring + rtl->rx.offset + 2 ) ); ! 442: if ( rx_status & RxOK ) { ! 443: DBGC2 ( rtl, "rtl8139 %p RX packet at offset " ! 444: "%x+%x\n", rtl, rtl->rx.offset, rx_len ); ! 445: ! 446: rx_iob = alloc_iob ( rx_len ); ! 447: if ( ! rx_iob ) { ! 448: netdev_rx_err ( netdev, NULL, -ENOMEM ); ! 449: /* Leave packet for next call to poll() */ ! 450: break; ! 451: } ! 452: ! 453: wrapped_len = ( ( rtl->rx.offset + 4 + rx_len ) ! 454: - RX_BUF_LEN ); ! 455: if ( wrapped_len < 0 ) ! 456: wrapped_len = 0; ! 457: ! 458: memcpy ( iob_put ( rx_iob, rx_len - wrapped_len ), ! 459: rtl->rx.ring + rtl->rx.offset + 4, ! 460: rx_len - wrapped_len ); ! 461: memcpy ( iob_put ( rx_iob, wrapped_len ), ! 462: rtl->rx.ring, wrapped_len ); ! 463: iob_unput ( rx_iob, 4 ); /* Strip CRC */ ! 464: ! 465: netdev_rx ( netdev, rx_iob ); ! 466: } else { ! 467: DBGC ( rtl, "rtl8139 %p RX bad packet (status %#04x " ! 468: "len %d)\n", rtl, rx_status, rx_len ); ! 469: netdev_rx_err ( netdev, NULL, -EINVAL ); ! 470: } ! 471: rtl->rx.offset = ( ( ( rtl->rx.offset + 4 + rx_len + 3 ) & ~3 ) ! 472: % RX_BUF_LEN ); ! 473: outw ( rtl->rx.offset - 16, rtl->ioaddr + RxBufPtr ); ! 474: } ! 475: } ! 476: ! 477: /** ! 478: * Enable/disable interrupts ! 479: * ! 480: * @v netdev Network device ! 481: * @v enable Interrupts should be enabled ! 482: */ ! 483: static void rtl_irq ( struct net_device *netdev, int enable ) { ! 484: struct rtl8139_nic *rtl = netdev->priv; ! 485: ! 486: DBGC ( rtl, "rtl8139 %p interrupts %s\n", ! 487: rtl, ( enable ? "enabled" : "disabled" ) ); ! 488: outw ( ( enable ? ( ROK | RER | TOK | TER ) : 0 ), ! 489: rtl->ioaddr + IntrMask ); ! 490: } ! 491: ! 492: /** RTL8139 net device operations */ ! 493: static struct net_device_operations rtl_operations = { ! 494: .open = rtl_open, ! 495: .close = rtl_close, ! 496: .transmit = rtl_transmit, ! 497: .poll = rtl_poll, ! 498: .irq = rtl_irq, ! 499: }; ! 500: ! 501: /** ! 502: * Probe PCI device ! 503: * ! 504: * @v pci PCI device ! 505: * @v id PCI ID ! 506: * @ret rc Return status code ! 507: */ ! 508: static int rtl_probe ( struct pci_device *pci ) { ! 509: struct net_device *netdev; ! 510: struct rtl8139_nic *rtl; ! 511: int rc; ! 512: ! 513: /* Allocate net device */ ! 514: netdev = alloc_etherdev ( sizeof ( *rtl ) ); ! 515: if ( ! netdev ) ! 516: return -ENOMEM; ! 517: netdev_init ( netdev, &rtl_operations ); ! 518: rtl = netdev->priv; ! 519: pci_set_drvdata ( pci, netdev ); ! 520: netdev->dev = &pci->dev; ! 521: memset ( rtl, 0, sizeof ( *rtl ) ); ! 522: rtl->ioaddr = pci->ioaddr; ! 523: ! 524: /* Fix up PCI device */ ! 525: adjust_pci_device ( pci ); ! 526: ! 527: /* Reset the NIC, set up EEPROM access and read MAC address */ ! 528: rtl_reset ( netdev ); ! 529: rtl_init_eeprom ( netdev ); ! 530: nvs_read ( &rtl->eeprom.nvs, EE_MAC, netdev->hw_addr, ETH_ALEN ); ! 531: ! 532: /* Register network device */ ! 533: if ( ( rc = register_netdev ( netdev ) ) != 0 ) ! 534: goto err_register_netdev; ! 535: ! 536: /* Mark as link up; we don't yet handle link state */ ! 537: netdev_link_up ( netdev ); ! 538: ! 539: /* Register non-volatile storage */ ! 540: if ( rtl->nvo.nvs ) { ! 541: if ( ( rc = register_nvo ( &rtl->nvo, ! 542: netdev_settings ( netdev ) ) ) != 0) ! 543: goto err_register_nvo; ! 544: } ! 545: ! 546: return 0; ! 547: ! 548: err_register_nvo: ! 549: unregister_netdev ( netdev ); ! 550: err_register_netdev: ! 551: rtl_reset ( netdev ); ! 552: netdev_nullify ( netdev ); ! 553: netdev_put ( netdev ); ! 554: return rc; ! 555: } ! 556: ! 557: /** ! 558: * Remove PCI device ! 559: * ! 560: * @v pci PCI device ! 561: */ ! 562: static void rtl_remove ( struct pci_device *pci ) { ! 563: struct net_device *netdev = pci_get_drvdata ( pci ); ! 564: struct rtl8139_nic *rtl = netdev->priv; ! 565: ! 566: if ( rtl->nvo.nvs ) ! 567: unregister_nvo ( &rtl->nvo ); ! 568: unregister_netdev ( netdev ); ! 569: rtl_reset ( netdev ); ! 570: netdev_nullify ( netdev ); ! 571: netdev_put ( netdev ); ! 572: } ! 573: ! 574: static struct pci_device_id rtl8139_nics[] = { ! 575: PCI_ROM(0x10ec, 0x8129, "rtl8129", "Realtek 8129", 0), ! 576: PCI_ROM(0x10ec, 0x8139, "rtl8139", "Realtek 8139", 0), ! 577: PCI_ROM(0x10ec, 0x8138, "rtl8139b", "Realtek 8139B", 0), ! 578: PCI_ROM(0x1186, 0x1300, "dfe538", "DFE530TX+/DFE538TX", 0), ! 579: PCI_ROM(0x1113, 0x1211, "smc1211-1", "SMC EZ10/100", 0), ! 580: PCI_ROM(0x1112, 0x1211, "smc1211", "SMC EZ10/100", 0), ! 581: PCI_ROM(0x1500, 0x1360, "delta8139", "Delta Electronics 8139", 0), ! 582: PCI_ROM(0x4033, 0x1360, "addtron8139", "Addtron Technology 8139", 0), ! 583: PCI_ROM(0x1186, 0x1340, "dfe690txd", "D-Link DFE690TXD", 0), ! 584: PCI_ROM(0x13d1, 0xab06, "fe2000vx", "AboCom FE2000VX", 0), ! 585: PCI_ROM(0x1259, 0xa117, "allied8139", "Allied Telesyn 8139", 0), ! 586: PCI_ROM(0x14ea, 0xab06, "fnw3603tx", "Planex FNW-3603-TX", 0), ! 587: PCI_ROM(0x14ea, 0xab07, "fnw3800tx", "Planex FNW-3800-TX", 0), ! 588: PCI_ROM(0xffff, 0x8139, "clone-rtl8139", "Cloned 8139", 0), ! 589: }; ! 590: ! 591: struct pci_driver rtl8139_driver __pci_driver = { ! 592: .ids = rtl8139_nics, ! 593: .id_count = ( sizeof ( rtl8139_nics ) / sizeof ( rtl8139_nics[0] ) ), ! 594: .probe = rtl_probe, ! 595: .remove = rtl_remove, ! 596: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.