2 natsemi.c - gPXE driver for the NatSemi DP8381x series.
6 natsemi.c: An Etherboot driver for the NatSemi DP8381x series.
8 Copyright (C) 2001 Entity Cyber, Inc.
10 This development of this Etherboot driver was funded by
12 Sicom Systems: http://www.sicompos.com/
14 Author: Marty Connor <mdc@etherboot.org>
15 Adapted from a Linux driver which was written by Donald Becker
17 This software may be used and distributed according to the terms
18 of the GNU Public License (GPL), incorporated herein by reference.
20 Original Copyright Notice:
22 Written/copyright 1999-2001 by Donald Becker.
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.
32 The original author may be reached as becker@scyld.com, or at
33 Scyld Computing Corporation
34 410 Severn Ave., Suite 210
37 Support information and updates available at
38 http://www.scyld.com/network/netsemi.html
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
49 FILE_LICENCE ( GPL_ANY
);
51 /* Revision History */
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
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>
81 /* Function Prototypes: */
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
);
95 /** natsemi net device operations */
96 static struct net_device_operations natsemi_operations
= {
98 .close
= natsemi_close
,
99 .transmit
= natsemi_transmit
,
100 .poll
= natsemi_poll
,
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
,
108 uint8_t mask
= natsemi_ee_bits
[bit_id
];
111 eereg
= inb ( np
->ioaddr
+ EE_REG
);
112 return ( eereg
& mask
);
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
,
119 uint8_t mask
= natsemi_ee_bits
[bit_id
];
122 eereg
= inb ( np
->ioaddr
+ EE_REG
);
124 eereg
|= ( data
& mask
);
125 outb ( eereg
, np
->ioaddr
+ EE_REG
);
128 static struct bit_basher_operations natsemi_basher_ops
= {
129 .read
= natsemi_spi_read_bit
,
130 .write
= natsemi_spi_write_bit
,
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.
137 static struct nvo_fragment natsemi_nvo_fragments
[] = {
143 * Set up for EEPROM access
147 static void natsemi_init_eeprom ( struct natsemi_private
*np
) {
149 /* Initialise three-wire bus
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
);
156 /*natsemi DP 83815 only supports at93c46
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
;
169 * @ret rc Return status code
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];
181 /* Allocate net device
183 netdev
= alloc_etherdev (sizeof (*np
));
187 netdev_init (netdev
, &natsemi_operations
);
189 pci_set_drvdata (pci
, netdev
);
190 netdev
->dev
= &pci
->dev
;
191 memset (np
, 0, sizeof (*np
));
192 np
->ioaddr
= pci
->ioaddr
;
194 adjust_pci_device (pci
);
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
);
201 /* decoding the MAC address read from NVS
202 * and save it in netdev->ll_addr
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
;
211 /* Mark as link up; we don't yet handle link state */
212 netdev_link_up ( netdev
);
214 if ((rc
= register_netdev (netdev
)) != 0)
215 goto err_register_netdev
;
221 natsemi_reset (netdev
);
231 static void natsemi_remove (struct pci_device
*pci
) {
232 struct net_device
*netdev
= pci_get_drvdata (pci
);
234 unregister_netdev (netdev
);
235 natsemi_reset (netdev
);
236 netdev_nullify ( netdev
);
245 * Issues a hardware reset and waits for the reset to complete.
247 static void natsemi_reset (struct net_device
*netdev
)
249 struct natsemi_private
*np
= netdev
->priv
;
257 natsemi_irq (netdev
, 0);
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).
267 cfg
= inl (np
->ioaddr
+ ChipConfig
) & CFG_RESET_SAVE
;
270 wcsr
= inl (np
->ioaddr
+ WOLCmd
) & WCSR_RESET_SAVE
;
273 rfcr
= inl (np
->ioaddr
+ RxFilterAddr
) & RFCR_RESET_SAVE
;
276 for (i
= 0; i
< 3; i
++) {
277 outl(i
*2, np
->ioaddr
+ RxFilterAddr
);
278 pmatch
[i
] = inw(np
->ioaddr
+ RxFilterData
);
282 for (i
= 0; i
< 3; i
++) {
283 outl(0xa+(i
*2), np
->ioaddr
+ RxFilterAddr
);
284 sopass
[i
] = inw(np
->ioaddr
+ RxFilterData
);
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
))
294 if (i
== NATSEMI_HW_TIMEOUT
) {
295 DBG ("natsemi_reset: reset did not complete in %d usec.\n", i
*5);
299 cfg
|= inl(np
->ioaddr
+ ChipConfig
) & ~CFG_RESET_SAVE
;
300 cfg
&= ~(CfgExtPhy
| CfgPhyDis
);
301 outl (cfg
, np
->ioaddr
+ ChipConfig
);
304 wcsr
|= inl (np
->ioaddr
+ WOLCmd
) & ~WCSR_RESET_SAVE
;
305 outl (wcsr
, np
->ioaddr
+ WOLCmd
);
308 rfcr
|= inl (np
->ioaddr
+ RxFilterAddr
) & ~RFCR_RESET_SAVE
;
311 for (i
= 0; i
< 3; i
++) {
312 outl (i
*2, np
->ioaddr
+ RxFilterAddr
);
313 outw (pmatch
[i
], np
->ioaddr
+ RxFilterData
);
315 for (i
= 0; i
< 3; i
++) {
316 outl (0xa+(i
*2), np
->ioaddr
+ RxFilterAddr
);
317 outw (sopass
[i
], np
->ioaddr
+ RxFilterData
);
320 outl (rfcr
, np
->ioaddr
+ RxFilterAddr
);
326 * @v netdev Net device
327 * @ret rc Return status code
329 static int natsemi_open (struct net_device
*netdev
)
331 struct natsemi_private
*np
= netdev
->priv
;
332 uint32_t tx_config
, rx_config
;
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.
342 outl (inl (np
->ioaddr
+ ClkRun
) & ~0x100, np
->ioaddr
+ ClkRun
);
344 /* Set MAC address in NIC
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
);
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;
361 outl (virt_to_bus (&np
->tx
[0]),np
->ioaddr
+ TxRingPtr
);
363 DBG ("Natsemi Tx descriptor loaded with: %#08x\n",
364 inl (np
->ioaddr
+ TxRingPtr
));
369 for (i
= 0 ; i
< NUM_RX_DESC
; i
++) {
370 np
->iobuf
[i
] = alloc_iob (RX_BUF_SIZE
);
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
);
380 outl (virt_to_bus (&np
->rx
[0]), np
->ioaddr
+ RxRingPtr
);
382 DBG ("Natsemi Rx descriptor loaded with: %#08x\n",
383 inl (np
->ioaddr
+ RxRingPtr
));
387 outl (RxFilterEnable
| AcceptBroadcast
| AcceptAllMulticast
| AcceptMyPhys
,
388 np
->ioaddr
+ RxFilterAddr
);
390 /* Initialize other registers.
391 * Configure the PCI bus bursts and FIFO thresholds.
392 * Configure for standard, in-spec Ethernet.
394 if (inl (np
->ioaddr
+ ChipConfig
) & 0x20000000) { /* Full duplex */
395 DBG ("Full duplex\n");
396 tx_config
= 0xD0801002 | 0xC0000000;
397 rx_config
= 0x10000020 | 0x10000000;
399 DBG ("Half duplex\n");
400 tx_config
= 0x10801002 & ~0xC0000000;
401 rx_config
= 0x00000020 & ~0x10000000;
403 outl (tx_config
, np
->ioaddr
+ TxConfig
);
404 outl (rx_config
, np
->ioaddr
+ RxConfig
);
406 DBG ("Tx config register = %#08x Rx config register = %#08x\n",
407 inl (np
->ioaddr
+ TxConfig
),
408 inl (np
->ioaddr
+ RxConfig
));
410 /*Set the Interrupt Mask register
412 outl((RxOk
|RxErr
|TxOk
|TxErr
),np
->ioaddr
+ IntrMask
);
415 outl (RxOn
, np
->ioaddr
+ ChipCmd
);
421 /* Frees any allocated buffers when memory
422 * for all buffers requested is not available
425 while (np
->rx
[i
].cmdsts
== RX_BUF_SIZE
) {
426 free_iob (np
->iobuf
[i
]);
435 * @v netdev Net device
437 static void natsemi_close (struct net_device
*netdev
)
439 struct natsemi_private
*np
= netdev
->priv
;
442 natsemi_reset (netdev
);
444 for (i
= 0; i
< NUM_RX_DESC
; i
++) {
445 free_iob (np
->iobuf
[i
]);
452 * @v netdev Network device
453 * @v iobuf I/O buffer
454 * @ret rc Return status code
456 static int natsemi_transmit (struct net_device
*netdev
, struct io_buffer
*iobuf
)
458 struct natsemi_private
*np
= netdev
->priv
;
460 if (np
->tx
[np
->tx_cur
].cmdsts
!= 0) {
461 DBG ("TX overflow\n");
465 /* Used by netdev_tx_complete ()
467 np
->tx_iobuf
[np
->tx_cur
] = iobuf
;
469 /* Pad and align packet has not been used because its not required
471 * iob_pad (iobuf, ETH_ZLEN);
472 * can be used to achieve it, if required
475 /* Add the packet to TX ring
477 np
->tx
[np
->tx_cur
].bufptr
= virt_to_bus (iobuf
->data
);
478 np
->tx
[np
->tx_cur
].cmdsts
= iob_len (iobuf
) | OWN
;
480 DBG ("TX id %d at %#08lx + %#08zx\n", np
->tx_cur
,
481 virt_to_bus (&iobuf
->data
), iob_len (iobuf
));
483 /* increment the circular buffer pointer to the next buffer location
485 np
->tx_cur
= (np
->tx_cur
+ 1) % TX_RING_SIZE
;
487 /*start the transmitter
489 outl (TxOn
, np
->ioaddr
+ ChipCmd
);
495 * Poll for received packets
497 * @v netdev Network device
499 static void natsemi_poll (struct net_device
*netdev
)
501 struct natsemi_private
*np
= netdev
->priv
;
502 unsigned int tx_status
;
503 unsigned int rx_status
;
504 unsigned int intr_status
;
506 struct io_buffer
*rx_iob
;
509 /* read the interrupt register
511 intr_status
= inl (np
->ioaddr
+ IntrStatus
);
516 DBG ("natsemi_poll: intr_status = %#08x\n", intr_status
);
518 /* Check status of transmitted packets
521 while (i
!= np
->tx_cur
) {
522 tx_status
= np
->tx
[np
->tx_dirty
].cmdsts
;
524 DBG ("tx_dirty = %d tx_cur=%d tx_status=%#08x\n",
525 np
->tx_dirty
, np
->tx_cur
, tx_status
);
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",
535 netdev_tx_complete (netdev
, np
->tx_iobuf
[np
->tx_dirty
]);
536 DBG ("Success transmitting packet\n");
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
;
544 /* Process received packets
546 rx_status
= (unsigned int) np
->rx
[np
->rx_cur
].cmdsts
;
547 while ((rx_status
& OWN
)) {
548 rx_len
= (rx_status
& DSIZE
) - CRC_SIZE
;
550 DBG ("Received packet, rx_curr = %d, rx_status = %#08x, rx_len = %d\n",
551 np
->rx_cur
, rx_status
, rx_len
);
553 if ((rx_status
& (DescMore
| DescPktOK
| RxTooLong
)) != DescPktOK
) {
554 netdev_rx_err (netdev
, NULL
, -EINVAL
);
556 DBG ("natsemi_poll: Corrupted packet received!"
558 np
->rx
[np
->rx_cur
].cmdsts
);
563 /* If unable allocate space for this packet,
564 * try again next poll
566 rx_iob
= alloc_iob (rx_len
);
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.
573 netdev_rx (netdev
, rx_iob
);
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
;
580 /* re-enable the potentially idle receive state machine
582 outl (RxOn
, np
->ioaddr
+ ChipCmd
);
586 * Enable/disable interrupts
588 * @v netdev Network device
589 * @v enable Non-zero for enable, zero for disable
591 static void natsemi_irq (struct net_device
*netdev
, int enable
)
593 struct natsemi_private
*np
= netdev
->priv
;
595 outl ((enable
? (RxOk
| RxErr
| TxOk
|TxErr
) : 0),
596 np
->ioaddr
+ IntrMask
);
597 outl ((enable
? 1 : 0), np
->ioaddr
+ IntrEnable
);
600 static struct pci_device_id natsemi_nics
[] = {
601 PCI_ROM(0x100b, 0x0020, "dp83815", "DP83815", 0),
604 struct pci_driver natsemi_driver __pci_driver
= {
606 .id_count
= (sizeof (natsemi_nics
) / sizeof (natsemi_nics
[0])),
607 .probe
= natsemi_probe
,
608 .remove
= natsemi_remove
,