diff options
Diffstat (limited to 'drivers/net/ethernet/stmicro/stmmac')
17 files changed, 376 insertions, 115 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig index 338e25a6374e..9ad927f646e8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig @@ -3,6 +3,7 @@ config STMMAC_ETH tristate "STMicroelectronics Multi-Gigabit Ethernet driver" depends on HAS_IOMEM && HAS_DMA select MII + select MDIO_XPCS select PAGE_POOL select PHYLINK select CRC32 diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index 487099092693..386663208c23 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -15,6 +15,7 @@ #include <linux/netdevice.h> #include <linux/stmmac.h> #include <linux/phy.h> +#include <linux/mdio-xpcs.h> #include <linux/module.h> #if IS_ENABLED(CONFIG_VLAN_8021Q) #define STMMAC_VLAN_TAG_USED @@ -33,6 +34,11 @@ #define DWMAC_CORE_5_00 0x50 #define DWMAC_CORE_5_10 0x51 #define DWXGMAC_CORE_2_10 0x21 +#define DWXLGMAC_CORE_2_00 0x20 + +/* Device ID */ +#define DWXGMAC_ID 0x76 +#define DWXLGMAC_ID 0x27 #define STMMAC_CHAN0 0 /* Always supported and default for all chips */ @@ -425,6 +431,12 @@ struct mac_link { u32 speed5000; u32 speed10000; } xgmii; + struct { + u32 speed25000; + u32 speed40000; + u32 speed50000; + u32 speed100000; + } xlgmii; }; struct mii_regs { @@ -446,6 +458,8 @@ struct mac_device_info { const struct stmmac_hwtimestamp *ptp; const struct stmmac_tc_ops *tc; const struct stmmac_mmc_ops *mmc; + const struct mdio_xpcs_ops *xpcs; + struct mdio_xpcs_args xpcs_args; struct mii_regs mii; /* MII register Addresses */ struct mac_link link; void __iomem *pcsr; /* vpointer to device CSRs */ @@ -456,6 +470,7 @@ struct mac_device_info { unsigned int pcs; unsigned int pmt; unsigned int ps; + unsigned int xlgmac; }; struct stmmac_rx_routing { @@ -467,6 +482,7 @@ int dwmac100_setup(struct stmmac_priv *priv); int dwmac1000_setup(struct stmmac_priv *priv); int dwmac4_setup(struct stmmac_priv *priv); int dwxgmac2_setup(struct stmmac_priv *priv); +int dwxlgmac2_setup(struct stmmac_priv *priv); void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6], unsigned int high, unsigned int low); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c index 9b7be996d07b..b2dc99289687 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c @@ -304,7 +304,7 @@ static int stm32mp1_parse_data(struct stm32_dwmac *dwmac, /* Get ETH_CLK clocks */ dwmac->clk_eth_ck = devm_clk_get(dev, "eth-ck"); if (IS_ERR(dwmac->clk_eth_ck)) { - dev_warn(dev, "No phy clock provided...\n"); + dev_info(dev, "No phy clock provided...\n"); dwmac->clk_eth_ck = NULL; } @@ -324,7 +324,7 @@ static int stm32mp1_parse_data(struct stm32_dwmac *dwmac, /* Get IRQ information early to have an ability to ask for deferred * probe if needed before we went too far with resource allocation. */ - dwmac->irq_pwr_wakeup = platform_get_irq_byname(pdev, + dwmac->irq_pwr_wakeup = platform_get_irq_byname_optional(pdev, "stm32_pwr_wakeup"); if (dwmac->irq_pwr_wakeup == -EPROBE_DEFER) return -EPROBE_DEFER; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c index 9becca280074..6e30d7eb4983 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c @@ -6,6 +6,7 @@ */ #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/delay.h> #include "common.h" #include "dwmac4_dma.h" @@ -14,22 +15,14 @@ int dwmac4_dma_reset(void __iomem *ioaddr) { u32 value = readl(ioaddr + DMA_BUS_MODE); - int limit; /* DMA SW reset */ value |= DMA_BUS_MODE_SFT_RESET; writel(value, ioaddr + DMA_BUS_MODE); - limit = 10; - while (limit--) { - if (!(readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET)) - break; - mdelay(10); - } - - if (limit < 0) - return -EBUSY; - return 0; + return readl_poll_timeout(ioaddr + DMA_BUS_MODE, value, + !(value & DMA_BUS_MODE_SFT_RESET), + 10000, 100000); } void dwmac4_set_rx_tail_ptr(void __iomem *ioaddr, u32 tail_ptr, u32 chan) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c index 688d36095333..cb87d31a99df 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c @@ -16,19 +16,14 @@ int dwmac_dma_reset(void __iomem *ioaddr) { u32 value = readl(ioaddr + DMA_BUS_MODE); - int err; /* DMA SW reset */ value |= DMA_BUS_MODE_SFT_RESET; writel(value, ioaddr + DMA_BUS_MODE); - err = readl_poll_timeout(ioaddr + DMA_BUS_MODE, value, + return readl_poll_timeout(ioaddr + DMA_BUS_MODE, value, !(value & DMA_BUS_MODE_SFT_RESET), 10000, 100000); - if (err) - return -EBUSY; - - return 0; } /* CSR1 enables the transmit DMA to check for new descriptor */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c index 67b754a56288..0e4575f7bedb 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c @@ -9,6 +9,7 @@ #include <linux/iopoll.h> #include "stmmac.h" #include "stmmac_ptp.h" +#include "dwxlgmac2.h" #include "dwxgmac2.h" static void dwxgmac2_core_init(struct mac_device_info *hw, @@ -1485,6 +1486,67 @@ const struct stmmac_ops dwxgmac210_ops = { .fpe_configure = dwxgmac3_fpe_configure, }; +static void dwxlgmac2_rx_queue_enable(struct mac_device_info *hw, u8 mode, + u32 queue) +{ + void __iomem *ioaddr = hw->pcsr; + u32 value; + + value = readl(ioaddr + XLGMAC_RXQ_ENABLE_CTRL0) & ~XGMAC_RXQEN(queue); + if (mode == MTL_QUEUE_AVB) + value |= 0x1 << XGMAC_RXQEN_SHIFT(queue); + else if (mode == MTL_QUEUE_DCB) + value |= 0x2 << XGMAC_RXQEN_SHIFT(queue); + writel(value, ioaddr + XLGMAC_RXQ_ENABLE_CTRL0); +} + +const struct stmmac_ops dwxlgmac2_ops = { + .core_init = dwxgmac2_core_init, + .set_mac = dwxgmac2_set_mac, + .rx_ipc = dwxgmac2_rx_ipc, + .rx_queue_enable = dwxlgmac2_rx_queue_enable, + .rx_queue_prio = dwxgmac2_rx_queue_prio, + .tx_queue_prio = dwxgmac2_tx_queue_prio, + .rx_queue_routing = NULL, + .prog_mtl_rx_algorithms = dwxgmac2_prog_mtl_rx_algorithms, + .prog_mtl_tx_algorithms = dwxgmac2_prog_mtl_tx_algorithms, + .set_mtl_tx_queue_weight = dwxgmac2_set_mtl_tx_queue_weight, + .map_mtl_to_dma = dwxgmac2_map_mtl_to_dma, + .config_cbs = dwxgmac2_config_cbs, + .dump_regs = dwxgmac2_dump_regs, + .host_irq_status = dwxgmac2_host_irq_status, + .host_mtl_irq_status = dwxgmac2_host_mtl_irq_status, + .flow_ctrl = dwxgmac2_flow_ctrl, + .pmt = dwxgmac2_pmt, + .set_umac_addr = dwxgmac2_set_umac_addr, + .get_umac_addr = dwxgmac2_get_umac_addr, + .set_eee_mode = dwxgmac2_set_eee_mode, + .reset_eee_mode = dwxgmac2_reset_eee_mode, + .set_eee_timer = dwxgmac2_set_eee_timer, + .set_eee_pls = dwxgmac2_set_eee_pls, + .pcs_ctrl_ane = NULL, + .pcs_rane = NULL, + .pcs_get_adv_lp = NULL, + .debug = NULL, + .set_filter = dwxgmac2_set_filter, + .safety_feat_config = dwxgmac3_safety_feat_config, + .safety_feat_irq_status = dwxgmac3_safety_feat_irq_status, + .safety_feat_dump = dwxgmac3_safety_feat_dump, + .set_mac_loopback = dwxgmac2_set_mac_loopback, + .rss_configure = dwxgmac2_rss_configure, + .update_vlan_hash = dwxgmac2_update_vlan_hash, + .rxp_config = dwxgmac3_rxp_config, + .get_mac_tx_timestamp = dwxgmac2_get_mac_tx_timestamp, + .flex_pps_config = dwxgmac2_flex_pps_config, + .sarc_configure = dwxgmac2_sarc_configure, + .enable_vlan = dwxgmac2_enable_vlan, + .config_l3_filter = dwxgmac2_config_l3_filter, + .config_l4_filter = dwxgmac2_config_l4_filter, + .set_arp_offload = dwxgmac2_set_arp_offload, + .est_configure = dwxgmac3_est_configure, + .fpe_configure = dwxgmac3_fpe_configure, +}; + int dwxgmac2_setup(struct stmmac_priv *priv) { struct mac_device_info *mac = priv->hw; @@ -1521,3 +1583,40 @@ int dwxgmac2_setup(struct stmmac_priv *priv) return 0; } + +int dwxlgmac2_setup(struct stmmac_priv *priv) +{ + struct mac_device_info *mac = priv->hw; + + dev_info(priv->device, "\tXLGMAC\n"); + + priv->dev->priv_flags |= IFF_UNICAST_FLT; + mac->pcsr = priv->ioaddr; + mac->multicast_filter_bins = priv->plat->multicast_filter_bins; + mac->unicast_filter_entries = priv->plat->unicast_filter_entries; + mac->mcast_bits_log2 = 0; + + if (mac->multicast_filter_bins) + mac->mcast_bits_log2 = ilog2(mac->multicast_filter_bins); + + mac->link.duplex = 0; + mac->link.speed1000 = XLGMAC_CONFIG_SS_1000; + mac->link.speed2500 = XLGMAC_CONFIG_SS_2500; + mac->link.xgmii.speed10000 = XLGMAC_CONFIG_SS_10G; + mac->link.xlgmii.speed25000 = XLGMAC_CONFIG_SS_25G; + mac->link.xlgmii.speed40000 = XLGMAC_CONFIG_SS_40G; + mac->link.xlgmii.speed50000 = XLGMAC_CONFIG_SS_50G; + mac->link.xlgmii.speed100000 = XLGMAC_CONFIG_SS_100G; + mac->link.speed_mask = XLGMAC_CONFIG_SS; + + mac->mii.addr = XGMAC_MDIO_ADDR; + mac->mii.data = XGMAC_MDIO_DATA; + mac->mii.addr_shift = 16; + mac->mii.addr_mask = GENMASK(20, 16); + mac->mii.reg_shift = 0; + mac->mii.reg_mask = GENMASK(15, 0); + mac->mii.clk_csr_shift = 19; + mac->mii.clk_csr_mask = GENMASK(21, 19); + + return 0; +} diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxlgmac2.h b/drivers/net/ethernet/stmicro/stmmac/dwxlgmac2.h new file mode 100644 index 000000000000..726090d49221 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/dwxlgmac2.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 Synopsys, Inc. and/or its affiliates. + * Synopsys DesignWare XLGMAC definitions. + */ + +#ifndef __STMMAC_DWXLGMAC2_H__ +#define __STMMAC_DWXLGMAC2_H__ + +/* MAC Registers */ +#define XLGMAC_CONFIG_SS GENMASK(30, 28) +#define XLGMAC_CONFIG_SS_SHIFT 28 +#define XLGMAC_CONFIG_SS_40G (0x0 << XLGMAC_CONFIG_SS_SHIFT) +#define XLGMAC_CONFIG_SS_25G (0x1 << XLGMAC_CONFIG_SS_SHIFT) +#define XLGMAC_CONFIG_SS_50G (0x2 << XLGMAC_CONFIG_SS_SHIFT) +#define XLGMAC_CONFIG_SS_100G (0x3 << XLGMAC_CONFIG_SS_SHIFT) +#define XLGMAC_CONFIG_SS_10G (0x4 << XLGMAC_CONFIG_SS_SHIFT) +#define XLGMAC_CONFIG_SS_2500 (0x6 << XLGMAC_CONFIG_SS_SHIFT) +#define XLGMAC_CONFIG_SS_1000 (0x7 << XLGMAC_CONFIG_SS_SHIFT) +#define XLGMAC_RXQ_ENABLE_CTRL0 0x00000140 + +#endif /* __STMMAC_DWXLGMAC2_H__ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c b/drivers/net/ethernet/stmicro/stmmac/hwif.c index 3af2e5015245..bb7114f970f8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.c +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c @@ -23,6 +23,18 @@ static u32 stmmac_get_id(struct stmmac_priv *priv, u32 id_reg) return reg & GENMASK(7, 0); } +static u32 stmmac_get_dev_id(struct stmmac_priv *priv, u32 id_reg) +{ + u32 reg = readl(priv->ioaddr + id_reg); + + if (!reg) { + dev_info(priv->device, "Version ID not available\n"); + return 0x0; + } + + return (reg & GENMASK(15, 8)) >> 8; +} + static void stmmac_dwmac_mode_quirk(struct stmmac_priv *priv) { struct mac_device_info *mac = priv->hw; @@ -69,11 +81,18 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv) return 0; } +static int stmmac_dwxlgmac_quirks(struct stmmac_priv *priv) +{ + priv->hw->xlgmac = true; + return 0; +} + static const struct stmmac_hwif_entry { bool gmac; bool gmac4; bool xgmac; u32 min_id; + u32 dev_id; const struct stmmac_regs_off regs; const void *desc; const void *dma; @@ -199,6 +218,7 @@ static const struct stmmac_hwif_entry { .gmac4 = false, .xgmac = true, .min_id = DWXGMAC_CORE_2_10, + .dev_id = DWXGMAC_ID, .regs = { .ptp_off = PTP_XGMAC_OFFSET, .mmc_off = MMC_XGMAC_OFFSET, @@ -212,6 +232,25 @@ static const struct stmmac_hwif_entry { .mmc = &dwxgmac_mmc_ops, .setup = dwxgmac2_setup, .quirks = NULL, + }, { + .gmac = false, + .gmac4 = false, + .xgmac = true, + .min_id = DWXLGMAC_CORE_2_00, + .dev_id = DWXLGMAC_ID, + .regs = { + .ptp_off = PTP_XGMAC_OFFSET, + .mmc_off = MMC_XGMAC_OFFSET, + }, + .desc = &dwxgmac210_desc_ops, + .dma = &dwxgmac210_dma_ops, + .mac = &dwxlgmac2_ops, + .hwtimestamp = &stmmac_ptp, + .mode = NULL, + .tc = &dwmac510_tc_ops, + .mmc = &dwxgmac_mmc_ops, + .setup = dwxlgmac2_setup, + .quirks = stmmac_dwxlgmac_quirks, }, }; @@ -223,13 +262,15 @@ int stmmac_hwif_init(struct stmmac_priv *priv) const struct stmmac_hwif_entry *entry; struct mac_device_info *mac; bool needs_setup = true; + u32 id, dev_id = 0; int i, ret; - u32 id; if (needs_gmac) { id = stmmac_get_id(priv, GMAC_VERSION); } else if (needs_gmac4 || needs_xgmac) { id = stmmac_get_id(priv, GMAC4_VERSION); + if (needs_xgmac) + dev_id = stmmac_get_dev_id(priv, GMAC4_VERSION); } else { id = 0; } @@ -267,6 +308,8 @@ int stmmac_hwif_init(struct stmmac_priv *priv) /* Use synopsys_id var because some setups can override this */ if (priv->synopsys_id < entry->min_id) continue; + if (needs_xgmac && (dev_id ^ entry->dev_id)) + continue; /* Only use generic HW helpers if needed */ mac->desc = mac->desc ? : entry->desc; diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h index df63b0367aff..fc350149ba34 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.h +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h @@ -577,6 +577,18 @@ struct stmmac_mmc_ops { #define stmmac_mmc_read(__priv, __args...) \ stmmac_do_void_callback(__priv, mmc, read, __args) +/* XPCS callbacks */ +#define stmmac_xpcs_validate(__priv, __args...) \ + stmmac_do_callback(__priv, xpcs, validate, __args) +#define stmmac_xpcs_config(__priv, __args...) \ + stmmac_do_callback(__priv, xpcs, config, __args) +#define stmmac_xpcs_get_state(__priv, __args...) \ + stmmac_do_callback(__priv, xpcs, get_state, __args) +#define stmmac_xpcs_link_up(__priv, __args...) \ + stmmac_do_callback(__priv, xpcs, link_up, __args) +#define stmmac_xpcs_probe(__priv, __args...) \ + stmmac_do_callback(__priv, xpcs, probe, __args) + struct stmmac_regs_off { u32 ptp_off; u32 mmc_off; @@ -593,6 +605,7 @@ extern const struct stmmac_dma_ops dwmac410_dma_ops; extern const struct stmmac_ops dwmac510_ops; extern const struct stmmac_tc_ops dwmac510_tc_ops; extern const struct stmmac_ops dwxgmac210_ops; +extern const struct stmmac_ops dwxlgmac2_ops; extern const struct stmmac_dma_ops dwxgmac210_dma_ops; extern const struct stmmac_desc_ops dwxgmac210_desc_ops; extern const struct stmmac_mmc_ops dwmac_mmc_ops; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index b29603ec744c..eae11c585025 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -732,20 +732,6 @@ static int stmmac_set_coalesce(struct net_device *dev, u32 rx_cnt = priv->plat->rx_queues_to_use; unsigned int rx_riwt; - /* Check not supported parameters */ - if ((ec->rx_coalesce_usecs_irq) || - (ec->rx_max_coalesced_frames_irq) || (ec->tx_coalesce_usecs_irq) || - (ec->use_adaptive_rx_coalesce) || (ec->use_adaptive_tx_coalesce) || - (ec->pkt_rate_low) || (ec->rx_coalesce_usecs_low) || - (ec->rx_max_coalesced_frames_low) || (ec->tx_coalesce_usecs_high) || - (ec->tx_max_coalesced_frames_low) || (ec->pkt_rate_high) || - (ec->tx_coalesce_usecs_low) || (ec->rx_coalesce_usecs_high) || - (ec->rx_max_coalesced_frames_high) || - (ec->tx_max_coalesced_frames_irq) || - (ec->stats_block_coalesce_usecs) || - (ec->tx_max_coalesced_frames_high) || (ec->rate_sample_interval)) - return -EOPNOTSUPP; - if (priv->use_riwt && (ec->rx_coalesce_usecs > 0)) { rx_riwt = stmmac_usec2riwt(ec->rx_coalesce_usecs, priv); @@ -914,6 +900,8 @@ static int stmmac_set_tunable(struct net_device *dev, } static const struct ethtool_ops stmmac_ethtool_ops = { + .supported_coalesce_params = ETHTOOL_COALESCE_USECS | + ETHTOOL_COALESCE_MAX_FRAMES, .begin = stmmac_check_if_running, .get_drvinfo = stmmac_ethtool_getdrvinfo, .get_msglevel = stmmac_ethtool_getmsglevel, diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c index 020159622559..fcf080243a0f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c @@ -10,6 +10,7 @@ *******************************************************************************/ #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/delay.h> #include "common.h" #include "stmmac_ptp.h" @@ -53,7 +54,6 @@ static void config_sub_second_increment(void __iomem *ioaddr, static int init_systime(void __iomem *ioaddr, u32 sec, u32 nsec) { - int limit; u32 value; writel(sec, ioaddr + PTP_STSUR); @@ -64,16 +64,9 @@ static int init_systime(void __iomem *ioaddr, u32 sec, u32 nsec) writel(value, ioaddr + PTP_TCR); /* wait for present system time initialize to complete */ - limit = 10; - while (limit--) { - if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSINIT)) - break; - mdelay(10); - } - if (limit < 0) - return -EBUSY; - - return 0; + return readl_poll_timeout(ioaddr + PTP_TCR, value, + !(value & PTP_TCR_TSINIT), + 10000, 100000); } static int config_addend(void __iomem *ioaddr, u32 addend) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 7da18c9afa01..0e8c80f23557 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -849,6 +849,38 @@ static void stmmac_validate(struct phylink_config *config, phylink_set(mac_supported, 10000baseKX4_Full); phylink_set(mac_supported, 10000baseKR_Full); } + if (!max_speed || (max_speed >= 25000)) { + phylink_set(mac_supported, 25000baseCR_Full); + phylink_set(mac_supported, 25000baseKR_Full); + phylink_set(mac_supported, 25000baseSR_Full); + } + if (!max_speed || (max_speed >= 40000)) { + phylink_set(mac_supported, 40000baseKR4_Full); + phylink_set(mac_supported, 40000baseCR4_Full); + phylink_set(mac_supported, 40000baseSR4_Full); + phylink_set(mac_supported, 40000baseLR4_Full); + } + if (!max_speed || (max_speed >= 50000)) { + phylink_set(mac_supported, 50000baseCR2_Full); + phylink_set(mac_supported, 50000baseKR2_Full); + phylink_set(mac_supported, 50000baseSR2_Full); + phylink_set(mac_supported, 50000baseKR_Full); + phylink_set(mac_supported, 50000baseSR_Full); + phylink_set(mac_supported, 50000baseCR_Full); + phylink_set(mac_supported, 50000baseLR_ER_FR_Full); + phylink_set(mac_supported, 50000baseDR_Full); + } + if (!max_speed || (max_speed >= 100000)) { + phylink_set(mac_supported, 100000baseKR4_Full); + phylink_set(mac_supported, 100000baseSR4_Full); + phylink_set(mac_supported, 100000baseCR4_Full); + phylink_set(mac_supported, 100000baseLR4_ER4_Full); + phylink_set(mac_supported, 100000baseKR2_Full); + phylink_set(mac_supported, 100000baseSR2_Full); + phylink_set(mac_supported, 100000baseCR2_Full); + phylink_set(mac_supported, 100000baseLR2_ER2_FR2_Full); + phylink_set(mac_supported, 100000baseDR2_Full); + } } /* Half-Duplex can only work with single queue */ @@ -858,33 +890,65 @@ static void stmmac_validate(struct phylink_config *config, phylink_set(mask, 1000baseT_Half); } - bitmap_and(supported, supported, mac_supported, - __ETHTOOL_LINK_MODE_MASK_NBITS); - bitmap_andnot(supported, supported, mask, - __ETHTOOL_LINK_MODE_MASK_NBITS); - bitmap_and(state->advertising, state->advertising, mac_supported, - __ETHTOOL_LINK_MODE_MASK_NBITS); - bitmap_andnot(state->advertising, state->advertising, mask, - __ETHTOOL_LINK_MODE_MASK_NBITS); + linkmode_and(supported, supported, mac_supported); + linkmode_andnot(supported, supported, mask); + + linkmode_and(state->advertising, state->advertising, mac_supported); + linkmode_andnot(state->advertising, state->advertising, mask); + + /* If PCS is supported, check which modes it supports. */ + stmmac_xpcs_validate(priv, &priv->hw->xpcs_args, supported, state); } static void stmmac_mac_pcs_get_state(struct phylink_config *config, struct phylink_link_state *state) { + struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev)); + state->link = 0; + stmmac_xpcs_get_state(priv, &priv->hw->xpcs_args, state); } static void stmmac_mac_config(struct phylink_config *config, unsigned int mode, const struct phylink_link_state *state) { struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev)); + + stmmac_xpcs_config(priv, &priv->hw->xpcs_args, state); +} + +static void stmmac_mac_an_restart(struct phylink_config *config) +{ + /* Not Supported */ +} + +static void stmmac_mac_link_down(struct phylink_config *config, + unsigned int mode, phy_interface_t interface) +{ + struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev)); + + stmmac_mac_set(priv, priv->ioaddr, false); + priv->eee_active = false; + stmmac_eee_init(priv); + stmmac_set_eee_pls(priv, priv->hw, false); +} + +static void stmmac_mac_link_up(struct phylink_config *config, + struct phy_device *phy, + unsigned int mode, phy_interface_t interface, + int speed, int duplex, + bool tx_pause, bool rx_pause) +{ + struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev)); u32 ctrl; + stmmac_xpcs_link_up(priv, &priv->hw->xpcs_args, speed, interface); + ctrl = readl(priv->ioaddr + MAC_CTRL_REG); ctrl &= ~priv->hw->link.speed_mask; - if (state->interface == PHY_INTERFACE_MODE_USXGMII) { - switch (state->speed) { + if (interface == PHY_INTERFACE_MODE_USXGMII) { + switch (speed) { case SPEED_10000: ctrl |= priv->hw->link.xgmii.speed10000; break; @@ -897,8 +961,34 @@ static void stmmac_mac_config(struct phylink_config *config, unsigned int mode, default: return; } + } else if (interface == PHY_INTERFACE_MODE_XLGMII) { + switch (speed) { + case SPEED_100000: + ctrl |= priv->hw->link.xlgmii.speed100000; + break; + case SPEED_50000: + ctrl |= priv->hw->link.xlgmii.speed50000; + break; + case SPEED_40000: + ctrl |= priv->hw->link.xlgmii.speed40000; + break; + case SPEED_25000: + ctrl |= priv->hw->link.xlgmii.speed25000; + break; + case SPEED_10000: + ctrl |= priv->hw->link.xgmii.speed10000; + break; + case SPEED_2500: + ctrl |= priv->hw->link.speed2500; + break; + case SPEED_1000: + ctrl |= priv->hw->link.speed1000; + break; + default: + return; + } } else { - switch (state->speed) { + switch (speed) { case SPEED_2500: ctrl |= priv->hw->link.speed2500; break; @@ -916,44 +1006,21 @@ static void stmmac_mac_config(struct phylink_config *config, unsigned int mode, } } - priv->speed = state->speed; + priv->speed = speed; if (priv->plat->fix_mac_speed) - priv->plat->fix_mac_speed(priv->plat->bsp_priv, state->speed); + priv->plat->fix_mac_speed(priv->plat->bsp_priv, speed); - if (!state->duplex) + if (!duplex) ctrl &= ~priv->hw->link.duplex; else ctrl |= priv->hw->link.duplex; /* Flow Control operation */ - if (state->pause) - stmmac_mac_flow_ctrl(priv, state->duplex); + if (tx_pause && rx_pause) + stmmac_mac_flow_ctrl(priv, duplex); writel(ctrl, priv->ioaddr + MAC_CTRL_REG); -} - -static void stmmac_mac_an_restart(struct phylink_config *config) -{ - /* Not Supported */ -} - -static void stmmac_mac_link_down(struct phylink_config *config, - unsigned int mode, phy_interface_t interface) -{ - struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev)); - - stmmac_mac_set(priv, priv->ioaddr, false); - priv->eee_active = false; - stmmac_eee_init(priv); - stmmac_set_eee_pls(priv, priv->hw, false); -} - -static void stmmac_mac_link_up(struct phylink_config *config, - unsigned int mode, phy_interface_t interface, - struct phy_device *phy) -{ - struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev)); stmmac_mac_set(priv, priv->ioaddr, true); if (phy && priv->dma_cap.eee) { @@ -1043,6 +1110,10 @@ static int stmmac_phy_setup(struct stmmac_priv *priv) priv->phylink_config.dev = &priv->dev->dev; priv->phylink_config.type = PHYLINK_NETDEV; + priv->phylink_config.pcs_poll = true; + + if (!fwnode) + fwnode = dev_fwnode(priv->device); phylink = phylink_create(&priv->phylink_config, fwnode, mode, &stmmac_phylink_mac_ops); @@ -1251,11 +1322,11 @@ static void stmmac_free_rx_buffer(struct stmmac_priv *priv, u32 queue, int i) struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i]; if (buf->page) - page_pool_put_page(rx_q->page_pool, buf->page, false); + page_pool_put_full_page(rx_q->page_pool, buf->page, false); buf->page = NULL; if (buf->sec_page) - page_pool_put_page(rx_q->page_pool, buf->sec_page, false); + page_pool_put_full_page(rx_q->page_pool, buf->sec_page, false); buf->sec_page = NULL; } @@ -2687,7 +2758,8 @@ static int stmmac_open(struct net_device *dev) int ret; if (priv->hw->pcs != STMMAC_PCS_TBI && - priv->hw->pcs != STMMAC_PCS_RTBI) { + priv->hw->pcs != STMMAC_PCS_RTBI && + priv->hw->xpcs == NULL) { ret = stmmac_init_phy(dev); if (ret) { netdev_err(priv->dev, diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c index cfe5d8b73142..b2a707e2ef43 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c @@ -382,6 +382,14 @@ int stmmac_mdio_register(struct net_device *ndev) max_addr = PHY_MAX_ADDR; } + if (mdio_bus_data->has_xpcs) { + priv->hw->xpcs = mdio_xpcs_get_ops(); + if (!priv->hw->xpcs) { + err = -ENODEV; + goto bus_register_fail; + } + } + if (mdio_bus_data->needs_reset) new_bus->reset = &stmmac_mdio_reset; @@ -433,6 +441,25 @@ int stmmac_mdio_register(struct net_device *ndev) found = 1; } + /* Try to probe the XPCS by scanning all addresses. */ + if (priv->hw->xpcs) { + struct mdio_xpcs_args *xpcs = &priv->hw->xpcs_args; + int ret, mode = priv->plat->phy_interface; + max_addr = PHY_MAX_ADDR; + + xpcs->bus = new_bus; + + for (addr = 0; addr < max_addr; addr++) { + xpcs->addr = addr; + + ret = stmmac_xpcs_probe(priv, xpcs, mode); + if (!ret) { + found = 1; + break; + } + } + } + if (!found && !mdio_node) { dev_warn(dev, "No PHY found\n"); mdiobus_unregister(new_bus); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c index fe2c9fa6a71c..7acbac73c29c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c @@ -579,28 +579,23 @@ static int __maybe_unused stmmac_pci_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(stmmac_pm_ops, stmmac_pci_suspend, stmmac_pci_resume); /* synthetic ID, no official vendor */ -#define PCI_VENDOR_ID_STMMAC 0x700 - -#define STMMAC_QUARK_ID 0x0937 -#define STMMAC_DEVICE_ID 0x1108 -#define STMMAC_EHL_RGMII1G_ID 0x4b30 -#define STMMAC_EHL_SGMII1G_ID 0x4b31 -#define STMMAC_TGL_SGMII1G_ID 0xa0ac -#define STMMAC_GMAC5_ID 0x7102 - -#define STMMAC_DEVICE(vendor_id, dev_id, info) { \ - PCI_VDEVICE(vendor_id, dev_id), \ - .driver_data = (kernel_ulong_t)&info \ - } +#define PCI_VENDOR_ID_STMMAC 0x0700 + +#define PCI_DEVICE_ID_STMMAC_STMMAC 0x1108 +#define PCI_DEVICE_ID_INTEL_QUARK_ID 0x0937 +#define PCI_DEVICE_ID_INTEL_EHL_RGMII1G_ID 0x4b30 +#define PCI_DEVICE_ID_INTEL_EHL_SGMII1G_ID 0x4b31 +#define PCI_DEVICE_ID_INTEL_TGL_SGMII1G_ID 0xa0ac +#define PCI_DEVICE_ID_SYNOPSYS_GMAC5_ID 0x7102 static const struct pci_device_id stmmac_id_table[] = { - STMMAC_DEVICE(STMMAC, STMMAC_DEVICE_ID, stmmac_pci_info), - STMMAC_DEVICE(STMICRO, PCI_DEVICE_ID_STMICRO_MAC, stmmac_pci_info), - STMMAC_DEVICE(INTEL, STMMAC_QUARK_ID, quark_pci_info), - STMMAC_DEVICE(INTEL, STMMAC_EHL_RGMII1G_ID, ehl_rgmii1g_pci_info), - STMMAC_DEVICE(INTEL, STMMAC_EHL_SGMII1G_ID, ehl_sgmii1g_pci_info), - STMMAC_DEVICE(INTEL, STMMAC_TGL_SGMII1G_ID, tgl_sgmii1g_pci_info), - STMMAC_DEVICE(SYNOPSYS, STMMAC_GMAC5_ID, snps_gmac5_pci_info), + { PCI_DEVICE_DATA(STMMAC, STMMAC, &stmmac_pci_info) }, + { PCI_DEVICE_DATA(STMICRO, MAC, &stmmac_pci_info) }, + { PCI_DEVICE_DATA(INTEL, QUARK_ID, &quark_pci_info) }, + { PCI_DEVICE_DATA(INTEL, EHL_RGMII1G_ID, &ehl_rgmii1g_pci_info) }, + { PCI_DEVICE_DATA(INTEL, EHL_SGMII1G_ID, &ehl_sgmii1g_pci_info) }, + { PCI_DEVICE_DATA(INTEL, TGL_SGMII1G_ID, &tgl_sgmii1g_pci_info) }, + { PCI_DEVICE_DATA(SYNOPSYS, GMAC5_ID, &snps_gmac5_pci_info) }, {} }; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 13fafd905db8..bcda49dcf619 100644 |