Skip to content

Commit

Permalink
Merge branch 'rework-phylink-interface-for-split-MAC-PCS-support'
Browse files Browse the repository at this point in the history
Russell King says:

====================
rework phylink interface for split MAC/PCS support

The following series changes the phylink interface to allow us to
better support split MAC / MAC PCS setups.  The fundamental change
required for this turns out to be quite simple.

Today, mac_config() is used for everything to do with setting the
parameters for the MAC, and mac_link_up() is used to inform the
MAC driver that the link is now up (and so to allow packet flow.)
mac_config() also has had a few implementation issues, with folk
who believe that members such as "speed" and "duplex" are always
valid, where "link" gets used inappropriately, etc.

With the proposed patches, all this changes subtly - but in a
backwards compatible way at this stage.

We pass the the full resolved link state (speed, duplex, pause) to
mac_link_up(), and it is now guaranteed that these parameters to
this function will always be valid (no more SPEED_UNKNOWN or
DUPLEX_UNKNOWN here - unless phylink is fed with such things.)

Drivers should convert over to using the state in mac_link_up()
rather than configuring the speed, duplex and pause in the
mac_config() method. The patch series includes a number of MAC
drivers which I've thought have been easy targets - I've left the
remainder as I think they need maintainer input. However, *all*
drivers will need conversion for future phylink development.

v2: add ocelot/felix and qca/ar9331 DSA drivers to patch 2, add
  received tested-by so far.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Feb 27, 2020
2 parents 2e6af0f + 24cb72d commit 6dd7f1a
Show file tree
Hide file tree
Showing 23 changed files with 358 additions and 180 deletions.
17 changes: 14 additions & 3 deletions Documentation/networking/sfp-phylink.rst
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,13 @@ phylib to the sfp/phylink support. Please send patches to improve
this documentation.

1. Optionally split the network driver's phylib update function into
three parts dealing with link-down, link-up and reconfiguring the
MAC settings. This can be done as a separate preparation commit.
two parts dealing with link-down and link-up. This can be done as
a separate preparation commit.

An example of this preparation can be found in git commit fc548b991fb0.
An older example of this preparation can be found in git commit
fc548b991fb0, although this was splitting into three parts; the
link-up part now includes configuring the MAC for the link settings.
Please see :c:func:`mac_link_up` for more information on this.

2. Replace::

Expand Down Expand Up @@ -207,6 +210,14 @@ this documentation.
using. This is particularly important for in-band negotiation
methods such as 1000base-X and SGMII.

The :c:func:`mac_link_up` method is used to inform the MAC that the
link has come up. The call includes the negotiation mode and interface
for reference only. The finalised link parameters are also supplied
(speed, duplex and flow control/pause enablement settings) which
should be used to configure the MAC when the MAC and PCS are not
tightly integrated, or when the settings are not coming from in-band
negotiation.

