Commit c78cbf49 authored by Ralf Baechle's avatar Ralf Baechle

Support for MIPSsim, the cycle accurate MIPS simulator.

Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent b288f135
......@@ -448,6 +448,17 @@ config MOMENCO_OCELOT_3
The Ocelot-3 is based off Discovery III System Controller and
PMC-Sierra Rm79000 core.
config MIPS_SIM
bool 'Support for MIPS simulator (MIPSsim)'
select DMA_NONCOHERENT
select IRQ_CPU
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_BIG_ENDIAN
select SYS_SUPPORTS_LITTLE_ENDIAN
help
This option enables support for MIPS Technologies MIPSsim software
emulator.
config MOMENCO_JAGUAR_ATX
bool "Support for Momentum Jaguar board"
select BOOT_ELF32
......
......@@ -436,6 +436,13 @@ load-$(CONFIG_MIPS_MALTA) += 0xffffffff80100000
core-$(CONFIG_MIPS_SEAD) += arch/mips/mips-boards/sead/
load-$(CONFIG_MIPS_SEAD) += 0xffffffff80100000
#
# MIPS SIM
#
core-$(CONFIG_MIPS_SIM) += arch/mips/mips-boards/sim/
cflags-$(CONFIG_MIPS_SIM) += -Iinclude/asm-mips/mach-sim
load-$(CONFIG_MIPS_SIM) += 0x80100000
#
# Momentum Ocelot board
#
......
......@@ -116,7 +116,7 @@
EXPORT(stext) # used for profiling
EXPORT(_stext)
#ifdef CONFIG_QEMU
#if defined(CONFIG_QEMU) || defined(CONFIG_MIPS_SIM)
/*
* Give us a fighting chance of running if execution beings at the
* kernel load address. This is needed because this platform does
......
#
# Copyright (C) 2005 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.
#
obj-y := sim_setup.o sim_mem.o sim_time.o sim_printf.o sim_int.o sim_irq.o \
sim_cmdline.o
obj-$(CONFIG_SMP) += sim_smp.o
/*
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 1999,2000 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.
*
* Kernel command line creation using the prom monitor (YAMON) argc/argv.
*/
#include <linux/init.h>
#include <linux/string.h>
#include <asm/bootinfo.h>
extern int prom_argc;
extern int *_prom_argv;
/*
* YAMON (32-bit PROM) pass arguments and environment as 32-bit pointer.
* This macro take care of sign extension.
*/
#define prom_argv(index) ((char *)(((int *)(int)_prom_argv)[(index)]))
char arcs_cmdline[CL_SIZE];
char * __init prom_getcmdline(void)
{
return &(arcs_cmdline[0]);
}
void __init prom_init_cmdline(void)
{
char *cp;
int actr;
actr = 1; /* Always ignore argv[0] */
cp = &(arcs_cmdline[0]);
while(actr < prom_argc) {
strcpy(cp, prom_argv(actr));
cp += strlen(prom_argv(actr));
*cp++ = ' ';
actr++;
}
if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
--cp;
*cp = '\0';
}
/*
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 1999, 2000 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.
*
* Interrupt exception dispatch code.
*/
#include <linux/config.h>
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
/* A lot of complication here is taken away because:
*
* 1) We handle one interrupt and return, sitting in a loop and moving across
* all the pending IRQ bits in the cause register is _NOT_ the answer, the
* common case is one pending IRQ so optimize in that direction.
*
* 2) We need not check against bits in the status register IRQ mask, that
* would make this routine slow as hell.
*
* 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in
* between like BSD spl() brain-damage.
*
* Furthermore, the IRQs on the MIPS board look basically (barring software
* IRQs which we don't use at all and all external interrupt sources are
* combined together on hardware interrupt 0 (MIPS IRQ 2)) like:
*
* MIPS IRQ Source
* -------- ------
* 0 Software (ignored)
* 1 Software (ignored)
* 2 Combined hardware interrupt (hw0)
* 3 Hardware (ignored)
* 4 Hardware (ignored)
* 5 Hardware (ignored)
* 6 Hardware (ignored)
* 7 R4k timer (what we use)
*
* Note: On the SEAD board thing are a little bit different.
* Here IRQ 2 (hw0) is wired to the UART0 and IRQ 3 (hw1) is wired
* wired to UART1.
*
* We handle the IRQ according to _our_ priority which is:
*
* Highest ---- R4k Timer
* Lowest ---- Combined hardware interrupt
*
* then we just return, if multiple IRQs are pending then we will just take
* another exception, big deal.
*/
.text
.set noreorder
.set noat
.align 5
NESTED(mipsIRQ, PT_SIZE, sp)
SAVE_ALL
CLI
.set at
mfc0 s0, CP0_CAUSE # get irq bits
mfc0 s1, CP0_STATUS # get irq mask
and s0, s1
/* First we check for r4k counter/timer IRQ. */
andi a0, s0, CAUSEF_IP7
beq a0, zero, 1f
andi a0, s0, CAUSEF_IP2 # delay slot, check hw0 interrupt
/* Wheee, a timer interrupt. */
move a0, sp
jal mips_timer_interrupt
nop
j ret_from_irq
nop
1:
#if defined(CONFIG_MIPS_SEAD)
beq a0, zero, 1f
andi a0, s0, CAUSEF_IP3 # delay slot, check hw1 interrupt
#else
beq a0, zero, 1f # delay slot, check hw3 interrupt
andi a0, s0, CAUSEF_IP5
#endif
/* Wheee, combined hardware level zero interrupt. */
#if defined(CONFIG_MIPS_ATLAS)
jal atlas_hw0_irqdispatch
#elif defined(CONFIG_MIPS_MALTA)
jal malta_hw0_irqdispatch
#elif defined(CONFIG_MIPS_SEAD)
jal sead_hw0_irqdispatch
#else
#error "MIPS board not supported\n"
#endif
move a0, sp # delay slot
j ret_from_irq
nop # delay slot
1:
#if defined(CONFIG_MIPS_SEAD)
beq a0, zero, 1f
andi a0, s0, CAUSEF_IP5 # delay slot, check hw3 interrupt
jal sead_hw1_irqdispatch
move a0, sp # delay slot
j ret_from_irq
nop # delay slot
1:
#endif
#if defined(CONFIG_MIPS_MALTA)
beq a0, zero, 1f # check hw3 (coreHI) interrupt
nop
jal corehi_irqdispatch
move a0, sp
j ret_from_irq
nop
1:
#endif
/*
* Here by mistake? This is possible, what can happen is that by the
* time we take the exception the IRQ pin goes low, so just leave if
* this is the case.
*/
move a1,s0
PRINT("Got interrupt: c0_cause = %08x\n")
mfc0 a1, CP0_EPC
PRINT("c0_epc = %08x\n")
j ret_from_irq
nop
END(mipsIRQ)
/*
* Copyright (C) 2005 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.
*
*/
#include <linux/init.h>
#include <linux/string.h>
#include <asm/bootinfo.h>
extern char arcs_cmdline[];
char * __init prom_getcmdline(void)
{
return arcs_cmdline;
}
void __init prom_init_cmdline(void)
{
/* nothing to do */
}
/*
* Copyright (C) 1999, 2005 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.
*
*/
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
#include <asm/mips-boards/simint.h>
extern void mips_cpu_irq_init(int);
extern asmlinkage void simIRQ(void);
asmlinkage void sim_hw0_irqdispatch(struct pt_regs *regs)
{
do_IRQ(2, regs);
}
void __init arch_init_irq(void)
{
/* Now safe to set the exception vector. */
set_except_vector(0, simIRQ);
mips_cpu_irq_init(MIPSCPU_INT_BASE);
}
/*
* Copyright (C) 1999, 2005 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.
*
* Interrupt exception dispatch code.
*
*/
#include <linux/config.h>
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
#include <asm/mips-boards/simint.h>
.text
.set noreorder
.set noat
.align 5
NESTED(simIRQ, PT_SIZE, sp)
SAVE_ALL
CLI
.set at
mfc0 s0, CP0_CAUSE # get irq bits
mfc0 s1, CP0_STATUS # get irq mask
andi s0, ST0_IM # CAUSE.CE may be non-zero!
and s0, s1
#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
.set mips32
clz a0, s0
.set mips0
negu a0
addu a0, 31-CAUSEB_IP
bltz a0, spurious
#else
beqz s0, spurious
li a0, 7
and t0, s0, 0xf000
sltiu t0, t0, 1
sll t0, 2
subu a0, t0
sll s0, t0
and t0, s0, 0xc000
sltiu t0, t0, 1
sll t0, 1
subu a0, t0
sll s0, t0
and t0, s0, 0x8000
sltiu t0, t0, 1
# sll t0, 0
subu a0, t0
# sll s0, t0
#endif
#ifdef CASCADE_IRQ
li a1, CASCADE_IRQ
bne a0, a1, 1f
addu a0, MIPSCPU_INT_BASE
jal CASCADE_DISPATCH
move a0, sp
j ret_from_irq
nop
1:
#else
addu a0, MIPSCPU_INT_BASE
#endif
jal do_IRQ
move a1, sp
j ret_from_irq
nop
spurious:
j spurious_interrupt
nop
END(simIRQ)
/*
* Copyright (C) 2005 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.
*
*/
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/bootmem.h>
#include <asm/bootinfo.h>
#include <asm/page.h>
#include <asm/mips-boards/prom.h>
/*#define DEBUG*/
enum simmem_memtypes {
simmem_reserved = 0,
simmem_free,
};
struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS];
#ifdef DEBUG
static char *mtypes[3] = {
"SIM reserved memory",
"SIM free memory",
};
#endif
/* References to section boundaries */
extern char _end;
#define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK)
struct prom_pmemblock * __init prom_getmdesc(void)
{
unsigned int memsize;
memsize = 0x02000000;
prom_printf("Setting default memory size 0x%08x\n", memsize);
memset(mdesc, 0, sizeof(mdesc));
mdesc[0].type = simmem_reserved;
mdesc[0].base = 0x00000000;
mdesc[0].size = 0x00001000;
mdesc[1].type = simmem_free;
mdesc[1].base = 0x00001000;
mdesc[1].size = 0x000ff000;
mdesc[2].type = simmem_reserved;
mdesc[2].base = 0x00100000;
mdesc[2].size = CPHYSADDR(PFN_ALIGN(&_end)) - mdesc[2].base;
mdesc[3].type = simmem_free;
mdesc[3].base = CPHYSADDR(PFN_ALIGN(&_end));
mdesc[3].size = memsize - mdesc[3].base;
return &mdesc[0];
}
static int __init prom_memtype_classify (unsigned int type)
{
switch (type) {
case simmem_free:
return BOOT_MEM_RAM;
case simmem_reserved:
default:
return BOOT_MEM_RESERVED;
}
}
void __init prom_meminit(void)
{
struct prom_pmemblock *p;
p = prom_getmdesc();
while (p->size) {
long type;
unsigned long base, size;
type = prom_memtype_classify (p->type);
base = p->base;
size = p->size;
add_memory_region(base, size, type);
p++;
}
}
unsigned long __init prom_free_prom_memory(void)
{
int i;
unsigned long freed = 0;
unsigned long addr;
for (i = 0; i < boot_mem_map.nr_map; i++) {
if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA)
continue;
addr = boot_mem_map.map[i].addr;
while (addr < boot_mem_map.map[i].addr
+ boot_mem_map.map[i].size) {
ClearPageReserved(virt_to_page(__va(addr)));
set_page_count(virt_to_page(__va(addr)), 1);
free_page((unsigned long)__va(addr));
addr += PAGE_SIZE;
freed += PAGE_SIZE;
}
}
printk("Freeing prom memory: %ldkb freed\n", freed >> 10);
return freed;
}
/*
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 1999,2000 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.
*
* Putting things on the screen/serial line using YAMONs facilities.
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/serial_reg.h>
#include <linux/spinlock.h>
#include <asm/io.h>
#include <asm/system.h>
static inline unsigned int serial_in(int offset)
{
return inb(0x3f8 + offset);
}
static inline void serial_out(int offset, int value)
{
outb(value, 0x3f8 + offset);
}
int putPromChar(char c)
{
while ((serial_in(UART_LSR) & UART_LSR_THRE) == 0)
;
serial_out(UART_TX, c);
return 1;
}
char getPromChar(void)
{
while (!(serial_in(UART_LSR) & 1))
;
return serial_in(UART_RX);
}
void prom_printf(char *fmt, ...)
{
va_list args;
int l;
char *p, *buf_end;
char buf[1024];
va_start(args, fmt);
l = vsprintf(buf, fmt, args); /* hopefully i < sizeof(buf) */
va_end(args);
buf_end = buf + l;
for (p = buf; p < buf_end; p++) {
/* Crude cr/nl handling is better than none */
if (*p == '\n')
putPromChar('\r');
putPromChar(*p);
}
}
/*
* Copyright (C) 2005 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.
*
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <asm/cpu.h>
#include <asm/bootinfo.h>
#include <asm/irq.h>
#include <asm/mips-boards/generic.h>
#include <asm/mips-boards/prom.h>
#include <asm/serial.h>
#include <asm/io.h>
#include <asm/time.h>
#include <asm/mips-boards/sim.h>
#include <asm/mips-boards/simint.h>
extern void sim_time_init(void);
extern void sim_timer_setup(struct irqaction *irq);
static void __init serial_init(void);
unsigned int _isbonito = 0;
extern void __init sanitize_tlb_entries(void);
const char *get_system_type(void)
{
return "MIPSsim";
}
void __init plat_setup(void)
{
set_io_port_base(0xbfd00000);
serial_init();
board_time_init = sim_time_init;
board_timer_setup = sim_timer_setup;
prom_printf("Linux started...\n");
#ifdef CONFIG_MT_SMP
sanitize_tlb_entries();
#endif
}
void prom_init(void)
{
set_io_port_base(0xbfd00000);
prom_printf("\nLINUX started...\n");
prom_init_cmdline();
prom_meminit();
}
static void __init serial_init(void)
{
#ifdef CONFIG_SERIAL_8250
struct uart_port s;
memset(&s, 0, sizeof(s));
s.iobase = 0x3f8;
/* hardware int 4 - the serial int, is CPU int 6
but poll for now */
s.irq = 0;
s.uartclk = BASE_BAUD * 16;
s.flags = ASYNC_BOOT_AUTOCONF | UPF_SKIP_TEST;
s.iotype = SERIAL_IO_PORT | ASYNC_SKIP_TEST;
s.regshift = 0;
s.timeout = 4;
if (early_serial_setup(&s) != 0) {
prom_printf(KERN_ERR "Serial setup failed!\n");
}
#endif
}
/*
* Copyright (C) 2005 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.
*
*/
/*
* Simulator Platform-specific hooks for SMP operation
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/cpumask.h>
#include <linux/interrupt.h>
#include <asm/atomic.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>
#ifdef CONFIG_MIPS_MT_SMTC
#include <asm/smtc_ipi.h>
#endif /* CONFIG_MIPS_MT_SMTC */
/* VPE/SMP Prototype implements platform interfaces directly */
#if !defined(CONFIG_MIPS_MT_SMP)
/*
* Cause the specified action to be performed on a targeted "CPU"
*/
void core_send_ipi(int cpu, unsigned int action)
{
#ifdef CONFIG_MIPS_MT_SMTC
void smtc_send_ipi(int, int, unsigned int);
smtc_send_ipi(cpu, LINUX_SMP_IPI, action);
#endif /* CONFIG_MIPS_MT_SMTC */
/* "CPU" may be TC of same VPE, VPE of same CPU, or different CPU */
}
/*
* Detect available CPUs/VPEs/TCs and populate phys_cpu_present_map
*/
void __init prom_build_cpu_map(void)
{
#ifdef CONFIG_MIPS_MT_SMTC
extern int mipsmt_build_cpu_map(int startslot);
int nextslot;
cpus_clear(phys_cpu_present_map);
/* Register the boot CPU */
smp_prepare_boot_cpu();
/*
* As of November, 2004, MIPSsim only simulates one core
* at a time. However, that core may be a MIPS MT core
* with multiple virtual processors and thread contexts.
*/
if (read_c0_config3() & (1<<2)) {
nextslot = mipsmt_build_cpu_map(1);
}
#endif /* CONFIG_MIPS_MT_SMTC */
}
/*
* Platform "CPU" startup hook
*/
void prom_boot_secondary(int cpu, struct task_struct *idle)
{
#ifdef CONFIG_MIPS_MT_SMTC
extern void smtc_boot_secondary(int cpu, struct task_struct *t);
smtc_boot_secondary(cpu, idle);
#endif /* CONFIG_MIPS_MT_SMTC */
}
/*
* Post-config but pre-boot cleanup entry point
*/
void prom_init_secondary(void)
{
#ifdef CONFIG_MIPS_MT_SMTC
void smtc_init_secondary(void);
smtc_init_secondary();
#endif /* CONFIG_MIPS_MT_SMTC */
}
/*
* Platform SMP pre-initialization
*/
void prom_prepare_cpus(unsigned int max_cpus)
{
#ifdef CONFIG_MIPS_MT_SMTC
void mipsmt_prepare_cpus(int c);
/*
* As noted above, we can assume a single CPU for now
* but it may be multithreaded.
*/
if (read_c0_config3() & (1<<2)) {
mipsmt_prepare_cpus(max_cpus);
}
#endif /* CONFIG_MIPS_MT_SMTC */
}
/*
* SMP initialization finalization entry point
*/
void prom_smp_finish(void)
{
#ifdef CONFIG_MIPS_MT_SMTC
void smtc_smp_finish(void);
smtc_smp_finish();
#endif /* CONFIG_MIPS_MT_SMTC */
}
/*
* Hook for after all CPUs are online
*/
void prom_cpus_done(void)
{
#ifdef CONFIG_MIPS_MT_SMTC
#endif /* CONFIG_MIPS_MT_SMTC */
}
#endif /* CONFIG_MIPS32R2_MT_SMP */
#include <linux/types.h>
#include <linux/config.h>
#include <linux/init.h>
#include <linux/kernel_stat.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <asm/mipsregs.h>
#include <asm/ptrace.h>
#include <asm/hardirq.h>
#include <asm/div64.h>
#include <asm/cpu.h>
#include <asm/time.h>
#include <linux/interrupt.h>
#include <linux/mc146818rtc.h>
#include <linux/timex.h>
#include <asm/mipsregs.h>
#include <asm/ptrace.h>
#include <asm/hardirq.h>
#include <asm/irq.h>
#include <asm/div64.h>
#include <asm/cpu.h>
#include <asm/time.h>
#include <asm/mc146818-time.h>
#include <asm/msc01_ic.h>
#include <asm/mips-boards/generic.h>
#include <asm/mips-boards/prom.h>
#include <asm/mips-boards/simint.h>
#include <asm/mc146818-time.h>
#include <asm/smp.h>
unsigned long cpu_khz;
extern asmlinkage void ll_local_timer_interrupt(int irq, struct pt_regs *regs);
irqreturn_t sim_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
#ifdef CONFIG_SMP
int cpu = smp_processor_id();
/*
* CPU 0 handles the global timer interrupt job
* resets count/compare registers to trigger next timer int.
*/
#ifndef CONFIG_MIPS_MT_SMTC
if (cpu == 0) {
timer_interrupt(irq, dev_id, regs);
}
else {
/* Everyone else needs to reset the timer int here as
ll_local_timer_interrupt doesn't */
/*
* FIXME: need to cope with counter underflow.
* More support needs to be added to kernel/time for
* counter/timer interrupts on multiple CPU's
*/
write_c0_compare (read_c0_count() + ( mips_hpt_frequency/HZ));
}
#else /* SMTC */
/*
* In SMTC system, one Count/Compare set exists per VPE.
* Which TC within a VPE gets the interrupt is essentially
* random - we only know that it shouldn't be one with
* IXMT set. Whichever TC gets the interrupt needs to
* send special interprocessor interrupts to the other
* TCs to make sure that they schedule, etc.
*
* That code is specific to the SMTC kernel, not to
* the simulation platform, so it's invoked from
* the general MIPS timer_interrupt routine.
*
* We have a problem in that the interrupt vector code
* had to turn off the timer IM bit to avoid redundant
* entries, but we may never get to mips_cpu_irq_end
* to turn it back on again if the scheduler gets
* involved. So we clear the pending timer here,
* and re-enable the mask...
*/
int vpflags = dvpe();
write_c0_compare (read_c0_count() - 1);
clear_c0_cause(0x100 << MIPSCPU_INT_CPUCTR);
set_c0_status(0x100 << MIPSCPU_INT_CPUCTR);
irq_enable_hazard();
evpe(vpflags);
if(cpu_data[cpu].vpe_id == 0) timer_interrupt(irq, dev_id, regs);
else write_c0_compare (read_c0_count() + ( mips_hpt_frequency/HZ));
smtc_timer_broadcast(cpu_data[cpu].vpe_id);
#endif /* CONFIG_MIPS_MT_SMTC */
/*
* every CPU should do profiling and process accounting
*/
local_timer_interrupt (irq, dev_id, regs);
return IRQ_HANDLED;
#else
return timer_interrupt (irq, dev_id, regs);
#endif
}
/*
* Estimate CPU frequency. Sets mips_counter_frequency as a side-effect
*/
static unsigned int __init estimate_cpu_frequency(void)
{
unsigned int prid = read_c0_prid() & 0xffff00;
unsigned int count;
#if 1
/*
* hardwire the board frequency to 12MHz.
*/
if ((prid == (PRID_COMP_MIPS | PRID_IMP_20KC)) ||
(prid == (PRID_COMP_MIPS | PRID_IMP_25KF)))
count = 12000000;
else
count = 6000000;
#else
unsigned int flags;
local_irq_save(flags);
/* Start counter exactly on falling edge of update flag */
while (CMOS_READ(RTC_REG_A) & RTC_UIP);
while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
/* Start r4k counter. */
write_c0_count(0);
/* Read counter exactly on falling edge of update flag */
while (CMOS_READ(RTC_REG_A) & RTC_UIP);
while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
count = read_c0_count();
/* restore interrupts */
local_irq_restore(flags);
#endif
mips_hpt_frequency = count;
if ((prid != (PRID_COMP_MIPS | PRID_IMP_20KC)) &&
(prid != (PRID_COMP_MIPS | PRID_IMP_25KF)))
count *= 2;
count += 5000; /* round */
count -= count%10000;
return count;
}
void __init sim_time_init(void)
{
unsigned int est_freq, flags;
local_irq_save(flags);
/* Set Data mode - binary. */
CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL);
est_freq = estimate_cpu_frequency ();
printk("CPU frequency %d.%02d MHz\n", est_freq/1000000,
(est_freq%1000000)*100/1000000);
cpu_khz = est_freq / 1000;
local_irq_restore(flags);
}
static int mips_cpu_timer_irq;
static void mips_timer_dispatch (struct pt_regs *regs)
{
do_IRQ (mips_cpu_timer_irq, regs);
}
void __init sim_timer_setup(struct irqaction *irq)
{
if (cpu_has_veic) {
set_vi_handler(MSC01E_INT_CPUCTR, mips_timer_dispatch);
mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR;
}
else {
if (cpu_has_vint)
set_vi_handler(MIPSCPU_INT_CPUCTR, mips_timer_dispatch);
mips_cpu_timer_irq = MIPSCPU_INT_BASE + MIPSCPU_INT_CPUCTR;
}
/* we are using the cpu counter for timer interrupts */
irq->handler = sim_timer_interrupt;
setup_irq(mips_cpu_timer_irq, irq);
#ifdef CONFIG_SMP
/* irq_desc(riptor) is a global resource, when the interrupt overlaps
on seperate cpu's the first one tries to handle the second interrupt.
The effect is that the int remains disabled on the second cpu.
Mark the interrupt with IRQ_PER_CPU to avoid any confusion */
irq_desc[mips_cpu_timer_irq].status |= IRQ_PER_CPU;
#endif
/* to generate the first timer interrupt */
write_c0_compare(read_c0_count() + (mips_hpt_frequency/HZ));
}
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2003, 2004 Chris Dearman
*/
#ifndef __ASM_MACH_SIM_CPU_FEATURE_OVERRIDES_H
#define __ASM_MACH_SIM_CPU_FEATURE_OVERRIDES_H
#include <linux/config.h>
/*
* CPU feature overrides for MIPS boards
*/
#ifdef CONFIG_CPU_MIPS32
#define cpu_has_tlb 1
#define cpu_has_4kex 1
#define cpu_has_4ktlb 1
#define cpu_has_fpu 0
/* #define cpu_has_32fpr ? */
#define cpu_has_counter 1
/* #define cpu_has_watch ? */
#define cpu_has_divec 1
#define cpu_has_vce 0
/* #define cpu_has_cache_cdex_p ? */
/* #define cpu_has_cache_cdex_s ? */
/* #define cpu_has_prefetch ? */
#define cpu_has_mcheck 1
/* #define cpu_has_ejtag ? */
#define cpu_has_llsc 1
/* #define cpu_has_vtag_icache ? */
/* #define cpu_has_dc_aliases ? */
/* #define cpu_has_ic_fills_f_dc ? */
#define cpu_has_nofpuex 0
/* #define cpu_has_64bits ? */
/* #define cpu_has_64bit_zero_reg ? */
/* #define cpu_has_subset_pcaches ? */
#endif
#ifdef CONFIG_CPU_MIPS64
#define cpu_has_tlb 1
#define cpu_has_4kex 1
#define cpu_has_4ktlb 1
/* #define cpu_has_fpu ? */
/* #define cpu_has_32fpr ? */
#define cpu_has_counter 1
/* #define cpu_has_watch ? */
#define cpu_has_divec 1
#define cpu_has_vce 0
/* #define cpu_has_cache_cdex_p ? */
/* #define cpu_has_cache_cdex_s ? */
/* #define cpu_has_prefetch ? */
#define cpu_has_mcheck 1
/* #define cpu_has_ejtag ? */
#define cpu_has_llsc 1
/* #define cpu_has_vtag_icache ? */
/* #define cpu_has_dc_aliases ? */
/* #define cpu_has_ic_fills_f_dc ? */
#define cpu_has_nofpuex 0
/* #define cpu_has_64bits ? */
/* #define cpu_has_64bit_zero_reg ? */
/* #define cpu_has_subset_pcaches ? */
#endif
#endif /* __ASM_MACH_MIPS_CPU_FEATURE_OVERRIDES_H */
/*
* Copyright (C) 2005 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.
*
*/
#ifndef _ASM_MIPS_BOARDS_SIM_H
#define _ASM_MIPS_BOARDS_SIM_H
#define STATS_ON 1
#define STATS_OFF 2
#define STATS_CLEAR 3
#define STATS_DUMP 4
#define TRACE_ON 5
#define TRACE_OFF 6
#define simcfg(code) \
({ \
__asm__ __volatile__( \
"sltiu $0,$0, %0" \
::"i"(code) \
); \
})
#endif
/*
* Copyright (C) 2005 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.
*/
#ifndef _MIPS_SIMINT_H
#define _MIPS_SIMINT_H
#define SIM_INT_BASE 0
#define MIPSCPU_INT_MB0 2
#define MIPSCPU_INT_BASE 16
#define MIPS_CPU_TIMER_IRQ 7
#define MIPSCPU_INT_CPUCTR 7
#define MSC01E_INT_BASE 64
#define MIPSCPU_INT_CPUCTR 7
#define MSC01E_INT_CPUCTR 11
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment