rk29 vmac: improve vmac suspend & resume function
authorlyx <lyx@rock-chips.com>
Tue, 20 Sep 2011 09:38:52 +0000 (02:38 -0700)
committerlyx <lyx@rock-chips.com>
Tue, 20 Sep 2011 09:41:18 +0000 (02:41 -0700)
1.解决因为以太网卡休眠唤醒概率性死锁,导致系统重启的bug

drivers/net/rk29_vmac.c
drivers/net/rk29_vmac.h

index 561b7928179f42e6e17ea0df636aed66ea980899..e8b72fc8ba5ec06885e31330b414bddc7a0586bd 100755 (executable)
@@ -173,9 +173,9 @@ static void vmac_handle_link_change(struct net_device *dev)
 static int __devinit vmac_mii_probe(struct net_device *dev)\r
 {\r
        struct vmac_priv *ap = netdev_priv(dev);\r
-       struct phy_device *phydev = NULL;\r
-       struct clk *sys_clk;\r
-       unsigned long clock_rate;\r
+       struct phy_device *phydev = NULL;       \r
+       //struct clk *sys_clk;\r
+       //unsigned long clock_rate;\r
        int phy_addr, err;\r
 \r
        /* find the first phy */\r
@@ -234,9 +234,8 @@ static int __devinit vmac_mii_probe(struct net_device *dev)
        ap->phy_dev = phydev;\r
 \r
        return 0;\r
-\r
-err_disconnect:\r
-       phy_disconnect(phydev);\r
+//err_disconnect:\r
+//     phy_disconnect(phydev);\r
 err_out:\r
        return err;\r
 }\r
@@ -287,6 +286,7 @@ err_out_free_mdio_irq:
        kfree(ap->mii_bus->irq);\r
 err_out:\r
        mdiobus_free(ap->mii_bus);\r
+       ap->mii_bus = NULL;\r
        return err;\r
 }\r
 \r
@@ -296,10 +296,12 @@ static void vmac_mii_exit(struct net_device *dev)
 \r
        if (ap->phy_dev)\r
                phy_disconnect(ap->phy_dev);\r
-\r
-       mdiobus_unregister(ap->mii_bus);\r
-       kfree(ap->mii_bus->irq);\r
-       mdiobus_free(ap->mii_bus);\r
+       if (ap->mii_bus) {\r
+               mdiobus_unregister(ap->mii_bus);\r
+               kfree(ap->mii_bus->irq);\r
+               mdiobus_free(ap->mii_bus);\r
+               ap->mii_bus = NULL;\r
+       }\r
 }\r
 \r
 static int vmacether_get_settings(struct net_device *dev,\r
@@ -1035,6 +1037,8 @@ int vmac_open(struct net_device *dev)
        if (ap == NULL)\r
                return -ENODEV;\r
 \r
+       wake_lock_timeout(&ap->resume_lock, 5*HZ);\r
+\r
        ap->shutdown = 0;\r
                \r
        //set rmii ref clock 50MHz\r
@@ -1113,6 +1117,9 @@ int vmac_open(struct net_device *dev)
        dev_info(&ap->pdev->dev, "PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",\r
               phydev->drv->name, dev_name(&phydev->dev), phydev->irq);\r
 \r
+       ap->suspending = 0;\r
+       ap->open_flag = 1;\r
+\r
        return 0;\r
 \r
 err_free_irq:\r
@@ -1136,6 +1143,11 @@ int vmac_close(struct net_device *dev)
        struct rk29_vmac_platform_data *pdata = ap->pdev->dev.platform_data;\r
 \r
        printk("enter func %s...\n", __func__);\r
+       \r
+       if (ap->suspending == 1) \r
+               return 0;\r
+\r
+       ap->open_flag = 0;\r
 \r
        netif_stop_queue(dev);\r
        napi_disable(&ap->napi);\r
@@ -1186,68 +1198,43 @@ int vmac_close(struct net_device *dev)
        return 0;\r
 }\r
 \r
-static void rk29_init_vmac(struct net_device *dev)\r
+int vmac_shutdown(struct net_device *dev)\r
 {\r
        struct vmac_priv *ap = netdev_priv(dev);\r
        unsigned int temp;\r
-       struct clk *mac_clk = NULL;\r
-       struct rk29_vmac_platform_data *pdata = ap->pdev->dev.platform_data;\r
-\r
+       \r
        printk("enter func %s...\n", __func__);\r
-               \r
-       //set rmii ref clock 50MHz\r
-       mac_clk = clk_get(NULL, "mac_ref_div"); \r
-       clk_set_rate(mac_clk, 50000000);\r
-       clk_enable(mac_clk);\r
-       clk_enable(clk_get(NULL,"mii_rx"));\r
-       clk_enable(clk_get(NULL,"mii_tx"));\r
-       clk_enable(clk_get(NULL,"hclk_mac"));\r
-       clk_enable(clk_get(NULL,"mac_ref"));\r
-\r
-       //phy power on\r
-       if (pdata && pdata->rmii_power_control)\r
-               pdata->rmii_power_control(1);\r
 \r
-       //msleep(1000);\r
-\r
-       /* IRQ mask */\r
-       temp = RXINT_MASK | ERR_MASK | TXCH_MASK | MDIO_MASK;\r
-       vmac_writel(ap, temp, ENABLE);\r
+       netif_stop_queue(dev);\r
+       napi_disable(&ap->napi);\r
 \r
-       /* Set control */\r
-       temp = (RX_BDT_LEN << 24) | (TX_BDT_LEN << 16) | TXRN_MASK | RXRN_MASK;\r
+       /* stop running transfers */\r
+       temp = vmac_readl(ap, CONTROL);\r
+       temp &= ~(TXRN_MASK | RXRN_MASK);\r
        vmac_writel(ap, temp, CONTROL);\r
 \r
-       /* enable, after all other bits are set */\r
-       vmac_writel(ap, temp | EN_MASK, CONTROL);\r
+       del_timer_sync(&ap->rx_timeout);\r
 \r
-}\r
+       /* disable phy */\r
+       phy_stop(ap->phy_dev);\r
+       vmac_mii_exit(dev);\r
+       netif_carrier_off(dev);\r
 \r
-static void rk29_vmac_shutdown(struct net_device *dev)\r
-{\r
-       struct vmac_priv *ap = netdev_priv(dev);\r
-       struct rk29_vmac_platform_data *pdata = ap->pdev->dev.platform_data;\r
-       \r
-       printk("enter func %s...\n", __func__);\r
-                                       \r
        /* disable interrupts */\r
        vmac_writel(ap, 0, ENABLE);\r
-       \r
+       free_irq(dev->irq, dev);\r
+\r
        /* turn off vmac */\r
        vmac_writel(ap, 0, CONTROL);\r
-                       \r
-       //phy power off\r
-       if (pdata && pdata->rmii_power_control)\r
-               pdata->rmii_power_control(0);\r
-       \r
-       //clock close\r
-       clk_disable(clk_get(NULL, "mac_ref_div"));              \r
-       clk_disable(clk_get(NULL,"mii_rx"));\r
-       clk_disable(clk_get(NULL,"mii_tx"));\r
-       clk_disable(clk_get(NULL,"hclk_mac"));\r
-       clk_disable(clk_get(NULL,"mac_ref"));\r
-}\r
+       /* vmac_reset_hw(vmac) */\r
+\r
+       ap->shutdown = 1;\r
+       wmb();\r
+\r
+       free_buffers(dev);\r
 \r
