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
);
130 generic_handle_domain_irq(part
->domain
, hwirq
);
132 chained_irq_exit(chip
, desc
);
135 static int partition_domain_alloc(struct irq_domain
*domain
, unsigned int virq
,
136 unsigned int nr_irqs
, void *arg
)
139 irq_hw_number_t hwirq
;
141 struct irq_fwspec
*fwspec
= arg
;
142 struct partition_desc
*part
;
144 BUG_ON(nr_irqs
!= 1);
145 ret
= domain
->ops
->translate(domain
, fwspec
, &hwirq
, &type
);
149 part
= domain
->host_data
;
151 set_bit(hwirq
, part
->bitmap
);
152 irq_set_chained_handler_and_data(irq_desc_get_irq(part
->chained_desc
),
153 partition_handle_irq
, part
);
154 irq_set_percpu_devid_partition(virq
, &part
->parts
[hwirq
].mask
);
155 irq_domain_set_info(domain
, virq
, hwirq
, &partition_irq_chip
, part
,
156 handle_percpu_devid_irq
, NULL
, NULL
);
157 irq_set_status_flags(virq
, IRQ_NOAUTOEN
);
162 static void partition_domain_free(struct irq_domain
*domain
, unsigned int virq
,
163 unsigned int nr_irqs
)
167 BUG_ON(nr_irqs
!= 1);
169 d
= irq_domain_get_irq_data(domain
, virq
);
170 irq_set_handler(virq
, NULL
);
171 irq_domain_reset_irq_data(d
);
174 int partition_translate_id(struct partition_desc
*desc
, void *partition_id
)
176 struct partition_affinity
*part
= NULL
;
179 for (i
= 0; i
< desc
->nr_parts
; i
++) {
180 if (desc
->parts
[i
].partition_id
== partition_id
) {
181 part
= &desc
->parts
[i
];
186 if (WARN_ON(!part
)) {
187 pr_err("Failed to find partition\n");
194 struct partition_desc
*partition_create_desc(struct fwnode_handle
*fwnode
,
195 struct partition_affinity
*parts
,
198 const struct irq_domain_ops
*ops
)
200 struct partition_desc
*desc
;
201 struct irq_domain
*d
;
203 BUG_ON(!ops
->select
|| !ops
->translate
);
205 desc
= kzalloc(sizeof(*desc
), GFP_KERNEL
);
210 desc
->ops
.free
= partition_domain_free
;
211 desc
->ops
.alloc
= partition_domain_alloc
;
213 d
= irq_domain_create_linear(fwnode
, nr_parts
, &desc
->ops
, desc
);
218 desc
->bitmap
= bitmap_zalloc(nr_parts
, GFP_KERNEL
);
219 if (WARN_ON(!desc
->bitmap
))
222 desc
->chained_desc
= irq_to_desc(chained_irq
);
223 desc
->nr_parts
= nr_parts
;
229 irq_domain_remove(d
);
235 struct irq_domain
*partition_get_domain(struct partition_desc
*dsc
)