You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'x86-apic-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86/apic changes from Ingo Molnar:
"Main changes:
- Multiple MSI support added to the APIC, PCI and AHCI code - acked
by all relevant maintainers, by Alexander Gordeev.
The advantage is that multiple AHCI ports can have multiple MSI
irqs assigned, and can thus spread to multiple CPUs.
[ Drivers can make use of this new facility via the
pci_enable_msi_block_auto() method ]
- x86 IOAPIC code from interrupt remapping cleanups from Joerg
Roedel:
These patches move all interrupt remapping specific checks out of
the x86 core code and replaces the respective call-sites with
function pointers. As a result the interrupt remapping code is
better abstraced from x86 core interrupt handling code.
- Various smaller improvements, fixes and cleanups."
* 'x86-apic-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (26 commits)
x86/intel/irq_remapping: Clean up x2apic opt-out security warning mess
x86, kvm: Fix intialization warnings in kvm.c
x86, irq: Move irq_remapped out of x86 core code
x86, io_apic: Introduce eoi_ioapic_pin call-back
x86, msi: Introduce x86_msi.compose_msi_msg call-back
x86, irq: Introduce setup_remapped_irq()
x86, irq: Move irq_remapped() check into free_remapped_irq
x86, io-apic: Remove !irq_remapped() check from __target_IO_APIC_irq()
x86, io-apic: Move CONFIG_IRQ_REMAP code out of x86 core
x86, irq: Add data structure to keep AMD specific irq remapping information
x86, irq: Move irq_remapping_enabled declaration to iommu code
x86, io_apic: Remove irq_remapping_enabled check in setup_timer_IRQ0_pin
x86, io_apic: Move irq_remapping_enabled checks out of check_timer()
x86, io_apic: Convert setup_ioapic_entry to function pointer
x86, io_apic: Introduce set_affinity function pointer
x86, msi: Use IRQ remapping specific setup_msi_irqs routine
x86, hpet: Introduce x86_msi_ops.setup_hpet_msi
x86, io_apic: Introduce x86_io_apic_ops.print_entries for debugging
x86, io_apic: Introduce x86_io_apic_ops.disable()
x86, apic: Mask IO-APIC and PIC unconditionally on LAPIC resume
...
This commit is contained in:
@@ -127,15 +127,42 @@ on the number of vectors that can be allocated; pci_enable_msi_block()
|
||||
returns as soon as it finds any constraint that doesn't allow the
|
||||
call to succeed.
|
||||
|
||||
4.2.3 pci_disable_msi
|
||||
4.2.3 pci_enable_msi_block_auto
|
||||
|
||||
int pci_enable_msi_block_auto(struct pci_dev *dev, unsigned int *count)
|
||||
|
||||
This variation on pci_enable_msi() call allows a device driver to request
|
||||
the maximum possible number of MSIs. The MSI specification only allows
|
||||
interrupts to be allocated in powers of two, up to a maximum of 2^5 (32).
|
||||
|
||||
If this function returns a positive number, it indicates that it has
|
||||
succeeded and the returned value is the number of allocated interrupts. In
|
||||
this case, the function enables MSI on this device and updates dev->irq to
|
||||
be the lowest of the new interrupts assigned to it. The other interrupts
|
||||
assigned to the device are in the range dev->irq to dev->irq + returned
|
||||
value - 1.
|
||||
|
||||
If this function returns a negative number, it indicates an error and
|
||||
the driver should not attempt to request any more MSI interrupts for
|
||||
this device.
|
||||
|
||||
If the device driver needs to know the number of interrupts the device
|
||||
supports it can pass the pointer count where that number is stored. The
|
||||
device driver must decide what action to take if pci_enable_msi_block_auto()
|
||||
succeeds, but returns a value less than the number of interrupts supported.
|
||||
If the device driver does not need to know the number of interrupts
|
||||
supported, it can set the pointer count to NULL.
|
||||
|
||||
4.2.4 pci_disable_msi
|
||||
|
||||
void pci_disable_msi(struct pci_dev *dev)
|
||||
|
||||
This function should be used to undo the effect of pci_enable_msi() or
|
||||
pci_enable_msi_block(). Calling it restores dev->irq to the pin-based
|
||||
interrupt number and frees the previously allocated message signaled
|
||||
interrupt(s). The interrupt may subsequently be assigned to another
|
||||
device, so drivers should not cache the value of dev->irq.
|
||||
pci_enable_msi_block() or pci_enable_msi_block_auto(). Calling it restores
|
||||
dev->irq to the pin-based interrupt number and frees the previously
|
||||
allocated message signaled interrupt(s). The interrupt may subsequently be
|
||||
assigned to another device, so drivers should not cache the value of
|
||||
dev->irq.
|
||||
|
||||
Before calling this function, a device driver must always call free_irq()
|
||||
on any interrupt for which it previously called request_irq().
|
||||
|
||||
@@ -80,9 +80,9 @@ extern void hpet_msi_write(struct hpet_dev *hdev, struct msi_msg *msg);
|
||||
extern void hpet_msi_read(struct hpet_dev *hdev, struct msi_msg *msg);
|
||||
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
extern int arch_setup_hpet_msi(unsigned int irq, unsigned int id);
|
||||
extern int default_setup_hpet_msi(unsigned int irq, unsigned int id);
|
||||
#else
|
||||
static inline int arch_setup_hpet_msi(unsigned int irq, unsigned int id)
|
||||
static inline int default_setup_hpet_msi(unsigned int irq, unsigned int id)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -111,6 +111,7 @@ extern void hpet_unregister_irq_handler(rtc_irq_handler handler);
|
||||
static inline int hpet_enable(void) { return 0; }
|
||||
static inline int is_hpet_enabled(void) { return 0; }
|
||||
#define hpet_readl(a) 0
|
||||
#define default_setup_hpet_msi NULL
|
||||
|
||||
#endif
|
||||
#endif /* _ASM_X86_HPET_H */
|
||||
|
||||
@@ -101,6 +101,7 @@ static inline void set_io_apic_irq_attr(struct io_apic_irq_attr *irq_attr,
|
||||
irq_attr->polarity = polarity;
|
||||
}
|
||||
|
||||
/* Intel specific interrupt remapping information */
|
||||
struct irq_2_iommu {
|
||||
struct intel_iommu *iommu;
|
||||
u16 irte_index;
|
||||
@@ -108,6 +109,12 @@ struct irq_2_iommu {
|
||||
u8 irte_mask;
|
||||
};
|
||||
|
||||
/* AMD specific interrupt remapping information */
|
||||
struct irq_2_irte {
|
||||
u16 devid; /* Device ID for IRTE table */
|
||||
u16 index; /* Index into IRTE table*/
|
||||
};
|
||||
|
||||
/*
|
||||
* This is performance-critical, we want to do it O(1)
|
||||
*
|
||||
@@ -120,7 +127,11 @@ struct irq_cfg {
|
||||
u8 vector;
|
||||
u8 move_in_progress : 1;
|
||||
#ifdef CONFIG_IRQ_REMAP
|
||||
struct irq_2_iommu irq_2_iommu;
|
||||
u8 remapped : 1;
|
||||
union {
|
||||
struct irq_2_iommu irq_2_iommu;
|
||||
struct irq_2_irte irq_2_irte;
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
extern void init_hypervisor(struct cpuinfo_x86 *c);
|
||||
extern void init_hypervisor_platform(void);
|
||||
extern bool hypervisor_x2apic_available(void);
|
||||
|
||||
/*
|
||||
* x86 hypervisor information
|
||||
@@ -41,6 +42,9 @@ struct hypervisor_x86 {
|
||||
|
||||
/* Platform setup (run once per boot) */
|
||||
void (*init_platform)(void);
|
||||
|
||||
/* X2APIC detection (run once per boot) */
|
||||
bool (*x2apic_available)(void);
|
||||
};
|
||||
|
||||
extern const struct hypervisor_x86 *x86_hyper;
|
||||
@@ -51,13 +55,4 @@ extern const struct hypervisor_x86 x86_hyper_ms_hyperv;
|
||||
extern const struct hypervisor_x86 x86_hyper_xen_hvm;
|
||||
extern const struct hypervisor_x86 x86_hyper_kvm;
|
||||
|
||||
static inline bool hypervisor_x2apic_available(void)
|
||||
{
|
||||
if (kvm_para_available())
|
||||
return true;
|
||||
if (xen_x2apic_para_available())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -144,11 +144,24 @@ extern int timer_through_8259;
|
||||
(mp_irq_entries && !skip_ioapic_setup && io_apic_irqs)
|
||||
|
||||
struct io_apic_irq_attr;
|
||||
struct irq_cfg;
|
||||
extern int io_apic_set_pci_routing(struct device *dev, int irq,
|
||||
struct io_apic_irq_attr *irq_attr);
|
||||
void setup_IO_APIC_irq_extra(u32 gsi);
|
||||
extern void ioapic_insert_resources(void);
|
||||
|
||||
extern int native_setup_ioapic_entry(int, struct IO_APIC_route_entry *,
|
||||
unsigned int, int,
|
||||
struct io_apic_irq_attr *);
|
||||
extern int native_setup_ioapic_entry(int, struct IO_APIC_route_entry *,
|
||||
unsigned int, int,
|
||||
struct io_apic_irq_attr *);
|
||||
extern void eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg);
|
||||
|
||||
extern void native_compose_msi_msg(struct pci_dev *pdev,
|
||||
unsigned int irq, unsigned int dest,
|
||||
struct msi_msg *msg, u8 hpet_id);
|
||||
extern void native_eoi_ioapic_pin(int apic, int pin, int vector);
|
||||
int io_apic_setup_irq_pin_once(unsigned int irq, int node, struct io_apic_irq_attr *attr);
|
||||
|
||||
extern int save_ioapic_entries(void);
|
||||
@@ -179,6 +192,12 @@ extern void __init native_io_apic_init_mappings(void);
|
||||
extern unsigned int native_io_apic_read(unsigned int apic, unsigned int reg);
|
||||
extern void native_io_apic_write(unsigned int apic, unsigned int reg, unsigned int val);
|
||||
extern void native_io_apic_modify(unsigned int apic, unsigned int reg, unsigned int val);
|
||||
extern void native_disable_io_apic(void);
|
||||
extern void native_io_apic_print_entries(unsigned int apic, unsigned int nr_entries);
|
||||
extern void intel_ir_io_apic_print_entries(unsigned int apic, unsigned int nr_entries);
|
||||
extern int native_ioapic_set_affinity(struct irq_data *,
|
||||
const struct cpumask *,
|
||||
bool);
|
||||
|
||||
static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
|
||||
{
|
||||
@@ -193,6 +212,9 @@ static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned
|
||||
{
|
||||
x86_io_apic_ops.modify(apic, reg, value);
|
||||
}
|
||||
|
||||
extern void io_apic_eoi(unsigned int apic, unsigned int vector);
|
||||
|
||||
#else /* !CONFIG_X86_IO_APIC */
|
||||
|
||||
#define io_apic_assign_pci_irqs 0
|
||||
@@ -223,6 +245,12 @@ static inline void disable_ioapic_support(void) { }
|
||||
#define native_io_apic_read NULL
|
||||
#define native_io_apic_write NULL
|
||||
#define native_io_apic_modify NULL
|
||||
#define native_disable_io_apic NULL
|
||||
#define native_io_apic_print_entries NULL
|
||||
#define native_ioapic_set_affinity NULL
|
||||
#define native_setup_ioapic_entry NULL
|
||||
#define native_compose_msi_msg NULL
|
||||
#define native_eoi_ioapic_pin NULL
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_X86_IO_APIC_H */
|
||||
|
||||
@@ -26,8 +26,6 @@
|
||||
|
||||
#ifdef CONFIG_IRQ_REMAP
|
||||
|
||||
extern int irq_remapping_enabled;
|
||||
|
||||
extern void setup_irq_remapping_ops(void);
|
||||
extern int irq_remapping_supported(void);
|
||||
extern int irq_remapping_prepare(void);
|
||||
@@ -40,22 +38,20 @@ extern int setup_ioapic_remapped_entry(int irq,
|
||||
unsigned int destination,
|
||||
int vector,
|
||||
struct io_apic_irq_attr *attr);
|
||||
extern int set_remapped_irq_affinity(struct irq_data *data,
|
||||
const struct cpumask *mask,
|
||||
bool force);
|
||||
extern void free_remapped_irq(int irq);
|
||||
extern void compose_remapped_msi_msg(struct pci_dev *pdev,
|
||||
unsigned int irq, unsigned int dest,
|
||||
struct msi_msg *msg, u8 hpet_id);
|
||||
extern int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec);
|
||||
extern int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
|
||||
int index, int sub_handle);
|
||||
extern int setup_hpet_msi_remapped(unsigned int irq, unsigned int id);
|
||||
extern void panic_if_irq_remap(const char *msg);
|
||||
extern bool setup_remapped_irq(int irq,
|
||||
struct irq_cfg *cfg,
|
||||
struct irq_chip *chip);
|
||||
|
||||
void irq_remap_modify_chip_defaults(struct irq_chip *chip);
|
||||
|
||||
#else /* CONFIG_IRQ_REMAP */
|
||||
|
||||
#define irq_remapping_enabled 0
|
||||
|
||||
static inline void setup_irq_remapping_ops(void) { }
|
||||
static inline int irq_remapping_supported(void) { return 0; }
|
||||
static inline int irq_remapping_prepare(void) { return -ENODEV; }
|
||||
@@ -71,31 +67,31 @@ static inline int setup_ioapic_remapped_entry(int irq,
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
static inline int set_remapped_irq_affinity(struct irq_data *data,
|
||||
const struct cpumask *mask,
|
||||
bool force)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void free_remapped_irq(int irq) { }
|
||||
static inline void compose_remapped_msi_msg(struct pci_dev *pdev,
|
||||
unsigned int irq, unsigned int dest,
|
||||
struct msi_msg *msg, u8 hpet_id)
|
||||
{
|
||||
}
|
||||
static inline int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
static inline int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
|
||||
int index, int sub_handle)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
static inline int setup_hpet_msi_remapped(unsigned int irq, unsigned int id)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline void panic_if_irq_remap(const char *msg)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void irq_remap_modify_chip_defaults(struct irq_chip *chip)
|
||||
{
|
||||
}
|
||||
|
||||
static inline bool setup_remapped_irq(int irq,
|
||||
struct irq_cfg *cfg,
|
||||
struct irq_chip *chip)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif /* CONFIG_IRQ_REMAP */
|
||||
|
||||
#endif /* __X86_IRQ_REMAPPING_H */
|
||||
|
||||
@@ -85,13 +85,13 @@ static inline long kvm_hypercall4(unsigned int nr, unsigned long p1,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int kvm_para_available(void)
|
||||
static inline bool kvm_para_available(void)
|
||||
{
|
||||
unsigned int eax, ebx, ecx, edx;
|
||||
char signature[13];
|
||||
|
||||
if (boot_cpu_data.cpuid_level < 0)
|
||||
return 0; /* So we don't blow up on old processors */
|
||||
return false; /* So we don't blow up on old processors */
|
||||
|
||||
if (cpu_has_hypervisor) {
|
||||
cpuid(KVM_CPUID_SIGNATURE, &eax, &ebx, &ecx, &edx);
|
||||
@@ -101,10 +101,10 @@ static inline int kvm_para_available(void)
|
||||
signature[12] = 0;
|
||||
|
||||
if (strcmp(signature, "KVMKVMKVM") == 0)
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline unsigned int kvm_arch_para_features(void)
|
||||
|
||||
@@ -121,9 +121,12 @@ static inline void x86_restore_msi_irqs(struct pci_dev *dev, int irq)
|
||||
#define arch_teardown_msi_irq x86_teardown_msi_irq
|
||||
#define arch_restore_msi_irqs x86_restore_msi_irqs
|
||||
/* implemented in arch/x86/kernel/apic/io_apic. */
|
||||
struct msi_desc;
|
||||
int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
|
||||
void native_teardown_msi_irq(unsigned int irq);
|
||||
void native_restore_msi_irqs(struct pci_dev *dev, int irq);
|
||||
int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
|
||||
unsigned int irq_base, unsigned int irq_offset);
|
||||
/* default to the implementation in drivers/lib/msi.c */
|
||||
#define HAVE_DEFAULT_MSI_TEARDOWN_IRQS
|
||||
#define HAVE_DEFAULT_MSI_RESTORE_IRQS
|
||||
|
||||
@@ -181,19 +181,38 @@ struct x86_platform_ops {
|
||||
};
|
||||
|
||||
struct pci_dev;
|
||||
struct msi_msg;
|
||||
|
||||
struct x86_msi_ops {
|
||||
int (*setup_msi_irqs)(struct pci_dev *dev, int nvec, int type);
|
||||
void (*compose_msi_msg)(struct pci_dev *dev, unsigned int irq,
|
||||
unsigned int dest, struct msi_msg *msg,
|
||||
u8 hpet_id);
|
||||
void (*teardown_msi_irq)(unsigned int irq);
|
||||
void (*teardown_msi_irqs)(struct pci_dev *dev);
|
||||
void (*restore_msi_irqs)(struct pci_dev *dev, int irq);
|
||||
int (*setup_hpet_msi)(unsigned int irq, unsigned int id);
|
||||
};
|
||||
|
||||
struct IO_APIC_route_entry;
|
||||
struct io_apic_irq_attr;
|
||||
struct irq_data;
|
||||
struct cpumask;
|
||||
|
||||
struct x86_io_apic_ops {
|
||||
void (*init) (void);
|
||||
unsigned int (*read) (unsigned int apic, unsigned int reg);
|
||||
void (*write) (unsigned int apic, unsigned int reg, unsigned int value);
|
||||
void (*modify)(unsigned int apic, unsigned int reg, unsigned int value);
|
||||
void (*init) (void);
|
||||
unsigned int (*read) (unsigned int apic, unsigned int reg);
|
||||
void (*write) (unsigned int apic, unsigned int reg, unsigned int value);
|
||||
void (*modify) (unsigned int apic, unsigned int reg, unsigned int value);
|
||||
void (*disable)(void);
|
||||
void (*print_entries)(unsigned int apic, unsigned int nr_entries);
|
||||
int (*set_affinity)(struct irq_data *data,
|
||||
const struct cpumask *mask,
|
||||
bool force);
|
||||
int (*setup_entry)(int irq, struct IO_APIC_route_entry *entry,
|
||||
unsigned int destination, int vector,
|
||||
struct io_apic_irq_attr *attr);
|
||||
void (*eoi_ioapic_pin)(int apic, int pin, int vector);
|
||||
};
|
||||
|
||||
extern struct x86_init_ops x86_init;
|
||||
|
||||
+12
-16
@@ -1477,8 +1477,7 @@ void __init bsp_end_local_APIC_setup(void)
|
||||
* Now that local APIC setup is completed for BP, configure the fault
|
||||
* handling for interrupt remapping.
|
||||
*/
|
||||
if (irq_remapping_enabled)
|
||||
irq_remap_enable_fault_handling();
|
||||
irq_remap_enable_fault_handling();
|
||||
|
||||
}
|
||||
|
||||
@@ -2251,8 +2250,7 @@ static int lapic_suspend(void)
|
||||
local_irq_save(flags);
|
||||
disable_local_APIC();
|
||||
|
||||
if (irq_remapping_enabled)
|
||||
irq_remapping_disable();
|
||||
irq_remapping_disable();
|
||||
|
||||
local_irq_restore(flags);
|
||||
return 0;
|
||||
@@ -2268,16 +2266,15 @@ static void lapic_resume(void)
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
if (irq_remapping_enabled) {
|
||||
/*
|
||||
* IO-APIC and PIC have their own resume routines.
|
||||
* We just mask them here to make sure the interrupt
|
||||
* subsystem is completely quiet while we enable x2apic
|
||||
* and interrupt-remapping.
|
||||
*/
|
||||
mask_ioapic_entries();
|
||||
legacy_pic->mask_all();
|
||||
}
|
||||
|
||||
/*
|
||||
* IO-APIC and PIC have their own resume routines.
|
||||
* We just mask them here to make sure the interrupt
|
||||
* subsystem is completely quiet while we enable x2apic
|
||||
* and interrupt-remapping.
|
||||
*/
|
||||
mask_ioapic_entries();
|
||||
legacy_pic->mask_all();
|
||||
|
||||
if (x2apic_mode)
|
||||
enable_x2apic();
|
||||
@@ -2320,8 +2317,7 @@ static void lapic_resume(void)
|
||||
apic_write(APIC_ESR, 0);
|
||||
apic_read(APIC_ESR);
|
||||
|
||||
if (irq_remapping_enabled)
|
||||
irq_remapping_reenable(x2apic_mode);
|
||||
irq_remapping_reenable(x2apic_mode);
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
+202
-261
File diff suppressed because it is too large
Load Diff
@@ -106,7 +106,7 @@ void default_send_IPI_mask_logical(const struct cpumask *cpumask, int vector)
|
||||
unsigned long mask = cpumask_bits(cpumask)[0];
|
||||
unsigned long flags;
|
||||
|
||||
if (WARN_ONCE(!mask, "empty IPI mask"))
|
||||
if (!mask)
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
@@ -79,3 +79,10 @@ void __init init_hypervisor_platform(void)
|
||||
if (x86_hyper->init_platform)
|
||||
x86_hyper->init_platform();
|
||||
}
|
||||
|
||||
bool __init hypervisor_x2apic_available(void)
|
||||
{
|
||||
return x86_hyper &&
|
||||
x86_hyper->x2apic_available &&
|
||||
x86_hyper->x2apic_available();
|
||||
}
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
|
||||
#define VMWARE_PORT_CMD_GETVERSION 10
|
||||
#define VMWARE_PORT_CMD_GETHZ 45
|
||||
#define VMWARE_PORT_CMD_GETVCPU_INFO 68
|
||||
#define VMWARE_PORT_CMD_LEGACY_X2APIC 3
|
||||
#define VMWARE_PORT_CMD_VCPU_RESERVED 31
|
||||
|
||||
#define VMWARE_PORT(cmd, eax, ebx, ecx, edx) \
|
||||
__asm__("inl (%%dx)" : \
|
||||
@@ -125,10 +128,20 @@ static void __cpuinit vmware_set_cpu_features(struct cpuinfo_x86 *c)
|
||||
set_cpu_cap(c, X86_FEATURE_TSC_RELIABLE);
|
||||
}
|
||||
|
||||
/* Checks if hypervisor supports x2apic without VT-D interrupt remapping. */
|
||||
static bool __init vmware_legacy_x2apic_available(void)
|
||||
{
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
VMWARE_PORT(GETVCPU_INFO, eax, ebx, ecx, edx);
|
||||
return (eax & (1 << VMWARE_PORT_CMD_VCPU_RESERVED)) == 0 &&
|
||||
(eax & (1 << VMWARE_PORT_CMD_LEGACY_X2APIC)) != 0;
|
||||
}
|
||||
|
||||
const __refconst struct hypervisor_x86 x86_hyper_vmware = {
|
||||
.name = "VMware",
|
||||
.detect = vmware_platform,
|
||||
.set_cpu_features = vmware_set_cpu_features,
|
||||
.init_platform = vmware_platform_setup,
|
||||
.x2apic_available = vmware_legacy_x2apic_available,
|
||||
};
|
||||
EXPORT_SYMBOL(x86_hyper_vmware);
|
||||
|
||||
@@ -478,7 +478,7 @@ static int hpet_msi_next_event(unsigned long delta,
|
||||
|
||||
static int hpet_setup_msi_irq(unsigned int irq)
|
||||
{
|
||||
if (arch_setup_hpet_msi(irq, hpet_blockid)) {
|
||||
if (x86_msi.setup_hpet_msi(irq, hpet_blockid)) {
|
||||
destroy_irq(irq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -505,6 +505,7 @@ static bool __init kvm_detect(void)
|
||||
const struct hypervisor_x86 x86_hyper_kvm __refconst = {
|
||||
.name = "KVM",
|
||||
.detect = kvm_detect,
|
||||
.x2apic_available = kvm_para_available,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(x86_hyper_kvm);
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <asm/time.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/io_apic.h>
|
||||
#include <asm/hpet.h>
|
||||
#include <asm/pat.h>
|
||||
#include <asm/tsc.h>
|
||||
#include <asm/iommu.h>
|
||||
@@ -111,15 +112,22 @@ 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,
|
||||
.restore_msi_irqs = default_restore_msi_irqs,
|
||||
.setup_msi_irqs = native_setup_msi_irqs,
|
||||
.compose_msi_msg = native_compose_msi_msg,
|
||||
.teardown_msi_irq = native_teardown_msi_irq,
|
||||
.teardown_msi_irqs = default_teardown_msi_irqs,
|
||||
.restore_msi_irqs = default_restore_msi_irqs,
|
||||
.setup_hpet_msi = default_setup_hpet_msi,
|
||||
};
|
||||
|
||||
struct x86_io_apic_ops x86_io_apic_ops = {
|
||||
.init = native_io_apic_init_mappings,
|
||||
.read = native_io_apic_read,
|
||||
.write = native_io_apic_write,
|
||||
.modify = native_io_apic_modify,
|
||||
.init = native_io_apic_init_mappings,
|
||||
.read = native_io_apic_read,
|
||||
.write = native_io_apic_write,
|
||||
.modify = native_io_apic_modify,
|
||||
.disable = native_disable_io_apic,
|
||||
.print_entries = native_io_apic_print_entries,
|
||||
.set_affinity = native_ioapic_set_affinity,
|
||||
.setup_entry = native_setup_ioapic_entry,
|
||||
.eoi_ioapic_pin = native_eoi_ioapic_pin,
|
||||
};
|
||||
|
||||
@@ -1637,6 +1637,7 @@ const struct hypervisor_x86 x86_hyper_xen_hvm __refconst = {
|
||||
.name = "Xen HVM",
|
||||
.detect = xen_hvm_platform,
|
||||
.init_platform = xen_hvm_guest_init,
|
||||
.x2apic_available = xen_x2apic_para_available,
|
||||
};
|
||||
EXPORT_SYMBOL(x86_hyper_xen_hvm);
|
||||
#endif
|
||||
|
||||
+89
-4
@@ -1061,6 +1061,86 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host)
|
||||
{}
|
||||
#endif
|
||||
|
||||
int ahci_init_interrupts(struct pci_dev *pdev, struct ahci_host_priv *hpriv)
|
||||
{
|
||||
int rc;
|
||||
unsigned int maxvec;
|
||||
|
||||
if (!(hpriv->flags & AHCI_HFLAG_NO_MSI)) {
|
||||
rc = pci_enable_msi_block_auto(pdev, &maxvec);
|
||||
if (rc > 0) {
|
||||
if ((rc == maxvec) || (rc == 1))
|
||||
return rc;
|
||||
/*
|
||||
* Assume that advantage of multipe MSIs is negated,
|
||||
* so fallback to single MSI mode to save resources
|
||||
*/
|
||||
pci_disable_msi(pdev);
|
||||
if (!pci_enable_msi(pdev))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
pci_intx(pdev, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ahci_host_activate - start AHCI host, request IRQs and register it
|
||||
* @host: target ATA host
|
||||
* @irq: base IRQ number to request
|
||||
* @n_msis: number of MSIs allocated for this host
|
||||
* @irq_handler: irq_handler used when requesting IRQs
|
||||
* @irq_flags: irq_flags used when requesting IRQs
|
||||
*
|
||||
* Similar to ata_host_activate, but requests IRQs according to AHCI-1.1
|
||||
* when multiple MSIs were allocated. That is one MSI per port, starting
|
||||
* from @irq.
|
||||
*
|
||||
* LOCKING:
|
||||
* Inherited from calling layer (may sleep).
|
||||
*
|
||||
* RETURNS:
|
||||
* 0 on success, -errno otherwise.
|
||||
*/
|
||||
int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis)
|
||||
{
|
||||
int i, rc;
|
||||
|
||||
/* Sharing Last Message among several ports is not supported */
|
||||
if (n_msis < host->n_ports)
|
||||
return -EINVAL;
|
||||
|
||||
rc = ata_host_start(host);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
for (i = 0; i < host->n_ports; i++) {
|
||||
rc = devm_request_threaded_irq(host->dev,
|
||||
irq + i, ahci_hw_interrupt, ahci_thread_fn, IRQF_SHARED,
|
||||
dev_driver_string(host->dev), host->ports[i]);
|
||||
if (rc)
|
||||
goto out_free_irqs;
|
||||
}
|
||||
|
||||
for (i = 0; i < host->n_ports; i++)
|
||||
ata_port_desc(host->ports[i], "irq %d", irq + i);
|
||||
|
||||
rc = ata_host_register(host, &ahci_sht);
|
||||
if (rc)
|
||||
goto out_free_all_irqs;
|
||||
|
||||
return 0;
|
||||
|
||||
out_free_all_irqs:
|
||||
i = host->n_ports;
|
||||
out_free_irqs:
|
||||
for (i--; i >= 0; i--)
|
||||
devm_free_irq(host->dev, irq + i, host->ports[i]);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
{
|
||||
unsigned int board_id = ent->driver_data;
|
||||
@@ -1069,7 +1149,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct ahci_host_priv *hpriv;
|
||||
struct ata_host *host;
|
||||
int n_ports, i, rc;
|
||||
int n_ports, n_msis, i, rc;
|
||||
int ahci_pci_bar = AHCI_PCI_BAR_STANDARD;
|
||||
|
||||
VPRINTK("ENTER\n");
|
||||
@@ -1156,11 +1236,12 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
if (ahci_sb600_enable_64bit(pdev))
|
||||
hpriv->flags &= ~AHCI_HFLAG_32BIT_ONLY;
|
||||
|
||||
if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
|
||||
pci_intx(pdev, 1);
|
||||
|
||||
hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar];
|
||||
|
||||
n_msis = ahci_init_interrupts(pdev, hpriv);
|
||||
if (n_msis > 1)
|
||||
hpriv->flags |= AHCI_HFLAG_MULTI_MSI;
|
||||
|
||||
/* save initial config */
|
||||
ahci_pci_save_initial_config(pdev, hpriv);
|
||||
|
||||
@@ -1256,6 +1337,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
ahci_pci_print_info(host);
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
if (hpriv->flags & AHCI_HFLAG_MULTI_MSI)
|
||||
return ahci_host_activate(host, pdev->irq, n_msis);
|
||||
|
||||
return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED,
|
||||
&ahci_sht);
|
||||
}
|
||||
|
||||
@@ -231,6 +231,7 @@ enum {
|
||||
AHCI_HFLAG_DELAY_ENGINE = (1 << 15), /* do not start engine on
|
||||
port start (wait until
|
||||
error-handling stage) */
|
||||
AHCI_HFLAG_MULTI_MSI = (1 << 16), /* multiple PCI MSIs */
|
||||
|
||||
/* ap->flags bits */
|
||||
|
||||
@@ -297,6 +298,8 @@ struct ahci_port_priv {
|
||||
unsigned int ncq_saw_d2h:1;
|
||||
unsigned int ncq_saw_dmas:1;
|
||||
unsigned int ncq_saw_sdb:1;
|
||||
u32 intr_status; /* interrupts to handle */
|
||||
spinlock_t lock; /* protects parent ata_port */
|
||||
u32 intr_mask; /* interrupts to enable */
|
||||
bool fbs_supported; /* set iff FBS is supported */
|
||||
bool fbs_enabled; /* set iff FBS is enabled */
|
||||
@@ -359,7 +362,10 @@ void ahci_set_em_messages(struct ahci_host_priv *hpriv,
|
||||
struct ata_port_info *pi);
|
||||
int ahci_reset_em(struct ata_host *host);
|
||||
irqreturn_t ahci_interrupt(int irq, void *dev_instance);
|
||||
irqreturn_t ahci_hw_interrupt(int irq, void *dev_instance);
|
||||
irqreturn_t ahci_thread_fn(int irq, void *dev_instance);
|
||||
void ahci_print_info(struct ata_host *host, const char *scc_s);
|
||||
int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis);
|
||||
|
||||
static inline void __iomem *__ahci_port_base(struct ata_host *host,
|
||||
unsigned int port_no)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user