mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-08-18 02:22:47 -07:00
[MIPS] Add support for MIPS CMP platform.
Signed-off-by: Chris Dearman <chris@mips.com> Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
This commit is contained in:
1 parent
308402445e
commit
39b8d52542
34 files changed
+2191
-123
No files matched your search
@@ -221,6 +221,7 @@ config MIPS_MALTA
|
|||||||
select DMA_NONCOHERENT
|
select DMA_NONCOHERENT
|
||||||
select GENERIC_ISA_DMA
|
select GENERIC_ISA_DMA
|
||||||
select IRQ_CPU
|
select IRQ_CPU
|
||||||
|
select IRQ_GIC
|
||||||
select HW_HAS_PCI
|
select HW_HAS_PCI
|
||||||
select I8253
|
select I8253
|
||||||
select I8259
|
select I8259
|
||||||
@@ -840,6 +841,9 @@ config MIPS_NILE4
|
|||||||
config MIPS_DISABLE_OBSOLETE_IDE
|
config MIPS_DISABLE_OBSOLETE_IDE
|
||||||
bool
|
bool
|
||||||
|
|
||||||
|
config SYNC_R4K
|
||||||
|
bool
|
||||||
|
|
||||||
config NO_IOPORT
|
config NO_IOPORT
|
||||||
def_bool n
|
def_bool n
|
||||||
|
|
||||||
@@ -909,6 +913,9 @@ config IRQ_TXX9
|
|||||||
config IRQ_GT641XX
|
config IRQ_GT641XX
|
||||||
bool
|
bool
|
||||||
|
|
||||||
|
config IRQ_GIC
|
||||||
|
bool
|
||||||
|
|
||||||
config MIPS_BOARDS_GEN
|
config MIPS_BOARDS_GEN
|
||||||
bool
|
bool
|
||||||
|
|
||||||
@@ -1811,6 +1818,17 @@ config NR_CPUS
|
|||||||
performance should round up your number of processors to the next
|
performance should round up your number of processors to the next
|
||||||
power of two.
|
power of two.
|
||||||
|
|
||||||
|
config MIPS_CMP
|
||||||
|
bool "MIPS CMP framework support"
|
||||||
|
depends on SMP
|
||||||
|
select SYNC_R4K
|
||||||
|
select SYS_SUPPORTS_SCHED_SMT
|
||||||
|
select WEAK_ORDERING
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
This is a placeholder option for the GCMP work. It will need to
|
||||||
|
be handled differently...
|
||||||
|
|
||||||
source "kernel/time/Kconfig"
|
source "kernel/time/Kconfig"
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ obj-$(CONFIG_CEVT_TXX9) += cevt-txx9.o
|
|||||||
obj-$(CONFIG_CSRC_BCM1480) += csrc-bcm1480.o
|
obj-$(CONFIG_CSRC_BCM1480) += csrc-bcm1480.o
|
||||||
obj-$(CONFIG_CSRC_R4K) += csrc-r4k.o
|
obj-$(CONFIG_CSRC_R4K) += csrc-r4k.o
|
||||||
obj-$(CONFIG_CSRC_SB1250) += csrc-sb1250.o
|
obj-$(CONFIG_CSRC_SB1250) += csrc-sb1250.o
|
||||||
|
obj-$(CONFIG_SYNC_R4K) += sync-r4k.o
|
||||||
|
|
||||||
binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \
|
binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \
|
||||||
irix5sys.o sysirix.o
|
irix5sys.o sysirix.o
|
||||||
@@ -50,6 +51,7 @@ obj-$(CONFIG_MIPS_MT) += mips-mt.o
|
|||||||
obj-$(CONFIG_MIPS_MT_FPAFF) += mips-mt-fpaff.o
|
obj-$(CONFIG_MIPS_MT_FPAFF) += mips-mt-fpaff.o
|
||||||
obj-$(CONFIG_MIPS_MT_SMTC) += smtc.o smtc-asm.o smtc-proc.o
|
obj-$(CONFIG_MIPS_MT_SMTC) += smtc.o smtc-asm.o smtc-proc.o
|
||||||
obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o
|
obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o
|
||||||
|
obj-$(CONFIG_MIPS_CMP) += smp-cmp.o
|
||||||
obj-$(CONFIG_CPU_MIPSR2) += spram.o
|
obj-$(CONFIG_CPU_MIPSR2) += spram.o
|
||||||
|
|
||||||
obj-$(CONFIG_MIPS_APSP_KSPD) += kspd.o
|
obj-$(CONFIG_MIPS_APSP_KSPD) += kspd.o
|
||||||
@@ -63,6 +65,7 @@ obj-$(CONFIG_IRQ_CPU_RM9K) += irq-rm9000.o
|
|||||||
obj-$(CONFIG_MIPS_BOARDS_GEN) += irq-msc01.o
|
obj-$(CONFIG_MIPS_BOARDS_GEN) += irq-msc01.o
|
||||||
obj-$(CONFIG_IRQ_TXX9) += irq_txx9.o
|
obj-$(CONFIG_IRQ_TXX9) += irq_txx9.o
|
||||||
obj-$(CONFIG_IRQ_GT641XX) += irq-gt641xx.o
|
obj-$(CONFIG_IRQ_GT641XX) += irq-gt641xx.o
|
||||||
|
obj-$(CONFIG_IRQ_GIC) += irq-gic.o
|
||||||
|
|
||||||
obj-$(CONFIG_32BIT) += scall32-o32.o
|
obj-$(CONFIG_32BIT) += scall32-o32.o
|
||||||
obj-$(CONFIG_64BIT) += scall64-64.o
|
obj-$(CONFIG_64BIT) += scall64-64.o
|
||||||
|
|||||||
@@ -169,6 +169,7 @@ static inline void check_wait(void)
|
|||||||
|
|
||||||
case CPU_24K:
|
case CPU_24K:
|
||||||
case CPU_34K:
|
case CPU_34K:
|
||||||
|
case CPU_1004K:
|
||||||
cpu_wait = r4k_wait;
|
cpu_wait = r4k_wait;
|
||||||
if (read_c0_config7() & MIPS_CONF7_WII)
|
if (read_c0_config7() & MIPS_CONF7_WII)
|
||||||
cpu_wait = r4k_wait_irqoff;
|
cpu_wait = r4k_wait_irqoff;
|
||||||
@@ -717,6 +718,9 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c)
|
|||||||
case PRID_IMP_74K:
|
case PRID_IMP_74K:
|
||||||
c->cputype = CPU_74K;
|
c->cputype = CPU_74K;
|
||||||
break;
|
break;
|
||||||
|
case PRID_IMP_1004K:
|
||||||
|
c->cputype = CPU_1004K;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
spram_config();
|
spram_config();
|
||||||
@@ -884,6 +888,7 @@ static __cpuinit const char *cpu_to_name(struct cpuinfo_mips *c)
|
|||||||
case CPU_24K: name = "MIPS 24K"; break;
|
case CPU_24K: name = "MIPS 24K"; break;
|
||||||
case CPU_25KF: name = "MIPS 25Kf"; break;
|
case CPU_25KF: name = "MIPS 25Kf"; break;
|
||||||
case CPU_34K: name = "MIPS 34K"; break;
|
case CPU_34K: name = "MIPS 34K"; break;
|
||||||
|
case CPU_1004K: name = "MIPS 1004K"; break;
|
||||||
case CPU_74K: name = "MIPS 74K"; break;
|
case CPU_74K: name = "MIPS 74K"; break;
|
||||||
case CPU_VR4111: name = "NEC VR4111"; break;
|
case CPU_VR4111: name = "NEC VR4111"; break;
|
||||||
case CPU_VR4121: name = "NEC VR4121"; break;
|
case CPU_VR4121: name = "NEC VR4121"; break;
|
||||||
|
|||||||
@@ -0,0 +1,295 @@
|
|||||||
|
#undef DEBUG
|
||||||
|
|
||||||
|
#include <linux/bitmap.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
|
||||||
|
#include <asm/io.h>
|
||||||
|
#include <asm/gic.h>
|
||||||
|
#include <asm/gcmpregs.h>
|
||||||
|
#include <asm/mips-boards/maltaint.h>
|
||||||
|
#include <asm/irq.h>
|
||||||
|
#include <linux/hardirq.h>
|
||||||
|
#include <asm-generic/bitops/find.h>
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned long _gic_base;
|
||||||
|
static unsigned int _irqbase, _mapsize, numvpes, numintrs;
|
||||||
|
static struct gic_intr_map *_intrmap;
|
||||||
|
|
||||||
|
static struct gic_pcpu_mask pcpu_masks[NR_CPUS];
|
||||||
|
static struct gic_pending_regs pending_regs[NR_CPUS];
|
||||||
|
static struct gic_intrmask_regs intrmask_regs[NR_CPUS];
|
||||||
|
|
||||||
|
#define gic_wedgeb2bok 0 /*
|
||||||
|
* Can GIC handle b2b writes to wedge register?
|
||||||
|
*/
|
||||||
|
#if gic_wedgeb2bok == 0
|
||||||
|
static DEFINE_SPINLOCK(gic_wedgeb2b_lock);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void gic_send_ipi(unsigned int intr)
|
||||||
|
{
|
||||||
|
#if gic_wedgeb2bok == 0
|
||||||
|
unsigned long flags;
|
||||||
|
#endif
|
||||||
|
pr_debug("CPU%d: %s status %08x\n", smp_processor_id(), __func__,
|
||||||
|
read_c0_status());
|
||||||
|
if (!gic_wedgeb2bok)
|
||||||
|
spin_lock_irqsave(&gic_wedgeb2b_lock, flags);
|
||||||
|
GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), 0x80000000 | intr);
|
||||||
|
if (!gic_wedgeb2bok) {
|
||||||
|
(void) GIC_REG(SHARED, GIC_SH_CONFIG);
|
||||||
|
spin_unlock_irqrestore(&gic_wedgeb2b_lock, flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is Malta specific and needs to be exported */
|
||||||
|
static void vpe_local_setup(unsigned int numvpes)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned long timer_interrupt = 5, perf_interrupt = 5;
|
||||||
|
unsigned int vpe_ctl;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setup the default performance counter timer interrupts
|
||||||
|
* for all VPEs
|
||||||
|
*/
|
||||||
|
for (i = 0; i < numvpes; i++) {
|
||||||
|
GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i);
|
||||||
|
|
||||||
|
/* Are Interrupts locally routable? */
|
||||||
|
GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_CTL), vpe_ctl);
|
||||||
|
if (vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK)
|
||||||
|
GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP),
|
||||||
|
GIC_MAP_TO_PIN_MSK | timer_interrupt);
|
||||||
|
|
||||||
|
if (vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK)
|
||||||
|
GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP),
|
||||||
|
GIC_MAP_TO_PIN_MSK | perf_interrupt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int gic_get_int(void)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
unsigned long *pending, *intrmask, *pcpu_mask;
|
||||||
|
unsigned long *pending_abs, *intrmask_abs;
|
||||||
|
|
||||||
|
/* Get per-cpu bitmaps */
|
||||||
|
pending = pending_regs[smp_processor_id()].pending;
|
||||||
|
intrmask = intrmask_regs[smp_processor_id()].intrmask;
|
||||||
|
pcpu_mask = pcpu_masks[smp_processor_id()].pcpu_mask;
|
||||||
|
|
||||||
|
pending_abs = (unsigned long *) GIC_REG_ABS_ADDR(SHARED,
|
||||||
|
GIC_SH_PEND_31_0_OFS);
|
||||||
|
intrmask_abs = (unsigned long *) GIC_REG_ABS_ADDR(SHARED,
|
||||||
|
GIC_SH_MASK_31_0_OFS);
|
||||||
|
|
||||||
|
for (i = 0; i < BITS_TO_LONGS(GIC_NUM_INTRS); i++) {
|
||||||
|
GICREAD(*pending_abs, pending[i]);
|
||||||
|
GICREAD(*intrmask_abs, intrmask[i]);
|
||||||
|
pending_abs++;
|
||||||
|
intrmask_abs++;
|
||||||
|
}
|
||||||
|
|
||||||
|
bitmap_and(pending, pending, intrmask, GIC_NUM_INTRS);
|
||||||
|
bitmap_and(pending, pending, pcpu_mask, GIC_NUM_INTRS);
|
||||||
|
|
||||||
|
i = find_first_bit(pending, GIC_NUM_INTRS);
|
||||||
|
|
||||||
|
pr_debug("CPU%d: %s pend=%d\n", smp_processor_id(), __func__, i);
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int gic_irq_startup(unsigned int irq)
|
||||||
|
{
|
||||||
|
pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
|
||||||
|
irq -= _irqbase;
|
||||||
|
/* FIXME: this is wrong for !GICISWORDLITTLEENDIAN */
|
||||||
|
GICWRITE(GIC_REG_ADDR(SHARED, (GIC_SH_SMASK_31_0_OFS + (irq / 32))),
|
||||||
|
1 << (irq % 32));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gic_irq_ack(unsigned int irq)
|
||||||
|
{
|
||||||
|
#if gic_wedgeb2bok == 0
|
||||||
|
unsigned long flags;
|
||||||
|
#endif
|
||||||
|
pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
|
||||||
|
irq -= _irqbase;
|
||||||
|
GICWRITE(GIC_REG_ADDR(SHARED, (GIC_SH_RMASK_31_0_OFS + (irq / 32))),
|
||||||
|
1 << (irq % 32));
|
||||||
|
|
||||||
|
if (_intrmap[irq].trigtype == GIC_TRIG_EDGE) {
|
||||||
|
if (!gic_wedgeb2bok)
|
||||||
|
spin_lock_irqsave(&gic_wedgeb2b_lock, flags);
|
||||||
|
GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq);
|
||||||
|
if (!gic_wedgeb2bok) {
|
||||||
|
(void) GIC_REG(SHARED, GIC_SH_CONFIG);
|
||||||
|
spin_unlock_irqrestore(&gic_wedgeb2b_lock, flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gic_mask_irq(unsigned int irq)
|
||||||
|
{
|
||||||
|
pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
|
||||||
|
irq -= _irqbase;
|
||||||
|
/* FIXME: this is wrong for !GICISWORDLITTLEENDIAN */
|
||||||
|
GICWRITE(GIC_REG_ADDR(SHARED, (GIC_SH_RMASK_31_0_OFS + (irq / 32))),
|
||||||
|
1 << (irq % 32));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gic_unmask_irq(unsigned int irq)
|
||||||
|
{
|
||||||
|
pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
|
||||||
|
irq -= _irqbase;
|
||||||
|
/* FIXME: this is wrong for !GICISWORDLITTLEENDIAN */
|
||||||
|
GICWRITE(GIC_REG_ADDR(SHARED, (GIC_SH_SMASK_31_0_OFS + (irq / 32))),
|
||||||
|
1 << (irq % 32));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
|
||||||
|
static DEFINE_SPINLOCK(gic_lock);
|
||||||
|
|
||||||
|
static void gic_set_affinity(unsigned int irq, cpumask_t cpumask)
|
||||||
|
{
|
||||||
|
cpumask_t tmp = CPU_MASK_NONE;
|
||||||
|
unsigned long flags;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
pr_debug(KERN_DEBUG "%s called\n", __func__);
|
||||||
|
irq -= _irqbase;
|
||||||
|
|
||||||
|
cpus_and(tmp, cpumask, cpu_online_map);
|
||||||
|
if (cpus_empty(tmp))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Assumption : cpumask refers to a single CPU */
|
||||||
|
spin_lock_irqsave(&gic_lock, flags);
|
||||||
|
for (;;) {
|
||||||
|
/* Re-route this IRQ */
|
||||||
|
GIC_SH_MAP_TO_VPE_SMASK(irq, first_cpu(tmp));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME: assumption that _intrmap is ordered and has no holes
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Update the intr_map */
|
||||||
|
_intrmap[irq].cpunum = first_cpu(tmp);
|
||||||
|
|
||||||
|
/* Update the pcpu_masks */
|
||||||
|
for (i = 0; i < NR_CPUS; i++)
|
||||||
|
clear_bit(irq, pcpu_masks[i].pcpu_mask);
|
||||||
|
set_bit(irq, pcpu_masks[first_cpu(tmp)].pcpu_mask);
|
||||||
|
|
||||||
|
}
|
||||||
|
irq_desc[irq].affinity = cpumask;
|
||||||
|
spin_unlock_irqrestore(&gic_lock, flags);
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static struct irq_chip gic_irq_controller = {
|
||||||
|
.name = "MIPS GIC",
|
||||||
|
.startup = gic_irq_startup,
|
||||||
|
.ack = gic_irq_ack,
|
||||||
|
.mask = gic_mask_irq,
|
||||||
|
.mask_ack = gic_mask_irq,
|
||||||
|
.unmask = gic_unmask_irq,
|
||||||
|
.eoi = gic_unmask_irq,
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
.set_affinity = gic_set_affinity,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
static void __init setup_intr(unsigned int intr, unsigned int cpu,
|
||||||
|
unsigned int pin, unsigned int polarity, unsigned int trigtype)
|
||||||
|
{
|
||||||
|
/* Setup Intr to Pin mapping */
|
||||||
|
if (pin & GIC_MAP_TO_NMI_MSK) {
|
||||||
|
GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)), pin);
|
||||||
|
/* FIXME: hack to route NMI to all cpu's */
|
||||||
|
for (cpu = 0; cpu < NR_CPUS; cpu += 32) {
|
||||||
|
GICWRITE(GIC_REG_ADDR(SHARED,
|
||||||
|
GIC_SH_MAP_TO_VPE_REG_OFF(intr, cpu)),
|
||||||
|
0xffffffff);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)),
|
||||||
|
GIC_MAP_TO_PIN_MSK | pin);
|
||||||
|
/* Setup Intr to CPU mapping */
|
||||||
|
GIC_SH_MAP_TO_VPE_SMASK(intr, cpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup Intr Polarity */
|
||||||
|
GIC_SET_POLARITY(intr, polarity);
|
||||||
|
|
||||||
|
/* Setup Intr Trigger Type */
|
||||||
|
GIC_SET_TRIGGER(intr, trigtype);
|
||||||
|
|
||||||
|
/* Init Intr Masks */
|
||||||
|
GIC_SET_INTR_MASK(intr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __init gic_basic_init(void)
|
||||||
|
{
|
||||||
|
unsigned int i, cpu;
|
||||||
|
|
||||||
|
/* Setup defaults */
|
||||||
|
for (i = 0; i < GIC_NUM_INTRS; i++) {
|
||||||
|
GIC_SET_POLARITY(i, GIC_POL_POS);
|
||||||
|
GIC_SET_TRIGGER(i, GIC_TRIG_LEVEL);
|
||||||
|
GIC_SET_INTR_MASK(i, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup specifics */
|
||||||
|
for (i = 0; i < _mapsize; i++) {
|
||||||
|
cpu = _intrmap[i].cpunum;
|
||||||
|
if (cpu == X)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
setup_intr(_intrmap[i].intrnum,
|
||||||
|
_intrmap[i].cpunum,
|
||||||
|
_intrmap[i].pin,
|
||||||
|
_intrmap[i].polarity,
|
||||||
|
_intrmap[i].trigtype);
|
||||||
|
/* Initialise per-cpu Interrupt software masks */
|
||||||
|
if (_intrmap[i].ipiflag)
|
||||||
|
set_bit(_intrmap[i].intrnum, pcpu_masks[cpu].pcpu_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
vpe_local_setup(numvpes);
|
||||||
|
|
||||||
|
for (i = _irqbase; i < (_irqbase + numintrs); i++)
|
||||||
|
set_irq_chip(i, &gic_irq_controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __init gic_init(unsigned long gic_base_addr,
|
||||||
|
unsigned long gic_addrspace_size,
|
||||||
|
struct gic_intr_map *intr_map, unsigned int intr_map_size,
|
||||||
|
unsigned int irqbase)
|
||||||
|
{
|
||||||
|
unsigned int gicconfig;
|
||||||
|
|
||||||
|
_gic_base = (unsigned long) ioremap_nocache(gic_base_addr,
|
||||||
|
gic_addrspace_size);
|
||||||
|
_irqbase = irqbase;
|
||||||
|
_intrmap = intr_map;
|
||||||
|
_mapsize = intr_map_size;
|
||||||
|
|
||||||
|
GICREAD(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig);
|
||||||
|
numintrs = (gicconfig & GIC_SH_CONFIG_NUMINTRS_MSK) >>
|
||||||
|
GIC_SH_CONFIG_NUMINTRS_SHF;
|
||||||
|
numintrs = ((numintrs + 1) * 8);
|
||||||
|
|
||||||
|
numvpes = (gicconfig & GIC_SH_CONFIG_NUMVPES_MSK) >>
|
||||||
|
GIC_SH_CONFIG_NUMVPES_SHF;
|
||||||
|
|
||||||
|
pr_debug("%s called\n", __func__);
|
||||||
|
|
||||||
|
gic_basic_init();
|
||||||
|
}
|
||||||
@@ -0,0 +1,265 @@
|
|||||||
|
/*
|
||||||
|
* This program is free software; you can distribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License (Version 2) as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope 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.,
|
||||||
|
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 MIPS Technologies, Inc.
|
||||||
|
* Chris Dearman (chris@mips.com)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#undef DEBUG
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/cpumask.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/compiler.h>
|
||||||
|
|
||||||
|
#include <asm/atomic.h>
|
||||||
|
#include <asm/cacheflush.h>
|
||||||
|
#include <asm/cpu.h>
|
||||||
|
#include <asm/processor.h>
|
||||||
|
#include <asm/system.h>
|
||||||
|
#include <asm/hardirq.h>
|
||||||
|
#include <asm/mmu_context.h>
|
||||||
|
#include <asm/smp.h>
|
||||||
|
#include <asm/time.h>
|
||||||
|
#include <asm/mipsregs.h>
|
||||||
|
#include <asm/mipsmtregs.h>
|
||||||
|
#include <asm/mips_mt.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Crude manipulation of the CPU masks to control which
|
||||||
|
* which CPU's are brought online during initialisation
|
||||||
|
*
|
||||||
|
* Beware... this needs to be called after CPU discovery
|
||||||
|
* but before CPU bringup
|
||||||
|
*/
|
||||||
|
static int __init allowcpus(char *str)
|
||||||
|
{
|
||||||
|
cpumask_t cpu_allow_map;
|
||||||
|
char buf[256];
|
||||||
|
int len;
|
||||||
|
|
||||||
|
cpus_clear(cpu_allow_map);
|
||||||
|
if (cpulist_parse(str, cpu_allow_map) == 0) {
|
||||||
|
cpu_set(0, cpu_allow_map);
|
||||||
|
cpus_and(cpu_possible_map, cpu_possible_map, cpu_allow_map);
|
||||||
|
len = cpulist_scnprintf(buf, sizeof(buf)-1, cpu_possible_map);
|
||||||
|
buf[len] = '\0';
|
||||||
|
pr_debug("Allowable CPUs: %s\n", buf);
|
||||||
|
return 1;
|
||||||
|
} else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
__setup("allowcpus=", allowcpus);
|
||||||
|
|
||||||
|
static void ipi_call_function(unsigned int cpu)
|
||||||
|
{
|
||||||
|
unsigned int action = 0;
|
||||||
|
|
||||||
|
pr_debug("CPU%d: %s cpu %d status %08x\n",
|
||||||
|
smp_processor_id(), __func__, cpu, read_c0_status());
|
||||||
|
|
||||||
|
switch (cpu) {
|
||||||
|
case 0:
|
||||||
|
action = GIC_IPI_EXT_INTR_CALLFNC_VPE0;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
action = GIC_IPI_EXT_INTR_CALLFNC_VPE1;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
action = GIC_IPI_EXT_INTR_CALLFNC_VPE2;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
action = GIC_IPI_EXT_INTR_CALLFNC_VPE3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
gic_send_ipi(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ipi_resched(unsigned int cpu)
|
||||||
|
{
|
||||||
|
unsigned int action = 0;
|
||||||
|
|
||||||
|
pr_debug("CPU%d: %s cpu %d status %08x\n",
|
||||||
|
smp_processor_id(), __func__, cpu, read_c0_status());
|
||||||
|
|
||||||
|
switch (cpu) {
|
||||||
|
case 0:
|
||||||
|
action = GIC_IPI_EXT_INTR_RESCHED_VPE0;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
action = GIC_IPI_EXT_INTR_RESCHED_VPE1;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
action = GIC_IPI_EXT_INTR_RESCHED_VPE2;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
action = GIC_IPI_EXT_INTR_RESCHED_VPE3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
gic_send_ipi(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME: This isn't restricted to CMP
|
||||||
|
* The SMVP kernel could use GIC interrupts if available
|
||||||
|
*/
|
||||||
|
void cmp_send_ipi_single(int cpu, unsigned int action)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
local_irq_save(flags);
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case SMP_CALL_FUNCTION:
|
||||||
|
ipi_call_function(cpu);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SMP_RESCHEDULE_YOURSELF:
|
||||||
|
ipi_resched(cpu);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
local_irq_restore(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cmp_send_ipi_mask(cpumask_t mask, unsigned int action)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for_each_cpu_mask(i, mask)
|
||||||
|
cmp_send_ipi_single(i, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cmp_init_secondary(void)
|
||||||
|
{
|
||||||
|
struct cpuinfo_mips *c = ¤t_cpu_data;
|
||||||
|
|
||||||
|
/* Assume GIC is present */
|
||||||
|
change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 | STATUSF_IP6 |
|
||||||
|
STATUSF_IP7);
|
||||||
|
|
||||||
|
/* Enable per-cpu interrupts: platform specific */
|
||||||
|
|
||||||
|
c->core = (read_c0_ebase() >> 1) & 0xff;
|
||||||
|
#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC)
|
||||||
|
c->vpe_id = (read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & TCBIND_CURVPE;
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_MIPS_MT_SMTC
|
||||||
|
c->tc_id = (read_c0_tcbind() >> TCBIND_CURTC_SHIFT) & TCBIND_CURTC;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cmp_smp_finish(void)
|
||||||
|
{
|
||||||
|
pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__);
|
||||||
|
|
||||||
|
/* CDFIXME: remove this? */
|
||||||
|
write_c0_compare(read_c0_count() + (8 * mips_hpt_frequency / HZ));
|
||||||
|
|
||||||
|
#ifdef CONFIG_MIPS_MT_FPAFF
|
||||||
|
/* If we have an FPU, enroll ourselves in the FPU-full mask */
|
||||||
|
if (cpu_has_fpu)
|
||||||
|
cpu_set(smp_processor_id(), mt_fpu_cpumask);
|
||||||
|
#endif /* CONFIG_MIPS_MT_FPAFF */
|
||||||
|
|
||||||
|
local_irq_enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cmp_cpus_done(void)
|
||||||
|
{
|
||||||
|
pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setup the PC, SP, and GP of a secondary processor and start it running
|
||||||
|
* smp_bootstrap is the place to resume from
|
||||||
|
* __KSTK_TOS(idle) is apparently the stack pointer
|
||||||
|
* (unsigned long)idle->thread_info the gp
|
||||||
|
*/
|
||||||
|
static void cmp_boot_secondary(int cpu, struct task_struct *idle)
|
||||||
|
{
|
||||||
|
struct thread_info *gp = task_thread_info(idle);
|
||||||
|
unsigned long sp = __KSTK_TOS(idle);
|
||||||
|
unsigned long pc = (unsigned long)&smp_bootstrap;
|
||||||
|
unsigned long a0 = 0;
|
||||||
|
|
||||||
|
pr_debug("SMPCMP: CPU%d: %s cpu %d\n", smp_processor_id(),
|
||||||
|
__func__, cpu);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* Needed? */
|
||||||
|
flush_icache_range((unsigned long)gp,
|
||||||
|
(unsigned long)(gp + sizeof(struct thread_info)));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
amon_cpu_start(cpu, pc, sp, gp, a0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Common setup before any secondaries are started
|
||||||
|
*/
|
||||||
|
void __init cmp_smp_setup(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int ncpu = 0;
|
||||||
|
|
||||||
|
pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__);
|
||||||
|
|
||||||
|
#ifdef CONFIG_MIPS_MT_FPAFF
|
||||||
|
/* If we have an FPU, enroll ourselves in the FPU-full mask */
|
||||||
|
if (cpu_has_fpu)
|
||||||
|
cpu_set(0, mt_fpu_cpumask);
|
||||||
|
#endif /* CONFIG_MIPS_MT_FPAFF */
|
||||||
|
|
||||||
|
for (i = 1; i < NR_CPUS; i++) {
|
||||||
|
if (amon_cpu_avail(i)) {
|
||||||
|
cpu_set(i, phys_cpu_present_map);
|
||||||
|
__cpu_number_map[i] = ++ncpu;
|
||||||
|
__cpu_logical_map[ncpu] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cpu_has_mipsmt) {
|
||||||
|
unsigned int nvpe, mvpconf0 = read_c0_mvpconf0();
|
||||||
|
|
||||||
|
nvpe = ((mvpconf0 & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1;
|
||||||
|
smp_num_siblings = nvpe;
|
||||||
|
}
|
||||||
|
pr_info("Detected %i available secondary CPU(s)\n", ncpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __init cmp_prepare_cpus(unsigned int max_cpus)
|
||||||
|
{
|
||||||
|
pr_debug("SMPCMP: CPU%d: %s max_cpus=%d\n",
|
||||||
|
smp_processor_id(), __func__, max_cpus);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME: some of these options are per-system, some per-core and
|
||||||
|
* some per-cpu
|
||||||
|
*/
|
||||||
|
mips_mt_set_cpuoptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct plat_smp_ops cmp_smp_ops = {
|
||||||
|
.send_ipi_single = cmp_send_ipi_single,
|
||||||
|
.send_ipi_mask = cmp_send_ipi_mask,
|
||||||
|
.init_secondary = cmp_init_secondary,
|
||||||
|
.smp_finish = cmp_smp_finish,
|
||||||
|
.cpus_done = cmp_cpus_done,
|
||||||
|
.boot_secondary = cmp_boot_secondary,
|
||||||
|
.smp_setup = cmp_smp_setup,
|
||||||
|
.prepare_cpus = cmp_prepare_cpus,
|
||||||
|
};
|
||||||
+15
-81
@@ -36,63 +36,7 @@
|
|||||||
#include <asm/mipsmtregs.h>
|
#include <asm/mipsmtregs.h>
|
||||||
#include <asm/mips_mt.h>
|
#include <asm/mips_mt.h>
|
||||||
|
|
||||||
#define MIPS_CPU_IPI_RESCHED_IRQ 0
|
static void __init smvp_copy_vpe_config(void)
|
||||||
#define MIPS_CPU_IPI_CALL_IRQ 1
|
|
||||||
|
|
||||||
static int cpu_ipi_resched_irq, cpu_ipi_call_irq;
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static void dump_mtregisters(int vpe, int tc)
|
|
||||||
{
|
|
||||||
printk("vpe %d tc %d\n", vpe, tc);
|
|
||||||
|
|
||||||
settc(tc);
|
|
||||||
|
|
||||||
printk(" c0 status 0x%lx\n", read_vpe_c0_status());
|
|
||||||
printk(" vpecontrol 0x%lx\n", read_vpe_c0_vpecontrol());
|
|
||||||
printk(" vpeconf0 0x%lx\n", read_vpe_c0_vpeconf0());
|
|
||||||
printk(" tcstatus 0x%lx\n", read_tc_c0_tcstatus());
|
|
||||||
printk(" tcrestart 0x%lx\n", read_tc_c0_tcrestart());
|
|
||||||
printk(" tcbind 0x%lx\n", read_tc_c0_tcbind());
|
|
||||||
printk(" tchalt 0x%lx\n", read_tc_c0_tchalt());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void ipi_resched_dispatch(void)
|
|
||||||
{
|
|
||||||
do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ipi_call_dispatch(void)
|
|
||||||
{
|
|
||||||
do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ);
|
|
||||||
}
|
|
||||||
|
|
||||||
static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
|
|
||||||
{
|
|
||||||
return IRQ_HANDLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
|
|
||||||
{
|
|
||||||
smp_call_function_interrupt();
|
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct irqaction irq_resched = {
|
|
||||||
.handler = ipi_resched_interrupt,
|
|
||||||
.flags = IRQF_DISABLED|IRQF_PERCPU,
|
|
||||||
.name = "IPI_resched"
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct irqaction irq_call = {
|
|
||||||
.handler = ipi_call_interrupt,
|
|
||||||
.flags = IRQF_DISABLED|IRQF_PERCPU,
|
|
||||||
.name = "IPI_call"
|
|
||||||
};
|
|
||||||
|
|
||||||
static void __init smp_copy_vpe_config(void)
|
|
||||||
{
|
{
|
||||||
write_vpe_c0_status(
|
write_vpe_c0_status(
|
||||||
(read_c0_status() & ~(ST0_IM | ST0_IE | ST0_KSU)) | ST0_CU0);
|
(read_c0_status() & ~(ST0_IM | ST0_IE | ST0_KSU)) | ST0_CU0);
|
||||||
@@ -109,7 +53,7 @@ static void __init smp_copy_vpe_config(void)
|
|||||||
write_vpe_c0_count(read_c0_count());
|
write_vpe_c0_count(read_c0_count());
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int __init smp_vpe_init(unsigned int tc, unsigned int mvpconf0,
|
static unsigned int __init smvp_vpe_init(unsigned int tc, unsigned int mvpconf0,
|
||||||
unsigned int ncpu)
|
unsigned int ncpu)
|
||||||
{
|
{
|
||||||
if (tc > ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT))
|
if (tc > ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT))
|
||||||
@@ -135,12 +79,12 @@ static unsigned int __init smp_vpe_init(unsigned int tc, unsigned int mvpconf0,
|
|||||||
write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE);
|
write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE);
|
||||||
|
|
||||||
if (tc != 0)
|
if (tc != 0)
|
||||||
smp_copy_vpe_config();
|
smvp_copy_vpe_config();
|
||||||
|
|
||||||
return ncpu;
|
return ncpu;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __init smp_tc_init(unsigned int tc, unsigned int mvpconf0)
|
static void __init smvp_tc_init(unsigned int tc, unsigned int mvpconf0)
|
||||||
{
|
{
|
||||||
unsigned long tmp;
|
unsigned long tmp;
|
||||||
|
|
||||||
@@ -207,15 +151,20 @@ static void vsmp_send_ipi_mask(cpumask_t mask, unsigned int action)
|
|||||||
|
|
||||||
static void __cpuinit vsmp_init_secondary(void)
|
static void __cpuinit vsmp_init_secondary(void)
|
||||||
{
|
{
|
||||||
/* Enable per-cpu interrupts */
|
extern int gic_present;
|
||||||
|
|
||||||
/* This is Malta specific: IPI,performance and timer inetrrupts */
|
/* This is Malta specific: IPI,performance and timer inetrrupts */
|
||||||
write_c0_status((read_c0_status() & ~ST0_IM ) |
|
if (gic_present)
|
||||||
(STATUSF_IP0 | STATUSF_IP1 | STATUSF_IP6 | STATUSF_IP7));
|
change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 |
|
||||||
|
STATUSF_IP6 | STATUSF_IP7);
|
||||||
|
else
|
||||||
|
change_c0_status(ST0_IM, STATUSF_IP0 | STATUSF_IP1 |
|
||||||
|
STATUSF_IP6 | STATUSF_IP7);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __cpuinit vsmp_smp_finish(void)
|
static void __cpuinit vsmp_smp_finish(void)
|
||||||
{
|
{
|
||||||
|
/* CDFIXME: remove this? */
|
||||||
write_c0_compare(read_c0_count() + (8* mips_hpt_frequency/HZ));
|
write_c0_compare(read_c0_count() + (8* mips_hpt_frequency/HZ));
|
||||||
|
|
||||||
#ifdef CONFIG_MIPS_MT_FPAFF
|
#ifdef CONFIG_MIPS_MT_FPAFF
|
||||||
@@ -276,7 +225,7 @@ static void __cpuinit vsmp_boot_secondary(int cpu, struct task_struct *idle)
|
|||||||
/*
|
/*
|
||||||
* Common setup before any secondaries are started
|
* Common setup before any secondaries are started
|
||||||
* Make sure all CPU's are in a sensible state before we boot any of the
|
* Make sure all CPU's are in a sensible state before we boot any of the
|
||||||
* secondarys
|
* secondaries
|
||||||
*/
|
*/
|
||||||
static void __init vsmp_smp_setup(void)
|
static void __init vsmp_smp_setup(void)
|
||||||
{
|
{
|
||||||
@@ -309,8 +258,8 @@ static void __init vsmp_smp_setup(void)
|
|||||||
for (tc = 0; tc <= ntc; tc++) {
|
for (tc = 0; tc <= ntc; tc++) {
|
||||||
settc(tc);
|
settc(tc);
|
||||||
|
|
||||||
smp_tc_init(tc, mvpconf0);
|
smvp_tc_init(tc, mvpconf0);
|
||||||
ncpu = smp_vpe_init(tc, mvpconf0, ncpu);
|
ncpu = smvp_vpe_init(tc, mvpconf0, ncpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Release config state */
|
/* Release config state */
|
||||||
@@ -324,21 +273,6 @@ static void __init vsmp_smp_setup(void)
|
|||||||
static void __init vsmp_prepare_cpus(unsigned int max_cpus)
|
static void __init vsmp_prepare_cpus(unsigned int max_cpus)
|
||||||
{
|
{
|
||||||
mips_mt_set_cpuoptions();
|
mips_mt_set_cpuoptions();
|
||||||
|
|
||||||
/* set up ipi interrupts */
|
|
||||||
if (cpu_has_vint) {
|
|
||||||
set_vi_handler(MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch);
|
|
||||||
set_vi_handler(MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch);
|
|
||||||
}
|
|
||||||
|
|
||||||
cpu_ipi_resched_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ;
|
|
||||||
cpu_ipi_call_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ;
|
|
||||||
|
|
||||||
setup_irq(cpu_ipi_resched_irq, &irq_resched);
|
|
||||||
setup_irq(cpu_ipi_call_irq, &irq_call);
|
|
||||||
|
|
||||||
set_irq_handler(cpu_ipi_resched_irq, handle_percpu_irq);
|
|
||||||
set_irq_handler(cpu_ipi_call_irq, handle_percpu_irq);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct plat_smp_ops vsmp_smp_ops = {
|
struct plat_smp_ops vsmp_smp_ops = {
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
#include <asm/atomic.h>
|
#include <asm/atomic.h>
|
||||||
#include <asm/cpu.h>
|
#include <asm/cpu.h>
|
||||||
#include <asm/processor.h>
|
#include <asm/processor.h>
|
||||||
|
#include <asm/r4k-timer.h>
|
||||||
#include <asm/system.h>
|
#include <asm/system.h>
|
||||||
#include <asm/mmu_context.h>
|
#include <asm/mmu_context.h>
|
||||||
#include <asm/time.h>
|
#include <asm/time.h>
|
||||||
@@ -125,6 +126,8 @@ asmlinkage __cpuinit void start_secondary(void)
|
|||||||
|
|
||||||
cpu_set(cpu, cpu_callin_map);
|
cpu_set(cpu, cpu_callin_map);
|
||||||
|
|
||||||
|
synchronise_count_slave();
|
||||||
|
|
||||||
cpu_idle();
|
cpu_idle();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,6 +290,7 @@ void smp_send_stop(void)
|
|||||||
void __init smp_cpus_done(unsigned int max_cpus)
|
void __init smp_cpus_done(unsigned int max_cpus)
|
||||||
{
|
{
|
||||||
mp_ops->cpus_done();
|
mp_ops->cpus_done();
|
||||||
|
synchronise_count_master();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* called from main before smp_init() */
|
/* called from main before smp_init() */
|
||||||
|
|||||||
@@ -331,7 +331,8 @@ static void smtc_tc_setup(int vpe, int tc, int cpu)
|
|||||||
/* In general, all TCs should have the same cpu_data indications */
|
/* In general, all TCs should have the same cpu_data indications */
|
||||||
memcpy(&cpu_data[cpu], &cpu_data[0], sizeof(struct cpuinfo_mips));
|
memcpy(&cpu_data[cpu], &cpu_data[0], sizeof(struct cpuinfo_mips));
|
||||||
/* For 34Kf, start with TC/CPU 0 as sole owner of single FPU context */
|
/* For 34Kf, start with TC/CPU 0 as sole owner of single FPU context */
|
||||||
if (cpu_data[0].cputype == CPU_34K)
|
if (cpu_data[0].cputype == CPU_34K ||
|
||||||
|
cpu_data[0].cputype == CPU_1004K)
|
||||||
cpu_data[cpu].options &= ~MIPS_CPU_FPU;
|
cpu_data[cpu].options &= ~MIPS_CPU_FPU;
|
||||||
cpu_data[cpu].vpe_id = vpe;
|
cpu_data[cpu].vpe_id = vpe;
|
||||||
cpu_data[cpu].tc_id = tc;
|
cpu_data[cpu].tc_id = tc;
|
||||||
|
|||||||
@@ -0,0 +1,159 @@
|
|||||||
|
/*
|
||||||
|
* Count register synchronisation.
|
||||||
|
*
|
||||||
|
* All CPUs will have their count registers synchronised to the CPU0 expirelo
|
||||||
|
* value. This can cause a small timewarp for CPU0. All other CPU's should
|
||||||
|
* not have done anything significant (but they may have had interrupts
|
||||||
|
* enabled briefly - prom_smp_finish() should not be responsible for enabling
|
||||||
|
* interrupts...)
|
||||||
|
*
|
||||||
|
* FIXME: broken for SMTC
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/irqflags.h>
|
||||||
|
#include <linux/r4k-timer.h>
|
||||||
|
|
||||||
|
#include <asm/atomic.h>
|
||||||
|
#include <asm/barrier.h>
|
||||||
|
#include <asm/cpumask.h>
|
||||||
|
#include <asm/mipsregs.h>
|
||||||
|
|
||||||
|
static atomic_t __initdata count_start_flag = ATOMIC_INIT(0);
|
||||||
|
static atomic_t __initdata count_count_start = ATOMIC_INIT(0);
|
||||||
|
static atomic_t __initdata count_count_stop = ATOMIC_INIT(0);
|
||||||
|
|
||||||
|
#define COUNTON 100
|
||||||
|
#define NR_LOOPS 5
|
||||||
|
|
||||||
|
void __init synchronise_count_master(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned long flags;
|
||||||
|
unsigned int initcount;
|
||||||
|
int nslaves;
|
||||||
|
|
||||||
|
#ifdef CONFIG_MIPS_MT_SMTC
|
||||||
|
/*
|
||||||
|
* SMTC needs to synchronise per VPE, not per CPU
|
||||||
|
* ignore for now
|
||||||
|
*/
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pr_info("Checking COUNT synchronization across %u CPUs: ",
|
||||||
|
num_online_cpus());
|
||||||
|
|
||||||
|
local_irq_save(flags);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Notify the slaves that it's time to start
|
||||||
|
*/
|
||||||
|
atomic_set(&count_start_flag, 1);
|
||||||
|
smp_wmb();
|
||||||
|
|
||||||
|
/* Count will be initialised to expirelo for all CPU's */
|
||||||
|
initcount = expirelo;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We loop a few times to get a primed instruction cache,
|
||||||
|
* then the last pass is more or less synchronised and
|
||||||
|
* the master and slaves each set their cycle counters to a known
|
||||||
|
* value all at once. This reduces the chance of having random offsets
|
||||||
|
* between the processors, and guarantees that the maximum
|
||||||
|
* delay between the cycle counters is never bigger than
|
||||||
|
* the latency of information-passing (cachelines) between
|
||||||
|
* two CPUs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
nslaves = num_online_cpus()-1;
|
||||||
|
for (i = 0; i < NR_LOOPS; i++) {
|
||||||
|
/* slaves loop on '!= ncpus' */
|
||||||
|
while (atomic_read(&count_count_start) != nslaves)
|
||||||
|
mb();
|
||||||
|
atomic_set(&count_count_stop, 0);
|
||||||
|
smp_wmb();
|
||||||
|
|
||||||
|
/* this lets the slaves write their count register */
|
||||||
|
atomic_inc(&count_count_start);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Everyone initialises count in the last loop:
|
||||||
|
*/
|
||||||
|
if (i == NR_LOOPS-1)
|
||||||
|
write_c0_count(initcount);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wait for all slaves to leave the synchronization point:
|
||||||
|
*/
|
||||||
|
while (atomic_read(&count_count_stop) != nslaves)
|
||||||
|
mb();
|
||||||
|
atomic_set(&count_count_start, 0);
|
||||||
|
smp_wmb();
|
||||||
|
atomic_inc(&count_count_stop);
|
||||||
|
}
|
||||||
|
/* Arrange for an interrupt in a short while */
|
||||||
|
write_c0_compare(read_c0_count() + COUNTON);
|
||||||
|
|
||||||
|
local_irq_restore(flags);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* i386 code reported the skew here, but the
|
||||||
|
* count registers were almost certainly out of sync
|
||||||
|
* so no point in alarming people
|
||||||
|
*/
|
||||||
|
printk("done.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void __init synchronise_count_slave(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned long flags;
|
||||||
|
unsigned int initcount;
|
||||||
|
int ncpus;
|
||||||
|
|
||||||
|
#ifdef CONFIG_MIPS_MT_SMTC
|
||||||
|
/*
|
||||||
|
* SMTC needs to synchronise per VPE, not per CPU
|
||||||
|
* ignore for now
|
||||||
|
*/
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
local_irq_save(flags);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Not every cpu is online at the time this gets called,
|
||||||
|
* so we first wait for the master to say everyone is ready
|
||||||
|
*/
|
||||||
|
|
||||||
|
while (!atomic_read(&count_start_flag))
|
||||||
|
mb();
|
||||||
|
|
||||||
|
/* Count will be initialised to expirelo for all CPU's */
|
||||||
|
initcount = expirelo;
|
||||||
|
|
||||||
|
ncpus = num_online_cpus();
|
||||||
|
for (i = 0; i < NR_LOOPS; i++) {
|
||||||
|
atomic_inc(&count_count_start);
|
||||||
|
while (atomic_read(&count_count_start) != ncpus)
|
||||||
|
mb();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Everyone initialises count in the last loop:
|
||||||
|
*/
|
||||||
|
if (i == NR_LOOPS-1)
|
||||||
|
write_c0_count(initcount);
|
||||||
|
|
||||||
|
atomic_inc(&count_count_stop);
|
||||||
|
while (atomic_read(&count_count_stop) != ncpus)
|
||||||
|
mb();
|
||||||
|
}
|
||||||
|
/* Arrange for an interrupt in a short while */
|
||||||
|
write_c0_compare(read_c0_count() + COUNTON);
|
||||||
|
|
||||||
|
local_irq_restore(flags);
|
||||||
|
}
|
||||||
|
#undef NR_LOOPS
|
||||||
|
#endif
|
||||||
+99
-12
@@ -22,6 +22,7 @@
|
|||||||
#include <linux/kallsyms.h>
|
#include <linux/kallsyms.h>
|
||||||
#include <linux/bootmem.h>
|
#include <linux/bootmem.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/ptrace.h>
|
||||||
|
|
||||||
#include <asm/bootinfo.h>
|
#include <asm/bootinfo.h>
|
||||||
#include <asm/branch.h>
|
#include <asm/branch.h>
|
||||||
@@ -80,19 +81,22 @@ void (*board_bind_eic_interrupt)(int irq, int regset);
|
|||||||
|
|
||||||
static void show_raw_backtrace(unsigned long reg29)
|
static void show_raw_backtrace(unsigned long reg29)
|
||||||
{
|
{
|
||||||
unsigned long *sp = (unsigned long *)reg29;
|
unsigned long *sp = (unsigned long *)(reg29 & ~3);
|
||||||
unsigned long addr;
|
unsigned long addr;
|
||||||
|
|
||||||
printk("Call Trace:");
|
printk("Call Trace:");
|
||||||
#ifdef CONFIG_KALLSYMS
|
#ifdef CONFIG_KALLSYMS
|
||||||
printk("\n");
|
printk("\n");
|
||||||
#endif
|
#endif
|
||||||
while (!kstack_end(sp)) {
|
#define IS_KVA01(a) ((((unsigned int)a) & 0xc0000000) == 0x80000000)
|
||||||
addr = *sp++;
|
if (IS_KVA01(sp)) {
|
||||||
if (__kernel_text_address(addr))
|
while (!kstack_end(sp)) {
|
||||||
print_ip_sym(addr);
|
addr = *sp++;
|
||||||
|
if (__kernel_text_address(addr))
|
||||||
|
print_ip_sym(addr);
|
||||||
|
}
|
||||||
|
printk("\n");
|
||||||
}
|
}
|
||||||
printk("\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_KALLSYMS
|
#ifdef CONFIG_KALLSYMS
|
||||||
@@ -192,16 +196,19 @@ EXPORT_SYMBOL(dump_stack);
|
|||||||
static void show_code(unsigned int __user *pc)
|
static void show_code(unsigned int __user *pc)
|
||||||
{
|
{
|
||||||
long i;
|
long i;
|
||||||
|
unsigned short __user *pc16 = NULL;
|
||||||
|
|
||||||
printk("\nCode:");
|
printk("\nCode:");
|
||||||
|
|
||||||
|
if ((unsigned long)pc & 1)
|
||||||
|
pc16 = (unsigned short __user *)((unsigned long)pc & ~1);
|
||||||
for(i = -3 ; i < 6 ; i++) {
|
for(i = -3 ; i < 6 ; i++) {
|
||||||
unsigned int insn;
|
unsigned int insn;
|
||||||
if (__get_user(insn, pc + i)) {
|
if (pc16 ? __get_user(insn, pc16 + i) : __get_user(insn, pc + i)) {
|
||||||
printk(" (Bad address in epc)\n");
|
printk(" (Bad address in epc)\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
printk("%c%08x%c", (i?' ':'<'), insn, (i?' ':'>'));
|
printk("%c%0*x%c", (i?' ':'<'), pc16 ? 4 : 8, insn, (i?' ':'>'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,10 +318,21 @@ void show_regs(struct pt_regs *regs)
|
|||||||
|
|
||||||
void show_registers(const struct pt_regs *regs)
|
void show_registers(const struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
|
const int field = 2 * sizeof(unsigned long);
|
||||||
|
|
||||||
__show_regs(regs);
|
__show_regs(regs);
|
||||||
print_modules();
|
print_modules();
|
||||||
printk("Process %s (pid: %d, threadinfo=%p, task=%p)\n",
|
printk("Process %s (pid: %d, threadinfo=%p, task=%p, tls=%0*lx)\n",
|
||||||
current->comm, task_pid_nr(current), current_thread_info(), current);
|
current->comm, current->pid, current_thread_info(), current,
|
||||||
|
field, current_thread_info()->tp_value);
|
||||||
|
if (cpu_has_userlocal) {
|
||||||
|
unsigned long tls;
|
||||||
|
|
||||||
|
tls = read_c0_userlocal();
|
||||||
|
if (tls != current_thread_info()->tp_value)
|
||||||
|
printk("*HwTLS: %0*lx\n", field, tls);
|
||||||
|
}
|
||||||
|
|
||||||
show_stacktrace(current, regs);
|
show_stacktrace(current, regs);
|
||||||
show_code((unsigned int __user *) regs->cp0_epc);
|
show_code((unsigned int __user *) regs->cp0_epc);
|
||||||
printk("\n");
|
printk("\n");
|
||||||
@@ -985,6 +1003,21 @@ asmlinkage void do_reserved(struct pt_regs *regs)
|
|||||||
(regs->cp0_cause & 0x7f) >> 2);
|
(regs->cp0_cause & 0x7f) >> 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __initdata l1parity = 1;
|
||||||
|
static int __init nol1parity(char *s)
|
||||||
|
{
|
||||||
|
l1parity = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
__setup("nol1par", nol1parity);
|
||||||
|
static int __initdata l2parity = 1;
|
||||||
|
static int __init nol2parity(char *s)
|
||||||
|
{
|
||||||
|
l2parity = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
__setup("nol2par", nol2parity);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some MIPS CPUs can enable/disable for cache parity detection, but do
|
* Some MIPS CPUs can enable/disable for cache parity detection, but do
|
||||||
* it different ways.
|
* it different ways.
|
||||||
@@ -994,6 +1027,62 @@ static inline void parity_protection_init(void)
|
|||||||
switch (current_cpu_type()) {
|
switch (current_cpu_type()) {
|
||||||
case CPU_24K:
|
case CPU_24K:
|
||||||
case CPU_34K:
|
case CPU_34K:
|
||||||
|
case CPU_74K:
|
||||||
|
case CPU_1004K:
|
||||||
|
{
|
||||||
|
#define ERRCTL_PE 0x80000000
|
||||||
|
#define ERRCTL_L2P 0x00800000
|
||||||
|
unsigned long errctl;
|
||||||
|
unsigned int l1parity_present, l2parity_present;
|
||||||
|
|
||||||
|
errctl = read_c0_ecc();
|
||||||
|
errctl &= ~(ERRCTL_PE|ERRCTL_L2P);
|
||||||
|
|
||||||
|
/* probe L1 parity support */
|
||||||
|
write_c0_ecc(errctl | ERRCTL_PE);
|
||||||
|
back_to_back_c0_hazard();
|
||||||
|
l1parity_present = (read_c0_ecc() & ERRCTL_PE);
|
||||||
|
|
||||||
|
/* probe L2 parity support */
|
||||||
|
write_c0_ecc(errctl|ERRCTL_L2P);
|
||||||
|
back_to_back_c0_hazard();
|
||||||
|
l2parity_present = (read_c0_ecc() & ERRCTL_L2P);
|
||||||
|
|
||||||
|
if (l1parity_present && l2parity_present) {
|
||||||
|
if (l1parity)
|
||||||
|
errctl |= ERRCTL_PE;
|
||||||
|
if (l1parity ^ l2parity)
|
||||||
|
errctl |= ERRCTL_L2P;
|
||||||
|
} else if (l1parity_present) {
|
||||||
|
if (l1parity)
|
||||||
|
errctl |= ERRCTL_PE;
|
||||||
|
} else if (l2parity_present) {
|
||||||
|
if (l2parity)
|
||||||
|
errctl |= ERRCTL_L2P;
|
||||||
|
} else {
|
||||||
|
/* No parity available */
|
||||||
|
}
|
||||||
|
|
||||||
|
printk(KERN_INFO "Writing ErrCtl register=%08lx\n", errctl);
|
||||||
|
|
||||||
|
write_c0_ecc(errctl);
|
||||||
|
back_to_back_c0_hazard();
|
||||||
|
errctl = read_c0_ecc();
|
||||||
|
printk(KERN_INFO "Readback ErrCtl register=%08lx\n", errctl);
|
||||||
|
|
||||||
|
if (l1parity_present)
|
||||||
|
printk(KERN_INFO "Cache parity protection %sabled\n",
|
||||||
|
(errctl & ERRCTL_PE) ? "en" : "dis");
|
||||||
|
|
||||||
|
if (l2parity_present) {
|
||||||
|
if (l1parity_present && l1parity)
|
||||||
|
errctl ^= ERRCTL_L2P;
|
||||||
|
printk(KERN_INFO "L2 cache parity protection %sabled\n",
|
||||||
|
(errctl & ERRCTL_L2P) ? "en" : "dis");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case CPU_5KC:
|
case CPU_5KC:
|
||||||
write_c0_ecc(0x80000000);
|
write_c0_ecc(0x80000000);
|
||||||
back_to_back_c0_hazard();
|
back_to_back_c0_hazard();
|
||||||
@@ -1353,7 +1442,6 @@ void __cpuinit per_cpu_trap_init(void)
|
|||||||
change_c0_status(ST0_CU|ST0_MX|ST0_RE|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX,
|
change_c0_status(ST0_CU|ST0_MX|ST0_RE|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX,
|
||||||
status_set);
|
status_set);
|
||||||
|
|
||||||
#ifdef CONFIG_CPU_MIPSR2
|
|
||||||
if (cpu_has_mips_r2) {
|
if (cpu_has_mips_r2) {
|
||||||
unsigned int enable = 0x0000000f;
|
unsigned int enable = 0x0000000f;
|
||||||
|
|
||||||
@@ -1362,7 +1450,6 @@ void __cpuinit per_cpu_trap_init(void)
|
|||||||
|
|
||||||
write_c0_hwrena(enable);
|
write_c0_hwrena(enable);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_MIPS_MT_SMTC
|
#ifdef CONFIG_MIPS_MT_SMTC
|
||||||
if (!secondaryTC) {
|
if (!secondaryTC) {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
obj-y := reset.o display.o init.o memory.o \
|
obj-y := reset.o display.o init.o memory.o \
|
||||||
cmdline.o time.o
|
cmdline.o time.o
|
||||||
|
obj-y += amon.o
|
||||||
|
|
||||||
obj-$(CONFIG_EARLY_PRINTK) += console.o
|
obj-$(CONFIG_EARLY_PRINTK) += console.o
|
||||||
obj-$(CONFIG_PCI) += pci.o
|
obj-$(CONFIG_PCI) += pci.o
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2007 MIPS Technologies, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
|
||||||
|
* This program is free software; you can distribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License (Version 2) as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope 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.,
|
||||||
|
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Arbitrary Monitor interface
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/smp.h>
|
||||||
|
|
||||||
|
#include <asm-mips/addrspace.h>
|
||||||
|
#include <asm-mips/mips-boards/launch.h>
|
||||||
|
#include <asm-mips/mipsmtregs.h>
|
||||||
|
|
||||||
|
int amon_cpu_avail(int cpu)
|
||||||
|
{
|
||||||
|
struct cpulaunch *launch = (struct cpulaunch *)KSEG0ADDR(CPULAUNCH);
|
||||||
|
|
||||||
|
if (cpu < 0 || cpu >= NCPULAUNCH) {
|
||||||
|
pr_debug("avail: cpu%d is out of range\n", cpu);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
launch += cpu;
|
||||||
|
if (!(launch->flags & LAUNCH_FREADY)) {
|
||||||
|
pr_debug("avail: cpu%d is not ready\n", cpu);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (launch->flags & (LAUNCH_FGO|LAUNCH_FGONE)) {
|
||||||
|
pr_debug("avail: too late.. cpu%d is already gone\n", cpu);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void amon_cpu_start(int cpu,
|
||||||
|
unsigned long pc, unsigned long sp,
|
||||||
|
unsigned long gp, unsigned long a0)
|
||||||
|
{
|
||||||
|
volatile struct cpulaunch *launch =
|
||||||
|
(struct cpulaunch *)KSEG0ADDR(CPULAUNCH);
|
||||||
|
|
||||||
|
if (!amon_cpu_avail(cpu))
|
||||||
|
return;
|
||||||
|
if (cpu == smp_processor_id()) {
|
||||||
|
pr_debug("launch: I am cpu%d!\n", cpu);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
launch += cpu;
|
||||||
|
|
||||||
|
pr_debug("launch: starting cpu%d\n", cpu);
|
||||||
|
|
||||||
|
launch->pc = pc;
|
||||||
|
launch->gp = gp;
|
||||||
|
launch->sp = sp;
|
||||||
|
launch->a0 = a0;
|
||||||
|
|
||||||
|
/* Make sure target sees parameters before the go bit */
|
||||||
|
smp_mb();
|
||||||
|
|
||||||
|
launch->flags |= LAUNCH_FGO;
|
||||||
|
while ((launch->flags & LAUNCH_FGONE) == 0)
|
||||||
|
;
|
||||||
|
pr_debug("launch: cpu%d gone!\n", cpu);
|
||||||
|
}
|
||||||
@@ -424,6 +424,9 @@ void __init prom_init(void)
|
|||||||
#ifdef CONFIG_SERIAL_8250_CONSOLE
|
#ifdef CONFIG_SERIAL_8250_CONSOLE
|
||||||
console_config();
|
console_config();
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_MIPS_CMP
|
||||||
|
register_smp_ops(&cmp_smp_ops);
|
||||||
|
#endif
|
||||||
#ifdef CONFIG_MIPS_MT_SMP
|
#ifdef CONFIG_MIPS_MT_SMP
|
||||||
register_smp_ops(&vsmp_smp_ops);
|
register_smp_ops(&vsmp_smp_ops);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -55,16 +55,36 @@
|
|||||||
unsigned long cpu_khz;
|
unsigned long cpu_khz;
|
||||||
|
|
||||||
static int mips_cpu_timer_irq;
|
static int mips_cpu_timer_irq;
|
||||||
|
static int mips_cpu_perf_irq;
|
||||||
extern int cp0_perfcount_irq;
|
extern int cp0_perfcount_irq;
|
||||||
|
|
||||||
|
DEFINE_PER_CPU(unsigned int, tickcount);
|
||||||
|
#define tickcount_this_cpu __get_cpu_var(tickcount)
|
||||||
|
static unsigned long ledbitmask;
|
||||||
|
|
||||||
static void mips_timer_dispatch(void)
|
static void mips_timer_dispatch(void)
|
||||||
{
|
{
|
||||||
|
#if defined(CONFIG_MIPS_MALTA) || defined(CONFIG_MIPS_ATLAS)
|
||||||
|
/*
|
||||||
|
* Yes, this is very tacky, won't work as expected with SMTC and
|
||||||
|
* dyntick will break it,
|
||||||
|
* but it gives me a nice warm feeling during debug
|
||||||
|
*/
|
||||||
|
#define LEDBAR 0xbf000408
|
||||||
|
if (tickcount_this_cpu++ >= HZ) {
|
||||||
|
tickcount_this_cpu = 0;
|
||||||
|
change_bit(smp_processor_id(), &ledbitmask);
|
||||||
|
smp_wmb(); /* Make sure every one else sees the change */
|
||||||
|
/* This will pick up any recent changes made by other CPU's */
|
||||||
|
*(unsigned int *)LEDBAR = ledbitmask;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
do_IRQ(mips_cpu_timer_irq);
|
do_IRQ(mips_cpu_timer_irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mips_perf_dispatch(void)
|
static void mips_perf_dispatch(void)
|
||||||
{
|
{
|
||||||
do_IRQ(cp0_perfcount_irq);
|
do_IRQ(mips_cpu_perf_irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -129,19 +149,18 @@ unsigned long read_persistent_clock(void)
|
|||||||
|
|
||||||
void __init plat_perf_setup(void)
|
void __init plat_perf_setup(void)
|
||||||
{
|
{
|
||||||
cp0_perfcount_irq = -1;
|
|
||||||
|
|
||||||
#ifdef MSC01E_INT_BASE
|
#ifdef MSC01E_INT_BASE
|
||||||
if (cpu_has_veic) {
|
if (cpu_has_veic) {
|
||||||
set_vi_handler(MSC01E_INT_PERFCTR, mips_perf_dispatch);
|
set_vi_handler(MSC01E_INT_PERFCTR, mips_perf_dispatch);
|
||||||
cp0_perfcount_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR;
|
mips_cpu_perf_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR;
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
if (cp0_perfcount_irq >= 0) {
|
if (cp0_perfcount_irq >= 0) {
|
||||||
if (cpu_has_vint)
|
if (cpu_has_vint)
|
||||||
set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch);
|
set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch);
|
||||||
|
mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
set_irq_handler(cp0_perfcount_irq, handle_percpu_irq);
|
set_irq_handler(mips_cpu_perf_irq, handle_percpu_irq);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
obj-y := malta_int.o malta_platform.o malta_setup.o
|
obj-y := malta_int.o malta_platform.o malta_setup.o
|
||||||
|
|
||||||
obj-$(CONFIG_MTD) += malta_mtd.o
|
obj-$(CONFIG_MTD) += malta_mtd.o
|
||||||
|
# FIXME FIXME FIXME
|
||||||
obj-$(CONFIG_MIPS_MT_SMTC) += malta_smtc.o
|
obj-$(CONFIG_MIPS_MT_SMTC) += malta_smtc.o
|
||||||
|
|
||||||
EXTRA_CFLAGS += -Werror
|
EXTRA_CFLAGS += -Werror
|
||||||
@@ -31,6 +31,7 @@
|
|||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/random.h>
|
#include <linux/random.h>
|
||||||
|
|
||||||
|
#include <asm/traps.h>
|
||||||
#include <asm/i8259.h>
|
#include <asm/i8259.h>
|
||||||
#include <asm/irq_cpu.h>
|
#include <asm/irq_cpu.h>
|
||||||
#include <asm/irq_regs.h>
|
#include <asm/irq_regs.h>
|
||||||
@@ -41,6 +42,14 @@
|
|||||||
#include <asm/mips-boards/generic.h>
|
#include <asm/mips-boards/generic.h>
|
||||||
#include <asm/mips-boards/msc01_pci.h>
|
#include <asm/mips-boards/msc01_pci.h>
|
||||||
#include <asm/msc01_ic.h>
|
#include <asm/msc01_ic.h>
|
||||||
|
#include <asm/gic.h>
|
||||||
|
#include <asm/gcmpregs.h>
|
||||||
|
|
||||||
|
int gcmp_present = -1;
|
||||||
|
int gic_present;
|
||||||
|
static unsigned long _msc01_biu_base;
|
||||||
|
static unsigned long _gcmp_base;
|
||||||
|
static unsigned int ipi_map[NR_CPUS];
|
||||||
|
|
||||||
static DEFINE_SPINLOCK(mips_irq_lock);
|
static DEFINE_SPINLOCK(mips_irq_lock);
|
||||||
|
|
||||||
@@ -121,6 +130,17 @@ static void malta_hw0_irqdispatch(void)
|
|||||||
do_IRQ(MALTA_INT_BASE + irq);
|
do_IRQ(MALTA_INT_BASE + irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void malta_ipi_irqdispatch(void)
|
||||||
|
{
|
||||||
|
int irq;
|
||||||
|
|
||||||
|
irq = gic_get_int();
|
||||||
|
if (irq < 0)
|
||||||
|
return; /* interrupt has already been cleared */
|
||||||
|
|
||||||
|
do_IRQ(MIPS_GIC_IRQ_BASE + irq);
|
||||||
|
}
|
||||||
|
|
||||||
static void corehi_irqdispatch(void)
|
static void corehi_irqdispatch(void)
|
||||||
{
|
{
|
||||||
unsigned int intedge, intsteer, pcicmd, pcibadaddr;
|
unsigned int intedge, intsteer, pcicmd, pcibadaddr;
|
||||||
@@ -257,12 +277,61 @@ asmlinkage void plat_irq_dispatch(void)
|
|||||||
|
|
||||||
if (irq == MIPSCPU_INT_I8259A)
|
if (irq == MIPSCPU_INT_I8259A)
|
||||||
malta_hw0_irqdispatch();
|
malta_hw0_irqdispatch();
|
||||||
|
else if (gic_present && ((1 << irq) & ipi_map[smp_processor_id()]))
|
||||||
|
malta_ipi_irqdispatch();
|
||||||
else if (irq >= 0)
|
else if (irq >= 0)
|
||||||
do_IRQ(MIPS_CPU_IRQ_BASE + irq);
|
do_IRQ(MIPS_CPU_IRQ_BASE + irq);
|
||||||
else
|
else
|
||||||
spurious_interrupt();
|
spurious_interrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_MIPS_MT_SMP
|
||||||
|
|
||||||
|
|
||||||
|
#define GIC_MIPS_CPU_IPI_RESCHED_IRQ 3
|
||||||
|
#define GIC_MIPS_CPU_IPI_CALL_IRQ 4
|
||||||
|
|
||||||
|
#define MIPS_CPU_IPI_RESCHED_IRQ 0 /* SW int 0 for resched */
|
||||||
|
#define C_RESCHED C_SW0
|
||||||
|
#define MIPS_CPU_IPI_CALL_IRQ 1 /* SW int 1 for resched */
|
||||||
|
#define C_CALL C_SW1
|
||||||
|
static int cpu_ipi_resched_irq, cpu_ipi_call_irq;
|
||||||
|
|
||||||
|
static void ipi_resched_dispatch(void)
|
||||||
|
{
|
||||||
|
do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ipi_call_dispatch(void)
|
||||||
|
{
|
||||||
|
do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ);
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
smp_call_function_interrupt();
|
||||||
|
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct irqaction irq_resched = {
|
||||||
|
.handler = ipi_resched_interrupt,
|
||||||
|
.flags = IRQF_DISABLED|IRQF_PERCPU,
|
||||||
|
.name = "IPI_resched"
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct irqaction irq_call = {
|
||||||
|
.handler = ipi_call_interrupt,
|
||||||
|
.flags = IRQF_DISABLED|IRQF_PERCPU,
|
||||||
|
.name = "IPI_call"
|
||||||
|
};
|
||||||
|
#endif /* CONFIG_MIPS_MT_SMP */
|
||||||
|
|
||||||
static struct irqaction i8259irq = {
|
static struct irqaction i8259irq = {
|
||||||
.handler = no_action,
|
.handler = no_action,
|
||||||
.name = "XT-PIC cascade"
|
.name = "XT-PIC cascade"
|
||||||
@@ -291,15 +360,90 @@ msc_irqmap_t __initdata msc_eicirqmap[] = {
|
|||||||
{MSC01E_INT_PERFCTR, MSC01_IRQ_LEVEL, 0},
|
{MSC01E_INT_PERFCTR, MSC01_IRQ_LEVEL, 0},
|
||||||
{MSC01E_INT_CPUCTR, MSC01_IRQ_LEVEL, 0}
|
{MSC01E_INT_CPUCTR, MSC01_IRQ_LEVEL, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
int __initdata msc_nr_eicirqs = ARRAY_SIZE(msc_eicirqmap);
|
int __initdata msc_nr_eicirqs = ARRAY_SIZE(msc_eicirqmap);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This GIC specific tabular array defines the association between External
|
||||||
|
* Interrupts and CPUs/Core Interrupts. The nature of the External
|
||||||
|
* Interrupts is also defined here - polarity/trigger.
|
||||||
|
*/
|
||||||
|
static struct gic_intr_map gic_intr_map[] = {
|
||||||
|
{ GIC_EXT_INTR(0), X, X, X, X, 0 },
|
||||||
|
{ GIC_EXT_INTR(1), X, X, X, X, 0 },
|
||||||
|
{ GIC_EXT_INTR(2), X, X, X, X, 0 },
|
||||||
|
{ GIC_EXT_INTR(3), 0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
|
||||||
|
{ GIC_EXT_INTR(4), 0, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
|
||||||
|
{ GIC_EXT_INTR(5), 0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
|
||||||
|
{ GIC_EXT_INTR(6), 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
|
||||||
|
{ GIC_EXT_INTR(7), 0, GIC_CPU_INT4, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
|
||||||
|
{ GIC_EXT_INTR(8), 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
|
||||||
|
{ GIC_EXT_INTR(9), 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
|
||||||
|
{ GIC_EXT_INTR(10), X, X, X, X, 0 },
|
||||||
|
{ GIC_EXT_INTR(11), X, X, X, X, 0 },
|
||||||
|
{ GIC_EXT_INTR(12), 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
|
||||||
|
{ GIC_EXT_INTR(13), 0, GIC_MAP_TO_NMI_MSK, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
|
||||||
|
{ GIC_EXT_INTR(14), 0, GIC_MAP_TO_NMI_MSK, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
|
||||||
|
{ GIC_EXT_INTR(15), X, X, X, X, 0 },
|
||||||
|
{ GIC_EXT_INTR(16), 0, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
|
||||||
|
{ GIC_EXT_INTR(17), 0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
|
||||||
|
{ GIC_EXT_INTR(18), 1, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
|
||||||
|
{ GIC_EXT_INTR(19), 1, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
|
||||||
|
{ GIC_EXT_INTR(20), 2, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
|
||||||
|
{ GIC_EXT_INTR(21), 2, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
|
||||||
|
{ GIC_EXT_INTR(22), 3, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
|
||||||
|
{ GIC_EXT_INTR(23), 3, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GCMP needs to be detected before any SMP initialisation
|
||||||
|
*/
|
||||||
|
int __init gcmp_probe(unsigned long addr, unsigned long size)
|
||||||
|
{
|
||||||
|
if (gcmp_present >= 0)
|
||||||
|
return gcmp_present;
|
||||||
|
|
||||||
|
_gcmp_base = (unsigned long) ioremap_nocache(GCMP_BASE_ADDR, GCMP_ADDRSPACE_SZ);
|
||||||
|
_msc01_biu_base = (unsigned long) ioremap_nocache(MSC01_BIU_REG_BASE, MSC01_BIU_ADDRSPACE_SZ);
|
||||||
|
gcmp_present = (GCMPGCB(GCMPB) & GCMP_GCB_GCMPB_GCMPBASE_MSK) == GCMP_BASE_ADDR;
|
||||||
|
|
||||||
|
if (gcmp_present)
|
||||||
|
printk(KERN_DEBUG "GCMP present\n");
|
||||||
|
return gcmp_present;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __init fill_ipi_map(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(gic_intr_map); i++) {
|
||||||
|
if (gic_intr_map[i].ipiflag && (gic_intr_map[i].cpunum != X))
|
||||||
|
ipi_map[gic_intr_map[i].cpunum] |=
|
||||||
|
(1 << (gic_intr_map[i].pin + 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void __init arch_init_irq(void)
|
void __init arch_init_irq(void)
|
||||||
{
|
{
|
||||||
|
int gic_present, gcmp_present;
|
||||||
|
|
||||||
init_i8259_irqs();
|
init_i8259_irqs();
|
||||||
|
|
||||||
if (!cpu_has_veic)
|
if (!cpu_has_veic)
|
||||||
mips_cpu_irq_init();
|
mips_cpu_irq_init();
|
||||||
|
|
||||||
|
gcmp_present = gcmp_probe(GCMP_BASE_ADDR, GCMP_ADDRSPACE_SZ);
|
||||||
|
if (gcmp_present) {
|
||||||
|
GCMPGCB(GICBA) = GIC_BASE_ADDR | GCMP_GCB_GICBA_EN_MSK;
|
||||||
|
gic_present = 1;
|
||||||
|
} else {
|
||||||
|
_msc01_biu_base = (unsigned long) ioremap_nocache(MSC01_BIU_REG_BASE, MSC01_BIU_ADDRSPACE_SZ);
|
||||||
|
gic_present = (REG(_msc01_biu_base, MSC01_SC_CFG) &
|
||||||
|
MSC01_SC_CFG_GICPRES_MSK) >> MSC01_SC_CFG_GICPRES_SHF;
|
||||||
|
}
|
||||||
|
if (gic_present)
|
||||||
|
printk(KERN_DEBUG "GIC present\n");
|
||||||
|
|
||||||
switch (mips_revision_sconid) {
|
switch (mips_revision_sconid) {
|
||||||
case MIPS_REVISION_SCON_SOCIT:
|
case MIPS_REVISION_SCON_SOCIT:
|
||||||
case MIPS_REVISION_SCON_ROCIT:
|
case MIPS_REVISION_SCON_ROCIT:
|
||||||
@@ -360,4 +504,206 @@ void __init arch_init_irq(void)
|
|||||||
setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI,
|
setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI,
|
||||||
&corehi_irqaction);
|
&corehi_irqaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_MIPS_MT_SMP)
|
||||||
|
if (gic_present) {
|
||||||
|
/* FIXME */
|
||||||
|
int i;
|
||||||
|
struct {
|
||||||
|
unsigned int resched;
|
||||||
|
unsigned int call;
|
||||||
|
} ipiirq[] = {
|
||||||
|
{
|
||||||
|
.resched = GIC_IPI_EXT_INTR_RESCHED_VPE0,
|
||||||
|
.call = GIC_IPI_EXT_INTR_CALLFNC_VPE0},
|
||||||
|
{
|
||||||
|
.resched = GIC_IPI_EXT_INTR_RESCHED_VPE1,
|
||||||
|
.call = GIC_IPI_EXT_INTR_CALLFNC_VPE1
|
||||||
|
}, {
|
||||||
|
.resched = GIC_IPI_EXT_INTR_RESCHED_VPE2,
|
||||||
|
.call = GIC_IPI_EXT_INTR_CALLFNC_VPE2
|
||||||
|
}, {
|
||||||
|
.resched = GIC_IPI_EXT_INTR_RESCHED_VPE3,
|
||||||
|
.call = GIC_IPI_EXT_INTR_CALLFNC_VPE3
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#define NIPI (sizeof(ipiirq)/sizeof(ipiirq[0]))
|
||||||
|
fill_ipi_map();
|
||||||
|
gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, gic_intr_map, ARRAY_SIZE(gic_intr_map), MIPS_GIC_IRQ_BASE);
|
||||||
|
if (!gcmp_present) {
|
||||||
|
/* Enable the GIC */
|
||||||
|
i = REG(_msc01_biu_base, MSC01_SC_CFG);
|
||||||
|
REG(_msc01_biu_base, MSC01_SC_CFG) =
|
||||||
|
(i | (0x1 << MSC01_SC_CFG_GICENA_SHF));
|
||||||
|
pr_debug("GIC Enabled\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set up ipi interrupts */
|
||||||
|
if (cpu_has_vint) {
|
||||||
|
set_vi_handler(MIPSCPU_INT_IPI0, malta_ipi_irqdispatch);
|
||||||
|
set_vi_handler(MIPSCPU_INT_IPI1, malta_ipi_irqdispatch);
|
||||||
|
}
|
||||||
|
/* Argh.. this really needs sorting out.. */
|
||||||
|
printk("CPU%d: status register was %08x\n", smp_processor_id(), read_c0_status());
|
||||||
|
write_c0_status(read_c0_status() | STATUSF_IP3 | STATUSF_IP4);
|
||||||
|
printk("CPU%d: status register now %08x\n", smp_processor_id(), read_c0_status());
|
||||||
|
write_c0_status(0x1100dc00);
|
||||||
|
printk("CPU%d: status register frc %08x\n", smp_processor_id(), read_c0_status());
|
||||||
|
for (i = 0; i < NIPI; i++) {
|
||||||
|
setup_irq(MIPS_GIC_IRQ_BASE + ipiirq[i].resched, &irq_resched);
|
||||||
|
setup_irq(MIPS_GIC_IRQ_BASE + ipiirq[i].call, &irq_call);
|
||||||
|
|
||||||
|
set_irq_handler(MIPS_GIC_IRQ_BASE + ipiirq[i].resched, handle_percpu_irq);
|
||||||
|
set_irq_handler(MIPS_GIC_IRQ_BASE + ipiirq[i].call, handle_percpu_irq);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* set up ipi interrupts */
|
||||||
|
if (cpu_has_veic) {
|
||||||
|
set_vi_handler (MSC01E_INT_SW0, ipi_resched_dispatch);
|
||||||
|
set_vi_handler (MSC01E_INT_SW1, ipi_call_dispatch);
|
||||||
|
cpu_ipi_resched_irq = MSC01E_INT_SW0;
|
||||||
|
cpu_ipi_call_irq = MSC01E_INT_SW1;
|
||||||
|
} else {
|
||||||
|
if (cpu_has_vint) {
|
||||||
|
set_vi_handler (MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch);
|
||||||
|
set_vi_handler (MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch);
|
||||||
|
}
|
||||||
|
cpu_ipi_resched_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ;
|
||||||
|
cpu_ipi_call_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ;
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_irq(cpu_ipi_resched_irq, &irq_resched);
|
||||||
|
setup_irq(cpu_ipi_call_irq, &irq_call);
|
||||||
|
|
||||||
|
set_irq_handler(cpu_ipi_resched_irq, handle_percpu_irq);
|
||||||
|
set_irq_handler(cpu_ipi_call_irq, handle_percpu_irq);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void malta_be_init(void)
|
||||||
|
{
|
||||||
|
if (gcmp_present) {
|
||||||
|
/* Could change CM error mask register */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static char *tr[8] = {
|
||||||
|
"mem", "gcr", "gic", "mmio",
|
||||||
|
"0x04", "0x05", "0x06", "0x07"
|
||||||
|
};
|
||||||
|
|
||||||
|
static char *mcmd[32] = {
|
||||||
|
[0x00] = "0x00",
|
||||||
|
[0x01] = "Legacy Write",
|
||||||
|
[0x02] = "Legacy Read",
|
||||||
|
[0x03] = "0x03",
|
||||||
|
[0x04] = "0x04",
|
||||||
|
[0x05] = "0x05",
|
||||||
|
[0x06] = "0x06",
|
||||||
|
[0x07] = "0x07",
|
||||||
|
[0x08] = "Coherent Read Own",
|
||||||
|
[0x09] = "Coherent Read Share",
|
||||||
|
[0x0a] = "Coherent Read Discard",
|
||||||
|
[0x0b] = "Coherent Ready Share Always",
|
||||||
|
[0x0c] = "Coherent Upgrade",
|
||||||
|
[0x0d] = "Coherent Writeback",
|
||||||
|
[0x0e] = "0x0e",
|
||||||
|
[0x0f] = "0x0f",
|
||||||
|
[0x10] = "Coherent Copyback",
|
||||||
|
[0x11] = "Coherent Copyback Invalidate",
|
||||||
|
[0x12] = "Coherent Invalidate",
|
||||||
|
[0x13] = "Coherent Write Invalidate",
|
||||||
|
[0x14] = "Coherent Completion Sync",
|
||||||
|
[0x15] = "0x15",
|
||||||
|
[0x16] = "0x16",
|
||||||
|
[0x17] = "0x17",
|
||||||
|
[0x18] = "0x18",
|
||||||
|
[0x19] = "0x19",
|
||||||
|
[0x1a] = "0x1a",
|
||||||
|
[0x1b] = "0x1b",
|
||||||
|
[0x1c] = "0x1c",
|
||||||
|
[0x1d] = "0x1d",
|
||||||
|
[0x1e] = "0x1e",
|
||||||
|
[0x1f] = "0x1f"
|
||||||
|
};
|
||||||
|
|
||||||
|
static char *core[8] = {
|
||||||
|
"Invalid/OK", "Invalid/Data",
|
||||||
|
"Shared/OK", "Shared/Data",
|
||||||
|
"Modified/OK", "Modified/Data",
|
||||||
|
"Exclusive/OK", "Exclusive/Data"
|
||||||
|
};
|
||||||
|
|
||||||
|
static char *causes[32] = {
|
||||||
|
"None", "GC_WR_ERR", "GC_RD_ERR", "COH_WR_ERR",
|
||||||
|
"COH_RD_ERR", "MMIO_WR_ERR", "MMIO_RD_ERR", "0x07",
|
||||||
|
"0x08", "0x09", "0x0a", "0x0b",
|
||||||
|
"0x0c", "0x0d", "0x0e", "0x0f",
|
||||||
|
"0x10", "0x11", "0x12", "0x13",
|
||||||
|
"0x14", "0x15", "0x16", "INTVN_WR_ERR",
|
||||||
|
"INTVN_RD_ERR", "0x19", "0x1a", "0x1b",
|
||||||
|
"0x1c", "0x1d", "0x1e", "0x1f"
|
||||||
|
};
|
||||||
|
|
||||||
|
int malta_be_handler(struct pt_regs *regs, int is_fixup)
|
||||||
|
{
|
||||||
|
/* This duplicates the handling in do_be which seems wrong */
|
||||||
|
int retval = is_fixup ? MIPS_BE_FIXUP : MIPS_BE_FATAL;
|
||||||
|
|
||||||
|
if (gcmp_present) {
|
||||||
|
unsigned long cm_error = GCMPGCB(GCMEC);
|
||||||
|
unsigned long cm_addr = GCMPGCB(GCMEA);
|
||||||
|
unsigned long cm_other = GCMPGCB(GCMEO);
|
||||||
|
unsigned long cause, ocause;
|
||||||
|
char buf[256];
|
||||||
|
|
||||||
|
cause = (cm_error & GCMP_GCB_GMEC_ERROR_TYPE_MSK);
|
||||||
|
if (cause != 0) {
|
||||||
|
cause >>= GCMP_GCB_GMEC_ERROR_TYPE_SHF;
|
||||||
|
if (cause < 16) {
|
||||||
|
unsigned long cca_bits = (cm_error >> 15) & 7;
|
||||||
|
unsigned long tr_bits = (cm_error >> 12) & 7;
|
||||||
|
unsigned long mcmd_bits = (cm_error >> 7) & 0x1f;
|
||||||
|
unsigned long stag_bits = (cm_error >> 3) & 15;
|
||||||
|
unsigned long sport_bits = (cm_error >> 0) & 7;
|
||||||
|
|
||||||
|
snprintf(buf, sizeof(buf),
|
||||||
|
"CCA=%lu TR=%s MCmd=%s STag=%lu "
|
||||||
|
"SPort=%lu\n",
|
||||||
|
cca_bits, tr[tr_bits], mcmd[mcmd_bits],
|
||||||
|
stag_bits, sport_bits);
|
||||||
|
} else {
|
||||||
|
/* glob state & sresp together */
|
||||||
|
unsigned long c3_bits = (cm_error >> 18) & 7;
|
||||||
|
unsigned long c2_bits = (cm_error >> 15) & 7;
|
||||||
|
unsigned long c1_bits = (cm_error >> 12) & 7;
|
||||||
|
unsigned long c0_bits = (cm_error >> 9) & 7;
|
||||||
|
unsigned long sc_bit = (cm_error >> 8) & 1;
|
||||||
|
unsigned long mcmd_bits = (cm_error >> 3) & 0x1f;
|
||||||
|
unsigned long sport_bits = (cm_error >> 0) & 7;
|
||||||
|
snprintf(buf, sizeof(buf),
|
||||||
|
"C3=%s C2=%s C1=%s C0=%s SC=%s "
|
||||||
|
"MCmd=%s SPort=%lu\n",
|
||||||
|
core[c3_bits], core[c2_bits],
|
||||||
|
core[c1_bits], core[c0_bits],
|
||||||
|
sc_bit ? "True" : "False",
|
||||||
|
mcmd[mcmd_bits], sport_bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
ocause = (cm_other & GCMP_GCB_GMEO_ERROR_2ND_MSK) >>
|
||||||
|
GCMP_GCB_GMEO_ERROR_2ND_SHF;
|
||||||
|
|
||||||
|
printk("CM_ERROR=%08lx %s <%s>\n", cm_error,
|
||||||
|
causes[cause], buf);
|
||||||
|
printk("CM_ADDR =%08lx\n", cm_addr);
|
||||||
|
printk("CM_OTHER=%08lx %s\n", cm_other, causes[ocause]);
|
||||||
|
|
||||||
|
/* reprime cause register */
|
||||||
|
GCMPGCB(GCMEC) = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
@@ -36,6 +36,9 @@
|
|||||||
#include <linux/console.h>
|
#include <linux/console.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern void malta_be_init(void);
|
||||||
|
extern int malta_be_handler(struct pt_regs *regs, int is_fixup);
|
||||||
|
|
||||||
struct resource standard_io_resources[] = {
|
struct resource standard_io_resources[] = {
|
||||||
{
|
{
|
||||||
.name = "dma1",
|
.name = "dma1",
|
||||||
@@ -220,4 +223,7 @@ void __init plat_mem_setup(void)
|
|||||||
screen_info_setup();
|
screen_info_setup();
|
||||||
#endif
|
#endif
|
||||||
mips_reboot_setup();
|
mips_reboot_setup();
|
||||||
|
|
||||||
|
board_be_init = malta_be_init;
|
||||||
|
board_be_handler = malta_be_handler;
|
||||||
}
|
}
|
||||||
+37
-6
@@ -54,6 +54,12 @@ static inline void r4k_on_each_cpu(void (*func) (void *info), void *info,
|
|||||||
preempt_enable();
|
preempt_enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_MIPS_CMP)
|
||||||
|
#define cpu_has_safe_index_cacheops 0
|
||||||
|
#else
|
||||||
|
#define cpu_has_safe_index_cacheops 1
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Must die.
|
* Must die.
|
||||||
*/
|
*/
|
||||||
@@ -482,6 +488,8 @@ static inline void local_r4k_flush_cache_page(void *args)
|
|||||||
|
|
||||||
if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) {
|
if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) {
|
||||||
r4k_blast_dcache_page(addr);
|
r4k_blast_dcache_page(addr);
|
||||||
|
if (exec && !cpu_icache_snoops_remote_store)
|
||||||
|
r4k_blast_scache_page(addr);
|
||||||
}
|
}
|
||||||
if (exec) {
|
if (exec) {
|
||||||
if (vaddr && cpu_has_vtag_icache && mm == current->active_mm) {
|
if (vaddr && cpu_has_vtag_icache && mm == current->active_mm) {
|
||||||
@@ -584,7 +592,7 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size)
|
|||||||
* subset property so we have to flush the primary caches
|
* subset property so we have to flush the primary caches
|
||||||
* explicitly
|
* explicitly
|
||||||
*/
|
*/
|
||||||
if (size >= dcache_size) {
|
if (cpu_has_safe_index_cacheops && size >= dcache_size) {
|
||||||
r4k_blast_dcache();
|
r4k_blast_dcache();
|
||||||
} else {
|
} else {
|
||||||
R4600_HIT_CACHEOP_WAR_IMPL;
|
R4600_HIT_CACHEOP_WAR_IMPL;
|
||||||
@@ -607,7 +615,7 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size >= dcache_size) {
|
if (cpu_has_safe_index_cacheops && size >= dcache_size) {
|
||||||
r4k_blast_dcache();
|
r4k_blast_dcache();
|
||||||
} else {
|
} else {
|
||||||
R4600_HIT_CACHEOP_WAR_IMPL;
|
R4600_HIT_CACHEOP_WAR_IMPL;
|
||||||
@@ -969,6 +977,7 @@ static void __cpuinit probe_pcache(void)
|
|||||||
case CPU_24K:
|
case CPU_24K:
|
||||||
case CPU_34K:
|
case CPU_34K:
|
||||||
case CPU_74K:
|
case CPU_74K:
|
||||||
|
case CPU_1004K:
|
||||||
if ((read_c0_config7() & (1 << 16))) {
|
if ((read_c0_config7() & (1 << 16))) {
|
||||||
/* effectively physically indexed dcache,
|
/* effectively physically indexed dcache,
|
||||||
thus no virtual aliases. */
|
thus no virtual aliases. */
|
||||||
@@ -1265,6 +1274,20 @@ static void __cpuinit coherency_setup(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_DMA_NONCOHERENT)
|
||||||
|
|
||||||
|
static int __cpuinitdata coherentio;
|
||||||
|
|
||||||
|
static int __init setcoherentio(char *str)
|
||||||
|
{
|
||||||
|
coherentio = 1;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
__setup("coherentio", setcoherentio);
|
||||||
|
#endif
|
||||||
|
|
||||||
void __cpuinit r4k_cache_init(void)
|
void __cpuinit r4k_cache_init(void)
|
||||||
{
|
{
|
||||||
extern void build_clear_page(void);
|
extern void build_clear_page(void);
|
||||||
@@ -1324,14 +1347,22 @@ void __cpuinit r4k_cache_init(void)
|
|||||||
flush_data_cache_page = r4k_flush_data_cache_page;
|
flush_data_cache_page = r4k_flush_data_cache_page;
|
||||||
flush_icache_range = r4k_flush_icache_range;
|
flush_icache_range = r4k_flush_icache_range;
|
||||||
|
|
||||||
#ifdef CONFIG_DMA_NONCOHERENT
|
#if defined(CONFIG_DMA_NONCOHERENT)
|
||||||
_dma_cache_wback_inv = r4k_dma_cache_wback_inv;
|
if (coherentio) {
|
||||||
_dma_cache_wback = r4k_dma_cache_wback_inv;
|
_dma_cache_wback_inv = (void *)cache_noop;
|
||||||
_dma_cache_inv = r4k_dma_cache_inv;
|
_dma_cache_wback = (void *)cache_noop;
|
||||||
|
_dma_cache_inv = (void *)cache_noop;
|
||||||
|
} else {
|
||||||
|
_dma_cache_wback_inv = r4k_dma_cache_wback_inv;
|
||||||
|
_dma_cache_wback = r4k_dma_cache_wback_inv;
|
||||||
|
_dma_cache_inv = r4k_dma_cache_inv;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
build_clear_page();
|
build_clear_page();
|
||||||
build_copy_page();
|
build_copy_page();
|
||||||
|
#if !defined(CONFIG_MIPS_CMP)
|
||||||
local_r4k___flush_cache_all(NULL);
|
local_r4k___flush_cache_all(NULL);
|
||||||
|
#endif
|
||||||
coherency_setup();
|
coherency_setup();
|
||||||
}
|
}
|
||||||
+1
-1
@@ -221,7 +221,7 @@ void copy_user_highpage(struct page *to, struct page *from,
|
|||||||
copy_page(vto, vfrom);
|
copy_page(vto, vfrom);
|
||||||
kunmap_atomic(vfrom, KM_USER0);
|
kunmap_atomic(vfrom, KM_USER0);
|
||||||
}
|
}
|
||||||
if (((vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc) ||
|
if ((!cpu_has_ic_fills_f_dc) ||
|
||||||
pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK))
|
pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK))
|
||||||
flush_data_cache_page((unsigned long)vto);
|
flush_data_cache_page((unsigned long)vto);
|
||||||
kunmap_atomic(vto, KM_USER1);
|
kunmap_atomic(vto, KM_USER1);
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
|
|||||||
case CPU_24K:
|
case CPU_24K:
|
||||||
case CPU_25KF:
|
case CPU_25KF:
|
||||||
case CPU_34K:
|
case CPU_34K:
|
||||||
|
case CPU_1004K:
|
||||||
case CPU_74K:
|
case CPU_74K:
|
||||||
case CPU_SB1:
|
case CPU_SB1:
|
||||||
case CPU_SB1A:
|
case CPU_SB1A:
|
||||||
|
|||||||
Loaded 20 of 34 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user