diff options
author | Vladimir Oltean <vladimir.oltean@nxp.com> | 2019-11-28 15:36:10 +0200 |
---|---|---|
committer | Dong Aisheng <aisheng.dong@nxp.com> | 2019-12-02 18:04:51 +0800 |
commit | f3ebad1269aad8a04710e84dc1cd5de485e5fec4 (patch) | |
tree | 6773e7fcbb19bf513e290e913cf96504d937cda2 | |
parent | 9dc338323fad18f18653d43e5e0d0a84a2355704 (diff) |
net: mscc: ocelot: do not force Felix MACs at lower speeds than gigabit
In the LS1028A, the VSC9959 switch was integrated with an NXP PCS which
performs SGMII AN and rate adaptation autonomously. The MAC does not
need to know about this, and forcing the MAC speed to something else,
when connected to a 10/100 link partner, actually breaks the GMII
internal link between the MAC and the PCS.
Add a quirk system in the ocelot driver, and a first quirk called "PCS
performs rate adaptation", to distinguish the VSC7514 from the VSC9959
regarding this behavior.
Signed-off-by: Catalin Horghidan <catalin.horghidan@nxp.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
-rw-r--r-- | drivers/net/dsa/ocelot/felix.c | 1 | ||||
-rw-r--r-- | drivers/net/dsa/ocelot/felix.h | 1 | ||||
-rw-r--r-- | drivers/net/dsa/ocelot/felix_vsc9959.c | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/mscc/ocelot.c | 32 | ||||
-rw-r--r-- | include/soc/mscc/ocelot.h | 7 |
5 files changed, 28 insertions, 14 deletions
diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index ac6908cf4997..ab9cd7f95c8a 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -249,6 +249,7 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports) ocelot->num_stats = felix->info->num_stats; ocelot->shared_queue_sz = felix->info->shared_queue_sz; ocelot->ops = felix->info->ops; + ocelot->quirks = felix->info->quirks; base = pci_resource_start(felix->pdev, felix->info->pci_bar); diff --git a/drivers/net/dsa/ocelot/felix.h b/drivers/net/dsa/ocelot/felix.h index 204296e51d0c..6649c0cbadd2 100644 --- a/drivers/net/dsa/ocelot/felix.h +++ b/drivers/net/dsa/ocelot/felix.h @@ -18,6 +18,7 @@ struct felix_info { unsigned int num_stats; int num_ports; int pci_bar; + unsigned long quirks; }; extern struct felix_info felix_info_vsc9959; diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c index ac91ede54178..cbbada2fe692 100644 --- a/drivers/net/dsa/ocelot/felix_vsc9959.c +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c @@ -584,4 +584,5 @@ struct felix_info felix_info_vsc9959 = { .shared_queue_sz = 128 * 1024, .num_ports = 6, .pci_bar = 4, + .quirks = OCELOT_PCS_PERFORMS_RATE_ADAPTATION, }; diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 1d43459db3b7..77f9f4a8eaaa 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -409,27 +409,32 @@ static u16 ocelot_wm_enc(u16 value) void ocelot_adjust_link(struct ocelot *ocelot, int port, struct phy_device *phydev) { + int speed, mac_speed, mac_mode = DEV_MAC_MODE_CFG_FDX_ENA; struct ocelot_port *ocelot_port = ocelot->ports[port]; - int speed, mode = 0; - switch (phydev->speed) { + if (ocelot->quirks & OCELOT_PCS_PERFORMS_RATE_ADAPTATION) + speed = SPEED_1000; + else + speed = phydev->speed; + + switch (speed) { case SPEED_10: - speed = OCELOT_SPEED_10; + mac_speed = OCELOT_SPEED_10; break; case SPEED_100: - speed = OCELOT_SPEED_100; + mac_speed = OCELOT_SPEED_100; break; case SPEED_1000: - speed = OCELOT_SPEED_1000; - mode = DEV_MAC_MODE_CFG_GIGA_MODE_ENA; + mac_speed = OCELOT_SPEED_1000; + mac_mode |= DEV_MAC_MODE_CFG_GIGA_MODE_ENA; break; case SPEED_2500: - speed = OCELOT_SPEED_2500; - mode = DEV_MAC_MODE_CFG_GIGA_MODE_ENA; + mac_speed = OCELOT_SPEED_2500; + mac_mode |= DEV_MAC_MODE_CFG_GIGA_MODE_ENA; break; default: dev_err(ocelot->dev, "Unsupported PHY speed on port %d: %d\n", - port, phydev->speed); + port, speed); return; } @@ -439,8 +444,7 @@ void ocelot_adjust_link(struct ocelot *ocelot, int port, return; /* Only full duplex supported for now */ - ocelot_port_writel(ocelot_port, DEV_MAC_MODE_CFG_FDX_ENA | - mode, DEV_MAC_MODE_CFG); + ocelot_port_writel(ocelot_port, mac_mode, DEV_MAC_MODE_CFG); if (ocelot->ops->pcs_init) ocelot->ops->pcs_init(ocelot, port); @@ -451,11 +455,11 @@ void ocelot_adjust_link(struct ocelot *ocelot, int port, /* Take MAC, Port, Phy (intern) and PCS (SGMII/Serdes) clock out of * reset */ - ocelot_port_writel(ocelot_port, DEV_CLOCK_CFG_LINK_SPEED(speed), + ocelot_port_writel(ocelot_port, DEV_CLOCK_CFG_LINK_SPEED(mac_speed), DEV_CLOCK_CFG); /* No PFC */ - ocelot_write_gix(ocelot, ANA_PFC_PFC_CFG_FC_LINK_SPEED(speed), + ocelot_write_gix(ocelot, ANA_PFC_PFC_CFG_FC_LINK_SPEED(mac_speed), ANA_PFC_PFC_CFG, port); /* Core: Enable port for frame transfer */ @@ -469,7 +473,7 @@ void ocelot_adjust_link(struct ocelot *ocelot, int port, SYS_MAC_FC_CFG_RX_FC_ENA | SYS_MAC_FC_CFG_TX_FC_ENA | SYS_MAC_FC_CFG_ZERO_PAUSE_ENA | SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) | - SYS_MAC_FC_CFG_FC_LINK_SPEED(speed), + SYS_MAC_FC_CFG_FC_LINK_SPEED(mac_speed), SYS_MAC_FC_CFG, port); ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port); } diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h index ad0843a0edfd..c64cf12d1569 100644 --- a/include/soc/mscc/ocelot.h +++ b/include/soc/mscc/ocelot.h @@ -404,6 +404,11 @@ enum ocelot_tag_prefix { OCELOT_TAG_PREFIX_LONG, }; +/* Hardware quirks (differences between switch instantiations) */ +enum { + OCELOT_PCS_PERFORMS_RATE_ADAPTATION = BIT(0), +}; + struct ocelot; struct ocelot_ops { @@ -464,6 +469,8 @@ struct ocelot { struct delayed_work stats_work; struct workqueue_struct *stats_queue; + unsigned long quirks; + u8 ptp:1; struct ptp_clock *ptp_clock; struct ptp_clock_info ptp_info; |