ia64/linux-2.6.18-xen.hg

view drivers/pci/syscall.c @ 882:8dec4aa9b8b9

PCI pass through: PCIe IO space multiplexing

This is required for more than 16 HVM domain to boot from
PCIe pass through device.

Linux as dom0 exclusively assigns IO space to downstream PCI bridges
and the assignment unit of PCI bridge IO space is 4K. So the only up
to 16 PCIe device can be accessed via IO space within 64K IO ports.
PCI expansion ROM BIOS often uses IO port access to boot from the
device, so on virtualized environment, it means only up to 16 guest
domain can boot from pass-through device.

This patch allows PCIe IO space sharing of pass-through device.
- reassign IO space of PCIe devices specified by
"guestiomuldev=[<segment>:]<bus>:<dev>[,[<segment:><bus>:dev]][,...]"
to be shared.
This is implemented as Linux PCI quirk fixup.

The sharing unit is PCIe switch. Ie IO space of the end point
devices under the same switch will be shared. If there are more than
one switches, two areas of IO space will be used.

- And the driver which arbitrates the accesses to the multiplexed PCIe
IO space. Later qemu-dm will use this.

Limitation:
IO port of IO shared devices can't be accessed from dom0 Linux device
driver. But this wouldn't be a big issue because PCIe specification
discourages the use of IO space and recommends that IO space should be
used only for bootable device with ROM code. OS device driver should
work without IO space access.

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
author Keir Fraser <keir.fraser@citrix.com>
date Thu May 28 09:57:49 2009 +0100 (2009-05-28)
parents 831230e53067
children
line source
1 /*
2 * pci_syscall.c
3 *
4 * For architectures where we want to allow direct access
5 * to the PCI config stuff - it would probably be preferable
6 * on PCs too, but there people just do it by hand with the
7 * magic northbridge registers..
8 */
10 #include <linux/sched.h>
11 #include <linux/errno.h>
12 #include <linux/pci.h>
13 #include <linux/smp_lock.h>
14 #include <linux/syscalls.h>
15 #include <asm/uaccess.h>
16 #include "pci.h"
18 asmlinkage long
19 sys_pciconfig_read(unsigned long bus, unsigned long dfn,
20 unsigned long off, unsigned long len,
21 void __user *buf)
22 {
23 struct pci_dev *dev;
24 u8 byte;
25 u16 word;
26 u32 dword;
27 long err, cfg_ret;
29 err = -EPERM;
30 if (!capable(CAP_SYS_ADMIN))
31 goto error;
33 err = -ENODEV;
34 dev = pci_find_slot(bus, dfn);
35 if (!dev)
36 goto error;
38 lock_kernel();
39 switch (len) {
40 case 1:
41 cfg_ret = pci_user_read_config_byte(dev, off, &byte);
42 break;
43 case 2:
44 cfg_ret = pci_user_read_config_word(dev, off, &word);
45 break;
46 case 4:
47 cfg_ret = pci_user_read_config_dword(dev, off, &dword);
48 break;
49 default:
50 err = -EINVAL;
51 unlock_kernel();
52 goto error;
53 };
54 unlock_kernel();
56 err = -EIO;
57 if (cfg_ret != PCIBIOS_SUCCESSFUL)
58 goto error;
60 switch (len) {
61 case 1:
62 err = put_user(byte, (unsigned char __user *)buf);
63 break;
64 case 2:
65 err = put_user(word, (unsigned short __user *)buf);
66 break;
67 case 4:
68 err = put_user(dword, (unsigned int __user *)buf);
69 break;
70 };
71 return err;
73 error:
74 /* ??? XFree86 doesn't even check the return value. They
75 just look for 0xffffffff in the output, since that's what
76 they get instead of a machine check on x86. */
77 switch (len) {
78 case 1:
79 put_user(-1, (unsigned char __user *)buf);
80 break;
81 case 2:
82 put_user(-1, (unsigned short __user *)buf);
83 break;
84 case 4:
85 put_user(-1, (unsigned int __user *)buf);
86 break;
87 };
88 return err;
89 }
91 asmlinkage long
92 sys_pciconfig_write(unsigned long bus, unsigned long dfn,
93 unsigned long off, unsigned long len,
94 void __user *buf)
95 {
96 struct pci_dev *dev;
97 u8 byte;
98 u16 word;
99 u32 dword;
100 int err = 0;
102 if (!capable(CAP_SYS_ADMIN))
103 return -EPERM;
105 dev = pci_find_slot(bus, dfn);
106 if (!dev)
107 return -ENODEV;
109 lock_kernel();
110 switch(len) {
111 case 1:
112 err = get_user(byte, (u8 __user *)buf);
113 if (err)
114 break;
115 err = pci_user_write_config_byte(dev, off, byte);
116 if (err != PCIBIOS_SUCCESSFUL)
117 err = -EIO;
118 break;
120 case 2:
121 err = get_user(word, (u16 __user *)buf);
122 if (err)
123 break;
124 err = pci_user_write_config_word(dev, off, word);
125 if (err != PCIBIOS_SUCCESSFUL)
126 err = -EIO;
127 break;
129 case 4:
130 err = get_user(dword, (u32 __user *)buf);
131 if (err)
132 break;
133 err = pci_user_write_config_dword(dev, off, dword);
134 if (err != PCIBIOS_SUCCESSFUL)
135 err = -EIO;
136 break;
138 default:
139 err = -EINVAL;
140 break;
141 };
142 unlock_kernel();
144 return err;
145 }