Commit ccb86a6907c9ba7b5be5f521362fc308e80bed34

Authored by Michael S. Tsirkin
Committed by Greg Kroah-Hartman
1 parent a56af87648

uio: add generic driver for PCI 2.3 devices

This adds a generic uio driver that can bind to any PCI device.  First
user will be virtualization where a qemu userspace process needs to give
guest OS access to the device.

Interrupts are handled using the Interrupt Disable bit in the PCI
command register and Interrupt Status bit in the PCI status register.
All devices compliant to PCI 2.3 (circa 2002) and all compliant PCI
Express devices should support these bits.  Driver detects this support,
and won't bind to devices which do not support the Interrupt Disable Bit
in the command register.

It's expected that more features of interest to virtualization will be
added to this driver in the future. Possibilities are: mmap for device
resources, MSI/MSI-X, eventfd (to interface with kvm), iommu.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Acked-by: Chris Wright <chrisw@redhat.com>
Signed-off-by: Hans J. Koch <hjk@linutronix.de>
Acked-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

Showing 6 changed files with 389 additions and 0 deletions Side-by-side Diff

Documentation/DocBook/uio-howto.tmpl
... ... @@ -25,6 +25,10 @@
25 25 <year>2006-2008</year>
26 26 <holder>Hans-Jürgen Koch.</holder>
27 27 </copyright>
  28 +<copyright>
  29 + <year>2009</year>
  30 + <holder>Red Hat Inc, Michael S. Tsirkin (mst@redhat.com)</holder>
  31 +</copyright>
28 32  
29 33 <legalnotice>
30 34 <para>
... ... @@ -42,6 +46,13 @@
42 46  
43 47 <revhistory>
44 48 <revision>
  49 + <revnumber>0.9</revnumber>
  50 + <date>2009-07-16</date>
  51 + <authorinitials>mst</authorinitials>
  52 + <revremark>Added generic pci driver
  53 + </revremark>
  54 + </revision>
  55 + <revision>
