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


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * arch/sh/drivers/dma/dma-g2.c
      4 *
      5 * G2 bus DMA support
      6 *
      7 * Copyright (C) 2003 - 2006  Paul Mundt
      8 */
      9#include <linux/init.h>
     10#include <linux/kernel.h>
     11#include <linux/module.h>
     12#include <linux/interrupt.h>
     13#include <asm/cacheflush.h>
     14#include <mach/sysasic.h>
     15#include <mach/dma.h>
     16#include <asm/dma.h>
     17
     18struct g2_channel {
     19	unsigned long g2_addr;		/* G2 bus address */
     20	unsigned long root_addr;	/* Root bus (SH-4) address */
     21	unsigned long size;		/* Size (in bytes), 32-byte aligned */
     22	unsigned long direction;	/* Transfer direction */
     23	unsigned long ctrl;		/* Transfer control */
     24	unsigned long chan_enable;	/* Channel enable */
     25	unsigned long xfer_enable;	/* Transfer enable */
     26	unsigned long xfer_stat;	/* Transfer status */
     27} __attribute__ ((aligned(32)));
     28
     29struct g2_status {
     30	unsigned long g2_addr;
     31	unsigned long root_addr;
     32	unsigned long size;
     33	unsigned long status;
     34} __attribute__ ((aligned(16)));
     35
     36struct g2_dma_info {
     37	struct g2_channel channel[G2_NR_DMA_CHANNELS];
     38	unsigned long pad1[G2_NR_DMA_CHANNELS];
     39	unsigned long wait_state;
     40	unsigned long pad2[10];
     41	unsigned long magic;
     42	struct g2_status status[G2_NR_DMA_CHANNELS];
     43} __attribute__ ((aligned(256)));
     44
     45static volatile struct g2_dma_info *g2_dma = (volatile struct g2_dma_info *)0xa05f7800;
     46
     47#define g2_bytes_remaining(i) \
     48	((g2_dma->channel[i].size - \
     49	  g2_dma->status[i].size) & 0x0fffffff)
     50
     51static irqreturn_t g2_dma_interrupt(int irq, void *dev_id)
     52{
     53	int i;
     54
     55	for (i = 0; i < G2_NR_DMA_CHANNELS; i++) {
     56		if (g2_dma->status[i].status & 0x20000000) {
     57			unsigned int bytes = g2_bytes_remaining(i);
     58
     59			if (likely(bytes == 0)) {
     60				struct dma_info *info = dev_id;
     61				struct dma_channel *chan = info->channels + i;
     62
     63				wake_up(&chan->wait_queue);
     64
     65				return IRQ_HANDLED;
     66			}
     67		}
     68	}
     69
     70	return IRQ_NONE;
     71}
     72
     73static int g2_enable_dma(struct dma_channel *chan)
     74{
     75	unsigned int chan_nr = chan->chan;
     76
     77	g2_dma->channel[chan_nr].chan_enable = 1;
     78	g2_dma->channel[chan_nr].xfer_enable = 1;
     79
     80	return 0;
     81}
     82
     83static int g2_disable_dma(struct dma_channel *chan)
     84{
     85	unsigned int chan_nr = chan->chan;
     86
     87	g2_dma->channel[chan_nr].chan_enable = 0;
     88	g2_dma->channel[chan_nr].xfer_enable = 0;
     89
     90	return 0;
     91}
     92
     93static int g2_xfer_dma(struct dma_channel *chan)
     94{
     95	unsigned int chan_nr = chan->chan;
     96
     97	if (chan->sar & 31) {
     98		printk("g2dma: unaligned source 0x%lx\n", chan->sar);
     99		return -EINVAL;
    100	}
    101
    102	if (chan->dar & 31) {
    103		printk("g2dma: unaligned dest 0x%lx\n", chan->dar);
    104		return -EINVAL;
    105	}
    106
    107	/* Align the count */
    108	if (chan->count & 31)
    109		chan->count = (chan->count + (32 - 1)) & ~(32 - 1);
    110
    111	/* Fixup destination */
    112	chan->dar += 0xa0800000;
    113
    114	/* Fixup direction */
    115	chan->mode = !chan->mode;
    116
    117	flush_icache_range((unsigned long)chan->sar, chan->count);
    118
    119	g2_disable_dma(chan);
    120
    121	g2_dma->channel[chan_nr].g2_addr   = chan->dar & 0x1fffffe0;
    122	g2_dma->channel[chan_nr].root_addr = chan->sar & 0x1fffffe0;
    123	g2_dma->channel[chan_nr].size	   = (chan->count & ~31) | 0x80000000;
    124	g2_dma->channel[chan_nr].direction = chan->mode;
    125
    126	/*
    127	 * bit 0 - ???
    128	 * bit 1 - if set, generate a hardware event on transfer completion
    129	 * bit 2 - ??? something to do with suspend?
    130	 */
    131	g2_dma->channel[chan_nr].ctrl	= 5; /* ?? */
    132
    133	g2_enable_dma(chan);
    134
    135	/* debug cruft */
    136	pr_debug("count, sar, dar, mode, ctrl, chan, xfer: %ld, 0x%08lx, "
    137		 "0x%08lx, %ld, %ld, %ld, %ld\n",
    138		 g2_dma->channel[chan_nr].size,
    139		 g2_dma->channel[chan_nr].root_addr,
    140		 g2_dma->channel[chan_nr].g2_addr,
    141		 g2_dma->channel[chan_nr].direction,
    142		 g2_dma->channel[chan_nr].ctrl,
    143		 g2_dma->channel[chan_nr].chan_enable,
    144		 g2_dma->channel[chan_nr].xfer_enable);
    145
    146	return 0;
    147}
    148
    149static int g2_get_residue(struct dma_channel *chan)
    150{
    151	return g2_bytes_remaining(chan->chan);
    152}
    153
    154static struct dma_ops g2_dma_ops = {
    155	.xfer		= g2_xfer_dma,
    156	.get_residue	= g2_get_residue,
    157};
    158
    159static struct dma_info g2_dma_info = {
    160	.name		= "g2_dmac",
    161	.nr_channels	= 4,
    162	.ops		= &g2_dma_ops,
    163	.flags		= DMAC_CHANNELS_TEI_CAPABLE,
    164};
    165
    166static int __init g2_dma_init(void)
    167{
    168	int ret;
    169
    170	ret = request_irq(HW_EVENT_G2_DMA, g2_dma_interrupt, 0,
    171			  "g2 DMA handler", &g2_dma_info);
    172	if (unlikely(ret))
    173		return -EINVAL;
    174
    175	/* Magic */
    176	g2_dma->wait_state	= 27;
    177	g2_dma->magic		= 0x4659404f;
    178
    179	ret = register_dmac(&g2_dma_info);
    180	if (unlikely(ret != 0))
    181		free_irq(HW_EVENT_G2_DMA, &g2_dma_info);
    182
    183	return ret;
    184}
    185
    186static void __exit g2_dma_exit(void)
    187{
    188	free_irq(HW_EVENT_G2_DMA, &g2_dma_info);
    189	unregister_dmac(&g2_dma_info);
    190}
    191
    192subsys_initcall(g2_dma_init);
    193module_exit(g2_dma_exit);
    194
    195MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
    196MODULE_DESCRIPTION("G2 bus DMA driver");
    197MODULE_LICENSE("GPL v2");