diff options
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/vega10_ih.c')
| -rw-r--r-- | drivers/gpu/drm/amd/amdgpu/vega10_ih.c | 324 | 
1 files changed, 243 insertions, 81 deletions
| diff --git a/drivers/gpu/drm/amd/amdgpu/vega10_ih.c b/drivers/gpu/drm/amd/amdgpu/vega10_ih.c index 2c250b01a903..6d1f804277f8 100644 --- a/drivers/gpu/drm/amd/amdgpu/vega10_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/vega10_ih.c @@ -50,6 +50,22 @@ static void vega10_ih_enable_interrupts(struct amdgpu_device *adev)  	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);  	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); +		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); +		WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2, ih_rb_cntl); +		adev->irq.ih2.enabled = true; +	}  }  /** @@ -71,6 +87,53 @@ static void vega10_ih_disable_interrupts(struct amdgpu_device *adev)  	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); +		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); +		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 vega10_ih_rb_cntl(struct amdgpu_ih_ring *ih, uint32_t ih_rb_cntl) +{ +	int rb_bufsz = order_base_2(ih->ring_size / 4); + +	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, +				   MC_SPACE, ih->use_bus_addr ? 1 : 4); +	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, +				   WPTR_OVERFLOW_CLEAR, 1); +	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, +				   WPTR_OVERFLOW_ENABLE, 1); +	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RB_SIZE, rb_bufsz); +	/* Ring Buffer write pointer writeback. If enabled, IH_RB_WPTR register +	 * value is written to memory +	 */ +	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, +				   WPTR_WRITEBACK_ENABLE, 1); +	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_SNOOP, 1); +	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_RO, 0); +	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_VMID, 0); + +	return ih_rb_cntl;  }  /** @@ -86,50 +149,32 @@ static void vega10_ih_disable_interrupts(struct amdgpu_device *adev)   */  static int vega10_ih_irq_init(struct amdgpu_device *adev)  { +	struct amdgpu_ih_ring *ih;  	int ret = 0; -	int rb_bufsz;  	u32 ih_rb_cntl, ih_doorbell_rtpr;  	u32 tmp; -	u64 wptr_off;  	/* disable irqs */  	vega10_ih_disable_interrupts(adev);  	adev->nbio_funcs->ih_control(adev); -	ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL); +	ih = &adev->irq.ih;  	/* Ring Buffer base. [39:8] of 40-bit address of the beginning of the ring buffer*/ -	if (adev->irq.ih.use_bus_addr) { -		WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE, adev->irq.ih.rb_dma_addr >> 8); -		WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE_HI, ((u64)adev->irq.ih.rb_dma_addr >> 40) & 0xff); -		ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_SPACE, 1); -	} else { -		WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE, adev->irq.ih.gpu_addr >> 8); -		WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE_HI, (adev->irq.ih.gpu_addr >> 40) & 0xff); -		ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_SPACE, 4); -	} -	rb_bufsz = order_base_2(adev->irq.ih.ring_size / 4); -	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); -	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, WPTR_OVERFLOW_ENABLE, 1); -	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RB_SIZE, rb_bufsz); -	/* Ring Buffer write pointer writeback. If enabled, IH_RB_WPTR register value is written to memory */ -	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, WPTR_WRITEBACK_ENABLE, 1); -	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_SNOOP, 1); -	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_RO, 0); -	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_VMID, 0); - -	if (adev->irq.msi_enabled) -		ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RPTR_REARM, 1); +	WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE, ih->gpu_addr >> 8); +	WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE_HI, (ih->gpu_addr >> 40) & 0xff); +	ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL); +	ih_rb_cntl = vega10_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);  	WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL, ih_rb_cntl);  	/* set the writeback address whether it's enabled or not */ -	if (adev->irq.ih.use_bus_addr) -		wptr_off = adev->irq.ih.rb_dma_addr + (adev->irq.ih.wptr_offs * 4); -	else -		wptr_off = adev->wb.gpu_addr + (adev->irq.ih.wptr_offs * 4); -	WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_ADDR_LO, lower_32_bits(wptr_off)); -	WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_ADDR_HI, upper_32_bits(wptr_off) & 0xFFFF); +	WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_ADDR_LO, +		     lower_32_bits(ih->wptr_addr)); +	WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_ADDR_HI, +		     upper_32_bits(ih->wptr_addr) & 0xFFFF);  	/* set rptr, wptr to 0 */  	WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR, 0); @@ -137,17 +182,48 @@ static int vega10_ih_irq_init(struct amdgpu_device *adev)  	ih_doorbell_rtpr = RREG32_SOC15(OSSSYS, 0, mmIH_DOORBELL_RPTR);  	if (adev->irq.ih.use_doorbell) { -		ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr, IH_DOORBELL_RPTR, -						 OFFSET, adev->irq.ih.doorbell_index); -		ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr, IH_DOORBELL_RPTR, +		ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr, +						 IH_DOORBELL_RPTR, OFFSET, +						 adev->irq.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, +		ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr, +						 IH_DOORBELL_RPTR,  						 ENABLE, 0);  	}  	WREG32_SOC15(OSSSYS, 0, mmIH_DOORBELL_RPTR, ih_doorbell_rtpr); -	adev->nbio_funcs->ih_doorbell_range(adev, adev->irq.ih.use_doorbell, -					    adev->irq.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 = vega10_ih_rb_cntl(ih, ih_rb_cntl); +		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); +	} + +	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_RING1); +		ih_rb_cntl = vega10_ih_rb_cntl(ih, ih_rb_cntl); +		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); +	}  	tmp = RREG32_SOC15(OSSSYS, 0, mmIH_STORM_CLIENT_LIST_CNTL);  	tmp = REG_SET_FIELD(tmp, IH_STORM_CLIENT_LIST_CNTL, @@ -191,32 +267,58 @@ static void vega10_ih_irq_disable(struct amdgpu_device *adev)   * ring buffer overflow and deal with it.   * Returns the value of the wptr.   */ -static u32 vega10_ih_get_wptr(struct amdgpu_device *adev) +static u32 vega10_ih_get_wptr(struct amdgpu_device *adev, +			      struct amdgpu_ih_ring *ih)  { -	u32 wptr, tmp; +	u32 wptr, reg, tmp; -	if (adev->irq.ih.use_bus_addr) -		wptr = le32_to_cpu(adev->irq.ih.ring[adev->irq.ih.wptr_offs]); +	wptr = le32_to_cpu(*ih->wptr_cpu); + +	if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW)) +		goto out; + +	/* Double check that the overflow wasn't already cleared. */ + +	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 -		wptr = le32_to_cpu(adev->wb.wb[adev->irq.ih.wptr_offs]); - -	if (REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW)) { -		wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0); - -		/* When a ring buffer overflow happen start parsing interrupt -		 * from the last not overwritten vector (wptr + 32). Hopefully -		 * this should allow us to catchup. -		 */ -		tmp = (wptr + 32) & adev->irq.ih.ptr_mask; -		dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n", -			wptr, adev->irq.ih.rptr, tmp); -		adev->irq.ih.rptr = tmp; - -		tmp = RREG32_NO_KIQ(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL)); -		tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); -		WREG32_NO_KIQ(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL), tmp); -	} -	return (wptr & adev->irq.ih.ptr_mask); +		BUG(); + +	wptr = RREG32_NO_KIQ(reg); +	if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW)) +		goto out; + +	wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0); + +	/* When a ring buffer overflow happen start parsing interrupt +	 * from the last not overwritten vector (wptr + 32). Hopefully +	 * this should allow us to catchup. +	 */ +	tmp = (wptr + 32) & ih->ptr_mask; +	dev_warn(adev->dev, "IH ring buffer overflow " +		 "(0x%08X, 0x%08X, 0x%08X)\n", +		 wptr, ih->rptr, tmp); +	ih->rptr = tmp; + +	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); + +out: +	return (wptr & ih->ptr_mask);  }  /** @@ -228,20 +330,21 @@ static u32 vega10_ih_get_wptr(struct amdgpu_device *adev)   * position and also advance the position.   */  static void vega10_ih_decode_iv(struct amdgpu_device *adev, -				 struct amdgpu_iv_entry *entry) +				struct amdgpu_ih_ring *ih, +				struct amdgpu_iv_entry *entry)  {  	/* wptr/rptr are in bytes! */ -	u32 ring_index = adev->irq.ih.rptr >> 2; +	u32 ring_index = ih->rptr >> 2;  	uint32_t dw[8]; -	dw[0] = le32_to_cpu(adev->irq.ih.ring[ring_index + 0]); -	dw[1] = le32_to_cpu(adev->irq.ih.ring[ring_index + 1]); -	dw[2] = le32_to_cpu(adev->irq.ih.ring[ring_index + 2]); -	dw[3] = le32_to_cpu(adev->irq.ih.ring[ring_index + 3]); -	dw[4] = le32_to_cpu(adev->irq.ih.ring[ring_index + 4]); -	dw[5] = le32_to_cpu(adev->irq.ih.ring[ring_index + 5]); -	dw[6] = le32_to_cpu(adev->irq.ih.ring[ring_index + 6]); -	dw[7] = le32_to_cpu(adev->irq.ih.ring[ring_index + 7]); +	dw[0] = le32_to_cpu(ih->ring[ring_index + 0]); +	dw[1] = le32_to_cpu(ih->ring[ring_index + 1]); +	dw[2] = le32_to_cpu(ih->ring[ring_index + 2]); +	dw[3] = le32_to_cpu(ih->ring[ring_index + 3]); +	dw[4] = le32_to_cpu(ih->ring[ring_index + 4]); +	dw[5] = le32_to_cpu(ih->ring[ring_index + 5]); +	dw[6] = le32_to_cpu(ih->ring[ring_index + 6]); +	dw[7] = le32_to_cpu(ih->ring[ring_index + 7]);  	entry->client_id = dw[0] & 0xff;  	entry->src_id = (dw[0] >> 8) & 0xff; @@ -257,9 +360,8 @@ static void vega10_ih_decode_iv(struct amdgpu_device *adev,  	entry->src_data[2] = dw[6];  	entry->src_data[3] = dw[7]; -  	/* wptr/rptr are in bytes! */ -	adev->irq.ih.rptr += 32; +	ih->rptr += 32;  }  /** @@ -269,37 +371,95 @@ static void vega10_ih_decode_iv(struct amdgpu_device *adev,   *   * Set the IH ring buffer rptr.   */ -static void vega10_ih_set_rptr(struct amdgpu_device *adev) +static void vega10_ih_set_rptr(struct amdgpu_device *adev, +			       struct amdgpu_ih_ring *ih)  { -	if (adev->irq.ih.use_doorbell) { +	if (ih->use_doorbell) {  		/* XXX check if swapping is necessary on BE */ -		if (adev->irq.ih.use_bus_addr) -			adev->irq.ih.ring[adev->irq.ih.rptr_offs] = adev->irq.ih.rptr; -		else -			adev->wb.wb[adev->irq.ih.rptr_offs] = adev->irq.ih.rptr; -		WDOORBELL32(adev->irq.ih.doorbell_index, adev->irq.ih.rptr); -	} else { -		WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR, adev->irq.ih.rptr); +		*ih->rptr_cpu = ih->rptr; +		WDOORBELL32(ih->doorbell_index, ih->rptr); +	} 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);  	}  } +/** + * vega10_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 vega10_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 vega10_ih_self_irq_funcs = { +	.process = vega10_ih_self_irq, +}; + +static void vega10_ih_set_self_irq_funcs(struct amdgpu_device *adev) +{ +	adev->irq.self_irq.num_types = 0; +	adev->irq.self_irq.funcs = &vega10_ih_self_irq_funcs; +} +  static int vega10_ih_early_init(void *handle)  {  	struct amdgpu_device *adev = (struct amdgpu_device *)handle;  	vega10_ih_set_interrupt_funcs(adev); +	vega10_ih_set_self_irq_funcs(adev);  	return 0;  }  static int vega10_ih_sw_init(void *handle)  { -	int r;  	struct amdgpu_device *adev = (struct amdgpu_device *)handle; +	int r; + +	r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_IH, 0, +			      &adev->irq.self_irq); +	if (r) +		return r;  	r = amdgpu_ih_ring_init(adev, &adev->irq.ih, 256 * 1024, true);  	if (r)  		return r; +	if (adev->asic_type == CHIP_VEGA10) { +		r = amdgpu_ih_ring_init(adev, &adev->irq.ih1, PAGE_SIZE, true); +		if (r) +			return r; + +		r = amdgpu_ih_ring_init(adev, &adev->irq.ih2, PAGE_SIZE, true); +		if (r) +			return r; +	} + +	/* TODO add doorbell for IH1 & IH2 as well */  	adev->irq.ih.use_doorbell = true;  	adev->irq.ih.doorbell_index = adev->doorbell_index.ih << 1; @@ -313,6 +473,8 @@ static int vega10_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; | 
