aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c108
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cik_ih.c6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cz_ih.c7
-rw-r--r--drivers/gpu/drm/amd/amdgpu/iceland_ih.c7
-rw-r--r--drivers/gpu/drm/amd/amdgpu/tonga_ih.c7
6 files changed, 136 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}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h
index 17b01aef4278..e124b59f39c1 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h
@@ -24,6 +24,7 @@
24#ifndef __AMDGPU_IRQ_H__ 24#ifndef __AMDGPU_IRQ_H__
25#define __AMDGPU_IRQ_H__ 25#define __AMDGPU_IRQ_H__
26 26
27#include <linux/irqdomain.h>
27#include "amdgpu_ih.h" 28#include "amdgpu_ih.h"
28 29
29#define AMDGPU_MAX_IRQ_SRC_ID 0x100 30#define AMDGPU_MAX_IRQ_SRC_ID 0x100
@@ -65,6 +66,10 @@ struct amdgpu_irq {
65 /* interrupt ring */ 66 /* interrupt ring */
66 struct amdgpu_ih_ring ih; 67 struct amdgpu_ih_ring ih;
67 const struct amdgpu_ih_funcs *ih_funcs; 68 const struct amdgpu_ih_funcs *ih_funcs;
69
70 /* gen irq stuff */
71 struct irq_domain *domain; /* GPU irq controller domain */
72 unsigned virq[AMDGPU_MAX_IRQ_SRC_ID];
68}; 73};
69 74
70void amdgpu_irq_preinstall(struct drm_device *dev); 75void amdgpu_irq_preinstall(struct drm_device *dev);
@@ -90,4 +95,8 @@ int amdgpu_irq_put(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
90bool amdgpu_irq_enabled(struct amdgpu_device *adev, struct amdgpu_irq_src *src, 95bool amdgpu_irq_enabled(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
91 unsigned type); 96 unsigned type);
92 97
98int amdgpu_irq_add_domain(struct amdgpu_device *adev);
99void amdgpu_irq_remove_domain(struct amdgpu_device *adev);
100unsigned amdgpu_irq_create_mapping(struct amdgpu_device *adev, unsigned src_id);
101
93#endif 102#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/cik_ih.c b/drivers/gpu/drm/amd/amdgpu/cik_ih.c
index 8993c50cb89f..30c9b3beeef9 100644
--- a/drivers/gpu/drm/amd/amdgpu/cik_ih.c
+++ b/drivers/gpu/drm/amd/amdgpu/cik_ih.c
@@ -274,6 +274,11 @@ static void cik_ih_set_rptr(struct amdgpu_device *adev)
274static int cik_ih_early_init(void *handle) 274static int cik_ih_early_init(void *handle)
275{ 275{
276 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 276 struct amdgpu_device *adev = (struct amdgpu_device *)handle;
277 int ret;
278
279 ret = amdgpu_irq_add_domain(adev);
280 if (ret)
281 return ret;
277 282
278 cik_ih_set_interrupt_funcs(adev); 283 cik_ih_set_interrupt_funcs(adev);
279 284
@@ -300,6 +305,7 @@ static int cik_ih_sw_fini(void *handle)
300 305
301 amdgpu_irq_fini(adev); 306 amdgpu_irq_fini(adev);
302 amdgpu_ih_ring_fini(adev); 307 amdgpu_ih_ring_fini(adev);
308 amdgpu_irq_remove_domain(adev);
303 309
304 return 0; 310 return 0;
305} 311}
diff --git a/drivers/gpu/drm/amd/amdgpu/cz_ih.c b/drivers/gpu/drm/amd/amdgpu/cz_ih.c
index bc751bfbcae2..c79638f8e732 100644
--- a/drivers/gpu/drm/amd/amdgpu/cz_ih.c
+++ b/drivers/gpu/drm/amd/amdgpu/cz_ih.c
@@ -253,8 +253,14 @@ static void cz_ih_set_rptr(struct amdgpu_device *adev)
253static int cz_ih_early_init(void *handle) 253static int cz_ih_early_init(void *handle)
254{ 254{
255 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 255 struct amdgpu_device *adev = (struct amdgpu_device *)handle;
256 int ret;
257
258 ret = amdgpu_irq_add_domain(adev);
259 if (ret)
260 return ret;
256 261
257 cz_ih_set_interrupt_funcs(adev); 262 cz_ih_set_interrupt_funcs(adev);
263
258 return 0; 264 return 0;
259} 265}
260 266
@@ -278,6 +284,7 @@ static int cz_ih_sw_fini(void *handle)
278 284
279 amdgpu_irq_fini(adev); 285 amdgpu_irq_fini(adev);
280 amdgpu_ih_ring_fini(adev); 286 amdgpu_ih_ring_fini(adev);
287 amdgpu_irq_remove_domain(adev);
281 288
282 return 0; 289 return 0;
283} 290}
diff --git a/drivers/gpu/drm/amd/amdgpu/iceland_ih.c b/drivers/gpu/drm/amd/amdgpu/iceland_ih.c
index 779532d350ff..679e7394a495 100644
--- a/drivers/gpu/drm/amd/amdgpu/iceland_ih.c
+++ b/drivers/gpu/drm/amd/amdgpu/iceland_ih.c
@@ -253,8 +253,14 @@ static void iceland_ih_set_rptr(struct amdgpu_device *adev)
253static int iceland_ih_early_init(void *handle) 253static int iceland_ih_early_init(void *handle)
254{ 254{
255 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 255 struct amdgpu_device *adev = (struct amdgpu_device *)handle;
256 int ret;
257
258 ret = amdgpu_irq_add_domain(adev);
259 if (ret)
260 return ret;
256 261
257 iceland_ih_set_interrupt_funcs(adev); 262 iceland_ih_set_interrupt_funcs(adev);
263
258 return 0; 264 return 0;
259} 265}
260 266
@@ -278,6 +284,7 @@ static int iceland_ih_sw_fini(void *handle)
278 284
279 amdgpu_irq_fini(adev); 285 amdgpu_irq_fini(adev);
280 amdgpu_ih_ring_fini(adev); 286 amdgpu_ih_ring_fini(adev);
287 amdgpu_irq_remove_domain(adev);
281 288
282 return 0; 289 return 0;
283} 290}
diff --git a/drivers/gpu/drm/amd/amdgpu/tonga_ih.c b/drivers/gpu/drm/amd/amdgpu/tonga_ih.c
index 743c372837aa..b6f7d7bff929 100644
--- a/drivers/gpu/drm/amd/amdgpu/tonga_ih.c
+++ b/drivers/gpu/drm/amd/amdgpu/tonga_ih.c
@@ -273,8 +273,14 @@ static void tonga_ih_set_rptr(struct amdgpu_device *adev)
273static int tonga_ih_early_init(void *handle) 273static int tonga_ih_early_init(void *handle)
274{ 274{
275 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 275 struct amdgpu_device *adev = (struct amdgpu_device *)handle;
276 int ret;
277
278 ret = amdgpu_irq_add_domain(adev);
279 if (ret)
280 return ret;
276 281
277 tonga_ih_set_interrupt_funcs(adev); 282 tonga_ih_set_interrupt_funcs(adev);
283
278 return 0; 284 return 0;
279} 285}
280 286
@@ -301,6 +307,7 @@ static int tonga_ih_sw_fini(void *handle)
301 307
302 amdgpu_irq_fini(adev); 308 amdgpu_irq_fini(adev);
303 amdgpu_ih_ring_fini(adev); 309 amdgpu_ih_ring_fini(adev);
310 amdgpu_irq_add_domain(adev);
304 311
305 return 0; 312 return 0;
306} 313}