Home | History | Annotate | Download | only in netboot
      1 /* -*- Mode:C; c-basic-offset:4; -*- */
      2 
      3 /*
      4    natsemi.c: An Etherboot driver for the NatSemi DP8381x series.
      5 
      6    Copyright (C) 2001 Entity Cyber, Inc.
      7 
      8    This development of this Etherboot driver was funded by
      9 
     10       Sicom Systems: http://www.sicompos.com/
     11 
     12    Author: Marty Connor (mdc (at) thinguin.org)
     13    Adapted from a Linux driver which was written by Donald Becker
     14 
     15    This software may be used and distributed according to the terms
     16    of the GNU Public License (GPL), incorporated herein by reference.
     17 
     18    Original Copyright Notice:
     19 
     20    Written/copyright 1999-2001 by Donald Becker.
     21 
     22    This software may be used and distributed according to the terms of
     23    the GNU General Public License (GPL), incorporated herein by reference.
     24    Drivers based on or derived from this code fall under the GPL and must
     25    retain the authorship, copyright and license notice.  This file is not
     26    a complete program and may only be used when the entire operating
     27    system is licensed under the GPL.  License for under other terms may be
     28    available.  Contact the original author for details.
     29 
     30    The original author may be reached as becker (at) scyld.com, or at
     31    Scyld Computing Corporation
     32    410 Severn Ave., Suite 210
     33    Annapolis MD 21403
     34 
     35    Support information and updates available at
     36    http://www.scyld.com/network/netsemi.html
     37 
     38    References:
     39 
     40    http://www.scyld.com/expert/100mbps.html
     41    http://www.scyld.com/expert/NWay.html
     42    Datasheet is available from:
     43    http://www.national.com/pf/DP/DP83815.html
     44 
     45 */
     46 
     47 /* Revision History */
     48 
     49 /*
     50   29 May 2001  mdc     1.0
     51      Initial Release.  Tested with Netgear FA311 and FA312 boards
     52 */
     53 /* Includes */
     55 
     56 #include "etherboot.h"
     57 #include "nic.h"
     58 #include "pci.h"
     59 #include "cards.h"
     60 
     61 /* defines */
     62 
     63 #define OWN       0x80000000
     64 #define DSIZE     0x00000FFF
     65 #define CRC_SIZE  4
     66 
     67 /* Time in ticks before concluding the transmitter is hung. */
     68 #define TX_TIMEOUT       (4*TICKS_PER_SEC)
     69 
     70 #define TX_BUF_SIZE    1536
     71 #define RX_BUF_SIZE    1536
     72 
     73 #define NUM_RX_DESC    4              /* Number of Rx descriptor registers. */
     74 
     75 typedef unsigned char  u8;
     76 typedef   signed char  s8;
     77 typedef unsigned short u16;
     78 typedef   signed short s16;
     79 typedef unsigned int   u32;
     80 typedef   signed int   s32;
     81 
     82 /* helpful macroes if on a big_endian machine for changing byte order.
     83    not strictly needed on Intel */
     84 #define le16_to_cpu(val) (val)
     85 #define cpu_to_le32(val) (val)
     86 #define get_unaligned(ptr) (*(ptr))
     87 #define put_unaligned(val, ptr) ((void)( *(ptr) = (val) ))
     88 #define get_u16(ptr) (*(u16 *)(ptr))
     89 #define virt_to_bus(x) ((unsigned long)x)
     90 #define virt_to_le32desc(addr)  virt_to_bus(addr)
     91 
     92 enum pcistuff {
     93     PCI_USES_IO     = 0x01,
     94     PCI_USES_MEM    = 0x02,
     95     PCI_USES_MASTER = 0x04,
     96     PCI_ADDR0       = 0x08,
     97     PCI_ADDR1       = 0x10,
     98 };
     99 
    100 /* MMIO operations required */
    101 #define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
    102 
    103 /* Offsets to the device registers.
    104    Unlike software-only systems, device drivers interact with complex hardware.
    105    It's not useful to define symbolic names for every register bit in the
    106    device.
    107 */
    108 enum register_offsets {
    109     ChipCmd      = 0x00,
    110     ChipConfig   = 0x04,
    111     EECtrl       = 0x08,
    112     PCIBusCfg    = 0x0C,
    113     IntrStatus   = 0x10,
    114     IntrMask     = 0x14,
    115     IntrEnable   = 0x18,
    116     TxRingPtr    = 0x20,
    117     TxConfig     = 0x24,
    118     RxRingPtr    = 0x30,
    119     RxConfig     = 0x34,
    120     ClkRun       = 0x3C,
    121     WOLCmd       = 0x40,
    122     PauseCmd     = 0x44,
    123     RxFilterAddr = 0x48,
    124     RxFilterData = 0x4C,
    125     BootRomAddr  = 0x50,
    126     BootRomData  = 0x54,
    127     SiliconRev   = 0x58,
    128     StatsCtrl    = 0x5C,
    129     StatsData    = 0x60,
    130     RxPktErrs    = 0x60,
    131     RxMissed     = 0x68,
    132     RxCRCErrs    = 0x64,
    133     PCIPM        = 0x44,
    134     PhyStatus    = 0xC0,
    135     MIntrCtrl    = 0xC4,
    136     MIntrStatus  = 0xC8,
    137 
    138     /* These are from the spec, around page 78... on a separate table. */
    139     PGSEL        = 0xCC,
    140     PMDCSR       = 0xE4,
    141     TSTDAT       = 0xFC,
    142     DSPCFG       = 0xF4,
    143     SDCFG        = 0x8C
    144 };
    145 
    146 /* Bit in ChipCmd. */
    147 enum ChipCmdBits {
    148     ChipReset = 0x100,
    149     RxReset   = 0x20,
    150     TxReset   = 0x10,
    151     RxOff     = 0x08,
    152     RxOn      = 0x04,
    153     TxOff     = 0x02,
    154     TxOn      = 0x01
    155 };
    156 
    157 /* Bits in the RxMode register. */
    158 enum rx_mode_bits {
    159     AcceptErr          = 0x20,
    160     AcceptRunt         = 0x10,
    161     AcceptBroadcast    = 0xC0000000,
    162     AcceptMulticast    = 0x00200000,
    163     AcceptAllMulticast = 0x20000000,
    164     AcceptAllPhys      = 0x10000000,
    165     AcceptMyPhys       = 0x08000000
    166 };
    167 
    168 typedef struct _BufferDesc {
    169     u32              link;
    170     volatile u32     cmdsts;
    171     u32              bufptr;
    172     u32				 software_use;
    173 } BufferDesc;
    174 
    175 /* Bits in network_desc.status */
    176 enum desc_status_bits {
    177     DescOwn   = 0x80000000,
    178     DescMore  = 0x40000000,
    179     DescIntr  = 0x20000000,
    180     DescNoCRC = 0x10000000,
    181     DescPktOK = 0x08000000,
    182     RxTooLong = 0x00400000
    183 };
    184 
    185 /* Globals */
    186 
    187 static int natsemi_debug = 1;			/* 1 normal messages, 0 quiet .. 7 verbose. */
    188 
    189 const char *nic_name;
    190 
    191 static u32 SavedClkRun;
    192 
    193 
    194 static unsigned short vendor, dev_id;
    195 static unsigned long ioaddr;
    196 
    197 static unsigned int cur_rx;
    198 
    199 static unsigned int advertising;
    200 
    201 static unsigned int rx_config;
    202 static unsigned int tx_config;
    203 
    204 /* Note: transmit and receive buffers and descriptors must be
    205    longword aligned
    206 */
    207 
    208 static BufferDesc txd              __attribute__ ((aligned(4)));
    209 static BufferDesc rxd[NUM_RX_DESC] __attribute__ ((aligned(4)));
    210 
    211 #ifdef USE_LOWMEM_BUFFER
    212 #define txb ((char *)0x10000 - TX_BUF_SIZE)
    213 #define rxb ((char *)0x10000 - NUM_RX_DESC*RX_BUF_SIZE - TX_BUF_SIZE)
    214 #else
    215 static unsigned char txb[TX_BUF_SIZE] __attribute__ ((aligned(4)));
    216 static unsigned char rxb[NUM_RX_DESC * RX_BUF_SIZE] __attribute__ ((aligned(4)));
    217 #endif
    218 
    219 /* Function Prototypes */
    220 
    221 struct nic *natsemi_probe(struct nic *nic, unsigned short *io_addrs, struct pci_device *pci);
    222 static int eeprom_read(long addr, int location);
    223 static int mdio_read(int phy_id, int location);
    224 static void natsemi_init(struct nic *nic);
    225 static void natsemi_reset(struct nic *nic);
    226 static void natsemi_init_rxfilter(struct nic *nic);
    227 static void natsemi_init_txd(struct nic *nic);
    228 static void natsemi_init_rxd(struct nic *nic);
    229 static void natsemi_set_rx_mode(struct nic *nic);
    230 static void natsemi_check_duplex(struct nic *nic);
    231 static void natsemi_transmit(struct nic *nic, const char *d, unsigned int t, unsigned int s, const char *p);
    232 static int  natsemi_poll(struct nic *nic);
    233 static void natsemi_disable(struct nic *nic);
    234 
    235 /*
    236  * Function: natsemi_probe
    237  *
    238  * Description: Retrieves the MAC address of the card, and sets up some
    239  * globals required by other routines,  and initializes the NIC, making it
    240  * ready to send and receive packets.
    241  *
    242  * Side effects:
    243  *            leaves the ioaddress of the natsemi chip in the variable ioaddr.
    244  *            leaves the natsemi initialized, and ready to recieve packets.
    245  *
    246  * Returns:   struct nic *:          pointer to NIC data structure
    247  */
    248 
    249 struct nic *
    250 natsemi_probe(struct nic *nic, unsigned short *io_addrs, struct pci_device *pci)
    251 {
    252     int i;
    253     int prev_eedata;
    254     u32 tmp;
    255 
    256     if (io_addrs == 0 || *io_addrs == 0)
    257         return NULL;
    258 
    259     /* initialize some commonly used globals */
    260 
    261     ioaddr     = *io_addrs & ~3;
    262     vendor     = pci->vendor;
    263     dev_id     = pci->dev_id;
    264     nic_name   = pci->name;
    265 
    266     adjust_pci_device(pci);
    267 
    268     /* natsemi has a non-standard PM control register
    269      * in PCI config space.  Some boards apparently need
    270      * to be brought to D0 in this manner.
    271      */
    272     pcibios_read_config_dword(pci->bus, pci->devfn, PCIPM, &tmp);
    273     if (tmp & (0x03|0x100)) {
    274 	/* D0 state, disable PME assertion */
    275 	u32 newtmp = tmp & ~(0x03|0x100);
    276 	pcibios_write_config_dword(pci->bus, pci->devfn, PCIPM, newtmp);
    277     }
    278 
    279     /* get MAC address */
    280 
    281     prev_eedata = eeprom_read(ioaddr, 6);
    282     for (i = 0; i < 3; i++) {
    283 	int eedata = eeprom_read(ioaddr, i + 7);
    284 	nic->node_addr[i*2] = (eedata << 1) + (prev_eedata >> 15);
    285 	nic->node_addr[i*2+1] = eedata >> 7;
    286 	prev_eedata = eedata;
    287     }
    288 
    289     printf("\nnatsemi_probe: MAC addr %! at ioaddr %#hX\n",
    290            nic->node_addr, ioaddr);
    291     printf("natsemi_probe: Vendor:%#hX Device:%#hX\n", vendor, dev_id);
    292 
    293     /* Reset the chip to erase any previous misconfiguration. */
    294     outl(ChipReset, ioaddr + ChipCmd);
    295 
    296     advertising = mdio_read(1, 4);
    297     {
    298 	u32 chip_config = inl(ioaddr + ChipConfig);
    299 	printf("%s: Transceiver default autoneg. %s "
    300 	       "10%s %s duplex.\n",
    301 	       nic_name,
    302 	       chip_config & 0x2000 ? "enabled, advertise" : "disabled, force",
    303 	       chip_config & 0x4000 ? "0" : "",
    304 	       chip_config & 0x8000 ? "full" : "half");
    305     }
    306     printf("%s: Transceiver status %hX advertising %hX\n",
    307 	   nic_name, (int)inl(ioaddr + 0x84), advertising);
    308 
    309     /* Disable PME:
    310      * The PME bit is initialized from the EEPROM contents.
    311      * PCI cards probably have PME disabled, but motherboard
    312      * implementations may have PME set to enable WakeOnLan.
    313      * With PME set the chip will scan incoming packets but
    314      * nothing will be written to memory. */
    315     SavedClkRun = inl(ioaddr + ClkRun);
    316     outl(SavedClkRun & ~0x100, ioaddr + ClkRun);
    317 
    318     /* initialize device */
    319     natsemi_init(nic);
    320 
    321     nic->reset    = natsemi_init;
    322     nic->poll     = natsemi_poll;
    323     nic->transmit = natsemi_transmit;
    324     nic->disable  = natsemi_disable;
    325 
    326     return nic;
    327 }
    328 
    329 /* Read the EEPROM and MII Management Data I/O (MDIO) interfaces.
    330    The EEPROM code is for the common 93c06/46 EEPROMs with 6 bit addresses.
    331 */
    332 
    333 /* Delay between EEPROM clock transitions.
    334    No extra delay is needed with 33Mhz PCI, but future 66Mhz access may need
    335    a delay. */
    336 #define eeprom_delay(ee_addr)	inl(ee_addr)
    337 
    338 enum EEPROM_Ctrl_Bits {
    339     EE_ShiftClk   = 0x04,
    340     EE_DataIn     = 0x01,
    341     EE_ChipSelect = 0x08,
    342     EE_DataOut    = 0x02
    343 };
    344 
    345 #define EE_Write0 (EE_ChipSelect)
    346 #define EE_Write1 (EE_ChipSelect | EE_DataIn)
    347 
    348 /* The EEPROM commands include the alway-set leading bit. */
    349 enum EEPROM_Cmds {
    350     EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6),
    351 };
    352 
    353 static int eeprom_read(long addr, int location)
    354 {
    355     int i;
    356     int retval = 0;
    357     int ee_addr = addr + EECtrl;
    358     int read_cmd = location | EE_ReadCmd;
    359     outl(EE_Write0, ee_addr);
    360 
    361     /* Shift the read command bits out. */
    362     for (i = 10; i >= 0; i--) {
    363 	short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0;
    364 	outl(dataval, ee_addr);
    365 	eeprom_delay(ee_addr);
    366 	outl(dataval | EE_ShiftClk, ee_addr);
    367 	eeprom_delay(ee_addr);
    368     }
    369     outl(EE_ChipSelect, ee_addr);
    370     eeprom_delay(ee_addr);
    371 
    372     for (i = 0; i < 16; i++) {
    373 	outl(EE_ChipSelect | EE_ShiftClk, ee_addr);
    374 	eeprom_delay(ee_addr);
    375 	retval |= (inl(ee_addr) & EE_DataOut) ? 1 << i : 0;
    376 	outl(EE_ChipSelect, ee_addr);
    377 	eeprom_delay(ee_addr);
    378     }
    379 
    380     /* Terminate the EEPROM access. */
    381     outl(EE_Write0, ee_addr);
    382     outl(0, ee_addr);
    383 
    384     return retval;
    385 }
    386 
    387 /*  MII transceiver control section.
    388 	The 83815 series has an internal transceiver, and we present the
    389 	management registers as if they were MII connected. */
    390 
    391 static int mdio_read(int phy_id, int location)
    392 {
    393     if (phy_id == 1 && location < 32)
    394 	return inl(ioaddr + 0x80 + (location<<2)) & 0xffff;
    395     else
    396 	return 0xffff;
    397 }
    398 
    399 /* Function: natsemi_init
    400  *
    401  * Description: resets the ethernet controller chip and configures
    402  *    registers and data structures required for sending and receiving packets.
    403  *
    404  * Arguments: struct nic *nic:          NIC data structure
    405  *
    406  * returns:   void.
    407  */
    408 
    409 static void
    410 natsemi_init(struct nic *nic)
    411 {
    412     natsemi_reset(nic);
    413 
    414     /* Disable PME:
    415      * The PME bit is initialized from the EEPROM contents.
    416      * PCI cards probably have PME disabled, but motherboard
    417      * implementations may have PME set to enable WakeOnLan.
    418      * With PME set the chip will scan incoming packets but
    419      * nothing will be written to memory. */
    420     outl(SavedClkRun & ~0x100, ioaddr + ClkRun);
    421 
    422     natsemi_init_rxfilter(nic);
    423 
    424     natsemi_init_txd(nic);
    425     natsemi_init_rxd(nic);
    426 
    427     /* Initialize other registers. */
    428     /* Configure the PCI bus bursts and FIFO thresholds. */
    429     /* Configure for standard, in-spec Ethernet. */
    430     if (inl(ioaddr + ChipConfig) & 0x20000000) {	/* Full duplex */
    431 	tx_config = 0xD0801002;
    432 	rx_config = 0x10000020;
    433     } else {
    434 	tx_config = 0x10801002;
    435 	rx_config = 0x0020;
    436     }
    437     outl(tx_config, ioaddr + TxConfig);
    438     outl(rx_config, ioaddr + RxConfig);
    439 
    440     natsemi_check_duplex(nic);
    441     natsemi_set_rx_mode(nic);
    442 
    443     outl(RxOn, ioaddr + ChipCmd);
    444 }
    445 
    446 /*
    447  * Function: natsemi_reset
    448  *
    449  * Description: soft resets the controller chip
    450  *
    451  * Arguments: struct nic *nic:          NIC data structure
    452  *
    453  * Returns:   void.
    454  */
    455 static void
    456 natsemi_reset(struct nic *nic)
    457 {
    458     outl(ChipReset, ioaddr + ChipCmd);
    459 
    460     /* On page 78 of the spec, they recommend some settings for "optimum
    461        performance" to be done in sequence.  These settings optimize some
    462        of the 100Mbit autodetection circuitry.  Also, we only want to do
    463        this for rev C of the chip.
    464     */
    465     if (inl(ioaddr + SiliconRev) == 0x302) {
    466 	outw(0x0001, ioaddr + PGSEL);
    467 	outw(0x189C, ioaddr + PMDCSR);
    468 	outw(0x0000, ioaddr + TSTDAT);
    469 	outw(0x5040, ioaddr + DSPCFG);
    470 	outw(0x008C, ioaddr + SDCFG);
    471     }
    472     /* Disable interrupts using the mask. */
    473     outl(0, ioaddr + IntrMask);
    474     outl(0, ioaddr + IntrEnable);
    475 }
    476 
    477 /* Function: natsemi_init_rxfilter
    478  *
    479  * Description: sets receive filter address to our MAC address
    480  *
    481  * Arguments: struct nic *nic:          NIC data structure
    482  *
    483  * returns:   void.
    484  */
    485 
    486 static void
    487 natsemi_init_rxfilter(struct nic *nic)
    488 {
    489     int i;
    490 
    491     for (i = 0; i < ETH_ALEN; i += 2) {
    492 	outl(i, ioaddr + RxFilterAddr);
    493 	outw(nic->node_addr[i] + (nic->node_addr[i+1] << 8), ioaddr + RxFilterData);
    494     }
    495 }
    496 
    497 /*
    498  * Function: natsemi_init_txd
    499  *
    500  * Description: initializes the Tx descriptor
    501  *
    502  * Arguments: struct nic *nic:          NIC data structure
    503  *
    504  * returns:   void.
    505  */
    506 
    507 static void
    508 natsemi_init_txd(struct nic *nic)
    509 {
    510     txd.link   = (u32) 0;
    511     txd.cmdsts = (u32) 0;
    512     txd.bufptr = (u32) &txb[0];
    513 
    514     /* load Transmit Descriptor Register */
    515     outl((u32) &txd, ioaddr + TxRingPtr);
    516     if (natsemi_debug > 1)
    517         printf("natsemi_init_txd: TX descriptor register loaded with: %X\n",
    518                inl(ioaddr + TxRingPtr));
    519 }
    520 
    521 /* Function: natsemi_init_rxd
    522  *
    523  * Description: initializes the Rx descriptor ring
    524  *
    525  * Arguments: struct nic *nic:          NIC data structure
    526  *
    527  * Returns:   void.
    528  */
    529 
    530 static void
    531 natsemi_init_rxd(struct nic *nic)
    532 {
    533     int i;
    534 
    535     cur_rx = 0;
    536 
    537     /* init RX descriptor */
    538     for (i = 0; i < NUM_RX_DESC; i++) {
    539         rxd[i].link   = (i+1 < NUM_RX_DESC) ? (u32) &rxd[i+1] : (u32) &rxd[0];
    540         rxd[i].cmdsts = (u32) RX_BUF_SIZE;
    541         rxd[i].bufptr = (u32) &rxb[i*RX_BUF_SIZE];
    542         if (natsemi_debug > 1)
    543             printf("natsemi_init_rxd: rxd[%d]=%X link=%X cmdsts=%X bufptr=%X\n",
    544                    i, &rxd[i], rxd[i].link, rxd[i].cmdsts, rxd[i].bufptr);
    545     }
    546 
    547     /* load Receive Descriptor Register */
    548     outl((u32) &rxd[0], ioaddr + RxRingPtr);
    549 
    550     if (natsemi_debug > 1)
    551         printf("natsemi_init_rxd: RX descriptor register loaded with: %X\n",
    552                inl(ioaddr + RxRingPtr));
    553 }
    554 
    555 /* Function: natsemi_set_rx_mode
    556  *
    557  * Description:
    558  *    sets the receive mode to accept all broadcast packets and packets
    559  *    with our MAC address, and reject all multicast packets.
    560  *
    561  * Arguments: struct nic *nic:          NIC data structure
    562  *
    563  * Returns:   void.
    564  */
    565 
    566 static void natsemi_set_rx_mode(struct nic *nic)
    567 {
    568     u32 rx_mode = AcceptBroadcast | AcceptMyPhys;
    569 
    570     outl(rx_mode, ioaddr + RxFilterAddr);
    571 }
    572 
    573 static void natsemi_check_duplex(struct nic *nic)
    574 {
    575     int duplex = inl(ioaddr + ChipConfig) & 0x20000000 ? 1 : 0;
    576 
    577     if (natsemi_debug)
    578 	printf("%s: Setting %s-duplex based on negotiated link"
    579 	       " capability.\n", nic_name,
    580 	       duplex ? "full" : "half");
    581     if (duplex) {
    582 	rx_config |= 0x10000000;
    583 	tx_config |= 0xC0000000;
    584     } else {
    585 	rx_config &= ~0x10000000;
    586 	tx_config &= ~0xC0000000;
    587     }
    588     outl(tx_config, ioaddr + TxConfig);
    589     outl(rx_config, ioaddr + RxConfig);
    590 }
    591 
    592 /* Function: natsemi_transmit
    593  *
    594  * Description: transmits a packet and waits for completion or timeout.
    595  *
    596  * Arguments: char d[6]:          destination ethernet address.
    597  *            unsigned short t:   ethernet protocol type.
    598  *            unsigned short s:   size of the data-part of the packet.
    599  *            char *p:            the data for the packet.
    600  *
    601  * Returns:   void.
    602  */
    603 
    604 static void
    605 natsemi_transmit(struct nic  *nic,
    606 		 const char  *d,     /* Destination */
    607 		 unsigned int t,     /* Type */
    608 		 unsigned int s,     /* size */
    609 		 const char  *p)     /* Packet */
    610 {
    611     u32 status, to, nstype;
    612     u32 tx_status;
    613 
    614     /* Stop the transmitter */
    615     outl(TxOff, ioaddr + ChipCmd);
    616 
    617     /* load Transmit Descriptor Register */
    618     outl((u32) &txd, ioaddr + TxRingPtr);
    619     if (natsemi_debug > 1)
    620         printf("natsemi_transmit: TX descriptor register loaded with: %X\n",
    621                inl(ioaddr + TxRingPtr));
    622 
    623     memcpy(txb, d, ETH_ALEN);
    624     memcpy(txb + ETH_ALEN, nic->node_addr, ETH_ALEN);
    625     nstype = htons(t);
    626     memcpy(txb + 2 * ETH_ALEN, (char*)&nstype, 2);
    627     memcpy(txb + ETH_HLEN, p, s);
    628 
    629     s += ETH_HLEN;
    630     s &= DSIZE;
    631 
    632     if (natsemi_debug > 1)
    633         printf("natsemi_transmit: sending %d bytes ethtype %hX\n", (int) s, t);
    634 
    635     /* pad to minimum packet size */
    636     while (s < ETH_ZLEN)
    637         txb[s++] = '\0';
    638 
    639     /* set the transmit buffer descriptor and enable Transmit State Machine */
    640     txd.bufptr = (u32) &txb[0];
    641     txd.cmdsts = (u32) OWN | s;
    642 
    643     /* restart the transmitter */
    644     outl(TxOn, ioaddr + ChipCmd);
    645 
    646     if (natsemi_debug > 1)
    647         printf("natsemi_transmit: Queued Tx packet size %d.\n", (int) s);
    648 
    649     to = currticks() + TX_TIMEOUT;
    650 
    651     while ((((volatile u32) tx_status=txd.cmdsts) & OWN) && (currticks() < to))
    652         /* wait */ ;
    653 
    654     if (currticks() >= to) {
    655         printf("natsemi_transmit: TX Timeout! Tx status %X.\n", tx_status);
    656     }
    657 
    658     if (!(tx_status & 0x08000000)) {
    659 	printf("natsemi_transmit: Transmit error, Tx status %X.\n", tx_status);
    660     }
    661 }
    662 
    663 /* Function: natsemi_poll
    664  *
    665  * Description: checks for a received packet and returns it if found.
    666  *
    667  * Arguments: struct nic *nic:          NIC data structure
    668  *
    669  * Returns:   1 if    packet was received.
    670  *            0 if no packet was received.
    671  *
    672  * Side effects:
    673  *            Returns (copies) the packet to the array nic->packet.
    674  *            Returns the length of the packet in nic->packetlen.
    675  */
    676 
    677 static int
    678 natsemi_poll(struct nic *nic)
    679 {
    680     u32 rx_status = rxd[cur_rx].cmdsts;
    681     int retstat = 0;
    682 
    683     if (natsemi_debug > 2)
    684         printf("natsemi_poll: cur_rx:%d, status:%X\n", cur_rx, rx_status);
    685 
    686     if (!(rx_status & OWN))
    687         return retstat;
    688 
    689     if (natsemi_debug > 1)
    690         printf("natsemi_poll: got a packet: cur_rx:%d, status:%X\n",
    691                cur_rx, rx_status);
    692 
    693     nic->packetlen = (rx_status & DSIZE) - CRC_SIZE;
    694 
    695     if ((rx_status & (DescMore|DescPktOK|RxTooLong)) != DescPktOK) {
    696         /* corrupted packet received */
    697         printf("natsemi_poll: Corrupted packet received, buffer status = %X\n",
    698                rx_status);
    699         retstat = 0;
    700     } else {
    701         /* give packet to higher level routine */
    702         memcpy(nic->packet, (rxb + cur_rx*RX_BUF_SIZE), nic->packetlen);
    703         retstat = 1;
    704     }
    705 
    706     /* return the descriptor and buffer to receive ring */
    707     rxd[cur_rx].cmdsts = RX_BUF_SIZE;
    708     rxd[cur_rx].bufptr = (u32) &rxb[cur_rx*RX_BUF_SIZE];
    709 
    710     if (++cur_rx == NUM_RX_DESC)
    711         cur_rx = 0;
    712 
    713     /* re-enable the potentially idle receive state machine */
    714     outl(RxOn, ioaddr + ChipCmd);
    715 
    716     return retstat;
    717 }
    718 
    719 /* Function: natsemi_disable
    720  *
    721  * Description: Turns off interrupts and stops Tx and Rx engines
    722  *
    723  * Arguments: struct nic *nic:          NIC data structure
    724  *
    725  * Returns:   void.
    726  */
    727 
    728 static void
    729 natsemi_disable(struct nic *nic)
    730 {
    731     /* Disable interrupts using the mask. */
    732     outl(0, ioaddr + IntrMask);
    733     outl(0, ioaddr + IntrEnable);
    734 
    735     /* Stop the chip's Tx and Rx processes. */
    736     outl(RxOff | TxOff, ioaddr + ChipCmd);
    737 
    738     /* Restore PME enable bit */
    739     outl(SavedClkRun, ioaddr + ClkRun);
    740 }
    741