[PATCH][RFC] Vector sharing

Kenji Kaneshige
2004-04-19T09:31:31Z

[-- Attachment #1: Type: text/plain, Size: 21581 bytes --]

Hi,

I'm trying to make a patch that allows device vectors to be shared by
multiple interrupt sources. This patch enables ia64 linux to boot on
the machine that has single vector number space and many device
interrupt sources (more than 184).

I am changing IA64_LAST_DEVICE_VECTOR to 0x30 in order to test my
patch. My patch seems to work fine on my test environment.

The information of /proc/interrupts on my test environment is shown
below. It says multiple devices are sharing the vector (==IRQ)
0x30. Of course, these devices are not sharing the same interrupt
lines.

CPU0 CPU1 CPU2 CPU3
29: 0 0 0 0 LSAPIC cmc_poll
30: 0 0 0 0 IO-SAPIC-level cpe_hndlr
31: 0 0 0 0 LSAPIC cmc_hndlr
34: 2 0 6 0 IO-SAPIC-edge ide0
39: 0 0 0 0 IO-SAPIC-level acpi
45: 0 50 189 2 IO-SAPIC-edge serial
48: 0 280 56383 16 IO-SAPIC-level ioc0,
ioc1, ehci_hcd, uhci_hcd, uhci_hcd, eth0, eth1
232: 0 0 0 0 LSAPIC mca_rdzv
238: 0 0 0 0 LSAPIC perfmon
239: 6732150 6729399 6729272 6729140 LSAPIC timer
240: 0 0 0 0 LSAPIC mca_wkup
254: 7 85 85 81 LSAPIC IPI
NMI: 0 0 0 0
ERR: 0

I am concerned about following point of the design:

o My patch supports to find the sharable vectors not only for
level triggered interrupt sources but also for edge triggered
interrupt sources (Please see
iosapic_find_sharable_vector()). But I am wondering if it is
needed for edge triggered interrupt sources. (As a matter of
fact, my patch doesn't mark the vectors for edge triggered
interrupts as sharable (e.g. iosapic_register_intr()).

Any comments are welcomed.

Thanks,
Kenji Kaneshige

diff -Naur linux-2.6.6-rc1/arch/ia64/kernel/iosapic.c
linux-2.6.6-rc1-changed/arch/ia64/kernel/iosapic.c
--- linux-2.6.6-rc1/arch/ia64/kernel/iosapic.c 2004-04-19
16:10:25.970346988 +0900
+++ linux-2.6.6-rc1-changed/arch/ia64/kernel/iosapic.c 2004-04-19
16:25:23.251036926 +0900
@@ -101,15 +101,23 @@

/* These tables map IA-64 vectors to the IOSAPIC pin that generates this
vector. */

-static struct iosapic_intr_info {
+struct iosapic_pin {
+ struct list_head pin_list; /* IOSAPIC pins which share the same vector
*/
char *addr; /* base address of IOSAPIC */
u32 low32; /* current value of low word of Redirection table entry
*/
unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */
- char rte_index; /* IOSAPIC RTE index (-1 => not an IOSAPIC interrupt)
*/
- unsigned char dmode : 3; /* delivery mode (see iosapic.h) */
+ char rte_index; /* IOSAPIC RTE index */
unsigned char polarity: 1; /* interrupt polarity (see iosapic.h) */
+};
+
+static struct iosapic_intr_info {
+ struct list_head pin_head; /* List head of IOSAPIC pins */
+ struct iosapic_pin pin; /* First entry of IOSAPIC pins list */
+ int count; /* # of pins (0 => not an IOSAPIC interrupt) */
+ unsigned char dmode : 3; /* delivery mode (see iosapic.h) */
unsigned char trigger : 1; /* trigger mode (see iosapic.h) */
-} iosapic_intr_info[IA64_NUM_VECTORS];
+ unsigned char type : 1; /* Vector type */
+} iosapic_intr_info[IA64_NUM_VECTORS] __cacheline_aligned;

static struct iosapic {
char *addr; /* base address of IOSAPIC */
@@ -142,10 +150,14 @@
_gsi_to_vector (unsigned int gsi)
{
struct iosapic_intr_info *info;
+ struct iosapic_pin *pin;

- for (info = iosapic_intr_info; info < iosapic_intr_info +
IA64_NUM_VECTORS; ++info)
- if (info->gsi_base + info->rte_index == gsi)
- return info - iosapic_intr_info;
+ for (info = iosapic_intr_info; info < iosapic_intr_info +
IA64_NUM_VECTORS; ++info) {
+ list_for_each_entry(pin, &info->pin_head, pin_list) {
+ if (pin->gsi_base + pin->rte_index == gsi)
+ return info - iosapic_intr_info;
+ }
+ }
return -1;
}

@@ -177,15 +189,13 @@
char *addr;
int rte_index;
char redir;
+ struct iosapic_pin *pin;

DBG(KERN_DEBUG"IOSAPIC: routing vector %d to 0x%x\n", vector, dest);

- rte_index = iosapic_intr_info[vector].rte_index;
- if (rte_index < 0)
+ if (!iosapic_intr_info[vector].count)
return; /* not an IOSAPIC interrupt */

- addr = iosapic_intr_info[vector].addr;
- pol = iosapic_intr_info[vector].polarity;
trigger = iosapic_intr_info[vector].trigger;
dmode = iosapic_intr_info[vector].dmode;

@@ -193,31 +203,47 @@
#ifdef CONFIG_SMP
{
unsigned int irq;
+ cpumask_t cpumask;

for (irq = 0; irq < NR_IRQS; ++irq)
if (irq_to_vector(irq) == vector) {
- set_irq_affinity_info(irq, (int)(dest & 0xffff), redir);
+ /* All pins should use the same destination CPU */
+ cpumask = get_irq_affinity_info(irq);
+ if (cpumask != CPU_MASK_ALL)
+ dest = cpu_physical_id(first_cpu(mask));
+ else
+ set_irq_affinity_info(irq, (int)(dest & 0xffff), redir);
break;
}
}
#endif

- low32 = ((pol << IOSAPIC_POLARITY_SHIFT) |
- (trigger << IOSAPIC_TRIGGER_SHIFT) |
- (dmode << IOSAPIC_DELIVERY_SHIFT) |
- ((mask ? 1 : 0) << IOSAPIC_MASK_SHIFT) |
- vector);
-
/* dest contains both id and eid */
high32 = (dest << IOSAPIC_DEST_SHIFT);

spin_lock_irqsave(&iosapic_lock, flags);
{
- writel(IOSAPIC_RTE_HIGH(rte_index), addr + IOSAPIC_REG_SELECT);
- writel(high32, addr + IOSAPIC_WINDOW);
- writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
- writel(low32, addr + IOSAPIC_WINDOW);
- iosapic_intr_info[vector].low32 = low32;
+ list_for_each_entry(pin, &iosapic_intr_info[vector].pin_head, pin_list)
{
+ /* Don't change RTE which is already unmasked */
+ if (!(pin->low32 & IOSAPIC_MASK))
+ continue;
+
+ rte_index = pin->rte_index;
+ addr = pin->addr;
+ pol = pin->polarity;
+
+ low32 = ((pol << IOSAPIC_POLARITY_SHIFT) |
+ (trigger << IOSAPIC_TRIGGER_SHIFT) |
+ (dmode << IOSAPIC_DELIVERY_SHIFT) |
+ ((mask ? 1 : 0) << IOSAPIC_MASK_SHIFT) |
+ vector);
+
+ writel(IOSAPIC_RTE_HIGH(rte_index), addr + IOSAPIC_REG_SELECT);
+ writel(high32, addr + IOSAPIC_WINDOW);
+ writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
+ writel(low32, addr + IOSAPIC_WINDOW);
+ pin->low32 = low32;
+ }
}
spin_unlock_irqrestore(&iosapic_lock, flags);
}
@@ -236,21 +262,24 @@
u32 low32;
int rte_index;
ia64_vector vec = irq_to_vector(irq);
+ struct iosapic_pin *pin;

- addr = iosapic_intr_info[vec].addr;
- rte_index = iosapic_intr_info[vec].rte_index;
-
- if (rte_index < 0)
+ if (!iosapic_intr_info[vec].count)
return; /* not an IOSAPIC interrupt! */

spin_lock_irqsave(&iosapic_lock, flags);
{
- writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
+ list_for_each_entry(pin, &iosapic_intr_info[vec].pin_head, pin_list) {
+ addr = pin->addr;
+ rte_index = pin->rte_index;
+
+ writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);

- /* set only the mask bit */
- low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK;
+ /* set only the mask bit */
+ low32 = pin->low32 |= IOSAPIC_MASK;

- writel(low32, addr + IOSAPIC_WINDOW);
+ writel(low32, addr + IOSAPIC_WINDOW);
+ }
}
spin_unlock_irqrestore(&iosapic_lock, flags);
}
@@ -263,17 +292,21 @@
u32 low32;
int rte_index;
ia64_vector vec = irq_to_vector(irq);
+ struct iosapic_pin *pin;

