Skip to contentSkip to conversation

pcnet32: PHY selection support

PATCH In review Seewer Philippe 2 participants 3 messages Feb 17, 2006

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 2/2 pcnet32: PHY selection support

Most AMD pcnet chips support up to 32 external PHYs. This patch introduces basic PHY selection/switching support, by adding two new module parameters:
-maxphy: how many PHYs the card supports
-usephy: which phy to use instead of eeprom default

Maxphy is necessary in order to check the range of usephy and may be overriden inside the module.

If only maxphy is present I've implemented an algorithm which checks the link state on all PHYs and uses the one that has a link.

I tested this extensively on our 2700/01 FTX cards and works. I have added a maxphy override for those cards to the driver as well.

The only drawback here is that I wasn't able to figure out how to dynamically switch the PHY, so the whole switching process is done in pcnet32_probe1 instead of open or when the link state changes. This means that once the driver is loaded the PHY which was connected must be used and no change is possible without physically resetting (power off/on) the card.

Patch applies to 2.6.16-rc3 and depends on patch nr. 1 to completely support AT 2700/01 FTX cards.

---

 pcnet32.c |  107 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 105 insertions(+), 2 deletions(-)
drivers/net/pcnet32.c 2006-02-17 16:40:47.000000000 +0100 renamed from drivers/net/pcnet32.c 2006-02-17 16:38:44.000000000 +0100 +105 -2
diff -uprN -X linux-2.6.16-rc3-vanilla/Documentation/dontdiff linux-2.6.16-rc3-vanilla/drivers/net/pcnet32.c linux-2.6.16-rc3/drivers/net/pcnet32.c
@@ -22,7 +22,7 @@
  *************************************************************************/
 
 #define DRV_NAME       "pcnet32"
-#define DRV_VERSION    "1.31d"
+#define DRV_VERSION    "1.32"
 #define DRV_RELDATE    "17.Feb.2006"
 #define PFX            DRV_NAME ": "
 
@@ -140,6 +140,10 @@ static int options[MAX_UNITS];
 static int full_duplex[MAX_UNITS];
 static int homepna[MAX_UNITS];
 
+/* Options to switch PHY */
+static int maxphy[MAX_UNITS];
+static int usephy[MAX_UNITS];
+
 /*
  *                             Theory of Operation
  *
@@ -267,6 +271,8 @@ static int homepna[MAX_UNITS];
  *        See Bugzilla 2669 and 4551.
  * v1.31d  17 Nov 2006 Philippe Seewer Extended AT 2700/01 FX support
  *         to support FTX variants as well.
+ * v1.32   17 Nov 2006 Philippe Seewer Basic PHY switching support on
+ *         module load.
  */
 
 
@@ -386,6 +392,8 @@ struct pcnet32_private {
     struct timer_list  watchdog_timer;
     struct timer_list  blink_timer;
     u32                        msg_enable;     /* debug message level */
+    int                 maxphy;         /* max PHYs supported by chip */
+    int                 usephy;         /* which PHY to use */
 };
 
 static void pcnet32_probe_vlbus(void);
@@ -417,6 +425,7 @@ static void pcnet32_get_regs(struct net_
 static void pcnet32_purge_tx_ring(struct net_device *dev);
 static int pcnet32_alloc_ring(struct net_device *dev, char *name);
 static void pcnet32_free_ring(struct net_device *dev);
+static void pcnet32_switch_phy(struct net_device *dev, int phy);
 
 
 enum pci_flags_bit {
@@ -1336,6 +1345,20 @@ pcnet32_probe1(unsigned long ioaddr, int
     lp->mii_if.mdio_read = mdio_read;
     lp->mii_if.mdio_write = mdio_write;
 
+    lp->maxphy = 1;
+    if ((cards_found >= MAX_UNITS) || (maxphy[cards_found]))
+        lp->maxphy = maxphy[cards_found];
+
+    lp->usephy = 0;
+    if ((cards_found >= MAX_UNITS) || (usephy[cards_found]))
+        lp->usephy = usephy[cards_found];
+
+    if (lp->usephy > lp->maxphy) {
+        printk(KERN_ERR PFX "   usephy paramater out of range! ignoring!\n");
+       lp->usephy = 0;
+    }
+
+
     if (fdx && !(lp->options & PCNET32_PORT_ASEL) &&
                ((cards_found>=MAX_UNITS) || full_duplex[cards_found]))
        lp->options |= PCNET32_PORT_FD;
@@ -1358,6 +1381,15 @@ pcnet32_probe1(unsigned long ioaddr, int
            && dev->dev_addr[2] == 0x75)
        lp->options = PCNET32_PORT_FD | PCNET32_PORT_GPSI;
 
+    /*
+     * Test for specific cards to set maxphy count
+     */
+    if (lp->pci_dev->subsystem_vendor == PCI_VENDOR_ID_AT &&
+       (lp->pci_dev->subsystem_device == PCI_SUBDEVICE_ID_AT_2700FTX ||
+        lp->pci_dev->subsystem_device == PCI_SUBDEVICE_ID_AT_2701FTX)) {
+      lp->maxphy = 2;
+    }
+
     lp->init_block.mode = le16_to_cpu(0x0003); /* Disable Rx and Tx. */
     lp->init_block.tlen_rlen = le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits);
     for (i = 0; i < 6; i++)
@@ -1403,9 +1435,38 @@ pcnet32_probe1(unsigned long ioaddr, int
     }
 
     /* Set the mii phy_id so that we can query the link state */
-    if (lp->mii)
+    if (lp->mii) {
        lp->mii_if.phy_id = ((lp->a.read_bcr (ioaddr, 33)) >> 5) & 0x1f;
 
+       /* Multi PHY? */
+       if (lp->maxphy > 1) {
+           /* Autoswitch? */
+           if (lp->usephy == 0) {
+               /* backup */
+               lp->usephy = lp->mii_if.phy_id;
+
+               /* give preference to eeprom default if no link */
+               media = lp->mii_if.phy_id;
+
+               /* check link */
+               for (i = 1; i <= lp->maxphy; i++) {
+                 lp->mii_if.phy_id = i;
+                 if (mii_check_media(&lp->mii_if, 0, 1)) {
+                   media = i;
+                   /* give preference to eeprom default if link found */
+                   if (i == lp->usephy)
+                     break;
+                 }
+               }
+
+               lp->mii_if.phy_id = media;
+           } else {
+               lp->mii_if.phy_id = lp->usephy;
+           }
+           pcnet32_switch_phy(dev, lp->mii_if.phy_id);
+       }
+    }
+
     /*
      * Override options:
      * Allied Telesyn AT 2700/2701 FX are 100Mbit only and do not
@@ -1573,6 +1634,32 @@ static void pcnet32_free_ring(struct net
     }
 }
 
+static void pcnet32_switch_phy(struct net_device *dev, int phy)
+{
+    struct pcnet32_private *lp = dev->priv;
+    unsigned long ioaddr = dev->base_addr;
+    int i;
+
+    /* Isolate all unused phy's */
+    for (i = 1; i < 3; i++) {
+      if (i != phy)
+        mdio_write(dev, 1, MII_BMCR, BMCR_ISOLATE);
+    }
+
+    /* Make sure used phy is not isolated */
+    mdio_write(dev, phy, MII_BMCR,
+              mdio_read(dev, phy, MII_BMCR) & ~BMCR_ISOLATE);
+
+    /* Rearead mii regs */
+    for (i = 0; i < 5; i++) {
+      mdio_read(dev, phy, i);
+      mdio_read(dev, phy, i);
+    }
+
+    /* Store PHY */
+    lp->a.write_bcr(ioaddr, 33, ((phy & 0x1f) << 5) | MII_BMCR);
+}
+
 
 static int
 pcnet32_open(struct net_device *dev)
@@ -1654,6 +1741,16 @@ pcnet32_open(struct net_device *dev)
            if (lp->options & PCNET32_PORT_100)
                val |= 0x08;
            lp->a.write_bcr (ioaddr, 32, val);
+           /*
+            * AT 2700 FTX seems broken somehow, when disabling the
+            * DANAS the mii registers for the fiber poort need to be
+            * set.
+            */
+           if (lp->pci_dev->subsystem_vendor == PCI_VENDOR_ID_AT &&
+               lp->pci_dev->subsystem_device == PCI_SUBDEVICE_ID_AT_2700FTX &&
+               lp->mii_if.phy_id == 1) {
+             mdio_write(dev, lp->mii_if.phy_id, MII_BMCR, 0x2100);
+           }
        } else {
            if (lp->options & PCNET32_PORT_ASEL) {
                lp->a.write_bcr(ioaddr, 32,
@@ -2505,6 +2602,12 @@ MODULE_PARM_DESC(full_duplex, DRV_NAME "
 module_param_array(homepna, int, NULL, 0);
 MODULE_PARM_DESC(homepna, DRV_NAME " mode for 79C978 cards (1 for HomePNA, 0 for Ethernet, default Ethernet");
 
+/* Module parameters for PHY selection support */
+module_param_array(maxphy, int, NULL, 0);
+MODULE_PARM_DESC(maxphy, DRV_NAME " max PHYs the card supports");
+module_param_array(usephy, int, NULL, 0);
+MODULE_PARM_DESC(usephy, DRV_NAME " use specified PHY port instead of default");
+
 MODULE_AUTHOR("Thomas Bogendoerfer");
 MODULE_DESCRIPTION("Driver for PCnet32 and PCnetPCI based ethercards");
 MODULE_LICENSE("GPL");
#1 lore raw
Quoted 8 lines · Seewer Philippe

Most AMD pcnet chips support up to 32 external PHYs. This patch introduces basic PHY selection/switching support, by adding two new module parameters:

(quoted diff) +0 -2
-maxphy: how many PHYs the card supports
-usephy: which phy to use instead of eeprom default

Maxphy is necessary in order to check the range of usephy and may be overriden inside the module.

It seems a bit pointless for the range check of a user-supplied value to be driven by another user-supplied value.

Quoted 2 lines

If only maxphy is present I've implemented an algorithm which checks the link state on all PHYs and uses the one that has a link.

Knowing how many PHYs to scan is potentially useful, but how about determining that at runtime? Missing PHYs should be detectable with a timeout or similar. Too risky?

--Adam

#2 lore raw
Quoted 8 lines · Adam Kropelin
Quoted 6 lines · Seewer Philippe

Most AMD pcnet chips support up to 32 external PHYs. This patch introduces basic PHY selection/switching support, by adding two new module parameters:

(quoted diff) +0 -2
-maxphy: how many PHYs the card supports
-usephy: which phy to use instead of eeprom default
Quoted 6 lines
Quoted 2 lines

Maxphy is necessary in order to check the range of usephy and may be overriden inside the module.

It seems a bit pointless for the range check of a user-supplied value to be driven by another user-supplied value.

I just want to make sure and there's the possibility of supplying only maxphy and let the autoswitch algorithm decide...

Quoted 9 lines
Quoted 4 lines

If only maxphy is present I've implemented an algorithm which checks the link state on all PHYs and uses the one that has a link.

Knowing how many PHYs to scan is potentially useful, but how about determining that at runtime? Missing PHYs should be detectable with a timeout or similar. Too risky?

Actually its possible to query them with mii and all non-present phy's should "return" 0xffff. I wanted my changes to have no impact on pcnet cards with only one phy, thats why.

Quoted 3 lines

--Adam