Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

coresight: Change device mode to atomic type

The device mode is defined as local type. This type cannot promise
SMP-safe access.

Change to atomic type and impose relax ordering, which ensures the
SMP-safe synchronisation and the ordering between the mode setting and
relevant operations.

Fixes: 22fd532eaa0c ("coresight: etm3x: adding operation mode for etm_enable()")
Reviewed-by: Mike Leach <mike.leach@linaro.org>
Tested-by: James Clark <james.clark@linaro.org>
Signed-off-by: Leo Yan <leo.yan@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Link: https://lore.kernel.org/r/20251111-arm_coresight_power_management_fix-v6-1-f55553b6c8b3@arm.com

authored by

Leo Yan and committed by
Suzuki K Poulose
693d1eac b139702a

+11 -14
+11 -14
include/linux/coresight.h
··· 251 251 * by @coresight_ops. 252 252 * @access: Device i/o access abstraction for this device. 253 253 * @dev: The device entity associated to this component. 254 - * @mode: This tracer's mode, i.e sysFS, Perf or disabled. This is 255 - * actually an 'enum cs_mode', but is stored in an atomic type. 256 - * This is always accessed through local_read() and local_set(), 257 - * but wherever it's done from within the Coresight device's lock, 258 - * a non-atomic read would also work. This is the main point of 259 - * synchronisation between code happening inside the sysfs mode's 260 - * coresight_mutex and outside when running in Perf mode. A compare 261 - * and exchange swap is done to atomically claim one mode or the 262 - * other. 254 + * @mode: The device mode, i.e sysFS, Perf or disabled. This is actually 255 + * an 'enum cs_mode' but stored in an atomic type. Access is always 256 + * through atomic APIs, ensuring SMP-safe synchronisation between 257 + * racing from sysFS and Perf mode. A compare-and-exchange 258 + * operation is done to atomically claim one mode or the other. 263 259 * @refcnt: keep track of what is in use. Only access this outside of the 264 260 * device's spinlock when the coresight_mutex held and mode == 265 261 * CS_MODE_SYSFS. Otherwise it must be accessed from inside the ··· 284 288 const struct coresight_ops *ops; 285 289 struct csdev_access access; 286 290 struct device dev; 287 - local_t mode; 291 + atomic_t mode; 288 292 int refcnt; 289 293 bool orphan; 290 294 /* sink specific fields */ ··· 620 624 static inline bool coresight_take_mode(struct coresight_device *csdev, 621 625 enum cs_mode new_mode) 622 626 { 623 - return local_cmpxchg(&csdev->mode, CS_MODE_DISABLED, new_mode) == 624 - CS_MODE_DISABLED; 627 + int curr = CS_MODE_DISABLED; 628 + 629 + return atomic_try_cmpxchg_acquire(&csdev->mode, &curr, new_mode); 625 630 } 626 631 627 632 static inline enum cs_mode coresight_get_mode(struct coresight_device *csdev) 628 633 { 629 - return local_read(&csdev->mode); 634 + return atomic_read_acquire(&csdev->mode); 630 635 } 631 636 632 637 static inline void coresight_set_mode(struct coresight_device *csdev, ··· 643 646 WARN(new_mode != CS_MODE_DISABLED && current_mode != CS_MODE_DISABLED && 644 647 current_mode != new_mode, "Device already in use\n"); 645 648 646 - local_set(&csdev->mode, new_mode); 649 + atomic_set_release(&csdev->mode, new_mode); 647 650 } 648 651 649 652 struct coresight_device *coresight_register(struct coresight_desc *desc);