📄 3c90x.c
字号:
/* * 3c90x.c -- This file implements the 3c90x driver for etherboot. Written * by Greg Beeley, Greg.Beeley@LightSys.org. Modified by Steve Smith, * Steve.Smith@Juno.Com * * This program Copyright (C) 1999 LightSys Technology Services, Inc. * Portions Copyright (C) 1999 Steve Smith * * This program may be re-distributed in source or binary form, modified, * sold, or copied for any purpose, provided that the above copyright message * and this text are included with all source copies or derivative works, and * provided that the above copyright message and this text are included in the * documentation of any binary-only distributions. This program is distributed * WITHOUT ANY WARRANTY, without even the warranty of FITNESS FOR A PARTICULAR * PURPOSE or MERCHANTABILITY. Please read the associated documentation * "3c90x.txt" before compiling and using this driver. * * -------- * * Program written with the assistance of the 3com documentation for * the 3c905B-TX card, as well as with some assistance from the 3c59x * driver Donald Becker wrote for the Linux kernel, and with some assistance * from the remainder of the Etherboot distribution. * * REVISION HISTORY: * * v0.10 1-26-1998 GRB Initial implementation. * v0.90 1-27-1998 GRB System works. * v1.00pre1 2-11-1998 GRB Got prom boot issue fixed. * v2.0 9-24-1999 SCS Modified for 3c905 (from 3c905b code) * Re-wrote poll and transmit for * better error recovery and heavy * network traffic operation * */#include "etherboot.h"#include "nic.h"#include "pci.h"#include "cards.h"#include "timer.h"#define XCVR_MAGIC (0x5A00)/** any single transmission fails after 16 collisions or other errors ** this is the number of times to retry the transmission -- this should ** be plenty **/#define XMIT_RETRIES 250#undef virt_to_bus#define virt_to_bus(x) ((unsigned long)x)/*** Register definitions for the 3c905 ***/enum Registers { regPowerMgmtCtrl_w = 0x7c, /** 905B Revision Only **/ regUpMaxBurst_w = 0x7a, /** 905B Revision Only **/ regDnMaxBurst_w = 0x78, /** 905B Revision Only **/ regDebugControl_w = 0x74, /** 905B Revision Only **/ regDebugData_l = 0x70, /** 905B Revision Only **/ regRealTimeCnt_l = 0x40, /** Universal **/ regUpBurstThresh_b = 0x3e, /** 905B Revision Only **/ regUpPoll_b = 0x3d, /** 905B Revision Only **/ regUpPriorityThresh_b = 0x3c, /** 905B Revision Only **/ regUpListPtr_l = 0x38, /** Universal **/ regCountdown_w = 0x36, /** Universal **/ regFreeTimer_w = 0x34, /** Universal **/ regUpPktStatus_l = 0x30, /** Universal with Exception, pg 130 **/ regTxFreeThresh_b = 0x2f, /** 90X Revision Only **/ regDnPoll_b = 0x2d, /** 905B Revision Only **/ regDnPriorityThresh_b = 0x2c, /** 905B Revision Only **/ regDnBurstThresh_b = 0x2a, /** 905B Revision Only **/ regDnListPtr_l = 0x24, /** Universal with Exception, pg 107 **/ regDmaCtrl_l = 0x20, /** Universal with Exception, pg 106 **/ /** **/ regIntStatusAuto_w = 0x1e, /** 905B Revision Only **/ regTxStatus_b = 0x1b, /** Universal with Exception, pg 113 **/ regTimer_b = 0x1a, /** Universal **/ regTxPktId_b = 0x18, /** 905B Revision Only **/ regCommandIntStatus_w = 0x0e, /** Universal (Command Variations) **/ };/** following are windowed registers **/enum Registers7 { regPowerMgmtEvent_7_w = 0x0c, /** 905B Revision Only **/ regVlanEtherType_7_w = 0x04, /** 905B Revision Only **/ regVlanMask_7_w = 0x00, /** 905B Revision Only **/ };enum Registers6 { regBytesXmittedOk_6_w = 0x0c, /** Universal **/ regBytesRcvdOk_6_w = 0x0a, /** Universal **/ regUpperFramesOk_6_b = 0x09, /** Universal **/ regFramesDeferred_6_b = 0x08, /** Universal **/ regFramesRecdOk_6_b = 0x07, /** Universal with Exceptions, pg 142 **/ regFramesXmittedOk_6_b = 0x06, /** Universal **/ regRxOverruns_6_b = 0x05, /** Universal **/ regLateCollisions_6_b = 0x04, /** Universal **/ regSingleCollisions_6_b = 0x03, /** Universal **/ regMultipleCollisions_6_b = 0x02, /** Universal **/ regSqeErrors_6_b = 0x01, /** Universal **/ regCarrierLost_6_b = 0x00, /** Universal **/ };enum Registers5 { regIndicationEnable_5_w = 0x0c, /** Universal **/ regInterruptEnable_5_w = 0x0a, /** Universal **/ regTxReclaimThresh_5_b = 0x09, /** 905B Revision Only **/ regRxFilter_5_b = 0x08, /** Universal **/ regRxEarlyThresh_5_w = 0x06, /** Universal **/ regTxStartThresh_5_w = 0x00, /** Universal **/ };enum Registers4 { regUpperBytesOk_4_b = 0x0d, /** Universal **/ regBadSSD_4_b = 0x0c, /** Universal **/ regMediaStatus_4_w = 0x0a, /** Universal with Exceptions, pg 201 **/ regPhysicalMgmt_4_w = 0x08, /** Universal **/ regNetworkDiagnostic_4_w = 0x06, /** Universal with Exceptions, pg 203 **/ regFifoDiagnostic_4_w = 0x04, /** Universal with Exceptions, pg 196 **/ regVcoDiagnostic_4_w = 0x02, /** Undocumented? **/ };enum Registers3 { regTxFree_3_w = 0x0c, /** Universal **/ regRxFree_3_w = 0x0a, /** Universal with Exceptions, pg 125 **/ regResetMediaOptions_3_w = 0x08, /** Media Options on B Revision, **/ /** Reset Options on Non-B Revision **/ regMacControl_3_w = 0x06, /** Universal with Exceptions, pg 199 **/ regMaxPktSize_3_w = 0x04, /** 905B Revision Only **/ regInternalConfig_3_l = 0x00, /** Universal, different bit **/ /** definitions, pg 59 **/ };enum Registers2 { regResetOptions_2_w = 0x0c, /** 905B Revision Only **/ regStationMask_2_3w = 0x06, /** Universal with Exceptions, pg 127 **/ regStationAddress_2_3w = 0x00, /** Universal with Exceptions, pg 127 **/ };enum Registers1 { regRxStatus_1_w = 0x0a, /** 90X Revision Only, Pg 126 **/ };enum Registers0 { regEepromData_0_w = 0x0c, /** Universal **/ regEepromCommand_0_w = 0x0a, /** Universal **/ regBiosRomData_0_b = 0x08, /** 905B Revision Only **/ regBiosRomAddr_0_l = 0x04, /** 905B Revision Only **/ };/*** The names for the eight register windows ***/enum Windows { winPowerVlan7 = 0x07, winStatistics6 = 0x06, winTxRxControl5 = 0x05, winDiagnostics4 = 0x04, winTxRxOptions3 = 0x03, winAddressing2 = 0x02, winUnused1 = 0x01, winEepromBios0 = 0x00, };/*** Command definitions for the 3c90X ***/enum Commands { cmdGlobalReset = 0x00, /** Universal with Exceptions, pg 151 **/ cmdSelectRegisterWindow = 0x01, /** Universal **/ cmdEnableDcConverter = 0x02, /** **/ cmdRxDisable = 0x03, /** **/ cmdRxEnable = 0x04, /** Universal **/ cmdRxReset = 0x05, /** Universal **/ cmdStallCtl = 0x06, /** Universal **/ cmdTxEnable = 0x09, /** Universal **/ cmdTxDisable = 0x0A, /** **/ cmdTxReset = 0x0B, /** Universal **/ cmdRequestInterrupt = 0x0C, /** **/ cmdAcknowledgeInterrupt = 0x0D, /** Universal **/ cmdSetInterruptEnable = 0x0E, /** Universal **/ cmdSetIndicationEnable = 0x0F, /** Universal **/ cmdSetRxFilter = 0x10, /** Universal **/ cmdSetRxEarlyThresh = 0x11, /** **/ cmdSetTxStartThresh = 0x13, /** **/ cmdStatisticsEnable = 0x15, /** **/ cmdStatisticsDisable = 0x16, /** **/ cmdDisableDcConverter = 0x17, /** **/ cmdSetTxReclaimThresh = 0x18, /** **/ cmdSetHashFilterBit = 0x19, /** **/ };/*** Values for int status register bitmask **/#define INT_INTERRUPTLATCH (1<<0)#define INT_HOSTERROR (1<<1)#define INT_TXCOMPLETE (1<<2)#define INT_RXCOMPLETE (1<<4)#define INT_RXEARLY (1<<5)#define INT_INTREQUESTED (1<<6)#define INT_UPDATESTATS (1<<7)#define INT_LINKEVENT (1<<8)#define INT_DNCOMPLETE (1<<9)#define INT_UPCOMPLETE (1<<10)#define INT_CMDINPROGRESS (1<<12)#define INT_WINDOWNUMBER (7<<13)/*** TX descriptor ***/typedef struct { unsigned int DnNextPtr; unsigned int FrameStartHeader; unsigned int HdrAddr; unsigned int HdrLength; unsigned int DataAddr; unsigned int DataLength; } TXD;/*** RX descriptor ***/typedef struct { unsigned int UpNextPtr; unsigned int UpPktStatus; unsigned int DataAddr; unsigned int DataLength; } RXD;/*** Global variables ***/static struct { unsigned char isBrev; unsigned char CurrentWindow; unsigned int IOAddr; unsigned char HWAddr[ETH_ALEN]; TXD TransmitDPD; RXD ReceiveUPD; } INF_3C90X;/*** a3c90x_internal_IssueCommand: sends a command to the 3c90x card ***/static inta3c90x_internal_IssueCommand(int ioaddr, int cmd, int param) { unsigned int val; /** Build the cmd. **/ val = cmd; val <<= 11; val |= param; /** Send the cmd to the cmd register **/ outw(val, ioaddr + regCommandIntStatus_w); /** Wait for the cmd to complete, if necessary **/ while (inw(ioaddr + regCommandIntStatus_w) & INT_CMDINPROGRESS); return 0; }/*** a3c90x_internal_SetWindow: selects a register window set. ***/static inta3c90x_internal_SetWindow(int ioaddr, int window) { /** Window already as set? **/ if (INF_3C90X.CurrentWindow == window) return 0; /** Issue the window command. **/ a3c90x_internal_IssueCommand(ioaddr, cmdSelectRegisterWindow, window); INF_3C90X.CurrentWindow = window; return 0; }/*** a3c90x_internal_ReadEeprom - read data from the serial eeprom. ***/static unsigned shorta3c90x_internal_ReadEeprom(int ioaddr, int address) { unsigned short val; /** Select correct window **/ a3c90x_internal_SetWindow(INF_3C90X.IOAddr, winEepromBios0); /** Make sure the eeprom isn't busy **/ while((1<<15) & inw(ioaddr + regEepromCommand_0_w)); /** Read the value. **/ outw(address + ((0x02)<<6), ioaddr + regEepromCommand_0_w); while((1<<15) & inw(ioaddr + regEepromCommand_0_w)); val = inw(ioaddr + regEepromData_0_w); return val;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -