Skip to content

Commit 4342ec5

Browse files
committed
Merge branch 'irq/for-gpio' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip into devel
2 parents 5751d3d + 495c38d commit 4342ec5

File tree

9 files changed

+533
-30
lines changed

9 files changed

+533
-30
lines changed

Documentation/driver-model/devres.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ IRQ
312312
devm_irq_alloc_descs_from()
313313
devm_irq_alloc_generic_chip()
314314
devm_irq_setup_generic_chip()
315+
devm_irq_sim_init()
315316

316317
LED
317318
devm_led_classdev_register()

include/linux/irq.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,8 @@ extern int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg);
568568
extern int irq_chip_pm_get(struct irq_data *data);
569569
extern int irq_chip_pm_put(struct irq_data *data);
570570
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
571+
extern void handle_fasteoi_ack_irq(struct irq_desc *desc);
572+
extern void handle_fasteoi_mask_irq(struct irq_desc *desc);
571573
extern void irq_chip_enable_parent(struct irq_data *data);
572574
extern void irq_chip_disable_parent(struct irq_data *data);
573575
extern void irq_chip_ack_parent(struct irq_data *data);

include/linux/irq_sim.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#ifndef _LINUX_IRQ_SIM_H
2+
#define _LINUX_IRQ_SIM_H
3+
/*
4+
* Copyright (C) 2017 Bartosz Golaszewski <[email protected]>
5+
*
6+
* This program is free software; you can redistribute it and/or modify it
7+
* under the terms of the GNU General Public License as published by the
8+
* Free Software Foundation; either version 2 of the License, or (at your
9+
* option) any later version.
10+
*/
11+
12+
#include <linux/irq_work.h>
13+
#include <linux/device.h>
14+
15+
/*
16+
* Provides a framework for allocating simulated interrupts which can be
17+
* requested like normal irqs and enqueued from process context.
18+
*/
19+
20+
struct irq_sim_work_ctx {
21+
struct irq_work work;
22+
int irq;
23+
};
24+
25+
struct irq_sim_irq_ctx {
26+
int irqnum;
27+
bool enabled;
28+
};
29+
30+
struct irq_sim {
31+
struct irq_sim_work_ctx work_ctx;
32+
int irq_base;
33+
unsigned int irq_count;
34+
struct irq_sim_irq_ctx *irqs;
35+
};
36+
37+
int irq_sim_init(struct irq_sim *sim, unsigned int num_irqs);
38+
int devm_irq_sim_init(struct device *dev, struct irq_sim *sim,
39+
unsigned int num_irqs);
40+
void irq_sim_fini(struct irq_sim *sim);
41+
void irq_sim_fire(struct irq_sim *sim, unsigned int offset);
42+
int irq_sim_irqnum(struct irq_sim *sim, unsigned int offset);
43+
44+
#endif /* _LINUX_IRQ_SIM_H */

include/linux/irqdomain.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,9 @@ extern void irq_domain_free_irqs_common(struct irq_domain *domain,
460460
extern void irq_domain_free_irqs_top(struct irq_domain *domain,
461461
unsigned int virq, unsigned int nr_irqs);
462462

463+
extern int irq_domain_push_irq(struct irq_domain *domain, int virq, void *arg);
464+
extern int irq_domain_pop_irq(struct irq_domain *domain, int virq);
465+
463466
extern int irq_domain_alloc_irqs_parent(struct irq_domain *domain,
464467
unsigned int irq_base,
465468
unsigned int nr_irqs, void *arg);

kernel/irq/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,20 @@ config GENERIC_IRQ_CHIP
6363
config IRQ_DOMAIN
6464
bool
6565

66+
# Support for simulated interrupts
67+
config IRQ_SIM
68+
bool
69+
select IRQ_WORK
70+
6671
# Support for hierarchical irq domains
6772
config IRQ_DOMAIN_HIERARCHY
6873
bool
6974
select IRQ_DOMAIN
7075

76+
# Support for hierarchical fasteoi+edge and fasteoi+level handlers
77+
config IRQ_FASTEOI_HIERARCHY_HANDLERS
78+
bool
79+
7180
# Generic IRQ IPI support
7281
config GENERIC_IRQ_IPI
7382
bool

kernel/irq/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ obj-$(CONFIG_IRQ_TIMINGS) += timings.o
44
obj-$(CONFIG_GENERIC_IRQ_CHIP) += generic-chip.o
55
obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o
66
obj-$(CONFIG_IRQ_DOMAIN) += irqdomain.o
7+
obj-$(CONFIG_IRQ_SIM) += irq_sim.o
78
obj-$(CONFIG_PROC_FS) += proc.o
89
obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o
910
obj-$(CONFIG_GENERIC_IRQ_MIGRATION) += cpuhotplug.o

kernel/irq/chip.c

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,6 +1092,112 @@ void irq_cpu_offline(void)
10921092
}
10931093

10941094
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
1095+
1096+
#ifdef CONFIG_IRQ_FASTEOI_HIERARCHY_HANDLERS
1097+
/**
1098+
* handle_fasteoi_ack_irq - irq handler for edge hierarchy
1099+
* stacked on transparent controllers
1100+
*
1101+
* @desc: the interrupt description structure for this irq
1102+
*
1103+
* Like handle_fasteoi_irq(), but for use with hierarchy where
1104+
* the irq_chip also needs to have its ->irq_ack() function
1105+
* called.
1106+
*/
1107+
void handle_fasteoi_ack_irq(struct irq_desc *desc)
1108+
{
1109+
struct irq_chip *chip = desc->irq_data.chip;
1110+
1111+
raw_spin_lock(&desc->lock);
1112+
1113+
if (!irq_may_run(desc))
1114+
goto out;
1115+
1116+
desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
1117+
1118+
/*
1119+
* If its disabled or no action available
1120+
* then mask it and get out of here:
1121+
*/
1122+
if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) {
1123+
desc->istate |= IRQS_PENDING;
1124+
mask_irq(desc);
1125+
goto out;
1126+
}
1127+
1128+
kstat_incr_irqs_this_cpu(desc);
1129+
if (desc->istate & IRQS_ONESHOT)
1130+
mask_irq(desc);
1131+
1132+
/* Start handling the irq */
1133+
desc->irq_data.chip->irq_ack(&desc->irq_data);
1134+
1135+
preflow_handler(desc);
1136+
handle_irq_event(desc);
1137+
1138+
cond_unmask_eoi_irq(desc, chip);
1139+
1140+
raw_spin_unlock(&desc->lock);
1141+
return;
1142+
out:
1143+
if (!(chip->flags & IRQCHIP_EOI_IF_HANDLED))
1144+
chip->irq_eoi(&desc->irq_data);
1145+
raw_spin_unlock(&desc->lock);
1146+
}
1147+
EXPORT_SYMBOL_GPL(handle_fasteoi_ack_irq);
1148+
1149+
/**
1150+
* handle_fasteoi_mask_irq - irq handler for level hierarchy
1151+
* stacked on transparent controllers
1152+
*
1153+
* @desc: the interrupt description structure for this irq
1154+
*
1155+
* Like handle_fasteoi_irq(), but for use with hierarchy where
1156+
* the irq_chip also needs to have its ->irq_mask_ack() function
1157+
* called.
1158+
*/
1159+
void handle_fasteoi_mask_irq(struct irq_desc *desc)
1160+
{
1161+
struct irq_chip *chip = desc->irq_data.chip;
1162+
1163+
raw_spin_lock(&desc->lock);
1164+
mask_ack_irq(desc);
1165+
1166+
if (!irq_may_run(desc))
1167+
goto out;
1168+
1169+
desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
1170+
1171+
/*
1172+
* If its disabled or no action available
1173+
* then mask it and get out of here:
1174+
*/
1175+
if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) {
1176+
desc->istate |= IRQS_PENDING;
1177+
mask_irq(desc);
1178+
goto out;
1179+
}
1180+
1181+
kstat_incr_irqs_this_cpu(desc);
1182+
if (desc->istate & IRQS_ONESHOT)
1183+
mask_irq(desc);
1184+
1185+
preflow_handler(desc);
1186+
handle_irq_event(desc);
1187+
1188+
cond_unmask_eoi_irq(desc, chip);
1189+
1190+
raw_spin_unlock(&desc->lock);
1191+
return;
1192+
out:
1193+
if (!(chip->flags & IRQCHIP_EOI_IF_HANDLED))
1194+
chip->irq_eoi(&desc->irq_data);
1195+
raw_spin_unlock(&desc->lock);
1196+
}
1197+
EXPORT_SYMBOL_GPL(handle_fasteoi_mask_irq);
1198+
1199+
#endif /* CONFIG_IRQ_FASTEOI_HIERARCHY_HANDLERS */
1200+
10951201
/**
10961202
* irq_chip_enable_parent - Enable the parent interrupt (defaults to unmask if
10971203
* NULL)
@@ -1105,6 +1211,7 @@ void irq_chip_enable_parent(struct irq_data *data)
11051211
else
11061212
data->chip->irq_unmask(data);
11071213
}
1214+
EXPORT_SYMBOL_GPL(irq_chip_enable_parent);
11081215

11091216
/**
11101217
* irq_chip_disable_parent - Disable the parent interrupt (defaults to mask if
@@ -1119,6 +1226,7 @@ void irq_chip_disable_parent(struct irq_data *data)
11191226
else
11201227
data->chip->irq_mask(data);
11211228
}
1229+
EXPORT_SYMBOL_GPL(irq_chip_disable_parent);
11221230

11231231
/**
11241232
* irq_chip_ack_parent - Acknowledge the parent interrupt
@@ -1181,6 +1289,7 @@ int irq_chip_set_affinity_parent(struct irq_data *data,
11811289

11821290
return -ENOSYS;
11831291
}
1292+
EXPORT_SYMBOL_GPL(irq_chip_set_affinity_parent);
11841293

11851294
/**
11861295
* irq_chip_set_type_parent - Set IRQ type on the parent interrupt

0 commit comments

Comments
 (0)