patch-2.3.48 linux/arch/i386/kernel/io_apic.c

Next file: linux/arch/i386/kernel/irq.c
Previous file: linux/arch/i386/kernel/i8259.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.47/linux/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c
@@ -28,6 +28,8 @@
 #include <asm/smp.h>
 #include <asm/desc.h>
 
+static spinlock_t ioapic_lock = SPIN_LOCK_UNLOCKED;
+
 /*
  * # of IO-APICs and # of IRQ routing registers
  */
@@ -87,9 +89,8 @@
 	entry->pin = pin;
 }
 
-#define DO_ACTION(name,R,ACTION, FINAL)					\
+#define __DO_ACTION(name,R,ACTION, FINAL)				\
 									\
-static void name##_IO_APIC_irq(unsigned int irq)			\
 {									\
 	int pin;							\
 	struct irq_pin_list *entry = irq_2_pin + irq;			\
@@ -109,8 +110,31 @@
 	FINAL;								\
 }
 
-DO_ACTION( mask,    0, |= 0x00010000, io_apic_sync(entry->apic))/* mask = 1 */
-DO_ACTION( unmask,  0, &= 0xfffeffff, )				/* mask = 0 */
+#define DO_ACTION(name,R,ACTION, FINAL)					\
+									\
+static void name##_IO_APIC_irq(unsigned int irq)			\
+__DO_ACTION(name,R,ACTION, FINAL)
+
+DO_ACTION( __mask,    0, |= 0x00010000, io_apic_sync(entry->apic))/* mask = 1 */
+DO_ACTION( __unmask,  0, &= 0xfffeffff, )				/* mask = 0 */
+
+static void mask_IO_APIC_irq (unsigned int irq)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ioapic_lock, flags);
+	__mask_IO_APIC_irq(irq);
+	spin_unlock_irqrestore(&ioapic_lock, flags);
+}
+
+static void unmask_IO_APIC_irq (unsigned int irq)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ioapic_lock, flags);
+	__unmask_IO_APIC_irq(irq);
+	spin_unlock_irqrestore(&ioapic_lock, flags);
+}
 
 void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
 {
@@ -537,7 +561,7 @@
 		entry.delivery_mode = dest_LowestPrio;
 		entry.dest_mode = 1;			/* logical delivery */
 		entry.mask = 0;				/* enable IRQ */
-		entry.dest.logical.logical_dest = APIC_ALL_CPUS; /* all CPUs */
+		entry.dest.logical.logical_dest = APIC_ALL_CPUS;
 
 		idx = find_irq_entry(apic,pin,mp_INT);
 		if (idx == -1) {
@@ -1026,16 +1050,16 @@
 
 static int __init nmi_irq_works(void)
 {
-	atomic_t tmp[NR_CPUS];
+	irq_cpustat_t tmp[NR_CPUS];
 	int j, cpu;
 
-	memcpy(tmp, nmi_counter, sizeof(tmp));
+	memcpy(tmp, irq_stat, sizeof(tmp));
 	sti();
 	mdelay(50);
 
 	for (j = 0; j < smp_num_cpus; j++) {
 		cpu = cpu_logical_map(j);
-		if (atomic_read(nmi_counter+cpu) - atomic_read(tmp+cpu) <= 3) {
+		if (atomic_read(&nmi_counter(cpu)) - atomic_read(&tmp[cpu].__nmi_counter) <= 3) {
 			printk("CPU#%d NMI appears to be stuck.\n", cpu);
 			return 0;
 		}
@@ -1055,14 +1079,9 @@
  * that was delayed but this is now handled in the device
  * independent code.
  */
-static void enable_edge_ioapic_irq(unsigned int irq)
-{
-	unmask_IO_APIC_irq(irq);
-}
+#define enable_edge_ioapic_irq unmask_IO_APIC_irq
 
-static void disable_edge_ioapic_irq(unsigned int irq)
-{
-}
+static void disable_edge_ioapic_irq (unsigned int irq) { /* nothing */ }
 
 /*
  * Starting up a edge-triggered IO-APIC interrupt is
@@ -1077,12 +1096,17 @@
 static unsigned int startup_edge_ioapic_irq(unsigned int irq)
 {
 	int was_pending = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ioapic_lock, flags);
 	if (irq < 16) {
 		disable_8259A_irq(irq);
 		if (i8259A_irq_pending(irq))
 			was_pending = 1;
 	}
-	enable_edge_ioapic_irq(irq);
+	__unmask_IO_APIC_irq(irq);
+	spin_unlock_irqrestore(&ioapic_lock, flags);
+
 	return was_pending;
 }
 
@@ -1093,14 +1117,15 @@
  * interrupt for real. This prevents IRQ storms from unhandled
  * devices.
  */
-void static ack_edge_ioapic_irq(unsigned int irq)
+static void ack_edge_ioapic_irq(unsigned int irq)
 {
 	if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED))
 					== (IRQ_PENDING | IRQ_DISABLED))
 		mask_IO_APIC_irq(irq);
 	ack_APIC_irq();
 }
-void static end_edge_ioapic_irq(unsigned int i){}
+
+static void end_edge_ioapic_irq (unsigned int i) { /* nothing */ }
 
 
 /*
@@ -1108,23 +1133,46 @@
  * and shutting down and starting up the interrupt
  * is the same as enabling and disabling them -- except
  * with a startup need to return a "was pending" value.
+ *
+ * Level triggered interrupts are special because we
+ * do not touch any IO-APIC register while handling
+ * them. We ack the APIC in the end-IRQ handler, not
+ * in the start-IRQ-handler. Protection against reentrance
+ * from the same interrupt is still provided, both by the
+ * generic IRQ layer and by the fact that an unacked local
+ * APIC does not accept IRQs.
  */
-static unsigned int startup_level_ioapic_irq(unsigned int irq)
+static unsigned int startup_level_ioapic_irq (unsigned int irq)
 {
 	unmask_IO_APIC_irq(irq);
+
 	return 0; /* don't check for pending */
 }
 
 #define shutdown_level_ioapic_irq	mask_IO_APIC_irq
 #define enable_level_ioapic_irq		unmask_IO_APIC_irq
 #define disable_level_ioapic_irq	mask_IO_APIC_irq
-#define end_level_ioapic_irq		unmask_IO_APIC_irq	
-void static mask_and_ack_level_ioapic_irq(unsigned int i)
+
+static void end_level_ioapic_irq (unsigned int i)
 {
-	mask_IO_APIC_irq(i);
 	ack_APIC_irq();
 }
 
+static void mask_and_ack_level_ioapic_irq (unsigned int i) { /* nothing */ }
+
+static void set_ioapic_affinity (unsigned int irq, unsigned int mask)
+{
+	unsigned long flags;
+	/*
+	 * Only the first 8 bits are valid.
+	 */
+	mask = mask << 24;
+
+	spin_lock_irqsave(&ioapic_lock, flags);
+	__DO_ACTION( target,  1, = mask, )
+	spin_unlock_irqrestore(&ioapic_lock, flags);
+}
+
 /*
  * Level and edge triggered IO-APIC interrupts need different handling,
  * so we use two separate IRQ descriptors. Edge triggered IRQs can be
@@ -1141,7 +1189,8 @@
 	enable_edge_ioapic_irq,
 	disable_edge_ioapic_irq,
 	ack_edge_ioapic_irq,
-	end_edge_ioapic_irq
+	end_edge_ioapic_irq,
+	set_ioapic_affinity,
 };
 
 static struct hw_interrupt_type ioapic_level_irq_type = {
@@ -1151,7 +1200,8 @@
 	enable_level_ioapic_irq,
 	disable_level_ioapic_irq,
 	mask_and_ack_level_ioapic_irq,
-	end_level_ioapic_irq
+	end_level_ioapic_irq,
+	set_ioapic_affinity,
 };
 
 static inline void init_IO_APIC_traps(void)
@@ -1185,12 +1235,12 @@
 	}
 }
 
-void static ack_lapic_irq (unsigned int irq)
+static void ack_lapic_irq (unsigned int irq)
 {
 	ack_APIC_irq();
 }
 
-void static end_lapic_irq (unsigned int i) { /* nothing */ }
+static void end_lapic_irq (unsigned int i) { /* nothing */ }
 
 static struct hw_interrupt_type lapic_irq_type = {
 	"local-APIC-edge",

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)