linux-pci.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC Patch V1 0/4] enhance IOAPIC core to support hotplug
@ 2014-05-27  8:24 Jiang Liu
  2014-05-27  8:24 ` [RFC Patch V1 1/4] x86, irq: refine mp_register_ioapic() to prepare for IOAPIC hotplug Jiang Liu
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Jiang Liu @ 2014-05-27  8:24 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, Thomas Gleixner, Grant Likely,
	Ingo Molnar, H. Peter Anvin, Rafael J. Wysocki, Bjorn Helgaas,
	Randy Dunlap, Yinghai Lu
  Cc: Jiang Liu, Konrad Rzeszutek Wilk, Andrew Morton, Tony Luck,
	Joerg Roedel, Paul Gortmaker, Greg Kroah-Hartman, x86,
	linux-kernel, linux-pci, linux-acpi

This patch set enhances IOAPIC core to support IOAPIC hotplug on x86
platforms. It's based on another patch set "use irqdomain to dynamically
allocate IRQ for IOAPIC" at https://lkml.org/lkml/2014/5/27/86

You may pull from 
https://github.com/jiangliu/linux.git ioapic/hotplug

Once passed review, we will use Yinghai's patches to glue IOAPIC
driver and ACPI PCI root driver to handle hotplug events.

Jiang Liu (4):
  x86, irq: refine mp_register_ioapic() to prepare for IOAPIC hotplug
  x86, irq, ACPI: introduce a rwsem to protect IOAPIC operations from
    hotplug
  x86, irq, ACPI: implement interface to support ACPI based IOAPIC
    hot-addition
  x86, irq, ACPI: implement interface to support ACPI based IOAPIC
    hot-removal

 arch/x86/include/asm/io_apic.h |    5 +-
 arch/x86/kernel/acpi/boot.c    |   44 +++++++--
 arch/x86/kernel/apic/io_apic.c |  207 ++++++++++++++++++++++++++++++----------
 3 files changed, 196 insertions(+), 60 deletions(-)

-- 
1.7.10.4


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [RFC Patch V1 1/4] x86, irq: refine mp_register_ioapic() to prepare for IOAPIC hotplug
  2014-05-27  8:24 [RFC Patch V1 0/4] enhance IOAPIC core to support hotplug Jiang Liu
@ 2014-05-27  8:24 ` Jiang Liu
  2014-05-28 20:49   ` Thomas Gleixner
  2014-05-27  8:24 ` [RFC Patch V1 2/4] x86, irq, ACPI: introduce a rwsem to protect IOAPIC operations from hotplug Jiang Liu
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 6+ messages in thread
From: Jiang Liu @ 2014-05-27  8:24 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, Thomas Gleixner, Grant Likely,
	Ingo Molnar, H. Peter Anvin, Rafael J. Wysocki, Bjorn Helgaas,
	Randy Dunlap, Yinghai Lu, x86, Jiang Liu
  Cc: Konrad Rzeszutek Wilk, Andrew Morton, Tony Luck, Joerg Roedel,
	Paul Gortmaker, Greg Kroah-Hartman, linux-kernel, linux-pci,
	linux-acpi, Ingo Molnar

Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
 arch/x86/include/asm/io_apic.h |    4 +-
 arch/x86/kernel/apic/io_apic.c |  143 ++++++++++++++++++++++++++--------------
 2 files changed, 94 insertions(+), 53 deletions(-)

diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h
index 6b40122bec0c..64379c285435 100644
--- a/arch/x86/include/asm/io_apic.h
+++ b/arch/x86/include/asm/io_apic.h
@@ -181,8 +181,8 @@ extern int mp_find_ioapic_pin(int ioapic, u32 gsi);
 extern u32 mp_pin_to_gsi(int ioapic, int pin);
 extern int mp_map_gsi_to_irq(u32 gsi, unsigned int flags);
 extern void mp_unmap_irq(int irq);
-extern void __init mp_register_ioapic(int id, u32 address, u32 gsi_base,
-				      ioapic_create_domain_fn cb, void *arg);
+extern int mp_register_ioapic(int id, u32 address, u32 gsi_base,
+			      ioapic_create_domain_fn cb, void *arg);
 extern struct irq_domain *mp_irqdomain_create(int ioapic,
 		struct device_node *np, const struct irq_domain_ops *ops);
 extern int mp_irqdomain_map(struct irq_domain *domain, unsigned int virq,
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index c7c84d5c0e57..f70fa239f34b 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -85,6 +85,7 @@ int sis_apic_bug = -1;
 static DEFINE_RAW_SPINLOCK(ioapic_lock);
 static DEFINE_RAW_SPINLOCK(vector_lock);
 static DEFINE_MUTEX(ioapic_mutex);
+static int ioapic_initialized;
 
 struct mp_pin_info {
 	int trigger;
@@ -2920,19 +2921,40 @@ out:
  */
 #define PIC_IRQS	(1UL << PIC_CASCADE_IR)
 
-static void ioapic_create_irqdomains(void)
+static int ioapic_create_irqdomain(int idx)
 {
-	int i, size;
-	struct ioapic *ip;
+	int size;
+	struct ioapic *ip = &ioapics[idx];
 
-	for_each_ioapic(i) {
-		ip = &ioapics[i];
-		size = sizeof(struct mp_pin_info) * mp_ioapic_pin_count(i);
-		ip->pin_info = kzalloc(size, GFP_KERNEL);
-		BUG_ON(!ip->pin_info);
-		if (ip->irqdomain_cb)
-			ip->irqdomain = ip->irqdomain_cb(i, ip->irqdomain_arg);
+	size = sizeof(struct mp_pin_info) * mp_ioapic_pin_count(idx);
+	ip->pin_info = kzalloc(size, GFP_KERNEL);
+	if (ip->pin_info == NULL && ioapic_initialized) {
+		pr_warn("failed to allocate memory IOAPIC pin_info.\n");
+		return -ENOMEM;
 	}
+	BUG_ON(!ip->pin_info);
+
+	if (ip->irqdomain_cb) {
+		ip->irqdomain = ip->irqdomain_cb(idx, ip->irqdomain_arg);
+		if (ip->irqdomain == NULL && ioapic_initialized) {
+			pr_warn("failed to create irqdomain for IOAPIC%d\n",
+				idx);
+			kfree(ip->pin_info);
+			ip->pin_info = NULL;
+			return -ENOMEM;
+		}
+		BUG_ON(!ip->irqdomain);
+	}
+
+	return 0;
+}
+
+static void ioapic_create_irqdomains(void)
+{
+	int idx;
+
+	for_each_ioapic(idx)
+		ioapic_create_irqdomain(idx);
 }
 
 void __init setup_IO_APIC(void)
@@ -2955,6 +2977,8 @@ void __init setup_IO_APIC(void)
 	init_IO_APIC_traps();
 	if (legacy_pic->nr_legacy_irqs)
 		check_timer();
+
+	ioapic_initialized = 1;
 }
 
 /*
@@ -3408,7 +3432,7 @@ io_apic_setup_irq_pin(unsigned int irq, int node, struct io_apic_irq_attr *attr)
 	return ret;
 }
 
-static int __init io_apic_get_redir_entries(int ioapic)
+static int io_apic_get_redir_entries(int ioapic)
 {
 	union IO_APIC_reg_01	reg_01;
 	unsigned long flags;
@@ -3455,7 +3479,7 @@ int __init arch_probe_nr_irqs(void)
 }
 
 #ifdef CONFIG_X86_32
-static int __init io_apic_get_unique_id(int ioapic, int apic_id)
+static int io_apic_get_unique_id(int ioapic, int apic_id)
 {
 	union IO_APIC_reg_00 reg_00;
 	static physid_mask_t apic_id_map = PHYSID_MASK_NONE;
@@ -3530,7 +3554,7 @@ static int __init io_apic_get_unique_id(int ioapic, int apic_id)
 	return apic_id;
 }
 
-static u8 __init io_apic_unique_id(u8 id)
+static u8 io_apic_unique_id(u8 id)
 {
 	if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) &&
 	    !APIC_XAPIC(apic_version[boot_cpu_physical_apicid]))
@@ -3539,7 +3563,7 @@ static u8 __init io_apic_unique_id(u8 id)
 		return id;
 }
 #else
-static u8 __init io_apic_unique_id(u8 id)
+static u8 io_apic_unique_id(u8 id)
 {
 	int i;
 	DECLARE_BITMAP(used, 256);
@@ -3553,7 +3577,7 @@ static u8 __init io_apic_unique_id(u8 id)
 }
 #endif
 
-static int __init io_apic_get_version(int ioapic)
+static int io_apic_get_version(int ioapic)
 {
 	union IO_APIC_reg_01	reg_01;
 	unsigned long flags;
@@ -3757,21 +3781,7 @@ int mp_find_ioapic_pin(int ioapic, u32 gsi)
 	return gsi - gsi_cfg->gsi_base;
 }
 
-static __init int bad_ioapic(unsigned long address)
-{
-	if (nr_ioapics >= MAX_IO_APICS) {
-		pr_warn("WARNING: Max # of I/O APICs (%d) exceeded (found %d), skipping\n",
-			MAX_IO_APICS, nr_ioapics);
-		return 1;
-	}
-	if (!address) {
-		pr_warn("WARNING: Bogus (zero) I/O APIC address found in table, skipping!\n");
-		return 1;
-	}
-	return 0;
-}
-
-static __init int bad_ioapic_register(int idx)
+static int bad_ioapic_register(int idx)
 {
 	union IO_APIC_reg_00 reg_00;
 	union IO_APIC_reg_01 reg_01;
@@ -3790,30 +3800,43 @@ static __init int bad_ioapic_register(int idx)
 	return 0;
 }
 
-void __init mp_register_ioapic(int id, u32 address, u32 gsi_base,
-			       ioapic_create_domain_fn cb, void *arg)
+static int find_free_ioapic_entry(void)
+{
+	return nr_ioapics;
+}
+
+int mp_register_ioapic(int id, u32 address, u32 gsi_base,
+		       ioapic_create_domain_fn cb, void *arg)
 {
-	int idx = 0;
-	int entries;
+	u32 gsi_end;
+	int idx, ioapic, entries;
 	struct mp_ioapic_gsi *gsi_cfg;
 
-	if (bad_ioapic(address))
-		return;
+	if (!address) {
+		pr_warn("WARNING: Bogus (zero) I/O APIC address found in table, skipping!\n");
+		return -EINVAL;
+	}
+	for_each_ioapic(ioapic)
+		if (ioapics[ioapic].mp_config.apicaddr == address) {
+			pr_warn("address 0x%x conflicts with IOAPIC%d\n",
+				address, ioapic);
+			return -EEXIST;
+		}
 
-	idx = nr_ioapics;
+	idx = find_free_ioapic_entry();
+	if (idx >= MAX_IO_APICS) {
+		pr_warn("WARNING: Max # of I/O APICs (%d) exceeded (found %d), skipping\n",
+			MAX_IO_APICS, idx);
+		return -ENOSPC;
+	}
 
 	ioapics[idx].mp_config.type = MP_IOAPIC;
 	ioapics[idx].mp_config.flags = MPC_APIC_USABLE;
 	ioapics[idx].mp_config.apicaddr = address;
-	ioapics[idx].irqdomain_cb = cb;
-	ioapics[idx].irqdomain_arg = arg;
-	ioapics[idx].irqdomain = NULL;
-
 	set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address);
-
 	if (bad_ioapic_register(idx)) {
 		clear_fixmap(FIX_IO_APIC_BASE_0 + idx);
-		return;
+		return -ENODEV;
 	}
 
 	ioapics[idx].mp_config.apicid = io_apic_unique_id(id);
@@ -3824,24 +3847,43 @@ void __init mp_register_ioapic(int id, u32 address, u32 gsi_base,
 	 * and to prevent reprogramming of IOAPIC pins (PCI GSIs).
 	 */
 	entries = io_apic_get_redir_entries(idx);
+	gsi_end = gsi_base + entries - 1;
+	for_each_ioapic(ioapic) {
+		gsi_cfg = mp_ioapic_gsi_routing(idx);
+		if ((gsi_base >= gsi_cfg->gsi_base &&
+		     gsi_base <= gsi_cfg->gsi_end) ||
+		    (gsi_end >= gsi_cfg->gsi_base &&
+		     gsi_end <= gsi_cfg->gsi_end)) {
+			pr_warn("GSI range [%u-%u] for new IOAPIC conflicts with GSI[%u-%u]\n",
+				gsi_base, gsi_end,
+				gsi_cfg->gsi_base, gsi_cfg->gsi_end);
+			clear_fixmap(FIX_IO_APIC_BASE_0 + idx);
+			return -EEXIST;
+		}
+	}
 	gsi_cfg = mp_ioapic_gsi_routing(idx);
 	gsi_cfg->gsi_base = gsi_base;
-	gsi_cfg->gsi_end = gsi_base + entries - 1;
+	gsi_cfg->gsi_end = gsi_end;
 
-	/*
-	 * The number of IO-APIC IRQ registers (== #pins):
-	 */
-	ioapics[idx].nr_registers = entries;
+	ioapics[idx].irqdomain_cb = cb;
+	ioapics[idx].irqdomain_arg = arg;
+	ioapics[idx].irqdomain = NULL;
 
 	if (gsi_cfg->gsi_end >= gsi_top)
 		gsi_top = gsi_cfg->gsi_end + 1;
 
+	if (nr_ioapics <= idx)
+		nr_ioapics = idx + 1;
+
+	/* Set nr_registers to mark entry present */
+	ioapics[idx].nr_registers = entries;
+
 	pr_info("IOAPIC[%d]: apic_id %d, version %d, address 0x%x, GSI %d-%d\n",
 		idx, mpc_ioapic_id(idx),
 		mpc_ioapic_ver(idx), mpc_ioapic_addr(idx),
 		gsi_cfg->gsi_base, gsi_cfg->gsi_end);
 
-	nr_ioapics++;
+	return 0;
 }
 
 struct irq_domain *mp_irqdomain_create(int ioapic, struct device_node *np,
@@ -3852,8 +3894,7 @@ struct irq_domain *mp_irqdomain_create(int ioapic, struct device_node *np,
 	int hwirqs = mp_ioapic_pin_count(ioapic);
 
 	domain = irq_domain_add_linear(np, hwirqs, ops, (void *)(long)ioapic);
-	BUG_ON(!domain);
-	if (gsi_cfg->gsi_base == 0)
+	if (domain && gsi_cfg->gsi_base == 0)
 		irq_set_default_host(domain);
 
 	return domain;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [RFC Patch V1 2/4] x86, irq, ACPI: introduce a rwsem to protect IOAPIC operations from hotplug
  2014-05-27  8:24 [RFC Patch V1 0/4] enhance IOAPIC core to support hotplug Jiang Liu
  2014-05-27  8:24 ` [RFC Patch V1 1/4] x86, irq: refine mp_register_ioapic() to prepare for IOAPIC hotplug Jiang Liu
@ 2014-05-27  8:24 ` Jiang Liu
  2014-05-27  8:24 ` [RFC Patch V1 3/4] x86, irq, ACPI: implement interface to support ACPI based IOAPIC hot-addition Jiang Liu
  2014-05-27  8:24 ` [RFC Patch V1 4/4] x86, irq, ACPI: implement interface to support ACPI based IOAPIC hot-removal Jiang Liu
  3 siblings, 0 replies; 6+ messages in thread
From: Jiang Liu @ 2014-05-27  8:24 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, Thomas Gleixner, Grant Likely,
	Ingo Molnar, H. Peter Anvin, Rafael J. Wysocki, Bjorn Helgaas,
	Randy Dunlap, Yinghai Lu, Len Brown, Pavel Machek, x86
  Cc: Jiang Liu, Konrad Rzeszutek Wilk, Andrew Morton, Tony Luck,
	Joerg Roedel, Paul Gortmaker, Greg Kroah-Hartman, linux-kernel,
	linux-pci, linux-acpi, linux-pm

We are going to support ACPI based IOAPIC hotplug, so introduce a rwsem
to protect IOAPIC data structures from IOAPIC hotplug. We choose to
serialize in ACPI instead of in the IOAPIC core because:
1) currently we are only plan to support ACPI based IOAPIC hotplug
2) it's much more clean and easy
3) It does't affect IOAPIC discovered by devicetree, SFI and mppparse.

Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
 arch/x86/kernel/acpi/boot.c |   13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index c8e8fe67bbc8..a1b388e88bcb 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -75,6 +75,8 @@ int acpi_fix_pin2_polarity __initdata;
 static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;
 #endif
 
