176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * eepro100.c -- This is a driver for Intel Fast Ethernet Controllers 376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * (ifec). 476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Originally written for Etherboot by: 676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright (C) AW Computer Systems. 876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * written by R.E.Wolff -- R.E.Wolff@BitWizard.nl 976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * AW Computer Systems is contributing to the free software community 1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * by paying for this driver and then putting the result under GPL. 1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * If you need a Linux device driver, please contact BitWizard for a 1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * quote. 1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This program is free software; you can redistribute it and/or 1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * modify it under the terms of the GNU General Public License as 1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * published by the Free Software Foundation; either version 2, or (at 1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * your option) any later version. 2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This program is distributed in the hope that it will be useful, but 2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * WITHOUT ANY WARRANTY; without even the implied warranty of 2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * General Public License for more details. 2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * You should have received a copy of the GNU General Public License 2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * along with this program; if not, write to the Free Software 2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * date version by what 3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Written: May 29 1997 V0.10 REW Initial revision. 3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * changes: May 31 1997 V0.90 REW Works! 3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Jun 1 1997 V0.91 REW Cleanup 3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Jun 2 1997 V0.92 REW Add some code documentation 3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Jul 25 1997 V1.00 REW Tested by AW to work in a PROM 3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Cleanup for publication 3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Dez 11 2004 V1.10 Kiszka Add RX ring buffer support 3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Jun 2008 v2.0 mdeck Updated to gPXE. Changed much. 4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Cleanups and fixes by Thomas Miletich<thomas.miletich@gmail.com> 4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This is the etherboot intel etherexpress Pro/100B driver. 4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * It was written from scratch, with Donald Beckers eepro100.c kernel 4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * driver as a guideline. Mostly the 82557 related definitions and the 4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * lower level routines have been cut-and-pasted into this source. 4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * The driver was finished before Intel got the NDA out of the closet. 5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Datasheet is now published and available from 5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ftp://download.intel.com/design/network/manuals/8255X_OpenSDM.pdf 5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * - Michael Brown 5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * */ 5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5676d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanFILE_LICENCE ( GPL2_OR_LATER ); 5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * General Theory of Operation 6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Initialization 6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ifec_pci_probe() is called by gPXE during initialization. Typical NIC 6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * initialization is performed. EEPROM data is read. 6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Network Boot 6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ifec_net_open() is called by gPXE before attempting to network boot from the 6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * card. Here, the Command Unit & Receive Unit are initialized. The tx & rx 7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * rings are setup. The MAC address is programmed and the card is configured. 7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Transmit 7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ifec_net_transmit() enqueues a packet in the tx ring - active::tcbs[] The tx 7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ring is composed of TCBs linked to each other into a ring. A tx request 7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * fills out the next available TCB with a pointer to the packet data. 7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * The last enqueued tx is always at active::tcb_head. Thus, a tx request fills 7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * out the TCB following tcb_head. 7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * active::tcb_tail points to the TCB we're awaiting completion of. 8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ifec_tx_process() checks tcb_tail, and once complete, 8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * blindly increments tcb_tail to the next ring TCB. 8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Receive 8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * priv::rfds[] is an array of Receive Frame Descriptors. The RFDs are linked 8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * together to form a ring. 8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ifec_net_poll() calls ifec_rx_process(), which checks the next RFD for 8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * data. If we received a packet, we allocate a new io_buffer and copy the 8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * packet data into it. If alloc_iob() fails, we don't touch the RFD and try 9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * again on the next poll. 9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Debugging levels: 9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * - DBG() is for any errors, i.e. failed alloc_iob(), malloc_dma(), 9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * TX overflow, corrupted packets, ... 9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * - DBG2() is for successful events, like packet received, 9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * packet transmitted, and other general notifications. 9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * - DBGP() prints the name of each called function on entry 10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdint.h> 10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <byteswap.h> 10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <errno.h> 10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdio.h> 10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <unistd.h> 10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/ethernet.h> 10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/if_ether.h> 10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/iobuf.h> 11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/malloc.h> 11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/pci.h> 11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/spi_bit.h> 11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/timer.h> 11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/nvs.h> 11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/threewire.h> 11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/netdevice.h> 11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "eepro100.h" 11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/****************************** Global data **********************************/ 12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This is the default configuration command data. The values were copied from 12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the Linux kernel initialization for the eepro100. 12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct ifec_cfg ifec_cfg = { 12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .status = 0, 12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .command = CmdConfigure | CmdSuspend, 12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .link = 0, /* Filled in later */ 12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .byte = { 22, /* How many bytes in this array */ 13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ( TX_FIFO << 4 ) | RX_FIFO, /* Rx & Tx FIFO limits */ 13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 0, 0, /* Adaptive Interframe Spacing */ 13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman RX_DMA_COUNT, /* Rx DMA max byte count */ 13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman TX_DMA_COUNT + 0x80, /* Tx DMA max byte count */ 13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 0x32, /* Many bits. */ 13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 0x03, /* Discard short receive & Underrun retries */ 13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 1, /* 1=Use MII 0=Use AUI */ 13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 0, 13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 0x2E, /* NSAI, Preamble length, & Loopback*/ 13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 0, /* Linear priority */ 14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 0x60, /* L PRI MODE & Interframe spacing */ 14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 0, 0xf2, 14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 0x48, /* Promiscuous, Broadcast disable, CRS & CDT */ 14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 0, 0x40, 14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 0xf2, /* Stripping, Padding, Receive CRC Transfer */ 14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 0x80, /* 0x40=Force full-duplex, 0x80=Allowfull-duplex*/ 14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 0x3f, /* Multiple IA */ 14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 0x0D } /* Multicast all */ 14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct net_device_operations ifec_operations = { 15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .open = ifec_net_open, 15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .close = ifec_net_close, 15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .transmit = ifec_net_transmit, 15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .poll = ifec_net_poll, 15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .irq = ifec_net_irq 15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/******************* gPXE PCI Device Driver API functions ********************/ 15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Initialize the PCI device. 16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v pci The device's associated pci_device structure. 16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v id The PCI device + vendor id. 16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret rc Returns zero if successfully initialized. 16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This function is called very early on, while gPXE is initializing. 16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This is a gPXE PCI Device Driver API function. 16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int ifec_pci_probe ( struct pci_device *pci, 17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const struct pci_device_id *id __unused ) 17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net_device *netdev; 17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_private *priv; 17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int rc; 17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "ifec_pci_probe: " ); 17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( pci->ioaddr == 0 ) 18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -EINVAL; 18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev = alloc_etherdev ( sizeof(*priv) ); 18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( !netdev ) 18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -ENOMEM; 18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_init ( netdev, &ifec_operations ); 18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman priv = netdev->priv; 18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pci_set_drvdata ( pci, netdev ); 19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev->dev = &pci->dev; 19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* enable bus master, etc */ 19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman adjust_pci_device( pci ); 19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "pci " ); 19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memset ( priv, 0, sizeof(*priv) ); 19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman priv->ioaddr = pci->ioaddr; 19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_reset ( netdev ); 20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "reset " ); 20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_init_eeprom ( netdev ); 20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* read MAC address */ 20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman nvs_read ( &priv->eeprom.nvs, EEPROM_ADDR_MAC_0, netdev->hw_addr, 20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ETH_ALEN ); 20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* read mdio_register */ 20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman nvs_read ( &priv->eeprom.nvs, EEPROM_ADDR_MDIO_REGISTER, 21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman &priv->mdio_register, 2 ); 21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_link_update ( netdev ); /* Update link state */ 21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ( rc = register_netdev ( netdev ) ) != 0 ) 21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto error; 21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "ints\n" ); 21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerror: 22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_reset ( netdev ); 22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_nullify ( netdev ); 22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_put ( netdev ); 22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return rc; 22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 23076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Remove a device from the PCI device list. 23176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 23276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v pci PCI device to remove. 23376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 23476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This is a PCI Device Driver API function. 23576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 23676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void ifec_pci_remove ( struct pci_device *pci ) 23776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 23876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net_device *netdev = pci_get_drvdata ( pci ); 23976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 24076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "ifec_pci_remove\n" ); 24176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 24276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unregister_netdev ( netdev ); 24376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_reset ( netdev ); 24476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_nullify ( netdev ); 24576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_put ( netdev ); 24676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 24776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 24876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/****************** gPXE Network Device Driver API functions *****************/ 24976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 25076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 25176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Close a network device. 25276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 25376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Device to close. 25476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 25576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This is a gPXE Network Device Driver API function. 25676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 25776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void ifec_net_close ( struct net_device *netdev ) 25876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 25976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_private *priv = netdev->priv; 26076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned long ioaddr = priv->ioaddr; 26176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned short intr_status; 26276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 26376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "ifec_net_close\n" ); 26476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 26576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* disable interrupts */ 26676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_net_irq ( netdev, 0 ); 26776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 26876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Ack & clear ints */ 26976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman intr_status = inw ( ioaddr + SCBStatus ); 27076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman outw ( intr_status, ioaddr + SCBStatus ); 27176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman inw ( ioaddr + SCBStatus ); 27276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 27376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_reset ( netdev ); 27476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 27576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Free any resources */ 27676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_free ( netdev ); 27776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 27876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 27976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Interrupts to be masked */ 28076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define INTERRUPT_MASK ( SCBMaskEarlyRx | SCBMaskFlowCtl ) 28176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 28276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 28376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Enable or disable IRQ masking. 28476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 28576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Device to control. 28676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v enable Zero to mask off IRQ, non-zero to enable IRQ. 28776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 28876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This is a gPXE Network Driver API function. 28976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 29076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void ifec_net_irq ( struct net_device *netdev, int enable ) 29176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 29276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_private *priv = netdev->priv; 29376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned long ioaddr = priv->ioaddr; 29476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 29576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "ifec_net_irq\n" ); 29676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 29776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman outw ( enable ? INTERRUPT_MASK : SCBMaskAll, ioaddr + SCBCmd ); 29876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 29976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 30076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 30176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Opens a network device. 30276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 30376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Device to be opened. 30476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret rc Non-zero if failed to open. 30576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 30676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This enables tx and rx on the device. 30776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This is a gPXE Network Device Driver API function. 30876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 30976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int ifec_net_open ( struct net_device *netdev ) 31076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 31176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_private *priv = netdev->priv; 31276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_ias *ias = NULL; 31376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_cfg *cfg = NULL; 31476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int i, options; 31576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int rc = -ENOMEM; 31676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 31776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "ifec_net_open: " ); 31876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 31976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Ensure interrupts are disabled. */ 32076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_net_irq ( netdev, 0 ); 32176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 32276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Initialize Command Unit and Receive Unit base addresses. */ 32376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_scb_cmd ( netdev, 0, RUAddrLoad ); 32476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_scb_cmd ( netdev, virt_to_bus ( &priv->stats ), CUStatsAddr ); 32576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_scb_cmd ( netdev, 0, CUCmdBase ); 32676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 32776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Initialize both rings */ 32876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ( rc = ifec_rx_setup ( netdev ) ) != 0 ) 32976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto error; 33076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ( rc = ifec_tx_setup ( netdev ) ) != 0 ) 33176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto error; 33276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 33376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Initialize MDIO */ 33476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman options = 0x00; /* 0x40 = 10mbps half duplex, 0x00 = Autosense */ 33576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_mdio_setup ( netdev, options ); 33676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 33776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Prepare MAC address w/ Individual Address Setup (ias) command.*/ 33876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ias = malloc_dma ( sizeof ( *ias ), CB_ALIGN ); 33976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( !ias ) { 34076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rc = -ENOMEM; 34176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto error; 34276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 34376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ias->command = CmdIASetup; 34476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ias->status = 0; 34576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memcpy ( ias->ia, netdev->ll_addr, ETH_ALEN ); 34676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 34776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Prepare operating parameters w/ a configure command. */ 34876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cfg = malloc_dma ( sizeof ( *cfg ), CB_ALIGN ); 34976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( !cfg ) { 35076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rc = -ENOMEM; 35176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto error; 35276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 35376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memcpy ( cfg, &ifec_cfg, sizeof ( *cfg ) ); 35476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cfg->link = virt_to_bus ( priv->tcbs ); 35576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cfg->byte[19] = ( options & 0x10 ) ? 0xC0 : 0x80; 35676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ias->link = virt_to_bus ( cfg ); 35776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 35876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Issue the ias and configure commands. */ 35976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_scb_cmd ( netdev, virt_to_bus ( ias ), CUStart ); 36076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_scb_cmd_wait ( netdev ); 36176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman priv->configured = 1; 36276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 36376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Wait up to 10 ms for configuration to initiate */ 36476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for ( i = 10; i && !cfg->status; i-- ) 36576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mdelay ( 1 ); 36676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ! cfg->status ) { 36776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "Failed to initiate!\n" ); 36876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto error; 36976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 37076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free_dma ( ias, sizeof ( *ias ) ); 37176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free_dma ( cfg, sizeof ( *cfg ) ); 37276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG2 ( "cfg " ); 37376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 37476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Enable rx by sending ring address to card */ 37576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( priv->rfds[0] != NULL ) { 37676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_scb_cmd ( netdev, virt_to_bus( priv->rfds[0] ), RUStart ); 37776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_scb_cmd_wait ( netdev ); 37876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 37976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG2 ( "rx_start\n" ); 38076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 38176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 38276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 38376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerror: 38476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free_dma ( cfg, sizeof ( *cfg ) ); 38576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free_dma ( ias, sizeof ( *ias ) ); 38676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_free ( netdev ); 38776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_reset ( netdev ); 38876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return rc; 38976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 39076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 39176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 39276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This function allows a driver to process events during operation. 39376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 39476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Device being polled. 39576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 39676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This is called periodically by gPXE to let the driver check the status of 39776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * transmitted packets and to allow the driver to check for received packets. 39876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This is a gPXE Network Device Driver API function. 39976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 40076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void ifec_net_poll ( struct net_device *netdev ) 40176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 40276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_private *priv = netdev->priv; 40376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman static int linkpoll = 0; 40476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned short intr_status; 40576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 40676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "ifec_net_poll\n" ); 40776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 40876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* acknowledge interrupts ASAP */ 40976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman intr_status = inw ( priv->ioaddr + SCBStatus ); 41076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman outw ( intr_status, priv->ioaddr + SCBStatus ); 41176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman inw ( priv->ioaddr + SCBStatus ); 41276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 41376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG2 ( "poll - status: 0x%04X\n", intr_status ); 41476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 41576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ++linkpoll > LINK_CHECK_PERIOD ) { 41676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman linkpoll = 0; 41776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_link_update ( netdev ); /* Update link state */ 41876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 41976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 42076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* anything to do here? */ 42176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ( intr_status & ( ~INTERRUPT_MASK ) ) == 0 ) 42276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 42376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 42476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* process received and transmitted packets */ 42576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_tx_process ( netdev ); 42676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_rx_process ( netdev ); 42776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 42876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_check_ru_status ( netdev, intr_status ); 42976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 43076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 43176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 43276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 43376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 43476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This transmits a packet. 43576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 43676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Device to transmit from. 43776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf Data to transmit. 43876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret rc Non-zero if failed to transmit. 43976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 44076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This is a gPXE Network Driver API function. 44176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 44276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int ifec_net_transmit ( struct net_device *netdev, 44376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct io_buffer *iobuf ) 44476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 44576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_private *priv = netdev->priv; 44676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_tcb *tcb = priv->tcb_head->next; 44776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned long ioaddr = priv->ioaddr; 44876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 44976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "ifec_net_transmit\n" ); 45076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 45176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Wait for TCB to become available. */ 45276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( tcb->status || tcb->iob ) { 45376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "TX overflow\n" ); 45476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -ENOBUFS; 45576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 45676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 45776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG2 ( "transmitting packet (%d bytes). status = %hX, cmd=%hX\n", 45876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iob_len ( iobuf ), tcb->status, inw ( ioaddr + SCBCmd ) ); 45976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 46076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tcb->command = CmdSuspend | CmdTx | CmdTxFlex; 46176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tcb->count = 0x01208000; 46276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tcb->tbd_addr0 = virt_to_bus ( iobuf->data ); 46376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tcb->tbd_size0 = 0x3FFF & iob_len ( iobuf ); 46476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tcb->iob = iobuf; 46576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 46676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_tx_wake ( netdev ); 46776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 46876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Append to end of ring. */ 46976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman priv->tcb_head = tcb; 47076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 47176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 47276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 47376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 47476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*************************** Local support functions *************************/ 47576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 47676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Define what each GPIO Pin does */ 47776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic const uint16_t ifec_ee_bits[] = { 47876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman [SPI_BIT_SCLK] = EE_SHIFT_CLK, 47976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman [SPI_BIT_MOSI] = EE_DATA_WRITE, 48076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman [SPI_BIT_MISO] = EE_DATA_READ, 48176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman [SPI_BIT_SS(0)] = EE_ENB, 48276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 48376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 48476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 48576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Read a single bit from the GPIO pins used for SPI. 48676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * should be called by SPI bitbash functions only 48776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 48876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v basher Bitbash device 48976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v bit_id Line to be read 49076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 49176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int ifec_spi_read_bit ( struct bit_basher *basher, 49276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned int bit_id ) 49376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 49476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_private *priv = 49576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman container_of ( basher, struct ifec_private, spi.basher ); 49676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned long ee_addr = priv->ioaddr + CSREeprom; 49776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned int ret = 0; 49876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t mask; 49976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 50076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "ifec_spi_read_bit\n" ); 50176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 50276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mask = ifec_ee_bits[bit_id]; 50376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ret = inw (ee_addr); 50476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 50576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ( ret & mask ) ? 1 : 0; 50676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 50776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 50876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 50976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Write a single bit to the GPIO pins used for SPI. 51076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * should be called by SPI bitbash functions only 51176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 51276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v basher Bitbash device 51376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v bit_id Line to write to 51476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v data Value to write 51576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 51676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void ifec_spi_write_bit ( struct bit_basher *basher, 51776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned int bit_id, 51876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned long data ) 51976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 52076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_private *priv = 52176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman container_of ( basher, struct ifec_private, spi.basher ); 52276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned long ee_addr = priv->ioaddr + CSREeprom; 52376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman short val; 52476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t mask = ifec_ee_bits[bit_id]; 52576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 52676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "ifec_spi_write_bit\n" ); 52776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 52876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman val = inw ( ee_addr ); 52976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman val &= ~mask; 53076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman val |= data & mask; 53176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 53276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman outw ( val, ee_addr ); 53376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 53476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 53576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* set function pointer to SPI read- and write-bit functions */ 53676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct bit_basher_operations ifec_basher_ops = { 53776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .read = ifec_spi_read_bit, 53876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .write = ifec_spi_write_bit, 53976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 54076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 54176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 54276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Initialize the eeprom stuff 54376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 54476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device 54576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 54676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void ifec_init_eeprom ( struct net_device *netdev ) 54776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 54876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_private *priv = netdev->priv; 54976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 55076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "ifec_init_eeprom\n" ); 55176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 55276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman priv->spi.basher.op = &ifec_basher_ops; 55376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman priv->spi.bus.mode = SPI_MODE_THREEWIRE; 55476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman init_spi_bit_basher ( &priv->spi ); 55576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 55676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman priv->eeprom.bus = &priv->spi.bus; 55776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 55876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* init as 93c46(93c14 compatible) first, to set the command len, 55976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * block size and word len. Needs to be set for address len detection. 56076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 56176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman init_at93c46 ( &priv->eeprom, 16 ); 56276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 56376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* detect address length, */ 56476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman threewire_detect_address_len ( &priv->eeprom ); 56576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 56676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* address len == 8 means 93c66 instead of 93c46 */ 56776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( priv->eeprom.address_len == 8 ) 56876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman init_at93c66 ( &priv->eeprom, 16 ); 56976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 57076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 57176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 57276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Check if the network cable is plugged in. 57376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 57476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device to check. 57576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret retval greater 0 if linkup. 57676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 57776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int ifec_link_check ( struct net_device *netdev ) 57876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 57976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_private *priv = netdev->priv; 58076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned short mdio_register = priv->mdio_register; 58176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 58276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "ifec_link_check\n" ); 58376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 58476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Read the status register once to discard stale data */ 58576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_mdio_read ( netdev, mdio_register & 0x1f, 1 ); 58676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Check to see if network cable is plugged in. */ 58776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ! ( ifec_mdio_read ( netdev, mdio_register & 0x1f, 1 ) 58876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman & ( 1 << 2 ) ) ) { 58976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 59076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 59176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 1; 59276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 59376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 59476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 59576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Check network cable link, inform gPXE as appropriate. 59676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 59776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device to check. 59876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 59976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void ifec_link_update ( struct net_device *netdev ) 60076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 60176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "ifec_link_update\n" ); 60276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 60376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Update link state */ 60476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ifec_link_check ( netdev ) ) 60576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_link_up ( netdev ); 60676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 60776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_link_down ( netdev ); 60876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 60976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 61076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 61176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Support function: ifec_mdio_read 61276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 61376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This probably reads a register in the "physical media interface chip". 61476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * -- REW 61576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 61676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int ifec_mdio_read ( struct net_device *netdev, int phy_id, 61776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int location ) 61876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 61976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_private *priv = netdev->priv; 62076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned long ioaddr = priv->ioaddr; 62176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int val; 62276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int boguscnt = 64*4; /* <64 usec. to complete, typ 27 ticks */ 62376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 62476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "ifec_mdio_read\n" ); 62576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 62676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman outl ( 0x08000000 | ( location << 16 ) | ( phy_id << 21 ), 62776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ioaddr + CSRCtrlMDI ); 62876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman do { 62976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman udelay ( 16 ); 63076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 63176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman val = inl ( ioaddr + CSRCtrlMDI ); 63276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 63376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( --boguscnt < 0 ) { 63476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( " ifec_mdio_read() time out with val = %X.\n", 63576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman val ); 63676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 63776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 63876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } while (! ( val & 0x10000000 ) ); 63976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return val & 0xffff; 64076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 64176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 64276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 64376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Initializes MDIO. 64476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 64576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device 64676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v options MDIO options 64776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 64876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void ifec_mdio_setup ( struct net_device *netdev, int options ) 64976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 65076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_private *priv = netdev->priv; 65176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned short mdio_register = priv->mdio_register; 65276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 65376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "ifec_mdio_setup\n" ); 65476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 65576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ( (mdio_register>>8) & 0x3f ) == DP83840 65676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman || ( (mdio_register>>8) & 0x3f ) == DP83840A ) { 65776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int mdi_reg23 = ifec_mdio_read ( netdev, mdio_register 65876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman & 0x1f, 23 ) | 0x0422; 65976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (CONGENB) 66076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mdi_reg23 |= 0x0100; 66176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG2 ( "DP83840 specific setup, setting register 23 to " 66276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "%hX.\n", mdi_reg23 ); 66376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_mdio_write ( netdev, mdio_register & 0x1f, 23, mdi_reg23 ); 66476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 66576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG2 ( "dp83840 " ); 66676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( options != 0 ) { 66776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_mdio_write ( netdev, mdio_register & 0x1f, 0, 66876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ( (options & 0x20) ? 0x2000 : 0 ) | 66976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ( (options & 0x10) ? 0x0100 : 0 ) ); 67076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG2 ( "set mdio_register. " ); 67176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 67276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 67376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 67476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 67576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Support function: ifec_mdio_write 67676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 67776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This probably writes to the "physical media interface chip". 67876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * -- REW 67976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 68076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int ifec_mdio_write ( struct net_device *netdev, 68176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int phy_id, int location, int value ) 68276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 68376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_private *priv = netdev->priv; 68476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned long ioaddr = priv->ioaddr; 68576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int val; 68676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int boguscnt = 64*4; /* <64 usec. to complete, typ 27 ticks */ 68776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 68876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "ifec_mdio_write\n" ); 68976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 69076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman outl ( 0x04000000 | ( location << 16 ) | ( phy_id << 21 ) | value, 69176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ioaddr + CSRCtrlMDI ); 69276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman do { 69376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman udelay ( 16 ); 69476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 69576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman val = inl ( ioaddr + CSRCtrlMDI ); 69676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( --boguscnt < 0 ) { 69776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( " ifec_mdio_write() time out with val = %X.\n", 69876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman val ); 69976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 70076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 70176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } while (! ( val & 0x10000000 ) ); 70276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return val & 0xffff; 70376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 70476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 70576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 70676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Resets the hardware. 70776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 70876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device 70976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 71076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void ifec_reset ( struct net_device *netdev ) 71176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 71276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_private *priv = netdev->priv; 71376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned long ioaddr = priv->ioaddr; 71476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 71576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "ifec_reset\n" ); 71676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 71776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* do partial reset first */ 71876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman outl ( PortPartialReset, ioaddr + CSRPort ); 71976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman inw ( ioaddr + SCBStatus ); 72076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman udelay ( 20 ); 72176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 72276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* full reset */ 72376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman outl ( PortReset, ioaddr + CSRPort ); 72476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman inw ( ioaddr + SCBStatus ); 72576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman udelay ( 20 ); 72676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 72776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* disable interrupts again */ 72876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_net_irq ( netdev, 0 ); 72976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 73076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 73176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 73276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * free()s the tx/rx rings. 73376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 73476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device 73576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 73676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void ifec_free ( struct net_device *netdev ) 73776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 73876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_private *priv = netdev_priv ( netdev ); 73976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int i; 74076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 74176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "ifec_free\n" ); 74276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 74376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* free all allocated receive io_buffers */ 74476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for ( i = 0; i < RFD_COUNT; i++ ) { 74576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free_iob ( priv->rx_iobs[i] ); 74676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman priv->rx_iobs[i] = NULL; 74776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman priv->rfds[i] = NULL; 74876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 74976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 75076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* free TX ring buffer */ 75176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free_dma ( priv->tcbs, TX_RING_BYTES ); 75276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 75376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman priv->tcbs = NULL; 75476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 75576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 75676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 75776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Initializes an RFD. 75876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 75976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v rfd RFD struct to initialize 76076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v command Command word 76176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v link Link value 76276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 76376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void ifec_rfd_init ( struct ifec_rfd *rfd, s16 command, u32 link ) 76476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 76576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "ifec_rfd_init\n" ); 76676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 76776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rfd->status = 0; 76876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rfd->command = command; 76976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rfd->rx_buf_addr = 0xFFFFFFFF; 77076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rfd->count = 0; 77176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rfd->size = RFD_PACKET_LEN; 77276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rfd->link = link; 77376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 77476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 77576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 77676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Send address of new RFD to card 77776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 77876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device 77976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 78076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void ifec_reprime_ru ( struct net_device *netdev ) 78176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 78276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_private *priv = netdev->priv; 78376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int cur_rx = priv->cur_rx; 78476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 78576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "ifec_reprime_ru\n" ); 78676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 78776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( priv->rfds[cur_rx] != NULL ) { 78876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_scb_cmd ( netdev, virt_to_bus ( priv->rfds[cur_rx] ), 78976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman RUStart ); 79076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_scb_cmd_wait ( netdev ); 79176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 79276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 79376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 79476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 79576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Check if reprime of RU needed 79676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 79776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device 79876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 79976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void ifec_check_ru_status ( struct net_device *netdev, 80076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned short intr_status ) 80176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 80276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_private *priv = netdev->priv; 80376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 80476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "ifec_check_ru_status\n" ); 80576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 80676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 80776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * The chip may have suspended reception for various reasons. 80876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Check for that, and re-prime it should this be the case. 80976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 81076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch ( ( intr_status >> 2 ) & 0xf ) { 81176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case 0: /* Idle */ 81276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case 4: /* Ready */ 81376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 81476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case 1: /* Suspended */ 81576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case 2: /* No resources (RFDs) */ 81676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case 9: /* Suspended with no more RBDs */ 81776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case 10: /* No resources due to no RBDs */ 81876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case 12: /* Ready with no RBDs */ 81976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "ifec_net_poll: RU reprimed.\n" ); 82076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_reprime_ru ( netdev ); 82176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 82276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman default: 82376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* reserved values */ 82476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "ifec_net_poll: RU state anomaly: %i\n", 82576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ( inw ( priv->ioaddr + SCBStatus ) >> 2 ) & 0xf ); 82676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 82776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 82876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 82976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 83076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define RFD_STATUS ( RFD_OK | RFDRxCol | RFDRxErr | RFDShort | \ 83176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman RFDDMAOverrun | RFDNoBufs | RFDCRCError ) 83276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 83376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Looks for received packets in the rx ring, reports success or error to 83476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the core accordingly. Starts reallocation of rx ring. 83576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 83676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device 83776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 83876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void ifec_rx_process ( struct net_device *netdev ) 83976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 84076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_private *priv = netdev->priv; 84176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int cur_rx = priv->cur_rx; 84276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct io_buffer *iob = priv->rx_iobs[cur_rx]; 84376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_rfd *rfd = priv->rfds[cur_rx]; 84476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned int rx_len; 84576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman s16 status; 84676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 84776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "ifec_rx_process\n" ); 84876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 84976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Process any received packets */ 85076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while ( iob && rfd && ( status = rfd->status ) ) { 85176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rx_len = rfd->count & RFDMaskCount; 85276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 85376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG2 ( "Got a packet: Len = %d, cur_rx = %d.\n", rx_len, 85476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cur_rx ); 85576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGIO_HD ( (void*)rfd->packet, 0x30 ); 85676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 85776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ( status & RFD_STATUS ) != RFD_OK ) { 85876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "Corrupted packet received. " 85976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "Status = %#08hx\n", status ); 86076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_rx_err ( netdev, iob, -EINVAL ); 86176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 86276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Hand off the packet to the network subsystem */ 86376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iob_put ( iob, rx_len ); 86476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG2 ( "Received packet: %p, len: %d\n", iob, rx_len ); 86576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_rx ( netdev, iob ); 86676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 86776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 86876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* make sure we don't reuse this RFD */ 86976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman priv->rx_iobs[cur_rx] = NULL; 87076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman priv->rfds[cur_rx] = NULL; 87176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 87276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Next RFD */ 87376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman priv->cur_rx = ( cur_rx + 1 ) % RFD_COUNT; 87476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cur_rx = priv->cur_rx; 87576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iob = priv->rx_iobs[cur_rx]; 87676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rfd = priv->rfds[cur_rx]; 87776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 87876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 87976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_refill_rx_ring ( netdev ); 88076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 88176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 88276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 88376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Allocates io_buffer, set pointers in ifec_private structure accordingly, 88476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * reserves space for RFD header in io_buffer. 88576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 88676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device 88776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v cur Descriptor number to work on 88876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v cmd Value to set cmd field in RFD to 88976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v link Pointer to ned RFD 89076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret rc 0 on success, negative on failure 89176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 89276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int ifec_get_rx_desc ( struct net_device *netdev, int cur, int cmd, 89376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int link ) 89476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 89576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_private *priv = netdev->priv; 89676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_rfd *rfd = priv->rfds[cur]; 89776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 89876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "ifec_get_rx_desc\n" ); 89976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 90076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman priv->rx_iobs[cur] = alloc_iob ( sizeof ( *rfd ) ); 90176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ! priv->rx_iobs[cur] ) { 90276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "alloc_iob failed. desc. nr: %d\n", cur ); 90376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman priv->rfds[cur] = NULL; 90476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -ENOMEM; 90576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 90676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 90776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Initialize new tail. */ 90876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman priv->rfds[cur] = priv->rx_iobs[cur]->data; 90976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_rfd_init ( priv->rfds[cur], cmd, link ); 91076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iob_reserve ( priv->rx_iobs[cur], RFD_HEADER_LEN ); 91176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 91276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 91376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 91476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 91576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 91676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Allocate new descriptor entries and initialize them if needed 91776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 91876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device 91976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 92076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void ifec_refill_rx_ring ( struct net_device *netdev ) 92176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 92276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_private *priv = netdev->priv; 92376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int i, cur_rx; 92476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned short intr_status; 92576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 92676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "ifec_refill_rx_ring\n" ); 92776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 92876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for ( i = 0; i < RFD_COUNT; i++ ) { 92976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cur_rx = ( priv->cur_rx + i ) % RFD_COUNT; 93076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* only refill if empty */ 93176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( priv->rfds[cur_rx] != NULL || 93276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman priv->rx_iobs[cur_rx] != NULL ) 93376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman continue; 93476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 93576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG2 ( "refilling RFD %d\n", cur_rx ); 93676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 93776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ifec_get_rx_desc ( netdev, cur_rx, 93876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman CmdSuspend | CmdEndOfList, 0 ) == 0 ) { 93976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( i > 0 ) { 94076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int prev_rx = ( ( ( cur_rx + RFD_COUNT ) - 1 ) 94176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman % RFD_COUNT ); 94276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_rfd *rfd = priv->rfds[prev_rx]; 94376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 94476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rfd->command = 0; 94576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rfd->link = virt_to_bus ( priv->rfds[cur_rx] ); 94676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 94776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 94876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 94976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 95076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman intr_status = inw ( priv->ioaddr + SCBStatus ); 95176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_check_ru_status ( netdev, intr_status ); 95276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 95376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 95476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 95576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Initial allocation & initialization of the rx ring. 95676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 95776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Device of rx ring. 95876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret rc Non-zero if error occured 95976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 96076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int ifec_rx_setup ( struct net_device *netdev ) 96176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 96276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_private *priv = netdev->priv; 96376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int i; 96476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 96576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "ifec_rx_setup\n" ); 96676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 96776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman priv->cur_rx = 0; 96876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 96976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* init values for ifec_refill_rx_ring() */ 97076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for ( i = 0; i < RFD_COUNT; i++ ) { 97176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman priv->rfds[i] = NULL; 97276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman priv->rx_iobs[i] = NULL; 97376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 97476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_refill_rx_ring ( netdev ); 97576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 97676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 97776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 97876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 97976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 98076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Initiates a SCB command. 98176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 98276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device 98376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v ptr General pointer value for command. 98476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v cmd Command to issue. 98576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret rc Non-zero if command not issued. 98676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 98776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int ifec_scb_cmd ( struct net_device *netdev, u32 ptr, u8 cmd ) 98876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 98976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_private *priv = netdev->priv; 99076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned long ioaddr = priv->ioaddr; 99176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int rc; 99276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 99376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "ifec_scb_cmd\n" ); 99476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 99576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rc = ifec_scb_cmd_wait ( netdev ); /* Wait until ready */ 99676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( !rc ) { 99776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman outl ( ptr, ioaddr + SCBPointer ); 99876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman outb ( cmd, ioaddr + SCBCmd ); /* Issue command */ 99976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 100076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return rc; 100176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 100276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 100376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 100476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Wait for command unit to accept a command. 100576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 100676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v cmd_ioaddr I/O address of command register. 100776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret rc Non-zero if command timed out. 100876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 100976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int ifec_scb_cmd_wait ( struct net_device *netdev ) 101076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 101176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_private *priv = netdev->priv; 101276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned long cmd_ioaddr = priv->ioaddr + SCBCmd; 101376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int rc, wait = CU_CMD_TIMEOUT; 101476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 101576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "ifec_scb_cmd_wait\n" ); 101676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 101776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for ( ; wait && ( rc = inb ( cmd_ioaddr ) ); wait-- ) 101876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman udelay ( 1 ); 101976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 102076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( !wait ) 102176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "ifec_scb_cmd_wait timeout!\n" ); 102276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return rc; 102376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 102476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 102576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 102676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Check status of transmitted packets & perform tx completions. 102776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 102876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device. 102976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 103076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void ifec_tx_process ( struct net_device *netdev ) 103176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 103276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_private *priv = netdev->priv; 103376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_tcb *tcb = priv->tcb_tail; 103476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman s16 status; 103576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 103676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "ifec_tx_process\n" ); 103776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 103876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Check status of transmitted packets */ 103976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while ( ( status = tcb->status ) && tcb->iob ) { 104076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( status & TCB_U ) { 104176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* report error to gPXE */ 104276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "ifec_tx_process : tx error!\n " ); 104376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_tx_complete_err ( netdev, tcb->iob, -EINVAL ); 104476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 104576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* report successful transmit */ 104676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_tx_complete ( netdev, tcb->iob ); 104776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 104876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG2 ( "tx completion\n" ); 104976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 105076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tcb->iob = NULL; 105176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tcb->status = 0; 105276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 105376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman priv->tcb_tail = tcb->next; /* Next TCB */ 105476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tcb = tcb->next; 105576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 105676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 105776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 105876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 105976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Allocates & initialize tx resources. 106076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 106176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device. 106276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret rc Non-zero if error occurred. 106376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 106476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int ifec_tx_setup ( struct net_device *netdev ) 106576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 106676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_private *priv = netdev->priv; 106776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_tcb *tcb; 106876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int i; 106976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 107076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "ifec_tx_setup\n" ); 107176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 107276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* allocate tx ring */ 107376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman priv->tcbs = malloc_dma ( TX_RING_BYTES, CB_ALIGN ); 107476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( !priv->tcbs ) { 107576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "TX-ring allocation failed\n" ); 107676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -ENOMEM; 107776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 107876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 107976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tcb = priv->tcb_tail = priv->tcbs; 108076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman priv->tx_curr = priv->tx_tail = 0; 108176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman priv->tx_cnt = 0; 108276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 108376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for ( i = 0; i < TCB_COUNT; i++, tcb++ ) { 108476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tcb->status = 0; 108576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tcb->count = 0x01208000; 108676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tcb->iob = NULL; 108776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tcb->tbda_addr = virt_to_bus ( &tcb->tbd_addr0 ); 108876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tcb->link = virt_to_bus ( tcb + 1 ); 108976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tcb->next = tcb + 1; 109076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 109176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* We point tcb_head at the last TCB, so the first ifec_net_transmit() 109276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * will use the first (head->next) TCB to transmit. */ 109376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman priv->tcb_head = --tcb; 109476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tcb->link = virt_to_bus ( priv->tcbs ); 109576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tcb->next = priv->tcbs; 109676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 109776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 109876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 109976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 110076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 110176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Wake up the Command Unit and issue a Resume/Start. 110276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 110376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device containing Command Unit 110476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 110576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * The time between clearing the S bit and issuing Resume must be as short as 110676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * possible to prevent a race condition. As noted in linux eepro100.c : 110776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Note: Watch out for the potential race condition here: imagine 110876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * erasing the previous suspend 110976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the chip processes the previous command 111076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the chip processes the final command, and suspends 111176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * doing the CU_RESUME 111276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the chip processes the next-yet-valid post-final-command. 111376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * So blindly sending a CU_RESUME is only safe if we do it immediately after 111476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * erasing the previous CmdSuspend, without the possibility of an intervening 111576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * delay. 111676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 111776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid ifec_tx_wake ( struct net_device *netdev ) 111876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 111976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_private *priv = netdev->priv; 112076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned long ioaddr = priv->ioaddr; 112176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ifec_tcb *tcb = priv->tcb_head->next; 112276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 112376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGP ( "ifec_tx_wake\n" ); 112476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 112576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* For the special case of the first transmit, we issue a START. The 112676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * card won't RESUME after the configure command. */ 112776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( priv->configured ) { 112876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman priv->configured = 0; 112976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_scb_cmd ( netdev, virt_to_bus ( tcb ), CUStart ); 113076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_scb_cmd_wait ( netdev ); 113176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 113276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 113376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 113476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Resume if suspended. */ 113576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch ( ( inw ( ioaddr + SCBStatus ) >> 6 ) & 0x3 ) { 113676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case 0: /* Idle - We should not reach this state. */ 113776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG2 ( "ifec_tx_wake: tx idle!\n" ); 113876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_scb_cmd ( netdev, virt_to_bus ( tcb ), CUStart ); 113976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_scb_cmd_wait ( netdev ); 114076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 114176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case 1: /* Suspended */ 114276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG2 ( "s" ); 114376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 114476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman default: /* Active */ 114576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG2 ( "a" ); 114676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 114776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_scb_cmd_wait ( netdev ); 114876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman outl ( 0, ioaddr + SCBPointer ); 114976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman priv->tcb_head->command &= ~CmdSuspend; 115076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Immediately issue Resume command */ 115176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman outb ( CUResume, ioaddr + SCBCmd ); 115276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifec_scb_cmd_wait ( netdev ); 115376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 115476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 115576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*********************************************************************/ 115676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 115776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct pci_device_id ifec_nics[] = { 115876d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x8086, 0x1029, "id1029", "Intel EtherExpressPro100 ID1029", 0), 115976d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x8086, 0x1030, "id1030", "Intel EtherExpressPro100 ID1030", 0), 116076d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x8086, 0x1031, "82801cam", "Intel 82801CAM (ICH3) Chipset Ethernet Controller", 0), 116176d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x8086, 0x1032, "eepro100-1032", "Intel PRO/100 VE Network Connection", 0), 116276d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x8086, 0x1033, "eepro100-1033", "Intel PRO/100 VM Network Connection", 0), 116376d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x8086, 0x1034, "eepro100-1034", "Intel PRO/100 VM Network Connection", 0), 116476d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x8086, 0x1035, "eepro100-1035", "Intel 82801CAM (ICH3) Chipset Ethernet Controller", 0), 116576d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x8086, 0x1036, "eepro100-1036", "Intel 82801CAM (ICH3) Chipset Ethernet Controller", 0), 116676d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x8086, 0x1037, "eepro100-1037", "Intel 82801CAM (ICH3) Chipset Ethernet Controller", 0), 116776d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x8086, 0x1038, "id1038", "Intel PRO/100 VM Network Connection", 0), 116876d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x8086, 0x1039, "82562et", "Intel PRO100 VE 82562ET", 0), 116976d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x8086, 0x103a, "id103a", "Intel Corporation 82559 InBusiness 10/100", 0), 117076d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x8086, 0x103b, "82562etb", "Intel PRO100 VE 82562ETB", 0), 117176d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x8086, 0x103c, "eepro100-103c", "Intel PRO/100 VM Network Connection", 0), 117276d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x8086, 0x103d, "eepro100-103d", "Intel PRO/100 VE Network Connection", 0), 117376d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x8086, 0x103e, "eepro100-103e", "Intel PRO/100 VM Network Connection", 0), 117476d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x8086, 0x1051, "prove", "Intel PRO/100 VE Network Connection", 0), 117576d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x8086, 0x1059, "82551qm", "Intel PRO/100 M Mobile Connection", 0), 117676d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x8086, 0x1209, "82559er", "Intel EtherExpressPro100 82559ER", 0), 117776d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x8086, 0x1227, "82865", "Intel 82865 EtherExpress PRO/100A", 0), 117876d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x8086, 0x1228, "82556", "Intel 82556 EtherExpress PRO/100 Smart", 0), 117976d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x8086, 0x1229, "eepro100", "Intel EtherExpressPro100", 0), 118076d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x8086, 0x2449, "82562em", "Intel EtherExpressPro100 82562EM", 0), 118176d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x8086, 0x2459, "82562-1", "Intel 82562 based Fast Ethernet Connection", 0), 118276d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x8086, 0x245d, "82562-2", "Intel 82562 based Fast Ethernet Connection", 0), 118376d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x8086, 0x1050, "82562ez", "Intel 82562EZ Network Connection", 0), 118476d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x8086, 0x1051, "eepro100-1051", "Intel 82801EB/ER (ICH5/ICH5R) Chipset Ethernet Controller", 0), 118576d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x8086, 0x1065, "82562-3", "Intel 82562 based Fast Ethernet Connection", 0), 118676d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x8086, 0x5200, "eepro100-5200", "Intel EtherExpress PRO/100 Intelligent Server", 0), 118776d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x8086, 0x5201, "eepro100-5201", "Intel EtherExpress PRO/100 Intelligent Server", 0), 118876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 118976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 119076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Cards with device ids 0x1030 to 0x103F, 0x2449, 0x2459 or 0x245D might need 119176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * a workaround for hardware bug on 10 mbit half duplex (see linux driver eepro100.c) 119276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 2003/03/17 gbaum */ 119376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 119476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct pci_driver ifec_driver __pci_driver = { 119576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .ids = ifec_nics, 119676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .id_count = ( sizeof (ifec_nics) / sizeof (ifec_nics[0]) ), 119776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .probe = ifec_pci_probe, 119876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .remove = ifec_pci_remove 119976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 120076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 120176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 120276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Local variables: 120376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * c-basic-offset: 8 120476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * c-indent-level: 8 120576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * tab-width: 8 120676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * End: 120776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 1208