[PATCH 00/13] mmu_notifier kill invalidate_page callback

2017-08-29 Thread Jérôme Glisse
(Sorry for so many list cross-posting and big cc)

Please help testing !

The invalidate_page callback suffered from 2 pitfalls. First it used to
happen after page table lock was release and thus a new page might have
been setup for the virtual address before the call to invalidate_page().

This is in a weird way fixed by c7ab0d2fdc840266b39db94538f74207ec2afbf6
which moved the callback under the page table lock. Which also broke
several existing user of the mmu_notifier API that assumed they could
sleep inside this callback.

The second pitfall was invalidate_page being the only callback not taking
a range of address in respect to invalidation but was giving an address
and a page. Lot of the callback implementer assumed this could never be
THP and thus failed to invalidate the appropriate range for THP pages.

By killing this callback we unify the mmu_notifier callback API to always
take a virtual address range as input.

There is now 2 clear API (I am not mentioning the youngess API which is
seldomly used):
  - invalidate_range_start()/end() callback (which allow you to sleep)
  - invalidate_range() where you can not sleep but happen right after
page table update under page table lock


Note that a lot of existing user feels broken in respect to range_start/
range_end. Many user only have range_start() callback but there is nothing
preventing them to undo what was invalidated in their range_start() callback
after it returns but before any CPU page table update take place.

The code pattern use in kvm or umem odp is an example on how to properly
avoid such race. In a nutshell use some kind of sequence number and active
range invalidation counter to block anything that might undo what the
range_start() callback did.

If you do not care about keeping fully in sync with CPU page table (ie
you can live with CPU page table pointing to new different page for a
given virtual address) then you can take a reference on the pages inside
the range_start callback and drop it in range_end or when your driver
is done with those pages.

Last alternative is to use invalidate_range() if you can do invalidation
without sleeping as invalidate_range() callback happens under the CPU
page table spinlock right after the page table is updated.


Note this is barely tested. I intend to do more testing of next few days
but i do not have access to all hardware that make use of the mmu_notifier
API.


First 2 patches convert existing call of mmu_notifier_invalidate_page()
to mmu_notifier_invalidate_range() and bracket those call with call to
mmu_notifier_invalidate_range_start()/end().

The next 10 patches remove existing invalidate_page() callback as it can
no longer happen.

Finaly the last page remove it completely so it can RIP.

Jérôme Glisse (13):
  dax: update to new mmu_notifier semantic
  mm/rmap: update to new mmu_notifier semantic
  powerpc/powernv: update to new mmu_notifier semantic
  drm/amdgpu: update to new mmu_notifier semantic
  IB/umem: update to new mmu_notifier semantic
  IB/hfi1: update to new mmu_notifier semantic
  iommu/amd: update to new mmu_notifier semantic
  iommu/intel: update to new mmu_notifier semantic
  misc/mic/scif: update to new mmu_notifier semantic
  sgi-gru: update to new mmu_notifier semantic
  xen/gntdev: update to new mmu_notifier semantic
  KVM: update to new mmu_notifier semantic
  mm/mmu_notifier: kill invalidate_page

Cc: Kirill A. Shutemov <kirill.shute...@linux.intel.com>
Cc: Linus Torvalds <torva...@linux-foundation.org>
Cc: Andrew Morton <a...@linux-foundation.org>
Cc: Andrea Arcangeli <aarca...@redhat.com>
Cc: Joerg Roedel <jroe...@suse.de>
Cc: Dan Williams <dan.j.willi...@intel.com>
Cc: Sudeep Dutt <sudeep.d...@intel.com>
Cc: Ashutosh Dixit <ashutosh.di...@intel.com>
Cc: Dimitri Sivanich <sivan...@sgi.com>
Cc: Jack Steiner <stei...@sgi.com>
Cc: Paolo Bonzini <pbonz...@redhat.com>
Cc: Radim Krčmář <rkrc...@redhat.com>

Cc: linuxppc-...@lists.ozlabs.org
Cc: dri-devel@lists.freedesktop.org
Cc: amd-...@lists.freedesktop.org
Cc: linux-r...@vger.kernel.org
Cc: io...@lists.linux-foundation.org
Cc: xen-de...@lists.xenproject.org
Cc: k...@vger.kernel.org


 arch/powerpc/platforms/powernv/npu-dma.c | 10 
 drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c   | 31 --
 drivers/infiniband/core/umem_odp.c   | 19 --
 drivers/infiniband/hw/hfi1/mmu_rb.c  |  9 ---
 drivers/iommu/amd_iommu_v2.c |  8 --
 drivers/iommu/intel-svm.c|  9 ---
 drivers/misc/mic/scif/scif_dma.c | 11 
 drivers/misc/sgi-gru/grutlbpurge.c   | 12 -
 drivers/xen/gntdev.c |  8 --
 fs/dax.c | 19 --
 include/linux/mm.h   |  1 +
 include/linux/mmu_notifier.h | 25 --
 mm/memory.c  | 26 +++-

[PATCH 2/2] drm/amdgpu: forbid mapping of userptr bo through radeon device file

2016-04-19 Thread Jérôme Glisse
Allowing userptr bo which are basicly a list of page from some vma
(so either anonymous page or file backed page) would lead to serious
corruption of kernel structures and counters (because we overwrite
the page->mapping field when mapping buffer).

This will already block if the buffer was populated before anyone does
try to mmap it because then TTM_PAGE_FLAG_SG would be set in in the
ttm_tt flags. But that flag is check before ttm_tt_populate in the ttm
vm fault handler.

So to be safe just add a check to verify_access() callback.

Signed-off-by: Jérôme Glisse 
Cc: 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
index 6f3369d..11af449 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -223,6 +223,8 @@ static int amdgpu_verify_access(struct ttm_buffer_object 
*bo, struct file *filp)
 {
struct amdgpu_bo *rbo = container_of(bo, struct amdgpu_bo, tbo);

+   if (amdgpu_ttm_tt_get_usermm(bo->ttm))
+   return -EPERM;
return drm_vma_node_verify_access(>gem_base.vma_node, filp);
 }

-- 
2.1.0



[PATCH 1/2] drm/radeon: forbid mapping of userptr bo through radeon device file

2016-04-19 Thread Jérôme Glisse
Allowing userptr bo which are basicly a list of page from some vma
(so either anonymous page or file backed page) would lead to serious
corruption of kernel structures and counters (because we overwrite
the page->mapping field when mapping buffer).

This will already block if the buffer was populated before anyone does
try to mmap it because then TTM_PAGE_FLAG_SG would be set in in the
ttm_tt flags. But that flag is check before ttm_tt_populate in the ttm
vm fault handler.

So to be safe just add a check to verify_access() callback.

Signed-off-by: Jérôme Glisse 
Cc: 
---
 drivers/gpu/drm/radeon/radeon_ttm.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c 
b/drivers/gpu/drm/radeon/radeon_ttm.c
index 7dddfdc..90f7394 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -235,6 +235,8 @@ static int radeon_verify_access(struct ttm_buffer_object 
*bo, struct file *filp)
 {
struct radeon_bo *rbo = container_of(bo, struct radeon_bo, tbo);

+   if (radeon_ttm_tt_has_userptr(bo->ttm))
+   return -EPERM;
return drm_vma_node_verify_access(>gem_base.vma_node, filp);
 }

-- 
2.1.0



[PATCH 14/14] drm/radeon: hard reset r600 and newer GPU when hibernating.

2016-03-18 Thread Jérôme Glisse
From: Jérome Glisse 

Some GPU block like UVD and VCE require hard reset to be properly
resume if there is no real powerdown of the asic like during various
hibernation step. This patch perform such hard reset.

Signed-off-by: Jérôme Glisse 
Cc: Alex Deucher 
Cc: Christian König 
---
 drivers/gpu/drm/radeon/radeon.h|  3 ++-
 drivers/gpu/drm/radeon/radeon_device.c | 10 +++---
 drivers/gpu/drm/radeon/radeon_drv.c|  9 +
 3 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 1ededd1..8e403be 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -2835,7 +2835,8 @@ extern bool radeon_ttm_tt_is_readonly(struct ttm_tt *ttm);
 extern void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc 
*mc, u64 base);
 extern void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc 
*mc);
 extern int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon);
-extern int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool 
fbcon);
+extern int radeon_suspend_kms(struct drm_device *dev, bool suspend,
+ bool fbcon, bool freeze);
 extern void radeon_ttm_set_active_vram_size(struct radeon_device *rdev, u64 
size);
 extern void radeon_program_register_sequence(struct radeon_device *rdev,
 const u32 *registers,
diff --git a/drivers/gpu/drm/radeon/radeon_device.c 
b/drivers/gpu/drm/radeon/radeon_device.c
index ec8de1a..93f1a27 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -1236,7 +1236,7 @@ static void radeon_switcheroo_set_state(struct pci_dev 
*pdev, enum vga_switchero
printk(KERN_INFO "radeon: switched off\n");
drm_kms_helper_poll_disable(dev);
dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
-   radeon_suspend_kms(dev, true, true);
+   radeon_suspend_kms(dev, true, true, false);
dev->switch_power_state = DRM_SWITCH_POWER_OFF;
}
 }
@@ -1561,7 +1561,8 @@ void radeon_device_fini(struct radeon_device *rdev)
  * Returns 0 for success or an error on failure.
  * Called at driver suspend.
  */
-int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon)
+int radeon_suspend_kms(struct drm_device *dev, bool suspend,
+  bool fbcon, bool freeze)
 {
struct radeon_device *rdev;
struct drm_crtc *crtc;
@@ -1636,7 +1637,10 @@ int radeon_suspend_kms(struct drm_device *dev, bool 
suspend, bool fbcon)
radeon_agp_suspend(rdev);

pci_save_state(dev->pdev);
-   if (suspend) {
+   if (freeze && rdev->family >= CHIP_R600) {
+   rdev->asic->asic_reset(rdev, true);
+   pci_restore_state(dev->pdev);
+   } else if (suspend) {
/* Shut down the device */
pci_disable_device(dev->pdev);
pci_set_power_state(dev->pdev, PCI_D3hot);
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c 
b/drivers/gpu/drm/radeon/radeon_drv.c
index 0847265..e9e6306 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -105,7 +105,8 @@ void radeon_driver_postclose_kms(struct drm_device *dev,
 struct drm_file *file_priv);
 void radeon_driver_preclose_kms(struct drm_device *dev,
struct drm_file *file_priv);
-int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon);
+int radeon_suspend_kms(struct drm_device *dev, bool suspend,
+  bool fbcon, bool freeze);
 int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon);
 u32 radeon_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe);
 int radeon_enable_vblank_kms(struct drm_device *dev, unsigned int pipe);
@@ -358,7 +359,7 @@ static int radeon_pmops_suspend(struct device *dev)
 {
struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *drm_dev = pci_get_drvdata(pdev);
-   return radeon_suspend_kms(drm_dev, true, true);
+   return radeon_suspend_kms(drm_dev, true, true, false);
 }

 static int radeon_pmops_resume(struct device *dev)
@@ -372,7 +373,7 @@ static int radeon_pmops_freeze(struct device *dev)
 {
struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *drm_dev = pci_get_drvdata(pdev);
-   return radeon_suspend_kms(drm_dev, false, true);
+   return radeon_suspend_kms(drm_dev, false, true, true);
 }

 static int radeon_pmops_thaw(struct device *dev)
@@ -397,7 +398,7 @@ static int radeon_pmops_runtime_suspend(struct device *dev)
drm_kms_helper_poll_disable(drm_dev);
vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF);

-   ret = radeon_suspend_kms(drm_dev, false, false);
+   ret = radeon_suspend_kms(drm_dev, false, false, 

[PATCH 13/14] drm/radeon: allow to force hard GPU reset.

2016-03-18 Thread Jérôme Glisse
From: Jérome Glisse 

In some cases, like when freezing for hibernation, we need to be
able to force hard reset even if no engine are stuck. This patch
add a bool option to current asic reset callback to allow to force
hard reset on asic that supports it.

Signed-off-by: Jérôme Glisse 
Cc: Alex Deucher 
Cc: Christian König 
---
 drivers/gpu/drm/radeon/cik.c |  8 +++-
 drivers/gpu/drm/radeon/evergreen.c   |  7 ++-
 drivers/gpu/drm/radeon/ni.c  |  7 ++-
 drivers/gpu/drm/radeon/r100.c|  2 +-
 drivers/gpu/drm/radeon/r300.c|  2 +-
 drivers/gpu/drm/radeon/r600.c|  7 ++-
 drivers/gpu/drm/radeon/radeon.h  |  4 ++--
 drivers/gpu/drm/radeon/radeon_asic.h | 16 
 drivers/gpu/drm/radeon/rs600.c   |  2 +-
 drivers/gpu/drm/radeon/si.c  |  7 ++-
 10 files changed, 44 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index b5bc9cf..7ee9304 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -5620,15 +5620,21 @@ static void cik_gpu_pci_config_reset(struct 
radeon_device *rdev)
  * cik_asic_reset - soft reset GPU
  *
  * @rdev: radeon_device pointer
+ * @hard: force hard reset
  *
  * Look up which blocks are hung and attempt
  * to reset them.
  * Returns 0 for success.
  */
-int cik_asic_reset(struct radeon_device *rdev)
+int cik_asic_reset(struct radeon_device *rdev, bool hard)
 {
u32 reset_mask;

+   if (hard) {
+   cik_gpu_pci_config_reset(rdev);
+   return 0;
+   }
+
reset_mask = cik_gpu_check_soft_reset(rdev);

if (reset_mask)
diff --git a/drivers/gpu/drm/radeon/evergreen.c 
b/drivers/gpu/drm/radeon/evergreen.c
index cc0cf9a..e483b07 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -3984,10 +3984,15 @@ void evergreen_gpu_pci_config_reset(struct 
radeon_device *rdev)
}
 }

-int evergreen_asic_reset(struct radeon_device *rdev)
+int evergreen_asic_reset(struct radeon_device *rdev, bool hard)
 {
u32 reset_mask;

+   if (hard) {
+   evergreen_gpu_pci_config_reset(rdev);
+   return 0;
+   }
+
reset_mask = evergreen_gpu_check_soft_reset(rdev);

if (reset_mask)
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c
index ec0aac8..4a3d7ca 100644
--- a/drivers/gpu/drm/radeon/ni.c
+++ b/drivers/gpu/drm/radeon/ni.c
@@ -1959,10 +1959,15 @@ static void cayman_gpu_soft_reset(struct radeon_device 
*rdev, u32 reset_mask)
evergreen_print_gpu_status_regs(rdev);
 }

-int cayman_asic_reset(struct radeon_device *rdev)
+int cayman_asic_reset(struct radeon_device *rdev, bool hard)
 {
u32 reset_mask;

+   if (hard) {
+   evergreen_gpu_pci_config_reset(rdev);
+   return 0;
+   }
+
reset_mask = cayman_gpu_check_soft_reset(rdev);

if (reset_mask)
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index 6e478a2..bbdf15f 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -2555,7 +2555,7 @@ void r100_bm_disable(struct radeon_device *rdev)
mdelay(1);
 }

-int r100_asic_reset(struct radeon_device *rdev)
+int r100_asic_reset(struct radeon_device *rdev, bool hard)
 {
struct r100_mc_save save;
u32 status, tmp;
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c
index 718b12b..7e417d8 100644
--- a/drivers/gpu/drm/radeon/r300.c
+++ b/drivers/gpu/drm/radeon/r300.c
@@ -410,7 +410,7 @@ static void r300_gpu_init(struct radeon_device *rdev)
 rdev->num_gb_pipes, rdev->num_z_pipes);
 }

-int r300_asic_reset(struct radeon_device *rdev)
+int r300_asic_reset(struct radeon_device *rdev, bool hard)
 {
struct r100_mc_save save;
u32 status, tmp;
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index 24fa982..d7896bb 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -1871,10 +1871,15 @@ static void r600_gpu_pci_config_reset(struct 
radeon_device *rdev)
}
 }

-int r600_asic_reset(struct radeon_device *rdev)
+int r600_asic_reset(struct radeon_device *rdev, bool hard)
 {
u32 reset_mask;

+   if (hard) {
+   r600_gpu_pci_config_reset(rdev);
+   return 0;
+   }
+
reset_mask = r600_gpu_check_soft_reset(rdev);

if (reset_mask)
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 91828ec..1ededd1 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1854,7 +1854,7 @@ struct radeon_asic {
int (*resume)(struct radeon_device *rdev);
int (*suspend)(struct radeon_device *rdev);
void (*vga_set_state)(struct radeon_device *rdev, bool state);
-   int (*asic_reset)(struct radeon_device *rdev);
+   int 

[PATCH 12/14] drm/radeon: add driver option to disable vce block.

2016-03-18 Thread Jérôme Glisse
From: Jérome Glisse 

Quite few suspend/hibernation bugs are related to this block. Add
an option to disable those as a work around.

Signed-off-by: Jérôme Glisse 
Cc: Alex Deucher 
Cc: Christian König 
---
 drivers/gpu/drm/radeon/radeon.h  | 1 +
 drivers/gpu/drm/radeon/radeon_asic.c | 2 ++
 drivers/gpu/drm/radeon/radeon_drv.c  | 4 
 3 files changed, 7 insertions(+)

diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 1b26cef..91828ec 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -114,6 +114,7 @@ extern int radeon_backlight;
 extern int radeon_auxch;
 extern int radeon_mst;
 extern int radeon_uvd;
+extern int radeon_vce;

 /*
  * Copy from radeon_drv.h so we don't have to include both and have conflicting
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c 
b/drivers/gpu/drm/radeon/radeon_asic.c
index b4810ef..bc5121d 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -2698,6 +2698,8 @@ int radeon_asic_init(struct radeon_device *rdev)

if (!radeon_uvd)
rdev->has_uvd = false;
+   if (!radeon_vce)
+   rdev->has_vce = false;

return 0;
 }
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c 
b/drivers/gpu/drm/radeon/radeon_drv.c
index a25b90b..0847265 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -197,6 +197,7 @@ int radeon_backlight = -1;
 int radeon_auxch = -1;
 int radeon_mst = 0;
 int radeon_uvd = 1;
+int radeon_vce = 1;

 MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers");
 module_param_named(no_wb, radeon_no_wb, int, 0444);
@@ -291,6 +292,9 @@ module_param_named(mst, radeon_mst, int, 0444);
 MODULE_PARM_DESC(uvd, "uvd enable/disable uvd support (1 = enable, 0 = 
disable)");
 module_param_named(uvd, radeon_uvd, int, 0444);

+MODULE_PARM_DESC(vce, "vce enable/disable vce support (1 = enable, 0 = 
disable)");
+module_param_named(vce, radeon_vce, int, 0444);
+
 static struct pci_device_id pciidlist[] = {
radeon_PCI_IDS
 };
-- 
1.8.3.1



[PATCH 11/14] drm/radeon: add driver option to disable uvd block.

2016-03-18 Thread Jérôme Glisse
From: Jérome Glisse 

Quite few suspend/hibernation bugs are related to this block. Add
an option to disable those as a work around.

Signed-off-by: Jérôme Glisse 
Cc: Alex Deucher 
Cc: Christian König 
---
 drivers/gpu/drm/radeon/radeon.h  | 1 +
 drivers/gpu/drm/radeon/radeon_asic.c | 3 +++
 drivers/gpu/drm/radeon/radeon_drv.c  | 4 
 3 files changed, 8 insertions(+)

diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 8ac3e07..1b26cef 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -113,6 +113,7 @@ extern int radeon_bapm;
 extern int radeon_backlight;
 extern int radeon_auxch;
 extern int radeon_mst;
+extern int radeon_uvd;

 /*
  * Copy from radeon_drv.h so we don't have to include both and have conflicting
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c 
b/drivers/gpu/drm/radeon/radeon_asic.c
index 46a4ced..b4810ef 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -2696,6 +2696,9 @@ int radeon_asic_init(struct radeon_device *rdev)
rdev->asic->pm.set_memory_clock = NULL;
}

+   if (!radeon_uvd)
+   rdev->has_uvd = false;
+
return 0;
 }

diff --git a/drivers/gpu/drm/radeon/radeon_drv.c 
b/drivers/gpu/drm/radeon/radeon_drv.c
index cad2555..a25b90b 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -196,6 +196,7 @@ int radeon_bapm = -1;
 int radeon_backlight = -1;
 int radeon_auxch = -1;
 int radeon_mst = 0;
+int radeon_uvd = 1;

 MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers");
 module_param_named(no_wb, radeon_no_wb, int, 0444);
@@ -287,6 +288,9 @@ module_param_named(auxch, radeon_auxch, int, 0444);
 MODULE_PARM_DESC(mst, "DisplayPort MST experimental support (1 = enable, 0 = 
disable)");
 module_param_named(mst, radeon_mst, int, 0444);

+MODULE_PARM_DESC(uvd, "uvd enable/disable uvd support (1 = enable, 0 = 
disable)");
+module_param_named(uvd, radeon_uvd, int, 0444);
+
 static struct pci_device_id pciidlist[] = {
radeon_PCI_IDS
 };
-- 
1.8.3.1



[PATCH 10/14] drm/radeon: consolidate cik vce initialization and startup code.

2016-03-18 Thread Jérôme Glisse
From: Jérome Glisse 

This match the exact same control flow as existing code. It just
use goto instead of multiple levels of if/else. It also clarify
early initialization failures by clearing rdev->has_vce doing so
does not change end result from hardware point of view, it only
avoids printing more error messages down the line and thus only
the original error is reported.

Signed-off-by: Jérôme Glisse 
Cc: Alex Deucher 
Cc: Christian König 
---
 drivers/gpu/drm/radeon/cik.c | 136 +--
 1 file changed, 91 insertions(+), 45 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index be14669..b5bc9cf 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -8568,6 +8568,92 @@ static void cik_uvd_resume(struct radeon_device *rdev)
}
 }

+static void cik_vce_init(struct radeon_device *rdev)
+{
+   int r;
+
+   if (!rdev->has_vce)
+   return;
+
+   r = radeon_vce_init(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed VCE (%d) init.\n", r);
+   /*
+* At this point rdev->vce.vcpu_bo is NULL which trickles down
+* to early fails cik_vce_start() and thus nothing happens
+* there. So it is pointless to try to go through that code
+* hence why we disable vce here.
+*/
+   rdev->has_vce = 0;
+   return;
+   }
+   rdev->ring[TN_RING_TYPE_VCE1_INDEX].ring_obj = NULL;
+   r600_ring_init(rdev, >ring[TN_RING_TYPE_VCE1_INDEX], 4096);
+   rdev->ring[TN_RING_TYPE_VCE2_INDEX].ring_obj = NULL;
+   r600_ring_init(rdev, >ring[TN_RING_TYPE_VCE2_INDEX], 4096);
+}
+
+static void cik_vce_start(struct radeon_device *rdev)
+{
+   int r;
+
+   if (!rdev->has_vce)
+   return;
+
+   r = radeon_vce_resume(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed VCE resume (%d).\n", r);
+   goto error;
+   }
+   r = vce_v2_0_resume(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed VCE resume (%d).\n", r);
+   goto error;
+   }
+   r = radeon_fence_driver_start_ring(rdev, TN_RING_TYPE_VCE1_INDEX);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing VCE1 fences (%d).\n", 
r);
+   goto error;
+   }
+   r = radeon_fence_driver_start_ring(rdev, TN_RING_TYPE_VCE2_INDEX);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing VCE2 fences (%d).\n", 
r);
+   goto error;
+   }
+   return;
+
+error:
+   rdev->ring[TN_RING_TYPE_VCE1_INDEX].ring_size = 0;
+   rdev->ring[TN_RING_TYPE_VCE2_INDEX].ring_size = 0;
+}
+
+static void cik_vce_resume(struct radeon_device *rdev)
+{
+   struct radeon_ring *ring;
+   int r;
+
+   if (!rdev->has_vce || !rdev->ring[TN_RING_TYPE_VCE1_INDEX].ring_size)
+   return;
+
+   ring = >ring[TN_RING_TYPE_VCE1_INDEX];
+   r = radeon_ring_init(rdev, ring, ring->ring_size, 0, VCE_CMD_NO_OP);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing VCE1 ring (%d).\n", r);
+   return;
+   }
+   ring = >ring[TN_RING_TYPE_VCE2_INDEX];
+   r = radeon_ring_init(rdev, ring, ring->ring_size, 0, VCE_CMD_NO_OP);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing VCE1 ring (%d).\n", r);
+   return;
+   }
+   r = vce_v1_0_init(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing VCE (%d).\n", r);
+   return;
+   }
+}
+
 /**
  * cik_startup - program the asic to a functional state
  *
@@ -8671,22 +8757,7 @@ static int cik_startup(struct radeon_device *rdev)
}

cik_uvd_start(rdev);
-
-   r = radeon_vce_resume(rdev);
-   if (!r) {
-   r = vce_v2_0_resume(rdev);
-   if (!r)
-   r = radeon_fence_driver_start_ring(rdev,
-  
TN_RING_TYPE_VCE1_INDEX);
-   if (!r)
-   r = radeon_fence_driver_start_ring(rdev,
-  
TN_RING_TYPE_VCE2_INDEX);
-   }
-   if (r) {
-   dev_err(rdev->dev, "VCE init error (%d).\n", r);
-   rdev->ring[TN_RING_TYPE_VCE1_INDEX].ring_size = 0;
-   rdev->ring[TN_RING_TYPE_VCE2_INDEX].ring_size = 0;
-   }
+   cik_vce_start(rdev);

/* Enable IRQ */
if (!rdev->irq.installed) {
@@ -8763,23 +8834,7 @@ static int cik_startup(struct radeon_device *rdev)
return r;

cik_uvd_resume(rdev);
-
-   r = -ENOENT;
-
-   ring = >ring[TN_RING_TYPE_VCE1_INDEX];
-   if (ring->ring_size)
-   r = radeon_ring_init(rdev, ring, ring->ring_size, 0,
-VCE_CMD_NO_OP);
-
-   

[PATCH 09/14] drm/radeon: consolidate si vce initialization and startup code.

2016-03-18 Thread Jérôme Glisse
From: Jérome Glisse 

This match the exact same control flow as existing code. It just
use goto instead of multiple levels of if/else. It also clarify
early initialization failures by clearing rdev->has_vce doing so
does not change end result from hardware point of view, it only
avoids printing more error messages down the line and thus only
the original error is reported.

Signed-off-by: Jérôme Glisse 
Cc: Alex Deucher 
Cc: Christian König 
---
 drivers/gpu/drm/radeon/si.c | 139 +---
 1 file changed, 93 insertions(+), 46 deletions(-)

diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c
index 067c384..7ed2a03 100644
--- a/drivers/gpu/drm/radeon/si.c
+++ b/drivers/gpu/drm/radeon/si.c
@@ -6935,6 +6935,92 @@ static void si_uvd_resume(struct radeon_device *rdev)
}
 }

+static void si_vce_init(struct radeon_device *rdev)
+{
+   int r;
+
+   if (!rdev->has_vce)
+   return;
+
+   r = radeon_vce_init(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed VCE (%d) init.\n", r);
+   /*
+* At this point rdev->vce.vcpu_bo is NULL which trickles down
+* to early fails si_vce_start() and thus nothing happens
+* there. So it is pointless to try to go through that code
+* hence why we disable vce here.
+*/
+   rdev->has_vce = 0;
+   return;
+   }
+   rdev->ring[TN_RING_TYPE_VCE1_INDEX].ring_obj = NULL;
+   r600_ring_init(rdev, >ring[TN_RING_TYPE_VCE1_INDEX], 4096);
+   rdev->ring[TN_RING_TYPE_VCE2_INDEX].ring_obj = NULL;
+   r600_ring_init(rdev, >ring[TN_RING_TYPE_VCE2_INDEX], 4096);
+}
+
+static void si_vce_start(struct radeon_device *rdev)
+{
+   int r;
+
+   if (!rdev->has_vce)
+   return;
+
+   r = radeon_vce_resume(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed VCE resume (%d).\n", r);
+   goto error;
+   }
+   r = vce_v1_0_resume(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed VCE resume (%d).\n", r);
+   goto error;
+   }
+   r = radeon_fence_driver_start_ring(rdev, TN_RING_TYPE_VCE1_INDEX);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing VCE1 fences (%d).\n", 
r);
+   goto error;
+   }
+   r = radeon_fence_driver_start_ring(rdev, TN_RING_TYPE_VCE2_INDEX);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing VCE2 fences (%d).\n", 
r);
+   goto error;
+   }
+   return;
+
+error:
+   rdev->ring[TN_RING_TYPE_VCE1_INDEX].ring_size = 0;
+   rdev->ring[TN_RING_TYPE_VCE2_INDEX].ring_size = 0;
+}
+
+static void si_vce_resume(struct radeon_device *rdev)
+{
+   struct radeon_ring *ring;
+   int r;
+
+   if (!rdev->has_vce || !rdev->ring[TN_RING_TYPE_VCE1_INDEX].ring_size)
+   return;
+
+   ring = >ring[TN_RING_TYPE_VCE1_INDEX];
+   r = radeon_ring_init(rdev, ring, ring->ring_size, 0, VCE_CMD_NO_OP);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing VCE1 ring (%d).\n", r);
+   return;
+   }
+   ring = >ring[TN_RING_TYPE_VCE2_INDEX];
+   r = radeon_ring_init(rdev, ring, ring->ring_size, 0, VCE_CMD_NO_OP);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing VCE1 ring (%d).\n", r);
+   return;
+   }
+   r = vce_v1_0_init(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing VCE (%d).\n", r);
+   return;
+   }
+}
+
 static int si_startup(struct radeon_device *rdev)
 {
struct radeon_ring *ring;
@@ -7014,22 +7100,7 @@ static int si_startup(struct radeon_device *rdev)
}

si_uvd_start(rdev);
-
-   r = radeon_vce_resume(rdev);
-   if (!r) {
-   r = vce_v1_0_resume(rdev);
-   if (!r)
-   r = radeon_fence_driver_start_ring(rdev,
-  
TN_RING_TYPE_VCE1_INDEX);
-   if (!r)
-   r = radeon_fence_driver_start_ring(rdev,
-  
TN_RING_TYPE_VCE2_INDEX);
-   }
-   if (r) {
-   dev_err(rdev->dev, "VCE init error (%d).\n", r);
-   rdev->ring[TN_RING_TYPE_VCE1_INDEX].ring_size = 0;
-   rdev->ring[TN_RING_TYPE_VCE2_INDEX].ring_size = 0;
-   }
+   si_vce_start(rdev);

/* Enable IRQ */
if (!rdev->irq.installed) {
@@ -7088,23 +7159,7 @@ static int si_startup(struct radeon_device *rdev)
return r;

si_uvd_resume(rdev);
-
-   r = -ENOENT;
-
-   ring = >ring[TN_RING_TYPE_VCE1_INDEX];
-   if (ring->ring_size)
-   r = radeon_ring_init(rdev, ring, ring->ring_size, 0,
-VCE_CMD_NO_OP);
-

[PATCH 08/14] drm/radeon: consolidate ni vce initialization and startup code.

2016-03-18 Thread Jérôme Glisse
From: Jérome Glisse 

This match the exact same control flow as existing code. It just
use goto instead of multiple levels of if/else. It also clarify
early initialization failures by clearing rdev->has_vce doing so
does not change end result from hardware point of view, it only
avoids printing more error messages down the line and thus only
the original error is reported.

Signed-off-by: Jérôme Glisse 
Cc: Alex Deucher 
Cc: Christian König 
---
 drivers/gpu/drm/radeon/ni.c | 139 +---
 1 file changed, 91 insertions(+), 48 deletions(-)

diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c
index 38c3947..ec0aac8 100644
--- a/drivers/gpu/drm/radeon/ni.c
+++ b/drivers/gpu/drm/radeon/ni.c
@@ -2069,6 +2069,93 @@ static void cayman_uvd_resume(struct radeon_device *rdev)
}
 }

+static void cayman_vce_init(struct radeon_device *rdev)
+{
+   int r;
+
+   /* Only set for CHIP_ARUBA */
+   if (!rdev->has_vce)
+   return;
+
+   r = radeon_vce_init(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed VCE (%d) init.\n", r);
+   /*
+* At this point rdev->vce.vcpu_bo is NULL which trickles down
+* to early fails cayman_vce_start() and thus nothing happens
+* there. So it is pointless to try to go through that code
+* hence why we disable vce here.
+*/
+   rdev->has_vce = 0;
+   return;
+   }
+   rdev->ring[TN_RING_TYPE_VCE1_INDEX].ring_obj = NULL;
+   r600_ring_init(rdev, >ring[TN_RING_TYPE_VCE1_INDEX], 4096);
+   rdev->ring[TN_RING_TYPE_VCE2_INDEX].ring_obj = NULL;
+   r600_ring_init(rdev, >ring[TN_RING_TYPE_VCE2_INDEX], 4096);
+}
+
+static void cayman_vce_start(struct radeon_device *rdev)
+{
+   int r;
+
+   if (!rdev->has_vce)
+   return;
+
+   r = radeon_vce_resume(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed VCE resume (%d).\n", r);
+   goto error;
+   }
+   r = vce_v1_0_resume(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed VCE resume (%d).\n", r);
+   goto error;
+   }
+   r = radeon_fence_driver_start_ring(rdev, TN_RING_TYPE_VCE1_INDEX);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing VCE1 fences (%d).\n", 
r);
+   goto error;
+   }
+   r = radeon_fence_driver_start_ring(rdev, TN_RING_TYPE_VCE2_INDEX);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing VCE2 fences (%d).\n", 
r);
+   goto error;
+   }
+   return;
+
+error:
+   rdev->ring[TN_RING_TYPE_VCE1_INDEX].ring_size = 0;
+   rdev->ring[TN_RING_TYPE_VCE2_INDEX].ring_size = 0;
+}
+
+static void cayman_vce_resume(struct radeon_device *rdev)
+{
+   struct radeon_ring *ring;
+   int r;
+
+   if (!rdev->has_vce || !rdev->ring[TN_RING_TYPE_VCE1_INDEX].ring_size)
+   return;
+
+   ring = >ring[TN_RING_TYPE_VCE1_INDEX];
+   r = radeon_ring_init(rdev, ring, ring->ring_size, 0, 0x0);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing VCE1 ring (%d).\n", r);
+   return;
+   }
+   ring = >ring[TN_RING_TYPE_VCE2_INDEX];
+   r = radeon_ring_init(rdev, ring, ring->ring_size, 0, 0x0);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing VCE1 ring (%d).\n", r);
+   return;
+   }
+   r = vce_v1_0_init(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing VCE (%d).\n", r);
+   return;
+   }
+}
+
 static int cayman_startup(struct radeon_device *rdev)
 {
struct radeon_ring *ring = >ring[RADEON_RING_TYPE_GFX_INDEX];
@@ -2124,25 +2211,7 @@ static int cayman_startup(struct radeon_device *rdev)
}

cayman_uvd_start(rdev);
-
-   if (rdev->family == CHIP_ARUBA) {
-   r = radeon_vce_resume(rdev);
-   if (!r)
-   r = vce_v1_0_resume(rdev);
-
-   if (!r)
-   r = radeon_fence_driver_start_ring(rdev,
-  
TN_RING_TYPE_VCE1_INDEX);
-   if (!r)
-   r = radeon_fence_driver_start_ring(rdev,
-  
TN_RING_TYPE_VCE2_INDEX);
-
-   if (r) {
-   dev_err(rdev->dev, "VCE init error (%d).\n", r);
-   rdev->ring[TN_RING_TYPE_VCE1_INDEX].ring_size = 0;
-   rdev->ring[TN_RING_TYPE_VCE2_INDEX].ring_size = 0;
-   }
-   }
+   cayman_vce_start(rdev);

r = radeon_fence_driver_start_ring(rdev, CAYMAN_RING_TYPE_CP1_INDEX);
if (r) {
@@ -2212,21 +2281,7 @@ static int cayman_startup(struct radeon_device *rdev)
return r;


[PATCH 07/14] drm/radeon: add a vce flag to know if need to initialize vce or not.

2016-03-18 Thread Jérôme Glisse
From: Jérome Glisse 

This will later on serve for module option to disable vce.

Signed-off-by: Jérôme Glisse 
Cc: Alex Deucher 
Cc: Christian König 
---
 drivers/gpu/drm/radeon/radeon.h  |  1 +
 drivers/gpu/drm/radeon/radeon_asic.c | 11 +--
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 007be29..8ac3e07 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -2423,6 +2423,7 @@ struct radeon_device {
int num_crtc; /* number of crtcs */
struct mutex dc_hw_i2c_mutex; /* display controller hw i2c mutex */
bool has_uvd;
+   bool has_vce;
struct r600_audio audio; /* audio stuff */
struct notifier_block acpi_nb;
/* only one userspace can use Hyperz features or CMASK at a time */
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c 
b/drivers/gpu/drm/radeon/radeon_asic.c
index 7d5a36d..46a4ced 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -2324,6 +2324,7 @@ int radeon_asic_init(struct radeon_device *rdev)
rdev->num_crtc = 2;

rdev->has_uvd = false;
+   rdev->has_vce = false;

switch (rdev->family) {
case CHIP_R100:
@@ -2454,6 +2455,7 @@ int radeon_asic_init(struct radeon_device *rdev)
/* set num crtcs */
rdev->num_crtc = 4;
rdev->has_uvd = true;
+   rdev->has_vce = true;
rdev->cg_flags =
RADEON_CG_SUPPORT_VCE_MGCG;
break;
@@ -2470,10 +2472,13 @@ int radeon_asic_init(struct radeon_device *rdev)
rdev->num_crtc = 2;
else
rdev->num_crtc = 6;
-   if (rdev->family == CHIP_HAINAN)
+   if (rdev->family == CHIP_HAINAN) {
rdev->has_uvd = false;
-   else
+   rdev->has_vce = false;
+   } else {
rdev->has_uvd = true;
+   rdev->has_vce = true;
+   }
switch (rdev->family) {
case CHIP_TAHITI:
rdev->cg_flags =
@@ -2578,6 +2583,7 @@ int radeon_asic_init(struct radeon_device *rdev)
rdev->asic = _asic;
rdev->num_crtc = 6;
rdev->has_uvd = true;
+   rdev->has_vce = true;
if (rdev->family == CHIP_BONAIRE) {
rdev->cg_flags =
RADEON_CG_SUPPORT_GFX_MGCG |
@@ -2678,6 +2684,7 @@ int radeon_asic_init(struct radeon_device *rdev)
RADEON_PG_SUPPORT_SAMU;*/
}
rdev->has_uvd = true;
+   rdev->has_vce = true;
break;
default:
/* FIXME: not supported yet */
-- 
1.8.3.1



[PATCH 06/14] drm/radeon: consolidate cik uvd initialization and startup code.

2016-03-18 Thread Jérôme Glisse
From: Jérome Glisse 

This match the exact same control flow as existing code. It just
use goto instead of multiple levels of if/else. It also clarify
early initialization failures by clearing rdev->has_uvd doing so
does not change end result from hardware point of view, it only
avoids printing more error messages down the line and thus only
the original error is reported.

Signed-off-by: Jérôme Glisse 
Cc: Alex Deucher 
Cc: Christian König 
---
 drivers/gpu/drm/radeon/cik.c | 108 +++
 1 file changed, 79 insertions(+), 29 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index f2a4c0f..be14669 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -8496,6 +8496,78 @@ restart_ih:
 /*
  * startup/shutdown callbacks
  */
+static void cik_uvd_init(struct radeon_device *rdev)
+{
+   int r;
+
+   if (!rdev->has_uvd)
+   return;
+
+   r = radeon_uvd_init(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed UVD (%d) init.\n", r);
+   /*
+* At this point rdev->uvd.vcpu_bo is NULL which trickles down
+* to early fails cik_uvd_start() and thus nothing happens
+* there. So it is pointless to try to go through that code
+* hence why we disable uvd here.
+*/
+   rdev->has_uvd = 0;
+   return;
+   }
+   rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_obj = NULL;
+   r600_ring_init(rdev, >ring[R600_RING_TYPE_UVD_INDEX], 4096);
+}
+
+static void cik_uvd_start(struct radeon_device *rdev)
+{
+   int r;
+
+   if (!rdev->has_uvd)
+   return;
+
+   r = radeon_uvd_resume(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed UVD resume (%d).\n", r);
+   goto error;
+   }
+   r = uvd_v4_2_resume(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed UVD 4.2 resume (%d).\n", r);
+   goto error;
+   }
+   r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_UVD_INDEX);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing UVD fences (%d).\n", r);
+   goto error;
+   }
+   return;
+
+error:
+   rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0;
+}
+
+static void cik_uvd_resume(struct radeon_device *rdev)
+{
+   struct radeon_ring *ring;
+   int r;
+
+   if (!rdev->has_uvd || !rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size)
+   return;
+
+   ring = >ring[R600_RING_TYPE_UVD_INDEX];
+   r = radeon_ring_init(rdev, ring, ring->ring_size, 0, RADEON_CP_PACKET2);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing UVD ring (%d).\n", r);
+   return;
+   }
+   r = uvd_v1_0_init(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing UVD (%d).\n", r);
+   return;
+   }
+}
+
 /**
  * cik_startup - program the asic to a functional state
  *
@@ -8598,18 +8670,7 @@ static int cik_startup(struct radeon_device *rdev)
return r;
}

-   r = radeon_uvd_resume(rdev);
-   if (!r) {
-   r = uvd_v4_2_resume(rdev);
-   if (!r) {
-   r = radeon_fence_driver_start_ring(rdev,
-  
R600_RING_TYPE_UVD_INDEX);
-   if (r)
-   dev_err(rdev->dev, "UVD fences init error 
(%d).\n", r);
-   }
-   }
-   if (r)
-   rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0;
+   cik_uvd_start(rdev);

r = radeon_vce_resume(rdev);
if (!r) {
@@ -8701,15 +8762,7 @@ static int cik_startup(struct radeon_device *rdev)
if (r)
return r;

-   ring = >ring[R600_RING_TYPE_UVD_INDEX];
-   if (ring->ring_size) {
-   r = radeon_ring_init(rdev, ring, ring->ring_size, 0,
-RADEON_CP_PACKET2);
-   if (!r)
-   r = uvd_v1_0_init(rdev);
-   if (r)
-   DRM_ERROR("radeon: failed initializing UVD (%d).\n", r);
-   }
+   cik_uvd_resume(rdev);

r = -ENOENT;

@@ -8802,8 +8855,10 @@ int cik_suspend(struct radeon_device *rdev)
radeon_vm_manager_fini(rdev);
cik_cp_enable(rdev, false);
cik_sdma_enable(rdev, false);
-   uvd_v1_0_fini(rdev);
-   radeon_uvd_suspend(rdev);
+   if (rdev->has_uvd) {
+   uvd_v1_0_fini(rdev);
+   radeon_uvd_suspend(rdev);
+   }
radeon_vce_suspend(rdev);
cik_fini_pg(rdev);
cik_fini_cg(rdev);
@@ -8930,12 +8985,7 @@ int cik_init(struct radeon_device *rdev)
ring->ring_obj = NULL;
r600_ring_init(rdev, ring, 256 * 1024);

-   r = radeon_uvd_init(rdev);
-   if (!r) {
-

[PATCH 05/14] drm/radeon: consolidate si uvd initialization and startup code.

2016-03-18 Thread Jérôme Glisse
From: Jérome Glisse 

This match the exact same control flow as existing code. It just
use goto instead of multiple levels of if/else. It also clarify
early initialization failures by clearing rdev->has_uvd doing so
does not change end result from hardware point of view, it only
avoids printing more error messages down the line and thus only
the original error is reported.

Signed-off-by: Jérôme Glisse 
Cc: Alex Deucher 
Cc: Christian König 
---
 drivers/gpu/drm/radeon/si.c | 100 +++-
 1 file changed, 70 insertions(+), 30 deletions(-)

diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c
index e894be2..067c384 100644
--- a/drivers/gpu/drm/radeon/si.c
+++ b/drivers/gpu/drm/radeon/si.c
@@ -6868,6 +6868,73 @@ restart_ih:
 /*
  * startup/shutdown callbacks
  */
+static void si_uvd_init(struct radeon_device *rdev)
+{
+   int r;
+
+   if (!rdev->has_uvd)
+   return;
+
+   r = radeon_uvd_init(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed UVD (%d) init.\n", r);
+   /*
+* At this point rdev->uvd.vcpu_bo is NULL which trickles down
+* to early fails uvd_v2_2_resume() and thus nothing happens
+* there. So it is pointless to try to go through that code
+* hence why we disable uvd here.
+*/
+   rdev->has_uvd = 0;
+   return;
+   }
+   rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_obj = NULL;
+   r600_ring_init(rdev, >ring[R600_RING_TYPE_UVD_INDEX], 4096);
+}
+
+static void si_uvd_start(struct radeon_device *rdev)
+{
+   int r;
+
+   if (!rdev->has_uvd)
+   return;
+
+   r = uvd_v2_2_resume(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed UVD resume (%d).\n", r);
+   goto error;
+   }
+   r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_UVD_INDEX);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing UVD fences (%d).\n", r);
+   goto error;
+   }
+   return;
+
+error:
+   rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0;
+}
+
+static void si_uvd_resume(struct radeon_device *rdev)
+{
+   struct radeon_ring *ring;
+   int r;
+
+   if (!rdev->has_uvd || !rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size)
+   return;
+
+   ring = >ring[R600_RING_TYPE_UVD_INDEX];
+   r = radeon_ring_init(rdev, ring, ring->ring_size, 0, RADEON_CP_PACKET2);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing UVD ring (%d).\n", r);
+   return;
+   }
+   r = uvd_v1_0_init(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing UVD (%d).\n", r);
+   return;
+   }
+}
+
 static int si_startup(struct radeon_device *rdev)
 {
struct radeon_ring *ring;
@@ -6946,17 +7013,7 @@ static int si_startup(struct radeon_device *rdev)
return r;
}

-   if (rdev->has_uvd) {
-   r = uvd_v2_2_resume(rdev);
-   if (!r) {
-   r = radeon_fence_driver_start_ring(rdev,
-  
R600_RING_TYPE_UVD_INDEX);
-   if (r)
-   dev_err(rdev->dev, "UVD fences init error 
(%d).\n", r);
-   }
-   if (r)
-   rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0;
-   }
+   si_uvd_start(rdev);

r = radeon_vce_resume(rdev);
if (!r) {
@@ -7030,17 +7087,7 @@ static int si_startup(struct radeon_device *rdev)
if (r)
return r;

-   if (rdev->has_uvd) {
-   ring = >ring[R600_RING_TYPE_UVD_INDEX];
-   if (ring->ring_size) {
-   r = radeon_ring_init(rdev, ring, ring->ring_size, 0,
-RADEON_CP_PACKET2);
-   if (!r)
-   r = uvd_v1_0_init(rdev);
-   if (r)
-   DRM_ERROR("radeon: failed initializing UVD 
(%d).\n", r);
-   }
-   }
+   si_uvd_resume(rdev);

r = -ENOENT;

@@ -7216,14 +7263,7 @@ int si_init(struct radeon_device *rdev)
ring->ring_obj = NULL;
r600_ring_init(rdev, ring, 64 * 1024);

-   if (rdev->has_uvd) {
-   r = radeon_uvd_init(rdev);
-   if (!r) {
-   ring = >ring[R600_RING_TYPE_UVD_INDEX];
-   ring->ring_obj = NULL;
-   r600_ring_init(rdev, ring, 4096);
-   }
-   }
+   si_uvd_init(rdev);

r = radeon_vce_init(rdev);
if (!r) {
-- 
1.8.3.1



[PATCH 04/14] drm/radeon: consolidate ni uvd initialization and startup code.

2016-03-18 Thread Jérôme Glisse
From: Jérome Glisse 

This match the exact same control flow as existing code. It just
use goto instead of multiple levels of if/else. It also clarify
early initialization failures by clearing rdev->has_uvd doing so
does not change end result from hardware point of view, it only
avoids printing more error messages down the line and thus only
the original error is reported.

Signed-off-by: Jérôme Glisse 
Cc: Alex Deucher 
Cc: Christian König 
---
 drivers/gpu/drm/radeon/ni.c | 100 
 1 file changed, 74 insertions(+), 26 deletions(-)

diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c
index b88d63c9..38c3947 100644
--- a/drivers/gpu/drm/radeon/ni.c
+++ b/drivers/gpu/drm/radeon/ni.c
@@ -2002,6 +2002,73 @@ bool cayman_gfx_is_lockup(struct radeon_device *rdev, 
struct radeon_ring *ring)
return radeon_ring_test_lockup(rdev, ring);
 }

+static void cayman_uvd_init(struct radeon_device *rdev)
+{
+   int r;
+
+   if (!rdev->has_uvd)
+   return;
+
+   r = radeon_uvd_init(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed UVD (%d) init.\n", r);
+   /*
+* At this point rdev->uvd.vcpu_bo is NULL which trickles down
+* to early fails uvd_v2_2_resume() and thus nothing happens
+* there. So it is pointless to try to go through that code
+* hence why we disable uvd here.
+*/
+   rdev->has_uvd = 0;
+   return;
+   }
+   rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_obj = NULL;
+   r600_ring_init(rdev, >ring[R600_RING_TYPE_UVD_INDEX], 4096);
+}
+
+static void cayman_uvd_start(struct radeon_device *rdev)
+{
+   int r;
+
+   if (!rdev->has_uvd)
+   return;
+
+   r = uvd_v2_2_resume(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed UVD resume (%d).\n", r);
+   goto error;
+   }
+   r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_UVD_INDEX);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing UVD fences (%d).\n", r);
+   goto error;
+   }
+   return;
+
+error:
+   rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0;
+}
+
+static void cayman_uvd_resume(struct radeon_device *rdev)
+{
+   struct radeon_ring *ring;
+   int r;
+
+   if (!rdev->has_uvd || !rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size)
+   return;
+
+   ring = >ring[R600_RING_TYPE_UVD_INDEX];
+   r = radeon_ring_init(rdev, ring, ring->ring_size, 0, RADEON_CP_PACKET2);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing UVD ring (%d).\n", r);
+   return;
+   }
+   r = uvd_v1_0_init(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing UVD (%d).\n", r);
+   return;
+   }
+}
+
 static int cayman_startup(struct radeon_device *rdev)
 {
struct radeon_ring *ring = >ring[RADEON_RING_TYPE_GFX_INDEX];
@@ -2056,15 +2123,7 @@ static int cayman_startup(struct radeon_device *rdev)
return r;
}

-   r = uvd_v2_2_resume(rdev);
-   if (!r) {
-   r = radeon_fence_driver_start_ring(rdev,
-  R600_RING_TYPE_UVD_INDEX);
-   if (r)
-   dev_err(rdev->dev, "UVD fences init error (%d).\n", r);
-   }
-   if (r)
-   rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0;
+   cayman_uvd_start(rdev);

if (rdev->family == CHIP_ARUBA) {
r = radeon_vce_resume(rdev);
@@ -2152,15 +2211,7 @@ static int cayman_startup(struct radeon_device *rdev)
if (r)
return r;

-   ring = >ring[R600_RING_TYPE_UVD_INDEX];
-   if (ring->ring_size) {
-   r = radeon_ring_init(rdev, ring, ring->ring_size, 0,
-RADEON_CP_PACKET2);
-   if (!r)
-   r = uvd_v1_0_init(rdev);
-   if (r)
-   DRM_ERROR("radeon: failed initializing UVD (%d).\n", r);
-   }
+   cayman_uvd_resume(rdev);

if (rdev->family == CHIP_ARUBA) {
ring = >ring[TN_RING_TYPE_VCE1_INDEX];
@@ -2230,8 +2281,10 @@ int cayman_suspend(struct radeon_device *rdev)
radeon_vm_manager_fini(rdev);
cayman_cp_enable(rdev, false);
cayman_dma_stop(rdev);
-   uvd_v1_0_fini(rdev);
-   radeon_uvd_suspend(rdev);
+   if (rdev->has_uvd) {
+   uvd_v1_0_fini(rdev);
+   radeon_uvd_suspend(rdev);
+   }
evergreen_irq_suspend(rdev);
radeon_wb_disable(rdev);
cayman_pcie_gart_disable(rdev);
@@ -2325,12 +2378,7 @@ int cayman_init(struct radeon_device *rdev)
ring->ring_obj = NULL;
r600_ring_init(rdev, ring, 64 * 1024);

-   r = radeon_uvd_init(rdev);
-   if (!r) 

[PATCH 03/14] drm/radeon: consolidate evergreen uvd initialization and startup code.

2016-03-18 Thread Jérôme Glisse
From: Jérome Glisse 

This match the exact same control flow as existing code. It just
use goto instead of multiple levels of if/else. It also clarify
early initialization failures by clearing rdev->has_uvd doing so
does not change end result from hardware point of view, it only
avoids printing more error messages down the line and thus only
the original error is reported.

Signed-off-by: Jérôme Glisse 
Cc: Alex Deucher 
Cc: Christian König 
---
 drivers/gpu/drm/radeon/evergreen.c | 102 +++--
 1 file changed, 74 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/radeon/evergreen.c 
b/drivers/gpu/drm/radeon/evergreen.c
index 76c4bdf..cc0cf9a 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -5363,6 +5363,73 @@ restart_ih:
return IRQ_HANDLED;
 }

+static void evergreen_uvd_init(struct radeon_device *rdev)
+{
+   int r;
+
+   if (!rdev->has_uvd)
+   return;
+
+   r = radeon_uvd_init(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed UVD (%d) init.\n", r);
+   /*
+* At this point rdev->uvd.vcpu_bo is NULL which trickles down
+* to early fails uvd_v2_2_resume() and thus nothing happens
+* there. So it is pointless to try to go through that code
+* hence why we disable uvd here.
+*/
+   rdev->has_uvd = 0;
+   return;
+   }
+   rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_obj = NULL;
+   r600_ring_init(rdev, >ring[R600_RING_TYPE_UVD_INDEX], 4096);
+}
+
+static void evergreen_uvd_start(struct radeon_device *rdev)
+{
+   int r;
+
+   if (!rdev->has_uvd)
+   return;
+
+   r = uvd_v2_2_resume(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed UVD resume (%d).\n", r);
+   goto error;
+   }
+   r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_UVD_INDEX);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing UVD fences (%d).\n", r);
+   goto error;
+   }
+   return;
+
+error:
+   rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0;
+}
+
+static void evergreen_uvd_resume(struct radeon_device *rdev)
+{
+   struct radeon_ring *ring;
+   int r;
+
+   if (!rdev->has_uvd || !rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size)
+   return;
+
+   ring = >ring[R600_RING_TYPE_UVD_INDEX];
+   r = radeon_ring_init(rdev, ring, ring->ring_size, 0, RADEON_CP_PACKET2);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing UVD ring (%d).\n", r);
+   return;
+   }
+   r = uvd_v1_0_init(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing UVD (%d).\n", r);
+   return;
+   }
+}
+
 static int evergreen_startup(struct radeon_device *rdev)
 {
struct radeon_ring *ring;
@@ -5427,16 +5494,7 @@ static int evergreen_startup(struct radeon_device *rdev)
return r;
}

-   r = uvd_v2_2_resume(rdev);
-   if (!r) {
-   r = radeon_fence_driver_start_ring(rdev,
-  R600_RING_TYPE_UVD_INDEX);
-   if (r)
-   dev_err(rdev->dev, "UVD fences init error (%d).\n", r);
-   }
-
-   if (r)
-   rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0;
+   evergreen_uvd_start(rdev);

