Remove unnecessary variable.
[people/cooldavid/gpxe.git] / src / drivers / net / natsemi.c
1 /* 
2    natsemi.c - gPXE driver for the NatSemi DP8381x series. 
3  
4    Based on:
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@etherboot.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   13 Dec 2003  Tim Legge         1.1 Enabled Multicast Support
58   29 May 2001  Marty Connor      1.0 Initial Release. Tested with Netgear FA311 and FA312 boards
59 */
60
61 #include <stdint.h>
62 #include <stdlib.h>
63 #include <stdio.h>
64 #include <io.h>
65 #include <errno.h>
66 #include <timer.h>
67 #include <byteswap.h>
68 #include <gpxe/pci.h>
69 #include <gpxe/if_ether.h>
70 #include <gpxe/ethernet.h>
71 #include <gpxe/iobuf.h>
72 #include <gpxe/netdevice.h>
73 #include <gpxe/spi_bit.h>
74 #include <gpxe/threewire.h>
75 #include <gpxe/nvo.h>
76 #include "natsemi.h"
77
78 /*  Function Prototypes: */
79  
80 static int natsemi_spi_read_bit ( struct bit_basher *, unsigned int );
81 static void natsemi_spi_write_bit ( struct bit_basher *,unsigned int, unsigned long ); 
82 static void natsemi_init_eeprom ( struct natsemi_private * ); 
83 static int natsemi_probe (struct pci_device *pci, const struct pci_device_id *id);
84 static void natsemi_reset (struct net_device *netdev);
85 static int natsemi_open (struct net_device *netdev);
86 static int natsemi_transmit (struct net_device *netdev, struct io_buffer *iobuf);
87 static void natsemi_poll (struct net_device *netdev);
88 static void natsemi_close (struct net_device *netdev);
89 static void natsemi_irq (struct net_device *netdev, int enable);
90 static void natsemi_remove (struct pci_device *pci);
91
92 /** natsemi net device operations */
93 static struct net_device_operations natsemi_operations = {
94         .open           = natsemi_open,
95         .close          = natsemi_close,
96         .transmit       = natsemi_transmit,
97         .poll           = natsemi_poll,
98         .irq            = natsemi_irq,
99 };
100
101 static int natsemi_spi_read_bit ( struct bit_basher *basher,
102                               unsigned int bit_id ) {
103         struct natsemi_private *np = container_of ( basher, struct natsemi_private,
104                                                  spibit.basher );
105         uint8_t mask = natsemi_ee_bits[bit_id];
106         uint8_t eereg;
107
108         eereg = inb ( np->ioaddr + EE_REG );
109         return ( eereg & mask );
110 }
111
112 static void natsemi_spi_write_bit ( struct bit_basher *basher,
113                                 unsigned int bit_id, unsigned long data ) {
114         struct natsemi_private *np = container_of ( basher, struct natsemi_private,
115                                                  spibit.basher );
116         uint8_t mask = natsemi_ee_bits[bit_id];
117         uint8_t eereg;
118
119         eereg = inb ( np->ioaddr + EE_REG );
120         eereg &= ~mask;
121         eereg |= ( data & mask );
122         outb ( eereg, np->ioaddr + EE_REG );
123 }
124
125 static struct bit_basher_operations natsemi_basher_ops = {
126         .read = natsemi_spi_read_bit,
127         .write = natsemi_spi_write_bit,
128 };
129
130 /* It looks that this portion of EEPROM can be used for 
131  * non-volatile stored options. Data sheet does not talk about this region.
132  * Currently it is not working. But with some efforts it can.
133  */
134 static struct nvo_fragment natsemi_nvo_fragments[] = {
135         { 0x0c, 0x68 },
136         { 0, 0 }
137 };
138
139 /*
140  * Set up for EEPROM access
141  *
142  * @v NAT               NATSEMI NIC
143  */
144 static void natsemi_init_eeprom ( struct natsemi_private *np ) {
145
146         /* Initialise three-wire bus 
147          */
148         np->spibit.basher.op = &natsemi_basher_ops;
149         np->spibit.bus.mode = SPI_MODE_THREEWIRE;
150         np->spibit.endianness = SPI_BIT_LITTLE_ENDIAN;
151         init_spi_bit_basher ( &np->spibit );
152
153         /*natsemi DP 83815 only supports at93c46
154          */
155         init_at93c46 ( &np->eeprom, 16 );
156         np->eeprom.bus = &np->spibit.bus;
157         np->nvo.nvs = &np->eeprom.nvs;
158         np->nvo.fragments = natsemi_nvo_fragments;
159 }
160
161 /**
162  * Probe PCI device
163  *
164  * @v pci       PCI device
165  * @v id        PCI ID
166  * @ret rc      Return status code
167  */
168 static int natsemi_probe (struct pci_device *pci,
169                        const struct pci_device_id *id __unused) {
170         struct net_device *netdev;
171         struct natsemi_private *np = NULL;
172         uint8_t ll_addr_encoded[MAX_LL_ADDR_LEN];
173         uint8_t last=0,last1=0;
174         uint8_t prev_bytes[2];
175         int i;
176         int rc;
177
178         /* Allocate net device 
179          */
180         netdev = alloc_etherdev (sizeof (*np));
181         if (! netdev) 
182                 return -ENOMEM;
183
184         netdev_init (netdev, &natsemi_operations);
185         np = netdev->priv;
186         pci_set_drvdata (pci, netdev);
187         netdev->dev = &pci->dev;
188         memset (np, 0, sizeof (*np));
189         np->ioaddr = pci->ioaddr;
190
191         adjust_pci_device (pci);
192
193         natsemi_reset (netdev);
194         natsemi_init_eeprom ( np );
195         nvs_read ( &np->eeprom.nvs, EE_MAC-1, prev_bytes, 1 );
196         nvs_read ( &np->eeprom.nvs, EE_MAC, ll_addr_encoded, ETH_ALEN );
197
198         /* decoding the MAC address read from NVS 
199          * and save it in netdev->ll_addr
200          */
201         last = prev_bytes[1] >> 7;
202         for ( i = 0 ; i < ETH_ALEN ; i++ ) {
203                 last1 = ll_addr_encoded[i] >> 7;
204                 netdev->ll_addr[i] = ll_addr_encoded[i] << 1 | last;
205                 last = last1;
206         }
207
208         if ((rc = register_netdev (netdev)) != 0)
209                 goto err_register_netdev;
210
211         return 0;
212
213 err_register_netdev:
214
215         natsemi_reset (netdev);
216         netdev_put (netdev);
217         return rc;
218 }
219
220 /**
221  * Remove PCI device
222  *
223  * @v pci       PCI device
224  */
225 static void natsemi_remove (struct pci_device *pci) {
226         struct net_device *netdev = pci_get_drvdata (pci);
227  
228         unregister_netdev (netdev);
229         natsemi_reset (netdev);
230         netdev_put (netdev);
231 }
232
233 /**
234  * Reset NIC
235  *
236  * @v           NATSEMI NIC
237  *
238  * Issues a hardware reset and waits for the reset to complete.
239  */
240 static void natsemi_reset (struct net_device *netdev) 
241 {
242         struct natsemi_private *np = netdev->priv;
243         int i;
244         u32 cfg;
245         u32 wcsr;
246         u32 rfcr;
247         u16 pmatch[3];
248         u16 sopass[3];
249
250         natsemi_irq (netdev, 0);
251
252         /*
253          * Resetting the chip causes some registers to be lost.
254          * Natsemi suggests NOT reloading the EEPROM while live, so instead
255          * we save the state that would have been loaded from EEPROM
256          * on a normal power-up (see the spec EEPROM map).
257          */
258
259         /* CFG */
260         cfg = inl (np->ioaddr + ChipConfig) & CFG_RESET_SAVE;
261
262         /* WCSR */
263         wcsr = inl (np->ioaddr + WOLCmd) & WCSR_RESET_SAVE;
264
265         /* RFCR */
266         rfcr = readl (np->ioaddr + RxFilterAddr) & RFCR_RESET_SAVE;
267
268         /* PMATCH */
269         for (i = 0; i < 3; i++) {
270                 outl(i*2, np->ioaddr + RxFilterAddr);
271                 pmatch[i] = inw(np->ioaddr + RxFilterData);
272         }
273
274         /* SOPAS */
275         for (i = 0; i < 3; i++) {
276                 outl(0xa+(i*2), np->ioaddr + RxFilterAddr);
277                 sopass[i] = inw(np->ioaddr + RxFilterData);
278         }
279
280         /* now whack the chip */
281         outl(ChipReset, np->ioaddr + ChipCmd);
282         for (i=0; i<NATSEMI_HW_TIMEOUT; i++) {
283                 if (! (inl (np->ioaddr + ChipCmd) & ChipReset))
284                        break;
285                 udelay(5);
286         }
287         if (i == NATSEMI_HW_TIMEOUT) {
288                 DBG ("natsemi_reset: reset did not complete in %d usec.\n", i*5);
289         }
290
291         /* restore CFG */
292         cfg |= inl(np->ioaddr + ChipConfig) & ~CFG_RESET_SAVE;
293         cfg &= ~(CfgExtPhy | CfgPhyDis);
294         outl (cfg, np->ioaddr + ChipConfig);
295
296         /* restore WCSR */
297         wcsr |= inl (np->ioaddr + WOLCmd) & ~WCSR_RESET_SAVE;
298         outl (wcsr, np->ioaddr + WOLCmd);
299
300         /* read RFCR */
301         rfcr |= inl (np->ioaddr + RxFilterAddr) & ~RFCR_RESET_SAVE;
302
303         /* restore PMATCH */
304         for (i = 0; i < 3; i++) {
305                 outl (i*2, np->ioaddr + RxFilterAddr);
306                 outw (pmatch[i], np->ioaddr + RxFilterData);
307         }
308         for (i = 0; i < 3; i++) {
309                 outl (0xa+(i*2), np->ioaddr + RxFilterAddr);
310                 outw (sopass[i], np->ioaddr + RxFilterData);
311         }
312         /* restore RFCR */
313         outl (rfcr, np->ioaddr + RxFilterAddr);
314 }
315
316 /**
317  * Open NIC
318  *
319  * @v netdev            Net device
320  * @ret rc              Return status code
321  */
322 static int natsemi_open (struct net_device *netdev)
323 {
324         struct natsemi_private *np = netdev->priv;
325         uint32_t tx_config, rx_config;
326         int i;
327         
328         /* Disable PME:
329          * The PME bit is initialized from the EEPROM contents.
330          * PCI cards probably have PME disabled, but motherboard
331          * implementations may have PME set to enable WakeOnLan. 
332          * With PME set the chip will scan incoming packets but
333          * nothing will be written to memory. 
334          */
335         outl (inl (np->ioaddr + ClkRun) & ~0x100, np->ioaddr + ClkRun);
336
337         /* Set MAC address in NIC
338          */
339         for (i = 0 ; i < ETH_ALEN ; i+=2) {
340                 outl (i, np->ioaddr + RxFilterAddr);
341                 outw (netdev->ll_addr[i] + (netdev->ll_addr[i + 1] << 8),
342                        np->ioaddr + RxFilterData);
343         }
344
345         /* Setup Tx Ring 
346          */
347         np->tx_cur = 0;
348         np->tx_dirty = 0;
349         for (i = 0 ; i < TX_RING_SIZE ; i++) {
350                 np->tx[i].link   = virt_to_bus ((i + 1 < TX_RING_SIZE) ? &np->tx[i + 1] : &np->tx[0]);
351                 np->tx[i].cmdsts = 0;
352                 np->tx[i].bufptr = 0;
353         }
354         outl (virt_to_bus (&np->tx[0]),np->ioaddr + TxRingPtr);
355
356         DBG ("Natsemi Tx descriptor loaded with: %#08lx\n",
357              inl (np->ioaddr + TxRingPtr));
358
359         /* Setup RX ring
360          */
361         np->rx_cur = 0;
362         for (i = 0 ; i < NUM_RX_DESC ; i++) {
363                 np->iobuf[i] = alloc_iob (RX_BUF_SIZE);
364                 if (! np->iobuf[i])
365                         goto memory_alloc_err;
366                 np->rx[i].link   = virt_to_bus ((i + 1 < NUM_RX_DESC) 
367                                                 ? &np->rx[i + 1] : &np->rx[0]);
368                 np->rx[i].cmdsts = RX_BUF_SIZE;
369                 np->rx[i].bufptr = virt_to_bus (np->iobuf[i]->data);
370                 DBG (" Address of iobuf [%d] = %p and iobuf->data = %p \n", i, 
371                       &np->iobuf[i],  &np->iobuf[i]->data);
372         }
373         outl (virt_to_bus (&np->rx[0]), np->ioaddr + RxRingPtr);
374
375         DBG ("Natsemi Rx descriptor loaded with: %#08lx\n",
376               inl (np->ioaddr + RxRingPtr));            
377
378         /* Setup RX Filter 
379          */
380         outl (RxFilterEnable | AcceptBroadcast | AcceptAllMulticast | AcceptMyPhys,
381               np->ioaddr + RxFilterAddr);
382
383         /* Initialize other registers. 
384          * Configure the PCI bus bursts and FIFO thresholds. 
385          * Configure for standard, in-spec Ethernet. 
386          */
387         if (inl (np->ioaddr + ChipConfig) & 0x20000000) {       /* Full duplex */
388                 DBG ("Full duplex\n");
389                 tx_config = 0xD0801002 |  0xC0000000;
390                 rx_config = 0x10000020 |  0x10000000;
391         } else {
392                 DBG ("Half duplex\n");
393                 tx_config = 0x10801002 & ~0xC0000000;
394                 rx_config = 0x00000020 & ~0x10000000;
395         }
396         outl (tx_config, np->ioaddr + TxConfig);
397         outl (rx_config, np->ioaddr + RxConfig);
398
399         DBG ("Tx config register = %#08lx Rx config register = %#08lx\n", 
400                inl (np->ioaddr + TxConfig),
401                inl (np->ioaddr + RxConfig));
402
403         /*Set the Interrupt Mask register
404          */
405         outl((RxOk|RxErr|TxOk|TxErr),np->ioaddr + IntrMask);
406         /*start the receiver 
407          */
408         outl (RxOn, np->ioaddr + ChipCmd);
409         
410         return 0;
411                        
412 memory_alloc_err:
413
414         /* Frees any allocated buffers when memory
415          * for all buffers requested is not available
416          */
417         i = 0;
418         while (np->rx[i].cmdsts == RX_BUF_SIZE) {
419                 free_iob (np->iobuf[i]);
420                 i++;
421         }
422         return -ENOMEM; 
423 }
424
425 /**
426  * Close NIC
427  *
428  * @v netdev            Net device
429  */
430 static void natsemi_close (struct net_device *netdev) 
431 {
432         struct natsemi_private *np = netdev->priv;
433         int i;
434
435         natsemi_reset (netdev);
436
437         for (i = 0; i < NUM_RX_DESC ; i++) {
438                 free_iob (np->iobuf[i]);
439         }
440 }
441
442 /** 
443  * Transmit packet
444  *
445  * @v netdev    Network device
446  * @v iobuf     I/O buffer
447  * @ret rc      Return status code
448  */
449 static int natsemi_transmit (struct net_device *netdev, struct io_buffer *iobuf)
450 {
451         struct natsemi_private *np = netdev->priv;
452
453         if (np->tx[np->tx_cur].cmdsts != 0) {
454                 DBG ("TX overflow\n");
455                 return -ENOBUFS;
456         }
457
458         /* Used by netdev_tx_complete ()
459          */
460         np->tx_iobuf[np->tx_cur] = iobuf;
461
462         /* Pad and align packet has not been used because its not required 
463          * by the hardware.
464          *      iob_pad (iobuf, ETH_ZLEN); 
465          * can be used to achieve it, if required
466          */
467
468         /* Add the packet to TX ring
469          */
470         np->tx[np->tx_cur].bufptr = virt_to_bus (iobuf->data);
471         np->tx[np->tx_cur].cmdsts = iob_len (iobuf) | OWN;
472
473         DBG ("TX id %d at %#08lx + %#08x\n", np->tx_cur,
474              virt_to_bus (&iobuf->data), iob_len (iobuf));
475
476         /* increment the circular buffer pointer to the next buffer location
477          */
478         np->tx_cur = (np->tx_cur + 1) % TX_RING_SIZE;
479
480         /*start the transmitter 
481          */
482         outl (TxOn, np->ioaddr + ChipCmd);
483
484         return 0;
485 }
486
487 /** 
488  * Poll for received packets
489  *
490  * @v netdev    Network device
491  */
492 static void natsemi_poll (struct net_device *netdev)
493 {
494         struct natsemi_private *np = netdev->priv;
495         unsigned int tx_status;
496         unsigned int rx_status;
497         unsigned int intr_status;
498         unsigned int rx_len;
499         struct io_buffer *rx_iob;
500         int i;
501         
502         /* read the interrupt register
503          */
504         intr_status = inl (np->ioaddr + IntrStatus);
505
506         if (!intr_status)
507                 goto end;
508
509         DBG ("natsemi_poll: intr_status = %#08x\n", intr_status);
510
511         /* Check status of transmitted packets
512          */
513         i = np->tx_dirty;
514         while (i != np->tx_cur) {
515                 tx_status = np->tx[np->tx_dirty].cmdsts;
516
517                 DBG ("tx_dirty = %d tx_cur=%d tx_status=%#08x\n",
518                      np->tx_dirty, np->tx_cur, tx_status);
519                 
520                 if (tx_status & OWN) 
521                         break;
522
523                 if (! (tx_status & DescPktOK)) {
524                         netdev_tx_complete_err (netdev,np->tx_iobuf[np->tx_dirty],-EINVAL);
525                         DBG ("Error transmitting packet, tx_status: %#08x\n",
526                              tx_status);
527                 } else {
528                         netdev_tx_complete (netdev, np->tx_iobuf[np->tx_dirty]);
529                         DBG ("Success transmitting packet\n");
530                 }
531
532                 np->tx[np->tx_dirty].cmdsts = 0;
533                 np->tx_dirty = (np->tx_dirty + 1) % TX_RING_SIZE;
534                 i = (i + 1) % TX_RING_SIZE;
535         }
536         
537         /* Process received packets 
538          */
539         rx_status = (unsigned int) np->rx[np->rx_cur].cmdsts; 
540         while ((rx_status & OWN)) {
541                 rx_len = (rx_status & DSIZE) - CRC_SIZE;
542
543                 DBG ("Received packet, rx_curr = %d, rx_status = %#08x, rx_len = %d\n",
544                      np->rx_cur, rx_status, rx_len);
545                 
546                 if ((rx_status & (DescMore | DescPktOK | RxTooLong)) != DescPktOK) {
547                         netdev_rx_err (netdev, NULL, -EINVAL);
548
549                         DBG ("natsemi_poll: Corrupted packet received!"
550                              " Status = %#08lx\n",
551                               np->rx[np->rx_cur].cmdsts);
552
553                 } else  {
554
555
556                         /* If unable allocate space for this packet,
557                          *  try again next poll
558                          */
559                         rx_iob = alloc_iob (rx_len);
560                         if (! rx_iob) 
561                                 goto end;
562                         memcpy (iob_put (rx_iob, rx_len), 
563                                 np->iobuf[np->rx_cur]->data, rx_len);
564                         /* Add this packet to the receive queue. 
565                          */
566                         netdev_rx (netdev, rx_iob);
567                 }
568                 np->rx[np->rx_cur].cmdsts = RX_BUF_SIZE;
569                 np->rx_cur = (np->rx_cur + 1) % NUM_RX_DESC;
570                 rx_status = np->rx[np->rx_cur].cmdsts; 
571         }
572 end:
573         /* re-enable the potentially idle receive state machine 
574          */
575         outl (RxOn, np->ioaddr + ChipCmd);      
576 }                               
577
578 /**
579  * Enable/disable interrupts
580  *
581  * @v netdev    Network device
582  * @v enable    Non-zero for enable, zero for disable
583  */
584 static void natsemi_irq (struct net_device *netdev, int enable)
585 {
586         struct natsemi_private *np = netdev->priv;
587
588         outl ((enable ? (RxOk | RxErr | TxOk|TxErr) : 0),
589               np->ioaddr + IntrMask); 
590         outl ((enable ? 1 : 0), np->ioaddr + IntrEnable);
591 }
592
593 static struct pci_device_id natsemi_nics[] = {
594         PCI_ROM(0x100b, 0x0020, "dp83815", "DP83815"),
595 };
596
597 struct pci_driver natsemi_driver __pci_driver = {
598         .ids = natsemi_nics,
599         .id_count = (sizeof (natsemi_nics) / sizeof (natsemi_nics[0])),
600         .probe = natsemi_probe,
601         .remove = natsemi_remove,
602 };