diff options
author | 2017-04-25 03:31:15 -0700 | |
---|---|---|
committer | 2017-05-22 06:48:08 +0000 | |
commit | bb756eebdac6fd24e8919e2c43f7d2c8c4091f59 (patch) | |
tree | ca11e03542edf2d8f631efeca5e1626d211107e3 /qemu/roms/ipxe/src/drivers/net/eepro100.c | |
parent | a14b48d18a9ed03ec191cf16b162206998a895ce (diff) |
Adding qemu as a submodule of KVMFORNFV
This Patch includes the changes to add qemu as a submodule to
kvmfornfv repo and make use of the updated latest qemu for the
execution of all testcase
Change-Id: I1280af507a857675c7f81d30c95255635667bdd7
Signed-off-by:RajithaY<rajithax.yerrumsetty@intel.com>
Diffstat (limited to 'qemu/roms/ipxe/src/drivers/net/eepro100.c')
-rw-r--r-- | qemu/roms/ipxe/src/drivers/net/eepro100.c | 1164 |
1 files changed, 0 insertions, 1164 deletions
diff --git a/qemu/roms/ipxe/src/drivers/net/eepro100.c b/qemu/roms/ipxe/src/drivers/net/eepro100.c deleted file mode 100644 index 1046cda39..000000000 --- a/qemu/roms/ipxe/src/drivers/net/eepro100.c +++ /dev/null @@ -1,1164 +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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, 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 iPXE. 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 iPXE during initialization. Typical NIC - * initialization is performed. EEPROM data is read. - * - * Network Boot - * - * ifec_net_open() is called by iPXE 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 <ipxe/ethernet.h> -#include <ipxe/if_ether.h> -#include <ipxe/iobuf.h> -#include <ipxe/malloc.h> -#include <ipxe/pci.h> -#include <ipxe/spi_bit.h> -#include <ipxe/timer.h> -#include <ipxe/nvs.h> -#include <ipxe/threewire.h> -#include <ipxe/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 -}; - -/******************* iPXE 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 iPXE is initializing. - * This is a iPXE PCI Device Driver API function. - */ -static int ifec_pci_probe ( struct pci_device *pci ) -{ - 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 ); - - if ( ( rc = register_netdev ( netdev ) ) != 0 ) - goto error; - - netdev_link_up ( netdev ); - - 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 ); -} - -/****************** iPXE Network Device Driver API functions *****************/ - -/* - * Close a network device. - * - * @v netdev Device to close. - * - * This is a iPXE 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 iPXE 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 iPXE 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 iPXE to let the driver check the status of - * transmitted packets and to allow the driver to check for received packets. - * This is a iPXE Network Device Driver API function. - */ -static void ifec_net_poll ( struct net_device *netdev ) -{ - struct ifec_private *priv = netdev->priv; - 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 ); - - /* 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 iPXE 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 (%zd 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 ); -} - -/* - * 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 & ~RFDShort ) ) != 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 occurred - */ -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 iPXE */ - 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, 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), -PCI_ROM(0x8086, 0x1092, "82562-3", "Intel Pro/100 VE Network", 0), -PCI_ROM(0x8086, 0x27dc, "eepro100-27dc", "Intel 82801G (ICH7) Chipset Ethernet Controller", 0), -PCI_ROM(0x8086, 0x10fe, "82552", "Intel 82552 10/100 Network Connection", 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: - */ |