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

sun3x_esp.c (6479B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/* sun3x_esp.c: ESP front-end for Sun3x systems.
      3 *
      4 * Copyright (C) 2007,2008 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
      5 */
      6
      7#include <linux/kernel.h>
      8#include <linux/gfp.h>
      9#include <linux/types.h>
     10#include <linux/delay.h>
     11#include <linux/module.h>
     12#include <linux/init.h>
     13#include <linux/platform_device.h>
     14#include <linux/dma-mapping.h>
     15#include <linux/interrupt.h>
     16#include <linux/io.h>
     17
     18#include <asm/sun3x.h>
     19#include <asm/dma.h>
     20#include <asm/dvma.h>
     21
     22/* DMA controller reg offsets */
     23#define DMA_CSR		0x00UL	/* rw  DMA control/status register    0x00   */
     24#define DMA_ADDR        0x04UL	/* rw  DMA transfer address register  0x04   */
     25#define DMA_COUNT       0x08UL	/* rw  DMA transfer count register    0x08   */
     26#define DMA_TEST        0x0cUL	/* rw  DMA test/debug register        0x0c   */
     27
     28#include <scsi/scsi_host.h>
     29
     30#include "esp_scsi.h"
     31
     32#define DRV_MODULE_NAME		"sun3x_esp"
     33#define PFX DRV_MODULE_NAME	": "
     34#define DRV_VERSION		"1.000"
     35#define DRV_MODULE_RELDATE	"Nov 1, 2007"
     36
     37/*
     38 * m68k always assumes readl/writel operate on little endian
     39 * mmio space; this is wrong at least for Sun3x, so we
     40 * need to workaround this until a proper way is found
     41 */
     42#if 0
     43#define dma_read32(REG) \
     44	readl(esp->dma_regs + (REG))
     45#define dma_write32(VAL, REG) \
     46	writel((VAL), esp->dma_regs + (REG))
     47#else
     48#define dma_read32(REG) \
     49	*(volatile u32 *)(esp->dma_regs + (REG))
     50#define dma_write32(VAL, REG) \
     51	do { *(volatile u32 *)(esp->dma_regs + (REG)) = (VAL); } while (0)
     52#endif
     53
     54static void sun3x_esp_write8(struct esp *esp, u8 val, unsigned long reg)
     55{
     56	writeb(val, esp->regs + (reg * 4UL));
     57}
     58
     59static u8 sun3x_esp_read8(struct esp *esp, unsigned long reg)
     60{
     61	return readb(esp->regs + (reg * 4UL));
     62}
     63
     64static int sun3x_esp_irq_pending(struct esp *esp)
     65{
     66	if (dma_read32(DMA_CSR) & (DMA_HNDL_INTR | DMA_HNDL_ERROR))
     67		return 1;
     68	return 0;
     69}
     70
     71static void sun3x_esp_reset_dma(struct esp *esp)
     72{
     73	u32 val;
     74
     75	val = dma_read32(DMA_CSR);
     76	dma_write32(val | DMA_RST_SCSI, DMA_CSR);
     77	dma_write32(val & ~DMA_RST_SCSI, DMA_CSR);
     78
     79	/* Enable interrupts.  */
     80	val = dma_read32(DMA_CSR);
     81	dma_write32(val | DMA_INT_ENAB, DMA_CSR);
     82}
     83
     84static void sun3x_esp_dma_drain(struct esp *esp)
     85{
     86	u32 csr;
     87	int lim;
     88
     89	csr = dma_read32(DMA_CSR);
     90	if (!(csr & DMA_FIFO_ISDRAIN))
     91		return;
     92
     93	dma_write32(csr | DMA_FIFO_STDRAIN, DMA_CSR);
     94
     95	lim = 1000;
     96	while (dma_read32(DMA_CSR) & DMA_FIFO_ISDRAIN) {
     97		if (--lim == 0) {
     98			printk(KERN_ALERT PFX "esp%d: DMA will not drain!\n",
     99			       esp->host->unique_id);
    100			break;
    101		}
    102		udelay(1);
    103	}
    104}
    105
    106static void sun3x_esp_dma_invalidate(struct esp *esp)
    107{
    108	u32 val;
    109	int lim;
    110
    111	lim = 1000;
    112	while ((val = dma_read32(DMA_CSR)) & DMA_PEND_READ) {
    113		if (--lim == 0) {
    114			printk(KERN_ALERT PFX "esp%d: DMA will not "
    115			       "invalidate!\n", esp->host->unique_id);
    116			break;
    117		}
    118		udelay(1);
    119	}
    120
    121	val &= ~(DMA_ENABLE | DMA_ST_WRITE | DMA_BCNT_ENAB);
    122	val |= DMA_FIFO_INV;
    123	dma_write32(val, DMA_CSR);
    124	val &= ~DMA_FIFO_INV;
    125	dma_write32(val, DMA_CSR);
    126}
    127
    128static void sun3x_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count,
    129				  u32 dma_count, int write, u8 cmd)
    130{
    131	u32 csr;
    132
    133	BUG_ON(!(cmd & ESP_CMD_DMA));
    134
    135	sun3x_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);
    136	sun3x_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);
    137	csr = dma_read32(DMA_CSR);
    138	csr |= DMA_ENABLE;
    139	if (write)
    140		csr |= DMA_ST_WRITE;
    141	else
    142		csr &= ~DMA_ST_WRITE;
    143	dma_write32(csr, DMA_CSR);
    144	dma_write32(addr, DMA_ADDR);
    145
    146	scsi_esp_cmd(esp, cmd);
    147}
    148
    149static int sun3x_esp_dma_error(struct esp *esp)
    150{
    151	u32 csr = dma_read32(DMA_CSR);
    152
    153	if (csr & DMA_HNDL_ERROR)
    154		return 1;
    155
    156	return 0;
    157}
    158
    159static const struct esp_driver_ops sun3x_esp_ops = {
    160	.esp_write8	=	sun3x_esp_write8,
    161	.esp_read8	=	sun3x_esp_read8,
    162	.irq_pending	=	sun3x_esp_irq_pending,
    163	.reset_dma	=	sun3x_esp_reset_dma,
    164	.dma_drain	=	sun3x_esp_dma_drain,
    165	.dma_invalidate	=	sun3x_esp_dma_invalidate,
    166	.send_dma_cmd	=	sun3x_esp_send_dma_cmd,
    167	.dma_error	=	sun3x_esp_dma_error,
    168};
    169
    170static int esp_sun3x_probe(struct platform_device *dev)
    171{
    172	struct scsi_host_template *tpnt = &scsi_esp_template;
    173	struct Scsi_Host *host;
    174	struct esp *esp;
    175	struct resource *res;
    176	int err = -ENOMEM;
    177
    178	host = scsi_host_alloc(tpnt, sizeof(struct esp));
    179	if (!host)
    180		goto fail;
    181
    182	host->max_id = 8;
    183	esp = shost_priv(host);
    184
    185	esp->host = host;
    186	esp->dev = &dev->dev;
    187	esp->ops = &sun3x_esp_ops;
    188
    189	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
    190	if (!res || !res->start)
    191		goto fail_unlink;
    192
    193	esp->regs = ioremap(res->start, 0x20);
    194	if (!esp->regs)
    195		goto fail_unmap_regs;
    196
    197	res = platform_get_resource(dev, IORESOURCE_MEM, 1);
    198	if (!res || !res->start)
    199		goto fail_unmap_regs;
    200
    201	esp->dma_regs = ioremap(res->start, 0x10);
    202
    203	esp->command_block = dma_alloc_coherent(esp->dev, 16,
    204						&esp->command_block_dma,
    205						GFP_KERNEL);
    206	if (!esp->command_block)
    207		goto fail_unmap_regs_dma;
    208
    209	host->irq = err = platform_get_irq(dev, 0);
    210	if (err < 0)
    211		goto fail_unmap_command_block;
    212	err = request_irq(host->irq, scsi_esp_intr, IRQF_SHARED,
    213			  "SUN3X ESP", esp);
    214	if (err < 0)
    215		goto fail_unmap_command_block;
    216
    217	esp->scsi_id = 7;
    218	esp->host->this_id = esp->scsi_id;
    219	esp->scsi_id_mask = (1 << esp->scsi_id);
    220	esp->cfreq = 20000000;
    221
    222	dev_set_drvdata(&dev->dev, esp);
    223
    224	err = scsi_esp_register(esp);
    225	if (err)
    226		goto fail_free_irq;
    227
    228	return 0;
    229
    230fail_free_irq:
    231	free_irq(host->irq, esp);
    232fail_unmap_command_block:
    233	dma_free_coherent(esp->dev, 16,
    234			  esp->command_block,
    235			  esp->command_block_dma);
    236fail_unmap_regs_dma:
    237	iounmap(esp->dma_regs);
    238fail_unmap_regs:
    239	iounmap(esp->regs);
    240fail_unlink:
    241	scsi_host_put(host);
    242fail:
    243	return err;
    244}
    245
    246static int esp_sun3x_remove(struct platform_device *dev)
    247{
    248	struct esp *esp = dev_get_drvdata(&dev->dev);
    249	unsigned int irq = esp->host->irq;
    250	u32 val;
    251
    252	scsi_esp_unregister(esp);
    253
    254	/* Disable interrupts.  */
    255	val = dma_read32(DMA_CSR);
    256	dma_write32(val & ~DMA_INT_ENAB, DMA_CSR);
    257
    258	free_irq(irq, esp);
    259	dma_free_coherent(esp->dev, 16,
    260			  esp->command_block,
    261			  esp->command_block_dma);
    262
    263	scsi_host_put(esp->host);
    264
    265	return 0;
    266}
    267
    268static struct platform_driver esp_sun3x_driver = {
    269	.probe          = esp_sun3x_probe,
    270	.remove         = esp_sun3x_remove,
    271	.driver = {
    272		.name   = "sun3x_esp",
    273	},
    274};
    275module_platform_driver(esp_sun3x_driver);
    276
    277MODULE_DESCRIPTION("Sun3x ESP SCSI driver");
    278MODULE_AUTHOR("Thomas Bogendoerfer (tsbogend@alpha.franken.de)");
    279MODULE_LICENSE("GPL");
    280MODULE_VERSION(DRV_VERSION);
    281MODULE_ALIAS("platform:sun3x_esp");