diff options
-rw-r--r-- | Documentation/DocBook/uio-howto.tmpl | 163 | ||||
-rw-r--r-- | MAINTAINERS | 7 | ||||
-rw-r--r-- | drivers/uio/Kconfig | 10 | ||||
-rw-r--r-- | drivers/uio/Makefile | 1 | ||||
-rw-r--r-- | drivers/uio/uio_pci_generic.c | 207 | ||||
-rw-r--r-- | include/linux/pci_regs.h | 1 |
6 files changed, 389 insertions, 0 deletions
diff --git a/Documentation/DocBook/uio-howto.tmpl b/Documentation/DocBook/uio-howto.tmpl index 8f6e3b2403c7..4d4ce0e61e42 100644 --- a/Documentation/DocBook/uio-howto.tmpl +++ b/Documentation/DocBook/uio-howto.tmpl | |||
@@ -25,6 +25,10 @@ | |||
25 | <year>2006-2008</year> | 25 | <year>2006-2008</year> |
26 | <holder>Hans-Jürgen Koch.</holder> | 26 | <holder>Hans-Jürgen Koch.</holder> |
27 | </copyright> | 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 | <legalnotice> | 33 | <legalnotice> |
30 | <para> | 34 | <para> |
@@ -42,6 +46,13 @@ GPL version 2. | |||
42 | 46 | ||
43 | <revhistory> | 47 | <revhistory> |
44 | <revision> | 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 | <revnumber>0.8</revnumber> | 56 | <revnumber>0.8</revnumber> |
46 | <date>2008-12-24</date> | 57 | <date>2008-12-24</date> |
47 | <authorinitials>hjk</authorinitials> | 58 | <authorinitials>hjk</authorinitials> |
@@ -809,6 +820,158 @@ framework to set up sysfs files for this region. Simply leave it alone. | |||
809 | 820 | ||
810 | </chapter> | 821 | </chapter> |
811 | 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 "8086 10f5" > /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 > /sys/bus/pci/drivers/e1000e/unbind | ||
852 | echo -n 0000:00:19.0 > /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 -> ../../../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 <stdlib.h> | ||
904 | #include <stdio.h> | ||
905 | #include <unistd.h> | ||
906 | #include <sys/types.h> | ||
907 | #include <sys/stat.h> | ||
908 | #include <fcntl.h> | ||
909 | #include <errno.h> | ||
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("/dev/uio0", O_RDONLY); | ||
921 | if (uiofd < 0) { | ||
922 | perror("uio open:"); | ||
923 | return errno; | ||
924 | } | ||
925 | configfd = open("/sys/class/uio/uio0/device/config", O_RDWR); | ||
926 | if (uiofd < 0) { | ||
927 | perror("config open:"); | ||
928 | return errno; | ||
929 | } | ||
930 | |||
931 | /* Read and cache command value */ | ||
932 | err = pread(configfd, &command_high, 1, 5); | ||
933 | if (err != 1) { | ||
934 | perror("command config read:"); | ||
935 | return errno; | ||
936 | } | ||
937 | command_high &= ~0x4; | ||
938 | |||
939 | for(i = 0;; ++i) { | ||
940 | /* Print out a message, for debugging. */ | ||
941 | if (i == 0) | ||
942 | fprintf(stderr, "Started uio test driver.\n"); | ||
943 | else | ||
944 | fprintf(stderr, "Interrupts: %d\n", 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, &command_high, 1, 5); | ||
953 | if (err != 1) { | ||
954 | perror("config write:"); | ||
955 | break; | ||
956 | } | ||
957 | |||
958 | /* Wait for next interrupt. */ | ||
959 | err = read(uiofd, &icount, 4); | ||
960 | if (err != 4) { | ||
961 | perror("uio read:"); | ||
962 | break; | ||
963 | } | ||
964 | |||
965 | } | ||
966 | return errno; | ||
967 | } | ||
968 | |||
969 | </programlisting> | ||
970 | </para> | ||
971 | </sect1> | ||
972 | |||
973 | </chapter> | ||
974 | |||
812 | <appendix id="app1"> | 975 | <appendix id="app1"> |
813 | <title>Further information</title> | 976 | <title>Further information</title> |
814 | <itemizedlist> | 977 | <itemizedlist> |
diff --git a/MAINTAINERS b/MAINTAINERS index 837b5985ac40..01193a4fe30e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -2218,6 +2218,13 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/arnd/asm-generic.git | |||
2218 | S: Maintained | 2218 | S: Maintained |
2219 | F: include/asm-generic | 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 | GFS2 FILE SYSTEM | 2228 | GFS2 FILE SYSTEM |
2222 | M: Steven Whitehouse <swhiteho@redhat.com> | 2229 | M: Steven Whitehouse <swhiteho@redhat.com> |
2223 | L: cluster-devel@redhat.com | 2230 | L: cluster-devel@redhat.com |
diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig index 45200fd68534..8aa1955f35ed 100644 --- a/drivers/uio/Kconfig +++ b/drivers/uio/Kconfig | |||
@@ -84,4 +84,14 @@ config UIO_SERCOS3 | |||
84 | 84 | ||
85 | If you compile this as a module, it will be called uio_sercos3. | 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 | endif | 97 | endif |
diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile index 5c2586d75797..73b2e7516729 100644 --- a/drivers/uio/Makefile +++ b/drivers/uio/Makefile | |||
@@ -5,3 +5,4 @@ obj-$(CONFIG_UIO_PDRV_GENIRQ) += uio_pdrv_genirq.o | |||
5 | obj-$(CONFIG_UIO_SMX) += uio_smx.o | 5 | obj-$(CONFIG_UIO_SMX) += uio_smx.o |
6 | obj-$(CONFIG_UIO_AEC) += uio_aec.o | 6 | obj-$(CONFIG_UIO_AEC) += uio_aec.o |
7 | obj-$(CONFIG_UIO_SERCOS3) += uio_sercos3.o | 7 | obj-$(CONFIG_UIO_SERCOS3) += uio_sercos3.o |
8 | obj-$(CONFIG_UIO_PCI_GENERIC) += uio_pci_generic.o | ||
diff --git a/drivers/uio/uio_pci_generic.c b/drivers/uio/uio_pci_generic.c new file mode 100644 index 000000000000..313da35984af --- /dev/null +++ b/drivers/uio/uio_pci_generic.c | |||
@@ -0,0 +1,207 @@ | |||
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); | ||
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index fcaee42c7ac2..dd0bed4f1cf0 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h | |||
@@ -42,6 +42,7 @@ | |||
42 | #define PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */ | 42 | #define PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */ |
43 | 43 | ||
44 | #define PCI_STATUS 0x06 /* 16 bits */ | 44 | #define PCI_STATUS 0x06 /* 16 bits */ |
45 | #define PCI_STATUS_INTERRUPT 0x08 /* Interrupt status */ | ||
45 | #define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */ | 46 | #define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */ |
46 | #define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */ | 47 | #define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */ |
47 | #define PCI_STATUS_UDF 0x40 /* Support User Definable Features [obsolete] */ | 48 | #define PCI_STATUS_UDF 0x40 /* Support User Definable Features [obsolete] */ |