ia64/linux-2.6.18-xen.hg

view drivers/pci/msi-apic.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 * MSI hooks for standard x86 apic
3 */
5 #include <linux/pci.h>
6 #include <linux/irq.h>
7 #include <asm/smp.h>
9 #include "msi.h"
11 /*
12 * Shifts for APIC-based data
13 */
15 #define MSI_DATA_VECTOR_SHIFT 0
16 #define MSI_DATA_VECTOR(v) (((u8)v) << MSI_DATA_VECTOR_SHIFT)
18 #define MSI_DATA_DELIVERY_SHIFT 8
19 #define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_SHIFT)
20 #define MSI_DATA_DELIVERY_LOWPRI (1 << MSI_DATA_DELIVERY_SHIFT)
22 #define MSI_DATA_LEVEL_SHIFT 14
23 #define MSI_DATA_LEVEL_DEASSERT (0 << MSI_DATA_LEVEL_SHIFT)
24 #define MSI_DATA_LEVEL_ASSERT (1 << MSI_DATA_LEVEL_SHIFT)
26 #define MSI_DATA_TRIGGER_SHIFT 15
27 #define MSI_DATA_TRIGGER_EDGE (0 << MSI_DATA_TRIGGER_SHIFT)
28 #define MSI_DATA_TRIGGER_LEVEL (1 << MSI_DATA_TRIGGER_SHIFT)
30 /*
31 * Shift/mask fields for APIC-based bus address
32 */
34 #define MSI_ADDR_HEADER 0xfee00000
36 #define MSI_ADDR_DESTID_MASK 0xfff0000f
37 #define MSI_ADDR_DESTID_CPU(cpu) ((cpu) << MSI_TARGET_CPU_SHIFT)
39 #define MSI_ADDR_DESTMODE_SHIFT 2
40 #define MSI_ADDR_DESTMODE_PHYS (0 << MSI_ADDR_DESTMODE_SHIFT)
41 #define MSI_ADDR_DESTMODE_LOGIC (1 << MSI_ADDR_DESTMODE_SHIFT)
43 #define MSI_ADDR_REDIRECTION_SHIFT 3
44 #define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT)
45 #define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT)
48 static void
49 msi_target_apic(unsigned int vector,
50 unsigned int dest_cpu,
51 u32 *address_hi, /* in/out */
52 u32 *address_lo) /* in/out */
53 {
54 u32 addr = *address_lo;
56 addr &= MSI_ADDR_DESTID_MASK;
57 addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(dest_cpu));
59 *address_lo = addr;
60 }
62 static int
63 msi_setup_apic(struct pci_dev *pdev, /* unused in generic */
64 unsigned int vector,
65 u32 *address_hi,
66 u32 *address_lo,
67 u32 *data)
68 {
69 unsigned long dest_phys_id;
71 dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
73 *address_hi = 0;
74 *address_lo = MSI_ADDR_HEADER |
75 MSI_ADDR_DESTMODE_PHYS |
76 MSI_ADDR_REDIRECTION_CPU |
77 MSI_ADDR_DESTID_CPU(dest_phys_id);
79 *data = MSI_DATA_TRIGGER_EDGE |
80 MSI_DATA_LEVEL_ASSERT |
81 MSI_DATA_DELIVERY_FIXED |
82 MSI_DATA_VECTOR(vector);
84 return 0;
85 }
87 static void
88 msi_teardown_apic(unsigned int vector)
89 {
90 return; /* no-op */
91 }
93 /*
94 * Generic ops used on most IA archs/platforms. Set with msi_register()
95 */
97 struct msi_ops msi_apic_ops = {
98 .setup = msi_setup_apic,
99 .teardown = msi_teardown_apic,
100 .target = msi_target_apic,
101 };