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

drm/xe: Add locks in gtidle code

The update of the residency values needs to be protected by a lock to
avoid multiple entrypoints, for example when multiple userspace clients
read the sysfs file. Other in-kernel clients are going to be added to
sample these values, making the problem worse. Protect those updates
with a raw_spinlock so it can be called by future integration with perf
pmu.

Suggested-by: Lucas De Marchi <lucas.demarchi@intel.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Lucas De Marchi <lucas.demarchi@intel.com>
Signed-off-by: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
Reviewed-by: Lucas De Marchi <lucas.demarchi@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20250110173308.2412232-2-lucas.demarchi@intel.com
Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>

authored by

Vinay Belgaumkar and committed by
Lucas De Marchi
d160dc6f c26f22da

+24 -3
+20 -3
drivers/gpu/drm/xe/xe_gt_idle.c
··· 69 69 { 70 70 u64 delta, overflow_residency, prev_residency; 71 71 72 + lockdep_assert_held(&gtidle->lock); 73 + 72 74 overflow_residency = BIT_ULL(32); 73 75 74 76 /* ··· 277 275 278 276 return sysfs_emit(buff, "%s\n", gt_idle_state_to_string(state)); 279 277 } 280 - static DEVICE_ATTR_RO(idle_status); 281 278 279 + u64 xe_gt_idle_residency_msec(struct xe_gt_idle *gtidle) 280 + { 281 + struct xe_guc_pc *pc = gtidle_to_pc(gtidle); 282 + u64 residency; 283 + unsigned long flags; 284 + 285 + raw_spin_lock_irqsave(&gtidle->lock, flags); 286 + residency = get_residency_ms(gtidle, gtidle->idle_residency(pc)); 287 + raw_spin_unlock_irqrestore(&gtidle->lock, flags); 288 + 289 + return residency; 290 + } 291 + 292 + static DEVICE_ATTR_RO(idle_status); 282 293 static ssize_t idle_residency_ms_show(struct device *dev, 283 294 struct device_attribute *attr, char *buff) 284 295 { ··· 300 285 u64 residency; 301 286 302 287 xe_pm_runtime_get(pc_to_xe(pc)); 303 - residency = gtidle->idle_residency(pc); 288 + residency = xe_gt_idle_residency_msec(gtidle); 304 289 xe_pm_runtime_put(pc_to_xe(pc)); 305 290 306 - return sysfs_emit(buff, "%llu\n", get_residency_ms(gtidle, residency)); 291 + return sysfs_emit(buff, "%llu\n", residency); 307 292 } 308 293 static DEVICE_ATTR_RO(idle_residency_ms); 309 294 ··· 345 330 kobj = kobject_create_and_add("gtidle", gt->sysfs); 346 331 if (!kobj) 347 332 return -ENOMEM; 333 + 334 + raw_spin_lock_init(&gtidle->lock); 348 335 349 336 if (xe_gt_is_media_type(gt)) { 350 337 snprintf(gtidle->name, sizeof(gtidle->name), "gt%d-mc", gt->info.id);
+1
drivers/gpu/drm/xe/xe_gt_idle.h
··· 17 17 void xe_gt_idle_enable_pg(struct xe_gt *gt); 18 18 void xe_gt_idle_disable_pg(struct xe_gt *gt); 19 19 int xe_gt_idle_pg_print(struct xe_gt *gt, struct drm_printer *p); 20 + u64 xe_gt_idle_residency_msec(struct xe_gt_idle *gtidle); 20 21 21 22 #endif /* _XE_GT_IDLE_H_ */
+3
drivers/gpu/drm/xe/xe_gt_idle_types.h
··· 6 6 #ifndef _XE_GT_IDLE_SYSFS_TYPES_H_ 7 7 #define _XE_GT_IDLE_SYSFS_TYPES_H_ 8 8 9 + #include <linux/spinlock.h> 9 10 #include <linux/types.h> 10 11 11 12 struct xe_guc_pc; ··· 32 31 u64 cur_residency; 33 32 /** @prev_residency: previous residency counter */ 34 33 u64 prev_residency; 34 + /** @lock: Lock protecting idle residency counters */ 35 + raw_spinlock_t lock; 35 36 /** @idle_status: get the current idle state */ 36 37 enum xe_gt_idle_state (*idle_status)(struct xe_guc_pc *pc); 37 38 /** @idle_residency: get idle residency counter */