Skip to content

Commit cdaae83

Browse files
Bhawanpreet Lakhaalexdeucher
authored andcommitted
drm/amd/display: Handle GPU reset for DC block
[Why] Previously we used the s3 codepath for gpu reset. This can lead to issues in certain case where we end of waiting for fences which will never come (because parts of the hw are off due to gpu reset) and we end up waiting forever causing a deadlock. [How] Handle GPU reset separately from normal s3 case. We essentially need to redo everything we do in s3, but avoid any drm calls. For GPU reset case suspend: -Acquire DC lock -Cache current dc_state -Commit 0 stream/planes to dc (this puts dc into a state where it can be powered off) -Disable interrupts resume -Edit cached state to force full update -Commit cached state from suspend -Build stream and plane updates from the cached state -Commit stream/plane updates -Enable interrupts -Release DC lock v2: -Formatting -Release dc_state Signed-off-by: Bhawanpreet Lakha <[email protected]> Acked-by: Alex Deucher <[email protected]> Reviewed-by: Nicholas Kazlauskas <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
1 parent 54f78a7 commit cdaae83

File tree

2 files changed

+182
-1
lines changed

2 files changed

+182
-1
lines changed

drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c

Lines changed: 181 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1538,10 +1538,114 @@ static int dm_hw_fini(void *handle)
15381538
return 0;
15391539
}
15401540

1541+
1542+
static int dm_enable_vblank(struct drm_crtc *crtc);
1543+
static void dm_disable_vblank(struct drm_crtc *crtc);
1544+
1545+
static void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev,
1546+
struct dc_state *state, bool enable)
1547+
{
1548+
enum dc_irq_source irq_source;
1549+
struct amdgpu_crtc *acrtc;
1550+
int rc = -EBUSY;
1551+
int i = 0;
1552+
1553+
for (i = 0; i < state->stream_count; i++) {
1554+
acrtc = get_crtc_by_otg_inst(
1555+
adev, state->stream_status[i].primary_otg_inst);
1556+
1557+
if (acrtc && state->stream_status[i].plane_count != 0) {
1558+
irq_source = IRQ_TYPE_PFLIP + acrtc->otg_inst;
1559+
rc = dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY;
1560+
DRM_DEBUG("crtc %d - vupdate irq %sabling: r=%d\n",
1561+
acrtc->crtc_id, enable ? "en" : "dis", rc);
1562+
if (rc)
1563+
DRM_WARN("Failed to %s pflip interrupts\n",
1564+
enable ? "enable" : "disable");
1565+
1566+
if (enable) {
1567+
rc = dm_enable_vblank(&acrtc->base);
1568+
if (rc)
1569+
DRM_WARN("Failed to enable vblank interrupts\n");
1570+
} else {
1571+
dm_disable_vblank(&acrtc->base);
1572+
}
1573+
1574+
}
1575+
}
1576+
1577+
}
1578+
1579+
enum dc_status amdgpu_dm_commit_zero_streams(struct dc *dc)
1580+
{
1581+
struct dc_state *context = NULL;
1582+
enum dc_status res = DC_ERROR_UNEXPECTED;
1583+
int i;
1584+
struct dc_stream_state *del_streams[MAX_PIPES];
1585+
int del_streams_count = 0;
1586+
1587+
memset(del_streams, 0, sizeof(del_streams));
1588+
1589+
context = dc_create_state(dc);
1590+
if (context == NULL)
1591+
goto context_alloc_fail;
1592+
1593+
dc_resource_state_copy_construct_current(dc, context);
1594+
1595+
/* First remove from context all streams */
1596+
for (i = 0; i < context->stream_count; i++) {
1597+
struct dc_stream_state *stream = context->streams[i];
1598+
1599+
del_streams[del_streams_count++] = stream;
1600+
}
1601+
1602+
/* Remove all planes for removed streams and then remove the streams */
1603+
for (i = 0; i < del_streams_count; i++) {
1604+
if (!dc_rem_all_planes_for_stream(dc, del_streams[i], context)) {
1605+
res = DC_FAIL_DETACH_SURFACES;
1606+
goto fail;
1607+
}
1608+
1609+
res = dc_remove_stream_from_ctx(dc, context, del_streams[i]);
1610+
if (res != DC_OK)
1611+
goto fail;
1612+
}
1613+
1614+
1615+
res = dc_validate_global_state(dc, context, false);
1616+
1617+
if (res != DC_OK) {
1618+
DRM_ERROR("%s:resource validation failed, dc_status:%d\n", __func__, res);
1619+
goto fail;
1620+
}
1621+
1622+
res = dc_commit_state(dc, context);
1623+
1624+
fail:
1625+
dc_release_state(context);
1626+
1627+
context_alloc_fail:
1628+
return res;
1629+
}
1630+
15411631
static int dm_suspend(void *handle)
15421632
{
15431633
struct amdgpu_device *adev = handle;
15441634
struct amdgpu_display_manager *dm = &adev->dm;
1635+
int ret = 0;
1636+
1637+
if (adev->in_gpu_reset) {
1638+
mutex_lock(&dm->dc_lock);
1639+
dm->cached_dc_state = dc_copy_state(dm->dc->current_state);
1640+
1641+
dm_gpureset_toggle_interrupts(adev, dm->cached_dc_state, false);
1642+
1643+
amdgpu_dm_commit_zero_streams(dm->dc);
1644+
1645+
amdgpu_dm_irq_suspend(adev);
1646+
1647+
return ret;
1648+
}
15451649

15461650
WARN_ON(adev->dm.cached_state);
15471651
adev->dm.cached_state = drm_atomic_helper_suspend(adev->ddev);
@@ -1657,6 +1761,46 @@ static void emulated_link_detect(struct dc_link *link)
16571761

16581762
}
16591763

1764+
static void dm_gpureset_commit_state(struct dc_state *dc_state,
1765+
struct amdgpu_display_manager *dm)
1766+
{
1767+
struct {
1768+
struct dc_surface_update surface_updates[MAX_SURFACES];
1769+
struct dc_plane_info plane_infos[MAX_SURFACES];
1770+
struct dc_scaling_info scaling_infos[MAX_SURFACES];
1771+
struct dc_flip_addrs flip_addrs[MAX_SURFACES];
1772+
struct dc_stream_update stream_update;
1773+
} * bundle;
1774+
int k, m;
1775+
1776+
bundle = kzalloc(sizeof(*bundle), GFP_KERNEL);
1777+
1778+
if (!bundle) {
1779+
dm_error("Failed to allocate update bundle\n");
1780+
goto cleanup;
1781+
}
1782+
1783+
for (k = 0; k < dc_state->stream_count; k++) {
1784+
bundle->stream_update.stream = dc_state->streams[k];
1785+
1786+
for (m = 0; m < dc_state->stream_status->plane_count; m++) {
1787+
bundle->surface_updates[m].surface =
1788+
dc_state->stream_status->plane_states[m];
1789+
bundle->surface_updates[m].surface->force_full_update =
1790+
true;
1791+
}
1792+
dc_commit_updates_for_stream(
1793+
dm->dc, bundle->surface_updates,
1794+
dc_state->stream_status->plane_count,
1795+
dc_state->streams[k], &bundle->stream_update, dc_state);
1796+
}
1797+
1798+
cleanup:
1799+
kfree(bundle);
1800+
1801+
return;
1802+
}
1803+
16601804
static int dm_resume(void *handle)
16611805
{
16621806
struct amdgpu_device *adev = handle;
@@ -1673,8 +1817,44 @@ static int dm_resume(void *handle)
16731817
struct dm_plane_state *dm_new_plane_state;
16741818
struct dm_atomic_state *dm_state = to_dm_atomic_state(dm->atomic_obj.state);
16751819
enum dc_connection_type new_connection_type = dc_connection_none;
1676-
int i, r;
1820+
struct dc_state *dc_state;
1821+
int i, r, j;
1822+
1823+
if (adev->in_gpu_reset) {
1824+
dc_state = dm->cached_dc_state;
16771825

1826+
r = dm_dmub_hw_init(adev);
1827+
if (r)
1828+
DRM_ERROR("DMUB interface failed to initialize: status=%d\n", r);
1829+
1830+
dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D0);
1831+
dc_resume(dm->dc);
1832+
1833+
amdgpu_dm_irq_resume_early(adev);
1834+
1835+
for (i = 0; i < dc_state->stream_count; i++) {
1836+
dc_state->streams[i]->mode_changed = true;
1837+
for (j = 0; j < dc_state->stream_status->plane_count; j++) {
1838+
dc_state->stream_status->plane_states[j]->update_flags.raw
1839+
= 0xffffffff;
1840+
}
1841+
}
1842+
1843+
WARN_ON(!dc_commit_state(dm->dc, dc_state));
1844+
1845+
dm_gpureset_commit_state(dm->cached_dc_state, dm);
1846+
1847+
dm_gpureset_toggle_interrupts(adev, dm->cached_dc_state, true);
1848+
1849+
dc_release_state(dm->cached_dc_state);
1850+
dm->cached_dc_state = NULL;
1851+
1852+
amdgpu_dm_irq_resume_late(adev);
1853+
1854+
mutex_unlock(&dm->dc_lock);
1855+
1856+
return 0;
1857+
}
16781858
/* Recreate dc_state - DC invalidates it when setting power state to S3. */
16791859
dc_release_state(dm_state->context);
16801860
dm_state->context = dc_create_state(dm->dc);

drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ struct amdgpu_display_manager {
315315
#endif
316316

317317
struct drm_atomic_state *cached_state;
318+
struct dc_state *cached_dc_state;
318319

319320
struct dm_comressor_info compressor;
320321

0 commit comments

Comments
 (0)