|
|
1.1 root 1: /*
2: natsemi.c - iPXE 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 <[email protected]>
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 [email protected], 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 iPXE 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 <ipxe/io.h>
68: #include <errno.h>
69: #include <byteswap.h>
70: #include <unistd.h>
71: #include <ipxe/pci.h>
72: #include <ipxe/if_ether.h>
73: #include <ipxe/ethernet.h>
74: #include <ipxe/iobuf.h>
75: #include <ipxe/netdevice.h>
76: #include <ipxe/spi_bit.h>
77: #include <ipxe/threewire.h>
78: #include <ipxe/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);
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: /*
134: * Set up for EEPROM access
135: *
136: * @v NAT NATSEMI NIC
137: */
138: static void natsemi_init_eeprom ( struct natsemi_private *np ) {
139:
140: /* Initialise three-wire bus
141: */
142: np->spibit.basher.op = &natsemi_basher_ops;
143: np->spibit.bus.mode = SPI_MODE_THREEWIRE;
144: np->spibit.endianness = SPI_BIT_LITTLE_ENDIAN;
145: init_spi_bit_basher ( &np->spibit );
146:
147: /*natsemi DP 83815 only supports at93c46
148: */
149: init_at93c46 ( &np->eeprom, 16 );
150: np->eeprom.bus = &np->spibit.bus;
151:
152: /* It looks that this portion of EEPROM can be used for
153: * non-volatile stored options. Data sheet does not talk about
154: * this region. Currently it is not working. But with some
155: * efforts it can.
156: */
157: nvo_init ( &np->nvo, &np->eeprom.nvs, 0x0c, 0x68, NULL, NULL );
158: }
159:
160: /**
161: * Probe PCI device
162: *
163: * @v pci PCI device
164: * @v id PCI ID
165: * @ret rc Return status code
166: */
167: static int natsemi_probe (struct pci_device *pci) {
168: struct net_device *netdev;
169: struct natsemi_private *np = NULL;
170: uint8_t ll_addr_encoded[MAX_LL_ADDR_LEN];
171: uint8_t last=0,last1=0;
172: uint8_t prev_bytes[2];
173: int i;
174: int rc;
175:
176: /* Allocate net device
177: */
178: netdev = alloc_etherdev (sizeof (*np));
179: if (! netdev)
180: return -ENOMEM;
181:
182: netdev_init (netdev, &natsemi_operations);
183: np = netdev->priv;
184: pci_set_drvdata (pci, netdev);
185: netdev->dev = &pci->dev;
186: memset (np, 0, sizeof (*np));
187: np->ioaddr = pci->ioaddr;
188:
189: adjust_pci_device (pci);
190:
191: natsemi_reset (netdev);
192: natsemi_init_eeprom ( np );
193: nvs_read ( &np->eeprom.nvs, EE_MAC-1, prev_bytes, 1 );
194: nvs_read ( &np->eeprom.nvs, EE_MAC, ll_addr_encoded, ETH_ALEN );
195:
196: /* decoding the MAC address read from NVS
197: * and save it in netdev->ll_addr
198: */
199: last = prev_bytes[1] >> 7;
200: for ( i = 0 ; i < ETH_ALEN ; i++ ) {
201: last1 = ll_addr_encoded[i] >> 7;
202: netdev->hw_addr[i] = ll_addr_encoded[i] << 1 | last;
203: last = last1;
204: }
205:
206: if ((rc = register_netdev (netdev)) != 0)
207: goto err_register_netdev;
208:
209: /* Mark as link up; we don't yet handle link state */
210: netdev_link_up ( 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_nullify ( netdev );
232: netdev_put (netdev);
233: }
234:
235: /**
236: * Reset NIC
237: *
238: * @v NATSEMI NIC
239: *
240: * Issues a hardware reset and waits for the reset to complete.
241: */
242: static void natsemi_reset (struct net_device *netdev)
243: {
244: struct natsemi_private *np = netdev->priv;
245: int i;
246: u32 cfg;
247: u32 wcsr;
248: u32 rfcr;
249: u16 pmatch[3];
250: u16 sopass[3];
251:
252: natsemi_irq (netdev, 0);
253:
254: /*
255: * Resetting the chip causes some registers to be lost.
256: * Natsemi suggests NOT reloading the EEPROM while live, so instead
257: * we save the state that would have been loaded from EEPROM
258: * on a normal power-up (see the spec EEPROM map).
259: */
260:
261: /* CFG */
262: cfg = inl (np->ioaddr + ChipConfig) & CFG_RESET_SAVE;
263:
264: /* WCSR */
265: wcsr = inl (np->ioaddr + WOLCmd) & WCSR_RESET_SAVE;
266:
267: /* RFCR */
268: rfcr = inl (np->ioaddr + RxFilterAddr) & RFCR_RESET_SAVE;
269:
270: /* PMATCH */
271: for (i = 0; i < 3; i++) {
272: outl(i*2, np->ioaddr + RxFilterAddr);
273: pmatch[i] = inw(np->ioaddr + RxFilterData);
274: }
275:
276: /* SOPAS */
277: for (i = 0; i < 3; i++) {
278: outl(0xa+(i*2), np->ioaddr + RxFilterAddr);
279: sopass[i] = inw(np->ioaddr + RxFilterData);
280: }
281:
282: /* now whack the chip */
283: outl(ChipReset, np->ioaddr + ChipCmd);
284: for (i=0; i<NATSEMI_HW_TIMEOUT; i++) {
285: if (! (inl (np->ioaddr + ChipCmd) & ChipReset))
286: break;
287: udelay(5);
288: }
289: if (i == NATSEMI_HW_TIMEOUT) {
290: DBG ("natsemi_reset: reset did not complete in %d usec.\n", i*5);
291: }
292:
293: /* restore CFG */
294: cfg |= inl(np->ioaddr + ChipConfig) & ~CFG_RESET_SAVE;
295: cfg &= ~(CfgExtPhy | CfgPhyDis);
296: outl (cfg, np->ioaddr + ChipConfig);
297:
298: /* restore WCSR */
299: wcsr |= inl (np->ioaddr + WOLCmd) & ~WCSR_RESET_SAVE;
300: outl (wcsr, np->ioaddr + WOLCmd);
301:
302: /* read RFCR */
303: rfcr |= inl (np->ioaddr + RxFilterAddr) & ~RFCR_RESET_SAVE;
304:
305: /* restore PMATCH */
306: for (i = 0; i < 3; i++) {
307: outl (i*2, np->ioaddr + RxFilterAddr);
308: outw (pmatch[i], np->ioaddr + RxFilterData);
309: }
310: for (i = 0; i < 3; i++) {
311: outl (0xa+(i*2), np->ioaddr + RxFilterAddr);
312: outw (sopass[i], np->ioaddr + RxFilterData);
313: }
314: /* restore RFCR */
315: outl (rfcr, np->ioaddr + RxFilterAddr);
316: }
317:
318: /**
319: * Open NIC
320: *
321: * @v netdev Net device
322: * @ret rc Return status code
323: */
324: static int natsemi_open (struct net_device *netdev)
325: {
326: struct natsemi_private *np = netdev->priv;
327: uint32_t tx_config, rx_config;
328: int i;
329:
330: /* Disable PME:
331: * The PME bit is initialized from the EEPROM contents.
332: * PCI cards probably have PME disabled, but motherboard
333: * implementations may have PME set to enable WakeOnLan.
334: * With PME set the chip will scan incoming packets but
335: * nothing will be written to memory.
336: */
337: outl (inl (np->ioaddr + ClkRun) & ~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: 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] = %p and iobuf->data = %p \n", i,
373: &np->iobuf[i], &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: 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: inl (np->ioaddr + TxConfig),
403: 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 %#08lx + %#08zx\n", np->tx_cur,
476: 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: 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: np->rx[np->rx_cur].cmdsts);
554:
555: } else {
556:
557:
558: /* If unable allocate space for this packet,
559: * try again next poll
560: */
561: rx_iob = alloc_iob (rx_len);
562: if (! rx_iob)
563: goto end;
564: memcpy (iob_put (rx_iob, rx_len),
565: np->iobuf[np->rx_cur]->data, rx_len);
566: /* Add this packet to the receive queue.
567: */
568: netdev_rx (netdev, rx_iob);
569: }
570: np->rx[np->rx_cur].cmdsts = RX_BUF_SIZE;
571: np->rx_cur = (np->rx_cur + 1) % NUM_RX_DESC;
572: rx_status = np->rx[np->rx_cur].cmdsts;
573: }
574: end:
575: /* re-enable the potentially idle receive state machine
576: */
577: outl (RxOn, np->ioaddr + ChipCmd);
578: }
579:
580: /**
581: * Enable/disable interrupts
582: *
583: * @v netdev Network device
584: * @v enable Non-zero for enable, zero for disable
585: */
586: static void natsemi_irq (struct net_device *netdev, int enable)
587: {
588: struct natsemi_private *np = netdev->priv;
589:
590: outl ((enable ? (RxOk | RxErr | TxOk|TxErr) : 0),
591: np->ioaddr + IntrMask);
592: outl ((enable ? 1 : 0), np->ioaddr + IntrEnable);
593: }
594:
595: static struct pci_device_id natsemi_nics[] = {
596: PCI_ROM(0x100b, 0x0020, "dp83815", "DP83815", 0),
597: };
598:
599: struct pci_driver natsemi_driver __pci_driver = {
600: .ids = natsemi_nics,
601: .id_count = (sizeof (natsemi_nics) / sizeof (natsemi_nics[0])),
602: .probe = natsemi_probe,
603: .remove = natsemi_remove,
604: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.