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.c (8710B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *  linux/arch/arm/mach-rpc/dma.c
      4 *
      5 *  Copyright (C) 1998 Russell King
      6 *
      7 *  DMA functions specific to RiscPC architecture
      8 */
      9#include <linux/mman.h>
     10#include <linux/init.h>
     11#include <linux/interrupt.h>
     12#include <linux/dma-mapping.h>
     13#include <linux/io.h>
     14
     15#include <asm/page.h>
     16#include <asm/dma.h>
     17#include <asm/fiq.h>
     18#include <asm/irq.h>
     19#include <mach/hardware.h>
     20#include <linux/uaccess.h>
     21
     22#include <asm/mach/dma.h>
     23#include <asm/hardware/iomd.h>
     24
     25struct iomd_dma {
     26	struct dma_struct	dma;
     27	void __iomem		*base;		/* Controller base address */
     28	int			irq;		/* Controller IRQ */
     29	unsigned int		state;
     30	dma_addr_t		cur_addr;
     31	unsigned int		cur_len;
     32	dma_addr_t		dma_addr;
     33	unsigned int		dma_len;
     34};
     35
     36#if 0
     37typedef enum {
     38	dma_size_8	= 1,
     39	dma_size_16	= 2,
     40	dma_size_32	= 4,
     41	dma_size_128	= 16
     42} dma_size_t;
     43#endif
     44
     45#define TRANSFER_SIZE	2
     46
     47#define CURA	(0)
     48#define ENDA	(IOMD_IO0ENDA - IOMD_IO0CURA)
     49#define CURB	(IOMD_IO0CURB - IOMD_IO0CURA)
     50#define ENDB	(IOMD_IO0ENDB - IOMD_IO0CURA)
     51#define CR	(IOMD_IO0CR - IOMD_IO0CURA)
     52#define ST	(IOMD_IO0ST - IOMD_IO0CURA)
     53
     54static void iomd_get_next_sg(struct iomd_dma *idma)
     55{
     56	unsigned long end, offset, flags = 0;
     57
     58	if (idma->dma.sg) {
     59		idma->cur_addr = idma->dma_addr;
     60		offset = idma->cur_addr & ~PAGE_MASK;
     61
     62		end = offset + idma->dma_len;
     63
     64		if (end > PAGE_SIZE)
     65			end = PAGE_SIZE;
     66
     67		if (offset + TRANSFER_SIZE >= end)
     68			flags |= DMA_END_L;
     69
     70		idma->cur_len = end - TRANSFER_SIZE;
     71
     72		idma->dma_len -= end - offset;
     73		idma->dma_addr += end - offset;
     74
     75		if (idma->dma_len == 0) {
     76			if (idma->dma.sgcount > 1) {
     77				idma->dma.sg = sg_next(idma->dma.sg);
     78				idma->dma_addr = idma->dma.sg->dma_address;
     79				idma->dma_len = idma->dma.sg->length;
     80				idma->dma.sgcount--;
     81			} else {
     82				idma->dma.sg = NULL;
     83				flags |= DMA_END_S;
     84			}
     85		}
     86	} else {
     87		flags = DMA_END_S | DMA_END_L;
     88		idma->cur_addr = 0;
     89		idma->cur_len = 0;
     90	}
     91
     92	idma->cur_len |= flags;
     93}
     94
     95static irqreturn_t iomd_dma_handle(int irq, void *dev_id)
     96{
     97	struct iomd_dma *idma = dev_id;
     98	void __iomem *base = idma->base;
     99	unsigned int state = idma->state;
    100	unsigned int status, cur, end;
    101
    102	do {
    103		status = readb(base + ST);
    104		if (!(status & DMA_ST_INT))
    105			goto out;
    106
    107		if ((state ^ status) & DMA_ST_AB)
    108			iomd_get_next_sg(idma);
    109
    110		// This efficiently implements state = OFL != AB ? AB : 0
    111		state = ((status >> 2) ^ status) & DMA_ST_AB;
    112		if (state) {
    113			cur = CURA;
    114			end = ENDA;
    115		} else {
    116			cur = CURB;
    117			end = ENDB;
    118		}
    119		writel(idma->cur_addr, base + cur);
    120		writel(idma->cur_len, base + end);
    121
    122		if (status & DMA_ST_OFL &&
    123		    idma->cur_len == (DMA_END_S|DMA_END_L))
    124			break;
    125	} while (1);
    126
    127	state = ~DMA_ST_AB;
    128	disable_irq_nosync(irq);
    129out:
    130	idma->state = state;
    131	return IRQ_HANDLED;
    132}
    133
    134static int iomd_request_dma(unsigned int chan, dma_t *dma)
    135{
    136	struct iomd_dma *idma = container_of(dma, struct iomd_dma, dma);
    137
    138	return request_irq(idma->irq, iomd_dma_handle,
    139			   0, idma->dma.device_id, idma);
    140}
    141
    142static void iomd_free_dma(unsigned int chan, dma_t *dma)
    143{
    144	struct iomd_dma *idma = container_of(dma, struct iomd_dma, dma);
    145
    146	free_irq(idma->irq, idma);
    147}
    148
    149static struct device isa_dma_dev = {
    150	.init_name		= "fallback device",
    151	.coherent_dma_mask	= ~(dma_addr_t)0,
    152	.dma_mask		= &isa_dma_dev.coherent_dma_mask,
    153};
    154
    155static void iomd_enable_dma(unsigned int chan, dma_t *dma)
    156{
    157	struct iomd_dma *idma = container_of(dma, struct iomd_dma, dma);
    158	void __iomem *base = idma->base;
    159	unsigned int ctrl = TRANSFER_SIZE | DMA_CR_E;
    160
    161	if (idma->dma.invalid) {
    162		idma->dma.invalid = 0;
    163
    164		/*
    165		 * Cope with ISA-style drivers which expect cache
    166		 * coherence.
    167		 */
    168		if (!idma->dma.sg) {
    169			idma->dma.sg = &idma->dma.buf;
    170			idma->dma.sgcount = 1;
    171			idma->dma.buf.length = idma->dma.count;
    172			idma->dma.buf.dma_address = dma_map_single(&isa_dma_dev,
    173				idma->dma.addr, idma->dma.count,
    174				idma->dma.dma_mode == DMA_MODE_READ ?
    175				DMA_FROM_DEVICE : DMA_TO_DEVICE);
    176		}
    177
    178		idma->dma_addr = idma->dma.sg->dma_address;
    179		idma->dma_len = idma->dma.sg->length;
    180
    181		writeb(DMA_CR_C, base + CR);
    182		idma->state = DMA_ST_AB;
    183	}
    184
    185	if (idma->dma.dma_mode == DMA_MODE_READ)
    186		ctrl |= DMA_CR_D;
    187
    188	writeb(ctrl, base + CR);
    189	enable_irq(idma->irq);
    190}
    191
    192static void iomd_disable_dma(unsigned int chan, dma_t *dma)
    193{
    194	struct iomd_dma *idma = container_of(dma, struct iomd_dma, dma);
    195	void __iomem *base = idma->base;
    196	unsigned long flags;
    197
    198	local_irq_save(flags);
    199	if (idma->state != ~DMA_ST_AB)
    200		disable_irq(idma->irq);
    201	writeb(0, base + CR);
    202	local_irq_restore(flags);
    203}
    204
    205static int iomd_set_dma_speed(unsigned int chan, dma_t *dma, int cycle)
    206{
    207	int tcr, speed;
    208
    209	if (cycle < 188)
    210		speed = 3;
    211	else if (cycle <= 250)
    212		speed = 2;
    213	else if (cycle < 438)
    214		speed = 1;
    215	else
    216		speed = 0;
    217
    218	tcr = iomd_readb(IOMD_DMATCR);
    219	speed &= 3;
    220
    221	switch (chan) {
    222	case DMA_0:
    223		tcr = (tcr & ~0x03) | speed;
    224		break;
    225
    226	case DMA_1:
    227		tcr = (tcr & ~0x0c) | (speed << 2);
    228		break;
    229
    230	case DMA_2:
    231		tcr = (tcr & ~0x30) | (speed << 4);
    232		break;
    233
    234	case DMA_3:
    235		tcr = (tcr & ~0xc0) | (speed << 6);
    236		break;
    237
    238	default:
    239		break;
    240	}
    241
    242	iomd_writeb(tcr, IOMD_DMATCR);
    243
    244	return speed;
    245}
    246
    247static struct dma_ops iomd_dma_ops = {
    248	.type		= "IOMD",
    249	.request	= iomd_request_dma,
    250	.free		= iomd_free_dma,
    251	.enable		= iomd_enable_dma,
    252	.disable	= iomd_disable_dma,
    253	.setspeed	= iomd_set_dma_speed,
    254};
    255
    256static struct fiq_handler fh = {
    257	.name	= "floppydma"
    258};
    259
    260struct floppy_dma {
    261	struct dma_struct	dma;
    262	unsigned int		fiq;
    263};
    264
    265static void floppy_enable_dma(unsigned int chan, dma_t *dma)
    266{
    267	struct floppy_dma *fdma = container_of(dma, struct floppy_dma, dma);
    268	void *fiqhandler_start;
    269	unsigned int fiqhandler_length;
    270	struct pt_regs regs;
    271
    272	if (fdma->dma.sg)
    273		BUG();
    274
    275	if (fdma->dma.dma_mode == DMA_MODE_READ) {
    276		extern unsigned char floppy_fiqin_start, floppy_fiqin_end;
    277		fiqhandler_start = &floppy_fiqin_start;
    278		fiqhandler_length = &floppy_fiqin_end - &floppy_fiqin_start;
    279	} else {
    280		extern unsigned char floppy_fiqout_start, floppy_fiqout_end;
    281		fiqhandler_start = &floppy_fiqout_start;
    282		fiqhandler_length = &floppy_fiqout_end - &floppy_fiqout_start;
    283	}
    284
    285	regs.ARM_r9  = fdma->dma.count;
    286	regs.ARM_r10 = (unsigned long)fdma->dma.addr;
    287	regs.ARM_fp  = (unsigned long)FLOPPYDMA_BASE;
    288
    289	if (claim_fiq(&fh)) {
    290		printk("floppydma: couldn't claim FIQ.\n");
    291		return;
    292	}
    293
    294	set_fiq_handler(fiqhandler_start, fiqhandler_length);
    295	set_fiq_regs(&regs);
    296	enable_fiq(fdma->fiq);
    297}
    298
    299static void floppy_disable_dma(unsigned int chan, dma_t *dma)
    300{
    301	struct floppy_dma *fdma = container_of(dma, struct floppy_dma, dma);
    302	disable_fiq(fdma->fiq);
    303	release_fiq(&fh);
    304}
    305
    306static int floppy_get_residue(unsigned int chan, dma_t *dma)
    307{
    308	struct pt_regs regs;
    309	get_fiq_regs(&regs);
    310	return regs.ARM_r9;
    311}
    312
    313static struct dma_ops floppy_dma_ops = {
    314	.type		= "FIQDMA",
    315	.enable		= floppy_enable_dma,
    316	.disable	= floppy_disable_dma,
    317	.residue	= floppy_get_residue,
    318};
    319
    320/*
    321 * This is virtual DMA - we don't need anything here.
    322 */
    323static void sound_enable_disable_dma(unsigned int chan, dma_t *dma)
    324{
    325}
    326
    327static struct dma_ops sound_dma_ops = {
    328	.type		= "VIRTUAL",
    329	.enable		= sound_enable_disable_dma,
    330	.disable	= sound_enable_disable_dma,
    331};
    332
    333static struct iomd_dma iomd_dma[6];
    334
    335static struct floppy_dma floppy_dma = {
    336	.dma		= {
    337		.d_ops	= &floppy_dma_ops,
    338	},
    339	.fiq		= FIQ_FLOPPYDATA,
    340};
    341
    342static dma_t sound_dma = {
    343	.d_ops		= &sound_dma_ops,
    344};
    345
    346static int __init rpc_dma_init(void)
    347{
    348	unsigned int i;
    349	int ret;
    350
    351	iomd_writeb(0, IOMD_IO0CR);
    352	iomd_writeb(0, IOMD_IO1CR);
    353	iomd_writeb(0, IOMD_IO2CR);
    354	iomd_writeb(0, IOMD_IO3CR);
    355
    356	iomd_writeb(0xa0, IOMD_DMATCR);
    357
    358	/*
    359	 * Setup DMA channels 2,3 to be for podules
    360	 * and channels 0,1 for internal devices
    361	 */
    362	iomd_writeb(DMA_EXT_IO3|DMA_EXT_IO2, IOMD_DMAEXT);
    363
    364	iomd_dma[DMA_0].base	= IOMD_BASE + IOMD_IO0CURA;
    365	iomd_dma[DMA_0].irq	= IRQ_DMA0;
    366	iomd_dma[DMA_1].base	= IOMD_BASE + IOMD_IO1CURA;
    367	iomd_dma[DMA_1].irq	= IRQ_DMA1;
    368	iomd_dma[DMA_2].base	= IOMD_BASE + IOMD_IO2CURA;
    369	iomd_dma[DMA_2].irq	= IRQ_DMA2;
    370	iomd_dma[DMA_3].base	= IOMD_BASE + IOMD_IO3CURA;
    371	iomd_dma[DMA_3].irq	= IRQ_DMA3;
    372	iomd_dma[DMA_S0].base	= IOMD_BASE + IOMD_SD0CURA;
    373	iomd_dma[DMA_S0].irq	= IRQ_DMAS0;
    374	iomd_dma[DMA_S1].base	= IOMD_BASE + IOMD_SD1CURA;
    375	iomd_dma[DMA_S1].irq	= IRQ_DMAS1;
    376
    377	for (i = DMA_0; i <= DMA_S1; i++) {
    378		iomd_dma[i].dma.d_ops = &iomd_dma_ops;
    379
    380		ret = isa_dma_add(i, &iomd_dma[i].dma);
    381		if (ret)
    382			printk("IOMDDMA%u: unable to register: %d\n", i, ret);
    383	}
    384
    385	ret = isa_dma_add(DMA_VIRTUAL_FLOPPY, &floppy_dma.dma);
    386	if (ret)
    387		printk("IOMDFLOPPY: unable to register: %d\n", ret);
    388	ret = isa_dma_add(DMA_VIRTUAL_SOUND, &sound_dma);
    389	if (ret)
    390		printk("IOMDSOUND: unable to register: %d\n", ret);
    391	return 0;
    392}
    393core_initcall(rpc_dma_init);