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

uio_mf624.c (5351B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * UIO driver fo Humusoft MF624 DAQ card.
      4 * Copyright (C) 2011 Rostislav Lisovy <lisovy@gmail.com>,
      5 *                    Czech Technical University in Prague
      6 */
      7
      8#include <linux/init.h>
      9#include <linux/module.h>
     10#include <linux/device.h>
     11#include <linux/pci.h>
     12#include <linux/slab.h>
     13#include <linux/io.h>
     14#include <linux/kernel.h>
     15#include <linux/uio_driver.h>
     16
     17#define PCI_VENDOR_ID_HUMUSOFT		0x186c
     18#define PCI_DEVICE_ID_MF624		0x0624
     19#define PCI_SUBVENDOR_ID_HUMUSOFT	0x186c
     20#define PCI_SUBDEVICE_DEVICE		0x0624
     21
     22/* BAR0 Interrupt control/status register */
     23#define INTCSR				0x4C
     24#define INTCSR_ADINT_ENABLE		(1 << 0)
     25#define INTCSR_CTR4INT_ENABLE		(1 << 3)
     26#define INTCSR_PCIINT_ENABLE		(1 << 6)
     27#define INTCSR_ADINT_STATUS		(1 << 2)
     28#define INTCSR_CTR4INT_STATUS		(1 << 5)
     29
     30enum mf624_interrupt_source {ADC, CTR4, ALL};
     31
     32static void mf624_disable_interrupt(enum mf624_interrupt_source source,
     33			     struct uio_info *info)
     34{
     35	void __iomem *INTCSR_reg = info->mem[0].internal_addr + INTCSR;
     36
     37	switch (source) {
     38	case ADC:
     39		iowrite32(ioread32(INTCSR_reg)
     40			& ~(INTCSR_ADINT_ENABLE | INTCSR_PCIINT_ENABLE),
     41			INTCSR_reg);
     42		break;
     43
     44	case CTR4:
     45		iowrite32(ioread32(INTCSR_reg)
     46			& ~(INTCSR_CTR4INT_ENABLE | INTCSR_PCIINT_ENABLE),
     47			INTCSR_reg);
     48		break;
     49
     50	case ALL:
     51	default:
     52		iowrite32(ioread32(INTCSR_reg)
     53			& ~(INTCSR_ADINT_ENABLE | INTCSR_CTR4INT_ENABLE
     54			    | INTCSR_PCIINT_ENABLE),
     55			INTCSR_reg);
     56		break;
     57	}
     58}
     59
     60static void mf624_enable_interrupt(enum mf624_interrupt_source source,
     61			    struct uio_info *info)
     62{
     63	void __iomem *INTCSR_reg = info->mem[0].internal_addr + INTCSR;
     64
     65	switch (source) {
     66	case ADC:
     67		iowrite32(ioread32(INTCSR_reg)
     68			| INTCSR_ADINT_ENABLE | INTCSR_PCIINT_ENABLE,
     69			INTCSR_reg);
     70		break;
     71
     72	case CTR4:
     73		iowrite32(ioread32(INTCSR_reg)
     74			| INTCSR_CTR4INT_ENABLE | INTCSR_PCIINT_ENABLE,
     75			INTCSR_reg);
     76		break;
     77
     78	case ALL:
     79	default:
     80		iowrite32(ioread32(INTCSR_reg)
     81			| INTCSR_ADINT_ENABLE | INTCSR_CTR4INT_ENABLE
     82			| INTCSR_PCIINT_ENABLE,
     83			INTCSR_reg);
     84		break;
     85	}
     86}
     87
     88static irqreturn_t mf624_irq_handler(int irq, struct uio_info *info)
     89{
     90	void __iomem *INTCSR_reg = info->mem[0].internal_addr + INTCSR;
     91
     92	if ((ioread32(INTCSR_reg) & INTCSR_ADINT_ENABLE)
     93	    && (ioread32(INTCSR_reg) & INTCSR_ADINT_STATUS)) {
     94		mf624_disable_interrupt(ADC, info);
     95		return IRQ_HANDLED;
     96	}
     97
     98	if ((ioread32(INTCSR_reg) & INTCSR_CTR4INT_ENABLE)
     99	    && (ioread32(INTCSR_reg) & INTCSR_CTR4INT_STATUS)) {
    100		mf624_disable_interrupt(CTR4, info);
    101		return IRQ_HANDLED;
    102	}
    103
    104	return IRQ_NONE;
    105}
    106
    107static int mf624_irqcontrol(struct uio_info *info, s32 irq_on)
    108{
    109	if (irq_on == 0)
    110		mf624_disable_interrupt(ALL, info);
    111	else if (irq_on == 1)
    112		mf624_enable_interrupt(ALL, info);
    113
    114	return 0;
    115}
    116
    117static int mf624_setup_mem(struct pci_dev *dev, int bar, struct uio_mem *mem, const char *name)
    118{
    119	resource_size_t start = pci_resource_start(dev, bar);
    120	resource_size_t len = pci_resource_len(dev, bar);
    121
    122	mem->name = name;
    123	mem->addr = start & PAGE_MASK;
    124	mem->offs = start & ~PAGE_MASK;
    125	if (!mem->addr)
    126		return -ENODEV;
    127	mem->size = ((start & ~PAGE_MASK) + len + PAGE_SIZE - 1) & PAGE_MASK;
    128	mem->memtype = UIO_MEM_PHYS;
    129	mem->internal_addr = pci_ioremap_bar(dev, bar);
    130	if (!mem->internal_addr)
    131		return -ENODEV;
    132	return 0;
    133}
    134
    135static int mf624_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
    136{
    137	struct uio_info *info;
    138
    139	info = devm_kzalloc(&dev->dev, sizeof(struct uio_info), GFP_KERNEL);
    140	if (!info)
    141		return -ENOMEM;
    142
    143	if (pci_enable_device(dev))
    144		return -ENODEV;
    145
    146	if (pci_request_regions(dev, "mf624"))
    147		goto out_disable;
    148
    149	info->name = "mf624";
    150	info->version = "0.0.1";
    151
    152	/* Note: Datasheet says device uses BAR0, BAR1, BAR2 -- do not trust it */
    153
    154	/* BAR0 */
    155	if (mf624_setup_mem(dev, 0, &info->mem[0], "PCI chipset, interrupts, status "
    156			    "bits, special functions"))
    157		goto out_release;
    158	/* BAR2 */
    159	if (mf624_setup_mem(dev, 2, &info->mem[1], "ADC, DAC, DIO"))
    160		goto out_unmap0;
    161
    162	/* BAR4 */
    163	if (mf624_setup_mem(dev, 4, &info->mem[2], "Counter/timer chip"))
    164		goto out_unmap1;
    165
    166	info->irq = dev->irq;
    167	info->irq_flags = IRQF_SHARED;
    168	info->handler = mf624_irq_handler;
    169
    170	info->irqcontrol = mf624_irqcontrol;
    171
    172	if (uio_register_device(&dev->dev, info))
    173		goto out_unmap2;
    174
    175	pci_set_drvdata(dev, info);
    176
    177	return 0;
    178
    179out_unmap2:
    180	iounmap(info->mem[2].internal_addr);
    181out_unmap1:
    182	iounmap(info->mem[1].internal_addr);
    183out_unmap0:
    184	iounmap(info->mem[0].internal_addr);
    185
    186out_release:
    187	pci_release_regions(dev);
    188
    189out_disable:
    190	pci_disable_device(dev);
    191
    192	return -ENODEV;
    193}
    194
    195static void mf624_pci_remove(struct pci_dev *dev)
    196{
    197	struct uio_info *info = pci_get_drvdata(dev);
    198
    199	mf624_disable_interrupt(ALL, info);
    200
    201	uio_unregister_device(info);
    202	pci_release_regions(dev);
    203	pci_disable_device(dev);
    204
    205	iounmap(info->mem[0].internal_addr);
    206	iounmap(info->mem[1].internal_addr);
    207	iounmap(info->mem[2].internal_addr);
    208}
    209
    210static const struct pci_device_id mf624_pci_id[] = {
    211	{ PCI_DEVICE(PCI_VENDOR_ID_HUMUSOFT, PCI_DEVICE_ID_MF624) },
    212	{ 0, }
    213};
    214
    215static struct pci_driver mf624_pci_driver = {
    216	.name = "mf624",
    217	.id_table = mf624_pci_id,
    218	.probe = mf624_pci_probe,
    219	.remove = mf624_pci_remove,
    220};
    221MODULE_DEVICE_TABLE(pci, mf624_pci_id);
    222
    223module_pci_driver(mf624_pci_driver);
    224MODULE_LICENSE("GPL v2");
    225MODULE_AUTHOR("Rostislav Lisovy <lisovy@gmail.com>");