* [PATCH v4 0/5] Add Cix Sky1 AUDSS clock and reset support
From: joakim.zhang @ 2026-06-17 6:04 UTC (permalink / raw)
To: mturquette, sboyd, bmasney, robh, krzk+dt, conor+dt, p.zabel,
gary.yang
Cc: cix-kernel-upstream, linux-clk, devicetree, linux-kernel,
linux-arm-kernel, Joakim Zhang
From: Joakim Zhang <joakim.zhang@cixtech.com>
This patch set adds the clock and reset support for AUDSS. The AUDSS
groups audio-related peripherals (HDA, I2S, DSP, DMA, mailboxes,
watchdog, timer, etc.) behind a single Clock and Reset Unit (CRU)
register block.
Clock and reset changes normally belong to separate subsystems and would
ideally be submitted as independent series. They are combined here because
the AUDSS DT bindings cross-reference each other: the system-control
binding describes the clock child node, the clock binding documents
reset lines exposed on the parent syscon, and the DTS example wires both
together. Keeping clock and reset in one series gives reviewers the full
picture when evaluating the binding layout, dependencies, and
integration.
Patches apply in the following order:
1. Reset support
- dt-bindings: soc: cix,sky1-system-control: add audss system control
- reset: cix: add audss support to sky1 reset driver
2. Clock support
- dt-bindings: clock: cix,sky1-audss-clock: add audss clock controller
- clk: cix: add sky1 audss clock controller
3. Device tree
- arm64: dts: cix: sky1: add audss system control
The reset and clock parts have each been build-tested and checked with
dt_binding_check independently. If reviewers prefer separate series for
the reset and clock maintainers, I can split and resubmit after this
round of review once the overall design is agreed on.
---
ChangeLogs:
v3->v4:
* move both power domain and resets into parset node (audss_cru)
* remove "simple-mfd", and change to populate the child node
* cix,sky1-audss.h -> cix,sky1-audss-clock.h
v2->v3:
* clk part:
* devm_reset_control_get()->devm_reset_control_get_exclusive()
* assert noc reset from suspend
* clock parents changes from 6 to 4, and rename the clock names,
explain more about this: confirm with our designer, In fact,
there are 6 clock sources going into the audio subsystem. audio_clk1
and audio_clk3 are redundant in design and are not actually needed
in practice, so they are not shown here.
* refine clocks and clock-names property
* add detailed description of clocks
* drop parent node from clk binding
* drop define AUDSS_MAX_CLKS
* reset part:
* rename reset signal macro, remove _N
* drop SKY1_AUDSS_SW_RESET_NUM
* switching to compatible-style of defining subnodes in parent schema
v1->v2:
* remove audss_rst device node since it doesn't has resource, and
move to reset-sky1.c driver.
* remove hda related which would be sent after this patch set accepted
* soc componnet is okay by default from dtsi
* fix for audss clk driver:
* remove "comment "Clock options for Cixtech audss:""
* add select MFD_SYSCON
* move lock and clk_data into struct sky1_audss_clks_priv
* const char *name -> const char * const * name
* remove CLK_GET_RATE_NOCACHE
* divicer -> divider
* Reverse Christmas tree order
* return reg ? 1 : 0; -> return !!reg;
* return ERR_CAST(hw); -> return hw;
* of_device_get_match_data(dev) -> device_get_match_data()
* add lock from runtime_suspend/resume
* loop to more mailing lists
Joakim Zhang (5):
dt-bindings: soc: cix,sky1-system-control: add audss system control
reset: cix: add audss support to sky1 reset driver
dt-bindings: clock: cix,sky1-audss-clock: add audss clock controller
clk: cix: add sky1 audss clock controller
arm64: dts: cix: sky1: add audss system control
.../bindings/clock/cix,sky1-audss-clock.yaml | 72 +
.../soc/cix/cix,sky1-system-control.yaml | 48 +
arch/arm64/boot/dts/cix/sky1.dtsi | 24 +
drivers/clk/Kconfig | 1 +
drivers/clk/Makefile | 1 +
drivers/clk/cix/Kconfig | 16 +
drivers/clk/cix/Makefile | 3 +
drivers/clk/cix/clk-sky1-audss.c | 1167 +++++++++++++++++
drivers/reset/reset-sky1.c | 86 +-
.../dt-bindings/clock/cix,sky1-audss-clock.h | 60 +
.../reset/cix,sky1-audss-system-control.h | 25 +
11 files changed, 1500 insertions(+), 3 deletions(-)
create mode 100644 Documentation/devicetree/bindings/clock/cix,sky1-audss-clock.yaml
create mode 100644 drivers/clk/cix/Kconfig
create mode 100644 drivers/clk/cix/Makefile
create mode 100644 drivers/clk/cix/clk-sky1-audss.c
create mode 100644 include/dt-bindings/clock/cix,sky1-audss-clock.h
create mode 100644 include/dt-bindings/reset/cix,sky1-audss-system-control.h
--
2.50.1
^ permalink raw reply
* [PATCH v4 3/5] dt-bindings: clock: cix,sky1-audss-clock: add audss clock controller
From: joakim.zhang @ 2026-06-17 6:04 UTC (permalink / raw)
To: mturquette, sboyd, bmasney, robh, krzk+dt, conor+dt, p.zabel,
gary.yang
Cc: cix-kernel-upstream, linux-clk, devicetree, linux-kernel,
linux-arm-kernel, Joakim Zhang
In-Reply-To: <20260617060437.1474816-1-joakim.zhang@cixtech.com>
From: Joakim Zhang <joakim.zhang@cixtech.com>
The AUDSS CRU contains an internal clock tree of muxes, dividers and
gates for DSP, I2S, HDA, DMAC and related blocks. The clock provider is
a child node of the cix,sky1-audss-system-control syscon and accesses
registers through the parent MMIO region.
Signed-off-by: Joakim Zhang <joakim.zhang@cixtech.com>
---
.../bindings/clock/cix,sky1-audss-clock.yaml | 72 +++++++++++++++++++
.../dt-bindings/clock/cix,sky1-audss-clock.h | 60 ++++++++++++++++
2 files changed, 132 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/cix,sky1-audss-clock.yaml
create mode 100644 include/dt-bindings/clock/cix,sky1-audss-clock.h
diff --git a/Documentation/devicetree/bindings/clock/cix,sky1-audss-clock.yaml b/Documentation/devicetree/bindings/clock/cix,sky1-audss-clock.yaml
new file mode 100644
index 000000000000..ea813c5a2307
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/cix,sky1-audss-clock.yaml
@@ -0,0 +1,72 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/cix,sky1-audss-clock.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Cix Sky1 audio subsystem clock controller
+
+maintainers:
+ - Joakim Zhang <joakim.zhang@cixtech.com>
+
+description: |
+ Clock provider for the Cix Sky1 audio subsystem (AUDSS).
+
+ This node is a child of a cix,sky1-audss-system-control syscon node
+ (see cix,sky1-system-control.yaml). It does not have a reg property; clock
+ mux, divider and gate fields are accessed through the parent register block.
+
+ Software reset lines for AUDSS blocks are exposed on the parent syscon via
+ #reset-cells (provider). Reset indices are defined in
+ include/dt-bindings/reset/cix,sky1-audss-system-control.h.
+
+ Four SoC-level reference clocks listed in clocks/clock-names feed the AUDSS
+ clock tree. The provider exposes the internal AUDSS clocks to other devices
+ via #clock-cells; indices are defined in cix,sky1-audss-clock.h.
+
+ The parent cix,sky1-audss-system-control node describes the SoC syscon
+ NoC (or bus) reset via resets and the audio subsystem power domain via
+ power-domains.
+
+properties:
+ compatible:
+ const: cix,sky1-audss-clock
+
+ '#clock-cells':
+ const: 1
+ description:
+ Clock indices are defined in include/dt-bindings/clock/cix,sky1-audss-clock.h.
+
+ clocks:
+ items:
+ - description: I2S parent clock for sampling rates multiple of 8kHz.
+ - description: I2S parent clock for sampling rates multiple of 11.025kHz.
+ - description: clock feeding most devices in audss (NOC, DSP, SRAM, HDA, DMAC, I2S, and Mailbox).
+ - description: clock feeding for HDA, Timer and Watchdog, which is a delicated 48MHz clock.
+
+ clock-names:
+ items:
+ - const: x8k
+ - const: x11k
+ - const: sys
+ - const: 48m
+
+required:
+ - compatible
+ - '#clock-cells'
+ - clocks
+ - clock-names
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/cix,sky1.h>
+
+ clock-controller {
+ compatible = "cix,sky1-audss-clock";
+ #clock-cells = <1>;
+ clocks = <&scmi_clk CLK_TREE_AUDIO_CLK0>, <&scmi_clk CLK_TREE_AUDIO_CLK2>,
+ <&scmi_clk CLK_TREE_AUDIO_CLK4>, <&scmi_clk CLK_TREE_AUDIO_CLK5>;
+ clock-names = "x8k", "x11k", "sys", "48m";
+ };
diff --git a/include/dt-bindings/clock/cix,sky1-audss-clock.h b/include/dt-bindings/clock/cix,sky1-audss-clock.h
new file mode 100644
index 000000000000..7e9bd3e6c7a1
--- /dev/null
+++ b/include/dt-bindings/clock/cix,sky1-audss-clock.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright 2026 Cix Technology Group Co., Ltd.
+ */
+
+#ifndef _DT_BINDINGS_CLK_CIX_SKY1_AUDSS_CLOCK_H
+#define _DT_BINDINGS_CLK_CIX_SKY1_AUDSS_CLOCK_H
+
+#define CLK_AUD_CLK4_DIV2 0
+#define CLK_AUD_CLK4_DIV4 1
+#define CLK_AUD_CLK5_DIV2 2
+
+#define CLK_DSP_CLK 3
+#define CLK_DSP_BCLK 4
+#define CLK_DSP_PBCLK 5
+
+#define CLK_SRAM_AXI 6
+
+#define CLK_HDA_SYS 7
+#define CLK_HDA_HDA 8
+
+#define CLK_DMAC_AXI 9
+
+#define CLK_WDG_APB 10
+#define CLK_WDG_WDG 11
+
+#define CLK_TIMER_APB 12
+#define CLK_TIMER_TIMER 13
+
+#define CLK_MB_0_APB 14 /* MB0: ap->dsp */
+#define CLK_MB_1_APB 15 /* MB1: dsp->ap */
+
+#define CLK_I2S0_APB 16
+#define CLK_I2S1_APB 17
+#define CLK_I2S2_APB 18
+#define CLK_I2S3_APB 19
+#define CLK_I2S4_APB 20
+#define CLK_I2S5_APB 21
+#define CLK_I2S6_APB 22
+#define CLK_I2S7_APB 23
+#define CLK_I2S8_APB 24
+#define CLK_I2S9_APB 25
+#define CLK_I2S0 26
+#define CLK_I2S1 27
+#define CLK_I2S2 28
+#define CLK_I2S3 29
+#define CLK_I2S4 30
+#define CLK_I2S5 31
+#define CLK_I2S6 32
+#define CLK_I2S7 33
+#define CLK_I2S8 34
+#define CLK_I2S9 35
+
+#define CLK_MCLK0 36
+#define CLK_MCLK1 37
+#define CLK_MCLK2 38
+#define CLK_MCLK3 39
+#define CLK_MCLK4 40
+
+#endif
--
2.50.1
^ permalink raw reply related
* [PATCH v4 2/5] reset: cix: add audss support to sky1 reset driver
From: joakim.zhang @ 2026-06-17 6:04 UTC (permalink / raw)
To: mturquette, sboyd, bmasney, robh, krzk+dt, conor+dt, p.zabel,
gary.yang
Cc: cix-kernel-upstream, linux-clk, devicetree, linux-kernel,
linux-arm-kernel, Joakim Zhang
In-Reply-To: <20260617060437.1474816-1-joakim.zhang@cixtech.com>
From: Joakim Zhang <joakim.zhang@cixtech.com>
Extend the Sky1 reset controller driver for the AUDSS CRU syscon. The
AUDSS block provides sixteen active-low software reset bits in one
register for audio subsystem peripherals, reusing the existing
regmap-based reset ops used by the FCH and S5 system control variants.
Signed-off-by: Joakim Zhang <joakim.zhang@cixtech.com>
---
drivers/reset/reset-sky1.c | 86 ++++++++++++++++++++++++++++++++++++--
1 file changed, 83 insertions(+), 3 deletions(-)
diff --git a/drivers/reset/reset-sky1.c b/drivers/reset/reset-sky1.c
index 78e80a533c39..462501c2ea06 100644
--- a/drivers/reset/reset-sky1.c
+++ b/drivers/reset/reset-sky1.c
@@ -10,12 +10,16 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_platform.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/regmap.h>
+#include <linux/reset.h>
#include <linux/reset-controller.h>
#include <dt-bindings/reset/cix,sky1-system-control.h>
#include <dt-bindings/reset/cix,sky1-s5-system-control.h>
+#include <dt-bindings/reset/cix,sky1-audss-system-control.h>
#define SKY1_RESET_SLEEP_MIN_US 50
#define SKY1_RESET_SLEEP_MAX_US 100
@@ -34,6 +38,7 @@ struct sky1_src {
struct reset_controller_dev rcdev;
const struct sky1_src_signal *signals;
struct regmap *regmap;
+ struct reset_control *rst_noc;
};
enum {
@@ -258,6 +263,34 @@ static const struct sky1_src_variant variant_sky1_fch = {
.signals_num = ARRAY_SIZE(sky1_src_fch_signals),
};
+enum {
+ AUDSS_SW_RST = 0x78,
+};
+
+static const struct sky1_src_signal sky1_audss_signals[] = {
+ [AUDSS_I2S0_SW_RST] = { AUDSS_SW_RST, BIT(0) },
+ [AUDSS_I2S1_SW_RST] = { AUDSS_SW_RST, BIT(1) },
+ [AUDSS_I2S2_SW_RST] = { AUDSS_SW_RST, BIT(2) },
+ [AUDSS_I2S3_SW_RST] = { AUDSS_SW_RST, BIT(3) },
+ [AUDSS_I2S4_SW_RST] = { AUDSS_SW_RST, BIT(4) },
+ [AUDSS_I2S5_SW_RST] = { AUDSS_SW_RST, BIT(5) },
+ [AUDSS_I2S6_SW_RST] = { AUDSS_SW_RST, BIT(6) },
+ [AUDSS_I2S7_SW_RST] = { AUDSS_SW_RST, BIT(7) },
+ [AUDSS_I2S8_SW_RST] = { AUDSS_SW_RST, BIT(8) },
+ [AUDSS_I2S9_SW_RST] = { AUDSS_SW_RST, BIT(9) },
+ [AUDSS_WDT_SW_RST] = { AUDSS_SW_RST, BIT(10) },
+ [AUDSS_TIMER_SW_RST] = { AUDSS_SW_RST, BIT(11) },
+ [AUDSS_MB0_SW_RST] = { AUDSS_SW_RST, BIT(12) },
+ [AUDSS_MB1_SW_RST] = { AUDSS_SW_RST, BIT(13) },
+ [AUDSS_HDA_SW_RST] = { AUDSS_SW_RST, BIT(14) },
+ [AUDSS_DMAC_SW_RST] = { AUDSS_SW_RST, BIT(15) },
+};
+
+static const struct sky1_src_variant variant_sky1_audss = {
+ .signals = sky1_audss_signals,
+ .signals_num = ARRAY_SIZE(sky1_audss_signals),
+};
+
static struct sky1_src *to_sky1_src(struct reset_controller_dev *rcdev)
{
return container_of(rcdev, struct sky1_src, rcdev);
@@ -318,17 +351,34 @@ static const struct reset_control_ops sky1_src_ops = {
.status = sky1_reset_status
};
+static int __maybe_unused sky1_reset_runtime_suspend(struct device *dev)
+{
+ struct sky1_src *sky1src = dev_get_drvdata(dev);
+
+ return reset_control_assert(sky1src->rst_noc);
+}
+
+static int __maybe_unused sky1_reset_runtime_resume(struct device *dev)
+{
+ struct sky1_src *sky1src = dev_get_drvdata(dev);
+
+ return reset_control_deassert(sky1src->rst_noc);
+}
+
static int sky1_reset_probe(struct platform_device *pdev)
{
struct sky1_src *sky1src;
struct device *dev = &pdev->dev;
const struct sky1_src_variant *variant;
+ int ret;
sky1src = devm_kzalloc(dev, sizeof(*sky1src), GFP_KERNEL);
if (!sky1src)
return -ENOMEM;
variant = of_device_get_match_data(dev);
+ if (!variant)
+ return -ENODEV;
sky1src->regmap = device_node_to_regmap(dev->of_node);
if (IS_ERR(sky1src->regmap)) {
@@ -343,12 +393,36 @@ static int sky1_reset_probe(struct platform_device *pdev)
sky1src->rcdev.of_node = dev->of_node;
sky1src->rcdev.dev = dev;
- return devm_reset_controller_register(dev, &sky1src->rcdev);
+ ret = devm_reset_controller_register(dev, &sky1src->rcdev);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, sky1src);
+
+ if (of_device_is_compatible(dev->of_node, "cix,sky1-audss-system-control")) {
+ sky1src->rst_noc = devm_reset_control_get_exclusive(dev, NULL);
+ if (IS_ERR(sky1src->rst_noc))
+ return dev_err_probe(dev, PTR_ERR(sky1src->rst_noc),
+ "failed to get audss noc reset");
+
+ pm_runtime_get_noresume(dev);
+ pm_runtime_set_active(dev);
+ devm_pm_runtime_enable(dev);
+
+ reset_control_deassert(sky1src->rst_noc);
+
+ ret = devm_of_platform_populate(dev);
+ pm_runtime_put(dev);
+ return ret;
+ }
+
+ return 0;
}
static const struct of_device_id sky1_sysreg_of_match[] = {
- { .compatible = "cix,sky1-system-control", .data = &variant_sky1_fch},
- { .compatible = "cix,sky1-s5-system-control", .data = &variant_sky1},
+ { .compatible = "cix,sky1-system-control", .data = &variant_sky1_fch },
+ { .compatible = "cix,sky1-s5-system-control", .data = &variant_sky1 },
+ { .compatible = "cix,sky1-audss-system-control", .data = &variant_sky1_audss },
{},
};
MODULE_DEVICE_TABLE(of, sky1_sysreg_of_match);
@@ -358,6 +432,12 @@ static struct platform_driver sky1_reset_driver = {
.driver = {
.name = "cix,sky1-rst",
.of_match_table = sky1_sysreg_of_match,
+ .pm = &(const struct dev_pm_ops){
+ SET_RUNTIME_PM_OPS(sky1_reset_runtime_suspend,
+ sky1_reset_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+ },
},
};
module_platform_driver(sky1_reset_driver)
--
2.50.1
^ permalink raw reply related
* Re: [PATCH net-next v7 2/2] net: ti: icssg-prueth: Add ethtool ops for Frame Preemption MAC Merge
From: MD Danish Anwar @ 2026-06-17 5:28 UTC (permalink / raw)
To: Meghana Malladi, Jakub Kicinski
Cc: elfring, haokexin, vadim.fedorenko, devnexen, horms,
jacob.e.keller, arnd, basharath, afd, parvathi, vladimir.oltean,
rogerq, pabeni, edumazet, davem, andrew+netdev, linux-arm-kernel,
netdev, linux-kernel, srk, vigneshr
In-Reply-To: <d0123269-b1e8-4fba-94b0-b94d3d9a5405@ti.com>
Meghana,
On 16/06/26 6:24 pm, Meghana Malladi wrote:
> Hi Jakub,
>
> On 6/16/26 05:09, Jakub Kicinski wrote:
>> On Mon, 15 Jun 2026 16:10:41 -0700 Jakub Kicinski wrote:
>>>> diff --git a/drivers/net/ethernet/ti/icssg/icssg_stats.h b/drivers/
>>>> net/ethernet/ti/icssg/icssg_stats.h
>>>> index 5ec0b38e0c67..8073deac35c3 100644
>>>> --- a/drivers/net/ethernet/ti/icssg/icssg_stats.h
>>>> +++ b/drivers/net/ethernet/ti/icssg/icssg_stats.h
>>>> @@ -189,6 +187,11 @@ static const struct icssg_pa_stats
>>>> icssg_all_pa_stats[] = {
>>>> ICSSG_PA_STATS(FW_INF_DROP_PRIOTAGGED),
>>>> ICSSG_PA_STATS(FW_INF_DROP_NOTAG),
>>>> ICSSG_PA_STATS(FW_INF_DROP_NOTMEMBER),
>>>> + ICSSG_PA_STATS(FW_PREEMPT_BAD_FRAG),
>>>> + ICSSG_PA_STATS(FW_PREEMPT_ASSEMBLY_ERR),
>>>> + ICSSG_PA_STATS(FW_PREEMPT_FRAG_CNT_TX),
>>>> + ICSSG_PA_STATS(FW_PREEMPT_ASSEMBLY_OK),
>>>> + ICSSG_PA_STATS(FW_PREEMPT_FRAG_CNT_RX),
>>>> ICSSG_PA_STATS(FW_RX_EOF_SHORT_FRMERR),
>>>> ICSSG_PA_STATS(FW_RX_B0_DROP_EARLY_EOF),
>>>> ICSSG_PA_STATS(FW_TX_JUMBO_FRM_CUTOFF),
>>>
>>> [Medium]
>>> Are these five new entries duplicating values that already have a
>>> standard uAPI?
>>>
>>> The same five firmware counters are exposed through the new
>>> .get_mm_stats callback as the standardized MAC Merge stats
>>> (MACMergeFrameAssOkCount, MACMergeFrameAssErrorCount,
>>> MACMergeFragCountRx,
>>> MACMergeFragCountTx, MACMergeFrameSmdErrorCount in struct
>>> ethtool_mm_stats), and adding them to icssg_all_pa_stats[] also
>>> publishes them via emac_get_strings() / emac_get_ethtool_stats() as
>>> ethtool -S strings.
>>>
>>> Documentation/networking/statistics.rst describes ethtool -S as the
>>> private-driver-stats interface; counters that have a standard uAPI are
>>> expected to flow only through that uAPI.
>>>
>>> Could the firmware-register lookup table used by emac_get_stat_by_name()
>>> be separated from the ethtool -S string table, so the new preemption
>>> counters feed get_mm_stats without also showing up under ethtool -S?
>>
>> This -- not sure about the other complaints but this one looks legit.
>
> I agree that this is legit, but right now there is no other place holder
> other than pa stats to put the mac merge firmware counters. I believe
You can put a boolean is_standard_stats. Only those where
is_standard_stats=false will be populated via ethtool. Others will be
populated via the standard interface.
Look at icssg_miig_stats for reference.
> the effort needs to go in re-structuring the hardware and firmware stats
> implementation to address this issue.
>
--
Thanks and Regards,
Danish
^ permalink raw reply
* Re: [PATCH v4 0/3] iommu/arm-smmu-v3: Tegra264 invalidation workaround
From: Nicolin Chen @ 2026-06-17 4:54 UTC (permalink / raw)
To: Ashish Mhetre
Cc: will, robin.murphy, joro, jgg, linux-arm-kernel, iommu,
linux-kernel, linux-tegra
In-Reply-To: <97b4dcc7-3ed3-47eb-ac38-51fc2dfb6480@nvidia.com>
On Wed, Jun 17, 2026 at 09:28:10AM +0530, Ashish Mhetre wrote:
> On 6/9/2026 1:02 PM, Ashish Mhetre wrote:
> Hi all,
>
> A gentle reminder to review the patches and share your comments.
https://docs.kernel.org/process/maintainer-tip.html
"
4.2.9 Merge window
Please do not expect patches to be reviewed or merged by tip
maintainers around or during the merge window. The trees are closed
to all but urgent fixes during this time. They reopen once the merge
window closes and a new -rc1 kernel has been released.
"
I would wait for rc1 to rebase and respin.
Nicolin
^ permalink raw reply
* Re: [PATCH v5 3/4] PCI: endpoint: Add support for DOE initialization and setup in EPC core
From: Aksh Garg @ 2026-06-17 4:47 UTC (permalink / raw)
To: Manivannan Sadhasivam
Cc: Bjorn Helgaas, linux-pci, linux-doc, kwilczynski, bhelgaas,
corbet, kishon, skhan, lukas, cassel, alistair, linux-arm-kernel,
linux-kernel, s-vadapalli, danishanwar, srk
In-Reply-To: <grfjlghqd3k3i3uxll2jksrh7pgi2mtxifbq2vymsdgbzijsnq@dvgu2qp2hza3>
On 16/06/26 11:52, Manivannan Sadhasivam wrote:
> On Fri, Jun 12, 2026 at 01:54:13PM +0530, Aksh Garg wrote:
>>
>>
>> On 12/06/26 00:42, Bjorn Helgaas wrote:
>>> On Wed, Jun 10, 2026 at 03:32:55PM +0530, Aksh Garg wrote:
>>>> Add pci_epc_init_capabilities() in EPC core driver to initialize and
>>>> setup the capabilities supported by the EPC driver. This calls
>>>> pci_epc_doe_setup() to setup the DOE framework for an endpoint controller,
>>>> which discovers the DOE capabilities (extended capability ID 0x2E), and
>>>> registers each discovered DOE mailbox for all the functions in the
>>>> endpoint controller.
>>>>
>>>> Add pci_epc_deinit_capabilities() in EPC core driver for cleanup of the
>>>> resources used by the capabilities of the EPC driver. This calls
>>>> pci_ep_doe_destroy() to destroy all DOE mailboxes and free associated
>>>> resources.
>>>>
>>>> Co-developed-by: Siddharth Vadapalli <s-vadapalli@ti.com>
>>>> Signed-off-by: Siddharth Vadapalli <s-vadapalli@ti.com>
>>>> Signed-off-by: Aksh Garg <a-garg7@ti.com>
>>>> ---
>>>> +/**
>>>> + * pci_epc_doe_setup() - Discover and setup DOE mailboxes for all functions
>>>> + * @epc: the EPC device on which DOE mailboxes has to be setup
>>>> + *
>>>> + * Discover DOE (Data Object Exchange) capabilities for all physical functions
>>>> + * in the endpoint controller and register DOE mailboxes.
>>>> + *
>>>> + * Returns: 0 on success, -errno on failure
>>>> + */
>>>> +static int pci_epc_doe_setup(struct pci_epc *epc)
>>>> +{
>>>> + u8 func_no, vfunc_no = 0;
>>>> + u16 cap_offset;
>>>> + int ret;
>>>> +
>>>> + if (!epc->ops || !epc->ops->find_ext_capability)
>>>> + return -EINVAL;
>>>
>>
>> Hi Bjorn,
>>
>> Thank you for your feedback comments. I will work on them and post v6
>> series incorporating the changes.
>>
>>> I don't see anything that sets pci_epc_ops.find_ext_capability in this
>>> series, so this looks currently unused and untestable, so likely not
>>> mergeable as-is. What's the plan for users of this?
>>>
>>
>> Currently there is no EPC driver upstream which supports DOE yet. However, I
>> am working on a platform which supports DOE (support for
>> which would be added soon). Mani pointed out that if EPC driver support
>> for the same is guaranteed to be added soon, the APIs can be merged
>> first.
>>
>> For the demonstration purpose, he asked to show how an EPC driver is
>> expected to use the API as a snippet in the cover letter itself.
>>
>
> I retract my previous comment here. Let's not introduce dead code in the kernel.
> We can review the series now, but cannot merge it until the EPC driver gets
> submitted.
Hi Mani,
Sure, I would prefer the series to be reviewed and gather Reviewed-by
tags by the time the EPC driver gets submitted, which would help
expedite the merge of this series later.
>
> - Mani
>
^ permalink raw reply
* [PATCH v2] KVM: arm64: nv: Fix SPSR_EL2 restore in kvm_hyp_handle_mops()
From: Weiming Shi @ 2026-06-17 4:08 UTC (permalink / raw)
To: Marc Zyngier, Oliver Upton, Catalin Marinas, Will Deacon
Cc: Joey Gouly, Steffen Eiden, Suzuki K Poulose, Zenghui Yu,
Jakub Kicinski, Andrew Morton, Hans Verkuil, Mark Rutland,
Kristina Martsenko, linux-arm-kernel, kvmarm, Zhong Wang,
Xuanqing Shi, Weiming Shi, stable
kvm_hyp_handle_mops() resets the single-step state machine as part of
rewinding state for a MOPS exception by modifying vcpu_cpsr() and
writing the result directly into hardware.
In the case of nested virtualization, vcpu_cpsr() is a synthetic value
such that the rest of KVM can deal with vEL2 cleanly. That means the
value requires translation before being written into hardware, which is
unfortunately missing from the MOPS handler.
Fix it by directly modifying SPSR_EL2 and avoiding the synthetic state
altogether, which will be resynchronized on the next 'full' exit back
to KVM.
Fixes: 2de451a329cf ("KVM: arm64: Add handler for MOPS exceptions")
Reported-by: Zhong Wang <wangzhong.c0ss4ck@bytedance.com>
Reported-by: Xuanqing Shi <shixuanqing.11@bytedance.com>
Link: https://lore.kernel.org/all/ajE4lHQevXNHpl1M@Air.local/
Cc: stable@vger.kernel.org
Signed-off-by: Weiming Shi <bestswngs@gmail.com>
---
v2:
- Reword the changelog (Oliver Upton).
- Modify the hardware SPSR_EL2 directly instead of translating the
synthetic vcpu_cpsr(), per review (Oliver Upton).
arch/arm64/kvm/hyp/include/hyp/switch.h | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
index e9b36a3b27bbc..0995e34aa3c54 100644
--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
@@ -448,16 +448,19 @@ static inline bool __populate_fault_info(struct kvm_vcpu *vcpu)
static inline bool kvm_hyp_handle_mops(struct kvm_vcpu *vcpu, u64 *exit_code)
{
+ u64 spsr;
+
*vcpu_pc(vcpu) = read_sysreg_el2(SYS_ELR);
arm64_mops_reset_regs(vcpu_gp_regs(vcpu), vcpu->arch.fault.esr_el2);
write_sysreg_el2(*vcpu_pc(vcpu), SYS_ELR);
/*
* Finish potential single step before executing the prologue
- * instruction.
+ * instruction. Modify the hardware SPSR_EL2 directly, as vcpu_cpsr()
+ * may hold a synthetic (vEL2) value for a guest hypervisor.
*/
- *vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS;
- write_sysreg_el2(*vcpu_cpsr(vcpu), SYS_SPSR);
+ spsr = read_sysreg_el2(SYS_SPSR);
+ write_sysreg_el2(spsr & ~DBG_SPSR_SS, SYS_SPSR);
return true;
}
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v4 0/3] iommu/arm-smmu-v3: Tegra264 invalidation workaround
From: Ashish Mhetre @ 2026-06-17 3:58 UTC (permalink / raw)
To: will, robin.murphy, joro, jgg, nicolinc
Cc: linux-arm-kernel, iommu, linux-kernel, linux-tegra
In-Reply-To: <20260609073204.1760077-1-amhetre@nvidia.com>
On 6/9/2026 1:02 PM, Ashish Mhetre wrote:
> Nvidia Tegra264 SMMUs are affected by an erratum where a TLB entry can
> survive an invalidation that races with concurrent traffic targeting
> the same entry. The hardware-recommended software workaround is to
> issue every CFGI/TLBI command (each followed by CMD_SYNC) twice.
> The second issue must execute only after the first issue's CMD_SYNC
> has completed, giving the sequence:
>
> TLBI/CFGI ... CMD_SYNC TLBI/CFGI ... CMD_SYNC
>
> ATC_INV is not affected and must not be doubled.
>
> The erratum is not flagged by any SMMUv3 IDR/IIDR register, so it
> cannot be detected from hardware ID. Tegra264 is device-tree-only
> (no ACPI/IORT support), so detection is purely by compatible string.
>
> This series is structured as a small refactor + detect + apply
> sequence so that each step is reviewable in isolation:
>
> 1/3 Pure refactor (no functional change): lift the existing
> force-sync conditions out of arm_smmu_cmdq_batch_add_cmd_p()
> into a new arm_smmu_cmdq_batch_force_sync() helper, so that
> adding another condition (in patch 3) is a one-liner.
> Authored by Nicolin Chen.
>
> 2/3 Detect the erratum and provide the classifier. Adds the
> ARM_SMMU_OPT_REPEAT_TLBI_CFGI per-instance option, a global
> arm_smmu_erratum_repeat_tlbi_cfgi_key static key, and the
> arm_smmu_erratum_cmd_needs_repeating() predicate. The static
> key means the wrapper compiles to a single tested branch on
> unaffected kernels.
>
> 3/3 Apply the workaround: factor arm_smmu_cmdq_issue_cmdlist()
> into a thin wrapper around __arm_smmu_cmdq_issue_cmdlist()
> that re-issues the cmdlist a second time when the predicate
> fires; register the same condition with the batch helper so
> full batches of CFGI/TLBI flush with sync=true; and add
> arm_vsmmu_can_batch_cmd() so iommufd does not mix command
> classes inside a single batch. Also documents the erratum
> in silicon-errata.rst.
>
> The series applies cleanly on linux-next/master (base-commit below).
>
> Changes since v3:
> - Drop the cmds->num == 0 early-return so the refactor is
> truly "no functional change".
> - Rename ARM_SMMU_OPT_TLBI_TWICE -> ARM_SMMU_OPT_REPEAT_TLBI_CFGI
> and rephrase its kdoc to be hardware-agnostic.
> - Rename arm_smmu_cmd_needs_tlbi_twice() ->
> arm_smmu_erratum_cmd_needs_repeating() and drop the kdoc
> above it.
> - Replace the explicit opcode switch with a single range check
> opcode >= CMDQ_OP_CFGI_STE && opcode < CMDQ_OP_ATC_INV.
> - Introduce arm_smmu_erratum_repeat_tlbi_cfgi_key static key:
> the predicate gates on it first so unaffected kernels pay
> only a single static_branch_unlikely() check.
> - Drop the verbose Tegra264-specific comments above
> arm_vsmmu_can_batch_cmd() and inside the batch helper.
> - Document the erratum in
> Documentation/arch/arm64/silicon-errata.rst.
> - Guard the repeat path in arm_smmu_cmdq_issue_cmdlist() with
> an n > 0 check so we never inspect cmds[0] on the bare-SYNC
> flush emitted by arm_smmu_cmdq_batch_add_cmd_p() when the
> next command is unsupported by the batch's pre-selected
> cmdq.
> - Drop the carried Reviewed-by tags now that the patch
> shape has changed; re-review appreciated.
>
> Changes since v2:
> - Split into a 3-patch series (refactor / detect / apply) to keep
> each step small and bisectable.
> - Move the classifier to arm-smmu-v3.h as static inline so the
> iommufd file can share it.
> - Add arm_vsmmu_can_batch_cmd() to split iommufd batches at
> "needs repeating" transitions so the per-batch decision based
> on the first command stays correct under mixed user input.
> - Spell out in the commit message why detection is via DT and
> not via IIDR/ACPI.
>
> Changes since v1:
> - Detect the erratum from the existing "nvidia,tegra264-smmu"
> compatible instead of adding a new property.
> - Centralise the doubling at the CMDQ submission layer and only
> apply it to CFGI/TLBI (not ATC_INV).
> - Drop the binding/dtsi patches accordingly.
>
> Ashish Mhetre (2):
> iommu/arm-smmu-v3: Detect Tegra264 erratum
> iommu/arm-smmu-v3: Issue CFGI/TLBI twice on Tegra264
>
> Nicolin Chen (1):
> iommu/arm-smmu-v3: Factor out CMDQ batch force-sync conditions
>
> Documentation/arch/arm64/silicon-errata.rst | 2 +
> .../arm/arm-smmu-v3/arm-smmu-v3-iommufd.c | 15 ++++-
> drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 65 +++++++++++++++----
> drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 24 +++++++
> 4 files changed, 94 insertions(+), 12 deletions(-)
>
>
> base-commit: 7da7f07112610a520567421dd2ffcb51beaefbcc
Hi all,
A gentle reminder to review the patches and share your comments.
Thanks,
Ashish Mhetre
^ permalink raw reply
* Re: [PATCH v2 1/3] Bluetooth: btmtksdio: correct btmtksdio_txrx_work() loop timeout check
From: Sergey Senozhatsky @ 2026-06-17 3:43 UTC (permalink / raw)
To: Sean Wang
Cc: Sergey Senozhatsky, Marcel Holtmann, Luiz Augusto von Dentz,
Mark-yw Chen, Sean Wang, Tomasz Figa, linux-bluetooth,
linux-kernel, linux-arm-kernel, linux-mediatek, stable
In-Reply-To: <CAGp9LzpCMGr2hyVJRMehs_BD4Rk6mS2jAifWuCgBaANdqgtvqA@mail.gmail.com>
On (26/06/16 19:40), Sean Wang wrote:
> > The btmtksdio_txrx_work() loop is expected to be terminated if running
> > for longer than 5*HZ. However the timeout check is reversed:
> > time_is_before_jiffies(old_jiffies + 5*HZ) evaluates to true when
> > old_jiffies + 5*HZ is in the past i.e. when a timeout has occurred.
> > Using OR with time_is_before_jiffies(txrx_timeout) means that:
> > - before the 5-second timeout: the condition is `int_status || false`,
> > so it loops as long as there are pending interrupts.
> > - after the 5-second timeout: the condition becomes `int_status || true`,
> > which is always true.
> >
> > Fix loop termination condition to actually enforce a 5*HZ timeout.
> >
> > Fixes: 26270bc189ea4 ("Bluetooth: btmtksdio: move interrupt service to work")
> > Cc: stable@vger.kernel.org
> > Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
> > ---
> > drivers/bluetooth/btmtksdio.c | 2 +-
> > 1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c
> > index 5b0fab7b89b5..c6f80c419e90 100644
> > --- a/drivers/bluetooth/btmtksdio.c
> > +++ b/drivers/bluetooth/btmtksdio.c
> > @@ -620,7 +620,7 @@ static void btmtksdio_txrx_work(struct work_struct *work)
> > if (btmtksdio_rx_packet(bdev, rx_size) < 0)
> > bdev->hdev->stat.err_rx++;
> > }
> > - } while (int_status || time_is_before_jiffies(txrx_timeout));
> > + } while (int_status && time_is_after_jiffies(txrx_timeout));
> >
>
> This patch has already been merged, so I think the series should be
> respun based on the latest code.
Oh, I see. Any chance it can be dropped from the tree or updated?
The patch is identical it's the commit message that has changed.
Otherwise, I can drop it from a v3 re-spin.
^ permalink raw reply
* Re: [PATCH v2 3/3] Bluetooth: btmtksdio: call cancel_work_sync() outside of host lock scope
From: Sergey Senozhatsky @ 2026-06-17 3:41 UTC (permalink / raw)
To: Sean Wang
Cc: Sergey Senozhatsky, Marcel Holtmann, Luiz Augusto von Dentz,
Mark-yw Chen, Sean Wang, Tomasz Figa, linux-bluetooth,
linux-kernel, linux-arm-kernel, linux-mediatek, stable
In-Reply-To: <CAGp9LzqT4knwk9hONu43cGDr005Phs3xw6T+YexXa3X6JEBOpA@mail.gmail.com>
On (26/06/16 19:56), Sean Wang wrote:
> The patch looks good to me. Inspired by your patch,
> do you think should we add another patch to keep txrx_work out of the
> reset window by rejecting TX during reset,
> ignoring reset-time interrupts, and making queued workers exit early?
I honestly don't know, it's hard for to me judge as I'm not all that
familiar with the code. To make things more complex, I don't think we
see any crashes on reset path. My personal preference maybe would be
to keep things the way they are?
> Some code like:
>
> --- a/drivers/bluetooth/btmtksdio.c
> +++ b/drivers/bluetooth/btmtksdio.c
> @@ -567,6 +567,8 @@ static void btmtksdio_txrx_work(struct work_struct *work)
> pm_runtime_get_sync(bdev->dev);
>
> sdio_claim_host(bdev->func);
> + if (test_bit(BTMTKSDIO_HW_RESET_ACTIVE, &bdev->tx_state))
> + goto out;
A nit: I think you can test_bit() outside of host lock scope.
Other than that I'm afraid I cannot be of much help here.
> /* Disable interrupt */
> sdio_writel(bdev->func, C_INT_EN_CLR, MTK_REG_CHLPCR, NULL);
> @@ -628,6 +630,7 @@ static void btmtksdio_txrx_work(struct work_struct *work)
> !test_bit(BTMTKSDIO_HW_RESET_ACTIVE, &bdev->tx_state))
> sdio_writel(bdev->func, C_INT_EN_SET, MTK_REG_CHLPCR, NULL);
>
> +out:
> sdio_release_host(bdev->func);
>
> pm_runtime_put_autosuspend(bdev->dev);
> @@ -646,6 +649,9 @@ static void btmtksdio_interrupt(struct sdio_func *func)
> /* Disable interrupt */
> sdio_writel(bdev->func, C_INT_EN_CLR, MTK_REG_CHLPCR, NULL);
>
> + if (test_bit(BTMTKSDIO_HW_RESET_ACTIVE, &bdev->tx_state))
> + return;
> +
> schedule_work(&bdev->txrx_work);
> }
>
> @@ -1250,6 +1256,9 @@ static int btmtksdio_send_frame(struct hci_dev
> *hdev, struct sk_buff *skb)
> {
> struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
>
> + if (test_bit(BTMTKSDIO_HW_RESET_ACTIVE, &bdev->tx_state))
> + return -EBUSY;
> +
> switch (hci_skb_pkt_type(skb)) {
> case HCI_COMMAND_PKT:
> hdev->stat.cmd_tx++;
^ permalink raw reply
* [PATCH net] net: airoha: Fix TX scheduler queue mask loop upper bound
From: Wayen Yan @ 2026-06-17 3:20 UTC (permalink / raw)
To: netdev
Cc: lorenzo, horms, pabeni, kuba, edumazet, andrew+netdev,
angelogioacchino.delregno, matthias.bgg, linux-arm-kernel,
linux-mediatek
In airoha_qdma_set_chan_tx_sched(), the loop clearing queue mask was
using AIROHA_NUM_TX_RING (32) instead of AIROHA_NUM_QOS_QUEUES (8).
Each channel has 8 queues, and TXQ_DISABLE_CHAN_QUEUE_MASK(channel, i)
computes BIT(i + (channel * 8)). With i ranging 0..31, this causes:
- channel 0: clears bit 0..31 (all 4 channels) instead of 0..7
- channel 1: clears bit 8..31 (channels 1-3) instead of 8..15
- channel 2: clears bit 16..31 (channels 2-3) instead of 16..23
- channel 3: clears bit 24..31 (channel 3 only) - correct by accident
While BIT(32+) on arm64 produces 64-bit values truncated to 0 in u32
mask parameter, the loop still incorrectly clears queues within the
same channel beyond queue 7.
Fix by using AIROHA_NUM_QOS_QUEUES (8) as the loop upper bound.
Fixes: ef1ca9271313 ("net: airoha: Add sched HTB offload support")
Signed-off-by: Wayen Yan <win847@gmail.com>
---
drivers/net/ethernet/airoha/airoha_eth.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 31cdb11cd7..a1eda13400 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -2217,7 +2217,7 @@ static int airoha_qdma_set_chan_tx_sched(struct net_device *dev,
struct airoha_gdm_port *port = netdev_priv(dev);
int i;
- for (i = 0; i < AIROHA_NUM_TX_RING; i++)
+ for (i = 0; i < AIROHA_NUM_QOS_QUEUES; i++)
airoha_qdma_clear(port->qdma, REG_QUEUE_CLOSE_CFG(channel),
TXQ_DISABLE_CHAN_QUEUE_MASK(channel, i));
--
2.51.0
^ permalink raw reply related
* [PATCH v3] dmaengine: sun6i-dma: Fix memory leak in sun6i_dma_terminate_all
From: Hongling Zeng @ 2026-06-17 2:34 UTC (permalink / raw)
To: vkoul, Frank.Li, wens, jernej.skrabec, samuel, mripard, arnd
Cc: dmaengine, linux-arm-kernel, linux-sunxi, linux-kernel,
zhongling0719, Hongling Zeng, Frank Li
When terminating a non-cyclic DMA transfer, the active descriptor
is not properly reclaimed. The descriptor is removed from the
desc_issued list in sun6i_dma_start_desc(), but in
sun6i_dma_terminate_all(), only cyclic transfer descriptors are
added to the desc_completed list before cleanup.
For non-cyclic transfers, pchan->desc is set to NULL without first
adding the descriptor back to a list that vchan_get_all_descriptors()
can collect. This causes the descriptor and its associated LLI chain
to be permanently leaked.
Fix by ensuring both cyclic and non-cyclic active descriptors are
added to the desc_completed list before setting pchan->desc to NULL.
Fixes: 555859308723 ("dmaengine: sun6i: Add driver for the Allwinner A31 DMA controller")
Signed-off-by: Hongling Zeng <zenghongling@kylinos.cn>
Acked-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Suggested-by: Frank Li <Frank.li@oss.nxp.com>
---
Change in v2;
-Add pchan->desc != pchan->done check to prevent race condition
where completed descriptors could be double-added to desc_completed
list, causing list corruption
---
Change in v3:
-Fix by using vchan_terminate_vdesc() as suggested by Frank Li
---
drivers/dma/sun6i-dma.c | 13 +++++--------
1 file changed, 5 insertions(+), 8 deletions(-)
diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
index 7a79f346250a..134ae840f176 100644
--- a/drivers/dma/sun6i-dma.c
+++ b/drivers/dma/sun6i-dma.c
@@ -946,16 +946,13 @@ static int sun6i_dma_terminate_all(struct dma_chan *chan)
spin_lock_irqsave(&vchan->vc.lock, flags);
- if (vchan->cyclic) {
- vchan->cyclic = false;
- if (pchan && pchan->desc) {
- struct virt_dma_desc *vd = &pchan->desc->vd;
- struct virt_dma_chan *vc = &vchan->vc;
-
- list_add_tail(&vd->node, &vc->desc_completed);
- }
+ if (pchan && pchan->desc && pchan->desc != pchan->done) {
+ struct virt_dma_desc *vd = &pchan->desc->vd;
+
+ vchan_terminate_vdesc(vd);
}
+ vchan->cyclic = false;
vchan_get_all_descriptors(&vchan->vc, &head);
if (pchan) {
--
2.25.1
^ permalink raw reply related
* [PATCH v4 0/2] pwm: Add Nuvoton MA35D1 PWM controller support
From: Chi-Wen Weng @ 2026-06-17 2:59 UTC (permalink / raw)
To: ukleinek, robh, krzk+dt, conor+dt
Cc: linux-arm-kernel, linux-pwm, devicetree, linux-kernel, cwweng,
cwweng.linux
From: Chi-Wen Weng <cwweng@nuvoton.com>
This series adds support for the Nuvoton MA35D1 PWM controller.
The MA35D1 PWM controller provides 6 PWM channels. The hardware supports
several counter types and output modes. This driver configures the controller
to use up-counting mode, auto-reload mode and independent output mode. The
waveform generator is configured to drive the output high at the zero point
and low at the compare-up point.
For the up-counting mode used by this driver, the counter counts from 0 to
PERIOD inclusive. Therefore, the programmed period is PERIOD + 1 cycles. The
hardware can generate 0% duty cycle with CMPDAT = 0 and 100% duty cycle with
CMPDAT > PERIOD. To keep 100% duty cycle representable, the driver limits the
maximum PERIOD value to 0xfffe and reserves CMPDAT = 0xffff for the full-duty
case.
The hardware buffers PERIOD and CMPDAT updates when IMMLDENn is disabled. The
driver keeps IMMLDENn disabled, so period and duty cycle updates take effect
at the end of the current period. Polarity and waveform-control changes are
applied directly and may cause transient output changes if the PWM is running.
When the PWM output is disabled by clearing POENn, the output pin is put into
tri-state according to the MA35D1 reference manual.
Changes in v4:
- Add a Limitations section to describe the hardware capabilities and driver
limitations.
- Add a link to the MA35D1 reference manual.
- Replace register address macros containing the base pointer with register
offset macros.
- Add readl/writel/rmw helper functions.
- Rename TOTAL_CHANNELS to NUM_CHANNELS.
- Use unsigned long for the cached clock rate.
- Use devm_clk_rate_exclusive_get().
- Configure polarity before enabling the counter and output.
- Add controller initialization for up-counting, auto-reload and independent
output mode.
- Configure the waveform generator for zero-point-high and compare-up-low
output.
- Fix the period conversion because the hardware period is PERIOD + 1 cycles.
- Limit the maximum PERIOD value to 0xfffe so that CMPDAT = 0xffff can be used
to generate 100% duty cycle.
- Use CNTEN and POEN bits to report the enabled state in .get_state().
- Disable the PWM by clearing POENn and CNTENn.
- Fix error message capitalization and trailing newlines.
- Fix coding style issues reported by review/checkpatch-style tools.
Changes in v3:
- Update nuvoton,ma35d1-pwm.yaml
- Add maintainers entry
- Increse "#pwm-cells" to 3
- Update ma35d1 pwm driver
- Make include header and macros definitions organized alphabetically
- Rename macros REG_PWM_XXXX to MA35D1_REG_PWM_XXXX
- Add macros for register address
v2 resend:
- Remove wrong 'Reviewed-by' tags.
Changes in v2:
- Update nuvoton,ma35d1-pwm.yaml
- Fix 'maxItems' of 'reg' to 1.
- Remove unused label
- Update ma35d1 pwm driver
- Remove MODULE_ALIAS()
- Add chip->atomic = true
Chi-Wen Weng (2):
dt-bindings: pwm: Add Nuvoton MA35D1 PWM controller
pwm: Add Nuvoton MA35D1 PWM controller support
.../bindings/pwm/nuvoton,ma35d1-pwm.yaml | 45 +++
drivers/pwm/Kconfig | 9 +
drivers/pwm/Makefile | 1 +
drivers/pwm/pwm-ma35d1.c | 344 ++++++++++++++++++
4 files changed, 399 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pwm/nuvoton,ma35d1-pwm.yaml
create mode 100644 drivers/pwm/pwm-ma35d1.c
--
2.25.1
^ permalink raw reply
* [PATCH 3/3] arm64: dts: renesas: r8a779g0: Add GICv3 ITS and update PCIe nodes
From: Marek Vasut @ 2026-06-17 2:59 UTC (permalink / raw)
To: linux-pci
Cc: Marek Vasut, Yoshihiro Shimoda, Krzysztof Wilczyński,
Bjorn Helgaas, Catalin Marinas, Conor Dooley, Geert Uytterhoeven,
Krzysztof Kozlowski, Lorenzo Pieralisi, Manivannan Sadhasivam,
Marc Zyngier, Rob Herring, devicetree, linux-arm-kernel,
linux-doc, linux-kernel, linux-renesas-soc
In-Reply-To: <20260617030008.154449-1-marek.vasut+renesas@mailbox.org>
This SoC implements GIC600 with GICv3 ITS and PCIe host mode on this
SoC can use it. Add GIC ITS node into GIC node, update interrupt-map
and add msi-map into PCIe controller node.
The GIC ITS does have master interface to issue transactions to RAM.
The interface does support cacheable transactions, however, it does
not support shareable attribute, because the AXI port signals are tied
to inactive in this implementation. Therefore, add "dma-noncoherent"
DT property into the GIC ITS subnode.
The GIC redistributor does not have cacheable/shareable, therefore
add "dma-noncoherent" DT property into the GIC node.
Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
---
NOTE: This would not be possible without prior work from Shimoda-san
https://lore.kernel.org/all/20240214052144.1966569-1-yoshihiro.shimoda.uh@renesas.com/
---
Cc: "Krzysztof Wilczyński" <kwilczynski@kernel.org>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Conor Dooley <conor+dt@kernel.org>
Cc: Geert Uytterhoeven <geert+renesas@glider.be>
Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
Cc: Lorenzo Pieralisi <lpieralisi@kernel.org>
Cc: Manivannan Sadhasivam <mani@kernel.org>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Rob Herring <robh@kernel.org>
Cc: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Cc: devicetree@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-doc@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-pci@vger.kernel.org
Cc: linux-renesas-soc@vger.kernel.org
---
arch/arm64/boot/dts/renesas/r8a779g0.dtsi | 31 ++++++++++++++++-------
1 file changed, 22 insertions(+), 9 deletions(-)
diff --git a/arch/arm64/boot/dts/renesas/r8a779g0.dtsi b/arch/arm64/boot/dts/renesas/r8a779g0.dtsi
index 3a8af825bb253..82e864acf2601 100644
--- a/arch/arm64/boot/dts/renesas/r8a779g0.dtsi
+++ b/arch/arm64/boot/dts/renesas/r8a779g0.dtsi
@@ -792,6 +792,7 @@ pciec0: pcie@e65d0000 {
resets = <&cpg 624>;
reset-names = "pwr";
max-link-speed = <4>;
+ msi-parent = <&its>;
num-lanes = <2>;
#address-cells = <3>;
#size-cells = <2>;
@@ -802,10 +803,10 @@ pciec0: pcie@e65d0000 {
dma-ranges = <0x42000000 0 0x00000000 0 0x00000000 1 0x00000000>;
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 7>;
- interrupt-map = <0 0 0 1 &gic GIC_SPI 449 IRQ_TYPE_LEVEL_HIGH>,
- <0 0 0 2 &gic GIC_SPI 449 IRQ_TYPE_LEVEL_HIGH>,
- <0 0 0 3 &gic GIC_SPI 449 IRQ_TYPE_LEVEL_HIGH>,
- <0 0 0 4 &gic GIC_SPI 449 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-map = <0 0 0 1 &gic 0 0 GIC_SPI 449 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 2 &gic 0 0 GIC_SPI 449 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 3 &gic 0 0 GIC_SPI 449 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 4 &gic 0 0 GIC_SPI 449 IRQ_TYPE_LEVEL_HIGH>;
snps,enable-cdm-check;
status = "disabled";
@@ -839,6 +840,7 @@ pciec1: pcie@e65d8000 {
resets = <&cpg 625>;
reset-names = "pwr";
max-link-speed = <4>;
+ msi-parent = <&its>;
num-lanes = <2>;
#address-cells = <3>;
#size-cells = <2>;
@@ -849,10 +851,10 @@ pciec1: pcie@e65d8000 {
dma-ranges = <0x42000000 0 0x00000000 0 0x00000000 1 0x00000000>;
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 7>;
- interrupt-map = <0 0 0 1 &gic GIC_SPI 456 IRQ_TYPE_LEVEL_HIGH>,
- <0 0 0 2 &gic GIC_SPI 456 IRQ_TYPE_LEVEL_HIGH>,
- <0 0 0 3 &gic GIC_SPI 456 IRQ_TYPE_LEVEL_HIGH>,
- <0 0 0 4 &gic GIC_SPI 456 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-map = <0 0 0 1 &gic 0 0 GIC_SPI 456 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 2 &gic 0 0 GIC_SPI 456 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 3 &gic 0 0 GIC_SPI 456 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 4 &gic 0 0 GIC_SPI 456 IRQ_TYPE_LEVEL_HIGH>;
snps,enable-cdm-check;
status = "disabled";
@@ -2131,11 +2133,22 @@ ipmmu_mm: iommu@eefc0000 {
gic: interrupt-controller@f1000000 {
compatible = "arm,gic-v3";
#interrupt-cells = <3>;
- #address-cells = <0>;
+ #address-cells = <2>;
+ #size-cells = <2>;
interrupt-controller;
reg = <0x0 0xf1000000 0 0x20000>,
<0x0 0xf1060000 0 0x110000>;
interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+ dma-noncoherent;
+
+ ranges = <0x0 0x0 0x0 0xf1000000 0x0 0x200000>;
+
+ its: msi-controller@40000 {
+ compatible = "arm,gic-v3-its";
+ reg = <0x0 0x40000 0x0 0x20000>;
+ dma-noncoherent;
+ msi-controller;
+ };
};
gpu: gpu@fd000000 {
--
2.53.0
^ permalink raw reply related
* [PATCH 2/3] irqchip/gic-v3: Add Renesas R-Car Gen4 erratum workaround
From: Marek Vasut @ 2026-06-17 2:59 UTC (permalink / raw)
To: linux-pci
Cc: Marek Vasut, Yoshihiro Shimoda, Krzysztof Wilczyński,
Bjorn Helgaas, Catalin Marinas, Conor Dooley, Geert Uytterhoeven,
Krzysztof Kozlowski, Lorenzo Pieralisi, Manivannan Sadhasivam,
Marc Zyngier, Rob Herring, devicetree, linux-arm-kernel,
linux-doc, linux-kernel, linux-renesas-soc
In-Reply-To: <20260617030008.154449-1-marek.vasut+renesas@mailbox.org>
Renesas R-Car S4/V4H/V4M GIC600 integration has address width for AXI
or APB interface configured to 32 bit, it can therefore access only
the first 4 GiB of physical address space. This information comes from
R-Car V4H Interface Specification sheet, there is currently no technical
update number assigned to this limitation. Further input from hardware
engineer indicates that this limitation also applies to R-Car S4 and V4M.
Name the limitation GEN4GICITS1, and add a driver quirk to mitigate this
limitation.
Note that the 0x0201743b GIC600 ID is not Renesas-specific, it is
common for many ARM GICv3 implementations. Therefore, add an extra
of_machine_is_compatible() check.
The GIC600 implementation in R-Car S4/V4H/V4M is r1p6.
Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
---
NOTE: This would not be possible without prior work from Shimoda-san
https://lore.kernel.org/all/20240214052050.1966439-1-yoshihiro.shimoda.uh@renesas.com/
---
Cc: "Krzysztof Wilczyński" <kwilczynski@kernel.org>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Conor Dooley <conor+dt@kernel.org>
Cc: Geert Uytterhoeven <geert+renesas@glider.be>
Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
Cc: Lorenzo Pieralisi <lpieralisi@kernel.org>
Cc: Manivannan Sadhasivam <mani@kernel.org>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Rob Herring <robh@kernel.org>
Cc: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Cc: devicetree@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-doc@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-pci@vger.kernel.org
Cc: linux-renesas-soc@vger.kernel.org
---
Documentation/arch/arm64/silicon-errata.rst | 1 +
arch/arm64/Kconfig | 9 +++++++++
drivers/irqchip/irq-gic-v3-its.c | 20 ++++++++++++++++++++
3 files changed, 30 insertions(+)
diff --git a/Documentation/arch/arm64/silicon-errata.rst b/Documentation/arch/arm64/silicon-errata.rst
index 014aa1c215a16..b0c68b64f5ac2 100644
--- a/Documentation/arch/arm64/silicon-errata.rst
+++ b/Documentation/arch/arm64/silicon-errata.rst
@@ -352,6 +352,7 @@ stable kernels.
+----------------+-----------------+-----------------+-----------------------------+
| Qualcomm Tech. | Kryo4xx Gold | N/A | ARM64_ERRATUM_1286807 |
+----------------+-----------------+-----------------+-----------------------------+
+| Renesas | S4/V4H/V4M | N/A | RENESAS_ERRATUM_GEN4GICITS1 |
+----------------+-----------------+-----------------+-----------------------------+
| Rockchip | RK3588 | #3588001 | ROCKCHIP_ERRATUM_3588001 |
+----------------+-----------------+-----------------+-----------------------------+
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index b3afe0688919b..b9e17ce475e61 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1382,6 +1382,15 @@ config NVIDIA_CARMEL_CNP_ERRATUM
If unsure, say Y.
+config RENESAS_ERRATUM_GEN4GICITS1
+ bool "Renesas R-Car Gen4: GIC600 can not access physical addresses above 4 GiB"
+ default y
+ help
+ The Renesas R-Car Gen4 S4/V4H/V4M GIC600 SoC integrations have AXI
+ addressing limited to the first 32-bit of physical address space.
+
+ If unsure, say Y.
+
config ROCKCHIP_ERRATUM_3568002
bool "Rockchip 3568002: GIC600 can not access physical addresses higher than 4GB"
default y
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index b57d81ad33a0a..ec3756f29cf1a 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -4901,6 +4901,18 @@ static bool __maybe_unused its_enable_rk3568002(void *data)
return true;
}
+static bool __maybe_unused its_enable_renesas_gen4(void *data)
+{
+ if (!of_machine_is_compatible("renesas,r8a779f0") &&
+ !of_machine_is_compatible("renesas,r8a779g0") &&
+ !of_machine_is_compatible("renesas,r8a779h0"))
+ return false;
+
+ gfp_flags_quirk |= GFP_DMA32;
+
+ return true;
+}
+
static const struct gic_quirk its_quirks[] = {
#ifdef CONFIG_CAVIUM_ERRATUM_22375
{
@@ -4975,6 +4987,14 @@ static const struct gic_quirk its_quirks[] = {
.mask = 0xffffffff,
.init = its_enable_rk3568002,
},
+#endif
+#ifdef CONFIG_RENESAS_ERRATUM_GEN4GICITS1
+ {
+ .desc = "ITS: Renesas R-Car Gen4 GIC600 32-bit limit",
+ .iidr = 0x0201743b,
+ .mask = 0xffffffff,
+ .init = its_enable_renesas_gen4,
+ },
#endif
{
}
--
2.53.0
^ permalink raw reply related
* [PATCH 1/3] PCI: rcar-gen4: Configure AXIINTC if iMSI-RX not used
From: Marek Vasut @ 2026-06-17 2:59 UTC (permalink / raw)
To: linux-pci
Cc: Marek Vasut, Yoshihiro Shimoda, Krzysztof Wilczyński,
Bjorn Helgaas, Catalin Marinas, Conor Dooley, Geert Uytterhoeven,
Krzysztof Kozlowski, Lorenzo Pieralisi, Manivannan Sadhasivam,
Marc Zyngier, Rob Herring, devicetree, linux-arm-kernel,
linux-doc, linux-kernel, linux-renesas-soc
In case MSI are enabled, but DWC built-in iMSI-RX is not in use, the
MSI are handled via GIC ITS. Configure all controller MSI registers
fully.
Set or clear MSI capability register MSICAP0 MSI enable MSIE bit and
PCIe Interrupt Status 0 Enable register PCIEINTSTS0EN MSI interrupt
enable MSI_CTRL_INT bit according to MSI enable state, set both bits
if MSI are enabled, clear both bits if MSI are disabled.
If MSI are disabled, or MSI are enabled and iMSI-RX is used, then
deconfigure AXIINTCADDR and AXIINTCCONT to 0, which disables any
pass through of MSI TLPs onto the AXI bus and then further into
GIC ITS translation registers.
If MSI are enabled and iMSI-RX is not used, the configure AXIINTCADDR
with target address of GIC ITS translation registers, and configure
AXIINTCCONT to enable MSI TLP pass through onto AXI bus and into the
GIC ITS. This specific configuration allows handling of MSI via the
GIC ITS instead of integrated iMSI-RX.
Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
---
NOTE: This would not be possible without prior work from Shimoda-san
---
Cc: "Krzysztof Wilczyński" <kwilczynski@kernel.org>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Conor Dooley <conor+dt@kernel.org>
Cc: Geert Uytterhoeven <geert+renesas@glider.be>
Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
Cc: Lorenzo Pieralisi <lpieralisi@kernel.org>
Cc: Manivannan Sadhasivam <mani@kernel.org>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Rob Herring <robh@kernel.org>
Cc: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Cc: devicetree@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-doc@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-pci@vger.kernel.org
Cc: linux-renesas-soc@vger.kernel.org
---
drivers/pci/controller/dwc/pcie-rcar-gen4.c | 53 +++++++++++++++++++--
1 file changed, 48 insertions(+), 5 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
index 485cfa8bd9692..ba6e3bedd6d0a 100644
--- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c
+++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
@@ -31,6 +31,10 @@
#define DEVICE_TYPE_RC BIT(4)
#define BIFUR_MOD_SET_ON BIT(0)
+/* MSI Capability */
+#define MSICAP0 0x0050
+#define MSICAP0_MSIE BIT(16)
+
/* PCIe Interrupt Status 0 */
#define PCIEINTSTS0 0x0084
@@ -55,6 +59,16 @@
#define APP_HOLD_PHY_RST BIT(16)
#define APP_LTSSM_ENABLE BIT(0)
+/* INTC address */
+#define AXIINTCADDR 0x0a00
+/* GITS GIC ITS translation register */
+#define AXIINTCADDR_VAL 0xf1050000
+
+/* INTC control & mask */
+#define AXIINTCCONT 0x0a04
+#define INTC_EN BIT(31)
+#define INTC_MASK GENMASK(11, 2)
+
/* PCIe Power Management Control */
#define PCIEPWRMNGCTRL 0x0070
#define APP_CLK_REQ_N BIT(11)
@@ -305,6 +319,39 @@ static struct rcar_gen4_pcie *rcar_gen4_pcie_alloc(struct platform_device *pdev)
return rcar;
}
+static void rcar_gen4_pcie_host_msi_init(struct dw_pcie_rp *pp)
+{
+ struct dw_pcie *dw = to_dw_pcie_from_pp(pp);
+ struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
+ u32 val;
+
+ /* Make sure MSICAP0 MSIE is configured. */
+ val = dw_pcie_readl_dbi(dw, MSICAP0);
+ if (pci_msi_enabled())
+ val |= MSICAP0_MSIE;
+ else
+ val &= ~MSICAP0_MSIE;
+ dw_pcie_writel_dbi(dw, MSICAP0, val);
+
+ if (!pci_msi_enabled() || pp->use_imsi_rx) {
+ /* Clear AXIINTC mapping. */
+ writel(0, rcar->base + AXIINTCADDR);
+ writel(0, rcar->base + AXIINTCCONT);
+ } else {
+ /* Point AXIINTC to GIC ITS and enable. */
+ writel(AXIINTCADDR_VAL, rcar->base + AXIINTCADDR);
+ writel(INTC_EN | INTC_MASK, rcar->base + AXIINTCCONT);
+ }
+
+ /* Configure MSI interrupt signal */
+ val = readl(rcar->base + PCIEINTSTS0EN);
+ if (pci_msi_enabled())
+ val |= MSI_CTRL_INT;
+ else
+ val &= ~MSI_CTRL_INT;
+ writel(val, rcar->base + PCIEINTSTS0EN);
+}
+
static int rcar_gen4_pcie_enable_device(struct pci_host_bridge *bridge,
struct pci_dev *dev)
{
@@ -359,7 +406,6 @@ static int rcar_gen4_pcie_host_init(struct dw_pcie_rp *pp)
struct dw_pcie *dw = to_dw_pcie_from_pp(pp);
struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
int ret;
- u32 val;
if (pp->bridge)
pp->bridge->enable_device = rcar_gen4_pcie_enable_device;
@@ -379,10 +425,7 @@ static int rcar_gen4_pcie_host_init(struct dw_pcie_rp *pp)
dw_pcie_writel_dbi2(dw, PCI_BASE_ADDRESS_0, 0x0);
dw_pcie_writel_dbi2(dw, PCI_BASE_ADDRESS_1, 0x0);
- /* Enable MSI interrupt signal */
- val = readl(rcar->base + PCIEINTSTS0EN);
- val |= MSI_CTRL_INT;
- writel(val, rcar->base + PCIEINTSTS0EN);
+ rcar_gen4_pcie_host_msi_init(pp);
msleep(PCIE_T_PVPERL_MS); /* pe_rst requires 100msec delay */
--
2.53.0
^ permalink raw reply related
* [PATCH v4 2/2] pwm: Add Nuvoton MA35D1 PWM controller support
From: Chi-Wen Weng @ 2026-06-17 2:59 UTC (permalink / raw)
To: ukleinek, robh, krzk+dt, conor+dt
Cc: linux-arm-kernel, linux-pwm, devicetree, linux-kernel, cwweng,
cwweng.linux, Trevor Gamblin
In-Reply-To: <20260617025925.2539334-1-cwweng.linux@gmail.com>
From: Chi-Wen Weng <cwweng@nuvoton.com>
Add a PWM framework driver for the Nuvoton MA35D1 PWM controller.
The MA35D1 PWM controller provides 6 PWM channels. The hardware supports
up, down and up-down counter types, auto-reload and one-shot modes, and
independent and complementary output modes. This driver configures all
channels to up-counting mode, auto-reload mode and independent output mode.
The waveform generator is configured to drive the output high at the zero
point and low at the compare-up point. In up-counting mode the counter
counts from 0 to PERIOD inclusive, so the PWM period is PERIOD + 1 cycles.
With the selected waveform actions, CMPDAT = 0 generates 0% duty cycle and
CMPDAT > PERIOD generates 100% duty cycle. Limit PERIOD to 0xfffe so that
CMPDAT = 0xffff can be used for the full-duty case.
PERIOD and CMPDAT updates are buffered by the hardware and take effect at
the end of the current period because IMMLDENn is left disabled. When the
PWM output is disabled, POENn is cleared and the output pin is put into
tri-state.
Reviewed-by: Trevor Gamblin <tgamblin@baylibre.com>
Signed-off-by: Chi-Wen Weng <cwweng@nuvoton.com>
---
drivers/pwm/Kconfig | 9 +
drivers/pwm/Makefile | 1 +
drivers/pwm/pwm-ma35d1.c | 344 +++++++++++++++++++++++++++++++++++++++
3 files changed, 354 insertions(+)
create mode 100644 drivers/pwm/pwm-ma35d1.c
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index e8886a9b64d9..355131e6efac 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -463,6 +463,15 @@ config PWM_LPSS_PLATFORM
To compile this driver as a module, choose M here: the module
will be called pwm-lpss-platform.
+config PWM_MA35D1
+ tristate "Nuvoton MA35D1 PWM support"
+ depends on ARCH_MA35 || COMPILE_TEST
+ help
+ Generic PWM framework driver for Nuvoton MA35D1.
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-ma35d1.
+
config PWM_MAX7360
tristate "MAX7360 PWMs"
depends on MFD_MAX7360
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 5630a521a7cf..7ad761ea27d1 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o
obj-$(CONFIG_PWM_LPSS) += pwm-lpss.o
obj-$(CONFIG_PWM_LPSS_PCI) += pwm-lpss-pci.o
obj-$(CONFIG_PWM_LPSS_PLATFORM) += pwm-lpss-platform.o
+obj-$(CONFIG_PWM_MA35D1) += pwm-ma35d1.o
obj-$(CONFIG_PWM_MAX7360) += pwm-max7360.o
obj-$(CONFIG_PWM_MC33XS2410) += pwm-mc33xs2410.o
obj-$(CONFIG_PWM_MEDIATEK) += pwm-mediatek.o
diff --git a/drivers/pwm/pwm-ma35d1.c b/drivers/pwm/pwm-ma35d1.c
new file mode 100644
index 000000000000..c07eedeca035
--- /dev/null
+++ b/drivers/pwm/pwm-ma35d1.c
@@ -0,0 +1,344 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for the Nuvoton MA35D1 PWM controller
+ *
+ * Copyright (C) 2026 Nuvoton Corporation
+ * Chi-Wen Weng <cwweng@nuvoton.com>
+ *
+ * Reference Manual:
+ * https://www.nuvoton.com.cn/resource-download.jsp?tp_GUID=DA05-MA35D16
+ *
+ * Limitations:
+ * - The hardware supports 6 PWM channels.
+ * - The hardware supports up, down and up-down counter types. This driver
+ * configures all channels to up-counting mode.
+ * - The hardware supports auto-reload and one-shot counter modes. This driver
+ * configures all channels to auto-reload mode.
+ * - The hardware supports independent and complementary output modes. This
+ * driver configures all channels to independent output mode.
+ * - The hardware supports programmable waveform actions at zero, period and
+ * compare points. This driver uses zero point high and compare-up point low
+ * actions for normal PWM output.
+ * - In up-counting mode, the counter counts from 0 to PERIOD inclusive. With
+ * zero point high and compare-up point low actions, CMPDAT = 0 produces 0%
+ * duty and CMPDAT > PERIOD produces 100% duty.
+ * - The driver limits PERIOD to 0xfffe so that CMPDAT can be set greater than
+ * PERIOD to generate a 100% duty cycle.
+ * - Period and duty cycle changes are buffered by hardware and take effect at
+ * the end of the current period because IMMLDENn is left disabled.
+ * - Polarity changes are applied directly and may cause a transient output
+ * change if the PWM output is running.
+ * - When disabled, the output pin is put in tri-state by clearing POENn.
+ */
+
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/math64.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+
+#define MA35D1_REG_PWM_CTL0 0x00
+#define MA35D1_REG_PWM_CTL1 0x04
+#define MA35D1_REG_PWM_CNTEN 0x20
+#define MA35D1_REG_PWM_PERIOD(ch) (0x30 + 4 * (ch))
+#define MA35D1_REG_PWM_CMPDAT(ch) (0x50 + 4 * (ch))
+#define MA35D1_REG_PWM_WGCTL0 0xb0
+#define MA35D1_REG_PWM_WGCTL1 0xb4
+#define MA35D1_REG_PWM_POLCTL 0xd4
+#define MA35D1_REG_PWM_POEN 0xd8
+
+#define MA35D1_PWM_CTL1_CNTMODE_MASK(ch) BIT(16 + (ch))
+#define MA35D1_PWM_CTL1_OUTMODE_MASK(ch) BIT(24 + ((ch) / 2))
+
+#define MA35D1_PWM_WGCTL_ACTION_MASK 0x3
+#define MA35D1_PWM_WGCTL_ACTION_LOW 1
+#define MA35D1_PWM_WGCTL_ACTION_HIGH 2
+
+#define MA35D1_PWM_WGCTL_ZERO_HIGH(ch) \
+ (MA35D1_PWM_WGCTL_ACTION_HIGH << (2 * (ch)))
+#define MA35D1_PWM_WGCTL_CMP_UP_LOW(ch) \
+ (MA35D1_PWM_WGCTL_ACTION_LOW << (2 * (ch)))
+
+#define MA35D1_PWM_CNTEN_EN(ch) BIT(ch)
+#define MA35D1_PWM_POEN_EN(ch) BIT(ch)
+#define MA35D1_PWM_POLCTL_INV(ch) BIT(ch)
+
+#define MA35D1_PWM_MAX_CMPDAT 0xffff
+#define MA35D1_PWM_MAX_PERIOD 0xfffe
+#define MA35D1_PWM_MAX_PERIOD_CYCLES (MA35D1_PWM_MAX_PERIOD + 1)
+#define MA35D1_PWM_NUM_CHANNELS 6
+
+struct nuvoton_pwm {
+ void __iomem *base;
+ unsigned long clkrate;
+};
+
+static inline struct nuvoton_pwm *nuvoton_pwm_from_chip(struct pwm_chip *chip)
+{
+ return pwmchip_get_drvdata(chip);
+}
+
+static inline u32 nuvoton_pwm_ctl1_cnttype_mask(unsigned int ch)
+{
+ return MA35D1_PWM_WGCTL_ACTION_MASK << (2 * ch);
+}
+
+static inline u32 nuvoton_pwm_wgctl_zero_mask(unsigned int ch)
+{
+ return MA35D1_PWM_WGCTL_ACTION_MASK << (2 * ch);
+}
+
+static inline u32 nuvoton_pwm_wgctl_period_mask(unsigned int ch)
+{
+ return MA35D1_PWM_WGCTL_ACTION_MASK << (16 + 2 * ch);
+}
+
+static inline u32 nuvoton_pwm_wgctl_cmp_up_mask(unsigned int ch)
+{
+ return MA35D1_PWM_WGCTL_ACTION_MASK << (2 * ch);
+}
+
+static inline u32 nuvoton_pwm_wgctl_cmp_down_mask(unsigned int ch)
+{
+ return MA35D1_PWM_WGCTL_ACTION_MASK << (16 + 2 * ch);
+}
+
+static inline u32 nuvoton_pwm_readl(struct nuvoton_pwm *nvtpwm,
+ unsigned int offset)
+{
+ return readl(nvtpwm->base + offset);
+}
+
+static inline void nuvoton_pwm_writel(struct nuvoton_pwm *nvtpwm,
+ unsigned int offset, u32 value)
+{
+ writel(value, nvtpwm->base + offset);
+}
+
+static inline void nuvoton_pwm_rmw(struct nuvoton_pwm *nvtpwm,
+ unsigned int offset, u32 mask, u32 value)
+{
+ u32 reg;
+
+ reg = nuvoton_pwm_readl(nvtpwm, offset);
+ reg &= ~mask;
+ reg |= value & mask;
+ nuvoton_pwm_writel(nvtpwm, offset, reg);
+}
+
+static void nuvoton_pwm_init(struct nuvoton_pwm *nvtpwm)
+{
+ u32 ctl1_mask = 0;
+ u32 wgctl0_mask = 0;
+ u32 wgctl0_val = 0;
+ u32 wgctl1_mask = 0;
+ u32 wgctl1_val = 0;
+ int ch;
+
+ for (ch = 0; ch < MA35D1_PWM_NUM_CHANNELS; ch++) {
+ /* CNTTYPEn = 00: up counter type */
+ ctl1_mask |= nuvoton_pwm_ctl1_cnttype_mask(ch);
+
+ /* CNTMODEn = 0: auto-reload mode */
+ ctl1_mask |= MA35D1_PWM_CTL1_CNTMODE_MASK(ch);
+
+ /* ZPCTLn = 10: output high at zero point */
+ wgctl0_mask |= nuvoton_pwm_wgctl_zero_mask(ch);
+ wgctl0_val |= MA35D1_PWM_WGCTL_ZERO_HIGH(ch);
+
+ /* PRDPCTLn = 00: do nothing at period point */
+ wgctl0_mask |= nuvoton_pwm_wgctl_period_mask(ch);
+
+ /* CMPUCTLn = 01: output low at compare up point */
+ wgctl1_mask |= nuvoton_pwm_wgctl_cmp_up_mask(ch);
+ wgctl1_val |= MA35D1_PWM_WGCTL_CMP_UP_LOW(ch);
+
+ /* CMPDCTLn = 00: do nothing at compare down point */
+ wgctl1_mask |= nuvoton_pwm_wgctl_cmp_down_mask(ch);
+ }
+
+ for (ch = 0; ch < MA35D1_PWM_NUM_CHANNELS; ch += 2) {
+ /* OUTMODEn = 0: independent mode */
+ ctl1_mask |= MA35D1_PWM_CTL1_OUTMODE_MASK(ch);
+ }
+
+ nuvoton_pwm_rmw(nvtpwm, MA35D1_REG_PWM_CTL1, ctl1_mask, 0);
+ nuvoton_pwm_rmw(nvtpwm, MA35D1_REG_PWM_WGCTL0,
+ wgctl0_mask, wgctl0_val);
+ nuvoton_pwm_rmw(nvtpwm, MA35D1_REG_PWM_WGCTL1,
+ wgctl1_mask, wgctl1_val);
+}
+
+static int nuvoton_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+ const struct pwm_state *state)
+{
+ struct nuvoton_pwm *nvtpwm = nuvoton_pwm_from_chip(chip);
+ u32 ch = pwm->hwpwm;
+ u64 duty_cycles, period_cycles;
+ u32 cmpdat, period;
+
+ if (!state->enabled) {
+ nuvoton_pwm_rmw(nvtpwm, MA35D1_REG_PWM_POEN,
+ MA35D1_PWM_POEN_EN(ch), 0);
+ nuvoton_pwm_rmw(nvtpwm, MA35D1_REG_PWM_CNTEN,
+ MA35D1_PWM_CNTEN_EN(ch), 0);
+
+ return 0;
+ }
+
+ period_cycles = mul_u64_u64_div_u64(nvtpwm->clkrate,
+ state->period,
+ NSEC_PER_SEC);
+ if (!period_cycles)
+ return -EINVAL;
+
+ if (period_cycles > MA35D1_PWM_MAX_PERIOD_CYCLES)
+ period_cycles = MA35D1_PWM_MAX_PERIOD_CYCLES;
+
+ duty_cycles = mul_u64_u64_div_u64(nvtpwm->clkrate,
+ state->duty_cycle,
+ NSEC_PER_SEC);
+ if (duty_cycles > period_cycles)
+ duty_cycles = period_cycles;
+
+ if (state->polarity == PWM_POLARITY_NORMAL)
+ nuvoton_pwm_rmw(nvtpwm, MA35D1_REG_PWM_POLCTL,
+ MA35D1_PWM_POLCTL_INV(ch), 0);
+ else
+ nuvoton_pwm_rmw(nvtpwm, MA35D1_REG_PWM_POLCTL,
+ MA35D1_PWM_POLCTL_INV(ch),
+ MA35D1_PWM_POLCTL_INV(ch));
+
+ /*
+ * In up-counting mode the counter counts from 0 to PERIOD inclusive.
+ * With zero point high and compare-up point low actions:
+ * - CMPDAT = 0 produces 0% duty.
+ * - CMPDAT > PERIOD produces 100% duty.
+ * PERIOD is limited to 0xfffe, so duty_cycles can be written directly
+ * to CMPDAT and still fit in the 16-bit compare field for 100% duty.
+ */
+ period = period_cycles - 1;
+ cmpdat = duty_cycles;
+
+ nuvoton_pwm_writel(nvtpwm, MA35D1_REG_PWM_PERIOD(ch), period);
+ nuvoton_pwm_writel(nvtpwm, MA35D1_REG_PWM_CMPDAT(ch), cmpdat);
+
+ nuvoton_pwm_rmw(nvtpwm, MA35D1_REG_PWM_CNTEN,
+ MA35D1_PWM_CNTEN_EN(ch), MA35D1_PWM_CNTEN_EN(ch));
+ nuvoton_pwm_rmw(nvtpwm, MA35D1_REG_PWM_POEN,
+ MA35D1_PWM_POEN_EN(ch), MA35D1_PWM_POEN_EN(ch));
+
+ return 0;
+}
+
+static int nuvoton_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
+ struct pwm_state *state)
+{
+ struct nuvoton_pwm *nvtpwm = nuvoton_pwm_from_chip(chip);
+ u32 ch = pwm->hwpwm;
+ u32 cmpdat, cnten, period, poen, polctl;
+ u64 duty_cycles, period_cycles;
+
+ cnten = nuvoton_pwm_readl(nvtpwm, MA35D1_REG_PWM_CNTEN);
+ poen = nuvoton_pwm_readl(nvtpwm, MA35D1_REG_PWM_POEN);
+ polctl = nuvoton_pwm_readl(nvtpwm, MA35D1_REG_PWM_POLCTL);
+ period = nuvoton_pwm_readl(nvtpwm, MA35D1_REG_PWM_PERIOD(ch)) &
+ MA35D1_PWM_MAX_CMPDAT;
+ cmpdat = nuvoton_pwm_readl(nvtpwm, MA35D1_REG_PWM_CMPDAT(ch)) &
+ MA35D1_PWM_MAX_CMPDAT;
+
+ period_cycles = period + 1;
+ if (cmpdat > period)
+ duty_cycles = period_cycles;
+ else
+ duty_cycles = cmpdat;
+
+ state->enabled = (cnten & MA35D1_PWM_CNTEN_EN(ch)) &&
+ (poen & MA35D1_PWM_POEN_EN(ch));
+ state->polarity = (polctl & MA35D1_PWM_POLCTL_INV(ch)) ?
+ PWM_POLARITY_INVERSED : PWM_POLARITY_NORMAL;
+ state->period = DIV64_U64_ROUND_UP(period_cycles * NSEC_PER_SEC,
+ nvtpwm->clkrate);
+ state->duty_cycle = DIV64_U64_ROUND_UP(duty_cycles * NSEC_PER_SEC,
+ nvtpwm->clkrate);
+
+ return 0;
+}
+
+static const struct pwm_ops nuvoton_pwm_ops = {
+ .apply = nuvoton_pwm_apply,
+ .get_state = nuvoton_pwm_get_state,
+};
+
+static int nuvoton_pwm_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct pwm_chip *chip;
+ struct nuvoton_pwm *nvtpwm;
+ struct clk *clk;
+ int ret;
+
+ chip = devm_pwmchip_alloc(dev, MA35D1_PWM_NUM_CHANNELS,
+ sizeof(*nvtpwm));
+ if (IS_ERR(chip))
+ return PTR_ERR(chip);
+
+ nvtpwm = nuvoton_pwm_from_chip(chip);
+
+ nvtpwm->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(nvtpwm->base))
+ return PTR_ERR(nvtpwm->base);
+
+ clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(clk))
+ return dev_err_probe(dev, PTR_ERR(clk),
+ "Unable to get the clock\n");
+
+ ret = devm_clk_rate_exclusive_get(dev, clk);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Unable to get exclusive clock rate\n");
+
+ nvtpwm->clkrate = clk_get_rate(clk);
+ if (!nvtpwm->clkrate)
+ return dev_err_probe(dev, -EINVAL,
+ "PWM clock rate is zero\n");
+
+ if (nvtpwm->clkrate > NSEC_PER_SEC)
+ return dev_err_probe(dev, -EINVAL,
+ "PWM clock out of range (%lu)\n",
+ nvtpwm->clkrate);
+
+ nuvoton_pwm_init(nvtpwm);
+
+ chip->ops = &nuvoton_pwm_ops;
+ chip->atomic = true;
+
+ ret = devm_pwmchip_add(dev, chip);
+ if (ret)
+ return dev_err_probe(dev, ret, "Unable to add PWM chip\n");
+
+ return 0;
+}
+
+static const struct of_device_id nuvoton_pwm_of_match[] = {
+ { .compatible = "nuvoton,ma35d1-pwm" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, nuvoton_pwm_of_match);
+
+static struct platform_driver nuvoton_pwm_driver = {
+ .probe = nuvoton_pwm_probe,
+ .driver = {
+ .name = "nuvoton-pwm",
+ .of_match_table = nuvoton_pwm_of_match,
+ },
+};
+module_platform_driver(nuvoton_pwm_driver);
+
+MODULE_AUTHOR("Chi-Wen Weng <cwweng@nuvoton.com>");
+MODULE_DESCRIPTION("Nuvoton MA35D1 PWM driver");
+MODULE_LICENSE("GPL");
--
2.25.1
^ permalink raw reply related
* [PATCH v4 1/2] dt-bindings: pwm: Add Nuvoton MA35D1 PWM controller
From: Chi-Wen Weng @ 2026-06-17 2:59 UTC (permalink / raw)
To: ukleinek, robh, krzk+dt, conor+dt
Cc: linux-arm-kernel, linux-pwm, devicetree, linux-kernel, cwweng,
cwweng.linux, Krzysztof Kozlowski
In-Reply-To: <20260617025925.2539334-1-cwweng.linux@gmail.com>
From: Chi-Wen Weng <cwweng@nuvoton.com>
Add device tree binding for the Nuvoton MA35D1 PWM controller.
The MA35D1 PWM controller provides 6 PWM channels and uses one register
region and one functional clock. The binding uses the standard PWM binding
with three PWM cells.
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Signed-off-by: Chi-Wen Weng <cwweng@nuvoton.com>
---
.../bindings/pwm/nuvoton,ma35d1-pwm.yaml | 45 +++++++++++++++++++
1 file changed, 45 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pwm/nuvoton,ma35d1-pwm.yaml
diff --git a/Documentation/devicetree/bindings/pwm/nuvoton,ma35d1-pwm.yaml b/Documentation/devicetree/bindings/pwm/nuvoton,ma35d1-pwm.yaml
new file mode 100644
index 000000000000..47a59bdd14d0
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/nuvoton,ma35d1-pwm.yaml
@@ -0,0 +1,45 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pwm/nuvoton,ma35d1-pwm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Nuvoton MA35D1 PWM controller
+
+maintainers:
+ - Chi-Wen Weng <cwweng@nuvoton.com>
+
+allOf:
+ - $ref: pwm.yaml#
+
+properties:
+ compatible:
+ enum:
+ - nuvoton,ma35d1-pwm
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ "#pwm-cells":
+ const: 3
+
+required:
+ - compatible
+ - reg
+ - clocks
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/nuvoton,ma35d1-clk.h>
+
+ pwm@40580000 {
+ compatible = "nuvoton,ma35d1-pwm";
+ reg = <0x40580000 0x400>;
+ clocks = <&clk EPWM0_GATE>;
+ #pwm-cells = <3>;
+ };
--
2.25.1
^ permalink raw reply related
* [PATCH] net: airoha: Fix off-by-one error in HTB rate-limit channel removal
From: Wayen Yan @ 2026-06-17 2:51 UTC (permalink / raw)
To: netdev
Cc: lorenzo, horms, pabeni, kuba, edumazet, andrew+netdev,
angelogioacchino.delregno, matthias.bgg, linux-arm-kernel,
linux-mediatek
In airoha_tc_remove_htb_queue(), the rate-limit was being cleared
using (queue + 1) instead of queue, causing:
- The original channel rate-limit configuration to remain active
- The next channel to be incorrectly disabled
- Potential out-of-bounds access when queue == 3 (channel 4)
The alloc path (airoha_tc_htb_alloc_leaf_queue) correctly uses
channel (0..3), but the remove path incorrectly added 1.
Fix by using queue directly to match the alloc and rollback paths.
Fixes: ef1ca9271313 ("net: airoha: Add sched HTB offload support")
Signed-off-by: Wayen Yan <win847@gmail.com>
---
drivers/net/ethernet/airoha/airoha_eth.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 31cdb11cd7..02807b3967 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -2805,7 +2805,7 @@ static void airoha_tc_remove_htb_queue(struct net_device *dev, int queue)
struct airoha_gdm_port *port = netdev_priv(dev);
netif_set_real_num_tx_queues(dev, dev->real_num_tx_queues - 1);
- airoha_qdma_set_tx_rate_limit(dev, queue + 1, 0, 0);
+ airoha_qdma_set_tx_rate_limit(dev, queue, 0, 0);
clear_bit(queue, port->qos_sq_bmap);
}
--
2.51.0
^ permalink raw reply related
* Re: [PATCH] KVM: arm64: nv: Translate vEL2 PSTATE to EL1 in kvm_hyp_handle_mops()
From: swing sze @ 2026-06-17 2:52 UTC (permalink / raw)
To: Oliver Upton
Cc: Marc Zyngier, Catalin Marinas, Will Deacon, Joey Gouly,
Steffen Eiden, Suzuki K Poulose, Zenghui Yu, Andrew Morton,
Jakub Kicinski, Bjorn Andersson, Mark Rutland, Kristina Martsenko,
linux-arm-kernel, kvmarm, Zhong Wang, Xuanqing Shi
In-Reply-To: <ajGur_YEMoMLZPSF@kernel.org>
Oliver Upton <oupton@kernel.org> 于2026年6月17日周三 04:14写道:
>
> Hi Weiming,
>
> Thanks for the fix.
>
> On Tue, Jun 16, 2026 at 07:49:44PM +0800, Weiming Shi wrote:
> > When a nested virtualisation guest is running its virtual EL2 (vEL2),
> > fixup_guest_exit() rewrites vcpu_cpsr() to the guest's virtual exception
> > level: a hardware PSTATE.M of EL1{t,h} is presented as EL2{t,h}. The
> > hardware, however, executes vEL2 at EL1.
> >
> > kvm_hyp_handle_mops() runs on the fast guest re-entry path, where it
> > clears the single-step bit and restores SPSR_EL2 directly from
> > vcpu_cpsr():
> >
> > *vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS;
> > write_sysreg_el2(*vcpu_cpsr(vcpu), SYS_SPSR);
> >
> > For a guest hypervisor this writes the vEL2 view (PSTATE.M == EL2h) into
> > the hardware SPSR_EL2 without translating it back. The fast path re-enters
> > the guest via __guest_enter()/ERET without going through
> > __sysreg_restore_el2_return_state(), so neither to_hw_pstate() nor the
> > "return to a less privileged mode" safety check there (which would set
> > PSR_IL_BIT) is applied. The ERET therefore restores PSTATE.M = EL2h and
> > re-enters the guest at the real EL2 with a guest-controlled ELR, escaping
> > stage-2 and the guest/host boundary.
> >
> > This is reachable on a kernel with FEAT_MOPS running a KVM nested guest
> > (kvm-arm.mode=nested): KVM sets HCRX_EL2.MCE2, which the guest hypervisor
> > cannot clear for its own context (is_nested_ctxt() is false), so a vEL2
> > MOPS exception is taken to the host and dispatched to kvm_hyp_handle_mops()
> > with VCPU_IN_HYP_CONTEXT set.
> >
> > Translate EL2{t,h} back to EL1{t,h} before writing SPSR_EL2, mirroring
> > kvm_hyp_handle_eret(). For non-nested guests vcpu_cpsr() never holds an
> > EL2 mode, so the translation is a no-op and behaviour is unchanged.
>
> The changelog is unnecessarily verbose, instead:
>
> kvm_hyp_handle_mops() resets the single-step state machine as part of
> rewinding state for a MOPS exception by modifying vcpu_cpsr() and
> writing the result directly into hardware.
>
> In the case of nested virtualization, vcpu_cpsr() is a synthetic value
> such that the rest of KVM can deal with vEL2 cleanly. That means the
> value requires translation before being written into hardware, which is
> unfortunately missing from the MOPS handler.
>
> Fix it by directly modifying SPSR_EL2 and avoiding the synthetic state
> altogether, which will be resynchronized on the next 'full' exit back
> to KVM.
>
> Also:
>
> Cc: stable@vger.kernel.org
>
> Definitely meets the bar :)
>
> > Fixes: 2de451a329cf ("KVM: arm64: Add handler for MOPS exceptions")
> > Assisted-by: Claude:claude-opus-4-8
> > Reported-by: Zhong Wang <wangzhong.c0ss4ck@bytedance.com>
> > Reported-by: Xuanqing Shi <shixuanqing.11@bytedance.com>
> > Signed-off-by: Weiming Shi <bestswngs@gmail.com>
> > ---
> > arch/arm64/kvm/hyp/include/hyp/switch.h | 23 ++++++++++++++++++++++-
> > 1 file changed, 22 insertions(+), 1 deletion(-)
> >
> > diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
> > index e9b36a3b27bbc..a6b7963ddbf0b 100644
> > --- a/arch/arm64/kvm/hyp/include/hyp/switch.h
> > +++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
> > @@ -448,6 +448,8 @@ static inline bool __populate_fault_info(struct kvm_vcpu *vcpu)
> >
> > static inline bool kvm_hyp_handle_mops(struct kvm_vcpu *vcpu, u64 *exit_code)
> > {
> > + u64 spsr, mode;
> > +
> > *vcpu_pc(vcpu) = read_sysreg_el2(SYS_ELR);
> > arm64_mops_reset_regs(vcpu_gp_regs(vcpu), vcpu->arch.fault.esr_el2);
> > write_sysreg_el2(*vcpu_pc(vcpu), SYS_ELR);
> > @@ -457,7 +459,26 @@ static inline bool kvm_hyp_handle_mops(struct kvm_vcpu *vcpu, u64 *exit_code)
> > * instruction.
> > */
> > *vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS;
> > - write_sysreg_el2(*vcpu_cpsr(vcpu), SYS_SPSR);
> > +
> > + /*
> > + * For a guest hypervisor, vcpu_cpsr() holds the vEL2 view
> > + * (PSTATE.M == EL2h) installed by fixup_guest_exit(), but vEL2
> > + * runs at EL1. Translate it back before restoring SPSR_EL2, as in
> > + * kvm_hyp_handle_eret().
> > + */
> > + spsr = *vcpu_cpsr(vcpu);
> > + mode = spsr & (PSR_MODE_MASK | PSR_MODE32_BIT);
> > + switch (mode) {
> > + case PSR_MODE_EL2t:
> > + mode = PSR_MODE_EL1t;
> > + break;
> > + case PSR_MODE_EL2h:
> > + mode = PSR_MODE_EL1h;
> > + break;
> > + }
> > + spsr = (spsr & ~(PSR_MODE_MASK | PSR_MODE32_BIT)) | mode;
> > +
> > + write_sysreg_el2(spsr, SYS_SPSR);
>
> As I allude to in the modified changelog, I'd rather we just manipulate
> the hardware value of SPSR_EL2 directly. We already do this in
> kvm_hyp_handle_eret()
>
> spsr = read_sysreg_el2(SYS_SPSR);
> write_sysreg_el2(spsr & ~DBG_SPSR_SS, SYS_SPSR);
>
> Thanks,
> Oliver
Hi Oliver,
Thanks for your review. I will send the v2 version later.
Best
Weiming Shi
^ permalink raw reply
* [PATCH] ARM: smp: Always separate IPI labels from counters
From: xuchenchen @ 2026-06-17 2:30 UTC (permalink / raw)
To: linux; +Cc: linux-arm-kernel, linux-kernel, xuchenchen
From: xuchenchen <xuchenchen@kylinos.cn>
The ARM IPI lines in /proc/interrupts print the IPI label separately
from the per-CPU counters. The first counter is printed with "%10u",
which only provides a leading space while the value is less than ten
digits.
Once the counter reaches ten digits, the output can become:
IPI0:1234129290 ...
Keep a fixed separator after the IPI label so the first counter is
always separated from the label, matching the arm64 output format.
Signed-off-by: xuchenchen <xuchenchen@kylinos.cn>
---
arch/arm/kernel/smp.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index b5fb4697b..721c5f9f9 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -551,7 +551,7 @@ void show_ipi_list(struct seq_file *p, int prec)
if (!ipi_desc[i])
continue;
- seq_printf(p, "%*s%u:", prec - 1, "IPI", i);
+ seq_printf(p, "%*s%u: ", prec - 1, "IPI", i);
for_each_online_cpu(cpu)
seq_printf(p, "%10u ", irq_desc_kstat_cpu(ipi_desc[i], cpu));
--
2.47.3
^ permalink raw reply related
* Re: [PATCH v2] dmaengine: sun6i-dma: Fix memory leak in sun6i_dma_terminate_all
From: Hongling Zeng @ 2026-06-17 2:28 UTC (permalink / raw)
To: Frank Li
Cc: Hongling Zeng, vkoul, Frank.Li, wens, jernej.skrabec, samuel,
mripard, arnd, dmaengine, linux-arm-kernel, linux-sunxi,
linux-kernel
In-Reply-To: <ajG2aR70B4z6j1fd@SMW015318>
Hi Frank and Jernej Skrabec:
Thanks for all the review!
You're absolutely right.After checking virt-dma.h, I see that
desc_terminated is the correct queue for actively terminated transfers.
I'll update to use:
- vchan_terminate_vdesc(vd);
I'll send v3 ,Please help to review.
Best regards,
Hongling Zeng
在 2026年06月17日 04:47, Frank Li 写道:
> On Tue, Jun 16, 2026 at 02:04:49PM +0800, Hongling Zeng wrote:
>> When terminating a non-cyclic DMA transfer, the active descriptor
>> is not properly reclaimed. The descriptor is removed from the
>> desc_issued list in sun6i_dma_start_desc(), but in
>> sun6i_dma_terminate_all(), only cyclic transfer descriptors are
>> added to the desc_completed list before cleanup.
>>
>> For non-cyclic transfers, pchan->desc is set to NULL without first
>> adding the descriptor back to a list that vchan_get_all_descriptors()
>> can collect. This causes the descriptor and its associated LLI chain
>> to be permanently leaked.
>>
>> Fix by ensuring both cyclic and non-cyclic active descriptors are
>> added to the desc_completed list before setting pchan->desc to NULL.
>>
>> Fixes: 555859308723 ("dmaengine: sun6i: Add driver for the Allwinner A31 DMA controller")
>> Signed-off-by: Hongling Zeng <zenghongling@kylinos.cn>
>>
>> ---
>> Change in v2;
>> -Add pchan->desc != pchan->done check to prevent race condition
>> where completed descriptors could be double-added to desc_completed
>> list, causing list corruption
>> ---
>> drivers/dma/sun6i-dma.c | 12 +++++-------
>> 1 file changed, 5 insertions(+), 7 deletions(-)
>>
>> diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
>> index 7a79f346250a..12d038ef5f2e 100644
>> --- a/drivers/dma/sun6i-dma.c
>> +++ b/drivers/dma/sun6i-dma.c
>> @@ -946,16 +946,14 @@ static int sun6i_dma_terminate_all(struct dma_chan *chan)
>>
>> spin_lock_irqsave(&vchan->vc.lock, flags);
>>
>> - if (vchan->cyclic) {
>> - vchan->cyclic = false;
>> - if (pchan && pchan->desc) {
>> - struct virt_dma_desc *vd = &pchan->desc->vd;
>> - struct virt_dma_chan *vc = &vchan->vc;
>> + if (pchan && pchan->desc && pchan->desc != pchan->done) {
>> + struct virt_dma_desc *vd = &pchan->desc->vd;
>> + struct virt_dma_chan *vc = &vchan->vc;
>>
>> - list_add_tail(&vd->node, &vc->desc_completed);
>> - }
>> + list_add_tail(&vd->node, &vc->desc_completed);
> should It be in desc_terminated queue?
>
> ref: https://lore.kernel.org/dmaengine/ajETw7uwVx_U9o5F@ryzen/T/#m541c24b45fb425c6a8a81d800db225b58411447e
>
> Frank
>> }
>>
>> + vchan->cyclic = false;
>> vchan_get_all_descriptors(&vchan->vc, &head);
>>
>> if (pchan) {
>> --
>> 2.25.1
>>
^ permalink raw reply
* Re: [PATCH v2 01/11] ASoC: fsl_asrc: Use guard() for spin locks
From: Bui Duc Phuc @ 2026-06-17 2:25 UTC (permalink / raw)
To: Frank Li
Cc: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Shengjiu Wang, Xiubo Li, Frank Li, Fabio Estevam, Nicolin Chen,
Sascha Hauer, Pengutronix Kernel Team, linux-sound, linux-kernel,
linux-arm-kernel, imx, linuxppc-dev
In-Reply-To: <ajAJt-EV1sSfG3OC@SMW015318>
Hi Frank,
>
> Reviewed-by: Frank Li <Frank.Li@nxp.com>
>
Thank you for taking the time to review the series and for providing
the Reviewed-by tags.
Best regards,
Phuc
^ permalink raw reply
* [PATCH 1/5] ARM: dts: mediatek: mt8127: Fix indentation error
From: Zakariya Hadrami via B4 Relay @ 2026-06-17 2:20 UTC (permalink / raw)
To: Matthias Brugger, AngeloGioacchino Del Regno, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sean Wang, Wim Van Sebroeck,
Guenter Roeck
Cc: linux-kernel, linux-arm-kernel, linux-mediatek, devicetree,
linux-watchdog, Zakariya Hadrami
In-Reply-To: <20260617-mt8127-amazon-ford-basic-v1-0-d02ad15ac359@proton.me>
From: Zakariya Hadrami <zkh1@proton.me>
Fix an indentation error caused by a space at the start of a line.
Signed-off-by: Zakariya Hadrami <zkh1@proton.me>
---
arch/arm/boot/dts/mediatek/mt8127.dtsi | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/mediatek/mt8127.dtsi b/arch/arm/boot/dts/mediatek/mt8127.dtsi
index aced173c2a52..bd61ec7e70c0 100644
--- a/arch/arm/boot/dts/mediatek/mt8127.dtsi
+++ b/arch/arm/boot/dts/mediatek/mt8127.dtsi
@@ -75,7 +75,7 @@ uart_clk: dummy26m {
compatible = "fixed-clock";
clock-frequency = <26000000>;
#clock-cells = <0>;
- };
+ };
};
timer {
--
2.54.0
^ permalink raw reply related
* [PATCH 2/5] ARM: dts: mediatek: mt8127: Add watchdog support
From: Zakariya Hadrami via B4 Relay @ 2026-06-17 2:20 UTC (permalink / raw)
To: Matthias Brugger, AngeloGioacchino Del Regno, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sean Wang, Wim Van Sebroeck,
Guenter Roeck
Cc: linux-kernel, linux-arm-kernel, linux-mediatek, devicetree,
linux-watchdog, Zakariya Hadrami
In-Reply-To: <20260617-mt8127-amazon-ford-basic-v1-0-d02ad15ac359@proton.me>
From: Zakariya Hadrami <zkh1@proton.me>
Add watchdog node and disable it by default as it was not present
initially.
Signed-off-by: Zakariya Hadrami <zkh1@proton.me>
---
arch/arm/boot/dts/mediatek/mt8127.dtsi | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/arch/arm/boot/dts/mediatek/mt8127.dtsi b/arch/arm/boot/dts/mediatek/mt8127.dtsi
index bd61ec7e70c0..1855dda42710 100644
--- a/arch/arm/boot/dts/mediatek/mt8127.dtsi
+++ b/arch/arm/boot/dts/mediatek/mt8127.dtsi
@@ -159,5 +159,12 @@ uart3: serial@11005000 {
clocks = <&uart_clk>;
status = "disabled";
};
+
+ watchdog: watchdog@10007000 {
+ compatible = "mediatek,mt8127-wdt","mediatek,mt6589-wdt";
+ reg = <0 0x10007000 0 0x100>;
+ interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_LOW>;
+ status = "disabled";
+ };
};
};
--
2.54.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox