Commit c1726d6f authored by Yasuaki Ishimatsu's avatar Yasuaki Ishimatsu Committed by Tony Luck

[IA64] Use per iosapic lock for indirect iosapic register access

Use per-iosapic lock for indirect iosapic register access. It reduces
lock contention.
Signed-off-by: default avatarKenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: default avatarYasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
Signed-off-by: default avatarTony Luck <tony.luck@intel.com>
parent 40598cbe
...@@ -125,6 +125,7 @@ static struct iosapic { ...@@ -125,6 +125,7 @@ static struct iosapic {
#ifdef CONFIG_NUMA #ifdef CONFIG_NUMA
unsigned short node; /* numa node association via pxm */ unsigned short node; /* numa node association via pxm */
#endif #endif
spinlock_t lock; /* lock for indirect reg access */
} iosapic_lists[NR_IOSAPICS]; } iosapic_lists[NR_IOSAPICS];
struct iosapic_rte_info { struct iosapic_rte_info {
...@@ -153,6 +154,16 @@ static unsigned char pcat_compat __devinitdata; /* 8259 compatibility flag */ ...@@ -153,6 +154,16 @@ static unsigned char pcat_compat __devinitdata; /* 8259 compatibility flag */
static int iosapic_kmalloc_ok; static int iosapic_kmalloc_ok;
static LIST_HEAD(free_rte_list); static LIST_HEAD(free_rte_list);
static inline void
iosapic_write(struct iosapic *iosapic, unsigned int reg, u32 val)
{
unsigned long flags;
spin_lock_irqsave(&iosapic->lock, flags);
__iosapic_write(iosapic->addr, reg, val);
spin_unlock_irqrestore(&iosapic->lock, flags);
}
/* /*
* Find an IOSAPIC associated with a GSI * Find an IOSAPIC associated with a GSI
*/ */
...@@ -226,7 +237,6 @@ set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask) ...@@ -226,7 +237,6 @@ set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask)
{ {
unsigned long pol, trigger, dmode; unsigned long pol, trigger, dmode;
u32 low32, high32; u32 low32, high32;
char __iomem *addr;
int rte_index; int rte_index;
char redir; char redir;
struct iosapic_rte_info *rte; struct iosapic_rte_info *rte;
...@@ -238,7 +248,6 @@ set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask) ...@@ -238,7 +248,6 @@ set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask)
return; /* not an IOSAPIC interrupt */ return; /* not an IOSAPIC interrupt */
rte_index = rte->rte_index; rte_index = rte->rte_index;
addr = rte->iosapic->addr;
pol = iosapic_intr_info[vector].polarity; pol = iosapic_intr_info[vector].polarity;
trigger = iosapic_intr_info[vector].trigger; trigger = iosapic_intr_info[vector].trigger;
dmode = iosapic_intr_info[vector].dmode; dmode = iosapic_intr_info[vector].dmode;
...@@ -268,8 +277,8 @@ set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask) ...@@ -268,8 +277,8 @@ set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask)
/* dest contains both id and eid */ /* dest contains both id and eid */
high32 = (dest << IOSAPIC_DEST_SHIFT); high32 = (dest << IOSAPIC_DEST_SHIFT);
iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32); iosapic_write(rte->iosapic, IOSAPIC_RTE_HIGH(rte_index), high32);
iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte_index), low32);
iosapic_intr_info[vector].low32 = low32; iosapic_intr_info[vector].low32 = low32;
iosapic_intr_info[vector].dest = dest; iosapic_intr_info[vector].dest = dest;
} }
...@@ -292,7 +301,7 @@ kexec_disable_iosapic(void) ...@@ -292,7 +301,7 @@ kexec_disable_iosapic(void)
iosapic_intr_info + IA64_NUM_VECTORS; ++info, ++vec) { iosapic_intr_info + IA64_NUM_VECTORS; ++info, ++vec) {
list_for_each_entry(rte, &info->rtes, list_for_each_entry(rte, &info->rtes,
rte_list) { rte_list) {
iosapic_write(rte->iosapic->addr, iosapic_write(rte->iosapic,
IOSAPIC_RTE_LOW(rte->rte_index), IOSAPIC_RTE_LOW(rte->rte_index),
IOSAPIC_MASK|vec); IOSAPIC_MASK|vec);
iosapic_eoi(rte->iosapic->addr, vec); iosapic_eoi(rte->iosapic->addr, vec);
...@@ -304,8 +313,6 @@ kexec_disable_iosapic(void) ...@@ -304,8 +313,6 @@ kexec_disable_iosapic(void)
static void static void
mask_irq (unsigned int irq) mask_irq (unsigned int irq)
{ {
unsigned long flags;
char __iomem *addr;
u32 low32; u32 low32;
int rte_index; int rte_index;
ia64_vector vec = irq_to_vector(irq); ia64_vector vec = irq_to_vector(irq);
...@@ -314,22 +321,17 @@ mask_irq (unsigned int irq) ...@@ -314,22 +321,17 @@ mask_irq (unsigned int irq)
if (list_empty(&iosapic_intr_info[vec].rtes)) if (list_empty(&iosapic_intr_info[vec].rtes))
return; /* not an IOSAPIC interrupt! */ return; /* not an IOSAPIC interrupt! */
spin_lock_irqsave(&iosapic_lock, flags);
/* set only the mask bit */ /* set only the mask bit */
low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK; low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK;
list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) { list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) {
addr = rte->iosapic->addr;
rte_index = rte->rte_index; rte_index = rte->rte_index;
iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte_index), low32);
} }
spin_unlock_irqrestore(&iosapic_lock, flags);
} }
static void static void
unmask_irq (unsigned int irq) unmask_irq (unsigned int irq)
{ {
unsigned long flags;
char __iomem *addr;
u32 low32; u32 low32;
int rte_index; int rte_index;
ia64_vector vec = irq_to_vector(irq); ia64_vector vec = irq_to_vector(irq);
...@@ -338,14 +340,11 @@ unmask_irq (unsigned int irq) ...@@ -338,14 +340,11 @@ unmask_irq (unsigned int irq)
if (list_empty(&iosapic_intr_info[vec].rtes)) if (list_empty(&iosapic_intr_info[vec].rtes))
return; /* not an IOSAPIC interrupt! */ return; /* not an IOSAPIC interrupt! */
spin_lock_irqsave(&iosapic_lock, flags);
low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK; low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK;
list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) { list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) {
addr = rte->iosapic->addr;
rte_index = rte->rte_index; rte_index = rte->rte_index;
iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte_index), low32);
} }
spin_unlock_irqrestore(&iosapic_lock, flags);
} }
...@@ -353,13 +352,12 @@ static void ...@@ -353,13 +352,12 @@ static void
iosapic_set_affinity (unsigned int irq, cpumask_t mask) iosapic_set_affinity (unsigned int irq, cpumask_t mask)
{ {
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
unsigned long flags;
u32 high32, low32; u32 high32, low32;
int dest, rte_index; int dest, rte_index;
char __iomem *addr;
int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0; int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0;
ia64_vector vec; ia64_vector vec;
struct iosapic_rte_info *rte; struct iosapic_rte_info *rte;
struct iosapic *iosapic;
irq &= (~IA64_IRQ_REDIRECTED); irq &= (~IA64_IRQ_REDIRECTED);
vec = irq_to_vector(irq); vec = irq_to_vector(irq);
...@@ -377,7 +375,6 @@ iosapic_set_affinity (unsigned int irq, cpumask_t mask) ...@@ -377,7 +375,6 @@ iosapic_set_affinity (unsigned int irq, cpumask_t mask)
/* dest contains both id and eid */ /* dest contains both id and eid */
high32 = dest << IOSAPIC_DEST_SHIFT; high32 = dest << IOSAPIC_DEST_SHIFT;
spin_lock_irqsave(&iosapic_lock, flags);
low32 = iosapic_intr_info[vec].low32 & ~(7 << IOSAPIC_DELIVERY_SHIFT); low32 = iosapic_intr_info[vec].low32 & ~(7 << IOSAPIC_DELIVERY_SHIFT);
if (redir) if (redir)
/* change delivery mode to lowest priority */ /* change delivery mode to lowest priority */
...@@ -389,12 +386,11 @@ iosapic_set_affinity (unsigned int irq, cpumask_t mask) ...@@ -389,12 +386,11 @@ iosapic_set_affinity (unsigned int irq, cpumask_t mask)
iosapic_intr_info[vec].low32 = low32; iosapic_intr_info[vec].low32 = low32;
iosapic_intr_info[vec].dest = dest; iosapic_intr_info[vec].dest = dest;
list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) { list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) {
addr = rte->iosapic->addr; iosapic = rte->iosapic;
rte_index = rte->rte_index; rte_index = rte->rte_index;
iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32); iosapic_write(iosapic, IOSAPIC_RTE_HIGH(rte_index), high32);
iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); iosapic_write(iosapic, IOSAPIC_RTE_LOW(rte_index), low32);
} }
spin_unlock_irqrestore(&iosapic_lock, flags);
#endif #endif
} }
...@@ -499,7 +495,7 @@ iosapic_version (char __iomem *addr) ...@@ -499,7 +495,7 @@ iosapic_version (char __iomem *addr)
* unsigned int reserved2 : 8; * unsigned int reserved2 : 8;
* } * }
*/ */
return iosapic_read(addr, IOSAPIC_VERSION); return __iosapic_read(addr, IOSAPIC_VERSION);
} }
static int iosapic_find_sharable_vector (unsigned long trigger, static int iosapic_find_sharable_vector (unsigned long trigger,
...@@ -857,8 +853,7 @@ iosapic_unregister_intr (unsigned int gsi) ...@@ -857,8 +853,7 @@ iosapic_unregister_intr (unsigned int gsi)
/* Mask the interrupt */ /* Mask the interrupt */
low32 = iosapic_intr_info[vector].low32 | IOSAPIC_MASK; low32 = iosapic_intr_info[vector].low32 | IOSAPIC_MASK;
iosapic_write(rte->iosapic->addr, iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte->rte_index), low32);
IOSAPIC_RTE_LOW(rte->rte_index), low32);
iosapic_intr_info[vector].count--; iosapic_intr_info[vector].count--;
iosapic_free_rte(rte); iosapic_free_rte(rte);
...@@ -1060,9 +1055,14 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base) ...@@ -1060,9 +1055,14 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&iosapic_lock, flags); spin_lock_irqsave(&iosapic_lock, flags);
index = find_iosapic(gsi_base);
if (index >= 0) {
spin_unlock_irqrestore(&iosapic_lock, flags);
return -EBUSY;
}
addr = ioremap(phys_addr, 0); addr = ioremap(phys_addr, 0);
ver = iosapic_version(addr); ver = iosapic_version(addr);
if ((err = iosapic_check_gsi_range(gsi_base, ver))) { if ((err = iosapic_check_gsi_range(gsi_base, ver))) {
iounmap(addr); iounmap(addr);
spin_unlock_irqrestore(&iosapic_lock, flags); spin_unlock_irqrestore(&iosapic_lock, flags);
...@@ -1083,6 +1083,7 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base) ...@@ -1083,6 +1083,7 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
#ifdef CONFIG_NUMA #ifdef CONFIG_NUMA
iosapic_lists[index].node = MAX_NUMNODES; iosapic_lists[index].node = MAX_NUMNODES;
#endif #endif
spin_lock_init(&iosapic_lists[index].lock);
spin_unlock_irqrestore(&iosapic_lock, flags); spin_unlock_irqrestore(&iosapic_lock, flags);
if ((gsi_base == 0) && pcat_compat) { if ((gsi_base == 0) && pcat_compat) {
......
...@@ -53,13 +53,13 @@ ...@@ -53,13 +53,13 @@
#define NR_IOSAPICS 256 #define NR_IOSAPICS 256
static inline unsigned int iosapic_read(char __iomem *iosapic, unsigned int reg) static inline unsigned int __iosapic_read(char __iomem *iosapic, unsigned int reg)
{ {
writel(reg, iosapic + IOSAPIC_REG_SELECT); writel(reg, iosapic + IOSAPIC_REG_SELECT);
return readl(iosapic + IOSAPIC_WINDOW); return readl(iosapic + IOSAPIC_WINDOW);
} }
static inline void iosapic_write(char __iomem *iosapic, unsigned int reg, u32 val) static inline void __iosapic_write(char __iomem *iosapic, unsigned int reg, u32 val)
{ {
writel(reg, iosapic + IOSAPIC_REG_SELECT); writel(reg, iosapic + IOSAPIC_REG_SELECT);
writel(val, iosapic + IOSAPIC_WINDOW); writel(val, iosapic + IOSAPIC_WINDOW);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment