Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ffa009c3 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* git://git.infradead.org/iommu-2.6:
  drivers/pci/intr_remapping.c: include acpi.h
  intel-iommu: Fix oops in device_to_iommu() when devices not found.
  intel-iommu: Handle PCI domains appropriately.
  intel-iommu: Fix device-to-iommu mapping for PCI-PCI bridges.
  x2apic/intr-remap: decouple interrupt remapping from x2apic
  x86, dmar: check if it's initialized before disable queue invalidation
  intel-iommu: set compatibility format interrupt
  Intel IOMMU Suspend/Resume Support - Interrupt Remapping
  Intel IOMMU Suspend/Resume Support - Queued Invalidation
  Intel IOMMU Suspend/Resume Support - DMAR
  intel-iommu: Add for_each_iommu() and for_each_active_iommu() macros
parents 8e320d02 46f06b72
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -253,6 +253,7 @@ config SMP
config X86_X2APIC
config X86_X2APIC
	bool "Support x2apic"
	bool "Support x2apic"
	depends on X86_LOCAL_APIC && X86_64
	depends on X86_LOCAL_APIC && X86_64
	select INTR_REMAP
	---help---
	---help---
	  This enables x2apic support on CPUs that have this feature.
	  This enables x2apic support on CPUs that have this feature.


@@ -1881,7 +1882,6 @@ config DMAR_FLOPPY_WA
config INTR_REMAP
config INTR_REMAP
	bool "Support for Interrupt Remapping (EXPERIMENTAL)"
	bool "Support for Interrupt Remapping (EXPERIMENTAL)"
	depends on X86_64 && X86_IO_APIC && PCI_MSI && ACPI && EXPERIMENTAL
	depends on X86_64 && X86_IO_APIC && PCI_MSI && ACPI && EXPERIMENTAL
	select X86_X2APIC
	---help---
	---help---
	  Supports Interrupt remapping for IO-APIC and MSI devices.
	  Supports Interrupt remapping for IO-APIC and MSI devices.
	  To use x2apic mode in the CPU's which support x2APIC enhancements or
	  To use x2apic mode in the CPU's which support x2APIC enhancements or
+3 −0
Original line number Original line Diff line number Diff line
@@ -107,6 +107,9 @@ extern u32 native_safe_apic_wait_icr_idle(void);
extern void native_apic_icr_write(u32 low, u32 id);
extern void native_apic_icr_write(u32 low, u32 id);
extern u64 native_apic_icr_read(void);
extern u64 native_apic_icr_read(void);


#define EIM_8BIT_APIC_ID	0
#define EIM_32BIT_APIC_ID	1

