patch-2.2.4 linux/drivers/net/mace.c
Next file: linux/drivers/net/myri_sbus.c
Previous file: linux/drivers/net/ibmtr.h
Back to the patch index
Back to the overall index
- Lines: 393
- Date:
Wed Mar 10 21:48:46 1999
- Orig file:
v2.2.3/linux/drivers/net/mace.c
- Orig date:
Mon Oct 5 13:13:39 1998
diff -u --recursive --new-file v2.2.3/linux/drivers/net/mace.c linux/drivers/net/mace.c
@@ -4,6 +4,12 @@
*
* Copyright (C) 1996 Paul Mackerras.
*/
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -16,6 +22,10 @@
#include <asm/pgtable.h>
#include "mace.h"
+#ifdef MODULE
+static struct device *mace_devs = NULL;
+#endif
+
#define N_RX_RING 8
#define N_TX_RING 6
#define MAX_TX_ACTIVE 1
@@ -71,6 +81,9 @@
static void mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs);
static void mace_set_timeout(struct device *dev);
static void mace_tx_timeout(unsigned long data);
+static inline void dbdma_reset(volatile struct dbdma_regs *dma);
+static inline void mace_clean_rings(struct mace_data *mp);
+static void __mace_set_address(struct device *dev, void *addr);
/*
* If we can't get a skbuff when we need it, we use this area for DMA.
@@ -78,7 +91,7 @@
static unsigned char dummy_buf[RX_BUFLEN+2];
/* Bit-reverse one byte of an ethernet hardware address. */
-static int
+static inline int
bitrev(int b)
{
int d = 0, i;
@@ -144,7 +157,8 @@
dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j];
printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]);
}
- printk("\n");
+ printk(", chip revision %d.%d\n",
+ in_8(&mp->mace->chipid_hi), in_8(&mp->mace->chipid_lo));
mp = (struct mace_data *) dev->priv;
mp->maccc = ENXMT | ENRCV;
@@ -193,6 +207,21 @@
return 0;
}
+static void dbdma_reset(volatile struct dbdma_regs *dma)
+{
+ int i;
+
+ out_le32(&dma->control, (WAKE|FLUSH|PAUSE|RUN) << 16);
+
+ /*
+ * Yes this looks peculiar, but apparently it needs to be this
+ * way on some machines.
+ */
+ for (i = 200; i > 0; --i)
+ if (ld_le32(&dma->control) & RUN)
+ udelay(1);
+}
+
static void mace_reset(struct device *dev)
{
struct mace_data *mp = (struct mace_data *) dev->priv;
@@ -203,14 +232,14 @@
i = 200;
while (--i) {
out_8(&mb->biucc, SWRST);
- if (mb->biucc & SWRST) {
- udelay(20);
+ if (in_8(&mb->biucc) & SWRST) {
+ udelay(10);
continue;
}
break;
}
if (!i) {
- printk("mace: cannot reset chip!\n");
+ printk(KERN_ERR "mace: cannot reset chip!\n");
return;
}
@@ -218,19 +247,14 @@
i = in_8(&mb->ir);
out_8(&mb->maccc, 0); /* turn off tx, rx */
- mb->biucc = XMTSP_64;
- mb->utr = RTRD;
- mb->fifocc = RCVFW_32 | XMTFW_16 | XMTFWU | RCVFWU | XMTBRST;
- mb->xmtfc = AUTO_PAD_XMIT; /* auto-pad short frames */
- mb->rcvfc = 0;
+ out_8(&mb->biucc, XMTSP_64);
+ out_8(&mb->utr, RTRD);
+ out_8(&mb->fifocc, RCVFW_32 | XMTFW_16 | XMTFWU | RCVFWU | XMTBRST);
+ out_8(&mb->xmtfc, AUTO_PAD_XMIT); /* auto-pad short frames */
+ out_8(&mb->rcvfc, 0);
/* load up the hardware address */
- out_8(&mb->iac, ADDRCHG | PHYADDR);
- while ((in_8(&mb->iac) & ADDRCHG) != 0)
- ;
- for (i = 0; i < 6; ++i) {
- out_8(&mb->padr, dev->dev_addr[i]);
- }
+ __mace_set_address(dev, dev->dev_addr);
/* clear the multicast filter */
out_8(&mb->iac, ADDRCHG | LOGADDR);
@@ -245,23 +269,30 @@
out_8(&mb->plscc, PORTSEL_GPSI + ENPLSIO);
}
-static int mace_set_address(struct device *dev, void *addr)
+static void __mace_set_address(struct device *dev, void *addr)
{
+ volatile struct mace *mb = ((struct mace_data *) dev->priv)->mace;
unsigned char *p = addr;
- struct mace_data *mp = (struct mace_data *) dev->priv;
- volatile struct mace *mb = mp->mace;
int i;
- unsigned long flags;
-
- save_flags(flags); cli();
/* load up the hardware address */
out_8(&mb->iac, ADDRCHG | PHYADDR);
while ((in_8(&mb->iac) & ADDRCHG) != 0)
;
- for (i = 0; i < 6; ++i) {
+ for (i = 0; i < 6; ++i)
out_8(&mb->padr, dev->dev_addr[i] = p[i]);
- }
+}
+
+static int mace_set_address(struct device *dev, void *addr)
+{
+ struct mace_data *mp = (struct mace_data *) dev->priv;
+ volatile struct mace *mb = mp->mace;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+
+ __mace_set_address(dev, addr);
+
out_8(&mb->iac, 0);
/* note: setting ADDRCHG clears ENRCV */
out_8(&mb->maccc, mp->maccc);
@@ -285,6 +316,7 @@
mace_reset(dev);
/* initialize list of sk_buffs for receiving and set up recv dma */
+ mace_clean_rings(mp);
memset((char *)mp->rx_cmds, 0, N_RX_RING * sizeof(struct dbdma_cmd));
cp = mp->rx_cmds;
for (i = 0; i < N_RX_RING - 1; ++i) {
@@ -335,25 +367,17 @@
out_8(&mb->maccc, mp->maccc);
/* enable all interrupts except receive interrupts */
out_8(&mb->imr, RCVINT);
+
+#ifdef MOD_INC_USE_COUNT
+ MOD_INC_USE_COUNT;
+#endif
return 0;
}
-static int mace_close(struct device *dev)
+static inline void mace_clean_rings(struct mace_data *mp)
{
- struct mace_data *mp = (struct mace_data *) dev->priv;
- volatile struct mace *mb = mp->mace;
- volatile struct dbdma_regs *rd = mp->rx_dma;
- volatile struct dbdma_regs *td = mp->tx_dma;
int i;
- /* disable rx and tx */
- mb->maccc = 0;
- mb->imr = 0xff; /* disable all intrs */
-
- /* disable rx and tx dma */
- st_le32(&rd->control, (RUN|PAUSE|FLUSH|WAKE) << 16); /* clear run bit */
- st_le32(&td->control, (RUN|PAUSE|FLUSH|WAKE) << 16); /* clear run bit */
-
/* free some skb's */
for (i = 0; i < N_RX_RING; ++i) {
if (mp->rx_bufs[i] != 0) {
@@ -366,6 +390,28 @@
if (++i >= N_TX_RING)
i = 0;
}
+}
+
+static int mace_close(struct device *dev)
+{
+ struct mace_data *mp = (struct mace_data *) dev->priv;
+ volatile struct mace *mb = mp->mace;
+ volatile struct dbdma_regs *rd = mp->rx_dma;
+ volatile struct dbdma_regs *td = mp->tx_dma;
+
+ /* disable rx and tx */
+ out_8(&mb->maccc, 0);
+ out_8(&mb->imr, 0xff); /* disable all intrs */
+
+ /* disable rx and tx dma */
+ st_le32(&rd->control, (RUN|PAUSE|FLUSH|WAKE) << 16); /* clear run bit */
+ st_le32(&td->control, (RUN|PAUSE|FLUSH|WAKE) << 16); /* clear run bit */
+
+ mace_clean_rings(mp);
+
+#ifdef MOD_DEC_USE_COUNT
+ MOD_DEC_USE_COUNT;
+#endif
return 0;
}
@@ -517,10 +563,10 @@
if (intr & MPCO)
mp->stats.rx_missed_errors += 256;
- mp->stats.rx_missed_errors += mb->mpc; /* reading clears it */
+ mp->stats.rx_missed_errors += in_8(&mb->mpc); /* reading clears it */
if (intr & RNTPCO)
mp->stats.rx_length_errors += 256;
- mp->stats.rx_length_errors += mb->rntpc; /* reading clears it */
+ mp->stats.rx_length_errors += in_8(&mb->rntpc); /* reading clears it */
if (intr & CERR)
++mp->stats.tx_heartbeat_errors;
if (intr & BABBLE)
@@ -547,7 +593,7 @@
mace_handle_misc_intrs(mp, intr);
i = mp->tx_empty;
- while (mb->pr & XMTSV) {
+ while (in_8(&mb->pr) & XMTSV) {
del_timer(&mp->tx_timeout);
mp->timeout_active = 0;
/*
@@ -555,13 +601,13 @@
* word. This appears to unlatch any error indication from
* the DMA controller.
*/
- intr = mb->ir;
+ intr = in_8(&mb->ir);
if (intr != 0)
mace_handle_misc_intrs(mp, intr);
if (mp->tx_bad_runt) {
fs = in_8(&mb->xmtfs);
mp->tx_bad_runt = 0;
- mb->xmtfc = AUTO_PAD_XMIT;
+ out_8(&mb->xmtfc, AUTO_PAD_XMIT);
continue;
}
dstat = ld_le32(&td->status);
@@ -571,7 +617,7 @@
* xcount is the number of complete frames which have been
* written to the fifo but for which status has not been read.
*/
- xcount = (mb->fifofc >> XMTFC_SH) & XMTFC_MASK;
+ xcount = (in_8(&mb->fifofc) >> XMTFC_SH) & XMTFC_MASK;
if (xcount == 0 || (dstat & DEAD)) {
/*
* If a packet was aborted before the DMA controller has
@@ -586,11 +632,15 @@
*/
out_8(&mb->xmtfc, DXMTFCS);
}
- fs = mb->xmtfs;
+ fs = in_8(&mb->xmtfs);
if ((fs & XMTSV) == 0) {
printk(KERN_ERR "mace: xmtfs not valid! (fs=%x xc=%d ds=%x)\n",
fs, xcount, dstat);
- return;
+ mace_reset(dev);
+ /*
+ * XXX mace likes to hang the machine after a xmtfs error.
+ * This is hard to reproduce, reseting *may* help
+ */
}
cp = mp->tx_cmds + NCMDS_TX * i;
stat = ld_le16(&cp->xfer_status);
@@ -600,7 +650,7 @@
* the transmit FIFO.
*/
udelay(1);
- x = (mb->fifofc >> XMTFC_SH) & XMTFC_MASK;
+ x = (in_8(&mb->fifofc) >> XMTFC_SH) & XMTFC_MASK;
if (x != 0) {
/* there were two bytes with an end-of-packet indication */
mp->tx_bad_runt = 1;
@@ -612,10 +662,10 @@
* We flush the transmit FIFO just in case (by setting the
* XMTFWU bit with the transmitter disabled).
*/
- out_8(&mb->maccc, mb->maccc & ~ENXMT);
- out_8(&mb->fifocc, mb->fifocc | XMTFWU);
+ out_8(&mb->maccc, in_8(&mb->maccc) & ~ENXMT);
+ out_8(&mb->fifocc, in_8(&mb->fifocc) | XMTFWU);
udelay(1);
- out_8(&mb->maccc, mb->maccc | ENXMT);
+ out_8(&mb->maccc, in_8(&mb->maccc) | ENXMT);
out_8(&mb->xmtfc, AUTO_PAD_XMIT);
}
}
@@ -632,7 +682,7 @@
++mp->stats.tx_carrier_errors;
if (fs & (UFLO|LCOL|RTRY))
++mp->stats.tx_aborted_errors;
- } else
+ } else
++mp->stats.tx_packets;
dev_kfree_skb(mp->tx_bufs[i]);
--mp->tx_active;
@@ -686,19 +736,19 @@
goto out;
/* update various counters */
- mace_handle_misc_intrs(mp, mb->ir);
+ mace_handle_misc_intrs(mp, in_8(&mb->ir));
cp = mp->tx_cmds + NCMDS_TX * mp->tx_empty;
/* turn off both tx and rx and reset the chip */
out_8(&mb->maccc, 0);
- out_le32(&td->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
printk(KERN_ERR "mace: transmit timeout - resetting\n");
+ dbdma_reset(td);
mace_reset(dev);
/* restart rx dma */
cp = bus_to_virt(ld_le32(&rd->cmdptr));
- out_le32(&rd->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+ dbdma_reset(rd);
out_le16(&cp->xfer_status, 0);
out_le32(&rd->cmdptr, virt_to_bus(cp));
out_le32(&rd->control, (RUN << 16) | RUN);
@@ -786,8 +836,8 @@
++mp->stats.rx_crc_errors;
} else {
/* Mace feature AUTO_STRIP_RCV is on by default, dropping the
- * FCS on frames with 802.3 headers. This means that Ethernet
- * frames have 8 extra octets at the end, while 802.3 frames
+ * FCS on frames with 802.3 headers. This means that Ethernet
+ * frames have 8 extra octets at the end, while 802.3 frames
* have only 4. We need to correctly account for this. */
if (*(unsigned short *)(data+12) < 1536) /* 802.3 header */
nb -= 4;
@@ -846,3 +896,35 @@
mp->rx_fill = i;
}
}
+
+#ifdef MODULE
+
+#if LINUX_VERSION_CODE > 0x20118
+MODULE_AUTHOR("Paul Mackerras");
+MODULE_DESCRIPTION("PowerMac MACE driver.");
+#endif
+
+int init_module(void)
+{
+ int res;
+
+ if(mace_devs != NULL)
+ return -EBUSY;
+ res = mace_probe(NULL);
+ return res;
+}
+
+void cleanup_module(void)
+{
+ struct mace_data *mp = (struct mace_data *) mace_devs->priv;
+ unregister_netdev(mace_devs);
+
+ free_irq(mace_devs->irq, mace_interrupt);
+ free_irq(mp->tx_dma_intr, mace_txdma_intr);
+ free_irq(mp->rx_dma_intr, mace_rxdma_intr);
+
+ kfree(mace_devs);
+ mace_devs = NULL;
+}
+
+#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)