linux/drivers/gpu/drm/amd/amdgpu/vega10_ih.c
<<
>>
Prefs
   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#include <drm/drmP.h>
  24#include "amdgpu.h"
  25#include "amdgpu_ih.h"
  26#include "soc15.h"
  27
  28
  29#include "vega10/soc15ip.h"
  30#include "vega10/OSSSYS/osssys_4_0_offset.h"
  31#include "vega10/OSSSYS/osssys_4_0_sh_mask.h"
  32
  33#include "soc15_common.h"
  34#include "vega10_ih.h"
  35
  36
  37
  38static void vega10_ih_set_interrupt_funcs(struct amdgpu_device *adev);
  39
  40/**
  41 * vega10_ih_enable_interrupts - Enable the interrupt ring buffer
  42 *
  43 * @adev: amdgpu_device pointer
  44 *
  45 * Enable the interrupt ring buffer (VEGA10).
  46 */
  47static void vega10_ih_enable_interrupts(struct amdgpu_device *adev)
  48{
  49        u32 ih_rb_cntl = RREG32(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL));
  50
  51        ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RB_ENABLE, 1);
  52        ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, ENABLE_INTR, 1);
  53        WREG32(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL), ih_rb_cntl);
  54        adev->irq.ih.enabled = true;
  55}
  56
  57/**
  58 * vega10_ih_disable_interrupts - Disable the interrupt ring buffer
  59 *
  60 * @adev: amdgpu_device pointer
  61 *
  62 * Disable the interrupt ring buffer (VEGA10).
  63 */
  64static void vega10_ih_disable_interrupts(struct amdgpu_device *adev)
  65{
  66        u32 ih_rb_cntl = RREG32(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL));
  67
  68        ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RB_ENABLE, 0);
  69        ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, ENABLE_INTR, 0);
  70        WREG32(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL), ih_rb_cntl);
  71        /* set rptr, wptr to 0 */
  72        WREG32(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_RPTR), 0);
  73        WREG32(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR), 0);
  74        adev->irq.ih.enabled = false;
  75        adev->irq.ih.rptr = 0;
  76}
  77
  78/**
  79 * vega10_ih_irq_init - init and enable the interrupt ring
  80 *
  81 * @adev: amdgpu_device pointer
  82 *
  83 * Allocate a ring buffer for the interrupt controller,
  84 * enable the RLC, disable interrupts, enable the IH
  85 * ring buffer and enable it (VI).
  86 * Called at device load and reume.
  87 * Returns 0 for success, errors for failure.
  88 */
  89static int vega10_ih_irq_init(struct amdgpu_device *adev)
  90{
  91        int ret = 0;
  92        int rb_bufsz;
  93        u32 ih_rb_cntl, ih_doorbell_rtpr;
  94        u32 tmp;
  95        u64 wptr_off;
  96
  97        /* disable irqs */
  98        vega10_ih_disable_interrupts(adev);
  99
 100        if (adev->flags & AMD_IS_APU)
 101                nbio_v7_0_ih_control(adev);
 102        else
 103                nbio_v6_1_ih_control(adev);
 104
 105        ih_rb_cntl = RREG32(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL));
 106        /* Ring Buffer base. [39:8] of 40-bit address of the beginning of the ring buffer*/
 107        if (adev->irq.ih.use_bus_addr) {
 108                WREG32(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE), adev->irq.ih.rb_dma_addr >> 8);
 109                WREG32(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_HI), ((u64)adev->irq.ih.rb_dma_addr >> 40) & 0xff);
 110                ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_SPACE, 1);
 111        } else {
 112                WREG32(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE), adev->irq.ih.gpu_addr >> 8);
 113                WREG32(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_HI), (adev->irq.ih.gpu_addr >> 40) & 0xff);
 114                ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_SPACE, 4);
 115        }
 116        rb_bufsz = order_base_2(adev->irq.ih.ring_size / 4);
 117        ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
 118        ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, WPTR_OVERFLOW_ENABLE, 1);
 119        ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RB_SIZE, rb_bufsz);
 120        /* Ring Buffer write pointer writeback. If enabled, IH_RB_WPTR register value is written to memory */
 121        ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, WPTR_WRITEBACK_ENABLE, 1);
 122        ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_SNOOP, 1);
 123        ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_RO, 0);
 124        ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_VMID, 0);
 125
 126        if (adev->irq.msi_enabled)
 127                ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RPTR_REARM, 1);
 128
 129        WREG32(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL), ih_rb_cntl);
 130
 131        /* set the writeback address whether it's enabled or not */
 132        if (adev->irq.ih.use_bus_addr)
 133                wptr_off = adev->irq.ih.rb_dma_addr + (adev->irq.ih.wptr_offs * 4);
 134        else
 135                wptr_off = adev->wb.gpu_addr + (adev->irq.ih.wptr_offs * 4);
 136        WREG32(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_ADDR_LO), lower_32_bits(wptr_off));
 137        WREG32(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_ADDR_HI), upper_32_bits(wptr_off) & 0xFF);
 138
 139        /* set rptr, wptr to 0 */
 140        WREG32(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_RPTR), 0);
 141        WREG32(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR), 0);
 142
 143        ih_doorbell_rtpr = RREG32(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_DOORBELL_RPTR));
 144        if (adev->irq.ih.use_doorbell) {
 145                ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr, IH_DOORBELL_RPTR,
 146                                                 OFFSET, adev->irq.ih.doorbell_index);
 147                ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr, IH_DOORBELL_RPTR,
 148                                                 ENABLE, 1);
 149        } else {
 150                ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr, IH_DOORBELL_RPTR,
 151                                                 ENABLE, 0);
 152        }
 153        WREG32(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_DOORBELL_RPTR), ih_doorbell_rtpr);
 154        if (adev->flags & AMD_IS_APU)
 155                nbio_v7_0_ih_doorbell_range(adev, adev->irq.ih.use_doorbell, adev->irq.ih.doorbell_index);
 156        else
 157                nbio_v6_1_ih_doorbell_range(adev, adev->irq.ih.use_doorbell, adev->irq.ih.doorbell_index);
 158
 159        tmp = RREG32(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_STORM_CLIENT_LIST_CNTL));
 160        tmp = REG_SET_FIELD(tmp, IH_STORM_CLIENT_LIST_CNTL,
 161                            CLIENT18_IS_STORM_CLIENT, 1);
 162        WREG32(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_STORM_CLIENT_LIST_CNTL), tmp);
 163
 164        tmp = RREG32(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_INT_FLOOD_CNTL));
 165        tmp = REG_SET_FIELD(tmp, IH_INT_FLOOD_CNTL, FLOOD_CNTL_ENABLE, 1);
 166        WREG32(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_INT_FLOOD_CNTL), tmp);
 167
 168        pci_set_master(adev->pdev);
 169
 170        /* enable interrupts */
 171        vega10_ih_enable_interrupts(adev);
 172
 173        return ret;
 174}
 175
 176/**
 177 * vega10_ih_irq_disable - disable interrupts
 178 *
 179 * @adev: amdgpu_device pointer
 180 *
 181 * Disable interrupts on the hw (VEGA10).
 182 */
 183static void vega10_ih_irq_disable(struct amdgpu_device *adev)
 184{
 185        vega10_ih_disable_interrupts(adev);
 186
 187        /* Wait and acknowledge irq */
 188        mdelay(1);
 189}
 190
 191/**
 192 * vega10_ih_get_wptr - get the IH ring buffer wptr
 193 *
 194 * @adev: amdgpu_device pointer
 195 *
 196 * Get the IH ring buffer wptr from either the register
 197 * or the writeback memory buffer (VEGA10).  Also check for
 198 * ring buffer overflow and deal with it.
 199 * Returns the value of the wptr.
 200 */
 201static u32 vega10_ih_get_wptr(struct amdgpu_device *adev)
 202{
 203        u32 wptr, tmp;
 204
 205        if (adev->irq.ih.use_bus_addr)
 206                wptr = le32_to_cpu(adev->irq.ih.ring[adev->irq.ih.wptr_offs]);
 207        else
 208                wptr = le32_to_cpu(adev->wb.wb[adev->irq.ih.wptr_offs]);
 209
 210        if (REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW)) {
 211                wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0);
 212
 213                /* When a ring buffer overflow happen start parsing interrupt
 214                 * from the last not overwritten vector (wptr + 32). Hopefully
 215                 * this should allow us to catchup.
 216                 */
 217                tmp = (wptr + 32) & adev->irq.ih.ptr_mask;
 218                dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
 219                        wptr, adev->irq.ih.rptr, tmp);
 220                adev->irq.ih.rptr = tmp;
 221
 222                tmp = RREG32(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL));
 223                tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
 224                WREG32(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL), tmp);
 225        }
 226        return (wptr & adev->irq.ih.ptr_mask);
 227}
 228
 229/**
 230 * vega10_ih_decode_iv - decode an interrupt vector
 231 *
 232 * @adev: amdgpu_device pointer
 233 *
 234 * Decodes the interrupt vector at the current rptr
 235 * position and also advance the position.
 236 */
 237static void vega10_ih_decode_iv(struct amdgpu_device *adev,
 238                                 struct amdgpu_iv_entry *entry)
 239{
 240        /* wptr/rptr are in bytes! */
 241        u32 ring_index = adev->irq.ih.rptr >> 2;
 242        uint32_t dw[8];
 243
 244        dw[0] = le32_to_cpu(adev->irq.ih.ring[ring_index + 0]);
 245        dw[1] = le32_to_cpu(adev->irq.ih.ring[ring_index + 1]);
 246        dw[2] = le32_to_cpu(adev->irq.ih.ring[ring_index + 2]);
 247        dw[3] = le32_to_cpu(adev->irq.ih.ring[ring_index + 3]);
 248        dw[4] = le32_to_cpu(adev->irq.ih.ring[ring_index + 4]);
 249        dw[5] = le32_to_cpu(adev->irq.ih.ring[ring_index + 5]);
 250        dw[6] = le32_to_cpu(adev->irq.ih.ring[ring_index + 6]);
 251        dw[7] = le32_to_cpu(adev->irq.ih.ring[ring_index + 7]);
 252
 253        entry->client_id = dw[0] & 0xff;
 254        entry->src_id = (dw[0] >> 8) & 0xff;
 255        entry->ring_id = (dw[0] >> 16) & 0xff;
 256        entry->vm_id = (dw[0] >> 24) & 0xf;
 257        entry->vm_id_src = (dw[0] >> 31);
 258        entry->timestamp = dw[1] | ((u64)(dw[2] & 0xffff) << 32);
 259        entry->timestamp_src = dw[2] >> 31;
 260        entry->pas_id = dw[3] & 0xffff;
 261        entry->pasid_src = dw[3] >> 31;
 262        entry->src_data[0] = dw[4];
 263        entry->src_data[1] = dw[5];
 264        entry->src_data[2] = dw[6];
 265        entry->src_data[3] = dw[7];
 266
 267
 268        /* wptr/rptr are in bytes! */
 269        adev->irq.ih.rptr += 32;
 270}
 271
 272/**
 273 * vega10_ih_set_rptr - set the IH ring buffer rptr
 274 *
 275 * @adev: amdgpu_device pointer
 276 *
 277 * Set the IH ring buffer rptr.
 278 */
 279static void vega10_ih_set_rptr(struct amdgpu_device *adev)
 280{
 281        if (adev->irq.ih.use_doorbell) {
 282                /* XXX check if swapping is necessary on BE */
 283                if (adev->irq.ih.use_bus_addr)
 284                        adev->irq.ih.ring[adev->irq.ih.rptr_offs] = adev->irq.ih.rptr;
 285                else
 286                        adev->wb.wb[adev->irq.ih.rptr_offs] = adev->irq.ih.rptr;
 287                WDOORBELL32(adev->irq.ih.doorbell_index, adev->irq.ih.rptr);
 288        } else {
 289                WREG32(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_RPTR), adev->irq.ih.rptr);
 290        }
 291}
 292
 293static int vega10_ih_early_init(void *handle)
 294{
 295        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 296
 297        vega10_ih_set_interrupt_funcs(adev);
 298        return 0;
 299}
 300
 301static int vega10_ih_sw_init(void *handle)
 302{
 303        int r;
 304        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 305
 306        r = amdgpu_ih_ring_init(adev, 256 * 1024, true);
 307        if (r)
 308                return r;
 309
 310        adev->irq.ih.use_doorbell = true;
 311        adev->irq.ih.doorbell_index = AMDGPU_DOORBELL64_IH << 1;
 312
 313        r = amdgpu_irq_init(adev);
 314
 315        return r;
 316}
 317
 318static int vega10_ih_sw_fini(void *handle)
 319{
 320        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 321
 322        amdgpu_irq_fini(adev);
 323        amdgpu_ih_ring_fini(adev);
 324
 325        return 0;
 326}
 327
 328static int vega10_ih_hw_init(void *handle)
 329{
 330        int r;
 331        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 332
 333        r = vega10_ih_irq_init(adev);
 334        if (r)
 335                return r;
 336
 337        return 0;
 338}
 339
 340static int vega10_ih_hw_fini(void *handle)
 341{
 342        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 343
 344        vega10_ih_irq_disable(adev);
 345
 346        return 0;
 347}
 348
 349static int vega10_ih_suspend(void *handle)
 350{
 351        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 352
 353        return vega10_ih_hw_fini(adev);
 354}
 355
 356static int vega10_ih_resume(void *handle)
 357{
 358        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 359
 360        return vega10_ih_hw_init(adev);
 361}
 362
 363static bool vega10_ih_is_idle(void *handle)
 364{
 365        /* todo */
 366        return true;
 367}
 368
 369static int vega10_ih_wait_for_idle(void *handle)
 370{
 371        /* todo */
 372        return -ETIMEDOUT;
 373}
 374
 375static int vega10_ih_soft_reset(void *handle)
 376{
 377        /* todo */
 378
 379        return 0;
 380}
 381
 382static int vega10_ih_set_clockgating_state(void *handle,
 383                                          enum amd_clockgating_state state)
 384{
 385        return 0;
 386}
 387
 388static int vega10_ih_set_powergating_state(void *handle,
 389                                          enum amd_powergating_state state)
 390{
 391        return 0;
 392}
 393
 394const struct amd_ip_funcs vega10_ih_ip_funcs = {
 395        .name = "vega10_ih",
 396        .early_init = vega10_ih_early_init,
 397        .late_init = NULL,
 398        .sw_init = vega10_ih_sw_init,
 399        .sw_fini = vega10_ih_sw_fini,
 400        .hw_init = vega10_ih_hw_init,
 401        .hw_fini = vega10_ih_hw_fini,
 402        .suspend = vega10_ih_suspend,
 403        .resume = vega10_ih_resume,
 404        .is_idle = vega10_ih_is_idle,
 405        .wait_for_idle = vega10_ih_wait_for_idle,
 406        .soft_reset = vega10_ih_soft_reset,
 407        .set_clockgating_state = vega10_ih_set_clockgating_state,
 408        .set_powergating_state = vega10_ih_set_powergating_state,
 409};
 410
 411static const struct amdgpu_ih_funcs vega10_ih_funcs = {
 412        .get_wptr = vega10_ih_get_wptr,
 413        .decode_iv = vega10_ih_decode_iv,
 414        .set_rptr = vega10_ih_set_rptr
 415};
 416
 417static void vega10_ih_set_interrupt_funcs(struct amdgpu_device *adev)
 418{
 419        if (adev->irq.ih_funcs == NULL)
 420                adev->irq.ih_funcs = &vega10_ih_funcs;
 421}
 422
 423const struct amdgpu_ip_block_version vega10_ih_ip_block =
 424{
 425        .type = AMD_IP_BLOCK_TYPE_IH,
 426        .major = 4,
 427        .minor = 0,
 428        .rev = 0,
 429        .funcs = &vega10_ih_ip_funcs,
 430};
 431