Home | History | Annotate | Line # | Download | only in amdgpu
      1 /*	$NetBSD: amdgpu_si_ih.c,v 1.2 2021/12/18 23:44:58 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright 2015 Advanced Micro Devices, Inc.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     22  * OTHER DEALINGS IN THE SOFTWARE.
     23  *
     24  */
     25 
     26 #include <sys/cdefs.h>
     27 __KERNEL_RCSID(0, "$NetBSD: amdgpu_si_ih.c,v 1.2 2021/12/18 23:44:58 riastradh Exp $");
     28 
     29 #include <linux/pci.h>
     30 
     31 #include "amdgpu.h"
     32 #include "amdgpu_ih.h"
     33 #include "sid.h"
     34 #include "si_ih.h"
     35 
     36 static void si_ih_set_interrupt_funcs(struct amdgpu_device *adev);
     37 
     38 static void si_ih_enable_interrupts(struct amdgpu_device *adev)
     39 {
     40 	u32 ih_cntl = RREG32(IH_CNTL);
     41 	u32 ih_rb_cntl = RREG32(IH_RB_CNTL);
     42 
     43 	ih_cntl |= ENABLE_INTR;
     44 	ih_rb_cntl |= IH_RB_ENABLE;
     45 	WREG32(IH_CNTL, ih_cntl);
     46 	WREG32(IH_RB_CNTL, ih_rb_cntl);
     47 	adev->irq.ih.enabled = true;
     48 }
     49 
     50 static void si_ih_disable_interrupts(struct amdgpu_device *adev)
     51 {
     52 	u32 ih_rb_cntl = RREG32(IH_RB_CNTL);
     53 	u32 ih_cntl = RREG32(IH_CNTL);
     54 
     55 	ih_rb_cntl &= ~IH_RB_ENABLE;
     56 	ih_cntl &= ~ENABLE_INTR;
     57 	WREG32(IH_RB_CNTL, ih_rb_cntl);
     58 	WREG32(IH_CNTL, ih_cntl);
     59 	WREG32(IH_RB_RPTR, 0);
     60 	WREG32(IH_RB_WPTR, 0);
     61 	adev->irq.ih.enabled = false;
     62 	adev->irq.ih.rptr = 0;
     63 }
     64 
     65 static int si_ih_irq_init(struct amdgpu_device *adev)
     66 {
     67 	struct amdgpu_ih_ring *ih = &adev->irq.ih;
     68 	int rb_bufsz;
     69 	u32 interrupt_cntl, ih_cntl, ih_rb_cntl;
     70 
     71 	si_ih_disable_interrupts(adev);
     72 	/* set dummy read address to dummy page address */
     73 	WREG32(INTERRUPT_CNTL2, adev->dummy_page_addr >> 8);
     74 	interrupt_cntl = RREG32(INTERRUPT_CNTL);
     75 	interrupt_cntl &= ~IH_DUMMY_RD_OVERRIDE;
     76 	interrupt_cntl &= ~IH_REQ_NONSNOOP_EN;
     77 	WREG32(INTERRUPT_CNTL, interrupt_cntl);
     78 
     79 	WREG32(IH_RB_BASE, adev->irq.ih.gpu_addr >> 8);
     80 	rb_bufsz = order_base_2(adev->irq.ih.ring_size / 4);
     81 
     82 	ih_rb_cntl = IH_WPTR_OVERFLOW_ENABLE |
     83 		     IH_WPTR_OVERFLOW_CLEAR |
     84 		     (rb_bufsz << 1) |
     85 		     IH_WPTR_WRITEBACK_ENABLE;
     86 
     87 	WREG32(IH_RB_WPTR_ADDR_LO, lower_32_bits(ih->wptr_addr));
     88 	WREG32(IH_RB_WPTR_ADDR_HI, upper_32_bits(ih->wptr_addr) & 0xFF);
     89 	WREG32(IH_RB_CNTL, ih_rb_cntl);
     90 	WREG32(IH_RB_RPTR, 0);
     91 	WREG32(IH_RB_WPTR, 0);
     92 
     93 	ih_cntl = MC_WRREQ_CREDIT(0x10) | MC_WR_CLEAN_CNT(0x10) | MC_VMID(0);
     94 	if (adev->irq.msi_enabled)
     95 		ih_cntl |= RPTR_REARM;
     96 	WREG32(IH_CNTL, ih_cntl);
     97 
     98 	pci_set_master(adev->pdev);
     99 	si_ih_enable_interrupts(adev);
    100 
    101 	return 0;
    102 }
    103 
    104 static void si_ih_irq_disable(struct amdgpu_device *adev)
    105 {
    106 	si_ih_disable_interrupts(adev);
    107 	mdelay(1);
    108 }
    109 
    110 static u32 si_ih_get_wptr(struct amdgpu_device *adev,
    111 			  struct amdgpu_ih_ring *ih)
    112 {
    113 	u32 wptr, tmp;
    114 
    115 	wptr = le32_to_cpu(*ih->wptr_cpu);
    116 
    117 	if (wptr & IH_RB_WPTR__RB_OVERFLOW_MASK) {
    118 		wptr &= ~IH_RB_WPTR__RB_OVERFLOW_MASK;
    119 		dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
    120 			wptr, ih->rptr, (wptr + 16) & ih->ptr_mask);
    121 		ih->rptr = (wptr + 16) & ih->ptr_mask;
    122 		tmp = RREG32(IH_RB_CNTL);
    123 		tmp |= IH_RB_CNTL__WPTR_OVERFLOW_CLEAR_MASK;
    124 		WREG32(IH_RB_CNTL, tmp);
    125 	}
    126 	return (wptr & ih->ptr_mask);
    127 }
    128 
    129 static void si_ih_decode_iv(struct amdgpu_device *adev,
    130 			    struct amdgpu_ih_ring *ih,
    131 			    struct amdgpu_iv_entry *entry)
    132 {
    133 	u32 ring_index = ih->rptr >> 2;
    134 	uint32_t dw[4];
    135 
    136 	dw[0] = le32_to_cpu(ih->ring[ring_index + 0]);
    137 	dw[1] = le32_to_cpu(ih->ring[ring_index + 1]);
    138 	dw[2] = le32_to_cpu(ih->ring[ring_index + 2]);
    139 	dw[3] = le32_to_cpu(ih->ring[ring_index + 3]);
    140 
    141 	entry->client_id = AMDGPU_IRQ_CLIENTID_LEGACY;
    142 	entry->src_id = dw[0] & 0xff;
    143 	entry->src_data[0] = dw[1] & 0xfffffff;
    144 	entry->ring_id = dw[2] & 0xff;
    145 	entry->vmid = (dw[2] >> 8) & 0xff;
    146 
    147 	ih->rptr += 16;
    148 }
    149 
    150 static void si_ih_set_rptr(struct amdgpu_device *adev,
    151 			   struct amdgpu_ih_ring *ih)
    152 {
    153 	WREG32(IH_RB_RPTR, ih->rptr);
    154 }
    155 
    156 static int si_ih_early_init(void *handle)
    157 {
    158 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
    159 
    160 	si_ih_set_interrupt_funcs(adev);
    161 
    162 	return 0;
    163 }
    164 
    165 static int si_ih_sw_init(void *handle)
    166 {
    167 	int r;
    168 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
    169 
    170 	r = amdgpu_ih_ring_init(adev, &adev->irq.ih, 64 * 1024, false);
    171 	if (r)
    172 		return r;
    173 
    174 	return amdgpu_irq_init(adev);
    175 }
    176 
    177 static int si_ih_sw_fini(void *handle)
    178 {
    179 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
    180 
    181 	amdgpu_irq_fini(adev);
    182 	amdgpu_ih_ring_fini(adev, &adev->irq.ih);
    183 
    184 	return 0;
    185 }
    186 
    187 static int si_ih_hw_init(void *handle)
    188 {
    189 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
    190 
    191 	return si_ih_irq_init(adev);
    192 }
    193 
    194 static int si_ih_hw_fini(void *handle)
    195 {
    196 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
    197 
    198 	si_ih_irq_disable(adev);
    199 
    200 	return 0;
    201 }
    202 
    203 static int si_ih_suspend(void *handle)
    204 {
    205 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
    206 
    207 	return si_ih_hw_fini(adev);
    208 }
    209 
    210 static int si_ih_resume(void *handle)
    211 {
    212 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
    213 
    214 	return si_ih_hw_init(adev);
    215 }
    216 
    217 static bool si_ih_is_idle(void *handle)
    218 {
    219 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
    220 	u32 tmp = RREG32(SRBM_STATUS);
    221 
    222 	if (tmp & SRBM_STATUS__IH_BUSY_MASK)
    223 		return false;
    224 
    225 	return true;
    226 }
    227 
    228 static int si_ih_wait_for_idle(void *handle)
    229 {
    230 	unsigned i;
    231 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
    232 
    233 	for (i = 0; i < adev->usec_timeout; i++) {
    234 		if (si_ih_is_idle(handle))
    235 			return 0;
    236 		udelay(1);
    237 	}
    238 	return -ETIMEDOUT;
    239 }
    240 
    241 static int si_ih_soft_reset(void *handle)
    242 {
    243 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
    244 
    245 	u32 srbm_soft_reset = 0;
    246 	u32 tmp = RREG32(SRBM_STATUS);
    247 
    248 	if (tmp & SRBM_STATUS__IH_BUSY_MASK)
    249 		srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_IH_MASK;
    250 
    251 	if (srbm_soft_reset) {
    252 		tmp = RREG32(SRBM_SOFT_RESET);
    253 		tmp |= srbm_soft_reset;
    254 		dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
    255 		WREG32(SRBM_SOFT_RESET, tmp);
    256 		tmp = RREG32(SRBM_SOFT_RESET);
    257 
    258 		udelay(50);
    259 
    260 		tmp &= ~srbm_soft_reset;
    261 		WREG32(SRBM_SOFT_RESET, tmp);
    262 		tmp = RREG32(SRBM_SOFT_RESET);
    263 
    264 		udelay(50);
    265 	}
    266 
    267 	return 0;
    268 }
    269 
    270 static int si_ih_set_clockgating_state(void *handle,
    271 					  enum amd_clockgating_state state)
    272 {
    273 	return 0;
    274 }
    275 
    276 static int si_ih_set_powergating_state(void *handle,
    277 					  enum amd_powergating_state state)
    278 {
    279 	return 0;
    280 }
    281 
    282 static const struct amd_ip_funcs si_ih_ip_funcs = {
    283 	.name = "si_ih",
    284 	.early_init = si_ih_early_init,
    285 	.late_init = NULL,
    286 	.sw_init = si_ih_sw_init,
    287 	.sw_fini = si_ih_sw_fini,
    288 	.hw_init = si_ih_hw_init,
    289 	.hw_fini = si_ih_hw_fini,
    290 	.suspend = si_ih_suspend,
    291 	.resume = si_ih_resume,
    292 	.is_idle = si_ih_is_idle,
    293 	.wait_for_idle = si_ih_wait_for_idle,
    294 	.soft_reset = si_ih_soft_reset,
    295 	.set_clockgating_state = si_ih_set_clockgating_state,
    296 	.set_powergating_state = si_ih_set_powergating_state,
    297 };
    298 
    299 static const struct amdgpu_ih_funcs si_ih_funcs = {
    300 	.get_wptr = si_ih_get_wptr,
    301 	.decode_iv = si_ih_decode_iv,
    302 	.set_rptr = si_ih_set_rptr
    303 };
    304 
    305 static void si_ih_set_interrupt_funcs(struct amdgpu_device *adev)
    306 {
    307 	adev->irq.ih_funcs = &si_ih_funcs;
    308 }
    309 
    310 const struct amdgpu_ip_block_version si_ih_ip_block =
    311 {
    312 	.type = AMD_IP_BLOCK_TYPE_IH,
    313 	.major = 1,
    314 	.minor = 0,
    315 	.rev = 0,
    316 	.funcs = &si_ih_ip_funcs,
    317 };
    318