Commit 3f371438 authored by Russell King's avatar Russell King

Merge flint.arm.linux.org.uk:/usr/src/bk/linux-2.6-smp

into flint.arm.linux.org.uk:/usr/src/bk/linux-2.6-rmk
parents 08432e0e d4118bd6
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/kallsyms.h> #include <linux/kallsyms.h>
#include <linux/proc_fs.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -85,6 +86,23 @@ static struct irqdesc bad_irq_desc = { ...@@ -85,6 +86,23 @@ static struct irqdesc bad_irq_desc = {
.disable_depth = 1, .disable_depth = 1,
}; };
#ifdef CONFIG_SMP
void synchronize_irq(unsigned int irq)
{
struct irqdesc *desc = irq_desc + irq;
while (desc->running)
barrier();
}
EXPORT_SYMBOL(synchronize_irq);
#define smp_set_running(desc) do { desc->running = 1; } while (0)
#define smp_clear_running(desc) do { desc->running = 0; } while (0)
#else
#define smp_set_running(desc) do { } while (0)
#define smp_clear_running(desc) do { } while (0)
#endif
/** /**
* disable_irq_nosync - disable an irq without waiting * disable_irq_nosync - disable an irq without waiting
* @irq: Interrupt to disable * @irq: Interrupt to disable
...@@ -231,6 +249,9 @@ int show_interrupts(struct seq_file *p, void *v) ...@@ -231,6 +249,9 @@ int show_interrupts(struct seq_file *p, void *v)
} else if (i == NR_IRQS) { } else if (i == NR_IRQS) {
#ifdef CONFIG_ARCH_ACORN #ifdef CONFIG_ARCH_ACORN
show_fiq_list(p, v); show_fiq_list(p, v);
#endif
#ifdef CONFIG_SMP
show_ipi_list(p);
#endif #endif
seq_printf(p, "Err: %10lu\n", irq_err_count); seq_printf(p, "Err: %10lu\n", irq_err_count);
} }
...@@ -329,18 +350,22 @@ void ...@@ -329,18 +350,22 @@ void
do_simple_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) do_simple_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
{ {
struct irqaction *action; struct irqaction *action;
const int cpu = smp_processor_id(); const unsigned int cpu = smp_processor_id();
desc->triggered = 1; desc->triggered = 1;
kstat_cpu(cpu).irqs[irq]++; kstat_cpu(cpu).irqs[irq]++;
smp_set_running(desc);
action = desc->action; action = desc->action;
if (action) { if (action) {
int ret = __do_irq(irq, action, regs); int ret = __do_irq(irq, action, regs);
if (ret != IRQ_HANDLED) if (ret != IRQ_HANDLED)
report_bad_irq(irq, regs, desc, ret); report_bad_irq(irq, regs, desc, ret);
} }
smp_clear_running(desc);
} }
/* /*
...@@ -350,7 +375,7 @@ do_simple_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) ...@@ -350,7 +375,7 @@ do_simple_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
void void
do_edge_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) do_edge_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
{ {
const int cpu = smp_processor_id(); const unsigned int cpu = smp_processor_id();
desc->triggered = 1; desc->triggered = 1;
...@@ -414,7 +439,7 @@ void ...@@ -414,7 +439,7 @@ void
do_level_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) do_level_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
{ {
struct irqaction *action; struct irqaction *action;
const int cpu = smp_processor_id(); const unsigned int cpu = smp_processor_id();
desc->triggered = 1; desc->triggered = 1;
...@@ -426,6 +451,8 @@ do_level_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) ...@@ -426,6 +451,8 @@ do_level_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
if (likely(!desc->disable_depth)) { if (likely(!desc->disable_depth)) {
kstat_cpu(cpu).irqs[irq]++; kstat_cpu(cpu).irqs[irq]++;
smp_set_running(desc);
/* /*
* Return with this interrupt masked if no action * Return with this interrupt masked if no action
*/ */
...@@ -440,6 +467,8 @@ do_level_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) ...@@ -440,6 +467,8 @@ do_level_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
!check_irq_lock(desc, irq, regs))) !check_irq_lock(desc, irq, regs)))
desc->chip->unmask(irq); desc->chip->unmask(irq);
} }
smp_clear_running(desc);
} }
} }
...@@ -878,8 +907,97 @@ int probe_irq_off(unsigned long irqs) ...@@ -878,8 +907,97 @@ int probe_irq_off(unsigned long irqs)
EXPORT_SYMBOL(probe_irq_off); EXPORT_SYMBOL(probe_irq_off);
#ifdef CONFIG_SMP
static void route_irq(struct irqdesc *desc, unsigned int irq, unsigned int cpu)
{
pr_debug("IRQ%u: moving from cpu%u to cpu%u\n", irq, desc->cpu, cpu);
spin_lock_irq(&irq_controller_lock);
desc->cpu = cpu;
desc->chip->set_cpu(desc, irq, cpu);
spin_unlock_irq(&irq_controller_lock);
}
#ifdef CONFIG_PROC_FS
static int
irq_affinity_read_proc(char *page, char **start, off_t off, int count,
int *eof, void *data)
{
struct irqdesc *desc = irq_desc + ((int)data);
int len = cpumask_scnprintf(page, count, desc->affinity);
if (count - len < 2)
return -EINVAL;
page[len++] = '\n';
page[len] = '\0';
return len;
}
static int
irq_affinity_write_proc(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
unsigned int irq = (unsigned int)data;
struct irqdesc *desc = irq_desc + irq;
cpumask_t affinity, tmp;
int ret = -EIO;
if (!desc->chip->set_cpu)
goto out;
ret = cpumask_parse(buffer, count, affinity);
if (ret)
goto out;
cpus_and(tmp, affinity, cpu_online_map);
if (cpus_empty(tmp)) {
ret = -EINVAL;
goto out;
}
desc->affinity = affinity;
route_irq(desc, irq, first_cpu(tmp));
ret = count;
out:
return ret;
}
#endif
#endif
void __init init_irq_proc(void) void __init init_irq_proc(void)
{ {
#if defined(CONFIG_SMP) && defined(CONFIG_PROC_FS)
struct proc_dir_entry *dir;
int irq;
dir = proc_mkdir("irq", 0);
if (!dir)
return;
for (irq = 0; irq < NR_IRQS; irq++) {
struct proc_dir_entry *entry;
struct irqdesc *desc;
char name[16];
desc = irq_desc + irq;
memset(name, 0, sizeof(name));
snprintf(name, sizeof(name) - 1, "%u", irq);
desc->procdir = proc_mkdir(name, dir);
if (!desc->procdir)
continue;
entry = create_proc_entry("smp_affinity", 0600, desc->procdir);
if (entry) {
entry->nlink = 1;
entry->data = (void *)irq;
entry->read_proc = irq_affinity_read_proc;
entry->write_proc = irq_affinity_write_proc;
}
}
#endif
} }
void __init init_IRQ(void) void __init init_IRQ(void)
...@@ -888,6 +1006,11 @@ void __init init_IRQ(void) ...@@ -888,6 +1006,11 @@ void __init init_IRQ(void)
extern void init_dma(void); extern void init_dma(void);
int irq; int irq;
#ifdef CONFIG_SMP
bad_irq_desc.affinity = CPU_MASK_ALL;
bad_irq_desc.cpu = smp_processor_id();
#endif
for (irq = 0, desc = irq_desc; irq < NR_IRQS; irq++, desc++) { for (irq = 0, desc = irq_desc; irq < NR_IRQS; irq++, desc++) {
*desc = bad_irq_desc; *desc = bad_irq_desc;
INIT_LIST_HEAD(&desc->pend); INIT_LIST_HEAD(&desc->pend);
......
...@@ -17,16 +17,16 @@ ...@@ -17,16 +17,16 @@
#include <linux/profile.h> #include <linux/profile.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/cpu.h>
#include <linux/smp.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#include <asm/cacheflush.h>
#include <asm/cpu.h> #include <asm/cpu.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/smp.h>
#include <asm/ptrace.h>
#include <asm/cacheflush.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
#include <asm/ptrace.h>
/* /*
* bitmask of present and online CPUs. * bitmask of present and online CPUs.
...@@ -42,6 +42,7 @@ cpumask_t cpu_online_map; ...@@ -42,6 +42,7 @@ cpumask_t cpu_online_map;
*/ */
struct ipi_data { struct ipi_data {
spinlock_t lock; spinlock_t lock;
unsigned long ipi_count;
unsigned long bits; unsigned long bits;
}; };
...@@ -242,12 +243,12 @@ int smp_call_function(void (*func)(void *info), void *info, int retry, ...@@ -242,12 +243,12 @@ int smp_call_function(void (*func)(void *info), void *info, int retry,
void show_ipi_list(struct seq_file *p) void show_ipi_list(struct seq_file *p)
{ {
int cpu; unsigned int cpu;
seq_printf(p, "IPI: "); seq_puts(p, "IPI:");
for_each_online_cpu(cpu) for_each_online_cpu(cpu)
seq_printf(p, "%10lu ", per_cpu(cpu_data, cpu).ipi_count); seq_printf(p, " %10lu", per_cpu(ipi_data, cpu).ipi_count);
seq_putc(p, '\n'); seq_putc(p, '\n');
} }
...@@ -316,12 +317,11 @@ static void ipi_cpu_stop(unsigned int cpu) ...@@ -316,12 +317,11 @@ static void ipi_cpu_stop(unsigned int cpu)
void do_IPI(unsigned int ipimask, struct pt_regs *regs) void do_IPI(unsigned int ipimask, struct pt_regs *regs)
{ {
unsigned int cpu = smp_processor_id(); unsigned int cpu = smp_processor_id();
struct ipi_data *ipi = &per_cpu(ipi_data, cpu);
per_cpu(cpu_data, cpu).ipi_count++; ipi->ipi_count++;
if (ipimask & (1 << 0)) { if (ipimask & (1 << 0)) {
struct ipi_data *ipi = &per_cpu(ipi_data, cpu);
for (;;) { for (;;) {
unsigned long msgs; unsigned long msgs;
......
...@@ -17,7 +17,6 @@ struct cpuinfo_arm { ...@@ -17,7 +17,6 @@ struct cpuinfo_arm {
struct cpu cpu; struct cpu cpu;
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
unsigned int loops_per_jiffy; unsigned int loops_per_jiffy;
unsigned long ipi_count;
#endif #endif
}; };
......
...@@ -47,6 +47,13 @@ struct irqchip { ...@@ -47,6 +47,13 @@ struct irqchip {
* Set wakeup-enable on the selected IRQ * Set wakeup-enable on the selected IRQ
*/ */
int (*wake)(unsigned int, unsigned int); int (*wake)(unsigned int, unsigned int);
#ifdef CONFIG_SMP
/*
* Route an interrupt to a CPU
*/
void (*set_cpu)(struct irqdesc *desc, unsigned int irq, unsigned int cpu);
#endif
}; };
struct irqdesc { struct irqdesc {
...@@ -67,6 +74,13 @@ struct irqdesc { ...@@ -67,6 +74,13 @@ struct irqdesc {
unsigned int noautoenable : 1; /* don't automatically enable IRQ */ unsigned int noautoenable : 1; /* don't automatically enable IRQ */
unsigned int unused :25; unsigned int unused :25;
struct proc_dir_entry *procdir;
#ifdef CONFIG_SMP
cpumask_t affinity;
unsigned int cpu;
#endif
/* /*
* IRQ lock detection * IRQ lock detection
*/ */
......
...@@ -32,6 +32,13 @@ extern cpumask_t cpu_present_mask; ...@@ -32,6 +32,13 @@ extern cpumask_t cpu_present_mask;
*/ */
#define PROC_CHANGE_PENALTY 15 #define PROC_CHANGE_PENALTY 15
struct seq_file;
/*
* generate IPI list text
*/
extern void show_ipi_list(struct seq_file *p);
/* /*
* Move global data into per-processor storage. * Move global data into per-processor storage.
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment