aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/irqchip/irq-gic-v3-its.c
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2014-11-24 09:35:12 -0500
committerJason Cooper <jason@lakedaemon.net>2014-11-26 10:55:13 -0500
commitc48ed51c0d101ec4351530bdd6e1a01808f0a441 (patch)
treeaeee90020039ca24df3fcdb88af4c35a39ee9bb7 /drivers/irqchip/irq-gic-v3-its.c
parentcc2d3216f53c9fff0030eb71cacc4ce5f39d1d7e (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.c77
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
519static 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
525static 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
549static void its_mask_irq(struct irq_data *d)
550{
551 lpi_set_config(d, false);
552}
553
554static void its_unmask_irq(struct irq_data *d)
555{
556 lpi_set_config(d, true);
557}
558
559static void its_eoi_irq(struct irq_data *d)
560{
561 gic_write_eoir(d->hwirq);
562}
563
564static 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
582static 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};