summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Lezcano <daniel.lezcano@linaro.org>2016-01-13 21:42:40 +0100
committerDaniel Lezcano <daniel.lezcano@linaro.org>2016-01-18 13:32:49 +0100
commit0a8abb23fb0ec686eb12a582691c27e339e561d5 (patch)
treefc5430b6414678e1d4bc8b7f9846521d0427db81
parentc00161b5219de03132f9cd1751396a2080469661 (diff)
Fixup tglx's commentsirq-timings-v0
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
-rw-r--r--include/linux/interrupt.h28
-rw-r--r--include/linux/irqdesc.h2
-rw-r--r--kernel/irq/handle.c4
-rw-r--r--kernel/irq/manage.c110
-rw-r--r--kernel/sched/idle-sched.c48
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);