From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-vk1-f182.google.com (mail-vk1-f182.google.com [209.85.221.182]) (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 E881C317148 for ; Sat, 6 Jun 2026 08:30:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.182 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780734607; cv=none; b=q2AJkysxX5PLT7rXh1hx/+kVIrjWQL8llhCQx9Ol0idJDFRYSQaUKlNgOLY3e/ZEAPo85TDhZ5DgyqfaAWZf0GcFLLFmMaWdK6kVeIlaFqnpKqw1yQXImRRV52eCRJbtIoXfvUKZzSRs3/J+4ON+572kd7FMrGqWMmX/hRQ3pXg= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780734607; c=relaxed/simple; bh=mWtqvokkNY0OMKtPyvUg9pSyjnftJ/9lXl/rcD/dICM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=j9/hryL4Vb6UYJxYSAj4s+cWYGLYLSXvVH60hxpCuk5KV3QxQd03uskCUYc5An0UtKunXoc9mxK2yi1RMyLprGi3+z04LFDOHRtT9+YVMOXZq8h/UxFEMzx/mIjCWr34IfOA74xP3+IdHa67SXK555+Ws64LKd318U5rmne+9go= 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=PdHKMJFy; arc=none smtp.client-ip=209.85.221.182 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="PdHKMJFy" Received: by mail-vk1-f182.google.com with SMTP id 71dfb90a1353d-59d6e44e5c8so2092611e0c.2 for ; Sat, 06 Jun 2026 01:30:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1780734604; x=1781339404; 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=+HeBzSN7Bi1btALPQSDlRLmfvwWO13MW01wePrMLTlc=; b=PdHKMJFyto62xqvsflwjRKVf1m8w+ws9+9xepWp3HnAJWuFcXxkBTu3/J7PKobqJiw rdfesohyRONN1fZaPtqINJgFAaskvkEHH/luNJM1moG5QHkvu5dXNpfg8I2z0Ly5u4JJ /zN0rRFQHb709PYWPHerYJKpMP2vEl5BL+bpaTLOZ5XZL/3qV7m3D6vR0kg9HfhZDXNC B/xRHJ4od1dkMxO/crfuPrxTzmFx/GxxbNI32AtRKM1++Plw/O0ts/zFnVQbmDnQpzhC +f04p9a1WuEhHHssm6MJTDL3QK//uoscg5TM3scOXDqOGRu92qZ6YSMdHkW8a6XDne9N Xadw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780734604; x=1781339404; 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=+HeBzSN7Bi1btALPQSDlRLmfvwWO13MW01wePrMLTlc=; b=ev+lRUtiW1paezDWTTnU19qb+P1rzpgPwqPxzF//Ue88daD/zHZe8g20tdbb7Eounw e2nGkNv7Z8hEbAYBzz97AEh3ihdARl1jOBNzXXJhKc9o7gModGji7alHUmaACU0550cM vSHpeNLvThoE36v7PYL1b+KfHl1Cmn8hHnqBanSR0nPXNqp+8fqj1rpGYQogQYp1DBfZ GPiAVuOh+SB374ZNPOVy2yehZW6fMWsB/7Jb6quw7tvQ12Px8/ubAu8f5jTc7aR62orD CYmbewosc4p1A9keC3+xWVJSQrila4WAS7KC3iWGCqfwV+G6HDfyLrQxPjZsomsVT+Xg VHng== X-Forwarded-Encrypted: i=1; AFNElJ/p5qMbLZ7l4mXoadqel4b6DglbIAwiJIL3RQVSSnYbAMXmkaUMrAjTZX55hR0U6ieTL40Or4ASqWv/xks=@vger.kernel.org X-Gm-Message-State: AOJu0YwXiefCQrn/RyT5pnKoQSv3zXlqD2nN5zRwhAlzcCMa5CxpjgFJ Vkeh2qekIkuvTBhTgq47qc/Y4rxbHAsW84j/tldmF9cAx+wnxcQe2lnr X-Gm-Gg: Acq92OFkcsUQh73cidE99UoDDaycz9KR54ZbhZ8MtCT9q0PpbbSM6DxQRmoLrTvDsH7 dpxQXCuoVLpa2fs1o8fpoPWW7RfmrRNQvkx8H1Su7ndBuqLtT4k3VAnIFWFCg+V8S8/tUbQ6TnA 22ibzqei4apu24ti3E81bKR4PnoBhNnvEbK/h335CqyzBQ/Qc588m8wdz1T3kvQ0Gfe7OyrpqgB 4uLUmFU2vd1IT1bW7vdileaABncEGJDje1onpkiSoWLqMJcO3PAeLE8tcG55jF4NaV0QmZWHooB K9eJKy9G2Xn1yBZPvSFxLdRkslryMkh12cCo7sfp7SUJRL1mkNfWyqTPRoGuLIn8xjiGbXXw2Gr 3yKBiwpGhx/2qTyrI1+dCMaqxJt2ko3xUjmWcyT1iSCbpiZaTLH5bL+SOhDjgiBII1GiOr1ota5 UBpAPXUmPdBn35WJAt4qSToq4mGFIg7fb+7bcKZuMKIXPjexQRjw== X-Received: by 2002:a05:6122:4f98:b0:56b:1eb:d396 with SMTP id 71dfb90a1353d-5ac5214ea81mr3559042e0c.14.1780734603792; Sat, 06 Jun 2026 01:30:03 -0700 (PDT) Received: from tresc054937.tre-sc.gov.br ([187.65.210.13]) by smtp.gmail.com with ESMTPSA id 71dfb90a1353d-5a6dc44d233sm9630281e0c.10.2026.06.06.01.29.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 06 Jun 2026 01:30:03 -0700 (PDT) From: Luiz Angelo Daros de Luca Date: Sat, 06 Jun 2026 05:29:27 -0300 Subject: [net-next PATCH v13 3/9] 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: <20260606-realtek_forward-v13-3-b9e409687cbe@gmail.com> References: <20260606-realtek_forward-v13-0-b9e409687cbe@gmail.com> In-Reply-To: <20260606-realtek_forward-v13-0-b9e409687cbe@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. As part of this refactoring, unused ports are explicitly placed into a blocked, isolated state with learning disabled, ensuring safe default hardware behavior. The driver also does not allocate a virtual IRQ mapping for unused ports. To accommodate this, a guard check is added to the interrupt handler (rtl8365mb_irq) to safely skip ports without a valid IRQ mapping. The irq domain teardown, however, does clean all ports as external PHYs may still map the IRQ. Furthermore, since the new initialization loop starts with all ports administratively isolated by default, CPU port forwarding and isolation masks are explicitly configured at the end of the setup phase to prevent egress traffic from being blocked. 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 | 166 +++++++++++++++++++++++------------- 1 file changed, 105 insertions(+), 61 deletions(-) diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/rtl8365mb.c index 37e1d7654b1d..14fee2a3001b 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); } @@ -1667,10 +1664,14 @@ static struct irq_chip rtl8365mb_irq_chip = { static int rtl8365mb_irq_map(struct irq_domain *domain, unsigned int irq, irq_hw_number_t hwirq) { - irq_set_chip_data(irq, domain->host_data); + struct realtek_priv *priv = domain->host_data; + struct rtl8365mb *mb = priv->chip_data; + + irq_set_chip_data(irq, priv); irq_set_chip_and_handler(irq, &rtl8365mb_irq_chip, handle_simple_irq); irq_set_nested_thread(irq, 1); irq_set_noprobe(irq); + irq_set_parent(irq, mb->irq); return 0; } @@ -1709,13 +1710,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) { @@ -1736,6 +1738,9 @@ static int rtl8365mb_irq_setup(struct realtek_priv *priv) goto out_put_node; } + /* Store the irq so that we know to map and free it during teardown */ + mb->irq = irq; + priv->irqdomain = irq_domain_create_linear(of_fwnode_handle(intc), priv->num_ports, &rtl8365mb_irqdomain_ops, priv); if (!priv->irqdomain) { @@ -1744,8 +1749,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"); @@ -1799,9 +1804,6 @@ static int rtl8365mb_irq_setup(struct realtek_priv *priv) goto out_remove_irqdomain; } - /* Store the irq so that we know to free it during teardown */ - mb->irq = irq; - ret = rtl8365mb_irq_enable(priv); if (ret) goto out_free_irq; @@ -1812,18 +1814,20 @@ static int rtl8365mb_irq_setup(struct realtek_priv *priv) out_free_irq: free_irq(mb->irq, 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_port(dp, ds) { + virq = irq_find_mapping(priv->irqdomain, dp->index); + + if (virq) + irq_dispose_mapping(virq); } irq_domain_remove(priv->irqdomain); priv->irqdomain = NULL; out_put_node: + mb->irq = 0; of_node_put(intc); return ret; @@ -1832,8 +1836,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 +1846,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 +1972,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,67 +2003,99 @@ static int rtl8365mb_setup(struct dsa_switch *ds) else if (ret) dev_info(priv->dev, "no interrupt support\n"); - for (i = 0; i < priv->num_ports; i++) { + dsa_switch_for_each_port(dp, ds) { /* 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. */ - if (dsa_is_dsa_port(ds, i)) { + if (dsa_port_is_dsa(dp)) { dev_err(priv->dev, "Cascading (DSA link) not supported\n"); ret = -EOPNOTSUPP; goto out_teardown_irq; } } - /* 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 (cpu->trap_port == RTL8365MB_MAX_NUM_PORTS) - cpu->trap_port = cpu_dp->index; - } - cpu->enable = cpu->mask > 0; + /* 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); - if (!cpu->enable) { - dev_err(priv->dev, "no CPU port defined\n"); - ret = -EINVAL; - goto out_teardown_irq; - } + /* Start with all port completely isolated */ + ret = rtl8365mb_port_set_isolation(priv, dp->index, 0); + if (ret) + goto out_teardown_irq; - ret = rtl8365mb_cpu_config(priv); - if (ret) - goto out_teardown_irq; + /* Disable learning */ + ret = rtl8365mb_port_set_learning(priv, dp->index, false); + if (ret) + goto out_teardown_irq; - /* Configure ports */ - for (i = 0; i < priv->num_ports; i++) { - struct rtl8365mb_port *p = &mb->ports[i]; + /* Set up per-port private data */ + p->priv = priv; + p->index = dp->index; + + /* 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); + } - if (dsa_is_unused_port(ds, i)) + /* 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 CPU 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