diff options
Diffstat (limited to 'drivers/net/ethernet/broadcom/genet/bcmgenet.c')
-rw-r--r-- | drivers/net/ethernet/broadcom/genet/bcmgenet.c | 1089 |
1 files changed, 494 insertions, 595 deletions
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 3e93f957430b..73d78dcb774d 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -2,7 +2,7 @@ /* * Broadcom GENET (Gigabit Ethernet) controller driver * - * Copyright (c) 2014-2024 Broadcom + * Copyright (c) 2014-2025 Broadcom */ #define pr_fmt(fmt) "bcmgenet: " fmt @@ -41,15 +41,13 @@ #include "bcmgenet.h" -/* Maximum number of hardware queues, downsized if needed */ -#define GENET_MAX_MQ_CNT 4 - /* Default highest priority queue for multi queue support */ -#define GENET_Q0_PRIORITY 0 +#define GENET_Q1_PRIORITY 0 +#define GENET_Q0_PRIORITY 1 -#define GENET_Q16_RX_BD_CNT \ +#define GENET_Q0_RX_BD_CNT \ (TOTAL_DESC - priv->hw_params->rx_queues * priv->hw_params->rx_bds_per_q) -#define GENET_Q16_TX_BD_CNT \ +#define GENET_Q0_TX_BD_CNT \ (TOTAL_DESC - priv->hw_params->tx_queues * priv->hw_params->tx_bds_per_q) #define RX_BUF_LENGTH 2048 @@ -104,7 +102,7 @@ static inline void dmadesc_set_addr(struct bcmgenet_priv *priv, * the platform is explicitly configured for 64-bits/LPAE. */ #ifdef CONFIG_PHYS_ADDR_T_64BIT - if (priv->hw_params->flags & GENET_HAS_40BITS) + if (bcmgenet_has_40bits(priv)) bcmgenet_writel(upper_32_bits(addr), d + DMA_DESC_ADDRESS_HI); #endif } @@ -446,33 +444,48 @@ static void bcmgenet_hfb_enable_filter(struct bcmgenet_priv *priv, u32 f_index) u32 offset; u32 reg; - offset = HFB_FLT_ENABLE_V3PLUS + (f_index < 32) * sizeof(u32); - reg = bcmgenet_hfb_reg_readl(priv, offset); - reg |= (1 << (f_index % 32)); - bcmgenet_hfb_reg_writel(priv, reg, offset); - reg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL); - reg |= RBUF_HFB_EN; - bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL); + if (GENET_IS_V1(priv) || GENET_IS_V2(priv)) { + reg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL); + reg |= (1 << ((f_index % 32) + RBUF_HFB_FILTER_EN_SHIFT)) | + RBUF_HFB_EN; + bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL); + } else { + offset = HFB_FLT_ENABLE_V3PLUS + (f_index < 32) * sizeof(u32); + reg = bcmgenet_hfb_reg_readl(priv, offset); + reg |= (1 << (f_index % 32)); + bcmgenet_hfb_reg_writel(priv, reg, offset); + reg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL); + reg |= RBUF_HFB_EN; + bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL); + } } static void bcmgenet_hfb_disable_filter(struct bcmgenet_priv *priv, u32 f_index) { u32 offset, reg, reg1; - offset = HFB_FLT_ENABLE_V3PLUS; - reg = bcmgenet_hfb_reg_readl(priv, offset); - reg1 = bcmgenet_hfb_reg_readl(priv, offset + sizeof(u32)); - if (f_index < 32) { - reg1 &= ~(1 << (f_index % 32)); - bcmgenet_hfb_reg_writel(priv, reg1, offset + sizeof(u32)); - } else { - reg &= ~(1 << (f_index % 32)); - bcmgenet_hfb_reg_writel(priv, reg, offset); - } - if (!reg && !reg1) { + if (GENET_IS_V1(priv) || GENET_IS_V2(priv)) { reg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL); - reg &= ~RBUF_HFB_EN; + reg &= ~(1 << ((f_index % 32) + RBUF_HFB_FILTER_EN_SHIFT)); + if (!(reg & RBUF_HFB_FILTER_EN_MASK)) + reg &= ~RBUF_HFB_EN; bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL); + } else { + offset = HFB_FLT_ENABLE_V3PLUS; + reg = bcmgenet_hfb_reg_readl(priv, offset); + reg1 = bcmgenet_hfb_reg_readl(priv, offset + sizeof(u32)); + if (f_index < 32) { + reg1 &= ~(1 << (f_index % 32)); + bcmgenet_hfb_reg_writel(priv, reg1, offset + sizeof(u32)); + } else { + reg &= ~(1 << (f_index % 32)); + bcmgenet_hfb_reg_writel(priv, reg, offset); + } + if (!reg && !reg1) { + reg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL); + reg &= ~RBUF_HFB_EN; + bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL); + } } } @@ -482,6 +495,9 @@ static void bcmgenet_hfb_set_filter_rx_queue_mapping(struct bcmgenet_priv *priv, u32 offset; u32 reg; + if (GENET_IS_V1(priv) || GENET_IS_V2(priv)) + return; + offset = f_index / 8; reg = bcmgenet_rdma_readl(priv, DMA_INDEX2RING_0 + offset); reg &= ~(0xF << (4 * (f_index % 8))); @@ -495,9 +511,13 @@ static void bcmgenet_hfb_set_filter_length(struct bcmgenet_priv *priv, u32 offset; u32 reg; - offset = HFB_FLT_LEN_V3PLUS + - ((priv->hw_params->hfb_filter_cnt - 1 - f_index) / 4) * - sizeof(u32); + if (GENET_IS_V1(priv) || GENET_IS_V2(priv)) + offset = HFB_FLT_LEN_V2; + else + offset = HFB_FLT_LEN_V3PLUS; + + offset += sizeof(u32) * + ((priv->hw_params->hfb_filter_cnt - 1 - f_index) / 4); reg = bcmgenet_hfb_reg_readl(priv, offset); reg &= ~(0xFF << (8 * (f_index % 4))); reg |= ((f_length & 0xFF) << (8 * (f_index % 4))); @@ -579,13 +599,13 @@ static void bcmgenet_hfb_create_rxnfc_filter(struct bcmgenet_priv *priv, struct bcmgenet_rxnfc_rule *rule) { struct ethtool_rx_flow_spec *fs = &rule->fs; - u32 offset = 0, f_length = 0, f; + u32 offset = 0, f_length = 0, f, q; u8 val_8, mask_8; __be16 val_16; u16 mask_16; size_t size; - f = fs->location; + f = fs->location + 1; if (fs->flow_type & FLOW_MAC_EXT) { bcmgenet_hfb_insert_data(priv, f, 0, &fs->h_ext.h_dest, &fs->m_ext.h_dest, @@ -667,19 +687,16 @@ static void bcmgenet_hfb_create_rxnfc_filter(struct bcmgenet_priv *priv, } bcmgenet_hfb_set_filter_length(priv, f, 2 * f_length); - if (!fs->ring_cookie || fs->ring_cookie == RX_CLS_FLOW_WAKE) { - /* Ring 0 flows can be handled by the default Descriptor Ring - * We'll map them to ring 0, but don't enable the filter - */ - bcmgenet_hfb_set_filter_rx_queue_mapping(priv, f, 0); - rule->state = BCMGENET_RXNFC_STATE_DISABLED; - } else { + if (fs->ring_cookie == RX_CLS_FLOW_WAKE) + q = 0; + else if (fs->ring_cookie == RX_CLS_FLOW_DISC) + q = priv->hw_params->rx_queues + 1; + else /* Other Rx rings are direct mapped here */ - bcmgenet_hfb_set_filter_rx_queue_mapping(priv, f, - fs->ring_cookie); - bcmgenet_hfb_enable_filter(priv, f); - rule->state = BCMGENET_RXNFC_STATE_ENABLED; - } + q = fs->ring_cookie; + bcmgenet_hfb_set_filter_rx_queue_mapping(priv, f, q); + bcmgenet_hfb_enable_filter(priv, f); + rule->state = BCMGENET_RXNFC_STATE_ENABLED; } /* bcmgenet_hfb_clear @@ -690,6 +707,7 @@ static void bcmgenet_hfb_clear_filter(struct bcmgenet_priv *priv, u32 f_index) { u32 base, i; + bcmgenet_hfb_set_filter_length(priv, f_index, 0); base = f_index * priv->hw_params->hfb_filter_size; for (i = 0; i < priv->hw_params->hfb_filter_size; i++) bcmgenet_hfb_writel(priv, 0x0, (base + i) * sizeof(u32)); @@ -699,22 +717,23 @@ static void bcmgenet_hfb_clear(struct bcmgenet_priv *priv) { u32 i; - if (GENET_IS_V1(priv) || GENET_IS_V2(priv)) - return; - - bcmgenet_hfb_reg_writel(priv, 0x0, HFB_CTRL); - bcmgenet_hfb_reg_writel(priv, 0x0, HFB_FLT_ENABLE_V3PLUS); - bcmgenet_hfb_reg_writel(priv, 0x0, HFB_FLT_ENABLE_V3PLUS + 4); - - for (i = DMA_INDEX2RING_0; i <= DMA_INDEX2RING_7; i++) - bcmgenet_rdma_writel(priv, 0x0, i); + bcmgenet_hfb_reg_writel(priv, 0, HFB_CTRL); - for (i = 0; i < (priv->hw_params->hfb_filter_cnt / 4); i++) - bcmgenet_hfb_reg_writel(priv, 0x0, - HFB_FLT_LEN_V3PLUS + i * sizeof(u32)); + if (!GENET_IS_V1(priv) && !GENET_IS_V2(priv)) { + bcmgenet_hfb_reg_writel(priv, 0, + HFB_FLT_ENABLE_V3PLUS); + bcmgenet_hfb_reg_writel(priv, 0, + HFB_FLT_ENABLE_V3PLUS + 4); + for (i = DMA_INDEX2RING_0; i <= DMA_INDEX2RING_7; i++) + bcmgenet_rdma_writel(priv, 0, i); + } for (i = 0; i < priv->hw_params->hfb_filter_cnt; i++) bcmgenet_hfb_clear_filter(priv, i); + + /* Enable filter 0 to send default flow to ring 0 */ + bcmgenet_hfb_set_filter_length(priv, 0, 4); + bcmgenet_hfb_enable_filter(priv, 0); } static void bcmgenet_hfb_init(struct bcmgenet_priv *priv) @@ -722,9 +741,6 @@ static void bcmgenet_hfb_init(struct bcmgenet_priv *priv) int i; INIT_LIST_HEAD(&priv->rxnfc_list); - if (GENET_IS_V1(priv) || GENET_IS_V2(priv)) - return; - for (i = 0; i < MAX_NUM_OF_FS_RULES; i++) { INIT_LIST_HEAD(&priv->rxnfc_rules[i].list); priv->rxnfc_rules[i].state = BCMGENET_RXNFC_STATE_UNUSED; @@ -819,20 +835,16 @@ static int bcmgenet_get_coalesce(struct net_device *dev, unsigned int i; ec->tx_max_coalesced_frames = - bcmgenet_tdma_ring_readl(priv, DESC_INDEX, - DMA_MBUF_DONE_THRESH); + bcmgenet_tdma_ring_readl(priv, 0, DMA_MBUF_DONE_THRESH); ec->rx_max_coalesced_frames = - bcmgenet_rdma_ring_readl(priv, DESC_INDEX, - DMA_MBUF_DONE_THRESH); + bcmgenet_rdma_ring_readl(priv, 0, DMA_MBUF_DONE_THRESH); ec->rx_coalesce_usecs = - bcmgenet_rdma_readl(priv, DMA_RING16_TIMEOUT) * 8192 / 1000; + bcmgenet_rdma_readl(priv, DMA_RING0_TIMEOUT) * 8192 / 1000; - for (i = 0; i < priv->hw_params->rx_queues; i++) { + for (i = 0; i <= priv->hw_params->rx_queues; i++) { ring = &priv->rx_rings[i]; ec->use_adaptive_rx_coalesce |= ring->dim.use_dim; } - ring = &priv->rx_rings[DESC_INDEX]; - ec->use_adaptive_rx_coalesce |= ring->dim.use_dim; return 0; } @@ -902,17 +914,13 @@ static int bcmgenet_set_coalesce(struct net_device *dev, /* Program all TX queues with the same values, as there is no * ethtool knob to do coalescing on a per-queue basis */ - for (i = 0; i < priv->hw_params->tx_queues; i++) + for (i = 0; i <= priv->hw_params->tx_queues; i++) bcmgenet_tdma_ring_writel(priv, i, ec->tx_max_coalesced_frames, DMA_MBUF_DONE_THRESH); - bcmgenet_tdma_ring_writel(priv, DESC_INDEX, - ec->tx_max_coalesced_frames, - DMA_MBUF_DONE_THRESH); - for (i = 0; i < priv->hw_params->rx_queues; i++) + for (i = 0; i <= priv->hw_params->rx_queues; i++) bcmgenet_set_ring_rx_coalesce(&priv->rx_rings[i], ec); - bcmgenet_set_ring_rx_coalesce(&priv->rx_rings[DESC_INDEX], ec); return 0; } @@ -1120,7 +1128,7 @@ static const struct bcmgenet_stats bcmgenet_gstrings_stats[] = { STAT_GENET_Q(1), STAT_GENET_Q(2), STAT_GENET_Q(3), - STAT_GENET_Q(16), + STAT_GENET_Q(4), }; #define BCMGENET_STATS_LEN ARRAY_SIZE(bcmgenet_gstrings_stats) @@ -1438,7 +1446,8 @@ static int bcmgenet_insert_flow(struct net_device *dev, } if (cmd->fs.ring_cookie > priv->hw_params->rx_queues && - cmd->fs.ring_cookie != RX_CLS_FLOW_WAKE) { + cmd->fs.ring_cookie != RX_CLS_FLOW_WAKE && + cmd->fs.ring_cookie != RX_CLS_FLOW_DISC) { netdev_err(dev, "rxnfc: Unsupported action (%llu)\n", cmd->fs.ring_cookie); return -EINVAL; @@ -1472,10 +1481,10 @@ static int bcmgenet_insert_flow(struct net_device *dev, loc_rule = &priv->rxnfc_rules[cmd->fs.location]; } if (loc_rule->state == BCMGENET_RXNFC_STATE_ENABLED) - bcmgenet_hfb_disable_filter(priv, cmd->fs.location); + bcmgenet_hfb_disable_filter(priv, cmd->fs.location + 1); if (loc_rule->state != BCMGENET_RXNFC_STATE_UNUSED) { list_del(&loc_rule->list); - bcmgenet_hfb_clear_filter(priv, cmd->fs.location); + bcmgenet_hfb_clear_filter(priv, cmd->fs.location + 1); } loc_rule->state = BCMGENET_RXNFC_STATE_UNUSED; memcpy(&loc_rule->fs, &cmd->fs, @@ -1505,10 +1514,10 @@ static int bcmgenet_delete_flow(struct net_device *dev, } if (rule->state == BCMGENET_RXNFC_STATE_ENABLED) - bcmgenet_hfb_disable_filter(priv, cmd->fs.location); + bcmgenet_hfb_disable_filter(priv, cmd->fs.location + 1); if (rule->state != BCMGENET_RXNFC_STATE_UNUSED) { list_del(&rule->list); - bcmgenet_hfb_clear_filter(priv, cmd->fs.location); + bcmgenet_hfb_clear_filter(priv, cmd->fs.location + 1); } rule->state = BCMGENET_RXNFC_STATE_UNUSED; memset(&rule->fs, 0, sizeof(struct ethtool_rx_flow_spec)); @@ -1651,9 +1660,9 @@ static int bcmgenet_power_down(struct bcmgenet_priv *priv, case GENET_POWER_PASSIVE: /* Power down LED */ - if (priv->hw_params->flags & GENET_HAS_EXT) { + if (bcmgenet_has_ext(priv)) { reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); - if (GENET_IS_V5(priv) && !priv->ephy_16nm) + if (GENET_IS_V5(priv) && !bcmgenet_has_ephy_16nm(priv)) reg |= EXT_PWR_DOWN_PHY_EN | EXT_PWR_DOWN_PHY_RD | EXT_PWR_DOWN_PHY_SD | @@ -1676,13 +1685,14 @@ static int bcmgenet_power_down(struct bcmgenet_priv *priv, return ret; } -static void bcmgenet_power_up(struct bcmgenet_priv *priv, - enum bcmgenet_power_mode mode) +static int bcmgenet_power_up(struct bcmgenet_priv *priv, + enum bcmgenet_power_mode mode) { + int ret = 0; u32 reg; - if (!(priv->hw_params->flags & GENET_HAS_EXT)) - return; + if (!bcmgenet_has_ext(priv)) + return ret; reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); @@ -1690,7 +1700,7 @@ static void bcmgenet_power_up(struct bcmgenet_priv *priv, case GENET_POWER_PASSIVE: reg &= ~(EXT_PWR_DOWN_DLL | EXT_PWR_DOWN_BIAS | EXT_ENERGY_DET_MASK); - if (GENET_IS_V5(priv) && !priv->ephy_16nm) { + if (GENET_IS_V5(priv) && !bcmgenet_has_ephy_16nm(priv)) { reg &= ~(EXT_PWR_DOWN_PHY_EN | EXT_PWR_DOWN_PHY_RD | EXT_PWR_DOWN_PHY_SD | @@ -1718,11 +1728,13 @@ static void bcmgenet_power_up(struct bcmgenet_priv *priv, } break; case GENET_POWER_WOL_MAGIC: - bcmgenet_wol_power_up_cfg(priv, mode); - return; + ret = bcmgenet_wol_power_up_cfg(priv, mode); + break; default: break; } + + return ret; } static struct enet_cb *bcmgenet_get_txcb(struct bcmgenet_priv *priv, @@ -1759,18 +1771,6 @@ static struct enet_cb *bcmgenet_put_txcb(struct bcmgenet_priv *priv, return tx_cb_ptr; } -static inline void bcmgenet_rx_ring16_int_disable(struct bcmgenet_rx_ring *ring) -{ - bcmgenet_intrl2_0_writel(ring->priv, UMAC_IRQ_RXDMA_DONE, - INTRL2_CPU_MASK_SET); -} - -static inline void bcmgenet_rx_ring16_int_enable(struct bcmgenet_rx_ring *ring) -{ - bcmgenet_intrl2_0_writel(ring->priv, UMAC_IRQ_RXDMA_DONE, - INTRL2_CPU_MASK_CLEAR); -} - static inline void bcmgenet_rx_ring_int_disable(struct bcmgenet_rx_ring *ring) { bcmgenet_intrl2_1_writel(ring->priv, @@ -1785,18 +1785,6 @@ static inline void bcmgenet_rx_ring_int_enable(struct bcmgenet_rx_ring *ring) INTRL2_CPU_MASK_CLEAR); } -static inline void bcmgenet_tx_ring16_int_disable(struct bcmgenet_tx_ring *ring) -{ - bcmgenet_intrl2_0_writel(ring->priv, UMAC_IRQ_TXDMA_DONE, - INTRL2_CPU_MASK_SET); -} - -static inline void bcmgenet_tx_ring16_int_enable(struct bcmgenet_tx_ring *ring) -{ - bcmgenet_intrl2_0_writel(ring->priv, UMAC_IRQ_TXDMA_DONE, - INTRL2_CPU_MASK_CLEAR); -} - static inline void bcmgenet_tx_ring_int_enable(struct bcmgenet_tx_ring *ring) { bcmgenet_intrl2_1_writel(ring->priv, 1 << ring->index, @@ -1877,12 +1865,7 @@ static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev, struct sk_buff *skb; /* Clear status before servicing to reduce spurious interrupts */ - if (ring->index == DESC_INDEX) - bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_TXDMA_DONE, - INTRL2_CPU_CLEAR); - else - bcmgenet_intrl2_1_writel(priv, (1 << ring->index), - INTRL2_CPU_CLEAR); + bcmgenet_intrl2_1_writel(priv, (1 << ring->index), INTRL2_CPU_CLEAR); /* Compute how many buffers are transmitted since last xmit call */ c_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_CONS_INDEX) @@ -1916,19 +1899,46 @@ static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev, ring->packets += pkts_compl; ring->bytes += bytes_compl; - netdev_tx_completed_queue(netdev_get_tx_queue(dev, ring->queue), + netdev_tx_completed_queue(netdev_get_tx_queue(dev, ring->index), pkts_compl, bytes_compl); return txbds_processed; } static unsigned int bcmgenet_tx_reclaim(struct net_device *dev, - struct bcmgenet_tx_ring *ring) + struct bcmgenet_tx_ring *ring, + bool all) { - unsigned int released; + struct bcmgenet_priv *priv = netdev_priv(dev); + struct device *kdev = &priv->pdev->dev; + unsigned int released, drop, wr_ptr; + struct enet_cb *cb_ptr; + struct sk_buff *skb; spin_lock_bh(&ring->lock); released = __bcmgenet_tx_reclaim(dev, ring); + if (all) { + skb = NULL; + drop = (ring->prod_index - ring->c_index) & DMA_C_INDEX_MASK; + released += drop; + ring->prod_index = ring->c_index & DMA_C_INDEX_MASK; + while (drop--) { + cb_ptr = bcmgenet_put_txcb(priv, ring); + skb = cb_ptr->skb; + bcmgenet_free_tx_cb(kdev, cb_ptr); + if (skb && cb_ptr == GENET_CB(skb)->first_cb) { + dev_consume_skb_any(skb); + skb = NULL; + } + } + if (skb) + dev_consume_skb_any(skb); + bcmgenet_tdma_ring_writel(priv, ring->index, + ring->prod_index, TDMA_PROD_INDEX); + wr_ptr = ring->write_ptr * WORDS_PER_BD(priv); + bcmgenet_tdma_ring_writel(priv, ring->index, wr_ptr, + TDMA_WRITE_PTR); + } spin_unlock_bh(&ring->lock); return released; @@ -1944,14 +1954,14 @@ static int bcmgenet_tx_poll(struct napi_struct *napi, int budget) spin_lock(&ring->lock); work_done = __bcmgenet_tx_reclaim(ring->priv->dev, ring); if (ring->free_bds > (MAX_SKB_FRAGS + 1)) { - txq = netdev_get_tx_queue(ring->priv->dev, ring->queue); + txq = netdev_get_tx_queue(ring->priv->dev, ring->index); netif_tx_wake_queue(txq); } spin_unlock(&ring->lock); if (work_done == 0) { napi_complete(napi); - ring->int_enable(ring); + bcmgenet_tx_ring_int_enable(ring); return 0; } @@ -1962,14 +1972,11 @@ static int bcmgenet_tx_poll(struct napi_struct *napi, int budget) static void bcmgenet_tx_reclaim_all(struct net_device *dev) { struct bcmgenet_priv *priv = netdev_priv(dev); - int i; - - if (netif_is_multiqueue(dev)) { - for (i = 0; i < priv->hw_params->tx_queues; i++) - bcmgenet_tx_reclaim(dev, &priv->tx_rings[i]); - } + int i = 0; - bcmgenet_tx_reclaim(dev, &priv->tx_rings[DESC_INDEX]); + do { + bcmgenet_tx_reclaim(dev, &priv->tx_rings[i++], true); + } while (i <= priv->hw_params->tx_queues && netif_is_multiqueue(dev)); } /* Reallocate the SKB to put enough headroom in front of it and insert @@ -2057,19 +2064,14 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev) index = skb_get_queue_mapping(skb); /* Mapping strategy: - * queue_mapping = 0, unclassified, packet xmited through ring16 - * queue_mapping = 1, goes to ring 0. (highest priority queue - * queue_mapping = 2, goes to ring 1. - * queue_mapping = 3, goes to ring 2. - * queue_mapping = 4, goes to ring 3. + * queue_mapping = 0, unclassified, packet xmited through ring 0 + * queue_mapping = 1, goes to ring 1. (highest priority queue) + * queue_mapping = 2, goes to ring 2. + * queue_mapping = 3, goes to ring 3. + * queue_mapping = 4, goes to ring 4. */ - if (index == 0) - index = DESC_INDEX; - else - index -= 1; - ring = &priv->tx_rings[index]; - txq = netdev_get_tx_queue(dev, ring->queue); + txq = netdev_get_tx_queue(dev, index); nr_frags = skb_shinfo(skb)->nr_frags; @@ -2242,15 +2244,8 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, unsigned int discards; /* Clear status before servicing to reduce spurious interrupts */ - if (ring->index == DESC_INDEX) { - bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_RXDMA_DONE, - INTRL2_CPU_CLEAR); - } else { - mask = 1 << (UMAC_IRQ1_RX_INTR_SHIFT + ring->index); - bcmgenet_intrl2_1_writel(priv, - mask, - INTRL2_CPU_CLEAR); - } + mask = 1 << (UMAC_IRQ1_RX_INTR_SHIFT + ring->index); + bcmgenet_intrl2_1_writel(priv, mask, INTRL2_CPU_CLEAR); p_index = bcmgenet_rdma_ring_readl(priv, ring->index, RDMA_PROD_INDEX); @@ -2399,7 +2394,7 @@ static int bcmgenet_rx_poll(struct napi_struct *napi, int budget) if (work_done < budget) { napi_complete_done(napi, work_done); - ring->int_enable(ring); + bcmgenet_rx_ring_int_enable(ring); } if (ring->dim.use_dim) { @@ -2523,7 +2518,7 @@ static void bcmgenet_link_intr_enable(struct bcmgenet_priv *priv) } else if (priv->ext_phy) { int0_enable |= UMAC_IRQ_LINK_EVENT; } else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) { - if (priv->hw_params->flags & GENET_HAS_MOCA_LINK_DET) + if (bcmgenet_has_moca_link_det(priv)) int0_enable |= UMAC_IRQ_LINK_EVENT; } bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR); @@ -2588,8 +2583,8 @@ static void init_umac(struct bcmgenet_priv *priv) } /* Enable MDIO interrupts on GENET v3+ */ - if (priv->hw_params->flags & GENET_HAS_MDIO_INTR) - int0_enable |= (UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR); + if (bcmgenet_has_mdio_intr(priv)) + int0_enable |= UMAC_IRQ_MDIO_EVENT; bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR); @@ -2639,15 +2634,6 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv, spin_lock_init(&ring->lock); ring->priv = priv; ring->index = index; - if (index == DESC_INDEX) { - ring->queue = 0; - ring->int_enable = bcmgenet_tx_ring16_int_enable; - ring->int_disable = bcmgenet_tx_ring16_int_disable; - } else { - ring->queue = index + 1; - ring->int_enable = bcmgenet_tx_ring_int_enable; - ring->int_disable = bcmgenet_tx_ring_int_disable; - } ring->cbs = priv->tx_cbs + start_ptr; ring->size = size; ring->clean_ptr = start_ptr; @@ -2658,8 +2644,8 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv, ring->end_ptr = end_ptr - 1; ring->prod_index = 0; - /* Set flow period for ring != 16 */ - if (index != DESC_INDEX) + /* Set flow period for ring != 0 */ + if (index) flow_period_val = ENET_MAX_MTU_SIZE << 16; bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_PROD_INDEX); @@ -2697,13 +2683,6 @@ static int bcmgenet_init_rx_ring(struct bcmgenet_priv *priv, ring->priv = priv; ring->index = index; - if (index == DESC_INDEX) { - ring->int_enable = bcmgenet_rx_ring16_int_enable; - ring->int_disable = bcmgenet_rx_ring16_int_disable; - } else { - ring->int_enable = bcmgenet_rx_ring_int_enable; - ring->int_disable = bcmgenet_rx_ring_int_disable; - } ring->cbs = priv->rx_cbs + start_ptr; ring->size = size; ring->c_index = 0; @@ -2749,15 +2728,11 @@ static void bcmgenet_enable_tx_napi(struct bcmgenet_priv *priv) unsigned int i; struct bcmgenet_tx_ring *ring; - for (i = 0; i < priv->hw_params->tx_queues; ++i) { + for (i = 0; i <= priv->hw_params->tx_queues; ++i) { ring = &priv->tx_rings[i]; napi_enable(&ring->napi); - ring->int_enable(ring); + bcmgenet_tx_ring_int_enable(ring); } - - ring = &priv->tx_rings[DESC_INDEX]; - napi_enable(&ring->napi); - ring->int_enable(ring); } static void bcmgenet_disable_tx_napi(struct bcmgenet_priv *priv) @@ -2765,13 +2740,10 @@ static void bcmgenet_disable_tx_napi(struct bcmgenet_priv *priv) unsigned int i; struct bcmgenet_tx_ring *ring; - for (i = 0; i < priv->hw_params->tx_queues; ++i) { + for (i = 0; i <= priv->hw_params->tx_queues; ++i) { ring = &priv->tx_rings[i]; napi_disable(&ring->napi); } - - ring = &priv->tx_rings[DESC_INDEX]; - napi_disable(&ring->napi); } static void bcmgenet_fini_tx_napi(struct bcmgenet_priv *priv) @@ -2779,82 +2751,104 @@ static void bcmgenet_fini_tx_napi(struct bcmgenet_priv *priv) unsigned int i; struct bcmgenet_tx_ring *ring; - for (i = 0; i < priv->hw_params->tx_queues; ++i) { + for (i = 0; i <= priv->hw_params->tx_queues; ++i) { ring = &priv->tx_rings[i]; netif_napi_del(&ring->napi); } +} - ring = &priv->tx_rings[DESC_INDEX]; - netif_napi_del(&ring->napi); +static int bcmgenet_tdma_disable(struct bcmgenet_priv *priv) +{ + int timeout = 0; + u32 reg, mask; + + reg = bcmgenet_tdma_readl(priv, DMA_CTRL); + mask = (1 << (priv->hw_params->tx_queues + 1)) - 1; + mask = (mask << DMA_RING_BUF_EN_SHIFT) | DMA_EN; + reg &= ~mask; + bcmgenet_tdma_writel(priv, reg, DMA_CTRL); + + /* Check DMA status register to confirm DMA is disabled */ + while (timeout++ < DMA_TIMEOUT_VAL) { + reg = bcmgenet_tdma_readl(priv, DMA_STATUS); + if ((reg & mask) == mask) + return 0; + + udelay(1); + } + + return -ETIMEDOUT; +} + +static int bcmgenet_rdma_disable(struct bcmgenet_priv *priv) +{ + int timeout = 0; + u32 reg, mask; + + reg = bcmgenet_rdma_readl(priv, DMA_CTRL); + mask = (1 << (priv->hw_params->rx_queues + 1)) - 1; + mask = (mask << DMA_RING_BUF_EN_SHIFT) | DMA_EN; + reg &= ~mask; + bcmgenet_rdma_writel(priv, reg, DMA_CTRL); + + /* Check DMA status register to confirm DMA is disabled */ + while (timeout++ < DMA_TIMEOUT_VAL) { + reg = bcmgenet_rdma_readl(priv, DMA_STATUS); + if ((reg & mask) == mask) + return 0; + + udelay(1); + } + + return -ETIMEDOUT; } /* Initialize Tx queues * - * Queues 0-3 are priority-based, each one has 32 descriptors, - * with queue 0 being the highest priority queue. + * Queues 1-4 are priority-based, each one has 32 descriptors, + * with queue 1 being the highest priority queue. * - * Queue 16 is the default Tx queue with - * GENET_Q16_TX_BD_CNT = 256 - 4 * 32 = 128 descriptors. + * Queue 0 is the default Tx queue with + * GENET_Q0_TX_BD_CNT = 256 - 4 * 32 = 128 descriptors. * * The transmit control block pool is then partitioned as follows: - * - Tx queue 0 uses tx_cbs[0..31] - * - Tx queue 1 uses tx_cbs[32..63] - * - Tx queue 2 uses tx_cbs[64..95] - * - Tx queue 3 uses tx_cbs[96..127] - * - Tx queue 16 uses tx_cbs[128..255] + * - Tx queue 0 uses tx_cbs[0..127] + * - Tx queue 1 uses tx_cbs[128..159] + * - Tx queue 2 uses tx_cbs[160..191] + * - Tx queue 3 uses tx_cbs[192..223] + * - Tx queue 4 uses tx_cbs[224..255] */ static void bcmgenet_init_tx_queues(struct net_device *dev) { struct bcmgenet_priv *priv = netdev_priv(dev); - u32 i, dma_enable; - u32 dma_ctrl, ring_cfg; - u32 dma_priority[3] = {0, 0, 0}; - - dma_ctrl = bcmgenet_tdma_readl(priv, DMA_CTRL); - dma_enable = dma_ctrl & DMA_EN; - dma_ctrl &= ~DMA_EN; - bcmgenet_tdma_writel(priv, dma_ctrl, DMA_CTRL); - - dma_ctrl = 0; - ring_cfg = 0; + unsigned int start = 0, end = GENET_Q0_TX_BD_CNT; + u32 i, ring_mask, dma_priority[3] = {0, 0, 0}; /* Enable strict priority arbiter mode */ bcmgenet_tdma_writel(priv, DMA_ARBITER_SP, DMA_ARB_CTRL); /* Initialize Tx priority queues */ - for (i = 0; i < priv->hw_params->tx_queues; i++) { - bcmgenet_init_tx_ring(priv, i, priv->hw_params->tx_bds_per_q, - i * priv->hw_params->tx_bds_per_q, - (i + 1) * priv->hw_params->tx_bds_per_q); - ring_cfg |= (1 << i); - dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); + for (i = 0; i <= priv->hw_params->tx_queues; i++) { + bcmgenet_init_tx_ring(priv, i, end - start, start, end); + start = end; + end += priv->hw_params->tx_bds_per_q; dma_priority[DMA_PRIO_REG_INDEX(i)] |= - ((GENET_Q0_PRIORITY + i) << DMA_PRIO_REG_SHIFT(i)); + (i ? GENET_Q1_PRIORITY : GENET_Q0_PRIORITY) + << DMA_PRIO_REG_SHIFT(i); } - /* Initialize Tx default queue 16 */ - bcmgenet_init_tx_ring(priv, DESC_INDEX, GENET_Q16_TX_BD_CNT, - priv->hw_params->tx_queues * - priv->hw_params->tx_bds_per_q, - TOTAL_DESC); - ring_cfg |= (1 << DESC_INDEX); - dma_ctrl |= (1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT)); - dma_priority[DMA_PRIO_REG_INDEX(DESC_INDEX)] |= - ((GENET_Q0_PRIORITY + priv->hw_params->tx_queues) << - DMA_PRIO_REG_SHIFT(DESC_INDEX)); - /* Set Tx queue priorities */ bcmgenet_tdma_writel(priv, dma_priority[0], DMA_PRIORITY_0); bcmgenet_tdma_writel(priv, dma_priority[1], DMA_PRIORITY_1); bcmgenet_tdma_writel(priv, dma_priority[2], DMA_PRIORITY_2); - /* Enable Tx queues */ - bcmgenet_tdma_writel(priv, ring_cfg, DMA_RING_CFG); + /* Configure Tx queues as descriptor rings */ + ring_mask = (1 << (priv->hw_params->tx_queues + 1)) - 1; + bcmgenet_tdma_writel(priv, ring_mask, DMA_RING_CFG); - /* Enable Tx DMA */ - if (dma_enable) - dma_ctrl |= DMA_EN; - bcmgenet_tdma_writel(priv, dma_ctrl, DMA_CTRL); + /* Enable Tx rings */ + ring_mask <<= DMA_RING_BUF_EN_SHIFT; + bcmgenet_tdma_writel(priv, ring_mask, DMA_CTRL); } static void bcmgenet_enable_rx_napi(struct bcmgenet_priv *priv) @@ -2862,15 +2856,11 @@ static void bcmgenet_enable_rx_napi(struct bcmgenet_priv *priv) unsigned int i; struct bcmgenet_rx_ring *ring; - for (i = 0; i < priv->hw_params->rx_queues; ++i) { + for (i = 0; i <= priv->hw_params->rx_queues; ++i) { ring = &priv->rx_rings[i]; napi_enable(&ring->napi); - ring->int_enable(ring); + bcmgenet_rx_ring_int_enable(ring); } - - ring = &priv->rx_rings[DESC_INDEX]; - napi_enable(&ring->napi); - ring->int_enable(ring); } static void bcmgenet_disable_rx_napi(struct bcmgenet_priv *priv) @@ -2878,15 +2868,11 @@ static void bcmgenet_disable_rx_napi(struct bcmgenet_priv *priv) unsigned int i; struct bcmgenet_rx_ring *ring; - for (i = 0; i < priv->hw_params->rx_queues; ++i) { + for (i = 0; i <= priv->hw_params->rx_queues; ++i) { ring = &priv->rx_rings[i]; napi_disable(&ring->napi); cancel_work_sync(&ring->dim.dim.work); } - - ring = &priv->rx_rings[DESC_INDEX]; - napi_disable(&ring->napi); - cancel_work_sync(&ring->dim.dim.work); } static void bcmgenet_fini_rx_napi(struct bcmgenet_priv *priv) @@ -2894,13 +2880,10 @@ static void bcmgenet_fini_rx_napi(struct bcmgenet_priv *priv) unsigned int i; struct bcmgenet_rx_ring *ring; - for (i = 0; i < priv->hw_params->rx_queues; ++i) { + for (i = 0; i <= priv->hw_params->rx_queues; ++i) { ring = &priv->rx_rings[i]; netif_napi_del(&ring->napi); } - - ring = &priv->rx_rings[DESC_INDEX]; - netif_napi_del(&ring->napi); } /* Initialize Rx queues @@ -2908,57 +2891,32 @@ static void bcmgenet_fini_rx_napi(struct bcmgenet_priv *priv) * Queues 0-15 are priority queues. Hardware Filtering Block (HFB) can be * used to direct traffic to these queues. * - * Queue 16 is the default Rx queue with GENET_Q16_RX_BD_CNT descriptors. + * Queue 0 is also the default Rx queue with GENET_Q0_RX_BD_CNT descriptors. */ static int bcmgenet_init_rx_queues(struct net_device *dev) { struct bcmgenet_priv *priv = netdev_priv(dev); - u32 i; - u32 dma_enable; - u32 dma_ctrl; - u32 ring_cfg; + unsigned int start = 0, end = GENET_Q0_RX_BD_CNT; + u32 i, ring_mask; int ret; - dma_ctrl = bcmgenet_rdma_readl(priv, DMA_CTRL); - dma_enable = dma_ctrl & DMA_EN; - dma_ctrl &= ~DMA_EN; - bcmgenet_rdma_writel(priv, dma_ctrl, DMA_CTRL); - - dma_ctrl = 0; - ring_cfg = 0; - /* Initialize Rx priority queues */ - for (i = 0; i < priv->hw_params->rx_queues; i++) { - ret = bcmgenet_init_rx_ring(priv, i, - priv->hw_params->rx_bds_per_q, - i * priv->hw_params->rx_bds_per_q, - (i + 1) * - priv->hw_params->rx_bds_per_q); + for (i = 0; i <= priv->hw_params->rx_queues; i++) { + ret = bcmgenet_init_rx_ring(priv, i, end - start, start, end); if (ret) return ret; - ring_cfg |= (1 << i); - dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); + start = end; + end += priv->hw_params->rx_bds_per_q; } - /* Initialize Rx default queue 16 */ - ret = bcmgenet_init_rx_ring(priv, DESC_INDEX, GENET_Q16_RX_BD_CNT, - priv->hw_params->rx_queues * - priv->hw_params->rx_bds_per_q, - TOTAL_DESC); - if (ret) - return ret; - - ring_cfg |= (1 << DESC_INDEX); - dma_ctrl |= (1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT)); - - /* Enable rings */ - bcmgenet_rdma_writel(priv, ring_cfg, DMA_RING_CFG); + /* Configure Rx queues as descriptor rings */ + ring_mask = (1 << (priv->hw_params->rx_queues + 1)) - 1; + bcmgenet_rdma_writel(priv, ring_mask, DMA_RING_CFG); - /* Configure ring as descriptor ring and re-enable DMA if enabled */ - if (dma_enable) - dma_ctrl |= DMA_EN; - bcmgenet_rdma_writel(priv, dma_ctrl, DMA_CTRL); + /* Enable Rx rings */ + ring_mask <<= DMA_RING_BUF_EN_SHIFT; + bcmgenet_rdma_writel(priv, ring_mask, DMA_CTRL); return 0; } @@ -2966,26 +2924,9 @@ static int bcmgenet_init_rx_queues(struct net_device *dev) static int bcmgenet_dma_teardown(struct bcmgenet_priv *priv) { int ret = 0; - int timeout = 0; - u32 reg; - u32 dma_ctrl; - int i; /* Disable TDMA to stop add more frames in TX DMA */ - reg = bcmgenet_tdma_readl(priv, DMA_CTRL); - reg &= ~DMA_EN; - bcmgenet_tdma_writel(priv, reg, DMA_CTRL); - - /* Check TDMA status register to confirm TDMA is disabled */ - while (timeout++ < DMA_TIMEOUT_VAL) { - reg = bcmgenet_tdma_readl(priv, DMA_STATUS); - if (reg & DMA_DISABLED) - break; - - udelay(1); - } - - if (timeout == DMA_TIMEOUT_VAL) { + if (-ETIMEDOUT == bcmgenet_tdma_disable(priv)) { netdev_warn(priv->dev, "Timed out while disabling TX DMA\n"); ret = -ETIMEDOUT; } @@ -2994,39 +2935,11 @@ static int bcmgenet_dma_teardown(struct bcmgenet_priv *priv) usleep_range(10000, 20000); /* Disable RDMA */ - reg = bcmgenet_rdma_readl(priv, DMA_CTRL); - reg &= ~DMA_EN; - bcmgenet_rdma_writel(priv, reg, DMA_CTRL); - - timeout = 0; - /* Check RDMA status register to confirm RDMA is disabled */ - while (timeout++ < DMA_TIMEOUT_VAL) { - reg = bcmgenet_rdma_readl(priv, DMA_STATUS); - if (reg & DMA_DISABLED) - break; - - udelay(1); - } - - if (timeout == DMA_TIMEOUT_VAL) { + if (-ETIMEDOUT == bcmgenet_rdma_disable(priv)) { netdev_warn(priv->dev, "Timed out while disabling RX DMA\n"); ret = -ETIMEDOUT; } - dma_ctrl = 0; - for (i = 0; i < priv->hw_params->rx_queues; i++) - dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); - reg = bcmgenet_rdma_readl(priv, DMA_CTRL); - reg &= ~dma_ctrl; - bcmgenet_rdma_writel(priv, reg, DMA_CTRL); - - dma_ctrl = 0; - for (i = 0; i < priv->hw_params->tx_queues; i++) - dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); - reg = bcmgenet_tdma_readl(priv, DMA_CTRL); - reg &= ~dma_ctrl; - bcmgenet_tdma_writel(priv, reg, DMA_CTRL); - return ret; } @@ -3038,32 +2951,53 @@ static void bcmgenet_fini_dma(struct bcmgenet_priv *priv) bcmgenet_fini_rx_napi(priv); bcmgenet_fini_tx_napi(priv); - for (i = 0; i < priv->num_tx_bds; i++) - dev_kfree_skb(bcmgenet_free_tx_cb(&priv->pdev->dev, - priv->tx_cbs + i)); - - for (i = 0; i < priv->hw_params->tx_queues; i++) { - txq = netdev_get_tx_queue(priv->dev, priv->tx_rings[i].queue); + for (i = 0; i <= priv->hw_params->tx_queues; i++) { + txq = netdev_get_tx_queue(priv->dev, i); netdev_tx_reset_queue(txq); } - txq = netdev_get_tx_queue(priv->dev, priv->tx_rings[DESC_INDEX].queue); - netdev_tx_reset_queue(txq); - bcmgenet_free_rx_buffers(priv); kfree(priv->rx_cbs); kfree(priv->tx_cbs); } /* init_edma: Initialize DMA control register */ -static int bcmgenet_init_dma(struct bcmgenet_priv *priv) +static int bcmgenet_init_dma(struct bcmgenet_priv *priv, bool flush_rx) { - int ret; - unsigned int i; struct enet_cb *cb; + unsigned int i; + int ret; + u32 reg; netif_dbg(priv, hw, priv->dev, "%s\n", __func__); + /* Disable TX DMA */ + ret = bcmgenet_tdma_disable(priv); + if (ret) { + netdev_err(priv->dev, "failed to halt Tx DMA\n"); + return ret; + } + + /* Disable RX DMA */ + ret = bcmgenet_rdma_disable(priv); + if (ret) { + netdev_err(priv->dev, "failed to halt Rx DMA\n"); + return ret; + } + + /* Flush TX queues */ + bcmgenet_umac_writel(priv, 1, UMAC_TX_FLUSH); + udelay(10); + bcmgenet_umac_writel(priv, 0, UMAC_TX_FLUSH); + + if (flush_rx) { + reg = bcmgenet_rbuf_ctrl_get(priv); + bcmgenet_rbuf_ctrl_set(priv, reg | BIT(0)); + udelay(10); + bcmgenet_rbuf_ctrl_set(priv, reg); + udelay(10); + } + /* Initialize common Rx ring structures */ priv->rx_bds = priv->base + priv->hw_params->rdma_offset; priv->num_rx_bds = TOTAL_DESC; @@ -3113,6 +3047,15 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *priv) /* Initialize Tx queues */ bcmgenet_init_tx_queues(priv->dev); + /* Enable RX/TX DMA */ + reg = bcmgenet_rdma_readl(priv, DMA_CTRL); + reg |= DMA_EN; + bcmgenet_rdma_writel(priv, reg, DMA_CTRL); + + reg = bcmgenet_tdma_readl(priv, DMA_CTRL); + reg |= DMA_EN; + bcmgenet_tdma_writel(priv, reg, DMA_CTRL); + return 0; } @@ -3142,7 +3085,7 @@ static void bcmgenet_irq_task(struct work_struct *work) } -/* bcmgenet_isr1: handle Rx and Tx priority queues */ +/* bcmgenet_isr1: handle Rx and Tx queues */ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id) { struct bcmgenet_priv *priv = dev_id; @@ -3161,7 +3104,7 @@ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id) "%s: IRQ=0x%x\n", __func__, status); /* Check Rx priority queue interrupts */ - for (index = 0; index < priv->hw_params->rx_queues; index++) { + for (index = 0; index <= priv->hw_params->rx_queues; index++) { if (!(status & BIT(UMAC_IRQ1_RX_INTR_SHIFT + index))) continue; @@ -3169,20 +3112,20 @@ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id) rx_ring->dim.event_ctr++; if (likely(napi_schedule_prep(&rx_ring->napi))) { - rx_ring->int_disable(rx_ring); + bcmgenet_rx_ring_int_disable(rx_ring); __napi_schedule_irqoff(&rx_ring->napi); } } /* Check Tx priority queue interrupts */ - for (index = 0; index < priv->hw_params->tx_queues; index++) { + for (index = 0; index <= priv->hw_params->tx_queues; index++) { if (!(status & BIT(index))) continue; tx_ring = &priv->tx_rings[index]; if (likely(napi_schedule_prep(&tx_ring->napi))) { - tx_ring->int_disable(tx_ring); + bcmgenet_tx_ring_int_disable(tx_ring); __napi_schedule_irqoff(&tx_ring->napi); } } @@ -3190,12 +3133,10 @@ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id) return IRQ_HANDLED; } -/* bcmgenet_isr0: handle Rx and Tx default queues + other stuff */ +/* bcmgenet_isr0: handle other stuff */ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id) { struct bcmgenet_priv *priv = dev_id; - struct bcmgenet_rx_ring *rx_ring; - struct bcmgenet_tx_ring *tx_ring; unsigned int status; unsigned long flags; @@ -3209,29 +3150,8 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id) netif_dbg(priv, intr, priv->dev, "IRQ=0x%x\n", status); - if (status & UMAC_IRQ_RXDMA_DONE) { - rx_ring = &priv->rx_rings[DESC_INDEX]; - rx_ring->dim.event_ctr++; - - if (likely(napi_schedule_prep(&rx_ring->napi))) { - rx_ring->int_disable(rx_ring); - __napi_schedule_irqoff(&rx_ring->napi); - } - } - - if (status & UMAC_IRQ_TXDMA_DONE) { - tx_ring = &priv->tx_rings[DESC_INDEX]; - - if (likely(napi_schedule_prep(&tx_ring->napi))) { - tx_ring->int_disable(tx_ring); - __napi_schedule_irqoff(&tx_ring->napi); - } - } - - if ((priv->hw_params->flags & GENET_HAS_MDIO_INTR) && - status & (UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR)) { + if (bcmgenet_has_mdio_intr(priv) && status & UMAC_IRQ_MDIO_EVENT) wake_up(&priv->wq); - } /* all other interested interrupts handled in bottom half */ status &= (UMAC_IRQ_LINK_EVENT | UMAC_IRQ_PHY_DET_R); @@ -3285,56 +3205,6 @@ static void bcmgenet_get_hw_addr(struct bcmgenet_priv *priv, put_unaligned_be16(addr_tmp, &addr[4]); } -/* Returns a reusable dma control register value */ -static u32 bcmgenet_dma_disable(struct bcmgenet_priv *priv, bool flush_rx) -{ - unsigned int i; - u32 reg; - u32 dma_ctrl; - - /* disable DMA */ - dma_ctrl = 1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT) | DMA_EN; - for (i = 0; i < priv->hw_params->tx_queues; i++) - dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); - reg = bcmgenet_tdma_readl(priv, DMA_CTRL); - reg &= ~dma_ctrl; - bcmgenet_tdma_writel(priv, reg, DMA_CTRL); - - dma_ctrl = 1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT) | DMA_EN; - for (i = 0; i < priv->hw_params->rx_queues; i++) - dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); - reg = bcmgenet_rdma_readl(priv, DMA_CTRL); - reg &= ~dma_ctrl; - bcmgenet_rdma_writel(priv, reg, DMA_CTRL); - - bcmgenet_umac_writel(priv, 1, UMAC_TX_FLUSH); - udelay(10); - bcmgenet_umac_writel(priv, 0, UMAC_TX_FLUSH); - - if (flush_rx) { - reg = bcmgenet_rbuf_ctrl_get(priv); - bcmgenet_rbuf_ctrl_set(priv, reg | BIT(0)); - udelay(10); - bcmgenet_rbuf_ctrl_set(priv, reg); - udelay(10); - } - - return dma_ctrl; -} - -static void bcmgenet_enable_dma(struct bcmgenet_priv *priv, u32 dma_ctrl) -{ - u32 reg; - - reg = bcmgenet_rdma_readl(priv, DMA_CTRL); - reg |= dma_ctrl; - bcmgenet_rdma_writel(priv, reg, DMA_CTRL); - - reg = bcmgenet_tdma_readl(priv, DMA_CTRL); - reg |= dma_ctrl; - bcmgenet_tdma_writel(priv, reg, DMA_CTRL); -} - static void bcmgenet_netif_start(struct net_device *dev) { struct bcmgenet_priv *priv = netdev_priv(dev); @@ -3358,7 +3228,6 @@ static void bcmgenet_netif_start(struct net_device *dev) static int bcmgenet_open(struct net_device *dev) { struct bcmgenet_priv *priv = netdev_priv(dev); - unsigned long dma_ctrl; int ret; netif_dbg(priv, ifup, dev, "bcmgenet_open\n"); @@ -3384,22 +3253,16 @@ static int bcmgenet_open(struct net_device *dev) bcmgenet_set_hw_addr(priv, dev->dev_addr); - /* Disable RX/TX DMA and flush TX and RX queues */ - dma_ctrl = bcmgenet_dma_disable(priv, true); + /* HFB init */ + bcmgenet_hfb_init(priv); /* Reinitialize TDMA and RDMA and SW housekeeping */ - ret = bcmgenet_init_dma(priv); + ret = bcmgenet_init_dma(priv, true); if (ret) { netdev_err(dev, "failed to initialize DMA\n"); goto err_clk_disable; } - /* Always enable ring 16 - descriptor ring */ - bcmgenet_enable_dma(priv, dma_ctrl); - - /* HFB init */ - bcmgenet_hfb_init(priv); - ret = request_irq(priv->irq0, bcmgenet_isr0, IRQF_SHARED, dev->name, priv); if (ret < 0) { @@ -3446,19 +3309,21 @@ static void bcmgenet_netif_stop(struct net_device *dev, bool stop_phy) { struct bcmgenet_priv *priv = netdev_priv(dev); - bcmgenet_disable_tx_napi(priv); netif_tx_disable(dev); /* Disable MAC receive */ + bcmgenet_hfb_reg_writel(priv, 0, HFB_CTRL); umac_enable_set(priv, CMD_RX_EN, false); + if (stop_phy) + phy_stop(dev->phydev); + bcmgenet_dma_teardown(priv); /* Disable MAC transmit. TX DMA disabled must be done before this */ umac_enable_set(priv, CMD_TX_EN, false); - if (stop_phy) - phy_stop(dev->phydev); + bcmgenet_disable_tx_napi(priv); bcmgenet_disable_rx_napi(priv); bcmgenet_intr_disable(priv); @@ -3506,16 +3371,11 @@ static void bcmgenet_dump_tx_queue(struct bcmgenet_tx_ring *ring) if (!netif_msg_tx_err(priv)) return; - txq = netdev_get_tx_queue(priv->dev, ring->queue); + txq = netdev_get_tx_queue(priv->dev, ring->index); spin_lock(&ring->lock); - if (ring->index == DESC_INDEX) { - intsts = ~bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_MASK_STATUS); - intmsk = UMAC_IRQ_TXDMA_DONE | UMAC_IRQ_TXDMA_MBDONE; - } else { - intsts = ~bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_MASK_STATUS); - intmsk = 1 << ring->index; - } + intsts = ~bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_MASK_STATUS); + intmsk = 1 << ring->index; c_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_CONS_INDEX); p_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_PROD_INDEX); txq_stopped = netif_tx_queue_stopped(txq); @@ -3529,7 +3389,7 @@ static void bcmgenet_dump_tx_queue(struct bcmgenet_tx_ring *ring) "(sw)c_index: %d (hw)c_index: %d\n" "(sw)clean_p: %d (sw)write_p: %d\n" "(sw)cb_ptr: %d (sw)end_ptr: %d\n", - ring->index, ring->queue, + ring->index, ring->index, txq_stopped ? "stopped" : "active", intsts & intmsk ? "enabled" : "disabled", free_bds, ring->size, @@ -3542,25 +3402,20 @@ static void bcmgenet_dump_tx_queue(struct bcmgenet_tx_ring *ring) static void bcmgenet_timeout(struct net_device *dev, unsigned int txqueue) { struct bcmgenet_priv *priv = netdev_priv(dev); - u32 int0_enable = 0; u32 int1_enable = 0; unsigned int q; netif_dbg(priv, tx_err, dev, "bcmgenet_timeout\n"); - for (q = 0; q < priv->hw_params->tx_queues; q++) + for (q = 0; q <= priv->hw_params->tx_queues; q++) bcmgenet_dump_tx_queue(&priv->tx_rings[q]); - bcmgenet_dump_tx_queue(&priv->tx_rings[DESC_INDEX]); bcmgenet_tx_reclaim_all(dev); - for (q = 0; q < priv->hw_params->tx_queues; q++) + for (q = 0; q <= priv->hw_params->tx_queues; q++) int1_enable |= (1 << q); - int0_enable = UMAC_IRQ_TXDMA_DONE; - /* Re-enable TX interrupts if disabled */ - bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR); bcmgenet_intrl2_1_writel(priv, int1_enable, INTRL2_CPU_MASK_CLEAR); netif_trans_update(dev); @@ -3664,16 +3519,13 @@ static struct net_device_stats *bcmgenet_get_stats(struct net_device *dev) struct bcmgenet_rx_ring *rx_ring; unsigned int q; - for (q = 0; q < priv->hw_params->tx_queues; q++) { + for (q = 0; q <= priv->hw_params->tx_queues; q++) { tx_ring = &priv->tx_rings[q]; tx_bytes += tx_ring->bytes; tx_packets += tx_ring->packets; } - tx_ring = &priv->tx_rings[DESC_INDEX]; - tx_bytes += tx_ring->bytes; - tx_packets += tx_ring->packets; - for (q = 0; q < priv->hw_params->rx_queues; q++) { + for (q = 0; q <= priv->hw_params->rx_queues; q++) { rx_ring = &priv->rx_rings[q]; rx_bytes += rx_ring->bytes; @@ -3681,11 +3533,6 @@ static struct net_device_stats *bcmgenet_get_stats(struct net_device *dev) rx_errors += rx_ring->errors; rx_dropped += rx_ring->dropped; } - rx_ring = &priv->rx_rings[DESC_INDEX]; - rx_bytes += rx_ring->bytes; - rx_packets += rx_ring->packets; - rx_errors += rx_ring->errors; - rx_dropped += rx_ring->dropped; dev->stats.tx_bytes = tx_bytes; dev->stats.tx_packets = tx_packets; @@ -3726,128 +3573,109 @@ static const struct net_device_ops bcmgenet_netdev_ops = { .ndo_change_carrier = bcmgenet_change_carrier, }; -/* Array of GENET hardware parameters/characteristics */ -static struct bcmgenet_hw_params bcmgenet_hw_params[] = { - [GENET_V1] = { - .tx_queues = 0, - .tx_bds_per_q = 0, - .rx_queues = 0, - .rx_bds_per_q = 0, - .bp_in_en_shift = 16, - .bp_in_mask = 0xffff, - .hfb_filter_cnt = 16, - .qtag_mask = 0x1F, - .hfb_offset = 0x1000, - .rdma_offset = 0x2000, - .tdma_offset = 0x3000, - .words_per_bd = 2, - }, - [GENET_V2] = { - .tx_queues = 4, - .tx_bds_per_q = 32, - .rx_queues = 0, - .rx_bds_per_q = 0, - .bp_in_en_shift = 16, - .bp_in_mask = 0xffff, - .hfb_filter_cnt = 16, - .qtag_mask = 0x1F, - .tbuf_offset = 0x0600, - .hfb_offset = 0x1000, - .hfb_reg_offset = 0x2000, - .rdma_offset = 0x3000, - .tdma_offset = 0x4000, - .words_per_bd = 2, - .flags = GENET_HAS_EXT, - }, - [GENET_V3] = { - .tx_queues = 4, - .tx_bds_per_q = 32, - .rx_queues = 0, - .rx_bds_per_q = 0, - .bp_in_en_shift = 17, - .bp_in_mask = 0x1ffff, - .hfb_filter_cnt = 48, - .hfb_filter_size = 128, - .qtag_mask = 0x3F, - .tbuf_offset = 0x0600, - .hfb_offset = 0x8000, - .hfb_reg_offset = 0xfc00, - .rdma_offset = 0x10000, - .tdma_offset = 0x11000, - .words_per_bd = 2, - .flags = GENET_HAS_EXT | GENET_HAS_MDIO_INTR | - GENET_HAS_MOCA_LINK_DET, - }, - [GENET_V4] = { - .tx_queues = 4, - .tx_bds_per_q = 32, - .rx_queues = 0, - .rx_bds_per_q = 0, - .bp_in_en_shift = 17, - .bp_in_mask = 0x1ffff, - .hfb_filter_cnt = 48, - .hfb_filter_size = 128, - .qtag_mask = 0x3F, - .tbuf_offset = 0x0600, - .hfb_offset = 0x8000, - .hfb_reg_offset = 0xfc00, - .rdma_offset = 0x2000, - .tdma_offset = 0x4000, - .words_per_bd = 3, - .flags = GENET_HAS_40BITS | GENET_HAS_EXT | - GENET_HAS_MDIO_INTR | GENET_HAS_MOCA_LINK_DET, - }, - [GENET_V5] = { - .tx_queues = 4, - .tx_bds_per_q = 32, - .rx_queues = 0, - .rx_bds_per_q = 0, - .bp_in_en_shift = 17, - .bp_in_mask = 0x1ffff, - .hfb_filter_cnt = 48, - .hfb_filter_size = 128, - .qtag_mask = 0x3F, - .tbuf_offset = 0x0600, - .hfb_offset = 0x8000, - .hfb_reg_offset = 0xfc00, - .rdma_offset = 0x2000, - .tdma_offset = 0x4000, - .words_per_bd = 3, - .flags = GENET_HAS_40BITS | GENET_HAS_EXT | - GENET_HAS_MDIO_INTR | GENET_HAS_MOCA_LINK_DET, - }, +/* GENET hardware parameters/characteristics */ +static const struct bcmgenet_hw_params bcmgenet_hw_params_v1 = { + .tx_queues = 0, + .tx_bds_per_q = 0, + .rx_queues = 0, + .rx_bds_per_q = 0, + .bp_in_en_shift = 16, + .bp_in_mask = 0xffff, + .hfb_filter_cnt = 16, + .hfb_filter_size = 64, + .qtag_mask = 0x1F, + .hfb_offset = 0x1000, + .hfb_reg_offset = GENET_RBUF_OFF + RBUF_HFB_CTRL_V1, + .rdma_offset = 0x2000, + .tdma_offset = 0x3000, + .words_per_bd = 2, +}; + +static const struct bcmgenet_hw_params bcmgenet_hw_params_v2 = { + .tx_queues = 4, + .tx_bds_per_q = 32, + .rx_queues = 0, + .rx_bds_per_q = 0, + .bp_in_en_shift = 16, + .bp_in_mask = 0xffff, + .hfb_filter_cnt = 16, + .hfb_filter_size = 64, + .qtag_mask = 0x1F, + .tbuf_offset = 0x0600, + .hfb_offset = 0x1000, + .hfb_reg_offset = 0x2000, + .rdma_offset = 0x3000, + .tdma_offset = 0x4000, + .words_per_bd = 2, +}; + +static const struct bcmgenet_hw_params bcmgenet_hw_params_v3 = { + .tx_queues = 4, + .tx_bds_per_q = 32, + .rx_queues = 0, + .rx_bds_per_q = 0, + .bp_in_en_shift = 17, + .bp_in_mask = 0x1ffff, + .hfb_filter_cnt = 48, + .hfb_filter_size = 128, + .qtag_mask = 0x3F, + .tbuf_offset = 0x0600, + .hfb_offset = 0x8000, + .hfb_reg_offset = 0xfc00, + .rdma_offset = 0x10000, + .tdma_offset = 0x11000, + .words_per_bd = 2, +}; + +static const struct bcmgenet_hw_params bcmgenet_hw_params_v4 = { + .tx_queues = 4, + .tx_bds_per_q = 32, + .rx_queues = 0, + .rx_bds_per_q = 0, + .bp_in_en_shift = 17, + .bp_in_mask = 0x1ffff, + .hfb_filter_cnt = 48, + .hfb_filter_size = 128, + .qtag_mask = 0x3F, + .tbuf_offset = 0x0600, + .hfb_offset = 0x8000, + .hfb_reg_offset = 0xfc00, + .rdma_offset = 0x2000, + .tdma_offset = 0x4000, + .words_per_bd = 3, }; /* Infer hardware parameters from the detected GENET version */ static void bcmgenet_set_hw_params(struct bcmgenet_priv *priv) { - struct bcmgenet_hw_params *params; + const struct bcmgenet_hw_params *params; u32 reg; u8 major; u16 gphy_rev; - if (GENET_IS_V5(priv) || GENET_IS_V4(priv)) { - bcmgenet_dma_regs = bcmgenet_dma_regs_v3plus; - genet_dma_ring_regs = genet_dma_ring_regs_v4; - } else if (GENET_IS_V3(priv)) { + /* default to latest values */ + params = &bcmgenet_hw_params_v4; + bcmgenet_dma_regs = bcmgenet_dma_regs_v3plus; + genet_dma_ring_regs = genet_dma_ring_regs_v4; + if (GENET_IS_V3(priv)) { + params = &bcmgenet_hw_params_v3; bcmgenet_dma_regs = bcmgenet_dma_regs_v3plus; genet_dma_ring_regs = genet_dma_ring_regs_v123; } else if (GENET_IS_V2(priv)) { + params = &bcmgenet_hw_params_v2; bcmgenet_dma_regs = bcmgenet_dma_regs_v2; genet_dma_ring_regs = genet_dma_ring_regs_v123; } else if (GENET_IS_V1(priv)) { + params = &bcmgenet_hw_params_v1; bcmgenet_dma_regs = bcmgenet_dma_regs_v1; genet_dma_ring_regs = genet_dma_ring_regs_v123; } - - /* enum genet_version starts at 1 */ - priv->hw_params = &bcmgenet_hw_params[priv->version]; - params = priv->hw_params; + priv->hw_params = params; /* Read GENET HW version */ reg = bcmgenet_sys_readl(priv, SYS_REV_CTRL); major = (reg >> 24 & 0x0f); - if (major == 6) + if (major == 6 || major == 7) major = 5; else if (major == 5) major = 4; @@ -3898,7 +3726,7 @@ static void bcmgenet_set_hw_params(struct bcmgenet_priv *priv) } #ifdef CONFIG_PHYS_ADDR_T_64BIT - if (!(params->flags & GENET_HAS_40BITS)) + if (!bcmgenet_has_40bits(priv)) pr_warn("GENET does not support 40-bits PA\n"); #endif @@ -3923,7 +3751,7 @@ static void bcmgenet_set_hw_params(struct bcmgenet_priv *priv) struct bcmgenet_plat_data { enum bcmgenet_version version; u32 dma_max_burst_length; - bool ephy_16nm; + u32 flags; }; static const struct bcmgenet_plat_data v1_plat_data = { @@ -3934,32 +3762,43 @@ static const struct bcmgenet_plat_data v1_plat_data = { static const struct bcmgenet_plat_data v2_plat_data = { .version = GENET_V2, .dma_max_burst_length = DMA_MAX_BURST_LENGTH, + .flags = GENET_HAS_EXT, }; static const struct bcmgenet_plat_data v3_plat_data = { .version = GENET_V3, .dma_max_burst_length = DMA_MAX_BURST_LENGTH, + .flags = GENET_HAS_EXT | GENET_HAS_MDIO_INTR | + GENET_HAS_MOCA_LINK_DET, }; static const struct bcmgenet_plat_data v4_plat_data = { .version = GENET_V4, .dma_max_burst_length = DMA_MAX_BURST_LENGTH, + .flags = GENET_HAS_40BITS | GENET_HAS_EXT | + GENET_HAS_MDIO_INTR | GENET_HAS_MOCA_LINK_DET, }; static const struct bcmgenet_plat_data v5_plat_data = { .version = GENET_V5, .dma_max_burst_length = DMA_MAX_BURST_LENGTH, + .flags = GENET_HAS_40BITS | GENET_HAS_EXT | + GENET_HAS_MDIO_INTR | GENET_HAS_MOCA_LINK_DET, }; static const struct bcmgenet_plat_data bcm2711_plat_data = { .version = GENET_V5, .dma_max_burst_length = 0x08, + .flags = GENET_HAS_40BITS | GENET_HAS_EXT | + GENET_HAS_MDIO_INTR | GENET_HAS_MOCA_LINK_DET, }; static const struct bcmgenet_plat_data bcm7712_plat_data = { .version = GENET_V5, .dma_max_burst_length = DMA_MAX_BURST_LENGTH, - .ephy_16nm = true, + .flags = GENET_HAS_40BITS | GENET_HAS_EXT | + GENET_HAS_MDIO_INTR | GENET_HAS_MOCA_LINK_DET | + GENET_HAS_EPHY_16NM, }; static const struct of_device_id bcmgenet_match[] = { @@ -4057,7 +3896,7 @@ static int bcmgenet_probe(struct platform_device *pdev) if (pdata) { priv->version = pdata->version; priv->dma_max_burst_length = pdata->dma_max_burst_length; - priv->ephy_16nm = pdata->ephy_16nm; + priv->flags = pdata->flags; } else { priv->version = pd->genet_version; priv->dma_max_burst_length = DMA_MAX_BURST_LENGTH; @@ -4077,7 +3916,7 @@ static int bcmgenet_probe(struct platform_device *pdev) bcmgenet_set_hw_params(priv); err = -EIO; - if (priv->hw_params->flags & GENET_HAS_40BITS) + if (bcmgenet_has_40bits(priv)) err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40)); if (err) err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); @@ -4132,16 +3971,13 @@ static int bcmgenet_probe(struct platform_device *pdev) if (err) goto err_clk_disable; - /* setup number of real queues + 1 (GENET_V1 has 0 hardware queues - * just the ring 16 descriptor based TX - */ + /* setup number of real queues + 1 */ netif_set_real_num_tx_queues(priv->dev, priv->hw_params->tx_queues + 1); netif_set_real_num_rx_queues(priv->dev, priv->hw_params->rx_queues + 1); /* Set default coalescing parameters */ - for (i = 0; i < priv->hw_params->rx_queues; i++) + for (i = 0; i <= priv->hw_params->rx_queues; i++) priv->rx_rings[i].rx_max_coalesced_frames = 1; - priv->rx_rings[DESC_INDEX].rx_max_coalesced_frames = 1; /* libphy will determine the link state */ netif_carrier_off(dev); @@ -4205,9 +4041,22 @@ static int bcmgenet_resume_noirq(struct device *d) reg = bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_STAT); if (reg & UMAC_IRQ_WAKE_EVENT) pm_wakeup_event(&priv->pdev->dev, 0); + + /* From WOL-enabled suspend, switch to regular clock */ + if (!bcmgenet_power_up(priv, GENET_POWER_WOL_MAGIC)) + return 0; + + /* Failed so fall through to reset MAC */ } - bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_WAKE_EVENT, INTRL2_CPU_CLEAR); + /* If this is an internal GPHY, power it back on now, before UniMAC is + * brought out of reset as absolutely no UniMAC activity is allowed + */ + if (priv->internal_phy) + bcmgenet_power_up(priv, GENET_POWER_PASSIVE); + + /* take MAC out of reset */ + bcmgenet_umac_reset(priv); return 0; } @@ -4217,23 +4066,46 @@ static int bcmgenet_resume(struct device *d) struct net_device *dev = dev_get_drvdata(d); struct bcmgenet_priv *priv = netdev_priv(dev); struct bcmgenet_rxnfc_rule *rule; - unsigned long dma_ctrl; int ret; + u32 reg; if (!netif_running(dev)) return 0; - /* From WOL-enabled suspend, switch to regular clock */ - if (device_may_wakeup(d) && priv->wolopts) - bcmgenet_power_up(priv, GENET_POWER_WOL_MAGIC); - - /* If this is an internal GPHY, power it back on now, before UniMAC is - * brought out of reset as absolutely no UniMAC activity is allowed - */ - if (priv->internal_phy) - bcmgenet_power_up(priv, GENET_POWER_PASSIVE); - - bcmgenet_umac_reset(priv); + if (device_may_wakeup(d) && priv->wolopts) { + reg = bcmgenet_umac_readl(priv, UMAC_CMD); + if (reg & CMD_RX_EN) { + /* Successfully exited WoL, just resume data flows */ + list_for_each_entry(rule, &priv->rxnfc_list, list) + if (rule->state == BCMGENET_RXNFC_STATE_ENABLED) + bcmgenet_hfb_enable_filter(priv, + rule->fs.location + 1); + bcmgenet_hfb_enable_filter(priv, 0); + bcmgenet_set_rx_mode(dev); + bcmgenet_enable_rx_napi(priv); + + /* Reinitialize Tx flows */ + bcmgenet_tdma_disable(priv); + bcmgenet_init_tx_queues(priv->dev); + reg = bcmgenet_tdma_readl(priv, DMA_CTRL); + reg |= DMA_EN; + bcmgenet_tdma_writel(priv, reg, DMA_CTRL); + bcmgenet_enable_tx_napi(priv); + + bcmgenet_link_intr_enable(priv); + phy_start_machine(dev->phydev); + + netif_device_attach(dev); + enable_irq(priv->irq1); + return 0; + } + /* MAC was reset so complete bcmgenet_netif_stop() */ + umac_enable_set(priv, CMD_RX_EN | CMD_TX_EN, false); + bcmgenet_rdma_disable(priv); + bcmgenet_intr_disable(priv); + bcmgenet_fini_dma(priv); + enable_irq(priv->irq1); + } init_umac(priv); @@ -4254,19 +4126,13 @@ static int bcmgenet_resume(struct device *d) if (rule->state != BCMGENET_RXNFC_STATE_UNUSED) bcmgenet_hfb_create_rxnfc_filter(priv, rule); - /* Disable RX/TX DMA and flush TX queues */ - dma_ctrl = bcmgenet_dma_disable(priv, false); - /* Reinitialize TDMA and RDMA and SW housekeeping */ - ret = bcmgenet_init_dma(priv); + ret = bcmgenet_init_dma(priv, false); if (ret) { netdev_err(dev, "failed to initialize DMA\n"); goto out_clk_disable; } - /* Always enable ring 16 - descriptor ring */ - bcmgenet_enable_dma(priv, dma_ctrl); - if (!device_may_wakeup(d)) phy_resume(dev->phydev); @@ -4287,19 +4153,52 @@ static int bcmgenet_suspend(struct device *d) { struct net_device *dev = dev_get_drvdata(d); struct bcmgenet_priv *priv = netdev_priv(dev); + struct bcmgenet_rxnfc_rule *rule; + u32 reg, hfb_enable = 0; if (!netif_running(dev)) return 0; netif_device_detach(dev); - bcmgenet_netif_stop(dev, true); + if (device_may_wakeup(d) && priv->wolopts) { + netif_tx_disable(dev); + + /* Suspend non-wake Rx data flows */ + if (priv->wolopts & WAKE_FILTER) + list_for_each_entry(rule, &priv->rxnfc_list, list) + if (rule->fs.ring_cookie == RX_CLS_FLOW_WAKE && + rule->state == BCMGENET_RXNFC_STATE_ENABLED) + hfb_enable |= 1 << rule->fs.location; + reg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL); + if (GENET_IS_V1(priv) || GENET_IS_V2(priv)) { + reg &= ~RBUF_HFB_FILTER_EN_MASK; + reg |= hfb_enable << (RBUF_HFB_FILTER_EN_SHIFT + 1); + } else { + bcmgenet_hfb_reg_writel(priv, hfb_enable << 1, + HFB_FLT_ENABLE_V3PLUS + 4); + } + if (!hfb_enable) + reg &= ~RBUF_HFB_EN; + bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL); - if (!device_may_wakeup(d)) - phy_suspend(dev->phydev); + /* Clear any old filter matches so only new matches wake */ + bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_MASK_SET); + bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_CLEAR); - /* Disable filtering */ - bcmgenet_hfb_reg_writel(priv, 0, HFB_CTRL); + if (-ETIMEDOUT == bcmgenet_tdma_disable(priv)) + netdev_warn(priv->dev, + "Timed out while disabling TX DMA\n"); + + bcmgenet_disable_tx_napi(priv); + bcmgenet_disable_rx_napi(priv); + disable_irq(priv->irq1); + bcmgenet_tx_reclaim_all(dev); + bcmgenet_fini_tx_napi(priv); + } else { + /* Teardown the interface */ + bcmgenet_netif_stop(dev, true); + } return 0; } |