/* Enable IRQ */
if (!rdev->irq.installed) {
@@ -5475,16 +5533,7 @@ static int evergreen_startup(struct radeon_device *rdev)
if (r)
return r;

-   ring = >ring[R600_RING_TYPE_UVD_INDEX];
-   if (ring->ring_size) {
-   r = radeon_ring_init(rdev, ring, ring->ring_size, 0,
-RADEON_CP_PACKET2);
-   if (!r)
-   r = uvd_v1_0_init(rdev);
-
-   if (r)
-   DRM_ERROR("radeon: error initializing UVD (%d).\n", r);
-   }
+   evergreen_uvd_resume(rdev);

r = radeon_ib_pool_init(rdev);
if (r) {
@@ -5539,8 +5588,10 @@ int evergreen_suspend(struct radeon_device *rdev)
 {
radeon_pm_suspend(rdev);
radeon_audio_fini(rdev);
-   uvd_v1_0_fini(rdev);
-   radeon_uvd_suspend(rdev);
+   if (rdev->has_uvd) {
+   uvd_v1_0_fini(rdev);
+   radeon_uvd_suspend(rdev);
+   }
r700_cp_stop(rdev);
r600_dma_stop(rdev);
evergreen_irq_suspend(rdev);
@@ -5641,12 +5692,7 @@ int evergreen_init(struct radeon_device *rdev)
rdev->ring[R600_RING_TYPE_DMA_INDEX].ring_obj = NULL;
r600_ring_init(rdev, >ring[R600_RING_TYPE_DMA_INDEX], 64 * 1024);

-   r = radeon_uvd_init(rdev);
-   if (!r) {
-   rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_obj = NULL;
-   r600_ring_init(rdev, 

[PATCH 02/14] drm/radeon: consolidate rv770 uvd initialization and startup code.

2016-03-18 Thread Jérôme Glisse
From: Jérome Glisse 

This match the exact same control flow as existing code. It just
use goto instead of multiple levels of if/else. It also clarify
early initialization failures by clearing rdev->has_uvd doing so
does not change end result from hardware point of view, it only
avoids printing more error messages down the line and thus only
the original error is reported.

Signed-off-by: Jérôme Glisse 
Cc: Alex Deucher 
Cc: Christian König 
---
 drivers/gpu/drm/radeon/rv770.c | 102 ++---
 1 file changed, 74 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index 01ee96a..fa0b03c 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -1681,6 +1681,73 @@ static int rv770_mc_init(struct radeon_device *rdev)
return 0;
 }

+static void rv770_uvd_init(struct radeon_device *rdev)
+{
+   int r;
+
+   if (!rdev->has_uvd)
+   return;
+
+   r = radeon_uvd_init(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed UVD (%d) init.\n", r);
+   /*
+* At this point rdev->uvd.vcpu_bo is NULL which trickles down
+* to early fails uvd_v2_2_resume() and thus nothing happens
+* there. So it is pointless to try to go through that code
+* hence why we disable uvd here.
+*/
+   rdev->has_uvd = 0;
+   return;
+   }
+   rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_obj = NULL;
+   r600_ring_init(rdev, >ring[R600_RING_TYPE_UVD_INDEX], 4096);
+}
+
+static void rv770_uvd_start(struct radeon_device *rdev)
+{
+   int r;
+
+   if (!rdev->has_uvd)
+   return;
+
+   r = uvd_v2_2_resume(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed UVD resume (%d).\n", r);
+   goto error;
+   }
+   r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_UVD_INDEX);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing UVD fences (%d).\n", r);
+   goto error;
+   }
+   return;
+
+error:
+   rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0;
+}
+
+static void rv770_uvd_resume(struct radeon_device *rdev)
+{
+   struct radeon_ring *ring;
+   int r;
+
+   if (!rdev->has_uvd || !rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size)
+   return;
+
+   ring = >ring[R600_RING_TYPE_UVD_INDEX];
+   r = radeon_ring_init(rdev, ring, ring->ring_size, 0, RADEON_CP_PACKET2);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing UVD ring (%d).\n", r);
+   return;
+   }
+   r = uvd_v1_0_init(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing UVD (%d).\n", r);
+   return;
+   }
+}
+
 static int rv770_startup(struct radeon_device *rdev)
 {
struct radeon_ring *ring;
@@ -1723,16 +1790,7 @@ static int rv770_startup(struct radeon_device *rdev)
return r;
}

-   r = uvd_v2_2_resume(rdev);
-   if (!r) {
-   r = radeon_fence_driver_start_ring(rdev,
-  R600_RING_TYPE_UVD_INDEX);
-   if (r)
-   dev_err(rdev->dev, "UVD fences init error (%d).\n", r);
-   }
-
-   if (r)
-   rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0;
+   rv770_uvd_start(rdev);

/* Enable IRQ */
if (!rdev->irq.installed) {
@@ -1772,16 +1830,7 @@ static int rv770_startup(struct radeon_device *rdev)
if (r)
return r;

-   ring = >ring[R600_RING_TYPE_UVD_INDEX];
-   if (ring->ring_size) {
-   r = radeon_ring_init(rdev, ring, ring->ring_size, 0,
-RADEON_CP_PACKET2);
-   if (!r)
-   r = uvd_v1_0_init(rdev);
-
-   if (r)
-   DRM_ERROR("radeon: failed initializing UVD (%d).\n", r);
-   }
+   rv770_uvd_resume(rdev);

r = radeon_ib_pool_init(rdev);
if (r) {
@@ -1831,8 +1880,10 @@ int rv770_suspend(struct radeon_device *rdev)
 {
radeon_pm_suspend(rdev);
radeon_audio_fini(rdev);
-   uvd_v1_0_fini(rdev);
-   radeon_uvd_suspend(rdev);
+   if (rdev->has_uvd) {
+   uvd_v1_0_fini(rdev);
+   radeon_uvd_suspend(rdev);
+   }
r700_cp_stop(rdev);
r600_dma_stop(rdev);
r600_irq_suspend(rdev);
@@ -1917,12 +1968,7 @@ int rv770_init(struct radeon_device *rdev)
rdev->ring[R600_RING_TYPE_DMA_INDEX].ring_obj = NULL;
r600_ring_init(rdev, >ring[R600_RING_TYPE_DMA_INDEX], 64 * 1024);

-   r = radeon_uvd_init(rdev);
-   if (!r) {
-   rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_obj = NULL;
-   r600_ring_init(rdev, >ring[R600_RING_TYPE_UVD_INDEX],
-

[PATCH 01/14] drm/radeon: consolidate r600 uvd initialization and startup code.

2016-03-18 Thread Jérôme Glisse
From: Jérome Glisse 

This match the exact same control flow as existing code. It just
use goto instead of multiple levels of if/else. It also clarify
early initialization failures by clearing rdev->has_uvd doing so
does not change end result from hardware point of view, it only
avoids printing more error messages down the line and thus only
the original error is reported.

Signed-off-by: Jérôme Glisse 
Cc: Alex Deucher 
Cc: Christian König 
---
 drivers/gpu/drm/radeon/r600.c | 99 ++-
 1 file changed, 70 insertions(+), 29 deletions(-)

diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index f86ab69..24fa982 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -3035,6 +3035,73 @@ void r600_clear_surface_reg(struct radeon_device *rdev, 
int reg)
/* FIXME: implement */
 }

+static void r600_uvd_init(struct radeon_device *rdev)
+{
+   int r;
+
+   if (!rdev->has_uvd)
+   return;
+
+   r = radeon_uvd_init(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed UVD (%d) init.\n", r);
+   /*
+* At this point rdev->uvd.vcpu_bo is NULL which trickles down
+* to early fails uvd_v1_0_resume() and thus nothing happens
+* there. So it is pointless to try to go through that code
+* hence why we disable uvd here.
+*/
+   rdev->has_uvd = 0;
+   return;
+   }
+   rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_obj = NULL;
+   r600_ring_init(rdev, >ring[R600_RING_TYPE_UVD_INDEX], 4096);
+}
+
+static void r600_uvd_start(struct radeon_device *rdev)
+{
+   int r;
+
+   if (!rdev->has_uvd)
+   return;
+
+   r = uvd_v1_0_resume(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed UVD resume (%d).\n", r);
+   goto error;
+   }
+   r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_UVD_INDEX);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing UVD fences (%d).\n", r);
+   goto error;
+   }
+   return;
+
+error:
+   rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0;
+}
+
+static void r600_uvd_resume(struct radeon_device *rdev)
+{
+   struct radeon_ring *ring;
+   int r;
+
+   if (!rdev->has_uvd || !rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size)
+   return;
+
+   ring = >ring[R600_RING_TYPE_UVD_INDEX];
+   r = radeon_ring_init(rdev, ring, ring->ring_size, 0, RADEON_CP_PACKET2);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing UVD ring (%d).\n", r);
+   return;
+   }
+   r = uvd_v1_0_init(rdev);
+   if (r) {
+   dev_err(rdev->dev, "failed initializing UVD (%d).\n", r);
+   return;
+   }
+}
+
 static int r600_startup(struct radeon_device *rdev)
 {
struct radeon_ring *ring;
@@ -3070,17 +3137,7 @@ static int r600_startup(struct radeon_device *rdev)
return r;
}

-   if (rdev->has_uvd) {
-   r = uvd_v1_0_resume(rdev);
-   if (!r) {
-   r = radeon_fence_driver_start_ring(rdev, 
R600_RING_TYPE_UVD_INDEX);
-   if (r) {
-   dev_err(rdev->dev, "failed initializing UVD 
fences (%d).\n", r);
-   }
-   }
-   if (r)
-   rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0;
-   }
+   r600_uvd_start(rdev);

/* Enable IRQ */
if (!rdev->irq.installed) {
@@ -3110,17 +3167,7 @@ static int r600_startup(struct radeon_device *rdev)
if (r)
return r;

-   if (rdev->has_uvd) {
-   ring = >ring[R600_RING_TYPE_UVD_INDEX];
-   if (ring->ring_size) {
-   r = radeon_ring_init(rdev, ring, ring->ring_size, 0,
-RADEON_CP_PACKET2);
-   if (!r)
-   r = uvd_v1_0_init(rdev);
-   if (r)
-   DRM_ERROR("radeon: failed initializing UVD 
(%d).\n", r);
-   }
-   }
+   r600_uvd_resume(rdev);

r = radeon_ib_pool_init(rdev);
if (r) {
@@ -3264,13 +3311,7 @@ int r600_init(struct radeon_device *rdev)
rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL;
r600_ring_init(rdev, >ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 
1024);

-   if (rdev->has_uvd) {
-   r = radeon_uvd_init(rdev);
-   if (!r) {
-   rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_obj = NULL;
-   r600_ring_init(rdev, 
>ring[R600_RING_TYPE_UVD_INDEX], 4096);
-   }
-   }
+   r600_uvd_init(rdev);

rdev->ih.ring_obj = NULL;
r600_ih_ring_init(rdev, 64 * 1024);
-- 

[PATCH 00/14] drm/radeon: uvd/vce cleanup and fix for hibernation

2016-03-18 Thread Jérôme Glisse
So all patches does not change the logic or outcome (from hw register
write point of view) only what error messages get printed on failure.

Patch 13 just add a new flag to asic reset so we can force hard reset.

Patch 14 takes advantages of that for the hibernation case and hard
reset during freeze. It seems to works well for several hibernation
cycles (both real hibernation and also when using PM_DEBUG facilities).

All this was only test on southern island laptop (si), i did however
read over and over the various patches to check that i did not change
behavior. I splitted them for each asic generation to make bisection
easier in the unlikely case that i did miss something.

Please review.

Cheers,
Jérôme



[PATCH 3/4] drm/radeon: consolidate uvd/vce initialization, resume and suspend.

2016-03-16 Thread Jérôme Glisse
From: Jérome Glisse 

This consolidate uvd/vce into a common shape for all generation. It
also leverage the rdev->has_uvd flags to know what it is useless to
try to resume/suspend uvd/vce block.

There is no functional changes when there is no error. On error the
device driver will behave differently than before after this patch.
It should now safely ignore uvd/vce errors and keeps normal operation
of others engine. This is an improvement over current situation where
we have different behavior depending on GPU generation and on what
fails.

Finaly this is a preparatory step for a patch which allow to disable
uvd/vce as a driver option.

This have only been tested on southern island so please test it on
other generations (i do not have hardware handy for now).

Signed-off-by: Jérôme Glisse 
Cc: Alex Deucher 
Cc: Christian König 
---
 drivers/gpu/drm/radeon/cik.c   | 226 ++
 drivers/gpu/drm/radeon/evergreen.c | 122 ++-
 drivers/gpu/drm/radeon/ni.c| 240 +
 drivers/gpu/drm/radeon/r600.c  | 113 -
 drivers/gpu/drm/radeon/rv770.c | 122 ++-
 drivers/gpu/drm/radeon/si.c| 213 
 drivers/gpu/drm/radeon/uvd_v4_2.c  |   5 +
 7 files changed, 724 insertions(+), 317 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index f2a4c0f..489e202 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -8496,6 +8496,142 @@ restart_ih:
 /*
  * startup/shutdown callbacks
  */
+
+static void cik_uvd_vce_init(struct radeon_device *rdev)
+{
+   struct radeon_ring *ring;
+   int r;
+
+   if (!rdev->has_uvd)
+   return;
+
+   r = radeon_uvd_init(rdev);
+   if (r)
+   goto error_uvd;
+   ring = >ring[R600_RING_TYPE_UVD_INDEX];
+   ring->ring_obj = NULL;
+   r600_ring_init(rdev, ring, 4096);
+
+   r = radeon_vce_init(rdev);
+   if (r)
+   goto error_vce;
+   ring = >ring[TN_RING_TYPE_VCE1_INDEX];
+   ring->ring_obj = NULL;
+   r600_ring_init(rdev, ring, 4096);
+   ring = >ring[TN_RING_TYPE_VCE2_INDEX];
+   ring->ring_obj = NULL;
+   r600_ring_init(rdev, ring, 4096);
+
+   return;
+
+error_vce:
+   radeon_uvd_fini(rdev);
+error_uvd:
+   dev_err(rdev->dev, "UVD/VCE init error (%d).\n", r);
+   /* On error just disable everything. */
+   rdev->has_uvd = 0;
+}
+
+static void cik_uvd_vce_startup(struct radeon_device *rdev)
+{
+   int r;
+
+   if (!rdev->has_uvd)
+   return;
+
+   r = uvd_v4_2_resume(rdev);
+   if (r)
+   goto error;
+   r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_UVD_INDEX);
+   if (r)
+   goto error_uvd;
+
+   r = radeon_vce_resume(rdev);
+   if (r)
+   goto error_uvd;
+   r = vce_v2_0_resume(rdev);
+   if (r)
+   goto error_vce;
+   r = radeon_fence_driver_start_ring(rdev, TN_RING_TYPE_VCE1_INDEX);
+   if (r)
+   goto error_vce;
+   r = radeon_fence_driver_start_ring(rdev, TN_RING_TYPE_VCE2_INDEX);
+   if (r)
+   goto error_vce;
+
+   return;
+
+error_vce:
+   radeon_vce_suspend(rdev);
+error_uvd:
+   radeon_uvd_suspend(rdev);
+error:
+   dev_err(rdev->dev, "UVD/VCE startup error (%d).\n", r);
+   /* On error just disable everything. */
+   radeon_vce_fini(rdev);
+   radeon_uvd_fini(rdev);
+   rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0;
+   rdev->ring[TN_RING_TYPE_VCE1_INDEX].ring_size = 0;
+   rdev->ring[TN_RING_TYPE_VCE2_INDEX].ring_size = 0;
+   rdev->has_uvd = 0;
+}
+
+static void cik_uvd_vce_resume(struct radeon_device *rdev)
+{
+   struct radeon_ring *ring;
+   int r;
+
+   if (!rdev->has_uvd)
+   return;
+
+   /* On uvd/vce error we disable uvd/vce so we should have bail above. */
+   BUG_ON(!rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size);
+   BUG_ON(!rdev->ring[TN_RING_TYPE_VCE1_INDEX].ring_size);
+   BUG_ON(!rdev->ring[TN_RING_TYPE_VCE2_INDEX].ring_size);
+
+   ring = >ring[R600_RING_TYPE_UVD_INDEX];
+   r = radeon_ring_init(rdev, ring, ring->ring_size, 0, RADEON_CP_PACKET2);
+   if (r)
+   goto error;
+   r = uvd_v1_0_init(rdev);
+   if (r)
+   goto error_uvd;
+
+   ring = >ring[TN_RING_TYPE_VCE1_INDEX];
+   r = radeon_ring_init(rdev, ring, ring->ring_size, 0, VCE_CMD_NO_OP);
+   if (r)
+   goto error_vce1;
+   ring = >ring[TN_RING_TYPE_VCE2_INDEX];
+   r = radeon_ring_init(rdev, ring, ring->ring_size, 0, VCE_CMD_NO_OP);
+   if (r)
+   goto error_vce2;
+   r = vce_v1_0_init(rdev);
+   if (r)
+   goto error_vce;
+
+   return;
+
+error_vce:
+   radeon_ring_fini(rdev, 

[PATCH 3/3] drm/ttm: under memory pressure minimize the size of memory pool

2014-08-13 Thread Jérôme Glisse
From: J?r?me Glisse 

When experiencing memory pressure we want to minimize pool size so that
memory we just shrinked is not added back again just as the next thing.

This will divide by 2 the maximum pool size for each device each time
the pool have to shrink. The limit is bumped again is next allocation
happen after one second since the last shrink. The one second delay is
obviously an arbitrary choice.

Signed-off-by: J?r?me Glisse 
Cc: Mario Kleiner 
Cc: Michel D?nzer 
Cc: Thomas Hellstrom 
Cc: Konrad Rzeszutek Wilk 
---
 drivers/gpu/drm/ttm/ttm_page_alloc.c | 35 +---
 drivers/gpu/drm/ttm/ttm_page_alloc_dma.c | 27 ++--
 2 files changed, 53 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c 
b/drivers/gpu/drm/ttm/ttm_page_alloc.c
index 09874d6..ab41adf 100644
--- a/drivers/gpu/drm/ttm/ttm_page_alloc.c
+++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c
@@ -68,6 +68,8 @@
  * @list: Pool of free uc/wc pages for fast reuse.
  * @gfp_flags: Flags to pass for alloc_page.
  * @npages: Number of pages in pool.
+ * @cur_max_size: Current maximum size for the pool.
+ * @shrink_timeout: Timeout for pool maximum size restriction.
  */
 struct ttm_page_pool {
spinlock_t  lock;
@@ -76,6 +78,8 @@ struct ttm_page_pool {
gfp_t   gfp_flags;
unsignednpages;
char*name;
+   unsignedcur_max_size;
+   unsigned long   last_shrink;
unsigned long   nfrees;
unsigned long   nrefills;
 };
@@ -289,6 +293,16 @@ static void ttm_pool_update_free_locked(struct 
ttm_page_pool *pool,
pool->nfrees += freed_pages;
 }

+static inline void ttm_pool_update_max_size(struct ttm_page_pool *pool)
+{
+   if (time_before(jiffies, pool->shrink_timeout))
+   return;
+   /* In case we reached zero bounce back to 512 pages. */
+   pool->cur_max_size = max(pool->cur_max_size << 1, 512);
+   pool->cur_max_size = min(pool->cur_max_size,
+_manager->options.max_size);
+}
+
 /**
  * Free pages from pool.
  *
@@ -407,6 +421,9 @@ ttm_pool_shrink_scan(struct shrinker *shrink, struct 
shrink_control *sc)
if (shrink_pages == 0)
break;
pool = &_manager->pools[(i + pool_offset)%NUM_POOLS];
+   /* No matter what make sure the pool do not grow in next 
second. */
+   pool->cur_max_size = pool->cur_max_size >> 1;
+   pool->shrink_timeout = jiffies + HZ;
shrink_pages = ttm_page_pool_free(pool, nr_free,
  sc->gfp_mask);
freed += nr_free - shrink_pages;
@@ -701,13 +718,12 @@ static void ttm_put_pages(struct page **pages, unsigned 
npages, int flags,
}
/* Check that we don't go over the pool limit */
npages = 0;
-   if (pool->npages > _manager->options.max_size) {
-   npages = pool->npages - _manager->options.max_size;
-   /* free at least NUM_PAGES_TO_ALLOC number of pages
-* to reduce calls to set_memory_wb */
-   if (npages < NUM_PAGES_TO_ALLOC)
-   npages = NUM_PAGES_TO_ALLOC;
-   }
+   /*
+* Free at least NUM_PAGES_TO_ALLOC number of pages to reduce calls to
+* set_memory_wb.
+*/
+   if (pool->npages > (pool->cur_max_size + NUM_PAGES_TO_ALLOC))
+   npages = pool->npages - pool->cur_max_size;
spin_unlock_irqrestore(>lock, irq_flags);
if (npages)
ttm_page_pool_free(pool, npages, GFP_KERNEL);
@@ -751,6 +767,9 @@ static int ttm_get_pages(struct page **pages, unsigned 
npages, int flags,
return 0;
}

+   /* Update pool size in case shrinker limited it. */
+   ttm_pool_update_max_size(pool);
+
/* combine zero flag to pool flags */
gfp_flags |= pool->gfp_flags;

@@ -803,6 +822,8 @@ static void ttm_page_pool_init_locked(struct ttm_page_pool 
*pool, gfp_t flags,
pool->npages = pool->nfrees = 0;
pool->gfp_flags = flags;
pool->name = name;
+   pool->cur_max_size = _manager->options.max_size;
+   pool->shrink_timeout = jiffies;
 }

 int ttm_page_alloc_init(struct ttm_mem_global *glob, unsigned max_pages)
diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c 
b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c
index a076ff3..80b10aa 100644
--- a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c
+++ b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c
@@ -93,6 +93,8 @@ enum pool_type {
  * @size: Size used during DMA allocation.
  * @npages_free: Count of available pages for re-use.
  * @npages_in_use: Count of pages that are in use.
+ * @cur_max_size: Current maximum size for the pool.
+ * @shrink_timeout: Timeout for pool maximum size restriction.
  * @nfrees: Stats 

[PATCH 2/3] drm/ttm: fix object deallocation to properly fill in the page pool.

2014-08-13 Thread Jérôme Glisse
From: J?r?me Glisse 

Current code never allowed the page pool to actualy fill in anyway. This fix
it and also allow it to grow over its limit until it grow beyond the batch
size for allocation and deallocation.

Signed-off-by: J?r?me Glisse 
Reviewed-by: Mario Kleiner 
Tested-by: Michel D?nzer 
Cc: Thomas Hellstrom 
Cc: Konrad Rzeszutek Wilk 
---
 drivers/gpu/drm/ttm/ttm_page_alloc_dma.c | 9 ++---
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c 
b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c
index c96db43..a076ff3 100644
--- a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c
+++ b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c
@@ -953,14 +953,9 @@ void ttm_dma_unpopulate(struct ttm_dma_tt *ttm_dma, struct 
device *dev)
} else {
pool->npages_free += count;
list_splice(_dma->pages_list, >free_list);
-   npages = count;
-   if (pool->npages_free > _manager->options.max_size) {
+   if (pool->npages_free >= (_manager->options.max_size +
+ NUM_PAGES_TO_ALLOC))
npages = pool->npages_free - _manager->options.max_size;
-   /* free at least NUM_PAGES_TO_ALLOC number of pages
-* to reduce calls to set_memory_wb */
-   if (npages < NUM_PAGES_TO_ALLOC)
-   npages = NUM_PAGES_TO_ALLOC;
-   }
}
spin_unlock_irqrestore(>lock, irq_flags);

-- 
1.9.3



[PATCH 1/3] drm/ttm: set sensible pool size limit.

2014-08-13 Thread Jérôme Glisse
From: J?r?me Glisse 

Due to bug in code it appear that some of the pool where never properly
use and always empty. Before fixing that bug this patch set sensible
limit on pool size. The magic 64MB number was nominated.

This is obviously a some what arbitrary number but the intend of ttm pool
is to minimize page alloc cost especialy when allocating page that will be
mark to be excluded from cpu cache mecanisms. We assume that mostly small
buffer that are constantly allocated/deallocated might suffer from core
memory allocation overhead as well as cache status change. This are the
assumptions behind the 64MB value.

This obviously need some serious testing including monitoring pool size.

Signed-off-by: J?r?me Glisse 
Cc: Mario Kleiner 
Cc: Michel D?nzer 
Cc: Thomas Hellstrom 
Cc: Konrad Rzeszutek Wilk 
---
 drivers/gpu/drm/ttm/ttm_memory.c | 16 ++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/ttm/ttm_memory.c b/drivers/gpu/drm/ttm/ttm_memory.c
index dbc2def..73b2ded 100644
--- a/drivers/gpu/drm/ttm/ttm_memory.c
+++ b/drivers/gpu/drm/ttm/ttm_memory.c
@@ -38,6 +38,16 @@
 #include 

 #define TTM_MEMORY_ALLOC_RETRIES 4
+/* Have a maximum of 64MB of memory inside the pool.
+ *
+ * This is obviously a some what arbitrary number but the intend of ttm pool
+ * is to minimize page alloc cost especialy when allocating page that will be
+ * mark to be excluded from cpu cache mecanisms. We assume that mostly small
+ * buffer that are constantly allocated/deallocated might suffer from core
+ * memory allocation overhead as well as cache status change. This are the
+ * assumptions behind the 64MB value.
+ */
+#define MAX_POOL_SIZE (64UL << 20UL)

 struct ttm_mem_zone {
struct kobject kobj;
@@ -363,6 +373,7 @@ int ttm_mem_global_init(struct ttm_mem_global *glob)
int ret;
int i;
struct ttm_mem_zone *zone;
+   unsigned long max_pool_size;

spin_lock_init(>lock);
glob->swap_queue = create_singlethread_workqueue("ttm_swap");
@@ -393,8 +404,9 @@ int ttm_mem_global_init(struct ttm_mem_global *glob)
pr_info("Zone %7s: Available graphics memory: %llu kiB\n",
zone->name, (unsigned long long)zone->max_mem >> 10);
}
-   ttm_page_alloc_init(glob, glob->zone_kernel->max_mem/(2*PAGE_SIZE));
-   ttm_dma_page_alloc_init(glob, glob->zone_kernel->max_mem/(2*PAGE_SIZE));
+   max_pool_size = min(glob->zone_kernel->max_mem >> 3UL, MAX_POOL_SIZE);
+   ttm_page_alloc_init(glob, max_pool_size / (2 * PAGE_SIZE));
+   ttm_dma_page_alloc_init(glob, max_pool_size / (2 * PAGE_SIZE));
return 0;
 out_no_zone:
ttm_mem_global_release(glob);
-- 
1.9.3



[PATCH 0/3] drm/ttm: hard to swim in an empty pool

2014-08-13 Thread Jérôme Glisse
So it seems there was several issue with the various ttm pool. The obvious
one is fixed in patch 2 where the always empty pool syndrom is addressed.
However the pool size are kind of crazy and because before some pool were
never actualy fill we might never have experience the hill effect of the
crazy maximum limit. This is what is addressed by first patch.

Last patch cook it up further so that under memory pressure the pool size
is divided by 2 each time a shrinker is run on a pool. There is a timeout
to restore the pool size on next allocation. Idea here is that memory should
not last and if it last then shrinker will keep minimize the pool size and
anyway thing are probably already sluggish once we it the shrinker path.

Of course because this fix thing in ttm memory allocation this need careful
testing. So before pushing anything i would like to see more people testing
this.

Cheers,
J?r?me