cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

macints.c (6664B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 *	Macintosh interrupts
      4 *
      5 * General design:
      6 * In contrary to the Amiga and Atari platforms, the Mac hardware seems to
      7 * exclusively use the autovector interrupts (the 'generic level0-level7'
      8 * interrupts with exception vectors 0x19-0x1f). The following interrupt levels
      9 * are used:
     10 *	1	- VIA1
     11 *		  - slot 0: one second interrupt (CA2)
     12 *		  - slot 1: VBlank (CA1)
     13 *		  - slot 2: ADB data ready (SR full)
     14 *		  - slot 3: ADB data  (CB2)
     15 *		  - slot 4: ADB clock (CB1)
     16 *		  - slot 5: timer 2
     17 *		  - slot 6: timer 1
     18 *		  - slot 7: status of IRQ; signals 'any enabled int.'
     19 *
     20 *	2	- VIA2 or RBV
     21 *		  - slot 0: SCSI DRQ (CA2)
     22 *		  - slot 1: NUBUS IRQ (CA1) need to read port A to find which
     23 *		  - slot 2: /EXP IRQ (only on IIci)
     24 *		  - slot 3: SCSI IRQ (CB2)
     25 *		  - slot 4: ASC IRQ (CB1)
     26 *		  - slot 5: timer 2 (not on IIci)
     27 *		  - slot 6: timer 1 (not on IIci)
     28 *		  - slot 7: status of IRQ; signals 'any enabled int.'
     29 *
     30 * Levels 3-6 vary by machine type. For VIA or RBV Macintoshes:
     31 *
     32 *	3	- unused (?)
     33 *
     34 *	4	- SCC
     35 *
     36 *	5	- unused (?)
     37 *		  [serial errors or special conditions seem to raise level 6
     38 *		  interrupts on some models (LC4xx?)]
     39 *
     40 *	6	- off switch (?)
     41 *
     42 * Machines with Quadra-like VIA hardware, except PSC and PMU machines, support
     43 * an alternate interrupt mapping, as used by A/UX. It spreads ethernet and
     44 * sound out to their own autovector IRQs and gives VIA1 a higher priority:
     45 *
     46 *	1	- unused (?)
     47 *
     48 *	3	- on-board SONIC
     49 *
     50 *	5	- Apple Sound Chip (ASC)
     51 *
     52 *	6	- VIA1
     53 *
     54 * For OSS Macintoshes (IIfx only), we apply an interrupt mapping similar to
     55 * the Quadra (A/UX) mapping:
     56 *
     57 *	1	- ISM IOP (ADB)
     58 *
     59 *	2	- SCSI
     60 *
     61 *	3	- NuBus
     62 *
     63 *	4	- SCC IOP
     64 *
     65 *	6	- VIA1
     66 *
     67 * For PSC Macintoshes (660AV, 840AV):
     68 *
     69 *	3	- PSC level 3
     70 *		  - slot 0: MACE
     71 *
     72 *	4	- PSC level 4
     73 *		  - slot 1: SCC channel A interrupt
     74 *		  - slot 2: SCC channel B interrupt
     75 *		  - slot 3: MACE DMA
     76 *
     77 *	5	- PSC level 5
     78 *
     79 *	6	- PSC level 6
     80 *
     81 * Finally we have good 'ole level 7, the non-maskable interrupt:
     82 *
     83 *	7	- NMI (programmer's switch on the back of some Macs)
     84 *		  Also RAM parity error on models which support it (IIc, IIfx?)
     85 *
     86 * The current interrupt logic looks something like this:
     87 *
     88 * - We install dispatchers for the autovector interrupts (1-7). These
     89 *   dispatchers are responsible for querying the hardware (the
     90 *   VIA/RBV/OSS/PSC chips) to determine the actual interrupt source. Using
     91 *   this information a machspec interrupt number is generated by placing the
     92 *   index of the interrupt hardware into the low three bits and the original
     93 *   autovector interrupt number in the upper 5 bits. The handlers for the
     94 *   resulting machspec interrupt are then called.
     95 *
     96 * - Nubus is a special case because its interrupts are hidden behind two
     97 *   layers of hardware. Nubus interrupts come in as index 1 on VIA #2,
     98 *   which translates to IRQ number 17. In this spot we install _another_
     99 *   dispatcher. This dispatcher finds the interrupting slot number (9-F) and
    100 *   then forms a new machspec interrupt number as above with the slot number
    101 *   minus 9 in the low three bits and the pseudo-level 7 in the upper five
    102 *   bits.  The handlers for this new machspec interrupt number are then
    103 *   called. This puts Nubus interrupts into the range 56-62.
    104 *
    105 * - The Baboon interrupts (used on some PowerBooks) are an even more special
    106 *   case. They're hidden behind the Nubus slot $C interrupt thus adding a
    107 *   third layer of indirection. Why oh why did the Apple engineers do that?
    108 *
    109 */
    110
    111#include <linux/types.h>
    112#include <linux/kernel.h>
    113#include <linux/sched.h>
    114#include <linux/sched/debug.h>
    115#include <linux/interrupt.h>
    116#include <linux/irq.h>
    117#include <linux/delay.h>
    118
    119#include <asm/irq.h>
    120#include <asm/macintosh.h>
    121#include <asm/macints.h>
    122#include <asm/mac_via.h>
    123#include <asm/mac_psc.h>
    124#include <asm/mac_oss.h>
    125#include <asm/mac_iop.h>
    126#include <asm/mac_baboon.h>
    127#include <asm/hwtest.h>
    128#include <asm/irq_regs.h>
    129
    130extern void show_registers(struct pt_regs *);
    131
    132irqreturn_t mac_nmi_handler(int, void *);
    133
    134static unsigned int mac_irq_startup(struct irq_data *);
    135static void mac_irq_shutdown(struct irq_data *);
    136
    137static struct irq_chip mac_irq_chip = {
    138	.name		= "mac",
    139	.irq_enable	= mac_irq_enable,
    140	.irq_disable	= mac_irq_disable,
    141	.irq_startup	= mac_irq_startup,
    142	.irq_shutdown	= mac_irq_shutdown,
    143};
    144
    145void __init mac_init_IRQ(void)
    146{
    147	m68k_setup_irq_controller(&mac_irq_chip, handle_simple_irq, IRQ_USER,
    148				  NUM_MAC_SOURCES - IRQ_USER);
    149
    150	/*
    151	 * Now register the handlers for the master IRQ handlers
    152	 * at levels 1-7. Most of the work is done elsewhere.
    153	 */
    154
    155	if (oss_present)
    156		oss_register_interrupts();
    157	else
    158		via_register_interrupts();
    159	if (psc)
    160		psc_register_interrupts();
    161	if (baboon_present)
    162		baboon_register_interrupts();
    163	iop_register_interrupts();
    164	if (request_irq(IRQ_AUTO_7, mac_nmi_handler, 0, "NMI",
    165			mac_nmi_handler))
    166		pr_err("Couldn't register NMI\n");
    167}
    168
    169/*
    170 *  mac_irq_enable - enable an interrupt source
    171 * mac_irq_disable - disable an interrupt source
    172 *
    173 * These routines are just dispatchers to the VIA/OSS/PSC routines.
    174 */
    175
    176void mac_irq_enable(struct irq_data *data)
    177{
    178	int irq = data->irq;
    179	int irq_src = IRQ_SRC(irq);
    180
    181	switch(irq_src) {
    182	case 1:
    183	case 2:
    184	case 7:
    185		if (oss_present)
    186			oss_irq_enable(irq);
    187		else
    188			via_irq_enable(irq);
    189		break;
    190	case 3:
    191	case 4:
    192	case 5:
    193	case 6:
    194		if (psc)
    195			psc_irq_enable(irq);
    196		else if (oss_present)
    197			oss_irq_enable(irq);
    198		break;
    199	case 8:
    200		if (baboon_present)
    201			baboon_irq_enable(irq);
    202		break;
    203	}
    204}
    205
    206void mac_irq_disable(struct irq_data *data)
    207{
    208	int irq = data->irq;
    209	int irq_src = IRQ_SRC(irq);
    210
    211	switch(irq_src) {
    212	case 1:
    213	case 2:
    214	case 7:
    215		if (oss_present)
    216			oss_irq_disable(irq);
    217		else
    218			via_irq_disable(irq);
    219		break;
    220	case 3:
    221	case 4:
    222	case 5:
    223	case 6:
    224		if (psc)
    225			psc_irq_disable(irq);
    226		else if (oss_present)
    227			oss_irq_disable(irq);
    228		break;
    229	case 8:
    230		if (baboon_present)
    231			baboon_irq_disable(irq);
    232		break;
    233	}
    234}
    235
    236static unsigned int mac_irq_startup(struct irq_data *data)
    237{
    238	int irq = data->irq;
    239
    240	if (IRQ_SRC(irq) == 7 && !oss_present)
    241		via_nubus_irq_startup(irq);
    242	else
    243		mac_irq_enable(data);
    244
    245	return 0;
    246}
    247
    248static void mac_irq_shutdown(struct irq_data *data)
    249{
    250	int irq = data->irq;
    251
    252	if (IRQ_SRC(irq) == 7 && !oss_present)
    253		via_nubus_irq_shutdown(irq);
    254	else
    255		mac_irq_disable(data);
    256}
    257
    258static volatile int in_nmi;
    259
    260irqreturn_t mac_nmi_handler(int irq, void *dev_id)
    261{
    262	if (in_nmi)
    263		return IRQ_HANDLED;
    264	in_nmi = 1;
    265
    266	pr_info("Non-Maskable Interrupt\n");
    267	show_registers(get_irq_regs());
    268
    269	in_nmi = 0;
    270	return IRQ_HANDLED;
    271}