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