Skip to content

Commit 88b6fc8

Browse files
author
Marc Zyngier
committed
Merge commit '32cffdd' into ppi-irq-core-for-rmk
2 parents a06f916 + 32cffdd commit 88b6fc8

File tree

8 files changed

+364
-35
lines changed

8 files changed

+364
-35
lines changed

include/linux/interrupt.h

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ typedef irqreturn_t (*irq_handler_t)(int, void *);
9595
* @flags: flags (see IRQF_* above)
9696
* @name: name of the device
9797
* @dev_id: cookie to identify the device
98+
* @percpu_dev_id: cookie to identify the device
9899
* @next: pointer to the next irqaction for shared interrupts
99100
* @irq: interrupt number
100101
* @dir: pointer to the proc/irq/NN/name entry
@@ -104,17 +105,18 @@ typedef irqreturn_t (*irq_handler_t)(int, void *);
104105
* @thread_mask: bitmask for keeping track of @thread activity
105106
*/
106107
struct irqaction {
107-
irq_handler_t handler;
108-
unsigned long flags;
109-
void *dev_id;
110-
struct irqaction *next;
111-
int irq;
112-
irq_handler_t thread_fn;
113-
struct task_struct *thread;
114-
unsigned long thread_flags;
115-
unsigned long thread_mask;
116-
const char *name;
117-
struct proc_dir_entry *dir;
108+
irq_handler_t handler;
109+
unsigned long flags;
110+
void *dev_id;
111+
void __percpu *percpu_dev_id;
112+
struct irqaction *next;
113+
int irq;
114+
irq_handler_t thread_fn;
115+
struct task_struct *thread;
116+
unsigned long thread_flags;
117+
unsigned long thread_mask;
118+
const char *name;
119+
struct proc_dir_entry *dir;
118120
} ____cacheline_internodealigned_in_smp;
119121

120122
extern irqreturn_t no_action(int cpl, void *dev_id);
@@ -136,6 +138,10 @@ extern int __must_check
136138
request_any_context_irq(unsigned int irq, irq_handler_t handler,
137139
unsigned long flags, const char *name, void *dev_id);
138140

141+
extern int __must_check
142+
request_percpu_irq(unsigned int irq, irq_handler_t handler,
143+
const char *devname, void __percpu *percpu_dev_id);
144+
139145
extern void exit_irq_thread(void);
140146
#else
141147

@@ -164,10 +170,18 @@ request_any_context_irq(unsigned int irq, irq_handler_t handler,
164170
return request_irq(irq, handler, flags, name, dev_id);
165171
}
166172

173+
static inline int __must_check
174+
request_percpu_irq(unsigned int irq, irq_handler_t handler,
175+
const char *devname, void __percpu *percpu_dev_id)
176+
{
177+
return request_irq(irq, handler, 0, devname, percpu_dev_id);
178+
}
179+
167180
static inline void exit_irq_thread(void) { }
168181
#endif
169182

170183
extern void free_irq(unsigned int, void *);
184+
extern void free_percpu_irq(unsigned int, void __percpu *);
171185

172186
struct device;
173187

@@ -207,7 +221,9 @@ extern void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id);
207221

208222
extern void disable_irq_nosync(unsigned int irq);
209223
extern void disable_irq(unsigned int irq);
224+
extern void disable_percpu_irq(unsigned int irq);
210225
extern void enable_irq(unsigned int irq);
226+
extern void enable_percpu_irq(unsigned int irq, unsigned int type);
211227

212228
/* The following three functions are for the core kernel use only. */
213229
#ifdef CONFIG_GENERIC_HARDIRQS

include/linux/irq.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ typedef void (*irq_preflow_handler_t)(struct irq_data *data);
6666
* IRQ_NO_BALANCING - Interrupt cannot be balanced (affinity set)
6767
* IRQ_MOVE_PCNTXT - Interrupt can be migrated from process context
6868
* IRQ_NESTED_TRHEAD - Interrupt nests into another thread
69+
* IRQ_PER_CPU_DEVID - Dev_id is a per-cpu variable
6970
*/
7071
enum {
7172
IRQ_TYPE_NONE = 0x00000000,
@@ -88,12 +89,13 @@ enum {
8889
IRQ_MOVE_PCNTXT = (1 << 14),
8990
IRQ_NESTED_THREAD = (1 << 15),
9091
IRQ_NOTHREAD = (1 << 16),
92+
IRQ_PER_CPU_DEVID = (1 << 17),
9193
};
9294

9395
#define IRQF_MODIFY_MASK \
9496
(IRQ_TYPE_SENSE_MASK | IRQ_NOPROBE | IRQ_NOREQUEST | \
9597
IRQ_NOAUTOEN | IRQ_MOVE_PCNTXT | IRQ_LEVEL | IRQ_NO_BALANCING | \
96-
IRQ_PER_CPU | IRQ_NESTED_THREAD)
98+
IRQ_PER_CPU | IRQ_NESTED_THREAD | IRQ_NOTHREAD | IRQ_PER_CPU_DEVID)
9799

