Commit 318e431b authored by Mukul Joshi's avatar Mukul Joshi Committed by Alex Deucher

drm/amdgpu: Enable IH retry CAM on GFX9

This patch enables the IH retry CAM on GFX9 series cards. This
retry filter is used to prevent sending lots of retry interrupts
in a short span of time and overflowing the IH ring buffer. This
will also help reduce CPU interrupt workload.
Signed-off-by: default avatarMukul Joshi <mukul.joshi@amd.com>
Reviewed-by: default avatarFelix Kuehling <Felix.Kuehling@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent e69c373c
...@@ -98,6 +98,8 @@ struct amdgpu_irq { ...@@ -98,6 +98,8 @@ struct amdgpu_irq {
struct irq_domain *domain; /* GPU irq controller domain */ struct irq_domain *domain; /* GPU irq controller domain */
unsigned virq[AMDGPU_MAX_IRQ_SRC_ID]; unsigned virq[AMDGPU_MAX_IRQ_SRC_ID];
uint32_t srbm_soft_reset; uint32_t srbm_soft_reset;
u32 retry_cam_doorbell_index;
bool retry_cam_enabled;
}; };
void amdgpu_irq_disable_all(struct amdgpu_device *adev); void amdgpu_irq_disable_all(struct amdgpu_device *adev);
......
...@@ -555,32 +555,49 @@ static int gmc_v9_0_process_interrupt(struct amdgpu_device *adev, ...@@ -555,32 +555,49 @@ static int gmc_v9_0_process_interrupt(struct amdgpu_device *adev,
const char *mmhub_cid; const char *mmhub_cid;
const char *hub_name; const char *hub_name;
u64 addr; u64 addr;
uint32_t cam_index = 0;
int ret;
addr = (u64)entry->src_data[0] << 12; addr = (u64)entry->src_data[0] << 12;
addr |= ((u64)entry->src_data[1] & 0xf) << 44; addr |= ((u64)entry->src_data[1] & 0xf) << 44;
if (retry_fault) { if (retry_fault) {
/* Returning 1 here also prevents sending the IV to the KFD */ if (adev->irq.retry_cam_enabled) {
/* Delegate it to a different ring if the hardware hasn't
* already done it.
*/
if (entry->ih == &adev->irq.ih) {
amdgpu_irq_delegate(adev, entry, 8);
return 1;
}
cam_index = entry->src_data[2] & 0x3ff;
/* Process it onyl if it's the first fault for this address */ ret = amdgpu_vm_handle_fault(adev, entry->pasid, addr, write_fault);
if (entry->ih != &adev->irq.ih_soft && WDOORBELL32(adev->irq.retry_cam_doorbell_index, cam_index);
amdgpu_gmc_filter_faults(adev, entry->ih, addr, entry->pasid, if (ret)
return 1;
} else {
/* Process it onyl if it's the first fault for this address */
if (entry->ih != &adev->irq.ih_soft &&
amdgpu_gmc_filter_faults(adev, entry->ih, addr, entry->pasid,
entry->timestamp)) entry->timestamp))
return 1; return 1;
/* Delegate it to a different ring if the hardware hasn't /* Delegate it to a different ring if the hardware hasn't
* already done it. * already done it.
*/ */
if (entry->ih == &adev->irq.ih) { if (entry->ih == &adev->irq.ih) {
amdgpu_irq_delegate(adev, entry, 8); amdgpu_irq_delegate(adev, entry, 8);
return 1; return 1;
} }
/* Try to handle the recoverable page faults by filling page /* Try to handle the recoverable page faults by filling page
* tables * tables
*/ */
if (amdgpu_vm_handle_fault(adev, entry->pasid, addr, write_fault)) if (amdgpu_vm_handle_fault(adev, entry->pasid, addr, write_fault))
return 1; return 1;
}
} }
if (!printk_ratelimit()) if (!printk_ratelimit())
......
...@@ -238,7 +238,7 @@ static void nbio_v7_4_ih_doorbell_range(struct amdgpu_device *adev, ...@@ -238,7 +238,7 @@ static void nbio_v7_4_ih_doorbell_range(struct amdgpu_device *adev,
if (use_doorbell) { if (use_doorbell) {
ih_doorbell_range = REG_SET_FIELD(ih_doorbell_range, BIF_IH_DOORBELL_RANGE, OFFSET, doorbell_index); ih_doorbell_range = REG_SET_FIELD(ih_doorbell_range, BIF_IH_DOORBELL_RANGE, OFFSET, doorbell_index);
ih_doorbell_range = REG_SET_FIELD(ih_doorbell_range, BIF_IH_DOORBELL_RANGE, SIZE, 4); ih_doorbell_range = REG_SET_FIELD(ih_doorbell_range, BIF_IH_DOORBELL_RANGE, SIZE, 8);
} else } else
ih_doorbell_range = REG_SET_FIELD(ih_doorbell_range, BIF_IH_DOORBELL_RANGE, SIZE, 0); ih_doorbell_range = REG_SET_FIELD(ih_doorbell_range, BIF_IH_DOORBELL_RANGE, SIZE, 0);
......
...@@ -38,6 +38,11 @@ ...@@ -38,6 +38,11 @@
#define mmIH_CHICKEN_ALDEBARAN 0x18d #define mmIH_CHICKEN_ALDEBARAN 0x18d
#define mmIH_CHICKEN_ALDEBARAN_BASE_IDX 0 #define mmIH_CHICKEN_ALDEBARAN_BASE_IDX 0
#define mmIH_RETRY_INT_CAM_CNTL_ALDEBARAN 0x00ea
#define mmIH_RETRY_INT_CAM_CNTL_ALDEBARAN_BASE_IDX 0
#define IH_RETRY_INT_CAM_CNTL_ALDEBARAN__ENABLE__SHIFT 0x10
#define IH_RETRY_INT_CAM_CNTL_ALDEBARAN__ENABLE_MASK 0x00010000L
static void vega20_ih_set_interrupt_funcs(struct amdgpu_device *adev); static void vega20_ih_set_interrupt_funcs(struct amdgpu_device *adev);
/** /**
...@@ -251,36 +256,14 @@ static int vega20_ih_enable_ring(struct amdgpu_device *adev, ...@@ -251,36 +256,14 @@ static int vega20_ih_enable_ring(struct amdgpu_device *adev,
return 0; return 0;
} }
/** static uint32_t vega20_setup_retry_doorbell(u32 doorbell_index)
* vega20_ih_reroute_ih - reroute VMC/UTCL2 ih to an ih ring
*
* @adev: amdgpu_device pointer
*
* Reroute VMC and UMC interrupts on primary ih ring to
* ih ring 1 so they won't lose when bunches of page faults
* interrupts overwhelms the interrupt handler(VEGA20)
*/
static void vega20_ih_reroute_ih(struct amdgpu_device *adev)
{ {
uint32_t tmp; u32 val = 0;
/* vega20 ih reroute will go through psp this val = REG_SET_FIELD(val, IH_DOORBELL_RPTR, OFFSET, doorbell_index);
* function is used for newer asics starting arcturus val = REG_SET_FIELD(val, IH_DOORBELL_RPTR, ENABLE, 1);
*/
if (adev->ip_versions[OSSSYS_HWIP][0] >= IP_VERSION(4, 2, 1)) { return val;
/* Reroute to IH ring 1 for VMC */
WREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_INDEX, 0x12);
tmp = RREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_DATA);
tmp = REG_SET_FIELD(tmp, IH_CLIENT_CFG_DATA, CLIENT_TYPE, 1);
tmp = REG_SET_FIELD(tmp, IH_CLIENT_CFG_DATA, RING_ID, 1);
WREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_DATA, tmp);
/* Reroute IH ring 1 for UTCL2 */
WREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_INDEX, 0x1B);
tmp = RREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_DATA);
tmp = REG_SET_FIELD(tmp, IH_CLIENT_CFG_DATA, RING_ID, 1);
WREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_DATA, tmp);
}
} }
/** /**
...@@ -333,8 +316,6 @@ static int vega20_ih_irq_init(struct amdgpu_device *adev) ...@@ -333,8 +316,6 @@ static int vega20_ih_irq_init(struct amdgpu_device *adev)
for (i = 0; i < ARRAY_SIZE(ih); i++) { for (i = 0; i < ARRAY_SIZE(ih); i++) {
if (ih[i]->ring_size) { if (ih[i]->ring_size) {
if (i == 1)
vega20_ih_reroute_ih(adev);
ret = vega20_ih_enable_ring(adev, ih[i]); ret = vega20_ih_enable_ring(adev, ih[i]);
if (ret) if (ret)
return ret; return ret;
...@@ -347,6 +328,20 @@ static int vega20_ih_irq_init(struct amdgpu_device *adev) ...@@ -347,6 +328,20 @@ static int vega20_ih_irq_init(struct amdgpu_device *adev)
pci_set_master(adev->pdev); pci_set_master(adev->pdev);
/* Allocate the doorbell for IH Retry CAM */
adev->irq.retry_cam_doorbell_index = (adev->doorbell_index.ih + 3) << 1;
WREG32_SOC15(OSSSYS, 0, mmIH_DOORBELL_RETRY_CAM,
vega20_setup_retry_doorbell(adev->irq.retry_cam_doorbell_index));
/* Enable IH Retry CAM */
if (adev->ip_versions[OSSSYS_HWIP][0] == IP_VERSION(4, 4, 0))
WREG32_FIELD15(OSSSYS, 0, IH_RETRY_INT_CAM_CNTL_ALDEBARAN,
ENABLE, 1);
else
WREG32_FIELD15(OSSSYS, 0, IH_RETRY_INT_CAM_CNTL, ENABLE, 1);
adev->irq.retry_cam_enabled = true;
/* enable interrupts */ /* enable interrupts */
ret = vega20_ih_toggle_interrupts(adev, true); ret = vega20_ih_toggle_interrupts(adev, true);
if (ret) if (ret)
......
...@@ -2172,7 +2172,15 @@ static void svm_range_drain_retry_fault(struct svm_range_list *svms) ...@@ -2172,7 +2172,15 @@ static void svm_range_drain_retry_fault(struct svm_range_list *svms)
pr_debug("drain retry fault gpu %d svms %p\n", i, svms); pr_debug("drain retry fault gpu %d svms %p\n", i, svms);
amdgpu_ih_wait_on_checkpoint_process_ts(pdd->dev->adev, amdgpu_ih_wait_on_checkpoint_process_ts(pdd->dev->adev,
&pdd->dev->adev->irq.ih1); pdd->dev->adev->irq.retry_cam_enabled ?
&pdd->dev->adev->irq.ih :
&pdd->dev->adev->irq.ih1);
if (pdd->dev->adev->irq.retry_cam_enabled)
amdgpu_ih_wait_on_checkpoint_process_ts(pdd->dev->adev,
&pdd->dev->adev->irq.ih_soft);
pr_debug("drain retry fault gpu %d svms 0x%p done\n", i, svms); pr_debug("drain retry fault gpu %d svms 0x%p done\n", i, svms);
} }
if (atomic_cmpxchg(&svms->drain_pagefaults, drain, 0) != drain) if (atomic_cmpxchg(&svms->drain_pagefaults, drain, 0) != drain)
......
...@@ -135,6 +135,8 @@ ...@@ -135,6 +135,8 @@
#define mmIH_RB_WPTR_ADDR_LO_BASE_IDX 0 #define mmIH_RB_WPTR_ADDR_LO_BASE_IDX 0
#define mmIH_DOORBELL_RPTR 0x0087 #define mmIH_DOORBELL_RPTR 0x0087
#define mmIH_DOORBELL_RPTR_BASE_IDX 0 #define mmIH_DOORBELL_RPTR_BASE_IDX 0
#define mmIH_DOORBELL_RETRY_CAM 0x0088
#define mmIH_DOORBELL_RETRY_CAM_BASE_IDX 0
#define mmIH_RB_CNTL_RING1 0x008c #define mmIH_RB_CNTL_RING1 0x008c
#define mmIH_RB_CNTL_RING1_BASE_IDX 0 #define mmIH_RB_CNTL_RING1_BASE_IDX 0
#define mmIH_RB_BASE_RING1 0x008d #define mmIH_RB_BASE_RING1 0x008d
...@@ -159,6 +161,8 @@ ...@@ -159,6 +161,8 @@
#define mmIH_RB_WPTR_RING2_BASE_IDX 0 #define mmIH_RB_WPTR_RING2_BASE_IDX 0
#define mmIH_DOORBELL_RPTR_RING2 0x009f #define mmIH_DOORBELL_RPTR_RING2 0x009f
#define mmIH_DOORBELL_RPTR_RING2_BASE_IDX 0 #define mmIH_DOORBELL_RPTR_RING2_BASE_IDX 0
#define mmIH_RETRY_CAM_ACK 0x00a4
#define mmIH_RETRY_CAM_ACK_BASE_IDX 0
#define mmIH_VERSION 0x00a5 #define mmIH_VERSION 0x00a5
#define mmIH_VERSION_BASE_IDX 0 #define mmIH_VERSION_BASE_IDX 0
#define mmIH_CNTL 0x00c0 #define mmIH_CNTL 0x00c0
...@@ -235,6 +239,8 @@ ...@@ -235,6 +239,8 @@
#define mmIH_MMHUB_ERROR_BASE_IDX 0 #define mmIH_MMHUB_ERROR_BASE_IDX 0
#define mmIH_MEM_POWER_CTRL 0x00e8 #define mmIH_MEM_POWER_CTRL 0x00e8
#define mmIH_MEM_POWER_CTRL_BASE_IDX 0 #define mmIH_MEM_POWER_CTRL_BASE_IDX 0
#define mmIH_RETRY_INT_CAM_CNTL 0x00e9
#define mmIH_RETRY_INT_CAM_CNTL_BASE_IDX 0
#define mmIH_REGISTER_LAST_PART2 0x00ff #define mmIH_REGISTER_LAST_PART2 0x00ff
#define mmIH_REGISTER_LAST_PART2_BASE_IDX 0 #define mmIH_REGISTER_LAST_PART2_BASE_IDX 0
#define mmSEM_CLK_CTRL 0x0100 #define mmSEM_CLK_CTRL 0x0100
......
...@@ -349,6 +349,17 @@ ...@@ -349,6 +349,17 @@
#define IH_DOORBELL_RPTR_RING2__ENABLE__SHIFT 0x1c #define IH_DOORBELL_RPTR_RING2__ENABLE__SHIFT 0x1c
#define IH_DOORBELL_RPTR_RING2__OFFSET_MASK 0x03FFFFFFL #define IH_DOORBELL_RPTR_RING2__OFFSET_MASK 0x03FFFFFFL
#define IH_DOORBELL_RPTR_RING2__ENABLE_MASK 0x10000000L #define IH_DOORBELL_RPTR_RING2__ENABLE_MASK 0x10000000L
//IH_RETRY_INT_CAM_CNTL
#define IH_RETRY_INT_CAM_CNTL__CAM_SIZE__SHIFT 0x0
#define IH_RETRY_INT_CAM_CNTL__BACK_PRESSURE_SKID_VALUE__SHIFT 0x8
#define IH_RETRY_INT_CAM_CNTL__ENABLE__SHIFT 0x10
#define IH_RETRY_INT_CAM_CNTL__BACK_PRESSURE_ENABLE__SHIFT 0x11
#define IH_RETRY_INT_CAM_CNTL__PER_VF_ENTRY_SIZE__SHIFT 0x14
#define IH_RETRY_INT_CAM_CNTL__CAM_SIZE_MASK 0x0000001FL
#define IH_RETRY_INT_CAM_CNTL__BACK_PRESSURE_SKID_VALUE_MASK 0x00003F00L
#define IH_RETRY_INT_CAM_CNTL__ENABLE_MASK 0x00010000L
#define IH_RETRY_INT_CAM_CNTL__BACK_PRESSURE_ENABLE_MASK 0x00020000L
#define IH_RETRY_INT_CAM_CNTL__PER_VF_ENTRY_SIZE_MASK 0x00300000L
//IH_VERSION //IH_VERSION
#define IH_VERSION__MINVER__SHIFT 0x0 #define IH_VERSION__MINVER__SHIFT 0x0
#define IH_VERSION__MAJVER__SHIFT 0x8 #define IH_VERSION__MAJVER__SHIFT 0x8
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment