551fc17ecfc7cc379a804d6467ccd83d1fa2076d
[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;
405                 rx_config = 0x10000020;
406         } else {
407                 tx_config = 0x10801002;
408                 rx_config = 0x0020;
409         }
410         outl ( tx_config, nat->ioaddr + TxConfig );
411         outl ( rx_config, nat->ioaddr + RxConfig );
412
413         /*start the receiver 
414          */
415         outl ( RxOn, nat->ioaddr + ChipCmd );
416
417         /* mask the interrupts. note interrupt is not enabled here
418          */
419         return 0;
420                        
421 memory_alloc_err:
422
423         /* this block frees the previously allocated buffers
424          * if memory for all the buffers is not available
425          */
426         i = 0;
427         while ( nat->rx[i].cmdsts == RX_BUF_SIZE ) {
428                 free_iob ( nat->iobuf[i] );
429                 i++;
430         }
431         return -ENOMEM; 
432 }
433
434 /**
435  * Close NIC
436  *
437  * @v netdev            Net device
438  */
439 static void nat_close ( struct net_device *netdev ) {
440         struct natsemi_nic *nat = netdev->priv;
441         int i;
442
443         /* Reset the hardware to disable everything in one go
444          */
445         nat_reset ( nat );
446
447         /* Free RX ring
448          */
449         for ( i = 0; i < NUM_RX_DESC ; i++ ) {
450                 
451                 free_iob ( nat->iobuf[i] );
452         }
453 }
454
455 /** 
456  * Transmit packet
457  *
458  * @v netdev    Network device
459  * @v iobuf     I/O buffer
460  * @ret rc      Return status code
461  */
462 static int nat_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
463         struct natsemi_nic *nat = netdev->priv;
464
465         /* check for space in TX ring
466          */
467         if ( nat->tx[nat->tx_cur].cmdsts != 0 ) {
468                 DBG ( "TX overflow\n" );
469                 return -ENOBUFS;
470         }
471
472         /* to be used in netdev_tx_complete
473          */
474         nat->tx_iobuf[nat->tx_cur] = iobuf;
475
476         /* Pad and align packet has not been used because its not required here
477          * iob_pad ( iobuf, ETH_ZLEN ); can be used to achieve it
478          */
479
480         /* Add to TX ring
481          */
482         DBG ( "TX id %d at %lx + %x\n", nat->tx_cur,
483               virt_to_bus ( &iobuf->data ), iob_len ( iobuf ) );
484
485         nat->tx[nat->tx_cur].bufptr = virt_to_bus ( iobuf->data );
486         nat->tx[nat->tx_cur].cmdsts = iob_len ( iobuf ) | OWN;
487
488         /* increment the circular buffer pointer to the next buffer location
489          */
490         nat->tx_cur = ( nat->tx_cur + 1 ) % TX_RING_SIZE;
491
492         /*start the transmitter 
493          */
494         outl ( TxOn, nat->ioaddr + ChipCmd );
495
496         return 0;
497 }
498
499 /** 
500  * Poll for received packets
501  *
502  * @v netdev    Network device
503  * @v rx_quota  Maximum number of packets to receive
504  */
505 static void nat_poll ( struct net_device *netdev) {
506         struct natsemi_nic *nat = netdev->priv;
507         unsigned int status;
508         unsigned int rx_status;
509         unsigned int intr_status;
510         unsigned int rx_len;
511         struct io_buffer *rx_iob;
512         int i;
513         
514         /* read the interrupt register
515          */
516         intr_status = inl ( nat->ioaddr + IntrStatus );
517         if ( !intr_status )
518                 goto end;
519
520         /* check the status of packets given to card for transmission
521          */     
522         DBG ( "Intr status %X\n",intr_status );
523
524         i = nat->tx_dirty;
525         while ( i!= nat->tx_cur ) {
526                 status = nat->tx[nat->tx_dirty].cmdsts;
527                 DBG ( "value of tx_dirty = %d tx_cur=%d status=%X\n",
528                         nat->tx_dirty,nat->tx_cur,status );
529                 
530                 /* check if current packet has been transmitted or not
531                  */
532                 if ( status & OWN ) 
533                         break;
534
535                 /* Check if any errors in transmission
536                  */
537                 if (! ( status & DescPktOK ) ) {
538                         DBG ( "Error in sending Packet status:%X\n",
539                                         (unsigned int) status );
540                         netdev_tx_complete_err ( netdev,nat->tx_iobuf[nat->tx_dirty],-EINVAL );
541                 } else {
542                         DBG ( "Success in transmitting Packet\n" );
543                         netdev_tx_complete ( netdev,nat->tx_iobuf[nat->tx_dirty] );
544                 }
545
546                 /* setting cmdsts zero, indicating that it can be reused 
547                  */
548                 nat->tx[nat->tx_dirty].cmdsts = 0;
549                 nat->tx_dirty = ( nat->tx_dirty + 1 ) % TX_RING_SIZE;
550                 i = ( i + 1 ) % TX_RING_SIZE;
551         }
552         
553         /* Handle received packets 
554          */
555         rx_status = (unsigned int) nat->rx[nat->rx_cur].cmdsts; 
556         while ( ( rx_status & OWN ) ) {
557                 rx_len = ( rx_status & DSIZE ) - CRC_SIZE;
558
559                 /*check for the corrupt packet 
560                  */
561                 if ( ( rx_status & ( DescMore|DescPktOK|RxTooLong ) ) != DescPktOK) {
562                          DBG ( "natsemi_poll: Corrupted packet received, "
563                                         "buffer status = %X ^ %X \n",rx_status,
564                                         (unsigned int) nat->rx[nat->rx_cur].cmdsts );
565                          netdev_rx_err ( netdev,NULL,-EINVAL );
566                 } else  {
567                         rx_iob = alloc_iob ( rx_len );
568
569                         if ( !rx_iob ) 
570                                 /* leave packet for next call to poll
571                                  */
572                                 goto end;
573                         memcpy ( iob_put ( rx_iob,rx_len ),
574                                         nat->iobuf[nat->rx_cur]->data,rx_len );
575                         DBG ( "received packet\n" );
576
577                         /* add to the receive queue. 
578                          */
579                         netdev_rx ( netdev,rx_iob );
580                 }
581                 nat->rx[nat->rx_cur].cmdsts = RX_BUF_SIZE;
582                 nat->rx_cur = ( nat->rx_cur + 1 ) % NUM_RX_DESC;
583                 rx_status = nat->rx[nat->rx_cur].cmdsts; 
584         }
585 end:
586
587         /* re-enable the potentially idle receive state machine 
588          */
589         outl ( RxOn, nat->ioaddr + ChipCmd );   
590 }                               
591
592 /**
593  * Enable/disable interrupts
594  *
595  * @v netdev    Network device
596  * @v enable    Interrupts should be enabled
597  */
598 static void nat_irq ( struct net_device *netdev, int enable ) {
599         struct natsemi_nic *nat = netdev->priv;
600
601         outl ( ( enable ? ( RxOk|RxErr|TxOk|TxErr ) :0 ),
602                 nat->ioaddr + IntrMask); 
603         outl ( ( enable ? 1:0 ),nat->ioaddr + IntrEnable );
604 }
605
606
607
608
609
610 /** natsemi net device operations */
611 static struct net_device_operations nat_operations = {
612         .open           = nat_open,
613         .close          = nat_close,
614         .transmit       = nat_transmit,
615         .poll           = nat_poll,
616         .irq            = nat_irq,
617 };
618
619 /*
620  * Probe PCI device
621  *
622  * @v pci       PCI device
623  * @v id        PCI ID
624  * @ret rc      Return status code
625  */
626 static int nat_probe ( struct pci_device *pci,
627                        const struct pci_device_id *id __unused ) {
628         struct net_device *netdev;
629         struct natsemi_nic *nat = NULL;
630         int rc;
631         int i;
632         uint8_t ll_addr_encoded[MAX_LL_ADDR_LEN];
633         uint8_t last = 0;
634         uint8_t last1 = 0;
635         uint8_t prev_bytes[2];
636
637         /* Allocate net device 
638          */
639         netdev = alloc_etherdev ( sizeof ( *nat ) );
640         if ( ! netdev ) 
641                 return -ENOMEM;
642         netdev_init ( netdev,&nat_operations );
643         nat = netdev->priv;
644         pci_set_drvdata ( pci, netdev );
645         netdev->dev = &pci->dev;
646         memset ( nat, 0, sizeof ( *nat ) );
647         nat->ioaddr = pci->ioaddr;
648
649         /* Fix up PCI device
650          */
651         adjust_pci_device ( pci );
652
653         /* Reset the NIC, set up EEPROM access and read MAC address
654          */
655         nat_reset ( nat );
656         nat_init_eeprom ( nat );
657         nvs_read ( &nat->eeprom.nvs, EE_MAC-1, prev_bytes, 1 );
658         nvs_read ( &nat->eeprom.nvs, EE_MAC, ll_addr_encoded, ETH_ALEN );
659
660         /* decoding the MAC address read from NVS 
661          * and save it in netdev->ll_addr
662          */
663         last = prev_bytes[1] >> 7;
664         for ( i = 0 ; i < ETH_ALEN ; i++ ) {
665                 last1 = ll_addr_encoded[i] >> 7;
666                 netdev->ll_addr[i] = ll_addr_encoded[i] << 1 | last;
667                 last = last1;
668         }
669
670         /* Register network device
671          */
672         if ( ( rc = register_netdev ( netdev ) ) != 0 )
673                 goto err_register_netdev;
674
675         return 0;
676
677 err_register_netdev:
678
679         /* Disable NIC
680          */
681         nat_reset ( nat );
682
683         /* Free net device
684          */
685         netdev_put ( netdev );
686         return rc;
687 }
688
689 /**
690  * Remove PCI device
691  *
692  * @v pci       PCI device
693  */
694 static void nat_remove ( struct pci_device *pci ) {
695         struct net_device *netdev = pci_get_drvdata ( pci );
696         struct natsemi_nic *nat = netdev->priv;
697  
698         if ( nat->nvo.nvs )
699                 nvo_unregister ( &nat->nvo );
700                 
701         unregister_netdev ( netdev );
702         nat_reset ( nat );
703         netdev_put ( netdev );
704 }
705
706 static struct pci_device_id natsemi_nics[] = {
707         PCI_ROM(0x100b, 0x0020, "dp83815", "DP83815"),
708 };
709
710 struct pci_driver natsemi_driver __pci_driver = {
711         .ids = natsemi_nics,
712         .id_count = ( sizeof ( natsemi_nics ) / sizeof ( natsemi_nics[0] ) ),
713         .probe = nat_probe,
714         .remove = nat_remove,
715 };