⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 net_3c509.cxx

📁 C++ 编写的EROS RTOS
💻 CXX
📖 第 1 页 / 共 4 页
字号:
/* * 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 3c509 and * 3c509b.  If anyone has a PCMCIA card out there to test with, I'll * be glad to help debug it.  We do not support MCA bus at * the moment, though the probes are stubbed properly.  The EISA bus * code is untested, but should work okay. */#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 <eros/Device.h>#include <io.h>#include <eros/Invoke.h>#include <eros/memory.h>#include <kerninc/MsgLog.hxx>#include <kerninc/util.hxx>/* for fine-grain timing: */#include <../kernel/lostart.hxx>/* #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. *  * In general, we wish to copy the data directly from/to the * user-supplied buffer.  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. *  * NEWS FLASH *  * sjmuir points out that the important issue from the software side * is not whether the ethernet PACKET is aligned, but whether the * ethernet PAYLOAD is aligned.  In particular, the ethernet packet * header is 14 bytes, which leaves the payload at a 16-bit boundary. * Given this, we decided that the interface should be prepared to * hand back packets in the following form: *  *             <- 16 -> *            +--------+ *            |        | *      +-----+        | *      |              | *      ~              ~ *      |              | *      +--------------+ *       <-    32    -> *  * The major gotcha with this is that one must be careful about * trailing packet bytes.  If the end of the packet falls across a * page boundary, one cannot safely read beyond the end of the packet * to obtain pad bytes. *  * After some cursing and muttering about this I resolved that the * damn thing should just be alignment insensitive, and should do the * right thing to ensure that it does NOT violate a page boundary. *  */#define	MIN_ENET_PACKET_SZ   0X3C#define MAX_ENET_PACKET_SZ   0x05ea#define TX_FIFO_THRESH MAX_ENET_PACKET_SZ + 4 + 2DEFMODULE(3c509, Probe, AutoAttach, "3c509 Interrupt");/* THEORY OF OPERATION: *  * The 3c509 is capable of some fairly serious autoconfiguration, even * in the absence of Plug And Play.  [Note: The current driver assumes * that no Plug and Play support exists in the kernel -- it will need * to be (slightly) revised when Plug and Play becomes a factor]. * Unlike most ISA devices, it is capable of being left in a * "detached" state. *  * The probe phase of this driver simply builds the equipment list. * It inquires of each card what it's desired io port address, ROM * address, and IRQ line are.  It tags each card so that it can be * activated later, but leaves the card UNACTIVATED.  In the * unactivated state, the card can pretty much be relied on to leave * us alone. *  *  * For reasons of (SHORT LIVED) compatibility with existing code that * assumes the old driver design, this driver has an auto-activate * phase.  The auto-activate phase simply configures each card at it's * default configured address.  Conceptually, the card attachment * should be done from user level using a device key. *  *  * Contention resolution for the 3c509 is done using a single global * ID port. [Note: there is a disagreement in the documentation * concerning the ID PORT.  In one statement, it says that the ID PORT * is remembered by the card.  In the other, it says that cards in the * ID_WAIT state remember the *last* port in the range 0x1?0 to which * a zero has been written.  If this is the case, the ID PORT need not * be a global variable at all.  Until I have an opportunity to test * it, I don't intend to make assumptions.] *  * The 3c509 ID PORT is (regrettably) global.  It is set during the * early part of the probe phase. *  *  * Under normal operating conditions, the cards are left in register * window 1.  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. *  * There is a (necessary) race condition between the read/write packet * routines and the interrupt handler.  This is resolved by disabling * the etherlink interrupt during read/write. */static uint16_t id_port = 0x100;#define MANU_3COM   0x6d50#define tagValue devInfo[0]#define rxFilter devInfo[1]#define curInts devInfo[2]/* PnP Ports/Values of interest: */enum {  PnpAddress = 0x279,  PnpWrite =   0xa79,  PnpSelConfigCtrl = 0x2,	/* select configuration control register */  ElinkSetContention = 0x0,	/* set card to run contention-based */				/* configuration  */};/* ID Port access values */enum {  IdRdEEPROM        = 0x80,  IdGlobalReset     = 0xc0,  IdSetTagReg       = 0xd0,  IdTestAdapter     = 0xd8,  IdActivate        = 0xe0,  IdActivatePreconf = 0xff,} ;#if 0#define	ID_PORT				0X0100#define	ID_PORT_GOTO_ID_WAIT		0X00#define	ID_PORT_RD_EEPROM		0X80#define	ID_PORT_GLOBAL_RESET		0XC0#define	ID_PORT_SET_TAG_REG		0XD0#define	ID_PORT_TEST_ADAPTER		0XD8#define	ID_PORT_ACTIVATE_IO_PORT	0XE0#define	ID_PORT_ACTIVATE_PRECONFIG	0XFF#endif/* Register window offsets */enum {  El3Cmd = 0xe,			/* common to all windows */  El3Status = 0xe,		/* BYTE value */  El3Window = 0xf,		/* BYTE value */  El3EepromData = 0xc,  El3EepromCmd = 0xa,  El3RsrcConfig = 0x8,  El3AddrConfig = 0x6,  El3ConfigCtrl = 0x4,  El3ProductId = 0x2,  El3ManufacturerID = 0x0,} ;/* Window 0 offsets: */enum {  Wn0Irq = 0x08,  Wn0ConfigCtrl = 0x04,};/* Window 1 offsets: */enum {  Wn1RxStatus   = 0x08,  Wn1TxStatus   = 0x0B,  Wn1Rxuint8_tFifo = 0x00,  Wn1RxFifo     = 0x00,  Wn1Txuint8_tFifo = 0x00,  Wn1TxFifo     = 0x00,  Wn1TxFree     = 0x0c,  Wn1Timer      = 0x0a,};/* Window 4 offsets: */enum {  Wn4MediaType   = 0x0a,} ;/* Window 5 offsets: */enum {  Wn5IntMask      = 0x0a,  Wn5StatusMask   = 0x0c,} ;/* Media status bits: */enum {  MediaStatusLK  = 0x80,	/* link beat enable (TP) */  MediaStatusJE  = 0x40,	/* Jabber Enable */} ;#define EISA_WINREG(base, x) ((base) + 0xc80 + (x))/* Commands: */enum {  GlobalReset        = 0u  << 11,  SelectWindow       = 1u  << 11,  StartCoax          = 2u  << 11,  RxDisable          = 3u  << 11,  RxEnable           = 4u  << 11,  RxReset            = 5u  << 11,  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,  StatsEnable        = 21u << 11,  StatsDisable       = 22u << 11,  StopCoax           = 23u << 11,  SetTxReclaimThresh = 24u << 11,  PowerUp            = 27u << 11, /* 3c509b, 3c589b */  PowerDownFull      = 28u << 11, /* 3c509b, 3c589b */  PowerAuto          = 29u << 11, /* 3c509b, 3c589b */};/* Set RX filter command args: */enum {  RxIndividual = 0x1,  RxMulticast  = 0x2,  RxBroadcast  = 0x4,  RxPromisc    = 0x8,};/* Status register bits: */enum {  CurWindow    = 0xE000,	/* current window number */  /* Intervening bits are reserved */  InProgress   = 0x1000,  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 */  RxsErrType    = 0x3800,	/* mask to fetch error type */  Rxsuint8_ts      = 0x07ff,	/* RX packet len, excluding padding */  /* 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,};/* 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 */};/* Bit values for the internal configuration register: */enum {  IsaActivateMask       = 0x3u << 18,  IsaActivatePnP        = 0x2u << 18,  IsaActivateContention = 0x1u << 18,  IsaActivateBoth       = 0x0u << 18,  /* Following describe how the FIFO ram should be divvied up between   * TX and RX FIFO -- ratios are TX::RX.  Defaults to 1:1   */  Ram_3to5               = 0x0u << 16,/* ram size must be 000b */  Ram_1to3               = 0x1u << 16,/* ram size must be 000b */  Ram_1to1               = 0x2u << 16,  RamSpeed2              = 0x0u << 4, /* don't mess with this! */  RamSize8k              = 0x0u,  RamSize32k             = 0x2u,  AddrCfgXcvr            = 0xc000,  XcvrTwistedPair        = 0x0,  XcvrAUI                = 0x1,  XcvrReserved           = 0x2,  XcvrBNC                = 0x3,  RsrcCfgIrq             = 0xf000,  AddrCfgIoBase          = 0x001f,} ;static void Invoke(NetInterface *, Invocation& inv); /* FORWARD */#if 0static void TxPacket(NetInterface *); /* FORWARD */#endifstatic void RxPacket(NetInterface *); /* FORWARD */static void ReadPacket(NetInterface *ni, Invocation& inv); /* FORWARD */static void WritePacket(NetInterface *ni, Invocation& inv); /* FORWARD */static void MultiReadPacket(NetInterface *ni, Invocation& inv); /* FORWARD */#if 0static void MultiWritePacket(NetInterface *ni, Invocation& inv); /* FORWARD */#endifstatic void Enable(NetInterface *); /* FORWARD */static void UpdateStatistics(NetInterface *); /* FORWARD */static void HandleInterrupt(NetInterface *); /* FORWARD */static void HandleInterrupt(IntAction *); /* FORWARD */inline voidOutCmd(NetInterface *ni, uint16_t cmd, bool andWait = false){  out16(cmd, ni->ioAddr + El3Cmd);  if (andWait)    while (in16(ni->ioAddr + El3Status) & InProgress)      ;}inline voidSetWindow(NetInterface* ni, int whichWindow){  OutCmd(ni, SelectWindow | whichWindow);}#ifdef CONFIG_EISA/* Assumes we are in window 0; */static uint16_tReadEEPROM(uint32_t iobase, uint32_t offset){  out16(IdRdEEPROM + offset, iobase + El3EepromCmd);	  /* EEPROM requires 162 usec stall: */  Machine::SpinWaitMs(1);  return inh(iobase + El3EepromData);}#endif/* Read a word from the EEPROM via the ID port. */static uint16_tIsaIdRdEEPROM(uint16_t id_port, uint32_t offset){  /* Issue read command, and pause for at least 162 us. for it to complete.     Assume extra-fast 16Mhz bus. */  out8(IdRdEEPROM + offset, id_port);  /* Pause for at least 162 us. for the read to take place. */  Machine::SpinWaitMs(1);	/* let things settle */    /* Read 16-bit value from ID Port. */  uint16_t temp = 0;  for (uint8_t loop = 0; loop < 16; loop++)    temp = (temp << 1) + (inb(id_port) & 0x1);  return temp;}inline voidEISA_Probe(AutoConf * ac){#ifdef CONFIG_EISA  /* Check all slots of the EISA bus. */  for (uint32_t ioaddr = 0x1000; ioaddr < 0x9000; ioaddr++) {    if (inh(EISA_WINREG(ioaddr, El3ManufacturerID)) != MANU_3COM)      continue;    ac->present = true;    /* Switch to Window 0 -- this might be a reboot, so the state     * is not necessarily known.     */    outh(EISA_WINREG(ioaddr, El3Cmd), SelectWindow);    uint16_t irq = inh(EISA_WINREG(ioaddr, Wn0Irq)) >> 12;    NetInterface *ni = NetInterface::Alloc();    ni->irq = irq;    ni->ioAddr = ioaddr;    ni->ioLen = 0x0f;    ni->addr = 0;    ni->len = 0;    ni->xcvr = (inh(ioaddr + 6) & AddrCfgXcvr) >> 14;    ni->name = "EtherLink III (EISA)";    ni->devClass = DEV_NET_ENET;    ni->updateStats = UpdateStatistics;    for (int i = 0; i < 3; i++) {      uint16_t hw = ReadEEPROM(ioaddr, i);      ni->linkAddr[i*2] = (hw >> 8) & 0xffu;      ni->linkAddr[ i*2 + 1 ] = hw & 0xffu;    }    /* Drop the product ID back in the EEPROM register: */    ReadEEPROM(ioaddr, 3);  }#else  /* This will peephole out -- it suppresses a compiler warning. */  ac->present = ac->present;#endif}inline voidMCA_Probe(AutoConf * ac){#ifdef CONFIG_MCA#else  /* This will peephole out -- it suppresses a compiler warning. */  ac->present = ac->present;#endif}#define ioport_isavail(x) truestatic void IdentifySequence(){  /* Lock down the ID PORT, in case that was reset - harmless if the   * card is in the ID_WAIT state.   */  out8(0x0, id_port);  Machine::SpinWaitMs(1);	/* let things settle */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -