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
49FILE_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
83static int natsemi_spi_read_bit ( struct bit_basher *, unsigned int );
84static void natsemi_spi_write_bit ( struct bit_basher *,unsigned int, unsigned long );
85static void natsemi_init_eeprom ( struct natsemi_private * );
86static int natsemi_probe (struct pci_device *pci, const struct pci_device_id *id);
87static void natsemi_reset (struct net_device *netdev);
88static int natsemi_open (struct net_device *netdev);
89static int natsemi_transmit (struct net_device *netdev, struct io_buffer *iobuf);
90static void natsemi_poll (struct net_device *netdev);
91static void natsemi_close (struct net_device *netdev);
92static void natsemi_irq (struct net_device *netdev, int enable);
93static void natsemi_remove (struct pci_device *pci);
94
95/** natsemi net device operations */
96static 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
104static 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
115static 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
128static 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 */
137static 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 */
147static 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 */
171static 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
219err_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 */
231static 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 */
247static 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 */
329static 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
419memory_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 */
437static 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 */
456static 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 */
499static 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	}
579end:
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 */
591static 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
600static struct pci_device_id natsemi_nics[] = {
601	PCI_ROM(0x100b, 0x0020, "dp83815", "DP83815", 0),
602};
603
604struct 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