1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2017-2018 Bartosz Golaszewski <brgl@bgdev.pl>
4 * Copyright (C) 2020 Bartosz Golaszewski <bgolaszewski@baylibre.com>
7 #include <linux/cleanup.h>
8 #include <linux/interrupt.h>
10 #include <linux/irq_sim.h>
11 #include <linux/irq_work.h>
12 #include <linux/slab.h>
14 struct irq_sim_work_ctx
{
16 unsigned int irq_count
;
17 unsigned long *pending
;
18 struct irq_domain
*domain
;
19 struct irq_sim_ops ops
;
23 struct irq_sim_irq_ctx
{
25 struct irq_sim_work_ctx
*work_ctx
;
28 static void irq_sim_irqmask(struct irq_data
*data
)
30 struct irq_sim_irq_ctx
*irq_ctx
= irq_data_get_irq_chip_data(data
);
32 irq_ctx
->enabled
= false;
35 static void irq_sim_irqunmask(struct irq_data
*data
)
37 struct irq_sim_irq_ctx
*irq_ctx
= irq_data_get_irq_chip_data(data
);
39 irq_ctx
->enabled
= true;
42 static int irq_sim_set_type(struct irq_data
*data
, unsigned int type
)
44 /* We only support rising and falling edge trigger types. */
45 if (type
& ~IRQ_TYPE_EDGE_BOTH
)
48 irqd_set_trigger_type(data
, type
);
53 static int irq_sim_get_irqchip_state(struct irq_data
*data
,
54 enum irqchip_irq_state which
, bool *state
)
56 struct irq_sim_irq_ctx
*irq_ctx
= irq_data_get_irq_chip_data(data
);
57 irq_hw_number_t hwirq
= irqd_to_hwirq(data
);
60 case IRQCHIP_STATE_PENDING
:
62 *state
= test_bit(hwirq
, irq_ctx
->work_ctx
->pending
);
71 static int irq_sim_set_irqchip_state(struct irq_data
*data
,
72 enum irqchip_irq_state which
, bool state
)
74 struct irq_sim_irq_ctx
*irq_ctx
= irq_data_get_irq_chip_data(data
);
75 irq_hw_number_t hwirq
= irqd_to_hwirq(data
);
78 case IRQCHIP_STATE_PENDING
:
79 if (irq_ctx
->enabled
) {
80 assign_bit(hwirq
, irq_ctx
->work_ctx
->pending
, state
);
82 irq_work_queue(&irq_ctx
->work_ctx
->work
);
92 static int irq_sim_request_resources(struct irq_data
*data
)
94 struct irq_sim_irq_ctx
*irq_ctx
= irq_data_get_irq_chip_data(data
);
95 struct irq_sim_work_ctx
*work_ctx
= irq_ctx
->work_ctx
;
96 irq_hw_number_t hwirq
= irqd_to_hwirq(data
);
98 if (work_ctx
->ops
.irq_sim_irq_requested
)
99 return work_ctx
->ops
.irq_sim_irq_requested(work_ctx
->domain
,
101 work_ctx
->user_data
);
106 static void irq_sim_release_resources(struct irq_data
*data
)
108 struct irq_sim_irq_ctx
*irq_ctx
= irq_data_get_irq_chip_data(data
);
109 struct irq_sim_work_ctx
*work_ctx
= irq_ctx
->work_ctx
;
110 irq_hw_number_t hwirq
= irqd_to_hwirq(data
);
112 if (work_ctx
->ops
.irq_sim_irq_released
)
113 work_ctx
->ops
.irq_sim_irq_released(work_ctx
->domain
, hwirq
,
114 work_ctx
->user_data
);
117 static struct irq_chip irq_sim_irqchip
= {
119 .irq_mask
= irq_sim_irqmask
,
120 .irq_unmask
= irq_sim_irqunmask
,
121 .irq_set_type
= irq_sim_set_type
,
122 .irq_get_irqchip_state
= irq_sim_get_irqchip_state
,
123 .irq_set_irqchip_state
= irq_sim_set_irqchip_state
,
124 .irq_request_resources
= irq_sim_request_resources
,
125 .irq_release_resources
= irq_sim_release_resources
,
128 static void irq_sim_handle_irq(struct irq_work
*work
)
130 struct irq_sim_work_ctx
*work_ctx
;
131 unsigned int offset
= 0;
134 work_ctx
= container_of(work
, struct irq_sim_work_ctx
, work
);
136 while (!bitmap_empty(work_ctx
->pending
, work_ctx
->irq_count
)) {
137 offset
= find_next_bit(work_ctx
->pending
,
138 work_ctx
->irq_count
, offset
);
139 clear_bit(offset
, work_ctx
->pending
);
140 irqnum
= irq_find_mapping(work_ctx
->domain
, offset
);
141 handle_simple_irq(irq_to_desc(irqnum
));
145 static int irq_sim_domain_map(struct irq_domain
*domain
,
146 unsigned int virq
, irq_hw_number_t hw
)
148 struct irq_sim_work_ctx
*work_ctx
= domain
->host_data
;
149 struct irq_sim_irq_ctx
*irq_ctx
;
151 irq_ctx
= kzalloc(sizeof(*irq_ctx
), GFP_KERNEL
);
155 irq_set_chip(virq
, &irq_sim_irqchip
);
156 irq_set_chip_data(virq
, irq_ctx
);
157 irq_set_handler(virq
, handle_simple_irq
);
158 irq_modify_status(virq
, IRQ_NOREQUEST
| IRQ_NOAUTOEN
, IRQ_NOPROBE
);
159 irq_ctx
->work_ctx
= work_ctx
;
164 static void irq_sim_domain_unmap(struct irq_domain
*domain
, unsigned int virq
)
166 struct irq_sim_irq_ctx
*irq_ctx
;
167 struct irq_data
*irqd
;
169 irqd
= irq_domain_get_irq_data(domain
, virq
);
170 irq_ctx
= irq_data_get_irq_chip_data(irqd
);
172 irq_set_handler(virq
, NULL
);
173 irq_domain_reset_irq_data(irqd
);
177 static const struct irq_domain_ops irq_sim_domain_ops
= {
178 .map
= irq_sim_domain_map
,
179 .unmap
= irq_sim_domain_unmap
,
183 * irq_domain_create_sim - Create a new interrupt simulator irq_domain and
184 * allocate a range of dummy interrupts.
186 * @fwnode: struct fwnode_handle to be associated with this domain.
187 * @num_irqs: Number of interrupts to allocate.
189 * On success: return a new irq_domain object.
190 * On failure: a negative errno wrapped with ERR_PTR().
192 struct irq_domain
*irq_domain_create_sim(struct fwnode_handle
*fwnode
,
193 unsigned int num_irqs
)
195 return irq_domain_create_sim_full(fwnode
, num_irqs
, NULL
, NULL
);
197 EXPORT_SYMBOL_GPL(irq_domain_create_sim
);
199 struct irq_domain
*irq_domain_create_sim_full(struct fwnode_handle
*fwnode
,
200 unsigned int num_irqs
,
201 const struct irq_sim_ops
*ops
,
204 struct irq_sim_work_ctx
*work_ctx
__free(kfree
) =
205 kmalloc(sizeof(*work_ctx
), GFP_KERNEL
);
208 return ERR_PTR(-ENOMEM
);
210 unsigned long *pending
__free(bitmap
) = bitmap_zalloc(num_irqs
, GFP_KERNEL
);
212 return ERR_PTR(-ENOMEM
);
214 work_ctx
->domain
= irq_domain_create_linear(fwnode
, num_irqs
,
217 if (!work_ctx
->domain
)
218 return ERR_PTR(-ENOMEM
);
220 work_ctx
->irq_count
= num_irqs
;
221 work_ctx
->work
= IRQ_WORK_INIT_HARD(irq_sim_handle_irq
);
222 work_ctx
->pending
= no_free_ptr(pending
);
223 work_ctx
->user_data
= data
;
226 memcpy(&work_ctx
->ops
, ops
, sizeof(*ops
));
228 return no_free_ptr(work_ctx
)->domain
;
230 EXPORT_SYMBOL_GPL(irq_domain_create_sim_full
);
233 * irq_domain_remove_sim - Deinitialize the interrupt simulator domain: free
234 * the interrupt descriptors and allocated memory.
236 * @domain: The interrupt simulator domain to tear down.
238 void irq_domain_remove_sim(struct irq_domain
*domain
)
240 struct irq_sim_work_ctx
*work_ctx
= domain
->host_data
;
242 irq_work_sync(&work_ctx
->work
);
243 bitmap_free(work_ctx
->pending
);
246 irq_domain_remove(domain
);
248 EXPORT_SYMBOL_GPL(irq_domain_remove_sim
);
250 static void devm_irq_domain_remove_sim(void *data
)
252 struct irq_domain
*domain
= data
;
254 irq_domain_remove_sim(domain
);
258 * devm_irq_domain_create_sim - Create a new interrupt simulator for
261 * @dev: Device to initialize the simulator object for.
262 * @fwnode: struct fwnode_handle to be associated with this domain.
263 * @num_irqs: Number of interrupts to allocate
265 * On success: return a new irq_domain object.
266 * On failure: a negative errno wrapped with ERR_PTR().
268 struct irq_domain
*devm_irq_domain_create_sim(struct device
*dev
,
269 struct fwnode_handle
*fwnode
,
270 unsigned int num_irqs
)
272 return devm_irq_domain_create_sim_full(dev
, fwnode
, num_irqs
,
275 EXPORT_SYMBOL_GPL(devm_irq_domain_create_sim
);
278 devm_irq_domain_create_sim_full(struct device
*dev
,
279 struct fwnode_handle
*fwnode
,
280 unsigned int num_irqs
,
281 const struct irq_sim_ops
*ops
,
284 struct irq_domain
*domain
;
287 domain
= irq_domain_create_sim_full(fwnode
, num_irqs
, ops
, data
);
291 ret
= devm_add_action_or_reset(dev
, devm_irq_domain_remove_sim
, domain
);
297 EXPORT_SYMBOL_GPL(devm_irq_domain_create_sim_full
);