diff options
author | Alex Deucher <alexander.deucher@amd.com> | 2015-11-06 01:29:08 -0500 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2016-01-11 09:52:57 -0500 |
commit | 5f2323658e4829ffb893553297e64795a90cbcd9 (patch) | |
tree | 7862a0b646c43f8e525eca9a98e2705bdd0bbb77 | |
parent | ba228ac8f512c9cd09cb4245c424ab1632da0c24 (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.c | 108 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/cik_ih.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/cz_ih.c | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/iceland_ih.c | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/tonga_ih.c | 7 |
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 */ | ||
471 | static void amdgpu_irq_mask(struct irq_data *irqd) | ||
472 | { | ||
473 | /* XXX */ | ||
474 | } | ||
475 | |||
476 | static void amdgpu_irq_unmask(struct irq_data *irqd) | ||
477 | { | ||
478 | /* XXX */ | ||
479 | } | ||
480 | |||
481 | static struct irq_chip amdgpu_irq_chip = { | ||
482 | .name = "amdgpu-ih", | ||
483 | .irq_mask = amdgpu_irq_mask, | ||
484 | .irq_unmask = amdgpu_irq_unmask, | ||
485 | }; | ||
486 | |||
487 | static 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 | |||
498 | static 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 | */ | ||
510 | int 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 | */ | ||
530 | void 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 | */ | ||
550 | unsigned 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 | ||
70 | void amdgpu_irq_preinstall(struct drm_device *dev); | 75 | void amdgpu_irq_preinstall(struct drm_device *dev); |
@@ -90,4 +95,8 @@ int amdgpu_irq_put(struct amdgpu_device *adev, struct amdgpu_irq_src *src, | |||
90 | bool amdgpu_irq_enabled(struct amdgpu_device *adev, struct amdgpu_irq_src *src, | 95 | bool amdgpu_irq_enabled(struct amdgpu_device *adev, struct amdgpu_irq_src *src, |
91 | unsigned type); | 96 | unsigned type); |
92 | 97 | ||
98 | int amdgpu_irq_add_domain(struct amdgpu_device *adev); | ||
99 | void amdgpu_irq_remove_domain(struct amdgpu_device *adev); | ||
100 | unsigned 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) | |||
274 | static int cik_ih_early_init(void *handle) | 274 | static 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) | |||
253 | static int cz_ih_early_init(void *handle) | 253 | static 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) | |||
253 | static int iceland_ih_early_init(void *handle) | 253 | static 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) | |||
273 | static int tonga_ih_early_init(void *handle) | 273 | static 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 | } |