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

a2091.c (6559B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2#include <linux/types.h>
      3#include <linux/init.h>
      4#include <linux/interrupt.h>
      5#include <linux/mm.h>
      6#include <linux/slab.h>
      7#include <linux/spinlock.h>
      8#include <linux/zorro.h>
      9#include <linux/module.h>
     10
     11#include <asm/page.h>
     12#include <asm/amigaints.h>
     13#include <asm/amigahw.h>
     14
     15#include <scsi/scsi.h>
     16#include <scsi/scsi_cmnd.h>
     17#include <scsi/scsi_device.h>
     18#include <scsi/scsi_eh.h>
     19#include <scsi/scsi_tcq.h>
     20#include "wd33c93.h"
     21#include "a2091.h"
     22
     23
     24struct a2091_hostdata {
     25	struct WD33C93_hostdata wh;
     26	struct a2091_scsiregs *regs;
     27};
     28
     29static irqreturn_t a2091_intr(int irq, void *data)
     30{
     31	struct Scsi_Host *instance = data;
     32	struct a2091_hostdata *hdata = shost_priv(instance);
     33	unsigned int status = hdata->regs->ISTR;
     34	unsigned long flags;
     35
     36	if (!(status & (ISTR_INT_F | ISTR_INT_P)) || !(status & ISTR_INTS))
     37		return IRQ_NONE;
     38
     39	spin_lock_irqsave(instance->host_lock, flags);
     40	wd33c93_intr(instance);
     41	spin_unlock_irqrestore(instance->host_lock, flags);
     42	return IRQ_HANDLED;
     43}
     44
     45static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
     46{
     47	struct scsi_pointer *scsi_pointer = WD33C93_scsi_pointer(cmd);
     48	struct Scsi_Host *instance = cmd->device->host;
     49	struct a2091_hostdata *hdata = shost_priv(instance);
     50	struct WD33C93_hostdata *wh = &hdata->wh;
     51	struct a2091_scsiregs *regs = hdata->regs;
     52	unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
     53	unsigned long addr = virt_to_bus(scsi_pointer->ptr);
     54
     55	/* don't allow DMA if the physical address is bad */
     56	if (addr & A2091_XFER_MASK) {
     57		wh->dma_bounce_len = (scsi_pointer->this_residual + 511) & ~0x1ff;
     58		wh->dma_bounce_buffer = kmalloc(wh->dma_bounce_len,
     59						GFP_KERNEL);
     60
     61		/* can't allocate memory; use PIO */
     62		if (!wh->dma_bounce_buffer) {
     63			wh->dma_bounce_len = 0;
     64			return 1;
     65		}
     66
     67		/* get the physical address of the bounce buffer */
     68		addr = virt_to_bus(wh->dma_bounce_buffer);
     69
     70		/* the bounce buffer may not be in the first 16M of physmem */
     71		if (addr & A2091_XFER_MASK) {
     72			/* we could use chipmem... maybe later */
     73			kfree(wh->dma_bounce_buffer);
     74			wh->dma_bounce_buffer = NULL;
     75			wh->dma_bounce_len = 0;
     76			return 1;
     77		}
     78
     79		if (!dir_in) {
     80			/* copy to bounce buffer for a write */
     81			memcpy(wh->dma_bounce_buffer, scsi_pointer->ptr,
     82			       scsi_pointer->this_residual);
     83		}
     84	}
     85
     86	/* setup dma direction */
     87	if (!dir_in)
     88		cntr |= CNTR_DDIR;
     89
     90	/* remember direction */
     91	wh->dma_dir = dir_in;
     92
     93	regs->CNTR = cntr;
     94
     95	/* setup DMA *physical* address */
     96	regs->ACR = addr;
     97
     98	if (dir_in) {
     99		/* invalidate any cache */
    100		cache_clear(addr, scsi_pointer->this_residual);
    101	} else {
    102		/* push any dirty cache */
    103		cache_push(addr, scsi_pointer->this_residual);
    104	}
    105	/* start DMA */
    106	regs->ST_DMA = 1;
    107
    108	/* return success */
    109	return 0;
    110}
    111
    112static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
    113		     int status)
    114{
    115	struct scsi_pointer *scsi_pointer = WD33C93_scsi_pointer(SCpnt);
    116	struct a2091_hostdata *hdata = shost_priv(instance);
    117	struct WD33C93_hostdata *wh = &hdata->wh;
    118	struct a2091_scsiregs *regs = hdata->regs;
    119
    120	/* disable SCSI interrupts */
    121	unsigned short cntr = CNTR_PDMD;
    122
    123	if (!wh->dma_dir)
    124		cntr |= CNTR_DDIR;
    125
    126	/* disable SCSI interrupts */
    127	regs->CNTR = cntr;
    128
    129	/* flush if we were reading */
    130	if (wh->dma_dir) {
    131		regs->FLUSH = 1;
    132		while (!(regs->ISTR & ISTR_FE_FLG))
    133			;
    134	}
    135
    136	/* clear a possible interrupt */
    137	regs->CINT = 1;
    138
    139	/* stop DMA */
    140	regs->SP_DMA = 1;
    141
    142	/* restore the CONTROL bits (minus the direction flag) */
    143	regs->CNTR = CNTR_PDMD | CNTR_INTEN;
    144
    145	/* copy from a bounce buffer, if necessary */
    146	if (status && wh->dma_bounce_buffer) {
    147		if (wh->dma_dir)
    148			memcpy(scsi_pointer->ptr, wh->dma_bounce_buffer,
    149			       scsi_pointer->this_residual);
    150		kfree(wh->dma_bounce_buffer);
    151		wh->dma_bounce_buffer = NULL;
    152		wh->dma_bounce_len = 0;
    153	}
    154}
    155
    156static struct scsi_host_template a2091_scsi_template = {
    157	.module			= THIS_MODULE,
    158	.name			= "Commodore A2091/A590 SCSI",
    159	.show_info		= wd33c93_show_info,
    160	.write_info		= wd33c93_write_info,
    161	.proc_name		= "A2901",
    162	.queuecommand		= wd33c93_queuecommand,
    163	.eh_abort_handler	= wd33c93_abort,
    164	.eh_host_reset_handler	= wd33c93_host_reset,
    165	.can_queue		= CAN_QUEUE,
    166	.this_id		= 7,
    167	.sg_tablesize		= SG_ALL,
    168	.cmd_per_lun		= CMD_PER_LUN,
    169	.dma_boundary		= PAGE_SIZE - 1,
    170	.cmd_size		= sizeof(struct scsi_pointer),
    171};
    172
    173static int a2091_probe(struct zorro_dev *z, const struct zorro_device_id *ent)
    174{
    175	struct Scsi_Host *instance;
    176	int error;
    177	struct a2091_scsiregs *regs;
    178	wd33c93_regs wdregs;
    179	struct a2091_hostdata *hdata;
    180
    181	if (!request_mem_region(z->resource.start, 256, "wd33c93"))
    182		return -EBUSY;
    183
    184	instance = scsi_host_alloc(&a2091_scsi_template,
    185				   sizeof(struct a2091_hostdata));
    186	if (!instance) {
    187		error = -ENOMEM;
    188		goto fail_alloc;
    189	}
    190
    191	instance->irq = IRQ_AMIGA_PORTS;
    192	instance->unique_id = z->slotaddr;
    193
    194	regs = ZTWO_VADDR(z->resource.start);
    195	regs->DAWR = DAWR_A2091;
    196
    197	wdregs.SASR = &regs->SASR;
    198	wdregs.SCMD = &regs->SCMD;
    199
    200	hdata = shost_priv(instance);
    201	hdata->wh.no_sync = 0xff;
    202	hdata->wh.fast = 0;
    203	hdata->wh.dma_mode = CTRL_DMA;
    204	hdata->regs = regs;
    205
    206	wd33c93_init(instance, wdregs, dma_setup, dma_stop, WD33C93_FS_8_10);
    207	error = request_irq(IRQ_AMIGA_PORTS, a2091_intr, IRQF_SHARED,
    208			    "A2091 SCSI", instance);
    209	if (error)
    210		goto fail_irq;
    211
    212	regs->CNTR = CNTR_PDMD | CNTR_INTEN;
    213
    214	error = scsi_add_host(instance, NULL);
    215	if (error)
    216		goto fail_host;
    217
    218	zorro_set_drvdata(z, instance);
    219
    220	scsi_scan_host(instance);
    221	return 0;
    222
    223fail_host:
    224	free_irq(IRQ_AMIGA_PORTS, instance);
    225fail_irq:
    226	scsi_host_put(instance);
    227fail_alloc:
    228	release_mem_region(z->resource.start, 256);
    229	return error;
    230}
    231
    232static void a2091_remove(struct zorro_dev *z)
    233{
    234	struct Scsi_Host *instance = zorro_get_drvdata(z);
    235	struct a2091_hostdata *hdata = shost_priv(instance);
    236
    237	hdata->regs->CNTR = 0;
    238	scsi_remove_host(instance);
    239	free_irq(IRQ_AMIGA_PORTS, instance);
    240	scsi_host_put(instance);
    241	release_mem_region(z->resource.start, 256);
    242}
    243
    244static struct zorro_device_id a2091_zorro_tbl[] = {
    245	{ ZORRO_PROD_CBM_A590_A2091_1 },
    246	{ ZORRO_PROD_CBM_A590_A2091_2 },
    247	{ 0 }
    248};
    249MODULE_DEVICE_TABLE(zorro, a2091_zorro_tbl);
    250
    251static struct zorro_driver a2091_driver = {
    252	.name		= "a2091",
    253	.id_table	= a2091_zorro_tbl,
    254	.probe		= a2091_probe,
    255	.remove		= a2091_remove,
    256};
    257
    258static int __init a2091_init(void)
    259{
    260	return zorro_register_driver(&a2091_driver);
    261}
    262module_init(a2091_init);
    263
    264static void __exit a2091_exit(void)
    265{
    266	zorro_unregister_driver(&a2091_driver);
    267}
    268module_exit(a2091_exit);
    269
    270MODULE_DESCRIPTION("Commodore A2091/A590 SCSI");
    271MODULE_LICENSE("GPL");