[prev in list] [next in list] [prev in thread] [next in thread] 

List:       linux-kernel
Subject:    [PATCH] IO-APIC partial enabler, 2.1.84
From:       MOLNAR Ingo <mingo () chiara ! csoma ! elte ! hu>
Date:       1998-01-31 21:56:25
[Download RAW message or body]


this patch brings IO-APIC IRQ handling in sync with the changed IRQ model,
and enables IO-APIC IRQs in some very basic & safe situations:

      - when the IO-APIC has no PCI pins connected
      - when the user has explicitly specified a pirq= line

i've tested these changes with very heavy parallel networking and disk IO
load, and saw not a single problem. The UP and 486 case is not tested yet 
(it's untouched).

there is no black/whitelist yet, will add them ASAP.

the patch also includes 8390.c changes, with them i got rid of those
annoying 'reentering ...' messages.

the pt_regs solution in disable_irq() is quite ugly, is there any better
solution to 'simulate' interrupts from syscall level?

-- mingo

--- 2.1.84/linux/arch/i386/kernel/irq.c	Fri Feb  6 02:28:30 1998
+++ linux/arch/i386/kernel/irq.c	Fri Feb  6 09:21:56 1998
@@ -98,9 +98,6 @@
 
 static int irq_events [NR_IRQS] = { -1, };
 static int disabled_irq [NR_IRQS] = { 0, };
-#ifdef __SMP__
-static int irq_owner [NR_IRQS] = { NO_PROC_ID, };
-#endif
 
 /*
  * Not all IRQs can be routed through the IO-APIC, eg. on certain (older)
@@ -125,7 +122,7 @@
    *  - explicitly use irq 16-19 depending on which PCI irq
    *    line your PCI controller uses.
    */
-  unsigned int io_apic_irqs = 0xff0000;
+  unsigned int io_apic_irqs = 0;
 #endif
 
 static inline void mask_8259A(int irq)
@@ -609,12 +606,40 @@
 
 void enable_irq(unsigned int irq)
 {
+	int cpu = smp_processor_id(), should_handle_irq;
 	unsigned long flags;
 
 	spin_lock_irqsave(&irq_controller_lock, flags);
 	disabled_irq[irq]--;
-	unmask_irq(irq);
-	spin_unlock_irqrestore(&irq_controller_lock, flags);
+
+	if (IO_APIC_IRQ(irq) && !disabled_irq[irq] && irq_events[irq]) {
+		struct pt_regs regs;
+
+		disabled_irq[irq]++;
+		spin_unlock(&irq_controller_lock);
+		release_irqlock(cpu);
+		irq_enter(cpu, irq);
+again:
+		handle_IRQ_event(irq, &regs);
+
+		spin_lock(&irq_controller_lock);
+		disabled_irq[irq]--;
+		should_handle_irq=0;
+		if (--irq_events[irq] && !disabled_irq[irq]) {
+			should_handle_irq=1;
+			disabled_irq[irq]++;
+		}
+		spin_unlock(&irq_controller_lock);
+
+		if (should_handle_irq)
+			goto again;
+
+		irq_exit(cpu, irq);
+		__restore_flags(flags);
+	} else {
+		unmask_irq(irq);
+		spin_unlock_irqrestore(&irq_controller_lock, flags);
+	}
 }
 
 /*
@@ -661,40 +686,34 @@
  */
 static void do_ioapic_IRQ(int irq, int cpu, struct pt_regs * regs)
 {
-	int should_handle_irq;
+	int should_handle_irq = 0;
+
+	ack_APIC_irq();
 
 	spin_lock(&irq_controller_lock);
-	should_handle_irq = 0;
-	if (!irq_events[irq]++ && !disabled_irq[irq]) {
-		should_handle_irq = 1;
-		irq_owner[irq] = cpu;
-		hardirq_enter(cpu);
-	}
 
-	ack_APIC_irq();
+	if (!irq_events[irq]++ && !disabled_irq[irq])
+		should_handle_irq = 1;
 
 	spin_unlock(&irq_controller_lock);
-	
-	if (should_handle_irq) {
-again:
-		if (!handle_IRQ_event(irq, regs))
-			disabled_irq[irq] = 1;
 
-	}
+	irq_enter(cpu, irq);
 
-	spin_lock(&irq_controller_lock);
-	release_irqlock(cpu);
+	if (should_handle_irq) {
+again:
+		handle_IRQ_event(irq, regs);
 
-	if ((--irq_events[irq]) && (!disabled_irq[irq]) && should_handle_irq) {
+		spin_lock(&irq_controller_lock);
+		should_handle_irq=0;
+		if (--irq_events[irq] && !disabled_irq[irq])
+			should_handle_irq=1;
 		spin_unlock(&irq_controller_lock);
-		goto again;
-	}
 
-	irq_owner[irq] = NO_PROC_ID;
-	hardirq_exit(cpu);
-	spin_unlock(&irq_controller_lock);
+		if (should_handle_irq)
+			goto again;
+	}
 
-	enable_IO_APIC_irq(irq);
+	irq_exit(cpu, irq);
 }
 #endif
 
@@ -861,7 +880,7 @@
 unsigned long probe_irq_on (void)
 {
 	unsigned int i, j, irqs = 0;
-	unsigned long delay;
+	unsigned long delay, flags;
 
 	/*
 	 * save current irq counts
@@ -873,10 +892,10 @@
 	 */
 	for (i = NR_IRQS-1; i > 0; i--) {
 		if (!irq_action[i]) {
-			spin_lock(&irq_controller_lock);
+			spin_lock_irqsave(&irq_controller_lock,flags);
 			unmask_irq(i);
 			irqs |= (1 << i);
-			spin_unlock(&irq_controller_lock);
+			spin_unlock_irqrestore(&irq_controller_lock,flags);
 		}
 	}
 
@@ -961,9 +980,6 @@
 	printk("INIT IRQ\n");
 	for (i=0; i<NR_IRQS; i++) {
 		irq_events[i] = 0;
-#ifdef __SMP__
-		irq_owner[i] = NO_PROC_ID;
-#endif
 		disabled_irq[i] = 0;
 	}
 	/*
--- 2.1.84/linux/arch/i386/kernel/smp.c	Sun Feb  1 01:17:45 1998
+++ linux/arch/i386/kernel/smp.c	Fri Feb  6 09:32:24 1998
@@ -367,14 +367,6 @@
 					--mp_irq_entries;
 				}
 
-printk(" Itype:%d Iflag:%d srcbus:%d srcbusI:%d dstapic:%d dstI:%d.\n",
-		m->mpc_irqtype,
-		m->mpc_irqflag,
-		m->mpc_srcbus,
-		m->mpc_srcbusirq,
-		m->mpc_dstapic,
-		m->mpc_dstirq);
-
 				mpt+=sizeof(*m);
 				count+=sizeof(*m);
 				break;
--- 2.1.84/linux/arch/i386/kernel/io_apic.c	Tue Jan 27 04:22:12 1998
+++ linux/arch/i386/kernel/io_apic.c	Fri Feb  6 09:45:13 1998
@@ -129,7 +129,7 @@
 	 * Disable it in the IO-APIC irq-routing table:
 	 */
 	*(((int *)&entry)+0) = io_apic_read(0x10+irq*2);
-	entry.mask = 1;
+	entry.mask = 0;
 	io_apic_write(0x10+2*irq, *(((int *)&entry)+0));
 }
 
@@ -151,8 +151,9 @@
  * specific CPU-side IRQs.
  */
 
-#define MAX_PIRQS 4
+#define MAX_PIRQS 8
 int pirq_entries [MAX_PIRQS];
+int pirqs_enabled;
 
 void ioapic_pirq_setup(char *str, int *ints)
 {
@@ -161,9 +162,12 @@
 	for (i=0; i<MAX_PIRQS; i++)
 		pirq_entries[i]=-1;
 
-	if (!ints)
+	if (!ints) {
+		pirqs_enabled=0;
 		printk("PIRQ redirection SETUP, trusting MP-BIOS.\n");
-	else {
+
+	} else {
+		pirqs_enabled=1;
 		printk("PIRQ redirection SETUP, working around broken MP-BIOS.\n");
 		max = MAX_PIRQS;
 		if (ints[0] < MAX_PIRQS)
@@ -503,6 +507,18 @@
 		if (IO_APIC_IRQ(i))
 			setup_IO_APIC_irq_ISA_default (i);
 #endif
+
+	/*
+	 * the following IO-APIC's can be enabled without any
+	 * blacklist/whitelist checking:
+	 *
+	 * - which have no PCI pins connected
+	 * - for which the user has specified a pirq= parameter
+	 */
+	if ((nr_ioapic_registers == 16) || pirqs_enabled)
+		io_apic_irqs = ~((1<<0)|(1<<2)|(1<<13));
+	else
+		io_apic_irqs = 0;
 
 	setup_IO_APIC_irqs ();
 
--- 2.1.84/linux/drivers/net/8390.c	Thu Jan  8 12:16:26 1998
+++ linux/drivers/net/8390.c	Fri Feb  6 06:48:40 1998
@@ -54,6 +54,8 @@
 #include <asm/uaccess.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/delay.h>
 #include <linux/errno.h>
 #include <linux/fcntl.h>
 #include <linux/in.h>
@@ -185,10 +187,12 @@
 
     /* Mask interrupts from the ethercard. */
     outb_p(0x00, e8390_base + EN0_IMR);
+    disable_irq(dev->irq);
     synchronize_irq();
     if (dev->interrupt) {
 	printk("%s: Tx request while isr active.\n",dev->name);
 	outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+	enable_irq(dev->irq);
 	ei_local->stat.tx_errors++;
 	dev_kfree_skb(skb, FREE_WRITE);
 	return 0;
@@ -226,6 +230,7 @@
 	ei_local->irqlock = 0;
 	dev->tbusy = 1;
 	outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+	enable_irq(dev->irq);
 	ei_local->stat.tx_errors++;
 	return 1;
     }
@@ -272,6 +277,7 @@
     /* Turn 8390 interrupts back on. */
     ei_local->irqlock = 0;
     outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+    enable_irq(dev->irq);
 
     dev_kfree_skb (skb, FREE_WRITE);
     ei_local->stat.tx_bytes += send_length;
@@ -608,7 +614,6 @@
 static void ei_rx_overrun(struct device *dev)
 {
     int e8390_base = dev->base_addr;
-    unsigned long wait_start_time;
     unsigned char was_txing, must_resend = 0;
     struct ei_device *ei_local = (struct ei_device *) dev->priv;
     
@@ -629,9 +634,7 @@
      * it "is not a reliable indicator and subsequently should be ignored."
      * We wait at least 10ms.
      */
-    wait_start_time = jiffies;
-    while (jiffies - wait_start_time <= 1*HZ/100)
-	barrier();
+    udelay(10*1000);
 
     /*
      * Reset RBCR[01] back to zero as per magic incantation.

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic