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

pci.c (3355B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * PCI driver for the High Speed UART DMA
      4 *
      5 * Copyright (C) 2015 Intel Corporation
      6 * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
      7 *
      8 * Partially based on the bits found in drivers/tty/serial/mfd.c.
      9 */
     10
     11#include <linux/bitops.h>
     12#include <linux/device.h>
     13#include <linux/module.h>
     14#include <linux/pci.h>
     15
     16#include "hsu.h"
     17
     18#define HSU_PCI_DMASR		0x00
     19#define HSU_PCI_DMAISR		0x04
     20
     21#define HSU_PCI_CHAN_OFFSET	0x100
     22
     23#define PCI_DEVICE_ID_INTEL_MFLD_HSU_DMA	0x081e
     24#define PCI_DEVICE_ID_INTEL_MRFLD_HSU_DMA	0x1192
     25
     26static irqreturn_t hsu_pci_irq(int irq, void *dev)
     27{
     28	struct hsu_dma_chip *chip = dev;
     29	u32 dmaisr;
     30	u32 status;
     31	unsigned short i;
     32	int ret = 0;
     33	int err;
     34
     35	dmaisr = readl(chip->regs + HSU_PCI_DMAISR);
     36	for (i = 0; i < chip->hsu->nr_channels; i++) {
     37		if (dmaisr & 0x1) {
     38			err = hsu_dma_get_status(chip, i, &status);
     39			if (err > 0)
     40				ret |= 1;
     41			else if (err == 0)
     42				ret |= hsu_dma_do_irq(chip, i, status);
     43		}
     44		dmaisr >>= 1;
     45	}
     46
     47	return IRQ_RETVAL(ret);
     48}
     49
     50static int hsu_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
     51{
     52	struct hsu_dma_chip *chip;
     53	int ret;
     54
     55	ret = pcim_enable_device(pdev);
     56	if (ret)
     57		return ret;
     58
     59	ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev));
     60	if (ret) {
     61		dev_err(&pdev->dev, "I/O memory remapping failed\n");
     62		return ret;
     63	}
     64
     65	pci_set_master(pdev);
     66	pci_try_set_mwi(pdev);
     67
     68	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
     69	if (ret)
     70		return ret;
     71
     72	chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
     73	if (!chip)
     74		return -ENOMEM;
     75
     76	ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
     77	if (ret < 0)
     78		return ret;
     79
     80	chip->dev = &pdev->dev;
     81	chip->regs = pcim_iomap_table(pdev)[0];
     82	chip->length = pci_resource_len(pdev, 0);
     83	chip->offset = HSU_PCI_CHAN_OFFSET;
     84	chip->irq = pci_irq_vector(pdev, 0);
     85
     86	ret = hsu_dma_probe(chip);
     87	if (ret)
     88		return ret;
     89
     90	ret = request_irq(chip->irq, hsu_pci_irq, 0, "hsu_dma_pci", chip);
     91	if (ret)
     92		goto err_register_irq;
     93
     94	/*
     95	 * On Intel Tangier B0 and Anniedale the interrupt line, disregarding
     96	 * to have different numbers, is shared between HSU DMA and UART IPs.
     97	 * Thus on such SoCs we are expecting that IRQ handler is called in
     98	 * UART driver only. Instead of handling the spurious interrupt
     99	 * from HSU DMA here and waste CPU time and delay HSU UART interrupt
    100	 * handling, disable the interrupt entirely.
    101	 */
    102	if (pdev->device == PCI_DEVICE_ID_INTEL_MRFLD_HSU_DMA)
    103		disable_irq_nosync(chip->irq);
    104
    105	pci_set_drvdata(pdev, chip);
    106
    107	return 0;
    108
    109err_register_irq:
    110	hsu_dma_remove(chip);
    111	return ret;
    112}
    113
    114static void hsu_pci_remove(struct pci_dev *pdev)
    115{
    116	struct hsu_dma_chip *chip = pci_get_drvdata(pdev);
    117
    118	free_irq(chip->irq, chip);
    119	hsu_dma_remove(chip);
    120}
    121
    122static const struct pci_device_id hsu_pci_id_table[] = {
    123	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MFLD_HSU_DMA), 0 },
    124	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MRFLD_HSU_DMA), 0 },
    125	{ }
    126};
    127MODULE_DEVICE_TABLE(pci, hsu_pci_id_table);
    128
    129static struct pci_driver hsu_pci_driver = {
    130	.name		= "hsu_dma_pci",
    131	.id_table	= hsu_pci_id_table,
    132	.probe		= hsu_pci_probe,
    133	.remove		= hsu_pci_remove,
    134};
    135
    136module_pci_driver(hsu_pci_driver);
    137
    138MODULE_LICENSE("GPL v2");
    139MODULE_DESCRIPTION("High Speed UART DMA PCI driver");
    140MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>");