duplex setting added to natsemi.c
[people/holger/gpxe.git] / src / drivers / net / natsemi.c
1 /* natsemi.c - gPXE driver for the NatSemi DP8381x series. */
2
3 /*
4
5  
6    natsemi.c: An Etherboot driver for the NatSemi DP8381x series.
7
8    Copyright (C) 2001 Entity Cyber, Inc.
9    
10    This development of this Etherboot driver was funded by 
11    
12       Sicom Systems: http://www.sicompos.com/
13    
14    Author: Marty Connor (mdc@thinguin.org)         
15    Adapted from a Linux driver which was written by Donald Becker
16    
17    This software may be used and distributed according to the terms
18    of the GNU Public License (GPL), incorporated herein by reference.
19    
20    Original Copyright Notice:
21    
22    Written/copyright 1999-2001 by Donald Becker.
23    
24    This software may be used and distributed according to the terms of
25    the GNU General Public License (GPL), incorporated herein by reference.
26    Drivers based on or derived from this code fall under the GPL and must
27    retain the authorship, copyright and license notice.  This file is not
28    a complete program and may only be used when the entire operating
29    system is licensed under the GPL.  License for under other terms may be
30    available.  Contact the original author for details.
31    
32    The original author may be reached as becker@scyld.com, or at
33    Scyld Computing Corporation
34    410 Severn Ave., Suite 210
35    Annapolis MD 21403
36    
37    Support information and updates available at
38    http://www.scyld.com/network/netsemi.html
39    
40    References:
41    
42    http://www.scyld.com/expert/100mbps.html
43    http://www.scyld.com/expert/NWay.html
44    Datasheet is available from:
45    http://www.national.com/pf/DP/DP83815.html
46
47 */
48
49 /* Revision History */
50
51 /*
52   02 JUL 2007 Udayan Kumar       1.2 ported the driver from etherboot to gPXE API.
53                                      Fully rewritten,adapting the old driver.
54                                      Added a circular buffer for transmit and receive.
55                                      transmit routine will not wait for transmission to finish.
56                                      poll routine deals with it.
57
58   13 Dec 2003 timlegge           1.1 Enabled Multicast Support
59   29 May 2001  mdc               1.0
60      Initial Release.            Tested with Netgear FA311 and FA312 boards
61 */
62  
63
64
65
66 #include <stdint.h>
67 #include <pic8259.h>
68 #include <stdlib.h>
69 #include <stdio.h>
70 #include <io.h>
71 #include <errno.h>
72 #include <timer.h>
73 #include <byteswap.h>
74 #include <gpxe/pci.h>
75 #include <gpxe/if_ether.h>
76 #include <gpxe/ethernet.h>
77 #include <gpxe/iobuf.h>
78 #include <gpxe/netdevice.h>
79 #include <gpxe/spi_bit.h>
80 #include <gpxe/threewire.h>
81 #include <gpxe/nvo.h>
82
83 #define TX_RING_SIZE 4
84 #define NUM_RX_DESC  4
85 #define RX_BUF_SIZE 1536
86 #define OWN       0x80000000
87 #define DSIZE     0x00000FFF
88 #define CRC_SIZE  4
89
90 struct natsemi_tx {
91         uint32_t link;
92         uint32_t cmdsts;
93         uint32_t bufptr;
94 };
95
96 struct natsemi_rx {
97         uint32_t link;
98         uint32_t cmdsts;
99         uint32_t bufptr;
100 };
101
102 struct natsemi_nic {
103         unsigned short ioaddr;
104         unsigned short tx_cur;
105         unsigned short tx_dirty;
106         unsigned short rx_cur;
107         struct natsemi_tx tx[TX_RING_SIZE];
108         struct natsemi_rx rx[NUM_RX_DESC];
109
110         /* need to add iobuf as we cannot free iobuf->data in close without this 
111          * alternatively substracting sizeof(head) and sizeof(list_head) can also 
112          * give the same.
113          */
114         struct io_buffer *iobuf[NUM_RX_DESC];
115
116         /* netdev_tx_complete needs pointer to the iobuf of the data so as to free 
117          * it from the memory.
118          */
119         struct io_buffer *tx_iobuf[TX_RING_SIZE];
120         struct spi_bit_basher spibit;
121         struct spi_device eeprom;
122         struct nvo_block nvo;
123 };
124
125 /* NATSEMI: Offsets to the device registers.
126  * Unlike software-only systems, device drivers interact with complex hardware.
127  * It's not useful to define symbolic names for every register bit in the
128  * device.
129  */
130 enum register_offsets {
131     ChipCmd      = 0x00, 
132     ChipConfig   = 0x04, 
133     EECtrl       = 0x08, 
134     PCIBusCfg    = 0x0C,
135     IntrStatus   = 0x10, 
136     IntrMask     = 0x14, 
137     IntrEnable   = 0x18,
138     TxRingPtr    = 0x20, 
139     TxConfig     = 0x24,
140     RxRingPtr    = 0x30,
141     RxConfig     = 0x34, 
142     ClkRun       = 0x3C,
143     WOLCmd       = 0x40, 
144     PauseCmd     = 0x44,
145     RxFilterAddr = 0x48, 
146     RxFilterData = 0x4C,
147     BootRomAddr  = 0x50, 
148     BootRomData  = 0x54, 
149     SiliconRev   = 0x58, 
150     StatsCtrl    = 0x5C,
151     StatsData    = 0x60, 
152     RxPktErrs    = 0x60, 
153     RxMissed     = 0x68, 
154     RxCRCErrs    = 0x64,
155     PCIPM        = 0x44,
156     PhyStatus    = 0xC0, 
157     MIntrCtrl    = 0xC4, 
158     MIntrStatus  = 0xC8,
159
160     /* These are from the spec, around page 78... on a separate table. 
161      */
162     PGSEL        = 0xCC, 
163     PMDCSR       = 0xE4, 
164     TSTDAT       = 0xFC, 
165     DSPCFG       = 0xF4, 
166     SDCFG        = 0x8C,
167     BasicControl = 0x80,        
168     BasicStatus  = 0x84
169             
170 };
171
172 /* Bit in ChipCmd.
173  */
174 enum ChipCmdBits {
175     ChipReset = 0x100, 
176     RxReset   = 0x20, 
177     TxReset   = 0x10, 
178     RxOff     = 0x08, 
179     RxOn      = 0x04,
180     TxOff     = 0x02, 
181     TxOn      = 0x01
182 };
183
184 /* Bits in the RxMode register.
185  */
186 enum rx_mode_bits {
187     AcceptErr          = 0x20,
188     AcceptRunt         = 0x10,
189     AcceptBroadcast    = 0xC0000000,
190     AcceptMulticast    = 0x00200000, 
191     AcceptAllMulticast = 0x20000000,
192     AcceptAllPhys      = 0x10000000, 
193     AcceptMyPhys       = 0x08000000,
194     RxFilterEnable     = 0x80000000
195 };
196
197 /* Bits in network_desc.status
198  */
199 enum desc_status_bits {
200     DescOwn   = 0x80000000, 
201     DescMore  = 0x40000000, 
202     DescIntr  = 0x20000000,
203     DescNoCRC = 0x10000000,
204     DescPktOK = 0x08000000, 
205     RxTooLong = 0x00400000
206 };
207
208 /*Bits in Interrupt Mask register
209  */
210 enum Intr_mask_register_bits {
211     RxOk       = 0x001,
212     RxErr      = 0x004,
213     TxOk       = 0x040,
214     TxErr      = 0x100 
215 };      
216
217 /*  EEPROM access , values are devices specific
218  */
219 #define EE_CS           0x08    /* EEPROM chip select */
220 #define EE_SK           0x04    /* EEPROM shift clock */
221 #define EE_DI           0x01    /* Data in */
222 #define EE_DO           0x02    /* Data out */
223
224 /* Offsets within EEPROM (these are word offsets)
225  */
226 #define EE_MAC 7
227 #define EE_REG  EECtrl
228 static uint32_t SavedClkRun;    
229
230 static const uint8_t nat_ee_bits[] = {
231         [SPI_BIT_SCLK]  = EE_SK,
232         [SPI_BIT_MOSI]  = EE_DI,
233         [SPI_BIT_MISO]  = EE_DO,
234         [SPI_BIT_SS(0)] = EE_CS,
235 };
236
237 static int nat_spi_read_bit ( struct bit_basher *basher,
238                               unsigned int bit_id ) {
239         struct natsemi_nic *nat = container_of ( basher, struct natsemi_nic,
240                                                  spibit.basher );
241         uint8_t mask = nat_ee_bits[bit_id];
242         uint8_t eereg;
243
244         eereg = inb ( nat->ioaddr + EE_REG );
245         return ( eereg & mask );
246 }
247
248 static void nat_spi_write_bit ( struct bit_basher *basher,
249                                 unsigned int bit_id, unsigned long data ) {
250         struct natsemi_nic *nat = container_of ( basher, struct natsemi_nic,
251                                                  spibit.basher );
252         uint8_t mask = nat_ee_bits[bit_id];
253         uint8_t eereg;
254
255         eereg = inb ( nat->ioaddr + EE_REG );
256         eereg &= ~mask;
257         eereg |= ( data & mask );
258         outb ( eereg, nat->ioaddr + EE_REG );
259 }
260
261 static struct bit_basher_operations nat_basher_ops = {
262         .read = nat_spi_read_bit,
263         .write = nat_spi_write_bit,
264 };
265
266 /* It looks that this portion of EEPROM can be used for 
267  * non-volatile stored options. Data sheet does not talk about this region.
268  * Currently it is not working. But with some efforts it can.
269  */
270 static struct nvo_fragment nat_nvo_fragments[] = {
271         { 0x0c, 0x68 },
272         { 0, 0 }
273 };
274
275 /*
276  * Set up for EEPROM access
277  *
278  * @v NAT               NATSEMI NIC
279  */
280  void nat_init_eeprom ( struct natsemi_nic *nat ) {
281
282         /* Initialise three-wire bus 
283          */
284         nat->spibit.basher.op = &nat_basher_ops;
285         nat->spibit.bus.mode = SPI_MODE_THREEWIRE;
286         nat->spibit.endianness = SPI_BIT_LITTLE_ENDIAN;
287         init_spi_bit_basher ( &nat->spibit );
288
289         /*natsemi DP 83815 only supports at93c46
290          */
291         init_at93c46 ( &nat->eeprom, 16 );
292         nat->eeprom.bus = &nat->spibit.bus;
293
294         nat->nvo.nvs = &nat->eeprom.nvs;
295         nat->nvo.fragments = nat_nvo_fragments;
296 }
297
298 /*
299  * Reset NIC
300  *
301  * @v           NATSEMI NIC
302  *
303  * Issues a hardware reset and waits for the reset to complete.
304  */
305 static void nat_reset ( struct natsemi_nic *nat ) {
306
307         int i;
308
309         /* Reset chip
310          */
311         outl ( ChipReset, nat->ioaddr + ChipCmd );
312         mdelay ( 10 );
313         nat->tx_dirty = 0;
314         nat->tx_cur = 0;
315         for ( i = 0 ; i < TX_RING_SIZE ; i++ ) {
316                 nat->tx[i].link = 0;
317                 nat->tx[i].cmdsts = 0;
318                 nat->tx[i].bufptr = 0;
319         }
320         nat->rx_cur = 0;
321         outl ( virt_to_bus( &nat->tx[0] ),nat->ioaddr + TxRingPtr );
322         outl ( virt_to_bus( &nat->rx[0] ),nat->ioaddr + RxRingPtr );
323
324         outl ( TxOff|RxOff, nat->ioaddr + ChipCmd );
325
326         /* Restore PME enable bit
327          */
328         outl ( SavedClkRun, nat->ioaddr + ClkRun );
329 }
330
331 /*
332  * Open NIC
333  *
334  * @v netdev            Net device
335  * @ret rc              Return status code
336  */
337 static int nat_open ( struct net_device *netdev ) {
338         struct natsemi_nic *nat = netdev->priv;
339         int i;
340         uint32_t tx_config,rx_config;
341         
342         /* Disable PME:
343          * The PME bit is initialized from the EEPROM contents.
344          * PCI cards probably have PME disabled, but motherboard
345          * implementations may have PME set to enable WakeOnLan. 
346          * With PME set the chip will scan incoming packets but
347          * nothing will be written to memory. 
348          */
349         SavedClkRun = inl ( nat->ioaddr + ClkRun );
350         outl ( SavedClkRun & ~0x100, nat->ioaddr + ClkRun );
351
352         /* Setting up Mac address in the NIC
353          */
354         for ( i = 0 ; i < ETH_ALEN ; i+=2 ) {
355                 outl ( i,nat->ioaddr + RxFilterAddr );
356                 outw ( netdev->ll_addr[i] + ( netdev->ll_addr[i + 1] << 8 ),
357                        nat->ioaddr + RxFilterData );
358         }
359
360         /*Set up the Tx Ring
361          */
362         nat->tx_cur = 0;
363         nat->tx_dirty = 0;
364         for ( i = 0 ; i < TX_RING_SIZE ; i++ ) {
365                 nat->tx[i].link   = virt_to_bus ( ( i + 1 < TX_RING_SIZE ) ? &nat->tx[i + 1] : &nat->tx[0] );
366                 nat->tx[i].cmdsts = 0;
367                 nat->tx[i].bufptr = 0;
368         }
369
370         /* Set up RX ring
371          */
372         nat->rx_cur = 0;
373         for ( i = 0 ; i < NUM_RX_DESC ; i++ ) {
374                 nat->iobuf[i] = alloc_iob ( RX_BUF_SIZE );
375                 if ( !nat->iobuf[i] )
376                         goto memory_alloc_err;
377                 nat->rx[i].link   = virt_to_bus ( ( i + 1 < NUM_RX_DESC ) ? &nat->rx[i + 1] : &nat->rx[0] );
378                 nat->rx[i].cmdsts = RX_BUF_SIZE;
379                 nat->rx[i].bufptr = virt_to_bus ( nat->iobuf[i]->data );
380         }
381
382         /* load Receive Descriptor Register
383          */
384         outl ( virt_to_bus ( &nat->rx[0] ), nat->ioaddr + RxRingPtr );
385         DBG ( "Natsemi Rx descriptor loaded with: %X\n",
386                 (unsigned int) inl ( nat->ioaddr + RxRingPtr ) );               
387
388         /* setup Tx ring
389          */
390         outl ( virt_to_bus ( &nat->tx[0] ),nat->ioaddr + TxRingPtr );
391         DBG ( "Natsemi Tx descriptor loaded with: %X\n",
392                 (unsigned int)inl ( nat->ioaddr + TxRingPtr ) );
393
394         /* Enables RX
395          */
396         outl ( RxFilterEnable|AcceptBroadcast|AcceptAllMulticast|AcceptMyPhys,
397                  nat->ioaddr + RxFilterAddr );
398
399         /* Initialize other registers. 
400          * Configure the PCI bus bursts and FIFO thresholds. 
401          * Configure for standard, in-spec Ethernet. 
402          */
403         if ( inl ( nat->ioaddr + ChipConfig ) & 0x20000000 ) {  /* Full duplex */
404                 tx_config = 0xD0801002|0xC0000000;
405                 DBG("Full duplex\n");
406                 rx_config = 0x10000020|0x10000000;;
407         } else {
408                 tx_config = 0x10801002& ~0xC0000000;;
409                 DBG("Half duplex\n");
410                 rx_config = 0x0020& ~0x10000000;;;
411         }
412         outl ( tx_config, nat->ioaddr + TxConfig );
413         outl ( rx_config, nat->ioaddr + RxConfig );
414
415         /*start the receiver 
416          */
417         outl ( RxOn, nat->ioaddr + ChipCmd );
418
419         /* mask the interrupts. note interrupt is not enabled here
420          */
421         return 0;
422                        
423 memory_alloc_err:
424
425         /* this block frees the previously allocated buffers
426          * if memory for all the buffers is not available
427          */
428         i = 0;
429         while ( nat->rx[i].cmdsts == RX_BUF_SIZE ) {
430                 free_iob ( nat->iobuf[i] );
431                 i++;
432         }
433         return -ENOMEM; 
434 }
435
436 /**
437  * Close NIC
438  *
439  * @v netdev            Net device
440  */
441 static void nat_close ( struct net_device *netdev ) {
442         struct natsemi_nic *nat = netdev->priv;
443         int i;
444
445         /* Reset the hardware to disable everything in one go
446          */
447         nat_reset ( nat );
448
449         /* Free RX ring
450          */
451         for ( i = 0; i < NUM_RX_DESC ; i++ ) {
452                 
453                 free_iob ( nat->iobuf[i] );
454         }
455 }
456
457 /** 
458  * Transmit packet
459  *
460  * @v netdev    Network device
461  * @v iobuf     I/O buffer
462  * @ret rc      Return status code
463  */
464 static int nat_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
465         struct natsemi_nic *nat = netdev->priv;
466
467         /* check for space in TX ring
468          */
469         if ( nat->tx[nat->tx_cur].cmdsts != 0 ) {
470                 DBG ( "TX overflow\n" );
471                 return -ENOBUFS;
472         }
473
474         /* to be used in netdev_tx_complete
475          */
476         nat->tx_iobuf[nat->tx_cur] = iobuf;
477
478         /* Pad and align packet has not been used because its not required here
479          * iob_pad ( iobuf, ETH_ZLEN ); can be used to achieve it
480          */
481
482         /* Add to TX ring
483          */
484         DBG ( "TX id %d at %lx + %x\n", nat->tx_cur,
485               virt_to_bus ( &iobuf->data ), iob_len ( iobuf ) );
486
487         nat->tx[nat->tx_cur].bufptr = virt_to_bus ( iobuf->data );
488         nat->tx[nat->tx_cur].cmdsts = iob_len ( iobuf ) | OWN;
489
490         /* increment the circular buffer pointer to the next buffer location
491          */
492         nat->tx_cur = ( nat->tx_cur + 1 ) % TX_RING_SIZE;
493
494         /*start the transmitter 
495          */
496         outl ( TxOn, nat->ioaddr + ChipCmd );
497
498         return 0;
499 }
500
501 /** 
502  * Poll for received packets
503  *
504  * @v netdev    Network device
505  * @v rx_quota  Maximum number of packets to receive
506  */
507 static void nat_poll ( struct net_device *netdev) {
508         struct natsemi_nic *nat = netdev->priv;
509         unsigned int status;
510         unsigned int rx_status;
511         unsigned int intr_status;
512         unsigned int rx_len;
513         struct io_buffer *rx_iob;
514         int i;
515         
516         /* read the interrupt register
517          */
518         intr_status = inl ( nat->ioaddr + IntrStatus );
519         if ( !intr_status )
520                 goto end;
521
522         /* check the status of packets given to card for transmission
523          */     
524         DBG ( "Intr status %X\n",intr_status );
525
526         i = nat->tx_dirty;
527         while ( i!= nat->tx_cur ) {
528                 status = nat->tx[nat->tx_dirty].cmdsts;
529                 DBG ( "value of tx_dirty = %d tx_cur=%d status=%X\n",
530                         nat->tx_dirty,nat->tx_cur,status );
531                 
532                 /* check if current packet has been transmitted or not
533                  */
534                 if ( status & OWN ) 
535                         break;
536
537                 /* Check if any errors in transmission
538                  */
539                 if (! ( status & DescPktOK ) ) {
540                         DBG ( "Error in sending Packet status:%X\n",
541                                         (unsigned int) status );
542                         netdev_tx_complete_err ( netdev,nat->tx_iobuf[nat->tx_dirty],-EINVAL );
543                 } else {
544                         DBG ( "Success in transmitting Packet\n" );
545                         netdev_tx_complete ( netdev,nat->tx_iobuf[nat->tx_dirty] );
546                 }
547
548                 /* setting cmdsts zero, indicating that it can be reused 
549                  */
550                 nat->tx[nat->tx_dirty].cmdsts = 0;
551                 nat->tx_dirty = ( nat->tx_dirty + 1 ) % TX_RING_SIZE;
552                 i = ( i + 1 ) % TX_RING_SIZE;
553         }
554         
555         /* Handle received packets 
556          */
557         rx_status = (unsigned int) nat->rx[nat->rx_cur].cmdsts; 
558         while ( ( rx_status & OWN ) ) {
559                 rx_len = ( rx_status & DSIZE ) - CRC_SIZE;
560
561                 /*check for the corrupt packet 
562                  */
563                 if ( ( rx_status & ( DescMore|DescPktOK|RxTooLong ) ) != DescPktOK) {
564                          DBG ( "natsemi_poll: Corrupted packet received, "
565                                         "buffer status = %X ^ %X \n",rx_status,
566                                         (unsigned int) nat->rx[nat->rx_cur].cmdsts );
567                          netdev_rx_err ( netdev,NULL,-EINVAL );
568                 } else  {
569                         rx_iob = alloc_iob ( rx_len );
570
571                         if ( !rx_iob ) 
572                                 /* leave packet for next call to poll
573                                  */
574                                 goto end;
575                         memcpy ( iob_put ( rx_iob,rx_len ),
576                                         nat->iobuf[nat->rx_cur]->data,rx_len );
577                         DBG ( "received packet\n" );
578
579                         /* add to the receive queue. 
580                          */
581                         netdev_rx ( netdev,rx_iob );
582                 }
583                 nat->rx[nat->rx_cur].cmdsts = RX_BUF_SIZE;
584                 nat->rx_cur = ( nat->rx_cur + 1 ) % NUM_RX_DESC;
585                 rx_status = nat->rx[nat->rx_cur].cmdsts; 
586         }
587 end:
588
589         /* re-enable the potentially idle receive state machine 
590          */
591         outl ( RxOn, nat->ioaddr + ChipCmd );   
592 }                               
593
594 /**
595  * Enable/disable interrupts
596  *
597  * @v netdev    Network device
598  * @v enable    Interrupts should be enabled
599  */
600 static void nat_irq ( struct net_device *netdev, int enable ) {
601         struct natsemi_nic *nat = netdev->priv;
602
603         outl ( ( enable ? ( RxOk|RxErr|TxOk|TxErr ) :0 ),
604                 nat->ioaddr + IntrMask); 
605         outl ( ( enable ? 1:0 ),nat->ioaddr + IntrEnable );
606 }
607
608
609
610
611
612 /** natsemi net device operations */
613 static struct net_device_operations nat_operations = {
614         .open           = nat_open,
615         .close          = nat_close,
616         .transmit       = nat_transmit,
617         .poll           = nat_poll,
618         .irq            = nat_irq,
619 };
620
621 /*
622  * Probe PCI device
623  *
624  * @v pci       PCI device
625  * @v id        PCI ID
626  * @ret rc      Return status code
627  */
628 static int nat_probe ( struct pci_device *pci,
629                        const struct pci_device_id *id __unused ) {
630         struct net_device *netdev;
631         struct natsemi_nic *nat = NULL;
632         int rc;
633         int i;
634         uint8_t ll_addr_encoded[MAX_LL_ADDR_LEN];
635         uint8_t last = 0;
636         uint8_t last1 = 0;
637         uint8_t prev_bytes[2];
638
639         /* Allocate net device 
640          */
641         netdev = alloc_etherdev ( sizeof ( *nat ) );
642         if ( ! netdev ) 
643                 return -ENOMEM;
644         netdev_init ( netdev,&nat_operations );
645         nat = netdev->priv;
646         pci_set_drvdata ( pci, netdev );
647         netdev->dev = &pci->dev;
648         memset ( nat, 0, sizeof ( *nat ) );
649         nat->ioaddr = pci->ioaddr;
650
651         /* Fix up PCI device
652          */
653         adjust_pci_device ( pci );
654
655         /* Reset the NIC, set up EEPROM access and read MAC address
656          */
657         nat_reset ( nat );
658         nat_init_eeprom ( nat );
659         nvs_read ( &nat->eeprom.nvs, EE_MAC-1, prev_bytes, 1 );
660         nvs_read ( &nat->eeprom.nvs, EE_MAC, ll_addr_encoded, ETH_ALEN );
661
662         /* decoding the MAC address read from NVS 
663          * and save it in netdev->ll_addr
664          */
665         last = prev_bytes[1] >> 7;
666         for ( i = 0 ; i < ETH_ALEN ; i++ ) {
667                 last1 = ll_addr_encoded[i] >> 7;
668                 netdev->ll_addr[i] = ll_addr_encoded[i] << 1 | last;
669                 last = last1;
670         }
671
672         /* Register network device
673          */
674         if ( ( rc = register_netdev ( netdev ) ) != 0 )
675                 goto err_register_netdev;
676
677         return 0;
678
679 err_register_netdev:
680
681         /* Disable NIC
682          */
683         nat_reset ( nat );
684
685         /* Free net device
686          */
687         netdev_put ( netdev );
688         return rc;
689 }
690
691 /**
692  * Remove PCI device
693  *
694  * @v pci       PCI device
695  */
696 static void nat_remove ( struct pci_device *pci ) {
697         struct net_device *netdev = pci_get_drvdata ( pci );
698         struct natsemi_nic *nat = netdev->priv;
699  
700         if ( nat->nvo.nvs )
701                 nvo_unregister ( &nat->nvo );
702                 
703         unregister_netdev ( netdev );
704         nat_reset ( nat );
705         netdev_put ( netdev );
706 }
707
708 static struct pci_device_id natsemi_nics[] = {
709         PCI_ROM(0x100b, 0x0020, "dp83815", "DP83815"),
710 };
711
712 struct pci_driver natsemi_driver __pci_driver = {
713         .ids = natsemi_nics,
714         .id_count = ( sizeof ( natsemi_nics ) / sizeof ( natsemi_nics[0] ) ),
715         .probe = nat_probe,
716         .remove = nat_remove,
717 };