- addr = iosapic_intr_info[vec].addr;
- rte_index = iosapic_intr_info[vec].rte_index;
- if (rte_index < 0)
+ if (!iosapic_intr_info[vec].count)
return; /* not an IOSAPIC interrupt! */

spin_lock_irqsave(&iosapic_lock, flags);
{
- writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
- low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK;
- writel(low32, addr + IOSAPIC_WINDOW);
+ list_for_each_entry(pin, &iosapic_intr_info[vec].pin_head, pin_list) {
+ addr = pin->addr;
+ rte_index = pin->rte_index;
+
+ writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
+ low32 = pin->low32 &= ~IOSAPIC_MASK;
+ writel(low32, addr + IOSAPIC_WINDOW);
+ }
}
spin_unlock_irqrestore(&iosapic_lock, flags);
}
@@ -289,6 +322,7 @@
char *addr;
int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0;
ia64_vector vec;
+ struct iosapic_pin *pin;

irq &= (~IA64_IRQ_REDIRECTED);
vec = irq_to_vector(irq);
@@ -298,10 +332,7 @@

dest = cpu_physical_id(first_cpu(mask));

- rte_index = iosapic_intr_info[vec].rte_index;
- addr = iosapic_intr_info[vec].addr;
-
- if (rte_index < 0)
+ if (!iosapic_intr_info[vec].count)
return; /* not an IOSAPIC interrupt */

set_irq_affinity_info(irq, dest, redir);
@@ -311,21 +342,26 @@

spin_lock_irqsave(&iosapic_lock, flags);
{
- /* get current delivery mode by reading the low32 */
- writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
- low32 = iosapic_intr_info[vec].low32 & ~(7 << IOSAPIC_DELIVERY_SHIFT);
- if (redir)
- /* change delivery mode to lowest priority */
- low32 |= (IOSAPIC_LOWEST_PRIORITY << IOSAPIC_DELIVERY_SHIFT);
- else
- /* change delivery mode to fixed */
- low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT);
-
- iosapic_intr_info[vec].low32 = low32;
- writel(IOSAPIC_RTE_HIGH(rte_index), addr + IOSAPIC_REG_SELECT);
- writel(high32, addr + IOSAPIC_WINDOW);
- writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
- writel(low32, addr + IOSAPIC_WINDOW);
+ list_for_each_entry(pin, &iosapic_intr_info[vec].pin_head, pin_list) {
+ rte_index = pin->rte_index;
+ addr = pin->addr;
+
+ /* get current delivery mode by reading the low32 */
+ writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
+ low32 = pin->low32 & ~(7 << IOSAPIC_DELIVERY_SHIFT);
+ if (redir)
+ /* change delivery mode to lowest priority */
+ low32 |= (IOSAPIC_LOWEST_PRIORITY << IOSAPIC_DELIVERY_SHIFT);
+ else
+ /* change delivery mode to fixed */
+ low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT);
+
+ pin->low32 = low32;
+ writel(IOSAPIC_RTE_HIGH(rte_index), addr + IOSAPIC_REG_SELECT);
+ writel(high32, addr + IOSAPIC_WINDOW);
+ writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
+ writel(low32, addr + IOSAPIC_WINDOW);
+ }
}
spin_unlock_irqrestore(&iosapic_lock, flags);
#endif
@@ -346,8 +382,11 @@
iosapic_end_level_irq (unsigned int irq)
{
ia64_vector vec = irq_to_vector(irq);
+ struct iosapic_pin *pin;

- writel(vec, iosapic_intr_info[vec].addr + IOSAPIC_EOI);
+ list_for_each_entry(pin, &iosapic_intr_info[vec].pin_head, pin_list) {
+ writel(vec, pin->addr + IOSAPIC_EOI);
+ }
}

#define iosapic_shutdown_level_irq mask_irq
@@ -427,6 +466,30 @@
}

/*
+ * Find a sharable vector.
+ *
+ * NOTE: This function assumes that platform interrupt doesn't share
+ * the vector.
+ */
+static int
+iosapic_find_sharable_vector (unsigned long trigger)
+{
+ int i;
+ static int next_vector = IA64_FIRST_DEVICE_VECTOR;
+
+ for (i = 0; i < IA64_LAST_DEVICE_VECTOR - IA64_FIRST_DEVICE_VECTOR + 1;
i++) {
+ if (next_vector > IA64_LAST_DEVICE_VECTOR)
+ next_vector = IA64_FIRST_DEVICE_VECTOR;
+
+ if (iosapic_intr_info[next_vector].type == IOSAPIC_VECTOR_SHARABLE &&
+ iosapic_intr_info[next_vector].trigger == trigger)
+ return next_vector++;
+ }
+
+ return -1;
+}
+
+/*
* if the given vector is already owned by other,
* assign a new vector for the other and make the vector available
*/
@@ -435,22 +498,20 @@
{
int new_vector;

- if (iosapic_intr_info[vector].rte_index >= 0 ||
iosapic_intr_info[vector].addr
- || iosapic_intr_info[vector].gsi_base ||
iosapic_intr_info[vector].dmode
- || iosapic_intr_info[vector].polarity ||
iosapic_intr_info[vector].trigger)
+ if (!iosapic_intr_info[vector].count)
{
new_vector = assign_irq_vector(AUTO_ASSIGN);
printk(KERN_INFO "Reassigning vector %d to %d\n", vector, new_vector);
memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector],
sizeof(struct iosapic_intr_info));
memset(&iosapic_intr_info[vector], 0, sizeof(struct
iosapic_intr_info));
- iosapic_intr_info[vector].rte_index = -1;
+ INIT_LIST_HEAD(&iosapic_intr_info[vector].pin_head);
}
}

static void
register_intr (unsigned int gsi, int vector, unsigned char delivery,
- unsigned long polarity, unsigned long trigger)
+ unsigned long polarity, unsigned long trigger, unsigned long type)
{
irq_desc_t *idesc;
struct hw_interrupt_type *irq_type;
@@ -458,6 +519,7 @@
int index;
unsigned long gsi_base;
char *iosapic_address;
+ struct iosapic_pin *pin, *tmp;

index = find_iosapic(gsi);
if (index < 0) {
@@ -468,13 +530,86 @@
iosapic_address = iosapic_lists[index].addr;
gsi_base = iosapic_lists[index].gsi_base;

- rte_index = gsi - gsi_base;
- iosapic_intr_info[vector].rte_index = rte_index;
- iosapic_intr_info[vector].polarity = polarity;
- iosapic_intr_info[vector].dmode = delivery;
- iosapic_intr_info[vector].addr = iosapic_address;
- iosapic_intr_info[vector].gsi_base = gsi_base;
- iosapic_intr_info[vector].trigger = trigger;
+ /*
+ * Only interrupt sources whose delivery mode is IOSAPIC_LOWEST_PRIORITY
or
+ * IOSAPIC_FIXED can share the vector in the current implementation.
+ */
+ if (delivery != IOSAPIC_LOWEST_PRIORITY &&
+ delivery != IOSAPIC_FIXED &&
+ type != IOSAPIC_VECTOR_EXCLUSIVE)
+ {
+ type = IOSAPIC_VECTOR_EXCLUSIVE;
+ }
+
+ pin = NULL;
+ list_for_each_entry(tmp, &iosapic_intr_info[vector].pin_head, pin_list) {
+ if (tmp->gsi_base + tmp->rte_index == gsi) {
+ pin = tmp;
+ break;
+ }
+ }
+
+ if (!pin) {
+ /*
+ * Register a new interrupt
+ */
+ if (!iosapic_intr_info[vector].count) {
+ pin = &iosapic_intr_info[vector].pin;
+ iosapic_intr_info[vector].dmode = delivery;
+ iosapic_intr_info[vector].trigger = trigger;
+ iosapic_intr_info[vector].type = type;
+ }
+ else if (type == IOSAPIC_VECTOR_EXCLUSIVE) {
+ printk (KERN_WARNING "%s: vector %d is in use\n", __FUNCTION__,
vector);
+ return;
+ }
+ else if (iosapic_intr_info[vector].type == IOSAPIC_VECTOR_EXCLUSIVE) {
+ printk (KERN_WARNING "%s: cannot share the vector %d\n",
__FUNCTION__, vector);
+ return;
+ }
+ else {
+ pin = kmalloc(sizeof(struct iosapic_pin), GFP_KERNEL);
+ if (!pin) {
+ printk (KERN_WARNING "%s: cannot allocate memory\n", __FUNCTION__);
+ return;
+ }
+ }
+
+ rte_index = gsi - gsi_base;
+ pin->rte_index = rte_index;
+ pin->polarity = polarity;
+ pin->addr = iosapic_address;
+ pin->gsi_base = gsi_base;
+ pin->low32 = IOSAPIC_MASK;
+
+ list_add_tail(&pin->pin_list, &iosapic_intr_info[vector].pin_head);
+ iosapic_intr_info[vector].count++;
+ }
+ else {
+ /*
+ * Override a existing interupt
+ */
+ if (iosapic_intr_info[vector].count > 1) {
+ if (iosapic_intr_info[vector].trigger != trigger) {
+ printk (KERN_WARNING "%s: cannot change trigger mode\n",
__FUNCTION__);
+ return;
+ }
+ if (type == IOSAPIC_VECTOR_EXCLUSIVE) {
+ printk (KERN_WARNING "%s: vector %d is already shared\n",
__FUNCTION__, vector);
+ return;
+ }
+ }
+
+ rte_index = gsi - gsi_base;
+ pin->rte_index = rte_index;
+ pin->polarity = polarity;
+ pin->addr = iosapic_address;
+ pin->gsi_base = gsi_base;
+ pin->low32 = IOSAPIC_MASK;
+ iosapic_intr_info[vector].dmode = delivery;
+ iosapic_intr_info[vector].trigger = trigger;
+ iosapic_intr_info[vector].type = type;
+ }

if (trigger == IOSAPIC_EDGE)
irq_type = &irq_type_iosapic_edge;
@@ -504,10 +639,17 @@

vector = gsi_to_vector(gsi);
if (vector < 0)
- vector = assign_irq_vector(AUTO_ASSIGN);
+ vector = assign_irq_vector_nopanic(AUTO_ASSIGN);
+
+ if (vector < 0)
+ vector = iosapic_find_sharable_vector(trigger);
+
+ if (vector < 0)
+ panic ("%s: out of interrupt vectors!", __FUNCTION__);

register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
- polarity, trigger);
+ polarity, trigger,
+ (trigger == IOSAPIC_EDGE ? IOSAPIC_VECTOR_EXCLUSIVE :
IOSAPIC_VECTOR_SHARABLE));

printk(KERN_INFO "GSI 0x%x(%s,%s) -> CPU 0x%04x vector %d\n",
gsi, (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
@@ -555,7 +697,7 @@
}

register_intr(gsi, vector, delivery, polarity,
- trigger);
+ trigger, IOSAPIC_VECTOR_EXCLUSIVE);

printk(KERN_INFO "PLATFORM int 0x%x: GSI 0x%x(%s,%s) -> CPU 0x%04x vector
%d\n",
int_type, gsi, (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
@@ -581,7 +723,7 @@

vector = isa_irq_to_vector(isa_irq);

- register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, polarity, trigger);
+ register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, polarity, trigger,
IOSAPIC_VECTOR_EXCLUSIVE);

DBG("ISA: IRQ %u -> GSI 0x%x (%s,%s) -> CPU 0x%04x vector %d\n",
isa_irq, gsi, polarity == IOSAPIC_POL_HIGH ? "high" : "low",
@@ -596,8 +738,10 @@
{
int vector;

- for (vector = 0; vector < IA64_NUM_VECTORS; ++vector)
- iosapic_intr_info[vector].rte_index = -1; /* mark as unused */
+ for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) {
+ iosapic_intr_info[vector].count = 0; /* mark as unused */
+ INIT_LIST_HEAD(&iosapic_intr_info[vector].pin_head);
+ }

pcat_compat = system_pcat_compat;
if (pcat_compat) {
@@ -710,12 +854,17 @@
/* allocate a vector for this interrupt line */
if (pcat_compat && (gsi < 16))
vector = isa_irq_to_vector(gsi);
- else
+ else {
/* new GSI; allocate a vector for it */
- vector = assign_irq_vector(AUTO_ASSIGN);
+ vector = assign_irq_vector_nopanic(AUTO_ASSIGN);
+ if (vector < 0)
+ vector = iosapic_find_sharable_vector(IOSAPIC_LEVEL);
+ if (vector < 0)
+ panic ("%s: out of interrupt vectors!", __FUNCTION__);
+ }

register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, IOSAPIC_POL_LOW,
- IOSAPIC_LEVEL);
+ IOSAPIC_LEVEL, IOSAPIC_VECTOR_SHARABLE);
}
entry->irq = vector;
snprintf(pci_id, sizeof(pci_id), "%02x:%02x:%02x[%c]",
@@ -728,7 +877,7 @@
idesc = irq_descp(vector);
if (idesc->handler != irq_type)
register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, IOSAPIC_POL_LOW,
- IOSAPIC_LEVEL);
+ IOSAPIC_LEVEL, IOSAPIC_VECTOR_SHARABLE);

}
}
diff -Naur linux-2.6.6-rc1/arch/ia64/kernel/irq.c
linux-2.6.6-rc1-changed/arch/ia64/kernel/irq.c
--- linux-2.6.6-rc1/arch/ia64/kernel/irq.c 2004-04-04 12:38:13.000000000
+0900
+++ linux-2.6.6-rc1-changed/arch/ia64/kernel/irq.c 2004-04-19
16:10:53.513448673 +0900
@@ -935,6 +935,11 @@
}
}

+cpumask_t get_irq_affinity_info (unsigned int irq)
+{
+ return irq_affinity[irq];
+}
+
static int irq_affinity_read_proc (char *page, char **start, off_t off,
int count, int *eof, void *data)
{
diff -Naur linux-2.6.6-rc1/arch/ia64/kernel/irq_ia64.c
linux-2.6.6-rc1-changed/arch/ia64/kernel/irq_ia64.c
--- linux-2.6.6-rc1/arch/ia64/kernel/irq_ia64.c 2004-04-19
16:10:25.971323555 +0900
+++ linux-2.6.6-rc1-changed/arch/ia64/kernel/irq_ia64.c 2004-04-19
16:10:53.513448673 +0900
@@ -72,17 +72,25 @@
preempt_enable_no_resched();
}

