lkml.org 
[lkml]   [1999]   [May]   [13]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[patch] disable_irq was disable_irq_nosync in Alpha [Re: [2.2.8] undefined reference to `disable_irq_nosync' (+ fix)]
On Thu, 13 May 1999 bvermeul@blackstar.xs4all.nl wrote:

>You seem to have forgotten the fact that linux also supports the Alpha
>platform. That's where I had the problem. The source was freshly untarred,

Since I only have i386 so it's hard for me to try out the code (I could
try if it compile using a cross compiler of course...)

I looked at Alpha now and there is a good news and a bad news...

The good news is that you don't need to implement a disable_irq_nosync()
because it just exists and right now is called disable_irq() (the bad news
is implicit in the good news ;).

(offtopic: I noticed that an Alpha architecture is called "avanti" that in
plain Italian means "go ahead", who knows if it's called so due it's
italian meaning... ;).

Interesting to not that even if disable_irq() in alpha can return before
all irq are expired in all CPU, then if an enable_irq() is run while there
is the irq still running, the Alpha port won't allow the irq to reenter
itself as in the i386 case (but the i386 race was really subtle and the
i386 port was at least trying to wait all irq to expire).

Since it's fun to write code for hardware I don't own I'll try to fix the
race in Alpha too but in remote-mode ;).

Here is an alpha-Alpha patch ;) for 2.2.8 that address the disable_irq()
SMP race. Seems quite strightforward to me.

(it's called alpha-irq-nosync-2.2.8-A)

Index: arch/alpha/kernel/irq.c
===================================================================
RCS file: /var/cvs/linux/arch/alpha/kernel/irq.c,v
retrieving revision 1.1.2.2
diff -u -r1.1.2.2 irq.c
--- irq.c 1999/01/18 13:56:36 1.1.2.2
+++ linux/arch/alpha/kernel/irq.c 1999/05/13 00:33:38
@@ -2,6 +2,8 @@
* linux/arch/alpha/kernel/irq.c
*
* Copyright (C) 1995 Linus Torvalds
+ * Copyright (C) 1999 Andrea Arcangeli (SMP race fixes in disable_irq()
+ * and irq_desc cacheline aligned)
*
* This file contains the code used by various IRQ handling routines:
* asking for different IRQ's should be done through these routines
@@ -176,7 +178,7 @@
*/

static struct irqaction timer_irq = { NULL, 0, 0, NULL, NULL, NULL};
-static struct irqaction *irq_action[NR_IRQS];
+static irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned;


static inline void
@@ -192,7 +194,7 @@
}

void
-disable_irq(unsigned int irq_nr)
+disable_irq_nosync(unsigned int irq_nr)
{
unsigned long flags;

@@ -202,6 +204,22 @@
}

void
+disable_irq(unsigned int irq_nr)
+{
+ unsigned long * status = &irq_desc[irq_nr].status;
+
+ disable_irq_nosync(irq_nr);
+
+ if (!local_irq_count[smp_processor_id()])
+ while (test_and_set_bit(status, IRQ_BUSY_BIT))
+ {
+ do {
+ barrier();
+ } while (test_bit(status, IRQ_BUSY_BIT));
+ }
+}
+
+void
enable_irq(unsigned int irq_nr)
{
unsigned long flags;
@@ -209,6 +227,7 @@
save_and_cli(flags);
unmask_irq(irq_nr);
restore_flags(flags);
+ clear_bit(&irq_desc[irq_nr].status, IRQ_BUSY_BIT);
}

int
@@ -216,7 +235,7 @@
{
struct irqaction **p;

- p = irq_action + irq;
+ p = &irq_desc[irq].irq_action;
if (*p == NULL)
return 0;
return -EBUSY;
@@ -237,7 +256,7 @@
if (!handler)
return -EINVAL;

- p = irq_action + irq;
+ p = &irq_desc[irq].irq_action;
action = *p;
if (action) {
/* Can't share interrupts unless both agree to */
@@ -298,14 +317,14 @@
printk("Trying to free reserved IRQ %d\n", irq);
return;
}
- for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) {
+ for (p = &irq_desc[irq].irq_action; (action = *p) != NULL; p = &action->next) {
if (action->dev_id != dev_id)
continue;

/* Found it - now free it */
save_and_cli(flags);
*p = action->next;
- if (!irq[irq_action])
+ if (!irq_desc[irq].irq_action)
mask_irq(irq);
restore_flags(flags);
kfree(action);
@@ -328,7 +347,7 @@
#endif

for (i = 0; i < NR_IRQS; i++) {
- action = irq_action[i];
+ action = irq_desc[i].irq_action;
if (!action)
continue;
p += sprintf(p, "%3d: ",i);
@@ -711,7 +730,7 @@
printk("PC = %016lx PS=%04lx\n", regs->pc, regs->ps);
printk("Expecting: ");
for (i = 0; i < ACTUAL_NR_IRQS; i++)
- if ((action = irq_action[i]))
+ if ((action = irq_desc[i].irq_action))
while (action->handler) {
printk("[%s:%d] ", action->name, i);
action = action->next;
@@ -736,6 +755,8 @@
handle_irq(int irq, int ack, struct pt_regs * regs)
{
struct irqaction * action;
+ struct irq_desc * desc = &irq_desc[irq];
+ unsigned long * status = &desc->status;
int cpu = smp_processor_id();

if ((unsigned) irq > ACTUAL_NR_IRQS) {
@@ -763,9 +784,12 @@
}
#endif

+ if (test_and_set_bit(status, IRQ_BUSY_BIT))
+ return;
+
irq_enter(cpu, irq);
kstat.irqs[cpu][irq] += 1;
- action = irq_action[irq];
+ action = desc->irq_action;

/*
* For normal interrupts, we mask it out, and then ACK it.
@@ -793,6 +817,8 @@
unexpected_irq(irq, regs);
}
irq_exit(cpu, irq);
+
+ clear_bit(status, IRQ_BUSY_BIT))
}


@@ -812,7 +838,7 @@
if (!(PROBE_MASK & (1UL << i))) {
continue;
}
- action = irq_action[i];
+ action = irq_desc[i].irq_action;
if (!action) {
enable_irq(i);
irqs |= (1UL << i);
Index: arch/alpha/kernel/irq.h
===================================================================
RCS file: /var/cvs/linux/arch/alpha/kernel/irq.h,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 irq.h
--- irq.h 1999/01/18 01:37:13 1.1.2.1
+++ linux/arch/alpha/kernel/irq.h 1999/05/13 00:18:27
@@ -10,6 +10,17 @@

#include <linux/config.h>

+typedef struct
+{
+ unsigned long status;
+#define IRQ_BUSY_BIT 0
+ struct irqaction * irq_action;
+#ifdef __SMP__
+ __attribute__((aligned (L1_CACHE_BYTES)))
+#endif
+}
+irq_desc_t;
+
#define STANDARD_INIT_IRQ_PROLOG \
outb(0, DMA1_RESET_REG); \
outb(0, DMA2_RESET_REG); \
Index: include/asm-alpha/irq.h
===================================================================
RCS file: /var/cvs/linux/include/asm-alpha/irq.h,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 irq.h
--- irq.h 1999/01/18 01:33:41 1.1.2.1
+++ linux/include/asm-alpha/irq.h 1999/05/13 00:20:01
@@ -92,6 +92,7 @@
}

extern void disable_irq(unsigned int);
+extern void disable_irq_nosync(unsigned int);
extern void enable_irq(unsigned int);

struct pt_regs;
Index: arch/alpha/kernel/alpha_ksyms.c
===================================================================
RCS file: /var/cvs/linux/arch/alpha/kernel/alpha_ksyms.c,v
retrieving revision 1.1.2.2
diff -u -r1.1.2.2 alpha_ksyms.c
--- alpha_ksyms.c 1999/01/18 13:56:35 1.1.2.2
+++ linux/arch/alpha/kernel/alpha_ksyms.c 1999/05/13 00:37:12
@@ -52,6 +52,7 @@
EXPORT_SYMBOL(local_irq_count);
EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
+EXPORT_SYMBOL(disable_irq_nosync);
EXPORT_SYMBOL(screen_info);
EXPORT_SYMBOL(perf_irq);

Tell me if it compiles. If it compiles then make sure to use disable_irq()
in the network driver to try out my new code (using disable_irq_nosync()
as 2.2.8 does, wouldn't stress my patch above).

As implementation details: I added a irq_desc because the right thing to
do is to put data accessed by the same CPU near (and in this case I also
added a pad to cacheline align also considering the max nr of irq is 64,
not too much). Otherwise I imagine we would generate a heavy ping pong of
data between L1 caches in SMP.

Andrea Arcangeli


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2005-03-22 13:51    [W:0.085 / U:0.336 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site