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