[velocity] Rewrite VIA Velocity driver
Signed-off-by: Adrian Jamróz <adrian.jamroz@gmail.com> Modified-by: Thomas Miletich <thomas.miletich@gmail.com> Signed-off-by: Thomas Miletich <thomas.miletich@gmail.com> Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
parent
bba5a39026
commit
4fabc0012a
|
@ -0,0 +1,807 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Adrian Jamróz <adrian.jamroz@gmail.com>
|
||||
*
|
||||
* 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 <stdint.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <byteswap.h>
|
||||
#include <ipxe/netdevice.h>
|
||||
#include <ipxe/ethernet.h>
|
||||
#include <ipxe/if_ether.h>
|
||||
#include <ipxe/iobuf.h>
|
||||
#include <ipxe/malloc.h>
|
||||
#include <ipxe/pci.h>
|
||||
#include <ipxe/mii.h>
|
||||
#include "velocity.h"
|
||||
|
||||
#define velocity_setbit(_reg, _mask) writeb ( readb ( _reg ) | _mask, _reg )
|
||||
#define virt_to_le32bus(x) ( cpu_to_le32 ( virt_to_bus ( x ) ) )
|
||||
|
||||
/** @file
|
||||
*
|
||||
* VIA Velocity network driver
|
||||
*
|
||||
*/
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* MII interface
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
* Stop MII auto-polling
|
||||
*
|
||||
* @v vlc Velocity device
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int velocity_autopoll_stop ( struct velocity_nic *vlc ) {
|
||||
int timeout = VELOCITY_TIMEOUT_US;
|
||||
|
||||
/* Disable MII auto polling */
|
||||
writeb ( 0, vlc->regs + VELOCITY_MIICR );
|
||||
|
||||
/* Wait for disabling to take effect */
|
||||
while ( timeout-- ) {
|
||||
udelay ( 1 );
|
||||
if ( readb ( vlc->regs + VELOCITY_MIISR ) &
|
||||
VELOCITY_MIISR_IDLE )
|
||||
return 0;
|
||||
}
|
||||
|
||||
DBGC ( vlc, "MII autopoll stop timeout\n" );
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start MII auto-polling
|
||||
*
|
||||
* @v vlc Velocity device
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int velocity_autopoll_start ( struct velocity_nic *vlc ) {
|
||||
int timeout = VELOCITY_TIMEOUT_US;
|
||||
|
||||
/* Enable MII auto polling */
|
||||
writeb ( VELOCITY_MIICR_MAUTO, vlc->regs + VELOCITY_MIICR );
|
||||
|
||||
/* Wait for enabling to take effect */
|
||||
while ( timeout-- ) {
|
||||
udelay ( 1 );
|
||||
if ( ( readb ( vlc->regs + VELOCITY_MIISR ) &
|
||||
VELOCITY_MIISR_IDLE ) == 0 )
|
||||
return 0;
|
||||
}
|
||||
|
||||
DBGC ( vlc, "MII autopoll start timeout\n" );
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read from MII register
|
||||
*
|
||||
* @v mii MII interface
|
||||
* @v reg Register address
|
||||
* @ret value Data read, or negative error
|
||||
*/
|
||||
static int velocity_mii_read ( struct mii_interface *mii, unsigned int reg ) {
|
||||
struct velocity_nic *vlc =
|
||||
container_of ( mii, struct velocity_nic, mii );
|
||||
int timeout = VELOCITY_TIMEOUT_US;
|
||||
int result;
|
||||
|
||||
DBGC2 ( vlc, "VELOCITY %p MII read reg %d\n", vlc, reg );
|
||||
|
||||
/* Disable autopolling before we can access MII */
|
||||
velocity_autopoll_stop ( vlc );
|
||||
|
||||
/* Send read command and address */
|
||||
writeb ( reg, vlc->regs + VELOCITY_MIIADDR );
|
||||
velocity_setbit ( vlc->regs + VELOCITY_MIICR, VELOCITY_MIICR_RCMD );
|
||||
|
||||
/* Wait for read to complete */
|
||||
while ( timeout-- ) {
|
||||
udelay ( 1 );
|
||||
if ( ( readb ( vlc->regs + VELOCITY_MIICR ) &
|
||||
VELOCITY_MIICR_RCMD ) == 0 ) {
|
||||
result = readw ( vlc->regs + VELOCITY_MIIDATA );
|
||||
velocity_autopoll_start ( vlc );
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/* Restart autopolling */
|
||||
velocity_autopoll_start ( vlc );
|
||||
|
||||
DBGC ( vlc, "MII read timeout\n" );
|
||||
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 velocity_mii_write ( struct mii_interface *mii, unsigned int reg,
|
||||
unsigned int data) {
|
||||
struct velocity_nic *vlc =
|
||||
container_of ( mii, struct velocity_nic, mii );
|
||||
int timeout = VELOCITY_TIMEOUT_US;
|
||||
|
||||
DBGC2 ( vlc, "VELOCITY %p MII write reg %d data 0x%04x\n",
|
||||
vlc, reg, data );
|
||||
|
||||
/* Disable autopolling before we can access MII */
|
||||
velocity_autopoll_stop ( vlc );
|
||||
|
||||
/* Send write command, data and destination register */
|
||||
writeb ( reg, vlc->regs + VELOCITY_MIIADDR );
|
||||
writew ( data, vlc->regs + VELOCITY_MIIDATA );
|
||||
velocity_setbit ( vlc->regs + VELOCITY_MIICR, VELOCITY_MIICR_WCMD );
|
||||
|
||||
/* Wait for write to complete */
|
||||
while ( timeout-- ) {
|
||||
udelay ( 1 );
|
||||
if ( ( readb ( vlc->regs + VELOCITY_MIICR ) &
|
||||
VELOCITY_MIICR_WCMD ) == 0 ) {
|
||||
velocity_autopoll_start ( vlc );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Restart autopolling */
|
||||
velocity_autopoll_start ( vlc );
|
||||
|
||||
DBGC ( vlc, "MII write timeout\n" );
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/** Velocity MII operations */
|
||||
static struct mii_operations velocity_mii_operations = {
|
||||
.read = velocity_mii_read,
|
||||
.write = velocity_mii_write,
|
||||
};
|
||||
|
||||
/**
|
||||
* Set Link speed
|
||||
*
|
||||
* @v vlc Velocity device
|
||||
*/
|
||||
static void velocity_set_link ( struct velocity_nic *vlc ) {
|
||||
int tmp;
|
||||
|
||||
/* Advertise 1000MBit */
|
||||
tmp = velocity_mii_read ( &vlc->mii, MII_CTRL1000 );
|
||||
tmp |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
|
||||
velocity_mii_write ( &vlc->mii, MII_CTRL1000, tmp );
|
||||
|
||||
/* Enable GBit operation in MII Control Register */
|
||||
tmp = velocity_mii_read ( &vlc->mii, MII_BMCR );
|
||||
tmp |= BMCR_SPEED1000;
|
||||
velocity_mii_write ( &vlc->mii, MII_BMCR, tmp );
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Device reset
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
* Reload eeprom contents
|
||||
*
|
||||
* @v vlc Velocity device
|
||||
*/
|
||||
static int velocity_reload_eeprom ( struct velocity_nic *vlc ) {
|
||||
int timeout = VELOCITY_TIMEOUT_US;
|
||||
|
||||
/* Initiate reload */
|
||||
velocity_setbit ( vlc->regs + VELOCITY_EECSR, VELOCITY_EECSR_RELOAD );
|
||||
|
||||
/* Wait for reload to complete */
|
||||
while ( timeout-- ) {
|
||||
udelay ( 1 );
|
||||
if ( ( readb ( vlc->regs + VELOCITY_EECSR ) &
|
||||
VELOCITY_EECSR_RELOAD ) == 0 )
|
||||
return 0;
|
||||
}
|
||||
|
||||
DBGC ( vlc, "VELOCITY %p EEPROM reload timeout\n", vlc );
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset hardware
|
||||
*
|
||||
* @v vlc Velocity device
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int velocity_reset ( struct velocity_nic *vlc ) {
|
||||
int timeout = VELOCITY_TIMEOUT_US;
|
||||
uint8_t tmp;
|
||||
|
||||
DBGC ( vlc, "VELOCITY %p reset\n", vlc );
|
||||
|
||||
/* clear sticky Power state bits */
|
||||
tmp = readb ( vlc->regs + VELOCITY_STICKY );
|
||||
tmp &= ~( VELOCITY_STICKY_DS0 | VELOCITY_STICKY_DS1 );
|
||||
writeb ( tmp, vlc->regs + VELOCITY_STICKY );
|
||||
|
||||
/* clear PACPI, which might have been enabled by the EEPROM reload */
|
||||
tmp = readb ( vlc->regs + VELOCITY_CFGA );
|
||||
tmp &= ~VELOCITY_CFGA_PACPI;
|
||||
writeb ( tmp, vlc->regs + VELOCITY_CFGA );
|
||||
|
||||
velocity_setbit ( vlc->regs + VELOCITY_CRS1, VELOCITY_CR1_SFRST );
|
||||
|
||||
/* Wait for reset to complete */
|
||||
while ( timeout-- ) {
|
||||
udelay ( 1 );
|
||||
if ( ( readb ( vlc->regs + VELOCITY_CRS1 ) &
|
||||
VELOCITY_CR1_SFRST ) == 0 )
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Link state
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
* Check link state
|
||||
*
|
||||
* @v netdev Network device
|
||||
*/
|
||||
static void velocity_check_link ( struct net_device *netdev ) {
|
||||
struct velocity_nic *vlc = netdev->priv;
|
||||
|
||||
if ( readb ( vlc->regs + VELOCITY_PHYSTS0 ) & VELOCITY_PHYSTS0_LINK ) {
|
||||
netdev_link_up ( netdev );
|
||||
DBGC ( vlc, "VELOCITY %p link up\n", vlc );
|
||||
} else {
|
||||
netdev_link_down ( netdev );
|
||||
DBGC ( vlc, "VELOCITY %p link down\n", vlc );
|
||||
}
|
||||
|
||||
/* The card disables auto-poll after a link change */
|
||||
velocity_autopoll_start ( vlc );
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Network device interface
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
* Allocate descriptor rings
|
||||
*
|
||||
* @v vlc Velocity device
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int velocity_alloc_rings ( struct velocity_nic *vlc ) {
|
||||
int rc = 0;
|
||||
|
||||
/* Allocate RX descriptor ring */
|
||||
vlc->rx_prod = 0;
|
||||
vlc->rx_cons = 0;
|
||||
vlc->rx_commit = 0;
|
||||
vlc->rx_ring = malloc_dma ( VELOCITY_RXDESC_SIZE, VELOCITY_RING_ALIGN );
|
||||
if ( ! vlc->rx_ring )
|
||||
return -ENOMEM;
|
||||
|
||||
memset ( vlc->rx_ring, 0, VELOCITY_RXDESC_SIZE );
|
||||
|
||||
DBGC2 ( vlc, "VELOCITY %p RX ring start address: %p(phys: %#08lx)\n",
|
||||
vlc, vlc->rx_ring, virt_to_bus ( vlc->rx_ring ) );
|
||||
|
||||
/* Allocate TX descriptor ring */
|
||||
vlc->tx_prod = 0;
|
||||
vlc->tx_cons = 0;
|
||||
vlc->tx_ring = malloc_dma ( VELOCITY_TXDESC_SIZE, VELOCITY_RING_ALIGN );
|
||||
if ( ! vlc->tx_ring ) {
|
||||
rc = -ENOMEM;
|
||||
goto err_tx_alloc;
|
||||
}
|
||||
|
||||
memset ( vlc->tx_ring, 0, VELOCITY_TXDESC_SIZE );
|
||||
|
||||
/* Send RX ring to the card */
|
||||
writel ( virt_to_bus ( vlc->rx_ring ),
|
||||
vlc->regs + VELOCITY_RXDESC_ADDR_LO );
|
||||
writew ( VELOCITY_RXDESC_NUM - 1, vlc->regs + VELOCITY_RXDESCNUM );
|
||||
|
||||
/* Send TX ring to the card */
|
||||
writel ( virt_to_bus ( vlc->tx_ring ),
|
||||
vlc->regs + VELOCITY_TXDESC_ADDR_LO0 );
|
||||
writew ( VELOCITY_TXDESC_NUM - 1, vlc->regs + VELOCITY_TXDESCNUM );
|
||||
|
||||
DBGC2 ( vlc, "VELOCITY %p TX ring start address: %p(phys: %#08lx)\n",
|
||||
vlc, vlc->tx_ring, virt_to_bus ( vlc->tx_ring ) );
|
||||
|
||||
return 0;
|
||||
|
||||
err_tx_alloc:
|
||||
free_dma ( vlc->rx_ring, VELOCITY_RXDESC_SIZE );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refill receive descriptor ring
|
||||
*
|
||||
* @v vlc Velocity device
|
||||
*/
|
||||
static void velocity_refill_rx ( struct velocity_nic *vlc ) {
|
||||
struct velocity_rx_descriptor *desc;
|
||||
struct io_buffer *iobuf;
|
||||
int rx_idx, i = 0;
|
||||
|
||||
/* Check for new packets */
|
||||
while ( ( vlc->rx_prod - vlc->rx_cons ) < VELOCITY_RXDESC_NUM ) {
|
||||
iobuf = alloc_iob ( VELOCITY_RX_MAX_LEN );
|
||||
|
||||
/* Memory pressure: try again next poll */
|
||||
if ( ! iobuf )
|
||||
break;
|
||||
|
||||
rx_idx = ( vlc->rx_prod++ % VELOCITY_RXDESC_NUM );
|
||||
desc = &vlc->rx_ring[rx_idx];
|
||||
|
||||
/* Set descrptor fields */
|
||||
desc->des1 = 0;
|
||||
desc->addr = virt_to_le32bus ( iobuf-> data );
|
||||
desc->des2 = cpu_to_le32 (
|
||||
VELOCITY_DES2_SIZE ( VELOCITY_RX_MAX_LEN - 1 ) |
|
||||
VELOCITY_DES2_IC );
|
||||
|
||||
vlc->rx_buffs[rx_idx] = iobuf;
|
||||
i++;
|
||||
|
||||
/* Return RX descriptors in blocks of 4 (hw requirement) */
|
||||
if ( rx_idx % 4 == 3 ) {
|
||||
int j;
|
||||
for (j = 0; j < 4; j++) {
|
||||
desc = &vlc->rx_ring[rx_idx - j];
|
||||
desc->des0 = cpu_to_le32 ( VELOCITY_DES0_OWN );
|
||||
}
|
||||
vlc->rx_commit += 4;
|
||||
}
|
||||
}
|
||||
|
||||
wmb();
|
||||
|
||||
if ( vlc->rx_commit ) {
|
||||
writew ( vlc->rx_commit,
|
||||
vlc->regs + VELOCITY_RXDESC_RESIDUECNT );
|
||||
vlc->rx_commit = 0;
|
||||
}
|
||||
|
||||
if ( i > 0 )
|
||||
DBGC2 ( vlc, "VELOCITY %p refilled %d RX descriptors\n",
|
||||
vlc, i );
|
||||
}
|
||||
|
||||
/**
|
||||
* Open network device
|
||||
*
|
||||
* @v netdev Network device
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int velocity_open ( struct net_device *netdev ) {
|
||||
struct velocity_nic *vlc = netdev->priv;
|
||||
int rc;
|
||||
|
||||
DBGC ( vlc, "VELOCITY %p open\n", vlc );
|
||||
DBGC ( vlc, "VELOCITY %p regs at: %p\n", vlc, vlc->regs );
|
||||
|
||||
/* Allocate descriptor rings */
|
||||
if ( ( rc = velocity_alloc_rings ( vlc ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
velocity_refill_rx ( vlc );
|
||||
|
||||
/* Enable TX/RX queue */
|
||||
writew ( VELOCITY_TXQCSRS_RUN0, vlc->regs + VELOCITY_TXQCSRS );
|
||||
writew ( VELOCITY_RXQCSR_RUN | VELOCITY_RXQCSR_WAK,
|
||||
vlc->regs + VELOCITY_RXQCSRS );
|
||||
|
||||
/* Enable interrupts */
|
||||
writeb ( 0xff, vlc->regs + VELOCITY_IMR0 );
|
||||
writeb ( 0xff, vlc->regs + VELOCITY_IMR1 );
|
||||
|
||||
/* Start MAC */
|
||||
writeb ( VELOCITY_CR0_STOP, vlc->regs + VELOCITY_CRC0 );
|
||||
writeb ( VELOCITY_CR1_DPOLL, vlc->regs + VELOCITY_CRC0 );
|
||||
writeb ( VELOCITY_CR0_START | VELOCITY_CR0_TXON | VELOCITY_CR0_RXON,
|
||||
vlc->regs + VELOCITY_CRS0 );
|
||||
|
||||
/* Receive all packets */
|
||||
writeb ( 0xff, vlc->regs + VELOCITY_RCR );
|
||||
|
||||
/* Set initial link state */
|
||||
velocity_check_link ( netdev );
|
||||
|
||||
velocity_autopoll_start ( vlc );
|
||||
|
||||
DBGC2 ( vlc, "VELOCITY %p CR3 %02x\n",
|
||||
vlc, readb ( vlc->regs + 0x0B ) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close network device
|
||||
*
|
||||
* @v netdev Network device
|
||||
*/
|
||||
static void velocity_close ( struct net_device *netdev ) {
|
||||
struct velocity_nic *vlc = netdev->priv;
|
||||
int i;
|
||||
|
||||
/* Stop NIC */
|
||||
writeb ( VELOCITY_CR0_TXON | VELOCITY_CR0_RXON,
|
||||
vlc->regs + VELOCITY_CRC0 );
|
||||
writeb ( VELOCITY_CR0_STOP, vlc->regs + VELOCITY_CRS0 );
|
||||
|
||||
/* Clear RX ring information */
|
||||
writel ( 0, vlc->regs + VELOCITY_RXDESC_ADDR_LO );
|
||||
writew ( 0, vlc->regs + VELOCITY_RXDESCNUM );
|
||||
|
||||
/* Destroy RX ring */
|
||||
free_dma ( vlc->rx_ring, VELOCITY_RXDESC_SIZE );
|
||||
vlc->rx_ring = NULL;
|
||||
vlc->rx_prod = 0;
|
||||
vlc->rx_cons = 0;
|
||||
|
||||
/* Discard receive buffers */
|
||||
for ( i = 0 ; i < VELOCITY_RXDESC_NUM ; i++ ) {
|
||||
if ( vlc->rx_buffs[i] )
|
||||
free_iob ( vlc->rx_buffs[i] );
|
||||
vlc->rx_buffs[i] = NULL;
|
||||
}
|
||||
|
||||
/* Clear TX ring information */
|
||||
writel ( 0, vlc->regs + VELOCITY_TXDESC_ADDR_LO0 );
|
||||
writew ( 0, vlc->regs + VELOCITY_TXDESCNUM );
|
||||
|
||||
/* Destroy TX ring */
|
||||
free_dma ( vlc->tx_ring, VELOCITY_TXDESC_SIZE );
|
||||
vlc->tx_ring = NULL;
|
||||
vlc->tx_prod = 0;
|
||||
vlc->tx_cons = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transmit packet
|
||||
*
|
||||
* @v netdev Network device
|
||||
* @v iobuf I/O buffer
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int velocity_transmit ( struct net_device *netdev,
|
||||
struct io_buffer *iobuf ) {
|
||||
struct velocity_nic *vlc = netdev->priv;
|
||||
struct velocity_tx_descriptor *desc;
|
||||
unsigned int tx_idx;
|
||||
|
||||
/* Pad packet to minimum length */
|
||||
iob_pad ( iobuf, ETH_ZLEN );
|
||||
|
||||
tx_idx = ( vlc->tx_prod++ % VELOCITY_TXDESC_NUM );
|
||||
desc = &vlc->tx_ring[tx_idx];
|
||||
|
||||
/* Set packet size and transfer ownership to NIC */
|
||||
desc->des0 = cpu_to_le32 ( VELOCITY_DES0_OWN |
|
||||
VELOCITY_DES2_SIZE ( iob_len ( iobuf ) ) );
|
||||
/* Data in first desc fragment, only desc for packet, generate INT */
|
||||
desc->des1 = cpu_to_le32 ( VELOCITY_DES1_FRAG ( 1 ) |
|
||||
VELOCITY_DES1_TCPLS |
|
||||
VELOCITY_DES1_INTR );
|
||||
|
||||
desc->frags[0].addr = virt_to_le32bus ( iobuf->data );
|
||||
desc->frags[0].des2 = cpu_to_le32 (
|
||||
VELOCITY_DES2_SIZE ( iob_len ( iobuf ) ) );
|
||||
|
||||
wmb();
|
||||
|
||||
/* Initiate TX */
|
||||
velocity_setbit ( vlc->regs + VELOCITY_TXQCSRS, VELOCITY_TXQCSRS_WAK0 );
|
||||
|
||||
DBGC2 ( vlc, "VELOCITY %p tx_prod=%d desc=%p iobuf=%p len=%zd\n",
|
||||
vlc, tx_idx, desc, iobuf->data, iob_len ( iobuf ) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Poll for received packets.
|
||||
*
|
||||
* @v vlc Velocity device
|
||||
*/
|
||||
static void velocity_poll_rx ( struct velocity_nic *vlc ) {
|
||||
struct velocity_rx_descriptor *desc;
|
||||
struct io_buffer *iobuf;
|
||||
int rx_idx;
|
||||
size_t len;
|
||||
uint32_t des0;
|
||||
|
||||
/* Check for packets */
|
||||
while ( vlc->rx_cons != vlc->rx_prod ) {
|
||||
rx_idx = ( vlc->rx_cons % VELOCITY_RXDESC_NUM );
|
||||
desc = &vlc->rx_ring[rx_idx];
|
||||
|
||||
des0 = cpu_to_le32 ( desc->des0 );
|
||||
|
||||
/* Return if descriptor still in use */
|
||||
if ( des0 & VELOCITY_DES0_OWN )
|
||||
return;
|
||||
|
||||
iobuf = vlc->rx_buffs[rx_idx];
|
||||
|
||||
/* Get length, strip CRC */
|
||||
len = VELOCITY_DES0_RMBC ( des0 ) - 4;
|
||||
iob_put ( iobuf, len );
|
||||
|
||||
DBGC2 ( vlc, "VELOCITY %p got packet on idx=%d (prod=%d), len %zd\n",
|
||||
vlc, rx_idx, vlc->rx_prod % VELOCITY_RXDESC_NUM, len );
|
||||
|
||||
if ( des0 & VELOCITY_DES0_RX_ERR ) {
|
||||
/* Report receive error */
|
||||
netdev_rx_err ( vlc->netdev, iobuf, -EINVAL );
|
||||
DBGC ( vlc, "VELOCITY %p receive error, status: %02x\n",
|
||||
vlc, des0 );
|
||||
} else if ( des0 & VELOCITY_DES0_RXOK ) {
|
||||
/* Report receive success */
|
||||
netdev_rx( vlc->netdev, iobuf );
|
||||
} else {
|
||||
/* Card indicated neither success nor failure
|
||||
* Technically this shouldn't happen, but we saw it
|
||||
* in debugging once. */
|
||||
DBGC ( vlc, "VELOCITY %p RX neither ERR nor OK: %04x\n",
|
||||
vlc, des0 );
|
||||
DBGC ( vlc, "packet len: %zd\n", len );
|
||||
DBGC_HD ( vlc, iobuf->data, 64 );
|
||||
|
||||
/* we don't know what it is, treat is as an error */
|
||||
netdev_rx_err ( vlc->netdev, iobuf, -EINVAL );
|
||||
}
|
||||
|
||||
vlc->rx_cons++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Poll for completed packets.
|
||||
*
|
||||
* @v vlc Velocity device
|
||||
*/
|
||||
static void velocity_poll_tx ( struct velocity_nic *vlc ) {
|
||||
struct velocity_tx_descriptor *desc;
|
||||
int tx_idx;
|
||||
|
||||
/* Check for packets */
|
||||
while ( vlc->tx_cons != vlc->tx_prod ) {
|
||||
tx_idx = ( vlc->tx_cons % VELOCITY_TXDESC_NUM );
|
||||
desc = &vlc->tx_ring[tx_idx];
|
||||
|
||||
/* Return if descriptor still in use */
|
||||
if ( le32_to_cpu ( desc->des0 ) & VELOCITY_DES0_OWN )
|
||||
return;
|
||||
|
||||
/* Report errors */
|
||||
if ( le32_to_cpu ( desc->des0 ) & VELOCITY_DES0_TERR ) {
|
||||
netdev_tx_complete_next_err ( vlc->netdev, -EINVAL );
|
||||
return;
|
||||
}
|
||||
|
||||
netdev_tx_complete_next ( vlc->netdev );
|
||||
|
||||
DBGC2 ( vlc, "VELOCITY %p poll_tx cons=%d prod=%d tsr=%04x\n",
|
||||
vlc, tx_idx, vlc->tx_prod % VELOCITY_TXDESC_NUM,
|
||||
( desc->des0 & 0xffff ) );
|
||||
vlc->tx_cons++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Poll for completed and received packets
|
||||
*
|
||||
* @v netdev Network device
|
||||
*/
|
||||
static void velocity_poll ( struct net_device *netdev ) {
|
||||
struct velocity_nic *vlc = netdev->priv;
|
||||
uint8_t isr1;
|
||||
|
||||
isr1 = readb ( vlc->regs + VELOCITY_ISR1 );
|
||||
|
||||
/* ACK interrupts */
|
||||
writew ( 0xFFFF, vlc->regs + VELOCITY_ISR0 );
|
||||
|
||||
/* Check for competed packets */
|
||||
velocity_poll_rx ( vlc );
|
||||
velocity_poll_tx ( vlc );
|
||||
|
||||
if ( isr1 & VELOCITY_ISR1_SRCI ) {
|
||||
/* Update linkstate */
|
||||
DBGC2 ( vlc, "VELOCITY %p link status interrupt\n", vlc );
|
||||
velocity_check_link ( netdev );
|
||||
}
|
||||
|
||||
velocity_refill_rx ( vlc );
|
||||
|
||||
/* deal with potential RX stall caused by RX ring underrun */
|
||||
writew ( VELOCITY_RXQCSR_RUN | VELOCITY_RXQCSR_WAK,
|
||||
vlc->regs + VELOCITY_RXQCSRS );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable interrupts
|
||||
*
|
||||
* @v netdev Network device
|
||||
* @v enable Interrupts should be enabled
|
||||
*/
|
||||
static void velocity_irq ( struct net_device *netdev, int enable ) {
|
||||
struct velocity_nic *vlc = netdev->priv;
|
||||
|
||||
DBGC ( vlc, "VELOCITY %p interrupts %s\n", vlc,
|
||||
enable ? "enable" : "disable" );
|
||||
|
||||
if (enable) {
|
||||
/* Enable interrupts */
|
||||
writeb ( VELOCITY_CR3_GINTMSK1, vlc->regs + VELOCITY_CRS3 );
|
||||
} else {
|
||||
/* Disable interrupts */
|
||||
writeb ( VELOCITY_CR3_GINTMSK1, vlc->regs + VELOCITY_CRC3 );
|
||||
}
|
||||
}
|
||||
|
||||
/** Velocity network device operations */
|
||||
static struct net_device_operations velocity_operations = {
|
||||
.open = velocity_open,
|
||||
.close = velocity_close,
|
||||
.transmit = velocity_transmit,
|
||||
.poll = velocity_poll,
|
||||
.irq = velocity_irq,
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* PCI interface
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
* Probe PCI device
|
||||
*
|
||||
* @v pci PCI device
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int velocity_probe ( struct pci_device *pci ) {
|
||||
struct net_device *netdev;
|
||||
struct velocity_nic *vlc;
|
||||
int rc;
|
||||
|
||||
/* Allocate and initialise net device */
|
||||
netdev = alloc_etherdev ( sizeof ( *vlc ) );
|
||||
if ( ! netdev ) {
|
||||
rc = -ENOMEM;
|
||||
goto err_alloc;
|
||||
}
|
||||
netdev_init ( netdev, &velocity_operations );
|
||||
vlc = netdev->priv;
|
||||
pci_set_drvdata ( pci, netdev );
|
||||
netdev->dev = &pci->dev;
|
||||
|
||||
/* Fix up PCI device */
|
||||
adjust_pci_device ( pci );
|
||||
|
||||
/* Map registers */
|
||||
vlc->regs = ioremap ( pci->membase, VELOCITY_BAR_SIZE );
|
||||
vlc->netdev = netdev;
|
||||
|
||||
/* Reset the NIC */
|
||||
if ( ( rc = velocity_reset ( vlc ) ) != 0 )
|
||||
goto err_reset;
|
||||
|
||||
/* Reload EEPROM */
|
||||
if ( ( rc = velocity_reload_eeprom ( vlc ) ) != 0 )
|
||||
goto err_reset;
|
||||
|
||||
/* Get MAC address */
|
||||
netdev->hw_addr[0] = readb ( vlc->regs + VELOCITY_MAC0 );
|
||||
netdev->hw_addr[1] = readb ( vlc->regs + VELOCITY_MAC1 );
|
||||
netdev->hw_addr[2] = readb ( vlc->regs + VELOCITY_MAC2 );
|
||||
netdev->hw_addr[3] = readb ( vlc->regs + VELOCITY_MAC3 );
|
||||
netdev->hw_addr[4] = readb ( vlc->regs + VELOCITY_MAC4 );
|
||||
netdev->hw_addr[5] = readb ( vlc->regs + VELOCITY_MAC5 );
|
||||
|
||||
/* Initialise and reset MII interface */
|
||||
mii_init ( &vlc->mii, &velocity_mii_operations );
|
||||
if ( ( rc = mii_reset ( &vlc->mii ) ) != 0 ) {
|
||||
DBGC ( vlc, "VELOCITY %p could not reset MII: %s\n",
|
||||
vlc, strerror ( rc ) );
|
||||
goto err_mii_reset;
|
||||
}
|
||||
|
||||
/* Enable proper link advertising */
|
||||
velocity_set_link ( vlc );
|
||||
|
||||
/* Register network device */
|
||||
if ( ( rc = register_netdev ( netdev ) ) != 0 )
|
||||
goto err_register_netdev;
|
||||
|
||||
return 0;
|
||||
|
||||
err_register_netdev:
|
||||
err_mii_reset:
|
||||
velocity_reset ( vlc );
|
||||
err_reset:
|
||||
netdev_nullify ( netdev );
|
||||
netdev_put ( netdev );
|
||||
err_alloc:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove PCI device
|
||||
*
|
||||
* @v pci PCI device
|
||||
*/
|
||||
static void velocity_remove ( struct pci_device *pci ) {
|
||||
struct net_device *netdev = pci_get_drvdata ( pci );
|
||||
struct velocity_nic *vlc = netdev->priv;
|
||||
|
||||
/* Unregister network device */
|
||||
unregister_netdev ( netdev );
|
||||
|
||||
/* Reset card */
|
||||
velocity_reset ( vlc );
|
||||
|
||||
/* Free network device */
|
||||
netdev_nullify ( netdev );
|
||||
netdev_put ( netdev );
|
||||
}
|
||||
|
||||
/** Velocity PCI device IDs */
|
||||
static struct pci_device_id velocity_nics[] = {
|
||||
PCI_ROM ( 0x1106, 0x3119, "vt6122", "VIA Velocity", 0 ),
|
||||
};
|
||||
|
||||
/** Velocity PCI driver */
|
||||
struct pci_driver velocity_driver __pci_driver = {
|
||||
.ids = velocity_nics,
|
||||
.id_count = ( sizeof ( velocity_nics ) / sizeof ( velocity_nics[0] ) ),
|
||||
.probe = velocity_probe,
|
||||
.remove = velocity_remove,
|
||||
};
|
|
@ -0,0 +1,356 @@
|
|||
#ifndef _VELOCITY_H
|
||||
#define _VELOCITY_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* VIA Velocity network driver
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/** Skeleton BAR size */
|
||||
#define VELOCITY_BAR_SIZE 256
|
||||
|
||||
/** Default timeout */
|
||||
#define VELOCITY_TIMEOUT_US 10 * 1000
|
||||
|
||||
struct velocity_frag {
|
||||
uint32_t addr;
|
||||
uint32_t des2;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/** Velocity descriptor format */
|
||||
struct velocity_tx_descriptor {
|
||||
uint32_t des0;
|
||||
uint32_t des1;
|
||||
/* We only use the first fragment, the HW requires us to have 7 */
|
||||
struct velocity_frag frags[7];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct velocity_rx_descriptor {
|
||||
uint32_t des0;
|
||||
uint32_t des1;
|
||||
uint32_t addr;
|
||||
uint32_t des2;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define VELOCITY_DES0_RMBC(_n) (((_n) >> 16) & 0x1fff)
|
||||
#define VELOCITY_DES0_OWN (1 << 31)
|
||||
#define VELOCITY_DES0_TERR (1 << 15)
|
||||
#define VELOCITY_DES0_RXOK (1 << 15)
|
||||
#define VELOCITY_DES0_FDX (1 << 14)
|
||||
#define VELOCITY_DES0_GMII (1 << 13)
|
||||
#define VELOCITY_DES0_LNKFL (1 << 12)
|
||||
#define VELOCITY_DES0_SHDN (1 << 10)
|
||||
#define VELOCITY_DES0_CRS (1 << 9)
|
||||
#define VELOCITY_DES0_CDH (1 << 8)
|
||||
#define VELOCITY_DES0_ABT (1 << 7)
|
||||
#define VELOCITY_DES0_OWT (1 << 6)
|
||||
#define VELOCITY_DES0_OWC (1 << 5)
|
||||
#define VELOCITY_DES0_COLS (1 << 4)
|
||||
|
||||
#define VELOCITY_DES0_RXSHDN (1 << 30)
|
||||
#define VELOCITY_DES0_RXER (1 << 5)
|
||||
#define VELOCITY_DES0_RLE (1 << 4)
|
||||
#define VELOCITY_DES0_CE (1 << 3)
|
||||
#define VELOCITY_DES0_FAE (1 << 2)
|
||||
#define VELOCITY_DES0_CRC (1 << 1)
|
||||
#define VELOCITY_DES0_RX_ERR ( VELOCITY_DES0_RXER | \
|
||||
VELOCITY_DES0_RLE | \
|
||||
VELOCITY_DES0_CE | \
|
||||
VELOCITY_DES0_FAE | \
|
||||
VELOCITY_DES0_CRC )
|
||||
|
||||
/** TX descriptor fragment number */
|
||||
#define VELOCITY_DES1_FRAG(_n) (((_n + 1) & 0xf) << 28)
|
||||
#define VELOCITY_DES1_TCPLS ((1 << 24) | (1 << 25))
|
||||
#define VELOCITY_DES1_INTR (1 << 23)
|
||||
#define VELOCITY_DES1_PIC (1 << 22)
|
||||
#define VELOCITY_DES1_VETAG (1 << 21)
|
||||
#define VELOCITY_DES1_IPCK (1 << 20)
|
||||
#define VELOCITY_DES1_UDPCK (1 << 19)
|
||||
#define VELOCITY_DES1_TCPCK (1 << 18)
|
||||
#define VELOCITY_DES1_JMBO (1 << 17)
|
||||
#define VELOCITY_DES1_CRC (1 << 16)
|
||||
|
||||
#define VELOCITY_DES2_IC (1 << 31)
|
||||
#define VELOCITY_DES2_SIZE(_n) (((_n) & 0x1fff) << 16)
|
||||
|
||||
/** Number of receive descriptors
|
||||
*
|
||||
* Must be a multiple of 4 (hardware requirement).
|
||||
*/
|
||||
#define VELOCITY_RXDESC_NUM 8
|
||||
#define VELOCITY_RXDESC_SIZE \
|
||||
( VELOCITY_RXDESC_NUM * sizeof ( struct velocity_rx_descriptor ) )
|
||||
|
||||
/** Number of transmit descriptors */
|
||||
#define VELOCITY_TXDESC_NUM 8
|
||||
#define VELOCITY_TXDESC_SIZE \
|
||||
( VELOCITY_TXDESC_NUM * sizeof ( struct velocity_tx_descriptor ) )
|
||||
|
||||
/** Descriptor alignment */
|
||||
#define VELOCITY_RING_ALIGN 64
|
||||
|
||||
/** Receive buffer length */
|
||||
#define VELOCITY_RX_MAX_LEN 1536
|
||||
|
||||
/** MAC address registers */
|
||||
#define VELOCITY_MAC0 0x00
|
||||
#define VELOCITY_MAC1 0x01
|
||||
#define VELOCITY_MAC2 0x02
|
||||
#define VELOCITY_MAC3 0x03
|
||||
#define VELOCITY_MAC4 0x04
|
||||
#define VELOCITY_MAC5 0x05
|
||||
|
||||
/** Receive control register */
|
||||
#define VELOCITY_RCR 0x06
|
||||
#define RHINE_RCR_SYMERR_ACCEPT (1 << 7) /*< Accept symbol error */
|
||||
#define RHINE_RCR_FILTER_ACCEPT (1 << 6) /*< Accept based on filter */
|
||||
#define RHINE_RCR_LONG_ACCEPT (1 << 5) /*< Accept long packets */
|
||||
#define RHINE_RCR_PROMISC (1 << 4) /*< Promiscuous mode */
|
||||
#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 VELOCITY_TCR 0x07
|
||||
#define VELOCITY_TCR_LB0 (1 << 0) /*< Loopback control */
|
||||
#define VELOCITY_TCR_LB1 (1 << 1) /*< Loopback control */
|
||||
#define VELOCITY_TCR_COLTMC0 (1 << 2) /*< Collision retry control */
|
||||
#define VELOCITY_TCR_COLTMC1 (1 << 3) /*< Collision retry control */
|
||||
|
||||
/** Command register 0 (set) */
|
||||
#define VELOCITY_CRS0 0x08
|
||||
#define VELOCITY_CR0_TXON (1 << 3) /*< Transmit enable */
|
||||
#define VELOCITY_CR0_RXON (1 << 2) /*< Receive enable */
|
||||
#define VELOCITY_CR0_STOP (1 << 1) /*< Stop NIC */
|
||||
#define VELOCITY_CR0_START (1 << 0) /*< Start NIC */
|
||||
|
||||
/** Command register 1 (set) */
|
||||
#define VELOCITY_CRS1 0x09
|
||||
#define VELOCITY_CR1_SFRST (1 << 7) /*< Software reset */
|
||||
#define VELOCITY_CR1_TM1EN (1 << 6) /*< Perioding software counting */
|
||||
#define VELOCITY_CR1_TM0EN (1 << 5) /*< Single-shot software counting */
|
||||
#define VELOCITY_CR1_DPOLL (1 << 3) /*< Disable auto polling */
|
||||
#define VELOCITY_CR1_DISAU (1 << 0) /*< Unicast reception disable */
|
||||
|
||||
/** Command register 2 (set) */
|
||||
#define VELOCITY_CRS2 0x0A
|
||||
#define VELOCITY_CR2_XONEN (1 << 7) /*< XON/XOFF mode enable */
|
||||
#define VELOCITY_CR2_FDXTFCEN (1 << 6) /*< FDX flow control TX */
|
||||
#define VELOCITY_CR2_FDXRFCEN (1 << 5)
|
||||
#define VELOCITY_CR2_HDXFCEN (1 << 4)
|
||||
|
||||
/** Command register 3 (set) */
|
||||
#define VELOCITY_CRS3 0x0B
|
||||
#define VELOCITY_CR3_FOSRST (1 << 6)
|
||||
#define VELOCITY_CR3_FPHYRST (1 << 5)
|
||||
#define VELOCITY_CR3_DIAG (1 << 4)
|
||||
#define VELOCITY_CR3_INTPCTL (1 << 2)
|
||||
#define VELOCITY_CR3_GINTMSK1 (1 << 1)
|
||||
#define VELOCITY_CR3_SWPEND (1 << 0)
|
||||
|
||||
/** Command register 0 (clear) */
|
||||
#define VELOCITY_CRC0 0x0C
|
||||
|
||||
/** Command register 1 (clear) */
|
||||
#define VELOCITY_CRC1 0x0D
|
||||
|
||||
/** Command register 2 (clear */
|
||||
#define VELOCITY_CRC2 0x0E
|
||||
|
||||
/** Command register 3 (clear */
|
||||
#define VELOCITY_CRC3 0x0F
|
||||
#define VELOCITY_CAM0 0x10
|
||||
#define VELOCITY_CAM1 0x11
|
||||
#define VELOCITY_CAM2 0x12
|
||||
#define VELOCITY_CAM3 0x13
|
||||
#define VELOCITY_CAM4 0x14
|
||||
#define VELOCITY_CAM5 0x15
|
||||
#define VELOCITY_CAM6 0x16
|
||||
#define VELOCITY_CAM7 0x17
|
||||
#define VELOCITY_TXDESC_HI 0x18 /* Hi part of 64bit txdesc base addr */
|
||||
#define VELOCITY_DATABUF_HI 0x1D /* Hi part of 64bit data buffer addr */
|
||||
#define VELOCITY_INTCTL0 0x20 /* interrupt control register */
|
||||
#define VELOCITY_RXSUPPTHR 0x20
|
||||
#define VELOCITY_TXSUPPTHR 0x20
|
||||
#define VELOCITY_INTHOLDOFF 0x20
|
||||
#define VELOCITY_INTCTL1 0x21 /* interrupt control register */
|
||||
#define VELOCITY_TXHOSTERR 0x22 /* TX host error status */
|
||||
#define VELOCITY_RXHOSTERR 0x23 /* RX host error status */
|
||||
|
||||
/** Interrupt status register 0 */
|
||||
#define VELOCITY_ISR0 0x24
|
||||
#define VELOCITY_ISR0_PTX3 (1 << 7)
|
||||
#define VELOCITY_ISR0_PTX2 (1 << 6)
|
||||
#define VELOCITY_ISR0_PTX1 (1 << 5)
|
||||
#define VELOCITY_ISR0_PTX0 (1 << 4)
|
||||
#define VELOCITY_ISR0_PTXI (1 << 3)
|
||||
#define VELOCITY_ISR0_PRXI (1 << 2)
|
||||
#define VELOCITY_ISR0_PPTXI (1 << 1)
|
||||
#define VELOCITY_ISR0_PPRXI (1 << 0)
|
||||
|
||||
/** Interrupt status register 1 */
|
||||
#define VELOCITY_ISR1 0x25
|
||||
#define VELOCITY_ISR1_SRCI (1 << 7)
|
||||
#define VELOCITY_ISR1_LSTPEI (1 << 6)
|
||||
#define VELOCITY_ISR1_LSTEI (1 << 5)
|
||||
#define VELOCITY_ISR1_OVFL (1 << 4)
|
||||
#define VELOCITY_ISR1_FLONI (1 << 3)
|
||||
#define VELOCITY_ISR1_RACEI (1 << 2)
|
||||
|
||||
/** Interrupt status register 2 */
|
||||
#define VELOCITY_ISR2 0x26
|
||||
#define VELOCITY_ISR2_HFLD (1 << 7)
|
||||
#define VELOCITY_ISR2_UDPI (1 << 6)
|
||||
#define VELOCITY_ISR2_MIBFI (1 << 5)
|
||||
#define VELOCITY_ISR2_SHDNII (1 << 4)
|
||||
#define VELOCITY_ISR2_PHYI (1 << 3)
|
||||
#define VELOCITY_ISR2_PWEI (1 << 2)
|
||||
#define VELOCITY_ISR2_TMR1I (1 << 1)
|
||||
#define VELOCITY_ISR2_TMR0I (1 << 0)
|
||||
|
||||
/** Interrupt status register 3 */
|
||||
#define VELOCITY_ISR3 0x27
|
||||
|
||||
/** Interrupt mask register 0 */
|
||||
#define VELOCITY_IMR0 0x28
|
||||
|
||||
/** Interrupt mask register 1 */
|
||||
#define VELOCITY_IMR1 0x29
|
||||
|
||||
/** Interrupt mask register 2 */
|
||||
#define VELOCITY_IMR2 0x2a
|
||||
|
||||
/** Interrupt mask register 3 */
|
||||
#define VELOCITY_IMR3 0x2b
|
||||
|
||||
#define VELOCITY_TXSTS_PORT 0x2C /* Transmit status port (???) */
|
||||
#define VELOCITY_TXQCSRS 0x30 /* TX queue ctl/status set */
|
||||
|
||||
#define VELOCITY_TXQCSRS_DEAD3 (1 << 15)
|
||||
#define VELOCITY_TXQCSRS_WAK3 (1 << 14)
|
||||
#define VELOCITY_TXQCSRS_ACT3 (1 << 13)
|
||||
#define VELOCITY_TXQCSRS_RUN3 (1 << 12)
|
||||
#define VELOCITY_TXQCSRS_DEAD2 (1 << 11)
|
||||
#define VELOCITY_TXQCSRS_WAK2 (1 << 10)
|
||||
#define VELOCITY_TXQCSRS_ACT2 (1 << 9)
|
||||
#define VELOCITY_TXQCSRS_RUN2 (1 << 8)
|
||||
#define VELOCITY_TXQCSRS_DEAD1 (1 << 7)
|
||||
#define VELOCITY_TXQCSRS_WAK1 (1 << 6)
|
||||
#define VELOCITY_TXQCSRS_ACT1 (1 << 5)
|
||||
#define VELOCITY_TXQCSRS_RUN1 (1 << 4)
|
||||
#define VELOCITY_TXQCSRS_DEAD0 (1 << 3)
|
||||
#define VELOCITY_TXQCSRS_WAK0 (1 << 2)
|
||||
#define VELOCITY_TXQCSRS_ACT0 (1 << 1)
|
||||
#define VELOCITY_TXQCSRS_RUN0 (1 << 0)
|
||||
|
||||
#define VELOCITY_RXQCSRS 0x32 /* RX queue ctl/status set */
|
||||
#define VELOCITY_RXQCSRC 0x36
|
||||
|
||||
#define VELOCITY_RXQCSR_DEAD (1 << 3)
|
||||
#define VELOCITY_RXQCSR_WAK (1 << 2)
|
||||
#define VELOCITY_RXQCSR_ACT (1 << 1)
|
||||
#define VELOCITY_RXQCSR_RUN (1 << 0)
|
||||
|
||||
#define VELOCITY_TXQCSRC 0x34 /* TX queue ctl/status clear */
|
||||
#define VELOCITY_RXQCSRC 0x36 /* RX queue ctl/status clear */
|
||||
#define VELOCITY_RXDESC_ADDR_LO 0x38 /* RX desc base addr (lo 32 bits) */
|
||||
#define VELOCITY_RXDESC_CONSIDX 0x3C /* Current RX descriptor index */
|
||||
#define VELOCITY_TXQTIMER 0x3E /* TX queue timer pend register */
|
||||
#define VELOCITY_RXQTIMER 0x3F /* RX queue timer pend register */
|
||||
#define VELOCITY_TXDESC_ADDR_LO0 0x40 /* TX desc0 base addr (lo 32 bits) */
|
||||
#define VELOCITY_TXDESC_ADDR_LO1 0x44 /* TX desc1 base addr (lo 32 bits) */
|
||||
#define VELOCITY_TXDESC_ADDR_LO2 0x48 /* TX desc2 base addr (lo 32 bits) */
|
||||
#define VELOCITY_TXDESC_ADDR_LO3 0x4C /* TX desc3 base addr (lo 32 bits) */
|
||||
#define VELOCITY_RXDESCNUM 0x50 /* Size of RX desc ring */
|
||||
#define VELOCITY_TXDESCNUM 0x52 /* Size of TX desc ring */
|
||||
#define VELOCITY_TXDESC_CONSIDX0 0x54 /* Current TX descriptor index */
|
||||
#define VELOCITY_TXDESC_CONSIDX1 0x56 /* Current TX descriptor index */
|
||||
#define VELOCITY_TXDESC_CONSIDX2 0x58 /* Current TX descriptor index */
|
||||
#define VELOCITY_TXDESC_CONSIDX3 0x5A /* Current TX descriptor index */
|
||||
#define VELOCITY_TX_PAUSE_TIMER 0x5C /* TX pause frame timer */
|
||||
#define VELOCITY_RXDESC_RESIDUECNT 0x5E /* RX descriptor residue count */
|
||||
#define VELOCITY_FIFOTEST0 0x60 /* FIFO test register */
|
||||
#define VELOCITY_FIFOTEST1 0x64 /* FIFO test register */
|
||||
#define VELOCITY_CAMADDR 0x68 /* CAM address register */
|
||||
#define VELOCITY_CAMCTL 0x69 /* CAM control register */
|
||||
#define VELOCITY_MIICFG 0x6C /* MII port config register */
|
||||
#define VELOCITY_MIISR 0x6D /* MII port status register */
|
||||
#define VELOCITY_MIISR_IDLE (1 << 7)
|
||||
#define VELOCITY_PHYSTS0 0x6E /* PHY status register */
|
||||
#define VELOCITY_PHYSTS0_LINK (1 << 6)
|
||||
#define VELOCITY_PHYSTS1 0x6F /* PHY status register */
|
||||
#define VELOCITY_MIICR 0x70 /* MII command register */
|
||||
#define VELOCITY_MIICR_MAUTO (1 << 7)
|
||||
#define VELOCITY_MIICR_RCMD (1 << 6)
|
||||
#define VELOCITY_MIICR_WCMD (1 << 5)
|
||||
#define VELOCITY_MIICR_MDPM (1 << 4)
|
||||
#define VELOCITY_MIICR_MOUT (1 << 3)
|
||||
#define VELOCITY_MIICR_MDO (1 << 2)
|
||||
#define VELOCITY_MIICR_MDI (1 << 1)
|
||||
#define VELOCITY_MIICR_MDC (1 << 0)
|
||||
|
||||
#define VELOCITY_MIIADDR 0x71 /* MII address register */
|
||||
#define VELOCITY_MIIDATA 0x72 /* MII data register */
|
||||
#define VELOCITY_SSTIMER 0x74 /* single-shot timer */
|
||||
#define VELOCITY_PTIMER 0x76 /* periodic timer */
|
||||
#define VELOCITY_DMACFG0 0x7C /* DMA config 0 */
|
||||
#define VELOCITY_DMACFG1 0x7D /* DMA config 1 */
|
||||
#define VELOCITY_RXCFG 0x7E /* MAC RX config */
|
||||
#define VELOCITY_TXCFG 0x7F /* MAC TX config */
|
||||
#define VELOCITY_SWEEDATA 0x85 /* EEPROM software loaded data */
|
||||
|
||||
/** Chip Configuration Register A */
|
||||
#define VELOCITY_CFGA 0x78
|
||||
#define VELOCITY_CFGA_PACPI (1 << 0)
|
||||
|
||||
/** Power Management Sticky Register */
|
||||
#define VELOCITY_STICKY 0x83
|
||||
#define VELOCITY_STICKY_DS0 (1 << 0)
|
||||
#define VELOCITY_STICKY_DS1 (1 << 1)
|
||||
|
||||
#define VELOCITY_EEWRDAT 0x8C /* EEPROM embedded write */
|
||||
#define VELOCITY_EECSUM 0x92 /* EEPROM checksum */
|
||||
#define VELOCITY_EECSR 0x93 /* EEPROM control/status */
|
||||
#define VELOCITY_EECSR_RELOAD (1 << 5)
|
||||
#define VELOCITY_EERDDAT 0x94 /* EEPROM embedded read */
|
||||
#define VELOCITY_EEADDR 0x96 /* EEPROM address */
|
||||
#define VELOCITY_EECMD 0x97 /* EEPROM embedded command */
|
||||
|
||||
/** A Velocity network card */
|
||||
struct velocity_nic {
|
||||
/** Registers */
|
||||
void *regs;
|
||||
/** MII interface */
|
||||
struct mii_interface mii;
|
||||
/** Netdev */
|
||||
struct net_device *netdev;
|
||||
|
||||
/** Receive descriptor ring */
|
||||
struct velocity_rx_descriptor *rx_ring;
|
||||
/** Receive I/O buffers */
|
||||
struct io_buffer *rx_buffs[VELOCITY_RXDESC_NUM];
|
||||
/** Receive producer index */
|
||||
unsigned int rx_prod;
|
||||
/** Receive consumer index */
|
||||
unsigned int rx_cons;
|
||||
/** Receive commit number
|
||||
*
|
||||
* Used to fullfill the hardware requirement of returning receive buffers
|
||||
* to the hardware only in blocks of 4.
|
||||
*/
|
||||
unsigned int rx_commit;
|
||||
|
||||
/** Transmit descriptor ring */
|
||||
struct velocity_tx_descriptor *tx_ring;
|
||||
/** Transmit producer index */
|
||||
unsigned int tx_prod;
|
||||
/** Transmit consumer index */
|
||||
unsigned int tx_cons;
|
||||
};
|
||||
|
||||
#endif /* _VELOCITY_H */
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -114,7 +114,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
|||
#define ERRFILE_tlan ( ERRFILE_DRIVER | 0x00420000 )
|
||||
#define ERRFILE_tulip ( ERRFILE_DRIVER | 0x00430000 )
|
||||
#define ERRFILE_rhine ( ERRFILE_DRIVER | 0x00440000 )
|
||||
#define ERRFILE_via_velocity ( ERRFILE_DRIVER | 0x00450000 )
|
||||
#define ERRFILE_velocity ( ERRFILE_DRIVER | 0x00450000 )
|
||||
#define ERRFILE_w89c840 ( ERRFILE_DRIVER | 0x00460000 )
|
||||
#define ERRFILE_ipoib ( ERRFILE_DRIVER | 0x00470000 )
|
||||
#define ERRFILE_e1000_main ( ERRFILE_DRIVER | 0x00480000 )
|
||||
|
|
Reference in New Issue