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

dma-isa.c (5178B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *  linux/arch/arm/kernel/dma-isa.c
      4 *
      5 *  Copyright (C) 1999-2000 Russell King
      6 *
      7 *  ISA DMA primitives
      8 *  Taken from various sources, including:
      9 *   linux/include/asm/dma.h: Defines for using and allocating dma channels.
     10 *     Written by Hennus Bergman, 1992.
     11 *     High DMA channel support & info by Hannu Savolainen and John Boyd,
     12 *     Nov. 1992.
     13 *   arch/arm/kernel/dma-ebsa285.c
     14 *   Copyright (C) 1998 Phil Blundell
     15 */
     16#include <linux/ioport.h>
     17#include <linux/init.h>
     18#include <linux/dma-mapping.h>
     19#include <linux/io.h>
     20
     21#include <asm/dma.h>
     22#include <asm/mach/dma.h>
     23
     24#define ISA_DMA_MASK		0
     25#define ISA_DMA_MODE		1
     26#define ISA_DMA_CLRFF		2
     27#define ISA_DMA_PGHI		3
     28#define ISA_DMA_PGLO		4
     29#define ISA_DMA_ADDR		5
     30#define ISA_DMA_COUNT		6
     31
     32static unsigned int isa_dma_port[8][7] = {
     33	/* MASK   MODE   CLRFF  PAGE_HI PAGE_LO ADDR COUNT */
     34	{  0x0a,  0x0b,  0x0c,  0x487,  0x087,  0x00, 0x01 },
     35	{  0x0a,  0x0b,  0x0c,  0x483,  0x083,  0x02, 0x03 },
     36	{  0x0a,  0x0b,  0x0c,  0x481,  0x081,  0x04, 0x05 },
     37	{  0x0a,  0x0b,  0x0c,  0x482,  0x082,  0x06, 0x07 },
     38	{  0xd4,  0xd6,  0xd8,  0x000,  0x000,  0xc0, 0xc2 },
     39	{  0xd4,  0xd6,  0xd8,  0x48b,  0x08b,  0xc4, 0xc6 },
     40	{  0xd4,  0xd6,  0xd8,  0x489,  0x089,  0xc8, 0xca },
     41	{  0xd4,  0xd6,  0xd8,  0x48a,  0x08a,  0xcc, 0xce }
     42};
     43
     44static int isa_get_dma_residue(unsigned int chan, dma_t *dma)
     45{
     46	unsigned int io_port = isa_dma_port[chan][ISA_DMA_COUNT];
     47	int count;
     48
     49	count = 1 + inb(io_port);
     50	count |= inb(io_port) << 8;
     51
     52	return chan < 4 ? count : (count << 1);
     53}
     54
     55static struct device isa_dma_dev = {
     56	.init_name		= "fallback device",
     57	.coherent_dma_mask	= ~(dma_addr_t)0,
     58	.dma_mask		= &isa_dma_dev.coherent_dma_mask,
     59};
     60
     61static void isa_enable_dma(unsigned int chan, dma_t *dma)
     62{
     63	if (dma->invalid) {
     64		unsigned long address, length;
     65		unsigned int mode;
     66		enum dma_data_direction direction;
     67
     68		mode = (chan & 3) | dma->dma_mode;
     69		switch (dma->dma_mode & DMA_MODE_MASK) {
     70		case DMA_MODE_READ:
     71			direction = DMA_FROM_DEVICE;
     72			break;
     73
     74		case DMA_MODE_WRITE:
     75			direction = DMA_TO_DEVICE;
     76			break;
     77
     78		case DMA_MODE_CASCADE:
     79			direction = DMA_BIDIRECTIONAL;
     80			break;
     81
     82		default:
     83			direction = DMA_NONE;
     84			break;
     85		}
     86
     87		if (!dma->sg) {
     88			/*
     89			 * Cope with ISA-style drivers which expect cache
     90			 * coherence.
     91			 */
     92			dma->sg = &dma->buf;
     93			dma->sgcount = 1;
     94			dma->buf.length = dma->count;
     95			dma->buf.dma_address = dma_map_single(&isa_dma_dev,
     96				dma->addr, dma->count,
     97				direction);
     98		}
     99
    100		address = dma->buf.dma_address;
    101		length  = dma->buf.length - 1;
    102
    103		outb(address >> 16, isa_dma_port[chan][ISA_DMA_PGLO]);
    104		outb(address >> 24, isa_dma_port[chan][ISA_DMA_PGHI]);
    105
    106		if (chan >= 4) {
    107			address >>= 1;
    108			length >>= 1;
    109		}
    110
    111		outb(0, isa_dma_port[chan][ISA_DMA_CLRFF]);
    112
    113		outb(address, isa_dma_port[chan][ISA_DMA_ADDR]);
    114		outb(address >> 8, isa_dma_port[chan][ISA_DMA_ADDR]);
    115
    116		outb(length, isa_dma_port[chan][ISA_DMA_COUNT]);
    117		outb(length >> 8, isa_dma_port[chan][ISA_DMA_COUNT]);
    118
    119		outb(mode, isa_dma_port[chan][ISA_DMA_MODE]);
    120		dma->invalid = 0;
    121	}
    122	outb(chan & 3, isa_dma_port[chan][ISA_DMA_MASK]);
    123}
    124
    125static void isa_disable_dma(unsigned int chan, dma_t *dma)
    126{
    127	outb(chan | 4, isa_dma_port[chan][ISA_DMA_MASK]);
    128}
    129
    130static struct dma_ops isa_dma_ops = {
    131	.type		= "ISA",
    132	.enable		= isa_enable_dma,
    133	.disable	= isa_disable_dma,
    134	.residue	= isa_get_dma_residue,
    135};
    136
    137static struct resource dma_resources[] = { {
    138	.name	= "dma1",
    139	.start	= 0x0000,
    140	.end	= 0x000f
    141}, {
    142	.name	= "dma low page",
    143	.start	= 0x0080,
    144	.end 	= 0x008f
    145}, {
    146	.name	= "dma2",
    147	.start	= 0x00c0,
    148	.end	= 0x00df
    149}, {
    150	.name	= "dma high page",
    151	.start	= 0x0480,
    152	.end	= 0x048f
    153} };
    154
    155static dma_t isa_dma[8];
    156
    157/*
    158 * ISA DMA always starts at channel 0
    159 */
    160void __init isa_init_dma(void)
    161{
    162	/*
    163	 * Try to autodetect presence of an ISA DMA controller.
    164	 * We do some minimal initialisation, and check that
    165	 * channel 0's DMA address registers are writeable.
    166	 */
    167	outb(0xff, 0x0d);
    168	outb(0xff, 0xda);
    169
    170	/*
    171	 * Write high and low address, and then read them back
    172	 * in the same order.
    173	 */
    174	outb(0x55, 0x00);
    175	outb(0xaa, 0x00);
    176
    177	if (inb(0) == 0x55 && inb(0) == 0xaa) {
    178		unsigned int chan, i;
    179
    180		for (chan = 0; chan < 8; chan++) {
    181			isa_dma[chan].d_ops = &isa_dma_ops;
    182			isa_disable_dma(chan, NULL);
    183		}
    184
    185		outb(0x40, 0x0b);
    186		outb(0x41, 0x0b);
    187		outb(0x42, 0x0b);
    188		outb(0x43, 0x0b);
    189
    190		outb(0xc0, 0xd6);
    191		outb(0x41, 0xd6);
    192		outb(0x42, 0xd6);
    193		outb(0x43, 0xd6);
    194
    195		outb(0, 0xd4);
    196
    197		outb(0x10, 0x08);
    198		outb(0x10, 0xd0);
    199
    200		/*
    201		 * Is this correct?  According to my documentation, it
    202		 * doesn't appear to be.  It should be:
    203		 *  outb(0x3f, 0x40b); outb(0x3f, 0x4d6);
    204		 */
    205		outb(0x30, 0x40b);
    206		outb(0x31, 0x40b);
    207		outb(0x32, 0x40b);
    208		outb(0x33, 0x40b);
    209		outb(0x31, 0x4d6);
    210		outb(0x32, 0x4d6);
    211		outb(0x33, 0x4d6);
    212
    213		for (i = 0; i < ARRAY_SIZE(dma_resources); i++)
    214			request_resource(&ioport_resource, dma_resources + i);
    215
    216		for (chan = 0; chan < 8; chan++) {
    217			int ret = isa_dma_add(chan, &isa_dma[chan]);
    218			if (ret)
    219				pr_err("ISADMA%u: unable to register: %d\n",
    220				       chan, ret);
    221		}
    222
    223		request_dma(DMA_ISA_CASCADE, "cascade");
    224	}
    225}