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