98100
#define IRQ_NO_BALANCING_MASK (IRQ_PER_CPU | IRQ_NO_BALANCING)
99101

@@ -336,12 +338,14 @@ struct irq_chip {
336338
* IRQCHIP_MASK_ON_SUSPEND: Mask non wake irqs in the suspend path
337339
* IRQCHIP_ONOFFLINE_ENABLED: Only call irq_on/off_line callbacks
338340
* when irq enabled
341+
* IRQCHIP_SKIP_SET_WAKE: Skip chip.irq_set_wake(), for this irq chip
339342
*/
340343
enum {
341344
IRQCHIP_SET_TYPE_MASKED = (1 << 0),
342345
IRQCHIP_EOI_IF_HANDLED = (1 << 1),
343346
IRQCHIP_MASK_ON_SUSPEND = (1 << 2),
344347
IRQCHIP_ONOFFLINE_ENABLED = (1 << 3),
348+
IRQCHIP_SKIP_SET_WAKE = (1 << 4),
345349
};
346350

347351
/* This include will go away once we isolated irq_desc usage to core code */
@@ -365,6 +369,8 @@ enum {
365369
struct irqaction;
366370
extern int setup_irq(unsigned int irq, struct irqaction *new);
367371
extern void remove_irq(unsigned int irq, struct irqaction *act);
372+
extern int setup_percpu_irq(unsigned int irq, struct irqaction *new);
373+
extern void remove_percpu_irq(unsigned int irq, struct irqaction *act);
368374

369375
extern void irq_cpu_online(void);
370376
extern void irq_cpu_offline(void);
@@ -392,6 +398,7 @@ extern void handle_edge_irq(unsigned int irq, struct irq_desc *desc);
392398
extern void handle_edge_eoi_irq(unsigned int irq, struct irq_desc *desc);
393399
extern void handle_simple_irq(unsigned int irq, struct irq_desc *desc);
394400
extern void handle_percpu_irq(unsigned int irq, struct irq_desc *desc);
401+
extern void handle_percpu_devid_irq(unsigned int irq, struct irq_desc *desc);
395402
extern void handle_bad_irq(unsigned int irq, struct irq_desc *desc);
396403
extern void handle_nested_irq(unsigned int irq);
397404

@@ -420,6 +427,8 @@ static inline void irq_set_chip_and_handler(unsigned int irq, struct irq_chip *c
420427
irq_set_chip_and_handler_name(irq, chip, handle, NULL);
421428
}
422429

430+
extern int irq_set_percpu_devid(unsigned int irq);
431+
423432
extern void
424433
__irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
425434
const char *name);
@@ -481,6 +490,13 @@ static inline void irq_set_nested_thread(unsigned int irq, bool nest)
481490
irq_clear_status_flags(irq, IRQ_NESTED_THREAD);
482491
}
483492

493+
static inline void irq_set_percpu_devid_flags(unsigned int irq)
494+
{
495+
irq_set_status_flags(irq,
496+
IRQ_NOAUTOEN | IRQ_PER_CPU | IRQ_NOTHREAD |
497+
IRQ_NOPROBE | IRQ_PER_CPU_DEVID);
498+
}
499+
484500
/* Handle dynamic irq creation and destruction */
485501
extern unsigned int create_irq_nr(unsigned int irq_want, int node);
486502
extern int create_irq(void);

include/linux/irqdesc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ struct irq_desc {
5353
unsigned long last_unhandled; /* Aging timer for unhandled count */
5454
unsigned int irqs_unhandled;
5555
raw_spinlock_t lock;
56+
struct cpumask *percpu_enabled;
5657
#ifdef CONFIG_SMP
5758
const struct cpumask *affinity_hint;
5859
struct irq_affinity_notify *affinity_notify;

kernel/irq/chip.c

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
int irq_set_chip(unsigned int irq, struct irq_chip *chip)
2727
{
2828
unsigned long flags;
29-
struct irq_desc *desc = irq_get_desc_lock(irq, &flags);
29+
struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0);
3030

3131
if (!desc)
3232
return -EINVAL;
@@ -54,7 +54,7 @@ EXPORT_SYMBOL(irq_set_chip);
5454
int irq_set_irq_type(unsigned int irq, unsigned int type)
5555
{
5656
unsigned long flags;
57-
struct irq_desc *desc = irq_get_desc_buslock(irq, &flags);
57+
struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL);
5858
int ret = 0;
5959

6060
if (!desc)
@@ -78,7 +78,7 @@ EXPORT_SYMBOL(irq_set_irq_type);
7878
int irq_set_handler_data(unsigned int irq, void *data)
7979
{
8080
unsigned long flags;
81-
struct irq_desc *desc = irq_get_desc_lock(irq, &flags);
81+
struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0);
8282

8383
if (!desc)
8484
return -EINVAL;
@@ -98,7 +98,7 @@ EXPORT_SYMBOL(irq_set_handler_data);
9898
int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry)
9999
{
100100
unsigned long flags;
101-
struct irq_desc *desc = irq_get_desc_lock(irq, &flags);
101+
struct irq_desc *desc = irq_get_desc_lock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL);
102102

