* [PATCH v4 0/5] arm_mpam: resctrl: Counter Assignment (ABMC)
From: Ben Horgan @ 2026-05-20 21:24 UTC (permalink / raw)
To: ben.horgan
Cc: amitsinght, baisheng.gao, baolin.wang, carl, dave.martin, david,
dfustini, fenghuay, gshan, james.morse, jic23, kobak, lcherian,
linux-arm-kernel, linux-kernel, peternewman, punit.agrawal,
quic_jiles, reinette.chatre, rohit.mathew, scott, sdonthineni,
tan.shaopeng, xhao, zengheng4, x86
Version 4 of this series addresses a few review comments and some concerns
of the sashiko bot.
From the cover letter of v3:
Removing the rfc tag as the resctrl precursors [1] have been queued in tip
x86/cache. Due to that dependency, it would be good for this to also go through
x86/cache.
This series adds support for memory bandwidth monitoring.
Please review and test.
Changelogs in patches.
[1] https://lore.kernel.org/all/20260506082855.3694761-1-ben.horgan@arm.com/
Description from the initial cover letter:
The MPAM counter assignment (ABMC emulation) changes that were dropped from
the resctrl glue series due to some missing precursors in resctrl. Counter
assignment enables bandwidth monitoring in systems that have fewer
monitors than resctrl monitor groups.
rfc v1: https://lore.kernel.org/lkml/20260225205436.3571756-1-ben.horgan@arm.com/
rfc v2: https://lore.kernel.org/lkml/20260319165540.381410-1-ben.horgan@arm.com/
v3: https://lore.kernel.org/linux-arm-kernel/20260511154147.557481-1-ben.horgan@arm.com/
The code can be found at:
https://gitlab.arm.com/linux-arm/linux-bh.git mpam_abmc_v4
Ben Horgan (2):
arm_mpam: resctrl: Pre-allocate assignable monitors
arm64: mpam: Add memory bandwidth usage (MBWU) documentation
James Morse (3):
arm_mpam: resctrl: Pick classes for use as MBM counters
arm_mpam: resctrl: Add resctrl_arch_config_cntr() for ABMC use
arm_mpam: resctrl: Add resctrl_arch_cntr_read() &
resctrl_arch_reset_cntr()
Documentation/arch/arm64/mpam.rst | 17 ++
drivers/resctrl/mpam_internal.h | 6 +-
drivers/resctrl/mpam_resctrl.c | 308 +++++++++++++++++++++++++++---
3 files changed, 308 insertions(+), 23 deletions(-)
--
2.43.0
^ permalink raw reply
* [PATCH v4 2/5] arm_mpam: resctrl: Pre-allocate assignable monitors
From: Ben Horgan @ 2026-05-20 21:24 UTC (permalink / raw)
To: ben.horgan
Cc: amitsinght, baisheng.gao, baolin.wang, carl, dave.martin, david,
dfustini, fenghuay, gshan, james.morse, jic23, kobak, lcherian,
linux-arm-kernel, linux-kernel, peternewman, punit.agrawal,
quic_jiles, reinette.chatre, rohit.mathew, scott, sdonthineni,
tan.shaopeng, xhao, zengheng4, x86
In-Reply-To: <20260520212458.1797221-1-ben.horgan@arm.com>
MPAM is able to emulate ABMC, i.e. mbm_event mode, by making memory
bandwidth monitors assignable. Rather than supporting the 'default'
mbm_assign_mode always use 'mbm_event' mode even if there are sufficient
memory bandwidth monitors. The per monitor event configuration is only
provided by resctrl when in 'mbm_event' mode and so only allowing
'mbm_event' mode will make it easier to support per-monitor event
configuration for MPAM. For the moment, the only event supported is
mbm_total_event with no bandwidth type configuration. The 'mbm_assign_mode'
file will still show 'default' when there is no support for memory
bandwidth monitoring.
The monitors need to be allocated from the driver, and mapped to whichever
control/monitor group resctrl wants to use them with.
Add a second array to hold the monitor values indexed by resctrl's cntr_id.
When CDP is in use, two monitors are needed so the available number of
counters halves. Platforms with one monitor will have zero monitors when
CDP is in use.
Co-developed-by: James Morse <james.morse@arm.com>
Signed-off-by: James Morse <james.morse@arm.com>
Signed-off-by: Ben Horgan <ben.horgan@arm.com>
---
Changes since rfc v1:
abmc enabled even if enough counters
Helpers from dropped free running commits
carry on with zero counters if using cdp
set config bits
use kmalloc_objs
drop tags for rework
Configure mbm_cntr_configurable, mbm_cntr_assign_fixed
Changes since rfc v2:
Don't set mon->assigned_counters to an error pointer
Fix mpam_resctrl_teardown_mon()
Remove free running check
Separate cleanup allocations, e.g. __free(), from the rest
Restrict scope on err in mpam_resctrl_monitor_init()
Changes since v3:
Correct NULL check in mpam_resctrl_teardown_mon() (Shaopeng)
variable allocation ordering in mpam_resctrl_pick_domain_id() (Shaopeng)
Move mon.* assignments from mpam_resctrl_monitor_sync_abmc_vals()
to mpam_resctrl_monitor_init_abmc() counters (Sashiko)
use kvmalloc_obj() for allocations that may be big on some
platforms (Sashiko)
---
drivers/resctrl/mpam_internal.h | 6 +-
drivers/resctrl/mpam_resctrl.c | 139 +++++++++++++++++++++++++++++++-
2 files changed, 141 insertions(+), 4 deletions(-)
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index 1914aefdcba9..7a166b395b5a 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -411,7 +411,11 @@ struct mpam_resctrl_res {
struct mpam_resctrl_mon {
struct mpam_class *class;
- /* per-class data that resctrl needs will live here */
+ /* Array of allocated MBWU monitors, indexed by (closid, rmid). */
+ int *mbwu_idx_to_mon;
+
+ /* Array of assigned MBWU monitors, indexed by idx argument. */
+ int *assigned_counters;
};
static inline int mpam_alloc_csu_mon(struct mpam_class *class)
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index f70fa65d39e4..a13eb232a19d 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -75,6 +75,8 @@ static DECLARE_WAIT_QUEUE_HEAD(wait_cacheinfo_ready);
*/
static bool resctrl_enabled;
+static unsigned int l3_num_allocated_mbwu = ~0;
+
bool resctrl_arch_alloc_capable(void)
{
struct mpam_resctrl_res *res;
@@ -140,7 +142,7 @@ int resctrl_arch_cntr_read(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
bool resctrl_arch_mbm_cntr_assign_enabled(struct rdt_resource *r)
{
- return false;
+ return (r == &mpam_resctrl_controls[RDT_RESOURCE_L3].resctrl_res);
}
int resctrl_arch_mbm_cntr_assign_set(struct rdt_resource *r, bool enable)
@@ -185,6 +187,18 @@ static void resctrl_reset_task_closids(void)
read_unlock(&tasklist_lock);
}
+static void mpam_resctrl_monitor_sync_abmc_vals(struct rdt_resource *l3)
+{
+ l3->mon.num_mbm_cntrs = l3_num_allocated_mbwu;
+ if (cdp_enabled)
+ l3->mon.num_mbm_cntrs /= 2;
+
+ /*
+ * Continue as normal even if enabling cdp causes there to be
+ * zero counters. This avoid giving resctrl mixed messages.
+ */
+}
+
int resctrl_arch_set_cdp_enabled(enum resctrl_res_level rid, bool enable)
{
u32 partid_i = RESCTRL_RESERVED_CLOSID, partid_d = RESCTRL_RESERVED_CLOSID;
@@ -244,6 +258,7 @@ int resctrl_arch_set_cdp_enabled(enum resctrl_res_level rid, bool enable)
WRITE_ONCE(arm64_mpam_global_default, mpam_get_regval(current));
resctrl_reset_task_closids();
+ mpam_resctrl_monitor_sync_abmc_vals(l3);
for_each_possible_cpu(cpu)
mpam_set_cpu_defaults(cpu, partid_d, partid_i, 0, 0);
@@ -613,6 +628,9 @@ static bool class_has_usable_mbwu(struct mpam_class *class)
if (!mpam_has_feature(mpam_feat_msmon_mbwu, cprops))
return false;
+ if (!cprops->num_mbwu_mon)
+ return false;
+
return true;
}
@@ -935,6 +953,52 @@ static void mpam_resctrl_pick_mba(void)
}
}
+static void __free_mbwu_mon(struct mpam_class *class, int *array,
+ u16 num_mbwu_mon)
+{
+ for (int i = 0; i < num_mbwu_mon; i++) {
+ if (array[i] < 0)
+ continue;
+
+ mpam_free_mbwu_mon(class, array[i]);
+ array[i] = ~0;
+ }
+}
+
+static int __alloc_mbwu_mon(struct mpam_class *class, int *array,
+ u16 num_mbwu_mon)
+{
+ for (int i = 0; i < num_mbwu_mon; i++) {
+ int mbwu_mon = mpam_alloc_mbwu_mon(class);
+
+ if (mbwu_mon < 0) {
+ __free_mbwu_mon(class, array, num_mbwu_mon);
+ return mbwu_mon;
+ }
+ array[i] = mbwu_mon;
+ }
+
+ l3_num_allocated_mbwu = min(l3_num_allocated_mbwu, num_mbwu_mon);
+
+ return 0;
+}
+
+static int *__alloc_mbwu_array(struct mpam_class *class, u16 num_mbwu_mon)
+{
+ int err;
+
+ int *array __free(kvfree) = kvmalloc_objs(*array, num_mbwu_mon);
+ if (!array)
+ return ERR_PTR(-ENOMEM);
+
+ memset(array, -1, num_mbwu_mon * sizeof(*array));
+
+ err = __alloc_mbwu_mon(class, array, num_mbwu_mon);
+ if (err)
+ return ERR_PTR(err);
+ return_ptr(array);
+}
+
static void counter_update_class(enum resctrl_event_id evt_id,
struct mpam_class *class)
{
@@ -1089,6 +1153,43 @@ static int mpam_resctrl_pick_domain_id(int cpu, struct mpam_component *comp)
return comp->comp_id;
}
+/*
+ * This must run after all event counters have been picked so that any free
+ * running counters have already been allocated.
+ */
+static int mpam_resctrl_monitor_init_abmc(struct mpam_resctrl_mon *mon)
+{
+ struct mpam_resctrl_res *res = &mpam_resctrl_controls[RDT_RESOURCE_L3];
+ size_t num_rmid = resctrl_arch_system_num_rmid_idx();
+ struct rdt_resource *l3 = &res->resctrl_res;
+ struct mpam_class *class = mon->class;
+ u16 num_mbwu_mon;
+ int *cntrs;
+
+ int *rmid_array __free(kvfree) = kvmalloc_objs(*rmid_array, num_rmid);
+ if (!rmid_array) {
+ pr_debug("Failed to allocate RMID array\n");
+ return -ENOMEM;
+ }
+ memset(rmid_array, -1, num_rmid * sizeof(*rmid_array));
+
+ num_mbwu_mon = class->props.num_mbwu_mon;
+ cntrs = __alloc_mbwu_array(mon->class, num_mbwu_mon);
+ if (IS_ERR(cntrs))
+ return PTR_ERR(cntrs);
+ mon->assigned_counters = cntrs;
+ mon->mbwu_idx_to_mon = no_free_ptr(rmid_array);
+
+ l3->mon.mbm_cntr_assignable = true;
+ l3->mon.mbm_assign_on_mkdir = true;
+ l3->mon.mbm_cntr_configurable = false;
+ l3->mon.mbm_cntr_assign_fixed = true;
+
+ mpam_resctrl_monitor_sync_abmc_vals(l3);
+
+ return 0;
+}
+
static int mpam_resctrl_monitor_init(struct mpam_resctrl_mon *mon,
enum resctrl_event_id type)
{
@@ -1133,8 +1234,21 @@ static int mpam_resctrl_monitor_init(struct mpam_resctrl_mon *mon,
*/
l3->mon.num_rmid = resctrl_arch_system_num_rmid_idx();
- if (resctrl_enable_mon_event(type, false, 0, NULL))
- l3->mon_capable = true;
+ if (type == QOS_L3_MBM_TOTAL_EVENT_ID) {
+ int err;
+
+ err = mpam_resctrl_monitor_init_abmc(mon);
+ if (err)
+ return err;
+
+ static_assert(MAX_EVT_CONFIG_BITS == 0x7f);
+ l3->mon.mbm_cfg_mask = MAX_EVT_CONFIG_BITS;
+ }
+
+ if (!resctrl_enable_mon_event(type, false, 0, NULL))
+ return -EINVAL;
+
+ l3->mon_capable = true;
return 0;
}
@@ -1697,6 +1811,23 @@ void mpam_resctrl_exit(void)
resctrl_exit();
}
+static void mpam_resctrl_teardown_mon(struct mpam_resctrl_mon *mon, struct mpam_class *class)
+{
+ u32 num_mbwu_mon = l3_num_allocated_mbwu;
+
+ if (!mon->mbwu_idx_to_mon)
+ return;
+
+ if (mon->assigned_counters) {
+ __free_mbwu_mon(class, mon->assigned_counters, num_mbwu_mon);
+ kvfree(mon->assigned_counters);
+ mon->assigned_counters = NULL;
+ }
+
+ kvfree(mon->mbwu_idx_to_mon);
+ mon->mbwu_idx_to_mon = NULL;
+}
+
/*
* The driver is detaching an MSC from this class, if resctrl was using it,
* pull on resctrl_exit().
@@ -1719,6 +1850,8 @@ void mpam_resctrl_teardown_class(struct mpam_class *class)
for_each_mpam_resctrl_mon(mon, eventid) {
if (mon->class == class) {
mon->class = NULL;
+
+ mpam_resctrl_teardown_mon(mon, class);
break;
}
}
--
2.43.0
^ permalink raw reply related
* [PATCH v4 1/5] arm_mpam: resctrl: Pick classes for use as MBM counters
From: Ben Horgan @ 2026-05-20 21:24 UTC (permalink / raw)
To: ben.horgan
Cc: amitsinght, baisheng.gao, baolin.wang, carl, dave.martin, david,
dfustini, fenghuay, gshan, james.morse, jic23, kobak, lcherian,
linux-arm-kernel, linux-kernel, peternewman, punit.agrawal,
quic_jiles, reinette.chatre, rohit.mathew, scott, sdonthineni,
tan.shaopeng, xhao, zengheng4, x86, Shaopeng Tan,
Jonathan Cameron
In-Reply-To: <20260520212458.1797221-1-ben.horgan@arm.com>
From: James Morse <james.morse@arm.com>
resctrl has two types of bandwidth counters, NUMA-local and global. MPAM
can only count globally; either using MSC at the L3 cache or in the memory
controllers. When global and local equate to the same thing continue just
to call it global.
Pick the corresponding MPAM classes to back the MBM counters. As resctrl
requires all monitors to be at the L3 cache, we can only use the counters
at the memory controllers when they have the same topology as the L3 cache
and the traffic they see if the same. In particular, for the bandwidth
counters at the memory controllers to be exposed to resctrl it is required
there is a single L3 cache and a single NUMA node as otherwise cross NUMA
traffic will be counted at the wrong instance.
Tested-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
Tested-by: Zeng Heng <zengheng4@huawei.com>
Reviewed-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Signed-off-by: James Morse <james.morse@arm.com>
Signed-off-by: Ben Horgan <ben.horgan@arm.com>
---
Changes since rfc v1:
Move finding any_mon_comp into monitor boilerplate patch
Move mpam_resctrl_get_domain_from_cpu() into monitor boilerplate
Remove free running check
Trim commit message
Changes since v3:
Extra paragraph in commit message
---
drivers/resctrl/mpam_resctrl.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 226ff6f532fa..f70fa65d39e4 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -606,6 +606,16 @@ static bool cache_has_usable_csu(struct mpam_class *class)
return true;
}
+static bool class_has_usable_mbwu(struct mpam_class *class)
+{
+ struct mpam_props *cprops = &class->props;
+
+ if (!mpam_has_feature(mpam_feat_msmon_mbwu, cprops))
+ return false;
+
+ return true;
+}
+
/*
* Calculate the worst-case percentage change from each implemented step
* in the control.
@@ -983,6 +993,22 @@ static void mpam_resctrl_pick_counters(void)
break;
}
}
+
+ if (class_has_usable_mbwu(class) &&
+ topology_matches_l3(class) &&
+ traffic_matches_l3(class)) {
+ pr_debug("class %u has usable MBWU, and matches L3 topology and traffic\n",
+ class->level);
+
+ /*
+ * We can't distinguish traffic by destination so
+ * we don't know if it's staying on the same NUMA
+ * node. Hence, we can't calculate mbm_local except
+ * when we only have one L3 and it's equivalent to
+ * mbm_total and so always use mbm_total.
+ */
+ counter_update_class(QOS_L3_MBM_TOTAL_EVENT_ID, class);
+ }
}
}
--
2.43.0
^ permalink raw reply related
* [PATCH v4 3/5] arm_mpam: resctrl: Add resctrl_arch_config_cntr() for ABMC use
From: Ben Horgan @ 2026-05-20 21:24 UTC (permalink / raw)
To: ben.horgan
Cc: amitsinght, baisheng.gao, baolin.wang, carl, dave.martin, david,
dfustini, fenghuay, gshan, james.morse, jic23, kobak, lcherian,
linux-arm-kernel, linux-kernel, peternewman, punit.agrawal,
quic_jiles, reinette.chatre, rohit.mathew, scott, sdonthineni,
tan.shaopeng, xhao, zengheng4, x86, Jonathan Cameron
In-Reply-To: <20260520212458.1797221-1-ben.horgan@arm.com>
From: James Morse <james.morse@arm.com>
ABMC, mbm_event mode, has a helper resctrl_arch_config_cntr() for changing
the mapping between 'cntr_id' and a CLOSID/RMID pair.
Add the helper.
For MPAM this is done by updating the mon->mbwu_idx_to_mon[] array, and as
usual CDP means it needs doing in three different ways.
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Signed-off-by: James Morse <james.morse@arm.com>
Signed-off-by: Ben Horgan <ben.horgan@arm.com>
---
Changes since new rfc:
Mention mbm_event mode in commit message
Changes since v3:
Warning bound (Sashiko)
---
drivers/resctrl/mpam_resctrl.c | 44 +++++++++++++++++++++++++++++-----
1 file changed, 38 insertions(+), 6 deletions(-)
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index a13eb232a19d..1f9a8ae157ca 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -127,12 +127,6 @@ void resctrl_arch_reset_cntr(struct rdt_resource *r, struct rdt_l3_mon_domain *d
{
}
-void resctrl_arch_config_cntr(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
- enum resctrl_event_id evtid, u32 rmid, u32 closid,
- u32 cntr_id, bool assign)
-{
-}
-
int resctrl_arch_cntr_read(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
u32 unused, u32 rmid, int cntr_id,
enum resctrl_event_id eventid, u64 *val)
@@ -1076,6 +1070,44 @@ static void mpam_resctrl_pick_counters(void)
}
}
+static void __config_cntr(struct mpam_resctrl_mon *mon, u32 cntr_id,
+ enum resctrl_conf_type cdp_type, u32 closid, u32 rmid,
+ bool assign)
+{
+ u32 mbwu_idx, mon_idx = resctrl_get_config_index(cntr_id, cdp_type);
+
+ WARN_ON_ONCE(mon_idx >= l3_num_allocated_mbwu);
+
+ closid = resctrl_get_config_index(closid, cdp_type);
+ mbwu_idx = resctrl_arch_rmid_idx_encode(closid, rmid);
+
+ if (assign)
+ mon->mbwu_idx_to_mon[mbwu_idx] = mon->assigned_counters[mon_idx];
+ else
+ mon->mbwu_idx_to_mon[mbwu_idx] = -1;
+}
+
+void resctrl_arch_config_cntr(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
+ enum resctrl_event_id evtid, u32 rmid, u32 closid,
+ u32 cntr_id, bool assign)
+{
+ struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[evtid];
+
+ if (!mon->mbwu_idx_to_mon || !mon->assigned_counters) {
+ pr_debug("monitor arrays not allocated\n");
+ return;
+ }
+
+ if (cdp_enabled) {
+ __config_cntr(mon, cntr_id, CDP_CODE, closid, rmid, assign);
+ __config_cntr(mon, cntr_id, CDP_DATA, closid, rmid, assign);
+ } else {
+ __config_cntr(mon, cntr_id, CDP_NONE, closid, rmid, assign);
+ }
+
+ resctrl_arch_reset_rmid(r, d, closid, rmid, evtid);
+}
+
static int mpam_resctrl_control_init(struct mpam_resctrl_res *res)
{
struct mpam_class *class = res->class;
--
2.43.0
^ permalink raw reply related
* [PATCH v4 4/5] arm_mpam: resctrl: Add resctrl_arch_cntr_read() & resctrl_arch_reset_cntr()
From: Ben Horgan @ 2026-05-20 21:24 UTC (permalink / raw)
To: ben.horgan
Cc: amitsinght, baisheng.gao, baolin.wang, carl, dave.martin, david,
dfustini, fenghuay, gshan, james.morse, jic23, kobak, lcherian,
linux-arm-kernel, linux-kernel, peternewman, punit.agrawal,
quic_jiles, reinette.chatre, rohit.mathew, scott, sdonthineni,
tan.shaopeng, xhao, zengheng4, x86, Jonathan Cameron
In-Reply-To: <20260520212458.1797221-1-ben.horgan@arm.com>
From: James Morse <james.morse@arm.com>
When used in 'mbm_event' mode, ABMC emulation, resctrl uses arch hooks to
read and reset the memory bandwidth utilization (MBWU) counters.
Add these.
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Signed-off-by: James Morse <james.morse@arm.com>
Signed-off-by: Ben Horgan <ben.horgan@arm.com>
---
Changes since rfc v1:
Move __reset_mon() and reset_mon_cdp_safe() helpers here
support mbwu in __read_mon()
Mention mbm_event mode in commit message
Changes since v3:
USE_PREALLOCATED_IDX, separate h/w counters are needed for code and data
when cdp_enabled is true
---
drivers/resctrl/mpam_resctrl.c | 99 +++++++++++++++++++++++++++++-----
1 file changed, 86 insertions(+), 13 deletions(-)
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 1f9a8ae157ca..d236ecd38aa3 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -121,19 +121,6 @@ void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_l3_mon_domain *d
{
}
-void resctrl_arch_reset_cntr(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
- u32 closid, u32 rmid, int cntr_id,
- enum resctrl_event_id eventid)
-{
-}
-
-int resctrl_arch_cntr_read(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
- u32 unused, u32 rmid, int cntr_id,
- enum resctrl_event_id eventid, u64 *val)
-{
- return -EOPNOTSUPP;
-}
-
bool resctrl_arch_mbm_cntr_assign_enabled(struct rdt_resource *r)
{
return (r == &mpam_resctrl_controls[RDT_RESOURCE_L3].resctrl_res);
@@ -463,6 +450,14 @@ static int __read_mon(struct mpam_resctrl_mon *mon, struct mpam_component *mon_c
/* Shift closid to account for CDP */
closid = resctrl_get_config_index(closid, cdp_type);
+ if (mon_idx == USE_PRE_ALLOCATED) {
+ int mbwu_idx = resctrl_arch_rmid_idx_encode(closid, rmid);
+
+ mon_idx = mon->mbwu_idx_to_mon[mbwu_idx];
+ if (mon_idx == -1)
+ return -ENOENT;
+ }
+
if (irqs_disabled()) {
/* Check if we can access this domain without an IPI */
return -EIO;
@@ -535,6 +530,84 @@ int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain_hdr *hdr,
closid, rmid, val);
}
+/* MBWU counters when in ABMC mode */
+int resctrl_arch_cntr_read(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
+ u32 closid, u32 rmid, int mon_idx,
+ enum resctrl_event_id eventid, u64 *val)
+{
+ struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[eventid];
+ struct mpam_resctrl_dom *l3_dom;
+ struct mpam_component *mon_comp;
+
+ if (!mpam_is_enabled())
+ return -EINVAL;
+
+ if (eventid == QOS_L3_OCCUP_EVENT_ID || !mon->class)
+ return -EINVAL;
+
+ l3_dom = container_of(d, struct mpam_resctrl_dom, resctrl_mon_dom);
+ mon_comp = l3_dom->mon_comp[eventid];
+
+ return read_mon_cdp_safe(mon, mon_comp, mpam_feat_msmon_mbwu,
+ USE_PRE_ALLOCATED, closid, rmid, val);
+}
+
+static void __reset_mon(struct mpam_resctrl_mon *mon, struct mpam_component *mon_comp,
+ int mon_idx,
+ enum resctrl_conf_type cdp_type, u32 closid, u32 rmid)
+{
+ struct mon_cfg cfg = { };
+
+ if (!mpam_is_enabled())
+ return;
+
+ /* Shift closid to account for CDP */
+ closid = resctrl_get_config_index(closid, cdp_type);
+
+ if (mon_idx == USE_PRE_ALLOCATED) {
+ int mbwu_idx = resctrl_arch_rmid_idx_encode(closid, rmid);
+
+ mon_idx = mon->mbwu_idx_to_mon[mbwu_idx];
+ }
+
+ if (mon_idx == -1)
+ return;
+ cfg.mon = mon_idx;
+ mpam_msmon_reset_mbwu(mon_comp, &cfg);
+}
+
+static void reset_mon_cdp_safe(struct mpam_resctrl_mon *mon, struct mpam_component *mon_comp,
+ int mon_idx, u32 closid, u32 rmid)
+{
+ if (cdp_enabled) {
+ __reset_mon(mon, mon_comp, mon_idx, CDP_CODE, closid, rmid);
+ __reset_mon(mon, mon_comp, mon_idx, CDP_DATA, closid, rmid);
+ } else {
+ __reset_mon(mon, mon_comp, mon_idx, CDP_NONE, closid, rmid);
+ }
+}
+
+/* Reset an assigned counter */
+void resctrl_arch_reset_cntr(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
+ u32 closid, u32 rmid, int cntr_id,
+ enum resctrl_event_id eventid)
+{
+ struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[eventid];
+ struct mpam_resctrl_dom *l3_dom;
+ struct mpam_component *mon_comp;
+
+ if (!mpam_is_enabled())
+ return;
+
+ if (eventid == QOS_L3_OCCUP_EVENT_ID || !mon->class)
+ return;
+
+ l3_dom = container_of(d, struct mpam_resctrl_dom, resctrl_mon_dom);
+ mon_comp = l3_dom->mon_comp[eventid];
+
+ reset_mon_cdp_safe(mon, mon_comp, USE_PRE_ALLOCATED, closid, rmid);
+}
+
/*
* The rmid realloc threshold should be for the smallest cache exposed to
* resctrl.
--
2.43.0
^ permalink raw reply related
* [PATCH v4 5/5] arm64: mpam: Add memory bandwidth usage (MBWU) documentation
From: Ben Horgan @ 2026-05-20 21:24 UTC (permalink / raw)
To: ben.horgan
Cc: amitsinght, baisheng.gao, baolin.wang, carl, dave.martin, david,
dfustini, fenghuay, gshan, james.morse, jic23, kobak, lcherian,
linux-arm-kernel, linux-kernel, peternewman, punit.agrawal,
quic_jiles, reinette.chatre, rohit.mathew, scott, sdonthineni,
tan.shaopeng, xhao, zengheng4, x86
In-Reply-To: <20260520212458.1797221-1-ben.horgan@arm.com>
Memory bandwidth monitoring make uses of MBWU monitors and is now exposed
to the user via resctrl. Add some documentation so the user knows what to
expect.
Co-developed-by: James Morse <james.morse@arm.com>
Signed-off-by: James Morse <james.morse@arm.com>
Signed-off-by: Ben Horgan <ben.horgan@arm.com>
---
Documentation/arch/arm64/mpam.rst | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/Documentation/arch/arm64/mpam.rst b/Documentation/arch/arm64/mpam.rst
index 570f51a8d4eb..208ff17068c4 100644
--- a/Documentation/arch/arm64/mpam.rst
+++ b/Documentation/arch/arm64/mpam.rst
@@ -65,6 +65,23 @@ The supported features are:
there is at least one CSU monitor on each MSC that makes up the L3 group.
Exposing CSU counters from other caches or devices is not supported.
+* Memory Bandwidth Usage (MBWU) on or after the L3 cache. resctrl uses the
+ L3 cache-id to identify where the memory bandwidth is measured. For this
+ reason the platform must have an L3 cache with cache-id's supplied by
+ firmware. (It doesn't need to support MPAM.)
+
+ Memory bandwidth monitoring makes use of MBWU monitors in each MSC that
+ makes up the L3 group. If the memory bandwidth monitoring is on the memory
+ rather than the L3 then there must be a single global L3 as otherwise it
+ is unknown which L3 the traffic came from.
+
+ To expose 'mbm_total_bytes', the topology of the group of MSC chosen must
+ match the topology of the L3 cache so that the cache-id's can be
+ repainted. For example: Platforms with Memory bandwidth monitors on
+ CPU-less NUMA nodes cannot expose 'mbm_total_bytes' as these nodes do not
+ have a corresponding L3 cache. 'mbm_local_bytes' is not exposed as MPAM
+ cannot distinguish local traffic from global traffic.
+
Reporting Bugs
==============
If you are not seeing the counters or controls you expect please share the
--
2.43.0
^ permalink raw reply related
* [PATCH] ARM: footbridge: remove redundant checks for CONFIG_NEW_LEDS
From: Ethan Nelson-Moore @ 2026-05-20 21:26 UTC (permalink / raw)
To: linux-arm-kernel, linux-kernel; +Cc: Ethan Nelson-Moore, Russell King
Code in mach-footbridge checks for both CONFIG_NEW_LEDS and
CONFIG_LEDS_CLASS. CONFIG_LEDS_CLASS depends on CONFIG_NEW_LEDS, and
therefore checking for both is unnecessary. Remove the checks for
CONFIG_NEW_LEDS.
Signed-off-by: Ethan Nelson-Moore <enelsonmoore@gmail.com>
---
| 2 +-
| 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
--git a/arch/arm/mach-footbridge/ebsa285.c b/arch/arm/mach-footbridge/ebsa285.c
index a65554b1c1d8..2e23c35a4f28 100644
--- a/arch/arm/mach-footbridge/ebsa285.c
+++ b/arch/arm/mach-footbridge/ebsa285.c
@@ -19,7 +19,7 @@
#include "common.h"
/* LEDs */
-#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+#ifdef CONFIG_LEDS_CLASS
#define XBUS_AMBER_L BIT(0)
#define XBUS_GREEN_L BIT(1)
#define XBUS_RED_L BIT(2)
--git a/arch/arm/mach-footbridge/netwinder-hw.c b/arch/arm/mach-footbridge/netwinder-hw.c
index a33f4c3b9505..14989d557ebf 100644
--- a/arch/arm/mach-footbridge/netwinder-hw.c
+++ b/arch/arm/mach-footbridge/netwinder-hw.c
@@ -701,7 +701,7 @@ static void netwinder_restart(enum reboot_mode mode, const char *cmd)
}
/* LEDs */
-#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+#ifdef CONFIG_LEDS_CLASS
struct netwinder_led {
struct led_classdev cdev;
u8 mask;
--
2.43.0
^ permalink raw reply related
* Re: [PATCH 1/8] mm: Add ptep_try_install() for lockless empty-slot installs
From: David Hildenbrand (Arm) @ 2026-05-20 21:29 UTC (permalink / raw)
To: Tejun Heo
Cc: Alexei Starovoitov, David Vernet, Andrea Righi, Changwoo Min,
Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Martin KaFai Lau, Kumar Kartikeya Dwivedi, Catalin Marinas,
Will Deacon, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, Andrew Morton, Mike Rapoport, Emil Tsalapatis,
sched-ext, bpf, X86 ML, linux-arm-kernel, linux-mm, LKML
In-Reply-To: <ag3_qpKObFOLKgbR@slm.duckdns.org>
On 5/20/26 20:38, Tejun Heo wrote:
> On Wed, May 20, 2026 at 10:41:15AM +0200, David Hildenbrand (Arm) wrote:
>> And that should be carefully documented.
>
> Will do.
>
>>> The fault handler has to install _some_ page and let kernel continue.
>>> Scratch page or arena page doesn't matter. Potentially different CPUs
>>> will see different page. It's not a concern at all.
>>> bpf prog is buggy, but the kernel will continue to work without a glitch.
>>> bpf runtime will disable and unload misbehaving prog.
>>
>> Having one page table walker overwrite a scratch page on race is just rather ...
>> questionable locking design, that just screams for problems long-term, really.
>>
>> At least in apply_range_clear_cb() one could similarly switch to
>> ptep_try_install() to at least have both these paths handle races in a
>> reasonable way. (having to handle when ptep_try_install() is not really implemented)
>
> Hmm... wouldn't that be more confusing on apply_range_clear_cb() side?
> Whether it maintains the current behavior (if collide with scratch, try
> again with scratch as the original value) or flip the behavior (fail if
> scratch), that extra logic is spurious, and those tend to confuse people as
> they force asking why it has to be that specific way. If the goal is
> documenting the subtlety, wouldn't a detailed comment serve the purpose
> better?
I would let all operations that can happen concurrently work with atomics, not
just a single one.
Alexei correctly concluded that ptep_get_and_clear() might be one option that
should do on x86 and arm64 from a quick glimpse.
>
>> Anyhow, the documentation of ptep_try_install() must clearly spell out that this
>> must be used very carefully, and only in special kernel page tables, never user
>> page tables. There are likely other scenarios we should document (caller must
>> prevent concurrent page table teardown somehow, and must be prepared to handle
>> races if other code is not using atomics).
>>
>> To highlight that, we should likely consider adding a "kernel" in the name, like
>> "ptep_try_install_kernel()".
>>
>> I am also not sure if "install" is the right terminology and whether it should
>> instead be "ptep_try_set()". (set_pte_at is the non-atomic interface right now)
>
> So, ptep_try_set_kernel()?
I guess we could do that, but we don't have a lot of existing functions that are
specific to kernel page tables ... only pte_offset_kernel() and
pte_alloc_one_kernel()/pte_free_kernel().
The most important part is getting the documentation right.
We should probably document that code concurrently clearing PTEs should be using
ptep_get_and_clear().
--
Cheers,
David
^ permalink raw reply
* Re: [PATCH v7 1/2] media: dt-bindings: Add CSI Pixel Formatter DT bindings
From: Laurent Pinchart @ 2026-05-20 21:33 UTC (permalink / raw)
To: Guoniu Zhou
Cc: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Frank Li, imx, linux-media, devicetree,
linux-arm-kernel, linux-kernel, Guoniu Zhou, Krzysztof Kozlowski
In-Reply-To: <20260518-csi_formatter-v7-1-562b750557e3@oss.nxp.com>
Hi Guoniu,
Thank you for the patch.
On Mon, May 18, 2026 at 10:19:46AM +0800, Guoniu Zhou wrote:
> From: Guoniu Zhou <guoniu.zhou@nxp.com>
>
> The i.MX95 CSI pixel formatting module uses packet info, pixel and
> non-pixel data from the CSI-2 host controller and reformat them to
> match Pixel Link(PL) definition.
>
> Reviewed-by: Frank Li <Frank.Li@nxp.com>
> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
> Signed-off-by: Guoniu Zhou <guoniu.zhou@nxp.com>
> ---
> Changes in v7:
> - Change compatible to imx95-csi-formatter as IP is i.MX95 specific per Marco's suggestion
> Link: https://lore.kernel.org/linux-media/20260511-csi_formatter-v6-0-01028e312e2b@oss.nxp.com/T/#mcd135b3de179b3cb69daa1fd6e0e8e27c85b3332
> ---
> .../bindings/media/fsl,imx95-csi-formatter.yaml | 87 ++++++++++++++++++++++
> 1 file changed, 87 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/media/fsl,imx95-csi-formatter.yaml b/Documentation/devicetree/bindings/media/fsl,imx95-csi-formatter.yaml
> new file mode 100644
> index 000000000000..28adea06c494
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/fsl,imx95-csi-formatter.yaml
> @@ -0,0 +1,87 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/media/fsl,imx95-csi-formatter.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: i.MX95 CSI Pixel Formatter
> +
> +maintainers:
> + - Guoniu Zhou <guoniu.zhou@nxp.com>
> +
> +description:
> + The CSI pixel formatting module found on i.MX95 uses packet info, pixel
> + and non-pixel data from the CSI-2 host controller and reformat them to
> + match Pixel Link(PL) definition.
> +
> +properties:
> + compatible:
> + const: fsl,imx95-csi-formatter
> +
> + reg:
> + maxItems: 1
> +
> + clocks:
> + maxItems: 1
> +
> + power-domains:
> + maxItems: 1
> +
> + ports:
> + $ref: /schemas/graph.yaml#/properties/ports
> +
> + properties:
> + port@0:
> + $ref: /schemas/graph.yaml#/$defs/port-base
> + unevaluatedProperties: false
> + description: MIPI CSI-2 RX IDI interface
> +
> + properties:
> + endpoint:
> + $ref: video-interfaces.yaml#
> + unevaluatedProperties: false
What properties defined in video-interfaces.yaml do you expect ? The
example below does not use any, and the driver in 2/2 doesn't appear to
parse any either.
> +
> + port@1:
> + $ref: /schemas/graph.yaml#/properties/port
> + description: Pixel Link Interface
> +
> +required:
> + - compatible
> + - reg
> + - clocks
> + - power-domains
> + - ports
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/clock/nxp,imx95-clock.h>
> +
> + formatter@20 {
> + compatible = "fsl,imx95-csi-formatter";
> + reg = <0x20 0x100>;
> + clocks = <&cameramix_csr IMX95_CLK_CAMBLK_CSI2_FOR0>;
> + power-domains = <&scmi_devpd 3>;
> +
> + ports {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + port@0 {
> + reg = <0>;
> +
> + endpoint {
> + remote-endpoint = <&mipi_csi_0_out>;
> + };
> + };
> +
> + port@1 {
> + reg = <1>;
> +
> + endpoint {
> + remote-endpoint = <&isi_in_2>;
> + };
> + };
> + };
> + };
--
Regards,
Laurent Pinchart
^ permalink raw reply
* Re: [PATCH v2 0/5] mm: reduce mmap_lock contention and improve page fault performance
From: David Hildenbrand (Arm) @ 2026-05-20 21:35 UTC (permalink / raw)
To: Matthew Wilcox, Barry Song
Cc: Liam R. Howlett, Suren Baghdasaryan, Lorenzo Stoakes, akpm,
linux-mm, vbabka, rppt, mhocko, jack, pfalcato, wanglian, chentao,
lianux.mm, kunwu.chan, liyangouwen1, chrisl, kasong, shikemeng,
nphamcs, bhe, youngjun.park, linux-arm-kernel, linux-kernel,
loongarch, linuxppc-dev, linux-riscv, linux-s390, Nanzhe Zhao
In-Reply-To: <ag4kj84EcKqamdB-@casper.infradead.org>
On 5/20/26 23:15, Matthew Wilcox wrote:
> On Thu, May 21, 2026 at 05:14:20AM +0800, Barry Song wrote:
>> My understanding is that we should not blame applications here. This is 2026:
>> there are basically only two kinds of applications — single-threaded and
>> multi-threaded — and single-threaded applications are nearly extinct.
>
> all of the applications i run are either single threaded or don't fork.
> what multithreaded applications call fork?
Traditionally the problem was random libraries using fork+execve to launch other
programs ... instead of using alternatives like posix_spwan (some use cases
require more work done before execve and cannot yet switch to that). I'd hope
that that is less of a problem on Android.
I assume Android zygote might be multi threaded? Maybe sshd as well? Systemd?
But I'd be surprised if there are really performance implications.
Not sure about webbroswers .... I think most of them switched to fork servers,
where I would assume fork servers would be single-threaded.
So, yeah, getting a clear understanding how this ends up being a problem on
Android would be great.
--
Cheers,
David
^ permalink raw reply
* Re: [PATCH v2 0/5] mm: reduce mmap_lock contention and improve page fault performance
From: Yang Shi @ 2026-05-20 21:39 UTC (permalink / raw)
To: David Hildenbrand (Arm)
Cc: Lorenzo Stoakes, Suren Baghdasaryan, Barry Song, Matthew Wilcox,
akpm, linux-mm, liam, vbabka, rppt, mhocko, jack, pfalcato,
wanglian, chentao, lianux.mm, kunwu.chan, liyangouwen1, chrisl,
kasong, shikemeng, nphamcs, bhe, youngjun.park, linux-arm-kernel,
linux-kernel, loongarch, linuxppc-dev, linux-riscv, linux-s390,
Nanzhe Zhao
In-Reply-To: <e6d1017a-e4c5-493e-bfca-932c6d64eaac@kernel.org>
On Wed, May 20, 2026 at 3:34 AM David Hildenbrand (Arm)
<david@kernel.org> wrote:
>
> On 5/19/26 14:53, Lorenzo Stoakes wrote:
> > On Mon, May 18, 2026 at 12:56:59PM -0700, Suren Baghdasaryan wrote:
> >
> >>>
> >>> I think we either need to fix `fork()`, or keep the current
> >>> behavior of dropping the VMA lock before performing I/O.
> >>
> >> I see. So, this problem arises from the fact that we are changing the
> >> pagefaults requiring I/O operation to hold VMA lock...
> >> And you want to lock VMA on fork only if vma_is_anonymous(vma) ||
> >> is_cow_mapping(vma->vm_flags). So, we will be blocking page faults for
> >> anonymous and COW VMAs only while holding mmap_write_lock, preventing
> >> any VMA modification. On the surface, that looks ok to me but I might
> >> be missing some corner cases. If nobody sees any obvious issues, I
> >> think it's worth a try.
> >
> > Not sure if you noticed but I did raise concerns ;)
> >
> > I wonder if you've confused the fault path and fork here, as I think Barry has
> > been a little unclear on that.
> >
> > What's being suggested in this thread is to fundamentally change fork behaviour
> > so it's different from the entire history of the kernel (or - presumably - at
> > least recent history :)
> I don't want fork() to become different in that regard.
>
> There is already a slight difference with vs. without per-VMA locks, because
> there is a window in-between us taking the write mmap_lock and all the per-VMA
> locks. I raised that previously [1] and assumed that it is probably fine.
>
> I also raised in the past why I think we must not allow concurrent page faults,
> at least as soon as anonymous memory is involved [2].
Thanks for sharing the context, it is quite helpful to understand the
race conditions. Because Lorenzo also raised the concern about page
fault race, I will reply to all the concerns regarding page fault race
together in this thread.
IIUC, there is already some sort of race with per vma lock. Before per
vma lock, mmap_lock did lock everything. So page fault happened either
before fork or after fork. But page fault can happen on other VMAs
which have not been lock'ed yet during fork with per vma lock. For
example, we have 3 VMAs, we lock the first VMA, but page fault still
can happen on the other 2 VMAs during fork if they already have
anon_vma. This is the status quo now, but it seems not harmful.
The bad race shared by David is caused by racing with copy page. So it
seems like it will be fine as long as we serialize copy page against
page fault if I don't miss anything. Since we decide whether to copy
page or not by checking vma->anon_vma, so it seems fine to not take
vma lock if vma->anon_vma is NULL. This will not introduce more race
either because setting up a new anon_vma in page fault or madvise
requires taking mmap_lock according to the earlier discussions.
Thanks,
Yang
>
> ... and I raised that this is pretty much slower by design right now: "Well, the
> design decision that CONFIG_PER_VMA_LOCK made for now to make page faults fast
> and to make blocking any page faults from happening to be slower ..." [3]
>
> [1] https://lore.kernel.org/all/970295ab-e85d-7af3-76e6-df53a5c52f8b@redhat.com/
> [2] https://lore.kernel.org/all/7e3f35cc-59b9-bf12-b8b1-4ed78223844a@redhat.com/
> [3] https://lore.kernel.org/all/2efa2c89-3765-721d-2c3c-00590054aa5b@redhat.com/
>
> --
> Cheers,
>
> David
>
^ permalink raw reply
* Re: [PATCH 09/10] [v6 omap] ARM: dts: omap2: add stlc4560 spi-wireless node
From: Johannes Berg @ 2026-05-20 21:39 UTC (permalink / raw)
To: Arnd Bergmann, linux-gpio
Cc: linux-kernel, Arnd Bergmann, Christian Lamparter, Aaro Koskinen,
Andreas Kemnade, Kevin Hilman, Roger Quadros, Tony Lindgren,
Thomas Bogendoerfer, John Paul Adrian Glaubitz, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
Linus Walleij, Bartosz Golaszewski, Dmitry Torokhov, Lee Jones,
Pavel Machek, Matti Vaittinen, Florian Fainelli, Jonas Gorski,
Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, linux-wireless, linux-omap,
linux-arm-kernel, linux-mips, linux-sh, linux-input, linux-leds,
netdev, Krzysztof Kozlowski
In-Reply-To: <20260520183815.2510387-10-arnd@kernel.org>
On Wed, 2026-05-20 at 20:38 +0200, Arnd Bergmann wrote:
>
> v1 through v5: adaptations that correspond to the binding updates
FWIW, I had just applied v5 of these three patches today, but didn't
send out a pull request yet. I'll do that tomorrow morning.
johannes
^ permalink raw reply
* Re: [PATCH 09/10] [v6 omap] ARM: dts: omap2: add stlc4560 spi-wireless node
From: Andreas Kemnade @ 2026-05-20 21:46 UTC (permalink / raw)
To: Arnd Bergmann
Cc: linux-gpio, linux-kernel, Arnd Bergmann, Christian Lamparter,
Johannes Berg, Aaro Koskinen, Kevin Hilman, Roger Quadros,
Tony Lindgren, Thomas Bogendoerfer, John Paul Adrian Glaubitz,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, Linus Walleij, Bartosz Golaszewski,
Dmitry Torokhov, Lee Jones, Pavel Machek, Matti Vaittinen,
Florian Fainelli, Jonas Gorski, Andrew Lunn, Vladimir Oltean,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
linux-wireless, linux-omap, linux-arm-kernel, linux-mips,
linux-sh, linux-input, linux-leds, netdev, Krzysztof Kozlowski
In-Reply-To: <20260520183815.2510387-10-arnd@kernel.org>
On Wed, 20 May 2026 20:38:14 +0200
Arnd Bergmann <arnd@kernel.org> wrote:
> From: Arnd Bergmann <arnd@arndb.de>
>
> Converted from the platform_device creation in board-n8x0.c.
>
> Link: https://lore.kernel.org/all/20230314163201.955689-1-arnd@kernel.org/
> Reviewed-by: Krzysztof Kozlowski <krzk@kernel.org>
> Reviewed-by: Linus Walleij <linusw@kernel.org>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
> v6: no changes
> v1 through v5: adaptations that correspond to the binding updates
> ---
> arch/arm/boot/dts/ti/omap/omap2.dtsi | 4 ++++
> arch/arm/boot/dts/ti/omap/omap2420-n8x0-common.dtsi | 12 ++++++++++++
> 2 files changed, 16 insertions(+)
>
Reviewed-by: Andreas Kemnade <andreas@kemnade.info>
^ permalink raw reply
* [PATCH] arm64: dts: hisilicon: hi3660-hikey960: move role-switch endpoint into connector
From: Akash Sukhavasi @ 2026-05-20 21:53 UTC (permalink / raw)
To: xuwei5; +Cc: krzk+dt, robh, conor+dt, linux-arm-kernel, devicetree,
linux-kernel
The rt1711h Type-C controller on the HiKey960 has the USB role-switch
endpoint placed as a top-level 'port' node, outside the connector
subnode. This triggers two dtbs_check warnings against
richtek,rt1711h.yaml:
- 'port' does not match any of the regexes: '^pinctrl-[0-9]+$'
- connector:ports: 'port@0' is a required property
Move the role-switch endpoint into the connector's port@0, which is
where usb-connector.yaml expects it. Update the DWC3 remote-endpoint
phandle accordingly.
The TCPM core (tcpm.c) looks up the role switch starting from the
connector fwnode via fwnode_usb_role_switch_get(). With the endpoint
inside the connector's port@0, it is found through the primary lookup
path rather than the device-level fallback.
Cross-compiled for arm64. Verified with dt_binding_check and
dtbs_check. Not runtime-tested on hardware.
Signed-off-by: Akash Sukhavasi <akash.sukhavasi@gmail.com>
---
.../boot/dts/hisilicon/hi3660-hikey960.dts | 17 +++++++----------
1 file changed, 7 insertions(+), 10 deletions(-)
diff --git a/arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dts b/arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dts
index c6056a85c..27fb08d34 100644
--- a/arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dts
+++ b/arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dts
@@ -550,6 +550,12 @@ usb_con: connector {
ports {
#address-cells = <1>;
#size-cells = <0>;
+ port@0 {
+ reg = <0>;
+ usb_con_hs: endpoint {
+ remote-endpoint = <&dwc3_role_switch>;
+ };
+ };
port@1 {
reg = <1>;
usb_con_ss: endpoint {
@@ -558,15 +564,6 @@ usb_con_ss: endpoint {
};
};
};
- port {
- #address-cells = <1>;
- #size-cells = <0>;
-
- rt1711h_ep: endpoint@0 {
- reg = <0>;
- remote-endpoint = <&dwc3_role_switch>;
- };
- };
};
adv7533: adv7533@39 {
@@ -683,7 +680,7 @@ port {
#size-cells = <0>;
dwc3_role_switch: endpoint@0 {
reg = <0>;
- remote-endpoint = <&rt1711h_ep>;
+ remote-endpoint = <&usb_con_hs>;
};
dwc3_ss: endpoint@1 {
--
2.54.0
^ permalink raw reply related
* [PATCH v6 0/9] dmaengine: Add new API to combine configuration and descriptor preparation
From: Frank.Li @ 2026-05-20 22:00 UTC (permalink / raw)
To: Vinod Koul, Manivannan Sadhasivam, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Christoph Hellwig,
Sagi Grimberg, Chaitanya Kulkarni, Herbert Xu, David S. Miller,
Nicolas Ferre, Alexandre Belloni, Claudiu Beznea, Koichiro Den,
Niklas Cassel
Cc: dmaengine, linux-kernel, linux-pci, linux-nvme, mhi,
linux-arm-msm, linux-crypto, linux-arm-kernel, imx, Frank Li,
Damien Le Moal
Previously, configuration and preparation required two separate calls. This
works well when configuration is done only once during initialization.
However, in cases where the burst length or source/destination address must
be adjusted for each transfer, calling two functions is verbose.
if (dmaengine_slave_config(chan, &sconf)) {
dev_err(dev, "DMA slave config fail\n");
return -EIO;
}
tx = dmaengine_prep_slave_single(chan, dma_local, len, dir, flags);
After new API added
tx = dmaengine_prep_config_single(chan, dma_local, len, dir, flags, &sconf);
Additional, prevous two calls requires additional locking to ensure both
steps complete atomically.
mutex_lock()
dmaengine_slave_config()
dmaengine_prep_slave_single()
mutex_unlock()
after new API added, mutex lock can be moved. See patch
nvmet: pci-epf: Use dmaengine_prep_config_single_safe() API
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
Changes in v6:
- Fix sashaki AI report problem, detail see each patch's change log
- Link to v5: https://lore.kernel.org/r/20260512-dma_prep_config-v5-0-26865bf7d935@nxp.com
Changes in v5:
- collect Mani's reviewed-by tags
- use kernel doc for new APIs.
- Link to v4: https://lore.kernel.org/r/20260506-dma_prep_config-v4-0-85b3d22babff@nxp.com
Changes in v4:
- remove void* context in config_prep() callback
- use spin lock to protect config() and prep().
- Link to v3: https://lore.kernel.org/r/20260105-dma_prep_config-v3-0-a8480362fd42@nxp.com
Changes in v3:
- collect review tags
- create safe version in framework
- Link to v2: https://lore.kernel.org/r/20251218-dma_prep_config-v2-0-c07079836128@nxp.com
Changes in v2:
- Use name dmaengine_prep_config_single() and dmaengine_prep_config_sg()
- Add _safe version to avoid confuse, which needn't additional mutex.
- Update document/
- Update commit message. add () for function name. Use upcase for subject.
- Add more explain for remove lock.
- Link to v1: https://lore.kernel.org/r/20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com
---
Frank Li (9):
dmaengine: Add API to combine configuration and preparation (sg and single)
dmaengine: Add safe API to combine configuration and preparation
PCI: endpoint: pci-epf-test: Use dmaenigne_prep_config_single() to simplify code
dmaengine: dw-edma: Use new .device_prep_config_sg() callback
dmaengine: dw-edma: Pass dma_slave_config to dw_edma_device_transfer()
nvmet: pci-epf: Remove unnecessary dmaengine_terminate_sync() on each DMA transfer
nvmet: pci-epf: Use dmaengine_prep_config_single_safe() API
PCI: epf-mhi: Use dmaengine_prep_config_single() to simplify code
crypto: atmel: Use dmaengine_prep_config_sg() API
Documentation/driver-api/dmaengine/client.rst | 9 ++
drivers/crypto/atmel-aes.c | 10 +-
drivers/dma/dmaengine.c | 2 +
drivers/dma/dw-edma/dw-edma-core.c | 41 +++++--
drivers/nvme/target/pci-epf.c | 24 +----
drivers/pci/endpoint/functions/pci-epf-mhi.c | 52 +++------
drivers/pci/endpoint/functions/pci-epf-test.c | 8 +-
include/linux/dmaengine.h | 149 ++++++++++++++++++++++++--
8 files changed, 208 insertions(+), 87 deletions(-)
---
base-commit: 254f49634ee16a731174d2ae34bc50bd5f45e731
change-id: 20251204-dma_prep_config-654170d245a2
Best regards,
--
Frank Li <Frank.Li@nxp.com>
^ permalink raw reply
* [PATCH v6 1/9] dmaengine: Add API to combine configuration and preparation (sg and single)
From: Frank.Li @ 2026-05-20 22:00 UTC (permalink / raw)
To: Vinod Koul, Manivannan Sadhasivam, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Christoph Hellwig,
Sagi Grimberg, Chaitanya Kulkarni, Herbert Xu, David S. Miller,
Nicolas Ferre, Alexandre Belloni, Claudiu Beznea, Koichiro Den,
Niklas Cassel
Cc: dmaengine, linux-kernel, linux-pci, linux-nvme, mhi,
linux-arm-msm, linux-crypto, linux-arm-kernel, imx, Frank Li
In-Reply-To: <20260520-dma_prep_config-v6-0-06e49b7acb38@nxp.com>
From: Frank Li <Frank.Li@nxp.com>
Previously, configuration and preparation required two separate calls. This
works well when configuration is done only once during initialization.
However, in cases where the burst length or source/destination address must
be adjusted for each transfer, calling two functions is verbose and
requires additional locking to ensure both steps complete atomically.
Add a new API dmaengine_prep_config_single() and dmaengine_prep_config_sg()
and callback device_prep_config_sg() that combines configuration and
preparation into a single operation. If the configuration argument is
passed as NULL, fall back to the existing implementation.
Tested-by: Niklas Cassel <cassel@kernel.org>
Acked-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
change in v4
- drop context in device_prep_config_sg()
change in v3
- remove Deprecated for callback device_prep_slave_sg().
- Move condition check before sg init.
- split function at return type.
- move safe version to next patch
change in v2
- add () for function
- use short name device_prep_sg(), remove "slave" and "config". the 'slave'
is reduntant. after remove slave, the function name is difference existed
one, so remove _config suffix.
---
Documentation/driver-api/dmaengine/client.rst | 9 ++++
include/linux/dmaengine.h | 63 +++++++++++++++++++++++----
2 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/Documentation/driver-api/dmaengine/client.rst b/Documentation/driver-api/dmaengine/client.rst
index d491e385d61a9..5ee5d4a3596dd 100644
--- a/Documentation/driver-api/dmaengine/client.rst
+++ b/Documentation/driver-api/dmaengine/client.rst
@@ -80,6 +80,10 @@ The details of these operations are:
- slave_sg: DMA a list of scatter gather buffers from/to a peripheral
+ - config_sg: Similar with slave_sg, just pass down dma_slave_config
+ struct to avoid calling dmaengine_slave_config() every time adjusting the
+ burst length or the FIFO address is needed.
+
- peripheral_dma_vec: DMA an array of scatter gather buffers from/to a
peripheral. Similar to slave_sg, but uses an array of dma_vec
structures instead of a scatterlist.
@@ -106,6 +110,11 @@ The details of these operations are:
unsigned int sg_len, enum dma_data_direction direction,
unsigned long flags);
+ struct dma_async_tx_descriptor *dmaengine_prep_config_sg(
+ struct dma_chan *chan, struct scatterlist *sgl,
+ unsigned int sg_len, enum dma_transfer_direction dir,
+ unsigned long flags, struct dma_slave_config *config);
+
struct dma_async_tx_descriptor *dmaengine_prep_peripheral_dma_vec(
struct dma_chan *chan, const struct dma_vec *vecs,
size_t nents, enum dma_data_direction direction,
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index b3d251c9734e9..defa377d2ef54 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -835,6 +835,7 @@ struct dma_filter {
* where the address and size of each segment is located in one entry of
* the dma_vec array.
* @device_prep_slave_sg: prepares a slave dma operation
+ * @device_prep_config_sg: prepares a slave DMA operation with dma_slave_config
* @device_prep_dma_cyclic: prepare a cyclic dma operation suitable for audio.
* The function takes a buffer of size buf_len. The callback function will
* be called after period_len bytes have been transferred.
@@ -934,6 +935,10 @@ struct dma_device {
struct dma_chan *chan, struct scatterlist *sgl,
unsigned int sg_len, enum dma_transfer_direction direction,
unsigned long flags, void *context);
+ struct dma_async_tx_descriptor *(*device_prep_config_sg)(
+ struct dma_chan *chan, struct scatterlist *sgl,
+ unsigned int sg_len, enum dma_transfer_direction direction,
+ unsigned long flags, struct dma_slave_config *config);
struct dma_async_tx_descriptor *(*device_prep_dma_cyclic)(
struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
size_t period_len, enum dma_transfer_direction direction,
@@ -974,22 +979,44 @@ static inline bool is_slave_direction(enum dma_transfer_direction direction)
(direction == DMA_DEV_TO_DEV);
}
-static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_single(
- struct dma_chan *chan, dma_addr_t buf, size_t len,
- enum dma_transfer_direction dir, unsigned long flags)
+static inline struct dma_async_tx_descriptor *
+dmaengine_prep_config_single(struct dma_chan *chan, dma_addr_t buf, size_t len,
+ enum dma_transfer_direction dir,
+ unsigned long flags,
+ struct dma_slave_config *config)
{
struct scatterlist sg;
+
+ if (!chan || !chan->device)
+ return NULL;
+
sg_init_table(&sg, 1);
sg_dma_address(&sg) = buf;
sg_dma_len(&sg) = len;
- if (!chan || !chan->device || !chan->device->device_prep_slave_sg)
+ if (chan->device->device_prep_config_sg)
+ return chan->device->device_prep_config_sg(chan, &sg, 1, dir,
+ flags, config);
+
+ if (config)
+ if (dmaengine_slave_config(chan, config))
+ return NULL;
+
+ if (!chan->device->device_prep_slave_sg)
return NULL;
return chan->device->device_prep_slave_sg(chan, &sg, 1,
dir, flags, NULL);
}
+static inline struct dma_async_tx_descriptor *
+dmaengine_prep_slave_single(struct dma_chan *chan, dma_addr_t buf, size_t len,
+ enum dma_transfer_direction dir,
+ unsigned long flags)
+{
+ return dmaengine_prep_config_single(chan, buf, len, dir, flags, NULL);
+}
+
/**
* dmaengine_prep_peripheral_dma_vec() - Prepare a DMA scatter-gather descriptor
* @chan: The channel to be used for this descriptor
@@ -1010,17 +1037,37 @@ static inline struct dma_async_tx_descriptor *dmaengine_prep_peripheral_dma_vec(
dir, flags);
}
-static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_sg(
- struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len,
- enum dma_transfer_direction dir, unsigned long flags)
+static inline struct dma_async_tx_descriptor *
+dmaengine_prep_config_sg(struct dma_chan *chan, struct scatterlist *sgl,
+ unsigned int sg_len, enum dma_transfer_direction dir,
+ unsigned long flags, struct dma_slave_config *config)
{
- if (!chan || !chan->device || !chan->device->device_prep_slave_sg)
+ if (!chan || !chan->device)
+ return NULL;
+
+ if (chan->device->device_prep_config_sg)
+ return chan->device->device_prep_config_sg(chan, sgl, sg_len,
+ dir, flags, config);
+
+ if (config)
+ if (dmaengine_slave_config(chan, config))
+ return NULL;
+
+ if (!chan->device->device_prep_slave_sg)
return NULL;
return chan->device->device_prep_slave_sg(chan, sgl, sg_len,
dir, flags, NULL);
}
+static inline struct dma_async_tx_descriptor *
+dmaengine_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
+ unsigned int sg_len, enum dma_transfer_direction dir,
+ unsigned long flags)
+{
+ return dmaengine_prep_config_sg(chan, sgl, sg_len, dir, flags, NULL);
+}
+
#ifdef CONFIG_RAPIDIO_DMA_ENGINE
struct rio_dma_ext;
static inline struct dma_async_tx_descriptor *dmaengine_prep_rio_sg(
--
2.43.0
^ permalink raw reply related
* [PATCH v6 2/9] dmaengine: Add safe API to combine configuration and preparation
From: Frank.Li @ 2026-05-20 22:00 UTC (permalink / raw)
To: Vinod Koul, Manivannan Sadhasivam, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Christoph Hellwig,
Sagi Grimberg, Chaitanya Kulkarni, Herbert Xu, David S. Miller,
Nicolas Ferre, Alexandre Belloni, Claudiu Beznea, Koichiro Den,
Niklas Cassel
Cc: dmaengine, linux-kernel, linux-pci, linux-nvme, mhi,
linux-arm-msm, linux-crypto, linux-arm-kernel, imx, Frank Li
In-Reply-To: <20260520-dma_prep_config-v6-0-06e49b7acb38@nxp.com>
From: Frank Li <Frank.Li@nxp.com>
Introduce dmaengine_prep_config_single_safe() and
dmaengine_prep_config_sg_safe() to provide a reentrant-safe way to
combine slave configuration and transfer preparation.
Drivers may implement the new device_prep_config_sg() callback to perform
both steps atomically. If the callback is not provided, the helpers fall
back to calling dmaengine_slave_config() followed by
dmaengine_prep_slave_sg() under per-channel spinlock protection.
Tested-by: Niklas Cassel <cassel@kernel.org>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
change in v6
- replace mutex with spinlock in commit message
- use spinlock_saveirq according to AI review results
"The documentation in struct dma_chan notes that *_prep() may be called
from a completion callback. Since completion callbacks often execute in
softirq or hardirq contexts, if a thread calls this function from
process context, local interrupts remain enabled.
If a DMA interrupt fires on the same CPU while the lock is held, the
completion callback could attempt to call this function again to queue
the next transfer, leading it to wait on the already-held chan->lock.
Does this fallback path need to use spin_lock_irqsave() and
spin_unlock_irqrestore() to safely disable interrupts?
"
chagne in v5
- remove reduntant lock commments.
- use kernel doc to descritp API
chagne in v4
- use spinlock() to protect config() and prep()
change in v3
- new patch
---
drivers/dma/dmaengine.c | 2 ++
include/linux/dmaengine.h | 86 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 88 insertions(+)
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 405bd2fbb4a3b..ba29e60160c1a 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -1099,6 +1099,8 @@ static int __dma_async_device_channel_register(struct dma_device *device,
chan->dev->device.parent = device->dev;
chan->dev->chan = chan;
chan->dev->dev_id = device->dev_id;
+ spin_lock_init(&chan->lock);
+
if (!name)
dev_set_name(&chan->dev->device, "dma%dchan%d", device->dev_id, chan->chan_id);
else
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index defa377d2ef54..6fe46c0c94527 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -322,6 +322,8 @@ struct dma_router {
* @slave: ptr to the device using this channel
* @cookie: last cookie value returned to client
* @completed_cookie: last completed cookie for this channel
+ * @lock: protect between config and prepare transfer when driver have not
+ * implemented callback device_prep_config_sg().
* @chan_id: channel ID for sysfs
* @dev: class device for sysfs
* @name: backlink name for sysfs
@@ -341,6 +343,12 @@ struct dma_chan {
dma_cookie_t cookie;
dma_cookie_t completed_cookie;
+ /*
+ * protect between config and prepare transfer because *_prep() may be
+ * called from complete callback, which is in GFP_NOSLEEP context.
+ */
+ spinlock_t lock;
+
/* sysfs */
int chan_id;
struct dma_chan_dev *dev;
@@ -1068,6 +1076,84 @@ dmaengine_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
return dmaengine_prep_config_sg(chan, sgl, sg_len, dir, flags, NULL);
}
+/**
+ * dmaengine_prep_config_sg_safe - prepare a scatter-gather DMA transfer
+ * with atomic slave configuration update
+ * @chan: DMA channel
+ * @sgl: scatterlist for the transfer
+ * @sg_len: number of entries in @sgl
+ * @dir: DMA transfer direction
+ * @flags: transfer preparation flags
+ * @config: DMA slave configuration for this transfer
+ *
+ * Prepare a DMA scatter-gather transfer together with a corresponding slave
+ * configuration update in a re-entrant and race-safe manner.
+ *
+ * DMA engine drivers may implement the optional
+ * device_prep_config_sg() callback to perform both the slave configuration
+ * and descriptor preparation atomically. In this case, the operation is
+ * fully handled by the DMA engine driver.
+ *
+ * If the DMA engine driver does not implement device_prep_config_sg(), falls
+ * back to calling dmaengine_slave_config() followed by dmaengine_prep_slave_sg().
+ * The fallback path is protected by a per-channel spinlock to ensure that
+ * concurrent callers cannot interleave configuration and descriptor preparation
+ * on the same DMA channel.
+ *
+ * Return: Pointer to a prepared DMA async transaction descriptor on success,
+ * or %NULL if the transfer could not be prepared.
+ */
+static inline struct dma_async_tx_descriptor *
+dmaengine_prep_config_sg_safe(struct dma_chan *chan, struct scatterlist *sgl,
+ unsigned int sg_len,
+ enum dma_transfer_direction dir,
+ unsigned long flags,
+ struct dma_slave_config *config)
+{
+ struct dma_async_tx_descriptor *tx;
+ unsigned long spinlock_flags;
+
+ if (!chan || !chan->device)
+ return NULL;
+
+ if (!chan->device->device_prep_config_sg)
+ spin_lock_irqsave(&chan->lock, spinlock_flags);
+
+ tx = dmaengine_prep_config_sg(chan, sgl, sg_len, dir, flags, config);
+
+ if (!chan->device->device_prep_config_sg)
+ spin_unlock_irqrestore(&chan->lock, spinlock_flags);
+
+ return tx;
+}
+
+/**
+ * dmaengine_prep_config_single_safe - prepare a single-buffer DMA transfer
+ * with atomic slave configuration update
+ * @chan: DMA channel
+ * @buf: DMA buffer address
+ * @len: length of the transfer in bytes
+ * @dir: DMA transfer direction
+ * @flags: transfer preparation flags
+ * @config: DMA slave configuration for this transfer
+ *
+ * Detail see dmaengine_prep_config_sg_safe().
+ */
+static inline struct dma_async_tx_descriptor *
+dmaengine_prep_config_single_safe(struct dma_chan *chan, dma_addr_t buf,
+ size_t len, enum dma_transfer_direction dir,
+ unsigned long flags,
+ struct dma_slave_config *config)
+{
+ struct scatterlist sg;
+
+ sg_init_table(&sg, 1);
+ sg_dma_address(&sg) = buf;
+ sg_dma_len(&sg) = len;
+
+ return dmaengine_prep_config_sg_safe(chan, &sg, 1, dir, flags, config);
+}
+
#ifdef CONFIG_RAPIDIO_DMA_ENGINE
struct rio_dma_ext;
static inline struct dma_async_tx_descriptor *dmaengine_prep_rio_sg(
--
2.43.0
^ permalink raw reply related
* [PATCH v6 3/9] PCI: endpoint: pci-epf-test: Use dmaenigne_prep_config_single() to simplify code
From: Frank.Li @ 2026-05-20 22:00 UTC (permalink / raw)
To: Vinod Koul, Manivannan Sadhasivam, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Christoph Hellwig,
Sagi Grimberg, Chaitanya Kulkarni, Herbert Xu, David S. Miller,
Nicolas Ferre, Alexandre Belloni, Claudiu Beznea, Koichiro Den,
Niklas Cassel
Cc: dmaengine, linux-kernel, linux-pci, linux-nvme, mhi,
linux-arm-msm, linux-crypto, linux-arm-kernel, imx, Frank Li,
Damien Le Moal
In-Reply-To: <20260520-dma_prep_config-v6-0-06e49b7acb38@nxp.com>
From: Frank Li <Frank.Li@nxp.com>
Use dmaenigne_prep_config_single() to simplify code.
No functional change.
Tested-by: Niklas Cassel <cassel@kernel.org>
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Acked-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
change in v3
- add Damien Le Moal review tag
---
drivers/pci/endpoint/functions/pci-epf-test.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index 591d301fa89d8..0f5cf2d795108 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -182,12 +182,8 @@ static int pci_epf_test_data_transfer(struct pci_epf_test *epf_test,
else
sconf.src_addr = dma_remote;
- if (dmaengine_slave_config(chan, &sconf)) {
- dev_err(dev, "DMA slave config fail\n");
- return -EIO;
- }
- tx = dmaengine_prep_slave_single(chan, dma_local, len, dir,
- flags);
+ tx = dmaengine_prep_config_single(chan, dma_local, len,
+ dir, flags, &sconf);
} else {
tx = dmaengine_prep_dma_memcpy(chan, dma_dst, dma_src, len,
flags);
--
2.43.0
^ permalink raw reply related
* [PATCH v6 4/9] dmaengine: dw-edma: Use new .device_prep_config_sg() callback
From: Frank.Li @ 2026-05-20 22:00 UTC (permalink / raw)
To: Vinod Koul, Manivannan Sadhasivam, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Christoph Hellwig,
Sagi Grimberg, Chaitanya Kulkarni, Herbert Xu, David S. Miller,
Nicolas Ferre, Alexandre Belloni, Claudiu Beznea, Koichiro Den,
Niklas Cassel
Cc: dmaengine, linux-kernel, linux-pci, linux-nvme, mhi,
linux-arm-msm, linux-crypto, linux-arm-kernel, imx, Frank Li,
Damien Le Moal
In-Reply-To: <20260520-dma_prep_config-v6-0-06e49b7acb38@nxp.com>
From: Frank Li <Frank.Li@nxp.com>
Use the new .device_prep_config_sg() callback to combine configuration and
descriptor preparation.
No functional changes.
Tested-by: Niklas Cassel <cassel@kernel.org>
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
change in v6
- check dw_edma_device_config() return value; find by sashiko AI.
change in v4
- drop context in callback.
change in v3
- add Damien Le Moal review tag
---
drivers/dma/dw-edma/dw-edma-core.c | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index c2feb3adc79fa..92572dd8131e6 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -577,10 +577,11 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
}
static struct dma_async_tx_descriptor *
-dw_edma_device_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,
- unsigned int len,
- enum dma_transfer_direction direction,
- unsigned long flags, void *context)
+dw_edma_device_prep_config_sg(struct dma_chan *dchan, struct scatterlist *sgl,
+ unsigned int len,
+ enum dma_transfer_direction direction,
+ unsigned long flags,
+ struct dma_slave_config *config)
{
struct dw_edma_transfer xfer;
@@ -591,6 +592,9 @@ dw_edma_device_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,
xfer.flags = flags;
xfer.type = EDMA_XFER_SCATTER_GATHER;
+ if (config && dw_edma_device_config(dchan, config))
+ return NULL;
+
return dw_edma_device_transfer(&xfer);
}
@@ -970,7 +974,7 @@ static int dw_edma_channel_setup(struct dw_edma *dw, u32 wr_alloc, u32 rd_alloc)
dma->device_terminate_all = dw_edma_device_terminate_all;
dma->device_issue_pending = dw_edma_device_issue_pending;
dma->device_tx_status = dw_edma_device_tx_status;
- dma->device_prep_slave_sg = dw_edma_device_prep_slave_sg;
+ dma->device_prep_config_sg = dw_edma_device_prep_config_sg;
dma->device_prep_dma_cyclic = dw_edma_device_prep_dma_cyclic;
dma->device_prep_interleaved_dma = dw_edma_device_prep_interleaved_dma;
--
2.43.0
^ permalink raw reply related
* [PATCH v6 5/9] dmaengine: dw-edma: Pass dma_slave_config to dw_edma_device_transfer()
From: Frank.Li @ 2026-05-20 22:00 UTC (permalink / raw)
To: Vinod Koul, Manivannan Sadhasivam, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Christoph Hellwig,
Sagi Grimberg, Chaitanya Kulkarni, Herbert Xu, David S. Miller,
Nicolas Ferre, Alexandre Belloni, Claudiu Beznea, Koichiro Den,
Niklas Cassel
Cc: dmaengine, linux-kernel, linux-pci, linux-nvme, mhi,
linux-arm-msm, linux-crypto, linux-arm-kernel, imx, Frank Li
In-Reply-To: <20260520-dma_prep_config-v6-0-06e49b7acb38@nxp.com>
From: Frank Li <Frank.Li@nxp.com>
Pass dma_slave_config to dw_edma_device_transfer() to support atomic
configuration and descriptor preparation when a non-NULL config is
provided to device_prep_config_sg().
Tested-by: Niklas Cassel <cassel@kernel.org>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
change in v3
- rewrite dw_edma_device_slave_config() according to Damien's suggestion.
---
drivers/dma/dw-edma/dw-edma-core.c | 27 +++++++++++++++++++++------
1 file changed, 21 insertions(+), 6 deletions(-)
diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index 92572dd8131e6..ba37bc983dcd2 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -267,6 +267,20 @@ static int dw_edma_device_config(struct dma_chan *dchan,
return 0;
}
+static struct dma_slave_config *
+dw_edma_device_get_config(struct dma_chan *dchan,
+ struct dma_slave_config *config)
+{
+ struct dw_edma_chan *chan;
+
+ if (config)
+ return config;
+
+ chan = dchan2dw_edma_chan(dchan);
+
+ return &chan->config;
+}
+
static int dw_edma_device_pause(struct dma_chan *dchan)
{
struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
@@ -385,7 +399,8 @@ dw_edma_device_tx_status(struct dma_chan *dchan, dma_cookie_t cookie,
}
static struct dma_async_tx_descriptor *
-dw_edma_device_transfer(struct dw_edma_transfer *xfer)
+dw_edma_device_transfer(struct dw_edma_transfer *xfer,
+ struct dma_slave_config *config)
{
struct dw_edma_chan *chan = dchan2dw_edma_chan(xfer->dchan);
enum dma_transfer_direction dir = xfer->direction;
@@ -472,8 +487,8 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
src_addr = xfer->xfer.il->src_start;
dst_addr = xfer->xfer.il->dst_start;
} else {
- src_addr = chan->config.src_addr;
- dst_addr = chan->config.dst_addr;
+ src_addr = config->src_addr;
+ dst_addr = config->dst_addr;
}
if (dir == DMA_DEV_TO_MEM)
@@ -595,7 +610,7 @@ dw_edma_device_prep_config_sg(struct dma_chan *dchan, struct scatterlist *sgl,
if (config && dw_edma_device_config(dchan, config))
return NULL;
- return dw_edma_device_transfer(&xfer);
+ return dw_edma_device_transfer(&xfer, dw_edma_device_get_config(dchan, config));
}
static struct dma_async_tx_descriptor *
@@ -614,7 +629,7 @@ dw_edma_device_prep_dma_cyclic(struct dma_chan *dchan, dma_addr_t paddr,
xfer.flags = flags;
xfer.type = EDMA_XFER_CYCLIC;
- return dw_edma_device_transfer(&xfer);
+ return dw_edma_device_transfer(&xfer, dw_edma_device_get_config(dchan, NULL));
}
static struct dma_async_tx_descriptor *
@@ -630,7 +645,7 @@ dw_edma_device_prep_interleaved_dma(struct dma_chan *dchan,
xfer.flags = flags;
xfer.type = EDMA_XFER_INTERLEAVED;
- return dw_edma_device_transfer(&xfer);
+ return dw_edma_device_transfer(&xfer, dw_edma_device_get_config(dchan, NULL));
}
static void dw_hdma_set_callback_result(struct virt_dma_desc *vd,
--
2.43.0
^ permalink raw reply related
* [PATCH v6 6/9] nvmet: pci-epf: Remove unnecessary dmaengine_terminate_sync() on each DMA transfer
From: Frank.Li @ 2026-05-20 22:00 UTC (permalink / raw)
To: Vinod Koul, Manivannan Sadhasivam, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Christoph Hellwig,
Sagi Grimberg, Chaitanya Kulkarni, Herbert Xu, David S. Miller,
Nicolas Ferre, Alexandre Belloni, Claudiu Beznea, Koichiro Den,
Niklas Cassel
Cc: dmaengine, linux-kernel, linux-pci, linux-nvme, mhi,
linux-arm-msm, linux-crypto, linux-arm-kernel, imx, Frank Li,
Damien Le Moal
In-Reply-To: <20260520-dma_prep_config-v6-0-06e49b7acb38@nxp.com>
From: Frank Li <Frank.Li@nxp.com>
dmaengine_terminate_sync() cancels all pending requests. Calling it for
every DMA transfer is unnecessary and counterproductive. This function is
generally intended for cleanup paths such as module removal, device close,
or unbind operations.
Remove the redundant calls for success path and keep it only at error path.
Tested-by: Niklas Cassel <cassel@kernel.org>
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Acked-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
This one also fix stress test failure after remove mutex and use new API
dmaengine_prep_slave_sg_config().
---
drivers/nvme/target/pci-epf.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/nvme/target/pci-epf.c b/drivers/nvme/target/pci-epf.c
index 4e9db96ebfecd..2afe8f4d0e461 100644
--- a/drivers/nvme/target/pci-epf.c
+++ b/drivers/nvme/target/pci-epf.c
@@ -420,10 +420,9 @@ static int nvmet_pci_epf_dma_transfer(struct nvmet_pci_epf *nvme_epf,
if (dma_sync_wait(chan, cookie) != DMA_COMPLETE) {
dev_err(dev, "DMA transfer failed\n");
ret = -EIO;
+ dmaengine_terminate_sync(chan);
}
- dmaengine_terminate_sync(chan);
-
unmap:
dma_unmap_single(dma_dev, dma_addr, seg->length, dir);
--
2.43.0
^ permalink raw reply related
* [PATCH v6 7/9] nvmet: pci-epf: Use dmaengine_prep_config_single_safe() API
From: Frank.Li @ 2026-05-20 22:00 UTC (permalink / raw)
To: Vinod Koul, Manivannan Sadhasivam, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Christoph Hellwig,
Sagi Grimberg, Chaitanya Kulkarni, Herbert Xu, David S. Miller,
Nicolas Ferre, Alexandre Belloni, Claudiu Beznea, Koichiro Den,
Niklas Cassel
Cc: dmaengine, linux-kernel, linux-pci, linux-nvme, mhi,
linux-arm-msm, linux-crypto, linux-arm-kernel, imx, Frank Li
In-Reply-To: <20260520-dma_prep_config-v6-0-06e49b7acb38@nxp.com>
From: Frank Li <Frank.Li@nxp.com>
Use the new dmaengine_prep_config_single_safe() API to combine the
configuration and descriptor preparation into a single call.
Since dmaengine_prep_config_single_safe() performs the configuration and
preparation atomically and the mutex can be removed.
Tested-by: Niklas Cassel <cassel@kernel.org>
Acked-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
change in v6
- remove local unused variable lock (sashika AI)
---
drivers/nvme/target/pci-epf.c | 21 ++++-----------------
1 file changed, 4 insertions(+), 17 deletions(-)
diff --git a/drivers/nvme/target/pci-epf.c b/drivers/nvme/target/pci-epf.c
index 2afe8f4d0e461..f917d6ec278b7 100644
--- a/drivers/nvme/target/pci-epf.c
+++ b/drivers/nvme/target/pci-epf.c
@@ -368,18 +368,15 @@ static int nvmet_pci_epf_dma_transfer(struct nvmet_pci_epf *nvme_epf,
struct dma_chan *chan;
dma_cookie_t cookie;
dma_addr_t dma_addr;
- struct mutex *lock;
int ret;
switch (dir) {
case DMA_FROM_DEVICE:
- lock = &nvme_epf->dma_rx_lock;
chan = nvme_epf->dma_rx_chan;
sconf.direction = DMA_DEV_TO_MEM;
sconf.src_addr = seg->pci_addr;
break;
case DMA_TO_DEVICE:
- lock = &nvme_epf->dma_tx_lock;
chan = nvme_epf->dma_tx_chan;
sconf.direction = DMA_MEM_TO_DEV;
sconf.dst_addr = seg->pci_addr;
@@ -388,22 +385,15 @@ static int nvmet_pci_epf_dma_transfer(struct nvmet_pci_epf *nvme_epf,
return -EINVAL;
}
- mutex_lock(lock);
-
dma_dev = dmaengine_get_dma_device(chan);
dma_addr = dma_map_single(dma_dev, seg->buf, seg->length, dir);
ret = dma_mapping_error(dma_dev, dma_addr);
if (ret)
- goto unlock;
-
- ret = dmaengine_slave_config(chan, &sconf);
- if (ret) {
- dev_err(dev, "Failed to configure DMA channel\n");
- goto unmap;
- }
+ return ret;
- desc = dmaengine_prep_slave_single(chan, dma_addr, seg->length,
- sconf.direction, DMA_CTRL_ACK);
+ desc = dmaengine_prep_config_single_safe(chan, dma_addr, seg->length,
+ sconf.direction,
+ DMA_CTRL_ACK, &sconf);
if (!desc) {
dev_err(dev, "Failed to prepare DMA\n");
ret = -EIO;
@@ -426,9 +416,6 @@ static int nvmet_pci_epf_dma_transfer(struct nvmet_pci_epf *nvme_epf,
unmap:
dma_unmap_single(dma_dev, dma_addr, seg->length, dir);
-unlock:
- mutex_unlock(lock);
-
return ret;
}
--
2.43.0
^ permalink raw reply related
* [PATCH v6 8/9] PCI: epf-mhi: Use dmaengine_prep_config_single() to simplify code
From: Frank.Li @ 2026-05-20 22:00 UTC (permalink / raw)
To: Vinod Koul, Manivannan Sadhasivam, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Christoph Hellwig,
Sagi Grimberg, Chaitanya Kulkarni, Herbert Xu, David S. Miller,
Nicolas Ferre, Alexandre Belloni, Claudiu Beznea, Koichiro Den,
Niklas Cassel
Cc: dmaengine, linux-kernel, linux-pci, linux-nvme, mhi,
linux-arm-msm, linux-crypto, linux-arm-kernel, imx, Frank Li
In-Reply-To: <20260520-dma_prep_config-v6-0-06e49b7acb38@nxp.com>
From: Frank Li <Frank.Li@nxp.com>
Use dmaengine_prep_config_single() to simplify
pci_epf_mhi_edma_read[_sync]() and pci_epf_mhi_edma_write[_sync]().
No functional change.
Tested-by: Niklas Cassel <cassel@kernel.org>
Acked-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
Keep mutex lock because sync with other function.
---
drivers/pci/endpoint/functions/pci-epf-mhi.c | 52 +++++++++-------------------
1 file changed, 16 insertions(+), 36 deletions(-)
diff --git a/drivers/pci/endpoint/functions/pci-epf-mhi.c b/drivers/pci/endpoint/functions/pci-epf-mhi.c
index 7f5326925ed54..c3e3b58fb86cd 100644
--- a/drivers/pci/endpoint/functions/pci-epf-mhi.c
+++ b/drivers/pci/endpoint/functions/pci-epf-mhi.c
@@ -328,12 +328,6 @@ static int pci_epf_mhi_edma_read(struct mhi_ep_cntrl *mhi_cntrl,
config.direction = DMA_DEV_TO_MEM;
config.src_addr = buf_info->host_addr;
- ret = dmaengine_slave_config(chan, &config);
- if (ret) {
- dev_err(dev, "Failed to configure DMA channel\n");
- goto err_unlock;
- }
-
dst_addr = dma_map_single(dma_dev, buf_info->dev_addr, buf_info->size,
DMA_FROM_DEVICE);
ret = dma_mapping_error(dma_dev, dst_addr);
@@ -342,9 +336,10 @@ static int pci_epf_mhi_edma_read(struct mhi_ep_cntrl *mhi_cntrl,
goto err_unlock;
}
- desc = dmaengine_prep_slave_single(chan, dst_addr, buf_info->size,
- DMA_DEV_TO_MEM,
- DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
+ desc = dmaengine_prep_config_single(chan, dst_addr, buf_info->size,
+ DMA_DEV_TO_MEM,
+ DMA_CTRL_ACK | DMA_PREP_INTERRUPT,
+ &config);
if (!desc) {
dev_err(dev, "Failed to prepare DMA\n");
ret = -EIO;
@@ -401,12 +396,6 @@ static int pci_epf_mhi_edma_write(struct mhi_ep_cntrl *mhi_cntrl,
config.direction = DMA_MEM_TO_DEV;
config.dst_addr = buf_info->host_addr;
- ret = dmaengine_slave_config(chan, &config);
- if (ret) {
- dev_err(dev, "Failed to configure DMA channel\n");
- goto err_unlock;
- }
-
src_addr = dma_map_single(dma_dev, buf_info->dev_addr, buf_info->size,
DMA_TO_DEVICE);
ret = dma_mapping_error(dma_dev, src_addr);
@@ -415,9 +404,10 @@ static int pci_epf_mhi_edma_write(struct mhi_ep_cntrl *mhi_cntrl,
goto err_unlock;
}
- desc = dmaengine_prep_slave_single(chan, src_addr, buf_info->size,
- DMA_MEM_TO_DEV,
- DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
+ desc = dmaengine_prep_config_single(chan, src_addr, buf_info->size,
+ DMA_MEM_TO_DEV,
+ DMA_CTRL_ACK | DMA_PREP_INTERRUPT,
+ &config);
if (!desc) {
dev_err(dev, "Failed to prepare DMA\n");
ret = -EIO;
@@ -506,12 +496,6 @@ static int pci_epf_mhi_edma_read_async(struct mhi_ep_cntrl *mhi_cntrl,
config.direction = DMA_DEV_TO_MEM;
config.src_addr = buf_info->host_addr;
- ret = dmaengine_slave_config(chan, &config);
- if (ret) {
- dev_err(dev, "Failed to configure DMA channel\n");
- goto err_unlock;
- }
-
dst_addr = dma_map_single(dma_dev, buf_info->dev_addr, buf_info->size,
DMA_FROM_DEVICE);
ret = dma_mapping_error(dma_dev, dst_addr);
@@ -520,9 +504,10 @@ static int pci_epf_mhi_edma_read_async(struct mhi_ep_cntrl *mhi_cntrl,
goto err_unlock;
}
- desc = dmaengine_prep_slave_single(chan, dst_addr, buf_info->size,
- DMA_DEV_TO_MEM,
- DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
+ desc = dmaengine_prep_config_single(chan, dst_addr, buf_info->size,
+ DMA_DEV_TO_MEM,
+ DMA_CTRL_ACK | DMA_PREP_INTERRUPT,
+ &config);
if (!desc) {
dev_err(dev, "Failed to prepare DMA\n");
ret = -EIO;
@@ -585,12 +570,6 @@ static int pci_epf_mhi_edma_write_async(struct mhi_ep_cntrl *mhi_cntrl,
config.direction = DMA_MEM_TO_DEV;
config.dst_addr = buf_info->host_addr;
- ret = dmaengine_slave_config(chan, &config);
- if (ret) {
- dev_err(dev, "Failed to configure DMA channel\n");
- goto err_unlock;
- }
-
src_addr = dma_map_single(dma_dev, buf_info->dev_addr, buf_info->size,
DMA_TO_DEVICE);
ret = dma_mapping_error(dma_dev, src_addr);
@@ -599,9 +578,10 @@ static int pci_epf_mhi_edma_write_async(struct mhi_ep_cntrl *mhi_cntrl,
goto err_unlock;
}
- desc = dmaengine_prep_slave_single(chan, src_addr, buf_info->size,
- DMA_MEM_TO_DEV,
- DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
+ desc = dmaengine_prep_config_single(chan, src_addr, buf_info->size,
+ DMA_MEM_TO_DEV,
+ DMA_CTRL_ACK | DMA_PREP_INTERRUPT,
+ &config);
if (!desc) {
dev_err(dev, "Failed to prepare DMA\n");
ret = -EIO;
--
2.43.0
^ permalink raw reply related
* [PATCH v6 9/9] crypto: atmel: Use dmaengine_prep_config_sg() API
From: Frank.Li @ 2026-05-20 22:00 UTC (permalink / raw)
To: Vinod Koul, Manivannan Sadhasivam, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Christoph Hellwig,
Sagi Grimberg, Chaitanya Kulkarni, Herbert Xu, David S. Miller,
Nicolas Ferre, Alexandre Belloni, Claudiu Beznea, Koichiro Den,
Niklas Cassel
Cc: dmaengine, linux-kernel, linux-pci, linux-nvme, mhi,
linux-arm-msm, linux-crypto, linux-arm-kernel, imx, Frank Li
In-Reply-To: <20260520-dma_prep_config-v6-0-06e49b7acb38@nxp.com>
From: Frank Li <Frank.Li@nxp.com>
Using new API dmaengine_prep_config_sg() to simple code.
dmaengine_prep_config_sg() does not distinguish between configuration
failures and descriptor preparation failures, as both are reported through
a NULL return value. Converting both cases to -ENOMEM is therefore
acceptable and consistent with the helper's abstraction.
In practice, most users only care whether the operation succeeds or fails,
and do not depend on the exact errno value returned from this path.
Tested-by: Niklas Cassel <cassel@kernel.org>
Acked-by: Nicolas Ferre <nicolas.ferre@microchip.com>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
change in v6
- add commit message about error propagation (sashaki AI)
---
drivers/crypto/atmel-aes.c | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c
index b393689400b4c..d890b5a277b9c 100644
--- a/drivers/crypto/atmel-aes.c
+++ b/drivers/crypto/atmel-aes.c
@@ -795,7 +795,6 @@ static int atmel_aes_dma_transfer_start(struct atmel_aes_dev *dd,
struct dma_slave_config config;
dma_async_tx_callback callback;
struct atmel_aes_dma *dma;
- int err;
memset(&config, 0, sizeof(config));
config.src_addr_width = addr_width;
@@ -820,12 +819,9 @@ static int atmel_aes_dma_transfer_start(struct atmel_aes_dev *dd,
return -EINVAL;
}
- err = dmaengine_slave_config(dma->chan, &config);
- if (err)
- return err;
-
- desc = dmaengine_prep_slave_sg(dma->chan, dma->sg, dma->sg_len, dir,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ desc = dmaengine_prep_config_sg(dma->chan, dma->sg, dma->sg_len, dir,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK,
+ &config);
if (!desc)
return -ENOMEM;
--
2.43.0
^ permalink raw reply related
* [PATCH] irqchip/exynos-combiner: switch to raw_spinlock
From: Marek Szyprowski @ 2026-05-20 22:04 UTC (permalink / raw)
To: linux-arm-kernel, linux-samsung-soc, linux-rt-devel
Cc: Marek Szyprowski, Thomas Gleixner, Krzysztof Kozlowski,
Alim Akhtar, Sebastian Andrzej Siewior, Clark Williams,
Steven Rostedt
In-Reply-To: <CGME20260520220432eucas1p10502ca0f9368bd6de5ce027ad8170109@eucas1p1.samsung.com>
The exynos-combiner driver uses a regular spinlock to protect access to
the combiner interrupt status register in combiner_handle_cascade_irq(),
which is invoked in hard IRQ context as a chained interrupt handler.
When PREEMPT_RT is enabled on ARM, regular spinlock is converted to a
sleeping lock (mutex-based), which must not be used in atomic context
such as hard interrupt handlers. Switch the irq_controller_lock to
raw_spinlock, which remains a true non-sleeping spinlock even under
PREEMPT_RT.
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Fixes: a900e5d99718 ("ARM: exynos: move exynos4210-combiner to drivers/irqchip")
---
drivers/irqchip/exynos-combiner.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/irqchip/exynos-combiner.c b/drivers/irqchip/exynos-combiner.c
index 11d105457798..03cafcc5c835 100644
--- a/drivers/irqchip/exynos-combiner.c
+++ b/drivers/irqchip/exynos-combiner.c
@@ -24,7 +24,7 @@
#define IRQ_IN_COMBINER 8
-static DEFINE_SPINLOCK(irq_controller_lock);
+static DEFINE_RAW_SPINLOCK(irq_controller_lock);
struct combiner_chip_data {
unsigned int hwirq_offset;
@@ -72,9 +72,9 @@ static void combiner_handle_cascade_irq(struct irq_desc *desc)
chained_irq_enter(chip, desc);
- spin_lock(&irq_controller_lock);
+ raw_spin_lock(&irq_controller_lock);
status = readl_relaxed(chip_data->base + COMBINER_INT_STATUS);
- spin_unlock(&irq_controller_lock);
+ raw_spin_unlock(&irq_controller_lock);
status &= chip_data->irq_mask;
if (status == 0)
--
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