netdev
[Top] [All Lists]

[PATCH] 2.4.25 pcnet32.c bus master arbitration failure fix

To: tsbogend@xxxxxxxxxxxxxxxx, jgarzik@xxxxxxxxx, netdev@xxxxxxxxxxx
Subject: [PATCH] 2.4.25 pcnet32.c bus master arbitration failure fix
From: Don Fry <brazilnut@xxxxxxxxxx>
Date: Thu, 19 Feb 2004 13:54:41 -0800 (PST)
Sender: netdev-bounce@xxxxxxxxxxx
The driver did not properly serialize accesses to chip registers, resulting
in reading/writing the wrong register.  This patch eliminates this problem
and gets rid of the cause of the symptom of 'bus master arbitration failure'.

It was easier to use generic_mii_ioctl than modify the current pcnet32_ioctl
routine with the necessary locks.  This has been re-tested on an IA32 system.

--- linux-2.4.25/drivers/net/rmm.pcnet32.c      Thu Feb 19 13:34:29 2004
+++ linux-2.4.25/drivers/net/pcnet32.c  Thu Feb 19 13:48:02 2004
@@ -713,6 +713,8 @@
     lp->name = chipname;
     lp->shared_irq = shared;
     lp->mii_if.full_duplex = fdx;
+    lp->mii_if.phy_id_mask = 0x1f;
+    lp->mii_if.reg_num_mask = 0x1f;
     lp->dxsuflo = dxsuflo;
     lp->ltint = ltint;
     lp->mii = mii;
@@ -784,6 +786,9 @@
        }
     }
 
+    /* Set the mii phy_id so that we can query the link state */
+    if (lp->mii)
+       lp->mii_if.phy_id = ((lp->a.read_bcr (ioaddr, 33)) >> 5) & 0x1f;
     
     /* The PCNET32-specific entries in the device structure. */
     dev->open = &pcnet32_open;
@@ -1604,12 +1609,18 @@
        }
        /* restart autonegotiation */
        case ETHTOOL_NWAY_RST: {
-               return mii_nway_restart(&lp->mii_if);
+               int r;
+               spin_lock_irq(&lp->lock);
+               r = mii_nway_restart(&lp->mii_if);
+               spin_unlock_irq(&lp->lock);
+               return r;
        }
        /* get link status */
        case ETHTOOL_GLINK: {
                struct ethtool_value edata = {ETHTOOL_GLINK};
+               spin_lock_irq(&lp->lock);
                edata.data = mii_link_ok(&lp->mii_if);
+               spin_unlock_irq(&lp->lock);
                if (copy_to_user(useraddr, &edata, sizeof(edata)))
                        return -EFAULT;
                return 0;
@@ -1640,36 +1651,24 @@
 
 static int pcnet32_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-    unsigned long ioaddr = dev->base_addr;
     struct pcnet32_private *lp = dev->priv;     
     struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data;
-    int phyaddr = lp->a.read_bcr (ioaddr, 33);
+    int rc;
+    unsigned long flags;
 
     if (cmd == SIOCETHTOOL)
        return pcnet32_ethtool_ioctl(dev, (void *) rq->ifr_data);
 
+    /* SIOC[GS]MIIxxx ioctls */
     if (lp->mii) {
-       switch(cmd) {
-       case SIOCGMIIPHY:               /* Get address of MII PHY in use. */
-           data->phy_id = (phyaddr >> 5) & 0x1f;
-           /* Fall Through */
-       case SIOCGMIIREG:               /* Read MII PHY register. */
-           lp->a.write_bcr (ioaddr, 33, ((data->phy_id & 0x1f) << 5) | 
(data->reg_num & 0x1f));
-           data->val_out = lp->a.read_bcr (ioaddr, 34);
-           lp->a.write_bcr (ioaddr, 33, phyaddr);
-           return 0;
-       case SIOCSMIIREG:               /* Write MII PHY register. */
-           if (!capable(CAP_NET_ADMIN))
-               return -EPERM;
-           lp->a.write_bcr (ioaddr, 33, ((data->phy_id & 0x1f) << 5) | 
(data->reg_num & 0x1f));
-           lp->a.write_bcr (ioaddr, 34, data->val_in);
-           lp->a.write_bcr (ioaddr, 33, phyaddr);
-           return 0;
-       default:
-           return -EOPNOTSUPP;
-       }
+       spin_lock_irqsave(&lp->lock, flags);
+       rc = generic_mii_ioctl(&lp->mii_if, data, cmd, NULL);
+       spin_unlock_irqrestore(&lp->lock, flags);
+    } else {
+       rc = -EOPNOTSUPP;
     }
-    return -EOPNOTSUPP;
+
+    return rc;
 }
 
 static struct pci_driver pcnet32_driver = {

-- 
Don Fry
brazilnut@xxxxxxxxxx

<Prev in Thread] Current Thread [Next in Thread>
  • [PATCH] 2.4.25 pcnet32.c bus master arbitration failure fix, Don Fry <=