* [PATCH 03/13] kvm/powerpc: Fix the build for 32-bit Book 3S (classic) processors
From: Paul Mackerras @ 2011-05-11 10:39 UTC (permalink / raw)
To: linuxppc-dev, kvm; +Cc: Alexander Graf
In-Reply-To: <20110511103443.GA2837@brick.ozlabs.ibm.com>
Commits a5d4f3ad3a ("powerpc: Base support for exceptions using
HSRR0/1") and 673b189a2e ("powerpc: Always use SPRN_SPRG_HSCRATCH0
when running in HV mode") cause compile and link errors for 32-bit
classic Book 3S processors when KVM is enabled. This fixes these
errors.
Signed-off-by: Paul Mackerras <paulus@samba.org>
---
arch/powerpc/include/asm/reg.h | 5 +++++
arch/powerpc/kvm/book3s_rmhandlers.S | 2 ++
2 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 47e3416..05658b7 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -823,6 +823,11 @@
FTR_SECTION_ELSE_NESTED(66); \
mtspr SPRN_SPRG_HSCRATCH0,rX; \
ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_HVMODE_206, 66)
+
+#else /* CONFIG_PPC_BOOK3S_64 */
+#define GET_SCRATCH0(rX) mfspr rX,SPRN_SPRG_SCRATCH0
+#define SET_SCRATCH0(rX) mtspr SPRN_SPRG_SCRATCH0,rX
+
#endif
#ifdef CONFIG_PPC_BOOK3E_64
diff --git a/arch/powerpc/kvm/book3s_rmhandlers.S b/arch/powerpc/kvm/book3s_rmhandlers.S
index ae99af6..1a1b344 100644
--- a/arch/powerpc/kvm/book3s_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_rmhandlers.S
@@ -112,7 +112,9 @@ INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_MACHINE_CHECK
INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_DATA_STORAGE
INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_INST_STORAGE
INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_EXTERNAL
+#ifdef CONFIG_PPC_BOOK3S_64
INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_EXTERNAL_HV
+#endif
INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_ALIGNMENT
INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_PROGRAM
INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_FP_UNAVAIL
--
1.7.4.4
^ permalink raw reply related
* [PATCH 02/13] kvm/powerpc: Fix kvmppc_core_pending_dec
From: Paul Mackerras @ 2011-05-11 10:38 UTC (permalink / raw)
To: linuxppc-dev, kvm; +Cc: Alexander Graf
In-Reply-To: <20110511103443.GA2837@brick.ozlabs.ibm.com>
The vcpu->arch.pending_exceptions field is a bitfield indexed by
interrupt priority number as returned by kvmppc_book3s_vec2irqprio.
However, kvmppc_core_pending_dec was using an interrupt vector shifted
by 7 as the bit index. Fix it to use the irqprio value for the
decrementer interrupt instead. This problem was found by code
inspection.
Signed-off-by: Paul Mackerras <paulus@samba.org>
---
arch/powerpc/kvm/book3s.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c
index 3501961..42a2fed 100644
--- a/arch/powerpc/kvm/book3s.c
+++ b/arch/powerpc/kvm/book3s.c
@@ -237,7 +237,7 @@ void kvmppc_core_queue_dec(struct kvm_vcpu *vcpu)
int kvmppc_core_pending_dec(struct kvm_vcpu *vcpu)
{
- return test_bit(BOOK3S_INTERRUPT_DECREMENTER >> 7, &vcpu->arch.pending_exceptions);
+ return test_bit(BOOK3S_IRQPRIO_DECREMENTER, &vcpu->arch.pending_exceptions);
}
void kvmppc_core_dequeue_dec(struct kvm_vcpu *vcpu)
--
1.7.4.4
^ permalink raw reply related
* [PATCH 01/13] kvm/powerpc: Move fields between struct kvm_vcpu_arch and kvmppc_vcpu_book3s
From: Paul Mackerras @ 2011-05-11 10:36 UTC (permalink / raw)
To: linuxppc-dev, kvm; +Cc: Alexander Graf
In-Reply-To: <20110511103443.GA2837@brick.ozlabs.ibm.com>
This moves the slb field, which represents the state of the emulated
SLB, from the kvmppc_vcpu_book3s struct to the kvm_vcpu_arch, and the
hpte_hash_[v]pte[_long] fields from kvm_vcpu_arch to kvmppc_vcpu_book3s.
This is in accord with the principle that the kvm_vcpu_arch struct
represents the state of the emulated CPU, and the kvmppc_vcpu_book3s
struct holds the auxiliary data structures used in the emulation.
Signed-off-by: Paul Mackerras <paulus@samba.org>
---
arch/powerpc/include/asm/kvm_book3s.h | 34 +++++++++-------
arch/powerpc/include/asm/kvm_host.h | 34 +++++++---------
arch/powerpc/kvm/book3s.c | 7 ++-
arch/powerpc/kvm/book3s_64_mmu.c | 54 +++++++++++-------------
arch/powerpc/kvm/book3s_mmu_hpte.c | 71 +++++++++++++++++++-------------
arch/powerpc/kvm/trace.h | 2 +-
6 files changed, 106 insertions(+), 96 deletions(-)
diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h
index d62e703..cfb2012 100644
--- a/arch/powerpc/include/asm/kvm_book3s.h
+++ b/arch/powerpc/include/asm/kvm_book3s.h
@@ -24,20 +24,6 @@
#include <linux/kvm_host.h>
#include <asm/kvm_book3s_asm.h>
-struct kvmppc_slb {
- u64 esid;
- u64 vsid;
- u64 orige;
- u64 origv;
- bool valid : 1;
- bool Ks : 1;
- bool Kp : 1;
- bool nx : 1;
- bool large : 1; /* PTEs are 16MB */
- bool tb : 1; /* 1TB segment */
- bool class : 1;
-};
-
struct kvmppc_bat {
u64 raw;
u32 bepi;
@@ -67,11 +53,22 @@ struct kvmppc_sid_map {
#define VSID_POOL_SIZE (SID_CONTEXTS * 16)
#endif
+struct hpte_cache {
+ struct hlist_node list_pte;
+ struct hlist_node list_pte_long;
+ struct hlist_node list_vpte;
+ struct hlist_node list_vpte_long;
+ struct rcu_head rcu_head;
+ u64 host_va;
+ u64 pfn;
+ ulong slot;
+ struct kvmppc_pte pte;
+};
+
struct kvmppc_vcpu_book3s {
struct kvm_vcpu vcpu;
struct kvmppc_book3s_shadow_vcpu *shadow_vcpu;
struct kvmppc_sid_map sid_map[SID_MAP_NUM];
- struct kvmppc_slb slb[64];
struct {
u64 esid;
u64 vsid;
@@ -94,6 +91,13 @@ struct kvmppc_vcpu_book3s {
#endif
int context_id[SID_CONTEXTS];
ulong prog_flags; /* flags to inject when giving a 700 trap */
+
+ struct hlist_head hpte_hash_pte[HPTEG_HASH_NUM_PTE];
+ struct hlist_head hpte_hash_pte_long[HPTEG_HASH_NUM_PTE_LONG];
+ struct hlist_head hpte_hash_vpte[HPTEG_HASH_NUM_VPTE];
+ struct hlist_head hpte_hash_vpte_long[HPTEG_HASH_NUM_VPTE_LONG];
+ int hpte_cache_count;
+ spinlock_t mmu_lock;
};
#define CONTEXT_HOST 0
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index bba3b9b..3ebe51b 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -163,16 +163,18 @@ struct kvmppc_mmu {
bool (*is_dcbz32)(struct kvm_vcpu *vcpu);
};
-struct hpte_cache {
- struct hlist_node list_pte;
- struct hlist_node list_pte_long;
- struct hlist_node list_vpte;
- struct hlist_node list_vpte_long;
- struct rcu_head rcu_head;
- u64 host_va;
- u64 pfn;
- ulong slot;
- struct kvmppc_pte pte;
+struct kvmppc_slb {
+ u64 esid;
+ u64 vsid;
+ u64 orige;
+ u64 origv;
+ bool valid : 1;
+ bool Ks : 1;
+ bool Kp : 1;
+ bool nx : 1;
+ bool large : 1; /* PTEs are 16MB */
+ bool tb : 1; /* 1TB segment */
+ bool class : 1;
};
struct kvm_vcpu_arch {
@@ -187,6 +189,9 @@ struct kvm_vcpu_arch {
ulong highmem_handler;
ulong rmcall;
ulong host_paca_phys;
+ struct kvmppc_slb slb[64];
+ int slb_max; /* # valid entries in slb[] */
+ int slb_nr; /* total number of entries in SLB */
struct kvmppc_mmu mmu;
#endif
@@ -293,15 +298,6 @@ struct kvm_vcpu_arch {
struct kvm_vcpu_arch_shared *shared;
unsigned long magic_page_pa; /* phys addr to map the magic page to */
unsigned long magic_page_ea; /* effect. addr to map the magic page to */
-
-#ifdef CONFIG_PPC_BOOK3S
- struct hlist_head hpte_hash_pte[HPTEG_HASH_NUM_PTE];
- struct hlist_head hpte_hash_pte_long[HPTEG_HASH_NUM_PTE_LONG];
- struct hlist_head hpte_hash_vpte[HPTEG_HASH_NUM_VPTE];
- struct hlist_head hpte_hash_vpte_long[HPTEG_HASH_NUM_VPTE_LONG];
- int hpte_cache_count;
- spinlock_t mmu_lock;
-#endif
};
#endif /* __POWERPC_KVM_HOST_H__ */
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c
index c961de4..3501961 100644
--- a/arch/powerpc/kvm/book3s.c
+++ b/arch/powerpc/kvm/book3s.c
@@ -17,7 +17,6 @@
#include <linux/kvm_host.h>
#include <linux/err.h>
#include <linux/slab.h>
-#include "trace.h"
#include <asm/reg.h>
#include <asm/cputable.h>
@@ -33,6 +32,8 @@
#include <linux/vmalloc.h>
#include <linux/highmem.h>
+#include "trace.h"
+
#define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU
/* #define EXIT_DEBUG */
@@ -1190,8 +1191,8 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
sregs->u.s.sdr1 = to_book3s(vcpu)->sdr1;
if (vcpu->arch.hflags & BOOK3S_HFLAG_SLB) {
for (i = 0; i < 64; i++) {
- sregs->u.s.ppc64.slb[i].slbe = vcpu3s->slb[i].orige | i;
- sregs->u.s.ppc64.slb[i].slbv = vcpu3s->slb[i].origv;
+ sregs->u.s.ppc64.slb[i].slbe = vcpu->arch.slb[i].orige | i;
+ sregs->u.s.ppc64.slb[i].slbv = vcpu->arch.slb[i].origv;
}
} else {
for (i = 0; i < 16; i++)
diff --git a/arch/powerpc/kvm/book3s_64_mmu.c b/arch/powerpc/kvm/book3s_64_mmu.c
index d7889ef..c6d3e19 100644
--- a/arch/powerpc/kvm/book3s_64_mmu.c
+++ b/arch/powerpc/kvm/book3s_64_mmu.c
@@ -41,36 +41,36 @@ static void kvmppc_mmu_book3s_64_reset_msr(struct kvm_vcpu *vcpu)
}
static struct kvmppc_slb *kvmppc_mmu_book3s_64_find_slbe(
- struct kvmppc_vcpu_book3s *vcpu_book3s,
+ struct kvm_vcpu *vcpu,
gva_t eaddr)
{
int i;
u64 esid = GET_ESID(eaddr);
u64 esid_1t = GET_ESID_1T(eaddr);
- for (i = 0; i < vcpu_book3s->slb_nr; i++) {
+ for (i = 0; i < vcpu->arch.slb_nr; i++) {
u64 cmp_esid = esid;
- if (!vcpu_book3s->slb[i].valid)
+ if (!vcpu->arch.slb[i].valid)
continue;
- if (vcpu_book3s->slb[i].tb)
+ if (vcpu->arch.slb[i].tb)
cmp_esid = esid_1t;
- if (vcpu_book3s->slb[i].esid == cmp_esid)
- return &vcpu_book3s->slb[i];
+ if (vcpu->arch.slb[i].esid == cmp_esid)
+ return &vcpu->arch.slb[i];
}
dprintk("KVM: No SLB entry found for 0x%lx [%llx | %llx]\n",
eaddr, esid, esid_1t);
- for (i = 0; i < vcpu_book3s->slb_nr; i++) {
- if (vcpu_book3s->slb[i].vsid)
+ for (i = 0; i < vcpu->arch.slb_nr; i++) {
+ if (vcpu->arch.slb[i].vsid)
dprintk(" %d: %c%c%c %llx %llx\n", i,
- vcpu_book3s->slb[i].valid ? 'v' : ' ',
- vcpu_book3s->slb[i].large ? 'l' : ' ',
- vcpu_book3s->slb[i].tb ? 't' : ' ',
- vcpu_book3s->slb[i].esid,
- vcpu_book3s->slb[i].vsid);
+ vcpu->arch.slb[i].valid ? 'v' : ' ',
+ vcpu->arch.slb[i].large ? 'l' : ' ',
+ vcpu->arch.slb[i].tb ? 't' : ' ',
+ vcpu->arch.slb[i].esid,
+ vcpu->arch.slb[i].vsid);
}
return NULL;
@@ -81,7 +81,7 @@ static u64 kvmppc_mmu_book3s_64_ea_to_vp(struct kvm_vcpu *vcpu, gva_t eaddr,
{
struct kvmppc_slb *slb;
- slb = kvmppc_mmu_book3s_64_find_slbe(to_book3s(vcpu), eaddr);
+ slb = kvmppc_mmu_book3s_64_find_slbe(vcpu, eaddr);
if (!slb)
return 0;
@@ -180,7 +180,7 @@ static int kvmppc_mmu_book3s_64_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
return 0;
}
- slbe = kvmppc_mmu_book3s_64_find_slbe(vcpu_book3s, eaddr);
+ slbe = kvmppc_mmu_book3s_64_find_slbe(vcpu, eaddr);
if (!slbe)
goto no_seg_found;
@@ -320,10 +320,10 @@ static void kvmppc_mmu_book3s_64_slbmte(struct kvm_vcpu *vcpu, u64 rs, u64 rb)
esid_1t = GET_ESID_1T(rb);
slb_nr = rb & 0xfff;
- if (slb_nr > vcpu_book3s->slb_nr)
+ if (slb_nr > vcpu->arch.slb_nr)
return;
- slbe = &vcpu_book3s->slb[slb_nr];
+ slbe = &vcpu->arch.slb[slb_nr];
slbe->large = (rs & SLB_VSID_L) ? 1 : 0;
slbe->tb = (rs & SLB_VSID_B_1T) ? 1 : 0;
@@ -344,38 +344,35 @@ static void kvmppc_mmu_book3s_64_slbmte(struct kvm_vcpu *vcpu, u64 rs, u64 rb)
static u64 kvmppc_mmu_book3s_64_slbmfee(struct kvm_vcpu *vcpu, u64 slb_nr)
{
- struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
struct kvmppc_slb *slbe;
- if (slb_nr > vcpu_book3s->slb_nr)
+ if (slb_nr > vcpu->arch.slb_nr)
return 0;
- slbe = &vcpu_book3s->slb[slb_nr];
+ slbe = &vcpu->arch.slb[slb_nr];
return slbe->orige;
}
static u64 kvmppc_mmu_book3s_64_slbmfev(struct kvm_vcpu *vcpu, u64 slb_nr)
{
- struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
struct kvmppc_slb *slbe;
- if (slb_nr > vcpu_book3s->slb_nr)
+ if (slb_nr > vcpu->arch.slb_nr)
return 0;
- slbe = &vcpu_book3s->slb[slb_nr];
+ slbe = &vcpu->arch.slb[slb_nr];
return slbe->origv;
}
static void kvmppc_mmu_book3s_64_slbie(struct kvm_vcpu *vcpu, u64 ea)
{
- struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
struct kvmppc_slb *slbe;
dprintk("KVM MMU: slbie(0x%llx)\n", ea);
- slbe = kvmppc_mmu_book3s_64_find_slbe(vcpu_book3s, ea);
+ slbe = kvmppc_mmu_book3s_64_find_slbe(vcpu, ea);
if (!slbe)
return;
@@ -389,13 +386,12 @@ static void kvmppc_mmu_book3s_64_slbie(struct kvm_vcpu *vcpu, u64 ea)
static void kvmppc_mmu_book3s_64_slbia(struct kvm_vcpu *vcpu)
{
- struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
int i;
dprintk("KVM MMU: slbia()\n");
- for (i = 1; i < vcpu_book3s->slb_nr; i++)
- vcpu_book3s->slb[i].valid = false;
+ for (i = 1; i < vcpu->arch.slb_nr; i++)
+ vcpu->arch.slb[i].valid = false;
if (vcpu->arch.shared->msr & MSR_IR) {
kvmppc_mmu_flush_segments(vcpu);
@@ -464,7 +460,7 @@ static int kvmppc_mmu_book3s_64_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
ulong mp_ea = vcpu->arch.magic_page_ea;
if (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) {
- slb = kvmppc_mmu_book3s_64_find_slbe(to_book3s(vcpu), ea);
+ slb = kvmppc_mmu_book3s_64_find_slbe(vcpu, ea);
if (slb)
gvsid = slb->vsid;
}
diff --git a/arch/powerpc/kvm/book3s_mmu_hpte.c b/arch/powerpc/kvm/book3s_mmu_hpte.c
index 79751d8..41cb001 100644
--- a/arch/powerpc/kvm/book3s_mmu_hpte.c
+++ b/arch/powerpc/kvm/book3s_mmu_hpte.c
@@ -21,7 +21,6 @@
#include <linux/kvm_host.h>
#include <linux/hash.h>
#include <linux/slab.h>
-#include "trace.h"
#include <asm/kvm_ppc.h>
#include <asm/kvm_book3s.h>
@@ -29,6 +28,8 @@
#include <asm/mmu_context.h>
#include <asm/hw_irq.h>
+#include "trace.h"
+
#define PTE_SIZE 12
static struct kmem_cache *hpte_cache;
@@ -58,30 +59,31 @@ static inline u64 kvmppc_mmu_hash_vpte_long(u64 vpage)
void kvmppc_mmu_hpte_cache_map(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
{
u64 index;
+ struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
trace_kvm_book3s_mmu_map(pte);
- spin_lock(&vcpu->arch.mmu_lock);
+ spin_lock(&vcpu3s->mmu_lock);
/* Add to ePTE list */
index = kvmppc_mmu_hash_pte(pte->pte.eaddr);
- hlist_add_head_rcu(&pte->list_pte, &vcpu->arch.hpte_hash_pte[index]);
+ hlist_add_head_rcu(&pte->list_pte, &vcpu3s->hpte_hash_pte[index]);
/* Add to ePTE_long list */
index = kvmppc_mmu_hash_pte_long(pte->pte.eaddr);
hlist_add_head_rcu(&pte->list_pte_long,
- &vcpu->arch.hpte_hash_pte_long[index]);
+ &vcpu3s->hpte_hash_pte_long[index]);
/* Add to vPTE list */
index = kvmppc_mmu_hash_vpte(pte->pte.vpage);
- hlist_add_head_rcu(&pte->list_vpte, &vcpu->arch.hpte_hash_vpte[index]);
+ hlist_add_head_rcu(&pte->list_vpte, &vcpu3s->hpte_hash_vpte[index]);
/* Add to vPTE_long list */
index = kvmppc_mmu_hash_vpte_long(pte->pte.vpage);
hlist_add_head_rcu(&pte->list_vpte_long,
- &vcpu->arch.hpte_hash_vpte_long[index]);
+ &vcpu3s->hpte_hash_vpte_long[index]);
- spin_unlock(&vcpu->arch.mmu_lock);
+ spin_unlock(&vcpu3s->mmu_lock);
}
static void free_pte_rcu(struct rcu_head *head)
@@ -92,16 +94,18 @@ static void free_pte_rcu(struct rcu_head *head)
static void invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
{
+ struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
+
trace_kvm_book3s_mmu_invalidate(pte);
/* Different for 32 and 64 bit */
kvmppc_mmu_invalidate_pte(vcpu, pte);
- spin_lock(&vcpu->arch.mmu_lock);
+ spin_lock(&vcpu3s->mmu_lock);
/* pte already invalidated in between? */
if (hlist_unhashed(&pte->list_pte)) {
- spin_unlock(&vcpu->arch.mmu_lock);
+ spin_unlock(&vcpu3s->mmu_lock);
return;
}
@@ -115,14 +119,15 @@ static void invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
else
kvm_release_pfn_clean(pte->pfn);
- spin_unlock(&vcpu->arch.mmu_lock);
+ spin_unlock(&vcpu3s->mmu_lock);
- vcpu->arch.hpte_cache_count--;
+ vcpu3s->hpte_cache_count--;
call_rcu(&pte->rcu_head, free_pte_rcu);
}
static void kvmppc_mmu_pte_flush_all(struct kvm_vcpu *vcpu)
{
+ struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
struct hpte_cache *pte;
struct hlist_node *node;
int i;
@@ -130,7 +135,7 @@ static void kvmppc_mmu_pte_flush_all(struct kvm_vcpu *vcpu)
rcu_read_lock();
for (i = 0; i < HPTEG_HASH_NUM_VPTE_LONG; i++) {
- struct hlist_head *list = &vcpu->arch.hpte_hash_vpte_long[i];
+ struct hlist_head *list = &vcpu3s->hpte_hash_vpte_long[i];
hlist_for_each_entry_rcu(pte, node, list, list_vpte_long)
invalidate_pte(vcpu, pte);
@@ -141,12 +146,13 @@ static void kvmppc_mmu_pte_flush_all(struct kvm_vcpu *vcpu)
static void kvmppc_mmu_pte_flush_page(struct kvm_vcpu *vcpu, ulong guest_ea)
{
+ struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
struct hlist_head *list;
struct hlist_node *node;
struct hpte_cache *pte;
/* Find the list of entries in the map */
- list = &vcpu->arch.hpte_hash_pte[kvmppc_mmu_hash_pte(guest_ea)];
+ list = &vcpu3s->hpte_hash_pte[kvmppc_mmu_hash_pte(guest_ea)];
rcu_read_lock();
@@ -160,12 +166,13 @@ static void kvmppc_mmu_pte_flush_page(struct kvm_vcpu *vcpu, ulong guest_ea)
static void kvmppc_mmu_pte_flush_long(struct kvm_vcpu *vcpu, ulong guest_ea)
{
+ struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
struct hlist_head *list;
struct hlist_node *node;
struct hpte_cache *pte;
/* Find the list of entries in the map */
- list = &vcpu->arch.hpte_hash_pte_long[
+ list = &vcpu3s->hpte_hash_pte_long[
kvmppc_mmu_hash_pte_long(guest_ea)];
rcu_read_lock();
@@ -203,12 +210,13 @@ void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask)
/* Flush with mask 0xfffffffff */
static void kvmppc_mmu_pte_vflush_short(struct kvm_vcpu *vcpu, u64 guest_vp)
{
+ struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
struct hlist_head *list;
struct hlist_node *node;
struct hpte_cache *pte;
u64 vp_mask = 0xfffffffffULL;
- list = &vcpu->arch.hpte_hash_vpte[kvmppc_mmu_hash_vpte(guest_vp)];
+ list = &vcpu3s->hpte_hash_vpte[kvmppc_mmu_hash_vpte(guest_vp)];
rcu_read_lock();
@@ -223,12 +231,13 @@ static void kvmppc_mmu_pte_vflush_short(struct kvm_vcpu *vcpu, u64 guest_vp)
/* Flush with mask 0xffffff000 */
static void kvmppc_mmu_pte_vflush_long(struct kvm_vcpu *vcpu, u64 guest_vp)
{
+ struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
struct hlist_head *list;
struct hlist_node *node;
struct hpte_cache *pte;
u64 vp_mask = 0xffffff000ULL;
- list = &vcpu->arch.hpte_hash_vpte_long[
+ list = &vcpu3s->hpte_hash_vpte_long[
kvmppc_mmu_hash_vpte_long(guest_vp)];
rcu_read_lock();
@@ -261,6 +270,7 @@ void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 guest_vp, u64 vp_mask)
void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end)
{
+ struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
struct hlist_node *node;
struct hpte_cache *pte;
int i;
@@ -270,7 +280,7 @@ void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end)
rcu_read_lock();
for (i = 0; i < HPTEG_HASH_NUM_VPTE_LONG; i++) {
- struct hlist_head *list = &vcpu->arch.hpte_hash_vpte_long[i];
+ struct hlist_head *list = &vcpu3s->hpte_hash_vpte_long[i];
hlist_for_each_entry_rcu(pte, node, list, list_vpte_long)
if ((pte->pte.raddr >= pa_start) &&
@@ -283,12 +293,13 @@ void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end)
struct hpte_cache *kvmppc_mmu_hpte_cache_next(struct kvm_vcpu *vcpu)
{
+ struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
struct hpte_cache *pte;
pte = kmem_cache_zalloc(hpte_cache, GFP_KERNEL);
- vcpu->arch.hpte_cache_count++;
+ vcpu3s->hpte_cache_count++;
- if (vcpu->arch.hpte_cache_count == HPTEG_CACHE_NUM)
+ if (vcpu3s->hpte_cache_count == HPTEG_CACHE_NUM)
kvmppc_mmu_pte_flush_all(vcpu);
return pte;
@@ -309,17 +320,19 @@ static void kvmppc_mmu_hpte_init_hash(struct hlist_head *hash_list, int len)
int kvmppc_mmu_hpte_init(struct kvm_vcpu *vcpu)
{
+ struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
+
/* init hpte lookup hashes */
- kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_pte,
- ARRAY_SIZE(vcpu->arch.hpte_hash_pte));
- kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_pte_long,
- ARRAY_SIZE(vcpu->arch.hpte_hash_pte_long));
- kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_vpte,
- ARRAY_SIZE(vcpu->arch.hpte_hash_vpte));
- kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_vpte_long,
- ARRAY_SIZE(vcpu->arch.hpte_hash_vpte_long));
-
- spin_lock_init(&vcpu->arch.mmu_lock);
+ kvmppc_mmu_hpte_init_hash(vcpu3s->hpte_hash_pte,
+ ARRAY_SIZE(vcpu3s->hpte_hash_pte));
+ kvmppc_mmu_hpte_init_hash(vcpu3s->hpte_hash_pte_long,
+ ARRAY_SIZE(vcpu3s->hpte_hash_pte_long));
+ kvmppc_mmu_hpte_init_hash(vcpu3s->hpte_hash_vpte,
+ ARRAY_SIZE(vcpu3s->hpte_hash_vpte));
+ kvmppc_mmu_hpte_init_hash(vcpu3s->hpte_hash_vpte_long,
+ ARRAY_SIZE(vcpu3s->hpte_hash_vpte_long));
+
+ spin_lock_init(&vcpu3s->mmu_lock);
return 0;
}
diff --git a/arch/powerpc/kvm/trace.h b/arch/powerpc/kvm/trace.h
index 3aca1b0..d62a14b 100644
--- a/arch/powerpc/kvm/trace.h
+++ b/arch/powerpc/kvm/trace.h
@@ -252,7 +252,7 @@ TRACE_EVENT(kvm_book3s_mmu_flush,
),
TP_fast_assign(
- __entry->count = vcpu->arch.hpte_cache_count;
+ __entry->count = to_book3s(vcpu)->hpte_cache_count;
__entry->p1 = p1;
__entry->p2 = p2;
__entry->type = type;
--
1.7.4.4
^ permalink raw reply related
* [PATCH 0/13] Hypervisor-mode KVM on POWER7
From: Paul Mackerras @ 2011-05-11 10:34 UTC (permalink / raw)
To: linuxppc-dev, kvm; +Cc: Alexander Graf
The following series of patches enable KVM to exploit the hardware
hypervisor mode on 64-bit Power ISA Book3S machines. At present only
POWER7 is supported, but it would be easy to add other processors.
Running the KVM host in hypervisor mode means that the guest can use
both supervisor mode and user mode. That means that the guest can
execute supervisor-privilege instructions and access supervisor-
privilege registers. In addition the hardware directs most exceptions
to the guest. Thus we don't need to emulate any instructions in the
host. Generally, the only times we need to exit the guest are when it
does a hypercall or when an external interrupt or host timer
(decrementer) interrupt occurs.
The focus of this KVM implementation is to run guests that use the
PAPR (Power Architecture Platform Requirements) paravirtualization
interface, which is the interface supplied by PowerVM on IBM pSeries
machines.
These patches are against Ben Herrenschmidt's next branch in his tree
at git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc.git.
^ permalink raw reply
* [PATCH 02/37] powerpc: don't search for paca in freed memory
From: Milton Miller @ 2011-05-11 5:28 UTC (permalink / raw)
To: linuxppc-dev, Benjamin Herrenschmidt
In-Reply-To: <cover.1305092637.git.miltonm@bga.com>
Starting with 1426d5a3bd07589534286375998c0c8c6fdc5260 (powerpc:
Dynamically allocate pacas) we free the memory for pacas beyond
cpu_possible, but we failed to update the loop the secondary cpus use
to find their paca. If the system has running cpu threads for which
the kernel did not allocate a paca for they will search the memory that
was freed. For instance this could happen when the device tree for
a kdump kernel was not updated after a cpu hotplug, or the kernel is
running with more cpus than the kernel was configured.
Since c1854e00727f50f7ac99e98d26ece04c087ef785 (powerpc: Set nr_cpu_ids
early and use it to free PACAs) we set nr_cpu_ids before telling the
cpus to advance, so use that to limit the search.
We can't reference nr_cpu_ids without CONFIG_SMP because it is defined
as 1 instead of a memory location, but any extra threads should be sent
to kexec_wait in that case anyways, so make that explicit and remove
the search loop for UP.
Note to stable: The fix also requires
c1854e00727f50f7ac99e98d26ece04c087ef785 (powerpc: Set
nr_cpu_ids early and use it to free PACAs) to function. Also
9d07bc841c9779b4d7902e417f4e509996ce805d (Properly handshake CPUs going
out of boot spin loop) affects the second chunk, specifically the branch
target was 3b before and is 4b after that patch, and there was a blank
line before the #ifdef CONFIG_SMP that was removed
Cc: <stable@kernel.org> # .34.x: c1854e0072 powerpc: Set nr_cpu_ids early
Cc: <stable@kernel.org> # .34.x
Signed-off-by: Milton Miller <miltonm@bga.com>
---
arch/powerpc/kernel/head_64.S | 13 ++++++++-----
1 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index 73d6e9a..ba50409 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -218,13 +218,19 @@ generic_secondary_common_init:
*/
LOAD_REG_ADDR(r13, paca) /* Load paca pointer */
ld r13,0(r13) /* Get base vaddr of paca array */
+#ifndef CONFIG_SMP
+ addi r13,r13,PACA_SIZE /* know r13 if used accidentally */
+ b .kexec_wait /* wait for next kernel if !SMP */
+#else
+ LOAD_REG_ADDR(r7, nr_cpu_ids) /* Load nr_cpu_ids address */
+ lwz r7,0(r7) /* also the max paca allocated */
li r5,0 /* logical cpu id */
1: lhz r6,PACAHWCPUID(r13) /* Load HW procid from paca */
cmpw r6,r24 /* Compare to our id */
beq 2f
addi r13,r13,PACA_SIZE /* Loop to next PACA on miss */
addi r5,r5,1
- cmpwi r5,NR_CPUS
+ cmpw r5,r7 /* Check if more pacas exist */
blt 1b
mr r3,r24 /* not found, copy phys to r3 */
@@ -259,9 +265,6 @@ generic_secondary_common_init:
4: HMT_LOW
lbz r23,PACAPROCSTART(r13) /* Test if this processor should */
/* start. */
-#ifndef CONFIG_SMP
- b 4b /* Never go on non-SMP */
-#else
cmpwi 0,r23,0
beq 4b /* Loop until told to go */
@@ -273,7 +276,7 @@ generic_secondary_common_init:
subi r1,r1,STACK_FRAME_OVERHEAD
b __secondary_start
-#endif
+#endif /* SMP */
/*
* Turn the MMU off.
--
1.7.0.4
^ permalink raw reply related
* [PATCH 17/37] powerpc cell: use smp_request_message_ipi
From: Milton Miller @ 2011-05-11 5:29 UTC (permalink / raw)
To: linuxppc-dev, Benjamin Herrenschmidt
In-Reply-To: <cover.1305092637.git.miltonm@bga.com>
This is a request to merge patchwork id 3780 with the same subject.
I believe it was marked "changes requested" because it depended on a
patch that had requested changes, but those were resolved and this
one got overlooked. The next patch will remove smp_msg_recv.
thanks,
milton
Here is the original change log:
Subject: [PATCH 15/16] powerpc cell: use smp_request_message_ipi
cell native has 4 interrupts for ipis, so use the new smp_request_message_ipi
to save pathlength and the data-dependent branch.
This has the side effects of enabling the debugger ipi for kdump and
setting IRQF_PERCPU for the ipi interrupts. It doesn't undo the virq
mapping if it turns out the ipi is not used.
^ permalink raw reply
* [PATCH 00/37] fix paca memory usage and NR_CPU loops, factor ipi and simplify irq code
From: Milton Miller @ 2011-05-11 5:43 UTC (permalink / raw)
To: linuxppc-dev, Benjamin Herrenschmidt; +Cc: Thomas Gleixner
This series represents a somewhat ordered, somewhat meandering series
development series of patches I've been working on for the past few weeks.
It starts with memory corruption fixes that need to go back to stable
relating to slave cpu searches and paca allocation. After refactoring
and taking into consideration of patches merged upstream, I think this
is just the first 4, but the next 3 are related.
powerpc: fix memory corruption from unallocated slaves
powerpc: don't search for paca in freed memory
powerpc/kdump64: Don't reference freed memory as pacas
powerpc/iseries: cleanup and fix secondary startup
powerpc: Respect nr_cpu_ids when calling set_cpu_possible and set_cpu_present
powerpc: use nr_cpu_ids in initial paca allocation
powerpc: call no-longer static setup_nr_cpu_ids instead of replicating it
A search for NR_CPUS found that MSG_ALL_BUT_SELF was only used to enter
the debugger, but caused special code loops in all smp_ops,
so I pulled that code for a bit more path length in the loop to enter
the debugger or kexec. I then simplified the mpic code and factored
out common code in ipi interrupt multiplexing. That allowed an
easy change to remove a set of lwarx/stwcx. in the ipi send path.
powerpc: mpic: limit NR_CPUS loop to 32 bit
powerpc: mpic: break cpumask abstraction earlier
powerpc: remove call sites of MSG_ALL_BUT_SELF
powerpc: remove checks for MSG_ALL and MSG_ALL_BUT_SELF
linux/smp.h: remove unused MSG_ flags
powerpc/mpic: simplify ipi cpu mask handling
powerpc: remove powermac/pic.h
powerpc: remove alloc_maybe_bootmem for zalloc version
powerpc: remove stubbed beat smp support
powerpc cell: use smp_request_message_ipi [ patchwork 3780 ]
powerpc: move smp_ops_t from machdep.h to smp.h
powerpc: consolidate ipi message mux and demux
powerpc: add kconfig for muxed smp ipi support
powerpc: use bytes instead of bitops in smp ipi multiplexing
I then got sidetracked with Grant's quest to create irq_domains from the
irq_host code. I started going through the irq_host implementations in
arch/powerpc, removing some code that was redundant or not called, tring
to simplify the interfaces before we export them. Also standardizing
the use of the per-irq chip data and handler data.
powerpc: xics: cleanup xics_host_map and ipi
powerpc: radix trees are available before init_IRQ
powerpc: return early if irq_host lookup type is wrong
powerpc: remove trival irq_host_ops.unmap
powerpc: remove i8259 irq_host_ops->unmap
powerpc fsl_msi: don't abuse platform_data for driver_data
powerpc: fsl_msi: use chip_data not handler_data
powerpc: mpc5121_ads_cpld: remove use of NO_IRQ_IGNORE
powerpc: mpc62xx_pic: fix get_irq handling of NO_IRQ
powerpc: psurge: create a irq_host for secondary cpus
powerpc: remove irq_host_ops->remap hook
powerpc: spider-pic: get pic from chip_data instead of irq_map
powerpc: axon_msi: validate msi irq via chip_data
powerpc: add virq_is_host to reduce virq_to_host usage
powerpc: remove virq_to_host
powerpc: make IRQ_NOREQUEST last to clear, first to set
My vision is irq_host (or irq_domain) becomes a small wrapper layer
around the irq_desc layer. irq_host details are not needed beyond
that layer; the irq_host is a opaque pointer.
Populating reverse mappings (hwirq to virq) will become part of the
irq_host layer and happen at create_irq or irq_alloc_virt.
The return value of the reverse map functions will be the irqdesc and
ppc_md.get_irq will return the irqdesc. There is no reason to follow
up the radix tree lookup of hwirq to irq only to use that in another
radix-tree lookup to get the irqdesc that we need. (The only remaining
user of NO_IRQ_IGNORE is iSeries, and that special return is the only
holdup.)
I already have patches that replace the irq_map.host pointer with a
per-irq_host NR_IRQ bitmap (but they are entangled with Grant's series
to switch to irq_alloc as the primary allocator). As long as you have
fewer than BITS_PER_LONG irq_hosts that will be a win, and the only
path that might be slower is searching for the irq_host at unmap time.
For small irq count controllers that want to map all interrupts to
linux interrupts (including the legacy irq host), we can replace that
bitmap with an irq range.
The irq_host.hostdata field will become a parameter to alloc_irq_host,
and will be set as the irq's chip_data before calling ->map. The map
routine is free to change this later (ps3 uses per-cpu data, xics now
uses the ics sub-ops as chipdata). This allows a irq_host to have
several irq_chips for different flows but a driver can have multiple
irq_hosts for multiple instances of a given chip, distinguished
by chip_data.
My current thinking is the device node pointer stored in the host will
become generic match data, still used by the of wrapper to irq_domains
as a device node for default matching. Both the match data and the
chip data will be availible to the match routine. (This allows us to
keep the default of device node = match data without standardizing
a match struct inside each irq_hosts chipdata that we have to undo
every irq).
After doing a bunch of grep's on arch/sh, I think the interesting
parts of super8 interrupt handling that Thomas referred to are in
drivers/sh/intc. For some reason they populate the radix tree first
with a descriptor of their common interrupt controler abstraction
then walk the tree, replacing the tagged elements with the pointer
to their equivalent to irq_map. I do not yet understand the purpose
of this two phase allocation.
All patches are being sent to linuxppc-dev, a few have additional
cc's.
All patches were compiled for 3 configs: a smp 32 bit classic, a 32
bit book-e smp, and a 64 bit server, each had most platforms enabled.
I restricted many of my grep searches to arch/powerpc. I boot tested
using bml.
arch/powerpc/include/asm/dbell.h | 3 +-
arch/powerpc/include/asm/irq.h | 5 +-
arch/powerpc/include/asm/machdep.h | 21 ----
arch/powerpc/include/asm/smp.h | 33 +++++-
arch/powerpc/include/asm/system.h | 2 -
arch/powerpc/include/asm/xics.h | 2 +-
arch/powerpc/kernel/crash.c | 2 +-
arch/powerpc/kernel/dbell.c | 65 ++----------
arch/powerpc/kernel/head_64.S | 13 ++-
arch/powerpc/kernel/irq.c | 112 ++++----------------
arch/powerpc/kernel/kgdb.c | 2 +-
arch/powerpc/kernel/misc_64.S | 13 ++-
arch/powerpc/kernel/paca.c | 17 +--
arch/powerpc/kernel/pci_dn.c | 3 +-
arch/powerpc/kernel/setup-common.c | 14 ++--
arch/powerpc/kernel/smp.c | 118 ++++++++++++++-------
arch/powerpc/lib/alloc.c | 8 --
arch/powerpc/platforms/512x/mpc5121_ads_cpld.c | 6 +-
arch/powerpc/platforms/52xx/mpc52xx_pic.c | 4 +-
arch/powerpc/platforms/82xx/pq2ads-pci-pic.c | 8 --
arch/powerpc/platforms/85xx/smp.c | 6 +-
arch/powerpc/platforms/Kconfig | 11 ++-
arch/powerpc/platforms/Kconfig.cputype | 2 +
arch/powerpc/platforms/cell/Makefile | 1 -
arch/powerpc/platforms/cell/axon_msi.c | 3 +-
arch/powerpc/platforms/cell/beat_interrupt.c | 27 -----
arch/powerpc/platforms/cell/beat_interrupt.h | 3 -
arch/powerpc/platforms/cell/beat_smp.c | 123 ----------------------
arch/powerpc/platforms/cell/celleb_pci.c | 6 +-
arch/powerpc/platforms/cell/celleb_setup.c | 4 -
arch/powerpc/platforms/cell/interrupt.c | 27 ++----
arch/powerpc/platforms/cell/smp.c | 18 +---
arch/powerpc/platforms/cell/spider-pic.c | 13 ++-
arch/powerpc/platforms/embedded6xx/flipper-pic.c | 7 --
arch/powerpc/platforms/embedded6xx/hlwd-pic.c | 7 --
arch/powerpc/platforms/iseries/Kconfig | 1 +
arch/powerpc/platforms/iseries/exception.S | 59 ++++++----
arch/powerpc/platforms/iseries/irq.c | 3 +-
arch/powerpc/platforms/iseries/setup.c | 5 +
arch/powerpc/platforms/iseries/smp.c | 39 +-------
arch/powerpc/platforms/iseries/smp.h | 6 -
arch/powerpc/platforms/powermac/Kconfig | 11 ++-
arch/powerpc/platforms/powermac/pic.c | 13 +--
arch/powerpc/platforms/powermac/pic.h | 11 --
arch/powerpc/platforms/powermac/pmac.h | 1 +
arch/powerpc/platforms/powermac/smp.c | 87 +++++++++-------
arch/powerpc/platforms/ps3/interrupt.c | 6 -
arch/powerpc/platforms/ps3/smp.c | 22 +----
arch/powerpc/platforms/pseries/smp.c | 3 +-
arch/powerpc/sysdev/fsl_msi.c | 10 +-
arch/powerpc/sysdev/i8259.c | 13 ---
arch/powerpc/sysdev/mpic.c | 52 +++-------
arch/powerpc/sysdev/xics/icp-hv.c | 26 +----
arch/powerpc/sysdev/xics/icp-native.c | 26 +----
arch/powerpc/sysdev/xics/xics-common.c | 42 ++------
arch/powerpc/xmon/xmon.c | 2 +-
include/linux/smp.h | 10 --
57 files changed, 363 insertions(+), 794 deletions(-)
delete mode 100644 arch/powerpc/platforms/cell/beat_smp.c
delete mode 100644 arch/powerpc/platforms/iseries/smp.h
delete mode 100644 arch/powerpc/platforms/powermac/pic.h
^ permalink raw reply
* [PATCH 07/37] powerpc: call no-longer static setup_nr_cpu_ids instead of replicating it
From: Milton Miller @ 2011-05-11 5:28 UTC (permalink / raw)
To: linuxppc-dev, Benjamin Herrenschmidt
In-Reply-To: <cover.1305092637.git.miltonm@bga.com>
c1854e00727f50f7ac99e98d26ece04c087ef785 (powerpc: Set nr_cpu_ids early
and use it to free PACAs) copied the formerly static setup_nr_cpu_ids
from init/main.c but 34db18a054c600b6f81787165669dc572fe4de25 (smp:
move smp setup functions to kernel/smp.c) moved it to kernel/smp.c
with a declaration in include/linux/smp.h, so we can call it instead of
replicating it.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
I found this cleanup while c1854e was being merged, but saved it from the
end to ease backporting.
---
arch/powerpc/kernel/setup-common.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index fce759b..ef33a08 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -510,7 +510,7 @@ void __init smp_setup_cpu_maps(void)
cpu_init_thread_core_maps(nthreads);
/* Now that possible cpus are set, set nr_cpu_ids for later use */
- nr_cpu_ids = find_last_bit(cpumask_bits(cpu_possible_mask),NR_CPUS) + 1;
+ setup_nr_cpu_ids();
free_unused_pacas();
}
--
1.7.0.4
^ permalink raw reply related
* [PATCH 08/37] powerpc: mpic: limit NR_CPUS loop to 32 bit
From: Milton Miller @ 2011-05-11 5:28 UTC (permalink / raw)
To: linuxppc-dev, Benjamin Herrenschmidt
In-Reply-To: <cover.1305092637.git.miltonm@bga.com>
mpic_physmask was looping NR_CPUS times over a mask that was passed as
a u32. Since mpic is architecturaly limited to 32 physical cpus, clamp
the logical cpus to 32 when compiling (we could also clamp at runtime
to nr_cpu_ids).
Signed-off-by: Milton Miller <miltonm@bga.com>
---
arch/powerpc/sysdev/mpic.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 824a94f..a93da80 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -631,7 +631,7 @@ static inline u32 mpic_physmask(u32 cpumask)
int i;
u32 mask = 0;
- for (i = 0; i < NR_CPUS; ++i, cpumask >>= 1)
+ for (i = 0; i < min(32, NR_CPUS); ++i, cpumask >>= 1)
mask |= (cpumask & 1) << get_hard_smp_processor_id(i);
return mask;
}
--
1.7.0.4
^ permalink raw reply related
* [PATCH 09/37] powerpc: mpic: break cpumask abstraction earlier
From: Milton Miller @ 2011-05-11 5:29 UTC (permalink / raw)
To: linuxppc-dev, Benjamin Herrenschmidt
In-Reply-To: <cover.1305092637.git.miltonm@bga.com>
mpic_set_affinity is allocating and freeing a cpumask var even though
it was breaking the cpumask abstraction when passing the mask to
mpic_physmask. It also didn't have any check for allocatin failure.
Break the cpumask abstraction earlier and use simple bitwise and of the
bits from the mask with the bits of cpu_online_mask.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
arch/powerpc/sysdev/mpic.c | 10 +++-------
1 files changed, 3 insertions(+), 7 deletions(-)
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index a93da80..116695b 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -821,16 +821,12 @@ int mpic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid);
} else {
- cpumask_var_t tmp;
+ u32 mask = cpumask_bits(cpumask)[0];
- alloc_cpumask_var(&tmp, GFP_KERNEL);
-
- cpumask_and(tmp, cpumask, cpu_online_mask);
+ mask &= cpumask_bits(cpu_online_mask)[0];
mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION),
- mpic_physmask(cpumask_bits(tmp)[0]));
-
- free_cpumask_var(tmp);
+ mpic_physmask(mask));
}
return 0;
--
1.7.0.4
^ permalink raw reply related
* [PATCH 10/37] powerpc: remove call sites of MSG_ALL_BUT_SELF
From: Milton Miller @ 2011-05-11 5:29 UTC (permalink / raw)
To: linuxppc-dev, Benjamin Herrenschmidt
In-Reply-To: <cover.1305092637.git.miltonm@bga.com>
The only user of MSG_ALL_BUT_SELF in the whole kernel tree is powerpc,
and it only uses it to start the debugger. Both debuggers always call
smp_send_debugger_break with MSG_ALL_BUT_SELF, and only mpic can do
anything more optimal than a loop over all online cpus, but all message
passing implementations have to code for this special delivery target.
Convert smp_send_debugger_break to take void and loop calling the smp_ops
message_pass function for each of the other cpus in the online cpumask.
Use raw_smp_processor_id() because we are either entering the debugger
or trying to start kdump and the additional warning it not useful were
it to trigger.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
arch/powerpc/include/asm/smp.h | 2 +-
arch/powerpc/kernel/kgdb.c | 2 +-
arch/powerpc/kernel/smp.c | 19 +++++++++++++------
arch/powerpc/xmon/xmon.c | 2 +-
4 files changed, 16 insertions(+), 9 deletions(-)
diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h
index 5087349..91472c5 100644
--- a/arch/powerpc/include/asm/smp.h
+++ b/arch/powerpc/include/asm/smp.h
@@ -35,7 +35,7 @@ extern void cpu_die(void);
#ifdef CONFIG_SMP
-extern void smp_send_debugger_break(int cpu);
+extern void smp_send_debugger_break(void);
extern void smp_message_recv(int);
extern void start_secondary_resume(void);
diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c
index 42850ee..bd9d35f 100644
--- a/arch/powerpc/kernel/kgdb.c
+++ b/arch/powerpc/kernel/kgdb.c
@@ -109,7 +109,7 @@ static int kgdb_call_nmi_hook(struct pt_regs *regs)
#ifdef CONFIG_SMP
void kgdb_roundup_cpus(unsigned long flags)
{
- smp_send_debugger_break(MSG_ALL_BUT_SELF);
+ smp_send_debugger_break();
}
#endif
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 87517ab..b744114 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -218,11 +218,18 @@ void arch_send_call_function_ipi_mask(const struct cpumask *mask)
smp_ops->message_pass(cpu, PPC_MSG_CALL_FUNCTION);
}
-#ifdef CONFIG_DEBUGGER
-void smp_send_debugger_break(int cpu)
+#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
+void smp_send_debugger_break(void)
{
- if (likely(smp_ops))
- smp_ops->message_pass(cpu, PPC_MSG_DEBUGGER_BREAK);
+ int cpu;
+ int me = raw_smp_processor_id();
+
+ if (unlikely(!smp_ops))
+ return;
+
+ for_each_online_cpu(cpu)
+ if (cpu != me)
+ smp_ops->message_pass(cpu, PPC_MSG_DEBUGGER_BREAK);
}
#endif
@@ -230,9 +237,9 @@ void smp_send_debugger_break(int cpu)
void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *))
{
crash_ipi_function_ptr = crash_ipi_callback;
- if (crash_ipi_callback && smp_ops) {
+ if (crash_ipi_callback) {
mb();
- smp_ops->message_pass(MSG_ALL_BUT_SELF, PPC_MSG_DEBUGGER_BREAK);
+ smp_send_debugger_break();
}
}
#endif
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 91309c5..42541bb 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -437,7 +437,7 @@ static int xmon_core(struct pt_regs *regs, int fromipi)
xmon_owner = cpu;
mb();
if (ncpus > 1) {
- smp_send_debugger_break(MSG_ALL_BUT_SELF);
+ smp_send_debugger_break();
/* wait for other cpus to come in */
for (timeout = 100000000; timeout != 0; --timeout) {
if (cpumask_weight(&cpus_in_xmon) >= ncpus)
--
1.7.0.4
^ permalink raw reply related
* [PATCH 11/37] powerpc: remove checks for MSG_ALL and MSG_ALL_BUT_SELF
From: Milton Miller @ 2011-05-11 5:29 UTC (permalink / raw)
To: linuxppc-dev, Benjamin Herrenschmidt
In-Reply-To: <cover.1305092637.git.miltonm@bga.com>
Now that smp_ops->smp_message_pass is always called with an (online) cpu
number for the target remove the checks for MSG_ALL and MSG_ALL_BUT_SELF.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
rediffed for ppc-next xics split
---
arch/powerpc/include/asm/dbell.h | 2 +-
arch/powerpc/include/asm/machdep.h | 2 +-
arch/powerpc/include/asm/xics.h | 2 +-
arch/powerpc/kernel/dbell.c | 29 +++++------------------------
arch/powerpc/platforms/cell/beat_smp.c | 18 +-----------------
arch/powerpc/platforms/cell/smp.c | 18 +-----------------
arch/powerpc/platforms/iseries/smp.c | 18 +-----------------
arch/powerpc/platforms/powermac/smp.c | 17 +++--------------
arch/powerpc/platforms/ps3/smp.c | 22 +++-------------------
arch/powerpc/sysdev/mpic.c | 20 ++------------------
arch/powerpc/sysdev/xics/icp-hv.c | 18 +-----------------
arch/powerpc/sysdev/xics/icp-native.c | 18 +-----------------
12 files changed, 21 insertions(+), 163 deletions(-)
diff --git a/arch/powerpc/include/asm/dbell.h b/arch/powerpc/include/asm/dbell.h
index 0893ab9..3269eb4 100644
--- a/arch/powerpc/include/asm/dbell.h
+++ b/arch/powerpc/include/asm/dbell.h
@@ -27,7 +27,7 @@ enum ppc_dbell {
PPC_G_DBELL_MC = 4, /* guest mcheck doorbell */
};
-extern void doorbell_message_pass(int target, int msg);
+extern void doorbell_message_pass(int cpu, int msg);
extern void doorbell_exception(struct pt_regs *regs);
extern void doorbell_check_self(void);
extern void doorbell_setup_this_cpu(void);
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
index c6345ac..b0802a5 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -31,7 +31,7 @@ struct kimage;
#ifdef CONFIG_SMP
struct smp_ops_t {
- void (*message_pass)(int target, int msg);
+ void (*message_pass)(int cpu, int msg);
int (*probe)(void);
int (*kick_cpu)(int nr);
void (*setup_cpu)(int nr);
diff --git a/arch/powerpc/include/asm/xics.h b/arch/powerpc/include/asm/xics.h
index 6c06306..1750c8d 100644
--- a/arch/powerpc/include/asm/xics.h
+++ b/arch/powerpc/include/asm/xics.h
@@ -40,7 +40,7 @@ struct icp_ops {
void (*teardown_cpu)(void);
void (*flush_ipi)(void);
#ifdef CONFIG_SMP
- void (*message_pass)(int target, int msg);
+ void (*message_pass)(int cpu, int msg);
irq_handler_t ipi_action;
#endif
};
diff --git a/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c
index 3307a52..e49b24c 100644
--- a/arch/powerpc/kernel/dbell.c
+++ b/arch/powerpc/kernel/dbell.c
@@ -34,32 +34,13 @@ void doorbell_setup_this_cpu(void)
info->tag = mfspr(SPRN_PIR) & 0x3fff;
}
-void doorbell_message_pass(int target, int msg)
+void doorbell_message_pass(int cpu, int msg)
{
struct doorbell_cpu_info *info;
- int i;
-
- if (target < NR_CPUS) {
- info = &per_cpu(doorbell_cpu_info, target);
- set_bit(msg, &info->messages);
- ppc_msgsnd(PPC_DBELL, 0, info->tag);
- }
- else if (target == MSG_ALL_BUT_SELF) {
- for_each_online_cpu(i) {
- if (i == smp_processor_id())
- continue;
- info = &per_cpu(doorbell_cpu_info, i);
- set_bit(msg, &info->messages);
- ppc_msgsnd(PPC_DBELL, 0, info->tag);
- }
- }
- else { /* target == MSG_ALL */
- for_each_online_cpu(i) {
- info = &per_cpu(doorbell_cpu_info, i);
- set_bit(msg, &info->messages);
- }
- ppc_msgsnd(PPC_DBELL, PPC_DBELL_MSG_BRDCAST, 0);
- }
+
+ info = &per_cpu(doorbell_cpu_info, cpu);
+ set_bit(msg, &info->messages);
+ ppc_msgsnd(PPC_DBELL, 0, info->tag);
}
void doorbell_exception(struct pt_regs *regs)
diff --git a/arch/powerpc/platforms/cell/beat_smp.c b/arch/powerpc/platforms/cell/beat_smp.c
index 3e86acb..23bbe6e 100644
--- a/arch/powerpc/platforms/cell/beat_smp.c
+++ b/arch/powerpc/platforms/cell/beat_smp.c
@@ -67,22 +67,6 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu)
return 0;
}
-static void smp_beatic_message_pass(int target, int msg)
-{
- unsigned int i;
-
- if (target < NR_CPUS) {
- beatic_cause_IPI(target, msg);
- } else {
- for_each_online_cpu(i) {
- if (target == MSG_ALL_BUT_SELF
- && i == smp_processor_id())
- continue;
- beatic_cause_IPI(i, msg);
- }
- }
-}
-
static int __init smp_beatic_probe(void)
{
return cpumask_weight(cpu_possible_mask);
@@ -105,7 +89,7 @@ static int smp_celleb_cpu_bootable(unsigned int nr)
return 1;
}
static struct smp_ops_t bpa_beatic_smp_ops = {
- .message_pass = smp_beatic_message_pass,
+ .message_pass = beatic_cause_IPI,
.probe = smp_beatic_probe,
.kick_cpu = smp_celleb_kick_cpu,
.setup_cpu = smp_beatic_setup_cpu,
diff --git a/arch/powerpc/platforms/cell/smp.c b/arch/powerpc/platforms/cell/smp.c
index a2161b9..d176e61 100644
--- a/arch/powerpc/platforms/cell/smp.c
+++ b/arch/powerpc/platforms/cell/smp.c
@@ -103,22 +103,6 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu)
return 1;
}
-static void smp_iic_message_pass(int target, int msg)
-{
- unsigned int i;
-
- if (target < NR_CPUS) {
- iic_cause_IPI(target, msg);
- } else {
- for_each_online_cpu(i) {
- if (target == MSG_ALL_BUT_SELF
- && i == smp_processor_id())
- continue;
- iic_cause_IPI(i, msg);
- }
- }
-}
-
static int __init smp_iic_probe(void)
{
iic_request_IPIs();
@@ -168,7 +152,7 @@ static int smp_cell_cpu_bootable(unsigned int nr)
return 1;
}
static struct smp_ops_t bpa_iic_smp_ops = {
- .message_pass = smp_iic_message_pass,
+ .message_pass = iic_cause_IPI,
.probe = smp_iic_probe,
.kick_cpu = smp_cell_kick_cpu,
.setup_cpu = smp_cell_setup_cpu,
diff --git a/arch/powerpc/platforms/iseries/smp.c b/arch/powerpc/platforms/iseries/smp.c
index 02a677a..dcdbc5d 100644
--- a/arch/powerpc/platforms/iseries/smp.c
+++ b/arch/powerpc/platforms/iseries/smp.c
@@ -59,28 +59,12 @@ void iSeries_smp_message_recv(void)
smp_message_recv(msg);
}
-static inline void smp_iSeries_do_message(int cpu, int msg)
+static void smp_iSeries_message_pass(int cpu, int msg)
{
set_bit(msg, &iSeries_smp_message[cpu]);
HvCall_sendIPI(&(paca[cpu]));
}
-static void smp_iSeries_message_pass(int target, int msg)
-{
- int i;
-
- if (target < NR_CPUS)
- smp_iSeries_do_message(target, msg);
- else {
- for_each_online_cpu(i) {
- if ((target == MSG_ALL_BUT_SELF) &&
- (i == smp_processor_id()))
- continue;
- smp_iSeries_do_message(i, msg);
- }
- }
-}
-
static int smp_iSeries_probe(void)
{
return cpumask_weight(cpu_possible_mask);
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c
index 621d4b7..c49e719 100644
--- a/arch/powerpc/platforms/powermac/smp.c
+++ b/arch/powerpc/platforms/powermac/smp.c
@@ -186,21 +186,10 @@ irqreturn_t psurge_primary_intr(int irq, void *d)
return IRQ_HANDLED;
}
-static void smp_psurge_message_pass(int target, int msg)
+static void smp_psurge_message_pass(int cpu, int msg)
{
- int i;
-
- if (num_online_cpus() < 2)
- return;
-
- for_each_online_cpu(i) {
- if (target == MSG_ALL
- || (target == MSG_ALL_BUT_SELF && i != smp_processor_id())
- || target == i) {
- set_bit(msg, &psurge_smp_message[i]);
- psurge_set_ipi(i);
- }
- }
+ set_bit(msg, &psurge_smp_message[cpu]);
+ psurge_set_ipi(cpu);
}
/*
diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c
index 51ffde4..4c44794 100644
--- a/arch/powerpc/platforms/ps3/smp.c
+++ b/arch/powerpc/platforms/ps3/smp.c
@@ -39,7 +39,7 @@
#define MSG_COUNT 4
static DEFINE_PER_CPU(unsigned int [MSG_COUNT], ps3_ipi_virqs);
-static void do_message_pass(int target, int msg)
+static void ps3_smp_message_pass(int cpu, int msg)
{
int result;
unsigned int virq;
@@ -49,28 +49,12 @@ static void do_message_pass(int target, int msg)
return;
}
- virq = per_cpu(ps3_ipi_virqs, target)[msg];
+ virq = per_cpu(ps3_ipi_virqs, cpu)[msg];
result = ps3_send_event_locally(virq);
if (result)
DBG("%s:%d: ps3_send_event_locally(%d, %d) failed"
- " (%d)\n", __func__, __LINE__, target, msg, result);
-}
-
-static void ps3_smp_message_pass(int target, int msg)
-{
- int cpu;
-
- if (target < NR_CPUS)
- do_message_pass(target, msg);
- else if (target == MSG_ALL_BUT_SELF) {
- for_each_online_cpu(cpu)
- if (cpu != smp_processor_id())
- do_message_pass(cpu, msg);
- } else {
- for_each_online_cpu(cpu)
- do_message_pass(cpu, msg);
- }
+ " (%d)\n", __func__, __LINE__, cpu, msg, result);
}
static int ps3_smp_probe(void)
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 116695b..68ea50c 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -1628,31 +1628,15 @@ static void mpic_send_ipi(unsigned int ipi_no, const struct cpumask *cpu_mask)
mpic_physmask(cpumask_bits(cpu_mask)[0]));
}
-void smp_mpic_message_pass(int target, int msg)
+void smp_mpic_message_pass(int cpu, int msg)
{
- cpumask_var_t tmp;
-
/* make sure we're sending something that translates to an IPI */
if ((unsigned int)msg > 3) {
printk("SMP %d: smp_message_pass: unknown msg %d\n",
smp_processor_id(), msg);
return;
}
- switch (target) {
- case MSG_ALL:
- mpic_send_ipi(msg, cpu_online_mask);
- break;
- case MSG_ALL_BUT_SELF:
- alloc_cpumask_var(&tmp, GFP_NOWAIT);
- cpumask_andnot(tmp, cpu_online_mask,
- cpumask_of(smp_processor_id()));
- mpic_send_ipi(msg, tmp);
- free_cpumask_var(tmp);
- break;
- default:
- mpic_send_ipi(msg, cpumask_of(target));
- break;
- }
+ mpic_send_ipi(msg, cpumask_of(cpu));
}
int __init smp_mpic_probe(void)
diff --git a/arch/powerpc/sysdev/xics/icp-hv.c b/arch/powerpc/sysdev/xics/icp-hv.c
index 76e8724..234764c 100644
--- a/arch/powerpc/sysdev/xics/icp-hv.c
+++ b/arch/powerpc/sysdev/xics/icp-hv.c
@@ -118,7 +118,7 @@ static void icp_hv_set_cpu_priority(unsigned char cppr)
#ifdef CONFIG_SMP
-static inline void icp_hv_do_message(int cpu, int msg)
+static void icp_hv_message_pass(int cpu, int msg)
{
unsigned long *tgt = &per_cpu(xics_ipi_message, cpu);
@@ -127,22 +127,6 @@ static inline void icp_hv_do_message(int cpu, int msg)
icp_hv_set_qirr(cpu, IPI_PRIORITY);
}
-static void icp_hv_message_pass(int target, int msg)
-{
- unsigned int i;
-
- if (target < NR_CPUS) {
- icp_hv_do_message(target, msg);
- } else {
- for_each_online_cpu(i) {
- if (target == MSG_ALL_BUT_SELF
- && i == smp_processor_id())
- continue;
- icp_hv_do_message(i, msg);
- }
- }
-}
-
static irqreturn_t icp_hv_ipi_action(int irq, void *dev_id)
{
int cpu = smp_processor_id();
diff --git a/arch/powerpc/sysdev/xics/icp-native.c b/arch/powerpc/sysdev/xics/icp-native.c
index 3508321..246500e 100644
--- a/arch/powerpc/sysdev/xics/icp-native.c
+++ b/arch/powerpc/sysdev/xics/icp-native.c
@@ -134,7 +134,7 @@ static unsigned int icp_native_get_irq(void)
#ifdef CONFIG_SMP
-static inline void icp_native_do_message(int cpu, int msg)
+static void icp_native_message_pass(int cpu, int msg)
{
unsigned long *tgt = &per_cpu(xics_ipi_message, cpu);
@@ -143,22 +143,6 @@ static inline void icp_native_do_message(int cpu, int msg)
icp_native_set_qirr(cpu, IPI_PRIORITY);
}
-static void icp_native_message_pass(int target, int msg)
-{
- unsigned int i;
-
- if (target < NR_CPUS) {
- icp_native_do_message(target, msg);
- } else {
- for_each_online_cpu(i) {
- if (target == MSG_ALL_BUT_SELF
- && i == smp_processor_id())
- continue;
- icp_native_do_message(i, msg);
- }
- }
-}
-
static irqreturn_t icp_native_ipi_action(int irq, void *dev_id)
{
int cpu = smp_processor_id();
--
1.7.0.4
^ permalink raw reply related
* [PATCH 12/37] linux/smp.h: remove unused MSG_ flags
From: Milton Miller @ 2011-05-11 5:29 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel, Benjamin Herrenschmidt
In-Reply-To: <cover.1305092637.git.miltonm@bga.com>
Now that powerpc has removed its use of MSG_ALL_BUT_SELF and MSG_ALL
all these MSG_ flags are unused.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
To be merged by powerpc with the series posted to linuxppc-dev
After the previous 2 patches, grep shows the following false hits (from
partial symbol matches):
find . -name .git -prune -o -name .pc -prune -o -name patches -prune -o -type f|
xargs grep -E 'MSG_(ALL|RESCHEDULE|CALL_FUNCTION|INVALIDATE_TLB|STOP_CPU)'
XFRM_MSG_ALLOCSPI (include/linux/xfrm.h, net/xfrm/xfrm_user.c)
CHANNELMSG_ALLOFFERS_DELIVERED (drivers/staging/hv/)
PPC_MSG_CALL_FUNCTION, PPC_MSG_RESCHEDULE (arch/powerpc/)
SMP_MSG_RESCHEDULE (arch/sh/)
---
include/linux/smp.h | 10 ----------
1 files changed, 0 insertions(+), 10 deletions(-)
diff --git a/include/linux/smp.h b/include/linux/smp.h
index 74243c8..7ad824d 100644
--- a/include/linux/smp.h
+++ b/include/linux/smp.h
@@ -98,16 +98,6 @@ void ipi_call_unlock_irq(void);
*/
int on_each_cpu(smp_call_func_t func, void *info, int wait);
-#define MSG_ALL_BUT_SELF 0x8000 /* Assume <32768 CPU's */
-#define MSG_ALL 0x8001
-
-#define MSG_INVALIDATE_TLB 0x0001 /* Remote processor TLB invalidate */
-#define MSG_STOP_CPU 0x0002 /* Sent to shut down slave CPU's
- * when rebooting
- */
-#define MSG_RESCHEDULE 0x0003 /* Reschedule request from master CPU*/
-#define MSG_CALL_FUNCTION 0x0004 /* Call function on all other CPUs */
-
/*
* Mark the boot cpu "online" so that it can call console drivers in
* printk() and can access its per-cpu storage.
--
1.7.0.4
^ permalink raw reply related
* [PATCH 13/37] powerpc/mpic: simplify ipi cpu mask handling
From: Milton Miller @ 2011-05-11 5:29 UTC (permalink / raw)
To: linuxppc-dev, Benjamin Herrenschmidt
In-Reply-To: <cover.1305092637.git.miltonm@bga.com>
Now that MSG_ALL and MSG_ALL_BUT_SELF have been eliminated,
smp_mpic_mesage_pass no longer needs to lookup the cpumask just to
have mpic_send_ipi extract part of it and recode it in a NR_CPUS loop
by mpic_physmask.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
I chose stepwise refinement but this could be merged into the ALL_BUT_SELF
removal patch.
---
arch/powerpc/sysdev/mpic.c | 24 +++++++++++-------------
1 files changed, 11 insertions(+), 13 deletions(-)
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 68ea50c..53121f6 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -1613,30 +1613,28 @@ void mpic_request_ipis(void)
}
}
-static void mpic_send_ipi(unsigned int ipi_no, const struct cpumask *cpu_mask)
+void smp_mpic_message_pass(int cpu, int msg)
{
struct mpic *mpic = mpic_primary;
+ u32 physmask;
BUG_ON(mpic == NULL);
-#ifdef DEBUG_IPI
- DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, ipi_no);
-#endif
-
- mpic_cpu_write(MPIC_INFO(CPU_IPI_DISPATCH_0) +
- ipi_no * MPIC_INFO(CPU_IPI_DISPATCH_STRIDE),
- mpic_physmask(cpumask_bits(cpu_mask)[0]));
-}
-
-void smp_mpic_message_pass(int cpu, int msg)
-{
/* make sure we're sending something that translates to an IPI */
if ((unsigned int)msg > 3) {
printk("SMP %d: smp_message_pass: unknown msg %d\n",
smp_processor_id(), msg);
return;
}
- mpic_send_ipi(msg, cpumask_of(cpu));
+
+#ifdef DEBUG_IPI
+ DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, msg);
+#endif
+
+ physmask = 1 << get_hard_smp_processor_id(cpu);
+
+ mpic_cpu_write(MPIC_INFO(CPU_IPI_DISPATCH_0) +
+ msg * MPIC_INFO(CPU_IPI_DISPATCH_STRIDE), physmask);
}
int __init smp_mpic_probe(void)
--
1.7.0.4
^ permalink raw reply related
* [PATCH 14/37] powerpc: remove powermac/pic.h
From: Milton Miller @ 2011-05-11 5:29 UTC (permalink / raw)
To: linuxppc-dev, Benjamin Herrenschmidt
In-Reply-To: <cover.1305092637.git.miltonm@bga.com>
Its unused, and of the three declarations, one is duplicated in pmac.h,
the second is static and the third is renamed and static.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
---
arch/powerpc/platforms/powermac/pic.h | 11 -----------
1 files changed, 0 insertions(+), 11 deletions(-)
delete mode 100644 arch/powerpc/platforms/powermac/pic.h
diff --git a/arch/powerpc/platforms/powermac/pic.h b/arch/powerpc/platforms/powermac/pic.h
deleted file mode 100644
index d622a83..0000000
--- a/arch/powerpc/platforms/powermac/pic.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef __PPC_PLATFORMS_PMAC_PIC_H
-#define __PPC_PLATFORMS_PMAC_PIC_H
-
-#include <linux/irq.h>
-
-extern struct irq_chip pmac_pic;
-
-extern void pmac_pic_init(void);
-extern int pmac_get_irq(void);
-
-#endif /* __PPC_PLATFORMS_PMAC_PIC_H */
--
1.7.0.4
^ permalink raw reply related
* [PATCH 15/37] powerpc: remove alloc_maybe_bootmem for zalloc version
From: Milton Miller @ 2011-05-11 5:29 UTC (permalink / raw)
To: linuxppc-dev, Benjamin Herrenschmidt
In-Reply-To: <cover.1305092637.git.miltonm@bga.com>
Replace all remaining callers of alloc_maybe_bootmem with
zalloc_maybe_bootmem. The callsite in pci_dn is followed with a
memset to clear the memory, and not zeroing at the other callsites
in the celleb fake pci code could lead to following uninitialized
memory as pointers or even freeing said pointers on error paths.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
arch/powerpc/include/asm/system.h | 2 --
arch/powerpc/kernel/pci_dn.c | 3 +--
arch/powerpc/lib/alloc.c | 8 --------
arch/powerpc/platforms/cell/celleb_pci.c | 6 +++---
4 files changed, 4 insertions(+), 15 deletions(-)
diff --git a/arch/powerpc/include/asm/system.h b/arch/powerpc/include/asm/system.h
index 5e474dd..2dc595d 100644
--- a/arch/powerpc/include/asm/system.h
+++ b/arch/powerpc/include/asm/system.h
@@ -219,8 +219,6 @@ extern int mem_init_done; /* set on boot once kmalloc can be called */
extern int init_bootmem_done; /* set once bootmem is available */
extern phys_addr_t memory_limit;
extern unsigned long klimit;
-
-extern void *alloc_maybe_bootmem(size_t size, gfp_t mask);
extern void *zalloc_maybe_bootmem(size_t size, gfp_t mask);
extern int powersave_nap; /* set if nap mode can be used in idle loop */
diff --git a/arch/powerpc/kernel/pci_dn.c b/arch/powerpc/kernel/pci_dn.c
index d225d99..6baabc1 100644
--- a/arch/powerpc/kernel/pci_dn.c
+++ b/arch/powerpc/kernel/pci_dn.c
@@ -43,10 +43,9 @@ void * __devinit update_dn_pci_info(struct device_node *dn, void *data)
const u32 *regs;
struct pci_dn *pdn;
- pdn = alloc_maybe_bootmem(sizeof(*pdn), GFP_KERNEL);
+ pdn = zalloc_maybe_bootmem(sizeof(*pdn), GFP_KERNEL);
if (pdn == NULL)
return NULL;
- memset(pdn, 0, sizeof(*pdn));
dn->data = pdn;
pdn->node = dn;
pdn->phb = phb;
diff --git a/arch/powerpc/lib/alloc.c b/arch/powerpc/lib/alloc.c
index f53e09c..13b676c 100644
--- a/arch/powerpc/lib/alloc.c
+++ b/arch/powerpc/lib/alloc.c
@@ -6,14 +6,6 @@
#include <asm/system.h>
-void * __init_refok alloc_maybe_bootmem(size_t size, gfp_t mask)
-{
- if (mem_init_done)
- return kmalloc(size, mask);
- else
- return alloc_bootmem(size);
-}
-
void * __init_refok zalloc_maybe_bootmem(size_t size, gfp_t mask)
{
void *p;
diff --git a/arch/powerpc/platforms/cell/celleb_pci.c b/arch/powerpc/platforms/cell/celleb_pci.c
index 2904b0a..5822141 100644
--- a/arch/powerpc/platforms/cell/celleb_pci.c
+++ b/arch/powerpc/platforms/cell/celleb_pci.c
@@ -319,7 +319,7 @@ static int __init celleb_setup_fake_pci_device(struct device_node *node,
size = 256;
config = &private->fake_config[devno][fn];
- *config = alloc_maybe_bootmem(size, GFP_KERNEL);
+ *config = zalloc_maybe_bootmem(size, GFP_KERNEL);
if (*config == NULL) {
printk(KERN_ERR "PCI: "
"not enough memory for fake configuration space\n");
@@ -330,7 +330,7 @@ static int __init celleb_setup_fake_pci_device(struct device_node *node,
size = sizeof(struct celleb_pci_resource);
res = &private->res[devno][fn];
- *res = alloc_maybe_bootmem(size, GFP_KERNEL);
+ *res = zalloc_maybe_bootmem(size, GFP_KERNEL);
if (*res == NULL) {
printk(KERN_ERR
"PCI: not enough memory for resource data space\n");
@@ -431,7 +431,7 @@ static int __init phb_set_bus_ranges(struct device_node *dev,
static void __init celleb_alloc_private_mem(struct pci_controller *hose)
{
hose->private_data =
- alloc_maybe_bootmem(sizeof(struct celleb_pci_private),
+ zalloc_maybe_bootmem(sizeof(struct celleb_pci_private),
GFP_KERNEL);
}
--
1.7.0.4
^ permalink raw reply related
* [PATCH 16/37] powerpc: remove stubbed beat smp support
From: Milton Miller @ 2011-05-11 5:29 UTC (permalink / raw)
To: linuxppc-dev, Benjamin Herrenschmidt
In-Reply-To: <cover.1305092637.git.miltonm@bga.com>
I have no idea if the beat hypervisor supports multiple cpus in
a partition, but the code has not been touched since these stubs
were added in February of 2007 except to move them in April of 2008.
These are stubs: start_cpu always returns fail (which is dropped),
the message passing and reciving are empty functions, and the top
of file comment says "Incomplete".
Signed-off-by: Milton Miller <miltonm@bga.com>
---
arch/powerpc/platforms/cell/Makefile | 1 -
arch/powerpc/platforms/cell/beat_interrupt.c | 16 ----
arch/powerpc/platforms/cell/beat_interrupt.h | 3 -
arch/powerpc/platforms/cell/beat_smp.c | 107 --------------------------
arch/powerpc/platforms/cell/celleb_setup.c | 4 -
5 files changed, 0 insertions(+), 131 deletions(-)
delete mode 100644 arch/powerpc/platforms/cell/beat_smp.c
diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile
index 8839ef6..a4a8935 100644
--- a/arch/powerpc/platforms/cell/Makefile
+++ b/arch/powerpc/platforms/cell/Makefile
@@ -43,7 +43,6 @@ obj-y += celleb_setup.o \
beat_hvCall.o beat_interrupt.o \
beat_iommu.o
-obj-$(CONFIG_SMP) += beat_smp.o
obj-$(CONFIG_PPC_UDBG_BEAT) += beat_udbg.o
obj-$(CONFIG_SERIAL_TXX9) += celleb_scc_sio.o
obj-$(CONFIG_SPU_BASE) += beat_spu_priv1.o
diff --git a/arch/powerpc/platforms/cell/beat_interrupt.c b/arch/powerpc/platforms/cell/beat_interrupt.c
index 4cb9e14..d46f7e4 100644
--- a/arch/powerpc/platforms/cell/beat_interrupt.c
+++ b/arch/powerpc/platforms/cell/beat_interrupt.c
@@ -257,22 +257,6 @@ void __init beatic_init_IRQ(void)
irq_set_default_host(beatic_host);
}
-#ifdef CONFIG_SMP
-
-/* Nullified to compile with SMP mode */
-void beatic_setup_cpu(int cpu)
-{
-}
-
-void beatic_cause_IPI(int cpu, int mesg)
-{
-}
-
-void beatic_request_IPIs(void)
-{
-}
-#endif /* CONFIG_SMP */
-
void beatic_deinit_IRQ(void)
{
int i;
diff --git a/arch/powerpc/platforms/cell/beat_interrupt.h b/arch/powerpc/platforms/cell/beat_interrupt.h
index b470fd0..a7e52f9 100644
--- a/arch/powerpc/platforms/cell/beat_interrupt.h
+++ b/arch/powerpc/platforms/cell/beat_interrupt.h
@@ -24,9 +24,6 @@
extern void beatic_init_IRQ(void);
extern unsigned int beatic_get_irq(void);
-extern void beatic_cause_IPI(int cpu, int mesg);
-extern void beatic_request_IPIs(void);
-extern void beatic_setup_cpu(int);
extern void beatic_deinit_IRQ(void);
#endif
diff --git a/arch/powerpc/platforms/cell/beat_smp.c b/arch/powerpc/platforms/cell/beat_smp.c
deleted file mode 100644
index 23bbe6e..0000000
--- a/arch/powerpc/platforms/cell/beat_smp.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * SMP support for Celleb platform. (Incomplete)
- *
- * (C) Copyright 2006 TOSHIBA CORPORATION
- *
- * This code is based on arch/powerpc/platforms/cell/smp.c:
- * Dave Engebretsen, Peter Bergner, and
- * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com
- * Plus various changes from other IBM teams...
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#undef DEBUG
-
-#include <linux/kernel.h>
-#include <linux/smp.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/threads.h>
-#include <linux/cpu.h>
-
-#include <asm/irq.h>
-#include <asm/smp.h>
-#include <asm/machdep.h>
-#include <asm/udbg.h>
-
-#include "beat_interrupt.h"
-
-#ifdef DEBUG
-#define DBG(fmt...) udbg_printf(fmt)
-#else
-#define DBG(fmt...)
-#endif
-
-/*
- * The primary thread of each non-boot processor is recorded here before
- * smp init.
- */
-/* static cpumask_t of_spin_map; */
-
-/**
- * smp_startup_cpu() - start the given cpu
- *
- * At boot time, there is nothing to do for primary threads which were
- * started from Open Firmware. For anything else, call RTAS with the
- * appropriate start location.
- *
- * Returns:
- * 0 - failure
- * 1 - success
- */
-static inline int __devinit smp_startup_cpu(unsigned int lcpu)
-{
- return 0;
-}
-
-static int __init smp_beatic_probe(void)
-{
- return cpumask_weight(cpu_possible_mask);
-}
-
-static void __devinit smp_beatic_setup_cpu(int cpu)
-{
- beatic_setup_cpu(cpu);
-}
-
-static int __devinit smp_celleb_kick_cpu(int nr)
-{
- BUG_ON(nr < 0 || nr >= NR_CPUS);
-
- return smp_startup_cpu(nr);
-}
-
-static int smp_celleb_cpu_bootable(unsigned int nr)
-{
- return 1;
-}
-static struct smp_ops_t bpa_beatic_smp_ops = {
- .message_pass = beatic_cause_IPI,
- .probe = smp_beatic_probe,
- .kick_cpu = smp_celleb_kick_cpu,
- .setup_cpu = smp_beatic_setup_cpu,
- .cpu_bootable = smp_celleb_cpu_bootable,
-};
-
-/* This is called very early */
-void __init smp_init_celleb(void)
-{
- DBG(" -> smp_init_celleb()\n");
-
- smp_ops = &bpa_beatic_smp_ops;
-
- DBG(" <- smp_init_celleb()\n");
-}
diff --git a/arch/powerpc/platforms/cell/celleb_setup.c b/arch/powerpc/platforms/cell/celleb_setup.c
index e538455..d58d9ba 100644
--- a/arch/powerpc/platforms/cell/celleb_setup.c
+++ b/arch/powerpc/platforms/cell/celleb_setup.c
@@ -128,10 +128,6 @@ static void __init celleb_setup_arch_beat(void)
spu_management_ops = &spu_management_of_ops;
#endif
-#ifdef CONFIG_SMP
- smp_init_celleb();
-#endif
-
celleb_setup_arch_common();
}
--
1.7.0.4
^ permalink raw reply related
* [PATCH 19/37] powerpc: consolidate ipi message mux and demux
From: Milton Miller @ 2011-05-11 5:29 UTC (permalink / raw)
To: linuxppc-dev, Benjamin Herrenschmidt
In-Reply-To: <cover.1305092637.git.miltonm@bga.com>
Consolidate the mux and demux of ipi messages into smp.c and call
a new smp_ops callback to actually trigger the ipi.
The powerpc architecture code is optimised for having 4 distinct
ipi triggers, which are mapped to 4 distinct messages (ipi many, ipi
single, scheduler ipi, and enter debugger). However, several interrupt
controllers only provide a single software triggered interrupt that
can be delivered to each cpu. To resolve this limitation, each smp_ops
implementation created a per-cpu variable that is manipulated with atomic
bitops. Since these lines will be contended they are optimialy marked as
shared_aligned and take a full cache line for each cpu. Distro kernels
may have 2 or 3 of these in their config, each taking per-cpu space
even though at most one will be in use.
This consolidation removes smp_message_recv and replaces the single call
actions cases with direct calls from the common message recognition loop.
The complicated debugger ipi case with its muxed crash handling code is
moved to debug_ipi_action which is now called from the demux code (instead
of the multi-message action calling smp_message_recv).
I put a call to reschedule_action to increase the likelyhood of correctly
merging the anticipated scheduler_ipi() hook coming from the scheduler
tree; that single required call can be inlined later.
The actual message decode is a copy of the old pseries xics code with its
memory barriers and cache line spacing, augmented with a per-cpu unsigned
long based on the book-e doorbell code. The optional data is set via a
callback from the implementation and is passed to the new cause-ipi hook
along with the logical cpu number. While currently only the doorbell
implemntation uses this data it should be almost zero cost to retrieve and
pass it -- it adds a single register load for the argument from the same
cache line to which we just completed a store and the register is dead
on return from the call. I extended the data element from unsigned int
to unsigned long in case some other code wanted to associate a pointer.
The doorbell check_self is replaced by a call to smp_muxed_ipi_resend,
conditioned on the CPU_DBELL feature. The ifdef guard could be relaxed
to CONFIG_SMP but I left it with BOOKE for now.
Also, the doorbell interrupt vector for book-e was not calling irq_enter
and irq_exit, which throws off cpu accounting and causes code to not
realize it is running in interrupt context. Add the missing calls.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
This requires patch 3780 be applied first for cell to compile.
---
arch/powerpc/include/asm/dbell.h | 3 +-
arch/powerpc/include/asm/smp.h | 14 +++--
arch/powerpc/include/asm/xics.h | 2 +-
arch/powerpc/kernel/dbell.c | 46 +++-------------
arch/powerpc/kernel/irq.c | 4 +-
arch/powerpc/kernel/smp.c | 92 +++++++++++++++++++++----------
arch/powerpc/platforms/85xx/smp.c | 6 ++-
arch/powerpc/platforms/iseries/irq.c | 3 +-
arch/powerpc/platforms/iseries/smp.c | 23 +-------
arch/powerpc/platforms/iseries/smp.h | 6 --
arch/powerpc/platforms/powermac/smp.c | 27 ++-------
arch/powerpc/platforms/pseries/smp.c | 3 +-
arch/powerpc/sysdev/xics/icp-hv.c | 10 +---
arch/powerpc/sysdev/xics/icp-native.c | 10 +---
arch/powerpc/sysdev/xics/xics-common.c | 30 +----------
15 files changed, 107 insertions(+), 172 deletions(-)
delete mode 100644 arch/powerpc/platforms/iseries/smp.h
diff --git a/arch/powerpc/include/asm/dbell.h b/arch/powerpc/include/asm/dbell.h
index 3269eb4..9c70d0c 100644
--- a/arch/powerpc/include/asm/dbell.h
+++ b/arch/powerpc/include/asm/dbell.h
@@ -27,9 +27,8 @@ enum ppc_dbell {
PPC_G_DBELL_MC = 4, /* guest mcheck doorbell */
};
-extern void doorbell_message_pass(int cpu, int msg);
+extern void doorbell_cause_ipi(int cpu, unsigned long data);
extern void doorbell_exception(struct pt_regs *regs);
-extern void doorbell_check_self(void);
extern void doorbell_setup_this_cpu(void);
static inline void ppc_msgsnd(enum ppc_dbell type, u32 flags, u32 tag)
diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h
index 6f7c95c..9ae64bf 100644
--- a/arch/powerpc/include/asm/smp.h
+++ b/arch/powerpc/include/asm/smp.h
@@ -20,6 +20,7 @@
#include <linux/threads.h>
#include <linux/cpumask.h>
#include <linux/kernel.h>
+#include <linux/irqreturn.h>
#ifndef __ASSEMBLY__
@@ -37,6 +38,7 @@ extern void cpu_die(void);
struct smp_ops_t {
void (*message_pass)(int cpu, int msg);
+ void (*cause_ipi)(int cpu, unsigned long data);
int (*probe)(void);
int (*kick_cpu)(int nr);
void (*setup_cpu)(int nr);
@@ -49,7 +51,6 @@ struct smp_ops_t {
};
extern void smp_send_debugger_break(void);
-extern void smp_message_recv(int);
extern void start_secondary_resume(void);
extern void __devinit smp_generic_give_timebase(void);
extern void __devinit smp_generic_take_timebase(void);
@@ -109,13 +110,16 @@ extern int cpu_to_core_id(int cpu);
#define PPC_MSG_CALL_FUNC_SINGLE 2
#define PPC_MSG_DEBUGGER_BREAK 3
-/*
- * irq controllers that have dedicated ipis per message and don't
- * need additional code in the action handler may use this
- */
+/* for irq controllers that have dedicated ipis per message (4) */
extern int smp_request_message_ipi(int virq, int message);
extern const char *smp_ipi_name[];
+/* for irq controllers with only a single ipi */
+extern void smp_muxed_ipi_set_data(int cpu, unsigned long data);
+extern void smp_muxed_ipi_message_pass(int cpu, int msg);
+extern void smp_muxed_ipi_resend(void);
+extern irqreturn_t smp_ipi_demux(void);
+
void smp_init_iSeries(void);
void smp_init_pSeries(void);
void smp_init_cell(void);
diff --git a/arch/powerpc/include/asm/xics.h b/arch/powerpc/include/asm/xics.h
index 1750c8d..b183a40 100644
--- a/arch/powerpc/include/asm/xics.h
+++ b/arch/powerpc/include/asm/xics.h
@@ -40,7 +40,7 @@ struct icp_ops {
void (*teardown_cpu)(void);
void (*flush_ipi)(void);
#ifdef CONFIG_SMP
- void (*message_pass)(int cpu, int msg);
+ void (*cause_ipi)(int cpu, unsigned long data);
irq_handler_t ipi_action;
#endif
};
diff --git a/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c
index e49b24c..2cc451a 100644
--- a/arch/powerpc/kernel/dbell.c
+++ b/arch/powerpc/kernel/dbell.c
@@ -13,65 +13,35 @@
#include <linux/kernel.h>
#include <linux/smp.h>
#include <linux/threads.h>
-#include <linux/percpu.h>
+#include <linux/hardirq.h>
#include <asm/dbell.h>
#include <asm/irq_regs.h>
#ifdef CONFIG_SMP
-struct doorbell_cpu_info {
- unsigned long messages; /* current messages bits */
- unsigned int tag; /* tag value */
-};
-
-static DEFINE_PER_CPU(struct doorbell_cpu_info, doorbell_cpu_info);
-
void doorbell_setup_this_cpu(void)
{
- struct doorbell_cpu_info *info = &__get_cpu_var(doorbell_cpu_info);
+ unsigned long tag = mfspr(SPRN_PIR) & 0x3fff;
- info->messages = 0;
- info->tag = mfspr(SPRN_PIR) & 0x3fff;
+ smp_muxed_ipi_set_data(smp_processor_id(), tag);
}
-void doorbell_message_pass(int cpu, int msg)
+void doorbell_cause_ipi(int cpu, unsigned long data)
{
- struct doorbell_cpu_info *info;
-
- info = &per_cpu(doorbell_cpu_info, cpu);
- set_bit(msg, &info->messages);
- ppc_msgsnd(PPC_DBELL, 0, info->tag);
+ ppc_msgsnd(PPC_DBELL, 0, data);
}
void doorbell_exception(struct pt_regs *regs)
{
struct pt_regs *old_regs = set_irq_regs(regs);
- struct doorbell_cpu_info *info = &__get_cpu_var(doorbell_cpu_info);
- int msg;
- /* Warning: regs can be NULL when called from irq enable */
+ irq_enter();
- if (!info->messages || (num_online_cpus() < 2))
- goto out;
+ smp_ipi_demux();
- for (msg = 0; msg < 4; msg++)
- if (test_and_clear_bit(msg, &info->messages))
- smp_message_recv(msg);
-
-out:
+ irq_exit();
set_irq_regs(old_regs);
}
-
-void doorbell_check_self(void)
-{
- struct doorbell_cpu_info *info = &__get_cpu_var(doorbell_cpu_info);
-
- if (!info->messages)
- return;
-
- ppc_msgsnd(PPC_DBELL, 0, info->tag);
-}
-
#else /* CONFIG_SMP */
void doorbell_exception(struct pt_regs *regs)
{
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index a81dd74..826552c 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -66,7 +66,6 @@
#include <asm/ptrace.h>
#include <asm/machdep.h>
#include <asm/udbg.h>
-#include <asm/dbell.h>
#include <asm/smp.h>
#ifdef CONFIG_PPC64
@@ -160,7 +159,8 @@ notrace void arch_local_irq_restore(unsigned long en)
#if defined(CONFIG_BOOKE) && defined(CONFIG_SMP)
/* Check for pending doorbell interrupts and resend to ourself */
- doorbell_check_self();
+ if (cpu_has_feature(CPU_FTR_DBELL))
+ smp_muxed_ipi_resend();
#endif
/*
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index b744114..72717e1 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -111,35 +111,6 @@ int __devinit smp_generic_kick_cpu(int nr)
}
#endif
-void smp_message_recv(int msg)
-{
- switch(msg) {
- case PPC_MSG_CALL_FUNCTION:
- generic_smp_call_function_interrupt();
- break;
- case PPC_MSG_RESCHEDULE:
- /* we notice need_resched on exit */
- break;
- case PPC_MSG_CALL_FUNC_SINGLE:
- generic_smp_call_function_single_interrupt();
- break;
- case PPC_MSG_DEBUGGER_BREAK:
- if (crash_ipi_function_ptr) {
- crash_ipi_function_ptr(get_irq_regs());
- break;
- }
-#ifdef CONFIG_DEBUGGER
- debugger_ipi(get_irq_regs());
- break;
-#endif /* CONFIG_DEBUGGER */
- /* FALLTHROUGH */
- default:
- printk("SMP %d: smp_message_recv(): unknown msg %d\n",
- smp_processor_id(), msg);
- break;
- }
-}
-
static irqreturn_t call_function_action(int irq, void *data)
{
generic_smp_call_function_interrupt();
@@ -160,7 +131,15 @@ static irqreturn_t call_function_single_action(int irq, void *data)
static irqreturn_t debug_ipi_action(int irq, void *data)
{
- smp_message_recv(PPC_MSG_DEBUGGER_BREAK);
+ if (crash_ipi_function_ptr) {
+ crash_ipi_function_ptr(get_irq_regs());
+ return IRQ_HANDLED;
+ }
+
+#ifdef CONFIG_DEBUGGER
+ debugger_ipi(get_irq_regs());
+#endif /* CONFIG_DEBUGGER */
+
return IRQ_HANDLED;
}
@@ -199,6 +178,59 @@ int smp_request_message_ipi(int virq, int msg)
return err;
}
+struct cpu_messages {
+ unsigned long messages; /* current messages bits */
+ unsigned long data; /* data for cause ipi */
+};
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct cpu_messages, ipi_message);
+
+void smp_muxed_ipi_set_data(int cpu, unsigned long data)
+{
+ struct cpu_messages *info = &per_cpu(ipi_message, cpu);
+
+ info->data = data;
+}
+
+void smp_muxed_ipi_message_pass(int cpu, int msg)
+{
+ struct cpu_messages *info = &per_cpu(ipi_message, cpu);
+ unsigned long *tgt = &info->messages;
+
+ set_bit(msg, tgt);
+ mb();
+ smp_ops->cause_ipi(cpu, info->data);
+}
+
+void smp_muxed_ipi_resend(void)
+{
+ struct cpu_messages *info = &__get_cpu_var(ipi_message);
+ unsigned long *tgt = &info->messages;
+
+ if (*tgt)
+ smp_ops->cause_ipi(smp_processor_id(), info->data);
+}
+
+irqreturn_t smp_ipi_demux(void)
+{
+ struct cpu_messages *info = &__get_cpu_var(ipi_message);
+ unsigned long *tgt = &info->messages;
+
+ mb(); /* order any irq clear */
+ while (*tgt) {
+ if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, tgt))
+ generic_smp_call_function_interrupt();
+ if (test_and_clear_bit(PPC_MSG_RESCHEDULE, tgt))
+ reschedule_action(0, NULL); /* upcoming sched hook */
+ if (test_and_clear_bit(PPC_MSG_CALL_FUNC_SINGLE, tgt))
+ generic_smp_call_function_single_interrupt();
+#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
+ if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK, tgt))
+ debug_ipi_action(0, NULL);
+#endif
+ }
+ return IRQ_HANDLED;
+}
+
void smp_send_reschedule(int cpu)
{
if (likely(smp_ops))
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index fe3f6a3..d6a93a1 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -235,8 +235,10 @@ void __init mpc85xx_smp_init(void)
smp_85xx_ops.message_pass = smp_mpic_message_pass;
}
- if (cpu_has_feature(CPU_FTR_DBELL))
- smp_85xx_ops.message_pass = doorbell_message_pass;
+ if (cpu_has_feature(CPU_FTR_DBELL)) {
+ smp_85xx_ops.message_pass = smp_muxed_ipi_message_pass;
+ smp_85xx_ops.cause_ipi = doorbell_cause_ipi;
+ }
BUG_ON(!smp_85xx_ops.message_pass);
diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c
index 375c21c..b210345 100644
--- a/arch/powerpc/platforms/iseries/irq.c
+++ b/arch/powerpc/platforms/iseries/irq.c
@@ -42,7 +42,6 @@
#include "irq.h"
#include "pci.h"
#include "call_pci.h"
-#include "smp.h"
#ifdef CONFIG_PCI
@@ -316,7 +315,7 @@ unsigned int iSeries_get_irq(void)
#ifdef CONFIG_SMP
if (get_lppaca()->int_dword.fields.ipi_cnt) {
get_lppaca()->int_dword.fields.ipi_cnt = 0;
- iSeries_smp_message_recv();
+ smp_ipi_demux();
}
#endif /* CONFIG_SMP */
if (hvlpevent_is_pending())
diff --git a/arch/powerpc/platforms/iseries/smp.c b/arch/powerpc/platforms/iseries/smp.c
index dcdbc5d..e3265ad 100644
--- a/arch/powerpc/platforms/iseries/smp.c
+++ b/arch/powerpc/platforms/iseries/smp.c
@@ -42,26 +42,8 @@
#include <asm/cputable.h>
#include <asm/system.h>
-#include "smp.h"
-
-static unsigned long iSeries_smp_message[NR_CPUS];
-
-void iSeries_smp_message_recv(void)
-{
- int cpu = smp_processor_id();
- int msg;
-
- if (num_online_cpus() < 2)
- return;
-
- for (msg = 0; msg < 4; msg++)
- if (test_and_clear_bit(msg, &iSeries_smp_message[cpu]))
- smp_message_recv(msg);
-}
-
-static void smp_iSeries_message_pass(int cpu, int msg)
+static void smp_iSeries_cause_ipi(int cpu, unsigned long data)
{
- set_bit(msg, &iSeries_smp_message[cpu]);
HvCall_sendIPI(&(paca[cpu]));
}
@@ -93,7 +75,8 @@ static void __devinit smp_iSeries_setup_cpu(int nr)
}
static struct smp_ops_t iSeries_smp_ops = {
- .message_pass = smp_iSeries_message_pass,
+ .message_pass = smp_muxed_ipi_message_pass,
+ .cause_ipi = smp_iSeries_cause_ipi,
.probe = smp_iSeries_probe,
.kick_cpu = smp_iSeries_kick_cpu,
.setup_cpu = smp_iSeries_setup_cpu,
diff --git a/arch/powerpc/platforms/iseries/smp.h b/arch/powerpc/platforms/iseries/smp.h
deleted file mode 100644
index d501f7d..0000000
--- a/arch/powerpc/platforms/iseries/smp.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _PLATFORMS_ISERIES_SMP_H
-#define _PLATFORMS_ISERIES_SMP_H
-
-extern void iSeries_smp_message_recv(void);
-
-#endif /* _PLATFORMS_ISERIES_SMP_H */
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c
index c49e719..a340107 100644
--- a/arch/powerpc/platforms/powermac/smp.c
+++ b/arch/powerpc/platforms/powermac/smp.c
@@ -156,28 +156,13 @@ static inline void psurge_clr_ipi(int cpu)
/*
* On powersurge (old SMP powermac architecture) we don't have
* separate IPIs for separate messages like openpic does. Instead
- * we have a bitmap for each processor, where a 1 bit means that
- * the corresponding message is pending for that processor.
- * Ideally each cpu's entry would be in a different cache line.
+ * use the generic demux helpers
* -- paulus.
*/
-static unsigned long psurge_smp_message[NR_CPUS];
-
void psurge_smp_message_recv(void)
{
- int cpu = smp_processor_id();
- int msg;
-
- /* clear interrupt */
- psurge_clr_ipi(cpu);
-
- if (num_online_cpus() < 2)
- return;
-
- /* make sure there is a message there */
- for (msg = 0; msg < 4; msg++)
- if (test_and_clear_bit(msg, &psurge_smp_message[cpu]))
- smp_message_recv(msg);
+ psurge_clr_ipi(smp_processor_id());
+ smp_ipi_demux();
}
irqreturn_t psurge_primary_intr(int irq, void *d)
@@ -186,9 +171,8 @@ irqreturn_t psurge_primary_intr(int irq, void *d)
return IRQ_HANDLED;
}
-static void smp_psurge_message_pass(int cpu, int msg)
+static void smp_psurge_cause_ipi(int cpu, unsigned long data)
{
- set_bit(msg, &psurge_smp_message[cpu]);
psurge_set_ipi(cpu);
}
@@ -428,7 +412,8 @@ void __init smp_psurge_give_timebase(void)
/* PowerSurge-style Macs */
struct smp_ops_t psurge_smp_ops = {
- .message_pass = smp_psurge_message_pass,
+ .message_pass = smp_muxed_ipi_message_pass,
+ .cause_ipi = smp_psurge_cause_ipi,
.probe = smp_psurge_probe,
.kick_cpu = smp_psurge_kick_cpu,
.setup_cpu = smp_psurge_setup_cpu,
diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c
index 95f5781..fbffd7e 100644
--- a/arch/powerpc/platforms/pseries/smp.c
+++ b/arch/powerpc/platforms/pseries/smp.c
@@ -207,7 +207,8 @@ static struct smp_ops_t pSeries_mpic_smp_ops = {
};
static struct smp_ops_t pSeries_xics_smp_ops = {
- .message_pass = NULL, /* Filled at runtime by xics_smp_probe() */
+ .message_pass = smp_muxed_ipi_message_pass,
+ .cause_ipi = NULL, /* Filled at runtime by xics_smp_probe() */
.probe = xics_smp_probe,
.kick_cpu = smp_pSeries_kick_cpu,
.setup_cpu = smp_xics_setup_cpu,
diff --git a/arch/powerpc/sysdev/xics/icp-hv.c b/arch/powerpc/sysdev/xics/icp-hv.c
index 234764c..9518d36 100644
--- a/arch/powerpc/sysdev/xics/icp-hv.c
+++ b/arch/powerpc/sysdev/xics/icp-hv.c
@@ -118,12 +118,8 @@ static void icp_hv_set_cpu_priority(unsigned char cppr)
#ifdef CONFIG_SMP
-static void icp_hv_message_pass(int cpu, int msg)
+static void icp_hv_cause_ipi(int cpu, unsigned long data)
{
- unsigned long *tgt = &per_cpu(xics_ipi_message, cpu);
-
- set_bit(msg, tgt);
- mb();
icp_hv_set_qirr(cpu, IPI_PRIORITY);
}
@@ -133,7 +129,7 @@ static irqreturn_t icp_hv_ipi_action(int irq, void *dev_id)
icp_hv_set_qirr(cpu, 0xff);
- return xics_ipi_dispatch(cpu);
+ return smp_ipi_demux();
}
#endif /* CONFIG_SMP */
@@ -146,7 +142,7 @@ static const struct icp_ops icp_hv_ops = {
.flush_ipi = icp_hv_flush_ipi,
#ifdef CONFIG_SMP
.ipi_action = icp_hv_ipi_action,
- .message_pass = icp_hv_message_pass,
+ .cause_ipi = icp_hv_cause_ipi,
#endif
};
diff --git a/arch/powerpc/sysdev/xics/icp-native.c b/arch/powerpc/sysdev/xics/icp-native.c
index 246500e..1f15ad4 100644
--- a/arch/powerpc/sysdev/xics/icp-native.c
+++ b/arch/powerpc/sysdev/xics/icp-native.c
@@ -134,12 +134,8 @@ static unsigned int icp_native_get_irq(void)
#ifdef CONFIG_SMP
-static void icp_native_message_pass(int cpu, int msg)
+static void icp_native_cause_ipi(int cpu, unsigned long data)
{
- unsigned long *tgt = &per_cpu(xics_ipi_message, cpu);
-
- set_bit(msg, tgt);
- mb();
icp_native_set_qirr(cpu, IPI_PRIORITY);
}
@@ -149,7 +145,7 @@ static irqreturn_t icp_native_ipi_action(int irq, void *dev_id)
icp_native_set_qirr(cpu, 0xff);
- return xics_ipi_dispatch(cpu);
+ return smp_ipi_demux();
}
#endif /* CONFIG_SMP */
@@ -267,7 +263,7 @@ static const struct icp_ops icp_native_ops = {
.flush_ipi = icp_native_flush_ipi,
#ifdef CONFIG_SMP
.ipi_action = icp_native_ipi_action,
- .message_pass = icp_native_message_pass,
+ .cause_ipi = icp_native_cause_ipi,
#endif
};
diff --git a/arch/powerpc/sysdev/xics/xics-common.c b/arch/powerpc/sysdev/xics/xics-common.c
index a0576b7..a31a710 100644
--- a/arch/powerpc/sysdev/xics/xics-common.c
+++ b/arch/powerpc/sysdev/xics/xics-common.c
@@ -126,32 +126,6 @@ void xics_mask_unknown_vec(unsigned int vec)
#ifdef CONFIG_SMP
-DEFINE_PER_CPU_SHARED_ALIGNED(unsigned long, xics_ipi_message);
-
-irqreturn_t xics_ipi_dispatch(int cpu)
-{
- unsigned long *tgt = &per_cpu(xics_ipi_message, cpu);
-
- mb(); /* order mmio clearing qirr */
- while (*tgt) {
- if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, tgt)) {
- smp_message_recv(PPC_MSG_CALL_FUNCTION);
- }
- if (test_and_clear_bit(PPC_MSG_RESCHEDULE, tgt)) {
- smp_message_recv(PPC_MSG_RESCHEDULE);
- }
- if (test_and_clear_bit(PPC_MSG_CALL_FUNC_SINGLE, tgt)) {
- smp_message_recv(PPC_MSG_CALL_FUNC_SINGLE);
- }
-#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
- if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK, tgt)) {
- smp_message_recv(PPC_MSG_DEBUGGER_BREAK);
- }
-#endif
- }
- return IRQ_HANDLED;
-}
-
static void xics_request_ipi(void)
{
unsigned int ipi;
@@ -170,8 +144,8 @@ static void xics_request_ipi(void)
int __init xics_smp_probe(void)
{
- /* Setup message_pass callback based on which ICP is used */
- smp_ops->message_pass = icp_ops->message_pass;
+ /* Setup cause_ipi callback based on which ICP is used */
+ smp_ops->cause_ipi = icp_ops->cause_ipi;
/* Register all the IPIs */
xics_request_ipi();
--
1.7.0.4
^ permalink raw reply related
* [PATCH 18/37] powerpc: move smp_ops_t from machdep.h to smp.h
From: Milton Miller @ 2011-05-11 5:29 UTC (permalink / raw)
To: linuxppc-dev, Benjamin Herrenschmidt
In-Reply-To: <cover.1305092637.git.miltonm@bga.com>
I can't see any reason these functions are needed by machdep.h
and they are all hidden by CONFIG_SMP with no UP alternative.
Also move the declarations for the fallback timebase ops, which
are used to fill in the smp ops.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
arch/powerpc/include/asm/machdep.h | 21 ---------------------
arch/powerpc/include/asm/smp.h | 15 +++++++++++++++
2 files changed, 15 insertions(+), 21 deletions(-)
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
index b0802a5..47cacdd 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -29,21 +29,6 @@ struct file;
struct pci_controller;
struct kimage;
-#ifdef CONFIG_SMP
-struct smp_ops_t {
- void (*message_pass)(int cpu, int msg);
- int (*probe)(void);
- int (*kick_cpu)(int nr);
- void (*setup_cpu)(int nr);
- void (*bringup_done)(void);
- void (*take_timebase)(void);
- void (*give_timebase)(void);
- int (*cpu_disable)(void);
- void (*cpu_die)(unsigned int nr);
- int (*cpu_bootable)(unsigned int nr);
-};
-#endif
-
struct machdep_calls {
char *name;
#ifdef CONFIG_PPC64
@@ -312,12 +297,6 @@ extern sys_ctrler_t sys_ctrler;
#endif /* CONFIG_PPC_PMAC */
-#ifdef CONFIG_SMP
-/* Poor default implementations */
-extern void __devinit smp_generic_give_timebase(void);
-extern void __devinit smp_generic_take_timebase(void);
-#endif /* CONFIG_SMP */
-
/* Functions to produce codes on the leds.
* The SRC code should be unique for the message category and should
diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h
index 91472c5..6f7c95c 100644
--- a/arch/powerpc/include/asm/smp.h
+++ b/arch/powerpc/include/asm/smp.h
@@ -35,9 +35,24 @@ extern void cpu_die(void);
#ifdef CONFIG_SMP
+struct smp_ops_t {
+ void (*message_pass)(int cpu, int msg);
+ int (*probe)(void);
+ int (*kick_cpu)(int nr);
+ void (*setup_cpu)(int nr);
+ void (*bringup_done)(void);
+ void (*take_timebase)(void);
+ void (*give_timebase)(void);
+ int (*cpu_disable)(void);
+ void (*cpu_die)(unsigned int nr);
+ int (*cpu_bootable)(unsigned int nr);
+};
+
extern void smp_send_debugger_break(void);
extern void smp_message_recv(int);
extern void start_secondary_resume(void);
+extern void __devinit smp_generic_give_timebase(void);
+extern void __devinit smp_generic_take_timebase(void);
DECLARE_PER_CPU(unsigned int, cpu_pvr);
--
1.7.0.4
^ permalink raw reply related
* [PATCH 20/37] powerpc: add kconfig for muxed smp ipi support
From: Milton Miller @ 2011-05-11 5:29 UTC (permalink / raw)
To: linuxppc-dev, Benjamin Herrenschmidt
In-Reply-To: <cover.1305092637.git.miltonm@bga.com>
Compile the new smp ipi mux and demux code only if a platform
will make use of it. The new config is selected as required.
The new cause_ipi smp op is only available conditionally to point out
configs where the select is required; this makes setting the op an
immediate fail instead of a deferred unresolved symbol at link.
This also creates a new config for power surge powermac upgrade support
that can be disabled in expert mode but is default on.
I also removed the depends / default y on CONFIG_XICS since it is selected
by PSERIES.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
I kept this seperate mostly because of the addition of the PSURGE kconfig
and to focus the discussion on the seperate concepts but it can be merged
into the previous patch if desireed.
---
arch/powerpc/include/asm/smp.h | 2 ++
arch/powerpc/kernel/smp.c | 2 ++
arch/powerpc/platforms/Kconfig | 11 +++++++++--
arch/powerpc/platforms/Kconfig.cputype | 2 ++
arch/powerpc/platforms/iseries/Kconfig | 1 +
arch/powerpc/platforms/powermac/Kconfig | 11 ++++++++++-
arch/powerpc/platforms/powermac/pic.c | 4 ++--
arch/powerpc/platforms/powermac/smp.c | 8 ++++----
8 files changed, 32 insertions(+), 9 deletions(-)
diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h
index 9ae64bf..11eb404 100644
--- a/arch/powerpc/include/asm/smp.h
+++ b/arch/powerpc/include/asm/smp.h
@@ -38,7 +38,9 @@ extern void cpu_die(void);
struct smp_ops_t {
void (*message_pass)(int cpu, int msg);
+#ifdef CONFIG_PPC_SMP_MUXED_IPI
void (*cause_ipi)(int cpu, unsigned long data);
+#endif
int (*probe)(void);
int (*kick_cpu)(int nr);
void (*setup_cpu)(int nr);
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 72717e1..a28e945 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -178,6 +178,7 @@ int smp_request_message_ipi(int virq, int msg)
return err;
}
+#ifdef CONFIG_PPC_SMP_MUXED_IPI
struct cpu_messages {
unsigned long messages; /* current messages bits */
unsigned long data; /* data for cause ipi */
@@ -230,6 +231,7 @@ irqreturn_t smp_ipi_demux(void)
}
return IRQ_HANDLED;
}
+#endif /* CONFIG_PPC_SMP_MUXED_IPI */
void smp_send_reschedule(int cpu)
{
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index 6059053..ac95735 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -57,15 +57,22 @@ config UDBG_RTAS_CONSOLE
depends on PPC_RTAS
default n
+config PPC_SMP_MUXED_IPI
+ bool
+ help
+ Select this opton if your platform supports SMP and your
+ interrupt controller provides less than 4 interrupts to each
+ cpu. This will enable the generic code to multiplex the 4
+ messages on to one ipi.
+
config PPC_UDBG_BEAT
bool "BEAT based debug console"
depends on PPC_CELLEB
default n
config XICS
- depends on PPC_PSERIES
bool
- default y
+ select PPC_SMP_MUXED_IPI
config IPIC
bool
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index a1e6238..2165b65 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -73,6 +73,7 @@ config PPC_BOOK3S_64
config PPC_BOOK3E_64
bool "Embedded processors"
select PPC_FPU # Make it a choice ?
+ select PPC_SMP_MUXED_IPI
endchoice
@@ -178,6 +179,7 @@ config FSL_BOOKE
config PPC_FSL_BOOK3E
bool
select FSL_EMB_PERFMON
+ select PPC_SMP_MUXED_IPI
default y if FSL_BOOKE
config PTE_64BIT
diff --git a/arch/powerpc/platforms/iseries/Kconfig b/arch/powerpc/platforms/iseries/Kconfig
index ea1d362..b57cda3 100644
--- a/arch/powerpc/platforms/iseries/Kconfig
+++ b/arch/powerpc/platforms/iseries/Kconfig
@@ -1,6 +1,7 @@
config PPC_ISERIES
bool "IBM Legacy iSeries"
depends on PPC64 && PPC_BOOK3S
+ select PPC_SMP_MUXED_IPI
select PPC_INDIRECT_PIO
select PPC_INDIRECT_MMIO
select PPC_PCI_CHOICE if EXPERT
diff --git a/arch/powerpc/platforms/powermac/Kconfig b/arch/powerpc/platforms/powermac/Kconfig
index 1e1a087..1afd10f 100644
--- a/arch/powerpc/platforms/powermac/Kconfig
+++ b/arch/powerpc/platforms/powermac/Kconfig
@@ -18,4 +18,13 @@ config PPC_PMAC64
select PPC_970_NAP
default y
-
+config PPC_PMAC32_PSURGE
+ bool "Support for powersurge upgrade cards" if EXPERT
+ depends on SMP && PPC32 && PPC_PMAC
+ select PPC_SMP_MUXED_IPI
+ default y
+ help
+ The powersurge cpu boards can be used in the generation
+ of powermacs that have a socket for an upgradeable cpu card,
+ including the 7500, 8500, 9500, 9600. Support exists for
+ both dual and quad socket upgrade cards.
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c
index 2f34ad0..b706cb3 100644
--- a/arch/powerpc/platforms/powermac/pic.c
+++ b/arch/powerpc/platforms/powermac/pic.c
@@ -239,7 +239,7 @@ static unsigned int pmac_pic_get_irq(void)
unsigned long bits = 0;
unsigned long flags;
-#ifdef CONFIG_SMP
+#ifdef CONFIG_PPC_PMAC32_PSURGE
void psurge_smp_message_recv(void);
/* IPI's are a hack on the powersurge -- Cort */
@@ -247,7 +247,7 @@ static unsigned int pmac_pic_get_irq(void)
psurge_smp_message_recv();
return NO_IRQ_IGNORE; /* ignore, already handled */
}
-#endif /* CONFIG_SMP */
+#endif /* CONFIG_PPC_PMAC32_PSURGE */
raw_spin_lock_irqsave(&pmac_pic_lock, flags);
for (irq = max_real_irqs; (irq -= 32) >= 0; ) {
int i = irq >> 5;
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c
index a340107..67b6e14 100644
--- a/arch/powerpc/platforms/powermac/smp.c
+++ b/arch/powerpc/platforms/powermac/smp.c
@@ -70,7 +70,7 @@ static void (*pmac_tb_freeze)(int freeze);
static u64 timebase;
static int tb_req;
-#ifdef CONFIG_PPC32
+#ifdef CONFIG_PPC_PMAC32_PSURGE
/*
* Powersurge (old powermac SMP) support.
@@ -420,7 +420,7 @@ struct smp_ops_t psurge_smp_ops = {
.give_timebase = smp_psurge_give_timebase,
.take_timebase = smp_psurge_take_timebase,
};
-#endif /* CONFIG_PPC32 - actually powersurge support */
+#endif /* CONFIG_PPC_PMAC32_PSURGE */
/*
* Core 99 and later support
@@ -980,7 +980,7 @@ void __init pmac_setup_smp(void)
of_node_put(np);
smp_ops = &core99_smp_ops;
}
-#ifdef CONFIG_PPC32
+#ifdef CONFIG_PPC_PMAC32_PSURGE
else {
/* We have to set bits in cpu_possible_mask here since the
* secondary CPU(s) aren't in the device tree. Various
@@ -993,7 +993,7 @@ void __init pmac_setup_smp(void)
set_cpu_possible(cpu, true);
smp_ops = &psurge_smp_ops;
}
-#endif /* CONFIG_PPC32 */
+#endif /* CONFIG_PPC_PMAC32_PSURGE */
#ifdef CONFIG_HOTPLUG_CPU
ppc_md.cpu_die = pmac_cpu_die;
--
1.7.0.4
^ permalink raw reply related
* [PATCH 36/37] powerpc: remove virq_to_host
From: Milton Miller @ 2011-05-11 5:30 UTC (permalink / raw)
To: linuxppc-dev, Benjamin Herrenschmidt; +Cc: Thomas Gleixner
In-Reply-To: <cover.1305092637.git.miltonm@bga.com>
The only references to the irq_map[].host field are internal to
arch/powerpc/kernel/irq.c
Signed-off-by: Milton Miller <miltonm@bga.com>
---
---
arch/powerpc/include/asm/irq.h | 1 -
arch/powerpc/kernel/irq.c | 6 ------
2 files changed, 0 insertions(+), 7 deletions(-)
diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h
index a65d170..1bff591 100644
--- a/arch/powerpc/include/asm/irq.h
+++ b/arch/powerpc/include/asm/irq.h
@@ -129,7 +129,6 @@ struct irq_data;
extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d);
extern irq_hw_number_t virq_to_hw(unsigned int virq);
extern bool virq_is_host(unsigned int virq, struct irq_host *host);
-extern struct irq_host *virq_to_host(unsigned int virq);
/**
* irq_alloc_host - Allocate a new irq_host data structure
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 73cf290..4368b5e 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -516,12 +516,6 @@ bool virq_is_host(unsigned int virq, struct irq_host *host)
}
EXPORT_SYMBOL_GPL(virq_is_host);
-struct irq_host *virq_to_host(unsigned int virq)
-{
- return irq_map[virq].host;
-}
-EXPORT_SYMBOL_GPL(virq_to_host);
-
static int default_irq_host_match(struct irq_host *h, struct device_node *np)
{
return h->of_node != NULL && h->of_node == np;
--
1.7.0.4
^ permalink raw reply related
* [PATCH 22/37] powerpc: xics: cleanup xics_host_map and ipi
From: Milton Miller @ 2011-05-11 5:29 UTC (permalink / raw)
To: linuxppc-dev, Benjamin Herrenschmidt
In-Reply-To: <cover.1305092637.git.miltonm@bga.com>
Since we already have a special case in map to set the ipi handler, use
the desired flow.
If we don't find an ics to handle the interrupt complain instead of
returning 0 without having set a chip or handler.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
arch/powerpc/sysdev/xics/xics-common.c | 10 +++++-----
1 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/arch/powerpc/sysdev/xics/xics-common.c b/arch/powerpc/sysdev/xics/xics-common.c
index a31a710..43b2a79 100644
--- a/arch/powerpc/sysdev/xics/xics-common.c
+++ b/arch/powerpc/sysdev/xics/xics-common.c
@@ -135,9 +135,8 @@ static void xics_request_ipi(void)
/*
* IPIs are marked IRQF_DISABLED as they must run with irqs
- * disabled
+ * disabled, and PERCPU. The handler was set in map.
*/
- irq_set_handler(ipi, handle_percpu_irq);
BUG_ON(request_irq(ipi, icp_ops->ipi_action,
IRQF_DISABLED|IRQF_PERCPU, "IPI", NULL));
}
@@ -341,15 +340,16 @@ static int xics_host_map(struct irq_host *h, unsigned int virq,
/* Don't call into ICS for IPIs */
if (hw == XICS_IPI) {
irq_set_chip_and_handler(virq, &xics_ipi_chip,
- handle_fasteoi_irq);
+ handle_percpu_irq);
return 0;
}
/* Let the ICS setup the chip data */
list_for_each_entry(ics, &ics_list, link)
if (ics->map(ics, virq) == 0)
- break;
- return 0;
+ return 0;
+
+ return -EINVAL;
}
static int xics_host_xlate(struct irq_host *h, struct device_node *ct,
--
1.7.0.4
^ permalink raw reply related
* [PATCH 23/37] powerpc: radix trees are available before init_IRQ
From: Milton Miller @ 2011-05-11 5:29 UTC (permalink / raw)
To: linuxppc-dev, Benjamin Herrenschmidt; +Cc: Thomas Gleixner
In-Reply-To: <cover.1305092637.git.miltonm@bga.com>
Since the generic irq code uses a radix tree for sparse interrupts,
the initcall ordering has been changed to initialize radix trees before
irqs. We no longer need to defer creating revmap radix trees to the
arch_initcall irq_late_init.
Also, the kmem caches are allocated so we don't need to use
zalloc_maybe_bootmem.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
arch/powerpc/kernel/irq.c | 78 ++------------------------------------------
1 files changed, 4 insertions(+), 74 deletions(-)
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 826552c..f42e869 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -493,7 +493,6 @@ struct irq_map_entry {
static LIST_HEAD(irq_hosts);
static DEFINE_RAW_SPINLOCK(irq_big_lock);
-static unsigned int revmap_trees_allocated;
static DEFINE_MUTEX(revmap_trees_mutex);
static struct irq_map_entry irq_map[NR_IRQS];
static unsigned int irq_virq_count = NR_IRQS;
@@ -537,7 +536,7 @@ struct irq_host *irq_alloc_host(struct device_node *of_node,
/* Allocate structure and revmap table if using linear mapping */
if (revmap_type == IRQ_HOST_MAP_LINEAR)
size += revmap_arg * sizeof(unsigned int);
- host = zalloc_maybe_bootmem(size, GFP_KERNEL);
+ host = kzalloc(size, GFP_KERNEL);
if (host == NULL)
return NULL;
@@ -605,6 +604,9 @@ struct irq_host *irq_alloc_host(struct device_node *of_node,
smp_wmb();
host->revmap_data.linear.revmap = rmap;
break;
+ case IRQ_HOST_MAP_TREE:
+ INIT_RADIX_TREE(&host->revmap_data.tree, GFP_KERNEL);
+ break;
default:
break;
}
@@ -839,13 +841,6 @@ void irq_dispose_mapping(unsigned int virq)
host->revmap_data.linear.revmap[hwirq] = NO_IRQ;
break;
case IRQ_HOST_MAP_TREE:
- /*
- * Check if radix tree allocated yet, if not then nothing to
- * remove.
- */
- smp_rmb();
- if (revmap_trees_allocated < 1)
- break;
mutex_lock(&revmap_trees_mutex);
radix_tree_delete(&host->revmap_data.tree, hwirq);
mutex_unlock(&revmap_trees_mutex);
@@ -906,14 +901,6 @@ unsigned int irq_radix_revmap_lookup(struct irq_host *host,
WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE);
/*
- * Check if the radix tree exists and has bee initialized.
- * If not, we fallback to slow mode
- */
- if (revmap_trees_allocated < 2)
- return irq_find_mapping(host, hwirq);
-
- /* Now try to resolve */
- /*
* No rcu_read_lock(ing) needed, the ptr returned can't go under us
* as it's referencing an entry in the static irq_map table.
*/
@@ -935,18 +922,8 @@ unsigned int irq_radix_revmap_lookup(struct irq_host *host,
void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq,
irq_hw_number_t hwirq)
{
-
WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE);
- /*
- * Check if the radix tree exists yet.
- * If not, then the irq will be inserted into the tree when it gets
- * initialized.
- */
- smp_rmb();
- if (revmap_trees_allocated < 1)
- return;
-
if (virq != NO_IRQ) {
mutex_lock(&revmap_trees_mutex);
radix_tree_insert(&host->revmap_data.tree, hwirq,
@@ -1054,53 +1031,6 @@ int arch_early_irq_init(void)
return 0;
}
-/* We need to create the radix trees late */
-static int irq_late_init(void)
-{
- struct irq_host *h;
- unsigned int i;
-
- /*
- * No mutual exclusion with respect to accessors of the tree is needed
- * here as the synchronization is done via the state variable
- * revmap_trees_allocated.
- */
- list_for_each_entry(h, &irq_hosts, link) {
- if (h->revmap_type == IRQ_HOST_MAP_TREE)
- INIT_RADIX_TREE(&h->revmap_data.tree, GFP_KERNEL);
- }
-
- /*
- * Make sure the radix trees inits are visible before setting
- * the flag
- */
- smp_wmb();
- revmap_trees_allocated = 1;
-
- /*
- * Insert the reverse mapping for those interrupts already present
- * in irq_map[].
- */
- mutex_lock(&revmap_trees_mutex);
- for (i = 0; i < irq_virq_count; i++) {
- if (irq_map[i].host &&
- (irq_map[i].host->revmap_type == IRQ_HOST_MAP_TREE))
- radix_tree_insert(&irq_map[i].host->revmap_data.tree,
- irq_map[i].hwirq, &irq_map[i]);
- }
- mutex_unlock(&revmap_trees_mutex);
-
- /*
- * Make sure the radix trees insertions are visible before setting
- * the flag
- */
- smp_wmb();
- revmap_trees_allocated = 2;
-
- return 0;
-}
-arch_initcall(irq_late_init);
-
#ifdef CONFIG_VIRQ_DEBUG
static int virq_debug_show(struct seq_file *m, void *private)
{
--
1.7.0.4
^ permalink raw reply related
* [PATCH 21/37] powerpc: use bytes instead of bitops in smp ipi multiplexing
From: Milton Miller @ 2011-05-11 5:29 UTC (permalink / raw)
To: linuxppc-dev, Benjamin Herrenschmidt
In-Reply-To: <cover.1305092637.git.miltonm@bga.com>
Since there are only 4 messages, we can replace the atomic bit set
(which uses atomic load reserve and store conditional sequence) with
a byte stores to seperate bytes. We still have to perform a load
reserve and store conditional sequence to avoid loosing messages on
reception but we can do that with a single call to xchg.
The do {} while and __BIG_ENDIAN specific mask testing was chosen by
looking at the generated asm code. On gcc-4.4, the bit masking becomes
a simple bit mask and test of the register returned from xchg without
storing and loading the value to the stack like attempts with a union
of bytes and an int (or worse, loading single bit constants from the
constant pool into non-voliatle registers that had to be preseved on
the stack). The do {} while avoids an unconditional branch to the
end of the loop to test the entry / repeat condition of a while loop
and instead optimises for the expected single iteration of the loop.
We have a full mb() at the beginning to cover ordering between send,
ipi, and receive so we can use xchg_local and forgo the further
acquire and release barriers of xchg.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
v4: cast int to char ptr in msg send instead of char[] to int* for xchg/test
v3a: add resend to replace dorbell_check_self
v3: settle on casting from char message[4] __aligned(4) to int ptr
v2: try initialized messages
(ended up with globals for each check value, increased reg pressure)
v1: initial version, check bytes though pointer to result of xchg
(resulted in store to stack then byte load / compare / branch)
---
arch/powerpc/kernel/smp.c | 31 ++++++++++++++++++-------------
1 files changed, 18 insertions(+), 13 deletions(-)
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index a28e945..8321b0a 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -180,7 +180,7 @@ int smp_request_message_ipi(int virq, int msg)
#ifdef CONFIG_PPC_SMP_MUXED_IPI
struct cpu_messages {
- unsigned long messages; /* current messages bits */
+ int messages; /* current messages */
unsigned long data; /* data for cause ipi */
};
static DEFINE_PER_CPU_SHARED_ALIGNED(struct cpu_messages, ipi_message);
@@ -195,9 +195,9 @@ void smp_muxed_ipi_set_data(int cpu, unsigned long data)
void smp_muxed_ipi_message_pass(int cpu, int msg)
{
struct cpu_messages *info = &per_cpu(ipi_message, cpu);
- unsigned long *tgt = &info->messages;
+ char *message = (char *)&info->messages;
- set_bit(msg, tgt);
+ message[msg] = 1;
mb();
smp_ops->cause_ipi(cpu, info->data);
}
@@ -205,30 +205,35 @@ void smp_muxed_ipi_message_pass(int cpu, int msg)
void smp_muxed_ipi_resend(void)
{
struct cpu_messages *info = &__get_cpu_var(ipi_message);
- unsigned long *tgt = &info->messages;
- if (*tgt)
+ if (info->messages)
smp_ops->cause_ipi(smp_processor_id(), info->data);
}
irqreturn_t smp_ipi_demux(void)
{
struct cpu_messages *info = &__get_cpu_var(ipi_message);
- unsigned long *tgt = &info->messages;
+ unsigned int all;
mb(); /* order any irq clear */
- while (*tgt) {
- if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, tgt))
+
+ do {
+ all = xchg_local(&info->messages, 0);
+
+#ifdef __BIG_ENDIAN
+ if (all & (1 << (24 - 8 * PPC_MSG_CALL_FUNCTION)))
generic_smp_call_function_interrupt();
- if (test_and_clear_bit(PPC_MSG_RESCHEDULE, tgt))
+ if (all & (1 << (24 - 8 * PPC_MSG_RESCHEDULE)))
reschedule_action(0, NULL); /* upcoming sched hook */
- if (test_and_clear_bit(PPC_MSG_CALL_FUNC_SINGLE, tgt))
+ if (all & (1 << (24 - 8 * PPC_MSG_CALL_FUNC_SINGLE)))
generic_smp_call_function_single_interrupt();
-#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
- if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK, tgt))
+ if (all & (1 << (24 - 8 * PPC_MSG_DEBUGGER_BREAK)))
debug_ipi_action(0, NULL);
+#else
+#error Unsupported ENDIAN
#endif
- }
+ } while (info->messages);
+
return IRQ_HANDLED;
}
#endif /* CONFIG_PPC_SMP_MUXED_IPI */
--
1.7.0.4
^ permalink raw reply related
* [PATCH 24/37] powerpc: return early if irq_host lookup type is wrong
From: Milton Miller @ 2011-05-11 5:29 UTC (permalink / raw)
To: linuxppc-dev, Benjamin Herrenschmidt; +Cc: Thomas Gleixner
In-Reply-To: <cover.1305092637.git.miltonm@bga.com>
If for some reason the code incrorectly calls the wrong function to
manage the revmap, not only should we warn, we should take action.
However, in the paths we expect to be taken every delivered interrupt
change to WARN_ON_ONCE. Use the if (WARN_ON(x)) format to get the
unlikely for free.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
arch/powerpc/kernel/irq.c | 12 +++++++-----
1 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index f42e869..4a5aa8c 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -814,8 +814,7 @@ void irq_dispose_mapping(unsigned int virq)
return;
host = irq_map[virq].host;
- WARN_ON (host == NULL);
- if (host == NULL)
+ if (WARN_ON(host == NULL))
return;
/* Never unmap legacy interrupts */
@@ -898,7 +897,8 @@ unsigned int irq_radix_revmap_lookup(struct irq_host *host,
struct irq_map_entry *ptr;
unsigned int virq;
- WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE);
+ if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_TREE))
+ return irq_find_mapping(host, hwirq);
/*
* No rcu_read_lock(ing) needed, the ptr returned can't go under us
@@ -922,7 +922,8 @@ unsigned int irq_radix_revmap_lookup(struct irq_host *host,
void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq,
irq_hw_number_t hwirq)
{
- WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE);
+ if (WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE))
+ return;
if (virq != NO_IRQ) {
mutex_lock(&revmap_trees_mutex);
@@ -937,7 +938,8 @@ unsigned int irq_linear_revmap(struct irq_host *host,
{
unsigned int *revmap;
- WARN_ON(host->revmap_type != IRQ_HOST_MAP_LINEAR);
+ if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_LINEAR))
+ return irq_find_mapping(host, hwirq);
/* Check revmap bounds */
if (unlikely(hwirq >= host->revmap_data.linear.size))
--
1.7.0.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox