diff options
| author | Thomas Gleixner <[email protected]> | 2020-06-11 15:17:57 +0200 | 
|---|---|---|
| committer | Thomas Gleixner <[email protected]> | 2020-06-11 15:17:57 +0200 | 
| commit | f77d26a9fc525286bcef3d4f98b52e17482cf49c (patch) | |
| tree | 6b179c9aa84787773cb601a14a64255e2912154b /drivers/gpu/drm/amd/amdgpu/navi10_ih.c | |
| parent | b6bea24d41519e8c31e4798f1c1a3f67e540c5d0 (diff) | |
| parent | f0178fc01fe46bab6a95415f5647d1a74efcad1b (diff) | |
Merge branch 'x86/entry' into ras/core
to fixup conflicts in arch/x86/kernel/cpu/mce/core.c so MCE specific follow
up patches can be applied without creating a horrible merge conflict
afterwards.
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/navi10_ih.c')
| -rw-r--r-- | drivers/gpu/drm/amd/amdgpu/navi10_ih.c | 302 | 
1 files changed, 282 insertions, 20 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/navi10_ih.c b/drivers/gpu/drm/amd/amdgpu/navi10_ih.c index e08245a446fc..f97857ed3c7e 100644 --- a/drivers/gpu/drm/amd/amdgpu/navi10_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/navi10_ih.c @@ -49,8 +49,48 @@ static void navi10_ih_enable_interrupts(struct amdgpu_device *adev)  	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RB_ENABLE, 1);  	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, ENABLE_INTR, 1); -	WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL, ih_rb_cntl); +	if (amdgpu_sriov_vf(adev) && adev->asic_type < CHIP_NAVI10) { +		if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL, ih_rb_cntl)) { +			DRM_ERROR("PSP program IH_RB_CNTL failed!\n"); +			return; +		} +	} else { +		WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL, ih_rb_cntl); +	} +  	adev->irq.ih.enabled = true; + +	if (adev->irq.ih1.ring_size) { +		ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1); +		ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL_RING1, +					   RB_ENABLE, 1); +		if (amdgpu_sriov_vf(adev) && adev->asic_type < CHIP_NAVI10) { +			if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL_RING1, +						ih_rb_cntl)) { +				DRM_ERROR("program IH_RB_CNTL_RING1 failed!\n"); +				return; +			} +		} else { +			WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1, ih_rb_cntl); +		} +		adev->irq.ih1.enabled = true; +	} + +	if (adev->irq.ih2.ring_size) { +		ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2); +		ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL_RING2, +					   RB_ENABLE, 1); +		if (amdgpu_sriov_vf(adev) && adev->asic_type < CHIP_NAVI10) { +			if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL_RING2, +						ih_rb_cntl)) { +				DRM_ERROR("program IH_RB_CNTL_RING2 failed!\n"); +				return; +			} +		} else { +			WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2, ih_rb_cntl); +		} +		adev->irq.ih2.enabled = true; +	}  }  /** @@ -66,12 +106,61 @@ static void navi10_ih_disable_interrupts(struct amdgpu_device *adev)  	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RB_ENABLE, 0);  	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, ENABLE_INTR, 0); -	WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL, ih_rb_cntl); +	if (amdgpu_sriov_vf(adev) && adev->asic_type < CHIP_NAVI10) { +		if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL, ih_rb_cntl)) { +			DRM_ERROR("PSP program IH_RB_CNTL failed!\n"); +			return; +		} +	} else { +		WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL, ih_rb_cntl); +	} +  	/* set rptr, wptr to 0 */  	WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR, 0);  	WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR, 0);  	adev->irq.ih.enabled = false;  	adev->irq.ih.rptr = 0; + +	if (adev->irq.ih1.ring_size) { +		ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1); +		ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL_RING1, +					   RB_ENABLE, 0); +		if (amdgpu_sriov_vf(adev) && adev->asic_type < CHIP_NAVI10) { +			if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL_RING1, +						ih_rb_cntl)) { +				DRM_ERROR("program IH_RB_CNTL_RING1 failed!\n"); +				return; +			} +		} else { +			WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1, ih_rb_cntl); +		} +		/* set rptr, wptr to 0 */ +		WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING1, 0); +		WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_RING1, 0); +		adev->irq.ih1.enabled = false; +		adev->irq.ih1.rptr = 0; +	} + +	if (adev->irq.ih2.ring_size) { +		ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2); +		ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL_RING2, +					   RB_ENABLE, 0); +		if (amdgpu_sriov_vf(adev) && adev->asic_type < CHIP_NAVI10) { +			if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL_RING2, +						ih_rb_cntl)) { +				DRM_ERROR("program IH_RB_CNTL_RING2 failed!\n"); +				return; +			} +		} else { +			WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2, ih_rb_cntl); +		} +		/* set rptr, wptr to 0 */ +		WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING2, 0); +		WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_RING2, 0); +		adev->irq.ih2.enabled = false; +		adev->irq.ih2.rptr = 0; +	} +  }  static uint32_t navi10_ih_rb_cntl(struct amdgpu_ih_ring *ih, uint32_t ih_rb_cntl) @@ -97,6 +186,43 @@ static uint32_t navi10_ih_rb_cntl(struct amdgpu_ih_ring *ih, uint32_t ih_rb_cntl  	return ih_rb_cntl;  } +static uint32_t navi10_ih_doorbell_rptr(struct amdgpu_ih_ring *ih) +{ +	u32 ih_doorbell_rtpr = 0; + +	if (ih->use_doorbell) { +		ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr, +						 IH_DOORBELL_RPTR, OFFSET, +						 ih->doorbell_index); +		ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr, +						 IH_DOORBELL_RPTR, +						 ENABLE, 1); +	} else { +		ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr, +						 IH_DOORBELL_RPTR, +						 ENABLE, 0); +	} +	return ih_doorbell_rtpr; +} + +static void navi10_ih_reroute_ih(struct amdgpu_device *adev) +{ +	uint32_t tmp; + +	/* 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 UMC */ +	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); +} +  /**   * navi10_ih_irq_init - init and enable the interrupt ring   * @@ -111,7 +237,7 @@ static uint32_t navi10_ih_rb_cntl(struct amdgpu_ih_ring *ih, uint32_t ih_rb_cntl  static int navi10_ih_irq_init(struct amdgpu_device *adev)  {  	struct amdgpu_ih_ring *ih = &adev->irq.ih; -	u32 ih_rb_cntl, ih_doorbell_rtpr, ih_chicken; +	u32 ih_rb_cntl, ih_chicken;  	u32 tmp;  	/* disable irqs */ @@ -127,6 +253,15 @@ static int navi10_ih_irq_init(struct amdgpu_device *adev)  	ih_rb_cntl = navi10_ih_rb_cntl(ih, ih_rb_cntl);  	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RPTR_REARM,  				   !!adev->irq.msi_enabled); +	if (amdgpu_sriov_vf(adev) && adev->asic_type < CHIP_NAVI10) { +		if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL, ih_rb_cntl)) { +			DRM_ERROR("PSP program IH_RB_CNTL failed!\n"); +			return -ETIMEDOUT; +		} +	} else { +		WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL, ih_rb_cntl); +	} +	navi10_ih_reroute_ih(adev);  	if (unlikely(adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT)) {  		if (ih->use_bus_addr) { @@ -137,8 +272,6 @@ static int navi10_ih_irq_init(struct amdgpu_device *adev)  		}  	} -	WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL, ih_rb_cntl); -  	/* set the writeback address whether it's enabled or not */  	WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_ADDR_LO,  		     lower_32_bits(ih->wptr_addr)); @@ -149,22 +282,68 @@ static int navi10_ih_irq_init(struct amdgpu_device *adev)  	WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR, 0);  	WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR, 0); -	ih_doorbell_rtpr = RREG32_SOC15(OSSSYS, 0, mmIH_DOORBELL_RPTR); -	if (ih->use_doorbell) { -		ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr, -						 IH_DOORBELL_RPTR, OFFSET, -						 ih->doorbell_index); -		ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr, -						 IH_DOORBELL_RPTR, ENABLE, 1); -	} else { -		ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr, -						 IH_DOORBELL_RPTR, ENABLE, 0); -	} -	WREG32_SOC15(OSSSYS, 0, mmIH_DOORBELL_RPTR, ih_doorbell_rtpr); +	WREG32_SOC15(OSSSYS, 0, mmIH_DOORBELL_RPTR, +			navi10_ih_doorbell_rptr(ih));  	adev->nbio.funcs->ih_doorbell_range(adev, ih->use_doorbell,  					    ih->doorbell_index); +	ih = &adev->irq.ih1; +	if (ih->ring_size) { +		WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE_RING1, ih->gpu_addr >> 8); +		WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE_HI_RING1, +			     (ih->gpu_addr >> 40) & 0xff); + +		ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1); +		ih_rb_cntl = navi10_ih_rb_cntl(ih, ih_rb_cntl); +		ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, +					   WPTR_OVERFLOW_ENABLE, 0); +		ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, +					   RB_FULL_DRAIN_ENABLE, 1); +		if (amdgpu_sriov_vf(adev) && adev->asic_type < CHIP_NAVI10) { +			if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL_RING1, +						ih_rb_cntl)) { +				DRM_ERROR("program IH_RB_CNTL_RING1 failed!\n"); +				return -ETIMEDOUT; +			} +		} else { +			WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1, ih_rb_cntl); +		} +		/* set rptr, wptr to 0 */ +		WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_RING1, 0); +		WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING1, 0); + +		WREG32_SOC15(OSSSYS, 0, mmIH_DOORBELL_RPTR_RING1, +				navi10_ih_doorbell_rptr(ih)); +	} + +	ih = &adev->irq.ih2; +	if (ih->ring_size) { +		WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE_RING2, ih->gpu_addr >> 8); +		WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE_HI_RING2, +			     (ih->gpu_addr >> 40) & 0xff); + +		ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2); +		ih_rb_cntl = navi10_ih_rb_cntl(ih, ih_rb_cntl); + +		if (amdgpu_sriov_vf(adev) && adev->asic_type < CHIP_NAVI10) { +			if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL_RING2, +						ih_rb_cntl)) { +				DRM_ERROR("program IH_RB_CNTL_RING2 failed!\n"); +				return -ETIMEDOUT; +			} +		} else { +			WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2, ih_rb_cntl); +		} +		/* set rptr, wptr to 0 */ +		WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_RING2, 0); +		WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING2, 0); + +		WREG32_SOC15(OSSSYS, 0, mmIH_DOORBELL_RPTR_RING2, +			     navi10_ih_doorbell_rptr(ih)); +	} + +  	tmp = RREG32_SOC15(OSSSYS, 0, mmIH_STORM_CLIENT_LIST_CNTL);  	tmp = REG_SET_FIELD(tmp, IH_STORM_CLIENT_LIST_CNTL,  			    CLIENT18_IS_STORM_CLIENT, 1); @@ -217,7 +396,15 @@ static u32 navi10_ih_get_wptr(struct amdgpu_device *adev,  	if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))  		goto out; -	reg = 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))  		goto out; @@ -233,7 +420,15 @@ static u32 navi10_ih_get_wptr(struct amdgpu_device *adev,  		 wptr, ih->rptr, tmp);  	ih->rptr = tmp; -	reg = 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);  	WREG32_NO_KIQ(reg, tmp); @@ -333,8 +528,52 @@ static void navi10_ih_set_rptr(struct amdgpu_device *adev,  		if (amdgpu_sriov_vf(adev))  			navi10_ih_irq_rearm(adev, ih); -	} else +	} else if (ih == &adev->irq.ih) {  		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); +	} +} + +/** + * navi10_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 navi10_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 navi10_ih_self_irq_funcs = { +	.process = navi10_ih_self_irq, +}; + +static void navi10_ih_set_self_irq_funcs(struct amdgpu_device *adev) +{ +	adev->irq.self_irq.num_types = 0; +	adev->irq.self_irq.funcs = &navi10_ih_self_irq_funcs;  }  static int navi10_ih_early_init(void *handle) @@ -342,6 +581,7 @@ static int navi10_ih_early_init(void *handle)  	struct amdgpu_device *adev = (struct amdgpu_device *)handle;  	navi10_ih_set_interrupt_funcs(adev); +	navi10_ih_set_self_irq_funcs(adev);  	return 0;  } @@ -351,6 +591,12 @@ static int navi10_ih_sw_init(void *handle)  	struct amdgpu_device *adev = (struct amdgpu_device *)handle;  	bool use_bus_addr; +	r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_IH, 0, +				&adev->irq.self_irq); + +	if (r) +		return r; +  	/* use gpu virtual address for ih ring  	 * until ih_checken is programmed to allow  	 * use bus address for ih ring by psp bl */ @@ -363,6 +609,20 @@ static int navi10_ih_sw_init(void *handle)  	adev->irq.ih.use_doorbell = true;  	adev->irq.ih.doorbell_index = adev->doorbell_index.ih << 1; +	r = amdgpu_ih_ring_init(adev, &adev->irq.ih1, PAGE_SIZE, true); +	if (r) +		return r; + +	adev->irq.ih1.use_doorbell = true; +	adev->irq.ih1.doorbell_index = (adev->doorbell_index.ih + 1) << 1; + +	r = amdgpu_ih_ring_init(adev, &adev->irq.ih2, PAGE_SIZE, true); +	if (r) +		return r; + +	adev->irq.ih2.use_doorbell = true; +	adev->irq.ih2.doorbell_index = (adev->doorbell_index.ih + 2) << 1; +  	r = amdgpu_irq_init(adev);  	return r; @@ -373,6 +633,8 @@ static int navi10_ih_sw_fini(void *handle)  	struct amdgpu_device *adev = (struct amdgpu_device *)handle;  	amdgpu_irq_fini(adev); +	amdgpu_ih_ring_fini(adev, &adev->irq.ih2); +	amdgpu_ih_ring_fini(adev, &adev->irq.ih1);  	amdgpu_ih_ring_fini(adev, &adev->irq.ih);  	return 0;  |