* Re: [PATCH] xfrm: clear mode callbacks after failed mode setup
From: Steffen Klassert @ 2026-07-07 6:32 UTC (permalink / raw)
To: Cen Zhang
Cc: Herbert Xu, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Christian Hopps, netdev, linux-kernel,
baijiaju1990
In-Reply-To: <CAFRLqsXvrfWE4MWVic+en7KGs6UuxwjDot2ygt2cWH2TCUgmBg@mail.gmail.com>
On Tue, Jul 07, 2026 at 10:32:13AM +0800, Cen Zhang wrote:
> Hi all,
>
> Sorry for the noise, but I wanted to gently follow up on this patch in
> case it got buried.
>
> I would really appreciate any feedback when you have a chance. Please
> let me know if I should make any changes or provide more testing
> results.
It is not forgotten, I had it in my testing branch until now.
This is now applied to the ipsec tree, thanks a lot!
^ permalink raw reply
* Re: [PATCH v2] xfrm: iptfs: propagate SKBFL_SHARED_FRAG in iptfs_skb_add_frags()
From: Steffen Klassert @ 2026-07-07 6:33 UTC (permalink / raw)
To: Chen YanJun; +Cc: herbert, davem, netdev, moomichen
In-Reply-To: <20260701033152.29222-1-635381823cyj@gmail.com>
On Wed, Jul 01, 2026 at 11:31:52AM +0800, Chen YanJun wrote:
> From: Chen YanJun <moomichen@tencent.com>
>
> When iptfs_skb_add_frags() copies frag references from the source
> frag walk into a new SKB, it increments the page reference count via
> __skb_frag_ref() but does not propagate SKBFL_SHARED_FRAG to the
> destination SKB's skb_shinfo->flags.
>
> If the source SKB carries shared frags (e.g. from a page-pool backed
> receive path), the new inner SKB will appear to ESP as having privately
> owned frags. A subsequent esp_input() call for a nested transport-mode
> SA then takes the no-COW fast path and decrypts in place, writing over
> pages that are still referenced by the outer IPTFS SKB. This causes
> kernel-visible memory corruption and can trigger a panic.
>
> All other frag-transfer helpers in the kernel (skb_try_coalesce,
> skb_gro_receive, __pskb_copy_fclone, skb_shift, skb_segment) correctly
> propagate SKBFL_SHARED_FRAG; align iptfs_skb_add_frags() with this
> convention by setting the flag inside the loop immediately after
> __skb_frag_ref() and nr_frags++, so every exit path that attaches a frag
> unconditionally propagates SKBFL_SHARED_FRAG.
>
> Fixes: 5f2b6a909574 ("xfrm: iptfs: add skb-fragment sharing code")
> Signed-off-by: Chen YanJun <moomichen@tencent.com>
Applied, thanks Chen!
^ permalink raw reply
* Re: [PATCH ipsec] xfrm6: clear dst.dev on error to avoid double netdev_put in xfrm6_fill_dst()
From: Steffen Klassert @ 2026-07-07 6:34 UTC (permalink / raw)
To: Xiang Mei (Microsoft)
Cc: Herbert Xu, David S . Miller, netdev, Simon Horman, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, AutonomousCodeSecurity, tgopinath,
kys
In-Reply-To: <20260702010516.221830-1-xmei5@asu.edu>
On Thu, Jul 02, 2026 at 01:05:16AM +0000, Xiang Mei (Microsoft) wrote:
> On the error path where in6_dev_get(dev) returns NULL, xfrm6_fill_dst()
> releases the device reference with netdev_put() but leaves
> xdst->u.dst.dev set. dst_destroy() later calls netdev_put(dst->dev)
> again, so the same net_device reference is released twice, underflowing
> its refcount (ref_tracker WARNING + "unregister_netdevice: waiting for
> <dev> to become free").
>
> Clear xdst->u.dst.dev after the netdev_put(), the same way the XFRM
> device-offload paths xfrm_dev_state_add() and xfrm_dev_policy_add() in
> net/xfrm/xfrm_device.c NULL ->dev when releasing the reference on error.
>
> ref_tracker: reference already released.
> ref_tracker: allocated in:
> xfrm6_fill_dst (net/ipv6/xfrm6_policy.c:86)
> ...
> udpv6_sendmsg (net/ipv6/udp.c:1696)
> ...
> ref_tracker: freed in:
> xfrm6_fill_dst (net/ipv6/xfrm6_policy.c:90)
> ...
> WARNING: lib/ref_tracker.c:322 at ref_tracker_free+0x58b/0x780
> dst_destroy (net/core/dst.c:115)
> rcu_core
> handle_softirqs
> ...
>
> Fixes: 84c4a9dfbf43 ("xfrm6: release dev before returning error")
> Reported-by: AutonomousCodeSecurity@microsoft.com
> Signed-off-by: Xiang Mei (Microsoft) <xmei5@asu.edu>
Applied, thanks a lot!
^ permalink raw reply
* Re: [PATCH ipsec v2] xfrm: policy: preallocate inexact bins before xfrm_hash_rebuild reinsert
From: Steffen Klassert @ 2026-07-07 6:35 UTC (permalink / raw)
To: Florian Westphal
Cc: Xiang Mei (Microsoft), herbert, davem, netdev, horms, edumazet,
kuba, pabeni, AutonomousCodeSecurity, tgopinath, kys
In-Reply-To: <akdM501yK5_mk1th@strlen.de>
On Fri, Jul 03, 2026 at 07:47:19AM +0200, Florian Westphal wrote:
> Xiang Mei (Microsoft) <xmei5@asu.edu> wrote:
> > xfrm_hash_rebuild()'s first loop preallocates the bins/chains the reinsert
> > loop needs, so the reinsert (after hlist_del_rcu()) cannot allocate or
> > fail. But its guard is inverted: it skips policies with prefixlen <
> > threshold and preallocates for the rest.
> >
> > prefixlen < threshold is exactly when policy_hash_bysel() returns NULL and
> > the reinsert takes the allocating xfrm_policy_inexact_insert() path. So the
> > loop preallocates for the exact policies (which never allocate) and skips
> > the inexact ones, whose bin/node is then allocated GFP_ATOMIC during
> > reinsert. On failure the error path only WARN_ONCE()s and continues,
> > leaving a poisoned bydst node; the next rebuild's hlist_del_rcu()
> > dereferences LIST_POISON2 and takes a GPF. Reachable under memory pressure,
> > deterministic via failslab.
> >
> > Invert the guard so preallocation covers exactly the reinserted policies;
> > the reinsert then allocates nothing and cannot fail.
> >
> > Crash:
> > Oops: general protection fault, probably for non-canonical address
> > 0xfbd59c0000000024: 0000 [#1] SMP KASAN NOPTI
> > KASAN: maybe wild-memory-access in range [0xdead...]
> > ...
> > Workqueue: events xfrm_hash_rebuild
> > RIP: 0010:xfrm_hash_rebuild+0x5b3/0x1190
> > RAX: dead000000000122 (LIST_POISON2 + offset)
> > ...
> > Call Trace:
> > hlist_del_rcu (include/linux/rculist.h:599)
> > xfrm_hash_rebuild (net/xfrm/xfrm_policy.c:1365)
> > process_one_work (kernel/workqueue.c:3322)
> > worker_thread (kernel/workqueue.c:3486)
> > kthread (kernel/kthread.c:436)
> > ret_from_fork (arch/x86/kernel/process.c:158)
> > ret_from_fork_asm (arch/x86/entry/entry_64.S:245)
> > ...
> > Kernel panic - not syncing: Fatal exception in interrupt
> >
> > Fixes: 24969facd704 ("xfrm: policy: store inexact policies in an rhashtable")
> > Reported-by: AutonomousCodeSecurity@microsoft.com
> > Signed-off-by: Xiang Mei (Microsoft) <xmei5@asu.edu>
>
> Reviewed-by: Florian Westphal <fw@strlen.de>
Applied, thanks everyone!
^ permalink raw reply
* [PATCH net-next v10 0/4] net: stmmac: eic7700: add eth1 variant support and update delay bindings
From: lizhi2 @ 2026-07-07 6:40 UTC (permalink / raw)
To: devicetree, andrew+netdev, davem, edumazet, kuba, robh, krzk+dt,
conor+dt, netdev, pabeni, mcoquelin.stm32, alexandre.torgue,
rmk+kernel, linux-stm32, linux-arm-kernel, linux-kernel,
maxime.chevallier
Cc: ningyu, linmin, pinkesh.vaghela, pritesh.patel, weishangjuan,
horms, Zhi Li
From: Zhi Li <lizhi2@eswincomputing.com>
This series updates Ethernet support for the ESWIN EIC7700 SoC,
including support for the eth1 MAC variant.
The series includes DT binding updates and stmmac glue driver updates
for the EIC7700 Ethernet controller.
The changes include:
- Update the tx-internal-delay-ps binding property from a fixed enum
list to a range-based definition, and make it optional with the
corresponding driver update.
- Add support for the EIC7700 eth1 MAC variant, which has
silicon-specific RX sampling behavior and TX timing characteristics.
A dedicated compatible string is introduced for this hardware variant,
and the driver applies the required RX clock inversion handling and
timing adjustments.
Due to silicon characteristics, the eth1 interface has a fixed TX
internal delay of approximately 2 ns and an RX sampling skew of 4-5 ns
that cannot be compensated solely by standard RGMII delay settings.
The binding models the effective TX delay range of this variant, while
the driver handles the required hardware-specific timing configuration.
Only the DT bindings and driver patches are included in this series. The
DTS changes are intentionally omitted for the following reasons:
- The HSP bus infrastructure is being introduced by Pinkesh Vaghela's
DT series [0], currently under review.
- The HSPCRG clock/reset series [1] provides additional infrastructure
for the HSP subsystem.
Once these dependencies are merged, a follow-up DT series will enable
Ethernet, USB, eMMC, and SD across the HSP bus.
Reference:
[0] https://lore.kernel.org/lkml/20260706081055.1126275-1-pinkesh.vaghela@einfochips.com/
[1] https://lore.kernel.org/all/20260605060730.1605-1-dongxuyang@eswincomputing.com/
v9 -> v10:
- Drop the DTS patches (patches 5 and 6 in v9) from this series.
- Update the cover letter to include a description of the series.
- Add Conor Dooley's Acked-by tag.
- Link to v9:
https://lore.kernel.org/lkml/20260630063123.1118-1-lizhi2@eswincomputing.com/
v8 -> v9:
- patch2:
- Update DT binding schema for tx-internal-delay-ps:
- Replace the previous oneOf schema with a base range plus
allOf/if-then conditional constraints.
- Define a common range of 0-4540 ps and apply compatible-specific
constraints using conditional schema rules:
- eswin,eic7700-qos-eth:
maximum 2540 ps
- eswin,eic7700-qos-eth-clk-inversion:
minimum 2000 ps
- patch6:
- Refine DTS implementation to address Sashiko review comments:
- Address DTC and dtbs_check warnings.
- Improve node naming and HSP bus organization.
- patch5 and patch6:
- Update commit messages for the DTS patches:
- Clarify that the DTS patches are included only to provide an
overview of the complete Ethernet integration for review.
- The upstream DTS enablement will be submitted as a separate series
after the DT bindings and driver changes have been applied.
- Link to v8:
https://lore.kernel.org/lkml/20260610012727.848-1-lizhi2@eswincomputing.com/
v7 -> v8:
- eth0-related fixes were moved into separate series [1], [2]:
- All eth0-related fixes have been removed from this series to avoid mixing
MAC variants and RX timing logic in a single review context.
- Reference:
[1]https://lore.kernel.org/lkml/20260602014528.2076-1-lizhi2@eswincomputing.com/
[2]https://lore.kernel.org/lkml/20260518021919.404-1-lizhi2@eswincomputing.com/
- Update cover letter and overall series scope description:
- Replace previous wording "EIC7700 eth1 RX sampling timing fix"
with a more accurate description:
- Add eth1 MAC variant support.
- Update RGMII delay binding model.
- This reflects the structural nature of the series rather than a pure
bug fix.
- Split DT bindings changes into two patches:
- patch1:
- Relax RGMII internal delay constraints.
- Change rx/tx internal delay from enum-based model to range-based
model.
- Mark delay properties as optional.
- patch2:
- Introduce EIC7700 eth1 MAC variant compatible string
"eswin,eic7700-qos-eth-clk-inversion".
- Model silicon-specific RX clock inversion requirement via SoC
variant instead of board-level properties.
- Due to this restructuring:
- Patch structure and commit messages have changed significantly
compared to v7.
- The previously received Acked-by from Conor Dooley is not
carried forward because the binding patches were substantially
reworked and split.
- Split driver changes into two patches. No functional changes to eth1
compared to v7:
- patch 3:
- Make rx-internal-delay-ps and tx-internal-delay-ps optional.
- Remove mandatory DT property requirement in probe path.
- Allow zero-delay default when properties are absent.
- patch 4:
- Add support for eth1 MAC variant using compatible-specific
match data.
- Introduce RX clock inversion handling for eth1 at runtime.
- Apply speed-dependent configuration via fix_mac_speed()
callback.
- Note:
- These patches (5/6 and 6/6) are included only to facilitate review
of the overall Ethernet integration across bindings, driver, and
device tree.
A cleaned-up, upstream-ready DTS series will be submitted separately
once all dependencies and final hardware integration are completed.
- Link to v7:
https://lore.kernel.org/lkml/20260427072353.1114-1-lizhi2@eswincomputing.com/
v6 -> v7:
- Address checkpatch.pl --strict warnings for DTS changes:
- Split DT binding documentation and DTS board description into separate patches
- Fix DTS style issues reported by checkpatch:
- Reduce line length where applicable
- Add required description for rgmii-rxid
- DTS changes in this series are split into:
- Patch 3/4: syscon binding update (documentation / reference only)
- Patch 4/4: board DTS changes (architecture overview only)
These patches (3/4 and 4/4) are provided to facilitate review of the overall
Ethernet integration across binding, driver, and device tree, and are not
intended as final upstream submission in their current form.
A cleaned-up, upstream-ready DTS series will be submitted separately once
all dependencies and final hardware integration are completed.
- Note:
- Clock-related bindings referenced in earlier revisions are now already merged
into net-next, so dtbs_check warnings related to clock are no longer present
and are not relevant to this revision.
- No functional changes in the stmmac driver or binding semantics in this revision.
- Link to v6:
https://lore.kernel.org/lkml/20260423085501.760-1-lizhi2@eswincomputing.com/
v5 -> v6:
- Update DTS/DTSI descriptions to fix invalid phandle references reported by DTC:
- Add missing GMAC provider nodes required for proper hardware description:
- HSP power domain: GMAC nodes moved under this domain to reflect
hardware power hierarchy.
- Clock nodes: added to provide clk phandles referenced by GMAC.
- Reset nodes: added to provide reset phandles referenced by GMAC.
- Pinctrl nodes: defines pinctrl settings for GMAC signals
(pinctrl_gpio106, pinctrl_gpio111).
- Move GMAC nodes under the correct HSP power domain.
- Ensure DTS builds without dtc errors and all phandle references
(clk/reset/pinctrl/power-domain) are valid.
- This update does not change runtime behavior; it only improves DTS
consistency and resolves issues reported by dtc.
- Note:
- The patch 3/3 for DTS changes in this series provide an overview of the GMAC
integration and its dependencies, as discussed previously:
https://lore.kernel.org/lkml/64bf6b40-b947-4ffa-8d48-4d6341931327@lunn.ch/
- It is **not intended for upstream inclusion** in its current form,
and is provided solely for architecture overview and integration
context.
- A fully cleaned and upstream-ready DTS series will be submitted
separately once all related components (pinctrl, clock, power-domain,
etc.) are finalized.
- dtbs_check has been run on top of net-next for reference purposes.
Remaining warnings are expected due to missing EIC7700 clock bindings[1]
in net-next and do not reflect issues in the DTS design itself.
- One remaining warning:
- eswin,eic7700-clock
- The clock binding has already been applied to upstream and is present
in mainline, but not yet available in net-next.
- The syscon binding is extended in this series to include the
eswin,eic7700-syscfg compatible.
- Any further refinement of the syscfg binding will be handled in
separate patches if needed.
- Dependencies:
- [1]EIC7700 clock binding:
https://lore.kernel.org/lkml/20260303080637.2100-1-dongxuyang@eswincomputing.com/
(already applied to upstream)
- Link to v5:
https://lore.kernel.org/lkml/20260324073017.376-1-lizhi2@eswincomputing.com/
v4 -> v5:
- eswin,eic7700-eth.yaml:
- Add Acked-by from Conor Dooley
- No functional changes
- Update dwmac-eic7700.c:
- Disable clocks on the error path to fix a clock leak in
eic7700_dwmac_init() when regmap_set_bits() fails
(reported by Simon Horman <horms@kernel.org>)
- Link to v4:
https://lore.kernel.org/lkml/20260313075234.1567-1-lizhi2@eswincomputing.com/
v3 -> v4:
- Update eswin,eic7700-eth.yaml:
- Improve commit message in dt-bindings patch to clarify the
hardware difference of the eth1 MAC and why a new compatible
string is required.
- Move the newly added eswin,hsp-sp-csr item to the end of the list
to avoid inserting entries in the middle of the binding schema.
- Simplify the compatible schema by replacing the previous oneOf
construct with an enum.
- Update dwmac-eic7700.c:
- Fix build issues.
- Adjust code to match the updated binding definition.
- Update DTS/DTSI descriptions:
- Move SoC-level descriptions to the .dtsi file.
- Keep board-specific configuration in the .dts file.
- Link to v3:
https://lore.kernel.org/lkml/20260303061525.846-1-lizhi2@eswincomputing.com/
v2 -> v3:
- Update eswin,eic7700-eth.yaml:
- Extend rx-internal-delay-ps and tx-internal-delay-ps range
from 0-2400 to 0-2540 to match the full 7-bit hardware delay
field (127 * 20 ps).
- Add "multipleOf: 20" constraint to reflect the 20 ps hardware
step size.
- Make rx-internal-delay-ps and tx-internal-delay-ps optional.
A well-designed board should not require internal delay tuning.
- Remove rx-internal-delay-ps and tx-internal-delay-ps from the
example to avoid encouraging blind copy into board DTs.
- Update dwmac-eic7700.c:
- Treat rx-internal-delay-ps and tx-internal-delay-ps as optional
DT properties.
- Apply delay configuration only when properties are present.
- Keep TX/RX delay registers cleared by default to ensure a
deterministic state when no delay is specified.
- Describe Ethernet configuration for the HiFive Premier P550 board:
- Add GMAC controller nodes for the HiFive Premier P550 board
to describe the on-board Ethernet configuration.
The Ethernet controller depends on clock, reset, pinctrl
and HSP subsystem providers which are currently under
upstream review. These dependent nodes will be submitted
separately once the corresponding drivers are merged.
Due to these missing dependencies, dt-binding-check may
report warnings or failures for this series.
- No functional changes to RX clock inversion logic.
- Link to v2:
https://lore.kernel.org/lkml/20260209094628.886-1-lizhi2@eswincomputing.com/
- This series is based on the EIC7700 clock support series:
https://lore.kernel.org/all/20260210095008.726-1-dongxuyang@eswincomputing.com/
The clock series is currently under review.
v1 -> v2:
- Update eswin,eic7700-eth.yaml:
- Drop the vendor-specific properties eswin,rx-clk-invert and
eswin,tx-clk-invert.
- Introduce a distinct compatible string
"eswin,eic7700-qos-eth-clk-inversion" to describe MAC instances that
require internal RGMII clock inversion.
This models the SoC-specific hardware difference directly via the
compatible string and avoids per-board configuration properties.
- Change rx-internal-delay-ps and tx-internal-delay-ps from enum to
minimum/maximum to reflect the actual delay range (0-2400 ps)
- Add reference to High-Speed Subsystem documentation in eswin,hsp-sp-csr
description. The HSP CSR block is described in Chapter 10
("High-Speed Interface") of the EIC7700X SoC Technical Reference Manual,
Part 4 (EIC7700X_SoC_Technical_Reference_Manual_Part4.pdf):
https://github.com/eswincomputing/EIC7700X-SoC-Technical-Reference-Manual/releases
- Update dwmac-eic7700.c:
- Remove handling of eswin,rx-clk-invert and eswin,tx-clk-invert
properties.
- Select RX clock inversion based on the new
"eswin,eic7700-qos-eth-clk-inversion" compatible string, using
match data to apply the required configuration for affected MAC
instances (eth1).
- Link to v1:
https://lore.kernel.org/lkml/20260109080601.1262-1-lizhi2@eswincomputing.com/
Zhi Li (4):
dt-bindings: ethernet: eswin: relax internal delay model to
range-based constraints
dt-bindings: ethernet: eswin: add EIC7700 eth1 RX clock inversion
variant
net: stmmac: eic7700: make RGMII delay properties optional
net: stmmac: eic7700: add support for eth1 clock inversion variant
.../bindings/net/eswin,eic7700-eth.yaml | 74 +++++++++--
.../ethernet/stmicro/stmmac/dwmac-eic7700.c | 117 +++++++++++++++---
2 files changed, 164 insertions(+), 27 deletions(-)
--
2.25.1
^ permalink raw reply
* Re: [PATCH v2 1/4] dt-bindings: arm: altera: Add Agilex5 SoCDK TSN Config2 board
From: Krzysztof Kozlowski @ 2026-07-07 6:41 UTC (permalink / raw)
To: muhammad.nazim.amirul.nazle.asmade, dinguyen, maxime.chevallier
Cc: rmk+kernel, krzk+dt, conor+dt, robh, davem, edumazet, kuba,
pabeni, andrew+netdev, devicetree, linux-arm-kernel, netdev,
linux-kernel
In-Reply-To: <20260707061305.27580-2-muhammad.nazim.amirul.nazle.asmade@altera.com>
On 07/07/2026 08:13, muhammad.nazim.amirul.nazle.asmade@altera.com wrote:
> From: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>
>
> Add compatible string for the Intel SoCFPGA Agilex5 SoCDK TSN Config2
> board variant. This board enables gmac1 as a TSN port with an FPGA
> GMII-to-RGMII converter providing the RGMII clock delays.
>
> Signed-off-by: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>
So you just ignored the tag? Sure, we can ignore patches as well.
Dropping from patchwork.
Best regards,
Krzysztof
^ permalink raw reply
* [PATCH net-next v10 1/4] dt-bindings: ethernet: eswin: relax internal delay model to range-based constraints
From: lizhi2 @ 2026-07-07 6:41 UTC (permalink / raw)
To: devicetree, andrew+netdev, davem, edumazet, kuba, robh, krzk+dt,
conor+dt, netdev, pabeni, mcoquelin.stm32, alexandre.torgue,
rmk+kernel, linux-stm32, linux-arm-kernel, linux-kernel,
maxime.chevallier
Cc: ningyu, linmin, pinkesh.vaghela, pritesh.patel, weishangjuan,
horms, Zhi Li
In-Reply-To: <20260707064033.1265-1-lizhi2@eswincomputing.com>
From: Zhi Li <lizhi2@eswincomputing.com>
Relax internal delay constraints for EIC7700 Ethernet binding.
Replace fixed enumeration of rx-internal-delay-ps and tx-internal-delay-ps
with a range-based definition (0-2540 ps, 20 ps steps) to reflect actual
hardware capability.
Mark rx/tx internal delay properties as optional, as they are board-
specific tuning parameters rather than mandatory configuration.
Update the device tree example to align with the relaxed constraint model
and remove delay properties from the example to avoid implying they are
required.
No functional change to existing DT users.
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Zhi Li <lizhi2@eswincomputing.com>
---
.../bindings/net/eswin,eic7700-eth.yaml | 25 ++++++++++---------
1 file changed, 13 insertions(+), 12 deletions(-)
diff --git a/Documentation/devicetree/bindings/net/eswin,eic7700-eth.yaml b/Documentation/devicetree/bindings/net/eswin,eic7700-eth.yaml
index 65882ff79d8d..4e02fedae5c6 100644
--- a/Documentation/devicetree/bindings/net/eswin,eic7700-eth.yaml
+++ b/Documentation/devicetree/bindings/net/eswin,eic7700-eth.yaml
@@ -63,10 +63,14 @@ properties:
- const: stmmaceth
rx-internal-delay-ps:
- enum: [0, 200, 600, 1200, 1600, 1800, 2000, 2200, 2400]
+ minimum: 0
+ maximum: 2540
+ multipleOf: 20
tx-internal-delay-ps:
- enum: [0, 200, 600, 1200, 1600, 1800, 2000, 2200, 2400]
+ minimum: 0
+ maximum: 2540
+ multipleOf: 20
eswin,hsp-sp-csr:
description:
@@ -105,8 +109,6 @@ required:
- phy-mode
- resets
- reset-names
- - rx-internal-delay-ps
- - tx-internal-delay-ps
- eswin,hsp-sp-csr
unevaluatedProperties: false
@@ -116,23 +118,22 @@ examples:
ethernet@50400000 {
compatible = "eswin,eic7700-qos-eth", "snps,dwmac-5.20";
reg = <0x50400000 0x10000>;
- clocks = <&d0_clock 186>, <&d0_clock 171>, <&d0_clock 40>,
- <&d0_clock 193>;
- clock-names = "axi", "cfg", "stmmaceth", "tx";
interrupt-parent = <&plic>;
interrupts = <61>;
interrupt-names = "macirq";
- phy-mode = "rgmii-id";
- phy-handle = <&phy0>;
+ clocks = <&d0_clock 186>, <&d0_clock 171>, <&d0_clock 40>,
+ <&d0_clock 193>;
+ clock-names = "axi", "cfg", "stmmaceth", "tx";
resets = <&reset 95>;
reset-names = "stmmaceth";
- rx-internal-delay-ps = <200>;
- tx-internal-delay-ps = <200>;
eswin,hsp-sp-csr = <&hsp_sp_csr 0x100 0x108 0x118 0x114 0x11c>;
- snps,axi-config = <&stmmac_axi_setup>;
+ phy-handle = <&phy0>;
+ phy-mode = "rgmii-id";
snps,aal;
snps,fixed-burst;
snps,tso;
+ snps,axi-config = <&stmmac_axi_setup>;
+
stmmac_axi_setup: stmmac-axi-config {
snps,blen = <0 0 0 0 16 8 4>;
snps,rd_osr_lmt = <2>;
--
2.25.1
^ permalink raw reply related
* [PATCH net-next v10 2/4] dt-bindings: ethernet: eswin: add EIC7700 eth1 RX clock inversion variant
From: lizhi2 @ 2026-07-07 6:41 UTC (permalink / raw)
To: devicetree, andrew+netdev, davem, edumazet, kuba, robh, krzk+dt,
conor+dt, netdev, pabeni, mcoquelin.stm32, alexandre.torgue,
rmk+kernel, linux-stm32, linux-arm-kernel, linux-kernel,
maxime.chevallier
Cc: ningyu, linmin, pinkesh.vaghela, pritesh.patel, weishangjuan,
horms, Zhi Li, Conor Dooley
In-Reply-To: <20260707064033.1265-1-lizhi2@eswincomputing.com>
From: Zhi Li <lizhi2@eswincomputing.com>
The EIC7700 SoC integrates two GMAC instances. The eth1 MAC exhibits
different RX clock sampling characteristics due to silicon-inherent
timing behavior.
The eth1 MAC has a fixed, non-configurable RX clock-to-data skew at the
MAC input in the order of 4-5 ns. This cannot be compensated solely by
the standard MAC internal delay configuration and PHY delay, and RX clock
inversion is required at 1000Mbps for correct sampling.
The eth1 TX path also includes a fixed silicon-inherent delay of
approximately 2 ns. This delay is always present and cannot be disabled.
It is therefore part of the effective transmit timing observed on the
wire.
For the eth1 variant, the valid tx-internal-delay-ps values include
this fixed delay component. Consequently, the effective range becomes
2000-4540 ps (approximately 2000 ps fixed delay plus 0-2540 ps
programmable delay).
Introduce a dedicated compatible string
"eswin,eic7700-qos-eth-clk-inversion" to represent the eth1 variant,
allowing the driver to apply RX clock inversion only when required by
hardware variant selection.
This keeps SoC-level differentiation without exposing silicon-fixed skew
as configurable device tree parameters.
To reflect this, model the TX internal delay as a base 0-4540 ps range,
and constrain valid values per compatible using conditional schema rules.
Update the binding schema as follows:
- Define tx-internal-delay-ps as a base range: 0-4540 ps
- Add compatible-specific constraints using if/then rules:
* eswin,eic7700-qos-eth:
max 2540 ps
* eswin,eic7700-qos-eth-clk-inversion:
minimum 2000 ps (effective range 2000-4540 ps)
No functional change for existing "eswin,eic7700-qos-eth" users.
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Signed-off-by: Zhi Li <lizhi2@eswincomputing.com>
---
.../bindings/net/eswin,eic7700-eth.yaml | 51 ++++++++++++++++++-
1 file changed, 49 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/net/eswin,eic7700-eth.yaml b/Documentation/devicetree/bindings/net/eswin,eic7700-eth.yaml
index 4e02fedae5c6..ba49fd6a086c 100644
--- a/Documentation/devicetree/bindings/net/eswin,eic7700-eth.yaml
+++ b/Documentation/devicetree/bindings/net/eswin,eic7700-eth.yaml
@@ -20,16 +20,37 @@ select:
contains:
enum:
- eswin,eic7700-qos-eth
+ - eswin,eic7700-qos-eth-clk-inversion
required:
- compatible
allOf:
- $ref: snps,dwmac.yaml#
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: eswin,eic7700-qos-eth
+ then:
+ properties:
+ tx-internal-delay-ps:
+ maximum: 2540
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: eswin,eic7700-qos-eth-clk-inversion
+ then:
+ properties:
+ tx-internal-delay-ps:
+ minimum: 2000
properties:
compatible:
items:
- - const: eswin,eic7700-qos-eth
+ - enum:
+ - eswin,eic7700-qos-eth
+ - eswin,eic7700-qos-eth-clk-inversion
- const: snps,dwmac-5.20
reg:
@@ -69,7 +90,7 @@ properties:
tx-internal-delay-ps:
minimum: 0
- maximum: 2540
+ maximum: 4540
multipleOf: 20
eswin,hsp-sp-csr:
@@ -140,3 +161,29 @@ examples:
snps,wr_osr_lmt = <2>;
};
};
+
+ ethernet@50410000 {
+ compatible = "eswin,eic7700-qos-eth-clk-inversion", "snps,dwmac-5.20";
+ reg = <0x50410000 0x10000>;
+ interrupt-parent = <&plic>;
+ interrupts = <70>;
+ interrupt-names = "macirq";
+ clocks = <&d0_clock 186>, <&d0_clock 171>, <&d0_clock 40>,
+ <&d0_clock 194>;
+ clock-names = "axi", "cfg", "stmmaceth", "tx";
+ resets = <&reset 94>;
+ reset-names = "stmmaceth";
+ eswin,hsp-sp-csr = <&hsp_sp_csr 0x200 0x208 0x218 0x214 0x21c>;
+ phy-handle = <&gmac1_phy0>;
+ phy-mode = "rgmii-id";
+ snps,aal;
+ snps,fixed-burst;
+ snps,tso;
+ snps,axi-config = <&stmmac_axi_setup_gmac1>;
+
+ stmmac_axi_setup_gmac1: stmmac-axi-config {
+ snps,blen = <0 0 0 0 16 8 4>;
+ snps,rd_osr_lmt = <2>;
+ snps,wr_osr_lmt = <2>;
+ };
+ };
--
2.25.1
^ permalink raw reply related
* [PATCH net-next v10 3/4] net: stmmac: eic7700: make RGMII delay properties optional
From: lizhi2 @ 2026-07-07 6:42 UTC (permalink / raw)
To: devicetree, andrew+netdev, davem, edumazet, kuba, robh, krzk+dt,
conor+dt, netdev, pabeni, mcoquelin.stm32, alexandre.torgue,
rmk+kernel, linux-stm32, linux-arm-kernel, linux-kernel,
maxime.chevallier
Cc: ningyu, linmin, pinkesh.vaghela, pritesh.patel, weishangjuan,
horms, Zhi Li
In-Reply-To: <20260707064033.1265-1-lizhi2@eswincomputing.com>
From: Zhi Li <lizhi2@eswincomputing.com>
Make rx-internal-delay-ps and tx-internal-delay-ps optional in the
EIC7700 DWMAC driver.
The driver previously required both properties to be present and would
fail probe when they were missing. This restricts valid hardware
configurations where RGMII timing is instead provided by the PHY or
board design.
Update the driver to treat missing delay properties as zero delay,
allowing systems without explicit MAC-side delay tuning to operate
correctly.
This aligns the driver behavior with the updated device tree binding
and provides a safe default configuration when MAC-side delay
programming is not required.
Signed-off-by: Zhi Li <lizhi2@eswincomputing.com>
---
drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c | 6 ------
1 file changed, 6 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c
index 4ac979d874d6..ec99b597aeaf 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c
@@ -165,9 +165,6 @@ static int eic7700_dwmac_probe(struct platform_device *pdev)
dwc_priv->eth_clk_dly_param &= ~EIC7700_ETH_RX_ADJ_DELAY;
dwc_priv->eth_clk_dly_param |=
FIELD_PREP(EIC7700_ETH_RX_ADJ_DELAY, val);
- } else {
- return dev_err_probe(&pdev->dev, -EINVAL,
- "missing required property rx-internal-delay-ps\n");
}
/* Read tx-internal-delay-ps and update tx_clk delay */
@@ -187,9 +184,6 @@ static int eic7700_dwmac_probe(struct platform_device *pdev)
dwc_priv->eth_clk_dly_param &= ~EIC7700_ETH_TX_ADJ_DELAY;
dwc_priv->eth_clk_dly_param |=
FIELD_PREP(EIC7700_ETH_TX_ADJ_DELAY, val);
- } else {
- return dev_err_probe(&pdev->dev, -EINVAL,
- "missing required property tx-internal-delay-ps\n");
}
dwc_priv->eic7700_hsp_regmap =
--
2.25.1
^ permalink raw reply related
* [PATCH net-next v10 4/4] net: stmmac: eic7700: add support for eth1 clock inversion variant
From: lizhi2 @ 2026-07-07 6:42 UTC (permalink / raw)
To: devicetree, andrew+netdev, davem, edumazet, kuba, robh, krzk+dt,
conor+dt, netdev, pabeni, mcoquelin.stm32, alexandre.torgue,
rmk+kernel, linux-stm32, linux-arm-kernel, linux-kernel,
maxime.chevallier
Cc: ningyu, linmin, pinkesh.vaghela, pritesh.patel, weishangjuan,
horms, Zhi Li
In-Reply-To: <20260707064033.1265-1-lizhi2@eswincomputing.com>
From: Zhi Li <lizhi2@eswincomputing.com>
The eth1 MAC exhibits silicon-inherent RX and TX timing behavior that
differs from the eth0 implementation.
At 1000Mbps, RX sampling requires clock inversion due to a fixed MAC
input skew that cannot be compensated by standard RGMII delay settings.
The TX path includes a fixed ~2ns internal delay introduced by the MAC
silicon. This delay is always present and is already accounted for in
the device tree tx-internal-delay-ps property as part of the effective
output timing.
The tx-internal-delay-ps property describes the effective delay seen at
the MAC output. Since the hardware register controls only the
programmable portion of the delay, the driver subtracts the fixed
silicon-inherent component before programming the delay register.
Use compatible-specific match data to identify the eth1 variant and
apply RX clock inversion only at 1000Mbps.
The PHY interface mode is adjusted via phy_fix_phy_mode_for_mac_delays()
to avoid double-application of RGMII delays when MAC-side delays are
already present.
Link speed dependency means RX sampling configuration is applied in the
fix_mac_speed callback after negotiation.
No behavior changes for the existing eth0 controller.
Signed-off-by: Zhi Li <lizhi2@eswincomputing.com>
---
.../ethernet/stmicro/stmmac/dwmac-eic7700.c | 111 ++++++++++++++++--
1 file changed, 103 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c
index ec99b597aeaf..eab8c13fbdcc 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c
@@ -28,11 +28,15 @@
/*
* TX/RX Clock Delay Bit Masks:
- * - TX Delay: bits [14:8] — TX_CLK delay (unit: 0.02ns per bit)
- * - RX Delay: bits [30:24] — RX_CLK delay (unit: 0.02ns per bit)
+ * - TX Delay: bits [14:8] - TX_CLK delay (unit: 0.02ns per bit)
+ * - TX Invert : bit [15]
+ * - RX Delay: bits [30:24] - RX_CLK delay (unit: 0.02ns per bit)
+ * - RX Invert : bit [31]
*/
#define EIC7700_ETH_TX_ADJ_DELAY GENMASK(14, 8)
#define EIC7700_ETH_RX_ADJ_DELAY GENMASK(30, 24)
+#define EIC7700_ETH_TX_INV_DELAY BIT(15)
+#define EIC7700_ETH_RX_INV_DELAY BIT(31)
#define EIC7700_MAX_DELAY_STEPS 0x7F
#define EIC7700_DELAY_STEP_PS 20
@@ -43,7 +47,14 @@ static const char * const eic7700_clk_names[] = {
"tx", "axi", "cfg",
};
+struct eic7700_dwmac_data {
+ bool rgmii_rx_clk_invert;
+ bool has_internal_tx_delay;
+ u32 tx_clk_inherent_skew_ps;
+};
+
struct eic7700_qos_priv {
+ struct device *dev;
struct plat_stmmacenet_data *plat_dat;
struct regmap *eic7700_hsp_regmap;
u32 eth_axi_lp_ctrl_offset;
@@ -54,6 +65,7 @@ struct eic7700_qos_priv {
u32 eth_clk_dly_param;
bool has_txd_offset;
bool has_rxd_offset;
+ bool eth_rx_clk_inv;
};
static int eic7700_clks_config(void *priv, bool enabled)
@@ -97,9 +109,6 @@ static int eic7700_dwmac_init(struct device *dev, void *priv)
if (dwc->has_rxd_offset)
regmap_write(dwc->eic7700_hsp_regmap, dwc->eth_rxd_offset, 0);
- regmap_write(dwc->eic7700_hsp_regmap, dwc->eth_clk_offset,
- dwc->eth_clk_dly_param);
-
return 0;
}
@@ -126,8 +135,38 @@ static int eic7700_dwmac_resume(struct device *dev, void *priv)
return ret;
}
+/*
+ * eth1 requires RX clock inversion at 1000Mbps due to silicon-inherent
+ * RX sampling skew at MAC input.
+ *
+ * The configuration is updated in fix_mac_speed() because the required
+ * sampling behavior depends on the negotiated link speed.
+ */
+static void eic7700_dwmac_fix_speed(void *priv, phy_interface_t interface,
+ int speed, unsigned int mode)
+{
+ struct eic7700_qos_priv *dwc = (struct eic7700_qos_priv *)priv;
+ u32 dly_param = dwc->eth_clk_dly_param;
+
+ switch (speed) {
+ case SPEED_1000:
+ if (dwc->eth_rx_clk_inv)
+ dly_param |= EIC7700_ETH_RX_INV_DELAY;
+ break;
+ case SPEED_100:
+ case SPEED_10:
+ break;
+ default:
+ dev_warn(dwc->dev, "unsupported speed %u\n", speed);
+ return;
+ }
+
+ regmap_write(dwc->eic7700_hsp_regmap, dwc->eth_clk_offset, dly_param);
+}
+
static int eic7700_dwmac_probe(struct platform_device *pdev)
{
+ const struct eic7700_dwmac_data *data;
struct plat_stmmacenet_data *plat_dat;
struct stmmac_resources stmmac_res;
struct eic7700_qos_priv *dwc_priv;
@@ -148,6 +187,30 @@ static int eic7700_dwmac_probe(struct platform_device *pdev)
if (!dwc_priv)
return -ENOMEM;
+ dwc_priv->dev = &pdev->dev;
+
+ data = device_get_match_data(&pdev->dev);
+ if (!data)
+ return dev_err_probe(&pdev->dev,
+ -EINVAL, "no match data found\n");
+
+ dwc_priv->eth_rx_clk_inv = data->rgmii_rx_clk_invert;
+ /*
+ * The MAC silicon unconditionally adds ~2 ns TX delay; prevent
+ * the PHY from also adding TX delay to avoid doubling it.
+ *
+ * DT specifies rgmii-id (TX from MAC silicon, RX from PHY);
+ * override to rgmii-rxid so the PHY only adds its RX delay.
+ */
+ if (data->has_internal_tx_delay) {
+ plat_dat->phy_interface =
+ phy_fix_phy_mode_for_mac_delays(plat_dat->phy_interface,
+ true, false);
+ if (plat_dat->phy_interface == PHY_INTERFACE_MODE_NA)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "phy interface mode is NA\n");
+ }
+
/* Read rx-internal-delay-ps and update rx_clk delay */
if (!of_property_read_u32(pdev->dev.of_node,
"rx-internal-delay-ps", &delay_ps)) {
@@ -167,7 +230,13 @@ static int eic7700_dwmac_probe(struct platform_device *pdev)
FIELD_PREP(EIC7700_ETH_RX_ADJ_DELAY, val);
}
- /* Read tx-internal-delay-ps and update tx_clk delay */
+ /* Read tx-internal-delay-ps and update tx_clk delay.
+ *
+ * For eswin,eic7700-qos-eth-clk-inversion, the DT property describes
+ * the effective TX delay at the MAC output, including the inherent
+ * silicon delay. Subtract the fixed component to obtain the
+ * programmable delay value.
+ */
if (!of_property_read_u32(pdev->dev.of_node,
"tx-internal-delay-ps", &delay_ps)) {
if (delay_ps % EIC7700_DELAY_STEP_PS)
@@ -175,9 +244,16 @@ static int eic7700_dwmac_probe(struct platform_device *pdev)
"tx delay must be multiple of %dps\n",
EIC7700_DELAY_STEP_PS);
+ if (delay_ps < data->tx_clk_inherent_skew_ps)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "tx delay %ups below inherent skew %ups\n",
+ delay_ps, data->tx_clk_inherent_skew_ps);
+
+ delay_ps -= data->tx_clk_inherent_skew_ps;
+
if (delay_ps > EIC7700_MAX_DELAY_PS)
return dev_err_probe(&pdev->dev, -EINVAL,
- "tx delay out of range\n");
+ "tx delay out of programmable range\n");
val = delay_ps / EIC7700_DELAY_STEP_PS;
@@ -254,12 +330,31 @@ static int eic7700_dwmac_probe(struct platform_device *pdev)
plat_dat->exit = eic7700_dwmac_exit;
plat_dat->suspend = eic7700_dwmac_suspend;
plat_dat->resume = eic7700_dwmac_resume;
+ plat_dat->fix_mac_speed = eic7700_dwmac_fix_speed;
return devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res);
}
+static const struct eic7700_dwmac_data eic7700_dwmac_data = {
+ .rgmii_rx_clk_invert = false,
+ .has_internal_tx_delay = false,
+ .tx_clk_inherent_skew_ps = 0,
+};
+
+static const struct eic7700_dwmac_data eic7700_dwmac_data_clk_inversion = {
+ .rgmii_rx_clk_invert = true,
+ .has_internal_tx_delay = true,
+ .tx_clk_inherent_skew_ps = 2000,
+};
+
static const struct of_device_id eic7700_dwmac_match[] = {
- { .compatible = "eswin,eic7700-qos-eth" },
+ { .compatible = "eswin,eic7700-qos-eth",
+ .data = &eic7700_dwmac_data,
+ },
+ {
+ .compatible = "eswin,eic7700-qos-eth-clk-inversion",
+ .data = &eic7700_dwmac_data_clk_inversion,
+ },
{ }
};
MODULE_DEVICE_TABLE(of, eic7700_dwmac_match);
--
2.25.1
^ permalink raw reply related
* [PATCH iproute] ss: Don't re-print an SCTP listen socket as an assoc
From: Jamie Bainbridge @ 2026-07-07 6:46 UTC (permalink / raw)
To: netdev, Stephen Hemminger, Phil Sutter, Xin Long, Rustam Kovhaev
Cc: Jamie Bainbridge
"ss -Sa" prints a LISTEN-state SCTP sock once as a non-assoc when
is_sctp_assoc() correctly returns false, then again when we have cached
the inode in sctp_ino, so is_sctp_assoc() returns true.
On the second pass, we try to print the socket state with
sctp_sstate_name[s->state], but s->state == 10 (SCTP_SS_LISTENING)
but sctp_sstate_name[] only has 8 entries, so we illegally access beyond
the end of the name array.
If you are lucky, the space beyond the array is NULL and the argument to
the print format is printed as "(null)" by the C library:
$ ./misc/ss -San
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 5 192.0.2.10:9001 0.0.0.0:*
`- (null) 0 5 192.0.2.10:9001 0.0.0.0:*
`- ESTAB 0 0 192.0.2.10%net1:9001 192.0.2.9:11111
If you are unlucky, the space beyond the array is non-NULL and you
pass an invalid address to the print format:
$ ./misc/ss -San
Segmentation fault (core dumped)
The inode is correctly cached at the bottom of inet_show_sock(), so
check if we've already processed this SCTP LISTEN inode and exit early.
$ ./misc/ss -San
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 5 192.0.2.10:9001 0.0.0.0:*
`- ESTAB 0 0 192.0.2.10%net1:9001 192.0.2.9:11111
We cannot exit later than this (eg: in sock_state_print()) because by
then we're already halfway through a new line in inet_stats_print().
Keep the existing check in is_sctp_assoc() because that is needed to
differentiate related assocs from new endpoints.
Note: there is still a chance of double-printing a listen socket (now
with the correct format if netlink delivers us listen sockets and their
assocs with something else in between:
$ ./misc/ss -Sane
State Recv-Q Send-Q Local Address:Port Peer Address:Port
> LISTEN 0 5 192.0.2.10:9001 0.0.0.0:* ino:36518
LISTEN 0 5 192.0.2.10:9002 0.0.0.0:* ino:44485
`- ESTAB 0 0 192.0.2.10%net1:9002 192.0.2.9:22222 ino:44485
> LISTEN 0 5 192.0.2.10:9001 0.0.0.0:* ino:36518
`- ESTAB 0 0 192.0.2.10%net1:9001 122.0.2.9:11111 ino:36518
This behaviour existed before this commit. I don't see a way around this
except to pre-sort the results from netlink which seems unrealistic.
Fixes: f89d46ad63f6f ("ss: Add support for SCTP protocol")
Reported-by: Rustam Kovhaev <rkovhaev@gmail.com>
Signed-off-by: Jamie Bainbridge <jamie.bainbridge@gmail.com>
---
misc/ss.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/misc/ss.c b/misc/ss.c
index 14e9f27a75321556240a5f290b8bcf51c605a4c2..7e94160f7590c35aa187fe00902be8def7593608 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -3764,6 +3764,14 @@ static bool bpf_map_opts_is_enabled(void)
static int inet_show_sock(struct nlmsghdr *nlh,
struct sockstat *s)
{
+ /* SCTP assocs share the same inode number with their parent endpoint.
+ * If we've seen a LISTEN socket inode before, we've already printed it
+ * and cached the inode at the bottom of this function. We don't want
+ * to re-print the LISTEN socket again. so exit early.
+ */
+ if (s->type == IPPROTO_SCTP && s->state == SS_LISTEN && sctp_ino == s->ino)
+ return 0;
+
struct rtattr *tb[INET_DIAG_MAX+1];
struct inet_diag_msg *r = NLMSG_DATA(nlh);
unsigned char v6only = 0;
--
2.47.3
^ permalink raw reply related
* [PATCH net-next v5 0/3] net: dsa: motorcomm: Add LED support
From: David Yang @ 2026-07-07 6:47 UTC (permalink / raw)
To: netdev
Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
v4: https://lore.kernel.org/r/20260703165241.542195-1-mmyangfl@gmail.com
- fix some reg op typos
v3: https://lore.kernel.org/r/20260701155519.273212-1-mmyangfl@gmail.com
- fix null pointer dereference
- support polarity auto-configuration
v2: https://lore.kernel.org/r/20260629183137.541341-1-mmyangfl@gmail.com
- allocate LED structures only
- eliminate double locking
v1: https://lore.kernel.org/r/20260618202716.2166450-1-mmyangfl@gmail.com
- set up polarity correctly
- do not set up .brightness_get() to prevent dead lock
David Yang (3):
net: dsa: motorcomm: Move to subdirectory
net: dsa: motorcomm: Split SMI module
net: dsa: motorcomm: Add LED support
MAINTAINERS | 2 +-
drivers/net/dsa/Kconfig | 10 +-
drivers/net/dsa/Makefile | 2 +-
drivers/net/dsa/motorcomm/Kconfig | 17 +
drivers/net/dsa/motorcomm/Makefile | 5 +
.../net/dsa/{yt921x.c => motorcomm/chip.c} | 222 +------
.../net/dsa/{yt921x.h => motorcomm/chip.h} | 14 +-
drivers/net/dsa/motorcomm/leds.c | 615 ++++++++++++++++++
drivers/net/dsa/motorcomm/leds.h | 121 ++++
drivers/net/dsa/motorcomm/smi.c | 157 +++++
drivers/net/dsa/motorcomm/smi.h | 88 +++
11 files changed, 1033 insertions(+), 220 deletions(-)
create mode 100644 drivers/net/dsa/motorcomm/Kconfig
create mode 100644 drivers/net/dsa/motorcomm/Makefile
rename drivers/net/dsa/{yt921x.c => motorcomm/chip.c} (96%)
rename drivers/net/dsa/{yt921x.h => motorcomm/chip.h} (99%)
create mode 100644 drivers/net/dsa/motorcomm/leds.c
create mode 100644 drivers/net/dsa/motorcomm/leds.h
create mode 100644 drivers/net/dsa/motorcomm/smi.c
create mode 100644 drivers/net/dsa/motorcomm/smi.h
--
2.53.0
^ permalink raw reply
* [PATCH net-next v5 1/3] net: dsa: motorcomm: Move to subdirectory
From: David Yang @ 2026-07-07 6:47 UTC (permalink / raw)
To: netdev
Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
In-Reply-To: <20260707064752.1030345-1-mmyangfl@gmail.com>
yt921x is already the longest single-file DSA driver, so it's time to
split it into parts.
Signed-off-by: David Yang <mmyangfl@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
---
MAINTAINERS | 2 +-
drivers/net/dsa/Kconfig | 10 ++--------
drivers/net/dsa/Makefile | 2 +-
drivers/net/dsa/motorcomm/Kconfig | 8 ++++++++
drivers/net/dsa/motorcomm/Makefile | 3 +++
drivers/net/dsa/{yt921x.c => motorcomm/chip.c} | 2 +-
drivers/net/dsa/{yt921x.h => motorcomm/chip.h} | 0
7 files changed, 16 insertions(+), 11 deletions(-)
create mode 100644 drivers/net/dsa/motorcomm/Kconfig
create mode 100644 drivers/net/dsa/motorcomm/Makefile
rename drivers/net/dsa/{yt921x.c => motorcomm/chip.c} (99%)
rename drivers/net/dsa/{yt921x.h => motorcomm/chip.h} (100%)
diff --git a/MAINTAINERS b/MAINTAINERS
index 06df1171f4cf..b007f20b2763 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18039,7 +18039,7 @@ M: David Yang <mmyangfl@gmail.com>
L: netdev@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/net/dsa/motorcomm,yt921x.yaml
-F: drivers/net/dsa/yt921x.*
+F: drivers/net/dsa/motorcomm/
F: net/dsa/tag_yt921x.c
MOXA SMARTIO/INDUSTIO/INTELLIO SERIAL CARD
diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig
index 4ab567c5bbaf..98e9bbe47de7 100644
--- a/drivers/net/dsa/Kconfig
+++ b/drivers/net/dsa/Kconfig
@@ -72,6 +72,8 @@ config NET_DSA_MV88E6060
source "drivers/net/dsa/microchip/Kconfig"
+source "drivers/net/dsa/motorcomm/Kconfig"
+
source "drivers/net/dsa/mv88e6xxx/Kconfig"
source "drivers/net/dsa/mxl862xx/Kconfig"
@@ -158,12 +160,4 @@ config NET_DSA_VITESSE_VSC73XX_PLATFORM
This enables support for the Vitesse VSC7385, VSC7388, VSC7395
and VSC7398 SparX integrated ethernet switches, connected over
a CPU-attached address bus and work in memory-mapped I/O mode.
-
-config NET_DSA_YT921X
- tristate "Motorcomm YT9215 ethernet switch chip support"
- select NET_DSA_TAG_YT921X
- select NET_IEEE8021Q_HELPERS if DCB
- help
- This enables support for the Motorcomm YT9215 ethernet switch
- chip.
endmenu
diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile
index d2975badffc0..138225baa4d5 100644
--- a/drivers/net/dsa/Makefile
+++ b/drivers/net/dsa/Makefile
@@ -14,11 +14,11 @@ obj-$(CONFIG_NET_DSA_SMSC_LAN9303_MDIO) += lan9303_mdio.o
obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX) += vitesse-vsc73xx-core.o
obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX_PLATFORM) += vitesse-vsc73xx-platform.o
obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX_SPI) += vitesse-vsc73xx-spi.o
-obj-$(CONFIG_NET_DSA_YT921X) += yt921x.o
obj-y += b53/
obj-y += hirschmann/
obj-y += lantiq/
obj-y += microchip/
+obj-y += motorcomm/
obj-y += mv88e6xxx/
obj-y += mxl862xx/
obj-y += netc/
diff --git a/drivers/net/dsa/motorcomm/Kconfig b/drivers/net/dsa/motorcomm/Kconfig
new file mode 100644
index 000000000000..1fddd386f866
--- /dev/null
+++ b/drivers/net/dsa/motorcomm/Kconfig
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: ISC
+config NET_DSA_YT921X
+ tristate "Motorcomm YT9215 ethernet switch chip support"
+ select NET_DSA_TAG_YT921X
+ select NET_IEEE8021Q_HELPERS if DCB
+ help
+ This enables support for the Motorcomm YT9215 ethernet switch
+ chip.
diff --git a/drivers/net/dsa/motorcomm/Makefile b/drivers/net/dsa/motorcomm/Makefile
new file mode 100644
index 000000000000..afd03be9fa35
--- /dev/null
+++ b/drivers/net/dsa/motorcomm/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: ISC
+obj-$(CONFIG_NET_DSA_YT921X) += yt921x.o
+yt921x-objs := chip.o
diff --git a/drivers/net/dsa/yt921x.c b/drivers/net/dsa/motorcomm/chip.c
similarity index 99%
rename from drivers/net/dsa/yt921x.c
rename to drivers/net/dsa/motorcomm/chip.c
index 159b16606f6c..f070732845eb 100644
--- a/drivers/net/dsa/yt921x.c
+++ b/drivers/net/dsa/motorcomm/chip.c
@@ -26,7 +26,7 @@
#include <net/ieee8021q.h>
#include <net/pkt_cls.h>
-#include "yt921x.h"
+#include "chip.h"
struct yt921x_mib_desc {
unsigned int size;
diff --git a/drivers/net/dsa/yt921x.h b/drivers/net/dsa/motorcomm/chip.h
similarity index 100%
rename from drivers/net/dsa/yt921x.h
rename to drivers/net/dsa/motorcomm/chip.h
--
2.53.0
^ permalink raw reply related
* [PATCH net-next v5 2/3] net: dsa: motorcomm: Split SMI module
From: David Yang @ 2026-07-07 6:47 UTC (permalink / raw)
To: netdev
Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
In-Reply-To: <20260707064752.1030345-1-mmyangfl@gmail.com>
SMI operations are going to be used across different modules.
Signed-off-by: David Yang <mmyangfl@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/motorcomm/Makefile | 1 +
drivers/net/dsa/motorcomm/chip.c | 207 +----------------------------
drivers/net/dsa/motorcomm/smi.c | 157 ++++++++++++++++++++++
drivers/net/dsa/motorcomm/smi.h | 88 ++++++++++++
4 files changed, 247 insertions(+), 206 deletions(-)
create mode 100644 drivers/net/dsa/motorcomm/smi.c
create mode 100644 drivers/net/dsa/motorcomm/smi.h
diff --git a/drivers/net/dsa/motorcomm/Makefile b/drivers/net/dsa/motorcomm/Makefile
index afd03be9fa35..6cea5313a444 100644
--- a/drivers/net/dsa/motorcomm/Makefile
+++ b/drivers/net/dsa/motorcomm/Makefile
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: ISC
obj-$(CONFIG_NET_DSA_YT921X) += yt921x.o
yt921x-objs := chip.o
+yt921x-objs += smi.o
diff --git a/drivers/net/dsa/motorcomm/chip.c b/drivers/net/dsa/motorcomm/chip.c
index f070732845eb..6dee25b6754a 100644
--- a/drivers/net/dsa/motorcomm/chip.c
+++ b/drivers/net/dsa/motorcomm/chip.c
@@ -13,7 +13,6 @@
#include <linux/if_bridge.h>
#include <linux/if_hsr.h>
#include <linux/if_vlan.h>
-#include <linux/iopoll.h>
#include <linux/mdio.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -27,6 +26,7 @@
#include <net/pkt_cls.h>
#include "chip.h"
+#include "smi.h"
struct yt921x_mib_desc {
unsigned int size;
@@ -155,9 +155,6 @@ static const struct yt921x_info yt921x_infos[] = {
#define YT921X_VID_UNWARE 4095
-#define YT921X_POLL_SLEEP_US 10000
-#define YT921X_POLL_TIMEOUT_US 100000
-
/* The interval should be small enough to avoid overflow of 32bit MIBs.
*
* Until we can read MIBs from stats64 call directly (i.e. sleep
@@ -196,208 +193,6 @@ static u32 ethaddr_lo2_to_u32(const unsigned char *addr)
return (addr[4] << 8) | addr[5];
}
-static int yt921x_reg_read(struct yt921x_priv *priv, u32 reg, u32 *valp)
-{
- WARN_ON(!mutex_is_locked(&priv->reg_lock));
-
- return priv->reg_ops->read(priv->reg_ctx, reg, valp);
-}
-
-static int yt921x_reg_write(struct yt921x_priv *priv, u32 reg, u32 val)
-{
- WARN_ON(!mutex_is_locked(&priv->reg_lock));
-
- return priv->reg_ops->write(priv->reg_ctx, reg, val);
-}
-
-static int
-yt921x_reg_wait(struct yt921x_priv *priv, u32 reg, u32 mask, u32 *valp)
-{
- u32 val;
- int res;
- int ret;
-
- ret = read_poll_timeout(yt921x_reg_read, res,
- res || (val & mask) == *valp,
- YT921X_POLL_SLEEP_US, YT921X_POLL_TIMEOUT_US,
- false, priv, reg, &val);
- if (ret)
- return ret;
- if (res)
- return res;
-
- *valp = val;
- return 0;
-}
-
-static int
-yt921x_reg_update_bits(struct yt921x_priv *priv, u32 reg, u32 mask, u32 val)
-{
- int res;
- u32 v;
- u32 u;
-
- res = yt921x_reg_read(priv, reg, &v);
- if (res)
- return res;
-
- u = v;
- u &= ~mask;
- u |= val;
- if (u == v)
- return 0;
-
- return yt921x_reg_write(priv, reg, u);
-}
-
-static int yt921x_reg_set_bits(struct yt921x_priv *priv, u32 reg, u32 mask)
-{
- return yt921x_reg_update_bits(priv, reg, 0, mask);
-}
-
-static int yt921x_reg_clear_bits(struct yt921x_priv *priv, u32 reg, u32 mask)
-{
- return yt921x_reg_update_bits(priv, reg, mask, 0);
-}
-
-static int
-yt921x_reg_toggle_bits(struct yt921x_priv *priv, u32 reg, u32 mask, bool set)
-{
- return yt921x_reg_update_bits(priv, reg, mask, !set ? 0 : mask);
-}
-
-/* Some multi-word registers, like VLANn_CTRL, should be treated as a single
- * long register. More specifically, writes to parts of its words won't become
- * visible, until the last word is written.
- *
- * Here we require full read and write operations over these registers to
- * eliminate potential issues, although partial reads/writes are also possible.
- */
-
-static void update_ctrls_unaligned(u32 *lo, u32 *hi, u64 mask, u64 val)
-{
- *lo &= ~lower_32_bits(mask);
- *hi &= ~upper_32_bits(mask);
- *lo |= lower_32_bits(val);
- *hi |= upper_32_bits(val);
-}
-
-static int
-yt921x_regs_read(struct yt921x_priv *priv, u32 reg, u32 *vals,
- unsigned int num_regs)
-{
- int res;
-
- for (unsigned int i = 0; i < num_regs; i++) {
- res = yt921x_reg_read(priv, reg + 4 * i, &vals[i]);
- if (res)
- return res;
- }
-
- return 0;
-}
-
-static int
-yt921x_regs_write(struct yt921x_priv *priv, u32 reg, const u32 *vals,
- unsigned int num_regs)
-{
- int res;
-
- for (unsigned int i = 0; i < num_regs; i++) {
- res = yt921x_reg_write(priv, reg + 4 * i, vals[i]);
- if (res)
- return res;
- }
-
- return 0;
-}
-
-static int
-yt921x_regs_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
- const u32 *vals, unsigned int num_regs)
-{
- bool changed = false;
- u32 vs[4];
- int res;
-
- BUILD_BUG_ON(num_regs > ARRAY_SIZE(vs));
-
- res = yt921x_regs_read(priv, reg, vs, num_regs);
- if (res)
- return res;
-
- for (unsigned int i = 0; i < num_regs; i++) {
- u32 u = vs[i];
-
- u &= ~masks[i];
- u |= vals[i];
- if (u != vs[i])
- changed = true;
-
- vs[i] = u;
- }
-
- if (!changed)
- return 0;
-
- return yt921x_regs_write(priv, reg, vs, num_regs);
-}
-
-static int
-yt921x_regs_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
- unsigned int num_regs)
-{
- bool changed = false;
- u32 vs[4];
- int res;
-
- BUILD_BUG_ON(num_regs > ARRAY_SIZE(vs));
-
- res = yt921x_regs_read(priv, reg, vs, num_regs);
- if (res)
- return res;
-
- for (unsigned int i = 0; i < num_regs; i++) {
- u32 u = vs[i];
-
- u &= ~masks[i];
- if (u != vs[i])
- changed = true;
-
- vs[i] = u;
- }
-
- if (!changed)
- return 0;
-
- return yt921x_regs_write(priv, reg, vs, num_regs);
-}
-
-static int
-yt921x_reg64_write(struct yt921x_priv *priv, u32 reg, const u32 *vals)
-{
- return yt921x_regs_write(priv, reg, vals, 2);
-}
-
-static int
-yt921x_reg64_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
- const u32 *vals)
-{
- return yt921x_regs_update_bits(priv, reg, masks, vals, 2);
-}
-
-static int
-yt921x_reg64_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks)
-{
- return yt921x_regs_clear_bits(priv, reg, masks, 2);
-}
-
-static int
-yt921x_reg96_write(struct yt921x_priv *priv, u32 reg, const u32 *vals)
-{
- return yt921x_regs_write(priv, reg, vals, 3);
-}
-
static int yt921x_reg_mdio_read(void *context, u32 reg, u32 *valp)
{
struct yt921x_reg_mdio *mdio = context;
diff --git a/drivers/net/dsa/motorcomm/smi.c b/drivers/net/dsa/motorcomm/smi.c
new file mode 100644
index 000000000000..9054896e4cd1
--- /dev/null
+++ b/drivers/net/dsa/motorcomm/smi.c
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2026 David Yang
+ */
+
+#include <linux/iopoll.h>
+
+#include "chip.h"
+#include "smi.h"
+
+#define YT921X_POLL_SLEEP_US 10000
+#define YT921X_POLL_TIMEOUT_US 100000
+
+int yt921x_reg_read(struct yt921x_priv *priv, u32 reg, u32 *valp)
+{
+ lockdep_assert_held_once(&priv->reg_lock);
+
+ return priv->reg_ops->read(priv->reg_ctx, reg, valp);
+}
+
+int yt921x_reg_write(struct yt921x_priv *priv, u32 reg, u32 val)
+{
+ lockdep_assert_held_once(&priv->reg_lock);
+
+ return priv->reg_ops->write(priv->reg_ctx, reg, val);
+}
+
+int yt921x_reg_wait(struct yt921x_priv *priv, u32 reg, u32 mask, u32 *valp)
+{
+ u32 val;
+ int res;
+ int ret;
+
+ ret = read_poll_timeout(yt921x_reg_read, res,
+ res || (val & mask) == *valp,
+ YT921X_POLL_SLEEP_US, YT921X_POLL_TIMEOUT_US,
+ false, priv, reg, &val);
+ if (ret)
+ return ret;
+ if (res)
+ return res;
+
+ *valp = val;
+ return 0;
+}
+
+int yt921x_reg_update_bits(struct yt921x_priv *priv, u32 reg, u32 mask, u32 val)
+{
+ int res;
+ u32 v;
+ u32 u;
+
+ res = yt921x_reg_read(priv, reg, &v);
+ if (res)
+ return res;
+
+ u = v;
+ u &= ~mask;
+ u |= val;
+ if (u == v)
+ return 0;
+
+ return yt921x_reg_write(priv, reg, u);
+}
+
+int
+yt921x_regs_read(struct yt921x_priv *priv, u32 reg, u32 *vals,
+ unsigned int num_regs)
+{
+ int res;
+
+ for (unsigned int i = 0; i < num_regs; i++) {
+ res = yt921x_reg_read(priv, reg + 4 * i, &vals[i]);
+ if (res)
+ return res;
+ }
+
+ return 0;
+}
+
+int
+yt921x_regs_write(struct yt921x_priv *priv, u32 reg, const u32 *vals,
+ unsigned int num_regs)
+{
+ int res;
+
+ for (unsigned int i = 0; i < num_regs; i++) {
+ res = yt921x_reg_write(priv, reg + 4 * i, vals[i]);
+ if (res)
+ return res;
+ }
+
+ return 0;
+}
+
+int
+yt921x_regs_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
+ const u32 *vals, unsigned int num_regs)
+{
+ bool changed = false;
+ u32 vs[4];
+ int res;
+
+ if (WARN_ON_ONCE(num_regs > ARRAY_SIZE(vs)))
+ return -EINVAL;
+
+ res = yt921x_regs_read(priv, reg, vs, num_regs);
+ if (res)
+ return res;
+
+ for (unsigned int i = 0; i < num_regs; i++) {
+ u32 u = vs[i];
+
+ u &= ~masks[i];
+ u |= vals[i];
+ if (u != vs[i])
+ changed = true;
+
+ vs[i] = u;
+ }
+
+ if (!changed)
+ return 0;
+
+ return yt921x_regs_write(priv, reg, vs, num_regs);
+}
+
+int
+yt921x_regs_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
+ unsigned int num_regs)
+{
+ bool changed = false;
+ u32 vs[4];
+ int res;
+
+ if (WARN_ON_ONCE(num_regs > ARRAY_SIZE(vs)))
+ return -EINVAL;
+
+ res = yt921x_regs_read(priv, reg, vs, num_regs);
+ if (res)
+ return res;
+
+ for (unsigned int i = 0; i < num_regs; i++) {
+ u32 u = vs[i];
+
+ u &= ~masks[i];
+ if (u != vs[i])
+ changed = true;
+
+ vs[i] = u;
+ }
+
+ if (!changed)
+ return 0;
+
+ return yt921x_regs_write(priv, reg, vs, num_regs);
+}
diff --git a/drivers/net/dsa/motorcomm/smi.h b/drivers/net/dsa/motorcomm/smi.h
new file mode 100644
index 000000000000..2e956065eb90
--- /dev/null
+++ b/drivers/net/dsa/motorcomm/smi.h
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2026 David Yang
+ */
+
+#ifndef _YT_SMI_H
+#define _YT_SMI_H
+
+#include <linux/types.h>
+#include <linux/wordpart.h>
+
+struct yt921x_priv;
+
+int yt921x_reg_read(struct yt921x_priv *priv, u32 reg, u32 *valp);
+int yt921x_reg_write(struct yt921x_priv *priv, u32 reg, u32 val);
+int yt921x_reg_wait(struct yt921x_priv *priv, u32 reg, u32 mask, u32 *valp);
+int yt921x_reg_update_bits(struct yt921x_priv *priv, u32 reg, u32 mask,
+ u32 val);
+
+static inline int
+yt921x_reg_set_bits(struct yt921x_priv *priv, u32 reg, u32 mask)
+{
+ return yt921x_reg_update_bits(priv, reg, 0, mask);
+}
+
+static inline int
+yt921x_reg_clear_bits(struct yt921x_priv *priv, u32 reg, u32 mask)
+{
+ return yt921x_reg_update_bits(priv, reg, mask, 0);
+}
+
+static inline int
+yt921x_reg_toggle_bits(struct yt921x_priv *priv, u32 reg, u32 mask, bool set)
+{
+ return yt921x_reg_update_bits(priv, reg, mask, !set ? 0 : mask);
+}
+
+/* Some multi-word registers, like VLANn_CTRL, should be treated as a single
+ * long register. More specifically, writes to parts of its words won't become
+ * visible, until the last word is written.
+ *
+ * Here we require full read and write operations over these registers to
+ * eliminate potential issues, although partial reads/writes are also possible.
+ */
+
+static inline void update_ctrls_unaligned(u32 *lo, u32 *hi, u64 mask, u64 val)
+{
+ *lo &= ~lower_32_bits(mask);
+ *hi &= ~upper_32_bits(mask);
+ *lo |= lower_32_bits(val);
+ *hi |= upper_32_bits(val);
+}
+
+int yt921x_regs_read(struct yt921x_priv *priv, u32 reg, u32 *vals,
+ unsigned int num_regs);
+int yt921x_regs_write(struct yt921x_priv *priv, u32 reg, const u32 *vals,
+ unsigned int num_regs);
+int yt921x_regs_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
+ const u32 *vals, unsigned int num_regs);
+int yt921x_regs_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
+ unsigned int num_regs);
+
+static inline int
+yt921x_reg64_write(struct yt921x_priv *priv, u32 reg, const u32 *vals)
+{
+ return yt921x_regs_write(priv, reg, vals, 2);
+}
+
+static inline int
+yt921x_reg64_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
+ const u32 *vals)
+{
+ return yt921x_regs_update_bits(priv, reg, masks, vals, 2);
+}
+
+static inline int
+yt921x_reg64_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks)
+{
+ return yt921x_regs_clear_bits(priv, reg, masks, 2);
+}
+
+static inline int
+yt921x_reg96_write(struct yt921x_priv *priv, u32 reg, const u32 *vals)
+{
+ return yt921x_regs_write(priv, reg, vals, 3);
+}
+
+#endif
--
2.53.0
^ permalink raw reply related
* [PATCH net-next v5 3/3] net: dsa: motorcomm: Add LED support
From: David Yang @ 2026-07-07 6:47 UTC (permalink / raw)
To: netdev
Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
In-Reply-To: <20260707064752.1030345-1-mmyangfl@gmail.com>
LEDs can be described in the device tree using the same format as qca8k.
Each port can configure up to 3 LEDs.
Currently, only parallel mode and strict 1:1 mapping are supported.
Signed-off-by: David Yang <mmyangfl@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/motorcomm/Kconfig | 9 +
drivers/net/dsa/motorcomm/Makefile | 1 +
drivers/net/dsa/motorcomm/chip.c | 13 +-
drivers/net/dsa/motorcomm/chip.h | 14 +-
drivers/net/dsa/motorcomm/leds.c | 615 +++++++++++++++++++++++++++++
drivers/net/dsa/motorcomm/leds.h | 121 ++++++
6 files changed, 770 insertions(+), 3 deletions(-)
create mode 100644 drivers/net/dsa/motorcomm/leds.c
create mode 100644 drivers/net/dsa/motorcomm/leds.h
diff --git a/drivers/net/dsa/motorcomm/Kconfig b/drivers/net/dsa/motorcomm/Kconfig
index 1fddd386f866..3438e0b14361 100644
--- a/drivers/net/dsa/motorcomm/Kconfig
+++ b/drivers/net/dsa/motorcomm/Kconfig
@@ -6,3 +6,12 @@ config NET_DSA_YT921X
help
This enables support for the Motorcomm YT9215 ethernet switch
chip.
+
+config NET_DSA_YT921X_LEDS
+ bool "LED support for Motorcomm YT9215"
+ default y
+ depends on NET_DSA_YT921X
+ depends on LEDS_CLASS=y || LEDS_CLASS=NET_DSA_YT921X
+ help
+ This enables support for controlling the LEDs attached to the
+ Motorcomm YT9215 switch chips.
diff --git a/drivers/net/dsa/motorcomm/Makefile b/drivers/net/dsa/motorcomm/Makefile
index 6cea5313a444..5a63db0029ff 100644
--- a/drivers/net/dsa/motorcomm/Makefile
+++ b/drivers/net/dsa/motorcomm/Makefile
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: ISC
obj-$(CONFIG_NET_DSA_YT921X) += yt921x.o
yt921x-objs := chip.o
+yt921x-$(CONFIG_NET_DSA_YT921X_LEDS) += leds.o
yt921x-objs += smi.o
diff --git a/drivers/net/dsa/motorcomm/chip.c b/drivers/net/dsa/motorcomm/chip.c
index 6dee25b6754a..553efacd4f5e 100644
--- a/drivers/net/dsa/motorcomm/chip.c
+++ b/drivers/net/dsa/motorcomm/chip.c
@@ -26,6 +26,7 @@
#include <net/pkt_cls.h>
#include "chip.h"
+#include "leds.h"
#include "smi.h"
struct yt921x_mib_desc {
@@ -151,8 +152,6 @@ static const struct yt921x_info yt921x_infos[] = {
{}
};
-#define YT921X_NAME "yt921x"
-
#define YT921X_VID_UNWARE 4095
/* The interval should be small enough to avoid overflow of 32bit MIBs.
@@ -4581,6 +4580,12 @@ static int yt921x_dsa_setup(struct dsa_switch *ds)
if (res)
return res;
+#if IS_ENABLED(CONFIG_NET_DSA_YT921X_LEDS)
+ res = yt921x_leds_setup(priv);
+ if (res)
+ dev_warn(dev, "Failed to setup LEDs: %d\n", res);
+#endif
+
return 0;
}
@@ -4681,6 +4686,10 @@ static void yt921x_mdio_remove(struct mdio_device *mdiodev)
if (!priv)
return;
+#if IS_ENABLED(CONFIG_NET_DSA_YT921X_LEDS)
+ yt921x_leds_remove(priv);
+#endif
+
for (size_t i = ARRAY_SIZE(priv->ports); i-- > 0; ) {
struct yt921x_port *pp = &priv->ports[i];
diff --git a/drivers/net/dsa/motorcomm/chip.h b/drivers/net/dsa/motorcomm/chip.h
index 555046526669..6570ae5902ad 100644
--- a/drivers/net/dsa/motorcomm/chip.h
+++ b/drivers/net/dsa/motorcomm/chip.h
@@ -850,8 +850,13 @@ enum yt921x_fdb_entry_status {
#define YT921X_ACL_NUM (YT921X_ACL_BLK_NUM * YT921X_ACL_ENT_PER_BLK)
#define YT921X_UDF_NUM 8
+#define YT921X_LED_GROUP_NUM 3
+
/* 8 internal + 2 external + 1 mcu */
-#define YT921X_PORT_NUM 11
+#define YT921X_PORT_NUM 11
+#define YT921X_PORT_MCU 10
+
+#define YT921X_NAME "yt921x"
#define yt921x_port_is_internal(port) ((port) < 8)
#define yt921x_port_is_external(port) (8 <= (port) && (port) < 9)
@@ -938,6 +943,13 @@ struct yt921x_port {
struct yt921x_mib mib;
u64 rx_frames;
u64 tx_frames;
+
+#if IS_ENABLED(CONFIG_NET_DSA_YT921X_LEDS)
+ unsigned char led_duty;
+ unsigned short led_cycle;
+
+ struct yt921x_led *leds[YT921X_LED_GROUP_NUM];
+#endif
};
struct yt921x_reg_ops {
diff --git a/drivers/net/dsa/motorcomm/leds.c b/drivers/net/dsa/motorcomm/leds.c
new file mode 100644
index 000000000000..d2e68e2f21d6
--- /dev/null
+++ b/drivers/net/dsa/motorcomm/leds.c
@@ -0,0 +1,615 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2026 David Yang
+ */
+
+#include <linux/uleds.h>
+
+#include "chip.h"
+#include "leds.h"
+#include "smi.h"
+
+#define to_yt921x_led(led_cdev) \
+ container_of_const((led_cdev), struct yt921x_led, cdev)
+#define to_yt921x_port(led) ((led)->port)
+#define to_yt921x_priv(pp) \
+ container_of_const((pp), struct yt921x_priv, ports[(pp)->index])
+#define to_device(priv) ((priv)->ds.dev)
+
+static u32 yt921x_led_regaddr(struct yt921x_priv *priv, int port, int group)
+{
+ switch (group) {
+ case 0:
+ default:
+ return YT921X_LED0_PORTn(port);
+ case 1:
+ return YT921X_LED1_PORTn(port);
+ case 2:
+ return YT921X_LED2_PORTn(port);
+ }
+}
+
+static int
+yt921x_led_force_get(struct yt921x_priv *priv, int port, int group, bool *onp)
+{
+ u32 val;
+ int res;
+
+ res = yt921x_reg_read(priv, YT921X_LED2_PORTn(port), &val);
+ if (res)
+ return res;
+
+ *onp = (val & YT921X_LED2_PORT_FORCEn_M(group)) ==
+ YT921X_LED2_PORT_FORCEn_ON(group);
+ return 0;
+}
+
+static int
+yt921x_led_force_set(struct yt921x_priv *priv, int port, int group, bool on)
+{
+ struct yt921x_port *pp = &priv->ports[port];
+ struct yt921x_led *led = pp->leds[group];
+ u32 ctrl;
+ u32 mask;
+
+ led->use_cycle = false;
+ led->use_duty = false;
+
+ mask = YT921X_LED2_PORT_FORCEn_M(group);
+ ctrl = on ? YT921X_LED2_PORT_FORCEn_ON(group) :
+ YT921X_LED2_PORT_FORCEn_OFF(group);
+ return yt921x_reg_update_bits(priv, YT921X_LED2_PORTn(port), mask,
+ ctrl);
+}
+
+static int
+yt921x_led_blink_select(const struct yt921x_priv *priv, unsigned long on,
+ unsigned long off, unsigned short *cyclep,
+ unsigned char *dutyp)
+{
+ static const unsigned char dutys[] = {
+ YT921X_LED_DUTY(1, 6),
+ YT921X_LED_DUTY(1, 4),
+ YT921X_LED_DUTY(1, 3),
+ YT921X_LED_DUTY(1, 2),
+ };
+ unsigned int cycle_upper;
+ unsigned int cycle_req;
+ unsigned int duty_req;
+ unsigned int cycle;
+ unsigned int duty;
+
+ cycle = YT921X_LED_BLINK_MAX;
+ cycle_upper = cycle * 11585 / 8192 + 1; /* M_SQRT2 * cycle */
+ if (check_add_overflow(on, off, &cycle_req) || cycle_req >= cycle_upper)
+ return -EOPNOTSUPP;
+
+ for (; cycle > YT921X_LED_BLINK_MIN; cycle_upper >>= 1, cycle >>= 1)
+ if (cycle_req >= cycle_upper >> 1)
+ break;
+ *cyclep = cycle;
+
+ duty_req = DIV_ROUND_CLOSEST(YT921X_LED_DUTY_DENOM *
+ (on > off ? off : on), cycle_req);
+ for (unsigned int i = ARRAY_SIZE(dutys) - 1;; i--)
+ if (i == 0 || duty_req >= (dutys[i - 1] + dutys[i]) / 2) {
+ duty = dutys[i];
+ break;
+ }
+ if (on > off)
+ duty = YT921X_LED_DUTY_DENOM - duty;
+ *dutyp = duty;
+
+ return 0;
+}
+
+static int
+yt921x_led_blink_set(struct yt921x_priv *priv, int port, int group,
+ unsigned long *onp, unsigned long *offp)
+{
+ struct yt921x_port *pp = &priv->ports[port];
+ struct yt921x_led *led = pp->leds[group];
+ unsigned short cycle;
+ unsigned char duty;
+ bool use_cycle;
+ u32 ctrl;
+ u32 mask;
+ u32 val;
+ int res;
+
+ if (!*onp && !*offp) {
+ cycle = YT921X_LED_BLINK_DEF;
+ duty = YT921X_LED_DUTY(1, 2);
+ for (unsigned int i = 0; i < YT921X_LED_GROUP_NUM; i++)
+ if (i != group && pp->leds[i] &&
+ pp->leds[i]->use_duty) {
+ duty = pp->led_duty;
+ break;
+ }
+
+ use_cycle = false;
+ } else {
+ bool change_cycle;
+ bool change_duty;
+
+ res = yt921x_led_blink_select(priv, *onp, *offp, &cycle, &duty);
+ if (res)
+ return res;
+
+ use_cycle = cycle < YT921X_LED_BLINK_DEF;
+ change_cycle = use_cycle && cycle != pp->led_cycle;
+ change_duty = duty != pp->led_duty;
+ if (change_cycle || change_duty)
+ for (unsigned int i = 0; i < YT921X_LED_GROUP_NUM;
+ i++) {
+ if (i == group || !pp->leds[i])
+ continue;
+ if ((change_cycle && pp->leds[i]->use_cycle) ||
+ (change_duty && pp->leds[i]->use_duty))
+ return -EOPNOTSUPP;
+ }
+ }
+
+ /* The chip seems to jam a while if changing duty directly */
+ res = yt921x_reg_read(priv, YT921X_LED2_PORTn(port), &val);
+ if (res)
+ return res;
+
+ ctrl = val & ~YT921X_LED2_PORT_FORCEn_M(group);
+ ctrl |= YT921X_LED2_PORT_FORCEn_DONTCARE(group);
+ if (val != ctrl) {
+ res = yt921x_reg_write(priv, YT921X_LED2_PORTn(port), ctrl);
+ if (res)
+ return res;
+ }
+
+ mask = YT921X_LED1_PORT_BLINK_DUTY_M | YT921X_LED1_PORT_BLINK_DUTY_COMP;
+ switch (duty >= YT921X_LED_DUTY(1, 2) ? duty :
+ YT921X_LED_DUTY_DENOM - duty) {
+ default:
+ duty = YT921X_LED_DUTY(1, 2);
+ fallthrough;
+ case YT921X_LED_DUTY(1, 2):
+ ctrl = YT921X_LED1_PORT_BLINK_DUTY_1_2;
+ break;
+ case YT921X_LED_DUTY(2, 3):
+ ctrl = YT921X_LED1_PORT_BLINK_DUTY_2_3;
+ break;
+ case YT921X_LED_DUTY(3, 4):
+ ctrl = YT921X_LED1_PORT_BLINK_DUTY_3_4;
+ break;
+ case YT921X_LED_DUTY(5, 6):
+ ctrl = YT921X_LED1_PORT_BLINK_DUTY_5_6;
+ break;
+ }
+ if (duty < YT921X_LED_DUTY(1, 2))
+ ctrl |= YT921X_LED1_PORT_BLINK_DUTY_COMP;
+ if (use_cycle) {
+ mask |= YT921X_LED1_PORT_OTHER_BLINK_M;
+ ctrl |= YT921X_LED1_PORT_OTHER_BLINK(9 - __fls(cycle));
+ }
+ res = yt921x_reg_update_bits(priv, YT921X_LED1_PORTn(port), mask, ctrl);
+ if (res)
+ return res;
+
+ ctrl = val & ~(YT921X_LED2_PORT_FORCEn_M(group) |
+ YT921X_LED2_PORT_FORCE_BLINKn_M(group));
+ ctrl |= YT921X_LED2_PORT_FORCEn_BLINK(group);
+ if (use_cycle)
+ ctrl |= YT921X_LED2_PORT_FORCE_BLINKn_OTHER(group);
+ else
+ ctrl |= YT921X_LED2_PORT_FORCE_BLINKn(group, __fls(cycle) - 9);
+ res = yt921x_reg_write(priv, YT921X_LED2_PORTn(port), ctrl);
+ if (res)
+ return res;
+
+ led->use_cycle = use_cycle;
+ if (use_cycle)
+ pp->led_cycle = cycle;
+ led->use_duty = true;
+ pp->led_duty = duty;
+
+ *onp = DIV_ROUND_CLOSEST(duty * cycle, YT921X_LED_DUTY_DENOM);
+ *offp = cycle - *onp;
+ return 0;
+}
+
+static const u32 yt921x_led_trigger_maps[__TRIGGER_NETDEV_MAX] = {
+ [TRIGGER_NETDEV_LINK] = YT921X_LEDx_PORT_ACT_DUPLEX_HALF |
+ YT921X_LEDx_PORT_ACT_DUPLEX_FULL,
+ [TRIGGER_NETDEV_LINK_10] = YT921X_LEDx_PORT_ACT_10M,
+ [TRIGGER_NETDEV_LINK_100] = YT921X_LEDx_PORT_ACT_100M,
+ [TRIGGER_NETDEV_LINK_1000] = YT921X_LEDx_PORT_ACT_1000M,
+ [TRIGGER_NETDEV_HALF_DUPLEX] = YT921X_LEDx_PORT_ACT_DUPLEX_HALF,
+ [TRIGGER_NETDEV_FULL_DUPLEX] = YT921X_LEDx_PORT_ACT_DUPLEX_FULL,
+ [TRIGGER_NETDEV_TX] = YT921X_LEDx_PORT_ACT_TX,
+ [TRIGGER_NETDEV_RX] = YT921X_LEDx_PORT_ACT_RX,
+};
+
+static bool
+yt921x_led_trigger_is_supported(const struct yt921x_priv *priv, int port,
+ int group, unsigned long flags)
+{
+ unsigned int i;
+
+ for_each_set_bit(i, &flags, __TRIGGER_NETDEV_MAX)
+ if (!yt921x_led_trigger_maps[i])
+ return false;
+
+ return true;
+}
+
+static int
+yt921x_led_trigger_get(struct yt921x_priv *priv, int port, int group,
+ unsigned long *flagsp)
+{
+ u32 addr;
+ u32 val;
+ int res;
+
+ res = yt921x_reg_read(priv, YT921X_LED2_PORTn(port), &val);
+ if (res)
+ return res;
+
+ if ((val & YT921X_LED2_PORT_FORCEn_M(group)) !=
+ YT921X_LED2_PORT_FORCEn_DONTCARE(group)) {
+ *flagsp = 0;
+ return 0;
+ }
+
+ if (group != 2) {
+ addr = yt921x_led_regaddr(priv, port, group);
+ res = yt921x_reg_read(priv, addr, &val);
+ if (res)
+ return res;
+ }
+
+ *flagsp = 0;
+ for (unsigned int i = 0; i < __TRIGGER_NETDEV_MAX; i++) {
+ u32 mask = yt921x_led_trigger_maps[i];
+
+ if (mask && (val & mask) == mask)
+ *flagsp |= BIT(i);
+ }
+
+ return 0;
+}
+
+static int
+yt921x_led_trigger_set(struct yt921x_priv *priv, int port, int group,
+ unsigned long flags)
+{
+ struct yt921x_port *pp = &priv->ports[port];
+ struct yt921x_led *led = pp->leds[group];
+ unsigned int i;
+ u32 addr;
+ u32 ctrl;
+ u32 mask;
+ int res;
+
+ ctrl = 0;
+ for_each_set_bit(i, &flags, __TRIGGER_NETDEV_MAX) {
+ if (!yt921x_led_trigger_maps[i])
+ return -EOPNOTSUPP;
+
+ ctrl |= yt921x_led_trigger_maps[i];
+ }
+
+ led->use_cycle = false;
+ led->use_duty = false;
+
+ mask = !group ? YT921X_LED0_PORT_ACT_M : YT921X_LEDx_PORT_ACT_M;
+ if (group == 2) {
+ mask |= YT921X_LED2_PORT_FORCEn_M(group);
+ ctrl |= YT921X_LED2_PORT_FORCEn_DONTCARE(group);
+ }
+ addr = yt921x_led_regaddr(priv, port, group);
+ res = yt921x_reg_update_bits(priv, addr, mask, ctrl);
+ if (res)
+ return res;
+
+ if (group != 2) {
+ mask = YT921X_LED2_PORT_FORCEn_M(group);
+ ctrl = YT921X_LED2_PORT_FORCEn_DONTCARE(group);
+ res = yt921x_reg_update_bits(priv, YT921X_LED2_PORTn(port),
+ mask, ctrl);
+ if (res)
+ return res;
+ }
+
+ return 0;
+}
+
+static int
+yt921x_cled_brightness_set_blocking(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct yt921x_led *led = to_yt921x_led(led_cdev);
+ struct yt921x_port *pp = to_yt921x_port(led);
+ struct yt921x_priv *priv = to_yt921x_priv(pp);
+ int res;
+
+ mutex_lock(&priv->reg_lock);
+ res = yt921x_led_force_set(priv, pp->index, led->group, brightness);
+ mutex_unlock(&priv->reg_lock);
+
+ return res;
+}
+
+static int
+yt921x_cled_blink_set(struct led_classdev *led_cdev, unsigned long *delay_on,
+ unsigned long *delay_off)
+{
+ struct yt921x_led *led = to_yt921x_led(led_cdev);
+ struct yt921x_port *pp = to_yt921x_port(led);
+ struct yt921x_priv *priv = to_yt921x_priv(pp);
+ int res;
+
+ mutex_lock(&priv->reg_lock);
+ res = yt921x_led_blink_set(priv, pp->index, led->group, delay_on,
+ delay_off);
+ mutex_unlock(&priv->reg_lock);
+
+ return res;
+}
+
+static struct device * __maybe_unused
+yt921x_cled_hw_control_get_device(struct led_classdev *led_cdev)
+{
+ struct yt921x_led *led = to_yt921x_led(led_cdev);
+ struct yt921x_port *pp = to_yt921x_port(led);
+ struct yt921x_priv *priv = to_yt921x_priv(pp);
+ struct dsa_port *dp;
+
+ dp = dsa_to_port(&priv->ds, pp->index);
+ if (!dp || !dp->user)
+ return NULL;
+ return &dp->user->dev;
+}
+
+static int __maybe_unused
+yt921x_cled_hw_control_is_supported(struct led_classdev *led_cdev,
+ unsigned long flags)
+{
+ struct yt921x_led *led = to_yt921x_led(led_cdev);
+ struct yt921x_port *pp = to_yt921x_port(led);
+ struct yt921x_priv *priv = to_yt921x_priv(pp);
+
+ if (yt921x_led_trigger_is_supported(priv, pp->index, led->group, flags))
+ return 0;
+ return -EOPNOTSUPP;
+}
+
+static int __maybe_unused
+yt921x_cled_hw_control_get(struct led_classdev *led_cdev, unsigned long *flagsp)
+{
+ struct yt921x_led *led = to_yt921x_led(led_cdev);
+ struct yt921x_port *pp = to_yt921x_port(led);
+ struct yt921x_priv *priv = to_yt921x_priv(pp);
+ int res;
+
+ mutex_lock(&priv->reg_lock);
+ res = yt921x_led_trigger_get(priv, pp->index, led->group, flagsp);
+ mutex_unlock(&priv->reg_lock);
+
+ return res;
+}
+
+static int __maybe_unused
+yt921x_cled_hw_control_set(struct led_classdev *led_cdev, unsigned long flags)
+{
+ struct yt921x_led *led = to_yt921x_led(led_cdev);
+ struct yt921x_port *pp = to_yt921x_port(led);
+ struct yt921x_priv *priv = to_yt921x_priv(pp);
+ int res;
+
+ mutex_lock(&priv->reg_lock);
+ res = yt921x_led_trigger_set(priv, pp->index, led->group, flags);
+ mutex_unlock(&priv->reg_lock);
+
+ return res;
+}
+
+static int
+yt921x_led_setup(struct yt921x_priv *priv, int port,
+ struct fwnode_handle *fwnode, u32 *inv_maskp, u32 *inv_ctrlp)
+{
+ struct yt921x_port *pp = &priv->ports[port];
+ struct device *dev = to_device(priv);
+ struct led_init_data init_data;
+ struct led_classdev *led_cdev;
+ char name[LED_MAX_NAME_SIZE];
+ enum led_default_state state;
+ struct yt921x_led *led;
+ bool force_high;
+ bool force_low;
+ int polarity;
+ u32 group;
+ bool on;
+ int res;
+
+ if (port == YT921X_PORT_MCU) {
+ dev_err(dev, "No LEDs for port %d\n", port);
+ return -ENODEV;
+ }
+
+ res = fwnode_property_read_u32(fwnode, "reg", &group);
+ if (res)
+ return res;
+ if (group >= YT921X_LED_GROUP_NUM) {
+ dev_err(dev, "Invalid LED reg %u for port %d\n", group, port);
+ return -EINVAL;
+ }
+ if (pp->leds[group])
+ return -EEXIST;
+
+ force_high = fwnode_property_read_bool(fwnode, "active-high");
+ force_low = fwnode_property_read_bool(fwnode, "active-low");
+ if (force_high && force_low) {
+ dev_err(dev, "Duplicate polarities for LED %02d:%02u\n",
+ port, group);
+ return -EINVAL;
+ }
+ polarity = force_high ? 1 : force_low ? -1 : 0;
+
+ led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
+ if (!led)
+ return -ENOMEM;
+ led->port = pp;
+ led->group = group;
+
+ state = led_init_default_state_get(fwnode);
+
+ mutex_lock(&priv->reg_lock);
+ pp->leds[group] = led;
+ switch (state) {
+ case LEDS_DEFSTATE_OFF:
+ case LEDS_DEFSTATE_ON:
+ default:
+ on = state == LEDS_DEFSTATE_ON;
+ res = yt921x_led_force_set(priv, port, group, on);
+ break;
+ case LEDS_DEFSTATE_KEEP:
+ res = yt921x_led_force_get(priv, port, group, &on);
+ break;
+ }
+ mutex_unlock(&priv->reg_lock);
+ if (res)
+ goto err;
+
+ led_cdev = &led->cdev;
+ led_cdev->brightness = on;
+ led_cdev->max_brightness = 1;
+ led_cdev->flags = LED_RETAIN_AT_SHUTDOWN;
+ led_cdev->brightness_set_blocking = yt921x_cled_brightness_set_blocking;
+ led_cdev->blink_set = yt921x_cled_blink_set;
+#ifdef CONFIG_LEDS_TRIGGERS
+ led_cdev->hw_control_trigger = "netdev";
+ led_cdev->hw_control_get_device = yt921x_cled_hw_control_get_device;
+ led_cdev->hw_control_is_supported = yt921x_cled_hw_control_is_supported;
+ led_cdev->hw_control_get = yt921x_cled_hw_control_get;
+ led_cdev->hw_control_set = yt921x_cled_hw_control_set;
+#endif
+
+ snprintf(name, sizeof(name), YT921X_NAME "-%u:%02d:%02u",
+ priv->ds.index, port, group);
+ init_data = (typeof(init_data)){
+ .fwnode = fwnode,
+ .devicename = name,
+ .devname_mandatory = true,
+ };
+ res = devm_led_classdev_register_ext(dev, led_cdev, &init_data);
+ if (res)
+ goto err;
+
+ if (polarity) {
+ u32 bit = YT921X_LED_PAR_INV_INVnm(group, port);
+
+ *inv_maskp |= bit;
+ if (polarity > 0)
+ *inv_ctrlp |= bit;
+ }
+ return 0;
+
+err:
+ mutex_lock(&priv->reg_lock);
+ pp->leds[group] = NULL;
+ mutex_unlock(&priv->reg_lock);
+
+ devm_kfree(dev, led);
+ return res;
+}
+
+void yt921x_leds_remove(struct yt921x_priv *priv)
+{
+ struct device *dev = to_device(priv);
+
+ for (int port = 0; port < YT921X_PORT_NUM; port++) {
+ struct yt921x_port *pp = &priv->ports[port];
+
+ for (int group = 0; group < YT921X_LED_GROUP_NUM; group++) {
+ struct yt921x_led *led = pp->leds[group];
+
+ if (led)
+ devm_led_classdev_unregister(dev, &led->cdev);
+ }
+ }
+
+ for (int port = 0; port < YT921X_PORT_NUM; port++) {
+ struct yt921x_port *pp = &priv->ports[port];
+
+ for (int group = 0; group < YT921X_LED_GROUP_NUM; group++) {
+ struct yt921x_led *led = pp->leds[group];
+
+ if (led) {
+ pp->leds[group] = NULL;
+ devm_kfree(dev, led);
+ }
+ }
+ }
+}
+
+int yt921x_leds_setup(struct yt921x_priv *priv)
+{
+ struct dsa_switch *ds = &priv->ds;
+ struct dsa_port *dp;
+ u32 inv_ctrl = 0;
+ u32 inv_mask = 0;
+ u32 ctrl;
+ u32 mask;
+ int res;
+
+ dsa_switch_for_each_port(dp, ds) {
+ struct device_node *leds_np;
+ int port = dp->index;
+
+ if (!dp->dn)
+ continue;
+
+ leds_np = of_get_child_by_name(dp->dn, "leds");
+ if (!leds_np)
+ continue;
+
+ for_each_child_of_node_scoped(leds_np, led_np) {
+ res = yt921x_led_setup(priv, port,
+ of_fwnode_handle(led_np),
+ &inv_mask, &inv_ctrl);
+ if (res) {
+ of_node_put(leds_np);
+ goto err;
+ }
+ }
+
+ of_node_put(leds_np);
+ }
+
+ mutex_lock(&priv->reg_lock);
+
+ mask = YT921X_LED_CTRL_MODE_M | YT921X_LED_CTRL_PORT_NUM_M |
+ YT921X_LED_CTRL_EN;
+ ctrl = YT921X_LED_CTRL_MODE_PARALLEL |
+ YT921X_LED_CTRL_PORT_NUM(YT921X_PORT_NUM - 1) |
+ YT921X_LED_CTRL_EN;
+ res = yt921x_reg_update_bits(priv, YT921X_LED_CTRL, mask, ctrl);
+ if (res)
+ goto end;
+
+ /* Inversion is internal - force on will give low logic.
+ * In the rest of the file, treat LEDs as if active-low.
+ */
+ if (inv_mask)
+ res = yt921x_reg_update_bits(priv, YT921X_LED_PAR_INV, inv_mask,
+ inv_ctrl);
+
+end:
+ mutex_unlock(&priv->reg_lock);
+
+ if (res)
+ goto err;
+
+ return 0;
+
+err:
+ yt921x_leds_remove(priv);
+ return res;
+}
diff --git a/drivers/net/dsa/motorcomm/leds.h b/drivers/net/dsa/motorcomm/leds.h
new file mode 100644
index 000000000000..67373a190c8f
--- /dev/null
+++ b/drivers/net/dsa/motorcomm/leds.h
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2026 David Yang
+ */
+
+#ifndef _YT_LEDS_H
+#define _YT_LEDS_H
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/kconfig.h>
+#include <linux/leds.h>
+
+#define YT921X_LED_CTRL 0xd0000
+#define YT921X_LED_CTRL_EN BIT(21)
+#define YT921X_LED_CTRL_LOOPDETECT_BLINK_M GENMASK(20, 19) /* cycle = 512 * x ms */
+#define YT921X_LED_CTRL_LOOPDETECT_BLINK(x) FIELD_PREP(YT921X_LED_CTRL_LOOPDETECT_BLINK_M, (x))
+#define YT921X_LED_CTRL_PORT_NUM_M GENMASK(16, 13)
+#define YT921X_LED_CTRL_PORT_NUM(x) FIELD_PREP(YT921X_LED_CTRL_PORT_NUM_M, (x))
+#define YT921X_LED_CTRL_MODE_M GENMASK(1, 0)
+#define YT921X_LED_CTRL_MODE(x) FIELD_PREP(YT921X_LED_CTRL_MODE_M, (x))
+#define YT921X_LED_CTRL_MODE_PARALLEL YT921X_LED_CTRL_MODE(0)
+#define YT921X_LED_CTRL_MODE_SERIAL YT921X_LED_CTRL_MODE(2)
+#define YT921X_LED0_PORTn(port) (0xd0004 + 4 * (port))
+#define YT921X_LED0_PORT_ACT_M GENMASK(17, 0)
+#define YT921X_LED0_PORT_ACT_LINK_TRY_DIS BIT(17)
+#define YT921X_LED0_PORT_ACT_COLLISION_BLINK_INDI BIT(16)
+#define YT921X_LED1_PORTn(port) (0xd0040 + 4 * (port))
+#define YT921X_LED1_PORT_OTHER_BLINK_M GENMASK(31, 30) /* cycle = 512 >> x ms */
+#define YT921X_LED1_PORT_OTHER_BLINK(x) FIELD_PREP(YT921X_LED1_PORT_OTHER_BLINK_M, (x))
+#define YT921X_LED1_PORT_EEE_BLINK_M GENMASK(29, 28) /* cycle = 512 >> x ms */
+#define YT921X_LED1_PORT_EEE_BLINK(x) FIELD_PREP(YT921X_LED1_PORT_EEE_BLINK_M, (x))
+#define YT921X_LED1_PORT_BLINK_DUTY_COMP BIT(27)
+#define YT921X_LED1_PORT_BLINK_DUTY_M GENMASK(26, 25)
+#define YT921X_LED1_PORT_BLINK_DUTY(x) FIELD_PREP(YT921X_LED1_PORT_BLINK_DUTY_M, (x))
+#define YT921X_LED1_PORT_BLINK_DUTY_1_2 YT921X_LED1_PORT_BLINK_DUTY(0)
+#define YT921X_LED1_PORT_BLINK_DUTY_2_3 YT921X_LED1_PORT_BLINK_DUTY(1)
+#define YT921X_LED1_PORT_BLINK_DUTY_3_4 YT921X_LED1_PORT_BLINK_DUTY(2)
+#define YT921X_LED1_PORT_BLINK_DUTY_5_6 YT921X_LED1_PORT_BLINK_DUTY(3)
+#define YT921X_LED2_PORTn(port) (0xd0080 + 4 * (port))
+#define YT921X_LED2_PORT_FORCEn_M(grp) GENMASK(4 * (grp) + 19, 4 * (grp) + 18)
+#define YT921X_LED2_PORT_FORCEn(grp, x) ((x) << (4 * (grp) + 18))
+#define YT921X_LED2_PORT_FORCEn_DONTCARE(grp) YT921X_LED2_PORT_FORCEn(grp, 0)
+#define YT921X_LED2_PORT_FORCEn_BLINK(grp) YT921X_LED2_PORT_FORCEn(grp, 1)
+#define YT921X_LED2_PORT_FORCEn_ON(grp) YT921X_LED2_PORT_FORCEn(grp, 2)
+#define YT921X_LED2_PORT_FORCEn_OFF(grp) YT921X_LED2_PORT_FORCEn(grp, 3)
+#define YT921X_LED2_PORT_FORCE_BLINKn_M(grp) GENMASK(4 * (grp) + 17, 4 * (grp) + 16) /* cycle = 512 << x ms */
+#define YT921X_LED2_PORT_FORCE_BLINKn(grp, x) ((x) << (4 * (grp) + 16))
+#define YT921X_LED2_PORT_FORCE_BLINKn_OTHER(grp) YT921X_LED2_PORT_FORCE_BLINKn(grp, 3)
+#define YT921X_LEDx_PORT_ACT_M GENMASK(15, 0)
+#define YT921X_LEDx_PORT_ACT_EEE_BLINK BIT(15)
+#define YT921X_LEDx_PORT_ACT_LOOPDETECT_BLINK BIT(14)
+#define YT921X_LEDx_PORT_ACT_ACTIVE_BLINK BIT(13)
+#define YT921X_LEDx_PORT_ACT_DUPLEX_FULL BIT(12)
+#define YT921X_LEDx_PORT_ACT_DUPLEX_HALF BIT(11)
+#define YT921X_LEDx_PORT_ACT_TX_BLINK BIT(10)
+#define YT921X_LEDx_PORT_ACT_RX_BLINK BIT(9)
+#define YT921X_LEDx_PORT_ACT_TX BIT(8)
+#define YT921X_LEDx_PORT_ACT_RX BIT(7)
+#define YT921X_LEDx_PORT_ACT_1000M BIT(6)
+#define YT921X_LEDx_PORT_ACT_100M BIT(5)
+#define YT921X_LEDx_PORT_ACT_10M BIT(4)
+#define YT921X_LEDx_PORT_ACT_COLLISION_BLINK BIT(3)
+#define YT921X_LEDx_PORT_ACT_1000M_BLINK BIT(2)
+#define YT921X_LEDx_PORT_ACT_100M_BLINK BIT(1)
+#define YT921X_LEDx_PORT_ACT_10M_BLINK BIT(0)
+#define YT921X_LED_SER_CTRL 0xd0100
+#define YT921X_LED_SER_CTRL_UNK GENMASK(25, 24) /* delay? */
+#define YT921X_LED_SER_CTRL_ACTIVE_LOW BIT(4)
+#define YT921X_LED_SER_CTRL_GRP_NUM_M GENMASK(1, 0) /* #grp - 1 */
+#define YT921X_LED_SER_CTRL_GRP_NUM(x) FIELD_PREP(YT921X_LED_SER_CTRL_GRP_NUM_M, (x))
+#define YT921X_LED_SER_MAPnm(grp, port) (0xd0104 + 8 * (2 - (grp)) + 4 * ((port) / 5))
+#define YT921X_LED_SER_MAP_DSTn_PORT_M(port) GENMASK(6 * ((port) % 5) + 5, 6 * ((port) % 5) + 2)
+#define YT921X_LED_SER_MAP_DSTn_PORT(port, x) ((x) << (6 * ((port) % 5) + 2))
+#define YT921X_LED_SER_MAP_DSTn_LED_M(port) GENMASK(6 * ((port) % 5) + 1, 6 * ((port) % 5))
+#define YT921X_LED_SER_MAP_DSTn_LED(port, x) ((x) << (6 * ((port) % 5)))
+#define YT921X_LED_PAR_PORTS 0xd01c4
+#define YT921X_LED_PAR_INV 0xd01c8
+#define YT921X_LED_PAR_INV_INVnm(grp, port) BIT(10 * (grp) + (port))
+#define YT921X_LED_PAR_MAPn(port) (0xd01d0 + 4 * (port))
+#define YT921X_LED_PAR_MAP_DSTn_PORT_M(grp) GENMASK(6 * (grp) + 5, 6 * (grp) + 2)
+#define YT921X_LED_PAR_MAP_DSTn_PORT(grp, x) ((x) << (6 * (grp) + 2))
+#define YT921X_LED_PAR_MAP_DSTn_LED_M(grp) GENMASK(6 * (grp) + 1, 6 * (grp))
+#define YT921X_LED_PAR_MAP_DSTn_LED(grp, x) ((x) << (6 * (grp)))
+
+#define YT921X_LED_BLINK_MIN 64
+#define YT921X_LED_BLINK_DEF 512
+#define YT921X_LED_BLINK_MAX 2048
+
+/* 2 * lcm(2, 3, 4, 6) */
+#define YT921X_LED_DUTY_DENOM 24
+#define YT921X_LED_DUTY(nom, denom) (YT921X_LED_DUTY_DENOM * (nom) / (denom))
+
+struct yt921x_priv;
+
+struct yt921x_led {
+ struct led_classdev cdev;
+ struct yt921x_port *port;
+ unsigned char group;
+
+ bool use_cycle:1;
+ bool use_duty:1;
+};
+
+#if IS_ENABLED(CONFIG_NET_DSA_YT921X_LEDS)
+
+void yt921x_leds_remove(struct yt921x_priv *priv);
+int yt921x_leds_setup(struct yt921x_priv *priv);
+
+#else
+
+static inline void yt921x_leds_remove(struct yt921x_priv *priv) {}
+
+static inline int yt921x_leds_setup(struct yt921x_priv *priv)
+{
+ return 0;
+}
+
+#endif
+
+#endif
--
2.53.0
^ permalink raw reply related
* Re: [PATCH net v2] tun/tap & vhost-net: make qdisc backpressure opt-in via IFF_BACKPRESSURE
From: Simon Schippers @ 2026-07-07 6:52 UTC (permalink / raw)
To: Brett A C Sheffield
Cc: Michael S. Tsirkin, Willem de Bruijn, Jason Wang,
David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
netdev, Simon Horman, Jonathan Corbet, Shuah Khan, Andrew Lunn,
Tim Gebauer, linux-doc, linux-kernel
In-Reply-To: <akvhhy_JpH64KrcL@karahi.librecast.net>
[-- Attachment #1: Type: text/plain, Size: 2306 bytes --]
On 7/6/26 19:10, Brett A C Sheffield wrote:
> On 2026-07-06 17:33, Simon Schippers wrote:
>> But even if we could perfectly fix the performance issues, maybe users
>> even users rely on the dropping behavior. From Brett [1]:
>>
>> "In our multicast use case data is sent by multiple threads to multiple
>> groups simultaneously, this just breaks things to the extent that a
>> <2 second test times out after 5 minutes."
>>
>> We are *not* factor 5min * 60sec/min / 2s = 150 times slower than without
>> the patchset.
>
> I didn't mean to suggest 150x slower. It would have been more correct if I'd
> simply said "the test normally takes <2s but fails to complete with the
> patchset". The 5min timeout was irrelevant detail.
>
> The iperf3 tests give a much better picture of the performance impact.
>
> I thought a simple TCP test with a familar tool might be easier than explaining
> the ways in which we're torturing multicast ;-)
Yes :D
>
>> My theory is that the sender sends a fixed amount of data
>> of which most is dropped without backpressure, which is much faster then
>> the real processing, and so the test *relies* on the tail-dropping to
>> work.
>>
>> @Brett can you maybe support this theory?
>
> The test synchronizes two blobs of data. The amount of data that needs syncing
> is fixed, but the amount sent will vary as it is encoded with RaptorQ.
>
> The test sends on several multicast groups simultaneously. Each group is a
> stream of RaptorQ encoded symbols and the receiver listens on that group until
> is has enough symbols to decode. In practice, on a local tap interface, the
> packet loss is normally zero, so the amount of data sent is more or less fixed.
Hmm seems like my theory does not really hold up :D
Brett, can you try the two attached patches here with iperf3?
I think testing with 8 and 16 threads is enough, so where there is a
regression.
The two patches are about time when to wake:
Currently we wake after consuming half the internal ring buffer.
One of the attached patches wakes after 2 cachelines (128 of 1000
packets) and the other one just wakes once the ring buffer is empty.
This would really help :)
BTW: I will try to get hands on a Ryzen 9 9950X soon (I think we have a
machine at our chair) and then try to reproduce.
Thank you!
[-- Attachment #2: 0001-tun-set-waking-threshold-to-tx_ring.batch.patch --]
[-- Type: text/x-patch, Size: 1212 bytes --]
From 87356bd512f039ea52f5f9901288d043f7ac32d9 Mon Sep 17 00:00:00 2001
From: Simon Schippers <simon.schippers@tu-dortmund.de>
Date: Tue, 7 Jul 2026 08:20:21 +0200
Subject: [PATCH] tun: set waking threshold to >= tx_ring.batch
Replace the waking threshold of >= ring.size/2 with >= tx_ring.batch
allowing an earlier call of netif_tx_wake_queue(). tx_ring.batch is
defined as r->batch = SMP_CACHE_BYTES * 2 / sizeof(*(r->queue)), meaning
a batch describes a two cachelines of the ring.
On a tap interface on a x86 system this means that instead of waking
after consuming 1000/2=500 skbs it now wakes after 64 * 2 = 128 skbs.
---
drivers/net/tun.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index ffbe6f13fb1f..691432c042d6 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -2158,7 +2158,7 @@ static void __tun_wake_queue(struct tun_struct *tun,
smp_mb();
if (netif_tx_queue_stopped(txq)) {
tfile->cons_cnt += consumed;
- if (tfile->cons_cnt >= tfile->tx_ring.size / 2 ||
+ if (tfile->cons_cnt >= tfile->tx_ring.batch ||
__ptr_ring_empty(&tfile->tx_ring)) {
netif_tx_wake_queue(txq);
tfile->cons_cnt = 0;
--
2.43.0
[-- Attachment #3: 0001-tun-tap-vhost-net-make-qdisc-backpressure-opt-in-via.patch --]
[-- Type: text/x-patch, Size: 8432 bytes --]
From dcea36e105bc2126e9c48d34f9542c22b9123f5b Mon Sep 17 00:00:00 2001
From: Simon Schippers <simon.schippers@tu-dortmund.de>
Date: Thu, 2 Jul 2026 18:21:56 +0200
Subject: [PATCH net v2] tun/tap & vhost-net: make qdisc backpressure opt-in
via IFF_BACKPRESSURE
Commit 1d6e569b7d0c ("tun/tap & vhost-net: avoid ptr_ring tail-drop
when a qdisc is present") did not show a relevant performance regression
in my testing but on Brett Sheffield's librecast testbed it shows a
significant performance drop in a IPv6 multicast testcase. The regression
can be pinpointed when multiple iperf3 UDP threads are sending. For 8
threads the performance dropped from 13.5 Gbit/s to 9.13 Gbit/s. This is
the reason why this patch makes the qdisc backpressure behavior opt-in.
One option to accomplish the opt-in would be to set the default qdisc to
noqueue at init. However this may also break userspace as users might
have chosen a custom qdisc even though most of the qdiscs did nothing
for tun/tap in the past due to missing backpressure...
This is the reason why in this patch, the flag IFF_BACKPRESSURE is
introduced instead which is required to enable the backpressure logic.
This means the stopping logic in tun_net_xmit() and the waking logic in
__tun_wake_queue() are skipped if the flag is disabled.
To avoid a possible stall due to disabling IFF_BACKPRESSURE, the new
helper tun_force_wake_queue() is implemented. The helper safely wakes the
respective netdev queue and resets cons_cnt while the consumer_lock and
the producer_lock of the ring are held. The helper is run in tun_attach()
when a queue (re)attaches, in tun_set_iff() for attached tfiles, and
in tun_queue_resize().
The documentation in tuntap.rst is updated accordingly.
Fixes: 1d6e569b7d0c ("tun/tap & vhost-net: avoid ptr_ring tail-drop when a qdisc is present")
Reported-by: Brett Sheffield <brett@librecast.net>
Closes: https://lore.kernel.org/netdev/akVnoOYQOrt8k-Gu@karahi.librecast.net/T/#u
Signed-off-by: Simon Schippers <simon.schippers@tu-dortmund.de>
---
V1 -> V2:
- Sashiko: Ensure detached queues are woken on re-attach by calling the
new tun_force_wake_queue() helper from tun_attach(), and reuse it
across the existing wake paths.
- Specify the failing test case in the commit message.
---
Documentation/networking/tuntap.rst | 17 ++++++++++
drivers/net/tun.c | 49 ++++++++++++++++++-----------
include/uapi/linux/if_tun.h | 1 +
tools/include/uapi/linux/if_tun.h | 1 +
4 files changed, 50 insertions(+), 18 deletions(-)
diff --git a/Documentation/networking/tuntap.rst b/Documentation/networking/tuntap.rst
index 4d7087f727be..599264825dd2 100644
--- a/Documentation/networking/tuntap.rst
+++ b/Documentation/networking/tuntap.rst
@@ -206,6 +206,23 @@ enable is true we enable it, otherwise we disable it::
return ioctl(fd, TUNSETQUEUE, (void *)&ifr);
}
+3.4 qdisc backpressure
+----------------------
+
+Starting with Linux 7.2, IFF_BACKPRESSURE can be set to enable qdisc
+backpressure. Without it, TX drops occur when the internal ring buffer is
+full. With it, the kernel stops the TX queue instead, letting the qdisc
+hold packets. Drops only occur as a rare race. This can benefit protocols
+like TCP that react to drops. Backpressure requires a qdisc to be
+attached and has no effect with noqueue.
+
+The TUN/TAP ring buffer size can be reduced alongside this flag to
+further shift buffering into the qdisc and reduce bufferbloat, but comes
+at possible performance cost.
+
+When running multiple network streams in parallel, the flag may reduce
+performance due to the extra overhead of the backpressure mechanism.
+
Universal TUN/TAP device driver Frequently Asked Question
=========================================================
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index ffbe6f13fb1f..62e5eab4e345 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -98,7 +98,8 @@ static void tun_default_link_ksettings(struct net_device *dev,
#define TUN_FASYNC IFF_ATTACH_QUEUE
#define TUN_FEATURES (IFF_NO_PI | IFF_ONE_QUEUE | IFF_VNET_HDR | \
- IFF_MULTI_QUEUE | IFF_NAPI | IFF_NAPI_FRAGS)
+ IFF_MULTI_QUEUE | IFF_NAPI | IFF_NAPI_FRAGS | \
+ IFF_BACKPRESSURE)
#define GOODCOPY_LEN 128
@@ -694,6 +695,20 @@ static void tun_detach_all(struct net_device *dev)
module_put(THIS_MODULE);
}
+static void tun_force_wake_queue(struct tun_struct *tun,
+ struct tun_file *tfile)
+{
+ /* Ensure that the producer can not stop the
+ * queue concurrently by taking locks.
+ */
+ spin_lock_bh(&tfile->tx_ring.consumer_lock);
+ spin_lock(&tfile->tx_ring.producer_lock);
+ netif_wake_subqueue(tun->dev, tfile->queue_index);
+ tfile->cons_cnt = 0;
+ spin_unlock(&tfile->tx_ring.producer_lock);
+ spin_unlock_bh(&tfile->tx_ring.consumer_lock);
+}
+
static int tun_attach(struct tun_struct *tun, struct file *file,
bool skip_filter, bool napi, bool napi_frags,
bool publish_tun)
@@ -737,11 +752,9 @@ static int tun_attach(struct tun_struct *tun, struct file *file,
goto out;
}
- spin_lock(&tfile->tx_ring.consumer_lock);
- tfile->cons_cnt = 0;
- spin_unlock(&tfile->tx_ring.consumer_lock);
tfile->queue_index = tun->numqueues;
tfile->socket.sk->sk_shutdown &= ~RCV_SHUTDOWN;
+ tun_force_wake_queue(tun, tfile);
if (tfile->detached) {
/* Re-attach detached tfile, updating XDP queue_index */
@@ -1077,7 +1090,8 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
spin_lock(&tfile->tx_ring.producer_lock);
ret = __ptr_ring_produce(&tfile->tx_ring, skb);
- if (!qdisc_txq_has_no_queue(queue) &&
+ if ((tun->flags & IFF_BACKPRESSURE) &&
+ !qdisc_txq_has_no_queue(queue) &&
__ptr_ring_check_produce(&tfile->tx_ring) == -ENOSPC) {
netif_tx_stop_queue(queue);
/* Paired with smp_mb() in __tun_wake_queue() */
@@ -2151,8 +2165,12 @@ static ssize_t tun_put_user(struct tun_struct *tun,
static void __tun_wake_queue(struct tun_struct *tun,
struct tun_file *tfile, int consumed)
{
- struct netdev_queue *txq = netdev_get_tx_queue(tun->dev,
- tfile->queue_index);
+ struct netdev_queue *txq;
+
+ if (!(tun->flags & IFF_BACKPRESSURE))
+ return;
+
+ txq = netdev_get_tx_queue(tun->dev, tfile->queue_index);
/* Paired with smp_mb__after_atomic() in tun_net_xmit() */
smp_mb();
@@ -2764,7 +2782,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
struct tun_struct *tun;
struct tun_file *tfile = file->private_data;
struct net_device *dev;
- int err;
+ int err, i;
if (tfile->detached)
return -EINVAL;
@@ -2894,7 +2912,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
* xoff state.
*/
if (netif_running(tun->dev))
- netif_tx_wake_all_queues(tun->dev);
+ for (i = 0; i < tun->numqueues; i++)
+ tun_force_wake_queue(tun, rtnl_dereference(tun->tfiles[i]));
strscpy(ifr->ifr_name, tun->dev->name);
return 0;
@@ -3690,15 +3709,9 @@ static int tun_queue_resize(struct tun_struct *tun)
dev->tx_queue_len, GFP_KERNEL,
tun_ptr_free);
- if (!ret) {
- for (i = 0; i < tun->numqueues; i++) {
- tfile = rtnl_dereference(tun->tfiles[i]);
- spin_lock(&tfile->tx_ring.consumer_lock);
- netif_wake_subqueue(tun->dev, tfile->queue_index);
- tfile->cons_cnt = 0;
- spin_unlock(&tfile->tx_ring.consumer_lock);
- }
- }
+ if (!ret)
+ for (i = 0; i < tun->numqueues; i++)
+ tun_force_wake_queue(tun, rtnl_dereference(tun->tfiles[i]));
kfree(rings);
return ret;
diff --git a/include/uapi/linux/if_tun.h b/include/uapi/linux/if_tun.h
index 79d53c7a1ebd..73a77141315c 100644
--- a/include/uapi/linux/if_tun.h
+++ b/include/uapi/linux/if_tun.h
@@ -69,6 +69,7 @@
#define IFF_NAPI_FRAGS 0x0020
/* Used in TUNSETIFF to bring up tun/tap without carrier */
#define IFF_NO_CARRIER 0x0040
+#define IFF_BACKPRESSURE 0x0080
#define IFF_NO_PI 0x1000
/* This flag has no real effect */
#define IFF_ONE_QUEUE 0x2000
diff --git a/tools/include/uapi/linux/if_tun.h b/tools/include/uapi/linux/if_tun.h
index 2ec07de1d73b..97b670f5bc0a 100644
--- a/tools/include/uapi/linux/if_tun.h
+++ b/tools/include/uapi/linux/if_tun.h
@@ -67,6 +67,7 @@
#define IFF_TAP 0x0002
#define IFF_NAPI 0x0010
#define IFF_NAPI_FRAGS 0x0020
+#define IFF_BACKPRESSURE 0x0080
#define IFF_NO_PI 0x1000
/* This flag has no real effect */
#define IFF_ONE_QUEUE 0x2000
--
2.43.0
^ permalink raw reply related
* Re: [PATCH net v2] tun/tap & vhost-net: make qdisc backpressure opt-in via IFF_BACKPRESSURE
From: Simon Schippers @ 2026-07-07 6:56 UTC (permalink / raw)
To: Brett A C Sheffield
Cc: Michael S. Tsirkin, Willem de Bruijn, Jason Wang,
David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
netdev, Simon Horman, Jonathan Corbet, Shuah Khan, Andrew Lunn,
Tim Gebauer, linux-doc, linux-kernel
In-Reply-To: <0d28fdc4-3c03-48d6-bd59-e59f7a01f4b6@tu-dortmund.de>
[-- Attachment #1: Type: text/plain, Size: 568 bytes --]
On 7/7/26 08:52, Simon Schippers wrote:
> Brett, can you try the two attached patches here with iperf3?
> I think testing with 8 and 16 threads is enough, so where there is a
> regression.
>
> The two patches are about time when to wake:
> Currently we wake after consuming half the internal ring buffer.
> One of the attached patches wakes after 2 cachelines (128 of 1000
> packets) and the other one just wakes once the ring buffer is empty.
>
> This would really help :)
Whoops send you the wrong patch (the opt-in patch again), here
is the wake on empty patch.
[-- Attachment #2: 0001-tun-set-waking-threshold-to-ptr_ring_empty.patch --]
[-- Type: text/x-patch, Size: 917 bytes --]
From a4343922e635cb1cab017b2e85cdd2e606cb667a Mon Sep 17 00:00:00 2001
From: Simon Schippers <simon.schippers@tu-dortmund.de>
Date: Tue, 7 Jul 2026 08:38:31 +0200
Subject: [PATCH] tun: set waking threshold to ptr_ring_empty()
Only wake once the ptr_ring is empty, which results in later and less
calls of netif_tx_wake_queue().
---
drivers/net/tun.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index ffbe6f13fb1f..acbafd39f3ae 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -2158,8 +2158,7 @@ static void __tun_wake_queue(struct tun_struct *tun,
smp_mb();
if (netif_tx_queue_stopped(txq)) {
tfile->cons_cnt += consumed;
- if (tfile->cons_cnt >= tfile->tx_ring.size / 2 ||
- __ptr_ring_empty(&tfile->tx_ring)) {
+ if (__ptr_ring_empty(&tfile->tx_ring)) {
netif_tx_wake_queue(txq);
tfile->cons_cnt = 0;
}
--
2.43.0
^ permalink raw reply related
* [PATCH net] net/iucv: fix use-after-free of a severed iucv_path
From: Bryam Vargas via B4 Relay @ 2026-07-07 7:00 UTC (permalink / raw)
To: Paolo Abeni, Thorsten Winkler, Jakub Kicinski, Alexandra Winter,
Eric Dumazet, David S. Miller
Cc: linux-s390, Hidayath Khan, linux-kernel, netdev, Simon Horman,
Nagamani PV
From: Bryam Vargas <hexlabsecurity@proton.me>
af_iucv queues not-yet-received message notifications on iucv->message_q,
each holding a raw pointer to the connection's iucv_path. When the peer
severs the connection, iucv_sever_path() frees that path with
iucv_path_free() but leaves the notifications queued. A later recvmsg()
drains message_q via iucv_process_message_q() and hands the stale path to
message_receive() -- a use-after-free of the freed iucv_path.
Drop the queued notifications when the path is severed; once the path is
gone they can no longer be received. This also frees the notifications
leaked when a socket is closed with messages still queued.
Fixes: f0703c80e515 ("[AF_IUCV]: postpone receival of iucv-packets")
Closes: https://sashiko.dev/#/patchset/20260705-b4-disp-fc79c0dc-v1-1-d2cdcb57afa9@proton.me?part=1
Cc: stable@vger.kernel.org
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
---
net/iucv/af_iucv.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
index fed240b453bd..2869a103f7fa 100644
--- a/net/iucv/af_iucv.c
+++ b/net/iucv/af_iucv.c
@@ -337,6 +337,7 @@ static void iucv_sever_path(struct sock *sk, int with_user_data)
unsigned char user_data[16];
struct iucv_sock *iucv = iucv_sk(sk);
struct iucv_path *path = iucv->path;
+ struct sock_msg_q *p, *n;
/* Whoever resets the path pointer, must sever and free it. */
if (xchg(&iucv->path, NULL)) {
@@ -348,6 +349,19 @@ static void iucv_sever_path(struct sock *sk, int with_user_data)
} else
pr_iucv->path_sever(path, NULL);
iucv_path_free(path);
+
+ /*
+ * Message notifications queued on message_q still reference
+ * the now freed path; drop them, otherwise a later recvmsg()
+ * would pass the freed iucv_path to message_receive() via
+ * iucv_process_message_q().
+ */
+ spin_lock_bh(&iucv->message_q.lock);
+ list_for_each_entry_safe(p, n, &iucv->message_q.list, list) {
+ list_del(&p->list);
+ kfree(p);
+ }
+ spin_unlock_bh(&iucv->message_q.lock);
}
}
---
base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482
change-id: 20260707-b4-disp-783fedbb-39bc1bb9d4e0
Best regards,
--
Bryam Vargas <hexlabsecurity@proton.me>
^ permalink raw reply related
* Re: [PATCH v1 net-next] net: phy: Drop #inclusion of <linux/mod_devicetable.h> from <linux/mdio.h>
From: Uwe Kleine-König (The Capable Hub) @ 2026-07-07 7:15 UTC (permalink / raw)
To: Andrew Lunn; +Cc: Heiner Kallweit, Russell King, netdev, linux-kernel
In-Reply-To: <96a77bc9-9804-43fb-acf0-b93574cd60f3@lunn.ch>
[-- Attachment #1: Type: text/plain, Size: 769 bytes --]
Hello Andrew,
On Mon, Jul 06, 2026 at 11:28:33PM +0200, Andrew Lunn wrote:
> > That's exactly my thought, and there is commit ad428f5811bd
> > ("mod_devicetable.h: Split into per subsystem headers") that is part of
> > v7.2-rc2 and that does exactly that (apart from the filename).
>
> Ah, O.K. net-next tends to great dragged along the -rcX versions. So
> you can probably submit the networking changes in a weeks time. Just
> make sure they apply to
>
> https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git
Note that while I created the patch under discussion on top of -rc2, the
justification is also valid on -rc1 and the patch doesn't use the new
headers, so it can be applied to the above repo already now.
Best regards
Uwe
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* [RFC PATCH net v1] Revert "net: dsa: mt7530: untag VLAN-aware bridge PVID"
From: Eric Woudstra @ 2026-07-07 7:38 UTC (permalink / raw)
To: Chester A. Unal, Daniel Golle, Andrew Lunn, Vladimir Oltean,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Matthias Brugger, AngeloGioacchino Del Regno, Edward Parker
Cc: netdev, linux-mediatek, coreteam, Eric Woudstra
This reverts commit 4cb3cd670b2a29e52dd3cfd6463e44121674c9b8.
In the case of a userport of a switchdev attached to a vlan-aware bridge,
with untagged packets incoming, tagged at ingress of the bridge:
For all switchdev userports that support SWITCHDEV_OBJ_ID_PORT_VLAN,
which includes dsa-userports, the behaviour is that the tag is visible
in the ingress-hook. The commit mentioned above changes that, making
mt7530 deviate from this. Only on mt7530 the tag is not present in the
ingress-hook.
This, for one, is a problem for the software (forwarding) fastpath.
The flowtuple for this flow is created, with the tag included and marked
with the corresponding in_vlan_ingress bit.
Inside the ingress hook of the fastpath the incoming packet is tried to
match with the hash of this tuple, but is does not match any more.
The tag is missing. The packet does not follow the software-fastpath
in this direction.
Fixes: 4cb3cd670b2a ("net: dsa: mt7530: untag VLAN-aware bridge PVID")
Signed-off-by: Eric Woudstra <ericwouds@gmail.com>
---
drivers/net/dsa/mt7530.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index 3c2a3029b10cf..752ba92b08517 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -2447,7 +2447,6 @@ mt7530_setup(struct dsa_switch *ds)
}
ds->assisted_learning_on_cpu_port = true;
- ds->untag_vlan_aware_bridge_pvid = true;
ds->mtu_enforcement_ingress = true;
ds->ageing_time_min = 2 * 1000;
ds->ageing_time_max = (AGE_CNT_MAX + 1) * (AGE_UNIT_MAX + 1) * 1000;
@@ -2639,7 +2638,6 @@ mt7531_setup_common(struct dsa_switch *ds)
int ret, i;
ds->assisted_learning_on_cpu_port = true;
- ds->untag_vlan_aware_bridge_pvid = true;
ds->mtu_enforcement_ingress = true;
ds->ageing_time_min = 2 * 1000;
ds->ageing_time_max = (AGE_CNT_MAX + 1) * (AGE_UNIT_MAX + 1) * 1000;
--
2.53.0
^ permalink raw reply related
* [PATCH net] dibs: loopback: validate offset and size in move_data()
From: Dust Li @ 2026-07-07 7:43 UTC (permalink / raw)
To: Alexandra Winter
Cc: Wenjia Zhang, Wen Gu, Paolo Abeni, Mahanta Jambigi, D . Wythe,
Sidraya Jayagond, netdev, linux-kernel, stable,
Federico Kirschbaum
The loopback move_data() performs a memcpy into the registered DMB
without checking whether offset + size exceeds the DMB length. Unlike
real ISM hardware, which enforces memory region bounds natively, the
software loopback has no such protection.
A peer-supplied out-of-bounds offset or oversized write would result in
an OOB write past the allocated kernel buffer. Add an explicit bounds
check before the memcpy to reject such requests with -EINVAL.
Fixes: f7a22071dbf3("net/smc: implement DMB-related operations of loopback-ism")
Cc: stable@vger.kernel.org
Reported-by: Federico Kirschbaum <federico.kirschbaum@xbow.com>
Signed-off-by: Dust Li <dust.li@linux.alibaba.com>
---
drivers/dibs/dibs_loopback.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/dibs/dibs_loopback.c b/drivers/dibs/dibs_loopback.c
index ec3b48cb0e87..0f2e09311152 100644
--- a/drivers/dibs/dibs_loopback.c
+++ b/drivers/dibs/dibs_loopback.c
@@ -254,6 +254,11 @@ static int dibs_lo_move_data(struct dibs_dev *dibs, u64 dmb_tok,
read_unlock_bh(&ldev->dmb_ht_lock);
return -EINVAL;
}
+ if ((u64)offset + size > rmb_node->len) {
+ read_unlock_bh(&ldev->dmb_ht_lock);
+ return -EINVAL;
+ }
+
memcpy((char *)rmb_node->cpu_addr + offset, data, size);
sba_idx = rmb_node->sba_idx;
read_unlock_bh(&ldev->dmb_ht_lock);
--
2.43.7
^ permalink raw reply related
* Re: [PATCH net-next v12 0/7] net: stmmac: qcom-ethqos: add support for SCMI power domains
From: Bartosz Golaszewski @ 2026-07-07 7:48 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: linux-arm-msm, devicetree, linux-kernel, netdev, linux-stm32,
linux-arm-kernel, Drew Fustini, linux-sunxi, linux-amlogic,
linux-mips, imx, linux-renesas-soc, linux-rockchip, sophgo,
linux-riscv, Bartosz Golaszewski, Krzysztof Kozlowski,
Martin Blumenstingl, Lad Prabhakar, Bjorn Andersson,
Konrad Dybcio, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Maxime Coquelin, Alexandre Torgue, Vinod Koul,
Giuseppe Cavallaro, Chen-Yu Tsai, Jernej Skrabec, Neil Armstrong,
Kevin Hilman, Jerome Brunet, Shawn Guo, Fabio Estevam,
Jan Petrous, s32, Mohd Ayaan Anwar, Romain Gantois,
Geert Uytterhoeven, Magnus Damm, Maxime Ripard,
Christophe Roullier, Bartosz Golaszewski, Radu Rendec
In-Reply-To: <20260706-qcom-sa8255p-emac-v12-0-e3ab1ecf2901@oss.qualcomm.com>
On Mon, 6 Jul 2026 15:20:15 +0200, Bartosz Golaszewski
<bartosz.golaszewski@oss.qualcomm.com> said:
> Add support for the firmware-managed variant of the DesignWare MAC on
> the sa8255p platform. This series contains new DT bindings and driver
> changes required to support the MAC in the STMMAC driver.
>
> It also reorganizes the ethqos code quite a bit to make the introduction
> of power domains into the driver a bit easier on the eye.
>
> The DTS changes will go in separately.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
> ---
There's one more comment to address by Uwe so there'll be a v13. For merging
strategy: there are no build-time dependencies between the PHY and MAC parts.
Vinod, Jakub: do you prefer me to split the series next time into its PHY and
MAC parts for integration?
Bart
^ permalink raw reply
* Re: [PATCH net-next] net/tcp: Add explicit tracepoint for tcp_syn_ack_timeout()
From: Eric Dumazet @ 2026-07-07 7:52 UTC (permalink / raw)
To: Emil Tsalapatis
Cc: netdev, linux-trace-kernel, ncardwell, kuniyu, rostedt, mhiramat,
davem, kuba, pabeni
In-Reply-To: <20260707010151.43976-1-emil@etsalapatis.com>
On Mon, Jul 6, 2026 at 6:01 PM Emil Tsalapatis <emil@etsalapatis.com> wrote:
>
> Clang can inline the tcp_syn_ack_timeout() function during compilation,
> making it impossible to use kprobes for tracing without preventing
> inlining. Add an explicit tracepoint to it instead.
So much copy/pasting for a very small issue :/
>
> Signed-off-by: Emil Tsalapatis <emil@etsalapatis.com>
> ---
> include/trace/events/tcp.h | 72 ++++++++++++++++++++++++++++++++++++++
> net/ipv4/tcp_timer.c | 3 ++
> 2 files changed, 75 insertions(+)
>
tcp_syn_ack_timeout() is hardly a fast path, so you can instead:
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index 322db13333c7..ab2c3de19e46 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -748,7 +748,7 @@ static void tcp_write_timer(struct timer_list *t)
sock_put(sk);
}
-void tcp_syn_ack_timeout(const struct request_sock *req)
+noinline_for_tracing void tcp_syn_ack_timeout(const struct request_sock *req)
{
struct net *net = read_pnet(&inet_rsk(req)->ireq_net);
^ permalink raw reply related
* Re: [PATCH net] net/tls: Consume empty data records in tls_sw_read_sock()
From: Sabrina Dubroca @ 2026-07-07 7:58 UTC (permalink / raw)
To: Chuck Lever
Cc: john.fastabend, Jakub Kicinski, davem, edumazet, Paolo Abeni,
Simon Horman, netdev
In-Reply-To: <d036b6fa-4f53-444c-b376-83e122982f1d@app.fastmail.com>
2026-07-06, 15:16:21 -0400, Chuck Lever wrote:
>
>
> On Thu, Jul 2, 2026, at 5:50 PM, Sabrina Dubroca wrote:
> > 2026-07-02, 15:52:49 -0400, Chuck Lever wrote:
> >>
> >>
> >> On Thu, Jul 2, 2026, at 2:05 PM, Sabrina Dubroca wrote:
> >> > 2026-06-30, 15:15:51 -0400, Chuck Lever wrote:
> >> >> A peer may send a zero-length TLS application_data record; TLS 1.3
> >> >> explicitly permits these as a traffic-analysis countermeasure (RFC
> >> >> 8446, Section 5.1). After decryption such a record has full_len ==
> >> >> 0. tls_sw_read_sock() hands it to the read_actor, which has no
> >> >> payload to consume and returns zero. The loop treats a zero return
> >> >> as backpressure (used <= 0), requeues the skb at the head of
> >> >> rx_list, and stops. rx_list is serviced head-first on the next
> >> >> call, so the empty record is dequeued, fails the same way, and is
> >> >> requeued again; every later record on the connection is blocked
> >> >> behind it.
> >> >>
> >> >> tls_sw_recvmsg() does not stall on this: a zero-length data record
> >> >> copies nothing and falls through to consume_skb(). Mirror that in
> >> >> the read_sock() path by recognizing an empty data record before
> >> >> the actor runs, consuming it, and continuing.
> >> >>
> >> >> Fixes: 662fbcec32f4 ("net/tls: implement ->read_sock()")
> >> >> Signed-off-by: Chuck Lever <cel@kernel.org>
> >> >> ---
> >> >> net/tls/tls_sw.c | 11 +++++++++++
> >> >> 1 file changed, 11 insertions(+)
> >> >
> >> > Reviewed-by: Sabrina Dubroca <sd@queasysnail.net>
> >> >
> >> > I think tls_sw_splice_read() suffers from a similar issue (returning 0
> >> > even though more data may be available). Sashiko agrees, and also
> >> > found a few more pre-existing issues.
> >>
> >> Do you want a v2 series with those issues addressed?
> >
> > I'd be ok with this patch going in on its own, and the other issues
> > being addressed separately. If you have time to look into those,
> > that'd be great.
>
> patchwork shows this patch continues to be marked as "New". Is there
> something I need to do to help move it forward?
I don't think there's anything blocking it other than the length of
the maintainers' backlog.
--
Sabrina
^ permalink raw reply
* [PATCH net] netlink: specs: rt-link: convert bridge port flag attributes to u8
From: Danielle Ratson @ 2026-07-07 8:03 UTC (permalink / raw)
To: netdev
Cc: donald.hunter, kuba, davem, edumazet, pabeni, horms, razor, petrm,
nikolay, idosch, bridge, linux-kernel, Danielle Ratson
A number of IFLA_BRPORT_* attributes are documented in the rt-link spec
as having the "flag" type, i.e. a payload-less NLA_FLAG attribute whose
meaning is presence-only. This does not match the kernel, which emits
these attributes with nla_put_u8() and validates them as NLA_U8 in
br_port_policy[]. The values are not mere presence flags but carry a u8
payload (0/1).
Convert these bridge port attributes from "flag" to "u8" so the spec
reflects the actual wire format.
Fixes: 077b6022d24b ("doc/netlink/specs: Add sub-message type to rt_link family")
Assisted-by: Claude:claude-opus-4-8
Reviewed-by: Petr Machata <petrm@nvidia.com>
Acked-by: Nikolay Aleksandrov <nikolay@nvidia.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Danielle Ratson <danieller@nvidia.com>
---
Documentation/netlink/specs/rt-link.yaml | 40 ++++++++++++------------
1 file changed, 20 insertions(+), 20 deletions(-)
diff --git a/Documentation/netlink/specs/rt-link.yaml b/Documentation/netlink/specs/rt-link.yaml
index 892979da098e..68c26a70bb64 100644
--- a/Documentation/netlink/specs/rt-link.yaml
+++ b/Documentation/netlink/specs/rt-link.yaml
@@ -1585,31 +1585,31 @@ attribute-sets:
type: u32
-
name: mode
- type: flag
+ type: u8
-
name: guard
- type: flag
+ type: u8
-
name: protect
- type: flag
+ type: u8
-
name: fast-leave
- type: flag
+ type: u8
-
name: learning
- type: flag
+ type: u8
-
name: unicast-flood
- type: flag
+ type: u8
-
name: proxyarp
- type: flag
+ type: u8
-
name: learning-sync
- type: flag
+ type: u8
-
name: proxyarp-wifi
- type: flag
+ type: u8
-
name: root-id
type: binary
@@ -1656,34 +1656,34 @@ attribute-sets:
type: pad
-
name: mcast-flood
- type: flag
+ type: u8
-
name: mcast-to-ucast
- type: flag
+ type: u8
-
name: vlan-tunnel
- type: flag
+ type: u8
-
name: bcast-flood
- type: flag
+ type: u8
-
name: group-fwd-mask
type: u16
-
name: neigh-suppress
- type: flag
+ type: u8
-
name: isolated
- type: flag
+ type: u8
-
name: backup-port
type: u32
-
name: mrp-ring-open
- type: flag
+ type: u8
-
name: mrp-in-open
- type: flag
+ type: u8
-
name: mcast-eht-hosts-limit
type: u32
@@ -1692,10 +1692,10 @@ attribute-sets:
type: u32
-
name: locked
- type: flag
+ type: u8
-
name: mab
- type: flag
+ type: u8
-
name: mcast-n-groups
type: u32
@@ -1704,7 +1704,7 @@ attribute-sets:
type: u32
-
name: neigh-vlan-suppress
- type: flag
+ type: u8
-
name: backup-nhid
type: u32
--
2.54.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox