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

ebus.c (5995B)


      1// SPDX-License-Identifier: GPL-2.0
      2/* ebus.c: EBUS DMA library code.
      3 *
      4 * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
      5 * Copyright (C) 1999  David S. Miller (davem@redhat.com)
      6 */
      7
      8#include <linux/export.h>
      9#include <linux/kernel.h>
     10#include <linux/types.h>
     11#include <linux/interrupt.h>
     12#include <linux/delay.h>
     13
     14#include <asm/ebus_dma.h>
     15#include <asm/io.h>
     16
     17#define EBDMA_CSR	0x00UL	/* Control/Status */
     18#define EBDMA_ADDR	0x04UL	/* DMA Address */
     19#define EBDMA_COUNT	0x08UL	/* DMA Count */
     20
     21#define EBDMA_CSR_INT_PEND	0x00000001
     22#define EBDMA_CSR_ERR_PEND	0x00000002
     23#define EBDMA_CSR_DRAIN		0x00000004
     24#define EBDMA_CSR_INT_EN	0x00000010
     25#define EBDMA_CSR_RESET		0x00000080
     26#define EBDMA_CSR_WRITE		0x00000100
     27#define EBDMA_CSR_EN_DMA	0x00000200
     28#define EBDMA_CSR_CYC_PEND	0x00000400
     29#define EBDMA_CSR_DIAG_RD_DONE	0x00000800
     30#define EBDMA_CSR_DIAG_WR_DONE	0x00001000
     31#define EBDMA_CSR_EN_CNT	0x00002000
     32#define EBDMA_CSR_TC		0x00004000
     33#define EBDMA_CSR_DIS_CSR_DRN	0x00010000
     34#define EBDMA_CSR_BURST_SZ_MASK	0x000c0000
     35#define EBDMA_CSR_BURST_SZ_1	0x00080000
     36#define EBDMA_CSR_BURST_SZ_4	0x00000000
     37#define EBDMA_CSR_BURST_SZ_8	0x00040000
     38#define EBDMA_CSR_BURST_SZ_16	0x000c0000
     39#define EBDMA_CSR_DIAG_EN	0x00100000
     40#define EBDMA_CSR_DIS_ERR_PEND	0x00400000
     41#define EBDMA_CSR_TCI_DIS	0x00800000
     42#define EBDMA_CSR_EN_NEXT	0x01000000
     43#define EBDMA_CSR_DMA_ON	0x02000000
     44#define EBDMA_CSR_A_LOADED	0x04000000
     45#define EBDMA_CSR_NA_LOADED	0x08000000
     46#define EBDMA_CSR_DEV_ID_MASK	0xf0000000
     47
     48#define EBUS_DMA_RESET_TIMEOUT	10000
     49
     50static void __ebus_dma_reset(struct ebus_dma_info *p, int no_drain)
     51{
     52	int i;
     53	u32 val = 0;
     54
     55	writel(EBDMA_CSR_RESET, p->regs + EBDMA_CSR);
     56	udelay(1);
     57
     58	if (no_drain)
     59		return;
     60
     61	for (i = EBUS_DMA_RESET_TIMEOUT; i > 0; i--) {
     62		val = readl(p->regs + EBDMA_CSR);
     63
     64		if (!(val & (EBDMA_CSR_DRAIN | EBDMA_CSR_CYC_PEND)))
     65			break;
     66		udelay(10);
     67	}
     68}
     69
     70static irqreturn_t ebus_dma_irq(int irq, void *dev_id)
     71{
     72	struct ebus_dma_info *p = dev_id;
     73	unsigned long flags;
     74	u32 csr = 0;
     75
     76	spin_lock_irqsave(&p->lock, flags);
     77	csr = readl(p->regs + EBDMA_CSR);
     78	writel(csr, p->regs + EBDMA_CSR);
     79	spin_unlock_irqrestore(&p->lock, flags);
     80
     81	if (csr & EBDMA_CSR_ERR_PEND) {
     82		printk(KERN_CRIT "ebus_dma(%s): DMA error!\n", p->name);
     83		p->callback(p, EBUS_DMA_EVENT_ERROR, p->client_cookie);
     84		return IRQ_HANDLED;
     85	} else if (csr & EBDMA_CSR_INT_PEND) {
     86		p->callback(p,
     87			    (csr & EBDMA_CSR_TC) ?
     88			    EBUS_DMA_EVENT_DMA : EBUS_DMA_EVENT_DEVICE,
     89			    p->client_cookie);
     90		return IRQ_HANDLED;
     91	}
     92
     93	return IRQ_NONE;
     94
     95}
     96
     97int ebus_dma_register(struct ebus_dma_info *p)
     98{
     99	u32 csr;
    100
    101	if (!p->regs)
    102		return -EINVAL;
    103	if (p->flags & ~(EBUS_DMA_FLAG_USE_EBDMA_HANDLER |
    104			 EBUS_DMA_FLAG_TCI_DISABLE))
    105		return -EINVAL;
    106	if ((p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) && !p->callback)
    107		return -EINVAL;
    108	if (!strlen(p->name))
    109		return -EINVAL;
    110
    111	__ebus_dma_reset(p, 1);
    112
    113	csr = EBDMA_CSR_BURST_SZ_16 | EBDMA_CSR_EN_CNT;
    114
    115	if (p->flags & EBUS_DMA_FLAG_TCI_DISABLE)
    116		csr |= EBDMA_CSR_TCI_DIS;
    117
    118	writel(csr, p->regs + EBDMA_CSR);
    119
    120	return 0;
    121}
    122EXPORT_SYMBOL(ebus_dma_register);
    123
    124int ebus_dma_irq_enable(struct ebus_dma_info *p, int on)
    125{
    126	unsigned long flags;
    127	u32 csr;
    128
    129	if (on) {
    130		if (p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) {
    131			if (request_irq(p->irq, ebus_dma_irq, IRQF_SHARED, p->name, p))
    132				return -EBUSY;
    133		}
    134
    135		spin_lock_irqsave(&p->lock, flags);
    136		csr = readl(p->regs + EBDMA_CSR);
    137		csr |= EBDMA_CSR_INT_EN;
    138		writel(csr, p->regs + EBDMA_CSR);
    139		spin_unlock_irqrestore(&p->lock, flags);
    140	} else {
    141		spin_lock_irqsave(&p->lock, flags);
    142		csr = readl(p->regs + EBDMA_CSR);
    143		csr &= ~EBDMA_CSR_INT_EN;
    144		writel(csr, p->regs + EBDMA_CSR);
    145		spin_unlock_irqrestore(&p->lock, flags);
    146
    147		if (p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) {
    148			free_irq(p->irq, p);
    149		}
    150	}
    151
    152	return 0;
    153}
    154EXPORT_SYMBOL(ebus_dma_irq_enable);
    155
    156void ebus_dma_unregister(struct ebus_dma_info *p)
    157{
    158	unsigned long flags;
    159	u32 csr;
    160	int irq_on = 0;
    161
    162	spin_lock_irqsave(&p->lock, flags);
    163	csr = readl(p->regs + EBDMA_CSR);
    164	if (csr & EBDMA_CSR_INT_EN) {
    165		csr &= ~EBDMA_CSR_INT_EN;
    166		writel(csr, p->regs + EBDMA_CSR);
    167		irq_on = 1;
    168	}
    169	spin_unlock_irqrestore(&p->lock, flags);
    170
    171	if (irq_on)
    172		free_irq(p->irq, p);
    173}
    174EXPORT_SYMBOL(ebus_dma_unregister);
    175
    176int ebus_dma_request(struct ebus_dma_info *p, dma_addr_t bus_addr, size_t len)
    177{
    178	unsigned long flags;
    179	u32 csr;
    180	int err;
    181
    182	if (len >= (1 << 24))
    183		return -EINVAL;
    184
    185	spin_lock_irqsave(&p->lock, flags);
    186	csr = readl(p->regs + EBDMA_CSR);
    187	err = -EINVAL;
    188	if (!(csr & EBDMA_CSR_EN_DMA))
    189		goto out;
    190	err = -EBUSY;
    191	if (csr & EBDMA_CSR_NA_LOADED)
    192		goto out;
    193
    194	writel(len,      p->regs + EBDMA_COUNT);
    195	writel(bus_addr, p->regs + EBDMA_ADDR);
    196	err = 0;
    197
    198out:
    199	spin_unlock_irqrestore(&p->lock, flags);
    200
    201	return err;
    202}
    203EXPORT_SYMBOL(ebus_dma_request);
    204
    205void ebus_dma_prepare(struct ebus_dma_info *p, int write)
    206{
    207	unsigned long flags;
    208	u32 csr;
    209
    210	spin_lock_irqsave(&p->lock, flags);
    211	__ebus_dma_reset(p, 0);
    212
    213	csr = (EBDMA_CSR_INT_EN |
    214	       EBDMA_CSR_EN_CNT |
    215	       EBDMA_CSR_BURST_SZ_16 |
    216	       EBDMA_CSR_EN_NEXT);
    217
    218	if (write)
    219		csr |= EBDMA_CSR_WRITE;
    220	if (p->flags & EBUS_DMA_FLAG_TCI_DISABLE)
    221		csr |= EBDMA_CSR_TCI_DIS;
    222
    223	writel(csr, p->regs + EBDMA_CSR);
    224
    225	spin_unlock_irqrestore(&p->lock, flags);
    226}
    227EXPORT_SYMBOL(ebus_dma_prepare);
    228
    229unsigned int ebus_dma_residue(struct ebus_dma_info *p)
    230{
    231	return readl(p->regs + EBDMA_COUNT);
    232}
    233EXPORT_SYMBOL(ebus_dma_residue);
    234
    235unsigned int ebus_dma_addr(struct ebus_dma_info *p)
    236{
    237	return readl(p->regs + EBDMA_ADDR);
    238}
    239EXPORT_SYMBOL(ebus_dma_addr);
    240
    241void ebus_dma_enable(struct ebus_dma_info *p, int on)
    242{
    243	unsigned long flags;
    244	u32 orig_csr, csr;
    245
    246	spin_lock_irqsave(&p->lock, flags);
    247	orig_csr = csr = readl(p->regs + EBDMA_CSR);
    248	if (on)
    249		csr |= EBDMA_CSR_EN_DMA;
    250	else
    251		csr &= ~EBDMA_CSR_EN_DMA;
    252	if ((orig_csr & EBDMA_CSR_EN_DMA) !=
    253	    (csr & EBDMA_CSR_EN_DMA))
    254		writel(csr, p->regs + EBDMA_CSR);
    255	spin_unlock_irqrestore(&p->lock, flags);
    256}
    257EXPORT_SYMBOL(ebus_dma_enable);