1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2016 ARM Limited, All Rights Reserved.
4 * Author: Marc Zyngier <marc.zyngier@arm.com>
7 #include <linux/bitops.h>
8 #include <linux/interrupt.h>
9 #include <linux/irqchip.h>
10 #include <linux/irqchip/chained_irq.h>
11 #include <linux/irqchip/irq-partition-percpu.h>
12 #include <linux/irqdomain.h>
13 #include <linux/seq_file.h>
14 #include <linux/slab.h>
16 struct partition_desc
{
18 struct partition_affinity
*parts
;
19 struct irq_domain
*domain
;
20 struct irq_desc
*chained_desc
;
21 unsigned long *bitmap
;
22 struct irq_domain_ops ops
;
25 static bool partition_check_cpu(struct partition_desc
*part
,
26 unsigned int cpu
, unsigned int hwirq
)
28 return cpumask_test_cpu(cpu
, &part
->parts
[hwirq
].mask
);
31 static void partition_irq_mask(struct irq_data
*d
)
33 struct partition_desc
*part
= irq_data_get_irq_chip_data(d
);
34 struct irq_chip
*chip
= irq_desc_get_chip(part
->chained_desc
);
35 struct irq_data
*data
= irq_desc_get_irq_data(part
->chained_desc
);
37 if (partition_check_cpu(part
, smp_processor_id(), d
->hwirq
) &&
42 static void partition_irq_unmask(struct irq_data
*d
)
44 struct partition_desc
*part
= irq_data_get_irq_chip_data(d
);
45 struct irq_chip
*chip
= irq_desc_get_chip(part
->chained_desc
);
46 struct irq_data
*data
= irq_desc_get_irq_data(part
->chained_desc
);
48 if (partition_check_cpu(part
, smp_processor_id(), d
->hwirq
) &&
50 chip
->irq_unmask(data
);
53 static int partition_irq_set_irqchip_state(struct irq_data
*d
,
54 enum irqchip_irq_state which
,
57 struct partition_desc
*part
= irq_data_get_irq_chip_data(d
);
58 struct irq_chip
*chip
= irq_desc_get_chip(part
->chained_desc
);
59 struct irq_data
*data
= irq_desc_get_irq_data(part
->chained_desc
);
61 if (partition_check_cpu(part
, smp_processor_id(), d
->hwirq
) &&
62 chip
->irq_set_irqchip_state
)
63 return chip
->irq_set_irqchip_state(data
, which
, val
);
68 static int partition_irq_get_irqchip_state(struct irq_data
*d
,
69 enum irqchip_irq_state which
,
72 struct partition_desc
*part
= irq_data_get_irq_chip_data(d
);
73 struct irq_chip
*chip
= irq_desc_get_chip(part
->chained_desc
);
74 struct irq_data
*data
= irq_desc_get_irq_data(part
->chained_desc
);
76 if (partition_check_cpu(part
, smp_processor_id(), d
->hwirq
) &&
77 chip
->irq_get_irqchip_state
)
78 return chip
->irq_get_irqchip_state(data
, which
, val
);
83 static int partition_irq_set_type(struct irq_data
*d
, unsigned int type
)
85 struct partition_desc
*part
= irq_data_get_irq_chip_data(d
);
86 struct irq_chip
*chip
= irq_desc_get_chip(part
->chained_desc
);
87 struct irq_data
*data
= irq_desc_get_irq_data(part
->chained_desc
);
89 if (chip
->irq_set_type
)
90 return chip
->irq_set_type(data
, type
);
95 static void partition_irq_print_chip(struct irq_data
*d
, struct seq_file
*p
)
97 struct partition_desc
*part
= irq_data_get_irq_chip_data(d
);
98 struct irq_chip
*chip
= irq_desc_get_chip(part
->chained_desc
);
99 struct irq_data
*data
= irq_desc_get_irq_data(part
->chained_desc
);
101 seq_printf(p
, " %5s-%lu", chip
->name
, data
->hwirq
);
104 static struct irq_chip partition_irq_chip
= {
105 .irq_mask
= partition_irq_mask
,
106 .irq_unmask
= partition_irq_unmask
,
107 .irq_set_type
= partition_irq_set_type
,
108 .irq_get_irqchip_state
= partition_irq_get_irqchip_state
,
109 .irq_set_irqchip_state
= partition_irq_set_irqchip_state
,
110 .irq_print_chip
= partition_irq_print_chip
,
113 static void partition_handle_irq(struct irq_desc
*desc
)
115 struct partition_desc
*part
= irq_desc_get_handler_data(desc
);
116 struct irq_chip
*chip
= irq_desc_get_chip(desc
);
117 int cpu
= smp_processor_id();
120 chained_irq_enter(chip
, desc
);
122 for_each_set_bit(hwirq
, part
->bitmap
, part
->nr_parts
) {
123 if (partition_check_cpu(part
, cpu
, hwirq
))
127 if (unlikely(hwirq
== part
->nr_parts
)) {
128 handle_bad_irq(desc
);
131 irq
= irq_find_mapping(part
->domain
, hwirq
);
132 generic_handle_irq(irq
);
135 chained_irq_exit(chip
, desc
);
138 static int partition_domain_alloc(struct irq_domain
*domain
, unsigned int virq
,
139 unsigned int nr_irqs
, void *arg
)
142 irq_hw_number_t hwirq
;
144 struct irq_fwspec
*fwspec
= arg
;
145 struct partition_desc
*part
;
147 BUG_ON(nr_irqs
!= 1);
148 ret
= domain
->ops
->translate(domain
, fwspec
, &hwirq
, &type
);
152 part
= domain
->host_data
;
154 set_bit(hwirq
, part
->bitmap
);
155 irq_set_chained_handler_and_data(irq_desc_get_irq(part
->chained_desc
),
156 partition_handle_irq
, part
);
157 irq_set_percpu_devid_partition(virq
, &part
->parts
[hwirq
].mask
);
158 irq_domain_set_info(domain
, virq
, hwirq
, &partition_irq_chip
, part
,
159 handle_percpu_devid_irq
, NULL
, NULL
);
160 irq_set_status_flags(virq
, IRQ_NOAUTOEN
);
165 static void partition_domain_free(struct irq_domain
*domain
, unsigned int virq
,
166 unsigned int nr_irqs
)
170 BUG_ON(nr_irqs
!= 1);
172 d
= irq_domain_get_irq_data(domain
, virq
);
173 irq_set_handler(virq
, NULL
);
174 irq_domain_reset_irq_data(d
);
177 int partition_translate_id(struct partition_desc
*desc
, void *partition_id
)
179 struct partition_affinity
*part
= NULL
;
182 for (i
= 0; i
< desc
->nr_parts
; i
++) {
183 if (desc
->parts
[i
].partition_id
== partition_id
) {
184 part
= &desc
->parts
[i
];
189 if (WARN_ON(!part
)) {
190 pr_err("Failed to find partition\n");
197 struct partition_desc
*partition_create_desc(struct fwnode_handle
*fwnode
,
198 struct partition_affinity
*parts
,
201 const struct irq_domain_ops
*ops
)
203 struct partition_desc
*desc
;
204 struct irq_domain
*d
;
206 BUG_ON(!ops
->select
|| !ops
->translate
);
208 desc
= kzalloc(sizeof(*desc
), GFP_KERNEL
);
213 desc
->ops
.free
= partition_domain_free
;
214 desc
->ops
.alloc
= partition_domain_alloc
;
216 d
= irq_domain_create_linear(fwnode
, nr_parts
, &desc
->ops
, desc
);
221 desc
->bitmap
= kcalloc(BITS_TO_LONGS(nr_parts
), sizeof(long),
223 if (WARN_ON(!desc
->bitmap
))
226 desc
->chained_desc
= irq_to_desc(chained_irq
);
227 desc
->nr_parts
= nr_parts
;
233 irq_domain_remove(d
);
239 struct irq_domain
*partition_get_domain(struct partition_desc
*dsc
)