From 208ff0d42e0206a40ff2ebe2aef50f1daddfdbf4 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 7 Jul 2007 22:33:45 +0100 Subject: [PATCH 01/33] Revert mdc's warnings purge on natsemi.c, to allow for a clean rebase. --- src/drivers/net/natsemi.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index c5b87fcc..8c982c8b 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -536,8 +536,7 @@ natsemi_init_rxd(struct nic *nic __unused) rxd[i].bufptr = virt_to_bus(&rxb[i*RX_BUF_SIZE]); if (natsemi_debug > 1) printf("natsemi_init_rxd: rxd[%d]=%p link=%X cmdsts=%X bufptr=%4.4x\n", - i, &rxd[i], (unsigned int) rxd[i].link, (unsigned int) rxd[i].cmdsts, - (unsigned int) rxd[i].bufptr); + i, &rxd[i], rxd[i].link, rxd[i].cmdsts, rxd[i].bufptr); } /* load Receive Descriptor Register */ @@ -649,11 +648,11 @@ natsemi_transmit(struct nic *nic, /* wait */ ; if (currticks() >= to) { - printf("natsemi_transmit: TX Timeout! Tx status %X.\n", (unsigned int) tx_status); + printf("natsemi_transmit: TX Timeout! Tx status %X.\n", tx_status); } if (!(tx_status & 0x08000000)) { - printf("natsemi_transmit: Transmit error, Tx status %X.\n", (unsigned int) tx_status); + printf("natsemi_transmit: Transmit error, Tx status %X.\n", tx_status); } } @@ -678,7 +677,7 @@ natsemi_poll(struct nic *nic, int retrieve) int retstat = 0; if (natsemi_debug > 2) - printf("natsemi_poll: cur_rx:%d, status:%X\n", cur_rx, (unsigned int) rx_status); + printf("natsemi_poll: cur_rx:%d, status:%X\n", cur_rx, rx_status); if (!(rx_status & OWN)) return retstat; @@ -687,14 +686,14 @@ natsemi_poll(struct nic *nic, int retrieve) if (natsemi_debug > 1) printf("natsemi_poll: got a packet: cur_rx:%d, status:%X\n", - cur_rx, (unsigned int) rx_status); + cur_rx, rx_status); nic->packetlen = (rx_status & DSIZE) - CRC_SIZE; if ((rx_status & (DescMore|DescPktOK|RxTooLong)) != DescPktOK) { /* corrupted packet received */ printf("natsemi_poll: Corrupted packet received, buffer status = %X\n", - (unsigned int) rx_status); + rx_status); retstat = 0; } else { /* give packet to higher level routine */ From 4cea792470791da14712d1ae4e1cc12e98eda2ad Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Fri, 15 Jun 2007 21:42:09 -0400 Subject: [PATCH 02/33] testing if it works --- src/drivers/net/natsemi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index 8c982c8b..d7f9c95c 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -1,6 +1,7 @@ /* -*- Mode:C; c-basic-offset:4; -*- */ /* + NEEDS to change to match GPXE specs natsemi.c: An Etherboot driver for the NatSemi DP8381x series. Copyright (C) 2001 Entity Cyber, Inc. From 97efdbe9d7c4167c967bbd0f3c6e556b6978957c Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Mon, 18 Jun 2007 18:30:33 -0400 Subject: [PATCH 03/33] skel of new natsemi driver (still in developments) --- src/drivers/net/natsemi.c | 1122 +++++++++++++++---------------------- 1 file changed, 466 insertions(+), 656 deletions(-) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index d7f9c95c..949f8fe4 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -1,98 +1,62 @@ -/* -*- Mode:C; c-basic-offset:4; -*- */ - -/* - NEEDS to change to match GPXE specs - natsemi.c: An Etherboot driver for the NatSemi DP8381x series. - - Copyright (C) 2001 Entity Cyber, Inc. - - This development of this Etherboot driver was funded by - - Sicom Systems: http://www.sicompos.com/ - - Author: Marty Connor (mdc@etherboot.org) - Adapted from a Linux driver which was written by Donald Becker - - This software may be used and distributed according to the terms - of the GNU Public License (GPL), incorporated herein by reference. - - Original Copyright Notice: - - Written/copyright 1999-2001 by Donald Becker. - - This software may be used and distributed according to the terms of - the GNU General Public License (GPL), incorporated herein by reference. - Drivers based on or derived from this code fall under the GPL and must - retain the authorship, copyright and license notice. This file is not - a complete program and may only be used when the entire operating - system is licensed under the GPL. License for under other terms may be - available. Contact the original author for details. - - The original author may be reached as becker@scyld.com, or at - Scyld Computing Corporation - 410 Severn Ave., Suite 210 - Annapolis MD 21403 - - Support information and updates available at - http://www.scyld.com/network/netsemi.html - - References: - - http://www.scyld.com/expert/100mbps.html - http://www.scyld.com/expert/NWay.html - Datasheet is available from: - http://www.national.com/pf/DP/DP83815.html +/* natsemi.c - gPXE driver for the NatSemi DP8381x series. + */ -/* Revision History */ - -/* - 13 Dec 2003 timlegge 1.1 Enabled Multicast Support - 29 May 2001 mdc 1.0 - Initial Release. Tested with Netgear FA311 and FA312 boards -*/ -/* Includes */ - -#include "etherboot.h" -#include "nic.h" -#include "pcibios.h" +#include +#include +#include +#include +#include +#include +#include #include +#include #include +#include +#include +#include +#include +#include -/* defines */ +#define TX_RING_SIZE 4 +#define NUM_RX_DESC 4 -#define OWN 0x80000000 -#define DSIZE 0x00000FFF -#define CRC_SIZE 4 - -/* Time in ticks before concluding the transmitter is hung. */ -#define TX_TIMEOUT (4*TICKS_PER_SEC) - -#define TX_BUF_SIZE 1536 -#define RX_BUF_SIZE 1536 - -#define NUM_RX_DESC 4 /* Number of Rx descriptor registers. */ - -/* helpful macroes if on a big_endian machine for changing byte order. - not strictly needed on Intel */ -#define get_unaligned(ptr) (*(ptr)) -#define put_unaligned(val, ptr) ((void)( *(ptr) = (val) )) -#define get_u16(ptr) (*(u16 *)(ptr)) -#define virt_to_le32desc(addr) virt_to_bus(addr) - -enum pcistuff { - PCI_USES_IO = 0x01, - PCI_USES_MEM = 0x02, - PCI_USES_MASTER = 0x04, - PCI_ADDR0 = 0x08, - PCI_ADDR1 = 0x10, +struct natsemi_tx { + uint32_t link; + uint32_t cmdsts; + uint32_t bufptr; }; -/* MMIO operations required */ -#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1) +struct natsemi_rx { + uint32_t link; + uint32_t cmdsts; + uint32_t bufptr; +}; -/* Offsets to the device registers. +struct natsemi_nic { + unsigned short ioaddr; + unsigned short tx_next; + struct natsemi_tx tx[TX_RING_SIZE]; + struct natsemi_rx rx[NUM_RX_DESC]; + struct spi_bit_basher spibit; + struct spi_device eeprom; + struct nvo_block nvo; +}; + +/* Tuning Parameters */ +#define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */ +#define RX_FIFO_THRESH 4 /* Rx buffer level before first PCI xfer. */ +#define RX_DMA_BURST 4 /* Maximum PCI burst, '4' is 256 bytes */ +#define TX_DMA_BURST 4 /* Calculate as 16<ioaddr + Cfg9346 ); + return ( eereg & mask ); +} -/* - * Function: natsemi_probe +static void rtl_spi_write_bit ( struct bit_basher *basher, + unsigned int bit_id, unsigned long data ) { + struct rtl8139_nic *rtl = container_of ( basher, struct rtl8139_nic, + spibit.basher ); + uint8_t mask = rtl_ee_bits[bit_id]; + uint8_t eereg; + + eereg = inb ( rtl->ioaddr + Cfg9346 ); + eereg &= ~mask; + eereg |= ( data & mask ); + outb ( eereg, rtl->ioaddr + Cfg9346 ); +} + +static struct bit_basher_operations rtl_basher_ops = { + .read = rtl_spi_read_bit, + .write = rtl_spi_write_bit, +}; + +/** Portion of EEPROM available for non-volatile stored options * - * Description: Retrieves the MAC address of the card, and sets up some - * globals required by other routines, and initializes the NIC, making it - * ready to send and receive packets. - * - * Side effects: - * leaves the ioaddress of the natsemi chip in the variable ioaddr. - * leaves the natsemi initialized, and ready to recieve packets. - * - * Returns: struct nic *: pointer to NIC data structure + * We use offset 0x40 (i.e. address 0x20), length 0x40. This block is + * marked as VPD in the rtl8139 datasheets, so we use it only if we + * detect that the card is not supporting VPD. */ +static struct nvo_fragment rtl_nvo_fragments[] = { + { 0x20, 0x40 }, + { 0, 0 } +}; -static int -natsemi_probe ( struct nic *nic, struct pci_device *pci ) { +/** + * Set up for EEPROM access + * + * @v NAT NATSEMI NIC + */ + void nat_init_eeprom ( struct natsemi_nic *nat ) { + int ee9356; + int vpd; - int i; - int prev_eedata; - uint32_t tmp; + /* Initialise three-wire bus */ + nat->spibit.basher.op = &rtl_basher_ops; + rtl->spibit.bus.mode = SPI_MODE_THREEWIRE; + init_spi_bit_basher ( &rtl->spibit ); - if (pci->ioaddr == 0) - return 0; + /* Detect EEPROM type and initialise three-wire device */ + ee9356 = ( inw ( rtl->ioaddr + RxConfig ) & Eeprom9356 ); + if ( ee9356 ) { + DBG ( "EEPROM is an AT93C56\n" ); + init_at93c56 ( &rtl->eeprom, 16 ); + } else { + DBG ( "EEPROM is an AT93C46\n" ); + init_at93c46 ( &rtl->eeprom, 16 ); + } + rtl->eeprom.bus = &rtl->spibit.bus; - adjust_pci_device(pci); + /* Initialise space for non-volatile options, if available */ + vpd = ( inw ( rtl->ioaddr + Config1 ) & VPDEnable ); + if ( vpd ) { + DBG ( "EEPROM in use for VPD; cannot use for options\n" ); + } else { + rtl->nvo.nvs = &rtl->eeprom.nvs; + rtl->nvo.fragments = rtl_nvo_fragments; + } +} - /* initialize some commonly used globals */ +/** + * Reset NIC + * + * @v rtl NATSEMI NIC + * + * Issues a hardware reset and waits for the reset to complete. + */ +static void nat_reset ( struct nat_nic *nat ) { + + /* Reset chip */ + outb ( ChipReset, nat->ioaddr + ChipCmd ); + mdelay ( 10 ); + memset ( &nat->tx, 0, sizeof ( nat->tx ) ); + nat->rx.offset = 0; + + /* Restore PME enable bit */ + outl(SavedClkRun, nat->ioaddr + ClkRun); +} + +/** + * Open NIC + * + * @v netdev Net device + * @ret rc Return status code + */ +static int nat_open ( struct net_device *netdev ) { + struct natsemi_nic *nat = netdev->priv; + struct io_buffer *iobuf; + int i; - nic->irqno = 0; - pci_fill_nic ( nic, pci ); - nic->ioaddr = pci->ioaddr; + /* Disable PME: + * The PME bit is initialized from the EEPROM contents. + * PCI cards probably have PME disabled, but motherboard + * implementations may have PME set to enable WakeOnLan. + * With PME set the chip will scan incoming packets but + * nothing will be written to memory. */ + SavedClkRun = inl(nat->ioaddr + ClkRun); + outl(SavedClkRun & ~0x100, nat->ioaddr + ClkRun); - ioaddr = pci->ioaddr; - vendor = pci->vendor; - dev_id = pci->device; - nic_name = pci->driver_name; - - /* natsemi has a non-standard PM control register - * in PCI config space. Some boards apparently need - * to be brought to D0 in this manner. - */ - pci_read_config_dword ( pci, PCIPM, &tmp ); - if (tmp & (0x03|0x100)) { - /* D0 state, disable PME assertion */ - u32 newtmp = tmp & ~(0x03|0x100); - pci_write_config_dword(pci, PCIPM, newtmp); - } - - /* get MAC address */ - - prev_eedata = eeprom_read(ioaddr, 6); - for (i = 0; i < 3; i++) { - int eedata = eeprom_read(ioaddr, i + 7); - nic->node_addr[i*2] = (eedata << 1) + (prev_eedata >> 15); - nic->node_addr[i*2+1] = eedata >> 7; - prev_eedata = eedata; - } - - DBG ( "\nnatsemi_probe: MAC addr %s at ioaddr %4.4lx\n", - eth_ntoa ( nic->node_addr ), ioaddr); - DBG ( "natsemi_probe: Vendor:%#hX Device:%#hX\n", vendor, dev_id ); - - /* Reset the chip to erase any previous misconfiguration. */ - outl(ChipReset, ioaddr + ChipCmd); - - advertising = mdio_read(1, 4); - { - u32 chip_config = inl(ioaddr + ChipConfig); - printf("%s: Transceiver default autoneg. %s " - "10%s %s duplex.\n", - nic_name, - chip_config & 0x2000 ? "enabled, advertise" : "disabled, force", - chip_config & 0x4000 ? "0" : "", - chip_config & 0x8000 ? "full" : "half"); - } - printf("%s: Transceiver status %hX advertising %hX\n", - nic_name, (int)inl(ioaddr + 0x84), advertising); - - /* Disable PME: - * The PME bit is initialized from the EEPROM contents. - * PCI cards probably have PME disabled, but motherboard - * implementations may have PME set to enable WakeOnLan. - * With PME set the chip will scan incoming packets but - * nothing will be written to memory. */ - SavedClkRun = inl(ioaddr + ClkRun); - outl(SavedClkRun & ~0x100, ioaddr + ClkRun); - - /* initialize device */ - natsemi_init(nic); - nic->nic_op = &natsemi_operations; - - return 1; -} - -/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. - The EEPROM code is for the common 93c06/46 EEPROMs with 6 bit addresses. -*/ - -/* Delay between EEPROM clock transitions. - No extra delay is needed with 33Mhz PCI, but future 66Mhz access may need - a delay. */ -#define eeprom_delay(ee_addr) inl(ee_addr) - -enum EEPROM_Ctrl_Bits { - EE_ShiftClk = 0x04, - EE_DataIn = 0x01, - EE_ChipSelect = 0x08, - EE_DataOut = 0x02 -}; - -#define EE_Write0 (EE_ChipSelect) -#define EE_Write1 (EE_ChipSelect | EE_DataIn) - -/* The EEPROM commands include the alway-set leading bit. */ -enum EEPROM_Cmds { - EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6), -}; - -static int eeprom_read(long addr, int location) -{ - int i; - int retval = 0; - int ee_addr = addr + EECtrl; - int read_cmd = location | EE_ReadCmd; - outl(EE_Write0, ee_addr); - - /* Shift the read command bits out. */ - for (i = 10; i >= 0; i--) { - short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0; - outl(dataval, ee_addr); - eeprom_delay(ee_addr); - outl(dataval | EE_ShiftClk, ee_addr); - eeprom_delay(ee_addr); - } - outl(EE_ChipSelect, ee_addr); - eeprom_delay(ee_addr); - - for (i = 0; i < 16; i++) { - outl(EE_ChipSelect | EE_ShiftClk, ee_addr); - eeprom_delay(ee_addr); - retval |= (inl(ee_addr) & EE_DataOut) ? 1 << i : 0; - outl(EE_ChipSelect, ee_addr); - eeprom_delay(ee_addr); - } - - /* Terminate the EEPROM access. */ - outl(EE_Write0, ee_addr); - outl(0, ee_addr); - - return retval; -} - -/* MII transceiver control section. - The 83815 series has an internal transceiver, and we present the - management registers as if they were MII connected. */ - -static int mdio_read(int phy_id, int location) -{ - if (phy_id == 1 && location < 32) - return inl(ioaddr + 0x80 + (location<<2)) & 0xffff; - else - return 0xffff; -} - -/* Function: natsemi_init - * - * Description: resets the ethernet controller chip and configures - * registers and data structures required for sending and receiving packets. - * - * Arguments: struct nic *nic: NIC data structure - * - * returns: void. - */ - -static void -natsemi_init(struct nic *nic) -{ - natsemi_reset(nic); - /* Disable PME: - * The PME bit is initialized from the EEPROM contents. - * PCI cards probably have PME disabled, but motherboard - * implementations may have PME set to enable WakeOnLan. - * With PME set the chip will scan incoming packets but - * nothing will be written to memory. */ - outl(SavedClkRun & ~0x100, ioaddr + ClkRun); - natsemi_init_rxfilter(nic); - natsemi_init_txd(nic); - natsemi_init_rxd(nic); + /* Program the MAC address TODO enable this comment */ + /* + for ( i = 0 ; i < ETH_ALEN ; i++ ) + outb ( netdev->ll_addr[i], rtl->ioaddr + MAC0 + i ); + */ + /* Set up RX ring */ - /* Initialize other registers. */ - /* Configure the PCI bus bursts and FIFO thresholds. */ - /* Configure for standard, in-spec Ethernet. */ - if (inl(ioaddr + ChipConfig) & 0x20000000) { /* Full duplex */ - tx_config = 0xD0801002; - rx_config = 0x10000020; - } else { - tx_config = 0x10801002; - rx_config = 0x0020; - } - outl(tx_config, ioaddr + TxConfig); - outl(rx_config, ioaddr + RxConfig); + for (i=0;irx[i].link = virt_to_bus((i+1 < NUM_RX_DESC) ? &nat->rx[i+1] : &nat->rx[0]); + nat->rx[i].cmdsts = (u32) RX_BUF_SIZE; + nat->rx[i].bufptr = virt_to_bus(iobuf->data); + } - outl(RxOn, ioaddr + ChipCmd); + + /* load Receive Descriptor Register */ + outl(virt_to_bus(&nat->rx[0]), ioaddr + RxRingPtr); + DBG("Natsemi Rx descriptor loaded with: %X\n",inl(nat->ioaddr+RingPtr)); + + /* setup Tx ring */ + outl(virt_to_bus(&nat->tx[0]),nat->ioaddr+TxRingPtr); + DBG("Natsemi Tx descriptor loaded with: %X\n",inl(nat->ioaddr+TxRingPtr)); + + /* Enables RX */ + outl(RxFilterEnable|AcceptBroadcast|AcceptAllMulticast|AcceptMyPhys, nat->ioaddr+RxFilterAddr); + + /* Initialize other registers. */ + /* Configure the PCI bus bursts and FIFO thresholds. */ + /* Configure for standard, in-spec Ethernet. */ + if (inl(nat->ioaddr + ChipConfig) & 0x20000000) { /* Full duplex */ + tx_config = 0xD0801002; + rx_config = 0x10000020; + } else { + tx_config = 0x10801002; + rx_config = 0x0020; + } + outl(tx_config, nat->ioaddr + TxConfig); + outl(rx_config, nat->ioaddr + RxConfig); + + + + /*start the receiver and transmitter */ + outl(RxOn|TxOn, nat->ioaddr + ChipCmd); + + + return 0; } -/* - * Function: natsemi_reset +/** + * Close NIC * - * Description: soft resets the controller chip - * - * Arguments: struct nic *nic: NIC data structure - * - * Returns: void. + * @v netdev Net device */ -static void -natsemi_reset(struct nic *nic __unused) +static void rtl_close ( struct net_device *netdev ) { + struct rtl8139_nic *rtl = netdev->priv; + + /* Reset the hardware to disable everything in one go */ + rtl_reset ( rtl ); + + /* Free RX ring */ + free ( rtl->rx.ring ); + rtl->rx.ring = NULL; +} + +/** + * Transmit packet + * + * @v netdev Network device + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int natsemi_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { + struct natsemi_nic *nat = netdev->priv; + + /* Check for space in TX ring */ + if ( nat->tx.iobuf[nat->tx.next] != NULL ) { + printf ( "TX overflow\n" ); + return -ENOBUFS; + } + + /* Pad and align packet */ + iob_pad ( iobuf, ETH_ZLEN ); + + /* Add to TX ring */ + DBG ( "TX id %d at %lx+%x\n", rtl->tx.next, + virt_to_bus ( iobuf->data ), iob_len ( iobuf ) ); + rtl->tx.iobuf[rtl->tx.next] = iobuf; + outl ( virt_to_bus ( iobuf->data ), + rtl->ioaddr + TxAddr0 + 4 * rtl->tx.next ); + outl ( ( ( ( TX_FIFO_THRESH & 0x7e0 ) << 11 ) | iob_len ( iobuf ) ), + rtl->ioaddr + TxStatus0 + 4 * rtl->tx.next ); + rtl->tx.next = ( rtl->tx.next + 1 ) % TX_RING_SIZE; + + return 0; +} + +/** + * Poll for received packets + * + * @v netdev Network device + * @v rx_quota Maximum number of packets to receive + */ +static void rtl_poll ( struct net_device *netdev, unsigned int rx_quota ) { + struct rtl8139_nic *rtl = netdev->priv; + unsigned int status; + unsigned int tsad; + unsigned int rx_status; + unsigned int rx_len; + struct io_buffer *rx_iob; + int wrapped_len; + int i; + + /* Acknowledge interrupts */ + status = inw ( rtl->ioaddr + IntrStatus ); + if ( ! status ) + return; + outw ( status, rtl->ioaddr + IntrStatus ); + + /* Handle TX completions */ + tsad = inw ( rtl->ioaddr + TxSummary ); + for ( i = 0 ; i < TX_RING_SIZE ; i++ ) { + if ( ( rtl->tx.iobuf[i] != NULL ) && ( tsad & ( 1 << i ) ) ) { + DBG ( "TX id %d complete\n", i ); + netdev_tx_complete ( netdev, rtl->tx.iobuf[i] ); + rtl->tx.iobuf[i] = NULL; + } + } + + /* Handle received packets */ + while ( rx_quota && ! ( inw ( rtl->ioaddr + ChipCmd ) & RxBufEmpty ) ){ + rx_status = * ( ( uint16_t * ) + ( rtl->rx.ring + rtl->rx.offset ) ); + rx_len = * ( ( uint16_t * ) + ( rtl->rx.ring + rtl->rx.offset + 2 ) ); + if ( rx_status & RxOK ) { + DBG ( "RX packet at offset %x+%x\n", rtl->rx.offset, + rx_len ); + + rx_iob = alloc_iob ( rx_len ); + if ( ! rx_iob ) { + /* Leave packet for next call to poll() */ + break; + } + + wrapped_len = ( ( rtl->rx.offset + 4 + rx_len ) + - RX_BUF_LEN ); + if ( wrapped_len < 0 ) + wrapped_len = 0; + + memcpy ( iob_put ( rx_iob, rx_len - wrapped_len ), + rtl->rx.ring + rtl->rx.offset + 4, + rx_len - wrapped_len ); + memcpy ( iob_put ( rx_iob, wrapped_len ), + rtl->rx.ring, wrapped_len ); + + netdev_rx ( netdev, rx_iob ); + rx_quota--; + } else { + DBG ( "RX bad packet (status %#04x len %d)\n", + rx_status, rx_len ); + } + rtl->rx.offset = ( ( ( rtl->rx.offset + 4 + rx_len + 3 ) & ~3 ) + % RX_BUF_LEN ); + outw ( rtl->rx.offset - 16, rtl->ioaddr + RxBufPtr ); + } +} + +#if 0 +static void rtl_irq(struct nic *nic, irq_action_t action) { - outl(ChipReset, ioaddr + ChipCmd); + unsigned int mask; + /* Bit of a guess as to which interrupts we should allow */ + unsigned int interested = ROK | RER | RXOVW | FOVW | SERR; + + switch ( action ) { + case DISABLE : + case ENABLE : + mask = inw(rtl->ioaddr + IntrMask); + mask = mask & ~interested; + if ( action == ENABLE ) mask = mask | interested; + outw(mask, rtl->ioaddr + IntrMask); + break; + case FORCE : + /* Apparently writing a 1 to this read-only bit of a + * read-only and otherwise unrelated register will + * force an interrupt. If you ever want to see how + * not to write a datasheet, read the one for the + * RTL8139... + */ + outb(EROK, rtl->ioaddr + RxEarlyStatus); + break; + } +} +#endif + +/** + * Probe PCI device + * + * @v pci PCI device + * @v id PCI ID + * @ret rc Return status code + */ +static int nat_probe ( struct pci_device *pci, + const struct pci_device_id *id __unused ) { + struct net_device *netdev; + struct natsemi_nic *nat = NULL; + int registered_netdev = 0; + int rc; + + /* Fix up PCI device */ + adjust_pci_device ( pci ); + + /* Allocate net device */ + netdev = alloc_etherdev ( sizeof ( *nat ) ); + if ( ! netdev ) { + rc = -ENOMEM; + goto err; + } + nat = netdev->priv; + pci_set_drvdata ( pci, netdev ); + netdev->dev = &pci->dev; + memset ( nat, 0, sizeof ( *nat ) ); + nat->ioaddr = pci->ioaddr; + + /* Reset the NIC, set up EEPROM access and read MAC address */ + nat_reset ( nat ); + /* commenitng two line below. Have to be included in final natsemi.c TODO*/ + /* + nat_init_eeprom ( rtl ); + nvs_read ( &nat->eeprom.nvs, EE_MAC, netdev->ll_addr, ETH_ALEN ); - /* On page 78 of the spec, they recommend some settings for "optimum - performance" to be done in sequence. These settings optimize some - of the 100Mbit autodetection circuitry. Also, we only want to do - this for rev C of the chip. - */ - if (inl(ioaddr + SiliconRev) == 0x302) { - outw(0x0001, ioaddr + PGSEL); - outw(0x189C, ioaddr + PMDCSR); - outw(0x0000, ioaddr + TSTDAT); - outw(0x5040, ioaddr + DSPCFG); - outw(0x008C, ioaddr + SDCFG); - } - /* Disable interrupts using the mask. */ - outl(0, ioaddr + IntrMask); - outl(0, ioaddr + IntrEnable); -} - -/* Function: natsemi_init_rxfilter - * - * Description: sets receive filter address to our MAC address - * - * Arguments: struct nic *nic: NIC data structure - * - * returns: void. - */ - -static void -natsemi_init_rxfilter(struct nic *nic) -{ - int i; - - for (i = 0; i < ETH_ALEN; i += 2) { - outl(i, ioaddr + RxFilterAddr); - outw(nic->node_addr[i] + (nic->node_addr[i+1] << 8), ioaddr + RxFilterData); - } -} - -/* - * Function: natsemi_init_txd - * - * Description: initializes the Tx descriptor - * - * Arguments: struct nic *nic: NIC data structure - * - * returns: void. - */ - -static void -natsemi_init_txd(struct nic *nic __unused) -{ - txd.link = (u32) 0; - txd.cmdsts = (u32) 0; - txd.bufptr = virt_to_bus(&txb[0]); - - /* load Transmit Descriptor Register */ - outl(virt_to_bus(&txd), ioaddr + TxRingPtr); - if (natsemi_debug > 1) - printf("natsemi_init_txd: TX descriptor register loaded with: %lx\n", - inl(ioaddr + TxRingPtr)); -} - -/* Function: natsemi_init_rxd - * - * Description: initializes the Rx descriptor ring - * - * Arguments: struct nic *nic: NIC data structure - * - * Returns: void. - */ - -static void -natsemi_init_rxd(struct nic *nic __unused) -{ - int i; - - cur_rx = 0; - - /* init RX descriptor */ - for (i = 0; i < NUM_RX_DESC; i++) { - rxd[i].link = virt_to_bus((i+1 < NUM_RX_DESC) ? &rxd[i+1] : &rxd[0]); - rxd[i].cmdsts = (u32) RX_BUF_SIZE; - rxd[i].bufptr = virt_to_bus(&rxb[i*RX_BUF_SIZE]); - if (natsemi_debug > 1) - printf("natsemi_init_rxd: rxd[%d]=%p link=%X cmdsts=%X bufptr=%4.4x\n", - i, &rxd[i], rxd[i].link, rxd[i].cmdsts, rxd[i].bufptr); - } - - /* load Receive Descriptor Register */ - outl(virt_to_bus(&rxd[0]), ioaddr + RxRingPtr); - - if (natsemi_debug > 1) - printf("natsemi_init_rxd: RX descriptor register loaded with: %lx\n", - inl(ioaddr + RxRingPtr)); -} - -/* Function: natsemi_set_rx_mode - * - * Description: - * sets the receive mode to accept all broadcast packets and packets - * with our MAC address, and reject all multicast packets. - * - * Arguments: struct nic *nic: NIC data structure - * - * Returns: void. - */ - -static void natsemi_set_rx_mode(struct nic *nic __unused) -{ - u32 rx_mode = RxFilterEnable | AcceptBroadcast | - AcceptAllMulticast | AcceptMyPhys; + */ - outl(rx_mode, ioaddr + RxFilterAddr); + /* Point to NIC specific routines */ + netdev->open = nat_open; + netdev->close = nat_close; + netdev->transmit = nat_transmit; + netdev->poll = nat_poll; + + /* Register network device */ + if ( ( rc = register_netdev ( netdev ) ) != 0 ) + goto err; + registered_netdev = 1; + + /* Register non-volatile storagei + * uncomment lines below in final version*/ + /* + if ( rtl->nvo.nvs ) { + if ( ( rc = nvo_register ( &rtl->nvo ) ) != 0 ) + goto err; + } + */ + + return 0; + + err: + /* Disable NIC */ + if ( nat ) + nat_reset ( rtl ); + if ( registered_netdev ) + unregister_netdev ( netdev ); + /* Free net device */ + free_netdev ( netdev ); + return rc; } -static void natsemi_check_duplex(struct nic *nic __unused) -{ - int duplex = inl(ioaddr + ChipConfig) & 0x20000000 ? 1 : 0; - - if (natsemi_debug) - printf("%s: Setting %s-duplex based on negotiated link" - " capability.\n", nic_name, - duplex ? "full" : "half"); - if (duplex) { - rx_config |= 0x10000000; - tx_config |= 0xC0000000; - } else { - rx_config &= ~0x10000000; - tx_config &= ~0xC0000000; - } - outl(tx_config, ioaddr + TxConfig); - outl(rx_config, ioaddr + RxConfig); -} - -/* Function: natsemi_transmit +/** + * Remove PCI device * - * Description: transmits a packet and waits for completion or timeout. - * - * Arguments: char d[6]: destination ethernet address. - * unsigned short t: ethernet protocol type. - * unsigned short s: size of the data-part of the packet. - * char *p: the data for the packet. - * - * Returns: void. + * @v pci PCI device */ +static void rtl_remove ( struct pci_device *pci ) { + struct net_device *netdev = pci_get_drvdata ( pci ); + struct rtl8139_nic *rtl = netdev->priv; -static void -natsemi_transmit(struct nic *nic, - const char *d, /* Destination */ - unsigned int t, /* Type */ - unsigned int s, /* size */ - const char *p) /* Packet */ -{ - u32 to, nstype; - volatile u32 tx_status; - - /* Stop the transmitter */ - outl(TxOff, ioaddr + ChipCmd); - - /* load Transmit Descriptor Register */ - outl(virt_to_bus(&txd), ioaddr + TxRingPtr); - if (natsemi_debug > 1) - printf("natsemi_transmit: TX descriptor register loaded with: %lx\n", - inl(ioaddr + TxRingPtr)); - - memcpy(txb, d, ETH_ALEN); - memcpy(txb + ETH_ALEN, nic->node_addr, ETH_ALEN); - nstype = htons(t); - memcpy(txb + 2 * ETH_ALEN, (char*)&nstype, 2); - memcpy(txb + ETH_HLEN, p, s); - - s += ETH_HLEN; - s &= DSIZE; - - if (natsemi_debug > 1) - printf("natsemi_transmit: sending %d bytes ethtype %hX\n", (int) s, t); - - /* pad to minimum packet size */ - while (s < ETH_ZLEN) - txb[s++] = '\0'; - - /* set the transmit buffer descriptor and enable Transmit State Machine */ - txd.bufptr = virt_to_bus(&txb[0]); - txd.cmdsts = (u32) OWN | s; - - /* restart the transmitter */ - outl(TxOn, ioaddr + ChipCmd); - - if (natsemi_debug > 1) - printf("natsemi_transmit: Queued Tx packet size %d.\n", (int) s); - - to = currticks() + TX_TIMEOUT; - - while (((tx_status=txd.cmdsts) & OWN) && (currticks() < to)) - /* wait */ ; - - if (currticks() >= to) { - printf("natsemi_transmit: TX Timeout! Tx status %X.\n", tx_status); - } - - if (!(tx_status & 0x08000000)) { - printf("natsemi_transmit: Transmit error, Tx status %X.\n", tx_status); - } + if ( rtl->nvo.nvs ) + nvo_unregister ( &rtl->nvo ); + unregister_netdev ( netdev ); + rtl_reset ( rtl ); + free_netdev ( netdev ); } -/* Function: natsemi_poll - * - * Description: checks for a received packet and returns it if found. - * - * Arguments: struct nic *nic: NIC data structure - * - * Returns: 1 if packet was received. - * 0 if no packet was received. - * - * Side effects: - * Returns (copies) the packet to the array nic->packet. - * Returns the length of the packet in nic->packetlen. - */ - -static int -natsemi_poll(struct nic *nic, int retrieve) -{ - u32 rx_status = rxd[cur_rx].cmdsts; - int retstat = 0; - - if (natsemi_debug > 2) - printf("natsemi_poll: cur_rx:%d, status:%X\n", cur_rx, rx_status); - - if (!(rx_status & OWN)) - return retstat; - - if ( ! retrieve ) return 1; - - if (natsemi_debug > 1) - printf("natsemi_poll: got a packet: cur_rx:%d, status:%X\n", - cur_rx, rx_status); - - nic->packetlen = (rx_status & DSIZE) - CRC_SIZE; - - if ((rx_status & (DescMore|DescPktOK|RxTooLong)) != DescPktOK) { - /* corrupted packet received */ - printf("natsemi_poll: Corrupted packet received, buffer status = %X\n", - rx_status); - retstat = 0; - } else { - /* give packet to higher level routine */ - memcpy(nic->packet, (rxb + cur_rx*RX_BUF_SIZE), nic->packetlen); - retstat = 1; - } - - /* return the descriptor and buffer to receive ring */ - rxd[cur_rx].cmdsts = RX_BUF_SIZE; - rxd[cur_rx].bufptr = virt_to_bus(&rxb[cur_rx*RX_BUF_SIZE]); - - if (++cur_rx == NUM_RX_DESC) - cur_rx = 0; - - /* re-enable the potentially idle receive state machine */ - outl(RxOn, ioaddr + ChipCmd); - - return retstat; -} - -/* Function: natsemi_disable - * - * Description: Turns off interrupts and stops Tx and Rx engines - * - * Arguments: struct nic *nic: NIC data structure - * - * Returns: void. - */ - -static void -natsemi_disable ( struct nic *nic ) { - - natsemi_init(nic); - - /* Disable interrupts using the mask. */ - outl(0, ioaddr + IntrMask); - outl(0, ioaddr + IntrEnable); - - /* Stop the chip's Tx and Rx processes. */ - outl(RxOff | TxOff, ioaddr + ChipCmd); - - /* Restore PME enable bit */ - outl(SavedClkRun, ioaddr + ClkRun); -} - -/* Function: natsemi_irq - * - * Description: Enable, Disable, or Force interrupts - * - * Arguments: struct nic *nic: NIC data structure - * irq_action_t action: requested action to perform - * - * Returns: void. - */ - -static void -natsemi_irq(struct nic *nic __unused, irq_action_t action __unused) -{ - switch ( action ) { - case DISABLE : - break; - case ENABLE : - break; - case FORCE : - break; - } -} - -static struct nic_operations natsemi_operations = { - .connect = dummy_connect, - .poll = natsemi_poll, - .transmit = natsemi_transmit, - .irq = natsemi_irq, - +static struct pci_device_id rtl8139_nics[] = { +PCI_ROM(0x10ec, 0x8129, "rtl8129", "Realtek 8129"), +PCI_ROM(0x10ec, 0x8139, "rtl8139", "Realtek 8139"), +PCI_ROM(0x10ec, 0x8138, "rtl8139b", "Realtek 8139B"), +PCI_ROM(0x1186, 0x1300, "dfe538", "DFE530TX+/DFE538TX"), +PCI_ROM(0x1113, 0x1211, "smc1211-1", "SMC EZ10/100"), +PCI_ROM(0x1112, 0x1211, "smc1211", "SMC EZ10/100"), +PCI_ROM(0x1500, 0x1360, "delta8139", "Delta Electronics 8139"), +PCI_ROM(0x4033, 0x1360, "addtron8139", "Addtron Technology 8139"), +PCI_ROM(0x1186, 0x1340, "dfe690txd", "D-Link DFE690TXD"), +PCI_ROM(0x13d1, 0xab06, "fe2000vx", "AboCom FE2000VX"), +PCI_ROM(0x1259, 0xa117, "allied8139", "Allied Telesyn 8139"), +PCI_ROM(0x14ea, 0xab06, "fnw3603tx", "Planex FNW-3603-TX"), +PCI_ROM(0x14ea, 0xab07, "fnw3800tx", "Planex FNW-3800-TX"), +PCI_ROM(0xffff, 0x8139, "clone-rtl8139", "Cloned 8139"), }; -static struct pci_device_id natsemi_nics[] = { -PCI_ROM(0x100b, 0x0020, "dp83815", "DP83815"), +struct pci_driver rtl8139_driver __pci_driver = { + .ids = rtl8139_nics, + .id_count = ( sizeof ( rtl8139_nics ) / sizeof ( rtl8139_nics[0] ) ), + .probe = rtl_probe, + .remove = rtl_remove, }; - -PCI_DRIVER ( natsemi_driver, natsemi_nics, PCI_NO_CLASS ); - -DRIVER ( "NATSEMI", nic_driver, pci_driver, natsemi_driver, - natsemi_probe, natsemi_disable ); From c8f6207e7e720036d855dce95824bbf695400af5 Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Wed, 20 Jun 2007 19:07:04 -0400 Subject: [PATCH 04/33] added polling and transmit. eeprom access still remaining --- src/drivers/net/natsemi.c | 299 +++++++++++++++++++++----------------- 1 file changed, 166 insertions(+), 133 deletions(-) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index 949f8fe4..685b3986 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -36,9 +36,15 @@ struct natsemi_rx { struct natsemi_nic { unsigned short ioaddr; - unsigned short tx_next; + unsigned short tx_cur; + unsigned short tx_dirty; + unsigned short rx_cur; struct natsemi_tx tx[TX_RING_SIZE]; struct natsemi_rx rx[NUM_RX_DESC]; + /* need to add iobuf as we cannot free iobuf->data in close without this + * alternatively substracting sizeof(head) and sizeof(list_head) can also + * give the same.*/ + struct io_buffer *iobuf[NUM_RX_DESC]; struct spi_bit_basher spibit; struct spi_device eeprom; struct nvo_block nvo; @@ -54,7 +60,9 @@ struct natsemi_nic { #define RX_BUF_LEN 8192 /*buffer size should be multiple of 32 */ #define RX_BUF_PAD 4 #define RX_BUF_SIZE 1536 - +#define OWN 0x80000000 +#define DSIZE 0x00000FFF +#define CRC_SIZE 4 /* NATSEMI: Offsets to the device registers. Unlike software-only systems, device drivers interact with complex hardware. @@ -208,12 +216,12 @@ static struct nvo_fragment rtl_nvo_fragments[] = { * * @v NAT NATSEMI NIC */ - void nat_init_eeprom ( struct natsemi_nic *nat ) { + void rtl_init_eeprom ( struct natsemi_nic *rtl ) { int ee9356; int vpd; /* Initialise three-wire bus */ - nat->spibit.basher.op = &rtl_basher_ops; + rtl->spibit.basher.op = &rtl_basher_ops; rtl->spibit.bus.mode = SPI_MODE_THREEWIRE; init_spi_bit_basher ( &rtl->spibit ); @@ -241,17 +249,29 @@ static struct nvo_fragment rtl_nvo_fragments[] = { /** * Reset NIC * - * @v rtl NATSEMI NIC + * @v NATSEMI NIC * * Issues a hardware reset and waits for the reset to complete. */ static void nat_reset ( struct nat_nic *nat ) { + int i; /* Reset chip */ outb ( ChipReset, nat->ioaddr + ChipCmd ); mdelay ( 10 ); - memset ( &nat->tx, 0, sizeof ( nat->tx ) ); - nat->rx.offset = 0; + nat->tx_dirty=0; + nat->tx_cur=0; + for(i=0;itx[i].link=0; + nat->tx[i].cmdsts=0; + nat->tx[i].bufptr=0; + } + nat->rx_cur = 0; + outl(virt_to_bus(&nat->tx[0]),nat->ioaddr+TxRingPtr); + outl(virt_to_bus(&nat->rx[0]), nat->ioaddr + RxRingPtr); + + outl(TxOff|RxOff, nat->ioaddr + ChipCmd); /* Restore PME enable bit */ outl(SavedClkRun, nat->ioaddr + ClkRun); @@ -265,7 +285,7 @@ static void nat_reset ( struct nat_nic *nat ) { */ static int nat_open ( struct net_device *netdev ) { struct natsemi_nic *nat = netdev->priv; - struct io_buffer *iobuf; + //struct io_buffer *iobuf; int i; /* Disable PME: @@ -285,22 +305,38 @@ static int nat_open ( struct net_device *netdev ) { for ( i = 0 ; i < ETH_ALEN ; i++ ) outb ( netdev->ll_addr[i], rtl->ioaddr + MAC0 + i ); */ - /* Set up RX ring */ + + /*Set up the Tx Ring */ + nat->tx_cur=0; + nat->tx_dirty=0; + for (i=0;itx[i].link = virt_to_bus((i+1 < TX_RING_SIZE) ? &nat->tx[i+1] : &nat->tx[0]); + nat->tx[i].cmdsts = 0; + nat->tx[i].bufptr = 0; + } + + + + + + /* Set up RX ring */ + nat->rx_cur=0; for (i=0;iiobuf[i] = alloc_iob ( RX_BUF_SIZE ); + if (!nat->iobuf[i]) return -ENOMEM; nat->rx[i].link = virt_to_bus((i+1 < NUM_RX_DESC) ? &nat->rx[i+1] : &nat->rx[0]); - nat->rx[i].cmdsts = (u32) RX_BUF_SIZE; - nat->rx[i].bufptr = virt_to_bus(iobuf->data); + nat->rx[i].cmdsts = (uint32_t) RX_BUF_SIZE; + nat->rx[i].bufptr = virt_to_bus(nat->iobuf[i]->data); } /* load Receive Descriptor Register */ - outl(virt_to_bus(&nat->rx[0]), ioaddr + RxRingPtr); + outl(virt_to_bus(&nat->rx[0]), nat->ioaddr + RxRingPtr); DBG("Natsemi Rx descriptor loaded with: %X\n",inl(nat->ioaddr+RingPtr)); /* setup Tx ring */ @@ -325,8 +361,8 @@ static int nat_open ( struct net_device *netdev ) { - /*start the receiver and transmitter */ - outl(RxOn|TxOn, nat->ioaddr + ChipCmd); + /*start the receiver */ + outl(RxOn, nat->ioaddr + ChipCmd); return 0; @@ -337,15 +373,18 @@ static int nat_open ( struct net_device *netdev ) { * * @v netdev Net device */ -static void rtl_close ( struct net_device *netdev ) { - struct rtl8139_nic *rtl = netdev->priv; +static void nat_close ( struct net_device *netdev ) { + struct natsemi_nic *nat = netdev->priv; /* Reset the hardware to disable everything in one go */ - rtl_reset ( rtl ); + nat_reset ( nat ); /* Free RX ring */ - free ( rtl->rx.ring ); - rtl->rx.ring = NULL; + for (i=0;iiobuf[i] ); + } } /** @@ -358,24 +397,29 @@ static void rtl_close ( struct net_device *netdev ) { static int natsemi_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { struct natsemi_nic *nat = netdev->priv; - /* Check for space in TX ring */ - if ( nat->tx.iobuf[nat->tx.next] != NULL ) { + /* check for space in TX ring */ + + if (nat->tx[nat->tx_cur].cmdsts !=0) + { printf ( "TX overflow\n" ); return -ENOBUFS; } + /* Pad and align packet */ iob_pad ( iobuf, ETH_ZLEN ); /* Add to TX ring */ - DBG ( "TX id %d at %lx+%x\n", rtl->tx.next, + DBG ( "TX id %d at %lx+%x\n", nat->tx_cur, virt_to_bus ( iobuf->data ), iob_len ( iobuf ) ); - rtl->tx.iobuf[rtl->tx.next] = iobuf; - outl ( virt_to_bus ( iobuf->data ), - rtl->ioaddr + TxAddr0 + 4 * rtl->tx.next ); - outl ( ( ( ( TX_FIFO_THRESH & 0x7e0 ) << 11 ) | iob_len ( iobuf ) ), - rtl->ioaddr + TxStatus0 + 4 * rtl->tx.next ); - rtl->tx.next = ( rtl->tx.next + 1 ) % TX_RING_SIZE; + + nat->tx[nat->tx_cur].bufptr = virt_to_bus(iobuf->data); + nat->tx[nat->tx_cur].cmdsts= (uint32_t) iob_len(iobuf)|OWN; + + nat->tx_cur=(nat->tx_cur+1) % TX_RING_SIZE; + + /*start the transmitter */ + outl(TxOn, nat->ioaddr + ChipCmd); return 0; } @@ -386,98 +430,77 @@ static int natsemi_transmit ( struct net_device *netdev, struct io_buffer *iobuf * @v netdev Network device * @v rx_quota Maximum number of packets to receive */ -static void rtl_poll ( struct net_device *netdev, unsigned int rx_quota ) { - struct rtl8139_nic *rtl = netdev->priv; +static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { + struct natsemi_nic *nat = netdev->priv; unsigned int status; - unsigned int tsad; unsigned int rx_status; unsigned int rx_len; struct io_buffer *rx_iob; - int wrapped_len; int i; - /* Acknowledge interrupts */ - status = inw ( rtl->ioaddr + IntrStatus ); - if ( ! status ) - return; - outw ( status, rtl->ioaddr + IntrStatus ); - - /* Handle TX completions */ - tsad = inw ( rtl->ioaddr + TxSummary ); - for ( i = 0 ; i < TX_RING_SIZE ; i++ ) { - if ( ( rtl->tx.iobuf[i] != NULL ) && ( tsad & ( 1 << i ) ) ) { - DBG ( "TX id %d complete\n", i ); - netdev_tx_complete ( netdev, rtl->tx.iobuf[i] ); - rtl->tx.iobuf[i] = NULL; + + /* check the status of packets given to card for transmission */ + for ( i = 0 ; i < TX_RING_SIZE ; i++ ) + { + status=bus_to_virt(nat->tx[nat->tx_dirty].cmdsts); + /* check if current packet has been transmitted or not */ + if(status & own) + break; + /* Check if any errors in transmission */ + if (! (status & DescPktOK)) + { + printf("Error in sending Packet with data: %s\n and status:%X\n", + bus_to_virt(nat->tx[nat->tx_dirty].bufptr), + status); } + else + { + DBG("Success in transmitting Packet with data: %s", + bus_to_virt(nat->tx[nat->tx_dirty].bufptr)); + } + /* setting cmdsts zero, indicating that it can be reused */ + nat->tx[nat->tx_dirty].cmdsts=0; + nat->tx_dirty=(nat->tx_dirty +1) % TX_RING_SIZE; } - + + + rx_status=bus_to_virt(nat->rx[nat->rx_cur].cmdsts); /* Handle received packets */ - while ( rx_quota && ! ( inw ( rtl->ioaddr + ChipCmd ) & RxBufEmpty ) ){ - rx_status = * ( ( uint16_t * ) - ( rtl->rx.ring + rtl->rx.offset ) ); - rx_len = * ( ( uint16_t * ) - ( rtl->rx.ring + rtl->rx.offset + 2 ) ); - if ( rx_status & RxOK ) { - DBG ( "RX packet at offset %x+%x\n", rtl->rx.offset, - rx_len ); + while (rx_quota && (rx_status & OWN)) + { + rx_len= (rx_status & DSIZE) - CRC_SIZE; - rx_iob = alloc_iob ( rx_len ); - if ( ! rx_iob ) { - /* Leave packet for next call to poll() */ - break; - } - - wrapped_len = ( ( rtl->rx.offset + 4 + rx_len ) - - RX_BUF_LEN ); - if ( wrapped_len < 0 ) - wrapped_len = 0; - - memcpy ( iob_put ( rx_iob, rx_len - wrapped_len ), - rtl->rx.ring + rtl->rx.offset + 4, - rx_len - wrapped_len ); - memcpy ( iob_put ( rx_iob, wrapped_len ), - rtl->rx.ring, wrapped_len ); - - netdev_rx ( netdev, rx_iob ); - rx_quota--; - } else { - DBG ( "RX bad packet (status %#04x len %d)\n", - rx_status, rx_len ); + /*check for the corrupt packet */ + if((rx_status & (DescMore|DescPktOK|RxTooLong)) != DescPktOK) + { + printf("natsemi_poll: Corrupted packet received, + buffer status = %X\n",rx_status); } - rtl->rx.offset = ( ( ( rtl->rx.offset + 4 + rx_len + 3 ) & ~3 ) - % RX_BUF_LEN ); - outw ( rtl->rx.offset - 16, rtl->ioaddr + RxBufPtr ); + else + { + rx_iob = alloc_iob(rx_len); + if(!rx_iob) + /* leave packet for next call to poll*/ + return; + memcpy(iob_put(rx_iob,rx_len), + nat->rx[nat->rx_cur].bufptr,rxlen); + /* add to the receive queue. */ + netdev_rx(netdev,rx_iob); + rx_quota--; + } + nat->rx[nat->rx_cur].cmdsts = RX_BUF_SIZE; + nat->rx_cur=(nat->rx_cur+1) % NUM_RX_DESC; } -} -#if 0 -static void rtl_irq(struct nic *nic, irq_action_t action) -{ - unsigned int mask; - /* Bit of a guess as to which interrupts we should allow */ - unsigned int interested = ROK | RER | RXOVW | FOVW | SERR; - switch ( action ) { - case DISABLE : - case ENABLE : - mask = inw(rtl->ioaddr + IntrMask); - mask = mask & ~interested; - if ( action == ENABLE ) mask = mask | interested; - outw(mask, rtl->ioaddr + IntrMask); - break; - case FORCE : - /* Apparently writing a 1 to this read-only bit of a - * read-only and otherwise unrelated register will - * force an interrupt. If you ever want to see how - * not to write a datasheet, read the one for the - * RTL8139... - */ - outb(EROK, rtl->ioaddr + RxEarlyStatus); - break; - } -} -#endif + /* re-enable the potentially idle receive state machine */ + outl(RxOn, ioaddr + ChipCmd); +} + + + + + /** * Probe PCI device @@ -492,6 +515,7 @@ static int nat_probe ( struct pci_device *pci, struct natsemi_nic *nat = NULL; int registered_netdev = 0; int rc; + uint32_t advertising; /* Fix up PCI device */ adjust_pci_device ( pci ); @@ -517,6 +541,26 @@ static int nat_probe ( struct pci_device *pci, */ + + /* mdio routine of etherboot-5.4.0 natsemi driver has been removed and + * statement to read from MII transceiver control section is used directly + */ + + advertising = inl(nat->ioaddr + 0x80 + (4<<2)) & 0xffff; + { + uint32_t chip_config = inl(ioaddr + ChipConfig); + DBG("%s: Transceiver default autoneg. %s 10 %s %s duplex.\n", + pci->driver_name, + chip_config & 0x2000 ? "enabled, advertise" : "disabled, force", + chip_config & 0x4000 ? "0" : "", + chip_config & 0x8000 ? "full" : "half"); + } + DBG("%s: Transceiver status %hX advertising %hX\n",pci->driver_name, (int)inl(nat->ioaddr + 0x84), advertising); + + + + + /* Point to NIC specific routines */ netdev->open = nat_open; netdev->close = nat_close; @@ -542,7 +586,7 @@ static int nat_probe ( struct pci_device *pci, err: /* Disable NIC */ if ( nat ) - nat_reset ( rtl ); + nat_reset ( nat ); if ( registered_netdev ) unregister_netdev ( netdev ); /* Free net device */ @@ -555,37 +599,26 @@ static int nat_probe ( struct pci_device *pci, * * @v pci PCI device */ -static void rtl_remove ( struct pci_device *pci ) { +static void nat_remove ( struct pci_device *pci ) { struct net_device *netdev = pci_get_drvdata ( pci ); - struct rtl8139_nic *rtl = netdev->priv; - + struct natsemi_nic *nat = netdev->priv; +/* TODO if ( rtl->nvo.nvs ) nvo_unregister ( &rtl->nvo ); + */ unregister_netdev ( netdev ); - rtl_reset ( rtl ); + nat_reset ( nat ); free_netdev ( netdev ); } -static struct pci_device_id rtl8139_nics[] = { -PCI_ROM(0x10ec, 0x8129, "rtl8129", "Realtek 8129"), -PCI_ROM(0x10ec, 0x8139, "rtl8139", "Realtek 8139"), -PCI_ROM(0x10ec, 0x8138, "rtl8139b", "Realtek 8139B"), -PCI_ROM(0x1186, 0x1300, "dfe538", "DFE530TX+/DFE538TX"), -PCI_ROM(0x1113, 0x1211, "smc1211-1", "SMC EZ10/100"), -PCI_ROM(0x1112, 0x1211, "smc1211", "SMC EZ10/100"), -PCI_ROM(0x1500, 0x1360, "delta8139", "Delta Electronics 8139"), -PCI_ROM(0x4033, 0x1360, "addtron8139", "Addtron Technology 8139"), -PCI_ROM(0x1186, 0x1340, "dfe690txd", "D-Link DFE690TXD"), -PCI_ROM(0x13d1, 0xab06, "fe2000vx", "AboCom FE2000VX"), -PCI_ROM(0x1259, 0xa117, "allied8139", "Allied Telesyn 8139"), -PCI_ROM(0x14ea, 0xab06, "fnw3603tx", "Planex FNW-3603-TX"), -PCI_ROM(0x14ea, 0xab07, "fnw3800tx", "Planex FNW-3800-TX"), -PCI_ROM(0xffff, 0x8139, "clone-rtl8139", "Cloned 8139"), +static struct pci_device_id natsemi_nics[] = { + PCI_ROM(0x100b, 0x0020, "dp83815", "DP83815"), + }; -struct pci_driver rtl8139_driver __pci_driver = { - .ids = rtl8139_nics, - .id_count = ( sizeof ( rtl8139_nics ) / sizeof ( rtl8139_nics[0] ) ), - .probe = rtl_probe, - .remove = rtl_remove, +struct pci_driver natsemi_driver __pci_driver = { + .ids = natsemi_nics, + .id_count = ( sizeof ( natsemi_nics ) / sizeof ( natsemi_nics[0] ) ), + .probe = nat_probe, + .remove = nat_remove, }; From 99c680f74378ea080931e3e3af25c797c0b88186 Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Wed, 20 Jun 2007 19:46:22 -0400 Subject: [PATCH 05/33] same as before, but now compiling natsemi --- src/drivers/net/natsemi.c | 53 +++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index 685b3986..42ac1d3f 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -122,7 +122,7 @@ enum ChipCmdBits { RxOn = 0x04, TxOff = 0x02, TxOn = 0x01 -} +}; /* Bits in the RxMode register. */ @@ -163,7 +163,7 @@ enum desc_status_bits { static uint32_t SavedClkRun; - +/* TODO static const uint8_t rtl_ee_bits[] = { [SPI_BIT_SCLK] = EE_SK, [SPI_BIT_MOSI] = EE_DI, @@ -199,7 +199,7 @@ static struct bit_basher_operations rtl_basher_ops = { .read = rtl_spi_read_bit, .write = rtl_spi_write_bit, }; - +*/ /** Portion of EEPROM available for non-volatile stored options * * We use offset 0x40 (i.e. address 0x20), length 0x40. This block is @@ -216,16 +216,17 @@ static struct nvo_fragment rtl_nvo_fragments[] = { * * @v NAT NATSEMI NIC */ +/* TODO void rtl_init_eeprom ( struct natsemi_nic *rtl ) { int ee9356; int vpd; - /* Initialise three-wire bus */ + // Initialise three-wire bus rtl->spibit.basher.op = &rtl_basher_ops; rtl->spibit.bus.mode = SPI_MODE_THREEWIRE; init_spi_bit_basher ( &rtl->spibit ); - /* Detect EEPROM type and initialise three-wire device */ + //Detect EEPROM type and initialise three-wire device ee9356 = ( inw ( rtl->ioaddr + RxConfig ) & Eeprom9356 ); if ( ee9356 ) { DBG ( "EEPROM is an AT93C56\n" ); @@ -236,7 +237,7 @@ static struct nvo_fragment rtl_nvo_fragments[] = { } rtl->eeprom.bus = &rtl->spibit.bus; - /* Initialise space for non-volatile options, if available */ + // Initialise space for non-volatile options, if available vpd = ( inw ( rtl->ioaddr + Config1 ) & VPDEnable ); if ( vpd ) { DBG ( "EEPROM in use for VPD; cannot use for options\n" ); @@ -245,7 +246,7 @@ static struct nvo_fragment rtl_nvo_fragments[] = { rtl->nvo.fragments = rtl_nvo_fragments; } } - +*/ /** * Reset NIC * @@ -253,11 +254,11 @@ static struct nvo_fragment rtl_nvo_fragments[] = { * * Issues a hardware reset and waits for the reset to complete. */ -static void nat_reset ( struct nat_nic *nat ) { +static void nat_reset ( struct natsemi_nic *nat ) { int i; /* Reset chip */ - outb ( ChipReset, nat->ioaddr + ChipCmd ); + outl ( ChipReset, nat->ioaddr + ChipCmd ); mdelay ( 10 ); nat->tx_dirty=0; nat->tx_cur=0; @@ -287,6 +288,7 @@ static int nat_open ( struct net_device *netdev ) { struct natsemi_nic *nat = netdev->priv; //struct io_buffer *iobuf; int i; + uint32_t tx_config,rx_config; /* Disable PME: * The PME bit is initialized from the EEPROM contents. @@ -337,11 +339,11 @@ static int nat_open ( struct net_device *netdev ) { /* load Receive Descriptor Register */ outl(virt_to_bus(&nat->rx[0]), nat->ioaddr + RxRingPtr); - DBG("Natsemi Rx descriptor loaded with: %X\n",inl(nat->ioaddr+RingPtr)); + DBG("Natsemi Rx descriptor loaded with: %X\n",(unsigned int)inl(nat->ioaddr+RxRingPtr)); /* setup Tx ring */ outl(virt_to_bus(&nat->tx[0]),nat->ioaddr+TxRingPtr); - DBG("Natsemi Tx descriptor loaded with: %X\n",inl(nat->ioaddr+TxRingPtr)); + DBG("Natsemi Tx descriptor loaded with: %X\n",(unsigned int)inl(nat->ioaddr+TxRingPtr)); /* Enables RX */ outl(RxFilterEnable|AcceptBroadcast|AcceptAllMulticast|AcceptMyPhys, nat->ioaddr+RxFilterAddr); @@ -375,6 +377,8 @@ static int nat_open ( struct net_device *netdev ) { */ static void nat_close ( struct net_device *netdev ) { struct natsemi_nic *nat = netdev->priv; + int i; + /* Reset the hardware to disable everything in one go */ nat_reset ( nat ); @@ -394,7 +398,7 @@ static void nat_close ( struct net_device *netdev ) { * @v iobuf I/O buffer * @ret rc Return status code */ -static int natsemi_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { +static int nat_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { struct natsemi_nic *nat = netdev->priv; /* check for space in TX ring */ @@ -432,7 +436,7 @@ static int natsemi_transmit ( struct net_device *netdev, struct io_buffer *iobuf */ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { struct natsemi_nic *nat = netdev->priv; - unsigned int status; + uint32_t status; unsigned int rx_status; unsigned int rx_len; struct io_buffer *rx_iob; @@ -442,21 +446,20 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { /* check the status of packets given to card for transmission */ for ( i = 0 ; i < TX_RING_SIZE ; i++ ) { - status=bus_to_virt(nat->tx[nat->tx_dirty].cmdsts); + status=(uint32_t)bus_to_virt(nat->tx[nat->tx_dirty].cmdsts); /* check if current packet has been transmitted or not */ - if(status & own) + if(status & OWN) break; /* Check if any errors in transmission */ if (! (status & DescPktOK)) { printf("Error in sending Packet with data: %s\n and status:%X\n", - bus_to_virt(nat->tx[nat->tx_dirty].bufptr), - status); + (char *)bus_to_virt(nat->tx[nat->tx_dirty].bufptr),(unsigned int)status); } else { DBG("Success in transmitting Packet with data: %s", - bus_to_virt(nat->tx[nat->tx_dirty].bufptr)); + (char *)bus_to_virt(nat->tx[nat->tx_dirty].bufptr)); } /* setting cmdsts zero, indicating that it can be reused */ nat->tx[nat->tx_dirty].cmdsts=0; @@ -464,7 +467,7 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { } - rx_status=bus_to_virt(nat->rx[nat->rx_cur].cmdsts); + rx_status=(unsigned int)bus_to_virt(nat->rx[nat->rx_cur].cmdsts); /* Handle received packets */ while (rx_quota && (rx_status & OWN)) { @@ -473,8 +476,8 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { /*check for the corrupt packet */ if((rx_status & (DescMore|DescPktOK|RxTooLong)) != DescPktOK) { - printf("natsemi_poll: Corrupted packet received, - buffer status = %X\n",rx_status); + printf("natsemi_poll: Corrupted packet received, " + "buffer status = %X\n",rx_status); } else { @@ -483,7 +486,7 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { /* leave packet for next call to poll*/ return; memcpy(iob_put(rx_iob,rx_len), - nat->rx[nat->rx_cur].bufptr,rxlen); + nat->rx[nat->rx_cur].bufptr,rx_len); /* add to the receive queue. */ netdev_rx(netdev,rx_iob); rx_quota--; @@ -494,7 +497,7 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { /* re-enable the potentially idle receive state machine */ - outl(RxOn, ioaddr + ChipCmd); + outl(RxOn, nat->ioaddr + ChipCmd); } @@ -548,14 +551,14 @@ static int nat_probe ( struct pci_device *pci, advertising = inl(nat->ioaddr + 0x80 + (4<<2)) & 0xffff; { - uint32_t chip_config = inl(ioaddr + ChipConfig); + uint32_t chip_config = inl(nat->ioaddr + ChipConfig); DBG("%s: Transceiver default autoneg. %s 10 %s %s duplex.\n", pci->driver_name, chip_config & 0x2000 ? "enabled, advertise" : "disabled, force", chip_config & 0x4000 ? "0" : "", chip_config & 0x8000 ? "full" : "half"); } - DBG("%s: Transceiver status %hX advertising %hX\n",pci->driver_name, (int)inl(nat->ioaddr + 0x84), advertising); + DBG("%s: Transceiver status %hX advertising %hX\n",pci->driver_name, (int)inl(nat->ioaddr + 0x84),(unsigned int) advertising); From 9e962c3a011b8ef78a017a76e35bf6905eaa03be Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Mon, 25 Jun 2007 21:24:34 -0400 Subject: [PATCH 06/33] natsemi now needs eeprom access --- src/drivers/net/natsemi.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index 42ac1d3f..3bd8b059 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -446,7 +446,8 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { /* check the status of packets given to card for transmission */ for ( i = 0 ; i < TX_RING_SIZE ; i++ ) { - status=(uint32_t)bus_to_virt(nat->tx[nat->tx_dirty].cmdsts); + //status=(uint32_t)bus_to_virt(nat->tx[nat->tx_dirty].cmdsts); + status=(uint32_t)nat->tx[nat->tx_dirty].cmdsts; /* check if current packet has been transmitted or not */ if(status & OWN) break; @@ -454,12 +455,12 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { if (! (status & DescPktOK)) { printf("Error in sending Packet with data: %s\n and status:%X\n", - (char *)bus_to_virt(nat->tx[nat->tx_dirty].bufptr),(unsigned int)status); + (char *)nat->tx[nat->tx_dirty].bufptr,(unsigned int)status); } else { DBG("Success in transmitting Packet with data: %s", - (char *)bus_to_virt(nat->tx[nat->tx_dirty].bufptr)); + (char *)nat->tx[nat->tx_dirty].bufptr); } /* setting cmdsts zero, indicating that it can be reused */ nat->tx[nat->tx_dirty].cmdsts=0; @@ -467,7 +468,8 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { } - rx_status=(unsigned int)bus_to_virt(nat->rx[nat->rx_cur].cmdsts); + //rx_status=(unsigned int)bus_to_virt(nat->rx[nat->rx_cur].cmdsts); + rx_status=(unsigned int)nat->rx[nat->rx_cur].cmdsts; /* Handle received packets */ while (rx_quota && (rx_status & OWN)) { @@ -477,7 +479,8 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { if((rx_status & (DescMore|DescPktOK|RxTooLong)) != DescPktOK) { printf("natsemi_poll: Corrupted packet received, " - "buffer status = %X\n",rx_status); + "buffer status = %X ^ %X \n",rx_status, + (unsigned int) nat->rx[nat->rx_cur].cmdsts); } else { @@ -493,6 +496,8 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { } nat->rx[nat->rx_cur].cmdsts = RX_BUF_SIZE; nat->rx_cur=(nat->rx_cur+1) % NUM_RX_DESC; + //rx_status=(unsigned int)bus_to_virt(nat->rx[nat->rx_cur].cmdsts); + rx_status=(unsigned int)nat->rx[nat->rx_cur].cmdsts; } From 4a73631106887f8e101b71b5aee72a1af70b8fe6 Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Tue, 26 Jun 2007 17:20:34 -0400 Subject: [PATCH 07/33] added eeprom from rtl8139 but not working --- src/drivers/net/natsemi.c | 108 +++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 55 deletions(-) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index 3bd8b059..0b335594 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -149,64 +149,62 @@ enum desc_status_bits { -/* EEPROM access */ -#define EE_M1 0x80 /* Mode select bit 1 */ -#define EE_M0 0x40 /* Mode select bit 0 */ +/* EEPROM access , values are devices specific*/ +//#define EE_M1 0x80 /* Mode select bit 1 */ +//#define EE_M0 0x40 /* Mode select bit 0 */ #define EE_CS 0x08 /* EEPROM chip select */ #define EE_SK 0x04 /* EEPROM shift clock */ -#define EE_DI 0x02 /* Data in */ -#define EE_DO 0x01 /* Data out */ +#define EE_DI 0x01 /* Data in */ +#define EE_DO 0x02 /* Data out */ /* Offsets within EEPROM (these are word offsets) */ #define EE_MAC 7 - +#define EE_REG EECtrl static uint32_t SavedClkRun; -/* TODO -static const uint8_t rtl_ee_bits[] = { +static const uint8_t nat_ee_bits[] = { [SPI_BIT_SCLK] = EE_SK, [SPI_BIT_MOSI] = EE_DI, [SPI_BIT_MISO] = EE_DO, - [SPI_BIT_SS(0)] = ( EE_CS | EE_M1 ), + [SPI_BIT_SS(0)] = EE_CS, }; -static int rtl_spi_read_bit ( struct bit_basher *basher, +static int nat_spi_read_bit ( struct bit_basher *basher, unsigned int bit_id ) { - struct rtl8139_nic *rtl = container_of ( basher, struct rtl8139_nic, + struct natsemi_nic *nat = container_of ( basher, struct natsemi_nic, spibit.basher ); - uint8_t mask = rtl_ee_bits[bit_id]; + uint8_t mask = nat_ee_bits[bit_id]; uint8_t eereg; - eereg = inb ( rtl->ioaddr + Cfg9346 ); + eereg = inb ( nat->ioaddr + EE_REG); return ( eereg & mask ); } -static void rtl_spi_write_bit ( struct bit_basher *basher, +static void nat_spi_write_bit ( struct bit_basher *basher, unsigned int bit_id, unsigned long data ) { - struct rtl8139_nic *rtl = container_of ( basher, struct rtl8139_nic, + struct natsemi_nic *nat = container_of ( basher, struct natsemi_nic, spibit.basher ); - uint8_t mask = rtl_ee_bits[bit_id]; + uint8_t mask = nat_ee_bits[bit_id]; uint8_t eereg; - eereg = inb ( rtl->ioaddr + Cfg9346 ); + eereg = inb ( nat->ioaddr + EE_REG ); eereg &= ~mask; eereg |= ( data & mask ); - outb ( eereg, rtl->ioaddr + Cfg9346 ); + outb ( eereg, nat->ioaddr + EE_REG); } -static struct bit_basher_operations rtl_basher_ops = { - .read = rtl_spi_read_bit, - .write = rtl_spi_write_bit, +static struct bit_basher_operations nat_basher_ops = { + .read = nat_spi_read_bit, + .write = nat_spi_write_bit, }; -*/ /** Portion of EEPROM available for non-volatile stored options * * We use offset 0x40 (i.e. address 0x20), length 0x40. This block is * marked as VPD in the rtl8139 datasheets, so we use it only if we * detect that the card is not supporting VPD. */ -static struct nvo_fragment rtl_nvo_fragments[] = { +static struct nvo_fragment nat_nvo_fragments[] = { { 0x20, 0x40 }, { 0, 0 } }; @@ -216,37 +214,29 @@ static struct nvo_fragment rtl_nvo_fragments[] = { * * @v NAT NATSEMI NIC */ -/* TODO - void rtl_init_eeprom ( struct natsemi_nic *rtl ) { + void nat_init_eeprom ( struct natsemi_nic *nat ) { int ee9356; int vpd; // Initialise three-wire bus - rtl->spibit.basher.op = &rtl_basher_ops; - rtl->spibit.bus.mode = SPI_MODE_THREEWIRE; - init_spi_bit_basher ( &rtl->spibit ); + nat->spibit.basher.op = &nat_basher_ops; + nat->spibit.bus.mode = SPI_MODE_THREEWIRE; + init_spi_bit_basher ( &nat->spibit ); - //Detect EEPROM type and initialise three-wire device - ee9356 = ( inw ( rtl->ioaddr + RxConfig ) & Eeprom9356 ); - if ( ee9356 ) { - DBG ( "EEPROM is an AT93C56\n" ); - init_at93c56 ( &rtl->eeprom, 16 ); - } else { - DBG ( "EEPROM is an AT93C46\n" ); - init_at93c46 ( &rtl->eeprom, 16 ); - } - rtl->eeprom.bus = &rtl->spibit.bus; + DBG ( "EEPROM is an AT93C46\n" ); + init_at93c46 ( &nat->eeprom, 16 ); + nat->eeprom.bus = &nat->spibit.bus; // Initialise space for non-volatile options, if available - vpd = ( inw ( rtl->ioaddr + Config1 ) & VPDEnable ); - if ( vpd ) { - DBG ( "EEPROM in use for VPD; cannot use for options\n" ); - } else { - rtl->nvo.nvs = &rtl->eeprom.nvs; - rtl->nvo.fragments = rtl_nvo_fragments; - } + //vpd = ( inw ( rtl->ioaddr + Config1 ) & VPDEnable ); + //if ( vpd ) { + // DBG ( "EEPROM in use for VPD; cannot use for options\n" ); + //} else { +// nat->nvo.nvs = &nat->eeprom.nvs; +// nat->nvo.fragments = nat_nvo_fragments; +// } } -*/ + /** * Reset NIC * @@ -303,10 +293,14 @@ static int nat_open ( struct net_device *netdev ) { /* Program the MAC address TODO enable this comment */ - /* - for ( i = 0 ; i < ETH_ALEN ; i++ ) - outb ( netdev->ll_addr[i], rtl->ioaddr + MAC0 + i ); - */ + + for ( i = 0 ; i < ETH_ALEN ; i+=2 ) + { + outl(i,nat->ioaddr+RxFilterAddr); + outw ( netdev->ll_addr[i] + (netdev->ll_addr[i+1]<<8), nat->ioaddr +RxFilterData); + DBG("MAC address %d octet :%X %X\n",i,netdev->ll_addr[i],netdev->ll_addr[i+1]); + } + /*Set up the Tx Ring */ @@ -542,12 +536,16 @@ static int nat_probe ( struct pci_device *pci, /* Reset the NIC, set up EEPROM access and read MAC address */ nat_reset ( nat ); - /* commenitng two line below. Have to be included in final natsemi.c TODO*/ - /* - nat_init_eeprom ( rtl ); + nat_init_eeprom ( nat ); nvs_read ( &nat->eeprom.nvs, EE_MAC, netdev->ll_addr, ETH_ALEN ); - - */ + uint8_t eetest[12]; + int i; + nvs_read ( &nat->eeprom.nvs, 6, eetest,8 ); + for (i=0;i<8;i++) + { + printf("%d word : %X\n",i,eetest[i]); + } + /* mdio routine of etherboot-5.4.0 natsemi driver has been removed and From 623d10c66ff86b7606a735177490427f2e650458 Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Sat, 30 Jun 2007 19:30:41 -0400 Subject: [PATCH 08/33] debugging natsemi.c --- src/config.h | 2 +- src/drivers/bitbash/spi_bit.c | 7 +++- src/drivers/net/natsemi.c | 70 ++++++++++++++++++++++------------- 3 files changed, 51 insertions(+), 28 deletions(-) diff --git a/src/config.h b/src/config.h index 55409b0e..09344545 100644 --- a/src/config.h +++ b/src/config.h @@ -18,7 +18,7 @@ */ #define CONSOLE_FIRMWARE /* Default BIOS console */ -#undef CONSOLE_SERIAL /* Serial port */ +#define CONSOLE_SERIAL /* Serial port */ #undef CONSOLE_DIRECT_VGA /* Direct access to VGA card */ #undef CONSOLE_BTEXT /* Who knows what this does? */ #undef CONSOLE_PC_KBD /* Direct access to PC keyboard */ diff --git a/src/drivers/bitbash/spi_bit.c b/src/drivers/bitbash/spi_bit.c index e2175d60..fe583854 100644 --- a/src/drivers/bitbash/spi_bit.c +++ b/src/drivers/bitbash/spi_bit.c @@ -96,13 +96,18 @@ static void spi_bit_transfer ( struct spi_bit_basher *spibit, DBG ( "Transferring %d bits in mode %x\n", len, bus->mode ); +<<<<<<< HEAD:src/drivers/bitbash/spi_bit.c for ( step = 0 ; step < ( len * 2 ) ; step++ ) { /* Calculate byte offset and byte mask */ bit_offset = ( ( endianness == SPI_BIT_BIG_ENDIAN ) ? ( len - ( step / 2 ) - 1 ) : ( step / 2 ) ); byte_offset = ( bit_offset / 8 ); byte_mask = ( 1 << ( bit_offset % 8 ) ); - +======= +>>>>>>> debugging natsemi.c:src/drivers/bitbash/spi_bit.c +<<<<<<< HEAD:src/drivers/bitbash/spi_bit.c +======= +>>>>>>> debugging natsemi.c:src/drivers/bitbash/spi_bit.c /* Shift data in or out */ if ( sclk == cpha ) { const uint8_t *byte; diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index 0b335594..02bedfc3 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -205,7 +205,7 @@ static struct bit_basher_operations nat_basher_ops = { * detect that the card is not supporting VPD. */ static struct nvo_fragment nat_nvo_fragments[] = { - { 0x20, 0x40 }, + { 0x0f, 0x40 }, { 0, 0 } }; @@ -232,8 +232,8 @@ static struct nvo_fragment nat_nvo_fragments[] = { //if ( vpd ) { // DBG ( "EEPROM in use for VPD; cannot use for options\n" ); //} else { -// nat->nvo.nvs = &nat->eeprom.nvs; -// nat->nvo.fragments = nat_nvo_fragments; + nat->nvo.nvs = &nat->eeprom.nvs; + nat->nvo.fragments = nat_nvo_fragments; // } } @@ -293,12 +293,22 @@ static int nat_open ( struct net_device *netdev ) { /* Program the MAC address TODO enable this comment */ - + uint8_t last=0; + uint8_t last1=0; for ( i = 0 ; i < ETH_ALEN ; i+=2 ) { + // DBG("MAC address %d octet :%X %X\n",i,netdev->ll_addr[i],netdev->ll_addr[i+1]); + // DBG("LAst = %d last1 = %d\n",last,last1); outl(i,nat->ioaddr+RxFilterAddr); + last1=netdev->ll_addr[i]>>7; + netdev->ll_addr[i]=netdev->ll_addr[i]<<1|last; + last=(netdev->ll_addr[i+1]>>7); + netdev->ll_addr[i+1]=(netdev->ll_addr[i+1]<<1)+last1; + outw ( netdev->ll_addr[i] + (netdev->ll_addr[i+1]<<8), nat->ioaddr +RxFilterData); - DBG("MAC address %d octet :%X %X\n",i,netdev->ll_addr[i],netdev->ll_addr[i+1]); + //outw ( (fullbyte>>8)+(fullbyte<<8), nat->ioaddr +RxFilterData); + // DBG("MAC address %d octet :%X %X\n",i,netdev->ll_addr[i],netdev->ll_addr[i+1]); + // DBG("LAst = %d last1 = %d\n",last,last1); } @@ -403,17 +413,20 @@ static int nat_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { return -ENOBUFS; } + //DBG_HD(iobuf->data,iob_len(iobuf)); /* Pad and align packet */ iob_pad ( iobuf, ETH_ZLEN ); /* Add to TX ring */ DBG ( "TX id %d at %lx+%x\n", nat->tx_cur, - virt_to_bus ( iobuf->data ), iob_len ( iobuf ) ); + virt_to_bus ( &iobuf->data ), iob_len ( iobuf ) ); nat->tx[nat->tx_cur].bufptr = virt_to_bus(iobuf->data); nat->tx[nat->tx_cur].cmdsts= (uint32_t) iob_len(iobuf)|OWN; + + //DBG_HD(bus_to_virt(nat->tx[nat->tx_cur].bufptr), iob_len(iobuf) ); nat->tx_cur=(nat->tx_cur+1) % TX_RING_SIZE; /*start the transmitter */ @@ -430,40 +443,46 @@ static int nat_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { */ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { struct natsemi_nic *nat = netdev->priv; - uint32_t status; + unsigned int status; unsigned int rx_status; unsigned int rx_len; struct io_buffer *rx_iob; int i; - /* check the status of packets given to card for transmission */ - for ( i = 0 ; i < TX_RING_SIZE ; i++ ) + i=nat->tx_dirty; + while(i!=nat->tx_cur) { //status=(uint32_t)bus_to_virt(nat->tx[nat->tx_dirty].cmdsts); - status=(uint32_t)nat->tx[nat->tx_dirty].cmdsts; + status=nat->tx[nat->tx_dirty].cmdsts; + DBG("value of tx_dirty = %d tx_cur=%d status=%X\n", + nat->tx_dirty,nat->tx_cur,status); + /* check if current packet has been transmitted or not */ if(status & OWN) break; /* Check if any errors in transmission */ if (! (status & DescPktOK)) { - printf("Error in sending Packet with data: %s\n and status:%X\n", - (char *)nat->tx[nat->tx_dirty].bufptr,(unsigned int)status); + printf("Error in sending Packet status:%X\n", + (unsigned int)status); } else { - DBG("Success in transmitting Packet with data: %s", - (char *)nat->tx[nat->tx_dirty].bufptr); + DBG("Success in transmitting Packet with data\n"); + // DBG_HD(&nat->tx[nat->tx_dirty].bufptr,130); } /* setting cmdsts zero, indicating that it can be reused */ nat->tx[nat->tx_dirty].cmdsts=0; nat->tx_dirty=(nat->tx_dirty +1) % TX_RING_SIZE; + i=(i+1) % TX_RING_SIZE; + } //rx_status=(unsigned int)bus_to_virt(nat->rx[nat->rx_cur].cmdsts); rx_status=(unsigned int)nat->rx[nat->rx_cur].cmdsts; + //DBG ("Receiver Status = %x\n",rx_status); /* Handle received packets */ while (rx_quota && (rx_status & OWN)) { @@ -483,7 +502,10 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { /* leave packet for next call to poll*/ return; memcpy(iob_put(rx_iob,rx_len), - nat->rx[nat->rx_cur].bufptr,rx_len); + bus_to_virt(nat->rx[nat->rx_cur].bufptr),rx_len); + //DBG_HD(bus_to_virt(nat->rx[nat->rx_cur].bufptr),rx_len); + + DBG("received packet"); /* add to the receive queue. */ netdev_rx(netdev,rx_iob); rx_quota--; @@ -538,14 +560,10 @@ static int nat_probe ( struct pci_device *pci, nat_reset ( nat ); nat_init_eeprom ( nat ); nvs_read ( &nat->eeprom.nvs, EE_MAC, netdev->ll_addr, ETH_ALEN ); - uint8_t eetest[12]; + uint8_t eetest[128]; int i; - nvs_read ( &nat->eeprom.nvs, 6, eetest,8 ); - for (i=0;i<8;i++) - { - printf("%d word : %X\n",i,eetest[i]); - } - + nvs_read ( &nat->eeprom.nvs, 0, eetest,128 ); + // DBG_HD(&eetest,128); /* mdio routine of etherboot-5.4.0 natsemi driver has been removed and @@ -580,12 +598,12 @@ static int nat_probe ( struct pci_device *pci, /* Register non-volatile storagei * uncomment lines below in final version*/ - /* - if ( rtl->nvo.nvs ) { - if ( ( rc = nvo_register ( &rtl->nvo ) ) != 0 ) + + if ( nat->nvo.nvs ) { + if ( ( rc = nvo_register ( &nat->nvo ) ) != 0 ) goto err; } - */ + return 0; From 0c324caecf3ebc3c330ee1ef9b542347256611d8 Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Sat, 30 Jun 2007 22:23:19 -0400 Subject: [PATCH 09/33] free_netdev -> netdev_put --- src/drivers/net/natsemi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index 02bedfc3..8bd63bb9 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -614,7 +614,7 @@ static int nat_probe ( struct pci_device *pci, if ( registered_netdev ) unregister_netdev ( netdev ); /* Free net device */ - free_netdev ( netdev ); + netdev_put ( netdev ); return rc; } @@ -632,7 +632,7 @@ static void nat_remove ( struct pci_device *pci ) { */ unregister_netdev ( netdev ); nat_reset ( nat ); - free_netdev ( netdev ); + netdev_put ( netdev ); } static struct pci_device_id natsemi_nics[] = { From c6d0ef34787104d6011ff2a1f7ed8a8c726e9d4d Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Sun, 1 Jul 2007 17:11:22 -0400 Subject: [PATCH 10/33] added endianness to natsemi. --- src/drivers/bitbash/spi_bit.c | 7 +------ src/drivers/net/natsemi.c | 1 + 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/drivers/bitbash/spi_bit.c b/src/drivers/bitbash/spi_bit.c index fe583854..e2175d60 100644 --- a/src/drivers/bitbash/spi_bit.c +++ b/src/drivers/bitbash/spi_bit.c @@ -96,18 +96,13 @@ static void spi_bit_transfer ( struct spi_bit_basher *spibit, DBG ( "Transferring %d bits in mode %x\n", len, bus->mode ); -<<<<<<< HEAD:src/drivers/bitbash/spi_bit.c for ( step = 0 ; step < ( len * 2 ) ; step++ ) { /* Calculate byte offset and byte mask */ bit_offset = ( ( endianness == SPI_BIT_BIG_ENDIAN ) ? ( len - ( step / 2 ) - 1 ) : ( step / 2 ) ); byte_offset = ( bit_offset / 8 ); byte_mask = ( 1 << ( bit_offset % 8 ) ); -======= ->>>>>>> debugging natsemi.c:src/drivers/bitbash/spi_bit.c -<<<<<<< HEAD:src/drivers/bitbash/spi_bit.c -======= ->>>>>>> debugging natsemi.c:src/drivers/bitbash/spi_bit.c + /* Shift data in or out */ if ( sclk == cpha ) { const uint8_t *byte; diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index 8bd63bb9..f1a22605 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -221,6 +221,7 @@ static struct nvo_fragment nat_nvo_fragments[] = { // Initialise three-wire bus nat->spibit.basher.op = &nat_basher_ops; nat->spibit.bus.mode = SPI_MODE_THREEWIRE; + nat->spibit.endianness = SPI_BIT_LITTLE_ENDIAN; init_spi_bit_basher ( &nat->spibit ); DBG ( "EEPROM is an AT93C46\n" ); From 6d4dafdc6e4973ab74e3f41e439decaf1b7eb722 Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Sun, 1 Jul 2007 18:05:58 -0400 Subject: [PATCH 11/33] added netdev_tx_complete to natsemi.c --- src/drivers/net/natsemi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index f1a22605..5d3a0287 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -45,6 +45,9 @@ struct natsemi_nic { * alternatively substracting sizeof(head) and sizeof(list_head) can also * give the same.*/ struct io_buffer *iobuf[NUM_RX_DESC]; + /*netdev_tx_complete needs pointer to the iobuf of the data so as to free + it form the memory.*/ + struct io_buffer *tx_iobuf[TX_RING_SIZE]; struct spi_bit_basher spibit; struct spi_device eeprom; struct nvo_block nvo; @@ -415,6 +418,8 @@ static int nat_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { } //DBG_HD(iobuf->data,iob_len(iobuf)); + /* to be used in netdev_tx_complete*/ + nat->tx_iobuf[nat->tx_cur]=iobuf; /* Pad and align packet */ iob_pad ( iobuf, ETH_ZLEN ); @@ -473,6 +478,7 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { DBG("Success in transmitting Packet with data\n"); // DBG_HD(&nat->tx[nat->tx_dirty].bufptr,130); } + netdev_tx_complete(netdev,nat->tx_iobuf[nat->tx_dirty]); /* setting cmdsts zero, indicating that it can be reused */ nat->tx[nat->tx_dirty].cmdsts=0; nat->tx_dirty=(nat->tx_dirty +1) % TX_RING_SIZE; From 9ad59b60c590317909cb99cd3b1c8fcbb111f7f6 Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Mon, 2 Jul 2007 22:45:50 -0400 Subject: [PATCH 12/33] added change log to natsemi.c --- src/drivers/net/natsemi.c | 120 +++++++++++++++++++++++--------------- 1 file changed, 72 insertions(+), 48 deletions(-) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index 5d3a0287..d658bb6a 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -1,8 +1,67 @@ -/* natsemi.c - gPXE driver for the NatSemi DP8381x series. +/* natsemi.c - gPXE driver for the NatSemi DP8381x series. */ + +/* + + natsemi.c: An Etherboot driver for the NatSemi DP8381x series. + + Copyright (C) 2001 Entity Cyber, Inc. + + This development of this Etherboot driver was funded by + + Sicom Systems: http://www.sicompos.com/ + + Author: Marty Connor (mdc@thinguin.org) + Adapted from a Linux driver which was written by Donald Becker + + This software may be used and distributed according to the terms + of the GNU Public License (GPL), incorporated herein by reference. + + Original Copyright Notice: + + Written/copyright 1999-2001 by Donald Becker. + + This software may be used and distributed according to the terms of + the GNU General Public License (GPL), incorporated herein by reference. + Drivers based on or derived from this code fall under the GPL and must + retain the authorship, copyright and license notice. This file is not + a complete program and may only be used when the entire operating + system is licensed under the GPL. License for under other terms may be + available. Contact the original author for details. + + The original author may be reached as becker@scyld.com, or at + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 + + Support information and updates available at + http://www.scyld.com/network/netsemi.html + + References: + + http://www.scyld.com/expert/100mbps.html + http://www.scyld.com/expert/NWay.html + Datasheet is available from: + http://www.national.com/pf/DP/DP83815.html */ +/* Revision History */ + +/* + 02 JUL 2007 Udayan Kumar 1.2 ported the driver from etherboot to gPXE API + Added a circular buffer for transmit and receive. + transmit routine will not wait for transmission to finish + poll routine deals with it. + + 13 Dec 2003 timlegge 1.1 Enabled Multicast Support + 29 May 2001 mdc 1.0 + Initial Release. Tested with Netgear FA311 and FA312 boards +*/ + + + + #include #include #include @@ -21,6 +80,10 @@ #define TX_RING_SIZE 4 #define NUM_RX_DESC 4 +#define RX_BUF_SIZE 1536 +#define OWN 0x80000000 +#define DSIZE 0x00000FFF +#define CRC_SIZE 4 struct natsemi_tx { uint32_t link; @@ -46,26 +109,13 @@ struct natsemi_nic { * give the same.*/ struct io_buffer *iobuf[NUM_RX_DESC]; /*netdev_tx_complete needs pointer to the iobuf of the data so as to free - it form the memory.*/ + it from the memory.*/ struct io_buffer *tx_iobuf[TX_RING_SIZE]; struct spi_bit_basher spibit; struct spi_device eeprom; struct nvo_block nvo; }; -/* Tuning Parameters */ -#define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */ -#define RX_FIFO_THRESH 4 /* Rx buffer level before first PCI xfer. */ -#define RX_DMA_BURST 4 /* Maximum PCI burst, '4' is 256 bytes */ -#define TX_DMA_BURST 4 /* Calculate as 16<spibit.basher.op = &nat_basher_ops; @@ -227,18 +273,12 @@ static struct nvo_fragment nat_nvo_fragments[] = { nat->spibit.endianness = SPI_BIT_LITTLE_ENDIAN; init_spi_bit_basher ( &nat->spibit ); - DBG ( "EEPROM is an AT93C46\n" ); + /*natsemi DP 83815 only supports at93c46 */ init_at93c46 ( &nat->eeprom, 16 ); nat->eeprom.bus = &nat->spibit.bus; - // Initialise space for non-volatile options, if available - //vpd = ( inw ( rtl->ioaddr + Config1 ) & VPDEnable ); - //if ( vpd ) { - // DBG ( "EEPROM in use for VPD; cannot use for options\n" ); - //} else { nat->nvo.nvs = &nat->eeprom.nvs; nat->nvo.fragments = nat_nvo_fragments; -// } } /** @@ -280,7 +320,6 @@ static void nat_reset ( struct natsemi_nic *nat ) { */ static int nat_open ( struct net_device *netdev ) { struct natsemi_nic *nat = netdev->priv; - //struct io_buffer *iobuf; int i; uint32_t tx_config,rx_config; @@ -296,13 +335,10 @@ static int nat_open ( struct net_device *netdev ) { - /* Program the MAC address TODO enable this comment */ uint8_t last=0; uint8_t last1=0; for ( i = 0 ; i < ETH_ALEN ; i+=2 ) { - // DBG("MAC address %d octet :%X %X\n",i,netdev->ll_addr[i],netdev->ll_addr[i+1]); - // DBG("LAst = %d last1 = %d\n",last,last1); outl(i,nat->ioaddr+RxFilterAddr); last1=netdev->ll_addr[i]>>7; netdev->ll_addr[i]=netdev->ll_addr[i]<<1|last; @@ -310,9 +346,6 @@ static int nat_open ( struct net_device *netdev ) { netdev->ll_addr[i+1]=(netdev->ll_addr[i+1]<<1)+last1; outw ( netdev->ll_addr[i] + (netdev->ll_addr[i+1]<<8), nat->ioaddr +RxFilterData); - //outw ( (fullbyte>>8)+(fullbyte<<8), nat->ioaddr +RxFilterData); - // DBG("MAC address %d octet :%X %X\n",i,netdev->ll_addr[i],netdev->ll_addr[i+1]); - // DBG("LAst = %d last1 = %d\n",last,last1); } @@ -417,7 +450,6 @@ static int nat_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { return -ENOBUFS; } - //DBG_HD(iobuf->data,iob_len(iobuf)); /* to be used in netdev_tx_complete*/ nat->tx_iobuf[nat->tx_cur]=iobuf; @@ -432,7 +464,6 @@ static int nat_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { nat->tx[nat->tx_cur].cmdsts= (uint32_t) iob_len(iobuf)|OWN; - //DBG_HD(bus_to_virt(nat->tx[nat->tx_cur].bufptr), iob_len(iobuf) ); nat->tx_cur=(nat->tx_cur+1) % TX_RING_SIZE; /*start the transmitter */ @@ -459,7 +490,6 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { i=nat->tx_dirty; while(i!=nat->tx_cur) { - //status=(uint32_t)bus_to_virt(nat->tx[nat->tx_dirty].cmdsts); status=nat->tx[nat->tx_dirty].cmdsts; DBG("value of tx_dirty = %d tx_cur=%d status=%X\n", nat->tx_dirty,nat->tx_cur,status); @@ -487,9 +517,7 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { } - //rx_status=(unsigned int)bus_to_virt(nat->rx[nat->rx_cur].cmdsts); rx_status=(unsigned int)nat->rx[nat->rx_cur].cmdsts; - //DBG ("Receiver Status = %x\n",rx_status); /* Handle received packets */ while (rx_quota && (rx_status & OWN)) { @@ -510,16 +538,14 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { return; memcpy(iob_put(rx_iob,rx_len), bus_to_virt(nat->rx[nat->rx_cur].bufptr),rx_len); - //DBG_HD(bus_to_virt(nat->rx[nat->rx_cur].bufptr),rx_len); - DBG("received packet"); + DBG("received packet\n"); /* add to the receive queue. */ netdev_rx(netdev,rx_iob); rx_quota--; } nat->rx[nat->rx_cur].cmdsts = RX_BUF_SIZE; nat->rx_cur=(nat->rx_cur+1) % NUM_RX_DESC; - //rx_status=(unsigned int)bus_to_virt(nat->rx[nat->rx_cur].cmdsts); rx_status=(unsigned int)nat->rx[nat->rx_cur].cmdsts; } @@ -568,9 +594,7 @@ static int nat_probe ( struct pci_device *pci, nat_init_eeprom ( nat ); nvs_read ( &nat->eeprom.nvs, EE_MAC, netdev->ll_addr, ETH_ALEN ); uint8_t eetest[128]; - int i; nvs_read ( &nat->eeprom.nvs, 0, eetest,128 ); - // DBG_HD(&eetest,128); /* mdio routine of etherboot-5.4.0 natsemi driver has been removed and @@ -633,10 +657,10 @@ static int nat_probe ( struct pci_device *pci, static void nat_remove ( struct pci_device *pci ) { struct net_device *netdev = pci_get_drvdata ( pci ); struct natsemi_nic *nat = netdev->priv; -/* TODO - if ( rtl->nvo.nvs ) - nvo_unregister ( &rtl->nvo ); - */ + + if ( nat->nvo.nvs ) + nvo_unregister ( &nat->nvo ); + unregister_netdev ( netdev ); nat_reset ( nat ); netdev_put ( netdev ); From 0d4ecfa63c70e77e1755d490d3caa61e3453bf07 Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Tue, 3 Jul 2007 19:29:31 -0400 Subject: [PATCH 13/33] enabled interrupt in natsemi.c --- src/drivers/net/natsemi.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index d658bb6a..67c18b8e 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -200,6 +200,14 @@ enum desc_status_bits { RxTooLong = 0x00400000 }; +/*Bits in Interrupt Mask register */ + +enum Intr_mask_register_bits { + RxOk = 0x001, + RxErr = 0x004, + TxOk = 0x040, + TxErr = 0x100 +}; /* EEPROM access , values are devices specific*/ @@ -407,6 +415,12 @@ static int nat_open ( struct net_device *netdev ) { /*start the receiver */ outl(RxOn, nat->ioaddr + ChipCmd); + /*enable interrupts*/ + outl((RxOk|RxErr|TxOk|TxErr),nat->ioaddr + IntrMask); + outl(1,nat->ioaddr +IntrEnable); + + + return 0; } @@ -430,6 +444,8 @@ static void nat_close ( struct net_device *netdev ) { free_iob( nat->iobuf[i] ); } + /* disable interrupts */ + outl(0,nat->ioaddr +IntrEnable); } /** From 5e91a38269ea5e80e27f143a62b6aa926ff0ddcf Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Tue, 3 Jul 2007 22:20:47 -0400 Subject: [PATCH 14/33] interrupt in natsemi --- src/drivers/net/natsemi.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index 67c18b8e..9c8d4581 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -445,7 +445,7 @@ static void nat_close ( struct net_device *netdev ) { free_iob( nat->iobuf[i] ); } /* disable interrupts */ - outl(0,nat->ioaddr +IntrEnable); + outl(0,nat->ioaddr + IntrMask) ; } /** @@ -498,11 +498,21 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { struct natsemi_nic *nat = netdev->priv; unsigned int status; unsigned int rx_status; + unsigned int intr_status; unsigned int rx_len; struct io_buffer *rx_iob; int i; + outl(1,nat->ioaddr +IntrEnable); + /* read the interrupt register */ + intr_status=inl(nat->ioaddr+IntrStatus); + if(!intr_status) + goto end; + /* check the status of packets given to card for transmission */ + DBG("Intr status %X\n",intr_status); + + i=nat->tx_dirty; while(i!=nat->tx_cur) { @@ -551,7 +561,7 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { rx_iob = alloc_iob(rx_len); if(!rx_iob) /* leave packet for next call to poll*/ - return; + goto end; memcpy(iob_put(rx_iob,rx_len), bus_to_virt(nat->rx[nat->rx_cur].bufptr),rx_len); @@ -565,9 +575,11 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { rx_status=(unsigned int)nat->rx[nat->rx_cur].cmdsts; } +end: /* re-enable the potentially idle receive state machine */ - outl(RxOn, nat->ioaddr + ChipCmd); + outl(RxOn, nat->ioaddr + ChipCmd); + outl(1,nat->ioaddr +IntrEnable); } From 2383a070d8065f269baf6365948c5dd98b3efaa3 Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Tue, 3 Jul 2007 22:23:17 -0400 Subject: [PATCH 15/33] natsemi --- src/drivers/net/natsemi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index 9c8d4581..26691b41 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -503,7 +503,7 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { struct io_buffer *rx_iob; int i; - outl(1,nat->ioaddr +IntrEnable); + //outl(1,nat->ioaddr +IntrEnable); /* read the interrupt register */ intr_status=inl(nat->ioaddr+IntrStatus); if(!intr_status) @@ -579,7 +579,7 @@ end: /* re-enable the potentially idle receive state machine */ outl(RxOn, nat->ioaddr + ChipCmd); - outl(1,nat->ioaddr +IntrEnable); +// outl(1,nat->ioaddr +IntrEnable); } From a86b12728addc64f9a1e01907e95eb0884e8e4fe Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Thu, 5 Jul 2007 08:38:37 -0400 Subject: [PATCH 16/33] irq still not working will have to remove it --- src/drivers/net/natsemi.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index 26691b41..c4aa2398 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -63,6 +63,7 @@ #include +#include #include #include #include @@ -617,6 +618,15 @@ static int nat_probe ( struct pci_device *pci, memset ( nat, 0, sizeof ( *nat ) ); nat->ioaddr = pci->ioaddr; + /* getting the IRQ vector */ + unsigned long vector_phys = IRQ_INT ( pci->irq ) * 4; + DBG_HDA ( vector_phys, phys_to_virt ( vector_phys ), 4 ); + DBG_HD ( phys_to_virt ( 0xfaea5 ), 64 ); + DBG (" PIC state %X\n", irq_enabled(pci->irq)); + DBG (" IRQ Number %X\n",pci->irq); + + + /* Reset the NIC, set up EEPROM access and read MAC address */ nat_reset ( nat ); nat_init_eeprom ( nat ); From 4f2fab2e148923b87d38281e60309b4261f25397 Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Sat, 7 Jul 2007 16:07:30 -0400 Subject: [PATCH 17/33] natsemi.c is workin --- src/drivers/net/natsemi.c | 257 +++++++++++++++----------------------- 1 file changed, 102 insertions(+), 155 deletions(-) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index c4aa2398..2e21a433 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -107,10 +107,12 @@ struct natsemi_nic { struct natsemi_rx rx[NUM_RX_DESC]; /* need to add iobuf as we cannot free iobuf->data in close without this * alternatively substracting sizeof(head) and sizeof(list_head) can also - * give the same.*/ + * give the same. + */ struct io_buffer *iobuf[NUM_RX_DESC]; - /*netdev_tx_complete needs pointer to the iobuf of the data so as to free - it from the memory.*/ + /* netdev_tx_complete needs pointer to the iobuf of the data so as to free + * it from the memory. + */ struct io_buffer *tx_iobuf[TX_RING_SIZE]; struct spi_bit_basher spibit; struct spi_device eeprom; @@ -119,10 +121,10 @@ struct natsemi_nic { /* NATSEMI: Offsets to the device registers. - Unlike software-only systems, device drivers interact with complex hardware. - It's not useful to define symbolic names for every register bit in the - device. -*/ + * Unlike software-only systems, device drivers interact with complex hardware. + * It's not useful to define symbolic names for every register bit in the + * device. + */ enum register_offsets { ChipCmd = 0x00, ChipConfig = 0x04, @@ -258,25 +260,24 @@ static struct bit_basher_operations nat_basher_ops = { .read = nat_spi_read_bit, .write = nat_spi_write_bit, }; -/** Portion of EEPROM available for non-volatile stored options - * - * We use offset 0x40 (i.e. address 0x20), length 0x40. This block is - * marked as VPD in the rtl8139 datasheets, so we use it only if we - * detect that the card is not supporting VPD. + +/* It looks that this portion of EEPROM can be used for + * non-volatile stored options. Data sheet does not talk about this region. + * Currently it is not working. But with some efforts it can. */ static struct nvo_fragment nat_nvo_fragments[] = { - { 0x0c, 0x40 }, + { 0x0c, 0x68 }, { 0, 0 } }; -/** +/* * Set up for EEPROM access * * @v NAT NATSEMI NIC */ void nat_init_eeprom ( struct natsemi_nic *nat ) { - // Initialise three-wire bus + /* Initialise three-wire bus */ nat->spibit.basher.op = &nat_basher_ops; nat->spibit.bus.mode = SPI_MODE_THREEWIRE; nat->spibit.endianness = SPI_BIT_LITTLE_ENDIAN; @@ -286,11 +287,11 @@ static struct nvo_fragment nat_nvo_fragments[] = { init_at93c46 ( &nat->eeprom, 16 ); nat->eeprom.bus = &nat->spibit.bus; - nat->nvo.nvs = &nat->eeprom.nvs; - nat->nvo.fragments = nat_nvo_fragments; + nat->nvo.nvs = &nat->eeprom.nvs; + nat->nvo.fragments = nat_nvo_fragments; } -/** +/* * Reset NIC * * @v NATSEMI NIC @@ -305,8 +306,7 @@ static void nat_reset ( struct natsemi_nic *nat ) { mdelay ( 10 ); nat->tx_dirty=0; nat->tx_cur=0; - for(i=0;itx[i].link=0; nat->tx[i].cmdsts=0; nat->tx[i].bufptr=0; @@ -321,7 +321,7 @@ static void nat_reset ( struct natsemi_nic *nat ) { outl(SavedClkRun, nat->ioaddr + ClkRun); } -/** +/* * Open NIC * * @v netdev Net device @@ -333,50 +333,33 @@ static int nat_open ( struct net_device *netdev ) { uint32_t tx_config,rx_config; /* Disable PME: - * The PME bit is initialized from the EEPROM contents. - * PCI cards probably have PME disabled, but motherboard - * implementations may have PME set to enable WakeOnLan. - * With PME set the chip will scan incoming packets but - * nothing will be written to memory. */ + * The PME bit is initialized from the EEPROM contents. + * PCI cards probably have PME disabled, but motherboard + * implementations may have PME set to enable WakeOnLan. + * With PME set the chip will scan incoming packets but + * nothing will be written to memory. + */ SavedClkRun = inl(nat->ioaddr + ClkRun); outl(SavedClkRun & ~0x100, nat->ioaddr + ClkRun); - - - - uint8_t last=0; - uint8_t last1=0; - for ( i = 0 ; i < ETH_ALEN ; i+=2 ) - { + /* Setting up Mac address in the NIC */ + for ( i = 0 ; i < ETH_ALEN ; i+=2 ) { outl(i,nat->ioaddr+RxFilterAddr); - last1=netdev->ll_addr[i]>>7; - netdev->ll_addr[i]=netdev->ll_addr[i]<<1|last; - last=(netdev->ll_addr[i+1]>>7); - netdev->ll_addr[i+1]=(netdev->ll_addr[i+1]<<1)+last1; - outw ( netdev->ll_addr[i] + (netdev->ll_addr[i+1]<<8), nat->ioaddr +RxFilterData); } - - /*Set up the Tx Ring */ nat->tx_cur=0; nat->tx_dirty=0; - for (i=0;itx[i].link = virt_to_bus((i+1 < TX_RING_SIZE) ? &nat->tx[i+1] : &nat->tx[0]); nat->tx[i].cmdsts = 0; nat->tx[i].bufptr = 0; } - - - - /* Set up RX ring */ nat->rx_cur=0; - for (i=0;iiobuf[i] = alloc_iob ( RX_BUF_SIZE ); if (!nat->iobuf[i]) @@ -386,8 +369,7 @@ static int nat_open ( struct net_device *netdev ) { nat->rx[i].bufptr = virt_to_bus(nat->iobuf[i]->data); } - - /* load Receive Descriptor Register */ + /* load Receive Descriptor Register */ outl(virt_to_bus(&nat->rx[0]), nat->ioaddr + RxRingPtr); DBG("Natsemi Rx descriptor loaded with: %X\n",(unsigned int)inl(nat->ioaddr+RxRingPtr)); @@ -398,9 +380,10 @@ static int nat_open ( struct net_device *netdev ) { /* Enables RX */ outl(RxFilterEnable|AcceptBroadcast|AcceptAllMulticast|AcceptMyPhys, nat->ioaddr+RxFilterAddr); - /* Initialize other registers. */ - /* Configure the PCI bus bursts and FIFO thresholds. */ - /* Configure for standard, in-spec Ethernet. */ + /* Initialize other registers. + * Configure the PCI bus bursts and FIFO thresholds. + * Configure for standard, in-spec Ethernet. + */ if (inl(nat->ioaddr + ChipConfig) & 0x20000000) { /* Full duplex */ tx_config = 0xD0801002; rx_config = 0x10000020; @@ -411,17 +394,12 @@ static int nat_open ( struct net_device *netdev ) { outl(tx_config, nat->ioaddr + TxConfig); outl(rx_config, nat->ioaddr + RxConfig); - - /*start the receiver */ outl(RxOn, nat->ioaddr + ChipCmd); /*enable interrupts*/ outl((RxOk|RxErr|TxOk|TxErr),nat->ioaddr + IntrMask); - outl(1,nat->ioaddr +IntrEnable); - - - + //outl(1,nat->ioaddr +IntrEnable); return 0; } @@ -440,13 +418,12 @@ static void nat_close ( struct net_device *netdev ) { nat_reset ( nat ); /* Free RX ring */ - for (i=0;iiobuf[i] ); } /* disable interrupts */ - outl(0,nat->ioaddr + IntrMask) ; + //outl(0,nat->ioaddr + IntrMask) ; } /** @@ -459,11 +436,9 @@ static void nat_close ( struct net_device *netdev ) { static int nat_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { struct natsemi_nic *nat = netdev->priv; - /* check for space in TX ring */ - - if (nat->tx[nat->tx_cur].cmdsts !=0) - { - printf ( "TX overflow\n" ); + /* check for space in TX ring */ + if (nat->tx[nat->tx_cur].cmdsts !=0) { + DBG( "TX overflow\n" ); return -ENOBUFS; } @@ -478,9 +453,8 @@ static int nat_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { virt_to_bus ( &iobuf->data ), iob_len ( iobuf ) ); nat->tx[nat->tx_cur].bufptr = virt_to_bus(iobuf->data); - nat->tx[nat->tx_cur].cmdsts= (uint32_t) iob_len(iobuf)|OWN; - - + nat->tx[nat->tx_cur].cmdsts= iob_len(iobuf)|OWN; + /* increment the circular buffer pointer to the next buffer location */ nat->tx_cur=(nat->tx_cur+1) % TX_RING_SIZE; /*start the transmitter */ @@ -513,10 +487,8 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { /* check the status of packets given to card for transmission */ DBG("Intr status %X\n",intr_status); - i=nat->tx_dirty; - while(i!=nat->tx_cur) - { + while(i!=nat->tx_cur) { status=nat->tx[nat->tx_dirty].cmdsts; DBG("value of tx_dirty = %d tx_cur=%d status=%X\n", nat->tx_dirty,nat->tx_cur,status); @@ -525,47 +497,37 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { if(status & OWN) break; /* Check if any errors in transmission */ - if (! (status & DescPktOK)) - { - printf("Error in sending Packet status:%X\n", + if (! (status & DescPktOK)) { + DBG("Error in sending Packet status:%X\n", (unsigned int)status); + netdev_tx_complete_err(netdev,nat->tx_iobuf[nat->tx_dirty],-EINVAL); + } else { + DBG("Success in transmitting Packet\n"); + netdev_tx_complete(netdev,nat->tx_iobuf[nat->tx_dirty]); } - else - { - DBG("Success in transmitting Packet with data\n"); - // DBG_HD(&nat->tx[nat->tx_dirty].bufptr,130); - } - netdev_tx_complete(netdev,nat->tx_iobuf[nat->tx_dirty]); /* setting cmdsts zero, indicating that it can be reused */ nat->tx[nat->tx_dirty].cmdsts=0; nat->tx_dirty=(nat->tx_dirty +1) % TX_RING_SIZE; i=(i+1) % TX_RING_SIZE; - } - - rx_status=(unsigned int)nat->rx[nat->rx_cur].cmdsts; /* Handle received packets */ - while (rx_quota && (rx_status & OWN)) - { + rx_status=(unsigned int)nat->rx[nat->rx_cur].cmdsts; + while (rx_quota && (rx_status & OWN)) { rx_len= (rx_status & DSIZE) - CRC_SIZE; - /*check for the corrupt packet */ - if((rx_status & (DescMore|DescPktOK|RxTooLong)) != DescPktOK) - { - printf("natsemi_poll: Corrupted packet received, " + if((rx_status & (DescMore|DescPktOK|RxTooLong)) != DescPktOK) { + DBG("natsemi_poll: Corrupted packet received, " "buffer status = %X ^ %X \n",rx_status, (unsigned int) nat->rx[nat->rx_cur].cmdsts); - } - else - { + netdev_rx_err(netdev,NULL,-EINVAL); + } else { rx_iob = alloc_iob(rx_len); if(!rx_iob) /* leave packet for next call to poll*/ goto end; memcpy(iob_put(rx_iob,rx_len), - bus_to_virt(nat->rx[nat->rx_cur].bufptr),rx_len); - + nat->iobuf[nat->rx_cur]->data,rx_len); DBG("received packet\n"); /* add to the receive queue. */ netdev_rx(netdev,rx_iob); @@ -573,22 +535,25 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { } nat->rx[nat->rx_cur].cmdsts = RX_BUF_SIZE; nat->rx_cur=(nat->rx_cur+1) % NUM_RX_DESC; - rx_status=(unsigned int)nat->rx[nat->rx_cur].cmdsts; + rx_status=nat->rx[nat->rx_cur].cmdsts; } end: - /* re-enable the potentially idle receive state machine */ + /* re-enable the potentially idle receive state machine */ outl(RxOn, nat->ioaddr + ChipCmd); // outl(1,nat->ioaddr +IntrEnable); } +/** RTL8139 net device operations */ +static struct net_device_operations nat_operations = { + .open = nat_open, + .close = nat_close, + .transmit = nat_transmit, + .poll = nat_poll, +}; - - - - -/** +/* * Probe PCI device * * @v pci PCI device @@ -599,89 +564,71 @@ static int nat_probe ( struct pci_device *pci, const struct pci_device_id *id __unused ) { struct net_device *netdev; struct natsemi_nic *nat = NULL; - int registered_netdev = 0; int rc; - uint32_t advertising; - - /* Fix up PCI device */ - adjust_pci_device ( pci ); + int i; + uint8_t ll_addr_encoded[MAX_LL_ADDR_LEN]; + uint8_t last=0; + uint8_t last1=0; /* Allocate net device */ netdev = alloc_etherdev ( sizeof ( *nat ) ); - if ( ! netdev ) { - rc = -ENOMEM; - goto err; - } + if ( ! netdev ) + return -ENOMEM; + netdev_init(netdev,&nat_operations); nat = netdev->priv; pci_set_drvdata ( pci, netdev ); netdev->dev = &pci->dev; memset ( nat, 0, sizeof ( *nat ) ); nat->ioaddr = pci->ioaddr; - /* getting the IRQ vector */ - unsigned long vector_phys = IRQ_INT ( pci->irq ) * 4; - DBG_HDA ( vector_phys, phys_to_virt ( vector_phys ), 4 ); - DBG_HD ( phys_to_virt ( 0xfaea5 ), 64 ); - DBG (" PIC state %X\n", irq_enabled(pci->irq)); - DBG (" IRQ Number %X\n",pci->irq); - - + /* Fix up PCI device */ + adjust_pci_device ( pci ); /* Reset the NIC, set up EEPROM access and read MAC address */ nat_reset ( nat ); nat_init_eeprom ( nat ); - nvs_read ( &nat->eeprom.nvs, EE_MAC, netdev->ll_addr, ETH_ALEN ); - uint8_t eetest[128]; - nvs_read ( &nat->eeprom.nvs, 0, eetest,128 ); + nvs_read ( &nat->eeprom.nvs, EE_MAC, ll_addr_encoded, ETH_ALEN ); - - /* mdio routine of etherboot-5.4.0 natsemi driver has been removed and - * statement to read from MII transceiver control section is used directly - */ - - advertising = inl(nat->ioaddr + 0x80 + (4<<2)) & 0xffff; - { - uint32_t chip_config = inl(nat->ioaddr + ChipConfig); - DBG("%s: Transceiver default autoneg. %s 10 %s %s duplex.\n", - pci->driver_name, - chip_config & 0x2000 ? "enabled, advertise" : "disabled, force", - chip_config & 0x4000 ? "0" : "", - chip_config & 0x8000 ? "full" : "half"); - } - DBG("%s: Transceiver status %hX advertising %hX\n",pci->driver_name, (int)inl(nat->ioaddr + 0x84),(unsigned int) advertising); - - - - + /* decoding the MAC address read from NVS + * and save it in netdev->ll_addr + */ + for ( i = 0 ; i < ETH_ALEN ; i+=2 ) { + last1=ll_addr_encoded[i]>>7; + netdev->ll_addr[i]=ll_addr_encoded[i]<<1|last; + last=(ll_addr_encoded[i+1]>>7); + netdev->ll_addr[i+1]=(ll_addr_encoded[i+1]<<1)+last1; + } + /* TODO remove the block below */ + DBG("Contents of the EEPROM\n"); + uint8_t eetest[108]; + nvs_read(&nat->eeprom.nvs,0,eetest,108); + DBG_HD(&eetest,108); /* Point to NIC specific routines */ + /* netdev->open = nat_open; netdev->close = nat_close; netdev->transmit = nat_transmit; netdev->poll = nat_poll; - + */ /* Register network device */ if ( ( rc = register_netdev ( netdev ) ) != 0 ) - goto err; - registered_netdev = 1; + goto err_register_netdev; - /* Register non-volatile storagei - * uncomment lines below in final version*/ - - if ( nat->nvo.nvs ) { + /* Register non-volatile storage */ + if ( nat->nvo.nvs ) { if ( ( rc = nvo_register ( &nat->nvo ) ) != 0 ) - goto err; + goto err_register_nvo; } return 0; - err: +err_register_nvo: + unregister_netdev ( netdev ); +err_register_netdev: /* Disable NIC */ - if ( nat ) - nat_reset ( nat ); - if ( registered_netdev ) - unregister_netdev ( netdev ); + nat_reset ( nat ); /* Free net device */ netdev_put ( netdev ); return rc; From 83dd194330ec0628dc8b96871738855c38a0e5e4 Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Sat, 7 Jul 2007 20:42:53 -0400 Subject: [PATCH 18/33] Natsemi commented and almost done --- src/drivers/net/natsemi.c | 182 ++++++++++++++++++++++---------------- 1 file changed, 105 insertions(+), 77 deletions(-) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index 2e21a433..726bb170 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -50,13 +50,13 @@ /* 02 JUL 2007 Udayan Kumar 1.2 ported the driver from etherboot to gPXE API - Added a circular buffer for transmit and receive. - transmit routine will not wait for transmission to finish - poll routine deals with it. + Added a circular buffer for transmit and receive. + transmit routine will not wait for transmission to finish. + poll routine deals with it. - 13 Dec 2003 timlegge 1.1 Enabled Multicast Support - 29 May 2001 mdc 1.0 - Initial Release. Tested with Netgear FA311 and FA312 boards + 13 Dec 2003 timlegge 1.1 Enabled Multicast Support + 29 May 2001 mdc 1.0 + Initial Release. Tested with Netgear FA311 and FA312 boards */ @@ -119,7 +119,6 @@ struct natsemi_nic { struct nvo_block nvo; }; - /* NATSEMI: Offsets to the device registers. * Unlike software-only systems, device drivers interact with complex hardware. * It's not useful to define symbolic names for every register bit in the @@ -154,8 +153,8 @@ enum register_offsets { PhyStatus = 0xC0, MIntrCtrl = 0xC4, MIntrStatus = 0xC8, - - /* These are from the spec, around page 78... on a separate table. */ + /* These are from the spec, around page 78... on a separate table. + */ PGSEL = 0xCC, PMDCSR = 0xE4, TSTDAT = 0xFC, @@ -166,10 +165,8 @@ enum register_offsets { }; - - - -/* Bit in ChipCmd. */ +/* Bit in ChipCmd. + */ enum ChipCmdBits { ChipReset = 0x100, RxReset = 0x20, @@ -180,8 +177,8 @@ enum ChipCmdBits { TxOn = 0x01 }; - -/* Bits in the RxMode register. */ +/* Bits in the RxMode register. + */ enum rx_mode_bits { AcceptErr = 0x20, AcceptRunt = 0x10, @@ -193,7 +190,8 @@ enum rx_mode_bits { RxFilterEnable = 0x80000000 }; -/* Bits in network_desc.status */ +/* Bits in network_desc.status + */ enum desc_status_bits { DescOwn = 0x80000000, DescMore = 0x40000000, @@ -203,8 +201,8 @@ enum desc_status_bits { RxTooLong = 0x00400000 }; -/*Bits in Interrupt Mask register */ - +/*Bits in Interrupt Mask register + */ enum Intr_mask_register_bits { RxOk = 0x001, RxErr = 0x004, @@ -212,19 +210,19 @@ enum Intr_mask_register_bits { TxErr = 0x100 }; - -/* EEPROM access , values are devices specific*/ +/* EEPROM access , values are devices specific + */ #define EE_CS 0x08 /* EEPROM chip select */ #define EE_SK 0x04 /* EEPROM shift clock */ #define EE_DI 0x01 /* Data in */ #define EE_DO 0x02 /* Data out */ -/* Offsets within EEPROM (these are word offsets) */ +/* Offsets within EEPROM (these are word offsets) + */ #define EE_MAC 7 #define EE_REG EECtrl static uint32_t SavedClkRun; - static const uint8_t nat_ee_bits[] = { [SPI_BIT_SCLK] = EE_SK, [SPI_BIT_MOSI] = EE_DI, @@ -277,13 +275,15 @@ static struct nvo_fragment nat_nvo_fragments[] = { */ void nat_init_eeprom ( struct natsemi_nic *nat ) { - /* Initialise three-wire bus */ + /* Initialise three-wire bus + */ nat->spibit.basher.op = &nat_basher_ops; nat->spibit.bus.mode = SPI_MODE_THREEWIRE; nat->spibit.endianness = SPI_BIT_LITTLE_ENDIAN; init_spi_bit_basher ( &nat->spibit ); - /*natsemi DP 83815 only supports at93c46 */ + /*natsemi DP 83815 only supports at93c46 + */ init_at93c46 ( &nat->eeprom, 16 ); nat->eeprom.bus = &nat->spibit.bus; @@ -301,7 +301,8 @@ static struct nvo_fragment nat_nvo_fragments[] = { static void nat_reset ( struct natsemi_nic *nat ) { int i; - /* Reset chip */ + /* Reset chip + */ outl ( ChipReset, nat->ioaddr + ChipCmd ); mdelay ( 10 ); nat->tx_dirty=0; @@ -317,7 +318,8 @@ static void nat_reset ( struct natsemi_nic *nat ) { outl(TxOff|RxOff, nat->ioaddr + ChipCmd); - /* Restore PME enable bit */ + /* Restore PME enable bit + */ outl(SavedClkRun, nat->ioaddr + ClkRun); } @@ -342,13 +344,16 @@ static int nat_open ( struct net_device *netdev ) { SavedClkRun = inl(nat->ioaddr + ClkRun); outl(SavedClkRun & ~0x100, nat->ioaddr + ClkRun); - /* Setting up Mac address in the NIC */ + /* Setting up Mac address in the NIC + */ for ( i = 0 ; i < ETH_ALEN ; i+=2 ) { outl(i,nat->ioaddr+RxFilterAddr); - outw ( netdev->ll_addr[i] + (netdev->ll_addr[i+1]<<8), nat->ioaddr +RxFilterData); + outw ( netdev->ll_addr[i] + (netdev->ll_addr[i+1]<<8), + nat->ioaddr +RxFilterData); } - /*Set up the Tx Ring */ + /*Set up the Tx Ring + */ nat->tx_cur=0; nat->tx_dirty=0; for (i=0;itx[i].bufptr = 0; } - /* Set up RX ring */ + /* Set up RX ring + */ nat->rx_cur=0; for (i=0;irx[i].bufptr = virt_to_bus(nat->iobuf[i]->data); } - /* load Receive Descriptor Register */ + /* load Receive Descriptor Register + */ outl(virt_to_bus(&nat->rx[0]), nat->ioaddr + RxRingPtr); - DBG("Natsemi Rx descriptor loaded with: %X\n",(unsigned int)inl(nat->ioaddr+RxRingPtr)); + DBG("Natsemi Rx descriptor loaded with: %X\n", + (unsigned int)inl(nat->ioaddr+RxRingPtr)); - /* setup Tx ring */ + /* setup Tx ring + */ outl(virt_to_bus(&nat->tx[0]),nat->ioaddr+TxRingPtr); - DBG("Natsemi Tx descriptor loaded with: %X\n",(unsigned int)inl(nat->ioaddr+TxRingPtr)); + DBG("Natsemi Tx descriptor loaded with: %X\n", + (unsigned int)inl(nat->ioaddr+TxRingPtr)); - /* Enables RX */ - outl(RxFilterEnable|AcceptBroadcast|AcceptAllMulticast|AcceptMyPhys, nat->ioaddr+RxFilterAddr); + /* Enables RX + */ + outl(RxFilterEnable|AcceptBroadcast|AcceptAllMulticast|AcceptMyPhys, + nat->ioaddr+RxFilterAddr); /* Initialize other registers. * Configure the PCI bus bursts and FIFO thresholds. @@ -394,10 +406,12 @@ static int nat_open ( struct net_device *netdev ) { outl(tx_config, nat->ioaddr + TxConfig); outl(rx_config, nat->ioaddr + RxConfig); - /*start the receiver */ + /*start the receiver + */ outl(RxOn, nat->ioaddr + ChipCmd); - /*enable interrupts*/ + /*enable interrupts + */ outl((RxOk|RxErr|TxOk|TxErr),nat->ioaddr + IntrMask); //outl(1,nat->ioaddr +IntrEnable); @@ -414,15 +428,18 @@ static void nat_close ( struct net_device *netdev ) { int i; - /* Reset the hardware to disable everything in one go */ + /* Reset the hardware to disable everything in one go + */ nat_reset ( nat ); - /* Free RX ring */ + /* Free RX ring + */ for (i=0;iiobuf[i] ); } - /* disable interrupts */ + /* disable interrupts + */ //outl(0,nat->ioaddr + IntrMask) ; } @@ -436,28 +453,34 @@ static void nat_close ( struct net_device *netdev ) { static int nat_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { struct natsemi_nic *nat = netdev->priv; - /* check for space in TX ring */ + /* check for space in TX ring + */ if (nat->tx[nat->tx_cur].cmdsts !=0) { DBG( "TX overflow\n" ); return -ENOBUFS; } - /* to be used in netdev_tx_complete*/ + /* to be used in netdev_tx_complete + */ nat->tx_iobuf[nat->tx_cur]=iobuf; - /* Pad and align packet */ - iob_pad ( iobuf, ETH_ZLEN ); + /* Pad and align packet has been ignored because its not required here + * iob_pad ( iobuf, ETH_ZLEN ); can be used to achieve it + */ - /* Add to TX ring */ + /* Add to TX ring + */ DBG ( "TX id %d at %lx+%x\n", nat->tx_cur, virt_to_bus ( &iobuf->data ), iob_len ( iobuf ) ); nat->tx[nat->tx_cur].bufptr = virt_to_bus(iobuf->data); nat->tx[nat->tx_cur].cmdsts= iob_len(iobuf)|OWN; - /* increment the circular buffer pointer to the next buffer location */ + /* increment the circular buffer pointer to the next buffer location + */ nat->tx_cur=(nat->tx_cur+1) % TX_RING_SIZE; - /*start the transmitter */ + /*start the transmitter + */ outl(TxOn, nat->ioaddr + ChipCmd); return 0; @@ -479,12 +502,14 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { int i; //outl(1,nat->ioaddr +IntrEnable); - /* read the interrupt register */ + /* read the interrupt register + */ intr_status=inl(nat->ioaddr+IntrStatus); if(!intr_status) goto end; - /* check the status of packets given to card for transmission */ + /* check the status of packets given to card for transmission + */ DBG("Intr status %X\n",intr_status); i=nat->tx_dirty; @@ -493,10 +518,12 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { DBG("value of tx_dirty = %d tx_cur=%d status=%X\n", nat->tx_dirty,nat->tx_cur,status); - /* check if current packet has been transmitted or not */ + /* check if current packet has been transmitted or not + */ if(status & OWN) break; - /* Check if any errors in transmission */ + /* Check if any errors in transmission + */ if (! (status & DescPktOK)) { DBG("Error in sending Packet status:%X\n", (unsigned int)status); @@ -505,17 +532,20 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { DBG("Success in transmitting Packet\n"); netdev_tx_complete(netdev,nat->tx_iobuf[nat->tx_dirty]); } - /* setting cmdsts zero, indicating that it can be reused */ + /* setting cmdsts zero, indicating that it can be reused + */ nat->tx[nat->tx_dirty].cmdsts=0; nat->tx_dirty=(nat->tx_dirty +1) % TX_RING_SIZE; i=(i+1) % TX_RING_SIZE; } - /* Handle received packets */ + /* Handle received packets + */ rx_status=(unsigned int)nat->rx[nat->rx_cur].cmdsts; while (rx_quota && (rx_status & OWN)) { rx_len= (rx_status & DSIZE) - CRC_SIZE; - /*check for the corrupt packet */ + /*check for the corrupt packet + */ if((rx_status & (DescMore|DescPktOK|RxTooLong)) != DescPktOK) { DBG("natsemi_poll: Corrupted packet received, " "buffer status = %X ^ %X \n",rx_status, @@ -524,12 +554,14 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { } else { rx_iob = alloc_iob(rx_len); if(!rx_iob) - /* leave packet for next call to poll*/ + /* leave packet for next call to poll + */ goto end; memcpy(iob_put(rx_iob,rx_len), nat->iobuf[nat->rx_cur]->data,rx_len); DBG("received packet\n"); - /* add to the receive queue. */ + /* add to the receive queue. + */ netdev_rx(netdev,rx_iob); rx_quota--; } @@ -540,7 +572,8 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { end: - /* re-enable the potentially idle receive state machine */ + /* re-enable the potentially idle receive state machine + */ outl(RxOn, nat->ioaddr + ChipCmd); // outl(1,nat->ioaddr +IntrEnable); } @@ -570,7 +603,8 @@ static int nat_probe ( struct pci_device *pci, uint8_t last=0; uint8_t last1=0; - /* Allocate net device */ + /* Allocate net device + */ netdev = alloc_etherdev ( sizeof ( *nat ) ); if ( ! netdev ) return -ENOMEM; @@ -581,10 +615,12 @@ static int nat_probe ( struct pci_device *pci, memset ( nat, 0, sizeof ( *nat ) ); nat->ioaddr = pci->ioaddr; - /* Fix up PCI device */ + /* Fix up PCI device + */ adjust_pci_device ( pci ); - /* Reset the NIC, set up EEPROM access and read MAC address */ + /* Reset the NIC, set up EEPROM access and read MAC address + */ nat_reset ( nat ); nat_init_eeprom ( nat ); nvs_read ( &nat->eeprom.nvs, EE_MAC, ll_addr_encoded, ETH_ALEN ); @@ -598,24 +634,14 @@ static int nat_probe ( struct pci_device *pci, last=(ll_addr_encoded[i+1]>>7); netdev->ll_addr[i+1]=(ll_addr_encoded[i+1]<<1)+last1; } - /* TODO remove the block below */ - DBG("Contents of the EEPROM\n"); - uint8_t eetest[108]; - nvs_read(&nat->eeprom.nvs,0,eetest,108); - DBG_HD(&eetest,108); - /* Point to NIC specific routines */ - /* - netdev->open = nat_open; - netdev->close = nat_close; - netdev->transmit = nat_transmit; - netdev->poll = nat_poll; - */ - /* Register network device */ + /* Register network device + */ if ( ( rc = register_netdev ( netdev ) ) != 0 ) goto err_register_netdev; - /* Register non-volatile storage */ + /* Register non-volatile storage + */ if ( nat->nvo.nvs ) { if ( ( rc = nvo_register ( &nat->nvo ) ) != 0 ) goto err_register_nvo; @@ -627,9 +653,11 @@ static int nat_probe ( struct pci_device *pci, err_register_nvo: unregister_netdev ( netdev ); err_register_netdev: - /* Disable NIC */ + /* Disable NIC + */ nat_reset ( nat ); - /* Free net device */ + /* Free net device + */ netdev_put ( netdev ); return rc; } From 132d0fb70c6ddd83c47d744afe610f171a625a49 Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Sun, 8 Jul 2007 11:03:30 -0400 Subject: [PATCH 19/33] stopped memory leak in natsemi::nat_open() --- src/drivers/net/natsemi.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index 726bb170..bff384e7 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -49,7 +49,8 @@ /* Revision History */ /* - 02 JUL 2007 Udayan Kumar 1.2 ported the driver from etherboot to gPXE API + 02 JUL 2007 Udayan Kumar 1.2 ported the driver from etherboot to gPXE API. + Fully rewritten,adapting the old driver. Added a circular buffer for transmit and receive. transmit routine will not wait for transmission to finish. poll routine deals with it. @@ -366,10 +367,9 @@ static int nat_open ( struct net_device *netdev ) { */ nat->rx_cur=0; for (i=0;iiobuf[i] = alloc_iob ( RX_BUF_SIZE ); if (!nat->iobuf[i]) - return -ENOMEM; + goto memory_alloc_err; nat->rx[i].link = virt_to_bus((i+1 < NUM_RX_DESC) ? &nat->rx[i+1] : &nat->rx[0]); nat->rx[i].cmdsts = (uint32_t) RX_BUF_SIZE; nat->rx[i].bufptr = virt_to_bus(nat->iobuf[i]->data); @@ -414,8 +414,18 @@ static int nat_open ( struct net_device *netdev ) { */ outl((RxOk|RxErr|TxOk|TxErr),nat->ioaddr + IntrMask); //outl(1,nat->ioaddr +IntrEnable); - return 0; + +memory_alloc_err: + /* this block frees the previously allocated buffers + * if memory for all the buffers is not available + */ + i=0; + while(nat->rx[i].cmdsts == (uint32_t) RX_BUF_SIZE) { + free_iob(nat->iobuf[i]); + i++; + } + return -ENOMEM; } /** @@ -426,8 +436,6 @@ static int nat_open ( struct net_device *netdev ) { static void nat_close ( struct net_device *netdev ) { struct natsemi_nic *nat = netdev->priv; int i; - - /* Reset the hardware to disable everything in one go */ nat_reset ( nat ); @@ -464,7 +472,7 @@ static int nat_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { */ nat->tx_iobuf[nat->tx_cur]=iobuf; - /* Pad and align packet has been ignored because its not required here + /* Pad and align packet has not been used because its not required here * iob_pad ( iobuf, ETH_ZLEN ); can be used to achieve it */ @@ -569,9 +577,7 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { nat->rx_cur=(nat->rx_cur+1) % NUM_RX_DESC; rx_status=nat->rx[nat->rx_cur].cmdsts; } - end: - /* re-enable the potentially idle receive state machine */ outl(RxOn, nat->ioaddr + ChipCmd); @@ -646,8 +652,6 @@ static int nat_probe ( struct pci_device *pci, if ( ( rc = nvo_register ( &nat->nvo ) ) != 0 ) goto err_register_nvo; } - - return 0; err_register_nvo: @@ -681,7 +685,6 @@ static void nat_remove ( struct pci_device *pci ) { static struct pci_device_id natsemi_nics[] = { PCI_ROM(0x100b, 0x0020, "dp83815", "DP83815"), - }; struct pci_driver natsemi_driver __pci_driver = { From a8c2a4fa11cd0cced920e1883dbf327ce4978364 Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Sun, 8 Jul 2007 13:37:42 -0400 Subject: [PATCH 20/33] added nat_irq to natsemi.c --- src/drivers/net/natsemi.c | 47 +++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index bff384e7..aa7dae68 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -371,7 +371,7 @@ static int nat_open ( struct net_device *netdev ) { if (!nat->iobuf[i]) goto memory_alloc_err; nat->rx[i].link = virt_to_bus((i+1 < NUM_RX_DESC) ? &nat->rx[i+1] : &nat->rx[0]); - nat->rx[i].cmdsts = (uint32_t) RX_BUF_SIZE; + nat->rx[i].cmdsts = RX_BUF_SIZE; nat->rx[i].bufptr = virt_to_bus(nat->iobuf[i]->data); } @@ -410,10 +410,8 @@ static int nat_open ( struct net_device *netdev ) { */ outl(RxOn, nat->ioaddr + ChipCmd); - /*enable interrupts + /* mask the interrupts. note interrupt is not enabled here */ - outl((RxOk|RxErr|TxOk|TxErr),nat->ioaddr + IntrMask); - //outl(1,nat->ioaddr +IntrEnable); return 0; memory_alloc_err: @@ -421,7 +419,7 @@ memory_alloc_err: * if memory for all the buffers is not available */ i=0; - while(nat->rx[i].cmdsts == (uint32_t) RX_BUF_SIZE) { + while(nat->rx[i].cmdsts == RX_BUF_SIZE) { free_iob(nat->iobuf[i]); i++; } @@ -446,9 +444,6 @@ static void nat_close ( struct net_device *netdev ) { free_iob( nat->iobuf[i] ); } - /* disable interrupts - */ - //outl(0,nat->ioaddr + IntrMask) ; } /** @@ -509,7 +504,6 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { struct io_buffer *rx_iob; int i; - //outl(1,nat->ioaddr +IntrEnable); /* read the interrupt register */ intr_status=inl(nat->ioaddr+IntrStatus); @@ -581,15 +575,33 @@ end: /* re-enable the potentially idle receive state machine */ outl(RxOn, nat->ioaddr + ChipCmd); -// outl(1,nat->ioaddr +IntrEnable); } -/** RTL8139 net device operations */ +/** + * Enable/disable interrupts + * + * @v netdev Network device + * @v enable Interrupts should be enabled + */ +static void nat_irq ( struct net_device *netdev, int enable ) { + struct natsemi_nic *nat= netdev->priv; + + outl((enable?(RxOk|RxErr|TxOk|TxErr):0), + nat->ioaddr + IntrMask); + outl((enable ? 1:0),nat->ioaddr +IntrEnable); +} + + + + + +/** natsemi net device operations */ static struct net_device_operations nat_operations = { .open = nat_open, .close = nat_close, .transmit = nat_transmit, .poll = nat_poll, + .irq = nat_irq, }; /* @@ -634,11 +646,10 @@ static int nat_probe ( struct pci_device *pci, /* decoding the MAC address read from NVS * and save it in netdev->ll_addr */ - for ( i = 0 ; i < ETH_ALEN ; i+=2 ) { + for ( i = 0 ; i < ETH_ALEN ; i++) { last1=ll_addr_encoded[i]>>7; netdev->ll_addr[i]=ll_addr_encoded[i]<<1|last; - last=(ll_addr_encoded[i+1]>>7); - netdev->ll_addr[i+1]=(ll_addr_encoded[i+1]<<1)+last1; + last=last1; } /* Register network device @@ -646,16 +657,8 @@ static int nat_probe ( struct pci_device *pci, if ( ( rc = register_netdev ( netdev ) ) != 0 ) goto err_register_netdev; - /* Register non-volatile storage - */ - if ( nat->nvo.nvs ) { - if ( ( rc = nvo_register ( &nat->nvo ) ) != 0 ) - goto err_register_nvo; - } return 0; -err_register_nvo: - unregister_netdev ( netdev ); err_register_netdev: /* Disable NIC */ From f213f6a1a370b76a4f0c6ab397fea89b08f4f1cf Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Sun, 8 Jul 2007 14:29:55 -0400 Subject: [PATCH 21/33] no changes --- src/drivers/net/natsemi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index aa7dae68..e07fd49b 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -642,7 +642,6 @@ static int nat_probe ( struct pci_device *pci, nat_reset ( nat ); nat_init_eeprom ( nat ); nvs_read ( &nat->eeprom.nvs, EE_MAC, ll_addr_encoded, ETH_ALEN ); - /* decoding the MAC address read from NVS * and save it in netdev->ll_addr */ From bfa322bb1986b7a1dd4f5e50dc99cc459f3a925f Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Sun, 8 Jul 2007 15:12:38 -0400 Subject: [PATCH 22/33] :x --- src/drivers/net/natsemi.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index e07fd49b..8e4bb279 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -495,7 +495,7 @@ static int nat_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { * @v netdev Network device * @v rx_quota Maximum number of packets to receive */ -static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { +static void nat_poll ( struct net_device *netdev) { struct natsemi_nic *nat = netdev->priv; unsigned int status; unsigned int rx_status; @@ -544,7 +544,7 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { /* Handle received packets */ rx_status=(unsigned int)nat->rx[nat->rx_cur].cmdsts; - while (rx_quota && (rx_status & OWN)) { + while ((rx_status & OWN)) { rx_len= (rx_status & DSIZE) - CRC_SIZE; /*check for the corrupt packet */ @@ -565,7 +565,6 @@ static void nat_poll ( struct net_device *netdev, unsigned int rx_quota ) { /* add to the receive queue. */ netdev_rx(netdev,rx_iob); - rx_quota--; } nat->rx[nat->rx_cur].cmdsts = RX_BUF_SIZE; nat->rx_cur=(nat->rx_cur+1) % NUM_RX_DESC; @@ -620,6 +619,7 @@ static int nat_probe ( struct pci_device *pci, uint8_t ll_addr_encoded[MAX_LL_ADDR_LEN]; uint8_t last=0; uint8_t last1=0; + uint8_t prev_bytes[2]; /* Allocate net device */ @@ -641,10 +641,12 @@ static int nat_probe ( struct pci_device *pci, */ nat_reset ( nat ); nat_init_eeprom ( nat ); + nvs_read ( &nat->eeprom.nvs, EE_MAC-1, prev_bytes, 1); nvs_read ( &nat->eeprom.nvs, EE_MAC, ll_addr_encoded, ETH_ALEN ); /* decoding the MAC address read from NVS * and save it in netdev->ll_addr */ + last=prev_bytes[1]>>7; for ( i = 0 ; i < ETH_ALEN ; i++) { last1=ll_addr_encoded[i]>>7; netdev->ll_addr[i]=ll_addr_encoded[i]<<1|last; From 621f6fb503c0c7123143db36f2638308e52cc340 Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Sun, 8 Jul 2007 18:41:12 -0400 Subject: [PATCH 23/33] more indentation and styling done --- src/drivers/net/natsemi.c | 212 ++++++++++++++++++++------------------ 1 file changed, 114 insertions(+), 98 deletions(-) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index 8e4bb279..551fc17e 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -106,11 +106,13 @@ struct natsemi_nic { unsigned short rx_cur; struct natsemi_tx tx[TX_RING_SIZE]; struct natsemi_rx rx[NUM_RX_DESC]; + /* need to add iobuf as we cannot free iobuf->data in close without this * alternatively substracting sizeof(head) and sizeof(list_head) can also * give the same. */ struct io_buffer *iobuf[NUM_RX_DESC]; + /* netdev_tx_complete needs pointer to the iobuf of the data so as to free * it from the memory. */ @@ -154,6 +156,7 @@ enum register_offsets { PhyStatus = 0xC0, MIntrCtrl = 0xC4, MIntrStatus = 0xC8, + /* These are from the spec, around page 78... on a separate table. */ PGSEL = 0xCC, @@ -238,7 +241,7 @@ static int nat_spi_read_bit ( struct bit_basher *basher, uint8_t mask = nat_ee_bits[bit_id]; uint8_t eereg; - eereg = inb ( nat->ioaddr + EE_REG); + eereg = inb ( nat->ioaddr + EE_REG ); return ( eereg & mask ); } @@ -252,7 +255,7 @@ static void nat_spi_write_bit ( struct bit_basher *basher, eereg = inb ( nat->ioaddr + EE_REG ); eereg &= ~mask; eereg |= ( data & mask ); - outb ( eereg, nat->ioaddr + EE_REG); + outb ( eereg, nat->ioaddr + EE_REG ); } static struct bit_basher_operations nat_basher_ops = { @@ -302,26 +305,27 @@ static struct nvo_fragment nat_nvo_fragments[] = { static void nat_reset ( struct natsemi_nic *nat ) { int i; + /* Reset chip */ outl ( ChipReset, nat->ioaddr + ChipCmd ); mdelay ( 10 ); - nat->tx_dirty=0; - nat->tx_cur=0; - for(i=0;itx[i].link=0; - nat->tx[i].cmdsts=0; - nat->tx[i].bufptr=0; + nat->tx_dirty = 0; + nat->tx_cur = 0; + for ( i = 0 ; i < TX_RING_SIZE ; i++ ) { + nat->tx[i].link = 0; + nat->tx[i].cmdsts = 0; + nat->tx[i].bufptr = 0; } nat->rx_cur = 0; - outl(virt_to_bus(&nat->tx[0]),nat->ioaddr+TxRingPtr); - outl(virt_to_bus(&nat->rx[0]), nat->ioaddr + RxRingPtr); + outl ( virt_to_bus( &nat->tx[0] ),nat->ioaddr + TxRingPtr ); + outl ( virt_to_bus( &nat->rx[0] ),nat->ioaddr + RxRingPtr ); - outl(TxOff|RxOff, nat->ioaddr + ChipCmd); + outl ( TxOff|RxOff, nat->ioaddr + ChipCmd ); /* Restore PME enable bit */ - outl(SavedClkRun, nat->ioaddr + ClkRun); + outl ( SavedClkRun, nat->ioaddr + ClkRun ); } /* @@ -342,85 +346,86 @@ static int nat_open ( struct net_device *netdev ) { * With PME set the chip will scan incoming packets but * nothing will be written to memory. */ - SavedClkRun = inl(nat->ioaddr + ClkRun); - outl(SavedClkRun & ~0x100, nat->ioaddr + ClkRun); + SavedClkRun = inl ( nat->ioaddr + ClkRun ); + outl ( SavedClkRun & ~0x100, nat->ioaddr + ClkRun ); /* Setting up Mac address in the NIC */ for ( i = 0 ; i < ETH_ALEN ; i+=2 ) { - outl(i,nat->ioaddr+RxFilterAddr); - outw ( netdev->ll_addr[i] + (netdev->ll_addr[i+1]<<8), - nat->ioaddr +RxFilterData); + outl ( i,nat->ioaddr + RxFilterAddr ); + outw ( netdev->ll_addr[i] + ( netdev->ll_addr[i + 1] << 8 ), + nat->ioaddr + RxFilterData ); } /*Set up the Tx Ring */ - nat->tx_cur=0; - nat->tx_dirty=0; - for (i=0;itx[i].link = virt_to_bus((i+1 < TX_RING_SIZE) ? &nat->tx[i+1] : &nat->tx[0]); + nat->tx_cur = 0; + nat->tx_dirty = 0; + for ( i = 0 ; i < TX_RING_SIZE ; i++ ) { + nat->tx[i].link = virt_to_bus ( ( i + 1 < TX_RING_SIZE ) ? &nat->tx[i + 1] : &nat->tx[0] ); nat->tx[i].cmdsts = 0; nat->tx[i].bufptr = 0; } /* Set up RX ring */ - nat->rx_cur=0; - for (i=0;irx_cur = 0; + for ( i = 0 ; i < NUM_RX_DESC ; i++ ) { nat->iobuf[i] = alloc_iob ( RX_BUF_SIZE ); - if (!nat->iobuf[i]) + if ( !nat->iobuf[i] ) goto memory_alloc_err; - nat->rx[i].link = virt_to_bus((i+1 < NUM_RX_DESC) ? &nat->rx[i+1] : &nat->rx[0]); + nat->rx[i].link = virt_to_bus ( ( i + 1 < NUM_RX_DESC ) ? &nat->rx[i + 1] : &nat->rx[0] ); nat->rx[i].cmdsts = RX_BUF_SIZE; - nat->rx[i].bufptr = virt_to_bus(nat->iobuf[i]->data); + nat->rx[i].bufptr = virt_to_bus ( nat->iobuf[i]->data ); } /* load Receive Descriptor Register */ - outl(virt_to_bus(&nat->rx[0]), nat->ioaddr + RxRingPtr); - DBG("Natsemi Rx descriptor loaded with: %X\n", - (unsigned int)inl(nat->ioaddr+RxRingPtr)); + outl ( virt_to_bus ( &nat->rx[0] ), nat->ioaddr + RxRingPtr ); + DBG ( "Natsemi Rx descriptor loaded with: %X\n", + (unsigned int) inl ( nat->ioaddr + RxRingPtr ) ); /* setup Tx ring */ - outl(virt_to_bus(&nat->tx[0]),nat->ioaddr+TxRingPtr); - DBG("Natsemi Tx descriptor loaded with: %X\n", - (unsigned int)inl(nat->ioaddr+TxRingPtr)); + outl ( virt_to_bus ( &nat->tx[0] ),nat->ioaddr + TxRingPtr ); + DBG ( "Natsemi Tx descriptor loaded with: %X\n", + (unsigned int)inl ( nat->ioaddr + TxRingPtr ) ); /* Enables RX */ - outl(RxFilterEnable|AcceptBroadcast|AcceptAllMulticast|AcceptMyPhys, - nat->ioaddr+RxFilterAddr); + outl ( RxFilterEnable|AcceptBroadcast|AcceptAllMulticast|AcceptMyPhys, + nat->ioaddr + RxFilterAddr ); /* Initialize other registers. * Configure the PCI bus bursts and FIFO thresholds. * Configure for standard, in-spec Ethernet. */ - if (inl(nat->ioaddr + ChipConfig) & 0x20000000) { /* Full duplex */ + if ( inl ( nat->ioaddr + ChipConfig ) & 0x20000000 ) { /* Full duplex */ tx_config = 0xD0801002; rx_config = 0x10000020; } else { tx_config = 0x10801002; rx_config = 0x0020; } - outl(tx_config, nat->ioaddr + TxConfig); - outl(rx_config, nat->ioaddr + RxConfig); + outl ( tx_config, nat->ioaddr + TxConfig ); + outl ( rx_config, nat->ioaddr + RxConfig ); /*start the receiver */ - outl(RxOn, nat->ioaddr + ChipCmd); + outl ( RxOn, nat->ioaddr + ChipCmd ); /* mask the interrupts. note interrupt is not enabled here */ return 0; memory_alloc_err: + /* this block frees the previously allocated buffers * if memory for all the buffers is not available */ - i=0; - while(nat->rx[i].cmdsts == RX_BUF_SIZE) { - free_iob(nat->iobuf[i]); + i = 0; + while ( nat->rx[i].cmdsts == RX_BUF_SIZE ) { + free_iob ( nat->iobuf[i] ); i++; } return -ENOMEM; @@ -434,15 +439,16 @@ memory_alloc_err: static void nat_close ( struct net_device *netdev ) { struct natsemi_nic *nat = netdev->priv; int i; + /* Reset the hardware to disable everything in one go */ nat_reset ( nat ); /* Free RX ring */ - for (i=0;iiobuf[i] ); + free_iob ( nat->iobuf[i] ); } } @@ -458,14 +464,14 @@ static int nat_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { /* check for space in TX ring */ - if (nat->tx[nat->tx_cur].cmdsts !=0) { - DBG( "TX overflow\n" ); + if ( nat->tx[nat->tx_cur].cmdsts != 0 ) { + DBG ( "TX overflow\n" ); return -ENOBUFS; } /* to be used in netdev_tx_complete */ - nat->tx_iobuf[nat->tx_cur]=iobuf; + nat->tx_iobuf[nat->tx_cur] = iobuf; /* Pad and align packet has not been used because its not required here * iob_pad ( iobuf, ETH_ZLEN ); can be used to achieve it @@ -473,18 +479,19 @@ static int nat_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { /* Add to TX ring */ - DBG ( "TX id %d at %lx+%x\n", nat->tx_cur, + DBG ( "TX id %d at %lx + %x\n", nat->tx_cur, virt_to_bus ( &iobuf->data ), iob_len ( iobuf ) ); - nat->tx[nat->tx_cur].bufptr = virt_to_bus(iobuf->data); - nat->tx[nat->tx_cur].cmdsts= iob_len(iobuf)|OWN; + nat->tx[nat->tx_cur].bufptr = virt_to_bus ( iobuf->data ); + nat->tx[nat->tx_cur].cmdsts = iob_len ( iobuf ) | OWN; + /* increment the circular buffer pointer to the next buffer location */ - nat->tx_cur=(nat->tx_cur+1) % TX_RING_SIZE; + nat->tx_cur = ( nat->tx_cur + 1 ) % TX_RING_SIZE; /*start the transmitter */ - outl(TxOn, nat->ioaddr + ChipCmd); + outl ( TxOn, nat->ioaddr + ChipCmd ); return 0; } @@ -506,74 +513,80 @@ static void nat_poll ( struct net_device *netdev) { /* read the interrupt register */ - intr_status=inl(nat->ioaddr+IntrStatus); - if(!intr_status) - goto end; + intr_status = inl ( nat->ioaddr + IntrStatus ); + if ( !intr_status ) + goto end; /* check the status of packets given to card for transmission */ - DBG("Intr status %X\n",intr_status); + DBG ( "Intr status %X\n",intr_status ); - i=nat->tx_dirty; - while(i!=nat->tx_cur) { - status=nat->tx[nat->tx_dirty].cmdsts; - DBG("value of tx_dirty = %d tx_cur=%d status=%X\n", - nat->tx_dirty,nat->tx_cur,status); + i = nat->tx_dirty; + while ( i!= nat->tx_cur ) { + status = nat->tx[nat->tx_dirty].cmdsts; + DBG ( "value of tx_dirty = %d tx_cur=%d status=%X\n", + nat->tx_dirty,nat->tx_cur,status ); /* check if current packet has been transmitted or not */ - if(status & OWN) + if ( status & OWN ) break; + /* Check if any errors in transmission */ - if (! (status & DescPktOK)) { - DBG("Error in sending Packet status:%X\n", - (unsigned int)status); - netdev_tx_complete_err(netdev,nat->tx_iobuf[nat->tx_dirty],-EINVAL); + if (! ( status & DescPktOK ) ) { + DBG ( "Error in sending Packet status:%X\n", + (unsigned int) status ); + netdev_tx_complete_err ( netdev,nat->tx_iobuf[nat->tx_dirty],-EINVAL ); } else { - DBG("Success in transmitting Packet\n"); - netdev_tx_complete(netdev,nat->tx_iobuf[nat->tx_dirty]); + DBG ( "Success in transmitting Packet\n" ); + netdev_tx_complete ( netdev,nat->tx_iobuf[nat->tx_dirty] ); } + /* setting cmdsts zero, indicating that it can be reused */ - nat->tx[nat->tx_dirty].cmdsts=0; - nat->tx_dirty=(nat->tx_dirty +1) % TX_RING_SIZE; - i=(i+1) % TX_RING_SIZE; + nat->tx[nat->tx_dirty].cmdsts = 0; + nat->tx_dirty = ( nat->tx_dirty + 1 ) % TX_RING_SIZE; + i = ( i + 1 ) % TX_RING_SIZE; } /* Handle received packets */ - rx_status=(unsigned int)nat->rx[nat->rx_cur].cmdsts; - while ((rx_status & OWN)) { - rx_len= (rx_status & DSIZE) - CRC_SIZE; + rx_status = (unsigned int) nat->rx[nat->rx_cur].cmdsts; + while ( ( rx_status & OWN ) ) { + rx_len = ( rx_status & DSIZE ) - CRC_SIZE; + /*check for the corrupt packet */ - if((rx_status & (DescMore|DescPktOK|RxTooLong)) != DescPktOK) { - DBG("natsemi_poll: Corrupted packet received, " + if ( ( rx_status & ( DescMore|DescPktOK|RxTooLong ) ) != DescPktOK) { + DBG ( "natsemi_poll: Corrupted packet received, " "buffer status = %X ^ %X \n",rx_status, - (unsigned int) nat->rx[nat->rx_cur].cmdsts); - netdev_rx_err(netdev,NULL,-EINVAL); + (unsigned int) nat->rx[nat->rx_cur].cmdsts ); + netdev_rx_err ( netdev,NULL,-EINVAL ); } else { - rx_iob = alloc_iob(rx_len); - if(!rx_iob) + rx_iob = alloc_iob ( rx_len ); + + if ( !rx_iob ) /* leave packet for next call to poll */ goto end; - memcpy(iob_put(rx_iob,rx_len), - nat->iobuf[nat->rx_cur]->data,rx_len); - DBG("received packet\n"); + memcpy ( iob_put ( rx_iob,rx_len ), + nat->iobuf[nat->rx_cur]->data,rx_len ); + DBG ( "received packet\n" ); + /* add to the receive queue. */ - netdev_rx(netdev,rx_iob); + netdev_rx ( netdev,rx_iob ); } nat->rx[nat->rx_cur].cmdsts = RX_BUF_SIZE; - nat->rx_cur=(nat->rx_cur+1) % NUM_RX_DESC; - rx_status=nat->rx[nat->rx_cur].cmdsts; + nat->rx_cur = ( nat->rx_cur + 1 ) % NUM_RX_DESC; + rx_status = nat->rx[nat->rx_cur].cmdsts; } end: + /* re-enable the potentially idle receive state machine */ - outl(RxOn, nat->ioaddr + ChipCmd); + outl ( RxOn, nat->ioaddr + ChipCmd ); } /** @@ -583,11 +596,11 @@ end: * @v enable Interrupts should be enabled */ static void nat_irq ( struct net_device *netdev, int enable ) { - struct natsemi_nic *nat= netdev->priv; + struct natsemi_nic *nat = netdev->priv; - outl((enable?(RxOk|RxErr|TxOk|TxErr):0), + outl ( ( enable ? ( RxOk|RxErr|TxOk|TxErr ) :0 ), nat->ioaddr + IntrMask); - outl((enable ? 1:0),nat->ioaddr +IntrEnable); + outl ( ( enable ? 1:0 ),nat->ioaddr + IntrEnable ); } @@ -617,8 +630,8 @@ static int nat_probe ( struct pci_device *pci, int rc; int i; uint8_t ll_addr_encoded[MAX_LL_ADDR_LEN]; - uint8_t last=0; - uint8_t last1=0; + uint8_t last = 0; + uint8_t last1 = 0; uint8_t prev_bytes[2]; /* Allocate net device @@ -626,7 +639,7 @@ static int nat_probe ( struct pci_device *pci, netdev = alloc_etherdev ( sizeof ( *nat ) ); if ( ! netdev ) return -ENOMEM; - netdev_init(netdev,&nat_operations); + netdev_init ( netdev,&nat_operations ); nat = netdev->priv; pci_set_drvdata ( pci, netdev ); netdev->dev = &pci->dev; @@ -641,16 +654,17 @@ static int nat_probe ( struct pci_device *pci, */ nat_reset ( nat ); nat_init_eeprom ( nat ); - nvs_read ( &nat->eeprom.nvs, EE_MAC-1, prev_bytes, 1); + nvs_read ( &nat->eeprom.nvs, EE_MAC-1, prev_bytes, 1 ); nvs_read ( &nat->eeprom.nvs, EE_MAC, ll_addr_encoded, ETH_ALEN ); + /* decoding the MAC address read from NVS * and save it in netdev->ll_addr */ - last=prev_bytes[1]>>7; - for ( i = 0 ; i < ETH_ALEN ; i++) { - last1=ll_addr_encoded[i]>>7; - netdev->ll_addr[i]=ll_addr_encoded[i]<<1|last; - last=last1; + last = prev_bytes[1] >> 7; + for ( i = 0 ; i < ETH_ALEN ; i++ ) { + last1 = ll_addr_encoded[i] >> 7; + netdev->ll_addr[i] = ll_addr_encoded[i] << 1 | last; + last = last1; } /* Register network device @@ -661,9 +675,11 @@ static int nat_probe ( struct pci_device *pci, return 0; err_register_netdev: + /* Disable NIC */ nat_reset ( nat ); + /* Free net device */ netdev_put ( netdev ); From 11d246f3b53f7f0cf4138ae8297b1027fcde90ad Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Mon, 9 Jul 2007 21:54:02 -0400 Subject: [PATCH 24/33] duplex setting added to natsemi.c --- src/drivers/net/natsemi.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index 551fc17e..cdd07f21 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -401,11 +401,13 @@ static int nat_open ( struct net_device *netdev ) { * Configure for standard, in-spec Ethernet. */ if ( inl ( nat->ioaddr + ChipConfig ) & 0x20000000 ) { /* Full duplex */ - tx_config = 0xD0801002; - rx_config = 0x10000020; + tx_config = 0xD0801002|0xC0000000; + DBG("Full duplex\n"); + rx_config = 0x10000020|0x10000000;; } else { - tx_config = 0x10801002; - rx_config = 0x0020; + tx_config = 0x10801002& ~0xC0000000;; + DBG("Half duplex\n"); + rx_config = 0x0020& ~0x10000000;;; } outl ( tx_config, nat->ioaddr + TxConfig ); outl ( rx_config, nat->ioaddr + RxConfig ); From 751cb2e450d826a5d8d98fb811b126ffb4f489c8 Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Tue, 10 Jul 2007 13:29:30 -0400 Subject: [PATCH 25/33] added cable magic for 100Mps in natsemi --- src/drivers/net/natsemi.c | 76 +++++++++++++++++++++++++++++++++++---- 1 file changed, 70 insertions(+), 6 deletions(-) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index cdd07f21..43b7f2df 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -169,6 +169,15 @@ enum register_offsets { }; +/* the values for the 'magic' registers above (PGSEL=1) */ +#define PMDCSR_VAL 0x189c /* enable preferred adaptation circuitry */ +#define TSTDAT_VAL 0x0 +#define DSPCFG_VAL 0x5040 +#define SDCFG_VAL 0x008c /* set voltage thresholds for Signal Detect */ +#define DSPCFG_LOCK 0x20 /* coefficient lock bit in DSPCFG */ +#define DSPCFG_COEF 0x1000 /* see coefficient (in TSTDAT) bit in DSPCFG */ +#define TSTDAT_FIXED 0xe8 /* magic number for bad coefficients */ + /* Bit in ChipCmd. */ enum ChipCmdBits { @@ -181,6 +190,20 @@ enum ChipCmdBits { TxOn = 0x01 }; +enum ChipConfig_bits { + CfgPhyDis = 0x200, + CfgPhyRst = 0x400, + CfgExtPhy = 0x1000, + CfgAnegEnable = 0x2000, + CfgAneg100 = 0x4000, + CfgAnegFull = 0x8000, + CfgAnegDone = 0x8000000, + CfgFullDuplex = 0x20000000, + CfgSpeed100 = 0x40000000, + CfgLink = 0x80000000, +}; + + /* Bits in the RxMode register. */ enum rx_mode_bits { @@ -328,6 +351,41 @@ static void nat_reset ( struct natsemi_nic *nat ) { outl ( SavedClkRun, nat->ioaddr + ClkRun ); } +static void do_cable_magic ( struct net_device *netdev ) { + struct natsemi_nic *nat = netdev->priv; + uint16_t data; + /* + * 100 MBit links with short cables can trip an issue with the chip. + * The problem manifests as lots of CRC errors and/or flickering + * activity LED while idle. This process is based on instructions + * from engineers at National. + */ + if (inl(nat->ioaddr + ChipConfig) & CfgSpeed100) { + + outw(1, nat->ioaddr + PGSEL); + /* + * coefficient visibility should already be enabled via + * DSPCFG | 0x1000 + */ + data = inw(nat->ioaddr + TSTDAT) & 0xff; + /* + * the value must be negative, and within certain values + * (these values all come from National) + */ + if (!(data & 0x80) || ((data >= 0xd8) && (data <= 0xff))) { + + /* the bug has been triggered - fix the coefficient */ + outw(TSTDAT_FIXED, nat->ioaddr + TSTDAT); + /* lock the value */ + data = inw(nat->ioaddr + DSPCFG); + //np->dspcfg = data | DSPCFG_LOCK; + outw(data | DSPCFG_LOCK , nat->ioaddr + DSPCFG); + } + outw(0, nat->ioaddr + PGSEL); + } + +} + /* * Open NIC * @@ -401,13 +459,13 @@ static int nat_open ( struct net_device *netdev ) { * Configure for standard, in-spec Ethernet. */ if ( inl ( nat->ioaddr + ChipConfig ) & 0x20000000 ) { /* Full duplex */ - tx_config = 0xD0801002|0xC0000000; - DBG("Full duplex\n"); - rx_config = 0x10000020|0x10000000;; + tx_config = 0xD0801002 | 0xC0000000; + DBG ( "Full duplex\n" ); + rx_config = 0x10000020 | 0x10000000; } else { - tx_config = 0x10801002& ~0xC0000000;; - DBG("Half duplex\n"); - rx_config = 0x0020& ~0x10000000;;; + tx_config = 0x10801002 & ~0xC0000000; + DBG ( "Half duplex\n" ); + rx_config = 0x0020 & ~0x10000000; } outl ( tx_config, nat->ioaddr + TxConfig ); outl ( rx_config, nat->ioaddr + RxConfig ); @@ -415,6 +473,12 @@ static int nat_open ( struct net_device *netdev ) { /*start the receiver */ outl ( RxOn, nat->ioaddr + ChipCmd ); + + /* lines 1586 linux-natsemi.c uses cable magic + * testing this feature is required or not + */ + do_cable_magic ( netdev ); + /* mask the interrupts. note interrupt is not enabled here */ From 334abbde83749baf9813395a2ee1c97f9a676c4c Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Tue, 10 Jul 2007 15:08:58 -0400 Subject: [PATCH 26/33] init_fix_up --- src/drivers/net/natsemi.c | 161 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index 43b7f2df..e69a8f3f 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -79,6 +79,7 @@ #include #include #include +#include #define TX_RING_SIZE 4 #define NUM_RX_DESC 4 @@ -122,6 +123,28 @@ struct natsemi_nic { struct nvo_block nvo; }; + +/* + * Support for fibre connections on Am79C874: + * This phy needs a special setup when connected to a fibre cable. + * http://www.amd.com/files/connectivitysolutions/networking/archivednetworking/22235.pdf + */ +#define PHYID_AM79C874 0x0022561b + +enum { + MII_MCTRL = 0x15, /* mode control register */ + MII_FX_SEL = 0x0001, /* 100BASE-FX (fiber) */ + MII_EN_SCRM = 0x0004, /* enable scrambler (tp) */ +}; + + + +/* values we might find in the silicon revision register */ +#define SRR_DP83815_C 0x0302 +#define SRR_DP83815_D 0x0403 +#define SRR_DP83816_A4 0x0504 +#define SRR_DP83816_A5 0x0505 + /* NATSEMI: Offsets to the device registers. * Unlike software-only systems, device drivers interact with complex hardware. * It's not useful to define symbolic names for every register bit in the @@ -351,6 +374,143 @@ static void nat_reset ( struct natsemi_nic *nat ) { outl ( SavedClkRun, nat->ioaddr + ClkRun ); } + +static int mdio_read(struct net_device *netdev, int reg) { + struct natsemi_nic *nat = netdev->priv; + + /* The 83815 series has two ports: + * - an internal transceiver + * - an external mii bus + */ + return inw(nat->ioaddr+BasicControl+(reg<<2)); +} + +static void mdio_write(struct net_device *netdev, int reg, u16 data) { + struct natsemi_nic *nat = netdev->priv; + + /* The 83815 series has an internal transceiver; handle separately */ + writew(data, nat->ioaddr+BasicControl+(reg<<2)); +} + +static void init_phy_fixup(struct net_device *netdev) { + struct natsemi_nic *nat = netdev->priv; + int i; + u32 cfg; + u16 tmp; + uint16_t advertising; + int mii; + + /* restore stuff lost when power was out */ + tmp = mdio_read(netdev, MII_BMCR); + advertising= mdio_read(netdev, MII_ADVERTISE); +// if (np->autoneg == AUTONEG_ENABLE) { + /* renegotiate if something changed */ + if ((tmp & BMCR_ANENABLE) == 0 + || advertising != mdio_read(netdev, MII_ADVERTISE)) + { + /* turn on autonegotiation and force negotiation */ + tmp |= (BMCR_ANENABLE | BMCR_ANRESTART); + mdio_write(netdev, MII_ADVERTISE, advertising); + } +// } else { + /* turn off auto negotiation, set speed and duplexity */ +// tmp &= ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX); +// if (np->speed == SPEED_100) +/// tmp |= BMCR_SPEED100; +// if (np->duplex == DUPLEX_FULL) +// tmp |= BMCR_FULLDPLX; + /* + * Note: there is no good way to inform the link partner + * that our capabilities changed. The user has to unplug + * and replug the network cable after some changes, e.g. + * after switching from 10HD, autoneg off to 100 HD, + * autoneg off. + */ +// } + mdio_write(netdev, MII_BMCR, tmp); + inl(nat->ioaddr + ChipConfig); + udelay(1); + + /* find out what phy this is */ + mii = (mdio_read(netdev, MII_PHYSID1) << 16) + + mdio_read(netdev, MII_PHYSID2); + + /* handle external phys here */ + switch (mii) { + case PHYID_AM79C874: + /* phy specific configuration for fibre/tp operation */ + tmp = mdio_read(netdev, MII_MCTRL); + tmp &= ~(MII_FX_SEL | MII_EN_SCRM); + //if (dev->if_port == PORT_FIBRE) + // tmp |= MII_FX_SEL; + //else + tmp |= MII_EN_SCRM; + mdio_write(netdev, MII_MCTRL, tmp); + break; + default: + break; + } + cfg = inl(nat->ioaddr + ChipConfig); + if (cfg & CfgExtPhy) + return; + + /* On page 78 of the spec, they recommend some settings for "optimum + performance" to be done in sequence. These settings optimize some + of the 100Mbit autodetection circuitry. They say we only want to + do this for rev C of the chip, but engineers at NSC (Bradley + Kennedy) recommends always setting them. If you don't, you get + errors on some autonegotiations that make the device unusable. + + It seems that the DSP needs a few usec to reinitialize after + the start of the phy. Just retry writing these values until they + stick. + */ + uint32_t srr = inl(nat->ioaddr + SiliconRev); + int NATSEMI_HW_TIMEOUT = 400; + for (i=0;iioaddr + PGSEL); + outw(PMDCSR_VAL, nat->ioaddr + PMDCSR); + outw(TSTDAT_VAL, nat->ioaddr + TSTDAT); + dspcfg = (srr <= SRR_DP83815_C)? + DSPCFG_VAL : (DSPCFG_COEF | readw(nat->ioaddr + DSPCFG)); + outw(dspcfg, nat->ioaddr + DSPCFG); + outw(SDCFG_VAL, nat->ioaddr + SDCFG); + outw(0, nat->ioaddr + PGSEL); + inl(nat->ioaddr + ChipConfig); + udelay(10); + + outw(1, nat->ioaddr + PGSEL); + dspcfg_1 = readw(nat->ioaddr + DSPCFG); + outw(0, nat->ioaddr + PGSEL); + if (dspcfg == dspcfg_1) + break; + } + + if (i==NATSEMI_HW_TIMEOUT) { + DBG ( "Natsemi: DSPCFG mismatch after retrying for" + " %d usec.\n", i*10); + } else { + DBG ( "NATSEMI: DSPCFG accepted after %d usec.\n", + i*10); + } + /* + * Enable PHY Specific event based interrupts. Link state change + * and Auto-Negotiation Completion are among the affected. + * Read the intr status to clear it (needed for wake events). + */ + inw(nat->ioaddr + MIntrStatus); + //MICRIntEn = 0x2 + outw(0x2, nat->ioaddr + MIntrCtrl); +} + + +/* + * Patch up for fixing CRC errors. + * adapted from linux natsemi driver + * + */ static void do_cable_magic ( struct net_device *netdev ) { struct natsemi_nic *nat = netdev->priv; uint16_t data; @@ -478,6 +638,7 @@ static int nat_open ( struct net_device *netdev ) { * testing this feature is required or not */ do_cable_magic ( netdev ); + init_phy_fixup ( netdev ); /* mask the interrupts. note interrupt is not enabled here From d6ceb8bbd79f8f2bb13f727ac6b0f2f81287f68d Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Tue, 10 Jul 2007 15:29:55 -0400 Subject: [PATCH 27/33] added silicon revision number --- src/drivers/net/natsemi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index e69a8f3f..5e9f4dfa 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -466,6 +466,7 @@ static void init_phy_fixup(struct net_device *netdev) { stick. */ uint32_t srr = inl(nat->ioaddr + SiliconRev); + DBG ( "Natsemi : silicon revision %#04x.\n",(unsigned int)srr); int NATSEMI_HW_TIMEOUT = 400; for (i=0;irx[nat->rx_cur].cmdsts ); netdev_rx_err ( netdev,NULL,-EINVAL ); } else { From f58c8511a046467b2da897c92fb537ba83791f59 Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Tue, 10 Jul 2007 15:47:34 -0400 Subject: [PATCH 28/33] more debugging --- src/drivers/net/natsemi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index 5e9f4dfa..0267c1bc 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -631,6 +631,9 @@ static int nat_open ( struct net_device *netdev ) { outl ( tx_config, nat->ioaddr + TxConfig ); outl ( rx_config, nat->ioaddr + RxConfig ); + DBG ( "Tx config register = %x Rx config register = %x\n", + (unsigned int) inl ( nat->ioaddr + TxConfig), + (unsigned int) inl ( nat->ioaddr + RxConfig) ); /*start the receiver */ outl ( RxOn, nat->ioaddr + ChipCmd ); @@ -641,6 +644,7 @@ static int nat_open ( struct net_device *netdev ) { do_cable_magic ( netdev ); init_phy_fixup ( netdev ); + /* mask the interrupts. note interrupt is not enabled here */ @@ -783,6 +787,8 @@ static void nat_poll ( struct net_device *netdev) { rx_status = (unsigned int) nat->rx[nat->rx_cur].cmdsts; while ( ( rx_status & OWN ) ) { rx_len = ( rx_status & DSIZE ) - CRC_SIZE; + DBG ( " Status of received packet = %X , Lenght of Packet = %X\n", + rx_status,rx_len ); /*check for the corrupt packet */ From 008bfb6e8544f9974d834855b35b6876230c4fe5 Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Wed, 11 Jul 2007 12:30:44 -0400 Subject: [PATCH 29/33] more debugging --- src/drivers/net/natsemi.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index 0267c1bc..d2097abb 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -596,6 +596,8 @@ static int nat_open ( struct net_device *netdev ) { nat->rx[i].link = virt_to_bus ( ( i + 1 < NUM_RX_DESC ) ? &nat->rx[i + 1] : &nat->rx[0] ); nat->rx[i].cmdsts = RX_BUF_SIZE; nat->rx[i].bufptr = virt_to_bus ( nat->iobuf[i]->data ); + // DBG ( " Address of iobuf [%d] = %x and iobuf->data = %x \n", i, + // nat->iobuf[i],nat->iobuf[i]->data); } /* load Receive Descriptor Register @@ -793,10 +795,11 @@ static void nat_poll ( struct net_device *netdev) { /*check for the corrupt packet */ if ( ( rx_status & ( DescMore|DescPktOK|RxTooLong ) ) != DescPktOK) { - DBG ( "natsemi_poll: Corrupted packet received, " - "buffer status = %X \n", - (unsigned int) nat->rx[nat->rx_cur].cmdsts ); - netdev_rx_err ( netdev,NULL,-EINVAL ); + DBG ( "natsemi_poll: Corrupted packet received, " + "buffer status = %X \n", + (unsigned int) nat->rx[nat->rx_cur].cmdsts ); + //DBG_HD ( nat->iobuf[nat->rx_cur]->data,rx_len); + netdev_rx_err ( netdev,NULL,-EINVAL ); } else { rx_iob = alloc_iob ( rx_len ); @@ -807,6 +810,7 @@ static void nat_poll ( struct net_device *netdev) { memcpy ( iob_put ( rx_iob,rx_len ), nat->iobuf[nat->rx_cur]->data,rx_len ); DBG ( "received packet\n" ); + //DBG_HD ( nat->iobuf[nat->rx_cur]->data,30); /* add to the receive queue. */ From ecfa8f41e8ef581d9922f8b8868cfb5d9c0dc840 Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Fri, 13 Jul 2007 22:55:17 -0400 Subject: [PATCH 30/33] mdc's+nvs --- src/drivers/net/natsemi.c | 1233 +++++++++++++------------------------ 1 file changed, 443 insertions(+), 790 deletions(-) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index d2097abb..bd97ebdc 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -1,8 +1,8 @@ -/* natsemi.c - gPXE driver for the NatSemi DP8381x series. */ - -/* - +/* + natsemi.c - gPXE driver for the NatSemi DP8381x series. + Based on: + natsemi.c: An Etherboot driver for the NatSemi DP8381x series. Copyright (C) 2001 Entity Cyber, Inc. @@ -11,7 +11,7 @@ Sicom Systems: http://www.sicompos.com/ - Author: Marty Connor (mdc@thinguin.org) + Author: Marty Connor Adapted from a Linux driver which was written by Donald Becker This software may be used and distributed according to the terms @@ -49,19 +49,14 @@ /* Revision History */ /* - 02 JUL 2007 Udayan Kumar 1.2 ported the driver from etherboot to gPXE API. + 02 Jul 2007 Udayan Kumar 1.2 ported the driver from etherboot to gPXE API. Fully rewritten,adapting the old driver. Added a circular buffer for transmit and receive. transmit routine will not wait for transmission to finish. poll routine deals with it. - - 13 Dec 2003 timlegge 1.1 Enabled Multicast Support - 29 May 2001 mdc 1.0 - Initial Release. Tested with Netgear FA311 and FA312 boards + 13 Dec 2003 Tim Legge 1.1 Enabled Multicast Support + 29 May 2001 Marty Connor 1.0 Initial Release. Tested with Netgear FA311 and FA312 boards */ - - - #include #include @@ -79,241 +74,65 @@ #include #include #include -#include +#include "natsemi.h" -#define TX_RING_SIZE 4 -#define NUM_RX_DESC 4 -#define RX_BUF_SIZE 1536 -#define OWN 0x80000000 -#define DSIZE 0x00000FFF -#define CRC_SIZE 4 +/* Function Prototypes: */ + +static int natsemi_spi_read_bit ( struct bit_basher *, unsigned int ); +static void natsemi_spi_write_bit ( struct bit_basher *,unsigned int, unsigned long ); +void natsemi_init_eeprom ( struct natsemi_private * ); +static int natsemi_probe (struct pci_device *pci, const struct pci_device_id *id); +static void natsemi_reset (struct net_device *netdev); +static int natsemi_open (struct net_device *netdev); +static int natsemi_transmit (struct net_device *netdev, struct io_buffer *iobuf); +static void natsemi_poll (struct net_device *netdev); +static void natsemi_close (struct net_device *netdev); +static void natsemi_irq (struct net_device *netdev, int enable); +static void natsemi_remove (struct pci_device *pci); -struct natsemi_tx { - uint32_t link; - uint32_t cmdsts; - uint32_t bufptr; +/** natsemi net device operations */ +static struct net_device_operations natsemi_operations = { + .open = natsemi_open, + .close = natsemi_close, + .transmit = natsemi_transmit, + .poll = natsemi_poll, + .irq = natsemi_irq, }; -struct natsemi_rx { - uint32_t link; - uint32_t cmdsts; - uint32_t bufptr; -}; - -struct natsemi_nic { - unsigned short ioaddr; - unsigned short tx_cur; - unsigned short tx_dirty; - unsigned short rx_cur; - struct natsemi_tx tx[TX_RING_SIZE]; - struct natsemi_rx rx[NUM_RX_DESC]; - - /* need to add iobuf as we cannot free iobuf->data in close without this - * alternatively substracting sizeof(head) and sizeof(list_head) can also - * give the same. - */ - struct io_buffer *iobuf[NUM_RX_DESC]; - - /* netdev_tx_complete needs pointer to the iobuf of the data so as to free - * it from the memory. - */ - struct io_buffer *tx_iobuf[TX_RING_SIZE]; - struct spi_bit_basher spibit; - struct spi_device eeprom; - struct nvo_block nvo; -}; - - -/* - * Support for fibre connections on Am79C874: - * This phy needs a special setup when connected to a fibre cable. - * http://www.amd.com/files/connectivitysolutions/networking/archivednetworking/22235.pdf - */ -#define PHYID_AM79C874 0x0022561b - -enum { - MII_MCTRL = 0x15, /* mode control register */ - MII_FX_SEL = 0x0001, /* 100BASE-FX (fiber) */ - MII_EN_SCRM = 0x0004, /* enable scrambler (tp) */ -}; - - - -/* values we might find in the silicon revision register */ -#define SRR_DP83815_C 0x0302 -#define SRR_DP83815_D 0x0403 -#define SRR_DP83816_A4 0x0504 -#define SRR_DP83816_A5 0x0505 - -/* NATSEMI: Offsets to the device registers. - * Unlike software-only systems, device drivers interact with complex hardware. - * It's not useful to define symbolic names for every register bit in the - * device. - */ -enum register_offsets { - ChipCmd = 0x00, - ChipConfig = 0x04, - EECtrl = 0x08, - PCIBusCfg = 0x0C, - IntrStatus = 0x10, - IntrMask = 0x14, - IntrEnable = 0x18, - TxRingPtr = 0x20, - TxConfig = 0x24, - RxRingPtr = 0x30, - RxConfig = 0x34, - ClkRun = 0x3C, - WOLCmd = 0x40, - PauseCmd = 0x44, - RxFilterAddr = 0x48, - RxFilterData = 0x4C, - BootRomAddr = 0x50, - BootRomData = 0x54, - SiliconRev = 0x58, - StatsCtrl = 0x5C, - StatsData = 0x60, - RxPktErrs = 0x60, - RxMissed = 0x68, - RxCRCErrs = 0x64, - PCIPM = 0x44, - PhyStatus = 0xC0, - MIntrCtrl = 0xC4, - MIntrStatus = 0xC8, - - /* These are from the spec, around page 78... on a separate table. - */ - PGSEL = 0xCC, - PMDCSR = 0xE4, - TSTDAT = 0xFC, - DSPCFG = 0xF4, - SDCFG = 0x8C, - BasicControl = 0x80, - BasicStatus = 0x84 - -}; - -/* the values for the 'magic' registers above (PGSEL=1) */ -#define PMDCSR_VAL 0x189c /* enable preferred adaptation circuitry */ -#define TSTDAT_VAL 0x0 -#define DSPCFG_VAL 0x5040 -#define SDCFG_VAL 0x008c /* set voltage thresholds for Signal Detect */ -#define DSPCFG_LOCK 0x20 /* coefficient lock bit in DSPCFG */ -#define DSPCFG_COEF 0x1000 /* see coefficient (in TSTDAT) bit in DSPCFG */ -#define TSTDAT_FIXED 0xe8 /* magic number for bad coefficients */ - -/* Bit in ChipCmd. - */ -enum ChipCmdBits { - ChipReset = 0x100, - RxReset = 0x20, - TxReset = 0x10, - RxOff = 0x08, - RxOn = 0x04, - TxOff = 0x02, - TxOn = 0x01 -}; - -enum ChipConfig_bits { - CfgPhyDis = 0x200, - CfgPhyRst = 0x400, - CfgExtPhy = 0x1000, - CfgAnegEnable = 0x2000, - CfgAneg100 = 0x4000, - CfgAnegFull = 0x8000, - CfgAnegDone = 0x8000000, - CfgFullDuplex = 0x20000000, - CfgSpeed100 = 0x40000000, - CfgLink = 0x80000000, -}; - - -/* Bits in the RxMode register. - */ -enum rx_mode_bits { - AcceptErr = 0x20, - AcceptRunt = 0x10, - AcceptBroadcast = 0xC0000000, - AcceptMulticast = 0x00200000, - AcceptAllMulticast = 0x20000000, - AcceptAllPhys = 0x10000000, - AcceptMyPhys = 0x08000000, - RxFilterEnable = 0x80000000 -}; - -/* Bits in network_desc.status - */ -enum desc_status_bits { - DescOwn = 0x80000000, - DescMore = 0x40000000, - DescIntr = 0x20000000, - DescNoCRC = 0x10000000, - DescPktOK = 0x08000000, - RxTooLong = 0x00400000 -}; - -/*Bits in Interrupt Mask register - */ -enum Intr_mask_register_bits { - RxOk = 0x001, - RxErr = 0x004, - TxOk = 0x040, - TxErr = 0x100 -}; - -/* EEPROM access , values are devices specific - */ -#define EE_CS 0x08 /* EEPROM chip select */ -#define EE_SK 0x04 /* EEPROM shift clock */ -#define EE_DI 0x01 /* Data in */ -#define EE_DO 0x02 /* Data out */ - -/* Offsets within EEPROM (these are word offsets) - */ -#define EE_MAC 7 -#define EE_REG EECtrl -static uint32_t SavedClkRun; - -static const uint8_t nat_ee_bits[] = { - [SPI_BIT_SCLK] = EE_SK, - [SPI_BIT_MOSI] = EE_DI, - [SPI_BIT_MISO] = EE_DO, - [SPI_BIT_SS(0)] = EE_CS, -}; - -static int nat_spi_read_bit ( struct bit_basher *basher, +static int natsemi_spi_read_bit ( struct bit_basher *basher, unsigned int bit_id ) { - struct natsemi_nic *nat = container_of ( basher, struct natsemi_nic, + struct natsemi_private *np = container_of ( basher, struct natsemi_private, spibit.basher ); - uint8_t mask = nat_ee_bits[bit_id]; + uint8_t mask = natsemi_ee_bits[bit_id]; uint8_t eereg; - eereg = inb ( nat->ioaddr + EE_REG ); + eereg = inb ( np->ioaddr + EE_REG ); return ( eereg & mask ); } -static void nat_spi_write_bit ( struct bit_basher *basher, +static void natsemi_spi_write_bit ( struct bit_basher *basher, unsigned int bit_id, unsigned long data ) { - struct natsemi_nic *nat = container_of ( basher, struct natsemi_nic, + struct natsemi_private *np = container_of ( basher, struct natsemi_private, spibit.basher ); - uint8_t mask = nat_ee_bits[bit_id]; + uint8_t mask = natsemi_ee_bits[bit_id]; uint8_t eereg; - eereg = inb ( nat->ioaddr + EE_REG ); + eereg = inb ( np->ioaddr + EE_REG ); eereg &= ~mask; eereg |= ( data & mask ); - outb ( eereg, nat->ioaddr + EE_REG ); + outb ( eereg, np->ioaddr + EE_REG ); } -static struct bit_basher_operations nat_basher_ops = { - .read = nat_spi_read_bit, - .write = nat_spi_write_bit, +static struct bit_basher_operations natsemi_basher_ops = { + .read = natsemi_spi_read_bit, + .write = natsemi_spi_write_bit, }; /* It looks that this portion of EEPROM can be used for * non-volatile stored options. Data sheet does not talk about this region. * Currently it is not working. But with some efforts it can. */ -static struct nvo_fragment nat_nvo_fragments[] = { +static struct nvo_fragment natsemi_nvo_fragments[] = { { 0x0c, 0x68 }, { 0, 0 } }; @@ -323,577 +142,59 @@ static struct nvo_fragment nat_nvo_fragments[] = { * * @v NAT NATSEMI NIC */ - void nat_init_eeprom ( struct natsemi_nic *nat ) { + void natsemi_init_eeprom ( struct natsemi_private *np ) { /* Initialise three-wire bus */ - nat->spibit.basher.op = &nat_basher_ops; - nat->spibit.bus.mode = SPI_MODE_THREEWIRE; - nat->spibit.endianness = SPI_BIT_LITTLE_ENDIAN; - init_spi_bit_basher ( &nat->spibit ); + np->spibit.basher.op = &natsemi_basher_ops; + np->spibit.bus.mode = SPI_MODE_THREEWIRE; + np->spibit.endianness = SPI_BIT_LITTLE_ENDIAN; + init_spi_bit_basher ( &np->spibit ); /*natsemi DP 83815 only supports at93c46 */ - init_at93c46 ( &nat->eeprom, 16 ); - nat->eeprom.bus = &nat->spibit.bus; - - nat->nvo.nvs = &nat->eeprom.nvs; - nat->nvo.fragments = nat_nvo_fragments; -} - -/* - * Reset NIC - * - * @v NATSEMI NIC - * - * Issues a hardware reset and waits for the reset to complete. - */ -static void nat_reset ( struct natsemi_nic *nat ) { - - int i; - - /* Reset chip - */ - outl ( ChipReset, nat->ioaddr + ChipCmd ); - mdelay ( 10 ); - nat->tx_dirty = 0; - nat->tx_cur = 0; - for ( i = 0 ; i < TX_RING_SIZE ; i++ ) { - nat->tx[i].link = 0; - nat->tx[i].cmdsts = 0; - nat->tx[i].bufptr = 0; - } - nat->rx_cur = 0; - outl ( virt_to_bus( &nat->tx[0] ),nat->ioaddr + TxRingPtr ); - outl ( virt_to_bus( &nat->rx[0] ),nat->ioaddr + RxRingPtr ); - - outl ( TxOff|RxOff, nat->ioaddr + ChipCmd ); - - /* Restore PME enable bit - */ - outl ( SavedClkRun, nat->ioaddr + ClkRun ); -} - - -static int mdio_read(struct net_device *netdev, int reg) { - struct natsemi_nic *nat = netdev->priv; - - /* The 83815 series has two ports: - * - an internal transceiver - * - an external mii bus - */ - return inw(nat->ioaddr+BasicControl+(reg<<2)); -} - -static void mdio_write(struct net_device *netdev, int reg, u16 data) { - struct natsemi_nic *nat = netdev->priv; - - /* The 83815 series has an internal transceiver; handle separately */ - writew(data, nat->ioaddr+BasicControl+(reg<<2)); -} - -static void init_phy_fixup(struct net_device *netdev) { - struct natsemi_nic *nat = netdev->priv; - int i; - u32 cfg; - u16 tmp; - uint16_t advertising; - int mii; - - /* restore stuff lost when power was out */ - tmp = mdio_read(netdev, MII_BMCR); - advertising= mdio_read(netdev, MII_ADVERTISE); -// if (np->autoneg == AUTONEG_ENABLE) { - /* renegotiate if something changed */ - if ((tmp & BMCR_ANENABLE) == 0 - || advertising != mdio_read(netdev, MII_ADVERTISE)) - { - /* turn on autonegotiation and force negotiation */ - tmp |= (BMCR_ANENABLE | BMCR_ANRESTART); - mdio_write(netdev, MII_ADVERTISE, advertising); - } -// } else { - /* turn off auto negotiation, set speed and duplexity */ -// tmp &= ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX); -// if (np->speed == SPEED_100) -/// tmp |= BMCR_SPEED100; -// if (np->duplex == DUPLEX_FULL) -// tmp |= BMCR_FULLDPLX; - /* - * Note: there is no good way to inform the link partner - * that our capabilities changed. The user has to unplug - * and replug the network cable after some changes, e.g. - * after switching from 10HD, autoneg off to 100 HD, - * autoneg off. - */ -// } - mdio_write(netdev, MII_BMCR, tmp); - inl(nat->ioaddr + ChipConfig); - udelay(1); - - /* find out what phy this is */ - mii = (mdio_read(netdev, MII_PHYSID1) << 16) - + mdio_read(netdev, MII_PHYSID2); - - /* handle external phys here */ - switch (mii) { - case PHYID_AM79C874: - /* phy specific configuration for fibre/tp operation */ - tmp = mdio_read(netdev, MII_MCTRL); - tmp &= ~(MII_FX_SEL | MII_EN_SCRM); - //if (dev->if_port == PORT_FIBRE) - // tmp |= MII_FX_SEL; - //else - tmp |= MII_EN_SCRM; - mdio_write(netdev, MII_MCTRL, tmp); - break; - default: - break; - } - cfg = inl(nat->ioaddr + ChipConfig); - if (cfg & CfgExtPhy) - return; - - /* On page 78 of the spec, they recommend some settings for "optimum - performance" to be done in sequence. These settings optimize some - of the 100Mbit autodetection circuitry. They say we only want to - do this for rev C of the chip, but engineers at NSC (Bradley - Kennedy) recommends always setting them. If you don't, you get - errors on some autonegotiations that make the device unusable. - - It seems that the DSP needs a few usec to reinitialize after - the start of the phy. Just retry writing these values until they - stick. - */ - uint32_t srr = inl(nat->ioaddr + SiliconRev); - DBG ( "Natsemi : silicon revision %#04x.\n",(unsigned int)srr); - int NATSEMI_HW_TIMEOUT = 400; - for (i=0;iioaddr + PGSEL); - outw(PMDCSR_VAL, nat->ioaddr + PMDCSR); - outw(TSTDAT_VAL, nat->ioaddr + TSTDAT); - dspcfg = (srr <= SRR_DP83815_C)? - DSPCFG_VAL : (DSPCFG_COEF | readw(nat->ioaddr + DSPCFG)); - outw(dspcfg, nat->ioaddr + DSPCFG); - outw(SDCFG_VAL, nat->ioaddr + SDCFG); - outw(0, nat->ioaddr + PGSEL); - inl(nat->ioaddr + ChipConfig); - udelay(10); - - outw(1, nat->ioaddr + PGSEL); - dspcfg_1 = readw(nat->ioaddr + DSPCFG); - outw(0, nat->ioaddr + PGSEL); - if (dspcfg == dspcfg_1) - break; - } - - if (i==NATSEMI_HW_TIMEOUT) { - DBG ( "Natsemi: DSPCFG mismatch after retrying for" - " %d usec.\n", i*10); - } else { - DBG ( "NATSEMI: DSPCFG accepted after %d usec.\n", - i*10); - } - /* - * Enable PHY Specific event based interrupts. Link state change - * and Auto-Negotiation Completion are among the affected. - * Read the intr status to clear it (needed for wake events). - */ - inw(nat->ioaddr + MIntrStatus); - //MICRIntEn = 0x2 - outw(0x2, nat->ioaddr + MIntrCtrl); -} - - -/* - * Patch up for fixing CRC errors. - * adapted from linux natsemi driver - * - */ -static void do_cable_magic ( struct net_device *netdev ) { - struct natsemi_nic *nat = netdev->priv; - uint16_t data; - /* - * 100 MBit links with short cables can trip an issue with the chip. - * The problem manifests as lots of CRC errors and/or flickering - * activity LED while idle. This process is based on instructions - * from engineers at National. - */ - if (inl(nat->ioaddr + ChipConfig) & CfgSpeed100) { - - outw(1, nat->ioaddr + PGSEL); - /* - * coefficient visibility should already be enabled via - * DSPCFG | 0x1000 - */ - data = inw(nat->ioaddr + TSTDAT) & 0xff; - /* - * the value must be negative, and within certain values - * (these values all come from National) - */ - if (!(data & 0x80) || ((data >= 0xd8) && (data <= 0xff))) { - - /* the bug has been triggered - fix the coefficient */ - outw(TSTDAT_FIXED, nat->ioaddr + TSTDAT); - /* lock the value */ - data = inw(nat->ioaddr + DSPCFG); - //np->dspcfg = data | DSPCFG_LOCK; - outw(data | DSPCFG_LOCK , nat->ioaddr + DSPCFG); - } - outw(0, nat->ioaddr + PGSEL); - } - -} - -/* - * Open NIC - * - * @v netdev Net device - * @ret rc Return status code - */ -static int nat_open ( struct net_device *netdev ) { - struct natsemi_nic *nat = netdev->priv; - int i; - uint32_t tx_config,rx_config; - - /* Disable PME: - * The PME bit is initialized from the EEPROM contents. - * PCI cards probably have PME disabled, but motherboard - * implementations may have PME set to enable WakeOnLan. - * With PME set the chip will scan incoming packets but - * nothing will be written to memory. - */ - SavedClkRun = inl ( nat->ioaddr + ClkRun ); - outl ( SavedClkRun & ~0x100, nat->ioaddr + ClkRun ); - - /* Setting up Mac address in the NIC - */ - for ( i = 0 ; i < ETH_ALEN ; i+=2 ) { - outl ( i,nat->ioaddr + RxFilterAddr ); - outw ( netdev->ll_addr[i] + ( netdev->ll_addr[i + 1] << 8 ), - nat->ioaddr + RxFilterData ); - } - - /*Set up the Tx Ring - */ - nat->tx_cur = 0; - nat->tx_dirty = 0; - for ( i = 0 ; i < TX_RING_SIZE ; i++ ) { - nat->tx[i].link = virt_to_bus ( ( i + 1 < TX_RING_SIZE ) ? &nat->tx[i + 1] : &nat->tx[0] ); - nat->tx[i].cmdsts = 0; - nat->tx[i].bufptr = 0; - } - - /* Set up RX ring - */ - nat->rx_cur = 0; - for ( i = 0 ; i < NUM_RX_DESC ; i++ ) { - nat->iobuf[i] = alloc_iob ( RX_BUF_SIZE ); - if ( !nat->iobuf[i] ) - goto memory_alloc_err; - nat->rx[i].link = virt_to_bus ( ( i + 1 < NUM_RX_DESC ) ? &nat->rx[i + 1] : &nat->rx[0] ); - nat->rx[i].cmdsts = RX_BUF_SIZE; - nat->rx[i].bufptr = virt_to_bus ( nat->iobuf[i]->data ); - // DBG ( " Address of iobuf [%d] = %x and iobuf->data = %x \n", i, - // nat->iobuf[i],nat->iobuf[i]->data); - } - - /* load Receive Descriptor Register - */ - outl ( virt_to_bus ( &nat->rx[0] ), nat->ioaddr + RxRingPtr ); - DBG ( "Natsemi Rx descriptor loaded with: %X\n", - (unsigned int) inl ( nat->ioaddr + RxRingPtr ) ); - - /* setup Tx ring - */ - outl ( virt_to_bus ( &nat->tx[0] ),nat->ioaddr + TxRingPtr ); - DBG ( "Natsemi Tx descriptor loaded with: %X\n", - (unsigned int)inl ( nat->ioaddr + TxRingPtr ) ); - - /* Enables RX - */ - outl ( RxFilterEnable|AcceptBroadcast|AcceptAllMulticast|AcceptMyPhys, - nat->ioaddr + RxFilterAddr ); - - /* Initialize other registers. - * Configure the PCI bus bursts and FIFO thresholds. - * Configure for standard, in-spec Ethernet. - */ - if ( inl ( nat->ioaddr + ChipConfig ) & 0x20000000 ) { /* Full duplex */ - tx_config = 0xD0801002 | 0xC0000000; - DBG ( "Full duplex\n" ); - rx_config = 0x10000020 | 0x10000000; - } else { - tx_config = 0x10801002 & ~0xC0000000; - DBG ( "Half duplex\n" ); - rx_config = 0x0020 & ~0x10000000; - } - outl ( tx_config, nat->ioaddr + TxConfig ); - outl ( rx_config, nat->ioaddr + RxConfig ); - - DBG ( "Tx config register = %x Rx config register = %x\n", - (unsigned int) inl ( nat->ioaddr + TxConfig), - (unsigned int) inl ( nat->ioaddr + RxConfig) ); - /*start the receiver - */ - outl ( RxOn, nat->ioaddr + ChipCmd ); - - /* lines 1586 linux-natsemi.c uses cable magic - * testing this feature is required or not - */ - do_cable_magic ( netdev ); - init_phy_fixup ( netdev ); - - - - /* mask the interrupts. note interrupt is not enabled here - */ - return 0; - -memory_alloc_err: - - /* this block frees the previously allocated buffers - * if memory for all the buffers is not available - */ - i = 0; - while ( nat->rx[i].cmdsts == RX_BUF_SIZE ) { - free_iob ( nat->iobuf[i] ); - i++; - } - return -ENOMEM; + init_at93c46 ( &np->eeprom, 16 ); + np->eeprom.bus = &np->spibit.bus; + np->nvo.nvs = &np->eeprom.nvs; + np->nvo.fragments = natsemi_nvo_fragments; } /** - * Close NIC - * - * @v netdev Net device - */ -static void nat_close ( struct net_device *netdev ) { - struct natsemi_nic *nat = netdev->priv; - int i; - - /* Reset the hardware to disable everything in one go - */ - nat_reset ( nat ); - - /* Free RX ring - */ - for ( i = 0; i < NUM_RX_DESC ; i++ ) { - - free_iob ( nat->iobuf[i] ); - } -} - -/** - * Transmit packet - * - * @v netdev Network device - * @v iobuf I/O buffer - * @ret rc Return status code - */ -static int nat_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { - struct natsemi_nic *nat = netdev->priv; - - /* check for space in TX ring - */ - if ( nat->tx[nat->tx_cur].cmdsts != 0 ) { - DBG ( "TX overflow\n" ); - return -ENOBUFS; - } - - /* to be used in netdev_tx_complete - */ - nat->tx_iobuf[nat->tx_cur] = iobuf; - - /* Pad and align packet has not been used because its not required here - * iob_pad ( iobuf, ETH_ZLEN ); can be used to achieve it - */ - - /* Add to TX ring - */ - DBG ( "TX id %d at %lx + %x\n", nat->tx_cur, - virt_to_bus ( &iobuf->data ), iob_len ( iobuf ) ); - - nat->tx[nat->tx_cur].bufptr = virt_to_bus ( iobuf->data ); - nat->tx[nat->tx_cur].cmdsts = iob_len ( iobuf ) | OWN; - - /* increment the circular buffer pointer to the next buffer location - */ - nat->tx_cur = ( nat->tx_cur + 1 ) % TX_RING_SIZE; - - /*start the transmitter - */ - outl ( TxOn, nat->ioaddr + ChipCmd ); - - return 0; -} - -/** - * Poll for received packets - * - * @v netdev Network device - * @v rx_quota Maximum number of packets to receive - */ -static void nat_poll ( struct net_device *netdev) { - struct natsemi_nic *nat = netdev->priv; - unsigned int status; - unsigned int rx_status; - unsigned int intr_status; - unsigned int rx_len; - struct io_buffer *rx_iob; - int i; - - /* read the interrupt register - */ - intr_status = inl ( nat->ioaddr + IntrStatus ); - if ( !intr_status ) - goto end; - - /* check the status of packets given to card for transmission - */ - DBG ( "Intr status %X\n",intr_status ); - - i = nat->tx_dirty; - while ( i!= nat->tx_cur ) { - status = nat->tx[nat->tx_dirty].cmdsts; - DBG ( "value of tx_dirty = %d tx_cur=%d status=%X\n", - nat->tx_dirty,nat->tx_cur,status ); - - /* check if current packet has been transmitted or not - */ - if ( status & OWN ) - break; - - /* Check if any errors in transmission - */ - if (! ( status & DescPktOK ) ) { - DBG ( "Error in sending Packet status:%X\n", - (unsigned int) status ); - netdev_tx_complete_err ( netdev,nat->tx_iobuf[nat->tx_dirty],-EINVAL ); - } else { - DBG ( "Success in transmitting Packet\n" ); - netdev_tx_complete ( netdev,nat->tx_iobuf[nat->tx_dirty] ); - } - - /* setting cmdsts zero, indicating that it can be reused - */ - nat->tx[nat->tx_dirty].cmdsts = 0; - nat->tx_dirty = ( nat->tx_dirty + 1 ) % TX_RING_SIZE; - i = ( i + 1 ) % TX_RING_SIZE; - } - - /* Handle received packets - */ - rx_status = (unsigned int) nat->rx[nat->rx_cur].cmdsts; - while ( ( rx_status & OWN ) ) { - rx_len = ( rx_status & DSIZE ) - CRC_SIZE; - DBG ( " Status of received packet = %X , Lenght of Packet = %X\n", - rx_status,rx_len ); - - /*check for the corrupt packet - */ - if ( ( rx_status & ( DescMore|DescPktOK|RxTooLong ) ) != DescPktOK) { - DBG ( "natsemi_poll: Corrupted packet received, " - "buffer status = %X \n", - (unsigned int) nat->rx[nat->rx_cur].cmdsts ); - //DBG_HD ( nat->iobuf[nat->rx_cur]->data,rx_len); - netdev_rx_err ( netdev,NULL,-EINVAL ); - } else { - rx_iob = alloc_iob ( rx_len ); - - if ( !rx_iob ) - /* leave packet for next call to poll - */ - goto end; - memcpy ( iob_put ( rx_iob,rx_len ), - nat->iobuf[nat->rx_cur]->data,rx_len ); - DBG ( "received packet\n" ); - //DBG_HD ( nat->iobuf[nat->rx_cur]->data,30); - - /* add to the receive queue. - */ - netdev_rx ( netdev,rx_iob ); - } - nat->rx[nat->rx_cur].cmdsts = RX_BUF_SIZE; - nat->rx_cur = ( nat->rx_cur + 1 ) % NUM_RX_DESC; - rx_status = nat->rx[nat->rx_cur].cmdsts; - } -end: - - /* re-enable the potentially idle receive state machine - */ - outl ( RxOn, nat->ioaddr + ChipCmd ); -} - -/** - * Enable/disable interrupts - * - * @v netdev Network device - * @v enable Interrupts should be enabled - */ -static void nat_irq ( struct net_device *netdev, int enable ) { - struct natsemi_nic *nat = netdev->priv; - - outl ( ( enable ? ( RxOk|RxErr|TxOk|TxErr ) :0 ), - nat->ioaddr + IntrMask); - outl ( ( enable ? 1:0 ),nat->ioaddr + IntrEnable ); -} - - - - - -/** natsemi net device operations */ -static struct net_device_operations nat_operations = { - .open = nat_open, - .close = nat_close, - .transmit = nat_transmit, - .poll = nat_poll, - .irq = nat_irq, -}; - -/* * Probe PCI device * * @v pci PCI device * @v id PCI ID * @ret rc Return status code */ -static int nat_probe ( struct pci_device *pci, - const struct pci_device_id *id __unused ) { +static int natsemi_probe (struct pci_device *pci, + const struct pci_device_id *id __unused) { struct net_device *netdev; - struct natsemi_nic *nat = NULL; - int rc; - int i; + struct natsemi_private *np = NULL; uint8_t ll_addr_encoded[MAX_LL_ADDR_LEN]; - uint8_t last = 0; - uint8_t last1 = 0; + uint8_t last=0,last1=0; uint8_t prev_bytes[2]; + int i; + int rc; /* Allocate net device */ - netdev = alloc_etherdev ( sizeof ( *nat ) ); - if ( ! netdev ) + netdev = alloc_etherdev (sizeof (*np)); + if (! netdev) return -ENOMEM; - netdev_init ( netdev,&nat_operations ); - nat = netdev->priv; - pci_set_drvdata ( pci, netdev ); + + netdev_init (netdev, &natsemi_operations); + np = netdev->priv; + pci_set_drvdata (pci, netdev); netdev->dev = &pci->dev; - memset ( nat, 0, sizeof ( *nat ) ); - nat->ioaddr = pci->ioaddr; + memset (np, 0, sizeof (*np)); + np->ioaddr = pci->ioaddr; - /* Fix up PCI device - */ - adjust_pci_device ( pci ); + adjust_pci_device (pci); - /* Reset the NIC, set up EEPROM access and read MAC address - */ - nat_reset ( nat ); - nat_init_eeprom ( nat ); - nvs_read ( &nat->eeprom.nvs, EE_MAC-1, prev_bytes, 1 ); - nvs_read ( &nat->eeprom.nvs, EE_MAC, ll_addr_encoded, ETH_ALEN ); + natsemi_reset (netdev); + natsemi_init_eeprom ( np ); + nvs_read ( &np->eeprom.nvs, EE_MAC-1, prev_bytes, 1 ); + nvs_read ( &np->eeprom.nvs, EE_MAC, ll_addr_encoded, ETH_ALEN ); /* decoding the MAC address read from NVS * and save it in netdev->ll_addr @@ -905,22 +206,15 @@ static int nat_probe ( struct pci_device *pci, last = last1; } - /* Register network device - */ - if ( ( rc = register_netdev ( netdev ) ) != 0 ) + if ((rc = register_netdev (netdev)) != 0) goto err_register_netdev; return 0; err_register_netdev: - /* Disable NIC - */ - nat_reset ( nat ); - - /* Free net device - */ - netdev_put ( netdev ); + natsemi_reset (netdev); + netdev_put (netdev); return rc; } @@ -929,16 +223,375 @@ err_register_netdev: * * @v pci PCI device */ -static void nat_remove ( struct pci_device *pci ) { - struct net_device *netdev = pci_get_drvdata ( pci ); - struct natsemi_nic *nat = netdev->priv; +static void natsemi_remove (struct pci_device *pci) { + struct net_device *netdev = pci_get_drvdata (pci); - if ( nat->nvo.nvs ) - nvo_unregister ( &nat->nvo ); + unregister_netdev (netdev); + natsemi_reset (netdev); + netdev_put (netdev); +} + +/** + * Reset NIC + * + * @v NATSEMI NIC + * + * Issues a hardware reset and waits for the reset to complete. + */ +static void natsemi_reset (struct net_device *netdev) +{ + struct natsemi_private *np = netdev->priv; + int i; + u32 cfg; + u32 wcsr; + u32 rfcr; + u16 pmatch[3]; + u16 sopass[3]; + + natsemi_irq (netdev, 0); + + /* + * Resetting the chip causes some registers to be lost. + * Natsemi suggests NOT reloading the EEPROM while live, so instead + * we save the state that would have been loaded from EEPROM + * on a normal power-up (see the spec EEPROM map). + */ + + /* CFG */ + cfg = inl (np->ioaddr + ChipConfig) & CFG_RESET_SAVE; + + /* WCSR */ + wcsr = inl (np->ioaddr + WOLCmd) & WCSR_RESET_SAVE; + + /* RFCR */ + rfcr = readl (np->ioaddr + RxFilterAddr) & RFCR_RESET_SAVE; + + /* PMATCH */ + for (i = 0; i < 3; i++) { + outl(i*2, np->ioaddr + RxFilterAddr); + pmatch[i] = inw(np->ioaddr + RxFilterData); + } + + /* SOPAS */ + for (i = 0; i < 3; i++) { + outl(0xa+(i*2), np->ioaddr + RxFilterAddr); + sopass[i] = inw(np->ioaddr + RxFilterData); + } + + /* now whack the chip */ + outl(ChipReset, np->ioaddr + ChipCmd); + for (i=0; iioaddr + ChipCmd) & ChipReset)) + break; + udelay(5); + } + if (i == NATSEMI_HW_TIMEOUT) { + printf ("natsemi_reset: reset did not complete in %d usec.\n", i*5); + } + + /* restore CFG */ + cfg |= inl(np->ioaddr + ChipConfig) & ~CFG_RESET_SAVE; + cfg &= ~(CfgExtPhy | CfgPhyDis); + outl (cfg, np->ioaddr + ChipConfig); + + /* restore WCSR */ + wcsr |= inl (np->ioaddr + WOLCmd) & ~WCSR_RESET_SAVE; + outl (wcsr, np->ioaddr + WOLCmd); + + /* read RFCR */ + rfcr |= inl (np->ioaddr + RxFilterAddr) & ~RFCR_RESET_SAVE; + + /* restore PMATCH */ + for (i = 0; i < 3; i++) { + outl (i*2, np->ioaddr + RxFilterAddr); + outw (pmatch[i], np->ioaddr + RxFilterData); + } + for (i = 0; i < 3; i++) { + outl (0xa+(i*2), np->ioaddr + RxFilterAddr); + outw (sopass[i], np->ioaddr + RxFilterData); + } + /* restore RFCR */ + outl (rfcr, np->ioaddr + RxFilterAddr); +} + +/** + * Open NIC + * + * @v netdev Net device + * @ret rc Return status code + */ +static int natsemi_open (struct net_device *netdev) +{ + struct natsemi_private *np = netdev->priv; + uint32_t tx_config, rx_config; + int i; + + /* Disable PME: + * The PME bit is initialized from the EEPROM contents. + * PCI cards probably have PME disabled, but motherboard + * implementations may have PME set to enable WakeOnLan. + * With PME set the chip will scan incoming packets but + * nothing will be written to memory. + */ + SavedClkRun = inl (np->ioaddr + ClkRun); + outl (SavedClkRun & ~0x100, np->ioaddr + ClkRun); + + /* Set MAC address in NIC + */ + for (i = 0 ; i < ETH_ALEN ; i+=2) { + outl (i, np->ioaddr + RxFilterAddr); + outw (netdev->ll_addr[i] + (netdev->ll_addr[i + 1] << 8), + np->ioaddr + RxFilterData); + } + + /* Setup Tx Ring + */ + np->tx_cur = 0; + np->tx_dirty = 0; + for (i = 0 ; i < TX_RING_SIZE ; i++) { + np->tx[i].link = virt_to_bus ((i + 1 < TX_RING_SIZE) ? &np->tx[i + 1] : &np->tx[0]); + np->tx[i].cmdsts = 0; + np->tx[i].bufptr = 0; + } + outl (virt_to_bus (&np->tx[0]),np->ioaddr + TxRingPtr); + + DBG ("Natsemi Tx descriptor loaded with: %#08x\n", + (unsigned int) inl (np->ioaddr + TxRingPtr)); + + /* Setup RX ring + */ + np->rx_cur = 0; + for (i = 0 ; i < NUM_RX_DESC ; i++) { + np->iobuf[i] = alloc_iob (RX_BUF_SIZE); + if (! np->iobuf[i]) + goto memory_alloc_err; + np->rx[i].link = virt_to_bus ((i + 1 < NUM_RX_DESC) + ? &np->rx[i + 1] : &np->rx[0]); + np->rx[i].cmdsts = RX_BUF_SIZE; + np->rx[i].bufptr = virt_to_bus (np->iobuf[i]->data); + DBG (" Address of iobuf [%d] = %#08x and iobuf->data = %#08x \n", i, + (unsigned int) &np->iobuf[i], (unsigned int) &np->iobuf[i]->data); + } + outl (virt_to_bus (&np->rx[0]), np->ioaddr + RxRingPtr); + + DBG ("Natsemi Rx descriptor loaded with: %#08x\n", + (unsigned int) inl (np->ioaddr + RxRingPtr)); + + /* Setup RX Filter + */ + outl (RxFilterEnable | AcceptBroadcast | AcceptAllMulticast | AcceptMyPhys, + np->ioaddr + RxFilterAddr); + + /* Initialize other registers. + * Configure the PCI bus bursts and FIFO thresholds. + * Configure for standard, in-spec Ethernet. + */ + if (inl (np->ioaddr + ChipConfig) & 0x20000000) { /* Full duplex */ + DBG ("Full duplex\n"); + tx_config = 0xD0801002 | 0xC0000000; + rx_config = 0x10000020 | 0x10000000; + } else { + DBG ("Half duplex\n"); + tx_config = 0x10801002 & ~0xC0000000; + rx_config = 0x00000020 & ~0x10000000; + } + outl (tx_config, np->ioaddr + TxConfig); + outl (rx_config, np->ioaddr + RxConfig); + + DBG ("Tx config register = %#08x Rx config register = %#08x\n", + (unsigned int) inl (np->ioaddr + TxConfig), + (unsigned int) inl (np->ioaddr + RxConfig)); + + /*Set the Interrupt Mask register + */ + outl((RxOk|RxErr|TxOk|TxErr),np->ioaddr + IntrMask); + /*start the receiver + */ + outl (RxOn, np->ioaddr + ChipCmd); + + return 0; + +memory_alloc_err: + + /* Frees any allocated buffers when memory + * for all buffers requested is not available + */ + i = 0; + while (np->rx[i].cmdsts == RX_BUF_SIZE) { + free_iob (np->iobuf[i]); + i++; + } + return -ENOMEM; +} + +/** + * Close NIC + * + * @v netdev Net device + */ +static void natsemi_close (struct net_device *netdev) +{ + struct natsemi_private *np = netdev->priv; + int i; + + natsemi_reset (netdev); + + for (i = 0; i < NUM_RX_DESC ; i++) { + free_iob (np->iobuf[i]); + } +} + +/** + * Transmit packet + * + * @v netdev Network device + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int natsemi_transmit (struct net_device *netdev, struct io_buffer *iobuf) +{ + struct natsemi_private *np = netdev->priv; + + if (np->tx[np->tx_cur].cmdsts != 0) { + DBG ("TX overflow\n"); + return -ENOBUFS; + } + + /* Used by netdev_tx_complete () + */ + np->tx_iobuf[np->tx_cur] = iobuf; + + /* Pad and align packet has not been used because its not required + * by the hardware. + * iob_pad (iobuf, ETH_ZLEN); + * can be used to achieve it, if required + */ + + /* Add the packet to TX ring + */ + np->tx[np->tx_cur].bufptr = virt_to_bus (iobuf->data); + np->tx[np->tx_cur].cmdsts = iob_len (iobuf) | OWN; + + DBG ("TX id %d at %#08x + %#08x\n", np->tx_cur, + (unsigned int) virt_to_bus (&iobuf->data), iob_len (iobuf)); + + /* increment the circular buffer pointer to the next buffer location + */ + np->tx_cur = (np->tx_cur + 1) % TX_RING_SIZE; + + /*start the transmitter + */ + outl (TxOn, np->ioaddr + ChipCmd); + + return 0; +} + +/** + * Poll for received packets + * + * @v netdev Network device + */ +static void natsemi_poll (struct net_device *netdev) +{ + struct natsemi_private *np = netdev->priv; + unsigned int tx_status; + unsigned int rx_status; + unsigned int intr_status; + unsigned int rx_len; + struct io_buffer *rx_iob; + int i; + + /* read the interrupt register + */ + intr_status = inl (np->ioaddr + IntrStatus); + + if (!intr_status) + goto end; + + DBG ("natsemi_poll: intr_status = %#08x\n", intr_status); + + /* Check status of transmitted packets + */ + i = np->tx_dirty; + while (i != np->tx_cur) { + tx_status = np->tx[np->tx_dirty].cmdsts; + + DBG ("tx_dirty = %d tx_cur=%d tx_status=%#08x\n", + np->tx_dirty, np->tx_cur, tx_status); - unregister_netdev ( netdev ); - nat_reset ( nat ); - netdev_put ( netdev ); + if (tx_status & OWN) + break; + + if (! (tx_status & DescPktOK)) { + netdev_tx_complete_err (netdev,np->tx_iobuf[np->tx_dirty],-EINVAL); + DBG ("Error transmitting packet, tx_status: %#08x\n", + (unsigned int) tx_status); + } else { + netdev_tx_complete (netdev, np->tx_iobuf[np->tx_dirty]); + DBG ("Success transmitting packet\n"); + } + + np->tx[np->tx_dirty].cmdsts = 0; + np->tx_dirty = (np->tx_dirty + 1) % TX_RING_SIZE; + i = (i + 1) % TX_RING_SIZE; + } + + /* Process received packets + */ + rx_status = (unsigned int) np->rx[np->rx_cur].cmdsts; + while ((rx_status & OWN)) { + rx_len = (rx_status & DSIZE) - CRC_SIZE; + + DBG ("Received packet, rx_curr = %d, rx_status = %#08x, rx_len = %d\n", + np->rx_cur, rx_status, rx_len); + + if ((rx_status & (DescMore | DescPktOK | RxTooLong)) != DescPktOK) { + netdev_rx_err (netdev, NULL, -EINVAL); + + DBG ("natsemi_poll: Corrupted packet received!" + " Status = %#08x\n", + (unsigned int) np->rx[np->rx_cur].cmdsts); + //DBG_HD (np->iobuf[np->rx_cur]->data, 30); + + } else { + + //DBG_HD (np->iobuf[np->rx_cur]->data, 30); + + /* If unable allocate space for this packet, + * try again next poll + */ + rx_iob = alloc_iob (rx_len); + if (! rx_iob) + goto end; + memcpy (iob_put (rx_iob, rx_len), + np->iobuf[np->rx_cur]->data, rx_len); + /* Add this packet to the receive queue. + */ + netdev_rx (netdev, rx_iob); + } + np->rx[np->rx_cur].cmdsts = RX_BUF_SIZE; + np->rx_cur = (np->rx_cur + 1) % NUM_RX_DESC; + rx_status = np->rx[np->rx_cur].cmdsts; + } +end: + /* re-enable the potentially idle receive state machine + */ + outl (RxOn, np->ioaddr + ChipCmd); +} + +/** + * Enable/disable interrupts + * + * @v netdev Network device + * @v enable Non-zero for enable, zero for disable + */ +static void natsemi_irq (struct net_device *netdev, int enable) +{ + struct natsemi_private *np = netdev->priv; + + outl ((enable ? (RxOk | RxErr | TxOk|TxErr) : 0), + np->ioaddr + IntrMask); + outl ((enable ? 1 : 0), np->ioaddr + IntrEnable); } static struct pci_device_id natsemi_nics[] = { @@ -947,7 +600,7 @@ static struct pci_device_id natsemi_nics[] = { struct pci_driver natsemi_driver __pci_driver = { .ids = natsemi_nics, - .id_count = ( sizeof ( natsemi_nics ) / sizeof ( natsemi_nics[0] ) ), - .probe = nat_probe, - .remove = nat_remove, + .id_count = (sizeof (natsemi_nics) / sizeof (natsemi_nics[0])), + .probe = natsemi_probe, + .remove = natsemi_remove, }; From 04962a0b312cd4824ab47ad53fbf98f3c3c4acd4 Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Sat, 14 Jul 2007 00:44:56 -0400 Subject: [PATCH 31/33] added natsemi.h --- src/drivers/net/natsemi.h | 232 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 src/drivers/net/natsemi.h diff --git a/src/drivers/net/natsemi.h b/src/drivers/net/natsemi.h new file mode 100644 index 00000000..d13d7015 --- /dev/null +++ b/src/drivers/net/natsemi.h @@ -0,0 +1,232 @@ +#define NATSEMI_HW_TIMEOUT 400 + +#define TX_RING_SIZE 4 +#define NUM_RX_DESC 4 +#define RX_BUF_SIZE 1536 +#define OWN 0x80000000 +#define DSIZE 0x00000FFF +#define CRC_SIZE 4 + +struct natsemi_tx { + uint32_t link; + uint32_t cmdsts; + uint32_t bufptr; +}; + +struct natsemi_rx { + uint32_t link; + uint32_t cmdsts; + uint32_t bufptr; +}; + +struct natsemi_private { + unsigned short ioaddr; + unsigned short tx_cur; + unsigned short tx_dirty; + unsigned short rx_cur; + struct natsemi_tx tx[TX_RING_SIZE]; + struct natsemi_rx rx[NUM_RX_DESC]; + + /* need to add iobuf as we cannot free iobuf->data in close without this + * alternatively substracting sizeof(head) and sizeof(list_head) can also + * give the same. + */ + struct io_buffer *iobuf[NUM_RX_DESC]; + + /* netdev_tx_complete needs pointer to the iobuf of the data so as to free + * it from the memory. + */ + struct io_buffer *tx_iobuf[TX_RING_SIZE]; + struct spi_bit_basher spibit; + struct spi_device eeprom; + struct nvo_block nvo; +}; + +/* + * Support for fibre connections on Am79C874: + * This phy needs a special setup when connected to a fibre cable. + * http://www.amd.com/files/connectivitysolutions/networking/archivednetworking/22235.pdf + */ +#define PHYID_AM79C874 0x0022561b + +enum { + MII_MCTRL = 0x15, /* mode control register */ + MII_FX_SEL = 0x0001, /* 100BASE-FX (fiber) */ + MII_EN_SCRM = 0x0004, /* enable scrambler (tp) */ +}; + + + +/* values we might find in the silicon revision register */ +#define SRR_DP83815_C 0x0302 +#define SRR_DP83815_D 0x0403 +#define SRR_DP83816_A4 0x0504 +#define SRR_DP83816_A5 0x0505 + +/* NATSEMI: Offsets to the device registers. + * Unlike software-only systems, device drivers interact with complex hardware. + * It's not useful to define symbolic names for every register bit in the + * device. + */ +enum register_offsets { + ChipCmd = 0x00, + ChipConfig = 0x04, + EECtrl = 0x08, + PCIBusCfg = 0x0C, + IntrStatus = 0x10, + IntrMask = 0x14, + IntrEnable = 0x18, + TxRingPtr = 0x20, + TxConfig = 0x24, + RxRingPtr = 0x30, + RxConfig = 0x34, + ClkRun = 0x3C, + WOLCmd = 0x40, + PauseCmd = 0x44, + RxFilterAddr = 0x48, + RxFilterData = 0x4C, + BootRomAddr = 0x50, + BootRomData = 0x54, + SiliconRev = 0x58, + StatsCtrl = 0x5C, + StatsData = 0x60, + RxPktErrs = 0x60, + RxMissed = 0x68, + RxCRCErrs = 0x64, + PCIPM = 0x44, + PhyStatus = 0xC0, + MIntrCtrl = 0xC4, + MIntrStatus = 0xC8, + + /* These are from the spec, around page 78... on a separate table. + */ + PGSEL = 0xCC, + PMDCSR = 0xE4, + TSTDAT = 0xFC, + DSPCFG = 0xF4, + SDCFG = 0x8C, + BasicControl = 0x80, + BasicStatus = 0x84 + +}; + +/* the values for the 'magic' registers above (PGSEL=1) */ +#define PMDCSR_VAL 0x189c /* enable preferred adaptation circuitry */ +#define TSTDAT_VAL 0x0 +#define DSPCFG_VAL 0x5040 +#define SDCFG_VAL 0x008c /* set voltage thresholds for Signal Detect */ +#define DSPCFG_LOCK 0x20 /* coefficient lock bit in DSPCFG */ +#define DSPCFG_COEF 0x1000 /* see coefficient (in TSTDAT) bit in DSPCFG */ +#define TSTDAT_FIXED 0xe8 /* magic number for bad coefficients */ + +/* Bit in ChipCmd. + */ +enum ChipCmdBits { + ChipReset = 0x100, + RxReset = 0x20, + TxReset = 0x10, + RxOff = 0x08, + RxOn = 0x04, + TxOff = 0x02, + TxOn = 0x01 +}; + +enum ChipConfig_bits { + CfgPhyDis = 0x200, + CfgPhyRst = 0x400, + CfgExtPhy = 0x1000, + CfgAnegEnable = 0x2000, + CfgAneg100 = 0x4000, + CfgAnegFull = 0x8000, + CfgAnegDone = 0x8000000, + CfgFullDuplex = 0x20000000, + CfgSpeed100 = 0x40000000, + CfgLink = 0x80000000, +}; + + +/* Bits in the RxMode register. + */ +enum rx_mode_bits { + AcceptErr = 0x20, + AcceptRunt = 0x10, + AcceptBroadcast = 0xC0000000, + AcceptMulticast = 0x00200000, + AcceptAllMulticast = 0x20000000, + AcceptAllPhys = 0x10000000, + AcceptMyPhys = 0x08000000, + RxFilterEnable = 0x80000000 +}; + +/* Bits in network_desc.status + */ +enum desc_status_bits { + DescOwn = 0x80000000, + DescMore = 0x40000000, + DescIntr = 0x20000000, + DescNoCRC = 0x10000000, + DescPktOK = 0x08000000, + RxTooLong = 0x00400000 +}; + +/*Bits in Interrupt Mask register + */ +enum Intr_mask_register_bits { + RxOk = 0x001, + RxErr = 0x004, + TxOk = 0x040, + TxErr = 0x100 +}; + +enum MIntrCtrl_bits { + MICRIntEn = 0x2, +}; + +static uint32_t SavedClkRun; + +/* CFG bits [13:16] [18:23] */ +#define CFG_RESET_SAVE 0xfde000 +/* WCSR bits [0:4] [9:10] */ +#define WCSR_RESET_SAVE 0x61f +/* RFCR bits [20] [22] [27:31] */ +#define RFCR_RESET_SAVE 0xf8500000; + +/* Delay between EEPROM clock transitions. + No extra delay is needed with 33Mhz PCI, but future 66Mhz access may need + a delay. */ +#define eeprom_delay(ee_addr) inl(ee_addr) + +enum EEPROM_Ctrl_Bits { + EE_ShiftClk = 0x04, + EE_DataIn = 0x01, + EE_ChipSelect = 0x08, + EE_DataOut = 0x02 +}; + +#define EE_Write0 (EE_ChipSelect) +#define EE_Write1 (EE_ChipSelect | EE_DataIn) + +/* The EEPROM commands include the alway-set leading bit. */ +enum EEPROM_Cmds { + EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6), +}; + +/* EEPROM access , values are devices specific + */ +#define EE_CS 0x08 /* EEPROM chip select */ +#define EE_SK 0x04 /* EEPROM shift clock */ +#define EE_DI 0x01 /* Data in */ +#define EE_DO 0x02 /* Data out */ + +/* Offsets within EEPROM (these are word offsets) + */ +#define EE_MAC 7 +#define EE_REG EECtrl + +static const uint8_t natsemi_ee_bits[] = { + [SPI_BIT_SCLK] = EE_SK, + [SPI_BIT_MOSI] = EE_DI, + [SPI_BIT_MISO] = EE_DO, + [SPI_BIT_SS(0)] = EE_CS, +}; + From fc47f2a4ce503c0b4509259292ab9500fc758674 Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Sat, 14 Jul 2007 15:36:15 -0400 Subject: [PATCH 32/33] replaces printf with dbg --- src/drivers/net/natsemi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index bd97ebdc..2ad9b540 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -286,7 +286,7 @@ static void natsemi_reset (struct net_device *netdev) udelay(5); } if (i == NATSEMI_HW_TIMEOUT) { - printf ("natsemi_reset: reset did not complete in %d usec.\n", i*5); + DBG ("natsemi_reset: reset did not complete in %d usec.\n", i*5); } /* restore CFG */ From 37517f7752628007bbb655c6f3835a94b9a1876d Mon Sep 17 00:00:00 2001 From: Udayan Kumar Date: Sat, 14 Jul 2007 20:01:30 -0400 Subject: [PATCH 33/33] removed type casting from DBG statements. --- src/drivers/net/natsemi.c | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index 2ad9b540..4928f1b8 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -59,7 +59,6 @@ */ #include -#include #include #include #include @@ -80,7 +79,7 @@ static int natsemi_spi_read_bit ( struct bit_basher *, unsigned int ); static void natsemi_spi_write_bit ( struct bit_basher *,unsigned int, unsigned long ); -void natsemi_init_eeprom ( struct natsemi_private * ); +static void natsemi_init_eeprom ( struct natsemi_private * ); static int natsemi_probe (struct pci_device *pci, const struct pci_device_id *id); static void natsemi_reset (struct net_device *netdev); static int natsemi_open (struct net_device *netdev); @@ -142,7 +141,7 @@ static struct nvo_fragment natsemi_nvo_fragments[] = { * * @v NAT NATSEMI NIC */ - void natsemi_init_eeprom ( struct natsemi_private *np ) { +static void natsemi_init_eeprom ( struct natsemi_private *np ) { /* Initialise three-wire bus */ @@ -355,8 +354,8 @@ static int natsemi_open (struct net_device *netdev) } outl (virt_to_bus (&np->tx[0]),np->ioaddr + TxRingPtr); - DBG ("Natsemi Tx descriptor loaded with: %#08x\n", - (unsigned int) inl (np->ioaddr + TxRingPtr)); + DBG ("Natsemi Tx descriptor loaded with: %#08lx\n", + inl (np->ioaddr + TxRingPtr)); /* Setup RX ring */ @@ -369,13 +368,13 @@ static int natsemi_open (struct net_device *netdev) ? &np->rx[i + 1] : &np->rx[0]); np->rx[i].cmdsts = RX_BUF_SIZE; np->rx[i].bufptr = virt_to_bus (np->iobuf[i]->data); - DBG (" Address of iobuf [%d] = %#08x and iobuf->data = %#08x \n", i, - (unsigned int) &np->iobuf[i], (unsigned int) &np->iobuf[i]->data); + DBG (" Address of iobuf [%d] = %p and iobuf->data = %p \n", i, + &np->iobuf[i], &np->iobuf[i]->data); } outl (virt_to_bus (&np->rx[0]), np->ioaddr + RxRingPtr); - DBG ("Natsemi Rx descriptor loaded with: %#08x\n", - (unsigned int) inl (np->ioaddr + RxRingPtr)); + DBG ("Natsemi Rx descriptor loaded with: %#08lx\n", + inl (np->ioaddr + RxRingPtr)); /* Setup RX Filter */ @@ -398,9 +397,9 @@ static int natsemi_open (struct net_device *netdev) outl (tx_config, np->ioaddr + TxConfig); outl (rx_config, np->ioaddr + RxConfig); - DBG ("Tx config register = %#08x Rx config register = %#08x\n", - (unsigned int) inl (np->ioaddr + TxConfig), - (unsigned int) inl (np->ioaddr + RxConfig)); + DBG ("Tx config register = %#08lx Rx config register = %#08lx\n", + inl (np->ioaddr + TxConfig), + inl (np->ioaddr + RxConfig)); /*Set the Interrupt Mask register */ @@ -472,8 +471,8 @@ static int natsemi_transmit (struct net_device *netdev, struct io_buffer *iobuf) np->tx[np->tx_cur].bufptr = virt_to_bus (iobuf->data); np->tx[np->tx_cur].cmdsts = iob_len (iobuf) | OWN; - DBG ("TX id %d at %#08x + %#08x\n", np->tx_cur, - (unsigned int) virt_to_bus (&iobuf->data), iob_len (iobuf)); + DBG ("TX id %d at %#08lx + %#08x\n", np->tx_cur, + virt_to_bus (&iobuf->data), iob_len (iobuf)); /* increment the circular buffer pointer to the next buffer location */ @@ -525,7 +524,7 @@ static void natsemi_poll (struct net_device *netdev) if (! (tx_status & DescPktOK)) { netdev_tx_complete_err (netdev,np->tx_iobuf[np->tx_dirty],-EINVAL); DBG ("Error transmitting packet, tx_status: %#08x\n", - (unsigned int) tx_status); + tx_status); } else { netdev_tx_complete (netdev, np->tx_iobuf[np->tx_dirty]); DBG ("Success transmitting packet\n"); @@ -549,13 +548,11 @@ static void natsemi_poll (struct net_device *netdev) netdev_rx_err (netdev, NULL, -EINVAL); DBG ("natsemi_poll: Corrupted packet received!" - " Status = %#08x\n", - (unsigned int) np->rx[np->rx_cur].cmdsts); - //DBG_HD (np->iobuf[np->rx_cur]->data, 30); + " Status = %#08lx\n", + np->rx[np->rx_cur].cmdsts); } else { - //DBG_HD (np->iobuf[np->rx_cur]->data, 30); /* If unable allocate space for this packet, * try again next poll