anolis-cloud-kernel/include/linux/ioasid.h

338 lines
8.8 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __LINUX_IOASID_H
#define __LINUX_IOASID_H
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/xarray.h>
#include <linux/refcount.h>
#include <uapi/linux/ioasid.h>
#define INVALID_IOASID ((ioasid_t)-1)
#define IOASID_DMA_NO_PASID 0 /* For DMA request w/o PASID */
#define IOASID_ALLOC_BASE 1 /* Start of the allocation */
typedef unsigned int ioasid_t;
typedef ioasid_t (*ioasid_alloc_fn_t)(ioasid_t min, ioasid_t max, void *data);
typedef void (*ioasid_free_fn_t)(ioasid_t ioasid, void *data);
/* IOASID set types */
enum ioasid_set_type {
IOASID_SET_TYPE_NULL = 1, /* Set token is NULL */
IOASID_SET_TYPE_MM, /* Set token is a mm_struct pointer
* i.e. associated with a process
*/
IOASID_SET_TYPE_NR,
};
/**
* struct ioasid_set - Meta data about ioasid_set
* @nh: List of notifiers private to that set
* @xa: XArray to store ioasid_set private IDs, can be used for
* guest-host IOASID mapping, or just a private IOASID namespace.
* @token: Unique to identify an IOASID set
* @type: Token types
* @quota: Max number of IOASIDs can be allocated within the set
* @nr_ioasids: Number of IOASIDs currently allocated in the set
* @id: ID of the set
*/
struct ioasid_set {
struct atomic_notifier_head nh;
struct xarray xa;
void *token;
int type;
int quota;
atomic_t nr_ioasids;
int id;
bool free_pending;
struct rcu_head rcu;
};
/**
* struct ioasid_allocator_ops - IOASID allocator helper functions and data
*
* @alloc: helper function to allocate IOASID
* @free: helper function to free IOASID
* @list: for tracking ops that share helper functions but not data
* @pdata: data belong to the allocator, provided when calling alloc()
*/
struct ioasid_allocator_ops {
ioasid_alloc_fn_t alloc;
ioasid_free_fn_t free;
struct list_head list;
void *pdata;
};
/* Notification data when IOASID status changed */
enum ioasid_notify_val {
IOASID_NOTIFY_ALLOC = 1,
IOASID_NOTIFY_FREE,
IOASID_NOTIFY_BIND,
IOASID_NOTIFY_UNBIND,
};
#define IOASID_NOTIFY_FLAG_ALL BIT(0)
#define IOASID_NOTIFY_FLAG_SET BIT(1)
/**
* enum ioasid_notifier_prios - IOASID event notification order
*
* When status of an IOASID changes, users might need to take actions to
* reflect the new state. For example, when an IOASID is freed due to
* exception, the hardware context in virtual CPU, DMA device, and IOMMU
* shall be cleared and drained. Order is required to prevent life cycle
* problems.
*/
enum ioasid_notifier_prios {
IOASID_PRIO_LAST,
IOASID_PRIO_DEVICE,
IOASID_PRIO_IOMMU,
IOASID_PRIO_CPU,
};
/**
* struct ioasid_nb_args - Argument provided by IOASID core when notifier
* is called.
* @id: The IOASID being notified
* @spid: The set private ID associated with the IOASID
* @set: The IOASID set of @id
* @pdata: The private data attached to the IOASID
*/
struct ioasid_nb_args {
ioasid_t id;
ioasid_t spid;
struct ioasid_set *set;
void *pdata;
};
extern struct ioasid_set *host_pasid_set;
#if IS_ENABLED(CONFIG_IOASID)
void ioasid_install_capacity(ioasid_t total);
int ioasid_reserve_capacity(ioasid_t nr_ioasid);
int ioasid_cancel_capacity(ioasid_t nr_ioasid);
struct ioasid_set *ioasid_set_alloc(void *token, ioasid_t quota, int type);
int ioasid_set_free(struct ioasid_set *set);
struct ioasid_set *ioasid_find_mm_set(struct mm_struct *token);
ioasid_t ioasid_alloc(struct ioasid_set *set, ioasid_t min, ioasid_t max,
void *private);
int ioasid_get(struct ioasid_set *set, ioasid_t ioasid);
int ioasid_get_locked(struct ioasid_set *set, ioasid_t ioasid);
int ioasid_get_if_owned(ioasid_t ioasid);
bool ioasid_put(struct ioasid_set *set, ioasid_t ioasid);
bool ioasid_put_locked(struct ioasid_set *set, ioasid_t ioasid);
void ioasid_free(struct ioasid_set *set, ioasid_t ioasid);
void ioasid_free_all_in_set(struct ioasid_set *set);
void *ioasid_find(struct ioasid_set *set, ioasid_t ioasid,
bool (*getter)(void *));
struct ioasid_set *ioasid_find_set(ioasid_t ioasid);
int ioasid_register_allocator(struct ioasid_allocator_ops *allocator);
void ioasid_unregister_allocator(struct ioasid_allocator_ops *allocator);
int ioasid_attach_data(ioasid_t ioasid, void *data);
void ioasid_detach_data(ioasid_t ioasid);
int ioasid_attach_spid(ioasid_t ioasid, ioasid_t spid);
void ioasid_detach_spid(ioasid_t ioasid);
ioasid_t ioasid_find_by_spid(struct ioasid_set *set, ioasid_t spid, bool get);
int ioasid_register_notifier(struct ioasid_set *set,
struct notifier_block *nb);
void ioasid_unregister_notifier(struct ioasid_set *set,
struct notifier_block *nb);
void ioasid_set_for_each_ioasid(struct ioasid_set *sdata,
void (*fn)(ioasid_t id, void *data),
void *data);
int ioasid_register_notifier_mm(struct mm_struct *mm, struct notifier_block *nb);
void ioasid_unregister_notifier_mm(struct mm_struct *mm, struct notifier_block *nb);
#ifdef CONFIG_CGROUP_IOASIDS
int ioasid_cg_charge(struct ioasid_set *set);
void ioasid_cg_uncharge(struct ioasid_set *set);
#else
/* No cgroup control, allocation will proceed until run out total pool */
static inline int ioasid_cg_charge(struct ioasid_set *set)
{
return 0;
}
static inline int ioasid_cg_uncharge(struct ioasid_set *set)
{
return 0;
}
#endif /* CGROUP_IOASIDS */
bool ioasid_queue_work(struct work_struct *work);
static inline bool pasid_valid(ioasid_t ioasid)
{
return ioasid != INVALID_IOASID;
}
/* IOASID userspace support */
struct ioasid_user;
#if IS_ENABLED(CONFIG_IOASID_USER)
extern struct ioasid_user *ioasid_user_get_from_task(struct task_struct *task);
extern void ioasid_user_put(struct ioasid_user *iuser);
extern void ioasid_user_for_each_id(struct ioasid_user *iuser, void *data,
void (*fn)(ioasid_t id, void *data));
extern struct ioasid_set *host_pasid_set;
#else /* CONFIG_IOASID_USER */
static inline struct ioasid_user *
ioasid_user_get_from_task(struct task_struct *task)
{
return ERR_PTR(-ENOTTY);
}
static inline void ioasid_user_put(struct ioasid_user *iuser)
{
}
static inline void ioasid_user_for_each_id(struct ioasid_user *iuser, void *data,
void (*fn)(ioasid_t id, void *data))
{
}
#endif /* CONFIG_IOASID_USER */
#else /* !CONFIG_IOASID */
static inline void ioasid_install_capacity(ioasid_t total)
{
}
static inline int ioasid_reserve_capacity(ioasid_t nr_ioasid)
{
return -ENOSPC;
}
static inline int ioasid_cancel_capacity(ioasid_t nr_ioasid)
{
return -EINVAL;
}
static inline ioasid_t ioasid_alloc(struct ioasid_set *set, ioasid_t min,
ioasid_t max, void *private)
{
return INVALID_IOASID;
}
static inline struct ioasid_set *ioasid_set_alloc(void *token, ioasid_t quota,
int type)
{
return ERR_PTR(-ENOTSUPP);
}
static inline void ioasid_free(struct ioasid_set *set, ioasid_t ioasid)
{
}
static inline struct ioasid_set *ioasid_find_mm_set(struct mm_struct *token)
{
return NULL;
}
static inline int ioasid_get(struct ioasid_set *set, ioasid_t ioasid)
{
return -ENOTSUPP;
}
static inline int ioasid_get_locked(struct ioasid_set *set, ioasid_t ioasid)
{
return -ENOTSUPP;
}
static inline int ioasid_get_if_owned(ioasid_t ioasid)
{
return -ENOTSUPP;
}
static inline bool ioasid_put(struct ioasid_set *set, ioasid_t ioasid)
{
return false;
}
static inline bool ioasid_put_locked(struct ioasid_set *set, ioasid_t ioasid)
{
return false;
}
static inline void *ioasid_find(struct ioasid_set *set, ioasid_t ioasid,
bool (*getter)(void *))
{
return NULL;
}
static inline int ioasid_register_notifier(struct notifier_block *nb)
{
return -ENOTSUPP;
}
static inline void ioasid_unregister_notifier(struct notifier_block *nb)
{
}
static inline int ioasid_register_allocator(struct ioasid_allocator_ops *allocator)
{
return -ENOTSUPP;
}
static inline void ioasid_unregister_allocator(struct ioasid_allocator_ops *allocator)
{
}
static inline int ioasid_attach_data(ioasid_t ioasid, void *data)
{
return -ENOTSUPP;
}
static inline bool pasid_valid(ioasid_t ioasid)
{
return false;
}
static inline void ioasid_detach_data(ioasid_t ioasid)
{
}
static inline void ioasid_free_all_in_set(struct ioasid_set *set)
{
}
static inline struct ioasid_set *ioasid_find_set(ioasid_t ioasid)
{
return ERR_PTR(-ENOTSUPP);
}
static inline int ioasid_attach_spid(ioasid_t ioasid, ioasid_t spid)
{
return -ENOTSUPP;
}
static inline void ioasid_detach_spid(ioasid_t ioasid)
{
}
static inline ioasid_t ioasid_find_by_spid(struct ioasid_set *set,
ioasid_t spid, bool get)
{
return INVALID_IOASID;
}
static inline void ioasid_set_for_each_ioasid(struct ioasid_set *sdata,
void (*fn)(ioasid_t id, void *data),
void *data)
{
}
static inline int ioasid_register_notifier_mm(struct mm_struct *mm,
struct notifier_block *nb)
{
return -ENOTSUPP;
}
static inline void ioasid_unregister_notifier_mm(struct mm_struct *mm,
struct notifier_block *nb)
{
}
static inline bool ioasid_queue_work(struct work_struct *work)
{
return false;
}
#endif /* CONFIG_IOASID */
#endif /* __LINUX_IOASID_H */