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

mac_esp.c (11818B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/* mac_esp.c: ESP front-end for Macintosh Quadra systems.
      3 *
      4 * Adapted from jazz_esp.c and the old mac_esp.c.
      5 *
      6 * The pseudo DMA algorithm is based on the one used in NetBSD.
      7 * See sys/arch/mac68k/obio/esp.c for some background information.
      8 *
      9 * Copyright (C) 2007-2008 Finn Thain
     10 */
     11
     12#include <linux/kernel.h>
     13#include <linux/types.h>
     14#include <linux/module.h>
     15#include <linux/init.h>
     16#include <linux/interrupt.h>
     17#include <linux/platform_device.h>
     18#include <linux/dma-mapping.h>
     19#include <linux/scatterlist.h>
     20#include <linux/delay.h>
     21#include <linux/io.h>
     22#include <linux/nubus.h>
     23#include <linux/slab.h>
     24
     25#include <asm/irq.h>
     26#include <asm/dma.h>
     27#include <asm/macints.h>
     28#include <asm/macintosh.h>
     29#include <asm/mac_via.h>
     30
     31#include <scsi/scsi_host.h>
     32
     33#include "esp_scsi.h"
     34
     35#define DRV_MODULE_NAME     "mac_esp"
     36#define PFX                 DRV_MODULE_NAME ": "
     37#define DRV_VERSION         "1.000"
     38#define DRV_MODULE_RELDATE  "Sept 15, 2007"
     39
     40#define MAC_ESP_IO_BASE          0x50F00000
     41#define MAC_ESP_REGS_QUADRA      (MAC_ESP_IO_BASE + 0x10000)
     42#define MAC_ESP_REGS_QUADRA2     (MAC_ESP_IO_BASE + 0xF000)
     43#define MAC_ESP_REGS_QUADRA3     (MAC_ESP_IO_BASE + 0x18000)
     44#define MAC_ESP_REGS_SPACING     0x402
     45#define MAC_ESP_PDMA_REG         0xF9800024
     46#define MAC_ESP_PDMA_REG_SPACING 0x4
     47#define MAC_ESP_PDMA_IO_OFFSET   0x100
     48
     49#define esp_read8(REG)		mac_esp_read8(esp, REG)
     50#define esp_write8(VAL, REG)	mac_esp_write8(esp, VAL, REG)
     51
     52struct mac_esp_priv {
     53	struct esp *esp;
     54	void __iomem *pdma_regs;
     55	void __iomem *pdma_io;
     56};
     57static struct esp *esp_chips[2];
     58static DEFINE_SPINLOCK(esp_chips_lock);
     59
     60#define MAC_ESP_GET_PRIV(esp) ((struct mac_esp_priv *) \
     61			       dev_get_drvdata((esp)->dev))
     62
     63static inline void mac_esp_write8(struct esp *esp, u8 val, unsigned long reg)
     64{
     65	nubus_writeb(val, esp->regs + reg * 16);
     66}
     67
     68static inline u8 mac_esp_read8(struct esp *esp, unsigned long reg)
     69{
     70	return nubus_readb(esp->regs + reg * 16);
     71}
     72
     73static void mac_esp_reset_dma(struct esp *esp)
     74{
     75	/* Nothing to do. */
     76}
     77
     78static void mac_esp_dma_drain(struct esp *esp)
     79{
     80	/* Nothing to do. */
     81}
     82
     83static void mac_esp_dma_invalidate(struct esp *esp)
     84{
     85	/* Nothing to do. */
     86}
     87
     88static int mac_esp_dma_error(struct esp *esp)
     89{
     90	return esp->send_cmd_error;
     91}
     92
     93static inline int mac_esp_wait_for_empty_fifo(struct esp *esp)
     94{
     95	int i = 500000;
     96
     97	do {
     98		if (!(esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES))
     99			return 0;
    100
    101		if (esp_read8(ESP_STATUS) & ESP_STAT_INTR)
    102			return 1;
    103
    104		udelay(2);
    105	} while (--i);
    106
    107	printk(KERN_ERR PFX "FIFO is not empty (sreg %02x)\n",
    108	       esp_read8(ESP_STATUS));
    109	esp->send_cmd_error = 1;
    110	return 1;
    111}
    112
    113static inline int mac_esp_wait_for_dreq(struct esp *esp)
    114{
    115	struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp);
    116	int i = 500000;
    117
    118	do {
    119		if (mep->pdma_regs == NULL) {
    120			if (via2_scsi_drq_pending())
    121				return 0;
    122		} else {
    123			if (nubus_readl(mep->pdma_regs) & 0x200)
    124				return 0;
    125		}
    126
    127		if (esp_read8(ESP_STATUS) & ESP_STAT_INTR)
    128			return 1;
    129
    130		udelay(2);
    131	} while (--i);
    132
    133	printk(KERN_ERR PFX "PDMA timeout (sreg %02x)\n",
    134	       esp_read8(ESP_STATUS));
    135	esp->send_cmd_error = 1;
    136	return 1;
    137}
    138
    139#define MAC_ESP_PDMA_LOOP(operands) \
    140	asm volatile ( \
    141	     "       tstw %1                   \n" \
    142	     "       jbeq 20f                  \n" \
    143	     "1:     movew " operands "        \n" \
    144	     "2:     movew " operands "        \n" \
    145	     "3:     movew " operands "        \n" \
    146	     "4:     movew " operands "        \n" \
    147	     "5:     movew " operands "        \n" \
    148	     "6:     movew " operands "        \n" \
    149	     "7:     movew " operands "        \n" \
    150	     "8:     movew " operands "        \n" \
    151	     "9:     movew " operands "        \n" \
    152	     "10:    movew " operands "        \n" \
    153	     "11:    movew " operands "        \n" \
    154	     "12:    movew " operands "        \n" \
    155	     "13:    movew " operands "        \n" \
    156	     "14:    movew " operands "        \n" \
    157	     "15:    movew " operands "        \n" \
    158	     "16:    movew " operands "        \n" \
    159	     "       subqw #1,%1               \n" \
    160	     "       jbne 1b                   \n" \
    161	     "20:    tstw %2                   \n" \
    162	     "       jbeq 30f                  \n" \
    163	     "21:    movew " operands "        \n" \
    164	     "       subqw #1,%2               \n" \
    165	     "       jbne 21b                  \n" \
    166	     "30:    tstw %3                   \n" \
    167	     "       jbeq 40f                  \n" \
    168	     "31:    moveb " operands "        \n" \
    169	     "32:    nop                       \n" \
    170	     "40:                              \n" \
    171	     "                                 \n" \
    172	     "       .section __ex_table,\"a\" \n" \
    173	     "       .align  4                 \n" \
    174	     "       .long   1b,40b            \n" \
    175	     "       .long   2b,40b            \n" \
    176	     "       .long   3b,40b            \n" \
    177	     "       .long   4b,40b            \n" \
    178	     "       .long   5b,40b            \n" \
    179	     "       .long   6b,40b            \n" \
    180	     "       .long   7b,40b            \n" \
    181	     "       .long   8b,40b            \n" \
    182	     "       .long   9b,40b            \n" \
    183	     "       .long  10b,40b            \n" \
    184	     "       .long  11b,40b            \n" \
    185	     "       .long  12b,40b            \n" \
    186	     "       .long  13b,40b            \n" \
    187	     "       .long  14b,40b            \n" \
    188	     "       .long  15b,40b            \n" \
    189	     "       .long  16b,40b            \n" \
    190	     "       .long  21b,40b            \n" \
    191	     "       .long  31b,40b            \n" \
    192	     "       .long  32b,40b            \n" \
    193	     "       .previous                 \n" \
    194	     : "+a" (addr), "+r" (count32), "+r" (count2) \
    195	     : "g" (count1), "a" (mep->pdma_io))
    196
    197static void mac_esp_send_pdma_cmd(struct esp *esp, u32 addr, u32 esp_count,
    198				  u32 dma_count, int write, u8 cmd)
    199{
    200	struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp);
    201
    202	esp->send_cmd_error = 0;
    203
    204	if (!write)
    205		scsi_esp_cmd(esp, ESP_CMD_FLUSH);
    206
    207	esp_write8((esp_count >> 0) & 0xFF, ESP_TCLOW);
    208	esp_write8((esp_count >> 8) & 0xFF, ESP_TCMED);
    209
    210	scsi_esp_cmd(esp, cmd);
    211
    212	do {
    213		unsigned int count32 = esp_count >> 5;
    214		unsigned int count2 = (esp_count & 0x1F) >> 1;
    215		unsigned int count1 = esp_count & 1;
    216		unsigned int start_addr = addr;
    217
    218		if (mac_esp_wait_for_dreq(esp))
    219			break;
    220
    221		if (write) {
    222			MAC_ESP_PDMA_LOOP("%4@,%0@+");
    223
    224			esp_count -= addr - start_addr;
    225		} else {
    226			unsigned int n;
    227
    228			MAC_ESP_PDMA_LOOP("%0@+,%4@");
    229
    230			if (mac_esp_wait_for_empty_fifo(esp))
    231				break;
    232
    233			n = (esp_read8(ESP_TCMED) << 8) + esp_read8(ESP_TCLOW);
    234			addr = start_addr + esp_count - n;
    235			esp_count = n;
    236		}
    237	} while (esp_count);
    238}
    239
    240static int mac_esp_irq_pending(struct esp *esp)
    241{
    242	if (esp_read8(ESP_STATUS) & ESP_STAT_INTR)
    243		return 1;
    244	return 0;
    245}
    246
    247static u32 mac_esp_dma_length_limit(struct esp *esp, u32 dma_addr, u32 dma_len)
    248{
    249	return dma_len > 0xFFFF ? 0xFFFF : dma_len;
    250}
    251
    252static irqreturn_t mac_scsi_esp_intr(int irq, void *dev_id)
    253{
    254	int got_intr;
    255
    256	/*
    257	 * This is an edge triggered IRQ, so we have to be careful to
    258	 * avoid missing a transition when it is shared by two ESP devices.
    259	 */
    260
    261	do {
    262		got_intr = 0;
    263		if (esp_chips[0] &&
    264		    (mac_esp_read8(esp_chips[0], ESP_STATUS) & ESP_STAT_INTR)) {
    265			(void)scsi_esp_intr(irq, esp_chips[0]);
    266			got_intr = 1;
    267		}
    268		if (esp_chips[1] &&
    269		    (mac_esp_read8(esp_chips[1], ESP_STATUS) & ESP_STAT_INTR)) {
    270			(void)scsi_esp_intr(irq, esp_chips[1]);
    271			got_intr = 1;
    272		}
    273	} while (got_intr);
    274
    275	return IRQ_HANDLED;
    276}
    277
    278static struct esp_driver_ops mac_esp_ops = {
    279	.esp_write8       = mac_esp_write8,
    280	.esp_read8        = mac_esp_read8,
    281	.irq_pending      = mac_esp_irq_pending,
    282	.dma_length_limit = mac_esp_dma_length_limit,
    283	.reset_dma        = mac_esp_reset_dma,
    284	.dma_drain        = mac_esp_dma_drain,
    285	.dma_invalidate   = mac_esp_dma_invalidate,
    286	.send_dma_cmd     = mac_esp_send_pdma_cmd,
    287	.dma_error        = mac_esp_dma_error,
    288};
    289
    290static int esp_mac_probe(struct platform_device *dev)
    291{
    292	struct scsi_host_template *tpnt = &scsi_esp_template;
    293	struct Scsi_Host *host;
    294	struct esp *esp;
    295	int err;
    296	struct mac_esp_priv *mep;
    297
    298	if (!MACH_IS_MAC)
    299		return -ENODEV;
    300
    301	if (dev->id > 1)
    302		return -ENODEV;
    303
    304	host = scsi_host_alloc(tpnt, sizeof(struct esp));
    305
    306	err = -ENOMEM;
    307	if (!host)
    308		goto fail;
    309
    310	host->max_id = 8;
    311	host->dma_boundary = PAGE_SIZE - 1;
    312	esp = shost_priv(host);
    313
    314	esp->host = host;
    315	esp->dev = &dev->dev;
    316
    317	esp->command_block = kzalloc(16, GFP_KERNEL);
    318	if (!esp->command_block)
    319		goto fail_unlink;
    320	esp->command_block_dma = (dma_addr_t)esp->command_block;
    321
    322	esp->scsi_id = 7;
    323	host->this_id = esp->scsi_id;
    324	esp->scsi_id_mask = 1 << esp->scsi_id;
    325
    326	mep = kzalloc(sizeof(struct mac_esp_priv), GFP_KERNEL);
    327	if (!mep)
    328		goto fail_free_command_block;
    329	mep->esp = esp;
    330	platform_set_drvdata(dev, mep);
    331
    332	switch (macintosh_config->scsi_type) {
    333	case MAC_SCSI_QUADRA:
    334		esp->cfreq     = 16500000;
    335		esp->regs      = (void __iomem *)MAC_ESP_REGS_QUADRA;
    336		mep->pdma_io   = esp->regs + MAC_ESP_PDMA_IO_OFFSET;
    337		mep->pdma_regs = NULL;
    338		break;
    339	case MAC_SCSI_QUADRA2:
    340		esp->cfreq     = 25000000;
    341		esp->regs      = (void __iomem *)(MAC_ESP_REGS_QUADRA2 +
    342				 dev->id * MAC_ESP_REGS_SPACING);
    343		mep->pdma_io   = esp->regs + MAC_ESP_PDMA_IO_OFFSET;
    344		mep->pdma_regs = (void __iomem *)(MAC_ESP_PDMA_REG +
    345				 dev->id * MAC_ESP_PDMA_REG_SPACING);
    346		nubus_writel(0x1d1, mep->pdma_regs);
    347		break;
    348	case MAC_SCSI_QUADRA3:
    349		/* These quadras have a real DMA controller (the PSC) but we
    350		 * don't know how to drive it so we must use PIO instead.
    351		 */
    352		esp->cfreq     = 25000000;
    353		esp->regs      = (void __iomem *)MAC_ESP_REGS_QUADRA3;
    354		mep->pdma_io   = NULL;
    355		mep->pdma_regs = NULL;
    356		break;
    357	}
    358	esp->fifo_reg = esp->regs + ESP_FDATA * 16;
    359
    360	esp->ops = &mac_esp_ops;
    361	esp->flags = ESP_FLAG_NO_DMA_MAP;
    362	if (mep->pdma_io == NULL) {
    363		printk(KERN_INFO PFX "using PIO for controller %d\n", dev->id);
    364		esp_write8(0, ESP_TCLOW);
    365		esp_write8(0, ESP_TCMED);
    366		esp->flags |= ESP_FLAG_DISABLE_SYNC;
    367		mac_esp_ops.send_dma_cmd = esp_send_pio_cmd;
    368	} else {
    369		printk(KERN_INFO PFX "using PDMA for controller %d\n", dev->id);
    370	}
    371
    372	host->irq = IRQ_MAC_SCSI;
    373
    374	/* The request_irq() call is intended to succeed for the first device
    375	 * and fail for the second device.
    376	 */
    377	err = request_irq(host->irq, mac_scsi_esp_intr, 0, "ESP", NULL);
    378	spin_lock(&esp_chips_lock);
    379	if (err < 0 && esp_chips[!dev->id] == NULL) {
    380		spin_unlock(&esp_chips_lock);
    381		goto fail_free_priv;
    382	}
    383	esp_chips[dev->id] = esp;
    384	spin_unlock(&esp_chips_lock);
    385
    386	err = scsi_esp_register(esp);
    387	if (err)
    388		goto fail_free_irq;
    389
    390	return 0;
    391
    392fail_free_irq:
    393	spin_lock(&esp_chips_lock);
    394	esp_chips[dev->id] = NULL;
    395	if (esp_chips[!dev->id] == NULL) {
    396		spin_unlock(&esp_chips_lock);
    397		free_irq(host->irq, NULL);
    398	} else
    399		spin_unlock(&esp_chips_lock);
    400fail_free_priv:
    401	kfree(mep);
    402fail_free_command_block:
    403	kfree(esp->command_block);
    404fail_unlink:
    405	scsi_host_put(host);
    406fail:
    407	return err;
    408}
    409
    410static int esp_mac_remove(struct platform_device *dev)
    411{
    412	struct mac_esp_priv *mep = platform_get_drvdata(dev);
    413	struct esp *esp = mep->esp;
    414	unsigned int irq = esp->host->irq;
    415
    416	scsi_esp_unregister(esp);
    417
    418	spin_lock(&esp_chips_lock);
    419	esp_chips[dev->id] = NULL;
    420	if (esp_chips[!dev->id] == NULL) {
    421		spin_unlock(&esp_chips_lock);
    422		free_irq(irq, NULL);
    423	} else
    424		spin_unlock(&esp_chips_lock);
    425
    426	kfree(mep);
    427
    428	kfree(esp->command_block);
    429
    430	scsi_host_put(esp->host);
    431
    432	return 0;
    433}
    434
    435static struct platform_driver esp_mac_driver = {
    436	.probe    = esp_mac_probe,
    437	.remove   = esp_mac_remove,
    438	.driver   = {
    439		.name	= DRV_MODULE_NAME,
    440	},
    441};
    442module_platform_driver(esp_mac_driver);
    443
    444MODULE_DESCRIPTION("Mac ESP SCSI driver");
    445MODULE_AUTHOR("Finn Thain");
    446MODULE_LICENSE("GPL v2");
    447MODULE_VERSION(DRV_VERSION);
    448MODULE_ALIAS("platform:" DRV_MODULE_NAME);