Skip to contentSkip to conversation

IRQ resource deallocation[0/2]

PATCH In review Kenji Kaneshige 2 participants 4 messages Dec 7, 2004 – Dec 10, 2004

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 IRQ resource deallocation[0/2]

Hi,

I had posted the IRQ resource deallocation patch a couple of monthes ago and I had incorporated all feedbacks from the mailing list
(http://marc.theaimsgroup.com/?l=linux-kernel&m=109688530703122&w=2).
But it doesn't seems to be included yet, so I would like to try again. I hope my patch is included onto -mm tree since I want the patches be tested by many people.

Here is a brief description:

Architecture dependent IRQ resources such as interrupt vector for PCI devices are allocated at pci_enable_device() time on i386, x86-64 and ia64 platform. Today, however, these IRQ resources are never deallocated even if they are no longer used. The following set of patches adds supports to deallocate IRQ resources at pci_disable_device() time.

The motivation of the set of patches is as follows:

- IRQ resources such as interrupt vectors should be freed if they are no longer used because the amount of these resources are limited. By deallocating IRQ resources, we can recycle them.

- I think some hardwares will support hot-pluggable I/O units with I/O xAPICs in the near future. So I/O xAPIC hot-plug support by OS will be needed soon. IRQ resouces deallocation will be one of the most important stuff for I/O xAPIC hot-plug.

For now, the following set of patches has ia64 implementation only. i386 and x86_64 implementations are TBD.

The patches are against 2.6.10-rc3.

Thanks,
Kenji Kaneshige

#1 lore raw
Quoted 6 lines · Kenji Kaneshige

I had posted the IRQ resource deallocation patch a couple of monthes ago and I had incorporated all feedbacks from the mailing list
(http://marc.theaimsgroup.com/?l=linux-kernel&m=109688530703122&w=2).
But it doesn't seems to be included yet, so I would like to try again. I hope my patch is included onto -mm tree since I want the patches be tested by many people.

You should remove the config option and make it unconditional.

Thanks,
Zwane

-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users. Discover which products truly live up to the hype. Start reading now.
http://productguide.itmanagersjournal.com/

#2 lore raw
Quoted 11 lines · Zwane Mwaikambo
Quoted 6 lines · Kenji Kaneshige

I had posted the IRQ resource deallocation patch a couple of monthes ago and I had incorporated all feedbacks from the mailing list
(http://marc.theaimsgroup.com/?l=linux-kernel&m=109688530703122&w=2).
But it doesn't seems to be included yet, so I would like to try again. I hope my patch is included onto -mm tree since I want the patches be tested by many people.

You should remove the config option and make it unconditional.

I think you're right. I'll update the patch.

Thanks,
Kenji Kaneshige

#3 lore raw
In reply to Zwane Mwaikambo

I'm attching the updated set of patches.

Andrew, could you consider applying these patches?

Thanks,
Kenji Kaneshige

Quoted 9 lines · Zwane Mwaikambo
Quoted 6 lines · Kenji Kaneshige

I had posted the IRQ resource deallocation patch a couple of monthes ago and I had incorporated all feedbacks from the mailing list
(http://marc.theaimsgroup.com/?l=linux-kernel&m=109688530703122&w=2).
But it doesn't seems to be included yet, so I would like to try again. I hope my patch is included onto -mm tree since I want the patches be tested by many people.

Quoted 6 lines

You should remove the config option and make it unconditional.

Thanks,
Zwane

Kernel Version: 2.6.10-rc3
Depends: none
Description:

This patch is ACPI portion of IRQ deallocation. This patch defines the following new interface. The implementation of this interface depends on each platform.

o void acpi_unregister_gsi(u32 gsi)

This is a opposite portion of acpi_register_gsi(). This has a responsibility for deallocating IRQ resources associated with the specified GSI number.

We need to consider the case of shared interrupt. In the case of shared interrupt, acpi_register_gsi() is called multiple times for one gsi. That is, registrations and unregistrations can be nested.

This function undoes the effect of one call to acpi_register_gsi(). If this matches the last registration, IRQ resources associated with the specified GSI number are freed.

This patch also adds the following new function.

o void acpi_pci_irq_disable (struct pci_dev *dev)

This function is a opposite portion of acpi_pci_enable_irq(). It clears the device's linux IRQ number and calls acpi_unregister_gsi() to deallocate IRQ resources.

---

 linux-2.6.10-rc3-kanesige/drivers/acpi/pci_irq.c |   52 +++++++++++++++++++++++
 linux-2.6.10-rc3-kanesige/include/linux/acpi.h   |   13 +++++
 2 files changed, 65 insertions(+)
drivers/acpi/pci_irq.c renamed from drivers/acpi/pci_irq.c~IRQ_deallocation_acpi +52 -0
diff -puN drivers/acpi/pci_irq.c~IRQ_deallocation_acpi drivers/acpi/pci_irq.c
@@ -407,3 +407,55 @@ acpi_pci_irq_enable (
 }
 EXPORT_SYMBOL(acpi_pci_irq_enable);
 
+
+#ifdef CONFIG_ACPI_DEALLOCATE_IRQ
+void
+acpi_pci_irq_disable (
+	struct pci_dev		*dev)
+{
+	u32			gsi = 0;
+	u8			pin = 0;
+	int			edge_level = ACPI_LEVEL_SENSITIVE;
+	int			active_high_low = ACPI_ACTIVE_LOW;
+
+	ACPI_FUNCTION_TRACE("acpi_pci_irq_disable");
+
+	if (!dev)
+		return_VOID;
+	
+	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+	if (!pin)
+		return_VOID;
+	pin--;
+
+	if (!dev->bus)
+		return_VOID;
+
+	/* 
+	 * First we check the PCI IRQ routing table (PRT) for an IRQ.
+	 */
+ 	gsi = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin,
+				  &edge_level, &active_high_low);
+	/*
+	 * If no PRT entry was found, we'll try to derive an IRQ from the
+	 * device's parent bridge.
+	 */
+	if (!gsi)
+ 		gsi = acpi_pci_irq_derive(dev, pin,
+					  &edge_level, &active_high_low);
+	if (!gsi)
+		return_VOID;
+
+	/*
+	 * TBD: It might be worth clearing dev->irq by magic constant
+	 * (e.g. PCI_UNDEFINED_IRQ).
+	 */
+
+	printk(KERN_INFO PREFIX "PCI interrupt for device %s disabled\n",
+	       pci_name(dev));
+
+	acpi_unregister_gsi(gsi);
+
+	return_VOID;
+}
+#endif /* CONFIG_ACPI_DEALLOCATE_IRQ */
include/linux/acpi.h renamed from include/linux/acpi.h~IRQ_deallocation_acpi +13 -0
diff -puN include/linux/acpi.h~IRQ_deallocation_acpi include/linux/acpi.h
@@ -416,6 +416,15 @@ static inline int acpi_boot_init(void)
 unsigned int acpi_register_gsi (u32 gsi, int edge_level, int active_high_low);
 int acpi_gsi_to_irq (u32 gsi, unsigned int *irq);
 
+/*
+ * This function undoes the effect of one call to acpi_register_gsi().
+ * If this matches the last registration, any IRQ resources for gsi
+ * are freed.
+ */
+#ifdef CONFIG_ACPI_DEALLOCATE_IRQ
+void acpi_unregister_gsi (u32 gsi);
+#endif
+
 #ifdef CONFIG_ACPI_PCI
 
 struct acpi_prt_entry {
@@ -441,6 +450,10 @@ struct pci_dev;
 int acpi_pci_irq_enable (struct pci_dev *dev);
 void acpi_penalize_isa_irq(int irq);
 
+#ifdef CONFIG_ACPI_DEALLOCATE_IRQ
+void acpi_pci_irq_disable (struct pci_dev *dev);
+#endif
+
 struct acpi_pci_driver {
 	struct acpi_pci_driver *next;
 	int (*add)(acpi_handle handle);

_

Kernel Version: 2.6.10-rc3
Depends: IRQ_deallocation_acpi.patch
Description:

This is an ia64 portion of IRQ resource deallocation. It implements pcibios_disable_device() and acpi_unregister_gsi() for ia64.

o acpi_unregister_gsi()

Summary of changes for implementing this interface:

- Add new function iosapic_unregister_intr() into arch/ia64/kernel/iosapic.c. This function frees an interrupt vector and related data structures.

- Add new function free_irq_vector() into arch/ia64/kernel/irq_ia64.c. This frees an unused vector.

- Change assign_irq_vector() to be able to support free_irq_vector().

o pcibios_disable_device()

This calls acpi_pci_irq_disable() to deallocate IRQ resources.

---

 linux-2.6.10-rc3-kanesige/arch/ia64/Kconfig           |    5 
 linux-2.6.10-rc3-kanesige/arch/ia64/kernel/acpi.c     |    9 +
 linux-2.6.10-rc3-kanesige/arch/ia64/kernel/iosapic.c  |   96 ++++++++++++++++--
 linux-2.6.10-rc3-kanesige/arch/ia64/kernel/irq.c      |    3 
 linux-2.6.10-rc3-kanesige/arch/ia64/kernel/irq_ia64.c |   27 ++++-
 linux-2.6.10-rc3-kanesige/arch/ia64/pci/pci.c         |    8 +
 linux-2.6.10-rc3-kanesige/include/asm-ia64/hw_irq.h   |    2 
 linux-2.6.10-rc3-kanesige/include/asm-ia64/iosapic.h  |    4 
 8 files changed, 141 insertions(+), 13 deletions(-)
arch/ia64/Kconfig renamed from arch/ia64/Kconfig~IRQ_deallocation_ia64 +5 -0
diff -puN arch/ia64/Kconfig~IRQ_deallocation_ia64 arch/ia64/Kconfig
@@ -302,6 +302,11 @@ config IA64_PALINFO
 	  To use this option, you have to ensure that the "/proc file system
 	  support" (CONFIG_PROC_FS) is enabled, too.
 
+config ACPI_DEALLOCATE_IRQ
+	bool
+	depends on IOSAPIC && EXPERIMENTAL
+	default y
+
 source "drivers/firmware/Kconfig"
 
 source "fs/Kconfig.binfmt"
arch/ia64/kernel/acpi.c renamed from arch/ia64/kernel/acpi.c~IRQ_deallocation_ia64 +9 -0
diff -puN arch/ia64/kernel/acpi.c~IRQ_deallocation_ia64 arch/ia64/kernel/acpi.c
@@ -517,6 +517,15 @@ acpi_register_gsi (u32 gsi, int edge_lev
 }
 EXPORT_SYMBOL(acpi_register_gsi);
 
+#ifdef CONFIG_ACPI_DEALLOCATE_IRQ
+void
+acpi_unregister_gsi (u32 gsi)
+{
+	iosapic_unregister_intr(gsi);
+}
+EXPORT_SYMBOL(acpi_unregister_gsi);
+#endif /* CONFIG_ACPI_DEALLOCATE_IRQ */
+
 static int __init
 acpi_parse_fadt (unsigned long phys_addr, unsigned long size)
 {
arch/ia64/kernel/iosapic.c renamed from arch/ia64/kernel/iosapic.c~IRQ_deallocation_ia64 +87 -9

141 lines not on this page · raw message

arch/ia64/kernel/irq.c renamed from arch/ia64/kernel/irq.c~IRQ_deallocation_ia64 +3 -0
diff -puN arch/ia64/kernel/irq.c~IRQ_deallocation_ia64 arch/ia64/kernel/irq.c
@@ -1030,6 +1030,9 @@ void move_irq(int irq)
 	irq_desc_t *desc = irq_descp(irq);
 	int redir = test_bit(irq, pending_irq_redir);
 
+	if (unlikely(!desc->handler->set_affinity))
+		return;
+
 	if (!cpus_empty(pending_irq_cpumask[irq])) {
 		cpus_and(tmp, pending_irq_cpumask[irq], cpu_online_map);
 		if (unlikely(!cpus_empty(tmp))) {
arch/ia64/kernel/irq_ia64.c renamed from arch/ia64/kernel/irq_ia64.c~IRQ_deallocation_ia64 +23 -4
diff -puN arch/ia64/kernel/irq_ia64.c~IRQ_deallocation_ia64 arch/ia64/kernel/irq_ia64.c
@@ -75,15 +75,34 @@ irq_exit (void)
 	preempt_enable_no_resched();
 }
 
+static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_NUM_DEVICE_VECTORS)];
+
 int
 assign_irq_vector (int irq)
 {
-	static int next_vector = IA64_FIRST_DEVICE_VECTOR;
-
-	if (next_vector > IA64_LAST_DEVICE_VECTOR)
+	int pos, vector;
+ again:
+	pos = find_first_zero_bit(ia64_vector_mask, IA64_NUM_DEVICE_VECTORS);
+	vector = IA64_FIRST_DEVICE_VECTOR + pos;
+	if (vector > IA64_LAST_DEVICE_VECTOR)
 		/* XXX could look for sharable vectors instead of panic'ing... */
 		panic("assign_irq_vector: out of interrupt vectors!");
-	return next_vector++;
+	if (test_and_set_bit(pos, ia64_vector_mask))
+		goto again;
+	return vector;
+}
+
+void
+free_irq_vector (int vector)
+{
+	int pos;
+
+	if (vector < IA64_FIRST_DEVICE_VECTOR || vector > IA64_LAST_DEVICE_VECTOR)
+		return;
+
+	pos = vector - IA64_FIRST_DEVICE_VECTOR;
+	if (!test_and_clear_bit(pos, ia64_vector_mask))
+		printk(KERN_WARNING "%s: double free!\n", __FUNCTION__);
 }
 
 extern unsigned int do_IRQ(unsigned long irq, struct pt_regs *regs);
arch/ia64/pci/pci.c renamed from arch/ia64/pci/pci.c~IRQ_deallocation_ia64 +8 -0
diff -puN arch/ia64/pci/pci.c~IRQ_deallocation_ia64 arch/ia64/pci/pci.c
@@ -480,6 +480,14 @@ pcibios_enable_device (struct pci_dev *d
 	return acpi_pci_irq_enable(dev);
 }
 
+#ifdef CONFIG_ACPI_DEALLOCATE_IRQ
+void
+pcibios_disable_device (struct pci_dev *dev)
+{
+	acpi_pci_irq_disable(dev);
+}
+#endif /* CONFIG_ACPI_DEALLOCATE_IRQ */
+
 void
 pcibios_align_resource (void *data, struct resource *res,
 		        unsigned long size, unsigned long align)
include/asm-ia64/hw_irq.h renamed from include/asm-ia64/hw_irq.h~IRQ_deallocation_ia64 +2 -0
diff -puN include/asm-ia64/hw_irq.h~IRQ_deallocation_ia64 include/asm-ia64/hw_irq.h
@@ -50,6 +50,7 @@ typedef u8 ia64_vector;
  */
 #define IA64_FIRST_DEVICE_VECTOR	0x30
 #define IA64_LAST_DEVICE_VECTOR		0xe7
+#define IA64_NUM_DEVICE_VECTORS		(IA64_LAST_DEVICE_VECTOR - IA64_FIRST_DEVICE_VECTOR + 1)
 
 #define IA64_MCA_RENDEZ_VECTOR		0xe8	/* MCA rendez interrupt */
 #define IA64_PERFMON_VECTOR		0xee	/* performanc monitor interrupt vector */
@@ -81,6 +82,7 @@ extern __u8 isa_irq_to_vector_map[16];
 extern struct hw_interrupt_type irq_type_ia64_lsapic;	/* CPU-internal interrupt controller */
 
 extern int assign_irq_vector (int irq);	/* allocate a free vector */
+extern void free_irq_vector (int vector);
 extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect);
 extern void register_percpu_irq (ia64_vector vec, struct irqaction *action);
 
include/asm-ia64/iosapic.h renamed from include/asm-ia64/iosapic.h~IRQ_deallocation_ia64 +4 -0
diff -puN include/asm-ia64/iosapic.h~IRQ_deallocation_ia64 include/asm-ia64/iosapic.h
@@ -78,6 +78,9 @@ extern int gsi_to_irq (unsigned int gsi)
 extern void iosapic_enable_intr (unsigned int vector);
 extern int iosapic_register_intr (unsigned int gsi, unsigned long polarity,
 				  unsigned long trigger);
+#ifdef CONFIG_ACPI_DEALLOCATE_IRQ
+extern void iosapic_unregister_intr (unsigned int irq);
+#endif
 extern void __init iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
 				      unsigned long polarity,
 				      unsigned long trigger);
@@ -97,6 +100,7 @@ extern void __init map_iosapic_to_node (
 #define iosapic_system_init(pcat_compat)			do { } while (0)
 #define iosapic_init(address,gsi_base)				do { } while (0)
 #define iosapic_register_intr(gsi,polarity,trigger)		(gsi)
+#define iosapic_unregister_intr(irq)				do { } while (0)
 #define iosapic_override_isa_irq(isa_irq,gsi,polarity,trigger)	do { } while (0)
 #define iosapic_register_platform_intr(type,gsi,pmi,eid,id, \
 	polarity,trigger)					(gsi)

_