diff options
Diffstat (limited to 'drivers/net/ethernet/freescale/fec_main.c')
| -rw-r--r-- | drivers/net/ethernet/freescale/fec_main.c | 550 |
1 files changed, 305 insertions, 245 deletions
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 1b55047c0237..c685a5c0cc51 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -22,56 +22,56 @@ * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. */ -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/pm_runtime.h> -#include <linux/ptrace.h> -#include <linux/errno.h> -#include <linux/ioport.h> -#include <linux/slab.h> -#include <linux/interrupt.h> +#include <linux/bitops.h> +#include <linux/bpf.h> +#include <linux/bpf_trace.h> +#include <linux/cacheflush.h> +#include <linux/clk.h> +#include <linux/crc32.h> #include <linux/delay.h> -#include <linux/netdevice.h> +#include <linux/errno.h> #include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/in.h> -#include <linux/ip.h> -#include <net/ip.h> -#include <net/page_pool/helpers.h> -#include <net/selftests.h> -#include <net/tso.h> -#include <linux/tcp.h> -#include <linux/udp.h> +#include <linux/fec.h> +#include <linux/filter.h> +#include <linux/gpio/consumer.h> #include <linux/icmp.h> -#include <linux/spinlock.h> -#include <linux/workqueue.h> -#include <linux/bitops.h> +#include <linux/if_vlan.h> +#include <linux/in.h> +#include <linux/interrupt.h> #include <linux/io.h> +#include <linux/ioport.h> +#include <linux/ip.h> #include <linux/irq.h> -#include <linux/clk.h> -#include <linux/crc32.h> -#include <linux/platform_device.h> -#include <linux/property.h> +#include <linux/kernel.h> #include <linux/mdio.h> -#include <linux/phy.h> -#include <linux/fec.h> +#include <linux/mfd/syscon.h> +#include <linux/module.h> +#include <linux/netdevice.h> #include <linux/of.h> #include <linux/of_mdio.h> #include <linux/of_net.h> -#include <linux/regulator/consumer.h> -#include <linux/if_vlan.h> +#include <linux/phy.h> #include <linux/pinctrl/consumer.h> -#include <linux/gpio/consumer.h> +#include <linux/phy_fixed.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/prefetch.h> -#include <linux/mfd/syscon.h> +#include <linux/property.h> +#include <linux/ptrace.h> #include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/skbuff.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/string.h> +#include <linux/tcp.h> +#include <linux/udp.h> +#include <linux/workqueue.h> +#include <net/ip.h> +#include <net/page_pool/helpers.h> +#include <net/selftests.h> +#include <net/tso.h> #include <soc/imx/cpuidle.h> -#include <linux/filter.h> -#include <linux/bpf.h> -#include <linux/bpf_trace.h> - -#include <asm/cacheflush.h> #include "fec.h" @@ -131,7 +131,7 @@ static const struct fec_devinfo fec_mvf600_info = { FEC_QUIRK_HAS_MDIO_C45, }; -static const struct fec_devinfo fec_imx6x_info = { +static const struct fec_devinfo fec_imx6sx_info = { .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM | FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB | @@ -168,7 +168,8 @@ static const struct fec_devinfo fec_imx8qm_info = { FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE | FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_COALESCE | FEC_QUIRK_CLEAR_SETUP_MII | FEC_QUIRK_HAS_MULTI_QUEUES | - FEC_QUIRK_DELAYED_CLKS_SUPPORT | FEC_QUIRK_HAS_MDIO_C45, + FEC_QUIRK_DELAYED_CLKS_SUPPORT | FEC_QUIRK_HAS_MDIO_C45 | + FEC_QUIRK_JUMBO_FRAME, }; static const struct fec_devinfo fec_s32v234_info = { @@ -196,7 +197,7 @@ static const struct of_device_id fec_dt_ids[] = { { .compatible = "fsl,imx28-fec", .data = &fec_imx28_info, }, { .compatible = "fsl,imx6q-fec", .data = &fec_imx6q_info, }, { .compatible = "fsl,mvf600-fec", .data = &fec_mvf600_info, }, - { .compatible = "fsl,imx6sx-fec", .data = &fec_imx6x_info, }, + { .compatible = "fsl,imx6sx-fec", .data = &fec_imx6sx_info, }, { .compatible = "fsl,imx6ul-fec", .data = &fec_imx6ul_info, }, { .compatible = "fsl,imx8mq-fec", .data = &fec_imx8mq_info, }, { .compatible = "fsl,imx8qm-fec", .data = &fec_imx8qm_info, }, @@ -234,6 +235,7 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); * 2048 byte skbufs are allocated. However, alignment requirements * varies between FEC variants. Worst case is 64, so round down by 64. */ +#define MAX_JUMBO_BUF_SIZE (round_down(16384 - FEC_DRV_RESERVE_SPACE - 64, 64)) #define PKT_MAXBUF_SIZE (round_down(2048 - 64, 64)) #define PKT_MINBUF_SIZE 64 @@ -251,12 +253,10 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); * size bits. Other FEC hardware does not, so we need to take that into * account when setting it. */ -#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ - defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARM) || \ - defined(CONFIG_ARM64) -#define OPT_FRAME_SIZE (PKT_MAXBUF_SIZE << 16) +#ifndef CONFIG_M5272 +#define OPT_ARCH_HAS_MAX_FL 1 #else -#define OPT_FRAME_SIZE 0 +#define OPT_ARCH_HAS_MAX_FL 0 #endif /* FEC MII MMFR bits definition */ @@ -276,16 +276,19 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); #define FEC_ECR_MAGICEN BIT(2) #define FEC_ECR_SLEEP BIT(3) #define FEC_ECR_EN1588 BIT(4) +#define FEC_ECR_SPEED BIT(5) #define FEC_ECR_BYTESWP BIT(8) /* FEC RCR bits definition */ #define FEC_RCR_LOOP BIT(0) -#define FEC_RCR_HALFDPX BIT(1) +#define FEC_RCR_DRT BIT(1) #define FEC_RCR_MII BIT(2) #define FEC_RCR_PROMISC BIT(3) #define FEC_RCR_BC_REJ BIT(4) #define FEC_RCR_FLOWCTL BIT(5) +#define FEC_RCR_RGMII BIT(6) #define FEC_RCR_RMII BIT(8) #define FEC_RCR_10BASET BIT(9) +#define FEC_RCR_NLC BIT(30) /* TX WMARK bits */ #define FEC_TXWMRK_STRFWD BIT(8) @@ -468,14 +471,14 @@ fec_enet_create_page_pool(struct fec_enet_private *fep, { struct bpf_prog *xdp_prog = READ_ONCE(fep->xdp_prog); struct page_pool_params pp_params = { - .order = 0, + .order = fep->pagepool_order, .flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV, .pool_size = size, .nid = dev_to_node(&fep->pdev->dev), .dev = &fep->pdev->dev, .dma_dir = xdp_prog ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE, .offset = FEC_ENET_XDP_HEADROOM, - .max_len = FEC_ENET_RX_FRSIZE, + .max_len = fep->rx_frame_size, }; int err; @@ -714,7 +717,12 @@ static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq, txq->bd.cur = bdp; /* Trigger transmission start */ - writel(0, txq->bd.reg_desc_active); + if (!(fep->quirks & FEC_QUIRK_ERR007885) || + !readl(txq->bd.reg_desc_active) || + !readl(txq->bd.reg_desc_active) || + !readl(txq->bd.reg_desc_active) || + !readl(txq->bd.reg_desc_active)) + writel(0, txq->bd.reg_desc_active); return 0; } @@ -840,6 +848,8 @@ static int fec_enet_txq_submit_tso(struct fec_enet_priv_tx_q *txq, struct fec_enet_private *fep = netdev_priv(ndev); int hdr_len, total_len, data_left; struct bufdesc *bdp = txq->bd.cur; + struct bufdesc *tmp_bdp; + struct bufdesc_ex *ebdp; struct tso_t tso; unsigned int index = 0; int ret; @@ -913,7 +923,34 @@ static int fec_enet_txq_submit_tso(struct fec_enet_priv_tx_q *txq, return 0; err_release: - /* TODO: Release all used data descriptors for TSO */ + /* Release all used data descriptors for TSO */ + tmp_bdp = txq->bd.cur; + + while (tmp_bdp != bdp) { + /* Unmap data buffers */ + if (tmp_bdp->cbd_bufaddr && + !IS_TSO_HEADER(txq, fec32_to_cpu(tmp_bdp->cbd_bufaddr))) + dma_unmap_single(&fep->pdev->dev, + fec32_to_cpu(tmp_bdp->cbd_bufaddr), + fec16_to_cpu(tmp_bdp->cbd_datlen), + DMA_TO_DEVICE); + + /* Clear standard buffer descriptor fields */ + tmp_bdp->cbd_sc = 0; + tmp_bdp->cbd_datlen = 0; + tmp_bdp->cbd_bufaddr = 0; + + /* Handle extended descriptor if enabled */ + if (fep->bufdesc_ex) { + ebdp = (struct bufdesc_ex *)tmp_bdp; + ebdp->cbd_esc = 0; + } + + tmp_bdp = fec_enet_get_nextdesc(tmp_bdp, &txq->bd); + } + + dev_kfree_skb_any(skb); + return ret; } @@ -973,7 +1010,7 @@ static void fec_enet_bd_init(struct net_device *dev) /* Set the last buffer to wrap */ bdp = fec_enet_get_prevdesc(bdp, &rxq->bd); - bdp->cbd_sc |= cpu_to_fec16(BD_SC_WRAP); + bdp->cbd_sc |= cpu_to_fec16(BD_ENET_RX_WRAP); rxq->bd.cur = rxq->bd.base; } @@ -1009,7 +1046,9 @@ static void fec_enet_bd_init(struct net_device *dev) struct page *page = txq->tx_buf[i].buf_p; if (page) - page_pool_put_page(page->pp, page, 0, false); + page_pool_put_page(pp_page_to_nmdesc(page)->pp, + page, 0, + false); } txq->tx_buf[i].buf_p = NULL; @@ -1021,7 +1060,7 @@ static void fec_enet_bd_init(struct net_device *dev) /* Set the last buffer to wrap */ bdp = fec_enet_get_prevdesc(bdp, &txq->bd); - bdp->cbd_sc |= cpu_to_fec16(BD_SC_WRAP); + bdp->cbd_sc |= cpu_to_fec16(BD_ENET_TX_WRAP); txq->dirty_tx = bdp; } } @@ -1045,7 +1084,7 @@ static void fec_enet_enable_ring(struct net_device *ndev) for (i = 0; i < fep->num_rx_queues; i++) { rxq = fep->rx_queue[i]; writel(rxq->bd.dma, fep->hwp + FEC_R_DES_START(i)); - writel(PKT_MAXBUF_SIZE, fep->hwp + FEC_R_BUFF_SIZE(i)); + writel(fep->max_buf_size, fep->hwp + FEC_R_BUFF_SIZE(i)); /* enable DMA1/2 */ if (i) @@ -1064,6 +1103,40 @@ static void fec_enet_enable_ring(struct net_device *ndev) } } +/* Whack a reset. We should wait for this. + * For i.MX6SX SOC, enet use AXI bus, we use disable MAC + * instead of reset MAC itself. + */ +static void fec_ctrl_reset(struct fec_enet_private *fep, bool allow_wol) +{ + u32 val; + + if (!allow_wol || !(fep->wol_flag & FEC_WOL_FLAG_SLEEP_ON)) { + if (fep->quirks & FEC_QUIRK_HAS_MULTI_QUEUES || + ((fep->quirks & FEC_QUIRK_NO_HARD_RESET) && fep->link)) { + writel(0, fep->hwp + FEC_ECNTRL); + } else { + writel(FEC_ECR_RESET, fep->hwp + FEC_ECNTRL); + udelay(10); + } + } else { + val = readl(fep->hwp + FEC_ECNTRL); + val |= (FEC_ECR_MAGICEN | FEC_ECR_SLEEP); + writel(val, fep->hwp + FEC_ECNTRL); + } +} + +static void fec_set_hw_mac_addr(struct net_device *ndev) +{ + struct fec_enet_private *fep = netdev_priv(ndev); + + writel(ndev->dev_addr[3] | (ndev->dev_addr[2] << 8) | + (ndev->dev_addr[1] << 16) | (ndev->dev_addr[0] << 24), + fep->hwp + FEC_ADDR_LOW); + writel((ndev->dev_addr[5] << 16) | (ndev->dev_addr[4] << 24), + fep->hwp + FEC_ADDR_HIGH); +} + /* * This function is called to start or restart the FEC during a link * change, transmit timeout, or to reconfigure the FEC. The network @@ -1073,34 +1146,22 @@ static void fec_restart(struct net_device *ndev) { struct fec_enet_private *fep = netdev_priv(ndev); - u32 temp_mac[2]; - u32 rcntl = OPT_FRAME_SIZE | 0x04; u32 ecntl = FEC_ECR_ETHEREN; + u32 rcntl = FEC_RCR_MII; + + if (OPT_ARCH_HAS_MAX_FL) + rcntl |= (fep->netdev->mtu + ETH_HLEN + ETH_FCS_LEN) << 16; if (fep->bufdesc_ex) fec_ptp_save_state(fep); - /* Whack a reset. We should wait for this. - * For i.MX6SX SOC, enet use AXI bus, we use disable MAC - * instead of reset MAC itself. - */ - if (fep->quirks & FEC_QUIRK_HAS_MULTI_QUEUES || - ((fep->quirks & FEC_QUIRK_NO_HARD_RESET) && fep->link)) { - writel(0, fep->hwp + FEC_ECNTRL); - } else { - writel(1, fep->hwp + FEC_ECNTRL); - udelay(10); - } + fec_ctrl_reset(fep, false); /* * enet-mac reset will reset mac address registers too, * so need to reconfigure it. */ - memcpy(&temp_mac, ndev->dev_addr, ETH_ALEN); - writel((__force u32)cpu_to_be32(temp_mac[0]), - fep->hwp + FEC_ADDR_LOW); - writel((__force u32)cpu_to_be32(temp_mac[1]), - fep->hwp + FEC_ADDR_HIGH); + fec_set_hw_mac_addr(ndev); /* Clear any outstanding interrupt, except MDIO. */ writel((0xffffffff & ~FEC_ENET_MII), fep->hwp + FEC_IEVENT); @@ -1115,7 +1176,7 @@ fec_restart(struct net_device *ndev) writel(0x04, fep->hwp + FEC_X_CNTRL); } else { /* No Rcv on Xmit */ - rcntl |= 0x02; + rcntl |= FEC_RCR_DRT; writel(0x0, fep->hwp + FEC_X_CNTRL); } @@ -1134,7 +1195,7 @@ fec_restart(struct net_device *ndev) else val &= ~FEC_RACC_OPTIONS; writel(val, fep->hwp + FEC_RACC); - writel(PKT_MAXBUF_SIZE, fep->hwp + FEC_FTRL); + writel(min(fep->rx_frame_size, fep->max_buf_size), fep->hwp + FEC_FTRL); } #endif @@ -1144,14 +1205,11 @@ fec_restart(struct net_device *ndev) */ if (fep->quirks & FEC_QUIRK_ENET_MAC) { /* Enable flow control and length check */ - rcntl |= 0x40000000 | 0x00000020; + rcntl |= FEC_RCR_NLC | FEC_RCR_FLOWCTL; /* RGMII, RMII or MII */ - if (fep->phy_interface == PHY_INTERFACE_MODE_RGMII || - fep->phy_interface == PHY_INTERFACE_MODE_RGMII_ID || - fep->phy_interface == PHY_INTERFACE_MODE_RGMII_RXID || - fep->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID) - rcntl |= (1 << 6); + if (phy_interface_mode_is_rgmii(fep->phy_interface)) + rcntl |= FEC_RCR_RGMII; else if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) rcntl |= FEC_RCR_RMII; else @@ -1160,7 +1218,7 @@ fec_restart(struct net_device *ndev) /* 1G, 100M or 10M */ if (ndev->phydev) { if (ndev->phydev->speed == SPEED_1000) - ecntl |= (1 << 5); + ecntl |= FEC_ECR_SPEED; else if (ndev->phydev->speed == SPEED_100) rcntl &= ~FEC_RCR_10BASET; else @@ -1224,8 +1282,18 @@ fec_restart(struct net_device *ndev) if (fep->quirks & FEC_QUIRK_ENET_MAC) { /* enable ENET endian swap */ ecntl |= FEC_ECR_BYTESWP; - /* enable ENET store and forward mode */ - writel(FEC_TXWMRK_STRFWD, fep->hwp + FEC_X_WMRK); + + /* When Jumbo Frame is enabled, the FIFO may not be large enough + * to hold an entire frame. In such cases, if the MTU exceeds + * (PKT_MAXBUF_SIZE - ETH_HLEN - ETH_FCS_LEN), configure the interface + * to operate in cut-through mode, triggered by the FIFO threshold. + * Otherwise, enable the ENET store-and-forward mode. + */ + if ((fep->quirks & FEC_QUIRK_JUMBO_FRAME) && + (ndev->mtu > (PKT_MAXBUF_SIZE - ETH_HLEN - ETH_FCS_LEN))) + writel(0xF, fep->hwp + FEC_X_WMRK); + else + writel(FEC_TXWMRK_STRFWD, fep->hwp + FEC_X_WMRK); } if (fep->bufdesc_ex) @@ -1344,22 +1412,7 @@ fec_stop(struct net_device *ndev) if (fep->bufdesc_ex) fec_ptp_save_state(fep); - /* Whack a reset. We should wait for this. - * For i.MX6SX SOC, enet use AXI bus, we use disable MAC - * instead of reset MAC itself. - */ - if (!(fep->wol_flag & FEC_WOL_FLAG_SLEEP_ON)) { - if (fep->quirks & FEC_QUIRK_HAS_MULTI_QUEUES) { - writel(0, fep->hwp + FEC_ECNTRL); - } else { - writel(FEC_ECR_RESET, fep->hwp + FEC_ECNTRL); - udelay(10); - } - } else { - val = readl(fep->hwp + FEC_ECNTRL); - val |= (FEC_ECR_MAGICEN | FEC_ECR_SLEEP); - writel(val, fep->hwp + FEC_ECNTRL); - } + fec_ctrl_reset(fep, true); writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); @@ -1549,7 +1602,8 @@ fec_enet_tx_queue(struct net_device *ndev, u16 queue_id, int budget) xdp_return_frame_rx_napi(xdpf); } else { /* recycle pages of XDP_TX frames */ /* The dma_sync_size = 0 as XDP_TX has already synced DMA for_device */ - page_pool_put_page(page->pp, page, 0, true); + page_pool_put_page(pp_page_to_nmdesc(page)->pp, page, + 0, true); } txq->tx_buf[index].buf_p = NULL; @@ -1591,19 +1645,21 @@ static void fec_enet_tx(struct net_device *ndev, int budget) fec_enet_tx_queue(ndev, i, budget); } -static void fec_enet_update_cbd(struct fec_enet_priv_rx_q *rxq, +static int fec_enet_update_cbd(struct fec_enet_priv_rx_q *rxq, struct bufdesc *bdp, int index) { struct page *new_page; dma_addr_t phys_addr; new_page = page_pool_dev_alloc_pages(rxq->page_pool); - WARN_ON(!new_page); - rxq->rx_skb_info[index].page = new_page; + if (unlikely(!new_page)) + return -ENOMEM; - rxq->rx_skb_info[index].offset = FEC_ENET_XDP_HEADROOM; + rxq->rx_buf[index] = new_page; phys_addr = page_pool_get_dma_addr(new_page) + FEC_ENET_XDP_HEADROOM; bdp->cbd_bufaddr = cpu_to_fec32(phys_addr); + + return 0; } static u32 @@ -1671,13 +1727,29 @@ xdp_err: return ret; } +static void fec_enet_rx_vlan(const struct net_device *ndev, struct sk_buff *skb) +{ + if (ndev->features & NETIF_F_HW_VLAN_CTAG_RX) { + const struct vlan_ethhdr *vlan_header = skb_vlan_eth_hdr(skb); + const u16 vlan_tag = ntohs(vlan_header->h_vlan_TCI); + + /* Push and remove the vlan tag */ + + memmove(skb->data + VLAN_HLEN, skb->data, ETH_ALEN * 2); + skb_pull(skb, VLAN_HLEN); + __vlan_hwaccel_put_tag(skb, + htons(ETH_P_8021Q), + vlan_tag); + } +} + /* During a receive, the bd_rx.cur points to the current incoming buffer. * When we update through the ring, if the next incoming buffer has * not been given to the system, we just set the empty indicator, * effectively tossing the packet. */ static int -fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id) +fec_enet_rx_queue(struct net_device *ndev, u16 queue_id, int budget) { struct fec_enet_private *fep = netdev_priv(ndev); struct fec_enet_priv_rx_q *rxq; @@ -1685,11 +1757,8 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id) unsigned short status; struct sk_buff *skb; ushort pkt_len; - __u8 *data; int pkt_received = 0; struct bufdesc_ex *ebdp = NULL; - bool vlan_packet_rcvd = false; - u16 vlan_tag; int index = 0; bool need_swap = fep->quirks & FEC_QUIRK_SWAP_FRAME; struct bpf_prog *xdp_prog = READ_ONCE(fep->xdp_prog); @@ -1698,9 +1767,9 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id) int cpu = smp_processor_id(); struct xdp_buff xdp; struct page *page; + __fec32 cbd_bufaddr; u32 sub_len = 4; -#if !defined(CONFIG_M5272) /*If it has the FEC_QUIRK_HAS_RACC quirk property, the bit of * FEC_RACC_SHIFT16 is set by default in the probe function. */ @@ -1708,7 +1777,6 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id) data_start += 2; sub_len += 2; } -#endif #if defined(CONFIG_COLDFIRE) && !defined(CONFIG_COLDFIRE_COHERENT_DMA) /* @@ -1723,7 +1791,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id) * These get messed up if we get called due to a busy condition. */ bdp = rxq->bd.cur; - xdp_init_buff(&xdp, PAGE_SIZE, &rxq->xdp_rxq); + xdp_init_buff(&xdp, PAGE_SIZE << fep->pagepool_order, &rxq->xdp_rxq); while (!((status = fec16_to_cpu(bdp->cbd_sc)) & BD_ENET_RX_EMPTY)) { @@ -1763,15 +1831,22 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id) ndev->stats.rx_packets++; pkt_len = fec16_to_cpu(bdp->cbd_datlen); ndev->stats.rx_bytes += pkt_len; + if (fep->quirks & FEC_QUIRK_HAS_RACC) + ndev->stats.rx_bytes -= 2; index = fec_enet_get_bd_index(bdp, &rxq->bd); - page = rxq->rx_skb_info[index].page; + page = rxq->rx_buf[index]; + cbd_bufaddr = bdp->cbd_bufaddr; + if (fec_enet_update_cbd(rxq, bdp, index)) { + ndev->stats.rx_dropped++; + goto rx_processing_done; + } + dma_sync_single_for_cpu(&fep->pdev->dev, - fec32_to_cpu(bdp->cbd_bufaddr), + fec32_to_cpu(cbd_bufaddr), pkt_len, DMA_FROM_DEVICE); prefetch(page_address(page)); - fec_enet_update_cbd(rxq, bdp, index); if (xdp_prog) { xdp_buff_clear_frags_flag(&xdp); @@ -1788,7 +1863,8 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id) * include that when passing upstream as it messes up * bridging applications. */ - skb = build_skb(page_address(page), PAGE_SIZE); + skb = build_skb(page_address(page), + PAGE_SIZE << fep->pagepool_order); if (unlikely(!skb)) { page_pool_recycle_direct(rxq->page_pool, page); ndev->stats.rx_dropped++; @@ -1802,10 +1878,11 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id) skb_mark_for_recycle(skb); if (unlikely(need_swap)) { + u8 *data; + data = page_address(page) + FEC_ENET_XDP_HEADROOM; swap_buffer(data, pkt_len); } - data = skb->data; /* Extract the enhanced buffer descriptor */ ebdp = NULL; @@ -1813,20 +1890,9 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id) ebdp = (struct bufdesc_ex *)bdp; /* If this is a VLAN packet remove the VLAN Tag */ - vlan_packet_rcvd = false; - if ((ndev->features & NETIF_F_HW_VLAN_CTAG_RX) && - fep->bufdesc_ex && - (ebdp->cbd_esc & cpu_to_fec32(BD_ENET_RX_VLAN))) { - /* Push and remove the vlan tag */ - struct vlan_hdr *vlan_header = - (struct vlan_hdr *) (data + ETH_HLEN); - vlan_tag = ntohs(vlan_header->h_vlan_TCI); - - vlan_packet_rcvd = true; - - memmove(skb->data + VLAN_HLEN, data, ETH_ALEN * 2); - skb_pull(skb, VLAN_HLEN); - } + if (fep->bufdesc_ex && + (ebdp->cbd_esc & cpu_to_fec32(BD_ENET_RX_VLAN))) + fec_enet_rx_vlan(ndev, skb); skb->protocol = eth_type_trans(skb, ndev); @@ -1845,12 +1911,6 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id) } } - /* Handle received VLAN packets */ - if (vlan_packet_rcvd) - __vlan_hwaccel_put_tag(skb, - htons(ETH_P_8021Q), - vlan_tag); - skb_record_rx_queue(skb, queue_id); napi_gro_receive(&fep->napi, skb); @@ -1898,7 +1958,7 @@ static int fec_enet_rx(struct net_device *ndev, int budget) /* Make sure that AVB queues are processed first. */ for (i = fep->num_rx_queues - 1; i >= 0; i--) - done += fec_enet_rx_queue(ndev, budget - done, i); + done += fec_enet_rx_queue(ndev, i, budget - done); return done; } @@ -2045,14 +2105,14 @@ static int fec_enet_us_to_tx_cycle(struct net_device *ndev, int us) return us * (fep->clk_ref_rate / 1000) / 1000; } -static int fec_enet_eee_mode_set(struct net_device *ndev, bool enable) +static int fec_enet_eee_mode_set(struct net_device *ndev, u32 lpi_timer, + bool enable) { struct fec_enet_private *fep = netdev_priv(ndev); - struct ethtool_keee *p = &fep->eee; unsigned int sleep_cycle, wake_cycle; if (enable) { - sleep_cycle = fec_enet_us_to_tx_cycle(ndev, p->tx_lpi_timer); + sleep_cycle = fec_enet_us_to_tx_cycle(ndev, lpi_timer); wake_cycle = sleep_cycle; } else { sleep_cycle = 0; @@ -2105,7 +2165,9 @@ static void fec_enet_adjust_link(struct net_device *ndev) napi_enable(&fep->napi); } if (fep->quirks & FEC_QUIRK_HAS_EEE) - fec_enet_eee_mode_set(ndev, phy_dev->enable_tx_lpi); + fec_enet_eee_mode_set(ndev, + phy_dev->eee_cfg.tx_lpi_timer, + phy_dev->enable_tx_lpi); } else { if (fep->link) { netif_stop_queue(ndev); @@ -2167,7 +2229,6 @@ static int fec_enet_mdio_read_c22(struct mii_bus *bus, int mii_id, int regnum) ret = FEC_MMFR_DATA(readl(fep->hwp + FEC_MII_DATA)); out: - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; @@ -2216,7 +2277,6 @@ static int fec_enet_mdio_read_c45(struct mii_bus *bus, int mii_id, ret = FEC_MMFR_DATA(readl(fep->hwp + FEC_MII_DATA)); out: - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; @@ -2248,7 +2308,6 @@ static int fec_enet_mdio_write_c22(struct mii_bus *bus, int mii_id, int regnum, if (ret) netdev_err(fep->netdev, "MDIO write timeout\n"); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; @@ -2292,7 +2351,6 @@ static int fec_enet_mdio_write_c45(struct mii_bus *bus, int mii_id, netdev_err(fep->netdev, "MDIO write timeout\n"); out: - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; @@ -2315,7 +2373,8 @@ static void fec_enet_phy_reset_after_clk_enable(struct net_device *ndev) */ phy_dev = of_phy_find_device(fep->phy_node); phy_reset_after_clk_enable(phy_dev); - put_device(&phy_dev->mdio.dev); + if (phy_dev) + put_device(&phy_dev->mdio.dev); } } @@ -2411,11 +2470,8 @@ static int fec_enet_parse_rgmii_delay(struct fec_enet_private *fep, static int fec_enet_mii_probe(struct net_device *ndev) { struct fec_enet_private *fep = netdev_priv(ndev); - struct phy_device *phy_dev = NULL; - char mdio_bus_id[MII_BUS_ID_SIZE]; - char phy_name[MII_BUS_ID_SIZE + 3]; - int phy_id; - int dev_id = fep->dev_id; + struct phy_device *phy_dev; + int ret; if (fep->phy_node) { phy_dev = of_phy_connect(ndev, fep->phy_node, @@ -2427,30 +2483,28 @@ static int fec_enet_mii_probe(struct net_device *ndev) } } else { /* check for attached phy */ - for (phy_id = 0; (phy_id < PHY_MAX_ADDR); phy_id++) { - if (!mdiobus_is_registered_device(fep->mii_bus, phy_id)) - continue; - if (dev_id--) - continue; - strscpy(mdio_bus_id, fep->mii_bus->id, MII_BUS_ID_SIZE); - break; - } + phy_dev = phy_find_first(fep->mii_bus); + if (fep->dev_id && phy_dev) + phy_dev = phy_find_next(fep->mii_bus, phy_dev); - if (phy_id >= PHY_MAX_ADDR) { + if (!phy_dev) { netdev_info(ndev, "no PHY, assuming direct connection to switch\n"); - strscpy(mdio_bus_id, "fixed-0", MII_BUS_ID_SIZE); - phy_id = 0; + phy_dev = fixed_phy_register_100fd(); + if (IS_ERR(phy_dev)) { + netdev_err(ndev, "could not register fixed PHY\n"); + return PTR_ERR(phy_dev); + } } - snprintf(phy_name, sizeof(phy_name), - PHY_ID_FMT, mdio_bus_id, phy_id); - phy_dev = phy_connect(ndev, phy_name, &fec_enet_adjust_link, - fep->phy_interface); - } + ret = phy_connect_direct(ndev, phy_dev, &fec_enet_adjust_link, + fep->phy_interface); + if (ret) { + if (phy_is_pseudo_fixed_link(phy_dev)) + fixed_phy_unregister(phy_dev); + netdev_err(ndev, "could not attach to PHY\n"); + return ret; + } - if (IS_ERR(phy_dev)) { - netdev_err(ndev, "could not attach to PHY\n"); - return PTR_ERR(phy_dev); } /* mask with MAC supported features */ @@ -2458,9 +2512,7 @@ static int fec_enet_mii_probe(struct net_device *ndev) phy_set_max_speed(phy_dev, 1000); phy_remove_link_mode(phy_dev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); -#if !defined(CONFIG_M5272) phy_support_sym_pause(phy_dev); -#endif } else phy_set_max_speed(phy_dev, 100); @@ -2487,7 +2539,6 @@ static int fec_enet_mii_init(struct platform_device *pdev) int err = -ENXIO; u32 mii_speed, holdtime; u32 bus_freq; - int addr; /* * The i.MX28 dual fec interfaces are not equal. @@ -2602,11 +2653,8 @@ static int fec_enet_mii_init(struct platform_device *pdev) of_node_put(node); /* find all the PHY devices on the bus and set mac_managed_pm to true */ - for (addr = 0; addr < PHY_MAX_ADDR; addr++) { - phydev = mdiobus_get_phy(fep->mii_bus, addr); - if (phydev) - phydev->mac_managed_pm = true; - } + mdiobus_for_each_phy(fep->mii_bus, phydev) + phydev->mac_managed_pm = true; mii_cnt++; @@ -2655,9 +2703,7 @@ static int fec_enet_get_regs_len(struct net_device *ndev) } /* List of registers that can be safety be read to dump them with ethtool */ -#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ - defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARM) || \ - defined(CONFIG_ARM64) || defined(CONFIG_COMPILE_TEST) +#if !defined(CONFIG_M5272) || defined(CONFIG_COMPILE_TEST) static __u32 fec_enet_register_version = 2; static u32 fec_enet_register_offset[] = { FEC_IEVENT, FEC_IMASK, FEC_R_DES_ACTIVE_0, FEC_X_DES_ACTIVE_0, @@ -2731,30 +2777,22 @@ static u32 fec_enet_register_offset[] = { static void fec_enet_get_regs(struct net_device *ndev, struct ethtool_regs *regs, void *regbuf) { + u32 reg_cnt = ARRAY_SIZE(fec_enet_register_offset); struct fec_enet_private *fep = netdev_priv(ndev); u32 __iomem *theregs = (u32 __iomem *)fep->hwp; + u32 *reg_list = fec_enet_register_offset; struct device *dev = &fep->pdev->dev; u32 *buf = (u32 *)regbuf; u32 i, off; int ret; -#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ - defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARM) || \ - defined(CONFIG_ARM64) || defined(CONFIG_COMPILE_TEST) - u32 *reg_list; - u32 reg_cnt; - - if (!of_machine_is_compatible("fsl,imx6ul")) { - reg_list = fec_enet_register_offset; - reg_cnt = ARRAY_SIZE(fec_enet_register_offset); - } else { + +#if !defined(CONFIG_M5272) || defined(CONFIG_COMPILE_TEST) + if (of_machine_is_compatible("fsl,imx6ul")) { reg_list = fec_enet_register_offset_6ul; reg_cnt = ARRAY_SIZE(fec_enet_register_offset_6ul); } -#else - /* coldfire */ - static u32 *reg_list = fec_enet_register_offset; - static const u32 reg_cnt = ARRAY_SIZE(fec_enet_register_offset); #endif + ret = pm_runtime_resume_and_get(dev); if (ret < 0) return; @@ -2774,7 +2812,6 @@ static void fec_enet_get_regs(struct net_device *ndev, buf[off] = readl(&theregs[off]); } - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); } @@ -3081,27 +3118,25 @@ static int fec_enet_us_to_itr_clock(struct net_device *ndev, int us) static void fec_enet_itr_coal_set(struct net_device *ndev) { struct fec_enet_private *fep = netdev_priv(ndev); - int rx_itr, tx_itr; + u32 rx_itr = 0, tx_itr = 0; + int rx_ictt, tx_ictt; - /* Must be greater than zero to avoid unpredictable behavior */ - if (!fep->rx_time_itr || !fep->rx_pkts_itr || - !fep->tx_time_itr || !fep->tx_pkts_itr) - return; - - /* Select enet system clock as Interrupt Coalescing - * timer Clock Source - */ - rx_itr = FEC_ITR_CLK_SEL; - tx_itr = FEC_ITR_CLK_SEL; + rx_ictt = fec_enet_us_to_itr_clock(ndev, fep->rx_time_itr); + tx_ictt = fec_enet_us_to_itr_clock(ndev, fep->tx_time_itr); - /* set ICFT and ICTT */ - rx_itr |= FEC_ITR_ICFT(fep->rx_pkts_itr); - rx_itr |= FEC_ITR_ICTT(fec_enet_us_to_itr_clock(ndev, fep->rx_time_itr)); - tx_itr |= FEC_ITR_ICFT(fep->tx_pkts_itr); - tx_itr |= FEC_ITR_ICTT(fec_enet_us_to_itr_clock(ndev, fep->tx_time_itr)); + if (rx_ictt > 0 && fep->rx_pkts_itr > 1) { + /* Enable with enet system clock as Interrupt Coalescing timer Clock Source */ + rx_itr = FEC_ITR_EN | FEC_ITR_CLK_SEL; + rx_itr |= FEC_ITR_ICFT(fep->rx_pkts_itr); + rx_itr |= FEC_ITR_ICTT(rx_ictt); + } - rx_itr |= FEC_ITR_EN; - tx_itr |= FEC_ITR_EN; + if (tx_ictt > 0 && fep->tx_pkts_itr > 1) { + /* Enable with enet system clock as Interrupt Coalescing timer Clock Source */ + tx_itr = FEC_ITR_EN | FEC_ITR_CLK_SEL; + tx_itr |= FEC_ITR_ICFT(fep->tx_pkts_itr); + tx_itr |= FEC_ITR_ICTT(tx_ictt); + } writel(tx_itr, fep->hwp + FEC_TXIC0); writel(rx_itr, fep->hwp + FEC_RXIC0); @@ -3181,7 +3216,6 @@ static int fec_enet_get_eee(struct net_device *ndev, struct ethtool_keee *edata) { struct fec_enet_private *fep = netdev_priv(ndev); - struct ethtool_keee *p = &fep->eee; if (!(fep->quirks & FEC_QUIRK_HAS_EEE)) return -EOPNOTSUPP; @@ -3189,8 +3223,6 @@ fec_enet_get_eee(struct net_device *ndev, struct ethtool_keee *edata) if (!netif_running(ndev)) return -ENETDOWN; - edata->tx_lpi_timer = p->tx_lpi_timer; - return phy_ethtool_get_eee(ndev->phydev, edata); } @@ -3198,7 +3230,6 @@ static int fec_enet_set_eee(struct net_device *ndev, struct ethtool_keee *edata) { struct fec_enet_private *fep = netdev_priv(ndev); - struct ethtool_keee *p = &fep->eee; if (!(fep->quirks & FEC_QUIRK_HAS_EEE)) return -EOPNOTSUPP; @@ -3206,8 +3237,6 @@ fec_enet_set_eee(struct net_device *ndev, struct ethtool_keee *edata) if (!netif_running(ndev)) return -ENETDOWN; - p->tx_lpi_timer = edata->tx_lpi_timer; - return phy_ethtool_set_eee(ndev->phydev, edata); } @@ -3282,7 +3311,8 @@ static void fec_enet_free_buffers(struct net_device *ndev) for (q = 0; q < fep->num_rx_queues; q++) { rxq = fep->rx_queue[q]; for (i = 0; i < rxq->bd.ring_size; i++) - page_pool_put_full_page(rxq->page_pool, rxq->rx_skb_info[i].page, false); + page_pool_put_full_page(rxq->page_pool, rxq->rx_buf[i], + false); for (i = 0; i < XDP_STATS_TOTAL; i++) rxq->stats[i] = 0; @@ -3311,7 +3341,8 @@ static void fec_enet_free_buffers(struct net_device *ndev) } else { struct page *page = txq->tx_buf[i].buf_p; - page_pool_put_page(page->pp, page, 0, false); + page_pool_put_page(pp_page_to_nmdesc(page)->pp, + page, 0, false); } txq->tx_buf[i].buf_p = NULL; @@ -3407,6 +3438,19 @@ fec_enet_alloc_rxq_buffers(struct net_device *ndev, unsigned int queue) return err; } + /* Some platforms require the RX buffer must be 64 bytes alignment. + * Some platforms require 16 bytes alignment. And some platforms + * require 4 bytes alignment. But since the page pool have been + * introduced into the driver, the address of RX buffer is always + * the page address plus FEC_ENET_XDP_HEADROOM, and + * FEC_ENET_XDP_HEADROOM is 256 bytes. Therefore, this address can + * satisfy all platforms. To prevent future modifications to + * FEC_ENET_XDP_HEADROOM from ignoring this hardware limitation, a + * BUILD_BUG_ON() test has been added, which ensures that + * FEC_ENET_XDP_HEADROOM provides the required alignment. + */ + BUILD_BUG_ON(FEC_ENET_XDP_HEADROOM & 0x3f); + for (i = 0; i < rxq->bd.ring_size; i++) { page = page_pool_dev_alloc_pages(rxq->page_pool); if (!page) @@ -3415,8 +3459,7 @@ fec_enet_alloc_rxq_buffers(struct net_device *ndev, unsigned int queue) phys_addr = page_pool_get_dma_addr(page) + FEC_ENET_XDP_HEADROOM; bdp->cbd_bufaddr = cpu_to_fec32(phys_addr); - rxq->rx_skb_info[i].page = page; - rxq->rx_skb_info[i].offset = FEC_ENET_XDP_HEADROOM; + rxq->rx_buf[i] = page; bdp->cbd_sc = cpu_to_fec16(BD_ENET_RX_EMPTY); if (fep->bufdesc_ex) { @@ -3429,7 +3472,7 @@ fec_enet_alloc_rxq_buffers(struct net_device *ndev, unsigned int queue) /* Set the last buffer to wrap. */ bdp = fec_enet_get_prevdesc(bdp, &rxq->bd); - bdp->cbd_sc |= cpu_to_fec16(BD_SC_WRAP); + bdp->cbd_sc |= cpu_to_fec16(BD_ENET_RX_WRAP); return 0; err_alloc: @@ -3465,7 +3508,7 @@ fec_enet_alloc_txq_buffers(struct net_device *ndev, unsigned int queue) /* Set the last buffer to wrap. */ bdp = fec_enet_get_prevdesc(bdp, &txq->bd); - bdp->cbd_sc |= cpu_to_fec16(BD_SC_WRAP); + bdp->cbd_sc |= cpu_to_fec16(BD_ENET_TX_WRAP); return 0; @@ -3558,7 +3601,6 @@ err_enet_mii_probe: err_enet_alloc: fec_enet_clk_enable(ndev, false); clk_enable: - pm_runtime_mark_last_busy(&fep->pdev->dev); pm_runtime_put_autosuspend(&fep->pdev->dev); pinctrl_pm_select_sleep_state(&fep->pdev->dev); return ret; @@ -3568,8 +3610,9 @@ static int fec_enet_close(struct net_device *ndev) { struct fec_enet_private *fep = netdev_priv(ndev); + struct phy_device *phy_dev = ndev->phydev; - phy_stop(ndev->phydev); + phy_stop(phy_dev); if (netif_device_present(ndev)) { napi_disable(&fep->napi); @@ -3577,7 +3620,10 @@ fec_enet_close(struct net_device *ndev) fec_stop(ndev); } - phy_disconnect(ndev->phydev); + phy_disconnect(phy_dev); + + if (!fep->phy_node && phy_is_pseudo_fixed_link(phy_dev)) + fixed_phy_unregister(phy_dev); if (fep->quirks & FEC_QUIRK_ERR006687) imx6q_cpuidle_fec_irqs_unused(); @@ -3589,7 +3635,6 @@ fec_enet_close(struct net_device *ndev) cpu_latency_qos_remove_request(&fep->pm_qos_req); pinctrl_pm_select_sleep_state(&fep->pdev->dev); - pm_runtime_mark_last_busy(&fep->pdev->dev); pm_runtime_put_autosuspend(&fep->pdev->dev); fec_enet_free_buffers(ndev); @@ -3662,7 +3707,6 @@ static void set_multicast_list(struct net_device *ndev) static int fec_set_mac_address(struct net_device *ndev, void *p) { - struct fec_enet_private *fep = netdev_priv(ndev); struct sockaddr *addr = p; if (addr) { @@ -3679,11 +3723,8 @@ fec_set_mac_address(struct net_device *ndev, void *p) if (!netif_running(ndev)) return 0; - writel(ndev->dev_addr[3] | (ndev->dev_addr[2] << 8) | - (ndev->dev_addr[1] << 16) | (ndev->dev_addr[0] << 24), - fep->hwp + FEC_ADDR_LOW); - writel((ndev->dev_addr[5] << 16) | (ndev->dev_addr[4] << 24), - fep->hwp + FEC_ADDR_HIGH); + fec_set_hw_mac_addr(ndev); + return 0; } @@ -3983,6 +4024,23 @@ static int fec_hwtstamp_set(struct net_device *ndev, return fec_ptp_set(ndev, config, extack); } +static int fec_change_mtu(struct net_device *ndev, int new_mtu) +{ + struct fec_enet_private *fep = netdev_priv(ndev); + int order; + + if (netif_running(ndev)) + return -EBUSY; + + order = get_order(new_mtu + ETH_HLEN + ETH_FCS_LEN + + FEC_DRV_RESERVE_SPACE); + fep->rx_frame_size = (PAGE_SIZE << order) - FEC_DRV_RESERVE_SPACE; + fep->pagepool_order = order; + WRITE_ONCE(ndev->mtu, new_mtu); + + return 0; +} + static const struct net_device_ops fec_netdev_ops = { .ndo_open = fec_enet_open, .ndo_stop = fec_enet_close, @@ -3992,6 +4050,7 @@ static const struct net_device_ops fec_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_tx_timeout = fec_timeout, .ndo_set_mac_address = fec_set_mac_address, + .ndo_change_mtu = fec_change_mtu, .ndo_eth_ioctl = phy_do_ioctl_running, .ndo_set_features = fec_set_features, .ndo_bpf = fec_enet_bpf, @@ -4026,10 +4085,8 @@ static int fec_enet_init(struct net_device *ndev) WARN_ON(dsize != (1 << dsize_log2)); #if defined(CONFIG_ARM) || defined(CONFIG_ARM64) - fep->rx_align = 0xf; fep->tx_align = 0xf; #else - fep->rx_align = 0x3; fep->tx_align = 0x3; #endif fep->rx_pkts_itr = FEC_ITR_ICFT_DEFAULT; @@ -4118,10 +4175,8 @@ static int fec_enet_init(struct net_device *ndev) fep->csum_flags |= FLAG_RX_CSUM_ENABLED; } - if (fep->quirks & FEC_QUIRK_HAS_MULTI_QUEUES) { + if (fep->quirks & FEC_QUIRK_HAS_MULTI_QUEUES) fep->tx_align = 0; - fep->rx_align = 0x3f; - } ndev->hw_features = ndev->features; @@ -4339,11 +4394,9 @@ fec_probe(struct platform_device *pdev) fep->num_rx_queues = num_rx_qs; fep->num_tx_queues = num_tx_qs; -#if !defined(CONFIG_M5272) /* default enable pause frame auto negotiation */ if (fep->quirks & FEC_QUIRK_HAS_GBIT) fep->pause_flag |= FEC_PAUSE_FLAG_AUTONEG; -#endif /* Select default pin state */ pinctrl_pm_select_default_state(&pdev->dev); @@ -4522,7 +4575,15 @@ fec_probe(struct platform_device *pdev) fec_enet_clk_enable(ndev, false); pinctrl_pm_select_sleep_state(&pdev->dev); - ndev->max_mtu = PKT_MAXBUF_SIZE - ETH_HLEN - ETH_FCS_LEN; + fep->pagepool_order = 0; + fep->rx_frame_size = FEC_ENET_RX_FRSIZE; + + if (fep->quirks & FEC_QUIRK_JUMBO_FRAME) + fep->max_buf_size = MAX_JUMBO_BUF_SIZE; + else + fep->max_buf_size = PKT_MAXBUF_SIZE; + + ndev->max_mtu = fep->max_buf_size - ETH_HLEN - ETH_FCS_LEN; ret = register_netdev(ndev); if (ret) @@ -4536,7 +4597,6 @@ fec_probe(struct platform_device *pdev) INIT_WORK(&fep->tx_timeout_work, fec_enet_timeout_work); - pm_runtime_mark_last_busy(&pdev->dev); pm_runtime_put_autosuspend(&pdev->dev); return 0; |
