linux/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
<<
>>
Prefs
   1/*
   2 * Copyright 2008 Advanced Micro Devices, Inc.
   3 * Copyright 2008 Red Hat Inc.
   4 * Copyright 2009 Jerome Glisse.
   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 * Authors: Dave Airlie
  25 *          Alex Deucher
  26 *          Jerome Glisse
  27 */
  28
  29/**
  30 * DOC: Interrupt Handling
  31 *
  32 * Interrupts generated within GPU hardware raise interrupt requests that are
  33 * passed to amdgpu IRQ handler which is responsible for detecting source and
  34 * type of the interrupt and dispatching matching handlers. If handling an
  35 * interrupt requires calling kernel functions that may sleep processing is
  36 * dispatched to work handlers.
  37 *
  38 * If MSI functionality is not disabled by module parameter then MSI
  39 * support will be enabled.
  40 *
  41 * For GPU interrupt sources that may be driven by another driver, IRQ domain
  42 * support is used (with mapping between virtual and hardware IRQs).
  43 */
  44
  45#include <linux/irq.h>
  46#include <linux/pci.h>
  47
  48#include <drm/drm_crtc_helper.h>
  49#include <drm/drm_vblank.h>
  50#include <drm/amdgpu_drm.h>
  51#include <drm/drm_drv.h>
  52#include "amdgpu.h"
  53#include "amdgpu_ih.h"
  54#include "atom.h"
  55#include "amdgpu_connectors.h"
  56#include "amdgpu_trace.h"
  57#include "amdgpu_amdkfd.h"
  58#include "amdgpu_ras.h"
  59
  60#include <linux/pm_runtime.h>
  61
  62#ifdef CONFIG_DRM_AMD_DC
  63#include "amdgpu_dm_irq.h"
  64#endif
  65
  66#define AMDGPU_WAIT_IDLE_TIMEOUT 200
  67
  68const char *soc15_ih_clientid_name[] = {
  69        "IH",
  70        "SDMA2 or ACP",
  71        "ATHUB",
  72        "BIF",
  73        "SDMA3 or DCE",
  74        "SDMA4 or ISP",
  75        "VMC1 or PCIE0",
  76        "RLC",
  77        "SDMA0",
  78        "SDMA1",
  79        "SE0SH",
  80        "SE1SH",
  81        "SE2SH",
  82        "SE3SH",
  83        "VCN1 or UVD1",
  84        "THM",
  85        "VCN or UVD",
  86        "SDMA5 or VCE0",
  87        "VMC",
  88        "SDMA6 or XDMA",
  89        "GRBM_CP",
  90        "ATS",
  91        "ROM_SMUIO",
  92        "DF",
  93        "SDMA7 or VCE1",
  94        "PWR",
  95        "reserved",
  96        "UTCL2",
  97        "EA",
  98        "UTCL2LOG",
  99        "MP0",
 100        "MP1"
 101};
 102
 103/**
 104 * amdgpu_hotplug_work_func - work handler for display hotplug event
 105 *
 106 * @work: work struct pointer
 107 *
 108 * This is the hotplug event work handler (all ASICs).
 109 * The work gets scheduled from the IRQ handler if there
 110 * was a hotplug interrupt.  It walks through the connector table
 111 * and calls hotplug handler for each connector. After this, it sends
 112 * a DRM hotplug event to alert userspace.
 113 *
 114 * This design approach is required in order to defer hotplug event handling
 115 * from the IRQ handler to a work handler because hotplug handler has to use
 116 * mutexes which cannot be locked in an IRQ handler (since &mutex_lock may
 117 * sleep).
 118 */
 119static void amdgpu_hotplug_work_func(struct work_struct *work)
 120{
 121        struct amdgpu_device *adev = container_of(work, struct amdgpu_device,
 122                                                  hotplug_work);
 123        struct drm_device *dev = adev_to_drm(adev);
 124        struct drm_mode_config *mode_config = &dev->mode_config;
 125        struct drm_connector *connector;
 126        struct drm_connector_list_iter iter;
 127
 128        mutex_lock(&mode_config->mutex);
 129        drm_connector_list_iter_begin(dev, &iter);
 130        drm_for_each_connector_iter(connector, &iter)
 131                amdgpu_connector_hotplug(connector);
 132        drm_connector_list_iter_end(&iter);
 133        mutex_unlock(&mode_config->mutex);
 134        /* Just fire off a uevent and let userspace tell us what to do */
 135        drm_helper_hpd_irq_event(dev);
 136}
 137
 138/**
 139 * amdgpu_irq_disable_all - disable *all* interrupts
 140 *
 141 * @adev: amdgpu device pointer
 142 *
 143 * Disable all types of interrupts from all sources.
 144 */
 145void amdgpu_irq_disable_all(struct amdgpu_device *adev)
 146{
 147        unsigned long irqflags;
 148        unsigned i, j, k;
 149        int r;
 150
 151        spin_lock_irqsave(&adev->irq.lock, irqflags);
 152        for (i = 0; i < AMDGPU_IRQ_CLIENTID_MAX; ++i) {
 153                if (!adev->irq.client[i].sources)
 154                        continue;
 155
 156                for (j = 0; j < AMDGPU_MAX_IRQ_SRC_ID; ++j) {
 157                        struct amdgpu_irq_src *src = adev->irq.client[i].sources[j];
 158
 159                        if (!src || !src->funcs->set || !src->num_types)
 160                                continue;
 161
 162                        for (k = 0; k < src->num_types; ++k) {
 163                                atomic_set(&src->enabled_types[k], 0);
 164                                r = src->funcs->set(adev, src, k,
 165                                                    AMDGPU_IRQ_STATE_DISABLE);
 166                                if (r)
 167                                        DRM_ERROR("error disabling interrupt (%d)\n",
 168                                                  r);
 169                        }
 170                }
 171        }
 172        spin_unlock_irqrestore(&adev->irq.lock, irqflags);
 173}
 174
 175/**
 176 * amdgpu_irq_handler - IRQ handler
 177 *
 178 * @irq: IRQ number (unused)
 179 * @arg: pointer to DRM device
 180 *
 181 * IRQ handler for amdgpu driver (all ASICs).
 182 *
 183 * Returns:
 184 * result of handling the IRQ, as defined by &irqreturn_t
 185 */
 186static irqreturn_t amdgpu_irq_handler(int irq, void *arg)
 187{
 188        struct drm_device *dev = (struct drm_device *) arg;
 189        struct amdgpu_device *adev = drm_to_adev(dev);
 190        irqreturn_t ret;
 191
 192        ret = amdgpu_ih_process(adev, &adev->irq.ih);
 193        if (ret == IRQ_HANDLED)
 194                pm_runtime_mark_last_busy(dev->dev);
 195
 196        /* For the hardware that cannot enable bif ring for both ras_controller_irq
 197         * and ras_err_evnet_athub_irq ih cookies, the driver has to poll status
 198         * register to check whether the interrupt is triggered or not, and properly
 199         * ack the interrupt if it is there
 200         */
 201        if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__PCIE_BIF)) {
 202                if (adev->nbio.ras_funcs &&
 203                    adev->nbio.ras_funcs->handle_ras_controller_intr_no_bifring)
 204                        adev->nbio.ras_funcs->handle_ras_controller_intr_no_bifring(adev);
 205
 206                if (adev->nbio.ras_funcs &&
 207                    adev->nbio.ras_funcs->handle_ras_err_event_athub_intr_no_bifring)
 208                        adev->nbio.ras_funcs->handle_ras_err_event_athub_intr_no_bifring(adev);
 209        }
 210
 211        return ret;
 212}
 213
 214/**
 215 * amdgpu_irq_handle_ih1 - kick of processing for IH1
 216 *
 217 * @work: work structure in struct amdgpu_irq
 218 *
 219 * Kick of processing IH ring 1.
 220 */
 221static void amdgpu_irq_handle_ih1(struct work_struct *work)
 222{
 223        struct amdgpu_device *adev = container_of(work, struct amdgpu_device,
 224                                                  irq.ih1_work);
 225
 226        amdgpu_ih_process(adev, &adev->irq.ih1);
 227}
 228
 229/**
 230 * amdgpu_irq_handle_ih2 - kick of processing for IH2
 231 *
 232 * @work: work structure in struct amdgpu_irq
 233 *
 234 * Kick of processing IH ring 2.
 235 */
 236static void amdgpu_irq_handle_ih2(struct work_struct *work)
 237{
 238        struct amdgpu_device *adev = container_of(work, struct amdgpu_device,
 239                                                  irq.ih2_work);
 240
 241        amdgpu_ih_process(adev, &adev->irq.ih2);
 242}
 243
 244/**
 245 * amdgpu_irq_handle_ih_soft - kick of processing for ih_soft
 246 *
 247 * @work: work structure in struct amdgpu_irq
 248 *
 249 * Kick of processing IH soft ring.
 250 */
 251static void amdgpu_irq_handle_ih_soft(struct work_struct *work)
 252{
 253        struct amdgpu_device *adev = container_of(work, struct amdgpu_device,
 254                                                  irq.ih_soft_work);
 255
 256        amdgpu_ih_process(adev, &adev->irq.ih_soft);
 257}
 258
 259/**
 260 * amdgpu_msi_ok - check whether MSI functionality is enabled
 261 *
 262 * @adev: amdgpu device pointer (unused)
 263 *
 264 * Checks whether MSI functionality has been disabled via module parameter
 265 * (all ASICs).
 266 *
 267 * Returns:
 268 * *true* if MSIs are allowed to be enabled or *false* otherwise
 269 */
 270static bool amdgpu_msi_ok(struct amdgpu_device *adev)
 271{
 272        if (amdgpu_msi == 1)
 273                return true;
 274        else if (amdgpu_msi == 0)
 275                return false;
 276
 277        return true;
 278}
 279
 280static void amdgpu_restore_msix(struct amdgpu_device *adev)
 281{
 282        u16 ctrl;
 283
 284        pci_read_config_word(adev->pdev, adev->pdev->msix_cap + PCI_MSIX_FLAGS, &ctrl);
 285        if (!(ctrl & PCI_MSIX_FLAGS_ENABLE))
 286                return;
 287
 288        /* VF FLR */
 289        ctrl &= ~PCI_MSIX_FLAGS_ENABLE;
 290        pci_write_config_word(adev->pdev, adev->pdev->msix_cap + PCI_MSIX_FLAGS, ctrl);
 291        ctrl |= PCI_MSIX_FLAGS_ENABLE;
 292        pci_write_config_word(adev->pdev, adev->pdev->msix_cap + PCI_MSIX_FLAGS, ctrl);
 293}
 294
 295/**
 296 * amdgpu_irq_init - initialize interrupt handling
 297 *
 298 * @adev: amdgpu device pointer
 299 *
 300 * Sets up work functions for hotplug and reset interrupts, enables MSI
 301 * functionality, initializes vblank, hotplug and reset interrupt handling.
 302 *
 303 * Returns:
 304 * 0 on success or error code on failure
 305 */
 306int amdgpu_irq_init(struct amdgpu_device *adev)
 307{
 308        int r = 0;
 309        unsigned int irq;
 310
 311        spin_lock_init(&adev->irq.lock);
 312
 313        /* Enable MSI if not disabled by module parameter */
 314        adev->irq.msi_enabled = false;
 315
 316        if (amdgpu_msi_ok(adev)) {
 317                int nvec = pci_msix_vec_count(adev->pdev);
 318                unsigned int flags;
 319
 320                if (nvec <= 0) {
 321                        flags = PCI_IRQ_MSI;
 322                } else {
 323                        flags = PCI_IRQ_MSI | PCI_IRQ_MSIX;
 324                }
 325                /* we only need one vector */
 326                nvec = pci_alloc_irq_vectors(adev->pdev, 1, 1, flags);
 327                if (nvec > 0) {
 328                        adev->irq.msi_enabled = true;
 329                        dev_dbg(adev->dev, "using MSI/MSI-X.\n");
 330                }
 331        }
 332
 333        if (!amdgpu_device_has_dc_support(adev)) {
 334                if (!adev->enable_virtual_display)
 335                        /* Disable vblank IRQs aggressively for power-saving */
 336                        /* XXX: can this be enabled for DC? */
 337                        adev_to_drm(adev)->vblank_disable_immediate = true;
 338
 339                r = drm_vblank_init(adev_to_drm(adev), adev->mode_info.num_crtc);
 340                if (r)
 341                        return r;
 342
 343                /* Pre-DCE11 */
 344                INIT_WORK(&adev->hotplug_work,
 345                                amdgpu_hotplug_work_func);
 346        }
 347
 348        INIT_WORK(&adev->irq.ih1_work, amdgpu_irq_handle_ih1);
 349        INIT_WORK(&adev->irq.ih2_work, amdgpu_irq_handle_ih2);
 350        INIT_WORK(&adev->irq.ih_soft_work, amdgpu_irq_handle_ih_soft);
 351
 352        /* Use vector 0 for MSI-X. */
 353        r = pci_irq_vector(adev->pdev, 0);
 354        if (r < 0)
 355                return r;
 356        irq = r;
 357
 358        /* PCI devices require shared interrupts. */
 359        r = request_irq(irq, amdgpu_irq_handler, IRQF_SHARED, adev_to_drm(adev)->driver->name,
 360                        adev_to_drm(adev));
 361        if (r) {
 362                if (!amdgpu_device_has_dc_support(adev))
 363                        flush_work(&adev->hotplug_work);
 364                return r;
 365        }
 366        adev->irq.installed = true;
 367        adev->irq.irq = irq;
 368        adev_to_drm(adev)->max_vblank_count = 0x00ffffff;
 369
 370        DRM_DEBUG("amdgpu: irq initialized.\n");
 371        return 0;
 372}
 373
 374
 375void amdgpu_irq_fini_hw(struct amdgpu_device *adev)
 376{
 377        if (adev->irq.installed) {
 378                free_irq(adev->irq.irq, adev_to_drm(adev));
 379                adev->irq.installed = false;
 380                if (adev->irq.msi_enabled)
 381                        pci_free_irq_vectors(adev->pdev);
 382
 383                if (!amdgpu_device_has_dc_support(adev))
 384                        flush_work(&adev->hotplug_work);
 385        }
 386
 387        amdgpu_ih_ring_fini(adev, &adev->irq.ih_soft);
 388        amdgpu_ih_ring_fini(adev, &adev->irq.ih);
 389        amdgpu_ih_ring_fini(adev, &adev->irq.ih1);
 390        amdgpu_ih_ring_fini(adev, &adev->irq.ih2);
 391}
 392
 393/**
 394 * amdgpu_irq_fini - shut down interrupt handling
 395 *
 396 * @adev: amdgpu device pointer
 397 *
 398 * Tears down work functions for hotplug and reset interrupts, disables MSI
 399 * functionality, shuts down vblank, hotplug and reset interrupt handling,
 400 * turns off interrupts from all sources (all ASICs).
 401 */
 402void amdgpu_irq_fini_sw(struct amdgpu_device *adev)
 403{
 404        unsigned i, j;
 405
 406        for (i = 0; i < AMDGPU_IRQ_CLIENTID_MAX; ++i) {
 407                if (!adev->irq.client[i].sources)
 408                        continue;
 409
 410                for (j = 0; j < AMDGPU_MAX_IRQ_SRC_ID; ++j) {
 411                        struct amdgpu_irq_src *src = adev->irq.client[i].sources[j];
 412
 413                        if (!src)
 414                                continue;
 415
 416                        kfree(src->enabled_types);
 417                        src->enabled_types = NULL;
 418                }
 419                kfree(adev->irq.client[i].sources);
 420                adev->irq.client[i].sources = NULL;
 421        }
 422}
 423
 424/**
 425 * amdgpu_irq_add_id - register IRQ source
 426 *
 427 * @adev: amdgpu device pointer
 428 * @client_id: client id
 429 * @src_id: source id
 430 * @source: IRQ source pointer
 431 *
 432 * Registers IRQ source on a client.
 433 *
 434 * Returns:
 435 * 0 on success or error code otherwise
 436 */
 437int amdgpu_irq_add_id(struct amdgpu_device *adev,
 438                      unsigned client_id, unsigned src_id,
 439                      struct amdgpu_irq_src *source)
 440{
 441        if (client_id >= AMDGPU_IRQ_CLIENTID_MAX)
 442                return -EINVAL;
 443
 444        if (src_id >= AMDGPU_MAX_IRQ_SRC_ID)
 445                return -EINVAL;
 446
 447        if (!source->funcs)
 448                return -EINVAL;
 449
 450        if (!adev->irq.client[client_id].sources) {
 451                adev->irq.client[client_id].sources =
 452                        kcalloc(AMDGPU_MAX_IRQ_SRC_ID,
 453                                sizeof(struct amdgpu_irq_src *),
 454                                GFP_KERNEL);
 455                if (!adev->irq.client[client_id].sources)
 456                        return -ENOMEM;
 457        }
 458
 459        if (adev->irq.client[client_id].sources[src_id] != NULL)
 460                return -EINVAL;
 461
 462        if (source->num_types && !source->enabled_types) {
 463                atomic_t *types;
 464
 465                types = kcalloc(source->num_types, sizeof(atomic_t),
 466                                GFP_KERNEL);
 467                if (!types)
 468                        return -ENOMEM;
 469
 470                source->enabled_types = types;
 471        }
 472
 473        adev->irq.client[client_id].sources[src_id] = source;
 474        return 0;
 475}
 476
 477/**
 478 * amdgpu_irq_dispatch - dispatch IRQ to IP blocks
 479 *
 480 * @adev: amdgpu device pointer
 481 * @ih: interrupt ring instance
 482 *
 483 * Dispatches IRQ to IP blocks.
 484 */
 485void amdgpu_irq_dispatch(struct amdgpu_device *adev,
 486                         struct amdgpu_ih_ring *ih)
 487{
 488        u32 ring_index = ih->rptr >> 2;
 489        struct amdgpu_iv_entry entry;
 490        unsigned client_id, src_id;
 491        struct amdgpu_irq_src *src;
 492        bool handled = false;
 493        int r;
 494
 495        entry.ih = ih;
 496        entry.iv_entry = (const uint32_t *)&ih->ring[ring_index];
 497        amdgpu_ih_decode_iv(adev, &entry);
 498
 499        trace_amdgpu_iv(ih - &adev->irq.ih, &entry);
 500
 501        client_id = entry.client_id;
 502        src_id = entry.src_id;
 503
 504        if (client_id >= AMDGPU_IRQ_CLIENTID_MAX) {
 505                DRM_DEBUG("Invalid client_id in IV: %d\n", client_id);
 506
 507        } else  if (src_id >= AMDGPU_MAX_IRQ_SRC_ID) {
 508                DRM_DEBUG("Invalid src_id in IV: %d\n", src_id);
 509
 510        } else if ((client_id == AMDGPU_IRQ_CLIENTID_LEGACY) &&
 511                   adev->irq.virq[src_id]) {
 512                generic_handle_domain_irq(adev->irq.domain, src_id);
 513
 514        } else if (!adev->irq.client[client_id].sources) {
 515                DRM_DEBUG("Unregistered interrupt client_id: %d src_id: %d\n",
 516                          client_id, src_id);
 517
 518        } else if ((src = adev->irq.client[client_id].sources[src_id])) {
 519                r = src->funcs->process(adev, src, &entry);
 520                if (r < 0)
 521                        DRM_ERROR("error processing interrupt (%d)\n", r);
 522                else if (r)
 523                        handled = true;
 524
 525        } else {
 526                DRM_DEBUG("Unhandled interrupt src_id: %d\n", src_id);
 527        }
 528
 529        /* Send it to amdkfd as well if it isn't already handled */
 530        if (!handled)
 531                amdgpu_amdkfd_interrupt(adev, entry.iv_entry);
 532}
 533
 534/**
 535 * amdgpu_irq_delegate - delegate IV to soft IH ring
 536 *
 537 * @adev: amdgpu device pointer
 538 * @entry: IV entry
 539 * @num_dw: size of IV
 540 *
 541 * Delegate the IV to the soft IH ring and schedule processing of it. Used
 542 * if the hardware delegation to IH1 or IH2 doesn't work for some reason.
 543 */
 544void amdgpu_irq_delegate(struct amdgpu_device *adev,
 545                         struct amdgpu_iv_entry *entry,
 546                         unsigned int num_dw)
 547{
 548        amdgpu_ih_ring_write(&adev->irq.ih_soft, entry->iv_entry, num_dw);
 549        schedule_work(&adev->irq.ih_soft_work);
 550}
 551
 552/**
 553 * amdgpu_irq_update - update hardware interrupt state
 554 *
 555 * @adev: amdgpu device pointer
 556 * @src: interrupt source pointer
 557 * @type: type of interrupt
 558 *
 559 * Updates interrupt state for the specific source (all ASICs).
 560 */
 561int amdgpu_irq_update(struct amdgpu_device *adev,
 562                             struct amdgpu_irq_src *src, unsigned type)
 563{
 564        unsigned long irqflags;
 565        enum amdgpu_interrupt_state state;
 566        int r;
 567
 568        spin_lock_irqsave(&adev->irq.lock, irqflags);
 569
 570        /* We need to determine after taking the lock, otherwise
 571           we might disable just enabled interrupts again */
 572        if (amdgpu_irq_enabled(adev, src, type))
 573                state = AMDGPU_IRQ_STATE_ENABLE;
 574        else
 575                state = AMDGPU_IRQ_STATE_DISABLE;
 576
 577        r = src->funcs->set(adev, src, type, state);
 578        spin_unlock_irqrestore(&adev->irq.lock, irqflags);
 579        return r;
 580}
 581
 582/**
 583 * amdgpu_irq_gpu_reset_resume_helper - update interrupt states on all sources
 584 *
 585 * @adev: amdgpu device pointer
 586 *
 587 * Updates state of all types of interrupts on all sources on resume after
 588 * reset.
 589 */
 590void amdgpu_irq_gpu_reset_resume_helper(struct amdgpu_device *adev)
 591{
 592        int i, j, k;
 593
 594        if (amdgpu_sriov_vf(adev) || amdgpu_passthrough(adev))
 595                amdgpu_restore_msix(adev);
 596
 597        for (i = 0; i < AMDGPU_IRQ_CLIENTID_MAX; ++i) {
 598                if (!adev->irq.client[i].sources)
 599                        continue;
 600
 601                for (j = 0; j < AMDGPU_MAX_IRQ_SRC_ID; ++j) {
 602                        struct amdgpu_irq_src *src = adev->irq.client[i].sources[j];
 603
 604                        if (!src || !src->funcs || !src->funcs->set)
 605                                continue;
 606                        for (k = 0; k < src->num_types; k++)
 607                                amdgpu_irq_update(adev, src, k);
 608                }
 609        }
 610}
 611
 612/**
 613 * amdgpu_irq_get - enable interrupt
 614 *
 615 * @adev: amdgpu device pointer
 616 * @src: interrupt source pointer
 617 * @type: type of interrupt
 618 *
 619 * Enables specified type of interrupt on the specified source (all ASICs).
 620 *
 621 * Returns:
 622 * 0 on success or error code otherwise
 623 */
 624int amdgpu_irq_get(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
 625                   unsigned type)
 626{
 627        if (!adev->irq.installed)
 628                return -ENOENT;
 629
 630        if (type >= src->num_types)
 631                return -EINVAL;
 632
 633        if (!src->enabled_types || !src->funcs->set)
 634                return -EINVAL;
 635
 636        if (atomic_inc_return(&src->enabled_types[type]) == 1)
 637                return amdgpu_irq_update(adev, src, type);
 638
 639        return 0;
 640}
 641
 642/**
 643 * amdgpu_irq_put - disable interrupt
 644 *
 645 * @adev: amdgpu device pointer
 646 * @src: interrupt source pointer
 647 * @type: type of interrupt
 648 *
 649 * Enables specified type of interrupt on the specified source (all ASICs).
 650 *
 651 * Returns:
 652 * 0 on success or error code otherwise
 653 */
 654int amdgpu_irq_put(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
 655                   unsigned type)
 656{
 657        if (!adev->irq.installed)
 658                return -ENOENT;
 659
 660        if (type >= src->num_types)
 661                return -EINVAL;
 662
 663        if (!src->enabled_types || !src->funcs->set)
 664                return -EINVAL;
 665
 666        if (atomic_dec_and_test(&src->enabled_types[type]))
 667                return amdgpu_irq_update(adev, src, type);
 668
 669        return 0;
 670}
 671
 672/**
 673 * amdgpu_irq_enabled - check whether interrupt is enabled or not
 674 *
 675 * @adev: amdgpu device pointer
 676 * @src: interrupt source pointer
 677 * @type: type of interrupt
 678 *
 679 * Checks whether the given type of interrupt is enabled on the given source.
 680 *
 681 * Returns:
 682 * *true* if interrupt is enabled, *false* if interrupt is disabled or on
 683 * invalid parameters
 684 */
 685bool amdgpu_irq_enabled(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
 686                        unsigned type)
 687{
 688        if (!adev->irq.installed)
 689                return false;
 690
 691        if (type >= src->num_types)
 692                return false;
 693
 694        if (!src->enabled_types || !src->funcs->set)
 695                return false;
 696
 697        return !!atomic_read(&src->enabled_types[type]);
 698}
 699
 700/* XXX: Generic IRQ handling */
 701static void amdgpu_irq_mask(struct irq_data *irqd)
 702{
 703        /* XXX */
 704}
 705
 706static void amdgpu_irq_unmask(struct irq_data *irqd)
 707{
 708        /* XXX */
 709}
 710
 711/* amdgpu hardware interrupt chip descriptor */
 712static struct irq_chip amdgpu_irq_chip = {
 713        .name = "amdgpu-ih",
 714        .irq_mask = amdgpu_irq_mask,
 715        .irq_unmask = amdgpu_irq_unmask,
 716};
 717
 718/**
 719 * amdgpu_irqdomain_map - create mapping between virtual and hardware IRQ numbers
 720 *
 721 * @d: amdgpu IRQ domain pointer (unused)
 722 * @irq: virtual IRQ number
 723 * @hwirq: hardware irq number
 724 *
 725 * Current implementation assigns simple interrupt handler to the given virtual
 726 * IRQ.
 727 *
 728 * Returns:
 729 * 0 on success or error code otherwise
 730 */
 731static int amdgpu_irqdomain_map(struct irq_domain *d,
 732                                unsigned int irq, irq_hw_number_t hwirq)
 733{
 734        if (hwirq >= AMDGPU_MAX_IRQ_SRC_ID)
 735                return -EPERM;
 736
 737        irq_set_chip_and_handler(irq,
 738                                 &amdgpu_irq_chip, handle_simple_irq);
 739        return 0;
 740}
 741
 742/* Implementation of methods for amdgpu IRQ domain */
 743static const struct irq_domain_ops amdgpu_hw_irqdomain_ops = {
 744        .map = amdgpu_irqdomain_map,
 745};
 746
 747/**
 748 * amdgpu_irq_add_domain - create a linear IRQ domain
 749 *
 750 * @adev: amdgpu device pointer
 751 *
 752 * Creates an IRQ domain for GPU interrupt sources
 753 * that may be driven by another driver (e.g., ACP).
 754 *
 755 * Returns:
 756 * 0 on success or error code otherwise
 757 */
 758int amdgpu_irq_add_domain(struct amdgpu_device *adev)
 759{
 760        adev->irq.domain = irq_domain_add_linear(NULL, AMDGPU_MAX_IRQ_SRC_ID,
 761                                                 &amdgpu_hw_irqdomain_ops, adev);
 762        if (!adev->irq.domain) {
 763                DRM_ERROR("GPU irq add domain failed\n");
 764                return -ENODEV;
 765        }
 766
 767        return 0;
 768}
 769
 770/**
 771 * amdgpu_irq_remove_domain - remove the IRQ domain
 772 *
 773 * @adev: amdgpu device pointer
 774 *
 775 * Removes the IRQ domain for GPU interrupt sources
 776 * that may be driven by another driver (e.g., ACP).
 777 */
 778void amdgpu_irq_remove_domain(struct amdgpu_device *adev)
 779{
 780        if (adev->irq.domain) {
 781                irq_domain_remove(adev->irq.domain);
 782                adev->irq.domain = NULL;
 783        }
 784}
 785
 786/**
 787 * amdgpu_irq_create_mapping - create mapping between domain Linux IRQs
 788 *
 789 * @adev: amdgpu device pointer
 790 * @src_id: IH source id
 791 *
 792 * Creates mapping between a domain IRQ (GPU IH src id) and a Linux IRQ
 793 * Use this for components that generate a GPU interrupt, but are driven
 794 * by a different driver (e.g., ACP).
 795 *
 796 * Returns:
 797 * Linux IRQ
 798 */
 799unsigned amdgpu_irq_create_mapping(struct amdgpu_device *adev, unsigned src_id)
 800{
 801        adev->irq.virq[src_id] = irq_create_mapping(adev->irq.domain, src_id);
 802
 803        return adev->irq.virq[src_id];
 804}
 805