📄 net_3c59x.cxx
字号:
/* * Copyright (C) 1998, 1999, Jonathan S. Shapiro. * * This file is part of the EROS Operating System. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//* References: * * 1. EtherLink(r) III Parallel Tasking(tm) ISA, EISA, Micro * Channel(r), and PCMCIA Adapter Drivers Technical Reference * * The current version of the driver has been tested only on 3c590XL. */#include <kerninc/kernel.hxx>#include <kerninc/Process.hxx>#include <kerninc/Invocation.hxx>#include <kerninc/AutoConf.hxx>#include <kerninc/IntAction.hxx>#include <kerninc/IRQ.hxx>#include <kerninc/Machine.hxx>#include <kerninc/Thread.hxx>#include <kerninc/NetInterface.hxx>#include <kerninc/IoRegion.hxx>#include <kerninc/PhysMem.hxx>#include <kerninc/PCI.hxx>#include <kerninc/PCI-def.hxx>#include <eros/Device.h>#include <io.h>#include <eros/Invoke.h>#include <eros/memory.h>#include <eros/machine/endian.h>#include <kerninc/MsgLog.hxx>#include <kerninc/util.h>#include <arch-kerninc/Process.hxx>/* for fine-grain timing: */#include <../kernel/lostart.hxx>#define BOOMERANG/* #define USE_RX_RING *//* #define ENET_DEBUG * #define VERBOSE *//* The min/max packet sizes at the ethernet level are dictated by wire * timing, and are entirely independent of the encapsulation (RFC984 * v/s IEEE 802.2/802.3. Both sizes exclude the CRC field, which is * automatically generated by the hardware (or if necessary by the * driver). * * The true min packet size for ethernet, excluding CRC field, is 60 bytes * The true max packet size for ethernet, excluding CRC field, is 1514 bytes. * */#define MIN_ENET_PACKET_SZ 0X3C#define MAX_ENET_PACKET_SZ 0x05ea#define TX_FIFO_THRESH MAX_ENET_PACKET_SZ + 4 + 2static bool Probe(AutoConf *ac);static bool Attach(AutoConf *ac);struct Driver ac_3c59x = { "3c59x", Probe, Attach} ;/* THEORY OF OPERATION: * * * The 3c59x is a true bus-mastering card. Given half a chance, it * will contrive to do it's own DMA to/from memory. In general, we * wish to avoid marginal copy overhead by transferring the data * directly from/to the user-supplied buffer. This complicates * things, as it imposes restrictions on alignment and forces us to * make tradeoffs regarding interrupt cost and copy cost. * * *** Alignment * * One problem with this is that the hardware requires the packet to * be a multiple of 4 bytes (zero padded if necessary), while the * enet spec allows the packet to be any desired length between min * and max. * * On the receive side, we therefore require that the user-supplied * buffer by aligned to a 32 bit boundary and ALSO multiple of 32 * bits. This allows us to accept the padding bytes from the card * directly into the buffer and then report the true length to the * caller. * * On the send side, we need to cope with short packets. The options * would appear to be one of the following: * * 1. Require the sent packet to be 32-bit aligned, handle the * trailing bytes specially by copying if necessary. * * 2. Require the sent packet buffer to be BOTH 32-bit aligned and a * multiple of 32-bits, obtaining the true packet length by * parsing the outbound packet. Unfortunately, this * requires the driver to do some parsing to determine if this is * an RFC894 packet or an IEEE 802.2/802.3 packet, so that is * not a preferred solution. * * 3. Require the sent packet buffer to be BOTH 32-bit aligned and a * 32-bit multiple, with the length prepended to the buffer. * * There is a tradeoff here, as the marginal interrupt may cost more * than making the extra copy. * * *** Normal State * * Under normal operating conditions, the cards are left in register * window *7*. This window holds all of the registers that are critical * to normal operation. Some supporting routines adjust the * registers, but these are always careful to switch them back. * * *** To Copy or Not To Copy * * Assuming that the packet is suitably aligned, we have the option of * letting the card handle the DMA via it's bus-mastering feature. * Taking a simplistic view, we can simply pin the pages of the reader * (writer) in memory, mark the pages as "I/O involved", and de-pin * them when we get the completion interrupt. * * If the user buffer is mis-aligned, we have something of a problem, * because the DMA engine on this card requires that the buffer be * aligned to a 64 bit boundary. For the moment, strictly to keep * things simple, we require that the packet address supplied by the * user be quadword aligned. If it is not, we return RC_RequestError. * The present driver will pin a maximum of two pages per request, to * allow the packet buffer to cross a page boundary. * * Note that pinning a buffer does NOT prevent the user from modifying * it out from under us or from colliding with driver writes. This is * okay. Caveat emptor! * * The current driver performs NO in-kernel buffering. Packets are * read directly into the user-provided buffer. Indeed, we do not * even bother to enable RX interrupts unless somebody goes to read a * packet and discovers the RX FIFO to be empty. This tends to give * us the best advantages of polling v/s interrupts, PROVIDED that the * RX FIFO is deep enough relative to the poll rate. * * On the 10 Mbit cards, we get away with this because it takes a * relatively long time for the RX FIFO to overflow. On the 100 Mbit * cards, I am concerned that the RX FIFO is in fact NOT deep enough, * in which case we may be forced to do something. Some possible * options: * * 1. Introduce a packet multiread operation. This is certainly the * first thing to attempt. * * 2. Extend the fifo into the kernel, eating the associated memory * overhead. * * 3. Export a kernel buffer to user land, raising risk of kernel * compromise by queue mishandling. * * 4. Have multiple packet readers in action simultaneously, and pin * their pages in memory. * * My basic view is to do the simple thing first and see how it goes. */#define MEDIA_AUTODETECT 1/* #define VORTEX_BUS_MASTER */#define TX_RING_SIZE 16#define RX_RING_SIZE 16#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*//* Set the copy breakpoint for the copy-only-tiny-frames scheme. Setting to > 1512 effectively disables this feature. */#define RX_COPYBREAK 200/* Number of times to check to see if the Tx FIFO has space, used in some limited cases. */#define WAIT_TX_AVAIL 200static struct { uint16_t prodId; uint8_t ioSize; uint32_t defaultOptions; char * name;} product_info[] = { { PCI_DEVICE_ID_3COM_3C590, 0x20, UINT32_MAX, "3c590 Vortex 10Mbps" }, { PCI_DEVICE_ID_3COM_3C595TX, 0x20, UINT32_MAX, "3c595 Vortex 100baseTX" }, { PCI_DEVICE_ID_3COM_3C595T4, 0x20, UINT32_MAX, "3c595 Vortex 100baseT4" }, { PCI_DEVICE_ID_3COM_3C595MII, 0x20, UINT32_MAX, "3c595 Vortex 100base-MII" }, { PCI_DEVICE_ID_3COM_3C900, 0x40, UINT32_MAX, "3c900 Boomerang 10baseT" }, { PCI_DEVICE_ID_3COM_3C900Combo, 0x40, UINT32_MAX, "3c900 Boomerang 10Mbps/Combo" }, { PCI_DEVICE_ID_3COM_3C905TX, 0x40, UINT32_MAX, "3c905 Boomerang 100baseTx" }, { PCI_DEVICE_ID_3COM_3C905T4, 0x40, UINT32_MAX, "3c905 Boomerang 100baseT4" }, { 0, 0x20, UINT32_MAX, "3c592 EISA 10mbps Demon/Vortex"}, { 0, 0x20, UINT32_MAX, "3c597 EISA Fast Demon/Vortex" },}; /* Register window offsets */enum { El3Cmd = 0xe, /* common to all windows */ El3Status = 0xe, /* BYTE value */#if 0 El3Window = 0xf, /* BYTE value */ El3EepromData = 0xc, El3EepromCmd = 0xa, El3RsrcConfig = 0x8, El3AddrConfig = 0x6, El3ConfigCtrl = 0x4, El3ProductId = 0x2, El3ManufacturerID = 0x0,#endif} ;enum { GlobalReset = 0u << 11, SelectWindow = 1u << 11, StartCoax = 2u << 11, RxDisable = 3u << 11, RxEnable = 4u << 11, RxReset = 5u << 11, UpStall = 6u << 11, UpUnstall = (6u << 11) + 1, DownStall = (6u << 11) + 2, DownUnstall = (6u << 11) + 3, RxDiscard = 8u << 11, TxEnable = 9u << 11, TxDisable = 10u << 11, TxReset = 11u << 11, ReqIntr = 12u << 11, AckIntr = 13u << 11, SetIntrMask = 14u << 11, SetStatusMask = 15u << 11, SetRxFilter = 16u << 11, SetRxThresh = 17u << 11, /* RX Early Threshold */ SetTxAvailThresh = 18u << 11, /* TX Available Threshold */ SetTxStartThresh = 19u << 11, SetDmaUp = 20u << 11, StartDmaDown = (20u << 11) + 1, StatsEnable = 21u << 11, StatsDisable = 22u << 11, StopCoax = 23u << 11,#if 0 SetTxReclaimThresh = 24u << 11, PowerUp = 27u << 11, /* 3c509b, 3c589b */ PowerDownFull = 28u << 11, /* 3c509b, 3c589b */ PowerAuto = 29u << 11, /* 3c509b, 3c589b */#endif};/* Commands: * Set RX filter command args: */enum { RxIndividual = 0x1, RxMulticast = 0x2, RxBroadcast = 0x4, RxPromisc = 0x8,};/* Status register bits: */enum {#if 0 CurWindow = 0xE000, /* current window number */#endif /* Intervening bits are reserved */ CmdInProgress= 0x1000, DmaInProgress= 0x0800, UpComplete = 0x0400, DownComplete = 0x0200, DmaDone = 0x0100, UpdateStats = 0x0080, /* generates interrupt when set if not masked */ IntRequested = 0x0040, /* generates interrupt when set if not masked */ RxEarly = 0x0020, /* generates interrupt when set if not masked */ RxComplete = 0x0010, /* generates interrupt when set if not masked */ TxAvail = 0x0008, /* generates interrupt when set if not masked */ TxComplete = 0x0004, /* generates interrupt when set if not masked */ AdapterFail = 0x0002, /* generates interrupt when set if not masked */ IntLatch = 0x0001,};/* RX Status register values: (16-bit register) */enum { RxsIncomplete = 0x8000u, /* incomplete RX packet */ RxsError = 0x4000, /* error in RX packet */ Rxsuint8_ts = 0x1fff, /* RX packet len, excluding padding */#if 0 /* Only on 3c509!!! * RX Error Type values: */ RxsOverrun = 0x0u << 11, RxsOversize = 0x1u << 11, /* oversize packet (> 1514 bytes) */ RxsDribble = 0x2u << 11, /* The trouble with dribbles... */ RxsRunt = 0x3u << 11, /* small packet */ RxsAlignment = 0x4u << 11, /* framing error */ RxsCRC = 0x5u << 11,#endif};/* TX Status register values: (8-bit register) */enum { TxsComplete = 0x80, TxsIntReq = 0x40, /* interrupt on completion requested */ TxsJabber = 0x20, /* jabber error -- TP only; TX Reset required */ TxsUnderrun = 0x10, /* TX Reset required */ TxsCollisions = 0x08, /* Maximum collisions */ TxsStatusOverflow = 0x04, TxsReclaim = 0x02, /* MCA only; else undefined */ /* bit 0 undefined */};/* Window 0 offsets: */enum { Wn0EepromCmd = 0x0a, Wn0EepromData = 0x0c,};enum Win0_EEPROM_bits { EEPROM_Read = 0x80, EEPROM_WRITE = 0x40, EEPROM_ERASE = 0xC0, EEPROM_EWENB = 0x30, /* Enable erasing/writing for 10 msec. */ EEPROM_EWDIS = 0x00, /* Disable EWENB before 10 msec timeout. */};/* EEPROM locations. */enum eeprom_offset { PhysAddr01=0, PhysAddr23=1, PhysAddr45=2, ModelID=3, EtherLink3ID=7,};/* Window 1 offsets -- on vortex, Window 1 is always visible in the * extended I/O space. */enum { Wn1RxStatus = 0x18, Wn1Timer = 0x1a, Wn1TxStatus = 0x1B, Wn1RxFifo = 0x10, Wn1TxFifo = 0x10, Wn1TxFree = 0x1c, Wn1RxErrors = 0x14,};#ifdef BOOMERANGenum { Wn1DnStatus = 0x20, Wn1DnListPtr = 0x24, Wn1DnFragAddr = 0x28, Wn1DnFragLen = 0x2C, Wn1DnListOffset = 0x23, Wn1TxFreeThresh = 0x2f, /* maybe obsolete */ Wn1UpStatus = 0x30, Wn1FreeTimer = 0x34, /* free timer register */ Wn1DownTimer = 0x36, /* count-down timer register */ Wn1UpListPtr = 0x38,};#endifenum Window3 { /* Window 3: MAC/config bits. */ Wn3Config=0, Wn3MacCtrl=6, Wn3Options=8,};enum { MacFullDuplex = 0x20,};union wn3_config { int i; struct w3_config_fields { unsigned int ram_size:3, ram_width:1, ram_speed:2, rom_size:2; int pad8:8; unsigned int ram_split:2, pad18:2, xcvr:3, pad21:1, autoselect:1; int pad24:7; } u;};/* Window 4 offsets: */enum { Wn4NetDiag = 0x06, Wn4MediaType = 0x0a,} ;enum Win4_Media_bits { Media_SQE = 0x0008, /* Enable SQE error counting for AUI. */ Media_10TP = 0x00C0, /* Enable link beat and jabber for 10baseT. */ Media_Lnk = 0x0080, /* Enable just link beat for 100TX/100FX. */ Media_LnkBeat = 0x0800,};enum Window7 { /* Window 7: Bus Master control. */ Wn7MasterAddr = 0, Wn7MasterLen = 6, Wn7MasterStatus = 12,};/* Boomerang bus master control registers. */enum MasterCtrl { PktStatus = 0x20, DownListPtr = 0x24, FragAddr = 0x28, FragLen = 0x2c, TxFreeThreshold = 0x2f, UpPktStatus = 0x30, UpListPtr = 0x38,};/* The Rx and Tx descriptor lists. Caution Alpha hackers: these types are 32 bits! Note also the 8 byte
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -