Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v8 14/22] RISC-V: perf: Implement supervisor counter delegation support
From: Charlie Jenkins @ 2026-07-20  7:21 UTC (permalink / raw)
  To: Atish Patra
  Cc: Jiri Olsa, Paul Walmsley, Mark Rutland, Rob Herring, Anup Patel,
	Namhyung Kim, Arnaldo Carvalho de Melo, Krzysztof Kozlowski,
	Ian Rogers, Will Deacon, James Clark, linux-arm-kernel,
	linux-riscv, linux-kernel, devicetree, linux-perf-users,
	Conor Dooley
In-Reply-To: <20260701-counter_delegation-v8-14-7909f863a645@meta.com>

# Add your code comments below. There is no need to trim or delete
# any existing content -- just insert your comments under the relevant
# lines of code. Lines starting with "> " are quoted diff context and
# lines starting with "| " are comments from other reviewers.
# The final email will be reformatted automatically to include only
# the sections that have your comments.
#
> There are few new RISC-V ISA exensions (ssccfg, sscsrind, smcntrpmf) which
> allows the hpmcounter/hpmevents to be programmed directly from S-mode. The
> implementation detects the ISA extension at runtime and uses them if
> available instead of SBI PMU extension. SBI PMU extension will still be
> used for firmware counters if the user requests it.
> 
> The current linux driver relies on event encoding defined by SBI PMU
> specification for standard perf events. However, there are no standard
> event encoding available in the ISA. In the future, we may want to
> decouple the counter delegation and SBI PMU completely. In that case,
> counter delegation supported platforms must rely on the event encoding
> defined in the perf json file or in the pmu driver.
> 
> For firmware events, it will continue to use the SBI PMU encoding as
> one can not support firmware event without SBI PMU.
> 
> Signed-off-by: Atish Patra <atishp@rivosinc.com>
>
> diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h
> index a3b24b88e401..cd22b5168689 100644
> --- a/arch/riscv/include/asm/csr.h
> +++ b/arch/riscv/include/asm/csr.h
> @@ -258,6 +258,7 @@
>  #endif
>  
>  #define SISELECT_SSCCFG_BASE		0x40
> +#define HPMEVENT_MASK			GENMASK_ULL(63, 56)
>  
>  /* mseccfg bits */
>  #define MSECCFG_PMM			ENVCFG_PMM
> diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
> index 2568c6808f5d..7995da4a98a1 100644
> --- a/drivers/perf/riscv_pmu_sbi.c
> +++ b/drivers/perf/riscv_pmu_sbi.c
> @@ -28,6 +28,8 @@
>  #include <asm/cpufeature.h>
>  #include <asm/vendor_extensions.h>
>  #include <asm/vendor_extensions/andes.h>
> +#include <asm/hwcap.h>
> +#include <asm/csr_ind.h>
>  
>  #define ALT_SBI_PMU_OVERFLOW(__ovl)					\
>  asm volatile(ALTERNATIVE_2(						\
> @@ -60,7 +62,20 @@ asm volatile(ALTERNATIVE(						\
>  #define PERF_EVENT_FLAG_USER_ACCESS	BIT(SYSCTL_USER_ACCESS)
>  #define PERF_EVENT_FLAG_LEGACY		BIT(SYSCTL_LEGACY)
>  
> -PMU_FORMAT_ATTR(event, "config:0-55");
> +#define RVPMU_SBI_PMU_FORMAT_ATTR	"config:0-47"
> +#define RVPMU_CDELEG_PMU_FORMAT_ATTR	"config:0-55"
> +
> +static ssize_t __maybe_unused rvpmu_format_show(struct device *dev, struct device_attribute *attr,
> +						char *buf);
> +
> +#define RVPMU_ATTR_ENTRY(_name, _func, _config)	(			\
> +	&((struct dev_ext_attribute[]) {				\
> +		{ __ATTR(_name, 0444, _func, NULL), (void *)_config }	\
> +	})[0].attr.attr)
> +
> +#define RVPMU_FORMAT_ATTR_ENTRY(_name, _config) \
> +	RVPMU_ATTR_ENTRY(_name, rvpmu_format_show, (char *)_config)
> +
>  PMU_FORMAT_ATTR(firmware, "config:62-63");
>  
>  static bool sbi_v2_available;
> @@ -68,7 +83,11 @@ static bool sbi_v3_available;
>  static DEFINE_STATIC_KEY_FALSE(sbi_pmu_snapshot_available);
>  #define sbi_pmu_snapshot_available() \
>  	static_branch_unlikely(&sbi_pmu_snapshot_available)
> +
>  static DEFINE_STATIC_KEY_FALSE(riscv_pmu_sbi_available);
> +#define riscv_pmu_sbi_available() \
> +		static_branch_likely(&riscv_pmu_sbi_available)
> +
>  static DEFINE_STATIC_KEY_FALSE(riscv_pmu_cdeleg_available);
>  
>  /* Avoid unnecessary code patching in the one time booting path*/
> @@ -83,19 +102,35 @@ static DEFINE_STATIC_KEY_FALSE(riscv_pmu_cdeleg_available);
>  #define riscv_pmu_sbi_available() \
>  		static_branch_likely(&riscv_pmu_sbi_available)
>  
> -static struct attribute *riscv_arch_formats_attr[] = {
> -	&format_attr_event.attr,
> +static struct attribute *riscv_sbi_pmu_formats_attr[] = {
> +	RVPMU_FORMAT_ATTR_ENTRY(event, RVPMU_SBI_PMU_FORMAT_ATTR),
>  	&format_attr_firmware.attr,
>  	NULL,
>  };
>  
> -static struct attribute_group riscv_pmu_format_group = {
> +static struct attribute_group riscv_sbi_pmu_format_group = {
>  	.name = "format",
> -	.attrs = riscv_arch_formats_attr,
> +	.attrs = riscv_sbi_pmu_formats_attr,
>  };
>  
> -static const struct attribute_group *riscv_pmu_attr_groups[] = {
> -	&riscv_pmu_format_group,
> +static const struct attribute_group *riscv_sbi_pmu_attr_groups[] = {
> +	&riscv_sbi_pmu_format_group,
> +	NULL,
> +};
> +
> +static struct attribute *riscv_cdeleg_pmu_formats_attr[] = {
> +	RVPMU_FORMAT_ATTR_ENTRY(event, RVPMU_CDELEG_PMU_FORMAT_ATTR),
> +	&format_attr_firmware.attr,
> +	NULL,
> +};
> +
> +static struct attribute_group riscv_cdeleg_pmu_format_group = {
> +	.name = "format",
> +	.attrs = riscv_cdeleg_pmu_formats_attr,
> +};
> +
> +static const struct attribute_group *riscv_cdeleg_pmu_attr_groups[] = {
> +	&riscv_cdeleg_pmu_format_group,
>  	NULL,
>  };
>  
> @@ -482,6 +517,14 @@ static void rvpmu_sbi_check_std_events(struct work_struct *work)
>  
>  static DECLARE_WORK(check_std_events_work, rvpmu_sbi_check_std_events);
>  
> +static ssize_t rvpmu_format_show(struct device *dev,
> +				 struct device_attribute *attr, char *buf)
> +{
> +	struct dev_ext_attribute *eattr = container_of(attr,
> +				struct dev_ext_attribute, attr);
> +	return sysfs_emit(buf, "%s\n", (char *)eattr->var);
> +}
> +
>  static int rvpmu_ctr_get_width(int idx)
>  {
>  	return pmu_ctr_list[idx].width;
> @@ -599,6 +642,38 @@ static uint8_t rvpmu_csr_index(struct perf_event *event)
>  	return pmu_ctr_list[event->hw.idx].csr - CSR_CYCLE;
>  }
>  
> +static uint64_t get_deleg_priv_filter_bits(struct perf_event *event)
> +{
> +	u64 priv_filter_bits = 0;
> +	bool guest_events = false;
> +
> +	if (event->attr.config1 & RISCV_PMU_CONFIG1_GUEST_EVENTS)
> +		guest_events = true;
> +	if (event->attr.exclude_kernel)
> +		priv_filter_bits |= guest_events ? HPMEVENT_VSINH : HPMEVENT_SINH;
> +	if (event->attr.exclude_user)
> +		priv_filter_bits |= guest_events ? HPMEVENT_VUINH : HPMEVENT_UINH;
> +	if (guest_events && event->attr.exclude_hv)
> +		priv_filter_bits |= HPMEVENT_SINH;
> +	if (event->attr.exclude_host)
> +		priv_filter_bits |= HPMEVENT_UINH | HPMEVENT_SINH;
> +	if (event->attr.exclude_guest)
> +		priv_filter_bits |= HPMEVENT_VSINH | HPMEVENT_VUINH;
> +
> +	return priv_filter_bits;
> +}
> +
> +static bool pmu_sbi_is_fw_event(struct perf_event *event)
> +{
> +	u32 type = event->attr.type;
> +	u64 config = event->attr.config;
> +
> +	if (type == PERF_TYPE_RAW && ((config >> 63) == 1))
> +		return true;
> +	else
> +		return false;
> +}
> +
>  static unsigned long rvpmu_sbi_get_filter_flags(struct perf_event *event)
>  {
>  	unsigned long cflags = 0;
> @@ -627,7 +702,8 @@ static int rvpmu_sbi_ctr_get_idx(struct perf_event *event)
>  	struct cpu_hw_events *cpuc = this_cpu_ptr(rvpmu->hw_events);
>  	struct sbiret ret;
>  	int idx;
> -	uint64_t cbase = 0, cmask = rvpmu->cmask;
> +	u64 cbase = 0;
> +	unsigned long ctr_mask = rvpmu->cmask;
>  	unsigned long cflags = 0;
>  
>  	cflags = rvpmu_sbi_get_filter_flags(event);
> @@ -640,21 +716,23 @@ static int rvpmu_sbi_ctr_get_idx(struct perf_event *event)
>  	if ((hwc->flags & PERF_EVENT_FLAG_LEGACY) && (event->attr.type == PERF_TYPE_HARDWARE)) {
>  		if (event->attr.config == PERF_COUNT_HW_CPU_CYCLES) {
>  			cflags |= SBI_PMU_CFG_FLAG_SKIP_MATCH;
> -			cmask = 1;
> +			ctr_mask = 1;
>  		} else if (event->attr.config == PERF_COUNT_HW_INSTRUCTIONS) {
>  			cflags |= SBI_PMU_CFG_FLAG_SKIP_MATCH;
> -			cmask = BIT(CSR_INSTRET - CSR_CYCLE);
> +			ctr_mask = BIT(CSR_INSTRET - CSR_CYCLE);
>  		}
> +	} else if (pmu_sbi_is_fw_event(event)) {
> +		ctr_mask = firmware_cmask;
>  	}
>  
>  	/* retrieve the available counter index */
>  #if defined(CONFIG_32BIT)
>  	ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_CFG_MATCH, cbase,
> -			cmask, cflags, hwc->event_base, hwc->config,
> +			ctr_mask, cflags, hwc->event_base, hwc->config,
>  			hwc->config >> 32);
>  #else
>  	ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_CFG_MATCH, cbase,
> -			cmask, cflags, hwc->event_base, hwc->config, 0);
> +			ctr_mask, cflags, hwc->event_base, hwc->config, 0);
>  #endif
>  	if (ret.error) {
>  		pr_debug("Not able to find a counter for event %lx config %llx\n",
> @@ -663,7 +741,7 @@ static int rvpmu_sbi_ctr_get_idx(struct perf_event *event)
>  	}
>  
>  	idx = ret.value;
> -	if (!test_bit(idx, &rvpmu->cmask) || !pmu_ctr_list[idx].value)
> +	if (!test_bit(idx, &ctr_mask) || !pmu_ctr_list[idx].value)
>  		return -ENOENT;
>  
>  	/* Additional sanity check for the counter id */
> @@ -713,29 +791,98 @@ static int sbi_pmu_event_find_cache(u64 config)
>  	return ret;
>  }
>  
> -static bool pmu_sbi_is_fw_event(struct perf_event *event)
> +static int rvpmu_sbi_event_map(struct perf_event *event, u64 *econfig)
>  {
>  	u32 type = event->attr.type;
>  	u64 config = event->attr.config;
>  
> -	if ((type == PERF_TYPE_RAW) && ((config >> 63) == 1))
> -		return true;
> -	else
> -		return false;
> +	/*
> +	 * Ensure we are finished checking standard hardware events for
> +	 * validity before allowing userspace to configure any events.
> +	 */
> +	flush_work(&check_std_events_work);
> +
> +	return riscv_pmu_get_event_info(type, config, econfig);
>  }
>  
> -static int rvpmu_sbi_event_map(struct perf_event *event, u64 *econfig)
> +static int cdeleg_pmu_event_find_cache(u64 config, u64 *eventid, uint32_t *counter_mask)
> +{
> +	unsigned int cache_type, cache_op, cache_result;
> +
> +	if (!current_pmu_cache_event_map)
> +		return -ENOENT;
> +
> +	cache_type = (config >>  0) & 0xff;
> +	if (cache_type >= PERF_COUNT_HW_CACHE_MAX)
> +		return -EINVAL;
> +
> +	cache_op = (config >>  8) & 0xff;
> +	if (cache_op >= PERF_COUNT_HW_CACHE_OP_MAX)
> +		return -EINVAL;
> +
> +	cache_result = (config >> 16) & 0xff;
> +	if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
> +		return -EINVAL;
> +
> +	if (eventid)
> +		*eventid = current_pmu_cache_event_map[cache_type][cache_op]
> +						      [cache_result].event_id;
> +	if (counter_mask)
> +		*counter_mask = current_pmu_cache_event_map[cache_type][cache_op]
> +							   [cache_result].counter_mask;
> +
> +	return 0;
> +}
> +
> +static int rvpmu_cdeleg_event_map(struct perf_event *event, u64 *econfig)
>  {
>  	u32 type = event->attr.type;
>  	u64 config = event->attr.config;
> +	int ret = 0;
>  
>  	/*
> -	 * Ensure we are finished checking standard hardware events for
> -	 * validity before allowing userspace to configure any events.
> +	 * There are two ways standard perf events can be mapped to platform specific
> +	 * encoding.
> +	 * 1. The vendor may specify the encodings in the driver.
> +	 * 2. The Perf tool for RISC-V may remap the standard perf event to platform
> +	 * specific encoding.
> +	 *
> +	 * As RISC-V ISA doesn't define any standard event encoding. Thus, perf tool allows
> +	 * vendor to define it via json file. The encoding defined in the json will override
> +	 * the perf legacy encoding. However, some user may want to run performance
> +	 * monitoring without perf tool as well. That's why, vendors may specify the event
> +	 * encoding in the driver as well if they want to support that use case too.
> +	 * If an encoding is defined in the json, it will be encoded as a raw event.
>  	 */
> -	flush_work(&check_std_events_work);
>  
> -	return riscv_pmu_get_event_info(type, config, econfig);
> +	switch (type) {
> +	case PERF_TYPE_HARDWARE:
> +		if (config >= PERF_COUNT_HW_MAX)
> +			return -EINVAL;
> +		if (!current_pmu_hw_event_map)
> +			return -ENOENT;
> +
> +		*econfig = current_pmu_hw_event_map[config].event_id;
> +		if (*econfig == HW_OP_UNSUPPORTED)
> +			ret = -ENOENT;
> +		break;
> +	case PERF_TYPE_HW_CACHE:
> +		ret = cdeleg_pmu_event_find_cache(config, econfig, NULL);
> +		if (ret)
> +			break;
> +		if (*econfig == CACHE_OP_UNSUPPORTED)
> +			ret = -ENOENT;
> +		break;
> +	case PERF_TYPE_RAW:
> +		*econfig = config & RISCV_PMU_DELEG_RAW_EVENT_MASK;
> +		break;
> +	default:
> +		ret = -ENOENT;
> +		break;
> +	}
> +
> +	/* event_base is not used for counter delegation */
> +	return ret;
>  }
>  
>  static void pmu_sbi_snapshot_free(struct riscv_pmu *pmu)
> @@ -821,7 +968,7 @@ static int pmu_sbi_snapshot_setup(struct riscv_pmu *pmu, int cpu)
>  	return 0;
>  }
>  
> -static u64 rvpmu_sbi_ctr_read(struct perf_event *event)
> +static u64 rvpmu_ctr_read(struct perf_event *event)
>  {
>  	struct hw_perf_event *hwc = &event->hw;
>  	int idx = hwc->idx;
> @@ -898,10 +1045,6 @@ static void rvpmu_sbi_ctr_start(struct perf_event *event, u64 ival)
>  	if (ret.error && (ret.error != SBI_ERR_ALREADY_STARTED))
>  		pr_err("Starting counter idx %d failed with error %d\n",
>  			hwc->idx, sbi_err_map_linux_errno(ret.error));
> -
> -	if ((hwc->flags & PERF_EVENT_FLAG_USER_ACCESS) &&
> -	    (hwc->flags & PERF_EVENT_FLAG_USER_READ_CNT))
> -		rvpmu_set_scounteren((void *)event);
>  }
>  
>  static void rvpmu_sbi_ctr_stop(struct perf_event *event, unsigned long flag)
> @@ -912,10 +1055,6 @@ static void rvpmu_sbi_ctr_stop(struct perf_event *event, unsigned long flag)
>  	struct cpu_hw_events *cpu_hw_evt = this_cpu_ptr(pmu->hw_events);
>  	struct riscv_pmu_snapshot_data *sdata = cpu_hw_evt->snapshot_addr;
>  
> -	if ((hwc->flags & PERF_EVENT_FLAG_USER_ACCESS) &&
> -	    (hwc->flags & PERF_EVENT_FLAG_USER_READ_CNT))
> -		rvpmu_reset_scounteren((void *)event);
> -
>  	if (sbi_pmu_snapshot_available())
>  		flag |= SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT;
>  
> @@ -951,12 +1090,6 @@ static int rvpmu_sbi_find_num_ctrs(void)
>  		return sbi_err_map_linux_errno(ret.error);
>  }
>  
> -static u32 rvpmu_deleg_find_ctrs(void)
> -{
> -	/* TODO */
> -	return 0;
> -}
> -
>  static int rvpmu_sbi_get_ctrinfo(u32 nsbi_ctr, u32 *num_fw_ctr, u32 *num_hw_ctr)
>  {
>  	struct sbiret ret;
> @@ -1034,55 +1167,75 @@ static inline void rvpmu_sbi_stop_hw_ctrs(struct riscv_pmu *pmu)
>  	}
>  }
>  
> -/*
> - * This function starts all the used counters in two step approach.
> - * Any counter that did not overflow can be start in a single step
> - * while the overflowed counters need to be started with updated initialization
> - * value.
> - */
> -static inline void rvpmu_sbi_start_ovf_ctrs_sbi(struct cpu_hw_events *cpu_hw_evt,
> -						u64 ctr_ovf_mask)
> +static void rvpmu_deleg_ctr_start_mask(unsigned long mask)
>  {
> -	int idx = 0, i;
> -	struct perf_event *event;
> -	unsigned long flag = SBI_PMU_START_FLAG_SET_INIT_VALUE;
> -	unsigned long ctr_start_mask = 0;
> -	uint64_t max_period;
> -	struct hw_perf_event *hwc;
> -	u64 init_val = 0;
> +	unsigned long scountinhibit_val = 0;
>  
> -	for (i = 0; i < BITS_TO_LONGS(RISCV_MAX_COUNTERS); i++) {
> -		ctr_start_mask = cpu_hw_evt->used_hw_ctrs[i] & ~ctr_ovf_mask;
> -		/* Start all the counters that did not overflow in a single shot */
> -		if (ctr_start_mask) {
> -			sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_START, i * BITS_PER_LONG,
> -				  ctr_start_mask, 0, 0, 0, 0);
> -		}
> -	}
> +	scountinhibit_val = csr_read(CSR_SCOUNTINHIBIT);
> +	scountinhibit_val &= ~mask;
> +
> +	csr_write(CSR_SCOUNTINHIBIT, scountinhibit_val);
> +}
> +
> +static void rvpmu_deleg_ctr_enable_irq(struct perf_event *event)
> +{
> +	unsigned long hpmevent_curr;
> +	unsigned long of_mask;
> +	struct hw_perf_event *hwc = &event->hw;
> +	int counter_idx = hwc->idx;
> +	unsigned long sip_val = csr_read(CSR_SIP);
> +
> +	if (!is_sampling_event(event) || (sip_val & SIP_LCOFIP))
> +		return;
>  
> -	/* Reinitialize and start all the counter that overflowed */
> -	while (ctr_ovf_mask) {
> -		if (ctr_ovf_mask & 0x01) {
> -			event = cpu_hw_evt->events[idx];
> -			hwc = &event->hw;
> -			max_period = riscv_pmu_ctr_get_width_mask(event);
> -			init_val = local64_read(&hwc->prev_count) & max_period;
>  #if defined(CONFIG_32BIT)
> -			sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_START, idx, 1,
> -				  flag, init_val, init_val >> 32, 0);
> +	hpmevent_curr = csr_ind_read(CSR_SIREG5, SISELECT_SSCCFG_BASE, counter_idx);
> +	of_mask = (u32)~HPMEVENTH_OF;
>  #else
> -			sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_START, idx, 1,
> -				  flag, init_val, 0, 0);
> +	hpmevent_curr = csr_ind_read(CSR_SIREG2, SISELECT_SSCCFG_BASE, counter_idx);
> +	of_mask = ~HPMEVENT_OF;
>  #endif
> -			perf_event_update_userpage(event);
> -		}
> -		ctr_ovf_mask = ctr_ovf_mask >> 1;
> -		idx++;
> -	}
> +
> +	hpmevent_curr &= of_mask;
> +#if defined(CONFIG_32BIT)
> +	csr_ind_write(CSR_SIREG5, SISELECT_SSCCFG_BASE, counter_idx, hpmevent_curr);
> +#else
> +	csr_ind_write(CSR_SIREG2, SISELECT_SSCCFG_BASE, counter_idx, hpmevent_curr);
> +#endif
> +}
> +
> +static void rvpmu_deleg_ctr_start(struct perf_event *event, u64 ival)
> +{
> +	unsigned long scountinhibit_val = 0;
> +	struct hw_perf_event *hwc = &event->hw;
> +
> +#if defined(CONFIG_32BIT)
> +	csr_ind_write(CSR_SIREG, SISELECT_SSCCFG_BASE, hwc->idx, ival & 0xFFFFFFFF);
> +	csr_ind_write(CSR_SIREG4, SISELECT_SSCCFG_BASE, hwc->idx, ival >> BITS_PER_LONG);
> +#else
> +	csr_ind_write(CSR_SIREG, SISELECT_SSCCFG_BASE, hwc->idx, ival);
> +#endif
> +
> +	rvpmu_deleg_ctr_enable_irq(event);
> +
> +	scountinhibit_val = csr_read(CSR_SCOUNTINHIBIT);
> +	scountinhibit_val &= ~BIT(hwc->idx);
> +
> +	csr_write(CSR_SCOUNTINHIBIT, scountinhibit_val);
> +}
> +
> +static void rvpmu_deleg_ctr_stop_mask(unsigned long mask)
> +{
> +	unsigned long scountinhibit_val = 0;
> +
> +	scountinhibit_val = csr_read(CSR_SCOUNTINHIBIT);
> +	scountinhibit_val |= mask;
> +
> +	csr_write(CSR_SCOUNTINHIBIT, scountinhibit_val);
>  }
>  
> -static inline void rvpmu_sbi_start_ovf_ctrs_snapshot(struct cpu_hw_events *cpu_hw_evt,
> -						     u64 ctr_ovf_mask)
> +static void rvpmu_sbi_start_ovf_ctrs_snapshot(struct cpu_hw_events *cpu_hw_evt,
> +					      u64 ctr_ovf_mask)
>  {
>  	int i, idx = 0;
>  	struct perf_event *event;
> @@ -1116,15 +1269,53 @@ static inline void rvpmu_sbi_start_ovf_ctrs_snapshot(struct cpu_hw_events *cpu_h
>  	}
>  }
>  
> -static void rvpmu_sbi_start_overflow_mask(struct riscv_pmu *pmu,
> -					  u64 ctr_ovf_mask)
> +/*
> + * This function starts all the used counters in two step approach.
> + * Any counter that did not overflow can be start in a single step
> + * while the overflowed counters need to be started with updated initialization
> + * value.
> + */
> +static void rvpmu_start_overflow_mask(struct riscv_pmu *pmu, u64 ctr_ovf_mask)
>  {
> +	int idx = 0, i;
> +	struct perf_event *event;
> +	unsigned long ctr_start_mask = 0;
> +	u64 max_period, init_val = 0;
> +	struct hw_perf_event *hwc;
>  	struct cpu_hw_events *cpu_hw_evt = this_cpu_ptr(pmu->hw_events);
>  
>  	if (sbi_pmu_snapshot_available())
> -		rvpmu_sbi_start_ovf_ctrs_snapshot(cpu_hw_evt, ctr_ovf_mask);
> -	else
> -		rvpmu_sbi_start_ovf_ctrs_sbi(cpu_hw_evt, ctr_ovf_mask);
> +		return rvpmu_sbi_start_ovf_ctrs_snapshot(cpu_hw_evt, ctr_ovf_mask);
> +
> +	/* Start all the counters that did not overflow */
> +	if (riscv_pmu_cdeleg_available()) {
> +		ctr_start_mask = cpu_hw_evt->used_hw_ctrs[0] & ~ctr_ovf_mask;
> +		rvpmu_deleg_ctr_start_mask(ctr_start_mask);
> +	} else {
> +		for (i = 0; i < BITS_TO_LONGS(RISCV_MAX_COUNTERS); i++) {
> +			ctr_start_mask = cpu_hw_evt->used_hw_ctrs[i] & ~ctr_ovf_mask;
> +			/* Start all the counters that did not overflow in a single shot */
> +			sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_START, i * BITS_PER_LONG,
> +				  ctr_start_mask, 0, 0, 0, 0);
> +		}
> +	}
> +
> +	/* Reinitialize and start all the counter that overflowed */
> +	while (ctr_ovf_mask) {
> +		if (ctr_ovf_mask & 0x01) {
> +			event = cpu_hw_evt->events[idx];
> +			hwc = &event->hw;
> +			max_period = riscv_pmu_ctr_get_width_mask(event);
> +			init_val = local64_read(&hwc->prev_count) & max_period;
> +			if (riscv_pmu_cdeleg_available())
> +				rvpmu_deleg_ctr_start(event, init_val);
> +			else
> +				rvpmu_sbi_ctr_start(event, init_val);
> +			perf_event_update_userpage(event);
> +		}
> +		ctr_ovf_mask = ctr_ovf_mask >> 1;
> +		idx++;
> +	}
>  }
>  
>  static irqreturn_t rvpmu_ovf_handler(int irq, void *dev)
> @@ -1159,10 +1350,18 @@ static irqreturn_t rvpmu_ovf_handler(int irq, void *dev)
>  	}
>  
>  	pmu = to_riscv_pmu(event->pmu);
> -	rvpmu_sbi_stop_hw_ctrs(pmu);
> +	if (riscv_pmu_cdeleg_available())
> +		rvpmu_deleg_ctr_stop_mask(cpu_hw_evt->used_hw_ctrs[0]);
> +	else
> +		rvpmu_sbi_stop_hw_ctrs(pmu);
>  
> -	/* Overflow status register should only be read after counter are stopped */
> -	if (sbi_pmu_snapshot_available())
> +	/*
> +	 * Overflow status register should only be read after counter are stopped.
> +	 * In counter delegation mode the overflows are reported in scountovf, not
> +	 * in the SBI snapshot area, so read the CSR directly even when an SBI PMU
> +	 * snapshot is also available.
> +	 */
> +	if (sbi_pmu_snapshot_available() && !riscv_pmu_cdeleg_available())
>  		overflow = sdata->ctr_overflow_mask;
>  	else
>  		ALT_SBI_PMU_OVERFLOW(overflow);
> @@ -1228,22 +1427,183 @@ static irqreturn_t rvpmu_ovf_handler(int irq, void *dev)
>  		hw_evt->state = 0;
>  	}
>  
> -	rvpmu_sbi_start_overflow_mask(pmu, overflowed_ctrs);
> +	rvpmu_start_overflow_mask(pmu, overflowed_ctrs);
>  	perf_sample_event_took(sched_clock() - start_clock);
>  
>  	return IRQ_HANDLED;
>  }
>  
> +static int get_deleg_hw_ctr_width(int counter_offset)
> +{
> +	unsigned long hpm_warl;
> +	int num_bits;
> +
> +	if (counter_offset < 3 || counter_offset > 31)
> +		return 0;
> +
> +	hpm_warl = csr_ind_warl(CSR_SIREG, SISELECT_SSCCFG_BASE, counter_offset, -1);
> +	if (!hpm_warl)
> +		return 0;
> +	num_bits = __fls(hpm_warl);
> +
> +#if defined(CONFIG_32BIT)
> +	/*
> +	 * The low half contributes a full BITS_PER_LONG bits when the counter is
> +	 * wider than 32 bits; the high half's __fls() gives the remaining width.
> +	 */
> +	hpm_warl = csr_ind_warl(CSR_SIREG4, SISELECT_SSCCFG_BASE, counter_offset, -1);
> +	if (hpm_warl)
> +		num_bits = BITS_PER_LONG + __fls(hpm_warl);
> +#endif
> +	return num_bits;
> +}
> +
> +static int rvpmu_deleg_find_ctrs(void)
> +{
> +	int i, num_hw_ctr = 0;
> +	union sbi_pmu_ctr_info cinfo;
> +	unsigned long scountinhibit_old = 0;
> +
> +	/* Do a WARL write/read to detect which hpmcounters have been delegated */
> +	scountinhibit_old = csr_read(CSR_SCOUNTINHIBIT);
> +	csr_write(CSR_SCOUNTINHIBIT, -1);
> +	cmask = csr_read(CSR_SCOUNTINHIBIT);
> +
> +	csr_write(CSR_SCOUNTINHIBIT, scountinhibit_old);
> +
> +	for_each_set_bit(i, &cmask, RISCV_MAX_HW_COUNTERS) {
> +		if (unlikely(i == 1))
> +			continue; /* This should never happen as TM is read only */
> +		cinfo.value = 0;
> +		cinfo.type = SBI_PMU_CTR_TYPE_HW;
> +		/*
> +		 * If counter delegation is enabled, the csr stored to the cinfo will
> +		 * be a virtual counter that the delegation attempts to read.
> +		 */
> +		cinfo.csr = CSR_CYCLE + i;
> +		if (i == 0 || i == 2)
> +			cinfo.width = 63;
> +		else
> +			cinfo.width = get_deleg_hw_ctr_width(i);
> +
> +		num_hw_ctr++;
> +		pmu_ctr_list[i].value = cinfo.value;
> +	}
> +
> +	return num_hw_ctr;
> +}
> +
> +static int get_deleg_fixed_hw_idx(struct cpu_hw_events *cpuc, struct perf_event *event)
> +{
> +	return -EINVAL;
> +}
> +
> +static int get_deleg_next_hpm_hw_idx(struct cpu_hw_events *cpuc, struct perf_event *event)
> +{
> +	unsigned long hw_ctr_mask = 0;
> +
> +	/*
> +	 * TODO: Treat every hpmcounter can monitor every event for now.
> +	 * The event to counter mapping should come from the json file.
> +	 * The mapping should also tell if sampling is supported or not.
> +	 */
> +
> +	/* Select only hpmcounters */
> +	hw_ctr_mask = cmask & (~0x7);
> +	hw_ctr_mask &= ~(cpuc->used_hw_ctrs[0]);
> +	return __ffs(hw_ctr_mask);
> +}
> +
> +static void update_deleg_hpmevent(int counter_idx, uint64_t event_value, uint64_t filter_bits)
> +{
> +	u64 hpmevent_value = 0;
> +
> +	/* OF bit should be enable during the start if sampling is requested */
> +	hpmevent_value = (event_value & ~HPMEVENT_MASK) | filter_bits | HPMEVENT_OF;
> +#if defined(CONFIG_32BIT)
> +	csr_ind_write(CSR_SIREG2, SISELECT_SSCCFG_BASE, counter_idx, hpmevent_value & 0xFFFFFFFF);
> +	if (riscv_isa_extension_available(NULL, SSCOFPMF))
> +		csr_ind_write(CSR_SIREG5, SISELECT_SSCCFG_BASE, counter_idx,
> +			      hpmevent_value >> BITS_PER_LONG);
> +#else
> +	csr_ind_write(CSR_SIREG2, SISELECT_SSCCFG_BASE, counter_idx, hpmevent_value);
> +#endif
> +}
> +
> +static int rvpmu_deleg_ctr_get_idx(struct perf_event *event)
> +{
> +	struct hw_perf_event *hwc = &event->hw;
> +	struct riscv_pmu *rvpmu = to_riscv_pmu(event->pmu);
> +	struct cpu_hw_events *cpuc = this_cpu_ptr(rvpmu->hw_events);
> +	unsigned long hw_ctr_max_id;
> +	u64 priv_filter;
> +	int idx;
> +
> +	/*
> +	 * TODO: We should not rely on SBI Perf encoding to check if the event
> +	 * is a fixed one or not.
> +	 */
> +	if (!is_sampling_event(event)) {
> +		idx = get_deleg_fixed_hw_idx(cpuc, event);
> +		if (idx == 0 || idx == 2) {
> +			/* Priv mode filter bits are only available if smcntrpmf is present */
> +			if (riscv_isa_extension_available(NULL, SMCNTRPMF))
> +				goto found_idx;
> +			else
> +				goto skip_update;
> +		}
> +	}
> +
> +	if (!cmask)
> +		goto out_err;
> +	hw_ctr_max_id = __fls(cmask);
> +	idx = get_deleg_next_hpm_hw_idx(cpuc, event);
> +	if (idx < 3 || idx > hw_ctr_max_id)
> +		goto out_err;
> +found_idx:
> +	priv_filter = get_deleg_priv_filter_bits(event);
> +	update_deleg_hpmevent(idx, hwc->config, priv_filter);
> +skip_update:
> +	if (!test_and_set_bit(idx, cpuc->used_hw_ctrs))
> +		return idx;
> +out_err:
> +	return -ENOENT;
> +}
> +
>  static void rvpmu_ctr_start(struct perf_event *event, u64 ival)
>  {
> -	rvpmu_sbi_ctr_start(event, ival);
> -	/* TODO: Counter delegation implementation */
> +	struct hw_perf_event *hwc = &event->hw;
> +
> +	if (riscv_pmu_cdeleg_available() && !pmu_sbi_is_fw_event(event))
> +		rvpmu_deleg_ctr_start(event, ival);
> +	else
> +		rvpmu_sbi_ctr_start(event, ival);
> +
> +	if ((hwc->flags & PERF_EVENT_FLAG_USER_ACCESS) &&
> +	    (hwc->flags & PERF_EVENT_FLAG_USER_READ_CNT))
> +		rvpmu_set_scounteren((void *)event);
>  }
>  
>  static void rvpmu_ctr_stop(struct perf_event *event, unsigned long flag)
>  {
> -	rvpmu_sbi_ctr_stop(event, flag);
> -	/* TODO: Counter delegation implementation */
> +	struct hw_perf_event *hwc = &event->hw;
> +
> +	if ((hwc->flags & PERF_EVENT_FLAG_USER_ACCESS) &&
> +	    (hwc->flags & PERF_EVENT_FLAG_USER_READ_CNT))
> +		rvpmu_reset_scounteren((void *)event);
> +
> +	if (riscv_pmu_cdeleg_available() && !pmu_sbi_is_fw_event(event)) {
> +		/*
> +		 * The counter is already stopped. No need to stop again. Counter
> +		 * mapping will be reset in clear_idx function.
> +		 */
> +		if (flag != RISCV_PMU_STOP_FLAG_RESET)
> +			rvpmu_deleg_ctr_stop_mask(BIT(hwc->idx));
> +		else
> +			update_deleg_hpmevent(hwc->idx, 0, 0);
> +	} else {
> +		rvpmu_sbi_ctr_stop(event, flag);
> +	}
>  }
>  
>  static int rvpmu_find_ctrs(void)
> @@ -1292,20 +1652,18 @@ static int rvpmu_find_ctrs(void)
>  
>  static int rvpmu_event_map(struct perf_event *event, u64 *econfig)
>  {
> -	return rvpmu_sbi_event_map(event, econfig);
> -	/* TODO: Counter delegation implementation */
> +	if (riscv_pmu_cdeleg_available() && !pmu_sbi_is_fw_event(event))
> +		return rvpmu_cdeleg_event_map(event, econfig);
> +	else
> +		return rvpmu_sbi_event_map(event, econfig);
>  }
>  
>  static int rvpmu_ctr_get_idx(struct perf_event *event)
>  {
> -	return rvpmu_sbi_ctr_get_idx(event);
> -	/* TODO: Counter delegation implementation */
> -}
> -
> -static u64 rvpmu_ctr_read(struct perf_event *event)
> -{
> -	return rvpmu_sbi_ctr_read(event);
> -	/* TODO: Counter delegation implementation */
> +	if (riscv_pmu_cdeleg_available() && !pmu_sbi_is_fw_event(event))
> +		return rvpmu_deleg_ctr_get_idx(event);
> +	else
> +		return rvpmu_sbi_ctr_get_idx(event);
>  }
>  
>  static int rvpmu_starting_cpu(unsigned int cpu, struct hlist_node *node)
> @@ -1323,7 +1681,16 @@ static int rvpmu_starting_cpu(unsigned int cpu, struct hlist_node *node)
>  		csr_write(CSR_SCOUNTEREN, 0x2);
>  
>  	/* Stop all the counters so that they can be enabled from perf */
> -	rvpmu_sbi_stop_all(pmu);
> +	if (riscv_pmu_cdeleg_available()) {
> +		rvpmu_deleg_ctr_stop_mask(cmask);
> +		if (riscv_pmu_sbi_available()) {
> +			/* Stop the firmware counters as well */
> +			sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_STOP, 0, firmware_cmask,
> +				  0, 0, 0, 0);
> +		}
> +	} else {
> +		rvpmu_sbi_stop_all(pmu);
> +	}
>  
>  	if (riscv_pmu_use_irq) {
>  		cpu_hw_evt->irq = riscv_pmu_irq;
> @@ -1632,8 +1999,11 @@ static int rvpmu_device_probe(struct platform_device *pdev)
>  	}
>  	irq_requested = (ret == 0);
>  
> -	pmu->pmu.attr_groups = riscv_pmu_attr_groups;
>  	pmu->pmu.parent = &pdev->dev;
> +	if (riscv_pmu_cdeleg_available_boot())
> +		pmu->pmu.attr_groups = riscv_cdeleg_pmu_attr_groups;
> +	else
> +		pmu->pmu.attr_groups = riscv_sbi_pmu_attr_groups;
>  	pmu->cmask = cmask;
>  	pmu->ctr_start = rvpmu_ctr_start;
>  	pmu->ctr_stop = rvpmu_ctr_stop;
> diff --git a/include/linux/perf/riscv_pmu.h b/include/linux/perf/riscv_pmu.h
> index f82a28040594..3c64151cb038 100644
> --- a/include/linux/perf/riscv_pmu.h
> +++ b/include/linux/perf/riscv_pmu.h
> @@ -20,6 +20,7 @@
>   */
>  
>  #define RISCV_MAX_COUNTERS	64
> +#define RISCV_MAX_HW_COUNTERS	32
>  #define RISCV_OP_UNSUPP		(-EOPNOTSUPP)
>  #define RISCV_PMU_SBI_PDEV_NAME	"riscv-pmu-sbi"
>  #define RISCV_PMU_LEGACY_PDEV_NAME	"riscv-pmu-legacy"
> @@ -28,6 +29,8 @@
>  
>  #define RISCV_PMU_CONFIG1_GUEST_EVENTS 0x1
>  
> +#define RISCV_PMU_DELEG_RAW_EVENT_MASK GENMASK_ULL(55, 0)
> +
>  struct cpu_hw_events {
>  	/* currently enabled events */
>  	int			n_events;

Reviewed-by: Charlie Jenkins <thecharlesjenkins@gmail.com>
Tested-by: Charlie Jenkins <thecharlesjenkins@gmail.com>

-- 
- Charlie



^ permalink raw reply

* [RFC PATCH] arm_mpam: remove sanity check of accessibility when error interrupt is SPI on SMT platforms
From: Yadong Qi @ 2026-07-20  7:24 UTC (permalink / raw)
  To: james.morse, ben.horgan, reinette.chatre, fenghuay, linux-kernel,
	lpieralisi, guohanjun, sudeep.holla, catalin.marinas, will,
	rafael, lenb, linux-acpi, linux-arm-kernel, ying.huang
  Cc: ptg-linux-kernel, yadong.qi

On SMT platforms, an L2 cache MSC is typically shared between sibling
threads. Per the MPAM ACPI spec (DEN0065B), the MSC's linked device
should be set to the processor container of those siblings, so the
kernel derives msc->accessibility as just the sibling CPUs.

Per the MPAM spec (IHI0099B), when an MSC is not integrated into a PE,
SPI/LPI is the recommended error interrupt. SPIs are not per-CPU, and a
sanity check in mpam_msc_setup_error_irq() requires accessibility ==
cpu_possible_mask — assuming a shared interrupt must be routable to all
CPUs. This creates a conflict on SMT platforms: the MSC has a restricted
accessibility but a shared error interrupt, causing probe to fail with:

  msc:N is a private resource with a shared error interrupt

This RFC patch removes the check to allow MSC probe to succeed on SMT
platforms, but this is mainly intended to start a discussion. We would
appreciate advice on the right way to handle this conflict. Is this a
spec issue, or should the driver handle SPI error interrupts differently
when an MSC has a restricted accessibility mask?

Signed-off-by: Yadong Qi <yadong.qi@linux.alibaba.com>
---
 drivers/resctrl/mpam_devices.c | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index b69f99488111..e8b2b5e00d7c 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -1964,13 +1964,6 @@ static int mpam_msc_setup_error_irq(struct mpam_msc *msc)
 	if (irq_is_percpu(irq))
 		return __setup_ppi(msc);
 
-	/* sanity check: shared interrupts can be routed anywhere? */
-	if (!cpumask_equal(&msc->accessibility, cpu_possible_mask)) {
-		pr_err_once("msc:%u is a private resource with a shared error interrupt",
-			    msc->id);
-		return -EINVAL;
-	}
-
 	return 0;
 }
 
-- 
2.43.0



^ permalink raw reply related

* Re: [PATCH] ARM: select HAVE_POSIX_CPU_TIMERS_TASK_WORK
From: Sebastian Andrzej Siewior @ 2026-07-20  7:26 UTC (permalink / raw)
  To: Karl Mehltretter
  Cc: Russell King, Arnd Bergmann, linux-rt-devel, linux-arm-kernel
In-Reply-To: <20260718214515.11275-1-kmehltretter@gmail.com>

On 2026-07-18 23:45:15 [+0200], Karl Mehltretter wrote:
> Commit c6e61c06d606 ("ARM: 9463/1: Allow to enable RT") enabled PREEMPT_RT
> on ARM but did not select HAVE_POSIX_CPU_TIMERS_TASK_WORK. This leaves
> CONFIG_POSIX_CPU_TIMERS_TASK_WORK disabled, so CPU timers expire in hard
> IRQ context.
> Fixes: c6e61c06d606 ("ARM: 9463/1: Allow to enable RT")
> Assisted-by: Claude:claude-fable-5
> Signed-off-by: Karl Mehltretter <kmehltretter@gmail.com>

Reviewed-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

> Found with a self-hosted syzkaller instance patched to fuzz kernels on
> QEMU's versatilepb machine (ARM926EJ-S, ARMv5TE). Runtime-tested before
> and after the change on that setup, and compile-tested mps2_defconfig
> with PREEMPT_RT (NOMMU, CPU_V7M).

I obviously got the rules confused while dropping the KVM patches.

Sebastian


^ permalink raw reply

* Re: [PATCH v8 18/22] RISC-V: perf: Add Qemu virt machine events
From: Charlie Jenkins @ 2026-07-20  7:21 UTC (permalink / raw)
  To: Atish Patra
  Cc: Jiri Olsa, Paul Walmsley, Mark Rutland, Rob Herring, Anup Patel,
	Namhyung Kim, Arnaldo Carvalho de Melo, Krzysztof Kozlowski,
	Ian Rogers, Will Deacon, James Clark, linux-arm-kernel,
	linux-riscv, linux-kernel, devicetree, linux-perf-users,
	Conor Dooley
In-Reply-To: <20260701-counter_delegation-v8-18-7909f863a645@meta.com>

On Wed, 01 Jul 2026 01:47:06 -0700, Atish Patra <atish.patra@linux.dev> wrote:
> Qemu virt machine supports a very minimal set of legacy perf events.
> Add them to the vendor table so that users can use them when
> counter delegation is enabled.
> 
> Qemu is identified by its marchid. Older Qemu reports all-zero
> mvendorid/marchid/mimpid, while newer Qemu reports the marchid 0x2a (42)
> allocated to it in the RISC-V ISA manual [1]. Register the events for
> both ids so they are available across Qemu versions.
> 
> [1] https://github.com/riscv/riscv-isa-manual/blob/main/marchid.md

Thanks for doing this.

Reviewed-by: Charlie Jenkins <thecharlesjenkins@gmail.com>
Tested-by: Charlie Jenkins <thecharlesjenkins@gmail.com>

-- 
- Charlie



^ permalink raw reply

* Re: [PATCH v8 17/22] RISC-V: perf: Add legacy event encodings via sysfs
From: Charlie Jenkins @ 2026-07-20  7:21 UTC (permalink / raw)
  To: Atish Patra
  Cc: Jiri Olsa, Paul Walmsley, Mark Rutland, Rob Herring, Anup Patel,
	Namhyung Kim, Arnaldo Carvalho de Melo, Krzysztof Kozlowski,
	Ian Rogers, Will Deacon, James Clark, linux-arm-kernel,
	linux-riscv, linux-kernel, devicetree, linux-perf-users,
	Conor Dooley
In-Reply-To: <20260701-counter_delegation-v8-17-7909f863a645@meta.com>

# Add your code comments below. There is no need to trim or delete
# any existing content -- just insert your comments under the relevant
# lines of code. Lines starting with "> " are quoted diff context and
# lines starting with "| " are comments from other reviewers.
# The final email will be reformatted automatically to include only
# the sections that have your comments.
#
> Define sysfs details for the legacy events so that any tool can
> parse these to understand the minimum set of legacy events
> supported by the platform. The sysfs entry will describe both event
> encoding and corresponding counter map so that an perf event can be
> programmed accordingly.
> 
> Signed-off-by: Atish Patra <atishp@rivosinc.com>
>
> diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
> index 19d9e4750424..8d56bef95a1b 100644
> --- a/drivers/perf/riscv_pmu_sbi.c
> +++ b/drivers/perf/riscv_pmu_sbi.c
> @@ -131,7 +131,20 @@ static struct attribute_group riscv_cdeleg_pmu_format_group = {
>  	.attrs = riscv_cdeleg_pmu_formats_attr,
>  };
>  
> +#define RVPMU_EVENT_ATTR_RESOLVE(m) #m
> +#define RVPMU_EVENT_CMASK_ATTR(_name, _var, config, mask) \
> +	PMU_EVENT_ATTR_STRING(_name, rvpmu_event_attr_##_var, \
> +			      "event=" RVPMU_EVENT_ATTR_RESOLVE(config) \
> +			      ",counterid_mask=" RVPMU_EVENT_ATTR_RESOLVE(mask))
> +
> +#define RVPMU_EVENT_ATTR_PTR(name) (&rvpmu_event_attr_##name.attr.attr)
> +
> +static struct attribute_group riscv_cdeleg_pmu_event_group __ro_after_init = {
> +	.name = "events",
> +};
> +
>  static const struct attribute_group *riscv_cdeleg_pmu_attr_groups[] = {
> +	&riscv_cdeleg_pmu_event_group,
>  	&riscv_cdeleg_pmu_format_group,
>  	NULL,
>  };
> @@ -447,11 +460,14 @@ struct riscv_vendor_pmu_events {
>  	const struct riscv_pmu_event *hw_event_map;
>  	const struct riscv_pmu_event (*cache_event_map)[PERF_COUNT_HW_CACHE_OP_MAX]
>  						       [PERF_COUNT_HW_CACHE_RESULT_MAX];
> +	struct attribute **attrs_events;
>  };
>  
> -#define RISCV_VENDOR_PMU_EVENTS(_vendorid, _archid, _implid, _hw_event_map, _cache_event_map) \
> +#define RISCV_VENDOR_PMU_EVENTS(_vendorid, _archid, _implid, _hw_event_map, \
> +				_cache_event_map, _attrs) \
>  	{ .vendorid = _vendorid, .archid = _archid, .implid = _implid, \
> -	  .hw_event_map = _hw_event_map, .cache_event_map = _cache_event_map },
> +	  .hw_event_map = _hw_event_map, .cache_event_map = _cache_event_map, \
> +	  .attrs_events = _attrs },
>  
>  static struct riscv_vendor_pmu_events pmu_vendor_events_table[] = {
>  };
> @@ -473,6 +489,8 @@ static void __init rvpmu_vendor_register_events(void)
>  		    pmu_vendor_events_table[i].archid == arch_id) {
>  			current_pmu_hw_event_map = pmu_vendor_events_table[i].hw_event_map;
>  			current_pmu_cache_event_map = pmu_vendor_events_table[i].cache_event_map;
> +			riscv_cdeleg_pmu_event_group.attrs =
> +							pmu_vendor_events_table[i].attrs_events;
>  			break;
>  		}
>  	}

Reviewed-by: Charlie Jenkins <thecharlesjenkins@gmail.com>
Tested-by: Charlie Jenkins <thecharlesjenkins@gmail.com>

-- 
- Charlie



^ permalink raw reply

* Re: [PATCH v8 16/22] RISC-V: perf: Use config2/vendor table for event to counter mapping
From: Charlie Jenkins @ 2026-07-20  7:21 UTC (permalink / raw)
  To: Atish Patra
  Cc: Jiri Olsa, Paul Walmsley, Mark Rutland, Rob Herring, Anup Patel,
	Namhyung Kim, Arnaldo Carvalho de Melo, Krzysztof Kozlowski,
	Ian Rogers, Will Deacon, James Clark, linux-arm-kernel,
	linux-riscv, linux-kernel, devicetree, linux-perf-users,
	Conor Dooley
In-Reply-To: <20260701-counter_delegation-v8-16-7909f863a645@meta.com>

