ftape on Cabrio---finally!

David Mosberger-Tang (davidm@AZStarNet.com)
Wed, 15 Nov 1995 23:22:46 -0700


Well, now that my Noname is back up (thanks to DEC for replacing the
faulty board and for RedHat for getting me an installation booster!) I
finally got back to looking into why ftape doesn't work on the
Cabriolet when it works just fine on the Noname. Turns out it was a
simple bug due to differences in the PALcode: the Noname PALcode does
the PCI interrupt acknowledge cycle all by itself, whereas the
Cabrio's PALcode doesn't do anything. Thus, the PIC never learned
that the CPU was processing the interrupt until it actually got
acknowledged (which, for SA_INTERRUPT handlers, happens only at the
end of the handler). Now the ftape handler likes to re-enable
interrupts because it's relatively slow, so BOOM, the interrupt
strikes again and that repeats itself until the kernel stack
overflows...

The simple fix is appended to this mail.

--david

--- 386/arch/alpha/kernel/irq.c Sat Oct 28 18:19:09 1995
+++ Cabriolet/arch/alpha/kernel/irq.c Thu Nov 16 05:07:35 1995
@@ -352,8 +352,39 @@
static inline void isa_device_interrupt(unsigned long vector,
struct pt_regs * regs)
{
- unsigned long pic;
+#if defined(CONFIG_ALPHA_APECS)
+# define IACK_SC APECS_IACK_SC
+#elif defined(CONFIG_ALPHA_LCA)
+# define IACK_SC LCA_IACK_SC
+#endif
int j;
+
+ /*
+ * Generate a PCI interrupt acknowledge cycle. The PIC will
+ * respond with the interrupt vector of the highest priority
+ * interrupt that is pending. The PALcode sets up the
+ * interrupts vectors such that irq level L generates vector
+ * L.
+ */
+ j = *(volatile int *) IACK_SC;
+ j &= 0xff;
+ if (j == 7) {
+ if (!(inb(0x20) & 0x80)) {
+ /* it's only a passive release... */
+ return;
+ }
+ }
+ device_interrupt(j, j, regs);
+#if 0
+ unsigned long pic;
+
+ /*
+ * It seems to me that the probability of two or more *device*
+ * interrupts occuring at almost exactly the same time is
+ * pretty low. So why pay the price of checking for
+ * additional interrupts here if the common case can be
+ * handled so much easier?
+ */
/*
* The first read of gives you *all* interrupting lines.
* Therefore, read the mask register and and out those lines
@@ -369,6 +400,7 @@
pic &= pic - 1;
device_interrupt(j, j, regs);
}
+#endif
}

static inline void cabriolet_and_eb66p_device_interrupt(unsigned long vector,