+static DECLARE_RWSEM(acpi_ioapic_rwsem);
+
 #ifndef __HAVE_ARCH_CMPXCHG
 #warning ACPI uses CMPXCHG, i486 and later hardware
 #endif
@@ -495,8 +497,11 @@ void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger)
 
 int acpi_gsi_to_irq(u32 gsi, unsigned int *irqp)
 {
-	int irq = mp_map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC | IOAPIC_MAP_CHECK);
+	int irq;
 
+	down_read(&acpi_ioapic_rwsem);
+	irq = mp_map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC | IOAPIC_MAP_CHECK);
+	up_read(&acpi_ioapic_rwsem);
 	if (irq >= 0) {
 		*irqp = irq;
 		return 0;
@@ -537,7 +542,9 @@ static int acpi_register_gsi_ioapic(struct device *dev, u32 gsi,
 	int irq = gsi;
 
 #ifdef CONFIG_X86_IO_APIC
+	down_read(&acpi_ioapic_rwsem);
 	irq = mp_register_gsi(dev, gsi, trigger, polarity);
+	up_read(&acpi_ioapic_rwsem);
 #endif
 
 	return irq;
@@ -546,7 +553,9 @@ static int acpi_register_gsi_ioapic(struct device *dev, u32 gsi,
 static void acpi_unregister_gsi_ioapic(u32 gsi)
 {
 #ifdef CONFIG_X86_IO_APIC
+	down_read(&acpi_ioapic_rwsem);
 	mp_unregister_gsi(gsi);
+	up_read(&acpi_ioapic_rwsem);
 #endif
 }
 
@@ -1198,7 +1207,9 @@ static void __init acpi_process_madt(void)
 			/*
 			 * Parse MADT IO-APIC entries
 			 */
+			down_write(&acpi_ioapic_rwsem);
 			error = acpi_parse_madt_ioapic_entries();
+			up_write(&acpi_ioapic_rwsem);
 			if (!error) {
 				acpi_set_irq_model_ioapic();
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [RFC Patch V1 3/4] x86, irq, ACPI: implement interface to support ACPI based IOAPIC hot-addition
  2014-05-27  8:24 [RFC Patch V1 0/4] enhance IOAPIC core to support hotplug Jiang Liu
  2014-05-27  8:24 ` [RFC Patch V1 1/4] x86, irq: refine mp_register_ioapic() to prepare for IOAPIC hotplug Jiang Liu
  2014-05-27  8:24 ` [RFC Patch V1 2/4] x86, irq, ACPI: introduce a rwsem to protect IOAPIC operations from hotplug Jiang Liu
@ 2014-05-27  8:24 ` Jiang Liu
  2014-05-27  8:24 ` [RFC Patch V1 4/4] x86, irq, ACPI: implement interface to support ACPI based IOAPIC hot-removal Jiang Liu
  3 siblings, 0 replies; 6+ messages in thread
From: Jiang Liu @ 2014-05-27  8:24 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, Thomas Gleixner, Grant Likely,
	Ingo Molnar, H. Peter Anvin, Rafael J. Wysocki, Bjorn Helgaas,
	Randy Dunlap, Yinghai Lu, Len Brown, Pavel Machek, x86, Jiang Liu
  Cc: Konrad Rzeszutek Wilk, Andrew Morton, Tony Luck, Joerg Roedel,
	Paul Gortmaker, Greg Kroah-Hartman, linux-kernel, linux-pci,
	linux-acpi, Ingo Molnar, linux-pm

Implement acpi_register_ioapic() and enhance mp_register_ioapic()
to support ACPI based IOAPIC hot-addition.

Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
 arch/x86/kernel/acpi/boot.c    |   18 ++++++++++++++++--
 arch/x86/kernel/apic/io_apic.c |   24 +++++++++++++++++++++---
 2 files changed, 37 insertions(+), 5 deletions(-)

diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index a1b388e88bcb..d807e16f8fec 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -655,8 +655,22 @@ EXPORT_SYMBOL(acpi_unmap_lsapic);
 
 int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base)
 {
-	/* TBD */
-	return -EINVAL;
+	int ret = -ENOSYS;
+#ifdef CONFIG_X86_IO_APIC
+	unsigned long long uid;
+	acpi_status status;
+
+	status = acpi_evaluate_integer(handle, METHOD_NAME__UID, NULL, &uid);
+	if (ACPI_FAILURE(status))
+		uid = 0;
+
+	down_write(&acpi_ioapic_rwsem);
+	ret  = mp_register_ioapic((int)uid, phys_addr, gsi_base,
+				  acpi_create_irqdomain, NULL);
+	up_write(&acpi_ioapic_rwsem);
+#endif
+
+	return ret;
 }
 
 EXPORT_SYMBOL(acpi_register_ioapic);
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index f70fa239f34b..4bddff760ff4 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -3802,7 +3802,13 @@ static int bad_ioapic_register(int idx)
 
 static int find_free_ioapic_entry(void)
 {
-	return nr_ioapics;
+	int idx;
+
+	for (idx = 0; idx < MAX_IO_APICS; idx++)
+		if (ioapics[idx].nr_registers == 0)
+			return idx;
+
+	return MAX_IO_APICS;
 }
 
 int mp_register_ioapic(int id, u32 address, u32 gsi_base,
@@ -3818,8 +3824,15 @@ int mp_register_ioapic(int id, u32 address, u32 gsi_base,
 	}
 	for_each_ioapic(ioapic)
 		if (ioapics[ioapic].mp_config.apicaddr == address) {
-			pr_warn("address 0x%x conflicts with IOAPIC%d\n",
-				address, ioapic);
+			/*
+			 * IOAPIC unit may also be visible in PCI scope.
+			 * When ioapic PCI driver's probe() is called,
+			 * the IOAPIC unit may have already been initialized
+			 * at boot time.
+			 */
+			if (!ioapic_initialized)
+				pr_warn("address 0x%x conflicts with IOAPIC%d\n",
+					address, ioapic);
 			return -EEXIST;
 		}
 
@@ -3875,6 +3888,11 @@ int mp_register_ioapic(int id, u32 address, u32 gsi_base,
 	if (nr_ioapics <= idx)
 		nr_ioapics = idx + 1;
 
+	if (ioapic_initialized && ioapic_create_irqdomain(idx)) {
+		clear_fixmap(FIX_IO_APIC_BASE_0 + idx);
+		return -ENOMEM;
+	}
+
 	/* Set nr_registers to mark entry present */
 	ioapics[idx].nr_registers = entries;
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [RFC Patch V1 4/4] x86, irq, ACPI: implement interface to support ACPI based IOAPIC hot-removal
  2014-05-27  8:24 [RFC Patch V1 0/4] enhance IOAPIC core to support hotplug Jiang Liu
                   ` (2 preceding siblings ...)
  2014-05-27  8:24 ` [RFC Patch V1 3/4] x86, irq, ACPI: implement interface to support ACPI based IOAPIC hot-addition Jiang Liu
@ 2014-05-27  8:24 ` Jiang Liu
  3 siblings, 0 replies; 6+ messages in thread
From: Jiang Liu @ 2014-05-27  8:24 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, Thomas Gleixner, Grant Likely,
	Ingo Molnar, H. Peter Anvin, Rafael J. Wysocki, Bjorn Helgaas,
	Randy Dunlap, Yinghai Lu, x86, Len Brown, Pavel Machek, Jiang Liu
  Cc: Konrad Rzeszutek Wilk, Andrew Morton, Tony Luck, Joerg Roedel,
	Paul Gortmaker, Greg Kroah-Hartman, linux-kernel, linux-pci,
	linux-acpi, Ingo Molnar, linux-pm

Implement acpi_unregister_ioapic() to support ACPI based IOAPIC hot-removal.
An IOAPIC could only be removed when all its pins are unused.

Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
 arch/x86/include/asm/io_apic.h |    1 +
 arch/x86/kernel/acpi/boot.c    |   13 ++++++++----
 arch/x86/kernel/apic/io_apic.c |   46 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 56 insertions(+), 4 deletions(-)

diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h
index 64379c285435..256ec8d9050c 100644
--- a/arch/x86/include/asm/io_apic.h
+++ b/arch/x86/include/asm/io_apic.h
@@ -183,6 +183,7 @@ extern int mp_map_gsi_to_irq(u32 gsi, unsigned int flags);
 extern void mp_unmap_irq(int irq);
 extern int mp_register_ioapic(int id, u32 address, u32 gsi_base,
 			      ioapic_create_domain_fn cb, void *arg);
+extern int mp_unregister_ioapic(u32 gsi_base);
 extern struct irq_domain *mp_irqdomain_create(int ioapic,
 		struct device_node *np, const struct irq_domain_ops *ops);
 extern int mp_irqdomain_map(struct irq_domain *domain, unsigned int virq,
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index d807e16f8fec..c17cc0510040 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -672,15 +672,20 @@ int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base)
 
 	return ret;
 }
-
 EXPORT_SYMBOL(acpi_register_ioapic);
 
 int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base)
 {
-	/* TBD */
-	return -EINVAL;
-}
+	int ret = -ENOSYS;
+
+#ifdef CONFIG_X86_IO_APIC
+	down_write(&acpi_ioapic_rwsem);
+	ret  = mp_unregister_ioapic(gsi_base);
+	up_write(&acpi_ioapic_rwsem);
+#endif
 
+	return ret;
+}
 EXPORT_SYMBOL(acpi_unregister_ioapic);
 
 static int __init acpi_parse_sbf(struct acpi_table_header *table)
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 4bddff760ff4..4343247d15b1 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -2949,6 +2949,18 @@ static int ioapic_create_irqdomain(int idx)
 	return 0;
 }
 
+static void ioapic_destroy_irqdomain(int idx)
+{
+	if (ioapics[idx].irqdomain) {
+		irq_domain_remove(ioapics[idx].irqdomain);
+		ioapics[idx].irqdomain = NULL;
+	}
+	if (ioapics[idx].pin_info) {
+		kfree(ioapics[idx].pin_info);
+		ioapics[idx].pin_info = NULL;
+	}
+}
+
 static void ioapic_create_irqdomains(void)
 {
 	int idx;
@@ -3904,6 +3916,40 @@ int mp_register_ioapic(int id, u32 address, u32 gsi_base,
 	return 0;
 }
 
+int mp_unregister_ioapic(u32 gsi_base)
+{
+	int ioapic, pin;
+	int found = 0;
+	struct mp_pin_info *pin_info;
+
+	for_each_ioapic(ioapic)
+		if (ioapics[ioapic].gsi_config.gsi_base == gsi_base) {
+			found = 1;
+			break;
+		}
+	if (!found) {
+		pr_warn("can't find IOAPIC for GSI %d\n", gsi_base);
+		return -ENODEV;
+	}
+
+	for_each_pin(ioapic, pin) {
+		pin_info = mp_pin_info(ioapic, pin);
+		if (pin_info->count) {
+			pr_warn("pin%d on IOAPIC%d is still in use.\n",
+				pin, ioapic);
+			return -EBUSY;
+		}
+	}
+
+	/* Mark entry not present */
+	ioapics[ioapic].nr_registers  = 0;
+	ioapic_destroy_irqdomain(ioapic);
+	clear_fixmap(FIX_IO_APIC_BASE_0 + ioapic);
+	memset(&ioapics[ioapic], 0, sizeof(ioapics[ioapic]));
+
+	return 0;
+}
+
 struct irq_domain *mp_irqdomain_create(int ioapic, struct device_node *np,
 				       const struct irq_domain_ops *ops)
 {
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [RFC Patch V1 1/4] x86, irq: refine mp_register_ioapic() to prepare for IOAPIC hotplug
  2014-05-27  8:24 ` [RFC Patch V1 1/4] x86, irq: refine mp_register_ioapic() to prepare for IOAPIC hotplug Jiang Liu
@ 2014-05-28 20:49   ` Thomas Gleixner
  0 siblings, 0 replies; 6+ messages in thread
From: Thomas Gleixner @ 2014-05-28 20:49 UTC (permalink / raw)
  To: Jiang Liu
  Cc: Benjamin Herrenschmidt, Grant Likely, Ingo Molnar, H. Peter Anvin,
	Rafael J. Wysocki, Bjorn Helgaas, Randy Dunlap, Yinghai Lu, x86,
	Konrad Rzeszutek Wilk, Andrew Morton, Tony Luck, Joerg Roedel,
	Paul Gortmaker, Greg Kroah-Hartman, linux-kernel, linux-pci,
	linux-acpi, Ingo Molnar

On Tue, 27 May 2014, Jiang Liu wrote:

> -static void ioapic_create_irqdomains(void)
> +static int ioapic_create_irqdomain(int idx)

...

> -static int __init io_apic_get_redir_entries(int ioapic)
> +static int io_apic_get_redir_entries(int ioapic)

Can you please split the functional changes from the trivial __init
removal ones?

Thanks,

	tglx

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2014-05-28 20:50 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-05-27  8:24 [RFC Patch V1 0/4] enhance IOAPIC core to support hotplug Jiang Liu
2014-05-27  8:24 ` [RFC Patch V1 1/4] x86, irq: refine mp_register_ioapic() to prepare for IOAPIC hotplug Jiang Liu
2014-05-28 20:49   ` Thomas Gleixner
2014-05-27  8:24 ` [RFC Patch V1 2/4] x86, irq, ACPI: introduce a rwsem to protect IOAPIC operations from hotplug Jiang Liu
2014-05-27  8:24 ` [RFC Patch V1 3/4] x86, irq, ACPI: implement interface to support ACPI based IOAPIC hot-addition Jiang Liu
2014-05-27  8:24 ` [RFC Patch V1 4/4] x86, irq, ACPI: implement interface to support ACPI based IOAPIC hot-removal Jiang Liu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).