net: dsa: microchip: move phylink_mac_ops to individual drivers

Similar to ksz_dev_ops, struct phylink_mac_ops shouldn't be part of
the common code. Instead, the common code should provide callable
functionality.

Invert the paradigm and export the common aspects from ksz_common.c, and
move the chip-specific stuff in individual drivers.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Bastien Curutchet (Schneider Electric) <bastien.curutchet@bootlin.com>
Link: https://patch.msgid.link/20260505-clean-ksz-driver-v1-5-05d70fa42461@bootlin.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Vladimir Oltean 2026-05-05 16:25:05 +02:00 committed by Jakub Kicinski
parent 0e3e45d330
commit 617bd10450
8 changed files with 196 additions and 194 deletions

View File

@ -1870,10 +1870,12 @@ static void ksz8_cpu_port_link_up(struct ksz_device *dev, int speed, int duplex,
SW_10_MBIT, ctrl);
}
void ksz8_phylink_mac_link_up(struct phylink_config *config,
struct phy_device *phydev, unsigned int mode,
phy_interface_t interface, int speed, int duplex,
bool tx_pause, bool rx_pause)
static void ksz8_phylink_mac_link_up(struct phylink_config *config,
struct phy_device *phydev,
unsigned int mode,
phy_interface_t interface,
int speed, int duplex,
bool tx_pause, bool rx_pause)
{
struct dsa_port *dp = dsa_phylink_to_port(config);
struct ksz_device *dev = dp->ds->priv;
@ -2097,6 +2099,32 @@ static void ksz8_switch_exit(struct ksz_device *dev)
ksz8_reset_switch(dev);
}
static void ksz88x3_phylink_mac_config(struct phylink_config *config,
unsigned int mode,
const struct phylink_link_state *state)
{
struct dsa_port *dp = dsa_phylink_to_port(config);
struct ksz_device *dev = dp->ds->priv;
dev->ports[dp->index].manual_flow = !(state->pause & MLO_PAUSE_AN);
}
const struct phylink_mac_ops ksz88x3_phylink_mac_ops = {
.mac_config = ksz88x3_phylink_mac_config,
.mac_link_down = ksz_phylink_mac_link_down,
.mac_link_up = ksz8_phylink_mac_link_up,
.mac_disable_tx_lpi = ksz_phylink_mac_disable_tx_lpi,
.mac_enable_tx_lpi = ksz_phylink_mac_enable_tx_lpi,
};
const struct phylink_mac_ops ksz8_phylink_mac_ops = {
.mac_config = ksz_phylink_mac_config,
.mac_link_down = ksz_phylink_mac_link_down,
.mac_link_up = ksz8_phylink_mac_link_up,
.mac_disable_tx_lpi = ksz_phylink_mac_disable_tx_lpi,
.mac_enable_tx_lpi = ksz_phylink_mac_enable_tx_lpi,
};
const struct ksz_dev_ops ksz8463_dev_ops = {
.setup = ksz8_setup,
.get_port_addr = ksz8463_get_port_addr,

View File

@ -12,13 +12,10 @@
#include <net/dsa.h>
#include "ksz_common.h"
void ksz8_phylink_mac_link_up(struct phylink_config *config,
struct phy_device *phydev, unsigned int mode,
phy_interface_t interface, int speed, int duplex,
bool tx_pause, bool rx_pause);
extern const struct ksz_dev_ops ksz8463_dev_ops;
extern const struct ksz_dev_ops ksz87xx_dev_ops;
extern const struct ksz_dev_ops ksz88xx_dev_ops;
extern const struct phylink_mac_ops ksz88x3_phylink_mac_ops;
extern const struct phylink_mac_ops ksz8_phylink_mac_ops;
#endif

View File

@ -1609,6 +1609,132 @@ static void ksz9477_switch_exit(struct ksz_device *dev)
ksz9477_reset_switch(dev);
}
static void ksz9477_set_gbit(struct ksz_device *dev, int port, bool gbit)
{
const u8 *bitval = dev->info->xmii_ctrl1;
const u16 *regs = dev->info->regs;
u8 data8;
ksz_pread8(dev, port, regs[P_XMII_CTRL_1], &data8);
data8 &= ~P_GMII_1GBIT_M;
if (gbit)
data8 |= FIELD_PREP(P_GMII_1GBIT_M, bitval[P_GMII_1GBIT]);
else
data8 |= FIELD_PREP(P_GMII_1GBIT_M, bitval[P_GMII_NOT_1GBIT]);
/* Write the updated value */
ksz_pwrite8(dev, port, regs[P_XMII_CTRL_1], data8);
}
static void ksz9477_set_100_10mbit(struct ksz_device *dev, int port, int speed)
{
const u8 *bitval = dev->info->xmii_ctrl0;
const u16 *regs = dev->info->regs;
u8 data8;
ksz_pread8(dev, port, regs[P_XMII_CTRL_0], &data8);
data8 &= ~P_MII_100MBIT_M;
if (speed == SPEED_100)
data8 |= FIELD_PREP(P_MII_100MBIT_M, bitval[P_MII_100MBIT]);
else
data8 |= FIELD_PREP(P_MII_100MBIT_M, bitval[P_MII_10MBIT]);
/* Write the updated value */
ksz_pwrite8(dev, port, regs[P_XMII_CTRL_0], data8);
}
static void ksz9477_port_set_xmii_speed(struct ksz_device *dev, int port,
int speed)
{
if (speed == SPEED_1000)
ksz9477_set_gbit(dev, port, true);
else
ksz9477_set_gbit(dev, port, false);
if (speed == SPEED_100 || speed == SPEED_10)
ksz9477_set_100_10mbit(dev, port, speed);
}
static void ksz9477_duplex_flowctrl(struct ksz_device *dev, int port, int duplex,
bool tx_pause, bool rx_pause)
{
const u8 *bitval = dev->info->xmii_ctrl0;
const u32 *masks = dev->info->masks;
const u16 *regs = dev->info->regs;
u8 mask;
u8 val;
mask = P_MII_DUPLEX_M | masks[P_MII_TX_FLOW_CTRL] |
masks[P_MII_RX_FLOW_CTRL];
if (duplex == DUPLEX_FULL)
val = FIELD_PREP(P_MII_DUPLEX_M, bitval[P_MII_FULL_DUPLEX]);
else
val = FIELD_PREP(P_MII_DUPLEX_M, bitval[P_MII_HALF_DUPLEX]);
if (tx_pause)
val |= masks[P_MII_TX_FLOW_CTRL];
if (rx_pause)
val |= masks[P_MII_RX_FLOW_CTRL];
ksz_prmw8(dev, port, regs[P_XMII_CTRL_0], mask, val);
}
void ksz9477_phylink_mac_link_up(struct phylink_config *config,
struct phy_device *phydev,
unsigned int mode,
phy_interface_t interface,
int speed, int duplex, bool tx_pause,
bool rx_pause)
{
struct dsa_port *dp = dsa_phylink_to_port(config);
struct ksz_device *dev = dp->ds->priv;
int port = dp->index;
struct ksz_port *p;
p = &dev->ports[port];
/* Internal PHYs */
if (dev->info->internal_phy[port])
return;
p->speed = speed;
ksz9477_port_set_xmii_speed(dev, port, speed);
ksz9477_duplex_flowctrl(dev, port, duplex, tx_pause, rx_pause);
}
static struct phylink_pcs *
ksz9477_phylink_mac_select_pcs(struct phylink_config *config,
phy_interface_t interface)
{
struct dsa_port *dp = dsa_phylink_to_port(config);
struct ksz_device *dev = dp->ds->priv;
struct ksz_port *p = &dev->ports[dp->index];
if (ksz_is_sgmii_port(dev, dp->index) &&
(interface == PHY_INTERFACE_MODE_SGMII ||
interface == PHY_INTERFACE_MODE_1000BASEX))
return p->pcs;
return NULL;
}
const struct phylink_mac_ops ksz9477_phylink_mac_ops = {
.mac_config = ksz_phylink_mac_config,
.mac_link_down = ksz_phylink_mac_link_down,
.mac_link_up = ksz9477_phylink_mac_link_up,
.mac_disable_tx_lpi = ksz_phylink_mac_disable_tx_lpi,
.mac_enable_tx_lpi = ksz_phylink_mac_enable_tx_lpi,
.mac_select_pcs = ksz9477_phylink_mac_select_pcs,
};
const struct ksz_dev_ops ksz9477_dev_ops = {
.setup = ksz9477_setup,
.get_port_addr = ksz9477_get_port_addr,

View File

@ -84,6 +84,14 @@ void ksz9477_acl_match_process_l2(struct ksz_device *dev, int port,
u16 ethtype, u8 *src_mac, u8 *dst_mac,
unsigned long cookie, u32 prio);
void ksz9477_phylink_mac_link_up(struct phylink_config *config,
struct phy_device *phydev,
unsigned int mode,
phy_interface_t interface,
int speed, int duplex, bool tx_pause,
bool rx_pause);
extern const struct ksz_dev_ops ksz9477_dev_ops;
extern const struct phylink_mac_ops ksz9477_phylink_mac_ops;
#endif

View File

@ -256,16 +256,6 @@ static const struct ksz_drive_strength ksz88x3_drive_strengths[] = {
{ KSZ8873_DRIVE_STRENGTH_16MA, 16000 },
};
static void ksz88x3_phylink_mac_config(struct phylink_config *config,
unsigned int mode,
const struct phylink_link_state *state);
static void ksz_phylink_mac_config(struct phylink_config *config,
unsigned int mode,
const struct phylink_link_state *state);
static void ksz_phylink_mac_link_down(struct phylink_config *config,
unsigned int mode,
phy_interface_t interface);
/**
* ksz_phylink_mac_disable_tx_lpi() - Callback to signal LPI support (Dummy)
* @config: phylink config structure
@ -273,7 +263,7 @@ static void ksz_phylink_mac_link_down(struct phylink_config *config,
* This function is a dummy handler. See ksz_phylink_mac_enable_tx_lpi() for
* a detailed explanation of EEE/LPI handling in KSZ switches.
*/
static void ksz_phylink_mac_disable_tx_lpi(struct phylink_config *config)
void ksz_phylink_mac_disable_tx_lpi(struct phylink_config *config)
{
}
@ -310,68 +300,12 @@ static void ksz_phylink_mac_disable_tx_lpi(struct phylink_config *config)
*
* Returns: 0 (Always success)
*/
static int ksz_phylink_mac_enable_tx_lpi(struct phylink_config *config,
u32 timer, bool tx_clock_stop)
int ksz_phylink_mac_enable_tx_lpi(struct phylink_config *config,
u32 timer, bool tx_clock_stop)
{
return 0;
}
static const struct phylink_mac_ops ksz88x3_phylink_mac_ops = {
.mac_config = ksz88x3_phylink_mac_config,
.mac_link_down = ksz_phylink_mac_link_down,
.mac_link_up = ksz8_phylink_mac_link_up,
.mac_disable_tx_lpi = ksz_phylink_mac_disable_tx_lpi,
.mac_enable_tx_lpi = ksz_phylink_mac_enable_tx_lpi,
};
static const struct phylink_mac_ops ksz8_phylink_mac_ops = {
.mac_config = ksz_phylink_mac_config,
.mac_link_down = ksz_phylink_mac_link_down,
.mac_link_up = ksz8_phylink_mac_link_up,
.mac_disable_tx_lpi = ksz_phylink_mac_disable_tx_lpi,
.mac_enable_tx_lpi = ksz_phylink_mac_enable_tx_lpi,
};
static void ksz9477_phylink_mac_link_up(struct phylink_config *config,
struct phy_device *phydev,
unsigned int mode,
phy_interface_t interface,
int speed, int duplex, bool tx_pause,
bool rx_pause);
static struct phylink_pcs *
ksz_phylink_mac_select_pcs(struct phylink_config *config,
phy_interface_t interface)
{
struct dsa_port *dp = dsa_phylink_to_port(config);
struct ksz_device *dev = dp->ds->priv;
struct ksz_port *p = &dev->ports[dp->index];
if (ksz_is_sgmii_port(dev, dp->index) &&
(interface == PHY_INTERFACE_MODE_SGMII ||
interface == PHY_INTERFACE_MODE_1000BASEX))
return p->pcs;
return NULL;
}
static const struct phylink_mac_ops ksz9477_phylink_mac_ops = {
.mac_config = ksz_phylink_mac_config,
.mac_link_down = ksz_phylink_mac_link_down,
.mac_link_up = ksz9477_phylink_mac_link_up,
.mac_disable_tx_lpi = ksz_phylink_mac_disable_tx_lpi,
.mac_enable_tx_lpi = ksz_phylink_mac_enable_tx_lpi,
.mac_select_pcs = ksz_phylink_mac_select_pcs,
};
static const struct phylink_mac_ops lan937x_phylink_mac_ops = {
.mac_config = ksz_phylink_mac_config,
.mac_link_down = ksz_phylink_mac_link_down,
.mac_link_up = ksz9477_phylink_mac_link_up,
.mac_disable_tx_lpi = ksz_phylink_mac_disable_tx_lpi,
.mac_enable_tx_lpi = ksz_phylink_mac_enable_tx_lpi,
};
static const u16 ksz8463_regs[] = {
[REG_SW_MAC_ADDR] = 0x10,
[REG_IND_CTRL_0] = 0x30,
@ -3068,9 +3002,9 @@ static u32 ksz_get_phy_flags(struct dsa_switch *ds, int port)
return 0;
}
static void ksz_phylink_mac_link_down(struct phylink_config *config,
unsigned int mode,
phy_interface_t interface)
void ksz_phylink_mac_link_down(struct phylink_config *config,
unsigned int mode,
phy_interface_t interface)
{
struct dsa_port *dp = dsa_phylink_to_port(config);
struct ksz_device *dev = dp->ds->priv;
@ -3657,19 +3591,9 @@ phy_interface_t ksz_get_xmii(struct ksz_device *dev, int port, bool gbit)
return interface;
}
static void ksz88x3_phylink_mac_config(struct phylink_config *config,
unsigned int mode,
const struct phylink_link_state *state)
{
struct dsa_port *dp = dsa_phylink_to_port(config);
struct ksz_device *dev = dp->ds->priv;
dev->ports[dp->index].manual_flow = !(state->pause & MLO_PAUSE_AN);
}
static void ksz_phylink_mac_config(struct phylink_config *config,
unsigned int mode,
const struct phylink_link_state *state)
void ksz_phylink_mac_config(struct phylink_config *config,
unsigned int mode,
const struct phylink_link_state *state)
{
struct dsa_port *dp = dsa_phylink_to_port(config);
struct ksz_device *dev = dp->ds->priv;
@ -3712,106 +3636,6 @@ bool ksz_get_gbit(struct ksz_device *dev, int port)
return gbit;
}
static void ksz_set_gbit(struct ksz_device *dev, int port, bool gbit)
{
const u8 *bitval = dev->info->xmii_ctrl1;
const u16 *regs = dev->info->regs;
u8 data8;
ksz_pread8(dev, port, regs[P_XMII_CTRL_1], &data8);
data8 &= ~P_GMII_1GBIT_M;
if (gbit)
data8 |= FIELD_PREP(P_GMII_1GBIT_M, bitval[P_GMII_1GBIT]);
else
data8 |= FIELD_PREP(P_GMII_1GBIT_M, bitval[P_GMII_NOT_1GBIT]);
/* Write the updated value */
ksz_pwrite8(dev, port, regs[P_XMII_CTRL_1], data8);
}
static void ksz_set_100_10mbit(struct ksz_device *dev, int port, int speed)
{
const u8 *bitval = dev->info->xmii_ctrl0;
const u16 *regs = dev->info->regs;
u8 data8;
ksz_pread8(dev, port, regs[P_XMII_CTRL_0], &data8);
data8 &= ~P_MII_100MBIT_M;
if (speed == SPEED_100)
data8 |= FIELD_PREP(P_MII_100MBIT_M, bitval[P_MII_100MBIT]);
else
data8 |= FIELD_PREP(P_MII_100MBIT_M, bitval[P_MII_10MBIT]);
/* Write the updated value */
ksz_pwrite8(dev, port, regs[P_XMII_CTRL_0], data8);
}
static void ksz_port_set_xmii_speed(struct ksz_device *dev, int port, int speed)
{
if (speed == SPEED_1000)
ksz_set_gbit(dev, port, true);
else
ksz_set_gbit(dev, port, false);
if (speed == SPEED_100 || speed == SPEED_10)
ksz_set_100_10mbit(dev, port, speed);
}
static void ksz_duplex_flowctrl(struct ksz_device *dev, int port, int duplex,
bool tx_pause, bool rx_pause)
{
const u8 *bitval = dev->info->xmii_ctrl0;
const u32 *masks = dev->info->masks;
const u16 *regs = dev->info->regs;
u8 mask;
u8 val;
mask = P_MII_DUPLEX_M | masks[P_MII_TX_FLOW_CTRL] |
masks[P_MII_RX_FLOW_CTRL];
if (duplex == DUPLEX_FULL)
val = FIELD_PREP(P_MII_DUPLEX_M, bitval[P_MII_FULL_DUPLEX]);
else
val = FIELD_PREP(P_MII_DUPLEX_M, bitval[P_MII_HALF_DUPLEX]);
if (tx_pause)
val |= masks[P_MII_TX_FLOW_CTRL];
if (rx_pause)
val |= masks[P_MII_RX_FLOW_CTRL];
ksz_prmw8(dev, port, regs[P_XMII_CTRL_0], mask, val);
}
static void ksz9477_phylink_mac_link_up(struct phylink_config *config,
struct phy_device *phydev,
unsigned int mode,
phy_interface_t interface,
int speed, int duplex, bool tx_pause,
bool rx_pause)
{
struct dsa_port *dp = dsa_phylink_to_port(config);
struct ksz_device *dev = dp->ds->priv;
int port = dp->index;
struct ksz_port *p;
p = &dev->ports[port];
/* Internal PHYs */
if (dev->info->internal_phy[port])
return;
p->speed = speed;
ksz_port_set_xmii_speed(dev, port, speed);
ksz_duplex_flowctrl(dev, port, duplex, tx_pause, rx_pause);
}
static int ksz_switch_detect(struct ksz_device *dev)
{
u8 id1, id2, id4;

View File

@ -479,6 +479,16 @@ void ksz_switch_macaddr_put(struct dsa_switch *ds);
void ksz_switch_shutdown(struct ksz_device *dev);
int ksz_handle_wake_reason(struct ksz_device *dev, int port);
void ksz_phylink_mac_disable_tx_lpi(struct phylink_config *config);
int ksz_phylink_mac_enable_tx_lpi(struct phylink_config *config,
u32 timer, bool tx_clock_stop);
void ksz_phylink_mac_config(struct phylink_config *config,
unsigned int mode,
const struct phylink_link_state *state);
void ksz_phylink_mac_link_down(struct phylink_config *config,
unsigned int mode,
phy_interface_t interface);
/* Common register access functions */
static inline struct regmap *ksz_regmap_8(struct ksz_device *dev)
{

View File

@ -7,5 +7,6 @@
#define __LAN937X_CFG_H
extern const struct ksz_dev_ops lan937x_dev_ops;
extern const struct phylink_mac_ops lan937x_phylink_mac_ops;
#endif

View File

@ -666,6 +666,14 @@ static void lan937x_switch_exit(struct ksz_device *dev)
lan937x_reset_switch(dev);
}
const struct phylink_mac_ops lan937x_phylink_mac_ops = {
.mac_config = ksz_phylink_mac_config,
.mac_link_down = ksz_phylink_mac_link_down,
.mac_link_up = ksz9477_phylink_mac_link_up,
.mac_disable_tx_lpi = ksz_phylink_mac_disable_tx_lpi,
.mac_enable_tx_lpi = ksz_phylink_mac_enable_tx_lpi,
};
const struct ksz_dev_ops lan937x_dev_ops = {
.setup = lan937x_setup,
.teardown = lan937x_teardown,