#ifdef ARIADNE_DEBUG int ariadne_debug = ARIADNE_DEBUG; #else int ariadne_debug = 1; #endif
/* Macros to Fix Endianness problems */
/* Swap the Bytes in a WORD */ #define swapw(x) (((x >> 8) & 0x00ff) | ((x << 8) & 0xff00)) /* Get the Low BYTE in a WORD */ #define lowb(x) (x & 0xff) /* Get the Swapped High WORD in a LONG */ #define swhighw(x) ((((x) >> 8) & 0xff00) | (((x) >> 24) & 0x00ff)) /* Get the Swapped Low WORD in a LONG */ #define swloww(x) ((((x) << 8) & 0xff00) | (((x) >> 8) & 0x00ff))
/* Transmit/Receive Ring Definitions */
#define TX_RING_SIZE 5 #define RX_RING_SIZE 16
#define PKT_BUF_SIZE 1520
/* Private Device Data */
struct ariadne_private { volatilestruct TDRE *tx_ring[TX_RING_SIZE]; volatilestruct RDRE *rx_ring[RX_RING_SIZE]; volatile u_short *tx_buff[TX_RING_SIZE]; volatile u_short *rx_buff[RX_RING_SIZE]; int cur_tx, cur_rx; /* The next free ring entry */ int dirty_tx; /* The ring entries to be free()ed */ char tx_full;
};
/* Structure Created in the Ariadne's RAM Buffer */
/* Set up TX Ring */ for (i = 0; i < TX_RING_SIZE; i++) { volatilestruct TDRE *t = &lancedata->tx_ring[i];
t->TMD0 = swloww(ARIADNE_RAM +
offsetof(struct lancedata, tx_buff[i]));
t->TMD1 = swhighw(ARIADNE_RAM +
offsetof(struct lancedata, tx_buff[i])) |
TF_STP | TF_ENP;
t->TMD2 = swapw((u_short)-PKT_BUF_SIZE);
t->TMD3 = 0;
priv->tx_ring[i] = &lancedata->tx_ring[i];
priv->tx_buff[i] = lancedata->tx_buff[i];
netdev_dbg(dev, "TX Entry %2d at %p, Buf at %p\n",
i, &lancedata->tx_ring[i], lancedata->tx_buff[i]);
}
/* Set up RX Ring */ for (i = 0; i < RX_RING_SIZE; i++) { volatilestruct RDRE *r = &lancedata->rx_ring[i];
r->RMD0 = swloww(ARIADNE_RAM +
offsetof(struct lancedata, rx_buff[i]));
r->RMD1 = swhighw(ARIADNE_RAM +
offsetof(struct lancedata, rx_buff[i])) |
RF_OWN;
r->RMD2 = swapw((u_short)-PKT_BUF_SIZE);
r->RMD3 = 0x0000;
priv->rx_ring[i] = &lancedata->rx_ring[i];
priv->rx_buff[i] = lancedata->rx_buff[i];
netdev_dbg(dev, "RX Entry %2d at %p, Buf at %p\n",
i, &lancedata->rx_ring[i], lancedata->rx_buff[i]);
}
}
staticint ariadne_rx(struct net_device *dev)
{ struct ariadne_private *priv = netdev_priv(dev); int entry = priv->cur_rx % RX_RING_SIZE; int i;
/* If we own the next entry, it's a new packet. Send it up */ while (!(lowb(priv->rx_ring[entry]->RMD1) & RF_OWN)) { int status = lowb(priv->rx_ring[entry]->RMD1);
if (status != (RF_STP | RF_ENP)) { /* There was an error */ /* There is a tricky error noted by * John Murphy <murf@perftech.com> to Russ Nelson: * Even with full-sized buffers it's possible for a * jabber packet to use two buffers, with only the * last correctly noting the error
*/ /* Only count a general error at the end of a packet */ if (status & RF_ENP)
dev->stats.rx_errors++; if (status & RF_FRAM)
dev->stats.rx_frame_errors++; if (status & RF_OFLO)
dev->stats.rx_over_errors++; if (status & RF_CRC)
dev->stats.rx_crc_errors++; if (status & RF_BUFF)
dev->stats.rx_fifo_errors++;
priv->rx_ring[entry]->RMD1 &= 0xff00 | RF_STP | RF_ENP;
} else { /* Malloc up new buffer, compatible with net-3 */ short pkt_len = swapw(priv->rx_ring[entry]->RMD3); struct sk_buff *skb;
skb = netdev_alloc_skb(dev, pkt_len + 2); if (!skb) { for (i = 0; i < RX_RING_SIZE; i++) if (lowb(priv->rx_ring[(entry + i) % RX_RING_SIZE]->RMD1) & RF_OWN) break;
if (i > RX_RING_SIZE - 2) {
dev->stats.rx_dropped++;
priv->rx_ring[entry]->RMD1 |= RF_OWN;
priv->cur_rx++;
} break;
}
skb_reserve(skb, 2); /* 16 byte align */
skb_put(skb, pkt_len); /* Make room */
skb_copy_to_linear_data(skb,
(constvoid *)priv->rx_buff[entry],
pkt_len);
skb->protocol = eth_type_trans(skb, dev);
netdev_dbg(dev, "RX pkt type 0x%04x from %pM to %pM data %p len %u\n",
((u_short *)skb->data)[6],
skb->data + 6, skb->data,
skb->data, skb->len);
if (csr0 & TINT) { /* Tx-done interrupt */ int dirty_tx = priv->dirty_tx;
handled = 1; while (dirty_tx < priv->cur_tx) { int entry = dirty_tx % TX_RING_SIZE; int status = lowb(priv->tx_ring[entry]->TMD1);
if (status & TF_OWN) break; /* It still hasn't been Txed */
priv->tx_ring[entry]->TMD1 &= 0xff00;
if (status & TF_ERR) { /* There was an major error, log it */ int err_status = priv->tx_ring[entry]->TMD3;
dev->stats.tx_errors++; if (err_status & EF_RTRY)
dev->stats.tx_aborted_errors++; if (err_status & EF_LCAR)
dev->stats.tx_carrier_errors++; if (err_status & EF_LCOL)
dev->stats.tx_window_errors++; if (err_status & EF_UFLO) { /* Ackk! On FIFO errors the Tx unit is turned off! */
dev->stats.tx_fifo_errors++; /* Remove this verbosity later! */
netdev_err(dev, "Tx FIFO error! Status %04x\n",
csr0); /* Restart the chip */
lance->RDP = STRT;
}
} else { if (status & (TF_MORE | TF_ONE))
dev->stats.collisions++;
dev->stats.tx_packets++;
}
dirty_tx++;
}
if (priv->tx_full && netif_queue_stopped(dev) &&
dirty_tx > priv->cur_tx - TX_RING_SIZE + 2) { /* The ring is no longer full */
priv->tx_full = 0;
netif_wake_queue(dev);
}
/* Clear any other interrupt, and set interrupt enable */
lance->RAP = CSR0; /* PCnet-ISA Controller Status */
lance->RDP = INEA | BABL | CERR | MISS | MERR | IDON;
if (ariadne_debug > 4)
netdev_dbg(dev, "exiting interrupt, csr%d=%#04x\n",
lance->RAP, lance->RDP);
/* Set the Init Block Mode */
lance->RAP = CSR15; /* Mode Register */
lance->RDP = 0x0000;
/* Set the Transmit Descriptor Ring Pointer */
lance->RAP = CSR30; /* Base Address of Transmit Ring */
lance->RDP = swloww(ARIADNE_RAM + offsetof(struct lancedata, tx_ring));
lance->RAP = CSR31; /* Base Address of transmit Ring */
lance->RDP = swhighw(ARIADNE_RAM + offsetof(struct lancedata, tx_ring));
/* Set the Receive Descriptor Ring Pointer */
lance->RAP = CSR24; /* Base Address of Receive Ring */
lance->RDP = swloww(ARIADNE_RAM + offsetof(struct lancedata, rx_ring));
lance->RAP = CSR25; /* Base Address of Receive Ring */
lance->RDP = swhighw(ARIADNE_RAM + offsetof(struct lancedata, rx_ring));
/* Set the Number of RX and TX Ring Entries */
lance->RAP = CSR76; /* Receive Ring Length */
lance->RDP = swapw(((u_short)-RX_RING_SIZE));
lance->RAP = CSR78; /* Transmit Ring Length */
lance->RDP = swapw(((u_short)-TX_RING_SIZE));
/* Enable Media Interface Port Auto Select (10BASE-2/10BASE-T) */
lance->RAP = ISACSR2; /* Miscellaneous Configuration */
lance->IDP = ASEL;
/* LED Control */
lance->RAP = ISACSR5; /* LED1 Status */
lance->IDP = PSE|XMTE;
lance->RAP = ISACSR6; /* LED2 Status */
lance->IDP = PSE|COLE;
lance->RAP = ISACSR7; /* LED3 Status */
lance->IDP = PSE|RCVE;
netif_start_queue(dev);
i = request_irq(IRQ_AMIGA_PORTS, ariadne_interrupt, IRQF_SHARED,
dev->name, dev); if (i) return i;
if (ariadne_debug > 1) {
netdev_dbg(dev, "Shutting down ethercard, status was %02x\n",
lance->RDP);
netdev_dbg(dev, "%lu packets missed\n",
dev->stats.rx_missed_errors);
}
/* We stop the LANCE here -- it occasionally polls memory if we don't */
lance->RDP = STOP;
/* FIXME: is the 79C960 new enough to do its own padding right ? */ if (skb->len < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) return NETDEV_TX_OK;
len = ETH_ZLEN;
}
/* Fill in a Tx ring entry */
netdev_dbg(dev, "TX pkt type 0x%04x from %pM to %pM data %p len %u\n",
((u_short *)skb->data)[6],
skb->data + 6, skb->data,
skb->data, skb->len);
local_irq_save(flags);
entry = priv->cur_tx % TX_RING_SIZE;
/* Caution: the write order is important here, set the base address with
the "ownership" bits last */
/* Set or clear the multicast filter for this adaptor. * num_addrs == -1 Promiscuous mode, receive all packets * num_addrs == 0 Normal mode, clear multicast list * num_addrs > 0 Multicast mode, receive normal and MC packets, * and do best-effort filtering.
*/ staticvoid set_multicast_list(struct net_device *dev)
{ volatilestruct Am79C960 *lance = (struct Am79C960 *)dev->base_addr;
if (!netif_running(dev)) return;
netif_stop_queue(dev);
/* We take the simple way out and always enable promiscuous mode */
lance->RAP = CSR0; /* PCnet-ISA Controller Status */
lance->RDP = STOP; /* Temporarily stop the lance */
ariadne_init_ring(dev);
if (dev->flags & IFF_PROMISC) {
lance->RAP = CSR15; /* Mode Register */
lance->RDP = PROM; /* Set promiscuous mode */
} else { short multicast_table[4]; int num_addrs = netdev_mc_count(dev); int i; /* We don't use the multicast table, * but rely on upper-layer filtering
*/
memset(multicast_table, (num_addrs == 0) ? 0 : -1, sizeof(multicast_table)); for (i = 0; i < 4; i++) {
lance->RAP = CSR8 + (i << 8); /* Logical Address Filter */
lance->RDP = swapw(multicast_table[i]);
}
lance->RAP = CSR15; /* Mode Register */
lance->RDP = 0x0000; /* Unset promiscuous mode */
}
lance->RAP = CSR0; /* PCnet-ISA Controller Status */
lance->RDP = INEA | STRT | IDON;/* Resume normal operation */
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.