net/cpsw: don't rely only on netif_running() to check which device is active
[deliverable/linux.git] / drivers / net / ethernet / ti / cpsw.c
index 5cf8d03b8cae429a73a89faf1b96db36383d0390..ff0d528204ab1816517463fa0829298a3cbe766c 100644 (file)
@@ -510,20 +510,31 @@ void cpsw_rx_handler(void *token, int len, int status)
 static irqreturn_t cpsw_interrupt(int irq, void *dev_id)
 {
        struct cpsw_priv *priv = dev_id;
+       u32 rx, tx, rx_thresh;
 
-       if (likely(netif_running(priv->ndev))) {
-               cpsw_intr_disable(priv);
-               cpsw_disable_irq(priv);
+       rx_thresh = __raw_readl(&priv->wr_regs->rx_thresh_stat);
+       rx = __raw_readl(&priv->wr_regs->rx_stat);
+       tx = __raw_readl(&priv->wr_regs->tx_stat);
+       if (!rx_thresh && !rx && !tx)
+               return IRQ_NONE;
+
+       cpsw_intr_disable(priv);
+       cpsw_disable_irq(priv);
+
+       if (netif_running(priv->ndev)) {
                napi_schedule(&priv->napi);
-       } else {
-               priv = cpsw_get_slave_priv(priv, 1);
-               if (likely(priv) && likely(netif_running(priv->ndev))) {
-                       cpsw_intr_disable(priv);
-                       cpsw_disable_irq(priv);
-                       napi_schedule(&priv->napi);
-               }
+               return IRQ_HANDLED;
+       }
+
+       priv = cpsw_get_slave_priv(priv, 1);
+       if (!priv)
+               return IRQ_NONE;
+
+       if (netif_running(priv->ndev)) {
+               napi_schedule(&priv->napi);
+               return IRQ_HANDLED;
        }
-       return IRQ_HANDLED;
+       return IRQ_NONE;
 }
 
 static int cpsw_poll(struct napi_struct *napi, int budget)
@@ -867,6 +878,15 @@ static void cpsw_init_host_port(struct cpsw_priv *priv)
        }
 }
 
+static void cpsw_slave_stop(struct cpsw_slave *slave, struct cpsw_priv *priv)
+{
+       if (!slave->phy)
+               return;
+       phy_stop(slave->phy);
+       phy_disconnect(slave->phy);
+       slave->phy = NULL;
+}
+
 static int cpsw_ndo_open(struct net_device *ndev)
 {
        struct cpsw_priv *priv = netdev_priv(ndev);
@@ -912,14 +932,16 @@ static int cpsw_ndo_open(struct net_device *ndev)
                        struct sk_buff *skb;
 
                        ret = -ENOMEM;
-                       skb = netdev_alloc_skb_ip_align(priv->ndev,
-                                                       priv->rx_packet_max);
+                       skb = __netdev_alloc_skb_ip_align(priv->ndev,
+                                       priv->rx_packet_max, GFP_KERNEL);
                        if (!skb)
-                               break;
+                               goto err_cleanup;
                        ret = cpdma_chan_submit(priv->rxch, skb, skb->data,
                                        skb_tailroom(skb), 0, GFP_KERNEL);
-                       if (WARN_ON(ret < 0))
-                               break;
+                       if (ret < 0) {
+                               kfree_skb(skb);
+                               goto err_cleanup;
+                       }
                }
                /* continue even if we didn't manage to submit all
                 * receive descs
@@ -944,15 +966,13 @@ static int cpsw_ndo_open(struct net_device *ndev)
        if (priv->data.dual_emac)
                priv->slaves[priv->emac_port].open_stat = true;
        return 0;
-}
 
-static void cpsw_slave_stop(struct cpsw_slave *slave, struct cpsw_priv *priv)
-{
-       if (!slave->phy)
-               return;
-       phy_stop(slave->phy);
-       phy_disconnect(slave->phy);
-       slave->phy = NULL;
+err_cleanup:
+       cpdma_ctlr_stop(priv->dma);
+       for_each_slave(priv, cpsw_slave_stop, priv);
+       pm_runtime_put_sync(&priv->pdev->dev);
+       netif_carrier_off(priv->ndev);
+       return ret;
 }
 
 static int cpsw_ndo_stop(struct net_device *ndev)
@@ -1520,7 +1540,7 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
                        memcpy(slave_data->mac_addr, mac_addr, ETH_ALEN);
 
                if (data->dual_emac) {
-                       if (of_property_read_u32(node, "dual_emac_res_vlan",
+                       if (of_property_read_u32(slave_node, "dual_emac_res_vlan",
                                                 &prop)) {
                                pr_err("Missing dual_emac_res_vlan in DT.\n");
                                slave_data->dual_emac_res_vlan = i+1;
This page took 0.028071 seconds and 5 git commands to generate.