The :c:func:`mac_config` method is used to update the MAC with the
requested state, and must avoid unnecessarily taking the link down
when making changes to the MAC configuration. This means the
Expand Down
4 changes: 3 additions & 1 deletion drivers/net/dsa/b53/b53_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -1289,7 +1289,9 @@ EXPORT_SYMBOL(b53_phylink_mac_link_down);
void b53_phylink_mac_link_up(struct dsa_switch *ds, int port,
unsigned int mode,
phy_interface_t interface,
struct phy_device *phydev)
struct phy_device *phydev,
int speed, int duplex,
bool tx_pause, bool rx_pause)
{
struct b53_device *dev = ds->priv;

Expand Down
4 changes: 3 additions & 1 deletion drivers/net/dsa/b53/b53_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,9 @@ void b53_phylink_mac_link_down(struct dsa_switch *ds, int port,
void b53_phylink_mac_link_up(struct dsa_switch *ds, int port,
unsigned int mode,
phy_interface_t interface,
struct phy_device *phydev);
struct phy_device *phydev,
int speed, int duplex,
bool tx_pause, bool rx_pause);
int b53_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering);
int b53_vlan_prepare(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan);
Expand Down
4 changes: 3 additions & 1 deletion drivers/net/dsa/bcm_sf2.c
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,9 @@ static void bcm_sf2_sw_mac_link_down(struct dsa_switch *ds, int port,
static void bcm_sf2_sw_mac_link_up(struct dsa_switch *ds, int port,
unsigned int mode,
phy_interface_t interface,
struct phy_device *phydev)
struct phy_device *phydev,
int speed, int duplex,
bool tx_pause, bool rx_pause)
{
struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
struct ethtool_eee *p = &priv->dev->ports[port].eee;
Expand Down
4 changes: 3 additions & 1 deletion drivers/net/dsa/lantiq_gswip.c
Original file line number Diff line number Diff line change
Expand Up @@ -1517,7 +1517,9 @@ static void gswip_phylink_mac_link_down(struct dsa_switch *ds, int port,
static void gswip_phylink_mac_link_up(struct dsa_switch *ds, int port,
unsigned int mode,
phy_interface_t interface,
struct phy_device *phydev)
struct phy_device *phydev,
int speed, int duplex,
bool tx_pause, bool rx_pause)
{
struct gswip_priv *priv = ds->priv;

Expand Down
4 changes: 3 additions & 1 deletion drivers/net/dsa/mt7530.c
Original file line number Diff line number Diff line change
Expand Up @@ -1482,7 +1482,9 @@ static void mt7530_phylink_mac_link_down(struct dsa_switch *ds, int port,
static void mt7530_phylink_mac_link_up(struct dsa_switch *ds, int port,
unsigned int mode,
phy_interface_t interface,
struct phy_device *phydev)
struct phy_device *phydev,
int speed, int duplex,
bool tx_pause, bool rx_pause)
{
struct mt7530_priv *priv = ds->priv;

Expand Down
79 changes: 62 additions & 17 deletions drivers/net/dsa/mv88e6xxx/chip.c
Original file line number Diff line number Diff line change
Expand Up @@ -632,33 +632,78 @@ static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port,
dev_err(ds->dev, "p%d: failed to configure MAC\n", port);
}

static void mv88e6xxx_mac_link_force(struct dsa_switch *ds, int port, int link)
static void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port,
unsigned int mode,
phy_interface_t interface)
{
struct mv88e6xxx_chip *chip = ds->priv;
int err;
const struct mv88e6xxx_ops *ops;
int err = 0;

mv88e6xxx_reg_lock(chip);
err = chip->info->ops->port_set_link(chip, port, link);
mv88e6xxx_reg_unlock(chip);
ops = chip->info->ops;

if (err)
dev_err(chip->dev, "p%d: failed to force MAC link\n", port);
}
/* Internal PHYs propagate their configuration directly to the MAC.
* External PHYs depend on whether the PPU is enabled for this port.
* FIXME: we should be using the PPU enable state here. What about
* an automedia port?
*/
if (!mv88e6xxx_phy_is_internal(ds, port) && ops->port_set_link) {
mv88e6xxx_reg_lock(chip);
err = ops->port_set_link(chip, port, LINK_FORCED_DOWN);
mv88e6xxx_reg_unlock(chip);

static void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port,
unsigned int mode,
phy_interface_t interface)
{
if (mode == MLO_AN_FIXED)
mv88e6xxx_mac_link_force(ds, port, LINK_FORCED_DOWN);
if (err)
dev_err(chip->dev,
"p%d: failed to force MAC link down\n", port);
}
}

static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port,
unsigned int mode, phy_interface_t interface,
struct phy_device *phydev)
struct phy_device *phydev,
int speed, int duplex,
bool tx_pause, bool rx_pause)
{
if (mode == MLO_AN_FIXED)
mv88e6xxx_mac_link_force(ds, port, LINK_FORCED_UP);
struct mv88e6xxx_chip *chip = ds->priv;
const struct mv88e6xxx_ops *ops;
int err = 0;

ops = chip->info->ops;

/* Internal PHYs propagate their configuration directly to the MAC.
* External PHYs depend on whether the PPU is enabled for this port.
* FIXME: we should be using the PPU enable state here. What about
* an automedia port?
*/
if (!mv88e6xxx_phy_is_internal(ds, port)) {
mv88e6xxx_reg_lock(chip);
/* FIXME: for an automedia port, should we force the link
* down here - what if the link comes up due to "other" media
* while we're bringing the port up, how is the exclusivity
* handled in the Marvell hardware? E.g. port 4 on 88E6532
* shared between internal PHY and Serdes.
*/
if (ops->port_set_speed) {
err = ops->port_set_speed(chip, port, speed);
if (err && err != -EOPNOTSUPP)
goto error;
}

if (ops->port_set_duplex) {
err = ops->port_set_duplex(chip, port, duplex);
if (err && err != -EOPNOTSUPP)
goto error;
}

if (ops->port_set_link)
err = ops->port_set_link(chip, port, LINK_FORCED_UP);
error:
mv88e6xxx_reg_unlock(chip);

if (err && err != -EOPNOTSUPP)
dev_err(ds->dev,
"p%d: failed to configure MAC link up\n", port);
}
}

