aboutsummaryrefslogtreecommitdiffstats
path: root/arch/m68k/mac
diff options
context:
space:
mode:
Diffstat (limited to 'arch/m68k/mac')
-rw-r--r--arch/m68k/mac/baboon.c58
-rw-r--r--arch/m68k/mac/config.c93
-rw-r--r--arch/m68k/mac/iop.c16
-rw-r--r--arch/m68k/mac/macints.c217
-rw-r--r--arch/m68k/mac/oss.c199
-rw-r--r--arch/m68k/mac/psc.c66
-rw-r--r--arch/m68k/mac/via.c329
7 files changed, 382 insertions, 596 deletions
diff --git a/arch/m68k/mac/baboon.c b/arch/m68k/mac/baboon.c
index 2a96bebd8969..3fe0e43d44f6 100644
--- a/arch/m68k/mac/baboon.c
+++ b/arch/m68k/mac/baboon.c
@@ -8,24 +8,16 @@
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/delay.h>
-#include <linux/init.h>
+#include <linux/irq.h>
-#include <asm/traps.h>
-#include <asm/bootinfo.h>
#include <asm/macintosh.h>
#include <asm/macints.h>
#include <asm/mac_baboon.h>
/* #define DEBUG_IRQS */
-extern void mac_enable_irq(unsigned int);
-extern void mac_disable_irq(unsigned int);
-
int baboon_present;
static volatile struct baboon *baboon;
-static unsigned char baboon_disabled;
#if 0
extern int macide_ack_intr(struct ata_channel *);
@@ -53,7 +45,7 @@ void __init baboon_init(void)
* Baboon interrupt handler. This works a lot like a VIA.
*/
-static irqreturn_t baboon_irq(int irq, void *dev_id)
+static void baboon_irq(unsigned int irq, struct irq_desc *desc)
{
int irq_bit, irq_num;
unsigned char events;
@@ -64,15 +56,16 @@ static irqreturn_t baboon_irq(int irq, void *dev_id)
(uint) baboon->mb_status);
#endif
- if (!(events = baboon->mb_ifr & 0x07))
- return IRQ_NONE;
+ events = baboon->mb_ifr & 0x07;
+ if (!events)
+ return;
irq_num = IRQ_BABOON_0;
irq_bit = 1;
do {
if (events & irq_bit) {
baboon->mb_ifr &= ~irq_bit;
- m68k_handle_int(irq_num);
+ generic_handle_irq(irq_num);
}
irq_bit <<= 1;
irq_num++;
@@ -82,7 +75,6 @@ static irqreturn_t baboon_irq(int irq, void *dev_id)
/* for now we need to smash all interrupts */
baboon->mb_ifr &= ~events;
#endif
- return IRQ_HANDLED;
}
/*
@@ -91,52 +83,32 @@ static irqreturn_t baboon_irq(int irq, void *dev_id)
void __init baboon_register_interrupts(void)
{
- baboon_disabled = 0;
- if (request_irq(IRQ_NUBUS_C, baboon_irq, 0, "baboon", (void *)baboon))
- pr_err("Couldn't register baboon interrupt\n");
+ irq_set_chained_handler(IRQ_NUBUS_C, baboon_irq);
}
/*
- * The means for masking individual baboon interrupts remains a mystery, so
- * enable the umbrella interrupt only when no baboon interrupt is disabled.
+ * The means for masking individual Baboon interrupts remains a mystery.
+ * However, since we only use the IDE IRQ, we can just enable/disable all
+ * Baboon interrupts. If/when we handle more than one Baboon IRQ, we must
+ * either figure out how to mask them individually or else implement the
+ * same workaround that's used for NuBus slots (see nubus_disabled and
+ * via_nubus_irq_shutdown).
*/
void baboon_irq_enable(int irq)
{
- int irq_idx = IRQ_IDX(irq);
-
#ifdef DEBUG_IRQUSE
printk("baboon_irq_enable(%d)\n", irq);
#endif
- baboon_disabled &= ~(1 << irq_idx);
- if (!baboon_disabled)
- mac_enable_irq(IRQ_NUBUS_C);
+ mac_irq_enable(irq_get_irq_data(IRQ_NUBUS_C));
}
void baboon_irq_disable(int irq)
{
- int irq_idx = IRQ_IDX(irq);
-
#ifdef DEBUG_IRQUSE
printk("baboon_irq_disable(%d)\n", irq);
#endif
- baboon_disabled |= 1 << irq_idx;
- if (baboon_disabled)
- mac_disable_irq(IRQ_NUBUS_C);
-}
-
-void baboon_irq_clear(int irq)
-{
- int irq_idx = IRQ_IDX(irq);
-
- baboon->mb_ifr &= ~(1 << irq_idx);
-}
-
-int baboon_irq_pending(int irq)
-{
- int irq_idx = IRQ_IDX(irq);
-
- return baboon->mb_ifr & (1 << irq_idx);
+ mac_irq_disable(irq_get_irq_data(IRQ_NUBUS_C));
}
diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c
index c247de02bc7e..f60ff5f59205 100644
--- a/arch/m68k/mac/config.c
+++ b/arch/m68k/mac/config.c
@@ -71,6 +71,31 @@ static void mac_get_model(char *str);
static void mac_identify(void);
static void mac_report_hardware(void);
+#ifdef CONFIG_EARLY_PRINTK
+asmlinkage void __init mac_early_print(const char *s, unsigned n);
+
+static void __init mac_early_cons_write(struct console *con,
+ const char *s, unsigned n)
+{
+ mac_early_print(s, n);
+}
+
+static struct console __initdata mac_early_cons = {
+ .name = "early",
+ .write = mac_early_cons_write,
+ .flags = CON_PRINTBUFFER | CON_BOOT,
+ .index = -1
+};
+
+int __init mac_unregister_early_cons(void)
+{
+ /* mac_early_print can't be used after init sections are discarded */
+ return unregister_console(&mac_early_cons);
+}
+
+late_initcall(mac_unregister_early_cons);
+#endif
+
static void __init mac_sched_init(irq_handler_t vector)
{
via_init_clock(vector);
@@ -164,6 +189,10 @@ void __init config_mac(void)
mach_beep = mac_mksound;
#endif
+#ifdef CONFIG_EARLY_PRINTK
+ register_console(&mac_early_cons);
+#endif
+
/*
* Determine hardware present
*/
@@ -192,7 +221,7 @@ void __init config_mac(void)
* inaccurate, so look here if a new Mac model won't run. Example: if
* a Mac crashes immediately after the VIA1 registers have been dumped
* to the screen, it probably died attempting to read DirB on a RBV.
- * Meaning it should have MAC_VIA_IIci here :-)
+ * Meaning it should have MAC_VIA_IICI here :-)
*/
struct mac_model *macintosh_config;
@@ -267,7 +296,7 @@ static struct mac_model mac_data_table[] = {
.ident = MAC_MODEL_IICI,
.name = "IIci",
.adb_type = MAC_ADB_II,
- .via_type = MAC_VIA_IIci,
+ .via_type = MAC_VIA_IICI,
.scsi_type = MAC_SCSI_OLD,
.scc_type = MAC_SCC_II,
.nubus_type = MAC_NUBUS,
@@ -276,7 +305,7 @@ static struct mac_model mac_data_table[] = {
.ident = MAC_MODEL_IIFX,
.name = "IIfx",
.adb_type = MAC_ADB_IOP,
- .via_type = MAC_VIA_IIci,
+ .via_type = MAC_VIA_IICI,
.scsi_type = MAC_SCSI_OLD,
.scc_type = MAC_SCC_IOP,
.nubus_type = MAC_NUBUS,
@@ -285,7 +314,7 @@ static struct mac_model mac_data_table[] = {
.ident = MAC_MODEL_IISI,
.name = "IIsi",
.adb_type = MAC_ADB_IISI,
- .via_type = MAC_VIA_IIci,
+ .via_type = MAC_VIA_IICI,
.scsi_type = MAC_SCSI_OLD,
.scc_type = MAC_SCC_II,
.nubus_type = MAC_NUBUS,
@@ -294,7 +323,7 @@ static struct mac_model mac_data_table[] = {
.ident = MAC_MODEL_IIVI,
.name = "IIvi",
.adb_type = MAC_ADB_IISI,
- .via_type = MAC_VIA_IIci,
+ .via_type = MAC_VIA_IICI,
.scsi_type = MAC_SCSI_OLD,
.scc_type = MAC_SCC_II,
.nubus_type = MAC_NUBUS,
@@ -303,7 +332,7 @@ static struct mac_model mac_data_table[] = {
.ident = MAC_MODEL_IIVX,
.name = "IIvx",
.adb_type = MAC_ADB_IISI,
- .via_type = MAC_VIA_IIci,
+ .via_type = MAC_VIA_IICI,
.scsi_type = MAC_SCSI_OLD,
.scc_type = MAC_SCC_II,
.nubus_type = MAC_NUBUS,
@@ -318,7 +347,7 @@ static struct mac_model mac_data_table[] = {
.ident = MAC_MODEL_CLII,
.name = "Classic II",
.adb_type = MAC_ADB_IISI,
- .via_type = MAC_VIA_IIci,
+ .via_type = MAC_VIA_IICI,
.scsi_type = MAC_SCSI_OLD,
.scc_type = MAC_SCC_II,
.nubus_type = MAC_NUBUS,
@@ -327,7 +356,7 @@ static struct mac_model mac_data_table[] = {
.ident = MAC_MODEL_CCL,
.name = "Color Classic",
.adb_type = MAC_ADB_CUDA,
- .via_type = MAC_VIA_IIci,
+ .via_type = MAC_VIA_IICI,
.scsi_type = MAC_SCSI_OLD,
.scc_type = MAC_SCC_II,
.nubus_type = MAC_NUBUS,
@@ -336,7 +365,7 @@ static struct mac_model mac_data_table[] = {
.ident = MAC_MODEL_CCLII,
.name = "Color Classic II",
.adb_type = MAC_ADB_CUDA,
- .via_type = MAC_VIA_IIci,
+ .via_type = MAC_VIA_IICI,
.scsi_type = MAC_SCSI_OLD,
.scc_type = MAC_SCC_II,
.nubus_type = MAC_NUBUS,
@@ -351,7 +380,7 @@ static struct mac_model mac_data_table[] = {
.ident = MAC_MODEL_LC,
.name = "LC",
.adb_type = MAC_ADB_IISI,
- .via_type = MAC_VIA_IIci,
+ .via_type = MAC_VIA_IICI,
.scsi_type = MAC_SCSI_OLD,
.scc_type = MAC_SCC_II,
.nubus_type = MAC_NUBUS,
@@ -360,7 +389,7 @@ static struct mac_model mac_data_table[] = {
.ident = MAC_MODEL_LCII,
.name = "LC II",
.adb_type = MAC_ADB_IISI,
- .via_type = MAC_VIA_IIci,
+ .via_type = MAC_VIA_IICI,
.scsi_type = MAC_SCSI_OLD,
.scc_type = MAC_SCC_II,
.nubus_type = MAC_NUBUS,
@@ -369,7 +398,7 @@ static struct mac_model mac_data_table[] = {
.ident = MAC_MODEL_LCIII,
.name = "LC III",
.adb_type = MAC_ADB_IISI,
- .via_type = MAC_VIA_IIci,
+ .via_type = MAC_VIA_IICI,
.scsi_type = MAC_SCSI_OLD,
.scc_type = MAC_SCC_II,
.nubus_type = MAC_NUBUS,
@@ -497,7 +526,7 @@ static struct mac_model mac_data_table[] = {
.ident = MAC_MODEL_P460,
.name = "Performa 460",
.adb_type = MAC_ADB_IISI,
- .via_type = MAC_VIA_IIci,
+ .via_type = MAC_VIA_IICI,
.scsi_type = MAC_SCSI_OLD,
.scc_type = MAC_SCC_II,
.nubus_type = MAC_NUBUS,
@@ -524,7 +553,7 @@ static struct mac_model mac_data_table[] = {
.ident = MAC_MODEL_P520,
.name = "Performa 520",
.adb_type = MAC_ADB_CUDA,
- .via_type = MAC_VIA_IIci,
+ .via_type = MAC_VIA_IICI,
.scsi_type = MAC_SCSI_OLD,
.scc_type = MAC_SCC_II,
.nubus_type = MAC_NUBUS,
@@ -533,7 +562,7 @@ static struct mac_model mac_data_table[] = {
.ident = MAC_MODEL_P550,
.name = "Performa 550",
.adb_type = MAC_ADB_CUDA,
- .via_type = MAC_VIA_IIci,
+ .via_type = MAC_VIA_IICI,
.scsi_type = MAC_SCSI_OLD,
.scc_type = MAC_SCC_II,
.nubus_type = MAC_NUBUS,
@@ -565,7 +594,7 @@ static struct mac_model mac_data_table[] = {
.ident = MAC_MODEL_TV,
.name = "TV",
.adb_type = MAC_ADB_CUDA,
- .via_type = MAC_VIA_QUADRA,
+ .via_type = MAC_VIA_IICI,
.scsi_type = MAC_SCSI_OLD,
.scc_type = MAC_SCC_II,
.nubus_type = MAC_NUBUS,
@@ -574,7 +603,7 @@ static struct mac_model mac_data_table[] = {
.ident = MAC_MODEL_P600,
.name = "Performa 600",
.adb_type = MAC_ADB_IISI,
- .via_type = MAC_VIA_IIci,
+ .via_type = MAC_VIA_IICI,
.scsi_type = MAC_SCSI_OLD,
.scc_type = MAC_SCC_II,
.nubus_type = MAC_NUBUS,
@@ -645,8 +674,8 @@ static struct mac_model mac_data_table[] = {
}, {
.ident = MAC_MODEL_PB150,
.name = "PowerBook 150",
- .adb_type = MAC_ADB_PB1,
- .via_type = MAC_VIA_IIci,
+ .adb_type = MAC_ADB_PB2,
+ .via_type = MAC_VIA_IICI,
.scsi_type = MAC_SCSI_OLD,
.ide_type = MAC_IDE_PB,
.scc_type = MAC_SCC_QUADRA,
@@ -732,17 +761,13 @@ static struct mac_model mac_data_table[] = {
* PowerBook Duos are pretty much like normal PowerBooks
* All of these probably have onboard SONIC in the Dock which
* means we'll have to probe for it eventually.
- *
- * Are these really MAC_VIA_IIci? The developer notes for the
- * Duos show pretty much the same custom parts as in most of
- * the other PowerBooks which would imply MAC_VIA_QUADRA.
*/
{
.ident = MAC_MODEL_PB210,
.name = "PowerBook Duo 210",
.adb_type = MAC_ADB_PB2,
- .via_type = MAC_VIA_IIci,
+ .via_type = MAC_VIA_IICI,
.scsi_type = MAC_SCSI_OLD,
.scc_type = MAC_SCC_QUADRA,
.nubus_type = MAC_NUBUS,
@@ -751,7 +776,7 @@ static struct mac_model mac_data_table[] = {
.ident = MAC_MODEL_PB230,
.name = "PowerBook Duo 230",
.adb_type = MAC_ADB_PB2,
- .via_type = MAC_VIA_IIci,
+ .via_type = MAC_VIA_IICI,
.scsi_type = MAC_SCSI_OLD,
.scc_type = MAC_SCC_QUADRA,
.nubus_type = MAC_NUBUS,
@@ -760,7 +785,7 @@ static struct mac_model mac_data_table[] = {
.ident = MAC_MODEL_PB250,
.name = "PowerBook Duo 250",
.adb_type = MAC_ADB_PB2,
- .via_type = MAC_VIA_IIci,
+ .via_type = MAC_VIA_IICI,
.scsi_type = MAC_SCSI_OLD,
.scc_type = MAC_SCC_QUADRA,
.nubus_type = MAC_NUBUS,
@@ -769,7 +794,7 @@ static struct mac_model mac_data_table[] = {
.ident = MAC_MODEL_PB270C,
.name = "PowerBook Duo 270c",
.adb_type = MAC_ADB_PB2,
- .via_type = MAC_VIA_IIci,
+ .via_type = MAC_VIA_IICI,
.scsi_type = MAC_SCSI_OLD,
.scc_type = MAC_SCC_QUADRA,
.nubus_type = MAC_NUBUS,
@@ -778,7 +803,7 @@ static struct mac_model mac_data_table[] = {
.ident = MAC_MODEL_PB280,
.name = "PowerBook Duo 280",
.adb_type = MAC_ADB_PB2,
- .via_type = MAC_VIA_IIci,
+ .via_type = MAC_VIA_IICI,
.scsi_type = MAC_SCSI_OLD,
.scc_type = MAC_SCC_QUADRA,
.nubus_type = MAC_NUBUS,
@@ -787,7 +812,7 @@ static struct mac_model mac_data_table[] = {
.ident = MAC_MODEL_PB280C,
.name = "PowerBook Duo 280c",
.adb_type = MAC_ADB_PB2,
- .via_type = MAC_VIA_IIci,
+ .via_type = MAC_VIA_IICI,
.scsi_type = MAC_SCSI_OLD,
.scc_type = MAC_SCC_QUADRA,
.nubus_type = MAC_NUBUS,
@@ -864,8 +889,14 @@ static void __init mac_identify(void)
scc_b_rsrcs[1].start = scc_b_rsrcs[1].end = IRQ_MAC_SCC_B;
break;
default:
- scc_a_rsrcs[1].start = scc_a_rsrcs[1].end = IRQ_MAC_SCC;
- scc_b_rsrcs[1].start = scc_b_rsrcs[1].end = IRQ_MAC_SCC;
+ /* On non-PSC machines, the serial ports share an IRQ. */
+ if (macintosh_config->ident == MAC_MODEL_IIFX) {
+ scc_a_rsrcs[1].start = scc_a_rsrcs[1].end = IRQ_MAC_SCC;
+ scc_b_rsrcs[1].start = scc_b_rsrcs[1].end = IRQ_MAC_SCC;
+ } else {
+ scc_a_rsrcs[1].start = scc_a_rsrcs[1].end = IRQ_AUTO_4;
+ scc_b_rsrcs[1].start = scc_b_rsrcs[1].end = IRQ_AUTO_4;
+ }
break;
}
diff --git a/arch/m68k/mac/iop.c b/arch/m68k/mac/iop.c
index 1ad4e9d80eba..7d8d46127ad9 100644
--- a/arch/m68k/mac/iop.c
+++ b/arch/m68k/mac/iop.c
@@ -115,7 +115,6 @@
#include <asm/macintosh.h>
#include <asm/macints.h>
#include <asm/mac_iop.h>
-#include <asm/mac_oss.h>
/*#define DEBUG_IOP*/
@@ -149,8 +148,6 @@ static struct listener iop_listeners[NUM_IOPS][NUM_IOP_CHAN];
irqreturn_t iop_ism_irq(int, void *);
-extern void oss_irq_enable(int);
-
/*
* Private access functions
*/
@@ -304,16 +301,13 @@ void __init iop_init(void)
void __init iop_register_interrupts(void)
{
if (iop_ism_present) {
- if (oss_present) {
- if (request_irq(OSS_IRQLEV_IOPISM, iop_ism_irq,
- IRQ_FLG_LOCK, "ISM IOP",
- (void *) IOP_NUM_ISM))
+ if (macintosh_config->ident == MAC_MODEL_IIFX) {
+ if (request_irq(IRQ_MAC_ADB, iop_ism_irq, 0,
+ "ISM IOP", (void *)IOP_NUM_ISM))
pr_err("Couldn't register ISM IOP interrupt\n");
- oss_irq_enable(IRQ_MAC_ADB);
} else {
- if (request_irq(IRQ_VIA2_0, iop_ism_irq,
- IRQ_FLG_LOCK|IRQ_FLG_FAST, "ISM IOP",
- (void *) IOP_NUM_ISM))
+ if (request_irq(IRQ_VIA2_0, iop_ism_irq, 0, "ISM IOP",
+ (void *)IOP_NUM_ISM))
pr_err("Couldn't register ISM IOP interrupt\n");
}
if (!iop_alive(iop_base[IOP_NUM_ISM])) {
diff --git a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c
index f92190c159b4..5c1a6b2ff0af 100644
--- a/arch/m68k/mac/macints.c
+++ b/arch/m68k/mac/macints.c
@@ -26,10 +26,6 @@
* - slot 6: timer 1 (not on IIci)
* - slot 7: status of IRQ; signals 'any enabled int.'
*
- * 2 - OSS (IIfx only?)
- * - slot 0: SCSI interrupt
- * - slot 1: Sound interrupt
- *
* Levels 3-6 vary by machine type. For VIA or RBV Macintoshes:
*
* 3 - unused (?)
@@ -42,21 +38,30 @@
*
* 6 - off switch (?)
*
- * For OSS Macintoshes (IIfx only at this point):
+ * Machines with Quadra-like VIA hardware, except PSC and PMU machines, support
+ * an alternate interrupt mapping, as used by A/UX. It spreads ethernet and
+ * sound out to their own autovector IRQs and gives VIA1 a higher priority:
*
- * 3 - Nubus interrupt
- * - slot 0: Slot $9
- * - slot 1: Slot $A
- * - slot 2: Slot $B
- * - slot 3: Slot $C
- * - slot 4: Slot $D
- * - slot 5: Slot $E
+ * 1 - unused (?)
*
- * 4 - SCC IOP
+ * 3 - on-board SONIC
+ *
+ * 5 - Apple Sound Chip (ASC)
+ *
+ * 6 - VIA1
+ *
+ * For OSS Macintoshes (IIfx only), we apply an interrupt mapping similar to
+ * the Quadra (A/UX) mapping:
+ *
+ * 1 - ISM IOP (ADB)
*
- * 5 - ISM IOP (ADB?)
+ * 2 - SCSI
*
- * 6 - unused
+ * 3 - NuBus
+ *
+ * 4 - SCC IOP
+ *
+ * 6 - VIA1
*
* For PSC Macintoshes (660AV, 840AV):
*
@@ -100,88 +105,29 @@
* case. They're hidden behind the Nubus slot $C interrupt thus adding a
* third layer of indirection. Why oh why did the Apple engineers do that?
*
- * - We support "fast" and "slow" handlers, just like the Amiga port. The
- * fast handlers are called first and with all interrupts disabled. They
- * are expected to execute quickly (hence the name). The slow handlers are
- * called last with interrupts enabled and the interrupt level restored.
- * They must therefore be reentrant.
- *
- * TODO:
- *
*/
-#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
-#include <linux/kernel_stat.h>
-#include <linux/interrupt.h> /* for intr_count */
+#include <linux/interrupt.h>
+#include <linux/irq.h>
#include <linux/delay.h>
-#include <linux/seq_file.h>
-#include <asm/system.h>
#include <asm/irq.h>
-#include <asm/traps.h>
-#include <asm/bootinfo.h>
#include <asm/macintosh.h>
+#include <asm/macints.h>
#include <asm/mac_via.h>
#include <asm/mac_psc.h>
+#include <asm/mac_oss.h>
+#include <asm/mac_iop.h>
+#include <asm/mac_baboon.h>
#include <asm/hwtest.h>
-#include <asm/errno.h>
-#include <asm/macints.h>
#include <asm/irq_regs.h>
-#include <asm/mac_oss.h>
#define SHUTUP_SONIC
/*
- * VIA/RBV hooks
- */
-
-extern void via_register_interrupts(void);
-extern void via_irq_enable(int);
-extern void via_irq_disable(int);
-extern void via_irq_clear(int);
-extern int via_irq_pending(int);
-
-/*
- * OSS hooks
- */
-
-extern void oss_register_interrupts(void);
-extern void oss_irq_enable(int);
-extern void oss_irq_disable(int);
-extern void oss_irq_clear(int);
-extern int oss_irq_pending(int);
-
-/*
- * PSC hooks
- */
-
-extern void psc_register_interrupts(void);
-extern void psc_irq_enable(int);
-extern void psc_irq_disable(int);
-extern void psc_irq_clear(int);
-extern int psc_irq_pending(int);
-
-/*
- * IOP hooks
- */
-
-extern void iop_register_interrupts(void);
-
-/*
- * Baboon hooks
- */
-
-extern int baboon_present;
-
-extern void baboon_register_interrupts(void);
-extern void baboon_irq_enable(int);
-extern void baboon_irq_disable(int);
-extern void baboon_irq_clear(int);
-
-/*
* console_loglevel determines NMI handler function
*/
@@ -190,14 +136,15 @@ irqreturn_t mac_debug_handler(int, void *);
/* #define DEBUG_MACINTS */
-void mac_enable_irq(unsigned int irq);
-void mac_disable_irq(unsigned int irq);
+static unsigned int mac_irq_startup(struct irq_data *);
+static void mac_irq_shutdown(struct irq_data *);
-static struct irq_controller mac_irq_controller = {
+static struct irq_chip mac_irq_chip = {
.name = "mac",
- .lock = __SPIN_LOCK_UNLOCKED(mac_irq_controller.lock),
- .enable = mac_enable_irq,
- .disable = mac_disable_irq,
+ .irq_enable = mac_irq_enable,
+ .irq_disable = mac_irq_disable,
+ .irq_startup = mac_irq_startup,
+ .irq_shutdown = mac_irq_shutdown,
};
void __init mac_init_IRQ(void)
@@ -205,7 +152,7 @@ void __init mac_init_IRQ(void)
#ifdef DEBUG_MACINTS
printk("mac_init_IRQ(): Setting things up...\n");
#endif
- m68k_setup_irq_controller(&mac_irq_controller, IRQ_USER,
+ m68k_setup_irq_controller(&mac_irq_chip, handle_simple_irq, IRQ_USER,
NUM_MAC_SOURCES - IRQ_USER);
/* Make sure the SONIC interrupt is cleared or things get ugly */
#ifdef SHUTUP_SONIC
@@ -241,22 +188,19 @@ void __init mac_init_IRQ(void)
}
/*
- * mac_enable_irq - enable an interrupt source
- * mac_disable_irq - disable an interrupt source
- * mac_clear_irq - clears a pending interrupt
- * mac_pending_irq - Returns the pending status of an IRQ (nonzero = pending)
+ * mac_irq_enable - enable an interrupt source
+ * mac_irq_disable - disable an interrupt source
*
* These routines are just dispatchers to the VIA/OSS/PSC routines.
*/
-void mac_enable_irq(unsigned int irq)
+void mac_irq_enable(struct irq_data *data)
{
+ int irq = data->irq;
int irq_src = IRQ_SRC(irq);
switch(irq_src) {
case 1:
- via_irq_enable(irq);
- break;
case 2:
case 7:
if (oss_present)
@@ -265,6 +209,7 @@ void mac_enable_irq(unsigned int irq)
via_irq_enable(irq);
break;
case 3:
+ case 4:
case 5:
case 6:
if (psc_present)
@@ -272,10 +217,6 @@ void mac_enable_irq(unsigned int irq)
else if (oss_present)
oss_irq_enable(irq);
break;
- case 4:
- if (psc_present)
- psc_irq_enable(irq);
- break;
case 8:
if (baboon_present)
baboon_irq_enable(irq);
@@ -283,14 +224,13 @@ void mac_enable_irq(unsigned int irq)
}
}
-void mac_disable_irq(unsigned int irq)
+void mac_irq_disable(struct irq_data *data)
{
+ int irq = data->irq;
int irq_src = IRQ_SRC(irq);
switch(irq_src) {
case 1:
- via_irq_disable(irq);
- break;
case 2:
case 7:
if (oss_present)
@@ -299,6 +239,7 @@ void mac_disable_irq(unsigned int irq)
via_irq_disable(irq);
break;
case 3:
+ case 4:
case 5:
case 6:
if (psc_present)
@@ -306,10 +247,6 @@ void mac_disable_irq(unsigned int irq)
else if (oss_present)
oss_irq_disable(irq);
break;
- case 4:
- if (psc_present)
- psc_irq_disable(irq);
- break;
case 8:
if (baboon_present)
baboon_irq_disable(irq);
@@ -317,65 +254,27 @@ void mac_disable_irq(unsigned int irq)
}
}
-void mac_clear_irq(unsigned int irq)
+static unsigned int mac_irq_startup(struct irq_data *data)
{
- switch(IRQ_SRC(irq)) {
- case 1:
- via_irq_clear(irq);
- break;
- case 2:
- case 7:
- if (oss_present)
- oss_irq_clear(irq);
- else
- via_irq_clear(irq);
- break;
- case 3:
- case 5:
- case 6:
- if (psc_present)
- psc_irq_clear(irq);
- else if (oss_present)
- oss_irq_clear(irq);
- break;
- case 4:
- if (psc_present)
- psc_irq_clear(irq);
- break;
- case 8:
- if (baboon_present)
- baboon_irq_clear(irq);
- break;
- }
+ int irq = data->irq;
+
+ if (IRQ_SRC(irq) == 7 && !oss_present)
+ via_nubus_irq_startup(irq);
+ else
+ mac_irq_enable(data);
+
+ return 0;
}
-int mac_irq_pending(unsigned int irq)
+static void mac_irq_shutdown(struct irq_data *data)
{
- switch(IRQ_SRC(irq)) {
- case 1:
- return via_irq_pending(irq);
- case 2:
- case 7:
- if (oss_present)
- return oss_irq_pending(irq);
- else
- return via_irq_pending(irq);
- case 3:
- case 5:
- case 6:
- if (psc_present)
- return psc_irq_pending(irq);
- else if (oss_present)
- return oss_irq_pending(irq);
- break;
- case 4:
- if (psc_present)
- return psc_irq_pending(irq);
- break;
- }
- return 0;
+ int irq = data->irq;
+
+ if (IRQ_SRC(irq) == 7 && !oss_present)
+ via_nubus_irq_shutdown(irq);
+ else
+ mac_irq_disable(data);
}
-EXPORT_SYMBOL(mac_irq_pending);
static int num_debug[8];
diff --git a/arch/m68k/mac/oss.c b/arch/m68k/mac/oss.c
index a9c0f5ab4cc0..6c4c882c126e 100644
--- a/arch/m68k/mac/oss.c
+++ b/arch/m68k/mac/oss.c
@@ -1,5 +1,5 @@
/*
- * OSS handling
+ * Operating System Services (OSS) chip handling
* Written by Joshua M. Thompson (funaho@jurai.org)
*
*
@@ -19,6 +19,7 @@
#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/irq.h>
#include <asm/bootinfo.h>
#include <asm/macintosh.h>
@@ -29,11 +30,6 @@
int oss_present;
volatile struct mac_oss *oss;
-static irqreturn_t oss_irq(int, void *);
-static irqreturn_t oss_nubus_irq(int, void *);
-
-extern irqreturn_t via1_irq(int, void *);
-
/*
* Initialize the OSS
*
@@ -53,30 +49,8 @@ void __init oss_init(void)
/* do this by setting the source's interrupt level to zero. */
for (i = 0; i <= OSS_NUM_SOURCES; i++) {
- oss->irq_level[i] = OSS_IRQLEV_DISABLED;
+ oss->irq_level[i] = 0;
}
- /* If we disable VIA1 here, we never really handle it... */
- oss->irq_level[OSS_VIA1] = OSS_IRQLEV_VIA1;
-}
-
-/*
- * Register the OSS and NuBus interrupt dispatchers.
- */
-
-void __init oss_register_interrupts(void)
-{
- if (request_irq(OSS_IRQLEV_SCSI, oss_irq, IRQ_FLG_LOCK,
- "scsi", (void *) oss))
- pr_err("Couldn't register %s interrupt\n", "scsi");
- if (request_irq(OSS_IRQLEV_NUBUS, oss_nubus_irq, IRQ_FLG_LOCK,
- "nubus", (void *) oss))
- pr_err("Couldn't register %s interrupt\n", "nubus");
- if (request_irq(OSS_IRQLEV_SOUND, oss_irq, IRQ_FLG_LOCK,
- "sound", (void *) oss))
- pr_err("Couldn't register %s interrupt\n", "sound");
- if (request_irq(OSS_IRQLEV_VIA1, via1_irq, IRQ_FLG_LOCK,
- "via1", (void *) via1))
- pr_err("Couldn't register %s interrupt\n", "via1");
}
/*
@@ -88,36 +62,35 @@ void __init oss_nubus_init(void)
}
/*
- * Handle miscellaneous OSS interrupts. Right now that's just sound
- * and SCSI; everything else is routed to its own autovector IRQ.
+ * Handle miscellaneous OSS interrupts.
*/
-static irqreturn_t oss_irq(int irq, void *dev_id)
+static void oss_irq(unsigned int irq, struct irq_desc *desc)
{
- int events;
-
- events = oss->irq_pending & (OSS_IP_SOUND|OSS_IP_SCSI);
- if (!events)
- return IRQ_NONE;
+ int events = oss->irq_pending &
+ (OSS_IP_IOPSCC | OSS_IP_SCSI | OSS_IP_IOPISM);
#ifdef DEBUG_IRQS
if ((console_loglevel == 10) && !(events & OSS_IP_SCSI)) {
- printk("oss_irq: irq %d events = 0x%04X\n", irq,
+ printk("oss_irq: irq %u events = 0x%04X\n", irq,
(int) oss->irq_pending);
}
#endif
- /* FIXME: how do you clear a pending IRQ? */
- if (events & OSS_IP_SOUND) {
- oss->irq_pending &= ~OSS_IP_SOUND;
- /* FIXME: call sound handler */
- } else if (events & OSS_IP_SCSI) {
+ if (events & OSS_IP_IOPSCC) {
+ oss->irq_pending &= ~OSS_IP_IOPSCC;
+ generic_handle_irq(IRQ_MAC_SCC);
+ }
+
+ if (events & OSS_IP_SCSI) {
oss->irq_pending &= ~OSS_IP_SCSI;
- m68k_handle_int(IRQ_MAC_SCSI);
- } else {
- /* FIXME: error check here? */
+ generic_handle_irq(IRQ_MAC_SCSI);
+ }
+
+ if (events & OSS_IP_IOPISM) {
+ oss->irq_pending &= ~OSS_IP_IOPISM;
+ generic_handle_irq(IRQ_MAC_ADB);
}
- return IRQ_HANDLED;
}
/*
@@ -126,13 +99,13 @@ static irqreturn_t oss_irq(int irq, void *dev_id)
* Unlike the VIA/RBV this is on its own autovector interrupt level.
*/
-static irqreturn_t oss_nubus_irq(int irq, void *dev_id)
+static void oss_nubus_irq(unsigned int irq, struct irq_desc *desc)
{
int events, irq_bit, i;
events = oss->irq_pending & OSS_IP_NUBUS;
if (!events)
- return IRQ_NONE;
+ return;
#ifdef DEBUG_NUBUS_INT
if (console_loglevel > 7) {
@@ -148,10 +121,36 @@ static irqreturn_t oss_nubus_irq(int irq, void *dev_id)
irq_bit >>= 1;
if (events & irq_bit) {
oss->irq_pending &= ~irq_bit;
- m68k_handle_int(NUBUS_SOURCE_BASE + i);
+ generic_handle_irq(NUBUS_SOURCE_BASE + i);
}
} while(events & (irq_bit - 1));
- return IRQ_HANDLED;
+}
+
+/*
+ * Register the OSS and NuBus interrupt dispatchers.
+ *
+ * This IRQ mapping is laid out with two things in mind: first, we try to keep
+ * things on their own levels to avoid having to do double-dispatches. Second,
+ * the levels match as closely as possible the alternate IRQ mapping mode (aka
+ * "A/UX mode") available on some VIA machines.
+ */
+
+#define OSS_IRQLEV_IOPISM IRQ_AUTO_1
+#define OSS_IRQLEV_SCSI IRQ_AUTO_2
+#define OSS_IRQLEV_NUBUS IRQ_AUTO_3
+#define OSS_IRQLEV_IOPSCC IRQ_AUTO_4
+#define OSS_IRQLEV_VIA1 IRQ_AUTO_6
+
+void __init oss_register_interrupts(void)
+{
+ irq_set_chained_handler(OSS_IRQLEV_IOPISM, oss_irq);
+ irq_set_chained_handler(OSS_IRQLEV_SCSI, oss_irq);
+ irq_set_chained_handler(OSS_IRQLEV_NUBUS, oss_nubus_irq);
+ irq_set_chained_handler(OSS_IRQLEV_IOPSCC, oss_irq);
+ irq_set_chained_handler(OSS_IRQLEV_VIA1, via1_irq);
+
+ /* OSS_VIA1 gets enabled here because it has no machspec interrupt. */
+ oss->irq_level[OSS_VIA1] = IRQ_AUTO_6;
}
/*
@@ -170,13 +169,13 @@ void oss_irq_enable(int irq) {
switch(irq) {
case IRQ_MAC_SCC:
oss->irq_level[OSS_IOPSCC] = OSS_IRQLEV_IOPSCC;
- break;
+ return;
case IRQ_MAC_ADB:
oss->irq_level[OSS_IOPISM] = OSS_IRQLEV_IOPISM;
- break;
+ return;
case IRQ_MAC_SCSI:
oss->irq_level[OSS_SCSI] = OSS_IRQLEV_SCSI;
- break;
+ return;
case IRQ_NUBUS_9:
case IRQ_NUBUS_A:
case IRQ_NUBUS_B:
@@ -185,13 +184,11 @@ void oss_irq_enable(int irq) {
case IRQ_NUBUS_E:
irq -= NUBUS_SOURCE_BASE;
oss->irq_level[irq] = OSS_IRQLEV_NUBUS;
- break;
-#ifdef DEBUG_IRQUSE
- default:
- printk("%s unknown irq %d\n", __func__, irq);
- break;
-#endif
+ return;
}
+
+ if (IRQ_SRC(irq) == 1)
+ via_irq_enable(irq);
}
/*
@@ -207,50 +204,14 @@ void oss_irq_disable(int irq) {
#endif
switch(irq) {
case IRQ_MAC_SCC:
- oss->irq_level[OSS_IOPSCC] = OSS_IRQLEV_DISABLED;
- break;
- case IRQ_MAC_ADB:
- oss->irq_level[OSS_IOPISM] = OSS_IRQLEV_DISABLED;
- break;
- case IRQ_MAC_SCSI:
- oss->irq_level[OSS_SCSI] = OSS_IRQLEV_DISABLED;
- break;
- case IRQ_NUBUS_9:
- case IRQ_NUBUS_A:
- case IRQ_NUBUS_B:
- case IRQ_NUBUS_C:
- case IRQ_NUBUS_D:
- case IRQ_NUBUS_E:
- irq -= NUBUS_SOURCE_BASE;
- oss->irq_level[irq] = OSS_IRQLEV_DISABLED;
- break;
-#ifdef DEBUG_IRQUSE
- default:
- printk("%s unknown irq %d\n", __func__, irq);
- break;
-#endif
- }
-}
-
-/*
- * Clear an OSS interrupt
- *
- * Not sure if this works or not but it's the only method I could
- * think of based on the contents of the mac_oss structure.
- */
-
-void oss_irq_clear(int irq) {
- /* FIXME: how to do this on OSS? */
- switch(irq) {
- case IRQ_MAC_SCC:
- oss->irq_pending &= ~OSS_IP_IOPSCC;
- break;
+ oss->irq_level[OSS_IOPSCC] = 0;
+ return;
case IRQ_MAC_ADB:
- oss->irq_pending &= ~OSS_IP_IOPISM;
- break;
+ oss->irq_level[OSS_IOPISM] = 0;
+ return;
case IRQ_MAC_SCSI:
- oss->irq_pending &= ~OSS_IP_SCSI;
- break;
+ oss->irq_level[OSS_SCSI] = 0;
+ return;
case IRQ_NUBUS_9:
case IRQ_NUBUS_A:
case IRQ_NUBUS_B:
@@ -258,36 +219,10 @@ void oss_irq_clear(int irq) {
case IRQ_NUBUS_D:
case IRQ_NUBUS_E:
irq -= NUBUS_SOURCE_BASE;
- oss->irq_pending &= ~(1 << irq);
- break;
+ oss->irq_level[irq] = 0;
+ return;
}
-}
-/*
- * Check to see if a specific OSS interrupt is pending
- */
-
-int oss_irq_pending(int irq)
-{
- switch(irq) {
- case IRQ_MAC_SCC:
- return oss->irq_pending & OSS_IP_IOPSCC;
- break;
- case IRQ_MAC_ADB:
- return oss->irq_pending & OSS_IP_IOPISM;
- break;
- case IRQ_MAC_SCSI:
- return oss->irq_pending & OSS_IP_SCSI;
- break;
- case IRQ_NUBUS_9:
- case IRQ_NUBUS_A:
- case IRQ_NUBUS_B:
- case IRQ_NUBUS_C:
- case IRQ_NUBUS_D:
- case IRQ_NUBUS_E:
- irq -= NUBUS_SOURCE_BASE;
- return oss->irq_pending & (1 << irq);
- break;
- }
- return 0;
+ if (IRQ_SRC(irq) == 1)
+ via_irq_disable(irq);
}
diff --git a/arch/m68k/mac/psc.c b/arch/m68k/mac/psc.c
index a4c3eb60706e..6f026fc302fa 100644
--- a/arch/m68k/mac/psc.c
+++ b/arch/m68k/mac/psc.c
@@ -18,6 +18,7 @@
#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/irq.h>
#include <asm/traps.h>
#include <asm/bootinfo.h>
@@ -30,8 +31,6 @@
int psc_present;
volatile __u8 *psc;
-irqreturn_t psc_irq(int, void *);
-
/*
* Debugging dump, used in various places to see what's going on.
*/
@@ -112,52 +111,52 @@ void __init psc_init(void)
}
/*
- * Register the PSC interrupt dispatchers for autovector interrupts 3-6.
- */
-
-void __init psc_register_interrupts(void)
-{
- if (request_irq(IRQ_AUTO_3, psc_irq, 0, "psc3", (void *) 0x30))
- pr_err("Couldn't register psc%d interrupt\n", 3);
- if (request_irq(IRQ_AUTO_4, psc_irq, 0, "psc4", (void *) 0x40))
- pr_err("Couldn't register psc%d interrupt\n", 4);
- if (request_irq(IRQ_AUTO_5, psc_irq, 0, "psc5", (void *) 0x50))
- pr_err("Couldn't register psc%d interrupt\n", 5);
- if (request_irq(IRQ_AUTO_6, psc_irq, 0, "psc6", (void *) 0x60))
- pr_err("Couldn't register psc%d interrupt\n", 6);
-}
-
-/*
* PSC interrupt handler. It's a lot like the VIA interrupt handler.
*/
-irqreturn_t psc_irq(int irq, void *dev_id)
+static void psc_irq(unsigned int irq, struct irq_desc *desc)
{
- int pIFR = pIFRbase + ((int) dev_id);
- int pIER = pIERbase + ((int) dev_id);
+ unsigned int offset = (unsigned int)irq_desc_get_handler_data(desc);
+ int pIFR = pIFRbase + offset;
+ int pIER = pIERbase + offset;
int irq_num;
unsigned char irq_bit, events;
#ifdef DEBUG_IRQS
- printk("psc_irq: irq %d pIFR = 0x%02X pIER = 0x%02X\n",
+ printk("psc_irq: irq %u pIFR = 0x%02X pIER = 0x%02X\n",
irq, (int) psc_read_byte(pIFR), (int) psc_read_byte(pIER));
#endif
events = psc_read_byte(pIFR) & psc_read_byte(pIER) & 0xF;
if (!events)
- return IRQ_NONE;
+ return;
irq_num = irq << 3;
irq_bit = 1;
do {
if (events & irq_bit) {
psc_write_byte(pIFR, irq_bit);
- m68k_handle_int(irq_num);
+ generic_handle_irq(irq_num);
}
irq_num++;
irq_bit <<= 1;
} while (events >= irq_bit);
- return IRQ_HANDLED;
+}
+
+/*
+ * Register the PSC interrupt dispatchers for autovector interrupts 3-6.
+ */
+
+void __init psc_register_interrupts(void)
+{
+ irq_set_chained_handler(IRQ_AUTO_3, psc_irq);
+ irq_set_handler_data(IRQ_AUTO_3, (void *)0x30);
+ irq_set_chained_handler(IRQ_AUTO_4, psc_irq);
+ irq_set_handler_data(IRQ_AUTO_4, (void *)0x40);
+ irq_set_chained_handler(IRQ_AUTO_5, psc_irq);
+ irq_set_handler_data(IRQ_AUTO_5, (void *)0x50);
+ irq_set_chained_handler(IRQ_AUTO_6, psc_irq);
+ irq_set_handler_data(IRQ_AUTO_6, (void *)0x60);
}
void psc_irq_enable(int irq) {
@@ -181,20 +180,3 @@ void psc_irq_disable(int irq) {
#endif
psc_write_byte(pIER, 1 << irq_idx);
}
-
-void psc_irq_clear(int irq) {
- int irq_src = IRQ_SRC(irq);
- int irq_idx = IRQ_IDX(irq);
- int pIFR = pIERbase + (irq_src << 4);
-
- psc_write_byte(pIFR, 1 << irq_idx);
-}
-
-int psc_irq_pending(int irq)
-{
- int irq_src = IRQ_SRC(irq);
- int irq_idx = IRQ_IDX(irq);
- int pIFR = pIERbase + (irq_src << 4);
-
- return psc_read_byte(pIFR) & (1 << irq_idx);
-}
diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c
index e71166daec6a..2d85662715fb 100644
--- a/arch/m68k/mac/via.c
+++ b/arch/m68k/mac/via.c
@@ -28,6 +28,7 @@
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/irq.h>
#include <asm/bootinfo.h>
#include <asm/macintosh.h>
@@ -62,27 +63,50 @@ static int gIER,gIFR,gBufA,gBufB;
#define MAC_CLOCK_LOW (MAC_CLOCK_TICK&0xFF)
#define MAC_CLOCK_HIGH (MAC_CLOCK_TICK>>8)
-/* To disable a NuBus slot on Quadras we make that slot IRQ line an output set
- * high. On RBV we just use the slot interrupt enable register. On Macs with
- * genuine VIA chips we must use nubus_disabled to keep track of disabled slot
- * interrupts. When any slot IRQ is disabled we mask the (edge triggered) CA1
- * or "SLOTS" interrupt. When no slot is disabled, we unmask the CA1 interrupt.
- * So, on genuine VIAs, having more than one NuBus IRQ can mean trouble,
- * because closing one of those drivers can mask all of the NuBus interrupts.
- * Also, since we can't mask the unregistered slot IRQs on genuine VIAs, it's
- * possible to get interrupts from cards that MacOS or the ROM has configured
- * but we have not. FWIW, "Designing Cards and Drivers for Macintosh II and
- * Macintosh SE", page 9-8, says, a slot IRQ with no driver would crash MacOS.
+
+/*
+ * On Macs with a genuine VIA chip there is no way to mask an individual slot
+ * interrupt. This limitation also seems to apply to VIA clone logic cores in
+ * Quadra-like ASICs. (RBV and OSS machines don't have this limitation.)
+ *
+ * We used to fake it by configuring the relevent VIA pin as an output
+ * (to mask the interrupt) or input (to unmask). That scheme did not work on
+ * (at least) the Quadra 700. A NuBus card's /NMRQ signal is an open-collector
+ * circuit (see Designing Cards and Drivers for Macintosh II and Macintosh SE,
+ * p. 10-11 etc) but VIA outputs are not (see datasheet).
+ *
+ * Driving these outputs high must cause the VIA to source current and the
+ * card to sink current when it asserts /NMRQ. Current will flow but the pin
+ * voltage is uncertain and so the /NMRQ condition may still cause a transition
+ * at the VIA2 CA1 input (which explains the lost interrupts). A side effect
+ * is that a disabled slot IRQ can never be tested as pending or not.
+ *
+ * Driving these outputs low doesn't work either. All the slot /NMRQ lines are
+ * (active low) OR'd together to generate the CA1 (aka "SLOTS") interrupt (see
+ * The Guide To Macintosh Family Hardware, 2nd edition p. 167). If we drive a
+ * disabled /NMRQ line low, the falling edge immediately triggers a CA1
+ * interrupt and all slot interrupts after that will generate no transition
+ * and therefore no interrupt, even after being re-enabled.
+ *
+ * So we make the VIA port A I/O lines inputs and use nubus_disabled to keep
+ * track of their states. When any slot IRQ becomes disabled we mask the CA1
+ * umbrella interrupt. Only when all slot IRQs become enabled do we unmask
+ * the CA1 interrupt. It must remain enabled even when cards have no interrupt
+ * handler registered. Drivers must therefore disable a slot interrupt at the
+ * device before they call free_irq (like shared and autovector interrupts).
+ *
+ * There is also a related problem when MacOS is used to boot Linux. A network
+ * card brought up by a MacOS driver may raise an interrupt while Linux boots.
+ * This can be fatal since it can't be handled until the right driver loads
+ * (if such a driver exists at all). Apparently related to this hardware
+ * limitation, "Designing Cards and Drivers", p. 9-8, says that a slot
+ * interrupt with no driver would crash MacOS (the book was written before
+ * the appearance of Macs with RBV or OSS).
*/
+
static u8 nubus_disabled;
void via_debug_dump(void);
-irqreturn_t via1_irq(int, void *);
-irqreturn_t via2_irq(int, void *);
-irqreturn_t via_nubus_irq(int, void *);
-void via_irq_enable(int irq);
-void via_irq_disable(int irq);
-void via_irq_clear(int irq);
/*
* Initialize the VIAs
@@ -102,7 +126,7 @@ void __init via_init(void)
/* IIci, IIsi, IIvx, IIvi (P6xx), LC series */
- case MAC_VIA_IIci:
+ case MAC_VIA_IICI:
via1 = (void *) VIA1_BASE;
if (macintosh_config->ident == MAC_MODEL_IIFX) {
via2 = NULL;
@@ -199,38 +223,17 @@ void __init via_init(void)
if (oss_present)
return;
- /* Some machines support an alternate IRQ mapping that spreads */
- /* Ethernet and Sound out to their own autolevel IRQs and moves */
- /* VIA1 to level 6. A/UX uses this mapping and we do too. Note */
- /* that the IIfx emulates this alternate mapping using the OSS. */
-
- via_alt_mapping = 0;
- if (macintosh_config->via_type == MAC_VIA_QUADRA)
- switch (macintosh_config->ident) {
- case MAC_MODEL_C660:
- case MAC_MODEL_Q840:
- /* not applicable */
- break;
- case MAC_MODEL_P588:
- case MAC_MODEL_TV:
- case MAC_MODEL_PB140:
- case MAC_MODEL_PB145:
- case MAC_MODEL_PB160:
- case MAC_MODEL_PB165:
- case MAC_MODEL_PB165C:
- case MAC_MODEL_PB170:
- case MAC_MODEL_PB180:
- case MAC_MODEL_PB180C:
- case MAC_MODEL_PB190:
- case MAC_MODEL_PB520:
- /* not yet tested */
- break;
- default:
- via_alt_mapping = 1;
- via1[vDirB] |= 0x40;
- via1[vBufB] &= ~0x40;
- break;
- }
+ if ((macintosh_config->via_type == MAC_VIA_QUADRA) &&
+ (macintosh_config->adb_type != MAC_ADB_PB1) &&
+ (macintosh_config->adb_type != MAC_ADB_PB2) &&
+ (macintosh_config->ident != MAC_MODEL_C660) &&
+ (macintosh_config->ident != MAC_MODEL_Q840)) {
+ via_alt_mapping = 1;
+ via1[vDirB] |= 0x40;
+ via1[vBufB] &= ~0x40;
+ } else {
+ via_alt_mapping = 0;
+ }
/*
* Now initialize VIA2. For RBV we just kill all interrupts;
@@ -250,22 +253,28 @@ void __init via_init(void)
via2[vACR] &= ~0x03; /* disable port A & B latches */
}
+ /* Everything below this point is VIA2 only... */
+
+ if (rbv_present)
+ return;
+
/*
- * Set vPCR for control line interrupts (but not on RBV)
+ * Set vPCR for control line interrupts.
+ *
+ * CA1 (SLOTS IRQ), CB1 (ASC IRQ): negative edge trigger.
+ *
+ * Macs with ESP SCSI have a negative edge triggered SCSI interrupt.
+ * Testing reveals that PowerBooks do too. However, the SE/30
+ * schematic diagram shows an active high NCR5380 IRQ line.
*/
- if (!rbv_present) {
- /* For all VIA types, CA1 (SLOTS IRQ) and CB1 (ASC IRQ)
- * are made negative edge triggered here.
- */
- if (macintosh_config->scsi_type == MAC_SCSI_OLD) {
- /* CB2 (IRQ) indep. input, positive edge */
- /* CA2 (DRQ) indep. input, positive edge */
- via2[vPCR] = 0x66;
- } else {
- /* CB2 (IRQ) indep. input, negative edge */
- /* CA2 (DRQ) indep. input, negative edge */
- via2[vPCR] = 0x22;
- }
+
+ pr_debug("VIA2 vPCR is 0x%02X\n", via2[vPCR]);
+ if (macintosh_config->via_type == MAC_VIA_II) {
+ /* CA2 (SCSI DRQ), CB2 (SCSI IRQ): indep. input, pos. edge */
+ via2[vPCR] = 0x66;
+ } else {
+ /* CA2 (SCSI DRQ), CB2 (SCSI IRQ): indep. input, neg. edge */
+ via2[vPCR] = 0x22;
}
}
@@ -281,40 +290,11 @@ void __init via_init_clock(irq_handler_t func)
via1[vT1CL] = MAC_CLOCK_LOW;
via1[vT1CH] = MAC_CLOCK_HIGH;
- if (request_irq(IRQ_MAC_TIMER_1, func, IRQ_FLG_LOCK, "timer", func))
+ if (request_irq(IRQ_MAC_TIMER_1, func, 0, "timer", func))
pr_err("Couldn't register %s interrupt\n", "timer");
}
/*
- * Register the interrupt dispatchers for VIA or RBV machines only.
- */
-
-void __init via_register_interrupts(void)
-{
- if (via_alt_mapping) {
- if (request_irq(IRQ_AUTO_1, via1_irq,
- IRQ_FLG_LOCK|IRQ_FLG_FAST, "software",
- (void *) via1))
- pr_err("Couldn't register %s interrupt\n", "software");
- if (request_irq(IRQ_AUTO_6, via1_irq,
- IRQ_FLG_LOCK|IRQ_FLG_FAST, "via1",
- (void *) via1))
- pr_err("Couldn't register %s interrupt\n", "via1");
- } else {
- if (request_irq(IRQ_AUTO_1, via1_irq,
- IRQ_FLG_LOCK|IRQ_FLG_FAST, "via1",
- (void *) via1))
- pr_err("Couldn't register %s interrupt\n", "via1");
- }
- if (request_irq(IRQ_AUTO_2, via2_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
- "via2", (void *) via2))
- pr_err("Couldn't register %s interrupt\n", "via2");
- if (request_irq(IRQ_MAC_NUBUS, via_nubus_irq,
- IRQ_FLG_LOCK|IRQ_FLG_FAST, "nubus", (void *) via2))
- pr_err("Couldn't register %s interrupt\n", "nubus");
-}
-
-/*
* Debugging dump, used in various places to see what's going on.
*/
@@ -409,34 +389,55 @@ void __init via_nubus_init(void)
via2[gBufB] |= 0x02;
}
- /* Disable all the slot interrupts (where possible). */
+ /*
+ * Disable the slot interrupts. On some hardware that's not possible.
+ * On some hardware it's unclear what all of these I/O lines do.
+ */
switch (macintosh_config->via_type) {
case MAC_VIA_II:
- /* Just make the port A lines inputs. */
- switch(macintosh_config->ident) {
- case MAC_MODEL_II:
- case MAC_MODEL_IIX:
- case MAC_MODEL_IICX:
- case MAC_MODEL_SE30:
- /* The top two bits are RAM size outputs. */
- via2[vDirA] &= 0xC0;
- break;
- default:
- via2[vDirA] &= 0x80;
- }
+ case MAC_VIA_QUADRA:
+ pr_debug("VIA2 vDirA is 0x%02X\n", via2[vDirA]);
break;
- case MAC_VIA_IIci:
+ case MAC_VIA_IICI:
/* RBV. Disable all the slot interrupts. SIER works like IER. */
via2[rSIER] = 0x7F;
break;
+ }
+}
+
+void via_nubus_irq_startup(int irq)
+{
+ int irq_idx = IRQ_IDX(irq);
+
+ switch (macintosh_config->via_type) {
+ case MAC_VIA_II:
case MAC_VIA_QUADRA:
- /* Disable the inactive slot interrupts by making those lines outputs. */
- if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
- (macintosh_config->adb_type != MAC_ADB_PB2)) {
- via2[vBufA] |= 0x7F;
- via2[vDirA] |= 0x7F;
+ /* Make the port A line an input. Probably redundant. */
+ if (macintosh_config->via_type == MAC_VIA_II) {
+ /* The top two bits are RAM size outputs. */
+ via2[vDirA] &= 0xC0 | ~(1 << irq_idx);
+ } else {
+ /* Allow NuBus slots 9 through F. */
+ via2[vDirA] &= 0x80 | ~(1 << irq_idx);
}
+ /* fall through */
+ case MAC_VIA_IICI:
+ via_irq_enable(irq);
+ break;
+ }
+}
+
+void via_nubus_irq_shutdown(int irq)
+{
+ switch (macintosh_config->via_type) {
+ case MAC_VIA_II:
+ case MAC_VIA_QUADRA:
+ /* Ensure that the umbrella CA1 interrupt remains enabled. */
+ via_irq_enable(irq);
+ break;
+ case MAC_VIA_IICI:
+ via_irq_disable(irq);
break;
}
}
@@ -446,48 +447,46 @@ void __init via_nubus_init(void)
* via6522.c :-), disable/pending masks added.
*/
-irqreturn_t via1_irq(int irq, void *dev_id)
+void via1_irq(unsigned int irq, struct irq_desc *desc)
{
int irq_num;
unsigned char irq_bit, events;
events = via1[vIFR] & via1[vIER] & 0x7F;
if (!events)
- return IRQ_NONE;
+ return;
irq_num = VIA1_SOURCE_BASE;
irq_bit = 1;
do {
if (events & irq_bit) {
via1[vIFR] = irq_bit;
- m68k_handle_int(irq_num);
+ generic_handle_irq(irq_num);
}
++irq_num;
irq_bit <<= 1;
} while (events >= irq_bit);
- return IRQ_HANDLED;
}
-irqreturn_t via2_irq(int irq, void *dev_id)
+static void via2_irq(unsigned int irq, struct irq_desc *desc)
{
int irq_num;
unsigned char irq_bit, events;
events = via2[gIFR] & via2[gIER] & 0x7F;
if (!events)
- return IRQ_NONE;
+ return;
irq_num = VIA2_SOURCE_BASE;
irq_bit = 1;
do {
if (events & irq_bit) {
via2[gIFR] = irq_bit | rbv_clear;
- m68k_handle_int(irq_num);
+ generic_handle_irq(irq_num);
}
++irq_num;
irq_bit <<= 1;
} while (events >= irq_bit);
- return IRQ_HANDLED;
}
/*
@@ -495,7 +494,7 @@ irqreturn_t via2_irq(int irq, void *dev_id)
* VIA2 dispatcher as a fast interrupt handler.
*/
-irqreturn_t via_nubus_irq(int irq, void *dev_id)
+void via_nubus_irq(unsigned int irq, struct irq_desc *desc)
{
int slot_irq;
unsigned char slot_bit, events;
@@ -506,7 +505,7 @@ irqreturn_t via_nubus_irq(int irq, void *dev_id)
else
events &= ~via2[vDirA];
if (!events)
- return IRQ_NONE;
+ return;
do {
slot_irq = IRQ_NUBUS_F;
@@ -514,7 +513,7 @@ irqreturn_t via_nubus_irq(int irq, void *dev_id)
do {
if (events & slot_bit) {
events &= ~slot_bit;
- m68k_handle_int(slot_irq);
+ generic_handle_irq(slot_irq);
}
--slot_irq;
slot_bit >>= 1;
@@ -528,7 +527,24 @@ irqreturn_t via_nubus_irq(int irq, void *dev_id)
else
events &= ~via2[vDirA];
} while (events);
- return IRQ_HANDLED;
+}
+
+/*
+ * Register the interrupt dispatchers for VIA or RBV machines only.
+ */
+
+void __init via_register_interrupts(void)
+{
+ if (via_alt_mapping) {
+ /* software interrupt */
+ irq_set_chained_handler(IRQ_AUTO_1, via1_irq);
+ /* via1 interrupt */
+ irq_set_chained_handler(IRQ_AUTO_6, via1_irq);
+ } else {
+ irq_set_chained_handler(IRQ_AUTO_1, via1_irq);
+ }
+ irq_set_chained_handler(IRQ_AUTO_2, via2_irq);
+ irq_set_chained_handler(IRQ_MAC_NUBUS, via_nubus_irq);
}
void via_irq_enable(int irq) {
@@ -547,25 +563,18 @@ void via_irq_enable(int irq) {
} else if (irq_src == 7) {
switch (macintosh_config->via_type) {
case MAC_VIA_II:
+ case MAC_VIA_QUADRA:
nubus_disabled &= ~(1 << irq_idx);
/* Enable the CA1 interrupt when no slot is disabled. */
if (!nubus_disabled)
via2[gIER] = IER_SET_BIT(1);
break;
- case MAC_VIA_IIci:
+ case MAC_VIA_IICI:
/* On RBV, enable the slot interrupt.
* SIER works like IER.
*/
via2[rSIER] = IER_SET_BIT(irq_idx);
break;
- case MAC_VIA_QUADRA:
- /* Make the port A line an input to enable the slot irq.
- * But not on PowerBooks, that's ADB.
- */
- if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
- (macintosh_config->adb_type != MAC_ADB_PB2))
- via2[vDirA] &= ~(1 << irq_idx);
- break;
}
}
}
@@ -585,60 +594,18 @@ void via_irq_disable(int irq) {
} else if (irq_src == 7) {
switch (macintosh_config->via_type) {
case MAC_VIA_II:
+ case MAC_VIA_QUADRA:
nubus_disabled |= 1 << irq_idx;
if (nubus_disabled)
via2[gIER] = IER_CLR_BIT(1);
break;
- case MAC_VIA_IIci:
+ case MAC_VIA_IICI:
via2[rSIER] = IER_CLR_BIT(irq_idx);
break;
- case MAC_VIA_QUADRA:
- if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
- (macintosh_config->adb_type != MAC_ADB_PB2))
- via2[vDirA] |= 1 << irq_idx;
- break;
}
}
}
-void via_irq_clear(int irq) {
- int irq_src = IRQ_SRC(irq);
- int irq_idx = IRQ_IDX(irq);
- int irq_bit = 1 << irq_idx;
-
- if (irq_src == 1) {
- via1[vIFR] = irq_bit;
- } else if (irq_src == 2) {
- via2[gIFR] = irq_bit | rbv_clear;
- } else if (irq_src == 7) {
- /* FIXME: There is no way to clear an individual nubus slot
- * IRQ flag, other than getting the device to do it.
- */
- }
-}
-
-/*
- * Returns nonzero if an interrupt is pending on the given
- * VIA/IRQ combination.
- */
-
-int via_irq_pending(int irq)
-{
- int irq_src = IRQ_SRC(irq);
- int irq_idx = IRQ_IDX(irq);
- int irq_bit = 1 << irq_idx;
-
- if (irq_src == 1) {
- return via1[vIFR] & irq_bit;
- } else if (irq_src == 2) {
- return via2[gIFR] & irq_bit;
- } else if (irq_src == 7) {
- /* Always 0 for MAC_VIA_QUADRA if the slot irq is disabled. */
- return ~via2[gBufA] & irq_bit;
- }
- return 0;
-}
-
void via1_set_head(int head)
{
if (head == 0)
@@ -647,3 +614,9 @@ void via1_set_head(int head)
via1[vBufA] |= VIA1A_vHeadSel;
}
EXPORT_SYMBOL(via1_set_head);
+
+int via2_scsi_drq_pending(void)
+{
+ return via2[gIFR] & (1 << IRQ_IDX(IRQ_MAC_SCSIDRQ));
+}
+EXPORT_SYMBOL(via2_scsi_drq_pending);