mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 19:21:31 -04:00
Merge branch 'stable/xen-pcifront-0.8.2' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen
and branch 'for-linus' of git://xenbits.xen.org/people/sstabellini/linux-pvhvm * 'for-linus' of git://xenbits.xen.org/people/sstabellini/linux-pvhvm: xen: register xen pci notifier xen: initialize cpu masks for pv guests in xen_smp_init xen: add a missing #include to arch/x86/pci/xen.c xen: mask the MTRR feature from the cpuid xen: make hvc_xen console work for dom0. xen: add the direct mapping area for ISA bus access xen: Initialize xenbus for dom0. xen: use vcpu_ops to setup cpu masks xen: map a dummy page for local apic and ioapic in xen_set_fixmap xen: remap MSIs into pirqs when running as initial domain xen: remap GSIs as pirqs when running as initial domain xen: introduce XEN_DOM0 as a silent option xen: map MSIs into pirqs xen: support GSI -> pirq remapping in PV on HVM guests xen: add xen hvm acpi_register_gsi variant acpi: use indirect call to register gsi in different modes xen: implement xen_hvm_register_pirq xen: get the maximum number of pirqs from xen xen: support pirq != irq * 'stable/xen-pcifront-0.8.2' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen: (27 commits) X86/PCI: Remove the dependency on isapnp_disable. xen: Update Makefile with CONFIG_BLOCK dependency for biomerge.c MAINTAINERS: Add myself to the Xen Hypervisor Interface and remove Chris Wright. x86: xen: Sanitse irq handling (part two) swiotlb-xen: On x86-32 builts, select SWIOTLB instead of depending on it. MAINTAINERS: Add myself for Xen PCI and Xen SWIOTLB maintainer. xen/pci: Request ACS when Xen-SWIOTLB is activated. xen-pcifront: Xen PCI frontend driver. xenbus: prevent warnings on unhandled enumeration values xenbus: Xen paravirtualised PCI hotplug support. xen/x86/PCI: Add support for the Xen PCI subsystem x86: Introduce x86_msi_ops msi: Introduce default_[teardown|setup]_msi_irqs with fallback. x86/PCI: Export pci_walk_bus function. x86/PCI: make sure _PAGE_IOMAP it set on pci mappings x86/PCI: Clean up pci_cache_line_size xen: fix shared irq device passthrough xen: Provide a variant of xen_poll_irq with timeout. xen: Find an unbound irq number in reverse order (high to low). xen: statically initialize cpu_evtchn_mask_p ... Fix up trivial conflicts in drivers/pci/Makefile
This commit is contained in:
commit
18cb657ca1
44 changed files with 2845 additions and 95 deletions
|
|
@ -1893,6 +1893,11 @@ config PCI_OLPC
|
|||
def_bool y
|
||||
depends on PCI && OLPC && (PCI_GOOLPC || PCI_GOANY)
|
||||
|
||||
config PCI_XEN
|
||||
def_bool y
|
||||
depends on PCI && XEN
|
||||
select SWIOTLB_XEN
|
||||
|
||||
config PCI_DOMAINS
|
||||
def_bool y
|
||||
depends on PCI
|
||||
|
|
|
|||
|
|
@ -93,6 +93,9 @@ extern u8 acpi_sci_flags;
|
|||
extern int acpi_sci_override_gsi;
|
||||
void acpi_pic_sci_set_trigger(unsigned int, u16);
|
||||
|
||||
extern int (*__acpi_register_gsi)(struct device *dev, u32 gsi,
|
||||
int trigger, int polarity);
|
||||
|
||||
static inline void disable_acpi(void)
|
||||
{
|
||||
acpi_disabled = 1;
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@
|
|||
#include <asm-generic/int-ll64.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
#include <xen/xen.h>
|
||||
|
||||
#define build_mmio_read(name, size, type, reg, barrier) \
|
||||
static inline type name(const volatile void __iomem *addr) \
|
||||
{ type ret; asm volatile("mov" size " %1,%0":reg (ret) \
|
||||
|
|
@ -351,6 +353,17 @@ extern void early_iounmap(void __iomem *addr, unsigned long size);
|
|||
extern void fixup_early_ioremap(void);
|
||||
extern bool is_early_ioremap_ptep(pte_t *ptep);
|
||||
|
||||
#ifdef CONFIG_XEN
|
||||
struct bio_vec;
|
||||
|
||||
extern bool xen_biovec_phys_mergeable(const struct bio_vec *vec1,
|
||||
const struct bio_vec *vec2);
|
||||
|
||||
#define BIOVEC_PHYS_MERGEABLE(vec1, vec2) \
|
||||
(__BIOVEC_PHYS_MERGEABLE(vec1, vec2) && \
|
||||
(!xen_domain() || xen_biovec_phys_mergeable(vec1, vec2)))
|
||||
#endif /* CONFIG_XEN */
|
||||
|
||||
#define IO_SPACE_LIMIT 0xffff
|
||||
|
||||
#endif /* _ASM_X86_IO_H */
|
||||
|
|
|
|||
|
|
@ -169,6 +169,7 @@ extern void mask_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries);
|
|||
extern int restore_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries);
|
||||
|
||||
extern void probe_nr_irqs_gsi(void);
|
||||
extern int get_nr_irqs_gsi(void);
|
||||
|
||||
extern void setup_ioapic_ids_from_mpc(void);
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <linux/string.h>
|
||||
#include <asm/scatterlist.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/x86_init.h>
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
|
|
@ -94,8 +95,36 @@ static inline void early_quirks(void) { }
|
|||
|
||||
extern void pci_iommu_alloc(void);
|
||||
|
||||
/* MSI arch hook */
|
||||
#define arch_setup_msi_irqs arch_setup_msi_irqs
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
/* MSI arch specific hooks */
|
||||
static inline int x86_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
|
||||
{
|
||||
return x86_msi.setup_msi_irqs(dev, nvec, type);
|
||||
}
|
||||
|
||||
static inline void x86_teardown_msi_irqs(struct pci_dev *dev)
|
||||
{
|
||||
x86_msi.teardown_msi_irqs(dev);
|
||||
}
|
||||
|
||||
static inline void x86_teardown_msi_irq(unsigned int irq)
|
||||
{
|
||||
x86_msi.teardown_msi_irq(irq);
|
||||
}
|
||||
#define arch_setup_msi_irqs x86_setup_msi_irqs
|
||||
#define arch_teardown_msi_irqs x86_teardown_msi_irqs
|
||||
#define arch_teardown_msi_irq x86_teardown_msi_irq
|
||||
/* implemented in arch/x86/kernel/apic/io_apic. */
|
||||
int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
|
||||
void native_teardown_msi_irq(unsigned int irq);
|
||||
/* default to the implementation in drivers/lib/msi.c */
|
||||
#define HAVE_DEFAULT_MSI_TEARDOWN_IRQS
|
||||
void default_teardown_msi_irqs(struct pci_dev *dev);
|
||||
#else
|
||||
#define native_setup_msi_irqs NULL
|
||||
#define native_teardown_msi_irq NULL
|
||||
#define default_teardown_msi_irqs NULL
|
||||
#endif
|
||||
|
||||
#define PCI_DMA_BUS_IS_PHYS (dma_ops->is_phys)
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ enum pci_bf_sort_state {
|
|||
extern unsigned int pcibios_max_latency;
|
||||
|
||||
void pcibios_resource_survey(void);
|
||||
void pcibios_set_cache_line_size(void);
|
||||
|
||||
/* pci-pc.c */
|
||||
|
||||
|
|
|
|||
|
|
@ -154,9 +154,18 @@ struct x86_platform_ops {
|
|||
int (*i8042_detect)(void);
|
||||
};
|
||||
|
||||
struct pci_dev;
|
||||
|
||||
struct x86_msi_ops {
|
||||
int (*setup_msi_irqs)(struct pci_dev *dev, int nvec, int type);
|
||||
void (*teardown_msi_irq)(unsigned int irq);
|
||||
void (*teardown_msi_irqs)(struct pci_dev *dev);
|
||||
};
|
||||
|
||||
extern struct x86_init_ops x86_init;
|
||||
extern struct x86_cpuinit_ops x86_cpuinit;
|
||||
extern struct x86_platform_ops x86_platform;
|
||||
extern struct x86_msi_ops x86_msi;
|
||||
|
||||
extern void x86_init_noop(void);
|
||||
extern void x86_init_uint_noop(unsigned int unused);
|
||||
|
|
|
|||
65
arch/x86/include/asm/xen/pci.h
Normal file
65
arch/x86/include/asm/xen/pci.h
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
#ifndef _ASM_X86_XEN_PCI_H
|
||||
#define _ASM_X86_XEN_PCI_H
|
||||
|
||||
#if defined(CONFIG_PCI_XEN)
|
||||
extern int __init pci_xen_init(void);
|
||||
extern int __init pci_xen_hvm_init(void);
|
||||
#define pci_xen 1
|
||||
#else
|
||||
#define pci_xen 0
|
||||
#define pci_xen_init (0)
|
||||
static inline int pci_xen_hvm_init(void)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
#if defined(CONFIG_XEN_DOM0)
|
||||
void __init xen_setup_pirqs(void);
|
||||
#else
|
||||
static inline void __init xen_setup_pirqs(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_PCI_MSI)
|
||||
#if defined(CONFIG_PCI_XEN)
|
||||
/* The drivers/pci/xen-pcifront.c sets this structure to
|
||||
* its own functions.
|
||||
*/
|
||||
struct xen_pci_frontend_ops {
|
||||
int (*enable_msi)(struct pci_dev *dev, int **vectors);
|
||||
void (*disable_msi)(struct pci_dev *dev);
|
||||
int (*enable_msix)(struct pci_dev *dev, int **vectors, int nvec);
|
||||
void (*disable_msix)(struct pci_dev *dev);
|
||||
};
|
||||
|
||||
extern struct xen_pci_frontend_ops *xen_pci_frontend;
|
||||
|
||||
static inline int xen_pci_frontend_enable_msi(struct pci_dev *dev,
|
||||
int **vectors)
|
||||
{
|
||||
if (xen_pci_frontend && xen_pci_frontend->enable_msi)
|
||||
return xen_pci_frontend->enable_msi(dev, vectors);
|
||||
return -ENODEV;
|
||||
}
|
||||
static inline void xen_pci_frontend_disable_msi(struct pci_dev *dev)
|
||||
{
|
||||
if (xen_pci_frontend && xen_pci_frontend->disable_msi)
|
||||
xen_pci_frontend->disable_msi(dev);
|
||||
}
|
||||
static inline int xen_pci_frontend_enable_msix(struct pci_dev *dev,
|
||||
int **vectors, int nvec)
|
||||
{
|
||||
if (xen_pci_frontend && xen_pci_frontend->enable_msix)
|
||||
return xen_pci_frontend->enable_msix(dev, vectors, nvec);
|
||||
return -ENODEV;
|
||||
}
|
||||
static inline void xen_pci_frontend_disable_msix(struct pci_dev *dev)
|
||||
{
|
||||
if (xen_pci_frontend && xen_pci_frontend->disable_msix)
|
||||
xen_pci_frontend->disable_msix(dev);
|
||||
}
|
||||
#endif /* CONFIG_PCI_XEN */
|
||||
#endif /* CONFIG_PCI_MSI */
|
||||
|
||||
#endif /* _ASM_X86_XEN_PCI_H */
|
||||
|
|
@ -513,6 +513,33 @@ int acpi_isa_irq_to_gsi(unsigned isa_irq, u32 *gsi)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_register_gsi_pic(struct device *dev, u32 gsi,
|
||||
int trigger, int polarity)
|
||||
{
|
||||
#ifdef CONFIG_PCI
|
||||
/*
|
||||
* Make sure all (legacy) PCI IRQs are set as level-triggered.
|
||||
*/
|
||||
if (trigger == ACPI_LEVEL_SENSITIVE)
|
||||
eisa_set_level_irq(gsi);
|
||||
#endif
|
||||
|
||||
return gsi;
|
||||
}
|
||||
|
||||
static int acpi_register_gsi_ioapic(struct device *dev, u32 gsi,
|
||||
int trigger, int polarity)
|
||||
{
|
||||
#ifdef CONFIG_X86_IO_APIC
|
||||
gsi = mp_register_gsi(dev, gsi, trigger, polarity);
|
||||
#endif
|
||||
|
||||
return gsi;
|
||||
}
|
||||
|
||||
int (*__acpi_register_gsi)(struct device *dev, u32 gsi,
|
||||
int trigger, int polarity) = acpi_register_gsi_pic;
|
||||
|
||||
/*
|
||||
* success: return IRQ number (>=0)
|
||||
* failure: return < 0
|
||||
|
|
@ -522,26 +549,26 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity)
|
|||
unsigned int irq;
|
||||
unsigned int plat_gsi = gsi;
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
/*
|
||||
* Make sure all (legacy) PCI IRQs are set as level-triggered.
|
||||
*/
|
||||
if (acpi_irq_model == ACPI_IRQ_MODEL_PIC) {
|
||||
if (trigger == ACPI_LEVEL_SENSITIVE)
|
||||
eisa_set_level_irq(gsi);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X86_IO_APIC
|
||||
if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC) {
|
||||
plat_gsi = mp_register_gsi(dev, gsi, trigger, polarity);
|
||||
}
|
||||
#endif
|
||||
plat_gsi = (*__acpi_register_gsi)(dev, gsi, trigger, polarity);
|
||||
irq = gsi_to_irq(plat_gsi);
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
void __init acpi_set_irq_model_pic(void)
|
||||
{
|
||||
acpi_irq_model = ACPI_IRQ_MODEL_PIC;
|
||||
__acpi_register_gsi = acpi_register_gsi_pic;
|
||||
acpi_ioapic = 0;
|
||||
}
|
||||
|
||||
void __init acpi_set_irq_model_ioapic(void)
|
||||
{
|
||||
acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC;
|
||||
__acpi_register_gsi = acpi_register_gsi_ioapic;
|
||||
acpi_ioapic = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* ACPI based hotplug support for CPU
|
||||
*/
|
||||
|
|
@ -1259,8 +1286,7 @@ static void __init acpi_process_madt(void)
|
|||
*/
|
||||
error = acpi_parse_madt_ioapic_entries();
|
||||
if (!error) {
|
||||
acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC;
|
||||
acpi_ioapic = 1;
|
||||
acpi_set_irq_model_ioapic();
|
||||
|
||||
smp_found_config = 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3331,7 +3331,7 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int irq)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
|
||||
int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
|
||||
{
|
||||
int node, ret, sub_handle, index = 0;
|
||||
unsigned int irq, irq_want;
|
||||
|
|
@ -3389,7 +3389,7 @@ error:
|
|||
return ret;
|
||||
}
|
||||
|
||||
void arch_teardown_msi_irq(unsigned int irq)
|
||||
void native_teardown_msi_irq(unsigned int irq)
|
||||
{
|
||||
destroy_irq(irq);
|
||||
}
|
||||
|
|
@ -3650,6 +3650,11 @@ void __init probe_nr_irqs_gsi(void)
|
|||
printk(KERN_DEBUG "nr_irqs_gsi: %d\n", nr_irqs_gsi);
|
||||
}
|
||||
|
||||
int get_nr_irqs_gsi(void)
|
||||
{
|
||||
return nr_irqs_gsi;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPARSE_IRQ
|
||||
int __init arch_probe_nr_irqs(void)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,10 +6,12 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include <asm/bios_ebda.h>
|
||||
#include <asm/paravirt.h>
|
||||
#include <asm/pci_x86.h>
|
||||
#include <asm/pci.h>
|
||||
#include <asm/mpspec.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/apic.h>
|
||||
|
|
@ -99,3 +101,8 @@ struct x86_platform_ops x86_platform = {
|
|||
};
|
||||
|
||||
EXPORT_SYMBOL_GPL(x86_platform);
|
||||
struct x86_msi_ops x86_msi = {
|
||||
.setup_msi_irqs = native_setup_msi_irqs,
|
||||
.teardown_msi_irq = native_teardown_msi_irq,
|
||||
.teardown_msi_irqs = default_teardown_msi_irqs,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ obj-$(CONFIG_PCI_BIOS) += pcbios.o
|
|||
obj-$(CONFIG_PCI_MMCONFIG) += mmconfig_$(BITS).o direct.o mmconfig-shared.o
|
||||
obj-$(CONFIG_PCI_DIRECT) += direct.o
|
||||
obj-$(CONFIG_PCI_OLPC) += olpc.o
|
||||
obj-$(CONFIG_PCI_XEN) += xen.o
|
||||
|
||||
obj-y += fixup.o
|
||||
obj-$(CONFIG_ACPI) += acpi.o
|
||||
|
|
|
|||
|
|
@ -421,16 +421,10 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum)
|
|||
|
||||
return bus;
|
||||
}
|
||||
|
||||
int __init pcibios_init(void)
|
||||
void __init pcibios_set_cache_line_size(void)
|
||||
{
|
||||
struct cpuinfo_x86 *c = &boot_cpu_data;
|
||||
|
||||
if (!raw_pci_ops) {
|
||||
printk(KERN_WARNING "PCI: System does not support PCI\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set PCI cacheline size to that of the CPU if the CPU has reported it.
|
||||
* (For older CPUs that don't support cpuid, we se it to 32 bytes
|
||||
|
|
@ -445,7 +439,16 @@ int __init pcibios_init(void)
|
|||
pci_dfl_cache_line_size = 32 >> 2;
|
||||
printk(KERN_DEBUG "PCI: Unknown cacheline size. Setting to 32 bytes\n");
|
||||
}
|
||||
}
|
||||
|
||||
int __init pcibios_init(void)
|
||||
{
|
||||
if (!raw_pci_ops) {
|
||||
printk(KERN_WARNING "PCI: System does not support PCI\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pcibios_set_cache_line_size();
|
||||
pcibios_resource_survey();
|
||||
|
||||
if (pci_bf_sort >= pci_force_bf)
|
||||
|
|
|
|||
|
|
@ -316,6 +316,8 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
|
|||
*/
|
||||
prot |= _PAGE_CACHE_UC_MINUS;
|
||||
|
||||
prot |= _PAGE_IOMAP; /* creating a mapping for IO */
|
||||
|
||||
vma->vm_page_prot = __pgprot(prot);
|
||||
|
||||
if (io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
|
||||
|
|
|
|||
414
arch/x86/pci/xen.c
Normal file
414
arch/x86/pci/xen.c
Normal file
|
|
@ -0,0 +1,414 @@
|
|||
/*
|
||||
* Xen PCI Frontend Stub - puts some "dummy" functions in to the Linux
|
||||
* x86 PCI core to support the Xen PCI Frontend
|
||||
*
|
||||
* Author: Ryan Wilson <hap9@epoch.ncsc.mil>
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <asm/io_apic.h>
|
||||
#include <asm/pci_x86.h>
|
||||
|
||||
#include <asm/xen/hypervisor.h>
|
||||
|
||||
#include <xen/features.h>
|
||||
#include <xen/events.h>
|
||||
#include <asm/xen/pci.h>
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static int xen_hvm_register_pirq(u32 gsi, int triggering)
|
||||
{
|
||||
int rc, irq;
|
||||
struct physdev_map_pirq map_irq;
|
||||
int shareable = 0;
|
||||
char *name;
|
||||
|
||||
if (!xen_hvm_domain())
|
||||
return -1;
|
||||
|
||||
map_irq.domid = DOMID_SELF;
|
||||
map_irq.type = MAP_PIRQ_TYPE_GSI;
|
||||
map_irq.index = gsi;
|
||||
map_irq.pirq = -1;
|
||||
|
||||
rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
|
||||
if (rc) {
|
||||
printk(KERN_WARNING "xen map irq failed %d\n", rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (triggering == ACPI_EDGE_SENSITIVE) {
|
||||
shareable = 0;
|
||||
name = "ioapic-edge";
|
||||
} else {
|
||||
shareable = 1;
|
||||
name = "ioapic-level";
|
||||
}
|
||||
|
||||
irq = xen_map_pirq_gsi(map_irq.pirq, gsi, shareable, name);
|
||||
|
||||
printk(KERN_DEBUG "xen: --> irq=%d, pirq=%d\n", irq, map_irq.pirq);
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
static int acpi_register_gsi_xen_hvm(struct device *dev, u32 gsi,
|
||||
int trigger, int polarity)
|
||||
{
|
||||
return xen_hvm_register_pirq(gsi, trigger);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_PCI_MSI)
|
||||
#include <linux/msi.h>
|
||||
#include <asm/msidef.h>
|
||||
|
||||
struct xen_pci_frontend_ops *xen_pci_frontend;
|
||||
EXPORT_SYMBOL_GPL(xen_pci_frontend);
|
||||
|
||||
static void xen_msi_compose_msg(struct pci_dev *pdev, unsigned int pirq,
|
||||
struct msi_msg *msg)
|
||||
{
|
||||
/* We set vector == 0 to tell the hypervisor we don't care about it,
|
||||
* but we want a pirq setup instead.
|
||||
* We use the dest_id field to pass the pirq that we want. */
|
||||
msg->address_hi = MSI_ADDR_BASE_HI | MSI_ADDR_EXT_DEST_ID(pirq);
|
||||
msg->address_lo =
|
||||
MSI_ADDR_BASE_LO |
|
||||
MSI_ADDR_DEST_MODE_PHYSICAL |
|
||||
MSI_ADDR_REDIRECTION_CPU |
|
||||
MSI_ADDR_DEST_ID(pirq);
|
||||
|
||||
msg->data =
|
||||
MSI_DATA_TRIGGER_EDGE |
|
||||
MSI_DATA_LEVEL_ASSERT |
|
||||
/* delivery mode reserved */
|
||||
(3 << 8) |
|
||||
MSI_DATA_VECTOR(0);
|
||||
}
|
||||
|
||||
static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
|
||||
{
|
||||
int irq, pirq, ret = 0;
|
||||
struct msi_desc *msidesc;
|
||||
struct msi_msg msg;
|
||||
|
||||
list_for_each_entry(msidesc, &dev->msi_list, list) {
|
||||
xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ?
|
||||
"msi-x" : "msi", &irq, &pirq);
|
||||
if (irq < 0 || pirq < 0)
|
||||
goto error;
|
||||
printk(KERN_DEBUG "xen: msi --> irq=%d, pirq=%d\n", irq, pirq);
|
||||
xen_msi_compose_msg(dev, pirq, &msg);
|
||||
ret = set_irq_msi(irq, msidesc);
|
||||
if (ret < 0)
|
||||
goto error_while;
|
||||
write_msi_msg(irq, &msg);
|
||||
}
|
||||
return 0;
|
||||
|
||||
error_while:
|
||||
unbind_from_irqhandler(irq, NULL);
|
||||
error:
|
||||
if (ret == -ENODEV)
|
||||
dev_err(&dev->dev, "Xen PCI frontend has not registered" \
|
||||
" MSI/MSI-X support!\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* For MSI interrupts we have to use drivers/xen/event.s functions to
|
||||
* allocate an irq_desc and setup the right */
|
||||
|
||||
|
||||
static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
|
||||
{
|
||||
int irq, ret, i;
|
||||
struct msi_desc *msidesc;
|
||||
int *v;
|
||||
|
||||
v = kzalloc(sizeof(int) * max(1, nvec), GFP_KERNEL);
|
||||
if (!v)
|
||||
return -ENOMEM;
|
||||
|
||||
if (type == PCI_CAP_ID_MSIX)
|
||||
ret = xen_pci_frontend_enable_msix(dev, &v, nvec);
|
||||
else
|
||||
ret = xen_pci_frontend_enable_msi(dev, &v);
|
||||
if (ret)
|
||||
goto error;
|
||||
i = 0;
|
||||
list_for_each_entry(msidesc, &dev->msi_list, list) {
|
||||
irq = xen_allocate_pirq(v[i], 0, /* not sharable */
|
||||
(type == PCI_CAP_ID_MSIX) ?
|
||||
"pcifront-msi-x" : "pcifront-msi");
|
||||
if (irq < 0)
|
||||
return -1;
|
||||
|
||||
ret = set_irq_msi(irq, msidesc);
|
||||
if (ret)
|
||||
goto error_while;
|
||||
i++;
|
||||
}
|
||||
kfree(v);
|
||||
return 0;
|
||||
|
||||
error_while:
|
||||
unbind_from_irqhandler(irq, NULL);
|
||||
error:
|
||||
if (ret == -ENODEV)
|
||||
dev_err(&dev->dev, "Xen PCI frontend has not registered" \
|
||||
" MSI/MSI-X support!\n");
|
||||
|
||||
kfree(v);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void xen_teardown_msi_irqs(struct pci_dev *dev)
|
||||
{
|
||||
struct msi_desc *msidesc;
|
||||
|
||||
msidesc = list_entry(dev->msi_list.next, struct msi_desc, list);
|
||||
if (msidesc->msi_attrib.is_msix)
|
||||
xen_pci_frontend_disable_msix(dev);
|
||||
else
|
||||
xen_pci_frontend_disable_msi(dev);
|
||||
}
|
||||
|
||||
static void xen_teardown_msi_irq(unsigned int irq)
|
||||
{
|
||||
xen_destroy_irq(irq);
|
||||
}
|
||||
|
||||
static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
|
||||
{
|
||||
int irq, ret;
|
||||
struct msi_desc *msidesc;
|
||||
|
||||
list_for_each_entry(msidesc, &dev->msi_list, list) {
|
||||
irq = xen_create_msi_irq(dev, msidesc, type);
|
||||
if (irq < 0)
|
||||
return -1;
|
||||
|
||||
ret = set_irq_msi(irq, msidesc);
|
||||
if (ret)
|
||||
goto error;
|
||||
}
|
||||
return 0;
|
||||
|
||||
error:
|
||||
xen_destroy_irq(irq);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int xen_pcifront_enable_irq(struct pci_dev *dev)
|
||||
{
|
||||
int rc;
|
||||
int share = 1;
|
||||
|
||||
dev_info(&dev->dev, "Xen PCI enabling IRQ: %d\n", dev->irq);
|
||||
|
||||
if (dev->irq < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (dev->irq < NR_IRQS_LEGACY)
|
||||
share = 0;
|
||||
|
||||
rc = xen_allocate_pirq(dev->irq, share, "pcifront");
|
||||
if (rc < 0) {
|
||||
dev_warn(&dev->dev, "Xen PCI IRQ: %d, failed to register:%d\n",
|
||||
dev->irq, rc);
|
||||
return rc;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init pci_xen_init(void)
|
||||
{
|
||||
if (!xen_pv_domain() || xen_initial_domain())
|
||||
return -ENODEV;
|
||||
|
||||
printk(KERN_INFO "PCI: setting up Xen PCI frontend stub\n");
|
||||
|
||||
pcibios_set_cache_line_size();
|
||||
|
||||
pcibios_enable_irq = xen_pcifront_enable_irq;
|
||||
pcibios_disable_irq = NULL;
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
/* Keep ACPI out of the picture */
|
||||
acpi_noirq = 1;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
x86_msi.setup_msi_irqs = xen_setup_msi_irqs;
|
||||
x86_msi.teardown_msi_irq = xen_teardown_msi_irq;
|
||||
x86_msi.teardown_msi_irqs = xen_teardown_msi_irqs;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init pci_xen_hvm_init(void)
|
||||
{
|
||||
if (!xen_feature(XENFEAT_hvm_pirqs))
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
/*
|
||||
* We don't want to change the actual ACPI delivery model,
|
||||
* just how GSIs get registered.
|
||||
*/
|
||||
__acpi_register_gsi = acpi_register_gsi_xen_hvm;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
x86_msi.setup_msi_irqs = xen_hvm_setup_msi_irqs;
|
||||
x86_msi.teardown_msi_irq = xen_teardown_msi_irq;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_XEN_DOM0
|
||||
static int xen_register_pirq(u32 gsi, int triggering)
|
||||
{
|
||||
int rc, irq;
|
||||
struct physdev_map_pirq map_irq;
|
||||
int shareable = 0;
|
||||
char *name;
|
||||
|
||||
if (!xen_pv_domain())
|
||||
return -1;
|
||||
|
||||
if (triggering == ACPI_EDGE_SENSITIVE) {
|
||||
shareable = 0;
|
||||
name = "ioapic-edge";
|
||||
} else {
|
||||
shareable = 1;
|
||||
name = "ioapic-level";
|
||||
}
|
||||
|
||||
irq = xen_allocate_pirq(gsi, shareable, name);
|
||||
|
||||
printk(KERN_DEBUG "xen: --> irq=%d\n", irq);
|
||||
|
||||
if (irq < 0)
|
||||
goto out;
|
||||
|
||||
map_irq.domid = DOMID_SELF;
|
||||
map_irq.type = MAP_PIRQ_TYPE_GSI;
|
||||
map_irq.index = gsi;
|
||||
map_irq.pirq = irq;
|
||||
|
||||
rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
|
||||
if (rc) {
|
||||
printk(KERN_WARNING "xen map irq failed %d\n", rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
out:
|
||||
return irq;
|
||||
}
|
||||
|
||||
static int xen_register_gsi(u32 gsi, int triggering, int polarity)
|
||||
{
|
||||
int rc, irq;
|
||||
struct physdev_setup_gsi setup_gsi;
|
||||
|
||||
if (!xen_pv_domain())
|
||||
return -1;
|
||||
|
||||
printk(KERN_DEBUG "xen: registering gsi %u triggering %d polarity %d\n",
|
||||
gsi, triggering, polarity);
|
||||
|
||||
irq = xen_register_pirq(gsi, triggering);
|
||||
|
||||
setup_gsi.gsi = gsi;
|
||||
setup_gsi.triggering = (triggering == ACPI_EDGE_SENSITIVE ? 0 : 1);
|
||||
setup_gsi.polarity = (polarity == ACPI_ACTIVE_HIGH ? 0 : 1);
|
||||
|
||||
rc = HYPERVISOR_physdev_op(PHYSDEVOP_setup_gsi, &setup_gsi);
|
||||
if (rc == -EEXIST)
|
||||
printk(KERN_INFO "Already setup the GSI :%d\n", gsi);
|
||||
else if (rc) {
|
||||
printk(KERN_ERR "Failed to setup GSI :%d, err_code:%d\n",
|
||||
gsi, rc);
|
||||
}
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
static __init void xen_setup_acpi_sci(void)
|
||||
{
|
||||
int rc;
|
||||
int trigger, polarity;
|
||||
int gsi = acpi_sci_override_gsi;
|
||||
|
||||
if (!gsi)
|
||||
return;
|
||||
|
||||
rc = acpi_get_override_irq(gsi, &trigger, &polarity);
|
||||
if (rc) {
|
||||
printk(KERN_WARNING "xen: acpi_get_override_irq failed for acpi"
|
||||
" sci, rc=%d\n", rc);
|
||||
return;
|
||||
}
|
||||
trigger = trigger ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE;
|
||||
polarity = polarity ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
|
||||
|
||||
printk(KERN_INFO "xen: sci override: global_irq=%d trigger=%d "
|
||||
"polarity=%d\n", gsi, trigger, polarity);
|
||||
|
||||
gsi = xen_register_gsi(gsi, trigger, polarity);
|
||||
printk(KERN_INFO "xen: acpi sci %d\n", gsi);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int acpi_register_gsi_xen(struct device *dev, u32 gsi,
|
||||
int trigger, int polarity)
|
||||
{
|
||||
return xen_register_gsi(gsi, trigger, polarity);
|
||||
}
|
||||
|
||||
static int __init pci_xen_initial_domain(void)
|
||||
{
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
x86_msi.setup_msi_irqs = xen_initdom_setup_msi_irqs;
|
||||
x86_msi.teardown_msi_irq = xen_teardown_msi_irq;
|
||||
#endif
|
||||
xen_setup_acpi_sci();
|
||||
__acpi_register_gsi = acpi_register_gsi_xen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __init xen_setup_pirqs(void)
|
||||
{
|
||||
int irq;
|
||||
|
||||
pci_xen_initial_domain();
|
||||
|
||||
if (0 == nr_ioapics) {
|
||||
for (irq = 0; irq < NR_IRQS_LEGACY; irq++)
|
||||
xen_allocate_pirq(irq, 0, "xt-pic");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Pre-allocate legacy irqs */
|
||||
for (irq = 0; irq < NR_IRQS_LEGACY; irq++) {
|
||||
int trigger, polarity;
|
||||
|
||||
if (acpi_get_override_irq(irq, &trigger, &polarity) == -1)
|
||||
continue;
|
||||
|
||||
xen_register_pirq(irq,
|
||||
trigger ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -13,6 +13,16 @@ config XEN
|
|||
kernel to boot in a paravirtualized environment under the
|
||||
Xen hypervisor.
|
||||
|
||||
config XEN_DOM0
|
||||
def_bool y
|
||||
depends on XEN && PCI_XEN && SWIOTLB_XEN
|
||||
depends on X86_LOCAL_APIC && X86_IO_APIC && ACPI && PCI
|
||||
|
||||
# Dummy symbol since people have come to rely on the PRIVILEGED_GUEST
|
||||
# name in tools.
|
||||
config XEN_PRIVILEGED_GUEST
|
||||
def_bool XEN_DOM0
|
||||
|
||||
config XEN_PVHVM
|
||||
def_bool y
|
||||
depends on XEN
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@
|
|||
#include <asm/paravirt.h>
|
||||
#include <asm/apic.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/xen/pci.h>
|
||||
#include <asm/xen/hypercall.h>
|
||||
#include <asm/xen/hypervisor.h>
|
||||
#include <asm/fixmap.h>
|
||||
|
|
@ -236,6 +237,7 @@ static __init void xen_init_cpuid_mask(void)
|
|||
cpuid_leaf1_edx_mask =
|
||||
~((1 << X86_FEATURE_MCE) | /* disable MCE */
|
||||
(1 << X86_FEATURE_MCA) | /* disable MCA */
|
||||
(1 << X86_FEATURE_MTRR) | /* disable MTRR */
|
||||
(1 << X86_FEATURE_ACC)); /* thermal monitoring */
|
||||
|
||||
if (!xen_initial_domain())
|
||||
|
|
@ -1184,6 +1186,7 @@ asmlinkage void __init xen_start_kernel(void)
|
|||
|
||||
xen_raw_console_write("mapping kernel into physical memory\n");
|
||||
pgd = xen_setup_kernel_pagetable(pgd, xen_start_info->nr_pages);
|
||||
xen_ident_map_ISA();
|
||||
|
||||
/* Allocate and initialize top and mid mfn levels for p2m structure */
|
||||
xen_build_mfn_list_list();
|
||||
|
|
@ -1222,6 +1225,8 @@ asmlinkage void __init xen_start_kernel(void)
|
|||
add_preferred_console("xenboot", 0, NULL);
|
||||
add_preferred_console("tty", 0, NULL);
|
||||
add_preferred_console("hvc", 0, NULL);
|
||||
if (pci_xen)
|
||||
x86_init.pci.arch_init = pci_xen_init;
|
||||
} else {
|
||||
/* Make sure ACS will be enabled */
|
||||
pci_request_acs();
|
||||
|
|
|
|||
|
|
@ -1975,6 +1975,7 @@ static void *m2v(phys_addr_t maddr)
|
|||
return __ka(m2p(maddr));
|
||||
}
|
||||
|
||||
/* Set the page permissions on an identity-mapped pages */
|
||||
static void set_page_prot(void *addr, pgprot_t prot)
|
||||
{
|
||||
unsigned long pfn = __pa(addr) >> PAGE_SHIFT;
|
||||
|
|
@ -2159,6 +2160,8 @@ __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
|
|||
}
|
||||
#endif /* CONFIG_X86_64 */
|
||||
|
||||
static unsigned char dummy_mapping[PAGE_SIZE] __page_aligned_bss;
|
||||
|
||||
static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
|
||||
{
|
||||
pte_t pte;
|
||||
|
|
@ -2178,9 +2181,6 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
|
|||
# endif
|
||||
#else
|
||||
case VSYSCALL_LAST_PAGE ... VSYSCALL_FIRST_PAGE:
|
||||
#endif
|
||||
#ifdef CONFIG_X86_LOCAL_APIC
|
||||
case FIX_APIC_BASE: /* maps dummy local APIC */
|
||||
#endif
|
||||
case FIX_TEXT_POKE0:
|
||||
case FIX_TEXT_POKE1:
|
||||
|
|
@ -2188,6 +2188,22 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
|
|||
pte = pfn_pte(phys, prot);
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_X86_LOCAL_APIC
|
||||
case FIX_APIC_BASE: /* maps dummy local APIC */
|
||||
pte = pfn_pte(PFN_DOWN(__pa(dummy_mapping)), PAGE_KERNEL);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X86_IO_APIC
|
||||
case FIX_IO_APIC_BASE_0 ... FIX_IO_APIC_BASE_END:
|
||||
/*
|
||||
* We just don't map the IO APIC - all access is via
|
||||
* hypercalls. Keep the address in the pte for reference.
|
||||
*/
|
||||
pte = pfn_pte(PFN_DOWN(__pa(dummy_mapping)), PAGE_KERNEL);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case FIX_PARAVIRT_BOOTMAP:
|
||||
/* This is an MFN, but it isn't an IO mapping from the
|
||||
IO domain */
|
||||
|
|
@ -2212,6 +2228,29 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
|
|||
#endif
|
||||
}
|
||||
|
||||
__init void xen_ident_map_ISA(void)
|
||||
{
|
||||
unsigned long pa;
|
||||
|
||||
/*
|
||||
* If we're dom0, then linear map the ISA machine addresses into
|
||||
* the kernel's address space.
|
||||
*/
|
||||
if (!xen_initial_domain())
|
||||
return;
|
||||
|
||||
xen_raw_printk("Xen: setup ISA identity maps\n");
|
||||
|
||||
for (pa = ISA_START_ADDRESS; pa < ISA_END_ADDRESS; pa += PAGE_SIZE) {
|
||||
pte_t pte = mfn_pte(PFN_DOWN(pa), PAGE_KERNEL_IO);
|
||||
|
||||
if (HYPERVISOR_update_va_mapping(PAGE_OFFSET + pa, pte, 0))
|
||||
BUG();
|
||||
}
|
||||
|
||||
xen_flush_tlb();
|
||||
}
|
||||
|
||||
static __init void xen_post_allocator_init(void)
|
||||
{
|
||||
pv_mmu_ops.set_pte = xen_set_pte;
|
||||
|
|
@ -2320,6 +2359,8 @@ void __init xen_init_mmu_ops(void)
|
|||
pv_mmu_ops = xen_mmu_ops;
|
||||
|
||||
vmap_lazy_unmap = false;
|
||||
|
||||
memset(dummy_mapping, 0xff, PAGE_SIZE);
|
||||
}
|
||||
|
||||
/* Protected by xen_reservation_lock. */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/* Glue code to lib/swiotlb-xen.c */
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/pci.h>
|
||||
#include <xen/swiotlb-xen.h>
|
||||
|
||||
#include <asm/xen/hypervisor.h>
|
||||
|
|
@ -55,6 +56,9 @@ void __init pci_xen_swiotlb_init(void)
|
|||
if (xen_swiotlb) {
|
||||
xen_swiotlb_init(1);
|
||||
dma_ops = &xen_swiotlb_dma_ops;
|
||||
|
||||
/* Make sure ACS will be enabled */
|
||||
pci_request_acs();
|
||||
}
|
||||
}
|
||||
IOMMU_INIT_FINISH(pci_xen_swiotlb_detect,
|
||||
|
|
|
|||
|
|
@ -204,6 +204,9 @@ char * __init xen_memory_setup(void)
|
|||
* Even though this is normal, usable memory under Xen, reserve
|
||||
* ISA memory anyway because too many things think they can poke
|
||||
* about in there.
|
||||
*
|
||||
* In a dom0 kernel, this region is identity mapped with the
|
||||
* hardware ISA area, so it really is out of bounds.
|
||||
*/
|
||||
e820_add_region(ISA_START_ADDRESS, ISA_END_ADDRESS - ISA_START_ADDRESS,
|
||||
E820_RESERVED);
|
||||
|
|
@ -367,7 +370,5 @@ void __init xen_arch_setup(void)
|
|||
|
||||
pm_idle = xen_idle;
|
||||
|
||||
paravirt_disable_iospace();
|
||||
|
||||
fiddle_vdso();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include <asm/xen/interface.h>
|
||||
#include <asm/xen/hypercall.h>
|
||||
|
||||
#include <xen/xen.h>
|
||||
#include <xen/page.h>
|
||||
#include <xen/events.h>
|
||||
|
||||
|
|
@ -156,6 +157,9 @@ static void __init xen_fill_possible_map(void)
|
|||
{
|
||||
int i, rc;
|
||||
|
||||
if (xen_initial_domain())
|
||||
return;
|
||||
|
||||
for (i = 0; i < nr_cpu_ids; i++) {
|
||||
rc = HYPERVISOR_vcpu_op(VCPUOP_is_up, i, NULL);
|
||||
if (rc >= 0) {
|
||||
|
|
@ -165,6 +169,27 @@ static void __init xen_fill_possible_map(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void __init xen_filter_cpu_maps(void)
|
||||
{
|
||||
int i, rc;
|
||||
|
||||
if (!xen_initial_domain())
|
||||
return;
|
||||
|
||||
num_processors = 0;
|
||||
disabled_cpus = 0;
|
||||
for (i = 0; i < nr_cpu_ids; i++) {
|
||||
rc = HYPERVISOR_vcpu_op(VCPUOP_is_up, i, NULL);
|
||||
if (rc >= 0) {
|
||||
num_processors++;
|
||||
set_cpu_possible(i, true);
|
||||
} else {
|
||||
set_cpu_possible(i, false);
|
||||
set_cpu_present(i, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void __init xen_smp_prepare_boot_cpu(void)
|
||||
{
|
||||
BUG_ON(smp_processor_id() != 0);
|
||||
|
|
@ -174,6 +199,7 @@ static void __init xen_smp_prepare_boot_cpu(void)
|
|||
old memory can be recycled */
|
||||
make_lowmem_page_readwrite(xen_initial_gdt);
|
||||
|
||||
xen_filter_cpu_maps();
|
||||
xen_setup_vcpu_info_placement();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue