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