summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2019-05-28 01:25:46 +0300
committerDave Airlie <airlied@redhat.com>2019-05-28 01:59:11 +0300
commit88cd7a2c1b29f61a2a3fab76216a43f3b779e0cd (patch)
treeb8a4311c8f7edfc92c1055b6a5a86b1a5552878e /drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
parentcd6c84d8f0cdc911df435bb075ba22ce3c605b07 (diff)
parent909fa3321d348ef69366aad9e84e1dd9ee0bd060 (diff)
downloadlinux-88cd7a2c1b29f61a2a3fab76216a43f3b779e0cd.tar.xz
Merge tag 'drm-misc-next-2019-05-24' of git://anongit.freedesktop.org/drm/drm-misc into drm-next
drm-misc-next for v5.3, try #2: UAPI Changes: - Add HDR source metadata property. - Make drm.h compile on GNU/kFreeBSD by including stdint.h - Clarify how the userspace reviewer has to review new kernel UAPI. - Clarify that for using new UAPI, merging to drm-next or drm-misc-next should be enough. Cross-subsystem Changes: - video/hdmi: Add unpack function for DRM infoframes. - Device tree bindings: * Updating a property for Mali Midgard GPUs * Updating a property for STM32 DSI panel * Adding support for FriendlyELEC HD702E 800x1280 panel * Adding support for Evervision VGG804821 800x480 5.0" WVGA TFT panel * Adding support for the EDT ET035012DM6 3.5" 320x240 QVGA 24-bit RGB TFT. * Adding support for Three Five displays TFC S9700RTWV43TR-01B 800x480 panel with resistive touch found on TI's AM335X-EVM. * Adding support for EDT ETM0430G0DH6 480x272 panel. - Add OSD101T2587-53TS driver with DT bindings. - Add Samsung S6E63M0 panel driver with DT bindings. - Add VXT VL050-8048NT-C01 800x480 panel with DT bindings. - Dma-buf: - Make mmap callback actually optional. - Documentation updates. - Fix debugfs refcount inbalance. - Remove unused sync_dump function. - Fix device tree bindings in drm-misc-next after a botched merge. Core Changes: - Add support for HDR infoframes and related EDID parsing. - Remove prime sg_table caching, now done inside dma-buf. - Add shiny new drm_gem_vram helpers for simple VRAM drivers; with some fixes to the new API on top. - Small fix to job cleanup without timeout handler. - Documentation fixes to drm_fourcc. - Replace lookups of drm_format with struct drm_format_info; remove functions that become obsolete by this conversion. - Remove double include in bridge/panel.c and some drivers. - Remove drmP.h include from drm/edid and drm/dp. - Fix null pointer deref in drm_fb_helper_hotplug_event(). - Remove most members from drm_fb_helper_crtc, only mode_set is kept. - Remove race of fb helpers with userspace; only restore mode when userspace is not master. - Move legacy setup from drm_file.c to drm_legacy_misc.c - Rework scheduler job destruction. - drm/bus was removed, remove from TODO. - Add __drm_atomic_helper_crtc_reset() to subclass crtc_state, and convert some drivers to use it (conversion is not complete yet). - Bump vblank timeout wait to 100 ms for atomic. - Docbook fix for drm_hdmi_infoframe_set_hdr_metadata. Driver Changes: - sun4i: Use DRM_GEM_CMA_VMAP_DRIVER_OPS instead of definining manually. - v3d: Small cleanups, adding support for compute shaders, reservation/synchronization fixes and job management refactoring, fixes MMU and debugfs. - lima: Fix null pointer in irq handler on startup, set default timeout for scheduled jobs. - stm/ltdc: Assorted fixes and adding FB modifier support. - amdgpu: Avoid hw reset if guilty job was already signaled. - virtio: Add seqno to fences, add trace events, use correct flags for fence allocation. - Convert AST, bochs, mgag200, vboxvideo, hisilicon to the new drm_gem_vram API. - sun6i_mipi_dsi: Support DSI GENERIC_SHORT_WRITE_2 transfers. - bochs: Small fix to use PTR_RET_OR_ZERO and driver unload. - gma500: header fixes - cirrus: Remove unused files. - mediatek: Fix compiler warning after merging the HDR series. - vc4: Rework binner bo handling. Signed-off-by: Dave Airlie <airlied@redhat.com> From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/052875a5-27ba-3832-60c2-193d950afdff@linux.intel.com
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_device.c')
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_device.c146
1 files changed, 95 insertions, 51 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index cc8ad3831982..9f282e971197 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -3341,8 +3341,6 @@ static int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev,
if (!ring || !ring->sched.thread)
continue;
- drm_sched_stop(&ring->sched);
-
/* after all hw jobs are reset, hw fence is meaningless, so force_completion */
amdgpu_fence_driver_force_completion(ring);
}
@@ -3350,8 +3348,7 @@ static int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev,
if(job)
drm_sched_increase_karma(&job->base);
-
-
+ /* Don't suspend on bare metal if we are not going to HW reset the ASIC */
if (!amdgpu_sriov_vf(adev)) {
if (!need_full_reset)
@@ -3489,38 +3486,21 @@ end:
return r;
}
-static void amdgpu_device_post_asic_reset(struct amdgpu_device *adev,
- struct amdgpu_job *job)
+static bool amdgpu_device_lock_adev(struct amdgpu_device *adev, bool trylock)
{
- int i;
-
- for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
- struct amdgpu_ring *ring = adev->rings[i];
-
- if (!ring || !ring->sched.thread)
- continue;
+ if (trylock) {
+ if (!mutex_trylock(&adev->lock_reset))
+ return false;
+ } else
+ mutex_lock(&adev->lock_reset);
- if (!adev->asic_reset_res)
- drm_sched_resubmit_jobs(&ring->sched);
-
- drm_sched_start(&ring->sched, !adev->asic_reset_res);
- }
-
- if (!amdgpu_device_has_dc_support(adev)) {
- drm_helper_resume_force_mode(adev->ddev);
- }
-
- adev->asic_reset_res = 0;
-}
-
-static void amdgpu_device_lock_adev(struct amdgpu_device *adev)
-{
- mutex_lock(&adev->lock_reset);
atomic_inc(&adev->gpu_reset_counter);
adev->in_gpu_reset = 1;
/* Block kfd: SRIOV would do it separately */
if (!amdgpu_sriov_vf(adev))
amdgpu_amdkfd_pre_reset(adev);
+
+ return true;
}
static void amdgpu_device_unlock_adev(struct amdgpu_device *adev)
@@ -3548,40 +3528,42 @@ static void amdgpu_device_unlock_adev(struct amdgpu_device *adev)
int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
struct amdgpu_job *job)
{
- int r;
+ struct list_head device_list, *device_list_handle = NULL;
+ bool need_full_reset, job_signaled;
struct amdgpu_hive_info *hive = NULL;
- bool need_full_reset = false;
struct amdgpu_device *tmp_adev = NULL;
- struct list_head device_list, *device_list_handle = NULL;
+ int i, r = 0;
+ need_full_reset = job_signaled = false;
INIT_LIST_HEAD(&device_list);
dev_info(adev->dev, "GPU reset begin!\n");
+ hive = amdgpu_get_xgmi_hive(adev, false);
+
/*
- * In case of XGMI hive disallow concurrent resets to be triggered
- * by different nodes. No point also since the one node already executing
- * reset will also reset all the other nodes in the hive.
+ * Here we trylock to avoid chain of resets executing from
+ * either trigger by jobs on different adevs in XGMI hive or jobs on
+ * different schedulers for same device while this TO handler is running.
+ * We always reset all schedulers for device and all devices for XGMI
+ * hive so that should take care of them too.
*/
- hive = amdgpu_get_xgmi_hive(adev, 0);
- if (hive && adev->gmc.xgmi.num_physical_nodes > 1 &&
- !mutex_trylock(&hive->reset_lock))
+
+ if (hive && !mutex_trylock(&hive->reset_lock)) {
+ DRM_INFO("Bailing on TDR for s_job:%llx, hive: %llx as another already in progress",
+ job->base.id, hive->hive_id);
return 0;
+ }
/* Start with adev pre asic reset first for soft reset check.*/
- amdgpu_device_lock_adev(adev);
- r = amdgpu_device_pre_asic_reset(adev,
- job,
- &need_full_reset);
- if (r) {
- /*TODO Should we stop ?*/
- DRM_ERROR("GPU pre asic reset failed with err, %d for drm dev, %s ",
- r, adev->ddev->unique);
- adev->asic_reset_res = r;
+ if (!amdgpu_device_lock_adev(adev, !hive)) {
+ DRM_INFO("Bailing on TDR for s_job:%llx, as another already in progress",
+ job->base.id);
+ return 0;
}
/* Build list of devices to reset */
- if (need_full_reset && adev->gmc.xgmi.num_physical_nodes > 1) {
+ if (adev->gmc.xgmi.num_physical_nodes > 1) {
if (!hive) {
amdgpu_device_unlock_adev(adev);
return -ENODEV;
@@ -3598,13 +3580,56 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
device_list_handle = &device_list;
}
+ /* block all schedulers and reset given job's ring */
+ list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) {
+ for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+ struct amdgpu_ring *ring = tmp_adev->rings[i];
+
+ if (!ring || !ring->sched.thread)
+ continue;
+
+ drm_sched_stop(&ring->sched, &job->base);
+ }
+ }
+
+
+ /*
+ * Must check guilty signal here since after this point all old
+ * HW fences are force signaled.
+ *
+ * job->base holds a reference to parent fence
+ */
+ if (job && job->base.s_fence->parent &&
+ dma_fence_is_signaled(job->base.s_fence->parent))
+ job_signaled = true;
+
+ if (!amdgpu_device_ip_need_full_reset(adev))
+ device_list_handle = &device_list;
+
+ if (job_signaled) {
+ dev_info(adev->dev, "Guilty job already signaled, skipping HW reset");
+ goto skip_hw_reset;
+ }
+
+
+ /* Guilty job will be freed after this*/
+ r = amdgpu_device_pre_asic_reset(adev,
+ job,
+ &need_full_reset);
+ if (r) {
+ /*TODO Should we stop ?*/
+ DRM_ERROR("GPU pre asic reset failed with err, %d for drm dev, %s ",
+ r, adev->ddev->unique);
+ adev->asic_reset_res = r;
+ }
+
retry: /* Rest of adevs pre asic reset from XGMI hive. */
list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) {
if (tmp_adev == adev)
continue;
- amdgpu_device_lock_adev(tmp_adev);
+ amdgpu_device_lock_adev(tmp_adev, false);
r = amdgpu_device_pre_asic_reset(tmp_adev,
NULL,
&need_full_reset);
@@ -3628,9 +3653,28 @@ retry: /* Rest of adevs pre asic reset from XGMI hive. */
goto retry;
}
+skip_hw_reset:
+
/* Post ASIC reset for all devs .*/
list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) {
- amdgpu_device_post_asic_reset(tmp_adev, tmp_adev == adev ? job : NULL);
+ for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+ struct amdgpu_ring *ring = tmp_adev->rings[i];
+
+ if (!ring || !ring->sched.thread)
+ continue;
+
+ /* No point to resubmit jobs if we didn't HW reset*/
+ if (!tmp_adev->asic_reset_res && !job_signaled)
+ drm_sched_resubmit_jobs(&ring->sched);
+
+ drm_sched_start(&ring->sched, !tmp_adev->asic_reset_res);
+ }
+
+ if (!amdgpu_device_has_dc_support(tmp_adev) && !job_signaled) {
+ drm_helper_resume_force_mode(tmp_adev->ddev);
+ }
+
+ tmp_adev->asic_reset_res = 0;
if (r) {
/* bad news, how to tell it to userspace ? */
@@ -3643,7 +3687,7 @@ retry: /* Rest of adevs pre asic reset from XGMI hive. */
amdgpu_device_unlock_adev(tmp_adev);
}
- if (hive && adev->gmc.xgmi.num_physical_nodes > 1)
+ if (hive)
mutex_unlock(&hive->reset_lock);
if (r)