]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/ucc_geth.c
ucc_geth: Fix IRQ freeing code in ucc_geth_open()
[linux-2.6-omap-h63xx.git] / drivers / net / ucc_geth.c
index c87747bb24c55eb9ea2ac58992eabfdf348b664b..3d1966c34d29c55052d6e8bf71b7af9f9d35f652 100644 (file)
@@ -1615,8 +1615,8 @@ static int init_phy(struct net_device *dev)
        priv->oldspeed = 0;
        priv->oldduplex = -1;
 
-       snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, priv->ug_info->mdio_bus,
-                       priv->ug_info->phy_address);
+       snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, priv->ug_info->mdio_bus,
+                priv->ug_info->phy_address);
 
        phydev = phy_connect(dev, phy_id, &adjust_link, 0, priv->phy_interface);
 
@@ -1647,6 +1647,7 @@ static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth)
        struct ucc_fast_private *uccf;
        u32 cecr_subblock;
        u32 temp;
+       int i = 10;
 
        uccf = ugeth->uccf;
 
@@ -1664,8 +1665,9 @@ static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth)
 
        /* Wait for command to complete */
        do {
+               msleep(10);
                temp = in_be32(uccf->p_ucce);
-       } while (!(temp & UCCE_GRA));
+       } while (!(temp & UCCE_GRA) && --i);
 
        uccf->stopped_tx = 1;
 
@@ -1677,6 +1679,7 @@ static int ugeth_graceful_stop_rx(struct ucc_geth_private * ugeth)
        struct ucc_fast_private *uccf;
        u32 cecr_subblock;
        u8 temp;
+       int i = 10;
 
        uccf = ugeth->uccf;
 
@@ -1694,9 +1697,9 @@ static int ugeth_graceful_stop_rx(struct ucc_geth_private * ugeth)
                                                ucc_num);
                qe_issue_cmd(QE_GRACEFUL_STOP_RX, cecr_subblock,
                             QE_CR_PROTOCOL_ETHERNET, 0);
-
+               msleep(10);
                temp = in_8(&ugeth->p_rx_glbl_pram->rxgstpack);
-       } while (!(temp & GRACEFUL_STOP_ACKNOWLEDGE_RX));
+       } while (!(temp & GRACEFUL_STOP_ACKNOWLEDGE_RX) && --i);
 
        uccf->stopped_rx = 1;
 
@@ -2297,8 +2300,6 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth)
        tempval &= ~(MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX);
        out_be32(&ug_regs->maccfg1, tempval);
 
-       free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev);
-
        ucc_geth_memclean(ugeth);
 }
 
@@ -3352,13 +3353,17 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
        return 0;
 }
 
-/* ucc_geth_timeout gets called when a packet has not been
- * transmitted after a set amount of time.
- * For now, assume that clearing out all the structures, and
- * starting over will fix the problem. */
-static void ucc_geth_timeout(struct net_device *dev)
+static int ucc_geth_close(struct net_device *dev);
+static int ucc_geth_open(struct net_device *dev);
+
+/* Reopen device. This will reset the MAC and PHY. */
+static void ucc_geth_timeout_work(struct work_struct *work)
 {
-       struct ucc_geth_private *ugeth = netdev_priv(dev);
+       struct ucc_geth_private *ugeth;
+       struct net_device *dev;
+
+       ugeth = container_of(work, struct ucc_geth_private, timeout_work);
+       dev = ugeth->dev;
 
        ugeth_vdbg("%s: IN", __func__);
 
@@ -3367,13 +3372,29 @@ static void ucc_geth_timeout(struct net_device *dev)
        ugeth_dump_regs(ugeth);
 
        if (dev->flags & IFF_UP) {
-               ucc_geth_stop(ugeth);
-               ucc_geth_startup(ugeth);
+               /*
+                * Must reset MAC *and* PHY. This is done by reopening
+                * the device.
+                */
+               ucc_geth_close(dev);
+               ucc_geth_open(dev);
        }
 
        netif_tx_schedule_all(dev);
 }
 
+/*
+ * ucc_geth_timeout gets called when a packet has not been
+ * transmitted after a set amount of time.
+ */
+static void ucc_geth_timeout(struct net_device *dev)
+{
+       struct ucc_geth_private *ugeth = netdev_priv(dev);
+
+       netif_carrier_off(dev);
+       schedule_work(&ugeth->timeout_work);
+}
+
 /* This is called by the kernel when a frame is ready for transmission. */
 /* It is pointed to by the dev->hard_start_xmit function pointer */
 static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -3502,8 +3523,6 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
                        netif_receive_skb(skb);
                }
 
-               ugeth->dev->last_rx = jiffies;
-
                skb = get_new_skb(ugeth, bd);
                if (!skb) {
                        if (netif_msg_rx_err(ugeth))
@@ -3738,21 +3757,20 @@ static int ucc_geth_open(struct net_device *dev)
 
        phy_start(ugeth->phydev);
 
-       err =
-           request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler, 0,
-                       "UCC Geth", dev);
+       err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX);
        if (err) {
                if (netif_msg_ifup(ugeth))
-                       ugeth_err("%s: Cannot get IRQ for net device, aborting.",
-                                 dev->name);
+                       ugeth_err("%s: Cannot enable net device, aborting.", dev->name);
                ucc_geth_stop(ugeth);
                goto out_err;
        }
 
-       err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX);
+       err = request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler,
+                         0, "UCC Geth", dev);
        if (err) {
                if (netif_msg_ifup(ugeth))
-                       ugeth_err("%s: Cannot enable net device, aborting.", dev->name);
+                       ugeth_err("%s: Cannot get IRQ for net device, aborting.",
+                                 dev->name);
                ucc_geth_stop(ugeth);
                goto out_err;
        }
@@ -3778,6 +3796,8 @@ static int ucc_geth_close(struct net_device *dev)
 
        ucc_geth_stop(ugeth);
 
+       free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev);
+
        phy_disconnect(ugeth->phydev);
        ugeth->phydev = NULL;
 
@@ -4026,6 +4046,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
        dev->hard_start_xmit = ucc_geth_start_xmit;
        dev->tx_timeout = ucc_geth_timeout;
        dev->watchdog_timeo = TX_TIMEOUT;
+       INIT_WORK(&ugeth->timeout_work, ucc_geth_timeout_work);
        netif_napi_add(dev, &ugeth->napi, ucc_geth_poll, UCC_GETH_DEV_WEIGHT);
 #ifdef CONFIG_NET_POLL_CONTROLLER
        dev->poll_controller = ucc_netpoll;