cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vega10_ih.c (17876B)


      1/*
      2 * Copyright 2016 Advanced Micro Devices, Inc.
      3 *
      4 * Permission is hereby granted, free of charge, to any person obtaining a
      5 * copy of this software and associated documentation files (the "Software"),
      6 * to deal in the Software without restriction, including without limitation
      7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8 * and/or sell copies of the Software, and to permit persons to whom the
      9 * Software is furnished to do so, subject to the following conditions:
     10 *
     11 * The above copyright notice and this permission notice shall be included in
     12 * all copies or substantial portions of the Software.
     13 *
     14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20 * OTHER DEALINGS IN THE SOFTWARE.
     21 *
     22 */
     23
     24#include <linux/pci.h>
     25
     26#include "amdgpu.h"
     27#include "amdgpu_ih.h"
     28#include "soc15.h"
     29
     30#include "oss/osssys_4_0_offset.h"
     31#include "oss/osssys_4_0_sh_mask.h"
     32
     33#include "soc15_common.h"
     34#include "vega10_ih.h"
     35
     36#define MAX_REARM_RETRY 10
     37
     38static void vega10_ih_set_interrupt_funcs(struct amdgpu_device *adev);
     39
     40/**
     41 * vega10_ih_init_register_offset - Initialize register offset for ih rings
     42 *
     43 * @adev: amdgpu_device pointer
     44 *
     45 * Initialize register offset ih rings (VEGA10).
     46 */
     47static void vega10_ih_init_register_offset(struct amdgpu_device *adev)
     48{
     49	struct amdgpu_ih_regs *ih_regs;
     50
     51	if (adev->irq.ih.ring_size) {
     52		ih_regs = &adev->irq.ih.ih_regs;
     53		ih_regs->ih_rb_base = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE);
     54		ih_regs->ih_rb_base_hi = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_HI);
     55		ih_regs->ih_rb_cntl = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL);
     56		ih_regs->ih_rb_wptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR);
     57		ih_regs->ih_rb_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_RPTR);
     58		ih_regs->ih_doorbell_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_DOORBELL_RPTR);
     59		ih_regs->ih_rb_wptr_addr_lo = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_ADDR_LO);
     60		ih_regs->ih_rb_wptr_addr_hi = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_ADDR_HI);
     61		ih_regs->psp_reg_id = PSP_REG_IH_RB_CNTL;
     62	}
     63
     64	if (adev->irq.ih1.ring_size) {
     65		ih_regs = &adev->irq.ih1.ih_regs;
     66		ih_regs->ih_rb_base = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_RING1);
     67		ih_regs->ih_rb_base_hi = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_HI_RING1);
     68		ih_regs->ih_rb_cntl = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL_RING1);
     69		ih_regs->ih_rb_wptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_RING1);
     70		ih_regs->ih_rb_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_RPTR_RING1);
     71		ih_regs->ih_doorbell_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_DOORBELL_RPTR_RING1);
     72		ih_regs->psp_reg_id = PSP_REG_IH_RB_CNTL_RING1;
     73	}
     74
     75	if (adev->irq.ih2.ring_size) {
     76		ih_regs = &adev->irq.ih2.ih_regs;
     77		ih_regs->ih_rb_base = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_RING2);
     78		ih_regs->ih_rb_base_hi = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_HI_RING2);
     79		ih_regs->ih_rb_cntl = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL_RING2);
     80		ih_regs->ih_rb_wptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_RING2);
     81		ih_regs->ih_rb_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_RPTR_RING2);
     82		ih_regs->ih_doorbell_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_DOORBELL_RPTR_RING2);
     83		ih_regs->psp_reg_id = PSP_REG_IH_RB_CNTL_RING2;
     84	}
     85}
     86
     87/**
     88 * vega10_ih_toggle_ring_interrupts - toggle the interrupt ring buffer
     89 *
     90 * @adev: amdgpu_device pointer
     91 * @ih: amdgpu_ih_ring pointet
     92 * @enable: true - enable the interrupts, false - disable the interrupts
     93 *
     94 * Toggle the interrupt ring buffer (VEGA10)
     95 */
     96static int vega10_ih_toggle_ring_interrupts(struct amdgpu_device *adev,
     97					    struct amdgpu_ih_ring *ih,
     98					    bool enable)
     99{
    100	struct amdgpu_ih_regs *ih_regs;
    101	uint32_t tmp;
    102
    103	ih_regs = &ih->ih_regs;
    104
    105	tmp = RREG32(ih_regs->ih_rb_cntl);
    106	tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, RB_ENABLE, (enable ? 1 : 0));
    107	tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, RB_GPU_TS_ENABLE, 1);
    108	/* enable_intr field is only valid in ring0 */
    109	if (ih == &adev->irq.ih)
    110		tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, ENABLE_INTR, (enable ? 1 : 0));
    111	if (amdgpu_sriov_vf(adev)) {
    112		if (psp_reg_program(&adev->psp, ih_regs->psp_reg_id, tmp)) {
    113			dev_err(adev->dev, "PSP program IH_RB_CNTL failed!\n");
    114			return -ETIMEDOUT;
    115		}
    116	} else {
    117		WREG32(ih_regs->ih_rb_cntl, tmp);
    118	}
    119
    120	if (enable) {
    121		ih->enabled = true;
    122	} else {
    123		/* set rptr, wptr to 0 */
    124		WREG32(ih_regs->ih_rb_rptr, 0);
    125		WREG32(ih_regs->ih_rb_wptr, 0);
    126		ih->enabled = false;
    127		ih->rptr = 0;
    128	}
    129
    130	return 0;
    131}
    132
    133/**
    134 * vega10_ih_toggle_interrupts - Toggle all the available interrupt ring buffers
    135 *
    136 * @adev: amdgpu_device pointer
    137 * @enable: enable or disable interrupt ring buffers
    138 *
    139 * Toggle all the available interrupt ring buffers (VEGA10).
    140 */
    141static int vega10_ih_toggle_interrupts(struct amdgpu_device *adev, bool enable)
    142{
    143	struct amdgpu_ih_ring *ih[] = {&adev->irq.ih, &adev->irq.ih1, &adev->irq.ih2};
    144	int i;
    145	int r;
    146
    147	for (i = 0; i < ARRAY_SIZE(ih); i++) {
    148		if (ih[i]->ring_size) {
    149			r = vega10_ih_toggle_ring_interrupts(adev, ih[i], enable);
    150			if (r)
    151				return r;
    152		}
    153	}
    154
    155	return 0;
    156}
    157
    158static uint32_t vega10_ih_rb_cntl(struct amdgpu_ih_ring *ih, uint32_t ih_rb_cntl)
    159{
    160	int rb_bufsz = order_base_2(ih->ring_size / 4);
    161
    162	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL,
    163				   MC_SPACE, ih->use_bus_addr ? 1 : 4);
    164	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL,
    165				   WPTR_OVERFLOW_CLEAR, 1);
    166	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL,
    167				   WPTR_OVERFLOW_ENABLE, 1);
    168	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RB_SIZE, rb_bufsz);
    169	/* Ring Buffer write pointer writeback. If enabled, IH_RB_WPTR register
    170	 * value is written to memory
    171	 */
    172	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL,
    173				   WPTR_WRITEBACK_ENABLE, 1);
    174	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_SNOOP, 1);
    175	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_RO, 0);
    176	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_VMID, 0);
    177
    178	return ih_rb_cntl;
    179}
    180
    181static uint32_t vega10_ih_doorbell_rptr(struct amdgpu_ih_ring *ih)
    182{
    183	u32 ih_doorbell_rtpr = 0;
    184
    185	if (ih->use_doorbell) {
    186		ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr,
    187						 IH_DOORBELL_RPTR, OFFSET,
    188						 ih->doorbell_index);
    189		ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr,
    190						 IH_DOORBELL_RPTR,
    191						 ENABLE, 1);
    192	} else {
    193		ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr,
    194						 IH_DOORBELL_RPTR,
    195						 ENABLE, 0);
    196	}
    197	return ih_doorbell_rtpr;
    198}
    199
    200/**
    201 * vega10_ih_enable_ring - enable an ih ring buffer
    202 *
    203 * @adev: amdgpu_device pointer
    204 * @ih: amdgpu_ih_ring pointer
    205 *
    206 * Enable an ih ring buffer (VEGA10)
    207 */
    208static int vega10_ih_enable_ring(struct amdgpu_device *adev,
    209				 struct amdgpu_ih_ring *ih)
    210{
    211	struct amdgpu_ih_regs *ih_regs;
    212	uint32_t tmp;
    213
    214	ih_regs = &ih->ih_regs;
    215
    216	/* Ring Buffer base. [39:8] of 40-bit address of the beginning of the ring buffer*/
    217	WREG32(ih_regs->ih_rb_base, ih->gpu_addr >> 8);
    218	WREG32(ih_regs->ih_rb_base_hi, (ih->gpu_addr >> 40) & 0xff);
    219
    220	tmp = RREG32(ih_regs->ih_rb_cntl);
    221	tmp = vega10_ih_rb_cntl(ih, tmp);
    222	if (ih == &adev->irq.ih)
    223		tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, RPTR_REARM, !!adev->irq.msi_enabled);
    224	if (ih == &adev->irq.ih1)
    225		tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, RB_FULL_DRAIN_ENABLE, 1);
    226	if (amdgpu_sriov_vf(adev)) {
    227		if (psp_reg_program(&adev->psp, ih_regs->psp_reg_id, tmp)) {
    228			dev_err(adev->dev, "PSP program IH_RB_CNTL failed!\n");
    229			return -ETIMEDOUT;
    230		}
    231	} else {
    232		WREG32(ih_regs->ih_rb_cntl, tmp);
    233	}
    234
    235	if (ih == &adev->irq.ih) {
    236		/* set the ih ring 0 writeback address whether it's enabled or not */
    237		WREG32(ih_regs->ih_rb_wptr_addr_lo, lower_32_bits(ih->wptr_addr));
    238		WREG32(ih_regs->ih_rb_wptr_addr_hi, upper_32_bits(ih->wptr_addr) & 0xFFFF);
    239	}
    240
    241	/* set rptr, wptr to 0 */
    242	WREG32(ih_regs->ih_rb_wptr, 0);
    243	WREG32(ih_regs->ih_rb_rptr, 0);
    244
    245	WREG32(ih_regs->ih_doorbell_rptr, vega10_ih_doorbell_rptr(ih));
    246
    247	return 0;
    248}
    249
    250/**
    251 * vega10_ih_irq_init - init and enable the interrupt ring
    252 *
    253 * @adev: amdgpu_device pointer
    254 *
    255 * Allocate a ring buffer for the interrupt controller,
    256 * enable the RLC, disable interrupts, enable the IH
    257 * ring buffer and enable it (VI).
    258 * Called at device load and reume.
    259 * Returns 0 for success, errors for failure.
    260 */
    261static int vega10_ih_irq_init(struct amdgpu_device *adev)
    262{
    263	struct amdgpu_ih_ring *ih[] = {&adev->irq.ih, &adev->irq.ih1, &adev->irq.ih2};
    264	u32 ih_chicken;
    265	int ret;
    266	int i;
    267
    268	/* disable irqs */
    269	ret = vega10_ih_toggle_interrupts(adev, false);
    270	if (ret)
    271		return ret;
    272
    273	adev->nbio.funcs->ih_control(adev);
    274
    275	if (adev->asic_type == CHIP_RENOIR) {
    276		ih_chicken = RREG32_SOC15(OSSSYS, 0, mmIH_CHICKEN);
    277		if (adev->irq.ih.use_bus_addr) {
    278			ih_chicken = REG_SET_FIELD(ih_chicken, IH_CHICKEN,
    279						   MC_SPACE_GPA_ENABLE, 1);
    280		}
    281		WREG32_SOC15(OSSSYS, 0, mmIH_CHICKEN, ih_chicken);
    282	}
    283
    284	for (i = 0; i < ARRAY_SIZE(ih); i++) {
    285		if (ih[i]->ring_size) {
    286			ret = vega10_ih_enable_ring(adev, ih[i]);
    287			if (ret)
    288				return ret;
    289		}
    290	}
    291
    292	pci_set_master(adev->pdev);
    293
    294	/* enable interrupts */
    295	ret = vega10_ih_toggle_interrupts(adev, true);
    296	if (ret)
    297		return ret;
    298
    299	if (adev->irq.ih_soft.ring_size)
    300		adev->irq.ih_soft.enabled = true;
    301
    302	return 0;
    303}
    304
    305/**
    306 * vega10_ih_irq_disable - disable interrupts
    307 *
    308 * @adev: amdgpu_device pointer
    309 *
    310 * Disable interrupts on the hw (VEGA10).
    311 */
    312static void vega10_ih_irq_disable(struct amdgpu_device *adev)
    313{
    314	vega10_ih_toggle_interrupts(adev, false);
    315
    316	/* Wait and acknowledge irq */
    317	mdelay(1);
    318}
    319
    320/**
    321 * vega10_ih_get_wptr - get the IH ring buffer wptr
    322 *
    323 * @adev: amdgpu_device pointer
    324 * @ih: IH ring buffer to fetch wptr
    325 *
    326 * Get the IH ring buffer wptr from either the register
    327 * or the writeback memory buffer (VEGA10).  Also check for
    328 * ring buffer overflow and deal with it.
    329 * Returns the value of the wptr.
    330 */
    331static u32 vega10_ih_get_wptr(struct amdgpu_device *adev,
    332			      struct amdgpu_ih_ring *ih)
    333{
    334	u32 wptr, tmp;
    335	struct amdgpu_ih_regs *ih_regs;
    336
    337	if (ih == &adev->irq.ih) {
    338		/* Only ring0 supports writeback. On other rings fall back
    339		 * to register-based code with overflow checking below.
    340		 */
    341		wptr = le32_to_cpu(*ih->wptr_cpu);
    342
    343		if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
    344			goto out;
    345	}
    346
    347	ih_regs = &ih->ih_regs;
    348
    349	/* Double check that the overflow wasn't already cleared. */
    350	wptr = RREG32_NO_KIQ(ih_regs->ih_rb_wptr);
    351	if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
    352		goto out;
    353
    354	wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0);
    355
    356	/* When a ring buffer overflow happen start parsing interrupt
    357	 * from the last not overwritten vector (wptr + 32). Hopefully
    358	 * this should allow us to catchup.
    359	 */
    360	tmp = (wptr + 32) & ih->ptr_mask;
    361	dev_warn(adev->dev, "IH ring buffer overflow "
    362		 "(0x%08X, 0x%08X, 0x%08X)\n",
    363		 wptr, ih->rptr, tmp);
    364	ih->rptr = tmp;
    365
    366	tmp = RREG32_NO_KIQ(ih_regs->ih_rb_cntl);
    367	tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
    368	WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp);
    369
    370out:
    371	return (wptr & ih->ptr_mask);
    372}
    373
    374/**
    375 * vega10_ih_irq_rearm - rearm IRQ if lost
    376 *
    377 * @adev: amdgpu_device pointer
    378 * @ih: IH ring to match
    379 *
    380 */
    381static void vega10_ih_irq_rearm(struct amdgpu_device *adev,
    382			       struct amdgpu_ih_ring *ih)
    383{
    384	uint32_t v = 0;
    385	uint32_t i = 0;
    386	struct amdgpu_ih_regs *ih_regs;
    387
    388	ih_regs = &ih->ih_regs;
    389	/* Rearm IRQ / re-wwrite doorbell if doorbell write is lost */
    390	for (i = 0; i < MAX_REARM_RETRY; i++) {
    391		v = RREG32_NO_KIQ(ih_regs->ih_rb_rptr);
    392		if ((v < ih->ring_size) && (v != ih->rptr))
    393			WDOORBELL32(ih->doorbell_index, ih->rptr);
    394		else
    395			break;
    396	}
    397}
    398
    399/**
    400 * vega10_ih_set_rptr - set the IH ring buffer rptr
    401 *
    402 * @adev: amdgpu_device pointer
    403 * @ih: IH ring buffer to set rptr
    404 *
    405 * Set the IH ring buffer rptr.
    406 */
    407static void vega10_ih_set_rptr(struct amdgpu_device *adev,
    408			       struct amdgpu_ih_ring *ih)
    409{
    410	struct amdgpu_ih_regs *ih_regs;
    411
    412	if (ih->use_doorbell) {
    413		/* XXX check if swapping is necessary on BE */
    414		*ih->rptr_cpu = ih->rptr;
    415		WDOORBELL32(ih->doorbell_index, ih->rptr);
    416
    417		if (amdgpu_sriov_vf(adev))
    418			vega10_ih_irq_rearm(adev, ih);
    419	} else {
    420		ih_regs = &ih->ih_regs;
    421		WREG32(ih_regs->ih_rb_rptr, ih->rptr);
    422	}
    423}
    424
    425/**
    426 * vega10_ih_self_irq - dispatch work for ring 1 and 2
    427 *
    428 * @adev: amdgpu_device pointer
    429 * @source: irq source
    430 * @entry: IV with WPTR update
    431 *
    432 * Update the WPTR from the IV and schedule work to handle the entries.
    433 */
    434static int vega10_ih_self_irq(struct amdgpu_device *adev,
    435			      struct amdgpu_irq_src *source,
    436			      struct amdgpu_iv_entry *entry)
    437{
    438	switch (entry->ring_id) {
    439	case 1:
    440		schedule_work(&adev->irq.ih1_work);
    441		break;
    442	case 2:
    443		schedule_work(&adev->irq.ih2_work);
    444		break;
    445	default: break;
    446	}
    447	return 0;
    448}
    449
    450static const struct amdgpu_irq_src_funcs vega10_ih_self_irq_funcs = {
    451	.process = vega10_ih_self_irq,
    452};
    453
    454static void vega10_ih_set_self_irq_funcs(struct amdgpu_device *adev)
    455{
    456	adev->irq.self_irq.num_types = 0;
    457	adev->irq.self_irq.funcs = &vega10_ih_self_irq_funcs;
    458}
    459
    460static int vega10_ih_early_init(void *handle)
    461{
    462	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
    463
    464	vega10_ih_set_interrupt_funcs(adev);
    465	vega10_ih_set_self_irq_funcs(adev);
    466	return 0;
    467}
    468
    469static int vega10_ih_sw_init(void *handle)
    470{
    471	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
    472	int r;
    473
    474	r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_IH, 0,
    475			      &adev->irq.self_irq);
    476	if (r)
    477		return r;
    478
    479	r = amdgpu_ih_ring_init(adev, &adev->irq.ih, 256 * 1024, true);
    480	if (r)
    481		return r;
    482
    483	adev->irq.ih.use_doorbell = true;
    484	adev->irq.ih.doorbell_index = adev->doorbell_index.ih << 1;
    485
    486	if (!(adev->flags & AMD_IS_APU)) {
    487		r = amdgpu_ih_ring_init(adev, &adev->irq.ih1, PAGE_SIZE, true);
    488		if (r)
    489			return r;
    490
    491		adev->irq.ih1.use_doorbell = true;
    492		adev->irq.ih1.doorbell_index = (adev->doorbell_index.ih + 1) << 1;
    493
    494		r = amdgpu_ih_ring_init(adev, &adev->irq.ih2, PAGE_SIZE, true);
    495		if (r)
    496			return r;
    497
    498		adev->irq.ih2.use_doorbell = true;
    499		adev->irq.ih2.doorbell_index = (adev->doorbell_index.ih + 2) << 1;
    500	}
    501	/* initialize ih control registers offset */
    502	vega10_ih_init_register_offset(adev);
    503
    504	r = amdgpu_ih_ring_init(adev, &adev->irq.ih_soft, PAGE_SIZE, true);
    505	if (r)
    506		return r;
    507
    508	r = amdgpu_irq_init(adev);
    509
    510	return r;
    511}
    512
    513static int vega10_ih_sw_fini(void *handle)
    514{
    515	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
    516
    517	amdgpu_irq_fini_sw(adev);
    518
    519	return 0;
    520}
    521
    522static int vega10_ih_hw_init(void *handle)
    523{
    524	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
    525
    526	return vega10_ih_irq_init(adev);
    527}
    528
    529static int vega10_ih_hw_fini(void *handle)
    530{
    531	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
    532
    533	vega10_ih_irq_disable(adev);
    534
    535	return 0;
    536}
    537
    538static int vega10_ih_suspend(void *handle)
    539{
    540	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
    541
    542	return vega10_ih_hw_fini(adev);
    543}
    544
    545static int vega10_ih_resume(void *handle)
    546{
    547	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
    548
    549	return vega10_ih_hw_init(adev);
    550}
    551
    552static bool vega10_ih_is_idle(void *handle)
    553{
    554	/* todo */
    555	return true;
    556}
    557
    558static int vega10_ih_wait_for_idle(void *handle)
    559{
    560	/* todo */
    561	return -ETIMEDOUT;
    562}
    563
    564static int vega10_ih_soft_reset(void *handle)
    565{
    566	/* todo */
    567
    568	return 0;
    569}
    570
    571static void vega10_ih_update_clockgating_state(struct amdgpu_device *adev,
    572					       bool enable)
    573{
    574	uint32_t data, def, field_val;
    575
    576	if (adev->cg_flags & AMD_CG_SUPPORT_IH_CG) {
    577		def = data = RREG32_SOC15(OSSSYS, 0, mmIH_CLK_CTRL);
    578		field_val = enable ? 0 : 1;
    579		/**
    580		 * Vega10/12 and RAVEN don't have IH_BUFFER_MEM_CLK_SOFT_OVERRIDE field.
    581		 */
    582		if (adev->asic_type == CHIP_RENOIR)
    583			data = REG_SET_FIELD(data, IH_CLK_CTRL,
    584				     IH_BUFFER_MEM_CLK_SOFT_OVERRIDE, field_val);
    585
    586		data = REG_SET_FIELD(data, IH_CLK_CTRL,
    587				     DBUS_MUX_CLK_SOFT_OVERRIDE, field_val);
    588		data = REG_SET_FIELD(data, IH_CLK_CTRL,
    589				     OSSSYS_SHARE_CLK_SOFT_OVERRIDE, field_val);
    590		data = REG_SET_FIELD(data, IH_CLK_CTRL,
    591				     LIMIT_SMN_CLK_SOFT_OVERRIDE, field_val);
    592		data = REG_SET_FIELD(data, IH_CLK_CTRL,
    593				     DYN_CLK_SOFT_OVERRIDE, field_val);
    594		data = REG_SET_FIELD(data, IH_CLK_CTRL,
    595				     REG_CLK_SOFT_OVERRIDE, field_val);
    596		if (def != data)
    597			WREG32_SOC15(OSSSYS, 0, mmIH_CLK_CTRL, data);
    598	}
    599}
    600
    601static int vega10_ih_set_clockgating_state(void *handle,
    602					  enum amd_clockgating_state state)
    603{
    604	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
    605
    606	vega10_ih_update_clockgating_state(adev,
    607				state == AMD_CG_STATE_GATE);
    608	return 0;
    609
    610}
    611
    612static int vega10_ih_set_powergating_state(void *handle,
    613					  enum amd_powergating_state state)
    614{
    615	return 0;
    616}
    617
    618const struct amd_ip_funcs vega10_ih_ip_funcs = {
    619	.name = "vega10_ih",
    620	.early_init = vega10_ih_early_init,
    621	.late_init = NULL,
    622	.sw_init = vega10_ih_sw_init,
    623	.sw_fini = vega10_ih_sw_fini,
    624	.hw_init = vega10_ih_hw_init,
    625	.hw_fini = vega10_ih_hw_fini,
    626	.suspend = vega10_ih_suspend,
    627	.resume = vega10_ih_resume,
    628	.is_idle = vega10_ih_is_idle,
    629	.wait_for_idle = vega10_ih_wait_for_idle,
    630	.soft_reset = vega10_ih_soft_reset,
    631	.set_clockgating_state = vega10_ih_set_clockgating_state,
    632	.set_powergating_state = vega10_ih_set_powergating_state,
    633};
    634
    635static const struct amdgpu_ih_funcs vega10_ih_funcs = {
    636	.get_wptr = vega10_ih_get_wptr,
    637	.decode_iv = amdgpu_ih_decode_iv_helper,
    638	.decode_iv_ts = amdgpu_ih_decode_iv_ts_helper,
    639	.set_rptr = vega10_ih_set_rptr
    640};
    641
    642static void vega10_ih_set_interrupt_funcs(struct amdgpu_device *adev)
    643{
    644	adev->irq.ih_funcs = &vega10_ih_funcs;
    645}
    646
    647const struct amdgpu_ip_block_version vega10_ih_ip_block =
    648{
    649	.type = AMD_IP_BLOCK_TYPE_IH,
    650	.major = 4,
    651	.minor = 0,
    652	.rev = 0,
    653	.funcs = &vega10_ih_ip_funcs,
    654};