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