Skip to contentSkip to conversation

x86, irq: Support ioapic controller hotplug

PATCH Superseded Yinghai Lu 5 participants 53 messages Aug 11, 2013 – Oct 21, 2013

Subsystems (8)
Stable branch x86 ACPI PCI +4 more subsystems

v4 of 5 Superseded Latest is v5 →

lore
Share & tools
lore

Yinghai Lu

author
#0 lore raw

v4 cover x86, irq: Support ioapic controller hotplug

Hi,

Intel cpu (from IVB) include cpu cores, mem controller, and IIO. When hotplug cpu physically, it will involve cpu hotplug, mem hotplug, and pci root hotplug.

IIO includes pci host bridge, ioapic controller and iommu etc. pci devices will need to use ioapic and iommu.
So to make pci root bus hotplug working, we need ioapic hotplug support.

Now ioapics are with ACPI MADT table. During booting, kernel will parse MADT and put info into ioapic arrays.
Also Bjorn added one pci device based driver, but it is not wired in yet, as it need to call acpi_register_ioapic, and that is TBD.

This patchset will
1. extend genirq to support reserve/alloc_reserved method. because we want irqs for one ioapic controller to be linear mapping to the gsi range.
2. change ioapic array operation code so we could insert new ioapic and remove one leave the blank slot.
3. record irq_base in gsi_config in ioapic struct, and use it to convert gsi to irq for pci device using that ioapic controller
4. make static ioapic path (from MADT) use same code as hot-add path, with reserve/alloc_reserved method.
5. change ioapic add/remove to use acpi way, as that is only needed when pci root bus hotplug.
6. also support the case that ioapic controller is hiding in pci config space or ioapic address is not managed by pci reallocation subsys.

Also include some cleanups
1. print MSI-X clearly in /proc/interrupts and dmesg.
2. convert ioapic irq_2_pin to be generic list.

It is based on linus's tree of 2013/08/10 aka v3.11-rc4.

could get them from:
git://git.kernel.org/pub/scm/linux/kernel/git/yinghai/linux-yinghai.git for-x86-irq

-v3: split last patch to 4 patches per request from Bjorn.
drop one patch that will put pci device name in proc/interrupts update changelog.
-v4: address review from tglx, change to realloc to alloc_reserved.
separate x86 code and core code into different patches.

Yinghai Lu (28):
genirq: Split __irq_reserve_irqs from irq_alloc_descs
genirq: Add irq_alloc_reserved_desc()
genirq: Do not free unallocated irq descriptors
x86, irq: Change irq_remap_modify_chip_defaults() to static x86, irq: Modify irq chip once for irq remapping
x86, irq: Show MSI-X clearly in debug message
x86, irq: Show MSI-X in /proc/interrupt
x86, irq: Make dmar_msi/hpet_msi irq_chip name consistent ia64, irq: Add dummy create_irq_nr()
iommu, irq: Allocate irq_desc for dmar_msi with local node x86, irq: Kill create_irq()
x86, irq: Convert irq_2_pin list to generic list
x86, irq: Add alloc_reserved_irq_and_cfg_at()
x86, irq: Move down arch_early_irq_init()
x86, irq: Split out alloc_ioapic_save_registers()
xen, irq: Call irq_alloc_reserved_desc_at() at first
x86, irq: Reserve irq range and alloc_reserved for booting path x86, irq: Add ioapic_gsi_to_irq
x86, irq: Add for_each_ioapic helper
x86, irq: More strict checking about registering ioapic x86, irq: Make mp_register_ioapic handle hot-added ioapic x86, irq: Add mp_unregister_ioapic to handle hot-remove ioapic x86, ioapic: Find usable ioapic id for 64bit.
x86: Move declaration for mp_register_ioapic()
PCI, x86: Make ioapic hotplug support built-in
PCI, x86, ACPI: Link acpi ioapic register to ioapic
PCI, x86, ACPI: Enable ioapic hotplug support with acpi host bridge. PCI, x86, ACPI: get ioapic address from acpi device

 arch/ia64/kernel/irq_ia64.c          |  10 +
 arch/x86/include/asm/hw_irq.h        |   2 +-
 arch/x86/include/asm/io_apic.h       |  13 +
 arch/x86/include/asm/irq_remapping.h |  14 +-
 arch/x86/include/asm/mpspec.h        |  21 +-
 arch/x86/kernel/acpi/boot.c          |  32 +--
 arch/x86/kernel/apic/apic.c          |   9 +-
 arch/x86/kernel/apic/io_apic.c       | 480 +++++++++++++++++++++++++----------
 arch/x86/kernel/devicetree.c         |   2 +-
 drivers/acpi/pci_root.c              |   4 +
 drivers/iommu/amd_iommu_init.c       |   2 +-
 drivers/iommu/dmar.c                 |   2 +-
 drivers/iommu/intel_irq_remapping.c  |   2 +-
 drivers/iommu/irq_remapping.c        |  18 +-
 drivers/pci/Kconfig                  |   3 +-
 drivers/pci/ioapic.c                 | 229 ++++++++++++-----
 drivers/xen/events.c                 |   8 +-
 include/linux/irq.h                  |   4 +
 include/linux/pci-acpi.h             |   8 +
 kernel/irq/irqdesc.c                 |  80 ++++--
 20 files changed, 679 insertions(+), 264 deletions(-)
Signature · 1 line
1.8.1.4
author
#1 lore raw

PATCH v4 1/28 genirq: Split __irq_reserve_irqs from irq_alloc_descs

irq_alloc_descs and irq_reserve_irqs are almost the same. Separate code out to __irq_reserved_irqs, and other two reuse __irq_reserve_irqs.

We will use __irq_reserve_irqs for coming ioapic hotplug support.

-v2: fix func docbook related comments, pointed out by tglx.

---
 include/linux/irq.h  |  1 +
 kernel/irq/irqdesc.c | 54 ++++++++++++++++++++++++++++++----------------------
 2 files changed, 32 insertions(+), 23 deletions(-)
include/linux/irq.h +1 -0
index f04d3ba..8c46cb2 100644
@@ -611,6 +611,7 @@ int __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
 
 void irq_free_descs(unsigned int irq, unsigned int cnt);
 int irq_reserve_irqs(unsigned int from, unsigned int cnt);
+int __irq_reserve_irqs(int irq, unsigned int from, unsigned int cnt);
 
 static inline void irq_free_desc(unsigned int irq)
 {
kernel/irq/irqdesc.c +31 -23

88 lines not on this page · raw message

Signature · 1 line
1.8.1.4
author
#2 lore raw

PATCH v4 2/28 genirq: Add irq_alloc_reserved_desc()

In reply to Yinghai Lu

For ioapic hot-add support, it would be easy if we have continuous irq numbers for hot added ioapic controller.

We can reserve irq range at first, and later allocate desc for those pre-reserved irqs when they are needed.

The reasons for not allocating them during reserving:
1. only several pins of one ioapic are used, allocate for all pins, will waste memory for not used pins.
2. allocate later when is needed could make sure irq_desc is allocated on local node ram, as dev->node is set at that point.

-v2: update changelog by adding reasons, requested by Konrad. -v3: according to tglx:
separate core code change with arch code change. change function name to irq_alloc_reserved_desc. kill __irq_is_reserved().
remove not need exports.
according to Sebastian:
spare one comments by put two functions together.

Cc Joerg Roedel <[email protected]>
Cc Konrad Rzeszutek Wilk <[email protected]>
Cc Sebastian Andrzej Siewior <[email protected]>
---
 include/linux/irq.h  |  3 +++
 kernel/irq/irqdesc.c | 23 +++++++++++++++++++++++
 2 files changed, 26 insertions(+)
include/linux/irq.h +3 -0
index 8c46cb2..b998ea7 100644
@@ -592,10 +592,13 @@ static inline u32 irq_get_trigger_type(unsigned int irq)
 
 int __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
 		struct module *owner);
+int __irq_alloc_reserved_desc(int at, int node, struct module *owner);
 
 /* use macros to avoid needing export.h for THIS_MODULE */
 #define irq_alloc_descs(irq, from, cnt, node)	\
 	__irq_alloc_descs(irq, from, cnt, node, THIS_MODULE)
+#define irq_alloc_reserved_desc_at(at, node)	\
+	__irq_alloc_reserved_desc(at, node, THIS_MODULE)
 
 #define irq_alloc_desc(node)			\
 	irq_alloc_descs(-1, 0, 1, node)
kernel/irq/irqdesc.c +23 -0
index a151db6..1166545 100644
@@ -410,6 +410,29 @@ __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
 EXPORT_SYMBOL_GPL(__irq_alloc_descs);
 
 /**
+ * __irq_alloc_reserved_desc - allocate irq descriptor for irq that is already reserved
+ * @irq:	Allocate for specific irq number if irq >= 0
+ * @node:	Preferred node on which the irq descriptor should be allocated
+ * @owner:	Owning module (can be NULL)
+ *
+ * Returns the irq number or error code
+ */
+int __ref __irq_alloc_reserved_desc(int irq, int node, struct module *owner)
+{
+	mutex_lock(&sparse_irq_lock);
+	if (!test_bit(irq, allocated_irqs)) {
+		mutex_unlock(&sparse_irq_lock);
+		return -EINVAL;
+	}
+	mutex_unlock(&sparse_irq_lock);
+
+	if (irq_to_desc(irq))
+		return irq;
+
+	return alloc_descs(irq, 1, node, owner);
+}
+
+/**
  * irq_reserve_irqs - mark irqs allocated
  * @from:	mark from irq number
  * @cnt:	number of irqs to mark
Signature · 1 line
1.8.1.4
author
#3 lore raw

PATCH v4 3/28 genirq: Do not free unallocated irq descriptors

In reply to Yinghai Lu

Hot-added interrupt controllers can reserve a range of interrupt numbers, but only allocate some of them. To simplify the release on hot-remove allow them to iterate over the reserved range, let the free_desc() code return early when the descriptor does not exist

-v2: changelog from tglx

---
 kernel/irq/irqdesc.c | 3 +++
 1 file changed, 3 insertions(+)
kernel/irq/irqdesc.c +3 -0
index 1166545..bbf0601 100644
@@ -165,6 +165,9 @@ static void free_desc(unsigned int irq)
 {
 	struct irq_desc *desc = irq_to_desc(irq);
 
+	if (!desc)
+		return;
+
 	unregister_irq_proc(irq, desc);
 
 	mutex_lock(&sparse_irq_lock);
Signature · 1 line
1.8.1.4
author
#4 lore raw

PATCH v4 4/28 x86, irq: Change irq_remap_modify_chip_defaults() to static

In reply to Yinghai Lu

Change irq_remap_modify_chip_defaults() to static, as we have no outside user.

Cc Joerg Roedel <[email protected]>
Cc Konrad Rzeszutek Wilk <[email protected]>
Cc Sebastian Andrzej Siewior <[email protected]>
---
 arch/x86/include/asm/irq_remapping.h | 6 ------
 drivers/iommu/irq_remapping.c        | 2 +-
 2 files changed, 1 insertion(+), 7 deletions(-)
arch/x86/include/asm/irq_remapping.h +0 -6
index d806b22..606f42e 100644
@@ -56,8 +56,6 @@ 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 */
 
 static inline void setup_irq_remapping_ops(void) { }
@@ -91,10 +89,6 @@ 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)
drivers/iommu/irq_remapping.c +1 -1
index 39f81ae..85ae2cf 100644
@@ -375,7 +375,7 @@ static void ir_print_prefix(struct irq_data *data, struct seq_file *p)
 	seq_printf(p, " IR-%s", data->chip->name);
 }
 
-void irq_remap_modify_chip_defaults(struct irq_chip *chip)
+static void irq_remap_modify_chip_defaults(struct irq_chip *chip)
 {
 	chip->irq_print_chip = ir_print_prefix;
 	chip->irq_ack = ir_ack_apic_edge;
Signature · 1 line
1.8.1.4
author
#5 lore raw

PATCH v4 5/28 x86, irq: Modify irq chip once for irq remapping

In reply to Yinghai Lu

Current code: after irq remapping is enabled, irq_chip fields are modified during every irq setup.
mp_register_gsi
io_apic_set_pci_routing
io_apic_setup_irq_pin
setup_ioapic_irq
ioapic_register_intr
setup_remapped_irq
native_setup_msi_irqs
setup_msi_irq
setup_remapped_irq
default_setup_hpet_msi
setup_remapped_irq
that is not efficient.

We only need to modify those irq chip one time after we enable irq remapping.

Change irq_remap_modify_chip_defaults() to __init as it only gets called during booting stage, via irq_remap_modify_chips().

Affected irq_chip: ioapic_chip, msi_chip, hpet_msi_type. We don't need to use #ifdef in irq_remap_modify_chips():
IRQ_REMAP only support x86_64 && X86_IO_APIC && PCI_MSI. HPET_TIMER is selected when x86_64 is set.
When we have IRQ_REMAP enabled, al three chips are defined and used.

-v3: Remove irq_chip in setup_remapped_irq according to Sebastian.
also add missing "\n" in printk.

Cc Konrad Rzeszutek Wilk <[email protected]>
Cc Sebastian Andrzej Siewior <[email protected]>
Cc Joerg Roedel <[email protected]>
---
 arch/x86/include/asm/io_apic.h       |  5 +++++
 arch/x86/include/asm/irq_remapping.h |  8 ++------
 arch/x86/kernel/apic/apic.c          |  9 ++++++++-
 arch/x86/kernel/apic/io_apic.c       | 14 ++++++--------
 drivers/iommu/irq_remapping.c        | 13 ++++++++++---
 5 files changed, 31 insertions(+), 18 deletions(-)
arch/x86/include/asm/io_apic.h +5 -0
index 459e50a..eaff3ad 100644
@@ -215,6 +215,11 @@ static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned
 
 extern void io_apic_eoi(unsigned int apic, unsigned int vector);
 
+extern struct irq_chip ioapic_chip;
+extern struct irq_chip msi_chip;
+extern struct irq_chip hpet_msi_type;
+void irq_remap_modify_chips(void);
+
 #else  /* !CONFIG_X86_IO_APIC */
 
 #define io_apic_assign_pci_irqs 0
arch/x86/include/asm/irq_remapping.h +2 -6
index 606f42e..304c93f 100644
@@ -52,9 +52,7 @@ extern void compose_remapped_msi_msg(struct pci_dev *pdev,
 				     struct msi_msg *msg, u8 hpet_id);
 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);
+extern bool setup_remapped_irq(int irq, struct irq_cfg *cfg);
 
 #else  /* CONFIG_IRQ_REMAP */
 
@@ -89,9 +87,7 @@ static inline void panic_if_irq_remap(const char *msg)
 {
 }
 
-static inline bool setup_remapped_irq(int irq,
-				      struct irq_cfg *cfg,
-				      struct irq_chip *chip)
+static inline bool setup_remapped_irq(int irq, struct irq_cfg *cfg)
 {
 	return false;
 }
arch/x86/kernel/apic/apic.c +8 -1
index eca89c5..9b64203 100644
@@ -1571,6 +1571,8 @@ void enable_x2apic(void)
 int __init enable_IR(void)
 {
 #ifdef CONFIG_IRQ_REMAP
+	int ret;
+
 	if (!irq_remapping_supported()) {
 		pr_debug("intr-remapping not supported\n");
 		return -1;
@@ -1582,7 +1584,12 @@ int __init enable_IR(void)
 		return -1;
 	}
 
-	return irq_remapping_enable();
+	ret = irq_remapping_enable();
+
+	if (ret >= 0)
+		irq_remap_modify_chips();
+
+	return ret;
 #endif
 	return -1;
 }
arch/x86/kernel/apic/io_apic.c +6 -8
index 9ed796c..eda56ad 100644
@@ -1238,8 +1238,6 @@ void __setup_vector_irq(int cpu)
 	raw_spin_unlock(&vector_lock);
 }
 
-static struct irq_chip ioapic_chip;
-
 #ifdef CONFIG_X86_32
 static inline int IO_APIC_irq_trigger(int irq)
 {
@@ -1280,7 +1278,7 @@ static void ioapic_register_intr(unsigned int irq, struct irq_cfg *cfg,
 		fasteoi = false;
 	}
 
-	if (setup_remapped_irq(irq, cfg, chip))
+	if (setup_remapped_irq(irq, cfg))
 		fasteoi = trigger != 0;
 
 	hdl = fasteoi ? handle_fasteoi_irq : handle_edge_irq;
@@ -2511,7 +2509,7 @@ static void ack_apic_level(struct irq_data *data)
 	ioapic_irqd_unmask(data, cfg, masked);
 }
 
