aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
diff options
context:
space:
mode:
authorAlex Deucher <alexander.deucher@amd.com>2015-11-06 01:29:08 -0500
committerAlex Deucher <alexander.deucher@amd.com>2016-01-11 09:52:57 -0500
commit5f2323658e4829ffb893553297e64795a90cbcd9 (patch)
tree7862a0b646c43f8e525eca9a98e2705bdd0bbb77 /drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
parentba228ac8f512c9cd09cb4245c424ab1632da0c24 (diff)
drm/amdgpu: add irq domain support
Hardware blocks on the GPU like ACP generate interrupts in the GPU interrupt controller, but are driven by a separate driver. Add an irq domain to the GPU driver so that blocks like ACP can register a Linux interrupt. Acked-by: Dave Airlie <airlied@redhat.com> Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c')
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c108
1 files changed, 100 insertions, 8 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
index 7c42ff670080..3006182c5d0d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
@@ -312,6 +312,7 @@ int amdgpu_irq_add_id(struct amdgpu_device *adev, unsigned src_id,
312 } 312 }
313 313
314 adev->irq.sources[src_id] = source; 314 adev->irq.sources[src_id] = source;
315
315 return 0; 316 return 0;
316} 317}
317 318
@@ -335,15 +336,19 @@ void amdgpu_irq_dispatch(struct amdgpu_device *adev,
335 return; 336 return;
336 } 337 }
337 338
338 src = adev->irq.sources[src_id]; 339 if (adev->irq.virq[src_id]) {
339 if (!src) { 340 generic_handle_irq(irq_find_mapping(adev->irq.domain, src_id));
340 DRM_DEBUG("Unhandled interrupt src_id: %d\n", src_id); 341 } else {
341 return; 342 src = adev->irq.sources[src_id];
342 } 343 if (!src) {
344 DRM_DEBUG("Unhandled interrupt src_id: %d\n", src_id);
345 return;
346 }
343 347
344 r = src->funcs->process(adev, src, entry); 348 r = src->funcs->process(adev, src, entry);
345 if (r) 349 if (r)
346 DRM_ERROR("error processing interrupt (%d)\n", r); 350 DRM_ERROR("error processing interrupt (%d)\n", r);
351 }
347} 352}
348 353
349/** 354/**
@@ -461,3 +466,90 @@ bool amdgpu_irq_enabled(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
461 466
462 return !!atomic_read(&src->enabled_types[type]); 467 return !!atomic_read(&src->enabled_types[type]);
463} 468}
469
470/* gen irq */
471static void amdgpu_irq_mask(struct irq_data *irqd)
472{
473 /* XXX */
474}
475
476static void amdgpu_irq_unmask(struct irq_data *irqd)
477{
478 /* XXX */
479}
480
481static struct irq_chip amdgpu_irq_chip = {
482 .name = "amdgpu-ih",
483 .irq_mask = amdgpu_irq_mask,
484 .irq_unmask = amdgpu_irq_unmask,
485};
486
487static int amdgpu_irqdomain_map(struct irq_domain *d,
488 unsigned int irq, irq_hw_number_t hwirq)
489{
490 if (hwirq >= AMDGPU_MAX_IRQ_SRC_ID)
491 return -EPERM;
492
493 irq_set_chip_and_handler(irq,
494 &amdgpu_irq_chip, handle_simple_irq);
495 return 0;
496}
497
498static struct irq_domain_ops amdgpu_hw_irqdomain_ops = {
499 .map = amdgpu_irqdomain_map,
500};
501
502/**
503 * amdgpu_irq_add_domain - create a linear irq domain
504 *
505 * @adev: amdgpu device pointer
506 *
507 * Create an irq domain for GPU interrupt sources
508 * that may be driven by another driver (e.g., ACP).
509 */
510int amdgpu_irq_add_domain(struct amdgpu_device *adev)
511{
512 adev->irq.domain = irq_domain_add_linear(NULL, AMDGPU_MAX_IRQ_SRC_ID,
513 &amdgpu_hw_irqdomain_ops, adev);
514 if (!adev->irq.domain) {
515 DRM_ERROR("GPU irq add domain failed\n");
516 return -ENODEV;
517 }
518
519 return 0;
520}
521
522/**
523 * amdgpu_irq_remove_domain - remove the irq domain
524 *
525 * @adev: amdgpu device pointer
526 *
527 * Remove the irq domain for GPU interrupt sources
528 * that may be driven by another driver (e.g., ACP).
529 */
530void amdgpu_irq_remove_domain(struct amdgpu_device *adev)
531{
532 if (adev->irq.domain) {
533 irq_domain_remove(adev->irq.domain);
534 adev->irq.domain = NULL;
535 }
536}
537
538/**
539 * amdgpu_irq_create_mapping - create a mapping between a domain irq and a
540 * Linux irq
541 *
542 * @adev: amdgpu device pointer
543 * @src_id: IH source id
544 *
545 * Create a mapping between a domain irq (GPU IH src id) and a Linux irq
546 * Use this for components that generate a GPU interrupt, but are driven
547 * by a different driver (e.g., ACP).
548 * Returns the Linux irq.
549 */
550unsigned amdgpu_irq_create_mapping(struct amdgpu_device *adev, unsigned src_id)
551{
552 adev->irq.virq[src_id] = irq_create_mapping(adev->irq.domain, src_id);
553
554 return adev->irq.virq[src_id];
555}