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 rtl_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 void rtl8139_reset(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);
for (i = 0; i < 3; i++)
*ap++ = le16_to_cpu (rtl8139_read_eeprom(i + 7, addr_len));
- rtl_reset(dev);
+ rtl8139_reset(dev);
if (inb(ioaddr + RTL_REG_MEDIASTATUS) & RTL_REG_MEDIASTATUS_MSRLINKFAIL) {
printf("Cable not connected or other link failure\n");
(RX_FIFO_THRESH << 13) |
(RX_DMA_BURST << 8);
-static void set_rx_mode(struct eth_device *dev) {
- unsigned int mc_filter[2];
- int rx_mode;
+static void rtl8139_set_rx_mode(struct eth_device *dev)
+{
/* !IFF_PROMISC */
- rx_mode = RTL_REG_RXCONFIG_ACCEPTBROADCAST |
- RTL_REG_RXCONFIG_ACCEPTMULTICAST |
- RTL_REG_RXCONFIG_ACCEPTMYPHYS;
- mc_filter[1] = mc_filter[0] = 0xffffffff;
+ unsigned int rx_mode = RTL_REG_RXCONFIG_ACCEPTBROADCAST |
+ RTL_REG_RXCONFIG_ACCEPTMULTICAST |
+ RTL_REG_RXCONFIG_ACCEPTMYPHYS;
outl(rtl8139_rx_config | rx_mode, ioaddr + RTL_REG_RXCONFIG);
- outl(mc_filter[0], ioaddr + RTL_REG_MAR0 + 0);
- outl(mc_filter[1], ioaddr + RTL_REG_MAR0 + 4);
+ outl(0xffffffff, ioaddr + RTL_REG_MAR0 + 0);
+ outl(0xffffffff, ioaddr + RTL_REG_MAR0 + 4);
}
-static void rtl_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){
- if ((inb(ioaddr + RTL_REG_CHIPCMD) &
- RTL_REG_CHIPCMD_CMDRESET) == 0)
+ for (i = 0; i < 100; i++) {
+ reg = inb(ioaddr + RTL_REG_CHIPCMD);
+ if (!(reg & RTL_REG_CHIPCMD_CMDRESET))
break;
- udelay (100); /* wait 100us */
+
+ 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);
/* Must enable Tx/Rx before setting transfer thresholds! */
outb(RTL_REG_CHIPCMD_CMDRXENB | RTL_REG_CHIPCMD_CMDTXENB,
- ioaddr + RTL_REG_CHIPCMD);
- outl((RX_FIFO_THRESH<<13) | (RX_BUF_LEN_IDX<<11) | (RX_DMA_BURST<<8),
- ioaddr + RTL_REG_RXCONFIG); /* accept no frames yet! */
- outl((TX_DMA_BURST<<8)|0x03000000, ioaddr + RTL_REG_TXCONFIG);
-
- /* The Linux driver changes RTL_REG_CONFIG1 here to use a different LED pattern
- * for half duplex or full/autodetect duplex (for full/autodetect, the
- * outputs are TX/RX, Link10/100, FULL, while for half duplex it uses
- * TX/RX, Link100, Link10). This is messy, because it doesn't match
- * 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. */
-
- debug_cond(DEBUG_RX,
- "rx ring address is %lX\n",(unsigned long)rx_ring);
+ ioaddr + RTL_REG_CHIPCMD);
+
+ /* accept no frames yet! */
+ outl(rtl8139_rx_config, ioaddr + RTL_REG_RXCONFIG);
+ outl((TX_DMA_BURST << 8) | 0x03000000, ioaddr + RTL_REG_TXCONFIG);
+
+ /*
+ * The Linux driver changes RTL_REG_CONFIG1 here to use a different
+ * LED pattern for half duplex or full/autodetect duplex (for
+ * full/autodetect, the outputs are TX/RX, Link10/100, FULL, while
+ * for half duplex it uses TX/RX, Link100, Link10). This is messy,
+ * because it doesn't match 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.
+ */
+ debug_cond(DEBUG_RX, "rx ring address is %p\n", rx_ring);
+
flush_cache((unsigned long)rx_ring, RX_BUF_LEN);
outl(phys_to_bus((int)rx_ring), ioaddr + RTL_REG_RXBUF);
- /* If we add multicast support, the RTL_REG_MAR0 register would have to be
- * initialized to 0xffffffffffffffff (two 32 bit accesses). Etherboot
- * only needs broadcast (for ARP/RARP/BOOTP/DHCP) and unicast. */
-
+ /*
+ * If we add multicast support, the RTL_REG_MAR0 register would have
+ * to be initialized to 0xffffffffffffffff (two 32 bit accesses).
+ * Etherboot only needs broadcast (for ARP/RARP/BOOTP/DHCP) and
+ * unicast.
+ */
outb(RTL_REG_CHIPCMD_CMDRXENB | RTL_REG_CHIPCMD_CMDTXENB,
- ioaddr + RTL_REG_CHIPCMD);
+ ioaddr + RTL_REG_CHIPCMD);
outl(rtl8139_rx_config, ioaddr + RTL_REG_RXCONFIG);
/* Start the chip's Tx and Rx process. */
outl(0, ioaddr + RTL_REG_RXMISSED);
- /* set_rx_mode */
- set_rx_mode(dev);
+ rtl8139_set_rx_mode(dev);
/* Disable all known interrupts by setting the interrupt mask. */
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);
- rtl_reset(dev);
+ 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);
- rtl_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);
}