On Wed, 01 Jul 2026 01:47:04 -0700, Atish Patra <atish.patra@linux.dev> wrote:
> The counter restriction specified in the json file is passed to
> the drivers via config2 paarameter in perf attributes. This allows
> any platform vendor to define their custom mapping between event and
> hpmcounters without any rules defined in the ISA.
> 
> For legacy events, the platform vendor may define the mapping in
> the driver in the vendor event table.
> The fixed cycle and instruction counters are fixed (0 and 2
> respectively) by the ISA and maps to the legacy events. The platform
> vendor must specify this in the driver if intended to be used while
> profiling. Otherwise, they can just specify the alternate hpmcounters
> that may monitor and/or sample the cycle/instruction counts.
> 
> [...]

Reviewed-by: Charlie Jenkins <thecharlesjenkins@gmail.com>
Tested-by: Charlie Jenkins <thecharlesjenkins@gmail.com>

-- 
- Charlie



^ permalink raw reply

* Re: [PATCH v8 13/22] RISC-V: perf: Add a mechanism to defined legacy event encoding
From: Charlie Jenkins @ 2026-07-20  7:21 UTC (permalink / raw)
  To: Atish Patra
  Cc: Jiri Olsa, Paul Walmsley, Mark Rutland, Rob Herring, Anup Patel,
	Namhyung Kim, Arnaldo Carvalho de Melo, Krzysztof Kozlowski,
	Ian Rogers, Will Deacon, James Clark, linux-arm-kernel,
	linux-riscv, linux-kernel, devicetree, linux-perf-users,
	Conor Dooley
In-Reply-To: <20260701-counter_delegation-v8-13-7909f863a645@meta.com>

On Wed, 01 Jul 2026 01:47:01 -0700, Atish Patra <atish.patra@linux.dev> wrote:
> RISC-V ISA doesn't define any standard event encodings or specify
> any event to counter mapping. Thus, event encoding information
> and corresponding counter mapping fot those events needs to be
> provided in the driver for each vendor.
> 
> Add a framework to support that. The individual platform events
> will be added later.
> 
> [...]

Reviewed-by: Charlie Jenkins <thecharlesjenkins@gmail.com>
Tested-by: Charlie Jenkins <thecharlesjenkins@gmail.com>

-- 
- Charlie



^ permalink raw reply

* Re: [PATCH v8 09/22] RISC-V: Add Ssccfg/Smcdeleg ISA extension definition and parsing
From: Charlie Jenkins @ 2026-07-20  7:21 UTC (permalink / raw)
  To: Atish Patra
  Cc: Jiri Olsa, Paul Walmsley, Mark Rutland, Rob Herring, Anup Patel,
	Namhyung Kim, Arnaldo Carvalho de Melo, Krzysztof Kozlowski,
	Ian Rogers, Will Deacon, James Clark, linux-arm-kernel,
	linux-riscv, linux-kernel, devicetree, linux-perf-users,
	Conor Dooley
In-Reply-To: <20260701-counter_delegation-v8-9-7909f863a645@meta.com>

On Wed, 01 Jul 2026 01:46:57 -0700, Atish Patra <atish.patra@linux.dev> wrote:
> Smcdeleg extension allows the M-mode to delegate selected counters
> to S-mode so that it can access those counters and correpsonding
> hpmevent CSRs without M-mode.
> 
> Ssccfg (‘Ss’ for Privileged architecture and Supervisor-level
> extension, ‘ccfg’ for Counter Configuration) provides access to
> delegated counters and new supervisor-level state.
> 
> [...]

Reviewed-by: Charlie Jenkins <thecharlesjenkins@gmail.com>

-- 
- Charlie



^ permalink raw reply

* Re: [PATCH v8 12/22] RISC-V: perf: Modify the counter discovery mechanism
From: Charlie Jenkins @ 2026-07-20  7:21 UTC (permalink / raw)
  To: Atish Patra
  Cc: Jiri Olsa, Paul Walmsley, Mark Rutland, Rob Herring, Anup Patel,
	Namhyung Kim, Arnaldo Carvalho de Melo, Krzysztof Kozlowski,
	Ian Rogers, Will Deacon, James Clark, linux-arm-kernel,
	linux-riscv, linux-kernel, devicetree, linux-perf-users,
	Conor Dooley
In-Reply-To: <20260701-counter_delegation-v8-12-7909f863a645@meta.com>

On Wed, 01 Jul 2026 01:47:00 -0700, Atish Patra <atish.patra@linux.dev> wrote:
> diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
> index 74d934238821..c20f1e33c65d 100644
> --- a/drivers/perf/riscv_pmu_sbi.c
> +++ b/drivers/perf/riscv_pmu_sbi.c
> @@ -1599,13 +1658,23 @@ static int __init rvpmu_devinit(void)
> [ ... skip 15 lines ... ]
> +	 * in S-mode via Supervisor Counter delegation.
> +	 */
> +	if (riscv_isa_extension_available(NULL, SSCCFG) &&
> +	    riscv_isa_extension_available(NULL, SMCDELEG) &&
> +	    riscv_isa_extension_available(NULL, SSCSRIND))
> +		static_branch_enable(&riscv_pmu_cdeleg_available);

This needs to not only check that smcdeleg is supported in linux, but
also that it is supported in the SBI implementation correct? Trying to
boot this on OpenSBI before 6bb6b61c27eb ("lib: sbi: Add support for smcsrind and
smcdeleg") will fail on an illegal instruction in
rvpmu_deleg_find_ctrs() while trying to access the scountinhibit csr in
the patch "RISC-V: perf: Implement supervisor counter delegation
support". The proper mstateen bits need to be set for this to work
without crashing.

-- 
- Charlie



^ permalink raw reply

* Re: [PATCH v8 08/22] RISC-V: Add Sscfg extension CSR definition
From: Charlie Jenkins @ 2026-07-20  7:21 UTC (permalink / raw)
  To: Atish Patra
  Cc: Jiri Olsa, Paul Walmsley, Mark Rutland, Rob Herring, Anup Patel,
	Namhyung Kim, Arnaldo Carvalho de Melo, Krzysztof Kozlowski,
	Ian Rogers, Will Deacon, James Clark, linux-arm-kernel,
	linux-riscv, linux-kernel, devicetree, linux-perf-users,
	Conor Dooley
In-Reply-To: <20260701-counter_delegation-v8-8-7909f863a645@meta.com>

On Wed, 01 Jul 2026 01:46:56 -0700, Atish Patra <atish.patra@linux.dev> wrote:
> This adds the scountinhibit CSR definition and S-mode accessible hpmevent
> bits defined by smcdeleg/ssccfg. scountinhibit allows S-mode to start/stop
> counters directly from S-mode without invoking SBI calls to M-mode. It is
> also used to figure out the counters delegated to S-mode by the M-mode as
> well.
> 
> Signed-off-by: Kaiwen Xue <kaiwenx@rivosinc.com>

Does this need to be signed off by you?

Reviewed-by: Charlie Jenkins <thecharlesjenkins@gmail.com>
Tested-by: Charlie Jenkins <thecharlesjenkins@gmail.com>

-- 
- Charlie



^ permalink raw reply

* Re: [PATCH v8 06/22] RISC-V: Add Smcntrpmf extension parsing
From: Charlie Jenkins @ 2026-07-20  7:21 UTC (permalink / raw)
  To: Atish Patra
  Cc: Jiri Olsa, Paul Walmsley, Mark Rutland, Rob Herring, Anup Patel,
	Namhyung Kim, Arnaldo Carvalho de Melo, Krzysztof Kozlowski,
	Ian Rogers, Will Deacon, James Clark, linux-arm-kernel,
	linux-riscv, linux-kernel, devicetree, linux-perf-users,
	Conor Dooley
In-Reply-To: <20260701-counter_delegation-v8-6-7909f863a645@meta.com>

On Wed, 01 Jul 2026 01:46:54 -0700, Atish Patra <atish.patra@linux.dev> wrote:
> Smcntrpmf extension allows M-mode to enable privilege mode filtering
> for cycle/instret counters. However, the cyclecfg/instretcfg CSRs are
> available in Ssccfg only if Smcntrpmf is present.
> 
> That's why, kernel needs to detect presence of Smcntrpmf extension and
> enable privilege mode filtering for cycle/instret counters.
> 
> [...]

Reviewed-by: Charlie Jenkins <thecharlesjenkins@gmail.com>
Tested-by: Charlie Jenkins <thecharlesjenkins@gmail.com>

-- 
- Charlie



^ permalink raw reply

* Re: [PATCH v8 05/22] RISC-V: Define indirect CSR access helpers
From: Charlie Jenkins @ 2026-07-20  7:21 UTC (permalink / raw)
  To: Atish Patra
  Cc: Jiri Olsa, Paul Walmsley, Mark Rutland, Rob Herring, Anup Patel,
	Namhyung Kim, Arnaldo Carvalho de Melo, Krzysztof Kozlowski,
	Ian Rogers, Will Deacon, James Clark, linux-arm-kernel,
	linux-riscv, linux-kernel, devicetree, linux-perf-users,
	Conor Dooley
In-Reply-To: <20260701-counter_delegation-v8-5-7909f863a645@meta.com>

On Wed, 01 Jul 2026 01:46:53 -0700, Atish Patra <atish.patra@linux.dev> wrote:
> The indirect CSR requires multiple instructions to read/write CSR.
> Add a few helper functions for ease of usage.

Reviewed-by: Charlie Jenkins <thecharlesjenkins@gmail.com>
Tested-by: Charlie Jenkins <thecharlesjenkins@gmail.com>

-- 
- Charlie



^ permalink raw reply

* Re: [PATCH v8 02/22] RISC-V: Add Sxcsrind ISA extension CSR definitions
From: Charlie Jenkins @ 2026-07-20  7:21 UTC (permalink / raw)
  To: Atish Patra
  Cc: Jiri Olsa, Paul Walmsley, Mark Rutland, Rob Herring, Anup Patel,
	Namhyung Kim, Arnaldo Carvalho de Melo, Krzysztof Kozlowski,
	Ian Rogers, Will Deacon, James Clark, linux-arm-kernel,
	linux-riscv, linux-kernel, devicetree, linux-perf-users,
	Conor Dooley
In-Reply-To: <20260701-counter_delegation-v8-2-7909f863a645@meta.com>

On Wed, 01 Jul 2026 01:46:50 -0700, Atish Patra <atish.patra@linux.dev> wrote:
> This adds definitions of new CSRs and bits defined in Sxcsrind ISA
> extension. These CSR enables indirect accesses mechanism to access
> any CSRs in M-, S-, and VS-mode. The range of the select values
> and ireg will be define by the ISA extension using Sxcsrind extension.

Reviewed-by: Charlie Jenkins <thecharlesjenkins@gmail.com>
Tested-by: Charlie Jenkins <thecharlesjenkins@gmail.com>

-- 
- Charlie



^ permalink raw reply

* Re: [PATCH v8 03/22] RISC-V: Add Sxcsrind ISA extension definition and parsing
From: Charlie Jenkins @ 2026-07-20  7:21 UTC (permalink / raw)
  To: Atish Patra
  Cc: Jiri Olsa, Paul Walmsley, Mark Rutland, Rob Herring, Anup Patel,
	Namhyung Kim, Arnaldo Carvalho de Melo, Krzysztof Kozlowski,
	Ian Rogers, Will Deacon, James Clark, linux-arm-kernel,
	linux-riscv, linux-kernel, devicetree, linux-perf-users,
	Conor Dooley
In-Reply-To: <20260701-counter_delegation-v8-3-7909f863a645@meta.com>

On Wed, 01 Jul 2026 01:46:51 -0700, Atish Patra <atish.patra@linux.dev> wrote:
> The S[m|s]csrind extension extends the indirect CSR access mechanism
> defined in Smaia/Ssaia extensions.
> 
> This patch just enables the definition and parsing.

Reviewed-by: Charlie Jenkins <thecharlesjenkins@gmail.com>
Tested-by: Charlie Jenkins <thecharlesjenkins@gmail.com>

-- 
- Charlie



^ permalink raw reply

* Re: [PATCH v8 01/22] RISC-V: perf: fix resource cleanup on driver probe failure
From: Charlie Jenkins @ 2026-07-20  7:21 UTC (permalink / raw)
  To: Atish Patra
  Cc: Jiri Olsa, Paul Walmsley, Mark Rutland, Rob Herring, Anup Patel,
	Namhyung Kim, Arnaldo Carvalho de Melo, Krzysztof Kozlowski,
	Ian Rogers, Will Deacon, James Clark, linux-arm-kernel,
	linux-riscv, linux-kernel, devicetree, linux-perf-users,
	Conor Dooley
In-Reply-To: <20260701-counter_delegation-v8-1-7909f863a645@meta.com>

On Wed, 01 Jul 2026 01:46:49 -0700, Atish Patra <atish.patra@linux.dev> wrote:
> Sashiko pointed out various UAF and memory leak issues around
> pmu_sbi_device_probe() error paths.
> 
> If the probe fails, here are list of cleanups needed.
> a. Already registered pmu must be freed
> b. per cpu IRQ must be released
> c. pmu_ctr_list data structure must be freed
> d. cpu hotplug state must be cleaned up only if added.
> 
> [...]

Reviewed-by: Charlie Jenkins <thecharlesjenkins@gmail.com>

-- 
- Charlie



^ permalink raw reply

* Re: [PATCH v10 3/4] reset: cix: add sky1 audss auxiliary reset driver
From: Philipp Zabel @ 2026-07-20  7:20 UTC (permalink / raw)
  To: joakim.zhang, mturquette, sboyd, bmasney, robh, krzk+dt, conor+dt
  Cc: cix-kernel-upstream, linux-clk, devicetree, linux-kernel,
	linux-arm-kernel
In-Reply-To: <20260720051505.1252774-4-joakim.zhang@cixtech.com>

On Mo, 2026-07-20 at 13:15 +0800, joakim.zhang@cixtech.com wrote:
> From: Joakim Zhang <joakim.zhang@cixtech.com>
> 
> Add an auxiliary reset controller driver for the AUDSS CRU. Sixteen
> software reset lines for audio subsystem peripherals are controlled
> through one register in the CRU register map.
> 
> The driver is created by the AUDSS clock platform driver and registers
> the reset controller on the CRU device node.
> 
> Signed-off-by: Joakim Zhang <joakim.zhang@cixtech.com>
> ---
>  drivers/reset/Kconfig            |  13 +++
>  drivers/reset/Makefile           |   1 +
>  drivers/reset/reset-sky1-audss.c | 137 +++++++++++++++++++++++++++++++
>  3 files changed, 151 insertions(+)
>  create mode 100644 drivers/reset/reset-sky1-audss.c
> 
> diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
> index d009eb0849a3..b19e719f2abe 100644
> --- a/drivers/reset/Kconfig
> +++ b/drivers/reset/Kconfig
> @@ -300,6 +300,19 @@ config RESET_SKY1
>  	help
>  	  This enables the reset controller for Cix Sky1.
>  
> +config RESET_SKY1_AUDSS
> +	tristate "Cix Sky1 Audio Subsystem reset controller"
> +	depends on ARCH_CIX || COMPILE_TEST
> +	select AUXILIARY_BUS
> +	default CLK_SKY1_AUDSS
> +	help
> +	  Support for block-level software reset lines in the Cix Sky1
> +	  Audio Subsystem (AUDSS) Clock and Reset Unit. Sixteen reset
> +	  outputs for audio peripherals are controlled through the CRU
> +	  register map. The driver binds as an auxiliary device from
> +	  the AUDSS clock driver. Say M or Y here if you want to build
> +	  this driver.
> +
>  config RESET_SOCFPGA
>  	bool "SoCFPGA Reset Driver" if COMPILE_TEST && (!ARM || !ARCH_INTEL_SOCFPGA)
>  	default ARM && ARCH_INTEL_SOCFPGA
> diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
> index 3e52569bd276..e81407ea3e29 100644
> --- a/drivers/reset/Makefile
> +++ b/drivers/reset/Makefile
> @@ -39,6 +39,7 @@ obj-$(CONFIG_RESET_RZV2H_USB2PHY) += reset-rzv2h-usb2phy.o
>  obj-$(CONFIG_RESET_SCMI) += reset-scmi.o
>  obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
>  obj-$(CONFIG_RESET_SKY1) += reset-sky1.o
> +obj-$(CONFIG_RESET_SKY1_AUDSS) += reset-sky1-audss.o
>  obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o
>  obj-$(CONFIG_RESET_SUNPLUS) += reset-sunplus.o
>  obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
> diff --git a/drivers/reset/reset-sky1-audss.c b/drivers/reset/reset-sky1-audss.c
> new file mode 100644
> index 000000000000..d31d80e1251a
> --- /dev/null
> +++ b/drivers/reset/reset-sky1-audss.c
> @@ -0,0 +1,137 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Cix Sky1 Audio Subsystem reset controller driver
> + *
> + * Copyright 2026 Cix Technology Group Co., Ltd.
> + */
> +
> +#include <dt-bindings/reset/cix,sky1-audss-cru.h>
> +
> +#include <linux/auxiliary_bus.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/module.h>
> +#include <linux/of.h>

What is this used for?

> +#include <linux/regmap.h>
> +#include <linux/reset-controller.h>
> +
> +#define SKY1_RESET_SLEEP_MIN_US		50
> +#define SKY1_RESET_SLEEP_MAX_US		100

Is this delay compatible with all possible modules being reset?

Are min and max from a spec or is this just some safe value?
Maybe you could only define the _MIN_US and use fsleep() below.

> +
> +#define AUDSS_SW_RST			0x78
> +
> +struct sky1_audss_reset_map {
> +	unsigned int offset;
> +	unsigned int mask;
> +};
> +
> +struct sky1_audss_reset {
> +	struct reset_controller_dev rcdev;
> +	struct regmap *regmap;
> +	const struct sky1_audss_reset_map *map;
> +};
> +
> +static const struct sky1_audss_reset_map sky1_audss_reset_map[] = {
> +	[AUDSS_I2S0_SW_RST]   = { AUDSS_SW_RST, BIT(0) },
> +	[AUDSS_I2S1_SW_RST]   = { AUDSS_SW_RST, BIT(1) },
> +	[AUDSS_I2S2_SW_RST]   = { AUDSS_SW_RST, BIT(2) },
> +	[AUDSS_I2S3_SW_RST]   = { AUDSS_SW_RST, BIT(3) },
> +	[AUDSS_I2S4_SW_RST]   = { AUDSS_SW_RST, BIT(4) },
> +	[AUDSS_I2S5_SW_RST]   = { AUDSS_SW_RST, BIT(5) },
> +	[AUDSS_I2S6_SW_RST]   = { AUDSS_SW_RST, BIT(6) },
> +	[AUDSS_I2S7_SW_RST]   = { AUDSS_SW_RST, BIT(7) },
> +	[AUDSS_I2S8_SW_RST]   = { AUDSS_SW_RST, BIT(8) },
> +	[AUDSS_I2S9_SW_RST]   = { AUDSS_SW_RST, BIT(9) },
> +	[AUDSS_WDT_SW_RST]    = { AUDSS_SW_RST, BIT(10) },
> +	[AUDSS_TIMER_SW_RST]  = { AUDSS_SW_RST, BIT(11) },
> +	[AUDSS_MB0_SW_RST]    = { AUDSS_SW_RST, BIT(12) },
> +	[AUDSS_MB1_SW_RST]    = { AUDSS_SW_RST, BIT(13) },
> +	[AUDSS_HDA_SW_RST]    = { AUDSS_SW_RST, BIT(14) },
> +	[AUDSS_DMAC_SW_RST]   = { AUDSS_SW_RST, BIT(15) },
> +};
> +
> +static struct sky1_audss_reset *to_sky1_audss_reset(struct reset_controller_dev *rcdev)
> +{
> +	return container_of(rcdev, struct sky1_audss_reset, rcdev);
> +}
> +
> +static int sky1_audss_reset_set(struct reset_controller_dev *rcdev,
> +				unsigned long id, bool assert)
> +{
> +	struct sky1_audss_reset *priv = to_sky1_audss_reset(rcdev);
> +	const struct sky1_audss_reset_map *signal = &priv->map[id];
> +	unsigned int value = assert ? 0 : signal->mask;
> +
> +	return regmap_update_bits(priv->regmap, signal->offset, signal->mask, value);

Consider using regmap_assign_bits() instead.

> +}
> +
> +static int sky1_audss_reset_assert(struct reset_controller_dev *rcdev,
> +				   unsigned long id)
> +{
> +	int ret;
> +
> +	ret = sky1_audss_reset_set(rcdev, id, true);
> +	if (ret)
> +		return ret;
> +
> +	usleep_range(SKY1_RESET_SLEEP_MIN_US, SKY1_RESET_SLEEP_MAX_US);
> +	return 0;
> +}
> +
> +static int sky1_audss_reset_deassert(struct reset_controller_dev *rcdev,
> +				     unsigned long id)
> +{
> +	int ret;
> +
> +	ret = sky1_audss_reset_set(rcdev, id, false);
> +	if (ret)
> +		return ret;
> +
> +	usleep_range(SKY1_RESET_SLEEP_MIN_US, SKY1_RESET_SLEEP_MAX_US);

This is the same in both assert and deassert. You could move it into
the helper function.

regards
Philipp


^ permalink raw reply

* [PATCH v5 4/4] irqchip/gic-v3-its: Fix grammar and replace a bit number with its symbol
From: Kemeng Shi @ 2026-07-20  7:12 UTC (permalink / raw)
  To: maz, tglx, jason, lpieralisi, radu
  Cc: linux-arm-kernel, linux-kernel, Kemeng Shi
In-Reply-To: <20260720071215.50705-1-shikemeng@huaweicloud.com>

Fix grammatical errors in comments and simplify the comment about reading
GITS_BASER_INDIRECT to check two-level support.

Signed-off-by: Kemeng Shi <shikemeng@huaweicloud.com>
---
 drivers/irqchip/irq-gic-v3-its.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 5dc91862fc15..8935a6e7a20f 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -163,7 +163,7 @@ struct event_lpi_map {
 
 /*
  * The ITS view of a device - belongs to an ITS, owns an interrupt
- * translation table, and a list of interrupts.  If it some of its
+ * translation table, and a list of interrupts.  If some of its
  * LPIs are injected into a guest (GICv4), the event_map.vm field
  * indicates which one.
  */
@@ -2502,8 +2502,7 @@ static bool its_parse_indirect_baser(struct its_node *its,
 	/* No need to enable Indirection if memory requirement < (psz*2)bytes */
 	if ((esz << ids) > (psz * 2)) {
 		/*
-		 * Find out whether hw supports a single or two-level table by
-		 * table by reading bit at offset '62' after writing '1' to it.
+		 * Find out whether hw supports a single or two-level table
 		 */
 		its_write_baser(its, baser, val | GITS_BASER_INDIRECT);
 		indirect = !!(baser->val & GITS_BASER_INDIRECT);
-- 
2.36.1



^ permalink raw reply related

* [PATCH v5 0/4] Some Minor fixes and cleanups to irqchip/gic-v3-its
From: Kemeng Shi @ 2026-07-20  7:12 UTC (permalink / raw)
  To: maz, tglx, jason, lpieralisi, radu
  Cc: linux-arm-kernel, linux-kernel, Kemeng Shi

There are some random fixes and cleanups to irqchip/gic-v3-its. More
details can be found in respective patches.
Thanks.

v1->v2:
- Drop unneeded patches and some minor improvement.
v2->v3:
- Fix an extra leak issue in its_vpe_irq_domain_alloc().
- Remove redundant check in its_vpe_db_proxy_unmap_locked()
v3->v4:
- Add missing Fixes tags
- Improve changelog description
v4->v5:
- Collect RVB from Radu
- Drop more unneeded patches
- Use existing error handling to do its_vpe_teardown() in patch 3/4

Kemeng Shi (4):
  irqchip/gic-v3-its: Fix memleak in its_probe_one()
  irqchip/gic-v3-its: Fix its node leak in gic_acpi_parse_madt_its()
  irqchip/gic-v3-its: Fix leak in its_vpe_irq_domain_alloc()
  irqchip/gic-v3-its: Fix grammar and replace a bit number with its
    symbol

 drivers/irqchip/irq-gic-v3-its.c | 29 +++++++++++++++++++----------
 1 file changed, 19 insertions(+), 10 deletions(-)

-- 
2.36.1



^ permalink raw reply

* [PATCH v5 2/4] irqchip/gic-v3-its: Fix its node leak in gic_acpi_parse_madt_its()
From: Kemeng Shi @ 2026-07-20  7:12 UTC (permalink / raw)
  To: maz, tglx, jason, lpieralisi, radu
  Cc: linux-arm-kernel, linux-kernel, Kemeng Shi
In-Reply-To: <20260720071215.50705-1-shikemeng@huaweicloud.com>

Fix its node leak when its_probe_one() failed in
gic_acpi_parse_madt_its().

Fixes: 9585a495ac936 ("irqchip/gic-v3-its: Split allocation from initialisation of its_node")
Signed-off-by: Kemeng Shi <shikemeng@huaweicloud.com>
Reviewed-by: Radu Rendec <radu@rendec.net>
---
 drivers/irqchip/irq-gic-v3-its.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index d721b6101e0a..3e4edcb64065 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -5747,9 +5747,13 @@ static int __init gic_acpi_parse_madt_its(union acpi_subtable_headers *header,
 		its->flags |= ITS_FLAGS_FORCE_NON_SHAREABLE;
 
 	err = its_probe_one(its);
-	if (!err)
-		return 0;
+	if (err)
+		goto probe_err;
+
+	return 0;
 
+probe_err:
+	its_node_destroy(its);
 node_err:
 	iort_deregister_domain_token(its_entry->translation_id);
 dom_err:
-- 
2.36.1



^ permalink raw reply related

* [PATCH v5 1/4] irqchip/gic-v3-its: Fix memleak in its_probe_one()
From: Kemeng Shi @ 2026-07-20  7:12 UTC (permalink / raw)
  To: maz, tglx, jason, lpieralisi, radu
  Cc: linux-arm-kernel, linux-kernel, Kemeng Shi
In-Reply-To: <20260720071215.50705-1-shikemeng@huaweicloud.com>

Fix collection leak when its_init_domain() failed in its_probe_one().

Fixes: 4c21f3c26ecc2 ("irqchip: GICv3: ITS: DT probing and initialization")
Signed-off-by: Kemeng Shi <shikemeng@huaweicloud.com>
Reviewed-by: Radu Rendec <radu@rendec.net>
---
 drivers/irqchip/irq-gic-v3-its.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 291d7668cc8d..d721b6101e0a 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -5326,7 +5326,7 @@ static int __init its_probe_one(struct its_node *its)
 
 	err = its_init_domain(its);
 	if (err)
-		goto out_free_tables;
+		goto out_free_col;
 
 	raw_spin_lock(&its_lock);
 	list_add(&its->entry, &its_nodes);
@@ -5334,6 +5334,8 @@ static int __init its_probe_one(struct its_node *its)
 
 	return 0;
 
+out_free_col:
+	kfree(its->collections);
 out_free_tables:
 	its_free_tables(its);
 out_free_cmd:
-- 
2.36.1



^ permalink raw reply related

* [PATCH v5 3/4] irqchip/gic-v3-its: Fix leak in its_vpe_irq_domain_alloc()
From: Kemeng Shi @ 2026-07-20  7:12 UTC (permalink / raw)
  To: maz, tglx, jason, lpieralisi, radu
  Cc: linux-arm-kernel, linux-kernel, Kemeng Shi
In-Reply-To: <20260720071215.50705-1-shikemeng@huaweicloud.com>

When its_irq_gic_domain_alloc() fails, the following
its_vpe_irq_domain_free() skips calling its_vep_teardown() for the
corresponding irq. Try its_vpe_teardown() in error handling to avoid
the leak issue.

Fixes: 7d75bbb4bc1ad ("irqchip/gic-v3-its: Add VPE irq domain allocation/teardown")
Signed-off-by: Kemeng Shi <shikemeng@huaweicloud.com>
---
 drivers/irqchip/irq-gic-v3-its.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 3e4edcb64065..5dc91862fc15 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -4594,9 +4594,11 @@ static int its_vpe_init(struct its_vpe *vpe)
 
 static void its_vpe_teardown(struct its_vpe *vpe)
 {
-	its_vpe_db_proxy_unmap(vpe);
-	its_vpe_id_free(vpe->vpe_id);
-	its_free_pending_table(vpe->vpt_page);
+	if (vpe->vpt_page != NULL) {
+		its_vpe_db_proxy_unmap(vpe);
+		its_vpe_id_free(vpe->vpe_id);
+		its_free_pending_table(vpe->vpt_page);
+	}
 }
 
 static void its_vpe_irq_domain_free(struct irq_domain *domain,
@@ -4674,8 +4676,10 @@ static int its_vpe_irq_domain_alloc(struct irq_domain *domain, unsigned int virq
 		irqd_set_resend_when_in_progress(irq_get_irq_data(virq + i));
 	}
 
-	if (err)
+	if (err) {
+		its_vpe_teardown(vm->vpes[i]);
 		its_vpe_irq_domain_free(domain, virq, i);
+	}
 
 	return err;
 }
-- 
2.36.1



^ permalink raw reply related

* Re: [PATCH] drm/mediatek: Check CRTC state before freeing
From: CK Hu (胡俊光) @ 2026-07-20  6:47 UTC (permalink / raw)
  To: p.zabel@pengutronix.de, AngeloGioacchino Del Regno,
	chunkuang.hu@kernel.org, ruoyuw560@gmail.com, airlied@gmail.com,
	matthias.bgg@gmail.com, simona@ffwll.ch
  Cc: dri-devel@lists.freedesktop.org,
	linux-mediatek@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org
In-Reply-To: <20260707150528.2270739-1-ruoyuw560@gmail.com>

On Tue, 2026-07-07 at 23:05 +0800, Ruoyu Wang wrote:
> External email : Please do not click links or open attachments until you have verified the sender or the content.
> 
> 
> mtk_crtc_reset() destroys the current CRTC state only when crtc->state
> is non-NULL, but it always converts crtc->state to struct mtk_crtc_state
> and passes the result to kfree().
> 
> When reset is called without an existing state, container_of(NULL, ...)
> does not produce NULL. Keep the mtk state free in the same crtc->state
> guard as the helper state destruction.
> 
> This issue was found by a static analysis checker and confirmed by
> manual source review.

Reviewed-by: CK Hu <ck.hu@mediatek.com>

> 
> Fixes: 2d267b81898e ("drm/mtk: Use __drm_atomic_helper_crtc_reset")
> Signed-off-by: Ruoyu Wang <ruoyuw560@gmail.com>
> ---
>  drivers/gpu/drm/mediatek/mtk_crtc.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.c b/drivers/gpu/drm/mediatek/mtk_crtc.c
> index 8e552cdc3b53b..97e3ff412e6ee 100644
> --- a/drivers/gpu/drm/mediatek/mtk_crtc.c
> +++ b/drivers/gpu/drm/mediatek/mtk_crtc.c
> @@ -154,10 +154,10 @@ static void mtk_crtc_reset(struct drm_crtc *crtc)
>  {
>         struct mtk_crtc_state *state;
> 
> -       if (crtc->state)
> +       if (crtc->state) {
>                 __drm_atomic_helper_crtc_destroy_state(crtc->state);
> -
> -       kfree(to_mtk_crtc_state(crtc->state));
> +               kfree(to_mtk_crtc_state(crtc->state));
> +       }
>         crtc->state = NULL;
> 
>         state = kzalloc_obj(*state);
> --
> 2.51.0
> 
> 


^ permalink raw reply

* RE: [PATCH v2] PCI: imx6: Fix i.MX6Q/DL boot hang by separating PHY power and reference clock control
From: Hongxing Zhu @ 2026-07-20  6:39 UTC (permalink / raw)
  To: Bjorn Helgaas, Hongxing Zhu (OSS)
  Cc: Manivannan Sadhasivam, Frank Li, l.stach@pengutronix.de,
	lpieralisi@kernel.org, kwilczynski@kernel.org, robh@kernel.org,
	bhelgaas@google.com, s.hauer@pengutronix.de,
	kernel@pengutronix.de, festevam@gmail.com,
	linux-pci@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	imx@lists.linux.dev, linux-kernel@vger.kernel.org
In-Reply-To: <20260717231426.GA211988@bhelgaas>

> -----Original Message-----
> From: Bjorn Helgaas <helgaas@kernel.org>
> Sent: Saturday, July 18, 2026 7:14 AM
> To: Hongxing Zhu (OSS) <hongxing.zhu@oss.nxp.com>
> Cc: Manivannan Sadhasivam <mani@kernel.org>; Frank Li <frank.li@nxp.com>;
> l.stach@pengutronix.de; lpieralisi@kernel.org; kwilczynski@kernel.org;
> robh@kernel.org; bhelgaas@google.com; s.hauer@pengutronix.de;
> kernel@pengutronix.de; festevam@gmail.com; linux-pci@vger.kernel.org; linux-
> arm-kernel@lists.infradead.org; imx@lists.linux.dev; linux-
> kernel@vger.kernel.org; Hongxing Zhu <hongxing.zhu@nxp.com>
> Subject: Re: [PATCH v2] PCI: imx6: Fix i.MX6Q/DL boot hang by separating PHY
> power and reference clock control
> 
> On Fri, Jul 17, 2026 at 08:57:04AM +0000, Hongxing Zhu (OSS) wrote:
> > > -----Original Message-----
> > > From: Manivannan Sadhasivam <mani@kernel.org>
> > ...
> > > On Wed, Jul 08, 2026 at 11:59:27AM +0800, hongxing.zhu@oss.nxp.com
> wrote:
> > > > From: Richard Zhu <hongxing.zhu@nxp.com>
> > > >
> > > > Commit 610fa91d9863 ("PCI: imx6: Assert PERST# before enabling
> > > > regulators") introduced a boot hang on i.MX6Q/DL variants by
> > > > changing the initialization sequence.
> > > >
> > > > The issue stems from coupling PHY power (TEST_PD) and reference
> > > > clock
> > > > (REF_CLK_EN) control in imx6q_pcie_enable_ref_clk(). When these
> > > > are managed together, the timing between PHY power-up and
> > > > reference clock enablement cannot be properly controlled, leading
> > > > to initialization failures.
> 
> This is kind of a hand-wavy description that doesn't explain exactly what
> 610fa91d9863 changed that broke the boot.
> 
> I don't understand what you're saying about timing between PHY power-up and
> REFCLK enable because it looks like you enable REFCLK *first*, then power up the
> PHY.  There's a 200us delay in
> imx_pcie_clk_enable() after enabling REFCLK, but that was already there in
> 610fa91d9863.
Hi Bjorn:
You're right that my initial description was unclear. Let me explain exactly
what commit 610fa91d9863 changed that caused the boot hang.

Before commit 610fa91d9863:

The function call order was:

imx_pcie_assert_core_reset() - Asserts TEST_PD and clears REF_CLK_EN
imx_pcie_clk_enable() - Clears TEST_PD and asserts REF_CLK_EN
Link training starts with TEST_PD properly cleared ✓

After commit 610fa91d9863:

The function call order changed to:

imx_pcie_clk_enable() - Clears TEST_PD and asserts REF_CLK_EN
imx_pcie_assert_core_reset() - Re-asserts TEST_PD and asserts REF_CLK_EN again
imx_pcie_deassert_core_reset() - Does NOT clear TEST_PD
Link training starts with TEST_PD still asserted ✗

Root cause: The reordering means TEST_PD gets cleared early in
imx_pcie_clk_enable(), but then gets re-asserted by
imx_pcie_assert_core_reset() and is never cleared again before link training
begins. This causes the boot hang.

This fix ensures TEST_PD is cleared at the appropriate time regardless of the
function call order.

> 
> > > What is the timing requirement here?
> >
> > The timing requirement is that TEST_PD must be deasserted (cleared)
> > before link training starts.
> 
> Is there any delay required between deasserting TEST_PD and link training?
> 
> Prior to this patch, imx_pcie_deassert_core_reset() didn't touch TEST_PD on
> imx6qp, but it did delay 200us in imx6qp_pcie_core_reset().
> Now it will clear TEST_PD and still delay 200us.
> 
Yes, there is a delay requirement (~ 120us) between TEST_PD de-assertion and
link training start.

This delay is already satisfied by the PERST# toggling sequence in
imx_pcie_assert_perst(), which is called after imx_pcie_deassert_core_reset().
The PERST# assertion time is much longer than 120us, so it provides sufficient
delay.

Regarding the 200us delay in imx6qp_pcie_core_reset(): this delay was
originally intended to satisfy the TEST_PD timing requirement. Since TEST_PD
is now properly cleared in imx_pcie_deassert_core_reset() and the timing is
covered by the subsequent PERST# sequence, the 200us delay in
imx6qp_pcie_core_reset() is redundant and could be removed in a follow-up
patch.

> On imx6q, it didn't touch TEST_PD or delay.  Now it will clear TEST_PD but still
> won't delay.
> 
> I don't see any other delay enforced between PHY power up (in
> imx_pcie_deassert_core_reset()) and link training.  So after this patch, it looks like
> the chipset-specific behavior in
> imx_pcie_deassert_core_reset() is:
> 
>   imx6sx:  clear TEST_POWERDOWN, no delay
>   imx6q:   clear TEST_PD, no delay
>   imx6qp:  clear TEST_PD, usleep(200)
>   imx7d:   wait for PHY PLL lock
>   imx95:   nothing
> 
> Here's the path I see after this patch is applied:
> 
>   imx_pcie_probe
>     dw_pcie_host_init
>       imx_pcie_host_init
>         imx_pcie_clk_enable
>           imx6q_pcie_enable_ref_clk(enable=true)
>             regmap_set_bits(IMX6Q_GPR1_PCIE_REF_CLK_EN)   # REFCLK enable
>           usleep(200)                                     # <-- delay
>         imx_pcie_assert_core_reset
>           imx6q_pcie_core_reset(assert=true)
>             regmap_set_bits(IMX6Q_GPR1_PCIE_TEST_PD)      # PHY power off
>         imx_pcie_ltssm_disable
>         imx_pcie_deassert_core_reset
> 
>           imx6q_pcie_core_reset(assert=false)
>             regmap_clear_bits(IMX6Q_GPR1_PCIE_TEST_PD)    # PHY power on
>        -- or --
>           imx6qp_pcie_core_reset(assert=false)
>             regmap_clear_bits(IMX6Q_GPR1_PCIE_TEST_PD)    # PHY power on
>             regmap_update_bits(IMX6Q_GPR1_PCIE_SW_RST)
>             usleep(200)                                   # <-- delay
> 
>       dw_pcie_start_link
>         imx_pcie_start_link
> 
> > Before commit 610fa91d9863:
> > - imx_pcie_assert_core_reset(): Assert TEST_PD and REF_CLK_EN
> > - imx_pcie_clk_enable(): Deassert TEST_PD and assert REF_CLK_EN
> > - Link training starts with TEST_PD properly cleared
> >
> > After commit 610fa91d9863:
> > - imx_pcie_clk_enable(): Deassert TEST_PD and assert REF_CLK_EN
> > - imx_pcie_assert_core_reset(): Assert TEST_PD and assert REF_CLK_EN
> > again
> > - Link training starts with TEST_PD still asserted (never cleared
> > again)
> >
> > This commit corrects the sequence, and makes sure the TEST_PD is
> > cleared before link training starts.
> 
> 
> > > > Fix this by separating the two concerns:
> > > >
> > > > - Move PHY power control (TEST_PD) to imx6q_pcie_core_reset() where it
> > > >   logically belongs with reset operations. This ensures PHY power state
> > > >   is managed as part of the core reset sequence.
> > > >
> > > > - Update imx6qp_pcie_core_reset() to call imx6q_pcie_core_reset() for
> > > >   shared PHY power management, avoiding code duplication.
> > > >
> > > > - Make imx6q_pcie_enable_ref_clk() responsible only for reference clock
> > > >   (REF_CLK_EN) control, simplifying its purpose.
> > > >
> > > > - Remove the 10us delay workaround from imx6q_pcie_enable_ref_clk() as
> > > >   proper sequencing is now handled by the core_reset functions.
> > > >
> > > > This refactoring ensures PHY power is controlled during reset
> > > > operations, fixing the boot hang while improving code maintainability.
> > > >
> > >
> > > This patch does too many things at once. Can't you split it and keep
> > > the minimal fix in one patch?
> >
> > Okay, I'll split this into a patch series in v3.
> 
> The "invoke imx_pcie_assert_core_reset() explicitly in error path of
> imx_pcie_host_init() and imx_pcie_host_exit()" part seems unrelated to the boot
> hang.
The changes to the error path and exit function are related to this fix.

Previously, imx_pcie_clk_disable() would assert TEST_PD for i.MX6Q/i.MX6QP as
a side effect. However, with this patch, TEST_PD manipulation is moved out of
the clock enable/disable functions and into the core reset functions where it
logically belongs.

This means we need to explicitly call imx_pcie_assert_core_reset() in the
error path of imx_pcie_host_init() and in imx_pcie_host_exit() to ensure
TEST_PD is properly asserted during shutdown/cleanup. Without this, we would
have a power leak issue, which is why Sashiko suggested this change in the
previous review.

Thanks for your kindly review.
Best Regards
Richard Zhu
> 
> > > > Fixes: 610fa91d9863 ("PCI: imx6: Assert PERST# before enabling
> > > > regulators")
> > > > Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
> > > > ---
> > > > Changes in v2:
> > > > Regarding sashiko's reivew, invoke imx_pcie_assert_core_reset()
> > > > explicitly in error path of imx_pcie_host_init() and imx_pcie_host_exit().
> > > > ---
> > > >  drivers/pci/controller/dwc/pci-imx6.c | 45
> > > > ++++++++++++---------------
> > > >  1 file changed, 20 insertions(+), 25 deletions(-)
> > > >
> > > > diff --git a/drivers/pci/controller/dwc/pci-imx6.c
> > > > b/drivers/pci/controller/dwc/pci-imx6.c
> > > > index 9406bba36953f..53f3da6ab30d5 100644
> > > > --- a/drivers/pci/controller/dwc/pci-imx6.c
> > > > +++ b/drivers/pci/controller/dwc/pci-imx6.c
> > > > @@ -680,21 +680,12 @@ static int imx_pcie_attach_pd(struct device
> > > > *dev)
> > > >
> > > >  static int imx6q_pcie_enable_ref_clk(struct imx_pcie *imx_pcie,
> > > > bool
> > > > enable)  {
> > > > -	if (enable) {
> > > > -		/* power up core phy and enable ref clock */
> > > > -		regmap_clear_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
> > > IMX6Q_GPR1_PCIE_TEST_PD);
> > > > -		/*
> > > > -		 * The async reset input need ref clock to sync internally,
> > > > -		 * when the ref clock comes after reset, internal synced
> > > > -		 * reset time is too short, cannot meet the requirement.
> > > > -		 * Add a ~10us delay here.
> > > > -		 */
> > > > -		usleep_range(10, 100);
> > > > -		regmap_set_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
> > > IMX6Q_GPR1_PCIE_REF_CLK_EN);
> > > > -	} else {
> > > > -		regmap_clear_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
> > > IMX6Q_GPR1_PCIE_REF_CLK_EN);
> > > > -		regmap_set_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
> > > IMX6Q_GPR1_PCIE_TEST_PD);
> > > > -	}
> > > > +	if (enable)
> > > > +		regmap_set_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
> > > > +				IMX6Q_GPR1_PCIE_REF_CLK_EN);
> > > > +	else
> > > > +		regmap_clear_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
> > > > +				  IMX6Q_GPR1_PCIE_REF_CLK_EN);
> > > >
> > > >  	return 0;
> > > >  }
> > > > @@ -823,23 +814,25 @@ static int imx6sx_pcie_core_reset(struct
> > > > imx_pcie
> > > *imx_pcie, bool assert)
> > > >  	return 0;
> > > >  }
> > > >
> > > > -static int imx6qp_pcie_core_reset(struct imx_pcie *imx_pcie, bool
> > > > assert)
> > > > +static int imx6q_pcie_core_reset(struct imx_pcie *imx_pcie, bool
> > > > +assert)
> > > >  {
> > > > -	regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
> > > IMX6Q_GPR1_PCIE_SW_RST,
> > > > -			   assert ? IMX6Q_GPR1_PCIE_SW_RST : 0);
> > > > -	if (!assert)
> > > > -		usleep_range(200, 500);
> > > > +	if (assert)
> > > > +		regmap_set_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
> > > > +				IMX6Q_GPR1_PCIE_TEST_PD);
> > > > +	else
> > > > +		regmap_clear_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
> > > > +				  IMX6Q_GPR1_PCIE_TEST_PD);
> > > >
> > > >  	return 0;
> > > >  }
> > > >
> > > > -static int imx6q_pcie_core_reset(struct imx_pcie *imx_pcie, bool
> > > > assert)
> > > > +static int imx6qp_pcie_core_reset(struct imx_pcie *imx_pcie, bool
> > > > +assert)
> > > >  {
> > > > +	imx6q_pcie_core_reset(imx_pcie, assert);
> > > > +	regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
> > > IMX6Q_GPR1_PCIE_SW_RST,
> > > > +			   assert ? IMX6Q_GPR1_PCIE_SW_RST : 0);
> > > >  	if (!assert)
> > > > -		return 0;
> > > > -
> > > > -	regmap_set_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
> > > IMX6Q_GPR1_PCIE_TEST_PD);
> > > > -	regmap_set_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
> > > IMX6Q_GPR1_PCIE_REF_CLK_EN);
> > > > +		usleep_range(200, 500);
> > > >
> > > >  	return 0;
> > > >  }
> > > > @@ -1445,6 +1438,7 @@ static int imx_pcie_host_init(struct dw_pcie_rp
> *pp)
> > > >  	return 0;
> > > >
> > > >  err_phy_off:
> > > > +	imx_pcie_assert_core_reset(imx_pcie);
> > > >  	phy_power_off(imx_pcie->phy);
> > > >  err_phy_exit:
> > > >  	phy_exit(imx_pcie->phy);
> > > > @@ -1471,6 +1465,7 @@ static void imx_pcie_host_exit(struct
> > > > dw_pcie_rp
> > > *pp)
> > > >  			dev_err(pci->dev, "unable to power off PHY\n");
> > > >  		phy_exit(imx_pcie->phy);
> > > >  	}
> > > > +	imx_pcie_assert_core_reset(imx_pcie);
> > > >  	imx_pcie_clk_disable(imx_pcie);
> > > >
> > > >  	pci_pwrctrl_power_off_devices(pci->dev);
> > > > --
> > > > 2.34.1
> > > >
> > >
> > > --
> > > மணிவண்ணன் சதாசிவம்

^ permalink raw reply

* [PATCH v9 03/16] KVM: arm64: PMU: Freeze counter count after first run
From: Akihiko Odaki @ 2026-07-20  5:37 UTC (permalink / raw)
  To: Marc Zyngier, Oliver Upton, Joey Gouly, Suzuki K Poulose,
	Zenghui Yu, Catalin Marinas, Will Deacon, Kees Cook,
	Gustavo A. R. Silva, Paolo Bonzini, Jonathan Corbet, Shuah Khan,
	Shuah Khan, Yury Norov, Rasmus Villemoes, Steffen Eiden
  Cc: linux-arm-kernel, kvmarm, linux-kernel, linux-hardening, devel,
	kvm, linux-doc, linux-kselftest, Akihiko Odaki
In-Reply-To: <20260720-hybrid-v9-0-2b713ca1b5dc@rsg.ci.i.u-tokyo.ac.jp>

PMU configuration is VM-scoped, but SET_NR_COUNTERS can be issued
through any vCPU. Checking only whether that vCPU's PMU has been
initialized allows userspace to change the counter count through an idle
sibling after another vCPU has run.

Reject the attribute once any vCPU has run. This keeps the VM-wide
implemented counter mask and the PMCR_EL0.N value stable after guest
execution begins.

Fixes: b7628c797376 ("KVM: arm64: Allow userspace to limit the number of PMU counters for EL2 VMs")
Assisted-by: Codex:gpt-5.6-sol
Signed-off-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
---
 arch/arm64/kvm/pmu-emul.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c
index b5df6843dbcd..b4b877f31097 100644
--- a/arch/arm64/kvm/pmu-emul.c
+++ b/arch/arm64/kvm/pmu-emul.c
@@ -1087,6 +1087,9 @@ static int kvm_arm_pmu_v3_set_nr_counters(struct kvm_vcpu *vcpu, unsigned int n)
 {
 	struct kvm *kvm = vcpu->kvm;
 
+	if (kvm_vm_has_ran_once(kvm))
+		return -EBUSY;
+
 	if (!kvm->arch.arm_pmu)
 		return -EINVAL;
 

-- 
2.55.0



^ permalink raw reply related

* Re: [PATCH v2 7/7] soc: mediatek: mtk-mmsys: Add resets for mt8167
From: Krzysztof Kozlowski @ 2026-07-20  6:30 UTC (permalink / raw)
  To: Luca Leonardo Scorcia
  Cc: linux-mediatek, Wim Van Sebroeck, Guenter Roeck, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Philipp Zabel, linux-watchdog,
	devicetree, linux-kernel, linux-arm-kernel
In-Reply-To: <20260717163959.714561-8-l.scorcia@gmail.com>

On Fri, Jul 17, 2026 at 06:39:18PM +0200, Luca Leonardo Scorcia wrote:
> The mt8167 SoC has 64 MMSYS resets, split in two contiguous 32-bits
> registers, MMSYS_SW0_RST_B (0x140) and MMSYS_SW1_RST_B (0x144), as
> also stated in the downstream kernel for the Lenovo Smart Clock
> in the ddp_reg.h header.
> 
> Signed-off-by: Luca Leonardo Scorcia <l.scorcia@gmail.com>
> ---
>  drivers/soc/mediatek/mt8167-mmsys.h | 41 +++++++++++++++++++++++++++++
>  drivers/soc/mediatek/mtk-mmsys.c    |  3 +++
>  2 files changed, 44 insertions(+)
> 
> diff --git a/drivers/soc/mediatek/mt8167-mmsys.h b/drivers/soc/mediatek/mt8167-mmsys.h
> index eef14083c47b..dc3e882a9893 100644
> --- a/drivers/soc/mediatek/mt8167-mmsys.h
> +++ b/drivers/soc/mediatek/mt8167-mmsys.h
> @@ -3,6 +3,47 @@
>  #ifndef __SOC_MEDIATEK_MT8167_MMSYS_H
>  #define __SOC_MEDIATEK_MT8167_MMSYS_H
>  
> +#include <linux/soc/mediatek/mtk-mmsys.h>
> +#include <dt-bindings/reset/mediatek,mt8167-resets.h>
> +
> +#define MT8167_MMSYS_SW0_RST_B				0x140
> +#define MT8167_MMSYS_SW1_RST_B				0x144
> +
> +/* MMSYS resets */
> +static const u8 mmsys_mt8167_rst_tb[] = {

No, data structures NEVER go to the headers because it leads easily to
duplicated data.

Best regards,
Krzysztof



^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox