1bce5c2eaSStephen Hemminger // SPDX-License-Identifier: GPL-2.0 2ccb86a69SMichael S. Tsirkin /* uio_pci_generic - generic UIO driver for PCI 2.3 devices 3ccb86a69SMichael S. Tsirkin * 4ccb86a69SMichael S. Tsirkin * Copyright (C) 2009 Red Hat, Inc. 5ccb86a69SMichael S. Tsirkin * Author: Michael S. Tsirkin <mst@redhat.com> 6ccb86a69SMichael S. Tsirkin * 7ccb86a69SMichael S. Tsirkin * Since the driver does not declare any device ids, you must allocate 8ccb86a69SMichael S. Tsirkin * id and bind the device to the driver yourself. For example: 9ccb86a69SMichael S. Tsirkin * 10ccb86a69SMichael S. Tsirkin * # echo "8086 10f5" > /sys/bus/pci/drivers/uio_pci_generic/new_id 11ccb86a69SMichael S. Tsirkin * # echo -n 0000:00:19.0 > /sys/bus/pci/drivers/e1000e/unbind 12ccb86a69SMichael S. Tsirkin * # echo -n 0000:00:19.0 > /sys/bus/pci/drivers/uio_pci_generic/bind 13ccb86a69SMichael S. Tsirkin * # ls -l /sys/bus/pci/devices/0000:00:19.0/driver 14ccb86a69SMichael S. Tsirkin * .../0000:00:19.0/driver -> ../../../bus/pci/drivers/uio_pci_generic 15ccb86a69SMichael S. Tsirkin * 16ccb86a69SMichael S. Tsirkin * Driver won't bind to devices which do not support the Interrupt Disable Bit 17ccb86a69SMichael S. Tsirkin * in the command register. All devices compliant to PCI 2.3 (circa 2002) and 18ccb86a69SMichael S. Tsirkin * all compliant PCI Express devices should support this bit. 19ccb86a69SMichael S. Tsirkin */ 20ccb86a69SMichael S. Tsirkin 21ccb86a69SMichael S. Tsirkin #include <linux/device.h> 22ccb86a69SMichael S. Tsirkin #include <linux/module.h> 23ccb86a69SMichael S. Tsirkin #include <linux/pci.h> 245a0e3ad6STejun Heo #include <linux/slab.h> 25ccb86a69SMichael S. Tsirkin #include <linux/uio_driver.h> 26ccb86a69SMichael S. Tsirkin 27ccb86a69SMichael S. Tsirkin #define DRIVER_VERSION "0.01.0" 28ccb86a69SMichael S. Tsirkin #define DRIVER_AUTHOR "Michael S. Tsirkin <mst@redhat.com>" 29ccb86a69SMichael S. Tsirkin #define DRIVER_DESC "Generic UIO driver for PCI 2.3 devices" 30ccb86a69SMichael S. Tsirkin 31ccb86a69SMichael S. Tsirkin struct uio_pci_generic_dev { 32ccb86a69SMichael S. Tsirkin struct uio_info info; 33ccb86a69SMichael S. Tsirkin struct pci_dev *pdev; 34ccb86a69SMichael S. Tsirkin }; 35ccb86a69SMichael S. Tsirkin 36ccb86a69SMichael S. Tsirkin static inline struct uio_pci_generic_dev * 37ccb86a69SMichael S. Tsirkin to_uio_pci_generic_dev(struct uio_info *info) 38ccb86a69SMichael S. Tsirkin { 39ccb86a69SMichael S. Tsirkin return container_of(info, struct uio_pci_generic_dev, info); 40ccb86a69SMichael S. Tsirkin } 41ccb86a69SMichael S. Tsirkin 42865a11f9SVenkatesh Srinivas static int release(struct uio_info *info, struct inode *inode) 43865a11f9SVenkatesh Srinivas { 44865a11f9SVenkatesh Srinivas struct uio_pci_generic_dev *gdev = to_uio_pci_generic_dev(info); 45865a11f9SVenkatesh Srinivas 46865a11f9SVenkatesh Srinivas /* 47865a11f9SVenkatesh Srinivas * This driver is insecure when used with devices doing DMA, but some 48865a11f9SVenkatesh Srinivas * people (mis)use it with such devices. 49865a11f9SVenkatesh Srinivas * Let's at least make sure DMA isn't left enabled after the userspace 50865a11f9SVenkatesh Srinivas * driver closes the fd. 51865a11f9SVenkatesh Srinivas * Note that there's a non-zero chance doing this will wedge the device 52865a11f9SVenkatesh Srinivas * at least until reset. 53865a11f9SVenkatesh Srinivas */ 54865a11f9SVenkatesh Srinivas pci_clear_master(gdev->pdev); 55865a11f9SVenkatesh Srinivas return 0; 56865a11f9SVenkatesh Srinivas } 57865a11f9SVenkatesh Srinivas 58ccb86a69SMichael S. Tsirkin /* Interrupt handler. Read/modify/write the command register to disable 59ccb86a69SMichael S. Tsirkin * the interrupt. */ 60ccb86a69SMichael S. Tsirkin static irqreturn_t irqhandler(int irq, struct uio_info *info) 61ccb86a69SMichael S. Tsirkin { 62ccb86a69SMichael S. Tsirkin struct uio_pci_generic_dev *gdev = to_uio_pci_generic_dev(info); 63ccb86a69SMichael S. Tsirkin 642502dbdfSJan Kiszka if (!pci_check_and_mask_intx(gdev->pdev)) 652502dbdfSJan Kiszka return IRQ_NONE; 66ccb86a69SMichael S. Tsirkin 67ccb86a69SMichael S. Tsirkin /* UIO core will signal the user process. */ 682502dbdfSJan Kiszka return IRQ_HANDLED; 69ccb86a69SMichael S. Tsirkin } 70ccb86a69SMichael S. Tsirkin 71b17b75bbSBill Pemberton static int probe(struct pci_dev *pdev, 72ccb86a69SMichael S. Tsirkin const struct pci_device_id *id) 73ccb86a69SMichael S. Tsirkin { 74ccb86a69SMichael S. Tsirkin struct uio_pci_generic_dev *gdev; 75ccb86a69SMichael S. Tsirkin int err; 76ccb86a69SMichael S. Tsirkin 77ef84928cSAlexandru Ardelean err = pcim_enable_device(pdev); 78ccb86a69SMichael S. Tsirkin if (err) { 79ccb86a69SMichael S. Tsirkin dev_err(&pdev->dev, "%s: pci_enable_device failed: %d\n", 80ccb86a69SMichael S. Tsirkin __func__, err); 81ccb86a69SMichael S. Tsirkin return err; 82ccb86a69SMichael S. Tsirkin } 83ccb86a69SMichael S. Tsirkin 84ef84928cSAlexandru Ardelean if (pdev->irq && !pci_intx_mask_supported(pdev)) 85ef84928cSAlexandru Ardelean return -ENOMEM; 86ccb86a69SMichael S. Tsirkin 87ef84928cSAlexandru Ardelean gdev = devm_kzalloc(&pdev->dev, sizeof(struct uio_pci_generic_dev), GFP_KERNEL); 88ef84928cSAlexandru Ardelean if (!gdev) 89ef84928cSAlexandru Ardelean return -ENOMEM; 90ccb86a69SMichael S. Tsirkin 91ccb86a69SMichael S. Tsirkin gdev->info.name = "uio_pci_generic"; 92ccb86a69SMichael S. Tsirkin gdev->info.version = DRIVER_VERSION; 93865a11f9SVenkatesh Srinivas gdev->info.release = release; 94acec09e6SJim Harris gdev->pdev = pdev; 95*61de21a8SJie Li if (pdev->irq && (pdev->irq != IRQ_NOTCONNECTED)) { 96ccb86a69SMichael S. Tsirkin gdev->info.irq = pdev->irq; 97ccb86a69SMichael S. Tsirkin gdev->info.irq_flags = IRQF_SHARED; 98ccb86a69SMichael S. Tsirkin gdev->info.handler = irqhandler; 99acec09e6SJim Harris } else { 100acec09e6SJim Harris dev_warn(&pdev->dev, "No IRQ assigned to device: " 101acec09e6SJim Harris "no support for interrupts?\n"); 102acec09e6SJim Harris } 103ccb86a69SMichael S. Tsirkin 1044849e0edSAlexandru Ardelean return devm_uio_register_device(&pdev->dev, &gdev->info); 105ccb86a69SMichael S. Tsirkin } 106ccb86a69SMichael S. Tsirkin 107cd437398SPeter Huewe static struct pci_driver uio_pci_driver = { 108ccb86a69SMichael S. Tsirkin .name = "uio_pci_generic", 109ccb86a69SMichael S. Tsirkin .id_table = NULL, /* only dynamic id's */ 110ccb86a69SMichael S. Tsirkin .probe = probe, 111ccb86a69SMichael S. Tsirkin }; 112ccb86a69SMichael S. Tsirkin 113cd437398SPeter Huewe module_pci_driver(uio_pci_driver); 114ccb86a69SMichael S. Tsirkin MODULE_VERSION(DRIVER_VERSION); 115ccb86a69SMichael S. Tsirkin MODULE_LICENSE("GPL v2"); 116ccb86a69SMichael S. Tsirkin MODULE_AUTHOR(DRIVER_AUTHOR); 117ccb86a69SMichael S. Tsirkin MODULE_DESCRIPTION(DRIVER_DESC); 118