aboutsummaryrefslogtreecommitdiff
path: root/arch/ia64/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-27 10:05:42 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-27 10:05:42 -0700
commitfc67b16ecaf6ebde04096030c268adddade023f1 (patch)
tree1cce42cdca1fc9e4ec41b9f7f72c60e343cebca7 /arch/ia64/kernel
parente8108c98dd6d65613fa0ec9d2300f89c48d554bf (diff)
parent2d29306b231a1a0e7a70166c10e4c0f917b21334 (diff)
Automatic merge of rsync://rsync.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6.git
Diffstat (limited to 'arch/ia64/kernel')
-rw-r--r--arch/ia64/kernel/entry.S14
-rw-r--r--arch/ia64/kernel/iosapic.c358
-rw-r--r--arch/ia64/kernel/irq_ia64.c16
-rw-r--r--arch/ia64/kernel/perfmon.c59
-rw-r--r--arch/ia64/kernel/perfmon_default_smpl.c13
-rw-r--r--arch/ia64/kernel/setup.c69
-rw-r--r--arch/ia64/kernel/smpboot.c217
-rw-r--r--arch/ia64/kernel/unwind.c27
8 files changed, 619 insertions, 154 deletions
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
index 0272c010a3b..bd86fea49a0 100644
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -728,12 +728,8 @@ ENTRY(ia64_leave_syscall)
mov f8=f0 // clear f8
;;
ld8 r30=[r2],16 // M0|1 load cr.ifs
- mov.m ar.ssd=r0 // M2 clear ar.ssd
- cmp.eq p9,p0=r0,r0 // set p9 to indicate that we should restore cr.ifs
- ;;
ld8 r25=[r3],16 // M0|1 load ar.unat
- mov.m ar.csd=r0 // M2 clear ar.csd
- mov r22=r0 // clear r22
+ cmp.eq p9,p0=r0,r0 // set p9 to indicate that we should restore cr.ifs
;;
ld8 r26=[r2],PT(B0)-PT(AR_PFS) // M0|1 load ar.pfs
(pKStk) mov r22=psr // M2 read PSR now that interrupts are disabled
@@ -756,11 +752,15 @@ ENTRY(ia64_leave_syscall)
mov f7=f0 // clear f7
;;
ld8.fill r12=[r2] // restore r12 (sp)
+ mov.m ar.ssd=r0 // M2 clear ar.ssd
+ mov r22=r0 // clear r22
+
ld8.fill r15=[r3] // restore r15
+(pUStk) st1 [r14]=r17
addl r3=THIS_CPU(ia64_phys_stacked_size_p8),r0
;;
-(pUStk) ld4 r3=[r3] // r3 = cpu_data->phys_stacked_size_p8
-(pUStk) st1 [r14]=r17
+(pUStk) ld4 r17=[r3] // r17 = cpu_data->phys_stacked_size_p8
+ mov.m ar.csd=r0 // M2 clear ar.csd
mov b6=r18 // I0 restore b6
;;
mov r14=r0 // clear r14
diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c
index c15be5c38f5..88b014381df 100644
--- a/arch/ia64/kernel/iosapic.c
+++ b/arch/ia64/kernel/iosapic.c
@@ -79,6 +79,7 @@
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/string.h>
+#include <linux/bootmem.h>
#include <asm/delay.h>
#include <asm/hw_irq.h>
@@ -98,19 +99,30 @@
#define DBG(fmt...)
#endif
+#define NR_PREALLOCATE_RTE_ENTRIES (PAGE_SIZE / sizeof(struct iosapic_rte_info))
+#define RTE_PREALLOCATED (1)
+
static DEFINE_SPINLOCK(iosapic_lock);
/* These tables map IA-64 vectors to the IOSAPIC pin that generates this vector. */
-static struct iosapic_intr_info {
+struct iosapic_rte_info {
+ struct list_head rte_list; /* node in list of RTEs sharing the same vector */
char __iomem *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) */
+ char rte_index; /* IOSAPIC RTE index */
+ int refcnt; /* reference counter */
+ unsigned int flags; /* flags */
+} ____cacheline_aligned;
+
+static struct iosapic_intr_info {
+ struct list_head rtes; /* RTEs using this vector (empty => not an IOSAPIC interrupt) */
+ int count; /* # of RTEs that shares this vector */
+ u32 low32; /* current value of low word of Redirection table entry */
+ unsigned int dest; /* destination CPU physical ID */
unsigned char dmode : 3; /* delivery mode (see iosapic.h) */
unsigned char polarity: 1; /* interrupt polarity (see iosapic.h) */
unsigned char trigger : 1; /* trigger mode (see iosapic.h) */
- int refcnt; /* reference counter */
} iosapic_intr_info[IA64_NUM_VECTORS];
static struct iosapic {
@@ -126,6 +138,8 @@ static int num_iosapic;
static unsigned char pcat_compat __initdata; /* 8259 compatibility flag */
+static int iosapic_kmalloc_ok;
+static LIST_HEAD(free_rte_list);
/*
* Find an IOSAPIC associated with a GSI
@@ -147,10 +161,12 @@ static inline int
_gsi_to_vector (unsigned int gsi)
{
struct iosapic_intr_info *info;
+ struct iosapic_rte_info *rte;
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;
+ list_for_each_entry(rte, &info->rtes, rte_list)
+ if (rte->gsi_base + rte->rte_index == gsi)
+ return info - iosapic_intr_info;
return -1;
}
@@ -167,33 +183,52 @@ gsi_to_vector (unsigned int gsi)
int
gsi_to_irq (unsigned int gsi)
{
+ unsigned long flags;
+ int irq;
/*
* XXX fix me: this assumes an identity mapping vetween IA-64 vector and Linux irq
* numbers...
*/
- return _gsi_to_vector(gsi);
+ spin_lock_irqsave(&iosapic_lock, flags);
+ {
+ irq = _gsi_to_vector(gsi);
+ }
+ spin_unlock_irqrestore(&iosapic_lock, flags);
+
+ return irq;
+}
+
+static struct iosapic_rte_info *gsi_vector_to_rte(unsigned int gsi, unsigned int vec)
+{
+ struct iosapic_rte_info *rte;
+
+ list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list)
+ if (rte->gsi_base + rte->rte_index == gsi)
+ return rte;
+ return NULL;
}
static void
-set_rte (unsigned int vector, unsigned int dest, int mask)
+set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask)
{
unsigned long pol, trigger, dmode;
u32 low32, high32;
char __iomem *addr;
int rte_index;
char redir;
+ struct iosapic_rte_info *rte;
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)
+ rte = gsi_vector_to_rte(gsi, vector);
+ if (!rte)
return; /* not an IOSAPIC interrupt */
- addr = iosapic_intr_info[vector].addr;
+ rte_index = rte->rte_index;
+ addr = rte->addr;
pol = iosapic_intr_info[vector].polarity;
trigger = iosapic_intr_info[vector].trigger;
dmode = iosapic_intr_info[vector].dmode;
- vector &= (~IA64_IRQ_REDIRECTED);
redir = (dmode == IOSAPIC_LOWEST_PRIORITY) ? 1 : 0;
@@ -221,6 +256,7 @@ set_rte (unsigned int vector, unsigned int dest, int mask)
iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32);
iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
iosapic_intr_info[vector].low32 = low32;
+ iosapic_intr_info[vector].dest = dest;
}
static void
@@ -237,18 +273,20 @@ mask_irq (unsigned int irq)
u32 low32;
int rte_index;
ia64_vector vec = irq_to_vector(irq);
+ struct iosapic_rte_info *rte;
- addr = iosapic_intr_info[vec].addr;
- rte_index = iosapic_intr_info[vec].rte_index;
-
- if (rte_index < 0)
+ if (list_empty(&iosapic_intr_info[vec].rtes))
return; /* not an IOSAPIC interrupt! */
spin_lock_irqsave(&iosapic_lock, flags);
{
/* set only the mask bit */
low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK;
- iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
+ list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) {
+ addr = rte->addr;
+ rte_index = rte->rte_index;
+ iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
+ }
}
spin_unlock_irqrestore(&iosapic_lock, flags);
}
@@ -261,16 +299,19 @@ unmask_irq (unsigned int irq)
u32 low32;
int rte_index;
ia64_vector vec = irq_to_vector(irq);
+ struct iosapic_rte_info *rte;
- addr = iosapic_intr_info[vec].addr;
- rte_index = iosapic_intr_info[vec].rte_index;
- if (rte_index < 0)
+ if (list_empty(&iosapic_intr_info[vec].rtes))
return; /* not an IOSAPIC interrupt! */
spin_lock_irqsave(&iosapic_lock, flags);
{
low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK;
- iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
+ list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) {
+ addr = rte->addr;
+ rte_index = rte->rte_index;
+ iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
+ }
}
spin_unlock_irqrestore(&iosapic_lock, flags);
}
@@ -286,6 +327,7 @@ iosapic_set_affinity (unsigned int irq, cpumask_t mask)
char __iomem *addr;
int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0;
ia64_vector vec;
+ struct iosapic_rte_info *rte;
irq &= (~IA64_IRQ_REDIRECTED);
vec = irq_to_vector(irq);
@@ -295,10 +337,7 @@ iosapic_set_affinity (unsigned int irq, cpumask_t mask)
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 (list_empty(&iosapic_intr_info[vec].rtes))
return; /* not an IOSAPIC interrupt */
set_irq_affinity_info(irq, dest, redir);
@@ -318,8 +357,13 @@ iosapic_set_affinity (unsigned int irq, cpumask_t mask)
low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT);
iosapic_intr_info[vec].low32 = low32;
- iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32);
- iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
+ iosapic_intr_info[vec].dest = dest;
+ list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) {
+ addr = rte->addr;
+ rte_index = rte->rte_index;
+ iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32);
+ iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
+ }
}
spin_unlock_irqrestore(&iosapic_lock, flags);
#endif
@@ -340,9 +384,11 @@ static void
iosapic_end_level_irq (unsigned int irq)
{
ia64_vector vec = irq_to_vector(irq);
+ struct iosapic_rte_info *rte;
move_irq(irq);
- iosapic_eoi(iosapic_intr_info[vec].addr, vec);
+ list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list)
+ iosapic_eoi(rte->addr, vec);
}
#define iosapic_shutdown_level_irq mask_irq
@@ -422,6 +468,34 @@ iosapic_version (char __iomem *addr)
return iosapic_read(addr, IOSAPIC_VERSION);
}
+static int iosapic_find_sharable_vector (unsigned long trigger, unsigned long pol)
+{
+ int i, vector = -1, min_count = -1;
+ struct iosapic_intr_info *info;
+
+ /*
+ * shared vectors for edge-triggered interrupts are not
+ * supported yet
+ */
+ if (trigger == IOSAPIC_EDGE)
+ return -1;
+
+ for (i = IA64_FIRST_DEVICE_VECTOR; i <= IA64_LAST_DEVICE_VECTOR; i++) {
+ info = &iosapic_intr_info[i];
+ if (info->trigger == trigger && info->polarity == pol &&
+ (info->dmode == IOSAPIC_FIXED || info->dmode == IOSAPIC_LOWEST_PRIORITY)) {
+ if (min_count == -1 || info->count < min_count) {
+ vector = i;
+ min_count = info->count;
+ }
+ }
+ }
+ if (vector < 0)
+ panic("%s: out of interrupt vectors!\n", __FUNCTION__);
+
+ return vector;
+}
+
/*
* if the given vector is already owned by other,
* assign a new vector for the other and make the vector available
@@ -431,19 +505,63 @@ iosapic_reassign_vector (int vector)
{
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 (!list_empty(&iosapic_intr_info[vector].rtes)) {
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));
+ INIT_LIST_HEAD(&iosapic_intr_info[new_vector].rtes);
+ list_move(iosapic_intr_info[vector].rtes.next, &iosapic_intr_info[new_vector].rtes);
memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info));
- iosapic_intr_info[vector].rte_index = -1;
+ iosapic_intr_info[vector].low32 = IOSAPIC_MASK;
+ INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
}
}
+static struct iosapic_rte_info *iosapic_alloc_rte (void)
+{
+ int i;
+ struct iosapic_rte_info *rte;
+ int preallocated = 0;
+
+ if (!iosapic_kmalloc_ok && list_empty(&free_rte_list)) {
+ rte = alloc_bootmem(sizeof(struct iosapic_rte_info) * NR_PREALLOCATE_RTE_ENTRIES);
+ if (!rte)
+ return NULL;
+ for (i = 0; i < NR_PREALLOCATE_RTE_ENTRIES; i++, rte++)
+ list_add(&rte->rte_list, &free_rte_list);
+ }
+
+ if (!list_empty(&free_rte_list)) {
+ rte = list_entry(free_rte_list.next, struct iosapic_rte_info, rte_list);
+ list_del(&rte->rte_list);
+ preallocated++;
+ } else {
+ rte = kmalloc(sizeof(struct iosapic_rte_info), GFP_ATOMIC);
+ if (!rte)
+ return NULL;
+ }
+
+ memset(rte, 0, sizeof(struct iosapic_rte_info));
+ if (preallocated)
+ rte->flags |= RTE_PREALLOCATED;
+
+ return rte;
+}
+
+static void iosapic_free_rte (struct iosapic_rte_info *rte)
+{
+ if (rte->flags & RTE_PREALLOCATED)
+ list_add_tail(&rte->rte_list, &free_rte_list);
+ else
+ kfree(rte);
+}
+
+static inline int vector_is_shared (int vector)
+{
+ return (iosapic_intr_info[vector].count > 1);
+}
+
static void
register_intr (unsigned int gsi, int vector, unsigned char delivery,
unsigned long polarity, unsigned long trigger)
@@ -454,6 +572,7 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
int index;
unsigned long gsi_base;
void __iomem *iosapic_address;
+ struct iosapic_rte_info *rte;
index = find_iosapic(gsi);
if (index < 0) {
@@ -464,14 +583,33 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
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;
+ rte = gsi_vector_to_rte(gsi, vector);
+ if (!rte) {
+ rte = iosapic_alloc_rte();
+ if (!rte) {
+ printk(KERN_WARNING "%s: cannot allocate memory\n", __FUNCTION__);
+ return;
+ }
+
+ rte_index = gsi - gsi_base;
+ rte->rte_index = rte_index;
+ rte->addr = iosapic_address;
+ rte->gsi_base = gsi_base;
+ rte->refcnt++;
+ list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes);
+ iosapic_intr_info[vector].count++;
+ }
+ else if (vector_is_shared(vector)) {
+ struct iosapic_intr_info *info = &iosapic_intr_info[vector];
+ if (info->trigger != trigger || info->polarity != polarity) {
+ printk (KERN_WARNING "%s: cannot override the interrupt\n", __FUNCTION__);
+ return;
+ }
+ }
+
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;
- iosapic_intr_info[vector].refcnt++;
if (trigger == IOSAPIC_EDGE)
irq_type = &irq_type_iosapic_edge;
@@ -494,6 +632,13 @@ get_target_cpu (unsigned int gsi, int vector)
static int cpu = -1;
/*
+ * In case of vector shared by multiple RTEs, all RTEs that
+ * share the vector need to use the same destination CPU.
+ */
+ if (!list_empty(&iosapic_intr_info[vector].rtes))
+ return iosapic_intr_info[vector].dest;
+
+ /*
* If the platform supports redirection via XTP, let it
* distribute interrupts.
*/
@@ -565,10 +710,12 @@ int
iosapic_register_intr (unsigned int gsi,
unsigned long polarity, unsigned long trigger)
{
- int vector;
+ int vector, mask = 1;
unsigned int dest;
unsigned long flags;
-
+ struct iosapic_rte_info *rte;
+ u32 low32;
+again:
/*
* If this GSI has already been registered (i.e., it's a
* shared interrupt, or we lost a race to register it),
@@ -578,19 +725,45 @@ iosapic_register_intr (unsigned int gsi,
{
vector = gsi_to_vector(gsi);
if (vector > 0) {
- iosapic_intr_info[vector].refcnt++;
+ rte = gsi_vector_to_rte(gsi, vector);
+ rte->refcnt++;
spin_unlock_irqrestore(&iosapic_lock, flags);
return vector;
}
+ }
+ spin_unlock_irqrestore(&iosapic_lock, flags);
+
+ /* If vector is running out, we try to find a sharable vector */
+ vector = assign_irq_vector_nopanic(AUTO_ASSIGN);
+ if (vector < 0)
+ vector = iosapic_find_sharable_vector(trigger, polarity);
+
+ spin_lock_irqsave(&irq_descp(vector)->lock, flags);
+ spin_lock(&iosapic_lock);
+ {
+ if (gsi_to_vector(gsi) > 0) {
+ if (list_empty(&iosapic_intr_info[vector].rtes))
+ free_irq_vector(vector);
+ spin_unlock(&iosapic_lock);
+ spin_unlock_irqrestore(&irq_descp(vector)->lock, flags);
+ goto again;
+ }
- vector = assign_irq_vector(AUTO_ASSIGN);
dest = get_target_cpu(gsi, vector);
register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
- polarity, trigger);
+ polarity, trigger);
- set_rte(vector, dest, 1);
+ /*
+ * If the vector is shared and already unmasked for
+ * other interrupt sources, don't mask it.
+ */
+ low32 = iosapic_intr_info[vector].low32;
+ if (vector_is_shared(vector) && !(low32 & IOSAPIC_MASK))
+ mask = 0;
+ set_rte(gsi, vector, dest, mask);
}
- spin_unlock_irqrestore(&iosapic_lock, flags);
+ spin_unlock(&iosapic_lock);
+ spin_unlock_irqrestore(&irq_descp(vector)->lock, flags);
printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n",
gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
@@ -607,8 +780,10 @@ iosapic_unregister_intr (unsigned int gsi)
unsigned long flags;
int irq, vector;
irq_desc_t *idesc;
- int rte_index;
+ u32 low32;
unsigned long trigger, polarity;
+ unsigned int dest;
+ struct iosapic_rte_info *rte;
/*
* If the irq associated with the gsi is not found,
@@ -627,54 +802,56 @@ iosapic_unregister_intr (unsigned int gsi)
spin_lock_irqsave(&idesc->lock, flags);
spin_lock(&iosapic_lock);
{
- rte_index = iosapic_intr_info[vector].rte_index;
- if (rte_index < 0) {
- spin_unlock(&iosapic_lock);
- spin_unlock_irqrestore(&idesc->lock, flags);
+ if ((rte = gsi_vector_to_rte(gsi, vector)) == NULL) {
printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", gsi);
WARN_ON(1);
- return;
+ goto out;
}
- if (--iosapic_intr_info[vector].refcnt > 0) {
- spin_unlock(&iosapic_lock);
- spin_unlock_irqrestore(&idesc->lock, flags);
- return;
- }
+ if (--rte->refcnt > 0)
+ goto out;
- /*
- * If interrupt handlers still exist on the irq
- * associated with the gsi, don't unregister the
- * interrupt.
- */
- if (idesc->action) {
- iosapic_intr_info[vector].refcnt++;
- spin_unlock(&iosapic_lock);
- spin_unlock_irqrestore(&idesc->lock, flags);
- printk(KERN_WARNING "Cannot unregister GSI. IRQ %u is still in use.\n", irq);
- return;
- }
+ /* Mask the interrupt */
+ low32 = iosapic_intr_info[vector].low32 | IOSAPIC_MASK;
+ iosapic_write(rte->addr, IOSAPIC_RTE_LOW(rte->rte_index), low32);
- /* Clear the interrupt controller descriptor. */
- idesc->handler = &no_irq_type;
+ /* Remove the rte entry from the list */
+ list_del(&rte->rte_list);
+ iosapic_intr_info[vector].count--;
+ iosapic_free_rte(rte);
- trigger = iosapic_intr_info[vector].trigger;
+ trigger = iosapic_intr_info[vector].trigger;
polarity = iosapic_intr_info[vector].polarity;
+ dest = iosapic_intr_info[vector].dest;
+ printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d unregistered\n",
+ gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
+ (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
+ cpu_logical_id(dest), dest, vector);
+
+ if (list_empty(&iosapic_intr_info[vector].rtes)) {
+ /* Sanity check */
+ BUG_ON(iosapic_intr_info[vector].count);
+
+ /* Clear the interrupt controller descriptor */
+ idesc->handler = &no_irq_type;
+
+ /* Clear the interrupt information */
+ memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info));
+ iosapic_intr_info[vector].low32 |= IOSAPIC_MASK;
+ INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
+
+ if (idesc->action) {
+ printk(KERN_ERR "interrupt handlers still exist on IRQ %u\n", irq);
+ WARN_ON(1);
+ }
- /* Clear the interrupt information. */
- memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info));
- iosapic_intr_info[vector].rte_index = -1; /* mark as unused */
+ /* Free the interrupt vector */
+ free_irq_vector(vector);
+ }
}
+ out:
spin_unlock(&iosapic_lock);
spin_unlock_irqrestore(&idesc->lock, flags);
-
- /* Free the interrupt vector */
- free_irq_vector(vector);
-
- printk(KERN_INFO "GSI %u (%s, %s) -> vector %d unregisterd.\n",
- gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
- (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
- vector);
}
#endif /* CONFIG_ACPI_DEALLOCATE_IRQ */
@@ -724,7 +901,7 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
(polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
cpu_logical_id(dest), dest, vector);
- set_rte(vector, dest, mask);
+ set_rte(gsi, vector, dest, mask);
return vector;
}
@@ -750,7 +927,7 @@ iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
polarity == IOSAPIC_POL_HIGH ? "high" : "low",
cpu_logical_id(dest), dest, vector);
- set_rte(vector, dest, 1);
+ set_rte(gsi, vector, dest, 1);
}
void __init
@@ -758,8 +935,10 @@ iosapic_system_init (int system_pcat_compat)
{
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].low32 = IOSAPIC_MASK;
+ INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes); /* mark as unused */
+ }
pcat_compat = system_pcat_compat;
if (pcat_compat) {
@@ -825,3 +1004,10 @@ map_iosapic_to_node(unsigned int gsi_base, int node)
return;
}
#endif
+
+static int __init iosapic_enable_kmalloc (void)
+{
+ iosapic_kmalloc_ok = 1;
+ return 0;
+}
+core_initcall (iosapic_enable_kmalloc);
diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c
index 5ba06ebe355..4fe60c7a2e9 100644
--- a/arch/ia64/kernel/irq_ia64.c
+++ b/arch/ia64/kernel/irq_ia64.c
@@ -63,20 +63,30 @@ EXPORT_SYMBOL(isa_irq_to_vector_map);
static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_NUM_DEVICE_VECTORS)];
int
-assign_irq_vector (int irq)
+assign_irq_vector_nopanic (int irq)
{
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 -1;
if (test_and_set_bit(pos, ia64_vector_mask))
goto again;
return vector;
}
+int
+assign_irq_vector (int irq)
+{
+ int vector = assign_irq_vector_nopanic(irq);
+
+ if (vector < 0)
+ panic("assign_irq_vector: out of interrupt vectors!");
+
+ return vector;
+}
+
void
free_irq_vector (int vector)
{
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index 71147be3279..376fcbc3f8d 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -480,14 +480,6 @@ typedef struct {
#define PFM_CMD_ARG_MANY -1 /* cannot be zero */
typedef struct {
- int debug; /* turn on/off debugging via syslog */
- int debug_ovfl; /* turn on/off debug printk in overflow handler */
- int fastctxsw; /* turn on/off fast (unsecure) ctxsw */
- int expert_mode; /* turn on/off value checking */
- int debug_pfm_read;
-} pfm_sysctl_t;
-
-typedef struct {
unsigned long pfm_spurious_ovfl_intr_count; /* keep track of spurious ovfl interrupts */
unsigned long pfm_replay_ovfl_intr_count; /* keep track of replayed ovfl interrupts */
unsigned long pfm_ovfl_intr_count; /* keep track of ovfl interrupts */
@@ -514,8 +506,8 @@ static LIST_HEAD(pfm_buffer_fmt_list);
static pmu_config_t *pmu_conf;
/* sysctl() controls */
-static pfm_sysctl_t pfm_sysctl;
-int pfm_debug_var;
+pfm_sysctl_t pfm_sysctl;
+EXPORT_SYMBOL(pfm_sysctl);
static ctl_table pfm_ctl_table[]={
{1, "debug", &pfm_sysctl.debug, sizeof(int), 0666, NULL, &proc_dointvec, NULL,},
@@ -1576,7 +1568,7 @@ pfm_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
goto abort_locked;
}
- DPRINT(("[%d] fd=%d type=%d\n", current->pid, msg->pfm_gen_msg.msg_ctx_fd, msg->pfm_gen_msg.msg_type));
+ DPRINT(("fd=%d type=%d\n", msg->pfm_gen_msg.msg_ctx_fd, msg->pfm_gen_msg.msg_type));
ret = -EFAULT;
if(copy_to_user(buf, msg, sizeof(pfm_msg_t)) == 0) ret = sizeof(pfm_msg_t);
@@ -3695,8 +3687,6 @@ pfm_debug(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
pfm_sysctl.debug = m == 0 ? 0 : 1;
- pfm_debug_var = pfm_sysctl.debug;
-
printk(KERN_INFO "perfmon debugging %s (timing reset)\n", pfm_sysctl.debug ? "on" : "off");
if (m == 0) {
@@ -4996,13 +4986,21 @@ pfm_context_force_terminate(pfm_context_t *ctx, struct pt_regs *regs)
}
static int pfm_ovfl_notify_user(pfm_context_t *ctx, unsigned long ovfl_pmds);
-
+ /*
+ * pfm_handle_work() can be called with interrupts enabled
+ * (TIF_NEED_RESCHED) or disabled. The down_interruptible
+ * call may sleep, therefore we must re-enable interrupts
+ * to avoid deadlocks. It is safe to do so because this function
+ * is called ONLY when returning to user level (PUStk=1), in which case
+ * there is no risk of kernel stack overflow due to deep
+ * interrupt nesting.
+ */
void
pfm_handle_work(void)
{
pfm_context_t *ctx;
struct pt_regs *regs;
- unsigned long flags;
+ unsigned long flags, dummy_flags;
unsigned long ovfl_regs;
unsigned int reason;
int ret;
@@ -5039,18 +5037,15 @@ pfm_handle_work(void)
//if (CTX_OVFL_NOBLOCK(ctx)) goto skip_blocking;
if (reason == PFM_TRAP_REASON_RESET) goto skip_blocking;
+ /*
+ * restore interrupt mask to what it was on entry.
+ * Could be enabled/diasbled.
+ */
UNPROTECT_CTX(ctx, flags);
- /*
- * pfm_handle_work() is currently called with interrupts disabled.
- * The down_interruptible call may sleep, therefore we
- * must re-enable interrupts to avoid deadlocks. It is
- * safe to do so because this function is called ONLY
- * when returning to user level (PUStk=1), in which case
- * there is no risk of kernel stack overflow due to deep
- * interrupt nesting.
- */
- BUG_ON(flags & IA64_PSR_I);
+ /*
+ * force interrupt enable because of down_interruptible()
+ */
local_irq_enable();
DPRINT(("before block sleeping\n"));
@@ -5064,12 +5059,12 @@ pfm_handle_work(void)
DPRINT(("after block sleeping ret=%d\n", ret));
/*
- * disable interrupts to restore state we had upon entering
- * this function
+ * lock context and mask interrupts again
+ * We save flags into a dummy because we may have
+ * altered interrupts mask compared to entry in this
+ * function.
*/
- local_irq_disable();
-
- PROTECT_CTX(ctx, flags);
+ PROTECT_CTX(ctx, dummy_flags);
/*
* we need to read the ovfl_regs only after wake-up
@@ -5095,7 +5090,9 @@ skip_blocking:
ctx->ctx_ovfl_regs[0] = 0UL;
nothing_to_do:
-
+ /*
+ * restore flags as they were upon entry
+ */
UNPROTECT_CTX(ctx, flags);
}
diff --git a/arch/ia64/kernel/perfmon_default_smpl.c b/arch/ia64/kernel/perfmon_default_smpl.c
index 965d2900455..344941db0a9 100644
--- a/arch/ia64/kernel/perfmon_default_smpl.c
+++ b/arch/ia64/kernel/perfmon_default_smpl.c
@@ -20,24 +20,17 @@ MODULE_AUTHOR("Stephane Eranian <eranian@hpl.hp.com>");
MODULE_DESCRIPTION("perfmon default sampling format");
MODULE_LICENSE("GPL");
-MODULE_PARM(debug, "i");
-MODULE_PARM_DESC(debug, "debug");
-
-MODULE_PARM(debug_ovfl, "i");
-MODULE_PARM_DESC(debug_ovfl, "debug ovfl");
-
-
#define DEFAULT_DEBUG 1
#ifdef DEFAULT_DEBUG
#define DPRINT(a) \
do { \
- if (unlikely(debug >0)) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \
+ if (unlikely(pfm_sysctl.debug >0)) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \
} while (0)
#define DPRINT_ovfl(a) \
do { \
- if (unlikely(debug_ovfl >0)) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \
+ if (unlikely(pfm_sysctl.debug > 0 && pfm_sysctl.debug_ovfl >0)) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \
} while (0)
#else
@@ -45,8 +38,6 @@ MODULE_PARM_DESC(debug_ovfl, "debug ovfl");
#define DPRINT_ovfl(a)
#endif
-static int debug, debug_ovfl;
-
static int
default_validate(struct task_struct *task, unsigned int flags, int cpu, void *data)
{
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index f05650c801d..b7e6b4cb374 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -4,10 +4,15 @@
* Copyright (C) 1998-2001, 2003-2004 Hewlett-Packard Co
* David Mosberger-Tang <davidm@hpl.hp.com>
* Stephane Eranian <eranian@hpl.hp.com>
- * Copyright (C) 2000, Rohit Seth <rohit.seth@intel.com>
+ * Copyright (C) 2000, 2004 Intel Corp
+ * Rohit Seth <rohit.seth@intel.com>
+ * Suresh Siddha <suresh.b.siddha@intel.com>
+ * Gordon Jin <gordon.jin@intel.com>
* Copyright (C) 1999 VA Linux Systems
* Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
*
+ * 12/26/04 S.Siddha, G.Jin, R.Seth
+ * Add multi-threading and multi-core detection
* 11/12/01 D.Mosberger Convert get_cpuinfo() to seq_file based show_cpuinfo().
* 04/04/00 D.Mosberger renamed cpu_initialized to cpu_online_map
* 03/31/00 R.Seth cpu_initialized and current->processor fixes
@@ -296,6 +301,34 @@ mark_bsp_online (void)
#endif
}
+#ifdef CONFIG_SMP
+static void
+check_for_logical_procs (void)
+{
+ pal_logical_to_physical_t info;
+ s64 status;
+
+ status = ia64_pal_logical_to_phys(0, &info);
+ if (status == -1) {
+ printk(KERN_INFO "No logical to physical processor mapping "
+ "available\n");
+ return;
+ }
+ if (status) {
+ printk(KERN_ERR "ia64_pal_logical_to_phys failed with %ld\n",
+ status);
+ return;
+ }
+ /*
+ * Total number of siblings that BSP has. Though not all of them
+ * may have booted successfully. The correct number of siblings
+ * booted is in info.overview_num_log.
+ */
+ smp_num_siblings = info.overview_tpc;
+ smp_num_cpucores = info.overview_cpp;
+}
+#endif
+
void __init
setup_arch (char **cmdline_p)
{
@@ -356,6 +389,19 @@ setup_arch (char **cmdline_p)
#ifdef CONFIG_SMP
cpu_physical_id(0) = hard_smp_processor_id();
+
+ cpu_set(0, cpu_sibling_map[0]);
+ cpu_set(0, cpu_core_map[0]);
+
+ check_for_logical_procs();
+ if (smp_num_cpucores > 1)
+ printk(KERN_INFO
+ "cpu package is Multi-Core capable: number of cores=%d\n",
+ smp_num_cpucores);
+ if (smp_num_siblings > 1)
+ printk(KERN_INFO
+ "cpu package is Multi-Threading capable: number of siblings=%d\n",
+ smp_num_siblings);
#endif
cpu_init(); /* initialize the bootstrap CPU */
@@ -459,12 +505,23 @@ show_cpuinfo (struct seq_file *m, void *v)
"cpu regs : %u\n"
"cpu MHz : %lu.%06lu\n"
"itc MHz : %lu.%06lu\n"
- "BogoMIPS : %lu.%02lu\n\n",
+ "BogoMIPS : %lu.%02lu\n",
cpunum, c->vendor, family, c->model, c->revision, c->archrev,
features, c->ppn, c->number,
c->proc_freq / 1000000, c->proc_freq % 1000000,
c->itc_freq / 1000000, c->itc_freq % 1000000,
lpj*HZ/500000, (lpj*HZ/5000) % 100);
+#ifdef CONFIG_SMP
+ seq_printf(m, "siblings : %u\n", c->num_log);
+ if (c->threads_per_core > 1 || c->cores_per_socket > 1)
+ seq_printf(m,
+ "physical id: %u\n"
+ "core id : %u\n"
+ "thread id : %u\n",
+ c->socket_id, c->core_id, c->thread_id);
+#endif
+ seq_printf(m,"\n");
+
return 0;
}
@@ -533,6 +590,14 @@ identify_cpu (struct cpuinfo_ia64 *c)
memcpy(c->vendor, cpuid.field.vendor, 16);
#ifdef CONFIG_SMP
c->cpu = smp_processor_id();
+
+ /* below default values will be overwritten by identify_siblings()
+ * for Multi-Threading/Multi-Core capable cpu's
+ */
+ c->threads_per_core = c->cores_per_socket = c->num_log = 1;
+ c->socket_id = -1;
+
+ identify_siblings(c);
#endif
c->ppn = cpuid.field.ppn;
c->number = cpuid.field.number;
diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c
index ca1536db339..0d5ee57c986 100644
--- a/arch/ia64/kernel/smpboot.c
+++ b/arch/ia64/kernel/smpboot.c
@@ -1,8 +1,13 @@
/*
* SMP boot-related support
*
- * Copyright (C) 1998-2003 Hewlett-Packard Co
+ * Copyright (C) 1998-2003, 2005 Hewlett-Packard Co
* David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 2001, 2004-2005 Intel Corp
+ * Rohit Seth <rohit.seth@intel.com>
+ * Suresh Siddha <suresh.b.siddha@intel.com>
+ * Gordon Jin <gordon.jin@intel.com>
+ * Ashok Raj <ashok.raj@intel.com>
*
* 01/05/16 Rohit Seth <rohit.seth@intel.com> Moved SMP booting functions from smp.c to here.
* 01/04/27 David Mosberger <davidm@hpl.hp.com> Added ITC synching code.
@@ -10,6 +15,11 @@
* smp_boot_cpus()/smp_commence() is replaced by
* smp_prepare_cpus()/__cpu_up()/smp_cpus_done().
* 04/06/21 Ashok Raj <ashok.raj@intel.com> Added CPU Hotplug Support
+ * 04/12/26 Jin Gordon <gordon.jin@intel.com>
+ * 04/12/26 Rohit Seth <rohit.seth@intel.com>
+ * Add multi-threading and multi-core detection
+ * 05/01/30 Suresh Siddha <suresh.b.siddha@intel.com>
+ * Setup cpu_sibling_map and cpu_core_map
*/
#include <linux/config.h>
@@ -122,6 +132,11 @@ EXPORT_SYMBOL(cpu_online_map);
cpumask_t cpu_possible_map;
EXPORT_SYMBOL(cpu_possible_map);
+cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned;
+cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned;
+int smp_num_siblings = 1;
+int smp_num_cpucores = 1;
+
/* which logical CPU number maps to which CPU (physical APIC ID) */
volatile int ia64_cpu_to_sapicid[NR_CPUS];
EXPORT_SYMBOL(ia64_cpu_to_sapicid);
@@ -156,7 +171,8 @@ sync_master (void *arg)
local_irq_save(flags);
{
for (i = 0; i < NUM_ROUNDS*NUM_ITERS; ++i) {
- while (!go[MASTER]);
+ while (!go[MASTER])
+ cpu_relax();
go[MASTER] = 0;
go[SLAVE] = ia64_get_itc();
}
@@ -179,7 +195,8 @@ get_delta (long *rt, long *master)
for (i = 0; i < NUM_ITERS; ++i) {
t0 = ia64_get_itc();
go[MASTER] = 1;
- while (!(tm = go[SLAVE]));
+ while (!(tm = go[SLAVE]))
+ cpu_relax();
go[SLAVE] = 0;
t1 = ia64_get_itc();
@@ -258,7 +275,8 @@ ia64_sync_itc (unsigned int master)
return;
}
- while (go[MASTER]); /* wait for master to be ready */
+ while (go[MASTER])
+ cpu_relax(); /* wait for master to be ready */
spin_lock_irqsave(&itc_sync_lock, flags);
{
@@ -595,7 +613,68 @@ void __devinit smp_prepare_boot_cpu(void)
cpu_set(smp_processor_id(), cpu_callin_map);
}
+/*
+ * mt_info[] is a temporary store for all info returned by
+ * PAL_LOGICAL_TO_PHYSICAL, to be copied into cpuinfo_ia64 when the
+ * specific cpu comes.
+ */
+static struct {
+ __u32 socket_id;
+ __u16 core_id;
+ __u16 thread_id;
+ __u16 proc_fixed_addr;
+ __u8 valid;
+}mt_info[NR_CPUS] __devinit;
+
#ifdef CONFIG_HOTPLUG_CPU
+static inline void
+remove_from_mtinfo(int cpu)
+{
+ int i;
+
+ for_each_cpu(i)
+ if (mt_info[i].valid && mt_info[i].socket_id ==
+ cpu_data(cpu)->socket_id)
+ mt_info[i].valid = 0;
+}
+
+static inline void
+clear_cpu_sibling_map(int cpu)
+{
+ int i;
+
+ for_each_cpu_mask(i, cpu_sibling_map[cpu])
+ cpu_clear(cpu, cpu_sibling_map[i]);
+ for_each_cpu_mask(i, cpu_core_map[cpu])
+ cpu_clear(cpu, cpu_core_map[i]);
+
+ cpu_sibling_map[cpu] = cpu_core_map[cpu] = CPU_MASK_NONE;
+}
+
+static void
+remove_siblinginfo(int cpu)
+{
+ int last = 0;
+
+ if (cpu_data(cpu)->threads_per_core == 1 &&
+ cpu_data(cpu)->cores_per_socket == 1) {
+ cpu_clear(cpu, cpu_core_map[cpu]);
+ cpu_clear(cpu, cpu_sibling_map[cpu]);
+ return;
+ }
+
+ last = (cpus_weight(cpu_core_map[cpu]) == 1 ? 1 : 0);
+
+ /* remove it from all sibling map's */
+ clear_cpu_sibling_map(cpu);
+
+ /* if this cpu is the last in the core group, remove all its info
+ * from mt_info structure
+ */
+ if (last)
+ remove_from_mtinfo(cpu);
+}
+
extern void fixup_irqs(void);
/* must be called with cpucontrol mutex held */
int __cpu_disable(void)
@@ -608,6 +687,7 @@ int __cpu_disable(void)
if (cpu == 0)
return -EBUSY;
+ remove_siblinginfo(cpu);
fixup_irqs();
local_flush_tlb_all();
cpu_clear(cpu, cpu_callin_map);
@@ -660,6 +740,23 @@ smp_cpus_done (unsigned int dummy)
(int)num_online_cpus(), bogosum/(500000/HZ), (bogosum/(5000/HZ))%100);
}
+static inline void __devinit
+set_cpu_sibling_map(int cpu)
+{
+ int i;
+
+ for_each_online_cpu(i) {
+ if ((cpu_data(cpu)->socket_id == cpu_data(i)->socket_id)) {
+ cpu_set(i, cpu_core_map[cpu]);
+ cpu_set(cpu, cpu_core_map[i]);
+ if (cpu_data(cpu)->core_id == cpu_data(i)->core_id) {
+ cpu_set(i, cpu_sibling_map[cpu]);
+ cpu_set(cpu, cpu_sibling_map[i]);
+ }
+ }
+ }
+}
+
int __devinit
__cpu_up (unsigned int cpu)
{
@@ -682,6 +779,15 @@ __cpu_up (unsigned int cpu)
if (ret < 0)
return ret;
+ if (cpu_data(cpu)->threads_per_core == 1 &&
+ cpu_data(cpu)->cores_per_socket == 1) {
+ cpu_set(cpu, cpu_sibling_map[cpu]);
+ cpu_set(cpu, cpu_core_map[cpu]);
+ return 0;
+ }
+
+ set_cpu_sibling_map(cpu);
+
return 0;
}
@@ -709,3 +815,106 @@ init_smp_config(void)
ia64_sal_strerror(sal_ret));
}
+static inline int __devinit
+check_for_mtinfo_index(void)
+{
+ int i;
+
+ for_each_cpu(i)
+ if (!mt_info[i].valid)
+ return i;
+
+ return -1;
+}
+
+/*
+ * Search the mt_info to find out if this socket's cid/tid information is
+ * cached or not. If the socket exists, fill in the core_id and thread_id
+ * in cpuinfo
+ */
+static int __devinit
+check_for_new_socket(__u16 logical_address, struct cpuinfo_ia64 *c)
+{
+ int i;
+ __u32 sid = c->socket_id;
+
+ for_each_cpu(i) {
+ if (mt_info[i].valid && mt_info[i].proc_fixed_addr == logical_address
+ && mt_info[i].socket_id == sid) {
+ c->core_id = mt_info[i].core_id;
+ c->thread_id = mt_info[i].thread_id;
+ return 1; /* not a new socket */
+ }
+ }
+ return 0;
+}
+
+/*
+ * identify_siblings(cpu) gets called from identify_cpu. This populates the
+ * information related to logical execution units in per_cpu_data structure.
+ */
+void __devinit
+identify_siblings(struct cpuinfo_ia64 *c)
+{
+ s64 status;
+ u16 pltid;
+ u64 proc_fixed_addr;
+ int count, i;
+ pal_logical_to_physical_t info;
+
+ if (smp_num_cpucores == 1 && smp_num_siblings == 1)
+ return;
+
+ if ((status = ia64_pal_logical_to_phys(0, &info)) != PAL_STATUS_SUCCESS) {
+ printk(KERN_ERR "ia64_pal_logical_to_phys failed with %ld\n",
+ status);
+ return;
+ }
+ if ((status = ia64_sal_physical_id_info(&pltid)) != PAL_STATUS_SUCCESS) {
+ printk(KERN_ERR "ia64_sal_pltid failed with %ld\n", status);
+ return;
+ }
+ if ((status = ia64_pal_fixed_addr(&proc_fixed_addr)) != PAL_STATUS_SUCCESS) {
+ printk(KERN_ERR "ia64_pal_fixed_addr failed with %ld\n", status);
+ return;
+ }
+
+ c->socket_id = (pltid << 8) | info.overview_ppid;
+ c->cores_per_socket = info.overview_cpp;
+ c->threads_per_core = info.overview_tpc;
+ count = c->num_log = info.overview_num_log;
+
+ /* If the thread and core id information is already cached, then
+ * we will simply update cpu_info and return. Otherwise, we will
+ * do the PAL calls and cache core and thread id's of all the siblings.
+ */
+ if (check_for_new_socket(proc_fixed_addr, c))
+ return;
+
+ for (i = 0; i < count; i++) {
+ int index;
+
+ if (i && (status = ia64_pal_logical_to_phys(i, &info))
+ != PAL_STATUS_SUCCESS) {
+ printk(KERN_ERR "ia64_pal_logical_to_phys failed"
+ " with %ld\n", status);
+ return;
+ }
+ if (info.log2_la == proc_fixed_addr) {
+ c->core_id = info.log1_cid;
+ c->thread_id = info.log1_tid;
+ }
+
+ index = check_for_mtinfo_index();
+ /* We will not do the mt_info caching optimization in this case.
+ */
+ if (index < 0)
+ continue;
+
+ mt_info[index].valid = 1;
+ mt_info[index].socket_id = c->socket_id;
+ mt_info[index].core_id = info.log1_cid;
+ mt_info[index].thread_id = info.log1_tid;
+ mt_info[index].proc_fixed_addr = info.log2_la;
+ }
+}
diff --git a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c
index d494ff647ca..2776a074c6f 100644
--- a/arch/ia64/kernel/unwind.c
+++ b/arch/ia64/kernel/unwind.c
@@ -1943,23 +1943,30 @@ EXPORT_SYMBOL(unw_unwind);
int
unw_unwind_to_user (struct unw_frame_info *info)
{
- unsigned long ip, sp;
+ unsigned long ip, sp, pr = 0;
while (unw_unwind(info) >= 0) {
- if (unw_get_rp(info, &ip) < 0) {
- unw_get_ip(info, &ip);
- UNW_DPRINT(0, "unwind.%s: failed to read return pointer (ip=0x%lx)\n",
- __FUNCTION__, ip);
- return -1;
- }
unw_get_sp(info, &sp);
- if (sp >= (unsigned long)info->task + IA64_STK_OFFSET)
+ if ((long)((unsigned long)info->task + IA64_STK_OFFSET - sp)
+ < IA64_PT_REGS_SIZE) {
+ UNW_DPRINT(0, "unwind.%s: ran off the top of the kernel stack\n",
+ __FUNCTION__);
break;
- if (ip < FIXADDR_USER_END)
+ }
+ if (unw_is_intr_frame(info) &&
+ (pr & (1UL << PRED_USER_STACK)))
return 0;
+ if (unw_get_pr (info, &pr) < 0) {
+ unw_get_rp(info, &ip);
+ UNW_DPRINT(0, "unwind.%s: failed to read "
+ "predicate register (ip=0x%lx)\n",
+ __FUNCTION__, ip);
+ return -1;
+ }
}
unw_get_ip(info, &ip);
- UNW_DPRINT(0, "unwind.%s: failed to unwind to user-level (ip=0x%lx)\n", __FUNCTION__, ip);
+ UNW_DPRINT(0, "unwind.%s: failed to unwind to user-level (ip=0x%lx)\n",
+ __FUNCTION__, ip);
return -1;
}
EXPORT_SYMBOL(unw_unwind_to_user);