u32 msg_enable;
u32 phy_type;
struct mii_if_info mii;
+
+ /* work queue */
struct work_struct phy_configure;
+ int work_pending;
spinlock_t lock;
/*
* Finds and reports the PHY address
*/
-static void smc_detect_phy(struct net_device *dev)
+static void smc_phy_detect(struct net_device *dev)
{
struct smc_local *lp = netdev_priv(dev);
int phyaddr;
smc_phy_configure_exit:
spin_unlock_irq(&lp->lock);
+ lp->work_pending = 0;
}
/*
/*
* Reconfiguring the PHY doesn't seem like a bad idea here, but
* smc_phy_configure() calls msleep() which calls schedule_timeout()
- * which calls schedule(). Ence we use a work queue.
+ * which calls schedule(). Hence we use a work queue.
*/
- if (lp->phy_type != 0)
- schedule_work(&lp->phy_configure);
+ if (lp->phy_type != 0) {
+ if (schedule_work(&lp->phy_configure)) {
+ lp->work_pending = 1;
+ }
+ }
/* We can accept TX packets again */
dev->trans_start = jiffies;
smc_shutdown(dev);
if (lp->phy_type != 0) {
- flush_scheduled_work();
+ /* We need to ensure that no calls to
+ smc_phy_configure are pending.
+
+ flush_scheduled_work() cannot be called because we
+ are running with the netlink semaphore held (from
+ devinet_ioctl()) and the pending work queue
+ contains linkwatch_event() (scheduled by
+ netif_carrier_off() above). linkwatch_event() also
+ wants the netlink semaphore.
+ */
+ while(lp->work_pending)
+ schedule();
smc_phy_powerdown(dev, lp->mii.phy_id);
}
* Locate the phy, if any.
*/
if (lp->version >= (CHIP_91100 << 4))
- smc_detect_phy(dev);
+ smc_phy_detect(dev);
/* Set default parameters */
lp->msg_enable = NETIF_MSG_LINK;