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