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
+ variables). Hopefully fixed rtl8139_recv() 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
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
+ rtl8139_recv 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.
static int rtl8139_probe(struct eth_device *dev, bd_t *bis);
static int rtl8139_read_eeprom(unsigned int location, unsigned int addr_len);
static void rtl8139_reset(struct eth_device *dev);
-static int rtl_transmit(struct eth_device *dev, void *packet, int length);
-static int rtl_poll(struct eth_device *dev);
-static void rtl_disable(struct eth_device *dev);
+static int rtl8139_send(struct eth_device *dev, void *packet, int length);
+static int rtl8139_recv(struct eth_device *dev);
+static void rtl8139_stop(struct eth_device *dev);
static int rtl_bcast_addr(struct eth_device *dev, const u8 *bcast_mac, int join)
{
return (0);
dev->priv = (void *) devno;
dev->iobase = (int)bus_to_phys(iobase);
dev->init = rtl8139_probe;
- dev->halt = rtl_disable;
- dev->send = rtl_transmit;
- dev->recv = rtl_poll;
+ dev->halt = rtl8139_stop;
+ dev->send = rtl8139_send;
+ dev->recv = rtl8139_recv;
dev->mcast = rtl_bcast_addr;
eth_register (dev);
outl(0xffffffff, ioaddr + RTL_REG_MAR0 + 4);
}
-static void rtl8139_reset(struct eth_device *dev)
+static void rtl8139_hw_reset(struct eth_device *dev)
{
u8 reg;
int i;
outb(RTL_REG_CHIPCMD_CMDRESET, ioaddr + RTL_REG_CHIPCMD);
- cur_rx = 0;
- cur_tx = 0;
-
/* Give the chip 10ms to finish the reset. */
for (i = 0; i < 100; i++) {
reg = inb(ioaddr + RTL_REG_CHIPCMD);
udelay(100);
}
+}
+
+static void rtl8139_reset(struct eth_device *dev)
+{
+ int i;
+
+ cur_rx = 0;
+ cur_tx = 0;
+ rtl8139_hw_reset(dev);
for (i = 0; i < ETH_ALEN; i++)
outb(dev->enetaddr[i], ioaddr + RTL_REG_MAC0 + i);
outw(0, ioaddr + RTL_REG_INTRMASK);
}
-static int rtl_transmit(struct eth_device *dev, void *packet, int length)
+static int rtl8139_send(struct eth_device *dev, void *packet, int length)
{
- unsigned int status;
- unsigned long txstatus;
unsigned int len = length;
+ unsigned long txstatus;
+ unsigned int status;
int i = 0;
ioaddr = dev->iobase;
- memcpy((char *)tx_buffer, (char *)packet, (int)length);
+ memcpy(tx_buffer, packet, length);
debug_cond(DEBUG_TX, "sending %d bytes\n", len);
- /* Note: RTL8139 doesn't auto-pad, send minimum payload (another 4
- * bytes are sent automatically for the FCS, totalling to 64 bytes). */
- while (len < ETH_ZLEN) {
+ /*
+ * Note: RTL8139 doesn't auto-pad, send minimum payload (another 4
+ * bytes are sent automatically for the FCS, totalling to 64 bytes).
+ */
+ while (len < ETH_ZLEN)
tx_buffer[len++] = '\0';
- }
flush_cache((unsigned long)tx_buffer, length);
- outl(phys_to_bus((int)tx_buffer), ioaddr + RTL_REG_TXADDR0 + cur_tx*4);
- outl(((TX_FIFO_THRESH<<11) & 0x003f0000) | len,
- ioaddr + RTL_REG_TXSTATUS0 + cur_tx*4);
+ outl(phys_to_bus((unsigned long)tx_buffer),
+ ioaddr + RTL_REG_TXADDR0 + cur_tx * 4);
+ outl(((TX_FIFO_THRESH << 11) & 0x003f0000) | len,
+ ioaddr + RTL_REG_TXSTATUS0 + cur_tx * 4);
do {
status = inw(ioaddr + RTL_REG_INTRSTATUS);
* Only acknlowledge interrupt sources we can properly
* handle here - the RTL_REG_INTRSTATUS_RXOVERFLOW/
* RTL_REG_INTRSTATUS_RXFIFOOVER MUST be handled in the
- * rtl_poll() function.
+ * rtl8139_recv() function.
*/
- outw(status & (RTL_REG_INTRSTATUS_TXOK |
- RTL_REG_INTRSTATUS_TXERR |
- RTL_REG_INTRSTATUS_PCIERR),
- ioaddr + RTL_REG_INTRSTATUS);
- if ((status & (RTL_REG_INTRSTATUS_TXOK |
- RTL_REG_INTRSTATUS_TXERR |
- RTL_REG_INTRSTATUS_PCIERR)) != 0)
+ status &= RTL_REG_INTRSTATUS_TXOK | RTL_REG_INTRSTATUS_TXERR |
+ RTL_REG_INTRSTATUS_PCIERR;
+ outw(status, ioaddr + RTL_REG_INTRSTATUS);
+ if (status)
break;
+
udelay(10);
} while (i++ < RTL_TIMEOUT);
- txstatus = inl(ioaddr + RTL_REG_TXSTATUS0 + cur_tx*4);
-
- if (status & RTL_REG_INTRSTATUS_TXOK) {
- cur_tx = (cur_tx + 1) % NUM_TX_DESC;
-
- debug_cond(DEBUG_TX,
- "tx done, status %hX txstatus %lX\n",
- status, txstatus);
-
- return length;
- } else {
+ txstatus = inl(ioaddr + RTL_REG_TXSTATUS0 + cur_tx * 4);
+ if (!(status & RTL_REG_INTRSTATUS_TXOK)) {
debug_cond(DEBUG_TX,
- "tx timeout/error (%d usecs), status %hX txstatus %lX\n",
- 10*i, status, txstatus);
+ "tx timeout/error (%d usecs), status %hX txstatus %lX\n",
+ 10 * i, status, txstatus);
rtl8139_reset(dev);
return 0;
}
+
+ cur_tx = (cur_tx + 1) % NUM_TX_DESC;
+
+ debug_cond(DEBUG_TX, "tx done, status %hX txstatus %lX\n",
+ status, txstatus);
+
+ return length;
}
-static int rtl_poll(struct eth_device *dev)
+static int rtl8139_recv(struct eth_device *dev)
{
- unsigned int status;
- unsigned int ring_offs;
+ const unsigned int rxstat = RTL_REG_INTRSTATUS_RXFIFOOVER |
+ RTL_REG_INTRSTATUS_RXOVERFLOW |
+ RTL_REG_INTRSTATUS_RXOK;
unsigned int rx_size, rx_status;
- int length=0;
+ unsigned int ring_offs;
+ unsigned int status;
+ int length = 0;
ioaddr = dev->iobase;
- if (inb(ioaddr + RTL_REG_CHIPCMD) & RTL_REG_CHIPCMD_RXBUFEMPTY) {
+ if (inb(ioaddr + RTL_REG_CHIPCMD) & RTL_REG_CHIPCMD_RXBUFEMPTY)
return 0;
- }
status = inw(ioaddr + RTL_REG_INTRSTATUS);
/* See below for the rest of the interrupt acknowledges. */
- outw(status & ~(RTL_REG_INTRSTATUS_RXFIFOOVER |
- RTL_REG_INTRSTATUS_RXOVERFLOW |
- RTL_REG_INTRSTATUS_RXOK),
- ioaddr + RTL_REG_INTRSTATUS);
+ outw(status & ~rxstat, ioaddr + RTL_REG_INTRSTATUS);
- debug_cond(DEBUG_RX, "rtl_poll: int %hX ", status);
+ debug_cond(DEBUG_RX, "%s: int %hX ", __func__, status);
ring_offs = cur_rx % RX_BUF_LEN;
/* ring_offs is guaranteed being 4-byte aligned */
if ((rx_status & (RTL_STS_RXBADSYMBOL | RTL_STS_RXRUNT |
RTL_STS_RXTOOLONG | RTL_STS_RXCRCERR |
RTL_STS_RXBADALIGN)) ||
- (rx_size < ETH_ZLEN) || (rx_size > ETH_FRAME_LEN + 4)) {
+ (rx_size < ETH_ZLEN) ||
+ (rx_size > ETH_FRAME_LEN + 4)) {
printf("rx error %hX\n", rx_status);
- rtl8139_reset(dev); /* this clears all interrupts still pending */
+ /* this clears all interrupts still pending */
+ rtl8139_reset(dev);
return 0;
}
/* Received a good packet */
length = rx_size - 4; /* no one cares about the FCS */
- if (ring_offs+4+rx_size-4 > RX_BUF_LEN) {
- int semi_count = RX_BUF_LEN - ring_offs - 4;
+ if (ring_offs + 4 + rx_size - 4 > RX_BUF_LEN) {
unsigned char rxdata[RX_BUF_LEN];
+ int semi_count = RX_BUF_LEN - ring_offs - 4;
memcpy(rxdata, rx_ring + ring_offs + 4, semi_count);
- memcpy(&(rxdata[semi_count]), rx_ring, rx_size-4-semi_count);
+ memcpy(&rxdata[semi_count], rx_ring,
+ rx_size - 4 - semi_count);
net_process_received_packet(rxdata, length);
debug_cond(DEBUG_RX, "rx packet %d+%d bytes",
- semi_count, rx_size-4-semi_count);
+ semi_count, rx_size - 4 - semi_count);
} else {
net_process_received_packet(rx_ring + ring_offs + 4, length);
- debug_cond(DEBUG_RX, "rx packet %d bytes", rx_size-4);
+ debug_cond(DEBUG_RX, "rx packet %d bytes", rx_size - 4);
}
flush_cache((unsigned long)rx_ring, RX_BUF_LEN);
- cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
+ cur_rx = ROUND(cur_rx + rx_size + 4, 4);
outw(cur_rx - 16, ioaddr + RTL_REG_RXBUFPTR);
- /* 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. */
- outw(status & (RTL_REG_INTRSTATUS_RXFIFOOVER |
- RTL_REG_INTRSTATUS_RXOVERFLOW |
- RTL_REG_INTRSTATUS_RXOK), ioaddr + RTL_REG_INTRSTATUS);
+ /*
+ * 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.
+ */
+ outw(status & rxstat, ioaddr + RTL_REG_INTRSTATUS);
+
return length;
}
-static void rtl_disable(struct eth_device *dev)
+static void rtl8139_stop(struct eth_device *dev)
{
- int i;
-
ioaddr = dev->iobase;
- /* reset the chip */
- outb(RTL_REG_CHIPCMD_CMDRESET, ioaddr + RTL_REG_CHIPCMD);
-
- /* Give the chip 10ms to finish the reset. */
- for (i=0; i<100; ++i){
- if ((inb(ioaddr + RTL_REG_CHIPCMD) & RTL_REG_CHIPCMD_CMDRESET) == 0) break;
- udelay (100); /* wait 100us */
- }
+ rtl8139_hw_reset(dev);
}