* Re: [PATCH net-next v6 14/15] dt-bindings: net: add onsemi's S2500
From: Krzysztof Kozlowski @ 2026-06-30 6:29 UTC (permalink / raw)
To: Selvamani Rajagopal
Cc: Andrew Lunn, Piergiorgio Beruto, Heiner Kallweit, Russell King,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Andrew Lunn, Parthiban Veerasooran, Richard Cochran, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Simon Horman, Jonathan Corbet,
Shuah Khan, netdev, linux-kernel, devicetree, linux-doc,
Jerry Ray
In-Reply-To: <20260629-s2500-mac-phy-support-v6-14-18ce79500371@onsemi.com>
On Mon, Jun 29, 2026 at 10:23:44AM -0700, Selvamani Rajagopal wrote:
> Add YAML device tree binding for the onsemi S2500 IEEE 802.3cg
No improvements.
So not only you ignored review comment but you also ignored actual
review tag.
Don't worry, we can ignore your patches as well.
Best regards,
Krzysztof
^ permalink raw reply
* [PATCH net-next v9 0/6] net: stmmac: eic7700: add eth1 variant support and update delay bindings
From: lizhi2 @ 2026-06-30 6:31 UTC (permalink / raw)
To: devicetree, andrew+netdev, davem, edumazet, kuba, robh, krzk+dt,
conor+dt, netdev, pabeni, mcoquelin.stm32, alexandre.torgue,
rmk+kernel, pjw, palmer, aou, alex, linux-riscv, linux-stm32,
linux-arm-kernel, linux-kernel, maxime.chevallier
Cc: ningyu, linmin, pinkesh.vaghela, pritesh.patel, weishangjuan,
horms, lee, wens, Zhi Li
From: Zhi Li <lizhi2@eswincomputing.com>
v8 -> v9:
- patch1:
- Add Reviewed-by: Rob Herring <robh@kernel.org>
- 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 (6):
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
dt-bindings: mfd: syscon: add ESWIN EIC7700 compatible
riscv: dts: eswin: eic7700-hifive-premier-p550: enable Ethernet
controller
.../devicetree/bindings/mfd/syscon.yaml | 2 +
.../bindings/net/eswin,eic7700-eth.yaml | 74 +++++-
.../dts/eswin/eic7700-hifive-premier-p550.dts | 240 ++++++++++++++++++
arch/riscv/boot/dts/eswin/eic7700.dtsi | 105 ++++++++
.../ethernet/stmicro/stmmac/dwmac-eic7700.c | 117 ++++++++-
5 files changed, 511 insertions(+), 27 deletions(-)
--
2.25.1
^ permalink raw reply
* [PATCH net-next v9 1/6] dt-bindings: ethernet: eswin: relax internal delay model to range-based constraints
From: lizhi2 @ 2026-06-30 6:32 UTC (permalink / raw)
To: devicetree, andrew+netdev, davem, edumazet, kuba, robh, krzk+dt,
conor+dt, netdev, pabeni, mcoquelin.stm32, alexandre.torgue,
rmk+kernel, pjw, palmer, aou, alex, linux-riscv, linux-stm32,
linux-arm-kernel, linux-kernel, maxime.chevallier
Cc: ningyu, linmin, pinkesh.vaghela, pritesh.patel, weishangjuan,
horms, lee, wens, Zhi Li
In-Reply-To: <20260630063123.1118-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 v9 2/6] dt-bindings: ethernet: eswin: add EIC7700 eth1 RX clock inversion variant
From: lizhi2 @ 2026-06-30 6:32 UTC (permalink / raw)
To: devicetree, andrew+netdev, davem, edumazet, kuba, robh, krzk+dt,
conor+dt, netdev, pabeni, mcoquelin.stm32, alexandre.torgue,
rmk+kernel, pjw, palmer, aou, alex, linux-riscv, linux-stm32,
linux-arm-kernel, linux-kernel, maxime.chevallier
Cc: ningyu, linmin, pinkesh.vaghela, pritesh.patel, weishangjuan,
horms, lee, wens, Zhi Li
In-Reply-To: <20260630063123.1118-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.
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 v9 3/6] net: stmmac: eic7700: make RGMII delay properties optional
From: lizhi2 @ 2026-06-30 6:32 UTC (permalink / raw)
To: devicetree, andrew+netdev, davem, edumazet, kuba, robh, krzk+dt,
conor+dt, netdev, pabeni, mcoquelin.stm32, alexandre.torgue,
rmk+kernel, pjw, palmer, aou, alex, linux-riscv, linux-stm32,
linux-arm-kernel, linux-kernel, maxime.chevallier
Cc: ningyu, linmin, pinkesh.vaghela, pritesh.patel, weishangjuan,
horms, lee, wens, Zhi Li
In-Reply-To: <20260630063123.1118-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 v9 4/6] net: stmmac: eic7700: add support for eth1 clock inversion variant
From: lizhi2 @ 2026-06-30 6:33 UTC (permalink / raw)
To: devicetree, andrew+netdev, davem, edumazet, kuba, robh, krzk+dt,
conor+dt, netdev, pabeni, mcoquelin.stm32, alexandre.torgue,
rmk+kernel, pjw, palmer, aou, alex, linux-riscv, linux-stm32,
linux-arm-kernel, linux-kernel, maxime.chevallier
Cc: ningyu, linmin, pinkesh.vaghela, pritesh.patel, weishangjuan,
horms, lee, wens, Zhi Li
In-Reply-To: <20260630063123.1118-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 net-next v9 5/6] dt-bindings: mfd: syscon: add ESWIN EIC7700 compatible
From: lizhi2 @ 2026-06-30 6:34 UTC (permalink / raw)
To: devicetree, andrew+netdev, davem, edumazet, kuba, robh, krzk+dt,
conor+dt, netdev, pabeni, mcoquelin.stm32, alexandre.torgue,
rmk+kernel, pjw, palmer, aou, alex, linux-riscv, linux-stm32,
linux-arm-kernel, linux-kernel, maxime.chevallier
Cc: ningyu, linmin, pinkesh.vaghela, pritesh.patel, weishangjuan,
horms, lee, wens, Zhi Li, Conor Dooley
In-Reply-To: <20260630063123.1118-1-lizhi2@eswincomputing.com>
From: Zhi Li <lizhi2@eswincomputing.com>
Document ESWIN EIC7700 SoC compatible for syscon registers.
This patch is included only to provide the DTS context for reviewing the
binding and driver changes in this series.
The upstream DTS series will be submitted separately after the binding
and driver changes are finalized.
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Signed-off-by: Zhi Li <lizhi2@eswincomputing.com>
---
Documentation/devicetree/bindings/mfd/syscon.yaml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/mfd/syscon.yaml b/Documentation/devicetree/bindings/mfd/syscon.yaml
index e22867088063..7d3365601249 100644
--- a/Documentation/devicetree/bindings/mfd/syscon.yaml
+++ b/Documentation/devicetree/bindings/mfd/syscon.yaml
@@ -62,6 +62,7 @@ select:
- cirrus,ep7209-syscon3
- cnxt,cx92755-uc
- econet,en751221-chip-scu
+ - eswin,eic7700-syscfg
- freecom,fsg-cs2-system-controller
- fsl,imx93-aonmix-ns-syscfg
- fsl,imx93-wakeupmix-syscfg
@@ -175,6 +176,7 @@ properties:
- cirrus,ep7209-syscon3
- cnxt,cx92755-uc
- econet,en751221-chip-scu
+ - eswin,eic7700-syscfg
- freecom,fsg-cs2-system-controller
- fsl,imx93-aonmix-ns-syscfg
- fsl,imx93-wakeupmix-syscfg
--
2.25.1
^ permalink raw reply related
* [PATCH net-next v9 6/6] riscv: dts: eswin: eic7700-hifive-premier-p550: enable Ethernet controller
From: lizhi2 @ 2026-06-30 6:34 UTC (permalink / raw)
To: devicetree, andrew+netdev, davem, edumazet, kuba, robh, krzk+dt,
conor+dt, netdev, pabeni, mcoquelin.stm32, alexandre.torgue,
rmk+kernel, pjw, palmer, aou, alex, linux-riscv, linux-stm32,
linux-arm-kernel, linux-kernel, maxime.chevallier
Cc: ningyu, linmin, pinkesh.vaghela, pritesh.patel, weishangjuan,
horms, lee, wens, Zhi Li
In-Reply-To: <20260630063123.1118-1-lizhi2@eswincomputing.com>
From: Zhi Li <lizhi2@eswincomputing.com>
Enable the on-board Gigabit Ethernet controller on the
HiFive Premier P550 development board.
This patch is included only to provide the DTS context for reviewing the
binding and driver changes in this series.
The upstream DTS series will be submitted separately after the binding
and driver changes are finalized.
Signed-off-by: Zhi Li <lizhi2@eswincomputing.com>
---
.../dts/eswin/eic7700-hifive-premier-p550.dts | 240 ++++++++++++++++++
arch/riscv/boot/dts/eswin/eic7700.dtsi | 105 ++++++++
2 files changed, 345 insertions(+)
diff --git a/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts b/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
index 131ed1fc6b2e..9d37bafdd1b2 100644
--- a/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
+++ b/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
@@ -13,11 +13,251 @@ / {
aliases {
serial0 = &uart0;
+ ethernet0 = &gmac0;
+ ethernet1 = &gmac1;
};
chosen {
stdout-path = "serial0:115200n8";
};
+
+ vcc_1v8: regulator-1v8 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc1v8";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+};
+
+&xtal {
+ clock-frequency = <24000000>;
+ clock-output-names = "xtal24m";
+};
+
+&pinctrl {
+ status = "okay";
+ vrgmii-supply = <&vcc_1v8>;
+
+ pinctrl_gpio0: gpio0-grp {
+ gpio0-pins {
+ pins = "gpio0";
+ function = "gpio";
+ input-enable;
+ bias-disable;
+ };
+ };
+
+ pinctrl_gpio5: gpio5-grp {
+ gpio5-pins {
+ pins = "gpio5";
+ function = "gpio";
+ input-enable;
+ bias-disable;
+ };
+ };
+
+ pinctrl_gpio11: gpio11-grp {
+ gpio11-pins {
+ pins = "gpio11";
+ function = "gpio";
+ input-enable;
+ bias-disable;
+ };
+ };
+
+ pinctrl_gpio14: gpio14-grp {
+ gpio14-pins {
+ pins = "mode_set1";
+ function = "gpio";
+ input-disable;
+ bias-pull-up;
+ };
+ };
+
+ pinctrl_gpio15: gpio15-grp {
+ gpio15-pins {
+ pins = "mode_set2";
+ function = "gpio";
+ input-enable;
+ bias-disable;
+ };
+ };
+
+ pinctrl_gpio28: gpio28-grp {
+ gpio28-pins {
+ pins = "gpio28";
+ function = "gpio";
+ input-enable;
+ bias-disable;
+ };
+ };
+
+ pinctrl_gpio43: gpio43-grp {
+ gpio43-pins {
+ pins = "usb1_pwren";
+ function = "gpio";
+ input-disable;
+ bias-disable;
+ };
+ };
+
+ pinctrl_gpio71: gpio71-grp {
+ gpio71-pins {
+ pins = "mipi_csi0_xhs";
+ function = "gpio";
+ input-disable;
+ bias-pull-up;
+ };
+ };
+
+ pinctrl_gpio74: gpio74-grp {
+ gpio74-pins {
+ pins = "mipi_csi1_xhs";
+ function = "gpio";
+ input-disable;
+ bias-pull-up;
+ };
+ };
+
+ pinctrl_gpio76: gpio76-grp {
+ gpio76-pins {
+ pins = "mipi_csi2_xvs";
+ function = "gpio";
+ input-disable;
+ bias-disable;
+ };
+ };
+
+ pinctrl_gpio77: gpio77-grp {
+ gpio77-pins {
+ pins = "mipi_csi2_xhs";
+ function = "gpio";
+ input-disable;
+ bias-pull-up;
+ };
+ };
+
+ pinctrl_gpio79: gpio79-grp {
+ gpio79-pins {
+ pins = "mipi_csi3_xvs";
+ function = "gpio";
+ input-disable;
+ bias-disable;
+ };
+ };
+
+ pinctrl_gpio80: gpio80-grp {
+ gpio80-pins {
+ pins = "mipi_csi3_xhs";
+ function = "gpio";
+ input-disable;
+ bias-pull-up;
+ };
+ };
+
+ pinctrl_gpio82: gpio82-grp {
+ gpio82-pins {
+ pins = "mipi_csi4_xvs";
+ function = "gpio";
+ input-disable;
+ bias-pull-up;
+ };
+ };
+
+ pinctrl_gpio84: gpio84-grp {
+ gpio84-pins {
+ pins = "mipi_csi4_mclk";
+ function = "gpio";
+ input-disable;
+ bias-disable;
+ };
+ };
+
+ pinctrl_gpio85: gpio85-grp {
+ gpio85-pins {
+ pins = "mipi_csi5_xvs";
+ function = "gpio";
+ input-disable;
+ bias-pull-up;
+ };
+ };
+
+ pinctrl_gpio94: gpio94-grp {
+ gpio94-pins {
+ pins = "s_mode";
+ function = "gpio";
+ input-disable;
+ bias-disable;
+ };
+ };
+
+ pinctrl_gpio106: gpio106-grp {
+ gpio106-pins {
+ pins = "gpio106";
+ function = "gpio";
+ input-disable;
+ bias-disable;
+ };
+ };
+
+ pinctrl_gpio111: gpio111-grp {
+ gpio111-pins {
+ pins = "gpio111";
+ function = "gpio";
+ input-disable;
+ bias-disable;
+ };
+ };
+};
+
+&gmac0 {
+ phy-handle = <&gmac0_phy0>;
+ phy-mode = "rgmii-id";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpio106>;
+ rx-internal-delay-ps = <20>;
+ tx-internal-delay-ps = <100>;
+ status = "okay";
+};
+
+&gmac0_mdio {
+ gmac0_phy0: ethernet-phy@0 {
+ compatible = "ethernet-phy-id001c.c916";
+ reg = <0>;
+ reset-gpios = <&gpioD 10 GPIO_ACTIVE_LOW>;
+ reset-assert-us = <10000>;
+ reset-deassert-us = <80000>;
+ };
+};
+
+&gmac1 {
+ phy-handle = <&gmac1_phy0>;
+ /*
+ * The MAC silicon unconditionally introduces an ~2 ns TX clock-to-data
+ * skew (MAC-side TX internal delay). The PHY provides the standard
+ * ~2 ns RX internal delay. The driver additionally inverts the RX
+ * clock at 1000 Mb/s to correct a silicon RX sampling timing issue.
+ * phy-mode is "rgmii-id": TX delay from the MAC silicon, RX delay
+ * from the PHY.
+ */
+ phy-mode = "rgmii-id";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpio111>;
+ rx-internal-delay-ps = <200>;
+ tx-internal-delay-ps = <2200>;
+ status = "okay";
+};
+
+&gmac1_mdio {
+ gmac1_phy0: ethernet-phy@0 {
+ compatible = "ethernet-phy-id001c.c916";
+ reg = <0>;
+ reset-gpios = <&gpioD 15 GPIO_ACTIVE_LOW>;
+ reset-assert-us = <10000>;
+ reset-deassert-us = <80000>;
+ };
};
&uart0 {
diff --git a/arch/riscv/boot/dts/eswin/eic7700.dtsi b/arch/riscv/boot/dts/eswin/eic7700.dtsi
index c3ed93008bca..041ecc5cb007 100644
--- a/arch/riscv/boot/dts/eswin/eic7700.dtsi
+++ b/arch/riscv/boot/dts/eswin/eic7700.dtsi
@@ -5,6 +5,9 @@
/dts-v1/;
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/reset/eswin,eic7700-reset.h>
+
/ {
#address-cells = <2>;
#size-cells = <2>;
@@ -202,6 +205,11 @@ pmu {
<0x00000000 0x0000000f 0xfffffffc 0x000000ff 0x00000078>;
};
+ xtal: clock-24m {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ };
+
soc {
compatible = "simple-bus";
ranges;
@@ -245,6 +253,85 @@ plic: interrupt-controller@c000000 {
#interrupt-cells = <1>;
};
+ hsp: bus@0 {
+ compatible = "simple-pm-bus";
+ ranges = <0x0 0x50400000 0x0 0x50400000 0x0 0xa0000>;
+ clocks = <&clk 171>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ hsp_sp_csr: hsp-sp-top-csr@50440000 {
+ compatible = "eswin,eic7700-syscfg", "syscon";
+ reg = <0x0 0x50440000 0x0 0x2000>;
+ };
+
+ gmac0: ethernet@50400000 {
+ compatible = "eswin,eic7700-qos-eth",
+ "snps,dwmac-5.20";
+ reg = <0x0 0x50400000 0x0 0x10000>;
+ interrupts = <61>;
+ interrupt-names = "macirq";
+ clocks = <&clk 186>,
+ <&clk 171>,
+ <&clk 40>,
+ <&clk 193>;
+ clock-names = "axi", "cfg", "stmmaceth", "tx";
+ resets = <&reset EIC7700_RESET_HSP_ETH0_ARST>;
+ reset-names = "stmmaceth";
+ eswin,hsp-sp-csr = <&hsp_sp_csr 0x100 0x108 0x118 0x114 0x11c>;
+ snps,aal;
+ snps,fixed-burst;
+ snps,tso;
+ snps,axi-config = <&stmmac_axi_setup_gmac0>;
+ status = "disabled";
+
+ gmac0_mdio: mdio {
+ compatible = "snps,dwmac-mdio";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ stmmac_axi_setup_gmac0: stmmac-axi-config {
+ snps,blen = <0 0 0 0 16 8 4>;
+ snps,rd_osr_lmt = <2>;
+ snps,wr_osr_lmt = <2>;
+ };
+ };
+
+ gmac1: ethernet@50410000 {
+ compatible = "eswin,eic7700-qos-eth-clk-inversion",
+ "snps,dwmac-5.20";
+ reg = <0x0 0x50410000 0x0 0x10000>;
+ interrupts = <70>;
+ interrupt-names = "macirq";
+ clocks = <&clk 186>,
+ <&clk 171>,
+ <&clk 40>,
+ <&clk 194>;
+ clock-names = "axi", "cfg", "stmmaceth", "tx";
+ resets = <&reset EIC7700_RESET_HSP_ETH1_ARST>;
+ reset-names = "stmmaceth";
+ eswin,hsp-sp-csr = <&hsp_sp_csr 0x200 0x208 0x218 0x214 0x21c>;
+ snps,aal;
+ snps,fixed-burst;
+ snps,tso;
+ snps,axi-config = <&stmmac_axi_setup_gmac1>;
+ status = "disabled";
+
+ gmac1_mdio: mdio {
+ compatible = "snps,dwmac-mdio";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ 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>;
+ };
+ };
+ };
+
uart0: serial@50900000 {
compatible = "snps,dw-apb-uart";
reg = <0x0 0x50900000 0x0 0x10000>;
@@ -341,5 +428,23 @@ gpioD: gpio-port@3 {
#gpio-cells = <2>;
};
};
+
+ pinctrl: pinctrl@51600080 {
+ compatible = "eswin,eic7700-pinctrl";
+ reg = <0x0 0x51600080 0x0 0x1fff80>;
+ };
+
+ clk: clock-controller@51828000 {
+ compatible = "eswin,eic7700-clock";
+ reg = <0x0 0x51828000 0x0 0x300>;
+ clocks = <&xtal>;
+ #clock-cells = <1>;
+ };
+
+ reset: reset-controller@51828300 {
+ compatible = "eswin,eic7700-reset";
+ reg = <0x0 0x51828300 0x0 0x200>;
+ #reset-cells = <1>;
+ };
};
};
--
2.25.1
^ permalink raw reply related
* [PATCH net-next v2] ionic: Change list definition method
From: Lei Zhu @ 2026-06-30 6:54 UTC (permalink / raw)
To: brett.creeley, andrew+netdev, davem, edumazet, kuba, pabeni
Cc: netdev, zhulei_szu
From: Lei Zhu <zhulei@kylinos.cn>
The LIST_HEAD macro can both define a linked list and initialize
it in one step. To simplify code, we replace the separate operations
of linked list definition and manual initialization with the LIST_HEAD
macro.
Signed-off-by: Lei Zhu <zhulei@kylinos.cn>
---
Changes in v2:
- Order the variable declaration lines longest to shortest
drivers/net/ethernet/pensando/ionic/ionic_rx_filter.c | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.c b/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.c
index 528114877677..c999754afb5f 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.c
@@ -558,18 +558,15 @@ struct sync_item {
void ionic_rx_filter_sync(struct ionic_lif *lif)
{
struct device *dev = lif->ionic->dev;
- struct list_head sync_add_list;
- struct list_head sync_del_list;
struct sync_item *sync_item;
struct ionic_rx_filter *f;
+ LIST_HEAD(sync_add_list);
+ LIST_HEAD(sync_del_list);
struct hlist_head *head;
struct hlist_node *tmp;
struct sync_item *spos;
unsigned int i;
- INIT_LIST_HEAD(&sync_add_list);
- INIT_LIST_HEAD(&sync_del_list);
-
clear_bit(IONIC_LIF_F_FILTER_SYNC_NEEDED, lif->state);
/* Copy the filters to be added and deleted
--
2.25.1
^ permalink raw reply related
* [PATCH v2 0/5] netfilter: nf_flow_table_path: L2 bridge offload
From: Daniel Pawlik @ 2026-06-30 6:57 UTC (permalink / raw)
To: netfilter-devel, netdev
Cc: pablo, fw, phil, davem, edumazet, kuba, pabeni, horms,
andrew+netdev, razor, idosch, matthias.bgg,
angelogioacchino.delregno, bridge, coreteam, linux-mediatek,
linux-arm-kernel, rchen14b, lorenzo, Daniel Pawlik
This series adds L2 bridge offload support to nft_flow_offload, allowing
bridged IPv4/IPv6 flows to be accelerated by the flowtable fast path
without requiring L3 routing.
Background
----------
Hardware flow offload engines (e.g. MediaTek PPE) can accelerate bridged
traffic but require that nft_flow_offload detect and handle bridged flows
differently from routed ones: no routing table lookup, MAC addresses from
the Ethernet header, and VLAN context pre-populated from the bridge port.
v2: Fix missing Returns: tags in kernel-doc comments for the three new
bridge helpers (br_fdb_has_forwarding_entry_rcu,
br_vlan_get_offload_info_rcu, br_vlan_is_enabled_rcu).
Patches
-------
1/5 net: export __dev_fill_forward_path
Refactors dev_fill_forward_path() to expose __dev_fill_forward_path()
which accepts a caller-supplied net_device_path_ctx, needed to
pre-populate VLAN state before the forward path walk.
2/5 net: bridge: add flow offload helpers
Adds br_fdb_has_forwarding_entry_rcu(), br_vlan_get_offload_info_rcu()
and br_vlan_is_enabled_rcu() to expose bridge state to nft_flow_offload
without requiring inclusion of net/bridge/br_private.h.
3/5 netfilter: nf_flow_table_path: add L2 bridge offload
Core of the series. Adds nft_flow_offload_is_bridging() detection,
nft_flow_route_bridging() which avoids nf_route() (fails for
bridged-only subnets), MAC/VLAN pre-population for bridged flows,
and a dst leak fix. nft_flow_route() becomes a thin dispatcher.
4/5 netfilter: nf_flow_table_path: handle DEV_PATH_MTK_WDMA in path info
Fixes zero-source-MAC in PPE entries when a bridged flow traverses
MT7996/MT7915 WiFi WDMA hardware.
5/5 netfilter: nf_flow_table_path: add VLAN passthrough support
Records VLAN encap info for passthrough-mode bridge ports so hardware
offload entries include the correct VLAN tag.
Rebase note
-----------
Originally developed against OpenWrt pending-6.18 patches by Ryan Chen
<rchen14b@gmail.com> and Bo-Cun Chen <bc-bocun.chen@mediatek.com>.
Rebased to current upstream: path discovery infrastructure moved to
nf_flow_table_path.c in commit 93d7a7ed0734 ("netfilter: flowtable: move
path discovery infrastructure to its own file"), so all netfilter changes
now land in that file rather than nft_flow_offload.c.
How to enable bridge offload
-----------------------------
1. Load kmod-br-netfilter so that bridged IP traffic traverses the
netfilter forward chain.
2. Enable netfilter hooks on the bridge:
echo 1 > /sys/class/net/<br>/bridge/nf_call_iptables
echo 1 > /sys/class/net/<br>/bridge/nf_call_ip6tables
3. Register bridge member interfaces in the nft flowtable:
table inet filter {
flowtable f {
hook ingress priority filter
devices = { eth0, wlan0 }
}
chain forward {
type filter hook forward priority filter
meta l4proto { tcp, udp } flow add @f
}
}
Daniel Pawlik (1):
net: bridge: add flow offload helpers
Ryan Chen (4):
net: export __dev_fill_forward_path
netfilter: nf_flow_table_path: add L2 bridge offload
netfilter: nf_flow_table_path: handle DEV_PATH_MTK_WDMA in path info
netfilter: nf_flow_table_path: add VLAN passthrough support
include/linux/if_bridge.h | 23 ++++
include/linux/netdevice.h | 2 +
net/bridge/br_fdb.c | 34 +++++
net/bridge/br_vlan.c | 47 +++++++
net/core/dev.c | 32 +++--
net/netfilter/nf_flow_table_path.c | 201 +++++++++++++++++++++++++++--
6 files changed, 316 insertions(+), 23 deletions(-)
--
2.54.0
^ permalink raw reply
* [PATCH 1/5] net: export __dev_fill_forward_path
From: Daniel Pawlik @ 2026-06-30 6:57 UTC (permalink / raw)
To: netfilter-devel, netdev
Cc: pablo, fw, phil, davem, edumazet, kuba, pabeni, horms,
andrew+netdev, razor, idosch, matthias.bgg,
angelogioacchino.delregno, bridge, coreteam, linux-mediatek,
linux-arm-kernel, rchen14b, lorenzo, Daniel Pawlik
In-Reply-To: <20260630065735.3341614-1-pawlik.dan@gmail.com>
From: Ryan Chen <rchen14b@gmail.com>
Export __dev_fill_forward_path() which accepts a caller-supplied
net_device_path_ctx, allowing callers to pre-populate context (e.g.
VLAN state) before the forward path walk. The existing
dev_fill_forward_path() is refactored to call it.
This is a prerequisite for nft_flow_offload bridge offload, which needs
to supply a pre-populated ctx for bridge port devices.
Signed-off-by: Ryan Chen <rchen14b@gmail.com>
Signed-off-by: Daniel Pawlik <pawlik.dan@gmail.com>
---
include/linux/netdevice.h | 2 ++
net/core/dev.c | 32 ++++++++++++++++++++------------
2 files changed, 22 insertions(+), 12 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 9981d637f8b5..c1d0b897de95 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -3422,6 +3422,8 @@ int dev_get_iflink(const struct net_device *dev);
int dev_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb);
int dev_fill_forward_path(const struct net_device *dev, const u8 *daddr,
struct net_device_path_stack *stack);
+int __dev_fill_forward_path(struct net_device_path_ctx *ctx, const u8 *daddr,
+ struct net_device_path_stack *stack);
struct net_device *dev_get_by_name(struct net *net, const char *name);
struct net_device *dev_get_by_name_rcu(struct net *net, const char *name);
struct net_device *__dev_get_by_name(struct net *net, const char *name);
diff --git a/net/core/dev.c b/net/core/dev.c
index 4b3d5cfdf6e0..62f1d0b64c76 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -750,44 +750,52 @@ static struct net_device_path *dev_fwd_path(struct net_device_path_stack *stack)
return &stack->path[k];
}
-int dev_fill_forward_path(const struct net_device *dev, const u8 *daddr,
- struct net_device_path_stack *stack)
+int __dev_fill_forward_path(struct net_device_path_ctx *ctx, const u8 *daddr,
+ struct net_device_path_stack *stack)
{
const struct net_device *last_dev;
- struct net_device_path_ctx ctx = {
- .dev = dev,
- };
struct net_device_path *path;
int ret = 0;
- memcpy(ctx.daddr, daddr, sizeof(ctx.daddr));
+ memcpy(ctx->daddr, daddr, sizeof(ctx->daddr));
stack->num_paths = 0;
- while (ctx.dev && ctx.dev->netdev_ops->ndo_fill_forward_path) {
- last_dev = ctx.dev;
+ while (ctx->dev && ctx->dev->netdev_ops->ndo_fill_forward_path) {
+ last_dev = ctx->dev;
path = dev_fwd_path(stack);
if (!path)
return -1;
memset(path, 0, sizeof(struct net_device_path));
- ret = ctx.dev->netdev_ops->ndo_fill_forward_path(&ctx, path);
+ ret = ctx->dev->netdev_ops->ndo_fill_forward_path(ctx, path);
if (ret < 0)
return -1;
- if (WARN_ON_ONCE(last_dev == ctx.dev))
+ if (WARN_ON_ONCE(last_dev == ctx->dev))
return -1;
}
- if (!ctx.dev)
+ if (!ctx->dev)
return ret;
path = dev_fwd_path(stack);
if (!path)
return -1;
path->type = DEV_PATH_ETHERNET;
- path->dev = ctx.dev;
+ path->dev = ctx->dev;
return ret;
}
+EXPORT_SYMBOL_GPL(__dev_fill_forward_path);
+
+int dev_fill_forward_path(const struct net_device *dev, const u8 *daddr,
+ struct net_device_path_stack *stack)
+{
+ struct net_device_path_ctx ctx = {
+ .dev = dev,
+ };
+
+ return __dev_fill_forward_path(&ctx, daddr, stack);
+}
EXPORT_SYMBOL_GPL(dev_fill_forward_path);
/* must be called under rcu_read_lock(), as we dont take a reference */
--
2.54.0
^ permalink raw reply related
* [PATCH 2/5] net: bridge: add flow offload helpers
From: Daniel Pawlik @ 2026-06-30 6:57 UTC (permalink / raw)
To: netfilter-devel, netdev
Cc: pablo, fw, phil, davem, edumazet, kuba, pabeni, horms,
andrew+netdev, razor, idosch, matthias.bgg,
angelogioacchino.delregno, bridge, coreteam, linux-mediatek,
linux-arm-kernel, rchen14b, lorenzo, Daniel Pawlik
In-Reply-To: <20260630065735.3341614-1-pawlik.dan@gmail.com>
Add three helpers that expose the bridge state needed by nft_flow_offload
without requiring callers to include net/bridge/br_private.h. Each
performs a single br_port_get_rcu() lookup:
- br_fdb_has_forwarding_entry_rcu(): resolves the VLAN id for the packet
(skb tag or PVID when filtering is on, 0 otherwise) then checks whether
the bridge FDB contains a forwarding entry (dst != NULL, non-local) for
the resulting MAC/VLAN pair.
- br_vlan_get_offload_info_rcu(): when VLAN filtering is active, returns
the VLAN id (skb tag or PVID) and writes the bridge VLAN protocol to
*proto in a single port lookup. Returns 0 when filtering is off.
- br_vlan_is_enabled_rcu(): returns true when VLAN filtering is enabled
on the bridge a port device belongs to.
Based on MediaTek SDK patches by Bo-Cun Chen <bc-bocun.chen@mediatek.com>
and the OpenWrt bridge offload series by Ryan Chen <rchen14b@gmail.com>.
Signed-off-by: Daniel Pawlik <pawlik.dan@gmail.com>
---
include/linux/if_bridge.h | 23 +++++++++++++++++++
net/bridge/br_fdb.c | 34 ++++++++++++++++++++++++++++
net/bridge/br_vlan.c | 47 +++++++++++++++++++++++++++++++++++++++
3 files changed, 104 insertions(+)
diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index 75673b8bffcb..c1cae54749c5 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -148,6 +148,9 @@ int br_vlan_get_info(const struct net_device *dev, u16 vid,
struct bridge_vlan_info *p_vinfo);
int br_vlan_get_info_rcu(const struct net_device *dev, u16 vid,
struct bridge_vlan_info *p_vinfo);
+u16 br_vlan_get_offload_info_rcu(const struct net_device *dev,
+ const struct sk_buff *skb, __be16 *proto);
+bool br_vlan_is_enabled_rcu(const struct net_device *dev);
bool br_mst_enabled(const struct net_device *dev);
int br_mst_get_info(const struct net_device *dev, u16 msti, unsigned long *vids);
int br_mst_get_state(const struct net_device *dev, u16 msti, u8 *state);
@@ -184,6 +187,17 @@ static inline int br_vlan_get_info_rcu(const struct net_device *dev, u16 vid,
return -EINVAL;
}
+static inline u16 br_vlan_get_offload_info_rcu(const struct net_device *dev,
+ const struct sk_buff *skb,
+ __be16 *proto)
+{
+ return 0;
+}
+
+static inline bool br_vlan_is_enabled_rcu(const struct net_device *dev)
+{
+ return false;
+}
static inline bool br_mst_enabled(const struct net_device *dev)
{
return false;
@@ -209,6 +223,8 @@ void br_fdb_clear_offload(const struct net_device *dev, u16 vid);
bool br_port_flag_is_set(const struct net_device *dev, unsigned long flag);
u8 br_port_get_stp_state(const struct net_device *dev);
clock_t br_get_ageing_time(const struct net_device *br_dev);
+bool br_fdb_has_forwarding_entry_rcu(const struct net_device *dev,
+ const struct sk_buff *skb, const u8 *addr);
#else
static inline struct net_device *
br_fdb_find_port(const struct net_device *br_dev,
@@ -237,6 +253,13 @@ static inline clock_t br_get_ageing_time(const struct net_device *br_dev)
{
return 0;
}
+
+static inline bool br_fdb_has_forwarding_entry_rcu(const struct net_device *dev,
+ const struct sk_buff *skb,
+ const u8 *addr)
+{
+ return false;
+}
#endif
#endif
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index e4570bbed854..2a65b203274e 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -267,6 +267,40 @@ struct net_bridge_fdb_entry *br_fdb_find_rcu(struct net_bridge *br,
return fdb_find_rcu(&br->fdb_hash_tbl, addr, vid);
}
+/**
+ * br_fdb_has_forwarding_entry_rcu - check if a MAC can be forwarded by the bridge
+ * @dev: bridge port network device
+ * @skb: packet buffer (used to determine VLAN id)
+ * @addr: destination MAC address
+ *
+ * Resolves the VLAN id for @skb on @dev (skb VLAN tag when present, PVID
+ * when VLAN filtering is enabled, 0 otherwise) then checks whether the bridge
+ * FDB contains a forwarding entry (dst != NULL, not a local/self entry) for
+ * @addr and that VLAN id. Single br_port_get_rcu() lookup.
+ * Must be called under RCU read lock.
+ *
+ * Returns: true if a forwarding entry exists for @addr, false otherwise.
+ */
+bool br_fdb_has_forwarding_entry_rcu(const struct net_device *dev,
+ const struct sk_buff *skb, const u8 *addr)
+{
+ struct net_bridge_port *port = br_port_get_rcu(dev);
+ struct net_bridge_fdb_entry *fdb;
+ u16 vid = 0;
+
+ if (!port)
+ return false;
+ if (br_opt_get(port->br, BROPT_VLAN_ENABLED)) {
+ if (skb_vlan_tag_present(skb))
+ vid = skb_vlan_tag_get_id(skb);
+ else
+ br_vlan_get_pvid_rcu(dev, &vid);
+ }
+ fdb = br_fdb_find_rcu(port->br, addr, vid);
+ return fdb && fdb->dst;
+}
+EXPORT_SYMBOL_GPL(br_fdb_has_forwarding_entry_rcu);
+
/* When a static FDB entry is added, the mac address from the entry is
* added to the bridge private HW address list and all required ports
* are then updated with the new information.
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
index 5560afcaaca3..974e57ea533a 100644
--- a/net/bridge/br_vlan.c
+++ b/net/bridge/br_vlan.c
@@ -1559,6 +1559,53 @@ int br_vlan_get_info_rcu(const struct net_device *dev, u16 vid,
}
EXPORT_SYMBOL_GPL(br_vlan_get_info_rcu);
+/**
+ * br_vlan_get_offload_info_rcu - get VLAN id and protocol for bridge flow offload
+ * @dev: bridge port network device
+ * @skb: packet buffer
+ * @proto: output for the bridge VLAN protocol (set only when return value != 0)
+ *
+ * When VLAN filtering is enabled, resolves the VLAN id for flow offload (skb
+ * VLAN tag id if present, PVID otherwise) and writes the bridge VLAN protocol
+ * to @proto. Single br_port_get_rcu() lookup. Must be called under RCU read
+ * lock.
+ *
+ * Returns: the VLAN id, or 0 when filtering is off or @dev is not a bridge port.
+ */
+u16 br_vlan_get_offload_info_rcu(const struct net_device *dev,
+ const struct sk_buff *skb, __be16 *proto)
+{
+ struct net_bridge_port *port = br_port_get_rcu(dev);
+ u16 vid = 0;
+
+ if (!port || !br_opt_get(port->br, BROPT_VLAN_ENABLED))
+ return 0;
+ if (skb_vlan_tag_present(skb))
+ vid = skb_vlan_tag_get_id(skb);
+ else
+ br_vlan_get_pvid_rcu(dev, &vid);
+ if (vid)
+ *proto = port->br->vlan_proto;
+ return vid;
+}
+EXPORT_SYMBOL_GPL(br_vlan_get_offload_info_rcu);
+
+/**
+ * br_vlan_is_enabled_rcu - check if VLAN filtering is active on a port's bridge
+ * @dev: bridge port network device
+ *
+ * Must be called under RCU read lock.
+ *
+ * Returns: true if VLAN filtering is enabled, false otherwise.
+ */
+bool br_vlan_is_enabled_rcu(const struct net_device *dev)
+{
+ struct net_bridge_port *port = br_port_get_rcu(dev);
+
+ return port && br_opt_get(port->br, BROPT_VLAN_ENABLED);
+}
+EXPORT_SYMBOL_GPL(br_vlan_is_enabled_rcu);
+
static int br_vlan_is_bind_vlan_dev(const struct net_device *dev)
{
return is_vlan_dev(dev) &&
--
2.54.0
^ permalink raw reply related
* [PATCH 3/5] netfilter: nf_flow_table_path: add L2 bridge offload
From: Daniel Pawlik @ 2026-06-30 6:57 UTC (permalink / raw)
To: netfilter-devel, netdev
Cc: pablo, fw, phil, davem, edumazet, kuba, pabeni, horms,
andrew+netdev, razor, idosch, matthias.bgg,
angelogioacchino.delregno, bridge, coreteam, linux-mediatek,
linux-arm-kernel, rchen14b, lorenzo, Daniel Pawlik
In-Reply-To: <20260630065735.3341614-1-pawlik.dan@gmail.com>
From: Ryan Chen <rchen14b@gmail.com>
Allow nft_flow_offload to accelerate traffic forwarded at layer 2 through
Linux bridge ports.
Detection: nft_flow_offload_is_bridging() identifies bridged flows by
checking that the ingress device is a bridge port and that the destination
MAC appears in the bridge FDB with a forwarding destination port (non-local
entry). VLAN resolution and FDB lookup are combined in a single
br_port_get_rcu() call via br_fdb_has_forwarding_entry_rcu().
Routing: nft_flow_route_bridging() allocates minimal dst entries anchored
to the bridge master device via rt_dst_alloc()/ip6_dst_alloc(). A full
routing table lookup via nf_route() is intentionally avoided: it fails for
prefixes that are only bridged, not routed, through the bridge interface
(e.g. when the bridge has no IP address or the bridged subnet is not in
the routing table).
MAC addresses: for bridged flows, nft_dev_forward_path() copies Ethernet
addresses directly from the packet header instead of going through the
neighbour table. Direction (original vs reply) is resolved against the
conntrack direction so both flow directions receive the correct MAC pair.
VLAN context: nft_br_vlan_dev_fill_forward_path() pre-populates the
net_device_path_ctx with the port VLAN id and protocol before the forward
path walk, enabling VLAN-aware hardware offload entries.
Also:
- info->indev is updated for every path type in nft_dev_path_info() so
the bridge ingress device is correctly tracked regardless of path type.
- nft_flow_route() is now a thin dispatcher that delegates to
nft_flow_route_routing() (routed traffic) or nft_flow_route_bridging()
(bridged traffic); the exported API is unchanged.
Path discovery infrastructure was moved to nf_flow_table_path.c in
commit 93d7a7ed0734 ("netfilter: flowtable: move path discovery
infrastructure to its own file"), so all changes land in that file.
Based on a MediaTek SDK patch by Bo-Cun Chen <bc-bocun.chen@mediatek.com>.
Co-developed-by: Daniel Pawlik <pawlik.dan@gmail.com>
Signed-off-by: Daniel Pawlik <pawlik.dan@gmail.com>
Signed-off-by: Ryan Chen <rchen14b@gmail.com>
---
net/netfilter/nf_flow_table_path.c | 167 +++++++++++++++++++++++++++--
1 file changed, 157 insertions(+), 10 deletions(-)
diff --git a/net/netfilter/nf_flow_table_path.c b/net/netfilter/nf_flow_table_path.c
index 98c03b487f52..6c470854127f 100644
--- a/net/netfilter/nf_flow_table_path.c
+++ b/net/netfilter/nf_flow_table_path.c
@@ -15,6 +15,10 @@
#include <net/netfilter/nf_conntrack_core.h>
#include <net/netfilter/nf_conntrack_extend.h>
#include <net/netfilter/nf_flow_table.h>
+#include <linux/if_bridge.h>
+#include <linux/if_ether.h>
+#include <net/route.h>
+#include <net/ip6_route.h>
static enum flow_offload_xmit_type nft_xmit_type(struct dst_entry *dst)
{
@@ -42,7 +46,25 @@ static bool nft_is_valid_ether_device(const struct net_device *dev)
return true;
}
-static int nft_dev_fill_forward_path(const struct nf_flow_route *route,
+static bool nft_flow_offload_is_bridging(struct sk_buff *skb)
+{
+ bool ret;
+
+ if (!netif_is_bridge_port(skb->dev))
+ return false;
+ if (!skb_mac_header_was_set(skb))
+ return false;
+
+ rcu_read_lock();
+ ret = br_fdb_has_forwarding_entry_rcu(skb->dev, skb,
+ eth_hdr(skb)->h_dest);
+ rcu_read_unlock();
+
+ return ret;
+}
+
+static int nft_dev_fill_forward_path(struct net_device_path_ctx *ctx,
+ const struct nf_flow_route *route,
const struct dst_entry *dst_cache,
const struct nf_conn *ct,
enum ip_conntrack_dir dir, u8 *ha,
@@ -58,6 +80,12 @@ static int nft_dev_fill_forward_path(const struct nf_flow_route *route,
goto out;
}
+ /* Bridging fastpath copies Ethernet addresses into ha; do not replace
+ * them via neighbour lookup on the routed destination device.
+ */
+ if (!is_zero_ether_addr(ha))
+ goto out;
+
n = dst_neigh_lookup(dst_cache, daddr);
if (!n)
return -1;
@@ -72,7 +100,23 @@ static int nft_dev_fill_forward_path(const struct nf_flow_route *route,
return -1;
out:
- return dev_fill_forward_path(dev, ha, stack);
+ return __dev_fill_forward_path(ctx, ha, stack);
+}
+
+static void nft_br_vlan_dev_fill_forward_path(const struct nft_pktinfo *pkt,
+ struct net_device_path_ctx *ctx)
+{
+ __be16 proto = 0;
+ u16 vlan_id;
+
+ rcu_read_lock();
+ vlan_id = br_vlan_get_offload_info_rcu(pkt->skb->dev, pkt->skb, &proto);
+ if (vlan_id) {
+ ctx->num_vlans = 1;
+ ctx->vlan[0].id = vlan_id;
+ ctx->vlan[0].proto = proto;
+ }
+ rcu_read_unlock();
}
struct nft_forward_info {
@@ -103,13 +147,13 @@ static int nft_dev_path_info(const struct net_device_path_stack *stack,
for (i = 0; i < stack->num_paths; i++) {
path = &stack->path[i];
+ info->indev = path->dev;
switch (path->type) {
case DEV_PATH_ETHERNET:
case DEV_PATH_DSA:
case DEV_PATH_VLAN:
case DEV_PATH_PPPOE:
case DEV_PATH_TUN:
- info->indev = path->dev;
if (is_zero_ether_addr(info->h_source))
memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN);
@@ -244,6 +288,7 @@ static int nft_flow_tunnel_update_route(const struct nft_pktinfo *pkt,
}
static int nft_dev_forward_path(const struct nft_pktinfo *pkt,
+ bool is_bridging,
struct nf_flow_route *route,
const struct nf_conn *ct,
enum ip_conntrack_dir dir,
@@ -251,11 +296,33 @@ static int nft_dev_forward_path(const struct nft_pktinfo *pkt,
{
const struct dst_entry *dst = route->tuple[dir].dst;
struct net_device_path_stack stack;
+ struct net_device_path_ctx ctx = {
+ .dev = dst->dev,
+ };
struct nft_forward_info info = {};
+ enum ip_conntrack_info pkt_ctinfo;
+ enum ip_conntrack_dir skb_dir;
+ struct ethhdr *eth;
unsigned char ha[ETH_ALEN];
int i;
- if (nft_dev_fill_forward_path(route, dst, ct, dir, ha, &stack) < 0 ||
+ memset(ha, 0, sizeof(ha));
+
+ if (is_bridging) {
+ nf_ct_get(pkt->skb, &pkt_ctinfo);
+ eth = eth_hdr(pkt->skb);
+ skb_dir = CTINFO2DIR(pkt_ctinfo);
+ if (skb_dir != dir) {
+ memcpy(ha, eth->h_source, ETH_ALEN);
+ memcpy(info.h_source, eth->h_dest, ETH_ALEN);
+ } else {
+ memcpy(ha, eth->h_dest, ETH_ALEN);
+ memcpy(info.h_source, eth->h_source, ETH_ALEN);
+ }
+ nft_br_vlan_dev_fill_forward_path(pkt, &ctx);
+ }
+
+ if (nft_dev_fill_forward_path(&ctx, route, dst, ct, dir, ha, &stack) < 0 ||
nft_dev_path_info(&stack, &info, ha, &ft->data) < 0)
return -ENOENT;
@@ -292,9 +359,11 @@ static int nft_dev_forward_path(const struct nft_pktinfo *pkt,
return 0;
}
-int nft_flow_route(const struct nft_pktinfo *pkt, const struct nf_conn *ct,
- struct nf_flow_route *route, enum ip_conntrack_dir dir,
- struct nft_flowtable *ft)
+static int nft_flow_route_routing(const struct nft_pktinfo *pkt,
+ const struct nf_conn *ct,
+ struct nf_flow_route *route,
+ enum ip_conntrack_dir dir,
+ struct nft_flowtable *ft)
{
struct dst_entry *this_dst = skb_dst(pkt->skb);
struct dst_entry *other_dst = NULL;
@@ -334,12 +403,12 @@ int nft_flow_route(const struct nft_pktinfo *pkt, const struct nf_conn *ct,
nft_default_forward_path(route, this_dst, dir);
nft_default_forward_path(route, other_dst, !dir);
- if (route->tuple[dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH &&
- nft_dev_forward_path(pkt, route, ct, dir, ft) < 0)
+ if (route->tuple[dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH &&
+ nft_dev_forward_path(pkt, false, route, ct, dir, ft) < 0)
goto err_dst_release;
if (route->tuple[!dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH &&
- nft_dev_forward_path(pkt, route, ct, !dir, ft) < 0)
+ nft_dev_forward_path(pkt, false, route, ct, !dir, ft) < 0)
goto err_dst_release;
return 0;
@@ -349,4 +418,82 @@ int nft_flow_route(const struct nft_pktinfo *pkt, const struct nf_conn *ct,
dst_release(route->tuple[!dir].dst);
return -ENOENT;
}
+
+static int nft_flow_route_bridging(const struct nft_pktinfo *pkt,
+ const struct nf_conn *ct,
+ struct nf_flow_route *route,
+ enum ip_conntrack_dir dir,
+ struct nft_flowtable *ft)
+{
+ struct dst_entry *dsts[IP_CT_DIR_MAX] = {};
+ struct net_device *br_dev;
+ int i;
+
+ /* Allocate minimal dsts anchored to the bridge master device to supply
+ * xmit_type and MTU. A full routing lookup via nf_route() is avoided
+ * because it fails for prefixes that are bridged but not routed.
+ */
+ rcu_read_lock();
+ br_dev = netdev_master_upper_dev_get_rcu(pkt->skb->dev);
+ if (!br_dev || !netif_is_bridge_master(br_dev)) {
+ rcu_read_unlock();
+ return -ENOENT;
+ }
+
+ for (i = 0; i < IP_CT_DIR_MAX; i++) {
+ switch (nft_pf(pkt)) {
+ case NFPROTO_IPV4: {
+ struct rtable *rt;
+
+ rt = rt_dst_alloc(br_dev, 0, RTN_UNICAST, true);
+ if (rt)
+ dsts[i] = &rt->dst;
+ break;
+ }
+ case NFPROTO_IPV6: {
+ struct rt6_info *rt;
+
+ rt = ip6_dst_alloc(nft_net(pkt), br_dev, 0);
+ if (rt)
+ dsts[i] = &rt->dst;
+ break;
+ }
+ }
+ }
+ rcu_read_unlock();
+
+ if (!dsts[dir] || !dsts[!dir]) {
+ dst_release(dsts[dir]);
+ dst_release(dsts[!dir]);
+ return -ENOENT;
+ }
+
+ nft_default_forward_path(route, dsts[dir], dir);
+ nft_default_forward_path(route, dsts[!dir], !dir);
+ /* Drop allocation references; route->tuple[*].dst holds the clones. */
+ dst_release(dsts[dir]);
+ dst_release(dsts[!dir]);
+
+ if (route->tuple[dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH &&
+ route->tuple[!dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH) {
+ if (nft_dev_forward_path(pkt, true, route, ct, dir, ft) ||
+ nft_dev_forward_path(pkt, true, route, ct, !dir, ft)) {
+ dst_release(route->tuple[dir].dst);
+ dst_release(route->tuple[!dir].dst);
+ return -ENOENT;
+ }
+ }
+
+ return 0;
+}
+
+int nft_flow_route(const struct nft_pktinfo *pkt, const struct nf_conn *ct,
+ struct nf_flow_route *route, enum ip_conntrack_dir dir,
+ struct nft_flowtable *ft)
+{
+ if (nft_flow_offload_is_bridging(pkt->skb))
+ return nft_flow_route_bridging(pkt, ct, route, dir, ft);
+
+ return nft_flow_route_routing(pkt, ct, route, dir, ft);
+}
EXPORT_SYMBOL_GPL(nft_flow_route);
--
2.54.0
^ permalink raw reply related
* [PATCH 4/5] netfilter: nf_flow_table_path: handle DEV_PATH_MTK_WDMA in path info
From: Daniel Pawlik @ 2026-06-30 6:57 UTC (permalink / raw)
To: netfilter-devel, netdev
Cc: pablo, fw, phil, davem, edumazet, kuba, pabeni, horms,
andrew+netdev, razor, idosch, matthias.bgg,
angelogioacchino.delregno, bridge, coreteam, linux-mediatek,
linux-arm-kernel, rchen14b, lorenzo, Daniel Pawlik
In-Reply-To: <20260630065735.3341614-1-pawlik.dan@gmail.com>
From: Ryan Chen <rchen14b@gmail.com>
Without this change, nft_dev_path_info() hits the default -ENOENT path
for WiFi bridge offload via WDMA on MT7996. When a bridged flow goes
through the MT7996 WiFi device, the DEV_PATH_MTK_WDMA step does not set
h_source, causing the PPE entry to receive a zero source MAC and packets
to stall in both software fastpath and hardware path.
Based on a MediaTek SDK patch by Bo-Cun Chen <bc-bocun.chen@mediatek.com>.
Signed-off-by: Ryan Chen <rchen14b@gmail.com>
Signed-off-by: Daniel Pawlik <pawlik.dan@gmail.com>
---
net/netfilter/nf_flow_table_path.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/net/netfilter/nf_flow_table_path.c b/net/netfilter/nf_flow_table_path.c
index 6c470854127f..580aa1db3cb4 100644
--- a/net/netfilter/nf_flow_table_path.c
+++ b/net/netfilter/nf_flow_table_path.c
@@ -219,6 +219,10 @@ static int nft_dev_path_info(const struct net_device_path_stack *stack,
}
info->xmit_type = FLOW_OFFLOAD_XMIT_DIRECT;
break;
+ case DEV_PATH_MTK_WDMA:
+ if (is_zero_ether_addr(info->h_source))
+ memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN);
+ break;
default:
return -1;
}
--
2.54.0
^ permalink raw reply related
* [PATCH 5/5] netfilter: nf_flow_table_path: add VLAN passthrough support
From: Daniel Pawlik @ 2026-06-30 6:57 UTC (permalink / raw)
To: netfilter-devel, netdev
Cc: pablo, fw, phil, davem, edumazet, kuba, pabeni, horms,
andrew+netdev, razor, idosch, matthias.bgg,
angelogioacchino.delregno, bridge, coreteam, linux-mediatek,
linux-arm-kernel, rchen14b, lorenzo, Daniel Pawlik
In-Reply-To: <20260630065735.3341614-1-pawlik.dan@gmail.com>
From: Ryan Chen <rchen14b@gmail.com>
VLAN passthrough packets can be offloaded when bridge-nf-filter-vlan-tagged
is enabled. When a packet has a VLAN tag and the bridge does not have VLAN
filtering enabled (passthrough mode), record the VLAN encap info so the
hardware flow offload entry includes the correct VLAN tag.
Without this change, VLAN-tagged bridged traffic cannot be offloaded by PPE
because the VLAN encap information is missing from the flow entry.
Enable with: echo 1 > /proc/sys/net/bridge/bridge-nf-filter-vlan-tagged
Based on a MediaTek SDK patch by Chak-Kei Lam <chak-kei.lam@mediatek.com>.
Signed-off-by: Ryan Chen <rchen14b@gmail.com>
Signed-off-by: Daniel Pawlik <pawlik.dan@gmail.com>
---
net/netfilter/nf_flow_table_path.c | 32 ++++++++++++++++++++++++++++--
1 file changed, 30 insertions(+), 2 deletions(-)
diff --git a/net/netfilter/nf_flow_table_path.c b/net/netfilter/nf_flow_table_path.c
index 580aa1db3cb4..d15c425c88c4 100644
--- a/net/netfilter/nf_flow_table_path.c
+++ b/net/netfilter/nf_flow_table_path.c
@@ -17,6 +17,7 @@
#include <net/netfilter/nf_flow_table.h>
#include <linux/if_bridge.h>
#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
#include <net/route.h>
#include <net/ip6_route.h>
@@ -136,6 +137,29 @@ struct nft_forward_info {
enum flow_offload_xmit_type xmit_type;
};
+static void nft_fill_vlan_passthrough_info(const struct nft_pktinfo *pkt,
+ struct nft_forward_info *info)
+{
+ if (!skb_vlan_tag_present(pkt->skb))
+ return;
+
+ rcu_read_lock();
+ /* when bridge VLAN filtering is enabled, the bridge handles the tag */
+ if (netif_is_bridge_port(pkt->skb->dev) &&
+ !br_vlan_is_enabled_rcu(pkt->skb->dev)) {
+ if (info->num_encaps >= NF_FLOW_TABLE_ENCAP_MAX) {
+ info->indev = NULL;
+ } else {
+ info->encap[info->num_encaps].id =
+ skb_vlan_tag_get_id(pkt->skb);
+ info->encap[info->num_encaps].proto =
+ pkt->skb->vlan_proto;
+ info->num_encaps++;
+ }
+ }
+ rcu_read_unlock();
+}
+
static int nft_dev_path_info(const struct net_device_path_stack *stack,
struct nft_forward_info *info,
unsigned char *ha, struct nf_flowtable *flowtable)
@@ -326,8 +350,12 @@ static int nft_dev_forward_path(const struct nft_pktinfo *pkt,
nft_br_vlan_dev_fill_forward_path(pkt, &ctx);
}
- if (nft_dev_fill_forward_path(&ctx, route, dst, ct, dir, ha, &stack) < 0 ||
- nft_dev_path_info(&stack, &info, ha, &ft->data) < 0)
+ if (nft_dev_fill_forward_path(&ctx, route, dst, ct, dir, ha, &stack) < 0)
+ return -ENOENT;
+
+ nft_fill_vlan_passthrough_info(pkt, &info);
+
+ if (nft_dev_path_info(&stack, &info, ha, &ft->data) < 0)
return -ENOENT;
if (!nft_flowtable_find_dev(info.indev, ft))
--
2.54.0
^ permalink raw reply related
* [PATCH] af_unix: mark MSG_SPLICE_PAGES frags shared
From: Yiming Qian @ 2026-06-30 7:05 UTC (permalink / raw)
To: security
Cc: Kuniyuki Iwashima, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, netdev, linux-kernel, lingchen5202005,
yimingqian591
unix_stream_sendmsg() splices external pages directly into skb frags when
MSG_SPLICE_PAGES is set, but it does not propagate SKBFL_SHARED_FRAG
afterward.
That leaves later writers without the shared-frag marker even though the
skb still references externally owned pages.
Set the marker after a successful skb_splice_from_iter() call.
Fixes: a0dbf5f818f90 ("af_unix: Support MSG_SPLICE_PAGES")
Reported-by: Yiming Qian <yimingqian591@gmail.com>
Reported-by: Can Liu <lingchen5202005@gmail.com>
Signed-off-by: Yiming Qian <yimingqian591@gmail.com>
Signed-off-by: Can Liu <lingchen5202005@gmail.com>
---
net/unix/af_unix.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index f7a9d55eee8a1..f2cd0f8ec0914 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -2458,6 +2458,7 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg,
goto out_free;
size = err;
+ skb_shinfo(skb)->flags |= SKBFL_SHARED_FRAG;
refcount_add(size, &sk->sk_wmem_alloc);
} else {
skb_put(skb, size - data_len);
--
2.34.1
^ permalink raw reply related
* Re: [net-next v24 3/7] net: mtip: Add buffers management functions to the L2 switch driver
From: Łukasz Majewski @ 2026-06-30 7:09 UTC (permalink / raw)
To: Jakub Kicinski
Cc: andrew+netdev, davem, edumazet, pabeni, richardcochran, lgirdwood,
nathan, linux-kernel, netdev, krzk+dt, imx, linux-arm-kernel,
robh, Andrew Lunn
In-Reply-To: <20260609103704.443c0b57@wsk>
Hi Jakub,
> Hi Jakub,
>
> > This is an AI-generated review of your patch. The human sending this
> > email has considered the AI review valid, or at least plausible.
> > ---
> > net: mtip: Add buffers management functions to the L2 switch driver
> >
> > This patch fills in mtip_alloc_buffers() and mtip_free_buffers() for
> > the MTIP L2 switch driver, replacing the previously empty stubs with
> > real page_pool setup/teardown and tx_bounce buffer allocation/free.
> >
> > > diff --git a/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.c
> > > b/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.c index
> > > 1d1005a42306..5b5229ee411d 100644 ---
> > > a/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.c +++
> > > b/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.c @@ -892,11
> > > +892,101 @@ static void mtip_get_drvinfo(struct net_device *dev,
> > > static void mtip_free_buffers(struct net_device *dev)
> > > {
> > > + struct mtip_ndev_priv *priv = netdev_priv(dev);
> > > + struct switch_enet_private *fep = priv->fep;
> > > + int i;
> > > +
> > > + for (i = 0; i < RX_RING_SIZE; i++) {
> > > + if (!fep->page[i])
> > > + continue;
> > > +
> > > + page_pool_put_full_page(fep->page_pool,
> > > + fep->page[i], false);
> > > + fep->page[i] = NULL;
> > > + }
> > > +
> > > + page_pool_destroy(fep->page_pool);
> > > + fep->page_pool = NULL;
> > > +
> > > + for (i = 0; i < TX_RING_SIZE; i++) {
> > > + kfree(fep->tx_bounce[i]);
> > > + fep->tx_bounce[i] = NULL;
> > > + }
> > > +}
> >
> > [High]
> > Now that mtip_free_buffers() is no longer an empty stub, can the
> > mtip_open() error path tear down buffers that another active port is
> > still using?
> >
> > Looking at mtip_open():
> >
> > if (fep->usage_count == 0) {
> > ...
> > ret = mtip_alloc_buffers(dev);
> > if (ret)
> > goto mtip_alloc_buffers_err;
> > }
> > ...
> > ret = mtip_mii_probe(dev);
> > if (ret)
> > goto mtip_mii_probe_err;
> > ...
> > mtip_mii_probe_err:
> > mtip_free_buffers(dev);
> > mtip_alloc_buffers_err:
> > if (fep->usage_count == 0) {
> > netif_napi_del(&fep->napi);
> > clk_disable(fep->clk_ipg);
> > }
> > return ret;
> >
> > mtip_alloc_buffers() only runs when fep->usage_count == 0, so the
> > page_pool, fep->page[] and fep->tx_bounce[] are shared across switch
> > ports and only allocated on first open. mtip_close() reflects this
> > and only calls mtip_free_buffers() when fep->usage_count == 1.
> >
> > When a second port is opened (fep->usage_count > 0) and
> > mtip_mii_probe() fails, the mtip_mii_probe_err label still calls
> > mtip_free_buffers() unconditionally, which destroys the page_pool
> > and frees the tx_bounce buffers that the first, still-active port is
> > using.
> >
> > Should the mtip_mii_probe_err teardown also be guarded by
> > fep->usage_count == 0 (or the labels reordered) so buffers are only
> > freed for the last user, similar to mtip_close()?
> >
> > After this change the previously harmless call becomes a real
> > teardown, so the surviving port's NAPI path (mtip_switch_rx() and
> > the later mtip_update_cbd() refill) would dereference a freed
> > fep->page_pool and NULL fep->page[] / fep->tx_bounce[] entries
> > whenever the second port's PHY probe fails while the first port is
> > up.
> > >
> > > +static int mtip_create_page_pool(struct switch_enet_private *fep,
> > > int size) +{
> > [ ... ]
> > > +}
> > >
> > > static int mtip_alloc_buffers(struct net_device *dev)
> > > {
> > [ ... ]
> > > return 0;
> > > +
> > > + err:
> > > + mtip_free_buffers(dev);
> > > + return -ENOMEM;
> > > }
> > >
>
> Thank you for sending the AI review.
>
> Please find my comments:
>
> - I've gone through them and yes, there are a few issues found.
> However, those are IMHO not critical ones.
>
> - Some issues are not valid at all - like concern what happens when
> the switch is run on multi processor chip - both imx287 and vf610 are
> single core chips.
>
> - It seems like the AI review is "progressing" - i.e. there were no
> issues found with v23 for this particular patch. I do guess that the
> new Orc Mode from [1] has found it.
>
> - I do guess that different AI agent would generate different review
>
> - The aforementioned issues could be addressed with a fix patches -
> dragging along (and preparing for upstream) patch set with ~3400
> LOC (which is rejected by non-deterministic AI review) takes too
> much resources now.
>
Could you provide some guidelines about how to proceed?
The series was sent shortly before the net-next being open (and then it
was closed because of the new merge window).
Now it is open again, so maybe you would find some more time for this
patch set discussion?
Thanks in advance.
>
> To sum up:
> ----------
>
> The MTIP driver for v6.6 kernel (YPRR Scarthgap) with and without
> PREEMPT_RT for vf610 and imx287 as well as the v24 for net-next can be
> found at [2].
>
>
> Links:
>
> [1] - https://netdev-ai.bots.linux.dev/ai-local.html
> [2] - https://github.com/lmajewski/linux-imx28-l2switch/branches
>
>
>
--
Best regards,
Łukasz Majewski
^ permalink raw reply
* RE: [PATCH] net: lan743x: Initialize eth_syslock spinlock before use
From: Thangaraj.S @ 2026-06-30 7:09 UTC (permalink / raw)
To: davthompson, arighi, Bryan.Whitehead, UNGLinuxDriver
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, Raju.Lakkaraju,
netdev, linux-kernel
In-Reply-To: <SJ0PR12MB8113F67510A03A9486C8EB26C7EB2@SJ0PR12MB8113.namprd12.prod.outlook.com>
Reviewed-by: Thangaraj Samynathan<Thangaraj.s@microchip.com>
> -----Original Message-----
> From: David Thompson <davthompson@nvidia.com>
> Sent: Saturday, June 27, 2026 1:21 AM
> To: Andrea Righi <arighi@nvidia.com>; Bryan Whitehead - C21958
> <Bryan.Whitehead@microchip.com>; UNGLinuxDriver
> <UNGLinuxDriver@microchip.com>
> Cc: Andrew Lunn <andrew+netdev@lunn.ch>; David S . Miller
> <davem@davemloft.net>; Eric Dumazet <edumazet@google.com>; Jakub
> Kicinski <kuba@kernel.org>; Paolo Abeni <pabeni@redhat.com>; Raju
> Lakkaraju <Raju.Lakkaraju@microchip.com>; netdev@vger.kernel.org; linux-
> kernel@vger.kernel.org
> Subject: RE: [PATCH] net: lan743x: Initialize eth_syslock spinlock before use
>
> EXTERNAL EMAIL: Do not click links or open attachments unless you know
> the content is safe
>
> > -----Original Message-----
> > From: Andrea Righi <arighi@nvidia.com>
> > Sent: Friday, June 26, 2026 12:32 PM
> > To: Bryan Whitehead <bryan.whitehead@microchip.com>;
> > UNGLinuxDriver@microchip.com
> > Cc: Andrew Lunn <andrew+netdev@lunn.ch>; David S . Miller
> > <davem@davemloft.net>; Eric Dumazet <edumazet@google.com>; Jakub
> > Kicinski <kuba@kernel.org>; Paolo Abeni <pabeni@redhat.com>; Raju
> > Lakkaraju <Raju.Lakkaraju@microchip.com>; David Thompson
> > <davthompson@nvidia.com>; netdev@vger.kernel.org; linux-
> > kernel@vger.kernel.org
> > Subject: [PATCH] net: lan743x: Initialize eth_syslock spinlock before
> > use
> >
> > lan743x_hardware_init() calls pci11x1x_strap_get_status() during the
> > PCI11x1x probe sequence. That helper acquires the Ethernet subsystem
> > hardware lock via lan743x_hs_syslock_acquire(), which relies on
> > adapter->eth_syslock_spinlock to serialize access.
> >
> > The spinlock is currently initialized only after the strap status is
> > read. With CONFIG_DEBUG_SPINLOCK enabled, taking the zeroed
> > initialized spinlock can trip the spinlock debug check.
> >
> > Fix by initializing adapter->eth_syslock_spinlock before reading the
> > strap status so the probe path never attempts to lock an uninitialized
> spinlock.
> >
> > Fixes: 46b777ad9a8c ("net: lan743x: Add support to SGMII 1G and 2.5G")
> > Cc: stable@vger.kernel.org # v6.0+
> > Signed-off-by: Andrea Righi <arighi@nvidia.com>
> > ---
> > drivers/net/ethernet/microchip/lan743x_main.c | 2 +-
> > 1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/drivers/net/ethernet/microchip/lan743x_main.c
> > b/drivers/net/ethernet/microchip/lan743x_main.c
> > index 1cdce35e14239..e759171bfd766 100644
> > --- a/drivers/net/ethernet/microchip/lan743x_main.c
> > +++ b/drivers/net/ethernet/microchip/lan743x_main.c
> > @@ -3541,8 +3541,8 @@ static int lan743x_hardware_init(struct
> > lan743x_adapter *adapter,
> > adapter->max_tx_channels = PCI11X1X_MAX_TX_CHANNELS;
> > adapter->used_tx_channels = PCI11X1X_USED_TX_CHANNELS;
> > adapter->max_vector_count = PCI11X1X_MAX_VECTOR_COUNT;
> > - pci11x1x_strap_get_status(adapter);
> > spin_lock_init(&adapter->eth_syslock_spinlock);
> > + pci11x1x_strap_get_status(adapter);
> > mutex_init(&adapter->sgmii_rw_lock);
> > pci11x1x_set_rfe_rd_fifo_threshold(adapter);
> > sgmii_ctl = lan743x_csr_read(adapter, SGMII_CTL);
> > --
> > 2.54.0
>
> Reviewed-by: David Thompson <davthompson@nvidia.com>
^ permalink raw reply
* Re: [PATCH net-next v9 2/6] dt-bindings: ethernet: eswin: add EIC7700 eth1 RX clock inversion variant
From: Maxime Chevallier @ 2026-06-30 7:10 UTC (permalink / raw)
To: lizhi2, devicetree, andrew+netdev, davem, edumazet, kuba, robh,
krzk+dt, conor+dt, netdev, pabeni, mcoquelin.stm32,
alexandre.torgue, rmk+kernel, pjw, palmer, aou, alex, linux-riscv,
linux-stm32, linux-arm-kernel, linux-kernel
Cc: ningyu, linmin, pinkesh.vaghela, pritesh.patel, weishangjuan,
horms, lee, wens
In-Reply-To: <20260630063239.1158-1-lizhi2@eswincomputing.com>
Hi,
On 6/30/26 08:32, lizhi2@eswincomputing.com wrote:
> 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)
>
Maybe Andrew can help answering that one, but does it ever make sense to insert
a delay beyond 2540 ps ?
Maxime
^ permalink raw reply
* Re: [PATCH bpf-next v3 1/2] bpf, sockmap: disallow update and delete from tc, xdp and flow_dissector
From: Sechang Lim @ 2026-06-30 7:14 UTC (permalink / raw)
To: John Fastabend
Cc: Alexei Starovoitov, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
David S . Miller, Jakub Kicinski, Jesper Dangaard Brouer,
Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
Stanislav Fomichev, Emil Tsalapatis, Lorenz Bauer, Jakub Sitnicki,
Jiayuan Chen, Shuah Khan, bpf, netdev, linux-kselftest,
linux-kernel
In-Reply-To: <akNXhg5K7aV7Opdr@john-p8>
On Mon, Jun 29, 2026 at 10:47:41PM -0700, John Fastabend wrote:
>I think we additionally need to also block
>BPF_PROG_TYPE_SOCKET_FILTER? Did you check this case I guess the same
>case is possible there?
>
Yes, same inversion. I'll block BPF_PROG_TYPE_SOCKET_FILTER in v4.
>Then another patch needs to restrict BPF_SOCK_OPS users. For that
>we need to block BPF_SOCK_OPS_HDR_OPT_LEN_CB and BPF_SOCK_OPS_WRITE_*.
>Let me know if you want to do those as well. Let me know if you want
>to do both patches or just the prog blocking above with the possible
>addition of SOCKET_FILTER. I didn't search very hard so probably need
>to check all the BPF_SOCK_OPS_* to find the valid cases.
>
Just the prog blocking with BPF_PROG_TYPE_SOCKET_FILTER added. I'll
leave SOCK_OPS out of this series.
Bests,
Sechang
^ permalink raw reply
* Re: [PATCH v2 1/6] dt-bindings: net: bluetooth: Document Qualcomm IPQ5018 Bluetooth controller
From: Krzysztof Kozlowski @ 2026-06-30 7:15 UTC (permalink / raw)
To: George Moussalem
Cc: Jens Axboe, Ulf Hansson, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Johannes Berg, Jeff Johnson, Bartosz Golaszewski,
Marcel Holtmann, Luiz Augusto von Dentz, Balakrishna Godavarthi,
Rocky Liao, Saravana Kannan, Andrew Lunn, Heiner Kallweit,
Russell King, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Bjorn Andersson, Konrad Dybcio,
Mathieu Poirier, Philipp Zabel, linux-block, linux-kernel,
linux-mmc, devicetree, linux-wireless, ath10k, linux-arm-msm,
linux-bluetooth, netdev, linux-remoteproc
In-Reply-To: <20260629-ipq5018-bluetooth-v2-1-02770f03b6bb@outlook.com>
On Mon, Jun 29, 2026 at 05:01:44PM +0400, George Moussalem wrote:
> +unevaluatedProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/clock/qcom,gcc-ipq5018.h>
> + #include <dt-bindings/interrupt-controller/arm-gic.h>
> + #include <dt-bindings/reset/qcom,gcc-ipq5018.h>
> +
> + bluetooth {
Don't send new versions while discussion is still going. I need to
repeat my question - what bus does that sit on?
Device nodes represent real devices. Real devices sit on a bus, usually.
Do you have here a bus?
> + compatible = "qcom,ipq5018-bt";
Best regards,
Krzysztof
^ permalink raw reply
* [PATCH net v3] nfc: nci: Fix conn_info use-after-free
From: Sanghyun Park @ 2026-06-30 7:17 UTC (permalink / raw)
To: David Heidelberg, Krzysztof Kozlowski
Cc: Sanghyun Park, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Ian Ray, Joe Damato, Kuniyuki Iwashima,
Kees Cook, Ashutosh Desai, Vadim Fedorenko, Deepak Sharma,
Michael Thalmeier, Christophe Ricard, Samuel Ortiz, oe-linux-nfc,
netdev, linux-kernel
nci_tx_work() looks up conn_info from conn_info_list and keeps using
that pointer while sending queued data. nci_core_conn_close_rsp_packet()
runs on the separate rx_wq and can remove and free the same conn_info,
so the tx worker can dereference freed memory.
The same lifetime rule also has to cover other conn_info_list users and
the direct rf_conn_info and hci_dev->conn_info aliases. Protect
conn_info_list and conn_info pointer aliases with a dedicated lock, use
it while publishing and removing entries, and keep readers under the lock
while they dereference conn_info or copy the fields they need.
In nci_tx_work(), take the lock only around lookup, credit checks, skb
dequeue, and credit accounting so close cannot free conn_info while it is
used, but transport send latency does not block rx_wq response
processing.
Fixes: 736bb9577407 ("NFC: nci: Support logical connections management")
Signed-off-by: Sanghyun Park <sanghyun.park.cnu@gmail.com>
---
v3:
- Add Fixes tag for the logical connection close lifetime bug.
- Add the missing NFC maintainer and oe-linux-nfc list.
- Cover all conn_info_list helper users, not only nci_tx_work().
- Protect direct rf_conn_info and hci_dev->conn_info aliases.
- Publish and remove conn_info entries under the same lock.
- Protect RF conn_info discovery publication with the same lock.
- Keep HCI rx_skb immediate dereferences under conn_info_lock.
- Narrow nci_send_data() lock coverage around skb queueing.
- Avoid holding conn_info_lock across nci_send_frame().
- Use spin_lock_bh() so HCI timer callbacks do not take a sleepable lock.
- Keep conn_info_lock alive until nci_dev teardown instead of destroying it before nfc_remove_device().
v2: https://patchwork.kernel.org/project/netdevbpf/patch/20260610081657.686636-1-sanghyun.park.cnu@gmail.com/
- Replace flush-only fix with conn_info locking around tx and close.
v1: https://patchwork.kernel.org/project/netdevbpf/patch/CAOrxSK5UmFFfzdRG+P89+E+Rvg_1DmOvTs+M7353Q8=hkPXmSg@mail.gmail.com/
drivers/nfc/st-nci/se.c | 16 +++---
include/net/nfc/nci_core.h | 10 +++-
net/nfc/nci/core.c | 98 +++++++++++++++++++++++++--------
net/nfc/nci/data.c | 68 ++++++++++++++---------
net/nfc/nci/hci.c | 109 +++++++++++++++++++++++++++++--------
net/nfc/nci/ntf.c | 22 ++++++--
net/nfc/nci/rsp.c | 50 ++++++++++++-----
7 files changed, 269 insertions(+), 104 deletions(-)
diff --git a/drivers/nfc/st-nci/se.c b/drivers/nfc/st-nci/se.c
index 607ec768eb7b4..1f8e2265e20b0 100644
--- a/drivers/nfc/st-nci/se.c
+++ b/drivers/nfc/st-nci/se.c
@@ -548,6 +548,7 @@ static int st_nci_hci_network_init(struct nci_dev *ndev)
struct core_conn_create_dest_spec_params *dest_params;
struct dest_spec_params spec_params;
struct nci_conn_info *conn_info;
+ u8 nfcee_id;
int r, dev_num;
dest_params =
@@ -569,9 +570,14 @@ static int st_nci_hci_network_init(struct nci_dev *ndev)
if (r != NCI_STATUS_OK)
goto free_dest_params;
+ spin_lock_bh(&ndev->conn_info_lock);
conn_info = ndev->hci_dev->conn_info;
- if (!conn_info)
+ if (!conn_info) {
+ spin_unlock_bh(&ndev->conn_info_lock);
goto free_dest_params;
+ }
+ nfcee_id = conn_info->dest_params->id;
+ spin_unlock_bh(&ndev->conn_info_lock);
ndev->hci_dev->init_data.gate_count = ARRAY_SIZE(st_nci_gates);
memcpy(ndev->hci_dev->init_data.gates, st_nci_gates,
@@ -601,13 +607,9 @@ static int st_nci_hci_network_init(struct nci_dev *ndev)
* HCI will be used here only for proprietary commands.
*/
if (test_bit(ST_NCI_FACTORY_MODE, &info->flags))
- r = nci_nfcee_mode_set(ndev,
- ndev->hci_dev->conn_info->dest_params->id,
- NCI_NFCEE_DISABLE);
+ r = nci_nfcee_mode_set(ndev, nfcee_id, NCI_NFCEE_DISABLE);
else
- r = nci_nfcee_mode_set(ndev,
- ndev->hci_dev->conn_info->dest_params->id,
- NCI_NFCEE_ENABLE);
+ r = nci_nfcee_mode_set(ndev, nfcee_id, NCI_NFCEE_ENABLE);
free_dest_params:
kfree(dest_params);
diff --git a/include/net/nfc/nci_core.h b/include/net/nfc/nci_core.h
index 664d5058e66e0..a5b186f273d97 100644
--- a/include/net/nfc/nci_core.h
+++ b/include/net/nfc/nci_core.h
@@ -19,6 +19,7 @@
#include <linux/interrupt.h>
#include <linux/skbuff.h>
+#include <linux/spinlock.h>
#include <linux/tty.h>
#include <net/nfc/nfc.h>
@@ -227,6 +228,8 @@ struct nci_dev {
struct sk_buff_head tx_q;
struct mutex req_lock;
+ /* Serializes conn_info_list and conn_info pointer alias updates. */
+ spinlock_t conn_info_lock;
struct completion req_completion;
__u32 req_status;
__u32 req_result;
@@ -382,8 +385,11 @@ void nci_clear_target_list(struct nci_dev *ndev);
#define NCI_REQ_CANCELED 2
void nci_req_complete(struct nci_dev *ndev, int result);
-struct nci_conn_info *nci_get_conn_info_by_conn_id(struct nci_dev *ndev,
- int conn_id);
+struct nci_conn_info *nci_get_conn_info_by_conn_id_locked(struct nci_dev *ndev,
+ int conn_id);
+int nci_get_conn_info_by_dest_type_params_locked(struct nci_dev *ndev,
+ u8 dest_type,
+ const struct dest_spec_params *params);
int nci_get_conn_info_by_dest_type_params(struct nci_dev *ndev, u8 dest_type,
const struct dest_spec_params *params);
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c
index 5f46c4b5720f6..57595a829c8b0 100644
--- a/net/nfc/nci/core.c
+++ b/net/nfc/nci/core.c
@@ -40,8 +40,8 @@ static void nci_cmd_work(struct work_struct *work);
static void nci_rx_work(struct work_struct *work);
static void nci_tx_work(struct work_struct *work);
-struct nci_conn_info *nci_get_conn_info_by_conn_id(struct nci_dev *ndev,
- int conn_id)
+struct nci_conn_info *nci_get_conn_info_by_conn_id_locked(struct nci_dev *ndev,
+ int conn_id)
{
struct nci_conn_info *conn_info;
@@ -53,8 +53,9 @@ struct nci_conn_info *nci_get_conn_info_by_conn_id(struct nci_dev *ndev,
return NULL;
}
-int nci_get_conn_info_by_dest_type_params(struct nci_dev *ndev, u8 dest_type,
- const struct dest_spec_params *params)
+int nci_get_conn_info_by_dest_type_params_locked(struct nci_dev *ndev,
+ u8 dest_type,
+ const struct dest_spec_params *params)
{
const struct nci_conn_info *conn_info;
@@ -71,6 +72,19 @@ int nci_get_conn_info_by_dest_type_params(struct nci_dev *ndev, u8 dest_type,
return -EINVAL;
}
+
+int nci_get_conn_info_by_dest_type_params(struct nci_dev *ndev, u8 dest_type,
+ const struct dest_spec_params *params)
+{
+ int conn_id;
+
+ spin_lock_bh(&ndev->conn_info_lock);
+ conn_id = nci_get_conn_info_by_dest_type_params_locked(ndev, dest_type,
+ params);
+ spin_unlock_bh(&ndev->conn_info_lock);
+
+ return conn_id;
+}
EXPORT_SYMBOL(nci_get_conn_info_by_dest_type_params);
/* ---- NCI requests ---- */
@@ -411,13 +425,17 @@ static void nci_nfcc_loopback_cb(void *context, struct sk_buff *skb, int err)
struct nci_dev *ndev = (struct nci_dev *)context;
struct nci_conn_info *conn_info;
- conn_info = nci_get_conn_info_by_conn_id(ndev, ndev->cur_conn_id);
+ spin_lock_bh(&ndev->conn_info_lock);
+ conn_info = nci_get_conn_info_by_conn_id_locked(ndev,
+ ndev->cur_conn_id);
if (!conn_info) {
+ spin_unlock_bh(&ndev->conn_info_lock);
nci_req_complete(ndev, NCI_STATUS_REJECTED);
return;
}
conn_info->rx_skb = skb;
+ spin_unlock_bh(&ndev->conn_info_lock);
nci_req_complete(ndev, NCI_STATUS_OK);
}
@@ -443,13 +461,17 @@ int nci_nfcc_loopback(struct nci_dev *ndev, const void *data, size_t data_len,
NULL);
}
- conn_info = nci_get_conn_info_by_conn_id(ndev, conn_id);
- if (!conn_info)
+ spin_lock_bh(&ndev->conn_info_lock);
+ conn_info = nci_get_conn_info_by_conn_id_locked(ndev, conn_id);
+ if (!conn_info) {
+ spin_unlock_bh(&ndev->conn_info_lock);
return -EPROTO;
+ }
/* store cb and context to be used on receiving data */
conn_info->data_exchange_cb = nci_nfcc_loopback_cb;
conn_info->data_exchange_cb_context = ndev;
+ spin_unlock_bh(&ndev->conn_info_lock);
skb = nci_skb_alloc(ndev, NCI_DATA_HDR_SIZE + data_len, GFP_KERNEL);
if (!skb)
@@ -464,8 +486,15 @@ int nci_nfcc_loopback(struct nci_dev *ndev, const void *data, size_t data_len,
ndev->cur_conn_id = conn_id;
r = nci_request(ndev, nci_send_data_req, &loopback_data,
msecs_to_jiffies(NCI_DATA_TIMEOUT));
- if (r == NCI_STATUS_OK && resp)
- *resp = conn_info->rx_skb;
+ if (r == NCI_STATUS_OK && resp) {
+ spin_lock_bh(&ndev->conn_info_lock);
+ conn_info = nci_get_conn_info_by_conn_id_locked(ndev, conn_id);
+ if (conn_info)
+ *resp = conn_info->rx_skb;
+ else
+ r = -EPROTO;
+ spin_unlock_bh(&ndev->conn_info_lock);
+ }
return r;
}
@@ -1045,12 +1074,6 @@ static int nci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target,
int rc;
struct nci_conn_info *conn_info;
- conn_info = ndev->rf_conn_info;
- if (!conn_info) {
- kfree_skb(skb);
- return -EPROTO;
- }
-
pr_debug("target_idx %d, len %d\n", target->idx, skb->len);
if (!ndev->target_active_prot) {
@@ -1064,9 +1087,19 @@ static int nci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target,
return -EBUSY;
}
+ spin_lock_bh(&ndev->conn_info_lock);
+ conn_info = ndev->rf_conn_info;
+ if (!conn_info) {
+ spin_unlock_bh(&ndev->conn_info_lock);
+ kfree_skb(skb);
+ clear_bit(NCI_DATA_EXCHANGE, &ndev->flags);
+ return -EPROTO;
+ }
+
/* store cb and context to be used on receiving data */
conn_info->data_exchange_cb = cb;
conn_info->data_exchange_cb_context = cb_context;
+ spin_unlock_bh(&ndev->conn_info_lock);
rc = nci_send_data(ndev, NCI_STATIC_RF_CONN_ID, skb);
if (rc)
@@ -1288,6 +1321,7 @@ int nci_register_device(struct nci_dev *ndev)
timer_setup(&ndev->data_timer, nci_data_timer, 0);
mutex_init(&ndev->req_lock);
+ spin_lock_init(&ndev->conn_info_lock);
INIT_LIST_HEAD(&ndev->conn_info_list);
rc = nfc_register_device(ndev->nfc_dev);
@@ -1333,11 +1367,16 @@ void nci_unregister_device(struct nci_dev *ndev)
destroy_workqueue(ndev->rx_wq);
destroy_workqueue(ndev->tx_wq);
+ spin_lock_bh(&ndev->conn_info_lock);
list_for_each_entry_safe(conn_info, n, &ndev->conn_info_list, list) {
list_del(&conn_info->list);
+ if (conn_info == ndev->rf_conn_info)
+ ndev->rf_conn_info = NULL;
+ if (conn_info == ndev->hci_dev->conn_info)
+ ndev->hci_dev->conn_info = NULL;
/* conn_info is allocated with devm_kzalloc */
}
-
+ spin_unlock_bh(&ndev->conn_info_lock);
nfc_remove_device(ndev->nfc_dev);
}
EXPORT_SYMBOL(nci_unregister_device);
@@ -1523,23 +1562,31 @@ static void nci_tx_work(struct work_struct *work)
struct nci_conn_info *conn_info;
struct sk_buff *skb;
- conn_info = nci_get_conn_info_by_conn_id(ndev, ndev->cur_conn_id);
- if (!conn_info)
- return;
+ /* Send queued tx data */
+ for (;;) {
+ spin_lock_bh(&ndev->conn_info_lock);
+ conn_info = nci_get_conn_info_by_conn_id_locked(ndev,
+ ndev->cur_conn_id);
+ if (!conn_info)
+ goto unlock;
- pr_debug("credits_cnt %d\n", atomic_read(&conn_info->credits_cnt));
+ pr_debug("credits_cnt %d\n",
+ atomic_read(&conn_info->credits_cnt));
+
+ if (!atomic_read(&conn_info->credits_cnt))
+ goto unlock;
- /* Send queued tx data */
- while (atomic_read(&conn_info->credits_cnt)) {
skb = skb_dequeue(&ndev->tx_q);
if (!skb)
- return;
- kcov_remote_start_common(skb_get_kcov_handle(skb));
+ goto unlock;
/* Check if data flow control is used */
if (atomic_read(&conn_info->credits_cnt) !=
NCI_DATA_FLOW_CONTROL_NOT_USED)
atomic_dec(&conn_info->credits_cnt);
+ spin_unlock_bh(&ndev->conn_info_lock);
+
+ kcov_remote_start_common(skb_get_kcov_handle(skb));
pr_debug("NCI TX: MT=data, PBF=%d, conn_id=%d, plen=%d\n",
nci_pbf(skb->data),
@@ -1552,6 +1599,9 @@ static void nci_tx_work(struct work_struct *work)
jiffies + msecs_to_jiffies(NCI_DATA_TIMEOUT));
kcov_remote_stop();
}
+
+unlock:
+ spin_unlock_bh(&ndev->conn_info_lock);
}
/* ----- NCI RX worker thread (data & control) ----- */
diff --git a/net/nfc/nci/data.c b/net/nfc/nci/data.c
index 5f98c73db5afd..334c0e5a94dbc 100644
--- a/net/nfc/nci/data.c
+++ b/net/nfc/nci/data.c
@@ -30,8 +30,10 @@ void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb,
data_exchange_cb_t cb;
void *cb_context;
- conn_info = nci_get_conn_info_by_conn_id(ndev, conn_id);
+ spin_lock_bh(&ndev->conn_info_lock);
+ conn_info = nci_get_conn_info_by_conn_id_locked(ndev, conn_id);
if (!conn_info) {
+ spin_unlock_bh(&ndev->conn_info_lock);
kfree_skb(skb);
clear_bit(NCI_DATA_EXCHANGE, &ndev->flags);
return;
@@ -39,6 +41,7 @@ void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb,
cb = conn_info->data_exchange_cb;
cb_context = conn_info->data_exchange_cb_context;
+ spin_unlock_bh(&ndev->conn_info_lock);
pr_debug("len %d, err %d\n", skb ? skb->len : 0, err);
@@ -85,19 +88,26 @@ static inline void nci_push_data_hdr(struct nci_dev *ndev,
int nci_conn_max_data_pkt_payload_size(struct nci_dev *ndev, __u8 conn_id)
{
const struct nci_conn_info *conn_info;
+ int max_pkt_payload_len;
- conn_info = nci_get_conn_info_by_conn_id(ndev, conn_id);
- if (!conn_info)
+ spin_lock_bh(&ndev->conn_info_lock);
+ conn_info = nci_get_conn_info_by_conn_id_locked(ndev, conn_id);
+ if (!conn_info) {
+ spin_unlock_bh(&ndev->conn_info_lock);
return -EPROTO;
+ }
+ max_pkt_payload_len = conn_info->max_pkt_payload_len;
+ spin_unlock_bh(&ndev->conn_info_lock);
- return conn_info->max_pkt_payload_len;
+ return max_pkt_payload_len;
}
EXPORT_SYMBOL(nci_conn_max_data_pkt_payload_size);
static int nci_queue_tx_data_frags(struct nci_dev *ndev,
__u8 conn_id,
- struct sk_buff *skb) {
- const struct nci_conn_info *conn_info;
+ struct sk_buff *skb,
+ __u8 max_pkt_payload_len)
+{
int total_len = skb->len;
const unsigned char *data = skb->data;
unsigned long flags;
@@ -108,17 +118,10 @@ static int nci_queue_tx_data_frags(struct nci_dev *ndev,
pr_debug("conn_id 0x%x, total_len %d\n", conn_id, total_len);
- conn_info = nci_get_conn_info_by_conn_id(ndev, conn_id);
- if (!conn_info) {
- rc = -EPROTO;
- goto exit;
- }
-
__skb_queue_head_init(&frags_q);
while (total_len) {
- frag_len =
- min_t(int, total_len, conn_info->max_pkt_payload_len);
+ frag_len = min_t(int, total_len, max_pkt_payload_len);
skb_frag = nci_skb_alloc(ndev,
(NCI_DATA_HDR_SIZE + frag_len),
@@ -171,40 +174,47 @@ static int nci_queue_tx_data_frags(struct nci_dev *ndev,
int nci_send_data(struct nci_dev *ndev, __u8 conn_id, struct sk_buff *skb)
{
const struct nci_conn_info *conn_info;
+ __u8 max_pkt_payload_len;
int rc = 0;
pr_debug("conn_id 0x%x, plen %d\n", conn_id, skb->len);
- conn_info = nci_get_conn_info_by_conn_id(ndev, conn_id);
+ spin_lock_bh(&ndev->conn_info_lock);
+ conn_info = nci_get_conn_info_by_conn_id_locked(ndev, conn_id);
if (!conn_info) {
rc = -EPROTO;
- goto free_exit;
+ goto unlock;
}
+ max_pkt_payload_len = conn_info->max_pkt_payload_len;
+ spin_unlock_bh(&ndev->conn_info_lock);
/* check if the packet need to be fragmented */
- if (skb->len <= conn_info->max_pkt_payload_len) {
+ if (skb->len <= max_pkt_payload_len) {
/* no need to fragment packet */
nci_push_data_hdr(ndev, conn_id, skb, NCI_PBF_LAST);
skb_queue_tail(&ndev->tx_q, skb);
} else {
/* fragment packet and queue the fragments */
- rc = nci_queue_tx_data_frags(ndev, conn_id, skb);
+ rc = nci_queue_tx_data_frags(ndev, conn_id, skb,
+ max_pkt_payload_len);
if (rc) {
pr_err("failed to fragment tx data packet\n");
- goto free_exit;
+ kfree_skb(skb);
+ return rc;
}
}
+ spin_lock_bh(&ndev->conn_info_lock);
ndev->cur_conn_id = conn_id;
- queue_work(ndev->tx_wq, &ndev->tx_work);
-
- goto exit;
-
-free_exit:
- kfree_skb(skb);
+ spin_unlock_bh(&ndev->conn_info_lock);
-exit:
+ queue_work(ndev->tx_wq, &ndev->tx_work);
+ return rc;
+unlock:
+ spin_unlock_bh(&ndev->conn_info_lock);
+ if (rc)
+ kfree_skb(skb);
return rc;
}
EXPORT_SYMBOL(nci_send_data);
@@ -282,11 +292,15 @@ void nci_rx_data_packet(struct nci_dev *ndev, struct sk_buff *skb)
nci_conn_id(skb->data),
nci_plen(skb->data));
- conn_info = nci_get_conn_info_by_conn_id(ndev, nci_conn_id(skb->data));
+ spin_lock_bh(&ndev->conn_info_lock);
+ conn_info = nci_get_conn_info_by_conn_id_locked(ndev,
+ nci_conn_id(skb->data));
if (!conn_info) {
+ spin_unlock_bh(&ndev->conn_info_lock);
kfree_skb(skb);
return;
}
+ spin_unlock_bh(&ndev->conn_info_lock);
/* strip the nci data header */
skb_pull(skb, NCI_DATA_HDR_SIZE);
diff --git a/net/nfc/nci/hci.c b/net/nfc/nci/hci.c
index c03e8a0bd3bd6..e2f7ab15973ce 100644
--- a/net/nfc/nci/hci.c
+++ b/net/nfc/nci/hci.c
@@ -147,14 +147,22 @@ static int nci_hci_send_data(struct nci_dev *ndev, u8 pipe,
struct sk_buff *skb;
int len, i, r;
u8 cb = pipe;
+ u8 conn_id;
+ u8 max_pkt_payload_len;
+ spin_lock_bh(&ndev->conn_info_lock);
conn_info = ndev->hci_dev->conn_info;
- if (!conn_info)
+ if (!conn_info) {
+ spin_unlock_bh(&ndev->conn_info_lock);
return -EPROTO;
+ }
+ conn_id = conn_info->conn_id;
+ max_pkt_payload_len = conn_info->max_pkt_payload_len;
+ spin_unlock_bh(&ndev->conn_info_lock);
i = 0;
- skb = nci_skb_alloc(ndev, conn_info->max_pkt_payload_len +
- NCI_DATA_HDR_SIZE, GFP_ATOMIC);
+ skb = nci_skb_alloc(ndev, max_pkt_payload_len + NCI_DATA_HDR_SIZE,
+ GFP_ATOMIC);
if (!skb)
return -ENOMEM;
@@ -163,12 +171,11 @@ static int nci_hci_send_data(struct nci_dev *ndev, u8 pipe,
do {
/* If last packet add NCI_HFP_NO_CHAINING */
- if (i + conn_info->max_pkt_payload_len -
- (skb->len + 1) >= data_len) {
+ if (i + max_pkt_payload_len - (skb->len + 1) >= data_len) {
cb |= NCI_HFP_NO_CHAINING;
len = data_len - i;
} else {
- len = conn_info->max_pkt_payload_len - skb->len - 1;
+ len = max_pkt_payload_len - skb->len - 1;
}
*(u8 *)skb_push(skb, 1) = cb;
@@ -176,15 +183,14 @@ static int nci_hci_send_data(struct nci_dev *ndev, u8 pipe,
if (len > 0)
skb_put_data(skb, data + i, len);
- r = nci_send_data(ndev, conn_info->conn_id, skb);
+ r = nci_send_data(ndev, conn_id, skb);
if (r < 0)
return r;
i += len;
if (i < data_len) {
- skb = nci_skb_alloc(ndev,
- conn_info->max_pkt_payload_len +
+ skb = nci_skb_alloc(ndev, max_pkt_payload_len +
NCI_DATA_HDR_SIZE, GFP_ATOMIC);
if (!skb)
return -ENOMEM;
@@ -225,17 +231,22 @@ int nci_hci_send_cmd(struct nci_dev *ndev, u8 gate, u8 cmd,
const struct nci_hcp_message *message;
const struct nci_conn_info *conn_info;
struct nci_data data;
+ struct sk_buff *rx_skb;
int r;
u8 pipe = ndev->hci_dev->gate2pipe[gate];
if (pipe == NCI_HCI_INVALID_PIPE)
return -EADDRNOTAVAIL;
+ spin_lock_bh(&ndev->conn_info_lock);
conn_info = ndev->hci_dev->conn_info;
- if (!conn_info)
+ if (!conn_info) {
+ spin_unlock_bh(&ndev->conn_info_lock);
return -EPROTO;
+ }
data.conn_id = conn_info->conn_id;
+ spin_unlock_bh(&ndev->conn_info_lock);
data.pipe = pipe;
data.cmd = NCI_HCP_HEADER(NCI_HCI_HCP_COMMAND, cmd);
data.data = param;
@@ -244,13 +255,22 @@ int nci_hci_send_cmd(struct nci_dev *ndev, u8 gate, u8 cmd,
r = nci_request(ndev, nci_hci_send_data_req, &data,
msecs_to_jiffies(NCI_DATA_TIMEOUT));
if (r == NCI_STATUS_OK) {
- message = (struct nci_hcp_message *)conn_info->rx_skb->data;
+ spin_lock_bh(&ndev->conn_info_lock);
+ conn_info = ndev->hci_dev->conn_info;
+ rx_skb = conn_info ? conn_info->rx_skb : NULL;
+ if (!rx_skb) {
+ spin_unlock_bh(&ndev->conn_info_lock);
+ return -EPROTO;
+ }
+
+ message = (struct nci_hcp_message *)rx_skb->data;
r = nci_hci_result_to_errno(
NCI_HCP_MSG_GET_CMD(message->header));
- skb_pull(conn_info->rx_skb, NCI_HCI_HCP_MESSAGE_HEADER_LEN);
+ skb_pull(rx_skb, NCI_HCI_HCP_MESSAGE_HEADER_LEN);
+ spin_unlock_bh(&ndev->conn_info_lock);
if (!r && skb)
- *skb = conn_info->rx_skb;
+ *skb = rx_skb;
}
return r;
@@ -366,11 +386,15 @@ static void nci_hci_resp_received(struct nci_dev *ndev, u8 pipe,
{
struct nci_conn_info *conn_info;
+ spin_lock_bh(&ndev->conn_info_lock);
conn_info = ndev->hci_dev->conn_info;
- if (!conn_info)
+ if (!conn_info) {
+ spin_unlock_bh(&ndev->conn_info_lock);
goto exit;
+ }
conn_info->rx_skb = skb;
+ spin_unlock_bh(&ndev->conn_info_lock);
exit:
nci_req_complete(ndev, NCI_STATUS_OK);
@@ -510,11 +534,15 @@ int nci_hci_open_pipe(struct nci_dev *ndev, u8 pipe)
struct nci_data data;
const struct nci_conn_info *conn_info;
+ spin_lock_bh(&ndev->conn_info_lock);
conn_info = ndev->hci_dev->conn_info;
- if (!conn_info)
+ if (!conn_info) {
+ spin_unlock_bh(&ndev->conn_info_lock);
return -EPROTO;
+ }
data.conn_id = conn_info->conn_id;
+ spin_unlock_bh(&ndev->conn_info_lock);
data.pipe = pipe;
data.cmd = NCI_HCP_HEADER(NCI_HCI_HCP_COMMAND,
NCI_HCI_ANY_OPEN_PIPE);
@@ -569,6 +597,7 @@ int nci_hci_set_param(struct nci_dev *ndev, u8 gate, u8 idx,
const struct nci_hcp_message *message;
const struct nci_conn_info *conn_info;
struct nci_data data;
+ struct sk_buff *rx_skb;
int r;
u8 *tmp;
u8 pipe = ndev->hci_dev->gate2pipe[gate];
@@ -578,9 +607,14 @@ int nci_hci_set_param(struct nci_dev *ndev, u8 gate, u8 idx,
if (pipe == NCI_HCI_INVALID_PIPE)
return -EADDRNOTAVAIL;
+ spin_lock_bh(&ndev->conn_info_lock);
conn_info = ndev->hci_dev->conn_info;
- if (!conn_info)
+ if (!conn_info) {
+ spin_unlock_bh(&ndev->conn_info_lock);
return -EPROTO;
+ }
+ data.conn_id = conn_info->conn_id;
+ spin_unlock_bh(&ndev->conn_info_lock);
tmp = kmalloc(1 + param_len, GFP_KERNEL);
if (!tmp)
@@ -589,7 +623,6 @@ int nci_hci_set_param(struct nci_dev *ndev, u8 gate, u8 idx,
*tmp = idx;
memcpy(tmp + 1, param, param_len);
- data.conn_id = conn_info->conn_id;
data.pipe = pipe;
data.cmd = NCI_HCP_HEADER(NCI_HCI_HCP_COMMAND,
NCI_HCI_ANY_SET_PARAMETER);
@@ -599,10 +632,20 @@ int nci_hci_set_param(struct nci_dev *ndev, u8 gate, u8 idx,
r = nci_request(ndev, nci_hci_send_data_req, &data,
msecs_to_jiffies(NCI_DATA_TIMEOUT));
if (r == NCI_STATUS_OK) {
- message = (struct nci_hcp_message *)conn_info->rx_skb->data;
+ spin_lock_bh(&ndev->conn_info_lock);
+ conn_info = ndev->hci_dev->conn_info;
+ rx_skb = conn_info ? conn_info->rx_skb : NULL;
+ if (!rx_skb) {
+ spin_unlock_bh(&ndev->conn_info_lock);
+ kfree(tmp);
+ return -EPROTO;
+ }
+
+ message = (struct nci_hcp_message *)rx_skb->data;
r = nci_hci_result_to_errno(
NCI_HCP_MSG_GET_CMD(message->header));
- skb_pull(conn_info->rx_skb, NCI_HCI_HCP_MESSAGE_HEADER_LEN);
+ skb_pull(rx_skb, NCI_HCI_HCP_MESSAGE_HEADER_LEN);
+ spin_unlock_bh(&ndev->conn_info_lock);
}
kfree(tmp);
@@ -616,6 +659,7 @@ int nci_hci_get_param(struct nci_dev *ndev, u8 gate, u8 idx,
const struct nci_hcp_message *message;
const struct nci_conn_info *conn_info;
struct nci_data data;
+ struct sk_buff *rx_skb;
int r;
u8 pipe = ndev->hci_dev->gate2pipe[gate];
@@ -624,11 +668,15 @@ int nci_hci_get_param(struct nci_dev *ndev, u8 gate, u8 idx,
if (pipe == NCI_HCI_INVALID_PIPE)
return -EADDRNOTAVAIL;
+ spin_lock_bh(&ndev->conn_info_lock);
conn_info = ndev->hci_dev->conn_info;
- if (!conn_info)
+ if (!conn_info) {
+ spin_unlock_bh(&ndev->conn_info_lock);
return -EPROTO;
+ }
data.conn_id = conn_info->conn_id;
+ spin_unlock_bh(&ndev->conn_info_lock);
data.pipe = pipe;
data.cmd = NCI_HCP_HEADER(NCI_HCI_HCP_COMMAND,
NCI_HCI_ANY_GET_PARAMETER);
@@ -639,13 +687,22 @@ int nci_hci_get_param(struct nci_dev *ndev, u8 gate, u8 idx,
msecs_to_jiffies(NCI_DATA_TIMEOUT));
if (r == NCI_STATUS_OK) {
- message = (struct nci_hcp_message *)conn_info->rx_skb->data;
+ spin_lock_bh(&ndev->conn_info_lock);
+ conn_info = ndev->hci_dev->conn_info;
+ rx_skb = conn_info ? conn_info->rx_skb : NULL;
+ if (!rx_skb) {
+ spin_unlock_bh(&ndev->conn_info_lock);
+ return -EPROTO;
+ }
+
+ message = (struct nci_hcp_message *)rx_skb->data;
r = nci_hci_result_to_errno(
NCI_HCP_MSG_GET_CMD(message->header));
- skb_pull(conn_info->rx_skb, NCI_HCI_HCP_MESSAGE_HEADER_LEN);
+ skb_pull(rx_skb, NCI_HCI_HCP_MESSAGE_HEADER_LEN);
+ spin_unlock_bh(&ndev->conn_info_lock);
if (!r && skb)
- *skb = conn_info->rx_skb;
+ *skb = rx_skb;
}
return r;
@@ -729,12 +786,16 @@ int nci_hci_dev_session_init(struct nci_dev *ndev)
ndev->hci_dev->count_pipes = 0;
ndev->hci_dev->expected_pipes = 0;
+ spin_lock_bh(&ndev->conn_info_lock);
conn_info = ndev->hci_dev->conn_info;
- if (!conn_info)
+ if (!conn_info) {
+ spin_unlock_bh(&ndev->conn_info_lock);
return -EPROTO;
+ }
conn_info->data_exchange_cb = nci_hci_data_received_cb;
conn_info->data_exchange_cb_context = ndev;
+ spin_unlock_bh(&ndev->conn_info_lock);
nci_hci_reset_pipes(ndev->hci_dev);
diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c
index c96512bb86531..4828a1c9d35f0 100644
--- a/net/nfc/nci/ntf.c
+++ b/net/nfc/nci/ntf.c
@@ -81,13 +81,17 @@ static int nci_core_conn_credits_ntf_packet(struct nci_dev *ndev,
i, ntf->conn_entries[i].conn_id,
ntf->conn_entries[i].credits);
- conn_info = nci_get_conn_info_by_conn_id(ndev,
- ntf->conn_entries[i].conn_id);
- if (!conn_info)
+ spin_lock_bh(&ndev->conn_info_lock);
+ conn_info = nci_get_conn_info_by_conn_id_locked(ndev,
+ ntf->conn_entries[i].conn_id);
+ if (!conn_info) {
+ spin_unlock_bh(&ndev->conn_info_lock);
return 0;
+ }
atomic_add(ntf->conn_entries[i].credits,
&conn_info->credits_cnt);
+ spin_unlock_bh(&ndev->conn_info_lock);
}
/* trigger the next tx */
@@ -828,9 +832,12 @@ static int nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
exit:
if (err == NCI_STATUS_OK) {
+ spin_lock_bh(&ndev->conn_info_lock);
conn_info = ndev->rf_conn_info;
- if (!conn_info)
+ if (!conn_info) {
+ spin_unlock_bh(&ndev->conn_info_lock);
return 0;
+ }
conn_info->max_pkt_payload_len = ntf.max_data_pkt_payload_size;
conn_info->initial_num_credits = ntf.initial_num_credits;
@@ -838,6 +845,7 @@ static int nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
/* set the available credits to initial value */
atomic_set(&conn_info->credits_cnt,
conn_info->initial_num_credits);
+ spin_unlock_bh(&ndev->conn_info_lock);
/* store general bytes to be reported later in dep_link_up */
if (ntf.rf_interface == NCI_RF_INTERFACE_NFC_DEP) {
@@ -901,9 +909,13 @@ static int nci_rf_deactivate_ntf_packet(struct nci_dev *ndev,
pr_debug("entry, type 0x%x, reason 0x%x\n", ntf->type, ntf->reason);
+ spin_lock_bh(&ndev->conn_info_lock);
conn_info = ndev->rf_conn_info;
- if (!conn_info)
+ if (!conn_info) {
+ spin_unlock_bh(&ndev->conn_info_lock);
return 0;
+ }
+ spin_unlock_bh(&ndev->conn_info_lock);
/* drop tx data queue */
skb_queue_purge(&ndev->tx_q);
diff --git a/net/nfc/nci/rsp.c b/net/nfc/nci/rsp.c
index 9eeb862825c5f..0cff1250923ed 100644
--- a/net/nfc/nci/rsp.c
+++ b/net/nfc/nci/rsp.c
@@ -186,6 +186,7 @@ static void nci_rf_disc_rsp_packet(struct nci_dev *ndev,
const struct sk_buff *skb)
{
struct nci_conn_info *conn_info;
+ struct nci_conn_info *new_conn_info;
__u8 status = skb->data[0];
pr_debug("status 0x%x\n", status);
@@ -193,19 +194,33 @@ static void nci_rf_disc_rsp_packet(struct nci_dev *ndev,
if (status == NCI_STATUS_OK) {
atomic_set(&ndev->state, NCI_DISCOVERY);
+ spin_lock_bh(&ndev->conn_info_lock);
conn_info = ndev->rf_conn_info;
+ spin_unlock_bh(&ndev->conn_info_lock);
+
if (!conn_info) {
- conn_info = devm_kzalloc(&ndev->nfc_dev->dev,
- sizeof(struct nci_conn_info),
- GFP_KERNEL);
- if (!conn_info) {
+ new_conn_info = devm_kzalloc(&ndev->nfc_dev->dev,
+ sizeof(struct nci_conn_info),
+ GFP_KERNEL);
+ if (!new_conn_info) {
status = NCI_STATUS_REJECTED;
goto exit;
}
- conn_info->conn_id = NCI_STATIC_RF_CONN_ID;
- INIT_LIST_HEAD(&conn_info->list);
- list_add(&conn_info->list, &ndev->conn_info_list);
- ndev->rf_conn_info = conn_info;
+
+ new_conn_info->conn_id = NCI_STATIC_RF_CONN_ID;
+ INIT_LIST_HEAD(&new_conn_info->list);
+
+ spin_lock_bh(&ndev->conn_info_lock);
+ if (!ndev->rf_conn_info) {
+ list_add(&new_conn_info->list,
+ &ndev->conn_info_list);
+ ndev->rf_conn_info = new_conn_info;
+ new_conn_info = NULL;
+ }
+ spin_unlock_bh(&ndev->conn_info_lock);
+
+ if (new_conn_info)
+ devm_kfree(&ndev->nfc_dev->dev, new_conn_info);
}
}
@@ -298,20 +313,20 @@ static void nci_core_conn_create_rsp_packet(struct nci_dev *ndev,
conn_info->dest_params->id = ndev->cur_params.id;
conn_info->dest_params->protocol = ndev->cur_params.protocol;
conn_info->conn_id = rsp->conn_id;
+ conn_info->max_pkt_payload_len = rsp->max_ctrl_pkt_payload_len;
+ atomic_set(&conn_info->credits_cnt, rsp->credits_cnt);
/* Note: data_exchange_cb and data_exchange_cb_context need to
* be specify out of nci_core_conn_create_rsp_packet
*/
INIT_LIST_HEAD(&conn_info->list);
+ spin_lock_bh(&ndev->conn_info_lock);
list_add(&conn_info->list, &ndev->conn_info_list);
if (ndev->cur_params.id == ndev->hci_dev->nfcee_id)
ndev->hci_dev->conn_info = conn_info;
-
- conn_info->conn_id = rsp->conn_id;
- conn_info->max_pkt_payload_len = rsp->max_ctrl_pkt_payload_len;
- atomic_set(&conn_info->credits_cnt, rsp->credits_cnt);
+ spin_unlock_bh(&ndev->conn_info_lock);
}
free_conn_info:
@@ -330,14 +345,19 @@ static void nci_core_conn_close_rsp_packet(struct nci_dev *ndev,
pr_debug("status 0x%x\n", status);
if (status == NCI_STATUS_OK) {
- conn_info = nci_get_conn_info_by_conn_id(ndev,
- ndev->cur_conn_id);
+ spin_lock_bh(&ndev->conn_info_lock);
+ conn_info = nci_get_conn_info_by_conn_id_locked(ndev,
+ ndev->cur_conn_id);
if (conn_info) {
list_del(&conn_info->list);
if (conn_info == ndev->rf_conn_info)
ndev->rf_conn_info = NULL;
- devm_kfree(&ndev->nfc_dev->dev, conn_info);
+ if (conn_info == ndev->hci_dev->conn_info)
+ ndev->hci_dev->conn_info = NULL;
}
+ spin_unlock_bh(&ndev->conn_info_lock);
+ if (conn_info)
+ devm_kfree(&ndev->nfc_dev->dev, conn_info);
}
nci_req_complete(ndev, status);
}
--
2.48.1
^ permalink raw reply related
* [PATCH net v2] octeontx2-pf: fix SQB pointer leak on init failure
From: Dawei Feng @ 2026-06-30 7:16 UTC (permalink / raw)
To: sgoutham
Cc: rkannoth, gakula, sbhatta, hkelam, bbhushan2, andrew+netdev,
davem, edumazet, kuba, pabeni, jbrandeb, richardcochran, amakarov,
netdev, linux-kernel, stable, jianhao.xu, zilin, Dawei Feng
otx2_init_hw_resources() initializes SQ aura and pool resources before
several later setup steps. On failure, err_free_sq_ptrs only frees SQB
pages, leaving the per-SQ sqb_ptrs arrays behind.
Use otx2_free_sq_res() for the SQ unwind path and let it free sqb_ptrs
even when sq->sqe has not been allocated yet.
The bug was first flagged by an experimental analysis tool we are
developing for kernel memory-management bugs while analyzing
v6.13-rc1. The tool is still under development and is not yet publicly
available. Manual inspection confirms that the bug is still
present in v7.1.1.
An x86_64 allyesconfig build showed no new warnings. As we do not have an
OcteonTX2 PF device and the corresponding AF mailbox setup to test with,
no runtime testing was able to be performed.
Fixes: caa2da34fd25 ("octeontx2-pf: Initialize and config queues")
Cc: stable@vger.kernel.org
Reviewed-by: Ratheesh Kannoth <rkannoth@marvell.com>
Signed-off-by: Dawei Feng <dawei.feng@seu.edu.cn>
---
v2:
- Rebase on net/main.
- Drop the timestamp qmem cleanup and the PTP Fixes tag because net/main
already has commit a056db30de92 ("octeontx2-pf: Fix leak of SQ timestamp
buffer on teardown").
.../ethernet/marvell/octeontx2/nic/otx2_pf.c | 21 +++++++++----------
1 file changed, 10 insertions(+), 11 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
index b63df5737ff2..88ac85354445 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
@@ -1568,15 +1568,15 @@ static void otx2_free_sq_res(struct otx2_nic *pf)
otx2_sq_free_sqbs(pf);
for (qidx = 0; qidx < otx2_get_total_tx_queues(pf); qidx++) {
sq = &qset->sq[qidx];
- /* Skip freeing Qos queues if they are not initialized */
- if (!sq->sqe)
- continue;
- qmem_free(pf->dev, sq->sqe);
- qmem_free(pf->dev, sq->sqe_ring);
- qmem_free(pf->dev, sq->cpt_resp);
- qmem_free(pf->dev, sq->tso_hdrs);
- qmem_free(pf->dev, sq->timestamps);
- kfree(sq->sg);
+ /* sq->sqe is not initialized for unused QoS queues */
+ if (sq->sqe) {
+ qmem_free(pf->dev, sq->sqe);
+ qmem_free(pf->dev, sq->sqe_ring);
+ qmem_free(pf->dev, sq->cpt_resp);
+ qmem_free(pf->dev, sq->tso_hdrs);
+ qmem_free(pf->dev, sq->timestamps);
+ kfree(sq->sg);
+ }
kfree(sq->sqb_ptrs);
}
}
@@ -1711,13 +1711,12 @@ int otx2_init_hw_resources(struct otx2_nic *pf)
return err;
err_free_nix_queues:
- otx2_free_sq_res(pf);
otx2_free_cq_res(pf);
otx2_ctx_disable(mbox, NIX_AQ_CTYPE_RQ, false);
err_free_txsch:
otx2_txschq_stop(pf);
err_free_sq_ptrs:
- otx2_sq_free_sqbs(pf);
+ otx2_free_sq_res(pf);
err_free_rq_ptrs:
otx2_free_aura_ptr(pf, AURA_NIX_RQ);
otx2_ctx_disable(mbox, NPA_AQ_CTYPE_POOL, true);
--
2.34.1
^ permalink raw reply related
* Re: [PATCH net-next 1/2] tools: ynl: pyynl: re-export the library API from the package root
From: Jan Stancek @ 2026-06-30 7:28 UTC (permalink / raw)
To: Jakub Kicinski
Cc: davem, netdev, edumazet, pabeni, andrew+netdev, horms,
donald.hunter, sdf, gal, ast
In-Reply-To: <20260630001432.2204298-2-kuba@kernel.org>
On Tue, Jun 30, 2026 at 2:20 AM Jakub Kicinski <kuba@kernel.org> wrote:
>
> The public classes live in pyynl.lib, so users had to spell out
>
> from pyynl.lib import YnlFamily
>
> which I forget at least once a month. Re-export lib's API from
> the package __init__ so that
>
> from pyynl import YnlFamily
>
> works as well. I don't think there was a real reason not to do
> this?
I think it was more uncertainty on my part whether in future we get
more subdirectories.
Acked-by: Jan Stancek <jstancek@redhat.com>
>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
> tools/net/ynl/pyynl/__init__.py | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/tools/net/ynl/pyynl/__init__.py b/tools/net/ynl/pyynl/__init__.py
> index e69de29bb2d1..d8f59c132ab7 100644
> --- a/tools/net/ynl/pyynl/__init__.py
> +++ b/tools/net/ynl/pyynl/__init__.py
> @@ -0,0 +1,9 @@
> +# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
> +
> +""" Python YNL (YAML Netlink) library. """
> +
> +# Re-export the public library API so it can be imported straight from the
> +# package, e.g. `from pyynl import YnlFamily`.
> +# pylint: disable=wildcard-import,unused-wildcard-import
> +from .lib import *
> +from .lib import __all__
> --
> 2.54.0
>
^ permalink raw reply
* Re: [PATCH v2 1/6] dt-bindings: net: bluetooth: Document Qualcomm IPQ5018 Bluetooth controller
From: George Moussalem @ 2026-06-30 7:31 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Jens Axboe, Ulf Hansson, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Johannes Berg, Jeff Johnson, Bartosz Golaszewski,
Marcel Holtmann, Luiz Augusto von Dentz, Balakrishna Godavarthi,
Rocky Liao, Saravana Kannan, Andrew Lunn, Heiner Kallweit,
Russell King, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Bjorn Andersson, Konrad Dybcio,
Mathieu Poirier, Philipp Zabel, linux-block, linux-kernel,
linux-mmc, devicetree, linux-wireless, ath10k, linux-arm-msm,
linux-bluetooth, netdev, linux-remoteproc
In-Reply-To: <20260630-wondrous-lean-stoat-be0b9a@quoll>
On 6/30/26 11:15, Krzysztof Kozlowski wrote:
> On Mon, Jun 29, 2026 at 05:01:44PM +0400, George Moussalem wrote:
>> +unevaluatedProperties: false
>> +
>> +examples:
>> + - |
>> + #include <dt-bindings/clock/qcom,gcc-ipq5018.h>
>> + #include <dt-bindings/interrupt-controller/arm-gic.h>
>> + #include <dt-bindings/reset/qcom,gcc-ipq5018.h>
>> +
>> + bluetooth {
>
> Don't send new versions while discussion is still going. I need to
> repeat my question - what bus does that sit on?
>
> Device nodes represent real devices. Real devices sit on a bus, usually.
> Do you have here a bus?
I'm afraid I don't have a definitive answer. Again, my understanding
based on downstream code is that the 'controller' is basically a Cortex
M0 processor running Bluetooth firmware connected to an RF. Data
transport is over a shared memory carveout with APPS signaling the
controller through writes to an IPC mailbox register, while the
controller has an interrupt line back to signal APPS.
>
>> + compatible = "qcom,ipq5018-bt";
>
> Best regards,
> Krzysztof
>
Best regards,
George
^ permalink raw reply
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