diff options
author | Marc Zyngier <marc.zyngier@arm.com> | 2014-11-24 09:35:12 -0500 |
---|---|---|
committer | Jason Cooper <jason@lakedaemon.net> | 2014-11-26 10:55:13 -0500 |
commit | c48ed51c0d101ec4351530bdd6e1a01808f0a441 (patch) | |
tree | aeee90020039ca24df3fcdb88af4c35a39ee9bb7 /drivers/irqchip/irq-gic-v3-its.c | |
parent | cc2d3216f53c9fff0030eb71cacc4ce5f39d1d7e (diff) |
irqchip: GICv3: ITS: irqchip implementation
The usual methods that are used to present an irqchip to the rest
of the kernel
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Link: https://lkml.kernel.org/r/1416839720-18400-6-git-send-email-marc.zyngier@arm.com
Signed-off-by: Jason Cooper <jason@lakedaemon.net>
Diffstat (limited to 'drivers/irqchip/irq-gic-v3-its.c')
-rw-r--r-- | drivers/irqchip/irq-gic-v3-its.c | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index a5ab12c7d7fc..d24bebdfb064 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c | |||
@@ -40,6 +40,8 @@ | |||
40 | 40 | ||
41 | #define ITS_FLAGS_CMDQ_NEEDS_FLUSHING (1 << 0) | 41 | #define ITS_FLAGS_CMDQ_NEEDS_FLUSHING (1 << 0) |
42 | 42 | ||
43 | #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0) | ||
44 | |||
43 | /* | 45 | /* |
44 | * Collection structure - just an ID, and a redistributor address to | 46 | * Collection structure - just an ID, and a redistributor address to |
45 | * ping. We use one per CPU as a bag of interrupts assigned to this | 47 | * ping. We use one per CPU as a bag of interrupts assigned to this |
@@ -509,3 +511,78 @@ static void its_send_invall(struct its_node *its, struct its_collection *col) | |||
509 | 511 | ||
510 | its_send_single_command(its, its_build_invall_cmd, &desc); | 512 | its_send_single_command(its, its_build_invall_cmd, &desc); |
511 | } | 513 | } |
514 | |||
515 | /* | ||
516 | * irqchip functions - assumes MSI, mostly. | ||
517 | */ | ||
518 | |||
519 | static inline u32 its_get_event_id(struct irq_data *d) | ||
520 | { | ||
521 | struct its_device *its_dev = irq_data_get_irq_chip_data(d); | ||
522 | return d->hwirq - its_dev->lpi_base; | ||
523 | } | ||
524 | |||
525 | static void lpi_set_config(struct irq_data *d, bool enable) | ||
526 | { | ||
527 | struct its_device *its_dev = irq_data_get_irq_chip_data(d); | ||
528 | irq_hw_number_t hwirq = d->hwirq; | ||
529 | u32 id = its_get_event_id(d); | ||
530 | u8 *cfg = page_address(gic_rdists->prop_page) + hwirq - 8192; | ||
531 | |||
532 | if (enable) | ||
533 | *cfg |= LPI_PROP_ENABLED; | ||
534 | else | ||
535 | *cfg &= ~LPI_PROP_ENABLED; | ||
536 | |||
537 | /* | ||
538 | * Make the above write visible to the redistributors. | ||
539 | * And yes, we're flushing exactly: One. Single. Byte. | ||
540 | * Humpf... | ||
541 | */ | ||
542 | if (gic_rdists->flags & RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING) | ||
543 | __flush_dcache_area(cfg, sizeof(*cfg)); | ||
544 | else | ||
545 | dsb(ishst); | ||
546 | its_send_inv(its_dev, id); | ||
547 | } | ||
548 | |||
549 | static void its_mask_irq(struct irq_data *d) | ||
550 | { | ||
551 | lpi_set_config(d, false); | ||
552 | } | ||
553 | |||
554 | static void its_unmask_irq(struct irq_data *d) | ||
555 | { | ||
556 | lpi_set_config(d, true); | ||
557 | } | ||
558 | |||
559 | static void its_eoi_irq(struct irq_data *d) | ||
560 | { | ||
561 | gic_write_eoir(d->hwirq); | ||
562 | } | ||
563 | |||
564 | static int its_set_affinity(struct irq_data *d, const struct cpumask *mask_val, | ||
565 | bool force) | ||
566 | { | ||
567 | unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask); | ||
568 | struct its_device *its_dev = irq_data_get_irq_chip_data(d); | ||
569 | struct its_collection *target_col; | ||
570 | u32 id = its_get_event_id(d); | ||
571 | |||
572 | if (cpu >= nr_cpu_ids) | ||
573 | return -EINVAL; | ||
574 | |||
575 | target_col = &its_dev->its->collections[cpu]; | ||
576 | its_send_movi(its_dev, target_col, id); | ||
577 | its_dev->collection = target_col; | ||
578 | |||
579 | return IRQ_SET_MASK_OK_DONE; | ||
580 | } | ||
581 | |||
582 | static struct irq_chip its_irq_chip = { | ||
583 | .name = "ITS", | ||
584 | .irq_mask = its_mask_irq, | ||
585 | .irq_unmask = its_unmask_irq, | ||
586 | .irq_eoi = its_eoi_irq, | ||
587 | .irq_set_affinity = its_set_affinity, | ||
588 | }; | ||