Commit 22666cc1 authored by Christian König's avatar Christian König Committed by Alex Deucher
Browse files

drm/amdgpu: move IV prescreening into the GMC code



The GMC/VM subsystem is causing the faults, so move the handling here as
well.

Signed-off-by: default avatarChristian König <christian.koenig@amd.com>
Reviewed-by: default avatarFelix Kuehling <Felix.Kuehling@amd.com>
Acked-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent a655dad4
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -51,14 +51,12 @@ struct amdgpu_ih_ring {
struct amdgpu_ih_funcs {
	/* ring read/write ptr handling, called from interrupt context */
	u32 (*get_wptr)(struct amdgpu_device *adev);
	bool (*prescreen_iv)(struct amdgpu_device *adev);
	void (*decode_iv)(struct amdgpu_device *adev,
			  struct amdgpu_iv_entry *entry);
	void (*set_rptr)(struct amdgpu_device *adev);
};

#define amdgpu_ih_get_wptr(adev) (adev)->irq.ih_funcs->get_wptr((adev))
#define amdgpu_ih_prescreen_iv(adev) (adev)->irq.ih_funcs->prescreen_iv((adev))
#define amdgpu_ih_decode_iv(adev, iv) (adev)->irq.ih_funcs->decode_iv((adev), (iv))
#define amdgpu_ih_set_rptr(adev) (adev)->irq.ih_funcs->set_rptr((adev))

+0 −4
Original line number Diff line number Diff line
@@ -145,10 +145,6 @@ static void amdgpu_irq_callback(struct amdgpu_device *adev,
	u32 ring_index = ih->rptr >> 2;
	struct amdgpu_iv_entry entry;

	/* Prescreening of high-frequency interrupts */
	if (!amdgpu_ih_prescreen_iv(adev))
		return;

	entry.iv_entry = (const uint32_t *)&ih->ring[ring_index];
	amdgpu_ih_decode_iv(adev, &entry);

+0 −13
Original line number Diff line number Diff line
@@ -228,18 +228,6 @@ static u32 cik_ih_get_wptr(struct amdgpu_device *adev)
 * [127:96] - reserved
 */

/**
 * cik_ih_prescreen_iv - prescreen an interrupt vector
 *
 * @adev: amdgpu_device pointer
 *
 * Returns true if the interrupt vector should be further processed.
 */
static bool cik_ih_prescreen_iv(struct amdgpu_device *adev)
{
	return true;
}

 /**
 * cik_ih_decode_iv - decode an interrupt vector
 *
@@ -445,7 +433,6 @@ static const struct amd_ip_funcs cik_ih_ip_funcs = {

static const struct amdgpu_ih_funcs cik_ih_funcs = {
	.get_wptr = cik_ih_get_wptr,
	.prescreen_iv = cik_ih_prescreen_iv,
	.decode_iv = cik_ih_decode_iv,
	.set_rptr = cik_ih_set_rptr
};
+0 −13
Original line number Diff line number Diff line
@@ -207,18 +207,6 @@ static u32 cz_ih_get_wptr(struct amdgpu_device *adev)
	return (wptr & adev->irq.ih.ptr_mask);
}

/**
 * cz_ih_prescreen_iv - prescreen an interrupt vector
 *
 * @adev: amdgpu_device pointer
 *
 * Returns true if the interrupt vector should be further processed.
 */
static bool cz_ih_prescreen_iv(struct amdgpu_device *adev)
{
	return true;
}

/**
 * cz_ih_decode_iv - decode an interrupt vector
 *
@@ -426,7 +414,6 @@ static const struct amd_ip_funcs cz_ih_ip_funcs = {

static const struct amdgpu_ih_funcs cz_ih_funcs = {
	.get_wptr = cz_ih_get_wptr,
	.prescreen_iv = cz_ih_prescreen_iv,
	.decode_iv = cz_ih_decode_iv,
	.set_rptr = cz_ih_set_rptr
};
+59 −0
Original line number Diff line number Diff line
@@ -244,6 +244,62 @@ static int gmc_v9_0_vm_fault_interrupt_state(struct amdgpu_device *adev,
	return 0;
}

/**
 * vega10_ih_prescreen_iv - prescreen an interrupt vector
 *
 * @adev: amdgpu_device pointer
 *
 * Returns true if the interrupt vector should be further processed.
 */
static bool gmc_v9_0_prescreen_iv(struct amdgpu_device *adev,
				  struct amdgpu_iv_entry *entry,
				  uint64_t addr)
{
	struct amdgpu_vm *vm;
	u64 key;
	int r;

	/* No PASID, can't identify faulting process */
	if (!entry->pasid)
		return true;

	/* Not a retry fault */
	if (!(entry->src_data[1] & 0x80))
		return true;

	/* Track retry faults in per-VM fault FIFO. */
	spin_lock(&adev->vm_manager.pasid_lock);
	vm = idr_find(&adev->vm_manager.pasid_idr, entry->pasid);
	if (!vm) {
		/* VM not found, process it normally */
		spin_unlock(&adev->vm_manager.pasid_lock);
		return true;
	}

	key = AMDGPU_VM_FAULT(entry->pasid, addr);
	r = amdgpu_vm_add_fault(vm->fault_hash, key);

	/* Hash table is full or the fault is already being processed,
	 * ignore further page faults
	 */
	if (r != 0) {
		spin_unlock(&adev->vm_manager.pasid_lock);
		return false;
	}
	/* No locking required with single writer and single reader */
	r = kfifo_put(&vm->faults, key);
	if (!r) {
		/* FIFO is full. Ignore it until there is space */
		amdgpu_vm_clear_fault(vm->fault_hash, key);
		spin_unlock(&adev->vm_manager.pasid_lock);
		return false;
	}

	spin_unlock(&adev->vm_manager.pasid_lock);
	/* It's the first fault for this address, process it normally */
	return true;
}

static int gmc_v9_0_process_interrupt(struct amdgpu_device *adev,
				struct amdgpu_irq_src *source,
				struct amdgpu_iv_entry *entry)
@@ -255,6 +311,9 @@ static int gmc_v9_0_process_interrupt(struct amdgpu_device *adev,
	addr = (u64)entry->src_data[0] << 12;
	addr |= ((u64)entry->src_data[1] & 0xf) << 44;

	if (!gmc_v9_0_prescreen_iv(adev, entry, addr))
		return 1; /* This also prevents sending it to KFD */

	if (!amdgpu_sriov_vf(adev)) {
		status = RREG32(hub->vm_l2_pro_fault_status);
		WREG32_P(hub->vm_l2_pro_fault_cntl, 1, ~1);
Loading