-static struct irq_chip ioapic_chip __read_mostly = {
+struct irq_chip ioapic_chip __read_mostly = {
 	.name			= "IO-APIC",
 	.irq_startup		= startup_ioapic_irq,
 	.irq_mask		= mask_ioapic_irq,
@@ -3093,7 +3091,7 @@ msi_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force)
  * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
  * which implement the MSI or MSI-X Capability Structure.
  */
-static struct irq_chip msi_chip = {
+struct irq_chip msi_chip = {
 	.name			= "PCI-MSI",
 	.irq_unmask		= unmask_msi_irq,
 	.irq_mask		= mask_msi_irq,
@@ -3123,7 +3121,7 @@ int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
 	if (!irq_offset)
 		write_msi_msg(irq, &msg);
 
-	setup_remapped_irq(irq, irq_get_chip_data(irq), chip);
+	setup_remapped_irq(irq, irq_get_chip_data(irq));
 
 	irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge");
 
@@ -3240,7 +3238,7 @@ static int hpet_msi_set_affinity(struct irq_data *data,
 	return IRQ_SET_MASK_OK_NOCOPY;
 }
 
-static struct irq_chip hpet_msi_type = {
+struct irq_chip hpet_msi_type = {
 	.name = "HPET_MSI",
 	.irq_unmask = hpet_msi_unmask,
 	.irq_mask = hpet_msi_mask,
@@ -3261,7 +3259,7 @@ int default_setup_hpet_msi(unsigned int irq, unsigned int id)
 
 	hpet_msi_write(irq_get_handler_data(irq), &msg);
 	irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
-	setup_remapped_irq(irq, irq_get_chip_data(irq), chip);
+	setup_remapped_irq(irq, irq_get_chip_data(irq));
 
 	irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge");
 	return 0;
drivers/iommu/irq_remapping.c +10 -3
index 85ae2cf..8e4e3af 100644
@@ -375,19 +375,26 @@ static void ir_print_prefix(struct irq_data *data, struct seq_file *p)
 	seq_printf(p, " IR-%s", data->chip->name);
 }
 
-static void irq_remap_modify_chip_defaults(struct irq_chip *chip)
+static void __init irq_remap_modify_chip_defaults(struct irq_chip *chip)
 {
+	printk(KERN_DEBUG "irq_chip: %s ==> IR-%s\n", chip->name, chip->name);
 	chip->irq_print_chip = ir_print_prefix;
 	chip->irq_ack = ir_ack_apic_edge;
 	chip->irq_eoi = ir_ack_apic_level;
 	chip->irq_set_affinity = x86_io_apic_ops.set_affinity;
 }
 
-bool setup_remapped_irq(int irq, struct irq_cfg *cfg, struct irq_chip *chip)
+void __init irq_remap_modify_chips(void)
+{
+	irq_remap_modify_chip_defaults(&ioapic_chip);
+	irq_remap_modify_chip_defaults(&msi_chip);
+	irq_remap_modify_chip_defaults(&hpet_msi_type);
+}
+
+bool setup_remapped_irq(int irq, struct irq_cfg *cfg)
 {
 	if (!irq_remapped(cfg))
 		return false;
 	irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
-	irq_remap_modify_chip_defaults(chip);
 	return true;
 }
Signature · 1 line
1.8.1.4
author
#6 lore raw

PATCH v4 6/28 x86, irq: Show MSI-X clearly in debug message

In reply to Yinghai Lu

Print out exact MSI or MSI-X instead of MSI/MSI-X.

Cc Joerg Roedel <[email protected]>
Cc Konrad Rzeszutek Wilk <[email protected]>
Cc Sebastian Andrzej Siewior <[email protected]>
---
 arch/x86/kernel/apic/io_apic.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
arch/x86/kernel/apic/io_apic.c +2 -1
index eda56ad..119fdf8 100644
@@ -3125,7 +3125,8 @@ int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
 
 	irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge");
 
-	dev_printk(KERN_DEBUG, &dev->dev, "irq %d for MSI/MSI-X\n", irq);
+	dev_printk(KERN_DEBUG, &dev->dev, "irq %d for MSI%s\n", irq,
+			 msidesc->msi_attrib.is_msix ? "-X" : "");
 
 	return 0;
 }
Signature · 1 line
1.8.1.4
author
#7 lore raw

PATCH v4 7/28 x86, irq: Show MSI-X in /proc/interrupt

In reply to Yinghai Lu

Now MSI-X is shown as MSI in /proc/interrupt.

We could use new added irq_print_chip() interface to append -X for MSI-X.

After this patch, we will have PCI-MSI-X-edge IR-PCI-MSI-X-edge for MSI-X instead of PCI-MSI-edge IR-PCI-MSI-edge in the /proc/interrupt.

-v2: do not need to check if msi_desc is null in msi_irq_print_chip().

Cc Joerg Roedel <[email protected]>
Cc Konrad Rzeszutek Wilk <[email protected]>
Cc Sebastian Andrzej Siewior <[email protected]>
---
 arch/x86/kernel/apic/io_apic.c | 7 +++++++
 drivers/iommu/irq_remapping.c  | 5 ++++-
 2 files changed, 11 insertions(+), 1 deletion(-)
arch/x86/kernel/apic/io_apic.c +7 -0
index 119fdf8..cf320fb 100644
@@ -3087,6 +3087,12 @@ msi_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force)
 	return IRQ_SET_MASK_OK_NOCOPY;
 }
 
+static void msi_irq_print_chip(struct irq_data *data, struct seq_file *p)
+{
+	seq_printf(p, " %s%s", data->chip->name,
+			data->msi_desc->msi_attrib.is_msix ? "-X" : "");
+}
+
 /*
  * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
  * which implement the MSI or MSI-X Capability Structure.
@@ -3098,6 +3104,7 @@ struct irq_chip msi_chip = {
 	.irq_ack		= ack_apic_edge,
 	.irq_set_affinity	= msi_set_affinity,
 	.irq_retrigger		= ioapic_retrigger_irq,
+	.irq_print_chip		= msi_irq_print_chip,
 };
 
 int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
drivers/iommu/irq_remapping.c +4 -1
index 8e4e3af..6893d75 100644
@@ -372,7 +372,10 @@ static void ir_ack_apic_level(struct irq_data *data)
 
 static void ir_print_prefix(struct irq_data *data, struct seq_file *p)
 {
-	seq_printf(p, " IR-%s", data->chip->name);
+	seq_printf(p, " IR-%s%s", data->chip->name,
+			data->msi_desc ?
+			 (data->msi_desc->msi_attrib.is_msix ? "-X" : "")
+			 : "");
 }
 
 static void __init irq_remap_modify_chip_defaults(struct irq_chip *chip)
Signature · 1 line
1.8.1.4
author
#8 lore raw

PATCH v4 8/28 x86, irq: Make dmar_msi/hpet_msi irq_chip name consistent

In reply to Yinghai Lu

All others are using "-" instead of "_".

Change dmar_msi and hpet_msi to use "-".

Cc Joerg Roedel <[email protected]>
Cc Konrad Rzeszutek Wilk <[email protected]>
Cc Sebastian Andrzej Siewior <[email protected]>
---
 arch/x86/kernel/apic/io_apic.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
arch/x86/kernel/apic/io_apic.c +2 -2
index cf320fb..47add1a 100644
@@ -3199,7 +3199,7 @@ dmar_msi_set_affinity(struct irq_data *data, const struct cpumask *mask,
 }
 
 static struct irq_chip dmar_msi_type = {
-	.name			= "DMAR_MSI",
+	.name			= "DMAR-MSI",
 	.irq_unmask		= dmar_msi_unmask,
 	.irq_mask		= dmar_msi_mask,
 	.irq_ack		= ack_apic_edge,
@@ -3247,7 +3247,7 @@ static int hpet_msi_set_affinity(struct irq_data *data,
 }
 
 struct irq_chip hpet_msi_type = {
-	.name = "HPET_MSI",
+	.name = "HPET-MSI",
 	.irq_unmask = hpet_msi_unmask,
 	.irq_mask = hpet_msi_mask,
 	.irq_ack = ack_apic_edge,
Signature · 1 line
1.8.1.4
author
#9 lore raw

PATCH v4 9/28 ia64, irq: Add dummy create_irq_nr()

In reply to Yinghai Lu

create_irq() will return -1 when fail to allocate. create_irq_nr() will return 0 when fail to allocate.

Will use it to fix one return value checking for dmar_msi irq.

---
 arch/ia64/kernel/irq_ia64.c | 10 ++++++++++
 1 file changed, 10 insertions(+)
arch/ia64/kernel/irq_ia64.c +10 -0
index 1034884..38e46df 100644
@@ -429,6 +429,16 @@ int create_irq(void)
 	return irq;
 }
 
+unsigned int create_irq_nr(unsigned int from, int node)
+{
+	int irq = create_irq();
+
+	if (irq < 0)
+		irq = 0;
+
+	return irq;
+}
+
 void destroy_irq(unsigned int irq)
 {
 	dynamic_irq_cleanup(irq);
Signature · 1 line
1.8.1.4
author
#10 lore raw

PATCH v4 10/28 iommu, irq: Allocate irq_desc for dmar_msi with local node

In reply to Yinghai Lu

iommu irq's irq_desc should be on local node ram.

Fix the return value checking problem.
create_irq() will return -1 when fail to allocate. create_irq_nr() will return 0 when fail to allocate.
here only check !irq, so need to change it to use create_irq_nr instead.

-v2: According to Sebastian, add cc to stable.

Cc Joerg Roedel <[email protected]>
Cc Donald Dutile <[email protected]>
Cc Sebastian Andrzej Siewior <[email protected]>
---
 drivers/iommu/dmar.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iommu/dmar.c +1 -1
index 785675a..db41e36 100644
@@ -1277,7 +1277,7 @@ int dmar_set_interrupt(struct intel_iommu *iommu)
 	if (iommu->irq)
 		return 0;
 
-	irq = create_irq();
+	irq = create_irq_nr(0, iommu->node);
 	if (!irq) {
 		pr_err("IOMMU: no free vectors\n");
 		return -EINVAL;
Signature · 1 line
1.8.1.4
author
#11 lore raw

PATCH v4 11/28 x86, irq: Kill create_irq()

In reply to Yinghai Lu

create_irq() will return -1 when failing to allocate. create_irq_nr() will return 0 when failing to allocate.

It only causes confusion.

Now we have no user for create_irq(), so remove create_irq() for x86.

Cc Joerg Roedel <[email protected]>
Cc Konrad Rzeszutek Wilk <[email protected]>
Cc Sebastian Andrzej Siewior <[email protected]>
---
 arch/x86/kernel/apic/io_apic.c | 15 ---------------
 1 file changed, 15 deletions(-)
arch/x86/kernel/apic/io_apic.c +0 -15
index 47add1a..ccfb1d3 100644
@@ -2968,21 +2968,6 @@ unsigned int create_irq_nr(unsigned int from, int node)
 	return __create_irqs(from, 1, node);
 }
 
-int create_irq(void)
-{
-	int node = cpu_to_node(0);
-	unsigned int irq_want;
-	int irq;
-
-	irq_want = nr_irqs_gsi;
-	irq = create_irq_nr(irq_want, node);
-
-	if (irq == 0)
-		irq = -1;
-
-	return irq;
-}
-
 void destroy_irq(unsigned int irq)
 {
 	struct irq_cfg *cfg = irq_get_chip_data(irq);
Signature · 1 line
1.8.1.4
author
#12 lore raw

PATCH v4 12/28 x86, irq: Convert irq_2_pin list to generic list

In reply to Yinghai Lu

Now irq_2_pin list is own grown list for ioapic irq/pin tracking. We can use generic list to replace it so we could use generic helper functions to operate it.

Also make free_irq_cfg() free irq_2_pin list to support coming ioapic hotplug.

Cc Konrad Rzeszutek Wilk <[email protected]>
Cc Sebastian Andrzej Siewior <[email protected]>
Cc Joerg Roedel <[email protected]>
---
 arch/x86/include/asm/hw_irq.h  |  2 +-
 arch/x86/kernel/apic/io_apic.c | 22 ++++++++++++----------
 2 files changed, 13 insertions(+), 11 deletions(-)
arch/x86/include/asm/hw_irq.h +1 -1
index e4ac559..8504333 100644
@@ -139,7 +139,7 @@ struct irq_2_irte {
  * Most irqs are mapped 1:1 with pins.
  */
 struct irq_cfg {
-	struct irq_pin_list	*irq_2_pin;
+	struct list_head	irq_2_pin;
 	cpumask_var_t		domain;
 	cpumask_var_t		old_domain;
 	u8			vector;
arch/x86/kernel/apic/io_apic.c +12 -10
index ccfb1d3..ef2d530 100644
@@ -66,7 +66,7 @@
 #define __apicdebuginit(type) static type __init
 
 #define for_each_irq_pin(entry, head) \
-	for (entry = head; entry; entry = entry->next)
+	list_for_each_entry(entry, &head, list)
 
 /*
  *      Is the SiS APIC rmw bug present ?
@@ -176,8 +176,8 @@ void mp_save_irq(struct mpc_intsrc *m)
 }
 
 struct irq_pin_list {
+	struct list_head list;
 	int apic, pin;
-	struct irq_pin_list *next;
 };
 
 static struct irq_pin_list *alloc_irq_pin_list(int node)
@@ -213,6 +213,7 @@ int __init arch_early_irq_init(void)
 	irq_reserve_irqs(0, legacy_pic->nr_legacy_irqs);
 
 	for (i = 0; i < count; i++) {
+		INIT_LIST_HEAD(&cfg[i].irq_2_pin);
 		irq_set_chip_data(i, &cfg[i]);
 		zalloc_cpumask_var_node(&cfg[i].domain, GFP_KERNEL, node);
 		zalloc_cpumask_var_node(&cfg[i].old_domain, GFP_KERNEL, node);
@@ -245,6 +246,7 @@ static struct irq_cfg *alloc_irq_cfg(unsigned int irq, int node)
 		goto out_cfg;
 	if (!zalloc_cpumask_var_node(&cfg->old_domain, GFP_KERNEL, node))
 		goto out_domain;
+	INIT_LIST_HEAD(&cfg->irq_2_pin);
 	return cfg;
 out_domain:
 	free_cpumask_var(cfg->domain);
@@ -255,11 +257,15 @@ out_cfg:
 
 static void free_irq_cfg(unsigned int at, struct irq_cfg *cfg)
 {
+	struct irq_pin_list *entry, *tmp;
+
 	if (!cfg)
 		return;
 	irq_set_chip_data(at, NULL);
 	free_cpumask_var(cfg->domain);
 	free_cpumask_var(cfg->old_domain);
+	list_for_each_entry_safe(entry, tmp, &cfg->irq_2_pin, list)
+		kfree(entry);
 	kfree(cfg);
 }
 
@@ -420,15 +426,12 @@ static void ioapic_mask_entry(int apic, int pin)
  */
 static int __add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pin)
 {
-	struct irq_pin_list **last, *entry;
+	struct irq_pin_list *entry;
 
 	/* don't allow duplicates */
-	last = &cfg->irq_2_pin;
-	for_each_irq_pin(entry, cfg->irq_2_pin) {
+	for_each_irq_pin(entry, cfg->irq_2_pin)
 		if (entry->apic == apic && entry->pin == pin)
 			return 0;
-		last = &entry->next;
-	}
 
 	entry = alloc_irq_pin_list(node);
 	if (!entry) {
@@ -439,7 +442,7 @@ static int __add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pi
 	entry->apic = apic;
 	entry->pin = pin;
 
-	*last = entry;
+	list_add_tail(&entry->list, &cfg->irq_2_pin);
 	return 0;
 }
 
@@ -1622,8 +1625,7 @@ __apicdebuginit(void) print_IO_APICs(void)
 		cfg = irq_get_chip_data(irq);
 		if (!cfg)
 			continue;
-		entry = cfg->irq_2_pin;
-		if (!entry)
+		if (list_empty(&cfg->irq_2_pin))
 			continue;
 		printk(KERN_DEBUG "IRQ%d ", irq);
 		for_each_irq_pin(entry, cfg->irq_2_pin)
Signature · 1 line
1.8.1.4
author
#13 lore raw

PATCH v4 13/28 x86, irq: Add alloc_reserved_irq_and_cfg_at()

In reply to Yinghai Lu

For ioapic hot-add support, it would be easy if we have continuous irq numbers for new added ioapic controller.

We can reserve irq range at first, then allocate those pre-reserved one when it is needed.

Add alloc_reserved_irq_and_cfg_at() to really allocate irq_desc and cfg, because pre-reserved only mark bits in allocate_irqs bit maps.

Also fallback to alloc_irq_and_cfg_at(), and it is needed as we do not actually reserved irq for io apic irq yet.

This patch is x86 arch code.

-v2: update changelog by adding reasons, requested by Konrad. -v3: according to tglx, separate to another patch, and use
alloc_reserved_... instead of realloc_...
also add handling for one possible path in
alloc_reserved_irq_and_cfg_at().

Cc Joerg Roedel <[email protected]>
Cc Konrad Rzeszutek Wilk <[email protected]>
Cc Sebastian Andrzej Siewior <[email protected]>
---
 arch/x86/kernel/apic/io_apic.c | 25 ++++++++++++++++++++++++-
 1 file changed, 24 insertions(+), 1 deletion(-)
arch/x86/kernel/apic/io_apic.c +24 -1
index ef2d530..c883da9 100644
@@ -301,6 +301,29 @@ static void free_irq_at(unsigned int at, struct irq_cfg *cfg)
 	irq_free_desc(at);
 }
 
+static struct irq_cfg *alloc_reserved_irq_and_cfg_at(unsigned int at, int node)
+{
+	struct irq_cfg *cfg;
+	int res;
+
+	res = irq_alloc_reserved_desc_at(at, node);
+
+	if (res >= 0) {
+		cfg = irq_desc_get_chip_data(irq_to_desc(at));
+		if (cfg)
+			return cfg;
+
+		cfg = alloc_irq_cfg(at, node);
+		if (cfg)
+			irq_set_chip_data(at, cfg);
+		else
+			irq_free_desc(at);
+
+		return cfg;
+	}
+
+	return alloc_irq_and_cfg_at(at, node);
+}
 
 struct io_apic {
 	unsigned int index;
@@ -3352,7 +3375,7 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
 static int
 io_apic_setup_irq_pin(unsigned int irq, int node, struct io_apic_irq_attr *attr)
 {
-	struct irq_cfg *cfg = alloc_irq_and_cfg_at(irq, node);
+	struct irq_cfg *cfg = alloc_reserved_irq_and_cfg_at(irq, node);
 	int ret;
 
 	if (!cfg)
Signature · 1 line
1.8.1.4
author
#14 lore raw

PATCH v4 14/28 x86, irq: Move down arch_early_irq_init()

In reply to Yinghai Lu

Change position only.

Prepare to update arch_early_irq_init() that needs to call some static functions.

Cc Joerg Roedel <[email protected]>
Cc Konrad Rzeszutek Wilk <[email protected]>
Cc Sebastian Andrzej Siewior <[email protected]>
---
 arch/x86/kernel/apic/io_apic.c | 89 +++++++++++++++++++++---------------------
 1 file changed, 44 insertions(+), 45 deletions(-)
arch/x86/kernel/apic/io_apic.c +44 -45
index c883da9..18b123b 100644
@@ -185,51 +185,6 @@ static struct irq_pin_list *alloc_irq_pin_list(int node)
 	return kzalloc_node(sizeof(struct irq_pin_list), GFP_KERNEL, node);
 }
 
-
-/* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */
-static struct irq_cfg irq_cfgx[NR_IRQS_LEGACY];
-
-int __init arch_early_irq_init(void)
-{
-	struct irq_cfg *cfg;
-	int count, node, i;
-
-	if (!legacy_pic->nr_legacy_irqs)
-		io_apic_irqs = ~0UL;
-
-	for (i = 0; i < nr_ioapics; i++) {
-		ioapics[i].saved_registers =
-			kzalloc(sizeof(struct IO_APIC_route_entry) *
-				ioapics[i].nr_registers, GFP_KERNEL);
-		if (!ioapics[i].saved_registers)
-			pr_err("IOAPIC %d: suspend/resume impossible!\n", i);
-	}
-
-	cfg = irq_cfgx;
-	count = ARRAY_SIZE(irq_cfgx);
-	node = cpu_to_node(0);
-
-	/* Make sure the legacy interrupts are marked in the bitmap */
-	irq_reserve_irqs(0, legacy_pic->nr_legacy_irqs);
-
-	for (i = 0; i < count; i++) {
-		INIT_LIST_HEAD(&cfg[i].irq_2_pin);
-		irq_set_chip_data(i, &cfg[i]);
-		zalloc_cpumask_var_node(&cfg[i].domain, GFP_KERNEL, node);
-		zalloc_cpumask_var_node(&cfg[i].old_domain, GFP_KERNEL, node);
-		/*
-		 * For legacy IRQ's, start with assigning irq0 to irq15 to
-		 * IRQ0_VECTOR to IRQ15_VECTOR for all cpu's.
-		 */
-		if (i < legacy_pic->nr_legacy_irqs) {
-			cfg[i].vector = IRQ0_VECTOR + i;
-			cpumask_setall(cfg[i].domain);
-		}
-	}
-
-	return 0;
-}
-
 static struct irq_cfg *irq_cfg(unsigned int irq)
 {
 	return irq_get_chip_data(irq);
@@ -325,6 +280,50 @@ static struct irq_cfg *alloc_reserved_irq_and_cfg_at(unsigned int at, int node)
 	return alloc_irq_and_cfg_at(at, node);
 }
 
+/* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */
+static struct irq_cfg irq_cfgx[NR_IRQS_LEGACY];
+
+int __init arch_early_irq_init(void)
+{
+	struct irq_cfg *cfg;
+	int count, node, i;
+
+	if (!legacy_pic->nr_legacy_irqs)
+		io_apic_irqs = ~0UL;
+
+	for (i = 0; i < nr_ioapics; i++) {
+		ioapics[i].saved_registers =
+			kzalloc(sizeof(struct IO_APIC_route_entry) *
+				ioapics[i].nr_registers, GFP_KERNEL);
+		if (!ioapics[i].saved_registers)
+			pr_err("IOAPIC %d: suspend/resume impossible!\n", i);
+	}
+
+	cfg = irq_cfgx;
+	count = ARRAY_SIZE(irq_cfgx);
+	node = cpu_to_node(0);
+
+	/* Make sure the legacy interrupts are marked in the bitmap */
+	irq_reserve_irqs(0, legacy_pic->nr_legacy_irqs);
+
+	for (i = 0; i < count; i++) {
+		INIT_LIST_HEAD(&cfg[i].irq_2_pin);
+		irq_set_chip_data(i, &cfg[i]);
+		zalloc_cpumask_var_node(&cfg[i].domain, GFP_KERNEL, node);
+		zalloc_cpumask_var_node(&cfg[i].old_domain, GFP_KERNEL, node);
+		/*
+		 * For legacy IRQ's, start with assigning irq0 to irq15 to
+		 * IRQ0_VECTOR to IRQ15_VECTOR for all cpu's.
+		 */
+		if (i < legacy_pic->nr_legacy_irqs) {
+			cfg[i].vector = IRQ0_VECTOR + i;
+			cpumask_setall(cfg[i].domain);
+		}
+	}
+
+	return 0;
+}
+
 struct io_apic {
 	unsigned int index;
 	unsigned int unused[3];
Signature · 1 line
1.8.1.4
author
#15 lore raw

PATCH v4 15/28 x86, irq: Split out alloc_ioapic_save_registers()

In reply to Yinghai Lu

Split alloc_ioapic_save_registers() from early_irq_init(), so it will be used per ioapic.

Will call that later for hot-added ioapic controller.

Cc Joerg Roedel <[email protected]>
Cc Konrad Rzeszutek Wilk <[email protected]>
Cc Sebastian Andrzej Siewior <[email protected]>
---
 arch/x86/kernel/apic/io_apic.c | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)
arch/x86/kernel/apic/io_apic.c +15 -7
index 18b123b..3e0530c 100644
@@ -283,6 +283,19 @@ static struct irq_cfg *alloc_reserved_irq_and_cfg_at(unsigned int at, int node)
 /* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */
 static struct irq_cfg irq_cfgx[NR_IRQS_LEGACY];
 
+static void alloc_ioapic_saved_registers(int idx)
+{
+	if (ioapics[idx].saved_registers)
+		return;
+
+	ioapics[idx].saved_registers =
+			kzalloc(sizeof(struct IO_APIC_route_entry) *
+				ioapics[idx].nr_registers, GFP_KERNEL);
+
+	if (!ioapics[idx].saved_registers)
+		pr_err("IOAPIC %d: suspend/resume impossible!\n", idx);
+}
+
 int __init arch_early_irq_init(void)
 {
 	struct irq_cfg *cfg;
@@ -291,13 +304,8 @@ int __init arch_early_irq_init(void)
 	if (!legacy_pic->nr_legacy_irqs)
 		io_apic_irqs = ~0UL;
 
-	for (i = 0; i < nr_ioapics; i++) {
-		ioapics[i].saved_registers =
-			kzalloc(sizeof(struct IO_APIC_route_entry) *
-				ioapics[i].nr_registers, GFP_KERNEL);
-		if (!ioapics[i].saved_registers)
-			pr_err("IOAPIC %d: suspend/resume impossible!\n", i);
-	}
+	for (i = 0; i < nr_ioapics; i++)
+		alloc_ioapic_saved_registers(i);
 
 	cfg = irq_cfgx;
 	count = ARRAY_SIZE(irq_cfgx);
Signature · 1 line
1.8.1.4
author
#16 lore raw

PATCH v4 16/28 xen, irq: Call irq_alloc_reserved_desc_at() at first

In reply to Yinghai Lu

To make x86 irq allocation to be same with booting path and ioapic hot add path, We will pre-reserve irq for all gsi at first. We have to use alloc_reserved here, otherwise irq_alloc_desc_at will fail because bit is already get marked for pre-reserved in irq bitmaps.

---
 drivers/xen/events.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/xen/events.c +6 -2
index a58ac43..1a3647c 100644
@@ -507,8 +507,12 @@ static int __must_check xen_allocate_irq_gsi(unsigned gsi)
 	/* Legacy IRQ descriptors are already allocated by the arch. */
 	if (gsi < NR_IRQS_LEGACY)
 		irq = gsi;
-	else
-		irq = irq_alloc_desc_at(gsi, -1);
+	else {
+		/* for x86, irq already get reserved for gsi */
+		irq = irq_alloc_reserved_desc_at(gsi, -1);
+		if (irq < 0)
+			irq = irq_alloc_desc_at(gsi, -1);
+	}
 
 	xen_irq_init(irq);
 
Signature · 1 line
1.8.1.4
author
#17 lore raw

PATCH v4 17/28 x86, irq: Reserve irq range and alloc_reserved for booting path

In reply to Yinghai Lu

We will use reserve and alloc_reserved_irq_and_cfg_at for hotplug ioapic path.

To make thing simple, we could make booting path use same code.

All irq range for all GSIs will be reserved at first, and alloc_reserved will really allocate those irq_desc/cfg when it is used.

Cc Joerg Roedel <[email protected]>
Cc Konrad Rzeszutek Wilk <[email protected]>
Cc Sebastian Andrzej Siewior <[email protected]>
---
 arch/x86/include/asm/io_apic.h |  1 +
 arch/x86/kernel/apic/io_apic.c | 80 +++++++++++++++++++++++++++++++-----------
 2 files changed, 60 insertions(+), 21 deletions(-)
arch/x86/include/asm/io_apic.h +1 -0
index eaff3ad..8181fd8 100644
@@ -176,6 +176,7 @@ extern void setup_ioapic_ids_from_mpc_nocheck(void);
 struct mp_ioapic_gsi{
 	u32 gsi_base;
 	u32 gsi_end;
+	u32 irq_base;
 };
 extern struct mp_ioapic_gsi  mp_gsi_routing[];
 extern u32 gsi_top;
arch/x86/kernel/apic/io_apic.c +59 -21

108 lines not on this page · raw message

Signature · 1 line
1.8.1.4
author
#18 lore raw

PATCH v4 18/28 x86, irq: Add ioapic_gsi_to_irq

In reply to Yinghai Lu

For hot add ioapic, irq_base is not equal to gsi_base. We need a way to do mapping between gsi and irq.

Also remove irq_to_gsi() that is confusing, just use that array directly as we only have one caller and it already check input irq before use it.

Cc Pavel Machek <[email protected]>
Cc Joerg Roedel <[email protected]>
Cc Konrad Rzeszutek Wilk <[email protected]>
Cc Sebastian Andrzej Siewior <[email protected]>
---
 arch/x86/include/asm/io_apic.h |  1 +
 arch/x86/kernel/acpi/boot.c    | 22 +++++-----------------
 arch/x86/kernel/apic/io_apic.c | 29 ++++++++++++++++++++++++++++-
 3 files changed, 34 insertions(+), 18 deletions(-)
arch/x86/include/asm/io_apic.h +1 -0
index 8181fd8..02ac411 100644
@@ -180,6 +180,7 @@ struct mp_ioapic_gsi{
 };
 extern struct mp_ioapic_gsi  mp_gsi_routing[];
 extern u32 gsi_top;
+int ioapic_gsi_to_irq(u32 gsi);
 int mp_find_ioapic(u32 gsi);
 int mp_find_ioapic_pin(int ioapic, u32 gsi);
 void __init mp_register_ioapic(int id, u32 address, u32 gsi_base);
arch/x86/kernel/acpi/boot.c +5 -17
index 2627a81..5be15d1 100644
@@ -112,6 +112,10 @@ static unsigned int gsi_to_irq(unsigned int gsi)
 		}
 	}
 
+#ifdef CONFIG_X86_IO_APIC
+	if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC)
+		return ioapic_gsi_to_irq(gsi);
+#endif
 	/* Provide an identity mapping of gsi == irq
 	 * except on truly weird platforms that have
 	 * non isa irqs in the first 16 gsis.
@@ -124,22 +128,6 @@ static unsigned int gsi_to_irq(unsigned int gsi)
 	return irq;
 }
 
-static u32 irq_to_gsi(int irq)
-{
-	unsigned int gsi;
-
-	if (irq < NR_IRQS_LEGACY)
-		gsi = isa_irq_to_gsi[irq];
-	else if (irq < gsi_top)
-		gsi = irq;
-	else if (irq < (gsi_top + NR_IRQS_LEGACY))
-		gsi = irq - gsi_top;
-	else
-		gsi = 0xffffffff;
-
-	return gsi;
-}
-
 /*
  * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_END,
  * to map the target physical address. The problem is that set_fixmap()
@@ -529,7 +517,7 @@ int acpi_isa_irq_to_gsi(unsigned isa_irq, u32 *gsi)
 {
 	if (isa_irq >= 16)
 		return -1;
-	*gsi = irq_to_gsi(isa_irq);
+	*gsi = isa_irq_to_gsi[isa_irq];
 	return 0;
 }
 
arch/x86/kernel/apic/io_apic.c +28 -1
index cb272c9..8d087f1 100644
@@ -1041,13 +1041,16 @@ static int pin_2_irq(int idx, int apic, int pin)
 
 	if (test_bit(bus, mp_bus_not_pci)) {
 		irq = mp_irqs[idx].srcbusirq;
-	} else {
+	} else if (gsi_cfg->gsi_base == gsi_cfg->irq_base) {
 		u32 gsi = gsi_cfg->gsi_base + pin;
 
 		if (gsi >= NR_IRQS_LEGACY)
 			irq = gsi;
 		else
 			irq = gsi_top + gsi;
+	} else {
+		/* hotadd ioapic */
+		irq = gsi_cfg->irq_base + pin;
 	}
 
 #ifdef CONFIG_X86_32
