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

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
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -98,6 +98,8 @@ struct amdgpu_irq {
	struct irq_domain		*domain; /* GPU irq controller domain */
	unsigned			virq[AMDGPU_MAX_IRQ_SRC_ID];
	uint32_t                        srbm_soft_reset;
	u32                             retry_cam_doorbell_index;
	bool                            retry_cam_enabled;
};

void amdgpu_irq_disable_all(struct amdgpu_device *adev);
+34 −17
Original line number Diff line number Diff line
@@ -555,13 +555,29 @@ static int gmc_v9_0_process_interrupt(struct amdgpu_device *adev,
	const char *mmhub_cid;
	const char *hub_name;
	u64 addr;
	uint32_t cam_index = 0;
	int ret;

	addr = (u64)entry->src_data[0] << 12;
	addr |= ((u64)entry->src_data[1] & 0xf) << 44;

	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;

			ret = amdgpu_vm_handle_fault(adev, entry->pasid, addr, write_fault);
			WDOORBELL32(adev->irq.retry_cam_doorbell_index, cam_index);
			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,
@@ -582,6 +598,7 @@ static int gmc_v9_0_process_interrupt(struct amdgpu_device *adev,
			if (amdgpu_vm_handle_fault(adev, entry->pasid, addr, write_fault))
				return 1;
		}
	}

	if (!printk_ratelimit())
		return 0;
+1 −1
Original line number Diff line number Diff line
@@ -238,7 +238,7 @@ static void nbio_v7_4_ih_doorbell_range(struct amdgpu_device *adev,

	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, SIZE, 4);
		ih_doorbell_range = REG_SET_FIELD(ih_doorbell_range, BIF_IH_DOORBELL_RANGE, SIZE, 8);
	} else
		ih_doorbell_range = REG_SET_FIELD(ih_doorbell_range, BIF_IH_DOORBELL_RANGE, SIZE, 0);

+25 −30
Original line number Diff line number Diff line
@@ -38,6 +38,11 @@
#define mmIH_CHICKEN_ALDEBARAN			0x18d
#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);

/**
@@ -251,36 +256,14 @@ static int vega20_ih_enable_ring(struct amdgpu_device *adev,
	return 0;
}

/**
 * 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)
static uint32_t vega20_setup_retry_doorbell(u32 doorbell_index)
{
	uint32_t tmp;
	u32 val = 0;

	/* vega20 ih reroute will go through psp this
	 * function is used for newer asics starting arcturus
	 */
	if (adev->ip_versions[OSSSYS_HWIP][0] >= IP_VERSION(4, 2, 1)) {
		/* 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);
	val = REG_SET_FIELD(val, IH_DOORBELL_RPTR, OFFSET, doorbell_index);
	val = REG_SET_FIELD(val, IH_DOORBELL_RPTR, ENABLE, 1);

		/* 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);
	}
	return val;
}

/**
@@ -333,8 +316,6 @@ static int vega20_ih_irq_init(struct amdgpu_device *adev)

	for (i = 0; i < ARRAY_SIZE(ih); i++) {
		if (ih[i]->ring_size) {
			if (i == 1)
				vega20_ih_reroute_ih(adev);
			ret = vega20_ih_enable_ring(adev, ih[i]);
			if (ret)
				return ret;
@@ -347,6 +328,20 @@ static int vega20_ih_irq_init(struct amdgpu_device *adev)

	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 */
	ret = vega20_ih_toggle_interrupts(adev, true);
	if (ret)
+9 −1
Original line number Diff line number Diff line
@@ -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);

		amdgpu_ih_wait_on_checkpoint_process_ts(pdd->dev->adev,
				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);
	}
	if (atomic_cmpxchg(&svms->drain_pagefaults, drain, 0) != drain)
Loading