mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-08-14 06:22:34 +02:00
Changing the netif_carrier_*() state behind phylink's back has always
been prohibited because it messes up with phylinks state tracking, and
means that phylink no longer guarantees to call the mac_link_down()
and mac_link_up() methods at the appropriate times. This was later
documented in the sfp-phylink network driver conversion guide.
stmmac was converted to phylink in 2019, but nothing was done with the
"PCS" code. Since then, apart from the updates as part of phylink
development, nothing has happened with stmmac to improve its use of
phylink, or even to address this point.
A couple of years ago, a has_integrated_pcs boolean was added by Bart,
which later became the STMMAC_FLAG_HAS_INTEGRATED_PCS flag, to avoid
manipulating the netif_carrier_*() state. This flag is mis-named,
because whenever the stmmac is synthesized for its native SGMII, TBI
or RTBI interfaces, it has an "integrated PCS". This boolean/flag
actually means "ignore the status from the integrated PCS".
Discussing with Bart, the reasons for this are lost to the winds of
time (which is why we should always document the reasons in the commit
message.)
RGMII also has in-band status, and the dwmac cores and stmmac code
supports this but with one bug that saves the day.
When dwmac cores are synthesised for RGMII only, they do not contain
an integrated PCS, and so priv->dma_cap.pcs is clear, which prevents
(incorrectly) the "RGMII PCS" being used, meaning we don't read the
in-band status. However, a core synthesised for RGMII and also SGMII,
TBI or RTBI will have this capability bit set, thus making these
code paths reachable.
The Jetson Xavier NX uses RGMII mode to talk to its PHY, and removing
the incorrect check for priv->dma_cap.pcs reveals the theortical issue
with netif_carrier_*() manipulation is real:
dwc-eth-dwmac 2490000.ethernet eth0: Register MEM_TYPE_PAGE_POOL RxQ-0
dwc-eth-dwmac 2490000.ethernet eth0: PHY [stmmac-0:00] driver [RTL8211F Gigabit Ethernet] (irq=141)
dwc-eth-dwmac 2490000.ethernet eth0: No Safety Features support found
dwc-eth-dwmac 2490000.ethernet eth0: IEEE 1588-2008 Advanced Timestamp supported
dwc-eth-dwmac 2490000.ethernet eth0: registered PTP clock
dwc-eth-dwmac 2490000.ethernet eth0: configuring for phy/rgmii-id link mode
8021q: adding VLAN 0 to HW filter on device eth0
dwc-eth-dwmac 2490000.ethernet eth0: Adding VLAN ID 0 is not supported
Link is Up - 1000/Full
Link is Down
Link is Up - 1000/Full
This looks good until one realises that the phylink "Link" status
messages are missing, even when the RJ45 cable is reconnected. Nothing
one can do results in the interface working. The interrupt handler
(which prints those "Link is" messages) always wins over phylink's
resolve worker, meaning phylink never calls the mac_link_up() nor
mac_link_down() methods.
eth0 also sees no traffic received, and is unable to obtain a DHCP
address:
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group defa
ult qlen 1000
link/ether e6:d3:6a:e6:92:de brd ff:ff:ff:ff:ff:ff
RX: bytes packets errors dropped overrun mcast
0 0 0 0 0 0
TX: bytes packets errors dropped carrier collsns
27686 149 0 0 0 0
With the STMMAC_FLAG_HAS_INTEGRATED_PCS flag set, which disables the
netif_carrier_*() manipulation then stmmac works normally:
dwc-eth-dwmac 2490000.ethernet eth0: Register MEM_TYPE_PAGE_POOL RxQ-0
dwc-eth-dwmac 2490000.ethernet eth0: PHY [stmmac-0:00] driver [RTL8211F Gigabit Ethernet] (irq=141)
dwc-eth-dwmac 2490000.ethernet eth0: No Safety Features support found
dwc-eth-dwmac 2490000.ethernet eth0: IEEE 1588-2008 Advanced Timestamp supported
dwc-eth-dwmac 2490000.ethernet eth0: registered PTP clock
dwc-eth-dwmac 2490000.ethernet eth0: configuring for phy/rgmii-id link mode
8021q: adding VLAN 0 to HW filter on device eth0
dwc-eth-dwmac 2490000.ethernet eth0: Adding VLAN ID 0 is not supported
Link is Up - 1000/Full
dwc-eth-dwmac 2490000.ethernet eth0: Link is Up - 1Gbps/Full - flow control rx/tx
and packets can be transferred.
This clearly shows that when priv->hw->pcs is set, but
STMMAC_FLAG_HAS_INTEGRATED_PCS is clear, the driver reliably fails.
Discovering whether a platform falls into this is impossible as
parsing all the dtsi and dts files to find out which use the stmmac
driver, whether any of them use RGMII or SGMII and also depends
whether an external interface is being used. The kernel likely
doesn't contain all dts files either.
The only driver that sets this flag uses the qcom,sa8775p-ethqos
compatible, and uses SGMII or 2500BASE-X.
but these are saved from this problem by the incorrect check for
priv->dma_cap.pcs.
So, we have to assume that for every other platform that uses SGMII
with stmmac is using an external PCS.
Moreover, ethtool output can be incorrect. With the full-duplex link
negotiated, ethtool reports:
Speed: 1000Mb/s
Duplex: Half
because with dwmac4, the full-duplex bit is in bit 16 of the status,
priv->xstats.pcs_duplex becomes BIT(16) for full duplex, but the
ethtool ksettings duplex member is u8 - so becomes zero. Moreover,
the supported, advertised and link partner modes are all "not
reported".
Finally, ksettings_set() won't be able to set the advertisement on
a PHY if this PCS code is activated, which is incorrect when SGMII
is used with a PHY.
Thus, remove:
1. the incorrect netif_carrier_*() manipulation.
2. the broken ethtool ksettings code.
Given that all uses of STMMAC_FLAG_HAS_INTEGRATED_PCS are now gone,
remove the flag from stmmac.h and dwmac-qcom-ethqos.c.
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Tested-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Tested-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Link: https://patch.msgid.link/E1v9P5y-0000000AolC-1QWH@rmk-PC.armlinux.org.uk
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
303 lines
8.7 KiB
C
303 lines
8.7 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/*******************************************************************************
|
|
|
|
Header file for stmmac platform data
|
|
|
|
Copyright (C) 2009 STMicroelectronics Ltd
|
|
|
|
|
|
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
|
*******************************************************************************/
|
|
|
|
#ifndef __STMMAC_PLATFORM_DATA
|
|
#define __STMMAC_PLATFORM_DATA
|
|
|
|
#include <linux/platform_device.h>
|
|
#include <linux/phylink.h>
|
|
|
|
#define MTL_MAX_RX_QUEUES 8
|
|
#define MTL_MAX_TX_QUEUES 8
|
|
#define STMMAC_CH_MAX 8
|
|
|
|
#define STMMAC_RX_COE_NONE 0
|
|
#define STMMAC_RX_COE_TYPE1 1
|
|
#define STMMAC_RX_COE_TYPE2 2
|
|
|
|
/* Define the macros for CSR clock range parameters to be passed by
|
|
* platform code.
|
|
* This could also be configured at run time using CPU freq framework. */
|
|
|
|
/* MDC Clock Selection define*/
|
|
#define STMMAC_CSR_60_100M 0x0 /* MDC = clk_scr_i/42 */
|
|
#define STMMAC_CSR_100_150M 0x1 /* MDC = clk_scr_i/62 */
|
|
#define STMMAC_CSR_20_35M 0x2 /* MDC = clk_scr_i/16 */
|
|
#define STMMAC_CSR_35_60M 0x3 /* MDC = clk_scr_i/26 */
|
|
#define STMMAC_CSR_150_250M 0x4 /* MDC = clk_scr_i/102 */
|
|
#define STMMAC_CSR_250_300M 0x5 /* MDC = clk_scr_i/124 */
|
|
#define STMMAC_CSR_300_500M 0x6 /* MDC = clk_scr_i/204 */
|
|
#define STMMAC_CSR_500_800M 0x7 /* MDC = clk_scr_i/324 */
|
|
|
|
/* MTL algorithms identifiers */
|
|
#define MTL_TX_ALGORITHM_WRR 0x0
|
|
#define MTL_TX_ALGORITHM_WFQ 0x1
|
|
#define MTL_TX_ALGORITHM_DWRR 0x2
|
|
#define MTL_TX_ALGORITHM_SP 0x3
|
|
#define MTL_RX_ALGORITHM_SP 0x4
|
|
#define MTL_RX_ALGORITHM_WSP 0x5
|
|
|
|
/* RX/TX Queue Mode */
|
|
#define MTL_QUEUE_AVB 0x0
|
|
#define MTL_QUEUE_DCB 0x1
|
|
|
|
/* The MDC clock could be set higher than the IEEE 802.3
|
|
* specified frequency limit 0f 2.5 MHz, by programming a clock divider
|
|
* of value different than the above defined values. The resultant MDIO
|
|
* clock frequency of 12.5 MHz is applicable for the interfacing chips
|
|
* supporting higher MDC clocks.
|
|
* The MDC clock selection macros need to be defined for MDC clock rate
|
|
* of 12.5 MHz, corresponding to the following selection.
|
|
*/
|
|
#define STMMAC_CSR_I_4 0x8 /* clk_csr_i/4 */
|
|
#define STMMAC_CSR_I_6 0x9 /* clk_csr_i/6 */
|
|
#define STMMAC_CSR_I_8 0xA /* clk_csr_i/8 */
|
|
#define STMMAC_CSR_I_10 0xB /* clk_csr_i/10 */
|
|
#define STMMAC_CSR_I_12 0xC /* clk_csr_i/12 */
|
|
#define STMMAC_CSR_I_14 0xD /* clk_csr_i/14 */
|
|
#define STMMAC_CSR_I_16 0xE /* clk_csr_i/16 */
|
|
#define STMMAC_CSR_I_18 0xF /* clk_csr_i/18 */
|
|
|
|
/* AXI DMA Burst length supported */
|
|
#define DMA_AXI_BLEN_4 (1 << 1)
|
|
#define DMA_AXI_BLEN_8 (1 << 2)
|
|
#define DMA_AXI_BLEN_16 (1 << 3)
|
|
#define DMA_AXI_BLEN_32 (1 << 4)
|
|
#define DMA_AXI_BLEN_64 (1 << 5)
|
|
#define DMA_AXI_BLEN_128 (1 << 6)
|
|
#define DMA_AXI_BLEN_256 (1 << 7)
|
|
#define DMA_AXI_BLEN_ALL (DMA_AXI_BLEN_4 | DMA_AXI_BLEN_8 | DMA_AXI_BLEN_16 \
|
|
| DMA_AXI_BLEN_32 | DMA_AXI_BLEN_64 \
|
|
| DMA_AXI_BLEN_128 | DMA_AXI_BLEN_256)
|
|
|
|
struct clk;
|
|
struct stmmac_priv;
|
|
|
|
/* Platfrom data for platform device structure's platform_data field */
|
|
|
|
struct stmmac_mdio_bus_data {
|
|
unsigned int phy_mask;
|
|
unsigned int pcs_mask;
|
|
unsigned int default_an_inband;
|
|
int *irqs;
|
|
int probed_phy_irq;
|
|
bool needs_reset;
|
|
};
|
|
|
|
struct stmmac_dma_cfg {
|
|
int pbl;
|
|
int txpbl;
|
|
int rxpbl;
|
|
bool pblx8;
|
|
int fixed_burst;
|
|
int mixed_burst;
|
|
bool aal;
|
|
bool eame;
|
|
bool multi_msi_en;
|
|
bool dche;
|
|
bool atds;
|
|
};
|
|
|
|
#define AXI_BLEN 7
|
|
struct stmmac_axi {
|
|
bool axi_lpi_en;
|
|
bool axi_xit_frm;
|
|
u32 axi_wr_osr_lmt;
|
|
u32 axi_rd_osr_lmt;
|
|
bool axi_kbbe;
|
|
u32 axi_blen[AXI_BLEN];
|
|
bool axi_fb;
|
|
bool axi_mb;
|
|
bool axi_rb;
|
|
};
|
|
|
|
struct stmmac_rxq_cfg {
|
|
u8 mode_to_use;
|
|
u32 chan;
|
|
u8 pkt_route;
|
|
bool use_prio;
|
|
u32 prio;
|
|
};
|
|
|
|
struct stmmac_txq_cfg {
|
|
u32 weight;
|
|
bool coe_unsupported;
|
|
u8 mode_to_use;
|
|
/* Credit Base Shaper parameters */
|
|
u32 send_slope;
|
|
u32 idle_slope;
|
|
u32 high_credit;
|
|
u32 low_credit;
|
|
bool use_prio;
|
|
u32 prio;
|
|
int tbs_en;
|
|
};
|
|
|
|
struct stmmac_safety_feature_cfg {
|
|
u32 tsoee;
|
|
u32 mrxpee;
|
|
u32 mestee;
|
|
u32 mrxee;
|
|
u32 mtxee;
|
|
u32 epsi;
|
|
u32 edpp;
|
|
u32 prtyen;
|
|
u32 tmouten;
|
|
};
|
|
|
|
/* Addresses that may be customized by a platform */
|
|
struct dwmac4_addrs {
|
|
u32 dma_chan;
|
|
u32 dma_chan_offset;
|
|
u32 mtl_chan;
|
|
u32 mtl_chan_offset;
|
|
u32 mtl_ets_ctrl;
|
|
u32 mtl_ets_ctrl_offset;
|
|
u32 mtl_txq_weight;
|
|
u32 mtl_txq_weight_offset;
|
|
u32 mtl_send_slp_cred;
|
|
u32 mtl_send_slp_cred_offset;
|
|
u32 mtl_high_cred;
|
|
u32 mtl_high_cred_offset;
|
|
u32 mtl_low_cred;
|
|
u32 mtl_low_cred_offset;
|
|
};
|
|
|
|
#define STMMAC_FLAG_SPH_DISABLE BIT(1)
|
|
#define STMMAC_FLAG_USE_PHY_WOL BIT(2)
|
|
#define STMMAC_FLAG_HAS_SUN8I BIT(3)
|
|
#define STMMAC_FLAG_TSO_EN BIT(4)
|
|
#define STMMAC_FLAG_SERDES_UP_AFTER_PHY_LINKUP BIT(5)
|
|
#define STMMAC_FLAG_VLAN_FAIL_Q_EN BIT(6)
|
|
#define STMMAC_FLAG_MULTI_MSI_EN BIT(7)
|
|
#define STMMAC_FLAG_EXT_SNAPSHOT_EN BIT(8)
|
|
#define STMMAC_FLAG_INT_SNAPSHOT_EN BIT(9)
|
|
#define STMMAC_FLAG_RX_CLK_RUNS_IN_LPI BIT(10)
|
|
#define STMMAC_FLAG_EN_TX_LPI_CLOCKGATING BIT(11)
|
|
#define STMMAC_FLAG_EN_TX_LPI_CLK_PHY_CAP BIT(12)
|
|
#define STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY BIT(13)
|
|
|
|
struct plat_stmmacenet_data {
|
|
int bus_id;
|
|
int phy_addr;
|
|
/* MAC ----- optional PCS ----- SerDes ----- optional PHY ----- Media
|
|
* ^
|
|
* phy_interface
|
|
*
|
|
* The Synopsys dwmac core only covers the MAC and an optional
|
|
* integrated PCS. Where the integrated PCS is used with a SerDes,
|
|
* e.g. for 1000base-X or Cisco SGMII, the connection between the
|
|
* PCS and SerDes will be TBI.
|
|
*
|
|
* Where the Synopsys dwmac core has been instantiated with multiple
|
|
* interface modes, these are selected via core-external configuration
|
|
* which is sampled when the dwmac core is reset. How this is done is
|
|
* platform glue specific, but this defines the interface used from
|
|
* the Synopsys dwmac core to the rest of the SoC.
|
|
*
|
|
* Where PCS other than the optional integrated Synopsys dwmac PCS
|
|
* is used, this counts as "the rest of the SoC" in the above
|
|
* paragraph.
|
|
*
|
|
* phy_interface is the PHY-side interface - the interface used by
|
|
* an attached PHY or SFP etc. This is equivalent to the interface
|
|
* that phylink uses.
|
|
*/
|
|
phy_interface_t phy_interface;
|
|
struct stmmac_mdio_bus_data *mdio_bus_data;
|
|
struct device_node *phy_node;
|
|
struct fwnode_handle *port_node;
|
|
struct device_node *mdio_node;
|
|
struct stmmac_dma_cfg *dma_cfg;
|
|
struct stmmac_safety_feature_cfg *safety_feat_cfg;
|
|
int clk_csr;
|
|
int has_gmac;
|
|
int enh_desc;
|
|
int tx_coe;
|
|
int rx_coe;
|
|
int bugged_jumbo;
|
|
int pmt;
|
|
int force_sf_dma_mode;
|
|
int force_thresh_dma_mode;
|
|
int riwt_off;
|
|
int max_speed;
|
|
int maxmtu;
|
|
int multicast_filter_bins;
|
|
int unicast_filter_entries;
|
|
int tx_fifo_size;
|
|
int rx_fifo_size;
|
|
u32 host_dma_width;
|
|
u32 rx_queues_to_use;
|
|
u32 tx_queues_to_use;
|
|
u8 rx_sched_algorithm;
|
|
u8 tx_sched_algorithm;
|
|
struct stmmac_rxq_cfg rx_queues_cfg[MTL_MAX_RX_QUEUES];
|
|
struct stmmac_txq_cfg tx_queues_cfg[MTL_MAX_TX_QUEUES];
|
|
void (*get_interfaces)(struct stmmac_priv *priv, void *bsp_priv,
|
|
unsigned long *interfaces);
|
|
int (*set_clk_tx_rate)(void *priv, struct clk *clk_tx_i,
|
|
phy_interface_t interface, int speed);
|
|
void (*fix_mac_speed)(void *priv, int speed, unsigned int mode);
|
|
int (*fix_soc_reset)(struct stmmac_priv *priv, void __iomem *ioaddr);
|
|
int (*serdes_powerup)(struct net_device *ndev, void *priv);
|
|
void (*serdes_powerdown)(struct net_device *ndev, void *priv);
|
|
int (*mac_finish)(struct net_device *ndev,
|
|
void *priv,
|
|
unsigned int mode,
|
|
phy_interface_t interface);
|
|
void (*ptp_clk_freq_config)(struct stmmac_priv *priv);
|
|
int (*init)(struct platform_device *pdev, void *priv);
|
|
void (*exit)(struct platform_device *pdev, void *priv);
|
|
int (*suspend)(struct device *dev, void *priv);
|
|
int (*resume)(struct device *dev, void *priv);
|
|
struct mac_device_info *(*setup)(void *priv);
|
|
int (*clks_config)(void *priv, bool enabled);
|
|
int (*crosststamp)(ktime_t *device, struct system_counterval_t *system,
|
|
void *ctx);
|
|
void (*dump_debug_regs)(void *priv);
|
|
int (*pcs_init)(struct stmmac_priv *priv);
|
|
void (*pcs_exit)(struct stmmac_priv *priv);
|
|
struct phylink_pcs *(*select_pcs)(struct stmmac_priv *priv,
|
|
phy_interface_t interface);
|
|
void *bsp_priv;
|
|
struct clk *stmmac_clk;
|
|
struct clk *pclk;
|
|
struct clk *clk_ptp_ref;
|
|
struct clk *clk_tx_i; /* clk_tx_i to MAC core */
|
|
unsigned long clk_ptp_rate;
|
|
unsigned long clk_ref_rate;
|
|
struct clk_bulk_data *clks;
|
|
int num_clks;
|
|
unsigned int mult_fact_100ns;
|
|
s32 ptp_max_adj;
|
|
u32 cdc_error_adj;
|
|
struct reset_control *stmmac_rst;
|
|
struct reset_control *stmmac_ahb_rst;
|
|
struct stmmac_axi *axi;
|
|
int has_gmac4;
|
|
int rss_en;
|
|
int mac_port_sel_speed;
|
|
int has_xgmac;
|
|
u8 vlan_fail_q;
|
|
struct pci_dev *pdev;
|
|
int int_snapshot_num;
|
|
int msi_mac_vec;
|
|
int msi_wol_vec;
|
|
int msi_lpi_vec;
|
|
int msi_sfty_ce_vec;
|
|
int msi_sfty_ue_vec;
|
|
int msi_rx_base_vec;
|
|
int msi_tx_base_vec;
|
|
const struct dwmac4_addrs *dwmac4_addrs;
|
|
unsigned int flags;
|
|
};
|
|
#endif
|