mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-16 12:31:52 -04:00
Merge branch 'net-stmmac-phylink-pcs-conversion'
Russell King says: ==================== net: stmmac: phylink PCS conversion This series is radical - it takes the brave step of ripping out much of the existing PCS support code and throwing it all away. I have discussed the introduction of the STMMAC_FLAG_HAS_INTEGRATED_PCS flag with Bartosz Golaszewski, and the conclusion I came to is that this is to workaround the breakage that I've been going on about concerning the phylink conversion for the last five or six years. The problem is that the stmmac PCS code manipulates the netif carrier state, which confuses phylink. There is a way of testing this out on the Jetson Xavier NX platform as the "PCS" code paths can be exercised while in RGMII mode - because RGMII also has in-band status and the status register is shared with SGMII. Testing this out confirms my long held theory: the interrupt handler manipulates the netif carrier state before phylink gets a look-in, which means that the mac_link_up() and mac_link_down() methods are never called, resulting in the device being non-functional. Moreover, on dwmac4 cores, ethtool reports incorrect information - despite having a full-duplex link, ethtool reports that it is half-dupex. Thus, this code is completely broken - anyone using it will not have a functional platform, and thus it doesn't deserve to live any longer, especially as it's a thorn in phylink. Rip all this out, leaving just the bare bones initialisation in place. However, this is not the last of what's broken. We have this hw->ps integer which is really not descriptive, and the DT property from which it comes from does little to help understand what's going on. Putting all the clues together: - early configuration of the GMAC configuration register for the speed. - setting the SGMII rate adapter layer to take its speed from the GMAC configuration register. Lastly, setting the transmit enable (TE) bit, which is a typo that puts the nail in the coffin of this code. It should be the transmit configuration (TC) bit. Given that when the link comes up, phylink will call mac_link_up() which will overwrite the speed in the GMAC configuration register, the only part of this that is functional is changing where the SGMII rate adapter layer gets its speed from, which is a boolean. From what I've found so far, everyone who sets the snps,ps-speed property which configures this mode also configures a fixed link, so the pre-configuration is unnecessary - the link will come up anyway. So, this series rips that out the preconfiguration as well, and replaces hw->ps with a boolean hw->reverse_sgmii_enable flag. We then move the sole PCS configuration into a phylink_pcs instance, which configures the PCS control register in the same way as is done during the probe function. Thus, we end up with much easier and simpler conversion to phylink PCS than previous attempts. Even so, this still results in inband mode always being enabled at the moment in the new .pcs_config() method to reflect what the probe function was doing. The next stage will be to change that to allow phylink to correctly configure the PCS. This needs fixing to allow platform glue maintainers who are currently blocked to progress. Please note, however, that this has not been tested with any SGMII platform. I've tried to get as many people into the Cc list with get_maintainers, I hope that's sufficient to get enough eyeballs on this. Changes since RFC: - new patch (7) to remove RGMII "pcs" mode - new patch (8) to move reverse "pcs" mode to stmmac_check_pcs_mode() - new patch (9) to simplify the code moved in the previous patch - new patch (10) to rename the confusing hw->ps to something more understandable. - new patch (11) to shut up inappropriate complaints about "snps,ps-speed" being invalid. - new patch (13) to add a MAC .pcs_init method, which will only be called when core has PCS present. - modify patch 14 to use this new pcs_init method. Despite getting a couple of responses to the RFC series posted in September, I have had nothing testing this on hardware. I have tested this on the Jetson Xavier NX, which included trial runs with enabling the RGMII "pcs" mode, hence the new patches that rip out this mode. I have come to the conclusion that the only way to get stmmac changes tested is to get them merged into net-next, thereby forcing people to have to run with them... and we'll deal with any fallout later. ==================== Link: https://patch.msgid.link/aPECqg0vZGnBFCbh@shell.armlinux.org.uk Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
@@ -7,7 +7,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \
|
||||
dwmac4_dma.o dwmac4_lib.o dwmac4_core.o dwmac5.o hwif.o \
|
||||
stmmac_tc.o dwxgmac2_core.o dwxgmac2_dma.o dwxgmac2_descs.o \
|
||||
stmmac_xdp.o stmmac_est.o stmmac_fpe.o stmmac_vlan.o \
|
||||
$(stmmac-y)
|
||||
stmmac_pcs.o $(stmmac-y)
|
||||
|
||||
stmmac-$(CONFIG_STMMAC_SELFTESTS) += stmmac_selftests.o
|
||||
|
||||
|
||||
@@ -192,9 +192,6 @@ struct stmmac_extra_stats {
|
||||
unsigned long irq_pcs_ane_n;
|
||||
unsigned long irq_pcs_link_n;
|
||||
unsigned long irq_rgmii_n;
|
||||
unsigned long pcs_link;
|
||||
unsigned long pcs_duplex;
|
||||
unsigned long pcs_speed;
|
||||
/* debug register */
|
||||
unsigned long mtl_tx_status_fifo_full;
|
||||
unsigned long mtl_tx_fifo_not_empty;
|
||||
@@ -273,7 +270,6 @@ struct stmmac_safety_stats {
|
||||
#define FLOW_AUTO (FLOW_TX | FLOW_RX)
|
||||
|
||||
/* PCS defines */
|
||||
#define STMMAC_PCS_RGMII (1 << 0)
|
||||
#define STMMAC_PCS_SGMII (1 << 1)
|
||||
|
||||
#define SF_DMA_MODE 1 /* DMA STORE-AND-FORWARD Operation Mode */
|
||||
@@ -603,13 +599,13 @@ struct mac_device_info {
|
||||
unsigned int mcast_bits_log2;
|
||||
unsigned int rx_csum;
|
||||
unsigned int pcs;
|
||||
unsigned int ps;
|
||||
unsigned int xlgmac;
|
||||
unsigned int num_vlan;
|
||||
u32 vlan_filter[32];
|
||||
bool vlan_fail_q_en;
|
||||
u8 vlan_fail_q;
|
||||
bool hw_vlan_en;
|
||||
bool reverse_sgmii_enable;
|
||||
};
|
||||
|
||||
struct stmmac_rx_routing {
|
||||
|
||||
@@ -96,7 +96,6 @@ struct ethqos_emac_driver_data {
|
||||
bool rgmii_config_loopback_en;
|
||||
bool has_emac_ge_3;
|
||||
const char *link_clk_name;
|
||||
bool has_integrated_pcs;
|
||||
u32 dma_addr_width;
|
||||
struct dwmac4_addrs dwmac4_addrs;
|
||||
bool needs_sgmii_loopback;
|
||||
@@ -282,7 +281,6 @@ static const struct ethqos_emac_driver_data emac_v4_0_0_data = {
|
||||
.rgmii_config_loopback_en = false,
|
||||
.has_emac_ge_3 = true,
|
||||
.link_clk_name = "phyaux",
|
||||
.has_integrated_pcs = true,
|
||||
.needs_sgmii_loopback = true,
|
||||
.dma_addr_width = 36,
|
||||
.dwmac4_addrs = {
|
||||
@@ -624,7 +622,7 @@ static void ethqos_set_serdes_speed(struct qcom_ethqos *ethqos, int speed)
|
||||
|
||||
static void ethqos_pcs_set_inband(struct stmmac_priv *priv, bool enable)
|
||||
{
|
||||
stmmac_pcs_ctrl_ane(priv, enable, 0, 0);
|
||||
stmmac_pcs_ctrl_ane(priv, enable, 0);
|
||||
}
|
||||
|
||||
/* On interface toggle MAC registers gets reset.
|
||||
@@ -856,8 +854,6 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
|
||||
plat_dat->flags |= STMMAC_FLAG_TSO_EN;
|
||||
if (of_device_is_compatible(np, "qcom,qcs404-ethqos"))
|
||||
plat_dat->flags |= STMMAC_FLAG_RX_CLK_RUNS_IN_LPI;
|
||||
if (data->has_integrated_pcs)
|
||||
plat_dat->flags |= STMMAC_FLAG_HAS_INTEGRATED_PCS;
|
||||
if (data->dma_addr_width)
|
||||
plat_dat->host_dma_width = data->dma_addr_width;
|
||||
|
||||
|
||||
@@ -38,10 +38,10 @@
|
||||
#define GMAC_INT_DISABLE_PCSAN BIT(2)
|
||||
#define GMAC_INT_DISABLE_PMT BIT(3)
|
||||
#define GMAC_INT_DISABLE_TIMESTAMP BIT(9)
|
||||
#define GMAC_INT_DISABLE_PCS (GMAC_INT_DISABLE_RGMII | \
|
||||
GMAC_INT_DISABLE_PCSLINK | \
|
||||
#define GMAC_INT_DISABLE_PCS (GMAC_INT_DISABLE_PCSLINK | \
|
||||
GMAC_INT_DISABLE_PCSAN)
|
||||
#define GMAC_INT_DEFAULT_MASK (GMAC_INT_DISABLE_TIMESTAMP | \
|
||||
#define GMAC_INT_DEFAULT_MASK (GMAC_INT_DISABLE_RGMII | \
|
||||
GMAC_INT_DISABLE_TIMESTAMP | \
|
||||
GMAC_INT_DISABLE_PCS)
|
||||
|
||||
/* PMT Control and Status */
|
||||
|
||||
@@ -22,39 +22,30 @@
|
||||
#include "stmmac_ptp.h"
|
||||
#include "dwmac1000.h"
|
||||
|
||||
static int dwmac1000_pcs_init(struct stmmac_priv *priv)
|
||||
{
|
||||
if (!priv->dma_cap.pcs)
|
||||
return 0;
|
||||
|
||||
return stmmac_integrated_pcs_init(priv, GMAC_PCS_BASE);
|
||||
}
|
||||
|
||||
static void dwmac1000_core_init(struct mac_device_info *hw,
|
||||
struct net_device *dev)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 value = readl(ioaddr + GMAC_CONTROL);
|
||||
int mtu = dev->mtu;
|
||||
u32 value;
|
||||
|
||||
/* Configure GMAC core */
|
||||
value |= GMAC_CORE_INIT;
|
||||
value = readl(ioaddr + GMAC_CONTROL);
|
||||
|
||||
if (mtu > 1500)
|
||||
value |= GMAC_CONTROL_2K;
|
||||
if (mtu > 2000)
|
||||
value |= GMAC_CONTROL_JE;
|
||||
|
||||
if (hw->ps) {
|
||||
value |= GMAC_CONTROL_TE;
|
||||
|
||||
value &= ~hw->link.speed_mask;
|
||||
switch (hw->ps) {
|
||||
case SPEED_1000:
|
||||
value |= hw->link.speed1000;
|
||||
break;
|
||||
case SPEED_100:
|
||||
value |= hw->link.speed100;
|
||||
break;
|
||||
case SPEED_10:
|
||||
value |= hw->link.speed10;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
writel(value, ioaddr + GMAC_CONTROL);
|
||||
writel(value | GMAC_CORE_INIT, ioaddr + GMAC_CONTROL);
|
||||
|
||||
/* Mask GMAC interrupts */
|
||||
value = GMAC_INT_DEFAULT_MASK;
|
||||
@@ -263,39 +254,6 @@ static void dwmac1000_pmt(struct mac_device_info *hw, unsigned long mode)
|
||||
writel(pmt, ioaddr + GMAC_PMT);
|
||||
}
|
||||
|
||||
/* RGMII or SMII interface */
|
||||
static void dwmac1000_rgsmii(void __iomem *ioaddr, struct stmmac_extra_stats *x)
|
||||
{
|
||||
u32 status;
|
||||
|
||||
status = readl(ioaddr + GMAC_RGSMIIIS);
|
||||
x->irq_rgmii_n++;
|
||||
|
||||
/* Check the link status */
|
||||
if (status & GMAC_RGSMIIIS_LNKSTS) {
|
||||
int speed_value;
|
||||
|
||||
x->pcs_link = 1;
|
||||
|
||||
speed_value = ((status & GMAC_RGSMIIIS_SPEED) >>
|
||||
GMAC_RGSMIIIS_SPEED_SHIFT);
|
||||
if (speed_value == GMAC_RGSMIIIS_SPEED_125)
|
||||
x->pcs_speed = SPEED_1000;
|
||||
else if (speed_value == GMAC_RGSMIIIS_SPEED_25)
|
||||
x->pcs_speed = SPEED_100;
|
||||
else
|
||||
x->pcs_speed = SPEED_10;
|
||||
|
||||
x->pcs_duplex = (status & GMAC_RGSMIIIS_LNKMOD_MASK);
|
||||
|
||||
pr_info("Link is Up - %d/%s\n", (int)x->pcs_speed,
|
||||
x->pcs_duplex ? "Full" : "Half");
|
||||
} else {
|
||||
x->pcs_link = 0;
|
||||
pr_info("Link is Down\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int dwmac1000_irq_status(struct mac_device_info *hw,
|
||||
struct stmmac_extra_stats *x)
|
||||
{
|
||||
@@ -337,9 +295,6 @@ static int dwmac1000_irq_status(struct mac_device_info *hw,
|
||||
|
||||
dwmac_pcs_isr(ioaddr, GMAC_PCS_BASE, intr_status, x);
|
||||
|
||||
if (intr_status & PCS_RGSMIIIS_IRQ)
|
||||
dwmac1000_rgsmii(ioaddr, x);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -394,9 +349,9 @@ static void dwmac1000_set_eee_timer(struct mac_device_info *hw, int ls, int tw)
|
||||
}
|
||||
|
||||
static void dwmac1000_ctrl_ane(struct stmmac_priv *priv, bool ane,
|
||||
bool srgmi_ral, bool loopback)
|
||||
bool srgmi_ral)
|
||||
{
|
||||
dwmac_ctrl_ane(priv->ioaddr, GMAC_PCS_BASE, ane, srgmi_ral, loopback);
|
||||
dwmac_ctrl_ane(priv->ioaddr, GMAC_PCS_BASE, ane, srgmi_ral);
|
||||
}
|
||||
|
||||
static void dwmac1000_debug(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
@@ -488,6 +443,7 @@ static void dwmac1000_set_mac_loopback(void __iomem *ioaddr, bool enable)
|
||||
}
|
||||
|
||||
const struct stmmac_ops dwmac1000_ops = {
|
||||
.pcs_init = dwmac1000_pcs_init,
|
||||
.core_init = dwmac1000_core_init,
|
||||
.set_mac = stmmac_set_mac,
|
||||
.rx_ipc = dwmac1000_rx_ipc_enable,
|
||||
|
||||
@@ -106,8 +106,7 @@
|
||||
#define GMAC_INT_LPI_EN BIT(5)
|
||||
#define GMAC_INT_TSIE BIT(12)
|
||||
|
||||
#define GMAC_PCS_IRQ_DEFAULT (GMAC_INT_RGSMIIS | GMAC_INT_PCS_LINK | \
|
||||
GMAC_INT_PCS_ANE)
|
||||
#define GMAC_PCS_IRQ_DEFAULT (GMAC_INT_PCS_LINK | GMAC_INT_PCS_ANE)
|
||||
|
||||
#define GMAC_INT_DEFAULT_ENABLE (GMAC_INT_PMT_EN | GMAC_INT_LPI_EN | \
|
||||
GMAC_INT_TSIE)
|
||||
|
||||
@@ -22,34 +22,24 @@
|
||||
#include "dwmac4.h"
|
||||
#include "dwmac5.h"
|
||||
|
||||
static int dwmac4_pcs_init(struct stmmac_priv *priv)
|
||||
{
|
||||
if (!priv->dma_cap.pcs)
|
||||
return 0;
|
||||
|
||||
return stmmac_integrated_pcs_init(priv, GMAC_PCS_BASE);
|
||||
}
|
||||
|
||||
static void dwmac4_core_init(struct mac_device_info *hw,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 value = readl(ioaddr + GMAC_CONFIG);
|
||||
unsigned long clk_rate;
|
||||
u32 value;
|
||||
|
||||
value |= GMAC_CORE_INIT;
|
||||
|
||||
if (hw->ps) {
|
||||
value |= GMAC_CONFIG_TE;
|
||||
|
||||
value &= hw->link.speed_mask;
|
||||
switch (hw->ps) {
|
||||
case SPEED_1000:
|
||||
value |= hw->link.speed1000;
|
||||
break;
|
||||
case SPEED_100:
|
||||
value |= hw->link.speed100;
|
||||
break;
|
||||
case SPEED_10:
|
||||
value |= hw->link.speed10;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
writel(value, ioaddr + GMAC_CONFIG);
|
||||
value = readl(ioaddr + GMAC_CONFIG);
|
||||
writel(value | GMAC_CORE_INIT, ioaddr + GMAC_CONFIG);
|
||||
|
||||
/* Configure LPI 1us counter to number of CSR clock ticks in 1us - 1 */
|
||||
clk_rate = clk_get_rate(priv->plat->stmmac_clk);
|
||||
@@ -583,43 +573,9 @@ static void dwmac4_flow_ctrl(struct mac_device_info *hw, unsigned int duplex,
|
||||
}
|
||||
}
|
||||
|
||||
static void dwmac4_ctrl_ane(struct stmmac_priv *priv, bool ane, bool srgmi_ral,
|
||||
bool loopback)
|
||||
static void dwmac4_ctrl_ane(struct stmmac_priv *priv, bool ane, bool srgmi_ral)
|
||||
{
|
||||
dwmac_ctrl_ane(priv->ioaddr, GMAC_PCS_BASE, ane, srgmi_ral, loopback);
|
||||
}
|
||||
|
||||
/* RGMII or SMII interface */
|
||||
static void dwmac4_phystatus(void __iomem *ioaddr, struct stmmac_extra_stats *x)
|
||||
{
|
||||
u32 status;
|
||||
|
||||
status = readl(ioaddr + GMAC_PHYIF_CONTROL_STATUS);
|
||||
x->irq_rgmii_n++;
|
||||
|
||||
/* Check the link status */
|
||||
if (status & GMAC_PHYIF_CTRLSTATUS_LNKSTS) {
|
||||
int speed_value;
|
||||
|
||||
x->pcs_link = 1;
|
||||
|
||||
speed_value = ((status & GMAC_PHYIF_CTRLSTATUS_SPEED) >>
|
||||
GMAC_PHYIF_CTRLSTATUS_SPEED_SHIFT);
|
||||
if (speed_value == GMAC_PHYIF_CTRLSTATUS_SPEED_125)
|
||||
x->pcs_speed = SPEED_1000;
|
||||
else if (speed_value == GMAC_PHYIF_CTRLSTATUS_SPEED_25)
|
||||
x->pcs_speed = SPEED_100;
|
||||
else
|
||||
x->pcs_speed = SPEED_10;
|
||||
|
||||
x->pcs_duplex = (status & GMAC_PHYIF_CTRLSTATUS_LNKMOD);
|
||||
|
||||
pr_info("Link is Up - %d/%s\n", (int)x->pcs_speed,
|
||||
x->pcs_duplex ? "Full" : "Half");
|
||||
} else {
|
||||
x->pcs_link = 0;
|
||||
pr_info("Link is Down\n");
|
||||
}
|
||||
dwmac_ctrl_ane(priv->ioaddr, GMAC_PCS_BASE, ane, srgmi_ral);
|
||||
}
|
||||
|
||||
static int dwmac4_irq_mtl_status(struct stmmac_priv *priv,
|
||||
@@ -693,8 +649,6 @@ static int dwmac4_irq_status(struct mac_device_info *hw,
|
||||
}
|
||||
|
||||
dwmac_pcs_isr(ioaddr, GMAC_PCS_BASE, intr_status, x);
|
||||
if (intr_status & PCS_RGSMIIIS_IRQ)
|
||||
dwmac4_phystatus(ioaddr, x);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -929,6 +883,7 @@ static int dwmac4_config_l4_filter(struct mac_device_info *hw, u32 filter_no,
|
||||
}
|
||||
|
||||
const struct stmmac_ops dwmac4_ops = {
|
||||
.pcs_init = dwmac4_pcs_init,
|
||||
.core_init = dwmac4_core_init,
|
||||
.update_caps = dwmac4_update_caps,
|
||||
.set_mac = stmmac_set_mac,
|
||||
@@ -963,6 +918,7 @@ const struct stmmac_ops dwmac4_ops = {
|
||||
};
|
||||
|
||||
const struct stmmac_ops dwmac410_ops = {
|
||||
.pcs_init = dwmac4_pcs_init,
|
||||
.core_init = dwmac4_core_init,
|
||||
.update_caps = dwmac4_update_caps,
|
||||
.set_mac = stmmac_dwmac4_set_mac,
|
||||
@@ -999,6 +955,7 @@ const struct stmmac_ops dwmac410_ops = {
|
||||
};
|
||||
|
||||
const struct stmmac_ops dwmac510_ops = {
|
||||
.pcs_init = dwmac4_pcs_init,
|
||||
.core_init = dwmac4_core_init,
|
||||
.update_caps = dwmac4_update_caps,
|
||||
.set_mac = stmmac_dwmac4_set_mac,
|
||||
|
||||
@@ -23,29 +23,8 @@ static void dwxgmac2_core_init(struct mac_device_info *hw,
|
||||
tx = readl(ioaddr + XGMAC_TX_CONFIG);
|
||||
rx = readl(ioaddr + XGMAC_RX_CONFIG);
|
||||
|
||||
tx |= XGMAC_CORE_INIT_TX;
|
||||
rx |= XGMAC_CORE_INIT_RX;
|
||||
|
||||
if (hw->ps) {
|
||||
tx |= XGMAC_CONFIG_TE;
|
||||
tx &= ~hw->link.speed_mask;
|
||||
|
||||
switch (hw->ps) {
|
||||
case SPEED_10000:
|
||||
tx |= hw->link.xgmii.speed10000;
|
||||
break;
|
||||
case SPEED_2500:
|
||||
tx |= hw->link.speed2500;
|
||||
break;
|
||||
case SPEED_1000:
|
||||
default:
|
||||
tx |= hw->link.speed1000;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
writel(tx, ioaddr + XGMAC_TX_CONFIG);
|
||||
writel(rx, ioaddr + XGMAC_RX_CONFIG);
|
||||
writel(tx | XGMAC_CORE_INIT_TX, ioaddr + XGMAC_TX_CONFIG);
|
||||
writel(rx | XGMAC_CORE_INIT_RX, ioaddr + XGMAC_RX_CONFIG);
|
||||
writel(XGMAC_INT_DEFAULT_EN, ioaddr + XGMAC_INT_EN);
|
||||
}
|
||||
|
||||
|
||||
@@ -313,6 +313,8 @@ enum stmmac_lpi_mode {
|
||||
|
||||
/* Helpers to program the MAC core */
|
||||
struct stmmac_ops {
|
||||
/* Initialise any PCS instances */
|
||||
int (*pcs_init)(struct stmmac_priv *priv);
|
||||
/* MAC core initialization */
|
||||
void (*core_init)(struct mac_device_info *hw, struct net_device *dev);
|
||||
/* Update MAC capabilities */
|
||||
@@ -374,8 +376,8 @@ struct stmmac_ops {
|
||||
struct stmmac_extra_stats *x, u32 rx_queues,
|
||||
u32 tx_queues);
|
||||
/* PCS calls */
|
||||
void (*pcs_ctrl_ane)(struct stmmac_priv *priv, bool ane, bool srgmi_ral,
|
||||
bool loopback);
|
||||
void (*pcs_ctrl_ane)(struct stmmac_priv *priv, bool ane,
|
||||
bool srgmi_ral);
|
||||
/* Safety Features */
|
||||
int (*safety_feat_config)(void __iomem *ioaddr, unsigned int asp,
|
||||
struct stmmac_safety_feature_cfg *safety_cfg);
|
||||
@@ -413,6 +415,8 @@ struct stmmac_ops {
|
||||
u32 pclass);
|
||||
};
|
||||
|
||||
#define stmmac_mac_pcs_init(__priv) \
|
||||
stmmac_do_callback(__priv, mac, pcs_init, __priv)
|
||||
#define stmmac_core_init(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, core_init, __args)
|
||||
#define stmmac_mac_update_caps(__priv) \
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#include <net/xdp.h>
|
||||
#include <uapi/linux/bpf.h>
|
||||
|
||||
struct stmmac_pcs;
|
||||
|
||||
struct stmmac_resources {
|
||||
void __iomem *addr;
|
||||
u8 mac[ETH_ALEN];
|
||||
@@ -273,6 +275,8 @@ struct stmmac_priv {
|
||||
unsigned int pause_time;
|
||||
struct mii_bus *mii;
|
||||
|
||||
struct stmmac_pcs *integrated_pcs;
|
||||
|
||||
struct phylink_config phylink_config;
|
||||
struct phylink *phylink;
|
||||
|
||||
|
||||
@@ -322,47 +322,6 @@ static int stmmac_ethtool_get_link_ksettings(struct net_device *dev,
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
|
||||
if (!(priv->plat->flags & STMMAC_FLAG_HAS_INTEGRATED_PCS) &&
|
||||
(priv->hw->pcs & STMMAC_PCS_RGMII ||
|
||||
priv->hw->pcs & STMMAC_PCS_SGMII)) {
|
||||
u32 supported, advertising, lp_advertising;
|
||||
|
||||
if (!priv->xstats.pcs_link) {
|
||||
cmd->base.speed = SPEED_UNKNOWN;
|
||||
cmd->base.duplex = DUPLEX_UNKNOWN;
|
||||
return 0;
|
||||
}
|
||||
cmd->base.duplex = priv->xstats.pcs_duplex;
|
||||
|
||||
cmd->base.speed = priv->xstats.pcs_speed;
|
||||
|
||||
/* Encoding of PSE bits is defined in 802.3z, 37.2.1.4 */
|
||||
|
||||
ethtool_convert_link_mode_to_legacy_u32(
|
||||
&supported, cmd->link_modes.supported);
|
||||
ethtool_convert_link_mode_to_legacy_u32(
|
||||
&advertising, cmd->link_modes.advertising);
|
||||
ethtool_convert_link_mode_to_legacy_u32(
|
||||
&lp_advertising, cmd->link_modes.lp_advertising);
|
||||
|
||||
/* Reg49[3] always set because ANE is always supported */
|
||||
cmd->base.autoneg = ADVERTISED_Autoneg;
|
||||
supported |= SUPPORTED_Autoneg;
|
||||
advertising |= ADVERTISED_Autoneg;
|
||||
lp_advertising |= ADVERTISED_Autoneg;
|
||||
|
||||
cmd->base.port = PORT_OTHER;
|
||||
|
||||
ethtool_convert_legacy_u32_to_link_mode(
|
||||
cmd->link_modes.supported, supported);
|
||||
ethtool_convert_legacy_u32_to_link_mode(
|
||||
cmd->link_modes.advertising, advertising);
|
||||
ethtool_convert_legacy_u32_to_link_mode(
|
||||
cmd->link_modes.lp_advertising, lp_advertising);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return phylink_ethtool_ksettings_get(priv->phylink, cmd);
|
||||
}
|
||||
|
||||
@@ -372,20 +331,6 @@ stmmac_ethtool_set_link_ksettings(struct net_device *dev,
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
|
||||
if (!(priv->plat->flags & STMMAC_FLAG_HAS_INTEGRATED_PCS) &&
|
||||
(priv->hw->pcs & STMMAC_PCS_RGMII ||
|
||||
priv->hw->pcs & STMMAC_PCS_SGMII)) {
|
||||
/* Only support ANE */
|
||||
if (cmd->base.autoneg != AUTONEG_ENABLE)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&priv->lock);
|
||||
stmmac_pcs_ctrl_ane(priv, 1, priv->hw->ps, 0);
|
||||
mutex_unlock(&priv->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return phylink_ethtool_ksettings_set(priv->phylink, cmd);
|
||||
}
|
||||
|
||||
@@ -479,11 +424,7 @@ stmmac_get_pauseparam(struct net_device *netdev,
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(netdev);
|
||||
|
||||
if (priv->hw->pcs) {
|
||||
pause->autoneg = 1;
|
||||
} else {
|
||||
phylink_ethtool_get_pauseparam(priv->phylink, pause);
|
||||
}
|
||||
phylink_ethtool_get_pauseparam(priv->phylink, pause);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -492,12 +433,7 @@ stmmac_set_pauseparam(struct net_device *netdev,
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(netdev);
|
||||
|
||||
if (priv->hw->pcs) {
|
||||
pause->autoneg = 1;
|
||||
return 0;
|
||||
} else {
|
||||
return phylink_ethtool_set_pauseparam(priv->phylink, pause);
|
||||
}
|
||||
return phylink_ethtool_set_pauseparam(priv->phylink, pause);
|
||||
}
|
||||
|
||||
static u64 stmmac_get_rx_normal_irq_n(struct stmmac_priv *priv, int q)
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include "stmmac_ptp.h"
|
||||
#include "stmmac_fpe.h"
|
||||
#include "stmmac.h"
|
||||
#include "stmmac_pcs.h"
|
||||
#include "stmmac_xdp.h"
|
||||
#include <linux/reset.h>
|
||||
#include <linux/of_mdio.h>
|
||||
@@ -850,6 +851,13 @@ static struct phylink_pcs *stmmac_mac_select_pcs(struct phylink_config *config,
|
||||
return pcs;
|
||||
}
|
||||
|
||||
/* The PCS control register is only relevant for SGMII, TBI and RTBI
|
||||
* modes. We no longer support TBI or RTBI, so only configure this
|
||||
* register when operating in SGMII mode with the integrated PCS.
|
||||
*/
|
||||
if (priv->hw->pcs & STMMAC_PCS_SGMII && priv->integrated_pcs)
|
||||
return &priv->integrated_pcs->pcs;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1086,17 +1094,25 @@ static const struct phylink_mac_ops stmmac_phylink_mac_ops = {
|
||||
static void stmmac_check_pcs_mode(struct stmmac_priv *priv)
|
||||
{
|
||||
int interface = priv->plat->phy_interface;
|
||||
int speed = priv->plat->mac_port_sel_speed;
|
||||
|
||||
if (priv->dma_cap.pcs) {
|
||||
if ((interface == PHY_INTERFACE_MODE_RGMII) ||
|
||||
(interface == PHY_INTERFACE_MODE_RGMII_ID) ||
|
||||
(interface == PHY_INTERFACE_MODE_RGMII_RXID) ||
|
||||
(interface == PHY_INTERFACE_MODE_RGMII_TXID)) {
|
||||
netdev_dbg(priv->dev, "PCS RGMII support enabled\n");
|
||||
priv->hw->pcs = STMMAC_PCS_RGMII;
|
||||
} else if (interface == PHY_INTERFACE_MODE_SGMII) {
|
||||
netdev_dbg(priv->dev, "PCS SGMII support enabled\n");
|
||||
priv->hw->pcs = STMMAC_PCS_SGMII;
|
||||
if (priv->dma_cap.pcs && interface == PHY_INTERFACE_MODE_SGMII) {
|
||||
netdev_dbg(priv->dev, "PCS SGMII support enabled\n");
|
||||
priv->hw->pcs = STMMAC_PCS_SGMII;
|
||||
|
||||
switch (speed) {
|
||||
case SPEED_10:
|
||||
case SPEED_100:
|
||||
case SPEED_1000:
|
||||
priv->hw->reverse_sgmii_enable = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_warn(priv->device, "invalid port speed\n");
|
||||
fallthrough;
|
||||
case 0:
|
||||
priv->hw->reverse_sgmii_enable = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3443,19 +3459,6 @@ static int stmmac_hw_setup(struct net_device *dev)
|
||||
stmmac_set_umac_addr(priv, priv->hw, dev->dev_addr, 0);
|
||||
phylink_rx_clk_stop_unblock(priv->phylink);
|
||||
|
||||
/* PS and related bits will be programmed according to the speed */
|
||||
if (priv->hw->pcs) {
|
||||
int speed = priv->plat->mac_port_sel_speed;
|
||||
|
||||
if ((speed == SPEED_10) || (speed == SPEED_100) ||
|
||||
(speed == SPEED_1000)) {
|
||||
priv->hw->ps = speed;
|
||||
} else {
|
||||
dev_warn(priv->device, "invalid port speed\n");
|
||||
priv->hw->ps = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize the MAC Core */
|
||||
stmmac_core_init(priv, priv->hw, dev);
|
||||
|
||||
@@ -3492,9 +3495,6 @@ static int stmmac_hw_setup(struct net_device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->hw->pcs)
|
||||
stmmac_pcs_ctrl_ane(priv, 1, priv->hw->ps, 0);
|
||||
|
||||
/* set TX and RX rings length */
|
||||
stmmac_set_rings_length(priv);
|
||||
|
||||
@@ -6001,15 +6001,6 @@ static void stmmac_common_interrupt(struct stmmac_priv *priv)
|
||||
for (queue = 0; queue < queues_count; queue++)
|
||||
stmmac_host_mtl_irq_status(priv, priv->hw, queue);
|
||||
|
||||
/* PCS link status */
|
||||
if (priv->hw->pcs &&
|
||||
!(priv->plat->flags & STMMAC_FLAG_HAS_INTEGRATED_PCS)) {
|
||||
if (priv->xstats.pcs_link)
|
||||
netif_carrier_on(priv->dev);
|
||||
else
|
||||
netif_carrier_off(priv->dev);
|
||||
}
|
||||
|
||||
stmmac_timestamp_interrupt(priv, priv);
|
||||
}
|
||||
}
|
||||
@@ -7249,6 +7240,13 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
|
||||
"Enable RX Mitigation via HW Watchdog Timer\n");
|
||||
}
|
||||
|
||||
/* Unimplemented PCS init (as indicated by stmmac_do_callback()
|
||||
* perversely returning -EINVAL) is non-fatal.
|
||||
*/
|
||||
ret = stmmac_mac_pcs_init(priv);
|
||||
if (ret != -EINVAL)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
47
drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.c
Normal file
47
drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.c
Normal file
@@ -0,0 +1,47 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#include "stmmac.h"
|
||||
#include "stmmac_pcs.h"
|
||||
|
||||
static void dwmac_integrated_pcs_get_state(struct phylink_pcs *pcs,
|
||||
unsigned int neg_mode,
|
||||
struct phylink_link_state *state)
|
||||
{
|
||||
state->link = false;
|
||||
}
|
||||
|
||||
static int dwmac_integrated_pcs_config(struct phylink_pcs *pcs,
|
||||
unsigned int neg_mode,
|
||||
phy_interface_t interface,
|
||||
const unsigned long *advertising,
|
||||
bool permit_pause_to_mac)
|
||||
{
|
||||
struct stmmac_pcs *spcs = phylink_pcs_to_stmmac_pcs(pcs);
|
||||
|
||||
dwmac_ctrl_ane(spcs->base, 0, 1, spcs->priv->hw->reverse_sgmii_enable);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct phylink_pcs_ops dwmac_integrated_pcs_ops = {
|
||||
.pcs_get_state = dwmac_integrated_pcs_get_state,
|
||||
.pcs_config = dwmac_integrated_pcs_config,
|
||||
};
|
||||
|
||||
int stmmac_integrated_pcs_init(struct stmmac_priv *priv, unsigned int offset)
|
||||
{
|
||||
struct stmmac_pcs *spcs;
|
||||
|
||||
spcs = devm_kzalloc(priv->device, sizeof(*spcs), GFP_KERNEL);
|
||||
if (!spcs)
|
||||
return -ENOMEM;
|
||||
|
||||
spcs->priv = priv;
|
||||
spcs->base = priv->ioaddr + offset;
|
||||
spcs->pcs.ops = &dwmac_integrated_pcs_ops;
|
||||
|
||||
__set_bit(PHY_INTERFACE_MODE_SGMII, spcs->pcs.supported_interfaces);
|
||||
|
||||
priv->integrated_pcs = spcs;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
#ifndef __STMMAC_PCS_H__
|
||||
#define __STMMAC_PCS_H__
|
||||
|
||||
#include <linux/phylink.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include "common.h"
|
||||
@@ -46,6 +47,22 @@
|
||||
#define GMAC_ANE_RFE_SHIFT 12
|
||||
#define GMAC_ANE_ACK BIT(14)
|
||||
|
||||
struct stmmac_priv;
|
||||
|
||||
struct stmmac_pcs {
|
||||
struct stmmac_priv *priv;
|
||||
void __iomem *base;
|
||||
struct phylink_pcs pcs;
|
||||
};
|
||||
|
||||
static inline struct stmmac_pcs *
|
||||
phylink_pcs_to_stmmac_pcs(struct phylink_pcs *pcs)
|
||||
{
|
||||
return container_of(pcs, struct stmmac_pcs, pcs);
|
||||
}
|
||||
|
||||
int stmmac_integrated_pcs_init(struct stmmac_priv *priv, unsigned int offset);
|
||||
|
||||
/**
|
||||
* dwmac_pcs_isr - TBI, RTBI, or SGMII PHY ISR
|
||||
* @ioaddr: IO registers pointer
|
||||
@@ -82,13 +99,12 @@ static inline void dwmac_pcs_isr(void __iomem *ioaddr, u32 reg,
|
||||
* @reg: Base address of the AN Control Register.
|
||||
* @ane: to enable the auto-negotiation
|
||||
* @srgmi_ral: to manage MAC-2-MAC SGMII connections.
|
||||
* @loopback: to cause the PHY to loopback tx data into rx path.
|
||||
* Description: this is the main function to configure the AN control register
|
||||
* and init the ANE, select loopback (usually for debugging purpose) and
|
||||
* configure SGMII RAL.
|
||||
*/
|
||||
static inline void dwmac_ctrl_ane(void __iomem *ioaddr, u32 reg, bool ane,
|
||||
bool srgmi_ral, bool loopback)
|
||||
bool srgmi_ral)
|
||||
{
|
||||
u32 value = readl(ioaddr + GMAC_AN_CTRL(reg));
|
||||
|
||||
@@ -104,9 +120,6 @@ static inline void dwmac_ctrl_ane(void __iomem *ioaddr, u32 reg, bool ane,
|
||||
if (srgmi_ral)
|
||||
value |= GMAC_AN_CTRL_SGMRAL;
|
||||
|
||||
if (loopback)
|
||||
value |= GMAC_AN_CTRL_ELE;
|
||||
|
||||
writel(value, ioaddr + GMAC_AN_CTRL(reg));
|
||||
}
|
||||
#endif /* __STMMAC_PCS_H__ */
|
||||
|
||||
@@ -171,7 +171,6 @@ struct dwmac4_addrs {
|
||||
u32 mtl_low_cred_offset;
|
||||
};
|
||||
|
||||
#define STMMAC_FLAG_HAS_INTEGRATED_PCS BIT(0)
|
||||
#define STMMAC_FLAG_SPH_DISABLE BIT(1)
|
||||
#define STMMAC_FLAG_USE_PHY_WOL BIT(2)
|
||||
#define STMMAC_FLAG_HAS_SUN8I BIT(3)
|
||||
|
||||
Reference in New Issue
Block a user