|
@@ -52,3 +52,200 @@ cabriolet_enable_irq(struct irq_data *d)
|
|
|
|
|
|
static void
|
|
|
cabriolet_disable_irq(struct irq_data *d)
|
|
|
+{
|
|
|
+ cabriolet_update_irq_hw(d->irq, cached_irq_mask |= 1UL << d->irq);
|
|
|
+}
|
|
|
+
|
|
|
+static struct irq_chip cabriolet_irq_type = {
|
|
|
+ .name = "CABRIOLET",
|
|
|
+ .irq_unmask = cabriolet_enable_irq,
|
|
|
+ .irq_mask = cabriolet_disable_irq,
|
|
|
+ .irq_mask_ack = cabriolet_disable_irq,
|
|
|
+};
|
|
|
+
|
|
|
+static void
|
|
|
+cabriolet_device_interrupt(unsigned long v)
|
|
|
+{
|
|
|
+ unsigned long pld;
|
|
|
+ unsigned int i;
|
|
|
+
|
|
|
+ /* Read the interrupt summary registers */
|
|
|
+ pld = inb(0x804) | (inb(0x805) << 8) | (inb(0x806) << 16);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Now for every possible bit set, work through them and call
|
|
|
+ * the appropriate interrupt handler.
|
|
|
+ */
|
|
|
+ while (pld) {
|
|
|
+ i = ffz(~pld);
|
|
|
+ pld &= pld - 1; /* clear least bit set */
|
|
|
+ if (i == 4) {
|
|
|
+ isa_device_interrupt(v);
|
|
|
+ } else {
|
|
|
+ handle_irq(16 + i);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void __init
|
|
|
+common_init_irq(void (*srm_dev_int)(unsigned long v))
|
|
|
+{
|
|
|
+ init_i8259a_irqs();
|
|
|
+
|
|
|
+ if (alpha_using_srm) {
|
|
|
+ alpha_mv.device_interrupt = srm_dev_int;
|
|
|
+ init_srm_irqs(35, 0);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ long i;
|
|
|
+
|
|
|
+ outb(0xff, 0x804);
|
|
|
+ outb(0xff, 0x805);
|
|
|
+ outb(0xff, 0x806);
|
|
|
+
|
|
|
+ for (i = 16; i < 35; ++i) {
|
|
|
+ irq_set_chip_and_handler(i, &cabriolet_irq_type,
|
|
|
+ handle_level_irq);
|
|
|
+ irq_set_status_flags(i, IRQ_LEVEL);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ common_init_isa_dma();
|
|
|
+ setup_irq(16+4, &isa_cascade_irqaction);
|
|
|
+}
|
|
|
+
|
|
|
+#ifndef CONFIG_ALPHA_PC164
|
|
|
+static void __init
|
|
|
+cabriolet_init_irq(void)
|
|
|
+{
|
|
|
+ common_init_irq(srm_device_interrupt);
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_PC164)
|
|
|
+/* In theory, the PC164 has the same interrupt hardware as the other
|
|
|
+ Cabriolet based systems. However, something got screwed up late
|
|
|
+ in the development cycle which broke the interrupt masking hardware.
|
|
|
+ Repeat, it is not possible to mask and ack interrupts. At all.
|
|
|
+
|
|
|
+ In an attempt to work around this, while processing interrupts,
|
|
|
+ we do not allow the IPL to drop below what it is currently. This
|
|
|
+ prevents the possibility of recursion.
|
|
|
+
|
|
|
+ ??? Another option might be to force all PCI devices to use edge
|
|
|
+ triggered rather than level triggered interrupts. That might be
|
|
|
+ too invasive though. */
|
|
|
+
|
|
|
+static void
|
|
|
+pc164_srm_device_interrupt(unsigned long v)
|
|
|
+{
|
|
|
+ __min_ipl = getipl();
|
|
|
+ srm_device_interrupt(v);
|
|
|
+ __min_ipl = 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+pc164_device_interrupt(unsigned long v)
|
|
|
+{
|
|
|
+ __min_ipl = getipl();
|
|
|
+ cabriolet_device_interrupt(v);
|
|
|
+ __min_ipl = 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void __init
|
|
|
+pc164_init_irq(void)
|
|
|
+{
|
|
|
+ common_init_irq(pc164_srm_device_interrupt);
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+/*
|
|
|
+ * The EB66+ is very similar to the EB66 except that it does not have
|
|
|
+ * the on-board NCR and Tulip chips. In the code below, I have used
|
|
|
+ * slot number to refer to the id select line and *not* the slot
|
|
|
+ * number used in the EB66+ documentation. However, in the table,
|
|
|
+ * I've given the slot number, the id select line and the Jxx number
|
|
|
+ * that's printed on the board. The interrupt pins from the PCI slots
|
|
|
+ * are wired into 3 interrupt summary registers at 0x804, 0x805 and
|
|
|
+ * 0x806 ISA.
|
|
|
+ *
|
|
|
+ * In the table, -1 means don't assign an IRQ number. This is usually
|
|
|
+ * because it is the Saturn IO (SIO) PCI/ISA Bridge Chip.
|
|
|
+ */
|
|
|
+
|
|
|
+static inline int __init
|
|
|
+eb66p_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
|
|
+{
|
|
|
+ static char irq_tab[5][5] __initdata = {
|
|
|
+ /*INT INTA INTB INTC INTD */
|
|
|
+ {16+0, 16+0, 16+5, 16+9, 16+13}, /* IdSel 6, slot 0, J25 */
|
|
|
+ {16+1, 16+1, 16+6, 16+10, 16+14}, /* IdSel 7, slot 1, J26 */
|
|
|
+ { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */
|
|
|
+ {16+2, 16+2, 16+7, 16+11, 16+15}, /* IdSel 9, slot 2, J27 */
|
|
|
+ {16+3, 16+3, 16+8, 16+12, 16+6} /* IdSel 10, slot 3, J28 */
|
|
|
+ };
|
|
|
+ const long min_idsel = 6, max_idsel = 10, irqs_per_slot = 5;
|
|
|
+ return COMMON_TABLE_LOOKUP;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/*
|
|
|
+ * The AlphaPC64 is very similar to the EB66+ except that its slots
|
|
|
+ * are numbered differently. In the code below, I have used slot
|
|
|
+ * number to refer to the id select line and *not* the slot number
|
|
|
+ * used in the AlphaPC64 documentation. However, in the table, I've
|
|
|
+ * given the slot number, the id select line and the Jxx number that's
|
|
|
+ * printed on the board. The interrupt pins from the PCI slots are
|
|
|
+ * wired into 3 interrupt summary registers at 0x804, 0x805 and 0x806
|
|
|
+ * ISA.
|
|
|
+ *
|
|
|
+ * In the table, -1 means don't assign an IRQ number. This is usually
|
|
|
+ * because it is the Saturn IO (SIO) PCI/ISA Bridge Chip.
|
|
|
+ */
|
|
|
+
|
|
|
+static inline int __init
|
|
|
+cabriolet_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
|
|
+{
|
|
|
+ static char irq_tab[5][5] __initdata = {
|
|
|
+ /*INT INTA INTB INTC INTD */
|
|
|
+ { 16+2, 16+2, 16+7, 16+11, 16+15}, /* IdSel 5, slot 2, J21 */
|
|
|
+ { 16+0, 16+0, 16+5, 16+9, 16+13}, /* IdSel 6, slot 0, J19 */
|
|
|
+ { 16+1, 16+1, 16+6, 16+10, 16+14}, /* IdSel 7, slot 1, J20 */
|
|
|
+ { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */
|
|
|
+ { 16+3, 16+3, 16+8, 16+12, 16+16} /* IdSel 9, slot 3, J22 */
|
|
|
+ };
|
|
|
+ const long min_idsel = 5, max_idsel = 9, irqs_per_slot = 5;
|
|
|
+ return COMMON_TABLE_LOOKUP;
|
|
|
+}
|
|
|
+
|
|
|
+static inline void __init
|
|
|
+cabriolet_enable_ide(void)
|
|
|
+{
|
|
|
+ if (pc873xx_probe() == -1) {
|
|
|
+ printk(KERN_ERR "Probing for PC873xx Super IO chip failed.\n");
|
|
|
+ } else {
|
|
|
+ printk(KERN_INFO "Found %s Super IO chip at 0x%x\n",
|
|
|
+ pc873xx_get_model(), pc873xx_get_base());
|
|
|
+
|
|
|
+ pc873xx_enable_ide();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static inline void __init
|
|
|
+cabriolet_init_pci(void)
|
|
|
+{
|
|
|
+ common_init_pci();
|
|
|
+ cabriolet_enable_ide();
|
|
|
+}
|
|
|
+
|
|
|
+static inline void __init
|
|
|
+cia_cab_init_pci(void)
|
|
|
+{
|
|
|
+ cia_init_pci();
|
|
|
+ cabriolet_enable_ide();
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * The PC164 and LX164 have 19 PCI interrupts, four from each of the four
|
|
|
+ * PCI slots, the SIO, PCI/IDE, and USB.
|
|
|
+ *
|