summaryrefslogtreecommitdiff
path: root/include/linux/intel-svm.h
blob: d7c403d0dd27d84ecdc8d8b094739e32b85968e2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright © 2015 Intel Corporation.
 *
 * Authors: David Woodhouse <David.Woodhouse@intel.com>
 */

#ifndef __INTEL_SVM_H__
#define __INTEL_SVM_H__

struct device;

struct svm_dev_ops {
	void (*fault_cb)(struct device *dev, int pasid, u64 address,
			 void *private, int rwxp, int response);
};

/* Values for rxwp in fault_cb callback */
#define SVM_REQ_READ	(1<<3)
#define SVM_REQ_WRITE	(1<<2)
#define SVM_REQ_EXEC	(1<<1)
#define SVM_REQ_PRIV	(1<<0)


/*
 * The SVM_FLAG_PRIVATE_PASID flag requests a PASID which is *not* the "main"
 * PASID for the current process. Even if a PASID already exists, a new one
 * will be allocated. And the PASID allocated with SVM_FLAG_PRIVATE_PASID
 * will not be given to subsequent callers. This facility allows a driver to
 * disambiguate between multiple device contexts which access the same MM,
 * if there is no other way to do so. It should be used sparingly, if at all.
 */
#define SVM_FLAG_PRIVATE_PASID		(1<<0)

/*
 * The SVM_FLAG_SUPERVISOR_MODE flag requests a PASID which can be used only
 * for access to kernel addresses. No IOTLB flushes are automatically done
 * for kernel mappings; it is valid only for access to the kernel's static
 * 1:1 mapping of physical memory — not to vmalloc or even module mappings.
 * A future API addition may permit the use of such ranges, by means of an
 * explicit IOTLB flush call (akin to the DMA API's unmap method).
 *
 * It is unlikely that we will ever hook into flush_tlb_kernel_range() to
 * do such IOTLB flushes automatically.
 */
#define SVM_FLAG_SUPERVISOR_MODE	(1<<1)

#ifdef CONFIG_INTEL_IOMMU_SVM

/**
 * intel_svm_bind_mm() - Bind the current process to a PASID
 * @dev:	Device to be granted access
 * @pasid:	Address for allocated PASID
 * @flags:	Flags. Later for requesting supervisor mode, etc.
 * @ops:	Callbacks to device driver
 *
 * This function attempts to enable PASID support for the given device.
 * If the @pasid argument is non-%NULL, a PASID is allocated for access
 * to the MM of the current process.
 *
 * By using a %NULL value for the @pasid argument, this function can
 * be used to simply validate that PASID support is available for the
 * given device — i.e. that it is behind an IOMMU which has the
 * requisite support, and is enabled.
 *
 * Page faults are handled transparently by the IOMMU code, and there
 * should be no need for the device driver to be involved. If a page
 * fault cannot be handled (i.e. is an invalid address rather than
 * just needs paging in), then the page request will be completed by
 * the core IOMMU code with appropriate status, and the device itself
 * can then report the resulting fault to its driver via whatever
 * mechanism is appropriate.
 *
 * Multiple calls from the same process may result in the same PASID
 * being re-used. A reference count is kept.
 */
extern int intel_svm_bind_mm(struct device *dev, int *pasid, int flags,
			     struct svm_dev_ops *ops);

/**
 * intel_svm_unbind_mm() - Unbind a specified PASID
 * @dev:	Device for which PASID was allocated
 * @pasid:	PASID value to be unbound
 *
 * This function allows a PASID to be retired when the device no
 * longer requires access to the address space of a given process.
 *
 * If the use count for the PASID in question reaches zero, the
 * PASID is revoked and may no longer be used by hardware.
 *
 * Device drivers are required to ensure that no access (including
 * page requests) is currently outstanding for the PASID in question,
 * before calling this function.
 */
extern int intel_svm_unbind_mm(struct device *dev, int pasid);

/**
 * intel_svm_is_pasid_valid() - check if pasid is valid
 * @dev:	Device for which PASID was allocated
 * @pasid:	PASID value to be checked
 *
 * This function checks if the specified pasid is still valid. A
 * valid pasid means the backing mm is still having a valid user.
 * For kernel callers init_mm is always valid. for other mm, if mm->mm_users
 * is non-zero, it is valid.
 *
 * returns -EINVAL if invalid pasid, 0 if pasid ref count is invalid
 * 1 if pasid is valid.
 */
extern int intel_svm_is_pasid_valid(struct device *dev, int pasid);

#else /* CONFIG_INTEL_IOMMU_SVM */

static inline int intel_svm_bind_mm(struct device *dev, int *pasid,
				    int flags, struct svm_dev_ops *ops)
{
	return -ENOSYS;
}

static inline int intel_svm_unbind_mm(struct device *dev, int pasid)
{
	BUG();
}

static inline int intel_svm_is_pasid_valid(struct device *dev, int pasid)
{
	return -EINVAL;
}
#endif /* CONFIG_INTEL_IOMMU_SVM */

#define intel_svm_available(dev) (!intel_svm_bind_mm((dev), NULL, 0, NULL))

#endif /* __INTEL_SVM_H__ */