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

isadma.c (3221B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  ISA DMA support functions
      4 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
      5 */
      6
      7/*
      8 * Defining following add some delay. Maybe this helps for some broken
      9 * ISA DMA controllers.
     10 */
     11
     12#undef HAVE_REALLY_SLOW_DMA_CONTROLLER
     13
     14#include <linux/export.h>
     15#include <sound/core.h>
     16#include <asm/dma.h>
     17
     18/**
     19 * snd_dma_program - program an ISA DMA transfer
     20 * @dma: the dma number
     21 * @addr: the physical address of the buffer
     22 * @size: the DMA transfer size
     23 * @mode: the DMA transfer mode, DMA_MODE_XXX
     24 *
     25 * Programs an ISA DMA transfer for the given buffer.
     26 */
     27void snd_dma_program(unsigned long dma,
     28		     unsigned long addr, unsigned int size,
     29                     unsigned short mode)
     30{
     31	unsigned long flags;
     32
     33	flags = claim_dma_lock();
     34	disable_dma(dma);
     35	clear_dma_ff(dma);
     36	set_dma_mode(dma, mode);
     37	set_dma_addr(dma, addr);
     38	set_dma_count(dma, size);
     39	if (!(mode & DMA_MODE_NO_ENABLE))
     40		enable_dma(dma);
     41	release_dma_lock(flags);
     42}
     43EXPORT_SYMBOL(snd_dma_program);
     44
     45/**
     46 * snd_dma_disable - stop the ISA DMA transfer
     47 * @dma: the dma number
     48 *
     49 * Stops the ISA DMA transfer.
     50 */
     51void snd_dma_disable(unsigned long dma)
     52{
     53	unsigned long flags;
     54
     55	flags = claim_dma_lock();
     56	clear_dma_ff(dma);
     57	disable_dma(dma);
     58	release_dma_lock(flags);
     59}
     60EXPORT_SYMBOL(snd_dma_disable);
     61
     62/**
     63 * snd_dma_pointer - return the current pointer to DMA transfer buffer in bytes
     64 * @dma: the dma number
     65 * @size: the dma transfer size
     66 *
     67 * Return: The current pointer in DMA transfer buffer in bytes.
     68 */
     69unsigned int snd_dma_pointer(unsigned long dma, unsigned int size)
     70{
     71	unsigned long flags;
     72	unsigned int result, result1;
     73
     74	flags = claim_dma_lock();
     75	clear_dma_ff(dma);
     76	if (!isa_dma_bridge_buggy)
     77		disable_dma(dma);
     78	result = get_dma_residue(dma);
     79	/*
     80	 * HACK - read the counter again and choose higher value in order to
     81	 * avoid reading during counter lower byte roll over if the
     82	 * isa_dma_bridge_buggy is set.
     83	 */
     84	result1 = get_dma_residue(dma);
     85	if (!isa_dma_bridge_buggy)
     86		enable_dma(dma);
     87	release_dma_lock(flags);
     88	if (unlikely(result < result1))
     89		result = result1;
     90#ifdef CONFIG_SND_DEBUG
     91	if (result > size)
     92		pr_err("ALSA: pointer (0x%x) for DMA #%ld is greater than transfer size (0x%x)\n", result, dma, size);
     93#endif
     94	if (result >= size || result == 0)
     95		return 0;
     96	else
     97		return size - result;
     98}
     99EXPORT_SYMBOL(snd_dma_pointer);
    100
    101struct snd_dma_data {
    102	int dma;
    103};
    104
    105static void __snd_release_dma(struct device *dev, void *data)
    106{
    107	struct snd_dma_data *p = data;
    108
    109	snd_dma_disable(p->dma);
    110	free_dma(p->dma);
    111}
    112
    113/**
    114 * snd_devm_request_dma - the managed version of request_dma()
    115 * @dev: the device pointer
    116 * @dma: the dma number
    117 * @name: the name string of the requester
    118 *
    119 * Returns zero on success, or a negative error code.
    120 * The requested DMA will be automatically released at unbinding via devres.
    121 */
    122int snd_devm_request_dma(struct device *dev, int dma, const char *name)
    123{
    124	struct snd_dma_data *p;
    125
    126	if (request_dma(dma, name))
    127		return -EBUSY;
    128	p = devres_alloc(__snd_release_dma, sizeof(*p), GFP_KERNEL);
    129	if (!p) {
    130		free_dma(dma);
    131		return -ENOMEM;
    132	}
    133	p->dma = dma;
    134	devres_add(dev, p);
    135	return 0;
    136}
    137EXPORT_SYMBOL_GPL(snd_devm_request_dma);