diff options
| author | Finn Thain <fthain@telegraphics.com.au> | 2011-10-24 01:11:17 +1100 | 
|---|---|---|
| committer | Geert Uytterhoeven <geert@linux-m68k.org> | 2011-12-10 19:52:47 +0100 | 
| commit | c4af5da7f24ff1bf60db2d6ff3e9d9bd912ca47a (patch) | |
| tree | 2f653a61672f5720e436411526ab6339838fb3bc | |
| parent | 8d9f014ad16711d79c8a575f2d3d009d2a16c7b7 (diff) | |
| download | olio-linux-3.10-c4af5da7f24ff1bf60db2d6ff3e9d9bd912ca47a.tar.xz olio-linux-3.10-c4af5da7f24ff1bf60db2d6ff3e9d9bd912ca47a.zip  | |
m68k/mac: fix nubus slot irq disable and shutdown
Improve NuBus slot interrupt handling code and documentation. This patch fixes the NuBus NIC (mac8390) in my Quadra 700.
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
| -rw-r--r-- | arch/m68k/include/asm/mac_via.h | 2 | ||||
| -rw-r--r-- | arch/m68k/mac/macints.c | 27 | ||||
| -rw-r--r-- | arch/m68k/mac/via.c | 123 | 
3 files changed, 110 insertions, 42 deletions
diff --git a/arch/m68k/include/asm/mac_via.h b/arch/m68k/include/asm/mac_via.h index 53e831c4097..aeeedf8b2d2 100644 --- a/arch/m68k/include/asm/mac_via.h +++ b/arch/m68k/include/asm/mac_via.h @@ -257,6 +257,8 @@ extern int rbv_present,via_alt_mapping;  extern void via_register_interrupts(void);  extern void via_irq_enable(int);  extern void via_irq_disable(int); +extern void via_nubus_irq_startup(int irq); +extern void via_nubus_irq_shutdown(int irq);  extern void via1_irq(unsigned int irq, struct irq_desc *desc);  extern void via1_set_head(int);  extern int via2_scsi_drq_pending(void); diff --git a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c index 41dd164aac2..74f5a97c986 100644 --- a/arch/m68k/mac/macints.c +++ b/arch/m68k/mac/macints.c @@ -151,10 +151,15 @@ irqreturn_t mac_debug_handler(int, void *);  /* #define DEBUG_MACINTS */ +static unsigned int mac_irq_startup(struct irq_data *); +static void mac_irq_shutdown(struct irq_data *); +  static struct irq_chip mac_irq_chip = {  	.name		= "mac",  	.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) @@ -274,6 +279,28 @@ void mac_irq_disable(struct irq_data *data)  	}  } +static unsigned int mac_irq_startup(struct irq_data *data) +{ +	int irq = data->irq; + +	if (IRQ_SRC(irq) == 7 && !oss_present) +		via_nubus_irq_startup(irq); +	else +		mac_irq_enable(data); + +	return 0; +} + +static void mac_irq_shutdown(struct irq_data *data) +{ +	int irq = data->irq; + +	if (IRQ_SRC(irq) == 7 && !oss_present) +		via_nubus_irq_shutdown(irq); +	else +		mac_irq_disable(data); +} +  static int num_debug[8];  irqreturn_t mac_debug_handler(int irq, void *dev_id) diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c index 642b44615f7..97996a48b04 100644 --- a/arch/m68k/mac/via.c +++ b/arch/m68k/mac/via.c @@ -63,18 +63,47 @@ 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); @@ -354,34 +383,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:  		/* 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;  	}  } @@ -507,6 +557,7 @@ 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) @@ -518,14 +569,6 @@ void via_irq_enable(int irq) {  			 */  			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;  		}  	}  } @@ -545,6 +588,7 @@ 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); @@ -552,11 +596,6 @@ void via_irq_disable(int irq) {  		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;  		}  	}  }  |