45 56 <revnumber>0.8</revnumber>
46 57 <date>2008-12-24</date>
47 58 <authorinitials>hjk</authorinitials>
... ... @@ -804,6 +815,158 @@
804 815 <para>
805 816 You can also use <function>select()</function> on
806 817 <filename>/dev/uioX</filename>.
  818 + </para>
  819 +</sect1>
  820 +
  821 +</chapter>
  822 +
  823 +<chapter id="uio_pci_generic" xreflabel="Using Generic driver for PCI cards">
  824 +<?dbhtml filename="uio_pci_generic.html"?>
  825 +<title>Generic PCI UIO driver</title>
  826 + <para>
  827 + The generic driver is a kernel module named uio_pci_generic.
  828 + It can work with any device compliant to PCI 2.3 (circa 2002) and
  829 + any compliant PCI Express device. Using this, you only need to
  830 + write the userspace driver, removing the need to write
  831 + a hardware-specific kernel module.
  832 + </para>
  833 +
  834 +<sect1 id="uio_pci_generic_binding">
  835 +<title>Making the driver recognize the device</title>
  836 + <para>
  837 +Since the driver does not declare any device ids, it will not get loaded
  838 +automatically and will not automatically bind to any devices, you must load it
  839 +and allocate id to the driver yourself. For example:
  840 + <programlisting>
  841 + modprobe uio_pci_generic
  842 + echo &quot;8086 10f5&quot; &gt; /sys/bus/pci/drivers/uio_pci_generic/new_id
  843 + </programlisting>
  844 + </para>
  845 + <para>
  846 +If there already is a hardware specific kernel driver for your device, the
  847 +generic driver still won't bind to it, in this case if you want to use the
  848 +generic driver (why would you?) you'll have to manually unbind the hardware
  849 +specific driver and bind the generic driver, like this:
  850 + <programlisting>
  851 + echo -n 0000:00:19.0 &gt; /sys/bus/pci/drivers/e1000e/unbind
  852 + echo -n 0000:00:19.0 &gt; /sys/bus/pci/drivers/uio_pci_generic/bind
  853 + </programlisting>
  854 + </para>
  855 + <para>
  856 +You can verify that the device has been bound to the driver
  857 +by looking for it in sysfs, for example like the following:
  858 + <programlisting>
  859 + ls -l /sys/bus/pci/devices/0000:00:19.0/driver
  860 + </programlisting>
  861 +Which if successful should print
  862 + <programlisting>
  863 + .../0000:00:19.0/driver -&gt; ../../../bus/pci/drivers/uio_pci_generic
  864 + </programlisting>
  865 +Note that the generic driver will not bind to old PCI 2.2 devices.
  866 +If binding the device failed, run the following command:
  867 + <programlisting>
  868 + dmesg
  869 + </programlisting>
  870 +and look in the output for failure reasons
  871 + </para>
  872 +</sect1>
  873 +
  874 +<sect1 id="uio_pci_generic_internals">
  875 +<title>Things to know about uio_pci_generic</title>
  876 + <para>
  877 +Interrupts are handled using the Interrupt Disable bit in the PCI command
  878 +register and Interrupt Status bit in the PCI status register. All devices
  879 +compliant to PCI 2.3 (circa 2002) and all compliant PCI Express devices should
  880 +support these bits. uio_pci_generic detects this support, and won't bind to
  881 +devices which do not support the Interrupt Disable Bit in the command register.
  882 + </para>
  883 + <para>
  884 +On each interrupt, uio_pci_generic sets the Interrupt Disable bit.
  885 +This prevents the device from generating further interrupts
  886 +until the bit is cleared. The userspace driver should clear this
  887 +bit before blocking and waiting for more interrupts.
  888 + </para>
  889 +</sect1>
  890 +<sect1 id="uio_pci_generic_userspace">
  891 +<title>Writing userspace driver using uio_pci_generic</title>
  892 + <para>
  893 +Userspace driver can use pci sysfs interface, or the
  894 +libpci libray that wraps it, to talk to the device and to
  895 +re-enable interrupts by writing to the command register.
  896 + </para>
  897 +</sect1>
  898 +<sect1 id="uio_pci_generic_example">
  899 +<title>Example code using uio_pci_generic</title>
  900 + <para>
  901 +Here is some sample userspace driver code using uio_pci_generic:
  902 +<programlisting>
  903 +#include &lt;stdlib.h&gt;
  904 +#include &lt;stdio.h&gt;
  905 +#include &lt;unistd.h&gt;
  906 +#include &lt;sys/types.h&gt;
  907 +#include &lt;sys/stat.h&gt;
  908 +#include &lt;fcntl.h&gt;
  909 +#include &lt;errno.h&gt;
  910 +
  911 +int main()
  912 +{
  913 + int uiofd;
  914 + int configfd;
  915 + int err;
  916 + int i;
  917 + unsigned icount;
  918 + unsigned char command_high;
  919 +
  920 + uiofd = open(&quot;/dev/uio0&quot;, O_RDONLY);
  921 + if (uiofd &lt; 0) {
  922 + perror(&quot;uio open:&quot;);
  923 + return errno;
  924 + }
  925 + configfd = open(&quot;/sys/class/uio/uio0/device/config&quot;, O_RDWR);
  926 + if (uiofd &lt; 0) {
  927 + perror(&quot;config open:&quot;);
  928 + return errno;
  929 + }
  930 +
  931 + /* Read and cache command value */
  932 + err = pread(configfd, &amp;command_high, 1, 5);
  933 + if (err != 1) {
  934 + perror(&quot;command config read:&quot;);
  935 + return errno;
  936 + }
  937 + command_high &amp;= ~0x4;
  938 +
  939 + for(i = 0;; ++i) {
  940 + /* Print out a message, for debugging. */
  941 + if (i == 0)
  942 + fprintf(stderr, &quot;Started uio test driver.\n&quot;);
  943 + else
  944 + fprintf(stderr, &quot;Interrupts: %d\n&quot;, icount);
  945 +
  946 + /****************************************/
  947 + /* Here we got an interrupt from the
  948 + device. Do something to it. */
  949 + /****************************************/
  950 +
  951 + /* Re-enable interrupts. */
  952 + err = pwrite(configfd, &amp;command_high, 1, 5);
  953 + if (err != 1) {
  954 + perror(&quot;config write:&quot;);
  955 + break;
  956 + }
  957 +
  958 + /* Wait for next interrupt. */
  959 + err = read(uiofd, &amp;icount, 4);
  960 + if (err != 4) {
  961 + perror(&quot;uio read:&quot;);
  962 + break;
  963 + }
  964 +
  965 + }
  966 + return errno;
  967 +}
  968 +
  969 +</programlisting>
807 970 </para>
808 971 </sect1>
809 972  
... ... @@ -2218,6 +2218,13 @@
2218 2218 S: Maintained
2219 2219 F: include/asm-generic
2220 2220  
  2221 +GENERIC UIO DRIVER FOR PCI DEVICES
  2222 +M: Michael S. Tsirkin <mst@redhat.com>
  2223 +L: kvm@vger.kernel.org
  2224 +L: linux-kernel@vger.kernel.org
  2225 +S: Supported
  2226 +F: drivers/uio/uio_pci_generic.c
  2227 +
2221 2228 GFS2 FILE SYSTEM
2222 2229 M: Steven Whitehouse <swhiteho@redhat.com>
2223 2230 L: cluster-devel@redhat.com
... ... @@ -84,5 +84,15 @@
84 84  
85 85 If you compile this as a module, it will be called uio_sercos3.
86 86  
  87 +config UIO_PCI_GENERIC
  88 + tristate "Generic driver for PCI 2.3 and PCI Express cards"
  89 + depends on PCI
  90 + default n
  91 + help
  92 + Generic driver that you can bind, dynamically, to any
  93 + PCI 2.3 compliant and PCI Express card. It is useful,
  94 + primarily, for virtualization scenarios.
  95 + If you compile this as a module, it will be called uio_pci_generic.
  96 +
87 97 endif
drivers/uio/Makefile
... ... @@ -5,4 +5,5 @@
5 5 obj-$(CONFIG_UIO_SMX) += uio_smx.o
6 6 obj-$(CONFIG_UIO_AEC) += uio_aec.o
7 7 obj-$(CONFIG_UIO_SERCOS3) += uio_sercos3.o
  8 +obj-$(CONFIG_UIO_PCI_GENERIC) += uio_pci_generic.o
drivers/uio/uio_pci_generic.c
  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 +
  32 +struct uio_pci_generic_dev {
  33 + struct uio_info info;
  34 + struct pci_dev *pdev;
  35 + spinlock_t lock; /* guards command register accesses */
  36 +};
  37 +
  38 +static inline struct uio_pci_generic_dev *
  39 +to_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. */
  46 +static 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;
  82 +done:
  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. */
  92 +static 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);
  119 +err:
  120 + pci_unblock_user_cfg_access(pdev);
  121 + return err;
  122 +}
  123 +
  124 +static 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;
  166 +err_register:
  167 + kfree(gdev);
  168 +err_alloc:
  169 +err_verify:
  170 + pci_disable_device(pdev);
  171 + return err;
  172 +}
  173 +
  174 +static 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 +
  183 +static 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 +
  190 +static int __init init(void)
  191 +{
  192 + pr_info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
  193 + return pci_register_driver(&driver);
  194 +}
  195 +
  196 +static void __exit cleanup(void)
  197 +{
  198 + pci_unregister_driver(&driver);
  199 +}
  200 +
  201 +module_init(init);
  202 +module_exit(cleanup);
  203 +
  204 +MODULE_VERSION(DRIVER_VERSION);
  205 +MODULE_LICENSE("GPL v2");
  206 +MODULE_AUTHOR(DRIVER_AUTHOR);
  207 +MODULE_DESCRIPTION(DRIVER_DESC);
include/linux/pci_regs.h
... ... @@ -42,6 +42,7 @@
42 42 #define PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */
43 43  
44 44 #define PCI_STATUS 0x06 /* 16 bits */
  45 +#define PCI_STATUS_INTERRUPT 0x08 /* Interrupt status */
45 46 #define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */
46 47 #define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */
47 48 #define PCI_STATUS_UDF 0x40 /* Support User Definable Features [obsolete] */