Skip to content

Commit bbf4ee2

Browse files
committed
Merge tag 'drm-intel-fixes-2020-04-15' of git://anongit.freedesktop.org/drm/drm-intel into drm-fixes
- Fix guest page access by using the brand new VFIO dma r/w interface (Yan) - Fix for i915 perf read buffers (Ashutosh) Signed-off-by: Dave Airlie <[email protected]> From: Rodrigo Vivi <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
2 parents 8f3d9f3 + 5809e8f commit bbf4ee2

File tree

2 files changed

+33
-78
lines changed

2 files changed

+33
-78
lines changed

drivers/gpu/drm/i915/gvt/kvmgt.c

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ struct kvmgt_vdev {
131131
struct work_struct release_work;
132132
atomic_t released;
133133
struct vfio_device *vfio_device;
134+
struct vfio_group *vfio_group;
134135
};
135136

136137
static inline struct kvmgt_vdev *kvmgt_vdev(struct intel_vgpu *vgpu)
@@ -151,6 +152,7 @@ static void gvt_unpin_guest_page(struct intel_vgpu *vgpu, unsigned long gfn,
151152
unsigned long size)
152153
{
153154
struct drm_i915_private *i915 = vgpu->gvt->gt->i915;
155+
struct kvmgt_vdev *vdev = kvmgt_vdev(vgpu);
154156
int total_pages;
155157
int npage;
156158
int ret;
@@ -160,7 +162,7 @@ static void gvt_unpin_guest_page(struct intel_vgpu *vgpu, unsigned long gfn,
160162
for (npage = 0; npage < total_pages; npage++) {
161163
unsigned long cur_gfn = gfn + npage;
162164

163-
ret = vfio_unpin_pages(mdev_dev(kvmgt_vdev(vgpu)->mdev), &cur_gfn, 1);
165+
ret = vfio_group_unpin_pages(vdev->vfio_group, &cur_gfn, 1);
164166
drm_WARN_ON(&i915->drm, ret != 1);
165167
}
166168
}
@@ -169,6 +171,7 @@ static void gvt_unpin_guest_page(struct intel_vgpu *vgpu, unsigned long gfn,
169171
static int gvt_pin_guest_page(struct intel_vgpu *vgpu, unsigned long gfn,
170172
unsigned long size, struct page **page)
171173
{
174+
struct kvmgt_vdev *vdev = kvmgt_vdev(vgpu);
172175
unsigned long base_pfn = 0;
173176
int total_pages;
174177
int npage;
@@ -183,8 +186,8 @@ static int gvt_pin_guest_page(struct intel_vgpu *vgpu, unsigned long gfn,
183186
unsigned long cur_gfn = gfn + npage;
184187
unsigned long pfn;
185188

186-
ret = vfio_pin_pages(mdev_dev(kvmgt_vdev(vgpu)->mdev), &cur_gfn, 1,
187-
IOMMU_READ | IOMMU_WRITE, &pfn);
189+
ret = vfio_group_pin_pages(vdev->vfio_group, &cur_gfn, 1,
190+
IOMMU_READ | IOMMU_WRITE, &pfn);
188191
if (ret != 1) {
189192
gvt_vgpu_err("vfio_pin_pages failed for gfn 0x%lx, ret %d\n",
190193
cur_gfn, ret);
@@ -792,6 +795,7 @@ static int intel_vgpu_open(struct mdev_device *mdev)
792795
struct kvmgt_vdev *vdev = kvmgt_vdev(vgpu);
793796
unsigned long events;
794797
int ret;
798+
struct vfio_group *vfio_group;
795799

796800
vdev->iommu_notifier.notifier_call = intel_vgpu_iommu_notifier;
797801
vdev->group_notifier.notifier_call = intel_vgpu_group_notifier;
@@ -814,6 +818,14 @@ static int intel_vgpu_open(struct mdev_device *mdev)
814818
goto undo_iommu;
815819
}
816820

821+
vfio_group = vfio_group_get_external_user_from_dev(mdev_dev(mdev));
822+
if (IS_ERR_OR_NULL(vfio_group)) {
823+
ret = !vfio_group ? -EFAULT : PTR_ERR(vfio_group);
824+
gvt_vgpu_err("vfio_group_get_external_user_from_dev failed\n");
825+
goto undo_register;
826+
}
827+
vdev->vfio_group = vfio_group;
828+
817829
/* Take a module reference as mdev core doesn't take
818830
* a reference for vendor driver.
819831
*/
@@ -830,6 +842,10 @@ static int intel_vgpu_open(struct mdev_device *mdev)
830842
return ret;
831843

832844
undo_group:
845+
vfio_group_put_external_user(vdev->vfio_group);
846+
vdev->vfio_group = NULL;
847+
848+
undo_register:
833849
vfio_unregister_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY,
834850
&vdev->group_notifier);
835851

@@ -884,6 +900,7 @@ static void __intel_vgpu_release(struct intel_vgpu *vgpu)
884900
kvmgt_guest_exit(info);
885901

886902
intel_vgpu_release_msi_eventfd_ctx(vgpu);
903+
vfio_group_put_external_user(vdev->vfio_group);
887904

888905
vdev->kvm = NULL;
889906
vgpu->handle = 0;
@@ -2035,33 +2052,14 @@ static int kvmgt_rw_gpa(unsigned long handle, unsigned long gpa,
20352052
void *buf, unsigned long len, bool write)
20362053
{
20372054
struct kvmgt_guest_info *info;
2038-
struct kvm *kvm;
2039-
int idx, ret;
2040-
bool kthread = current->mm == NULL;
20412055

20422056
if (!handle_valid(handle))
20432057
return -ESRCH;
20442058

20452059
info = (struct kvmgt_guest_info *)handle;
2046-
kvm = info->kvm;
2047-
2048-
if (kthread) {
2049-
if (!mmget_not_zero(kvm->mm))
2050-
return -EFAULT;
2051-
use_mm(kvm->mm);
2052-
}
2053-
2054-
idx = srcu_read_lock(&kvm->srcu);
2055-
ret = write ? kvm_write_guest(kvm, gpa, buf, len) :
2056-
kvm_read_guest(kvm, gpa, buf, len);
2057-
srcu_read_unlock(&kvm->srcu, idx);
2058-
2059-
if (kthread) {
2060-
unuse_mm(kvm->mm);
2061-
mmput(kvm->mm);
2062-
}
20632060

2064-
return ret;
2061+
return vfio_dma_rw(kvmgt_vdev(info->vgpu)->vfio_group,
2062+
gpa, buf, len, write);
20652063
}
20662064

20672065
static int kvmgt_read_gpa(unsigned long handle, unsigned long gpa,

drivers/gpu/drm/i915/i915_perf.c

Lines changed: 11 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2940,49 +2940,6 @@ void i915_oa_init_reg_state(const struct intel_context *ce,
29402940
gen8_update_reg_state_unlocked(ce, stream);
29412941
}
29422942

2943-
/**
2944-
* i915_perf_read_locked - &i915_perf_stream_ops->read with error normalisation
2945-
* @stream: An i915 perf stream
2946-
* @file: An i915 perf stream file
2947-
* @buf: destination buffer given by userspace
2948-
* @count: the number of bytes userspace wants to read
2949-
* @ppos: (inout) file seek position (unused)
2950-
*
2951-
* Besides wrapping &i915_perf_stream_ops->read this provides a common place to
2952-
* ensure that if we've successfully copied any data then reporting that takes
2953-
* precedence over any internal error status, so the data isn't lost.
2954-
*
2955-
* For example ret will be -ENOSPC whenever there is more buffered data than
2956-
* can be copied to userspace, but that's only interesting if we weren't able
2957-
* to copy some data because it implies the userspace buffer is too small to
2958-
* receive a single record (and we never split records).
2959-
*
2960-
* Another case with ret == -EFAULT is more of a grey area since it would seem
2961-
* like bad form for userspace to ask us to overrun its buffer, but the user
2962-
* knows best:
2963-
*
2964-
* http://yarchive.net/comp/linux/partial_reads_writes.html
2965-
*
2966-
* Returns: The number of bytes copied or a negative error code on failure.
2967-
*/
2968-
static ssize_t i915_perf_read_locked(struct i915_perf_stream *stream,
2969-
struct file *file,
2970-
char __user *buf,
2971-
size_t count,
2972-
loff_t *ppos)
2973-
{
2974-
/* Note we keep the offset (aka bytes read) separate from any
2975-
* error status so that the final check for whether we return
2976-
* the bytes read with a higher precedence than any error (see
2977-
* comment below) doesn't need to be handled/duplicated in
2978-
* stream->ops->read() implementations.
2979-
*/
2980-
size_t offset = 0;
2981-
int ret = stream->ops->read(stream, buf, count, &offset);
2982-
2983-
return offset ?: (ret ?: -EAGAIN);
2984-
}
2985-
29862943
/**
29872944
* i915_perf_read - handles read() FOP for i915 perf stream FDs
29882945
* @file: An i915 perf stream file
@@ -3008,7 +2965,8 @@ static ssize_t i915_perf_read(struct file *file,
30082965
{
30092966
struct i915_perf_stream *stream = file->private_data;
30102967
struct i915_perf *perf = stream->perf;
3011-
ssize_t ret;
2968+
size_t offset = 0;
2969+
int ret;
30122970

30132971
/* To ensure it's handled consistently we simply treat all reads of a
30142972
* disabled stream as an error. In particular it might otherwise lead
@@ -3031,13 +2989,12 @@ static ssize_t i915_perf_read(struct file *file,
30312989
return ret;
30322990

30332991
mutex_lock(&perf->lock);
3034-
ret = i915_perf_read_locked(stream, file,
3035-
buf, count, ppos);
2992+
ret = stream->ops->read(stream, buf, count, &offset);
30362993
mutex_unlock(&perf->lock);
3037-
} while (ret == -EAGAIN);
2994+
} while (!offset && !ret);
30382995
} else {
30392996
mutex_lock(&perf->lock);
3040-
ret = i915_perf_read_locked(stream, file, buf, count, ppos);
2997+
ret = stream->ops->read(stream, buf, count, &offset);
30412998
mutex_unlock(&perf->lock);
30422999
}
30433000

@@ -3048,15 +3005,15 @@ static ssize_t i915_perf_read(struct file *file,
30483005
* and read() returning -EAGAIN. Clearing the oa.pollin state here
30493006
* effectively ensures we back off until the next hrtimer callback
30503007
* before reporting another EPOLLIN event.
3008+
* The exception to this is if ops->read() returned -ENOSPC which means
3009+
* that more OA data is available than could fit in the user provided
3010+
* buffer. In this case we want the next poll() call to not block.
30513011
*/
3052-
if (ret >= 0 || ret == -EAGAIN) {
3053-
/* Maybe make ->pollin per-stream state if we support multiple
3054-
* concurrent streams in the future.
3055-
*/
3012+
if (ret != -ENOSPC)
30563013
stream->pollin = false;
3057-
}
30583014

3059-
return ret;
3015+
/* Possible values for ret are 0, -EFAULT, -ENOSPC, -EIO, ... */
3016+
return offset ?: (ret ?: -EAGAIN);
30603017
}
30613018

30623019
static enum hrtimer_restart oa_poll_check_timer_cb(struct hrtimer *hrtimer)

0 commit comments

Comments
 (0)