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

psc.c (3841B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *	Apple Peripheral System Controller (PSC)
      4 *
      5 *	The PSC is used on the AV Macs to control IO functions not handled
      6 *	by the VIAs (Ethernet, DSP, SCC).
      7 *
      8 * TO DO:
      9 *
     10 * Try to figure out what's going on in pIFR5 and pIFR6. There seem to be
     11 * persisant interrupt conditions in those registers and I have no idea what
     12 * they are. Granted it doesn't affect since we're not enabling any interrupts
     13 * on those levels at the moment, but it would be nice to know. I have a feeling
     14 * they aren't actually interrupt lines but data lines (to the DSP?)
     15 */
     16
     17#include <linux/types.h>
     18#include <linux/kernel.h>
     19#include <linux/mm.h>
     20#include <linux/delay.h>
     21#include <linux/init.h>
     22#include <linux/irq.h>
     23
     24#include <asm/traps.h>
     25#include <asm/macintosh.h>
     26#include <asm/macints.h>
     27#include <asm/mac_psc.h>
     28
     29#define DEBUG_PSC
     30
     31volatile __u8 *psc;
     32EXPORT_SYMBOL_GPL(psc);
     33
     34/*
     35 * Debugging dump, used in various places to see what's going on.
     36 */
     37
     38static void psc_debug_dump(void)
     39{
     40	int	i;
     41
     42	if (!psc)
     43		return;
     44
     45	for (i = 0x30 ; i < 0x70 ; i += 0x10) {
     46		printk(KERN_DEBUG "PSC #%d:  IFR = 0x%02X IER = 0x%02X\n",
     47			i >> 4,
     48			(int) psc_read_byte(pIFRbase + i),
     49			(int) psc_read_byte(pIERbase + i));
     50	}
     51}
     52
     53/*
     54 * Try to kill all DMA channels on the PSC. Not sure how this his
     55 * supposed to work; this is code lifted from macmace.c and then
     56 * expanded to cover what I think are the other 7 channels.
     57 */
     58
     59static __init void psc_dma_die_die_die(void)
     60{
     61	int i;
     62
     63	for (i = 0 ; i < 9 ; i++) {
     64		psc_write_word(PSC_CTL_BASE + (i << 4), 0x8800);
     65		psc_write_word(PSC_CTL_BASE + (i << 4), 0x1000);
     66		psc_write_word(PSC_CMD_BASE + (i << 5), 0x1100);
     67		psc_write_word(PSC_CMD_BASE + (i << 5) + 0x10, 0x1100);
     68	}
     69}
     70
     71/*
     72 * Initialize the PSC. For now this just involves shutting down all
     73 * interrupt sources using the IERs.
     74 */
     75
     76void __init psc_init(void)
     77{
     78	int i;
     79
     80	if (macintosh_config->ident != MAC_MODEL_C660
     81	 && macintosh_config->ident != MAC_MODEL_Q840)
     82	{
     83		psc = NULL;
     84		return;
     85	}
     86
     87	/*
     88	 * The PSC is always at the same spot, but using psc
     89	 * keeps things consistent with the psc_xxxx functions.
     90	 */
     91
     92	psc = (void *) PSC_BASE;
     93
     94	pr_debug("PSC detected at %p\n", psc);
     95
     96	psc_dma_die_die_die();
     97
     98#ifdef DEBUG_PSC
     99	psc_debug_dump();
    100#endif
    101	/*
    102	 * Mask and clear all possible interrupts
    103	 */
    104
    105	for (i = 0x30 ; i < 0x70 ; i += 0x10) {
    106		psc_write_byte(pIERbase + i, 0x0F);
    107		psc_write_byte(pIFRbase + i, 0x0F);
    108	}
    109}
    110
    111/*
    112 * PSC interrupt handler. It's a lot like the VIA interrupt handler.
    113 */
    114
    115static void psc_irq(struct irq_desc *desc)
    116{
    117	unsigned int offset = (unsigned int)irq_desc_get_handler_data(desc);
    118	unsigned int irq = irq_desc_get_irq(desc);
    119	int pIFR	= pIFRbase + offset;
    120	int pIER	= pIERbase + offset;
    121	int irq_num;
    122	unsigned char irq_bit, events;
    123
    124	events = psc_read_byte(pIFR) & psc_read_byte(pIER) & 0xF;
    125	if (!events)
    126		return;
    127
    128	irq_num = irq << 3;
    129	irq_bit = 1;
    130	do {
    131		if (events & irq_bit) {
    132			psc_write_byte(pIFR, irq_bit);
    133			generic_handle_irq(irq_num);
    134		}
    135		irq_num++;
    136		irq_bit <<= 1;
    137	} while (events >= irq_bit);
    138}
    139
    140/*
    141 * Register the PSC interrupt dispatchers for autovector interrupts 3-6.
    142 */
    143
    144void __init psc_register_interrupts(void)
    145{
    146	irq_set_chained_handler_and_data(IRQ_AUTO_3, psc_irq, (void *)0x30);
    147	irq_set_chained_handler_and_data(IRQ_AUTO_4, psc_irq, (void *)0x40);
    148	irq_set_chained_handler_and_data(IRQ_AUTO_5, psc_irq, (void *)0x50);
    149	irq_set_chained_handler_and_data(IRQ_AUTO_6, psc_irq, (void *)0x60);
    150}
    151
    152void psc_irq_enable(int irq) {
    153	int irq_src	= IRQ_SRC(irq);
    154	int irq_idx	= IRQ_IDX(irq);
    155	int pIER	= pIERbase + (irq_src << 4);
    156
    157	psc_write_byte(pIER, (1 << irq_idx) | 0x80);
    158}
    159
    160void psc_irq_disable(int irq) {
    161	int irq_src	= IRQ_SRC(irq);
    162	int irq_idx	= IRQ_IDX(irq);
    163	int pIER	= pIERbase + (irq_src << 4);
    164
    165	psc_write_byte(pIER, 1 << irq_idx);
    166}