diff options
Diffstat (limited to 'arch/m68k/mac')
| -rw-r--r-- | arch/m68k/mac/baboon.c | 58 | ||||
| -rw-r--r-- | arch/m68k/mac/config.c | 106 | ||||
| -rw-r--r-- | arch/m68k/mac/iop.c | 21 | ||||
| -rw-r--r-- | arch/m68k/mac/macints.c | 217 | ||||
| -rw-r--r-- | arch/m68k/mac/misc.c | 43 | ||||
| -rw-r--r-- | arch/m68k/mac/oss.c | 200 | ||||
| -rw-r--r-- | arch/m68k/mac/psc.c | 71 | ||||
| -rw-r--r-- | arch/m68k/mac/via.c | 334 | 
8 files changed, 405 insertions, 645 deletions
diff --git a/arch/m68k/mac/baboon.c b/arch/m68k/mac/baboon.c index 2a96bebd896..3fe0e43d44f 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 c247de02bc7..a471eab1a4d 100644 --- a/arch/m68k/mac/config.c +++ b/arch/m68k/mac/config.c @@ -26,11 +26,11 @@  #include <linux/adb.h>  #include <linux/cuda.h> -#define BOOTINFO_COMPAT_1_0  #include <asm/setup.h>  #include <asm/bootinfo.h> +#include <asm/bootinfo-mac.h> +#include <asm/byteorder.h> -#include <asm/system.h>  #include <asm/io.h>  #include <asm/irq.h>  #include <asm/pgtable.h> @@ -53,7 +53,7 @@ struct mac_booter_data mac_bi_data;  static unsigned long mac_orig_videoaddr;  /* Mac specific timer functions */ -extern unsigned long mac_gettimeoffset(void); +extern u32 mac_gettimeoffset(void);  extern int mac_hwclk(int, struct rtc_time *);  extern int mac_set_clock_mmss(unsigned long);  extern void iop_preinit(void); @@ -83,45 +83,46 @@ static void __init mac_sched_init(irq_handler_t vector)  int __init mac_parse_bootinfo(const struct bi_record *record)  {  	int unknown = 0; -	const u_long *data = record->data; +	const void *data = record->data; -	switch (record->tag) { +	switch (be16_to_cpu(record->tag)) {  	case BI_MAC_MODEL: -		mac_bi_data.id = *data; +		mac_bi_data.id = be32_to_cpup(data);  		break;  	case BI_MAC_VADDR: -		mac_bi_data.videoaddr = *data; +		mac_bi_data.videoaddr = be32_to_cpup(data);  		break;  	case BI_MAC_VDEPTH: -		mac_bi_data.videodepth = *data; +		mac_bi_data.videodepth = be32_to_cpup(data);  		break;  	case BI_MAC_VROW: -		mac_bi_data.videorow = *data; +		mac_bi_data.videorow = be32_to_cpup(data);  		break;  	case BI_MAC_VDIM: -		mac_bi_data.dimensions = *data; +		mac_bi_data.dimensions = be32_to_cpup(data);  		break;  	case BI_MAC_VLOGICAL: -		mac_bi_data.videological = VIDEOMEMBASE + (*data & ~VIDEOMEMMASK); -		mac_orig_videoaddr = *data; +		mac_orig_videoaddr = be32_to_cpup(data); +		mac_bi_data.videological = +			VIDEOMEMBASE + (mac_orig_videoaddr & ~VIDEOMEMMASK);  		break;  	case BI_MAC_SCCBASE: -		mac_bi_data.sccbase = *data; +		mac_bi_data.sccbase = be32_to_cpup(data);  		break;  	case BI_MAC_BTIME: -		mac_bi_data.boottime = *data; +		mac_bi_data.boottime = be32_to_cpup(data);  		break;  	case BI_MAC_GMTBIAS: -		mac_bi_data.gmtbias = *data; +		mac_bi_data.gmtbias = be32_to_cpup(data);  		break;  	case BI_MAC_MEMSIZE: -		mac_bi_data.memsize = *data; +		mac_bi_data.memsize = be32_to_cpup(data);  		break;  	case BI_MAC_CPUID: -		mac_bi_data.cpuid = *data; +		mac_bi_data.cpuid = be32_to_cpup(data);  		break;  	case BI_MAC_ROMBASE: -		mac_bi_data.rombase = *data; +		mac_bi_data.rombase = be32_to_cpup(data);  		break;  	default:  		unknown = 1; @@ -153,7 +154,7 @@ void __init config_mac(void)  	mach_sched_init = mac_sched_init;  	mach_init_IRQ = mac_init_IRQ;  	mach_get_model = mac_get_model; -	mach_gettimeoffset = mac_gettimeoffset; +	arch_gettimeoffset = mac_gettimeoffset;  	mach_hwclk = mac_hwclk;  	mach_set_clock_mmss = mac_set_clock_mmss;  	mach_reset = mac_reset; @@ -192,7 +193,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 +268,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 +277,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 +286,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 +295,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 +304,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 +319,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 +328,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 +337,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 +352,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 +361,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 +370,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 +498,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 +525,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 +534,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 +566,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 +575,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 +646,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 +733,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 +748,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 +757,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 +766,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 +775,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 +784,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 +861,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;  	} @@ -950,6 +953,9 @@ int __init mac_platform_init(void)  {  	u8 *swim_base; +	if (!MACH_IS_MAC) +		return -ENODEV; +  	/*  	 * Serial devices  	 */ diff --git a/arch/m68k/mac/iop.c b/arch/m68k/mac/iop.c index 1ad4e9d80eb..4d2adfb32a2 100644 --- a/arch/m68k/mac/iop.c +++ b/arch/m68k/mac/iop.c @@ -111,17 +111,15 @@  #include <linux/init.h>  #include <linux/interrupt.h> -#include <asm/bootinfo.h>  #include <asm/macintosh.h>  #include <asm/macints.h>  #include <asm/mac_iop.h> -#include <asm/mac_oss.h>  /*#define DEBUG_IOP*/ -/* Set to non-zero if the IOPs are present. Set by iop_init() */ +/* Non-zero if the IOPs are present */ -int iop_scc_present,iop_ism_present; +int iop_scc_present, iop_ism_present;  /* structure for tracking channel listeners */ @@ -149,8 +147,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 +300,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 900d899f332..5c1a6b2ff0a 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) -			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/misc.c b/arch/m68k/mac/misc.c index e023fc6b37e..707b61aea20 100644 --- a/arch/m68k/mac/misc.c +++ b/arch/m68k/mac/misc.c @@ -19,15 +19,12 @@  #include <asm/uaccess.h>  #include <asm/io.h>  #include <asm/rtc.h> -#include <asm/system.h>  #include <asm/segment.h>  #include <asm/setup.h>  #include <asm/macintosh.h>  #include <asm/mac_via.h>  #include <asm/mac_oss.h> -#define BOOTINFO_COMPAT_1_0 -#include <asm/bootinfo.h>  #include <asm/machdep.h>  /* Offset between Unix time (1970-based) and Mac time (1904-based) */ @@ -304,35 +301,41 @@ static void via_write_pram(int offset, __u8 data)  static long via_read_time(void)  {  	union { -		__u8  cdata[4]; -		long  idata; +		__u8 cdata[4]; +		long idata;  	} result, last_result; -	int	ct; +	int count = 1; + +	via_pram_command(0x81, &last_result.cdata[3]); +	via_pram_command(0x85, &last_result.cdata[2]); +	via_pram_command(0x89, &last_result.cdata[1]); +	via_pram_command(0x8D, &last_result.cdata[0]);  	/*  	 * The NetBSD guys say to loop until you get the same reading  	 * twice in a row.  	 */ -	ct = 0; -	do { -		if (++ct > 10) { -			printk("via_read_time: couldn't get valid time, " -			       "last read = 0x%08lx and 0x%08lx\n", -			       last_result.idata, result.idata); -			break; -		} - -		last_result.idata = result.idata; -		result.idata = 0; - +	while (1) {  		via_pram_command(0x81, &result.cdata[3]);  		via_pram_command(0x85, &result.cdata[2]);  		via_pram_command(0x89, &result.cdata[1]);  		via_pram_command(0x8D, &result.cdata[0]); -	} while (result.idata != last_result.idata); -	return result.idata - RTC_OFFSET; +		if (result.idata == last_result.idata) +			return result.idata - RTC_OFFSET; + +		if (++count > 10) +			break; + +		last_result.idata = result.idata; +	} + +	pr_err("via_read_time: failed to read a stable value; " +	       "got 0x%08lx then 0x%08lx\n", +	       last_result.idata, result.idata); + +	return 0;  }  /* diff --git a/arch/m68k/mac/oss.c b/arch/m68k/mac/oss.c index a9c0f5ab4cc..54037125ebf 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,8 +19,8 @@  #include <linux/mm.h>  #include <linux/delay.h>  #include <linux/init.h> +#include <linux/irq.h> -#include <asm/bootinfo.h>  #include <asm/macintosh.h>  #include <asm/macints.h>  #include <asm/mac_via.h> @@ -29,11 +29,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 +48,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 +61,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 +98,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 +120,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 +168,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 +183,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 +203,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 +218,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 ba6ccab6401..835fa04511c 100644 --- a/arch/m68k/mac/psc.c +++ b/arch/m68k/mac/psc.c @@ -18,9 +18,9 @@  #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_psc.h> @@ -30,8 +30,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.   */ @@ -55,7 +53,7 @@ static void psc_debug_dump(void)   * expanded to cover what I think are the other 7 channels.   */ -static void psc_dma_die_die_die(void) +static __init void psc_dma_die_die_die(void)  {  	int i; @@ -88,7 +86,7 @@ void __init psc_init(void)  	/*  	 * The PSC is always at the same spot, but using psc -	 * keeps things consisant with the psc_xxxx functions. +	 * keeps things consistent with the psc_xxxx functions.  	 */  	psc = (void *) PSC_BASE; @@ -112,52 +110,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 +179,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 e71166daec6..e198dec868e 100644 --- a/arch/m68k/mac/via.c +++ b/arch/m68k/mac/via.c @@ -28,8 +28,8 @@  #include <linux/delay.h>  #include <linux/init.h>  #include <linux/module.h> +#include <linux/irq.h> -#include <asm/bootinfo.h>  #include <asm/macintosh.h>  #include <asm/macints.h>  #include <asm/mac_via.h> @@ -62,27 +62,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 +125,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 +222,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 +252,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 +289,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.   */ @@ -347,7 +326,7 @@ void via_debug_dump(void)   * TBI: get time offset between scheduling timer ticks   */ -unsigned long mac_gettimeoffset (void) +u32 mac_gettimeoffset(void)  {  	unsigned long ticks, offset = 0; @@ -361,7 +340,7 @@ unsigned long mac_gettimeoffset (void)  	ticks = MAC_CLOCK_TICK - ticks;  	ticks = ticks * 10000L / MAC_CLOCK_TICK; -	return ticks + offset; +	return (ticks + offset) * 1000;  }  /* @@ -409,34 +388,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 +446,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 +493,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 +504,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 +512,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 +526,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 +562,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 +593,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 +613,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);  | 
