summaryrefslogtreecommitdiff
path: root/gpxe/src/drivers/net/eepro100.c
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2016-02-09 18:08:47 -0800
committerH. Peter Anvin <hpa@zytor.com>2016-02-09 18:08:47 -0800
commitf2f897a1762fab84d2905f32b1c15dd7b42abb56 (patch)
treea38f51d3f1fcbf44afddb4736d549c12eaf491be /gpxe/src/drivers/net/eepro100.c
parent72d2959272b4616f17a97667e6dfa9d06bf109a3 (diff)
downloadsyslinux-f2f897a1762fab84d2905f32b1c15dd7b42abb56.tar.gz
gpxe: delete long since obsolete snapshot of gPXE
gPXE has been deprecated in favor of iPXE for many, many years now. It is much better than users get it directly from the iPXE project, since we should no longer need any special modifications for Syslinux use. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'gpxe/src/drivers/net/eepro100.c')
-rw-r--r--gpxe/src/drivers/net/eepro100.c1207
1 files changed, 0 insertions, 1207 deletions
diff --git a/gpxe/src/drivers/net/eepro100.c b/gpxe/src/drivers/net/eepro100.c
deleted file mode 100644
index 8a75608c..00000000
--- a/gpxe/src/drivers/net/eepro100.c
+++ /dev/null
@@ -1,1207 +0,0 @@
-/*
- * eepro100.c -- This is a driver for Intel Fast Ethernet Controllers
- * (ifec).
- *
- * Originally written for Etherboot by:
- *
- * Copyright (C) AW Computer Systems.
- * written by R.E.Wolff -- R.E.Wolff@BitWizard.nl
- *
- * AW Computer Systems is contributing to the free software community
- * by paying for this driver and then putting the result under GPL.
- *
- * If you need a Linux device driver, please contact BitWizard for a
- * quote.
- *
- * 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, 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.
- *
- *
- * date version by what
- * Written: May 29 1997 V0.10 REW Initial revision.
- * changes: May 31 1997 V0.90 REW Works!
- * Jun 1 1997 V0.91 REW Cleanup
- * Jun 2 1997 V0.92 REW Add some code documentation
- * Jul 25 1997 V1.00 REW Tested by AW to work in a PROM
- * Cleanup for publication
- * Dez 11 2004 V1.10 Kiszka Add RX ring buffer support
- * Jun 2008 v2.0 mdeck Updated to gPXE. Changed much.
- *
- * Cleanups and fixes by Thomas Miletich<thomas.miletich@gmail.com>
- *
- * This is the etherboot intel etherexpress Pro/100B driver.
- *
- * It was written from scratch, with Donald Beckers eepro100.c kernel
- * driver as a guideline. Mostly the 82557 related definitions and the
- * lower level routines have been cut-and-pasted into this source.
- *
- * The driver was finished before Intel got the NDA out of the closet.
- *
- * Datasheet is now published and available from
- * ftp://download.intel.com/design/network/manuals/8255X_OpenSDM.pdf
- * - Michael Brown
- * */
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-/*
- * General Theory of Operation
- *
- * Initialization
- *
- * ifec_pci_probe() is called by gPXE during initialization. Typical NIC
- * initialization is performed. EEPROM data is read.
- *
- * Network Boot
- *
- * ifec_net_open() is called by gPXE before attempting to network boot from the
- * card. Here, the Command Unit & Receive Unit are initialized. The tx & rx
- * rings are setup. The MAC address is programmed and the card is configured.
- *
- * Transmit
- *
- * ifec_net_transmit() enqueues a packet in the tx ring - active::tcbs[] The tx
- * ring is composed of TCBs linked to each other into a ring. A tx request
- * fills out the next available TCB with a pointer to the packet data.
- * The last enqueued tx is always at active::tcb_head. Thus, a tx request fills
- * out the TCB following tcb_head.
- * active::tcb_tail points to the TCB we're awaiting completion of.
- * ifec_tx_process() checks tcb_tail, and once complete,
- * blindly increments tcb_tail to the next ring TCB.
- *
- * Receive
- *
- * priv::rfds[] is an array of Receive Frame Descriptors. The RFDs are linked
- * together to form a ring.
- * ifec_net_poll() calls ifec_rx_process(), which checks the next RFD for
- * data. If we received a packet, we allocate a new io_buffer and copy the
- * packet data into it. If alloc_iob() fails, we don't touch the RFD and try
- * again on the next poll.
- */
-
-/*
- * Debugging levels:
- * - DBG() is for any errors, i.e. failed alloc_iob(), malloc_dma(),
- * TX overflow, corrupted packets, ...
- * - DBG2() is for successful events, like packet received,
- * packet transmitted, and other general notifications.
- * - DBGP() prints the name of each called function on entry
- */
-
-#include <stdint.h>
-#include <byteswap.h>
-#include <errno.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <gpxe/ethernet.h>
-#include <gpxe/if_ether.h>
-#include <gpxe/iobuf.h>
-#include <gpxe/malloc.h>
-#include <gpxe/pci.h>
-#include <gpxe/spi_bit.h>
-#include <gpxe/timer.h>
-#include <gpxe/nvs.h>
-#include <gpxe/threewire.h>
-#include <gpxe/netdevice.h>
-#include "eepro100.h"
-
-/****************************** Global data **********************************/
-
-/*
- * This is the default configuration command data. The values were copied from
- * the Linux kernel initialization for the eepro100.
- */
-static struct ifec_cfg ifec_cfg = {
- .status = 0,
- .command = CmdConfigure | CmdSuspend,
- .link = 0, /* Filled in later */
- .byte = { 22, /* How many bytes in this array */
- ( TX_FIFO << 4 ) | RX_FIFO, /* Rx & Tx FIFO limits */
- 0, 0, /* Adaptive Interframe Spacing */
- RX_DMA_COUNT, /* Rx DMA max byte count */
- TX_DMA_COUNT + 0x80, /* Tx DMA max byte count */
- 0x32, /* Many bits. */
- 0x03, /* Discard short receive & Underrun retries */
- 1, /* 1=Use MII 0=Use AUI */
- 0,
- 0x2E, /* NSAI, Preamble length, & Loopback*/
- 0, /* Linear priority */
- 0x60, /* L PRI MODE & Interframe spacing */
- 0, 0xf2,
- 0x48, /* Promiscuous, Broadcast disable, CRS & CDT */
- 0, 0x40,
- 0xf2, /* Stripping, Padding, Receive CRC Transfer */
- 0x80, /* 0x40=Force full-duplex, 0x80=Allowfull-duplex*/
- 0x3f, /* Multiple IA */
- 0x0D } /* Multicast all */
-};
-
-static struct net_device_operations ifec_operations = {
- .open = ifec_net_open,
- .close = ifec_net_close,
- .transmit = ifec_net_transmit,
- .poll = ifec_net_poll,
- .irq = ifec_net_irq
-};
-
-/******************* gPXE PCI Device Driver API functions ********************/
-
-/*
- * Initialize the PCI device.
- *
- * @v pci The device's associated pci_device structure.
- * @v id The PCI device + vendor id.
- * @ret rc Returns zero if successfully initialized.
- *
- * This function is called very early on, while gPXE is initializing.
- * This is a gPXE PCI Device Driver API function.
- */
-static int ifec_pci_probe ( struct pci_device *pci,
- const struct pci_device_id *id __unused )
-{
- struct net_device *netdev;
- struct ifec_private *priv;
- int rc;
-
- DBGP ( "ifec_pci_probe: " );
-
- if ( pci->ioaddr == 0 )
- return -EINVAL;
-
- netdev = alloc_etherdev ( sizeof(*priv) );
- if ( !netdev )
- return -ENOMEM;
-
- netdev_init ( netdev, &ifec_operations );
- priv = netdev->priv;
-
- pci_set_drvdata ( pci, netdev );
- netdev->dev = &pci->dev;
-
- /* enable bus master, etc */
- adjust_pci_device( pci );
-
- DBGP ( "pci " );
-
- memset ( priv, 0, sizeof(*priv) );
- priv->ioaddr = pci->ioaddr;
-
- ifec_reset ( netdev );
- DBGP ( "reset " );
-
- ifec_init_eeprom ( netdev );
-
- /* read MAC address */
- nvs_read ( &priv->eeprom.nvs, EEPROM_ADDR_MAC_0, netdev->hw_addr,
- ETH_ALEN );
- /* read mdio_register */
- nvs_read ( &priv->eeprom.nvs, EEPROM_ADDR_MDIO_REGISTER,
- &priv->mdio_register, 2 );
-
- ifec_link_update ( netdev ); /* Update link state */
-
- if ( ( rc = register_netdev ( netdev ) ) != 0 )
- goto error;
-
- DBGP ( "ints\n" );
-
- return 0;
-
-error:
- ifec_reset ( netdev );
- netdev_nullify ( netdev );
- netdev_put ( netdev );
-
- return rc;
-}
-
-/*
- * Remove a device from the PCI device list.
- *
- * @v pci PCI device to remove.
- *
- * This is a PCI Device Driver API function.
- */
-static void ifec_pci_remove ( struct pci_device *pci )
-{
- struct net_device *netdev = pci_get_drvdata ( pci );
-
- DBGP ( "ifec_pci_remove\n" );
-
- unregister_netdev ( netdev );
- ifec_reset ( netdev );
- netdev_nullify ( netdev );
- netdev_put ( netdev );
-}
-
-/****************** gPXE Network Device Driver API functions *****************/
-
-/*
- * Close a network device.
- *
- * @v netdev Device to close.
- *
- * This is a gPXE Network Device Driver API function.
- */
-static void ifec_net_close ( struct net_device *netdev )
-{
- struct ifec_private *priv = netdev->priv;
- unsigned long ioaddr = priv->ioaddr;
- unsigned short intr_status;
-
- DBGP ( "ifec_net_close\n" );
-
- /* disable interrupts */
- ifec_net_irq ( netdev, 0 );
-
- /* Ack & clear ints */
- intr_status = inw ( ioaddr + SCBStatus );
- outw ( intr_status, ioaddr + SCBStatus );
- inw ( ioaddr + SCBStatus );
-
- ifec_reset ( netdev );
-
- /* Free any resources */
- ifec_free ( netdev );
-}
-
-/* Interrupts to be masked */
-#define INTERRUPT_MASK ( SCBMaskEarlyRx | SCBMaskFlowCtl )
-
-/*
- * Enable or disable IRQ masking.
- *
- * @v netdev Device to control.
- * @v enable Zero to mask off IRQ, non-zero to enable IRQ.
- *
- * This is a gPXE Network Driver API function.
- */
-static void ifec_net_irq ( struct net_device *netdev, int enable )
-{
- struct ifec_private *priv = netdev->priv;
- unsigned long ioaddr = priv->ioaddr;
-
- DBGP ( "ifec_net_irq\n" );
-
- outw ( enable ? INTERRUPT_MASK : SCBMaskAll, ioaddr + SCBCmd );
-}
-
-/*
- * Opens a network device.
- *
- * @v netdev Device to be opened.
- * @ret rc Non-zero if failed to open.
- *
- * This enables tx and rx on the device.
- * This is a gPXE Network Device Driver API function.
- */
-static int ifec_net_open ( struct net_device *netdev )
-{
- struct ifec_private *priv = netdev->priv;
- struct ifec_ias *ias = NULL;
- struct ifec_cfg *cfg = NULL;
- int i, options;
- int rc = -ENOMEM;
-
- DBGP ( "ifec_net_open: " );
-
- /* Ensure interrupts are disabled. */
- ifec_net_irq ( netdev, 0 );
-
- /* Initialize Command Unit and Receive Unit base addresses. */
- ifec_scb_cmd ( netdev, 0, RUAddrLoad );
- ifec_scb_cmd ( netdev, virt_to_bus ( &priv->stats ), CUStatsAddr );
- ifec_scb_cmd ( netdev, 0, CUCmdBase );
-
- /* Initialize both rings */
- if ( ( rc = ifec_rx_setup ( netdev ) ) != 0 )
- goto error;
- if ( ( rc = ifec_tx_setup ( netdev ) ) != 0 )
- goto error;
-
- /* Initialize MDIO */
- options = 0x00; /* 0x40 = 10mbps half duplex, 0x00 = Autosense */
- ifec_mdio_setup ( netdev, options );
-
- /* Prepare MAC address w/ Individual Address Setup (ias) command.*/
- ias = malloc_dma ( sizeof ( *ias ), CB_ALIGN );
- if ( !ias ) {
- rc = -ENOMEM;
- goto error;
- }
- ias->command = CmdIASetup;
- ias->status = 0;
- memcpy ( ias->ia, netdev->ll_addr, ETH_ALEN );
-
- /* Prepare operating parameters w/ a configure command. */
- cfg = malloc_dma ( sizeof ( *cfg ), CB_ALIGN );
- if ( !cfg ) {
- rc = -ENOMEM;
- goto error;
- }
- memcpy ( cfg, &ifec_cfg, sizeof ( *cfg ) );
- cfg->link = virt_to_bus ( priv->tcbs );
- cfg->byte[19] = ( options & 0x10 ) ? 0xC0 : 0x80;
- ias->link = virt_to_bus ( cfg );
-
- /* Issue the ias and configure commands. */
- ifec_scb_cmd ( netdev, virt_to_bus ( ias ), CUStart );
- ifec_scb_cmd_wait ( netdev );
- priv->configured = 1;
-
- /* Wait up to 10 ms for configuration to initiate */
- for ( i = 10; i && !cfg->status; i-- )
- mdelay ( 1 );
- if ( ! cfg->status ) {
- DBG ( "Failed to initiate!\n" );
- goto error;
- }
- free_dma ( ias, sizeof ( *ias ) );
- free_dma ( cfg, sizeof ( *cfg ) );
- DBG2 ( "cfg " );
-
- /* Enable rx by sending ring address to card */
- if ( priv->rfds[0] != NULL ) {
- ifec_scb_cmd ( netdev, virt_to_bus( priv->rfds[0] ), RUStart );
- ifec_scb_cmd_wait ( netdev );
- }
- DBG2 ( "rx_start\n" );
-
- return 0;
-
-error:
- free_dma ( cfg, sizeof ( *cfg ) );
- free_dma ( ias, sizeof ( *ias ) );
- ifec_free ( netdev );
- ifec_reset ( netdev );
- return rc;
-}
-
-/*
- * This function allows a driver to process events during operation.
- *
- * @v netdev Device being polled.
- *
- * This is called periodically by gPXE to let the driver check the status of
- * transmitted packets and to allow the driver to check for received packets.
- * This is a gPXE Network Device Driver API function.
- */
-static void ifec_net_poll ( struct net_device *netdev )
-{
- struct ifec_private *priv = netdev->priv;
- static int linkpoll = 0;
- unsigned short intr_status;
-
- DBGP ( "ifec_net_poll\n" );
-
- /* acknowledge interrupts ASAP */
- intr_status = inw ( priv->ioaddr + SCBStatus );
- outw ( intr_status, priv->ioaddr + SCBStatus );
- inw ( priv->ioaddr + SCBStatus );
-
- DBG2 ( "poll - status: 0x%04X\n", intr_status );
-
- if ( ++linkpoll > LINK_CHECK_PERIOD ) {
- linkpoll = 0;
- ifec_link_update ( netdev ); /* Update link state */
- }
-
- /* anything to do here? */
- if ( ( intr_status & ( ~INTERRUPT_MASK ) ) == 0 )
- return;
-
- /* process received and transmitted packets */
- ifec_tx_process ( netdev );
- ifec_rx_process ( netdev );
-
- ifec_check_ru_status ( netdev, intr_status );
-
- return;
-}
-
-/*
- * This transmits a packet.
- *
- * @v netdev Device to transmit from.
- * @v iobuf Data to transmit.
- * @ret rc Non-zero if failed to transmit.
- *
- * This is a gPXE Network Driver API function.
- */
-static int ifec_net_transmit ( struct net_device *netdev,
- struct io_buffer *iobuf )
-{
- struct ifec_private *priv = netdev->priv;
- struct ifec_tcb *tcb = priv->tcb_head->next;
- unsigned long ioaddr = priv->ioaddr;
-
- DBGP ( "ifec_net_transmit\n" );
-
- /* Wait for TCB to become available. */
- if ( tcb->status || tcb->iob ) {
- DBG ( "TX overflow\n" );
- return -ENOBUFS;
- }
-
- DBG2 ( "transmitting packet (%d bytes). status = %hX, cmd=%hX\n",
- iob_len ( iobuf ), tcb->status, inw ( ioaddr + SCBCmd ) );
-
- tcb->command = CmdSuspend | CmdTx | CmdTxFlex;
- tcb->count = 0x01208000;
- tcb->tbd_addr0 = virt_to_bus ( iobuf->data );
- tcb->tbd_size0 = 0x3FFF & iob_len ( iobuf );
- tcb->iob = iobuf;
-
- ifec_tx_wake ( netdev );
-
- /* Append to end of ring. */
- priv->tcb_head = tcb;
-
- return 0;
-}
-
-/*************************** Local support functions *************************/
-
-/* Define what each GPIO Pin does */
-static const uint16_t ifec_ee_bits[] = {
- [SPI_BIT_SCLK] = EE_SHIFT_CLK,
- [SPI_BIT_MOSI] = EE_DATA_WRITE,
- [SPI_BIT_MISO] = EE_DATA_READ,
- [SPI_BIT_SS(0)] = EE_ENB,
-};
-
-/*
- * Read a single bit from the GPIO pins used for SPI.
- * should be called by SPI bitbash functions only
- *
- * @v basher Bitbash device
- * @v bit_id Line to be read
- */
-static int ifec_spi_read_bit ( struct bit_basher *basher,
- unsigned int bit_id )
-{
- struct ifec_private *priv =
- container_of ( basher, struct ifec_private, spi.basher );
- unsigned long ee_addr = priv->ioaddr + CSREeprom;
- unsigned int ret = 0;
- uint16_t mask;
-
- DBGP ( "ifec_spi_read_bit\n" );
-
- mask = ifec_ee_bits[bit_id];
- ret = inw (ee_addr);
-
- return ( ret & mask ) ? 1 : 0;
-}
-
-/*
- * Write a single bit to the GPIO pins used for SPI.
- * should be called by SPI bitbash functions only
- *
- * @v basher Bitbash device
- * @v bit_id Line to write to
- * @v data Value to write
- */
-static void ifec_spi_write_bit ( struct bit_basher *basher,
- unsigned int bit_id,
- unsigned long data )
-{
- struct ifec_private *priv =
- container_of ( basher, struct ifec_private, spi.basher );
- unsigned long ee_addr = priv->ioaddr + CSREeprom;
- short val;
- uint16_t mask = ifec_ee_bits[bit_id];
-
- DBGP ( "ifec_spi_write_bit\n" );
-
- val = inw ( ee_addr );
- val &= ~mask;
- val |= data & mask;
-
- outw ( val, ee_addr );
-}
-
-/* set function pointer to SPI read- and write-bit functions */
-static struct bit_basher_operations ifec_basher_ops = {
- .read = ifec_spi_read_bit,
- .write = ifec_spi_write_bit,
-};
-
-/*
- * Initialize the eeprom stuff
- *
- * @v netdev Network device
- */
-static void ifec_init_eeprom ( struct net_device *netdev )
-{
- struct ifec_private *priv = netdev->priv;
-
- DBGP ( "ifec_init_eeprom\n" );
-
- priv->spi.basher.op = &ifec_basher_ops;
- priv->spi.bus.mode = SPI_MODE_THREEWIRE;
- init_spi_bit_basher ( &priv->spi );
-
- priv->eeprom.bus = &priv->spi.bus;
-
- /* init as 93c46(93c14 compatible) first, to set the command len,
- * block size and word len. Needs to be set for address len detection.
- */
- init_at93c46 ( &priv->eeprom, 16 );
-
- /* detect address length, */
- threewire_detect_address_len ( &priv->eeprom );
-
- /* address len == 8 means 93c66 instead of 93c46 */
- if ( priv->eeprom.address_len == 8 )
- init_at93c66 ( &priv->eeprom, 16 );
-}
-
-/*
- * Check if the network cable is plugged in.
- *
- * @v netdev Network device to check.
- * @ret retval greater 0 if linkup.
- */
-static int ifec_link_check ( struct net_device *netdev )
-{
- struct ifec_private *priv = netdev->priv;
- unsigned short mdio_register = priv->mdio_register;
-
- DBGP ( "ifec_link_check\n" );
-
- /* Read the status register once to discard stale data */
- ifec_mdio_read ( netdev, mdio_register & 0x1f, 1 );
- /* Check to see if network cable is plugged in. */
- if ( ! ( ifec_mdio_read ( netdev, mdio_register & 0x1f, 1 )
- & ( 1 << 2 ) ) ) {
- return 0;
- }
- return 1;
-}
-
-/*
- * Check network cable link, inform gPXE as appropriate.
- *
- * @v netdev Network device to check.
- */
-static void ifec_link_update ( struct net_device *netdev )
-{
- DBGP ( "ifec_link_update\n" );
-
- /* Update link state */
- if ( ifec_link_check ( netdev ) )
- netdev_link_up ( netdev );
- else
- netdev_link_down ( netdev );
-}
-
-/*
- * Support function: ifec_mdio_read
- *
- * This probably reads a register in the "physical media interface chip".
- * -- REW
- */
-static int ifec_mdio_read ( struct net_device *netdev, int phy_id,
- int location )
-{
- struct ifec_private *priv = netdev->priv;
- unsigned long ioaddr = priv->ioaddr;
- int val;
- int boguscnt = 64*4; /* <64 usec. to complete, typ 27 ticks */
-
- DBGP ( "ifec_mdio_read\n" );
-
- outl ( 0x08000000 | ( location << 16 ) | ( phy_id << 21 ),
- ioaddr + CSRCtrlMDI );
- do {
- udelay ( 16 );
-
- val = inl ( ioaddr + CSRCtrlMDI );
-
- if ( --boguscnt < 0 ) {
- DBG ( " ifec_mdio_read() time out with val = %X.\n",
- val );
- break;
- }
- } while (! ( val & 0x10000000 ) );
- return val & 0xffff;
-}
-
-/*
- * Initializes MDIO.
- *
- * @v netdev Network device
- * @v options MDIO options
- */
-static void ifec_mdio_setup ( struct net_device *netdev, int options )
-{
- struct ifec_private *priv = netdev->priv;
- unsigned short mdio_register = priv->mdio_register;
-
- DBGP ( "ifec_mdio_setup\n" );
-
- if ( ( (mdio_register>>8) & 0x3f ) == DP83840
- || ( (mdio_register>>8) & 0x3f ) == DP83840A ) {
- int mdi_reg23 = ifec_mdio_read ( netdev, mdio_register
- & 0x1f, 23 ) | 0x0422;
- if (CONGENB)
- mdi_reg23 |= 0x0100;
- DBG2 ( "DP83840 specific setup, setting register 23 to "
- "%hX.\n", mdi_reg23 );
- ifec_mdio_write ( netdev, mdio_register & 0x1f, 23, mdi_reg23 );
- }
- DBG2 ( "dp83840 " );
- if ( options != 0 ) {
- ifec_mdio_write ( netdev, mdio_register & 0x1f, 0,
- ( (options & 0x20) ? 0x2000 : 0 ) |
- ( (options & 0x10) ? 0x0100 : 0 ) );
- DBG2 ( "set mdio_register. " );
- }
-}
-
-/*
- * Support function: ifec_mdio_write
- *
- * This probably writes to the "physical media interface chip".
- * -- REW
- */
-static int ifec_mdio_write ( struct net_device *netdev,
- int phy_id, int location, int value )
-{
- struct ifec_private *priv = netdev->priv;
- unsigned long ioaddr = priv->ioaddr;
- int val;
- int boguscnt = 64*4; /* <64 usec. to complete, typ 27 ticks */
-
- DBGP ( "ifec_mdio_write\n" );
-
- outl ( 0x04000000 | ( location << 16 ) | ( phy_id << 21 ) | value,
- ioaddr + CSRCtrlMDI );
- do {
- udelay ( 16 );
-
- val = inl ( ioaddr + CSRCtrlMDI );
- if ( --boguscnt < 0 ) {
- DBG ( " ifec_mdio_write() time out with val = %X.\n",
- val );
- break;
- }
- } while (! ( val & 0x10000000 ) );
- return val & 0xffff;
-}
-
-/*
- * Resets the hardware.
- *
- * @v netdev Network device
- */
-static void ifec_reset ( struct net_device *netdev )
-{
- struct ifec_private *priv = netdev->priv;
- unsigned long ioaddr = priv->ioaddr;
-
- DBGP ( "ifec_reset\n" );
-
- /* do partial reset first */
- outl ( PortPartialReset, ioaddr + CSRPort );
- inw ( ioaddr + SCBStatus );
- udelay ( 20 );
-
- /* full reset */
- outl ( PortReset, ioaddr + CSRPort );
- inw ( ioaddr + SCBStatus );
- udelay ( 20 );
-
- /* disable interrupts again */
- ifec_net_irq ( netdev, 0 );
-}
-
-/*
- * free()s the tx/rx rings.
- *
- * @v netdev Network device
- */
-static void ifec_free ( struct net_device *netdev )
-{
- struct ifec_private *priv = netdev_priv ( netdev );
- int i;
-
- DBGP ( "ifec_free\n" );
-
- /* free all allocated receive io_buffers */
- for ( i = 0; i < RFD_COUNT; i++ ) {
- free_iob ( priv->rx_iobs[i] );
- priv->rx_iobs[i] = NULL;
- priv->rfds[i] = NULL;
- }
-
- /* free TX ring buffer */
- free_dma ( priv->tcbs, TX_RING_BYTES );
-
- priv->tcbs = NULL;
-}
-
-/*
- * Initializes an RFD.
- *
- * @v rfd RFD struct to initialize
- * @v command Command word
- * @v link Link value
- */
-static void ifec_rfd_init ( struct ifec_rfd *rfd, s16 command, u32 link )
-{
- DBGP ( "ifec_rfd_init\n" );
-
- rfd->status = 0;
- rfd->command = command;
- rfd->rx_buf_addr = 0xFFFFFFFF;
- rfd->count = 0;
- rfd->size = RFD_PACKET_LEN;
- rfd->link = link;
-}
-
-/*
- * Send address of new RFD to card
- *
- * @v netdev Network device
- */
-static void ifec_reprime_ru ( struct net_device *netdev )
-{
- struct ifec_private *priv = netdev->priv;
- int cur_rx = priv->cur_rx;
-
- DBGP ( "ifec_reprime_ru\n" );
-
- if ( priv->rfds[cur_rx] != NULL ) {
- ifec_scb_cmd ( netdev, virt_to_bus ( priv->rfds[cur_rx] ),
- RUStart );
- ifec_scb_cmd_wait ( netdev );
- }
-}
-
-/*
- * Check if reprime of RU needed
- *
- * @v netdev Network device
- */
-static void ifec_check_ru_status ( struct net_device *netdev,
- unsigned short intr_status )
-{
- struct ifec_private *priv = netdev->priv;
-
- DBGP ( "ifec_check_ru_status\n" );
-
- /*
- * The chip may have suspended reception for various reasons.
- * Check for that, and re-prime it should this be the case.
- */
- switch ( ( intr_status >> 2 ) & 0xf ) {
- case 0: /* Idle */
- case 4: /* Ready */
- break;
- case 1: /* Suspended */
- case 2: /* No resources (RFDs) */
- case 9: /* Suspended with no more RBDs */
- case 10: /* No resources due to no RBDs */
- case 12: /* Ready with no RBDs */
- DBG ( "ifec_net_poll: RU reprimed.\n" );
- ifec_reprime_ru ( netdev );
- break;
- default:
- /* reserved values */
- DBG ( "ifec_net_poll: RU state anomaly: %i\n",
- ( inw ( priv->ioaddr + SCBStatus ) >> 2 ) & 0xf );
- break;
- }
-}
-
-#define RFD_STATUS ( RFD_OK | RFDRxCol | RFDRxErr | RFDShort | \
- RFDDMAOverrun | RFDNoBufs | RFDCRCError )
-/*
- * Looks for received packets in the rx ring, reports success or error to
- * the core accordingly. Starts reallocation of rx ring.
- *
- * @v netdev Network device
- */
-static void ifec_rx_process ( struct net_device *netdev )
-{
- struct ifec_private *priv = netdev->priv;
- int cur_rx = priv->cur_rx;
- struct io_buffer *iob = priv->rx_iobs[cur_rx];
- struct ifec_rfd *rfd = priv->rfds[cur_rx];
- unsigned int rx_len;
- s16 status;
-
- DBGP ( "ifec_rx_process\n" );
-
- /* Process any received packets */
- while ( iob && rfd && ( status = rfd->status ) ) {
- rx_len = rfd->count & RFDMaskCount;
-
- DBG2 ( "Got a packet: Len = %d, cur_rx = %d.\n", rx_len,
- cur_rx );
- DBGIO_HD ( (void*)rfd->packet, 0x30 );
-
- if ( ( status & RFD_STATUS ) != RFD_OK ) {
- DBG ( "Corrupted packet received. "
- "Status = %#08hx\n", status );
- netdev_rx_err ( netdev, iob, -EINVAL );
- } else {
- /* Hand off the packet to the network subsystem */
- iob_put ( iob, rx_len );
- DBG2 ( "Received packet: %p, len: %d\n", iob, rx_len );
- netdev_rx ( netdev, iob );
- }
-
- /* make sure we don't reuse this RFD */
- priv->rx_iobs[cur_rx] = NULL;
- priv->rfds[cur_rx] = NULL;
-
- /* Next RFD */
- priv->cur_rx = ( cur_rx + 1 ) % RFD_COUNT;
- cur_rx = priv->cur_rx;
- iob = priv->rx_iobs[cur_rx];
- rfd = priv->rfds[cur_rx];
- }
-
- ifec_refill_rx_ring ( netdev );
-}
-
-/*
- * Allocates io_buffer, set pointers in ifec_private structure accordingly,
- * reserves space for RFD header in io_buffer.
- *
- * @v netdev Network device
- * @v cur Descriptor number to work on
- * @v cmd Value to set cmd field in RFD to
- * @v link Pointer to ned RFD
- * @ret rc 0 on success, negative on failure
- */
-static int ifec_get_rx_desc ( struct net_device *netdev, int cur, int cmd,
- int link )
-{
- struct ifec_private *priv = netdev->priv;
- struct ifec_rfd *rfd = priv->rfds[cur];
-
- DBGP ( "ifec_get_rx_desc\n" );
-
- priv->rx_iobs[cur] = alloc_iob ( sizeof ( *rfd ) );
- if ( ! priv->rx_iobs[cur] ) {
- DBG ( "alloc_iob failed. desc. nr: %d\n", cur );
- priv->rfds[cur] = NULL;
- return -ENOMEM;
- }
-
- /* Initialize new tail. */
- priv->rfds[cur] = priv->rx_iobs[cur]->data;
- ifec_rfd_init ( priv->rfds[cur], cmd, link );
- iob_reserve ( priv->rx_iobs[cur], RFD_HEADER_LEN );
-
- return 0;
-}
-
-/*
- * Allocate new descriptor entries and initialize them if needed
- *
- * @v netdev Network device
- */
-static void ifec_refill_rx_ring ( struct net_device *netdev )
-{
- struct ifec_private *priv = netdev->priv;
- int i, cur_rx;
- unsigned short intr_status;
-
- DBGP ( "ifec_refill_rx_ring\n" );
-
- for ( i = 0; i < RFD_COUNT; i++ ) {
- cur_rx = ( priv->cur_rx + i ) % RFD_COUNT;
- /* only refill if empty */
- if ( priv->rfds[cur_rx] != NULL ||
- priv->rx_iobs[cur_rx] != NULL )
- continue;
-
- DBG2 ( "refilling RFD %d\n", cur_rx );
-
- if ( ifec_get_rx_desc ( netdev, cur_rx,
- CmdSuspend | CmdEndOfList, 0 ) == 0 ) {
- if ( i > 0 ) {
- int prev_rx = ( ( ( cur_rx + RFD_COUNT ) - 1 )
- % RFD_COUNT );
- struct ifec_rfd *rfd = priv->rfds[prev_rx];
-
- rfd->command = 0;
- rfd->link = virt_to_bus ( priv->rfds[cur_rx] );
- }
- }
- }
-
- intr_status = inw ( priv->ioaddr + SCBStatus );
- ifec_check_ru_status ( netdev, intr_status );
-}
-
-/*
- * Initial allocation & initialization of the rx ring.
- *
- * @v netdev Device of rx ring.
- * @ret rc Non-zero if error occured
- */
-static int ifec_rx_setup ( struct net_device *netdev )
-{
- struct ifec_private *priv = netdev->priv;
- int i;
-
- DBGP ( "ifec_rx_setup\n" );
-
- priv->cur_rx = 0;
-
- /* init values for ifec_refill_rx_ring() */
- for ( i = 0; i < RFD_COUNT; i++ ) {
- priv->rfds[i] = NULL;
- priv->rx_iobs[i] = NULL;
- }
- ifec_refill_rx_ring ( netdev );
-
- return 0;
-}
-
-/*
- * Initiates a SCB command.
- *
- * @v netdev Network device
- * @v ptr General pointer value for command.
- * @v cmd Command to issue.
- * @ret rc Non-zero if command not issued.
- */
-static int ifec_scb_cmd ( struct net_device *netdev, u32 ptr, u8 cmd )
-{
- struct ifec_private *priv = netdev->priv;
- unsigned long ioaddr = priv->ioaddr;
- int rc;
-
- DBGP ( "ifec_scb_cmd\n" );
-
- rc = ifec_scb_cmd_wait ( netdev ); /* Wait until ready */
- if ( !rc ) {
- outl ( ptr, ioaddr + SCBPointer );
- outb ( cmd, ioaddr + SCBCmd ); /* Issue command */
- }
- return rc;
-}
-
-/*
- * Wait for command unit to accept a command.
- *
- * @v cmd_ioaddr I/O address of command register.
- * @ret rc Non-zero if command timed out.
- */
-static int ifec_scb_cmd_wait ( struct net_device *netdev )
-{
- struct ifec_private *priv = netdev->priv;
- unsigned long cmd_ioaddr = priv->ioaddr + SCBCmd;
- int rc, wait = CU_CMD_TIMEOUT;
-
- DBGP ( "ifec_scb_cmd_wait\n" );
-
- for ( ; wait && ( rc = inb ( cmd_ioaddr ) ); wait-- )
- udelay ( 1 );
-
- if ( !wait )
- DBG ( "ifec_scb_cmd_wait timeout!\n" );
- return rc;
-}
-
-/*
- * Check status of transmitted packets & perform tx completions.
- *
- * @v netdev Network device.
- */
-static void ifec_tx_process ( struct net_device *netdev )
-{
- struct ifec_private *priv = netdev->priv;
- struct ifec_tcb *tcb = priv->tcb_tail;
- s16 status;
-
- DBGP ( "ifec_tx_process\n" );
-
- /* Check status of transmitted packets */
- while ( ( status = tcb->status ) && tcb->iob ) {
- if ( status & TCB_U ) {
- /* report error to gPXE */
- DBG ( "ifec_tx_process : tx error!\n " );
- netdev_tx_complete_err ( netdev, tcb->iob, -EINVAL );
- } else {
- /* report successful transmit */
- netdev_tx_complete ( netdev, tcb->iob );
- }
- DBG2 ( "tx completion\n" );
-
- tcb->iob = NULL;
- tcb->status = 0;
-
- priv->tcb_tail = tcb->next; /* Next TCB */
- tcb = tcb->next;
- }
-}
-
-/*
- * Allocates & initialize tx resources.
- *
- * @v netdev Network device.
- * @ret rc Non-zero if error occurred.
- */
-static int ifec_tx_setup ( struct net_device *netdev )
-{
- struct ifec_private *priv = netdev->priv;
- struct ifec_tcb *tcb;
- int i;
-
- DBGP ( "ifec_tx_setup\n" );
-
- /* allocate tx ring */
- priv->tcbs = malloc_dma ( TX_RING_BYTES, CB_ALIGN );
- if ( !priv->tcbs ) {
- DBG ( "TX-ring allocation failed\n" );
- return -ENOMEM;
- }
-
- tcb = priv->tcb_tail = priv->tcbs;
- priv->tx_curr = priv->tx_tail = 0;
- priv->tx_cnt = 0;
-
- for ( i = 0; i < TCB_COUNT; i++, tcb++ ) {
- tcb->status = 0;
- tcb->count = 0x01208000;
- tcb->iob = NULL;
- tcb->tbda_addr = virt_to_bus ( &tcb->tbd_addr0 );
- tcb->link = virt_to_bus ( tcb + 1 );
- tcb->next = tcb + 1;
- }
- /* We point tcb_head at the last TCB, so the first ifec_net_transmit()
- * will use the first (head->next) TCB to transmit. */
- priv->tcb_head = --tcb;
- tcb->link = virt_to_bus ( priv->tcbs );
- tcb->next = priv->tcbs;
-
- return 0;
-}
-
-/*
- * Wake up the Command Unit and issue a Resume/Start.
- *
- * @v netdev Network device containing Command Unit
- *
- * The time between clearing the S bit and issuing Resume must be as short as
- * possible to prevent a race condition. As noted in linux eepro100.c :
- * Note: Watch out for the potential race condition here: imagine
- * erasing the previous suspend
- * the chip processes the previous command
- * the chip processes the final command, and suspends
- * doing the CU_RESUME
- * the chip processes the next-yet-valid post-final-command.
- * So blindly sending a CU_RESUME is only safe if we do it immediately after
- * erasing the previous CmdSuspend, without the possibility of an intervening
- * delay.
- */
-void ifec_tx_wake ( struct net_device *netdev )
-{
- struct ifec_private *priv = netdev->priv;
- unsigned long ioaddr = priv->ioaddr;
- struct ifec_tcb *tcb = priv->tcb_head->next;
-
- DBGP ( "ifec_tx_wake\n" );
-
- /* For the special case of the first transmit, we issue a START. The
- * card won't RESUME after the configure command. */
- if ( priv->configured ) {
- priv->configured = 0;
- ifec_scb_cmd ( netdev, virt_to_bus ( tcb ), CUStart );
- ifec_scb_cmd_wait ( netdev );
- return;
- }
-
- /* Resume if suspended. */
- switch ( ( inw ( ioaddr + SCBStatus ) >> 6 ) & 0x3 ) {
- case 0: /* Idle - We should not reach this state. */
- DBG2 ( "ifec_tx_wake: tx idle!\n" );
- ifec_scb_cmd ( netdev, virt_to_bus ( tcb ), CUStart );
- ifec_scb_cmd_wait ( netdev );
- return;
- case 1: /* Suspended */
- DBG2 ( "s" );
- break;
- default: /* Active */
- DBG2 ( "a" );
- }
- ifec_scb_cmd_wait ( netdev );
- outl ( 0, ioaddr + SCBPointer );
- priv->tcb_head->command &= ~CmdSuspend;
- /* Immediately issue Resume command */
- outb ( CUResume, ioaddr + SCBCmd );
- ifec_scb_cmd_wait ( netdev );
-}
-
-/*********************************************************************/
-
-static struct pci_device_id ifec_nics[] = {
-PCI_ROM(0x8086, 0x1029, "id1029", "Intel EtherExpressPro100 ID1029", 0),
-PCI_ROM(0x8086, 0x1030, "id1030", "Intel EtherExpressPro100 ID1030", 0),
-PCI_ROM(0x8086, 0x1031, "82801cam", "Intel 82801CAM (ICH3) Chipset Ethernet Controller", 0),
-PCI_ROM(0x8086, 0x1032, "eepro100-1032", "Intel PRO/100 VE Network Connection", 0),
-PCI_ROM(0x8086, 0x1033, "eepro100-1033", "Intel PRO/100 VM Network Connection", 0),
-PCI_ROM(0x8086, 0x1034, "eepro100-1034", "Intel PRO/100 VM Network Connection", 0),
-PCI_ROM(0x8086, 0x1035, "eepro100-1035", "Intel 82801CAM (ICH3) Chipset Ethernet Controller", 0),
-PCI_ROM(0x8086, 0x1036, "eepro100-1036", "Intel 82801CAM (ICH3) Chipset Ethernet Controller", 0),
-PCI_ROM(0x8086, 0x1037, "eepro100-1037", "Intel 82801CAM (ICH3) Chipset Ethernet Controller", 0),
-PCI_ROM(0x8086, 0x1038, "id1038", "Intel PRO/100 VM Network Connection", 0),
-PCI_ROM(0x8086, 0x1039, "82562et", "Intel PRO100 VE 82562ET", 0),
-PCI_ROM(0x8086, 0x103a, "id103a", "Intel Corporation 82559 InBusiness 10/100", 0),
-PCI_ROM(0x8086, 0x103b, "82562etb", "Intel PRO100 VE 82562ETB", 0),
-PCI_ROM(0x8086, 0x103c, "eepro100-103c", "Intel PRO/100 VM Network Connection", 0),
-PCI_ROM(0x8086, 0x103d, "eepro100-103d", "Intel PRO/100 VE Network Connection", 0),
-PCI_ROM(0x8086, 0x103e, "eepro100-103e", "Intel PRO/100 VM Network Connection", 0),
-PCI_ROM(0x8086, 0x1051, "prove", "Intel PRO/100 VE Network Connection", 0),
-PCI_ROM(0x8086, 0x1059, "82551qm", "Intel PRO/100 M Mobile Connection", 0),
-PCI_ROM(0x8086, 0x1209, "82559er", "Intel EtherExpressPro100 82559ER", 0),
-PCI_ROM(0x8086, 0x1227, "82865", "Intel 82865 EtherExpress PRO/100A", 0),
-PCI_ROM(0x8086, 0x1228, "82556", "Intel 82556 EtherExpress PRO/100 Smart", 0),
-PCI_ROM(0x8086, 0x1229, "eepro100", "Intel EtherExpressPro100", 0),
-PCI_ROM(0x8086, 0x2449, "82562em", "Intel EtherExpressPro100 82562EM", 0),
-PCI_ROM(0x8086, 0x2459, "82562-1", "Intel 82562 based Fast Ethernet Connection", 0),
-PCI_ROM(0x8086, 0x245d, "82562-2", "Intel 82562 based Fast Ethernet Connection", 0),
-PCI_ROM(0x8086, 0x1050, "82562ez", "Intel 82562EZ Network Connection", 0),
-PCI_ROM(0x8086, 0x1051, "eepro100-1051", "Intel 82801EB/ER (ICH5/ICH5R) Chipset Ethernet Controller", 0),
-PCI_ROM(0x8086, 0x1065, "82562-3", "Intel 82562 based Fast Ethernet Connection", 0),
-PCI_ROM(0x8086, 0x5200, "eepro100-5200", "Intel EtherExpress PRO/100 Intelligent Server", 0),
-PCI_ROM(0x8086, 0x5201, "eepro100-5201", "Intel EtherExpress PRO/100 Intelligent Server", 0),
-};
-
-/* Cards with device ids 0x1030 to 0x103F, 0x2449, 0x2459 or 0x245D might need
- * a workaround for hardware bug on 10 mbit half duplex (see linux driver eepro100.c)
- * 2003/03/17 gbaum */
-
-struct pci_driver ifec_driver __pci_driver = {
- .ids = ifec_nics,
- .id_count = ( sizeof (ifec_nics) / sizeof (ifec_nics[0]) ),
- .probe = ifec_pci_probe,
- .remove = ifec_pci_remove
-};
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * c-indent-level: 8
- * tab-width: 8
- * End:
- */