103103
if (!desc)
104104
return -EINVAL;
@@ -119,7 +119,7 @@ int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry)
119119
int irq_set_chip_data(unsigned int irq, void *data)
120120
{
121121
unsigned long flags;
122-
struct irq_desc *desc = irq_get_desc_lock(irq, &flags);
122+
struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0);
123123

124124
if (!desc)
125125
return -EINVAL;
@@ -178,7 +178,7 @@ void irq_shutdown(struct irq_desc *desc)
178178
desc->depth = 1;
179179
if (desc->irq_data.chip->irq_shutdown)
180180
desc->irq_data.chip->irq_shutdown(&desc->irq_data);
181-
if (desc->irq_data.chip->irq_disable)
181+
else if (desc->irq_data.chip->irq_disable)
182182
desc->irq_data.chip->irq_disable(&desc->irq_data);
183183
else
184184
desc->irq_data.chip->irq_mask(&desc->irq_data);
@@ -204,6 +204,24 @@ void irq_disable(struct irq_desc *desc)
204204
}
205205
}
206206

207+
void irq_percpu_enable(struct irq_desc *desc, unsigned int cpu)
208+
{
209+
if (desc->irq_data.chip->irq_enable)
210+
desc->irq_data.chip->irq_enable(&desc->irq_data);
211+
else
212+
desc->irq_data.chip->irq_unmask(&desc->irq_data);
213+
cpumask_set_cpu(cpu, desc->percpu_enabled);
214+
}
215+
216+
void irq_percpu_disable(struct irq_desc *desc, unsigned int cpu)
217+
{
218+
if (desc->irq_data.chip->irq_disable)
219+
desc->irq_data.chip->irq_disable(&desc->irq_data);
220+
else
221+
desc->irq_data.chip->irq_mask(&desc->irq_data);
222+
cpumask_clear_cpu(cpu, desc->percpu_enabled);
223+
}
224+
207225
static inline void mask_ack_irq(struct irq_desc *desc)
208226
{
209227
if (desc->irq_data.chip->irq_mask_ack)
@@ -544,12 +562,44 @@ handle_percpu_irq(unsigned int irq, struct irq_desc *desc)
544562
chip->irq_eoi(&desc->irq_data);
545563
}
546564

565+
/**
566+
* handle_percpu_devid_irq - Per CPU local irq handler with per cpu dev ids
567+
* @irq: the interrupt number
568+
* @desc: the interrupt description structure for this irq
569+
*
570+
* Per CPU interrupts on SMP machines without locking requirements. Same as
571+
* handle_percpu_irq() above but with the following extras:
572+
*
573+
* action->percpu_dev_id is a pointer to percpu variables which
574+
* contain the real device id for the cpu on which this handler is
575+
* called
576+
*/
577+
void handle_percpu_devid_irq(unsigned int irq, struct irq_desc *desc)
578+
{
579+
struct irq_chip *chip = irq_desc_get_chip(desc);
580+
struct irqaction *action = desc->action;
581+
void *dev_id = __this_cpu_ptr(action->percpu_dev_id);
582+
irqreturn_t res;
583+
584+
kstat_incr_irqs_this_cpu(irq, desc);
585+
586+
if (chip->irq_ack)
587+
chip->irq_ack(&desc->irq_data);
588+
589+
trace_irq_handler_entry(irq, action);
590+
res = action->handler(irq, dev_id);
591+
trace_irq_handler_exit(irq, action, res);
592+
593+
if (chip->irq_eoi)
594+
chip->irq_eoi(&desc->irq_data);
595+
}
596+
547597
void
548598
__irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
549599
const char *name)
550600
{
551601
unsigned long flags;
552-
struct irq_desc *desc = irq_get_desc_buslock(irq, &flags);
602+
struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, 0);
553603

554604
if (!desc)
555605
return;
@@ -593,7 +643,7 @@ irq_set_chip_and_handler_name(unsigned int irq, struct irq_chip *chip,
593643
void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set)
594644
{
595645
unsigned long flags;
596-
struct irq_desc *desc = irq_get_desc_lock(irq, &flags);
646+
struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0);
597647

598648
if (!desc)
599649
return;

kernel/irq/internals.h

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ extern int irq_startup(struct irq_desc *desc);
7171
extern void irq_shutdown(struct irq_desc *desc);
7272
extern void irq_enable(struct irq_desc *desc);
7373
extern void irq_disable(struct irq_desc *desc);
74+
extern void irq_percpu_enable(struct irq_desc *desc, unsigned int cpu);
75+
extern void irq_percpu_disable(struct irq_desc *desc, unsigned int cpu);
7476
extern void mask_irq(struct irq_desc *desc);
7577
extern void unmask_irq(struct irq_desc *desc);
7678

@@ -114,14 +116,21 @@ static inline void chip_bus_sync_unlock(struct irq_desc *desc)
114116
desc->irq_data.chip->irq_bus_sync_unlock(&desc->irq_data);
115117
}
116118

119+
#define _IRQ_DESC_CHECK (1 << 0)
120+
#define _IRQ_DESC_PERCPU (1 << 1)
121+
122+
#define IRQ_GET_DESC_CHECK_GLOBAL (_IRQ_DESC_CHECK)
123+
#define IRQ_GET_DESC_CHECK_PERCPU (_IRQ_DESC_CHECK | _IRQ_DESC_PERCPU)
124+
117125
struct irq_desc *
118-
__irq_get_desc_lock(unsigned int irq, unsigned long *flags, bool bus);
126+
__irq_get_desc_lock(unsigned int irq, unsigned long *flags, bool bus,
127+
unsigned int check);
119128
void __irq_put_desc_unlock(struct irq_desc *desc, unsigned long flags, bool bus);
120129

121130
static inline struct irq_desc *
122-
irq_get_desc_buslock(unsigned int irq, unsigned long *flags)
131+
irq_get_desc_buslock(unsigned int irq, unsigned long *flags, unsigned int check)
123132
{
124-
return __irq_get_desc_lock(irq, flags, true);
133+
return __irq_get_desc_lock(irq, flags, true, check);
125134
}
126135

127136
static inline void
@@ -131,9 +140,9 @@ irq_put_desc_busunlock(struct irq_desc *desc, unsigned long flags)
131140
}
132141

133142
static inline struct irq_desc *
134-
irq_get_desc_lock(unsigned int irq, unsigned long *flags)
143+
irq_get_desc_lock(unsigned int irq, unsigned long *flags, unsigned int check)
135144
{
136-
return __irq_get_desc_lock(irq, flags, false);
145+
return __irq_get_desc_lock(irq, flags, false, check);
137146
}
138147

139148
static inline void

kernel/irq/irqdesc.c

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -424,11 +424,22 @@ unsigned int irq_get_next_irq(unsigned int offset)
424424
}
425425

426426
struct irq_desc *
427-
__irq_get_desc_lock(unsigned int irq, unsigned long *flags, bool bus)
427+
__irq_get_desc_lock(unsigned int irq, unsigned long *flags, bool bus,
428+
unsigned int check)
428429
{
429430
struct irq_desc *desc = irq_to_desc(irq);
430431

431432
if (desc) {
433+
if (check & _IRQ_DESC_CHECK) {
434+
if ((check & _IRQ_DESC_PERCPU) &&
435+
!irq_settings_is_per_cpu_devid(desc))
436+
return NULL;
437+
438+
if (!(check & _IRQ_DESC_PERCPU) &&
439+
irq_settings_is_per_cpu_devid(desc))
440+
return NULL;
441+
}
442+
432443
if (bus)
433444
chip_bus_lock(desc);
434445
raw_spin_lock_irqsave(&desc->lock, *flags);
@@ -443,6 +454,25 @@ void __irq_put_desc_unlock(struct irq_desc *desc, unsigned long flags, bool bus)
443454
chip_bus_sync_unlock(desc);
444455
}
445456

457+
int irq_set_percpu_devid(unsigned int irq)
458+
{
459+
struct irq_desc *desc = irq_to_desc(irq);
460+
461+
if (!desc)
462+
return -EINVAL;
463+
464+
if (desc->percpu_enabled)
465+
return -EINVAL;
466+
467+
desc->percpu_enabled = kzalloc(sizeof(*desc->percpu_enabled), GFP_KERNEL);
468+
469+
if (!desc->percpu_enabled)
470+
return -ENOMEM;
471+
472+
irq_set_percpu_devid_flags(irq);
473+
return 0;
474+
}
475+
446476
/**
447477
* dynamic_irq_cleanup - cleanup a dynamically allocated irq
448478
* @irq: irq number to initialize

0 commit comments

Comments
 (0)