Merge from Etherboot 5.4
authorMichael Brown <mcb30@etherboot.org>
Thu, 16 Mar 2006 18:30:54 +0000 (18:30 +0000)
committerMichael Brown <mcb30@etherboot.org>
Thu, 16 Mar 2006 18:30:54 +0000 (18:30 +0000)
1  2 
src/arch/i386/core/start32.S
src/drivers/net/3c90x.c
src/drivers/net/etherfabric.c
src/drivers/net/etherfabric.h
src/drivers/net/mlx_ipoib/patches/dhcpd.patch
src/drivers/net/mlx_ipoib/samples/dhcpd.conf
src/drivers/net/pcnet32.c
src/drivers/net/via-velocity.c
src/drivers/net/via-velocity.h

@@@ -116,8 -116,8 +116,9 @@@ os_regs_ptr
        movl    %esp, %ebp
        subl    $os_regs, %ebp
        
--      /* Load the stack pointer */
++      /* Load the stack pointer and convert it to physical address */
        movl    52(%esp), %esp
++      addl    %ebp, %esp
  
        /* Enable the virtual addresses */
        leal    _phys_to_virt(%ebp), %eax
@@@ -242,6 -242,6 +242,7 @@@ typedef struc
  /*** Global variables ***/
  static struct
      {
++    unsigned int      is3c556;
      unsigned char     isBrev;
      unsigned char     CurrentWindow;
      unsigned int      IOAddr;
@@@ -305,7 -305,7 +306,15 @@@ a3c90x_internal_ReadEeprom(int ioaddr, 
        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 -710,6 +719,7 @@@ static int a3c90x_probe ( struct nic *n
      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))
      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 -967,6 +986,7 @@@ static struct nic_operations a3c90x_ope
  
  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 */
index 0000000,0000000..9b2f649
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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:
++ */
index 0000000,0000000..950f8de
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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:
++ */
index 0000000,0000000..e2d0a20
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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.
++ 
index 0000000,0000000..ed6975f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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;
++}
++
@@@ -434,6 -441,6 +434,7 @@@ static void pcnet32_reset(struct nic *n
        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;
                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 -632,10 +639,10 @@@ static void pcnet32_disable ( struct ni
        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 -698,7 +705,7 @@@ static int pcnet32_probe ( struct nic *
        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;
  
                mii = 1;
                break;
        default:
++              chipname = "UNKNOWN";
                printf("PCnet version %#x, no PCnet32 chip.\n",
                       chip_version);
                return 0;
                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 */
        /* 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);
  
         */
        /* 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 */
                        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 -986,9 +1001,9 @@@ static struct nic_operations pcnet32_op
  };
  
  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 );
index 0000000,0000000..c51cc35
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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,
++};
index 0000000,0000000..a6c132d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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