Commit a274ce0f authored by David S. Miller's avatar David S. Miller

Merge branch 'Rethink-PHYLINK-callbacks-for-SJA1105-DSA'

Vladimir Oltean says:

====================
Rethink PHYLINK callbacks for SJA1105 DSA

This patchset implements phylink_mac_link_up and phylink_mac_link_down,
while also removing the code that was modifying the EGRESS and INGRESS
MAC settings for STP and replacing them with the "inhibit TX"
functionality.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents de47c5d8 8400cff6
...@@ -9,7 +9,7 @@ tristate "NXP SJA1105 Ethernet switch family support" ...@@ -9,7 +9,7 @@ tristate "NXP SJA1105 Ethernet switch family support"
This is the driver for the NXP SJA1105 automotive Ethernet switch This is the driver for the NXP SJA1105 automotive Ethernet switch
family. These are 5-port devices and are managed over an SPI family. These are 5-port devices and are managed over an SPI
interface. Probing is handled based on OF bindings and so is the interface. Probing is handled based on OF bindings and so is the
linkage to phylib. The driver supports the following revisions: linkage to PHYLINK. The driver supports the following revisions:
- SJA1105E (Gen. 1, No TT-Ethernet) - SJA1105E (Gen. 1, No TT-Ethernet)
- SJA1105T (Gen. 1, TT-Ethernet) - SJA1105T (Gen. 1, TT-Ethernet)
- SJA1105P (Gen. 2, No SGMII, No TT-Ethernet) - SJA1105P (Gen. 2, No SGMII, No TT-Ethernet)
......
...@@ -131,6 +131,8 @@ int sja1105_spi_send_long_packed_buf(const struct sja1105_private *priv, ...@@ -131,6 +131,8 @@ int sja1105_spi_send_long_packed_buf(const struct sja1105_private *priv,
sja1105_spi_rw_mode_t rw, u64 base_addr, sja1105_spi_rw_mode_t rw, u64 base_addr,
void *packed_buf, u64 buf_len); void *packed_buf, u64 buf_len);
int sja1105_static_config_upload(struct sja1105_private *priv); int sja1105_static_config_upload(struct sja1105_private *priv);
int sja1105_inhibit_tx(const struct sja1105_private *priv,
unsigned long port_bitmap, bool tx_inhibited);
extern struct sja1105_info sja1105e_info; extern struct sja1105_info sja1105e_info;
extern struct sja1105_info sja1105t_info; extern struct sja1105_info sja1105t_info;
......
...@@ -70,8 +70,7 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv) ...@@ -70,8 +70,7 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv)
/* Keep standard IFG of 12 bytes on egress. */ /* Keep standard IFG of 12 bytes on egress. */
.ifg = 0, .ifg = 0,
/* Always put the MAC speed in automatic mode, where it can be /* Always put the MAC speed in automatic mode, where it can be
* retrieved from the PHY object through phylib and * adjusted at runtime by PHYLINK.
* sja1105_adjust_port_config.
*/ */
.speed = SJA1105_SPEED_AUTO, .speed = SJA1105_SPEED_AUTO,
/* No static correction for 1-step 1588 events */ /* No static correction for 1-step 1588 events */
...@@ -116,7 +115,6 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv) ...@@ -116,7 +115,6 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv)
if (!table->entries) if (!table->entries)
return -ENOMEM; return -ENOMEM;
/* Override table based on phylib DT bindings */
table->entry_count = SJA1105_NUM_PORTS; table->entry_count = SJA1105_NUM_PORTS;
mac = table->entries; mac = table->entries;
...@@ -157,7 +155,7 @@ static int sja1105_init_mii_settings(struct sja1105_private *priv, ...@@ -157,7 +155,7 @@ static int sja1105_init_mii_settings(struct sja1105_private *priv,
if (!table->entries) if (!table->entries)
return -ENOMEM; return -ENOMEM;
/* Override table based on phylib DT bindings */ /* Override table based on PHYLINK DT bindings */
table->entry_count = SJA1105_MAX_XMII_PARAMS_COUNT; table->entry_count = SJA1105_MAX_XMII_PARAMS_COUNT;
mii = table->entries; mii = table->entries;
...@@ -689,26 +687,18 @@ static int sja1105_parse_dt(struct sja1105_private *priv, ...@@ -689,26 +687,18 @@ static int sja1105_parse_dt(struct sja1105_private *priv,
return rc; return rc;
} }
/* Convert back and forth MAC speed from Mbps to SJA1105 encoding */ /* Convert link speed from SJA1105 to ethtool encoding */
static int sja1105_speed[] = { static int sja1105_speed[] = {
[SJA1105_SPEED_AUTO] = 0, [SJA1105_SPEED_AUTO] = SPEED_UNKNOWN,
[SJA1105_SPEED_10MBPS] = 10, [SJA1105_SPEED_10MBPS] = SPEED_10,
[SJA1105_SPEED_100MBPS] = 100, [SJA1105_SPEED_100MBPS] = SPEED_100,
[SJA1105_SPEED_1000MBPS] = 1000, [SJA1105_SPEED_1000MBPS] = SPEED_1000,
}; };
/* Set link speed and enable/disable traffic I/O in the MAC configuration /* Set link speed in the MAC configuration for a specific port. */
* for a specific port.
*
* @speed_mbps: If 0, leave the speed unchanged, else adapt MAC to PHY speed.
* @enabled: Manage Rx and Tx settings for this port. If false, overrides the
* settings from the STP state, but not persistently (does not
* overwrite the static MAC info for this port).
*/
static int sja1105_adjust_port_config(struct sja1105_private *priv, int port, static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
int speed_mbps, bool enabled) int speed_mbps)
{ {
struct sja1105_mac_config_entry dyn_mac;
struct sja1105_xmii_params_entry *mii; struct sja1105_xmii_params_entry *mii;
struct sja1105_mac_config_entry *mac; struct sja1105_mac_config_entry *mac;
struct device *dev = priv->ds->dev; struct device *dev = priv->ds->dev;
...@@ -716,21 +706,27 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port, ...@@ -716,21 +706,27 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
sja1105_speed_t speed; sja1105_speed_t speed;
int rc; int rc;
mii = priv->static_config.tables[BLK_IDX_XMII_PARAMS].entries; /* On P/Q/R/S, one can read from the device via the MAC reconfiguration
* tables. On E/T, MAC reconfig tables are not readable, only writable.
* We have to *know* what the MAC looks like. For the sake of keeping
* the code common, we'll use the static configuration tables as a
* reasonable approximation for both E/T and P/Q/R/S.
*/
mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries; mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;
mii = priv->static_config.tables[BLK_IDX_XMII_PARAMS].entries;
switch (speed_mbps) { switch (speed_mbps) {
case 0: case SPEED_UNKNOWN:
/* No speed update requested */ /* No speed update requested */
speed = SJA1105_SPEED_AUTO; speed = SJA1105_SPEED_AUTO;
break; break;
case 10: case SPEED_10:
speed = SJA1105_SPEED_10MBPS; speed = SJA1105_SPEED_10MBPS;
break; break;
case 100: case SPEED_100:
speed = SJA1105_SPEED_100MBPS; speed = SJA1105_SPEED_100MBPS;
break; break;
case 1000: case SPEED_1000:
speed = SJA1105_SPEED_1000MBPS; speed = SJA1105_SPEED_1000MBPS;
break; break;
default: default:
...@@ -738,26 +734,16 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port, ...@@ -738,26 +734,16 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
return -EINVAL; return -EINVAL;
} }
/* If requested, overwrite SJA1105_SPEED_AUTO from the static MAC /* Overwrite SJA1105_SPEED_AUTO from the static MAC configuration
* configuration table, since this will be used for the clocking setup, * table, since this will be used for the clocking setup, and we no
* and we no longer need to store it in the static config (already told * longer need to store it in the static config (already told hardware
* hardware we want auto during upload phase). * we want auto during upload phase).
*/ */
mac[port].speed = speed; mac[port].speed = speed;
/* On P/Q/R/S, one can read from the device via the MAC reconfiguration
* tables. On E/T, MAC reconfig tables are not readable, only writable.
* We have to *know* what the MAC looks like. For the sake of keeping
* the code common, we'll use the static configuration tables as a
* reasonable approximation for both E/T and P/Q/R/S.
*/
dyn_mac = mac[port];
dyn_mac.ingress = enabled && mac[port].ingress;
dyn_mac.egress = enabled && mac[port].egress;
/* Write to the dynamic reconfiguration tables */ /* Write to the dynamic reconfiguration tables */
rc = sja1105_dynamic_config_write(priv, BLK_IDX_MAC_CONFIG, rc = sja1105_dynamic_config_write(priv, BLK_IDX_MAC_CONFIG, port,
port, &dyn_mac, true); &mac[port], true);
if (rc < 0) { if (rc < 0) {
dev_err(dev, "Failed to write MAC config: %d\n", rc); dev_err(dev, "Failed to write MAC config: %d\n", rc);
return rc; return rc;
...@@ -769,9 +755,6 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port, ...@@ -769,9 +755,6 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
* the clock setup does interrupt the clock signal for a certain time * the clock setup does interrupt the clock signal for a certain time
* which causes trouble for all PHYs relying on this signal. * which causes trouble for all PHYs relying on this signal.
*/ */
if (!enabled)
return 0;
phy_mode = mii->xmii_mode[port]; phy_mode = mii->xmii_mode[port];
if (phy_mode != XMII_MODE_RGMII) if (phy_mode != XMII_MODE_RGMII)
return 0; return 0;
...@@ -786,9 +769,24 @@ static void sja1105_mac_config(struct dsa_switch *ds, int port, ...@@ -786,9 +769,24 @@ static void sja1105_mac_config(struct dsa_switch *ds, int port,
struct sja1105_private *priv = ds->priv; struct sja1105_private *priv = ds->priv;
if (!state->link) if (!state->link)
sja1105_adjust_port_config(priv, port, 0, false); return;
else
sja1105_adjust_port_config(priv, port, state->speed, true); sja1105_adjust_port_config(priv, port, state->speed);
}
static void sja1105_mac_link_down(struct dsa_switch *ds, int port,
unsigned int mode,
phy_interface_t interface)
{
sja1105_inhibit_tx(ds->priv, BIT(port), true);
}
static void sja1105_mac_link_up(struct dsa_switch *ds, int port,
unsigned int mode,
phy_interface_t interface,
struct phy_device *phydev)
{
sja1105_inhibit_tx(ds->priv, BIT(port), false);
} }
static void sja1105_phylink_validate(struct dsa_switch *ds, int port, static void sja1105_phylink_validate(struct dsa_switch *ds, int port,
...@@ -1243,27 +1241,6 @@ static void sja1105_bridge_leave(struct dsa_switch *ds, int port, ...@@ -1243,27 +1241,6 @@ static void sja1105_bridge_leave(struct dsa_switch *ds, int port,
sja1105_bridge_member(ds, port, br, false); sja1105_bridge_member(ds, port, br, false);
} }
static u8 sja1105_stp_state_get(struct sja1105_private *priv, int port)
{
struct sja1105_mac_config_entry *mac;
mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;
if (!mac[port].ingress && !mac[port].egress && !mac[port].dyn_learn)
return BR_STATE_BLOCKING;
if (mac[port].ingress && !mac[port].egress && !mac[port].dyn_learn)
return BR_STATE_LISTENING;
if (mac[port].ingress && !mac[port].egress && mac[port].dyn_learn)
return BR_STATE_LEARNING;
if (mac[port].ingress && mac[port].egress && mac[port].dyn_learn)
return BR_STATE_FORWARDING;
/* This is really an error condition if the MAC was in none of the STP
* states above. But treating the port as disabled does nothing, which
* is adequate, and it also resets the MAC to a known state later on.
*/
return BR_STATE_DISABLED;
}
/* For situations where we need to change a setting at runtime that is only /* For situations where we need to change a setting at runtime that is only
* available through the static configuration, resetting the switch in order * available through the static configuration, resetting the switch in order
* to upload the new static config is unavoidable. Back up the settings we * to upload the new static config is unavoidable. Back up the settings we
...@@ -1274,27 +1251,18 @@ static int sja1105_static_config_reload(struct sja1105_private *priv) ...@@ -1274,27 +1251,18 @@ static int sja1105_static_config_reload(struct sja1105_private *priv)
{ {
struct sja1105_mac_config_entry *mac; struct sja1105_mac_config_entry *mac;
int speed_mbps[SJA1105_NUM_PORTS]; int speed_mbps[SJA1105_NUM_PORTS];
u8 stp_state[SJA1105_NUM_PORTS];
int rc, i; int rc, i;
mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries; mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;
/* Back up settings changed by sja1105_adjust_port_config and /* Back up the dynamic link speed changed by sja1105_adjust_port_config
* sja1105_bridge_stp_state_set and restore their defaults. * in order to temporarily restore it to SJA1105_SPEED_AUTO - which the
* switch wants to see in the static config in order to allow us to
* change it through the dynamic interface later.
*/ */
for (i = 0; i < SJA1105_NUM_PORTS; i++) { for (i = 0; i < SJA1105_NUM_PORTS; i++) {
speed_mbps[i] = sja1105_speed[mac[i].speed]; speed_mbps[i] = sja1105_speed[mac[i].speed];
mac[i].speed = SJA1105_SPEED_AUTO; mac[i].speed = SJA1105_SPEED_AUTO;
if (i == dsa_upstream_port(priv->ds, i)) {
mac[i].ingress = true;
mac[i].egress = true;
mac[i].dyn_learn = true;
} else {
stp_state[i] = sja1105_stp_state_get(priv, i);
mac[i].ingress = false;
mac[i].egress = false;
mac[i].dyn_learn = false;
}
} }
/* Reset switch and send updated static configuration */ /* Reset switch and send updated static configuration */
...@@ -1311,13 +1279,7 @@ static int sja1105_static_config_reload(struct sja1105_private *priv) ...@@ -1311,13 +1279,7 @@ static int sja1105_static_config_reload(struct sja1105_private *priv)
goto out; goto out;
for (i = 0; i < SJA1105_NUM_PORTS; i++) { for (i = 0; i < SJA1105_NUM_PORTS; i++) {
bool enabled = (speed_mbps[i] != 0); rc = sja1105_adjust_port_config(priv, i, speed_mbps[i]);
if (i != dsa_upstream_port(priv->ds, i))
sja1105_bridge_stp_state_set(priv->ds, i, stp_state[i]);
rc = sja1105_adjust_port_config(priv, i, speed_mbps[i],
enabled);
if (rc < 0) if (rc < 0)
goto out; goto out;
} }
...@@ -1923,6 +1885,8 @@ static const struct dsa_switch_ops sja1105_switch_ops = { ...@@ -1923,6 +1885,8 @@ static const struct dsa_switch_ops sja1105_switch_ops = {
.set_ageing_time = sja1105_set_ageing_time, .set_ageing_time = sja1105_set_ageing_time,
.phylink_validate = sja1105_phylink_validate, .phylink_validate = sja1105_phylink_validate,
.phylink_mac_config = sja1105_mac_config, .phylink_mac_config = sja1105_mac_config,
.phylink_mac_link_up = sja1105_mac_link_up,
.phylink_mac_link_down = sja1105_mac_link_down,
.get_strings = sja1105_get_strings, .get_strings = sja1105_get_strings,
.get_ethtool_stats = sja1105_get_ethtool_stats, .get_ethtool_stats = sja1105_get_ethtool_stats,
.get_sset_count = sja1105_get_sset_count, .get_sset_count = sja1105_get_sset_count,
......
...@@ -285,20 +285,22 @@ static int sja1105_cold_reset(const struct sja1105_private *priv) ...@@ -285,20 +285,22 @@ static int sja1105_cold_reset(const struct sja1105_private *priv)
return priv->info->reset_cmd(priv, &reset); return priv->info->reset_cmd(priv, &reset);
} }
static int sja1105_inhibit_tx(const struct sja1105_private *priv, int sja1105_inhibit_tx(const struct sja1105_private *priv,
const unsigned long *port_bitmap) unsigned long port_bitmap, bool tx_inhibited)
{ {
const struct sja1105_regs *regs = priv->info->regs; const struct sja1105_regs *regs = priv->info->regs;
u64 inhibit_cmd; u64 inhibit_cmd;
int port, rc; int rc;
rc = sja1105_spi_send_int(priv, SPI_READ, regs->port_control, rc = sja1105_spi_send_int(priv, SPI_READ, regs->port_control,
&inhibit_cmd, SJA1105_SIZE_PORT_CTRL); &inhibit_cmd, SJA1105_SIZE_PORT_CTRL);
if (rc < 0) if (rc < 0)
return rc; return rc;
for_each_set_bit(port, port_bitmap, SJA1105_NUM_PORTS) if (tx_inhibited)
inhibit_cmd |= BIT(port); inhibit_cmd |= port_bitmap;
else
inhibit_cmd &= ~port_bitmap;
return sja1105_spi_send_int(priv, SPI_WRITE, regs->port_control, return sja1105_spi_send_int(priv, SPI_WRITE, regs->port_control,
&inhibit_cmd, SJA1105_SIZE_PORT_CTRL); &inhibit_cmd, SJA1105_SIZE_PORT_CTRL);
...@@ -415,7 +417,7 @@ int sja1105_static_config_upload(struct sja1105_private *priv) ...@@ -415,7 +417,7 @@ int sja1105_static_config_upload(struct sja1105_private *priv)
* Tx on all ports and waiting for current packet to drain. * Tx on all ports and waiting for current packet to drain.
* Otherwise, the PHY will see an unterminated Ethernet packet. * Otherwise, the PHY will see an unterminated Ethernet packet.
*/ */
rc = sja1105_inhibit_tx(priv, &port_bitmap); rc = sja1105_inhibit_tx(priv, port_bitmap, true);
if (rc < 0) { if (rc < 0) {
dev_err(dev, "Failed to inhibit Tx on ports\n"); dev_err(dev, "Failed to inhibit Tx on ports\n");
return -ENXIO; return -ENXIO;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment