Fixes a soft reset timeout that occurs when the driver is
built as a module and gets reloaded.  On module unload the
phy gets put into power down mode, on a reload the soft
reset fails if the internal phy is in power down mode.
Also put a fix in to revert to using the internal phy
if the search for an external phy failed.

Signed-off-by: Jason Borg <[EMAIL PROTECTED]>
---

diff -uprN linux-2.6.18-rc4-orig/drivers/net/smc911x.c 
linux-2.6.18-rc4/drivers/net/smc911x.c
--- linux-2.6.18-rc4-orig/drivers/net/smc911x.c 2006-08-22 15:57:41.972128970 
-0400
+++ linux-2.6.18-rc4/drivers/net/smc911x.c      2006-08-22 15:58:28.210813025 
-0400
@@ -231,6 +231,86 @@ static void PRINT_PKT(u_char *buf, int l
        spin_unlock_irqrestore(&lp->lock, __flags);     \
 } while (0)
 
+static void smc911x_connect_int_phy (struct net_device *dev)
+{
+       unsigned long ioaddr = dev->base_addr;
+       unsigned int cfg;
+
+       cfg = SMC_GET_HW_CFG();
+
+       cfg &= ~HW_CFG_PHY_CLK_SEL_;
+       cfg |= HW_CFG_PHY_CLK_SEL_CLK_DIS_;
+       SMC_SET_HW_CFG(cfg);
+       udelay(10); /* Wait for clocks to stop */
+
+       cfg &= ~HW_CFG_EXT_PHY_EN_;
+       SMC_SET_HW_CFG(cfg);
+       udelay(10); /* Wait for clocks to stop */
+
+       cfg &= ~HW_CFG_PHY_CLK_SEL_;
+       cfg |= HW_CFG_PHY_CLK_SEL_INT_PHY_;
+       SMC_SET_HW_CFG(cfg);
+       udelay(10); /* Wait for clocks to stop */
+
+       cfg &= ~HW_CFG_SMI_SEL_;
+       SMC_SET_HW_CFG(cfg);
+}
+
+static void smc911x_connect_ext_phy (struct net_device *dev)
+{
+       unsigned long ioaddr = dev->base_addr;
+       unsigned int cfg;
+
+       cfg = SMC_GET_HW_CFG();
+
+       cfg &= ~HW_CFG_PHY_CLK_SEL_;
+       cfg |= HW_CFG_PHY_CLK_SEL_CLK_DIS_;
+       SMC_SET_HW_CFG(cfg);
+       udelay(10); /* Wait for clocks to stop */
+
+       cfg |= HW_CFG_EXT_PHY_EN_;
+       SMC_SET_HW_CFG(cfg);
+       udelay(10); /* Wait for clocks to stop */
+
+       cfg &= ~HW_CFG_PHY_CLK_SEL_;
+       cfg |= HW_CFG_PHY_CLK_SEL_EXT_PHY_;
+       SMC_SET_HW_CFG(cfg);
+       udelay(10); /* Wait for clocks to stop */
+
+       cfg |= HW_CFG_SMI_SEL_;
+       SMC_SET_HW_CFG(cfg);
+}
+
+/*
+ * Called before doing a soft reset.  If the internal phy is in
+ * power down mode, the soft reset will fail and timeout.
+ * The internal phy being in power down mode will not prevent
+ * the Device Ready bit (bit 0) of the PMT_CONTROL register
+ * from reading 1 (device is ready), so a specific check must
+ * be carried out.
+ */
+static void smc911x_srst_phy_pdown_check(struct net_device *dev)
+{
+       unsigned long ioaddr = dev->base_addr;
+       unsigned int bmcr;
+
+       /*
+        * Make sure the internal phy is connected, don't need to worry
+        * about checking for and reconnecting the external phy if it
+        * was connected, since the soft reset will clear the phy
+        * selection bits anyway.
+        */
+       smc911x_connect_int_phy(dev);
+
+       SMC_GET_PHY_BMCR(LAN911X_INTERNAL_PHY_ADDR, bmcr);
+
+       if (bmcr & BMCR_PDOWN) {
+               bmcr &= ~BMCR_PDOWN;
+               SMC_SET_PHY_BMCR(LAN911X_INTERNAL_PHY_ADDR, bmcr);
+               udelay(500); /* give it time to get up and running */
+       }
+}
+
 /*
  * this does a soft reset on the device
  */
@@ -258,6 +338,9 @@ static void smc911x_reset(struct net_dev
                }
        }
 
+       /* Ensure the internal phy is not in power down mode */
+       smc911x_srst_phy_pdown_check(dev);
+
        /* Disable all interrupts */
        spin_lock_irqsave(&lp->lock, flags);
        SMC_SET_INT_EN(0);
@@ -755,22 +838,7 @@ static void smc911x_phy_detect(struct ne
                case 0x117:
                        cfg = SMC_GET_HW_CFG();
                        if (cfg & HW_CFG_EXT_PHY_DET_) {
-                               cfg &= ~HW_CFG_PHY_CLK_SEL_;
-                               cfg |= HW_CFG_PHY_CLK_SEL_CLK_DIS_;
-                               SMC_SET_HW_CFG(cfg);
-                               udelay(10); /* Wait for clocks to stop */
-
-                               cfg |= HW_CFG_EXT_PHY_EN_;
-                               SMC_SET_HW_CFG(cfg);
-                               udelay(10); /* Wait for clocks to stop */
-
-                               cfg &= ~HW_CFG_PHY_CLK_SEL_;
-                               cfg |= HW_CFG_PHY_CLK_SEL_EXT_PHY_;
-                               SMC_SET_HW_CFG(cfg);
-                               udelay(10); /* Wait for clocks to stop */
-
-                               cfg |= HW_CFG_SMI_SEL_;
-                               SMC_SET_HW_CFG(cfg);
+                               smc911x_connect_ext_phy(dev);
 
                                for (phyaddr = 1; phyaddr < 32; ++phyaddr) {
 
@@ -788,13 +856,18 @@ static void smc911x_phy_detect(struct ne
                                                break;
                                        }
                                }
+
+                               PRINTK ("%s: No external phy found, using 
internal\n", dev->name);
+                                
+                               /* Revert to the internal phy settings */
+                               smc911x_connect_int_phy(dev);
                        }
                default:
                        /* Internal media only */
                        SMC_GET_PHY_ID1(1, id1);
                        SMC_GET_PHY_ID2(1, id2);
                        /* Save the PHY's address */
-                       lp->mii.phy_id = 1;
+                       lp->mii.phy_id = LAN911X_INTERNAL_PHY_ADDR;
                        lp->phy_type = id1 << 16 | id2;
        }
 
diff -uprN linux-2.6.18-rc4-orig/drivers/net/smc911x.h 
linux-2.6.18-rc4/drivers/net/smc911x.h
--- linux-2.6.18-rc4-orig/drivers/net/smc911x.h 2006-08-22 12:02:50.000000000 
-0400
+++ linux-2.6.18-rc4/drivers/net/smc911x.h      2006-08-22 16:21:24.951247991 
-0400
@@ -596,6 +596,7 @@ smc_pxa_dma_outsw(struct device *dev, u_
 #define PHY_SPECIAL_SPD_100FULL_               ((u16)0x0018)
 
 #define LAN911X_INTERNAL_PHY_ID                (0x0007C000)
+#define LAN911X_INTERNAL_PHY_ADDR      1
 
 /* Chip ID values */
 #define CHIP_9115      0x115


-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to