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 @@
#include <linux/errno.h>
#include <linux/list.h>
#include <linux/kallsyms.h>
#include <linux/proc_fs.h>
#include <asm/irq.h>
#include <asm/system.h>
......@@ -85,6 +86,23 @@ static struct irqdesc bad_irq_desc = {
.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
* @irq: Interrupt to disable
......@@ -231,6 +249,9 @@ int show_interrupts(struct seq_file *p, void *v)
} else if (i == NR_IRQS) {
#ifdef CONFIG_ARCH_ACORN
show_fiq_list(p, v);
#endif
#ifdef CONFIG_SMP
show_ipi_list(p);
#endif
seq_printf(p, "Err: %10lu\n", irq_err_count);
}
......@@ -329,18 +350,22 @@ void
do_simple_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
{
struct irqaction *action;
const int cpu = smp_processor_id();
const unsigned int cpu = smp_processor_id();
desc->triggered = 1;
kstat_cpu(cpu).irqs[irq]++;
smp_set_running(desc);
action = desc->action;
if (action) {
int ret = __do_irq(irq, action, regs);
if (ret != IRQ_HANDLED)
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)
void
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;
......@@ -414,7 +439,7 @@ void
do_level_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
{
struct irqaction *action;
const int cpu = smp_processor_id();
const unsigned int cpu = smp_processor_id();
desc->triggered = 1;
......@@ -426,6 +451,8 @@ do_level_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
if (likely(!desc->disable_depth)) {
kstat_cpu(cpu).irqs[irq]++;
smp_set_running(desc);
/*
* 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)
!check_irq_lock(desc, irq, regs)))
desc->chip->unmask(irq);
}
smp_clear_running(desc);
}
}
......@@ -878,8 +907,97 @@ int probe_irq_off(unsigned long irqs)
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)
{
#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)
......@@ -888,6 +1006,11 @@ void __init init_IRQ(void)
extern void init_dma(void);
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++) {
*desc = bad_irq_desc;
INIT_LIST_HEAD(&desc->pend);
......
......@@ -17,16 +17,16 @@
#include <linux/profile.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/cpu.h>
#include <linux/smp.h>
#include <linux/seq_file.h>
#include <asm/atomic.h>
#include <asm/cacheflush.h>
#include <asm/cpu.h>
#include <asm/processor.h>
#include <asm/smp.h>
#include <asm/ptrace.h>
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
#include <asm/ptrace.h>
/*
* bitmask of present and online CPUs.
......@@ -42,6 +42,7 @@ cpumask_t cpu_online_map;
*/
struct ipi_data {
spinlock_t lock;
unsigned long ipi_count;
unsigned long bits;
};
......@@ -242,12 +243,12 @@ int smp_call_function(void (*func)(void *info), void *info, int retry,
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)
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');
}
......@@ -316,12 +317,11 @@ static void ipi_cpu_stop(unsigned int cpu)
void do_IPI(unsigned int ipimask, struct pt_regs *regs)
{
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)) {
struct ipi_data *ipi = &per_cpu(ipi_data, cpu);
for (;;) {
unsigned long msgs;
......
......@@ -17,7 +17,6 @@ struct cpuinfo_arm {
struct cpu cpu;
#ifdef CONFIG_SMP
unsigned int loops_per_jiffy;
unsigned long ipi_count;
#endif
};
......
......@@ -47,6 +47,13 @@ struct irqchip {
* Set wakeup-enable on the selected IRQ
*/
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 {
......@@ -67,6 +74,13 @@ struct irqdesc {
unsigned int noautoenable : 1; /* don't automatically enable IRQ */
unsigned int unused :25;
struct proc_dir_entry *procdir;
#ifdef CONFIG_SMP
cpumask_t affinity;
unsigned int cpu;
#endif
/*
* IRQ lock detection
*/
......
......@@ -32,6 +32,13 @@ extern cpumask_t cpu_present_mask;
*/
#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.
*/
......
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