#ifdef CONFIG_X86_X2APIC
#ifdef CONFIG_X86_X2APIC
/*
/*
 * Make previous memory operations globally visible before
 * Make previous memory operations globally visible before
+7 −4
Original line number Original line Diff line number Diff line
@@ -162,10 +162,13 @@ extern int (*ioapic_renumber_irq)(int ioapic, int irq);
extern void ioapic_init_mappings(void);
extern void ioapic_init_mappings(void);


#ifdef CONFIG_X86_64
#ifdef CONFIG_X86_64
extern int save_IO_APIC_setup(void);
extern struct IO_APIC_route_entry **alloc_ioapic_entries(void);
extern void mask_IO_APIC_setup(void);
extern void free_ioapic_entries(struct IO_APIC_route_entry **ioapic_entries);
extern void restore_IO_APIC_setup(void);
extern int save_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries);
extern void reinit_intr_remapped_IO_APIC(int);
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 reinit_intr_remapped_IO_APIC(int intr_remapping,
	struct IO_APIC_route_entry **ioapic_entries);
#endif
#endif


extern void probe_nr_irqs_gsi(void);
extern void probe_nr_irqs_gsi(void);
+62 −8
Original line number Original line Diff line number Diff line
@@ -1304,6 +1304,7 @@ void __init enable_IR_x2apic(void)
#ifdef CONFIG_INTR_REMAP
#ifdef CONFIG_INTR_REMAP
	int ret;
	int ret;
	unsigned long flags;
	unsigned long flags;
	struct IO_APIC_route_entry **ioapic_entries = NULL;


	if (!cpu_has_x2apic)
	if (!cpu_has_x2apic)
		return;
		return;
@@ -1334,17 +1335,23 @@ void __init enable_IR_x2apic(void)
		return;
		return;
	}
	}


	ret = save_IO_APIC_setup();
	ioapic_entries = alloc_ioapic_entries();
	if (!ioapic_entries) {
		pr_info("Allocate ioapic_entries failed: %d\n", ret);
		goto end;
	}

	ret = save_IO_APIC_setup(ioapic_entries);
	if (ret) {
	if (ret) {
		pr_info("Saving IO-APIC state failed: %d\n", ret);
		pr_info("Saving IO-APIC state failed: %d\n", ret);
		goto end;
		goto end;
	}
	}


	local_irq_save(flags);
	local_irq_save(flags);
	mask_IO_APIC_setup();
	mask_IO_APIC_setup(ioapic_entries);
	mask_8259A();
	mask_8259A();


	ret = enable_intr_remapping(1);
	ret = enable_intr_remapping(EIM_32BIT_APIC_ID);


	if (ret && x2apic_preenabled) {
	if (ret && x2apic_preenabled) {
		local_irq_restore(flags);
		local_irq_restore(flags);
@@ -1364,9 +1371,9 @@ void __init enable_IR_x2apic(void)
		/*
		/*
		 * IR enabling failed
		 * IR enabling failed
		 */
		 */
		restore_IO_APIC_setup();
		restore_IO_APIC_setup(ioapic_entries);
	else
	else
		reinit_intr_remapped_IO_APIC(x2apic_preenabled);
		reinit_intr_remapped_IO_APIC(x2apic_preenabled, ioapic_entries);


	unmask_8259A();
	unmask_8259A();
	local_irq_restore(flags);
	local_irq_restore(flags);
@@ -1379,6 +1386,8 @@ void __init enable_IR_x2apic(void)
			pr_info("Enabled Interrupt-remapping\n");
			pr_info("Enabled Interrupt-remapping\n");
	} else
	} else
		pr_err("Failed to enable Interrupt-remapping and x2apic\n");
		pr_err("Failed to enable Interrupt-remapping and x2apic\n");
	if (ioapic_entries)
		free_ioapic_entries(ioapic_entries);
#else
#else
	if (!cpu_has_x2apic)
	if (!cpu_has_x2apic)
		return;
		return;
@@ -1954,6 +1963,10 @@ static int lapic_suspend(struct sys_device *dev, pm_message_t state)


	local_irq_save(flags);
	local_irq_save(flags);
	disable_local_APIC();
	disable_local_APIC();
#ifdef CONFIG_INTR_REMAP
	if (intr_remapping_enabled)
		disable_intr_remapping();
#endif
	local_irq_restore(flags);
	local_irq_restore(flags);
	return 0;
	return 0;
}
}
@@ -1964,15 +1977,41 @@ static int lapic_resume(struct sys_device *dev)
	unsigned long flags;
	unsigned long flags;
	int maxlvt;
	int maxlvt;


#ifdef CONFIG_INTR_REMAP
	int ret;
	struct IO_APIC_route_entry **ioapic_entries = NULL;

	if (!apic_pm_state.active)
	if (!apic_pm_state.active)
		return 0;
		return 0;


	maxlvt = lapic_get_maxlvt();

	local_irq_save(flags);
	local_irq_save(flags);
	if (x2apic) {
		ioapic_entries = alloc_ioapic_entries();
		if (!ioapic_entries) {
			WARN(1, "Alloc ioapic_entries in lapic resume failed.");
			return -ENOMEM;
		}


		ret = save_IO_APIC_setup(ioapic_entries);
		if (ret) {
			WARN(1, "Saving IO-APIC state failed: %d\n", ret);
			free_ioapic_entries(ioapic_entries);
			return ret;
		}

		mask_IO_APIC_setup(ioapic_entries);
		mask_8259A();
		enable_x2apic();
	}
