X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fsparc64%2Fkernel%2Firq.c;h=b7f6a1eb922fd0e033a948c468ee5275795ea330;hb=1be35e94e1da3669db492995cd2c8b1a37016b11;hp=d52b842915d42204001013460cb048b9560c888e;hpb=a91482bdcc2e0f6035702e46f1b99043a0893346;p=linux-2.6.git diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index d52b84291..b7f6a1eb9 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -118,6 +118,10 @@ static void register_irq_proc (unsigned int irq); action->flags |= __irq_ino(irq) << 48; #define get_ino_in_irqaction(action) (action->flags >> 48) +#if NR_CPUS > 64 +#error irqaction embedded smp affinity does not work with > 64 cpus, FIXME +#endif + #define put_smpaff_in_irqaction(action, smpaff) (action)->mask = (smpaff) #define get_smpaff_in_irqaction(action) ((action)->mask) @@ -454,7 +458,7 @@ int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_ action->next = NULL; action->dev_id = dev_id; put_ino_in_irqaction(action, irq); - put_smpaff_in_irqaction(action, CPU_MASK_NONE); + put_smpaff_in_irqaction(action, 0); if (tmp) tmp->next = action; @@ -687,10 +691,9 @@ static inline void redirect_intr(int cpu, struct ino_bucket *bp) * Just Do It. */ struct irqaction *ap = bp->irq_info; - cpumask_t cpu_mask; + cpumask_t cpu_mask = get_smpaff_in_irqaction(ap); unsigned int buddy, ticks; - cpu_mask = get_smpaff_in_irqaction(ap); cpus_and(cpu_mask, cpu_mask, cpu_online_map); if (cpus_empty(cpu_mask)) cpu_mask = cpu_online_map; @@ -711,7 +714,7 @@ static inline void redirect_intr(int cpu, struct ino_bucket *bp) if (++buddy >= NR_CPUS) buddy = 0; if (++ticks > NR_CPUS) { - put_smpaff_in_irqaction(ap, CPU_MASK_NONE); + put_smpaff_in_irqaction(ap, 0); goto out; } } @@ -945,7 +948,7 @@ int request_fast_irq(unsigned int irq, action->name = name; action->next = NULL; put_ino_in_irqaction(action, irq); - put_smpaff_in_irqaction(action, CPU_MASK_NONE); + put_smpaff_in_irqaction(action, 0); *(bucket->pil + irq_action) = action; enable_irq(irq); @@ -1163,15 +1166,53 @@ static struct proc_dir_entry * irq_dir [NUM_IVECS]; #ifdef CONFIG_SMP +#define HEX_DIGITS 16 + +static unsigned int parse_hex_value (const char __user *buffer, + unsigned long count, unsigned long *ret) +{ + unsigned char hexnum [HEX_DIGITS]; + unsigned long value; + int i; + + if (!count) + return -EINVAL; + if (count > HEX_DIGITS) + count = HEX_DIGITS; + if (copy_from_user(hexnum, buffer, count)) + return -EFAULT; + + /* + * Parse the first 8 characters as a hex string, any non-hex char + * is end-of-string. '00e1', 'e1', '00E1', 'E1' are all the same. + */ + value = 0; + + for (i = 0; i < count; i++) { + unsigned int c = hexnum[i]; + + switch (c) { + case '0' ... '9': c -= '0'; break; + case 'a' ... 'f': c -= 'a'-10; break; + case 'A' ... 'F': c -= 'A'-10; break; + default: + goto out; + } + value = (value << 4) | c; + } +out: + *ret = value; + return 0; +} + static int irq_affinity_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) { struct ino_bucket *bp = ivector_table + (long)data; struct irqaction *ap = bp->irq_info; - cpumask_t mask; + cpumask_t mask = get_smpaff_in_irqaction(ap); int len; - mask = get_smpaff_in_irqaction(ap); if (cpus_empty(mask)) mask = cpu_online_map; @@ -1182,7 +1223,7 @@ static int irq_affinity_read_proc (char *page, char **start, off_t off, return len; } -static inline void set_intr_affinity(int irq, cpumask_t hw_aff) +static inline void set_intr_affinity(int irq, unsigned long hw_aff) { struct ino_bucket *bp = ivector_table + irq; @@ -1200,17 +1241,22 @@ static int irq_affinity_write_proc (struct file *file, const char __user *buffer unsigned long count, void *data) { int irq = (long) data, full_count = count, err; - cpumask_t new_value; + unsigned long new_value, i; - err = cpumask_parse(buffer, count, new_value); + err = parse_hex_value(buffer, count, &new_value); /* * Do not allow disabling IRQs completely - it's a too easy * way to make the system unusable accidentally :-) At least * one online CPU still has to be targeted. */ - cpus_and(new_value, new_value, cpu_online_map); - if (cpus_empty(new_value)) + for (i = 0; i < NR_CPUS; i++) { + if ((new_value & (1UL << i)) != 0 && + !cpu_online(i)) + new_value &= ~(1UL << i); + } + + if (!new_value) return -EINVAL; set_intr_affinity(irq, new_value); @@ -1256,6 +1302,6 @@ static void register_irq_proc (unsigned int irq) void init_irq_proc (void) { /* create /proc/irq */ - root_irq_dir = proc_mkdir("irq", NULL); + root_irq_dir = proc_mkdir("irq", 0); }