/* rtl8139.c - etherboot driver for the Realtek 8139 chipset
ported from the linux driver written by Donald Becker
by Rainer Bawidamann (Rainer.Bawidamann@informatik.uni-ulm.de) 1999
This software may be used and distributed according to the terms
of the GNU Public License, incorporated herein by reference.
changes to the original driver:
- removed support for interrupts, switching to polling mode (yuck!)
- removed support for the 8129 chip (external MII)
*/
/*********************************************************************/
/* Revision History */
/*********************************************************************/
/*
28 Dec 2002 ken_yap@users.sourceforge.net (Ken Yap)
Put in virt_to_bus calls to allow Etherboot relocation.
06 Apr 2001 ken_yap@users.sourceforge.net (Ken Yap)
Following email from Hyun-Joon Cha, added a disable routine, otherwise
NIC remains live and can crash the kernel later.
4 Feb 2000 espenlaub@informatik.uni-ulm.de (Klaus Espenlaub)
Shuffled things around, removed the leftovers from the 8129 support
that was in the Linux driver and added a bit more 8139 definitions.
Moved the 8K receive buffer to a fixed, available address outside the
0x98000-0x9ffff range. This is a bit of a hack, but currently the only
way to make room for the Etherboot features that need substantial amounts
of code like the ANSI console support. Currently the buffer is just below
0x10000, so this even conforms to the tagged boot image specification,
which reserves the ranges 0x00000-0x10000 and 0x98000-0xA0000. My
interpretation of this "reserved" is that Etherboot may do whatever it
likes, as long as its environment is kept intact (like the BIOS
variables). Hopefully fixed rtl_poll() once and for all. The symptoms
were that if Etherboot was left at the boot menu for several minutes, the
first eth_poll failed. Seems like I am the only person who does this.
First of all I fixed the debugging code and then set out for a long bug
hunting session. It took me about a week full time work - poking around
various places in the driver, reading Don Becker's and Jeff Garzik's Linux
driver and even the FreeBSD driver (what a piece of crap!) - and
eventually spotted the nasty thing: the transmit routine was acknowledging
each and every interrupt pending, including the RxOverrun and RxFIFIOver
interrupts. This confused the RTL8139 thoroughly. It destroyed the
Rx ring contents by dumping the 2K FIFO contents right where we wanted to
get the next packet. Oh well, what fun.
18 Jan 2000 mdc@thinguin.org (Marty Connor)
Drastically simplified error handling. Basically, if any error
in transmission or reception occurs, the card is reset.
Also, pointed all transmit descriptors to the same buffer to
save buffer space. This should decrease driver size and avoid
corruption because of exceeding 32K during runtime.
28 Jul 1999 (Matthias Meixner - meixner@rbg.informatik.tu-darmstadt.de)
rtl_poll was quite broken: it used the RxOK interrupt flag instead
of the RxBufferEmpty flag which often resulted in very bad
transmission performace - below 1kBytes/s.
*/
#include "etherboot.h"
#include "nic.h"
#include "pci.h"
#include "timer.h"
/* PCI Tuning Parameters
Threshold is bytes transferred to chip before transmission starts. */
/* Symbolic offsets to registers. */
enum RTL8139_registers {
/* from 0x84 onwards are a number of power management/wakeup frame
* definitions we will probably never need to know about. */
};
enum RxEarlyStatusBits {
};
enum ChipCmdBits {
enum IntrMaskBits {
};
/* Interrupt register bits, using my own meaningful names. */
enum IntrStatusBits {
};
enum TxStatusBits {
};
enum RxStatusBits {
};
enum MediaStatusBits {
};
enum MIIBMCRBits {
};
enum CSCRBits {
};
/* Bits in RxConfig. */
enum rx_mode_bits {
};
/* The RTL8139 can only transmit from a contiguous, aligned memory block. */
static void rtl_disable(struct dev *);
{
int i;
int addr_len;
/* There are enough "RTL8139" strings on the console already, so
* be brief and concentrate on the interesting pieces of info... */
printf(" - ");
/* Mask the bit that says "this is an io addr" */
/* Copy IRQ from PCI information */
/* Bring the chip out of low-power mode. */
for (i = 0; i < 3; i++)
printf("Cable not connected or other link failure\n");
return(0);
}
return 1;
}
/* Serial EEPROM section. */
/* EEPROM_Ctrl bits. */
/*
Delay between EEPROM clock transitions.
No extra delay is needed with 33Mhz PCI, but 66Mhz may change this.
*/
/* The EEPROM commands include the alway-set leading bit. */
{
int i;
unsigned int retval = 0;
eeprom_delay();
/* Shift the read command bits out. */
for (i = 4 + addr_len; i >= 0; i--) {
eeprom_delay();
eeprom_delay();
}
eeprom_delay();
for (i = 16; i > 0; i--) {
eeprom_delay();
eeprom_delay();
}
/* Terminate the EEPROM access. */
eeprom_delay();
return retval;
}
static const unsigned int rtl8139_rx_config =
(RX_BUF_LEN_IDX << 11) |
(RX_FIFO_THRESH << 13) |
(RX_DMA_BURST << 8);
int rx_mode;
/* !IFF_PROMISC */
}
{
int i;
cur_rx = 0;
cur_tx = 0;
/* Give the chip 10ms to finish the reset. */
/* wait */;
for (i = 0; i < ETH_ALEN; i++)
/* The Linux driver changes Config1 here to use a different LED pattern
* for half duplex or full/autodetect duplex (for full/autodetect, the
* the inscription on the mounting bracket. It should not be changed
* from the configuration EEPROM default, because the card manufacturer
* should have set that to match the card. */
#ifdef DEBUG_RX
#endif
/* If we add multicast support, the MAR0 register would have to be
* initialized to 0xffffffffffffffff (two 32 bit accesses). Etherboot
/* Start the chip's Tx and Rx process. */
/* set_rx_mode */
/* Disable all known interrupts by setting the interrupt mask. */
}
{
unsigned long txstatus;
/* nstype assignment moved up here to avoid gcc 3.0.3 compiler bug */
#ifdef DEBUG_TX
#endif
/* Note: RTL8139 doesn't auto-pad, send minimum payload (another 4
* bytes are sent automatically for the FCS, totalling to 64 bytes). */
}
do {
/* Only acknlowledge interrupt sources we can properly handle
* here - the RxOverflow/RxFIFOOver MUST be handled in the
* rtl_poll() function. */
#ifdef DEBUG_TX
printf("tx done (%d ticks), status %hX txstatus %X\n",
#endif
} else {
#ifdef DEBUG_TX
#endif
}
}
{
unsigned int status;
unsigned int ring_offs;
return 0;
}
/* There is a packet ready */
if ( ! retrieve ) return 1;
/* See below for the rest of the interrupt acknowledges. */
#ifdef DEBUG_RX
#endif
rx_status &= 0xffff;
return 0;
}
/* Received a good packet */
#ifdef DEBUG_RX
#endif
} else {
#ifdef DEBUG_RX
#endif
}
#ifdef DEBUG_RX
printf(" at %X type %hhX%hhX rxstatus %hX\n",
#endif
/* See RTL8139 Programming Guide V0.1 for the official handling of
* Rx overflow situations. The document itself contains basically no
* usable information, except for a few exception handling rules. */
return 1;
}
{
unsigned int mask;
/* Bit of a guess as to which interrupts we should allow */
switch ( action ) {
case DISABLE :
case ENABLE :
break;
case FORCE :
/* Apparently writing a 1 to this read-only bit of a
* read-only and otherwise unrelated register will
* force an interrupt. If you ever want to see how
* not to write a datasheet, read the one for the
* RTL8139...
*/
break;
}
}
{
/* merge reset and disable */
/* reset the chip */
/* 10 ms timeout */
/* wait */;
}
};
.type = NIC_DRIVER,
.name = "RTL8139",
.probe = rtl8139_probe,
.ids = rtl8139_nics,
.class = 0,
};