diff options
author | Daniel Lezcano <daniel.lezcano@linaro.org> | 2016-01-13 21:42:40 +0100 |
---|---|---|
committer | Daniel Lezcano <daniel.lezcano@linaro.org> | 2016-01-18 13:32:49 +0100 |
commit | 0a8abb23fb0ec686eb12a582691c27e339e561d5 (patch) | |
tree | fc5430b6414678e1d4bc8b7f9846521d0427db81 | |
parent | c00161b5219de03132f9cd1751396a2080469661 (diff) |
Fixup tglx's commentsirq-timings-v0
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
-rw-r--r-- | include/linux/interrupt.h | 28 | ||||
-rw-r--r-- | include/linux/irqdesc.h | 2 | ||||
-rw-r--r-- | kernel/irq/handle.c | 4 | ||||
-rw-r--r-- | kernel/irq/manage.c | 110 | ||||
-rw-r--r-- | kernel/sched/idle-sched.c | 48 |
5 files changed, 100 insertions, 92 deletions
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index f48e8ff241b8..7ed1d4609f70 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -124,21 +124,8 @@ struct irqaction { extern irqreturn_t no_action(int cpl, void *dev_id); #ifdef CONFIG_IRQ_TIMINGS -/** - * timing handler to be called when an interrupt happens - */ -typedef void (*irqt_handler_t)(unsigned int, ktime_t, void *, void *); -/** - * struct irqtimings - per interrupt irq timings descriptor - * @handler: interrupt handler timings function - * @data: pointer to the private data to be passed to the handler - * @timestamp: latest interruption occurence - */ -struct irqtimings { - irqt_handler_t handler; - void *data; -} ____cacheline_internodealigned_in_smp; +typedef void (*irqt_handler_t)(unsigned int, ktime_t, void *); /** * struct irqt_ops - structure to be used by the subsystem to call the @@ -151,21 +138,10 @@ struct irqtimings { struct irqtimings_ops { int (*setup)(unsigned int, struct irqaction *); void (*free)(unsigned int, void *); + irqt_handler_t handler; }; extern int register_irq_timings(struct irqtimings_ops *ops); -extern int setup_irq_timings(unsigned int irq, struct irqaction *act); -extern void free_irq_timings(unsigned int irq, void *dev_id); -#else -static inline int setup_irq_timings(unsigned int irq, struct irqaction *act) -{ - return 0; -} - -static inline void free_irq_timings(unsigned int irq, void *dev_id) -{ - ; -} #endif extern int __must_check diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h index e0d4263fde18..c939f9a2ab5e 100644 --- a/include/linux/irqdesc.h +++ b/include/linux/irqdesc.h @@ -52,7 +52,7 @@ struct irq_desc { irq_preflow_handler_t preflow_handler; #endif #ifdef CONFIG_IRQ_TIMINGS - struct irqtimings *timings; + irqt_handler_t handle_irqt; #endif struct irqaction *action; /* IRQ action list */ unsigned int status_use_accessors; diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index 445a98c1a21b..e7d18e85e845 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c @@ -133,14 +133,14 @@ void __irq_wake_thread(struct irq_desc *desc, struct irqaction *action) } #ifdef CONFIG_IRQ_TIMINGS -void handle_irqt_event(struct irqtimings *irqt, struct irqaction *action) +static void handle_irqt_event(struct irqtimings *irqt, struct irqaction *action) { if (irqt) irqt->handler(action->irq, ktime_get(), action->dev_id, irqt->data); } #else -#define handle_irqt_event(a, b) +static inline void handle_irqt_event(struct irqtimings *,struct irqaction *) {} #endif irqreturn_t diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index e1718f44b0ee..dd83400685cf 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -1024,21 +1024,15 @@ static void irq_release_resources(struct irq_desc *desc) static struct irqtimings_ops *irqtimings_ops; /** - * register_irq_timings - register the ops when an irq is setup or freed + * free_irq_timings - call the timing unregister callback * - * @ops: the register/unregister ops to be called when at setup or - * free time + * @irq: the interrupt number * - * Returns -EBUSY if the slot is already in use, zero on success. */ -int register_irq_timings(struct irqtimings_ops *ops) +static void free_irq_timings(unsigned int irq, void *dev_id) { if (irqtimings_ops) - return -EBUSY; - - irqtimings_ops = ops; - - return 0; + irqtimings_ops->free(irq, dev_id); } /** @@ -1048,24 +1042,100 @@ int register_irq_timings(struct irqtimings_ops *ops) * * Returns -EINVAL in case of error, zero on success. */ -int setup_irq_timings(unsigned int irq, struct irqaction *act) +static int setup_irq_timings(unsigned int irq, struct irqaction *act) { - if (irqtimings_ops && irqtimings_ops->setup) - return irqtimings_ops->setup(irq, act); - return 0; + /* + * The irqtimings ops were not registered yet, exit without error. + */ + if (!irqtimings_ops) + return 0; + + /* + * No interrupt set for this descriptor or related to a timer. + * Timers are deterministic, so no need to try to do any + * timings on them. No error for both cases, we are just not + * interested. + */ + if (!act || (act->flags & __IRQF_TIMER)) + return 0; + + return irqtimings_ops->setup(irq, act->dev_id); +} + +static void free_irq_timings_action(unsigned int irq, struct irq_desc *desc) +{ + struct irqaction *action; + + for_each_desc_action(desc, action) + free_irq_timings(irq, action->dev_id); +} + +static int setup_irq_timings_action(unsigned int irq, struct irq_desc *desc) +{ + struct irqaction *action; + int ret = 0; + + for_each_desc_action(desc, action) { + ret = setup_irq_timings(irq, action); + if (ret) { + free_irq_timings_action(irq, desc); + break; + } + } + + return ret; } /** - * free_irq_timings - call the timing unregister callback + * register_irq_timings - register the ops when an irq is setup or freed * - * @irq: the interrupt number - * @dev_id: the device id + * @ops: the register/unregister ops to be called when at setup or + * free time * + * Returns -EBUSY if the slot is already in use, zero on success. */ -void free_irq_timings(unsigned int irq, void *dev_id) +int register_irq_timings(struct irqtimings_ops *ops) { - if (irqtimings_ops && irqtimings_ops->free) - irqtimings_ops->free(irq, dev_id); + struct irq_desc *desc; + unsigned int irq; + int ret; + + if (!ops || !ops->setup || !ops->free || !ops->handler) + return -EINVAL; + + if (irqtimings_ops) + return -EBUSY; + + irqtimings_ops = ops; + + /* + * For all the irq already setup, assign the timing callback. + * All interrupts with their desc NULL will be discarded. + */ + for_each_irq_desc(irq, desc) { + raw_spin_lock_irqsave(&desc->lock, flags); + + ret = setup_irq_timings_desc(irq, desc); + if (ret) { + raw_spin_unlock_irqrestore(&desc->lock, flags); + goto out_rollback; + } + desc->handler_irqt = ops->handler; + raw_spin_unlock_irqrestore(&desc->lock, flags); + } +out: + return ret; + +out_rollback: + for_each_irq_desc(irq, desc) { + raw_spin_lock_irqsave(&desc->lock, flags); + desc->handler_irqt = NULL; + for_each_desc_action(desc, action) + free_irq_timings(irq, action->dev_id); + raw_spin_unlock_irqrestore(&desc->lock, flags); + } + + goto out; } #endif /* CONFIG_IRQ_TIMINGS */ diff --git a/kernel/sched/idle-sched.c b/kernel/sched/idle-sched.c index ae81ab9fb7f1..466eea62eb9c 100644 --- a/kernel/sched/idle-sched.c +++ b/kernel/sched/idle-sched.c @@ -234,13 +234,6 @@ static void sched_idle_irq(unsigned int irq, ktime_t timestamp, stats_add(&w->stats, diff); } -/* - * Callback to be called when an interrupt happens. - */ -static struct irqtimings irq_timings = { - .handler = sched_idle_irq, -}; - static ktime_t next_irq_event(void) { unsigned int irq, cpu = raw_smp_processor_id(); @@ -473,16 +466,10 @@ out: * * This function will remove from the wakeup source prediction table. */ -static void sched_irq_timing_free(unsigned int irq, void *dev_id) +static void sched_irq_timing_free(unsigned int irq) { - struct irq_desc *desc = irq_to_desc(irq); struct wakeup *w; unsigned int cpu; - unsigned long flags; - - raw_spin_lock_irqsave(&desc->lock, flags); - desc->timings = NULL; - raw_spin_unlock_irqrestore(&desc->lock, flags); for_each_possible_cpu(cpu) { w = per_cpu(wakeups[irq], cpu); @@ -504,24 +491,13 @@ static void sched_irq_timing_free(unsigned int irq, void *dev_id) * * Returns zero on success. On error it returns -ENOMEM. */ -static int sched_irq_timing_setup(unsigned int irq, struct irqaction *act) +static int sched_irq_timing_setup(unsigned int irq) { - struct irq_desc *desc = irq_to_desc(irq); struct wakeup *w; unsigned int cpu; - unsigned long flags; int ret = -ENOMEM; /* - * No interrupt set for this descriptor or related to a timer. - * Timers are deterministic, so no need to try to do any - * prediction on them. No error for both cases, we are just not - * interested. - */ - if (!act || (act->flags & __IRQF_TIMER)) - return 0; - - /* * Allocates the wakeup structure and the stats structure. As * the interrupt can occur on any cpu, allocate the wakeup * structure per cpu basis. @@ -535,10 +511,6 @@ static int sched_irq_timing_setup(unsigned int irq, struct irqaction *act) per_cpu(wakeups[irq], cpu) = w; } - raw_spin_lock_irqsave(&desc->lock, flags); - desc->timings = &irq_timings; - raw_spin_unlock_irqrestore(&desc->lock, flags); - ret = 0; undo: /* @@ -556,6 +528,7 @@ undo: static struct irqtimings_ops irqt_ops = { .setup = sched_irq_timing_setup, .free = sched_irq_timing_free, + .handler = sched_idle_irq, }; /** @@ -569,8 +542,6 @@ static struct irqtimings_ops irqt_ops = { */ int __init sched_idle_init(void) { - struct irq_desc *desc; - unsigned int irq; int ret; /* @@ -578,18 +549,9 @@ int __init sched_idle_init(void) * freed interrupt will update their tracking. */ ret = register_irq_timings(&irqt_ops); - if (ret) { + if (ret) pr_err("Failed to register timings ops\n"); - return ret; - } - /* - * For all the irq already setup, assign the timing callback. - * All interrupts with their desc NULL will be discarded. - */ - for_each_irq_desc(irq, desc) - sched_irq_timing_setup(irq, desc->action); - - return 0; + return ret; } late_initcall(sched_idle_init); |