@@ -1473,6 +1476,30 @@ static void __init setup_IO_APIC_irqs(void)
 		__io_apic_setup_irqs(ioapic_idx);
 }
 
+int ioapic_gsi_to_irq(u32 gsi)
+{
+	int ioapic_idx = 0, irq = gsi;
+	struct mp_ioapic_gsi *gsi_cfg;
+
+	ioapic_idx = mp_find_ioapic(gsi);
+	if (ioapic_idx < 0)
+		return -1;
+
+	gsi_cfg = mp_ioapic_gsi_routing(ioapic_idx);
+	if (gsi_cfg->gsi_base == gsi_cfg->irq_base) {
+		if (gsi < NR_IRQS_LEGACY)
+			irq = gsi_top + gsi;
+	} else {
+		int pin = mp_find_ioapic_pin(ioapic_idx, gsi);
+
+		if (pin < 0)
+			return -1;
+		/* hotadd ioapic */
+		irq = gsi_cfg->irq_base + pin;
+	}
+
+	return irq;
+}
 /*
  * for the gsit that is not in first ioapic
  * but could not use acpi_register_gsi()
Signature · 1 line
1.8.1.4
author
#19 lore raw

PATCH v4 19/28 x86, irq: Add for_each_ioapic helper

In reply to Yinghai Lu

For hotadd and hotremove ioapic controller, we leave blank slots in ioapics array.

So we can not use for (i=...) to loop them any more.

Introdue ioapics_mask bitmap to track used ioapics, and use for_each_ioapic to loop them.

Cc Joerg Roedel <[email protected]>
Cc Konrad Rzeszutek Wilk <[email protected]>
Cc Sebastian Andrzej Siewior <[email protected]>
Cc Grant Likely <[email protected]>
Cc Paul Gortmaker <[email protected]>
Cc Andy Lutomirski <[email protected]>
---
 arch/x86/include/asm/io_apic.h      |  6 ++++
 arch/x86/kernel/apic/io_apic.c      | 64 ++++++++++++++++++++-----------------
 arch/x86/kernel/devicetree.c        |  2 +-
 drivers/iommu/amd_iommu_init.c      |  2 +-
 drivers/iommu/intel_irq_remapping.c |  2 +-
 5 files changed, 43 insertions(+), 33 deletions(-)
arch/x86/include/asm/io_apic.h +6 -0
index 02ac411..a25dcf1 100644
@@ -105,6 +105,12 @@ struct IR_IO_APIC_route_entry {
  * # of IO-APICs and # of IRQ routing registers
  */
 extern int nr_ioapics;
+extern DECLARE_BITMAP(ioapics_mask, MAX_IO_APICS);
+
+#define for_each_ioapic(i)						\
+	for ((i) = -1;							\
+		(i) = find_next_bit(ioapics_mask, MAX_IO_APICS, (i)+1), \
+		(i) < MAX_IO_APICS;)
 
 extern int mpc_ioapic_id(int ioapic);
 extern unsigned int mpc_ioapic_addr(int ioapic);
arch/x86/kernel/apic/io_apic.c +34 -30

217 lines not on this page · raw message

arch/x86/kernel/devicetree.c +1 -1
index 69eb2fa..c811e2f 100644
@@ -393,7 +393,7 @@ static void __init ioapic_add_ofnode(struct device_node *np)
 		return;
 	}
 
-	for (i = 0; i < nr_ioapics; i++) {
+	for_each_ioapic(i) {
 		if (r.start == mpc_ioapic_addr(i)) {
 			dt_add_ioapic_domain(i, np);
 			return;
drivers/iommu/amd_iommu_init.c +1 -1
index 7acbf35..7bbe9d2 100644
@@ -1743,7 +1743,7 @@ static bool __init check_ioapic_information(void)
 	if (cmdline_maps)
 		fw_bug = "";
 
-	for (idx = 0; idx < nr_ioapics; idx++) {
+	for_each_ioapic(idx) {
 		int devid, id = mpc_ioapic_id(idx);
 
 		devid = get_ioapic_devid(id);
drivers/iommu/intel_irq_remapping.c +1 -1
index f71673d..84a6807 100644
@@ -793,7 +793,7 @@ int __init parse_ioapics_under_ir(void)
 	if (!ir_supported)
 		return 0;
 
-	for (ioapic_idx = 0; ioapic_idx < nr_ioapics; ioapic_idx++) {
+	for_each_ioapic(ioapic_idx) {
 		int ioapic_id = mpc_ioapic_id(ioapic_idx);
 		if (!map_ioapic_to_ir(ioapic_id)) {
 			pr_err(FW_BUG "ioapic %d has no mapping iommu, "
Signature · 1 line
1.8.1.4
author
#20 lore raw

PATCH v4 20/28 x86, irq: More strict checking about registering ioapic

In reply to Yinghai Lu

1. check overlaping gsi range
for hot-add ioapic case, BIOS may have some entries in MADT and also have setting in pci root bus with _GSB of DSDT.

2. check if entries is in right range.

Cc Joerg Roedel <[email protected]>
Cc Konrad Rzeszutek Wilk <[email protected]>
Cc Sebastian Andrzej Siewior <[email protected]>
---
 arch/x86/kernel/apic/io_apic.c | 30 ++++++++++++++++++++++++------
 1 file changed, 24 insertions(+), 6 deletions(-)
arch/x86/kernel/apic/io_apic.c +24 -6
index b026cc7..60c6706 100644
@@ -3818,12 +3818,9 @@ void __init ioapic_insert_resources(void)
 	}
 }
 
-int mp_find_ioapic(u32 gsi)
+static int __mp_find_ioapic(u32 gsi)
 {
-	int i = 0;
-
-	if (nr_ioapics == 0)
-		return -1;
+	int i;
 
 	/* Find the IOAPIC that manages this GSI. */
 	for_each_ioapic(i) {
@@ -3833,10 +3830,19 @@ int mp_find_ioapic(u32 gsi)
 			return i;
 	}
 
-	printk(KERN_ERR "ERROR: Unable to locate IOAPIC for GSI %d\n", gsi);
 	return -1;
 }
 
+int mp_find_ioapic(u32 gsi)
+{
+	int ret = __mp_find_ioapic(gsi);
+
+	if (ret == -1)
+		pr_err("ERROR: Unable to locate IOAPIC for GSI %d\n", gsi);
+
+	return ret;
+}
+
 int mp_find_ioapic_pin(int ioapic, u32 gsi)
 {
 	struct mp_ioapic_gsi *gsi_cfg;
@@ -3888,6 +3894,11 @@ void __init mp_register_ioapic(int id, u32 address, u32 gsi_base)
 	if (bad_ioapic(address))
 		return;
 
+	/* already registered ? */
+	idx = __mp_find_ioapic(gsi_base);
+	if (idx >= 0)
+		return;
+
 	idx = find_first_zero_bit(ioapics_mask, MAX_IO_APICS);
 	if (idx >= MAX_IO_APICS) {
 		pr_warn("WARNING: Max # of I/O APICs (%d) exceeded, skipping\n",
@@ -3914,6 +3925,13 @@ 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);
+
+	if (!entries || entries > MP_MAX_IOAPIC_PIN) {
+		clear_fixmap(FIX_IO_APIC_BASE_0 + idx);
+		memset(&ioapics[idx], 0, sizeof(struct ioapic));
+		return;
+	}
+
 	gsi_cfg = mp_ioapic_gsi_routing(idx);
 	gsi_cfg->gsi_base = gsi_base;
 	gsi_cfg->gsi_end = gsi_base + entries - 1;
Signature · 1 line
1.8.1.4
#21 lore raw

Re: [PATCH v4 20/28] x86, irq: More strict checking about registering ioapic

2013/8/11 Yinghai Lu <[email protected]>

Quoted 68 lines

1. check overlaping gsi range
for hot-add ioapic case, BIOS may have some entries in MADT and also have setting in pci root bus with _GSB of DSDT.

2. check if entries is in right range.

Cc Joerg Roedel <[email protected]>
Cc Konrad Rzeszutek Wilk <[email protected]>
Cc Sebastian Andrzej Siewior <[email protected]>
---
 arch/x86/kernel/apic/io_apic.c | 30 ++++++++++++++++++++++++------
 1 file changed, 24 insertions(+), 6 deletions(-)
arch/x86/kernel/apic/io_apic.c +17 -6
index b026cc7..60c6706 100644
@@ -3818,12 +3818,9 @@ void __init ioapic_insert_resources(void)
        }
 }
 
-int mp_find_ioapic(u32 gsi)
+static int __mp_find_ioapic(u32 gsi)
 {
-       int i = 0;
-
-       if (nr_ioapics == 0)
-               return -1;
+       int i;
 
        /* Find the IOAPIC that manages this GSI. */
        for_each_ioapic(i) {
@@ -3833,10 +3830,19 @@ int mp_find_ioapic(u32 gsi)
                        return i;
        }
 
-       printk(KERN_ERR "ERROR: Unable to locate IOAPIC for GSI %d\n", gsi);
        return -1;
 }
 
+int mp_find_ioapic(u32 gsi)
+{
+       int ret = __mp_find_ioapic(gsi);
+
+       if (ret == -1)
+               pr_err("ERROR: Unable to locate IOAPIC for GSI %d\n", gsi);
+
+       return ret;
+}
+
 int mp_find_ioapic_pin(int ioapic, u32 gsi)
 {
        struct mp_ioapic_gsi *gsi_cfg;
@@ -3888,6 +3894,11 @@ void __init mp_register_ioapic(int id, u32 address, u32 gsi_base)
        if (bad_ioapic(address))
                return;
 
+       /* already registered ? */
+       idx = __mp_find_ioapic(gsi_base);
+       if (idx >= 0)
+               return;
+
        idx = find_first_zero_bit(ioapics_mask, MAX_IO_APICS);
        if (idx >= MAX_IO_APICS) {
                pr_warn("WARNING: Max # of I/O APICs (%d) exceeded, skipping\n",

arch/x86/kernel/apic/io_apic.c void __init mp_register_ioapic(int id, u32 address, u32 gsi_base) · line 3927

Quoted 3 lines
arch/x86/kernel/apic/io_apic.c +0 -0
@@ -3914,6 +3925,13 @@ 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);

"entries" is possible to be 0? io_apic_get_redir_entries() returns
"reg_01.bits.entries + 1"
as "entries".

Quoted 17 lines
arch/x86/kernel/apic/io_apic.c +7 -1
+
+       if (!entries || entries > MP_MAX_IOAPIC_PIN) {
+               clear_fixmap(FIX_IO_APIC_BASE_0 + idx);
+               memset(&ioapics[idx], 0, sizeof(struct ioapic));
+               return;
+       }
+
        gsi_cfg = mp_ioapic_gsi_routing(idx);
        gsi_cfg->gsi_base = gsi_base;
        gsi_cfg->gsi_end = gsi_base + entries - 1;
--

1.8.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 2 lines
Best regards
Tianyu Lan
#22 lore raw

Re: [PATCH v4 20/28] x86, irq: More strict checking about registering ioapic

In reply to Yinghai Lu

arch/x86/kernel/apic/io_apic.c void __init mp_register_ioapic(int id, u32 address, u32 gsi_base) · line 3900

Quoted 11 lines

int mp_find_ioapic_pin(int ioapic, u32 gsi)
{

arch/x86/kernel/apic/io_apic.c +4 -0
 	struct mp_ioapic_gsi *gsi_cfg;
@@ -3888,6 +3894,11 @@ void __init mp_register_ioapic(int id, u32 address, u32 gsi_base)
 	if (bad_ioapic(address))
 		return;
 
+	/* already registered ? */
+	idx = __mp_find_ioapic(gsi_base);
+	if (idx >= 0)
+		return;

Hi Yinghai,
If you add whether ioapic was already registered check here, so we will fail to add ioapic into global ioapic_list.
Then we also can not hot remove this ioapic.

1. We will call mp_register_ioapic during analyze MADT first.
2. We will try to add hotplug ioapic(which contain _GSB) to ioapic_list in acpi_pci_ioapic_add(), but will found this ioapic has been registered.

Thanks!
Yijing.

Quoted 19 lines
arch/x86/kernel/apic/io_apic.c +8 -0
+
 	idx = find_first_zero_bit(ioapics_mask, MAX_IO_APICS);
 	if (idx >= MAX_IO_APICS) {
 		pr_warn("WARNING: Max # of I/O APICs (%d) exceeded, skipping\n",
@@ -3914,6 +3925,13 @@ 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);
+
+	if (!entries || entries > MP_MAX_IOAPIC_PIN) {
+		clear_fixmap(FIX_IO_APIC_BASE_0 + idx);
+		memset(&ioapics[idx], 0, sizeof(struct ioapic));
+		return;
+	}
+
 	gsi_cfg = mp_ioapic_gsi_routing(idx);
 	gsi_cfg->gsi_base = gsi_base;
 	gsi_cfg->gsi_end = gsi_base + entries - 1;
Signature · 2 lines
Thanks!
Yijing
author
#23 lore raw

PATCH v4 21/28 x86, irq: Make mp_register_ioapic handle hot-added ioapic

In reply to Yinghai Lu

It needs to reserve irq range in allocated_irqs bitmaps and irq_base will be used to get right irq for ioapic/pin or gsi.

also need to use lock to protect ioapics_mask to avoid racing.

Cc Paul Gortmaker <[email protected]>
Cc Joerg Roedel <[email protected]>
Cc Konrad Rzeszutek Wilk <[email protected]>
Cc Sebastian Andrzej Siewior <[email protected]>
---
 arch/x86/include/asm/mpspec.h  |  1 +
 arch/x86/kernel/apic/io_apic.c | 68 ++++++++++++++++++++++++++++++++----------
 2 files changed, 54 insertions(+), 15 deletions(-)
arch/x86/include/asm/mpspec.h +1 -0
index 626cf70..13cf60c 100644
@@ -96,6 +96,7 @@ static inline void early_reserve_e820_mpc_new(void) { }
 
 void generic_processor_info(int apicid, int version);
 #ifdef CONFIG_ACPI
+int __mp_register_ioapic(int id, u32 address, u32 gsi_base, bool hot);
 extern void mp_register_ioapic(int id, u32 address, u32 gsi_base);
 extern void mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger,
 				   u32 gsi);
arch/x86/kernel/apic/io_apic.c +53 -15

119 lines not on this page · raw message

Signature · 1 line
1.8.1.4
author
#24 lore raw

PATCH v4 22/28 x86, irq: Add mp_unregister_ioapic to handle hot-remove ioapic

In reply to Yinghai Lu

It will free ioapic related irq_desc and also clear allocated_irqs bits.

Cc Joerg Roedel <[email protected]>
Cc Konrad Rzeszutek Wilk <[email protected]>
Cc Sebastian Andrzej Siewior <[email protected]>
---
 arch/x86/include/asm/mpspec.h  |  1 +
 arch/x86/kernel/apic/io_apic.c | 44 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 45 insertions(+)
arch/x86/include/asm/mpspec.h +1 -0
index 13cf60c..49f6ecc 100644
@@ -97,6 +97,7 @@ static inline void early_reserve_e820_mpc_new(void) { }
 void generic_processor_info(int apicid, int version);
 #ifdef CONFIG_ACPI
 int __mp_register_ioapic(int id, u32 address, u32 gsi_base, bool hot);
+int mp_unregister_ioapic(u32 gsi_base);
 extern void mp_register_ioapic(int id, u32 address, u32 gsi_base);
 extern void mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger,
 				   u32 gsi);
arch/x86/kernel/apic/io_apic.c +44 -0

62 lines not on this page · raw message

Signature · 1 line
1.8.1.4
author
#25 lore raw

PATCH v4 23/28 x86, ioapic: Find usable ioapic id for 64bit.

In reply to Yinghai Lu

Checking the id in register, if that is duplicated, will pick one and update id register.

Cc Joerg Roedel <[email protected]>
Cc Konrad Rzeszutek Wilk <[email protected]>
Cc Sebastian Andrzej Siewior <[email protected]>
---
 arch/x86/kernel/apic/io_apic.c | 38 +++++++++++++++++++++++++++++++++-----
 1 file changed, 33 insertions(+), 5 deletions(-)
arch/x86/kernel/apic/io_apic.c +33 -5
index a75e9d8..fb9bf06 100644
@@ -3652,19 +3652,22 @@ 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 __init io_apic_unique_id(int idx, u8 id)
 {
 	if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) &&
 	    !APIC_XAPIC(apic_version[boot_cpu_physical_apicid]))
-		return io_apic_get_unique_id(nr_ioapics, id);
+		return io_apic_get_unique_id(idx, id);
 	else
 		return id;
 }
 #else
-static u8 __init io_apic_unique_id(u8 id)
+static u8 io_apic_unique_id(int idx, u8 id)
 {
 	int i;
+	u8 new_id;
+	unsigned long flags;
 	DECLARE_BITMAP(used, 256);
+	union IO_APIC_reg_00 reg_00;
 
 	bitmap_zero(used, 256);
 	for_each_ioapic(i)
@@ -3672,7 +3675,32 @@ static u8 __init io_apic_unique_id(u8 id)
 
 	if (!test_bit(id, used))
 		return id;
-	return find_first_zero_bit(used, 256);
+
+	/* check register at first */
+	raw_spin_lock_irqsave(&ioapic_lock, flags);
+	reg_00.raw = io_apic_read(idx, 0);
+	raw_spin_unlock_irqrestore(&ioapic_lock, flags);
+	new_id = reg_00.bits.ID;
+	if (!test_bit(new_id, used)) {
+		apic_printk(APIC_VERBOSE, KERN_INFO
+			"IOAPIC[%d]: Using reg apic_id %d instead of %d\n",
+			 idx, new_id, id);
+		return new_id;
+	}
+
+	new_id = find_first_zero_bit(used, 256);
+	reg_00.bits.ID = new_id;
+	raw_spin_lock_irqsave(&ioapic_lock, flags);
+	io_apic_write(idx, 0, reg_00.raw);
+	reg_00.raw = io_apic_read(idx, 0);
+	raw_spin_unlock_irqrestore(&ioapic_lock, flags);
+
+	/* Sanity check */
+	if (reg_00.bits.ID != new_id)
+		pr_warn("IOAPIC[%d]: Unable to change apic_id to %d!\n",
+			idx, new_id);
+
+	return new_id;
 }
 #endif
 
@@ -3947,7 +3975,7 @@ int __mp_register_ioapic(int id, u32 address, u32 gsi_base, bool hotadd)
 	if (bad_ioapic_register(idx))
 		goto clear_out;
 
-	ioapics[idx].mp_config.apicid = io_apic_unique_id(id);
+	ioapics[idx].mp_config.apicid = io_apic_unique_id(idx, id);
 	ioapics[idx].mp_config.apicver = io_apic_get_version(idx);
 
 	/*
Signature · 1 line
1.8.1.4
author
#26 lore raw

PATCH v4 24/28 x86: Move declaration for mp_register_ioapic()

In reply to Yinghai Lu

Address compiling problem that Fengguang report.

---
 arch/x86/include/asm/mpspec.h | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)
arch/x86/include/asm/mpspec.h +18 -1
index 49f6ecc..a57f113 100644
@@ -95,10 +95,27 @@ static inline void early_reserve_e820_mpc_new(void) { }
 #endif
 
 void generic_processor_info(int apicid, int version);
-#ifdef CONFIG_ACPI
+
+#ifdef CONFIG_X86_IO_APIC
 int __mp_register_ioapic(int id, u32 address, u32 gsi_base, bool hot);
 int mp_unregister_ioapic(u32 gsi_base);
 extern void mp_register_ioapic(int id, u32 address, u32 gsi_base);
+#else
+static inline int __mp_register_ioapic(int id, u32 address, u32 gsi_base,
+					 bool hot)
+{
+	return 0;
+}
+static inline int mp_unregister_ioapic(u32 gsi_base)
+{
+	return 0;
+}
+static inline void mp_register_ioapic(int id, u32 address, u32 gsi_base)
+{
+}
+#endif
+
+#ifdef CONFIG_ACPI
 extern void mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger,
 				   u32 gsi);
 extern void mp_config_acpi_legacy_irqs(void);
Signature · 1 line
1.8.1.4
author
#27 lore raw

PATCH v4 25/28 PCI, x86: Make ioapic hotplug support built-in

In reply to Yinghai Lu

ioapic hotplug should be built-in like pci root bus hotplug.

Also need to make it depends on X86_IO_APIC.

---
 drivers/pci/Kconfig  | 3 ++-
 drivers/pci/ioapic.c | 6 +++++-
 2 files changed, 7 insertions(+), 2 deletions(-)
drivers/pci/Kconfig +2 -1
index 81944fb..6c9ede2 100644
@@ -109,9 +109,10 @@ config PCI_PASID
 	  If unsure, say N.
 
 config PCI_IOAPIC
-	tristate "PCI IO-APIC hotplug support" if X86
+	bool "PCI IO-APIC hotplug support" if X86
 	depends on PCI
 	depends on ACPI
+	depends on X86_IO_APIC
 	default !X86
 
 config PCI_LABEL
drivers/pci/ioapic.c +5 -1
index 1b90579..7d6b157 100644
@@ -113,6 +113,10 @@ static struct pci_driver ioapic_driver = {
 	.remove		= ioapic_remove,
 };
 
-module_pci_driver(ioapic_driver);
+static int __init ioapic_init(void)
+{
+	return pci_register_driver(&ioapic_driver);
+}
+module_init(ioapic_init);
 
 MODULE_LICENSE("GPL");
Signature · 1 line
1.8.1.4
maintainer
#28 lore raw

Re: [PATCH v4 25/28] PCI, x86: Make ioapic hotplug support built-in

Quoted 5 lines · Yinghai Lu

ioapic hotplug should be built-in like pci root bus hotplug.

Also need to make it depends on X86_IO_APIC.

Hi Yinghai,

What's the status of these? It looks like the last three or four could go via my PCI tree, but I don't know whether they depend on the earlier patches. If they could be applied separately, I could merge them and we could make *some* progress.

Also, it looks like you planned some rework related to _UID and resource parsing, so I've been waiting for that to show up before doing much more.

Bjorn

Quoted 40 lines
---
 drivers/pci/Kconfig  | 3 ++-
 drivers/pci/ioapic.c | 6 +++++-
 2 files changed, 7 insertions(+), 2 deletions(-)
drivers/pci/Kconfig +2 -1
index 81944fb..6c9ede2 100644
@@ -109,9 +109,10 @@ config PCI_PASID
 	  If unsure, say N.
 
 config PCI_IOAPIC
-	tristate "PCI IO-APIC hotplug support" if X86
+	bool "PCI IO-APIC hotplug support" if X86
 	depends on PCI
 	depends on ACPI
+	depends on X86_IO_APIC
 	default !X86
 
 config PCI_LABEL
drivers/pci/ioapic.c +5 -1
index 1b90579..7d6b157 100644
@@ -113,6 +113,10 @@ static struct pci_driver ioapic_driver = {
 	.remove		= ioapic_remove,
 };
 
-module_pci_driver(ioapic_driver);
+static int __init ioapic_init(void)
+{
+	return pci_register_driver(&ioapic_driver);
+}
+module_init(ioapic_init);
 
 MODULE_LICENSE("GPL");
Signature · 1 line
1.8.1.4
author
#29 lore raw

Re: [PATCH v4 25/28] PCI, x86: Make ioapic hotplug support built-in

Quoted 5 lines · Bjorn Helgaas
Quoted 4 lines · Yinghai Lu

ioapic hotplug should be built-in like pci root bus hotplug.

Also need to make it depends on X86_IO_APIC.

Quoted 8 lines
Quoted 1 line

Hi Yinghai,

What's the status of these? It looks like the last three or four could go via my PCI tree, but I don't know whether they depend on the earlier patches. If they could be applied separately, I could merge them and we could make *some* progress.

they are rely on other patches.

would be better if you give them ack, and let them via tip/x86/irq etc.

or in two parts: after first part go to upstream via tip, and we can push left pci related via pci tree.

Quoted 4 lines

Also, it looks like you planned some rework related to _UID and resource parsing, so I've been waiting for that to show up before doing much more.

yes, I have that ready. will post them shortly.

Thanks

Yinghai

author
#30 lore raw

PATCH v4 26/28 PCI, x86, ACPI: Link acpi ioapic register to ioapic

In reply to Yinghai Lu

During ioapic hotplug, acpi_register_ioapic will be called. Now for x86, that function is blank.
Fill that will update __mp_register_ioapic to use those ioapic.

---
 arch/x86/kernel/acpi/boot.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)
arch/x86/kernel/acpi/boot.c +6 -4
index 5be15d1..4a5336d 100644
@@ -707,16 +707,18 @@ EXPORT_SYMBOL(acpi_unmap_lsapic);
 
 int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base)
 {
-	/* TBD */
-	return -EINVAL;
+	unsigned long long id = 0;
+
+	acpi_evaluate_integer(handle, "_UID", NULL, &id);
+
+	return	__mp_register_ioapic(id, phys_addr, gsi_base, true);
 }
 
 EXPORT_SYMBOL(acpi_register_ioapic);
 
 int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base)
 {
-	/* TBD */
-	return -EINVAL;
+	return mp_unregister_ioapic(gsi_base);
 }
 
 EXPORT_SYMBOL(acpi_unregister_ioapic);
Signature · 1 line
1.8.1.4
#31 lore raw

Re: [PATCH v4 26/28] PCI, x86, ACPI: Link acpi ioapic register to ioapic

Quoted 14 lines · Yinghai Lu

During ioapic hotplug, acpi_register_ioapic will be called. Now for x86, that function is blank.
Fill that will update __mp_register_ioapic to use those ioapic.

---
 arch/x86/kernel/acpi/boot.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)
arch/x86/kernel/acpi/boot.c +0 -0
index 5be15d1..4a5336d 100644

arch/x86/kernel/acpi/boot.c EXPORT_SYMBOL(acpi_unmap_lsapic); · line 712

Quoted 8 lines
arch/x86/kernel/acpi/boot.c +3 -2
@@ -707,16 +707,18 @@ EXPORT_SYMBOL(acpi_unmap_lsapic);
 
 int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base)
 {
-	/* TBD */
-	return -EINVAL;
+	unsigned long long id = 0;
+
+	acpi_evaluate_integer(handle, "_UID", NULL, &id);

We cannot assume that "_UID" is an integer. "_UID" can be either an integer or a string. Need to consider the case when it is a string.

Thanks
Rui

Quoted 23 lines
arch/x86/kernel/acpi/boot.c +3 -3
+
+	return	__mp_register_ioapic(id, phys_addr, gsi_base, true);
 }
 
 EXPORT_SYMBOL(acpi_register_ioapic);
 
 int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base)
 {
-	/* TBD */
-	return -EINVAL;
+	return mp_unregister_ioapic(gsi_base);
 }
 
 EXPORT_SYMBOL(acpi_unregister_ioapic);
--

1.8.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

author
#32 lore raw

Re: [PATCH v4 26/28] PCI, x86, ACPI: Link acpi ioapic register to ioapic

Quoted 16 lines · rui wang
Quoted 15 lines · Yinghai Lu

During ioapic hotplug, acpi_register_ioapic will be called. Now for x86, that function is blank.
Fill that will update __mp_register_ioapic to use those ioapic.

---
 arch/x86/kernel/acpi/boot.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)
arch/x86/kernel/acpi/boot.c +0 -0
index 5be15d1..4a5336d 100644
@@ -707,16 +707,18 @@ EXPORT_SYMBOL(acpi_unmap_lsapic);
 
Quoted 10 lines

arch/x86/kernel/acpi/boot.c EXPORT_SYMBOL(acpi_unmap_lsapic); · line 712

Quoted 7 lines
arch/x86/kernel/acpi/boot.c +3 -2
 int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base)
 {
-     /* TBD */
-     return -EINVAL;
+     unsigned long long id = 0;
+
+     acpi_evaluate_integer(handle, "_UID", NULL, &id);

We cannot assume that "_UID" is an integer. "_UID" can be either an integer or a string. Need to consider the case when it is a string.

Yes.

But do you have test case for ioapic that _UID is not integer?

Thanks

Yinghai

#33 lore raw

Re: [PATCH v4 26/28] PCI, x86, ACPI: Link acpi ioapic register to ioapic

Quoted 29 lines · Yinghai Lu
Quoted 16 lines · rui wang
Quoted 15 lines · Yinghai Lu

During ioapic hotplug, acpi_register_ioapic will be called. Now for x86, that function is blank.
Fill that will update __mp_register_ioapic to use those ioapic.

---
 arch/x86/kernel/acpi/boot.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)
arch/x86/kernel/acpi/boot.c +0 -0
index 5be15d1..4a5336d 100644
@@ -707,16 +707,18 @@ EXPORT_SYMBOL(acpi_unmap_lsapic);
 
Quoted 11 lines

arch/x86/kernel/acpi/boot.c EXPORT_SYMBOL(acpi_unmap_lsapic); · line 712

Quoted 8 lines
arch/x86/kernel/acpi/boot.c +3 -2
 int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32
 gsi_base)
 {
-     /* TBD */
-     return -EINVAL;
+     unsigned long long id = 0;
+
+     acpi_evaluate_integer(handle, "_UID", NULL, &id);

We cannot assume that "_UID" is an integer. "_UID" can be either an integer or a string. Need to consider the case when it is a string.

Quoted 4 lines

Yes.

But do you have test case for ioapic that _UID is not integer?

Yes I have an IOAPIC with an _UID of:

        Name (_UID, "IOAPIC01")  // _UID: Unique ID

It's a bit challenge how you'll conjure unique identifiers from both integers and strings. If you have a new patch I can help try it out.

Thanks
Rui

Quoted 4 lines

Thanks

Yinghai

author
#34 lore raw

Re: [PATCH v4 26/28] PCI, x86, ACPI: Link acpi ioapic register to ioapic

Quoted 35 lines · rui wang
Quoted 29 lines · Yinghai Lu
Quoted 16 lines · rui wang
Quoted 15 lines · Yinghai Lu

During ioapic hotplug, acpi_register_ioapic will be called. Now for x86, that function is blank.
Fill that will update __mp_register_ioapic to use those ioapic.

---
 arch/x86/kernel/acpi/boot.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)
arch/x86/kernel/acpi/boot.c +0 -0
index 5be15d1..4a5336d 100644
@@ -707,16 +707,18 @@ EXPORT_SYMBOL(acpi_unmap_lsapic);
 
Quoted 11 lines

arch/x86/kernel/acpi/boot.c EXPORT_SYMBOL(acpi_unmap_lsapic); · line 712

Quoted 8 lines
arch/x86/kernel/acpi/boot.c +3 -2
 int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32
 gsi_base)
 {
-     /* TBD */
-     return -EINVAL;
+     unsigned long long id = 0;
+
+     acpi_evaluate_integer(handle, "_UID", NULL, &id);

We cannot assume that "_UID" is an integer. "_UID" can be either an integer or a string. Need to consider the case when it is a string.

Quoted 4 lines

Yes.

But do you have test case for ioapic that _UID is not integer?

Quoted 6 lines

Yes I have an IOAPIC with an _UID of:

        Name (_UID, "IOAPIC01")  // _UID: Unique ID

It's a bit challenge how you'll conjure unique identifiers from both integers and strings. If you have a new patch I can help try it out.

Then do you have _MAT with that ioapic device or else?

need to find the _MAT entry with GSM matching to find out ioapic id.

Thanks

Yinghai

#35 lore raw

Re: [PATCH v4 26/28] PCI, x86, ACPI: Link acpi ioapic register to ioapic

Quoted 38 lines · Yinghai Lu
Quoted 37 lines · rui wang
Quoted 29 lines · Yinghai Lu
Quoted 16 lines · rui wang
Quoted 15 lines · Yinghai Lu

During ioapic hotplug, acpi_register_ioapic will be called. Now for x86, that function is blank.
Fill that will update __mp_register_ioapic to use those ioapic.

---
 arch/x86/kernel/acpi/boot.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)
arch/x86/kernel/acpi/boot.c +0 -0
index 5be15d1..4a5336d 100644
@@ -707,16 +707,18 @@ EXPORT_SYMBOL(acpi_unmap_lsapic);
 
Quoted 11 lines

arch/x86/kernel/acpi/boot.c EXPORT_SYMBOL(acpi_unmap_lsapic); · line 712

Quoted 8 lines
arch/x86/kernel/acpi/boot.c +3 -2
 int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32
 gsi_base)
 {
-     /* TBD */
-     return -EINVAL;
+     unsigned long long id = 0;
+
+     acpi_evaluate_integer(handle, "_UID", NULL, &id);

We cannot assume that "_UID" is an integer. "_UID" can be either an integer or a string. Need to consider the case when it is a string.

Quoted 4 lines

Yes.

But do you have test case for ioapic that _UID is not integer?

Yes I have an IOAPIC with an _UID of:

Quoted 9 lines
Quoted 4 lines
        Name (_UID, "IOAPIC01")  // _UID: Unique ID

It's a bit challenge how you'll conjure unique identifiers from both integers and strings. If you have a new patch I can help try it out.

Then do you have _MAT with that ioapic device or else?

need to find the _MAT entry with GSM matching to find out ioapic id.

There's no _MAT for the IOAPICs. I only find _MAT for the LAPICs. But there's a static MADT in APIC.dsl which contains IOAPIC entries with ioapic ids.

Thanks
Rui

Quoted 5 lines

Thanks

Yinghai

author
#36 lore raw

Re: [PATCH v4 26/28] PCI, x86, ACPI: Link acpi ioapic register to ioapic

Quoted 4 lines · rui wang
Quoted 3 lines · Yinghai Lu
Quoted 2 lines

It's a bit challenge how you'll conjure unique identifiers from both integers and strings. If you have a new patch I can help try it out.

Quoted 8 lines
Quoted 4 lines

Then do you have _MAT with that ioapic device or else?

need to find the _MAT entry with GSM matching to find out ioapic id.

There's no _MAT for the IOAPICs. I only find _MAT for the LAPICs. But there's a static MADT in APIC.dsl which contains IOAPIC entries with ioapic ids.

ok, will change to check _MAT at first and fall back to MADT.

Yinghai

author
#37 lore raw

PATCH v4 27/28 PCI, x86, ACPI: Enable ioapic hotplug support with acpi host bridge.

In reply to Yinghai Lu

We need to have ioapic setup before normal pci drivers. otherwise other pci driver can not setup irq.

So we should not treat them as normal pci devices.
Also we will need to support ioapic hotplug without pci device around.

We need to call ioapic add/remove during host-bridge add/remove.

---
 drivers/acpi/pci_root.c  |   4 ++
 drivers/pci/ioapic.c     | 147 ++++++++++++++++++++++++++++++-----------------
 include/linux/pci-acpi.h |   8 +++
 3 files changed, 106 insertions(+), 53 deletions(-)
drivers/acpi/pci_root.c +4 -0
index 5917839..7577175 100644
@@ -532,6 +532,8 @@ static int acpi_pci_root_add(struct acpi_device *device,
 		pci_enable_bridges(root->bus);
 	}
 
+	acpi_pci_ioapic_add(root);
+
 	pci_bus_add_devices(root->bus);
 	return 1;
 
@@ -546,6 +548,8 @@ static void acpi_pci_root_remove(struct acpi_device *device)
 
 	pci_stop_root_bus(root->bus);
 
+	acpi_pci_ioapic_remove(root);
+
 	device_set_run_wake(root->bus->bridge, false);
 	pci_acpi_remove_bus_pm_notifier(device);
 
drivers/pci/ioapic.c +94 -53

195 lines not on this page · raw message

include/linux/pci-acpi.h +8 -0
index 1704479..b2a2ced 100644
@@ -69,6 +69,14 @@ static inline void acpiphp_remove_slots(struct pci_bus *bus) { }
 static inline void acpiphp_check_host_bridge(acpi_handle handle) { }
 #endif
 
+#ifdef CONFIG_PCI_IOAPIC
+void acpi_pci_ioapic_add(struct acpi_pci_root *root);
+void acpi_pci_ioapic_remove(struct acpi_pci_root *root);
+#else
+static inline void acpi_pci_ioapic_add(struct acpi_pci_root *root) { }
+static inline void acpi_pci_ioapic_remove(struct acpi_pci_root *root) { }
+#endif
+
 #else	/* CONFIG_ACPI */
 static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
 static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
Signature · 1 line
1.8.1.4
#38 lore raw

Re: [PATCH v4 27/28] PCI, x86, ACPI: Enable ioapic hotplug support with acpi host bridge.

Quoted 122 lines · Yinghai Lu

We need to have ioapic setup before normal pci drivers. otherwise other pci driver can not setup irq.

So we should not treat them as normal pci devices.
Also we will need to support ioapic hotplug without pci device around.

We need to call ioapic add/remove during host-bridge add/remove.

---
 drivers/acpi/pci_root.c  |   4 ++
 drivers/pci/ioapic.c     | 147
++++++++++++++++++++++++++++++-----------------
 include/linux/pci-acpi.h |   8 +++
 3 files changed, 106 insertions(+), 53 deletions(-)
drivers/acpi/pci_root.c +4 -0
index 5917839..7577175 100644
@@ -532,6 +532,8 @@ static int acpi_pci_root_add(struct acpi_device
 *device,
 		pci_enable_bridges(root->bus);
 	}
 
+	acpi_pci_ioapic_add(root);
+
 	pci_bus_add_devices(root->bus);
 	return 1;
@@ -546,6 +548,8 @@ static void acpi_pci_root_remove(struct acpi_device
 *device)
 
 	pci_stop_root_bus(root->bus);
 
+	acpi_pci_ioapic_remove(root);
+
 	device_set_run_wake(root->bus->bridge, false);
 	pci_acpi_remove_bus_pm_notifier(device);
drivers/pci/ioapic.c +27 -26
index 7d6b157..60351b2 100644
@@ -22,101 +22,142 @@
 #include <linux/slab.h>
 #include <acpi/acpi_bus.h>
 
-struct ioapic {
-	acpi_handle	handle;
+struct acpi_pci_ioapic {
+	acpi_handle	root_handle;
 	u32		gsi_base;
+	struct pci_dev *pdev;
+	struct list_head list;
 };
 
-static int ioapic_probe(struct pci_dev *dev, const struct pci_device_id
 *ent)
+static LIST_HEAD(ioapic_list);
+static DEFINE_MUTEX(ioapic_list_lock);
+
+static void handle_ioapic_add(acpi_handle handle, struct pci_dev **pdev,
+				 u32 *pgsi_base)
 {
-	acpi_handle handle;
 	acpi_status status;
 	unsigned long long gsb;
-	struct ioapic *ioapic;
+	struct pci_dev *dev;
+	u32 gsi_base;
 	int ret;
 	char *type;
-	struct resource *res;
+	struct resource r;
+	struct resource *res = &r;
+	char objname[64];
+	struct acpi_buffer buffer = {sizeof(objname), objname};
 
-	handle = DEVICE_ACPI_HANDLE(&dev->dev);
-	if (!handle)
-		return -EINVAL;
+	*pdev = NULL;
+	*pgsi_base = 0;
 
 	status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsb);
-	if (ACPI_FAILURE(status))
-		return -EINVAL;
-
-	/*
-	 * The previous code in acpiphp evaluated _MAT if _GSB failed, but
-	 * ACPI spec 4.0 sec 6.2.2 requires _GSB for hot-pluggable I/O APICs.
-	 */
+	if (ACPI_FAILURE(status) || !gsb)
+		return;
 
-	ioapic = kzalloc(sizeof(*ioapic), GFP_KERNEL);
-	if (!ioapic)
-		return -ENOMEM;
+	dev = acpi_get_pci_dev(handle);
+	if (!dev)
+		return;
 
-	ioapic->handle = handle;
-	ioapic->gsi_base = (u32) gsb;
+	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
 
-	if (dev->class == PCI_CLASS_SYSTEM_PIC_IOAPIC)
-		type = "IOAPIC";
-	else
-		type = "IOxAPIC";
+	gsi_base = gsb;
+	type = "IOxAPIC";
 
 	ret = pci_enable_device(dev);
 	if (ret < 0)
-		goto exit_free;
+		goto exit_put;
 
 	pci_set_master(dev);
 
+	if (dev->class == PCI_CLASS_SYSTEM_PIC_IOAPIC)

drivers/pci/ioapic.c line 81

Quoted 10 lines
drivers/pci/ioapic.c +4 -1
+		type = "IOAPIC";
+
 	if (pci_request_region(dev, 0, type))
 		goto exit_disable;
 
 	res = &dev->resource[0];
-	if (acpi_register_ioapic(ioapic->handle, res->start, ioapic->gsi_base))
+
+	if (acpi_register_ioapic(handle, res->start, gsi_base))
 		goto exit_release;

Here acpi_register_ioapic() fails for IOAPICs already described by the static MADT. So they won't be added to the ioapic_list. Subsequent hot-removal will also fail because they're not found by acpi_pci_ioapic_remove() on the ioapic_list.

Here's what I used to fix it:

Quoted 1 line

From 2fff3297b4c71c88d92b04ba9ad0a8931b3e99b8 Mon Sep 17 00:00:00 2001

From: Rui Wang <[email protected]>
Date: Tue, 27 Aug 2013 11:23:43 -0400
Subject: [PATCH] Hotadd of IOAPICs described in static MADT

For IOAPICs described in static MADT, we already called __mp_register_ioapic() in arch_early_irq_init(). During boot PCI root hotadd will call it again and will find it already registered, thus register_ioapic() won't add it to the ioapic_list. Subsequent hot-removal will also fail because it is not found on the
ioapic_list.

---
 arch/x86/kernel/apic/io_apic.c |    4 +++-
 drivers/pci/ioapic.c           |    3 ++-
 2 files changed, 5 insertions(+), 2 deletions(-)
arch/x86/kernel/apic/io_apic.c +0 -0
index fb9bf06..15ab9f1 100644
@@ -3956,8 +3956,10 @@ int __mp_register_ioapic(int id, u32 address,

u32 gsi_base, bool hotadd)

        /* already registered ? */
        idx = __mp_find_ioapic(gsi_base);
-       if (idx >= 0)
+       if (idx >= 0) {
+               ret = -EEXIST;
                goto out;

+ }

        idx = find_first_zero_bit(ioapics_mask, MAX_IO_APICS);
        if (idx >= MAX_IO_APICS) {
drivers/pci/ioapic.c +0 -0
index 41f7c69..83b002b 100644
@@ -126,7 +126,8 @@ static void handle_ioapic_add(acpi_handle handle,

struct pci_dev **pdev,

                }
        }
-       if (acpi_register_ioapic(handle, res->start, gsi_base)) {
+       ret = acpi_register_ioapic(handle, res->start, gsi_base);
+       if (ret && ret != -EEXIST) {
                if (dev)
                        goto exit_release;
                return;
Signature · 5 lines
1.7.3.4


Thanks
Rui
Quoted 138 lines
drivers/pci/ioapic.c +63 -26
-	pci_set_drvdata(dev, ioapic);
-	dev_info(&dev->dev, "%s at %pR, GSI %u\n", type, res, ioapic->gsi_base);
-	return 0;
+	pr_info("%s %s %s at %pR, GSI %u\n",
+		dev_name(&dev->dev), objname, type,
+		res, gsi_base);
+
+	*pdev = dev;
+	*pgsi_base = gsi_base;
+	return;
 
 exit_release:
 	pci_release_region(dev, 0);
 exit_disable:
 	pci_disable_device(dev);
-exit_free:
-	kfree(ioapic);
-	return -ENODEV;
+exit_put:
+	pci_dev_put(dev);
 }
 
-static void ioapic_remove(struct pci_dev *dev)
+static void handle_ioapic_remove(acpi_handle handle, struct pci_dev *dev,
+				  u32 gsi_base)
 {
-	struct ioapic *ioapic = pci_get_drvdata(dev);
+	acpi_unregister_ioapic(handle, gsi_base);
 
-	acpi_unregister_ioapic(ioapic->handle, ioapic->gsi_base);
 	pci_release_region(dev, 0);
 	pci_disable_device(dev);
-	kfree(ioapic);
+	pci_dev_put(dev);
 }
 
+static acpi_status register_ioapic(acpi_handle handle, u32 lvl,
+					void *context, void **rv)
+{
+	acpi_handle root_handle = context;
+	struct pci_dev *pdev;
+	u32 gsi_base;
+	struct acpi_pci_ioapic *ioapic;
 
-static DEFINE_PCI_DEVICE_TABLE(ioapic_devices) = {
-	{ PCI_DEVICE_CLASS(PCI_CLASS_SYSTEM_PIC_IOAPIC, ~0) },
-	{ PCI_DEVICE_CLASS(PCI_CLASS_SYSTEM_PIC_IOXAPIC, ~0) },
-	{ }
-};
-MODULE_DEVICE_TABLE(pci, ioapic_devices);
+	handle_ioapic_add(handle, &pdev, &gsi_base);
+	if (!gsi_base)
+		return AE_OK;
 
-static struct pci_driver ioapic_driver = {
-	.name		= "ioapic",
-	.id_table	= ioapic_devices,
-	.probe		= ioapic_probe,
-	.remove		= ioapic_remove,
-};
+	ioapic = kzalloc(sizeof(*ioapic), GFP_KERNEL);
+	if (!ioapic) {
+		pr_err("%s: cannot allocate memory\n", __func__);
+		handle_ioapic_remove(root_handle, pdev, gsi_base);
+		return AE_OK;
+	}
+	ioapic->root_handle = root_handle;
+	ioapic->pdev = pdev;
+	ioapic->gsi_base = gsi_base;
+
+	mutex_lock(&ioapic_list_lock);
+	list_add(&ioapic->list, &ioapic_list);
+	mutex_unlock(&ioapic_list_lock);
+
+	return AE_OK;
+}
 
-static int __init ioapic_init(void)
+void acpi_pci_ioapic_add(struct acpi_pci_root *root)
 {
-	return pci_register_driver(&ioapic_driver);
+	acpi_status status;
+
+	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, root->device->handle,
+				     (u32)1, register_ioapic, NULL,
+				     root->device->handle,
+				     NULL);
+	if (ACPI_FAILURE(status))
+		pr_err("%s: register_ioapic failure - %d", __func__, status);
 }
-module_init(ioapic_init);
 
-MODULE_LICENSE("GPL");
+void acpi_pci_ioapic_remove(struct acpi_pci_root *root)
+{
+	struct acpi_pci_ioapic *ioapic, *tmp;
+
+	mutex_lock(&ioapic_list_lock);
+	list_for_each_entry_safe(ioapic, tmp, &ioapic_list, list) {
+		if (root->device->handle != ioapic->root_handle)
+			continue;
+		list_del(&ioapic->list);
+		handle_ioapic_remove(ioapic->root_handle, ioapic->pdev,
+					ioapic->gsi_base);
+		kfree(ioapic);
+	}
+	mutex_unlock(&ioapic_list_lock);
+}
include/linux/pci-acpi.h +8 -0
index 1704479..b2a2ced 100644
@@ -69,6 +69,14 @@ static inline void acpiphp_remove_slots(struct pci_bus
 *bus) { }
 static inline void acpiphp_check_host_bridge(acpi_handle handle) { }
 #endif
 
+#ifdef CONFIG_PCI_IOAPIC
+void acpi_pci_ioapic_add(struct acpi_pci_root *root);
+void acpi_pci_ioapic_remove(struct acpi_pci_root *root);
+#else
+static inline void acpi_pci_ioapic_add(struct acpi_pci_root *root) { }
+static inline void acpi_pci_ioapic_remove(struct acpi_pci_root *root) { }
+#endif
+
 #else	/* CONFIG_ACPI */
 static inline void acpi_pci_add_bus(struct pci_bus *bus) { }

static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
--
1.8.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

#39 lore raw

Re: [PATCH v4 27/28] PCI, x86, ACPI: Enable ioapic hotplug support with acpi host bridge.

FWIW, I'm using my "I/O Hook" (http://lwn.net/Articles/561359/) as a tool to test yinghai's IOAPIC patchset. It can be used to test any kind of hotplug.

For people who don't yet have full hardware support and want to test the hotplug of IOAPIC, CPU, Memory, IOH, PCIe root, etc., it is an ideal tool. The latest version (v2) is at:
http://lwn.net/Articles/561779/

Thanks
Rui

author
#40 lore raw

Re: [PATCH v4 27/28] PCI, x86, ACPI: Enable ioapic hotplug support with acpi host bridge.

In reply to rui wang
Quoted 191 lines · rui wang
Quoted 122 lines · Yinghai Lu

We need to have ioapic setup before normal pci drivers. otherwise other pci driver can not setup irq.

So we should not treat them as normal pci devices.
Also we will need to support ioapic hotplug without pci device around.

We need to call ioapic add/remove during host-bridge add/remove.

---
 drivers/acpi/pci_root.c  |   4 ++
 drivers/pci/ioapic.c     | 147
++++++++++++++++++++++++++++++-----------------
 include/linux/pci-acpi.h |   8 +++
 3 files changed, 106 insertions(+), 53 deletions(-)
drivers/acpi/pci_root.c +4 -0
index 5917839..7577175 100644
@@ -532,6 +532,8 @@ static int acpi_pci_root_add(struct acpi_device
 *device,
              pci_enable_bridges(root->bus);
      }
 
+     acpi_pci_ioapic_add(root);
+
      pci_bus_add_devices(root->bus);
      return 1;
@@ -546,6 +548,8 @@ static void acpi_pci_root_remove(struct acpi_device
 *device)
 
      pci_stop_root_bus(root->bus);
 
+     acpi_pci_ioapic_remove(root);
+
      device_set_run_wake(root->bus->bridge, false);
      pci_acpi_remove_bus_pm_notifier(device);
drivers/pci/ioapic.c +27 -26
index 7d6b157..60351b2 100644
@@ -22,101 +22,142 @@
 #include <linux/slab.h>
 #include <acpi/acpi_bus.h>
 
-struct ioapic {
-     acpi_handle     handle;
+struct acpi_pci_ioapic {
+     acpi_handle     root_handle;
      u32             gsi_base;
+     struct pci_dev *pdev;
+     struct list_head list;
 };
 
-static int ioapic_probe(struct pci_dev *dev, const struct pci_device_id
 *ent)
+static LIST_HEAD(ioapic_list);
+static DEFINE_MUTEX(ioapic_list_lock);
+
+static void handle_ioapic_add(acpi_handle handle, struct pci_dev **pdev,
+                              u32 *pgsi_base)
 {
-     acpi_handle handle;
      acpi_status status;
      unsigned long long gsb;
-     struct ioapic *ioapic;
+     struct pci_dev *dev;
+     u32 gsi_base;
      int ret;
      char *type;
-     struct resource *res;
+     struct resource r;
+     struct resource *res = &r;
+     char objname[64];
+     struct acpi_buffer buffer = {sizeof(objname), objname};
 
-     handle = DEVICE_ACPI_HANDLE(&dev->dev);
-     if (!handle)
-             return -EINVAL;
+     *pdev = NULL;
+     *pgsi_base = 0;
 
      status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsb);
-     if (ACPI_FAILURE(status))
-             return -EINVAL;
-
-     /*
-      * The previous code in acpiphp evaluated _MAT if _GSB failed, but
-      * ACPI spec 4.0 sec 6.2.2 requires _GSB for hot-pluggable I/O APICs.
-      */
+     if (ACPI_FAILURE(status) || !gsb)
+             return;
 
-     ioapic = kzalloc(sizeof(*ioapic), GFP_KERNEL);
-     if (!ioapic)
-             return -ENOMEM;
+     dev = acpi_get_pci_dev(handle);
+     if (!dev)
+             return;
 
-     ioapic->handle = handle;
-     ioapic->gsi_base = (u32) gsb;
+     acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
 
-     if (dev->class == PCI_CLASS_SYSTEM_PIC_IOAPIC)
-             type = "IOAPIC";
-     else
-             type = "IOxAPIC";
+     gsi_base = gsb;
+     type = "IOxAPIC";
 
      ret = pci_enable_device(dev);
      if (ret < 0)
-             goto exit_free;
+             goto exit_put;
 
      pci_set_master(dev);
 
+     if (dev->class == PCI_CLASS_SYSTEM_PIC_IOAPIC)

drivers/pci/ioapic.c line 81

Quoted 10 lines
drivers/pci/ioapic.c +4 -1
+             type = "IOAPIC";
+
      if (pci_request_region(dev, 0, type))
              goto exit_disable;
 
      res = &dev->resource[0];
-     if (acpi_register_ioapic(ioapic->handle, res->start, ioapic->gsi_base))
+
+     if (acpi_register_ioapic(handle, res->start, gsi_base))
              goto exit_release;

Here acpi_register_ioapic() fails for IOAPICs already described by the static MADT. So they won't be added to the ioapic_list. Subsequent hot-removal will also fail because they're not found by acpi_pci_ioapic_remove() on the ioapic_list.

Here's what I used to fix it:

From 2fff3297b4c71c88d92b04ba9ad0a8931b3e99b8 Mon Sep 17 00:00:00 2001
From: Rui Wang <[email protected]>
Date: Tue, 27 Aug 2013 11:23:43 -0400
Subject: [PATCH] Hotadd of IOAPICs described in static MADT

For IOAPICs described in static MADT, we already called __mp_register_ioapic() in arch_early_irq_init(). During boot PCI root hotadd will call it again and will find it already registered, thus register_ioapic() won't add it to the ioapic_list. Subsequent hot-removal will also fail because it is not found on the
ioapic_list.

---
 arch/x86/kernel/apic/io_apic.c |    4 +++-
 drivers/pci/ioapic.c           |    3 ++-
 2 files changed, 5 insertions(+), 2 deletions(-)
arch/x86/kernel/apic/io_apic.c +3 -1
index fb9bf06..15ab9f1 100644
@@ -3956,8 +3956,10 @@ int __mp_register_ioapic(int id, u32 address,
 u32 gsi_base, bool hotadd)
 
        /* already registered ? */
        idx = __mp_find_ioapic(gsi_base);
-       if (idx >= 0)
+       if (idx >= 0) {
+               ret = -EEXIST;
                goto out;
+       }
 
        idx = find_first_zero_bit(ioapics_mask, MAX_IO_APICS);
        if (idx >= MAX_IO_APICS) {
drivers/pci/ioapic.c +2 -1
index 41f7c69..83b002b 100644
@@ -126,7 +126,8 @@ static void handle_ioapic_add(acpi_handle handle,
 struct pci_dev **pdev,
                }
        }
 
-       if (acpi_register_ioapic(handle, res->start, gsi_base)) {
+       ret = acpi_register_ioapic(handle, res->start, gsi_base);
+       if (ret && ret != -EEXIST) {
                if (dev)
                        goto exit_release;
                return;
Quoted 1 line

--

ok, will put it my series.

Thanks

Yinghai

#41 lore raw

Re: [PATCH v4 27/28] PCI, x86, ACPI: Enable ioapic hotplug support with acpi host bridge.

Quoted 193 lines · Yinghai Lu
Quoted 192 lines · rui wang
Quoted 132 lines · Yinghai Lu

We need to have ioapic setup before normal pci drivers. otherwise other pci driver can not setup irq.

So we should not treat them as normal pci devices.
Also we will need to support ioapic hotplug without pci device around.

We need to call ioapic add/remove during host-bridge add/remove.

---
 drivers/acpi/pci_root.c  |   4 ++
 drivers/pci/ioapic.c     | 147
++++++++++++++++++++++++++++++-----------------
 include/linux/pci-acpi.h |   8 +++
 3 files changed, 106 insertions(+), 53 deletions(-)
drivers/acpi/pci_root.c +4 -0
index 5917839..7577175 100644
@@ -532,6 +532,8 @@ static int acpi_pci_root_add(struct acpi_device
 *device,
              pci_enable_bridges(root->bus);
      }
 
+     acpi_pci_ioapic_add(root);
+
      pci_bus_add_devices(root->bus);
      return 1;
@@ -546,6 +548,8 @@ static void acpi_pci_root_remove(struct acpi_device
 *device)
 
      pci_stop_root_bus(root->bus);
 
+     acpi_pci_ioapic_remove(root);
+
      device_set_run_wake(root->bus->bridge, false);
      pci_acpi_remove_bus_pm_notifier(device);
drivers/pci/ioapic.c +17 -15
index 7d6b157..60351b2 100644
@@ -22,101 +22,142 @@
 #include <linux/slab.h>
 #include <acpi/acpi_bus.h>
 
-struct ioapic {
-     acpi_handle     handle;
+struct acpi_pci_ioapic {
+     acpi_handle     root_handle;
      u32             gsi_base;
+     struct pci_dev *pdev;
+     struct list_head list;
 };
 
-static int ioapic_probe(struct pci_dev *dev, const struct pci_device_id
 *ent)
+static LIST_HEAD(ioapic_list);
+static DEFINE_MUTEX(ioapic_list_lock);
+
+static void handle_ioapic_add(acpi_handle handle, struct pci_dev
 **pdev,
+                              u32 *pgsi_base)
 {
-     acpi_handle handle;
      acpi_status status;
      unsigned long long gsb;
-     struct ioapic *ioapic;
+     struct pci_dev *dev;
+     u32 gsi_base;
      int ret;
      char *type;
-     struct resource *res;
+     struct resource r;
+     struct resource *res = &r;
+     char objname[64];
+     struct acpi_buffer buffer = {sizeof(objname), objname};
 
-     handle = DEVICE_ACPI_HANDLE(&dev->dev);
-     if (!handle)
-             return -EINVAL;
+     *pdev = NULL;
+     *pgsi_base = 0;
 
      status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsb);
-     if (ACPI_FAILURE(status))
-             return -EINVAL;
-
-     /*
-      * The previous code in acpiphp evaluated _MAT if _GSB failed, but
-      * ACPI spec 4.0 sec 6.2.2 requires _GSB for hot-pluggable I/O

APICs.

drivers/pci/ioapic.c +12 -12
-      */
+     if (ACPI_FAILURE(status) || !gsb)
+             return;
 
-     ioapic = kzalloc(sizeof(*ioapic), GFP_KERNEL);
-     if (!ioapic)
-             return -ENOMEM;
+     dev = acpi_get_pci_dev(handle);
+     if (!dev)
+             return;
 
-     ioapic->handle = handle;
-     ioapic->gsi_base = (u32) gsb;
+     acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
 
-     if (dev->class == PCI_CLASS_SYSTEM_PIC_IOAPIC)
-             type = "IOAPIC";
-     else
-             type = "IOxAPIC";
+     gsi_base = gsb;
+     type = "IOxAPIC";
 
      ret = pci_enable_device(dev);
      if (ret < 0)
-             goto exit_free;
+             goto exit_put;
 
      pci_set_master(dev);
 
+     if (dev->class == PCI_CLASS_SYSTEM_PIC_IOAPIC)
+             type = "IOAPIC";
+
      if (pci_request_region(dev, 0, type))
              goto exit_disable;
 
      res = &dev->resource[0];
-     if (acpi_register_ioapic(ioapic->handle, res->start,

ioapic->gsi_base))

drivers/pci/ioapic.c

Quoted 3 lines
drivers/pci/ioapic.c +2 -0
+
+     if (acpi_register_ioapic(handle, res->start, gsi_base))
              goto exit_release;

Here acpi_register_ioapic() fails for IOAPICs already described by the static MADT. So they won't be added to the ioapic_list. Subsequent hot-removal will also fail because they're not found by acpi_pci_ioapic_remove() on the ioapic_list.

Here's what I used to fix it:

From 2fff3297b4c71c88d92b04ba9ad0a8931b3e99b8 Mon Sep 17 00:00:00 2001
From: Rui Wang <[email protected]>
Date: Tue, 27 Aug 2013 11:23:43 -0400
Subject: [PATCH] Hotadd of IOAPICs described in static MADT

For IOAPICs described in static MADT, we already called __mp_register_ioapic()
in arch_early_irq_init(). During boot PCI root hotadd will call it again and
will find it already registered, thus register_ioapic() won't add it to the
ioapic_list. Subsequent hot-removal will also fail because it is not found on the
ioapic_list.

---
 arch/x86/kernel/apic/io_apic.c |    4 +++-
 drivers/pci/ioapic.c           |    3 ++-
 2 files changed, 5 insertions(+), 2 deletions(-)
arch/x86/kernel/apic/io_apic.c +3 -1
index fb9bf06..15ab9f1 100644
@@ -3956,8 +3956,10 @@ int __mp_register_ioapic(int id, u32 address,
 u32 gsi_base, bool hotadd)
 
        /* already registered ? */
        idx = __mp_find_ioapic(gsi_base);
-       if (idx >= 0)
+       if (idx >= 0) {
+               ret = -EEXIST;
                goto out;
+       }
 
        idx = find_first_zero_bit(ioapics_mask, MAX_IO_APICS);
        if (idx >= MAX_IO_APICS) {
drivers/pci/ioapic.c +0 -0
index 41f7c69..83b002b 100644
@@ -126,7 +126,8 @@ static void handle_ioapic_add(acpi_handle handle,
 struct pci_dev **pdev,
                }
        }
 
Quoted 10 lines
Quoted 7 lines
drivers/pci/ioapic.c +2 -1
-       if (acpi_register_ioapic(handle, res->start, gsi_base)) {
+       ret = acpi_register_ioapic(handle, res->start, gsi_base);
+       if (ret && ret != -EEXIST) {
                if (dev)
                        goto exit_release;
                return;

--

ok, will put it my series.

That would be great. Thanks.

Rui

Quoted 4 lines

Thanks

Yinghai

#42 lore raw

Re: [PATCH v4 27/28] PCI, x86, ACPI: Enable ioapic hotplug support with acpi host bridge.

In reply to Yinghai Lu

drivers/acpi/pci_root.c static int acpi_pci_root_add(struct acpi_device *device, · line 533

Quoted 7 lines
drivers/acpi/pci_root.c +0 -0
index 5917839..7577175 100644
@@ -532,6 +532,8 @@ static int acpi_pci_root_add(struct acpi_device *device,
 		pci_enable_bridges(root->bus);
 	}

Hi Yinghai,
This like a mistake, pci_enable_bridges() should be called after hot added ioapic registered,
as the comments mention.

527 if (system_state != SYSTEM_BOOTING) {
528 pcibios_resource_survey_bus(root->bus);
529 pci_assign_unassigned_bus_resources(root->bus);
530
531 /* need to after hot-added ioapic is registered */ <--------------
532 pci_enable_bridges(root->bus);
533 }
534
535 acpi_pci_ioapic_add(root);

In my platform, some errors found like:

614.332730] mp_register_gsi: gsi 71

[  614.332733] ERROR: Unable to locate IOAPIC for GSI 71
[  614.332734] No IOAPIC for GSI 71
[  614.332736] ERROR: Unable to locate IOAPIC for GSI 71
[  614.332738] acpi_register_gsi: gsi 71, irq -1
[  614.332740] pci 0000:80:00.0: PCI INT A: failed to register GSI
[  614.332743] pci 0000:80:00.0: Error enabling bridge (-1), continuing
[  614.332857] mp_register_gsi: gsi 52
[  614.332859] ERROR: Unable to locate IOAPIC for GSI 52
[  614.332860] No IOAPIC for GSI 52
[  614.332861] ERROR: Unable to locate IOAPIC for GSI 52
[  614.332863] acpi_register_gsi: gsi 52, irq -1
[  614.332865] pci 0000:80:01.0: PCI INT A: failed to register GSI
[  614.332867] pci 0000:80:01.0: Error enabling bridge (-1), continuing
[  614.332979] mp_register_gsi: gsi 48
[  614.332980] ERROR: Unable to locate IOAPIC for GSI 48
[  614.332982] No IOAPIC for GSI 48
[  614.332983] ERROR: Unable to locate IOAPIC for GSI 48
[  614.332985] acpi_register_gsi: gsi 48, irq -1
[  614.332987] pci 0000:80:03.0: PCI INT A: failed to register GSI
[  614.332989] pci 0000:80:03.0: Error enabling bridge (-1), continuing
[  614.333101] mp_register_gsi: gsi 50
[  614.333102] ERROR: Unable to locate IOAPIC for GSI 50
[  614.333104] No IOAPIC for GSI 50
Quoted 235 lines
drivers/acpi/pci_root.c +4 -0
+	acpi_pci_ioapic_add(root);
+
 	pci_bus_add_devices(root->bus);
 	return 1;
 
@@ -546,6 +548,8 @@ static void acpi_pci_root_remove(struct acpi_device *device)
 
 	pci_stop_root_bus(root->bus);
 
+	acpi_pci_ioapic_remove(root);
+
 	device_set_run_wake(root->bus->bridge, false);
 	pci_acpi_remove_bus_pm_notifier(device);
 
drivers/pci/ioapic.c +94 -53
index 7d6b157..60351b2 100644
@@ -22,101 +22,142 @@
 #include <linux/slab.h>
 #include <acpi/acpi_bus.h>
 
-struct ioapic {
-	acpi_handle	handle;
+struct acpi_pci_ioapic {
+	acpi_handle	root_handle;
 	u32		gsi_base;
+	struct pci_dev *pdev;
+	struct list_head list;
 };
 
-static int ioapic_probe(struct pci_dev *dev, const struct pci_device_id *ent)
+static LIST_HEAD(ioapic_list);
+static DEFINE_MUTEX(ioapic_list_lock);
+
+static void handle_ioapic_add(acpi_handle handle, struct pci_dev **pdev,
+				 u32 *pgsi_base)
 {
-	acpi_handle handle;
 	acpi_status status;
 	unsigned long long gsb;
-	struct ioapic *ioapic;
+	struct pci_dev *dev;
+	u32 gsi_base;
 	int ret;
 	char *type;
-	struct resource *res;
+	struct resource r;
+	struct resource *res = &r;
+	char objname[64];
+	struct acpi_buffer buffer = {sizeof(objname), objname};
 
-	handle = DEVICE_ACPI_HANDLE(&dev->dev);
-	if (!handle)
-		return -EINVAL;
+	*pdev = NULL;
+	*pgsi_base = 0;
 
 	status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsb);
-	if (ACPI_FAILURE(status))
-		return -EINVAL;
-
-	/*
-	 * The previous code in acpiphp evaluated _MAT if _GSB failed, but
-	 * ACPI spec 4.0 sec 6.2.2 requires _GSB for hot-pluggable I/O APICs.
-	 */
+	if (ACPI_FAILURE(status) || !gsb)
+		return;
 
-	ioapic = kzalloc(sizeof(*ioapic), GFP_KERNEL);
-	if (!ioapic)
-		return -ENOMEM;
+	dev = acpi_get_pci_dev(handle);
+	if (!dev)
+		return;
 
-	ioapic->handle = handle;
-	ioapic->gsi_base = (u32) gsb;
+	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
 
-	if (dev->class == PCI_CLASS_SYSTEM_PIC_IOAPIC)
-		type = "IOAPIC";
-	else
-		type = "IOxAPIC";
+	gsi_base = gsb;
+	type = "IOxAPIC";
 
 	ret = pci_enable_device(dev);
 	if (ret < 0)
-		goto exit_free;
+		goto exit_put;
 
 	pci_set_master(dev);
 
+	if (dev->class == PCI_CLASS_SYSTEM_PIC_IOAPIC)
+		type = "IOAPIC";
+
 	if (pci_request_region(dev, 0, type))
 		goto exit_disable;
 
 	res = &dev->resource[0];
-	if (acpi_register_ioapic(ioapic->handle, res->start, ioapic->gsi_base))
+
+	if (acpi_register_ioapic(handle, res->start, gsi_base))
 		goto exit_release;
 
-	pci_set_drvdata(dev, ioapic);
-	dev_info(&dev->dev, "%s at %pR, GSI %u\n", type, res, ioapic->gsi_base);
-	return 0;
+	pr_info("%s %s %s at %pR, GSI %u\n",
+		dev_name(&dev->dev), objname, type,
+		res, gsi_base);
+
+	*pdev = dev;
+	*pgsi_base = gsi_base;
+	return;
 
 exit_release:
 	pci_release_region(dev, 0);
 exit_disable:
 	pci_disable_device(dev);
-exit_free:
-	kfree(ioapic);
-	return -ENODEV;
+exit_put:
+	pci_dev_put(dev);
 }
 
-static void ioapic_remove(struct pci_dev *dev)
+static void handle_ioapic_remove(acpi_handle handle, struct pci_dev *dev,
+				  u32 gsi_base)
 {
-	struct ioapic *ioapic = pci_get_drvdata(dev);
+	acpi_unregister_ioapic(handle, gsi_base);
 
-	acpi_unregister_ioapic(ioapic->handle, ioapic->gsi_base);
 	pci_release_region(dev, 0);
 	pci_disable_device(dev);
-	kfree(ioapic);
+	pci_dev_put(dev);
 }
 
+static acpi_status register_ioapic(acpi_handle handle, u32 lvl,
+					void *context, void **rv)
+{
+	acpi_handle root_handle = context;
+	struct pci_dev *pdev;
+	u32 gsi_base;
+	struct acpi_pci_ioapic *ioapic;
 
-static DEFINE_PCI_DEVICE_TABLE(ioapic_devices) = {
-	{ PCI_DEVICE_CLASS(PCI_CLASS_SYSTEM_PIC_IOAPIC, ~0) },
-	{ PCI_DEVICE_CLASS(PCI_CLASS_SYSTEM_PIC_IOXAPIC, ~0) },
-	{ }
-};
-MODULE_DEVICE_TABLE(pci, ioapic_devices);
+	handle_ioapic_add(handle, &pdev, &gsi_base);
+	if (!gsi_base)
+		return AE_OK;
 
-static struct pci_driver ioapic_driver = {
-	.name		= "ioapic",
-	.id_table	= ioapic_devices,
-	.probe		= ioapic_probe,
-	.remove		= ioapic_remove,
-};
+	ioapic = kzalloc(sizeof(*ioapic), GFP_KERNEL);
+	if (!ioapic) {
+		pr_err("%s: cannot allocate memory\n", __func__);
+		handle_ioapic_remove(root_handle, pdev, gsi_base);
+		return AE_OK;
+	}
+	ioapic->root_handle = root_handle;
+	ioapic->pdev = pdev;
+	ioapic->gsi_base = gsi_base;
+
+	mutex_lock(&ioapic_list_lock);
+	list_add(&ioapic->list, &ioapic_list);
+	mutex_unlock(&ioapic_list_lock);
+
+	return AE_OK;
+}
 
-static int __init ioapic_init(void)
+void acpi_pci_ioapic_add(struct acpi_pci_root *root)
 {
-	return pci_register_driver(&ioapic_driver);
+	acpi_status status;
+
+	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, root->device->handle,
+				     (u32)1, register_ioapic, NULL,
+				     root->device->handle,
+				     NULL);
+	if (ACPI_FAILURE(status))
+		pr_err("%s: register_ioapic failure - %d", __func__, status);
 }
-module_init(ioapic_init);
 
-MODULE_LICENSE("GPL");
+void acpi_pci_ioapic_remove(struct acpi_pci_root *root)
+{
+	struct acpi_pci_ioapic *ioapic, *tmp;
+
+	mutex_lock(&ioapic_list_lock);
+	list_for_each_entry_safe(ioapic, tmp, &ioapic_list, list) {
+		if (root->device->handle != ioapic->root_handle)
+			continue;
+		list_del(&ioapic->list);
+		handle_ioapic_remove(ioapic->root_handle, ioapic->pdev,
+					ioapic->gsi_base);
+		kfree(ioapic);
+	}
+	mutex_unlock(&ioapic_list_lock);
+}
include/linux/pci-acpi.h +8 -0
index 1704479..b2a2ced 100644
@@ -69,6 +69,14 @@ static inline void acpiphp_remove_slots(struct pci_bus *bus) { }
 static inline void acpiphp_check_host_bridge(acpi_handle handle) { }
 #endif
 
+#ifdef CONFIG_PCI_IOAPIC
+void acpi_pci_ioapic_add(struct acpi_pci_root *root);
+void acpi_pci_ioapic_remove(struct acpi_pci_root *root);
+#else
+static inline void acpi_pci_ioapic_add(struct acpi_pci_root *root) { }
+static inline void acpi_pci_ioapic_remove(struct acpi_pci_root *root) { }
+#endif
+
 #else	/* CONFIG_ACPI */
 static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
 static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
Signature · 2 lines
Thanks!
Yijing
author
#43 lore raw

PATCH v4 28/28 PCI, x86, ACPI: get ioapic address from acpi device

In reply to Yinghai Lu

Some ioapic controllers do not show up on pci config space, or pci device is there but no bar is used and is set by firmware in other non standard registers.

We can get ioapic address from ACPI0009's _CRS.

---
 drivers/pci/ioapic.c | 86 +++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 71 insertions(+), 15 deletions(-)
drivers/pci/ioapic.c +71 -15
index 60351b2..41f7c69 100644
@@ -32,6 +32,36 @@ struct acpi_pci_ioapic {
 static LIST_HEAD(ioapic_list);
 static DEFINE_MUTEX(ioapic_list_lock);
 
+static acpi_status setup_res(struct acpi_resource *acpi_res, void *data)
+{
+	struct resource *res;
+	struct acpi_resource_address64 addr;
+	acpi_status status;
+	unsigned long flags;
+	u64 start, end;
+
+	status = acpi_resource_to_address64(acpi_res, &addr);
+	if (!ACPI_SUCCESS(status))
+		return AE_OK;
+
+	if (addr.resource_type == ACPI_MEMORY_RANGE) {
+		if (addr.info.mem.caching == ACPI_PREFETCHABLE_MEMORY)
+			return AE_OK;
+		flags = IORESOURCE_MEM;
+	} else
+		return AE_OK;
+
+	start = addr.minimum + addr.translation_offset;
+	end = addr.maximum + addr.translation_offset;
+
+	res = data;
+	res->flags = flags;
+	res->start = start;
+	res->end = end;
+
+	return AE_OK;
+}
+
 static void handle_ioapic_add(acpi_handle handle, struct pci_dev **pdev,
 				 u32 *pgsi_base)
 {
@@ -54,33 +84,56 @@ static void handle_ioapic_add(acpi_handle handle, struct pci_dev **pdev,
 		return;
 
 	dev = acpi_get_pci_dev(handle);
-	if (!dev)
-		return;
+	if (!dev || !pci_resource_len(dev, 0)) {
+		struct acpi_device_info *info;
+		char *hid = NULL;
+
+		status = acpi_get_object_info(handle, &info);
+		if (ACPI_FAILURE(status))
+			goto exit_put;
+		if (info->valid & ACPI_VALID_HID)
+			hid = info->hardware_id.string;
+		if (!hid || strcmp(hid, "ACPI0009")) {
+			kfree(info);
+			goto exit_put;
+		}
+		kfree(info);
+		memset(res, 0, sizeof(*res));
+		acpi_walk_resources(handle, METHOD_NAME__CRS, setup_res, res);
+		if (!res->flags)
+			goto exit_put;
+	}
 
 	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
 
 	gsi_base = gsb;
 	type = "IOxAPIC";
+	if (dev) {
+		ret = pci_enable_device(dev);
+		if (ret < 0)
+			goto exit_put;
 
-	ret = pci_enable_device(dev);
-	if (ret < 0)
-		goto exit_put;
-
-	pci_set_master(dev);
+		pci_set_master(dev);
 
-	if (dev->class == PCI_CLASS_SYSTEM_PIC_IOAPIC)
-		type = "IOAPIC";
+		if (dev->class == PCI_CLASS_SYSTEM_PIC_IOAPIC)
+			type = "IOAPIC";
 
-	if (pci_request_region(dev, 0, type))
-		goto exit_disable;
+		if (pci_resource_len(dev, 0)) {
+			if (pci_request_region(dev, 0, type))
+				goto exit_disable;
 
-	res = &dev->resource[0];
+			res = &dev->resource[0];
+		}
+	}
 
-	if (acpi_register_ioapic(handle, res->start, gsi_base))
-		goto exit_release;
+	if (acpi_register_ioapic(handle, res->start, gsi_base)) {
+		if (dev)
+			goto exit_release;
+		return;
+	}
 
 	pr_info("%s %s %s at %pR, GSI %u\n",
-		dev_name(&dev->dev), objname, type,
+		dev ? dev_name(&dev->dev) : "", objname, type,
 		res, gsi_base);
 
 	*pdev = dev;
@@ -100,6 +153,9 @@ static void handle_ioapic_remove(acpi_handle handle, struct pci_dev *dev,
 {
 	acpi_unregister_ioapic(handle, gsi_base);
 
+	if (!dev)
+		return;
+
 	pci_release_region(dev, 0);
 	pci_disable_device(dev);
 	pci_dev_put(dev);
Signature · 1 line
1.8.1.4
#44 lore raw

Re: [PATCH v4 28/28] PCI, x86, ACPI: get ioapic address from acpi device

Quoted 19 lines · Yinghai Lu

Some ioapic controllers do not show up on pci config space, or pci device is there but no bar is used and is set by firmware in other non standard registers.

We can get ioapic address from ACPI0009's _CRS.

---
 drivers/pci/ioapic.c | 86
+++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 71 insertions(+), 15 deletions(-)
drivers/pci/ioapic.c +0 -0
index 60351b2..41f7c69 100644
@@ -32,6 +32,36 @@ struct acpi_pci_ioapic {
 static LIST_HEAD(ioapic_list);
 static DEFINE_MUTEX(ioapic_list_lock);

drivers/pci/ioapic.c struct acpi_pci_ioapic { · line 43

Quoted 10 lines
drivers/pci/ioapic.c +9 -0
 
+static acpi_status setup_res(struct acpi_resource *acpi_res, void *data)
+{
+	struct resource *res;
+	struct acpi_resource_address64 addr;
+	acpi_status status;
+	unsigned long flags;
+	u64 start, end;
+
+	status = acpi_resource_to_address64(acpi_res, &addr);

The above function fails on my machine because it does not handle Memory32Fixed resources. Is the following _CRS declaration allowed for IOAPIC?

            Device (APIC)
            {
                Name (_HID, "ACPI0009")  // _HID: Hardware ID
                Name (_CRS, ResourceTemplate ()  // _CRS: Current
Resource Settings
                {
                    Memory32Fixed (ReadOnly,
                        0xFEC01000,         // Address Base
                        0x00001000,         // Address Length
                        )
                })
                Method(_GSB) {
                        return (0x18)
                }
            }

Thanks
Rui

Quoted 117 lines
drivers/pci/ioapic.c +59 -15
+	if (!ACPI_SUCCESS(status))
+		return AE_OK;
+
+	if (addr.resource_type == ACPI_MEMORY_RANGE) {
+		if (addr.info.mem.caching == ACPI_PREFETCHABLE_MEMORY)
+			return AE_OK;
+		flags = IORESOURCE_MEM;
+	} else
+		return AE_OK;
+
+	start = addr.minimum + addr.translation_offset;
+	end = addr.maximum + addr.translation_offset;
+
+	res = data;
+	res->flags = flags;
+	res->start = start;
+	res->end = end;
+
+	return AE_OK;
+}
+
 static void handle_ioapic_add(acpi_handle handle, struct pci_dev **pdev,
 				 u32 *pgsi_base)
 {
@@ -54,33 +84,56 @@ static void handle_ioapic_add(acpi_handle handle, struct
 pci_dev **pdev,
 		return;
 
 	dev = acpi_get_pci_dev(handle);
-	if (!dev)
-		return;
+	if (!dev || !pci_resource_len(dev, 0)) {
+		struct acpi_device_info *info;
+		char *hid = NULL;
+
+		status = acpi_get_object_info(handle, &info);
+		if (ACPI_FAILURE(status))
+			goto exit_put;
+		if (info->valid & ACPI_VALID_HID)
+			hid = info->hardware_id.string;
+		if (!hid || strcmp(hid, "ACPI0009")) {
+			kfree(info);
+			goto exit_put;
+		}
+		kfree(info);
+		memset(res, 0, sizeof(*res));
+		acpi_walk_resources(handle, METHOD_NAME__CRS, setup_res, res);
+		if (!res->flags)
+			goto exit_put;
+	}
 
 	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
 
 	gsi_base = gsb;
 	type = "IOxAPIC";
+	if (dev) {
+		ret = pci_enable_device(dev);
+		if (ret < 0)
+			goto exit_put;
 
-	ret = pci_enable_device(dev);
-	if (ret < 0)
-		goto exit_put;
-
-	pci_set_master(dev);
+		pci_set_master(dev);
 
-	if (dev->class == PCI_CLASS_SYSTEM_PIC_IOAPIC)
-		type = "IOAPIC";
+		if (dev->class == PCI_CLASS_SYSTEM_PIC_IOAPIC)
+			type = "IOAPIC";
 
-	if (pci_request_region(dev, 0, type))
-		goto exit_disable;
+		if (pci_resource_len(dev, 0)) {
+			if (pci_request_region(dev, 0, type))
+				goto exit_disable;
 
-	res = &dev->resource[0];
+			res = &dev->resource[0];
+		}
+	}
 
-	if (acpi_register_ioapic(handle, res->start, gsi_base))
-		goto exit_release;
+	if (acpi_register_ioapic(handle, res->start, gsi_base)) {
+		if (dev)
+			goto exit_release;
+		return;
+	}
 
 	pr_info("%s %s %s at %pR, GSI %u\n",
-		dev_name(&dev->dev), objname, type,
+		dev ? dev_name(&dev->dev) : "", objname, type,
 		res, gsi_base);
 
drivers/pci/ioapic.c +3 -0
 	*pdev = dev;
@@ -100,6 +153,9 @@ static void handle_ioapic_remove(acpi_handle handle,
 struct pci_dev *dev,
 {
 	acpi_unregister_ioapic(handle, gsi_base);
 
+	if (!dev)
+		return;
+
 	pci_release_region(dev, 0);
 	pci_disable_device(dev);

pci_dev_put(dev);
--
1.8.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

#45 lore raw

Re: [PATCH v4 28/28] PCI, x86, ACPI: get ioapic address from acpi device

Quoted 21 lines · rui wang
Quoted 20 lines · Yinghai Lu

Some ioapic controllers do not show up on pci config space, or pci device is there but no bar is used and is set by firmware in other non standard registers.

We can get ioapic address from ACPI0009's _CRS.

---
 drivers/pci/ioapic.c | 86
+++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 71 insertions(+), 15 deletions(-)
drivers/pci/ioapic.c +0 -0
index 60351b2..41f7c69 100644
@@ -32,6 +32,36 @@ struct acpi_pci_ioapic {
 static LIST_HEAD(ioapic_list);
 static DEFINE_MUTEX(ioapic_list_lock);
 
Quoted 9 lines

drivers/pci/ioapic.c struct acpi_pci_ioapic { · line 43

Quoted 9 lines
drivers/pci/ioapic.c +9 -0
+static acpi_status setup_res(struct acpi_resource *acpi_res, void *data)
+{
+	struct resource *res;
+	struct acpi_resource_address64 addr;
+	acpi_status status;
+	unsigned long flags;
+	u64 start, end;
+
+	status = acpi_resource_to_address64(acpi_res, &addr);

I worked around the problem by replacing acpi_resource_to_address64() with resource_to_addr(). But resource_to_addr() is a static function in arch/x86/pci/acpi.c, not very convenient to use. Here's what I did:

arch/x86/pci/acpi.c +1 -1
index d641897..cb5940a 100644
@@ -218,7 +218,7 @@ static void teardown_mcfg_map(struct pci_root_info *info)
 }
 #endif
 
-static acpi_status
+acpi_status
 resource_to_addr(struct acpi_resource *resource,
                        struct acpi_resource_address64 *addr)
 {
drivers/pci/ioapic.c +0 -0
index 41f7c69..68d7395 100644
@@ -40,7 +40,7 @@ static acpi_status setup_res(struct acpi_resource

*acpi_res, void *data)

        unsigned long flags;
        u64 start, end;

- status = acpi_resource_to_address64(acpi_res, &addr);

+       status = resource_to_addr(acpi_res, &addr);
        if (!ACPI_SUCCESS(status))
                return AE_OK;
include/acpi/acpi_bus.h +0 -0
index 94383a7..ae7f759 100644
@@ -354,6 +354,10 @@ extern int unregister_acpi_notifier(struct

notifier_block *);

extern int register_acpi_bus_notifier(struct notifier_block *nb); extern void unregister_acpi_bus_notifier(struct notifier_block *nb);
+extern acpi_status
+resource_to_addr(struct acpi_resource *resource,
+ struct acpi_resource_address64 *addr);
+

Thanks
Rui

Quoted 145 lines

The above function fails on my machine because it does not handle Memory32Fixed resources. Is the following _CRS declaration allowed for IOAPIC?

            Device (APIC)
            {
                Name (_HID, "ACPI0009")  // _HID: Hardware ID
                Name (_CRS, ResourceTemplate ()  // _CRS: Current
Resource Settings
                {
                    Memory32Fixed (ReadOnly,
                        0xFEC01000,         // Address Base
                        0x00001000,         // Address Length
                        )
                })
                Method(_GSB) {
                        return (0x18)
                }
            }

Thanks
Rui

Quoted 119 lines
drivers/pci/ioapic.c +21 -0
+	if (!ACPI_SUCCESS(status))
+		return AE_OK;
+
+	if (addr.resource_type == ACPI_MEMORY_RANGE) {
+		if (addr.info.mem.caching == ACPI_PREFETCHABLE_MEMORY)
+			return AE_OK;
+		flags = IORESOURCE_MEM;
+	} else
+		return AE_OK;
+
+	start = addr.minimum + addr.translation_offset;
+	end = addr.maximum + addr.translation_offset;
+
+	res = data;
+	res->flags = flags;
+	res->start = start;
+	res->end = end;
+
+	return AE_OK;
+}
+
 static void handle_ioapic_add(acpi_handle handle, struct pci_dev **pdev,
 				 u32 *pgsi_base)
 {
@@ -54,33 +84,56 @@ static void handle_ioapic_add(acpi_handle handle,

struct
pci_dev **pdev,

drivers/pci/ioapic.c +41 -15
 		return;
 
 	dev = acpi_get_pci_dev(handle);
-	if (!dev)
-		return;
+	if (!dev || !pci_resource_len(dev, 0)) {
+		struct acpi_device_info *info;
+		char *hid = NULL;
+
+		status = acpi_get_object_info(handle, &info);
+		if (ACPI_FAILURE(status))
+			goto exit_put;
+		if (info->valid & ACPI_VALID_HID)
+			hid = info->hardware_id.string;
+		if (!hid || strcmp(hid, "ACPI0009")) {
+			kfree(info);
+			goto exit_put;
+		}
+		kfree(info);
+		memset(res, 0, sizeof(*res));
+		acpi_walk_resources(handle, METHOD_NAME__CRS, setup_res, res);
+		if (!res->flags)
+			goto exit_put;
+	}
 
 	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
 
 	gsi_base = gsb;
 	type = "IOxAPIC";
+	if (dev) {
+		ret = pci_enable_device(dev);
+		if (ret < 0)
+			goto exit_put;
 
-	ret = pci_enable_device(dev);
-	if (ret < 0)
-		goto exit_put;
-
-	pci_set_master(dev);
+		pci_set_master(dev);
 
-	if (dev->class == PCI_CLASS_SYSTEM_PIC_IOAPIC)
-		type = "IOAPIC";
+		if (dev->class == PCI_CLASS_SYSTEM_PIC_IOAPIC)
+			type = "IOAPIC";
 
-	if (pci_request_region(dev, 0, type))
-		goto exit_disable;
+		if (pci_resource_len(dev, 0)) {
+			if (pci_request_region(dev, 0, type))
+				goto exit_disable;
 
-	res = &dev->resource[0];
+			res = &dev->resource[0];
+		}
+	}
 
-	if (acpi_register_ioapic(handle, res->start, gsi_base))
-		goto exit_release;
+	if (acpi_register_ioapic(handle, res->start, gsi_base)) {
+		if (dev)
+			goto exit_release;
+		return;
+	}
 
 	pr_info("%s %s %s at %pR, GSI %u\n",
-		dev_name(&dev->dev), objname, type,
+		dev ? dev_name(&dev->dev) : "", objname, type,
 		res, gsi_base);
 
 	*pdev = dev;
@@ -100,6 +153,9 @@ static void handle_ioapic_remove(acpi_handle handle,
 struct pci_dev *dev,
 {
 	acpi_unregister_ioapic(handle, gsi_base);
 
+	if (!dev)
+		return;
+
 	pci_release_region(dev, 0);
 	pci_disable_device(dev);

pci_dev_put(dev);
--
1.8.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

#46 lore raw

Re: [PATCH v4 28/28] PCI, x86, ACPI: get ioapic address from acpi device

2013/8/23 rui wang <[email protected]>:

Quoted 22 lines · rui wang
Quoted 21 lines · Yinghai Lu
Quoted 20 lines

Some ioapic controllers do not show up on pci config space, or pci device is there but no bar is used and is set by firmware in other non standard registers.

We can get ioapic address from ACPI0009's _CRS.

---
 drivers/pci/ioapic.c | 86
+++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 71 insertions(+), 15 deletions(-)
drivers/pci/ioapic.c +0 -0
index 60351b2..41f7c69 100644
@@ -32,6 +32,36 @@ struct acpi_pci_ioapic {
 static LIST_HEAD(ioapic_list);
 static DEFINE_MUTEX(ioapic_list_lock);
 
Quoted 14 lines
Quoted 9 lines

drivers/pci/ioapic.c struct acpi_pci_ioapic { · line 43

Quoted 9 lines
drivers/pci/ioapic.c +9 -0
+static acpi_status setup_res(struct acpi_resource *acpi_res, void *data)
+{
+    struct resource *res;
+    struct acpi_resource_address64 addr;
+    acpi_status status;
+    unsigned long flags;
+    u64 start, end;
+
+    status = acpi_resource_to_address64(acpi_res, &addr);

I worked around the problem by replacing acpi_resource_to_address64() with resource_to_addr(). But resource_to_addr() is a static function in arch/x86/pci/acpi.c, not very convenient to use. Here's what I did:

Hi Rui&Yinghai:
How about using the following code to translate struct
acpi_resource to struct resouce in this setup_res()?

         if (acpi_dev_resource_address_space(...)
                || acpi_dev_resource_memory(..))
              return AE_OK;
Quoted 193 lines
arch/x86/pci/acpi.c +1 -1
index d641897..cb5940a 100644
@@ -218,7 +218,7 @@ static void teardown_mcfg_map(struct pci_root_info *info)
 }
 #endif
 
-static acpi_status
+acpi_status
 resource_to_addr(struct acpi_resource *resource,
                        struct acpi_resource_address64 *addr)
 {
drivers/pci/ioapic.c +1 -1
index 41f7c69..68d7395 100644
@@ -40,7 +40,7 @@ static acpi_status setup_res(struct acpi_resource
 *acpi_res, void *data)
        unsigned long flags;
        u64 start, end;
 
-       status = acpi_resource_to_address64(acpi_res, &addr);
+       status = resource_to_addr(acpi_res, &addr);
        if (!ACPI_SUCCESS(status))
                return AE_OK;
include/acpi/acpi_bus.h +4 -0
index 94383a7..ae7f759 100644
@@ -354,6 +354,10 @@ extern int unregister_acpi_notifier(struct
 notifier_block *);
 
 extern int register_acpi_bus_notifier(struct notifier_block *nb);
 extern void unregister_acpi_bus_notifier(struct notifier_block *nb);
+extern acpi_status
+resource_to_addr(struct acpi_resource *resource,
+                        struct acpi_resource_address64 *addr);
+
 

Thanks
Rui

Quoted 137 lines

The above function fails on my machine because it does not handle Memory32Fixed resources. Is the following _CRS declaration allowed for IOAPIC?

            Device (APIC)
            {
                Name (_HID, "ACPI0009")  // _HID: Hardware ID
                Name (_CRS, ResourceTemplate ()  // _CRS: Current
Resource Settings
                {
                    Memory32Fixed (ReadOnly,
                        0xFEC01000,         // Address Base
                        0x00001000,         // Address Length
                        )
                })
                Method(_GSB) {
                        return (0x18)
                }
            }

Thanks
Rui

Quoted 112 lines
drivers/pci/ioapic.c +21 -0
+    if (!ACPI_SUCCESS(status))
+            return AE_OK;
+
+    if (addr.resource_type == ACPI_MEMORY_RANGE) {
+            if (addr.info.mem.caching == ACPI_PREFETCHABLE_MEMORY)
+                    return AE_OK;
+            flags = IORESOURCE_MEM;
+    } else
+            return AE_OK;
+
+    start = addr.minimum + addr.translation_offset;
+    end = addr.maximum + addr.translation_offset;
+
+    res = data;
+    res->flags = flags;
+    res->start = start;
+    res->end = end;
+
+    return AE_OK;
+}
+
 static void handle_ioapic_add(acpi_handle handle, struct pci_dev **pdev,
                              u32 *pgsi_base)
 {
@@ -54,33 +84,56 @@ static void handle_ioapic_add(acpi_handle handle,

struct
pci_dev **pdev,

             return;

     dev = acpi_get_pci_dev(handle);
drivers/pci/ioapic.c +41 -15
-    if (!dev)
-            return;
+    if (!dev || !pci_resource_len(dev, 0)) {
+            struct acpi_device_info *info;
+            char *hid = NULL;
+
+            status = acpi_get_object_info(handle, &info);
+            if (ACPI_FAILURE(status))
+                    goto exit_put;
+            if (info->valid & ACPI_VALID_HID)
+                    hid = info->hardware_id.string;
+            if (!hid || strcmp(hid, "ACPI0009")) {
+                    kfree(info);
+                    goto exit_put;
+            }
+            kfree(info);
+            memset(res, 0, sizeof(*res));
+            acpi_walk_resources(handle, METHOD_NAME__CRS, setup_res, res);
+            if (!res->flags)
+                    goto exit_put;
+    }
 
     acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
 
     gsi_base = gsb;
     type = "IOxAPIC";
+    if (dev) {
+            ret = pci_enable_device(dev);
+            if (ret < 0)
+                    goto exit_put;
 
-    ret = pci_enable_device(dev);
-    if (ret < 0)
-            goto exit_put;
-
-    pci_set_master(dev);
+            pci_set_master(dev);
 
-    if (dev->class == PCI_CLASS_SYSTEM_PIC_IOAPIC)
-            type = "IOAPIC";
+            if (dev->class == PCI_CLASS_SYSTEM_PIC_IOAPIC)
+                    type = "IOAPIC";
 
-    if (pci_request_region(dev, 0, type))
-            goto exit_disable;
+            if (pci_resource_len(dev, 0)) {
+                    if (pci_request_region(dev, 0, type))
+                            goto exit_disable;
 
-    res = &dev->resource[0];
+                    res = &dev->resource[0];
+            }
+    }
 
-    if (acpi_register_ioapic(handle, res->start, gsi_base))
-            goto exit_release;
+    if (acpi_register_ioapic(handle, res->start, gsi_base)) {
+            if (dev)
+                    goto exit_release;
+            return;
+    }
 
     pr_info("%s %s %s at %pR, GSI %u\n",
-            dev_name(&dev->dev), objname, type,
+            dev ? dev_name(&dev->dev) : "", objname, type,
             res, gsi_base);
 
     *pdev = dev;
@@ -100,6 +153,9 @@ static void handle_ioapic_remove(acpi_handle handle,
 struct pci_dev *dev,
 {
     acpi_unregister_ioapic(handle, gsi_base);
 
+    if (!dev)
+            return;
+
     pci_release_region(dev, 0);
     pci_disable_device(dev);
     pci_dev_put(dev);

--
1.8.1.4

Quoted 8 lines
Quoted 7 lines

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 2 lines
Best regards
Tianyu Lan
author
#47 lore raw

Re: [PATCH v4 28/28] PCI, x86, ACPI: get ioapic address from acpi device

Quoted 5 lines · Lan Tianyu
Quoted 4 lines

I worked around the problem by replacing acpi_resource_to_address64() with resource_to_addr(). But resource_to_addr() is a static function in arch/x86/pci/acpi.c, not very convenient to use. Here's what I did:

Quoted 7 lines

Hi Rui&Yinghai:
How about using the following code to translate struct
acpi_resource to struct resouce in this setup_res()?

         if (acpi_dev_resource_address_space(...)
                || acpi_dev_resource_memory(..))
              return AE_OK;

Yest, that could be better, will update that.

Also can you submit patch that will use that in res_to_addr of arch/x86/pci/acpi.c?

Thanks

Yinghai

author
#48 lore raw

Re: [PATCH v4 28/28] PCI, x86, ACPI: get ioapic address from acpi device

Quoted 10 lines · Yinghai Lu
Quoted 9 lines · Lan Tianyu
Quoted 4 lines

I worked around the problem by replacing acpi_resource_to_address64() with resource_to_addr(). But resource_to_addr() is a static function in arch/x86/pci/acpi.c, not very convenient to use. Here's what I did:

Hi Rui&Yinghai:
How about using the following code to translate struct
acpi_resource to struct resouce in this setup_res()?

Quoted 8 lines
Quoted 3 lines
         if (acpi_dev_resource_address_space(...)
                || acpi_dev_resource_memory(..))
              return AE_OK;

Yest, that could be better, will update that.

Also can you submit patch that will use that in res_to_addr of arch/x86/pci/acpi.c?

looks acpi_dev_resource_address_space... does not handle PREFTCH and translation offset.

So now i have to use res_to_addr alike one.

Thanks

Yinghai

author
#49 lore raw

Re: [PATCH v4 28/28] PCI, x86, ACPI: get ioapic address from acpi device

Quoted 17 lines · Yinghai Lu
Quoted 16 lines · Yinghai Lu
Quoted 5 lines · Lan Tianyu
Quoted 4 lines

I worked around the problem by replacing acpi_resource_to_address64() with resource_to_addr(). But resource_to_addr() is a static function in arch/x86/pci/acpi.c, not very convenient to use. Here's what I did:

Quoted 7 lines

Hi Rui&Yinghai:
How about using the following code to translate struct
acpi_resource to struct resouce in this setup_res()?

         if (acpi_dev_resource_address_space(...)
                || acpi_dev_resource_memory(..))
              return AE_OK;

Yest, that could be better, will update that.

Quoted 7 lines
Quoted 2 lines

Also can you submit patch that will use that in res_to_addr of arch/x86/pci/acpi.c?

looks acpi_dev_resource_address_space... does not handle PREFTCH and translation offset.

So now i have to use res_to_addr alike one.

Raphael,

Maybe we should move resource_to_addr to acpi generic.

Please check if you are ok with attached.

Thanks

Yinghai

Subject: [PATCH] ACPI, x86/PCI: Move resource_to_addr() to acpi generic

Rui wang reported ioapic hot-add does not work on his machine that _CRS have MEMORY_FIXED.
He also proposed to expose resource_to_addr() and use it for ioapic.

We should move it to acpi generic, as ioapi.c current is in drivers/pci/.

Or should move it to acpica?

---
 arch/x86/pci/acpi.c     |   51 +-----------------------------------------------
 drivers/acpi/resource.c |   46 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/acpi.h    |    3 ++
 3 files changed, 51 insertions(+), 49 deletions(-)
arch/x86/pci/acpi.c +2 -49
Index: linux-2.6/arch/x86/pci/acpi.c
===================================================================
@@ -219,60 +219,13 @@ static void teardown_mcfg_map(struct pci
 #endif
 
 static acpi_status
-resource_to_addr(struct acpi_resource *resource,
-			struct acpi_resource_address64 *addr)
-{
-	acpi_status status;
-	struct acpi_resource_memory24 *memory24;
-	struct acpi_resource_memory32 *memory32;
-	struct acpi_resource_fixed_memory32 *fixed_memory32;
-
-	memset(addr, 0, sizeof(*addr));
-	switch (resource->type) {
-	case ACPI_RESOURCE_TYPE_MEMORY24:
-		memory24 = &resource->data.memory24;
-		addr->resource_type = ACPI_MEMORY_RANGE;
-		addr->minimum = memory24->minimum;
-		addr->address_length = memory24->address_length;
-		addr->maximum = addr->minimum + addr->address_length - 1;
-		return AE_OK;
-	case ACPI_RESOURCE_TYPE_MEMORY32:
-		memory32 = &resource->data.memory32;
-		addr->resource_type = ACPI_MEMORY_RANGE;
-		addr->minimum = memory32->minimum;
-		addr->address_length = memory32->address_length;
-		addr->maximum = addr->minimum + addr->address_length - 1;
-		return AE_OK;
-	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
-		fixed_memory32 = &resource->data.fixed_memory32;
-		addr->resource_type = ACPI_MEMORY_RANGE;
-		addr->minimum = fixed_memory32->address;
-		addr->address_length = fixed_memory32->address_length;
-		addr->maximum = addr->minimum + addr->address_length - 1;
-		return AE_OK;
-	case ACPI_RESOURCE_TYPE_ADDRESS16:
-	case ACPI_RESOURCE_TYPE_ADDRESS32:
-	case ACPI_RESOURCE_TYPE_ADDRESS64:
-		status = acpi_resource_to_address64(resource, addr);
-		if (ACPI_SUCCESS(status) &&
-		    (addr->resource_type == ACPI_MEMORY_RANGE ||
-		    addr->resource_type == ACPI_IO_RANGE) &&
-		    addr->address_length > 0) {
-			return AE_OK;
-		}
-		break;
-	}
-	return AE_ERROR;
-}
-
-static acpi_status
 count_resource(struct acpi_resource *acpi_res, void *data)
 {
 	struct pci_root_info *info = data;
 	struct acpi_resource_address64 addr;
 	acpi_status status;
 
-	status = resource_to_addr(acpi_res, &addr);
+	status = acpi_mem_addr_resource_to_address64(acpi_res, &addr);
 	if (ACPI_SUCCESS(status))
 		info->res_num++;
 	return AE_OK;
@@ -288,7 +241,7 @@ setup_resource(struct acpi_resource *acp
 	unsigned long flags;
 	u64 start, orig_end, end;
 
-	status = resource_to_addr(acpi_res, &addr);
+	status = acpi_mem_addr_resource_to_address64(acpi_res, &addr);
 	if (!ACPI_SUCCESS(status))
 		return AE_OK;
 
drivers/acpi/resource.c +46 -0

52 lines not on this page · raw message

include/linux/acpi.h +3 -0
Index: linux-2.6/include/linux/acpi.h
===================================================================
@@ -259,6 +259,9 @@ unsigned long acpi_dev_irq_flags(u8 trig
 bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index,
 				 struct resource *res);
 
+acpi_status acpi_mem_addr_resource_to_address64(struct acpi_resource *resource,
+			struct acpi_resource_address64 *addr);
+
 struct resource_list_entry {
 	struct list_head node;
 	struct resource res;
#50 lore raw

Re: [PATCH v4 28/28] PCI, x86, ACPI: get ioapic address from acpi device

2013/8/24 Yinghai Lu <[email protected]>:

Quoted 28 lines · Yinghai Lu
Quoted 17 lines · Yinghai Lu
Quoted 16 lines · Lan Tianyu
Quoted 5 lines
Quoted 4 lines

I worked around the problem by replacing acpi_resource_to_address64() with resource_to_addr(). But resource_to_addr() is a static function in arch/x86/pci/acpi.c, not very convenient to use. Here's what I did:

Quoted 7 lines

Hi Rui&Yinghai:
How about using the following code to translate struct
acpi_resource to struct resouce in this setup_res()?

         if (acpi_dev_resource_address_space(...)
                || acpi_dev_resource_memory(..))
              return AE_OK;

Yest, that could be better, will update that.

Quoted 7 lines
Quoted 2 lines

Also can you submit patch that will use that in res_to_addr of arch/x86/pci/acpi.c?

looks acpi_dev_resource_address_space... does not handle PREFTCH and translation offset.

So now i have to use res_to_addr alike one.

Raphael,

Quoted 7 lines

Maybe we should move resource_to_addr to acpi generic.

Please check if you are ok with attached.

Thanks

Yinghai

Hi Rafael & Yinghai:
I wrote 4 proposal patches to try to make acpi resource
functions to replace
resource_to_addr() in the arch/x86/pci/acpi.c. From my opinion,
resource_to_addr()
does most work which acpi resource functions have done. So please have a look. Thanks.
The following patches just passed through compiling test.

Patch 1
-------------------
commit 1800bc9dda7318314607fbae7afda8be38e056dc

Author: Lan Tianyu <[email protected]>
Date:   Mon Aug 26 14:40:39 2013 +0800

ACPI/Resource: Add setting PREFETCH flag support

drivers/acpi/resource.c +1 -1
index b7201fc..23a560b 100644
@@ -35,7 +35,7 @@
 #endif
 
 static unsigned long acpi_dev_memresource_flags(u64 len, u8 write_protect,
-                        bool window)
+                        bool window, bool prefetchable)
 {
     unsigned long flags = IORESOURCE_MEM;
 
@@ -48,6 +48,9 @@ static unsigned long acpi_dev_memresource_flags(u64

len, u8 write_protect,

     if (window)
         flags |= IORESOURCE_WINDOW;

+ if (prefetchable)
+ flags |= IORESOURCE_PREFETCH;
+

     return flags;

}

@@ -56,7 +59,8 @@ static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len,

 {
     res->start = start;
     res->end = start + len - 1;

- res->flags = acpi_dev_memresource_flags(len, write_protect, false);
+ res->flags = acpi_dev_memresource_flags(len, write_protect,
+ false, false);
}

/**
@@ -175,7 +179,7 @@ bool acpi_dev_resource_address_space(struct acpi_resource *ares,

 {
     acpi_status status;
     struct acpi_resource_address64 addr;
-    bool window;
+    bool window, prefetchable;
     u64 len;
     u8 io_decode;

@@ -199,9 +203,11 @@ bool acpi_dev_resource_address_space(struct acpi_resource *ares,

     switch(addr.resource_type) {
     case ACPI_MEMORY_RANGE:
         len = addr.maximum - addr.minimum + 1;
+        prefetchable =
+            addr.info.mem.caching == ACPI_PREFETCHABLE_MEMORY;
         res->flags = acpi_dev_memresource_flags(len,
                         addr.info.mem.write_protect,
-                        window);
+                        window, prefetchable);
         break;
     case ACPI_IO_RANGE:
         io_decode = addr.granularity == 0xfff ?
@@ -252,7 +258,7 @@ bool acpi_dev_resource_ext_address_space(struct
acpi_resource *ares,
         len = ext_addr->maximum - ext_addr->minimum + 1;
         res->flags = acpi_dev_memresource_flags(len,
                     ext_addr->info.mem.write_protect,
-                    window);
+                    window, false);
         break;
     case ACPI_IO_RANGE:
         io_decode = ext_addr->granularity == 0xfff ?

Patch 2
-----------
commit a3ff8345ffb51885b216ba0ae231252cd88d4e76

Author: Lan Tianyu <[email protected]>
Date:   Mon Aug 26 15:57:14 2013 +0800

ACPI/Resource: Add address translation support

drivers/acpi/resource.c +0 -0
index 23a560b..439ee44 100644
@@ -196,8 +196,8 @@ bool acpi_dev_resource_address_space(struct

acpi_resource *ares,

     if (ACPI_FAILURE(status))
         return true;
-    res->start = addr.minimum;
-    res->end = addr.maximum;
+    res->start = addr.minimum + addr.translation_offset;
+    res->end = addr.maximum + addr.translation_offset;
     window = addr.producer_consumer == ACPI_PRODUCER;

     switch(addr.resource_type) {

Patch 3
---------------
commit 68bfefe619b49baa5d372e0664a6cb6d5138fad1

Author: Lan Tianyu <[email protected]>
Date:   Mon Aug 26 21:45:32 2013 +0800

ACPI: Add new acpi_dev_resource_address_space_with_addr() function

Add new function which can return the converted struct
acpi_resource_address64.
This will be used to get transaction offset in the setup_resource().

drivers/acpi/resource.c +2 -2
index 439ee44..98a6c35 100644
@@ -174,11 +174,11 @@ EXPORT_SYMBOL_GPL(acpi_dev_resource_io);
  * and if that's the case, use the information in it to populate the generic
  * resource object pointed to by @res.
  */
-bool acpi_dev_resource_address_space(struct acpi_resource *ares,
+bool acpi_dev_resource_address_space_with_addr(struct acpi_resource *ares,
+                     struct acpi_resource_address64 *addr,
                      struct resource *res)
 {
     acpi_status status;
-    struct acpi_resource_address64 addr;
     bool window, prefetchable;
     u64 len;
     u8 io_decode;
@@ -192,28 +192,28 @@ bool acpi_dev_resource_address_space(struct

acpi_resource *ares,

         return false;
     }

- status = acpi_resource_to_address64(ares, &addr);

+    status = acpi_resource_to_address64(ares, addr);
     if (ACPI_FAILURE(status))
         return true;
-    res->start = addr.minimum + addr.translation_offset;
-    res->end = addr.maximum + addr.translation_offset;
-    window = addr.producer_consumer == ACPI_PRODUCER;
+    res->start = addr->minimum + addr->translation_offset;
+    res->end = addr->maximum + addr->translation_offset;
+    window = addr->producer_consumer == ACPI_PRODUCER;

- switch(addr.resource_type) {
+ switch (addr->resource_type) {
case ACPI_MEMORY_RANGE:
- len = addr.maximum - addr.minimum + 1;
+ len = addr->maximum - addr->minimum + 1;
prefetchable =
- addr.info.mem.caching == ACPI_PREFETCHABLE_MEMORY;

+            addr->info.mem.caching == ACPI_PREFETCHABLE_MEMORY;
         res->flags = acpi_dev_memresource_flags(len,
-                        addr.info.mem.write_protect,
+                        addr->info.mem.write_protect,
                         window, prefetchable);
         break;
     case ACPI_IO_RANGE:
-        io_decode = addr.granularity == 0xfff ?
+        io_decode = addr->granularity == 0xfff ?
                 ACPI_DECODE_10 : ACPI_DECODE_16;

- res->flags = acpi_dev_ioresource_flags(addr.minimum,
- addr.maximum,
+ res->flags = acpi_dev_ioresource_flags(addr->minimum,
+ addr->maximum,

                                io_decode, window);
         break;
     case ACPI_BUS_NUMBER_RANGE:

@@ -225,6 +225,16 @@ bool acpi_dev_resource_address_space(struct acpi_resource *ares,

     return true;

}
+EXPORT_SYMBOL_GPL(acpi_dev_resource_address_space_with_addr); +
+bool acpi_dev_resource_address_space(struct acpi_resource *ares,
+ struct resource *res)
+{
+ struct acpi_resource_address64 addr;
+
+ return acpi_dev_resource_address_space_with_addr(ares, &addr,
+ res);
+}
EXPORT_SYMBOL_GPL(acpi_dev_resource_address_space);

/**

include/linux/acpi.h +0 -0
index a5db4ae..9f5c0d5 100644
@@ -260,6 +260,9 @@ bool acpi_dev_resource_memory(struct acpi_resource

*ares, struct resource *res);
bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res); bool acpi_dev_resource_address_space(struct acpi_resource *ares,

                      struct resource *res);

+bool acpi_dev_resource_address_space_with_addr(struct acpi_resource *ares,
+ struct acpi_resource_address64 *addr,
+ struct resource *res);
bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares,

                      struct resource *res);

unsigned long acpi_dev_irq_flags(u8 triggering, u8 polarity, u8 shareable);

Patch 4
--------------
commit a8733a1da756a257d55e68994268174b84b33670

Author: Lan Tianyu <[email protected]>
Date:   Mon Aug 26 22:53:38 2013 +0800

X86/PCI/ACPI: Rework setup_resource() via functions acpi resource functions

arch/x86/pci/acpi.c +12 -69

118 lines not on this page · raw message

Signature · 2 lines
Best regards
Tianyu Lan
author
#51 lore raw

Re: [PATCH v4 28/28] PCI, x86, ACPI: get ioapic address from acpi device

Quoted 37 lines · Lan Tianyu

2013/8/24 Yinghai Lu <[email protected]>:

Quoted 28 lines · Yinghai Lu
Quoted 17 lines · Yinghai Lu
Quoted 16 lines · Lan Tianyu
Quoted 5 lines
Quoted 4 lines

I worked around the problem by replacing acpi_resource_to_address64() with resource_to_addr(). But resource_to_addr() is a static function in arch/x86/pci/acpi.c, not very convenient to use. Here's what I did:

Quoted 7 lines

Hi Rui&Yinghai:
How about using the following code to translate struct
acpi_resource to struct resouce in this setup_res()?

         if (acpi_dev_resource_address_space(...)
                || acpi_dev_resource_memory(..))
              return AE_OK;

Yest, that could be better, will update that.

Quoted 7 lines
Quoted 2 lines

Also can you submit patch that will use that in res_to_addr of arch/x86/pci/acpi.c?

looks acpi_dev_resource_address_space... does not handle PREFTCH and translation offset.

So now i have to use res_to_addr alike one.

Raphael,

Quoted 7 lines

Maybe we should move resource_to_addr to acpi generic.

Please check if you are ok with attached.

Thanks

Yinghai

Quoted 8 lines

Hi Rafael & Yinghai:
I wrote 4 proposal patches to try to make acpi resource
functions to replace
resource_to_addr() in the arch/x86/pci/acpi.c. From my opinion,
resource_to_addr()
does most work which acpi resource functions have done. So please have a look. Thanks.
The following patches just passed through compiling test.

Thanks for doing that.

Overall it's Good to me.

some comments inline.

Quoted 34 lines

Patch 1
-------------------
commit 1800bc9dda7318314607fbae7afda8be38e056dc

Author: Lan Tianyu <[email protected]>
Date:   Mon Aug 26 14:40:39 2013 +0800

ACPI/Resource: Add setting PREFETCH flag support

drivers/acpi/resource.c +4 -1
index b7201fc..23a560b 100644
@@ -35,7 +35,7 @@
 #endif
 
 static unsigned long acpi_dev_memresource_flags(u64 len, u8 write_protect,
-                        bool window)
+                        bool window, bool prefetchable)
 {
     unsigned long flags = IORESOURCE_MEM;
 
@@ -48,6 +48,9 @@ static unsigned long acpi_dev_memresource_flags(u64
 len, u8 write_protect,
     if (window)
         flags |= IORESOURCE_WINDOW;
 
+    if (prefetchable)
+        flags |= IORESOURCE_PREFETCH;
+
     return flags;
 }

drivers/acpi/resource.c static void acpi_dev_get_memresource(struct resource · line 65

Quoted 8 lines
drivers/acpi/resource.c +2 -1
@@ -56,7 +59,8 @@ static void acpi_dev_get_memresource(struct resource
 *res, u64 start, u64 len,
 {
     res->start = start;
     res->end = start + len - 1;
-    res->flags = acpi_dev_memresource_flags(len, write_protect, false);
+    res->flags = acpi_dev_memresource_flags(len, write_protect,
+                        false, false);
 }

passing write_protect, window then pref looks silly.

may use | IO_REOURCE_... etc outside of acpi_dev_memresource_flags directly.

Quoted 262 lines
drivers/acpi/resource.c +4 -2
 /**
@@ -175,7 +179,7 @@ bool acpi_dev_resource_address_space(struct
 acpi_resource *ares,
 {
     acpi_status status;
     struct acpi_resource_address64 addr;
-    bool window;
+    bool window, prefetchable;
     u64 len;
     u8 io_decode;
@@ -199,9 +203,11 @@ bool acpi_dev_resource_address_space(struct
 acpi_resource *ares,
     switch(addr.resource_type) {
     case ACPI_MEMORY_RANGE:
         len = addr.maximum - addr.minimum + 1;
+        prefetchable =
+            addr.info.mem.caching == ACPI_PREFETCHABLE_MEMORY;
         res->flags = acpi_dev_memresource_flags(len,
                         addr.info.mem.write_protect,
-                        window);
+                        window, prefetchable);
         break;
     case ACPI_IO_RANGE:
         io_decode = addr.granularity == 0xfff ?
drivers/acpi/resource.c +1 -1
@@ -252,7 +258,7 @@ bool acpi_dev_resource_ext_address_space(struct
 acpi_resource *ares,
         len = ext_addr->maximum - ext_addr->minimum + 1;
         res->flags = acpi_dev_memresource_flags(len,
                     ext_addr->info.mem.write_protect,
-                    window);
+                    window, false);
         break;
     case ACPI_IO_RANGE:
         io_decode = ext_addr->granularity == 0xfff ?

Patch 2
-----------
commit a3ff8345ffb51885b216ba0ae231252cd88d4e76

Author: Lan Tianyu <[email protected]>
Date:   Mon Aug 26 15:57:14 2013 +0800

ACPI/Resource: Add address translation support

drivers/acpi/resource.c +2 -2
index 23a560b..439ee44 100644
@@ -196,8 +196,8 @@ bool acpi_dev_resource_address_space(struct
 acpi_resource *ares,
     if (ACPI_FAILURE(status))
         return true;
 
-    res->start = addr.minimum;
-    res->end = addr.maximum;
+    res->start = addr.minimum + addr.translation_offset;
+    res->end = addr.maximum + addr.translation_offset;
     window = addr.producer_consumer == ACPI_PRODUCER;
 
     switch(addr.resource_type) {

Patch 3
---------------
commit 68bfefe619b49baa5d372e0664a6cb6d5138fad1

Author: Lan Tianyu <[email protected]>
Date:   Mon Aug 26 21:45:32 2013 +0800

ACPI: Add new acpi_dev_resource_address_space_with_addr() function

Add new function which can return the converted struct
acpi_resource_address64.
This will be used to get transaction offset in the setup_resource().

drivers/acpi/resource.c +13 -13
index 439ee44..98a6c35 100644
@@ -174,11 +174,11 @@ EXPORT_SYMBOL_GPL(acpi_dev_resource_io);
  * and if that's the case, use the information in it to populate the generic
  * resource object pointed to by @res.
  */
-bool acpi_dev_resource_address_space(struct acpi_resource *ares,
+bool acpi_dev_resource_address_space_with_addr(struct acpi_resource *ares,
+                     struct acpi_resource_address64 *addr,
                      struct resource *res)
 {
     acpi_status status;
-    struct acpi_resource_address64 addr;
     bool window, prefetchable;
     u64 len;
     u8 io_decode;
@@ -192,28 +192,28 @@ bool acpi_dev_resource_address_space(struct
 acpi_resource *ares,
         return false;
     }
 
-    status = acpi_resource_to_address64(ares, &addr);
+    status = acpi_resource_to_address64(ares, addr);
     if (ACPI_FAILURE(status))
         return true;
 
-    res->start = addr.minimum + addr.translation_offset;
-    res->end = addr.maximum + addr.translation_offset;
-    window = addr.producer_consumer == ACPI_PRODUCER;
+    res->start = addr->minimum + addr->translation_offset;
+    res->end = addr->maximum + addr->translation_offset;
+    window = addr->producer_consumer == ACPI_PRODUCER;
 
-    switch(addr.resource_type) {
+    switch (addr->resource_type) {
     case ACPI_MEMORY_RANGE:
-        len = addr.maximum - addr.minimum + 1;
+        len = addr->maximum - addr->minimum + 1;
         prefetchable =
-            addr.info.mem.caching == ACPI_PREFETCHABLE_MEMORY;
+            addr->info.mem.caching == ACPI_PREFETCHABLE_MEMORY;
         res->flags = acpi_dev_memresource_flags(len,
-                        addr.info.mem.write_protect,
+                        addr->info.mem.write_protect,
                         window, prefetchable);
         break;
     case ACPI_IO_RANGE:
-        io_decode = addr.granularity == 0xfff ?
+        io_decode = addr->granularity == 0xfff ?
                 ACPI_DECODE_10 : ACPI_DECODE_16;
-        res->flags = acpi_dev_ioresource_flags(addr.minimum,
-                               addr.maximum,
+        res->flags = acpi_dev_ioresource_flags(addr->minimum,
+                               addr->maximum,
                                io_decode, window);
         break;

case ACPI_BUS_NUMBER_RANGE:

drivers/acpi/resource.c +10 -0
@@ -225,6 +225,16 @@ bool acpi_dev_resource_address_space(struct
 acpi_resource *ares,
 
     return true;
 }
+EXPORT_SYMBOL_GPL(acpi_dev_resource_address_space_with_addr);
+
+bool acpi_dev_resource_address_space(struct acpi_resource *ares,
+                     struct resource *res)
+{
+    struct acpi_resource_address64 addr;
+
+    return acpi_dev_resource_address_space_with_addr(ares, &addr,
+                             res);
+}
 EXPORT_SYMBOL_GPL(acpi_dev_resource_address_space);
 

/**

include/linux/acpi.h +3 -0
index a5db4ae..9f5c0d5 100644
@@ -260,6 +260,9 @@ bool acpi_dev_resource_memory(struct acpi_resource
 *ares, struct resource *res);
 bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res);
 bool acpi_dev_resource_address_space(struct acpi_resource *ares,
                      struct resource *res);
+bool acpi_dev_resource_address_space_with_addr(struct acpi_resource *ares,
+                struct acpi_resource_address64 *addr,
+                struct resource *res);
 bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares,
                      struct resource *res);

unsigned long acpi_dev_irq_flags(u8 triggering, u8 polarity, u8 shareable);

Patch 4
--------------
commit a8733a1da756a257d55e68994268174b84b33670

Author: Lan Tianyu <[email protected]>
Date:   Mon Aug 26 22:53:38 2013 +0800

X86/PCI/ACPI: Rework setup_resource() via functions acpi resource functions

arch/x86/pci/acpi.c +6 -57
index d641897..d4f85a1 100644
@@ -219,62 +219,15 @@ static void teardown_mcfg_map(struct pci_root_info *info)
 #endif
 
 static acpi_status
-resource_to_addr(struct acpi_resource *resource,
-            struct acpi_resource_address64 *addr)
-{
-    acpi_status status;
-    struct acpi_resource_memory24 *memory24;
-    struct acpi_resource_memory32 *memory32;
-    struct acpi_resource_fixed_memory32 *fixed_memory32;
-
-    memset(addr, 0, sizeof(*addr));
-    switch (resource->type) {
-    case ACPI_RESOURCE_TYPE_MEMORY24:
-        memory24 = &resource->data.memory24;
-        addr->resource_type = ACPI_MEMORY_RANGE;
-        addr->minimum = memory24->minimum;
-        addr->address_length = memory24->address_length;
-        addr->maximum = addr->minimum + addr->address_length - 1;
-        return AE_OK;
-    case ACPI_RESOURCE_TYPE_MEMORY32:
-        memory32 = &resource->data.memory32;
-        addr->resource_type = ACPI_MEMORY_RANGE;
-        addr->minimum = memory32->minimum;
-        addr->address_length = memory32->address_length;
-        addr->maximum = addr->minimum + addr->address_length - 1;
-        return AE_OK;
-    case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
-        fixed_memory32 = &resource->data.fixed_memory32;
-        addr->resource_type = ACPI_MEMORY_RANGE;
-        addr->minimum = fixed_memory32->address;
-        addr->address_length = fixed_memory32->address_length;
-        addr->maximum = addr->minimum + addr->address_length - 1;
-        return AE_OK;
-    case ACPI_RESOURCE_TYPE_ADDRESS16:
-    case ACPI_RESOURCE_TYPE_ADDRESS32:
-    case ACPI_RESOURCE_TYPE_ADDRESS64:
-        status = acpi_resource_to_address64(resource, addr);
-        if (ACPI_SUCCESS(status) &&
-            (addr->resource_type == ACPI_MEMORY_RANGE ||
-            addr->resource_type == ACPI_IO_RANGE) &&
-            addr->address_length > 0) {
-            return AE_OK;
-        }
-        break;
-    }
-    return AE_ERROR;
-}
-
-static acpi_status
 count_resource(struct acpi_resource *acpi_res, void *data)
 {
     struct pci_root_info *info = data;
-    struct acpi_resource_address64 addr;
-    acpi_status status;
+    struct resource res;
 
-    status = resource_to_addr(acpi_res, &addr);
-    if (ACPI_SUCCESS(status))
+    if (acpi_dev_resource_address_space(acpi_res, &res)
+        || acpi_dev_resource_memory(acpi_res, &res))
         info->res_num++;
+
     return AE_OK;
 }
 
@@ -282,27 +235,18 @@ static acpi_status
 setup_resource(struct acpi_resource *acpi_res, void *data)
 {
     struct pci_root_info *info = data;
-    struct resource *res;
+    struct resource *res = &info->res[info->res_num];
     struct acpi_resource_address64 addr;
-    acpi_status status;
-    unsigned long flags;
     u64 start, orig_end, end;
 
-    status = resource_to_addr(acpi_res, &addr);
-    if (!ACPI_SUCCESS(status))
-        return AE_OK;
+    memset(&addr, 0x00, sizeof(addr));

arch/x86/pci/acpi.c static acpi_status · line 245

Quoted 10 lines
arch/x86/pci/acpi.c +2 -7
 
-    if (addr.resource_type == ACPI_MEMORY_RANGE) {
-        flags = IORESOURCE_MEM;
-        if (addr.info.mem.caching == ACPI_PREFETCHABLE_MEMORY)
-            flags |= IORESOURCE_PREFETCH;
-    } else if (addr.resource_type == ACPI_IO_RANGE) {
-        flags = IORESOURCE_IO;
-    } else
+    if (!(acpi_dev_resource_address_space_with_addr(acpi_res, &addr, res)
+        || acpi_dev_resource_memory(acpi_res, res)))

acpi_dev_resource_address_space_with_addr(acpi_res, &addr, res)

passing extra addr, just for translation_offset?

maybe pass res_offset directly?

arch/x86/pci/acpi.c static acpi_status · line 249

Quoted 6 lines
arch/x86/pci/acpi.c +2 -2
         return AE_OK;
 
-    start = addr.minimum + addr.translation_offset;
-    orig_end = end = addr.maximum + addr.translation_offset;
+    start = res->start;
+    orig_end = end = res->end;

Yinghai

#52 lore raw

Re: [PATCH v4 28/28] PCI, x86, ACPI: get ioapic address from acpi device

2013/8/27 Yinghai Lu <[email protected]>:

Quoted 98 lines · Lan Tianyu
Quoted 37 lines

2013/8/24 Yinghai Lu <[email protected]>:

Quoted 28 lines · Yinghai Lu
Quoted 17 lines · Yinghai Lu
Quoted 16 lines · Lan Tianyu
Quoted 5 lines
Quoted 4 lines

I worked around the problem by replacing acpi_resource_to_address64() with resource_to_addr(). But resource_to_addr() is a static function in arch/x86/pci/acpi.c, not very convenient to use. Here's what I did:

Quoted 7 lines

Hi Rui&Yinghai:
How about using the following code to translate struct
acpi_resource to struct resouce in this setup_res()?

         if (acpi_dev_resource_address_space(...)
                || acpi_dev_resource_memory(..))
              return AE_OK;

Yest, that could be better, will update that.

Quoted 7 lines
Quoted 2 lines

Also can you submit patch that will use that in res_to_addr of arch/x86/pci/acpi.c?

looks acpi_dev_resource_address_space... does not handle PREFTCH and translation offset.

So now i have to use res_to_addr alike one.

Raphael,

Quoted 7 lines

Maybe we should move resource_to_addr to acpi generic.

Please check if you are ok with attached.

Thanks

Yinghai

Quoted 8 lines

Hi Rafael & Yinghai:
I wrote 4 proposal patches to try to make acpi resource
functions to replace
resource_to_addr() in the arch/x86/pci/acpi.c. From my opinion,
resource_to_addr()
does most work which acpi resource functions have done. So please have a look. Thanks.
The following patches just passed through compiling test.

Thanks for doing that.

Overall it's Good to me.

some comments inline.

Quoted 34 lines

Patch 1
-------------------
commit 1800bc9dda7318314607fbae7afda8be38e056dc

Author: Lan Tianyu <[email protected]>
Date:   Mon Aug 26 14:40:39 2013 +0800

ACPI/Resource: Add setting PREFETCH flag support

drivers/acpi/resource.c +4 -1
index b7201fc..23a560b 100644
@@ -35,7 +35,7 @@
 #endif
 
 static unsigned long acpi_dev_memresource_flags(u64 len, u8 write_protect,
-                        bool window)
+                        bool window, bool prefetchable)
 {
     unsigned long flags = IORESOURCE_MEM;
 
@@ -48,6 +48,9 @@ static unsigned long acpi_dev_memresource_flags(u64
 len, u8 write_protect,
     if (window)
         flags |= IORESOURCE_WINDOW;
 
+    if (prefetchable)
+        flags |= IORESOURCE_PREFETCH;
+
     return flags;
 }

drivers/acpi/resource.c static void acpi_dev_get_memresource(struct resource · line 65

Quoted 8 lines
drivers/acpi/resource.c +2 -1
@@ -56,7 +59,8 @@ static void acpi_dev_get_memresource(struct resource
 *res, u64 start, u64 len,
 {
     res->start = start;
     res->end = start + len - 1;
-    res->flags = acpi_dev_memresource_flags(len, write_protect, false);
+    res->flags = acpi_dev_memresource_flags(len, write_protect,
+                        false, false);
 }

passing write_protect, window then pref looks silly.

Quoted 2 lines

may use | IO_REOURCE_... etc outside of acpi_dev_memresource_flags directly.

Yes, this looks better.

Quoted 275 lines
Quoted 262 lines
drivers/acpi/resource.c +4 -2
 /**
@@ -175,7 +179,7 @@ bool acpi_dev_resource_address_space(struct
 acpi_resource *ares,
 {
     acpi_status status;
     struct acpi_resource_address64 addr;
-    bool window;
+    bool window, prefetchable;
     u64 len;
     u8 io_decode;
@@ -199,9 +203,11 @@ bool acpi_dev_resource_address_space(struct
 acpi_resource *ares,
     switch(addr.resource_type) {
     case ACPI_MEMORY_RANGE:
         len = addr.maximum - addr.minimum + 1;
+        prefetchable =
+            addr.info.mem.caching == ACPI_PREFETCHABLE_MEMORY;
         res->flags = acpi_dev_memresource_flags(len,
                         addr.info.mem.write_protect,
-                        window);
+                        window, prefetchable);
         break;
     case ACPI_IO_RANGE:
         io_decode = addr.granularity == 0xfff ?
drivers/acpi/resource.c +1 -1
@@ -252,7 +258,7 @@ bool acpi_dev_resource_ext_address_space(struct
 acpi_resource *ares,
         len = ext_addr->maximum - ext_addr->minimum + 1;
         res->flags = acpi_dev_memresource_flags(len,
                     ext_addr->info.mem.write_protect,
-                    window);
+                    window, false);
         break;
     case ACPI_IO_RANGE:
         io_decode = ext_addr->granularity == 0xfff ?

Patch 2
-----------
commit a3ff8345ffb51885b216ba0ae231252cd88d4e76

Author: Lan Tianyu <[email protected]>
Date:   Mon Aug 26 15:57:14 2013 +0800

ACPI/Resource: Add address translation support

drivers/acpi/resource.c +2 -2
index 23a560b..439ee44 100644
@@ -196,8 +196,8 @@ bool acpi_dev_resource_address_space(struct
 acpi_resource *ares,
     if (ACPI_FAILURE(status))
         return true;
 
-    res->start = addr.minimum;
-    res->end = addr.maximum;
+    res->start = addr.minimum + addr.translation_offset;
+    res->end = addr.maximum + addr.translation_offset;
     window = addr.producer_consumer == ACPI_PRODUCER;
 
     switch(addr.resource_type) {

Patch 3
---------------
commit 68bfefe619b49baa5d372e0664a6cb6d5138fad1

Author: Lan Tianyu <[email protected]>
Date:   Mon Aug 26 21:45:32 2013 +0800

ACPI: Add new acpi_dev_resource_address_space_with_addr() function

Add new function which can return the converted struct
acpi_resource_address64.
This will be used to get transaction offset in the setup_resource().

drivers/acpi/resource.c +13 -13
index 439ee44..98a6c35 100644
@@ -174,11 +174,11 @@ EXPORT_SYMBOL_GPL(acpi_dev_resource_io);
  * and if that's the case, use the information in it to populate the generic
  * resource object pointed to by @res.
  */
-bool acpi_dev_resource_address_space(struct acpi_resource *ares,
+bool acpi_dev_resource_address_space_with_addr(struct acpi_resource *ares,
+                     struct acpi_resource_address64 *addr,
                      struct resource *res)
 {
     acpi_status status;
-    struct acpi_resource_address64 addr;
     bool window, prefetchable;
     u64 len;
     u8 io_decode;
@@ -192,28 +192,28 @@ bool acpi_dev_resource_address_space(struct
 acpi_resource *ares,
         return false;
     }
 
-    status = acpi_resource_to_address64(ares, &addr);
+    status = acpi_resource_to_address64(ares, addr);
     if (ACPI_FAILURE(status))
         return true;
 
-    res->start = addr.minimum + addr.translation_offset;
-    res->end = addr.maximum + addr.translation_offset;
-    window = addr.producer_consumer == ACPI_PRODUCER;
+    res->start = addr->minimum + addr->translation_offset;
+    res->end = addr->maximum + addr->translation_offset;
+    window = addr->producer_consumer == ACPI_PRODUCER;
 
-    switch(addr.resource_type) {
+    switch (addr->resource_type) {
     case ACPI_MEMORY_RANGE:
-        len = addr.maximum - addr.minimum + 1;
+        len = addr->maximum - addr->minimum + 1;
         prefetchable =
-            addr.info.mem.caching == ACPI_PREFETCHABLE_MEMORY;
+            addr->info.mem.caching == ACPI_PREFETCHABLE_MEMORY;
         res->flags = acpi_dev_memresource_flags(len,
-                        addr.info.mem.write_protect,
+                        addr->info.mem.write_protect,
                         window, prefetchable);
         break;
     case ACPI_IO_RANGE:
-        io_decode = addr.granularity == 0xfff ?
+        io_decode = addr->granularity == 0xfff ?
                 ACPI_DECODE_10 : ACPI_DECODE_16;
-        res->flags = acpi_dev_ioresource_flags(addr.minimum,
-                               addr.maximum,
+        res->flags = acpi_dev_ioresource_flags(addr->minimum,
+                               addr->maximum,
                                io_decode, window);
         break;

case ACPI_BUS_NUMBER_RANGE:

drivers/acpi/resource.c +10 -0
@@ -225,6 +225,16 @@ bool acpi_dev_resource_address_space(struct
 acpi_resource *ares,
 
     return true;
 }
+EXPORT_SYMBOL_GPL(acpi_dev_resource_address_space_with_addr);
+
+bool acpi_dev_resource_address_space(struct acpi_resource *ares,
+                     struct resource *res)
+{
+    struct acpi_resource_address64 addr;
+
+    return acpi_dev_resource_address_space_with_addr(ares, &addr,
+                             res);
+}
 EXPORT_SYMBOL_GPL(acpi_dev_resource_address_space);
 

/**

include/linux/acpi.h +3 -0
index a5db4ae..9f5c0d5 100644
@@ -260,6 +260,9 @@ bool acpi_dev_resource_memory(struct acpi_resource
 *ares, struct resource *res);
 bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res);
 bool acpi_dev_resource_address_space(struct acpi_resource *ares,
                      struct resource *res);
+bool acpi_dev_resource_address_space_with_addr(struct acpi_resource *ares,
+                struct acpi_resource_address64 *addr,
+                struct resource *res);
 bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares,
                      struct resource *res);

unsigned long acpi_dev_irq_flags(u8 triggering, u8 polarity, u8 shareable);

Patch 4
--------------
commit a8733a1da756a257d55e68994268174b84b33670

Author: Lan Tianyu <[email protected]>
Date:   Mon Aug 26 22:53:38 2013 +0800

X86/PCI/ACPI: Rework setup_resource() via functions acpi resource functions

arch/x86/pci/acpi.c +6 -57
index d641897..d4f85a1 100644
@@ -219,62 +219,15 @@ static void teardown_mcfg_map(struct pci_root_info *info)
 #endif
 
 static acpi_status
-resource_to_addr(struct acpi_resource *resource,
-            struct acpi_resource_address64 *addr)
-{
-    acpi_status status;
-    struct acpi_resource_memory24 *memory24;
-    struct acpi_resource_memory32 *memory32;
-    struct acpi_resource_fixed_memory32 *fixed_memory32;
-
-    memset(addr, 0, sizeof(*addr));
-    switch (resource->type) {
-    case ACPI_RESOURCE_TYPE_MEMORY24:
-        memory24 = &resource->data.memory24;
-        addr->resource_type = ACPI_MEMORY_RANGE;
-        addr->minimum = memory24->minimum;
-        addr->address_length = memory24->address_length;
-        addr->maximum = addr->minimum + addr->address_length - 1;
-        return AE_OK;
-    case ACPI_RESOURCE_TYPE_MEMORY32:
-        memory32 = &resource->data.memory32;
-        addr->resource_type = ACPI_MEMORY_RANGE;
-        addr->minimum = memory32->minimum;
-        addr->address_length = memory32->address_length;
-        addr->maximum = addr->minimum + addr->address_length - 1;
-        return AE_OK;
-    case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
-        fixed_memory32 = &resource->data.fixed_memory32;
-        addr->resource_type = ACPI_MEMORY_RANGE;
-        addr->minimum = fixed_memory32->address;
-        addr->address_length = fixed_memory32->address_length;
-        addr->maximum = addr->minimum + addr->address_length - 1;
-        return AE_OK;
-    case ACPI_RESOURCE_TYPE_ADDRESS16:
-    case ACPI_RESOURCE_TYPE_ADDRESS32:
-    case ACPI_RESOURCE_TYPE_ADDRESS64:
-        status = acpi_resource_to_address64(resource, addr);
-        if (ACPI_SUCCESS(status) &&
-            (addr->resource_type == ACPI_MEMORY_RANGE ||
-            addr->resource_type == ACPI_IO_RANGE) &&
-            addr->address_length > 0) {
-            return AE_OK;
-        }
-        break;
-    }
-    return AE_ERROR;
-}
-
-static acpi_status
 count_resource(struct acpi_resource *acpi_res, void *data)
 {
     struct pci_root_info *info = data;
-    struct acpi_resource_address64 addr;
-    acpi_status status;
+    struct resource res;
 
-    status = resource_to_addr(acpi_res, &addr);
-    if (ACPI_SUCCESS(status))
+    if (acpi_dev_resource_address_space(acpi_res, &res)
+        || acpi_dev_resource_memory(acpi_res, &res))
         info->res_num++;
+
     return AE_OK;
 }
 
@@ -282,27 +235,18 @@ static acpi_status
 setup_resource(struct acpi_resource *acpi_res, void *data)
 {
     struct pci_root_info *info = data;
-    struct resource *res;
+    struct resource *res = &info->res[info->res_num];
     struct acpi_resource_address64 addr;
-    acpi_status status;
-    unsigned long flags;
     u64 start, orig_end, end;
 
-    status = resource_to_addr(acpi_res, &addr);
-    if (!ACPI_SUCCESS(status))
-        return AE_OK;
+    memset(&addr, 0x00, sizeof(addr));

arch/x86/pci/acpi.c static acpi_status · line 245

Quoted 10 lines
arch/x86/pci/acpi.c +2 -7
 
-    if (addr.resource_type == ACPI_MEMORY_RANGE) {
-        flags = IORESOURCE_MEM;
-        if (addr.info.mem.caching == ACPI_PREFETCHABLE_MEMORY)
-            flags |= IORESOURCE_PREFETCH;
-    } else if (addr.resource_type == ACPI_IO_RANGE) {
-        flags = IORESOURCE_IO;
-    } else
+    if (!(acpi_dev_resource_address_space_with_addr(acpi_res, &addr, res)
+        || acpi_dev_resource_memory(acpi_res, res)))

acpi_dev_resource_address_space_with_addr(acpi_res, &addr, res)

Quoted 2 lines

passing extra addr, just for translation_offset?

For this case, it's "Yes", . For some other cases(e.g arch/ia64/pci/pci.c add_window()),
whole addr maybe necessary. To be more general, I hope it can return more infos

Quoted 13 lines

maybe pass res_offset directly?

arch/x86/pci/acpi.c static acpi_status · line 249

Quoted 6 lines
arch/x86/pci/acpi.c +2 -2
         return AE_OK;
 
-    start = addr.minimum + addr.translation_offset;
-    orig_end = end = addr.maximum + addr.translation_offset;
+    start = res->start;
+    orig_end = end = res->end;

Yinghai

Signature · 2 lines
Best regards
Tianyu Lan