* Re: [PATCH v2 0/3] drivers/perf: hisi: Updates for HiSilicon uncore PMUs
From: Yushan Wang @ 2026-06-12 9:35 UTC (permalink / raw)
To: will, mark.rutland, robin.murphy, linux-arm-kernel, linux-kernel
Cc: fanghao11, linuxarm, liuyonglong, prime.zeng, wangzhou1
In-Reply-To: <20260612093207.1242000-1-wangyushan12@huawei.com>
There are some issues with patch 1, please ignore this, sorry.
On 6/12/2026 5:32 PM, Yushan Wang wrote:
> This patchset added support of ITS PMU, and new version of MN PMU.
>
> ITS PMU supports counting number and latency of interrupts by
> catagory, and statistics of micro-ops of ITS.
>
> The new version of MN PMU added cycles event, to be used for MN
> metric computing.
>
> Changes:
> v2:
> - Added int_en filter to tell if int_id is used, enabling filtering
> interrupt with 0 int_id per Sashiko.
> - Changed event format width to align with register width per Sashiko.
> Link to v1: https://lore.kernel.org/all/20260423152959.1458563-1-wangyushan12@huawei.com/
> Link to Sashiko review report: https://sashiko.dev/#/patchset/20260423152959.1458563-1-wangyushan12%40huawei.com
>
> Yifan Wu (1):
> drivers/perf: hisi: Add new function for HiSilicon MN PMU driver
>
> Yushan Wang (2):
> drivers/perf: hisi: Replace counter number with defined macro
> drivers/perf: hisi: Support uncore ITS PMU
>
> Documentation/admin-guide/perf/hisi-pmu.rst | 12 +
> drivers/perf/hisilicon/Makefile | 2 +-
> drivers/perf/hisilicon/hisi_uncore_its_pmu.c | 375 +++++++++++++++++++
> drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c | 2 +-
> drivers/perf/hisilicon/hisi_uncore_mn_pmu.c | 61 ++-
> 5 files changed, 444 insertions(+), 8 deletions(-)
> create mode 100644 drivers/perf/hisilicon/hisi_uncore_its_pmu.c
>
^ permalink raw reply
* [PATCH v2 1/3] drivers/perf: hisi: Replace counter number with defined macro
From: Yushan Wang @ 2026-06-12 9:32 UTC (permalink / raw)
To: will, mark.rutland, robin.murphy, linux-arm-kernel, linux-kernel
Cc: fanghao11, linuxarm, liuyonglong, prime.zeng, wangzhou1,
wangyushan12
In-Reply-To: <20260612093207.1242000-1-wangyushan12@huawei.com>
The inline number means counter numbers of the PMU. Replace it with
already define macro for better readability.
Signed-off-by: Yushan Wang <wangyushan12@huawei.com>
---
drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
index f963e4f9e552..59e6dff4032f 100644
--- a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
@@ -362,7 +362,7 @@ static int hisi_l3c_pmu_check_filter(struct perf_event *event)
*/
static u32 hisi_l3c_pmu_get_counter_offset(int cntr_idx)
{
- return L3C_CNTR0_LOWER + L3C_HW_IDX(cntr_idx) * 8;
+ return L3C_CNTR0_LOWER + L3C_HW_IDX(cntr_idx) * L3C_NR_COUNTERS;
}
static u64 hisi_l3c_pmu_read_counter(struct hisi_pmu *l3c_pmu,
--
2.33.0
^ permalink raw reply related
* [PATCH v2 0/3] drivers/perf: hisi: Updates for HiSilicon uncore PMUs
From: Yushan Wang @ 2026-06-12 9:32 UTC (permalink / raw)
To: will, mark.rutland, robin.murphy, linux-arm-kernel, linux-kernel
Cc: fanghao11, linuxarm, liuyonglong, prime.zeng, wangzhou1,
wangyushan12
This patchset added support of ITS PMU, and new version of MN PMU.
ITS PMU supports counting number and latency of interrupts by
catagory, and statistics of micro-ops of ITS.
The new version of MN PMU added cycles event, to be used for MN
metric computing.
Changes:
v2:
- Added int_en filter to tell if int_id is used, enabling filtering
interrupt with 0 int_id per Sashiko.
- Changed event format width to align with register width per Sashiko.
Link to v1: https://lore.kernel.org/all/20260423152959.1458563-1-wangyushan12@huawei.com/
Link to Sashiko review report: https://sashiko.dev/#/patchset/20260423152959.1458563-1-wangyushan12%40huawei.com
Yifan Wu (1):
drivers/perf: hisi: Add new function for HiSilicon MN PMU driver
Yushan Wang (2):
drivers/perf: hisi: Replace counter number with defined macro
drivers/perf: hisi: Support uncore ITS PMU
Documentation/admin-guide/perf/hisi-pmu.rst | 12 +
drivers/perf/hisilicon/Makefile | 2 +-
drivers/perf/hisilicon/hisi_uncore_its_pmu.c | 375 +++++++++++++++++++
drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c | 2 +-
drivers/perf/hisilicon/hisi_uncore_mn_pmu.c | 61 ++-
5 files changed, 444 insertions(+), 8 deletions(-)
create mode 100644 drivers/perf/hisilicon/hisi_uncore_its_pmu.c
--
2.33.0
^ permalink raw reply
* [PATCH v2 2/3] drivers/perf: hisi: Support uncore ITS PMU
From: Yushan Wang @ 2026-06-12 9:32 UTC (permalink / raw)
To: will, mark.rutland, robin.murphy, linux-arm-kernel, linux-kernel
Cc: fanghao11, linuxarm, liuyonglong, prime.zeng, wangzhou1,
wangyushan12
In-Reply-To: <20260612093207.1242000-1-wangyushan12@huawei.com>
Support uncore ITS PMU, which provides the capability of counting
the number of interrupts routed to ITS by interrupt catagories, and the
latency. It also supports collecting statistics of micro-ops of ITS.
The driver adapts to HiSilicon uncore PMU framework. It does not support
overflow interruption, which is the same as NoC PMU, so a few dummy
functions or handling interrupts are left empty.
Signed-off-by: Yushan Wang <wangyushan12@huawei.com>
---
Documentation/admin-guide/perf/hisi-pmu.rst | 12 +
drivers/perf/hisilicon/Makefile | 2 +-
drivers/perf/hisilicon/hisi_uncore_its_pmu.c | 375 +++++++++++++++++++
3 files changed, 388 insertions(+), 1 deletion(-)
create mode 100644 drivers/perf/hisilicon/hisi_uncore_its_pmu.c
diff --git a/Documentation/admin-guide/perf/hisi-pmu.rst b/Documentation/admin-guide/perf/hisi-pmu.rst
index d56b2d690709..b2b79be998f9 100644
--- a/Documentation/admin-guide/perf/hisi-pmu.rst
+++ b/Documentation/admin-guide/perf/hisi-pmu.rst
@@ -128,6 +128,18 @@ channel with this option. The current supported channels are as follows:
7. tt_en: NoC PMU supports counting only transactions that have tracetag set
if this option is set. See the 2nd list for more information about tracetag.
+8. int_id: ITS PMU supports filtering by interrupt id, which is defined by
+hardware. Interrupt id takes up to 32 bits, and can be divided into 2 parts:
+
+- Upper 16 bits: DeviceID if counting LPI, PEID if counting SGI/PPI.
+- Lower 16 bits: EventID if counting LPI, IntID if counting SGI/PPI.
+
+int_id is a global configuration for each PMU instance, if multiple different
+int_id's are specified, the last came in will be effective.
+
+9. int_en: A one-bit flag to tell if int_id is used to filter the statistics. It
+allows filtering 0 DeviceID and EventID.
+
For HiSilicon uncore PMU v3 whose identifier is 0x40, some uncore PMUs are
further divided into parts for finer granularity of tracing, each part has its
own dedicated PMU, and all such PMUs together cover the monitoring job of events
diff --git a/drivers/perf/hisilicon/Makefile b/drivers/perf/hisilicon/Makefile
index 186be3d02238..5f28cfdb8a72 100644
--- a/drivers/perf/hisilicon/Makefile
+++ b/drivers/perf/hisilicon/Makefile
@@ -2,7 +2,7 @@
obj-$(CONFIG_HISI_PMU) += hisi_uncore_pmu.o hisi_uncore_l3c_pmu.o \
hisi_uncore_hha_pmu.o hisi_uncore_ddrc_pmu.o hisi_uncore_sllc_pmu.o \
hisi_uncore_pa_pmu.o hisi_uncore_cpa_pmu.o hisi_uncore_uc_pmu.o \
- hisi_uncore_noc_pmu.o hisi_uncore_mn_pmu.o
+ hisi_uncore_noc_pmu.o hisi_uncore_mn_pmu.o hisi_uncore_its_pmu.o
obj-$(CONFIG_HISI_PCIE_PMU) += hisi_pcie_pmu.o
obj-$(CONFIG_HNS3_PMU) += hns3_pmu.o
diff --git a/drivers/perf/hisilicon/hisi_uncore_its_pmu.c b/drivers/perf/hisilicon/hisi_uncore_its_pmu.c
new file mode 100644
index 000000000000..3d1316ee12ef
--- /dev/null
+++ b/drivers/perf/hisilicon/hisi_uncore_its_pmu.c
@@ -0,0 +1,375 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for HiSilicon Uncore ITS PMU device
+ *
+ * Copyright (c) 2026 HiSilicon Technologies Co., Ltd.
+ * Author: Yushan Wang <wangyushan12@huawei.com>
+ */
+#include <linux/bitops.h>
+#include <linux/cpuhotplug.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/sysfs.h>
+
+#include "hisi_uncore_pmu.h"
+
+#define ITS_PMU_VERSION 0x21000
+#define ITS_PMU_GLOBAL_CTRL 0x21004
+#define ITS_PMU_GLOBAL_CTRL_PMU_EN BIT(0)
+#define ITS_PMU_COUNTER_CTRL 0x21008
+#define ITS_PMU_EVENT_CTRL 0x2100c
+#define ITS_PMU_COUNTER0 0x21010
+
+#define ITS_PMU_INT_ID_MASK 0x20008
+#define ITS_PMU_INT_ID_CTRL 0x20084
+
+#define ITS_PMU_NR_COUNTERS 4
+
+#define ITS_PMU_EVENT_CNTRn(cntr0, n) ((cntr0) + 8 * (n))
+#define ITS_PMU_CNTR_CTRL_MASK(n) GENMASK(8 * ((n) + 1) - 1, 8 * (n))
+#define ITS_PMU_CNTR_EVENT_CFG(n, e) ((e) << ((n) * 8))
+#define ITS_PMU_EVENT_CTRL_TYPE GENMASK(12, 0)
+
+HISI_PMU_EVENT_ATTR_EXTRACTOR(int_id, config1, 31, 0);
+HISI_PMU_EVENT_ATTR_EXTRACTOR(int_en, config1, 32, 32);
+
+/* Dynamic CPU hotplug state used by this PMU driver */
+static enum cpuhp_state hisi_its_pmu_cpuhp_state;
+
+struct hisi_its_pmu_regs {
+ u32 version;
+ u32 pmu_ctrl;
+ u32 event_ctrl0;
+ u32 event_cntr0;
+ u32 cntr_ctrl;
+};
+
+static void hisi_its_pmu_write_evtype(struct hisi_pmu *its_pmu, int idx, u32 type)
+{
+ struct hisi_its_pmu_regs *reg_info = its_pmu->dev_info->private;
+ u32 reg;
+
+ reg = readl(its_pmu->base + reg_info->event_ctrl0);
+ reg &= ~ITS_PMU_CNTR_CTRL_MASK(idx);
+ reg |= ITS_PMU_CNTR_EVENT_CFG(idx, type);
+ writel(reg, its_pmu->base + reg_info->event_ctrl0);
+}
+
+static u64 hisi_its_pmu_read_counter(struct hisi_pmu *its_pmu,
+ struct hw_perf_event *hwc)
+{
+ struct hisi_its_pmu_regs *reg_info = its_pmu->dev_info->private;
+
+ return readq(its_pmu->base + ITS_PMU_EVENT_CNTRn(reg_info->event_cntr0, hwc->idx));
+}
+
+static void hisi_its_pmu_write_counter(struct hisi_pmu *its_pmu,
+ struct hw_perf_event *hwc, u64 val)
+{
+ struct hisi_its_pmu_regs *reg_info = its_pmu->dev_info->private;
+
+ writeq(val, its_pmu->base + ITS_PMU_EVENT_CNTRn(reg_info->event_cntr0, hwc->idx));
+}
+
+static void hisi_its_pmu_enable_counter(struct hisi_pmu *its_pmu,
+ struct hw_perf_event *hwc)
+{
+ struct hisi_its_pmu_regs *reg_info = its_pmu->dev_info->private;
+ u32 reg;
+
+ reg = readl(its_pmu->base + reg_info->cntr_ctrl);
+ reg |= BIT(hwc->idx);
+ writel(reg, its_pmu->base + reg_info->cntr_ctrl);
+}
+
+static void hisi_its_pmu_disable_counter(struct hisi_pmu *its_pmu,
+ struct hw_perf_event *hwc)
+{
+ struct hisi_its_pmu_regs *reg_info = its_pmu->dev_info->private;
+ u32 reg;
+
+ reg = readl(its_pmu->base + reg_info->cntr_ctrl);
+ reg &= ~BIT(hwc->idx);
+ writel(reg, its_pmu->base + reg_info->cntr_ctrl);
+}
+
+static void hisi_its_pmu_enable_counter_int(struct hisi_pmu *its_pmu,
+ struct hw_perf_event *hwc)
+{
+ /* We don't support interrupt, so a stub here. */
+}
+
+static void hisi_its_pmu_disable_counter_int(struct hisi_pmu *its_pmu,
+ struct hw_perf_event *hwc)
+{
+}
+
+static void hisi_its_pmu_start_counters(struct hisi_pmu *its_pmu)
+{
+ struct hisi_its_pmu_regs *reg_info = its_pmu->dev_info->private;
+ u32 reg;
+
+ reg = readl(its_pmu->base + reg_info->pmu_ctrl);
+ reg |= ITS_PMU_GLOBAL_CTRL_PMU_EN;
+ writel(reg, its_pmu->base + reg_info->pmu_ctrl);
+}
+
+static void hisi_its_pmu_stop_counters(struct hisi_pmu *its_pmu)
+{
+ struct hisi_its_pmu_regs *reg_info = its_pmu->dev_info->private;
+ u32 reg;
+
+ reg = readl(its_pmu->base + reg_info->pmu_ctrl);
+ reg &= ~ITS_PMU_GLOBAL_CTRL_PMU_EN;
+ writel(reg, its_pmu->base + reg_info->pmu_ctrl);
+}
+
+static void hisi_its_pmu_enable_filter(struct perf_event *event)
+{
+ struct hisi_pmu *its_pmu = to_hisi_pmu(event->pmu);
+ u32 int_id = hisi_get_int_id(event);
+ u32 int_en = hisi_get_int_en(event);
+
+ /*
+ * Don't touch global filtering config if user doesn't
+ * explicitly specify it.
+ */
+ if (int_en) {
+ writel(int_id, its_pmu->base + ITS_PMU_INT_ID_CTRL);
+ /* Write 0 to this register to enable filtering with int_id. */
+ writel(0, its_pmu->base + ITS_PMU_INT_ID_MASK);
+ } else {
+ writel(-1U, its_pmu->base + ITS_PMU_INT_ID_MASK);
+ }
+}
+
+static void hisi_its_pmu_disable_filter(struct perf_event *event)
+{
+ struct hisi_pmu *its_pmu = to_hisi_pmu(event->pmu);
+ u32 int_en = hisi_get_int_en(event);
+
+ /* Don't touch global filtering config if this is not the last counter. */
+ if (bitmap_weight(its_pmu->pmu_events.used_mask, its_pmu->num_counters) > 1)
+ return;
+
+ if (int_en) {
+ writel(0, its_pmu->base + ITS_PMU_INT_ID_CTRL);
+ writel(-1U, its_pmu->base + ITS_PMU_INT_ID_MASK);
+ }
+}
+
+static const struct hisi_uncore_ops hisi_uncore_its_ops = {
+ .write_evtype = hisi_its_pmu_write_evtype,
+ .get_event_idx = hisi_uncore_pmu_get_event_idx,
+ .read_counter = hisi_its_pmu_read_counter,
+ .write_counter = hisi_its_pmu_write_counter,
+ .enable_counter = hisi_its_pmu_enable_counter,
+ .disable_counter = hisi_its_pmu_disable_counter,
+ .enable_counter_int = hisi_its_pmu_enable_counter_int,
+ .disable_counter_int = hisi_its_pmu_disable_counter_int,
+ .start_counters = hisi_its_pmu_start_counters,
+ .stop_counters = hisi_its_pmu_stop_counters,
+ .enable_filter = hisi_its_pmu_enable_filter,
+ .disable_filter = hisi_its_pmu_disable_filter,
+};
+
+static struct attribute *hisi_its_pmu_format_attrs[] = {
+ HISI_PMU_FORMAT_ATTR(event, "config:0-7"),
+ HISI_PMU_FORMAT_ATTR(int_id, "config1:0-31"),
+ HISI_PMU_FORMAT_ATTR(int_en, "config1:32-32"),
+ NULL
+};
+
+static const struct attribute_group hisi_its_pmu_format_group = {
+ .name = "format",
+ .attrs = hisi_its_pmu_format_attrs,
+};
+
+static struct attribute *hisi_its_pmu_events_attrs[] = {
+ HISI_PMU_EVENT_ATTR(lpi_num, 0xc0),
+ HISI_PMU_EVENT_ATTR(lpi_time, 0x80),
+ HISI_PMU_EVENT_ATTR(sgi_num, 0xc1),
+ HISI_PMU_EVENT_ATTR(sgi_time, 0x81),
+ HISI_PMU_EVENT_ATTR(ppi_num, 0xc2),
+ HISI_PMU_EVENT_ATTR(ppi_time, 0x82),
+ HISI_PMU_EVENT_ATTR(sl3_lpi_num, 0xc3),
+ HISI_PMU_EVENT_ATTR(sl3_sgi_num, 0xc4),
+ HISI_PMU_EVENT_ATTR(sl3_ppi_num, 0xc5),
+ HISI_PMU_EVENT_ATTR(sl0_ddr_read, 0xc9),
+ HISI_PMU_EVENT_ATTR(sl0_ddr_time, 0x89),
+ HISI_PMU_EVENT_ATTR(sl1_ddr_read, 0xca),
+ HISI_PMU_EVENT_ATTR(sl1_ddr_time, 0x8a),
+ HISI_PMU_EVENT_ATTR(sl2_ddr_read, 0xcb),
+ HISI_PMU_EVENT_ATTR(sl2_ddr_time, 0x8b),
+ HISI_PMU_EVENT_ATTR(cycles, 0xcc),
+ NULL
+};
+
+static const struct attribute_group hisi_its_pmu_events_group = {
+ .name = "events",
+ .attrs = hisi_its_pmu_events_attrs,
+};
+
+static const struct attribute_group *hisi_its_pmu_attr_groups[] = {
+ &hisi_its_pmu_format_group,
+ &hisi_its_pmu_events_group,
+ &hisi_pmu_cpumask_attr_group,
+ &hisi_pmu_identifier_group,
+ NULL
+};
+
+static int hisi_its_pmu_dev_init(struct platform_device *pdev, struct hisi_pmu *its_pmu)
+{
+ struct hisi_its_pmu_regs *reg_info;
+
+ hisi_uncore_pmu_init_topology(its_pmu, &pdev->dev);
+
+ if (its_pmu->topo.scl_id < 0)
+ return dev_err_probe(&pdev->dev, -EINVAL, "failed to get scl-id\n");
+
+ if (its_pmu->topo.index_id < 0)
+ return dev_err_probe(&pdev->dev, -EINVAL, "failed to get idx-id\n");
+
+ its_pmu->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(its_pmu->base))
+ return dev_err_probe(&pdev->dev, PTR_ERR(its_pmu->base),
+ "fail to remap io memory\n");
+
+ its_pmu->dev_info = device_get_match_data(&pdev->dev);
+ if (!its_pmu->dev_info)
+ return -ENODEV;
+
+ its_pmu->pmu_events.attr_groups = its_pmu->dev_info->attr_groups;
+ its_pmu->counter_bits = its_pmu->dev_info->counter_bits;
+ its_pmu->check_event = its_pmu->dev_info->check_event;
+ its_pmu->num_counters = ITS_PMU_NR_COUNTERS;
+ its_pmu->ops = &hisi_uncore_its_ops;
+ its_pmu->dev = &pdev->dev;
+ its_pmu->on_cpu = -1;
+
+ reg_info = its_pmu->dev_info->private;
+ its_pmu->identifier = readl(its_pmu->base + reg_info->version);
+
+ return 0;
+}
+
+static void hisi_its_pmu_remove_cpuhp_instance(void *hotplug_node)
+{
+ cpuhp_state_remove_instance_nocalls(hisi_its_pmu_cpuhp_state, hotplug_node);
+}
+
+static void hisi_its_pmu_unregister_pmu(void *pmu)
+{
+ perf_pmu_unregister(pmu);
+}
+
+static int hisi_its_pmu_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct hisi_pmu *its_pmu;
+ char *name;
+ int ret;
+
+ its_pmu = devm_kzalloc(dev, sizeof(*its_pmu), GFP_KERNEL);
+ if (!its_pmu)
+ return -ENOMEM;
+
+ /*
+ * HiSilicon Uncore PMU framework needs to get common hisi_pmu device
+ * from device's drvdata.
+ */
+ platform_set_drvdata(pdev, its_pmu);
+
+ ret = hisi_its_pmu_dev_init(pdev, its_pmu);
+ if (ret)
+ return ret;
+
+ ret = cpuhp_state_add_instance(hisi_its_pmu_cpuhp_state, &its_pmu->node);
+ if (ret)
+ return dev_err_probe(dev, ret, "Fail to register cpuhp instance\n");
+
+ ret = devm_add_action_or_reset(dev, hisi_its_pmu_remove_cpuhp_instance,
+ &its_pmu->node);
+ if (ret)
+ return ret;
+
+ hisi_pmu_init(its_pmu, THIS_MODULE);
+
+ name = devm_kasprintf(dev, GFP_KERNEL, "hisi_scl%d_its%d",
+ its_pmu->topo.scl_id, its_pmu->topo.index_id);
+ if (!name)
+ return -ENOMEM;
+
+ ret = perf_pmu_register(&its_pmu->pmu, name, -1);
+ if (ret)
+ return dev_err_probe(dev, ret, "Fail to register PMU\n");
+
+ return devm_add_action_or_reset(dev, hisi_its_pmu_unregister_pmu,
+ &its_pmu->pmu);
+}
+
+static struct hisi_its_pmu_regs hisi_its_v1_pmu_regs = {
+ .version = ITS_PMU_VERSION,
+ .pmu_ctrl = ITS_PMU_GLOBAL_CTRL,
+ .event_ctrl0 = ITS_PMU_EVENT_CTRL,
+ .event_cntr0 = ITS_PMU_COUNTER0,
+ .cntr_ctrl = ITS_PMU_COUNTER_CTRL,
+};
+
+static const struct hisi_pmu_dev_info hisi_its_v1 = {
+ .attr_groups = hisi_its_pmu_attr_groups,
+ .counter_bits = 48,
+ .check_event = ITS_PMU_EVENT_CTRL_TYPE,
+ .private = &hisi_its_v1_pmu_regs,
+};
+
+static const struct acpi_device_id hisi_its_pmu_ids[] = {
+ { "HISI0591", (kernel_ulong_t) &hisi_its_v1 },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, hisi_its_pmu_ids);
+
+static struct platform_driver hisi_its_pmu_driver = {
+ .driver = {
+ .name = "hisi_its_pmu",
+ .acpi_match_table = hisi_its_pmu_ids,
+ .suppress_bind_attrs = true,
+ },
+ .probe = hisi_its_pmu_probe,
+};
+
+static int __init hisi_its_pmu_module_init(void)
+{
+ int ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN,
+ "perf/hisi/its:online",
+ hisi_uncore_pmu_online_cpu,
+ hisi_uncore_pmu_offline_cpu);
+ if (ret < 0) {
+ pr_err("hisi_its_pmu: Fail to setup cpuhp callbacks, ret = %d\n", ret);
+ return ret;
+ }
+ hisi_its_pmu_cpuhp_state = ret;
+
+ ret = platform_driver_register(&hisi_its_pmu_driver);
+ if (ret)
+ cpuhp_remove_multi_state(hisi_its_pmu_cpuhp_state);
+
+ return ret;
+}
+module_init(hisi_its_pmu_module_init);
+
+static void __exit hisi_its_pmu_module_exit(void)
+{
+ platform_driver_unregister(&hisi_its_pmu_driver);
+ cpuhp_remove_multi_state(hisi_its_pmu_cpuhp_state);
+}
+module_exit(hisi_its_pmu_module_exit);
+
+MODULE_IMPORT_NS("HISI_PMU");
+MODULE_DESCRIPTION("HiSilicon SoC Uncore ITS PMU driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Yushan Wang <wangyushan12@huawei.com>");
--
2.33.0
^ permalink raw reply related
* [PATCH v2 3/3] drivers/perf: hisi: Add new function for HiSilicon MN PMU driver
From: Yushan Wang @ 2026-06-12 9:32 UTC (permalink / raw)
To: will, mark.rutland, robin.murphy, linux-arm-kernel, linux-kernel
Cc: fanghao11, linuxarm, liuyonglong, prime.zeng, wangzhou1,
wangyushan12
In-Reply-To: <20260612093207.1242000-1-wangyushan12@huawei.com>
From: Yifan Wu <wuyifan50@huawei.com>
MN (Miscellaneous Node) is a hybrid node in ARM CHI. The MN PMU driver
using the HiSilicon uncore PMU framework.
On HiSilicon HIP13 platform, cycle event is supported on MN PMU. The
cycle event is exposed directly in driver and some variables shall be
added suffix to distinguish the version.
Signed-off-by: Yifan Wu <wuyifan50@huawei.com>
Signed-off-by: Yushan Wang <wangyushan12@huawei.com>
---
drivers/perf/hisilicon/hisi_uncore_mn_pmu.c | 61 +++++++++++++++++++--
1 file changed, 55 insertions(+), 6 deletions(-)
diff --git a/drivers/perf/hisilicon/hisi_uncore_mn_pmu.c b/drivers/perf/hisilicon/hisi_uncore_mn_pmu.c
index 4df4eebe243e..cdd5a1591408 100644
--- a/drivers/perf/hisilicon/hisi_uncore_mn_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_mn_pmu.c
@@ -192,7 +192,7 @@ static const struct attribute_group hisi_mn_pmu_format_group = {
.attrs = hisi_mn_pmu_format_attr,
};
-static struct attribute *hisi_mn_pmu_events_attr[] = {
+static struct attribute *hisi_mn_pmu_events_attr_v1[] = {
HISI_PMU_EVENT_ATTR(req_eobarrier_num, 0x00),
HISI_PMU_EVENT_ATTR(req_ecbarrier_num, 0x01),
HISI_PMU_EVENT_ATTR(req_dvmop_num, 0x02),
@@ -219,14 +219,55 @@ static struct attribute *hisi_mn_pmu_events_attr[] = {
NULL
};
-static const struct attribute_group hisi_mn_pmu_events_group = {
+static const struct attribute_group hisi_mn_pmu_events_group_v1 = {
.name = "events",
- .attrs = hisi_mn_pmu_events_attr,
+ .attrs = hisi_mn_pmu_events_attr_v1,
};
-static const struct attribute_group *hisi_mn_pmu_attr_groups[] = {
+static const struct attribute_group *hisi_mn_pmu_attr_groups_v1[] = {
&hisi_mn_pmu_format_group,
- &hisi_mn_pmu_events_group,
+ &hisi_mn_pmu_events_group_v1,
+ &hisi_pmu_cpumask_attr_group,
+ &hisi_pmu_identifier_group,
+ NULL
+};
+
+static struct attribute *hisi_mn_pmu_events_attr_v2[] = {
+ HISI_PMU_EVENT_ATTR(req_eobarrier_num, 0x00),
+ HISI_PMU_EVENT_ATTR(req_ecbarrier_num, 0x01),
+ HISI_PMU_EVENT_ATTR(req_dvmop_num, 0x02),
+ HISI_PMU_EVENT_ATTR(req_dvmsync_num, 0x03),
+ HISI_PMU_EVENT_ATTR(req_retry_num, 0x04),
+ HISI_PMU_EVENT_ATTR(req_writenosnp_num, 0x05),
+ HISI_PMU_EVENT_ATTR(req_readnosnp_num, 0x06),
+ HISI_PMU_EVENT_ATTR(snp_dvm_num, 0x07),
+ HISI_PMU_EVENT_ATTR(snp_dvmsync_num, 0x08),
+ HISI_PMU_EVENT_ATTR(l3t_req_dvm_num, 0x09),
+ HISI_PMU_EVENT_ATTR(l3t_req_dvmsync_num, 0x0A),
+ HISI_PMU_EVENT_ATTR(mn_req_dvm_num, 0x0B),
+ HISI_PMU_EVENT_ATTR(mn_req_dvmsync_num, 0x0C),
+ HISI_PMU_EVENT_ATTR(pa_req_dvm_num, 0x0D),
+ HISI_PMU_EVENT_ATTR(pa_req_dvmsync_num, 0x0E),
+ HISI_PMU_EVENT_ATTR(cycles, 0x0F),
+ HISI_PMU_EVENT_ATTR(snp_dvm_latency, 0x80),
+ HISI_PMU_EVENT_ATTR(snp_dvmsync_latency, 0x81),
+ HISI_PMU_EVENT_ATTR(l3t_req_dvm_latency, 0x82),
+ HISI_PMU_EVENT_ATTR(l3t_req_dvmsync_latency, 0x83),
+ HISI_PMU_EVENT_ATTR(mn_req_dvm_latency, 0x84),
+ HISI_PMU_EVENT_ATTR(mn_req_dvmsync_latency, 0x85),
+ HISI_PMU_EVENT_ATTR(pa_req_dvm_latency, 0x86),
+ HISI_PMU_EVENT_ATTR(pa_req_dvmsync_latency, 0x87),
+ NULL
+};
+
+static const struct attribute_group hisi_mn_pmu_events_group_v2 = {
+ .name = "events",
+ .attrs = hisi_mn_pmu_events_attr_v2,
+};
+
+static const struct attribute_group *hisi_mn_pmu_attr_groups_v2[] = {
+ &hisi_mn_pmu_format_group,
+ &hisi_mn_pmu_events_group_v2,
&hisi_pmu_cpumask_attr_group,
&hisi_pmu_identifier_group,
NULL
@@ -351,7 +392,14 @@ static struct hisi_mn_pmu_regs hisi_mn_v1_pmu_regs = {
};
static const struct hisi_pmu_dev_info hisi_mn_v1 = {
- .attr_groups = hisi_mn_pmu_attr_groups,
+ .attr_groups = hisi_mn_pmu_attr_groups_v1,
+ .counter_bits = 48,
+ .check_event = HISI_MN_EVTYPE_MASK,
+ .private = &hisi_mn_v1_pmu_regs,
+};
+
+static const struct hisi_pmu_dev_info hisi_mn_v2 = {
+ .attr_groups = hisi_mn_pmu_attr_groups_v2,
.counter_bits = 48,
.check_event = HISI_MN_EVTYPE_MASK,
.private = &hisi_mn_v1_pmu_regs,
@@ -359,6 +407,7 @@ static const struct hisi_pmu_dev_info hisi_mn_v1 = {
static const struct acpi_device_id hisi_mn_pmu_acpi_match[] = {
{ "HISI0222", (kernel_ulong_t) &hisi_mn_v1 },
+ { "HISI0224", (kernel_ulong_t) &hisi_mn_v2 },
{ }
};
MODULE_DEVICE_TABLE(acpi, hisi_mn_pmu_acpi_match);
--
2.33.0
^ permalink raw reply related
* Re: [PATCH v2 1/2] soc: aspeed: add BMC-side PCIe BMC device driver
From: Grégoire Layet @ 2026-06-12 9:21 UTC (permalink / raw)
To: Andrew Jeffery
Cc: joel, andrew, jacky_chou, yh_chung, ninad, linux-aspeed,
linux-arm-kernel, linux-kernel, anirudhsriniv
In-Reply-To: <CAFi2wKYzUDY5Gis9GaHdqeYdv-orHB+gWfLXkJBgbxfbnRgorA@mail.gmail.com>
Hello Andrew,
Anirudh Srinivasan and I have found that IPMI over KCS using the
PCI worked with the stock ASPEED bmc driver (the bmc driver in the V1)
but not with the trimmed-down version in the V2. I have apparently removed
a bit too much from the V2 , but that's not what I want to focus on.
This brings back the question of where we should put the registers
configuration,
considering that two different functionalities depend on it.
> It is also possible to put the SCU initialisation on the
> 8250_aspeed_vuart driver
> directly. This could be activated with a specific flag added to VUART nodes
> ('pcie2vuart' for example) on the DeviceTree.
Similarly to this idea, we could include have the necessary configuration in the
'kcs_bmc_aspeed' driver. This could be activated using a similar flag
,such as 'pci2lpc'
or 'pci2kcs' directly. However, this would result in a lot of code
duplication for most
of the configuration.
The issue for me is that, two drivers configuring the same registers
is not a good idea.
I don't know how to do this the proper way.
I wanted to add this information because it could influence the move to a
bmc_device driver that configures both VUART and KCS, over PCI.
This would be similar to the V2 bmc driver, and I fix the KCS bug.
Thanks,
Grégoire
^ permalink raw reply
* Re: [PATCH bpf-next v2 8/8] selftests/bpf: add tests to validate KASAN on JIT programs
From: Alexis Lothoré @ 2026-06-12 9:19 UTC (permalink / raw)
To: bot+bpf-ci, alexis.lothore, ast, daniel, andrii, martin.lau,
eddyz87, memxor, song, yonghong.song, jolsa, john.fastabend, tglx,
mingo, bp, dave.hansen, x86, hpa, shuah, mcoquelin.stm32,
alexandre.torgue, ihor.solodrai
Cc: ebpf, bastien.curutchet, thomas.petazzoni, bpf, linux-kernel,
linux-kselftest, linux-stm32, linux-arm-kernel, martin.lau, clm
In-Reply-To: <8642178be3be8efc7f19ac4a9aa37e699f2baa82cab200909b99997068c6ae7b@mail.kernel.org>
On Thu Jun 4, 2026 at 11:45 PM CEST, bot+bpf-ci wrote:
[...]
> The Sashiko AI review on the RFC v1 8/8 posting raised a concern here that
> does not seem to have been addressed in v2:
>
> https://lore.kernel.org/bpf/20260425065049.BEC63C2BCB0@smtp.kernel.org
>
> The original question was:
>
> KASAN operates in single-shot mode by default. After the first subtest
> triggers a report, will subsequent reports be suppressed, causing the
> remaining subtests to fail? Also, since BPF CI runs with panic_on_warn=1,
> will the first KASAN splat invoke check_panic_on_warn() and immediately
> panic the CI runner?
>
> KASAN runs in single-shot mode by default. mm/kasan/report.c suppresses
> reports after the first one unless kasan_multi_shot is set.
>
> This loop runs roughly 50 subtests, and each one expects a fresh KASAN
> report emitted via the JIT-inserted __asan_load/__asan_store calls that go
> through kasan_report().
>
> Under default single-shot KASAN, would the subtests after the first one see
> no report and fail the positive assertions?
>
> Separately, BPF CI runs with panic_on_warn=1 (config.ppc64el still sets
> panic_on_warn=1). Would the first KASAN splat reach check_panic_on_warn()
> and panic the runner?
>
> Nothing in v2 appears to enable kasan_multi_shot or guard against
> panic_on_warn. Was this intended to be handled somewhere?
Hoping to silence this one on the next revision: CI has been updated
separately to enable kasan_multi_shot, and so all subtests in v2
properly triggered the reports individually. The commit is lacking
documentation about this need though.
--
Alexis Lothoré, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* Re: [PATCH v2 11/16] power: sequencing: pcie-m2: Add usb and sdio targets for E-key connector
From: Chen-Yu Tsai @ 2026-06-12 9:17 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Bartosz Golaszewski, Greg Kroah-Hartman, Daniel Scally,
Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno, Alan Stern,
linux-acpi, driver-core, linux-pm, linux-usb, devicetree,
linux-mediatek, linux-arm-kernel, linux-kernel,
Manivannan Sadhasivam
In-Reply-To: <ail2VcubjT7HNGUC@ashevche-desk.local>
On Wed, Jun 10, 2026 at 11:36 PM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> On Wed, Jun 10, 2026 at 04:40:45PM +0800, Chen-Yu Tsai wrote:
> > The M.2 E-key connector allows either PCIe or SDIO for WiFi and USB or
> > UART for BT. Currently the driver only supports PCIe and UART.
> >
> > Add power sequencing targets for SDIO and USB. To avoid adding a
> > complicated dependency tree, rename the existing power sequencing units
> > "pcie" and "uart" to "wifi" and "bt". The existing target names are left
> > untouched. The new "sdio" and "usb" targets just point to the renamed
> > "wifi" and "bt" units.
>
> Why can we do that? No breakage? Only internal names? No ABI affected?
> Please, clarify all this in the commit message.
Will do.
In short, the target names (which are not modified) are used by the
consumer, while the unit names are internal only.
ChenYu
^ permalink raw reply
* Re: [PATCH net-next v2] net: airoha: Add TCP LRO support
From: Lorenzo Bianconi @ 2026-06-12 9:15 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Alexander Lobakin, linux-arm-kernel, linux-mediatek, netdev,
Madhur Agrawal
In-Reply-To: <20260610-airoha-eth-lro-v2-1-54be99b9a2d5@kernel.org>
[-- Attachment #1: Type: text/plain, Size: 13242 bytes --]
> Add hardware TCP Large Receive Offload (LRO) support to the airoha_eth
> driver, leveraging the EN7581/AN7583 SoC's 8 dedicated LRO hardware queues
> mapped to RX queues 24–31. LRO hw offloading does not support
> Scatter-Gather (SG) so it is required to increase the page_pool allocation
> order to 2 for RX queues 24–31 (LRO queues).
> Since HW LRO is configured per-QDMA and shared across all devices using
> it, LRO is mutually exclusive with multiple active devices on the same
> QDMA block. Call netdev_update_features() on sibling devices in
> ndo_open/ndo_stop so that NETIF_F_LRO availability is re-evaluated when
> the QDMA user count changes.
commenting on sashiko's report:
https://sashiko.dev/#/patchset/20260610-airoha-eth-lro-v2-1-54be99b9a2d5%40kernel.org
>
[...]
> +static int airoha_qdma_lro_rx_process(struct sk_buff *skb,
> + struct airoha_qdma_desc *desc)
> +{
> + u32 desc_ctrl = le32_to_cpu(READ_ONCE(desc->ctrl));
> + u32 len, th_off, tcp_ack_seq, agg_count, data_off;
> + struct skb_shared_info *shinfo = skb_shinfo(skb);
> + u32 msg1 = le32_to_cpu(READ_ONCE(desc->msg1));
> + u32 msg2 = le32_to_cpu(READ_ONCE(desc->msg2));
> + u32 msg3 = le32_to_cpu(READ_ONCE(desc->msg3));
> + u16 tcp_win, l2_len;
> + struct tcphdr *th;
> + bool ipv4, ipv6;
> +
> + agg_count = FIELD_GET(QDMA_ETH_RXMSG_AGG_COUNT_MASK, msg2);
> + if (agg_count <= 1)
> + return 0;
> +
> + ipv4 = FIELD_GET(QDMA_ETH_RXMSG_IP4_MASK, msg1);
> + ipv6 = FIELD_GET(QDMA_ETH_RXMSG_IP6_MASK, msg1);
> + if (!ipv4 && !ipv6)
> + return -EOPNOTSUPP;
> +
> + l2_len = FIELD_GET(QDMA_ETH_RXMSG_L2_LEN_MASK, msg2);
> + len = FIELD_GET(QDMA_DESC_LEN_MASK, desc_ctrl);
> + if (ipv4) {
> + struct iphdr *iph, _iph;
> +
> + iph = skb_header_pointer(skb, l2_len, sizeof(*iph), &_iph);
> + if (!iph)
> + return -EINVAL;
> +
> + if (iph->protocol != IPPROTO_TCP)
> + return -EOPNOTSUPP;
> +
> + if (iph->ihl < 5)
> + return -EINVAL;
> +
> + th_off = l2_len + (iph->ihl << 2);
> + if (!pskb_may_pull(skb, th_off))
> + return -EINVAL;
> +
> + iph = (struct iphdr *)(skb->data + l2_len);
> + iph->tot_len = cpu_to_be16(len - l2_len);
> + iph->check = 0;
> + iph->check = ip_fast_csum((void *)iph, iph->ihl);
> + } else {
> + struct ipv6hdr *ip6h;
> +
> + th_off = l2_len + sizeof(*ip6h);
> + if (!pskb_may_pull(skb, th_off))
> + return -EINVAL;
> +
> + ip6h = (struct ipv6hdr *)(skb->data + l2_len);
> + if (ip6h->nexthdr != NEXTHDR_TCP)
> + return -EOPNOTSUPP;
> +
> + ip6h->payload_len = cpu_to_be16(len - th_off);
> + }
> +
> + tcp_win = FIELD_GET(QDMA_ETH_RXMSG_TCP_WIN_MASK, msg3);
> + tcp_ack_seq = le32_to_cpu(READ_ONCE(desc->data));
> +
> + if (!pskb_may_pull(skb, th_off + sizeof(*th)))
> + return -EINVAL;
> +
> + th = (struct tcphdr *)(skb->data + th_off);
- Does this code validate that the TCP header length is at least 5?
- ack, I will add it in the next revision.
> + data_off = th_off + (th->doff << 2);
> + if (len <= data_off)
> + return -EINVAL;
> +
> + th->ack_seq = cpu_to_be32(tcp_ack_seq);
> + th->window = cpu_to_be16(tcp_win);
> +
> + /* Check tcp timestamp option */
> + if (th->doff == (sizeof(*th) + TCPOLEN_TSTAMP_ALIGNED) / 4) {
> + u32 topt;
> +
> + if (!pskb_may_pull(skb, data_off))
> + return -EINVAL;
> +
> + th = (struct tcphdr *)(skb->data + th_off);
> + topt = get_unaligned_be32(th + 1);
> + if (topt == ((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
> + (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) {
> + u8 *ptr = (u8 *)th + sizeof(*th) + 2 * sizeof(__be32);
> + __le32 tcp_ts_reply = READ_ONCE(desc->tcp_ts_reply);
> +
> + put_unaligned_be32(le32_to_cpu(tcp_ts_reply), ptr);
> + }
> + }
> +
> + shinfo->gso_type = ipv4 ? SKB_GSO_TCPV4 : SKB_GSO_TCPV6;
> + shinfo->gso_size = (len - data_off) / agg_count;
> + shinfo->gso_segs = agg_count;
- Could this gso_size calculation corrupt TCP sequence numbers during
forwarding?
- The TSO in the egress NIC will perform segmentation when the device is
routing the LRO packet to the destination so the TCP sequence numbers
will be recalculated. I agree gso_size is just an estimation of the real
MSS on the first n-1 packets and we can have a suboptimal MSS size on
egress segmented traffic, but the hw does not provide this info.
- Does this LRO processing need to initialize CHECKSUM_PARTIAL metadata?
- ack, I will work on it
> +
> + return 0;
> +}
> +
> static int airoha_qdma_rx_process(struct airoha_queue *q, int budget)
> {
> enum dma_data_direction dir = page_pool_get_dma_dir(q->page_pool);
[...]
>
> +static void airoha_update_netdev_features(struct airoha_gdm_dev *dev)
> +{
> + struct airoha_eth *eth = dev->eth;
> + int i, j;
> +
> + for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
> + struct airoha_gdm_port *port = eth->ports[i];
> +
> + if (!port)
> + continue;
> +
> + for (j = 0; j < ARRAY_SIZE(port->devs); j++) {
> + struct airoha_gdm_dev *iter_dev = port->devs[j];
> + struct net_device *netdev;
> +
> + if (!iter_dev || iter_dev == dev)
> + continue;
> +
> + if (iter_dev->qdma != dev->qdma)
> + continue;
> +
> + netdev = netdev_from_priv(iter_dev);
> + if (netdev->reg_state != NETREG_REGISTERED)
> + continue;
> +
> + netdev_update_features(netdev);
> + }
> + }
> +}
> +
> static int airoha_dev_open(struct net_device *netdev)
> {
> int err, len = ETH_HLEN + netdev->mtu + ETH_FCS_LEN;
> @@ -1778,6 +1970,18 @@ static int airoha_dev_open(struct net_device *netdev)
> struct airoha_gdm_port *port = dev->port;
> u32 cur_len, pse_port = FE_PSE_PORT_PPE1;
> struct airoha_qdma *qdma = dev->qdma;
> + int qdma_id = qdma - &qdma->eth->qdma[0];
> +
> + /* HW LRO is configured on the QDMA and it is shared between
> + * all the devices using it. Refuse to open a second device on
> + * the same QDMA if LRO is enabled on any device sharing it.
> + */
> + if (atomic_read(&qdma->users) &&
> + airoha_fe_lro_is_enabled(qdma->eth, qdma_id)) {
> + netdev_warn(netdev, "required to disable LRO on QDMA%d\n",
> + qdma_id);
> + return -EBUSY;
> + }
- Can a sibling interface that is DOWN bypass this LRO mutual exclusion check?
- AFAIU the kernel does not run the ndo_set_features() when the device is
down, just set the requested feature. When we bring up eth1, ndo_open()
callback will return an error.
Regards,
Lorenzo
>
> netif_tx_start_all_queues(netdev);
> err = airoha_set_vip_for_gdm_port(dev, true);
> @@ -1817,6 +2021,8 @@ static int airoha_dev_open(struct net_device *netdev)
> airoha_set_gdm_port_fwd_cfg(qdma->eth, REG_GDM_FWD_CFG(port->id),
> pse_port);
>
> + airoha_update_netdev_features(dev);
> +
> return 0;
> }
>
> @@ -1876,6 +2082,8 @@ static int airoha_dev_stop(struct net_device *netdev)
> }
> }
>
> + airoha_update_netdev_features(dev);
> +
> return 0;
> }
>
> @@ -2154,6 +2362,56 @@ int airoha_get_fe_port(struct airoha_gdm_dev *dev)
> }
> }
>
> +static netdev_features_t airoha_dev_fix_features(struct net_device *netdev,
> + netdev_features_t features)
> +{
> + struct airoha_gdm_dev *dev = netdev_priv(netdev);
> + struct airoha_qdma *qdma = dev->qdma;
> +
> + if (atomic_read(&qdma->users) > 1)
> + features &= ~NETIF_F_LRO;
> +
> + return features;
> +}
> +
> +static int airoha_dev_set_features(struct net_device *netdev,
> + netdev_features_t features)
> +{
> + netdev_features_t diff = netdev->features ^ features;
> + struct airoha_gdm_dev *dev = netdev_priv(netdev);
> + struct airoha_qdma *qdma = dev->qdma;
> + struct airoha_eth *eth = qdma->eth;
> + int qdma_id = qdma - ð->qdma[0];
> +
> + if (!(diff & NETIF_F_LRO))
> + return 0;
> +
> + if (features & NETIF_F_LRO) {
> + int i, lro_queue_index = 0;
> +
> + for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) {
> + struct airoha_queue *q = &qdma->q_rx[i];
> + u32 size;
> +
> + if (!q->ndesc)
> + continue;
> +
> + if (!airoha_qdma_is_lro_queue(q))
> + continue;
> +
> + size = SKB_WITH_OVERHEAD(AIROHA_RX_LEN(q->buf_size));
> + size = min_t(u32, size, CDM_LRO_AGG_SIZE_MASK);
> + airoha_fe_lro_init_rx_queue(eth, qdma_id,
> + lro_queue_index, i, size);
> + lro_queue_index++;
> + }
> + } else {
> + airoha_fe_lro_disable(eth, qdma_id);
> + }
> +
> + return 0;
> +}
> +
> static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
> struct net_device *netdev)
> {
> @@ -3082,6 +3340,8 @@ static const struct net_device_ops airoha_netdev_ops = {
> .ndo_stop = airoha_dev_stop,
> .ndo_change_mtu = airoha_dev_change_mtu,
> .ndo_select_queue = airoha_dev_select_queue,
> + .ndo_fix_features = airoha_dev_fix_features,
> + .ndo_set_features = airoha_dev_set_features,
> .ndo_start_xmit = airoha_dev_xmit,
> .ndo_get_stats64 = airoha_dev_get_stats64,
> .ndo_set_mac_address = airoha_dev_set_macaddr,
> @@ -3169,11 +3429,9 @@ static int airoha_alloc_gdm_device(struct airoha_eth *eth,
> netdev->ethtool_ops = &airoha_ethtool_ops;
> netdev->max_mtu = AIROHA_MAX_MTU;
> netdev->watchdog_timeo = 5 * HZ;
> - netdev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM | NETIF_F_TSO6 |
> - NETIF_F_IPV6_CSUM | NETIF_F_SG | NETIF_F_TSO |
> - NETIF_F_HW_TC;
> - netdev->features |= netdev->hw_features;
> - netdev->vlan_features = netdev->hw_features;
> + netdev->hw_features = AIROHA_HW_FEATURES | NETIF_F_LRO;
> + netdev->features |= AIROHA_HW_FEATURES;
> + netdev->vlan_features = AIROHA_HW_FEATURES;
> SET_NETDEV_DEV(netdev, eth->dev);
>
> /* reserve hw queues for HTB offloading */
> diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h
> index 8f42973f9cf5..e78ef751f244 100644
> --- a/drivers/net/ethernet/airoha/airoha_eth.h
> +++ b/drivers/net/ethernet/airoha/airoha_eth.h
> @@ -44,6 +44,18 @@
> (_n) == 15 ? 128 : \
> (_n) == 0 ? 1024 : 16)
>
> +#define AIROHA_LRO_PAGE_ORDER order_base_2(SZ_16K / PAGE_SIZE)
> +#define AIROHA_MAX_NUM_LRO_QUEUES 8
> +#define AIROHA_RXQ_LRO_EN_MASK GENMASK(31, 24)
> +#define AIROHA_RXQ_LRO_MAX_AGG_COUNT 64
> +#define AIROHA_RXQ_LRO_MAX_AGG_TIME 100
> +#define AIROHA_RXQ_LRO_MAX_AGE_TIME 2000
> +
> +#define AIROHA_HW_FEATURES \
> + (NETIF_F_IP_CSUM | NETIF_F_RXCSUM | \
> + NETIF_F_TSO6 | NETIF_F_IPV6_CSUM | \
> + NETIF_F_SG | NETIF_F_TSO | NETIF_F_HW_TC)
> +
> #define PSE_RSV_PAGES 128
> #define PSE_QUEUE_RSV_PAGES 64
>
> @@ -672,6 +684,18 @@ static inline bool airoha_is_7583(struct airoha_eth *eth)
> return eth->soc->version == 0x7583;
> }
>
> +static inline bool airoha_qdma_is_lro_queue(struct airoha_queue *q)
> +{
> + struct airoha_qdma *qdma = q->qdma;
> + int qid = q - &qdma->q_rx[0];
> +
> + /* EN7581 SoC supports at most 8 LRO rx queues */
> + BUILD_BUG_ON(hweight32(AIROHA_RXQ_LRO_EN_MASK) >
> + AIROHA_MAX_NUM_LRO_QUEUES);
> +
> + return !!(AIROHA_RXQ_LRO_EN_MASK & BIT(qid));
> +}
> +
> int airoha_get_fe_port(struct airoha_gdm_dev *dev);
> bool airoha_is_valid_gdm_dev(struct airoha_eth *eth,
> struct airoha_gdm_dev *dev);
> diff --git a/drivers/net/ethernet/airoha/airoha_regs.h b/drivers/net/ethernet/airoha/airoha_regs.h
> index 436f3c8779c1..dfc786583774 100644
> --- a/drivers/net/ethernet/airoha/airoha_regs.h
> +++ b/drivers/net/ethernet/airoha/airoha_regs.h
> @@ -122,6 +122,20 @@
> #define CDM_CRSN_QSEL_REASON_MASK(_n) \
> GENMASK(4 + (((_n) % 4) << 3), (((_n) % 4) << 3))
>
> +#define REG_CDM_LRO_RXQ(_n, _m) (CDM_BASE(_n) + 0x78 + ((_m) & 0x4))
> +#define LRO_RXQ_MASK(_n) GENMASK(4 + (((_n) & 0x3) << 3), ((_n) & 0x3) << 3)
> +
> +#define REG_CDM_LRO_EN(_n) (CDM_BASE(_n) + 0x80)
> +#define LRO_RXQ_EN_MASK GENMASK(7, 0)
> +
> +#define REG_CDM_LRO_LIMIT(_n) (CDM_BASE(_n) + 0x84)
> +#define CDM_LRO_AGG_NUM_MASK GENMASK(23, 16)
> +#define CDM_LRO_AGG_SIZE_MASK GENMASK(15, 0)
> +
> +#define REG_CDM_LRO_AGE_TIME(_n) (CDM_BASE(_n) + 0x88)
> +#define CDM_LRO_AGE_TIME_MASK GENMASK(31, 16)
> +#define CDM_LRO_AGG_TIME_MASK GENMASK(15, 0)
> +
> #define REG_GDM_FWD_CFG(_n) GDM_BASE(_n)
> #define GDM_PAD_EN_MASK BIT(28)
> #define GDM_DROP_CRC_ERR_MASK BIT(23)
> @@ -883,9 +897,15 @@
> #define QDMA_ETH_RXMSG_SPORT_MASK GENMASK(25, 21)
> #define QDMA_ETH_RXMSG_CRSN_MASK GENMASK(20, 16)
> #define QDMA_ETH_RXMSG_PPE_ENTRY_MASK GENMASK(15, 0)
> +/* RX MSG2 */
> +#define QDMA_ETH_RXMSG_AGG_COUNT_MASK GENMASK(31, 24)
> +#define QDMA_ETH_RXMSG_L2_LEN_MASK GENMASK(6, 0)
> +/* RX MSG3 */
> +#define QDMA_ETH_RXMSG_AGG_LEN_MASK GENMASK(31, 16)
> +#define QDMA_ETH_RXMSG_TCP_WIN_MASK GENMASK(15, 0)
>
> struct airoha_qdma_desc {
> - __le32 rsv;
> + __le32 tcp_ts_reply;
> __le32 ctrl;
> __le32 addr;
> __le32 data;
>
> ---
> base-commit: 660a9e399ab02c0cb86d277ed6b0c9d10c350fdd
> change-id: 20260520-airoha-eth-lro-a5d1c3631811
>
> Best regards,
> --
> Lorenzo Bianconi <lorenzo@kernel.org>
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [PATCH v2 10/16] power: sequencing: pcie-m2: support matching on remote "port" node
From: Chen-Yu Tsai @ 2026-06-12 9:12 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Bartosz Golaszewski, Greg Kroah-Hartman, Daniel Scally,
Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno, Alan Stern,
linux-acpi, driver-core, linux-pm, linux-usb, devicetree,
linux-mediatek, linux-arm-kernel, linux-kernel,
Manivannan Sadhasivam
In-Reply-To: <ail1sAxgh5Xtkj2y@ashevche-desk.local>
On Wed, Jun 10, 2026 at 11:33 PM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> On Wed, Jun 10, 2026 at 04:40:44PM +0800, Chen-Yu Tsai wrote:
> > A USB hub can have multiple ports, and this driver needs to
> > differentiate which port is being matched to. The USB hub driver now
> > associates the "port" node with the usb_port device, so here we can
> > use the remote "port" node to check for a match. Then fall back to
> > the remote device node for the other connection types.
>
> ...
>
> > + if (remote_port && remote_port == dev_of_node(dev))
> > + return PWRSEQ_MATCH_OK;
> > if (remote && (remote == dev_of_node(dev)))
> > return PWRSEQ_MATCH_OK;
>
> We have device_match_of_node() IIRC the name of that API.
Ack. Will also replace the existing instance.
^ permalink raw reply
* Re: [PATCH net-next v7 0/2] Add Frame Preemption MAC Merge support for ICSSG
From: Simon Horman @ 2026-06-12 9:01 UTC (permalink / raw)
To: Meghana Malladi
Cc: elfring, haokexin, vadim.fedorenko, devnexen, jacob.e.keller,
arnd, basharath, afd, parvathi, vladimir.oltean, rogerq,
danishanwar, pabeni, kuba, edumazet, davem, andrew+netdev,
linux-arm-kernel, netdev, linux-kernel, srk, Vignesh Raghavendra
In-Reply-To: <20260610052511.781752-1-m-malladi@ti.com>
On Wed, Jun 10, 2026 at 10:55:09AM +0530, Meghana Malladi wrote:
> This patch series adds QoS support to the ICSSG PRUETH driver.
> The first patch implements mqprio qdisc handling and TC offload hooks
> so userspace can request TC mappings and queue counts.
>
> It also integrates a driver-side mechanism to program the firmware
> with the IET/FPE preemption mask and to kick the firmware verify state
> machine when frame preemption is enabled. The second patch adds ethtool
> perations for the MAC Merge (Frame Preemption) sublayer, exposing .get_mm,
> .set_mm and .get_mm_stats so admins can view and change MAC Merge
> parameters and retrieve preemption statistics.
>
> v6: https://lore.kernel.org/all/20260525182700.3135858-1-m-malladi@ti.com/
>
> MD Danish Anwar (2):
> net: ti: icssg-prueth: Add Frame Preemption MAC Merge support
> net: ti: icssg-prueth: Add ethtool ops for Frame Preemption MAC Merge
Hi Meghana and MD,
There is AI-generated review of this patch-set available on both
https://sashiko.dev and https://netdev-ai.bots.linux.dev/sashiko/
I would appreciate it if you could look over that with a view
to addressing any issues that directly affect this patch-set.
...
^ permalink raw reply
* Re: [PATCH v2 08/16] Revert "dt-bindings: usb: mediatek,mtk-xhci: Add port for SuperSpeed EP"
From: Krzysztof Kozlowski @ 2026-06-12 8:59 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Bartosz Golaszewski, Greg Kroah-Hartman, Andy Shevchenko,
Daniel Scally, Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno, Alan Stern,
linux-acpi, driver-core, linux-pm, linux-usb, devicetree,
linux-mediatek, linux-arm-kernel, linux-kernel,
Manivannan Sadhasivam
In-Reply-To: <20260610084053.2059858-9-wenst@chromium.org>
On Wed, Jun 10, 2026 at 04:40:42PM +0800, Chen-Yu Tsai wrote:
> This reverts commit 454a1e3cd36c113341d7b71e8e691c6e47ab4a8a.
>
> mtk-xhci handles both USB 2.0 High Speed (HS) and USB 3.x SuperSpeed
> (SS) host connections. And there are USB 2.0 only mtk-xhci blocks.
> The SSUSB controller handles the device or gadget mode. Saying that
> SSUSB handles the HS portion is wrong.
>
> Fixes: 454a1e3cd36c ("dt-bindings: usb: mediatek,mtk-xhci: Add port for SuperSpeed EP")
> Cc: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
> Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
> ---
> Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml | 4 ----
> 1 file changed, 4 deletions(-)
Please squash both commits. Reverting just for sake of revert is
pointless. We want wrong binding to be corrected, not to be reverted.
You revert something if there is nothing to fix afterwards, IOW.
Best regards,
Krzysztof
^ permalink raw reply
* [PATCH] net: macb: add TX stall timeout callback to recover from lost TSTART write
From: Andrea della Porta @ 2026-06-12 9:01 UTC (permalink / raw)
To: netdev, Theo Lebrun, Andrea della Porta, Nicolas Ferre,
Claudiu Beznea, Andrew Lunn, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, linux-kernel, linux-arm-kernel,
linux-rpi-kernel
Cc: Lukasz Raczylo, Steffen Jaeckel
From: Lukasz Raczylo <lukasz@raczylo.com>
The MACB found in the Raspberry Pi RP1 suffers from sporadic stalls on
the TX queue.
While the exact root cause is not yet fully understood, it is likely
related to a hardware issue where a TSTART write to the NCR register
is missed, preventing the transmission from being kicked off.
Implement a timeout callback to handle TX queue stalls, triggering the
existing restart mechanism to recover.
Link: https://lore.kernel.org/all/20260514215459.36109-1-lukasz@raczylo.com/
Fixes: dc110d1b23564 ("net: cadence: macb: Add support for Raspberry Pi RP1 ethernet controller")
Signed-off-by: Lukasz Raczylo <lukasz@raczylo.com>
Co-developed-by: Steffen Jaeckel <sjaeckel@suse.de>
Signed-off-by: Steffen Jaeckel <sjaeckel@suse.de>
Co-developed-by: Andrea della Porta <andrea.porta@suse.com>
Signed-off-by: Andrea della Porta <andrea.porta@suse.com>
---
drivers/net/ethernet/cadence/macb_main.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index a12aa21244e83..615da65d5d68d 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -4522,6 +4522,16 @@ static int macb_setup_tc(struct net_device *dev, enum tc_setup_type type,
}
}
+static void macb_tx_timeout(struct net_device *dev, unsigned int q)
+{
+ struct macb *bp = netdev_priv(dev);
+
+ if (net_ratelimit())
+ netdev_err(dev, "TX stall detected, re-kicking TSTART\n");
+ dev->stats.tx_errors++;
+ macb_tx_restart(&bp->queues[q]);
+}
+
static const struct net_device_ops macb_netdev_ops = {
.ndo_open = macb_open,
.ndo_stop = macb_close,
@@ -4540,6 +4550,7 @@ static const struct net_device_ops macb_netdev_ops = {
.ndo_hwtstamp_set = macb_hwtstamp_set,
.ndo_hwtstamp_get = macb_hwtstamp_get,
.ndo_setup_tc = macb_setup_tc,
+ .ndo_tx_timeout = macb_tx_timeout,
};
/* Configure peripheral capabilities according to device tree
--
2.35.3
^ permalink raw reply related
* Re: [PATCH v2 07/16] usb: hub: Power on connected M.2 E-key connectors
From: Chen-Yu Tsai @ 2026-06-12 8:55 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Alan Stern, linux-acpi, driver-core, linux-pm, linux-usb,
devicetree, linux-mediatek, linux-arm-kernel, linux-kernel,
Manivannan Sadhasivam, Greg Kroah-Hartman, Andy Shevchenko,
Daniel Scally, Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno
In-Reply-To: <CAMRc=Mc3DqGb2MsvM4tjcqFuRraAO+EftO1UrtNFvR5dMRXmVA@mail.gmail.com>
On Thu, Jun 11, 2026 at 6:11 PM Bartosz Golaszewski <brgl@kernel.org> wrote:
>
> On Wed, 10 Jun 2026 10:40:41 +0200, Chen-Yu Tsai <wenst@chromium.org> said:
> > The new M.2 E-key connector can have a USB connection. For the USB device
> > on this connector to work, its power must be enabled and the W_DISABLE2#
> > signal deasserted. The connector driver handles this and provides a
> > toggle over the power sequencing API.
> >
> > This feature currently only supports a directly connected (no mux in
> > between) M.2 E-key connector. Existing USB connector types are not
> > covered. The USB A connector was recently added to the onboard devices
> > driver. USB B connectors have historically been managed by the USB
> > gadget or dual-role device controller drivers. USB C connectors are
> > handled by TCPM drivers.
> >
> > The power sequencing API does not know whether a power sequence provider
> > is not needed or not available yet, so we only request it for connectors
> > that we know need it, which at this time is just the E-key connector.
> >
> > On the USB side, the port firmware node (if present) is tied to the
> > usb_port device. This device is used to acquire the power sequencing
> > descriptor. This allows the provider to tell the different ports on one
> > hub apart.
> >
> > This feature is not implemented in the onboard USB devices driver. The
> > power sequencing API expects the consumer device to make the request,
> > but there is no device node to instantiate a platform device to tie
> > the driver to. The connector is not a child node of the USB host or
> > hub, and the graph connection is from a USB port to the connector.
> > And the connector itself already has a driver.
> >
> > Power sequencing is not directly enabled in the connector driver as
> > that would completely decouple the timing of it from the USB subsystem.
> > It would not be possible for the USB subsystem to toggle the power
> > for a power cycle or to disable the port.
> >
> > This change depends on another change to make the power sequencing
> > framework bool instead of tristate. The USB core and hub driver are
> > bool, so if the power sequencing framework is built as a module, the
> > kernel will fail to link.
> >
>
> That bit needs to go away I suppose?
Yeah, instead we need
config USB
depends on POWER_SEQUENCING && !POWER_SEQUENCING
But I ran into a dozen or so drivers that have "select USB", mostly
input devices:
config TOUCHSCREEN_USB_COMPOSITE
tristate "USB Touchscreen Driver"
depends on USB_ARCH_HAS_HCD
select USB
Kconfig complains about unmet dependencies.
> I see Andy has some suggestions but in general I like this approach much better
> than adding the pwrseq_get_index() function. Thanks!
Thanks!
ChenYu
^ permalink raw reply
* Re: [GIT PULL] KVM/arm64 updates for 7.2
From: Paolo Bonzini @ 2026-06-12 8:52 UTC (permalink / raw)
To: Marc Zyngier
Cc: Anshuman Khandual, Catalin Marinas, Eric Auger, Fuad Tabba,
Hyunwoo Kim, Jackie Liu, Joey Gouly, Mark Rutland, Oliver Upton,
Sascha Bischoff, Vincent Donnefort, Wei-Lin Chang, Will Deacon,
Zenghui Yu, Steffen Eiden, Suzuki K Poulose, Zenghui Yu, kvmarm,
kvm, linux-arm-kernel
In-Reply-To: <20260612084835.2992552-1-maz@kernel.org>
On Fri, Jun 12, 2026 at 10:48 AM Marc Zyngier <maz@kernel.org> wrote:
>
> Paolo,
>
> This is a bit of an odd merge window on the KVM/arm64 front. There is
> absolutely no new feature in the pull request. It is purely fixes,
> because it is simply becoming too hard to review new stuff when so
> many AI-fuelled fixes hit the list. And even then, I've arbitrarily
> tagged the branch today, knowing that there is quite a backlog of
> fixes that I will send very shortly, probably before -rc1.
No problem. Since I usually wait for the arch code to be merged before
sending my PRs, you have almost a week to send them and have them
included in the very first PRs.
Pulled these for now, thanks.
Paolo
> So here it is: only fixes and very minor improvements, all over the
> place. Details in the tag below.
>
> Please pull,
>
> M.
>
> The following changes since commit 5200f5f493f79f14bbdc349e402a40dfb32f23c8:
>
> Linux 7.1-rc4 (2026-05-17 13:59:58 -0700)
>
> are available in the Git repository at:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git tags/kvmarm-7.2
>
> for you to fetch changes up to 1ee27dacbe5dc4def481794d899d67b0d4570094:
>
> Merge branch kvm-arm64/nv-mmu-7.2 into kvmarm-master/next (2026-06-12 09:29:34 +0100)
>
> ----------------------------------------------------------------
> KVM/arm64 updates for 7.2
>
> * New features:
>
> - None. Zilch. Nada. Que dalle.
>
> * Fixes and other improvements:
>
> - Significant cleanup of the vgic-v5 PPI support which was merged in
> 7.1. This makes the code more maintainable, and squashes a couple
> of bugs in the meantime.
>
> - Set of fixes for the handling of the MMU in an NV context,
> particularly VNCR-triggered faults. S1POE support is fixed
> as well.
>
> - Large set of pKVM fixes, mostly addressing recurring issues
> around hypervisor tracking of donated pages in obscure cases
> where the donation could fail and leave things in a bizarre
> state.
>
> - Fixes for the so-called "lazy vgic init", which resulted in
> sleeping operations in non-preemptible sections. This turned
> out to be far more invasive than initially expected...
>
> - Reduce the overhead of L1/L2 context switch by not touching
> the FP registers.
>
> - Fix the way non-implemented page sizes are dealt with when
> a guest insist on using them for S2 translation.
>
> - The usual set of low-impact fixes and cleanups all over the map.
>
> ----------------------------------------------------------------
> Fuad Tabba (5):
> KVM: arm64: Guard against NULL vcpu on VHE hyp panic path
> KVM: arm64: Fix __deactivate_fgt macro parameter typo
> KVM: arm64: Seed pkvm_ownership_selftest vcpu memcache
> KVM: arm64: Pre-check vcpu memcache for host->guest share
> KVM: arm64: Pre-check vcpu memcache for host->guest donate
>
> Hyunwoo Kim (2):
> KVM: arm64: Clear __hyp_running_vcpu when flushing the pKVM hyp vCPU
> KVM: arm64: Bound used_lrs when flushing the pKVM hyp vCPU
>
> Jackie Liu (1):
> KVM: arm64: vgic-its: Make ABI commit helpers return void
>
> Marc Zyngier (29):
> KVM: arm64: nv: Track L2 to L1 exception emulation
> KVM: arm64: nv: Don't save/restore FP register during a nested ERET or exception
> KVM: arm64: timer: Repaint kvm_timer_{should,irq_can}_fire() to kvm_timer_{pending,enabled}()
> KVM: arm64: Simplify userspace notification of interrupt state
> KVM: arm64: timer: Kill the per-timer irq level cache
> KVM: arm64: pmu: Kill the PMU interrupt level cache
> KVM: arm64: vgic-v2: Force vgic init on injection outside the run loop
> KVM: arm64: vgic-v2: Don't init the vgic on in-kernel interrupt injection
> KVM: arm64: vgic-v5: Add for_each_visible_v5_ppi() iterator
> KVM: arm64: vgic-v5: Move PPI caps into kvm_vgic_global_state
> KVM: arm64: vgic-v5: Remove use of __assign_bit() with a constant
> KVM: arm64: vgic-v5: Drop pointless ARM64_HAS_GICV5_CPUIF check
> KVM: arm64: vgic: Constify struct irq_ops usage
> KVM: arm64: vgic: Consolidate vgic_allocate_private_irqs_locked()
> KVM: arm64: vgic-v5: Drop defensive checks from vgic_v5_ppi_queue_irq_unlock()
> KVM: arm64: vgic: Rationalise per-CPU irq accessor
> KVM: arm64: vgic-v5: Limit support to 64 PPIs
> KVM: arm64: Key CPTR_EL2.E0POE propagation on FEAT_S1POE
> KVM: arm64: Wire AT S1E1A in the system instruction handling table
> arm64: cpufeature: Expose ID_AA64ISAR2_EL1.ATS1A to KVM
> KVM: arm64: nv: Avoid dereferencing NULL VNCR pseudo-TLB
> KVM: arm64: nv: Hold kvm->mmu_lock while initialising vcpu->arch.vncr_tlb
> Merge branch kvm-arm64/no-lazy-vgic-init into kvmarm-master/next
> Merge branch kvm-arm64/nv-fp-elision into kvmarm-master/next
> Merge branch kvm-arm64/nv-granule-sizes into kvmarm-master/next
> Merge branch kvm-arm64/pkvm-fixes-7.2 into kvmarm-master/next
> Merge branch kvm-arm64/vgic-v5-PPI-fixes into kvmarm-master/next
> Merge branch kvm-arm64/misc-7.2 into kvmarm-master/next
> Merge branch kvm-arm64/nv-mmu-7.2 into kvmarm-master/next
>
> Oliver Upton (5):
> KVM: arm64: Don't leak PFN when kvm_translate_vncr() races MMU notifier
> KVM: arm64: nv: Fully update VNCR fixmap state in kvm_translate_vncr()
> KVM: arm64: nv: Inject SEA TTW when desc update can't write to GPA
> KVM: arm64: Restart instruction upon race in __kvm_at_s12()
> KVM: arm64: nv: Restart stage-1 walk if stage-2 desc update fails
>
> Sascha Bischoff (9):
> KVM: arm64: vgic-v5: Add missing trap handing for NV triage
> KVM: arm64: vgic-v5: Atomically assign bits to PPI DVI bitmap
> KVM: arm64: selftests: Add missing GIC CDEN to no-vgic-v5 selftest
> KVM: arm64: selftests: Cleanup unused vars in GICv5 PPI selftest
> KVM: arm64: selftests: Improve error handling for GICv5 PPI selftest
> Documentation: KVM: Fix typos in VGICv5 documentation
> Documentation: KVM: Clarify that PMU_V3_IRQ IntID requirements for GICv5
> irqchip/gic-v5: Immediately exec priority drop following activate
> KVM: arm64: Fix arch timer interrupts for GICv3-on-GICv5 guests
>
> Vincent Donnefort (4):
> KVM: arm64: Reset page order in pKVM hyp_pool
> KVM: arm64: Fix __pkvm_init_vm error path
> KVM: arm64: Add fail-safe for refcounted pages in __pkvm_hyp_donate_host
> KVM: arm64: Set a Linux errno on SMCCC error in kvm_call_hyp_nvhe()
>
> Wei-Lin Chang (5):
> KVM: arm64: nv: Rename vtcr_to_walk_info() to setup_s2_walk()
> KVM: arm64: Factor out TG0/1 decoding of VTCR and TCR
> KVM: arm64: nv: Use literal granule size in TLBI range calculation
> KVM: arm64: Fallback to a supported value for unsupported guest TGx
> KVM: arm64: Fix block mapping validity check in stage-1 walker
>
> Will Deacon (1):
> KVM: arm64: Don't populate TPIDR_EL2 in finalise_el2()
>
> Zenghui Yu (Huawei) (1):
> KVM: arm64: Remove @arch from __load_stage2()
>
> tabba@google.com (4):
> KVM: arm64: Flush HCR_EL2.VSE to deliver SErrors to pKVM guests
> KVM: arm64: Free hyp-share tracking node when share hypercall fails
> KVM: arm64: Avoid host/hyp share desync on unshare hypercall failure
> KVM: arm64: Roll back partial shares on kvm_share_hyp() failure
>
> Documentation/virt/kvm/devices/arm-vgic-v5.rst | 6 +-
> Documentation/virt/kvm/devices/vcpu.rst | 7 +-
> arch/arm64/include/asm/kvm_host.h | 8 +-
> arch/arm64/include/asm/kvm_hyp.h | 1 +
> arch/arm64/include/asm/kvm_mmu.h | 3 +-
> arch/arm64/kernel/cpufeature.c | 1 +
> arch/arm64/kernel/hyp-stub.S | 4 +-
> arch/arm64/kvm/arch_timer.c | 137 +++++++--------
> arch/arm64/kvm/arm.c | 41 +++--
> arch/arm64/kvm/at.c | 146 +++++++++++----
> arch/arm64/kvm/emulate-nested.c | 12 ++
> arch/arm64/kvm/fpsimd.c | 26 +++
> arch/arm64/kvm/hyp/include/hyp/switch.h | 2 +-
> arch/arm64/kvm/hyp/include/nvhe/mem_protect.h | 3 +-
> arch/arm64/kvm/hyp/nvhe/hyp-main.c | 21 ++-
> arch/arm64/kvm/hyp/nvhe/mem_protect.c | 37 ++--
> arch/arm64/kvm/hyp/nvhe/page_alloc.c | 21 ++-
> arch/arm64/kvm/hyp/nvhe/pkvm.c | 4 +-
> arch/arm64/kvm/hyp/nvhe/switch.c | 2 +-
> arch/arm64/kvm/hyp/nvhe/tlb.c | 4 +-
> arch/arm64/kvm/hyp/vgic-v5-sr.c | 82 ++-------
> arch/arm64/kvm/hyp/vhe/switch.c | 2 +-
> arch/arm64/kvm/hyp/vhe/tlb.c | 4 +-
> arch/arm64/kvm/mmu.c | 39 ++++-
> arch/arm64/kvm/nested.c | 234 ++++++++++++++++---------
> arch/arm64/kvm/pmu-emul.c | 31 +---
> arch/arm64/kvm/sys_regs.c | 20 +--
> arch/arm64/kvm/vgic/vgic-init.c | 45 ++---
> arch/arm64/kvm/vgic/vgic-irqfd.c | 6 +
> arch/arm64/kvm/vgic/vgic-its.c | 21 +--
> arch/arm64/kvm/vgic/vgic-kvm-device.c | 9 +-
> arch/arm64/kvm/vgic/vgic-v5.c | 51 ++----
> arch/arm64/kvm/vgic/vgic.c | 33 ++--
> arch/arm64/kvm/vgic/vgic.h | 3 +
> drivers/irqchip/irq-gic-v5.c | 13 +-
> include/kvm/arm_arch_timer.h | 7 +-
> include/kvm/arm_pmu.h | 5 +-
> include/kvm/arm_vgic.h | 19 +-
> tools/testing/selftests/kvm/arm64/no-vgic.c | 1 +
> tools/testing/selftests/kvm/arm64/vgic_v5.c | 10 +-
> 40 files changed, 651 insertions(+), 470 deletions(-)
>
^ permalink raw reply
* Re: [PATCH v7 11/30] drm/display: bridge_connector: Wire up HDMI 2.0 scrambler callbacks
From: Maxime Ripard @ 2026-06-12 8:52 UTC (permalink / raw)
To: Cristian Ciocaltea
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Sandy Huang,
Heiko Stübner, Andy Yan, Daniel Stone, Dave Stevenson,
Maíra Canal, Raspberry Pi Kernel Maintenance, kernel,
dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-11-445eb54ee1ed@collabora.com>
[-- Attachment #1: Type: text/plain, Size: 4179 bytes --]
On Tue, Jun 02, 2026 at 01:44:11AM +0300, Cristian Ciocaltea wrote:
> Connect the bridge connector's .scrambler_{enable|disable} callbacks to
> the underlying bridge's .hdmi_scrambler_{enable|disable} funcs when
> DRM_BRIDGE_OP_HDMI_SCRAMBLER is advertised.
>
> This completes the bridge connector plumbing so that the SCDC
> scrambling helpers can control source-side scrambling through the
> bridge chain.
>
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
> ---
> drivers/gpu/drm/display/drm_bridge_connector.c | 41 +++++++++++++++++++++++++-
> 1 file changed, 40 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
> index 9d21b1b57b0d..d048ab49eade 100644
> --- a/drivers/gpu/drm/display/drm_bridge_connector.c
> +++ b/drivers/gpu/drm/display/drm_bridge_connector.c
> @@ -555,6 +555,32 @@ static int drm_bridge_connector_write_spd_infoframe(struct drm_connector *connec
> return bridge->funcs->hdmi_write_spd_infoframe(bridge, buffer, len);
> }
>
> +static int drm_bridge_connector_scrambler_enable(struct drm_connector *connector)
> +{
> + struct drm_bridge_connector *bridge_connector =
> + to_drm_bridge_connector(connector);
> + struct drm_bridge *bridge;
> +
> + bridge = bridge_connector->bridge_hdmi;
> + if (!bridge)
> + return -EINVAL;
> +
> + return bridge->funcs->hdmi_scrambler_enable(bridge);
> +}
> +
> +static int drm_bridge_connector_scrambler_disable(struct drm_connector *connector)
> +{
> + struct drm_bridge_connector *bridge_connector =
> + to_drm_bridge_connector(connector);
> + struct drm_bridge *bridge;
> +
> + bridge = bridge_connector->bridge_hdmi;
> + if (!bridge)
> + return -EINVAL;
> +
> + return bridge->funcs->hdmi_scrambler_disable(bridge);
> +}
> +
> static const struct drm_edid *
> drm_bridge_connector_read_edid(struct drm_connector *connector)
> {
> @@ -580,7 +606,7 @@ static const struct drm_connector_hdmi_funcs drm_bridge_connector_hdmi_funcs = {
> .clear_infoframe = drm_bridge_connector_clear_hdmi_infoframe,
> .write_infoframe = drm_bridge_connector_write_hdmi_infoframe,
> },
> - /* audio, hdr_drm and spd are set dynamically during init */
> + /* scrambler, audio, hdr_drm and spd are set dynamically during init */
> };
>
> static const struct drm_connector_infoframe_funcs drm_bridge_connector_hdmi_audio_infoframe = {
> @@ -886,6 +912,11 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
> !bridge->funcs->hdmi_clear_spd_infoframe))
> return ERR_PTR(-EINVAL);
>
> + if (bridge->ops & DRM_BRIDGE_OP_HDMI_SCRAMBLER &&
> + (!bridge->funcs->hdmi_scrambler_enable ||
> + !bridge->funcs->hdmi_scrambler_disable))
> + return ERR_PTR(-EINVAL);
> +
> bridge_connector->bridge_hdmi = drm_bridge_get(bridge);
>
> if (bridge->supported_formats)
> @@ -990,6 +1021,14 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
> bridge_connector->hdmi_funcs.spd =
> drm_bridge_connector_hdmi_spd_infoframe;
>
> + if (bridge_connector->bridge_hdmi->ops & DRM_BRIDGE_OP_HDMI_SCRAMBLER) {
> + bridge_connector->hdmi_funcs.scrambler_enable =
> + drm_bridge_connector_scrambler_enable;
> + bridge_connector->hdmi_funcs.scrambler_disable =
> + drm_bridge_connector_scrambler_disable;
> + connector->hdmi.scrambler_supported = true;
> + }
> +
I think we're taking this backwards. The scrambler support isn't
optional: either the controller supports HDMI < 2.0, and then it doesn't
exist, or it supports >= 2.0 and then it's mandatory.
You're considering it optional here, when it's never actually optional
(unlike YUV420 for example)
I still think we should list, somehow, the capabilities of the
controller to the helpers, like max tmds rate supported, formats, etc.
We've so far put everything as an argument to drmm_connector_hdmi_init
but it becomes a bit overloaded, and I wonder if introducing a callback
wouldn't solve this, kind of like what we have for planes and formats.
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
^ permalink raw reply
* [GIT PULL] KVM/arm64 updates for 7.2
From: Marc Zyngier @ 2026-06-12 8:48 UTC (permalink / raw)
To: Paolo Bonzini
Cc: Anshuman Khandual, Catalin Marinas, Eric Auger, Fuad Tabba,
Hyunwoo Kim, Jackie Liu, Joey Gouly, Mark Rutland, Oliver Upton,
Sascha Bischoff, Vincent Donnefort, Wei-Lin Chang, Will Deacon,
Zenghui Yu, Steffen Eiden, Suzuki K Poulose, Zenghui Yu, kvmarm,
kvm, linux-arm-kernel
Paolo,
This is a bit of an odd merge window on the KVM/arm64 front. There is
absolutely no new feature in the pull request. It is purely fixes,
because it is simply becoming too hard to review new stuff when so
many AI-fuelled fixes hit the list. And even then, I've arbitrarily
tagged the branch today, knowing that there is quite a backlog of
fixes that I will send very shortly, probably before -rc1.
So here it is: only fixes and very minor improvements, all over the
place. Details in the tag below.
Please pull,
M.
The following changes since commit 5200f5f493f79f14bbdc349e402a40dfb32f23c8:
Linux 7.1-rc4 (2026-05-17 13:59:58 -0700)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git tags/kvmarm-7.2
for you to fetch changes up to 1ee27dacbe5dc4def481794d899d67b0d4570094:
Merge branch kvm-arm64/nv-mmu-7.2 into kvmarm-master/next (2026-06-12 09:29:34 +0100)
----------------------------------------------------------------
KVM/arm64 updates for 7.2
* New features:
- None. Zilch. Nada. Que dalle.
* Fixes and other improvements:
- Significant cleanup of the vgic-v5 PPI support which was merged in
7.1. This makes the code more maintainable, and squashes a couple
of bugs in the meantime.
- Set of fixes for the handling of the MMU in an NV context,
particularly VNCR-triggered faults. S1POE support is fixed
as well.
- Large set of pKVM fixes, mostly addressing recurring issues
around hypervisor tracking of donated pages in obscure cases
where the donation could fail and leave things in a bizarre
state.
- Fixes for the so-called "lazy vgic init", which resulted in
sleeping operations in non-preemptible sections. This turned
out to be far more invasive than initially expected...
- Reduce the overhead of L1/L2 context switch by not touching
the FP registers.
- Fix the way non-implemented page sizes are dealt with when
a guest insist on using them for S2 translation.
- The usual set of low-impact fixes and cleanups all over the map.
----------------------------------------------------------------
Fuad Tabba (5):
KVM: arm64: Guard against NULL vcpu on VHE hyp panic path
KVM: arm64: Fix __deactivate_fgt macro parameter typo
KVM: arm64: Seed pkvm_ownership_selftest vcpu memcache
KVM: arm64: Pre-check vcpu memcache for host->guest share
KVM: arm64: Pre-check vcpu memcache for host->guest donate
Hyunwoo Kim (2):
KVM: arm64: Clear __hyp_running_vcpu when flushing the pKVM hyp vCPU
KVM: arm64: Bound used_lrs when flushing the pKVM hyp vCPU
Jackie Liu (1):
KVM: arm64: vgic-its: Make ABI commit helpers return void
Marc Zyngier (29):
KVM: arm64: nv: Track L2 to L1 exception emulation
KVM: arm64: nv: Don't save/restore FP register during a nested ERET or exception
KVM: arm64: timer: Repaint kvm_timer_{should,irq_can}_fire() to kvm_timer_{pending,enabled}()
KVM: arm64: Simplify userspace notification of interrupt state
KVM: arm64: timer: Kill the per-timer irq level cache
KVM: arm64: pmu: Kill the PMU interrupt level cache
KVM: arm64: vgic-v2: Force vgic init on injection outside the run loop
KVM: arm64: vgic-v2: Don't init the vgic on in-kernel interrupt injection
KVM: arm64: vgic-v5: Add for_each_visible_v5_ppi() iterator
KVM: arm64: vgic-v5: Move PPI caps into kvm_vgic_global_state
KVM: arm64: vgic-v5: Remove use of __assign_bit() with a constant
KVM: arm64: vgic-v5: Drop pointless ARM64_HAS_GICV5_CPUIF check
KVM: arm64: vgic: Constify struct irq_ops usage
KVM: arm64: vgic: Consolidate vgic_allocate_private_irqs_locked()
KVM: arm64: vgic-v5: Drop defensive checks from vgic_v5_ppi_queue_irq_unlock()
KVM: arm64: vgic: Rationalise per-CPU irq accessor
KVM: arm64: vgic-v5: Limit support to 64 PPIs
KVM: arm64: Key CPTR_EL2.E0POE propagation on FEAT_S1POE
KVM: arm64: Wire AT S1E1A in the system instruction handling table
arm64: cpufeature: Expose ID_AA64ISAR2_EL1.ATS1A to KVM
KVM: arm64: nv: Avoid dereferencing NULL VNCR pseudo-TLB
KVM: arm64: nv: Hold kvm->mmu_lock while initialising vcpu->arch.vncr_tlb
Merge branch kvm-arm64/no-lazy-vgic-init into kvmarm-master/next
Merge branch kvm-arm64/nv-fp-elision into kvmarm-master/next
Merge branch kvm-arm64/nv-granule-sizes into kvmarm-master/next
Merge branch kvm-arm64/pkvm-fixes-7.2 into kvmarm-master/next
Merge branch kvm-arm64/vgic-v5-PPI-fixes into kvmarm-master/next
Merge branch kvm-arm64/misc-7.2 into kvmarm-master/next
Merge branch kvm-arm64/nv-mmu-7.2 into kvmarm-master/next
Oliver Upton (5):
KVM: arm64: Don't leak PFN when kvm_translate_vncr() races MMU notifier
KVM: arm64: nv: Fully update VNCR fixmap state in kvm_translate_vncr()
KVM: arm64: nv: Inject SEA TTW when desc update can't write to GPA
KVM: arm64: Restart instruction upon race in __kvm_at_s12()
KVM: arm64: nv: Restart stage-1 walk if stage-2 desc update fails
Sascha Bischoff (9):
KVM: arm64: vgic-v5: Add missing trap handing for NV triage
KVM: arm64: vgic-v5: Atomically assign bits to PPI DVI bitmap
KVM: arm64: selftests: Add missing GIC CDEN to no-vgic-v5 selftest
KVM: arm64: selftests: Cleanup unused vars in GICv5 PPI selftest
KVM: arm64: selftests: Improve error handling for GICv5 PPI selftest
Documentation: KVM: Fix typos in VGICv5 documentation
Documentation: KVM: Clarify that PMU_V3_IRQ IntID requirements for GICv5
irqchip/gic-v5: Immediately exec priority drop following activate
KVM: arm64: Fix arch timer interrupts for GICv3-on-GICv5 guests
Vincent Donnefort (4):
KVM: arm64: Reset page order in pKVM hyp_pool
KVM: arm64: Fix __pkvm_init_vm error path
KVM: arm64: Add fail-safe for refcounted pages in __pkvm_hyp_donate_host
KVM: arm64: Set a Linux errno on SMCCC error in kvm_call_hyp_nvhe()
Wei-Lin Chang (5):
KVM: arm64: nv: Rename vtcr_to_walk_info() to setup_s2_walk()
KVM: arm64: Factor out TG0/1 decoding of VTCR and TCR
KVM: arm64: nv: Use literal granule size in TLBI range calculation
KVM: arm64: Fallback to a supported value for unsupported guest TGx
KVM: arm64: Fix block mapping validity check in stage-1 walker
Will Deacon (1):
KVM: arm64: Don't populate TPIDR_EL2 in finalise_el2()
Zenghui Yu (Huawei) (1):
KVM: arm64: Remove @arch from __load_stage2()
tabba@google.com (4):
KVM: arm64: Flush HCR_EL2.VSE to deliver SErrors to pKVM guests
KVM: arm64: Free hyp-share tracking node when share hypercall fails
KVM: arm64: Avoid host/hyp share desync on unshare hypercall failure
KVM: arm64: Roll back partial shares on kvm_share_hyp() failure
Documentation/virt/kvm/devices/arm-vgic-v5.rst | 6 +-
Documentation/virt/kvm/devices/vcpu.rst | 7 +-
arch/arm64/include/asm/kvm_host.h | 8 +-
arch/arm64/include/asm/kvm_hyp.h | 1 +
arch/arm64/include/asm/kvm_mmu.h | 3 +-
arch/arm64/kernel/cpufeature.c | 1 +
arch/arm64/kernel/hyp-stub.S | 4 +-
arch/arm64/kvm/arch_timer.c | 137 +++++++--------
arch/arm64/kvm/arm.c | 41 +++--
arch/arm64/kvm/at.c | 146 +++++++++++----
arch/arm64/kvm/emulate-nested.c | 12 ++
arch/arm64/kvm/fpsimd.c | 26 +++
arch/arm64/kvm/hyp/include/hyp/switch.h | 2 +-
arch/arm64/kvm/hyp/include/nvhe/mem_protect.h | 3 +-
arch/arm64/kvm/hyp/nvhe/hyp-main.c | 21 ++-
arch/arm64/kvm/hyp/nvhe/mem_protect.c | 37 ++--
arch/arm64/kvm/hyp/nvhe/page_alloc.c | 21 ++-
arch/arm64/kvm/hyp/nvhe/pkvm.c | 4 +-
arch/arm64/kvm/hyp/nvhe/switch.c | 2 +-
arch/arm64/kvm/hyp/nvhe/tlb.c | 4 +-
arch/arm64/kvm/hyp/vgic-v5-sr.c | 82 ++-------
arch/arm64/kvm/hyp/vhe/switch.c | 2 +-
arch/arm64/kvm/hyp/vhe/tlb.c | 4 +-
arch/arm64/kvm/mmu.c | 39 ++++-
arch/arm64/kvm/nested.c | 234 ++++++++++++++++---------
arch/arm64/kvm/pmu-emul.c | 31 +---
arch/arm64/kvm/sys_regs.c | 20 +--
arch/arm64/kvm/vgic/vgic-init.c | 45 ++---
arch/arm64/kvm/vgic/vgic-irqfd.c | 6 +
arch/arm64/kvm/vgic/vgic-its.c | 21 +--
arch/arm64/kvm/vgic/vgic-kvm-device.c | 9 +-
arch/arm64/kvm/vgic/vgic-v5.c | 51 ++----
arch/arm64/kvm/vgic/vgic.c | 33 ++--
arch/arm64/kvm/vgic/vgic.h | 3 +
drivers/irqchip/irq-gic-v5.c | 13 +-
include/kvm/arm_arch_timer.h | 7 +-
include/kvm/arm_pmu.h | 5 +-
include/kvm/arm_vgic.h | 19 +-
tools/testing/selftests/kvm/arm64/no-vgic.c | 1 +
tools/testing/selftests/kvm/arm64/vgic_v5.c | 10 +-
40 files changed, 651 insertions(+), 470 deletions(-)
^ permalink raw reply
* Re: [PATCH v8 next 04/10] arm_mpam: Refactor rmid to reqPARTID/PMG mapping
From: Zeng Heng @ 2026-06-12 8:44 UTC (permalink / raw)
To: James Morse, ben.horgan, Dave.Martin, tan.shaopeng,
reinette.chatre, fenghuay, tglx, will, hpa, bp, babu.moger,
dave.hansen, mingo, tony.luck, gshan, catalin.marinas
Cc: linux-arm-kernel, x86, linux-kernel, wangkefeng.wang, sunnanyong
In-Reply-To: <2944b506-a462-42f8-95cf-404241fb27f0@arm.com>
Hi James,
>> @@ -478,6 +518,7 @@ static int __read_mon(struct mpam_resctrl_mon *mon, struct mpam_component *mon_c
>> enum resctrl_conf_type cdp_type, u32 closid, u32 rmid, u64 *val)
>> {
>> struct mon_cfg cfg;
>> + u32 reqpartid = rmid2reqpartid(rmid);
>>
>> if (!mpam_is_enabled())
>> return -EINVAL;
>> @@ -493,8 +534,8 @@ static int __read_mon(struct mpam_resctrl_mon *mon, struct mpam_component *mon_c
>> cfg = (struct mon_cfg) {
>> .mon = mon_idx,
>> .match_pmg = true,
>> - .partid = closid,
>> - .pmg = rmid,
>> + .partid = (cdp_type == CDP_CODE) ? reqpartid + 1 : reqpartid,
>> + .pmg = rmid2pmg(rmid),
>
> Not using the CLOSID here breaks multiple control groups.
>
After carefully reviewing your comments and Martin's patch series,
I tried to understand why there is insistence that CLOSID information
is necessary to support multiple control groups, but that is actually
not the case.
Before proceeding, please allow me to refer to base_partid as CPARTID
(control partition ID; I'm no longer borrowing the intPARTID concept
here). The associated partids_per_closid all share the same control
scheme.
The partids derived from partids_per_closid under a given CPARTID,
I will call MPARTID (monitor partition ID; no longer borrowing the
reqPARTID concept). These represent the PARTIDs used for different
monitoring groups under the same control scheme.
I've summarized the ID translation schemes from James and Martin as
follows:
+-------------------------------+------------------+
| CLOSID |{CDP}| RMID |
+-------------------------------+------------+-----+
| MPARTID | PMG |
| CPARTID(or MPARTID_hi) : MPARTID_lo | |
+--------------------------------------------+-----+
Where closid = cpartid (base_partid or mpartid_hi),
rmid = mpartid_lo * pmg_num + pmg,
with mpartid_lo in the range [0, partids_per_closid).
In this scheme, CLOSID and RMID are coupled together to form MPARTID,
which represents the monitor group PARTID.
In current patchset design, decoupling CLOSID and RMID, letting them
represent CPARTID and MPARTID respectively:
+---------------------------------------------+
| CLOSID |{CDP}|
+---------------------------------------------+
| CPARTID |
+---------------------------------------------+
+---------------------------------------------+
| RMID |
+---------------------------------------+-----+
| MPARTID | PMG |
| MPARTID_hi(or CPARTID) : MPARTID_lo | |
+---------------------------------------+-----+
Where closid = cpartid (base_partid or mpartid_hi),
rmid = mpartid * pmg_num + pmg,
and mpartid = mpartid_hi * partids_per_closid + mpartid_lo .
The design intent is to decouple CLOSID and RMID, rather than having
RMID depend on CLOSID to derive MPARTID. This decoupling is essential
for future dynamic allocation, because the relationship between MPARTID
and CPARTID must rely on table lookup rather than linear mapping. If
don't decouple in the static allocation design, we would need another
refactor when considering dynamic allocation extensibility.
The control path uses CLOSID alone (CPARTID), and the monitor path uses
RMID alone (the (MPARTID, PMG) pair). This definition also aligns
closely with the native resctrl concepts: CLOSID (Class of Service ID,
corresponding to CPARTID) and RMID (Resource Monitor ID, corresponding
to the (MPARTID, PMG) pair).
In the end, the number of control groups is determined by the number of
CPARTIDs. Both of these ID translation schemes support multiple control
groups.
Please allow me to rework the patch series into v9 based on my current
patches, incorporating your review feedback.
Best Regards,
Zeng Heng
^ permalink raw reply
* Re: [PATCH 3/3] arm64/coco: Add pKVM as a CC platform
From: Mostafa Saleh @ 2026-06-12 8:44 UTC (permalink / raw)
To: Aneesh Kumar K.V
Cc: linux-arm-kernel, linux-kernel, akpm, catalin.marinas, will, rppt,
maz
In-Reply-To: <yq5a1pemsmuj.fsf@kernel.org>
On Thu, Jun 04, 2026 at 02:29:00PM +0530, Aneesh Kumar K.V wrote:
> Mostafa Saleh <smostafa@google.com> writes:
>
> > pKVM does support memory encryption, expose that to the rest of
> > the kernel through cc_platform_has()
> >
> > At the moment, all devices inside the guest are emulated which
> > requires its memory to be shared back to the host (decrypted), so
> > set force_dma_unencrypted() to always return true.
> >
> > Although, typically pKVM guests rely on restricted-dma-pools to
> > bounce traffic, with this change, it is possible to solely rely on
> > the default SWIOTLB for that (assuming the appropriate size is set
> > from the command line)
> >
> > Signed-off-by: Mostafa Saleh <smostafa@google.com>
> > ---
> > This change is critical for the ongoing refactoring of the DMA-API[1]
> > that will break protected guests under pKVM with this patch. That is
> > due to this rework will make the state of the SWIOTLB and restricted
> > dma pools depends on the value returned by cc_platform_has()
> >
> > [1] https://lore.kernel.org/all/20260522042815.370873-1-aneesh.kumar@kernel.org/
> > ---
> > arch/arm64/include/asm/hypervisor.h | 13 +++++++++++++
> > arch/arm64/include/asm/mem_encrypt.h | 3 ++-
> > arch/arm64/kernel/rsi.c | 12 ------------
> > arch/arm64/mm/init.c | 15 ++++++++++++++-
> > drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c | 3 +++
> > 5 files changed, 32 insertions(+), 14 deletions(-)
> >
> > index d66291def0f4..26fe9c3f22e3 100644
[...]
> > --- a/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c
> > +++ b/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c
> > @@ -17,6 +17,7 @@
> > #include <asm/hypervisor.h>
> >
> > static size_t pkvm_granule;
> > +DEFINE_STATIC_KEY_FALSE_RO(pkvm_guest);
> >
>
> Do we need EXPORT_SYMBOL on this?
I was not sure about that, all users of this are in tree, I saw RME
code have the EXPORT but did not know why?
Thanks,
Mostafa
>
>
> -aneesh
^ permalink raw reply
* [PATCH v10 6/6] clk: scmi: Add i.MX95 OEM extension support for SCMI clock driver
From: Peng Fan (OSS) @ 2026-06-12 8:46 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Brian Masney, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sudeep Holla, Cristian Marussi,
Sebin Francis
Cc: linux-kernel, linux-clk, devicetree, arm-scmi, linux-arm-kernel,
Peng Fan
In-Reply-To: <20260612-clk-v10-v10-0-eb92484eda38@nxp.com>
From: Peng Fan <peng.fan@nxp.com>
- Introduce 'clk-scmi-oem.c' to support vendor-specific OEM extensions
for the SCMI clock driver, allows clean integration of vendor-specific
features without impacting the core SCMI clock driver logic.
- Extend 'clk-scmi.h' with 'scmi_clk_oem' structure and related
declarations.
- Initialize OEM extensions via 'scmi_clk_oem_init()'.
- Support querying OEM-specific features and setting spread spectrum.
- Pass 'scmi_device' to 'scmi_clk_ops_select()' for OEM data access.
Reviewed-by: Sebin Francis <sebin.francis@ti.com>
Reviewed-by: Cristian Marussi <cristian.marussi@arm.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
drivers/clk/Makefile | 2 +-
drivers/clk/clk-scmi-oem.c | 108 +++++++++++++++++++++++++++++++++++++++++++++
drivers/clk/clk-scmi.c | 19 ++++++--
drivers/clk/clk-scmi.h | 11 +++++
4 files changed, 136 insertions(+), 4 deletions(-)
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 6a726331b6c9e..c2ae700ec0f2a 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -98,7 +98,7 @@ obj-$(CONFIG_COMMON_CLK_RP1) += clk-rp1.o
obj-$(CONFIG_COMMON_CLK_RPMI) += clk-rpmi.o
obj-$(CONFIG_COMMON_CLK_HI655X) += clk-hi655x.o
obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o
-obj-$(CONFIG_COMMON_CLK_SCMI) += clk-scmi.o
+obj-$(CONFIG_COMMON_CLK_SCMI) += clk-scmi.o clk-scmi-oem.o
obj-$(CONFIG_COMMON_CLK_SCPI) += clk-scpi.o
obj-$(CONFIG_COMMON_CLK_SI5341) += clk-si5341.o
obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o
diff --git a/drivers/clk/clk-scmi-oem.c b/drivers/clk/clk-scmi-oem.c
new file mode 100644
index 0000000000000..be11d359b4ec3
--- /dev/null
+++ b/drivers/clk/clk-scmi-oem.c
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * The Vendor OEM extension for System Control and Power Interface (SCMI)
+ * Protocol based clock driver
+ *
+ * Copyright 2025 NXP
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/scmi_imx_protocol.h>
+#include <linux/scmi_protocol.h>
+
+#include "clk-scmi.h"
+
+#define SCMI_CLOCK_CFG_IMX_SSC 0x80
+#define SCMI_CLOCK_IMX_SS_PERCENTAGE_MASK GENMASK(7, 0)
+#define SCMI_CLOCK_IMX_SS_MOD_FREQ_MASK GENMASK(23, 8)
+#define SCMI_CLOCK_IMX_SS_ENABLE_MASK BIT(24)
+
+/*
+ * Selection is based on SCMI vendor_id/sub_vendor_id and optional machine
+ * compatible string, without involving impl_ver. impl_ver‑specific behavior
+ * should be considered a bug and handled via SCMI Quirk framework.
+ */
+struct scmi_clk_oem_info {
+ char *vendor_id;
+ char *sub_vendor_id;
+ char *compatible;
+ const void *data;
+};
+
+static int
+scmi_clk_imx_set_spread_spectrum(struct clk_hw *hw,
+ const struct clk_spread_spectrum *ss_conf)
+{
+ struct scmi_clk *clk = to_scmi_clk(hw);
+ int ret;
+ u32 val;
+
+ /*
+ * extConfigValue[7:0] - spread percentage (%)
+ * extConfigValue[23:8] - Modulation Frequency
+ * extConfigValue[24] - Enable/Disable
+ * extConfigValue[31:25] - Reserved
+ */
+ val = FIELD_PREP(SCMI_CLOCK_IMX_SS_PERCENTAGE_MASK, ss_conf->spread_bp / 10000);
+ val |= FIELD_PREP(SCMI_CLOCK_IMX_SS_MOD_FREQ_MASK, ss_conf->modfreq_hz);
+ if (ss_conf->method != CLK_SPREAD_NO)
+ val |= SCMI_CLOCK_IMX_SS_ENABLE_MASK;
+ ret = scmi_proto_clk_ops->config_oem_set(clk->ph, clk->id,
+ SCMI_CLOCK_CFG_IMX_SSC,
+ val, false);
+ if (ret)
+ dev_warn(clk->dev,
+ "Failed to set spread spectrum(%u,%u,%u) for clock ID %d\n",
+ ss_conf->modfreq_hz, ss_conf->spread_bp, ss_conf->method,
+ clk->id);
+
+ return ret;
+}
+
+static int
+scmi_clk_imx_query_oem_feats(const struct scmi_protocol_handle *ph, u32 id,
+ unsigned int *feats_key)
+{
+ int ret;
+ u32 val;
+
+ ret = scmi_proto_clk_ops->config_oem_get(ph, id,
+ SCMI_CLOCK_CFG_IMX_SSC,
+ &val, NULL, false);
+ if (!ret)
+ *feats_key |= BIT(SCMI_CLK_EXT_OEM_SSC_SUPPORTED);
+
+ return 0;
+}
+
+static const struct scmi_clk_oem scmi_clk_oem_imx = {
+ .query_ext_oem_feats = scmi_clk_imx_query_oem_feats,
+ .set_spread_spectrum = scmi_clk_imx_set_spread_spectrum,
+};
+
+static const struct scmi_clk_oem_info info[] = {
+ { SCMI_IMX_VENDOR, SCMI_IMX_SUBVENDOR, NULL, &scmi_clk_oem_imx },
+};
+
+int scmi_clk_oem_init(struct scmi_device *sdev)
+{
+ const struct scmi_handle *handle = sdev->handle;
+ int i, size = ARRAY_SIZE(info);
+
+ for (i = 0; i < size; i++) {
+ if (strcmp(handle->version->vendor_id, info[i].vendor_id) ||
+ strcmp(handle->version->sub_vendor_id, info[i].sub_vendor_id))
+ continue;
+ if (info[i].compatible &&
+ !of_machine_is_compatible(info[i].compatible))
+ continue;
+
+ break;
+ }
+
+ if (i < size)
+ dev_set_drvdata(&sdev->dev, (void *)info[i].data);
+
+ return 0;
+}
diff --git a/drivers/clk/clk-scmi.c b/drivers/clk/clk-scmi.c
index d88e78cc9a12e..2dd50c5b4ea8f 100644
--- a/drivers/clk/clk-scmi.c
+++ b/drivers/clk/clk-scmi.c
@@ -13,6 +13,8 @@
#include <linux/module.h>
#include <linux/scmi_protocol.h>
+#include "clk-scmi.h"
+
const struct scmi_clk_proto_ops *scmi_proto_clk_ops;
static unsigned long scmi_clk_recalc_rate(struct clk_hw *hw,
@@ -210,6 +212,7 @@ static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk,
static const struct clk_ops *
scmi_clk_ops_alloc(struct device *dev, unsigned long feats_key)
{
+ struct scmi_clk_oem *oem_data = dev_get_drvdata(dev);
struct clk_ops *ops;
ops = devm_kzalloc(dev, sizeof(*ops), GFP_KERNEL);
@@ -256,11 +259,15 @@ scmi_clk_ops_alloc(struct device *dev, unsigned long feats_key)
ops->set_duty_cycle = scmi_clk_set_duty_cycle;
}
+ if (oem_data && (feats_key & BIT(SCMI_CLK_EXT_OEM_SSC_SUPPORTED)))
+ ops->set_spread_spectrum = oem_data->set_spread_spectrum;
+
return ops;
}
/**
* scmi_clk_ops_select() - Select a proper set of clock operations
+ * @sdev: pointer to the SCMI device
* @sclk: A reference to an SCMI clock descriptor
* @atomic_capable: A flag to indicate if atomic mode is supported by the
* transport
@@ -285,8 +292,8 @@ scmi_clk_ops_alloc(struct device *dev, unsigned long feats_key)
* NULL otherwise.
*/
static const struct clk_ops *
-scmi_clk_ops_select(struct scmi_clk *sclk, bool atomic_capable,
- unsigned int atomic_threshold_us,
+scmi_clk_ops_select(struct scmi_device *sdev, struct scmi_clk *sclk,
+ bool atomic_capable, unsigned int atomic_threshold_us,
const struct clk_ops **clk_ops_db, size_t db_size)
{
int ret;
@@ -294,6 +301,7 @@ scmi_clk_ops_select(struct scmi_clk *sclk, bool atomic_capable,
const struct scmi_clock_info *ci = sclk->info;
unsigned int feats_key = 0;
const struct clk_ops *ops;
+ struct scmi_clk_oem *oem_data = dev_get_drvdata(&sdev->dev);
/*
* Note that when transport is atomic but SCMI protocol did not
@@ -318,6 +326,9 @@ scmi_clk_ops_select(struct scmi_clk *sclk, bool atomic_capable,
&val, NULL, false);
if (!ret)
feats_key |= BIT(SCMI_CLK_DUTY_CYCLE_SUPPORTED);
+
+ if (oem_data && oem_data->query_ext_oem_feats)
+ oem_data->query_ext_oem_feats(sclk->ph, sclk->id, &feats_key);
}
if (WARN_ON(feats_key >= db_size))
@@ -375,6 +386,8 @@ static int scmi_clocks_probe(struct scmi_device *sdev)
clk_data->num = count;
hws = clk_data->hws;
+ scmi_clk_oem_init(sdev);
+
transport_is_atomic = handle->is_transport_atomic(handle,
&atomic_threshold_us);
@@ -406,7 +419,7 @@ static int scmi_clocks_probe(struct scmi_device *sdev)
* to avoid sharing the devm_ allocated clk_ops between multiple
* SCMI clk driver instances.
*/
- scmi_ops = scmi_clk_ops_select(sclk, transport_is_atomic,
+ scmi_ops = scmi_clk_ops_select(sdev, sclk, transport_is_atomic,
atomic_threshold_us,
scmi_clk_ops_db,
ARRAY_SIZE(scmi_clk_ops_db));
diff --git a/drivers/clk/clk-scmi.h b/drivers/clk/clk-scmi.h
index 6ef6adc77c836..d7f63f36c56d1 100644
--- a/drivers/clk/clk-scmi.h
+++ b/drivers/clk/clk-scmi.h
@@ -7,6 +7,7 @@
#define __SCMI_CLK_H
#include <linux/bits.h>
+#include <linux/clk-provider.h>
#include <linux/scmi_protocol.h>
#include <linux/types.h>
@@ -19,6 +20,7 @@ enum scmi_clk_feats {
SCMI_CLK_RATE_CTRL_SUPPORTED,
SCMI_CLK_PARENT_CTRL_SUPPORTED,
SCMI_CLK_DUTY_CYCLE_SUPPORTED,
+ SCMI_CLK_EXT_OEM_SSC_SUPPORTED,
SCMI_CLK_FEATS_COUNT
};
@@ -37,4 +39,13 @@ struct scmi_clk {
extern const struct scmi_clk_proto_ops *scmi_proto_clk_ops;
+struct scmi_clk_oem {
+ int (*query_ext_oem_feats)(const struct scmi_protocol_handle *ph,
+ u32 id, unsigned int *feats_key);
+ int (*set_spread_spectrum)(struct clk_hw *hw,
+ const struct clk_spread_spectrum *ss_conf);
+};
+
+int scmi_clk_oem_init(struct scmi_device *dev);
+
#endif
--
2.34.1
^ permalink raw reply related
* [PATCH v10 5/6] clk: scmi: Introduce common header for SCMI clock interface
From: Peng Fan (OSS) @ 2026-06-12 8:46 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Brian Masney, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sudeep Holla, Cristian Marussi,
Sebin Francis
Cc: linux-kernel, linux-clk, devicetree, arm-scmi, linux-arm-kernel,
Peng Fan
In-Reply-To: <20260612-clk-v10-v10-0-eb92484eda38@nxp.com>
From: Peng Fan <peng.fan@nxp.com>
Added a new header file 'clk-scmi.h' to define common structures and
interfaces for the SCMI clock driver. This header will also be used by
OEM-specific extensions to ensure consistency and reusability.
Moved relevant structure definitions from the driver implementation to
'clk-scmi.h' to facilitate shared usage.
Reviewed-by: Sebin Francis <sebin.francis@ti.com>
Reviewed-by: Cristian Marussi <cristian.marussi@arm.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
drivers/clk/clk-scmi.c | 27 +--------------------------
drivers/clk/clk-scmi.h | 40 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 41 insertions(+), 26 deletions(-)
diff --git a/drivers/clk/clk-scmi.c b/drivers/clk/clk-scmi.c
index 7c562559ad8bb..d88e78cc9a12e 100644
--- a/drivers/clk/clk-scmi.c
+++ b/drivers/clk/clk-scmi.c
@@ -13,32 +13,7 @@
#include <linux/module.h>
#include <linux/scmi_protocol.h>
-#define NOT_ATOMIC false
-#define ATOMIC true
-
-enum scmi_clk_feats {
- SCMI_CLK_ATOMIC_SUPPORTED,
- SCMI_CLK_STATE_CTRL_SUPPORTED,
- SCMI_CLK_RATE_CTRL_SUPPORTED,
- SCMI_CLK_PARENT_CTRL_SUPPORTED,
- SCMI_CLK_DUTY_CYCLE_SUPPORTED,
- SCMI_CLK_FEATS_COUNT
-};
-
-#define SCMI_MAX_CLK_OPS BIT(SCMI_CLK_FEATS_COUNT)
-
-static const struct scmi_clk_proto_ops *scmi_proto_clk_ops;
-
-struct scmi_clk {
- u32 id;
- struct device *dev;
- struct clk_hw hw;
- const struct scmi_clock_info *info;
- const struct scmi_protocol_handle *ph;
- struct clk_parent_data *parent_data;
-};
-
-#define to_scmi_clk(clk) container_of(clk, struct scmi_clk, hw)
+const struct scmi_clk_proto_ops *scmi_proto_clk_ops;
static unsigned long scmi_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
diff --git a/drivers/clk/clk-scmi.h b/drivers/clk/clk-scmi.h
new file mode 100644
index 0000000000000..6ef6adc77c836
--- /dev/null
+++ b/drivers/clk/clk-scmi.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2025 NXP
+ */
+
+#ifndef __SCMI_CLK_H
+#define __SCMI_CLK_H
+
+#include <linux/bits.h>
+#include <linux/scmi_protocol.h>
+#include <linux/types.h>
+
+#define NOT_ATOMIC false
+#define ATOMIC true
+
+enum scmi_clk_feats {
+ SCMI_CLK_ATOMIC_SUPPORTED,
+ SCMI_CLK_STATE_CTRL_SUPPORTED,
+ SCMI_CLK_RATE_CTRL_SUPPORTED,
+ SCMI_CLK_PARENT_CTRL_SUPPORTED,
+ SCMI_CLK_DUTY_CYCLE_SUPPORTED,
+ SCMI_CLK_FEATS_COUNT
+};
+
+#define SCMI_MAX_CLK_OPS BIT(SCMI_CLK_FEATS_COUNT)
+
+struct scmi_clk {
+ u32 id;
+ struct device *dev;
+ struct clk_hw hw;
+ const struct scmi_clock_info *info;
+ const struct scmi_protocol_handle *ph;
+ struct clk_parent_data *parent_data;
+};
+
+#define to_scmi_clk(clk) container_of(clk, struct scmi_clk, hw)
+
+extern const struct scmi_clk_proto_ops *scmi_proto_clk_ops;
+
+#endif
--
2.34.1
^ permalink raw reply related
* [PATCH v10 4/6] clk: Add KUnit tests for assigned-clock-sscs
From: Peng Fan (OSS) @ 2026-06-12 8:46 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Brian Masney, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sudeep Holla, Cristian Marussi,
Sebin Francis
Cc: linux-kernel, linux-clk, devicetree, arm-scmi, linux-arm-kernel,
Peng Fan
In-Reply-To: <20260612-clk-v10-v10-0-eb92484eda38@nxp.com>
From: Peng Fan <peng.fan@nxp.com>
Add KUnit test coverage for the assigned-clock-sscs DT property that
configures spread spectrum on clocks before they are used.
Extend the existing test infrastructure to support spread spectrum:
- Add struct clk_spread_spectrum field to clk_dummy_context and a
clk_dummy_set_spread_spectrum callback
- Wire set_spread_spectrum into all dummy clock ops
- Extend clk_assigned_rates_register_clk and test parameter struct
to propagate initial SSCS values
Add a new separate test suite clk_assigned_sscs with three categories:
1. clk_assigned_sscs_assigns_one — verifies that a single
assigned-clock-sscs entry correctly configures spread spectrum
on one clock, testing both provider and consumer paths
2. clk_assigned_sscs_assigns_multiple — verifies that multiple
assigned-clock-sscs entries configure spread spectrum on two
clocks, testing both provider and consumer paths
3. clk_assigned_sscs_skips — verifies that malformed DT properties
are correctly skipped without error: missing assigned-clocks,
zero-valued SSCS, and null phandles, tested for both provider
and consumer scenarios
New DT overlays are added for all test scenarios:
- kunit_clk_assigned_sscs_one{,consumer} — single valid entry
- kunit_clk_assigned_sscs_multiple{,consumer} — two valid entries
- kunit_clk_assigned_sscs_without{,consumer} — missing assigned-clocks
- kunit_clk_assigned_sscs_zero{,consumer} — all-zero SSCS values
- kunit_clk_assigned_sscs_null{,consumer} — null phandle
Co-developed-by: Brian Masney <bmasney@redhat.com>
Signed-off-by: Brian Masney <bmasney@redhat.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
drivers/clk/Makefile | 10 +
drivers/clk/clk_test.c | 203 ++++++++++++++++++++-
drivers/clk/kunit_clk_assigned_rates.h | 10 +
.../clk/kunit_clk_assigned_rates_u64_multiple.dtso | 6 +
...t_clk_assigned_rates_u64_multiple_consumer.dtso | 6 +
drivers/clk/kunit_clk_assigned_rates_u64_one.dtso | 3 +
.../kunit_clk_assigned_rates_u64_one_consumer.dtso | 3 +
drivers/clk/kunit_clk_assigned_sscs_multiple.dtso | 20 ++
.../kunit_clk_assigned_sscs_multiple_consumer.dtso | 24 +++
drivers/clk/kunit_clk_assigned_sscs_null.dtso | 16 ++
.../clk/kunit_clk_assigned_sscs_null_consumer.dtso | 20 ++
drivers/clk/kunit_clk_assigned_sscs_one.dtso | 16 ++
.../clk/kunit_clk_assigned_sscs_one_consumer.dtso | 20 ++
drivers/clk/kunit_clk_assigned_sscs_without.dtso | 15 ++
.../kunit_clk_assigned_sscs_without_consumer.dtso | 19 ++
drivers/clk/kunit_clk_assigned_sscs_zero.dtso | 12 ++
.../clk/kunit_clk_assigned_sscs_zero_consumer.dtso | 16 ++
17 files changed, 416 insertions(+), 3 deletions(-)
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index cc108a75a9008..6a726331b6c9e 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -18,6 +18,16 @@ clk-test-y := clk_test.o \
kunit_clk_assigned_rates_without_consumer.dtbo.o \
kunit_clk_assigned_rates_zero.dtbo.o \
kunit_clk_assigned_rates_zero_consumer.dtbo.o \
+ kunit_clk_assigned_sscs_one.dtbo.o \
+ kunit_clk_assigned_sscs_one_consumer.dtbo.o \
+ kunit_clk_assigned_sscs_multiple.dtbo.o \
+ kunit_clk_assigned_sscs_multiple_consumer.dtbo.o \
+ kunit_clk_assigned_sscs_null.dtbo.o \
+ kunit_clk_assigned_sscs_null_consumer.dtbo.o \
+ kunit_clk_assigned_sscs_without.dtbo.o \
+ kunit_clk_assigned_sscs_without_consumer.dtbo.o \
+ kunit_clk_assigned_sscs_zero.dtbo.o \
+ kunit_clk_assigned_sscs_zero_consumer.dtbo.o \
kunit_clk_hw_get_dev_of_node.dtbo.o \
kunit_clk_parent_data_test.dtbo.o
obj-$(CONFIG_COMMON_CLK) += clk-divider.o
diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c
index b1961daac5e22..824adc95e0b2f 100644
--- a/drivers/clk/clk_test.c
+++ b/drivers/clk/clk_test.c
@@ -28,6 +28,7 @@ static const struct clk_ops empty_clk_ops = { };
struct clk_dummy_context {
struct clk_hw hw;
unsigned long rate;
+ struct clk_spread_spectrum sscs;
};
static unsigned long clk_dummy_recalc_rate(struct clk_hw *hw,
@@ -83,6 +84,17 @@ static int clk_dummy_set_rate(struct clk_hw *hw,
return 0;
}
+static int clk_dummy_set_spread_spectrum(struct clk_hw *hw,
+ const struct clk_spread_spectrum *ss_conf)
+{
+ struct clk_dummy_context *ctx =
+ container_of(hw, struct clk_dummy_context, hw);
+
+ ctx->sscs = *ss_conf;
+
+ return 0;
+}
+
static int clk_dummy_single_set_parent(struct clk_hw *hw, u8 index)
{
if (index >= clk_hw_get_num_parents(hw))
@@ -100,18 +112,21 @@ static const struct clk_ops clk_dummy_rate_ops = {
.recalc_rate = clk_dummy_recalc_rate,
.determine_rate = clk_dummy_determine_rate,
.set_rate = clk_dummy_set_rate,
+ .set_spread_spectrum = clk_dummy_set_spread_spectrum,
};
static const struct clk_ops clk_dummy_maximize_rate_ops = {
.recalc_rate = clk_dummy_recalc_rate,
.determine_rate = clk_dummy_maximize_rate,
.set_rate = clk_dummy_set_rate,
+ .set_spread_spectrum = clk_dummy_set_spread_spectrum,
};
static const struct clk_ops clk_dummy_minimize_rate_ops = {
.recalc_rate = clk_dummy_recalc_rate,
.determine_rate = clk_dummy_minimize_rate,
.set_rate = clk_dummy_set_rate,
+ .set_spread_spectrum = clk_dummy_set_spread_spectrum,
};
static const struct clk_ops clk_dummy_single_parent_ops = {
@@ -3097,6 +3112,7 @@ struct clk_assigned_rates_context {
* @overlay_end: Pointer to end of DT overlay to apply for test
* @rate0: Initial rate of first clk
* @rate1: Initial rate of second clk
+ * @sscs: Initial spread spectrum settings
* @consumer_test: true if a consumer is being tested
*/
struct clk_assigned_rates_test_param {
@@ -3105,6 +3121,7 @@ struct clk_assigned_rates_test_param {
u8 *overlay_end;
unsigned long rate0;
unsigned long rate1;
+ struct clk_spread_spectrum sscs;
bool consumer_test;
};
@@ -3116,7 +3133,7 @@ static void
clk_assigned_rates_register_clk(struct kunit *test,
struct clk_dummy_context *ctx,
struct device_node *np, const char *name,
- unsigned long rate)
+ unsigned long rate, const struct clk_spread_spectrum *sscs)
{
struct clk_init_data init = { };
@@ -3124,6 +3141,7 @@ clk_assigned_rates_register_clk(struct kunit *test,
init.ops = &clk_dummy_rate_ops;
ctx->hw.init = &init;
ctx->rate = rate;
+ ctx->sscs = *sscs;
KUNIT_ASSERT_EQ(test, 0, of_clk_hw_register_kunit(test, np, &ctx->hw));
KUNIT_ASSERT_EQ(test, ctx->rate, rate);
@@ -3167,14 +3185,16 @@ static int clk_assigned_rates_test_init(struct kunit *test)
KUNIT_ASSERT_LT(test, clk_cells, 2);
clk_assigned_rates_register_clk(test, &ctx->clk0, np,
- "test_assigned_rate0", test_param->rate0);
+ "test_assigned_rate0", test_param->rate0,
+ &test_param->sscs);
if (clk_cells == 0) {
KUNIT_ASSERT_EQ(test, 0,
of_clk_add_hw_provider_kunit(test, np, of_clk_hw_simple_get,
&ctx->clk0.hw));
} else if (clk_cells == 1) {
clk_assigned_rates_register_clk(test, &ctx->clk1, np,
- "test_assigned_rate1", test_param->rate1);
+ "test_assigned_rate1", test_param->rate1,
+ &test_param->sscs);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test,
data = kunit_kzalloc(test, struct_size(data, hws, 2), GFP_KERNEL));
@@ -3403,6 +3423,182 @@ static struct kunit_suite clk_assigned_rates_suite = {
.init = clk_assigned_rates_test_init,
};
+OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_one);
+OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_one_consumer);
+OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_multiple);
+OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_multiple_consumer);
+OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_without);
+OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_without_consumer);
+OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_zero);
+OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_zero_consumer);
+OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_null);
+OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_null_consumer);
+
+static void clk_assigned_sscs_assigns_one(struct kunit *test)
+{
+ struct clk_assigned_rates_context *ctx = test->priv;
+
+ KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.modfreq_hz, ASSIGNED_SSCS_0_MODFREQ);
+ KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.spread_bp, ASSIGNED_SSCS_0_SPREAD);
+ KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.method, ASSIGNED_SSCS_0_METHOD);
+}
+
+/* Test cases that assign sscs for one clk */
+static const struct clk_assigned_rates_test_param clk_assigned_sscs_assigns_one_test_params[] = {
+ {
+ /*
+ * Test that a single cell assigned-clock-sscs property
+ * assigns the sscs when the property is in the provider.
+ */
+ .desc = "provider assigns",
+ TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_one),
+ },
+ {
+ /*
+ * Test that a single cell assigned-clock-sscs property
+ * assigns the sscs when the property is in the consumer.
+ */
+ .desc = "consumer assigns",
+ TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_one_consumer),
+ .consumer_test = true,
+ },
+};
+KUNIT_ARRAY_PARAM_DESC(clk_assigned_sscs_assigns_one,
+ clk_assigned_sscs_assigns_one_test_params, desc)
+
+static void clk_assigned_sscs_assigns_multiple(struct kunit *test)
+{
+ struct clk_assigned_rates_context *ctx = test->priv;
+
+ KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.modfreq_hz, ASSIGNED_SSCS_0_MODFREQ);
+ KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.spread_bp, ASSIGNED_SSCS_0_SPREAD);
+ KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.method, ASSIGNED_SSCS_0_METHOD);
+ KUNIT_EXPECT_EQ(test, ctx->clk1.sscs.modfreq_hz, ASSIGNED_SSCS_1_MODFREQ);
+ KUNIT_EXPECT_EQ(test, ctx->clk1.sscs.spread_bp, ASSIGNED_SSCS_1_SPREAD);
+ KUNIT_EXPECT_EQ(test, ctx->clk1.sscs.method, ASSIGNED_SSCS_1_METHOD);
+}
+
+/* Test cases that assign sscs for multiple clks */
+static const
+struct clk_assigned_rates_test_param clk_assigned_sscs_assigns_multiple_test_params[] = {
+ {
+ /*
+ * Test that a multiple cell assigned-clock-sscs property
+ * assigns the sscs when the property is in the provider.
+ */
+ .desc = "provider assigns",
+ TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_multiple),
+ },
+ {
+ /*
+ * Test that a multiple cell assigned-clock-sscs property
+ * assigns the sscs when the property is in the consumer.
+ */
+ .desc = "consumer assigns",
+ TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_multiple_consumer),
+ .consumer_test = true,
+ },
+};
+KUNIT_ARRAY_PARAM_DESC(clk_assigned_sscs_assigns_multiple,
+ clk_assigned_sscs_assigns_multiple_test_params,
+ desc)
+
+static void clk_assigned_sscs_skips(struct kunit *test)
+{
+ struct clk_assigned_rates_context *ctx = test->priv;
+ const struct clk_assigned_rates_test_param *test_param = test->param_value;
+
+ KUNIT_EXPECT_NE(test, ctx->clk0.sscs.modfreq_hz, ASSIGNED_SSCS_0_MODFREQ);
+ KUNIT_EXPECT_NE(test, ctx->clk0.sscs.spread_bp, ASSIGNED_SSCS_0_SPREAD);
+ KUNIT_EXPECT_NE(test, ctx->clk0.sscs.method, ASSIGNED_SSCS_0_METHOD);
+ KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.modfreq_hz, test_param->sscs.modfreq_hz);
+ KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.spread_bp, test_param->sscs.spread_bp);
+ KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.method, test_param->sscs.method);
+}
+
+/* Test cases that skip changing the sscs due to malformed DT */
+static const struct clk_assigned_rates_test_param clk_assigned_sscs_skips_test_params[] = {
+ {
+ /*
+ * Test that an assigned-clock-sscs property without an assigned-clocks
+ * property fails when the property is in the provider.
+ */
+ .desc = "provider missing assigned-clocks",
+ TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_without),
+ .sscs = {50000, 60000, 3},
+ },
+ {
+ /*
+ * Test that an assigned-clock-sscs property without an assigned-clocks
+ * property fails when the property is in the consumer.
+ */
+ .desc = "consumer missing assigned-clocks",
+ TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_without_consumer),
+ .sscs = {50000, 60000, 3},
+ .consumer_test = true,
+ },
+ {
+ /*
+ * Test that an assigned-clock-sscs property of zero doesn't
+ * set sscs when the property is in the provider.
+ */
+ .desc = "provider assigned-clock-sscs of zero",
+ TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_zero),
+ .sscs = {50000, 60000, 3},
+ },
+ {
+ /*
+ * Test that an assigned-clock-sscs property of zero doesn't
+ * set sscs when the property is in the consumer.
+ */
+ .desc = "consumer assigned-clock-sscs of zero",
+ TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_zero_consumer),
+ .sscs = {50000, 60000, 3},
+ .consumer_test = true,
+ },
+ {
+ /*
+ * Test that an assigned-clocks property with a null phandle
+ * doesn't set sscs when the property is in the provider.
+ */
+ .desc = "provider assigned-clocks null phandle",
+ TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_null),
+ .sscs = {50000, 60000, 3},
+ },
+ {
+ /*
+ * Test that an assigned-clocks property with a null phandle
+ * doesn't set sscs when the property is in the consumer.
+ */
+ .desc = "consumer assigned-clocks null phandle",
+ TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_null_consumer),
+ .sscs = {50000, 60000, 3},
+ .consumer_test = true,
+ },
+};
+KUNIT_ARRAY_PARAM_DESC(clk_assigned_sscs_skips,
+ clk_assigned_sscs_skips_test_params,
+ desc)
+
+static struct kunit_case clk_assigned_sscs_test_cases[] = {
+ KUNIT_CASE_PARAM(clk_assigned_sscs_assigns_one,
+ clk_assigned_sscs_assigns_one_gen_params),
+ KUNIT_CASE_PARAM(clk_assigned_sscs_assigns_multiple,
+ clk_assigned_sscs_assigns_multiple_gen_params),
+ KUNIT_CASE_PARAM(clk_assigned_sscs_skips,
+ clk_assigned_sscs_skips_gen_params),
+ {}
+};
+
+/*
+ * Test suite for assigned-clock-sscs DT property.
+ */
+static struct kunit_suite clk_assigned_sscs_suite = {
+ .name = "clk_assigned_sscs",
+ .test_cases = clk_assigned_sscs_test_cases,
+ .init = clk_assigned_rates_test_init,
+};
+
static const struct clk_init_data clk_hw_get_dev_of_node_init_data = {
.name = "clk_hw_get_dev_of_node",
.ops = &empty_clk_ops,
@@ -3544,6 +3740,7 @@ static struct kunit_suite clk_hw_get_dev_of_node_test_suite = {
kunit_test_suites(
&clk_assigned_rates_suite,
+ &clk_assigned_sscs_suite,
&clk_hw_get_dev_of_node_test_suite,
&clk_leaf_mux_set_rate_parent_test_suite,
&clk_test_suite,
diff --git a/drivers/clk/kunit_clk_assigned_rates.h b/drivers/clk/kunit_clk_assigned_rates.h
index df2d84dcaa935..d7ae5ec2d25be 100644
--- a/drivers/clk/kunit_clk_assigned_rates.h
+++ b/drivers/clk/kunit_clk_assigned_rates.h
@@ -1,8 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <dt-bindings/clock/clock.h>
+
#ifndef _KUNIT_CLK_ASSIGNED_RATES_H
#define _KUNIT_CLK_ASSIGNED_RATES_H
#define ASSIGNED_RATES_0_RATE 1600000
#define ASSIGNED_RATES_1_RATE 9700000
+#define ASSIGNED_SSCS_0_MODFREQ 10000
+#define ASSIGNED_SSCS_0_SPREAD 30000
+#define ASSIGNED_SSCS_0_METHOD CLK_SSC_CENTER_SPREAD
+#define ASSIGNED_SSCS_1_MODFREQ 20000
+#define ASSIGNED_SSCS_1_SPREAD 40000
+#define ASSIGNED_SSCS_1_METHOD CLK_SSC_UP_SPREAD
+
#endif
diff --git a/drivers/clk/kunit_clk_assigned_rates_u64_multiple.dtso b/drivers/clk/kunit_clk_assigned_rates_u64_multiple.dtso
index 389b4e2eb7f74..3a717dab2d00b 100644
--- a/drivers/clk/kunit_clk_assigned_rates_u64_multiple.dtso
+++ b/drivers/clk/kunit_clk_assigned_rates_u64_multiple.dtso
@@ -12,5 +12,11 @@ clk: kunit-clock {
<&clk 1>;
assigned-clock-rates-u64 = /bits/ 64 <ASSIGNED_RATES_0_RATE>,
/bits/ 64 <ASSIGNED_RATES_1_RATE>;
+ assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+ ASSIGNED_SSCS_0_SPREAD
+ ASSIGNED_SSCS_0_METHOD>,
+ <ASSIGNED_SSCS_1_MODFREQ
+ ASSIGNED_SSCS_1_SPREAD
+ ASSIGNED_SSCS_1_METHOD>;
};
};
diff --git a/drivers/clk/kunit_clk_assigned_rates_u64_multiple_consumer.dtso b/drivers/clk/kunit_clk_assigned_rates_u64_multiple_consumer.dtso
index 3e117fd59b7da..cbee7cbad068f 100644
--- a/drivers/clk/kunit_clk_assigned_rates_u64_multiple_consumer.dtso
+++ b/drivers/clk/kunit_clk_assigned_rates_u64_multiple_consumer.dtso
@@ -16,5 +16,11 @@ kunit-clock-consumer {
<&clk 1>;
assigned-clock-rates-u64 = /bits/ 64 <ASSIGNED_RATES_0_RATE>,
/bits/ 64 <ASSIGNED_RATES_1_RATE>;
+ assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+ ASSIGNED_SSCS_0_SPREAD
+ ASSIGNED_SSCS_0_METHOD>,
+ <ASSIGNED_SSCS_1_MODFREQ
+ ASSIGNED_SSCS_1_SPREAD
+ ASSIGNED_SSCS_1_METHOD>;
};
};
diff --git a/drivers/clk/kunit_clk_assigned_rates_u64_one.dtso b/drivers/clk/kunit_clk_assigned_rates_u64_one.dtso
index 87041264e8f54..9b04d6927f083 100644
--- a/drivers/clk/kunit_clk_assigned_rates_u64_one.dtso
+++ b/drivers/clk/kunit_clk_assigned_rates_u64_one.dtso
@@ -10,5 +10,8 @@ clk: kunit-clock {
#clock-cells = <0>;
assigned-clocks = <&clk>;
assigned-clock-rates-u64 = /bits/ 64 <ASSIGNED_RATES_0_RATE>;
+ assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+ ASSIGNED_SSCS_0_SPREAD
+ ASSIGNED_SSCS_0_METHOD>;
};
};
diff --git a/drivers/clk/kunit_clk_assigned_rates_u64_one_consumer.dtso b/drivers/clk/kunit_clk_assigned_rates_u64_one_consumer.dtso
index 3259c003aec0b..4784d40520f41 100644
--- a/drivers/clk/kunit_clk_assigned_rates_u64_one_consumer.dtso
+++ b/drivers/clk/kunit_clk_assigned_rates_u64_one_consumer.dtso
@@ -14,5 +14,8 @@ kunit-clock-consumer {
compatible = "test,clk-consumer";
assigned-clocks = <&clk>;
assigned-clock-rates-u64 = /bits/ 64 <ASSIGNED_RATES_0_RATE>;
+ assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+ ASSIGNED_SSCS_0_SPREAD
+ ASSIGNED_SSCS_0_METHOD>;
};
};
diff --git a/drivers/clk/kunit_clk_assigned_sscs_multiple.dtso b/drivers/clk/kunit_clk_assigned_sscs_multiple.dtso
new file mode 100644
index 0000000000000..e3472f95987c3
--- /dev/null
+++ b/drivers/clk/kunit_clk_assigned_sscs_multiple.dtso
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+/plugin/;
+
+#include "kunit_clk_assigned_rates.h"
+
+&{/} {
+ clk: kunit-clock {
+ compatible = "test,clk-assigned-rates";
+ #clock-cells = <1>;
+ assigned-clocks = <&clk 0>,
+ <&clk 1>;
+ assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+ ASSIGNED_SSCS_0_SPREAD
+ ASSIGNED_SSCS_0_METHOD>,
+ <ASSIGNED_SSCS_1_MODFREQ
+ ASSIGNED_SSCS_1_SPREAD
+ ASSIGNED_SSCS_1_METHOD>;
+ };
+};
diff --git a/drivers/clk/kunit_clk_assigned_sscs_multiple_consumer.dtso b/drivers/clk/kunit_clk_assigned_sscs_multiple_consumer.dtso
new file mode 100644
index 0000000000000..6e8971bd272ab
--- /dev/null
+++ b/drivers/clk/kunit_clk_assigned_sscs_multiple_consumer.dtso
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+/plugin/;
+
+#include "kunit_clk_assigned_rates.h"
+
+&{/} {
+ clk: kunit-clock {
+ compatible = "test,clk-assigned-rates";
+ #clock-cells = <1>;
+ };
+
+ kunit-clock-consumer {
+ compatible = "test,clk-consumer";
+ assigned-clocks = <&clk 0>,
+ <&clk 1>;
+ assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+ ASSIGNED_SSCS_0_SPREAD
+ ASSIGNED_SSCS_0_METHOD>,
+ <ASSIGNED_SSCS_1_MODFREQ
+ ASSIGNED_SSCS_1_SPREAD
+ ASSIGNED_SSCS_1_METHOD>;
+ };
+};
diff --git a/drivers/clk/kunit_clk_assigned_sscs_null.dtso b/drivers/clk/kunit_clk_assigned_sscs_null.dtso
new file mode 100644
index 0000000000000..43b2068c845de
--- /dev/null
+++ b/drivers/clk/kunit_clk_assigned_sscs_null.dtso
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+/plugin/;
+
+#include "kunit_clk_assigned_rates.h"
+
+&{/} {
+ clk: kunit-clock {
+ compatible = "test,clk-assigned-rates";
+ #clock-cells = <0>;
+ assigned-clocks = <0>;
+ assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+ ASSIGNED_SSCS_0_SPREAD
+ ASSIGNED_SSCS_0_METHOD>;
+ };
+};
diff --git a/drivers/clk/kunit_clk_assigned_sscs_null_consumer.dtso b/drivers/clk/kunit_clk_assigned_sscs_null_consumer.dtso
new file mode 100644
index 0000000000000..bda008f5aaa35
--- /dev/null
+++ b/drivers/clk/kunit_clk_assigned_sscs_null_consumer.dtso
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+/plugin/;
+
+#include "kunit_clk_assigned_rates.h"
+
+&{/} {
+ clk: kunit-clock {
+ compatible = "test,clk-assigned-rates";
+ #clock-cells = <0>;
+ };
+
+ kunit-clock-consumer {
+ compatible = "test,clk-consumer";
+ assigned-clocks = <0>;
+ assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+ ASSIGNED_SSCS_0_SPREAD
+ ASSIGNED_SSCS_0_METHOD>;
+ };
+};
diff --git a/drivers/clk/kunit_clk_assigned_sscs_one.dtso b/drivers/clk/kunit_clk_assigned_sscs_one.dtso
new file mode 100644
index 0000000000000..91f585b5d8c9b
--- /dev/null
+++ b/drivers/clk/kunit_clk_assigned_sscs_one.dtso
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+/plugin/;
+
+#include "kunit_clk_assigned_rates.h"
+
+&{/} {
+ clk: kunit-clock {
+ compatible = "test,clk-assigned-rates";
+ #clock-cells = <0>;
+ assigned-clocks = <&clk>;
+ assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+ ASSIGNED_SSCS_0_SPREAD
+ ASSIGNED_SSCS_0_METHOD>;
+ };
+};
diff --git a/drivers/clk/kunit_clk_assigned_sscs_one_consumer.dtso b/drivers/clk/kunit_clk_assigned_sscs_one_consumer.dtso
new file mode 100644
index 0000000000000..0bc8a03c20412
--- /dev/null
+++ b/drivers/clk/kunit_clk_assigned_sscs_one_consumer.dtso
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+/plugin/;
+
+#include "kunit_clk_assigned_rates.h"
+
+&{/} {
+ clk: kunit-clock {
+ compatible = "test,clk-assigned-rates";
+ #clock-cells = <0>;
+ };
+
+ kunit-clock-consumer {
+ compatible = "test,clk-consumer";
+ assigned-clocks = <&clk>;
+ assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+ ASSIGNED_SSCS_0_SPREAD
+ ASSIGNED_SSCS_0_METHOD>;
+ };
+};
diff --git a/drivers/clk/kunit_clk_assigned_sscs_without.dtso b/drivers/clk/kunit_clk_assigned_sscs_without.dtso
new file mode 100644
index 0000000000000..08660846b55c1
--- /dev/null
+++ b/drivers/clk/kunit_clk_assigned_sscs_without.dtso
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+/plugin/;
+
+#include "kunit_clk_assigned_rates.h"
+
+&{/} {
+ clk: kunit-clock {
+ compatible = "test,clk-assigned-rates";
+ #clock-cells = <0>;
+ assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+ ASSIGNED_SSCS_0_SPREAD
+ ASSIGNED_SSCS_0_METHOD>;
+ };
+};
diff --git a/drivers/clk/kunit_clk_assigned_sscs_without_consumer.dtso b/drivers/clk/kunit_clk_assigned_sscs_without_consumer.dtso
new file mode 100644
index 0000000000000..e1c089c6f0c02
--- /dev/null
+++ b/drivers/clk/kunit_clk_assigned_sscs_without_consumer.dtso
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+/plugin/;
+
+#include "kunit_clk_assigned_rates.h"
+
+&{/} {
+ clk: kunit-clock {
+ compatible = "test,clk-assigned-rates";
+ #clock-cells = <0>;
+ };
+
+ kunit-clock-consumer {
+ compatible = "test,clk-consumer";
+ assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+ ASSIGNED_SSCS_0_SPREAD
+ ASSIGNED_SSCS_0_METHOD>;
+ };
+};
diff --git a/drivers/clk/kunit_clk_assigned_sscs_zero.dtso b/drivers/clk/kunit_clk_assigned_sscs_zero.dtso
new file mode 100644
index 0000000000000..f39f4e754e532
--- /dev/null
+++ b/drivers/clk/kunit_clk_assigned_sscs_zero.dtso
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+/plugin/;
+
+&{/} {
+ clk: kunit-clock {
+ compatible = "test,clk-assigned-rates";
+ #clock-cells = <0>;
+ assigned-clocks = <&clk>;
+ assigned-clock-sscs = <0 0 0>;
+ };
+};
diff --git a/drivers/clk/kunit_clk_assigned_sscs_zero_consumer.dtso b/drivers/clk/kunit_clk_assigned_sscs_zero_consumer.dtso
new file mode 100644
index 0000000000000..d6bd7dfada7e2
--- /dev/null
+++ b/drivers/clk/kunit_clk_assigned_sscs_zero_consumer.dtso
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+/plugin/;
+
+&{/} {
+ clk: kunit-clock {
+ compatible = "test,clk-assigned-rates";
+ #clock-cells = <0>;
+ };
+
+ kunit-clock-consumer {
+ compatible = "test,clk-consumer";
+ assigned-clocks = <&clk>;
+ assigned-clock-sscs = <0 0 0>;
+ };
+};
--
2.34.1
^ permalink raw reply related
* [PATCH v10 3/6] clk: conf: Support assigned-clock-sscs
From: Peng Fan (OSS) @ 2026-06-12 8:46 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Brian Masney, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sudeep Holla, Cristian Marussi,
Sebin Francis
Cc: linux-kernel, linux-clk, devicetree, arm-scmi, linux-arm-kernel,
Peng Fan
In-Reply-To: <20260612-clk-v10-v10-0-eb92484eda38@nxp.com>
From: Peng Fan <peng.fan@nxp.com>
Parse the Spread Spectrum Configuration(SSC) from device tree and configure
them before using the clock.
Each SSC is three u32 elements which means '<modfreq spreaddepth
modmethod>', so assigned-clock-sscs is an array of multiple three u32
elements.
Reviewed-by: Brian Masney <bmasney@redhat.com>
Reviewed-by: Sebin Francis <sebin.francis@ti.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
drivers/clk/clk-conf.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 76 insertions(+)
diff --git a/drivers/clk/clk-conf.c b/drivers/clk/clk-conf.c
index 303a0bb26e54a..550b8ae375a2c 100644
--- a/drivers/clk/clk-conf.c
+++ b/drivers/clk/clk-conf.c
@@ -155,6 +155,78 @@ static int __set_clk_rates(struct device_node *node, bool clk_supplier)
return 0;
}
+static int __set_clk_spread_spectrum(struct device_node *node, bool clk_supplier)
+{
+ u32 elem_size = sizeof(struct clk_spread_spectrum);
+ struct clk_spread_spectrum *sscs;
+ struct of_phandle_args clkspec;
+ int rc, count, index;
+ struct clk *clk;
+
+ /* modfreq, spreadPercent, modmethod */
+ count = of_property_count_elems_of_size(node, "assigned-clock-sscs", elem_size);
+ if (count <= 0)
+ return 0;
+
+ sscs = kcalloc(count, elem_size, GFP_KERNEL);
+ if (!sscs)
+ return -ENOMEM;
+
+ rc = of_property_read_u32_array(node, "assigned-clock-sscs", (u32 *)sscs,
+ count * 3);
+ if (rc)
+ goto free_sscs;
+
+ for (index = 0; index < count; index++) {
+ struct clk_spread_spectrum *conf = &sscs[index];
+ struct clk_hw *hw;
+
+ if (!conf->modfreq_hz && !conf->spread_bp && !conf->method)
+ continue;
+
+ rc = of_parse_phandle_with_args(node, "assigned-clocks", "#clock-cells",
+ index, &clkspec);
+ if (rc < 0) {
+ /* skip empty (null) phandles */
+ if (rc == -ENOENT) {
+ rc = 0;
+ continue;
+ } else
+ goto free_sscs;
+ }
+
+ if (clkspec.np == node && !clk_supplier) {
+ of_node_put(clkspec.np);
+ goto free_sscs;
+ }
+
+ clk = of_clk_get_from_provider(&clkspec);
+ of_node_put(clkspec.np);
+ if (IS_ERR(clk)) {
+ if (PTR_ERR(clk) != -EPROBE_DEFER)
+ pr_warn("clk: couldn't get clock %d for %pOF\n",
+ index, node);
+ rc = PTR_ERR(clk);
+ goto free_sscs;
+ }
+
+ hw = __clk_get_hw(clk);
+ rc = clk_hw_set_spread_spectrum(hw, conf);
+ if (rc < 0) {
+ pr_err("clk: couldn't set %s clk spread spectrum %u %u %u: %d\n",
+ __clk_get_name(clk), conf->modfreq_hz, conf->spread_bp,
+ conf->method, rc);
+ /* Do not fail */
+ rc = 0;
+ }
+ clk_put(clk);
+ }
+
+free_sscs:
+ kfree(sscs);
+ return rc;
+}
+
/**
* of_clk_set_defaults() - parse and set assigned clocks configuration
* @node: device node to apply clock settings for
@@ -174,6 +246,10 @@ int of_clk_set_defaults(struct device_node *node, bool clk_supplier)
if (!node)
return 0;
+ rc = __set_clk_spread_spectrum(node, clk_supplier);
+ if (rc < 0)
+ return rc;
+
rc = __set_clk_parents(node, clk_supplier);
if (rc < 0)
return rc;
--
2.34.1
^ permalink raw reply related
* [PATCH v10 2/6] clk: Introduce clk_hw_set_spread_spectrum
From: Peng Fan (OSS) @ 2026-06-12 8:46 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Brian Masney, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sudeep Holla, Cristian Marussi,
Sebin Francis
Cc: linux-kernel, linux-clk, devicetree, arm-scmi, linux-arm-kernel,
Peng Fan
In-Reply-To: <20260612-clk-v10-v10-0-eb92484eda38@nxp.com>
From: Peng Fan <peng.fan@nxp.com>
Add clk_hw_set_spread_spectrum to configure a clock to enable spread
spectrum feature. set_spread_spectrum ops is added for clk drivers to
have their own hardware specific implementation.
Reviewed-by: Brian Masney <bmasney@redhat.com>
Reviewed-by: Sebin Francis <sebin.francis@ti.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
drivers/clk/clk.c | 27 +++++++++++++++++++++++++++
include/linux/clk-provider.h | 31 +++++++++++++++++++++++++++++++
2 files changed, 58 insertions(+)
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 048adfa86a5d0..8c78621cde253 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -2774,6 +2774,33 @@ int clk_set_max_rate(struct clk *clk, unsigned long rate)
}
EXPORT_SYMBOL_GPL(clk_set_max_rate);
+int clk_hw_set_spread_spectrum(struct clk_hw *hw, const struct clk_spread_spectrum *ss_conf)
+{
+ struct clk_core *core;
+ int ret;
+
+ if (!hw)
+ return 0;
+
+ core = hw->core;
+
+ clk_prepare_lock();
+
+ ret = clk_pm_runtime_get(core);
+ if (ret)
+ goto fail;
+
+ if (core->ops->set_spread_spectrum)
+ ret = core->ops->set_spread_spectrum(hw, ss_conf);
+
+ clk_pm_runtime_put(core);
+
+fail:
+ clk_prepare_unlock();
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_hw_set_spread_spectrum);
+
/**
* clk_get_parent - return the parent of a clk
* @clk: the clk whose parent gets returned
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index b01a38fef8cf2..7d3747378739c 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -6,6 +6,7 @@
#ifndef __LINUX_CLK_PROVIDER_H
#define __LINUX_CLK_PROVIDER_H
+#include <dt-bindings/clock/clock.h>
#include <linux/of.h>
#include <linux/of_clk.h>
@@ -84,6 +85,26 @@ struct clk_duty {
unsigned int den;
};
+enum clk_ssc_method {
+ CLK_SPREAD_NO = CLK_SSC_NO_SPREAD,
+ CLK_SPREAD_CENTER = CLK_SSC_CENTER_SPREAD,
+ CLK_SPREAD_UP = CLK_SSC_UP_SPREAD,
+ CLK_SPREAD_DOWN = CLK_SSC_DOWN_SPREAD,
+};
+
+/**
+ * struct clk_spread_spectrum - Structure encoding spread spectrum of a clock
+ *
+ * @modfreq_hz: Modulation frequency
+ * @spread_bp: Modulation percent in permyriad
+ * @method: Modulation method
+ */
+struct clk_spread_spectrum {
+ u32 modfreq_hz;
+ u32 spread_bp;
+ enum clk_ssc_method method;
+};
+
/**
* struct clk_ops - Callback operations for hardware clocks; these are to
* be provided by the clock implementation, and will be called by drivers
@@ -174,6 +195,12 @@ struct clk_duty {
* separately via calls to .set_parent and .set_rate.
* Returns 0 on success, -EERROR otherwise.
*
+ * @set_spread_spectrum: Optional callback used to configure the spread
+ * spectrum modulation frequency, percentage, and method
+ * to reduce EMI by spreading the clock frequency over a
+ * wider range.
+ * Returns 0 on success, -EERROR otherwise.
+ *
* @recalc_accuracy: Recalculate the accuracy of this clock. The clock accuracy
* is expressed in ppb (parts per billion). The parent accuracy is
* an input parameter.
@@ -249,6 +276,8 @@ struct clk_ops {
int (*set_rate_and_parent)(struct clk_hw *hw,
unsigned long rate,
unsigned long parent_rate, u8 index);
+ int (*set_spread_spectrum)(struct clk_hw *hw,
+ const struct clk_spread_spectrum *ss_conf);
unsigned long (*recalc_accuracy)(struct clk_hw *hw,
unsigned long parent_accuracy);
int (*get_phase)(struct clk_hw *hw);
@@ -1436,6 +1465,8 @@ void clk_hw_get_rate_range(struct clk_hw *hw, unsigned long *min_rate,
unsigned long *max_rate);
void clk_hw_set_rate_range(struct clk_hw *hw, unsigned long min_rate,
unsigned long max_rate);
+int clk_hw_set_spread_spectrum(struct clk_hw *hw,
+ const struct clk_spread_spectrum *ss_conf);
static inline void __clk_hw_set_clk(struct clk_hw *dst, struct clk_hw *src)
{
--
2.34.1
^ permalink raw reply related
* [PATCH v10 1/6] dt-bindings: clock: Add spread spectrum definition
From: Peng Fan (OSS) @ 2026-06-12 8:46 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Brian Masney, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sudeep Holla, Cristian Marussi,
Sebin Francis
Cc: linux-kernel, linux-clk, devicetree, arm-scmi, linux-arm-kernel,
Peng Fan
In-Reply-To: <20260612-clk-v10-v10-0-eb92484eda38@nxp.com>
From: Peng Fan <peng.fan@nxp.com>
Per dt-schema, the modulation methods are: down-spread(3), up-spread(2),
center-spread(1), no-spread(0). So define them in dt-bindings to avoid
write the magic number in device tree.
Reviewed-by: Brian Masney <bmasney@redhat.com>
Acked-by: Rob Herring (Arm) <robh@kernel.org>
Reviewed-by: Sebin Francis <sebin.francis@ti.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
include/dt-bindings/clock/clock.h | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/include/dt-bindings/clock/clock.h b/include/dt-bindings/clock/clock.h
new file mode 100644
index 0000000000000..155e2653a120b
--- /dev/null
+++ b/include/dt-bindings/clock/clock.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
+/*
+ * Copyright 2025 NXP
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_H
+#define __DT_BINDINGS_CLOCK_H
+
+#define CLK_SSC_NO_SPREAD 0
+#define CLK_SSC_CENTER_SPREAD 1
+#define CLK_SSC_UP_SPREAD 2
+#define CLK_SSC_DOWN_SPREAD 3
+
+#endif /* __DT_BINDINGS_CLOCK_H */
--
2.34.1
^ 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