+static int next_vector = IA64_FIRST_DEVICE_VECTOR;
+
int
assign_irq_vector (int irq)
{
- static int next_vector = IA64_FIRST_DEVICE_VECTOR;
-
if (next_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++;
}

+int
+assign_irq_vector_nopanic (int irq)
+{
+ if (next_vector > IA64_LAST_DEVICE_VECTOR)
+ return -1;
+ return next_vector++;
+}
+
extern unsigned int do_IRQ(unsigned long irq, struct pt_regs *regs);

/*
diff -Naur linux-2.6.6-rc1/include/asm-ia64/hw_irq.h
linux-2.6.6-rc1-changed/include/asm-ia64/hw_irq.h
--- linux-2.6.6-rc1/include/asm-ia64/hw_irq.h 2004-04-19 16:10:27.139297942
+0900
+++ linux-2.6.6-rc1-changed/include/asm-ia64/hw_irq.h 2004-04-19
16:10:53.514425240 +0900
@@ -83,6 +83,7 @@
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 int assign_irq_vector_nopanic (int irq);
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);

diff -Naur linux-2.6.6-rc1/include/asm-ia64/iosapic.h
linux-2.6.6-rc1-changed/include/asm-ia64/iosapic.h
--- linux-2.6.6-rc1/include/asm-ia64/iosapic.h 2004-04-04
12:37:23.000000000 +0900
+++ linux-2.6.6-rc1-changed/include/asm-ia64/iosapic.h 2004-04-19
16:10:53.514425240 +0900
@@ -49,6 +49,12 @@
#define IOSAPIC_MASK_SHIFT 16
#define IOSAPIC_MASK (1<<IOSAPIC_MASK_SHIFT)

+/*
+ * Vector type
+ */
+#define IOSAPIC_VECTOR_EXCLUSIVE (0)
+#define IOSAPIC_VECTOR_SHARABLE (1)
+
#ifndef __ASSEMBLY__

#ifdef CONFIG_IOSAPIC
diff -Naur linux-2.6.6-rc1/include/asm-ia64/irq.h
linux-2.6.6-rc1-changed/include/asm-ia64/irq.h
--- linux-2.6.6-rc1/include/asm-ia64/irq.h 2004-04-19 16:10:27.140274509
+0900
+++ linux-2.6.6-rc1-changed/include/asm-ia64/irq.h 2004-04-19
16:10:53.514425240 +0900
@@ -29,6 +29,10 @@
extern void disable_irq_nosync (unsigned int);
extern void enable_irq (unsigned int);
extern void set_irq_affinity_info (unsigned int irq, int dest, int redir);
+#ifdef CONFIG_SMP
+#include <asm/cpumask.h>
+extern cpumask_t get_irq_affinity_info (unsigned int irq);
+#endif /* CONFIG_SMP */

struct irqaction;
struct pt_regs;

[-- Attachment #2: share_vector.patch --]
[-- Type: application/octet-stream, Size: 20070 bytes --]

diff -Naur linux-2.6.6-rc1/arch/ia64/kernel/iosapic.c linux-2.6.6-rc1-changed/arch/ia64/kernel/iosapic.c
--- linux-2.6.6-rc1/arch/ia64/kernel/iosapic.c 2004-04-19 16:10:25.970346988 +0900
+++ linux-2.6.6-rc1-changed/arch/ia64/kernel/iosapic.c 2004-04-19 16:25:23.251036926 +0900
@@ -101,15 +101,23 @@

/* These tables map IA-64 vectors to the IOSAPIC pin that generates this vector. */

-static struct iosapic_intr_info {
+struct iosapic_pin {
+ struct list_head pin_list; /* IOSAPIC pins which share the same vector */
char *addr; /* base address of IOSAPIC */
u32 low32; /* current value of low word of Redirection table entry */
unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */
- char rte_index; /* IOSAPIC RTE index (-1 => not an IOSAPIC interrupt) */
- unsigned char dmode : 3; /* delivery mode (see iosapic.h) */
+ char rte_index; /* IOSAPIC RTE index */
unsigned char polarity: 1; /* interrupt polarity (see iosapic.h) */
+};
+
+static struct iosapic_intr_info {
+ struct list_head pin_head; /* List head of IOSAPIC pins */
+ struct iosapic_pin pin; /* First entry of IOSAPIC pins list */
+ int count; /* # of pins (0 => not an IOSAPIC interrupt) */
+ unsigned char dmode : 3; /* delivery mode (see iosapic.h) */
unsigned char trigger : 1; /* trigger mode (see iosapic.h) */
-} iosapic_intr_info[IA64_NUM_VECTORS];
+ unsigned char type : 1; /* Vector type */
+} iosapic_intr_info[IA64_NUM_VECTORS] __cacheline_aligned;

static struct iosapic {
char *addr; /* base address of IOSAPIC */
@@ -142,10 +150,14 @@
_gsi_to_vector (unsigned int gsi)
{
struct iosapic_intr_info *info;
+ struct iosapic_pin *pin;

- for (info = iosapic_intr_info; info < iosapic_intr_info + IA64_NUM_VECTORS; ++info)
- if (info->gsi_base + info->rte_index == gsi)
- return info - iosapic_intr_info;
+ for (info = iosapic_intr_info; info < iosapic_intr_info + IA64_NUM_VECTORS; ++info) {
+ list_for_each_entry(pin, &info->pin_head, pin_list) {
+ if (pin->gsi_base + pin->rte_index == gsi)
+ return info - iosapic_intr_info;
+ }
+ }
return -1;
}

@@ -177,15 +189,13 @@
char *addr;
int rte_index;
char redir;
+ struct iosapic_pin *pin;

DBG(KERN_DEBUG"IOSAPIC: routing vector %d to 0x%x\n", vector, dest);

- rte_index = iosapic_intr_info[vector].rte_index;
- if (rte_index < 0)
+ if (!iosapic_intr_info[vector].count)
return; /* not an IOSAPIC interrupt */

- addr = iosapic_intr_info[vector].addr;
- pol = iosapic_intr_info[vector].polarity;
trigger = iosapic_intr_info[vector].trigger;
dmode = iosapic_intr_info[vector].dmode;

@@ -193,31 +203,47 @@
#ifdef CONFIG_SMP
{
unsigned int irq;
+ cpumask_t cpumask;

for (irq = 0; irq < NR_IRQS; ++irq)
if (irq_to_vector(irq) == vector) {
- set_irq_affinity_info(irq, (int)(dest & 0xffff), redir);
+ /* All pins should use the same destination CPU */
+ cpumask = get_irq_affinity_info(irq);
+ if (cpumask != CPU_MASK_ALL)
+ dest = cpu_physical_id(first_cpu(mask));
+ else
+ set_irq_affinity_info(irq, (int)(dest & 0xffff), redir);
break;
}
}
#endif

- low32 = ((pol << IOSAPIC_POLARITY_SHIFT) |
- (trigger << IOSAPIC_TRIGGER_SHIFT) |
- (dmode << IOSAPIC_DELIVERY_SHIFT) |
- ((mask ? 1 : 0) << IOSAPIC_MASK_SHIFT) |
- vector);
-
/* dest contains both id and eid */
high32 = (dest << IOSAPIC_DEST_SHIFT);

spin_lock_irqsave(&iosapic_lock, flags);
{
- writel(IOSAPIC_RTE_HIGH(rte_index), addr + IOSAPIC_REG_SELECT);
- writel(high32, addr + IOSAPIC_WINDOW);
- writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
- writel(low32, addr + IOSAPIC_WINDOW);
- iosapic_intr_info[vector].low32 = low32;
+ list_for_each_entry(pin, &iosapic_intr_info[vector].pin_head, pin_list) {
+ /* Don't change RTE which is already unmasked */
+ if (!(pin->low32 & IOSAPIC_MASK))
+ continue;
+
+ rte_index = pin->rte_index;
+ addr = pin->addr;
+ pol = pin->polarity;
+
+ low32 = ((pol << IOSAPIC_POLARITY_SHIFT) |
+ (trigger << IOSAPIC_TRIGGER_SHIFT) |
+ (dmode << IOSAPIC_DELIVERY_SHIFT) |
+ ((mask ? 1 : 0) << IOSAPIC_MASK_SHIFT) |
+ vector);
+
+ writel(IOSAPIC_RTE_HIGH(rte_index), addr + IOSAPIC_REG_SELECT);
+ writel(high32, addr + IOSAPIC_WINDOW);
+ writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
+ writel(low32, addr + IOSAPIC_WINDOW);
+ pin->low32 = low32;
+ }
}
spin_unlock_irqrestore(&iosapic_lock, flags);
}
@@ -236,21 +262,24 @@
u32 low32;
int rte_index;
ia64_vector vec = irq_to_vector(irq);
+ struct iosapic_pin *pin;

- addr = iosapic_intr_info[vec].addr;
- rte_index = iosapic_intr_info[vec].rte_index;
-
- if (rte_index < 0)
+ if (!iosapic_intr_info[vec].count)
return; /* not an IOSAPIC interrupt! */

spin_lock_irqsave(&iosapic_lock, flags);
{
- writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
+ list_for_each_entry(pin, &iosapic_intr_info[vec].pin_head, pin_list) {
+ addr = pin->addr;
+ rte_index = pin->rte_index;
+
+ writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);

- /* set only the mask bit */
- low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK;
+ /* set only the mask bit */
+ low32 = pin->low32 |= IOSAPIC_MASK;

- writel(low32, addr + IOSAPIC_WINDOW);
+ writel(low32, addr + IOSAPIC_WINDOW);
+ }
}
spin_unlock_irqrestore(&iosapic_lock, flags);
}
@@ -263,17 +292,21 @@
u32 low32;
int rte_index;
ia64_vector vec = irq_to_vector(irq);
+ struct iosapic_pin *pin;

- addr = iosapic_intr_info[vec].addr;
- rte_index = iosapic_intr_info[vec].rte_index;
- if (rte_index < 0)
+ if (!iosapic_intr_info[vec].count)
return; /* not an IOSAPIC interrupt! */

spin_lock_irqsave(&iosapic_lock, flags);
{
- writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
- low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK;
- writel(low32, addr + IOSAPIC_WINDOW);
+ list_for_each_entry(pin, &iosapic_intr_info[vec].pin_head, pin_list) {
+ addr = pin->addr;
+ rte_index = pin->rte_index;
+
+ writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
+ low32 = pin->low32 &= ~IOSAPIC_MASK;
+ writel(low32, addr + IOSAPIC_WINDOW);
+ }
}
spin_unlock_irqrestore(&iosapic_lock, flags);
}
@@ -289,6 +322,7 @@
char *addr;
int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0;
ia64_vector vec;
+ struct iosapic_pin *pin;

irq &= (~IA64_IRQ_REDIRECTED);
vec = irq_to_vector(irq);
@@ -298,10 +332,7 @@

dest = cpu_physical_id(first_cpu(mask));

- rte_index = iosapic_intr_info[vec].rte_index;
- addr = iosapic_intr_info[vec].addr;
-
- if (rte_index < 0)
+ if (!iosapic_intr_info[vec].count)
return; /* not an IOSAPIC interrupt */

set_irq_affinity_info(irq, dest, redir);
@@ -311,21 +342,26 @@

spin_lock_irqsave(&iosapic_lock, flags);
{
- /* get current delivery mode by reading the low32 */
- writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
- low32 = iosapic_intr_info[vec].low32 & ~(7 << IOSAPIC_DELIVERY_SHIFT);
- if (redir)
- /* change delivery mode to lowest priority */
- low32 |= (IOSAPIC_LOWEST_PRIORITY << IOSAPIC_DELIVERY_SHIFT);
- else
- /* change delivery mode to fixed */
- low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT);
-
- iosapic_intr_info[vec].low32 = low32;
- writel(IOSAPIC_RTE_HIGH(rte_index), addr + IOSAPIC_REG_SELECT);
- writel(high32, addr + IOSAPIC_WINDOW);
- writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
- writel(low32, addr + IOSAPIC_WINDOW);
+ list_for_each_entry(pin, &iosapic_intr_info[vec].pin_head, pin_list) {
+ rte_index = pin->rte_index;
+ addr = pin->addr;
+
+ /* get current delivery mode by reading the low32 */
+ writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
+ low32 = pin->low32 & ~(7 << IOSAPIC_DELIVERY_SHIFT);
+ if (redir)
+ /* change delivery mode to lowest priority */
+ low32 |= (IOSAPIC_LOWEST_PRIORITY << IOSAPIC_DELIVERY_SHIFT);
+ else
+ /* change delivery mode to fixed */
+ low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT);
+
+ pin->low32 = low32;
+ writel(IOSAPIC_RTE_HIGH(rte_index), addr + IOSAPIC_REG_SELECT);
+ writel(high32, addr + IOSAPIC_WINDOW);
+ writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
+ writel(low32, addr + IOSAPIC_WINDOW);
+ }
}
spin_unlock_irqrestore(&iosapic_lock, flags);
#endif
@@ -346,8 +382,11 @@
iosapic_end_level_irq (unsigned int irq)
{
ia64_vector vec = irq_to_vector(irq);
+ struct iosapic_pin *pin;

- writel(vec, iosapic_intr_info[vec].addr + IOSAPIC_EOI);
+ list_for_each_entry(pin, &iosapic_intr_info[vec].pin_head, pin_list) {
+ writel(vec, pin->addr + IOSAPIC_EOI);
+ }
}

#define iosapic_shutdown_level_irq mask_irq
@@ -427,6 +466,30 @@
}

/*
+ * Find a sharable vector.
+ *
+ * NOTE: This function assumes that platform interrupt doesn't share
+ * the vector.
+ */
+static int
+iosapic_find_sharable_vector (unsigned long trigger)
+{
+ int i;
+ static int next_vector = IA64_FIRST_DEVICE_VECTOR;
+
+ for (i = 0; i < IA64_LAST_DEVICE_VECTOR - IA64_FIRST_DEVICE_VECTOR + 1; i++) {
+ if (next_vector > IA64_LAST_DEVICE_VECTOR)
+ next_vector = IA64_FIRST_DEVICE_VECTOR;
+
+ if (iosapic_intr_info[next_vector].type == IOSAPIC_VECTOR_SHARABLE &&
+ iosapic_intr_info[next_vector].trigger == trigger)
+ return next_vector++;
+ }
+
+ return -1;
+}
+
+/*
* if the given vector is already owned by other,
* assign a new vector for the other and make the vector available
*/
@@ -435,22 +498,20 @@
{
int new_vector;

- if (iosapic_intr_info[vector].rte_index >= 0 || iosapic_intr_info[vector].addr
- || iosapic_intr_info[vector].gsi_base || iosapic_intr_info[vector].dmode
- || iosapic_intr_info[vector].polarity || iosapic_intr_info[vector].trigger)
+ if (!iosapic_intr_info[vector].count)
{
new_vector = assign_irq_vector(AUTO_ASSIGN);
printk(KERN_INFO "Reassigning vector %d to %d\n", vector, new_vector);
memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector],
sizeof(struct iosapic_intr_info));
memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info));
- iosapic_intr_info[vector].rte_index = -1;
+ INIT_LIST_HEAD(&iosapic_intr_info[vector].pin_head);
}
}

static void
register_intr (unsigned int gsi, int vector, unsigned char delivery,
- unsigned long polarity, unsigned long trigger)
+ unsigned long polarity, unsigned long trigger, unsigned long type)
{
irq_desc_t *idesc;
struct hw_interrupt_type *irq_type;
@@ -458,6 +519,7 @@
int index;
unsigned long gsi_base;
char *iosapic_address;
+ struct iosapic_pin *pin, *tmp;

index = find_iosapic(gsi);
if (index < 0) {
@@ -468,13 +530,86 @@
iosapic_address = iosapic_lists[index].addr;
gsi_base = iosapic_lists[index].gsi_base;

- rte_index = gsi - gsi_base;
- iosapic_intr_info[vector].rte_index = rte_index;
- iosapic_intr_info[vector].polarity = polarity;
- iosapic_intr_info[vector].dmode = delivery;
- iosapic_intr_info[vector].addr = iosapic_address;
- iosapic_intr_info[vector].gsi_base = gsi_base;
- iosapic_intr_info[vector].trigger = trigger;
+ /*
+ * Only interrupt sources whose delivery mode is IOSAPIC_LOWEST_PRIORITY or
+ * IOSAPIC_FIXED can share the vector in the current implementation.
+ */
+ if (delivery != IOSAPIC_LOWEST_PRIORITY &&
+ delivery != IOSAPIC_FIXED &&
+ type != IOSAPIC_VECTOR_EXCLUSIVE)
+ {
+ type = IOSAPIC_VECTOR_EXCLUSIVE;
+ }
+
+ pin = NULL;
+ list_for_each_entry(tmp, &iosapic_intr_info[vector].pin_head, pin_list) {
+ if (tmp->gsi_base + tmp->rte_index == gsi) {
+ pin = tmp;
+ break;
+ }
+ }
+
+ if (!pin) {
+ /*
+ * Register a new interrupt
+ */
+ if (!iosapic_intr_info[vector].count) {
+ pin = &iosapic_intr_info[vector].pin;
+ iosapic_intr_info[vector].dmode = delivery;
+ iosapic_intr_info[vector].trigger = trigger;
+ iosapic_intr_info[vector].type = type;
+ }
+ else if (type == IOSAPIC_VECTOR_EXCLUSIVE) {
+ printk (KERN_WARNING "%s: vector %d is in use\n", __FUNCTION__, vector);
+ return;
+ }
+ else if (iosapic_intr_info[vector].type == IOSAPIC_VECTOR_EXCLUSIVE) {
+ printk (KERN_WARNING "%s: cannot share the vector %d\n", __FUNCTION__, vector);
+ return;
+ }
+ else {
+ pin = kmalloc(sizeof(struct iosapic_pin), GFP_KERNEL);
+ if (!pin) {
+ printk (KERN_WARNING "%s: cannot allocate memory\n", __FUNCTION__);
+ return;
+ }
+ }
+
+ rte_index = gsi - gsi_base;
+ pin->rte_index = rte_index;
+ pin->polarity = polarity;
+ pin->addr = iosapic_address;
+ pin->gsi_base = gsi_base;
+ pin->low32 = IOSAPIC_MASK;
+
+ list_add_tail(&pin->pin_list, &iosapic_intr_info[vector].pin_head);
+ iosapic_intr_info[vector].count++;
+ }
+ else {
+ /*
+ * Override a existing interupt
+ */
+ if (iosapic_intr_info[vector].count > 1) {
+ if (iosapic_intr_info[vector].trigger != trigger) {
+ printk (KERN_WARNING "%s: cannot change trigger mode\n", __FUNCTION__);
+ return;
+ }
+ if (type == IOSAPIC_VECTOR_EXCLUSIVE) {
+ printk (KERN_WARNING "%s: vector %d is already shared\n", __FUNCTION__, vector);
+ return;
+ }
+ }
+
+ rte_index = gsi - gsi_base;
+ pin->rte_index = rte_index;
+ pin->polarity = polarity;
+ pin->addr = iosapic_address;
+ pin->gsi_base = gsi_base;
+ pin->low32 = IOSAPIC_MASK;
+ iosapic_intr_info[vector].dmode = delivery;
+ iosapic_intr_info[vector].trigger = trigger;
+ iosapic_intr_info[vector].type = type;
+ }

if (trigger == IOSAPIC_EDGE)
irq_type = &irq_type_iosapic_edge;
@@ -504,10 +639,17 @@

vector = gsi_to_vector(gsi);
if (vector < 0)
- vector = assign_irq_vector(AUTO_ASSIGN);
+ vector = assign_irq_vector_nopanic(AUTO_ASSIGN);
+
+ if (vector < 0)
+ vector = iosapic_find_sharable_vector(trigger);
+
+ if (vector < 0)
+ panic ("%s: out of interrupt vectors!", __FUNCTION__);

register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
- polarity, trigger);
+ polarity, trigger,
+ (trigger == IOSAPIC_EDGE ? IOSAPIC_VECTOR_EXCLUSIVE : IOSAPIC_VECTOR_SHARABLE));

printk(KERN_INFO "GSI 0x%x(%s,%s) -> CPU 0x%04x vector %d\n",
gsi, (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
@@ -555,7 +697,7 @@
}

register_intr(gsi, vector, delivery, polarity,
- trigger);
+ trigger, IOSAPIC_VECTOR_EXCLUSIVE);

printk(KERN_INFO "PLATFORM int 0x%x: GSI 0x%x(%s,%s) -> CPU 0x%04x vector %d\n",
int_type, gsi, (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
@@ -581,7 +723,7 @@

vector = isa_irq_to_vector(isa_irq);

- register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, polarity, trigger);
+ register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, polarity, trigger, IOSAPIC_VECTOR_EXCLUSIVE);

DBG("ISA: IRQ %u -> GSI 0x%x (%s,%s) -> CPU 0x%04x vector %d\n",
isa_irq, gsi, polarity == IOSAPIC_POL_HIGH ? "high" : "low",
@@ -596,8 +738,10 @@
{
int vector;

- for (vector = 0; vector < IA64_NUM_VECTORS; ++vector)
- iosapic_intr_info[vector].rte_index = -1; /* mark as unused */
+ for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) {
+ iosapic_intr_info[vector].count = 0; /* mark as unused */
+ INIT_LIST_HEAD(&iosapic_intr_info[vector].pin_head);
+ }

pcat_compat = system_pcat_compat;
if (pcat_compat) {
@@ -710,12 +854,17 @@
/* allocate a vector for this interrupt line */
if (pcat_compat && (gsi < 16))
vector = isa_irq_to_vector(gsi);
- else
+ else {
/* new GSI; allocate a vector for it */
- vector = assign_irq_vector(AUTO_ASSIGN);
+ vector = assign_irq_vector_nopanic(AUTO_ASSIGN);
+ if (vector < 0)
+ vector = iosapic_find_sharable_vector(IOSAPIC_LEVEL);
+ if (vector < 0)
+ panic ("%s: out of interrupt vectors!", __FUNCTION__);
+ }

register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, IOSAPIC_POL_LOW,
- IOSAPIC_LEVEL);
+ IOSAPIC_LEVEL, IOSAPIC_VECTOR_SHARABLE);
}
entry->irq = vector;
snprintf(pci_id, sizeof(pci_id), "%02x:%02x:%02x[%c]",
@@ -728,7 +877,7 @@
idesc = irq_descp(vector);
if (idesc->handler != irq_type)
register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, IOSAPIC_POL_LOW,
- IOSAPIC_LEVEL);
+ IOSAPIC_LEVEL, IOSAPIC_VECTOR_SHARABLE);

}
}
diff -Naur linux-2.6.6-rc1/arch/ia64/kernel/irq.c linux-2.6.6-rc1-changed/arch/ia64/kernel/irq.c
--- linux-2.6.6-rc1/arch/ia64/kernel/irq.c 2004-04-04 12:38:13.000000000 +0900
+++ linux-2.6.6-rc1-changed/arch/ia64/kernel/irq.c 2004-04-19 16:10:53.513448673 +0900
@@ -935,6 +935,11 @@
}
}

+cpumask_t get_irq_affinity_info (unsigned int irq)
+{
+ return irq_affinity[irq];
+}
+
static int irq_affinity_read_proc (char *page, char **start, off_t off,
int count, int *eof, void *data)
{
diff -Naur linux-2.6.6-rc1/arch/ia64/kernel/irq_ia64.c linux-2.6.6-rc1-changed/arch/ia64/kernel/irq_ia64.c
--- linux-2.6.6-rc1/arch/ia64/kernel/irq_ia64.c 2004-04-19 16:10:25.971323555 +0900
+++ linux-2.6.6-rc1-changed/arch/ia64/kernel/irq_ia64.c 2004-04-19 16:10:53.513448673 +0900
@@ -72,17 +72,25 @@
preempt_enable_no_resched();
}

+static int next_vector = IA64_FIRST_DEVICE_VECTOR;
+
int
assign_irq_vector (int irq)
{
- static int next_vector = IA64_FIRST_DEVICE_VECTOR;
-
if (next_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++;
}

+int
+assign_irq_vector_nopanic (int irq)
+{
+ if (next_vector > IA64_LAST_DEVICE_VECTOR)
+ return -1;
+ return next_vector++;
+}
+
extern unsigned int do_IRQ(unsigned long irq, struct pt_regs *regs);

/*
diff -Naur linux-2.6.6-rc1/include/asm-ia64/hw_irq.h linux-2.6.6-rc1-changed/include/asm-ia64/hw_irq.h
--- linux-2.6.6-rc1/include/asm-ia64/hw_irq.h 2004-04-19 16:10:27.139297942 +0900
+++ linux-2.6.6-rc1-changed/include/asm-ia64/hw_irq.h 2004-04-19 16:10:53.514425240 +0900
@@ -83,6 +83,7 @@
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 int assign_irq_vector_nopanic (int irq);
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);

diff -Naur linux-2.6.6-rc1/include/asm-ia64/iosapic.h linux-2.6.6-rc1-changed/include/asm-ia64/iosapic.h
--- linux-2.6.6-rc1/include/asm-ia64/iosapic.h 2004-04-04 12:37:23.000000000 +0900
+++ linux-2.6.6-rc1-changed/include/asm-ia64/iosapic.h 2004-04-19 16:10:53.514425240 +0900
@@ -49,6 +49,12 @@
#define IOSAPIC_MASK_SHIFT 16
#define IOSAPIC_MASK (1<<IOSAPIC_MASK_SHIFT)

+/*
+ * Vector type
+ */
+#define IOSAPIC_VECTOR_EXCLUSIVE (0)
+#define IOSAPIC_VECTOR_SHARABLE (1)
+
#ifndef __ASSEMBLY__

#ifdef CONFIG_IOSAPIC
diff -Naur linux-2.6.6-rc1/include/asm-ia64/irq.h linux-2.6.6-rc1-changed/include/asm-ia64/irq.h
--- linux-2.6.6-rc1/include/asm-ia64/irq.h 2004-04-19 16:10:27.140274509 +0900
+++ linux-2.6.6-rc1-changed/include/asm-ia64/irq.h 2004-04-19 16:10:53.514425240 +0900
@@ -29,6 +29,10 @@
extern void disable_irq_nosync (unsigned int);
extern void enable_irq (unsigned int);
extern void set_irq_affinity_info (unsigned int irq, int dest, int redir);
+#ifdef CONFIG_SMP
+#include <asm/cpumask.h>
+extern cpumask_t get_irq_affinity_info (unsigned int irq);
+#endif /* CONFIG_SMP */

struct irqaction;
struct pt_regs;