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