• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
natsemi_spi_read_bit(struct bit_basher * basher,unsigned int bit_id)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 
natsemi_spi_write_bit(struct bit_basher * basher,unsigned int bit_id,unsigned long data)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  */
natsemi_init_eeprom(struct natsemi_private * np)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  */
natsemi_probe(struct pci_device * pci,const struct pci_device_id * id __unused)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  */
natsemi_remove(struct pci_device * pci)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  */
natsemi_reset(struct net_device * netdev)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  */
natsemi_open(struct net_device * netdev)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  */
natsemi_close(struct net_device * netdev)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  */
natsemi_transmit(struct net_device * netdev,struct io_buffer * iobuf)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  */
natsemi_poll(struct net_device * netdev)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  */
natsemi_irq(struct net_device * netdev,int enable)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 };
610