#else
	if (!apic_pm_state.active)
		return 0;

	local_irq_save(flags);
	if (x2apic)
	if (x2apic)
		enable_x2apic();
		enable_x2apic();
#endif

	else {
	else {
		/*
		/*
		 * Make sure the APICBASE points to the right address
		 * Make sure the APICBASE points to the right address
@@ -1986,6 +2025,7 @@ static int lapic_resume(struct sys_device *dev)
		wrmsr(MSR_IA32_APICBASE, l, h);
		wrmsr(MSR_IA32_APICBASE, l, h);
	}
	}


	maxlvt = lapic_get_maxlvt();
	apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED);
	apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED);
	apic_write(APIC_ID, apic_pm_state.apic_id);
	apic_write(APIC_ID, apic_pm_state.apic_id);
	apic_write(APIC_DFR, apic_pm_state.apic_dfr);
	apic_write(APIC_DFR, apic_pm_state.apic_dfr);
@@ -2009,8 +2049,20 @@ static int lapic_resume(struct sys_device *dev)
	apic_write(APIC_ESR, 0);
	apic_write(APIC_ESR, 0);
	apic_read(APIC_ESR);
	apic_read(APIC_ESR);


#ifdef CONFIG_INTR_REMAP
	if (intr_remapping_enabled)
		reenable_intr_remapping(EIM_32BIT_APIC_ID);

	if (x2apic) {
		unmask_8259A();
		restore_IO_APIC_setup(ioapic_entries);
		free_ioapic_entries(ioapic_entries);
	}
#endif

	local_irq_restore(flags);
	local_irq_restore(flags);



	return 0;
	return 0;
}
}


@@ -2048,7 +2100,9 @@ static int __init init_lapic_sysfs(void)
		error = sysdev_register(&device_lapic);
		error = sysdev_register(&device_lapic);
	return error;
	return error;
}
}
device_initcall(init_lapic_sysfs);

/* local apic needs to resume before other devices access its registers. */
core_initcall(init_lapic_sysfs);


#else	/* CONFIG_PM */
#else	/* CONFIG_PM */


+94 −46
Original line number Original line Diff line number Diff line
@@ -851,63 +851,74 @@ __setup("pirq=", ioapic_pirq_setup);
#endif /* CONFIG_X86_32 */
#endif /* CONFIG_X86_32 */


#ifdef CONFIG_INTR_REMAP
#ifdef CONFIG_INTR_REMAP
/* I/O APIC RTE contents at the OS boot up */
struct IO_APIC_route_entry **alloc_ioapic_entries(void)
static struct IO_APIC_route_entry *early_ioapic_entries[MAX_IO_APICS];
{
	int apic;
	struct IO_APIC_route_entry **ioapic_entries;

	ioapic_entries = kzalloc(sizeof(*ioapic_entries) * nr_ioapics,
				GFP_ATOMIC);
	if (!ioapic_entries)
		return 0;

	for (apic = 0; apic < nr_ioapics; apic++) {
		ioapic_entries[apic] =
			kzalloc(sizeof(struct IO_APIC_route_entry) *
				nr_ioapic_registers[apic], GFP_ATOMIC);
		if (!ioapic_entries[apic])
			goto nomem;
	}

	return ioapic_entries;

nomem:
	while (--apic >= 0)
		kfree(ioapic_entries[apic]);
	kfree(ioapic_entries);

	return 0;
}


/*
/*
 * Saves all the IO-APIC RTE's
 * Saves all the IO-APIC RTE's
 */
 */
int save_IO_APIC_setup(void)
int save_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries)
{
{
	union IO_APIC_reg_01 reg_01;
	unsigned long flags;
	int apic, pin;
	int apic, pin;


	/*
	if (!ioapic_entries)
	 * The number of IO-APIC IRQ registers (== #pins):
		return -ENOMEM;
	 */
	for (apic = 0; apic < nr_ioapics; apic++) {
		spin_lock_irqsave(&ioapic_lock, flags);
		reg_01.raw = io_apic_read(apic, 1);
		spin_unlock_irqrestore(&ioapic_lock, flags);
		nr_ioapic_registers[apic] = reg_01.bits.entries+1;
	}


	for (apic = 0; apic < nr_ioapics; apic++) {
	for (apic = 0; apic < nr_ioapics; apic++) {
		early_ioapic_entries[apic] =
		if (!ioapic_entries[apic])
			kzalloc(sizeof(struct IO_APIC_route_entry) *
			return -ENOMEM;
				nr_ioapic_registers[apic], GFP_KERNEL);
		if (!early_ioapic_entries[apic])
			goto nomem;
	}


	for (apic = 0; apic < nr_ioapics; apic++)
		for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
		for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
			early_ioapic_entries[apic][pin] =
			ioapic_entries[apic][pin] =
				ioapic_read_entry(apic, pin);
				ioapic_read_entry(apic, pin);
	}


	return 0;
	return 0;

nomem:
	while (apic >= 0)
		kfree(early_ioapic_entries[apic--]);
	memset(early_ioapic_entries, 0,
		ARRAY_SIZE(early_ioapic_entries));

	return -ENOMEM;
}
}


void mask_IO_APIC_setup(void)
/*
 * Mask all IO APIC entries.
 */
void mask_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries)
{
{
	int apic, pin;
	int apic, pin;


	if (!ioapic_entries)
		return;

	for (apic = 0; apic < nr_ioapics; apic++) {
	for (apic = 0; apic < nr_ioapics; apic++) {
		if (!early_ioapic_entries[apic])
		if (!ioapic_entries[apic])
			break;
			break;

		for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
		for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
			struct IO_APIC_route_entry entry;
			struct IO_APIC_route_entry entry;


			entry = early_ioapic_entries[apic][pin];
			entry = ioapic_entries[apic][pin];
			if (!entry.mask) {
			if (!entry.mask) {
				entry.mask = 1;
				entry.mask = 1;
				ioapic_write_entry(apic, pin, entry);
				ioapic_write_entry(apic, pin, entry);
@@ -916,22 +927,30 @@ void mask_IO_APIC_setup(void)
	}
	}
}
}


void restore_IO_APIC_setup(void)
/*
 * Restore IO APIC entries which was saved in ioapic_entries.
 */
int restore_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries)
{
{
	int apic, pin;
	int apic, pin;


	if (!ioapic_entries)
		return -ENOMEM;

	for (apic = 0; apic < nr_ioapics; apic++) {
	for (apic = 0; apic < nr_ioapics; apic++) {
		if (!early_ioapic_entries[apic])
		if (!ioapic_entries[apic])
			break;
			return -ENOMEM;

		for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
		for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
			ioapic_write_entry(apic, pin,
			ioapic_write_entry(apic, pin,
					   early_ioapic_entries[apic][pin]);
					ioapic_entries[apic][pin]);
		kfree(early_ioapic_entries[apic]);
		early_ioapic_entries[apic] = NULL;
	}
	}
	return 0;
}
}


void reinit_intr_remapped_IO_APIC(int intr_remapping)
void reinit_intr_remapped_IO_APIC(int intr_remapping,
	struct IO_APIC_route_entry **ioapic_entries)

{
{
	/*
	/*
	 * for now plain restore of previous settings.
	 * for now plain restore of previous settings.
@@ -940,7 +959,17 @@ void reinit_intr_remapped_IO_APIC(int intr_remapping)
	 * table entries. for now, do a plain restore, and wait for
	 * table entries. for now, do a plain restore, and wait for
	 * the setup_IO_APIC_irqs() to do proper initialization.
	 * the setup_IO_APIC_irqs() to do proper initialization.
	 */
	 */
	restore_IO_APIC_setup();
	restore_IO_APIC_setup(ioapic_entries);
}

void free_ioapic_entries(struct IO_APIC_route_entry **ioapic_entries)
{
	int apic;

	for (apic = 0; apic < nr_ioapics; apic++)
		kfree(ioapic_entries[apic]);

	kfree(ioapic_entries);
}
}
#endif
#endif


@@ -2495,7 +2524,7 @@ static void irq_complete_move(struct irq_desc **descp)
static inline void irq_complete_move(struct irq_desc **descp) {}
static inline void irq_complete_move(struct irq_desc **descp) {}
#endif
#endif


#ifdef CONFIG_INTR_REMAP
#ifdef CONFIG_X86_X2APIC
static void __eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg)
static void __eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg)
{
{
	int apic, pin;
	int apic, pin;
@@ -2540,7 +2569,6 @@ static void ack_x2apic_edge(unsigned int irq)
{
{
	ack_x2APIC_irq();
	ack_x2APIC_irq();
}
}

#endif
#endif


static void ack_apic_edge(unsigned int irq)
static void ack_apic_edge(unsigned int irq)
@@ -2651,6 +2679,26 @@ static void ack_apic_level(unsigned int irq)
#endif
#endif
}
}


#ifdef CONFIG_INTR_REMAP
static void ir_ack_apic_edge(unsigned int irq)
{
#ifdef CONFIG_X86_X2APIC
       if (x2apic_enabled())
               return ack_x2apic_edge(irq);
#endif
       return ack_apic_edge(irq);
}

static void ir_ack_apic_level(unsigned int irq)
{
#ifdef CONFIG_X86_X2APIC
       if (x2apic_enabled())
               return ack_x2apic_level(irq);
#endif
       return ack_apic_level(irq);
}
#endif /* CONFIG_INTR_REMAP */

static struct irq_chip ioapic_chip __read_mostly = {
static struct irq_chip ioapic_chip __read_mostly = {
	.name		= "IO-APIC",
	.name		= "IO-APIC",
	.startup	= startup_ioapic_irq,
	.startup	= startup_ioapic_irq,
@@ -2670,8 +2718,8 @@ static struct irq_chip ir_ioapic_chip __read_mostly = {
	.mask		= mask_IO_APIC_irq,
	.mask		= mask_IO_APIC_irq,
	.unmask		= unmask_IO_APIC_irq,
	.unmask		= unmask_IO_APIC_irq,
#ifdef CONFIG_INTR_REMAP
#ifdef CONFIG_INTR_REMAP
	.ack		= ack_x2apic_edge,
	.ack		= ir_ack_apic_edge,
	.eoi		= ack_x2apic_level,
	.eoi		= ir_ack_apic_level,
#ifdef CONFIG_SMP
#ifdef CONFIG_SMP
	.set_affinity	= set_ir_ioapic_affinity_irq,
	.set_affinity	= set_ir_ioapic_affinity_irq,
#endif
#endif
@@ -3397,7 +3445,7 @@ static struct irq_chip msi_ir_chip = {
	.unmask		= unmask_msi_irq,
	.unmask		= unmask_msi_irq,
	.mask		= mask_msi_irq,
	.mask		= mask_msi_irq,
#ifdef CONFIG_INTR_REMAP
#ifdef CONFIG_INTR_REMAP
	.ack		= ack_x2apic_edge,
	.ack		= ir_ack_apic_edge,
#ifdef CONFIG_SMP
#ifdef CONFIG_SMP
	.set_affinity	= ir_set_msi_irq_affinity,
	.set_affinity	= ir_set_msi_irq_affinity,
#endif
#endif
Loading