summaryrefslogtreecommitdiffstats
path: root/src/drivers/net
diff options
context:
space:
mode:
Diffstat (limited to 'src/drivers/net')
-rw-r--r--src/drivers/net/3c90x.c22
-rw-r--r--src/drivers/net/etherfabric.c3042
-rw-r--r--src/drivers/net/etherfabric.h551
-rw-r--r--src/drivers/net/mlx_ipoib/patches/dhcpd.patch23
-rw-r--r--src/drivers/net/mlx_ipoib/samples/dhcpd.conf56
-rw-r--r--src/drivers/net/pcnet32.c46
-rw-r--r--src/drivers/net/via-velocity.c1949
-rw-r--r--src/drivers/net/via-velocity.h1938
8 files changed, 7614 insertions, 13 deletions
diff --git a/src/drivers/net/3c90x.c b/src/drivers/net/3c90x.c
index eee906914..0e855a44e 100644
--- a/src/drivers/net/3c90x.c
+++ b/src/drivers/net/3c90x.c
@@ -242,6 +242,7 @@ typedef struct
/*** Global variables ***/
static struct
{
+ unsigned int is3c556;
unsigned char isBrev;
unsigned char CurrentWindow;
unsigned int IOAddr;
@@ -305,7 +306,15 @@ a3c90x_internal_ReadEeprom(int ioaddr, int address)
while((1<<15) & inw(ioaddr + regEepromCommand_0_w));
/** Read the value. **/
- outw(address + ((0x02)<<6), ioaddr + regEepromCommand_0_w);
+ if (INF_3C90X.is3c556)
+ {
+ outw(address + (0x230), ioaddr + regEepromCommand_0_w);
+ }
+ else
+ {
+ outw(address + ((0x02)<<6), ioaddr + regEepromCommand_0_w);
+ }
+
while((1<<15) & inw(ioaddr + regEepromCommand_0_w));
val = inw(ioaddr + regEepromData_0_w);
@@ -710,6 +719,7 @@ static int a3c90x_probe ( struct nic *nic, struct pci_device *pci ) {
nic->ioaddr = pci->ioaddr;
nic->irqno = 0;
+ INF_3C90X.is3c556 = (pci->dev_id == 0x6055);
INF_3C90X.IOAddr = pci->ioaddr & ~3;
INF_3C90X.CurrentWindow = 255;
switch (a3c90x_internal_ReadEeprom(INF_3C90X.IOAddr, 0x03))
@@ -795,6 +805,15 @@ static int a3c90x_probe ( struct nic *nic, struct pci_device *pci ) {
INF_3C90X.HWAddr[5] = eeprom[HWADDR_OFFSET + 2]&0xFF;
printf("MAC Address = %!\n", INF_3C90X.HWAddr);
+ /** 3C556: Invert MII power **/
+ if (INF_3C90X.is3c556) {
+ unsigned int tmp;
+ a3c90x_internal_SetWindow(INF_3C90X.IOAddr, winAddressing2);
+ tmp = inw(INF_3C90X.IOAddr + regResetOptions_2_w);
+ tmp |= 0x4000;
+ outw(tmp, INF_3C90X.IOAddr + regResetOptions_2_w);
+ }
+
/* Test if the link is good, if not continue */
a3c90x_internal_SetWindow(INF_3C90X.IOAddr, winDiagnostics4);
mstat = inw(INF_3C90X.IOAddr + regMediaStatus_4_w);
@@ -967,6 +986,7 @@ static struct nic_operations a3c90x_operations = {
static struct pci_id a3c90x_nics[] = {
/* Original 90x revisions: */
+PCI_ROM(0x10b7, 0x6055, "3c556", "3C556"), /* Huricane */
PCI_ROM(0x10b7, 0x9000, "3c905-tpo", "3Com900-TPO"), /* 10 Base TPO */
PCI_ROM(0x10b7, 0x9001, "3c905-t4", "3Com900-Combo"), /* 10/100 T4 */
PCI_ROM(0x10b7, 0x9050, "3c905-tpo100", "3Com905-TX"), /* 100 Base TX / 10/100 TPO */
diff --git a/src/drivers/net/etherfabric.c b/src/drivers/net/etherfabric.c
new file mode 100644
index 000000000..9b2f64992
--- /dev/null
+++ b/src/drivers/net/etherfabric.c
@@ -0,0 +1,3042 @@
+/**************************************************************************
+ *
+ * Etherboot driver for Level 5 Etherfabric network cards
+ *
+ * Written by Michael Brown <mbrown@fensystems.co.uk>
+ *
+ * Copyright Fen Systems Ltd. 2005
+ * Copyright Level 5 Networks Inc. 2005
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL), incorporated herein by
+ * reference. Drivers based on or derived from this code fall under
+ * the GPL and must retain the authorship, copyright and license
+ * notice.
+ *
+ **************************************************************************
+ */
+
+#include "etherboot.h"
+#include "nic.h"
+#include "pci.h"
+#include "timer.h"
+#define dma_addr_t unsigned long
+#include "etherfabric.h"
+
+/**************************************************************************
+ *
+ * Constants and macros
+ *
+ **************************************************************************
+ */
+
+#define DBG(...)
+
+#define EFAB_ASSERT(x) \
+ do { \
+ if ( ! (x) ) { \
+ DBG ( "ASSERT(%s) failed at %s line %d [%s]\n", #x, \
+ __FILE__, __LINE__, __FUNCTION__ ); \
+ } \
+ } while (0)
+
+#define EFAB_TRACE(...)
+
+#define EFAB_REGDUMP(...)
+
+#define FALCON_USE_IO_BAR 1
+
+/*
+ * EtherFabric constants
+ *
+ */
+
+/* PCI Definitions */
+#define EFAB_VENDID_LEVEL5 0x1924
+#define FALCON_P_DEVID 0x0703 /* Temporary PCI ID */
+#define EF1002_DEVID 0xC101
+
+/**************************************************************************
+ *
+ * Data structures
+ *
+ **************************************************************************
+ */
+
+/*
+ * Buffers used for TX, RX and event queue
+ *
+ */
+#define EFAB_BUF_ALIGN 4096
+#define EFAB_DATA_BUF_SIZE 2048
+#define EFAB_RX_BUFS 16
+#define EFAB_RXD_SIZE 512
+#define EFAB_TXD_SIZE 512
+#define EFAB_EVQ_SIZE 512
+struct efab_buffers {
+ uint8_t eventq[4096];
+ uint8_t rxd[4096];
+ uint8_t txd[4096];
+ uint8_t tx_buf[EFAB_DATA_BUF_SIZE];
+ uint8_t rx_buf[EFAB_RX_BUFS][EFAB_DATA_BUF_SIZE];
+ uint8_t padding[EFAB_BUF_ALIGN-1];
+};
+static struct efab_buffers efab_buffers;
+
+/** An RX buffer */
+struct efab_rx_buf {
+ uint8_t *addr;
+ unsigned int len;
+ int id;
+};
+
+/** A TX buffer */
+struct efab_tx_buf {
+ uint8_t *addr;
+ unsigned int len;
+ int id;
+};
+
+/** Etherfabric event type */
+enum efab_event_type {
+ EFAB_EV_NONE = 0,
+ EFAB_EV_TX,
+ EFAB_EV_RX,
+};
+
+/** Etherfabric event */
+struct efab_event {
+ /** Event type */
+ enum efab_event_type type;
+ /** RX buffer ID */
+ int rx_id;
+ /** RX length */
+ unsigned int rx_len;
+};
+
+/*
+ * Etherfabric abstraction layer
+ *
+ */
+struct efab_nic;
+struct efab_operations {
+ void ( * get_membase ) ( struct efab_nic *efab );
+ int ( * reset ) ( struct efab_nic *efab );
+ int ( * init_nic ) ( struct efab_nic *efab );
+ int ( * read_eeprom ) ( struct efab_nic *efab );
+ void ( * build_rx_desc ) ( struct efab_nic *efab,
+ struct efab_rx_buf *rx_buf );
+ void ( * notify_rx_desc ) ( struct efab_nic *efab );
+ void ( * build_tx_desc ) ( struct efab_nic *efab,
+ struct efab_tx_buf *tx_buf );
+ void ( * notify_tx_desc ) ( struct efab_nic *efab );
+ int ( * fetch_event ) ( struct efab_nic *efab,
+ struct efab_event *event );
+ void ( * mask_irq ) ( struct efab_nic *efab, int enabled );
+ void ( * generate_irq ) ( struct efab_nic *efab );
+ void ( * mac_writel ) ( struct efab_nic *efab, efab_dword_t *value,
+ unsigned int mac_reg );
+ void ( * mac_readl ) ( struct efab_nic *efab, efab_dword_t *value,
+ unsigned int mac_reg );
+ int ( * init_mac ) ( struct efab_nic *efab );
+ void ( * mdio_write ) ( struct efab_nic *efab, int location,
+ int value );
+ int ( * mdio_read ) ( struct efab_nic *efab, int location );
+};
+
+/*
+ * Driver private data structure
+ *
+ */
+struct efab_nic {
+
+ /** PCI device */
+ struct pci_device *pci;
+
+ /** Operations table */
+ struct efab_operations *op;
+
+ /** Memory base */
+ void *membase;
+
+ /** I/O base */
+ unsigned int iobase;
+
+ /** Buffers */
+ uint8_t *eventq; /* Falcon only */
+ uint8_t *txd; /* Falcon only */
+ uint8_t *rxd; /* Falcon only */
+ struct efab_tx_buf tx_buf;
+ struct efab_rx_buf rx_bufs[EFAB_RX_BUFS];
+
+ /** Buffer pointers */
+ unsigned int eventq_read_ptr; /* Falcon only */
+ unsigned int tx_write_ptr;
+ unsigned int rx_write_ptr;
+ int tx_in_progress;
+
+ /** Port 0/1 on the NIC */
+ int port;
+
+ /** MAC address */
+ uint8_t mac_addr[ETH_ALEN];
+ /** GMII link options */
+ unsigned int link_options;
+ /** Link status */
+ int link_up;
+
+ /** INT_REG_KER for Falcon */
+ efab_oword_t int_ker __attribute__ (( aligned ( 16 ) ));
+};
+
+/**************************************************************************
+ *
+ * EEPROM access
+ *
+ **************************************************************************
+ */
+
+#define EFAB_EEPROM_SDA 0x80000000u
+#define EFAB_EEPROM_SCL 0x40000000u
+#define ARIZONA_24xx00_SLAVE 0xa0
+#define EFAB_EEPROM_READ_SELECT ( ARIZONA_24xx00_SLAVE | 1 )
+#define EFAB_EEPROM_WRITE_SELECT ( ARIZONA_24xx00_SLAVE | 0 )
+
+static void eeprom_release ( uint32_t *eeprom_reg ) {
+ unsigned int dev;
+
+ udelay ( 10 );
+ dev = readl ( eeprom_reg );
+ writel ( dev | ( EFAB_EEPROM_SDA | EFAB_EEPROM_SCL ),
+ eeprom_reg );
+ udelay ( 10 );
+}
+
+static void eeprom_start ( uint32_t *eeprom_reg ) {
+ unsigned int dev;
+
+ udelay ( 10 );
+ dev = readl ( eeprom_reg );
+
+ if ( ( dev & ( EFAB_EEPROM_SDA | EFAB_EEPROM_SCL ) ) !=
+ ( EFAB_EEPROM_SDA | EFAB_EEPROM_SCL ) ) {
+ udelay ( 10 );
+ writel ( dev | ( EFAB_EEPROM_SDA | EFAB_EEPROM_SCL ),
+ eeprom_reg );
+ udelay ( 1 );
+ }
+ dev &=~ ( EFAB_EEPROM_SDA | EFAB_EEPROM_SCL );
+
+ udelay ( 10 );
+ writel ( dev | EFAB_EEPROM_SCL, eeprom_reg) ;
+ udelay ( 1) ;
+
+ udelay ( 10 );
+ writel ( dev, eeprom_reg );
+ udelay ( 10 );
+}
+
+static void eeprom_stop ( uint32_t *eeprom_reg ) {
+ unsigned int dev;
+
+ udelay ( 10 );
+ dev = readl ( eeprom_reg );
+ EFAB_ASSERT ( ! ( dev & EFAB_EEPROM_SCL ) );
+
+ if ( dev & ( EFAB_EEPROM_SDA | EFAB_EEPROM_SCL ) ) {
+ dev &=~ ( EFAB_EEPROM_SDA | EFAB_EEPROM_SCL );
+ udelay ( 10 );
+ writel ( dev, eeprom_reg );
+ udelay ( 10 );
+ }
+
+ udelay ( 10 );
+ dev |= EFAB_EEPROM_SCL;
+ writel ( dev, eeprom_reg );
+ udelay ( 10 );
+
+ udelay ( 10 );
+ dev |= EFAB_EEPROM_SDA;
+ writel ( dev, eeprom_reg );
+ udelay ( 10 );
+}
+
+static void eeprom_write ( uint32_t *eeprom_reg, unsigned char data ) {
+ int i;
+ unsigned int dev;
+
+ udelay ( 10 );
+ dev = readl ( eeprom_reg );
+ udelay ( 10 );
+ EFAB_ASSERT ( ! ( dev & EFAB_EEPROM_SCL ) );
+
+ for ( i = 0 ; i < 8 ; i++, data <<= 1 ) {
+ if ( data & 0x80 ) {
+ dev |= EFAB_EEPROM_SDA;
+ } else {
+ dev &=~ EFAB_EEPROM_SDA;
+ }
+ udelay ( 10 );
+ writel ( dev, eeprom_reg );
+ udelay ( 10 );
+
+ udelay ( 10 );
+ writel ( dev | EFAB_EEPROM_SCL, eeprom_reg );
+ udelay ( 10 );
+
+ udelay ( 10 );
+ writel ( dev, eeprom_reg );
+ udelay ( 10 );
+ }
+
+ if( ! ( dev & EFAB_EEPROM_SDA ) ) {
+ udelay ( 10 );
+ writel ( dev | EFAB_EEPROM_SDA, eeprom_reg );
+ udelay ( 10 );
+ }
+}
+
+static unsigned char eeprom_read ( uint32_t *eeprom_reg ) {
+ unsigned int i, dev, rd;
+ unsigned char val = 0;
+
+ udelay ( 10 );
+ dev = readl ( eeprom_reg );
+ udelay ( 10 );
+ EFAB_ASSERT ( ! ( dev & EFAB_EEPROM_SCL ) );
+
+ if( ! ( dev & EFAB_EEPROM_SDA ) ) {
+ dev |= EFAB_EEPROM_SDA;
+ udelay ( 10 );
+ writel ( dev, eeprom_reg );
+ udelay ( 10 );
+ }
+
+ for( i = 0 ; i < 8 ; i++ ) {
+ udelay ( 10 );
+ writel ( dev | EFAB_EEPROM_SCL, eeprom_reg );
+ udelay ( 10 );
+
+ udelay ( 10 );
+ rd = readl ( eeprom_reg );
+ udelay ( 10 );
+ val = ( val << 1 ) | ( ( rd & EFAB_EEPROM_SDA ) != 0 );
+
+ udelay ( 10 );
+ writel ( dev, eeprom_reg );
+ udelay ( 10 );
+ }
+
+ return val;
+}
+
+static int eeprom_check_ack ( uint32_t *eeprom_reg ) {
+ int ack;
+ unsigned int dev;
+
+ udelay ( 10 );
+ dev = readl ( eeprom_reg );
+ EFAB_ASSERT ( ! ( dev & EFAB_EEPROM_SCL ) );
+
+ writel ( dev | EFAB_EEPROM_SCL, eeprom_reg );
+ udelay ( 10 );
+
+ udelay ( 10 );
+ ack = readl ( eeprom_reg ) & EFAB_EEPROM_SDA;
+
+ udelay ( 10 );
+ writel ( ack & ~EFAB_EEPROM_SCL, eeprom_reg );
+ udelay ( 10 );
+
+ return ( ack == 0 );
+}
+
+static void eeprom_send_ack ( uint32_t *eeprom_reg ) {
+ unsigned int dev;
+
+ udelay ( 10 );
+ dev = readl ( eeprom_reg );
+ EFAB_ASSERT ( ! ( dev & EFAB_EEPROM_SCL ) );
+
+ udelay ( 10 );
+ dev &= ~EFAB_EEPROM_SDA;
+ writel ( dev, eeprom_reg );
+ udelay ( 10 );
+
+ udelay ( 10 );
+ dev |= EFAB_EEPROM_SCL;
+ writel ( dev, eeprom_reg );
+ udelay ( 10 );
+
+ udelay ( 10 );
+ dev |= EFAB_EEPROM_SDA;
+ writel ( dev & ~EFAB_EEPROM_SCL, eeprom_reg );
+ udelay ( 10 );
+}
+
+static int efab_eeprom_read_mac ( uint32_t *eeprom_reg, uint8_t *mac_addr ) {
+ int i;
+
+ eeprom_start ( eeprom_reg );
+
+ eeprom_write ( eeprom_reg, EFAB_EEPROM_WRITE_SELECT );
+ if ( ! eeprom_check_ack ( eeprom_reg ) )
+ return 0;
+
+ eeprom_write ( eeprom_reg, 0 );
+ if ( ! eeprom_check_ack ( eeprom_reg ) )
+ return 0;
+
+ eeprom_stop ( eeprom_reg );
+ eeprom_start ( eeprom_reg );
+
+ eeprom_write ( eeprom_reg, EFAB_EEPROM_READ_SELECT );
+ if ( ! eeprom_check_ack ( eeprom_reg ) )
+ return 0;
+
+ for ( i = 0 ; i < ETH_ALEN ; i++ ) {
+ mac_addr[i] = eeprom_read ( eeprom_reg );
+ eeprom_send_ack ( eeprom_reg );
+ }
+
+ eeprom_stop ( eeprom_reg );
+
+ eeprom_release ( eeprom_reg );
+
+ return 1;
+}
+
+/**************************************************************************
+ *
+ * GMII routines
+ *
+ **************************************************************************
+ */
+
+/* GMII registers */
+#define MII_BMSR 0x01 /* Basic mode status register */
+#define MII_ADVERTISE 0x04 /* Advertisement control register */
+#define MII_LPA 0x05 /* Link partner ability register*/
+#define GMII_GTCR 0x09 /* 1000BASE-T control register */
+#define GMII_GTSR 0x0a /* 1000BASE-T status register */
+#define GMII_PSSR 0x11 /* PHY-specific status register */
+
+/* Basic mode status register. */
+#define BMSR_LSTATUS 0x0004 /* Link status */
+
+/* Link partner ability register. */
+#define LPA_10HALF 0x0020 /* Can do 10mbps half-duplex */
+#define LPA_10FULL 0x0040 /* Can do 10mbps full-duplex */
+#define LPA_100HALF 0x0080 /* Can do 100mbps half-duplex */
+#define LPA_100FULL 0x0100 /* Can do 100mbps full-duplex */
+#define LPA_100BASE4 0x0200 /* Can do 100mbps 4k packets */
+#define LPA_PAUSE 0x0400 /* Bit 10 - MAC pause */
+
+/* Pseudo extensions to the link partner ability register */
+#define LPA_1000FULL 0x00020000
+#define LPA_1000HALF 0x00010000
+
+#define LPA_100 (LPA_100FULL | LPA_100HALF | LPA_100BASE4)
+#define LPA_1000 ( LPA_1000FULL | LPA_1000HALF )
+#define LPA_DUPLEX ( LPA_10FULL | LPA_100FULL | LPA_1000FULL )
+
+/* Mask of bits not associated with speed or duplexity. */
+#define LPA_OTHER ~( LPA_10FULL | LPA_10HALF | LPA_100FULL | \
+ LPA_100HALF | LPA_1000FULL | LPA_1000HALF )
+
+/* PHY-specific status register */
+#define PSSR_LSTATUS 0x0400 /* Bit 10 - link status */
+
+/**
+ * Retrieve GMII autonegotiation advertised abilities
+ *
+ */
+static unsigned int gmii_autoneg_advertised ( struct efab_nic *efab ) {
+ unsigned int mii_advertise;
+ unsigned int gmii_advertise;
+
+ /* Extended bits are in bits 8 and 9 of GMII_GTCR */
+ mii_advertise = efab->op->mdio_read ( efab, MII_ADVERTISE );
+ gmii_advertise = ( ( efab->op->mdio_read ( efab, GMII_GTCR ) >> 8 )
+ & 0x03 );
+ return ( ( gmii_advertise << 16 ) | mii_advertise );
+}
+
+/**
+ * Retrieve GMII autonegotiation link partner abilities
+ *
+ */
+static unsigned int gmii_autoneg_lpa ( struct efab_nic *efab ) {
+ unsigned int mii_lpa;
+ unsigned int gmii_lpa;
+
+ /* Extended bits are in bits 10 and 11 of GMII_GTSR */
+ mii_lpa = efab->op->mdio_read ( efab, MII_LPA );
+ gmii_lpa = ( efab->op->mdio_read ( efab, GMII_GTSR ) >> 10 ) & 0x03;
+ return ( ( gmii_lpa << 16 ) | mii_lpa );
+}
+
+/**
+ * Calculate GMII autonegotiated link technology
+ *
+ */
+static unsigned int gmii_nway_result ( unsigned int negotiated ) {
+ unsigned int other_bits;
+
+ /* Mask out the speed and duplexity bits */
+ other_bits = negotiated & LPA_OTHER;
+
+ if ( negotiated & LPA_1000FULL )
+ return ( other_bits | LPA_1000FULL );
+ else if ( negotiated & LPA_1000HALF )
+ return ( other_bits | LPA_1000HALF );
+ else if ( negotiated & LPA_100FULL )
+ return ( other_bits | LPA_100FULL );
+ else if ( negotiated & LPA_100BASE4 )
+ return ( other_bits | LPA_100BASE4 );
+ else if ( negotiated & LPA_100HALF )
+ return ( other_bits | LPA_100HALF );
+ else if ( negotiated & LPA_10FULL )
+ return ( other_bits | LPA_10FULL );
+ else return ( other_bits | LPA_10HALF );
+}
+
+/**
+ * Check GMII PHY link status
+ *
+ */
+static int gmii_link_ok ( struct efab_nic *efab ) {
+ int status;
+ int phy_status;
+
+ /* BMSR is latching - it returns "link down" if the link has
+ * been down at any point since the last read. To get a
+ * real-time status, we therefore read the register twice and
+ * use the result of the second read.
+ */
+ efab->op->mdio_read ( efab, MII_BMSR );
+ status = efab->op->mdio_read ( efab, MII_BMSR );
+
+ /* Read the PHY-specific Status Register. This is
+ * non-latching, so we need do only a single read.
+ */
+ phy_status = efab->op->mdio_read ( efab, GMII_PSSR );
+
+ return ( ( status & BMSR_LSTATUS ) && ( phy_status & PSSR_LSTATUS ) );
+}
+
+/**************************************************************************
+ *
+ * Alaska PHY
+ *
+ **************************************************************************
+ */
+
+/**
+ * Initialise Alaska PHY
+ *
+ */
+static void alaska_init ( struct efab_nic *efab ) {
+ unsigned int advertised, lpa;
+
+ /* Read link up status */
+ efab->link_up = gmii_link_ok ( efab );
+
+ if ( ! efab->link_up )
+ return;
+
+ /* Determine link options from PHY. */
+ advertised = gmii_autoneg_advertised ( efab );
+ lpa = gmii_autoneg_lpa ( efab );
+ efab->link_options = gmii_nway_result ( advertised & lpa );
+
+ printf ( "%dMbps %s-duplex (%04x,%04x)\n",
+ ( efab->link_options & LPA_1000 ? 1000 :
+ ( efab->link_options & LPA_100 ? 100 : 10 ) ),
+ ( efab->link_options & LPA_DUPLEX ? "full" : "half" ),
+ advertised, lpa );
+}
+
+/**************************************************************************
+ *
+ * Mentor MAC
+ *
+ **************************************************************************
+ */
+
+/* GMAC configuration register 1 */
+#define GM_CFG1_REG_MAC 0x00
+#define GM_SW_RST_LBN 31
+#define GM_SW_RST_WIDTH 1
+#define GM_RX_FC_EN_LBN 5
+#define GM_RX_FC_EN_WIDTH 1
+#define GM_TX_FC_EN_LBN 4
+#define GM_TX_FC_EN_WIDTH 1
+#define GM_RX_EN_LBN 2
+#define GM_RX_EN_WIDTH 1
+#define GM_TX_EN_LBN 0
+#define GM_TX_EN_WIDTH 1
+
+/* GMAC configuration register 2 */
+#define GM_CFG2_REG_MAC 0x01
+#define GM_PAMBL_LEN_LBN 12
+#define GM_PAMBL_LEN_WIDTH 4
+#define GM_IF_MODE_LBN 8
+#define GM_IF_MODE_WIDTH 2
+#define GM_PAD_CRC_EN_LBN 2
+#define GM_PAD_CRC_EN_WIDTH 1
+#define GM_FD_LBN 0
+#define GM_FD_WIDTH 1
+
+/* GMAC maximum frame length register */
+#define GM_MAX_FLEN_REG_MAC 0x04
+#define GM_MAX_FLEN_LBN 0
+#define GM_MAX_FLEN_WIDTH 16
+
+/* GMAC MII management configuration register */
+#define GM_MII_MGMT_CFG_REG_MAC 0x08
+#define GM_MGMT_CLK_SEL_LBN 0
+#define GM_MGMT_CLK_SEL_WIDTH 3
+
+/* GMAC MII management command register */
+#define GM_MII_MGMT_CMD_REG_MAC 0x09
+#define GM_MGMT_SCAN_CYC_LBN 1
+#define GM_MGMT_SCAN_CYC_WIDTH 1
+#define GM_MGMT_RD_CYC_LBN 0
+#define GM_MGMT_RD_CYC_WIDTH 1
+
+/* GMAC MII management address register */
+#define GM_MII_MGMT_ADR_REG_MAC 0x0a
+#define GM_MGMT_PHY_ADDR_LBN 8
+#define GM_MGMT_PHY_ADDR_WIDTH 5
+#define GM_MGMT_REG_ADDR_LBN 0
+#define GM_MGMT_REG_ADDR_WIDTH 5
+
+/* GMAC MII management control register */
+#define GM_MII_MGMT_CTL_REG_MAC 0x0b
+#define GM_MGMT_CTL_LBN 0
+#define GM_MGMT_CTL_WIDTH 16
+
+/* GMAC MII management status register */
+#define GM_MII_MGMT_STAT_REG_MAC 0x0c
+#define GM_MGMT_STAT_LBN 0
+#define GM_MGMT_STAT_WIDTH 16
+
+/* GMAC MII management indicators register */
+#define GM_MII_MGMT_IND_REG_MAC 0x0d
+#define GM_MGMT_BUSY_LBN 0
+#define GM_MGMT_BUSY_WIDTH 1
+
+/* GMAC station address register 1 */
+#define GM_ADR1_REG_MAC 0x10
+#define GM_HWADDR_5_LBN 24
+#define GM_HWADDR_5_WIDTH 8
+#define GM_HWADDR_4_LBN 16
+#define GM_HWADDR_4_WIDTH 8
+#define GM_HWADDR_3_LBN 8
+#define GM_HWADDR_3_WIDTH 8
+#define GM_HWADDR_2_LBN 0
+#define GM_HWADDR_2_WIDTH 8
+
+/* GMAC station address register 2 */
+#define GM_ADR2_REG_MAC 0x11
+#define GM_HWADDR_1_LBN 24
+#define GM_HWADDR_1_WIDTH 8
+#define GM_HWADDR_0_LBN 16
+#define GM_HWADDR_0_WIDTH 8
+
+/* GMAC FIFO configuration register 0 */
+#define GMF_CFG0_REG_MAC 0x12
+#define GMF_FTFENREQ_LBN 12
+#define GMF_FTFENREQ_WIDTH 1
+#define GMF_STFENREQ_LBN 11
+#define GMF_STFENREQ_WIDTH 1
+#define GMF_FRFENREQ_LBN 10
+#define GMF_FRFENREQ_WIDTH 1
+#define GMF_SRFENREQ_LBN 9
+#define GMF_SRFENREQ_WIDTH 1
+#define GMF_WTMENREQ_LBN 8
+#define GMF_WTMENREQ_WIDTH 1
+
+/* GMAC FIFO configuration register 1 */
+#define GMF_CFG1_REG_MAC 0x13
+#define GMF_CFGFRTH_LBN 16
+#define GMF_CFGFRTH_WIDTH 5
+#define GMF_CFGXOFFRTX_LBN 0
+#define GMF_CFGXOFFRTX_WIDTH 16
+
+/* GMAC FIFO configuration register 2 */
+#define GMF_CFG2_REG_MAC 0x14
+#define GMF_CFGHWM_LBN 16
+#define GMF_CFGHWM_WIDTH 6
+#define GMF_CFGLWM_LBN 0
+#define GMF_CFGLWM_WIDTH 6
+
+/* GMAC FIFO configuration register 3 */
+#define GMF_CFG3_REG_MAC 0x15
+#define GMF_CFGHWMFT_LBN 16
+#define GMF_CFGHWMFT_WIDTH 6
+#define GMF_CFGFTTH_LBN 0
+#define GMF_CFGFTTH_WIDTH 6
+
+/* GMAC FIFO configuration register 4 */
+#define GMF_CFG4_REG_MAC 0x16
+#define GMF_HSTFLTRFRM_PAUSE_LBN 12
+#define GMF_HSTFLTRFRM_PAUSE_WIDTH 12
+
+/* GMAC FIFO configuration register 5 */
+#define GMF_CFG5_REG_MAC 0x17
+#define GMF_CFGHDPLX_LBN 22
+#define GMF_CFGHDPLX_WIDTH 1
+#define GMF_CFGBYTMODE_LBN 19
+#define GMF_CFGBYTMODE_WIDTH 1
+#define GMF_HSTDRPLT64_LBN 18
+#define GMF_HSTDRPLT64_WIDTH 1
+#define GMF_HSTFLTRFRMDC_PAUSE_LBN 12
+#define GMF_HSTFLTRFRMDC_PAUSE_WIDTH 1
+
+struct efab_mentormac_parameters {
+ int gmf_cfgfrth;
+ int gmf_cfgftth;
+ int gmf_cfghwmft;
+ int gmf_cfghwm;
+ int gmf_cfglwm;
+};
+
+/**
+ * Reset Mentor MAC
+ *
+ */
+static void mentormac_reset ( struct efab_nic *efab, int reset ) {
+ efab_dword_t reg;
+
+ EFAB_POPULATE_DWORD_1 ( reg, GM_SW_RST, reset );
+ efab->op->mac_writel ( efab, &reg, GM_CFG1_REG_MAC );
+ udelay ( 1000 );
+
+ if ( ( ! reset ) && ( efab->port == 0 ) ) {
+ /* Configure GMII interface so PHY is accessible.
+ * Note that GMII interface is connected only to port
+ * 0
+ */
+ EFAB_POPULATE_DWORD_1 ( reg, GM_MGMT_CLK_SEL, 0x4 );
+ efab->op->mac_writel ( efab, &reg, GM_MII_MGMT_CFG_REG_MAC );
+ udelay ( 10 );
+ }
+}
+
+/**
+ * Initialise Mentor MAC
+ *
+ */
+static void mentormac_init ( struct efab_nic *efab,
+ struct efab_mentormac_parameters *params ) {
+ int pause, if_mode, full_duplex, bytemode, half_duplex;
+ efab_dword_t reg;
+
+ /* Configuration register 1 */
+ pause = ( efab->link_options & LPA_PAUSE ) ? 1 : 0;
+ if ( ! ( efab->link_options & LPA_DUPLEX ) ) {
+ /* Half-duplex operation requires TX flow control */
+ pause = 1;
+ }
+ EFAB_POPULATE_DWORD_4 ( reg,
+ GM_TX_EN, 1,
+ GM_TX_FC_EN, pause,
+ GM_RX_EN, 1,
+ GM_RX_FC_EN, 1 );
+ efab->op->mac_writel ( efab, &reg, GM_CFG1_REG_MAC );
+ udelay ( 10 );
+
+ /* Configuration register 2 */
+ if_mode = ( efab->link_options & LPA_1000 ) ? 2 : 1;
+ full_duplex = ( efab->link_options & LPA_DUPLEX ) ? 1 : 0;
+ EFAB_POPULATE_DWORD_4 ( reg,
+ GM_IF_MODE, if_mode,
+ GM_PAD_CRC_EN, 1,
+ GM_FD, full_duplex,
+ GM_PAMBL_LEN, 0x7 /* ? */ );
+ efab->op->mac_writel ( efab, &reg, GM_CFG2_REG_MAC );
+ udelay ( 10 );
+
+ /* Max frame len register */
+ EFAB_POPULATE_DWORD_1 ( reg, GM_MAX_FLEN, ETH_FRAME_LEN );
+ efab->op->mac_writel ( efab, &reg, GM_MAX_FLEN_REG_MAC );
+ udelay ( 10 );
+
+ /* FIFO configuration register 0 */
+ EFAB_POPULATE_DWORD_5 ( reg,
+ GMF_FTFENREQ, 1,
+ GMF_STFENREQ, 1,
+ GMF_FRFENREQ, 1,
+ GMF_SRFENREQ, 1,
+ GMF_WTMENREQ, 1 );
+ efab->op->mac_writel ( efab, &reg, GMF_CFG0_REG_MAC );
+ udelay ( 10 );
+
+ /* FIFO configuration register 1 */
+ EFAB_POPULATE_DWORD_2 ( reg,
+ GMF_CFGFRTH, params->gmf_cfgfrth,
+ GMF_CFGXOFFRTX, 0xffff );
+ efab->op->mac_writel ( efab, &reg, GMF_CFG1_REG_MAC );
+ udelay ( 10 );
+
+ /* FIFO configuration register 2 */
+ EFAB_POPULATE_DWORD_2 ( reg,
+ GMF_CFGHWM, params->gmf_cfghwm,
+ GMF_CFGLWM, params->gmf_cfglwm );
+ efab->op->mac_writel ( efab, &reg, GMF_CFG2_REG_MAC );
+ udelay ( 10 );
+
+ /* FIFO configuration register 3 */
+ EFAB_POPULATE_DWORD_2 ( reg,
+ GMF_CFGHWMFT, params->gmf_cfghwmft,
+ GMF_CFGFTTH, params->gmf_cfgftth );
+ efab->op->mac_writel ( efab, &reg, GMF_CFG3_REG_MAC );
+ udelay ( 10 );
+
+ /* FIFO configuration register 4 */
+ EFAB_POPULATE_DWORD_1 ( reg, GMF_HSTFLTRFRM_PAUSE, 1 );
+ efab->op->mac_writel ( efab, &reg, GMF_CFG4_REG_MAC );
+ udelay ( 10 );
+
+ /* FIFO configuration register 5 */
+ bytemode = ( efab->link_options & LPA_1000 ) ? 1 : 0;
+ half_duplex = ( efab->link_options & LPA_DUPLEX ) ? 0 : 1;
+ efab->op->mac_readl ( efab, &reg, GMF_CFG5_REG_MAC );
+ EFAB_SET_DWORD_FIELD ( reg, GMF_CFGBYTMODE, bytemode );
+ EFAB_SET_DWORD_FIELD ( reg, GMF_CFGHDPLX, half_duplex );
+ EFAB_SET_DWORD_FIELD ( reg, GMF_HSTDRPLT64, half_duplex );
+ EFAB_SET_DWORD_FIELD ( reg, GMF_HSTFLTRFRMDC_PAUSE, 0 );
+ efab->op->mac_writel ( efab, &reg, GMF_CFG5_REG_MAC );
+ udelay ( 10 );
+
+ /* MAC address */
+ EFAB_POPULATE_DWORD_4 ( reg,
+ GM_HWADDR_5, efab->mac_addr[5],
+ GM_HWADDR_4, efab->mac_addr[4],
+ GM_HWADDR_3, efab->mac_addr[3],
+ GM_HWADDR_2, efab->mac_addr[2] );
+ efab->op->mac_writel ( efab, &reg, GM_ADR1_REG_MAC );
+ udelay ( 10 );
+ EFAB_POPULATE_DWORD_2 ( reg,
+ GM_HWADDR_1, efab->mac_addr[1],
+ GM_HWADDR_0, efab->mac_addr[0] );
+ efab->op->mac_writel ( efab, &reg, GM_ADR2_REG_MAC );
+ udelay ( 10 );
+}
+
+/**
+ * Wait for GMII access to complete
+ *
+ */
+static int mentormac_gmii_wait ( struct efab_nic *efab ) {
+ int count;
+ efab_dword_t indicator;
+
+ for ( count = 0 ; count < 1000 ; count++ ) {
+ udelay ( 10 );
+ efab->op->mac_readl ( efab, &indicator,
+ GM_MII_MGMT_IND_REG_MAC );
+ if ( EFAB_DWORD_FIELD ( indicator, GM_MGMT_BUSY ) == 0 )
+ return 1;
+ }
+ printf ( "Timed out waiting for GMII\n" );
+ return 0;
+}
+
+/**
+ * Write a GMII register
+ *
+ */
+static void mentormac_mdio_write ( struct efab_nic *efab, int phy_id,
+ int location, int value ) {
+ efab_dword_t reg;
+ int save_port;
+
+ EFAB_TRACE ( "Writing GMII %d register %02x with %04x\n", phy_id,
+ location, value );
+
+ /* Mentor MAC connects both PHYs to MAC 0 */
+ save_port = efab->port;
+ efab->port = 0;
+
+ /* Check MII not currently being accessed */
+ if ( ! mentormac_gmii_wait ( efab ) )
+ goto out;
+
+ /* Write the address register */
+ EFAB_POPULATE_DWORD_2 ( reg,
+ GM_MGMT_PHY_ADDR, phy_id,
+ GM_MGMT_REG_ADDR, location );
+ efab->op->mac_writel ( efab, &reg, GM_MII_MGMT_ADR_REG_MAC );
+ udelay ( 10 );
+
+ /* Write data */
+ EFAB_POPULATE_DWORD_1 ( reg, GM_MGMT_CTL, value );
+ efab->op->mac_writel ( efab, &reg, GM_MII_MGMT_CTL_REG_MAC );
+
+ /* Wait for data to be written */
+ mentormac_gmii_wait ( efab );
+
+ out:
+ /* Restore efab->port */
+ efab->port = save_port;
+}
+
+/**
+ * Read a GMII register
+ *
+ */
+static int mentormac_mdio_read ( struct efab_nic *efab, int phy_id,
+ int location ) {
+ efab_dword_t reg;
+ int value = 0xffff;
+ int save_port;
+
+ /* Mentor MAC connects both PHYs to MAC 0 */
+ save_port = efab->port;
+ efab->port = 0;
+
+ /* Check MII not currently being accessed */
+ if ( ! mentormac_gmii_wait ( efab ) )
+ goto out;
+
+ /* Write the address register */
+ EFAB_POPULATE_DWORD_2 ( reg,
+ GM_MGMT_PHY_ADDR, phy_id,
+ GM_MGMT_REG_ADDR, location );
+ efab->op->mac_writel ( efab, &reg, GM_MII_MGMT_ADR_REG_MAC );
+ udelay ( 10 );
+
+ /* Request data to be read */
+ EFAB_POPULATE_DWORD_1 ( reg, GM_MGMT_RD_CYC, 1 );
+ efab->op->mac_writel ( efab, &reg, GM_MII_MGMT_CMD_REG_MAC );
+
+ /* Wait for data to be become available */
+ if ( mentormac_gmii_wait ( efab ) ) {
+ /* Read data */
+ efab->op->mac_readl ( efab, &reg, GM_MII_MGMT_STAT_REG_MAC );
+ value = EFAB_DWORD_FIELD ( reg, GM_MGMT_STAT );
+ EFAB_TRACE ( "Read from GMII %d register %02x, got %04x\n",
+ phy_id, location, value );
+ }
+
+ /* Signal completion */
+ EFAB_ZERO_DWORD ( reg );
+ efab->op->mac_writel ( efab, &reg, GM_MII_MGMT_CMD_REG_MAC );
+ udelay ( 10 );
+
+ out:
+ /* Restore efab->port */
+ efab->port = save_port;
+
+ return value;
+}
+
+/**************************************************************************
+ *
+ * EF1002 routines
+ *
+ **************************************************************************
+ */
+
+/** Control and General Status */
+#define EF1_CTR_GEN_STATUS0_REG 0x0
+#define EF1_MASTER_EVENTS_LBN 12
+#define EF1_MASTER_EVENTS_WIDTH 1
+#define EF1_TX_ENGINE_EN_LBN 19
+#define EF1_TX_ENGINE_EN_WIDTH 1
+#define EF1_RX_ENGINE_EN_LBN 18
+#define EF1_RX_ENGINE_EN_WIDTH 1
+#define EF1_LB_RESET_LBN 3
+#define EF1_LB_RESET_WIDTH 1
+#define EF1_MAC_RESET_LBN 2
+#define EF1_MAC_RESET_WIDTH 1
+#define EF1_CAM_ENABLE_LBN 1
+#define EF1_CAM_ENABLE_WIDTH 1
+
+/** IRQ sources */
+#define EF1_IRQ_SRC_REG 0x0008
+
+/** IRQ mask */
+#define EF1_IRQ_MASK_REG 0x000c
+#define EF1_IRQ_PHY1_LBN 11
+#define EF1_IRQ_PHY1_WIDTH 1
+#define EF1_IRQ_PHY0_LBN 10
+#define EF1_IRQ_PHY0_WIDTH 1
+#define EF1_IRQ_SERR_LBN 7
+#define EF1_IRQ_SERR_WIDTH 1
+#define EF1_IRQ_EVQ_LBN 3
+#define EF1_IRQ_EVQ_WIDTH 1
+
+/** Event generation */
+#define EF1_EVT3_REG 0x38
+
+/** EEPROM access */
+#define EF1_EEPROM_REG 0x0040
+
+/** Control register 2 */
+#define EF1_CTL2_REG 0x4c
+#define EF1_MEM_MAP_4MB_LBN 11
+#define EF1_MEM_MAP_4MB_WIDTH 1
+#define EF1_EV_INTR_CLR_WRITE_LBN 6
+#define EF1_EV_INTR_CLR_WRITE_WIDTH 1
+#define EF1_SW_RESET_LBN 2
+#define EF1_SW_RESET_WIDTH 1
+#define EF1_INTR_AFTER_EVENT_LBN 1
+#define EF1_INTR_AFTER_EVENT_WIDTH 1
+
+/** Event FIFO */
+#define EF1_EVENT_FIFO_REG 0x50
+
+/** Event FIFO count */
+#define EF1_EVENT_FIFO_COUNT_REG 0x5c
+#define EF1_EV_COUNT_LBN 0
+#define EF1_EV_COUNT_WIDTH 16
+
+/** TX DMA control and status */
+#define EF1_DMA_TX_CSR_REG 0x80
+#define EF1_DMA_TX_CSR_CHAIN_EN_LBN 8
+#define EF1_DMA_TX_CSR_CHAIN_EN_WIDTH 1
+#define EF1_DMA_TX_CSR_ENABLE_LBN 4
+#define EF1_DMA_TX_CSR_ENABLE_WIDTH 1
+#define EF1_DMA_TX_CSR_INT_EN_LBN 0
+#define EF1_DMA_TX_CSR_INT_EN_WIDTH 1
+
+/** RX DMA control and status */
+#define EF1_DMA_RX_CSR_REG 0xa0
+#define EF1_DMA_RX_ABOVE_1GB_EN_LBN 6
+#define EF1_DMA_RX_ABOVE_1GB_EN_WIDTH 1
+#define EF1_DMA_RX_BELOW_1MB_EN_LBN 5
+#define EF1_DMA_RX_BELOW_1MB_EN_WIDTH 1
+#define EF1_DMA_RX_CSR_ENABLE_LBN 0
+#define EF1_DMA_RX_CSR_ENABLE_WIDTH 1
+
+/** Level 5 watermark register (in MAC space) */
+#define EF1_GMF_L5WM_REG_MAC 0x20
+#define EF1_L5WM_LBN 0
+#define EF1_L5WM_WIDTH 32
+
+/** MAC clock */
+#define EF1_GM_MAC_CLK_REG 0x112000
+#define EF1_GM_PORT0_MAC_CLK_LBN 0
+#define EF1_GM_PORT0_MAC_CLK_WIDTH 1
+#define EF1_GM_PORT1_MAC_CLK_LBN 1
+#define EF1_GM_PORT1_MAC_CLK_WIDTH 1
+
+/** TX descriptor FIFO */
+#define EF1_TX_DESC_FIFO 0x141000
+#define EF1_TX_KER_EVQ_LBN 80
+#define EF1_TX_KER_EVQ_WIDTH 12
+#define EF1_TX_KER_IDX_LBN 64
+#define EF1_TX_KER_IDX_WIDTH 16
+#define EF1_TX_KER_MODE_LBN 63
+#define EF1_TX_KER_MODE_WIDTH 1
+#define EF1_TX_KER_PORT_LBN 60
+#define EF1_TX_KER_PORT_WIDTH 1
+#define EF1_TX_KER_CONT_LBN 56
+#define EF1_TX_KER_CONT_WIDTH 1
+#define EF1_TX_KER_BYTE_CNT_LBN 32
+#define EF1_TX_KER_BYTE_CNT_WIDTH 24
+#define EF1_TX_KER_BUF_ADR_LBN 0
+#define EF1_TX_KER_BUF_ADR_WIDTH 32
+
+/** TX descriptor FIFO flush */
+#define EF1_TX_DESC_FIFO_FLUSH 0x141ffc
+
+/** RX descriptor FIFO */
+#define EF1_RX_DESC_FIFO 0x145000
+#define EF1_RX_KER_EVQ_LBN 48
+#define EF1_RX_KER_EVQ_WIDTH 12
+#define EF1_RX_KER_IDX_LBN 32
+#define EF1_RX_KER_IDX_WIDTH 16
+#define EF1_RX_KER_BUF_ADR_LBN 0
+#define EF1_RX_KER_BUF_ADR_WIDTH 32
+
+/** RX descriptor FIFO flush */
+#define EF1_RX_DESC_FIFO_FLUSH 0x145ffc
+
+/** CAM */
+#define EF1_CAM_BASE 0x1c0000
+#define EF1_CAM_WTF_DOES_THIS_DO_LBN 0
+#define EF1_CAM_WTF_DOES_THIS_DO_WIDTH 32
+
+/** Event queue pointers */
+#define EF1_EVQ_PTR_BASE 0x260000
+#define EF1_EVQ_SIZE_LBN 29
+#define EF1_EVQ_SIZE_WIDTH 2
+#define EF1_EVQ_SIZE_4K 3
+#define EF1_EVQ_SIZE_2K 2
+#define EF1_EVQ_SIZE_1K 1
+#define EF1_EVQ_SIZE_512 0
+#define EF1_EVQ_BUF_BASE_ID_LBN 0
+#define EF1_EVQ_BUF_BASE_ID_WIDTH 29
+
+/* MAC registers */
+#define EF1002_MAC_REGBANK 0x110000
+#define EF1002_MAC_REGBANK_SIZE 0x1000
+#define EF1002_MAC_REG_SIZE 0x08
+
+/** Offset of a MAC register within EF1002 */
+#define EF1002_MAC_REG( efab, mac_reg ) \
+ ( EF1002_MAC_REGBANK + \
+ ( (efab)->port * EF1002_MAC_REGBANK_SIZE ) + \
+ ( (mac_reg) * EF1002_MAC_REG_SIZE ) )
+
+/* Event queue entries */
+#define EF1_EV_CODE_LBN 20
+#define EF1_EV_CODE_WIDTH 8
+#define EF1_RX_EV_DECODE 0x01
+#define EF1_TX_EV_DECODE 0x02
+#define EF1_DRV_GEN_EV_DECODE 0x0f
+
+/* Receive events */
+#define EF1_RX_EV_LEN_LBN 48
+#define EF1_RX_EV_LEN_WIDTH 16
+#define EF1_RX_EV_PORT_LBN 17
+#define EF1_RX_EV_PORT_WIDTH 3
+#define EF1_RX_EV_OK_LBN 16
+#define EF1_RX_EV_OK_WIDTH 1
+#define EF1_RX_EV_IDX_LBN 0
+#define EF1_RX_EV_IDX_WIDTH 16
+
+/* Transmit events */
+#define EF1_TX_EV_PORT_LBN 17
+#define EF1_TX_EV_PORT_WIDTH 3
+#define EF1_TX_EV_OK_LBN 16
+#define EF1_TX_EV_OK_WIDTH 1
+#define EF1_TX_EV_IDX_LBN 0
+#define EF1_TX_EV_IDX_WIDTH 16
+
+/**
+ * Write dword to EF1002 register
+ *
+ */
+static inline void ef1002_writel ( struct efab_nic *efab, efab_dword_t *value,
+ unsigned int reg ) {
+ EFAB_REGDUMP ( "Writing register %x with " EFAB_DWORD_FMT "\n",
+ reg, EFAB_DWORD_VAL ( *value ) );
+ writel ( value->u32[0], efab->membase + reg );
+}
+
+/**
+ * Read dword from an EF1002 register
+ *
+ */
+static inline void ef1002_readl ( struct efab_nic *efab, efab_dword_t *value,
+ unsigned int reg ) {
+ value->u32[0] = readl ( efab->membase + reg );
+ EFAB_REGDUMP ( "Read from register %x, got " EFAB_DWORD_FMT "\n",
+ reg, EFAB_DWORD_VAL ( *value ) );
+}
+
+/**
+ * Read dword from an EF1002 register, silently
+ *
+ */
+static inline void ef1002_readl_silent ( struct efab_nic *efab,
+ efab_dword_t *value,
+ unsigned int reg ) {
+ value->u32[0] = readl ( efab->membase + reg );
+}
+
+/**
+ * Get memory base
+ *
+ */
+static void ef1002_get_membase ( struct efab_nic *efab ) {
+ unsigned long membase_phys;
+
+ membase_phys = pci_bar_start ( efab->pci, PCI_BASE_ADDRESS_0 );
+ efab->membase = ioremap ( membase_phys, 0x800000 );
+}
+
+/** PCI registers to backup/restore over a device reset */
+static const unsigned int efab_pci_reg_addr[] = {
+ PCI_COMMAND, 0x0c /* PCI_CACHE_LINE_SIZE */,
+ PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2,
+ PCI_BASE_ADDRESS_3, PCI_ROM_ADDRESS, PCI_INTERRUPT_LINE,
+};
+/** Number of registers in efab_pci_reg_addr */
+#define EFAB_NUM_PCI_REG \
+ ( sizeof ( efab_pci_reg_addr ) / sizeof ( efab_pci_reg_addr[0] ) )
+/** PCI configuration space backup */
+struct efab_pci_reg {
+ uint32_t reg[EFAB_NUM_PCI_REG];
+};
+
+/**
+ * Reset device
+ *
+ */
+static int ef1002_reset ( struct efab_nic *efab ) {
+ struct efab_pci_reg pci_reg;
+ struct pci_device *pci_dev = efab->pci;
+ efab_dword_t reg;
+ unsigned int i;
+ uint32_t tmp;
+
+ /* Back up PCI configuration registers */
+ for ( i = 0 ; i < EFAB_NUM_PCI_REG ; i++ ) {
+ pci_read_config_dword ( pci_dev, efab_pci_reg_addr[i],
+ &pci_reg.reg[i] );
+ }
+
+ /* Reset the whole device. */
+ EFAB_POPULATE_DWORD_1 ( reg, EF1_SW_RESET, 1 );
+ ef1002_writel ( efab, &reg, EF1_CTL2_REG );
+ mdelay ( 200 );
+
+ /* Restore PCI configuration space */
+ for ( i = 0 ; i < EFAB_NUM_PCI_REG ; i++ ) {
+ pci_write_config_dword ( pci_dev, efab_pci_reg_addr[i],
+ pci_reg.reg[i] );
+ }
+
+ /* Verify PCI configuration space */
+ for ( i = 0 ; i < EFAB_NUM_PCI_REG ; i++ ) {
+ pci_read_config_dword ( pci_dev, efab_pci_reg_addr[i], &tmp );
+ if ( tmp != pci_reg.reg[i] ) {
+ printf ( "PCI restore failed on register %02x "
+ "(is %08x, should be %08x); reboot\n",
+ i, tmp, pci_reg.reg[i] );
+ return 0;
+ }
+ }
+
+ /* Verify device reset complete */
+ ef1002_readl ( efab, &reg, EF1_CTR_GEN_STATUS0_REG );
+ if ( EFAB_DWORD_IS_ALL_ONES ( reg ) ) {
+ printf ( "Reset failed\n" );
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * Initialise NIC
+ *
+ */
+static int ef1002_init_nic ( struct efab_nic *efab ) {
+ efab_dword_t reg;
+ int save_port;
+
+ /* No idea what CAM is, but the 'datasheet' says that we have
+ * to write these values in at start of day
+ */
+ EFAB_POPULATE_DWORD_1 ( reg, EF1_CAM_WTF_DOES_THIS_DO, 0x6 );
+ ef1002_writel ( efab, &reg, EF1_CAM_BASE + 0x20018 );
+ udelay ( 1000 );
+ EFAB_POPULATE_DWORD_1 ( reg, EF1_CAM_WTF_DOES_THIS_DO, 0x01000000 );
+ ef1002_writel ( efab, &reg, EF1_CAM_BASE + 0x00018 );
+ udelay ( 1000 );
+
+ /* General control register 0 */
+ ef1002_readl ( efab, &reg, EF1_CTR_GEN_STATUS0_REG );
+ EFAB_SET_DWORD_FIELD ( reg, EF1_MASTER_EVENTS, 0 );
+ EFAB_SET_DWORD_FIELD ( reg, EF1_CAM_ENABLE, 1 );
+ ef1002_writel ( efab, &reg, EF1_CTR_GEN_STATUS0_REG );
+ udelay ( 1000 );
+
+ /* General control register 2 */
+ ef1002_readl ( efab, &reg, EF1_CTL2_REG );
+ EFAB_SET_DWORD_FIELD ( reg, EF1_INTR_AFTER_EVENT, 1 );
+ EFAB_SET_DWORD_FIELD ( reg, EF1_EV_INTR_CLR_WRITE, 0 );
+ EFAB_SET_DWORD_FIELD ( reg, EF1_MEM_MAP_4MB, 0 );
+ ef1002_writel ( efab, &reg, EF1_CTL2_REG );
+ udelay ( 1000 );
+
+ /* Enable RX DMA */
+ ef1002_readl ( efab, &reg, EF1_DMA_RX_CSR_REG );
+ EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_RX_CSR_ENABLE, 1 );
+ EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_RX_BELOW_1MB_EN, 1 );
+ EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_RX_ABOVE_1GB_EN, 1 );
+ ef1002_writel ( efab, &reg, EF1_DMA_RX_CSR_REG );
+ udelay ( 1000 );
+
+ /* Enable TX DMA */
+ ef1002_readl ( efab, &reg, EF1_DMA_TX_CSR_REG );
+ EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_TX_CSR_CHAIN_EN, 1 );
+ EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_TX_CSR_ENABLE, 0 /* ?? */ );
+ EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_TX_CSR_INT_EN, 0 /* ?? */ );
+ ef1002_writel ( efab, &reg, EF1_DMA_TX_CSR_REG );
+ udelay ( 1000 );
+
+ /* Flush descriptor queues */
+ EFAB_ZERO_DWORD ( reg );
+ ef1002_writel ( efab, &reg, EF1_RX_DESC_FIFO_FLUSH );
+ ef1002_writel ( efab, &reg, EF1_TX_DESC_FIFO_FLUSH );
+ wmb();
+ udelay ( 10000 );
+
+ /* Reset both MACs */
+ save_port = efab->port;
+ efab->port = 0;
+ mentormac_reset ( efab, 1 );
+ efab->port = 1;
+ mentormac_reset ( efab, 1 );
+
+ /* Reset both PHYs */
+ ef1002_readl ( efab, &reg, EF1_CTR_GEN_STATUS0_REG );
+ EFAB_SET_DWORD_FIELD ( reg, EF1_MAC_RESET, 1 );
+ ef1002_writel ( efab, &reg, EF1_CTR_GEN_STATUS0_REG );
+ udelay ( 10000 );
+ EFAB_SET_DWORD_FIELD ( reg, EF1_MAC_RESET, 0 );
+ ef1002_writel ( efab, &reg, EF1_CTR_GEN_STATUS0_REG );
+ udelay ( 10000 );
+
+ /* Take MACs out of reset */
+ efab->port = 0;
+ mentormac_reset ( efab, 0 );
+ efab->port = 1;
+ mentormac_reset ( efab, 0 );
+ efab->port = save_port;
+
+ /* Give PHY time to wake up. It takes a while. */
+ sleep ( 2 );
+
+ return 1;
+}
+
+/**
+ * Read MAC address from EEPROM
+ *
+ */
+static int ef1002_read_eeprom ( struct efab_nic *efab ) {
+ return efab_eeprom_read_mac ( efab->membase + EF1_EEPROM_REG,
+ efab->mac_addr );
+}
+
+/** RX descriptor */
+typedef efab_qword_t ef1002_rx_desc_t;
+
+/**
+ * Build RX descriptor
+ *
+ */
+static void ef1002_build_rx_desc ( struct efab_nic *efab,
+ struct efab_rx_buf *rx_buf ) {
+ ef1002_rx_desc_t rxd;
+
+ EFAB_POPULATE_QWORD_3 ( rxd,
+ EF1_RX_KER_EVQ, 0,
+ EF1_RX_KER_IDX, rx_buf->id,
+ EF1_RX_KER_BUF_ADR,
+ virt_to_bus ( rx_buf->addr ) );
+ ef1002_writel ( efab, &rxd.dword[0], EF1_RX_DESC_FIFO + 0 );
+ ef1002_writel ( efab, &rxd.dword[1], EF1_RX_DESC_FIFO + 4 );
+ udelay ( 10 );
+}
+
+/**
+ * Update RX descriptor write pointer
+ *
+ */
+static void ef1002_notify_rx_desc ( struct efab_nic *efab __unused ) {
+ /* Nothing to do */
+}
+
+/** TX descriptor */
+typedef efab_oword_t ef1002_tx_desc_t;
+
+/**
+ * Build TX descriptor
+ *
+ */
+static void ef1002_build_tx_desc ( struct efab_nic *efab,
+ struct efab_tx_buf *tx_buf ) {
+ ef1002_tx_desc_t txd;
+
+ EFAB_POPULATE_OWORD_7 ( txd,
+ EF1_TX_KER_EVQ, 0,
+ EF1_TX_KER_IDX, tx_buf->id,
+ EF1_TX_KER_MODE, 0 /* IP mode */,
+ EF1_TX_KER_PORT, efab->port,
+ EF1_TX_KER_CONT, 0,
+ EF1_TX_KER_BYTE_CNT, tx_buf->len,
+ EF1_TX_KER_BUF_ADR,
+ virt_to_bus ( tx_buf->addr ) );
+
+ ef1002_writel ( efab, &txd.dword[0], EF1_TX_DESC_FIFO + 0 );
+ ef1002_writel ( efab, &txd.dword[1], EF1_TX_DESC_FIFO + 4 );
+ ef1002_writel ( efab, &txd.dword[2], EF1_TX_DESC_FIFO + 8 );
+ udelay ( 10 );
+}
+
+/**
+ * Update TX descriptor write pointer
+ *
+ */
+static void ef1002_notify_tx_desc ( struct efab_nic *efab __unused ) {
+ /* Nothing to do */
+}
+
+/** An event */
+typedef efab_qword_t ef1002_event_t;
+
+/**
+ * Retrieve event from event queue
+ *
+ */
+static int ef1002_fetch_event ( struct efab_nic *efab,
+ struct efab_event *event ) {
+ efab_dword_t reg;
+ int ev_code;
+ int words;
+
+ /* Check event FIFO depth */
+ ef1002_readl_silent ( efab, &reg, EF1_EVENT_FIFO_COUNT_REG );
+ words = EFAB_DWORD_FIELD ( reg, EF1_EV_COUNT );
+ if ( ! words )
+ return 0;
+
+ /* Read event data */
+ ef1002_readl ( efab, &reg, EF1_EVENT_FIFO_REG );
+ DBG ( "Event is " EFAB_DWORD_FMT "\n", EFAB_DWORD_VAL ( reg ) );
+
+ /* Decode event */
+ ev_code = EFAB_DWORD_FIELD ( reg, EF1_EV_CODE );
+ switch ( ev_code ) {
+ case EF1_TX_EV_DECODE:
+ event->type = EFAB_EV_TX;
+ break;
+ case EF1_RX_EV_DECODE:
+ event->type = EFAB_EV_RX;
+ event->rx_id = EFAB_DWORD_FIELD ( reg, EF1_RX_EV_IDX );
+ /* RX len not available via event FIFO */
+ event->rx_len = ETH_FRAME_LEN;
+ break;
+ default:
+ printf ( "Unknown event type %d\n", ev_code );
+ event->type = EFAB_EV_NONE;
+ }
+
+ /* Clear any pending interrupts */
+ ef1002_readl ( efab, &reg, EF1_IRQ_SRC_REG );
+
+ return 1;
+}
+
+/**
+ * Enable/disable interrupts
+ *
+ */
+static void ef1002_mask_irq ( struct efab_nic *efab, int enabled ) {
+ efab_dword_t irq_mask;
+
+ EFAB_POPULATE_DWORD_2 ( irq_mask,
+ EF1_IRQ_SERR, enabled,
+ EF1_IRQ_EVQ, enabled );
+ ef1002_writel ( efab, &irq_mask, EF1_IRQ_MASK_REG );
+}
+
+/**
+ * Generate interrupt
+ *
+ */
+static void ef1002_generate_irq ( struct efab_nic *efab ) {
+ ef1002_event_t test_event;
+
+ EFAB_POPULATE_QWORD_1 ( test_event,
+ EF1_EV_CODE, EF1_DRV_GEN_EV_DECODE );
+ ef1002_writel ( efab, &test_event.dword[0], EF1_EVT3_REG );
+}
+
+/**
+ * Write dword to an EF1002 MAC register
+ *
+ */
+static void ef1002_mac_writel ( struct efab_nic *efab,
+ efab_dword_t *value, unsigned int mac_reg ) {
+ ef1002_writel ( efab, value, EF1002_MAC_REG ( efab, mac_reg ) );
+}
+
+/**
+ * Read dword from an EF1002 MAC register
+ *
+ */
+static void ef1002_mac_readl ( struct efab_nic *efab,
+ efab_dword_t *value, unsigned int mac_reg ) {
+ ef1002_readl ( efab, value, EF1002_MAC_REG ( efab, mac_reg ) );
+}
+
+/**
+ * Initialise MAC
+ *
+ */
+static int ef1002_init_mac ( struct efab_nic *efab ) {
+ static struct efab_mentormac_parameters ef1002_mentormac_params = {
+ .gmf_cfgfrth = 0x13,
+ .gmf_cfgftth = 0x10,
+ .gmf_cfghwmft = 0x555,
+ .gmf_cfghwm = 0x2a,
+ .gmf_cfglwm = 0x15,
+ };
+ efab_dword_t reg;
+ unsigned int mac_clk;
+
+ /* Initialise PHY */
+ alaska_init ( efab );
+
+ /* Initialise MAC */
+ mentormac_init ( efab, &ef1002_mentormac_params );
+
+ /* Write Level 5 watermark register */
+ EFAB_POPULATE_DWORD_1 ( reg, EF1_L5WM, 0x10040000 );
+ efab->op->mac_writel ( efab, &reg, EF1_GMF_L5WM_REG_MAC );
+ udelay ( 10 );
+
+ /* Set MAC clock speed */
+ ef1002_readl ( efab, &reg, EF1_GM_MAC_CLK_REG );
+ mac_clk = ( efab->link_options & LPA_1000 ) ? 0 : 1;
+ if ( efab->port == 0 ) {
+ EFAB_SET_DWORD_FIELD ( reg, EF1_GM_PORT0_MAC_CLK, mac_clk );
+ } else {
+ EFAB_SET_DWORD_FIELD ( reg, EF1_GM_PORT1_MAC_CLK, mac_clk );
+ }
+ ef1002_writel ( efab, &reg, EF1_GM_MAC_CLK_REG );
+ udelay ( 10 );
+
+ return 1;
+}
+
+/** MDIO write */
+static void ef1002_mdio_write ( struct efab_nic *efab, int location,
+ int value ) {
+ mentormac_mdio_write ( efab, efab->port + 2, location, value );
+}
+
+/** MDIO read */
+static int ef1002_mdio_read ( struct efab_nic *efab, int location ) {
+ return mentormac_mdio_read ( efab, efab->port + 2, location );
+}
+
+static struct efab_operations ef1002_operations = {
+ .get_membase = ef1002_get_membase,
+ .reset = ef1002_reset,
+ .init_nic = ef1002_init_nic,
+ .read_eeprom = ef1002_read_eeprom,
+ .build_rx_desc = ef1002_build_rx_desc,
+ .notify_rx_desc = ef1002_notify_rx_desc,
+ .build_tx_desc = ef1002_build_tx_desc,
+ .notify_tx_desc = ef1002_notify_tx_desc,
+ .fetch_event = ef1002_fetch_event,
+ .mask_irq = ef1002_mask_irq,
+ .generate_irq = ef1002_generate_irq,
+ .mac_writel = ef1002_mac_writel,
+ .mac_readl = ef1002_mac_readl,
+ .init_mac = ef1002_init_mac,
+ .mdio_write = ef1002_mdio_write,
+ .mdio_read = ef1002_mdio_read,
+};
+
+/**************************************************************************
+ *
+ * Falcon routines
+ *
+ **************************************************************************
+ */
+
+/* I/O BAR address register */
+#define FCN_IOM_IND_ADR_REG 0x0
+
+/* I/O BAR data register */
+#define FCN_IOM_IND_DAT_REG 0x4
+
+/* Interrupt enable register */
+#define FCN_INT_EN_REG_KER 0x0010
+#define FCN_MEM_PERR_INT_EN_KER_LBN 5
+#define FCN_MEM_PERR_INT_EN_KER_WIDTH 1
+#define FCN_KER_INT_CHAR_LBN 4
+#define FCN_KER_INT_CHAR_WIDTH 1
+#define FCN_KER_INT_KER_LBN 3
+#define FCN_KER_INT_KER_WIDTH 1
+#define FCN_ILL_ADR_ERR_INT_EN_KER_LBN 2
+#define FCN_ILL_ADR_ERR_INT_EN_KER_WIDTH 1
+#define FCN_SRM_PERR_INT_EN_KER_LBN 1
+#define FCN_SRM_PERR_INT_EN_KER_WIDTH 1
+#define FCN_DRV_INT_EN_KER_LBN 0
+#define FCN_DRV_INT_EN_KER_WIDTH 1
+
+/* Interrupt status register */
+#define FCN_INT_ADR_REG_KER 0x0030
+#define FCN_INT_ADR_KER_LBN 0
+#define FCN_INT_ADR_KER_WIDTH EFAB_DMA_TYPE_WIDTH ( 64 )
+
+/* Interrupt acknowledge register */
+#define FCN_INT_ACK_KER_REG 0x0050
+
+/* SPI host command register */
+#define FCN_EE_SPI_HCMD_REG_KER 0x0100
+#define FCN_EE_SPI_HCMD_CMD_EN_LBN 31
+#define FCN_EE_SPI_HCMD_CMD_EN_WIDTH 1
+#define FCN_EE_WR_TIMER_ACTIVE_LBN 28
+#define FCN_EE_WR_TIMER_ACTIVE_WIDTH 1
+#define FCN_EE_SPI_HCMD_SF_SEL_LBN 24
+#define FCN_EE_SPI_HCMD_SF_SEL_WIDTH 1
+#define FCN_EE_SPI_EEPROM 0
+#define FCN_EE_SPI_FLASH 1
+#define FCN_EE_SPI_HCMD_DABCNT_LBN 16
+#define FCN_EE_SPI_HCMD_DABCNT_WIDTH 5
+#define FCN_EE_SPI_HCMD_READ_LBN 15
+#define FCN_EE_SPI_HCMD_READ_WIDTH 1
+#define FCN_EE_SPI_READ 1
+#define FCN_EE_SPI_WRITE 0
+#define FCN_EE_SPI_HCMD_DUBCNT_LBN 12
+#define FCN_EE_SPI_HCMD_DUBCNT_WIDTH 2
+#define FCN_EE_SPI_HCMD_ADBCNT_LBN 8
+#define FCN_EE_SPI_HCMD_ADBCNT_WIDTH 2
+#define FCN_EE_SPI_HCMD_ENC_LBN 0
+#define FCN_EE_SPI_HCMD_ENC_WIDTH 8
+
+/* SPI host address register */
+#define FCN_EE_SPI_HADR_REG_KER 0x0110
+#define FCN_EE_SPI_HADR_DUBYTE_LBN 24
+#define FCN_EE_SPI_HADR_DUBYTE_WIDTH 8
+#define FCN_EE_SPI_HADR_ADR_LBN 0
+#define FCN_EE_SPI_HADR_ADR_WIDTH 24
+
+/* SPI host data register */
+#define FCN_EE_SPI_HDATA_REG_KER 0x0120
+#define FCN_EE_SPI_HDATA3_LBN 96
+#define FCN_EE_SPI_HDATA3_WIDTH 32
+#define FCN_EE_SPI_HDATA2_LBN 64
+#define FCN_EE_SPI_HDATA2_WIDTH 32
+#define FCN_EE_SPI_HDATA1_LBN 32
+#define FCN_EE_SPI_HDATA1_WIDTH 32
+#define FCN_EE_SPI_HDATA0_LBN 0
+#define FCN_EE_SPI_HDATA0_WIDTH 32
+
+/* GPIO control register */
+#define FCN_GPIO_CTL_REG_KER 0x0210
+#define FCN_FLASH_PRESENT_LBN 7
+#define FCN_FLASH_PRESENT_WIDTH 1
+#define FCN_EEPROM_PRESENT_LBN 6
+#define FCN_EEPROM_PRESENT_WIDTH 1
+
+/* Global control register */
+#define FCN_GLB_CTL_REG_KER 0x0220
+#define FCN_EXT_PHY_RST_CTL_LBN 63
+#define FCN_EXT_PHY_RST_CTL_WIDTH 1
+#define FCN_PCIE_SD_RST_CTL_LBN 61
+#define FCN_PCIE_SD_RST_CTL_WIDTH 1
+#define FCN_PCIX_RST_CTL_LBN 60
+#define FCN_PCIX_RST_CTL_WIDTH 1
+#define FCN_RST_EXT_PHY_LBN 31
+#define FCN_RST_EXT_PHY_WIDTH 1
+#define FCN_INT_RST_DUR_LBN 4
+#define FCN_INT_RST_DUR_WIDTH 3
+#define FCN_EXT_PHY_RST_DUR_LBN 1
+#define FCN_EXT_PHY_RST_DUR_WIDTH 3
+#define FCN_SWRST_LBN 0
+#define FCN_SWRST_WIDTH 1
+#define FCN_INCLUDE_IN_RESET 0
+#define FCN_EXCLUDE_FROM_RESET 1
+
+/* Timer table for kernel access */
+#define FCN_TIMER_CMD_REG_KER 0x420
+#define FCN_TIMER_MODE_LBN 12
+#define FCN_TIMER_MODE_WIDTH 2
+#define FCN_TIMER_MODE_DIS 0
+#define FCN_TIMER_MODE_INT_HLDOFF 1
+#define FCN_TIMER_VAL_LBN 0
+#define FCN_TIMER_VAL_WIDTH 12
+
+/* SRAM receive descriptor cache configuration register */
+#define FCN_SRM_RX_DC_CFG_REG_KER 0x610
+#define FCN_SRM_RX_DC_BASE_ADR_LBN 0
+#define FCN_SRM_RX_DC_BASE_ADR_WIDTH 21
+
+/* SRAM transmit descriptor cache configuration register */
+#define FCN_SRM_TX_DC_CFG_REG_KER 0x620
+#define FCN_SRM_TX_DC_BASE_ADR_LBN 0
+#define FCN_SRM_TX_DC_BASE_ADR_WIDTH 21
+
+/* Receive filter control register */
+#define FCN_RX_FILTER_CTL_REG_KER 0x810
+#define FCN_NUM_KER_LBN 24
+#define FCN_NUM_KER_WIDTH 2
+
+/* Receive descriptor update register */
+#define FCN_RX_DESC_UPD_REG_KER 0x0830
+#define FCN_RX_DESC_WPTR_LBN 96
+#define FCN_RX_DESC_WPTR_WIDTH 12
+#define FCN_RX_DESC_UPD_REG_KER_DWORD ( FCN_RX_DESC_UPD_REG_KER + 12 )
+#define FCN_RX_DESC_WPTR_DWORD_LBN 0
+#define FCN_RX_DESC_WPTR_DWORD_WIDTH 12
+
+/* Receive descriptor cache configuration register */
+#define FCN_RX_DC_CFG_REG_KER 0x840
+#define FCN_RX_DC_SIZE_LBN 0
+#define FCN_RX_DC_SIZE_WIDTH 2
+
+/* Transmit descriptor update register */
+#define FCN_TX_DESC_UPD_REG_KER 0x0a10
+#define FCN_TX_DESC_WPTR_LBN 96
+#define FCN_TX_DESC_WPTR_WIDTH 12
+#define FCN_TX_DESC_UPD_REG_KER_DWORD ( FCN_TX_DESC_UPD_REG_KER + 12 )
+#define FCN_TX_DESC_WPTR_DWORD_LBN 0
+#define FCN_TX_DESC_WPTR_DWORD_WIDTH 12
+
+/* Transmit descriptor cache configuration register */
+#define FCN_TX_DC_CFG_REG_KER 0xa20
+#define FCN_TX_DC_SIZE_LBN 0
+#define FCN_TX_DC_SIZE_WIDTH 2
+
+/* PHY management transmit data register */
+#define FCN_MD_TXD_REG_KER 0xc00
+#define FCN_MD_TXD_LBN 0
+#define FCN_MD_TXD_WIDTH 16
+
+/* PHY management receive data register */
+#define FCN_MD_RXD_REG_KER 0xc10
+#define FCN_MD_RXD_LBN 0
+#define FCN_MD_RXD_WIDTH 16
+
+/* PHY management configuration & status register */
+#define FCN_MD_CS_REG_KER 0xc20
+#define FCN_MD_GC_LBN 4
+#define FCN_MD_GC_WIDTH 1
+#define FCN_MD_RIC_LBN 2
+#define FCN_MD_RIC_WIDTH 1
+#define FCN_MD_WRC_LBN 0
+#define FCN_MD_WRC_WIDTH 1
+
+/* PHY management PHY address register */
+#define FCN_MD_PHY_ADR_REG_KER 0xc30
+#define FCN_MD_PHY_ADR_LBN 0
+#define FCN_MD_PHY_ADR_WIDTH 16
+
+/* PHY management ID register */
+#define FCN_MD_ID_REG_KER 0xc40
+#define FCN_MD_PRT_ADR_LBN 11
+#define FCN_MD_PRT_ADR_WIDTH 5
+#define FCN_MD_DEV_ADR_LBN 6
+#define FCN_MD_DEV_ADR_WIDTH 5
+
+/* PHY management status & mask register */
+#define FCN_MD_STAT_REG_KER 0xc50
+#define FCN_MD_BSY_LBN 0
+#define FCN_MD_BSY_WIDTH 1
+
+/* Port 0 and 1 MAC control registers */
+#define FCN_MAC0_CTRL_REG_KER 0xc80
+#define FCN_MAC1_CTRL_REG_KER 0xc90
+#define FCN_MAC_XOFF_VAL_LBN 16
+#define FCN_MAC_XOFF_VAL_WIDTH 16
+#define FCN_MAC_BCAD_ACPT_LBN 4
+#define FCN_MAC_BCAD_ACPT_WIDTH 1
+#define FCN_MAC_UC_PROM_LBN 3
+#define FCN_MAC_UC_PROM_WIDTH 1
+#define FCN_MAC_LINK_STATUS_LBN 2
+#define FCN_MAC_LINK_STATUS_WIDTH 1
+#define FCN_MAC_SPEED_LBN 0
+#define FCN_MAC_SPEED_WIDTH 2
+
+/* XGMAC global configuration - port 0*/
+#define FCN_XM_GLB_CFG_REG_P0_KER 0x1220
+#define FCN_XM_RX_STAT_EN_LBN 11
+#define FCN_XM_RX_STAT_EN_WIDTH 1
+#define FCN_XM_TX_STAT_EN_LBN 10
+#define FCN_XM_TX_STAT_EN_WIDTH 1
+#define FCN_XM_CUT_THRU_MODE_LBN 7
+#define FCN_XM_CUT_THRU_MODE_WIDTH 1
+#define FCN_XM_RX_JUMBO_MODE_LBN 6
+#define FCN_XM_RX_JUMBO_MODE_WIDTH 1
+
+/* XGMAC transmit configuration - port 0 */
+#define FCN_XM_TX_CFG_REG_P0_KER 0x1230
+#define FCN_XM_IPG_LBN 16
+#define FCN_XM_IPG_WIDTH 4
+#define FCN_XM_WTF_DOES_THIS_DO_LBN 9
+#define FCN_XM_WTF_DOES_THIS_DO_WIDTH 1
+#define FCN_XM_TXCRC_LBN 8
+#define FCN_XM_TXCRC_WIDTH 1
+#define FCN_XM_AUTO_PAD_LBN 5
+#define FCN_XM_AUTO_PAD_WIDTH 1
+#define FCN_XM_TX_PRMBL_LBN 2
+#define FCN_XM_TX_PRMBL_WIDTH 1
+#define FCN_XM_TXEN_LBN 1
+#define FCN_XM_TXEN_WIDTH 1
+
+/* XGMAC receive configuration - port 0 */
+#define FCN_XM_RX_CFG_REG_P0_KER 0x1240
+#define FCN_XM_PASS_CRC_ERR_LBN 25
+#define FCN_XM_PASS_CRC_ERR_WIDTH 1
+#define FCN_XM_AUTO_DEPAD_LBN 8
+#define FCN_XM_AUTO_DEPAD_WIDTH 1
+#define FCN_XM_RXEN_LBN 1
+#define FCN_XM_RXEN_WIDTH 1
+
+/* Receive descriptor pointer table */
+#define FCN_RX_DESC_PTR_TBL_KER 0x11800
+#define FCN_RX_DESCQ_BUF_BASE_ID_LBN 36
+#define FCN_RX_DESCQ_BUF_BASE_ID_WIDTH 20
+#define FCN_RX_DESCQ_EVQ_ID_LBN 24
+#define FCN_RX_DESCQ_EVQ_ID_WIDTH 12
+#define FCN_RX_DESCQ_OWNER_ID_LBN 10
+#define FCN_RX_DESCQ_OWNER_ID_WIDTH 14
+#define FCN_RX_DESCQ_SIZE_LBN 3
+#define FCN_RX_DESCQ_SIZE_WIDTH 2
+#define FCN_RX_DESCQ_SIZE_4K 3
+#define FCN_RX_DESCQ_SIZE_2K 2
+#define FCN_RX_DESCQ_SIZE_1K 1
+#define FCN_RX_DESCQ_SIZE_512 0
+#define FCN_RX_DESCQ_TYPE_LBN 2
+#define FCN_RX_DESCQ_TYPE_WIDTH 1
+#define FCN_RX_DESCQ_JUMBO_LBN 1
+#define FCN_RX_DESCQ_JUMBO_WIDTH 1
+#define FCN_RX_DESCQ_EN_LBN 0
+#define FCN_RX_DESCQ_EN_WIDTH 1
+
+/* Transmit descriptor pointer table */
+#define FCN_TX_DESC_PTR_TBL_KER 0x11900
+#define FCN_TX_DESCQ_EN_LBN 88
+#define FCN_TX_DESCQ_EN_WIDTH 1
+#define FCN_TX_DESCQ_BUF_BASE_ID_LBN 36
+#define FCN_TX_DESCQ_BUF_BASE_ID_WIDTH 20
+#define FCN_TX_DESCQ_EVQ_ID_LBN 24
+#define FCN_TX_DESCQ_EVQ_ID_WIDTH 12
+#define FCN_TX_DESCQ_OWNER_ID_LBN 10
+#define FCN_TX_DESCQ_OWNER_ID_WIDTH 14
+#define FCN_TX_DESCQ_SIZE_LBN 3
+#define FCN_TX_DESCQ_SIZE_WIDTH 2
+#define FCN_TX_DESCQ_SIZE_4K 3
+#define FCN_TX_DESCQ_SIZE_2K 2
+#define FCN_TX_DESCQ_SIZE_1K 1
+#define FCN_TX_DESCQ_SIZE_512 0
+#define FCN_TX_DESCQ_TYPE_LBN 1
+#define FCN_TX_DESCQ_TYPE_WIDTH 2
+#define FCN_TX_DESCQ_FLUSH_LBN 0
+#define FCN_TX_DESCQ_FLUSH_WIDTH 1
+
+/* Event queue pointer */
+#define FCN_EVQ_PTR_TBL_KER 0x11a00
+#define FCN_EVQ_EN_LBN 23
+#define FCN_EVQ_EN_WIDTH 1
+#define FCN_EVQ_SIZE_LBN 20
+#define FCN_EVQ_SIZE_WIDTH 3
+#define FCN_EVQ_SIZE_32K 6
+#define FCN_EVQ_SIZE_16K 5
+#define FCN_EVQ_SIZE_8K 4
+#define FCN_EVQ_SIZE_4K 3
+#define FCN_EVQ_SIZE_2K 2
+#define FCN_EVQ_SIZE_1K 1
+#define FCN_EVQ_SIZE_512 0
+#define FCN_EVQ_BUF_BASE_ID_LBN 0
+#define FCN_EVQ_BUF_BASE_ID_WIDTH 20
+
+/* Event queue read pointer */
+#define FCN_EVQ_RPTR_REG_KER 0x11b00
+#define FCN_EVQ_RPTR_LBN 0
+#define FCN_EVQ_RPTR_WIDTH 14
+#define FCN_EVQ_RPTR_REG_KER_DWORD ( FCN_EVQ_RPTR_REG_KER + 0 )
+#define FCN_EVQ_RPTR_DWORD_LBN 0
+#define FCN_EVQ_RPTR_DWORD_WIDTH 14
+
+/* Special buffer descriptors */
+#define FCN_BUF_FULL_TBL_KER 0x18000
+#define FCN_IP_DAT_BUF_SIZE_LBN 50
+#define FCN_IP_DAT_BUF_SIZE_WIDTH 1
+#define FCN_IP_DAT_BUF_SIZE_8K 1
+#define FCN_IP_DAT_BUF_SIZE_4K 0
+#define FCN_BUF_ADR_FBUF_LBN 14
+#define FCN_BUF_ADR_FBUF_WIDTH 34
+#define FCN_BUF_OWNER_ID_FBUF_LBN 0
+#define FCN_BUF_OWNER_ID_FBUF_WIDTH 14
+
+/* MAC registers */
+#define FALCON_MAC_REGBANK 0xe00
+#define FALCON_MAC_REGBANK_SIZE 0x200
+#define FALCON_MAC_REG_SIZE 0x10
+
+/** Offset of a MAC register within Falcon */
+#define FALCON_MAC_REG( efab, mac_reg ) \
+ ( FALCON_MAC_REGBANK + \
+ ( (efab)->port * FALCON_MAC_REGBANK_SIZE ) + \
+ ( (mac_reg) * FALCON_MAC_REG_SIZE ) )
+#define FCN_MAC_DATA_LBN 0
+#define FCN_MAC_DATA_WIDTH 32
+
+/* Transmit descriptor */
+#define FCN_TX_KER_PORT_LBN 63
+#define FCN_TX_KER_PORT_WIDTH 1
+#define FCN_TX_KER_BYTE_CNT_LBN 48
+#define FCN_TX_KER_BYTE_CNT_WIDTH 14
+#define FCN_TX_KER_BUF_ADR_LBN 0
+#define FCN_TX_KER_BUF_ADR_WIDTH EFAB_DMA_TYPE_WIDTH ( 46 )
+
+/* Receive descriptor */
+#define FCN_RX_KER_BUF_SIZE_LBN 48
+#define FCN_RX_KER_BUF_SIZE_WIDTH 14
+#define FCN_RX_KER_BUF_ADR_LBN 0
+#define FCN_RX_KER_BUF_ADR_WIDTH EFAB_DMA_TYPE_WIDTH ( 46 )
+
+/* Event queue entries */
+#define FCN_EV_CODE_LBN 60
+#define FCN_EV_CODE_WIDTH 4
+#define FCN_RX_IP_EV_DECODE 0
+#define FCN_TX_IP_EV_DECODE 2
+#define FCN_DRIVER_EV_DECODE 5
+
+/* Receive events */
+#define FCN_RX_PORT_LBN 30
+#define FCN_RX_PORT_WIDTH 1
+#define FCN_RX_EV_BYTE_CNT_LBN 16
+#define FCN_RX_EV_BYTE_CNT_WIDTH 14
+#define FCN_RX_EV_DESC_PTR_LBN 0
+#define FCN_RX_EV_DESC_PTR_WIDTH 12
+
+/* Transmit events */
+#define FCN_TX_EV_DESC_PTR_LBN 0
+#define FCN_TX_EV_DESC_PTR_WIDTH 12
+
+/* Fixed special buffer numbers to use */
+#define FALCON_EVQ_ID 0
+#define FALCON_TXD_ID 1
+#define FALCON_RXD_ID 2
+
+#if FALCON_USE_IO_BAR
+
+/* Write dword via the I/O BAR */
+static inline void _falcon_writel ( struct efab_nic *efab, uint32_t value,
+ unsigned int reg ) {
+ outl ( reg, efab->iobase + FCN_IOM_IND_ADR_REG );
+ outl ( value, efab->iobase + FCN_IOM_IND_DAT_REG );
+}
+
+/* Read dword via the I/O BAR */
+static inline uint32_t _falcon_readl ( struct efab_nic *efab,
+ unsigned int reg ) {
+ outl ( reg, efab->iobase + FCN_IOM_IND_ADR_REG );
+ return inl ( efab->iobase + FCN_IOM_IND_DAT_REG );
+}
+
+#else /* FALCON_USE_IO_BAR */
+
+#define _falcon_writel( efab, value, reg ) \
+ writel ( (value), (efab)->membase + (reg) )
+#define _falcon_readl( efab, reg ) readl ( (efab)->membase + (reg) )
+
+#endif /* FALCON_USE_IO_BAR */
+
+/**
+ * Write to a Falcon register
+ *
+ */
+static inline void falcon_write ( struct efab_nic *efab, efab_oword_t *value,
+ unsigned int reg ) {
+
+ EFAB_REGDUMP ( "Writing register %x with " EFAB_OWORD_FMT "\n",
+ reg, EFAB_OWORD_VAL ( *value ) );
+
+ _falcon_writel ( efab, value->u32[0], reg + 0 );
+ _falcon_writel ( efab, value->u32[1], reg + 4 );
+ _falcon_writel ( efab, value->u32[2], reg + 8 );
+ _falcon_writel ( efab, value->u32[3], reg + 12 );
+ wmb();
+}
+
+/**
+ * Write to Falcon SRAM
+ *
+ */
+static inline void falcon_write_sram ( struct efab_nic *efab,
+ efab_qword_t *value,
+ unsigned int index ) {
+ unsigned int reg = ( FCN_BUF_FULL_TBL_KER +
+ ( index * sizeof ( *value ) ) );
+
+ EFAB_REGDUMP ( "Writing SRAM register %x with " EFAB_QWORD_FMT "\n",
+ reg, EFAB_QWORD_VAL ( *value ) );
+
+ _falcon_writel ( efab, value->u32[0], reg + 0 );
+ _falcon_writel ( efab, value->u32[1], reg + 4 );
+ wmb();
+}
+
+/**
+ * Write dword to Falcon register that allows partial writes
+ *
+ */
+static inline void falcon_writel ( struct efab_nic *efab, efab_dword_t *value,
+ unsigned int reg ) {
+ EFAB_REGDUMP ( "Writing partial register %x with " EFAB_DWORD_FMT "\n",
+ reg, EFAB_DWORD_VAL ( *value ) );
+ _falcon_writel ( efab, value->u32[0], reg );
+}
+
+/**
+ * Read from a Falcon register
+ *
+ */
+static inline void falcon_read ( struct efab_nic *efab, efab_oword_t *value,
+ unsigned int reg ) {
+ value->u32[0] = _falcon_readl ( efab, reg + 0 );
+ value->u32[1] = _falcon_readl ( efab, reg + 4 );
+ value->u32[2] = _falcon_readl ( efab, reg + 8 );
+ value->u32[3] = _falcon_readl ( efab, reg + 12 );
+
+ EFAB_REGDUMP ( "Read from register %x, got " EFAB_OWORD_FMT "\n",
+ reg, EFAB_OWORD_VAL ( *value ) );
+}
+
+/**
+ * Read from Falcon SRAM
+ *
+ */
+static inline void falcon_read_sram ( struct efab_nic *efab,
+ efab_qword_t *value,
+ unsigned int index ) {
+ unsigned int reg = ( FCN_BUF_FULL_TBL_KER +
+ ( index * sizeof ( *value ) ) );
+
+ value->u32[0] = _falcon_readl ( efab, reg + 0 );
+ value->u32[1] = _falcon_readl ( efab, reg + 4 );
+ EFAB_REGDUMP ( "Read from SRAM register %x, got " EFAB_QWORD_FMT "\n",
+ reg, EFAB_QWORD_VAL ( *value ) );
+}
+
+/**
+ * Read dword from a portion of a Falcon register
+ *
+ */
+static inline void falcon_readl ( struct efab_nic *efab, efab_dword_t *value,
+ unsigned int reg ) {
+ value->u32[0] = _falcon_readl ( efab, reg );
+ EFAB_REGDUMP ( "Read from register %x, got " EFAB_DWORD_FMT "\n",
+ reg, EFAB_DWORD_VAL ( *value ) );
+}
+
+/**
+ * Verified write to Falcon SRAM
+ *
+ */
+static inline void falcon_write_sram_verify ( struct efab_nic *efab,
+ efab_qword_t *value,
+ unsigned int index ) {
+ efab_qword_t verify;
+
+ falcon_write_sram ( efab, value, index );
+ udelay ( 1000 );
+ falcon_read_sram ( efab, &verify, index );
+ if ( memcmp ( &verify, value, sizeof ( verify ) ) != 0 ) {
+ printf ( "SRAM index %x failure: wrote " EFAB_QWORD_FMT
+ " got " EFAB_QWORD_FMT "\n", index,
+ EFAB_QWORD_VAL ( *value ),
+ EFAB_QWORD_VAL ( verify ) );
+ }
+}
+
+/**
+ * Get memory base
+ *
+ */
+static void falcon_get_membase ( struct efab_nic *efab ) {
+ unsigned long membase_phys;
+
+ membase_phys = pci_bar_start ( efab->pci, PCI_BASE_ADDRESS_2 );
+ efab->membase = ioremap ( membase_phys, 0x20000 );
+}
+
+#define FCN_DUMP_REG( efab, _reg ) do { \
+ efab_oword_t reg; \
+ falcon_read ( efab, &reg, _reg ); \
+ printf ( #_reg " = " EFAB_OWORD_FMT "\n", \
+ EFAB_OWORD_VAL ( reg ) ); \
+ } while ( 0 );
+
+#define FCN_DUMP_MAC_REG( efab, _mac_reg ) do { \
+ efab_dword_t reg; \
+ efab->op->mac_readl ( efab, &reg, _mac_reg ); \
+ printf ( #_mac_reg " = " EFAB_DWORD_FMT "\n", \
+ EFAB_DWORD_VAL ( reg ) ); \
+ } while ( 0 );
+
+/**
+ * Dump register contents (for debugging)
+ *
+ * Marked as static inline so that it will not be compiled in if not
+ * used.
+ */
+static inline void falcon_dump_regs ( struct efab_nic *efab ) {
+ FCN_DUMP_REG ( efab, FCN_INT_EN_REG_KER );
+ FCN_DUMP_REG ( efab, FCN_INT_ADR_REG_KER );
+ FCN_DUMP_REG ( efab, FCN_GLB_CTL_REG_KER );
+ FCN_DUMP_REG ( efab, FCN_TIMER_CMD_REG_KER );
+ FCN_DUMP_REG ( efab, FCN_SRM_RX_DC_CFG_REG_KER );
+ FCN_DUMP_REG ( efab, FCN_SRM_TX_DC_CFG_REG_KER );
+ FCN_DUMP_REG ( efab, FCN_RX_FILTER_CTL_REG_KER );
+ FCN_DUMP_REG ( efab, FCN_RX_DC_CFG_REG_KER );
+ FCN_DUMP_REG ( efab, FCN_TX_DC_CFG_REG_KER );
+ FCN_DUMP_REG ( efab, FCN_MAC0_CTRL_REG_KER );
+ FCN_DUMP_REG ( efab, FCN_MAC1_CTRL_REG_KER );
+ FCN_DUMP_REG ( efab, FCN_XM_GLB_CFG_REG_P0_KER );
+ FCN_DUMP_REG ( efab, FCN_XM_TX_CFG_REG_P0_KER );
+ FCN_DUMP_REG ( efab, FCN_XM_RX_CFG_REG_P0_KER );
+ FCN_DUMP_REG ( efab, FCN_RX_DESC_PTR_TBL_KER );
+ FCN_DUMP_REG ( efab, FCN_TX_DESC_PTR_TBL_KER );
+ FCN_DUMP_REG ( efab, FCN_EVQ_PTR_TBL_KER );
+ FCN_DUMP_MAC_REG ( efab, GM_CFG1_REG_MAC );
+ FCN_DUMP_MAC_REG ( efab, GM_CFG2_REG_MAC );
+ FCN_DUMP_MAC_REG ( efab, GM_MAX_FLEN_REG_MAC );
+ FCN_DUMP_MAC_REG ( efab, GM_MII_MGMT_CFG_REG_MAC );
+ FCN_DUMP_MAC_REG ( efab, GM_ADR1_REG_MAC );
+ FCN_DUMP_MAC_REG ( efab, GM_ADR2_REG_MAC );
+ FCN_DUMP_MAC_REG ( efab, GMF_CFG0_REG_MAC );
+ FCN_DUMP_MAC_REG ( efab, GMF_CFG1_REG_MAC );
+ FCN_DUMP_MAC_REG ( efab, GMF_CFG2_REG_MAC );
+ FCN_DUMP_MAC_REG ( efab, GMF_CFG3_REG_MAC );
+ FCN_DUMP_MAC_REG ( efab, GMF_CFG4_REG_MAC );
+ FCN_DUMP_MAC_REG ( efab, GMF_CFG5_REG_MAC );
+}
+
+/**
+ * Create special buffer
+ *
+ */
+static void falcon_create_special_buffer ( struct efab_nic *efab,
+ void *addr, unsigned int index ) {
+ efab_qword_t buf_desc;
+ unsigned long dma_addr;
+
+ memset ( addr, 0, 4096 );
+ dma_addr = virt_to_bus ( addr );
+ EFAB_ASSERT ( ( dma_addr & ( EFAB_BUF_ALIGN - 1 ) ) == 0 );
+ EFAB_POPULATE_QWORD_3 ( buf_desc,
+ FCN_IP_DAT_BUF_SIZE, FCN_IP_DAT_BUF_SIZE_4K,
+ FCN_BUF_ADR_FBUF, ( dma_addr >> 12 ),
+ FCN_BUF_OWNER_ID_FBUF, 0 );
+ falcon_write_sram_verify ( efab, &buf_desc, index );
+}
+
+/**
+ * Update event queue read pointer
+ *
+ */
+static void falcon_eventq_read_ack ( struct efab_nic *efab ) {
+ efab_dword_t reg;
+
+ EFAB_ASSERT ( efab->eventq_read_ptr < EFAB_EVQ_SIZE );
+
+ EFAB_POPULATE_DWORD_1 ( reg, FCN_EVQ_RPTR_DWORD,
+ efab->eventq_read_ptr );
+ falcon_writel ( efab, &reg, FCN_EVQ_RPTR_REG_KER_DWORD );
+}
+
+/**
+ * Reset device
+ *
+ */
+static int falcon_reset ( struct efab_nic *efab ) {
+ efab_oword_t glb_ctl_reg_ker;
+
+ /* Initiate software reset */
+ EFAB_POPULATE_OWORD_5 ( glb_ctl_reg_ker,
+ FCN_EXT_PHY_RST_CTL, FCN_EXCLUDE_FROM_RESET,
+ FCN_PCIE_SD_RST_CTL, FCN_EXCLUDE_FROM_RESET,
+ FCN_PCIX_RST_CTL, FCN_EXCLUDE_FROM_RESET,
+ FCN_INT_RST_DUR, 0x7 /* datasheet */,
+ FCN_SWRST, 1 );
+ falcon_write ( efab, &glb_ctl_reg_ker, FCN_GLB_CTL_REG_KER );
+
+ /* Allow 20ms for reset */
+ mdelay ( 20 );
+
+ /* Check for device reset complete */
+ falcon_read ( efab, &glb_ctl_reg_ker, FCN_GLB_CTL_REG_KER );
+ if ( EFAB_OWORD_FIELD ( glb_ctl_reg_ker, FCN_SWRST ) != 0 ) {
+ printf ( "Reset failed\n" );
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * Initialise NIC
+ *
+ */
+static int falcon_init_nic ( struct efab_nic *efab ) {
+ efab_oword_t reg;
+ efab_dword_t timer_cmd;
+
+ /* Set up TX and RX descriptor caches in SRAM */
+ EFAB_POPULATE_OWORD_1 ( reg, FCN_SRM_TX_DC_BASE_ADR,
+ 0x130000 /* recommended in datasheet */ );
+ falcon_write ( efab, &reg, FCN_SRM_TX_DC_CFG_REG_KER );
+ EFAB_POPULATE_OWORD_1 ( reg, FCN_TX_DC_SIZE, 2 /* 32 descriptors */ );
+ falcon_write ( efab, &reg, FCN_TX_DC_CFG_REG_KER );
+ EFAB_POPULATE_OWORD_1 ( reg, FCN_SRM_RX_DC_BASE_ADR,
+ 0x100000 /* recommended in datasheet */ );
+ falcon_write ( efab, &reg, FCN_SRM_RX_DC_CFG_REG_KER );
+ EFAB_POPULATE_OWORD_1 ( reg, FCN_RX_DC_SIZE, 2 /* 32 descriptors */ );
+ falcon_write ( efab, &reg, FCN_RX_DC_CFG_REG_KER );
+
+ /* Set number of RSS CPUs */
+ EFAB_POPULATE_OWORD_1 ( reg, FCN_NUM_KER, 0 );
+ falcon_write ( efab, &reg, FCN_RX_FILTER_CTL_REG_KER );
+ udelay ( 1000 );
+
+ /* Reset the MAC */
+ mentormac_reset ( efab, 1 );
+ /* Take MAC out of reset */
+ mentormac_reset ( efab, 0 );
+
+ /* Set up event queue */
+ falcon_create_special_buffer ( efab, efab->eventq, FALCON_EVQ_ID );
+ EFAB_POPULATE_OWORD_3 ( reg,
+ FCN_EVQ_EN, 1,
+ FCN_EVQ_SIZE, FCN_EVQ_SIZE_512,
+ FCN_EVQ_BUF_BASE_ID, FALCON_EVQ_ID );
+ falcon_write ( efab, &reg, FCN_EVQ_PTR_TBL_KER );
+ udelay ( 1000 );
+
+ /* Set timer register */
+ EFAB_POPULATE_DWORD_2 ( timer_cmd,
+ FCN_TIMER_MODE, FCN_TIMER_MODE_DIS,
+ FCN_TIMER_VAL, 0 );
+ falcon_writel ( efab, &timer_cmd, FCN_TIMER_CMD_REG_KER );
+ udelay ( 1000 );
+
+ /* Initialise event queue read pointer */
+ falcon_eventq_read_ack ( efab );
+
+ /* Set up TX descriptor ring */
+ falcon_create_special_buffer ( efab, efab->txd, FALCON_TXD_ID );
+ EFAB_POPULATE_OWORD_5 ( reg,
+ FCN_TX_DESCQ_EN, 1,
+ FCN_TX_DESCQ_BUF_BASE_ID, FALCON_TXD_ID,
+ FCN_TX_DESCQ_EVQ_ID, 0,
+ FCN_TX_DESCQ_SIZE, FCN_TX_DESCQ_SIZE_512,
+ FCN_TX_DESCQ_TYPE, 0 /* kernel queue */ );
+ falcon_write ( efab, &reg, FCN_TX_DESC_PTR_TBL_KER );
+
+ /* Set up RX descriptor ring */
+ falcon_create_special_buffer ( efab, efab->rxd, FALCON_RXD_ID );
+ EFAB_POPULATE_OWORD_6 ( reg,
+ FCN_RX_DESCQ_BUF_BASE_ID, FALCON_RXD_ID,
+ FCN_RX_DESCQ_EVQ_ID, 0,
+ FCN_RX_DESCQ_SIZE, FCN_RX_DESCQ_SIZE_512,
+ FCN_RX_DESCQ_TYPE, 0 /* kernel queue */,
+ FCN_RX_DESCQ_JUMBO, 1,
+ FCN_RX_DESCQ_EN, 1 );
+ falcon_write ( efab, &reg, FCN_RX_DESC_PTR_TBL_KER );
+
+ /* Program INT_ADR_REG_KER */
+ EFAB_POPULATE_OWORD_1 ( reg,
+ FCN_INT_ADR_KER,
+ virt_to_bus ( &efab->int_ker ) );
+ falcon_write ( efab, &reg, FCN_INT_ADR_REG_KER );
+ udelay ( 1000 );
+
+ return 1;
+}
+
+/** SPI device */
+struct efab_spi_device {
+ /** Device ID */
+ unsigned int device_id;
+ /** Address length (in bytes) */
+ unsigned int addr_len;
+ /** Read command */
+ unsigned int read_command;
+};
+
+/**
+ * Wait for SPI command completion
+ *
+ */
+static int falcon_spi_wait ( struct efab_nic *efab ) {
+ efab_oword_t reg;
+ int count;
+
+ count = 0;
+ do {
+ udelay ( 100 );
+ falcon_read ( efab, &reg, FCN_EE_SPI_HCMD_REG_KER );
+ if ( EFAB_OWORD_FIELD ( reg, FCN_EE_SPI_HCMD_CMD_EN ) == 0 )
+ return 1;
+ } while ( ++count < 1000 );
+ printf ( "Timed out waiting for SPI\n" );
+ return 0;
+}
+
+/**
+ * Perform SPI read
+ *
+ */
+static int falcon_spi_read ( struct efab_nic *efab,
+ struct efab_spi_device *spi,
+ int address, void *data, unsigned int len ) {
+ efab_oword_t reg;
+
+ /* Program address register */
+ EFAB_POPULATE_OWORD_1 ( reg, FCN_EE_SPI_HADR_ADR, address );
+ falcon_write ( efab, &reg, FCN_EE_SPI_HADR_REG_KER );
+
+ /* Issue read command */
+ EFAB_POPULATE_OWORD_7 ( reg,
+ FCN_EE_SPI_HCMD_CMD_EN, 1,
+ FCN_EE_SPI_HCMD_SF_SEL, spi->device_id,
+ FCN_EE_SPI_HCMD_DABCNT, len,
+ FCN_EE_SPI_HCMD_READ, FCN_EE_SPI_READ,
+ FCN_EE_SPI_HCMD_DUBCNT, 0,
+ FCN_EE_SPI_HCMD_ADBCNT, spi->addr_len,
+ FCN_EE_SPI_HCMD_ENC, spi->read_command );
+ falcon_write ( efab, &reg, FCN_EE_SPI_HCMD_REG_KER );
+
+ /* Wait for read to complete */
+ if ( ! falcon_spi_wait ( efab ) )
+ return 0;
+
+ /* Read data */
+ falcon_read ( efab, &reg, FCN_EE_SPI_HDATA_REG_KER );
+ memcpy ( data, &reg, len );
+
+ return 1;
+}
+
+#define SPI_READ_CMD 0x03
+#define AT25F1024_ADDR_LEN 3
+#define AT25F1024_READ_CMD SPI_READ_CMD
+#define MC25XX640_ADDR_LEN 2
+#define MC25XX640_READ_CMD SPI_READ_CMD
+
+/** Falcon Flash SPI device */
+static struct efab_spi_device falcon_spi_flash = {
+ .device_id = FCN_EE_SPI_FLASH,
+ .addr_len = AT25F1024_ADDR_LEN,
+ .read_command = AT25F1024_READ_CMD,
+};
+
+/** Falcon EEPROM SPI device */
+static struct efab_spi_device falcon_spi_large_eeprom = {
+ .device_id = FCN_EE_SPI_EEPROM,
+ .addr_len = MC25XX640_ADDR_LEN,
+ .read_command = MC25XX640_READ_CMD,
+};
+
+/** Offset of MAC address within EEPROM or Flash */
+#define FALCON_MAC_ADDRESS_OFFSET(port) ( 0x310 + 0x08 * (port) )
+
+/**
+ * Read MAC address from EEPROM
+ *
+ */
+static int falcon_read_eeprom ( struct efab_nic *efab ) {
+ efab_oword_t reg;
+ int has_flash;
+ struct efab_spi_device *spi;
+
+ /* Determine the SPI device containing the MAC address */
+ falcon_read ( efab, &reg, FCN_GPIO_CTL_REG_KER );
+ has_flash = EFAB_OWORD_FIELD ( reg, FCN_FLASH_PRESENT );
+ spi = has_flash ? &falcon_spi_flash : &falcon_spi_large_eeprom;
+
+ return falcon_spi_read ( efab, spi,
+ FALCON_MAC_ADDRESS_OFFSET ( efab->port ),
+ efab->mac_addr, sizeof ( efab->mac_addr ) );
+}
+
+/** RX descriptor */
+typedef efab_qword_t falcon_rx_desc_t;
+
+/**
+ * Build RX descriptor
+ *
+ */
+static void falcon_build_rx_desc ( struct efab_nic *efab,
+ struct efab_rx_buf *rx_buf ) {
+ falcon_rx_desc_t *rxd;
+
+ rxd = ( ( falcon_rx_desc_t * ) efab->rxd ) + rx_buf->id;
+ EFAB_POPULATE_QWORD_2 ( *rxd,
+ FCN_RX_KER_BUF_SIZE, EFAB_DATA_BUF_SIZE,
+ FCN_RX_KER_BUF_ADR,
+ virt_to_bus ( rx_buf->addr ) );
+}
+
+/**
+ * Update RX descriptor write pointer
+ *
+ */
+static void falcon_notify_rx_desc ( struct efab_nic *efab ) {
+ efab_dword_t reg;
+
+ EFAB_POPULATE_DWORD_1 ( reg, FCN_RX_DESC_WPTR_DWORD,
+ efab->rx_write_ptr );
+ falcon_writel ( efab, &reg, FCN_RX_DESC_UPD_REG_KER_DWORD );
+}
+
+/** TX descriptor */
+typedef efab_qword_t falcon_tx_desc_t;
+
+/**
+ * Build TX descriptor
+ *
+ */
+static void falcon_build_tx_desc ( struct efab_nic *efab,
+ struct efab_tx_buf *tx_buf ) {
+ falcon_rx_desc_t *txd;
+
+ txd = ( ( falcon_rx_desc_t * ) efab->txd ) + tx_buf->id;
+ EFAB_POPULATE_QWORD_3 ( *txd,
+ FCN_TX_KER_PORT, efab->port,
+ FCN_TX_KER_BYTE_CNT, tx_buf->len,
+ FCN_TX_KER_BUF_ADR,
+ virt_to_bus ( tx_buf->addr ) );
+}
+
+/**
+ * Update TX descriptor write pointer
+ *
+ */
+static void falcon_notify_tx_desc ( struct efab_nic *efab ) {
+ efab_dword_t reg;
+
+ EFAB_POPULATE_DWORD_1 ( reg, FCN_TX_DESC_WPTR_DWORD,
+ efab->tx_write_ptr );
+ falcon_writel ( efab, &reg, FCN_TX_DESC_UPD_REG_KER_DWORD );
+}
+
+/** An event */
+typedef efab_qword_t falcon_event_t;
+
+/**
+ * Retrieve event from event queue
+ *
+ */
+static int falcon_fetch_event ( struct efab_nic *efab,
+ struct efab_event *event ) {
+ falcon_event_t *evt;
+ int ev_code;
+ int rx_port;
+
+ /* Check for event */
+ evt = ( ( falcon_event_t * ) efab->eventq ) + efab->eventq_read_ptr;
+ if ( EFAB_QWORD_IS_ZERO ( *evt ) ) {
+ /* No event */
+ return 0;
+ }
+
+ DBG ( "Event is " EFAB_QWORD_FMT "\n", EFAB_QWORD_VAL ( *evt ) );
+
+ /* Decode event */
+ ev_code = EFAB_QWORD_FIELD ( *evt, FCN_EV_CODE );
+ switch ( ev_code ) {
+ case FCN_TX_IP_EV_DECODE:
+ event->type = EFAB_EV_TX;
+ break;
+ case FCN_RX_IP_EV_DECODE:
+ event->type = EFAB_EV_RX;
+ event->rx_id = EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_DESC_PTR );
+ event->rx_len = EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_BYTE_CNT );
+ rx_port = EFAB_QWORD_FIELD ( *evt, FCN_RX_PORT );
+ if ( rx_port != efab->port ) {
+ /* Ignore packets on the wrong port. We can't
+ * just set event->type = EFAB_EV_NONE,
+ * because then the descriptor ring won't get
+ * refilled.
+ */
+ event->rx_len = 0;
+ }
+ break;
+ case FCN_DRIVER_EV_DECODE:
+ /* Ignore start-of-day events */
+ event->type = EFAB_EV_NONE;
+ break;
+ default:
+ printf ( "Unknown event type %d\n", ev_code );
+ event->type = EFAB_EV_NONE;
+ }
+
+ /* Clear event and any pending interrupts */
+ EFAB_ZERO_QWORD ( *evt );
+ falcon_writel ( efab, 0, FCN_INT_ACK_KER_REG );
+ udelay ( 10 );
+
+ /* Increment and update event queue read pointer */
+ efab->eventq_read_ptr = ( ( efab->eventq_read_ptr + 1 )
+ % EFAB_EVQ_SIZE );
+ falcon_eventq_read_ack ( efab );
+
+ return 1;
+}
+
+/**
+ * Enable/disable/generate interrupt
+ *
+ */
+static inline void falcon_interrupts ( struct efab_nic *efab, int enabled,
+ int force ) {
+ efab_oword_t int_en_reg_ker;
+
+ EFAB_POPULATE_OWORD_2 ( int_en_reg_ker,
+ FCN_KER_INT_KER, force,
+ FCN_DRV_INT_EN_KER, enabled );
+ falcon_write ( efab, &int_en_reg_ker, FCN_INT_EN_REG_KER );
+}
+
+/**
+ * Enable/disable interrupts
+ *
+ */
+static void falcon_mask_irq ( struct efab_nic *efab, int enabled ) {
+ falcon_interrupts ( efab, enabled, 0 );
+ if ( enabled ) {
+ /* Events won't trigger interrupts until we do this */
+ falcon_eventq_read_ack ( efab );
+ }
+}
+
+/**
+ * Generate interrupt
+ *
+ */
+static void falcon_generate_irq ( struct efab_nic *efab ) {
+ falcon_interrupts ( efab, 1, 1 );
+}
+
+/**
+ * Write dword to a Falcon MAC register
+ *
+ */
+static void falcon_mac_writel ( struct efab_nic *efab,
+ efab_dword_t *value, unsigned int mac_reg ) {
+ efab_oword_t temp;
+
+ EFAB_POPULATE_OWORD_1 ( temp, FCN_MAC_DATA,
+ EFAB_DWORD_FIELD ( *value, FCN_MAC_DATA ) );
+ falcon_write ( efab, &temp, FALCON_MAC_REG ( efab, mac_reg ) );
+}
+
+/**
+ * Read dword from a Falcon MAC register
+ *
+ */
+static void falcon_mac_readl ( struct efab_nic *efab, efab_dword_t *value,
+ unsigned int mac_reg ) {
+ efab_oword_t temp;
+
+ falcon_read ( efab, &temp, FALCON_MAC_REG ( efab, mac_reg ) );
+ EFAB_POPULATE_DWORD_1 ( *value, FCN_MAC_DATA,
+ EFAB_OWORD_FIELD ( temp, FCN_MAC_DATA ) );
+}
+
+/**
+ * Initialise MAC
+ *
+ */
+static int falcon_init_mac ( struct efab_nic *efab ) {
+ static struct efab_mentormac_parameters falcon_mentormac_params = {
+ .gmf_cfgfrth = 0x12,
+ .gmf_cfgftth = 0x08,
+ .gmf_cfghwmft = 0x1c,
+ .gmf_cfghwm = 0x3f,
+ .gmf_cfglwm = 0xa,
+ };
+ efab_oword_t reg;
+ int link_speed;
+
+ /* Initialise PHY */
+ alaska_init ( efab );
+
+ /* Initialise MAC */
+ mentormac_init ( efab, &falcon_mentormac_params );
+
+ /* Configure the Falcon MAC wrapper */
+ EFAB_POPULATE_OWORD_4 ( reg,
+ FCN_XM_RX_JUMBO_MODE, 0,
+ FCN_XM_CUT_THRU_MODE, 0,
+ FCN_XM_TX_STAT_EN, 1,
+ FCN_XM_RX_STAT_EN, 1);
+ falcon_write ( efab, &reg, FCN_XM_GLB_CFG_REG_P0_KER );
+
+ EFAB_POPULATE_OWORD_6 ( reg,
+ FCN_XM_TXEN, 1,
+ FCN_XM_TX_PRMBL, 1,
+ FCN_XM_AUTO_PAD, 1,
+ FCN_XM_TXCRC, 1,
+ FCN_XM_WTF_DOES_THIS_DO, 1,
+ FCN_XM_IPG, 0x3 );
+ falcon_write ( efab, &reg, FCN_XM_TX_CFG_REG_P0_KER );
+
+ EFAB_POPULATE_OWORD_3 ( reg,
+ FCN_XM_RXEN, 1,
+ FCN_XM_AUTO_DEPAD, 1,
+ FCN_XM_PASS_CRC_ERR, 1 );
+ falcon_write ( efab, &reg, FCN_XM_RX_CFG_REG_P0_KER );
+
+#warning "10G support not yet present"
+#define LPA_10000 0
+ if ( efab->link_options & LPA_10000 ) {
+ link_speed = 0x3;
+ } else if ( efab->link_options & LPA_1000 ) {
+ link_speed = 0x2;
+ } else if ( efab->link_options & LPA_100 ) {
+ link_speed = 0x1;
+ } else {
+ link_speed = 0x0;
+ }
+ EFAB_POPULATE_OWORD_5 ( reg,
+ FCN_MAC_XOFF_VAL, 0xffff /* datasheet */,
+ FCN_MAC_BCAD_ACPT, 1,
+ FCN_MAC_UC_PROM, 0,
+ FCN_MAC_LINK_STATUS, 1,
+ FCN_MAC_SPEED, link_speed );
+ falcon_write ( efab, &reg, ( efab->port == 0 ?
+ FCN_MAC0_CTRL_REG_KER : FCN_MAC1_CTRL_REG_KER ) );
+
+ return 1;
+}
+
+/**
+ * Wait for GMII access to complete
+ *
+ */
+static int falcon_gmii_wait ( struct efab_nic *efab ) {
+ efab_oword_t md_stat;
+ int count;
+
+ for ( count = 0 ; count < 1000 ; count++ ) {
+ udelay ( 10 );
+ falcon_read ( efab, &md_stat, FCN_MD_STAT_REG_KER );
+ if ( EFAB_OWORD_FIELD ( md_stat, FCN_MD_BSY ) == 0 )
+ return 1;
+ }
+ printf ( "Timed out waiting for GMII\n" );
+ return 0;
+}
+
+/** MDIO write */
+static void falcon_mdio_write ( struct efab_nic *efab, int location,
+ int value ) {
+ int phy_id = efab->port + 2;
+ efab_oword_t reg;
+
+#warning "10G PHY access not yet in place"
+
+ EFAB_TRACE ( "Writing GMII %d register %02x with %04x\n",
+ phy_id, location, value );
+
+ /* Check MII not currently being accessed */
+ if ( ! falcon_gmii_wait ( efab ) )
+ return;
+
+ /* Write the address registers */
+ EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_PHY_ADR, 0 /* phy_id ? */ );
+ falcon_write ( efab, &reg, FCN_MD_PHY_ADR_REG_KER );
+ udelay ( 10 );
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_PRT_ADR, phy_id,
+ FCN_MD_DEV_ADR, location );
+ falcon_write ( efab, &reg, FCN_MD_ID_REG_KER );
+ udelay ( 10 );
+
+ /* Write data */
+ EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_TXD, value );
+ falcon_write ( efab, &reg, FCN_MD_TXD_REG_KER );
+ udelay ( 10 );
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_WRC, 1,
+ FCN_MD_GC, 1 );
+ falcon_write ( efab, &reg, FCN_MD_CS_REG_KER );
+ udelay ( 10 );
+
+ /* Wait for data to be written */
+ falcon_gmii_wait ( efab );
+}
+
+/** MDIO read */
+static int falcon_mdio_read ( struct efab_nic *efab, int location ) {
+ int phy_id = efab->port + 2;
+ efab_oword_t reg;
+ int value;
+
+ /* Check MII not currently being accessed */
+ if ( ! falcon_gmii_wait ( efab ) )
+ return 0xffff;
+
+ /* Write the address registers */
+ EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_PHY_ADR, 0 /* phy_id ? */ );
+ falcon_write ( efab, &reg, FCN_MD_PHY_ADR_REG_KER );
+ udelay ( 10 );
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_PRT_ADR, phy_id,
+ FCN_MD_DEV_ADR, location );
+ falcon_write ( efab, &reg, FCN_MD_ID_REG_KER );
+ udelay ( 10 );
+
+ /* Request data to be read */
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_RIC, 1,
+ FCN_MD_GC, 1 );
+ falcon_write ( efab, &reg, FCN_MD_CS_REG_KER );
+ udelay ( 10 );
+
+ /* Wait for data to become available */
+ falcon_gmii_wait ( efab );
+
+ /* Read the data */
+ falcon_read ( efab, &reg, FCN_MD_RXD_REG_KER );
+ value = EFAB_OWORD_FIELD ( reg, FCN_MD_RXD );
+
+ EFAB_TRACE ( "Read from GMII %d register %02x, got %04x\n",
+ phy_id, location, value );
+
+ return value;
+}
+
+static struct efab_operations falcon_operations = {
+ .get_membase = falcon_get_membase,
+ .reset = falcon_reset,
+ .init_nic = falcon_init_nic,
+ .read_eeprom = falcon_read_eeprom,
+ .build_rx_desc = falcon_build_rx_desc,
+ .notify_rx_desc = falcon_notify_rx_desc,
+ .build_tx_desc = falcon_build_tx_desc,
+ .notify_tx_desc = falcon_notify_tx_desc,
+ .fetch_event = falcon_fetch_event,
+ .mask_irq = falcon_mask_irq,
+ .generate_irq = falcon_generate_irq,
+ .mac_writel = falcon_mac_writel,
+ .mac_readl = falcon_mac_readl,
+ .init_mac = falcon_init_mac,
+ .mdio_write = falcon_mdio_write,
+ .mdio_read = falcon_mdio_read,
+};
+
+/**************************************************************************
+ *
+ * Etherfabric abstraction layer
+ *
+ **************************************************************************
+ */
+
+/**
+ * Push RX buffer to RXD ring
+ *
+ */
+static inline void efab_push_rx_buffer ( struct efab_nic *efab,
+ struct efab_rx_buf *rx_buf ) {
+ /* Create RX descriptor */
+ rx_buf->id = efab->rx_write_ptr;
+ efab->op->build_rx_desc ( efab, rx_buf );
+
+ /* Update RX write pointer */
+ efab->rx_write_ptr = ( efab->rx_write_ptr + 1 ) % EFAB_RXD_SIZE;
+ efab->op->notify_rx_desc ( efab );
+
+ DBG ( "Added RX id %x\n", rx_buf->id );
+}
+
+/**
+ * Push TX buffer to TXD ring
+ *
+ */
+static inline void efab_push_tx_buffer ( struct efab_nic *efab,
+ struct efab_tx_buf *tx_buf ) {
+ /* Create TX descriptor */
+ tx_buf->id = efab->tx_write_ptr;
+ efab->op->build_tx_desc ( efab, tx_buf );
+
+ /* Update TX write pointer */
+ efab->tx_write_ptr = ( efab->tx_write_ptr + 1 ) % EFAB_TXD_SIZE;
+ efab->op->notify_tx_desc ( efab );
+
+ DBG ( "Added TX id %x\n", tx_buf->id );
+}
+
+/**
+ * Initialise MAC and wait for link up
+ *
+ */
+static int efab_init_mac ( struct efab_nic *efab ) {
+ int count;
+
+ /* This can take several seconds */
+ printf ( "Waiting for link.." );
+ count = 0;
+ do {
+ putchar ( '.' );
+ if ( ! efab->op->init_mac ( efab ) ) {
+ printf ( "failed\n" );
+ return 0;
+ }
+ if ( efab->link_up ) {
+ /* PHY init printed the message for us */
+ return 1;
+ }
+ sleep ( 1 );
+ } while ( ++count < 5 );
+ printf ( "timed out\n" );
+
+ return 0;
+}
+
+/**
+ * Initialise NIC
+ *
+ */
+static int efab_init_nic ( struct efab_nic *efab ) {
+ int i;
+
+ /* Reset NIC */
+ if ( ! efab->op->reset ( efab ) )
+ return 0;
+
+ /* Initialise NIC */
+ if ( ! efab->op->init_nic ( efab ) )
+ return 0;
+
+ /* Push RX descriptors */
+ for ( i = 0 ; i < EFAB_RX_BUFS ; i++ ) {
+ efab_push_rx_buffer ( efab, &efab->rx_bufs[i] );
+ }
+
+ /* Read MAC address from EEPROM */
+ if ( ! efab->op->read_eeprom ( efab ) )
+ return 0;
+ efab->mac_addr[ETH_ALEN-1] += efab->port;
+
+ /* Initialise MAC and wait for link up */
+ if ( ! efab_init_mac ( efab ) )
+ return 0;
+
+ return 1;
+}
+
+/**************************************************************************
+ *
+ * Etherboot interface
+ *
+ **************************************************************************
+ */
+
+/**************************************************************************
+POLL - Wait for a frame
+***************************************************************************/
+static int etherfabric_poll ( struct nic *nic, int retrieve ) {
+ struct efab_nic *efab = nic->priv_data;
+ struct efab_event event;
+ static struct efab_rx_buf *rx_buf = NULL;
+ int i;
+
+ /* Process the event queue until we hit either a packet
+ * received event or an empty event slot.
+ */
+ while ( ( rx_buf == NULL ) &&
+ efab->op->fetch_event ( efab, &event ) ) {
+ if ( event.type == EFAB_EV_TX ) {
+ /* TX completed - mark as done */
+ DBG ( "TX id %x complete\n",
+ efab->tx_buf.id );
+ efab->tx_in_progress = 0;
+ } else if ( event.type == EFAB_EV_RX ) {
+ /* RX - find corresponding buffer */
+ for ( i = 0 ; i < EFAB_RX_BUFS ; i++ ) {
+ if ( efab->rx_bufs[i].id == event.rx_id ) {
+ rx_buf = &efab->rx_bufs[i];
+ rx_buf->len = event.rx_len;
+ DBG ( "RX id %x (len %x) received\n",
+ rx_buf->id, rx_buf->len );
+ break;
+ }
+ }
+ if ( ! rx_buf ) {
+ printf ( "Invalid RX ID %x\n", event.rx_id );
+ }
+ } else if ( event.type == EFAB_EV_NONE ) {
+ DBG ( "Ignorable event\n" );
+ } else {
+ DBG ( "Unknown event\n" );
+ }
+ }
+
+ /* If there is no packet, return 0 */
+ if ( ! rx_buf )
+ return 0;
+
+ /* If we don't want to retrieve it just yet, return 1 */
+ if ( ! retrieve )
+ return 1;
+
+ /* Copy packet contents */
+ nic->packetlen = rx_buf->len;
+ memcpy ( nic->packet, rx_buf->addr, nic->packetlen );
+
+ /* Give this buffer back to the NIC */
+ efab_push_rx_buffer ( efab, rx_buf );
+
+ /* Prepare to receive next packet */
+ rx_buf = NULL;
+
+ return 1;
+}
+
+/**************************************************************************
+TRANSMIT - Transmit a frame
+***************************************************************************/
+static void etherfabric_transmit ( struct nic *nic, const char *dest,
+ unsigned int type, unsigned int size,
+ const char *data ) {
+ struct efab_nic *efab = nic->priv_data;
+ unsigned int nstype = htons ( type );
+
+ /* We can only transmit one packet at a time; a TX completion
+ * event must be received before we can transmit the next
+ * packet. Since there is only one static TX buffer, we don't
+ * worry unduly about overflow, but we report it anyway.
+ */
+ if ( efab->tx_in_progress ) {
+ printf ( "TX overflow!\n" );
+ }
+
+ /* Fill TX buffer, pad to ETH_ZLEN */
+ memcpy ( efab->tx_buf.addr, dest, ETH_ALEN );
+ memcpy ( efab->tx_buf.addr + ETH_ALEN, nic->node_addr, ETH_ALEN );
+ memcpy ( efab->tx_buf.addr + 2 * ETH_ALEN, &nstype, 2 );
+ memcpy ( efab->tx_buf.addr + ETH_HLEN, data, size );
+ size += ETH_HLEN;
+ while ( size < ETH_ZLEN ) {
+ efab->tx_buf.addr[size++] = '\0';
+ }
+ efab->tx_buf.len = size;
+
+ /* Push TX descriptor */
+ efab_push_tx_buffer ( efab, &efab->tx_buf );
+
+ /* There is no way to wait for TX complete (i.e. TX buffer
+ * available to re-use for the next transmit) without reading
+ * from the event queue. We therefore simply leave the TX
+ * buffer marked as "in use" until a TX completion event
+ * happens to be picked up by a call to etherfabric_poll().
+ */
+ efab->tx_in_progress = 1;
+
+ return;
+}
+
+/**************************************************************************
+DISABLE - Turn off ethernet interface
+***************************************************************************/
+static void etherfabric_disable ( struct dev *dev ) {
+ struct nic *nic = ( struct nic * ) dev;
+ struct efab_nic *efab = nic->priv_data;
+
+ efab->op->reset ( efab );
+ if ( efab->membase )
+ iounmap ( efab->membase );
+}
+
+/**************************************************************************
+IRQ - handle interrupts
+***************************************************************************/
+static void etherfabric_irq ( struct nic *nic, irq_action_t action ) {
+ struct efab_nic *efab = nic->priv_data;
+
+ switch ( action ) {
+ case DISABLE :
+ efab->op->mask_irq ( efab, 1 );
+ break;
+ case ENABLE :
+ efab->op->mask_irq ( efab, 0 );
+ break;
+ case FORCE :
+ /* Force NIC to generate a receive interrupt */
+ efab->op->generate_irq ( efab );
+ break;
+ }
+
+ return;
+}
+
+/**************************************************************************
+PROBE - Look for an adapter, this routine's visible to the outside
+***************************************************************************/
+static int etherfabric_probe ( struct dev *dev, struct pci_device *pci ) {
+ struct nic *nic = ( struct nic * ) dev;
+ static struct efab_nic efab;
+ static int nic_port = 1;
+ struct efab_buffers *buffers;
+ int i;
+
+ /* Set up our private data structure */
+ nic->priv_data = &efab;
+ memset ( &efab, 0, sizeof ( efab ) );
+ memset ( &efab_buffers, 0, sizeof ( efab_buffers ) );
+
+ /* Hook in appropriate operations table. Do this early. */
+ if ( pci->dev_id == EF1002_DEVID ) {
+ efab.op = &ef1002_operations;
+ } else {
+ efab.op = &falcon_operations;
+ }
+
+ /* Initialise efab data structure */
+ efab.pci = pci;
+ buffers = ( ( struct efab_buffers * )
+ ( ( ( void * ) &efab_buffers ) +
+ ( - virt_to_bus ( &efab_buffers ) ) % EFAB_BUF_ALIGN ) );
+ efab.eventq = buffers->eventq;
+ efab.txd = buffers->txd;
+ efab.rxd = buffers->rxd;
+ efab.tx_buf.addr = buffers->tx_buf;
+ for ( i = 0 ; i < EFAB_RX_BUFS ; i++ ) {
+ efab.rx_bufs[i].addr = buffers->rx_buf[i];
+ }
+
+ /* Enable the PCI device */
+ adjust_pci_device ( pci );
+ nic->ioaddr = pci->ioaddr & ~3;
+ nic->irqno = pci->irq;
+
+ /* Get iobase/membase */
+ efab.iobase = nic->ioaddr;
+ efab.op->get_membase ( &efab );
+
+ /* Switch NIC ports (i.e. try different ports on each probe) */
+ nic_port = 1 - nic_port;
+ efab.port = nic_port;
+
+ /* Initialise hardware */
+ if ( ! efab_init_nic ( &efab ) )
+ return 0;
+ memcpy ( nic->node_addr, efab.mac_addr, ETH_ALEN );
+
+ /* hello world */
+ printf ( "Found EtherFabric %s NIC %!\n", pci->name, nic->node_addr );
+
+ /* point to NIC specific routines */
+ dev->disable = etherfabric_disable;
+ nic->poll = etherfabric_poll;
+ nic->transmit = etherfabric_transmit;
+ nic->irq = etherfabric_irq;
+
+ return 1;
+}
+
+static struct pci_id etherfabric_nics[] = {
+PCI_ROM(0x1924, 0xC101, "ef1002", "EtherFabric EF1002"),
+PCI_ROM(0x1924, 0x0703, "falcon", "EtherFabric Falcon"),
+};
+
+static struct pci_driver etherfabric_driver __pci_driver = {
+ .type = NIC_DRIVER,
+ .name = "EFAB",
+ .probe = etherfabric_probe,
+ .ids = etherfabric_nics,
+ .id_count = sizeof(etherfabric_nics)/sizeof(etherfabric_nics[0]),
+ .class = 0,
+};
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * c-indent-level: 8
+ * tab-width: 8
+ * End:
+ */
diff --git a/src/drivers/net/etherfabric.h b/src/drivers/net/etherfabric.h
new file mode 100644
index 000000000..950f8de26
--- /dev/null
+++ b/src/drivers/net/etherfabric.h
@@ -0,0 +1,551 @@
+/**************************************************************************
+ *
+ * GPL net driver for Level 5 Etherfabric network cards
+ *
+ * Written by Michael Brown <mbrown@fensystems.co.uk>
+ *
+ * Copyright Fen Systems Ltd. 2005
+ * Copyright Level 5 Networks Inc. 2005
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL), incorporated herein by
+ * reference. Drivers based on or derived from this code fall under
+ * the GPL and must retain the authorship, copyright and license
+ * notice. This file is not a complete program and may only be used
+ * when the entire operating system is licensed under the GPL.
+ *
+ **************************************************************************
+ */
+
+#ifndef EFAB_BITFIELD_H
+#define EFAB_BITFIELD_H
+
+/** @file
+ *
+ * Etherfabric bitfield access
+ *
+ * Etherfabric NICs make extensive use of bitfields up to 128 bits
+ * wide. Since there is no native 128-bit datatype on most systems,
+ * and since 64-bit datatypes are inefficient on 32-bit systems and
+ * vice versa, we wrap accesses in a way that uses the most efficient
+ * datatype.
+ *
+ * The NICs are PCI devices and therefore little-endian. Since most
+ * of the quantities that we deal with are DMAed to/from host memory,
+ * we define our datatypes (efab_oword_t, efab_qword_t and
+ * efab_dword_t) to be little-endian.
+ *
+ * In the less common case of using PIO for individual register
+ * writes, we construct the little-endian datatype in host memory and
+ * then use non-swapping equivalents of writel/writeq, rather than
+ * constructing a native-endian datatype and relying on the implicit
+ * byte-swapping done by writel/writeq. (We use a similar strategy
+ * for register reads.)
+ */
+
+/** Dummy field low bit number */
+#define EFAB_DUMMY_FIELD_LBN 0
+/** Dummy field width */
+#define EFAB_DUMMY_FIELD_WIDTH 0
+/** Dword 0 low bit number */
+#define EFAB_DWORD_0_LBN 0
+/** Dword 0 width */
+#define EFAB_DWORD_0_WIDTH 32
+/** Dword 1 low bit number */
+#define EFAB_DWORD_1_LBN 32
+/** Dword 1 width */
+#define EFAB_DWORD_1_WIDTH 32
+/** Dword 2 low bit number */
+#define EFAB_DWORD_2_LBN 64
+/** Dword 2 width */
+#define EFAB_DWORD_2_WIDTH 32
+/** Dword 3 low bit number */
+#define EFAB_DWORD_3_LBN 96
+/** Dword 3 width */
+#define EFAB_DWORD_3_WIDTH 32
+
+/** Specified attribute (e.g. LBN) of the specified field */
+#define EFAB_VAL(field,attribute) field ## _ ## attribute
+/** Low bit number of the specified field */
+#define EFAB_LOW_BIT( field ) EFAB_VAL ( field, LBN )
+/** Bit width of the specified field */
+#define EFAB_WIDTH( field ) EFAB_VAL ( field, WIDTH )
+/** High bit number of the specified field */
+#define EFAB_HIGH_BIT(field) ( EFAB_LOW_BIT(field) + EFAB_WIDTH(field) - 1 )
+/** Mask equal in width to the specified field.
+ *
+ * For example, a field with width 5 would have a mask of 0x1f.
+ *
+ * The maximum width mask that can be generated is 64 bits.
+ */
+#define EFAB_MASK64( field ) \
+ ( EFAB_WIDTH(field) == 64 ? ~( ( uint64_t ) 0 ) : \
+ ( ( ( ( ( uint64_t ) 1 ) << EFAB_WIDTH(field) ) ) - 1 ) )
+
+/** Mask equal in width to the specified field.
+ *
+ * For example, a field with width 5 would have a mask of 0x1f.
+ *
+ * The maximum width mask that can be generated is 32 bits. Use
+ * EFAB_MASK64 for higher width fields.
+ */
+#define EFAB_MASK32( field ) \
+ ( EFAB_WIDTH(field) == 32 ? ~( ( uint32_t ) 0 ) : \
+ ( ( ( ( ( uint32_t ) 1 ) << EFAB_WIDTH(field) ) ) - 1 ) )
+
+/** A doubleword (i.e. 4 byte) datatype
+ *
+ * This datatype is defined to be little-endian.
+ */
+typedef union efab_dword {
+ uint32_t u32[1];
+ uint32_t opaque; /* For bitwise operations between two efab_dwords */
+} efab_dword_t;
+
+/** A quadword (i.e. 8 byte) datatype
+ *
+ * This datatype is defined to be little-endian.
+ */
+typedef union efab_qword {
+ uint64_t u64[1];
+ uint32_t u32[2];
+ efab_dword_t dword[2];
+} efab_qword_t;
+
+/**
+ * An octword (eight-word, i.e. 16 byte) datatype
+ *
+ * This datatype is defined to be little-endian.
+ */
+typedef union efab_oword {
+ uint64_t u64[2];
+ efab_qword_t qword[2];
+ uint32_t u32[4];
+ efab_dword_t dword[4];
+} efab_oword_t;
+
+/** Format string for printing an efab_dword_t */
+#define EFAB_DWORD_FMT "%08x"
+
+/** Format string for printing an efab_qword_t */
+#define EFAB_QWORD_FMT "%08x:%08x"
+
+/** Format string for printing an efab_oword_t */
+#define EFAB_OWORD_FMT "%08x:%08x:%08x:%08x"
+
+/** printk parameters for printing an efab_dword_t */
+#define EFAB_DWORD_VAL(dword) \
+ ( ( unsigned int ) le32_to_cpu ( (dword).u32[0] ) )
+
+/** printk parameters for printing an efab_qword_t */
+#define EFAB_QWORD_VAL(qword) \
+ ( ( unsigned int ) le32_to_cpu ( (qword).u32[1] ) ), \
+ ( ( unsigned int ) le32_to_cpu ( (qword).u32[0] ) )
+
+/** printk parameters for printing an efab_oword_t */
+#define EFAB_OWORD_VAL(oword) \
+ ( ( unsigned int ) le32_to_cpu ( (oword).u32[3] ) ), \
+ ( ( unsigned int ) le32_to_cpu ( (oword).u32[2] ) ), \
+ ( ( unsigned int ) le32_to_cpu ( (oword).u32[1] ) ), \
+ ( ( unsigned int ) le32_to_cpu ( (oword).u32[0] ) )
+
+/**
+ * Extract bit field portion [low,high) from the native-endian element
+ * which contains bits [min,max).
+ *
+ * For example, suppose "element" represents the high 32 bits of a
+ * 64-bit value, and we wish to extract the bits belonging to the bit
+ * field occupying bits 28-45 of this 64-bit value.
+ *
+ * Then EFAB_EXTRACT ( element, 32, 63, 28, 45 ) would give
+ *
+ * ( element ) << 4
+ *
+ * The result will contain the relevant bits filled in in the range
+ * [0,high-low), with garbage in bits [high-low+1,...).
+ */
+#define EFAB_EXTRACT_NATIVE( native_element, min ,max ,low ,high ) \
+ ( ( ( low > max ) || ( high < min ) ) ? 0 : \
+ ( ( low > min ) ? \
+ ( (native_element) >> ( low - min ) ) : \
+ ( (native_element) << ( min - low ) ) ) )
+
+/**
+ * Extract bit field portion [low,high) from the 64-bit little-endian
+ * element which contains bits [min,max)
+ */
+#define EFAB_EXTRACT64( element, min, max, low, high ) \
+ EFAB_EXTRACT_NATIVE ( le64_to_cpu(element), min, max, low, high )
+
+/**
+ * Extract bit field portion [low,high) from the 32-bit little-endian
+ * element which contains bits [min,max)
+ */
+#define EFAB_EXTRACT32( element, min, max, low, high ) \
+ EFAB_EXTRACT_NATIVE ( le32_to_cpu(element), min, max, low, high )
+
+#define EFAB_EXTRACT_OWORD64( oword, low, high ) \
+ ( EFAB_EXTRACT64 ( (oword).u64[0], 0, 63, low, high ) | \
+ EFAB_EXTRACT64 ( (oword).u64[1], 64, 127, low, high ) )
+
+#define EFAB_EXTRACT_QWORD64( qword, low, high ) \
+ ( EFAB_EXTRACT64 ( (qword).u64[0], 0, 63, low, high ) )
+
+#define EFAB_EXTRACT_OWORD32( oword, low, high ) \
+ ( EFAB_EXTRACT32 ( (oword).u32[0], 0, 31, low, high ) | \
+ EFAB_EXTRACT32 ( (oword).u32[1], 32, 63, low, high ) | \
+ EFAB_EXTRACT32 ( (oword).u32[2], 64, 95, low, high ) | \
+ EFAB_EXTRACT32 ( (oword).u32[3], 96, 127, low, high ) )
+
+#define EFAB_EXTRACT_QWORD32( qword, low, high ) \
+ ( EFAB_EXTRACT32 ( (qword).u32[0], 0, 31, low, high ) | \
+ EFAB_EXTRACT32 ( (qword).u32[1], 32, 63, low, high ) )
+
+#define EFAB_EXTRACT_DWORD( dword, low, high ) \
+ ( EFAB_EXTRACT32 ( (dword).u32[0], 0, 31, low, high ) )
+
+#define EFAB_OWORD_FIELD64( oword, field ) \
+ ( EFAB_EXTRACT_OWORD64 ( oword, EFAB_LOW_BIT ( field ), \
+ EFAB_HIGH_BIT ( field ) ) & \
+ EFAB_MASK64 ( field ) )
+
+#define EFAB_QWORD_FIELD64( qword, field ) \
+ ( EFAB_EXTRACT_QWORD64 ( qword, EFAB_LOW_BIT ( field ), \
+ EFAB_HIGH_BIT ( field ) ) & \
+ EFAB_MASK64 ( field ) )
+
+#define EFAB_OWORD_FIELD32( oword, field ) \
+ ( EFAB_EXTRACT_OWORD32 ( oword, EFAB_LOW_BIT ( field ), \
+ EFAB_HIGH_BIT ( field ) ) & \
+ EFAB_MASK32 ( field ) )
+
+#define EFAB_QWORD_FIELD32( qword, field ) \
+ ( EFAB_EXTRACT_QWORD32 ( qword, EFAB_LOW_BIT ( field ), \
+ EFAB_HIGH_BIT ( field ) ) & \
+ EFAB_MASK32 ( field ) )
+
+#define EFAB_DWORD_FIELD( dword, field ) \
+ ( EFAB_EXTRACT_DWORD ( dword, EFAB_LOW_BIT ( field ), \
+ EFAB_HIGH_BIT ( field ) ) & \
+ EFAB_MASK32 ( field ) )
+
+#define EFAB_OWORD_IS_ZERO64( oword ) \
+ ( ! ( (oword).u64[0] || (oword).u64[1] ) )
+
+#define EFAB_QWORD_IS_ZERO64( qword ) \
+ ( ! ( (qword).u64[0] ) )
+
+#define EFAB_OWORD_IS_ZERO32( oword ) \
+ ( ! ( (oword).u32[0] || (oword).u32[1] || \
+ (oword).u32[2] || (oword).u32[3] ) )
+
+#define EFAB_QWORD_IS_ZERO32( qword ) \
+ ( ! ( (qword).u32[0] || (qword).u32[1] ) )
+
+#define EFAB_DWORD_IS_ZERO( dword ) \
+ ( ! ( (dword).u32[0] ) )
+
+#define EFAB_OWORD_IS_ALL_ONES64( oword ) \
+ ( ( (oword).u64[0] & (oword).u64[1] ) == ~( ( uint64_t ) 0 ) )
+
+#define EFAB_QWORD_IS_ALL_ONES64( qword ) \
+ ( (qword).u64[0] == ~( ( uint64_t ) 0 ) )
+
+#define EFAB_OWORD_IS_ALL_ONES32( oword ) \
+ ( ( (oword).u32[0] & (oword).u32[1] & \
+ (oword).u32[2] & (oword).u32[3] ) == ~( ( uint32_t ) 0 ) )
+
+#define EFAB_QWORD_IS_ALL_ONES32( qword ) \
+ ( ( (qword).u32[0] & (qword).u32[1] ) == ~( ( uint32_t ) 0 ) )
+
+#define EFAB_DWORD_IS_ALL_ONES( dword ) \
+ ( (dword).u32[0] == ~( ( uint32_t ) 0 ) )
+
+#if ( BITS_PER_LONG == 64 )
+#define EFAB_OWORD_FIELD EFAB_OWORD_FIELD64
+#define EFAB_QWORD_FIELD EFAB_QWORD_FIELD64
+#define EFAB_OWORD_IS_ZERO EFAB_OWORD_IS_ZERO64
+#define EFAB_QWORD_IS_ZERO EFAB_QWORD_IS_ZERO64
+#define EFAB_OWORD_IS_ALL_ONES EFAB_OWORD_IS_ALL_ONES64
+#define EFAB_QWORD_IS_ALL_ONES EFAB_QWORD_IS_ALL_ONES64
+#else
+#define EFAB_OWORD_FIELD EFAB_OWORD_FIELD32
+#define EFAB_QWORD_FIELD EFAB_QWORD_FIELD32
+#define EFAB_OWORD_IS_ZERO EFAB_OWORD_IS_ZERO32
+#define EFAB_QWORD_IS_ZERO EFAB_QWORD_IS_ZERO32
+#define EFAB_OWORD_IS_ALL_ONES EFAB_OWORD_IS_ALL_ONES32
+#define EFAB_QWORD_IS_ALL_ONES EFAB_QWORD_IS_ALL_ONES32
+#endif
+
+/**
+ * Construct bit field portion
+ *
+ * Creates the portion of the bit field [low,high) that lies within
+ * the range [min,max).
+ */
+#define EFAB_INSERT_NATIVE64( min, max, low, high, value ) \
+ ( ( ( low > max ) || ( high < min ) ) ? 0 : \
+ ( ( low > min ) ? \
+ ( ( ( uint64_t ) (value) ) << ( low - min ) ) : \
+ ( ( ( uint64_t ) (value) ) >> ( min - low ) ) ) )
+
+#define EFAB_INSERT_NATIVE32( min, max, low, high, value ) \
+ ( ( ( low > max ) || ( high < min ) ) ? 0 : \
+ ( ( low > min ) ? \
+ ( ( ( uint32_t ) (value) ) << ( low - min ) ) : \
+ ( ( ( uint32_t ) (value) ) >> ( min - low ) ) ) )
+
+#define EFAB_INSERT_NATIVE( min, max, low, high, value ) \
+ ( ( ( ( max - min ) >= 32 ) || \
+ ( ( high - low ) >= 32 ) ) \
+ ? EFAB_INSERT_NATIVE64 ( min, max, low, high, value ) \
+ : EFAB_INSERT_NATIVE32 ( min, max, low, high, value ) )
+
+/**
+ * Construct bit field portion
+ *
+ * Creates the portion of the named bit field that lies within the
+ * range [min,max).
+ */
+#define EFAB_INSERT_FIELD_NATIVE( min, max, field, value ) \
+ EFAB_INSERT_NATIVE ( min, max, EFAB_LOW_BIT ( field ), \
+ EFAB_HIGH_BIT ( field ), value )
+
+/**
+ * Construct bit field
+ *
+ * Creates the portion of the named bit fields that lie within the
+ * range [min,max).
+ */
+#define EFAB_INSERT_FIELDS_NATIVE( min, max, \
+ field1, value1, \
+ field2, value2, \
+ field3, value3, \
+ field4, value4, \
+ field5, value5, \
+ field6, value6, \
+ field7, value7, \
+ field8, value8, \
+ field9, value9, \
+ field10, value10 ) \
+ ( EFAB_INSERT_FIELD_NATIVE ( min, max, field1, value1 ) | \
+ EFAB_INSERT_FIELD_NATIVE ( min, max, field2, value2 ) | \
+ EFAB_INSERT_FIELD_NATIVE ( min, max, field3, value3 ) | \
+ EFAB_INSERT_FIELD_NATIVE ( min, max, field4, value4 ) | \
+ EFAB_INSERT_FIELD_NATIVE ( min, max, field5, value5 ) | \
+ EFAB_INSERT_FIELD_NATIVE ( min, max, field6, value6 ) | \
+ EFAB_INSERT_FIELD_NATIVE ( min, max, field7, value7 ) | \
+ EFAB_INSERT_FIELD_NATIVE ( min, max, field8, value8 ) | \
+ EFAB_INSERT_FIELD_NATIVE ( min, max, field9, value9 ) | \
+ EFAB_INSERT_FIELD_NATIVE ( min, max, field10, value10 ) )
+
+#define EFAB_INSERT_FIELDS64( ... ) \
+ cpu_to_le64 ( EFAB_INSERT_FIELDS_NATIVE ( __VA_ARGS__ ) )
+
+#define EFAB_INSERT_FIELDS32( ... ) \
+ cpu_to_le32 ( EFAB_INSERT_FIELDS_NATIVE ( __VA_ARGS__ ) )
+
+#define EFAB_POPULATE_OWORD64( oword, ... ) do { \
+ (oword).u64[0] = EFAB_INSERT_FIELDS64 ( 0, 63, __VA_ARGS__ );\
+ (oword).u64[1] = EFAB_INSERT_FIELDS64 ( 64, 127, __VA_ARGS__ );\
+ } while ( 0 )
+
+#define EFAB_POPULATE_QWORD64( qword, ... ) do { \
+ (qword).u64[0] = EFAB_INSERT_FIELDS64 ( 0, 63, __VA_ARGS__ );\
+ } while ( 0 )
+
+#define EFAB_POPULATE_OWORD32( oword, ... ) do { \
+ (oword).u32[0] = EFAB_INSERT_FIELDS32 ( 0, 31, __VA_ARGS__ );\
+ (oword).u32[1] = EFAB_INSERT_FIELDS32 ( 32, 63, __VA_ARGS__ );\
+ (oword).u32[2] = EFAB_INSERT_FIELDS32 ( 64, 95, __VA_ARGS__ );\
+ (oword).u32[3] = EFAB_INSERT_FIELDS32 ( 96, 127, __VA_ARGS__ );\
+ } while ( 0 )
+
+#define EFAB_POPULATE_QWORD32( qword, ... ) do { \
+ (qword).u32[0] = EFAB_INSERT_FIELDS32 ( 0, 31, __VA_ARGS__ );\
+ (qword).u32[1] = EFAB_INSERT_FIELDS32 ( 32, 63, __VA_ARGS__ );\
+ } while ( 0 )
+
+#define EFAB_POPULATE_DWORD( dword, ... ) do { \
+ (dword).u32[0] = EFAB_INSERT_FIELDS32 ( 0, 31, __VA_ARGS__ );\
+ } while ( 0 )
+
+#if ( BITS_PER_LONG == 64 )
+#define EFAB_POPULATE_OWORD EFAB_POPULATE_OWORD64
+#define EFAB_POPULATE_QWORD EFAB_POPULATE_QWORD64
+#else
+#define EFAB_POPULATE_OWORD EFAB_POPULATE_OWORD32
+#define EFAB_POPULATE_QWORD EFAB_POPULATE_QWORD32
+#endif
+
+/* Populate an octword field with various numbers of arguments */
+#define EFAB_POPULATE_OWORD_10 EFAB_POPULATE_OWORD
+#define EFAB_POPULATE_OWORD_9( oword, ... ) \
+ EFAB_POPULATE_OWORD_10 ( oword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_OWORD_8( oword, ... ) \
+ EFAB_POPULATE_OWORD_9 ( oword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_OWORD_7( oword, ... ) \
+ EFAB_POPULATE_OWORD_8 ( oword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_OWORD_6( oword, ... ) \
+ EFAB_POPULATE_OWORD_7 ( oword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_OWORD_5( oword, ... ) \
+ EFAB_POPULATE_OWORD_6 ( oword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_OWORD_4( oword, ... ) \
+ EFAB_POPULATE_OWORD_5 ( oword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_OWORD_3( oword, ... ) \
+ EFAB_POPULATE_OWORD_4 ( oword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_OWORD_2( oword, ... ) \
+ EFAB_POPULATE_OWORD_3 ( oword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_OWORD_1( oword, ... ) \
+ EFAB_POPULATE_OWORD_2 ( oword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_ZERO_OWORD( oword ) \
+ EFAB_POPULATE_OWORD_1 ( oword, EFAB_DUMMY_FIELD, 0 )
+#define EFAB_SET_OWORD( oword ) \
+ EFAB_POPULATE_OWORD_4 ( oword, \
+ EFAB_DWORD_0, 0xffffffff, \
+ EFAB_DWORD_1, 0xffffffff, \
+ EFAB_DWORD_2, 0xffffffff, \
+ EFAB_DWORD_3, 0xffffffff )
+
+/* Populate a quadword field with various numbers of arguments */
+#define EFAB_POPULATE_QWORD_10 EFAB_POPULATE_QWORD
+#define EFAB_POPULATE_QWORD_9( qword, ... ) \
+ EFAB_POPULATE_QWORD_10 ( qword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_QWORD_8( qword, ... ) \
+ EFAB_POPULATE_QWORD_9 ( qword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_QWORD_7( qword, ... ) \
+ EFAB_POPULATE_QWORD_8 ( qword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_QWORD_6( qword, ... ) \
+ EFAB_POPULATE_QWORD_7 ( qword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_QWORD_5( qword, ... ) \
+ EFAB_POPULATE_QWORD_6 ( qword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_QWORD_4( qword, ... ) \
+ EFAB_POPULATE_QWORD_5 ( qword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_QWORD_3( qword, ... ) \
+ EFAB_POPULATE_QWORD_4 ( qword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_QWORD_2( qword, ... ) \
+ EFAB_POPULATE_QWORD_3 ( qword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_QWORD_1( qword, ... ) \
+ EFAB_POPULATE_QWORD_2 ( qword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_ZERO_QWORD( qword ) \
+ EFAB_POPULATE_QWORD_1 ( qword, EFAB_DUMMY_FIELD, 0 )
+#define EFAB_SET_QWORD( qword ) \
+ EFAB_POPULATE_QWORD_2 ( qword, \
+ EFAB_DWORD_0, 0xffffffff, \
+ EFAB_DWORD_1, 0xffffffff )
+
+/* Populate a dword field with various numbers of arguments */
+#define EFAB_POPULATE_DWORD_10 EFAB_POPULATE_DWORD
+#define EFAB_POPULATE_DWORD_9( dword, ... ) \
+ EFAB_POPULATE_DWORD_10 ( dword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_DWORD_8( dword, ... ) \
+ EFAB_POPULATE_DWORD_9 ( dword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_DWORD_7( dword, ... ) \
+ EFAB_POPULATE_DWORD_8 ( dword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_DWORD_6( dword, ... ) \
+ EFAB_POPULATE_DWORD_7 ( dword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_DWORD_5( dword, ... ) \
+ EFAB_POPULATE_DWORD_6 ( dword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_DWORD_4( dword, ... ) \
+ EFAB_POPULATE_DWORD_5 ( dword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_DWORD_3( dword, ... ) \
+ EFAB_POPULATE_DWORD_4 ( dword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_DWORD_2( dword, ... ) \
+ EFAB_POPULATE_DWORD_3 ( dword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_DWORD_1( dword, ... ) \
+ EFAB_POPULATE_DWORD_2 ( dword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_ZERO_DWORD( dword ) \
+ EFAB_POPULATE_DWORD_1 ( dword, EFAB_DUMMY_FIELD, 0 )
+#define EFAB_SET_DWORD( dword ) \
+ EFAB_POPULATE_DWORD_1 ( dword, EFAB_DWORD_0, 0xffffffff )
+
+/*
+ * Modify a named field within an already-populated structure. Used
+ * for read-modify-write operations.
+ *
+ */
+
+#define EFAB_INSERT_FIELD64( ... ) \
+ cpu_to_le64 ( EFAB_INSERT_FIELD_NATIVE ( __VA_ARGS__ ) )
+
+#define EFAB_INSERT_FIELD32( ... ) \
+ cpu_to_le32 ( EFAB_INSERT_FIELD_NATIVE ( __VA_ARGS__ ) )
+
+#define EFAB_INPLACE_MASK64( min, max, field ) \
+ EFAB_INSERT_FIELD64 ( min, max, field, EFAB_MASK64 ( field ) )
+
+#define EFAB_INPLACE_MASK32( min, max, field ) \
+ EFAB_INSERT_FIELD32 ( min, max, field, EFAB_MASK32 ( field ) )
+
+#define EFAB_SET_OWORD_FIELD64( oword, field, value ) do { \
+ (oword).u64[0] = ( ( (oword).u64[0] \
+ & ~EFAB_INPLACE_MASK64 ( 0, 63, field ) ) \
+ | EFAB_INSERT_FIELD64 ( 0, 63, field, value ) ); \
+ (oword).u64[1] = ( ( (oword).u64[1] \
+ & ~EFAB_INPLACE_MASK64 ( 64, 127, field ) ) \
+ | EFAB_INSERT_FIELD64 ( 64, 127, field, value ) ); \
+ } while ( 0 )
+
+#define EFAB_SET_QWORD_FIELD64( qword, field, value ) do { \
+ (qword).u64[0] = ( ( (qword).u64[0] \
+ & ~EFAB_INPLACE_MASK64 ( 0, 63, field ) ) \
+ | EFAB_INSERT_FIELD64 ( 0, 63, field, value ) ); \
+ } while ( 0 )
+
+#define EFAB_SET_OWORD_FIELD32( oword, field, value ) do { \
+ (oword).u32[0] = ( ( (oword).u32[0] \
+ & ~EFAB_INPLACE_MASK32 ( 0, 31, field ) ) \
+ | EFAB_INSERT_FIELD32 ( 0, 31, field, value ) ); \
+ (oword).u32[1] = ( ( (oword).u32[1] \
+ & ~EFAB_INPLACE_MASK32 ( 32, 63, field ) ) \
+ | EFAB_INSERT_FIELD32 ( 32, 63, field, value ) ); \
+ (oword).u32[2] = ( ( (oword).u32[2] \
+ & ~EFAB_INPLACE_MASK32 ( 64, 95, field ) ) \
+ | EFAB_INSERT_FIELD32 ( 64, 95, field, value ) ); \
+ (oword).u32[3] = ( ( (oword).u32[3] \
+ & ~EFAB_INPLACE_MASK32 ( 96, 127, field ) ) \
+ | EFAB_INSERT_FIELD32 ( 96, 127, field, value ) ); \
+ } while ( 0 )
+
+#define EFAB_SET_QWORD_FIELD32( qword, field, value ) do { \
+ (qword).u32[0] = ( ( (qword).u32[0] \
+ & ~EFAB_INPLACE_MASK32 ( 0, 31, field ) ) \
+ | EFAB_INSERT_FIELD32 ( 0, 31, field, value ) ); \
+ (qword).u32[1] = ( ( (qword).u32[1] \
+ & ~EFAB_INPLACE_MASK32 ( 32, 63, field ) ) \
+ | EFAB_INSERT_FIELD32 ( 32, 63, field, value ) ); \
+ } while ( 0 )
+
+#define EFAB_SET_DWORD_FIELD( dword, field, value ) do { \
+ (dword).u32[0] = ( ( (dword).u32[0] \
+ & ~EFAB_INPLACE_MASK32 ( 0, 31, field ) ) \
+ | EFAB_INSERT_FIELD32 ( 0, 31, field, value ) ); \
+ } while ( 0 )
+
+#if ( BITS_PER_LONG == 64 )
+#define EFAB_SET_OWORD_FIELD EFAB_SET_OWORD_FIELD64
+#define EFAB_SET_QWORD_FIELD EFAB_SET_QWORD_FIELD64
+#else
+#define EFAB_SET_OWORD_FIELD EFAB_SET_OWORD_FIELD32
+#define EFAB_SET_QWORD_FIELD EFAB_SET_QWORD_FIELD32
+#endif
+
+/* Used to avoid compiler warnings about shift range exceeding width
+ * of the data types when dma_addr_t is only 32 bits wide.
+ */
+#define DMA_ADDR_T_WIDTH ( 8 * sizeof ( dma_addr_t ) )
+#define EFAB_DMA_TYPE_WIDTH( width ) \
+ ( ( (width) < DMA_ADDR_T_WIDTH ) ? (width) : DMA_ADDR_T_WIDTH )
+#define EFAB_DMA_MAX_MASK ( ( DMA_ADDR_T_WIDTH == 64 ) ? \
+ ~( ( uint64_t ) 0 ) : ~( ( uint32_t ) 0 ) )
+#define EFAB_DMA_MASK(mask) ( (mask) & EFAB_DMA_MAX_MASK )
+
+#endif /* EFAB_BITFIELD_H */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * c-indent-level: 8
+ * tab-width: 8
+ * End:
+ */
diff --git a/src/drivers/net/mlx_ipoib/patches/dhcpd.patch b/src/drivers/net/mlx_ipoib/patches/dhcpd.patch
new file mode 100644
index 000000000..e2d0a2022
--- /dev/null
+++ b/src/drivers/net/mlx_ipoib/patches/dhcpd.patch
@@ -0,0 +1,23 @@
+diff -ru ../../orig/dhcp-3.0.4b2/common/options.c ./common/options.c
+--- ../../orig/dhcp-3.0.4b2/common/options.c 2005-11-02 01:19:03.000000000 +0200
++++ ./common/options.c 2005-12-06 14:38:17.000000000 +0200
+@@ -537,6 +537,7 @@
+ priority_list [priority_len++] = DHO_DHCP_LEASE_TIME;
+ priority_list [priority_len++] = DHO_DHCP_MESSAGE;
+ priority_list [priority_len++] = DHO_DHCP_REQUESTED_ADDRESS;
++ priority_list [priority_len++] = DHO_DHCP_CLIENT_IDENTIFIER;
+ priority_list [priority_len++] = DHO_FQDN;
+
+ if (prl && prl -> len > 0) {
+diff -ru ../../orig/dhcp-3.0.4b2/includes/site.h ./includes/site.h
+--- ../../orig/dhcp-3.0.4b2/includes/site.h 2002-03-12 20:33:39.000000000 +0200
++++ ./includes/site.h 2005-12-06 14:36:55.000000000 +0200
+@@ -135,7 +135,7 @@
+ the aforementioned problems do not matter to you, or if no other
+ API is supported for your system, you may want to go with it. */
+
+-/* #define USE_SOCKETS */
++#define USE_SOCKETS
+
+ /* Define this to use the Sun Streams NIT API.
+
diff --git a/src/drivers/net/mlx_ipoib/samples/dhcpd.conf b/src/drivers/net/mlx_ipoib/samples/dhcpd.conf
new file mode 100644
index 000000000..ed6975f91
--- /dev/null
+++ b/src/drivers/net/mlx_ipoib/samples/dhcpd.conf
@@ -0,0 +1,56 @@
+# dhcpd.conf
+#
+# Sample configuration file for ISC dhcpd
+#
+
+# option definitions common to all supported networks...
+
+DHCPD_INTERFACE = "ib0";
+
+# if you do not use dynamical DNS updates:
+#
+# this statement is needed by dhcpd-3 needs at least this statement.
+# you have to delete it for dhcpd-2, because it does not know it.
+#
+# if you want to use dynamical DNS updates, you should first read
+# read /usr/share/doc/packages/dhcp-server/DDNS-howto.txt
+ddns-update-style none; ddns-updates off;
+
+filename "pxelinux.bin";
+
+# If this DHCP server is the official DHCP server for the local
+# network, the authoritative directive should be uncommented.
+#authoritative;
+
+# No service will be given on this subnet, but declaring it helps the
+# DHCP server to understand the network topology.
+
+subnet 10.152.187.0 netmask 255.255.255.0 {
+}
+
+# This declaration allows BOOTP clients to get dynamic addresses,
+# which we don't really recommend.
+
+shared-network "ipoib_network" {
+ subnet 11.4.8.0 netmask 255.255.255.0 {
+ option dhcp-client-identifier = option dhcp-client-identifier;
+ option subnet-mask 255.255.255.0;
+ option domain-name "yok.mtl.com";
+ option domain-name-servers 10.0.0.1;
+ default-lease-time 28800;
+ max-lease-time 86400;
+ next-server 11.4.8.99;
+
+ }
+}
+
+
+# You need one such entry for each client
+host swlab35 {
+ fixed-address 11.4.8.35; # the IP address to be assigned to the client
+ # The value of the client identifier must be comprised from the prefix 20:00:
+ # folowed by the client's ipoib qp number - 55:04:01 in this example -
+ # followed by the GID of the port
+ option dhcp-client-identifier = 20:00:55:04:01:fe:80:00:00:00:00:00:00:00:02:c9:00:01:70:8a:81;
+}
+
diff --git a/src/drivers/net/pcnet32.c b/src/drivers/net/pcnet32.c
index 4255269bb..569912eed 100644
--- a/src/drivers/net/pcnet32.c
+++ b/src/drivers/net/pcnet32.c
@@ -434,6 +434,7 @@ static void pcnet32_reset(struct nic *nic)
if (lp->options & PCNET32_PORT_ASEL)
val |= 2;
lp->a.write_bcr(ioaddr, 2, val);
+
/* handle full duplex setting */
if (lp->full_duplex) {
val = lp->a.read_bcr(ioaddr, 9) & ~3;
@@ -483,6 +484,19 @@ static void pcnet32_reset(struct nic *nic)
lp->a.write_csr(ioaddr, 3, val);
}
#endif
+ if (1)
+ {
+ //disable interrupts
+ val = lp->a.read_csr(ioaddr, 3);
+ val = val
+ | (1 << 14) //BABLM intr disabled
+ | (1 << 12) //MISSM missed frame mask intr disabled
+ | (1 << 10) //RINTM receive intr disabled
+ | (1 << 9) //TINTM transmit intr disabled
+ | (1 << 8) //IDONM init done intr disabled
+ ;
+ lp->a.write_csr(ioaddr, 3, val);
+ }
if (lp->ltint) { /* Enable TxDone-intr inhibitor */
val = lp->a.read_csr(ioaddr, 5);
@@ -625,10 +639,10 @@ static void pcnet32_disable ( struct nic *nic __unused ) {
lp->a.write_csr(ioaddr, 0, 0x0004);
/*
- * Switch back to 16-bit mode to avoid problesm with dumb
+ * Switch back to 16-bit mode to avoid problems with dumb
* DOS packet driver after a warm reboot
*/
- lp->a.write_bcr(ioaddr, 20, 4);
+ lp->a.write_bcr(ioaddr, 20, 0);
}
/**************************************************************************
@@ -691,7 +705,7 @@ static int pcnet32_probe ( struct nic *nic, struct pci_device *pci ) {
chip_version =
a->read_csr(ioaddr, 88) | (a->read_csr(ioaddr, 89) << 16);
- dprintf(("PCnet chip version is %0xhX\n", chip_version));
+ dprintf(("PCnet chip version is 0x%X\n", chip_version));
if ((chip_version & 0xfff) != 0x003)
return 0;
@@ -753,6 +767,7 @@ static int pcnet32_probe ( struct nic *nic, struct pci_device *pci ) {
mii = 1;
break;
default:
+ chipname = "UNKNOWN";
printf("PCnet version %#x, no PCnet32 chip.\n",
chip_version);
return 0;
@@ -785,7 +800,7 @@ static int pcnet32_probe ( struct nic *nic, struct pci_device *pci ) {
nic->node_addr[i] = promaddr[i];
}
/* Print out some hardware info */
- printf("%s: %! at ioaddr %hX, ", pci->name, nic->node_addr,
+ printf("%s: %! at ioaddr 0x%hX, ", chipname, nic->node_addr,
ioaddr);
/* Set to pci bus master */
@@ -872,7 +887,6 @@ static int pcnet32_probe ( struct nic *nic, struct pci_device *pci ) {
/* switch pcnet32 to 32bit mode */
a->write_bcr(ioaddr, 20, 2);
-
a->write_csr(ioaddr, 1, (virt_to_bus(&lp->init_block)) & 0xffff);
a->write_csr(ioaddr, 2, (virt_to_bus(&lp->init_block)) >> 16);
@@ -883,15 +897,16 @@ static int pcnet32_probe ( struct nic *nic, struct pci_device *pci ) {
*/
/* Trigger an initialization just for the interrupt. */
- a->write_csr(ioaddr, 0, 0x41);
- mdelay(1);
+
+// a->write_csr(ioaddr, 0, 0x41);
+// mdelay(1);
cards_found++;
/* point to NIC specific routines */
pcnet32_reset(nic);
- if (1) {
- int tmp;
+ if (mii) {
+ int tmp;
int phy, phy_idx = 0;
u16 mii_lpa;
lp->phys[0] = 1; /* Default Setting */
@@ -928,6 +943,13 @@ static int pcnet32_probe ( struct nic *nic, struct pci_device *pci ) {
printf("10Mbps Half-Duplex\n");
else
printf("\n");
+ } else {
+ /* The older chips are fixed 10Mbps, and some support full duplex,
+ * although not via autonegotiation, but only via configuration. */
+ if (fdx)
+ printf("10Mbps Full-Duplex\n");
+ else
+ printf("10Mbps Half-Duplex\n");
}
nic->nic_op = &pcnet32_operations;
@@ -979,9 +1001,9 @@ static struct nic_operations pcnet32_operations = {
};
static struct pci_id pcnet32_nics[] = {
- PCI_ROM(0x1022, 0x2000, "lancepci", "AMD Lance/PCI"),
- PCI_ROM(0x1022, 0x2625, "pcnetfastiii", "AMD Lance/PCI PCNet/32"),
- PCI_ROM(0x1022, 0x2001, "amdhomepna", "AMD Lance/HomePNA"),
+ PCI_ROM(0x1022, 0x2000, "pcnet32", "AMD PCnet/PCI"),
+ PCI_ROM(0x1022, 0x2625, "pcnetfastiii", "AMD PCNet FAST III"),
+ PCI_ROM(0x1022, 0x2001, "amdhomepna", "AMD PCnet/HomePNA"),
};
PCI_DRIVER ( pcnet32_driver, pcnet32_nics, PCI_NO_CLASS );
diff --git a/src/drivers/net/via-velocity.c b/src/drivers/net/via-velocity.c
new file mode 100644
index 000000000..c51cc3506
--- /dev/null
+++ b/src/drivers/net/via-velocity.c
@@ -0,0 +1,1949 @@
+#define EB54 1
+/**************************************************************************
+* via-velocity.c: Etherboot device driver for the VIA 6120 Gigabit
+* Changes for Etherboot port:
+* Copyright (c) 2006 by Timothy Legge <tlegge@rogers.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*
+* This driver is based on:
+* via-velocity.c: VIA Velocity VT6120, VT6122 Ethernet driver
+* The changes are (c) Copyright 2004, Red Hat Inc.
+* <alan@redhat.com>
+* Additional fixes and clean up: Francois Romieu
+*
+* Original code:
+* Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
+* All rights reserved.
+* Author: Chuang Liang-Shing, AJ Jiang
+*
+* Linux Driver Version 2.6.15.4
+*
+* REVISION HISTORY:
+* ================
+*
+* v1.0 03-06-2006 timlegge Initial port of Linux driver
+*
+* Indent Options: indent -kr -i8
+*************************************************************************/
+
+/* to get some global routines like printf */
+#include "etherboot.h"
+/* to get the interface to the body of the program */
+#include "nic.h"
+/* to get the PCI support functions, if this is a PCI NIC */
+#include "pci.h"
+
+
+#include "via-velocity.h"
+
+typedef int pci_power_t;
+
+#define PCI_D0 ((int) 0)
+#define PCI_D1 ((int) 1)
+#define PCI_D2 ((int) 2)
+#define PCI_D3hot ((int) 3)
+#define PCI_D3cold ((int) 4)
+#define PCI_POWER_ERROR ((int) -1)
+
+
+/* Condensed operations for readability. */
+#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
+#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
+
+//FIXME: Move to pci.c
+int pci_set_power_state(struct pci_device *dev, int state);
+
+/* FIXME: Move BASE to the private structure */
+static u32 BASE;
+
+/* NIC specific static variables go here */
+#define VELOCITY_PARAM(N,D) \
+ static const int N[MAX_UNITS]=OPTION_DEFAULT;
+/* MODULE_PARM(N, "1-" __MODULE_STRING(MAX_UNITS) "i");\
+ MODULE_PARM_DESC(N, D); */
+
+VELOCITY_PARAM(RxDescriptors, "Number of receive descriptors");
+VELOCITY_PARAM(TxDescriptors, "Number of transmit descriptors");
+
+
+#define VLAN_ID_MIN 0
+#define VLAN_ID_MAX 4095
+#define VLAN_ID_DEF 0
+/* VID_setting[] is used for setting the VID of NIC.
+ 0: default VID.
+ 1-4094: other VIDs.
+*/
+VELOCITY_PARAM(VID_setting, "802.1Q VLAN ID");
+
+#define RX_THRESH_MIN 0
+#define RX_THRESH_MAX 3
+#define RX_THRESH_DEF 0
+/* rx_thresh[] is used for controlling the receive fifo threshold.
+ 0: indicate the rxfifo threshold is 128 bytes.
+ 1: indicate the rxfifo threshold is 512 bytes.
+ 2: indicate the rxfifo threshold is 1024 bytes.
+ 3: indicate the rxfifo threshold is store & forward.
+*/
+VELOCITY_PARAM(rx_thresh, "Receive fifo threshold");
+
+#define DMA_LENGTH_MIN 0
+#define DMA_LENGTH_MAX 7
+#define DMA_LENGTH_DEF 0
+
+/* DMA_length[] is used for controlling the DMA length
+ 0: 8 DWORDs
+ 1: 16 DWORDs
+ 2: 32 DWORDs
+ 3: 64 DWORDs
+ 4: 128 DWORDs
+ 5: 256 DWORDs
+ 6: SF(flush till emply)
+ 7: SF(flush till emply)
+*/
+VELOCITY_PARAM(DMA_length, "DMA length");
+
+#define TAGGING_DEF 0
+/* enable_tagging[] is used for enabling 802.1Q VID tagging.
+ 0: disable VID seeting(default).
+ 1: enable VID setting.
+*/
+VELOCITY_PARAM(enable_tagging, "Enable 802.1Q tagging");
+
+#define IP_ALIG_DEF 0
+/* IP_byte_align[] is used for IP header DWORD byte aligned
+ 0: indicate the IP header won't be DWORD byte aligned.(Default) .
+ 1: indicate the IP header will be DWORD byte aligned.
+ In some enviroment, the IP header should be DWORD byte aligned,
+ or the packet will be droped when we receive it. (eg: IPVS)
+*/
+VELOCITY_PARAM(IP_byte_align, "Enable IP header dword aligned");
+
+#define TX_CSUM_DEF 1
+/* txcsum_offload[] is used for setting the checksum offload ability of NIC.
+ (We only support RX checksum offload now)
+ 0: disable csum_offload[checksum offload
+ 1: enable checksum offload. (Default)
+*/
+VELOCITY_PARAM(txcsum_offload, "Enable transmit packet checksum offload");
+
+#define FLOW_CNTL_DEF 1
+#define FLOW_CNTL_MIN 1
+#define FLOW_CNTL_MAX 5
+
+/* flow_control[] is used for setting the flow control ability of NIC.
+ 1: hardware deafult - AUTO (default). Use Hardware default value in ANAR.
+ 2: enable TX flow control.
+ 3: enable RX flow control.
+ 4: enable RX/TX flow control.
+ 5: disable
+*/
+VELOCITY_PARAM(flow_control, "Enable flow control ability");
+
+#define MED_LNK_DEF 0
+#define MED_LNK_MIN 0
+#define MED_LNK_MAX 4
+/* speed_duplex[] is used for setting the speed and duplex mode of NIC.
+ 0: indicate autonegotiation for both speed and duplex mode
+ 1: indicate 100Mbps half duplex mode
+ 2: indicate 100Mbps full duplex mode
+ 3: indicate 10Mbps half duplex mode
+ 4: indicate 10Mbps full duplex mode
+
+ Note:
+ if EEPROM have been set to the force mode, this option is ignored
+ by driver.
+*/
+VELOCITY_PARAM(speed_duplex, "Setting the speed and duplex mode");
+
+#define VAL_PKT_LEN_DEF 0
+/* ValPktLen[] is used for setting the checksum offload ability of NIC.
+ 0: Receive frame with invalid layer 2 length (Default)
+ 1: Drop frame with invalid layer 2 length
+*/
+VELOCITY_PARAM(ValPktLen, "Receiving or Drop invalid 802.3 frame");
+
+#define WOL_OPT_DEF 0
+#define WOL_OPT_MIN 0
+#define WOL_OPT_MAX 7
+/* wol_opts[] is used for controlling wake on lan behavior.
+ 0: Wake up if recevied a magic packet. (Default)
+ 1: Wake up if link status is on/off.
+ 2: Wake up if recevied an arp packet.
+ 4: Wake up if recevied any unicast packet.
+ Those value can be sumed up to support more than one option.
+*/
+VELOCITY_PARAM(wol_opts, "Wake On Lan options");
+
+#define INT_WORKS_DEF 20
+#define INT_WORKS_MIN 10
+#define INT_WORKS_MAX 64
+
+VELOCITY_PARAM(int_works, "Number of packets per interrupt services");
+
+/* The descriptors for this card are required to be aligned on
+64 byte boundaries. As the align attribute does not guarantee alignment
+greater than the alignment of the start address (which for Etherboot
+is 16 bytes of alignment) it requires some extra steps. Add 64 to the
+size of the array and the init_ring adjusts the alignment */
+
+/* Define the TX Descriptor */
+static u8 tx_ring[TX_DESC_DEF * sizeof(struct tx_desc) + 64];
+
+/* Create a static buffer of size PKT_BUF_SZ for each TX Descriptor.
+All descriptors point to a part of this buffer */
+static u8 txb[(TX_DESC_DEF * PKT_BUF_SZ) + 64];
+
+/* Define the RX Descriptor */
+static u8 rx_ring[RX_DESC_DEF * sizeof(struct rx_desc) + 64];
+
+/* Create a static buffer of size PKT_BUF_SZ for each RX Descriptor
+ All descriptors point to a part of this buffer */
+static u8 rxb[(RX_DESC_DEF * PKT_BUF_SZ) + 64];
+
+static void velocity_init_info(struct pci_device *pdev,
+ struct velocity_info *vptr,
+ struct velocity_info_tbl *info);
+static int velocity_get_pci_info(struct velocity_info *,
+ struct pci_device *pdev);
+static int velocity_open(struct nic *nic, struct pci_device *pci);
+
+static int velocity_soft_reset(struct velocity_info *vptr);
+static void velocity_init_cam_filter(struct velocity_info *vptr);
+static void mii_init(struct velocity_info *vptr, u32 mii_status);
+static u32 velocity_get_opt_media_mode(struct velocity_info *vptr);
+static void velocity_print_link_status(struct velocity_info *vptr);
+static void safe_disable_mii_autopoll(struct mac_regs *regs);
+static void enable_flow_control_ability(struct velocity_info *vptr);
+static void enable_mii_autopoll(struct mac_regs *regs);
+static int velocity_mii_read(struct mac_regs *, u8 byIdx, u16 * pdata);
+static int velocity_mii_write(struct mac_regs *, u8 byMiiAddr, u16 data);
+static u32 mii_check_media_mode(struct mac_regs *regs);
+static u32 check_connection_type(struct mac_regs *regs);
+static int velocity_set_media_mode(struct velocity_info *vptr,
+ u32 mii_status);
+
+
+/*
+ * Internal board variants. At the moment we have only one
+ */
+
+static struct velocity_info_tbl chip_info_table[] = {
+ {CHIP_TYPE_VT6110,
+ "VIA Networking Velocity Family Gigabit Ethernet Adapter", 256, 1,
+ 0x00FFFFFFUL},
+ {0, NULL, 0, 0, 0}
+};
+
+/**
+ * velocity_set_int_opt - parser for integer options
+ * @opt: pointer to option value
+ * @val: value the user requested (or -1 for default)
+ * @min: lowest value allowed
+ * @max: highest value allowed
+ * @def: default value
+ * @name: property name
+ * @dev: device name
+ *
+ * Set an integer property in the module options. This function does
+ * all the verification and checking as well as reporting so that
+ * we don't duplicate code for each option.
+ */
+
+static void velocity_set_int_opt(int *opt, int val, int min, int max,
+ int def, char *name, char *devname)
+{
+ if (val == -1) {
+ printf("%s: set value of parameter %s to %d\n",
+ devname, name, def);
+ *opt = def;
+ } else if (val < min || val > max) {
+ printf
+ ("%s: the value of parameter %s is invalid, the valid range is (%d-%d)\n",
+ devname, name, min, max);
+ *opt = def;
+ } else {
+ printf("%s: set value of parameter %s to %d\n",
+ devname, name, val);
+ *opt = val;
+ }
+}
+
+/**
+ * velocity_set_bool_opt - parser for boolean options
+ * @opt: pointer to option value
+ * @val: value the user requested (or -1 for default)
+ * @def: default value (yes/no)
+ * @flag: numeric value to set for true.
+ * @name: property name
+ * @dev: device name
+ *
+ * Set a boolean property in the module options. This function does
+ * all the verification and checking as well as reporting so that
+ * we don't duplicate code for each option.
+ */
+
+static void velocity_set_bool_opt(u32 * opt, int val, int def, u32 flag,
+ char *name, char *devname)
+{
+ (*opt) &= (~flag);
+ if (val == -1) {
+ printf("%s: set parameter %s to %s\n",
+ devname, name, def ? "TRUE" : "FALSE");
+ *opt |= (def ? flag : 0);
+ } else if (val < 0 || val > 1) {
+ printf
+ ("%s: the value of parameter %s is invalid, the valid range is (0-1)\n",
+ devname, name);
+ *opt |= (def ? flag : 0);
+ } else {
+ printf("%s: set parameter %s to %s\n",
+ devname, name, val ? "TRUE" : "FALSE");
+ *opt |= (val ? flag : 0);
+ }
+}
+
+/**
+ * velocity_get_options - set options on device
+ * @opts: option structure for the device
+ * @index: index of option to use in module options array
+ * @devname: device name
+ *
+ * Turn the module and command options into a single structure
+ * for the current device
+ */
+
+static void velocity_get_options(struct velocity_opt *opts, int index,
+ char *devname)
+{
+
+ /* FIXME Do the options need to be configurable */
+ velocity_set_int_opt(&opts->rx_thresh, -1, RX_THRESH_MIN,
+ RX_THRESH_MAX, RX_THRESH_DEF, "rx_thresh",
+ devname);
+ velocity_set_int_opt(&opts->DMA_length, DMA_length[index],
+ DMA_LENGTH_MIN, DMA_LENGTH_MAX,
+ DMA_LENGTH_DEF, "DMA_length", devname);
+ velocity_set_int_opt(&opts->numrx, RxDescriptors[index],
+ RX_DESC_MIN, RX_DESC_MAX, RX_DESC_DEF,
+ "RxDescriptors", devname);
+ velocity_set_int_opt(&opts->numtx, TxDescriptors[index],
+ TX_DESC_MIN, TX_DESC_MAX, TX_DESC_DEF,
+ "TxDescriptors", devname);
+ velocity_set_int_opt(&opts->vid, VID_setting[index], VLAN_ID_MIN,
+ VLAN_ID_MAX, VLAN_ID_DEF, "VID_setting",
+ devname);
+ velocity_set_bool_opt(&opts->flags, enable_tagging[index],
+ TAGGING_DEF, VELOCITY_FLAGS_TAGGING,
+ "enable_tagging", devname);
+ velocity_set_bool_opt(&opts->flags, txcsum_offload[index],
+ TX_CSUM_DEF, VELOCITY_FLAGS_TX_CSUM,
+ "txcsum_offload", devname);
+ velocity_set_int_opt(&opts->flow_cntl, flow_control[index],
+ FLOW_CNTL_MIN, FLOW_CNTL_MAX, FLOW_CNTL_DEF,
+ "flow_control", devname);
+ velocity_set_bool_opt(&opts->flags, IP_byte_align[index],
+ IP_ALIG_DEF, VELOCITY_FLAGS_IP_ALIGN,
+ "IP_byte_align", devname);
+ velocity_set_bool_opt(&opts->flags, ValPktLen[index],
+ VAL_PKT_LEN_DEF, VELOCITY_FLAGS_VAL_PKT_LEN,
+ "ValPktLen", devname);
+ velocity_set_int_opt((int *) &opts->spd_dpx, speed_duplex[index],
+ MED_LNK_MIN, MED_LNK_MAX, MED_LNK_DEF,
+ "Media link mode", devname);
+ velocity_set_int_opt((int *) &opts->wol_opts, wol_opts[index],
+ WOL_OPT_MIN, WOL_OPT_MAX, WOL_OPT_DEF,
+ "Wake On Lan options", devname);
+ velocity_set_int_opt((int *) &opts->int_works, int_works[index],
+ INT_WORKS_MIN, INT_WORKS_MAX, INT_WORKS_DEF,
+ "Interrupt service works", devname);
+ opts->numrx = (opts->numrx & ~3);
+}
+
+/**
+ * velocity_init_cam_filter - initialise CAM
+ * @vptr: velocity to program
+ *
+ * Initialize the content addressable memory used for filters. Load
+ * appropriately according to the presence of VLAN
+ */
+
+static void velocity_init_cam_filter(struct velocity_info *vptr)
+{
+ struct mac_regs *regs = vptr->mac_regs;
+
+ /* Turn on MCFG_PQEN, turn off MCFG_RTGOPT */
+ WORD_REG_BITS_SET(MCFG_PQEN, MCFG_RTGOPT, &regs->MCFG);
+ WORD_REG_BITS_ON(MCFG_VIDFR, &regs->MCFG);
+
+ /* Disable all CAMs */
+ memset(vptr->vCAMmask, 0, sizeof(u8) * 8);
+ memset(vptr->mCAMmask, 0, sizeof(u8) * 8);
+ mac_set_cam_mask(regs, vptr->vCAMmask, VELOCITY_VLAN_ID_CAM);
+ mac_set_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM);
+
+ /* Enable first VCAM */
+ if (vptr->flags & VELOCITY_FLAGS_TAGGING) {
+ /* If Tagging option is enabled and VLAN ID is not zero, then
+ turn on MCFG_RTGOPT also */
+ if (vptr->options.vid != 0)
+ WORD_REG_BITS_ON(MCFG_RTGOPT, &regs->MCFG);
+
+ mac_set_cam(regs, 0, (u8 *) & (vptr->options.vid),
+ VELOCITY_VLAN_ID_CAM);
+ vptr->vCAMmask[0] |= 1;
+ mac_set_cam_mask(regs, vptr->vCAMmask,
+ VELOCITY_VLAN_ID_CAM);
+ } else {
+ u16 temp = 0;
+ mac_set_cam(regs, 0, (u8 *) & temp, VELOCITY_VLAN_ID_CAM);
+ temp = 1;
+ mac_set_cam_mask(regs, (u8 *) & temp,
+ VELOCITY_VLAN_ID_CAM);
+ }
+}
+
+static inline void velocity_give_many_rx_descs(struct velocity_info *vptr)
+{
+ struct mac_regs *regs = vptr->mac_regs;
+ int avail, dirty, unusable;
+
+ /*
+ * RD number must be equal to 4X per hardware spec
+ * (programming guide rev 1.20, p.13)
+ */
+ if (vptr->rd_filled < 4)
+ return;
+
+ wmb();
+
+ unusable = vptr->rd_filled & 0x0003;
+ dirty = vptr->rd_dirty - unusable;
+ for (avail = vptr->rd_filled & 0xfffc; avail; avail--) {
+ dirty = (dirty > 0) ? dirty - 1 : vptr->options.numrx - 1;
+// printf("return dirty: %d\n", dirty);
+ vptr->rd_ring[dirty].rdesc0.owner = OWNED_BY_NIC;
+ }
+
+ writew(vptr->rd_filled & 0xfffc, &regs->RBRDU);
+ vptr->rd_filled = unusable;
+}
+
+static int velocity_rx_refill(struct velocity_info *vptr)
+{
+ int dirty = vptr->rd_dirty, done = 0, ret = 0;
+
+// printf("rx_refill - rd_curr = %d, dirty = %d\n", vptr->rd_curr, dirty);
+ do {
+ struct rx_desc *rd = vptr->rd_ring + dirty;
+
+ /* Fine for an all zero Rx desc at init time as well */
+ if (rd->rdesc0.owner == OWNED_BY_NIC)
+ break;
+// printf("rx_refill - after owner %d\n", dirty);
+
+ rd->inten = 1;
+ rd->pa_high = 0;
+ rd->rdesc0.len = cpu_to_le32(vptr->rx_buf_sz);;
+
+ done++;
+ dirty = (dirty < vptr->options.numrx - 1) ? dirty + 1 : 0;
+ } while (dirty != vptr->rd_curr);
+
+ if (done) {
+// printf("\nGive Back Desc\n");
+ vptr->rd_dirty = dirty;
+ vptr->rd_filled += done;
+ velocity_give_many_rx_descs(vptr);
+ }
+
+ return ret;
+}
+
+extern void hex_dump(const char *data, const unsigned int len);
+/**************************************************************************
+POLL - Wait for a frame
+***************************************************************************/
+//EB53 static int velocity_poll(struct nic *nic, int retrieve)
+static int velocity_poll(struct nic *nic __unused)
+{
+ /* Work out whether or not there's an ethernet packet ready to
+ * read. Return 0 if not.
+ */
+
+ int rd_curr = vptr->rd_curr % RX_DESC_DEF;
+ struct rx_desc *rd = &(vptr->rd_ring[rd_curr]);
+
+ if (rd->rdesc0.owner == OWNED_BY_NIC)
+ return 0;
+ rmb();
+
+ /*
+ * Don't drop CE or RL error frame although RXOK is off
+ */
+ if ((rd->rdesc0.RSR & RSR_RXOK)
+ || (!(rd->rdesc0.RSR & RSR_RXOK)
+ && (rd->rdesc0.RSR & (RSR_CE | RSR_RL)))) {
+
+ nic->packetlen = rd->rdesc0.len;
+ // ptr->rxb + (rd_curr * PKT_BUF_SZ)
+ memcpy(nic->packet, bus_to_virt(rd->pa_low),
+ nic->packetlen - 4);
+
+ vptr->rd_curr++;
+ vptr->rd_curr = vptr->rd_curr % RX_DESC_DEF;
+ velocity_rx_refill(vptr);
+ return 1; /* Remove this line once this method is implemented */
+ }
+ return 0;
+}
+
+#define TX_TIMEOUT (1000);
+/**************************************************************************
+TRANSMIT - Transmit a frame
+***************************************************************************/
+static void velocity_transmit(struct nic *nic, const char *dest, /* Destination */
+ unsigned int type, /* Type */
+ unsigned int size, /* size */
+ const char *packet)
+{ /* Packet */
+ u16 nstype;
+ u32 to;
+ u8 *ptxb;
+ unsigned int pktlen;
+ struct tx_desc *td_ptr;
+
+ int entry = vptr->td_curr % TX_DESC_DEF;
+ td_ptr = &(vptr->td_rings[entry]);
+
+ /* point to the current txb incase multiple tx_rings are used */
+ ptxb = vptr->txb + (entry * PKT_BUF_SZ);
+ memcpy(ptxb, dest, ETH_ALEN); /* Destination */
+ memcpy(ptxb + ETH_ALEN, nic->node_addr, ETH_ALEN); /* Source */
+ nstype = htons((u16) type); /* Type */
+ memcpy(ptxb + 2 * ETH_ALEN, (u8 *) & nstype, 2); /* Type */
+ memcpy(ptxb + ETH_HLEN, packet, size);
+
+ td_ptr->tdesc1.TCPLS = TCPLS_NORMAL;
+ td_ptr->tdesc1.TCR = TCR0_TIC;
+ td_ptr->td_buf[0].queue = 0;
+
+ size += ETH_HLEN;
+ while (size < ETH_ZLEN) /* pad to min length */
+ ptxb[size++] = '\0';
+
+ if (size < ETH_ZLEN) {
+// printf("Padd that packet\n");
+ pktlen = ETH_ZLEN;
+// memcpy(ptxb, skb->data, skb->len);
+ memset(ptxb + size, 0, ETH_ZLEN - size);
+
+ vptr->td_rings[entry].tdesc0.pktsize = pktlen;
+ vptr->td_rings[entry].td_buf[0].pa_low = virt_to_bus(ptxb);
+ vptr->td_rings[entry].td_buf[0].pa_high &=
+ cpu_to_le32(0xffff0000L);
+ vptr->td_rings[entry].td_buf[0].bufsize =
+ vptr->td_rings[entry].tdesc0.pktsize;
+ vptr->td_rings[entry].tdesc1.CMDZ = 2;
+ } else {
+// printf("Correct size packet\n");
+ td_ptr->tdesc0.pktsize = size;
+ td_ptr->td_buf[0].pa_low = virt_to_bus(ptxb);
+ td_ptr->td_buf[0].pa_high = 0;
+ td_ptr->td_buf[0].bufsize = td_ptr->tdesc0.pktsize;
+// tdinfo->nskb_dma = 1;
+ td_ptr->tdesc1.CMDZ = 2;
+ }
+
+ if (vptr->flags & VELOCITY_FLAGS_TAGGING) {
+ td_ptr->tdesc1.pqinf.VID = (vptr->options.vid & 0xfff);
+ td_ptr->tdesc1.pqinf.priority = 0;
+ td_ptr->tdesc1.pqinf.CFI = 0;
+ td_ptr->tdesc1.TCR |= TCR0_VETAG;
+ }
+
+ vptr->td_curr = (entry + 1);
+
+ {
+
+ int prev = entry - 1;
+
+ if (prev < 0)
+ prev = TX_DESC_DEF - 1;
+ td_ptr->tdesc0.owner |= OWNED_BY_NIC;
+ td_ptr = &(vptr->td_rings[prev]);
+ td_ptr->td_buf[0].queue = 1;
+ mac_tx_queue_wake(vptr->mac_regs, 0);
+
+ }
+
+ to = currticks() + TX_TIMEOUT;
+ while ((td_ptr->tdesc0.owner & OWNED_BY_NIC) && (currticks() < to)); /* wait */
+
+ if (currticks() >= to) {
+ printf("TX Time Out");
+ }
+
+}
+
+/**************************************************************************
+DISABLE - Turn off ethernet interface
+***************************************************************************/
+static void velocity_disable(struct dev *dev __unused)
+{
+ /* put the card in its initial state */
+ /* This function serves 3 purposes.
+ * This disables DMA and interrupts so we don't receive
+ * unexpected packets or interrupts from the card after
+ * etherboot has finished.
+ * This frees resources so etherboot may use
+ * this driver on another interface
+ * This allows etherboot to reinitialize the interface
+ * if something is something goes wrong.
+ */
+ struct mac_regs *regs = vptr->mac_regs;
+ mac_disable_int(regs);
+ writel(CR0_STOP, &regs->CR0Set);
+ writew(0xFFFF, &regs->TDCSRClr);
+ writeb(0xFF, &regs->RDCSRClr);
+ safe_disable_mii_autopoll(regs);
+ mac_clear_isr(regs);
+
+ /* Power down the chip */
+// pci_set_power_state(vptr->pdev, PCI_D3hot);
+
+ vptr->flags &= (~VELOCITY_FLAGS_OPENED);
+}
+
+#ifdef EB54
+/**************************************************************************
+IRQ - handle interrupts
+***************************************************************************/
+static void velocity_irq(struct nic *nic __unused, irq_action_t action)
+{
+ /* This routine is somewhat optional. Etherboot itself
+ * doesn't use interrupts, but they are required under some
+ * circumstances when we're acting as a PXE stack.
+ *
+ * If you don't implement this routine, the only effect will
+ * be that your driver cannot be used via Etherboot's UNDI
+ * API. This won't affect programs that use only the UDP
+ * portion of the PXE API, such as pxelinux.
+ */
+
+ switch (action) {
+ case DISABLE:
+ case ENABLE:
+ /* Set receive interrupt enabled/disabled state */
+ /*
+ outb ( action == ENABLE ? IntrMaskEnabled : IntrMaskDisabled,
+ nic->ioaddr + IntrMaskRegister );
+ */
+ break;
+ case FORCE:
+ /* Force NIC to generate a receive interrupt */
+ /*
+ outb ( ForceInterrupt, nic->ioaddr + IntrForceRegister );
+ */
+ break;
+ }
+}
+#endif
+/**************************************************************************
+PROBE - Look for an adapter, this routine's visible to the outside
+***************************************************************************/
+
+#define board_found 1
+#define valid_link 0
+static int velocity_probe(struct dev *dev, struct pci_device *pci)
+{
+ struct nic *nic = (struct nic *) dev;
+ int ret, i;
+ struct mac_regs *regs;
+
+ printf("via-velocity.c: Found %s Vendor=0x%hX Device=0x%hX\n",
+ pci->name, pci->vendor, pci->dev_id);
+
+ /* point to private storage */
+ vptr = &vptx;
+ info = chip_info_table;
+
+ velocity_init_info(pci, vptr, info);
+
+//FIXME: pci_enable_device(pci);
+//FIXME: pci_set_power_state(pci, PCI_D0);
+
+ ret = velocity_get_pci_info(vptr, pci);
+ if (ret < 0) {
+ printf("Failed to find PCI device.\n");
+ return 0;
+ }
+
+ regs = ioremap(vptr->memaddr, vptr->io_size);
+ if (regs == NULL) {
+ printf("Unable to remap io\n");
+ return 0;
+ }
+
+ vptr->mac_regs = regs;
+
+ BASE = vptr->ioaddr;
+
+ printf("Chip ID: %hX\n", vptr->chip_id);
+
+ for (i = 0; i < 6; i++)
+ nic->node_addr[i] = readb(&regs->PAR[i]);
+
+ /* Print out some hardware info */
+ printf("%s: %! at ioaddr %hX, ", pci->name, nic->node_addr, BASE);
+
+ velocity_get_options(&vptr->options, 0, pci->name);
+
+ /*
+ * Mask out the options cannot be set to the chip
+ */
+ vptr->options.flags &= 0x00FFFFFFUL; //info->flags = 0x00FFFFFFUL;
+
+ /*
+ * Enable the chip specified capbilities
+ */
+
+ vptr->flags =
+ vptr->options.
+ flags | (0x00FFFFFFUL /*info->flags */ & 0xFF000000UL);
+
+ vptr->wol_opts = vptr->options.wol_opts;
+ vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED;
+
+ vptr->phy_id = MII_GET_PHY_ID(vptr->mac_regs);
+
+ if (vptr->flags & VELOCITY_FLAGS_TX_CSUM) {
+ printf("features missing\n");
+ }
+
+ /* and leave the chip powered down */
+// FIXME: pci_set_power_state(pci, PCI_D3hot);
+
+ check_connection_type(vptr->mac_regs);
+ velocity_open(nic, pci);
+
+ /* store NIC parameters */
+#ifdef EB54
+ nic->ioaddr = pci->ioaddr & ~3;
+ nic->irqno = pci->irq;
+ nic->irq = velocity_irq;
+#endif
+ dev->disable = velocity_disable;
+ nic->poll = velocity_poll;
+ nic->transmit = velocity_transmit;
+ return 1;
+}
+
+//#define IORESOURCE_IO 0x00000100 /* Resource type */
+
+/**
+ * velocity_init_info - init private data
+ * @pdev: PCI device
+ * @vptr: Velocity info
+ * @info: Board type
+ *
+ * Set up the initial velocity_info struct for the device that has been
+ * discovered.
+ */
+
+static void velocity_init_info(struct pci_device *pdev,
+ struct velocity_info *vptr,
+ struct velocity_info_tbl *info)
+{
+ memset(vptr, 0, sizeof(struct velocity_info));
+
+ vptr->pdev = pdev;
+ vptr->chip_id = info->chip_id;
+ vptr->io_size = info->io_size;
+ vptr->num_txq = info->txqueue;
+ vptr->multicast_limit = MCAM_SIZE;
+
+ printf
+ ("chip_id: 0x%hX, io_size: %d, num_txq %d, multicast_limit: %d\n",
+ vptr->chip_id, vptr->io_size, vptr->num_txq,
+ vptr->multicast_limit);
+ printf("Name: %s\n", info->name);
+
+// spin_lock_init(&vptr->lock);
+// INIT_LIST_HEAD(&vptr->list);
+}
+
+/**
+ * velocity_get_pci_info - retrieve PCI info for device
+ * @vptr: velocity device
+ * @pdev: PCI device it matches
+ *
+ * Retrieve the PCI configuration space data that interests us from
+ * the kernel PCI layer
+ */
+
+#define IORESOURCE_IO 0x00000100 /* Resource type */
+#define IORESOURCE_PREFETCH 0x00001000 /* No side effects */
+
+#define IORESOURCE_MEM 0x00000200
+#define BAR_0 0
+#define BAR_1 1
+#define BAR_5 5
+#define PCI_BASE_ADDRESS_SPACE 0x01 /* 0 = memory, 1 = I/O */
+#define PCI_BASE_ADDRESS_SPACE_IO 0x01
+#define PCI_BASE_ADDRESS_SPACE_MEMORY 0x00
+#define PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06
+#define PCI_BASE_ADDRESS_MEM_TYPE_32 0x00 /* 32 bit address */
+#define PCI_BASE_ADDRESS_MEM_TYPE_1M 0x02 /* Below 1M [obsolete] */
+#define PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 bit address */
+#define PCI_BASE_ADDRESS_MEM_PREFETCH 0x08 /* prefetchable? */
+//#define PCI_BASE_ADDRESS_MEM_MASK (~0x0fUL)
+// #define PCI_BASE_ADDRESS_IO_MASK (~0x03UL)
+
+unsigned long pci_resource_flags(struct pci_device *pdev, unsigned int bar)
+{
+ uint32_t l, sz;
+ unsigned long flags = 0;
+
+ pci_read_config_dword(pdev, bar, &l);
+ pci_write_config_dword(pdev, bar, ~0);
+ pci_read_config_dword(pdev, bar, &sz);
+ pci_write_config_dword(pdev, bar, l);
+
+ if (!sz || sz == 0xffffffff)
+ printf("Weird size\n");
+ if (l == 0xffffffff)
+ l = 0;
+ if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) {
+ /* sz = pci_size(l, sz, PCI_BASE_ADDRESS_MEM_MASK);
+ if (!sz)
+ continue;
+ res->start = l & PCI_BASE_ADDRESS_MEM_MASK;
+ */ flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK;
+ printf("Memory Resource\n");
+ } else {
+ // sz = pci_size(l, sz, PCI_BASE_ADDRESS_IO_MASK & 0xffff);
+ /// if (!sz)
+ /// continue;
+// res->start = l & PCI_BASE_ADDRESS_IO_MASK;
+ flags |= l & ~PCI_BASE_ADDRESS_IO_MASK;
+ printf("I/O Resource\n");
+ }
+ if (flags & PCI_BASE_ADDRESS_SPACE_IO) {
+ printf("Why is it here\n");
+ flags |= IORESOURCE_IO;
+ } else {
+ printf("here\n");
+//flags &= ~IORESOURCE_IO;
+ }
+
+
+ if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH)
+ flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH;
+
+
+ return flags;
+}
+static int velocity_get_pci_info(struct velocity_info *vptr,
+ struct pci_device *pdev)
+{
+ if (pci_read_config_byte(pdev, PCI_REVISION_ID, &vptr->rev_id) < 0) {
+ printf("DEBUG: pci_read_config_byte failed\n");
+ return -1;
+ }
+
+ adjust_pci_device(pdev);
+
+ vptr->ioaddr = pci_bar_start(pdev, PCI_BASE_ADDRESS_0);
+ vptr->memaddr = pci_bar_start(pdev, PCI_BASE_ADDRESS_1);
+
+ printf("Looking for I/O Resource - Found:");
+ if (!
+ (pci_resource_flags(pdev, PCI_BASE_ADDRESS_0) & IORESOURCE_IO))
+ {
+ printf
+ ("DEBUG: region #0 is not an I/O resource, aborting.\n");
+ return -1;
+ }
+
+ printf("Looking for Memory Resource - Found:");
+ if ((pci_resource_flags(pdev, PCI_BASE_ADDRESS_1) & IORESOURCE_IO)) {
+ printf("DEBUG: region #1 is an I/O resource, aborting.\n");
+ return -1;
+ }
+
+ if (pci_bar_size(pdev, PCI_BASE_ADDRESS_1) < 256) {
+ printf("DEBUG: region #1 is too small.\n");
+ return -1;
+ }
+ vptr->pdev = pdev;
+
+ return 0;
+}
+
+/**
+ * velocity_print_link_status - link status reporting
+ * @vptr: velocity to report on
+ *
+ * Turn the link status of the velocity card into a kernel log
+ * description of the new link state, detailing speed and duplex
+ * status
+ */
+
+static void velocity_print_link_status(struct velocity_info *vptr)
+{
+
+ if (vptr->mii_status & VELOCITY_LINK_FAIL) {
+ printf("failed to detect cable link\n");
+ } else if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
+ printf("Link autonegation");
+
+ if (vptr->mii_status & VELOCITY_SPEED_1000)
+ printf(" speed 1000M bps");
+ else if (vptr->mii_status & VELOCITY_SPEED_100)
+ printf(" speed 100M bps");
+ else
+ printf(" speed 10M bps");
+
+ if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
+ printf(" full duplex\n");
+ else
+ printf(" half duplex\n");
+ } else {
+ printf("Link forced");
+ switch (vptr->options.spd_dpx) {
+ case SPD_DPX_100_HALF:
+ printf(" speed 100M bps half duplex\n");
+ break;
+ case SPD_DPX_100_FULL:
+ printf(" speed 100M bps full duplex\n");
+ break;
+ case SPD_DPX_10_HALF:
+ printf(" speed 10M bps half duplex\n");
+ break;
+ case SPD_DPX_10_FULL:
+ printf(" speed 10M bps full duplex\n");
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/**
+ * velocity_rx_reset - handle a receive reset
+ * @vptr: velocity we are resetting
+ *
+ * Reset the ownership and status for the receive ring side.
+ * Hand all the receive queue to the NIC.
+ */
+
+static void velocity_rx_reset(struct velocity_info *vptr)
+{
+
+ struct mac_regs *regs = vptr->mac_regs;
+ int i;
+
+//ptr->rd_dirty = vptr->rd_filled = vptr->rd_curr = 0;
+
+ /*
+ * Init state, all RD entries belong to the NIC
+ */
+ for (i = 0; i < vptr->options.numrx; ++i)
+ vptr->rd_ring[i].rdesc0.owner = OWNED_BY_NIC;
+
+ writew(RX_DESC_DEF, &regs->RBRDU);
+ writel(virt_to_le32desc(vptr->rd_ring), &regs->RDBaseLo);
+ writew(0, &regs->RDIdx);
+ writew(RX_DESC_DEF - 1, &regs->RDCSize);
+}
+
+/**
+ * velocity_init_registers - initialise MAC registers
+ * @vptr: velocity to init
+ * @type: type of initialisation (hot or cold)
+ *
+ * Initialise the MAC on a reset or on first set up on the
+ * hardware.
+ */
+
+static void velocity_init_registers(struct nic *nic,
+ struct velocity_info *vptr,
+ enum velocity_init_type type)
+{
+ struct mac_regs *regs = vptr->mac_regs;
+ int i, mii_status;
+
+ mac_wol_reset(regs);
+
+ switch (type) {
+ case VELOCITY_INIT_RESET:
+ case VELOCITY_INIT_WOL:
+
+//netif_stop_queue(vptr->dev);
+
+ /*
+ * Reset RX to prevent RX pointer not on the 4X location
+ */
+ velocity_rx_reset(vptr);
+ mac_rx_queue_run(regs);
+ mac_rx_queue_wake(regs);
+
+ mii_status = velocity_get_opt_media_mode(vptr);
+
+ if (velocity_set_media_mode(vptr, mii_status) !=
+ VELOCITY_LINK_CHANGE) {
+ velocity_print_link_status(vptr);
+ if (!(vptr->mii_status & VELOCITY_LINK_FAIL))
+ printf("Link Failed\n");
+// netif_wake_queue(vptr->dev);
+ }
+
+ enable_flow_control_ability(vptr);
+
+ mac_clear_isr(regs);
+ writel(CR0_STOP, &regs->CR0Clr);
+ //writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT),
+ writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT),
+ &regs->CR0Set);
+ break;
+
+ case VELOCITY_INIT_COLD:
+ default:
+ /*
+ * Do reset
+ */
+ velocity_soft_reset(vptr);
+ mdelay(5);
+
+ mac_eeprom_reload(regs);
+ for (i = 0; i < 6; i++) {
+ writeb(nic->node_addr[i], &(regs->PAR[i]));
+ }
+ /*
+ * clear Pre_ACPI bit.
+ */
+ BYTE_REG_BITS_OFF(CFGA_PACPI, &(regs->CFGA));
+ mac_set_rx_thresh(regs, vptr->options.rx_thresh);
+ mac_set_dma_length(regs, vptr->options.DMA_length);
+
+ writeb(WOLCFG_SAM | WOLCFG_SAB, &regs->WOLCFGSet);
+ /*
+ * Back off algorithm use original IEEE standard
+ */
+ BYTE_REG_BITS_SET(CFGB_OFSET,
+ (CFGB_CRANDOM | CFGB_CAP | CFGB_MBA |
+ CFGB_BAKOPT), &regs->CFGB);
+
+ /*
+ * Init CAM filter
+ */
+ velocity_init_cam_filter(vptr);
+
+ /*
+ * Set packet filter: Receive directed and broadcast address
+ */
+//FIXME Multicast velocity_set_multi(nic);
+
+ /*
+ * Enable MII auto-polling
+ */
+ enable_mii_autopoll(regs);
+
+ vptr->int_mask = INT_MASK_DEF;
+
+ writel(virt_to_le32desc(vptr->rd_ring), &regs->RDBaseLo);
+ writew(vptr->options.numrx - 1, &regs->RDCSize);
+ mac_rx_queue_run(regs);
+ mac_rx_queue_wake(regs);
+
+ writew(vptr->options.numtx - 1, &regs->TDCSize);
+
+// for (i = 0; i < vptr->num_txq; i++) {
+ writel(virt_to_le32desc(vptr->td_rings),
+ &(regs->TDBaseLo[0]));
+ mac_tx_queue_run(regs, 0);
+// }
+
+ init_flow_control_register(vptr);
+
+ writel(CR0_STOP, &regs->CR0Clr);
+ writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT),
+ &regs->CR0Set);
+
+ mii_status = velocity_get_opt_media_mode(vptr);
+// netif_stop_queue(vptr->dev);
+
+ mii_init(vptr, mii_status);
+
+ if (velocity_set_media_mode(vptr, mii_status) !=
+ VELOCITY_LINK_CHANGE) {
+ velocity_print_link_status(vptr);
+ if (!(vptr->mii_status & VELOCITY_LINK_FAIL))
+ printf("Link Faaailll\n");
+// netif_wake_queue(vptr->dev);
+ }
+
+ enable_flow_control_ability(vptr);
+ mac_hw_mibs_init(regs);
+ mac_write_int_mask(vptr->int_mask, regs);
+ mac_clear_isr(regs);
+
+
+ }
+ velocity_print_link_status(vptr);
+}
+
+/**
+ * velocity_soft_reset - soft reset
+ * @vptr: velocity to reset
+ *
+ * Kick off a soft reset of the velocity adapter and then poll
+ * until the reset sequence has completed before returning.
+ */
+
+static int velocity_soft_reset(struct velocity_info *vptr)
+{
+ struct mac_regs *regs = vptr->mac_regs;
+ unsigned int i = 0;
+
+ writel(CR0_SFRST, &regs->CR0Set);
+
+ for (i = 0; i < W_MAX_TIMEOUT; i++) {
+ udelay(5);
+ if (!DWORD_REG_BITS_IS_ON(CR0_SFRST, &regs->CR0Set))
+ break;
+ }
+
+ if (i == W_MAX_TIMEOUT) {
+ writel(CR0_FORSRST, &regs->CR0Set);
+ /* FIXME: PCI POSTING */
+ /* delay 2ms */
+ mdelay(2);
+ }
+ return 0;
+}
+
+/**
+ * velocity_init_rings - set up DMA rings
+ * @vptr: Velocity to set up
+ *
+ * Allocate PCI mapped DMA rings for the receive and transmit layer
+ * to use.
+ */
+
+static int velocity_init_rings(struct velocity_info *vptr)
+{
+
+ int idx;
+
+ vptr->rd_curr = 0;
+ vptr->td_curr = 0;
+ memset(vptr->td_rings, 0, TX_DESC_DEF * sizeof(struct tx_desc));
+ memset(vptr->rd_ring, 0, RX_DESC_DEF * sizeof(struct rx_desc));
+// memset(vptr->tx_buffs, 0, TX_DESC_DEF * PKT_BUF_SZ);
+
+
+ for (idx = 0; idx < RX_DESC_DEF; idx++) {
+ *((u32 *) & (vptr->rd_ring[idx].rdesc0)) = 0;
+ vptr->rd_ring[idx].len = cpu_to_le32(vptr->rx_buf_sz);
+ vptr->rd_ring[idx].inten = 1;
+ vptr->rd_ring[idx].pa_low =
+ virt_to_bus(vptr->rxb + (RX_DESC_DEF * idx));
+ vptr->rd_ring[idx].pa_high = 0;
+ vptr->rd_ring[idx].rdesc0.owner = OWNED_BY_NIC;
+
+ }
+
+/* for (i = 0; idx < TX_DESC_DEF; idx++ ) {
+ vptr->td_rings[idx].tdesc1.TCPLS = TCPLS_NORMAL;
+ vptr->td_rings[idx].tdesc1.TCR = TCR0_TIC;
+ vptr->td_rings[idx].td_buf[0].queue = 0;
+ vptr->td_rings[idx].tdesc0.owner = ~OWNED_BY_NIC;
+ vptr->td_rings[idx].tdesc0.pktsize = 0;
+ vptr->td_rings[idx].td_buf[0].pa_low = cpu_to_le32(virt_to_bus(vptr->txb + (idx * PKT_BUF_SZ)));
+ vptr->td_rings[idx].td_buf[0].pa_high = 0;
+ vptr->td_rings[idx].td_buf[0].bufsize = 0;
+ vptr->td_rings[idx].tdesc1.CMDZ = 2;
+ }
+*/
+ return 0;
+}
+
+/**
+ * velocity_open - interface activation callback
+ * @dev: network layer device to open
+ *
+ * Called when the network layer brings the interface up. Returns
+ * a negative posix error code on failure, or zero on success.
+ *
+ * All the ring allocation and set up is done on open for this
+ * adapter to minimise memory usage when inactive
+ */
+
+#define PCI_BYTE_REG_BITS_ON(x,i,p) do{\
+ u8 byReg;\
+ pci_read_config_byte((p), (i), &(byReg));\
+ (byReg) |= (x);\
+ pci_write_config_byte((p), (i), (byReg));\
+} while (0)
+
+//
+// Registers in the PCI configuration space
+//
+#define PCI_REG_COMMAND 0x04 //
+#define PCI_REG_MODE0 0x60 //
+#define PCI_REG_MODE1 0x61 //
+#define PCI_REG_MODE2 0x62 //
+#define PCI_REG_MODE3 0x63 //
+#define PCI_REG_DELAY_TIMER 0x64 //
+
+// Bits in the (MODE2, 0x62) register
+//
+#define MODE2_PCEROPT 0x80 // take PCI bus ERror as a fatal and shutdown from software control
+#define MODE2_TXQ16 0x40 // TX write-back Queue control. 0->32 entries available in Tx write-back queue, 1->16 entries
+#define MODE2_TXPOST 0x08 // (Not support in VT3119)
+#define MODE2_AUTOOPT 0x04 // (VT3119 GHCI without such behavior)
+#define MODE2_MODE10T 0x02 // used to control tx Threshold for 10M case
+#define MODE2_TCPLSOPT 0x01 // TCP large send field update disable, hardware will not update related fields, leave it to software.
+
+//
+// Bits in the MODE3 register
+//
+#define MODE3_MIION 0x04 // MII symbol codine error detect enable ??
+
+// Bits in the (COMMAND, 0x04) register
+#define COMMAND_BUSM 0x04
+#define COMMAND_WAIT 0x80
+static int velocity_open(struct nic *nic, struct pci_device *pci __unused)
+{
+ int ret;
+
+ u8 diff;
+ u32 TxPhyAddr, RxPhyAddr;
+ u32 TxBufPhyAddr, RxBufPhyAddr;
+ vptr->TxDescArrays = tx_ring;
+ if (vptr->TxDescArrays == 0)
+ printf("Allot Error");
+
+ /* Tx Descriptor needs 64 bytes alignment; */
+ TxPhyAddr = virt_to_bus(vptr->TxDescArrays);
+ printf("Unaligned Address : %lX\n", TxPhyAddr);
+ diff = 64 - (TxPhyAddr - ((TxPhyAddr >> 6) << 6));
+ TxPhyAddr += diff;
+ vptr->td_rings = (struct tx_desc *) (vptr->TxDescArrays + diff);
+
+ printf("Aligned Address: %lX\n", virt_to_bus(vptr->td_rings));
+ vptr->tx_buffs = txb;
+ /* Rx Buffer needs 64 bytes alignment; */
+ TxBufPhyAddr = virt_to_bus(vptr->tx_buffs);
+ diff = 64 - (TxBufPhyAddr - ((TxBufPhyAddr >> 6) << 6));
+ TxBufPhyAddr += diff;
+ vptr->txb = (unsigned char *) (vptr->tx_buffs + diff);
+
+ vptr->RxDescArrays = rx_ring;
+ /* Rx Descriptor needs 64 bytes alignment; */
+ RxPhyAddr = virt_to_bus(vptr->RxDescArrays);
+ diff = 64 - (RxPhyAddr - ((RxPhyAddr >> 6) << 6));
+ RxPhyAddr += diff;
+ vptr->rd_ring = (struct rx_desc *) (vptr->RxDescArrays + diff);
+
+ vptr->rx_buffs = rxb;
+ /* Rx Buffer needs 64 bytes alignment; */
+ RxBufPhyAddr = virt_to_bus(vptr->rx_buffs);
+ diff = 64 - (RxBufPhyAddr - ((RxBufPhyAddr >> 6) << 6));
+ RxBufPhyAddr += diff;
+ vptr->rxb = (unsigned char *) (vptr->rx_buffs + diff);
+
+ if (vptr->RxDescArrays == NULL || vptr->RxDescArrays == NULL) {
+ printf("Allocate tx_ring or rd_ring failed\n");
+ return 0;
+ }
+
+ vptr->rx_buf_sz = PKT_BUF_SZ;
+/*
+ // turn this on to avoid retry forever
+ PCI_BYTE_REG_BITS_ON(MODE2_PCEROPT, PCI_REG_MODE2, pci);
+ // for some legacy BIOS and OS don't open BusM
+ // bit in PCI configuration space. So, turn it on.
+ PCI_BYTE_REG_BITS_ON(COMMAND_BUSM, PCI_REG_COMMAND, pci);
+ // turn this on to detect MII coding error
+ PCI_BYTE_REG_BITS_ON(MODE3_MIION, PCI_REG_MODE3, pci);
+ */
+ ret = velocity_init_rings(vptr);
+
+ /* Ensure chip is running */
+//FIXME: pci_set_power_state(vptr->pdev, PCI_D0);
+
+ velocity_init_registers(nic, vptr, VELOCITY_INIT_COLD);
+ mac_write_int_mask(0, vptr->mac_regs);
+// _int(vptr->mac_regs);
+ //mac_enable_int(vptr->mac_regs);
+
+ vptr->flags |= VELOCITY_FLAGS_OPENED;
+ return 1;
+
+}
+
+/*
+ * MII access , media link mode setting functions
+ */
+
+
+/**
+ * mii_init - set up MII
+ * @vptr: velocity adapter
+ * @mii_status: links tatus
+ *
+ * Set up the PHY for the current link state.
+ */
+
+static void mii_init(struct velocity_info *vptr, u32 mii_status __unused)
+{
+ u16 BMCR;
+
+ switch (PHYID_GET_PHY_ID(vptr->phy_id)) {
+ case PHYID_CICADA_CS8201:
+ /*
+ * Reset to hardware default
+ */
+ MII_REG_BITS_OFF((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR,
+ vptr->mac_regs);
+ /*
+ * Turn on ECHODIS bit in NWay-forced full mode and turn it
+ * off it in NWay-forced half mode for NWay-forced v.s.
+ * legacy-forced issue.
+ */
+ if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
+ MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR,
+ vptr->mac_regs);
+ else
+ MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR,
+ vptr->mac_regs);
+ /*
+ * Turn on Link/Activity LED enable bit for CIS8201
+ */
+ MII_REG_BITS_ON(PLED_LALBE, MII_REG_PLED, vptr->mac_regs);
+ break;
+ case PHYID_VT3216_32BIT:
+ case PHYID_VT3216_64BIT:
+ /*
+ * Reset to hardware default
+ */
+ MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR,
+ vptr->mac_regs);
+ /*
+ * Turn on ECHODIS bit in NWay-forced full mode and turn it
+ * off it in NWay-forced half mode for NWay-forced v.s.
+ * legacy-forced issue
+ */
+ if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
+ MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR,
+ vptr->mac_regs);
+ else
+ MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR,
+ vptr->mac_regs);
+ break;
+
+ case PHYID_MARVELL_1000:
+ case PHYID_MARVELL_1000S:
+ /*
+ * Assert CRS on Transmit
+ */
+ MII_REG_BITS_ON(PSCR_ACRSTX, MII_REG_PSCR, vptr->mac_regs);
+ /*
+ * Reset to hardware default
+ */
+ MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR,
+ vptr->mac_regs);
+ break;
+ default:
+ ;
+ }
+ velocity_mii_read(vptr->mac_regs, MII_REG_BMCR, &BMCR);
+ if (BMCR & BMCR_ISO) {
+ BMCR &= ~BMCR_ISO;
+ velocity_mii_write(vptr->mac_regs, MII_REG_BMCR, BMCR);
+ }
+}
+
+/**
+ * safe_disable_mii_autopoll - autopoll off
+ * @regs: velocity registers
+ *
+ * Turn off the autopoll and wait for it to disable on the chip
+ */
+
+static void safe_disable_mii_autopoll(struct mac_regs *regs)
+{
+ u16 ww;
+
+ /* turn off MAUTO */
+ writeb(0, &regs->MIICR);
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ udelay(1);
+ if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
+ break;
+ }
+}
+
+/**
+ * enable_mii_autopoll - turn on autopolling
+ * @regs: velocity registers
+ *
+ * Enable the MII link status autopoll feature on the Velocity
+ * hardware. Wait for it to enable.
+ */
+
+static void enable_mii_autopoll(struct mac_regs *regs)
+{
+ unsigned int ii;
+
+ writeb(0, &(regs->MIICR));
+ writeb(MIIADR_SWMPL, &regs->MIIADR);
+
+ for (ii = 0; ii < W_MAX_TIMEOUT; ii++) {
+ udelay(1);
+ if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
+ break;
+ }
+
+ writeb(MIICR_MAUTO, &regs->MIICR);
+
+ for (ii = 0; ii < W_MAX_TIMEOUT; ii++) {
+ udelay(1);
+ if (!BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
+ break;
+ }
+
+}
+
+/**
+ * velocity_mii_read - read MII data
+ * @regs: velocity registers
+ * @index: MII register index
+ * @data: buffer for received data
+ *
+ * Perform a single read of an MII 16bit register. Returns zero
+ * on success or -ETIMEDOUT if the PHY did not respond.
+ */
+
+static int velocity_mii_read(struct mac_regs *regs, u8 index, u16 * data)
+{
+ u16 ww;
+
+ /*
+ * Disable MIICR_MAUTO, so that mii addr can be set normally
+ */
+ safe_disable_mii_autopoll(regs);
+
+ writeb(index, &regs->MIIADR);
+
+ BYTE_REG_BITS_ON(MIICR_RCMD, &regs->MIICR);
+
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ if (!(readb(&regs->MIICR) & MIICR_RCMD))
+ break;
+ }
+
+ *data = readw(&regs->MIIDATA);
+
+ enable_mii_autopoll(regs);
+ if (ww == W_MAX_TIMEOUT)
+ return -1;
+ return 0;
+}
+
+/**
+ * velocity_mii_write - write MII data
+ * @regs: velocity registers
+ * @index: MII register index
+ * @data: 16bit data for the MII register
+ *
+ * Perform a single write to an MII 16bit register. Returns zero
+ * on success or -ETIMEDOUT if the PHY did not respond.
+ */
+
+static int velocity_mii_write(struct mac_regs *regs, u8 mii_addr, u16 data)
+{
+ u16 ww;
+
+ /*
+ * Disable MIICR_MAUTO, so that mii addr can be set normally
+ */
+ safe_disable_mii_autopoll(regs);
+
+ /* MII reg offset */
+ writeb(mii_addr, &regs->MIIADR);
+ /* set MII data */
+ writew(data, &regs->MIIDATA);
+
+ /* turn on MIICR_WCMD */
+ BYTE_REG_BITS_ON(MIICR_WCMD, &regs->MIICR);
+
+ /* W_MAX_TIMEOUT is the timeout period */
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ udelay(5);
+ if (!(readb(&regs->MIICR) & MIICR_WCMD))
+ break;
+ }
+ enable_mii_autopoll(regs);
+
+ if (ww == W_MAX_TIMEOUT)
+ return -1;
+ return 0;
+}
+
+/**
+ * velocity_get_opt_media_mode - get media selection
+ * @vptr: velocity adapter
+ *
+ * Get the media mode stored in EEPROM or module options and load
+ * mii_status accordingly. The requested link state information
+ * is also returned.
+ */
+
+static u32 velocity_get_opt_media_mode(struct velocity_info *vptr)
+{
+ u32 status = 0;
+
+ switch (vptr->options.spd_dpx) {
+ case SPD_DPX_AUTO:
+ status = VELOCITY_AUTONEG_ENABLE;
+ break;
+ case SPD_DPX_100_FULL:
+ status = VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL;
+ break;
+ case SPD_DPX_10_FULL:
+ status = VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL;
+ break;
+ case SPD_DPX_100_HALF:
+ status = VELOCITY_SPEED_100;
+ break;
+ case SPD_DPX_10_HALF:
+ status = VELOCITY_SPEED_10;
+ break;
+ }
+ vptr->mii_status = status;
+ return status;
+}
+
+/**
+ * mii_set_auto_on - autonegotiate on
+ * @vptr: velocity
+ *
+ * Enable autonegotation on this interface
+ */
+
+static void mii_set_auto_on(struct velocity_info *vptr)
+{
+ if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs))
+ MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs);
+ else
+ MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs);
+}
+
+
+/*
+static void mii_set_auto_off(struct velocity_info * vptr)
+{
+ MII_REG_BITS_OFF(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs);
+}
+*/
+
+/**
+ * set_mii_flow_control - flow control setup
+ * @vptr: velocity interface
+ *
+ * Set up the flow control on this interface according to
+ * the supplied user/eeprom options.
+ */
+
+static void set_mii_flow_control(struct velocity_info *vptr)
+{
+ /*Enable or Disable PAUSE in ANAR */
+ switch (vptr->options.flow_cntl) {
+ case FLOW_CNTL_TX:
+ MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+ MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+ break;
+
+ case FLOW_CNTL_RX:
+ MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+ MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+ break;
+
+ case FLOW_CNTL_TX_RX:
+ MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+ MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+ break;
+
+ case FLOW_CNTL_DISABLE:
+ MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+ MII_REG_BITS_OFF(ANAR_ASMDIR, MII_REG_ANAR,
+ vptr->mac_regs);
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * velocity_set_media_mode - set media mode
+ * @mii_status: old MII link state
+ *
+ * Check the media link state and configure the flow control
+ * PHY and also velocity hardware setup accordingly. In particular
+ * we need to set up CD polling and frame bursting.
+ */
+
+static int velocity_set_media_mode(struct velocity_info *vptr,
+ u32 mii_status)
+{
+ u32 curr_status;
+ struct mac_regs *regs = vptr->mac_regs;
+
+ vptr->mii_status = mii_check_media_mode(vptr->mac_regs);
+ curr_status = vptr->mii_status & (~VELOCITY_LINK_FAIL);
+
+ /* Set mii link status */
+ set_mii_flow_control(vptr);
+
+ /*
+ Check if new status is consisent with current status
+ if (((mii_status & curr_status) & VELOCITY_AUTONEG_ENABLE)
+ || (mii_status==curr_status)) {
+ vptr->mii_status=mii_check_media_mode(vptr->mac_regs);
+ vptr->mii_status=check_connection_type(vptr->mac_regs);
+ printf(MSG_LEVEL_INFO, "Velocity link no change\n");
+ return 0;
+ }
+ */
+
+ if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201) {
+ MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR,
+ vptr->mac_regs);
+ }
+
+ /*
+ * If connection type is AUTO
+ */
+ if (mii_status & VELOCITY_AUTONEG_ENABLE) {
+ printf("Velocity is AUTO mode\n");
+ /* clear force MAC mode bit */
+ BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, &regs->CHIPGCR);
+ /* set duplex mode of MAC according to duplex mode of MII */
+ MII_REG_BITS_ON(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10,
+ MII_REG_ANAR, vptr->mac_regs);
+ MII_REG_BITS_ON(G1000CR_1000FD | G1000CR_1000,
+ MII_REG_G1000CR, vptr->mac_regs);
+ MII_REG_BITS_ON(BMCR_SPEED1G, MII_REG_BMCR,
+ vptr->mac_regs);
+
+ /* enable AUTO-NEGO mode */
+ mii_set_auto_on(vptr);
+ } else {
+ u16 ANAR;
+ u8 CHIPGCR;
+
+ /*
+ * 1. if it's 3119, disable frame bursting in halfduplex mode
+ * and enable it in fullduplex mode
+ * 2. set correct MII/GMII and half/full duplex mode in CHIPGCR
+ * 3. only enable CD heart beat counter in 10HD mode
+ */
+
+ /* set force MAC mode bit */
+ BYTE_REG_BITS_ON(CHIPGCR_FCMODE, &regs->CHIPGCR);
+
+ CHIPGCR = readb(&regs->CHIPGCR);
+ CHIPGCR &= ~CHIPGCR_FCGMII;
+
+ if (mii_status & VELOCITY_DUPLEX_FULL) {
+ CHIPGCR |= CHIPGCR_FCFDX;
+ writeb(CHIPGCR, &regs->CHIPGCR);
+ printf
+ ("DEBUG: set Velocity to forced full mode\n");
+ if (vptr->rev_id < REV_ID_VT3216_A0)
+ BYTE_REG_BITS_OFF(TCR_TB2BDIS, &regs->TCR);
+ } else {
+ CHIPGCR &= ~CHIPGCR_FCFDX;
+ printf
+ ("DEBUG: set Velocity to forced half mode\n");
+ writeb(CHIPGCR, &regs->CHIPGCR);
+ if (vptr->rev_id < REV_ID_VT3216_A0)
+ BYTE_REG_BITS_ON(TCR_TB2BDIS, &regs->TCR);
+ }
+
+ MII_REG_BITS_OFF(G1000CR_1000FD | G1000CR_1000,
+ MII_REG_G1000CR, vptr->mac_regs);
+
+ if (!(mii_status & VELOCITY_DUPLEX_FULL)
+ && (mii_status & VELOCITY_SPEED_10)) {
+ BYTE_REG_BITS_OFF(TESTCFG_HBDIS, &regs->TESTCFG);
+ } else {
+ BYTE_REG_BITS_ON(TESTCFG_HBDIS, &regs->TESTCFG);
+ }
+ /* MII_REG_BITS_OFF(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs); */
+ velocity_mii_read(vptr->mac_regs, MII_REG_ANAR, &ANAR);
+ ANAR &= (~(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10));
+ if (mii_status & VELOCITY_SPEED_100) {
+ if (mii_status & VELOCITY_DUPLEX_FULL)
+ ANAR |= ANAR_TXFD;
+ else
+ ANAR |= ANAR_TX;
+ } else {
+ if (mii_status & VELOCITY_DUPLEX_FULL)
+ ANAR |= ANAR_10FD;
+ else
+ ANAR |= ANAR_10;
+ }
+ velocity_mii_write(vptr->mac_regs, MII_REG_ANAR, ANAR);
+ /* enable AUTO-NEGO mode */
+ mii_set_auto_on(vptr);
+ /* MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); */
+ }
+ /* vptr->mii_status=mii_check_media_mode(vptr->mac_regs); */
+ /* vptr->mii_status=check_connection_type(vptr->mac_regs); */
+ return VELOCITY_LINK_CHANGE;
+}
+
+/**
+ * mii_check_media_mode - check media state
+ * @regs: velocity registers
+ *
+ * Check the current MII status and determine the link status
+ * accordingly
+ */
+
+static u32 mii_check_media_mode(struct mac_regs *regs)
+{
+ u32 status = 0;
+ u16 ANAR;
+
+ if (!MII_REG_BITS_IS_ON(BMSR_LNK, MII_REG_BMSR, regs))
+ status |= VELOCITY_LINK_FAIL;
+
+ if (MII_REG_BITS_IS_ON(G1000CR_1000FD, MII_REG_G1000CR, regs))
+ status |= VELOCITY_SPEED_1000 | VELOCITY_DUPLEX_FULL;
+ else if (MII_REG_BITS_IS_ON(G1000CR_1000, MII_REG_G1000CR, regs))
+ status |= (VELOCITY_SPEED_1000);
+ else {
+ velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
+ if (ANAR & ANAR_TXFD)
+ status |=
+ (VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL);
+ else if (ANAR & ANAR_TX)
+ status |= VELOCITY_SPEED_100;
+ else if (ANAR & ANAR_10FD)
+ status |=
+ (VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL);
+ else
+ status |= (VELOCITY_SPEED_10);
+ }
+
+ if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) {
+ velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
+ if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10))
+ == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) {
+ if (MII_REG_BITS_IS_ON
+ (G1000CR_1000 | G1000CR_1000FD,
+ MII_REG_G1000CR, regs))
+ status |= VELOCITY_AUTONEG_ENABLE;
+ }
+ }
+
+ return status;
+}
+
+static u32 check_connection_type(struct mac_regs *regs)
+{
+ u32 status = 0;
+ u8 PHYSR0;
+ u16 ANAR;
+ PHYSR0 = readb(&regs->PHYSR0);
+
+ /*
+ if (!(PHYSR0 & PHYSR0_LINKGD))
+ status|=VELOCITY_LINK_FAIL;
+ */
+
+ if (PHYSR0 & PHYSR0_FDPX)
+ status |= VELOCITY_DUPLEX_FULL;
+
+ if (PHYSR0 & PHYSR0_SPDG)
+ status |= VELOCITY_SPEED_1000;
+ if (PHYSR0 & PHYSR0_SPD10)
+ status |= VELOCITY_SPEED_10;
+ else
+ status |= VELOCITY_SPEED_100;
+
+ if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) {
+ velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
+ if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10))
+ == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) {
+ if (MII_REG_BITS_IS_ON
+ (G1000CR_1000 | G1000CR_1000FD,
+ MII_REG_G1000CR, regs))
+ status |= VELOCITY_AUTONEG_ENABLE;
+ }
+ }
+
+ return status;
+}
+
+/**
+ * enable_flow_control_ability - flow control
+ * @vptr: veloity to configure
+ *
+ * Set up flow control according to the flow control options
+ * determined by the eeprom/configuration.
+ */
+
+static void enable_flow_control_ability(struct velocity_info *vptr)
+{
+
+ struct mac_regs *regs = vptr->mac_regs;
+
+ switch (vptr->options.flow_cntl) {
+
+ case FLOW_CNTL_DEFAULT:
+ if (BYTE_REG_BITS_IS_ON(PHYSR0_RXFLC, &regs->PHYSR0))
+ writel(CR0_FDXRFCEN, &regs->CR0Set);
+ else
+ writel(CR0_FDXRFCEN, &regs->CR0Clr);
+
+ if (BYTE_REG_BITS_IS_ON(PHYSR0_TXFLC, &regs->PHYSR0))
+ writel(CR0_FDXTFCEN, &regs->CR0Set);
+ else
+ writel(CR0_FDXTFCEN, &regs->CR0Clr);
+ break;
+
+ case FLOW_CNTL_TX:
+ writel(CR0_FDXTFCEN, &regs->CR0Set);
+ writel(CR0_FDXRFCEN, &regs->CR0Clr);
+ break;
+
+ case FLOW_CNTL_RX:
+ writel(CR0_FDXRFCEN, &regs->CR0Set);
+ writel(CR0_FDXTFCEN, &regs->CR0Clr);
+ break;
+
+ case FLOW_CNTL_TX_RX:
+ writel(CR0_FDXTFCEN, &regs->CR0Set);
+ writel(CR0_FDXRFCEN, &regs->CR0Set);
+ break;
+
+ case FLOW_CNTL_DISABLE:
+ writel(CR0_FDXRFCEN, &regs->CR0Clr);
+ writel(CR0_FDXTFCEN, &regs->CR0Clr);
+ break;
+
+ default:
+ break;
+ }
+
+}
+
+/* FIXME: Move to pci.c */
+/**
+ * pci_set_power_state - Set the power state of a PCI device
+ * @dev: PCI device to be suspended
+ * @state: Power state we're entering
+ *
+ * Transition a device to a new power state, using the Power Management
+ * Capabilities in the device's config space.
+ *
+ * RETURN VALUE:
+ * -EINVAL if trying to enter a lower state than we're already in.
+ * 0 if we're already in the requested state.
+ * -EIO if device does not support PCI PM.
+ * 0 if we can successfully change the power state.
+ */
+
+int pci_set_power_state(struct pci_device *dev, int state)
+{
+ int pm;
+ u16 pmcsr;
+ int current_state = 0;
+
+ /* bound the state we're entering */
+ if (state > 3)
+ state = 3;
+
+ /* Validate current state:
+ * Can enter D0 from any state, but if we can only go deeper
+ * to sleep if we're already in a low power state
+ */
+ if (state > 0 && current_state > state)
+ return -1;
+ else if (current_state == state)
+ return 0; /* we're already there */
+
+ /* find PCI PM capability in list */
+ pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+
+ /* abort if the device doesn't support PM capabilities */
+ if (!pm)
+ return -2;
+
+ /* check if this device supports the desired state */
+ if (state == 1 || state == 2) {
+ u16 pmc;
+ pci_read_config_word(dev, pm + PCI_PM_PMC, &pmc);
+ if (state == 1 && !(pmc & PCI_PM_CAP_D1))
+ return -2;
+ else if (state == 2 && !(pmc & PCI_PM_CAP_D2))
+ return -2;
+ }
+
+ /* If we're in D3, force entire word to 0.
+ * This doesn't affect PME_Status, disables PME_En, and
+ * sets PowerState to 0.
+ */
+ if (current_state >= 3)
+ pmcsr = 0;
+ else {
+ pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr);
+ pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
+ pmcsr |= state;
+ }
+
+ /* enter specified state */
+ pci_write_config_word(dev, pm + PCI_PM_CTRL, pmcsr);
+
+ /* Mandatory power management transition delays */
+ /* see PCI PM 1.1 5.6.1 table 18 */
+ if (state == 3 || current_state == 3)
+ mdelay(10);
+ else if (state == 2 || current_state == 2)
+ udelay(200);
+ current_state = state;
+
+ return 0;
+}
+
+static struct pci_id velocity_nics[] = {
+ PCI_ROM(0x1106, 0x3119, "via-velocity", "VIA Networking Velocity Family Gigabit Ethernet Adapter"),
+};
+
+static struct pci_driver velocity_driver __pci_driver = {
+ .type = NIC_DRIVER,
+ .name = "VIA-VELOCITY/PCI",
+ .probe = velocity_probe,
+ .ids = velocity_nics,
+ .id_count = sizeof(velocity_nics) / sizeof(velocity_nics[0]),
+ .class = 0,
+};
diff --git a/src/drivers/net/via-velocity.h b/src/drivers/net/via-velocity.h
new file mode 100644
index 000000000..a6c132dcc
--- /dev/null
+++ b/src/drivers/net/via-velocity.h
@@ -0,0 +1,1938 @@
+#define EB54 1
+/*
+ * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
+ * All rights reserved.
+ *
+ * This software may be redistributed and/or modified under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or
+ * 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.
+ *
+ * File: via-velocity.h
+ *
+ * Purpose: Header file to define driver's private structures.
+ *
+ * Author: Chuang Liang-Shing, AJ Jiang
+ *
+ * Date: Jan 24, 2003
+ *
+ * Changes for Etherboot Port:
+ * Copyright (c) 2006 by Timothy Legge <tlegge@rogers.com>
+ */
+
+#include "timer.h"
+
+#ifndef EB54
+typedef unsigned char u8;
+typedef signed char s8;
+typedef unsigned short u16;
+typedef signed short s16;
+typedef unsigned int u32;
+typedef signed int s32;
+#endif
+#ifndef VELOCITY_H
+#define VELOCITY_H
+
+#define VELOCITY_TX_CSUM_SUPPORT
+
+#define VELOCITY_NAME "via-velocity"
+#define VELOCITY_FULL_DRV_NAM "VIA Networking Velocity Family Gigabit Ethernet Adapter Driver"
+#define VELOCITY_VERSION "1.13"
+
+#define PKT_BUF_SZ 1564
+
+#define MAX_UNITS 8
+#define OPTION_DEFAULT { [0 ... MAX_UNITS-1] = -1}
+
+#define REV_ID_VT6110 (0)
+
+#define BYTE_REG_BITS_ON(x,p) do { writeb(readb((p))|(x),(p));} while (0)
+#define WORD_REG_BITS_ON(x,p) do { writew(readw((p))|(x),(p));} while (0)
+#define DWORD_REG_BITS_ON(x,p) do { writel(readl((p))|(x),(p));} while (0)
+
+#define BYTE_REG_BITS_IS_ON(x,p) (readb((p)) & (x))
+#define WORD_REG_BITS_IS_ON(x,p) (readw((p)) & (x))
+#define DWORD_REG_BITS_IS_ON(x,p) (readl((p)) & (x))
+
+#define BYTE_REG_BITS_OFF(x,p) do { writeb(readb((p)) & (~(x)),(p));} while (0)
+#define WORD_REG_BITS_OFF(x,p) do { writew(readw((p)) & (~(x)),(p));} while (0)
+#define DWORD_REG_BITS_OFF(x,p) do { writel(readl((p)) & (~(x)),(p));} while (0)
+
+#define BYTE_REG_BITS_SET(x,m,p) do { writeb( (readb((p)) & (~(m))) |(x),(p));} while (0)
+#define WORD_REG_BITS_SET(x,m,p) do { writew( (readw((p)) & (~(m))) |(x),(p));} while (0)
+#define DWORD_REG_BITS_SET(x,m,p) do { writel( (readl((p)) & (~(m)))|(x),(p));} while (0)
+
+#define VAR_USED(p) do {(p)=(p);} while (0)
+
+/*
+ * Purpose: Structures for MAX RX/TX descriptors.
+ */
+
+
+#define B_OWNED_BY_CHIP 1
+#define B_OWNED_BY_HOST 0
+
+/*
+ * Bits in the RSR0 register
+ */
+
+#define RSR_DETAG 0x0080
+#define RSR_SNTAG 0x0040
+#define RSR_RXER 0x0020
+#define RSR_RL 0x0010
+#define RSR_CE 0x0008
+#define RSR_FAE 0x0004
+#define RSR_CRC 0x0002
+#define RSR_VIDM 0x0001
+
+/*
+ * Bits in the RSR1 register
+ */
+
+#define RSR_RXOK 0x8000 // rx OK
+#define RSR_PFT 0x4000 // Perfect filtering address match
+#define RSR_MAR 0x2000 // MAC accept multicast address packet
+#define RSR_BAR 0x1000 // MAC accept broadcast address packet
+#define RSR_PHY 0x0800 // MAC accept physical address packet
+#define RSR_VTAG 0x0400 // 802.1p/1q tagging packet indicator
+#define RSR_STP 0x0200 // start of packet
+#define RSR_EDP 0x0100 // end of packet
+
+/*
+ * Bits in the RSR1 register
+ */
+
+#define RSR1_RXOK 0x80 // rx OK
+#define RSR1_PFT 0x40 // Perfect filtering address match
+#define RSR1_MAR 0x20 // MAC accept multicast address packet
+#define RSR1_BAR 0x10 // MAC accept broadcast address packet
+#define RSR1_PHY 0x08 // MAC accept physical address packet
+#define RSR1_VTAG 0x04 // 802.1p/1q tagging packet indicator
+#define RSR1_STP 0x02 // start of packet
+#define RSR1_EDP 0x01 // end of packet
+
+/*
+ * Bits in the CSM register
+ */
+
+#define CSM_IPOK 0x40 //IP Checkusm validatiaon ok
+#define CSM_TUPOK 0x20 //TCP/UDP Checkusm validatiaon ok
+#define CSM_FRAG 0x10 //Fragment IP datagram
+#define CSM_IPKT 0x04 //Received an IP packet
+#define CSM_TCPKT 0x02 //Received a TCP packet
+#define CSM_UDPKT 0x01 //Received a UDP packet
+
+/*
+ * Bits in the TSR0 register
+ */
+
+#define TSR0_ABT 0x0080 // Tx abort because of excessive collision
+#define TSR0_OWT 0x0040 // Jumbo frame Tx abort
+#define TSR0_OWC 0x0020 // Out of window collision
+#define TSR0_COLS 0x0010 // experience collision in this transmit event
+#define TSR0_NCR3 0x0008 // collision retry counter[3]
+#define TSR0_NCR2 0x0004 // collision retry counter[2]
+#define TSR0_NCR1 0x0002 // collision retry counter[1]
+#define TSR0_NCR0 0x0001 // collision retry counter[0]
+#define TSR0_TERR 0x8000 //
+#define TSR0_FDX 0x4000 // current transaction is serviced by full duplex mode
+#define TSR0_GMII 0x2000 // current transaction is serviced by GMII mode
+#define TSR0_LNKFL 0x1000 // packet serviced during link down
+#define TSR0_SHDN 0x0400 // shutdown case
+#define TSR0_CRS 0x0200 // carrier sense lost
+#define TSR0_CDH 0x0100 // AQE test fail (CD heartbeat)
+
+/*
+ * Bits in the TSR1 register
+ */
+
+#define TSR1_TERR 0x80 //
+#define TSR1_FDX 0x40 // current transaction is serviced by full duplex mode
+#define TSR1_GMII 0x20 // current transaction is serviced by GMII mode
+#define TSR1_LNKFL 0x10 // packet serviced during link down
+#define TSR1_SHDN 0x04 // shutdown case
+#define TSR1_CRS 0x02 // carrier sense lost
+#define TSR1_CDH 0x01 // AQE test fail (CD heartbeat)
+
+//
+// Bits in the TCR0 register
+//
+#define TCR0_TIC 0x80 // assert interrupt immediately while descriptor has been send complete
+#define TCR0_PIC 0x40 // priority interrupt request, INA# is issued over adaptive interrupt scheme
+#define TCR0_VETAG 0x20 // enable VLAN tag
+#define TCR0_IPCK 0x10 // request IP checksum calculation.
+#define TCR0_UDPCK 0x08 // request UDP checksum calculation.
+#define TCR0_TCPCK 0x04 // request TCP checksum calculation.
+#define TCR0_JMBO 0x02 // indicate a jumbo packet in GMAC side
+#define TCR0_CRC 0x01 // disable CRC generation
+
+#define TCPLS_NORMAL 3
+#define TCPLS_START 2
+#define TCPLS_END 1
+#define TCPLS_MED 0
+
+
+// max transmit or receive buffer size
+#define CB_RX_BUF_SIZE 2048UL // max buffer size
+ // NOTE: must be multiple of 4
+
+#define CB_MAX_RD_NUM 512 // MAX # of RD
+#define CB_MAX_TD_NUM 256 // MAX # of TD
+
+#define CB_INIT_RD_NUM_3119 128 // init # of RD, for setup VT3119
+#define CB_INIT_TD_NUM_3119 64 // init # of TD, for setup VT3119
+
+#define CB_INIT_RD_NUM 128 // init # of RD, for setup default
+#define CB_INIT_TD_NUM 64 // init # of TD, for setup default
+
+// for 3119
+#define CB_TD_RING_NUM 4 // # of TD rings.
+#define CB_MAX_SEG_PER_PKT 7 // max data seg per packet (Tx)
+
+
+/*
+ * If collisions excess 15 times , tx will abort, and
+ * if tx fifo underflow, tx will fail
+ * we should try to resend it
+ */
+
+#define CB_MAX_TX_ABORT_RETRY 3
+
+/*
+ * Receive descriptor
+ */
+
+struct rdesc0 {
+ u16 RSR; /* Receive status */
+ u16 len:14; /* Received packet length */
+ u16 reserved:1;
+ u16 owner:1; /* Who owns this buffer ? */
+};
+
+struct rdesc1 {
+ u16 PQTAG;
+ u8 CSM;
+ u8 IPKT;
+};
+
+struct rx_desc {
+ struct rdesc0 rdesc0;
+ struct rdesc1 rdesc1;
+ u32 pa_low; /* Low 32 bit PCI address */
+ u16 pa_high; /* Next 16 bit PCI address (48 total) */
+ u16 len:15; /* Frame size */
+ u16 inten:1; /* Enable interrupt */
+} __attribute__ ((__packed__));
+
+/*
+ * Transmit descriptor
+ */
+
+struct tdesc0 {
+ u16 TSR; /* Transmit status register */
+ u16 pktsize:14; /* Size of frame */
+ u16 reserved:1;
+ u16 owner:1; /* Who owns the buffer */
+};
+
+struct pqinf { /* Priority queue info */
+ u16 VID:12;
+ u16 CFI:1;
+ u16 priority:3;
+} __attribute__ ((__packed__));
+
+struct tdesc1 {
+ struct pqinf pqinf;
+ u8 TCR;
+ u8 TCPLS:2;
+ u8 reserved:2;
+ u8 CMDZ:4;
+} __attribute__ ((__packed__));
+
+struct td_buf {
+ u32 pa_low;
+ u16 pa_high;
+ u16 bufsize:14;
+ u16 reserved:1;
+ u16 queue:1;
+} __attribute__ ((__packed__));
+
+struct tx_desc {
+ struct tdesc0 tdesc0;
+ struct tdesc1 tdesc1;
+ struct td_buf td_buf[7];
+};
+
+#ifdef LINUX
+struct velocity_rd_info {
+ struct sk_buff *skb;
+ dma_addr_t skb_dma;
+};
+
+
+/**
+ * alloc_rd_info - allocate an rd info block
+ *
+ * Alocate and initialize a receive info structure used for keeping
+ * track of kernel side information related to each receive
+ * descriptor we are using
+ */
+
+static inline struct velocity_rd_info *alloc_rd_info(void)
+{
+ struct velocity_rd_info *ptr;
+ if ((ptr =
+ kmalloc(sizeof(struct velocity_rd_info), GFP_ATOMIC)) == NULL)
+ return NULL;
+ else {
+ memset(ptr, 0, sizeof(struct velocity_rd_info));
+ return ptr;
+ }
+}
+
+/*
+ * Used to track transmit side buffers.
+ */
+
+struct velocity_td_info {
+ struct sk_buff *skb;
+ u8 *buf;
+ int nskb_dma;
+ dma_addr_t skb_dma[7];
+ dma_addr_t buf_dma;
+};
+
+#endif
+enum {
+ OWNED_BY_HOST = 0,
+ OWNED_BY_NIC = 1
+} velocity_owner;
+
+
+/*
+ * MAC registers and macros.
+ */
+
+
+#define MCAM_SIZE 64
+#define VCAM_SIZE 64
+#define TX_QUEUE_NO 4
+
+#define MAX_HW_MIB_COUNTER 32
+#define VELOCITY_MIN_MTU (1514-14)
+#define VELOCITY_MAX_MTU (9000)
+
+/*
+ * Registers in the MAC
+ */
+
+#define MAC_REG_PAR 0x00 // physical address
+#define MAC_REG_RCR 0x06
+#define MAC_REG_TCR 0x07
+#define MAC_REG_CR0_SET 0x08
+#define MAC_REG_CR1_SET 0x09
+#define MAC_REG_CR2_SET 0x0A
+#define MAC_REG_CR3_SET 0x0B
+#define MAC_REG_CR0_CLR 0x0C
+#define MAC_REG_CR1_CLR 0x0D
+#define MAC_REG_CR2_CLR 0x0E
+#define MAC_REG_CR3_CLR 0x0F
+#define MAC_REG_MAR 0x10
+#define MAC_REG_CAM 0x10
+#define MAC_REG_DEC_BASE_HI 0x18
+#define MAC_REG_DBF_BASE_HI 0x1C
+#define MAC_REG_ISR_CTL 0x20
+#define MAC_REG_ISR_HOTMR 0x20
+#define MAC_REG_ISR_TSUPTHR 0x20
+#define MAC_REG_ISR_RSUPTHR 0x20
+#define MAC_REG_ISR_CTL1 0x21
+#define MAC_REG_TXE_SR 0x22
+#define MAC_REG_RXE_SR 0x23
+#define MAC_REG_ISR 0x24
+#define MAC_REG_ISR0 0x24
+#define MAC_REG_ISR1 0x25
+#define MAC_REG_ISR2 0x26
+#define MAC_REG_ISR3 0x27
+#define MAC_REG_IMR 0x28
+#define MAC_REG_IMR0 0x28
+#define MAC_REG_IMR1 0x29
+#define MAC_REG_IMR2 0x2A
+#define MAC_REG_IMR3 0x2B
+#define MAC_REG_TDCSR_SET 0x30
+#define MAC_REG_RDCSR_SET 0x32
+#define MAC_REG_TDCSR_CLR 0x34
+#define MAC_REG_RDCSR_CLR 0x36
+#define MAC_REG_RDBASE_LO 0x38
+#define MAC_REG_RDINDX 0x3C
+#define MAC_REG_TDBASE_LO 0x40
+#define MAC_REG_RDCSIZE 0x50
+#define MAC_REG_TDCSIZE 0x52
+#define MAC_REG_TDINDX 0x54
+#define MAC_REG_TDIDX0 0x54
+#define MAC_REG_TDIDX1 0x56
+#define MAC_REG_TDIDX2 0x58
+#define MAC_REG_TDIDX3 0x5A
+#define MAC_REG_PAUSE_TIMER 0x5C
+#define MAC_REG_RBRDU 0x5E
+#define MAC_REG_FIFO_TEST0 0x60
+#define MAC_REG_FIFO_TEST1 0x64
+#define MAC_REG_CAMADDR 0x68
+#define MAC_REG_CAMCR 0x69
+#define MAC_REG_GFTEST 0x6A
+#define MAC_REG_FTSTCMD 0x6B
+#define MAC_REG_MIICFG 0x6C
+#define MAC_REG_MIISR 0x6D
+#define MAC_REG_PHYSR0 0x6E
+#define MAC_REG_PHYSR1 0x6F
+#define MAC_REG_MIICR 0x70
+#define MAC_REG_MIIADR 0x71
+#define MAC_REG_MIIDATA 0x72
+#define MAC_REG_SOFT_TIMER0 0x74
+#define MAC_REG_SOFT_TIMER1 0x76
+#define MAC_REG_CFGA 0x78
+#define MAC_REG_CFGB 0x79
+#define MAC_REG_CFGC 0x7A
+#define MAC_REG_CFGD 0x7B
+#define MAC_REG_DCFG0 0x7C
+#define MAC_REG_DCFG1 0x7D
+#define MAC_REG_MCFG0 0x7E
+#define MAC_REG_MCFG1 0x7F
+
+#define MAC_REG_TBIST 0x80
+#define MAC_REG_RBIST 0x81
+#define MAC_REG_PMCC 0x82
+#define MAC_REG_STICKHW 0x83
+#define MAC_REG_MIBCR 0x84
+#define MAC_REG_EERSV 0x85
+#define MAC_REG_REVID 0x86
+#define MAC_REG_MIBREAD 0x88
+#define MAC_REG_BPMA 0x8C
+#define MAC_REG_EEWR_DATA 0x8C
+#define MAC_REG_BPMD_WR 0x8F
+#define MAC_REG_BPCMD 0x90
+#define MAC_REG_BPMD_RD 0x91
+#define MAC_REG_EECHKSUM 0x92
+#define MAC_REG_EECSR 0x93
+#define MAC_REG_EERD_DATA 0x94
+#define MAC_REG_EADDR 0x96
+#define MAC_REG_EMBCMD 0x97
+#define MAC_REG_JMPSR0 0x98
+#define MAC_REG_JMPSR1 0x99
+#define MAC_REG_JMPSR2 0x9A
+#define MAC_REG_JMPSR3 0x9B
+#define MAC_REG_CHIPGSR 0x9C
+#define MAC_REG_TESTCFG 0x9D
+#define MAC_REG_DEBUG 0x9E
+#define MAC_REG_CHIPGCR 0x9F
+#define MAC_REG_WOLCR0_SET 0xA0
+#define MAC_REG_WOLCR1_SET 0xA1
+#define MAC_REG_PWCFG_SET 0xA2
+#define MAC_REG_WOLCFG_SET 0xA3
+#define MAC_REG_WOLCR0_CLR 0xA4
+#define MAC_REG_WOLCR1_CLR 0xA5
+#define MAC_REG_PWCFG_CLR 0xA6
+#define MAC_REG_WOLCFG_CLR 0xA7
+#define MAC_REG_WOLSR0_SET 0xA8
+#define MAC_REG_WOLSR1_SET 0xA9
+#define MAC_REG_WOLSR0_CLR 0xAC
+#define MAC_REG_WOLSR1_CLR 0xAD
+#define MAC_REG_PATRN_CRC0 0xB0
+#define MAC_REG_PATRN_CRC1 0xB2
+#define MAC_REG_PATRN_CRC2 0xB4
+#define MAC_REG_PATRN_CRC3 0xB6
+#define MAC_REG_PATRN_CRC4 0xB8
+#define MAC_REG_PATRN_CRC5 0xBA
+#define MAC_REG_PATRN_CRC6 0xBC
+#define MAC_REG_PATRN_CRC7 0xBE
+#define MAC_REG_BYTEMSK0_0 0xC0
+#define MAC_REG_BYTEMSK0_1 0xC4
+#define MAC_REG_BYTEMSK0_2 0xC8
+#define MAC_REG_BYTEMSK0_3 0xCC
+#define MAC_REG_BYTEMSK1_0 0xD0
+#define MAC_REG_BYTEMSK1_1 0xD4
+#define MAC_REG_BYTEMSK1_2 0xD8
+#define MAC_REG_BYTEMSK1_3 0xDC
+#define MAC_REG_BYTEMSK2_0 0xE0
+#define MAC_REG_BYTEMSK2_1 0xE4
+#define MAC_REG_BYTEMSK2_2 0xE8
+#define MAC_REG_BYTEMSK2_3 0xEC
+#define MAC_REG_BYTEMSK3_0 0xF0
+#define MAC_REG_BYTEMSK3_1 0xF4
+#define MAC_REG_BYTEMSK3_2 0xF8
+#define MAC_REG_BYTEMSK3_3 0xFC
+
+/*
+ * Bits in the RCR register
+ */
+
+#define RCR_AS 0x80
+#define RCR_AP 0x40
+#define RCR_AL 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_TB2BDIS 0x80
+#define TCR_COLTMC1 0x08
+#define TCR_COLTMC0 0x04
+#define TCR_LB1 0x02 /* loopback[1] */
+#define TCR_LB0 0x01 /* loopback[0] */
+
+/*
+ * Bits in the CR0 register
+ */
+
+#define CR0_TXON 0x00000008UL
+#define CR0_RXON 0x00000004UL
+#define CR0_STOP 0x00000002UL /* stop MAC, default = 1 */
+#define CR0_STRT 0x00000001UL /* start MAC */
+#define CR0_SFRST 0x00008000UL /* software reset */
+#define CR0_TM1EN 0x00004000UL
+#define CR0_TM0EN 0x00002000UL
+#define CR0_DPOLL 0x00000800UL /* disable rx/tx auto polling */
+#define CR0_DISAU 0x00000100UL
+#define CR0_XONEN 0x00800000UL
+#define CR0_FDXTFCEN 0x00400000UL /* full-duplex TX flow control enable */
+#define CR0_FDXRFCEN 0x00200000UL /* full-duplex RX flow control enable */
+#define CR0_HDXFCEN 0x00100000UL /* half-duplex flow control enable */
+#define CR0_XHITH1 0x00080000UL /* TX XON high threshold 1 */
+#define CR0_XHITH0 0x00040000UL /* TX XON high threshold 0 */
+#define CR0_XLTH1 0x00020000UL /* TX pause frame low threshold 1 */
+#define CR0_XLTH0 0x00010000UL /* TX pause frame low threshold 0 */
+#define CR0_GSPRST 0x80000000UL
+#define CR0_FORSRST 0x40000000UL
+#define CR0_FPHYRST 0x20000000UL
+#define CR0_DIAG 0x10000000UL
+#define CR0_INTPCTL 0x04000000UL
+#define CR0_GINTMSK1 0x02000000UL
+#define CR0_GINTMSK0 0x01000000UL
+
+/*
+ * Bits in the CR1 register
+ */
+
+#define CR1_SFRST 0x80 /* software reset */
+#define CR1_TM1EN 0x40
+#define CR1_TM0EN 0x20
+#define CR1_DPOLL 0x08 /* disable rx/tx auto polling */
+#define CR1_DISAU 0x01
+
+/*
+ * Bits in the CR2 register
+ */
+
+#define CR2_XONEN 0x80
+#define CR2_FDXTFCEN 0x40 /* full-duplex TX flow control enable */
+#define CR2_FDXRFCEN 0x20 /* full-duplex RX flow control enable */
+#define CR2_HDXFCEN 0x10 /* half-duplex flow control enable */
+#define CR2_XHITH1 0x08 /* TX XON high threshold 1 */
+#define CR2_XHITH0 0x04 /* TX XON high threshold 0 */
+#define CR2_XLTH1 0x02 /* TX pause frame low threshold 1 */
+#define CR2_XLTH0 0x01 /* TX pause frame low threshold 0 */
+
+/*
+ * Bits in the CR3 register
+ */
+
+#define CR3_GSPRST 0x80
+#define CR3_FORSRST 0x40
+#define CR3_FPHYRST 0x20
+#define CR3_DIAG 0x10
+#define CR3_INTPCTL 0x04
+#define CR3_GINTMSK1 0x02
+#define CR3_GINTMSK0 0x01
+
+#define ISRCTL_UDPINT 0x8000
+#define ISRCTL_TSUPDIS 0x4000
+#define ISRCTL_RSUPDIS 0x2000
+#define ISRCTL_PMSK1 0x1000
+#define ISRCTL_PMSK0 0x0800
+#define ISRCTL_INTPD 0x0400
+#define ISRCTL_HCRLD 0x0200
+#define ISRCTL_SCRLD 0x0100
+
+/*
+ * Bits in the ISR_CTL1 register
+ */
+
+#define ISRCTL1_UDPINT 0x80
+#define ISRCTL1_TSUPDIS 0x40
+#define ISRCTL1_RSUPDIS 0x20
+#define ISRCTL1_PMSK1 0x10
+#define ISRCTL1_PMSK0 0x08
+#define ISRCTL1_INTPD 0x04
+#define ISRCTL1_HCRLD 0x02
+#define ISRCTL1_SCRLD 0x01
+
+/*
+ * Bits in the TXE_SR register
+ */
+
+#define TXESR_TFDBS 0x08
+#define TXESR_TDWBS 0x04
+#define TXESR_TDRBS 0x02
+#define TXESR_TDSTR 0x01
+
+/*
+ * Bits in the RXE_SR register
+ */
+
+#define RXESR_RFDBS 0x08
+#define RXESR_RDWBS 0x04
+#define RXESR_RDRBS 0x02
+#define RXESR_RDSTR 0x01
+
+/*
+ * Bits in the ISR register
+ */
+
+#define ISR_ISR3 0x80000000UL
+#define ISR_ISR2 0x40000000UL
+#define ISR_ISR1 0x20000000UL
+#define ISR_ISR0 0x10000000UL
+#define ISR_TXSTLI 0x02000000UL
+#define ISR_RXSTLI 0x01000000UL
+#define ISR_HFLD 0x00800000UL
+#define ISR_UDPI 0x00400000UL
+#define ISR_MIBFI 0x00200000UL
+#define ISR_SHDNI 0x00100000UL
+#define ISR_PHYI 0x00080000UL
+#define ISR_PWEI 0x00040000UL
+#define ISR_TMR1I 0x00020000UL
+#define ISR_TMR0I 0x00010000UL
+#define ISR_SRCI 0x00008000UL
+#define ISR_LSTPEI 0x00004000UL
+#define ISR_LSTEI 0x00002000UL
+#define ISR_OVFI 0x00001000UL
+#define ISR_FLONI 0x00000800UL
+#define ISR_RACEI 0x00000400UL
+#define ISR_TXWB1I 0x00000200UL
+#define ISR_TXWB0I 0x00000100UL
+#define ISR_PTX3I 0x00000080UL
+#define ISR_PTX2I 0x00000040UL
+#define ISR_PTX1I 0x00000020UL
+#define ISR_PTX0I 0x00000010UL
+#define ISR_PTXI 0x00000008UL
+#define ISR_PRXI 0x00000004UL
+#define ISR_PPTXI 0x00000002UL
+#define ISR_PPRXI 0x00000001UL
+
+/*
+ * Bits in the IMR register
+ */
+
+#define IMR_TXSTLM 0x02000000UL
+#define IMR_UDPIM 0x00400000UL
+#define IMR_MIBFIM 0x00200000UL
+#define IMR_SHDNIM 0x00100000UL
+#define IMR_PHYIM 0x00080000UL
+#define IMR_PWEIM 0x00040000UL
+#define IMR_TMR1IM 0x00020000UL
+#define IMR_TMR0IM 0x00010000UL
+
+#define IMR_SRCIM 0x00008000UL
+#define IMR_LSTPEIM 0x00004000UL
+#define IMR_LSTEIM 0x00002000UL
+#define IMR_OVFIM 0x00001000UL
+#define IMR_FLONIM 0x00000800UL
+#define IMR_RACEIM 0x00000400UL
+#define IMR_TXWB1IM 0x00000200UL
+#define IMR_TXWB0IM 0x00000100UL
+
+#define IMR_PTX3IM 0x00000080UL
+#define IMR_PTX2IM 0x00000040UL
+#define IMR_PTX1IM 0x00000020UL
+#define IMR_PTX0IM 0x00000010UL
+#define IMR_PTXIM 0x00000008UL
+#define IMR_PRXIM 0x00000004UL
+#define IMR_PPTXIM 0x00000002UL
+#define IMR_PPRXIM 0x00000001UL
+
+/* 0x0013FB0FUL = initial value of IMR */
+
+#define INT_MASK_DEF ( IMR_PPTXIM|IMR_PPRXIM| IMR_PTXIM|IMR_PRXIM | \
+ IMR_PWEIM|IMR_TXWB0IM|IMR_TXWB1IM|IMR_FLONIM| \
+ IMR_OVFIM|IMR_LSTEIM|IMR_LSTPEIM|IMR_SRCIM|IMR_MIBFIM|\
+ IMR_SHDNIM |IMR_TMR1IM|IMR_TMR0IM|IMR_TXSTLM )
+
+/*
+ * Bits in the TDCSR0/1, RDCSR0 register
+ */
+
+#define TRDCSR_DEAD 0x0008
+#define TRDCSR_WAK 0x0004
+#define TRDCSR_ACT 0x0002
+#define TRDCSR_RUN 0x0001
+
+/*
+ * Bits in the CAMADDR register
+ */
+
+#define CAMADDR_CAMEN 0x80
+#define CAMADDR_VCAMSL 0x40
+
+/*
+ * Bits in the CAMCR register
+ */
+
+#define CAMCR_PS1 0x80
+#define CAMCR_PS0 0x40
+#define CAMCR_AITRPKT 0x20
+#define CAMCR_AITR16 0x10
+#define CAMCR_CAMRD 0x08
+#define CAMCR_CAMWR 0x04
+#define CAMCR_PS_CAM_MASK 0x40
+#define CAMCR_PS_CAM_DATA 0x80
+#define CAMCR_PS_MAR 0x00
+
+/*
+ * Bits in the MIICFG register
+ */
+
+#define MIICFG_MPO1 0x80
+#define MIICFG_MPO0 0x40
+#define MIICFG_MFDC 0x20
+
+/*
+ * Bits in the MIISR register
+ */
+
+#define MIISR_MIDLE 0x80
+
+/*
+ * Bits in the PHYSR0 register
+ */
+
+#define PHYSR0_PHYRST 0x80
+#define PHYSR0_LINKGD 0x40
+#define PHYSR0_FDPX 0x10
+#define PHYSR0_SPDG 0x08
+#define PHYSR0_SPD10 0x04
+#define PHYSR0_RXFLC 0x02
+#define PHYSR0_TXFLC 0x01
+
+/*
+ * Bits in the PHYSR1 register
+ */
+
+#define PHYSR1_PHYTBI 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 MIIADR register
+ */
+
+#define MIIADR_SWMPL 0x80
+
+/*
+ * Bits in the CFGA register
+ */
+
+#define CFGA_PMHCTG 0x08
+#define CFGA_GPIO1PD 0x04
+#define CFGA_ABSHDN 0x02
+#define CFGA_PACPI 0x01
+
+/*
+ * Bits in the CFGB register
+ */
+
+#define CFGB_GTCKOPT 0x80
+#define CFGB_MIIOPT 0x40
+#define CFGB_CRSEOPT 0x20
+#define CFGB_OFSET 0x10
+#define CFGB_CRANDOM 0x08
+#define CFGB_CAP 0x04
+#define CFGB_MBA 0x02
+#define CFGB_BAKOPT 0x01
+
+/*
+ * Bits in the CFGC register
+ */
+
+#define CFGC_EELOAD 0x80
+#define CFGC_BROPT 0x40
+#define CFGC_DLYEN 0x20
+#define CFGC_DTSEL 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_IODIS 0x80
+#define CFGD_MSLVDACEN 0x40
+#define CFGD_CFGDACEN 0x20
+#define CFGD_PCI64EN 0x10
+#define CFGD_HTMRL4 0x08
+
+/*
+ * Bits in the DCFG1 register
+ */
+
+#define DCFG_XMWI 0x8000
+#define DCFG_XMRM 0x4000
+#define DCFG_XMRL 0x2000
+#define DCFG_PERDIS 0x1000
+#define DCFG_MRWAIT 0x0400
+#define DCFG_MWWAIT 0x0200
+#define DCFG_LATMEN 0x0100
+
+/*
+ * Bits in the MCFG0 register
+ */
+
+#define MCFG_RXARB 0x0080
+#define MCFG_RFT1 0x0020
+#define MCFG_RFT0 0x0010
+#define MCFG_LOWTHOPT 0x0008
+#define MCFG_PQEN 0x0004
+#define MCFG_RTGOPT 0x0002
+#define MCFG_VIDFR 0x0001
+
+/*
+ * Bits in the MCFG1 register
+ */
+
+#define MCFG_TXARB 0x8000
+#define MCFG_TXQBK1 0x0800
+#define MCFG_TXQBK0 0x0400
+#define MCFG_TXQNOBK 0x0200
+#define MCFG_SNAPOPT 0x0100
+
+/*
+ * Bits in the PMCC register
+ */
+
+#define PMCC_DSI 0x80
+#define PMCC_D2_DIS 0x40
+#define PMCC_D1_DIS 0x20
+#define PMCC_D3C_EN 0x10
+#define PMCC_D3H_EN 0x08
+#define PMCC_D2_EN 0x04
+#define PMCC_D1_EN 0x02
+#define PMCC_D0_EN 0x01
+
+/*
+ * Bits in STICKHW
+ */
+
+#define STICKHW_SWPTAG 0x10
+#define STICKHW_WOLSR 0x08
+#define STICKHW_WOLEN 0x04
+#define STICKHW_DS1 0x02 /* R/W by software/cfg cycle */
+#define STICKHW_DS0 0x01 /* suspend well DS write port */
+
+/*
+ * Bits in the MIBCR register
+ */
+
+#define MIBCR_MIBISTOK 0x80
+#define MIBCR_MIBISTGO 0x40
+#define MIBCR_MIBINC 0x20
+#define MIBCR_MIBHI 0x10
+#define MIBCR_MIBFRZ 0x08
+#define MIBCR_MIBFLSH 0x04
+#define MIBCR_MPTRINI 0x02
+#define MIBCR_MIBCLR 0x01
+
+/*
+ * Bits in the EERSV register
+ */
+
+#define EERSV_BOOT_RPL ((u8) 0x01) /* Boot method selection for VT6110 */
+
+#define EERSV_BOOT_MASK ((u8) 0x06)
+#define EERSV_BOOT_INT19 ((u8) 0x00)
+#define EERSV_BOOT_INT18 ((u8) 0x02)
+#define EERSV_BOOT_LOCAL ((u8) 0x04)
+#define EERSV_BOOT_BEV ((u8) 0x06)
+
+
+/*
+ * Bits in BPCMD
+ */
+
+#define BPCMD_BPDNE 0x80
+#define BPCMD_EBPWR 0x02
+#define BPCMD_EBPRD 0x01
+
+/*
+ * Bits in the EECSR register
+ */
+
+#define EECSR_EMBP 0x40 /* eeprom embeded programming */
+#define EECSR_RELOAD 0x20 /* eeprom content reload */
+#define EECSR_DPM 0x10 /* eeprom direct programming */
+#define EECSR_ECS 0x08 /* eeprom CS pin */
+#define EECSR_ECK 0x04 /* eeprom CK pin */
+#define EECSR_EDI 0x02 /* eeprom DI pin */
+#define EECSR_EDO 0x01 /* eeprom DO pin */
+
+/*
+ * Bits in the EMBCMD register
+ */
+
+#define EMBCMD_EDONE 0x80
+#define EMBCMD_EWDIS 0x08
+#define EMBCMD_EWEN 0x04
+#define EMBCMD_EWR 0x02
+#define EMBCMD_ERD 0x01
+
+/*
+ * Bits in TESTCFG register
+ */
+
+#define TESTCFG_HBDIS 0x80
+
+/*
+ * Bits in CHIPGCR register
+ */
+
+#define CHIPGCR_FCGMII 0x80
+#define CHIPGCR_FCFDX 0x40
+#define CHIPGCR_FCRESV 0x20
+#define CHIPGCR_FCMODE 0x10
+#define CHIPGCR_LPSOPT 0x08
+#define CHIPGCR_TM1US 0x04
+#define CHIPGCR_TM0US 0x02
+#define CHIPGCR_PHYINTEN 0x01
+
+/*
+ * Bits in WOLCR0
+ */
+
+#define WOLCR_MSWOLEN7 0x0080 /* enable pattern match filtering */
+#define WOLCR_MSWOLEN6 0x0040
+#define WOLCR_MSWOLEN5 0x0020
+#define WOLCR_MSWOLEN4 0x0010
+#define WOLCR_MSWOLEN3 0x0008
+#define WOLCR_MSWOLEN2 0x0004
+#define WOLCR_MSWOLEN1 0x0002
+#define WOLCR_MSWOLEN0 0x0001
+#define WOLCR_ARP_EN 0x0001
+
+/*
+ * Bits in WOLCR1
+ */
+
+#define WOLCR_LINKOFF_EN 0x0800 /* link off detected enable */
+#define WOLCR_LINKON_EN 0x0400 /* link on detected enable */
+#define WOLCR_MAGIC_EN 0x0200 /* magic packet filter enable */
+#define WOLCR_UNICAST_EN 0x0100 /* unicast filter enable */
+
+
+/*
+ * Bits in PWCFG
+ */
+
+#define PWCFG_PHYPWOPT 0x80 /* internal MII I/F timing */
+#define PWCFG_PCISTICK 0x40 /* PCI sticky R/W enable */
+#define PWCFG_WOLTYPE 0x20 /* pulse(1) or button (0) */
+#define PWCFG_LEGCY_WOL 0x10
+#define PWCFG_PMCSR_PME_SR 0x08
+#define PWCFG_PMCSR_PME_EN 0x04 /* control by PCISTICK */
+#define PWCFG_LEGACY_WOLSR 0x02 /* Legacy WOL_SR shadow */
+#define PWCFG_LEGACY_WOLEN 0x01 /* Legacy WOL_EN shadow */
+
+/*
+ * Bits in WOLCFG
+ */
+
+#define WOLCFG_PMEOVR 0x80 /* for legacy use, force PMEEN always */
+#define WOLCFG_SAM 0x20 /* accept multicast case reset, default=0 */
+#define WOLCFG_SAB 0x10 /* accept broadcast case reset, default=0 */
+#define WOLCFG_SMIIACC 0x08 /* ?? */
+#define WOLCFG_SGENWH 0x02
+#define WOLCFG_PHYINTEN 0x01 /* 0:PHYINT trigger enable, 1:use internal MII
+ to report status change */
+/*
+ * Bits in WOLSR1
+ */
+
+#define WOLSR_LINKOFF_INT 0x0800
+#define WOLSR_LINKON_INT 0x0400
+#define WOLSR_MAGIC_INT 0x0200
+#define WOLSR_UNICAST_INT 0x0100
+
+/*
+ * Ethernet address filter type
+ */
+
+#define PKT_TYPE_NONE 0x0000 /* Turn off receiver */
+#define PKT_TYPE_DIRECTED 0x0001 /* obselete, 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 /* NOTE.... the definition of LONG is >2048 bytes in our chip */
+#define PKT_TYPE_RUNT 0x4000
+#define PKT_TYPE_ERROR 0x8000 /* Accept error packets, e.g. CRC error */
+
+/*
+ * Loopback mode
+ */
+
+#define MAC_LB_NONE 0x00
+#define MAC_LB_INTERNAL 0x01
+#define MAC_LB_EXTERNAL 0x02
+
+/*
+ * Enabled mask value of irq
+ */
+
+#if defined(_SIM)
+#define IMR_MASK_VALUE 0x0033FF0FUL /* initial value of IMR
+ set IMR0 to 0x0F according to spec */
+
+#else
+#define IMR_MASK_VALUE 0x0013FB0FUL /* initial value of IMR
+ ignore MIBFI,RACEI to
+ reduce intr. frequency
+ NOTE.... do not enable NoBuf int mask at driver driver
+ when (1) NoBuf -> RxThreshold = SF
+ (2) OK -> RxThreshold = original value
+ */
+#endif
+
+/*
+ * Revision id
+ */
+
+#define REV_ID_VT3119_A0 0x00
+#define REV_ID_VT3119_A1 0x01
+#define REV_ID_VT3216_A0 0x10
+
+/*
+ * Max time out delay time
+ */
+
+#define W_MAX_TIMEOUT 0x0FFFU
+
+
+/*
+ * MAC registers as a structure. Cannot be directly accessed this
+ * way but generates offsets for readl/writel() calls
+ */
+
+struct mac_regs {
+ volatile u8 PAR[6]; /* 0x00 */
+ volatile u8 RCR;
+ volatile u8 TCR;
+
+ volatile u32 CR0Set; /* 0x08 */
+ volatile u32 CR0Clr; /* 0x0C */
+
+ volatile u8 MARCAM[8]; /* 0x10 */
+
+ volatile u32 DecBaseHi; /* 0x18 */
+ volatile u16 DbfBaseHi; /* 0x1C */
+ volatile u16 reserved_1E;
+
+ volatile u16 ISRCTL; /* 0x20 */
+ volatile u8 TXESR;
+ volatile u8 RXESR;
+
+ volatile u32 ISR; /* 0x24 */
+ volatile u32 IMR;
+
+ volatile u32 TDStatusPort; /* 0x2C */
+
+ volatile u16 TDCSRSet; /* 0x30 */
+ volatile u8 RDCSRSet;
+ volatile u8 reserved_33;
+ volatile u16 TDCSRClr;
+ volatile u8 RDCSRClr;
+ volatile u8 reserved_37;
+
+ volatile u32 RDBaseLo; /* 0x38 */
+ volatile u16 RDIdx; /* 0x3C */
+ volatile u16 reserved_3E;
+
+ volatile u32 TDBaseLo[4]; /* 0x40 */
+
+ volatile u16 RDCSize; /* 0x50 */
+ volatile u16 TDCSize; /* 0x52 */
+ volatile u16 TDIdx[4]; /* 0x54 */
+ volatile u16 tx_pause_timer; /* 0x5C */
+ volatile u16 RBRDU; /* 0x5E */
+
+ volatile u32 FIFOTest0; /* 0x60 */
+ volatile u32 FIFOTest1; /* 0x64 */
+
+ volatile u8 CAMADDR; /* 0x68 */
+ volatile u8 CAMCR; /* 0x69 */
+ volatile u8 GFTEST; /* 0x6A */
+ volatile u8 FTSTCMD; /* 0x6B */
+
+ volatile u8 MIICFG; /* 0x6C */
+ volatile u8 MIISR;
+ volatile u8 PHYSR0;
+ volatile u8 PHYSR1;
+ volatile u8 MIICR;
+ volatile u8 MIIADR;
+ volatile u16 MIIDATA;
+
+ volatile u16 SoftTimer0; /* 0x74 */
+ volatile u16 SoftTimer1;
+
+ volatile u8 CFGA; /* 0x78 */
+ volatile u8 CFGB;
+ volatile u8 CFGC;
+ volatile u8 CFGD;
+
+ volatile u16 DCFG; /* 0x7C */
+ volatile u16 MCFG;
+
+ volatile u8 TBIST; /* 0x80 */
+ volatile u8 RBIST;
+ volatile u8 PMCPORT;
+ volatile u8 STICKHW;
+
+ volatile u8 MIBCR; /* 0x84 */
+ volatile u8 reserved_85;
+ volatile u8 rev_id;
+ volatile u8 PORSTS;
+
+ volatile u32 MIBData; /* 0x88 */
+
+ volatile u16 EEWrData;
+
+ volatile u8 reserved_8E;
+ volatile u8 BPMDWr;
+ volatile u8 BPCMD;
+ volatile u8 BPMDRd;
+
+ volatile u8 EECHKSUM; /* 0x92 */
+ volatile u8 EECSR;
+
+ volatile u16 EERdData; /* 0x94 */
+ volatile u8 EADDR;
+ volatile u8 EMBCMD;
+
+
+ volatile u8 JMPSR0; /* 0x98 */
+ volatile u8 JMPSR1;
+ volatile u8 JMPSR2;
+ volatile u8 JMPSR3;
+ volatile u8 CHIPGSR; /* 0x9C */
+ volatile u8 TESTCFG;
+ volatile u8 DEBUG;
+ volatile u8 CHIPGCR;
+
+ volatile u16 WOLCRSet; /* 0xA0 */
+ volatile u8 PWCFGSet;
+ volatile u8 WOLCFGSet;
+
+ volatile u16 WOLCRClr; /* 0xA4 */
+ volatile u8 PWCFGCLR;
+ volatile u8 WOLCFGClr;
+
+ volatile u16 WOLSRSet; /* 0xA8 */
+ volatile u16 reserved_AA;
+
+ volatile u16 WOLSRClr; /* 0xAC */
+ volatile u16 reserved_AE;
+
+ volatile u16 PatternCRC[8]; /* 0xB0 */
+ volatile u32 ByteMask[4][4]; /* 0xC0 */
+} __attribute__ ((__packed__));
+
+
+enum hw_mib {
+ HW_MIB_ifRxAllPkts = 0,
+ HW_MIB_ifRxOkPkts,
+ HW_MIB_ifTxOkPkts,
+ HW_MIB_ifRxErrorPkts,
+ HW_MIB_ifRxRuntOkPkt,
+ HW_MIB_ifRxRuntErrPkt,
+ HW_MIB_ifRx64Pkts,
+ HW_MIB_ifTx64Pkts,
+ HW_MIB_ifRx65To127Pkts,
+ HW_MIB_ifTx65To127Pkts,
+ HW_MIB_ifRx128To255Pkts,
+ HW_MIB_ifTx128To255Pkts,
+ HW_MIB_ifRx256To511Pkts,
+ HW_MIB_ifTx256To511Pkts,
+ HW_MIB_ifRx512To1023Pkts,
+ HW_MIB_ifTx512To1023Pkts,
+ HW_MIB_ifRx1024To1518Pkts,
+ HW_MIB_ifTx1024To1518Pkts,
+ HW_MIB_ifTxEtherCollisions,
+ HW_MIB_ifRxPktCRCE,
+ HW_MIB_ifRxJumboPkts,
+ HW_MIB_ifTxJumboPkts,
+ HW_MIB_ifRxMacControlFrames,
+ HW_MIB_ifTxMacControlFrames,
+ HW_MIB_ifRxPktFAE,
+ HW_MIB_ifRxLongOkPkt,
+ HW_MIB_ifRxLongPktErrPkt,
+ HW_MIB_ifTXSQEErrors,
+ HW_MIB_ifRxNobuf,
+ HW_MIB_ifRxSymbolErrors,
+ HW_MIB_ifInRangeLengthErrors,
+ HW_MIB_ifLateCollisions,
+ HW_MIB_SIZE
+};
+
+enum chip_type {
+ CHIP_TYPE_VT6110 = 1,
+};
+
+struct velocity_info_tbl {
+ enum chip_type chip_id;
+ char *name;
+ int io_size;
+ int txqueue;
+ u32 flags;
+};
+
+struct velocity_info_tbl *info;
+
+#define mac_hw_mibs_init(regs) {\
+ BYTE_REG_BITS_ON(MIBCR_MIBFRZ,&((regs)->MIBCR));\
+ BYTE_REG_BITS_ON(MIBCR_MIBCLR,&((regs)->MIBCR));\
+ do {}\
+ while (BYTE_REG_BITS_IS_ON(MIBCR_MIBCLR,&((regs)->MIBCR)));\
+ BYTE_REG_BITS_OFF(MIBCR_MIBFRZ,&((regs)->MIBCR));\
+}
+
+#define mac_read_isr(regs) readl(&((regs)->ISR))
+#define mac_write_isr(regs, x) writel((x),&((regs)->ISR))
+#define mac_clear_isr(regs) writel(0xffffffffL,&((regs)->ISR))
+
+#define mac_write_int_mask(mask, regs) writel((mask),&((regs)->IMR));
+#define mac_disable_int(regs) writel(CR0_GINTMSK1,&((regs)->CR0Clr))
+#define mac_enable_int(regs) writel(CR0_GINTMSK1,&((regs)->CR0Set))
+
+#define mac_hw_mibs_read(regs, MIBs) {\
+ int i;\
+ BYTE_REG_BITS_ON(MIBCR_MPTRINI,&((regs)->MIBCR));\
+ for (i=0;i<HW_MIB_SIZE;i++) {\
+ (MIBs)[i]=readl(&((regs)->MIBData));\
+ }\
+}
+
+#define mac_set_dma_length(regs, n) {\
+ BYTE_REG_BITS_SET((n),0x07,&((regs)->DCFG));\
+}
+
+#define mac_set_rx_thresh(regs, n) {\
+ BYTE_REG_BITS_SET((n),(MCFG_RFT0|MCFG_RFT1),&((regs)->MCFG));\
+}
+
+#define mac_rx_queue_run(regs) {\
+ writeb(TRDCSR_RUN, &((regs)->RDCSRSet));\
+}
+
+#define mac_rx_queue_wake(regs) {\
+ writeb(TRDCSR_WAK, &((regs)->RDCSRSet));\
+}
+
+#define mac_tx_queue_run(regs, n) {\
+ writew(TRDCSR_RUN<<((n)*4),&((regs)->TDCSRSet));\
+}
+
+#define mac_tx_queue_wake(regs, n) {\
+ writew(TRDCSR_WAK<<(n*4),&((regs)->TDCSRSet));\
+}
+
+#define mac_eeprom_reload(regs) {\
+ int i=0;\
+ BYTE_REG_BITS_ON(EECSR_RELOAD,&((regs)->EECSR));\
+ do {\
+ udelay(10);\
+ if (i++>0x1000) {\
+ break;\
+ }\
+ }while (BYTE_REG_BITS_IS_ON(EECSR_RELOAD,&((regs)->EECSR)));\
+}
+
+enum velocity_cam_type {
+ VELOCITY_VLAN_ID_CAM = 0,
+ VELOCITY_MULTICAST_CAM
+};
+
+/**
+ * mac_get_cam_mask - Read a CAM mask
+ * @regs: register block for this velocity
+ * @mask: buffer to store mask
+ * @cam_type: CAM to fetch
+ *
+ * Fetch the mask bits of the selected CAM and store them into the
+ * provided mask buffer.
+ */
+
+static inline void mac_get_cam_mask(struct mac_regs *regs, u8 * mask,
+ enum velocity_cam_type cam_type)
+{
+ int i;
+ /* Select CAM mask */
+ BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0,
+ &regs->CAMCR);
+
+ if (cam_type == VELOCITY_VLAN_ID_CAM)
+ writeb(CAMADDR_VCAMSL, &regs->CAMADDR);
+ else
+ writeb(0, &regs->CAMADDR);
+
+ /* read mask */
+ for (i = 0; i < 8; i++)
+ *mask++ = readb(&(regs->MARCAM[i]));
+
+ /* disable CAMEN */
+ writeb(0, &regs->CAMADDR);
+
+ /* Select mar */
+ BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0,
+ &regs->CAMCR);
+
+}
+
+/**
+ * mac_set_cam_mask - Set a CAM mask
+ * @regs: register block for this velocity
+ * @mask: CAM mask to load
+ * @cam_type: CAM to store
+ *
+ * Store a new mask into a CAM
+ */
+
+static inline void mac_set_cam_mask(struct mac_regs *regs, u8 * mask,
+ enum velocity_cam_type cam_type)
+{
+ int i;
+ /* Select CAM mask */
+ BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0,
+ &regs->CAMCR);
+
+ if (cam_type == VELOCITY_VLAN_ID_CAM)
+ writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL, &regs->CAMADDR);
+ else
+ writeb(CAMADDR_CAMEN, &regs->CAMADDR);
+
+ for (i = 0; i < 8; i++) {
+ writeb(*mask++, &(regs->MARCAM[i]));
+ }
+ /* disable CAMEN */
+ writeb(0, &regs->CAMADDR);
+
+ /* Select mar */
+ BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0,
+ &regs->CAMCR);
+}
+
+/**
+ * mac_set_cam - set CAM data
+ * @regs: register block of this velocity
+ * @idx: Cam index
+ * @addr: 2 or 6 bytes of CAM data
+ * @cam_type: CAM to load
+ *
+ * Load an address or vlan tag into a CAM
+ */
+
+static inline void mac_set_cam(struct mac_regs *regs, int idx, u8 * addr,
+ enum velocity_cam_type cam_type)
+{
+ int i;
+
+ /* Select CAM mask */
+ BYTE_REG_BITS_SET(CAMCR_PS_CAM_DATA, CAMCR_PS1 | CAMCR_PS0,
+ &regs->CAMCR);
+
+ idx &= (64 - 1);
+
+ if (cam_type == VELOCITY_VLAN_ID_CAM)
+ writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL | idx,
+ &regs->CAMADDR);
+ else
+ writeb(CAMADDR_CAMEN | idx, &regs->CAMADDR);
+
+ if (cam_type == VELOCITY_VLAN_ID_CAM)
+ writew(*((u16 *) addr), &regs->MARCAM[0]);
+ else {
+ for (i = 0; i < 6; i++) {
+ writeb(*addr++, &(regs->MARCAM[i]));
+ }
+ }
+ BYTE_REG_BITS_ON(CAMCR_CAMWR, &regs->CAMCR);
+
+ udelay(10);
+
+ writeb(0, &regs->CAMADDR);
+
+ /* Select mar */
+ BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0,
+ &regs->CAMCR);
+}
+
+/**
+ * mac_get_cam - fetch CAM data
+ * @regs: register block of this velocity
+ * @idx: Cam index
+ * @addr: buffer to hold up to 6 bytes of CAM data
+ * @cam_type: CAM to load
+ *
+ * Load an address or vlan tag from a CAM into the buffer provided by
+ * the caller. VLAN tags are 2 bytes the address cam entries are 6.
+ */
+
+static inline void mac_get_cam(struct mac_regs *regs, int idx, u8 * addr,
+ enum velocity_cam_type cam_type)
+{
+ int i;
+
+ /* Select CAM mask */
+ BYTE_REG_BITS_SET(CAMCR_PS_CAM_DATA, CAMCR_PS1 | CAMCR_PS0,
+ &regs->CAMCR);
+
+ idx &= (64 - 1);
+
+ if (cam_type == VELOCITY_VLAN_ID_CAM)
+ writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL | idx,
+ &regs->CAMADDR);
+ else
+ writeb(CAMADDR_CAMEN | idx, &regs->CAMADDR);
+
+ BYTE_REG_BITS_ON(CAMCR_CAMRD, &regs->CAMCR);
+
+ udelay(10);
+
+ if (cam_type == VELOCITY_VLAN_ID_CAM)
+ *((u16 *) addr) = readw(&(regs->MARCAM[0]));
+ else
+ for (i = 0; i < 6; i++, addr++)
+ *((u8 *) addr) = readb(&(regs->MARCAM[i]));
+
+ writeb(0, &regs->CAMADDR);
+
+ /* Select mar */
+ BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0,
+ &regs->CAMCR);
+}
+
+/**
+ * mac_wol_reset - reset WOL after exiting low power
+ * @regs: register block of this velocity
+ *
+ * Called after we drop out of wake on lan mode in order to
+ * reset the Wake on lan features. This function doesn't restore
+ * the rest of the logic from the result of sleep/wakeup
+ */
+
+inline static void mac_wol_reset(struct mac_regs *regs)
+{
+
+ /* Turn off SWPTAG right after leaving power mode */
+ BYTE_REG_BITS_OFF(STICKHW_SWPTAG, &regs->STICKHW);
+ /* clear sticky bits */
+ BYTE_REG_BITS_OFF((STICKHW_DS1 | STICKHW_DS0), &regs->STICKHW);
+
+ BYTE_REG_BITS_OFF(CHIPGCR_FCGMII, &regs->CHIPGCR);
+ BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, &regs->CHIPGCR);
+ /* disable force PME-enable */
+ writeb(WOLCFG_PMEOVR, &regs->WOLCFGClr);
+ /* disable power-event config bit */
+ writew(0xFFFF, &regs->WOLCRClr);
+ /* clear power status */
+ writew(0xFFFF, &regs->WOLSRClr);
+}
+
+
+/*
+ * Header for WOL definitions. Used to compute hashes
+ */
+
+typedef u8 MCAM_ADDR[ETH_ALEN];
+
+struct arp_packet {
+ u8 dest_mac[ETH_ALEN];
+ u8 src_mac[ETH_ALEN];
+ u16 type;
+ u16 ar_hrd;
+ u16 ar_pro;
+ u8 ar_hln;
+ u8 ar_pln;
+ u16 ar_op;
+ u8 ar_sha[ETH_ALEN];
+ u8 ar_sip[4];
+ u8 ar_tha[ETH_ALEN];
+ u8 ar_tip[4];
+} __attribute__ ((__packed__));
+
+struct _magic_packet {
+ u8 dest_mac[6];
+ u8 src_mac[6];
+ u16 type;
+ u8 MAC[16][6];
+ u8 password[6];
+} __attribute__ ((__packed__));
+
+/*
+ * Store for chip context when saving and restoring status. Not
+ * all fields are saved/restored currently.
+ */
+
+struct velocity_context {
+ u8 mac_reg[256];
+ MCAM_ADDR cam_addr[MCAM_SIZE];
+ u16 vcam[VCAM_SIZE];
+ u32 cammask[2];
+ u32 patcrc[2];
+ u32 pattern[8];
+};
+
+
+/*
+ * MII registers.
+ */
+
+
+/*
+ * Registers in the MII (offset unit is WORD)
+ */
+
+#define MII_REG_BMCR 0x00 // physical address
+#define MII_REG_BMSR 0x01 //
+#define MII_REG_PHYID1 0x02 // OUI
+#define MII_REG_PHYID2 0x03 // OUI + Module ID + REV ID
+#define MII_REG_ANAR 0x04 //
+#define MII_REG_ANLPAR 0x05 //
+#define MII_REG_G1000CR 0x09 //
+#define MII_REG_G1000SR 0x0A //
+#define MII_REG_MODCFG 0x10 //
+#define MII_REG_TCSR 0x16 //
+#define MII_REG_PLED 0x1B //
+// NS, MYSON only
+#define MII_REG_PCR 0x17 //
+// ESI only
+#define MII_REG_PCSR 0x17 //
+#define MII_REG_AUXCR 0x1C //
+
+// Marvell 88E1000/88E1000S
+#define MII_REG_PSCR 0x10 // PHY specific control register
+
+//
+// Bits in the BMCR register
+//
+#define BMCR_RESET 0x8000 //
+#define BMCR_LBK 0x4000 //
+#define BMCR_SPEED100 0x2000 //
+#define BMCR_AUTO 0x1000 //
+#define BMCR_PD 0x0800 //
+#define BMCR_ISO 0x0400 //
+#define BMCR_REAUTO 0x0200 //
+#define BMCR_FDX 0x0100 //
+#define BMCR_SPEED1G 0x0040 //
+//
+// Bits in the BMSR register
+//
+#define BMSR_AUTOCM 0x0020 //
+#define BMSR_LNK 0x0004 //
+
+//
+// Bits in the ANAR register
+//
+#define ANAR_ASMDIR 0x0800 // Asymmetric PAUSE support
+#define ANAR_PAUSE 0x0400 // Symmetric PAUSE Support
+#define ANAR_T4 0x0200 //
+#define ANAR_TXFD 0x0100 //
+#define ANAR_TX 0x0080 //
+#define ANAR_10FD 0x0040 //
+#define ANAR_10 0x0020 //
+//
+// Bits in the ANLPAR register
+//
+#define ANLPAR_ASMDIR 0x0800 // Asymmetric PAUSE support
+#define ANLPAR_PAUSE 0x0400 // Symmetric PAUSE Support
+#define ANLPAR_T4 0x0200 //
+#define ANLPAR_TXFD 0x0100 //
+#define ANLPAR_TX 0x0080 //
+#define ANLPAR_10FD 0x0040 //
+#define ANLPAR_10 0x0020 //
+
+//
+// Bits in the G1000CR register
+//
+#define G1000CR_1000FD 0x0200 // PHY is 1000-T Full-duplex capable
+#define G1000CR_1000 0x0100 // PHY is 1000-T Half-duplex capable
+
+//
+// Bits in the G1000SR register
+//
+#define G1000SR_1000FD 0x0800 // LP PHY is 1000-T Full-duplex capable
+#define G1000SR_1000 0x0400 // LP PHY is 1000-T Half-duplex capable
+
+#define TCSR_ECHODIS 0x2000 //
+#define AUXCR_MDPPS 0x0004 //
+
+// Bits in the PLED register
+#define PLED_LALBE 0x0004 //
+
+// Marvell 88E1000/88E1000S Bits in the PHY specific control register (10h)
+#define PSCR_ACRSTX 0x0800 // Assert CRS on Transmit
+
+#define PHYID_CICADA_CS8201 0x000FC410UL
+#define PHYID_VT3216_32BIT 0x000FC610UL
+#define PHYID_VT3216_64BIT 0x000FC600UL
+#define PHYID_MARVELL_1000 0x01410C50UL
+#define PHYID_MARVELL_1000S 0x01410C40UL
+
+#define PHYID_REV_ID_MASK 0x0000000FUL
+
+#define PHYID_GET_PHY_REV_ID(i) ((i) & PHYID_REV_ID_MASK)
+#define PHYID_GET_PHY_ID(i) ((i) & ~PHYID_REV_ID_MASK)
+
+#define MII_REG_BITS_ON(x,i,p) do {\
+ u16 w;\
+ velocity_mii_read((p),(i),&(w));\
+ (w)|=(x);\
+ velocity_mii_write((p),(i),(w));\
+} while (0)
+
+#define MII_REG_BITS_OFF(x,i,p) do {\
+ u16 w;\
+ velocity_mii_read((p),(i),&(w));\
+ (w)&=(~(x));\
+ velocity_mii_write((p),(i),(w));\
+} while (0)
+
+#define MII_REG_BITS_IS_ON(x,i,p) ({\
+ u16 w;\
+ velocity_mii_read((p),(i),&(w));\
+ ((int) ((w) & (x)));})
+
+#define MII_GET_PHY_ID(p) ({\
+ u32 id;\
+ velocity_mii_read((p),MII_REG_PHYID2,(u16 *) &id);\
+ velocity_mii_read((p),MII_REG_PHYID1,((u16 *) &id)+1);\
+ (id);})
+
+#ifdef LINUX
+/*
+ * Inline debug routine
+ */
+
+
+enum velocity_msg_level {
+ MSG_LEVEL_ERR = 0, //Errors that will cause abnormal operation.
+ MSG_LEVEL_NOTICE = 1, //Some errors need users to be notified.
+ MSG_LEVEL_INFO = 2, //Normal message.
+ MSG_LEVEL_VERBOSE = 3, //Will report all trival errors.
+ MSG_LEVEL_DEBUG = 4 //Only for debug purpose.
+};
+
+#ifdef VELOCITY_DEBUG
+#define ASSERT(x) { \
+ if (!(x)) { \
+ printk(KERN_ERR "assertion %s failed: file %s line %d\n", #x,\
+ __FUNCTION__, __LINE__);\
+ BUG(); \
+ }\
+}
+#define VELOCITY_DBG(p,args...) printk(p, ##args)
+#else
+#define ASSERT(x)
+#define VELOCITY_DBG(x)
+#endif
+
+#define VELOCITY_PRT(l, p, args...) do {if (l<=msglevel) printf( p ,##args);} while (0)
+
+#define VELOCITY_PRT_CAMMASK(p,t) {\
+ int i;\
+ if ((t)==VELOCITY_MULTICAST_CAM) {\
+ for (i=0;i<(MCAM_SIZE/8);i++)\
+ printk("%02X",(p)->mCAMmask[i]);\
+ }\
+ else {\
+ for (i=0;i<(VCAM_SIZE/8);i++)\
+ printk("%02X",(p)->vCAMmask[i]);\
+ }\
+ printk("\n");\
+}
+
+#endif
+
+#define VELOCITY_WOL_MAGIC 0x00000000UL
+#define VELOCITY_WOL_PHY 0x00000001UL
+#define VELOCITY_WOL_ARP 0x00000002UL
+#define VELOCITY_WOL_UCAST 0x00000004UL
+#define VELOCITY_WOL_BCAST 0x00000010UL
+#define VELOCITY_WOL_MCAST 0x00000020UL
+#define VELOCITY_WOL_MAGIC_SEC 0x00000040UL
+
+/*
+ * Flags for options
+ */
+
+#define VELOCITY_FLAGS_TAGGING 0x00000001UL
+#define VELOCITY_FLAGS_TX_CSUM 0x00000002UL
+#define VELOCITY_FLAGS_RX_CSUM 0x00000004UL
+#define VELOCITY_FLAGS_IP_ALIGN 0x00000008UL
+#define VELOCITY_FLAGS_VAL_PKT_LEN 0x00000010UL
+
+#define VELOCITY_FLAGS_FLOW_CTRL 0x01000000UL
+
+/*
+ * Flags for driver status
+ */
+
+#define VELOCITY_FLAGS_OPENED 0x00010000UL
+#define VELOCITY_FLAGS_VMNS_CONNECTED 0x00020000UL
+#define VELOCITY_FLAGS_VMNS_COMMITTED 0x00040000UL
+#define VELOCITY_FLAGS_WOL_ENABLED 0x00080000UL
+
+/*
+ * Flags for MII status
+ */
+
+#define VELOCITY_LINK_FAIL 0x00000001UL
+#define VELOCITY_SPEED_10 0x00000002UL
+#define VELOCITY_SPEED_100 0x00000004UL
+#define VELOCITY_SPEED_1000 0x00000008UL
+#define VELOCITY_DUPLEX_FULL 0x00000010UL
+#define VELOCITY_AUTONEG_ENABLE 0x00000020UL
+#define VELOCITY_FORCED_BY_EEPROM 0x00000040UL
+
+/*
+ * For velocity_set_media_duplex
+ */
+
+#define VELOCITY_LINK_CHANGE 0x00000001UL
+
+enum speed_opt {
+ SPD_DPX_AUTO = 0,
+ SPD_DPX_100_HALF = 1,
+ SPD_DPX_100_FULL = 2,
+ SPD_DPX_10_HALF = 3,
+ SPD_DPX_10_FULL = 4
+};
+
+enum velocity_init_type {
+ VELOCITY_INIT_COLD = 0,
+ VELOCITY_INIT_RESET,
+ VELOCITY_INIT_WOL
+};
+
+enum velocity_flow_cntl_type {
+ FLOW_CNTL_DEFAULT = 1,
+ FLOW_CNTL_TX,
+ FLOW_CNTL_RX,
+ FLOW_CNTL_TX_RX,
+ FLOW_CNTL_DISABLE,
+};
+
+struct velocity_opt {
+ int numrx; /* Number of RX descriptors */
+ int numtx; /* Number of TX descriptors */
+ enum speed_opt spd_dpx; /* Media link mode */
+ int vid; /* vlan id */
+ int DMA_length; /* DMA length */
+ int rx_thresh; /* RX_THRESH */
+ int flow_cntl;
+ int wol_opts; /* Wake on lan options */
+ int td_int_count;
+ int int_works;
+ int rx_bandwidth_hi;
+ int rx_bandwidth_lo;
+ int rx_bandwidth_en;
+ u32 flags;
+};
+
+#define RX_DESC_MIN 4
+#define RX_DESC_MAX 255
+#define RX_DESC_DEF 64
+
+#define TX_DESC_MIN 1
+#define TX_DESC_MAX 256
+#define TX_DESC_DEF 4
+
+struct velocity_info {
+// struct list_head list;
+
+ struct pci_device *pdev;
+// struct net_device *dev;
+// struct net_device_stats stats;
+
+#ifdef CONFIG_PM
+ u32 pci_state[16];
+#endif
+
+// dma_addr_t rd_pool_dma;
+// dma_addr_t td_pool_dma[TX_QUEUE_NO];
+
+// dma_addr_t tx_bufs_dma;
+ u8 *tx_bufs;
+
+ u8 ip_addr[4];
+ enum chip_type chip_id;
+
+ struct mac_regs *mac_regs;
+ unsigned long memaddr;
+ unsigned long ioaddr;
+ u32 io_size;
+
+ u8 rev_id;
+
+#define AVAIL_TD(p,q) ((p)->options.numtx-((p)->td_used[(q)]))
+
+ int num_txq;
+
+ volatile int td_used[TX_QUEUE_NO];
+ int td_curr;
+ int td_tail[TX_QUEUE_NO];
+ unsigned char *TxDescArrays; /* Index of Tx Descriptor buffer */
+ unsigned char *RxDescArrays; /* Index of Rx Descriptor buffer */
+ unsigned char *tx_buffs;
+ unsigned char *rx_buffs;
+
+ unsigned char *txb;
+ unsigned char *rxb;
+ struct tx_desc *td_rings;
+ struct velocity_td_info *td_infos[TX_QUEUE_NO];
+
+ int rd_curr;
+ int rd_dirty;
+ u32 rd_filled;
+ struct rx_desc *rd_ring;
+ struct velocity_rd_info *rd_info; /* It's an array */
+
+#define GET_RD_BY_IDX(vptr, idx) (vptr->rd_ring[idx])
+ u32 mib_counter[MAX_HW_MIB_COUNTER];
+ struct velocity_opt options;
+
+ u32 int_mask;
+
+ u32 flags;
+
+ int rx_buf_sz;
+ u32 mii_status;
+ u32 phy_id;
+ int multicast_limit;
+
+ u8 vCAMmask[(VCAM_SIZE / 8)];
+ u8 mCAMmask[(MCAM_SIZE / 8)];
+
+// spinlock_t lock;
+
+ int wol_opts;
+ u8 wol_passwd[6];
+
+ struct velocity_context context;
+
+ u32 ticks;
+ u32 rx_bytes;
+
+} vptx;
+
+static struct velocity_info *vptr;
+
+#ifdef LINUX
+/**
+ * velocity_get_ip - find an IP address for the device
+ * @vptr: Velocity to query
+ *
+ * Dig out an IP address for this interface so that we can
+ * configure wakeup with WOL for ARP. If there are multiple IP
+ * addresses on this chain then we use the first - multi-IP WOL is not
+ * supported.
+ *
+ * CHECK ME: locking
+ */
+
+inline static int velocity_get_ip(struct velocity_info *vptr)
+{
+ struct in_device *in_dev = (struct in_device *) vptr->dev->ip_ptr;
+ struct in_ifaddr *ifa;
+
+ if (in_dev != NULL) {
+ ifa = (struct in_ifaddr *) in_dev->ifa_list;
+ if (ifa != NULL) {
+ memcpy(vptr->ip_addr, &ifa->ifa_address, 4);
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+
+/**
+ * velocity_update_hw_mibs - fetch MIB counters from chip
+ * @vptr: velocity to update
+ *
+ * The velocity hardware keeps certain counters in the hardware
+ * side. We need to read these when the user asks for statistics
+ * or when they overflow (causing an interrupt). The read of the
+ * statistic clears it, so we keep running master counters in user
+ * space.
+ */
+
+static inline void velocity_update_hw_mibs(struct velocity_info *vptr)
+{
+ u32 tmp;
+ int i;
+ BYTE_REG_BITS_ON(MIBCR_MIBFLSH, &(vptr->mac_regs->MIBCR));
+
+ while (BYTE_REG_BITS_IS_ON
+ (MIBCR_MIBFLSH, &(vptr->mac_regs->MIBCR)));
+
+ BYTE_REG_BITS_ON(MIBCR_MPTRINI, &(vptr->mac_regs->MIBCR));
+ for (i = 0; i < HW_MIB_SIZE; i++) {
+ tmp = readl(&(vptr->mac_regs->MIBData)) & 0x00FFFFFFUL;
+ vptr->mib_counter[i] += tmp;
+ }
+}
+#endif
+/**
+ * init_flow_control_register - set up flow control
+ * @vptr: velocity to configure
+ *
+ * Configure the flow control registers for this velocity device.
+ */
+
+static inline void init_flow_control_register(struct velocity_info *vptr)
+{
+ struct mac_regs *regs = vptr->mac_regs;
+
+ /* Set {XHITH1, XHITH0, XLTH1, XLTH0} in FlowCR1 to {1, 0, 1, 1}
+ depend on RD=64, and Turn on XNOEN in FlowCR1 */
+ writel((CR0_XONEN | CR0_XHITH1 | CR0_XLTH1 | CR0_XLTH0),
+ &regs->CR0Set);
+ writel((CR0_FDXTFCEN | CR0_FDXRFCEN | CR0_HDXFCEN | CR0_XHITH0),
+ &regs->CR0Clr);
+
+ /* Set TxPauseTimer to 0xFFFF */
+ writew(0xFFFF, &regs->tx_pause_timer);
+
+ /* Initialize RBRDU to Rx buffer count. */
+ writew(vptr->options.numrx, &regs->RBRDU);
+}
+
+
+#endif