/* * Amiga Linux/68k A2065 Ethernet Driver * * (C) Copyright 1995-2003 by Geert Uytterhoeven <geert@linux-m68k.org> * * Fixes and tips by: * - Janos Farkas (CHEXUM@sparta.banki.hu) * - Jes Degn Soerensen (jds@kom.auc.dk) * - Matt Domsch (Matt_Domsch@dell.com) * * ---------------------------------------------------------------------------- * * This program is based on * * ariadne.?: Amiga Linux/68k Ariadne Ethernet Driver * (C) Copyright 1995 by Geert Uytterhoeven, * Peter De Schrijver * * lance.c: An AMD LANCE ethernet driver for linux. * Written 1993-94 by Donald Becker. * * Am79C960: PCnet(tm)-ISA Single-Chip Ethernet Controller * Advanced Micro Devices * Publication #16907, Rev. B, Amendment/0, May 1994 * * ---------------------------------------------------------------------------- * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of the Linux * distribution for more details. * * ---------------------------------------------------------------------------- * * The A2065 is a Zorro-II board made by Commodore/Ameristar. It contains: * * - an Am7990 Local Area Network Controller for Ethernet (LANCE) with * both 10BASE-2 (thin coax) and AUI (DB-15) connectors
*/
/* Receive and transmit ring base, along with extra bits. */ unsignedshort rx_ptr; /* receive descriptor addr */ unsignedshort rx_len; /* receive len and high addr */ unsignedshort tx_ptr; /* transmit descriptor addr */ unsignedshort tx_len; /* transmit len and high addr */
/* The Tx and Rx ring entries must aligned on 8-byte boundaries. */ struct lance_rx_desc brx_ring[RX_RING_SIZE]; struct lance_tx_desc btx_ring[TX_RING_SIZE];
/* Setup the Lance Rx and Tx rings */ staticvoid lance_init_ring(struct net_device *dev)
{ struct lance_private *lp = netdev_priv(dev); volatilestruct lance_init_block *ib = lp->init_block; volatilestruct lance_init_block *aib = lp->lance_init_block; /* for LANCE_ADDR computations */ int leptr; int i;
/* Lock out other processes while setting up hardware */
netif_stop_queue(dev);
lp->rx_new = lp->tx_new = 0;
lp->rx_old = lp->tx_old = 0;
ib->mode = 0;
/* Copy the ethernet address to the lance init block * Note that on the sparc you need to swap the ethernet address.
*/
ib->phys_addr[0] = dev->dev_addr[1];
ib->phys_addr[1] = dev->dev_addr[0];
ib->phys_addr[2] = dev->dev_addr[3];
ib->phys_addr[3] = dev->dev_addr[2];
ib->phys_addr[4] = dev->dev_addr[5];
ib->phys_addr[5] = dev->dev_addr[4];
/* Setup the Tx ring entries */
netdev_dbg(dev, "TX rings:\n"); for (i = 0; i <= 1 << lp->lance_log_tx_bufs; i++) {
leptr = LANCE_ADDR(&aib->tx_buf[i][0]);
ib->btx_ring[i].tmd0 = leptr;
ib->btx_ring[i].tmd1_hadr = leptr >> 16;
ib->btx_ring[i].tmd1_bits = 0;
ib->btx_ring[i].length = 0xf000; /* The ones required by tmd2 */
ib->btx_ring[i].misc = 0; if (i < 3)
netdev_dbg(dev, "%d: 0x%08x\n", i, leptr);
}
/* Setup the Rx ring entries */
netdev_dbg(dev, "RX rings:\n"); for (i = 0; i < 1 << lp->lance_log_rx_bufs; i++) {
leptr = LANCE_ADDR(&aib->rx_buf[i][0]);
ib->brx_ring[i].rmd0 = leptr;
ib->brx_ring[i].rmd1_hadr = leptr >> 16;
ib->brx_ring[i].rmd1_bits = LE_R1_OWN;
ib->brx_ring[i].length = -RX_BUFF_SIZE | 0xf000;
ib->brx_ring[i].mblength = 0; if (i < 3)
netdev_dbg(dev, "%d: 0x%08x\n", i, leptr);
}
/* Wait for the lance to complete initialization */ for (i = 0; (i < 100) && !(ll->rdp & (LE_C0_ERR | LE_C0_IDON)); i++)
barrier(); if ((i == 100) || (ll->rdp & LE_C0_ERR)) {
pr_err("unopened after %d ticks, csr0=%04x\n", i, ll->rdp); return -EIO;
}
/* Clear IDON by writing a "1", enable interrupts and start lance */
ll->rdp = LE_C0_IDON;
ll->rdp = LE_C0_INEA | LE_C0_STRT;
/* We got an incomplete frame? */ if ((bits & LE_R1_POK) != LE_R1_POK) {
dev->stats.rx_over_errors++;
dev->stats.rx_errors++; continue;
} elseif (bits & LE_R1_ERR) { /* Count only the end frame as a rx error, * not the beginning
*/ if (bits & LE_R1_BUF)
dev->stats.rx_fifo_errors++; if (bits & LE_R1_CRC)
dev->stats.rx_crc_errors++; if (bits & LE_R1_OFL)
dev->stats.rx_over_errors++; if (bits & LE_R1_FRA)
dev->stats.rx_frame_errors++; if (bits & LE_R1_EOP)
dev->stats.rx_errors++;
} else { int len = (rd->mblength & 0xfff) - 4; struct sk_buff *skb = netdev_alloc_skb(dev, len + 2);
/* buffer errors and underflows turn off * the transmitter, so restart the adapter
*/ if (status & (LE_T3_BUF | LE_T3_UFL)) {
dev->stats.tx_fifo_errors++;
netdev_err(dev, "Tx: ERR_BUF|ERR_UFL, restarting\n"); /* Stop the lance */
ll->rap = LE_CSR0;
ll->rdp = LE_C0_STOP;
lance_init_ring(dev);
load_csrs(lp);
init_restart_lance(lp); return 0;
}
} elseif ((td->tmd1_bits & LE_T1_POK) == LE_T1_POK) { /* So we don't count the packet more than once. */
td->tmd1_bits &= ~(LE_T1_POK);
/* One collision before packet was sent. */ if (td->tmd1_bits & LE_T1_EONE)
dev->stats.collisions++;
/* More than one collision, be optimistic. */ if (td->tmd1_bits & LE_T1_EMORE)
dev->stats.collisions += 2;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.