1*ccb86a69SMichael S. Tsirkin /* uio_pci_generic - generic UIO driver for PCI 2.3 devices 2*ccb86a69SMichael S. Tsirkin * 3*ccb86a69SMichael S. Tsirkin * Copyright (C) 2009 Red Hat, Inc. 4*ccb86a69SMichael S. Tsirkin * Author: Michael S. Tsirkin <mst@redhat.com> 5*ccb86a69SMichael S. Tsirkin * 6*ccb86a69SMichael S. Tsirkin * This work is licensed under the terms of the GNU GPL, version 2. 7*ccb86a69SMichael S. Tsirkin * 8*ccb86a69SMichael S. Tsirkin * Since the driver does not declare any device ids, you must allocate 9*ccb86a69SMichael S. Tsirkin * id and bind the device to the driver yourself. For example: 10*ccb86a69SMichael S. Tsirkin * 11*ccb86a69SMichael S. Tsirkin * # echo "8086 10f5" > /sys/bus/pci/drivers/uio_pci_generic/new_id 12*ccb86a69SMichael S. Tsirkin * # echo -n 0000:00:19.0 > /sys/bus/pci/drivers/e1000e/unbind 13*ccb86a69SMichael S. Tsirkin * # echo -n 0000:00:19.0 > /sys/bus/pci/drivers/uio_pci_generic/bind 14*ccb86a69SMichael S. Tsirkin * # ls -l /sys/bus/pci/devices/0000:00:19.0/driver 15*ccb86a69SMichael S. Tsirkin * .../0000:00:19.0/driver -> ../../../bus/pci/drivers/uio_pci_generic 16*ccb86a69SMichael S. Tsirkin * 17*ccb86a69SMichael S. Tsirkin * Driver won't bind to devices which do not support the Interrupt Disable Bit 18*ccb86a69SMichael S. Tsirkin * in the command register. All devices compliant to PCI 2.3 (circa 2002) and 19*ccb86a69SMichael S. Tsirkin * all compliant PCI Express devices should support this bit. 20*ccb86a69SMichael S. Tsirkin */ 21*ccb86a69SMichael S. Tsirkin 22*ccb86a69SMichael S. Tsirkin #include <linux/device.h> 23*ccb86a69SMichael S. Tsirkin #include <linux/module.h> 24*ccb86a69SMichael S. Tsirkin #include <linux/pci.h> 25*ccb86a69SMichael S. Tsirkin #include <linux/uio_driver.h> 26*ccb86a69SMichael S. Tsirkin #include <linux/spinlock.h> 27*ccb86a69SMichael S. Tsirkin 28*ccb86a69SMichael S. Tsirkin #define DRIVER_VERSION "0.01.0" 29*ccb86a69SMichael S. Tsirkin #define DRIVER_AUTHOR "Michael S. Tsirkin <mst@redhat.com>" 30*ccb86a69SMichael S. Tsirkin #define DRIVER_DESC "Generic UIO driver for PCI 2.3 devices" 31*ccb86a69SMichael S. Tsirkin 32*ccb86a69SMichael S. Tsirkin struct uio_pci_generic_dev { 33*ccb86a69SMichael S. Tsirkin struct uio_info info; 34*ccb86a69SMichael S. Tsirkin struct pci_dev *pdev; 35*ccb86a69SMichael S. Tsirkin spinlock_t lock; /* guards command register accesses */ 36*ccb86a69SMichael S. Tsirkin }; 37*ccb86a69SMichael S. Tsirkin 38*ccb86a69SMichael S. Tsirkin static inline struct uio_pci_generic_dev * 39*ccb86a69SMichael S. Tsirkin to_uio_pci_generic_dev(struct uio_info *info) 40*ccb86a69SMichael S. Tsirkin { 41*ccb86a69SMichael S. Tsirkin return container_of(info, struct uio_pci_generic_dev, info); 42*ccb86a69SMichael S. Tsirkin } 43*ccb86a69SMichael S. Tsirkin 44*ccb86a69SMichael S. Tsirkin /* Interrupt handler. Read/modify/write the command register to disable 45*ccb86a69SMichael S. Tsirkin * the interrupt. */ 46*ccb86a69SMichael S. Tsirkin static irqreturn_t irqhandler(int irq, struct uio_info *info) 47*ccb86a69SMichael S. Tsirkin { 48*ccb86a69SMichael S. Tsirkin struct uio_pci_generic_dev *gdev = to_uio_pci_generic_dev(info); 49*ccb86a69SMichael S. Tsirkin struct pci_dev *pdev = gdev->pdev; 50*ccb86a69SMichael S. Tsirkin irqreturn_t ret = IRQ_NONE; 51*ccb86a69SMichael S. Tsirkin u32 cmd_status_dword; 52*ccb86a69SMichael S. Tsirkin u16 origcmd, newcmd, status; 53*ccb86a69SMichael S. Tsirkin 54*ccb86a69SMichael S. Tsirkin /* We do a single dword read to retrieve both command and status. 55*ccb86a69SMichael S. Tsirkin * Document assumptions that make this possible. */ 56*ccb86a69SMichael S. Tsirkin BUILD_BUG_ON(PCI_COMMAND % 4); 57*ccb86a69SMichael S. Tsirkin BUILD_BUG_ON(PCI_COMMAND + 2 != PCI_STATUS); 58*ccb86a69SMichael S. Tsirkin 59*ccb86a69SMichael S. Tsirkin spin_lock_irq(&gdev->lock); 60*ccb86a69SMichael S. Tsirkin pci_block_user_cfg_access(pdev); 61*ccb86a69SMichael S. Tsirkin 62*ccb86a69SMichael S. Tsirkin /* Read both command and status registers in a single 32-bit operation. 63*ccb86a69SMichael S. Tsirkin * Note: we could cache the value for command and move the status read 64*ccb86a69SMichael S. Tsirkin * out of the lock if there was a way to get notified of user changes 65*ccb86a69SMichael S. Tsirkin * to command register through sysfs. Should be good for shared irqs. */ 66*ccb86a69SMichael S. Tsirkin pci_read_config_dword(pdev, PCI_COMMAND, &cmd_status_dword); 67*ccb86a69SMichael S. Tsirkin origcmd = cmd_status_dword; 68*ccb86a69SMichael S. Tsirkin status = cmd_status_dword >> 16; 69*ccb86a69SMichael S. Tsirkin 70*ccb86a69SMichael S. Tsirkin /* Check interrupt status register to see whether our device 71*ccb86a69SMichael S. Tsirkin * triggered the interrupt. */ 72*ccb86a69SMichael S. Tsirkin if (!(status & PCI_STATUS_INTERRUPT)) 73*ccb86a69SMichael S. Tsirkin goto done; 74*ccb86a69SMichael S. Tsirkin 75*ccb86a69SMichael S. Tsirkin /* We triggered the interrupt, disable it. */ 76*ccb86a69SMichael S. Tsirkin newcmd = origcmd | PCI_COMMAND_INTX_DISABLE; 77*ccb86a69SMichael S. Tsirkin if (newcmd != origcmd) 78*ccb86a69SMichael S. Tsirkin pci_write_config_word(pdev, PCI_COMMAND, newcmd); 79*ccb86a69SMichael S. Tsirkin 80*ccb86a69SMichael S. Tsirkin /* UIO core will signal the user process. */ 81*ccb86a69SMichael S. Tsirkin ret = IRQ_HANDLED; 82*ccb86a69SMichael S. Tsirkin done: 83*ccb86a69SMichael S. Tsirkin 84*ccb86a69SMichael S. Tsirkin pci_unblock_user_cfg_access(pdev); 85*ccb86a69SMichael S. Tsirkin spin_unlock_irq(&gdev->lock); 86*ccb86a69SMichael S. Tsirkin return ret; 87*ccb86a69SMichael S. Tsirkin } 88*ccb86a69SMichael S. Tsirkin 89*ccb86a69SMichael S. Tsirkin /* Verify that the device supports Interrupt Disable bit in command register, 90*ccb86a69SMichael S. Tsirkin * per PCI 2.3, by flipping this bit and reading it back: this bit was readonly 91*ccb86a69SMichael S. Tsirkin * in PCI 2.2. */ 92*ccb86a69SMichael S. Tsirkin static int __devinit verify_pci_2_3(struct pci_dev *pdev) 93*ccb86a69SMichael S. Tsirkin { 94*ccb86a69SMichael S. Tsirkin u16 orig, new; 95*ccb86a69SMichael S. Tsirkin int err = 0; 96*ccb86a69SMichael S. Tsirkin 97*ccb86a69SMichael S. Tsirkin pci_block_user_cfg_access(pdev); 98*ccb86a69SMichael S. Tsirkin pci_read_config_word(pdev, PCI_COMMAND, &orig); 99*ccb86a69SMichael S. Tsirkin pci_write_config_word(pdev, PCI_COMMAND, 100*ccb86a69SMichael S. Tsirkin orig ^ PCI_COMMAND_INTX_DISABLE); 101*ccb86a69SMichael S. Tsirkin pci_read_config_word(pdev, PCI_COMMAND, &new); 102*ccb86a69SMichael S. Tsirkin /* There's no way to protect against 103*ccb86a69SMichael S. Tsirkin * hardware bugs or detect them reliably, but as long as we know 104*ccb86a69SMichael S. Tsirkin * what the value should be, let's go ahead and check it. */ 105*ccb86a69SMichael S. Tsirkin if ((new ^ orig) & ~PCI_COMMAND_INTX_DISABLE) { 106*ccb86a69SMichael S. Tsirkin err = -EBUSY; 107*ccb86a69SMichael S. Tsirkin dev_err(&pdev->dev, "Command changed from 0x%x to 0x%x: " 108*ccb86a69SMichael S. Tsirkin "driver or HW bug?\n", orig, new); 109*ccb86a69SMichael S. Tsirkin goto err; 110*ccb86a69SMichael S. Tsirkin } 111*ccb86a69SMichael S. Tsirkin if (!((new ^ orig) & PCI_COMMAND_INTX_DISABLE)) { 112*ccb86a69SMichael S. Tsirkin dev_warn(&pdev->dev, "Device does not support " 113*ccb86a69SMichael S. Tsirkin "disabling interrupts: unable to bind.\n"); 114*ccb86a69SMichael S. Tsirkin err = -ENODEV; 115*ccb86a69SMichael S. Tsirkin goto err; 116*ccb86a69SMichael S. Tsirkin } 117*ccb86a69SMichael S. Tsirkin /* Now restore the original value. */ 118*ccb86a69SMichael S. Tsirkin pci_write_config_word(pdev, PCI_COMMAND, orig); 119*ccb86a69SMichael S. Tsirkin err: 120*ccb86a69SMichael S. Tsirkin pci_unblock_user_cfg_access(pdev); 121*ccb86a69SMichael S. Tsirkin return err; 122*ccb86a69SMichael S. Tsirkin } 123*ccb86a69SMichael S. Tsirkin 124*ccb86a69SMichael S. Tsirkin static int __devinit probe(struct pci_dev *pdev, 125*ccb86a69SMichael S. Tsirkin const struct pci_device_id *id) 126*ccb86a69SMichael S. Tsirkin { 127*ccb86a69SMichael S. Tsirkin struct uio_pci_generic_dev *gdev; 128*ccb86a69SMichael S. Tsirkin int err; 129*ccb86a69SMichael S. Tsirkin 130*ccb86a69SMichael S. Tsirkin if (!pdev->irq) { 131*ccb86a69SMichael S. Tsirkin dev_warn(&pdev->dev, "No IRQ assigned to device: " 132*ccb86a69SMichael S. Tsirkin "no support for interrupts?\n"); 133*ccb86a69SMichael S. Tsirkin return -ENODEV; 134*ccb86a69SMichael S. Tsirkin } 135*ccb86a69SMichael S. Tsirkin 136*ccb86a69SMichael S. Tsirkin err = pci_enable_device(pdev); 137*ccb86a69SMichael S. Tsirkin if (err) { 138*ccb86a69SMichael S. Tsirkin dev_err(&pdev->dev, "%s: pci_enable_device failed: %d\n", 139*ccb86a69SMichael S. Tsirkin __func__, err); 140*ccb86a69SMichael S. Tsirkin return err; 141*ccb86a69SMichael S. Tsirkin } 142*ccb86a69SMichael S. Tsirkin 143*ccb86a69SMichael S. Tsirkin err = verify_pci_2_3(pdev); 144*ccb86a69SMichael S. Tsirkin if (err) 145*ccb86a69SMichael S. Tsirkin goto err_verify; 146*ccb86a69SMichael S. Tsirkin 147*ccb86a69SMichael S. Tsirkin gdev = kzalloc(sizeof(struct uio_pci_generic_dev), GFP_KERNEL); 148*ccb86a69SMichael S. Tsirkin if (!gdev) { 149*ccb86a69SMichael S. Tsirkin err = -ENOMEM; 150*ccb86a69SMichael S. Tsirkin goto err_alloc; 151*ccb86a69SMichael S. Tsirkin } 152*ccb86a69SMichael S. Tsirkin 153*ccb86a69SMichael S. Tsirkin gdev->info.name = "uio_pci_generic"; 154*ccb86a69SMichael S. Tsirkin gdev->info.version = DRIVER_VERSION; 155*ccb86a69SMichael S. Tsirkin gdev->info.irq = pdev->irq; 156*ccb86a69SMichael S. Tsirkin gdev->info.irq_flags = IRQF_SHARED; 157*ccb86a69SMichael S. Tsirkin gdev->info.handler = irqhandler; 158*ccb86a69SMichael S. Tsirkin gdev->pdev = pdev; 159*ccb86a69SMichael S. Tsirkin spin_lock_init(&gdev->lock); 160*ccb86a69SMichael S. Tsirkin 161*ccb86a69SMichael S. Tsirkin if (uio_register_device(&pdev->dev, &gdev->info)) 162*ccb86a69SMichael S. Tsirkin goto err_register; 163*ccb86a69SMichael S. Tsirkin pci_set_drvdata(pdev, gdev); 164*ccb86a69SMichael S. Tsirkin 165*ccb86a69SMichael S. Tsirkin return 0; 166*ccb86a69SMichael S. Tsirkin err_register: 167*ccb86a69SMichael S. Tsirkin kfree(gdev); 168*ccb86a69SMichael S. Tsirkin err_alloc: 169*ccb86a69SMichael S. Tsirkin err_verify: 170*ccb86a69SMichael S. Tsirkin pci_disable_device(pdev); 171*ccb86a69SMichael S. Tsirkin return err; 172*ccb86a69SMichael S. Tsirkin } 173*ccb86a69SMichael S. Tsirkin 174*ccb86a69SMichael S. Tsirkin static void remove(struct pci_dev *pdev) 175*ccb86a69SMichael S. Tsirkin { 176*ccb86a69SMichael S. Tsirkin struct uio_pci_generic_dev *gdev = pci_get_drvdata(pdev); 177*ccb86a69SMichael S. Tsirkin 178*ccb86a69SMichael S. Tsirkin uio_unregister_device(&gdev->info); 179*ccb86a69SMichael S. Tsirkin pci_disable_device(pdev); 180*ccb86a69SMichael S. Tsirkin kfree(gdev); 181*ccb86a69SMichael S. Tsirkin } 182*ccb86a69SMichael S. Tsirkin 183*ccb86a69SMichael S. Tsirkin static struct pci_driver driver = { 184*ccb86a69SMichael S. Tsirkin .name = "uio_pci_generic", 185*ccb86a69SMichael S. Tsirkin .id_table = NULL, /* only dynamic id's */ 186*ccb86a69SMichael S. Tsirkin .probe = probe, 187*ccb86a69SMichael S. Tsirkin .remove = remove, 188*ccb86a69SMichael S. Tsirkin }; 189*ccb86a69SMichael S. Tsirkin 190*ccb86a69SMichael S. Tsirkin static int __init init(void) 191*ccb86a69SMichael S. Tsirkin { 192*ccb86a69SMichael S. Tsirkin pr_info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); 193*ccb86a69SMichael S. Tsirkin return pci_register_driver(&driver); 194*ccb86a69SMichael S. Tsirkin } 195*ccb86a69SMichael S. Tsirkin 196*ccb86a69SMichael S. Tsirkin static void __exit cleanup(void) 197*ccb86a69SMichael S. Tsirkin { 198*ccb86a69SMichael S. Tsirkin pci_unregister_driver(&driver); 199*ccb86a69SMichael S. Tsirkin } 200*ccb86a69SMichael S. Tsirkin 201*ccb86a69SMichael S. Tsirkin module_init(init); 202*ccb86a69SMichael S. Tsirkin module_exit(cleanup); 203*ccb86a69SMichael S. Tsirkin 204*ccb86a69SMichael S. Tsirkin MODULE_VERSION(DRIVER_VERSION); 205*ccb86a69SMichael S. Tsirkin MODULE_LICENSE("GPL v2"); 206*ccb86a69SMichael S. Tsirkin MODULE_AUTHOR(DRIVER_AUTHOR); 207*ccb86a69SMichael S. Tsirkin MODULE_DESCRIPTION(DRIVER_DESC); 208