static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
Expand Down
4 changes: 3 additions & 1 deletion drivers/net/dsa/ocelot/felix.c
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,9 @@ static void felix_phylink_mac_link_down(struct dsa_switch *ds, int port,
static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port,
unsigned int link_an_mode,
phy_interface_t interface,
struct phy_device *phydev)
struct phy_device *phydev,
int speed, int duplex,
bool tx_pause, bool rx_pause)
{
struct ocelot *ocelot = ds->priv;
struct ocelot_port *ocelot_port = ocelot->ports[port];
Expand Down
4 changes: 3 additions & 1 deletion drivers/net/dsa/qca/ar9331.c
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,9 @@ static void ar9331_sw_phylink_mac_link_down(struct dsa_switch *ds, int port,
static void ar9331_sw_phylink_mac_link_up(struct dsa_switch *ds, int port,
unsigned int mode,
phy_interface_t interface,
struct phy_device *phydev)
struct phy_device *phydev,
int speed, int duplex,
bool tx_pause, bool rx_pause)
{
struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv;
struct regmap *regmap = priv->regmap;
Expand Down
4 changes: 3 additions & 1 deletion drivers/net/dsa/sja1105/sja1105_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -786,7 +786,9 @@ static void sja1105_mac_link_down(struct dsa_switch *ds, int port,
static void sja1105_mac_link_up(struct dsa_switch *ds, int port,
unsigned int mode,
phy_interface_t interface,
struct phy_device *phydev)
struct phy_device *phydev,
int speed, int duplex,
bool tx_pause, bool rx_pause)
{
sja1105_inhibit_tx(ds->priv, BIT(port), false);
}
Expand Down
1 change: 0 additions & 1 deletion drivers/net/ethernet/cadence/macb.h
Original file line number Diff line number Diff line change
Expand Up @@ -1200,7 +1200,6 @@ struct macb {
unsigned int dma_burst_length;

phy_interface_t phy_interface;
int speed;

/* AT91RM9200 transmit */
struct sk_buff *skb; /* holds skb until xmit interrupt completes */
Expand Down
57 changes: 34 additions & 23 deletions drivers/net/ethernet/cadence/macb_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -571,37 +571,20 @@ static void macb_mac_config(struct phylink_config *config, unsigned int mode,

old_ctrl = ctrl = macb_or_gem_readl(bp, NCFGR);

/* Clear all the bits we might set later */
ctrl &= ~(MACB_BIT(SPD) | MACB_BIT(FD) | MACB_BIT(PAE));

if (bp->caps & MACB_CAPS_MACB_IS_EMAC) {
if (state->interface == PHY_INTERFACE_MODE_RMII)
ctrl |= MACB_BIT(RM9200_RMII);
} else {
ctrl &= ~(GEM_BIT(GBE) | GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL));

/* We do not support MLO_PAUSE_RX yet */
if (state->pause & MLO_PAUSE_TX)
ctrl |= MACB_BIT(PAE);
ctrl &= ~(GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL));

if (state->interface == PHY_INTERFACE_MODE_SGMII)
ctrl |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL);
}

if (state->speed == SPEED_1000)
ctrl |= GEM_BIT(GBE);
else if (state->speed == SPEED_100)
ctrl |= MACB_BIT(SPD);

if (state->duplex)
ctrl |= MACB_BIT(FD);

/* Apply the new configuration, if any */
if (old_ctrl ^ ctrl)
macb_or_gem_writel(bp, NCFGR, ctrl);

bp->speed = state->speed;

spin_unlock_irqrestore(&bp->lock, flags);
}

Expand All @@ -626,16 +609,42 @@ static void macb_mac_link_down(struct phylink_config *config, unsigned int mode,
netif_tx_stop_all_queues(ndev);
}

static void macb_mac_link_up(struct phylink_config *config, unsigned int mode,
phy_interface_t interface, struct phy_device *phy)
static void macb_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 net_device *ndev = to_net_dev(config->dev);
struct macb *bp = netdev_priv(ndev);
struct macb_queue *queue;
unsigned long flags;
unsigned int q;
u32 ctrl;

spin_lock_irqsave(&bp->lock, flags);

ctrl = macb_or_gem_readl(bp, NCFGR);

ctrl &= ~(MACB_BIT(SPD) | MACB_BIT(FD));

if (speed == SPEED_100)
ctrl |= MACB_BIT(SPD);

if (duplex)
ctrl |= MACB_BIT(FD);

if (!(bp->caps & MACB_CAPS_MACB_IS_EMAC)) {
macb_set_tx_clk(bp->tx_clk, bp->speed, ndev);
ctrl &= ~(GEM_BIT(GBE) | MACB_BIT(PAE));

if (speed == SPEED_1000)
ctrl |= GEM_BIT(GBE);

/* We do not support MLO_PAUSE_RX yet */
if (tx_pause)
ctrl |= MACB_BIT(PAE);

macb_set_tx_clk(bp->tx_clk, speed, ndev);

/* Initialize rings & buffers as clearing MACB_BIT(TE) in link down
* cleared the pipeline and control registers.
Expand All @@ -648,6 +657,10 @@ static void macb_mac_link_up(struct phylink_config *config, unsigned int mode,
bp->rx_intr_mask | MACB_TX_INT_FLAGS | MACB_BIT(HRESP));
}

macb_or_gem_writel(bp, NCFGR, ctrl);

spin_unlock_irqrestore(&bp->lock, flags);

/* Enable Rx and Tx */
macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(RE) | MACB_BIT(TE));

Expand Down Expand Up @@ -4429,8 +4442,6 @@ static int macb_probe(struct platform_device *pdev)
else
bp->phy_interface = interface;

bp->speed = SPEED_UNKNOWN;

/* IP specific init */
err = init(pdev);
if (err)
Expand Down
Loading

0 comments on commit 6dd7f1a

Please sign in to comment.