+       return 0;\r
+}\r
 \r
 void vmac_update_stats(struct vmac_priv *ap)\r
 {\r
@@ -1475,7 +1462,6 @@ static int __devinit vmac_probe(struct platform_device *pdev)
        struct resource *res;\r
        unsigned int mem_base, mem_size, irq;\r
        int err;\r
-       struct clk *sys_clk;\r
        struct rk29_vmac_platform_data *pdata = pdev->dev.platform_data;\r
 \r
        dev = alloc_etherdev(sizeof(*ap));\r
@@ -1554,7 +1540,10 @@ static int __devinit vmac_probe(struct platform_device *pdev)
            dev->irq, dev->dev_addr);\r
        platform_set_drvdata(pdev, dev);\r
 \r
+       ap->suspending = 0;\r
+       ap->open_flag = 0;\r
        wake_lock_init(&idlelock, WAKE_LOCK_IDLE, "vmac");\r
+       wake_lock_init(&ap->resume_lock, WAKE_LOCK_SUSPEND, "vmac_resume");\r
 \r
        //config rk29 vmac as rmii, 100MHz \r
        if (pdata && pdata->vmac_register_set)\r
@@ -1608,19 +1597,42 @@ static int __devexit vmac_remove(struct platform_device *pdev)
        return 0;\r
 }\r
 \r
+static void rk29_vmac_power_off(struct net_device *dev)\r
+{\r
+       struct vmac_priv *ap = netdev_priv(dev);\r
+       struct rk29_vmac_platform_data *pdata = ap->pdev->dev.platform_data;\r
+\r
+       printk("enter func %s...\n", __func__);\r
+\r
+       //phy power off\r
+       if (pdata && pdata->rmii_power_control)\r
+               pdata->rmii_power_control(0);\r
+\r
+       //clock close\r
+       clk_disable(clk_get(NULL, "mac_ref_div"));\r
+       clk_disable(clk_get(NULL,"mii_rx"));\r
+       clk_disable(clk_get(NULL,"mii_tx"));\r
+       clk_disable(clk_get(NULL,"hclk_mac"));\r
+       clk_disable(clk_get(NULL,"mac_ref"));\r
+\r
+}\r
+\r
 static int\r
 rk29_vmac_suspend(struct device *dev)\r
 {\r
        struct platform_device *pdev = to_platform_device(dev);\r
        struct net_device *ndev = platform_get_drvdata(pdev);\r
-\r
+       struct vmac_priv *ap = netdev_priv(ndev);\r
+       \r
        if (ndev) {\r
-               if (netif_running(ndev)) {\r
-                       if (ndev->irq)\r
-                               disable_irq(ndev->irq);\r
+               if (ap->open_flag == 1) {\r
                        netif_stop_queue(ndev);\r
                        netif_device_detach(ndev);\r
-                       rk29_vmac_shutdown(ndev);\r
+                       if (ap->suspending == 0) {\r
+                               vmac_shutdown(ndev);\r
+                               rk29_vmac_power_off(ndev);\r
+                               ap->suspending = 1;\r
+                       }\r
                }\r
        }\r
        return 0;\r
@@ -1631,14 +1643,12 @@ rk29_vmac_resume(struct device *dev)
 {\r
        struct platform_device *pdev = to_platform_device(dev);\r
        struct net_device *ndev = platform_get_drvdata(pdev);\r
-\r
+       struct vmac_priv *ap = netdev_priv(ndev);\r
+       \r
        if (ndev) {\r
-               if (netif_running(ndev)) {\r
-                       rk29_init_vmac(ndev);\r
+               if (ap->open_flag == 1) {\r
                        netif_device_attach(ndev);\r
                        netif_start_queue(ndev);\r
-                       if (ndev->irq)\r
-                               enable_irq(ndev->irq);\r
                }\r
        }\r
        return 0;\r
index eb962d80b549744645306f9241abdeefbc65c754..a1f67c07fb37f8b4e3791df1b69392e0af2f5735 100755 (executable)
@@ -183,6 +183,10 @@ struct     vmac_priv {
        int speed;\r
        int duplex;\r
 \r
+       int open_flag;\r
+       int suspending;\r
+       struct wake_lock resume_lock;\r
+\r
        /* debug */\r
        int shutdown;\r
 };\r