patch-2.4.20 linux-2.4.20/drivers/net/via-rhine.c
Next file: linux-2.4.20/drivers/net/wan/8253x/crc32.c
Previous file: linux-2.4.20/drivers/net/tulip/tulip_core.c
Back to the patch index
Back to the overall index
- Lines: 402
- Date:
Thu Nov 28 15:53:14 2002
- Orig file:
linux-2.4.19/drivers/net/via-rhine.c
- Orig date:
Fri Aug 2 17:39:44 2002
diff -urN linux-2.4.19/drivers/net/via-rhine.c linux-2.4.20/drivers/net/via-rhine.c
@@ -93,6 +93,10 @@
- transmit frame queue message is off by one - fixed
- adds IntrNormalSummary to "Something Wicked" exclusion list
so normal interrupts will not trigger the message (src: Donald Becker)
+ (Roger Luethi)
+ - show confused chip where to continue after Tx error
+ - location of collision counter is chip specific
+ - allow selecting backoff algorithm (module parameter)
*/
@@ -111,6 +115,9 @@
Setting to > 1518 effectively disables this feature. */
static int rx_copybreak;
+/* Select a backoff algorithm (Ethernet capture effect) */
+static int backoff;
+
/* Used to pass the media type, etc.
Both 'options[]' and 'full_duplex[]' should exist for driver
interoperability.
@@ -213,11 +220,13 @@
MODULE_PARM(max_interrupt_work, "i");
MODULE_PARM(debug, "i");
MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(backoff, "i");
MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
MODULE_PARM_DESC(max_interrupt_work, "VIA Rhine maximum events handled per interrupt");
MODULE_PARM_DESC(debug, "VIA Rhine debug level (0-7)");
MODULE_PARM_DESC(rx_copybreak, "VIA Rhine copy breakpoint for copy-only-tiny-frames");
+MODULE_PARM_DESC(backoff, "VIA Rhine: Bits 0-3: backoff algorithm");
MODULE_PARM_DESC(options, "VIA Rhine: Bits 0-3: media type, bit 17: full duplex");
MODULE_PARM_DESC(full_duplex, "VIA Rhine full duplex setting(s) (1)");
@@ -234,7 +243,8 @@
Boards with this chip are functional only in a bus-master PCI slot.
Many operational settings are loaded from the EEPROM to the Config word at
-offset 0x78. This driver assumes that they are correct.
+offset 0x78. For most of these settings, this driver assumes that they are
+correct.
If this driver is compiled to use PCI memory space operations the EEPROM
must be configured to enable memory ops.
@@ -386,9 +396,10 @@
StickyHW=0x83, WOLcrClr=0xA4, WOLcgClr=0xA7, PwrcsrClr=0xAC,
};
-/* Bits in ConfigD (select backoff algorithm (Ethernet capture effect)) */
+/* Bits in ConfigD */
enum backoff_bits {
- BackOpt=0x01, BackAMD=0x02, BackDEC=0x04, BackRandom=0x08
+ BackOptional=0x01, BackModify=0x02,
+ BackCaptureEffect=0x04, BackRandom=0x08
};
#ifdef USE_MEM
@@ -402,7 +413,7 @@
/* Bits in the interrupt status/mask registers. */
enum intr_status_bits {
IntrRxDone=0x0001, IntrRxErr=0x0004, IntrRxEmpty=0x0020,
- IntrTxDone=0x0002, IntrTxAbort=0x0008, IntrTxUnderrun=0x0010,
+ IntrTxDone=0x0002, IntrTxError=0x0008, IntrTxUnderrun=0x0010,
IntrPCIErr=0x0040,
IntrStatsMax=0x0080, IntrRxEarly=0x0100, IntrMIIChange=0x0200,
IntrRxOverflow=0x0400, IntrRxDropped=0x0800, IntrRxNoBuf=0x1000,
@@ -428,24 +439,27 @@
/* The Rx and Tx buffer descriptors. */
struct rx_desc {
s32 rx_status;
- u32 desc_length;
+ u32 desc_length; /* Chain flag, Buffer/frame length */
u32 addr;
u32 next_desc;
};
struct tx_desc {
s32 tx_status;
- u32 desc_length;
+ u32 desc_length; /* Chain flag, Tx Config, Frame length */
u32 addr;
u32 next_desc;
};
+/* Initial value for tx_desc.desc_length, Buffer size goes to bits 0-10 */
+#define TXDESC 0x00e08000
+
enum rx_status_bits {
RxOK=0x8000, RxWholePkt=0x0300, RxErr=0x008F
};
-/* Bits in *_desc.status */
+/* Bits in *_desc.*_status */
enum desc_status_bits {
- DescOwn=0x80000000, DescEndPacket=0x4000, DescIntr=0x1000,
+ DescOwn=0x80000000
};
/* Bits in ChipCmd. */
@@ -514,9 +528,10 @@
static void via_rhine_error(struct net_device *dev, int intr_status);
static void via_rhine_set_rx_mode(struct net_device *dev);
static struct net_device_stats *via_rhine_get_stats(struct net_device *dev);
-static int via_rhine_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static int via_rhine_close(struct net_device *dev);
static inline void clear_tally_counters(long ioaddr);
+static inline void via_restart_tx(struct net_device *dev);
static void wait_for_reset(struct net_device *dev, int chip_id, char *name)
{
@@ -703,6 +718,11 @@
writeb(readb(ioaddr + ConfigA) & 0xFE, ioaddr + ConfigA);
}
+ /* Select backoff algorithm */
+ if (backoff)
+ writeb(readb(ioaddr + ConfigD) & (0xF0 | backoff),
+ ioaddr + ConfigD);
+
dev->irq = pdev->irq;
np = dev->priv;
@@ -713,6 +733,8 @@
np->mii_if.dev = dev;
np->mii_if.mdio_read = mdio_read;
np->mii_if.mdio_write = mdio_write;
+ np->mii_if.phy_id_mask = 0x1f;
+ np->mii_if.reg_num_mask = 0x1f;
if (dev->mem_start)
option = dev->mem_start;
@@ -729,7 +751,7 @@
if (np->mii_if.full_duplex) {
printk(KERN_INFO "%s: Set to forced full duplex, autonegotiation"
" disabled.\n", dev->name);
- np->mii_if.duplex_lock = 1;
+ np->mii_if.force_media = 1;
}
/* The chip-specific entries in the device structure. */
@@ -738,7 +760,7 @@
dev->stop = via_rhine_close;
dev->get_stats = via_rhine_get_stats;
dev->set_multicast_list = via_rhine_set_rx_mode;
- dev->do_ioctl = via_rhine_ioctl;
+ dev->do_ioctl = netdev_ioctl;
dev->tx_timeout = via_rhine_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
if (np->drv_flags & ReqTxAlign)
@@ -937,7 +959,7 @@
for (i = 0; i < TX_RING_SIZE; i++) {
np->tx_skbuff[i] = 0;
np->tx_ring[i].tx_status = 0;
- np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000);
+ np->tx_ring[i].desc_length = cpu_to_le32(TXDESC);
next += sizeof(struct tx_desc);
np->tx_ring[i].next_desc = cpu_to_le32(next);
np->tx_buf[i] = &np->tx_bufs[i * PKT_BUF_SZ];
@@ -953,7 +975,7 @@
for (i = 0; i < TX_RING_SIZE; i++) {
np->tx_ring[i].tx_status = 0;
- np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000);
+ np->tx_ring[i].desc_length = cpu_to_le32(TXDESC);
np->tx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */
if (np->tx_skbuff[i]) {
if (np->tx_skbuff_dma[i]) {
@@ -978,7 +1000,7 @@
writeb(dev->dev_addr[i], ioaddr + StationAddr + i);
/* Initialize other registers. */
- writew(0x0006, ioaddr + PCIBusConfig); /* Store & forward */
+ writew(0x0006, ioaddr + PCIBusConfig); /* Tune configuration??? */
/* Configure initial FIFO thresholds. */
writeb(0x20, ioaddr + TxConfig);
np->tx_thresh = 0x20;
@@ -993,13 +1015,14 @@
via_rhine_set_rx_mode(dev);
/* Enable interrupts by setting the interrupt mask. */
- writew(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow| IntrRxDropped|
- IntrTxDone | IntrTxAbort | IntrTxUnderrun |
+ writew(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow |
+ IntrRxDropped | IntrRxNoBuf | IntrTxAborted |
+ IntrTxDone | IntrTxError | IntrTxUnderrun |
IntrPCIErr | IntrStatsMax | IntrLinkChange | IntrMIIChange,
ioaddr + IntrEnable);
np->chip_cmd = CmdStart|CmdTxOn|CmdRxOn|CmdNoTxPoll;
- if (np->mii_if.duplex_lock)
+ if (np->mii_if.force_media)
np->chip_cmd |= CmdFDuplex;
writew(np->chip_cmd, ioaddr + ChipCmd);
@@ -1041,7 +1064,7 @@
switch (regnum) {
case MII_BMCR: /* Is user forcing speed/duplex? */
if (value & 0x9000) /* Autonegotiation. */
- np->mii_if.duplex_lock = 0;
+ np->mii_if.force_media = 0;
else
np->mii_if.full_duplex = (value & 0x0100) ? 1 : 0;
break;
@@ -1112,7 +1135,7 @@
int negotiated = mii_lpa & np->mii_if.advertising;
int duplex;
- if (np->mii_if.duplex_lock || mii_lpa == 0xffff)
+ if (np->mii_if.force_media || mii_lpa == 0xffff)
return;
duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
if (np->mii_if.full_duplex != duplex) {
@@ -1237,7 +1260,7 @@
}
np->tx_ring[entry].desc_length =
- cpu_to_le32(0x00E08000 | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
+ cpu_to_le32(TXDESC | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
/* lock eth irq */
spin_lock_irq (&np->lock);
@@ -1289,13 +1312,14 @@
IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf))
via_rhine_rx(dev);
- if (intr_status & (IntrTxDone | IntrTxAbort | IntrTxUnderrun |
+ if (intr_status & (IntrTxDone | IntrTxError | IntrTxUnderrun |
IntrTxAborted))
via_rhine_tx(dev);
/* Abnormal error summary/uncommon events handlers. */
if (intr_status & (IntrPCIErr | IntrLinkChange | IntrMIIChange |
- IntrStatsMax | IntrTxAbort | IntrTxUnderrun))
+ IntrStatsMax | IntrTxError | IntrTxAborted |
+ IntrTxUnderrun))
via_rhine_error(dev, intr_status);
if (--boguscnt < 0) {
@@ -1307,7 +1331,7 @@
}
if (debug > 3)
- printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
+ printk(KERN_DEBUG "%s: exiting interrupt, status=%4.4x.\n",
dev->name, readw(ioaddr + IntrStatus));
}
@@ -1323,11 +1347,11 @@
/* find and cleanup dirty tx descriptors */
while (np->dirty_tx != np->cur_tx) {
txstatus = le32_to_cpu(np->tx_ring[entry].tx_status);
- if (txstatus & DescOwn)
- break;
if (debug > 6)
printk(KERN_DEBUG " Tx scavenge %d status %8.8x.\n",
entry, txstatus);
+ if (txstatus & DescOwn)
+ break;
if (txstatus & 0x8000) {
if (debug > 1)
printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
@@ -1337,10 +1361,22 @@
if (txstatus & 0x0200) np->stats.tx_window_errors++;
if (txstatus & 0x0100) np->stats.tx_aborted_errors++;
if (txstatus & 0x0080) np->stats.tx_heartbeat_errors++;
- if (txstatus & 0x0002) np->stats.tx_fifo_errors++;
+ if (((np->chip_id == VT86C100A) && txstatus & 0x0002) ||
+ (txstatus & 0x0800) || (txstatus & 0x1000)) {
+ np->stats.tx_fifo_errors++;
+ np->tx_ring[entry].tx_status = cpu_to_le32(DescOwn);
+ break; /* Keep the skb - we try again */
+ }
/* Transmitter restarted in 'abnormal' handler. */
} else {
- np->stats.collisions += (txstatus >> 3) & 15;
+ if (np->chip_id == VT86C100A)
+ np->stats.collisions += (txstatus >> 3) & 0x0F;
+ else
+ np->stats.collisions += txstatus & 0x0F;
+ if (debug > 6)
+ printk(KERN_DEBUG "collisions: %1.1x:%1.1x\n",
+ (txstatus >> 3) & 0xF,
+ txstatus & 0xF);
np->stats.tx_bytes += np->tx_skbuff[entry]->len;
np->stats.tx_packets++;
}
@@ -1476,6 +1512,17 @@
writew(CmdRxDemand | np->chip_cmd, dev->base_addr + ChipCmd);
}
+static inline void via_restart_tx(struct net_device *dev) {
+ struct netdev_private *np = dev->priv;
+ int entry = np->dirty_tx % TX_RING_SIZE;
+
+ /* We know better than the chip where it should continue */
+ writel(np->tx_ring_dma + entry * sizeof(struct tx_desc),
+ dev->base_addr + TxRingPtr);
+
+ writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd);
+}
+
static void via_rhine_error(struct net_device *dev, int intr_status)
{
struct netdev_private *np = dev->priv;
@@ -1501,19 +1548,23 @@
np->stats.rx_missed_errors += readw(ioaddr + RxMissed);
clear_tally_counters(ioaddr);
}
- if (intr_status & IntrTxAbort) {
- /* Stats counted in Tx-done handler, just restart Tx. */
- writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd);
+ if (intr_status & IntrTxError) {
+ if (debug > 1)
+ printk(KERN_INFO "%s: Abort %4.4x, frame dropped.\n",
+ dev->name, intr_status);
+ via_restart_tx(dev);
}
if (intr_status & IntrTxUnderrun) {
if (np->tx_thresh < 0xE0)
writeb(np->tx_thresh += 0x20, ioaddr + TxConfig);
if (debug > 1)
- printk(KERN_INFO "%s: Transmitter underrun, increasing Tx "
- "threshold setting to %2.2x.\n", dev->name, np->tx_thresh);
+ printk(KERN_INFO "%s: Transmitter underrun, Tx "
+ "threshold now %2.2x.\n",
+ dev->name, np->tx_thresh);
+ via_restart_tx(dev);
}
if (intr_status & ~( IntrLinkChange | IntrStatsMax |
- IntrTxAbort | IntrTxAborted | IntrNormalSummary)) {
+ IntrTxError | IntrTxAborted | IntrNormalSummary)) {
if (debug > 1)
printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
dev->name, intr_status);
@@ -1584,7 +1635,7 @@
writeb(np->rx_thresh | rx_mode, ioaddr + RxConfig);
}
-static int via_rhine_ethtool_ioctl (struct net_device *dev, void *useraddr)
+static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
{
struct netdev_private *np = dev->priv;
u32 ethcmd;
@@ -1667,44 +1718,26 @@
return -EOPNOTSUPP;
}
-static int via_rhine_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct netdev_private *np = dev->priv;
- struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data;
- unsigned long flags;
- int retval;
+ struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
+ int rc;
- if (cmd == SIOCETHTOOL)
- return via_rhine_ethtool_ioctl(dev, (void *) rq->ifr_data);
-
- spin_lock_irqsave(&np->lock, flags);
- retval = 0;
+ if (!netif_running(dev))
+ return -EINVAL;
- switch(cmd) {
- case SIOCGMIIPHY: /* Get address of MII PHY in use. */
- case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */
- data->phy_id = np->phys[0] & 0x1f;
- /* Fall Through */
-
- case SIOCGMIIREG: /* Read MII PHY register. */
- case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */
- data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
- break;
+ if (cmd == SIOCETHTOOL)
+ rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
- case SIOCSMIIREG: /* Write MII PHY register. */
- case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */
- if (!capable(CAP_NET_ADMIN)) {
- retval = -EPERM;
- break;
- }
- mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
- break;
- default:
- retval = -EOPNOTSUPP;
+ else {
+ spin_lock_irq(&np->lock);
+ rc = generic_mii_ioctl(&np->mii_if, data, cmd, NULL);
+ spin_unlock_irq(&np->lock);
}
- spin_unlock_irqrestore(&np->lock, flags);
- return retval;
+ return rc;
}
static int via_rhine_close(struct net_device *dev)
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)