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