From ad4f58d410de36b2c2ceb560167b16f53a3de5d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Jamr=C3=B3z?= Date: Sat, 13 Jul 2013 16:11:50 +0200 Subject: [PATCH] [rhine] Rewrite VIA Rhine driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the old via-rhine driver with a new version using the iPXE API. Includes fixes by Thomas Miletich for: - MMIO access - Link detection - RX completion in RX overflow case - Reset and EEPROM reloading - CRC stripping - Missing cpu_to_le32() calls - Missing memory barriers Signed-off-by: Adrian Jamróz Modified-by: Thomas Miletich Tested-by: Thomas Miletich Tested-by: Robin Smidsrød Modified-by: Michael Brown Tested-by: Michael Brown Signed-off-by: Michael Brown --- src/drivers/net/rhine.c | 787 +++++++++++++++++++ src/drivers/net/rhine.h | 250 ++++++ src/drivers/net/via-rhine.c | 1447 ----------------------------------- src/include/ipxe/errfile.h | 2 +- 4 files changed, 1038 insertions(+), 1448 deletions(-) create mode 100644 src/drivers/net/rhine.c create mode 100644 src/drivers/net/rhine.h delete mode 100644 src/drivers/net/via-rhine.c diff --git a/src/drivers/net/rhine.c b/src/drivers/net/rhine.c new file mode 100644 index 00000000..42bc124e --- /dev/null +++ b/src/drivers/net/rhine.c @@ -0,0 +1,787 @@ +/* + * Copyright (C) 2012 Adrian Jamroz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rhine.h" + +/** @file + * + * VIA Rhine network driver + * + */ + +/****************************************************************************** + * + * MII interface + * + ****************************************************************************** + */ + +/** + * Read from MII register + * + * @v mii MII interface + * @v reg Register address + * @ret value Data read, or negative error + */ +static int rhine_mii_read ( struct mii_interface *mii, unsigned int reg ) { + struct rhine_nic *rhn = container_of ( mii, struct rhine_nic, mii ); + unsigned int timeout = RHINE_TIMEOUT_US; + uint8_t cr; + + DBGC2 ( rhn, "RHINE %p MII read reg %d\n", rhn, reg ); + + /* Initiate read */ + writeb ( reg, rhn->regs + RHINE_MII_ADDR ); + cr = readb ( rhn->regs + RHINE_MII_CR ); + writeb ( ( cr | RHINE_MII_CR_RDEN ), rhn->regs + RHINE_MII_CR ); + + /* Wait for read to complete */ + while ( timeout-- ) { + udelay ( 1 ); + cr = readb ( rhn->regs + RHINE_MII_CR ); + if ( ! ( cr & RHINE_MII_CR_RDEN ) ) + return readw ( rhn->regs + RHINE_MII_RDWR ); + } + + DBGC ( rhn, "RHINE %p MII read timeout\n", rhn ); + return -ETIMEDOUT; +} + +/** + * Write to MII register + * + * @v mii MII interface + * @v reg Register address + * @v data Data to write + * @ret rc Return status code + */ +static int rhine_mii_write ( struct mii_interface *mii, unsigned int reg, + unsigned int data ) { + struct rhine_nic *rhn = container_of ( mii, struct rhine_nic, mii ); + unsigned int timeout = RHINE_TIMEOUT_US; + uint8_t cr; + + DBGC2 ( rhn, "RHINE %p MII write reg %d data 0x%04x\n", + rhn, reg, data ); + + /* Initiate write */ + writeb ( reg, rhn->regs + RHINE_MII_ADDR ); + writew ( data, rhn->regs + RHINE_MII_RDWR ); + cr = readb ( rhn->regs + RHINE_MII_CR ); + writeb ( ( cr | RHINE_MII_CR_WREN ), rhn->regs + RHINE_MII_CR ); + + /* Wait for write to complete */ + while ( timeout-- ) { + udelay ( 1 ); + cr = readb ( rhn->regs + RHINE_MII_CR ); + if ( ! ( cr & RHINE_MII_CR_WREN ) ) + return 0; + } + + DBGC ( rhn, "RHINE %p MII write timeout\n", rhn ); + return -ETIMEDOUT; +} + +/** Rhine MII operations */ +static struct mii_operations rhine_mii_operations = { + .read = rhine_mii_read, + .write = rhine_mii_write, +}; + +/** + * Enable auto-polling + * + * @v rhn Rhine device + * @ret rc Return status code + * + * This is voodoo. There seems to be no documentation on exactly what + * we are waiting for, or why we have to do anything other than simply + * turn the feature on. + */ +static int rhine_mii_autopoll ( struct rhine_nic *rhn ) { + unsigned int timeout = RHINE_TIMEOUT_US; + uint8_t addr; + + /* Initiate auto-polling */ + writeb ( MII_BMSR, rhn->regs + RHINE_MII_ADDR ); + writeb ( RHINE_MII_CR_AUTOPOLL, rhn->regs + RHINE_MII_CR ); + + /* Wait for auto-polling to complete */ + while ( timeout-- ) { + udelay ( 1 ); + addr = readb ( rhn->regs + RHINE_MII_ADDR ); + if ( ! ( addr & RHINE_MII_ADDR_MDONE ) ) { + writeb ( ( MII_BMSR | RHINE_MII_ADDR_MSRCEN ), + rhn->regs + RHINE_MII_ADDR ); + return 0; + } + } + + DBGC ( rhn, "RHINE %p MII auto-poll timeout\n", rhn ); + return -ETIMEDOUT; +} + +/****************************************************************************** + * + * Device reset + * + ****************************************************************************** + */ + +/** + * Reset hardware + * + * @v rhn Rhine device + * @ret rc Return status code + * + * We're using PIO because this might reset the MMIO enable bit. + */ +static int rhine_reset ( struct rhine_nic *rhn ) { + unsigned int timeout = RHINE_TIMEOUT_US; + uint8_t cr1; + + DBGC ( rhn, "RHINE %p reset\n", rhn ); + + /* Initiate reset */ + outb ( RHINE_CR1_RESET, rhn->ioaddr + RHINE_CR1 ); + + /* Wait for reset to complete */ + while ( timeout-- ) { + udelay ( 1 ); + cr1 = inb ( rhn->ioaddr + RHINE_CR1 ); + if ( ! ( cr1 & RHINE_CR1_RESET ) ) + return 0; + } + + DBGC ( rhn, "RHINE %p reset timeout\n", rhn ); + return -ETIMEDOUT; +} + +/** + * Enable MMIO register access + * + * @v rhn Rhine device + * @v revision Card revision + */ +static void rhine_enable_mmio ( struct rhine_nic *rhn, int revision ) { + uint8_t conf; + + if ( revision < RHINE_REVISION_OLD ) { + conf = inb ( rhn->ioaddr + RHINE_CHIPCFG_A ); + outb ( ( conf | RHINE_CHIPCFG_A_MMIO ), + rhn->ioaddr + RHINE_CHIPCFG_A ); + } else { + conf = inb ( rhn->ioaddr + RHINE_CHIPCFG_D ); + outb ( ( conf | RHINE_CHIPCFG_D_MMIO ), + rhn->ioaddr + RHINE_CHIPCFG_D ); + } +} + +/** + * Reload EEPROM contents + * + * @v rhn Rhine device + * @ret rc Return status code + * + * We're using PIO because this might reset the MMIO enable bit. + */ +static int rhine_reload_eeprom ( struct rhine_nic *rhn ) { + unsigned int timeout = RHINE_TIMEOUT_US; + uint8_t eeprom; + + /* Initiate reload */ + eeprom = inb ( rhn->ioaddr + RHINE_EEPROM_CTRL ); + outb ( ( eeprom | RHINE_EEPROM_CTRL_RELOAD ), + rhn->ioaddr + RHINE_EEPROM_CTRL ); + + /* Wait for reload to complete */ + while ( timeout-- ) { + udelay ( 1 ); + eeprom = inb ( rhn->ioaddr + RHINE_EEPROM_CTRL ); + if ( ! ( eeprom & RHINE_EEPROM_CTRL_RELOAD ) ) + return 0; + } + + DBGC ( rhn, "RHINE %p EEPROM reload timeout\n", rhn ); + return -ETIMEDOUT; +} + +/****************************************************************************** + * + * Link state + * + ****************************************************************************** + */ + +/** + * Check link state + * + * @v netdev Network device + */ +static void rhine_check_link ( struct net_device *netdev ) { + struct rhine_nic *rhn = netdev->priv; + uint8_t mii_sr; + + /* Read MII status register */ + mii_sr = readb ( rhn->regs + RHINE_MII_SR ); + DBGC ( rhn, "RHINE %p link status %02x\n", rhn, mii_sr ); + + /* Report link state */ + if ( ! ( mii_sr & RHINE_MII_SR_LINKPOLL ) ) { + netdev_link_up ( netdev ); + } else if ( mii_sr & RHINE_MII_SR_PHYERR ) { + netdev_link_err ( netdev, -EIO ); + } else { + netdev_link_down ( netdev ); + } +} + +/****************************************************************************** + * + * Network device interface + * + ****************************************************************************** + */ + +/** + * Create descriptor ring + * + * @v rhn Rhine device + * @v ring Descriptor ring + * @ret rc Return status code + */ +static int rhine_create_ring ( struct rhine_nic *rhn, + struct rhine_ring *ring ) { + size_t len = ( ring->count * sizeof ( ring->desc[0] ) ); + struct rhine_descriptor *next; + physaddr_t address; + unsigned int i; + + /* Allocate descriptors */ + ring->desc = malloc_dma ( len, RHINE_RING_ALIGN ); + if ( ! ring->desc ) + return -ENOMEM; + + /* Initialise descriptor ring */ + memset ( ring->desc, 0, len ); + for ( i = 0 ; i < ring->count ; i++ ) { + next = &ring->desc[ ( i + 1 ) % ring->count ]; + ring->desc[i].next = cpu_to_le32 ( virt_to_bus ( next ) ); + } + + /* Program ring address */ + address = virt_to_bus ( ring->desc ); + writel ( address, rhn->regs + ring->reg ); + + DBGC ( rhn, "RHINE %p ring %02x is at [%08llx,%08llx)\n", + rhn, ring->reg, ( ( unsigned long long ) address ), + ( ( unsigned long long ) address + len ) ); + + return 0; +} + +/** + * Destroy descriptor ring + * + * @v rhn Rhine device + * @v ring Descriptor ring + */ +static void rhine_destroy_ring ( struct rhine_nic *rhn, + struct rhine_ring *ring ) { + size_t len = ( ring->count * sizeof ( ring->desc[0] ) ); + + /* Clear ring address */ + writel ( 0, rhn->regs + ring->reg ); + + /* Free descriptor ring */ + free_dma ( ring->desc, len ); + ring->desc = NULL; + ring->prod = 0; + ring->cons = 0; +} + +/** + * Refill RX descriptor ring + * + * @v rhn Rhine device + */ +static void rhine_refill_rx ( struct rhine_nic *rhn ) { + struct rhine_descriptor *desc; + struct io_buffer *iobuf; + unsigned int rx_idx; + physaddr_t address; + + while ( ( rhn->rx.prod - rhn->rx.cons ) < RHINE_RXDESC_NUM ) { + + /* Allocate I/O buffer */ + iobuf = alloc_iob ( RHINE_RX_MAX_LEN ); + if ( ! iobuf ) { + /* Wait for next refill */ + return; + } + + /* Populate next receive descriptor */ + rx_idx = ( rhn->rx.prod++ % RHINE_RXDESC_NUM ); + desc = &rhn->rx.desc[rx_idx]; + address = virt_to_bus ( iobuf->data ); + desc->buffer = cpu_to_le32 ( address ); + desc->des1 = + cpu_to_le32 ( RHINE_DES1_SIZE ( RHINE_RX_MAX_LEN - 1) | + RHINE_DES1_CHAIN | RHINE_DES1_IC ); + wmb(); + desc->des0 = cpu_to_le32 ( RHINE_DES0_OWN ); + + /* Record I/O buffer */ + rhn->rx_iobuf[rx_idx] = iobuf; + + DBGC2 ( rhn, "RHINE %p RX %d is [%llx,%llx)\n", rhn, rx_idx, + ( ( unsigned long long ) address ), + ( ( unsigned long long ) address + RHINE_RX_MAX_LEN ) ); + } +} + +/** + * Open network device + * + * @v netdev Network device + * @ret rc Return status code + */ +static int rhine_open ( struct net_device *netdev ) { + struct rhine_nic *rhn = netdev->priv; + int rc; + + /* Create transmit ring */ + if ( ( rc = rhine_create_ring ( rhn, &rhn->tx ) ) != 0 ) + goto err_create_tx; + + /* Create receive ring */ + if ( ( rc = rhine_create_ring ( rhn, &rhn->rx ) ) != 0 ) + goto err_create_rx; + + /* Set receive configuration */ + writeb ( ( RHINE_RCR_PHYS_ACCEPT | RHINE_RCR_BCAST_ACCEPT | + RHINE_RCR_RUNT_ACCEPT ), rhn->regs + RHINE_RCR ); + + /* Enable link status monitoring */ + if ( ( rc = rhine_mii_autopoll ( rhn ) ) != 0 ) + goto err_mii_autopoll; + + /* Some cards need an extra delay(observed with VT6102) */ + mdelay ( 10 ); + + /* Enable RX/TX of packets */ + writeb ( ( RHINE_CR0_STARTNIC | RHINE_CR0_RXEN | RHINE_CR0_TXEN ), + rhn->regs + RHINE_CR0 ); + + /* Enable auto polling and full duplex operation */ + rhn->cr1 = RHINE_CR1_FDX; + writeb ( rhn->cr1, rhn->regs + RHINE_CR1 ); + + /* Refill RX ring */ + rhine_refill_rx ( rhn ); + + /* Update link state */ + rhine_check_link ( netdev ); + + return 0; + + err_mii_autopoll: + rhine_destroy_ring ( rhn, &rhn->rx ); + err_create_rx: + rhine_destroy_ring ( rhn, &rhn->tx ); + err_create_tx: + return rc; +} + +/** + * Close network device + * + * @v netdev Network device + */ +static void rhine_close ( struct net_device *netdev ) { + struct rhine_nic *rhn = netdev->priv; + unsigned int i; + + /* Disable interrupts */ + writeb ( 0, RHINE_IMR0 ); + writeb ( 0, RHINE_IMR1 ); + + /* Stop card, clear RXON and TXON bits */ + writeb ( RHINE_CR0_STOPNIC, rhn->regs + RHINE_CR0 ); + + /* Destroy receive ring */ + rhine_destroy_ring ( rhn, &rhn->rx ); + + /* Discard any unused receive buffers */ + for ( i = 0 ; i < RHINE_RXDESC_NUM ; i++ ) { + if ( rhn->rx_iobuf[i] ) + free_iob ( rhn->rx_iobuf[i] ); + rhn->rx_iobuf[i] = NULL; + } + + /* Destroy transmit ring */ + rhine_destroy_ring ( rhn, &rhn->tx ); +} + +/** + * Transmit packet + * + * @v netdev Network device + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int rhine_transmit ( struct net_device *netdev, + struct io_buffer *iobuf ) { + struct rhine_nic *rhn = netdev->priv; + struct rhine_descriptor *desc; + physaddr_t address; + unsigned int tx_idx; + + /* Get next transmit descriptor */ + if ( ( rhn->tx.prod - rhn->tx.cons ) >= RHINE_TXDESC_NUM ) + return -ENOBUFS; + tx_idx = ( rhn->tx.prod++ % RHINE_TXDESC_NUM ); + desc = &rhn->tx.desc[tx_idx]; + + /* Pad and align packet */ + iob_pad ( iobuf, ETH_ZLEN ); + address = virt_to_bus ( iobuf->data ); + + /* Populate transmit descriptor */ + desc->buffer = cpu_to_le32 ( address ); + desc->des1 = cpu_to_le32 ( RHINE_DES1_IC | RHINE_TDES1_STP | + RHINE_TDES1_EDP | RHINE_DES1_CHAIN | + RHINE_DES1_SIZE ( iob_len ( iobuf ) ) ); + wmb(); + desc->des0 = cpu_to_le32 ( RHINE_DES0_OWN ); + wmb(); + + /* Notify card that there are packets ready to transmit */ + writeb ( ( rhn->cr1 | RHINE_CR1_TXPOLL ), rhn->regs + RHINE_CR1 ); + + DBGC2 ( rhn, "RHINE %p TX %d is [%llx,%llx)\n", rhn, tx_idx, + ( ( unsigned long long ) address ), + ( ( unsigned long long ) address + iob_len ( iobuf ) ) ); + + return 0; +} + +/** + * Poll for completed packets + * + * @v netdev Network device + */ +static void rhine_poll_tx ( struct net_device *netdev ) { + struct rhine_nic *rhn = netdev->priv; + struct rhine_descriptor *desc; + unsigned int tx_idx; + uint32_t des0; + + /* Check for completed packets */ + while ( rhn->tx.cons != rhn->tx.prod ) { + + /* Get next transmit descriptor */ + tx_idx = ( rhn->tx.cons % RHINE_TXDESC_NUM ); + desc = &rhn->tx.desc[tx_idx]; + + /* Stop if descriptor is still in use */ + if ( desc->des0 & cpu_to_le32 ( RHINE_DES0_OWN ) ) + return; + + /* Complete TX descriptor */ + des0 = le32_to_cpu ( desc->des0 ); + if ( des0 & RHINE_TDES0_TERR ) { + DBGC ( rhn, "RHINE %p TX %d error (DES0 %08x)\n", + rhn, tx_idx, des0 ); + netdev_tx_complete_next_err ( netdev, -EIO ); + } else { + DBGC2 ( rhn, "RHINE %p TX %d complete\n", rhn, tx_idx ); + netdev_tx_complete_next ( netdev ); + } + rhn->tx.cons++; + } +} + +/** + * Poll for received packets + * + * @v netdev Network device + */ +static void rhine_poll_rx ( struct net_device *netdev ) { + struct rhine_nic *rhn = netdev->priv; + struct rhine_descriptor *desc; + struct io_buffer *iobuf; + unsigned int rx_idx; + uint32_t des0; + size_t len; + + /* Check for received packets */ + while ( rhn->rx.cons != rhn->rx.prod ) { + + /* Get next receive descriptor */ + rx_idx = ( rhn->rx.cons % RHINE_RXDESC_NUM ); + desc = &rhn->rx.desc[rx_idx]; + + /* Stop if descriptor is still in use */ + if ( desc->des0 & cpu_to_le32 ( RHINE_DES0_OWN ) ) + return; + + /* Populate I/O buffer */ + iobuf = rhn->rx_iobuf[rx_idx]; + rhn->rx_iobuf[rx_idx] = NULL; + des0 = le32_to_cpu ( desc->des0 ); + len = ( RHINE_DES0_GETSIZE ( des0 ) - 4 /* strip CRC */ ); + iob_put ( iobuf, len ); + + /* Hand off to network stack */ + if ( des0 & RHINE_RDES0_RXOK ) { + DBGC2 ( rhn, "RHINE %p RX %d complete (length %zd)\n", + rhn, rx_idx, len ); + netdev_rx ( netdev, iobuf ); + } else { + DBGC ( rhn, "RHINE %p RX %d error (length %zd, DES0 " + "%08x)\n", rhn, rx_idx, len, des0 ); + netdev_rx_err ( netdev, iobuf, -EIO ); + } + rhn->rx.cons++; + } +} + +/** + * Poll for completed and received packets + * + * @v netdev Network device + */ +static void rhine_poll ( struct net_device *netdev ) { + struct rhine_nic *rhn = netdev->priv; + uint8_t isr0; + uint8_t isr1; + + /* Read and acknowledge interrupts */ + isr0 = readb ( rhn->regs + RHINE_ISR0 ); + isr1 = readb ( rhn->regs + RHINE_ISR1 ); + if ( isr0 ) + writeb ( isr0, rhn->regs + RHINE_ISR0 ); + if ( isr1 ) + writeb ( isr1, rhn->regs + RHINE_ISR1 ); + + /* Report unexpected errors */ + if ( ( isr0 & ( RHINE_ISR0_MIBOVFL | RHINE_ISR0_PCIERR | + RHINE_ISR0_RXRINGERR | RHINE_ISR0_TXRINGERR ) ) || + ( isr1 & ( RHINE_ISR1_GPI | RHINE_ISR1_TXABORT | + RHINE_ISR1_RXFIFOOVFL | RHINE_ISR1_RXFIFOUNFL | + RHINE_ISR1_TXFIFOUNFL ) ) ) { + DBGC ( rhn, "RHINE %p unexpected ISR0 %02x ISR1 %02x\n", + rhn, isr0, isr1 ); + /* Report as a TX error */ + netdev_tx_err ( netdev, NULL, -EIO ); + } + + /* Poll for TX completions, if applicable */ + if ( isr0 & ( RHINE_ISR0_TXDONE | RHINE_ISR0_TXERR ) ) + rhine_poll_tx ( netdev ); + + /* Poll for RX completions, if applicable */ + if ( isr0 & ( RHINE_ISR0_RXDONE | RHINE_ISR0_RXERR ) ) + rhine_poll_rx ( netdev ); + + /* Handle RX buffer exhaustion */ + if ( isr1 & RHINE_ISR1_RXNOBUF ) { + rhine_poll_rx ( netdev ); + netdev_rx_err ( netdev, NULL, -ENOBUFS ); + } + + /* Check link state, if applicable */ + if ( isr1 & RHINE_ISR1_PORTSTATE ) + rhine_check_link ( netdev ); + + /* Refill RX ring */ + rhine_refill_rx ( rhn ); +} + +/** + * Enable or disable interrupts + * + * @v netdev Network device + * @v enable Interrupts should be enabled + */ +static void rhine_irq ( struct net_device *netdev, int enable ) { + struct rhine_nic *nic = netdev->priv; + + if ( enable ) { + /* Enable interrupts */ + writeb ( 0xff, nic->regs + RHINE_IMR0 ); + writeb ( 0xff, nic->regs + RHINE_IMR1 ); + } else { + /* Disable interrupts */ + writeb ( 0, nic->regs + RHINE_IMR0 ); + writeb ( 0, nic->regs + RHINE_IMR1 ); + } +} + +/** Rhine network device operations */ +static struct net_device_operations rhine_operations = { + .open = rhine_open, + .close = rhine_close, + .transmit = rhine_transmit, + .poll = rhine_poll, + .irq = rhine_irq, +}; + +/****************************************************************************** + * + * PCI interface + * + ****************************************************************************** + */ + +/** + * Probe PCI device + * + * @v pci PCI device + * @ret rc Return status code + */ +static int rhine_probe ( struct pci_device *pci ) { + struct net_device *netdev; + struct rhine_nic *rhn; + uint8_t revision; + unsigned int i; + int rc; + + /* Allocate and initialise net device */ + netdev = alloc_etherdev ( sizeof ( *rhn ) ); + if ( ! netdev ) { + rc = -ENOMEM; + goto err_alloc; + } + netdev_init ( netdev, &rhine_operations ); + rhn = netdev->priv; + pci_set_drvdata ( pci, netdev ); + netdev->dev = &pci->dev; + memset ( rhn, 0, sizeof ( *rhn ) ); + rhine_init_ring ( &rhn->tx, RHINE_TXDESC_NUM, RHINE_TXQUEUE_BASE ); + rhine_init_ring ( &rhn->rx, RHINE_RXDESC_NUM, RHINE_RXQUEUE_BASE ); + + /* Fix up PCI device */ + adjust_pci_device ( pci ); + + /* Map registers */ + rhn->regs = ioremap ( pci->membase, RHINE_BAR_SIZE ); + rhn->ioaddr = pci->ioaddr; + DBGC ( rhn, "RHINE %p regs at %08lx, I/O at %04lx\n", rhn, + pci->membase, pci->ioaddr ); + + /* Reset the NIC */ + if ( ( rc = rhine_reset ( rhn ) ) != 0 ) + goto err_reset; + + /* Reload EEPROM */ + if ( ( rc = rhine_reload_eeprom ( rhn ) ) != 0 ) + goto err_reload_eeprom; + + /* Read card revision and enable MMIO */ + pci_read_config_byte ( pci, PCI_REVISION, &revision ); + DBGC ( rhn, "RHINE %p revision %#02x detected\n", rhn, revision ); + rhine_enable_mmio ( rhn, revision ); + + /* Read MAC address */ + for ( i = 0 ; i < ETH_ALEN ; i++ ) + netdev->hw_addr[i] = readb ( rhn->regs + RHINE_MAC + i ); + + /* Initialise and reset MII interface */ + mii_init ( &rhn->mii, &rhine_mii_operations ); + if ( ( rc = mii_reset ( &rhn->mii ) ) != 0 ) { + DBGC ( rhn, "RHINE %p could not reset MII: %s\n", + rhn, strerror ( rc ) ); + goto err_mii_reset; + } + DBGC ( rhn, "RHINE PHY vendor %04x device %04x\n", + rhine_mii_read ( &rhn->mii, 0x02 ), + rhine_mii_read ( &rhn->mii, 0x03 ) ); + + /* Register network device */ + if ( ( rc = register_netdev ( netdev ) ) != 0 ) + goto err_register_netdev; + + /* Set initial link state */ + rhine_check_link ( netdev ); + + return 0; + + err_register_netdev: + err_mii_reset: + err_reload_eeprom: + rhine_reset ( rhn ); + err_reset: + netdev_nullify ( netdev ); + netdev_put ( netdev ); + err_alloc: + return rc; +} + +/** + * Remove PCI device + * + * @v pci PCI device + */ +static void rhine_remove ( struct pci_device *pci ) { + struct net_device *netdev = pci_get_drvdata ( pci ); + struct rhine_nic *nic = netdev->priv; + + /* Unregister network device */ + unregister_netdev ( netdev ); + + /* Reset card */ + rhine_reset ( nic ); + + /* Free network device */ + netdev_nullify ( netdev ); + netdev_put ( netdev ); +} + +/** Rhine PCI device IDs */ +static struct pci_device_id rhine_nics[] = { + PCI_ROM ( 0x1106, 0x3065, "dlink-530tx", "VIA VT6102", 0 ), + PCI_ROM ( 0x1106, 0x3106, "vt6105", "VIA VT6105", 0 ), + PCI_ROM ( 0x1106, 0x3043, "dlink-530tx-old", "VIA VT3043", 0 ), + PCI_ROM ( 0x1106, 0x3053, "vt6105m", "VIA VT6105M", 0 ), + PCI_ROM ( 0x1106, 0x6100, "via-rhine-old", "VIA 86C100A", 0 ) +}; + +/** Rhine PCI driver */ +struct pci_driver rhine_driver __pci_driver = { + .ids = rhine_nics, + .id_count = ( sizeof ( rhine_nics ) / sizeof ( rhine_nics[0] ) ), + .probe = rhine_probe, + .remove = rhine_remove, +}; diff --git a/src/drivers/net/rhine.h b/src/drivers/net/rhine.h new file mode 100644 index 00000000..b26f9ae7 --- /dev/null +++ b/src/drivers/net/rhine.h @@ -0,0 +1,250 @@ +#ifndef _RHINE_H +#define _RHINE_H + +/** @file + * + * VIA Rhine network driver + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** Rhine BAR size */ +#define RHINE_BAR_SIZE 256 + +/** Default timeout */ +#define RHINE_TIMEOUT_US 10000 + +/** Rhine descriptor format */ +struct rhine_descriptor { + uint32_t des0; + uint32_t des1; + uint32_t buffer; + uint32_t next; +} __attribute__ (( packed )); + +#define RHINE_DES0_OWN (1 << 31) /*< Owned descriptor */ +#define RHINE_DES1_IC (1 << 23) /*< Generate interrupt */ +#define RHINE_TDES1_EDP (1 << 22) /*< End of packet */ +#define RHINE_TDES1_STP (1 << 21) /*< Start of packet */ +#define RHINE_TDES1_TCPCK (1 << 20) /*< HW TCP checksum */ +#define RHINE_TDES1_UDPCK (1 << 19) /*< HW UDP checksum */ +#define RHINE_TDES1_IPCK (1 << 18) /*< HW IP checksum */ +#define RHINE_TDES1_TAG (1 << 17) /*< Tagged frame */ +#define RHINE_TDES1_CRC (1 << 16) /*< No CRC */ +#define RHINE_DES1_CHAIN (1 << 15) /*< Chained descriptor */ +#define RHINE_DES1_SIZE(_x) ((_x) & 0x7ff) /*< Frame size */ +#define RHINE_DES0_GETSIZE(_x) (((_x) >> 16) & 0x7ff) + +#define RHINE_RDES0_RXOK (1 << 15) +#define RHINE_RDES0_VIDHIT (1 << 14) +#define RHINE_RDES0_MAR (1 << 13) +#define RHINE_RDES0_BAR (1 << 12) +#define RHINE_RDES0_PHY (1 << 11) +#define RHINE_RDES0_CHN (1 << 10) +#define RHINE_RDES0_STP (1 << 9) +#define RHINE_RDES0_EDP (1 << 8) +#define RHINE_RDES0_BUFF (1 << 7) +#define RHINE_RDES0_FRAG (1 << 6) +#define RHINE_RDES0_RUNT (1 << 5) +#define RHINE_RDES0_LONG (1 << 4) +#define RHINE_RDES0_FOV (1 << 3) +#define RHINE_RDES0_FAE (1 << 2) +#define RHINE_RDES0_CRCE (1 << 1) +#define RHINE_RDES0_RERR (1 << 0) + +#define RHINE_TDES0_TERR (1 << 15) +#define RHINE_TDES0_UDF (1 << 11) +#define RHINE_TDES0_CRS (1 << 10) +#define RHINE_TDES0_OWC (1 << 9) +#define RHINE_TDES0_ABT (1 << 8) +#define RHINE_TDES0_CDH (1 << 7) +#define RHINE_TDES0_COLS (1 << 4) +#define RHINE_TDES0_NCR(_x) ((_x) & 0xf) + +#define RHINE_RING_ALIGN 4 + +/** Rhine descriptor rings sizes */ +#define RHINE_RXDESC_NUM 4 +#define RHINE_TXDESC_NUM 8 +#define RHINE_RX_MAX_LEN 1536 + +/** Rhine MAC address registers */ +#define RHINE_MAC 0x00 + +/** Receive control register */ +#define RHINE_RCR 0x06 +#define RHINE_RCR_FIFO_TRSH(_x) (((_x) & 0x7) << 5) /*< RX FIFO threshold */ +#define RHINE_RCR_PHYS_ACCEPT (1 << 4) /*< Accept matching PA */ +#define RHINE_RCR_BCAST_ACCEPT (1 << 3) /*< Accept broadcast */ +#define RHINE_RCR_MCAST_ACCEPT (1 << 2) /*< Accept multicast */ +#define RHINE_RCR_RUNT_ACCEPT (1 << 1) /*< Accept runt frames */ +#define RHINE_RCR_ERR_ACCEPT (1 << 0) /*< Accept erroneous frames */ + +/** Transmit control register */ +#define RHINE_TCR 0x07 +#define RHINE_TCR_LOOPBACK(_x) (((_x) & 0x3) << 1) /*< Transmit loop mode */ +#define RHINE_TCR_TAGGING (1 << 0) /*< 802.1P/Q packet tagging */ + +/** Command 0 register */ +#define RHINE_CR0 0x08 +#define RHINE_CR0_RXSTART (1 << 6) +#define RHINE_CR0_TXSTART (1 << 5) +#define RHINE_CR0_TXEN (1 << 4) /*< Transmit enable */ +#define RHINE_CR0_RXEN (1 << 3) /*< Receive enable */ +#define RHINE_CR0_STOPNIC (1 << 2) /*< Stop NIC */ +#define RHINE_CR0_STARTNIC (1 << 1) /*< Start NIC */ + +/** Command 1 register */ +#define RHINE_CR1 0x09 +#define RHINE_CR1_RESET (1 << 7) /*< Software reset */ +#define RHINE_CR1_RXPOLL (1 << 6) /*< Receive poll demand */ +#define RHINE_CR1_TXPOLL (1 << 5) /*< Xmit poll demand */ +#define RHINE_CR1_AUTOPOLL (1 << 3) /*< Disable autopoll */ +#define RHINE_CR1_FDX (1 << 2) /*< Full duplex */ +#define RIHNE_CR1_ACCUNI (1 << 1) /*< Disable accept unicast */ + +/** Transmit queue wake register */ +#define RHINE_TXQUEUE_WAKE 0x0a + +/** Interrupt service 0 */ +#define RHINE_ISR0 0x0c +#define RHINE_ISR0_MIBOVFL (1 << 7) +#define RHINE_ISR0_PCIERR (1 << 6) +#define RHINE_ISR0_RXRINGERR (1 << 5) +#define RHINE_ISR0_TXRINGERR (1 << 4) +#define RHINE_ISR0_TXERR (1 << 3) +#define RHINE_ISR0_RXERR (1 << 2) +#define RHINE_ISR0_TXDONE (1 << 1) +#define RHINE_ISR0_RXDONE (1 << 0) + +/** Interrupt service 1 */ +#define RHINE_ISR1 0x0d +#define RHINE_ISR1_GPI (1 << 7) +#define RHINE_ISR1_PORTSTATE (1 << 6) +#define RHINE_ISR1_TXABORT (1 << 5) +#define RHINE_ISR1_RXNOBUF (1 << 4) +#define RHINE_ISR1_RXFIFOOVFL (1 << 3) +#define RHINE_ISR1_RXFIFOUNFL (1 << 2) +#define RHINE_ISR1_TXFIFOUNFL (1 << 1) +#define RHINE_ISR1_EARLYRX (1 << 0) + +/** Interrupt enable mask register 0 */ +#define RHINE_IMR0 0x0e + +/** Interrupt enable mask register 1 */ +#define RHINE_IMR1 0x0f + +/** RX queue descriptor base address */ +#define RHINE_RXQUEUE_BASE 0x18 + +/** TX queue 0 descriptor base address */ +#define RHINE_TXQUEUE_BASE 0x1c + +/** MII configuration */ +#define RHINE_MII_CFG 0x6c + +/** MII status register */ +#define RHINE_MII_SR 0x6d +#define RHINE_MII_SR_PHYRST (1 << 7) /*< PHY reset */ +#define RHINE_MII_SR_LINKNWAY (1 << 4) /*< Link status after N-Way */ +#define RHINE_MII_SR_PHYERR (1 << 3) /*< PHY device error */ +#define RHINE_MII_SR_DUPLEX (1 << 2) /*< Duplex mode after N-Way */ +#define RHINE_MII_SR_LINKPOLL (1 << 1) /*< Link status after poll */ +#define RHINE_MII_SR_LINKSPD (1 << 0) /*< Link speed after N-Way */ + +/** MII bus control 0 register */ +#define RHINE_MII_BCR0 0x6e + +/** MII bus control 1 register */ +#define RHINE_MII_BCR1 0x6f + +/** MII control register */ +#define RHINE_MII_CR 0x70 +#define RHINE_MII_CR_AUTOPOLL (1 << 7) /*< MII auto polling */ +#define RHINE_MII_CR_RDEN (1 << 6) /*< PHY read enable */ +#define RHINE_MII_CR_WREN (1 << 5) /*< PHY write enable */ +#define RHINE_MII_CR_DIRECT (1 << 4) /*< Direct programming mode */ +#define RHINE_MII_CR_MDIOOUT (1 << 3) /*< MDIO output enable */ + +/** MII port address */ +#define RHINE_MII_ADDR 0x71 +#define RHINE_MII_ADDR_MSRCEN (1 << 6) +#define RHINE_MII_ADDR_MDONE (1 << 5) + +/** MII read/write data */ +#define RHINE_MII_RDWR 0x72 + +/** EERPOM control/status register */ +#define RHINE_EEPROM_CTRL 0x74 +#define RHINE_EEPROM_CTRL_STATUS (1 << 7) /*< EEPROM status */ +#define RHINE_EEPROM_CTRL_RELOAD (1 << 5) /*< EEPROM reload */ + +/** Chip configuration A */ +#define RHINE_CHIPCFG_A 0x78 +/* MMIO enable. Only valid for Rhine I. Reserved on later boards */ +#define RHINE_CHIPCFG_A_MMIO (1 << 5) + +/** Chip configuration B */ +#define RHINE_CHIPCFG_B 0x79 + +/** Chip configuation C */ +#define RHINE_CHIPCFG_C 0x7a + +/** Chip configuration D */ +#define RHINE_CHIPCFG_D 0x7b +/* MMIO enable. Only valid on Rhine II and later. GPIOEN on Rhine I */ +#define RHINE_CHIPCFG_D_MMIO (1 << 7) + +#define RHINE_REVISION_OLD 0x20 + +/** A VIA Rhine descriptor ring */ +struct rhine_ring { + /** Descriptors */ + struct rhine_descriptor *desc; + /** Producer index */ + unsigned int prod; + /** Consumer index */ + unsigned int cons; + + /** Number of descriptors */ + unsigned int count; + /** Register address */ + unsigned int reg; +}; + +/** + * Initialise descriptor ring + * + * @v ring Descriptor ring + * @v count Number of descriptors (must be a power of 2) + * @v reg Register address + */ +static inline __attribute__ (( always_inline)) void +rhine_init_ring ( struct rhine_ring *ring, unsigned int count, + unsigned int reg ) { + ring->count = count; + ring->reg = reg; +} + +/** A VIA Rhine network card */ +struct rhine_nic { + /** I/O address (some PIO access is always required) */ + unsigned long ioaddr; + /** Registers */ + void *regs; + /** Cached value of CR1 (to avoid read-modify-write on fast path) */ + uint8_t cr1; + + /** MII interface */ + struct mii_interface mii; + + /** Transmit descriptor ring */ + struct rhine_ring tx; + /** Receive descriptor ring */ + struct rhine_ring rx; + /** Receive I/O buffers */ + struct io_buffer *rx_iobuf[RHINE_RXDESC_NUM]; +}; + +#endif /* _RHINE_H */ diff --git a/src/drivers/net/via-rhine.c b/src/drivers/net/via-rhine.c deleted file mode 100644 index f3bb4e01..00000000 --- a/src/drivers/net/via-rhine.c +++ /dev/null @@ -1,1447 +0,0 @@ -/* rhine.c:Fast Ethernet driver for Linux. */ -/* - Adapted 09-jan-2000 by Paolo Marini (paolom@prisma-eng.it) - - originally 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. - Drivers derived from this code also fall under the GPL and must retain - this authorship and copyright notice. - - Under no circumstances are the authors responsible for - the proper functioning of this software, nor do the authors assume any - responsibility for damages incurred with its use. - - This driver is designed for the VIA VT86C100A Rhine-II PCI Fast Ethernet - controller. - -*/ - -static const char *version = "rhine.c v1.0.2 2004-10-29\n"; - -/* A few user-configurable values. */ - -// max time out delay time -#define W_MAX_TIMEOUT 0x0FFFU - -/* Size of the in-memory receive ring. */ -#define RX_BUF_LEN_IDX 3 /* 0==8K, 1==16K, 2==32K, 3==64K */ -#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX) - -/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */ -#define TX_BUF_SIZE 1536 -#define RX_BUF_SIZE 1536 - -/* PCI Tuning Parameters - Threshold is bytes transferred to chip before transmission starts. */ -#define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */ - -/* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024. */ -#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 - -/* Operational parameters that usually are not changed. */ -/* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT ((2000*HZ)/1000) - -#include "etherboot.h" -#include "nic.h" -#include -#include - -/* define all ioaddr */ - -#define byPAR0 ioaddr -#define byRCR ioaddr + 6 -#define byTCR ioaddr + 7 -#define byCR0 ioaddr + 8 -#define byCR1 ioaddr + 9 -#define byISR0 ioaddr + 0x0c -#define byISR1 ioaddr + 0x0d -#define byIMR0 ioaddr + 0x0e -#define byIMR1 ioaddr + 0x0f -#define byMAR0 ioaddr + 0x10 -#define byMAR1 ioaddr + 0x11 -#define byMAR2 ioaddr + 0x12 -#define byMAR3 ioaddr + 0x13 -#define byMAR4 ioaddr + 0x14 -#define byMAR5 ioaddr + 0x15 -#define byMAR6 ioaddr + 0x16 -#define byMAR7 ioaddr + 0x17 -#define dwCurrentRxDescAddr ioaddr + 0x18 -#define dwCurrentTxDescAddr ioaddr + 0x1c -#define dwCurrentRDSE0 ioaddr + 0x20 -#define dwCurrentRDSE1 ioaddr + 0x24 -#define dwCurrentRDSE2 ioaddr + 0x28 -#define dwCurrentRDSE3 ioaddr + 0x2c -#define dwNextRDSE0 ioaddr + 0x30 -#define dwNextRDSE1 ioaddr + 0x34 -#define dwNextRDSE2 ioaddr + 0x38 -#define dwNextRDSE3 ioaddr + 0x3c -#define dwCurrentTDSE0 ioaddr + 0x40 -#define dwCurrentTDSE1 ioaddr + 0x44 -#define dwCurrentTDSE2 ioaddr + 0x48 -#define dwCurrentTDSE3 ioaddr + 0x4c -#define dwNextTDSE0 ioaddr + 0x50 -#define dwNextTDSE1 ioaddr + 0x54 -#define dwNextTDSE2 ioaddr + 0x58 -#define dwNextTDSE3 ioaddr + 0x5c -#define dwCurrRxDMAPtr ioaddr + 0x60 -#define dwCurrTxDMAPtr ioaddr + 0x64 -#define byMPHY ioaddr + 0x6c -#define byMIISR ioaddr + 0x6d -#define byBCR0 ioaddr + 0x6e -#define byBCR1 ioaddr + 0x6f -#define byMIICR ioaddr + 0x70 -#define byMIIAD ioaddr + 0x71 -#define wMIIDATA ioaddr + 0x72 -#define byEECSR ioaddr + 0x74 -#define byTEST ioaddr + 0x75 -#define byGPIO ioaddr + 0x76 -#define byCFGA ioaddr + 0x78 -#define byCFGB ioaddr + 0x79 -#define byCFGC ioaddr + 0x7a -#define byCFGD ioaddr + 0x7b -#define wTallyCntMPA ioaddr + 0x7c -#define wTallyCntCRC ioaddr + 0x7d -#define bySTICKHW ioaddr + 0x83 -#define byWOLcrClr ioaddr + 0xA4 -#define byWOLcgClr ioaddr + 0xA7 -#define byPwrcsrClr ioaddr + 0xAC - -/*--------------------- Exioaddr Definitions -------------------------*/ - -/* - * Bits in the RCR register - */ - -#define RCR_RRFT2 0x80 -#define RCR_RRFT1 0x40 -#define RCR_RRFT0 0x20 -#define RCR_PROM 0x10 -#define RCR_AB 0x08 -#define RCR_AM 0x04 -#define RCR_AR 0x02 -#define RCR_SEP 0x01 - -/* - * Bits in the TCR register - */ - -#define TCR_RTSF 0x80 -#define TCR_RTFT1 0x40 -#define TCR_RTFT0 0x20 -#define TCR_OFSET 0x08 -#define TCR_LB1 0x04 /* loopback[1] */ -#define TCR_LB0 0x02 /* loopback[0] */ - -/* - * Bits in the CR0 register - */ - -#define CR0_RDMD 0x40 /* rx descriptor polling demand */ -#define CR0_TDMD 0x20 /* tx descriptor polling demand */ -#define CR0_TXON 0x10 -#define CR0_RXON 0x08 -#define CR0_STOP 0x04 /* stop NIC, default = 1 */ -#define CR0_STRT 0x02 /* start NIC */ -#define CR0_INIT 0x01 /* start init process */ - - -/* - * Bits in the CR1 register - */ - -#define CR1_SFRST 0x80 /* software reset */ -#define CR1_RDMD1 0x40 /* RDMD1 */ -#define CR1_TDMD1 0x20 /* TDMD1 */ -#define CR1_KEYPAG 0x10 /* turn on par/key */ -#define CR1_DPOLL 0x08 /* disable rx/tx auto polling */ -#define CR1_FDX 0x04 /* full duplex mode */ -#define CR1_ETEN 0x02 /* early tx mode */ -#define CR1_EREN 0x01 /* early rx mode */ - -/* - * Bits in the CR register - */ - -#define CR_RDMD 0x0040 /* rx descriptor polling demand */ -#define CR_TDMD 0x0020 /* tx descriptor polling demand */ -#define CR_TXON 0x0010 -#define CR_RXON 0x0008 -#define CR_STOP 0x0004 /* stop NIC, default = 1 */ -#define CR_STRT 0x0002 /* start NIC */ -#define CR_INIT 0x0001 /* start init process */ -#define CR_SFRST 0x8000 /* software reset */ -#define CR_RDMD1 0x4000 /* RDMD1 */ -#define CR_TDMD1 0x2000 /* TDMD1 */ -#define CR_KEYPAG 0x1000 /* turn on par/key */ -#define CR_DPOLL 0x0800 /* disable rx/tx auto polling */ -#define CR_FDX 0x0400 /* full duplex mode */ -#define CR_ETEN 0x0200 /* early tx mode */ -#define CR_EREN 0x0100 /* early rx mode */ - -/* - * Bits in the IMR0 register - */ - -#define IMR0_CNTM 0x80 -#define IMR0_BEM 0x40 -#define IMR0_RUM 0x20 -#define IMR0_TUM 0x10 -#define IMR0_TXEM 0x08 -#define IMR0_RXEM 0x04 -#define IMR0_PTXM 0x02 -#define IMR0_PRXM 0x01 - -/* define imrshadow */ - -#define IMRShadow 0x5AFF - -/* - * Bits in the IMR1 register - */ - -#define IMR1_INITM 0x80 -#define IMR1_SRCM 0x40 -#define IMR1_NBFM 0x10 -#define IMR1_PRAIM 0x08 -#define IMR1_RES0M 0x04 -#define IMR1_ETM 0x02 -#define IMR1_ERM 0x01 - -/* - * Bits in the ISR register - */ - -#define ISR_INITI 0x8000 -#define ISR_SRCI 0x4000 -#define ISR_ABTI 0x2000 -#define ISR_NORBF 0x1000 -#define ISR_PKTRA 0x0800 -#define ISR_RES0 0x0400 -#define ISR_ETI 0x0200 -#define ISR_ERI 0x0100 -#define ISR_CNT 0x0080 -#define ISR_BE 0x0040 -#define ISR_RU 0x0020 -#define ISR_TU 0x0010 -#define ISR_TXE 0x0008 -#define ISR_RXE 0x0004 -#define ISR_PTX 0x0002 -#define ISR_PRX 0x0001 - -/* - * Bits in the ISR0 register - */ - -#define ISR0_CNT 0x80 -#define ISR0_BE 0x40 -#define ISR0_RU 0x20 -#define ISR0_TU 0x10 -#define ISR0_TXE 0x08 -#define ISR0_RXE 0x04 -#define ISR0_PTX 0x02 -#define ISR0_PRX 0x01 - -/* - * Bits in the ISR1 register - */ - -#define ISR1_INITI 0x80 -#define ISR1_SRCI 0x40 -#define ISR1_NORBF 0x10 -#define ISR1_PKTRA 0x08 -#define ISR1_ETI 0x02 -#define ISR1_ERI 0x01 - -/* ISR ABNORMAL CONDITION */ - -#define ISR_ABNORMAL ISR_BE+ISR_RU+ISR_TU+ISR_CNT+ISR_NORBF+ISR_PKTRA - -/* - * Bits in the MIISR register - */ - -#define MIISR_MIIERR 0x08 -#define MIISR_MRERR 0x04 -#define MIISR_LNKFL 0x02 -#define MIISR_SPEED 0x01 - -/* - * Bits in the MIICR register - */ - -#define MIICR_MAUTO 0x80 -#define MIICR_RCMD 0x40 -#define MIICR_WCMD 0x20 -#define MIICR_MDPM 0x10 -#define MIICR_MOUT 0x08 -#define MIICR_MDO 0x04 -#define MIICR_MDI 0x02 -#define MIICR_MDC 0x01 - -/* - * Bits in the EECSR register - */ - -#define EECSR_EEPR 0x80 /* eeprom programed status, 73h means programed */ -#define EECSR_EMBP 0x40 /* eeprom embedded programming */ -#define EECSR_AUTOLD 0x20 /* eeprom content reload */ -#define EECSR_DPM 0x10 /* eeprom direct programming */ -#define EECSR_CS 0x08 /* eeprom CS pin */ -#define EECSR_SK 0x04 /* eeprom SK pin */ -#define EECSR_DI 0x02 /* eeprom DI pin */ -#define EECSR_DO 0x01 /* eeprom DO pin */ - -/* - * Bits in the BCR0 register - */ - -#define BCR0_CRFT2 0x20 -#define BCR0_CRFT1 0x10 -#define BCR0_CRFT0 0x08 -#define BCR0_DMAL2 0x04 -#define BCR0_DMAL1 0x02 -#define BCR0_DMAL0 0x01 - -/* - * Bits in the BCR1 register - */ - -#define BCR1_CTSF 0x20 -#define BCR1_CTFT1 0x10 -#define BCR1_CTFT0 0x08 -#define BCR1_POT2 0x04 -#define BCR1_POT1 0x02 -#define BCR1_POT0 0x01 - -/* - * Bits in the CFGA register - */ - -#define CFGA_EELOAD 0x80 /* enable eeprom embedded and direct programming */ -#define CFGA_JUMPER 0x40 -#define CFGA_MTGPIO 0x08 -#define CFGA_T10EN 0x02 -#define CFGA_AUTO 0x01 - -/* - * Bits in the CFGB register - */ - -#define CFGB_PD 0x80 -#define CFGB_POLEN 0x02 -#define CFGB_LNKEN 0x01 - -/* - * Bits in the CFGC register - */ - -#define CFGC_M10TIO 0x80 -#define CFGC_M10POL 0x40 -#define CFGC_PHY1 0x20 -#define CFGC_PHY0 0x10 -#define CFGC_BTSEL 0x08 -#define CFGC_BPS2 0x04 /* bootrom select[2] */ -#define CFGC_BPS1 0x02 /* bootrom select[1] */ -#define CFGC_BPS0 0x01 /* bootrom select[0] */ - -/* - * Bits in the CFGD register - */ - -#define CFGD_GPIOEN 0x80 -#define CFGD_DIAG 0x40 -#define CFGD_MAGIC 0x10 -#define CFGD_RANDOM 0x08 -#define CFGD_CFDX 0x04 -#define CFGD_CEREN 0x02 -#define CFGD_CETEN 0x01 - -/* Bits in RSR */ -#define RSR_RERR 0x00000001 -#define RSR_CRC 0x00000002 -#define RSR_FAE 0x00000004 -#define RSR_FOV 0x00000008 -#define RSR_LONG 0x00000010 -#define RSR_RUNT 0x00000020 -#define RSR_SERR 0x00000040 -#define RSR_BUFF 0x00000080 -#define RSR_EDP 0x00000100 -#define RSR_STP 0x00000200 -#define RSR_CHN 0x00000400 -#define RSR_PHY 0x00000800 -#define RSR_BAR 0x00001000 -#define RSR_MAR 0x00002000 -#define RSR_RXOK 0x00008000 -#define RSR_ABNORMAL RSR_RERR+RSR_LONG+RSR_RUNT - -/* Bits in TSR */ -#define TSR_NCR0 0x00000001 -#define TSR_NCR1 0x00000002 -#define TSR_NCR2 0x00000004 -#define TSR_NCR3 0x00000008 -#define TSR_COLS 0x00000010 -#define TSR_CDH 0x00000080 -#define TSR_ABT 0x00000100 -#define TSR_OWC 0x00000200 -#define TSR_CRS 0x00000400 -#define TSR_UDF 0x00000800 -#define TSR_TBUFF 0x00001000 -#define TSR_SERR 0x00002000 -#define TSR_JAB 0x00004000 -#define TSR_TERR 0x00008000 -#define TSR_ABNORMAL TSR_TERR+TSR_OWC+TSR_ABT+TSR_JAB+TSR_CRS -#define TSR_OWN_BIT 0x80000000 - -#define CB_DELAY_LOOP_WAIT 10 /* 10ms */ -/* enabled mask value of irq */ - -#define W_IMR_MASK_VALUE 0x1BFF /* initial value of IMR */ - -/* Ethernet address filter type */ -#define PKT_TYPE_DIRECTED 0x0001 /* obsolete, directed address is always accepted */ -#define PKT_TYPE_MULTICAST 0x0002 -#define PKT_TYPE_ALL_MULTICAST 0x0004 -#define PKT_TYPE_BROADCAST 0x0008 -#define PKT_TYPE_PROMISCUOUS 0x0020 -#define PKT_TYPE_LONG 0x2000 -#define PKT_TYPE_RUNT 0x4000 -#define PKT_TYPE_ERROR 0x8000 /* accept error packets, e.g. CRC error */ - -/* Loopback mode */ - -#define NIC_LB_NONE 0x00 -#define NIC_LB_INTERNAL 0x01 -#define NIC_LB_PHY 0x02 /* MII or Internal-10BaseT loopback */ - -#define TX_RING_SIZE 2 -#define RX_RING_SIZE 2 -#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ - -#define PCI_REG_MODE3 0x53 -#define MODE3_MIION 0x04 /* in PCI_REG_MOD3 OF PCI space */ - -enum rhine_revs { - VT86C100A = 0x00, - VTunknown0 = 0x20, - VT6102 = 0x40, - VT8231 = 0x50, /* Integrated MAC */ - VT8233 = 0x60, /* Integrated MAC */ - VT8235 = 0x74, /* Integrated MAC */ - VT8237 = 0x78, /* Integrated MAC */ - VTunknown1 = 0x7C, - VT6105 = 0x80, - VT6105_B0 = 0x83, - VT6105L = 0x8A, - VT6107 = 0x8C, - VTunknown2 = 0x8E, - VT6105M = 0x90, -}; - -/* Transmit and receive descriptors definition */ - -struct rhine_tx_desc -{ - union VTC_tx_status_tag - { - struct - { - unsigned long ncro:1; - unsigned long ncr1:1; - unsigned long ncr2:1; - unsigned long ncr3:1; - unsigned long cols:1; - unsigned long reserve_1:2; - unsigned long cdh:1; - unsigned long abt:1; - unsigned long owc:1; - unsigned long crs:1; - unsigned long udf:1; - unsigned long tbuff:1; - unsigned long serr:1; - unsigned long jab:1; - unsigned long terr:1; - unsigned long reserve_2:15; - unsigned long own_bit:1; - } - bits; - unsigned long lw; - } - tx_status; - - union VTC_tx_ctrl_tag - { - struct - { - unsigned long tx_buf_size:11; - unsigned long extend_tx_buf_size:4; - unsigned long chn:1; - unsigned long crc:1; - unsigned long reserve_1:4; - unsigned long stp:1; - unsigned long edp:1; - unsigned long ic:1; - unsigned long reserve_2:8; - } - bits; - unsigned long lw; - } - tx_ctrl; - - unsigned long buf_addr_1:32; - unsigned long buf_addr_2:32; - -}; - -struct rhine_rx_desc -{ - union VTC_rx_status_tag - { - struct - { - unsigned long rerr:1; - unsigned long crc_error:1; - unsigned long fae:1; - unsigned long fov:1; - unsigned long toolong:1; - unsigned long runt:1; - unsigned long serr:1; - unsigned long buff:1; - unsigned long edp:1; - unsigned long stp:1; - unsigned long chn:1; - unsigned long phy:1; - unsigned long bar:1; - unsigned long mar:1; - unsigned long reserve_1:1; - unsigned long rxok:1; - unsigned long frame_length:11; - unsigned long reverve_2:4; - unsigned long own_bit:1; - } - bits; - unsigned long lw; - } - rx_status; - - union VTC_rx_ctrl_tag - { - struct - { - unsigned long rx_buf_size:11; - unsigned long extend_rx_buf_size:4; - unsigned long reserved_1:17; - } - bits; - unsigned long lw; - } - rx_ctrl; - - unsigned long buf_addr_1:32; - unsigned long buf_addr_2:32; - -}; - -struct { - char txbuf[TX_RING_SIZE * PKT_BUF_SZ + 32]; - char rxbuf[RX_RING_SIZE * PKT_BUF_SZ + 32]; - char txdesc[TX_RING_SIZE * sizeof (struct rhine_tx_desc) + 32]; - char rxdesc[RX_RING_SIZE * sizeof (struct rhine_rx_desc) + 32]; -} rhine_buffers __shared; - -/* The I/O extent. */ -#define rhine_TOTAL_SIZE 0x80 - -#ifdef HAVE_DEVLIST -struct netdev_entry rhine_drv = - { "rhine", rhine_probe, rhine_TOTAL_SIZE, NULL }; -#endif - -static int rhine_debug = 1; - -/* - Theory of Operation - -I. Board Compatibility - -This driver is designed for the VIA 86c100A Rhine-II PCI Fast Ethernet -controller. - -II. Board-specific settings - -Boards with this chip are functional only in a bus-master PCI slot. - -Many operational settings are loaded from the EEPROM to the Config word at -offset 0x78. This driver assumes that they are correct. -If this driver is compiled to use PCI memory space operations the EEPROM -must be configured to enable memory ops. - -III. Driver operation - -IIIa. Ring buffers - -This driver uses two statically allocated fixed-size descriptor lists -formed into rings by a branch from the final descriptor to the beginning of -the list. The ring sizes are set at compile time by RX/TX_RING_SIZE. - -IIIb/c. Transmit/Receive Structure - -This driver attempts to use a zero-copy receive and transmit scheme. - -Alas, all data buffers are required to start on a 32 bit boundary, so -the driver must often copy transmit packets into bounce buffers. - -The driver allocates full frame size skbuffs for the Rx ring buffers at -open() time and passes the skb->data field to the chip as receive data -buffers. When an incoming frame is less than RX_COPYBREAK bytes long, -a fresh skbuff is allocated and the frame is copied to the new skbuff. -When the incoming frame is larger, the skbuff is passed directly up the -protocol stack. Buffers consumed this way are replaced by newly allocated -skbuffs in the last phase of netdev_rx(). - -The RX_COPYBREAK value is chosen to trade-off the memory wasted by -using a full-sized skbuff for small frames vs. the copying costs of larger -frames. New boards are typically used in generously configured machines -and the underfilled buffers have negligible impact compared to the benefit of -a single allocation size, so the default value of zero results in never -copying packets. When copying is done, the cost is usually mitigated by using -a combined copy/checksum routine. Copying also preloads the cache, which is -most useful with small frames. - -Since the VIA chips are only able to transfer data to buffers on 32 bit -boundaries, the the IP header at offset 14 in an ethernet frame isn't -longword aligned for further processing. Copying these unaligned buffers -has the beneficial effect of 16-byte aligning the IP header. - -IIId. Synchronization - -The driver runs as two independent, single-threaded flows of control. One -is the send-packet routine, which enforces single-threaded use by the -dev->tbusy flag. The other thread is the interrupt handler, which is single -threaded by the hardware and interrupt handling software. - -The send packet thread has partial control over the Tx ring and 'dev->tbusy' -flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next -queue slot is empty, it clears the tbusy flag when finished otherwise it sets -the 'lp->tx_full' flag. - -The interrupt handler has exclusive control over the Rx ring and records stats -from the Tx ring. After reaping the stats, it marks the Tx queue entry as -empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it -clears both the tx_full and tbusy flags. - -IV. Notes - -IVb. References - -Preliminary VT86C100A manual from http://www.via.com.tw/ -http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html -http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html - -IVc. Errata - -The VT86C100A manual is not reliable information. -The chip does not handle unaligned transmit or receive buffers, resulting -in significant performance degradation for bounce buffer copies on transmit -and unaligned IP headers on receive. -The chip does not pad to minimum transmit length. - -*/ - -/* The rest of these values should never change. */ -#define NUM_TX_DESC 2 /* Number of Tx descriptor registers. */ - -static struct rhine_private -{ - char devname[8]; /* Used only for kernel debugging. */ - const char *product_name; - struct rhine_rx_desc *rx_ring; - struct rhine_tx_desc *tx_ring; - char *rx_buffs[RX_RING_SIZE]; - char *tx_buffs[TX_RING_SIZE]; - - /* temporary Rx buffers. */ - - int chip_id; - int chip_revision; - unsigned short ioaddr; - unsigned int cur_rx, cur_tx; /* The next free and used entries */ - unsigned int dirty_rx, dirty_tx; - /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - struct sk_buff *tx_skbuff[TX_RING_SIZE]; - unsigned char mc_filter[8]; /* Current multicast filter. */ - char phys[4]; /* MII device addresses. */ - unsigned int tx_full:1; /* The Tx queue is full. */ - unsigned int full_duplex:1; /* Full-duplex operation requested. */ - unsigned int default_port:4; /* Last dev->if_port value. */ - unsigned int media2:4; /* Secondary monitored media port. */ - unsigned int medialock:1; /* Don't sense media type. */ - unsigned int mediasense:1; /* Media sensing in progress. */ -} -rhine; - -static void rhine_probe1 (struct nic *nic, struct pci_device *pci, int ioaddr, - int chip_id, int options); -static int QueryAuto (int); -static int ReadMII (int byMIIIndex, int); -static void WriteMII (char, char, char, int); -static void MIIDelay (void); -static void rhine_init_ring (struct nic *dev); -static void rhine_disable (struct nic *nic); -static void rhine_reset (struct nic *nic); -static int rhine_poll (struct nic *nic, int retrieve); -static void rhine_transmit (struct nic *nic, const char *d, unsigned int t, - unsigned int s, const char *p); -static void reload_eeprom(int ioaddr); - - -static void reload_eeprom(int ioaddr) -{ - int i; - outb(0x20, byEECSR); - /* Typically 2 cycles to reload. */ - for (i = 0; i < 150; i++) - if (! (inb(byEECSR) & 0x20)) - break; -} -/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ -static void -rhine_init_ring (struct nic *nic) -{ - struct rhine_private *tp = (struct rhine_private *) nic->priv_data; - int i; - - tp->tx_full = 0; - tp->cur_rx = tp->cur_tx = 0; - tp->dirty_rx = tp->dirty_tx = 0; - - for (i = 0; i < RX_RING_SIZE; i++) - { - - tp->rx_ring[i].rx_status.bits.own_bit = 1; - tp->rx_ring[i].rx_ctrl.bits.rx_buf_size = 1536; - - tp->rx_ring[i].buf_addr_1 = virt_to_bus (tp->rx_buffs[i]); - tp->rx_ring[i].buf_addr_2 = virt_to_bus (&tp->rx_ring[i + 1]); - /* printf("[%d]buf1=%hX,buf2=%hX",i,tp->rx_ring[i].buf_addr_1,tp->rx_ring[i].buf_addr_2); */ - } - /* Mark the last entry as wrapping the ring. */ - /* tp->rx_ring[i-1].rx_ctrl.bits.rx_buf_size =1518; */ - tp->rx_ring[i - 1].buf_addr_2 = virt_to_bus (&tp->rx_ring[0]); - /*printf("[%d]buf1=%hX,buf2=%hX",i-1,tp->rx_ring[i-1].buf_addr_1,tp->rx_ring[i-1].buf_addr_2); */ - - /* The Tx buffer descriptor is filled in as needed, but we - do need to clear the ownership bit. */ - - for (i = 0; i < TX_RING_SIZE; i++) - { - - tp->tx_ring[i].tx_status.lw = 0; - tp->tx_ring[i].tx_ctrl.lw = 0x00e08000; - tp->tx_ring[i].buf_addr_1 = virt_to_bus (tp->tx_buffs[i]); - tp->tx_ring[i].buf_addr_2 = virt_to_bus (&tp->tx_ring[i + 1]); - /* printf("[%d]buf1=%hX,buf2=%hX",i,tp->tx_ring[i].buf_addr_1,tp->tx_ring[i].buf_addr_2); */ - } - - tp->tx_ring[i - 1].buf_addr_2 = virt_to_bus (&tp->tx_ring[0]); - /* printf("[%d]buf1=%hX,buf2=%hX",i,tp->tx_ring[i-1].buf_addr_1,tp->tx_ring[i-1].buf_addr_2); */ -} - -int -QueryAuto (int ioaddr) -{ - int byMIIIndex; - int MIIReturn; - - int advertising,mii_reg5; - int negociated; - - byMIIIndex = 0x04; - MIIReturn = ReadMII (byMIIIndex, ioaddr); - advertising=MIIReturn; - - byMIIIndex = 0x05; - MIIReturn = ReadMII (byMIIIndex, ioaddr); - mii_reg5=MIIReturn; - - negociated=mii_reg5 & advertising; - - if ( (negociated & 0x100) || (negociated & 0x1C0) == 0x40 ) - return 1; - else - return 0; - -} - -int -ReadMII (int byMIIIndex, int ioaddr) -{ - int ReturnMII; - char byMIIAdrbak; - char byMIICRbak; - char byMIItemp; - unsigned long ct; - - byMIIAdrbak = inb (byMIIAD); - byMIICRbak = inb (byMIICR); - outb (byMIICRbak & 0x7f, byMIICR); - MIIDelay (); - - outb (byMIIIndex, byMIIAD); - MIIDelay (); - - outb (inb (byMIICR) | 0x40, byMIICR); - - byMIItemp = inb (byMIICR); - byMIItemp = byMIItemp & 0x40; - - ct = currticks(); - while (byMIItemp != 0 && ct + 2*1000 < currticks()) - { - byMIItemp = inb (byMIICR); - byMIItemp = byMIItemp & 0x40; - } - MIIDelay (); - - ReturnMII = inw (wMIIDATA); - - outb (byMIIAdrbak, byMIIAD); - outb (byMIICRbak, byMIICR); - MIIDelay (); - - return (ReturnMII); - -} - -void -WriteMII (char byMIISetByte, char byMIISetBit, char byMIIOP, int ioaddr) -{ - int ReadMIItmp; - int MIIMask; - char byMIIAdrbak; - char byMIICRbak; - char byMIItemp; - unsigned long ct; - - - byMIIAdrbak = inb (byMIIAD); - - byMIICRbak = inb (byMIICR); - outb (byMIICRbak & 0x7f, byMIICR); - MIIDelay (); - outb (byMIISetByte, byMIIAD); - MIIDelay (); - - outb (inb (byMIICR) | 0x40, byMIICR); - - byMIItemp = inb (byMIICR); - byMIItemp = byMIItemp & 0x40; - - ct = currticks(); - while (byMIItemp != 0 && ct + 2*1000 < currticks()) - { - byMIItemp = inb (byMIICR); - byMIItemp = byMIItemp & 0x40; - } - MIIDelay (); - - ReadMIItmp = inw (wMIIDATA); - MIIMask = 0x0001; - MIIMask = MIIMask << byMIISetBit; - - - if (byMIIOP == 0) - { - MIIMask = ~MIIMask; - ReadMIItmp = ReadMIItmp & MIIMask; - } - else - { - ReadMIItmp = ReadMIItmp | MIIMask; - - } - outw (ReadMIItmp, wMIIDATA); - MIIDelay (); - - outb (inb (byMIICR) | 0x20, byMIICR); - byMIItemp = inb (byMIICR); - byMIItemp = byMIItemp & 0x20; - - ct = currticks(); - while (byMIItemp != 0 && ct + 2*1000 < currticks()) - { - byMIItemp = inb (byMIICR); - byMIItemp = byMIItemp & 0x20; - } - MIIDelay (); - - outb (byMIIAdrbak & 0x7f, byMIIAD); - outb (byMIICRbak, byMIICR); - MIIDelay (); - -} - -void -MIIDelay (void) -{ - int i; - for (i = 0; i < 0x7fff; i++) - { - ( void ) inb (0x61); - ( void ) inb (0x61); - ( void ) inb (0x61); - ( void ) inb (0x61); - } -} - -/* Offsets to the device registers. */ -enum register_offsets { - StationAddr=0x00, RxConfig=0x06, TxConfig=0x07, ChipCmd=0x08, - IntrStatus=0x0C, IntrEnable=0x0E, - MulticastFilter0=0x10, MulticastFilter1=0x14, - RxRingPtr=0x18, TxRingPtr=0x1C, GFIFOTest=0x54, - MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIBusConfig=0x6E, - MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72, MACRegEEcsr=0x74, - ConfigA=0x78, ConfigB=0x79, ConfigC=0x7A, ConfigD=0x7B, - RxMissed=0x7C, RxCRCErrs=0x7E, MiscCmd=0x81, - StickyHW=0x83, IntrStatus2=0x84, WOLcrClr=0xA4, WOLcgClr=0xA7, - PwrcsrClr=0xAC, -}; - -/* Bits in the interrupt status/mask registers. */ -enum intr_status_bits { - IntrRxDone=0x0001, IntrRxErr=0x0004, IntrRxEmpty=0x0020, - IntrTxDone=0x0002, IntrTxError=0x0008, IntrTxUnderrun=0x0210, - IntrPCIErr=0x0040, - IntrStatsMax=0x0080, IntrRxEarly=0x0100, - IntrRxOverflow=0x0400, IntrRxDropped=0x0800, IntrRxNoBuf=0x1000, - IntrTxAborted=0x2000, IntrLinkChange=0x4000, - IntrRxWakeUp=0x8000, - IntrNormalSummary=0x0003, IntrAbnormalSummary=0xC260, - IntrTxDescRace=0x080000, /* mapped from IntrStatus2 */ - IntrTxErrSummary=0x082218, -}; -#define DEFAULT_INTR (IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow | \ - IntrRxDropped | IntrRxNoBuf) - -/*************************************************************************** - IRQ - PXE IRQ Handler -***************************************************************************/ -void rhine_irq ( struct nic *nic, irq_action_t action ) { - struct rhine_private *tp = (struct rhine_private *) nic->priv_data; - /* Enable interrupts by setting the interrupt mask. */ - unsigned int intr_status; - - switch ( action ) { - case DISABLE : - case ENABLE : - intr_status = inw(nic->ioaddr + IntrStatus); - /* On Rhine-II, Bit 3 indicates Tx descriptor write-back race. */ - - /* added comment by guard */ - /* For supporting VT6107, please use revision id to recognize different chips in driver */ - // if (tp->chip_id == 0x3065) - if( tp->chip_revision < 0x80 && tp->chip_revision >=0x40 ) - intr_status |= inb(nic->ioaddr + IntrStatus2) << 16; - intr_status = (intr_status & ~DEFAULT_INTR); - if ( action == ENABLE ) - intr_status = intr_status | DEFAULT_INTR; - outw(intr_status, nic->ioaddr + IntrEnable); - break; - case FORCE : - outw(0x0010, nic->ioaddr + 0x84); - break; - } -} - -static struct nic_operations rhine_operations; - -static int -rhine_probe ( struct nic *nic, struct pci_device *pci ) { - - struct rhine_private *tp = (struct rhine_private *) nic->priv_data; - - if (!pci->ioaddr) - return 0; - - rhine_probe1 (nic, pci, pci->ioaddr, pci->device, -1); - - adjust_pci_device ( pci ); - - rhine_reset (nic); - - nic->nic_op = &rhine_operations; - - nic->irqno = pci->irq; - nic->ioaddr = tp->ioaddr; - - return 1; -} - -static void set_rx_mode(struct nic *nic __unused) { - struct rhine_private *tp = (struct rhine_private *) nic->priv_data; - unsigned char rx_mode; - int ioaddr = tp->ioaddr; - - /* ! IFF_PROMISC */ - outl(0xffffffff, byMAR0); - outl(0xffffffff, byMAR4); - rx_mode = 0x0C; - - outb(0x60 /* thresh */ | rx_mode, byRCR ); -} - -static void -rhine_probe1 (struct nic *nic, struct pci_device *pci, int ioaddr, int chip_id, int options) -{ - struct rhine_private *tp; - static int did_version = 0; /* Already printed version info. */ - unsigned int i, ww; - unsigned int timeout; - int FDXFlag; - int byMIIvalue, LineSpeed, MIICRbak; - uint8_t revision_id; - unsigned char mode3_reg; - - if (rhine_debug > 0 && did_version++ == 0) - printf ("%s",version); - - // get revision id. - pci_read_config_byte(pci, PCI_REVISION, &revision_id); - - /* D-Link provided reset code (with comment additions) */ - if (revision_id >= 0x40) { - unsigned char byOrgValue; - - if(rhine_debug > 0) - printf("Enabling Sticky Bit Workaround for Chip_id: 0x%hX\n" - , chip_id); - /* clear sticky bit before reset & read ethernet address */ - byOrgValue = inb(bySTICKHW); - byOrgValue = byOrgValue & 0xFC; - outb(byOrgValue, bySTICKHW); - - /* (bits written are cleared?) */ - /* disable force PME-enable */ - outb(0x80, byWOLcgClr); - /* disable power-event config bit */ - outb(0xFF, byWOLcrClr); - /* clear power status (undocumented in vt6102 docs?) */ - outb(0xFF, byPwrcsrClr); - - } - - /* Reset the chip to erase previous misconfiguration. */ - outw(CR_SFRST, byCR0); - // if vt3043 delay after reset - if (revision_id <0x40) { - udelay(10000); - } - // polling till software reset complete - // W_MAX_TIMEOUT is the timeout period - for(ww = 0; ww < W_MAX_TIMEOUT; ww++) { - if ((inw(byCR0) & CR_SFRST) == 0) - break; - } - - // issue AUTOLoad in EECSR to reload eeprom - outb(0x20, byEECSR ); - - // if vt3065 delay after reset - if (revision_id >=0x40) { - // delay 8ms to let MAC stable - mdelay(8); - /* - * for 3065D, EEPROM reloaded will cause bit 0 in MAC_REG_CFGA - * turned on. it makes MAC receive magic packet - * automatically. So, we turn it off. (D-Link) - */ - outb(inb(byCFGA) & 0xFE, byCFGA); - } - - /* turn on bit2 in PCI configuration register 0x53 , only for 3065*/ - if (revision_id >= 0x40) { - pci_read_config_byte(pci, PCI_REG_MODE3, &mode3_reg); - pci_write_config_byte(pci, PCI_REG_MODE3, mode3_reg|MODE3_MIION); - } - - - /* back off algorithm ,disable the right-most 4-bit off CFGD*/ - outb(inb(byCFGD) & (~(CFGD_RANDOM | CFGD_CFDX | CFGD_CEREN | CFGD_CETEN)), byCFGD); - - /* reload eeprom */ - reload_eeprom(ioaddr); - - /* Perhaps this should be read from the EEPROM? */ - for (i = 0; i < ETH_ALEN; i++) - nic->node_addr[i] = inb (byPAR0 + i); - - DBG ( "IO address %#hX Ethernet Address: %s\n", ioaddr, eth_ntoa ( nic->node_addr ) ); - - /* restart MII auto-negotiation */ - WriteMII (0, 9, 1, ioaddr); - printf ("Analyzing Media type,this may take several seconds... "); - for (i = 0; i < 5; i++) - { - /* need to wait 1 millisecond - we will round it up to 50-100ms */ - timeout = currticks() + 2; - for (timeout = currticks() + 2; currticks() < timeout;) - /* nothing */; - if (ReadMII (1, ioaddr) & 0x0020) - break; - } - printf ("OK.\n"); - -#if 0 - /* JJM : for Debug */ - printf("MII : Address %hhX ",inb(ioaddr+0x6c)); - { - unsigned char st1,st2,adv1,adv2,l1,l2; - - st1=ReadMII(1,ioaddr)>>8; - st2=ReadMII(1,ioaddr)&0xFF; - adv1=ReadMII(4,ioaddr)>>8; - adv2=ReadMII(4,ioaddr)&0xFF; - l1=ReadMII(5,ioaddr)>>8; - l2=ReadMII(5,ioaddr)&0xFF; - printf(" status 0x%hhX%hhX, advertising 0x%hhX%hhX, link 0x%hhX%hhX\n", st1,st2,adv1,adv2,l1,l2); - } -#endif - - - /* query MII to know LineSpeed,duplex mode */ - byMIIvalue = inb (ioaddr + 0x6d); - LineSpeed = byMIIvalue & MIISR_SPEED; - if (LineSpeed != 0) //JJM - { - printf ("Linespeed=10Mbs"); - } - else - { - printf ("Linespeed=100Mbs"); - } - - FDXFlag = QueryAuto (ioaddr); - if (FDXFlag == 1) - { - printf (" Fullduplex\n"); - outw (CR_FDX, byCR0); - } - else - { - printf (" Halfduplex\n"); - } - - - /* set MII 10 FULL ON, only apply in vt3043 */ - if(chip_id == 0x3043) - WriteMII (0x17, 1, 1, ioaddr); - - /* turn on MII link change */ - MIICRbak = inb (byMIICR); - outb (MIICRbak & 0x7F, byMIICR); - MIIDelay (); - outb (0x41, byMIIAD); - MIIDelay (); - - /* while((inb(byMIIAD)&0x20)==0) ; */ - outb (MIICRbak | 0x80, byMIICR); - - nic->priv_data = &rhine; - tp = &rhine; - tp->chip_id = chip_id; - tp->ioaddr = ioaddr; - tp->phys[0] = -1; - tp->chip_revision = revision_id; - - /* The lower four bits are the media type. */ - if (options > 0) - { - tp->full_duplex = (options & 16) ? 1 : 0; - tp->default_port = options & 15; - if (tp->default_port) - tp->medialock = 1; - } - return; -} - -static void -rhine_disable ( struct nic *nic ) { - - struct rhine_private *tp = (struct rhine_private *) nic->priv_data; - int ioaddr = tp->ioaddr; - - rhine_reset(nic); - - printf ("rhine disable\n"); - /* Switch to loopback mode to avoid hardware races. */ - outb(0x60 | 0x01, byTCR); - /* Stop the chip's Tx and Rx processes. */ - outw(CR_STOP, byCR0); -} - -/************************************************************************** -ETH_RESET - Reset adapter -***************************************************************************/ -static void -rhine_reset (struct nic *nic) -{ - struct rhine_private *tp = (struct rhine_private *) nic->priv_data; - int ioaddr = tp->ioaddr; - int i, j; - int FDXFlag, CRbak; - void *rx_ring_tmp; - void *tx_ring_tmp; - void *rx_bufs_tmp; - void *tx_bufs_tmp; - unsigned long rx_ring_tmp1; - unsigned long tx_ring_tmp1; - unsigned long rx_bufs_tmp1; - unsigned long tx_bufs_tmp1; - - /* printf ("rhine_reset\n"); */ - /* Soft reset the chip. */ - /*outb(CmdReset, ioaddr + ChipCmd); */ - - tx_bufs_tmp = rhine_buffers.txbuf; - tx_ring_tmp = rhine_buffers.txdesc; - rx_bufs_tmp = rhine_buffers.rxbuf; - rx_ring_tmp = rhine_buffers.rxdesc; - - /* tune RD TD 32 byte alignment */ - rx_ring_tmp1 = virt_to_bus ( rx_ring_tmp ); - j = (rx_ring_tmp1 + 32) & (~0x1f); - /* printf ("txring[%d]", j); */ - tp->rx_ring = (struct rhine_rx_desc *) bus_to_virt (j); - - tx_ring_tmp1 = virt_to_bus ( tx_ring_tmp ); - j = (tx_ring_tmp1 + 32) & (~0x1f); - tp->tx_ring = (struct rhine_tx_desc *) bus_to_virt (j); - /* printf ("rxring[%X]", j); */ - - - tx_bufs_tmp1 = virt_to_bus ( tx_bufs_tmp ); - j = (int) (tx_bufs_tmp1 + 32) & (~0x1f); - tx_bufs_tmp = bus_to_virt (j); - /* printf ("txb[%X]", j); */ - - rx_bufs_tmp1 = virt_to_bus ( rx_bufs_tmp ); - j = (int) (rx_bufs_tmp1 + 32) & (~0x1f); - rx_bufs_tmp = bus_to_virt (j); - /* printf ("rxb[%X][%X]", rx_bufs_tmp1, j); */ - - for (i = 0; i < RX_RING_SIZE; i++) - { - tp->rx_buffs[i] = (char *) rx_bufs_tmp; - /* printf("r[%X]",tp->rx_buffs[i]); */ - rx_bufs_tmp += 1536; - } - - for (i = 0; i < TX_RING_SIZE; i++) - { - tp->tx_buffs[i] = (char *) tx_bufs_tmp; - /* printf("t[%X]",tp->tx_buffs[i]); */ - tx_bufs_tmp += 1536; - } - - /* software reset */ - outb (CR1_SFRST, byCR1); - MIIDelay (); - - /* printf ("init ring"); */ - rhine_init_ring (nic); - /*write TD RD Descriptor to MAC */ - outl (virt_to_bus (tp->rx_ring), dwCurrentRxDescAddr); - outl (virt_to_bus (tp->tx_ring), dwCurrentTxDescAddr); - - /* Setup Multicast */ - set_rx_mode(nic); - - /* set TCR RCR threshold to store and forward*/ - outb (0x3e, byBCR0); - outb (0x38, byBCR1); - outb (0x2c, byRCR); - outb (0x60, byTCR); - /* Set Fulldupex */ - FDXFlag = QueryAuto (ioaddr); - if (FDXFlag == 1) - { - outb (CFGD_CFDX, byCFGD); - outw (CR_FDX, byCR0); - } - - /* KICK NIC to WORK */ - CRbak = inw (byCR0); - CRbak = CRbak & 0xFFFB; /* not CR_STOP */ - outw ((CRbak | CR_STRT | CR_TXON | CR_RXON | CR_DPOLL), byCR0); - - /* disable all known interrupt */ - outw (0, byIMR0); -} -/* Beware of PCI posted writes */ -#define IOSYNC do { inb(nic->ioaddr + StationAddr); } while (0) - -static int -rhine_poll (struct nic *nic, int retrieve) -{ - struct rhine_private *tp = (struct rhine_private *) nic->priv_data; - int rxstatus, good = 0;; - - if (tp->rx_ring[tp->cur_rx].rx_status.bits.own_bit == 0) - { - unsigned int intr_status; - /* There is a packet ready */ - if(!retrieve) - return 1; - - intr_status = inw(nic->ioaddr + IntrStatus); - /* On Rhine-II, Bit 3 indicates Tx descriptor write-back race. */ -#if 0 - if (tp->chip_id == 0x3065) - intr_status |= inb(nic->ioaddr + IntrStatus2) << 16; -#endif - /* Acknowledge all of the current interrupt sources ASAP. */ - if (intr_status & IntrTxDescRace) - outb(0x08, nic->ioaddr + IntrStatus2); - outw(intr_status & 0xffff, nic->ioaddr + IntrStatus); - IOSYNC; - - rxstatus = tp->rx_ring[tp->cur_rx].rx_status.lw; - if ((rxstatus & 0x0300) != 0x0300) - { - printf("rhine_poll: bad status\n"); - } - else if (rxstatus & (RSR_ABNORMAL)) - { - printf ("rxerr[%X]\n", rxstatus); - } - else - good = 1; - - if (good) - { - nic->packetlen = tp->rx_ring[tp->cur_rx].rx_status.bits.frame_length; - memcpy (nic->packet, tp->rx_buffs[tp->cur_rx], nic->packetlen); - /* printf ("Packet RXed\n"); */ - } - tp->rx_ring[tp->cur_rx].rx_status.bits.own_bit = 1; - tp->cur_rx++; - tp->cur_rx = tp->cur_rx % RX_RING_SIZE; - } - /* Acknowledge all of the current interrupt sources ASAP. */ - outw(DEFAULT_INTR & ~IntrRxDone, nic->ioaddr + IntrStatus); - - IOSYNC; - - return good; -} - -static void -rhine_transmit (struct nic *nic, - const char *d, unsigned int t, unsigned int s, const char *p) -{ - struct rhine_private *tp = (struct rhine_private *) nic->priv_data; - int ioaddr = tp->ioaddr; - int entry; - unsigned char CR1bak; - unsigned char CR0bak; - unsigned int nstype; - unsigned long ct; - - - /*printf ("rhine_transmit\n"); */ - /* setup ethernet header */ - - - /* Calculate the next Tx descriptor entry. */ - entry = tp->cur_tx % TX_RING_SIZE; - - memcpy (tp->tx_buffs[entry], d, ETH_ALEN); /* dst */ - memcpy (tp->tx_buffs[entry] + ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */ - - nstype=htons(t); - memcpy(tp->tx_buffs[entry] + 2 * ETH_ALEN, (char*)&nstype, 2); - - memcpy (tp->tx_buffs[entry] + ETH_HLEN, p, s); - s += ETH_HLEN; - while (s < ETH_ZLEN) - *((char *) tp->tx_buffs[entry] + (s++)) = 0; - - tp->tx_ring[entry].tx_ctrl.bits.tx_buf_size = s; - - tp->tx_ring[entry].tx_status.bits.own_bit = 1; - - - CR1bak = inb (byCR1); - - CR1bak = CR1bak | CR1_TDMD1; - /*printf("tdsw=[%X]",tp->tx_ring[entry].tx_status.lw); */ - /*printf("tdcw=[%X]",tp->tx_ring[entry].tx_ctrl.lw); */ - /*printf("tdbuf1=[%X]",tp->tx_ring[entry].buf_addr_1); */ - /*printf("tdbuf2=[%X]",tp->tx_ring[entry].buf_addr_2); */ - /*printf("td1=[%X]",inl(dwCurrentTDSE0)); */ - /*printf("td2=[%X]",inl(dwCurrentTDSE1)); */ - /*printf("td3=[%X]",inl(dwCurrentTDSE2)); */ - /*printf("td4=[%X]",inl(dwCurrentTDSE3)); */ - - outb (CR1bak, byCR1); - do - { - ct = currticks(); - /* Wait until transmit is finished or timeout*/ - while((tp->tx_ring[entry].tx_status.bits.own_bit !=0) && - ct + 10*1000 < currticks()) - ; - - if(tp->tx_ring[entry].tx_status.bits.terr == 0) - break; - - if(tp->tx_ring[entry].tx_status.bits.abt == 1) - { - // turn on TX - CR0bak = inb(byCR0); - CR0bak = CR0bak|CR_TXON; - outb(CR0bak,byCR0); - } - }while(0); - tp->cur_tx++; - - /*outw(IMRShadow,byIMR0); */ - /*dev_kfree_skb(tp->tx_skbuff[entry], FREE_WRITE); */ - /*tp->tx_skbuff[entry] = 0; */ -} - -static struct nic_operations rhine_operations = { - .connect = dummy_connect, - .poll = rhine_poll, - .transmit = rhine_transmit, - .irq = rhine_irq, - -}; - -static struct pci_device_id rhine_nics[] = { -PCI_ROM(0x1106, 0x3065, "dlink-530tx", "VIA 6102", 0), -PCI_ROM(0x1106, 0x3106, "via-rhine-6105", "VIA 6105", 0), -PCI_ROM(0x1106, 0x3043, "dlink-530tx-old", "VIA 3043", 0), /* Rhine-I 86c100a */ -PCI_ROM(0x1106, 0x3053, "via6105m", "VIA 6105M", 0), -PCI_ROM(0x1106, 0x6100, "via-rhine-old", "VIA 86C100A", 0), /* Rhine-II */ -}; - -PCI_DRIVER ( rhine_driver, rhine_nics, PCI_NO_CLASS ); - -DRIVER ( "VIA 86C100", nic_driver, pci_driver, rhine_driver, - rhine_probe, rhine_disable ); - -/* EOF via-rhine.c */ - -/* - * Local variables: - * c-basic-offset: 8 - * c-indent-level: 8 - * tab-width: 8 - * End: - */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 73e1d89f..2c4c9920 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -113,7 +113,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_sundance ( ERRFILE_DRIVER | 0x00410000 ) #define ERRFILE_tlan ( ERRFILE_DRIVER | 0x00420000 ) #define ERRFILE_tulip ( ERRFILE_DRIVER | 0x00430000 ) -#define ERRFILE_via_rhine ( ERRFILE_DRIVER | 0x00440000 ) +#define ERRFILE_rhine ( ERRFILE_DRIVER | 0x00440000 ) #define ERRFILE_via_velocity ( ERRFILE_DRIVER | 0x00450000 ) #define ERRFILE_w89c840 ( ERRFILE_DRIVER | 0x00460000 ) #define ERRFILE_ipoib ( ERRFILE_DRIVER | 0x00470000 )