Skip to content

Commit

Permalink
Merge tag 'drm-intel-fixes-2017-01-05' of git://anongit.freedesktop.o…
Browse files Browse the repository at this point in the history
…rg/git/drm-intel

Pull i915 drm fixes from Jani Nikula:
 "Here's a bunch of drm/i915 fixes for v4.10-rc3. It includes GVT-g
  fixes.

  My new year's resolution is to start using signed tags for pulls. If
  that feels like a déjà vu, it's ((new year's) resolution), not (new
  (year's resolution))"

[ Taking this directly from Jani because Dave Airlie is only partially
  connected right now.  - Linus ]

* tag 'drm-intel-fixes-2017-01-05' of git://anongit.freedesktop.org/git/drm-intel:
  drm/i915: Prevent timeline updates whilst performing reset
  drm/i915: Silence allocation failure during sg_trim()
  drm/i915: Don't clflush before release phys object
  drm/i915: Fix oops in overlay due to frontbuffer tracking
  drm/i915: Fix oopses in the overlay code due to i915_gem_active stuff
  drm/i915: Initialize overlay->last_flip properly
  drm/i915: Move the min_pixclk[] handling to the end of readout
  drm/i915: Force VDD off on the new power seqeuencer before starting to use it
  drm/i915/gvt: fix typo in cfg_space range check
  drm/i915/gvt: fix an issue in emulating cfg space PCI_COMMAND
  drm/i915/gvt/kvmgt: trival: code cleanup
  drm/i915/gvt/kvmgt: prevent double-release of vgpu
  drm/i915/gvt/kvmgt: check returned slot for gfn
  drm/i915/gvt/kvmgt: dereference the pointer within lock
  drm/i915/gvt: reset the GGTT entry when vGPU created
  drm/i915/gvt: fix an error in opregion handling
  • Loading branch information
Linus Torvalds committed Jan 5, 2017
2 parents c433eb7 + 2471eb5 commit ed40875
Show file tree
Hide file tree
Showing 11 changed files with 190 additions and 45 deletions.
4 changes: 2 additions & 2 deletions drivers/gpu/drm/i915/gvt/cfg_space.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ static int emulate_pci_command_write(struct intel_vgpu *vgpu,
u8 changed = old ^ new;
int ret;

memcpy(vgpu_cfg_space(vgpu) + offset, p_data, bytes);
if (!(changed & PCI_COMMAND_MEMORY))
return 0;

Expand All @@ -142,7 +143,6 @@ static int emulate_pci_command_write(struct intel_vgpu *vgpu,
return ret;
}

memcpy(vgpu_cfg_space(vgpu) + offset, p_data, bytes);
return 0;
}

Expand Down Expand Up @@ -240,7 +240,7 @@ int intel_vgpu_emulate_cfg_write(struct intel_vgpu *vgpu, unsigned int offset,
if (WARN_ON(bytes > 4))
return -EINVAL;

if (WARN_ON(offset + bytes >= INTEL_GVT_MAX_CFG_SPACE_SZ))
if (WARN_ON(offset + bytes > INTEL_GVT_MAX_CFG_SPACE_SZ))
return -EINVAL;

/* First check if it's PCI_COMMAND */
Expand Down
55 changes: 55 additions & 0 deletions drivers/gpu/drm/i915/gvt/gtt.c
Original file line number Diff line number Diff line change
Expand Up @@ -1998,6 +1998,8 @@ int intel_vgpu_init_gtt(struct intel_vgpu *vgpu)
INIT_LIST_HEAD(&gtt->oos_page_list_head);
INIT_LIST_HEAD(&gtt->post_shadow_list_head);

intel_vgpu_reset_ggtt(vgpu);

ggtt_mm = intel_vgpu_create_mm(vgpu, INTEL_GVT_MM_GGTT,
NULL, 1, 0);
if (IS_ERR(ggtt_mm)) {
Expand Down Expand Up @@ -2206,6 +2208,7 @@ int intel_vgpu_g2v_destroy_ppgtt_mm(struct intel_vgpu *vgpu,
int intel_gvt_init_gtt(struct intel_gvt *gvt)
{
int ret;
void *page_addr;

gvt_dbg_core("init gtt\n");

Expand All @@ -2218,6 +2221,23 @@ int intel_gvt_init_gtt(struct intel_gvt *gvt)
return -ENODEV;
}

gvt->gtt.scratch_ggtt_page =
alloc_page(GFP_KERNEL | GFP_ATOMIC | __GFP_ZERO);
if (!gvt->gtt.scratch_ggtt_page) {
gvt_err("fail to allocate scratch ggtt page\n");
return -ENOMEM;
}

page_addr = page_address(gvt->gtt.scratch_ggtt_page);

gvt->gtt.scratch_ggtt_mfn =
intel_gvt_hypervisor_virt_to_mfn(page_addr);
if (gvt->gtt.scratch_ggtt_mfn == INTEL_GVT_INVALID_ADDR) {
gvt_err("fail to translate scratch ggtt page\n");
__free_page(gvt->gtt.scratch_ggtt_page);
return -EFAULT;
}

if (enable_out_of_sync) {
ret = setup_spt_oos(gvt);
if (ret) {
Expand All @@ -2239,6 +2259,41 @@ int intel_gvt_init_gtt(struct intel_gvt *gvt)
*/
void intel_gvt_clean_gtt(struct intel_gvt *gvt)
{
__free_page(gvt->gtt.scratch_ggtt_page);

if (enable_out_of_sync)
clean_spt_oos(gvt);
}

/**
* intel_vgpu_reset_ggtt - reset the GGTT entry
* @vgpu: a vGPU
*
* This function is called at the vGPU create stage
* to reset all the GGTT entries.
*
*/
void intel_vgpu_reset_ggtt(struct intel_vgpu *vgpu)
{
struct intel_gvt *gvt = vgpu->gvt;
struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops;
u32 index;
u32 offset;
u32 num_entries;
struct intel_gvt_gtt_entry e;

memset(&e, 0, sizeof(struct intel_gvt_gtt_entry));
e.type = GTT_TYPE_GGTT_PTE;
ops->set_pfn(&e, gvt->gtt.scratch_ggtt_mfn);
e.val64 |= _PAGE_PRESENT;

index = vgpu_aperture_gmadr_base(vgpu) >> PAGE_SHIFT;
num_entries = vgpu_aperture_sz(vgpu) >> PAGE_SHIFT;
for (offset = 0; offset < num_entries; offset++)
ops->set_entry(NULL, &e, index + offset, false, 0, vgpu);

index = vgpu_hidden_gmadr_base(vgpu) >> PAGE_SHIFT;
num_entries = vgpu_hidden_sz(vgpu) >> PAGE_SHIFT;
for (offset = 0; offset < num_entries; offset++)
ops->set_entry(NULL, &e, index + offset, false, 0, vgpu);
}
4 changes: 4 additions & 0 deletions drivers/gpu/drm/i915/gvt/gtt.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ struct intel_gvt_gtt {
struct list_head oos_page_use_list_head;
struct list_head oos_page_free_list_head;
struct list_head mm_lru_list_head;

struct page *scratch_ggtt_page;
unsigned long scratch_ggtt_mfn;
};

enum {
Expand Down Expand Up @@ -202,6 +205,7 @@ struct intel_vgpu_gtt {

extern int intel_vgpu_init_gtt(struct intel_vgpu *vgpu);
extern void intel_vgpu_clean_gtt(struct intel_vgpu *vgpu);
void intel_vgpu_reset_ggtt(struct intel_vgpu *vgpu);

extern int intel_gvt_init_gtt(struct intel_gvt *gvt);
extern void intel_gvt_clean_gtt(struct intel_gvt *gvt);
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/i915/gvt/gvt.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ struct intel_vgpu {
struct notifier_block group_notifier;
struct kvm *kvm;
struct work_struct release_work;
atomic_t released;
} vdev;
#endif
};
Expand Down
46 changes: 36 additions & 10 deletions drivers/gpu/drm/i915/gvt/kvmgt.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,15 @@ static struct gvt_dma *__gvt_cache_find(struct intel_vgpu *vgpu, gfn_t gfn)
static kvm_pfn_t gvt_cache_find(struct intel_vgpu *vgpu, gfn_t gfn)
{
struct gvt_dma *entry;
kvm_pfn_t pfn;

mutex_lock(&vgpu->vdev.cache_lock);

entry = __gvt_cache_find(vgpu, gfn);
mutex_unlock(&vgpu->vdev.cache_lock);
pfn = (entry == NULL) ? 0 : entry->pfn;

return entry == NULL ? 0 : entry->pfn;
mutex_unlock(&vgpu->vdev.cache_lock);
return pfn;
}

static void gvt_cache_add(struct intel_vgpu *vgpu, gfn_t gfn, kvm_pfn_t pfn)
Expand Down Expand Up @@ -497,7 +500,16 @@ static int intel_vgpu_open(struct mdev_device *mdev)
goto undo_iommu;
}

return kvmgt_guest_init(mdev);
ret = kvmgt_guest_init(mdev);
if (ret)
goto undo_group;

atomic_set(&vgpu->vdev.released, 0);
return ret;

undo_group:
vfio_unregister_notifier(&mdev->dev, VFIO_GROUP_NOTIFY,
&vgpu->vdev.group_notifier);

undo_iommu:
vfio_unregister_notifier(&mdev->dev, VFIO_IOMMU_NOTIFY,
Expand All @@ -509,17 +521,26 @@ static int intel_vgpu_open(struct mdev_device *mdev)
static void __intel_vgpu_release(struct intel_vgpu *vgpu)
{
struct kvmgt_guest_info *info;
int ret;

if (!handle_valid(vgpu->handle))
return;

vfio_unregister_notifier(&vgpu->vdev.mdev->dev, VFIO_IOMMU_NOTIFY,
if (atomic_cmpxchg(&vgpu->vdev.released, 0, 1))
return;

ret = vfio_unregister_notifier(&vgpu->vdev.mdev->dev, VFIO_IOMMU_NOTIFY,
&vgpu->vdev.iommu_notifier);
vfio_unregister_notifier(&vgpu->vdev.mdev->dev, VFIO_GROUP_NOTIFY,
WARN(ret, "vfio_unregister_notifier for iommu failed: %d\n", ret);

ret = vfio_unregister_notifier(&vgpu->vdev.mdev->dev, VFIO_GROUP_NOTIFY,
&vgpu->vdev.group_notifier);
WARN(ret, "vfio_unregister_notifier for group failed: %d\n", ret);

info = (struct kvmgt_guest_info *)vgpu->handle;
kvmgt_guest_exit(info);

vgpu->vdev.kvm = NULL;
vgpu->handle = 0;
}

Expand All @@ -534,6 +555,7 @@ static void intel_vgpu_release_work(struct work_struct *work)
{
struct intel_vgpu *vgpu = container_of(work, struct intel_vgpu,
vdev.release_work);

__intel_vgpu_release(vgpu);
}

Expand Down Expand Up @@ -1134,6 +1156,10 @@ static int kvmgt_write_protect_add(unsigned long handle, u64 gfn)

idx = srcu_read_lock(&kvm->srcu);
slot = gfn_to_memslot(kvm, gfn);
if (!slot) {
srcu_read_unlock(&kvm->srcu, idx);
return -EINVAL;
}

spin_lock(&kvm->mmu_lock);

Expand Down Expand Up @@ -1164,6 +1190,10 @@ static int kvmgt_write_protect_remove(unsigned long handle, u64 gfn)

idx = srcu_read_lock(&kvm->srcu);
slot = gfn_to_memslot(kvm, gfn);
if (!slot) {
srcu_read_unlock(&kvm->srcu, idx);
return -EINVAL;
}

spin_lock(&kvm->mmu_lock);

Expand Down Expand Up @@ -1311,18 +1341,14 @@ static int kvmgt_guest_init(struct mdev_device *mdev)

static bool kvmgt_guest_exit(struct kvmgt_guest_info *info)
{
struct intel_vgpu *vgpu;

if (!info) {
gvt_err("kvmgt_guest_info invalid\n");
return false;
}

vgpu = info->vgpu;

kvm_page_track_unregister_notifier(info->kvm, &info->track_node);
kvmgt_protect_table_destroy(info);
gvt_cache_destroy(vgpu);
gvt_cache_destroy(info->vgpu);
vfree(info);

return true;
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/i915/gvt/opregion.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ static int map_vgpu_opregion(struct intel_vgpu *vgpu, bool map)
int i, ret;

for (i = 0; i < INTEL_GVT_OPREGION_PAGES; i++) {
mfn = intel_gvt_hypervisor_virt_to_mfn(vgpu_opregion(vgpu)
mfn = intel_gvt_hypervisor_virt_to_mfn(vgpu_opregion(vgpu)->va
+ i * PAGE_SIZE);
if (mfn == INTEL_GVT_INVALID_ADDR) {
gvt_err("fail to get MFN from VA\n");
Expand Down
22 changes: 16 additions & 6 deletions drivers/gpu/drm/i915/i915_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -244,14 +244,16 @@ i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj)

static void
__i915_gem_object_release_shmem(struct drm_i915_gem_object *obj,
struct sg_table *pages)
struct sg_table *pages,
bool needs_clflush)
{
GEM_BUG_ON(obj->mm.madv == __I915_MADV_PURGED);

if (obj->mm.madv == I915_MADV_DONTNEED)
obj->mm.dirty = false;

if ((obj->base.read_domains & I915_GEM_DOMAIN_CPU) == 0 &&
if (needs_clflush &&
(obj->base.read_domains & I915_GEM_DOMAIN_CPU) == 0 &&
!cpu_cache_is_coherent(obj->base.dev, obj->cache_level))
drm_clflush_sg(pages);

Expand All @@ -263,7 +265,7 @@ static void
i915_gem_object_put_pages_phys(struct drm_i915_gem_object *obj,
struct sg_table *pages)
{
__i915_gem_object_release_shmem(obj, pages);
__i915_gem_object_release_shmem(obj, pages, false);

if (obj->mm.dirty) {
struct address_space *mapping = obj->base.filp->f_mapping;
Expand Down Expand Up @@ -2231,7 +2233,7 @@ i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj,
struct sgt_iter sgt_iter;
struct page *page;

__i915_gem_object_release_shmem(obj, pages);
__i915_gem_object_release_shmem(obj, pages, true);

i915_gem_gtt_finish_pages(obj, pages);

Expand Down Expand Up @@ -2322,7 +2324,7 @@ static void i915_sg_trim(struct sg_table *orig_st)
if (orig_st->nents == orig_st->orig_nents)
return;

if (sg_alloc_table(&new_st, orig_st->nents, GFP_KERNEL))
if (sg_alloc_table(&new_st, orig_st->nents, GFP_KERNEL | __GFP_NOWARN))
return;

new_sg = new_st.sgl;
Expand Down Expand Up @@ -2728,6 +2730,7 @@ static void i915_gem_reset_engine(struct intel_engine_cs *engine)
struct drm_i915_gem_request *request;
struct i915_gem_context *incomplete_ctx;
struct intel_timeline *timeline;
unsigned long flags;
bool ring_hung;

if (engine->irq_seqno_barrier)
Expand Down Expand Up @@ -2763,13 +2766,20 @@ static void i915_gem_reset_engine(struct intel_engine_cs *engine)
if (i915_gem_context_is_default(incomplete_ctx))
return;

timeline = i915_gem_context_lookup_timeline(incomplete_ctx, engine);

spin_lock_irqsave(&engine->timeline->lock, flags);
spin_lock(&timeline->lock);

list_for_each_entry_continue(request, &engine->timeline->requests, link)
if (request->ctx == incomplete_ctx)
reset_request(request);

timeline = i915_gem_context_lookup_timeline(incomplete_ctx, engine);
list_for_each_entry(request, &timeline->requests, link)
reset_request(request);

spin_unlock(&timeline->lock);
spin_unlock_irqrestore(&engine->timeline->lock, flags);
}

void i915_gem_reset(struct drm_i915_private *dev_priv)
Expand Down
19 changes: 19 additions & 0 deletions drivers/gpu/drm/i915/i915_gem_request.h
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,25 @@ i915_gem_active_set(struct i915_gem_active *active,
rcu_assign_pointer(active->request, request);
}

/**
* i915_gem_active_set_retire_fn - updates the retirement callback
* @active - the active tracker
* @fn - the routine called when the request is retired
* @mutex - struct_mutex used to guard retirements
*
* i915_gem_active_set_retire_fn() updates the function pointer that
* is called when the final request associated with the @active tracker
* is retired.
*/
static inline void
i915_gem_active_set_retire_fn(struct i915_gem_active *active,
i915_gem_retire_fn fn,
struct mutex *mutex)
{
lockdep_assert_held(mutex);
active->retire = fn ?: i915_gem_retire_noop;
}

static inline struct drm_i915_gem_request *
__i915_gem_active_peek(const struct i915_gem_active *active)
{
Expand Down
Loading

0 comments on commit ed40875

Please sign in to comment.