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

gus_dma.c (6447B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Routines for GF1 DMA control
      4 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
      5 */
      6
      7#include <asm/dma.h>
      8#include <linux/slab.h>
      9#include <sound/core.h>
     10#include <sound/gus.h>
     11
     12static void snd_gf1_dma_ack(struct snd_gus_card * gus)
     13{
     14	unsigned long flags;
     15
     16	spin_lock_irqsave(&gus->reg_lock, flags);
     17	snd_gf1_write8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL, 0x00);
     18	snd_gf1_look8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL);
     19	spin_unlock_irqrestore(&gus->reg_lock, flags);
     20}
     21
     22static void snd_gf1_dma_program(struct snd_gus_card * gus,
     23				unsigned int addr,
     24				unsigned long buf_addr,
     25				unsigned int count,
     26				unsigned int cmd)
     27{
     28	unsigned long flags;
     29	unsigned int address;
     30	unsigned char dma_cmd;
     31	unsigned int address_high;
     32
     33	snd_printdd("dma_transfer: addr=0x%x, buf=0x%lx, count=0x%x\n",
     34		    addr, buf_addr, count);
     35
     36	if (gus->gf1.dma1 > 3) {
     37		if (gus->gf1.enh_mode) {
     38			address = addr >> 1;
     39		} else {
     40			if (addr & 0x1f) {
     41				snd_printd("snd_gf1_dma_transfer: unaligned address (0x%x)?\n", addr);
     42				return;
     43			}
     44			address = (addr & 0x000c0000) | ((addr & 0x0003ffff) >> 1);
     45		}
     46	} else {
     47		address = addr;
     48	}
     49
     50	dma_cmd = SNDRV_GF1_DMA_ENABLE | (unsigned short) cmd;
     51#if 0
     52	dma_cmd |= 0x08;
     53#endif
     54	if (dma_cmd & SNDRV_GF1_DMA_16BIT) {
     55		count++;
     56		count &= ~1;	/* align */
     57	}
     58	if (gus->gf1.dma1 > 3) {
     59		dma_cmd |= SNDRV_GF1_DMA_WIDTH16;
     60		count++;
     61		count &= ~1;	/* align */
     62	}
     63	snd_gf1_dma_ack(gus);
     64	snd_dma_program(gus->gf1.dma1, buf_addr, count, dma_cmd & SNDRV_GF1_DMA_READ ? DMA_MODE_READ : DMA_MODE_WRITE);
     65#if 0
     66	snd_printk(KERN_DEBUG "address = 0x%x, count = 0x%x, dma_cmd = 0x%x\n",
     67		   address << 1, count, dma_cmd);
     68#endif
     69	spin_lock_irqsave(&gus->reg_lock, flags);
     70	if (gus->gf1.enh_mode) {
     71		address_high = ((address >> 16) & 0x000000f0) | (address & 0x0000000f);
     72		snd_gf1_write16(gus, SNDRV_GF1_GW_DRAM_DMA_LOW, (unsigned short) (address >> 4));
     73		snd_gf1_write8(gus, SNDRV_GF1_GB_DRAM_DMA_HIGH, (unsigned char) address_high);
     74	} else
     75		snd_gf1_write16(gus, SNDRV_GF1_GW_DRAM_DMA_LOW, (unsigned short) (address >> 4));
     76	snd_gf1_write8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL, dma_cmd);
     77	spin_unlock_irqrestore(&gus->reg_lock, flags);
     78}
     79
     80static struct snd_gf1_dma_block *snd_gf1_dma_next_block(struct snd_gus_card * gus)
     81{
     82	struct snd_gf1_dma_block *block;
     83
     84	/* PCM block have bigger priority than synthesizer one */
     85	if (gus->gf1.dma_data_pcm) {
     86		block = gus->gf1.dma_data_pcm;
     87		if (gus->gf1.dma_data_pcm_last == block) {
     88			gus->gf1.dma_data_pcm =
     89			gus->gf1.dma_data_pcm_last = NULL;
     90		} else {
     91			gus->gf1.dma_data_pcm = block->next;
     92		}
     93	} else if (gus->gf1.dma_data_synth) {
     94		block = gus->gf1.dma_data_synth;
     95		if (gus->gf1.dma_data_synth_last == block) {
     96			gus->gf1.dma_data_synth =
     97			gus->gf1.dma_data_synth_last = NULL;
     98		} else {
     99			gus->gf1.dma_data_synth = block->next;
    100		}
    101	} else {
    102		block = NULL;
    103	}
    104	if (block) {
    105		gus->gf1.dma_ack = block->ack;
    106		gus->gf1.dma_private_data = block->private_data;
    107	}
    108	return block;
    109}
    110
    111
    112static void snd_gf1_dma_interrupt(struct snd_gus_card * gus)
    113{
    114	struct snd_gf1_dma_block *block;
    115
    116	snd_gf1_dma_ack(gus);
    117	if (gus->gf1.dma_ack)
    118		gus->gf1.dma_ack(gus, gus->gf1.dma_private_data);
    119	spin_lock(&gus->dma_lock);
    120	if (gus->gf1.dma_data_pcm == NULL &&
    121	    gus->gf1.dma_data_synth == NULL) {
    122	    	gus->gf1.dma_ack = NULL;
    123		gus->gf1.dma_flags &= ~SNDRV_GF1_DMA_TRIGGER;
    124		spin_unlock(&gus->dma_lock);
    125		return;
    126	}
    127	block = snd_gf1_dma_next_block(gus);
    128	spin_unlock(&gus->dma_lock);
    129	if (!block)
    130		return;
    131	snd_gf1_dma_program(gus, block->addr, block->buf_addr, block->count, (unsigned short) block->cmd);
    132	kfree(block);
    133#if 0
    134	snd_printd(KERN_DEBUG "program dma (IRQ) - "
    135		   "addr = 0x%x, buffer = 0x%lx, count = 0x%x, cmd = 0x%x\n",
    136		   block->addr, block->buf_addr, block->count, block->cmd);
    137#endif
    138}
    139
    140int snd_gf1_dma_init(struct snd_gus_card * gus)
    141{
    142	mutex_lock(&gus->dma_mutex);
    143	gus->gf1.dma_shared++;
    144	if (gus->gf1.dma_shared > 1) {
    145		mutex_unlock(&gus->dma_mutex);
    146		return 0;
    147	}
    148	gus->gf1.interrupt_handler_dma_write = snd_gf1_dma_interrupt;
    149	gus->gf1.dma_data_pcm = 
    150	gus->gf1.dma_data_pcm_last =
    151	gus->gf1.dma_data_synth = 
    152	gus->gf1.dma_data_synth_last = NULL;
    153	mutex_unlock(&gus->dma_mutex);
    154	return 0;
    155}
    156
    157int snd_gf1_dma_done(struct snd_gus_card * gus)
    158{
    159	struct snd_gf1_dma_block *block;
    160
    161	mutex_lock(&gus->dma_mutex);
    162	gus->gf1.dma_shared--;
    163	if (!gus->gf1.dma_shared) {
    164		snd_dma_disable(gus->gf1.dma1);
    165		snd_gf1_set_default_handlers(gus, SNDRV_GF1_HANDLER_DMA_WRITE);
    166		snd_gf1_dma_ack(gus);
    167		while ((block = gus->gf1.dma_data_pcm)) {
    168			gus->gf1.dma_data_pcm = block->next;
    169			kfree(block);
    170		}
    171		while ((block = gus->gf1.dma_data_synth)) {
    172			gus->gf1.dma_data_synth = block->next;
    173			kfree(block);
    174		}
    175		gus->gf1.dma_data_pcm_last =
    176		gus->gf1.dma_data_synth_last = NULL;
    177	}
    178	mutex_unlock(&gus->dma_mutex);
    179	return 0;
    180}
    181
    182int snd_gf1_dma_transfer_block(struct snd_gus_card * gus,
    183			       struct snd_gf1_dma_block * __block,
    184			       int atomic,
    185			       int synth)
    186{
    187	unsigned long flags;
    188	struct snd_gf1_dma_block *block;
    189
    190	block = kmalloc(sizeof(*block), atomic ? GFP_ATOMIC : GFP_KERNEL);
    191	if (!block)
    192		return -ENOMEM;
    193
    194	*block = *__block;
    195	block->next = NULL;
    196
    197	snd_printdd("addr = 0x%x, buffer = 0x%lx, count = 0x%x, cmd = 0x%x\n",
    198		    block->addr, (long) block->buffer, block->count,
    199		    block->cmd);
    200
    201	snd_printdd("gus->gf1.dma_data_pcm_last = 0x%lx\n",
    202		    (long)gus->gf1.dma_data_pcm_last);
    203	snd_printdd("gus->gf1.dma_data_pcm = 0x%lx\n",
    204		    (long)gus->gf1.dma_data_pcm);
    205
    206	spin_lock_irqsave(&gus->dma_lock, flags);
    207	if (synth) {
    208		if (gus->gf1.dma_data_synth_last) {
    209			gus->gf1.dma_data_synth_last->next = block;
    210			gus->gf1.dma_data_synth_last = block;
    211		} else {
    212			gus->gf1.dma_data_synth = 
    213			gus->gf1.dma_data_synth_last = block;
    214		}
    215	} else {
    216		if (gus->gf1.dma_data_pcm_last) {
    217			gus->gf1.dma_data_pcm_last->next = block;
    218			gus->gf1.dma_data_pcm_last = block;
    219		} else {
    220			gus->gf1.dma_data_pcm = 
    221			gus->gf1.dma_data_pcm_last = block;
    222		}
    223	}
    224	if (!(gus->gf1.dma_flags & SNDRV_GF1_DMA_TRIGGER)) {
    225		gus->gf1.dma_flags |= SNDRV_GF1_DMA_TRIGGER;
    226		block = snd_gf1_dma_next_block(gus);
    227		spin_unlock_irqrestore(&gus->dma_lock, flags);
    228		if (block == NULL)
    229			return 0;
    230		snd_gf1_dma_program(gus, block->addr, block->buf_addr, block->count, (unsigned short) block->cmd);
    231		kfree(block);
    232		return 0;
    233	}
    234	spin_unlock_irqrestore(&gus->dma_lock, flags);
    235	return 0;
    236}