diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 8d54ca19a047c..7464dcf16b822 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -49,9 +49,17 @@ #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 #define SKB_ALIGNMENT 32 +/* The packet ready threshold truncates a frame where the status block would + * be written, so above ENET_MAX_MTU the blocks have to be turned off. The + * checksum offloads live in those blocks, so they go too. + */ +static bool bcmgenet_jumbo(const struct net_device *dev) +{ + return dev->mtu > ENET_MAX_MTU; +} + /* Tx/Rx DMA register offset, skip 256 descriptors */ #define WORDS_PER_BD(p) (p->hw_params->words_per_bd) #define DMA_DESC_SIZE (WORDS_PER_BD(priv) * sizeof(u32)) @@ -744,8 +752,17 @@ static void bcmgenet_hfb_init(struct bcmgenet_priv *priv) INIT_LIST_HEAD(&priv->rxnfc_rules[i].list); priv->rxnfc_rules[i].state = BCMGENET_RXNFC_STATE_UNUSED; } +} + +static void bcmgenet_hfb_restore(struct bcmgenet_priv *priv) +{ + struct bcmgenet_rxnfc_rule *rule; bcmgenet_hfb_clear(priv); + + list_for_each_entry(rule, &priv->rxnfc_list, list) + if (rule->state != BCMGENET_RXNFC_STATE_UNUSED) + bcmgenet_hfb_create_rxnfc_filter(priv, rule); } static int bcmgenet_begin(struct net_device *dev) @@ -2142,11 +2159,13 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev) */ GENET_CB(skb)->bytes_sent = skb->len; - /* add the Transmit Status Block */ - skb = bcmgenet_add_tsb(dev, skb, ring); - if (!skb) { - ret = NETDEV_TX_OK; - goto out; + /* add the Transmit Status Block, absent in jumbo mode */ + if (!bcmgenet_jumbo(dev)) { + skb = bcmgenet_add_tsb(dev, skb, ring); + if (!skb) { + ret = NETDEV_TX_OK; + goto out; + } } for (i = 0; i <= nr_frags; i++) { @@ -2201,7 +2220,8 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev) GENET_CB(skb)->last_cb = tx_cb_ptr; - bcmgenet_hide_tsb(skb); + if (!bcmgenet_jumbo(dev)) + bcmgenet_hide_tsb(skb); skb_tx_timestamp(skb); /* Decrement total BD count and advance our write pointer */ @@ -2331,6 +2351,10 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, __be16 rx_csum; cb = &priv->rx_cbs[ring->read_ptr]; + if (bcmgenet_jumbo(dev)) + dma_length_status = + bcmgenet_readl(cb->bd_addr + + DMA_DESC_LENGTH_STATUS); skb = bcmgenet_rx_refill(priv, cb); if (unlikely(!skb)) { @@ -2338,13 +2362,17 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, goto next; } - status = (struct status_64 *)skb->data; - dma_length_status = status->length_status; - if (dev->features & NETIF_F_RXCSUM) { - rx_csum = (__force __be16)(status->rx_csum & 0xffff); - if (rx_csum) { - skb->csum = (__force __wsum)ntohs(rx_csum); - skb->ip_summed = CHECKSUM_COMPLETE; + if (!bcmgenet_jumbo(dev)) { + status = (struct status_64 *)skb->data; + dma_length_status = status->length_status; + if (dev->features & NETIF_F_RXCSUM) { + rx_csum = (__force __be16)(status->rx_csum & + 0xffff); + if (rx_csum) { + skb->csum = + (__force __wsum)ntohs(rx_csum); + skb->ip_summed = CHECKSUM_COMPLETE; + } } } @@ -2359,7 +2387,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, __func__, p_index, ring->c_index, ring->read_ptr, dma_length_status); - if (unlikely(len > RX_BUF_LENGTH)) { + if (unlikely(len > priv->rx_buf_len)) { netif_err(priv, rx_status, dev, "oversized packet\n"); BCMGENET_STATS64_INC(stats, length_errors); dev_kfree_skb_any(skb); @@ -2404,9 +2432,14 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, skb_put(skb, len); - /* remove RSB and hardware 2bytes added for IP alignment */ - skb_pull(skb, 66); - len -= 66; + /* remove the alignment bytes, and the RSB if there is one */ + if (bcmgenet_jumbo(dev)) { + skb_pull(skb, ENET_RBUF_ALIGN); + len -= ENET_RBUF_ALIGN; + } else { + skb_pull(skb, ENET_RX_OFFSET); + len -= ENET_RX_OFFSET; + } if (priv->crc_fwd_en) { skb_trim(skb, len - ETH_FCS_LEN); @@ -2588,37 +2621,62 @@ static void bcmgenet_link_intr_enable(struct bcmgenet_priv *priv) bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR); } -static void init_umac(struct bcmgenet_priv *priv) +/* Threshold in register units. Covers the alignment bytes and the frame, but + * not the status block, which the hardware adds on top. + */ +static unsigned int bcmgenet_pkt_rdy_thld(unsigned int mtu) { - struct device *kdev = &priv->pdev->dev; - u32 reg; - u32 int0_enable = 0; + unsigned int len = ENET_RBUF_ALIGN + mtu + ETH_HLEN + VLAN_HLEN; - dev_dbg(&priv->pdev->dev, "bcmgenet: init_umac\n"); + len = round_up(len, ENET_THLD_BURST) / ENET_THLD_UNIT; - reset_umac(priv); + /* Keep the reset default for the common MTUs */ + return clamp_t(unsigned int, len, ENET_THLD_DEFAULT, ENET_THLD_MAX); +} - /* clear tx/rx counter */ - bcmgenet_umac_writel(priv, - MIB_RESET_RX | MIB_RESET_TX | MIB_RESET_RUNT, - UMAC_MIB_CTRL); - bcmgenet_umac_writel(priv, 0, UMAC_MIB_CTRL); +/* A buffer has to hold everything the hardware can deliver: a whole frame in + * jumbo mode, the threshold plus the status block otherwise. + */ +static unsigned int bcmgenet_rx_buf_len(unsigned int mtu) +{ + if (mtu > ENET_MAX_MTU) + return round_up(ENET_RBUF_ALIGN + ENET_MAX_FRAME_LEN(mtu), + ENET_THLD_BURST); - bcmgenet_umac_writel(priv, ENET_MAX_MTU_SIZE, UMAC_MAX_FRAME_LEN); + return ENET_RSB_LEN + bcmgenet_pkt_rdy_thld(mtu) * ENET_THLD_UNIT; +} + +/* The status blocks follow the MTU, so this runs on an MTU change as well as + * at open. Call with the MAC disabled. + */ +static void bcmgenet_set_status_blocks(struct bcmgenet_priv *priv) +{ + bool jumbo = bcmgenet_jumbo(priv->dev); + u32 reg; - /* init tx registers, enable TSB */ reg = bcmgenet_tbuf_ctrl_get(priv); - reg |= TBUF_64B_EN; + if (jumbo) + reg &= ~TBUF_64B_EN; + else + reg |= TBUF_64B_EN; bcmgenet_tbuf_ctrl_set(priv, reg); - /* init rx registers, enable ip header optimization and RSB */ + /* ip header optimization stays on, the RSB follows the MTU */ reg = bcmgenet_rbuf_readl(priv, RBUF_CTRL); - reg |= RBUF_ALIGN_2B | RBUF_64B_EN; + reg |= RBUF_ALIGN_2B; + if (jumbo) + reg &= ~RBUF_64B_EN; + else + reg |= RBUF_64B_EN; bcmgenet_rbuf_writel(priv, reg, RBUF_CTRL); - /* enable rx checksumming */ + /* rx checksumming needs the RSB */ reg = bcmgenet_rbuf_readl(priv, RBUF_CHK_CTRL); - reg |= RBUF_RXCHK_EN | RBUF_L3_PARSE_DIS; + reg |= RBUF_L3_PARSE_DIS; + if (jumbo) + reg &= ~RBUF_RXCHK_EN; + else + reg |= RBUF_RXCHK_EN; /* If UniMAC forwards CRC, we need to skip over it to get * a valid CHK bit to be set in the per-packet status word */ @@ -2627,6 +2685,44 @@ static void init_umac(struct bcmgenet_priv *priv) else reg &= ~RBUF_SKIP_FCS; bcmgenet_rbuf_writel(priv, reg, RBUF_CHK_CTRL); +} + +/* Program the MTU dependent registers. Call with the MAC disabled. */ +static void bcmgenet_set_mtu_regs(struct bcmgenet_priv *priv, unsigned int mtu) +{ + u32 thld; + + bcmgenet_umac_writel(priv, ENET_MAX_FRAME_LEN(mtu), UMAC_MAX_FRAME_LEN); + + /* GENET v1 maps other registers at these offsets */ + if (GENET_IS_V1(priv)) + return; + + thld = bcmgenet_pkt_rdy_thld(mtu); + bcmgenet_rbuf_writel(priv, thld, RBUF_PKT_RDY_THLD); + bcmgenet_writel(thld, priv->base + priv->hw_params->tbuf_offset + + TBUF_PKT_RDY_THLD); +} + +static void init_umac(struct bcmgenet_priv *priv) +{ + struct device *kdev = &priv->pdev->dev; + u32 reg; + u32 int0_enable = 0; + + dev_dbg(&priv->pdev->dev, "bcmgenet: init_umac\n"); + + reset_umac(priv); + + /* clear tx/rx counter */ + bcmgenet_umac_writel(priv, + MIB_RESET_RX | MIB_RESET_TX | MIB_RESET_RUNT, + UMAC_MIB_CTRL); + bcmgenet_umac_writel(priv, 0, UMAC_MIB_CTRL); + + bcmgenet_set_mtu_regs(priv, priv->dev->mtu); + + bcmgenet_set_status_blocks(priv); if (!GENET_IS_V1(priv) && !GENET_IS_V2(priv)) bcmgenet_rbuf_writel(priv, 1, RBUF_TBUF_SIZE_CTRL); @@ -2710,7 +2806,7 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv, /* Set flow period for ring != 0 */ if (index) - flow_period_val = ENET_MAX_MTU_SIZE << 16; + flow_period_val = ENET_MAX_FRAME_LEN(priv->dev->mtu) << 16; bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_PROD_INDEX); bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_CONS_INDEX); @@ -2720,7 +2816,7 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv, TDMA_FLOW_PERIOD); bcmgenet_tdma_ring_writel(priv, index, ((size << DMA_RING_SIZE_SHIFT) | - RX_BUF_LENGTH), DMA_RING_BUF_SIZE); + priv->rx_buf_len), DMA_RING_BUF_SIZE); /* Set start and end address, read and write pointers */ bcmgenet_tdma_ring_writel(priv, index, start_ptr * words_per_bd, @@ -2768,7 +2864,7 @@ static int bcmgenet_init_rx_ring(struct bcmgenet_priv *priv, bcmgenet_rdma_ring_writel(priv, index, 0, RDMA_CONS_INDEX); bcmgenet_rdma_ring_writel(priv, index, ((size << DMA_RING_SIZE_SHIFT) | - RX_BUF_LENGTH), DMA_RING_BUF_SIZE); + priv->rx_buf_len), DMA_RING_BUF_SIZE); bcmgenet_rdma_ring_writel(priv, index, (DMA_FC_THRESH_LO << DMA_XOFF_THRESHOLD_SHIFT) | @@ -3013,6 +3109,10 @@ static void bcmgenet_fini_dma(struct bcmgenet_priv *priv) struct netdev_queue *txq; int i; + /* An MTU change can fail with the rings already freed */ + if (!priv->rx_cbs) + return; + bcmgenet_fini_rx_napi(priv); bcmgenet_fini_tx_napi(priv); @@ -3023,7 +3123,9 @@ static void bcmgenet_fini_dma(struct bcmgenet_priv *priv) bcmgenet_free_rx_buffers(priv); kfree(priv->rx_cbs); + priv->rx_cbs = NULL; kfree(priv->tx_cbs); + priv->tx_cbs = NULL; } /* init_edma: Initialize DMA control register */ @@ -3083,6 +3185,7 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *priv, bool flush_rx) GFP_KERNEL); if (!priv->tx_cbs) { kfree(priv->rx_cbs); + priv->rx_cbs = NULL; return -ENOMEM; } @@ -3101,7 +3204,9 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *priv, bool flush_rx) netdev_err(priv->dev, "failed to initialize Rx queues\n"); bcmgenet_free_rx_buffers(priv); kfree(priv->rx_cbs); + priv->rx_cbs = NULL; kfree(priv->tx_cbs); + priv->tx_cbs = NULL; return ret; } @@ -3270,7 +3375,7 @@ static void bcmgenet_get_hw_addr(struct bcmgenet_priv *priv, put_unaligned_be16(addr_tmp, &addr[4]); } -static void bcmgenet_netif_start(struct net_device *dev) +static void bcmgenet_netif_start(struct net_device *dev, bool start_phy) { struct bcmgenet_priv *priv = netdev_priv(dev); @@ -3287,7 +3392,8 @@ static void bcmgenet_netif_start(struct net_device *dev) /* Monitor link interrupts now */ bcmgenet_link_intr_enable(priv); - phy_start(dev->phydev); + if (start_phy) + phy_start(dev->phydev); } static int bcmgenet_open(struct net_device *dev) @@ -3318,8 +3424,8 @@ static int bcmgenet_open(struct net_device *dev) bcmgenet_set_hw_addr(priv, dev->dev_addr); - /* HFB init */ - bcmgenet_hfb_init(priv); + /* Restore the filters, the MAC was reset above */ + bcmgenet_hfb_restore(priv); /* Reinitialize TDMA and RDMA and SW housekeeping */ ret = bcmgenet_init_dma(priv, true); @@ -3350,8 +3456,9 @@ static int bcmgenet_open(struct net_device *dev) bcmgenet_phy_pause_set(dev, priv->rx_pause, priv->tx_pause); - bcmgenet_netif_start(dev); + bcmgenet_netif_start(dev, true); + priv->datapath_up = true; netif_tx_start_all_queues(dev); return 0; @@ -3374,6 +3481,8 @@ static void bcmgenet_netif_stop(struct net_device *dev, bool stop_phy) { struct bcmgenet_priv *priv = netdev_priv(dev); + /* Stop completion polling before it can wake a stopped queue */ + bcmgenet_disable_tx_napi(priv); netif_tx_disable(dev); /* Disable MAC receive */ @@ -3388,7 +3497,6 @@ static void bcmgenet_netif_stop(struct net_device *dev, bool stop_phy) /* Disable MAC transmit. TX DMA disabled must be done before this */ umac_enable_set(priv, CMD_TX_EN, false); - bcmgenet_disable_tx_napi(priv); bcmgenet_disable_rx_napi(priv); bcmgenet_intr_disable(priv); @@ -3409,7 +3517,11 @@ static int bcmgenet_close(struct net_device *dev) netif_dbg(priv, ifdown, dev, "bcmgenet_close\n"); - bcmgenet_netif_stop(dev, false); + /* A failed MTU change can have torn the datapath down already */ + if (priv->datapath_up) { + bcmgenet_netif_stop(dev, false); + priv->datapath_up = false; + } /* Really kill the PHY state machine and disconnect from it */ phy_disconnect(dev->phydev); @@ -3654,6 +3766,83 @@ static int bcmgenet_change_carrier(struct net_device *dev, bool new_carrier) return 0; } +/* Jumbo turns off the status blocks that carry both checksum offloads. Mask + * them here rather than clearing hw_features: a feature set in features but + * missing from hw_features counts as permanently on. + */ +static netdev_features_t bcmgenet_fix_features(struct net_device *dev, + netdev_features_t features) +{ + if (bcmgenet_jumbo(dev)) + features &= ~(NETIF_F_HW_CSUM | NETIF_F_RXCSUM); + + return features; +} + +static int bcmgenet_change_mtu(struct net_device *dev, int new_mtu) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + unsigned int old_mtu = dev->mtu; + int ret; + + if (!netif_running(dev)) { + WRITE_ONCE(dev->mtu, new_mtu); + priv->rx_buf_len = bcmgenet_rx_buf_len(new_mtu); + netdev_update_features(dev); + return 0; + } + + /* The watchdog trips on an idle queue once the rings are gone */ + netif_device_detach(dev); + + /* Only the buffers and the MTU registers change, leave the PHY up */ + bcmgenet_netif_stop(dev, false); + priv->datapath_up = false; + + WRITE_ONCE(dev->mtu, new_mtu); + priv->rx_buf_len = bcmgenet_rx_buf_len(new_mtu); + bcmgenet_set_mtu_regs(priv, new_mtu); + bcmgenet_set_status_blocks(priv); + + ret = bcmgenet_init_dma(priv, true); + if (ret) { + /* Retry the size that was allocated a moment ago */ + WRITE_ONCE(dev->mtu, old_mtu); + priv->rx_buf_len = bcmgenet_rx_buf_len(old_mtu); + bcmgenet_set_mtu_regs(priv, old_mtu); + bcmgenet_set_status_blocks(priv); + if (bcmgenet_init_dma(priv, true)) { + /* Nothing left to run on. Take the interface down so + * that close and suspend do not tear it down twice. + */ + netdev_err(dev, "failed to restore MTU %u, closing\n", + old_mtu); + netif_close(dev); + + /* Mark the device present again, __dev_open() + * refuses a detached one. The queues stay stopped + * because the interface is down by now. + */ + netif_device_attach(dev); + return ret; + } + } + + bcmgenet_hfb_restore(priv); + bcmgenet_netif_start(dev, false); + + /* bcmgenet_netif_start() only restores the link interrupt */ + if (bcmgenet_has_mdio_intr(priv)) + bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_MDIO_EVENT, + INTRL2_CPU_MASK_CLEAR); + + priv->datapath_up = true; + netif_device_attach(dev); + netdev_update_features(dev); + + return ret; +} + static const struct net_device_ops bcmgenet_netdev_ops = { .ndo_open = bcmgenet_open, .ndo_stop = bcmgenet_close, @@ -3665,6 +3854,8 @@ static const struct net_device_ops bcmgenet_netdev_ops = { .ndo_set_features = bcmgenet_set_features, .ndo_get_stats64 = bcmgenet_get_stats64, .ndo_change_carrier = bcmgenet_change_carrier, + .ndo_change_mtu = bcmgenet_change_mtu, + .ndo_fix_features = bcmgenet_fix_features, }; /* GENET hardware parameters/characteristics */ @@ -4021,8 +4212,12 @@ static int bcmgenet_probe(struct platform_device *pdev) /* Mii wait queue */ init_waitqueue_head(&priv->wq); - /* Always use RX_BUF_LENGTH (2KB) buffer for all chips */ - priv->rx_buf_len = RX_BUF_LENGTH; + bcmgenet_hfb_init(priv); + + /* v1 cannot program the thresholds, so it stays at the default MTU */ + priv->rx_buf_len = bcmgenet_rx_buf_len(dev->mtu); + if (!GENET_IS_V1(priv)) + dev->max_mtu = ENET_MAX_JUMBO_MTU; INIT_WORK(&priv->bcmgenet_irq_work, bcmgenet_irq_task); priv->clk_wol = devm_clk_get_optional(&priv->pdev->dev, "enet-wol"); @@ -4225,10 +4420,7 @@ static int bcmgenet_resume(struct device *d) bcmgenet_set_hw_addr(priv, dev->dev_addr); /* Restore hardware filters */ - bcmgenet_hfb_clear(priv); - list_for_each_entry(rule, &priv->rxnfc_list, list) - if (rule->state != BCMGENET_RXNFC_STATE_UNUSED) - bcmgenet_hfb_create_rxnfc_filter(priv, rule); + bcmgenet_hfb_restore(priv); /* Reinitialize TDMA and RDMA and SW housekeeping */ ret = bcmgenet_init_dma(priv, false); @@ -4240,7 +4432,7 @@ static int bcmgenet_resume(struct device *d) if (!device_may_wakeup(d)) phy_resume(dev->phydev); - bcmgenet_netif_start(dev); + bcmgenet_netif_start(dev, true); netif_device_attach(dev); diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index 9e4110c7fdf6f..bf47be87f7af0 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -27,13 +27,39 @@ /* which ring is descriptor based */ #define DESC_INDEX 16 -/* Body(1500) + EH_SIZE(14) + VLANTAG(4) + BRCMTAG(6) + FCS(4) = 1528. - * 1536 is multiple of 256 bytes - */ #define ENET_BRCM_TAG_LEN 6 #define ENET_PAD 8 -#define ENET_MAX_MTU_SIZE (ETH_DATA_LEN + ETH_HLEN + VLAN_HLEN + \ + +/* The hardware writes a status block and two alignment bytes ahead of the + * frame. + */ +#define ENET_RSB_LEN 64 +#define ENET_RBUF_ALIGN 2 +#define ENET_RX_OFFSET (ENET_RSB_LEN + ENET_RBUF_ALIGN) + +/* Longest frame the MAC must accept for a given MTU */ +#define ENET_MAX_FRAME_LEN(mtu) ((mtu) + ETH_HLEN + VLAN_HLEN + \ ENET_BRCM_TAG_LEN + ETH_FCS_LEN + ENET_PAD) + +/* RBUF and TBUF hand a frame to the DMA once the threshold is reached, so a + * longer frame arrives without an end of packet marker and is dropped. Both + * registers are 8 bit in units of 16 bytes and want a multiple of the 256 + * byte burst size, so 0xf0 is the largest usable value. + */ +#define ENET_THLD_UNIT 16 +#define ENET_THLD_BURST 256 +#define ENET_THLD_DEFAULT 0x80 +#define ENET_THLD_MAX 0xf0 +#define ENET_THLD_MAX_LEN (ENET_THLD_MAX * ENET_THLD_UNIT) + +/* Largest MTU the threshold allows while the status blocks are in use, with + * room for a VLAN tag so a VLAN interface can use the parent MTU. + */ +#define ENET_MAX_MTU (ENET_THLD_MAX_LEN - ENET_RBUF_ALIGN - \ + ETH_HLEN - VLAN_HLEN) + +/* Above that the status blocks have to be turned off, see bcmgenet_jumbo() */ +#define ENET_MAX_JUMBO_MTU 9000 #define DMA_MAX_BURST_LENGTH 0x10 /* misc. configuration */ @@ -219,6 +245,8 @@ struct bcmgenet_rx_stats64 { #define RBUF_ALIGN_2B (1 << 1) #define RBUF_BAD_DIS (1 << 2) +#define RBUF_PKT_RDY_THLD 0x08 + #define RBUF_STATUS 0x0C #define RBUF_STATUS_WOL (1 << 0) #define RBUF_STATUS_MPD_INTR_ACTIVE (1 << 1) @@ -249,6 +277,7 @@ struct bcmgenet_rx_stats64 { #define TBUF_CTRL 0x00 #define TBUF_64B_EN (1 << 0) #define TBUF_BP_MC 0x0C +#define TBUF_PKT_RDY_THLD 0x10 #define TBUF_ENERGY_CTRL 0x14 #define TBUF_EEE_EN (1 << 0) #define TBUF_PM_EN (1 << 1) @@ -616,6 +645,7 @@ struct bcmgenet_priv { struct bcmgenet_rx_ring rx_rings[GENET_MAX_MQ_CNT + 1]; /* other misc variables */ + bool datapath_up; const struct bcmgenet_hw_params *hw_params; u32 flags; unsigned autoneg_pause:1;