realtek: dsa: consolidate switch_irq()
Some checks are pending
Build Kernel / Build all affected Kernels (push) Waiting to run
Build all core packages / Build all core packages for selected target (push) Waiting to run
Build and Push prebuilt tools container / Build and Push all prebuilt containers (push) Waiting to run
Build host tools / Build host tools for linux and macos based systems (push) Waiting to run

The dsa irq handler works always in the same way for all SoCs.

- Read register ISR_PORT_LINK_STS_CHG to determine the ports that
  triggered the irq.
- Write the read value back to the register to confirm the irq
- Read link status via MAC_LINK_STS
- Trigger dsa_port_phylink_mac_change() for each changed port

Currently each SoC has its own implementation. Drop that in
favour of a generic implementation that makes use of the existing
bit register read/write helpers.

Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Link: https://github.com/openwrt/openwrt/pull/22273
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
This commit is contained in:
Markus Stockhausen 2026-03-04 19:16:23 +01:00 committed by Hauke Mehrtens
parent 42fcfe535c
commit 056176cde1
6 changed files with 23 additions and 125 deletions

View file

@ -1532,6 +1532,27 @@ static int rtl83xx_fib_event(struct notifier_block *this, unsigned long event, v
return NOTIFY_DONE;
}
static irqreturn_t rtldsa_switch_irq(int irq, void *dev_id)
{
struct rtl838x_switch_priv *priv;
struct dsa_switch *ds = dev_id;
u64 link, ports;
priv = ds->priv;
ports = priv->r->get_port_reg_le(priv->r->isr_port_link_sts_chg);
priv->r->set_port_reg_le(ports, priv->r->isr_port_link_sts_chg);
/* read latched */
link = priv->r->get_port_reg_le(priv->r->mac_link_sts);
link = priv->r->get_port_reg_le(priv->r->mac_link_sts);
for (int port = 0; port < priv->cpu_port; port++)
if (ports & BIT_ULL(port))
dsa_port_phylink_mac_change(ds, port, link & BIT_ULL(port));
return IRQ_HANDLED;
}
/*
* TODO: This check is usually built into the DSA initialization functions. After carving
* out the mdio driver from the ethernet driver, there are two drivers that must be loaded
@ -1699,24 +1720,8 @@ static int rtl83xx_sw_probe(struct platform_device *pdev)
priv->link_state_irq = platform_get_irq(pdev, 0);
pr_info("LINK state irq: %d\n", priv->link_state_irq);
switch (priv->family_id) {
case RTL8380_FAMILY_ID:
err = request_irq(priv->link_state_irq, rtl838x_switch_irq,
IRQF_SHARED, "rtl838x-link-state", priv->ds);
break;
case RTL8390_FAMILY_ID:
err = request_irq(priv->link_state_irq, rtl839x_switch_irq,
IRQF_SHARED, "rtl839x-link-state", priv->ds);
break;
case RTL9300_FAMILY_ID:
err = request_irq(priv->link_state_irq, rtldsa_930x_switch_irq,
IRQF_SHARED, "rtl930x-link-state", priv->ds);
break;
case RTL9310_FAMILY_ID:
err = request_irq(priv->link_state_irq, rtl931x_switch_irq,
IRQF_SHARED, "rtl931x-link-state", priv->ds);
break;
}
err = request_irq(priv->link_state_irq, rtldsa_switch_irq,
IRQF_SHARED, "rtldsa-link-state", priv->ds);
if (err) {
dev_err(dev, "Error setting up switch interrupt.\n");
/* Need to free allocated switch here */

View file

@ -1898,27 +1898,3 @@ const struct rtldsa_config rtldsa_838x_cfg = {
.lag_set_port_members = rtldsa_838x_lag_set_port_members,
.lag_setup_algomask = rtldsa_83xx_lag_setup_algomask,
};
irqreturn_t rtl838x_switch_irq(int irq, void *dev_id)
{
struct dsa_switch *ds = dev_id;
u32 status = sw_r32(RTL838X_ISR_GLB_SRC);
u32 ports = sw_r32(RTL838X_ISR_PORT_LINK_STS_CHG);
u32 link;
/* Clear status */
sw_w32(ports, RTL838X_ISR_PORT_LINK_STS_CHG);
pr_debug("RTL8380 Link change: status: %x, ports %x\n", status, ports);
for (int i = 0; i < 28; i++) {
if (ports & BIT(i)) {
link = sw_r32(RTL838X_MAC_LINK_STS);
if (link & BIT(i))
dsa_port_phylink_mac_change(ds, i, true);
else
dsa_port_phylink_mac_change(ds, i, false);
}
}
return IRQ_HANDLED;
}

View file

@ -708,30 +708,6 @@ static void rtl839x_set_static_move_action(int port, bool forward)
RTL839X_L2_PORT_STATIC_MV_ACT(port));
}
irqreturn_t rtl839x_switch_irq(int irq, void *dev_id)
{
struct dsa_switch *ds = dev_id;
u32 status = sw_r32(RTL839X_ISR_GLB_SRC);
u64 ports = rtl839x_get_port_reg_le(RTL839X_ISR_PORT_LINK_STS_CHG);
u64 link;
/* Clear status */
rtl839x_set_port_reg_le(ports, RTL839X_ISR_PORT_LINK_STS_CHG);
pr_debug("RTL8390 Link change: status: %x, ports %llx\n", status, ports);
for (int i = 0; i < RTL839X_CPU_PORT; i++) {
if (ports & BIT_ULL(i)) {
link = rtl839x_get_port_reg_le(RTL839X_MAC_LINK_STS);
if (link & BIT_ULL(i))
dsa_port_phylink_mac_change(ds, i, true);
else
dsa_port_phylink_mac_change(ds, i, false);
}
}
return IRQ_HANDLED;
}
static void
rtldsa_839x_vlan_profile_dump(struct rtl838x_switch_priv *priv, int idx)
{

View file

@ -159,23 +159,18 @@ int rtl838x_set_egress_rate(struct rtl838x_switch_priv *priv, int port, u32 rate
/* RTL838x-specific */
u32 rtl838x_hash(struct rtl838x_switch_priv *priv, u64 seed);
irqreturn_t rtl838x_switch_irq(int irq, void *dev_id);
void rtldsa_838x_print_matrix(void);
/* RTL839x-specific */
u32 rtl839x_hash(struct rtl838x_switch_priv *priv, u64 seed);
irqreturn_t rtl839x_switch_irq(int irq, void *dev_id);
void rtl839x_exec_tbl2_cmd(u32 cmd);
void rtldsa_839x_print_matrix(void);
/* RTL930x-specific */
u32 rtl930x_hash(struct rtl838x_switch_priv *priv, u64 seed);
irqreturn_t rtldsa_930x_switch_irq(int irq, void *dev_id);
irqreturn_t rtl839x_switch_irq(int irq, void *dev_id);
void rtldsa_930x_print_matrix(void);
/* RTL931x-specific */
irqreturn_t rtl931x_switch_irq(int irq, void *dev_id);
void rtldsa_931x_print_matrix(void);
int rtl83xx_lag_add(struct dsa_switch *ds, int group, int port, struct netdev_lag_upper_info *info);

View file

@ -1112,29 +1112,6 @@ void rtl9300_dump_debug(void)
);
}
irqreturn_t rtldsa_930x_switch_irq(int irq, void *dev_id)
{
struct dsa_switch *ds = dev_id;
struct rtl838x_switch_priv *priv = ds->priv;
unsigned long ports = sw_r32(RTL930X_ISR_PORT_LINK_STS_CHG);
unsigned int i;
u32 link;
/* Clear status */
sw_w32(ports, RTL930X_ISR_PORT_LINK_STS_CHG);
/* Read the register twice because of issues with latency at least
* with the external RTL8226 PHY on the XGS1210
*/
link = sw_r32(RTL930X_MAC_LINK_STS);
link = sw_r32(RTL930X_MAC_LINK_STS);
for_each_set_bit(i, &ports, priv->cpu_port)
dsa_port_phylink_mac_change(ds, i, link & BIT(i));
return IRQ_HANDLED;
}
/* Calculate both the block 0 and the block 1 hash, and return in
* lower and higher word of the return value since only 12 bit of
* the hash are significant

View file

@ -462,37 +462,6 @@ static int rtldsa_931x_port_rate_police_del(struct dsa_switch *ds, int port,
return 0;
}
irqreturn_t rtl931x_switch_irq(int irq, void *dev_id)
{
struct dsa_switch *ds = dev_id;
u32 status = sw_r32(RTL931X_ISR_GLB_SRC);
u64 ports = rtl839x_get_port_reg_le(RTL931X_ISR_PORT_LINK_STS_CHG);
u64 link;
/* Clear status */
rtl839x_set_port_reg_le(ports, RTL931X_ISR_PORT_LINK_STS_CHG);
pr_debug("RTL931X Link change: status: %x, ports %016llx\n", status, ports);
link = rtl839x_get_port_reg_le(RTL931X_MAC_LINK_STS);
/* Must re-read this to get correct status */
link = rtl839x_get_port_reg_le(RTL931X_MAC_LINK_STS);
pr_debug("RTL931X Link change: status: %x, link status %016llx\n", status, link);
for (int i = 0; i < 56; i++) {
if (ports & BIT_ULL(i)) {
if (link & BIT_ULL(i)) {
pr_debug("%s port %d up\n", __func__, i);
dsa_port_phylink_mac_change(ds, i, true);
} else {
pr_debug("%s port %d down\n", __func__, i);
dsa_port_phylink_mac_change(ds, i, false);
}
}
}
return IRQ_HANDLED;
}
void rtldsa_931x_print_matrix(void)
{
struct table_reg *r = rtl_table_get(RTL9310_TBL_2, 1);