From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-ua1-f49.google.com (mail-ua1-f49.google.com [209.85.222.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 01A6F372EC0 for ; Mon, 25 May 2026 19:48:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.49 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779738504; cv=none; b=AyoR//EGpEDnnG2VKDFvJCjnOE/MdRePdLcpFUXcTjp9wxePfiXrtp337VMBhA92UAjAO5nMwfpNZgd8uRihz/EoVoLuQ/gVMw9A1yUffnA0N/XJSZNd54beOLP8Ix1dGctkgV+zsXStO5wk/GP/MLC62QG0QE1qN704QtrSoMU= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779738504; c=relaxed/simple; bh=D1wj/JFTaFjBniNMTmZjoOwzM5LCRO5q0kzkuvfbs7g=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ojda5va4DWu90alLF/TrOPEhyykA4XnnK5EqZVB3fD4nP5AlgyO51ovQtP0/MMb7AH3DGS0RqNWc2xzGTz2eZEzJKjhDzwNmo8WmDnfANCK4Ps0Xe5Kjyanem0OniGepwTP7WQOUCHOA8x+3NQwLvUV1IR5BaM6Jz//xcheks80= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=GSIZVTbo; arc=none smtp.client-ip=209.85.222.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="GSIZVTbo" Received: by mail-ua1-f49.google.com with SMTP id a1e0cc1a2514c-960b00874cfso3825313241.0 for ; Mon, 25 May 2026 12:48:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779738500; x=1780343300; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=aYHIcd4bbGqwm2U+v3yuHG+2tAyqIOBeGKeTJonOCew=; b=GSIZVTbokPHOD0b4QdQam4+5BDYcdKIT91NL+fRArPr1glw0NeSD9pBrB7btSLCZmk zsoFuBVM/Nc3B7BzU3pLamno6iLR+daK91apa/qNlIj99kx/gG9aAJeMnHHcbHqX0zz1 eqF5Cn+1bLAVxsFGa1hXkkx8V+YU3BE5YcUZqjVmcLK/RYjgommE5I0dwdFk7+2bbCC5 De3awu8loNUJJ5jZcxHUAx572G+hDJRIzH9GNh/TBsVvcC0KzhSFQKwtm3pWbFP+//ao wq7Jc2D0hPP2dlDAGEEqNLbhbbtEt9BRWoirMwqQ7+VPSPgZQNov36agkWcMdc8Q1whX zWMw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779738500; x=1780343300; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=aYHIcd4bbGqwm2U+v3yuHG+2tAyqIOBeGKeTJonOCew=; b=D6w1q5ygi5LSfrty04FGZxJtJ6vDYsfayhnK4EO9+YXnN2uWvR3zSLMw7rBwDF7b40 ds/Dd+z46XFpANTXulWqcZNyTI+IFLNMb7/xYOoAHX9IHe55jjy++W9G6x7y1FnxYqPC cRngpVCj0RVcBCsql4C2rUmYiT7+LkrLpXFPmBgXw1e5eMXImY+KcigpBvelN+WFNvJO usk6KlWJMGXrV0hlOHHSLVXG4ry0OvBt47THOUfIgS9+JrtoPgeIGSvRy92LRmNpExNM PDF+dn5htem9x5Pxz6FUAGAADWt3JNVHqeQdVb8Ut5+C7ZDATtI//efL7E8QhH/Xr4WM YqJg== X-Forwarded-Encrypted: i=1; AFNElJ8Kz/xYq4QVm93v8Nx9zGC/9HQfwE6OZb9PC4RyzjhEBE4QDNN+uebMJKP3HWOoKk8GvMpgynlTNd2iFS8=@vger.kernel.org X-Gm-Message-State: AOJu0Yy9NHp0/12Mu4zOC+8igPRbjl8eDivBzi7vLLz+q3E1zCBrPWYO s/U3IMZJLDrZ+EodK+5NqGlRjyQN2Hxh3d8TiR1l02RwupHEDU6kEu/8 X-Gm-Gg: Acq92OHuCcnGmx3DlYojuXH7WLBXnaC/4MSKwvgjBYM0SyYh7SJUWCTrb2LP87kMrTm ZXabyi2dUeG5cPIGWvT0zQiPE6Kc64jVnZTA//5U1PNLdDQ6tCadAXzC5ULNaeWYW9LQTGCqDXh XhW2uIuErDFkM0U4xvDZWn5HnKI2RQOSHVsD04iuFgEnJpLQbK7SDvKCVQM+ynfTsQxvCUnjx4+ lCL1QX2JESnnQeMSK1XN+65G1zjD+RK0Cp+5PFUbYAYCgg3lKqmkOlgfPCvAbTg3MxYaWzT9GvR jpHg7HAXExvhZDbShEWByf4dxRxuFodEz1u26lRCxQjLN3EpurzYQhqgJR/xFEOugIeeYdJMbec Z00zTTRBO5kLdjGjfZhghP5y3TjDoibJoaz+sJHTl2KEENhkvS+7MD7lEd4afGgd1mXfkprlVOf tjXrsTWyp9/Dc6HdwCHn/qA9npQC0JKjVNaMoeww== X-Received: by 2002:a05:6102:2b96:b0:631:e729:4579 with SMTP id ada2fe7eead31-67c80b74bddmr8052096137.24.1779738499762; Mon, 25 May 2026 12:48:19 -0700 (PDT) Received: from tresc054937.tre-sc.gov.br ([187.65.210.13]) by smtp.gmail.com with ESMTPSA id a1e0cc1a2514c-96173af3e82sm11092456241.10.2026.05.25.12.48.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 25 May 2026 12:48:19 -0700 (PDT) From: Luiz Angelo Daros de Luca Date: Mon, 25 May 2026 16:47:58 -0300 Subject: [net-next PATCH v8 2/8] net: dsa: realtek: rtl8365mb: use dsa helpers for port iteration Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20260525-realtek_forward-v8-2-5eb80a4675be@gmail.com> References: <20260525-realtek_forward-v8-0-5eb80a4675be@gmail.com> In-Reply-To: <20260525-realtek_forward-v8-0-5eb80a4675be@gmail.com> To: Andrew Lunn , Vladimir Oltean , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Linus Walleij , =?utf-8?q?Alvin_=C5=A0ipraga?= , Yury Norov , Rasmus Villemoes , Russell King Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Abdulkader Alrezej , Mieczyslaw Nalewaj , Luiz Angelo Daros de Luca X-Mailer: b4 0.15.2 Convert open-coded port iteration loops to use the DSA helpers and restructure rtl8365mb_setup() into clear blocking, user, and CPU port phases. This refactoring introduces the following behavioral and defensive changes: - CPU port forwarding/isolation is now explicitly configured. This is necessary to prevent egress traffic from being blocked by the new initialization loop that starts with all ports disabled (reported by Abdulkader Alrezej during series testing). - A guard check is added to the interrupt handler (rtl8365mb_irq) to safely skip ports without a virtual IRQ mapping. Since unused ports no longer receive a virq mapping, this prevents dangerous calls to handle_nested_irq(0) if a link event fires on an unmapped port. - The driver now explicitly returns -EOPNOTSUPP if a DSA cascade link port is detected. This topology is not supported yet and has historically been broken because the absence of a direct CPU port disables CPU tagging entirely, rendering the switch non-functional for DSA. - The rtl8365mb_setup() function now explicitly enforces the presence of a CPU port, returning -EINVAL if none are found. Suggested-by: Abdulkader Alrezej Reviewed-by: Linus Walleij Reviewed-by: Mieczyslaw Nalewaj Signed-off-by: Luiz Angelo Daros de Luca --- drivers/net/dsa/realtek/rtl8365mb.c | 158 +++++++++++++++++++++++++----------- 1 file changed, 109 insertions(+), 49 deletions(-) diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/rtl8365mb.c index 2637884fe472..27746b0694c9 100644 --- a/drivers/net/dsa/realtek/rtl8365mb.c +++ b/drivers/net/dsa/realtek/rtl8365mb.c @@ -1554,18 +1554,15 @@ static void rtl8365mb_stats_setup(struct realtek_priv *priv) { struct rtl8365mb *mb = priv->chip_data; struct dsa_switch *ds = &priv->ds; - int i; + struct dsa_port *dp; /* Per-chip global mutex to protect MIB counter access, since doing * so requires accessing a series of registers in a particular order. */ mutex_init(&mb->mib_lock); - for (i = 0; i < priv->num_ports; i++) { - struct rtl8365mb_port *p = &mb->ports[i]; - - if (dsa_is_unused_port(ds, i)) - continue; + dsa_switch_for_each_available_port(dp, ds) { + struct rtl8365mb_port *p = &mb->ports[dp->index]; /* Per-port spinlock to protect the stats64 data */ spin_lock_init(&p->stats_lock); @@ -1581,13 +1578,10 @@ static void rtl8365mb_stats_teardown(struct realtek_priv *priv) { struct rtl8365mb *mb = priv->chip_data; struct dsa_switch *ds = &priv->ds; - int i; - - for (i = 0; i < priv->num_ports; i++) { - struct rtl8365mb_port *p = &mb->ports[i]; + struct dsa_port *dp; - if (dsa_is_unused_port(ds, i)) - continue; + dsa_switch_for_each_available_port(dp, ds) { + struct rtl8365mb_port *p = &mb->ports[dp->index]; cancel_delayed_work_sync(&p->mib_work); } @@ -1646,6 +1640,9 @@ static irqreturn_t rtl8365mb_irq(int irq, void *data) for_each_set_bit(line, &line_changes, priv->num_ports) { int child_irq = irq_find_mapping(priv->irqdomain, line); + if (!child_irq) + continue; + handle_nested_irq(child_irq); } @@ -1709,13 +1706,14 @@ static int rtl8365mb_irq_disable(struct realtek_priv *priv) static int rtl8365mb_irq_setup(struct realtek_priv *priv) { struct rtl8365mb *mb = priv->chip_data; + struct dsa_switch *ds = &priv->ds; struct device_node *intc; + struct dsa_port *dp; u32 irq_trig; int virq; int irq; u32 val; int ret; - int i; intc = of_get_child_by_name(priv->dev->of_node, "interrupt-controller"); if (!intc) { @@ -1744,8 +1742,8 @@ static int rtl8365mb_irq_setup(struct realtek_priv *priv) goto out_put_node; } - for (i = 0; i < priv->num_ports; i++) { - virq = irq_create_mapping(priv->irqdomain, i); + dsa_switch_for_each_available_port(dp, ds) { + virq = irq_create_mapping(priv->irqdomain, dp->index); if (!virq) { dev_err(priv->dev, "failed to create irq domain mapping\n"); @@ -1815,9 +1813,11 @@ static int rtl8365mb_irq_setup(struct realtek_priv *priv) mb->irq = 0; out_remove_irqdomain: - for (i = 0; i < priv->num_ports; i++) { - virq = irq_find_mapping(priv->irqdomain, i); - irq_dispose_mapping(virq); + dsa_switch_for_each_available_port(dp, ds) { + virq = irq_find_mapping(priv->irqdomain, dp->index); + + if (virq) + irq_dispose_mapping(virq); } irq_domain_remove(priv->irqdomain); @@ -1832,8 +1832,9 @@ static int rtl8365mb_irq_setup(struct realtek_priv *priv) static void rtl8365mb_irq_teardown(struct realtek_priv *priv) { struct rtl8365mb *mb = priv->chip_data; + struct dsa_switch *ds = &priv->ds; + struct dsa_port *dp; int virq; - int i; if (mb->irq) { free_irq(mb->irq, priv); @@ -1841,9 +1842,15 @@ static void rtl8365mb_irq_teardown(struct realtek_priv *priv) } if (priv->irqdomain) { - for (i = 0; i < priv->num_ports; i++) { - virq = irq_find_mapping(priv->irqdomain, i); - irq_dispose_mapping(virq); + /* Unused ports with a linked PHY still have an active IRQ + * mapping that must be disposed of during teardown. Loop + * through all ports. + */ + dsa_switch_for_each_port(dp, ds) { + virq = irq_find_mapping(priv->irqdomain, dp->index); + + if (virq) + irq_dispose_mapping(virq); } irq_domain_remove(priv->irqdomain); @@ -1961,10 +1968,11 @@ static int rtl8365mb_setup(struct dsa_switch *ds) { struct realtek_priv *priv = ds->priv; struct rtl8365mb_cpu *cpu; - struct dsa_port *cpu_dp; + u32 downports_mask = 0; + u32 upports_mask = 0; struct rtl8365mb *mb; + struct dsa_port *dp; int ret; - int i; mb = priv->chip_data; cpu = &mb->cpu; @@ -1991,46 +1999,98 @@ static int rtl8365mb_setup(struct dsa_switch *ds) else if (ret) dev_info(priv->dev, "no interrupt support\n"); - /* Configure CPU tagging */ - dsa_switch_for_each_cpu_port(cpu_dp, ds) { - cpu->mask |= BIT(cpu_dp->index); + /* Start with all ports blocked, including unused ports */ + dsa_switch_for_each_port(dp, ds) { + struct rtl8365mb_port *p = &mb->ports[dp->index]; + + if (dsa_port_is_dsa(dp)) { + /* Cascading (DSA links) is not supported yet. + * Historically, the driver has always been broken + * without a dedicated CPU port because CPU tagging + * would be disabled, rendering the switch entirely + * non-functional for DSA operations. + */ + dev_err(ds->dev, + "Cascading (DSA link) not supported\n"); + ret = -EOPNOTSUPP; + goto out_teardown_irq; + } - if (cpu->trap_port == RTL8365MB_MAX_NUM_PORTS) - cpu->trap_port = cpu_dp->index; - } - cpu->enable = cpu->mask > 0; - ret = rtl8365mb_cpu_config(priv); - if (ret) - goto out_teardown_irq; + /* Set the initial STP state of all ports to DISABLED, otherwise + * ports will still forward frames to the CPU despite being + * administratively down by default. + */ + rtl8365mb_port_stp_state_set(ds, dp->index, BR_STATE_DISABLED); - /* Configure ports */ - for (i = 0; i < priv->num_ports; i++) { - struct rtl8365mb_port *p = &mb->ports[i]; + /* Start with all port completely isolated */ + ret = rtl8365mb_port_set_isolation(priv, dp->index, 0); + if (ret) + goto out_teardown_irq; + + /* Disable learning */ + ret = rtl8365mb_port_set_learning(priv, dp->index, false); + if (ret) + goto out_teardown_irq; + + /* Set up per-port private data */ + p->priv = priv; + p->index = dp->index; - if (dsa_is_unused_port(ds, i)) + /* Collect CPU ports. If we support cascade switches, it should + * also include the upstream DSA ports. + */ + if (!dsa_port_is_cpu(dp)) + continue; + + upports_mask |= BIT(dp->index); + } + + /* Configure user ports */ + dsa_switch_for_each_port(dp, ds) { + if (!dsa_port_is_user(dp)) continue; /* Forward only to the CPU */ - ret = rtl8365mb_port_set_isolation(priv, i, cpu->mask); + ret = rtl8365mb_port_set_isolation(priv, dp->index, + upports_mask); if (ret) goto out_teardown_irq; - /* Disable learning */ - ret = rtl8365mb_port_set_learning(priv, i, false); + /* If we support cascade switches, it should also include the + * downstream DSA ports. + */ + downports_mask |= BIT(dp->index); + } + + /* Configure CPU tagging */ + /* If we support cascade switches, it should also include the upstream + * DSA ports. + */ + dsa_switch_for_each_cpu_port(dp, ds) { + /* Use the first CPU port as trap_port */ + if (cpu->trap_port == RTL8365MB_MAX_NUM_PORTS) + cpu->trap_port = dp->index; + + /* Forward to all user ports */ + ret = rtl8365mb_port_set_isolation(priv, dp->index, + downports_mask); if (ret) goto out_teardown_irq; + } - /* Set the initial STP state of all ports to DISABLED, otherwise - * ports will still forward frames to the CPU despite being - * administratively down by default. - */ - rtl8365mb_port_stp_state_set(ds, i, BR_STATE_DISABLED); + cpu->mask = upports_mask; + cpu->enable = cpu->mask > 0; - /* Set up per-port private data */ - p->priv = priv; - p->index = i; + if (!cpu->enable) { + dev_err(priv->dev, "no upstream (CPU, Link) port defined\n"); + ret = -EINVAL; + goto out_teardown_irq; } + ret = rtl8365mb_cpu_config(priv); + if (ret) + goto out_teardown_irq; + ret = rtl8365mb_port_change_mtu(ds, cpu->trap_port, ETH_DATA_LEN); if (ret) goto out_teardown_irq; -- 2.54.0