So it's pretty much the same patchset except for patch 7 (use mutex instead of spinlock) and 9 & 10 which correspond to previous patch 9 split in two and the sa allocation being simplified.
The patchset can be found at : http://people.freedesktop.org/~glisse/reset/
Cheers, Jerome Glisse
From: Christian König deathsimple@vodafone.de
Different rings have different criteria to test if they are stuck.
v2: rebased on current drm-next
Signed-off-by: Christian König deathsimple@vodafone.de Reviewed-by: Alex Deucher alexander.deucher@amd.com Reviewed-by: Jerome Glisse jglisse@redhat.com --- drivers/gpu/drm/radeon/radeon.h | 4 +- drivers/gpu/drm/radeon/radeon_asic.c | 44 ++++++++++++++++++-------------- drivers/gpu/drm/radeon/radeon_fence.c | 2 +- 3 files changed, 28 insertions(+), 22 deletions(-)
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 138b952..bea99e3 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1144,7 +1144,6 @@ 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); - bool (*gpu_is_lockup)(struct radeon_device *rdev, struct radeon_ring *cp); int (*asic_reset)(struct radeon_device *rdev); /* ioctl hw specific callback. Some hw might want to perform special * operation on specific ioctl. For instance on wait idle some hw @@ -1173,6 +1172,7 @@ struct radeon_asic { void (*ring_start)(struct radeon_device *rdev, struct radeon_ring *cp); int (*ring_test)(struct radeon_device *rdev, struct radeon_ring *cp); int (*ib_test)(struct radeon_device *rdev, struct radeon_ring *cp); + bool (*is_lockup)(struct radeon_device *rdev, struct radeon_ring *cp); } ring[RADEON_NUM_RINGS]; /* irqs */ struct { @@ -1730,7 +1730,6 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v); #define radeon_suspend(rdev) (rdev)->asic->suspend((rdev)) #define radeon_cs_parse(rdev, r, p) (rdev)->asic->ring[(r)].cs_parse((p)) #define radeon_vga_set_state(rdev, state) (rdev)->asic->vga_set_state((rdev), (state)) -#define radeon_gpu_is_lockup(rdev, cp) (rdev)->asic->gpu_is_lockup((rdev), (cp)) #define radeon_asic_reset(rdev) (rdev)->asic->asic_reset((rdev)) #define radeon_gart_tlb_flush(rdev) (rdev)->asic->gart.tlb_flush((rdev)) #define radeon_gart_set_page(rdev, i, p) (rdev)->asic->gart.set_page((rdev), (i), (p)) @@ -1739,6 +1738,7 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v); #define radeon_ib_test(rdev, r, cp) (rdev)->asic->ring[(r)].ib_test((rdev), (cp)) #define radeon_ring_ib_execute(rdev, r, ib) (rdev)->asic->ring[(r)].ib_execute((rdev), (ib)) #define radeon_ring_ib_parse(rdev, r, ib) (rdev)->asic->ring[(r)].ib_parse((rdev), (ib)) +#define radeon_ring_is_lockup(rdev, r, cp) (rdev)->asic->ring[(r)].is_lockup((rdev), (cp)) #define radeon_irq_set(rdev) (rdev)->asic->irq.set((rdev)) #define radeon_irq_process(rdev) (rdev)->asic->irq.process((rdev)) #define radeon_get_vblank_counter(rdev, crtc) (rdev)->asic->display.get_vblank_counter((rdev), (crtc)) diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index be4dc2f..958b9ea 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -134,7 +134,6 @@ static struct radeon_asic r100_asic = { .suspend = &r100_suspend, .resume = &r100_resume, .vga_set_state = &r100_vga_set_state, - .gpu_is_lockup = &r100_gpu_is_lockup, .asic_reset = &r100_asic_reset, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, @@ -152,6 +151,7 @@ static struct radeon_asic r100_asic = { .ring_start = &r100_ring_start, .ring_test = &r100_ring_test, .ib_test = &r100_ib_test, + .is_lockup = &r100_gpu_is_lockup, } }, .irq = { @@ -208,7 +208,6 @@ static struct radeon_asic r200_asic = { .suspend = &r100_suspend, .resume = &r100_resume, .vga_set_state = &r100_vga_set_state, - .gpu_is_lockup = &r100_gpu_is_lockup, .asic_reset = &r100_asic_reset, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, @@ -226,6 +225,7 @@ static struct radeon_asic r200_asic = { .ring_start = &r100_ring_start, .ring_test = &r100_ring_test, .ib_test = &r100_ib_test, + .is_lockup = &r100_gpu_is_lockup, } }, .irq = { @@ -282,7 +282,6 @@ static struct radeon_asic r300_asic = { .suspend = &r300_suspend, .resume = &r300_resume, .vga_set_state = &r100_vga_set_state, - .gpu_is_lockup = &r300_gpu_is_lockup, .asic_reset = &r300_asic_reset, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, @@ -300,6 +299,7 @@ static struct radeon_asic r300_asic = { .ring_start = &r300_ring_start, .ring_test = &r100_ring_test, .ib_test = &r100_ib_test, + .is_lockup = &r300_gpu_is_lockup, } }, .irq = { @@ -356,7 +356,6 @@ static struct radeon_asic r300_asic_pcie = { .suspend = &r300_suspend, .resume = &r300_resume, .vga_set_state = &r100_vga_set_state, - .gpu_is_lockup = &r300_gpu_is_lockup, .asic_reset = &r300_asic_reset, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, @@ -374,6 +373,7 @@ static struct radeon_asic r300_asic_pcie = { .ring_start = &r300_ring_start, .ring_test = &r100_ring_test, .ib_test = &r100_ib_test, + .is_lockup = &r300_gpu_is_lockup, } }, .irq = { @@ -430,7 +430,6 @@ static struct radeon_asic r420_asic = { .suspend = &r420_suspend, .resume = &r420_resume, .vga_set_state = &r100_vga_set_state, - .gpu_is_lockup = &r300_gpu_is_lockup, .asic_reset = &r300_asic_reset, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, @@ -448,6 +447,7 @@ static struct radeon_asic r420_asic = { .ring_start = &r300_ring_start, .ring_test = &r100_ring_test, .ib_test = &r100_ib_test, + .is_lockup = &r300_gpu_is_lockup, } }, .irq = { @@ -504,7 +504,6 @@ static struct radeon_asic rs400_asic = { .suspend = &rs400_suspend, .resume = &rs400_resume, .vga_set_state = &r100_vga_set_state, - .gpu_is_lockup = &r300_gpu_is_lockup, .asic_reset = &r300_asic_reset, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, @@ -522,6 +521,7 @@ static struct radeon_asic rs400_asic = { .ring_start = &r300_ring_start, .ring_test = &r100_ring_test, .ib_test = &r100_ib_test, + .is_lockup = &r300_gpu_is_lockup, } }, .irq = { @@ -578,7 +578,6 @@ static struct radeon_asic rs600_asic = { .suspend = &rs600_suspend, .resume = &rs600_resume, .vga_set_state = &r100_vga_set_state, - .gpu_is_lockup = &r300_gpu_is_lockup, .asic_reset = &rs600_asic_reset, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, @@ -596,6 +595,7 @@ static struct radeon_asic rs600_asic = { .ring_start = &r300_ring_start, .ring_test = &r100_ring_test, .ib_test = &r100_ib_test, + .is_lockup = &r300_gpu_is_lockup, } }, .irq = { @@ -652,7 +652,6 @@ static struct radeon_asic rs690_asic = { .suspend = &rs690_suspend, .resume = &rs690_resume, .vga_set_state = &r100_vga_set_state, - .gpu_is_lockup = &r300_gpu_is_lockup, .asic_reset = &rs600_asic_reset, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, @@ -670,6 +669,7 @@ static struct radeon_asic rs690_asic = { .ring_start = &r300_ring_start, .ring_test = &r100_ring_test, .ib_test = &r100_ib_test, + .is_lockup = &r300_gpu_is_lockup, } }, .irq = { @@ -726,7 +726,6 @@ static struct radeon_asic rv515_asic = { .suspend = &rv515_suspend, .resume = &rv515_resume, .vga_set_state = &r100_vga_set_state, - .gpu_is_lockup = &r300_gpu_is_lockup, .asic_reset = &rs600_asic_reset, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, @@ -744,6 +743,7 @@ static struct radeon_asic rv515_asic = { .ring_start = &rv515_ring_start, .ring_test = &r100_ring_test, .ib_test = &r100_ib_test, + .is_lockup = &r300_gpu_is_lockup, } }, .irq = { @@ -800,7 +800,6 @@ static struct radeon_asic r520_asic = { .suspend = &rv515_suspend, .resume = &r520_resume, .vga_set_state = &r100_vga_set_state, - .gpu_is_lockup = &r300_gpu_is_lockup, .asic_reset = &rs600_asic_reset, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, @@ -818,6 +817,7 @@ static struct radeon_asic r520_asic = { .ring_start = &rv515_ring_start, .ring_test = &r100_ring_test, .ib_test = &r100_ib_test, + .is_lockup = &r300_gpu_is_lockup, } }, .irq = { @@ -874,7 +874,6 @@ static struct radeon_asic r600_asic = { .suspend = &r600_suspend, .resume = &r600_resume, .vga_set_state = &r600_vga_set_state, - .gpu_is_lockup = &r600_gpu_is_lockup, .asic_reset = &r600_asic_reset, .ioctl_wait_idle = r600_ioctl_wait_idle, .gui_idle = &r600_gui_idle, @@ -891,6 +890,7 @@ static struct radeon_asic r600_asic = { .cs_parse = &r600_cs_parse, .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, + .is_lockup = &r600_gpu_is_lockup, } }, .irq = { @@ -946,7 +946,6 @@ static struct radeon_asic rs780_asic = { .fini = &r600_fini, .suspend = &r600_suspend, .resume = &r600_resume, - .gpu_is_lockup = &r600_gpu_is_lockup, .vga_set_state = &r600_vga_set_state, .asic_reset = &r600_asic_reset, .ioctl_wait_idle = r600_ioctl_wait_idle, @@ -964,6 +963,7 @@ static struct radeon_asic rs780_asic = { .cs_parse = &r600_cs_parse, .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, + .is_lockup = &r600_gpu_is_lockup, } }, .irq = { @@ -1020,7 +1020,6 @@ static struct radeon_asic rv770_asic = { .suspend = &rv770_suspend, .resume = &rv770_resume, .asic_reset = &r600_asic_reset, - .gpu_is_lockup = &r600_gpu_is_lockup, .vga_set_state = &r600_vga_set_state, .ioctl_wait_idle = r600_ioctl_wait_idle, .gui_idle = &r600_gui_idle, @@ -1037,6 +1036,7 @@ static struct radeon_asic rv770_asic = { .cs_parse = &r600_cs_parse, .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, + .is_lockup = &r600_gpu_is_lockup, } }, .irq = { @@ -1092,7 +1092,6 @@ static struct radeon_asic evergreen_asic = { .fini = &evergreen_fini, .suspend = &evergreen_suspend, .resume = &evergreen_resume, - .gpu_is_lockup = &evergreen_gpu_is_lockup, .asic_reset = &evergreen_asic_reset, .vga_set_state = &r600_vga_set_state, .ioctl_wait_idle = r600_ioctl_wait_idle, @@ -1110,6 +1109,7 @@ static struct radeon_asic evergreen_asic = { .cs_parse = &evergreen_cs_parse, .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, + .is_lockup = &evergreen_gpu_is_lockup, } }, .irq = { @@ -1165,7 +1165,6 @@ static struct radeon_asic sumo_asic = { .fini = &evergreen_fini, .suspend = &evergreen_suspend, .resume = &evergreen_resume, - .gpu_is_lockup = &evergreen_gpu_is_lockup, .asic_reset = &evergreen_asic_reset, .vga_set_state = &r600_vga_set_state, .ioctl_wait_idle = r600_ioctl_wait_idle, @@ -1183,6 +1182,7 @@ static struct radeon_asic sumo_asic = { .cs_parse = &evergreen_cs_parse, .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, + .is_lockup = &evergreen_gpu_is_lockup, }, }, .irq = { @@ -1238,7 +1238,6 @@ static struct radeon_asic btc_asic = { .fini = &evergreen_fini, .suspend = &evergreen_suspend, .resume = &evergreen_resume, - .gpu_is_lockup = &evergreen_gpu_is_lockup, .asic_reset = &evergreen_asic_reset, .vga_set_state = &r600_vga_set_state, .ioctl_wait_idle = r600_ioctl_wait_idle, @@ -1256,6 +1255,7 @@ static struct radeon_asic btc_asic = { .cs_parse = &evergreen_cs_parse, .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, + .is_lockup = &evergreen_gpu_is_lockup, } }, .irq = { @@ -1321,7 +1321,6 @@ static struct radeon_asic cayman_asic = { .fini = &cayman_fini, .suspend = &cayman_suspend, .resume = &cayman_resume, - .gpu_is_lockup = &cayman_gpu_is_lockup, .asic_reset = &cayman_asic_reset, .vga_set_state = &r600_vga_set_state, .ioctl_wait_idle = r600_ioctl_wait_idle, @@ -1340,6 +1339,7 @@ static struct radeon_asic cayman_asic = { .cs_parse = &evergreen_cs_parse, .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, + .is_lockup = &cayman_gpu_is_lockup, }, [CAYMAN_RING_TYPE_CP1_INDEX] = { .ib_execute = &cayman_ring_ib_execute, @@ -1349,6 +1349,7 @@ static struct radeon_asic cayman_asic = { .cs_parse = &evergreen_cs_parse, .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, + .is_lockup = &cayman_gpu_is_lockup, }, [CAYMAN_RING_TYPE_CP2_INDEX] = { .ib_execute = &cayman_ring_ib_execute, @@ -1358,6 +1359,7 @@ static struct radeon_asic cayman_asic = { .cs_parse = &evergreen_cs_parse, .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, + .is_lockup = &cayman_gpu_is_lockup, } }, .irq = { @@ -1413,7 +1415,6 @@ static struct radeon_asic trinity_asic = { .fini = &cayman_fini, .suspend = &cayman_suspend, .resume = &cayman_resume, - .gpu_is_lockup = &cayman_gpu_is_lockup, .asic_reset = &cayman_asic_reset, .vga_set_state = &r600_vga_set_state, .ioctl_wait_idle = r600_ioctl_wait_idle, @@ -1432,6 +1433,7 @@ static struct radeon_asic trinity_asic = { .cs_parse = &evergreen_cs_parse, .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, + .is_lockup = &cayman_gpu_is_lockup, }, [CAYMAN_RING_TYPE_CP1_INDEX] = { .ib_execute = &cayman_ring_ib_execute, @@ -1441,6 +1443,7 @@ static struct radeon_asic trinity_asic = { .cs_parse = &evergreen_cs_parse, .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, + .is_lockup = &cayman_gpu_is_lockup, }, [CAYMAN_RING_TYPE_CP2_INDEX] = { .ib_execute = &cayman_ring_ib_execute, @@ -1450,6 +1453,7 @@ static struct radeon_asic trinity_asic = { .cs_parse = &evergreen_cs_parse, .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, + .is_lockup = &cayman_gpu_is_lockup, } }, .irq = { @@ -1515,7 +1519,6 @@ static struct radeon_asic si_asic = { .fini = &si_fini, .suspend = &si_suspend, .resume = &si_resume, - .gpu_is_lockup = &si_gpu_is_lockup, .asic_reset = &si_asic_reset, .vga_set_state = &r600_vga_set_state, .ioctl_wait_idle = r600_ioctl_wait_idle, @@ -1534,6 +1537,7 @@ static struct radeon_asic si_asic = { .cs_parse = NULL, .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, + .is_lockup = &si_gpu_is_lockup, }, [CAYMAN_RING_TYPE_CP1_INDEX] = { .ib_execute = &si_ring_ib_execute, @@ -1543,6 +1547,7 @@ static struct radeon_asic si_asic = { .cs_parse = NULL, .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, + .is_lockup = &si_gpu_is_lockup, }, [CAYMAN_RING_TYPE_CP2_INDEX] = { .ib_execute = &si_ring_ib_execute, @@ -1552,6 +1557,7 @@ static struct radeon_asic si_asic = { .cs_parse = NULL, .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, + .is_lockup = &si_gpu_is_lockup, } }, .irq = { diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 4bd36a3..66b2229 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -259,7 +259,7 @@ retry: * if we experiencing a lockup the value doesn't change */ if (seq == rdev->fence_drv[fence->ring].last_seq && - radeon_gpu_is_lockup(rdev, &rdev->ring[fence->ring])) { + radeon_ring_is_lockup(rdev, fence->ring, &rdev->ring[fence->ring])) { /* good news we believe it's a lockup */ printk(KERN_WARNING "GPU lockup (waiting for 0x%08X last fence id 0x%08X)\n", fence->seq, seq);
From: Christian König deathsimple@vodafone.de
It makes no sense at all to have more than one flag.
Signed-off-by: Christian König deathsimple@vodafone.de Reviewed-by: Alex Deucher alexander.deucher@amd.com Reviewed-by: Jerome Glisse jglisse@redhat.com --- drivers/gpu/drm/radeon/r100.c | 1 - drivers/gpu/drm/radeon/r300.c | 1 - drivers/gpu/drm/radeon/radeon.h | 1 - drivers/gpu/drm/radeon/radeon_device.c | 1 - drivers/gpu/drm/radeon/radeon_fence.c | 36 +++++++++++-------------------- drivers/gpu/drm/radeon/rs600.c | 1 - 6 files changed, 13 insertions(+), 28 deletions(-)
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index fe33d35..6573e28 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -2296,7 +2296,6 @@ int r100_asic_reset(struct radeon_device *rdev) if (G_000E40_SE_BUSY(status) || G_000E40_RE_BUSY(status) || G_000E40_TAM_BUSY(status) || G_000E40_PB_BUSY(status)) { dev_err(rdev->dev, "failed to reset GPU\n"); - rdev->gpu_lockup = true; ret = -1; } else dev_info(rdev->dev, "GPU reset succeed\n"); diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index fa14383..a63f432 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -449,7 +449,6 @@ int r300_asic_reset(struct radeon_device *rdev) /* Check if GPU is idle */ if (G_000E40_GA_BUSY(status) || G_000E40_VAP_BUSY(status)) { dev_err(rdev->dev, "failed to reset GPU\n"); - rdev->gpu_lockup = true; ret = -1; } else dev_info(rdev->dev, "GPU reset succeed\n"); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index bea99e3..365334b 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1529,7 +1529,6 @@ struct radeon_device { struct radeon_mutex cs_mutex; struct radeon_wb wb; struct radeon_dummy_page dummy_page; - bool gpu_lockup; bool shutdown; bool suspend; bool need_dma32; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index ea7df16..eb63a06 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -714,7 +714,6 @@ int radeon_device_init(struct radeon_device *rdev, rdev->is_atom_bios = false; rdev->usec_timeout = RADEON_MAX_USEC_TIMEOUT; rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024; - rdev->gpu_lockup = false; rdev->accel_working = false;
DRM_INFO("initializing kernel modesetting (%s 0x%04X:0x%04X 0x%04X:0x%04X).\n", diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 66b2229..36c411f 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -71,14 +71,7 @@ int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence) return 0; } fence->seq = atomic_add_return(1, &rdev->fence_drv[fence->ring].seq); - if (!rdev->ring[fence->ring].ready) - /* FIXME: cp is not running assume everythings is done right - * away - */ - radeon_fence_write(rdev, fence->seq, fence->ring); - else - radeon_fence_ring_emit(rdev, fence->ring, fence); - + radeon_fence_ring_emit(rdev, fence->ring, fence); trace_radeon_fence_emit(rdev->ddev, fence->seq); fence->emitted = true; list_move_tail(&fence->list, &rdev->fence_drv[fence->ring].emitted); @@ -191,9 +184,6 @@ bool radeon_fence_signaled(struct radeon_fence *fence) if (!fence) return true;
- if (fence->rdev->gpu_lockup) - return true; - write_lock_irqsave(&fence->rdev->fence_lock, irq_flags); signaled = fence->signaled; /* if we are shuting down report all fence as signaled */ @@ -260,18 +250,16 @@ retry: */ if (seq == rdev->fence_drv[fence->ring].last_seq && radeon_ring_is_lockup(rdev, fence->ring, &rdev->ring[fence->ring])) { + /* good news we believe it's a lockup */ printk(KERN_WARNING "GPU lockup (waiting for 0x%08X last fence id 0x%08X)\n", fence->seq, seq); - /* FIXME: what should we do ? marking everyone - * as signaled for now - */ - rdev->gpu_lockup = true; + + /* mark the ring as not ready any more */ + rdev->ring[fence->ring].ready = false; r = radeon_gpu_reset(rdev); if (r) return r; - radeon_fence_write(rdev, fence->seq, fence->ring); - rdev->gpu_lockup = false; } timeout = RADEON_FENCE_JIFFIES_TIMEOUT; write_lock_irqsave(&rdev->fence_lock, irq_flags); @@ -289,10 +277,11 @@ int radeon_fence_wait_next(struct radeon_device *rdev, int ring) struct radeon_fence *fence; int r;
- if (rdev->gpu_lockup) { - return 0; - } write_lock_irqsave(&rdev->fence_lock, irq_flags); + if (!rdev->ring[ring].ready) { + write_unlock_irqrestore(&rdev->fence_lock, irq_flags); + return -EBUSY; + } if (list_empty(&rdev->fence_drv[ring].emitted)) { write_unlock_irqrestore(&rdev->fence_lock, irq_flags); return 0; @@ -312,10 +301,11 @@ int radeon_fence_wait_last(struct radeon_device *rdev, int ring) struct radeon_fence *fence; int r;
- if (rdev->gpu_lockup) { - return 0; - } write_lock_irqsave(&rdev->fence_lock, irq_flags); + if (!rdev->ring[ring].ready) { + write_unlock_irqrestore(&rdev->fence_lock, irq_flags); + return -EBUSY; + } if (list_empty(&rdev->fence_drv[ring].emitted)) { write_unlock_irqrestore(&rdev->fence_lock, irq_flags); return 0; diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index d25cf86..f709fe8 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -396,7 +396,6 @@ int rs600_asic_reset(struct radeon_device *rdev) /* Check if GPU is idle */ if (G_000E40_GA_BUSY(status) || G_000E40_VAP_BUSY(status)) { dev_err(rdev->dev, "failed to reset GPU\n"); - rdev->gpu_lockup = true; ret = -1; } else dev_info(rdev->dev, "GPU reset succeed\n");
From: Christian König deathsimple@vodafone.de
Just register the debugfs files on init instead of checking the chipset type multiple times.
Signed-off-by: Christian König deathsimple@vodafone.de Reviewed-by: Alex Deucher alexander.deucher@amd.com Reviewed-by: Jerome Glisse jglisse@redhat.com --- drivers/gpu/drm/radeon/radeon_ring.c | 31 +++++++++++++++++++------------ 1 files changed, 19 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index cc33b3d..b6eb1d2 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -34,7 +34,7 @@ #include "atom.h"
int radeon_debugfs_ib_init(struct radeon_device *rdev); -int radeon_debugfs_ring_init(struct radeon_device *rdev); +int radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ring *ring);
u32 radeon_get_ib_value(struct radeon_cs_parser *p, int idx) { @@ -237,9 +237,6 @@ int radeon_ib_pool_init(struct radeon_device *rdev) if (radeon_debugfs_ib_init(rdev)) { DRM_ERROR("Failed to register debugfs file for IB !\n"); } - if (radeon_debugfs_ring_init(rdev)) { - DRM_ERROR("Failed to register debugfs file for rings !\n"); - } radeon_mutex_unlock(&rdev->ib_pool.mutex); return 0; } @@ -411,6 +408,9 @@ int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsig } ring->ptr_mask = (ring->ring_size / 4) - 1; ring->ring_free_dw = ring->ring_size / 4; + if (radeon_debugfs_ring_init(rdev, ring)) { + DRM_ERROR("Failed to register debugfs file for rings !\n"); + } return 0; }
@@ -501,17 +501,24 @@ static char radeon_debugfs_ib_names[RADEON_IB_POOL_SIZE][32]; static unsigned radeon_debugfs_ib_idx[RADEON_IB_POOL_SIZE]; #endif
-int radeon_debugfs_ring_init(struct radeon_device *rdev) +int radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ring *ring) { #if defined(CONFIG_DEBUG_FS) - if (rdev->family >= CHIP_CAYMAN) - return radeon_debugfs_add_files(rdev, radeon_debugfs_ring_info_list, - ARRAY_SIZE(radeon_debugfs_ring_info_list)); - else - return radeon_debugfs_add_files(rdev, radeon_debugfs_ring_info_list, 1); -#else - return 0; + unsigned i; + for (i = 0; i < ARRAY_SIZE(radeon_debugfs_ring_info_list); ++i) { + struct drm_info_list *info = &radeon_debugfs_ring_info_list[i]; + int ridx = *(int*)radeon_debugfs_ring_info_list[i].data; + unsigned r; + + if (&rdev->ring[ridx] != ring) + continue; + + r = radeon_debugfs_add_files(rdev, info, 1); + if (r) + return r; + } #endif + return 0; }
int radeon_debugfs_ib_init(struct radeon_device *rdev)
From: Christian König deathsimple@vodafone.de
Removing all the different error messages and having just one standard behaviour over all chipset generations.
Signed-off-by: Christian König deathsimple@vodafone.de Reviewed-by: Alex Deucher alexander.deucher@amd.com Reviewed-by: Jerome Glisse jglisse@redhat.com --- drivers/gpu/drm/radeon/evergreen.c | 7 ++----- drivers/gpu/drm/radeon/ni.c | 7 ++----- drivers/gpu/drm/radeon/r100.c | 7 ++----- drivers/gpu/drm/radeon/r300.c | 7 ++----- drivers/gpu/drm/radeon/r420.c | 7 ++----- drivers/gpu/drm/radeon/r520.c | 8 +++----- drivers/gpu/drm/radeon/r600.c | 7 ++----- drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_ring.c | 30 ++++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/rs400.c | 7 ++----- drivers/gpu/drm/radeon/rs600.c | 7 ++----- drivers/gpu/drm/radeon/rs690.c | 7 ++----- drivers/gpu/drm/radeon/rv515.c | 8 +++----- drivers/gpu/drm/radeon/rv770.c | 7 ++----- 14 files changed, 57 insertions(+), 60 deletions(-)
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index cfa372c..ca47f52 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -3248,12 +3248,9 @@ static int evergreen_startup(struct radeon_device *rdev) if (r) return r;
- r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); - if (r) { - DRM_ERROR("radeon: failed testing IB (%d).\n", r); - rdev->accel_working = false; + r = radeon_ib_ring_tests(rdev); + if (r) return r; - }
r = r600_audio_init(rdev); if (r) { diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index a48ca53..0146428 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -1601,12 +1601,9 @@ static int cayman_startup(struct radeon_device *rdev) if (r) return r;
- r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); - if (r) { - DRM_ERROR("radeon: failed testing IB (%d).\n", r); - rdev->accel_working = false; + r = radeon_ib_ring_tests(rdev); + if (r) return r; - }
r = radeon_vm_manager_start(rdev); if (r) diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 6573e28..ac53bd8 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -3964,12 +3964,9 @@ static int r100_startup(struct radeon_device *rdev) if (r) return r;
- r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); - if (r) { - dev_err(rdev->dev, "failed testing IB (%d).\n", r); - rdev->accel_working = false; + r = radeon_ib_ring_tests(rdev); + if (r) return r; - }
return 0; } diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index a63f432..26e0db8 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -1417,12 +1417,9 @@ static int r300_startup(struct radeon_device *rdev) if (r) return r;
- r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); - if (r) { - dev_err(rdev->dev, "failed testing IB (%d).\n", r); - rdev->accel_working = false; + r = radeon_ib_ring_tests(rdev); + if (r) return r; - }
return 0; } diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c index f3fcaac..99137be 100644 --- a/drivers/gpu/drm/radeon/r420.c +++ b/drivers/gpu/drm/radeon/r420.c @@ -279,12 +279,9 @@ static int r420_startup(struct radeon_device *rdev) if (r) return r;
- r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); - if (r) { - dev_err(rdev->dev, "failed testing IB (%d).\n", r); - rdev->accel_working = false; + r = radeon_ib_ring_tests(rdev); + if (r) return r; - }
return 0; } diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c index ebcc15b..b5cf837 100644 --- a/drivers/gpu/drm/radeon/r520.c +++ b/drivers/gpu/drm/radeon/r520.c @@ -207,12 +207,10 @@ static int r520_startup(struct radeon_device *rdev) if (r) return r;
- r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); - if (r) { - dev_err(rdev->dev, "failed testing IB (%d).\n", r); - rdev->accel_working = false; + r = radeon_ib_ring_tests(rdev); + if (r) return r; - } + return 0; }
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index c8187c4..06eccd1 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2494,12 +2494,9 @@ int r600_startup(struct radeon_device *rdev) if (r) return r;
- r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); - if (r) { - DRM_ERROR("radeon: failed testing IB (%d).\n", r); - rdev->accel_working = false; + r = radeon_ib_ring_tests(rdev); + if (r) return r; - }
return 0; } diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 365334b..8801657 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -793,6 +793,7 @@ int radeon_ib_pool_init(struct radeon_device *rdev); void radeon_ib_pool_fini(struct radeon_device *rdev); int radeon_ib_pool_start(struct radeon_device *rdev); int radeon_ib_pool_suspend(struct radeon_device *rdev); +int radeon_ib_ring_tests(struct radeon_device *rdev); /* Ring access between begin & end cannot sleep */ int radeon_ring_index(struct radeon_device *rdev, struct radeon_ring *cp); void radeon_ring_free_size(struct radeon_device *rdev, struct radeon_ring *cp); diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index b6eb1d2..1b020ef 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -267,6 +267,36 @@ int radeon_ib_pool_suspend(struct radeon_device *rdev) return radeon_sa_bo_manager_suspend(rdev, &rdev->ib_pool.sa_manager); }
+int radeon_ib_ring_tests(struct radeon_device *rdev) +{ + unsigned i; + int r; + + for (i = 0; i < RADEON_NUM_RINGS; ++i) { + struct radeon_ring *ring = &rdev->ring[i]; + + if (!ring->ready) + continue; + + r = radeon_ib_test(rdev, i, ring); + if (r) { + ring->ready = false; + + if (i == RADEON_RING_TYPE_GFX_INDEX) { + /* oh, oh, that's really bad */ + DRM_ERROR("radeon: failed testing IB on GFX ring (%d).\n", r); + rdev->accel_working = false; + return r; + + } else { + /* still not good, but we can live with it */ + DRM_ERROR("radeon: failed testing IB on ring %d (%d).\n", i, r); + } + } + } + return 0; +} + /* * Ring. */ diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index 4cf381b..a464eb5 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -430,12 +430,9 @@ static int rs400_startup(struct radeon_device *rdev) if (r) return r;
- r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); - if (r) { - dev_err(rdev->dev, "failed testing IB (%d).\n", r); - rdev->accel_working = false; + r = radeon_ib_ring_tests(rdev); + if (r) return r; - }
return 0; } diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index f709fe8..a286dea 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -882,12 +882,9 @@ static int rs600_startup(struct radeon_device *rdev) if (r) return r;
- r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); - if (r) { - dev_err(rdev->dev, "failed testing IB (%d).\n", r); - rdev->accel_working = false; + r = radeon_ib_ring_tests(rdev); + if (r) return r; - }
return 0; } diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c index f2c3b9d..3277dde 100644 --- a/drivers/gpu/drm/radeon/rs690.c +++ b/drivers/gpu/drm/radeon/rs690.c @@ -647,12 +647,9 @@ static int rs690_startup(struct radeon_device *rdev) if (r) return r;
- r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); - if (r) { - dev_err(rdev->dev, "failed testing IB (%d).\n", r); - rdev->accel_working = false; + r = radeon_ib_ring_tests(rdev); + if (r) return r; - }
return 0; } diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index d8d78fe..7f08ced 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -412,12 +412,10 @@ static int rv515_startup(struct radeon_device *rdev) if (r) return r;
- r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); - if (r) { - dev_err(rdev->dev, "failed testing IB (%d).\n", r); - rdev->accel_working = false; + r = radeon_ib_ring_tests(rdev); + if (r) return r; - } + return 0; }
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index cdab1ae..a8b0016 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -1114,12 +1114,9 @@ static int rv770_startup(struct radeon_device *rdev) if (r) return r;
- r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); - if (r) { - dev_err(rdev->dev, "IB test failed (%d).\n", r); - rdev->accel_working = false; + r = radeon_ib_ring_tests(rdev); + if (r) return r; - }
return 0; }
From: Christian König deathsimple@vodafone.de
Previusly multiple rings could trigger multiple GPU resets at the same time.
Signed-off-by: Christian König deathsimple@vodafone.de Reviewed-by: Jerome Glisse jglisse@redhat.com --- drivers/gpu/drm/radeon/radeon.h | 3 +- drivers/gpu/drm/radeon/radeon_fence.c | 150 +++++++++++++++++---------------- 2 files changed, 77 insertions(+), 76 deletions(-)
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 8801657..85a3aa9 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -255,8 +255,7 @@ struct radeon_fence_driver { volatile uint32_t *cpu_addr; atomic_t seq; uint32_t last_seq; - unsigned long last_jiffies; - unsigned long last_timeout; + unsigned long last_activity; wait_queue_head_t queue; struct list_head created; struct list_head emitted; diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 36c411f..1a9765a 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -74,6 +74,10 @@ int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence) radeon_fence_ring_emit(rdev, fence->ring, fence); trace_radeon_fence_emit(rdev->ddev, fence->seq); fence->emitted = true; + /* are we the first fence on a previusly idle ring? */ + if (list_empty(&rdev->fence_drv[fence->ring].emitted)) { + rdev->fence_drv[fence->ring].last_activity = jiffies; + } list_move_tail(&fence->list, &rdev->fence_drv[fence->ring].emitted); write_unlock_irqrestore(&rdev->fence_lock, irq_flags); return 0; @@ -85,34 +89,14 @@ static bool radeon_fence_poll_locked(struct radeon_device *rdev, int ring) struct list_head *i, *n; uint32_t seq; bool wake = false; - unsigned long cjiffies;
seq = radeon_fence_read(rdev, ring); - if (seq != rdev->fence_drv[ring].last_seq) { - rdev->fence_drv[ring].last_seq = seq; - rdev->fence_drv[ring].last_jiffies = jiffies; - rdev->fence_drv[ring].last_timeout = RADEON_FENCE_JIFFIES_TIMEOUT; - } else { - cjiffies = jiffies; - if (time_after(cjiffies, rdev->fence_drv[ring].last_jiffies)) { - cjiffies -= rdev->fence_drv[ring].last_jiffies; - if (time_after(rdev->fence_drv[ring].last_timeout, cjiffies)) { - /* update the timeout */ - rdev->fence_drv[ring].last_timeout -= cjiffies; - } else { - /* the 500ms timeout is elapsed we should test - * for GPU lockup - */ - rdev->fence_drv[ring].last_timeout = 1; - } - } else { - /* wrap around update last jiffies, we will just wait - * a little longer - */ - rdev->fence_drv[ring].last_jiffies = cjiffies; - } + if (seq == rdev->fence_drv[ring].last_seq) return false; - } + + rdev->fence_drv[ring].last_seq = seq; + rdev->fence_drv[ring].last_activity = jiffies; + n = NULL; list_for_each(i, &rdev->fence_drv[ring].emitted) { fence = list_entry(i, struct radeon_fence, list); @@ -207,66 +191,84 @@ int radeon_fence_wait(struct radeon_fence *fence, bool intr) struct radeon_device *rdev; unsigned long irq_flags, timeout; u32 seq; - int r; + int i, r; + bool signaled;
if (fence == NULL) { WARN(1, "Querying an invalid fence : %p !\n", fence); - return 0; + return -EINVAL; } + rdev = fence->rdev; - if (radeon_fence_signaled(fence)) { - return 0; - } - timeout = rdev->fence_drv[fence->ring].last_timeout; -retry: - /* save current sequence used to check for GPU lockup */ - seq = rdev->fence_drv[fence->ring].last_seq; - trace_radeon_fence_wait_begin(rdev->ddev, seq); - if (intr) { + signaled = radeon_fence_signaled(fence); + while (!signaled) { + read_lock_irqsave(&rdev->fence_lock, irq_flags); + timeout = jiffies - RADEON_FENCE_JIFFIES_TIMEOUT; + if (time_after(rdev->fence_drv[fence->ring].last_activity, timeout)) { + /* the normal case, timeout is somewhere before last_activity */ + timeout = rdev->fence_drv[fence->ring].last_activity - timeout; + } else { + /* either jiffies wrapped around, or no fence was signaled in the last 500ms + * anyway we will just wait for the minimum amount and then check for a lockup */ + timeout = 1; + } + /* save current sequence value used to check for GPU lockups */ + seq = rdev->fence_drv[fence->ring].last_seq; + read_unlock_irqrestore(&rdev->fence_lock, irq_flags); + + trace_radeon_fence_wait_begin(rdev->ddev, seq); radeon_irq_kms_sw_irq_get(rdev, fence->ring); - r = wait_event_interruptible_timeout(rdev->fence_drv[fence->ring].queue, - radeon_fence_signaled(fence), timeout); + if (intr) { + r = wait_event_interruptible_timeout( + rdev->fence_drv[fence->ring].queue, + (signaled = radeon_fence_signaled(fence)), timeout); + } else { + r = wait_event_timeout( + rdev->fence_drv[fence->ring].queue, + (signaled = radeon_fence_signaled(fence)), timeout); + } radeon_irq_kms_sw_irq_put(rdev, fence->ring); if (unlikely(r < 0)) { return r; } - } else { - radeon_irq_kms_sw_irq_get(rdev, fence->ring); - r = wait_event_timeout(rdev->fence_drv[fence->ring].queue, - radeon_fence_signaled(fence), timeout); - radeon_irq_kms_sw_irq_put(rdev, fence->ring); - } - trace_radeon_fence_wait_end(rdev->ddev, seq); - if (unlikely(!radeon_fence_signaled(fence))) { - /* we were interrupted for some reason and fence isn't - * isn't signaled yet, resume wait - */ - if (r) { - timeout = r; - goto retry; - } - /* don't protect read access to rdev->fence_drv[t].last_seq - * if we experiencing a lockup the value doesn't change - */ - if (seq == rdev->fence_drv[fence->ring].last_seq && - radeon_ring_is_lockup(rdev, fence->ring, &rdev->ring[fence->ring])) { - - /* good news we believe it's a lockup */ - printk(KERN_WARNING "GPU lockup (waiting for 0x%08X last fence id 0x%08X)\n", - fence->seq, seq); - - /* mark the ring as not ready any more */ - rdev->ring[fence->ring].ready = false; - r = radeon_gpu_reset(rdev); - if (r) - return r; + trace_radeon_fence_wait_end(rdev->ddev, seq); + + if (unlikely(!signaled)) { + /* we were interrupted for some reason and fence + * isn't signaled yet, resume waiting */ + if (r) { + continue; + } + + write_lock_irqsave(&rdev->fence_lock, irq_flags); + /* check if sequence value has changed since last_activity */ + if (seq != rdev->fence_drv[fence->ring].last_seq) { + write_unlock_irqrestore(&rdev->fence_lock, irq_flags); + continue; + } + + /* change sequence value on all rings, so nobody else things there is a lockup */ + for (i = 0; i < RADEON_NUM_RINGS; ++i) + rdev->fence_drv[i].last_seq -= 0x10000; + write_unlock_irqrestore(&rdev->fence_lock, irq_flags); + + if (radeon_ring_is_lockup(rdev, fence->ring, &rdev->ring[fence->ring])) { + + /* good news we believe it's a lockup */ + printk(KERN_WARNING "GPU lockup (waiting for 0x%08X last fence id 0x%08X)\n", + fence->seq, seq); + + /* mark the ring as not ready any more */ + rdev->ring[fence->ring].ready = false; + r = radeon_gpu_reset(rdev); + if (r) + return r; + + write_lock_irqsave(&rdev->fence_lock, irq_flags); + rdev->fence_drv[fence->ring].last_activity = jiffies; + write_unlock_irqrestore(&rdev->fence_lock, irq_flags); + } } - timeout = RADEON_FENCE_JIFFIES_TIMEOUT; - write_lock_irqsave(&rdev->fence_lock, irq_flags); - rdev->fence_drv[fence->ring].last_timeout = RADEON_FENCE_JIFFIES_TIMEOUT; - rdev->fence_drv[fence->ring].last_jiffies = jiffies; - write_unlock_irqrestore(&rdev->fence_lock, irq_flags); - goto retry; } return 0; }
From: Christian König deathsimple@vodafone.de
Aligning offset can make it bigger than tmp->offset leading to an overrun bug in the following subtraction.
v2: Against initial suspicions this can't happen in mainline, so no need to push it into stable.
Signed-off-by: Christian König deathsimple@vodafone.de Reviewed-by: Michel Dänzer michel.daenzer@amd.com Reviewed-by: Jerome Glisse jglisse@redhat.com --- drivers/gpu/drm/radeon/radeon_sa.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/gpu/drm/radeon/radeon_sa.c b/drivers/gpu/drm/radeon/radeon_sa.c index 4cce47e..8fbfe69 100644 --- a/drivers/gpu/drm/radeon/radeon_sa.c +++ b/drivers/gpu/drm/radeon/radeon_sa.c @@ -150,7 +150,7 @@ int radeon_sa_bo_new(struct radeon_device *rdev, offset = 0; list_for_each_entry(tmp, &sa_manager->sa_bo, list) { /* room before this object ? */ - if ((tmp->offset - offset) >= size) { + if (offset < tmp->offset && (tmp->offset - offset) >= size) { head = tmp->list.prev; goto out; }
From: Christian König deathsimple@vodafone.de
Make the suballocator self containing to locking.
v2: split the bugfix into a seperate patch. v3: Jerome Glisse use mutex, no reason to use spinlock that are more heavyweight than mutex
Signed-off-by: Christian König deathsimple@vodafone.de Signed-off-by: Jerome Glisse jglisse@redhat.com --- drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_sa.c | 15 +++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 85a3aa9..34c1041 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -381,6 +381,7 @@ struct radeon_bo_list { * alignment). */ struct radeon_sa_manager { + struct mutex mutex; struct radeon_bo *bo; struct list_head sa_bo; unsigned size; diff --git a/drivers/gpu/drm/radeon/radeon_sa.c b/drivers/gpu/drm/radeon/radeon_sa.c index 8fbfe69..8c76c2e 100644 --- a/drivers/gpu/drm/radeon/radeon_sa.c +++ b/drivers/gpu/drm/radeon/radeon_sa.c @@ -37,6 +37,7 @@ int radeon_sa_bo_manager_init(struct radeon_device *rdev, { int r;
+ mutex_init(&sa_manager->mutex); sa_manager->bo = NULL; sa_manager->size = size; sa_manager->domain = domain; @@ -139,15 +140,15 @@ int radeon_sa_bo_new(struct radeon_device *rdev,
BUG_ON(align > RADEON_GPU_PAGE_SIZE); BUG_ON(size > sa_manager->size); + mutex_lock(&sa_manager->mutex);
/* no one ? */ - head = sa_manager->sa_bo.prev; if (list_empty(&sa_manager->sa_bo)) { + head = &sa_manager->sa_bo; goto out; }
/* look for a hole big enough */ - offset = 0; list_for_each_entry(tmp, &sa_manager->sa_bo, list) { /* room before this object ? */ if (offset < tmp->offset && (tmp->offset - offset) >= size) { @@ -157,9 +158,8 @@ int radeon_sa_bo_new(struct radeon_device *rdev, offset = tmp->offset + tmp->size; wasted = offset % align; if (wasted) { - wasted = align - wasted; + offset += align - wasted; } - offset += wasted; } /* room at the end ? */ head = sa_manager->sa_bo.prev; @@ -167,11 +167,11 @@ int radeon_sa_bo_new(struct radeon_device *rdev, offset = tmp->offset + tmp->size; wasted = offset % align; if (wasted) { - wasted = align - wasted; + offset += wasted = align - wasted; } - offset += wasted; if ((sa_manager->size - offset) < size) { /* failed to find somethings big enough */ + mutex_unlock(&sa_manager->mutex); return -ENOMEM; }
@@ -180,10 +180,13 @@ out: sa_bo->offset = offset; sa_bo->size = size; list_add(&sa_bo->list, head); + mutex_unlock(&sa_manager->mutex); return 0; }
void radeon_sa_bo_free(struct radeon_device *rdev, struct radeon_sa_bo *sa_bo) { + mutex_lock(&sa_bo->manager->mutex); list_del_init(&sa_bo->list); + mutex_unlock(&sa_bo->manager->mutex); }
On 01.05.2012 19:19, j.glisse@gmail.com wrote:
NAK, radeon_sa_bo_free is called from interrupt context, so a mutex won't work here.
Also because of the short amount of time the lock is (or should be) hold a spinlock seems to be more appropriate here.
Christian.
From: Christian König deathsimple@vodafone.de
Dumping the current allocations.
v2: convert to mutex
Signed-off-by: Christian König deathsimple@vodafone.de Reviewed-by: Jerome Glisse jglisse@redhat.com --- drivers/gpu/drm/radeon/radeon_object.h | 5 +++++ drivers/gpu/drm/radeon/radeon_ring.c | 22 ++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_sa.c | 14 ++++++++++++++ 3 files changed, 41 insertions(+), 0 deletions(-)
diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h index f9104be..d9b9333 100644 --- a/drivers/gpu/drm/radeon/radeon_object.h +++ b/drivers/gpu/drm/radeon/radeon_object.h @@ -161,5 +161,10 @@ extern int radeon_sa_bo_new(struct radeon_device *rdev, unsigned size, unsigned align); extern void radeon_sa_bo_free(struct radeon_device *rdev, struct radeon_sa_bo *sa_bo); +#if defined(CONFIG_DEBUG_FS) +extern void radeon_sa_bo_dump_debug_info(struct radeon_sa_manager *sa_manager, + struct seq_file *m); +#endif +
#endif diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index 1b020ef..1d9bce9 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -529,6 +529,23 @@ static int radeon_debugfs_ib_info(struct seq_file *m, void *data) static struct drm_info_list radeon_debugfs_ib_list[RADEON_IB_POOL_SIZE]; static char radeon_debugfs_ib_names[RADEON_IB_POOL_SIZE][32]; static unsigned radeon_debugfs_ib_idx[RADEON_IB_POOL_SIZE]; + +static int radeon_debugfs_sa_info(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + struct radeon_device *rdev = dev->dev_private; + + radeon_sa_bo_dump_debug_info(&rdev->ib_pool.sa_manager, m); + + return 0; + +} + +static struct drm_info_list radeon_debugfs_sa_list[] = { + {"radeon_sa_info", &radeon_debugfs_sa_info, 0, NULL}, +}; + #endif
int radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ring *ring) @@ -555,6 +572,11 @@ int radeon_debugfs_ib_init(struct radeon_device *rdev) { #if defined(CONFIG_DEBUG_FS) unsigned i; + int r; + + r = radeon_debugfs_add_files(rdev, radeon_debugfs_sa_list, 1); + if (r) + return r;
for (i = 0; i < RADEON_IB_POOL_SIZE; i++) { sprintf(radeon_debugfs_ib_names[i], "radeon_ib_%04u", i); diff --git a/drivers/gpu/drm/radeon/radeon_sa.c b/drivers/gpu/drm/radeon/radeon_sa.c index 8c76c2e..88906c9 100644 --- a/drivers/gpu/drm/radeon/radeon_sa.c +++ b/drivers/gpu/drm/radeon/radeon_sa.c @@ -190,3 +190,17 @@ void radeon_sa_bo_free(struct radeon_device *rdev, struct radeon_sa_bo *sa_bo) list_del_init(&sa_bo->list); mutex_unlock(&sa_bo->manager->mutex); } + +#if defined(CONFIG_DEBUG_FS) +void radeon_sa_bo_dump_debug_info(struct radeon_sa_manager *sa_manager, + struct seq_file *m) +{ + struct radeon_sa_bo *i; + + mutex_lock(&sa_manager->mutex); + list_for_each_entry(i, &sa_manager->sa_bo, list) { + seq_printf(m, "offset %08d: size %4d\n", i->offset, i->size); + } + mutex_unlock(&sa_manager->mutex); +} +#endif
From: Jerome Glisse jglisse@redhat.com
The sa allocator is suppose to be a ring allocator, ie allocation happen first at the end and if there is no more room we start at the begining again. This patch make the code match this design. sa_manager keep track of the start & end hole, it first try to allocate in the end hole, if it fails it allocate in the begining hole, if it fails it returns (caller is expected to retry).
When freeing we need to make sure that we properly grow the end hole and start hole. We take advantage of the fact that the sa_bo list is ordered by offset. That means that when we free an sa_bo the previous sa_bo in list is also the sa_bo just before the sa_bo we are freeing and reversly for the next.
Signed-off-by: Jerome Glisse jglisse@redhat.com --- drivers/gpu/drm/radeon/radeon.h | 3 + drivers/gpu/drm/radeon/radeon_sa.c | 101 ++++++++++++++++++++++++------------ 2 files changed, 71 insertions(+), 33 deletions(-)
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 34c1041..ad12ef8 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -385,6 +385,9 @@ struct radeon_sa_manager { struct radeon_bo *bo; struct list_head sa_bo; unsigned size; + unsigned ehole_size; + unsigned shole_size; + unsigned ehole_offset; uint64_t gpu_addr; void *cpu_ptr; uint32_t domain; diff --git a/drivers/gpu/drm/radeon/radeon_sa.c b/drivers/gpu/drm/radeon/radeon_sa.c index 88906c9..8c0b3e6 100644 --- a/drivers/gpu/drm/radeon/radeon_sa.c +++ b/drivers/gpu/drm/radeon/radeon_sa.c @@ -40,6 +40,9 @@ int radeon_sa_bo_manager_init(struct radeon_device *rdev, mutex_init(&sa_manager->mutex); sa_manager->bo = NULL; sa_manager->size = size; + sa_manager->shole_size = 0; + sa_manager->ehole_size = size; + sa_manager->ehole_offset = 0; sa_manager->domain = domain; INIT_LIST_HEAD(&sa_manager->sa_bo);
@@ -134,61 +137,93 @@ int radeon_sa_bo_new(struct radeon_device *rdev, struct radeon_sa_bo *sa_bo, unsigned size, unsigned align) { - struct radeon_sa_bo *tmp; - struct list_head *head; unsigned offset = 0, wasted = 0;
BUG_ON(align > RADEON_GPU_PAGE_SIZE); BUG_ON(size > sa_manager->size); + mutex_lock(&sa_manager->mutex);
- /* no one ? */ - if (list_empty(&sa_manager->sa_bo)) { - head = &sa_manager->sa_bo; + wasted = (align - (sa_manager->ehole_offset % align)) % align; + if ((size + wasted) < sa_manager->ehole_size) { + /* we keep sa_bo list ordered by offset */ + list_add_tail(&sa_bo->list, &sa_manger->sa_bo); + offset = sa_manager->ehole_offset + wasted; + sa_manager->ehole_offset += wasted + size; + sa_manager->ehole_size -= wasted + size; goto out; }
- /* look for a hole big enough */ - list_for_each_entry(tmp, &sa_manager->sa_bo, list) { - /* room before this object ? */ - if (offset < tmp->offset && (tmp->offset - offset) >= size) { - head = tmp->list.prev; - goto out; - } - offset = tmp->offset + tmp->size; - wasted = offset % align; - if (wasted) { - offset += align - wasted; - } - } - /* room at the end ? */ - head = sa_manager->sa_bo.prev; - tmp = list_entry(head, struct radeon_sa_bo, list); - offset = tmp->offset + tmp->size; - wasted = offset % align; - if (wasted) { - offset += wasted = align - wasted; - } - if ((sa_manager->size - offset) < size) { - /* failed to find somethings big enough */ - mutex_unlock(&sa_manager->mutex); - return -ENOMEM; + if (size < sa_manager->shole_size) { + /* keep sa_bo list ordered by offset */ + list_add(&sa_bo->list, &sa_manger->sa_bo); + sa_manager->shole_size = 0; + offset = 0; + goto out; }
+ mutex_unlock(&sa_manager->mutex); + return -ENOMEM; + out: sa_bo->manager = sa_manager; sa_bo->offset = offset; sa_bo->size = size; - list_add(&sa_bo->list, head); mutex_unlock(&sa_manager->mutex); return 0; }
void radeon_sa_bo_free(struct radeon_device *rdev, struct radeon_sa_bo *sa_bo) { - mutex_lock(&sa_bo->manager->mutex); + struct radeon_sa_manager *sa_manager = sa_bo->manager; + struct radeon_sa_bo *tmp; + + mutex_lock(&manager->mutex); + + /* try first to grow the end hole as we want to allocate from the + * end first + */ + if ((sa_bo->offset + sa_bo->size) == sa_manager->ehole_offset) { + if (sa_bo->list.prev != &sa_manager->sa_bo) { + /* all sa_bo are in list in offset order if there is a + * sa_bo before the one we are freeing then make sure + * we grow the end hole down to the end of the previous + * sa_bo + */ + tmp = list_entry(sa_bo->list.prev, struct radeon_sa_bo, list); + sa_manager->ehole_offset = tmp->offset + tmp->size; + sa_manager->ehole_size += sa_manager->size - sa_manager->ehole_offset; + } else { + /* this bo was alone in the list */ + sa_manager->ehole_offset = 0; + sa_manager->ehole_size = sa_manager->size; + sa_manager->shole_size = 0; + } + } else if (sa_bo->offset == sa_manager->shole_size) { + if (sa_bo->list.next != &sa_manager->sa_bo) { + /* all sa_bo are in list in offset order if there is a + * sa_bo after the one we are freeing then make sure + * we grow the start hole up to the begining of the next + * sa_bo + */ + tmp = list_entry(sa_bo->list.next, struct radeon_sa_bo, list); + sa_manager->shole_size = tmp->offset; + } else { + /* this case should never happen as it means this sa_b + * was alone in the list so that : + * (sa_bo->offset + sa_bo->size) == sa_manager->ehole_offset + * should be true and we should have been in previous + * branch restore things and print an warning + */ + sa_manager->ehole_offset = 0; + sa_manager->ehole_size = sa_manager->size; + sa_manager->shole_size = 0; + dev_warn(rdev->dev, "sa allocator structure corrupted\n"); + } + } list_del_init(&sa_bo->list); - mutex_unlock(&sa_bo->manager->mutex); + + mutex_unlock(&manager->mutex); }
#if defined(CONFIG_DEBUG_FS)
From: Jerome Glisse jglisse@redhat.com
wakequeue is use in case we want to wait until we got something that allow to allocate the object.
Signed-off-by: Christian König deathsimple@vodafone.de Signed-off-by: Jerome Glisse jglisse@redhat.com --- drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_gart.c | 2 +- drivers/gpu/drm/radeon/radeon_object.h | 2 +- drivers/gpu/drm/radeon/radeon_ring.c | 6 +++++- drivers/gpu/drm/radeon/radeon_sa.c | 32 ++++++++++++++++++++++++++++++-- 5 files changed, 38 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index ad12ef8..8a6dd46 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -382,6 +382,7 @@ struct radeon_bo_list { */ struct radeon_sa_manager { struct mutex mutex; + wait_queue_head_t queue; struct radeon_bo *bo; struct list_head sa_bo; unsigned size; diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index c58a036..7af4ff9 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -395,7 +395,7 @@ int radeon_vm_bind(struct radeon_device *rdev, struct radeon_vm *vm) retry: r = radeon_sa_bo_new(rdev, &rdev->vm_manager.sa_manager, &vm->sa_bo, RADEON_GPU_PAGE_ALIGN(vm->last_pfn * 8), - RADEON_GPU_PAGE_SIZE); + RADEON_GPU_PAGE_SIZE, false); if (r) { if (list_empty(&rdev->vm_manager.lru_vm)) { return r; diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h index d9b9333..85f33d9 100644 --- a/drivers/gpu/drm/radeon/radeon_object.h +++ b/drivers/gpu/drm/radeon/radeon_object.h @@ -158,7 +158,7 @@ extern int radeon_sa_bo_manager_suspend(struct radeon_device *rdev, extern int radeon_sa_bo_new(struct radeon_device *rdev, struct radeon_sa_manager *sa_manager, struct radeon_sa_bo *sa_bo, - unsigned size, unsigned align); + unsigned size, unsigned align, bool block); extern void radeon_sa_bo_free(struct radeon_device *rdev, struct radeon_sa_bo *sa_bo); #if defined(CONFIG_DEBUG_FS) diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index 1d9bce9..f8ecb3e 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -124,7 +124,7 @@ retry: if (rdev->ib_pool.ibs[idx].fence == NULL) { r = radeon_sa_bo_new(rdev, &rdev->ib_pool.sa_manager, &rdev->ib_pool.ibs[idx].sa_bo, - size, 256); + size, 256, false); if (!r) { *ib = &rdev->ib_pool.ibs[idx]; (*ib)->ptr = rdev->ib_pool.sa_manager.cpu_ptr; @@ -222,6 +222,10 @@ int radeon_ib_pool_init(struct radeon_device *rdev) return 0; }
+ /* copy over the sa_manager we have to do this to silence + * kernel possible deadlock detection code to complain about + * a false positive + */ rdev->ib_pool.sa_manager = tmp; INIT_LIST_HEAD(&rdev->ib_pool.sa_manager.sa_bo); for (i = 0; i < RADEON_IB_POOL_SIZE; i++) { diff --git a/drivers/gpu/drm/radeon/radeon_sa.c b/drivers/gpu/drm/radeon/radeon_sa.c index 8c0b3e6..f7b20b1 100644 --- a/drivers/gpu/drm/radeon/radeon_sa.c +++ b/drivers/gpu/drm/radeon/radeon_sa.c @@ -38,6 +38,7 @@ int radeon_sa_bo_manager_init(struct radeon_device *rdev, int r;
mutex_init(&sa_manager->mutex); + init_waitqueue_head(&sa_manager->queue); sa_manager->bo = NULL; sa_manager->size = size; sa_manager->shole_size = 0; @@ -61,6 +62,8 @@ void radeon_sa_bo_manager_fini(struct radeon_device *rdev, { struct radeon_sa_bo *sa_bo, *tmp;
+ wake_up_all(&sa_manager->queue); + mutex_lock(&sa_manager->mutex); if (!list_empty(&sa_manager->sa_bo)) { dev_err(rdev->dev, "sa_manager is not empty, clearing anyway\n"); } @@ -69,6 +72,7 @@ void radeon_sa_bo_manager_fini(struct radeon_device *rdev, } radeon_bo_unref(&sa_manager->bo); sa_manager->size = 0; + mutex_unlock(&sa_manager->mutex); }
int radeon_sa_bo_manager_start(struct radeon_device *rdev, @@ -117,6 +121,17 @@ int radeon_sa_bo_manager_suspend(struct radeon_device *rdev, return r; }
+static inline unsigned radeon_sa_bo_max_free(struct radeon_sa_manager *m, + unsigned align) +{ + unsigned start, end, wasted; + + wasted = (align - (sa_manager->ehole_offset % align)) % align; + end = wasted > sa_manager->ehole_size ? 0 : sa_manager->ehole_size - wasted; + start = sa_manager->shole_size; + return start < end ? end : start; +} + /* * Principe is simple, we keep a list of sub allocation in offset * order (first entry has offset == 0, last entry has the highest @@ -135,13 +150,14 @@ int radeon_sa_bo_manager_suspend(struct radeon_device *rdev, int radeon_sa_bo_new(struct radeon_device *rdev, struct radeon_sa_manager *sa_manager, struct radeon_sa_bo *sa_bo, - unsigned size, unsigned align) + unsigned size, unsigned align, bool block) { unsigned offset = 0, wasted = 0;
BUG_ON(align > RADEON_GPU_PAGE_SIZE); BUG_ON(size > sa_manager->size);
+retry: mutex_lock(&sa_manager->mutex);
wasted = (align - (sa_manager->ehole_offset % align)) % align; @@ -161,8 +177,20 @@ int radeon_sa_bo_new(struct radeon_device *rdev, offset = 0; goto out; } - mutex_unlock(&sa_manager->mutex); + + if (block) { + /* failed to find something big enough, wait + * for the biggest hole to increase in size + */ + r = wait_event_interruptible(sa_manager->queue, + radeon_sa_bo_max_free(sa_manager, align) >= size); + if (r) { + return r; + } + goto retry; + } + return -ENOMEM;
out:
From: Christian König deathsimple@vodafone.de
Instead of hacking the calculation multiple times.
Signed-off-by: Christian König deathsimple@vodafone.de Reviewed-by: Jerome Glisse jglisse@redhat.com --- drivers/gpu/drm/radeon/radeon_gart.c | 6 ++---- drivers/gpu/drm/radeon/radeon_object.h | 11 +++++++++++ drivers/gpu/drm/radeon/radeon_ring.c | 6 ++---- 3 files changed, 15 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 7af4ff9..96a2a81 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -404,10 +404,8 @@ retry: radeon_vm_unbind(rdev, vm_evict); goto retry; } - vm->pt = rdev->vm_manager.sa_manager.cpu_ptr; - vm->pt += (vm->sa_bo.offset >> 3); - vm->pt_gpu_addr = rdev->vm_manager.sa_manager.gpu_addr; - vm->pt_gpu_addr += vm->sa_bo.offset; + vm->pt = radeon_sa_bo_cpu_addr(&vm->sa_bo); + vm->pt_gpu_addr = radeon_sa_bo_gpu_addr(&vm->sa_bo); memset(vm->pt, 0, RADEON_GPU_PAGE_ALIGN(vm->last_pfn * 8));
retry_id: diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h index 85f33d9..2b71971 100644 --- a/drivers/gpu/drm/radeon/radeon_object.h +++ b/drivers/gpu/drm/radeon/radeon_object.h @@ -146,6 +146,17 @@ extern struct radeon_bo_va *radeon_bo_va(struct radeon_bo *rbo, /* * sub allocation */ + +static inline uint64_t radeon_sa_bo_gpu_addr(struct radeon_sa_bo *sa_bo) +{ + return sa_bo->manager->gpu_addr + sa_bo->offset; +} + +static inline void * radeon_sa_bo_cpu_addr(struct radeon_sa_bo *sa_bo) +{ + return sa_bo->manager->cpu_ptr + sa_bo->offset; +} + extern int radeon_sa_bo_manager_init(struct radeon_device *rdev, struct radeon_sa_manager *sa_manager, unsigned size, u32 domain); diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index f8ecb3e..fc63ebb 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -127,10 +127,8 @@ retry: size, 256, false); if (!r) { *ib = &rdev->ib_pool.ibs[idx]; - (*ib)->ptr = rdev->ib_pool.sa_manager.cpu_ptr; - (*ib)->ptr += ((*ib)->sa_bo.offset >> 2); - (*ib)->gpu_addr = rdev->ib_pool.sa_manager.gpu_addr; - (*ib)->gpu_addr += (*ib)->sa_bo.offset; + (*ib)->ptr = radeon_sa_bo_cpu_addr(&(*ib)->sa_bo); + (*ib)->gpu_addr = radeon_sa_bo_gpu_addr(&(*ib)->sa_bo); (*ib)->fence = fence; (*ib)->vm_id = 0; (*ib)->is_const_ib = false;
From: Christian König deathsimple@vodafone.de
Directly use the suballocator to get small chunks of memory. It's equally fast and doesn't crash when we encounter a GPU reset.
Signed-off-by: Christian König deathsimple@vodafone.de Reviewed-by: Jerome Glisse jglisse@redhat.com --- drivers/gpu/drm/radeon/evergreen.c | 1 - drivers/gpu/drm/radeon/ni.c | 1 - drivers/gpu/drm/radeon/r600.c | 1 - drivers/gpu/drm/radeon/radeon.h | 29 +------ drivers/gpu/drm/radeon/radeon_device.c | 2 - drivers/gpu/drm/radeon/radeon_semaphore.c | 134 ++++------------------------- drivers/gpu/drm/radeon/rv770.c | 1 - drivers/gpu/drm/radeon/si.c | 1 - 8 files changed, 22 insertions(+), 148 deletions(-)
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index ca47f52..a76389c 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -3431,7 +3431,6 @@ void evergreen_fini(struct radeon_device *rdev) evergreen_pcie_gart_fini(rdev); r600_vram_scratch_fini(rdev); radeon_gem_fini(rdev); - radeon_semaphore_driver_fini(rdev); radeon_fence_driver_fini(rdev); radeon_agp_fini(rdev); radeon_bo_fini(rdev); diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 0146428..c0b0956 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -1773,7 +1773,6 @@ void cayman_fini(struct radeon_device *rdev) cayman_pcie_gart_fini(rdev); r600_vram_scratch_fini(rdev); radeon_gem_fini(rdev); - radeon_semaphore_driver_fini(rdev); radeon_fence_driver_fini(rdev); radeon_bo_fini(rdev); radeon_atombios_fini(rdev); diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 06eccd1..a252160 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2672,7 +2672,6 @@ void r600_fini(struct radeon_device *rdev) r600_vram_scratch_fini(rdev); radeon_agp_fini(rdev); radeon_gem_fini(rdev); - radeon_semaphore_driver_fini(rdev); radeon_fence_driver_fini(rdev); radeon_bo_fini(rdev); radeon_atombios_fini(rdev); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 8a6dd46..83ff115 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -432,34 +432,12 @@ int radeon_mode_dumb_destroy(struct drm_file *file_priv, /* * Semaphores. */ -struct radeon_ring; - -#define RADEON_SEMAPHORE_BO_SIZE 256 - -struct radeon_semaphore_driver { - rwlock_t lock; - struct list_head bo; -}; - -struct radeon_semaphore_bo; - -/* everything here is constant */ struct radeon_semaphore { - struct list_head list; - uint64_t gpu_addr; - uint32_t *cpu_ptr; - struct radeon_semaphore_bo *bo; -}; - -struct radeon_semaphore_bo { - struct list_head list; - struct radeon_ib *ib; - struct list_head free; - struct radeon_semaphore semaphores[RADEON_SEMAPHORE_BO_SIZE/8]; - unsigned nused; + struct radeon_sa_bo sa_bo; + signed waiters; + uint64_t gpu_addr; };
-void radeon_semaphore_driver_fini(struct radeon_device *rdev); int radeon_semaphore_create(struct radeon_device *rdev, struct radeon_semaphore **semaphore); void radeon_semaphore_emit_signal(struct radeon_device *rdev, int ring, @@ -1523,7 +1501,6 @@ struct radeon_device { struct radeon_mman mman; rwlock_t fence_lock; struct radeon_fence_driver fence_drv[RADEON_NUM_RINGS]; - struct radeon_semaphore_driver semaphore_drv; struct radeon_ring ring[RADEON_NUM_RINGS]; struct radeon_ib_pool ib_pool; struct radeon_irq irq; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index eb63a06..f314819 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -733,11 +733,9 @@ int radeon_device_init(struct radeon_device *rdev, mutex_init(&rdev->pm.mutex); mutex_init(&rdev->vram_mutex); rwlock_init(&rdev->fence_lock); - rwlock_init(&rdev->semaphore_drv.lock); INIT_LIST_HEAD(&rdev->gem.objects); init_waitqueue_head(&rdev->irq.vblank_queue); init_waitqueue_head(&rdev->irq.idle_queue); - INIT_LIST_HEAD(&rdev->semaphore_drv.bo); /* initialize vm here */ rdev->vm_manager.use_bitmap = 1; rdev->vm_manager.max_pfn = 1 << 20; diff --git a/drivers/gpu/drm/radeon/radeon_semaphore.c b/drivers/gpu/drm/radeon/radeon_semaphore.c index 61dd4e3..a746410 100644 --- a/drivers/gpu/drm/radeon/radeon_semaphore.c +++ b/drivers/gpu/drm/radeon/radeon_semaphore.c @@ -31,108 +31,27 @@ #include "drm.h" #include "radeon.h"
-static int radeon_semaphore_add_bo(struct radeon_device *rdev) +int radeon_semaphore_create(struct radeon_device *rdev, + struct radeon_semaphore **semaphore) { - struct radeon_semaphore_bo *bo; - unsigned long irq_flags; - uint64_t gpu_addr; - uint32_t *cpu_ptr; - int r, i; - + int r;
- bo = kmalloc(sizeof(struct radeon_semaphore_bo), GFP_KERNEL); - if (bo == NULL) { + *semaphore = kmalloc(sizeof(struct radeon_semaphore), GFP_KERNEL); + if (*semaphore == NULL) { return -ENOMEM; } - INIT_LIST_HEAD(&bo->free); - INIT_LIST_HEAD(&bo->list); - bo->nused = 0;
- r = radeon_ib_get(rdev, 0, &bo->ib, RADEON_SEMAPHORE_BO_SIZE); + r = radeon_sa_bo_new(rdev, &rdev->ib_pool.sa_manager, + &(*semaphore)->sa_bo, 8, 8, true); if (r) { - dev_err(rdev->dev, "failed to get a bo after 5 retry\n"); - kfree(bo); + kfree(*semaphore); + *semaphore = NULL; return r; } - gpu_addr = rdev->ib_pool.sa_manager.gpu_addr; - gpu_addr += bo->ib->sa_bo.offset; - cpu_ptr = rdev->ib_pool.sa_manager.cpu_ptr; - cpu_ptr += (bo->ib->sa_bo.offset >> 2); - for (i = 0; i < (RADEON_SEMAPHORE_BO_SIZE/8); i++) { - bo->semaphores[i].gpu_addr = gpu_addr; - bo->semaphores[i].cpu_ptr = cpu_ptr; - bo->semaphores[i].bo = bo; - list_add_tail(&bo->semaphores[i].list, &bo->free); - gpu_addr += 8; - cpu_ptr += 2; - } - write_lock_irqsave(&rdev->semaphore_drv.lock, irq_flags); - list_add_tail(&bo->list, &rdev->semaphore_drv.bo); - write_unlock_irqrestore(&rdev->semaphore_drv.lock, irq_flags); - return 0; -}
-static void radeon_semaphore_del_bo_locked(struct radeon_device *rdev, - struct radeon_semaphore_bo *bo) -{ - radeon_sa_bo_free(rdev, &bo->ib->sa_bo); - radeon_fence_unref(&bo->ib->fence); - list_del(&bo->list); - kfree(bo); -} - -void radeon_semaphore_shrink_locked(struct radeon_device *rdev) -{ - struct radeon_semaphore_bo *bo, *n; - - if (list_empty(&rdev->semaphore_drv.bo)) { - return; - } - /* only shrink if first bo has free semaphore */ - bo = list_first_entry(&rdev->semaphore_drv.bo, struct radeon_semaphore_bo, list); - if (list_empty(&bo->free)) { - return; - } - list_for_each_entry_safe_continue(bo, n, &rdev->semaphore_drv.bo, list) { - if (bo->nused) - continue; - radeon_semaphore_del_bo_locked(rdev, bo); - } -} - -int radeon_semaphore_create(struct radeon_device *rdev, - struct radeon_semaphore **semaphore) -{ - struct radeon_semaphore_bo *bo; - unsigned long irq_flags; - bool do_retry = true; - int r; - -retry: - *semaphore = NULL; - write_lock_irqsave(&rdev->semaphore_drv.lock, irq_flags); - list_for_each_entry(bo, &rdev->semaphore_drv.bo, list) { - if (list_empty(&bo->free)) - continue; - *semaphore = list_first_entry(&bo->free, struct radeon_semaphore, list); - (*semaphore)->cpu_ptr[0] = 0; - (*semaphore)->cpu_ptr[1] = 0; - list_del(&(*semaphore)->list); - bo->nused++; - break; - } - write_unlock_irqrestore(&rdev->semaphore_drv.lock, irq_flags); - - if (*semaphore == NULL) { - if (do_retry) { - do_retry = false; - r = radeon_semaphore_add_bo(rdev); - if (r) - return r; - goto retry; - } - return -ENOMEM; - } + (*semaphore)->waiters = 0; + (*semaphore)->gpu_addr = radeon_sa_bo_gpu_addr(&(*semaphore)->sa_bo); + *((uint64_t*)radeon_sa_bo_cpu_addr(&(*semaphore)->sa_bo)) = 0;
return 0; } @@ -140,39 +59,24 @@ retry: void radeon_semaphore_emit_signal(struct radeon_device *rdev, int ring, struct radeon_semaphore *semaphore) { + --semaphore->waiters; radeon_semaphore_ring_emit(rdev, ring, &rdev->ring[ring], semaphore, false); }
void radeon_semaphore_emit_wait(struct radeon_device *rdev, int ring, struct radeon_semaphore *semaphore) { + ++semaphore->waiters; radeon_semaphore_ring_emit(rdev, ring, &rdev->ring[ring], semaphore, true); }
void radeon_semaphore_free(struct radeon_device *rdev, struct radeon_semaphore *semaphore) { - unsigned long irq_flags; - - write_lock_irqsave(&rdev->semaphore_drv.lock, irq_flags); - semaphore->bo->nused--; - list_add_tail(&semaphore->list, &semaphore->bo->free); - radeon_semaphore_shrink_locked(rdev); - write_unlock_irqrestore(&rdev->semaphore_drv.lock, irq_flags); -} - -void radeon_semaphore_driver_fini(struct radeon_device *rdev) -{ - struct radeon_semaphore_bo *bo, *n; - unsigned long irq_flags; - - write_lock_irqsave(&rdev->semaphore_drv.lock, irq_flags); - /* we force to free everything */ - list_for_each_entry_safe(bo, n, &rdev->semaphore_drv.bo, list) { - if (!list_empty(&bo->free)) { - dev_err(rdev->dev, "still in use semaphore\n"); - } - radeon_semaphore_del_bo_locked(rdev, bo); + if (semaphore->waiters > 0) { + dev_err(rdev->dev, "Semaphore %p has more waiters than signalers," + " hardware lockup imminent!\n", semaphore); } - write_unlock_irqrestore(&rdev->semaphore_drv.lock, irq_flags); + radeon_sa_bo_free(rdev, &semaphore->sa_bo); + kfree(semaphore); } diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index a8b0016..40f82e2 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -1278,7 +1278,6 @@ void rv770_fini(struct radeon_device *rdev) rv770_pcie_gart_fini(rdev); r600_vram_scratch_fini(rdev); radeon_gem_fini(rdev); - radeon_semaphore_driver_fini(rdev); radeon_fence_driver_fini(rdev); radeon_agp_fini(rdev); radeon_bo_fini(rdev); diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 27bda98..f05d37a 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -4117,7 +4117,6 @@ void si_fini(struct radeon_device *rdev) si_pcie_gart_fini(rdev); r600_vram_scratch_fini(rdev); radeon_gem_fini(rdev); - radeon_semaphore_driver_fini(rdev); radeon_fence_driver_fini(rdev); radeon_bo_fini(rdev); radeon_atombios_fini(rdev);
From: Christian König deathsimple@vodafone.de
We should signal the caller that we haven't waited at all.
v2: only change fence_wait_next not fence_wait_last.
Signed-off-by: Christian König deathsimple@vodafone.de Reviewed-by: Michel Dänzer michel.daenzer@amd.com Reviewed-by: Jerome Glisse jglisse@redhat.com --- drivers/gpu/drm/radeon/radeon_fence.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 1a9765a..2fbbc34 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -286,7 +286,7 @@ int radeon_fence_wait_next(struct radeon_device *rdev, int ring) } if (list_empty(&rdev->fence_drv[ring].emitted)) { write_unlock_irqrestore(&rdev->fence_lock, irq_flags); - return 0; + return -ENOENT; } fence = list_entry(rdev->fence_drv[ring].emitted.next, struct radeon_fence, list);
From: Christian König deathsimple@vodafone.de
As discussed with Michel that name better describes the behavior of this function.
Signed-off-by: Christian König deathsimple@vodafone.de Reviewed-by: Michel Dänzer michel.daenzer@amd.com Reviewed-by: Jerome Glisse jglisse@redhat.com --- drivers/gpu/drm/radeon/radeon.h | 2 +- drivers/gpu/drm/radeon/radeon_device.c | 2 +- drivers/gpu/drm/radeon/radeon_fence.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 83ff115..fbbbc5a 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -285,7 +285,7 @@ void radeon_fence_process(struct radeon_device *rdev, int ring); bool radeon_fence_signaled(struct radeon_fence *fence); int radeon_fence_wait(struct radeon_fence *fence, bool interruptible); int radeon_fence_wait_next(struct radeon_device *rdev, int ring); -int radeon_fence_wait_last(struct radeon_device *rdev, int ring); +int radeon_fence_wait_empty(struct radeon_device *rdev, int ring); struct radeon_fence *radeon_fence_ref(struct radeon_fence *fence); void radeon_fence_unref(struct radeon_fence **fence); int radeon_fence_count_emitted(struct radeon_device *rdev, int ring); diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index f314819..d77f19f 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -913,7 +913,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) radeon_bo_evict_vram(rdev); /* wait for gpu to finish processing current batch */ for (i = 0; i < RADEON_NUM_RINGS; i++) - radeon_fence_wait_last(rdev, i); + radeon_fence_wait_empty(rdev, i);
radeon_save_bios_scratch_regs(rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 2fbbc34..2d13843 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -297,7 +297,7 @@ int radeon_fence_wait_next(struct radeon_device *rdev, int ring) return r; }
-int radeon_fence_wait_last(struct radeon_device *rdev, int ring) +int radeon_fence_wait_empty(struct radeon_device *rdev, int ring) { unsigned long irq_flags; struct radeon_fence *fence; @@ -442,7 +442,7 @@ void radeon_fence_driver_fini(struct radeon_device *rdev) for (ring = 0; ring < RADEON_NUM_RINGS; ring++) { if (!rdev->fence_drv[ring].initialized) continue; - radeon_fence_wait_last(rdev, ring); + radeon_fence_wait_empty(rdev, ring); wake_up_all(&rdev->fence_drv[ring].queue); write_lock_irqsave(&rdev->fence_lock, irq_flags); radeon_scratch_free(rdev, rdev->fence_drv[ring].scratch_reg);
From: Christian König deathsimple@vodafone.de
Should be used to free resource that are protected by a fence.
Signed-off-by: Christian König deathsimple@vodafone.de Reviewed-by: Jerome Glisse jglisse@redhat.com --- drivers/gpu/drm/radeon/radeon.h | 8 ++++- drivers/gpu/drm/radeon/radeon_fence.c | 50 +++++++++++++++++++++++++++++--- 2 files changed, 52 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index fbbbc5a..11cceb3 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -259,7 +259,6 @@ struct radeon_fence_driver { wait_queue_head_t queue; struct list_head created; struct list_head emitted; - struct list_head signaled; bool initialized; };
@@ -274,6 +273,10 @@ struct radeon_fence { /* RB, DMA, etc. */ int ring; struct radeon_semaphore *semaphore; + + /* called when fence is signaled */ + void (*signal_callback)(struct radeon_device *rdev, void *data); + void *callback_data; };
int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring); @@ -289,6 +292,9 @@ int radeon_fence_wait_empty(struct radeon_device *rdev, int ring); struct radeon_fence *radeon_fence_ref(struct radeon_fence *fence); void radeon_fence_unref(struct radeon_fence **fence); int radeon_fence_count_emitted(struct radeon_device *rdev, int ring); +bool radeon_fence_set_signal_callback(struct radeon_fence *fence, + void (*callback)(struct radeon_device *, void *), + void *data);
/* * Tiling registers diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 2d13843..c58660a 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -83,7 +83,8 @@ int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence) return 0; }
-static bool radeon_fence_poll_locked(struct radeon_device *rdev, int ring) +static bool radeon_fence_poll_locked(struct radeon_device *rdev, int ring, + struct list_head *signaled) { struct radeon_fence *fence; struct list_head *i, *n; @@ -110,7 +111,7 @@ static bool radeon_fence_poll_locked(struct radeon_device *rdev, int ring) i = n; do { n = i->prev; - list_move_tail(i, &rdev->fence_drv[ring].signaled); + list_move_tail(i, signaled); fence = list_entry(i, struct radeon_fence, list); fence->signaled = true; i = n; @@ -120,6 +121,20 @@ static bool radeon_fence_poll_locked(struct radeon_device *rdev, int ring) return wake; }
+static void radeon_fence_process_signaled(struct radeon_device *rdev, struct list_head *signaled) +{ + struct radeon_fence *fence; + struct list_head *i, *n; + + list_for_each_safe(i, n, signaled) { + fence = list_entry(i, struct radeon_fence, list); + list_del_init(&fence->list); + if (fence->signal_callback) { + fence->signal_callback(rdev, fence->callback_data); + } + } +} + static void radeon_fence_destroy(struct kref *kref) { unsigned long irq_flags; @@ -152,6 +167,8 @@ int radeon_fence_create(struct radeon_device *rdev, (*fence)->seq = 0; (*fence)->ring = ring; (*fence)->semaphore = NULL; + (*fence)->signal_callback = NULL; + (*fence)->callback_data = NULL; INIT_LIST_HEAD(&(*fence)->list);
write_lock_irqsave(&rdev->fence_lock, irq_flags); @@ -164,6 +181,7 @@ bool radeon_fence_signaled(struct radeon_fence *fence) { unsigned long irq_flags; bool signaled = false; + LIST_HEAD(siglist);
if (!fence) return true; @@ -179,10 +197,12 @@ bool radeon_fence_signaled(struct radeon_fence *fence) signaled = true; } if (!signaled) { - radeon_fence_poll_locked(fence->rdev, fence->ring); + radeon_fence_poll_locked(fence->rdev, fence->ring, &siglist); signaled = fence->signaled; } write_unlock_irqrestore(&fence->rdev->fence_lock, irq_flags); + radeon_fence_process_signaled(fence->rdev, &siglist); + return signaled; }
@@ -341,10 +361,12 @@ void radeon_fence_process(struct radeon_device *rdev, int ring) { unsigned long irq_flags; bool wake; + LIST_HEAD(signaled);
write_lock_irqsave(&rdev->fence_lock, irq_flags); - wake = radeon_fence_poll_locked(rdev, ring); + wake = radeon_fence_poll_locked(rdev, ring, &signaled); write_unlock_irqrestore(&rdev->fence_lock, irq_flags); + radeon_fence_process_signaled(rdev, &signaled); if (wake) { wake_up_all(&rdev->fence_drv[ring].queue); } @@ -373,6 +395,25 @@ int radeon_fence_count_emitted(struct radeon_device *rdev, int ring) return not_processed; }
+bool radeon_fence_set_signal_callback(struct radeon_fence *fence, + void (*callback)(struct radeon_device *, void *), + void *data) +{ + struct radeon_device *rdev = fence->rdev; + unsigned long irq_flags; + bool isset = false; + + /* a readlock is suficient, cause this should be called only once */ + read_lock_irqsave(&rdev->fence_lock, irq_flags); + if (fence->emitted && !fence->signaled) { + fence->signal_callback = callback; + fence->callback_data = data; + isset = true; + } + read_unlock_irqrestore(&rdev->fence_lock, irq_flags); + return isset; +} + int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring) { unsigned long irq_flags; @@ -413,7 +454,6 @@ static void radeon_fence_driver_init_ring(struct radeon_device *rdev, int ring) atomic_set(&rdev->fence_drv[ring].seq, 0); INIT_LIST_HEAD(&rdev->fence_drv[ring].created); INIT_LIST_HEAD(&rdev->fence_drv[ring].emitted); - INIT_LIST_HEAD(&rdev->fence_drv[ring].signaled); init_waitqueue_head(&rdev->fence_drv[ring].queue); rdev->fence_drv[ring].initialized = false; }
From: Christian König deathsimple@vodafone.de
It's never used and so practically superfluous.
Signed-off-by: Christian König deathsimple@vodafone.de Reviewed-by: Jerome Glisse jglisse@redhat.com --- drivers/gpu/drm/radeon/radeon.h | 1 - drivers/gpu/drm/radeon/radeon_fence.c | 7 ------- 2 files changed, 0 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 11cceb3..fa4dc73 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -257,7 +257,6 @@ struct radeon_fence_driver { uint32_t last_seq; unsigned long last_activity; wait_queue_head_t queue; - struct list_head created; struct list_head emitted; bool initialized; }; diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index c58660a..326bdb5 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -154,8 +154,6 @@ int radeon_fence_create(struct radeon_device *rdev, struct radeon_fence **fence, int ring) { - unsigned long irq_flags; - *fence = kmalloc(sizeof(struct radeon_fence), GFP_KERNEL); if ((*fence) == NULL) { return -ENOMEM; @@ -170,10 +168,6 @@ int radeon_fence_create(struct radeon_device *rdev, (*fence)->signal_callback = NULL; (*fence)->callback_data = NULL; INIT_LIST_HEAD(&(*fence)->list); - - write_lock_irqsave(&rdev->fence_lock, irq_flags); - list_add_tail(&(*fence)->list, &rdev->fence_drv[ring].created); - write_unlock_irqrestore(&rdev->fence_lock, irq_flags); return 0; }
@@ -452,7 +446,6 @@ static void radeon_fence_driver_init_ring(struct radeon_device *rdev, int ring) rdev->fence_drv[ring].cpu_addr = NULL; rdev->fence_drv[ring].gpu_addr = 0; atomic_set(&rdev->fence_drv[ring].seq, 0); - INIT_LIST_HEAD(&rdev->fence_drv[ring].created); INIT_LIST_HEAD(&rdev->fence_drv[ring].emitted); init_waitqueue_head(&rdev->fence_drv[ring].queue); rdev->fence_drv[ring].initialized = false;
From: Christian König deathsimple@vodafone.de
To prevent deadlocks under extreme conditions.
v2: rebase on top of new sa_manager patch
Signed-off-by: Christian König deathsimple@vodafone.de Reviewed-by: Jerome Glisse jglisse@redhat.com --- drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_gart.c | 2 +- drivers/gpu/drm/radeon/radeon_object.h | 3 ++- drivers/gpu/drm/radeon/radeon_ring.c | 2 +- drivers/gpu/drm/radeon/radeon_sa.c | 8 +++++++- 5 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index fa4dc73..f18aa13 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -397,6 +397,7 @@ struct radeon_sa_manager { uint64_t gpu_addr; void *cpu_ptr; uint32_t domain; + void (*try_free)(struct radeon_device *); };
struct radeon_sa_bo; diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 96a2a81..1766671 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -291,7 +291,7 @@ int radeon_vm_manager_init(struct radeon_device *rdev) /* mark first vm as always in use, it's the system one */ r = radeon_sa_bo_manager_init(rdev, &rdev->vm_manager.sa_manager, rdev->vm_manager.max_pfn * 8, - RADEON_GEM_DOMAIN_VRAM); + RADEON_GEM_DOMAIN_VRAM, NULL); if (r) { dev_err(rdev->dev, "failed to allocate vm bo (%dKB)\n", (rdev->vm_manager.max_pfn * 8) >> 10); diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h index 2b71971..242c76f 100644 --- a/drivers/gpu/drm/radeon/radeon_object.h +++ b/drivers/gpu/drm/radeon/radeon_object.h @@ -159,7 +159,8 @@ static inline void * radeon_sa_bo_cpu_addr(struct radeon_sa_bo *sa_bo)
extern int radeon_sa_bo_manager_init(struct radeon_device *rdev, struct radeon_sa_manager *sa_manager, - unsigned size, u32 domain); + unsigned size, u32 domain, + void (*try_free)(struct radeon_device *rdev)); extern void radeon_sa_bo_manager_fini(struct radeon_device *rdev, struct radeon_sa_manager *sa_manager); extern int radeon_sa_bo_manager_start(struct radeon_device *rdev, diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index fc63ebb..0293342 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -208,7 +208,7 @@ int radeon_ib_pool_init(struct radeon_device *rdev)
r = radeon_sa_bo_manager_init(rdev, &tmp, RADEON_IB_POOL_SIZE*64*1024, - RADEON_GEM_DOMAIN_GTT); + RADEON_GEM_DOMAIN_GTT, NULL); if (r) { return r; } diff --git a/drivers/gpu/drm/radeon/radeon_sa.c b/drivers/gpu/drm/radeon/radeon_sa.c index f7b20b1..6541b0d 100644 --- a/drivers/gpu/drm/radeon/radeon_sa.c +++ b/drivers/gpu/drm/radeon/radeon_sa.c @@ -33,7 +33,8 @@
int radeon_sa_bo_manager_init(struct radeon_device *rdev, struct radeon_sa_manager *sa_manager, - unsigned size, u32 domain) + unsigned size, u32 domain, + void (*try_free)(struct radeon_device *rdev)) { int r;
@@ -45,6 +46,7 @@ int radeon_sa_bo_manager_init(struct radeon_device *rdev, sa_manager->ehole_size = size; sa_manager->ehole_offset = 0; sa_manager->domain = domain; + sa_manager->try_free = try_free; INIT_LIST_HEAD(&sa_manager->sa_bo);
r = radeon_bo_create(rdev, size, RADEON_GPU_PAGE_SIZE, true, @@ -183,6 +185,10 @@ retry: /* failed to find something big enough, wait * for the biggest hole to increase in size */ + if (sa_manager->try_free) { + /* try to free something */ + sa_manager->try_free(rdev); + } r = wait_event_interruptible(sa_manager->queue, radeon_sa_bo_max_free(sa_manager, align) >= size); if (r) {
From: Christian König deathsimple@vodafone.de
It isn't necessary any more and the suballocator seems to perform even better.
v2: ignore ERESTARTSYS in error reporting, split fence changes into seperate patch, use try_free SA callback to avoid lockups v3: rebase on top of sa manager new patch
Signed-off-by: Christian König deathsimple@vodafone.de Reviewed-by: Jerome Glisse jglisse@redhat.com --- drivers/gpu/drm/radeon/radeon.h | 17 +-- drivers/gpu/drm/radeon/radeon_device.c | 1 - drivers/gpu/drm/radeon/radeon_gart.c | 12 +- drivers/gpu/drm/radeon/radeon_ring.c | 274 ++++++++++------------------- drivers/gpu/drm/radeon/radeon_semaphore.c | 2 +- 5 files changed, 103 insertions(+), 203 deletions(-)
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index f18aa13..0c8893d 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -614,7 +614,6 @@ void radeon_irq_kms_pflip_irq_put(struct radeon_device *rdev, int crtc);
struct radeon_ib { struct radeon_sa_bo sa_bo; - unsigned idx; uint32_t length_dw; uint64_t gpu_addr; uint32_t *ptr; @@ -623,18 +622,6 @@ struct radeon_ib { bool is_const_ib; };
-/* - * locking - - * mutex protects scheduled_ibs, ready, alloc_bm - */ -struct radeon_ib_pool { - struct radeon_mutex mutex; - struct radeon_sa_manager sa_manager; - struct radeon_ib ibs[RADEON_IB_POOL_SIZE]; - bool ready; - unsigned head_id; -}; - struct radeon_ring { struct radeon_bo *ring_obj; volatile uint32_t *ring; @@ -775,7 +762,6 @@ struct si_rlc { int radeon_ib_get(struct radeon_device *rdev, int ring, struct radeon_ib **ib, unsigned size); void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib **ib); -bool radeon_ib_try_free(struct radeon_device *rdev, struct radeon_ib *ib); int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib); int radeon_ib_pool_init(struct radeon_device *rdev); void radeon_ib_pool_fini(struct radeon_device *rdev); @@ -1508,7 +1494,8 @@ struct radeon_device { rwlock_t fence_lock; struct radeon_fence_driver fence_drv[RADEON_NUM_RINGS]; struct radeon_ring ring[RADEON_NUM_RINGS]; - struct radeon_ib_pool ib_pool; + bool ib_pool_ready; + struct radeon_sa_manager sa_manager; struct radeon_irq irq; struct radeon_asic *asic; struct radeon_gem gem; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index d77f19f..26fb9da 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -723,7 +723,6 @@ int radeon_device_init(struct radeon_device *rdev, /* mutex initialization are all done here so we * can recall function without having locking issues */ radeon_mutex_init(&rdev->cs_mutex); - radeon_mutex_init(&rdev->ib_pool.mutex); for (i = 0; i < RADEON_NUM_RINGS; ++i) mutex_init(&rdev->ring[i].mutex); mutex_init(&rdev->dc_hw_i2c_mutex); diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 1766671..8eba1c6 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -432,8 +432,8 @@ retry_id: rdev->vm_manager.use_bitmap |= 1 << id; vm->id = id; list_add_tail(&vm->list, &rdev->vm_manager.lru_vm); - return radeon_vm_bo_update_pte(rdev, vm, rdev->ib_pool.sa_manager.bo, - &rdev->ib_pool.sa_manager.bo->tbo.mem); + return radeon_vm_bo_update_pte(rdev, vm, rdev->sa_manager.bo, + &rdev->sa_manager.bo->tbo.mem); }
/* object have to be reserved */ @@ -631,7 +631,7 @@ int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm) /* map the ib pool buffer at 0 in virtual address space, set * read only */ - r = radeon_vm_bo_add(rdev, vm, rdev->ib_pool.sa_manager.bo, 0, + r = radeon_vm_bo_add(rdev, vm, rdev->sa_manager.bo, 0, RADEON_VM_PAGE_READABLE | RADEON_VM_PAGE_SNOOPED); return r; } @@ -648,12 +648,12 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm) radeon_mutex_unlock(&rdev->cs_mutex);
/* remove all bo */ - r = radeon_bo_reserve(rdev->ib_pool.sa_manager.bo, false); + r = radeon_bo_reserve(rdev->sa_manager.bo, false); if (!r) { - bo_va = radeon_bo_va(rdev->ib_pool.sa_manager.bo, vm); + bo_va = radeon_bo_va(rdev->sa_manager.bo, vm); list_del_init(&bo_va->bo_list); list_del_init(&bo_va->vm_list); - radeon_bo_unreserve(rdev->ib_pool.sa_manager.bo); + radeon_bo_unreserve(rdev->sa_manager.bo); kfree(bo_va); } if (!list_empty(&vm->va)) { diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index 0293342..7031d69 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -24,6 +24,7 @@ * Authors: Dave Airlie * Alex Deucher * Jerome Glisse + * Christian König */ #include <linux/seq_file.h> #include <linux/slab.h> @@ -33,8 +34,10 @@ #include "radeon.h" #include "atom.h"
-int radeon_debugfs_ib_init(struct radeon_device *rdev); -int radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ring *ring); +/* + * IB. + */ +int radeon_debugfs_sa_init(struct radeon_device *rdev);
u32 radeon_get_ib_value(struct radeon_cs_parser *p, int idx) { @@ -61,121 +64,71 @@ u32 radeon_get_ib_value(struct radeon_cs_parser *p, int idx) return idx_value; }
-void radeon_ring_write(struct radeon_ring *ring, uint32_t v) -{ -#if DRM_DEBUG_CODE - if (ring->count_dw <= 0) { - DRM_ERROR("radeon: writting more dword to ring than expected !\n"); - } -#endif - ring->ring[ring->wptr++] = v; - ring->wptr &= ring->ptr_mask; - ring->count_dw--; - ring->ring_free_dw--; -} - -/* - * IB. - */ -bool radeon_ib_try_free(struct radeon_device *rdev, struct radeon_ib *ib) -{ - bool done = false; - - /* only free ib which have been emited */ - if (ib->fence && ib->fence->emitted) { - if (radeon_fence_signaled(ib->fence)) { - radeon_fence_unref(&ib->fence); - radeon_sa_bo_free(rdev, &ib->sa_bo); - done = true; - } - } - return done; -} - int radeon_ib_get(struct radeon_device *rdev, int ring, struct radeon_ib **ib, unsigned size) { - struct radeon_fence *fence; - unsigned cretry = 0; - int r = 0, i, idx; + int r;
- *ib = NULL; - /* align size on 256 bytes */ - size = ALIGN(size, 256); + *ib = kmalloc(sizeof(struct radeon_ib), GFP_KERNEL); + if (*ib == NULL) { + return -ENOMEM; + }
- r = radeon_fence_create(rdev, &fence, ring); + r = radeon_sa_bo_new(rdev, &rdev->sa_manager, &(*ib)->sa_bo, size, 256, true); if (r) { - dev_err(rdev->dev, "failed to create fence for new IB\n"); + if (r != -ERESTARTSYS) { + dev_err(rdev->dev, "failed to get a new IB (%d)\n", r); + } + kfree(*ib); + *ib = NULL; return r; }
- radeon_mutex_lock(&rdev->ib_pool.mutex); - idx = rdev->ib_pool.head_id; -retry: - if (cretry > 5) { - dev_err(rdev->dev, "failed to get an ib after 5 retry\n"); - radeon_mutex_unlock(&rdev->ib_pool.mutex); - radeon_fence_unref(&fence); - return -ENOMEM; - } - cretry++; - for (i = 0; i < RADEON_IB_POOL_SIZE; i++) { - radeon_ib_try_free(rdev, &rdev->ib_pool.ibs[idx]); - if (rdev->ib_pool.ibs[idx].fence == NULL) { - r = radeon_sa_bo_new(rdev, &rdev->ib_pool.sa_manager, - &rdev->ib_pool.ibs[idx].sa_bo, - size, 256, false); - if (!r) { - *ib = &rdev->ib_pool.ibs[idx]; - (*ib)->ptr = radeon_sa_bo_cpu_addr(&(*ib)->sa_bo); - (*ib)->gpu_addr = radeon_sa_bo_gpu_addr(&(*ib)->sa_bo); - (*ib)->fence = fence; - (*ib)->vm_id = 0; - (*ib)->is_const_ib = false; - /* ib are most likely to be allocated in a ring fashion - * thus rdev->ib_pool.head_id should be the id of the - * oldest ib - */ - rdev->ib_pool.head_id = (1 + idx); - rdev->ib_pool.head_id &= (RADEON_IB_POOL_SIZE - 1); - radeon_mutex_unlock(&rdev->ib_pool.mutex); - return 0; - } - } - idx = (idx + 1) & (RADEON_IB_POOL_SIZE - 1); - } - /* this should be rare event, ie all ib scheduled none signaled yet. - */ - for (i = 0; i < RADEON_IB_POOL_SIZE; i++) { - if (rdev->ib_pool.ibs[idx].fence && rdev->ib_pool.ibs[idx].fence->emitted) { - r = radeon_fence_wait(rdev->ib_pool.ibs[idx].fence, false); - if (!r) { - goto retry; - } - /* an error happened */ - break; - } - idx = (idx + 1) & (RADEON_IB_POOL_SIZE - 1); + r = radeon_fence_create(rdev, &(*ib)->fence, ring); + if (r) { + dev_err(rdev->dev, "failed to create fence for new IB (%d)\n", r); + radeon_sa_bo_free(rdev, &(*ib)->sa_bo); + kfree(*ib); + *ib = NULL; + return r; } - radeon_mutex_unlock(&rdev->ib_pool.mutex); - radeon_fence_unref(&fence); - return r; + + (*ib)->ptr = rdev->sa_manager.cpu_ptr; + (*ib)->ptr += ((*ib)->sa_bo.offset >> 2); + (*ib)->gpu_addr = rdev->sa_manager.gpu_addr; + (*ib)->gpu_addr += (*ib)->sa_bo.offset; + (*ib)->vm_id = 0; + (*ib)->is_const_ib = false; + + return 0; +} + +static void radeon_ib_destroy(struct radeon_device *rdev, void *data) +{ + struct radeon_ib *ib = data; + radeon_sa_bo_free(rdev, &ib->sa_bo); + radeon_fence_unref(&ib->fence); + kfree(ib); }
void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib **ib) { struct radeon_ib *tmp = *ib; + bool destroy = true;
*ib = NULL; if (tmp == NULL) { return; } - radeon_mutex_lock(&rdev->ib_pool.mutex); - if (tmp->fence && !tmp->fence->emitted) { - radeon_sa_bo_free(rdev, &tmp->sa_bo); - radeon_fence_unref(&tmp->fence); + + if (tmp->fence) { + destroy = !radeon_fence_set_signal_callback( + tmp->fence, radeon_ib_destroy, tmp); + } + + if (destroy) { + radeon_ib_destroy(rdev, tmp); } - radeon_mutex_unlock(&rdev->ib_pool.mutex); }
int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib) @@ -185,7 +138,7 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib)
if (!ib->length_dw || !ring->ready) { /* TODO: Nothings in the ib we should report. */ - DRM_ERROR("radeon: couldn't schedule IB(%u).\n", ib->idx); + DRM_ERROR("radeon: couldn't schedule IB.\n"); return -EINVAL; }
@@ -201,72 +154,58 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib) return 0; }
+static void radeon_ib_try_free(struct radeon_device *rdev) +{ + int ring; + + for (ring = 0; ring < RADEON_NUM_RINGS; ring++) { + if (rdev->fence_drv[ring].initialized) + radeon_fence_process(rdev, ring); + } +} + int radeon_ib_pool_init(struct radeon_device *rdev) { - struct radeon_sa_manager tmp; - int i, r; + int r;
- r = radeon_sa_bo_manager_init(rdev, &tmp, + if (rdev->ib_pool_ready) { + return 0; + } + + r = radeon_sa_bo_manager_init(rdev, &rdev->sa_manager, RADEON_IB_POOL_SIZE*64*1024, - RADEON_GEM_DOMAIN_GTT, NULL); + RADEON_GEM_DOMAIN_GTT, + radeon_ib_try_free); if (r) { return r; }
- radeon_mutex_lock(&rdev->ib_pool.mutex); - if (rdev->ib_pool.ready) { - radeon_mutex_unlock(&rdev->ib_pool.mutex); - radeon_sa_bo_manager_fini(rdev, &tmp); - return 0; + if (radeon_debugfs_sa_init(rdev)) { + DRM_ERROR("Failed to register debugfs file for SA !\n"); }
- /* copy over the sa_manager we have to do this to silence - * kernel possible deadlock detection code to complain about - * a false positive - */ - rdev->ib_pool.sa_manager = tmp; - INIT_LIST_HEAD(&rdev->ib_pool.sa_manager.sa_bo); - for (i = 0; i < RADEON_IB_POOL_SIZE; i++) { - rdev->ib_pool.ibs[i].fence = NULL; - rdev->ib_pool.ibs[i].idx = i; - rdev->ib_pool.ibs[i].length_dw = 0; - INIT_LIST_HEAD(&rdev->ib_pool.ibs[i].sa_bo.list); - } - rdev->ib_pool.head_id = 0; - rdev->ib_pool.ready = true; DRM_INFO("radeon: ib pool ready.\n"); + rdev->ib_pool_ready = true;
- if (radeon_debugfs_ib_init(rdev)) { - DRM_ERROR("Failed to register debugfs file for IB !\n"); - } - radeon_mutex_unlock(&rdev->ib_pool.mutex); return 0; }
void radeon_ib_pool_fini(struct radeon_device *rdev) { - unsigned i; - - radeon_mutex_lock(&rdev->ib_pool.mutex); - if (rdev->ib_pool.ready) { - for (i = 0; i < RADEON_IB_POOL_SIZE; i++) { - radeon_sa_bo_free(rdev, &rdev->ib_pool.ibs[i].sa_bo); - radeon_fence_unref(&rdev->ib_pool.ibs[i].fence); - } - radeon_sa_bo_manager_fini(rdev, &rdev->ib_pool.sa_manager); - rdev->ib_pool.ready = false; + if (rdev->ib_pool_ready) { + radeon_sa_bo_manager_fini(rdev, &rdev->sa_manager); + rdev->ib_pool_ready = false; } - radeon_mutex_unlock(&rdev->ib_pool.mutex); }
int radeon_ib_pool_start(struct radeon_device *rdev) { - return radeon_sa_bo_manager_start(rdev, &rdev->ib_pool.sa_manager); + return radeon_sa_bo_manager_start(rdev, &rdev->sa_manager); }
int radeon_ib_pool_suspend(struct radeon_device *rdev) { - return radeon_sa_bo_manager_suspend(rdev, &rdev->ib_pool.sa_manager); + return radeon_sa_bo_manager_suspend(rdev, &rdev->sa_manager); }
int radeon_ib_ring_tests(struct radeon_device *rdev) @@ -302,6 +241,21 @@ int radeon_ib_ring_tests(struct radeon_device *rdev) /* * Ring. */ +int radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ring *ring); + +void radeon_ring_write(struct radeon_ring *ring, uint32_t v) +{ +#if DRM_DEBUG_CODE + if (ring->count_dw <= 0) { + DRM_ERROR("radeon: writting more dword to ring than expected !\n"); + } +#endif + ring->ring[ring->wptr++] = v; + ring->wptr &= ring->ptr_mask; + ring->count_dw--; + ring->ring_free_dw--; +} + int radeon_ring_index(struct radeon_device *rdev, struct radeon_ring *ring) { /* r1xx-r5xx only has CP ring */ @@ -508,37 +462,13 @@ static struct drm_info_list radeon_debugfs_ring_info_list[] = { {"radeon_ring_cp2", radeon_debugfs_ring_info, 0, &cayman_ring_type_cp2_index}, };
-static int radeon_debugfs_ib_info(struct seq_file *m, void *data) -{ - struct drm_info_node *node = (struct drm_info_node *) m->private; - struct drm_device *dev = node->minor->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_ib *ib = &rdev->ib_pool.ibs[*((unsigned*)node->info_ent->data)]; - unsigned i; - - if (ib == NULL) { - return 0; - } - seq_printf(m, "IB %04u\n", ib->idx); - seq_printf(m, "IB fence %p\n", ib->fence); - seq_printf(m, "IB size %05u dwords\n", ib->length_dw); - for (i = 0; i < ib->length_dw; i++) { - seq_printf(m, "[%05u]=0x%08X\n", i, ib->ptr[i]); - } - return 0; -} - -static struct drm_info_list radeon_debugfs_ib_list[RADEON_IB_POOL_SIZE]; -static char radeon_debugfs_ib_names[RADEON_IB_POOL_SIZE][32]; -static unsigned radeon_debugfs_ib_idx[RADEON_IB_POOL_SIZE]; - static int radeon_debugfs_sa_info(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; struct radeon_device *rdev = dev->dev_private;
- radeon_sa_bo_dump_debug_info(&rdev->ib_pool.sa_manager, m); + radeon_sa_bo_dump_debug_info(&rdev->sa_manager, m);
return 0;
@@ -570,26 +500,10 @@ int radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ring *rin return 0; }
-int radeon_debugfs_ib_init(struct radeon_device *rdev) +int radeon_debugfs_sa_init(struct radeon_device *rdev) { #if defined(CONFIG_DEBUG_FS) - unsigned i; - int r; - - r = radeon_debugfs_add_files(rdev, radeon_debugfs_sa_list, 1); - if (r) - return r; - - for (i = 0; i < RADEON_IB_POOL_SIZE; i++) { - sprintf(radeon_debugfs_ib_names[i], "radeon_ib_%04u", i); - radeon_debugfs_ib_idx[i] = i; - radeon_debugfs_ib_list[i].name = radeon_debugfs_ib_names[i]; - radeon_debugfs_ib_list[i].show = &radeon_debugfs_ib_info; - radeon_debugfs_ib_list[i].driver_features = 0; - radeon_debugfs_ib_list[i].data = &radeon_debugfs_ib_idx[i]; - } - return radeon_debugfs_add_files(rdev, radeon_debugfs_ib_list, - RADEON_IB_POOL_SIZE); + return radeon_debugfs_add_files(rdev, radeon_debugfs_sa_list, 1); #else return 0; #endif diff --git a/drivers/gpu/drm/radeon/radeon_semaphore.c b/drivers/gpu/drm/radeon/radeon_semaphore.c index a746410..4cdcef2 100644 --- a/drivers/gpu/drm/radeon/radeon_semaphore.c +++ b/drivers/gpu/drm/radeon/radeon_semaphore.c @@ -41,7 +41,7 @@ int radeon_semaphore_create(struct radeon_device *rdev, return -ENOMEM; }
- r = radeon_sa_bo_new(rdev, &rdev->ib_pool.sa_manager, + r = radeon_sa_bo_new(rdev, &rdev->sa_manager, &(*semaphore)->sa_bo, 8, 8, true); if (r) { kfree(*semaphore);
From: Christian König deathsimple@vodafone.de
Rings need to lock in order, otherwise the ring subsystem can deadlock.
v2: fix error handling and number of locked doublewords. v3: stop creating unneeded semaphores.
Signed-off-by: Christian König deathsimple@vodafone.de Reviewed-by: Jerome Glisse jglisse@redhat.com --- drivers/gpu/drm/radeon/radeon.h | 4 ++ drivers/gpu/drm/radeon/radeon_cs.c | 35 ++++++------------ drivers/gpu/drm/radeon/radeon_semaphore.c | 56 +++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_ttm.c | 48 +++++++++++-------------- 4 files changed, 93 insertions(+), 50 deletions(-)
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 0c8893d..a231566 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -450,6 +450,10 @@ void radeon_semaphore_emit_signal(struct radeon_device *rdev, int ring, struct radeon_semaphore *semaphore); void radeon_semaphore_emit_wait(struct radeon_device *rdev, int ring, struct radeon_semaphore *semaphore); +int radeon_semaphore_sync_rings(struct radeon_device *rdev, + struct radeon_semaphore *semaphore, + bool sync_to[RADEON_NUM_RINGS], + int dst_ring); void radeon_semaphore_free(struct radeon_device *rdev, struct radeon_semaphore *semaphore);
diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index 5cac832..64b86e7 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -118,6 +118,7 @@ static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority static int radeon_cs_sync_rings(struct radeon_cs_parser *p) { bool sync_to_ring[RADEON_NUM_RINGS] = { }; + bool need_sync = false; int i, r;
for (i = 0; i < p->nrelocs; i++) { @@ -126,36 +127,24 @@ static int radeon_cs_sync_rings(struct radeon_cs_parser *p)
if (!(p->relocs[i].flags & RADEON_RELOC_DONT_SYNC)) { struct radeon_fence *fence = p->relocs[i].robj->tbo.sync_obj; - if (!radeon_fence_signaled(fence)) { + if (fence->ring != p->ring && !radeon_fence_signaled(fence)) { sync_to_ring[fence->ring] = true; + need_sync = true; } } }
- for (i = 0; i < RADEON_NUM_RINGS; ++i) { - /* no need to sync to our own or unused rings */ - if (i == p->ring || !sync_to_ring[i] || !p->rdev->ring[i].ready) - continue; - - if (!p->ib->fence->semaphore) { - r = radeon_semaphore_create(p->rdev, &p->ib->fence->semaphore); - if (r) - return r; - } - - r = radeon_ring_lock(p->rdev, &p->rdev->ring[i], 3); - if (r) - return r; - radeon_semaphore_emit_signal(p->rdev, i, p->ib->fence->semaphore); - radeon_ring_unlock_commit(p->rdev, &p->rdev->ring[i]); + if (!need_sync) { + return 0; + }
- r = radeon_ring_lock(p->rdev, &p->rdev->ring[p->ring], 3); - if (r) - return r; - radeon_semaphore_emit_wait(p->rdev, p->ring, p->ib->fence->semaphore); - radeon_ring_unlock_commit(p->rdev, &p->rdev->ring[p->ring]); + r = radeon_semaphore_create(p->rdev, &p->ib->fence->semaphore); + if (r) { + return r; } - return 0; + + return radeon_semaphore_sync_rings(p->rdev, p->ib->fence->semaphore, + sync_to_ring, p->ring); }
int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data) diff --git a/drivers/gpu/drm/radeon/radeon_semaphore.c b/drivers/gpu/drm/radeon/radeon_semaphore.c index 4cdcef2..799e439 100644 --- a/drivers/gpu/drm/radeon/radeon_semaphore.c +++ b/drivers/gpu/drm/radeon/radeon_semaphore.c @@ -70,6 +70,62 @@ void radeon_semaphore_emit_wait(struct radeon_device *rdev, int ring, radeon_semaphore_ring_emit(rdev, ring, &rdev->ring[ring], semaphore, true); }
+int radeon_semaphore_sync_rings(struct radeon_device *rdev, + struct radeon_semaphore *semaphore, + bool sync_to[RADEON_NUM_RINGS], + int dst_ring) +{ + int i, r; + + for (i = 0; i < RADEON_NUM_RINGS; ++i) { + unsigned num_ops = i == dst_ring ? RADEON_NUM_RINGS : 1; + + /* don't lock unused rings */ + if (!sync_to[i] && i != dst_ring) + continue; + + /* prevent GPU deadlocks */ + if (!rdev->ring[i].ready) { + dev_err(rdev->dev, "Trying to sync to a disabled ring!"); + r = -EINVAL; + goto error; + } + + r = radeon_ring_lock(rdev, &rdev->ring[i], num_ops * 8); + if (r) + goto error; + } + + for (i = 0; i < RADEON_NUM_RINGS; ++i) { + /* no need to sync to our own or unused rings */ + if (!sync_to[i] || i == dst_ring) + continue; + + radeon_semaphore_emit_signal(rdev, i, semaphore); + radeon_semaphore_emit_wait(rdev, dst_ring, semaphore); + } + + for (i = 0; i < RADEON_NUM_RINGS; ++i) { + + /* don't unlock unused rings */ + if (!sync_to[i] && i != dst_ring) + continue; + + radeon_ring_unlock_commit(rdev, &rdev->ring[i]); + } + + return 0; + +error: + /* unlock all locks taken so far */ + for (--i; i >= 0; --i) { + if (sync_to[i] || i == dst_ring) { + radeon_ring_unlock_undo(rdev, &rdev->ring[i]); + } + } + return r; +} + void radeon_semaphore_free(struct radeon_device *rdev, struct radeon_semaphore *semaphore) { diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index f493c64..5e3d54d 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -222,8 +222,8 @@ static int radeon_move_blit(struct ttm_buffer_object *bo, { struct radeon_device *rdev; uint64_t old_start, new_start; - struct radeon_fence *fence; - int r, i; + struct radeon_fence *fence, *old_fence; + int r;
rdev = radeon_get_rdev(bo->bdev); r = radeon_fence_create(rdev, &fence, radeon_copy_ring_index(rdev)); @@ -242,6 +242,7 @@ static int radeon_move_blit(struct ttm_buffer_object *bo, break; default: DRM_ERROR("Unknown placement %d\n", old_mem->mem_type); + radeon_fence_unref(&fence); return -EINVAL; } switch (new_mem->mem_type) { @@ -253,42 +254,35 @@ static int radeon_move_blit(struct ttm_buffer_object *bo, break; default: DRM_ERROR("Unknown placement %d\n", old_mem->mem_type); + radeon_fence_unref(&fence); return -EINVAL; } if (!rdev->ring[radeon_copy_ring_index(rdev)].ready) { DRM_ERROR("Trying to move memory with ring turned off.\n"); + radeon_fence_unref(&fence); return -EINVAL; }
BUILD_BUG_ON((PAGE_SIZE % RADEON_GPU_PAGE_SIZE) != 0);
/* sync other rings */ - if (rdev->family >= CHIP_R600) { - for (i = 0; i < RADEON_NUM_RINGS; ++i) { - /* no need to sync to our own or unused rings */ - if (i == radeon_copy_ring_index(rdev) || !rdev->ring[i].ready) - continue; - - if (!fence->semaphore) { - r = radeon_semaphore_create(rdev, &fence->semaphore); - /* FIXME: handle semaphore error */ - if (r) - continue; - } + old_fence = bo->sync_obj; + if (old_fence && old_fence->ring != fence->ring + && !radeon_fence_signaled(old_fence)) { + bool sync_to_ring[RADEON_NUM_RINGS] = { }; + sync_to_ring[old_fence->ring] = true; + + r = radeon_semaphore_create(rdev, &fence->semaphore); + if (r) { + radeon_fence_unref(&fence); + return r; + }
- r = radeon_ring_lock(rdev, &rdev->ring[i], 3); - /* FIXME: handle ring lock error */ - if (r) - continue; - radeon_semaphore_emit_signal(rdev, i, fence->semaphore); - radeon_ring_unlock_commit(rdev, &rdev->ring[i]); - - r = radeon_ring_lock(rdev, &rdev->ring[radeon_copy_ring_index(rdev)], 3); - /* FIXME: handle ring lock error */ - if (r) - continue; - radeon_semaphore_emit_wait(rdev, radeon_copy_ring_index(rdev), fence->semaphore); - radeon_ring_unlock_commit(rdev, &rdev->ring[radeon_copy_ring_index(rdev)]); + r = radeon_semaphore_sync_rings(rdev, fence->semaphore, + sync_to_ring, fence->ring); + if (r) { + radeon_fence_unref(&fence); + return r; } }
From: Christian König deathsimple@vodafone.de
Instead of all this humpy pumpy with recursive mutex (which also fixes only halve of the problem) move the actual gpu reset out of the fence code, return -EDEADLK and then reset the gpu in the calling ioctl function.
v2: Split removal of radeon_mutex into separate patch. Return -EAGAIN if reset is successful.
Signed-off-by: Christian König deathsimple@vodafone.de Reviewed-by: Jerome Glisse jglisse@redhat.com --- drivers/gpu/drm/radeon/radeon_cs.c | 13 +++++++++++++ drivers/gpu/drm/radeon/radeon_device.c | 5 ----- drivers/gpu/drm/radeon/radeon_fence.c | 10 +++------- drivers/gpu/drm/radeon/radeon_gem.c | 16 ++++++++++++++++ 4 files changed, 32 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index 64b86e7..a0826bb 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -489,6 +489,16 @@ out: return r; }
+static int radeon_cs_handle_lockup(struct radeon_device *rdev, int r) +{ + if (r == -EDEADLK) { + r = radeon_gpu_reset(rdev); + if (!r) + r = -EAGAIN; + } + return r; +} + int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { struct radeon_device *rdev = dev->dev_private; @@ -510,6 +520,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) if (r) { DRM_ERROR("Failed to initialize parser !\n"); radeon_cs_parser_fini(&parser, r); + r = radeon_cs_handle_lockup(rdev, r); radeon_mutex_unlock(&rdev->cs_mutex); return r; } @@ -518,6 +529,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) if (r != -ERESTARTSYS) DRM_ERROR("Failed to parse relocation %d!\n", r); radeon_cs_parser_fini(&parser, r); + r = radeon_cs_handle_lockup(rdev, r); radeon_mutex_unlock(&rdev->cs_mutex); return r; } @@ -531,6 +543,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) } out: radeon_cs_parser_fini(&parser, r); + r = radeon_cs_handle_lockup(rdev, r); radeon_mutex_unlock(&rdev->cs_mutex); return r; } diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 26fb9da..1dac27d 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -984,9 +984,6 @@ int radeon_gpu_reset(struct radeon_device *rdev) int r; int resched;
- /* Prevent CS ioctl from interfering */ - radeon_mutex_lock(&rdev->cs_mutex); - radeon_save_bios_scratch_regs(rdev); /* block TTM */ resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev); @@ -1001,8 +998,6 @@ int radeon_gpu_reset(struct radeon_device *rdev) ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched); }
- radeon_mutex_unlock(&rdev->cs_mutex); - if (r) { /* bad news, how to tell it to userspace ? */ dev_info(rdev->dev, "GPU reset failed\n"); diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 326bdb5..24a4d4b 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -264,6 +264,8 @@ int radeon_fence_wait(struct radeon_fence *fence, bool intr) /* change sequence value on all rings, so nobody else things there is a lockup */ for (i = 0; i < RADEON_NUM_RINGS; ++i) rdev->fence_drv[i].last_seq -= 0x10000; + + rdev->fence_drv[fence->ring].last_activity = jiffies; write_unlock_irqrestore(&rdev->fence_lock, irq_flags);
if (radeon_ring_is_lockup(rdev, fence->ring, &rdev->ring[fence->ring])) { @@ -274,13 +276,7 @@ int radeon_fence_wait(struct radeon_fence *fence, bool intr)
/* mark the ring as not ready any more */ rdev->ring[fence->ring].ready = false; - r = radeon_gpu_reset(rdev); - if (r) - return r; - - write_lock_irqsave(&rdev->fence_lock, irq_flags); - rdev->fence_drv[fence->ring].last_activity = jiffies; - write_unlock_irqrestore(&rdev->fence_lock, irq_flags); + return -EDEADLK; } } } diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index c7008b5..e15cb1f 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -154,6 +154,17 @@ void radeon_gem_object_close(struct drm_gem_object *obj, radeon_bo_unreserve(rbo); }
+static int radeon_gem_handle_lockup(struct radeon_device *rdev, int r) +{ + if (r == -EDEADLK) { + radeon_mutex_lock(&rdev->cs_mutex); + r = radeon_gpu_reset(rdev); + if (!r) + r = -EAGAIN; + radeon_mutex_unlock(&rdev->cs_mutex); + } + return r; +}
/* * GEM ioctls. @@ -210,12 +221,14 @@ int radeon_gem_create_ioctl(struct drm_device *dev, void *data, args->initial_domain, false, false, &gobj); if (r) { + r = radeon_gem_handle_lockup(rdev, r); return r; } r = drm_gem_handle_create(filp, gobj, &handle); /* drop reference from allocate - handle holds it now */ drm_gem_object_unreference_unlocked(gobj); if (r) { + r = radeon_gem_handle_lockup(rdev, r); return r; } args->handle = handle; @@ -245,6 +258,7 @@ int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data, r = radeon_gem_set_domain(gobj, args->read_domains, args->write_domain);
drm_gem_object_unreference_unlocked(gobj); + r = radeon_gem_handle_lockup(robj->rdev, r); return r; }
@@ -301,6 +315,7 @@ int radeon_gem_busy_ioctl(struct drm_device *dev, void *data, break; } drm_gem_object_unreference_unlocked(gobj); + r = radeon_gem_handle_lockup(robj->rdev, r); return r; }
@@ -322,6 +337,7 @@ int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data, if (robj->rdev->asic->ioctl_wait_idle) robj->rdev->asic->ioctl_wait_idle(robj->rdev, robj); drm_gem_object_unreference_unlocked(gobj); + r = radeon_gem_handle_lockup(robj->rdev, r); return r; }
From: Christian König deathsimple@vodafone.de
Not needed anymore.
Signed-off-by: Christian König deathsimple@vodafone.de Reviewed-by: Jerome Glisse jglisse@redhat.com --- drivers/gpu/drm/radeon/radeon.h | 44 +------------------------------- drivers/gpu/drm/radeon/radeon_cs.c | 10 +++--- drivers/gpu/drm/radeon/radeon_device.c | 2 +- drivers/gpu/drm/radeon/radeon_gart.c | 16 ++++++------ drivers/gpu/drm/radeon/radeon_gem.c | 4 +- 5 files changed, 17 insertions(+), 59 deletions(-)
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index a231566..d573356 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -155,48 +155,6 @@ static inline int radeon_atrm_get_bios_chunk(uint8_t *bios, int offset, int len) #endif bool radeon_get_bios(struct radeon_device *rdev);
- -/* - * Mutex which allows recursive locking from the same process. - */ -struct radeon_mutex { - struct mutex mutex; - struct task_struct *owner; - int level; -}; - -static inline void radeon_mutex_init(struct radeon_mutex *mutex) -{ - mutex_init(&mutex->mutex); - mutex->owner = NULL; - mutex->level = 0; -} - -static inline void radeon_mutex_lock(struct radeon_mutex *mutex) -{ - if (mutex_trylock(&mutex->mutex)) { - /* The mutex was unlocked before, so it's ours now */ - mutex->owner = current; - } else if (mutex->owner != current) { - /* Another process locked the mutex, take it */ - mutex_lock(&mutex->mutex); - mutex->owner = current; - } - /* Otherwise the mutex was already locked by this process */ - - mutex->level++; -} - -static inline void radeon_mutex_unlock(struct radeon_mutex *mutex) -{ - if (--mutex->level > 0) - return; - - mutex->owner = NULL; - mutex_unlock(&mutex->mutex); -} - - /* * Dummy page */ @@ -1505,7 +1463,7 @@ struct radeon_device { struct radeon_gem gem; struct radeon_pm pm; uint32_t bios_scratch[RADEON_BIOS_NUM_SCRATCH]; - struct radeon_mutex cs_mutex; + struct mutex cs_mutex; struct radeon_wb wb; struct radeon_dummy_page dummy_page; bool shutdown; diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index a0826bb..38e1496 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -505,9 +505,9 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) struct radeon_cs_parser parser; int r;
- radeon_mutex_lock(&rdev->cs_mutex); + mutex_lock(&rdev->cs_mutex); if (!rdev->accel_working) { - radeon_mutex_unlock(&rdev->cs_mutex); + mutex_unlock(&rdev->cs_mutex); return -EBUSY; } /* initialize parser */ @@ -521,7 +521,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) DRM_ERROR("Failed to initialize parser !\n"); radeon_cs_parser_fini(&parser, r); r = radeon_cs_handle_lockup(rdev, r); - radeon_mutex_unlock(&rdev->cs_mutex); + mutex_unlock(&rdev->cs_mutex); return r; } r = radeon_cs_parser_relocs(&parser); @@ -530,7 +530,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) DRM_ERROR("Failed to parse relocation %d!\n", r); radeon_cs_parser_fini(&parser, r); r = radeon_cs_handle_lockup(rdev, r); - radeon_mutex_unlock(&rdev->cs_mutex); + mutex_unlock(&rdev->cs_mutex); return r; } r = radeon_cs_ib_chunk(rdev, &parser); @@ -544,7 +544,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) out: radeon_cs_parser_fini(&parser, r); r = radeon_cs_handle_lockup(rdev, r); - radeon_mutex_unlock(&rdev->cs_mutex); + mutex_unlock(&rdev->cs_mutex); return r; }
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 1dac27d..5df53dd 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -722,7 +722,7 @@ int radeon_device_init(struct radeon_device *rdev,
/* mutex initialization are all done here so we * can recall function without having locking issues */ - radeon_mutex_init(&rdev->cs_mutex); + mutex_init(&rdev->cs_mutex); for (i = 0; i < RADEON_NUM_RINGS; ++i) mutex_init(&rdev->ring[i].mutex); mutex_init(&rdev->dc_hw_i2c_mutex); diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 8eba1c6..71b28e91 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -356,13 +356,13 @@ int radeon_vm_manager_suspend(struct radeon_device *rdev) { struct radeon_vm *vm, *tmp;
- radeon_mutex_lock(&rdev->cs_mutex); + mutex_lock(&rdev->cs_mutex); /* unbind all active vm */ list_for_each_entry_safe(vm, tmp, &rdev->vm_manager.lru_vm, list) { radeon_vm_unbind_locked(rdev, vm); } rdev->vm_manager.funcs->fini(rdev); - radeon_mutex_unlock(&rdev->cs_mutex); + mutex_unlock(&rdev->cs_mutex); return radeon_sa_bo_manager_suspend(rdev, &rdev->vm_manager.sa_manager); }
@@ -478,9 +478,9 @@ int radeon_vm_bo_add(struct radeon_device *rdev, if (last_pfn > vm->last_pfn) { /* grow va space 32M by 32M */ unsigned align = ((32 << 20) >> 12) - 1; - radeon_mutex_lock(&rdev->cs_mutex); + mutex_lock(&rdev->cs_mutex); radeon_vm_unbind_locked(rdev, vm); - radeon_mutex_unlock(&rdev->cs_mutex); + mutex_unlock(&rdev->cs_mutex); vm->last_pfn = (last_pfn + align) & ~align; } head = &vm->va; @@ -596,9 +596,9 @@ int radeon_vm_bo_rmv(struct radeon_device *rdev, return 0;
mutex_lock(&vm->mutex); - radeon_mutex_lock(&rdev->cs_mutex); + mutex_lock(&rdev->cs_mutex); radeon_vm_bo_update_pte(rdev, vm, bo, NULL); - radeon_mutex_unlock(&rdev->cs_mutex); + mutex_unlock(&rdev->cs_mutex); list_del(&bo_va->vm_list); mutex_unlock(&vm->mutex); list_del(&bo_va->bo_list); @@ -643,9 +643,9 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm)
mutex_lock(&vm->mutex);
- radeon_mutex_lock(&rdev->cs_mutex); + mutex_lock(&rdev->cs_mutex); radeon_vm_unbind_locked(rdev, vm); - radeon_mutex_unlock(&rdev->cs_mutex); + mutex_unlock(&rdev->cs_mutex);
/* remove all bo */ r = radeon_bo_reserve(rdev->sa_manager.bo, false); diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index e15cb1f..bd4521e 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -157,11 +157,11 @@ void radeon_gem_object_close(struct drm_gem_object *obj, static int radeon_gem_handle_lockup(struct radeon_device *rdev, int r) { if (r == -EDEADLK) { - radeon_mutex_lock(&rdev->cs_mutex); + mutex_lock(&rdev->cs_mutex); r = radeon_gpu_reset(rdev); if (!r) r = -EAGAIN; - radeon_mutex_unlock(&rdev->cs_mutex); + mutex_unlock(&rdev->cs_mutex); } return r; }
From: Christian König deathsimple@vodafone.de
It isn't chipset specific, so it makes no sense to have that inside r100.c.
Signed-off-by: Christian König deathsimple@vodafone.de Reviewed-by: Jerome Glisse jglisse@redhat.com --- drivers/gpu/drm/radeon/evergreen.c | 5 +-- drivers/gpu/drm/radeon/ni.c | 5 +-- drivers/gpu/drm/radeon/r100.c | 57 +-------------------------------- drivers/gpu/drm/radeon/r300.c | 4 +- drivers/gpu/drm/radeon/r600.c | 10 +----- drivers/gpu/drm/radeon/radeon.h | 16 ++------- drivers/gpu/drm/radeon/radeon_asic.h | 5 --- drivers/gpu/drm/radeon/radeon_ring.c | 53 +++++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/si.c | 5 +-- 9 files changed, 69 insertions(+), 91 deletions(-)
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index a76389c..353d10a 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -2424,7 +2424,6 @@ bool evergreen_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *rin u32 srbm_status; u32 grbm_status; u32 grbm_status_se0, grbm_status_se1; - struct r100_gpu_lockup *lockup = &rdev->config.evergreen.lockup; int r;
srbm_status = RREG32(SRBM_STATUS); @@ -2432,7 +2431,7 @@ bool evergreen_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *rin grbm_status_se0 = RREG32(GRBM_STATUS_SE0); grbm_status_se1 = RREG32(GRBM_STATUS_SE1); if (!(grbm_status & GUI_ACTIVE)) { - r100_gpu_lockup_update(lockup, ring); + radeon_ring_lockup_update(ring); return false; } /* force CP activities */ @@ -2444,7 +2443,7 @@ bool evergreen_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *rin radeon_ring_unlock_commit(rdev, ring); } ring->rptr = RREG32(CP_RB_RPTR); - return r100_gpu_cp_is_lockup(rdev, lockup, ring); + return radeon_ring_test_lockup(rdev, ring); }
static int evergreen_gpu_soft_reset(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index c0b0956..4327b32 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -1397,7 +1397,6 @@ bool cayman_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) u32 srbm_status; u32 grbm_status; u32 grbm_status_se0, grbm_status_se1; - struct r100_gpu_lockup *lockup = &rdev->config.cayman.lockup; int r;
srbm_status = RREG32(SRBM_STATUS); @@ -1405,7 +1404,7 @@ bool cayman_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) grbm_status_se0 = RREG32(GRBM_STATUS_SE0); grbm_status_se1 = RREG32(GRBM_STATUS_SE1); if (!(grbm_status & GUI_ACTIVE)) { - r100_gpu_lockup_update(lockup, ring); + radeon_ring_lockup_update(ring); return false; } /* force CP activities */ @@ -1418,7 +1417,7 @@ bool cayman_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) } /* XXX deal with CP0,1,2 */ ring->rptr = RREG32(ring->rptr_reg); - return r100_gpu_cp_is_lockup(rdev, lockup, ring); + return radeon_ring_test_lockup(rdev, ring); }
static int cayman_gpu_soft_reset(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index ac53bd8..cd00909 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -2155,59 +2155,6 @@ int r100_mc_wait_for_idle(struct radeon_device *rdev) return -1; }
-void r100_gpu_lockup_update(struct r100_gpu_lockup *lockup, struct radeon_ring *ring) -{ - lockup->last_cp_rptr = ring->rptr; - lockup->last_jiffies = jiffies; -} - -/** - * r100_gpu_cp_is_lockup() - check if CP is lockup by recording information - * @rdev: radeon device structure - * @lockup: r100_gpu_lockup structure holding CP lockup tracking informations - * @cp: radeon_cp structure holding CP information - * - * We don't need to initialize the lockup tracking information as we will either - * have CP rptr to a different value of jiffies wrap around which will force - * initialization of the lockup tracking informations. - * - * A possible false positivie is if we get call after while and last_cp_rptr == - * the current CP rptr, even if it's unlikely it might happen. To avoid this - * if the elapsed time since last call is bigger than 2 second than we return - * false and update the tracking information. Due to this the caller must call - * r100_gpu_cp_is_lockup several time in less than 2sec for lockup to be reported - * the fencing code should be cautious about that. - * - * Caller should write to the ring to force CP to do something so we don't get - * false positive when CP is just gived nothing to do. - * - **/ -bool r100_gpu_cp_is_lockup(struct radeon_device *rdev, struct r100_gpu_lockup *lockup, struct radeon_ring *ring) -{ - unsigned long cjiffies, elapsed; - - cjiffies = jiffies; - if (!time_after(cjiffies, lockup->last_jiffies)) { - /* likely a wrap around */ - lockup->last_cp_rptr = ring->rptr; - lockup->last_jiffies = jiffies; - return false; - } - if (ring->rptr != lockup->last_cp_rptr) { - /* CP is still working no lockup */ - lockup->last_cp_rptr = ring->rptr; - lockup->last_jiffies = jiffies; - return false; - } - elapsed = jiffies_to_msecs(cjiffies - lockup->last_jiffies); - if (elapsed >= 10000) { - dev_err(rdev->dev, "GPU lockup CP stall for more than %lumsec\n", elapsed); - return true; - } - /* give a chance to the GPU ... */ - return false; -} - bool r100_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) { u32 rbbm_status; @@ -2215,7 +2162,7 @@ bool r100_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
rbbm_status = RREG32(R_000E40_RBBM_STATUS); if (!G_000E40_GUI_ACTIVE(rbbm_status)) { - r100_gpu_lockup_update(&rdev->config.r100.lockup, ring); + radeon_ring_lockup_update(ring); return false; } /* force CP activities */ @@ -2227,7 +2174,7 @@ bool r100_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) radeon_ring_unlock_commit(rdev, ring); } ring->rptr = RREG32(ring->rptr_reg); - return r100_gpu_cp_is_lockup(rdev, &rdev->config.r100.lockup, ring); + return radeon_ring_test_lockup(rdev, ring); }
void r100_bm_disable(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 26e0db8..e207664 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -384,7 +384,7 @@ bool r300_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
rbbm_status = RREG32(R_000E40_RBBM_STATUS); if (!G_000E40_GUI_ACTIVE(rbbm_status)) { - r100_gpu_lockup_update(&rdev->config.r300.lockup, ring); + radeon_ring_lockup_update(ring); return false; } /* force CP activities */ @@ -396,7 +396,7 @@ bool r300_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) radeon_ring_unlock_commit(rdev, ring); } ring->rptr = RREG32(RADEON_CP_RB_RPTR); - return r100_gpu_cp_is_lockup(rdev, &rdev->config.r300.lockup, ring); + return radeon_ring_test_lockup(rdev, ring); }
int r300_asic_reset(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index a252160..48f6fae 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -1350,19 +1350,13 @@ bool r600_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) u32 srbm_status; u32 grbm_status; u32 grbm_status2; - struct r100_gpu_lockup *lockup; int r;
- if (rdev->family >= CHIP_RV770) - lockup = &rdev->config.rv770.lockup; - else - lockup = &rdev->config.r600.lockup; - srbm_status = RREG32(R_000E50_SRBM_STATUS); grbm_status = RREG32(R_008010_GRBM_STATUS); grbm_status2 = RREG32(R_008014_GRBM_STATUS2); if (!G_008010_GUI_ACTIVE(grbm_status)) { - r100_gpu_lockup_update(lockup, ring); + radeon_ring_lockup_update(ring); return false; } /* force CP activities */ @@ -1374,7 +1368,7 @@ bool r600_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) radeon_ring_unlock_commit(rdev, ring); } ring->rptr = RREG32(ring->rptr_reg); - return r100_gpu_cp_is_lockup(rdev, lockup, ring); + return radeon_ring_test_lockup(rdev, ring); }
int r600_asic_reset(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index d573356..a5d707d 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -596,6 +596,8 @@ struct radeon_ring { unsigned ring_size; unsigned ring_free_dw; int count_dw; + unsigned long last_activity; + unsigned last_rptr; uint64_t gpu_addr; uint32_t align_mask; uint32_t ptr_mask; @@ -739,6 +741,8 @@ void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *cp); void radeon_ring_unlock_commit(struct radeon_device *rdev, struct radeon_ring *cp); void radeon_ring_unlock_undo(struct radeon_device *rdev, struct radeon_ring *cp); int radeon_ring_test(struct radeon_device *rdev, struct radeon_ring *cp); +void radeon_ring_lockup_update(struct radeon_ring *ring); +bool radeon_ring_test_lockup(struct radeon_device *rdev, struct radeon_ring *ring); int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *cp, unsigned ring_size, unsigned rptr_offs, unsigned rptr_reg, unsigned wptr_reg, u32 ptr_reg_shift, u32 ptr_reg_mask, u32 nop); @@ -1188,16 +1192,10 @@ struct radeon_asic { /* * Asic structures */ -struct r100_gpu_lockup { - unsigned long last_jiffies; - u32 last_cp_rptr; -}; - struct r100_asic { const unsigned *reg_safe_bm; unsigned reg_safe_bm_size; u32 hdp_cntl; - struct r100_gpu_lockup lockup; };
struct r300_asic { @@ -1205,7 +1203,6 @@ struct r300_asic { unsigned reg_safe_bm_size; u32 resync_scratch; u32 hdp_cntl; - struct r100_gpu_lockup lockup; };
struct r600_asic { @@ -1227,7 +1224,6 @@ struct r600_asic { unsigned tiling_group_size; unsigned tile_config; unsigned backend_map; - struct r100_gpu_lockup lockup; };
struct rv770_asic { @@ -1253,7 +1249,6 @@ struct rv770_asic { unsigned tiling_group_size; unsigned tile_config; unsigned backend_map; - struct r100_gpu_lockup lockup; };
struct evergreen_asic { @@ -1280,7 +1275,6 @@ struct evergreen_asic { unsigned tiling_group_size; unsigned tile_config; unsigned backend_map; - struct r100_gpu_lockup lockup; };
struct cayman_asic { @@ -1319,7 +1313,6 @@ struct cayman_asic { unsigned multi_gpu_tile_size;
unsigned tile_config; - struct r100_gpu_lockup lockup; };
struct si_asic { @@ -1350,7 +1343,6 @@ struct si_asic { unsigned multi_gpu_tile_size;
unsigned tile_config; - struct r100_gpu_lockup lockup; };
union radeon_asic_config { diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 3d9f9f1..d3ec546 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -103,11 +103,6 @@ int r100_pci_gart_enable(struct radeon_device *rdev); void r100_pci_gart_disable(struct radeon_device *rdev); int r100_debugfs_mc_info_init(struct radeon_device *rdev); int r100_gui_wait_for_idle(struct radeon_device *rdev); -void r100_gpu_lockup_update(struct r100_gpu_lockup *lockup, - struct radeon_ring *cp); -bool r100_gpu_cp_is_lockup(struct radeon_device *rdev, - struct r100_gpu_lockup *lockup, - struct radeon_ring *cp); void r100_ib_fini(struct radeon_device *rdev); int r100_ib_test(struct radeon_device *rdev, struct radeon_ring *ring); void r100_irq_disable(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index 7031d69..b34575f 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -352,6 +352,59 @@ void radeon_ring_unlock_undo(struct radeon_device *rdev, struct radeon_ring *rin mutex_unlock(&ring->mutex); }
+void radeon_ring_lockup_update(struct radeon_ring *ring) +{ + ring->last_rptr = ring->rptr; + ring->last_activity = jiffies; +} + +/** + * radeon_ring_test_lockup() - check if ring is lockedup by recording information + * @rdev: radeon device structure + * @ring: radeon_ring structure holding ring information + * + * We don't need to initialize the lockup tracking information as we will either + * have CP rptr to a different value of jiffies wrap around which will force + * initialization of the lockup tracking informations. + * + * A possible false positivie is if we get call after while and last_cp_rptr == + * the current CP rptr, even if it's unlikely it might happen. To avoid this + * if the elapsed time since last call is bigger than 2 second than we return + * false and update the tracking information. Due to this the caller must call + * radeon_ring_test_lockup several time in less than 2sec for lockup to be reported + * the fencing code should be cautious about that. + * + * Caller should write to the ring to force CP to do something so we don't get + * false positive when CP is just gived nothing to do. + * + **/ +bool radeon_ring_test_lockup(struct radeon_device *rdev, struct radeon_ring *ring) +{ + unsigned long cjiffies, elapsed; + uint32_t rptr; + + cjiffies = jiffies; + if (!time_after(cjiffies, ring->last_activity)) { + /* likely a wrap around */ + radeon_ring_lockup_update(ring); + return false; + } + rptr = RREG32(ring->rptr_reg); + ring->rptr = (rptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift; + if (ring->rptr != ring->last_rptr) { + /* CP is still working no lockup */ + radeon_ring_lockup_update(ring); + return false; + } + elapsed = jiffies_to_msecs(cjiffies - ring->last_activity); + if (elapsed >= 10000) { + dev_err(rdev->dev, "GPU lockup CP stall for more than %lumsec\n", elapsed); + return true; + } + /* give a chance to the GPU ... */ + return false; +} + int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsigned ring_size, unsigned rptr_offs, unsigned rptr_reg, unsigned wptr_reg, u32 ptr_reg_shift, u32 ptr_reg_mask, u32 nop) diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index f05d37a..e76d8b1 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -2217,7 +2217,6 @@ bool si_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) u32 srbm_status; u32 grbm_status, grbm_status2; u32 grbm_status_se0, grbm_status_se1; - struct r100_gpu_lockup *lockup = &rdev->config.si.lockup; int r;
srbm_status = RREG32(SRBM_STATUS); @@ -2226,7 +2225,7 @@ bool si_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) grbm_status_se0 = RREG32(GRBM_STATUS_SE0); grbm_status_se1 = RREG32(GRBM_STATUS_SE1); if (!(grbm_status & GUI_ACTIVE)) { - r100_gpu_lockup_update(lockup, ring); + radeon_ring_lockup_update(ring); return false; } /* force CP activities */ @@ -2239,7 +2238,7 @@ bool si_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) } /* XXX deal with CP0,1,2 */ ring->rptr = RREG32(ring->rptr_reg); - return r100_gpu_cp_is_lockup(rdev, lockup, ring); + return radeon_ring_test_lockup(rdev, ring); }
static int si_gpu_soft_reset(struct radeon_device *rdev)
From: Christian König deathsimple@vodafone.de
Don't hard code the 10 seconds timeout. Compute jobs can run much longer.
Signed-off-by: Christian König deathsimple@vodafone.de Reviewed-by: Jerome Glisse jglisse@redhat.com --- drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_drv.c | 4 ++++ drivers/gpu/drm/radeon/radeon_ring.c | 2 +- 3 files changed, 6 insertions(+), 1 deletions(-)
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index a5d707d..d0834a9 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -94,6 +94,7 @@ extern int radeon_disp_priority; extern int radeon_hw_i2c; extern int radeon_pcie_gen2; extern int radeon_msi; +extern int radeon_lockup_timeout;
/* * Copy from radeon_drv.h so we don't have to include both and have conflicting diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index ef7bb3f..e62e56a 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -128,6 +128,7 @@ int radeon_disp_priority = 0; int radeon_hw_i2c = 0; int radeon_pcie_gen2 = 0; int radeon_msi = -1; +int radeon_lockup_timeout = 10000;
MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers"); module_param_named(no_wb, radeon_no_wb, int, 0444); @@ -177,6 +178,9 @@ module_param_named(pcie_gen2, radeon_pcie_gen2, int, 0444); MODULE_PARM_DESC(msi, "MSI support (1 = enable, 0 = disable, -1 = auto)"); module_param_named(msi, radeon_msi, int, 0444);
+MODULE_PARM_DESC(lockup_timeout, "GPU lockup timeout in ms (defaul 10000 = 10 seconds, 0 = disable)"); +module_param_named(lockup_timeout, radeon_lockup_timeout, int, 0444); + static int radeon_suspend(struct drm_device *dev, pm_message_t state) { drm_radeon_private_t *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index b34575f..65286b7 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -397,7 +397,7 @@ bool radeon_ring_test_lockup(struct radeon_device *rdev, struct radeon_ring *rin return false; } elapsed = jiffies_to_msecs(cjiffies - ring->last_activity); - if (elapsed >= 10000) { + if (radeon_lockup_timeout && elapsed >= radeon_lockup_timeout) { dev_err(rdev->dev, "GPU lockup CP stall for more than %lumsec\n", elapsed); return true; }
From: Christian König deathsimple@vodafone.de
Fixing just another deadlock problem with gpu reset tests.
Signed-off-by: Christian König deathsimple@vodafone.de Reviewed-by: Jerome Glisse jglisse@redhat.com --- drivers/gpu/drm/radeon/radeon_ring.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index 65286b7..4069b01 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -302,7 +302,9 @@ int radeon_ring_alloc(struct radeon_device *rdev, struct radeon_ring *ring, unsi if (ndw < ring->ring_free_dw) { break; } + mutex_unlock(&ring->mutex); r = radeon_fence_wait_next(rdev, radeon_ring_index(rdev, ring)); + mutex_lock(&ring->mutex); if (r) return r; }
From: Christian König deathsimple@vodafone.de
Nothing chipset or ring specific with it, so also move it to radon_ring.
Signed-off-by: Christian König deathsimple@vodafone.de Reviewed-by: Jerome Glisse jglisse@redhat.com --- drivers/gpu/drm/radeon/evergreen.c | 10 +--------- drivers/gpu/drm/radeon/ni.c | 11 +---------- drivers/gpu/drm/radeon/r100.c | 10 +--------- drivers/gpu/drm/radeon/r300.c | 10 +--------- drivers/gpu/drm/radeon/r600.c | 10 +--------- drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_ring.c | 16 ++++++++++++++++ drivers/gpu/drm/radeon/si.c | 11 +---------- 8 files changed, 23 insertions(+), 56 deletions(-)
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 353d10a..ec61194 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -2424,7 +2424,6 @@ bool evergreen_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *rin u32 srbm_status; u32 grbm_status; u32 grbm_status_se0, grbm_status_se1; - int r;
srbm_status = RREG32(SRBM_STATUS); grbm_status = RREG32(GRBM_STATUS); @@ -2435,14 +2434,7 @@ bool evergreen_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *rin return false; } /* force CP activities */ - r = radeon_ring_lock(rdev, ring, 2); - if (!r) { - /* PACKET2 NOP */ - radeon_ring_write(ring, 0x80000000); - radeon_ring_write(ring, 0x80000000); - radeon_ring_unlock_commit(rdev, ring); - } - ring->rptr = RREG32(CP_RB_RPTR); + radeon_ring_force_activity(rdev, ring); return radeon_ring_test_lockup(rdev, ring); }
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 4327b32..8a9c85d 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -1397,7 +1397,6 @@ bool cayman_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) u32 srbm_status; u32 grbm_status; u32 grbm_status_se0, grbm_status_se1; - int r;
srbm_status = RREG32(SRBM_STATUS); grbm_status = RREG32(GRBM_STATUS); @@ -1408,15 +1407,7 @@ bool cayman_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) return false; } /* force CP activities */ - r = radeon_ring_lock(rdev, ring, 2); - if (!r) { - /* PACKET2 NOP */ - radeon_ring_write(ring, 0x80000000); - radeon_ring_write(ring, 0x80000000); - radeon_ring_unlock_commit(rdev, ring); - } - /* XXX deal with CP0,1,2 */ - ring->rptr = RREG32(ring->rptr_reg); + radeon_ring_force_activity(rdev, ring); return radeon_ring_test_lockup(rdev, ring); }
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index cd00909..ee0103c 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -2158,7 +2158,6 @@ int r100_mc_wait_for_idle(struct radeon_device *rdev) bool r100_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) { u32 rbbm_status; - int r;
rbbm_status = RREG32(R_000E40_RBBM_STATUS); if (!G_000E40_GUI_ACTIVE(rbbm_status)) { @@ -2166,14 +2165,7 @@ bool r100_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) return false; } /* force CP activities */ - r = radeon_ring_lock(rdev, ring, 2); - if (!r) { - /* PACKET2 NOP */ - radeon_ring_write(ring, 0x80000000); - radeon_ring_write(ring, 0x80000000); - radeon_ring_unlock_commit(rdev, ring); - } - ring->rptr = RREG32(ring->rptr_reg); + radeon_ring_force_activity(rdev, ring); return radeon_ring_test_lockup(rdev, ring); }
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index e207664..04ec269 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -380,7 +380,6 @@ void r300_gpu_init(struct radeon_device *rdev) bool r300_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) { u32 rbbm_status; - int r;
rbbm_status = RREG32(R_000E40_RBBM_STATUS); if (!G_000E40_GUI_ACTIVE(rbbm_status)) { @@ -388,14 +387,7 @@ bool r300_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) return false; } /* force CP activities */ - r = radeon_ring_lock(rdev, ring, 2); - if (!r) { - /* PACKET2 NOP */ - radeon_ring_write(ring, 0x80000000); - radeon_ring_write(ring, 0x80000000); - radeon_ring_unlock_commit(rdev, ring); - } - ring->rptr = RREG32(RADEON_CP_RB_RPTR); + radeon_ring_force_activity(rdev, ring); return radeon_ring_test_lockup(rdev, ring); }
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 48f6fae..2bce657 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -1350,7 +1350,6 @@ bool r600_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) u32 srbm_status; u32 grbm_status; u32 grbm_status2; - int r;
srbm_status = RREG32(R_000E50_SRBM_STATUS); grbm_status = RREG32(R_008010_GRBM_STATUS); @@ -1360,14 +1359,7 @@ bool r600_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) return false; } /* force CP activities */ - r = radeon_ring_lock(rdev, ring, 2); - if (!r) { - /* PACKET2 NOP */ - radeon_ring_write(ring, 0x80000000); - radeon_ring_write(ring, 0x80000000); - radeon_ring_unlock_commit(rdev, ring); - } - ring->rptr = RREG32(ring->rptr_reg); + radeon_ring_force_activity(rdev, ring); return radeon_ring_test_lockup(rdev, ring); }
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index d0834a9..76ca5ad 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -742,6 +742,7 @@ void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *cp); void radeon_ring_unlock_commit(struct radeon_device *rdev, struct radeon_ring *cp); void radeon_ring_unlock_undo(struct radeon_device *rdev, struct radeon_ring *cp); int radeon_ring_test(struct radeon_device *rdev, struct radeon_ring *cp); +void radeon_ring_force_activity(struct radeon_device *rdev, struct radeon_ring *ring); void radeon_ring_lockup_update(struct radeon_ring *ring); bool radeon_ring_test_lockup(struct radeon_device *rdev, struct radeon_ring *ring); int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *cp, unsigned ring_size, diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index 4069b01..5226576 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -354,6 +354,22 @@ void radeon_ring_unlock_undo(struct radeon_device *rdev, struct radeon_ring *rin mutex_unlock(&ring->mutex); }
+void radeon_ring_force_activity(struct radeon_device *rdev, struct radeon_ring *ring) +{ + int r; + + mutex_lock(&ring->mutex); + radeon_ring_free_size(rdev, ring); + if (ring->rptr == ring->wptr) { + r = radeon_ring_alloc(rdev, ring, 1); + if (!r) { + radeon_ring_write(ring, ring->nop); + radeon_ring_commit(rdev, ring); + } + } + mutex_unlock(&ring->mutex); +} + void radeon_ring_lockup_update(struct radeon_ring *ring) { ring->last_rptr = ring->rptr; diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index e76d8b1..b25a8ff 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -2217,7 +2217,6 @@ bool si_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) u32 srbm_status; u32 grbm_status, grbm_status2; u32 grbm_status_se0, grbm_status_se1; - int r;
srbm_status = RREG32(SRBM_STATUS); grbm_status = RREG32(GRBM_STATUS); @@ -2229,15 +2228,7 @@ bool si_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) return false; } /* force CP activities */ - r = radeon_ring_lock(rdev, ring, 2); - if (!r) { - /* PACKET2 NOP */ - radeon_ring_write(ring, 0x80000000); - radeon_ring_write(ring, 0x80000000); - radeon_ring_unlock_commit(rdev, ring); - } - /* XXX deal with CP0,1,2 */ - ring->rptr = RREG32(ring->rptr_reg); + radeon_ring_force_activity(rdev, ring); return radeon_ring_test_lockup(rdev, ring); }
From: Christian König deathsimple@vodafone.de
Since it is now identical to r100_gpu_is_lockup.
Signed-off-by: Christian König deathsimple@vodafone.de Reviewed-by: Jerome Glisse jglisse@redhat.com --- drivers/gpu/drm/radeon/r300.c | 14 -------------- drivers/gpu/drm/radeon/radeon_asic.c | 16 ++++++++-------- drivers/gpu/drm/radeon/radeon_asic.h | 1 - 3 files changed, 8 insertions(+), 23 deletions(-)
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 04ec269..6419a59 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -377,20 +377,6 @@ void r300_gpu_init(struct radeon_device *rdev) rdev->num_gb_pipes, rdev->num_z_pipes); }
-bool r300_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) -{ - u32 rbbm_status; - - rbbm_status = RREG32(R_000E40_RBBM_STATUS); - if (!G_000E40_GUI_ACTIVE(rbbm_status)) { - radeon_ring_lockup_update(ring); - return false; - } - /* force CP activities */ - radeon_ring_force_activity(rdev, ring); - return radeon_ring_test_lockup(rdev, ring); -} - int r300_asic_reset(struct radeon_device *rdev) { struct r100_mc_save save; diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 958b9ea..5e5694e 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -299,7 +299,7 @@ static struct radeon_asic r300_asic = { .ring_start = &r300_ring_start, .ring_test = &r100_ring_test, .ib_test = &r100_ib_test, - .is_lockup = &r300_gpu_is_lockup, + .is_lockup = &r100_gpu_is_lockup, } }, .irq = { @@ -373,7 +373,7 @@ static struct radeon_asic r300_asic_pcie = { .ring_start = &r300_ring_start, .ring_test = &r100_ring_test, .ib_test = &r100_ib_test, - .is_lockup = &r300_gpu_is_lockup, + .is_lockup = &r100_gpu_is_lockup, } }, .irq = { @@ -447,7 +447,7 @@ static struct radeon_asic r420_asic = { .ring_start = &r300_ring_start, .ring_test = &r100_ring_test, .ib_test = &r100_ib_test, - .is_lockup = &r300_gpu_is_lockup, + .is_lockup = &r100_gpu_is_lockup, } }, .irq = { @@ -521,7 +521,7 @@ static struct radeon_asic rs400_asic = { .ring_start = &r300_ring_start, .ring_test = &r100_ring_test, .ib_test = &r100_ib_test, - .is_lockup = &r300_gpu_is_lockup, + .is_lockup = &r100_gpu_is_lockup, } }, .irq = { @@ -595,7 +595,7 @@ static struct radeon_asic rs600_asic = { .ring_start = &r300_ring_start, .ring_test = &r100_ring_test, .ib_test = &r100_ib_test, - .is_lockup = &r300_gpu_is_lockup, + .is_lockup = &r100_gpu_is_lockup, } }, .irq = { @@ -669,7 +669,7 @@ static struct radeon_asic rs690_asic = { .ring_start = &r300_ring_start, .ring_test = &r100_ring_test, .ib_test = &r100_ib_test, - .is_lockup = &r300_gpu_is_lockup, + .is_lockup = &r100_gpu_is_lockup, } }, .irq = { @@ -743,7 +743,7 @@ static struct radeon_asic rv515_asic = { .ring_start = &rv515_ring_start, .ring_test = &r100_ring_test, .ib_test = &r100_ib_test, - .is_lockup = &r300_gpu_is_lockup, + .is_lockup = &r100_gpu_is_lockup, } }, .irq = { @@ -817,7 +817,7 @@ static struct radeon_asic r520_asic = { .ring_start = &rv515_ring_start, .ring_test = &r100_ring_test, .ib_test = &r100_ib_test, - .is_lockup = &r300_gpu_is_lockup, + .is_lockup = &r100_gpu_is_lockup, } }, .irq = { diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index d3ec546..3f7ecbb 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -154,7 +154,6 @@ extern int r300_init(struct radeon_device *rdev); extern void r300_fini(struct radeon_device *rdev); extern int r300_suspend(struct radeon_device *rdev); extern int r300_resume(struct radeon_device *rdev); -extern bool r300_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *cp); extern int r300_asic_reset(struct radeon_device *rdev); extern void r300_ring_start(struct radeon_device *rdev, struct radeon_ring *ring); extern void r300_fence_ring_emit(struct radeon_device *rdev,
From: Christian König deathsimple@vodafone.de
Since it is now identical to evergreen_gpu_is_lockup.
Signed-off-by: Christian König deathsimple@vodafone.de Reviewed-by: Jerome Glisse jglisse@redhat.com --- drivers/gpu/drm/radeon/ni.c | 19 ------------------- drivers/gpu/drm/radeon/radeon_asic.c | 12 ++++++------ drivers/gpu/drm/radeon/radeon_asic.h | 1 - 3 files changed, 6 insertions(+), 26 deletions(-)
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 8a9c85d..107b217 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -1392,25 +1392,6 @@ int cayman_cp_resume(struct radeon_device *rdev) return 0; }
-bool cayman_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) -{ - u32 srbm_status; - u32 grbm_status; - u32 grbm_status_se0, grbm_status_se1; - - srbm_status = RREG32(SRBM_STATUS); - grbm_status = RREG32(GRBM_STATUS); - grbm_status_se0 = RREG32(GRBM_STATUS_SE0); - grbm_status_se1 = RREG32(GRBM_STATUS_SE1); - if (!(grbm_status & GUI_ACTIVE)) { - radeon_ring_lockup_update(ring); - return false; - } - /* force CP activities */ - radeon_ring_force_activity(rdev, ring); - return radeon_ring_test_lockup(rdev, ring); -} - static int cayman_gpu_soft_reset(struct radeon_device *rdev) { struct evergreen_mc_save save; diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 5e5694e..f533df5 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -1339,7 +1339,7 @@ static struct radeon_asic cayman_asic = { .cs_parse = &evergreen_cs_parse, .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, - .is_lockup = &cayman_gpu_is_lockup, + .is_lockup = &evergreen_gpu_is_lockup, }, [CAYMAN_RING_TYPE_CP1_INDEX] = { .ib_execute = &cayman_ring_ib_execute, @@ -1349,7 +1349,7 @@ static struct radeon_asic cayman_asic = { .cs_parse = &evergreen_cs_parse, .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, - .is_lockup = &cayman_gpu_is_lockup, + .is_lockup = &evergreen_gpu_is_lockup, }, [CAYMAN_RING_TYPE_CP2_INDEX] = { .ib_execute = &cayman_ring_ib_execute, @@ -1359,7 +1359,7 @@ static struct radeon_asic cayman_asic = { .cs_parse = &evergreen_cs_parse, .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, - .is_lockup = &cayman_gpu_is_lockup, + .is_lockup = &evergreen_gpu_is_lockup, } }, .irq = { @@ -1433,7 +1433,7 @@ static struct radeon_asic trinity_asic = { .cs_parse = &evergreen_cs_parse, .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, - .is_lockup = &cayman_gpu_is_lockup, + .is_lockup = &evergreen_gpu_is_lockup, }, [CAYMAN_RING_TYPE_CP1_INDEX] = { .ib_execute = &cayman_ring_ib_execute, @@ -1443,7 +1443,7 @@ static struct radeon_asic trinity_asic = { .cs_parse = &evergreen_cs_parse, .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, - .is_lockup = &cayman_gpu_is_lockup, + .is_lockup = &evergreen_gpu_is_lockup, }, [CAYMAN_RING_TYPE_CP2_INDEX] = { .ib_execute = &cayman_ring_ib_execute, @@ -1453,7 +1453,7 @@ static struct radeon_asic trinity_asic = { .cs_parse = &evergreen_cs_parse, .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, - .is_lockup = &cayman_gpu_is_lockup, + .is_lockup = &evergreen_gpu_is_lockup, } }, .irq = { diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 3f7ecbb..513f33f 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -440,7 +440,6 @@ int cayman_init(struct radeon_device *rdev); void cayman_fini(struct radeon_device *rdev); int cayman_suspend(struct radeon_device *rdev); int cayman_resume(struct radeon_device *rdev); -bool cayman_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *cp); int cayman_asic_reset(struct radeon_device *rdev); void cayman_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); int cayman_vm_init(struct radeon_device *rdev);
On Tue, May 1, 2012 at 1:19 PM, j.glisse@gmail.com wrote:
Of course i sent the wrong patch 9 & 10 correct one: http://people.freedesktop.org/~glisse/reset/0009-drm-radeon-improve-sa-alloc... http://people.freedesktop.org/~glisse/reset/0010-drm-radeon-sa-allocator-add...
Note that i am in process of testing all this
Cheers, Jerome
dri-devel@lists.freedesktop.org