Commit 1e63ebc0 authored by Alex Deucher's avatar Alex Deucher
Browse files

drm/amdgpu/gfx11: add support for disable_kq



Plumb in support for disabling kernel queues in
GFX11.  We have to bring up a GFX queue briefly in
order to initialize the clear state.  After that
we can disable it.

v2: use ring counts per Felix' suggestion
v3: fix stream fault handler, enable EOP interrupts
v4: fix MEC interrupt offset (Sunil)

Reviewed-by: default avatarSunil Khatri <sunil.khatri@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 1f61fc28
Loading
Loading
Loading
Loading
+136 −55
Original line number Diff line number Diff line
@@ -1156,6 +1156,10 @@ static int gfx_v11_0_gfx_ring_init(struct amdgpu_device *adev, int ring_id,

	ring->ring_obj = NULL;
	ring->use_doorbell = true;
	if (adev->gfx.disable_kq) {
		ring->no_scheduler = true;
		ring->no_user_submission = true;
	}

	if (!ring_id)
		ring->doorbell_index = adev->doorbell_index.gfx_ring0 << 1;
@@ -1588,7 +1592,7 @@ static void gfx_v11_0_alloc_ip_dump(struct amdgpu_device *adev)

static int gfx_v11_0_sw_init(struct amdgpu_ip_block *ip_block)
{
	int i, j, k, r, ring_id = 0;
	int i, j, k, r, ring_id;
	int xcc_id = 0;
	struct amdgpu_device *adev = ip_block->adev;
	int num_queue_per_pipe = 1; /* we only enable 1 KGQ per pipe */
@@ -1745,6 +1749,8 @@ static int gfx_v11_0_sw_init(struct amdgpu_ip_block *ip_block)
		return r;
	}

	if (adev->gfx.num_gfx_rings) {
		ring_id = 0;
		/* set up the gfx ring */
		for (i = 0; i < adev->gfx.me.num_me; i++) {
			for (j = 0; j < num_queue_per_pipe; j++) {
@@ -1760,7 +1766,9 @@ static int gfx_v11_0_sw_init(struct amdgpu_ip_block *ip_block)
				}
			}
		}
	}

	if (adev->gfx.num_compute_rings) {
		ring_id = 0;
		/* set up the compute queues - allocate horizontally across pipes */
		for (i = 0; i < adev->gfx.mec.num_mec; ++i) {
@@ -1779,6 +1787,7 @@ static int gfx_v11_0_sw_init(struct amdgpu_ip_block *ip_block)
				}
			}
		}
	}

	adev->gfx.gfx_supported_reset =
		amdgpu_get_soft_full_reset_mask(&adev->gfx.gfx_ring[0]);
@@ -4567,12 +4576,24 @@ static int gfx_v11_0_cp_resume(struct amdgpu_device *adev)
			return r;
	}

	if (adev->gfx.disable_kq) {
		for (i = 0; i < adev->gfx.num_gfx_rings; i++) {
			ring = &adev->gfx.gfx_ring[i];
			/* we don't want to set ring->ready */
			r = amdgpu_ring_test_ring(ring);
			if (r)
				return r;
		}
		if (amdgpu_async_gfx_ring)
			amdgpu_gfx_disable_kgq(adev, 0);
	} else {
		for (i = 0; i < adev->gfx.num_gfx_rings; i++) {
			ring = &adev->gfx.gfx_ring[i];
			r = amdgpu_ring_test_helper(ring);
			if (r)
				return r;
		}
	}

	for (i = 0; i < adev->gfx.num_compute_rings; i++) {
		ring = &adev->gfx.compute_ring[i];
@@ -4780,6 +4801,46 @@ static int gfx_v11_0_hw_init(struct amdgpu_ip_block *ip_block)
	return r;
}

static int gfx_v11_0_set_userq_eop_interrupts(struct amdgpu_device *adev,
					      bool enable)
{
	if (adev->gfx.disable_kq) {
		unsigned int irq_type;
		int m, p, r;

		for (m = 0; m < adev->gfx.me.num_me; m++) {
			for (p = 0; p < adev->gfx.me.num_pipe_per_me; p++) {
				irq_type = AMDGPU_CP_IRQ_GFX_ME0_PIPE0_EOP + p;
				if (enable)
					r = amdgpu_irq_get(adev, &adev->gfx.eop_irq,
							   irq_type);
				else
					r = amdgpu_irq_put(adev, &adev->gfx.eop_irq,
							   irq_type);
				if (r)
					return r;
			}
		}

		for (m = 0; m < adev->gfx.mec.num_mec; ++m) {
			for (p = 0; p < adev->gfx.mec.num_pipe_per_mec; p++) {
				irq_type = AMDGPU_CP_IRQ_COMPUTE_MEC1_PIPE0_EOP
					+ (m * adev->gfx.mec.num_pipe_per_mec)
					+ p;
				if (enable)
					r = amdgpu_irq_get(adev, &adev->gfx.eop_irq,
							   irq_type);
				else
					r = amdgpu_irq_put(adev, &adev->gfx.eop_irq,
							   irq_type);
				if (r)
					return r;
			}
		}
	}
	return 0;
}

static int gfx_v11_0_hw_fini(struct amdgpu_ip_block *ip_block)
{
	struct amdgpu_device *adev = ip_block->adev;
@@ -4789,9 +4850,11 @@ static int gfx_v11_0_hw_fini(struct amdgpu_ip_block *ip_block)
	amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0);
	amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0);
	amdgpu_irq_put(adev, &adev->gfx.bad_op_irq, 0);
	gfx_v11_0_set_userq_eop_interrupts(adev, false);

	if (!adev->no_hw_access) {
		if (amdgpu_async_gfx_ring) {
		if (amdgpu_async_gfx_ring &&
		    !adev->gfx.disable_kq) {
			if (amdgpu_gfx_disable_kgq(adev, 0))
				DRM_ERROR("KGQ disable failed\n");
		}
@@ -5117,11 +5180,22 @@ static int gfx_v11_0_early_init(struct amdgpu_ip_block *ip_block)
{
	struct amdgpu_device *adev = ip_block->adev;

	if (amdgpu_disable_kq == 1)
		adev->gfx.disable_kq = true;

	adev->gfx.funcs = &gfx_v11_0_gfx_funcs;

	if (adev->gfx.disable_kq) {
		/* We need one GFX ring temporarily to set up
		 * the clear state.
		 */
		adev->gfx.num_gfx_rings = 1;
		adev->gfx.num_compute_rings = 0;
	} else {
		adev->gfx.num_gfx_rings = GFX11_NUM_GFX_RINGS;
		adev->gfx.num_compute_rings = min(amdgpu_gfx_get_num_kcq(adev),
						  AMDGPU_MAX_COMPUTE_RINGS);
	}

	gfx_v11_0_set_kiq_pm4_funcs(adev);
	gfx_v11_0_set_ring_funcs(adev);
@@ -5152,6 +5226,11 @@ static int gfx_v11_0_late_init(struct amdgpu_ip_block *ip_block)
	r = amdgpu_irq_get(adev, &adev->gfx.bad_op_irq, 0);
	if (r)
		return r;

	r = gfx_v11_0_set_userq_eop_interrupts(adev, true);
	if (r)
		return r;

	return 0;
}

@@ -6510,6 +6589,7 @@ static void gfx_v11_0_handle_priv_fault(struct amdgpu_device *adev,
	pipe_id = (entry->ring_id & 0x03) >> 0;
	queue_id = (entry->ring_id & 0x70) >> 4;

	if (!adev->gfx.disable_kq) {
		switch (me_id) {
		case 0:
			for (i = 0; i < adev->gfx.num_gfx_rings; i++) {
@@ -6533,6 +6613,7 @@ static void gfx_v11_0_handle_priv_fault(struct amdgpu_device *adev,
			break;
		}
	}
}

static int gfx_v11_0_priv_reg_irq(struct amdgpu_device *adev,
				  struct amdgpu_irq_src *source,