root/drivers/gpu/drm/amd/amdgpu/iceland_ih.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. iceland_ih_enable_interrupts
  2. iceland_ih_disable_interrupts
  3. iceland_ih_irq_init
  4. iceland_ih_irq_disable
  5. iceland_ih_get_wptr
  6. iceland_ih_decode_iv
  7. iceland_ih_set_rptr
  8. iceland_ih_early_init
  9. iceland_ih_sw_init
  10. iceland_ih_sw_fini
  11. iceland_ih_hw_init
  12. iceland_ih_hw_fini
  13. iceland_ih_suspend
  14. iceland_ih_resume
  15. iceland_ih_is_idle
  16. iceland_ih_wait_for_idle
  17. iceland_ih_soft_reset
  18. iceland_ih_set_clockgating_state
  19. iceland_ih_set_powergating_state
  20. iceland_ih_set_interrupt_funcs

   1 /*
   2  * Copyright 2014 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 "vid.h"
  29 
  30 #include "oss/oss_2_4_d.h"
  31 #include "oss/oss_2_4_sh_mask.h"
  32 
  33 #include "bif/bif_5_1_d.h"
  34 #include "bif/bif_5_1_sh_mask.h"
  35 
  36 /*
  37  * Interrupts
  38  * Starting with r6xx, interrupts are handled via a ring buffer.
  39  * Ring buffers are areas of GPU accessible memory that the GPU
  40  * writes interrupt vectors into and the host reads vectors out of.
  41  * There is a rptr (read pointer) that determines where the
  42  * host is currently reading, and a wptr (write pointer)
  43  * which determines where the GPU has written.  When the
  44  * pointers are equal, the ring is idle.  When the GPU
  45  * writes vectors to the ring buffer, it increments the
  46  * wptr.  When there is an interrupt, the host then starts
  47  * fetching commands and processing them until the pointers are
  48  * equal again at which point it updates the rptr.
  49  */
  50 
  51 static void iceland_ih_set_interrupt_funcs(struct amdgpu_device *adev);
  52 
  53 /**
  54  * iceland_ih_enable_interrupts - Enable the interrupt ring buffer
  55  *
  56  * @adev: amdgpu_device pointer
  57  *
  58  * Enable the interrupt ring buffer (VI).
  59  */
  60 static void iceland_ih_enable_interrupts(struct amdgpu_device *adev)
  61 {
  62         u32 ih_cntl = RREG32(mmIH_CNTL);
  63         u32 ih_rb_cntl = RREG32(mmIH_RB_CNTL);
  64 
  65         ih_cntl = REG_SET_FIELD(ih_cntl, IH_CNTL, ENABLE_INTR, 1);
  66         ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RB_ENABLE, 1);
  67         WREG32(mmIH_CNTL, ih_cntl);
  68         WREG32(mmIH_RB_CNTL, ih_rb_cntl);
  69         adev->irq.ih.enabled = true;
  70 }
  71 
  72 /**
  73  * iceland_ih_disable_interrupts - Disable the interrupt ring buffer
  74  *
  75  * @adev: amdgpu_device pointer
  76  *
  77  * Disable the interrupt ring buffer (VI).
  78  */
  79 static void iceland_ih_disable_interrupts(struct amdgpu_device *adev)
  80 {
  81         u32 ih_rb_cntl = RREG32(mmIH_RB_CNTL);
  82         u32 ih_cntl = RREG32(mmIH_CNTL);
  83 
  84         ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RB_ENABLE, 0);
  85         ih_cntl = REG_SET_FIELD(ih_cntl, IH_CNTL, ENABLE_INTR, 0);
  86         WREG32(mmIH_RB_CNTL, ih_rb_cntl);
  87         WREG32(mmIH_CNTL, ih_cntl);
  88         /* set rptr, wptr to 0 */
  89         WREG32(mmIH_RB_RPTR, 0);
  90         WREG32(mmIH_RB_WPTR, 0);
  91         adev->irq.ih.enabled = false;
  92         adev->irq.ih.rptr = 0;
  93 }
  94 
  95 /**
  96  * iceland_ih_irq_init - init and enable the interrupt ring
  97  *
  98  * @adev: amdgpu_device pointer
  99  *
 100  * Allocate a ring buffer for the interrupt controller,
 101  * enable the RLC, disable interrupts, enable the IH
 102  * ring buffer and enable it (VI).
 103  * Called at device load and reume.
 104  * Returns 0 for success, errors for failure.
 105  */
 106 static int iceland_ih_irq_init(struct amdgpu_device *adev)
 107 {
 108         struct amdgpu_ih_ring *ih = &adev->irq.ih;
 109         int rb_bufsz;
 110         u32 interrupt_cntl, ih_cntl, ih_rb_cntl;
 111 
 112         /* disable irqs */
 113         iceland_ih_disable_interrupts(adev);
 114 
 115         /* setup interrupt control */
 116         WREG32(mmINTERRUPT_CNTL2, adev->dummy_page_addr >> 8);
 117         interrupt_cntl = RREG32(mmINTERRUPT_CNTL);
 118         /* INTERRUPT_CNTL__IH_DUMMY_RD_OVERRIDE_MASK=0 - dummy read disabled with msi, enabled without msi
 119          * INTERRUPT_CNTL__IH_DUMMY_RD_OVERRIDE_MASK=1 - dummy read controlled by IH_DUMMY_RD_EN
 120          */
 121         interrupt_cntl = REG_SET_FIELD(interrupt_cntl, INTERRUPT_CNTL, IH_DUMMY_RD_OVERRIDE, 0);
 122         /* INTERRUPT_CNTL__IH_REQ_NONSNOOP_EN_MASK=1 if ring is in non-cacheable memory, e.g., vram */
 123         interrupt_cntl = REG_SET_FIELD(interrupt_cntl, INTERRUPT_CNTL, IH_REQ_NONSNOOP_EN, 0);
 124         WREG32(mmINTERRUPT_CNTL, interrupt_cntl);
 125 
 126         /* Ring Buffer base. [39:8] of 40-bit address of the beginning of the ring buffer*/
 127         WREG32(mmIH_RB_BASE, adev->irq.ih.gpu_addr >> 8);
 128 
 129         rb_bufsz = order_base_2(adev->irq.ih.ring_size / 4);
 130         ih_rb_cntl = REG_SET_FIELD(0, IH_RB_CNTL, WPTR_OVERFLOW_ENABLE, 1);
 131         ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
 132         ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RB_SIZE, rb_bufsz);
 133 
 134         /* Ring Buffer write pointer writeback. If enabled, IH_RB_WPTR register value is written to memory */
 135         ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, WPTR_WRITEBACK_ENABLE, 1);
 136 
 137         /* set the writeback address whether it's enabled or not */
 138         WREG32(mmIH_RB_WPTR_ADDR_LO, lower_32_bits(ih->wptr_addr));
 139         WREG32(mmIH_RB_WPTR_ADDR_HI, upper_32_bits(ih->wptr_addr) & 0xFF);
 140 
 141         WREG32(mmIH_RB_CNTL, ih_rb_cntl);
 142 
 143         /* set rptr, wptr to 0 */
 144         WREG32(mmIH_RB_RPTR, 0);
 145         WREG32(mmIH_RB_WPTR, 0);
 146 
 147         /* Default settings for IH_CNTL (disabled at first) */
 148         ih_cntl = RREG32(mmIH_CNTL);
 149         ih_cntl = REG_SET_FIELD(ih_cntl, IH_CNTL, MC_VMID, 0);
 150 
 151         if (adev->irq.msi_enabled)
 152                 ih_cntl = REG_SET_FIELD(ih_cntl, IH_CNTL, RPTR_REARM, 1);
 153         WREG32(mmIH_CNTL, ih_cntl);
 154 
 155         pci_set_master(adev->pdev);
 156 
 157         /* enable interrupts */
 158         iceland_ih_enable_interrupts(adev);
 159 
 160         return 0;
 161 }
 162 
 163 /**
 164  * iceland_ih_irq_disable - disable interrupts
 165  *
 166  * @adev: amdgpu_device pointer
 167  *
 168  * Disable interrupts on the hw (VI).
 169  */
 170 static void iceland_ih_irq_disable(struct amdgpu_device *adev)
 171 {
 172         iceland_ih_disable_interrupts(adev);
 173 
 174         /* Wait and acknowledge irq */
 175         mdelay(1);
 176 }
 177 
 178 /**
 179  * iceland_ih_get_wptr - get the IH ring buffer wptr
 180  *
 181  * @adev: amdgpu_device pointer
 182  *
 183  * Get the IH ring buffer wptr from either the register
 184  * or the writeback memory buffer (VI).  Also check for
 185  * ring buffer overflow and deal with it.
 186  * Used by cz_irq_process(VI).
 187  * Returns the value of the wptr.
 188  */
 189 static u32 iceland_ih_get_wptr(struct amdgpu_device *adev,
 190                                struct amdgpu_ih_ring *ih)
 191 {
 192         u32 wptr, tmp;
 193 
 194         wptr = le32_to_cpu(*ih->wptr_cpu);
 195 
 196         if (REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW)) {
 197                 wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0);
 198                 /* When a ring buffer overflow happen start parsing interrupt
 199                  * from the last not overwritten vector (wptr + 16). Hopefully
 200                  * this should allow us to catchup.
 201                  */
 202                 dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
 203                          wptr, ih->rptr, (wptr + 16) & ih->ptr_mask);
 204                 ih->rptr = (wptr + 16) & ih->ptr_mask;
 205                 tmp = RREG32(mmIH_RB_CNTL);
 206                 tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
 207                 WREG32(mmIH_RB_CNTL, tmp);
 208         }
 209         return (wptr & ih->ptr_mask);
 210 }
 211 
 212 /**
 213  * iceland_ih_decode_iv - decode an interrupt vector
 214  *
 215  * @adev: amdgpu_device pointer
 216  *
 217  * Decodes the interrupt vector at the current rptr
 218  * position and also advance the position.
 219  */
 220 static void iceland_ih_decode_iv(struct amdgpu_device *adev,
 221                                  struct amdgpu_ih_ring *ih,
 222                                  struct amdgpu_iv_entry *entry)
 223 {
 224         /* wptr/rptr are in bytes! */
 225         u32 ring_index = ih->rptr >> 2;
 226         uint32_t dw[4];
 227 
 228         dw[0] = le32_to_cpu(ih->ring[ring_index + 0]);
 229         dw[1] = le32_to_cpu(ih->ring[ring_index + 1]);
 230         dw[2] = le32_to_cpu(ih->ring[ring_index + 2]);
 231         dw[3] = le32_to_cpu(ih->ring[ring_index + 3]);
 232 
 233         entry->client_id = AMDGPU_IRQ_CLIENTID_LEGACY;
 234         entry->src_id = dw[0] & 0xff;
 235         entry->src_data[0] = dw[1] & 0xfffffff;
 236         entry->ring_id = dw[2] & 0xff;
 237         entry->vmid = (dw[2] >> 8) & 0xff;
 238         entry->pasid = (dw[2] >> 16) & 0xffff;
 239 
 240         /* wptr/rptr are in bytes! */
 241         ih->rptr += 16;
 242 }
 243 
 244 /**
 245  * iceland_ih_set_rptr - set the IH ring buffer rptr
 246  *
 247  * @adev: amdgpu_device pointer
 248  *
 249  * Set the IH ring buffer rptr.
 250  */
 251 static void iceland_ih_set_rptr(struct amdgpu_device *adev,
 252                                 struct amdgpu_ih_ring *ih)
 253 {
 254         WREG32(mmIH_RB_RPTR, ih->rptr);
 255 }
 256 
 257 static int iceland_ih_early_init(void *handle)
 258 {
 259         struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 260         int ret;
 261 
 262         ret = amdgpu_irq_add_domain(adev);
 263         if (ret)
 264                 return ret;
 265 
 266         iceland_ih_set_interrupt_funcs(adev);
 267 
 268         return 0;
 269 }
 270 
 271 static int iceland_ih_sw_init(void *handle)
 272 {
 273         int r;
 274         struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 275 
 276         r = amdgpu_ih_ring_init(adev, &adev->irq.ih, 64 * 1024, false);
 277         if (r)
 278                 return r;
 279 
 280         r = amdgpu_irq_init(adev);
 281 
 282         return r;
 283 }
 284 
 285 static int iceland_ih_sw_fini(void *handle)
 286 {
 287         struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 288 
 289         amdgpu_irq_fini(adev);
 290         amdgpu_ih_ring_fini(adev, &adev->irq.ih);
 291         amdgpu_irq_remove_domain(adev);
 292 
 293         return 0;
 294 }
 295 
 296 static int iceland_ih_hw_init(void *handle)
 297 {
 298         int r;
 299         struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 300 
 301         r = iceland_ih_irq_init(adev);
 302         if (r)
 303                 return r;
 304 
 305         return 0;
 306 }
 307 
 308 static int iceland_ih_hw_fini(void *handle)
 309 {
 310         struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 311 
 312         iceland_ih_irq_disable(adev);
 313 
 314         return 0;
 315 }
 316 
 317 static int iceland_ih_suspend(void *handle)
 318 {
 319         struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 320 
 321         return iceland_ih_hw_fini(adev);
 322 }
 323 
 324 static int iceland_ih_resume(void *handle)
 325 {
 326         struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 327 
 328         return iceland_ih_hw_init(adev);
 329 }
 330 
 331 static bool iceland_ih_is_idle(void *handle)
 332 {
 333         struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 334         u32 tmp = RREG32(mmSRBM_STATUS);
 335 
 336         if (REG_GET_FIELD(tmp, SRBM_STATUS, IH_BUSY))
 337                 return false;
 338 
 339         return true;
 340 }
 341 
 342 static int iceland_ih_wait_for_idle(void *handle)
 343 {
 344         unsigned i;
 345         u32 tmp;
 346         struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 347 
 348         for (i = 0; i < adev->usec_timeout; i++) {
 349                 /* read MC_STATUS */
 350                 tmp = RREG32(mmSRBM_STATUS);
 351                 if (!REG_GET_FIELD(tmp, SRBM_STATUS, IH_BUSY))
 352                         return 0;
 353                 udelay(1);
 354         }
 355         return -ETIMEDOUT;
 356 }
 357 
 358 static int iceland_ih_soft_reset(void *handle)
 359 {
 360         u32 srbm_soft_reset = 0;
 361         struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 362         u32 tmp = RREG32(mmSRBM_STATUS);
 363 
 364         if (tmp & SRBM_STATUS__IH_BUSY_MASK)
 365                 srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET,
 366                                                 SOFT_RESET_IH, 1);
 367 
 368         if (srbm_soft_reset) {
 369                 tmp = RREG32(mmSRBM_SOFT_RESET);
 370                 tmp |= srbm_soft_reset;
 371                 dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
 372                 WREG32(mmSRBM_SOFT_RESET, tmp);
 373                 tmp = RREG32(mmSRBM_SOFT_RESET);
 374 
 375                 udelay(50);
 376 
 377                 tmp &= ~srbm_soft_reset;
 378                 WREG32(mmSRBM_SOFT_RESET, tmp);
 379                 tmp = RREG32(mmSRBM_SOFT_RESET);
 380 
 381                 /* Wait a little for things to settle down */
 382                 udelay(50);
 383         }
 384 
 385         return 0;
 386 }
 387 
 388 static int iceland_ih_set_clockgating_state(void *handle,
 389                                           enum amd_clockgating_state state)
 390 {
 391         return 0;
 392 }
 393 
 394 static int iceland_ih_set_powergating_state(void *handle,
 395                                           enum amd_powergating_state state)
 396 {
 397         return 0;
 398 }
 399 
 400 static const struct amd_ip_funcs iceland_ih_ip_funcs = {
 401         .name = "iceland_ih",
 402         .early_init = iceland_ih_early_init,
 403         .late_init = NULL,
 404         .sw_init = iceland_ih_sw_init,
 405         .sw_fini = iceland_ih_sw_fini,
 406         .hw_init = iceland_ih_hw_init,
 407         .hw_fini = iceland_ih_hw_fini,
 408         .suspend = iceland_ih_suspend,
 409         .resume = iceland_ih_resume,
 410         .is_idle = iceland_ih_is_idle,
 411         .wait_for_idle = iceland_ih_wait_for_idle,
 412         .soft_reset = iceland_ih_soft_reset,
 413         .set_clockgating_state = iceland_ih_set_clockgating_state,
 414         .set_powergating_state = iceland_ih_set_powergating_state,
 415 };
 416 
 417 static const struct amdgpu_ih_funcs iceland_ih_funcs = {
 418         .get_wptr = iceland_ih_get_wptr,
 419         .decode_iv = iceland_ih_decode_iv,
 420         .set_rptr = iceland_ih_set_rptr
 421 };
 422 
 423 static void iceland_ih_set_interrupt_funcs(struct amdgpu_device *adev)
 424 {
 425         adev->irq.ih_funcs = &iceland_ih_funcs;
 426 }
 427 
 428 const struct amdgpu_ip_block_version iceland_ih_ip_block =
 429 {
 430         .type = AMD_IP_BLOCK_TYPE_IH,
 431         .major = 2,
 432         .minor = 4,
 433         .rev = 0,
 434         .funcs = &iceland_ih_ip_funcs,
 435 };

/* [<][>][^][v][top][bottom][index][help] */