[PATCH 1/8] Formalize virtual-IRQ remapping configuration.
mostrows at watson.ibm.com
mostrows at watson.ibm.com
Tue May 30 06:42:05 EST 2006
Instead of setting various global various to configure the behavior of
virtual-IRQ remapping, each platform has the option of calling
virt_irq_config() in "init_early" to specify:
- the offset to be used (i.e. NUM_ISA_INTERRUPTS)
- the number of interrupt vectors which are to be mapped 1-1
- the number of interrupt vectors that may be arbitrarily remapped
If virt_irq_config() is not called, the default configuration will be
used (512 identity-mapped interrupts with no offset).
--
Signed-off-by: Michal Ostrowski <mostrows at watson.ibm.com>
---
arch/powerpc/kernel/irq.c | 62 ++++++++++++++++----------------
arch/powerpc/kernel/prom.c | 4 --
arch/powerpc/kernel/setup_64.c | 6 +++
arch/powerpc/platforms/iseries/setup.c | 3 +-
arch/powerpc/platforms/pseries/setup.c | 10 +++++
include/asm-powerpc/irq.h | 30 +++++++++++----
6 files changed, 70 insertions(+), 45 deletions(-)
2f99449cbcacf67694e38698ec9860f86ba052e2
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 57d560c..efcb859 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -268,32 +268,35 @@ void __init init_IRQ(void)
#define UNDEFINED_IRQ 0xffffffff
unsigned int virt_irq_to_real_map[NR_IRQS];
-/*
- * Don't use virtual irqs 0, 1, 2 for devices.
- * The pcnet32 driver considers interrupt numbers < 2 to be invalid,
- * and 2 is the XICS IPI interrupt.
- * We limit virtual irqs to __irq_offet_value less than virt_irq_max so
- * that when we offset them we don't end up with an interrupt
- * number >= virt_irq_max.
- */
-#define MIN_VIRT_IRQ 3
-
-unsigned int virt_irq_max;
+static unsigned int min_virt_irq;
static unsigned int max_virt_irq;
static unsigned int nr_virt_irqs;
void
-virt_irq_init(void)
+virt_irq_config(unsigned int offset,
+ unsigned int num_shifted, unsigned int num_remapped)
{
- int i;
+ __irq_offset_value = offset;
+ min_virt_irq = num_shifted;
+ max_virt_irq = num_shifted + num_remapped - 1;
+ nr_virt_irqs = num_remapped;
- if ((virt_irq_max == 0) || (virt_irq_max > (NR_IRQS - 1)))
- virt_irq_max = NR_IRQS - 1;
- max_virt_irq = virt_irq_max - __irq_offset_value;
- nr_virt_irqs = max_virt_irq - MIN_VIRT_IRQ + 1;
+ BUG_ON(max_virt_irq + __irq_offset_value > (NR_IRQS-1));
+}
+void
+virt_irq_init(void)
+{
+ int i;
for (i = 0; i < NR_IRQS; i++)
virt_irq_to_real_map[i] = UNDEFINED_IRQ;
+
+ /* Configure the default mappings; don't remap interrupts,
+ * use 1-1 virt <-> real mappings. Subsequently platforms may
+ * choose to call virt_irq_config with their own custom settings.
+ */
+ virt_irq_config(0, NR_IRQS, 0);
+
}
/* Create a mapping for a real_irq if it doesn't already exist.
@@ -304,30 +307,25 @@ int virt_irq_create_mapping(unsigned int
unsigned int virq, first_virq;
static int warned;
- if (ppc64_interrupt_controller == IC_OPEN_PIC)
- return real_irq; /* no mapping for openpic (for now) */
-
- if (ppc64_interrupt_controller == IC_CELL_PIC)
- return real_irq; /* no mapping for iic either */
-
- /* don't map interrupts < MIN_VIRT_IRQ */
- if (real_irq < MIN_VIRT_IRQ) {
+ /* don't map interrupts < min_virt_irq */
+ if (real_irq < min_virt_irq) {
virt_irq_to_real_map[real_irq] = real_irq;
return real_irq;
}
- /* map to a number between MIN_VIRT_IRQ and max_virt_irq */
+ /* map to a number between min_virt_irq and max_virt_irq */
virq = real_irq;
if (virq > max_virt_irq)
- virq = (virq % nr_virt_irqs) + MIN_VIRT_IRQ;
+ virq = (virq % nr_virt_irqs) + min_virt_irq;
/* search for this number or a free slot */
first_virq = virq;
while (virt_irq_to_real_map[virq] != UNDEFINED_IRQ) {
if (virt_irq_to_real_map[virq] == real_irq)
return virq;
+
if (++virq > max_virt_irq)
- virq = MIN_VIRT_IRQ;
+ virq = min_virt_irq;
if (virq == first_virq)
goto nospace; /* oops, no free slots */
}
@@ -338,8 +336,10 @@ int virt_irq_create_mapping(unsigned int
nospace:
if (!warned) {
printk(KERN_CRIT "Interrupt table is full\n");
- printk(KERN_CRIT "Increase virt_irq_max (currently %d) "
- "in your kernel sources and rebuild.\n", virt_irq_max);
+ printk(KERN_CRIT "Modify kernel sources to call "
+ "virt_irq_config() with a larger value "
+ "of \"num_remapped\" (currently %d) and rebuild.\n",
+ nr_virt_irqs);
warned = 1;
}
return NO_IRQ;
@@ -358,7 +358,7 @@ unsigned int real_irq_to_virt_slowpath(u
virq = real_irq;
if (virq > max_virt_irq)
- virq = (virq % nr_virt_irqs) + MIN_VIRT_IRQ;
+ virq = (virq % nr_virt_irqs) + min_virt_irq;
first_virq = virq;
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 9a07f97..bfbe6a7 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -472,10 +472,6 @@ void __init finish_device_tree(void)
DBG(" -> finish_device_tree\n");
-#ifdef CONFIG_PPC64
- /* Initialize virtual IRQ map */
- virt_irq_init();
-#endif
scan_interrupt_controllers();
/*
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 4467c49..4669179 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -389,6 +389,12 @@ void __init setup_system(void)
*/
check_for_initrd();
+
+ /* Configure default setting for virtual IRQ remapping.
+ * ppc_md.init_early() may reconfigure this with virt_irq_config()
+ */
+ virt_irq_init();
+
/*
* Do some platform specific early initializations, that includes
* setting up the hash table pointers. It also sets up some interrupt-mapping
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index a6fd9be..6a7d04b 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -688,8 +688,9 @@ static int __init iseries_probe(void)
/*
* The Hypervisor only allows us up to 256 interrupt
* sources (the irq number is passed in a u8).
+ * This call provides us with vectors 0 .. 255 without remapping.
*/
- virt_irq_max = 255;
+ virt_irq_config(0, 256, 0);
return 1;
}
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 5f79f01..9d22265 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -270,7 +270,6 @@ static void __init pSeries_discover_pic
* Setup interrupt mapping options that are needed for finish_device_tree
* to properly parse the OF interrupt tree & do the virtual irq mapping
*/
- __irq_offset_value = NUM_ISA_INTERRUPTS;
ppc64_interrupt_controller = IC_INVALID;
for (np = NULL; (np = of_find_node_by_name(np, "interrupt-controller"));) {
typep = (char *)get_property(np, "compatible", NULL);
@@ -286,6 +285,15 @@ static void __init pSeries_discover_pic
printk("pSeries_discover_pic: failed to recognize"
" interrupt-controller\n");
+ /*
+ * Don't use virtual irqs 0, 1, 2 for devices.
+ * The pcnet32 driver considers interrupt numbers < 2 to be invalid,
+ * and 2 is the XICS IPI interrupt.
+ */
+
+ virt_irq_config(NUM_ISA_INTERRUPTS, 3,
+ NR_IRQS - (3 + NUM_ISA_INTERRUPTS));
+
}
static void pSeries_mach_cpu_die(void)
diff --git a/include/asm-powerpc/irq.h b/include/asm-powerpc/irq.h
index 7bc6d73..f2adbc0 100644
--- a/include/asm-powerpc/irq.h
+++ b/include/asm-powerpc/irq.h
@@ -54,18 +54,32 @@
*/
extern unsigned int virt_irq_to_real_map[NR_IRQS];
-/* The maximum virtual IRQ number that we support. This
- * can be set by the platform and will be reduced by the
- * value of __irq_offset_value. It defaults to and is
- * capped by (NR_IRQS - 1).
- */
-extern unsigned int virt_irq_max;
-
/* Create a mapping for a real_irq if it doesn't already exist.
* Return the virtual irq as a convenience.
*/
int virt_irq_create_mapping(unsigned int real_irq);
-void virt_irq_init(void);
+
+/* Initializes the virtual IRQ re-mapping, before ppc_md.init_early() */
+extern void virt_irq_init(void);
+
+/* virt_irq_config - Configure the division of the virtual IRQ space.
+ * Each platform may call this to set it's own specific
+ * IRQ remapping parameters.
+ * @offset: offset of remapped space (i.e. NUM_ISA_INTERRUPTS).
+ * @num_shifted: number of vectors to be simply shifted to account for
+ * the offset with no other remapping.
+ * @num_remapper: number of vectors that may be arbitrarily remapped.
+ *
+ * Virtual IRQ vectors will have the following mappings to the IRQ vectors
+ * as seen by the approrpiate interrupt controller:
+ * 0 .. offset-1 -> 0 .. offset-1 (1-1 mapping)
+ * offset .. offset+num_shifted-1 -> 0 .. num_shifted-1 (shift by offset)
+ * offset+num_shifted .. offset+num_shifted+num_remapped-1 ->
+ * arbitrary mappings to real irq as required.
+ */
+extern void virt_irq_config(unsigned int offset,
+ unsigned int num_linear,
+ unsigned int num_remapped);
static inline unsigned int virt_irq_to_real(unsigned int virt_irq)
{
--
1.1.4.g0b63-dirty
More information about the Linuxppc-dev
mailing list