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