drm/amdgpu: add support for self irq on Vega10 v2

This finally enables processing of ring 1 & 2.

v2: fix copy&paste error

Signed-off-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Christian König 2018-09-26 14:15:21 +02:00 committed by Alex Deucher
parent 9dd60c4e59
commit cf67950e22

View File

@ -270,7 +270,7 @@ static void vega10_ih_irq_disable(struct amdgpu_device *adev)
static u32 vega10_ih_get_wptr(struct amdgpu_device *adev, static u32 vega10_ih_get_wptr(struct amdgpu_device *adev,
struct amdgpu_ih_ring *ih) struct amdgpu_ih_ring *ih)
{ {
u32 wptr, tmp; u32 wptr, reg, tmp;
wptr = le32_to_cpu(*ih->wptr_cpu); wptr = le32_to_cpu(*ih->wptr_cpu);
@ -278,7 +278,17 @@ static u32 vega10_ih_get_wptr(struct amdgpu_device *adev,
goto out; goto out;
/* Double check that the overflow wasn't already cleared. */ /* Double check that the overflow wasn't already cleared. */
wptr = RREG32_NO_KIQ(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR));
if (ih == &adev->irq.ih)
reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR);
else if (ih == &adev->irq.ih1)
reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_RING1);
else if (ih == &adev->irq.ih2)
reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_RING2);
else
BUG();
wptr = RREG32_NO_KIQ(reg);
if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW)) if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
goto out; goto out;
@ -294,9 +304,18 @@ static u32 vega10_ih_get_wptr(struct amdgpu_device *adev,
wptr, ih->rptr, tmp); wptr, ih->rptr, tmp);
ih->rptr = tmp; ih->rptr = tmp;
tmp = RREG32_NO_KIQ(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL)); if (ih == &adev->irq.ih)
reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL);
else if (ih == &adev->irq.ih1)
reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL_RING1);
else if (ih == &adev->irq.ih2)
reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL_RING2);
else
BUG();
tmp = RREG32_NO_KIQ(reg);
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
WREG32_NO_KIQ(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL), tmp); WREG32_NO_KIQ(reg, tmp);
out: out:
return (wptr & ih->ptr_mask); return (wptr & ih->ptr_mask);
@ -359,23 +378,72 @@ static void vega10_ih_set_rptr(struct amdgpu_device *adev,
/* XXX check if swapping is necessary on BE */ /* XXX check if swapping is necessary on BE */
*ih->rptr_cpu = ih->rptr; *ih->rptr_cpu = ih->rptr;
WDOORBELL32(ih->doorbell_index, ih->rptr); WDOORBELL32(ih->doorbell_index, ih->rptr);
} else { } else if (ih == &adev->irq.ih) {
WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR, ih->rptr); WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR, ih->rptr);
} else if (ih == &adev->irq.ih1) {
WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING1, ih->rptr);
} else if (ih == &adev->irq.ih2) {
WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING2, ih->rptr);
} }
} }
/**
* vega10_ih_self_irq - dispatch work for ring 1 and 2
*
* @adev: amdgpu_device pointer
* @source: irq source
* @entry: IV with WPTR update
*
* Update the WPTR from the IV and schedule work to handle the entries.
*/
static int vega10_ih_self_irq(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
struct amdgpu_iv_entry *entry)
{
uint32_t wptr = cpu_to_le32(entry->src_data[0]);
switch (entry->ring_id) {
case 1:
*adev->irq.ih1.wptr_cpu = wptr;
schedule_work(&adev->irq.ih1_work);
break;
case 2:
*adev->irq.ih2.wptr_cpu = wptr;
schedule_work(&adev->irq.ih2_work);
break;
default: break;
}
return 0;
}
static const struct amdgpu_irq_src_funcs vega10_ih_self_irq_funcs = {
.process = vega10_ih_self_irq,
};
static void vega10_ih_set_self_irq_funcs(struct amdgpu_device *adev)
{
adev->irq.self_irq.num_types = 0;
adev->irq.self_irq.funcs = &vega10_ih_self_irq_funcs;
}
static int vega10_ih_early_init(void *handle) static int vega10_ih_early_init(void *handle)
{ {
struct amdgpu_device *adev = (struct amdgpu_device *)handle; struct amdgpu_device *adev = (struct amdgpu_device *)handle;
vega10_ih_set_interrupt_funcs(adev); vega10_ih_set_interrupt_funcs(adev);
vega10_ih_set_self_irq_funcs(adev);
return 0; return 0;
} }
static int vega10_ih_sw_init(void *handle) static int vega10_ih_sw_init(void *handle)
{ {
int r;
struct amdgpu_device *adev = (struct amdgpu_device *)handle; struct amdgpu_device *adev = (struct amdgpu_device *)handle;
int r;
r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_IH, 0,
&adev->irq.self_irq);
if (r)
return r;
r = amdgpu_ih_ring_init(adev, &adev->irq.ih, 256 * 1024, true); r = amdgpu_ih_ring_init(adev, &adev->irq.ih, 256 * 1024, true);
if (r) if (r)