Imported from Etherboot 5.4 tree
authorMichael Brown <mcb30@etherboot.org>
Thu, 19 May 2005 16:51:32 +0000 (16:51 +0000)
committerMichael Brown <mcb30@etherboot.org>
Thu, 19 May 2005 16:51:32 +0000 (16:51 +0000)
1  2 
src/drivers/net/amd8111e.c
src/drivers/net/amd8111e.h
src/proto/fsp.c

index 0000000,0000000..611cbc8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,681 @@@
++/* Advanced  Micro Devices Inc. AMD8111E Linux Network Driver 
++ * Copyright (C) 2004 Advanced Micro Devices 
++ * Copyright (C) 2005 Liu Tao <liutao1980@gmail.com> [etherboot port]
++ * 
++ * Copyright 2001,2002 Jeff Garzik <jgarzik@mandrakesoft.com> [ 8139cp.c,tg3.c ]
++ * Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com)[ tg3.c]
++ * Copyright 1996-1999 Thomas Bogendoerfer [ pcnet32.c ]
++ * Derived from the lance driver written 1993,1994,1995 by Donald Becker.
++ * Copyright 1993 United States Government as represented by the
++ *    Director, National Security Agency.[ pcnet32.c ]
++ * Carsten Langgaard, carstenl@mips.com [ pcnet32.c ]
++ * Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
++ *
++ * 
++ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 
++ * USA
++ */
++
++#include "etherboot.h"
++#include "nic.h"
++#include "mii.h"
++#include "pci.h"
++#include "timer.h"
++#include "string.h"
++#include "stdint.h"
++#include "amd8111e.h"
++
++
++/* driver definitions */
++#define NUM_TX_SLOTS  2
++#define NUM_RX_SLOTS  4
++#define TX_SLOTS_MASK 1
++#define RX_SLOTS_MASK 3
++
++#define TX_BUF_LEN    1536
++#define RX_BUF_LEN    1536
++
++#define TX_PKT_LEN_MAX        (ETH_FRAME_LEN - ETH_HLEN)
++#define RX_PKT_LEN_MIN        60
++#define RX_PKT_LEN_MAX        ETH_FRAME_LEN
++
++#define TX_TIMEOUT    3000
++#define TX_PROCESS_TIME       10
++#define TX_RETRY      (TX_TIMEOUT / TX_PROCESS_TIME)
++
++#define PHY_RW_RETRY  10
++
++
++struct amd8111e_tx_desc {
++      u16 buf_len;
++      u16 tx_flags;
++      u16 tag_ctrl_info;
++      u16 tag_ctrl_cmd;
++      u32 buf_phy_addr;
++      u32 reserved;
++}; 
++
++struct amd8111e_rx_desc {
++      u32 reserved;
++      u16 msg_len;
++      u16 tag_ctrl_info; 
++      u16 buf_len;
++      u16 rx_flags;
++      u32 buf_phy_addr;
++};
++
++struct eth_frame {
++      u8 dst_addr[ETH_ALEN];
++      u8 src_addr[ETH_ALEN];
++      u16 type;
++      u8 data[ETH_FRAME_LEN - ETH_HLEN];
++} __attribute__((packed));
++
++struct amd8111e_priv {
++      struct amd8111e_tx_desc tx_ring[NUM_TX_SLOTS];
++      struct amd8111e_rx_desc rx_ring[NUM_RX_SLOTS];
++      unsigned char tx_buf[NUM_TX_SLOTS][TX_BUF_LEN];
++      unsigned char rx_buf[NUM_RX_SLOTS][RX_BUF_LEN];
++      unsigned long tx_idx, rx_idx;
++      int tx_consistent;
++
++      char opened;
++      char link;
++      char speed;
++      char duplex;
++      int ext_phy_addr;
++      u32 ext_phy_id;
++
++      struct pci_device *pdev;
++      struct nic *nic;
++      void *mmio;
++};
++
++static struct amd8111e_priv amd8111e;
++
++
++/********************************************************
++ *            locale functions                        *
++ ********************************************************/
++static void amd8111e_init_hw_default(struct amd8111e_priv *lp);
++static int amd8111e_start(struct amd8111e_priv *lp);
++static int amd8111e_read_phy(struct amd8111e_priv *lp, int phy_addr, int reg, u32 *val);
++#if 0
++static int amd8111e_write_phy(struct amd8111e_priv *lp, int phy_addr, int reg, u32 val);
++#endif
++static void amd8111e_probe_ext_phy(struct amd8111e_priv *lp);
++static void amd8111e_disable_interrupt(struct amd8111e_priv *lp);
++static void amd8111e_enable_interrupt(struct amd8111e_priv *lp);
++static void amd8111e_force_interrupt(struct amd8111e_priv *lp);
++static int amd8111e_get_mac_address(struct amd8111e_priv *lp);
++static int amd8111e_init_rx_ring(struct amd8111e_priv *lp);
++static int amd8111e_init_tx_ring(struct amd8111e_priv *lp);
++static int amd8111e_wait_tx_ring(struct amd8111e_priv *lp, unsigned int index);
++static void amd8111e_wait_link(struct amd8111e_priv *lp);
++static void amd8111e_poll_link(struct amd8111e_priv *lp);
++static void amd8111e_restart(struct amd8111e_priv *lp);
++
++
++/* 
++ * This function clears necessary the device registers. 
++ */   
++static void amd8111e_init_hw_default(struct amd8111e_priv *lp)
++{
++      unsigned int reg_val;
++      unsigned int logic_filter[2] = {0,};
++      void *mmio = lp->mmio;
++
++        /* stop the chip */
++      writel(RUN, mmio + CMD0);
++
++      /* Clear RCV_RING_BASE_ADDR */
++      writel(0, mmio + RCV_RING_BASE_ADDR0);
++
++      /* Clear XMT_RING_BASE_ADDR */
++      writel(0, mmio + XMT_RING_BASE_ADDR0);
++      writel(0, mmio + XMT_RING_BASE_ADDR1);
++      writel(0, mmio + XMT_RING_BASE_ADDR2);
++      writel(0, mmio + XMT_RING_BASE_ADDR3);
++
++      /* Clear CMD0  */
++      writel(CMD0_CLEAR, mmio + CMD0);
++      
++      /* Clear CMD2 */
++      writel(CMD2_CLEAR, mmio + CMD2);
++
++      /* Clear CMD7 */
++      writel(CMD7_CLEAR, mmio + CMD7);
++
++      /* Clear DLY_INT_A and DLY_INT_B */
++      writel(0x0, mmio + DLY_INT_A);
++      writel(0x0, mmio + DLY_INT_B);
++
++      /* Clear FLOW_CONTROL */
++      writel(0x0, mmio + FLOW_CONTROL);
++
++      /* Clear INT0  write 1 to clear register */
++      reg_val = readl(mmio + INT0);
++      writel(reg_val, mmio + INT0);
++
++      /* Clear STVAL */
++      writel(0x0, mmio + STVAL);
++
++      /* Clear INTEN0 */
++      writel(INTEN0_CLEAR, mmio + INTEN0);
++
++      /* Clear LADRF */
++      writel(0x0, mmio + LADRF);
++
++      /* Set SRAM_SIZE & SRAM_BOUNDARY registers  */
++      writel(0x80010, mmio + SRAM_SIZE);
++
++      /* Clear RCV_RING0_LEN */
++      writel(0x0, mmio +  RCV_RING_LEN0);
++
++      /* Clear XMT_RING0/1/2/3_LEN */
++      writel(0x0, mmio +  XMT_RING_LEN0);
++      writel(0x0, mmio +  XMT_RING_LEN1);
++      writel(0x0, mmio +  XMT_RING_LEN2);
++      writel(0x0, mmio +  XMT_RING_LEN3);
++
++      /* Clear XMT_RING_LIMIT */
++      writel(0x0, mmio + XMT_RING_LIMIT);
++
++      /* Clear MIB */
++      writew(MIB_CLEAR, mmio + MIB_ADDR);
++
++      /* Clear LARF */
++      amd8111e_writeq(*(u64*)logic_filter, mmio + LADRF);
++
++      /* SRAM_SIZE register */
++      reg_val = readl(mmio + SRAM_SIZE);
++      
++      /* Set default value to CTRL1 Register */
++      writel(CTRL1_DEFAULT, mmio + CTRL1);
++
++      /* To avoid PCI posting bug */
++      readl(mmio + CMD2);
++}
++
++/* 
++ * This function initializes the device registers  and starts the device.  
++ */
++static int amd8111e_start(struct amd8111e_priv *lp)
++{
++      struct nic *nic = lp->nic;
++      void *mmio = lp->mmio;
++      int i, reg_val;
++
++      /* stop the chip */
++      writel(RUN, mmio + CMD0);
++
++      /* AUTOPOLL0 Register *//*TBD default value is 8100 in FPS */
++      writew(0x8100 | lp->ext_phy_addr, mmio + AUTOPOLL0);
++
++      /* enable the port manager and set auto negotiation always */
++      writel(VAL1 | EN_PMGR, mmio + CMD3 );
++      writel(XPHYANE | XPHYRST, mmio + CTRL2); 
++
++      /* set control registers */
++      reg_val = readl(mmio + CTRL1);
++      reg_val &= ~XMTSP_MASK;
++      writel(reg_val | XMTSP_128 | CACHE_ALIGN, mmio + CTRL1);
++
++      /* initialize tx and rx ring base addresses */
++      amd8111e_init_tx_ring(lp);
++      amd8111e_init_rx_ring(lp);
++      writel(virt_to_bus(lp->tx_ring), mmio + XMT_RING_BASE_ADDR0);
++      writel(virt_to_bus(lp->rx_ring), mmio + RCV_RING_BASE_ADDR0);
++      writew(NUM_TX_SLOTS, mmio + XMT_RING_LEN0);
++      writew(NUM_RX_SLOTS, mmio + RCV_RING_LEN0);
++      
++      /* set default IPG to 96 */
++      writew(DEFAULT_IPG, mmio + IPG);
++      writew(DEFAULT_IPG - IFS1_DELTA, mmio + IFS1); 
++
++      /* AutoPAD transmit, Retransmit on Underflow */
++      writel(VAL0 | APAD_XMT | REX_RTRY | REX_UFLO, mmio + CMD2);
++      
++      /* JUMBO disabled */
++      writel(JUMBO, mmio + CMD3);
++
++      /* Setting the MAC address to the device */
++      for(i = 0; i < ETH_ALEN; i++)
++              writeb(nic->node_addr[i], mmio + PADR + i); 
++
++      /* set RUN bit to start the chip, interrupt not enabled */
++      writel(VAL2 | RDMD0 | VAL0 | RUN, mmio + CMD0);
++      
++      /* To avoid PCI posting bug */
++      readl(mmio + CMD0);
++      return 0;
++}
++
++/* 
++This function will read the PHY registers.
++*/
++static int amd8111e_read_phy(struct amd8111e_priv *lp, int phy_addr, int reg, u32 *val)
++{
++      void *mmio = lp->mmio;
++      unsigned int reg_val;
++      unsigned int retry = PHY_RW_RETRY;
++
++      reg_val = readl(mmio + PHY_ACCESS);
++      while (reg_val & PHY_CMD_ACTIVE)
++              reg_val = readl(mmio + PHY_ACCESS);
++
++      writel(PHY_RD_CMD | ((phy_addr & 0x1f) << 21) | ((reg & 0x1f) << 16),
++              mmio + PHY_ACCESS);
++      do {
++              reg_val = readl(mmio + PHY_ACCESS);
++              udelay(30);  /* It takes 30 us to read/write data */
++      } while (--retry && (reg_val & PHY_CMD_ACTIVE));
++
++      if (reg_val & PHY_RD_ERR) {
++              *val = 0;
++              return -1;
++      }
++      
++      *val = reg_val & 0xffff;
++      return 0;
++}
++
++/* 
++This function will write into PHY registers. 
++*/
++#if 0
++static int amd8111e_write_phy(struct amd8111e_priv *lp, int phy_addr, int reg, u32 val)
++{
++      void *mmio = lp->mmio;
++      unsigned int reg_val;
++      unsigned int retry = PHY_RW_RETRY;
++
++      reg_val = readl(mmio + PHY_ACCESS);
++      while (reg_val & PHY_CMD_ACTIVE)
++              reg_val = readl(mmio + PHY_ACCESS);
++
++      writel(PHY_WR_CMD | ((phy_addr & 0x1f) << 21) | ((reg & 0x1f) << 16) | val,
++              mmio + PHY_ACCESS);
++      do {
++              reg_val = readl(mmio + PHY_ACCESS);
++              udelay(30);  /* It takes 30 us to read/write the data */
++      } while (--retry && (reg_val & PHY_CMD_ACTIVE));
++      
++      if(reg_val & PHY_RD_ERR)
++              return -1;
++
++      return 0;
++}
++#endif
++
++static void amd8111e_probe_ext_phy(struct amd8111e_priv *lp)
++{
++      int i;
++
++      lp->ext_phy_id = 0;
++      lp->ext_phy_addr = 1;
++      
++      for (i = 0x1e; i >= 0; i--) {
++              u32 id1, id2;
++
++              if (amd8111e_read_phy(lp, i, MII_PHYSID1, &id1))
++                      continue;
++              if (amd8111e_read_phy(lp, i, MII_PHYSID2, &id2))
++                      continue;
++              lp->ext_phy_id = (id1 << 16) | id2;
++              lp->ext_phy_addr = i;
++              break;
++      }
++
++      if (lp->ext_phy_id)
++              printf("Found MII PHY ID 0x%08x at address 0x%02x\n",
++                      lp->ext_phy_id, lp->ext_phy_addr);
++      else
++              printf("Couldn't detect MII PHY, assuming address 0x01\n");
++}
++
++static void amd8111e_disable_interrupt(struct amd8111e_priv *lp)
++{
++      void *mmio = lp->mmio;
++      unsigned int int0;
++
++      writel(INTREN, mmio + CMD0);
++      writel(INTEN0_CLEAR, mmio + INTEN0);
++      int0 = readl(mmio + INT0);
++      writel(int0, mmio + INT0);
++      readl(mmio + INT0);
++}
++
++static void amd8111e_enable_interrupt(struct amd8111e_priv *lp)
++{
++      void *mmio = lp->mmio;
++
++      writel(VAL3 | LCINTEN | VAL1 | TINTEN0 | VAL0 | RINTEN0, mmio + INTEN0);
++      writel(VAL0 | INTREN, mmio + CMD0);
++      readl(mmio + CMD0);
++}
++
++static void amd8111e_force_interrupt(struct amd8111e_priv *lp)
++{
++      void *mmio = lp->mmio;
++
++      writel(VAL0 | UINTCMD, mmio + CMD0);
++      readl(mmio + CMD0);
++}
++
++static int amd8111e_get_mac_address(struct amd8111e_priv *lp)
++{
++      struct nic *nic = lp->nic;
++      void *mmio = lp->mmio;
++      int i;
++
++      /* BIOS should have set mac address to PADR register,
++       * so we read PADR to get it.
++       */
++      for (i = 0; i < ETH_ALEN; i++)
++              nic->node_addr[i] = readb(mmio + PADR + i);
++      printf("Ethernet addr: %!\n", nic->node_addr);
++
++      return 0;
++}
++
++static int amd8111e_init_rx_ring(struct amd8111e_priv *lp)
++{
++      int i;
++
++      lp->rx_idx = 0;
++      
++        /* Initilaizing receive descriptors */
++      for (i = 0; i < NUM_RX_SLOTS; i++) {
++              lp->rx_ring[i].buf_phy_addr = cpu_to_le32(virt_to_bus(lp->rx_buf[i]));
++              lp->rx_ring[i].buf_len = cpu_to_le16(RX_BUF_LEN);
++              wmb();
++              lp->rx_ring[i].rx_flags = cpu_to_le16(OWN_BIT);
++      }
++
++      return 0;
++}
++
++static int amd8111e_init_tx_ring(struct amd8111e_priv *lp)
++{
++      int i;
++
++      lp->tx_idx = 0;
++      lp->tx_consistent = 1;
++      
++      /* Initializing transmit descriptors */
++      for (i = 0; i < NUM_TX_SLOTS; i++) {
++              lp->tx_ring[i].tx_flags = 0;
++              lp->tx_ring[i].buf_phy_addr = 0;
++              lp->tx_ring[i].buf_len = 0;
++      }
++
++      return 0;
++}
++
++static int amd8111e_wait_tx_ring(struct amd8111e_priv *lp, unsigned int index)
++{
++      volatile u16 status;
++      int retry = TX_RETRY;
++
++      status = le16_to_cpu(lp->tx_ring[index].tx_flags);
++      while (--retry && (status & OWN_BIT)) {
++              mdelay(TX_PROCESS_TIME);
++              status = le16_to_cpu(lp->tx_ring[index].tx_flags);
++      }
++      if (status & OWN_BIT) {
++              printf("Error: tx slot %d timeout, stat = 0x%x\n", index, status);
++              amd8111e_restart(lp);
++              return -1;
++      }
++
++      return 0;
++}
++
++static void amd8111e_wait_link(struct amd8111e_priv *lp)
++{
++      unsigned int status;
++      u32 reg_val;
++
++      do {
++              /* read phy to update STAT0 register */
++              amd8111e_read_phy(lp, lp->ext_phy_addr, MII_BMCR, &reg_val);
++              amd8111e_read_phy(lp, lp->ext_phy_addr, MII_BMSR, &reg_val);
++              amd8111e_read_phy(lp, lp->ext_phy_addr, MII_ADVERTISE, &reg_val);
++              amd8111e_read_phy(lp, lp->ext_phy_addr, MII_LPA, &reg_val);
++              status = readl(lp->mmio + STAT0);
++      } while (!(status & AUTONEG_COMPLETE) || !(status & LINK_STATS));
++}
++
++static void amd8111e_poll_link(struct amd8111e_priv *lp)
++{
++      unsigned int status, speed;
++      u32 reg_val;
++
++      if (!lp->link) {
++              /* read phy to update STAT0 register */
++              amd8111e_read_phy(lp, lp->ext_phy_addr, MII_BMCR, &reg_val);
++              amd8111e_read_phy(lp, lp->ext_phy_addr, MII_BMSR, &reg_val);
++              amd8111e_read_phy(lp, lp->ext_phy_addr, MII_ADVERTISE, &reg_val);
++              amd8111e_read_phy(lp, lp->ext_phy_addr, MII_LPA, &reg_val);
++              status = readl(lp->mmio + STAT0);
++
++              if (status & LINK_STATS) {
++                      lp->link = 1;
++                      speed = (status & SPEED_MASK) >> 7;
++                      if (speed == PHY_SPEED_100)
++                              lp->speed = 1;
++                      else
++                              lp->speed = 0;
++                      if (status & FULL_DPLX)
++                              lp->duplex = 1;
++                      else
++                              lp->duplex = 0;
++
++                      printf("Link is up: %s Mbps %s duplex\n",
++                              lp->speed ? "100" : "10", lp->duplex ? "full" : "half");
++              }
++      } else {
++              status = readl(lp->mmio + STAT0);
++              if (!(status & LINK_STATS)) {
++                      lp->link = 0;
++                      printf("Link is down\n");
++              }
++      }
++}
++
++static void amd8111e_restart(struct amd8111e_priv *lp)
++{
++      printf("\nStarting nic...\n");
++      amd8111e_disable_interrupt(lp);
++      amd8111e_init_hw_default(lp);
++      amd8111e_probe_ext_phy(lp);
++      amd8111e_get_mac_address(lp);
++      amd8111e_start(lp);
++
++      printf("Waiting link up...\n");
++      lp->link = 0;
++      amd8111e_wait_link(lp);
++      amd8111e_poll_link(lp);
++}
++
++
++/********************************************************
++ *            Interface Functions                     *
++ ********************************************************/
++
++static void amd8111e_transmit(struct nic *nic, const char *dst_addr,
++              unsigned int type, unsigned int size, const char *packet)
++{
++      struct amd8111e_priv *lp = nic->priv_data;
++      struct eth_frame *frame;
++      unsigned int index;
++
++      /* check packet size */
++      if (size > TX_PKT_LEN_MAX) {
++              printf("amd8111e_transmit(): too large packet, drop\n");
++              return;
++      }
++
++      /* get tx slot */
++      index = lp->tx_idx;
++      if (amd8111e_wait_tx_ring(lp, index))
++              return;
++
++      /* fill frame */
++      frame = (struct eth_frame *)lp->tx_buf[index];
++      memset(frame->data, 0, TX_PKT_LEN_MAX);
++      memcpy(frame->dst_addr, dst_addr, ETH_ALEN);
++      memcpy(frame->src_addr, nic->node_addr, ETH_ALEN);
++      frame->type = htons(type);
++      memcpy(frame->data, packet, size);
++
++      /* start xmit */
++      lp->tx_ring[index].buf_len = cpu_to_le16(ETH_HLEN + size);
++      lp->tx_ring[index].buf_phy_addr = cpu_to_le32(virt_to_bus(frame));
++      wmb();
++      lp->tx_ring[index].tx_flags = 
++              cpu_to_le16(OWN_BIT | STP_BIT | ENP_BIT | ADD_FCS_BIT | LTINT_BIT);
++      writel(VAL1 | TDMD0, lp->mmio + CMD0);
++      readl(lp->mmio + CMD0);
++
++      /* update slot pointer */
++      lp->tx_idx = (lp->tx_idx + 1) & TX_SLOTS_MASK;
++}
++
++static int amd8111e_poll(struct nic *nic, int retrieve)
++{
++      /* return true if there's an ethernet packet ready to read */
++      /* nic->packet should contain data on return */
++      /* nic->packetlen should contain length of data */
++
++      struct amd8111e_priv *lp = nic->priv_data;
++      u16 status, pkt_len;
++      unsigned int index, pkt_ok;
++
++      amd8111e_poll_link(lp);
++
++      index = lp->rx_idx;
++      status = le16_to_cpu(lp->rx_ring[index].rx_flags);
++      pkt_len = le16_to_cpu(lp->rx_ring[index].msg_len) - 4;  /* remove 4bytes FCS */
++      
++      if (status & OWN_BIT)
++              return 0;
++
++      if (status & ERR_BIT)
++              pkt_ok = 0;
++      else if (!(status & STP_BIT))
++              pkt_ok = 0;
++      else if (!(status & ENP_BIT))
++              pkt_ok = 0;
++      else if (pkt_len < RX_PKT_LEN_MIN)
++              pkt_ok = 0;
++      else if (pkt_len > RX_PKT_LEN_MAX)
++              pkt_ok = 0;
++      else
++              pkt_ok = 1;
++
++      if (pkt_ok) {
++              if (!retrieve)
++                      return 1;
++              nic->packetlen = pkt_len;
++              memcpy(nic->packet, lp->rx_buf[index], nic->packetlen);
++      }
++
++      lp->rx_ring[index].buf_phy_addr = cpu_to_le32(virt_to_bus(lp->rx_buf[index]));
++      lp->rx_ring[index].buf_len = cpu_to_le16(RX_BUF_LEN);
++      wmb();
++      lp->rx_ring[index].rx_flags = cpu_to_le16(OWN_BIT);
++      writel(VAL2 | RDMD0, lp->mmio + CMD0);
++      readl(lp->mmio + CMD0);
++
++      lp->rx_idx = (lp->rx_idx + 1) & RX_SLOTS_MASK;
++      return pkt_ok;
++}
++
++static void amd8111e_disable(struct nic *nic)
++{
++      struct amd8111e_priv *lp = nic->priv_data;
++
++      /* disable interrupt */
++      amd8111e_disable_interrupt(lp);
++
++      /* stop chip */
++      amd8111e_init_hw_default(lp);
++
++      /* unmap mmio */
++      iounmap(lp->mmio);
++
++      /* update status */
++      lp->opened = 0;
++}
++
++static void amd8111e_irq(struct nic *nic, irq_action_t action)
++{
++      struct amd8111e_priv *lp = nic->priv_data;
++              
++      switch (action) {
++      case DISABLE:
++              amd8111e_disable_interrupt(lp);
++              break;
++      case ENABLE:
++              amd8111e_enable_interrupt(lp);
++              break;
++      case FORCE:
++              amd8111e_force_interrupt(lp);
++              break;
++      }
++}
++
++static struct nic_operations amd8111e_operations = {
++      .connect        = dummy_connect,
++      .poll           = amd8111e_poll,
++      .transmit       = amd8111e_transmit,
++      .irq            = amd8111e_irq,
++};
++
++static int amd8111e_probe(struct nic *nic, struct pci_device *pdev)
++{
++      struct amd8111e_priv *lp = &amd8111e;
++      unsigned long mmio_start, mmio_len;
++
++      pci_fill_nic ( nic, pdev );
++      
++      mmio_start = pci_bar_start(pdev, PCI_BASE_ADDRESS_0);
++      mmio_len = pci_bar_size(pdev, PCI_BASE_ADDRESS_0);
++
++      memset(lp, 0, sizeof(*lp));
++      lp->pdev = pdev;
++      lp->nic = nic;
++      lp->mmio = ioremap(mmio_start, mmio_len);
++      lp->opened = 1;
++      adjust_pci_device(pdev);
++
++      nic->priv_data = lp;
++
++      amd8111e_restart(lp);
++
++      nic->nic_op     = &amd8111e_operations;
++      return 1;
++}
++
++static struct pci_id amd8111e_nics[] = {
++      PCI_ROM(0x1022, 0x7462, "amd8111e",     "AMD8111E"),
++};
++
++PCI_DRIVER ( amd8111e_driver, amd8111e_nics, PCI_NO_CLASS );
++
++DRIVER ( "AMD8111E", nic_driver, pci_driver, amd8111e_driver,
++       amd8111e_probe, amd8111e_disable );
index 0000000,0000000..82b8f7a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,629 @@@
++/*
++ * Advanced  Micro Devices Inc. AMD8111E Linux Network Driver 
++ * Copyright (C) 2003 Advanced Micro Devices 
++ *
++ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 
++ * USA
++
++Module Name:
++
++    amd8111e.h
++
++Abstract:
++      
++       AMD8111 based 10/100 Ethernet Controller driver definitions. 
++
++Environment:
++    
++      Kernel Mode
++
++Revision History:
++      3.0.0
++         Initial Revision.
++      3.0.1
++*/
++
++#ifndef _AMD811E_H
++#define _AMD811E_H
++
++/* Command style register access
++
++Registers CMD0, CMD2, CMD3,CMD7 and INTEN0 uses a write access technique called command style access. It allows the write to selected bits of this register without altering the bits that are not selected. Command style registers are divided into 4 bytes that can be written independently. Higher order bit of each byte is the  value bit that specifies the value that will be written into the selected bits of register. 
++
++eg., if the value 10011010b is written into the least significant byte of a command style register, bits 1,3 and 4 of the register will be set to 1, and the other bits will not be altered. If the value 00011010b is written into the same byte, bits 1,3 and 4 will be cleared to 0 and the other bits will not be altered.
++
++*/
++
++/*  Offset for Memory Mapped Registers. */
++/* 32 bit registers */
++
++#define  ASF_STAT             0x00    /* ASF status register */
++#define CHIPID                        0x04    /* Chip ID regsiter */
++#define       MIB_DATA                0x10    /* MIB data register */
++#define MIB_ADDR              0x14    /* MIB address register */
++#define STAT0                 0x30    /* Status0 register */
++#define INT0                  0x38    /* Interrupt0 register */
++#define INTEN0                        0x40    /* Interrupt0  enable register*/
++#define CMD0                  0x48    /* Command0 register */
++#define CMD2                  0x50    /* Command2 register */
++#define CMD3                  0x54    /* Command3 resiter */
++#define CMD7                  0x64    /* Command7 register */
++
++#define CTRL1                         0x6C    /* Control1 register */
++#define CTRL2                         0x70    /* Control2 register */
++
++#define XMT_RING_LIMIT                0x7C    /* Transmit ring limit register */
++
++#define AUTOPOLL0             0x88    /* Auto-poll0 register */
++#define AUTOPOLL1             0x8A    /* Auto-poll1 register */
++#define AUTOPOLL2             0x8C    /* Auto-poll2 register */
++#define AUTOPOLL3             0x8E    /* Auto-poll3 register */
++#define AUTOPOLL4             0x90    /* Auto-poll4 register */
++#define       AUTOPOLL5               0x92    /* Auto-poll5 register */
++
++#define AP_VALUE              0x98    /* Auto-poll value register */
++#define DLY_INT_A             0xA8    /* Group A delayed interrupt register */
++#define DLY_INT_B             0xAC    /* Group B delayed interrupt register */
++
++#define FLOW_CONTROL          0xC8    /* Flow control register */
++#define PHY_ACCESS            0xD0    /* PHY access register */
++
++#define STVAL                 0xD8    /* Software timer value register */
++
++#define XMT_RING_BASE_ADDR0   0x100   /* Transmit ring0 base addr register */
++#define XMT_RING_BASE_ADDR1   0x108   /* Transmit ring1 base addr register */
++#define XMT_RING_BASE_ADDR2   0x110   /* Transmit ring2 base addr register */
++#define XMT_RING_BASE_ADDR3   0x118   /* Transmit ring2 base addr register */
++
++#define RCV_RING_BASE_ADDR0   0x120   /* Transmit ring0 base addr register */
++
++#define PMAT0                 0x190   /* OnNow pattern register0 */
++#define PMAT1                 0x194   /* OnNow pattern register1 */
++
++/* 16bit registers */
++
++#define XMT_RING_LEN0         0x140   /* Transmit Ring0 length register */
++#define XMT_RING_LEN1         0x144   /* Transmit Ring1 length register */
++#define XMT_RING_LEN2         0x148   /* Transmit Ring2 length register */
++#define XMT_RING_LEN3         0x14C   /* Transmit Ring3 length register */
++
++#define RCV_RING_LEN0         0x150   /* Receive Ring0 length register */
++
++#define SRAM_SIZE             0x178   /* SRAM size register */
++#define SRAM_BOUNDARY         0x17A   /* SRAM boundary register */
++
++/* 48bit register */
++
++#define PADR                  0x160   /* Physical address register */
++
++#define IFS1                  0x18C   /* Inter-frame spacing Part1 register */
++#define IFS                   0x18D   /* Inter-frame spacing register */
++#define IPG                   0x18E   /* Inter-frame gap register */
++/* 64bit register */
++
++#define LADRF                 0x168   /* Logical address filter register */
++
++
++/* Register Bit Definitions */
++typedef enum {
++
++      ASF_INIT_DONE           = (1 << 1),
++      ASF_INIT_PRESENT        = (1 << 0),
++
++}STAT_ASF_BITS; 
++   
++typedef enum {
++
++      MIB_CMD_ACTIVE          = (1 << 15 ),
++      MIB_RD_CMD              = (1 << 13 ),
++      MIB_CLEAR               = (1 << 12 ),
++      MIB_ADDRESS             = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3)|
++                                      (1 << 4) | (1 << 5),
++}MIB_ADDR_BITS;
++
++
++typedef enum {
++      
++      PMAT_DET                = (1 << 12),
++      MP_DET                  = (1 << 11),
++      LC_DET                  = (1 << 10),
++      SPEED_MASK              = (1 << 9)|(1 << 8)|(1 << 7),
++      FULL_DPLX               = (1 << 6),
++      LINK_STATS              = (1 << 5),
++      AUTONEG_COMPLETE        = (1 << 4),
++      MIIPD                   = (1 << 3),
++      RX_SUSPENDED            = (1 << 2),
++      TX_SUSPENDED            = (1 << 1),
++      RUNNING                 = (1 << 0),
++
++}STAT0_BITS;
++
++#define PHY_SPEED_10          0x2
++#define PHY_SPEED_100         0x3
++
++/* INT0                               0x38, 32bit register */
++typedef enum {
++
++      INTR                    = (1 << 31),
++      PCSINT                  = (1 << 28), 
++      LCINT                   = (1 << 27),
++      APINT5                  = (1 << 26),
++      APINT4                  = (1 << 25),
++      APINT3                  = (1 << 24),
++      TINT_SUM                = (1 << 23),
++      APINT2                  = (1 << 22),
++      APINT1                  = (1 << 21),
++      APINT0                  = (1 << 20),
++      MIIPDTINT               = (1 << 19),
++      MCCINT                  = (1 << 17),
++      MREINT                  = (1 << 16),
++      RINT_SUM                = (1 << 15),
++      SPNDINT                 = (1 << 14),
++      MPINT                   = (1 << 13),
++      SINT                    = (1 << 12),
++      TINT3                   = (1 << 11),
++      TINT2                   = (1 << 10),
++      TINT1                   = (1 << 9),
++      TINT0                   = (1 << 8),
++      UINT                    = (1 << 7),
++      STINT                   = (1 << 4),
++      RINT0                   = (1 << 0),
++
++}INT0_BITS;
++
++typedef enum {
++
++      VAL3                    = (1 << 31),   /* VAL bit for byte 3 */
++      VAL2                    = (1 << 23),   /* VAL bit for byte 2 */
++      VAL1                    = (1 << 15),   /* VAL bit for byte 1 */
++      VAL0                    = (1 << 7),    /* VAL bit for byte 0 */
++
++}VAL_BITS;
++
++typedef enum {
++
++      /* VAL3 */
++      LCINTEN                 = (1 << 27),
++      APINT5EN                = (1 << 26),
++      APINT4EN                = (1 << 25),
++      APINT3EN                = (1 << 24),
++      /* VAL2 */
++      APINT2EN                = (1 << 22),
++      APINT1EN                = (1 << 21),
++      APINT0EN                = (1 << 20),
++      MIIPDTINTEN             = (1 << 19),
++      MCCIINTEN               = (1 << 18),
++      MCCINTEN                = (1 << 17),
++      MREINTEN                = (1 << 16),
++      /* VAL1 */
++      SPNDINTEN               = (1 << 14),
++      MPINTEN                 = (1 << 13),
++      TINTEN3                 = (1 << 11),
++      SINTEN                  = (1 << 12),
++      TINTEN2                 = (1 << 10),
++      TINTEN1                 = (1 << 9),
++      TINTEN0                 = (1 << 8),
++      /* VAL0 */
++      STINTEN                 = (1 << 4),
++      RINTEN0                 = (1 << 0),
++
++      INTEN0_CLEAR            = 0x1F7F7F1F, /* Command style register */
++
++}INTEN0_BITS;         
++
++typedef enum {
++      /* VAL2 */
++      RDMD0                   = (1 << 16),
++      /* VAL1 */
++      TDMD3                   = (1 << 11),
++      TDMD2                   = (1 << 10),
++      TDMD1                   = (1 << 9),
++      TDMD0                   = (1 << 8),
++      /* VAL0 */
++      UINTCMD                 = (1 << 6),
++      RX_FAST_SPND            = (1 << 5),
++      TX_FAST_SPND            = (1 << 4),
++      RX_SPND                 = (1 << 3),
++      TX_SPND                 = (1 << 2),
++      INTREN                  = (1 << 1),
++      RUN                     = (1 << 0),
++
++      CMD0_CLEAR              = 0x000F0F7F,   /* Command style register */    
++
++}CMD0_BITS;
++
++typedef enum {
++
++      /* VAL3 */
++      CONDUIT_MODE            = (1 << 29),
++      /* VAL2 */
++      RPA                     = (1 << 19),
++      DRCVPA                  = (1 << 18),
++      DRCVBC                  = (1 << 17),
++      PROM                    = (1 << 16),
++      /* VAL1 */
++      ASTRP_RCV               = (1 << 13),
++      RCV_DROP0               = (1 << 12),
++      EMBA                    = (1 << 11),
++      DXMT2PD                 = (1 << 10),
++      LTINTEN                 = (1 << 9),
++      DXMTFCS                 = (1 << 8),
++      /* VAL0 */
++      APAD_XMT                = (1 << 6),
++      DRTY                    = (1 << 5),
++      INLOOP                  = (1 << 4),
++      EXLOOP                  = (1 << 3),
++      REX_RTRY                = (1 << 2),
++      REX_UFLO                = (1 << 1),
++      REX_LCOL                = (1 << 0),
++
++      CMD2_CLEAR              = 0x3F7F3F7F,   /* Command style register */
++
++}CMD2_BITS;
++
++typedef enum {
++
++      /* VAL3 */
++      ASF_INIT_DONE_ALIAS     = (1 << 29),
++      /* VAL2 */
++      JUMBO                   = (1 << 21),
++      VSIZE                   = (1 << 20),    
++      VLONLY                  = (1 << 19),
++      VL_TAG_DEL              = (1 << 18),    
++      /* VAL1 */
++      EN_PMGR                 = (1 << 14),                    
++      INTLEVEL                = (1 << 13),
++      FORCE_FULL_DUPLEX       = (1 << 12),    
++      FORCE_LINK_STATUS       = (1 << 11),    
++      APEP                    = (1 << 10),    
++      MPPLBA                  = (1 << 9),     
++      /* VAL0 */
++      RESET_PHY_PULSE         = (1 << 2),     
++      RESET_PHY               = (1 << 1),     
++      PHY_RST_POL             = (1 << 0),     
++
++}CMD3_BITS;
++
++
++typedef enum {
++
++      /* VAL0 */
++      PMAT_SAVE_MATCH         = (1 << 4),
++      PMAT_MODE               = (1 << 3),
++      MPEN_SW                 = (1 << 1),
++      LCMODE_SW               = (1 << 0),
++
++      CMD7_CLEAR              = 0x0000001B    /* Command style register */
++
++}CMD7_BITS;
++
++
++typedef enum {
++
++      RESET_PHY_WIDTH         = (0xF << 16) | (0xF<< 20), /* 0x00FF0000 */
++      XMTSP_MASK              = (1 << 9) | (1 << 8),  /* 9:8 */
++      XMTSP_128               = (1 << 9),     /* 9 */ 
++      XMTSP_64                = (1 << 8),
++      CACHE_ALIGN             = (1 << 4),
++      BURST_LIMIT_MASK        = (0xF << 0 ),
++      CTRL1_DEFAULT           = 0x00010111,
++
++}CTRL1_BITS;
++
++typedef enum {
++
++      FMDC_MASK               = (1 << 9)|(1 << 8),    /* 9:8 */
++      XPHYRST                 = (1 << 7),
++      XPHYANE                 = (1 << 6),
++      XPHYFD                  = (1 << 5),
++      XPHYSP                  = (1 << 4) | (1 << 3),  /* 4:3 */
++      APDW_MASK               = (1 << 2) | (1 << 1) | (1 << 0), /* 2:0 */
++
++}CTRL2_BITS;
++
++/* XMT_RING_LIMIT             0x7C, 32bit register */
++typedef enum {
++
++      XMT_RING2_LIMIT         = (0xFF << 16), /* 23:16 */
++      XMT_RING1_LIMIT         = (0xFF << 8),  /* 15:8 */
++      XMT_RING0_LIMIT         = (0xFF << 0),  /* 7:0 */
++
++}XMT_RING_LIMIT_BITS;
++
++typedef enum {
++
++      AP_REG0_EN              = (1 << 15),
++      AP_REG0_ADDR_MASK       = (0xF << 8) |(1 << 12),/* 12:8 */
++      AP_PHY0_ADDR_MASK       = (0xF << 0) |(1 << 4),/* 4:0 */
++
++}AUTOPOLL0_BITS;
++
++/* AUTOPOLL1                  0x8A, 16bit register */
++typedef enum {
++
++      AP_REG1_EN              = (1 << 15),
++      AP_REG1_ADDR_MASK       = (0xF << 8) |(1 << 12),/* 12:8 */
++      AP_PRE_SUP1             = (1 << 6),
++      AP_PHY1_DFLT            = (1 << 5),
++      AP_PHY1_ADDR_MASK       = (0xF << 0) |(1 << 4),/* 4:0 */
++
++}AUTOPOLL1_BITS;
++
++
++typedef enum {
++
++      AP_REG2_EN              = (1 << 15),
++      AP_REG2_ADDR_MASK       = (0xF << 8) |(1 << 12),/* 12:8 */
++      AP_PRE_SUP2             = (1 << 6),
++      AP_PHY2_DFLT            = (1 << 5),
++      AP_PHY2_ADDR_MASK       = (0xF << 0) |(1 << 4),/* 4:0 */
++
++}AUTOPOLL2_BITS;
++
++typedef enum {
++
++      AP_REG3_EN              = (1 << 15),
++      AP_REG3_ADDR_MASK       = (0xF << 8) |(1 << 12),/* 12:8 */
++      AP_PRE_SUP3             = (1 << 6),
++      AP_PHY3_DFLT            = (1 << 5),
++      AP_PHY3_ADDR_MASK       = (0xF << 0) |(1 << 4),/* 4:0 */
++
++}AUTOPOLL3_BITS;
++
++
++typedef enum {
++
++      AP_REG4_EN              = (1 << 15),
++      AP_REG4_ADDR_MASK       = (0xF << 8) |(1 << 12),/* 12:8 */
++      AP_PRE_SUP4             = (1 << 6),
++      AP_PHY4_DFLT            = (1 << 5),
++      AP_PHY4_ADDR_MASK       = (0xF << 0) |(1 << 4),/* 4:0 */
++
++}AUTOPOLL4_BITS;
++
++
++typedef enum {
++
++      AP_REG5_EN              = (1 << 15),
++      AP_REG5_ADDR_MASK       = (0xF << 8) |(1 << 12),/* 12:8 */
++      AP_PRE_SUP5             = (1 << 6),
++      AP_PHY5_DFLT            = (1 << 5),
++      AP_PHY5_ADDR_MASK       = (0xF << 0) |(1 << 4),/* 4:0 */
++
++}AUTOPOLL5_BITS;
++
++
++
++
++/* AP_VALUE                   0x98, 32bit ragister */
++typedef enum {
++
++      AP_VAL_ACTIVE           = (1 << 31),
++      AP_VAL_RD_CMD           = ( 1 << 29),
++      AP_ADDR                 = (1 << 18)|(1 << 17)|(1 << 16), /* 18:16 */
++      AP_VAL                  = (0xF << 0) | (0xF << 4) |( 0xF << 8) |
++                                (0xF << 12),  /* 15:0 */
++
++}AP_VALUE_BITS;
++
++typedef enum {
++
++      DLY_INT_A_R3            = (1 << 31),
++      DLY_INT_A_R2            = (1 << 30),
++      DLY_INT_A_R1            = (1 << 29),
++      DLY_INT_A_R0            = (1 << 28),
++      DLY_INT_A_T3            = (1 << 27),
++      DLY_INT_A_T2            = (1 << 26),
++      DLY_INT_A_T1            = (1 << 25),
++      DLY_INT_A_T0            = ( 1 << 24),
++      EVENT_COUNT_A           = (0xF << 16) | (0x1 << 20),/* 20:16 */
++      MAX_DELAY_TIME_A        = (0xF << 0) | (0xF << 4) | (1 << 8)|
++                                (1 << 9) | (1 << 10), /* 10:0 */
++
++}DLY_INT_A_BITS;
++
++typedef enum {
++
++      DLY_INT_B_R3            = (1 << 31),
++      DLY_INT_B_R2            = (1 << 30),
++      DLY_INT_B_R1            = (1 << 29),
++      DLY_INT_B_R0            = (1 << 28),
++      DLY_INT_B_T3            = (1 << 27),
++      DLY_INT_B_T2            = (1 << 26),
++      DLY_INT_B_T1            = (1 << 25),
++      DLY_INT_B_T0            = ( 1 << 24),
++      EVENT_COUNT_B           = (0xF << 16) | (0x1 << 20),/* 20:16 */
++      MAX_DELAY_TIME_B        = (0xF << 0) | (0xF << 4) | (1 << 8)| 
++                                (1 << 9) | (1 << 10), /* 10:0 */
++}DLY_INT_B_BITS;
++
++
++/* FLOW_CONTROL               0xC8, 32bit register */
++typedef enum {
++
++      PAUSE_LEN_CHG           = (1 << 30),
++      FTPE                    = (1 << 22),
++      FRPE                    = (1 << 21),
++      NAPA                    = (1 << 20),
++      NPA                     = (1 << 19),
++      FIXP                    = ( 1 << 18),
++      FCCMD                   = ( 1 << 16),
++      PAUSE_LEN               = (0xF << 0) | (0xF << 4) |( 0xF << 8) |                                          (0xF << 12),  /* 15:0 */
++
++}FLOW_CONTROL_BITS;
++
++/* PHY_ ACCESS                        0xD0, 32bit register */
++typedef enum {
++
++      PHY_CMD_ACTIVE          = (1 << 31),
++      PHY_WR_CMD              = (1 << 30),
++      PHY_RD_CMD              = (1 << 29),
++      PHY_RD_ERR              = (1 << 28),
++      PHY_PRE_SUP             = (1 << 27),
++      PHY_ADDR                = (1 << 21) | (1 << 22) | (1 << 23)|
++                                      (1 << 24) |(1 << 25),/* 25:21 */
++      PHY_REG_ADDR            = (1 << 16) | (1 << 17) | (1 << 18)|                                                    (1 << 19) | (1 << 20),/* 20:16 */
++      PHY_DATA                = (0xF << 0)|(0xF << 4) |(0xF << 8)|
++                                      (0xF << 12),/* 15:0 */
++
++}PHY_ACCESS_BITS;
++
++
++/* PMAT0                      0x190,   32bit register */
++typedef enum {
++      PMR_ACTIVE              = (1 << 31),
++      PMR_WR_CMD              = (1 << 30),
++      PMR_RD_CMD              = (1 << 29),
++      PMR_BANK                = (1 <<28),
++      PMR_ADDR                = (0xF << 16)|(1 << 20)|(1 << 21)|
++                                      (1 << 22),/* 22:16 */
++      PMR_B4                  = (0xF << 0) | (0xF << 4),/* 15:0 */
++}PMAT0_BITS;
++
++
++/* PMAT1                      0x194,   32bit register */
++typedef enum {
++      PMR_B3                  = (0xF << 24) | (0xF <<28),/* 31:24 */
++      PMR_B2                  = (0xF << 16) |(0xF << 20),/* 23:16 */
++      PMR_B1                  = (0xF << 8) | (0xF <<12), /* 15:8 */
++      PMR_B0                  = (0xF << 0)|(0xF << 4),/* 7:0 */
++}PMAT1_BITS;
++
++/************************************************************************/
++/*                                                                      */
++/*                      MIB counter definitions                         */
++/*                                                                      */
++/************************************************************************/
++
++#define rcv_miss_pkts                         0x00
++#define rcv_octets                            0x01
++#define rcv_broadcast_pkts                    0x02
++#define rcv_multicast_pkts                    0x03
++#define rcv_undersize_pkts                    0x04
++#define rcv_oversize_pkts                     0x05
++#define rcv_fragments                         0x06
++#define rcv_jabbers                           0x07
++#define rcv_unicast_pkts                      0x08
++#define rcv_alignment_errors                  0x09
++#define rcv_fcs_errors                                0x0A
++#define rcv_good_octets                               0x0B
++#define rcv_mac_ctrl                          0x0C
++#define rcv_flow_ctrl                         0x0D
++#define rcv_pkts_64_octets                    0x0E
++#define rcv_pkts_65to127_octets                       0x0F
++#define rcv_pkts_128to255_octets              0x10
++#define rcv_pkts_256to511_octets              0x11
++#define rcv_pkts_512to1023_octets             0x12
++#define rcv_pkts_1024to1518_octets            0x13
++#define rcv_unsupported_opcode                        0x14
++#define rcv_symbol_errors                     0x15
++#define rcv_drop_pkts_ring1                   0x16
++#define rcv_drop_pkts_ring2                   0x17
++#define rcv_drop_pkts_ring3                   0x18
++#define rcv_drop_pkts_ring4                   0x19
++#define rcv_jumbo_pkts                                0x1A
++
++#define xmt_underrun_pkts                     0x20
++#define xmt_octets                            0x21
++#define xmt_packets                           0x22
++#define xmt_broadcast_pkts                    0x23
++#define xmt_multicast_pkts                    0x24
++#define xmt_collisions                                0x25
++#define xmt_unicast_pkts                      0x26
++#define xmt_one_collision                     0x27
++#define xmt_multiple_collision                        0x28
++#define xmt_deferred_transmit                 0x29
++#define xmt_late_collision                    0x2A
++#define xmt_excessive_defer                   0x2B
++#define xmt_loss_carrier                      0x2C
++#define xmt_excessive_collision                       0x2D
++#define xmt_back_pressure                     0x2E
++#define xmt_flow_ctrl                         0x2F
++#define xmt_pkts_64_octets                    0x30
++#define xmt_pkts_65to127_octets                       0x31
++#define xmt_pkts_128to255_octets              0x32
++#define xmt_pkts_256to511_octets              0x33
++#define xmt_pkts_512to1023_octets             0x34
++#define xmt_pkts_1024to1518_octet             0x35
++#define xmt_oversize_pkts                     0x36
++#define xmt_jumbo_pkts                                0x37
++
++/* ipg parameters */
++#define DEFAULT_IPG                   0x60
++#define IFS1_DELTA                    36
++#define       IPG_CONVERGE_JIFFIES (HZ/2)
++#define       IPG_STABLE_TIME 5
++#define       MIN_IPG 96
++#define       MAX_IPG 255
++#define IPG_STEP      16
++#define CSTATE  1 
++#define SSTATE  2 
++
++/* amd8111e decriptor flag definitions */
++typedef enum {
++
++      OWN_BIT         =       (1 << 15),
++      ADD_FCS_BIT     =       (1 << 13),
++      LTINT_BIT       =       (1 << 12),
++      STP_BIT         =       (1 << 9),
++      ENP_BIT         =       (1 << 8),
++      KILL_BIT        =       (1 << 6),
++      TCC_VLAN_INSERT =       (1 << 1),
++      TCC_VLAN_REPLACE =      (1 << 1) |( 1<< 0),
++
++}TX_FLAG_BITS;
++
++typedef enum {
++      ERR_BIT         =       (1 << 14),
++      FRAM_BIT        =       (1 << 13),
++      OFLO_BIT        =       (1 << 12),
++      CRC_BIT         =       (1 << 11),
++      PAM_BIT         =       (1 << 6),
++      LAFM_BIT        =       (1 << 5),
++      BAM_BIT         =       (1 << 4),
++      TT_VLAN_TAGGED  =       (1 << 3) |(1 << 2),/* 0x000 */
++      TT_PRTY_TAGGED  =       (1 << 3),/* 0x0008 */
++
++}RX_FLAG_BITS;
++
++#define RESET_RX_FLAGS                0x0000
++#define TT_MASK                       0x000c
++#define TCC_MASK              0x0003
++
++/* driver ioctl parameters */
++#define AMD8111E_REG_DUMP_LEN  13*sizeof(u32) 
++
++/* crc generator constants */
++#define CRC32 0xedb88320
++#define INITCRC 0xFFFFFFFF
++
++/* kernel provided writeq does not write 64 bits into the amd8111e device register instead writes only higher 32bits data into lower 32bits of the register.
++BUG? */
++#define  amd8111e_writeq(_UlData,_memMap)   \
++              writel(*(u32*)(&_UlData), _memMap);     \
++              writel(*(u32*)((u8*)(&_UlData)+4), _memMap+4)   
++
++/* maps the external speed options to internal value */
++typedef enum {
++      SPEED_AUTONEG,
++      SPEED10_HALF,
++      SPEED10_FULL,
++      SPEED100_HALF,
++      SPEED100_FULL,
++}EXT_PHY_OPTION;
++
++
++#endif /* _AMD8111E_H */
++
diff --combined src/proto/fsp.c
index 0000000,0000000..6aba937
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,245 @@@
++    /*********************************************************************\
++    * Copyright (c) 2005 by Radim Kolar (hsn-sendmail.cz)                 *
++    *                                                                     *
++    * You may copy or modify this file in any manner you wish, provided   *
++    * that this notice is always included, and that you hold the author   *
++    * harmless for any loss or damage resulting from the installation or  *
++    * use of this software.                                               *
++    *                                                                     *
++    * This file provides support for FSP v2 protocol written from scratch *
++    * by Radim Kolar,   FSP project leader.                               *
++    *                                                                     *
++    * ABOUT FSP                                                           *
++    * FSP is a lightweight file transfer protocol and is being used for   *
++    * booting, Internet firmware updates, embedded devices and in         *
++    * wireless applications. FSP is very easy to implement; contact Radim *
++    * Kolar if you need hand optimized assembler FSP stacks for various   *
++    * microcontrollers, CPUs or consultations.                            *
++    * http://fsp.sourceforge.net/                                         *
++    *                                                                     *
++    * REVISION HISTORY                                                    *
++    * 1.0 2005-03-17 rkolar   Initial coding                              *
++    * 1.1 2005-03-24 rkolar   We really need to send CC_BYE to the server *
++    *                         at end of transfer, because next stage boot *
++    *                         loader is unable to contact FSP server      *
++    *                         until session timeouts.                     *
++    * 1.2 2005-03-26 rkolar   We need to query filesize in advance,       *
++    *                         because NBI loader do not reads file until  *
++    *                         eof is reached.
++    * REMARKS                                                             *
++    * there is no support for selecting port number of fsp server, maybe  *
++    *   we should parse fsp:// URLs in boot image filename.               *
++    * this implementation has filename limit 255 chars.                   *
++    \*********************************************************************/
++
++#ifdef DOWNLOAD_PROTO_FSP
++#include "etherboot.h"
++#include "nic.h"
++
++#define FSP_PORT 21
++
++/* FSP commands */
++#define CC_GET_FILE   0x42
++#define CC_BYE                0x4A
++#define CC_ERR                0x40
++#define CC_STAT               0x4D
++
++/* etherboot limits */
++#define FSP_MAXFILENAME 255
++
++struct fsp_info {
++      in_addr server_ip;
++      uint16_t server_port;
++      uint16_t local_port;
++      const char *filename;
++      int (*fnc)(unsigned char *, unsigned int, unsigned int, int);
++};
++
++struct fsp_header {
++      uint8_t cmd;
++      uint8_t sum;
++      uint16_t key;
++      uint16_t seq;
++      uint16_t len;
++      uint32_t pos;
++} PACKED;
++
++#define FSP_MAXPAYLOAD (ETH_MAX_MTU - \
++  (sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(struct fsp_header)))
++
++static struct fsp_request {
++      struct iphdr ip;
++      struct udphdr udp;
++      struct fsp_header fsp;
++      unsigned char data[FSP_MAXFILENAME + 1 + 2];
++} request;
++
++struct fsp_reply {
++      struct iphdr ip;
++      struct udphdr udp;
++      struct fsp_header fsp;
++      unsigned char data[FSP_MAXPAYLOAD];
++} PACKED;
++
++
++static int await_fsp(int ival, void *ptr, unsigned short ptype __unused,
++                      struct iphdr *ip, struct udphdr *udp)
++{
++      if(!udp)
++          return 0;
++      if (ip->dest.s_addr != arptable[ARP_CLIENT].ipaddr.s_addr) 
++          return 0;
++        if (ntohs(udp->dest) != ival)
++            return 0;
++      if (ntohs(udp->len) < 12+sizeof(struct udphdr))
++          return 0;
++      return 1;
++}
++
++static int proto_fsp(struct fsp_info *info)
++{
++    uint32_t filepos;
++    uint32_t filelength=0;
++    int i,retry;
++    uint16_t reqlen;
++    struct fsp_reply *reply;
++    int block=1;
++    
++    /* prepare FSP request packet */
++    filepos=0;
++    i=strlen(info->filename);
++    if(i>FSP_MAXFILENAME)
++    {
++      printf("Boot filename is too long.\n");
++      return 0;
++    }
++    strcpy(request.data,info->filename);
++    *(uint16_t *)(request.data+i+1)=htons(FSP_MAXPAYLOAD);
++    request.fsp.len=htons(i+1);
++    reqlen=i+3+12;
++
++    rx_qdrain();
++    retry=0;
++
++    /* main loop */
++    for(;;) {
++      int  sum;
++      long timeout;
++
++        /* query filelength if not known */
++      if(filelength == 0)
++          request.fsp.cmd=CC_STAT;
++              
++      /* prepare request packet */
++      request.fsp.pos=htonl(filepos);
++      request.fsp.seq=random();
++      request.fsp.sum=0;
++      for(i=0,sum=reqlen;i<reqlen;i++)
++      {
++          sum += ((uint8_t *)&request.fsp)[i];
++        }
++      request.fsp.sum= sum + (sum >> 8);
++      /* send request */
++        if (!udp_transmit(info->server_ip.s_addr, info->local_port,
++                       info->server_port, sizeof(request.ip) +
++                       sizeof(request.udp) + reqlen, &request))
++                          return (0);
++      /* wait for retry */                
++#ifdef  CONGESTED
++        timeout =
++            rfc2131_sleep_interval(filepos ? TFTP_REXMT : TIMEOUT, retry);
++#else
++      timeout = rfc2131_sleep_interval(TIMEOUT, retry);
++#endif
++      retry++;
++        if (!await_reply(await_fsp, info->local_port, NULL, timeout))
++          continue;
++      reply=(struct fsp_reply *) &nic.packet[ETH_HLEN];    
++      /* check received packet */
++      if (reply->fsp.seq != request.fsp.seq)
++          continue;
++      reply->udp.len=ntohs(reply->udp.len)-sizeof(struct udphdr);
++      if(reply->udp.len < ntohs(reply->fsp.len) + 12 )
++          continue;
++        sum=-reply->fsp.sum;
++      for(i=0;i<reply->udp.len;i++)
++      {
++          sum += ((uint8_t *)&(reply->fsp))[i];
++        }
++        sum = (sum + (sum >> 8)) & 0xff;
++      if(sum != reply->fsp.sum)
++      {
++          printf("FSP checksum failed. computed %d, but packet has %d.\n",sum,reply->fsp.sum);
++          continue;
++      }
++      if(reply->fsp.cmd == CC_ERR)
++      {
++          printf("\nFSP error: %s",info->filename);
++          if(reply->fsp.len)
++              printf(" [%s]",reply->data);
++          printf("\n");
++          return 0;
++      }
++      if(reply->fsp.cmd == CC_BYE && filelength == 1)
++      {
++          info->fnc(request.data,block,1,1);
++          return 1;
++      }
++      if(reply->fsp.cmd == CC_STAT)
++      {
++          if(reply->data[8] == 0)
++          {
++              /* file not found, etc. */
++              filelength=0xffffffff;
++          } else
++          {
++              filelength= ntohl(*((uint32_t *)&reply->data[4]));
++          }
++          request.fsp.cmd = CC_GET_FILE;
++          request.fsp.key = reply->fsp.key;
++          retry=0;
++          continue;
++      }
++
++      if(reply->fsp.cmd == CC_GET_FILE)
++      {
++          if(ntohl(reply->fsp.pos) != filepos)
++              continue;
++          request.fsp.key = reply->fsp.key;
++          retry=0;
++          i=ntohs(reply->fsp.len);
++          if(i == 1)
++          {
++              request.fsp.cmd=CC_BYE;
++              request.data[0]=reply->data[0];
++              continue;
++          }
++          /* let last byte alone */
++            if(i >= filelength)
++              i = filelength - 1;
++          if(!info->fnc(reply->data,block++,i,0))
++              return 0;
++          filepos += i;
++          filelength -= i;
++      }
++    }
++
++    return 0;
++}
++
++int url_fsp(const char *name, int (*fnc)(unsigned char *, unsigned int, unsigned int, int))
++{
++      struct fsp_info info;
++      /* Set the defaults */
++      info.server_ip.s_addr    = arptable[ARP_SERVER].ipaddr.s_addr;
++      info.server_port         = FSP_PORT;
++      info.local_port          = 1024 + random() & 0xfbff;
++      info.fnc                 = fnc;
++      
++      /* Now parse the url */
++      /* printf("fsp-URI: [%s]\n", name); */
++        /* quick hack for now */
++      info.filename=name;
++      return proto_fsp(&info);
++}
++#endif