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)
}
}
+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);
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
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)
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;