mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-22 07:27:12 +08:00
Some driver components, like eudebug or ccs-mode, can't be used when VFs are enabled. Add functions to allow those components to block the PF from enabling VFs for the requested duration. Introduce trivial counter to allow lockdown or exclusive access that can be used in the scenarios where we can't follow the strict owner semantics as required by the rw_semaphore implementation. Before enabling VFs, the PF will try to arm the "vfs_enabling" guard for the exclusive access. This will fail if there are some lockdown requests already initiated by the other components. For testing purposes, add debugfs file which will call these new functions from the file's open/close hooks. Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com> Cc: Matthew Brost <matthew.brost@intel.com> Cc: Christoph Manszewski <christoph.manszewski@intel.com> Reviewed-by: Christoph Manszewski <christoph.manszewski@intel.com> Link: https://patch.msgid.link/20251109162451.4779-1-michal.wajdeczko@intel.com
120 lines
3.0 KiB
C
120 lines
3.0 KiB
C
/* SPDX-License-Identifier: MIT */
|
|
/*
|
|
* Copyright © 2025 Intel Corporation
|
|
*/
|
|
|
|
#ifndef _XE_GUARD_H_
|
|
#define _XE_GUARD_H_
|
|
|
|
#include <linux/spinlock.h>
|
|
|
|
/**
|
|
* struct xe_guard - Simple logic to protect a feature.
|
|
*
|
|
* Implements simple semaphore-like logic that can be used to lockdown the
|
|
* feature unless it is already in use. Allows enabling of the otherwise
|
|
* incompatible features, where we can't follow the strict owner semantics
|
|
* required by the &rw_semaphore.
|
|
*
|
|
* NOTE! It shouldn't be used to protect a data, use &rw_semaphore instead.
|
|
*/
|
|
struct xe_guard {
|
|
/**
|
|
* @counter: implements simple exclusive/lockdown logic:
|
|
* if == 0 then guard/feature is idle/not in use,
|
|
* if < 0 then feature is active and can't be locked-down,
|
|
* if > 0 then feature is lockded-down and can't be activated.
|
|
*/
|
|
int counter;
|
|
|
|
/** @name: the name of the guard (useful for debug) */
|
|
const char *name;
|
|
|
|
/** @owner: the info about the last owner of the guard (for debug) */
|
|
void *owner;
|
|
|
|
/** @lock: protects guard's data */
|
|
spinlock_t lock;
|
|
};
|
|
|
|
/**
|
|
* xe_guard_init() - Initialize the guard.
|
|
* @guard: the &xe_guard to init
|
|
* @name: name of the guard
|
|
*/
|
|
static inline void xe_guard_init(struct xe_guard *guard, const char *name)
|
|
{
|
|
spin_lock_init(&guard->lock);
|
|
guard->counter = 0;
|
|
guard->name = name;
|
|
}
|
|
|
|
/**
|
|
* xe_guard_arm() - Arm the guard for the exclusive/lockdown mode.
|
|
* @guard: the &xe_guard to arm
|
|
* @lockdown: arm for lockdown(true) or exclusive(false) mode
|
|
* @who: optional owner info (for debug only)
|
|
*
|
|
* Multiple lockdown requests are allowed.
|
|
* Only single exclusive access can be granted.
|
|
* Will fail if the guard is already in exclusive mode.
|
|
* On success, must call the xe_guard_disarm() to release.
|
|
*
|
|
* Return: 0 on success or a negative error code on failure.
|
|
*/
|
|
static inline int xe_guard_arm(struct xe_guard *guard, bool lockdown, void *who)
|
|
{
|
|
guard(spinlock)(&guard->lock);
|
|
|
|
if (lockdown) {
|
|
if (guard->counter < 0)
|
|
return -EBUSY;
|
|
guard->counter++;
|
|
} else {
|
|
if (guard->counter > 0)
|
|
return -EPERM;
|
|
if (guard->counter < 0)
|
|
return -EUSERS;
|
|
guard->counter--;
|
|
}
|
|
|
|
guard->owner = who;
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* xe_guard_disarm() - Disarm the guard from exclusive/lockdown mode.
|
|
* @guard: the &xe_guard to disarm
|
|
* @lockdown: disarm from lockdown(true) or exclusive(false) mode
|
|
*
|
|
* Return: true if successfully disarmed or false in case of mismatch.
|
|
*/
|
|
static inline bool xe_guard_disarm(struct xe_guard *guard, bool lockdown)
|
|
{
|
|
guard(spinlock)(&guard->lock);
|
|
|
|
if (lockdown) {
|
|
if (guard->counter <= 0)
|
|
return false;
|
|
guard->counter--;
|
|
} else {
|
|
if (guard->counter != -1)
|
|
return false;
|
|
guard->counter++;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* xe_guard_mode_str() - Convert guard mode into a string.
|
|
* @lockdown: flag used to select lockdown or exclusive mode
|
|
*
|
|
* Return: "lockdown" or "exclusive" string.
|
|
*/
|
|
static inline const char *xe_guard_mode_str(bool lockdown)
|
|
{
|
|
return lockdown ? "lockdown" : "exclusive";
|
|
}
|
|
|
|
#endif
|