15b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* rtl8139.c - etherboot driver for the Realtek 8139 chipset 25b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 35b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project ported from the linux driver written by Donald Becker 45b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project by Rainer Bawidamann (Rainer.Bawidamann@informatik.uni-ulm.de) 1999 55b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 65b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project This software may be used and distributed according to the terms 75b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project of the GNU Public License, incorporated herein by reference. 85b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 95b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project changes to the original driver: 105b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project - removed support for interrupts, switching to polling mode (yuck!) 115b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project - removed support for the 8129 chip (external MII) 125b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 135b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project*/ 145b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 155b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/*********************************************************************/ 165b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* Revision History */ 175b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/*********************************************************************/ 185b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 195b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* 205b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 215b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 06 Apr 2001 ken_yap@users.sourceforge.net (Ken Yap) 225b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project Following email from Hyun-Joon Cha, added a disable routine, otherwise 235b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project NIC remains live and can crash the kernel later. 245b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 255b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 4 Feb 2000 espenlaub@informatik.uni-ulm.de (Klaus Espenlaub) 265b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project Shuffled things around, removed the leftovers from the 8129 support 275b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project that was in the Linux driver and added a bit more 8139 definitions. 285b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project Moved the 8K receive buffer to a fixed, available address outside the 295b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 0x98000-0x9ffff range. This is a bit of a hack, but currently the only 305b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project way to make room for the Etherboot features that need substantial amounts 315b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project of code like the ANSI console support. Currently the buffer is just below 325b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 0x10000, so this even conforms to the tagged boot image specification, 335b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project which reserves the ranges 0x00000-0x10000 and 0x98000-0xA0000. My 345b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project interpretation of this "reserved" is that Etherboot may do whatever it 355b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project likes, as long as its environment is kept intact (like the BIOS 365b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project variables). Hopefully fixed rtl_poll() once and for all. The symptoms 375b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project were that if Etherboot was left at the boot menu for several minutes, the 385b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project first eth_poll failed. Seems like I am the only person who does this. 395b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project First of all I fixed the debugging code and then set out for a long bug 405b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project hunting session. It took me about a week full time work - poking around 415b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project various places in the driver, reading Don Becker's and Jeff Garzik's Linux 425b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project driver and even the FreeBSD driver (what a piece of crap!) - and 435b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project eventually spotted the nasty thing: the transmit routine was acknowledging 445b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project each and every interrupt pending, including the RxOverrun and RxFIFIOver 455b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project interrupts. This confused the RTL8139 thoroughly. It destroyed the 465b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project Rx ring contents by dumping the 2K FIFO contents right where we wanted to 475b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project get the next packet. Oh well, what fun. 485b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 495b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 18 Jan 2000 mdc@thinguin.org (Marty Connor) 505b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project Drastically simplified error handling. Basically, if any error 515b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project in transmission or reception occurs, the card is reset. 525b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project Also, pointed all transmit descriptors to the same buffer to 535b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project save buffer space. This should decrease driver size and avoid 545b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project corruption because of exceeding 32K during runtime. 555b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 565b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 28 Jul 1999 (Matthias Meixner - meixner@rbg.informatik.tu-darmstadt.de) 575b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project rtl_poll was quite broken: it used the RxOK interrupt flag instead 585b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project of the RxBufferEmpty flag which often resulted in very bad 595b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project transmission performace - below 1kBytes/s. 605b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 615b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project*/ 625b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 635b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#include "etherboot.h" 645b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#include "nic.h" 655b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#include "pci.h" 665b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#include "cards.h" 675b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#include "timer.h" 685b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 695b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define RTL_TIMEOUT (1*TICKS_PER_SEC) 705b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 715b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* PCI Tuning Parameters 725b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project Threshold is bytes transferred to chip before transmission starts. */ 735b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */ 745b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define RX_FIFO_THRESH 4 /* Rx buffer level before first PCI xfer. */ 755b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define RX_DMA_BURST 4 /* Maximum PCI burst, '4' is 256 bytes */ 765b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define TX_DMA_BURST 4 /* Calculate as 16<<val. */ 775b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define NUM_TX_DESC 4 /* Number of Tx descriptor registers. */ 785b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define TX_BUF_SIZE ETH_FRAME_LEN /* FCS is added by the chip */ 795b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define RX_BUF_LEN_IDX 0 /* 0, 1, 2 is allowed - 8,16,32K rx buffer */ 805b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX) 815b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 825b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#undef DEBUG_TX 835b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#undef DEBUG_RX 845b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 855b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* Symbolic offsets to registers. */ 865b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectenum RTL8139_registers { 875b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project MAC0=0, /* Ethernet hardware address. */ 885b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project MAR0=8, /* Multicast filter. */ 895b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project TxStatus0=0x10, /* Transmit status (four 32bit registers). */ 905b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project TxAddr0=0x20, /* Tx descriptors (also four 32bit). */ 915b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project RxBuf=0x30, RxEarlyCnt=0x34, RxEarlyStatus=0x36, 925b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project ChipCmd=0x37, RxBufPtr=0x38, RxBufAddr=0x3A, 935b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project IntrMask=0x3C, IntrStatus=0x3E, 945b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project TxConfig=0x40, RxConfig=0x44, 955b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project Timer=0x48, /* general-purpose counter. */ 965b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project RxMissed=0x4C, /* 24 bits valid, write clears. */ 975b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project Cfg9346=0x50, Config0=0x51, Config1=0x52, 985b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project TimerIntrReg=0x54, /* intr if gp counter reaches this value */ 995b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project MediaStatus=0x58, 1005b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project Config3=0x59, 1015b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project MultiIntr=0x5C, 1025b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project RevisionID=0x5E, /* revision of the RTL8139 chip */ 1035b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project TxSummary=0x60, 1045b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project MII_BMCR=0x62, MII_BMSR=0x64, NWayAdvert=0x66, NWayLPAR=0x68, 1055b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project NWayExpansion=0x6A, 1065b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project DisconnectCnt=0x6C, FalseCarrierCnt=0x6E, 1075b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project NWayTestReg=0x70, 1085b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project RxCnt=0x72, /* packet received counter */ 1095b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project CSCR=0x74, /* chip status and configuration register */ 1105b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project PhyParm1=0x78,TwisterParm=0x7c,PhyParm2=0x80, /* undocumented */ 1115b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* from 0x84 onwards are a number of power management/wakeup frame 1125b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * definitions we will probably never need to know about. */ 1135b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project}; 1145b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1155b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectenum ChipCmdBits { 1165b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project CmdReset=0x10, CmdRxEnb=0x08, CmdTxEnb=0x04, RxBufEmpty=0x01, }; 1175b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1185b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* Interrupt register bits, using my own meaningful names. */ 1195b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectenum IntrStatusBits { 1205b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project PCIErr=0x8000, PCSTimeout=0x4000, CableLenChange= 0x2000, 1215b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project RxFIFOOver=0x40, RxUnderrun=0x20, RxOverflow=0x10, 1225b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project TxErr=0x08, TxOK=0x04, RxErr=0x02, RxOK=0x01, 1235b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project}; 1245b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectenum TxStatusBits { 1255b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project TxHostOwns=0x2000, TxUnderrun=0x4000, TxStatOK=0x8000, 1265b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project TxOutOfWindow=0x20000000, TxAborted=0x40000000, 1275b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project TxCarrierLost=0x80000000, 1285b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project}; 1295b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectenum RxStatusBits { 1305b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project RxMulticast=0x8000, RxPhysical=0x4000, RxBroadcast=0x2000, 1315b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project RxBadSymbol=0x0020, RxRunt=0x0010, RxTooLong=0x0008, RxCRCErr=0x0004, 1325b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project RxBadAlign=0x0002, RxStatusOK=0x0001, 1335b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project}; 1345b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1355b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectenum MediaStatusBits { 1365b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project MSRTxFlowEnable=0x80, MSRRxFlowEnable=0x40, MSRSpeed10=0x08, 1375b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project MSRLinkFail=0x04, MSRRxPauseFlag=0x02, MSRTxPauseFlag=0x01, 1385b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project}; 1395b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1405b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectenum MIIBMCRBits { 1415b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project BMCRReset=0x8000, BMCRSpeed100=0x2000, BMCRNWayEnable=0x1000, 1425b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project BMCRRestartNWay=0x0200, BMCRDuplex=0x0100, 1435b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project}; 1445b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1455b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectenum CSCRBits { 1465b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project CSCR_LinkOKBit=0x0400, CSCR_LinkChangeBit=0x0800, 1475b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project CSCR_LinkStatusBits=0x0f000, CSCR_LinkDownOffCmd=0x003c0, 1485b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project CSCR_LinkDownCmd=0x0f3c0, 1495b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project}; 1505b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1515b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* Bits in RxConfig. */ 1525b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectenum rx_mode_bits { 1535b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project RxCfgWrap=0x80, 1545b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project AcceptErr=0x20, AcceptRunt=0x10, AcceptBroadcast=0x08, 1555b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project AcceptMulticast=0x04, AcceptMyPhys=0x02, AcceptAllPhys=0x01, 1565b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project}; 1575b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1585b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic int ioaddr; 1595b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic unsigned int cur_rx,cur_tx; 1605b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1615b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* The RTL8139 can only transmit from a contiguous, aligned memory block. */ 1625b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic unsigned char tx_buffer[TX_BUF_SIZE] __attribute__((aligned(4))); 1635b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1645b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* I know that this is a MEGA HACK, but the tagged boot image specification 1655b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * states that we can do whatever we want below 0x10000 - so we do! */ 1665b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* But we still give the user the choice of using an internal buffer 1675b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project just in case - Ken */ 1685b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#ifdef USE_LOWMEM_BUFFER 1695b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define rx_ring ((unsigned char *)(0x10000 - (RX_BUF_LEN + 16))) 1705b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#else 1715b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic unsigned char rx_ring[RX_BUF_LEN+16] __attribute__((aligned(4))); 1725b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#endif 1735b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1745b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstruct nic *rtl8139_probe(struct nic *nic, unsigned short *probeaddrs, 1755b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project struct pci_device *pci); 1765b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic int read_eeprom(int location); 1775b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic void rtl_reset(struct nic *nic); 1785b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic void rtl_transmit(struct nic *nic, const char *destaddr, 1795b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project unsigned int type, unsigned int len, const char *data); 1805b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic int rtl_poll(struct nic *nic); 1815b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic void rtl_disable(struct nic*); 1825b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1835b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1845b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstruct nic *rtl8139_probe(struct nic *nic, unsigned short *probeaddrs, 1855b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project struct pci_device *pci) 1865b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project{ 1875b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project int i; 1885b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project int speed10, fullduplex; 1895b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1905b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* There are enough "RTL8139" strings on the console already, so 1915b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * be brief and concentrate on the interesting pieces of info... */ 1925b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project printf(" - "); 1935b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1945b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* Mask the bit that says "this is an io addr" */ 1955b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project ioaddr = probeaddrs[0] & ~3; 1965b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1975b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project adjust_pci_device(pci); 1985b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1995b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* Bring the chip out of low-power mode. */ 2005b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outb(0x00, ioaddr + Config1); 2015b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2025b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if (read_eeprom(0) != 0xffff) { 2035b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project unsigned short *ap = (unsigned short*)nic->node_addr; 2045b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project for (i = 0; i < 3; i++) 2055b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project *ap++ = read_eeprom(i + 7); 2065b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } else { 2075b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project unsigned char *ap = (unsigned char*)nic->node_addr; 2085b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project for (i = 0; i < ETH_ALEN; i++) 2095b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project *ap++ = inb(ioaddr + MAC0 + i); 2105b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } 2115b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2125b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project speed10 = inb(ioaddr + MediaStatus) & MSRSpeed10; 2135b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project fullduplex = inw(ioaddr + MII_BMCR) & BMCRDuplex; 2145b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project printf("ioaddr %#hX, addr %! %sMbps %s-duplex\n", ioaddr, 2155b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project nic->node_addr, speed10 ? "10" : "100", 2165b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project fullduplex ? "full" : "half"); 2175b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2185b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project rtl_reset(nic); 2195b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2205b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project nic->reset = rtl_reset; 2215b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project nic->poll = rtl_poll; 2225b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project nic->transmit = rtl_transmit; 2235b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project nic->disable = rtl_disable; 2245b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2255b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project return nic; 2265b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project} 2275b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2285b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* Serial EEPROM section. */ 2295b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2305b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* EEPROM_Ctrl bits. */ 2315b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */ 2325b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define EE_CS 0x08 /* EEPROM chip select. */ 2335b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define EE_DATA_WRITE 0x02 /* EEPROM chip data in. */ 2345b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define EE_WRITE_0 0x00 2355b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define EE_WRITE_1 0x02 2365b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define EE_DATA_READ 0x01 /* EEPROM chip data out. */ 2375b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define EE_ENB (0x80 | EE_CS) 2385b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2395b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* 2405b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project Delay between EEPROM clock transitions. 2415b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project No extra delay is needed with 33Mhz PCI, but 66Mhz may change this. 2425b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project*/ 2435b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2445b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define eeprom_delay() inl(ee_addr) 2455b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2465b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* The EEPROM commands include the alway-set leading bit. */ 2475b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define EE_WRITE_CMD (5 << 6) 2485b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define EE_READ_CMD (6 << 6) 2495b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define EE_ERASE_CMD (7 << 6) 2505b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2515b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic int read_eeprom(int location) 2525b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project{ 2535b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project int i; 2545b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project unsigned int retval = 0; 2555b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project long ee_addr = ioaddr + Cfg9346; 2565b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project int read_cmd = location | EE_READ_CMD; 2575b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2585b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outb(EE_ENB & ~EE_CS, ee_addr); 2595b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outb(EE_ENB, ee_addr); 2605b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2615b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* Shift the read command bits out. */ 2625b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project for (i = 10; i >= 0; i--) { 2635b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; 2645b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outb(EE_ENB | dataval, ee_addr); 2655b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project eeprom_delay(); 2665b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outb(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); 2675b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project eeprom_delay(); 2685b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } 2695b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outb(EE_ENB, ee_addr); 2705b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project eeprom_delay(); 2715b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2725b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project for (i = 16; i > 0; i--) { 2735b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outb(EE_ENB | EE_SHIFT_CLK, ee_addr); 2745b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project eeprom_delay(); 2755b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project retval = (retval << 1) | ((inb(ee_addr) & EE_DATA_READ) ? 1 : 0); 2765b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outb(EE_ENB, ee_addr); 2775b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project eeprom_delay(); 2785b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } 2795b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2805b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* Terminate the EEPROM access. */ 2815b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outb(~EE_CS, ee_addr); 2825b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project return retval; 2835b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project} 2845b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2855b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic void rtl_reset(struct nic* nic) 2865b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project{ 2875b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project int i; 2885b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2895b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outb(CmdReset, ioaddr + ChipCmd); 2905b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2915b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project cur_rx = 0; 2925b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project cur_tx = 0; 2935b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2945b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* Give the chip 10ms to finish the reset. */ 2955b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project load_timer2(10*TICKS_PER_MS); 2965b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project while ((inb(ioaddr + ChipCmd) & CmdReset) != 0 && timer2_running()) 2975b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* wait */; 2985b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2995b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project for (i = 0; i < ETH_ALEN; i++) 3005b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outb(nic->node_addr[i], ioaddr + MAC0 + i); 3015b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3025b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* Must enable Tx/Rx before setting transfer thresholds! */ 3035b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); 3045b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outl((RX_FIFO_THRESH<<13) | (RX_BUF_LEN_IDX<<11) | (RX_DMA_BURST<<8), 3055b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project ioaddr + RxConfig); /* accept no frames yet! */ 3065b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outl((TX_DMA_BURST<<8)|0x03000000, ioaddr + TxConfig); 3075b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3085b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* The Linux driver changes Config1 here to use a different LED pattern 3095b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * for half duplex or full/autodetect duplex (for full/autodetect, the 3105b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * outputs are TX/RX, Link10/100, FULL, while for half duplex it uses 3115b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * TX/RX, Link100, Link10). This is messy, because it doesn't match 3125b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * the inscription on the mounting bracket. It should not be changed 3135b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * from the configuration EEPROM default, because the card manufacturer 3145b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * should have set that to match the card. */ 3155b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3165b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#ifdef DEBUG_RX 3175b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project printf("rx ring address is %X\n",(unsigned long)rx_ring); 3185b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#endif 3195b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outl((unsigned long)rx_ring, ioaddr + RxBuf); 3205b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3215b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* Start the chip's Tx and Rx process. */ 3225b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outl(0, ioaddr + RxMissed); 3235b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* set_rx_mode */ 3245b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outb(AcceptBroadcast|AcceptMyPhys, ioaddr + RxConfig); 3255b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* If we add multicast support, the MAR0 register would have to be 3265b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * initialized to 0xffffffffffffffff (two 32 bit accesses). Etherboot 3275b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * only needs broadcast (for ARP/RARP/BOOTP/DHCP) and unicast. */ 3285b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); 3295b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3305b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* Disable all known interrupts by setting the interrupt mask. */ 3315b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outw(0, ioaddr + IntrMask); 3325b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project} 3335b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3345b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic void rtl_transmit(struct nic *nic, const char *destaddr, 3355b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project unsigned int type, unsigned int len, const char *data) 3365b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project{ 3375b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project unsigned int status, to, nstype; 3385b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project unsigned long txstatus; 3395b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3405b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project memcpy(tx_buffer, destaddr, ETH_ALEN); 3415b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project memcpy(tx_buffer + ETH_ALEN, nic->node_addr, ETH_ALEN); 3425b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project nstype = htons(type); 3435b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project memcpy(tx_buffer + 2 * ETH_ALEN, (char*)&nstype, 2); 3445b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project memcpy(tx_buffer + ETH_HLEN, data, len); 3455b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3465b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project len += ETH_HLEN; 3475b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#ifdef DEBUG_TX 3485b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project printf("sending %d bytes ethtype %hX\n", len, type); 3495b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#endif 3505b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3515b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* Note: RTL8139 doesn't auto-pad, send minimum payload (another 4 3525b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * bytes are sent automatically for the FCS, totalling to 64 bytes). */ 3535b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project while (len < ETH_ZLEN) { 3545b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project tx_buffer[len++] = '\0'; 3555b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } 3565b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3575b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outl((unsigned long)tx_buffer, ioaddr + TxAddr0 + cur_tx*4); 3585b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outl(((TX_FIFO_THRESH<<11) & 0x003f0000) | len, 3595b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project ioaddr + TxStatus0 + cur_tx*4); 3605b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3615b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project to = currticks() + RTL_TIMEOUT; 3625b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3635b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project do { 3645b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project status = inw(ioaddr + IntrStatus); 3655b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* Only acknlowledge interrupt sources we can properly handle 3665b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * here - the RxOverflow/RxFIFOOver MUST be handled in the 3675b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * rtl_poll() function. */ 3685b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outw(status & (TxOK | TxErr | PCIErr), ioaddr + IntrStatus); 3695b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if ((status & (TxOK | TxErr | PCIErr)) != 0) break; 3705b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } while (currticks() < to); 3715b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3725b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project txstatus = inl(ioaddr+ TxStatus0 + cur_tx*4); 3735b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3745b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if (status & TxOK) { 3755b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project cur_tx = (cur_tx + 1) % NUM_TX_DESC; 3765b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#ifdef DEBUG_TX 3775b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project printf("tx done (%d ticks), status %hX txstatus %X\n", 3785b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project to-currticks(), status, txstatus); 3795b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#endif 3805b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } else { 3815b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#ifdef DEBUG_TX 3825b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project printf("tx timeout/error (%d ticks), status %hX txstatus %X\n", 3835b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project currticks()-to, status, txstatus); 3845b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#endif 3855b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project rtl_reset(nic); 3865b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } 3875b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project} 3885b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3895b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic int rtl_poll(struct nic *nic) 3905b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project{ 3915b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project unsigned int status; 3925b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project unsigned int ring_offs; 3935b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project unsigned int rx_size, rx_status; 3945b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3955b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if (inb(ioaddr + ChipCmd) & RxBufEmpty) { 3965b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project return 0; 3975b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } 3985b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3995b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project status = inw(ioaddr + IntrStatus); 4005b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* See below for the rest of the interrupt acknowledges. */ 4015b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outw(status & ~(RxFIFOOver | RxOverflow | RxOK), ioaddr + IntrStatus); 4025b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 4035b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#ifdef DEBUG_RX 4045b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project printf("rtl_poll: int %hX ", status); 4055b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#endif 4065b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 4075b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project ring_offs = cur_rx % RX_BUF_LEN; 4085b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project rx_status = *(unsigned int*)(rx_ring + ring_offs); 4095b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project rx_size = rx_status >> 16; 4105b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project rx_status &= 0xffff; 4115b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 4125b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if ((rx_status & (RxBadSymbol|RxRunt|RxTooLong|RxCRCErr|RxBadAlign)) || 4135b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project (rx_size < ETH_ZLEN) || (rx_size > ETH_FRAME_LEN + 4)) { 4145b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project printf("rx error %hX\n", rx_status); 4155b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project rtl_reset(nic); /* this clears all interrupts still pending */ 4165b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project return 0; 4175b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } 4185b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 4195b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* Received a good packet */ 4205b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project nic->packetlen = rx_size - 4; /* no one cares about the FCS */ 4215b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if (ring_offs+4+rx_size-4 > RX_BUF_LEN) { 4225b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project int semi_count = RX_BUF_LEN - ring_offs - 4; 4235b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 4245b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project memcpy(nic->packet, rx_ring + ring_offs + 4, semi_count); 4255b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project memcpy(nic->packet+semi_count, rx_ring, rx_size-4-semi_count); 4265b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#ifdef DEBUG_RX 4275b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project printf("rx packet %d+%d bytes", semi_count,rx_size-4-semi_count); 4285b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#endif 4295b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } else { 4305b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project memcpy(nic->packet, rx_ring + ring_offs + 4, nic->packetlen); 4315b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#ifdef DEBUG_RX 4325b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project printf("rx packet %d bytes", rx_size-4); 4335b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#endif 4345b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } 4355b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#ifdef DEBUG_RX 4365b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project printf(" at %X type %hhX%hhX rxstatus %hX\n", 4375b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project (unsigned long)(rx_ring+ring_offs+4), 4385b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project nic->packet[12], nic->packet[13], rx_status); 4395b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#endif 4405b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project cur_rx = (cur_rx + rx_size + 4 + 3) & ~3; 4415b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outw(cur_rx - 16, ioaddr + RxBufPtr); 4425b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* See RTL8139 Programming Guide V0.1 for the official handling of 4435b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * Rx overflow situations. The document itself contains basically no 4445b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * usable information, except for a few exception handling rules. */ 4455b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outw(status & (RxFIFOOver | RxOverflow | RxOK), ioaddr + IntrStatus); 4465b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project return 1; 4475b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project} 4485b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 4495b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic void rtl_disable(struct nic *nic) 4505b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project{ 4515b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* reset the chip */ 4525b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outb(CmdReset, ioaddr + ChipCmd); 4535b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 4545b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* 10 ms timeout */ 4555b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project load_timer2(10*TICKS_PER_MS); 4565b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project while ((inb(ioaddr + ChipCmd) & CmdReset) != 0 && timer2_running()) 4575b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* wait */; 4585b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project} 459