removed type casting from DBG statements.
[people/holger/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         SavedClkRun = inl (np->ioaddr + ClkRun);
336         outl (SavedClkRun & ~0x100, np->ioaddr + ClkRun);
337
338         /* Set MAC address in NIC
339          */
340         for (i = 0 ; i < ETH_ALEN ; i+=2) {
341                 outl (i, np->ioaddr + RxFilterAddr);
342                 outw (netdev->ll_addr[i] + (netdev->ll_addr[i + 1] << 8),
343                        np->ioaddr + RxFilterData);
344         }
345
346         /* Setup Tx Ring 
347          */
348         np->tx_cur = 0;
349         np->tx_dirty = 0;
350         for (i = 0 ; i < TX_RING_SIZE ; i++) {
351                 np->tx[i].link   = virt_to_bus ((i + 1 < TX_RING_SIZE) ? &np->tx[i + 1] : &np->tx[0]);
352                 np->tx[i].cmdsts = 0;
353                 np->tx[i].bufptr = 0;
354         }
355         outl (virt_to_bus (&np->tx[0]),np->ioaddr + TxRingPtr);
356
357         DBG ("Natsemi Tx descriptor loaded with: %#08lx\n",
358              inl (np->ioaddr + TxRingPtr));
359
360         /* Setup RX ring
361          */
362         np->rx_cur = 0;
363         for (i = 0 ; i < NUM_RX_DESC ; i++) {
364                 np->iobuf[i] = alloc_iob (RX_BUF_SIZE);
365                 if (! np->iobuf[i])
366                         goto memory_alloc_err;
367                 np->rx[i].link   = virt_to_bus ((i + 1 < NUM_RX_DESC) 
368                                                 ? &np->rx[i + 1] : &np->rx[0]);
369                 np->rx[i].cmdsts = RX_BUF_SIZE;
370                 np->rx[i].bufptr = virt_to_bus (np->iobuf[i]->data);
371                 DBG (" Address of iobuf [%d] = %p and iobuf->data = %p \n", i, 
372                       &np->iobuf[i],  &np->iobuf[i]->data);
373         }
374         outl (virt_to_bus (&np->rx[0]), np->ioaddr + RxRingPtr);
375
376         DBG ("Natsemi Rx descriptor loaded with: %#08lx\n",
377               inl (np->ioaddr + RxRingPtr));            
378
379         /* Setup RX Filter 
380          */
381         outl (RxFilterEnable | AcceptBroadcast | AcceptAllMulticast | AcceptMyPhys,
382               np->ioaddr + RxFilterAddr);
383
384         /* Initialize other registers. 
385          * Configure the PCI bus bursts and FIFO thresholds. 
386          * Configure for standard, in-spec Ethernet. 
387          */
388         if (inl (np->ioaddr + ChipConfig) & 0x20000000) {       /* Full duplex */
389                 DBG ("Full duplex\n");
390                 tx_config = 0xD0801002 |  0xC0000000;
391                 rx_config = 0x10000020 |  0x10000000;
392         } else {
393                 DBG ("Half duplex\n");
394                 tx_config = 0x10801002 & ~0xC0000000;
395                 rx_config = 0x00000020 & ~0x10000000;
396         }
397         outl (tx_config, np->ioaddr + TxConfig);
398         outl (rx_config, np->ioaddr + RxConfig);
399
400         DBG ("Tx config register = %#08lx Rx config register = %#08lx\n", 
401                inl (np->ioaddr + TxConfig),
402                inl (np->ioaddr + RxConfig));
403
404         /*Set the Interrupt Mask register
405          */
406         outl((RxOk|RxErr|TxOk|TxErr),np->ioaddr + IntrMask);
407         /*start the receiver 
408          */
409         outl (RxOn, np->ioaddr + ChipCmd);
410         
411         return 0;
412                        
413 memory_alloc_err:
414
415         /* Frees any allocated buffers when memory
416          * for all buffers requested is not available
417          */
418         i = 0;
419         while (np->rx[i].cmdsts == RX_BUF_SIZE) {
420                 free_iob (np->iobuf[i]);
421                 i++;
422         }
423         return -ENOMEM; 
424 }
425
426 /**
427  * Close NIC
428  *
429  * @v netdev            Net device
430  */
431 static void natsemi_close (struct net_device *netdev) 
432 {
433         struct natsemi_private *np = netdev->priv;
434         int i;
435
436         natsemi_reset (netdev);
437
438         for (i = 0; i < NUM_RX_DESC ; i++) {
439                 free_iob (np->iobuf[i]);
440         }
441 }
442
443 /** 
444  * Transmit packet
445  *
446  * @v netdev    Network device
447  * @v iobuf     I/O buffer
448  * @ret rc      Return status code
449  */
450 static int natsemi_transmit (struct net_device *netdev, struct io_buffer *iobuf)
451 {
452         struct natsemi_private *np = netdev->priv;
453
454         if (np->tx[np->tx_cur].cmdsts != 0) {
455                 DBG ("TX overflow\n");
456                 return -ENOBUFS;
457         }
458
459         /* Used by netdev_tx_complete ()
460          */
461         np->tx_iobuf[np->tx_cur] = iobuf;
462
463         /* Pad and align packet has not been used because its not required 
464          * by the hardware.
465          *      iob_pad (iobuf, ETH_ZLEN); 
466          * can be used to achieve it, if required
467          */
468
469         /* Add the packet to TX ring
470          */
471         np->tx[np->tx_cur].bufptr = virt_to_bus (iobuf->data);
472         np->tx[np->tx_cur].cmdsts = iob_len (iobuf) | OWN;
473
474         DBG ("TX id %d at %#08lx + %#08x\n", np->tx_cur,
475              virt_to_bus (&iobuf->data), iob_len (iobuf));
476
477         /* increment the circular buffer pointer to the next buffer location
478          */
479         np->tx_cur = (np->tx_cur + 1) % TX_RING_SIZE;
480
481         /*start the transmitter 
482          */
483         outl (TxOn, np->ioaddr + ChipCmd);
484
485         return 0;
486 }
487
488 /** 
489  * Poll for received packets
490  *
491  * @v netdev    Network device
492  */
493 static void natsemi_poll (struct net_device *netdev)
494 {
495         struct natsemi_private *np = netdev->priv;
496         unsigned int tx_status;
497         unsigned int rx_status;
498         unsigned int intr_status;
499         unsigned int rx_len;
500         struct io_buffer *rx_iob;
501         int i;
502         
503         /* read the interrupt register
504          */
505         intr_status = inl (np->ioaddr + IntrStatus);
506
507         if (!intr_status)
508                 goto end;
509
510         DBG ("natsemi_poll: intr_status = %#08x\n", intr_status);
511
512         /* Check status of transmitted packets
513          */
514         i = np->tx_dirty;
515         while (i != np->tx_cur) {
516                 tx_status = np->tx[np->tx_dirty].cmdsts;
517
518                 DBG ("tx_dirty = %d tx_cur=%d tx_status=%#08x\n",
519                      np->tx_dirty, np->tx_cur, tx_status);
520                 
521                 if (tx_status & OWN) 
522                         break;
523
524                 if (! (tx_status & DescPktOK)) {
525                         netdev_tx_complete_err (netdev,np->tx_iobuf[np->tx_dirty],-EINVAL);
526                         DBG ("Error transmitting packet, tx_status: %#08x\n",
527                              tx_status);
528                 } else {
529                         netdev_tx_complete (netdev, np->tx_iobuf[np->tx_dirty]);
530                         DBG ("Success transmitting packet\n");
531                 }
532
533                 np->tx[np->tx_dirty].cmdsts = 0;
534                 np->tx_dirty = (np->tx_dirty + 1) % TX_RING_SIZE;
535                 i = (i + 1) % TX_RING_SIZE;
536         }
537         
538         /* Process received packets 
539          */
540         rx_status = (unsigned int) np->rx[np->rx_cur].cmdsts; 
541         while ((rx_status & OWN)) {
542                 rx_len = (rx_status & DSIZE) - CRC_SIZE;
543
544                 DBG ("Received packet, rx_curr = %d, rx_status = %#08x, rx_len = %d\n",
545                      np->rx_cur, rx_status, rx_len);
546                 
547                 if ((rx_status & (DescMore | DescPktOK | RxTooLong)) != DescPktOK) {
548                         netdev_rx_err (netdev, NULL, -EINVAL);
549
550                         DBG ("natsemi_poll: Corrupted packet received!"
551                              " Status = %#08lx\n",
552                               np->rx[np->rx_cur].cmdsts);
553
554                 } else  {
555
556
557                         /* If unable allocate space for this packet,
558                          *  try again next poll
559                          */
560                         rx_iob = alloc_iob (rx_len);
561                         if (! rx_iob) 
562                                 goto end;
563                         memcpy (iob_put (rx_iob, rx_len), 
564                                 np->iobuf[np->rx_cur]->data, rx_len);
565                         /* Add this packet to the receive queue. 
566                          */
567                         netdev_rx (netdev, rx_iob);
568                 }
569                 np->rx[np->rx_cur].cmdsts = RX_BUF_SIZE;
570                 np->rx_cur = (np->rx_cur + 1) % NUM_RX_DESC;
571                 rx_status = np->rx[np->rx_cur].cmdsts; 
572         }
573 end:
574         /* re-enable the potentially idle receive state machine 
575          */
576         outl (RxOn, np->ioaddr + ChipCmd);      
577 }                               
578
579 /**
580  * Enable/disable interrupts
581  *
582  * @v netdev    Network device
583  * @v enable    Non-zero for enable, zero for disable
584  */
585 static void natsemi_irq (struct net_device *netdev, int enable)
586 {
587         struct natsemi_private *np = netdev->priv;
588
589         outl ((enable ? (RxOk | RxErr | TxOk|TxErr) : 0),
590               np->ioaddr + IntrMask); 
591         outl ((enable ? 1 : 0), np->ioaddr + IntrEnable);
592 }
593
594 static struct pci_device_id natsemi_nics[] = {
595         PCI_ROM(0x100b, 0x0020, "dp83815", "DP83815"),
596 };
597
598 struct pci_driver natsemi_driver __pci_driver = {
599         .ids = natsemi_nics,
600         .id_count = (sizeof (natsemi_nics) / sizeof (natsemi_nics[0])),
601         .probe = natsemi_probe,
602         .remove = natsemi_remove,
603 };