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