From 487d70d0b8bd1c70d099a7526077ffefee412050 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Tue, 23 Nov 2010 16:06:25 +0100 Subject: MIPS: Add generic support for multiple machines within a single kernel This patch adds a generic solution to support multiple machines based on a given SoC within a single kernel image. It is implemented already for several other architectures but MIPS has no generic support for that yet. [Ralf: This competes with DT but DT is a much more complex solution and this code has been used by OpenWRT for a long time so for now DT is a bad reason to stop the merge but longer term this should be migrated to DT.] Signed-off-by: Gabor Juhos Cc: linux-mips@linux-mips.org Cc: kaloz@openwrt.org Cc: Luis R. Rodriguez Cc: Cliff Holden Patchwork: https://patchwork.linux-mips.org/patch/1814/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/Makefile | 1 + arch/mips/kernel/mips_machine.c | 86 +++++++++++++++++++++++++++++++++++++++++ arch/mips/kernel/proc.c | 7 +++- arch/mips/kernel/vmlinux.lds.S | 7 ++++ 4 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 arch/mips/kernel/mips_machine.c (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 22b2e0e38617..39773979ca6d 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -95,6 +95,7 @@ obj-$(CONFIG_GPIO_TXX9) += gpio_txx9.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_SPINLOCK_TEST) += spinlock_test.o +obj-$(CONFIG_MIPS_MACHINE) += mips_machine.o obj-$(CONFIG_OF) += prom.o diff --git a/arch/mips/kernel/mips_machine.c b/arch/mips/kernel/mips_machine.c new file mode 100644 index 000000000000..411a058d2c53 --- /dev/null +++ b/arch/mips/kernel/mips_machine.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2008-2010 Gabor Juhos + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ +#include +#include +#include + +#include + +static struct mips_machine *mips_machine __initdata; +static char *mips_machine_name = "Unknown"; + +#define for_each_machine(mach) \ + for ((mach) = (struct mips_machine *)&__mips_machines_start; \ + (mach) && \ + (unsigned long)(mach) < (unsigned long)&__mips_machines_end; \ + (mach)++) + +__init void mips_set_machine_name(const char *name) +{ + char *p; + + if (name == NULL) + return; + + p = kstrdup(name, GFP_KERNEL); + if (!p) + pr_err("MIPS: no memory for machine_name\n"); + + mips_machine_name = p; +} + +char *mips_get_machine_name(void) +{ + return mips_machine_name; +} + +__init int mips_machtype_setup(char *id) +{ + struct mips_machine *mach; + + for_each_machine(mach) { + if (mach->mach_id == NULL) + continue; + + if (strcmp(mach->mach_id, id) == 0) { + mips_machtype = mach->mach_type; + return 0; + } + } + + pr_err("MIPS: no machine found for id '%s', supported machines:\n", id); + pr_err("%-24s %s\n", "id", "name"); + for_each_machine(mach) + pr_err("%-24s %s\n", mach->mach_id, mach->mach_name); + + return 1; +} + +__setup("machtype=", mips_machtype_setup); + +__init void mips_machine_setup(void) +{ + struct mips_machine *mach; + + for_each_machine(mach) { + if (mips_machtype == mach->mach_type) { + mips_machine = mach; + break; + } + } + + if (!mips_machine) + return; + + mips_set_machine_name(mips_machine->mach_name); + pr_info("MIPS: machine is %s\n", mips_machine_name); + + if (mips_machine->mach_setup) + mips_machine->mach_setup(); +} diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index 26109c4d5170..4195abb55e59 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -12,6 +12,7 @@ #include #include #include +#include unsigned int vced_count, vcei_count; @@ -31,8 +32,12 @@ static int show_cpuinfo(struct seq_file *m, void *v) /* * For the first processor also print the system type */ - if (n == 0) + if (n == 0) { seq_printf(m, "system type\t\t: %s\n", get_system_type()); + if (mips_get_machine_name()) + seq_printf(m, "machine\t\t\t: %s\n", + mips_get_machine_name()); + } seq_printf(m, "processor\t\t: %ld\n", n); sprintf(fmt, "cpu model\t\t: %%s V%%d.%%d%s\n", diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S index f25df73db923..570607b376b5 100644 --- a/arch/mips/kernel/vmlinux.lds.S +++ b/arch/mips/kernel/vmlinux.lds.S @@ -98,6 +98,13 @@ SECTIONS INIT_TEXT_SECTION(PAGE_SIZE) INIT_DATA_SECTION(16) + . = ALIGN(4); + .mips.machines.init : AT(ADDR(.mips.machines.init) - LOAD_OFFSET) { + __mips_machines_start = .; + *(.mips.machines.init) + __mips_machines_end = .; + } + /* .exit.text is discarded at runtime, not link time, to deal with * references from .rodata */ -- cgit v1.2.3 From e77c32fe284a4da1b4e0994890a4d3527812eb61 Mon Sep 17 00:00:00 2001 From: David Daney Date: Tue, 21 Dec 2010 14:19:09 -0800 Subject: MIPS: Probe for presence of KScratch registers. Probe c0_config4 for KScratch registers and report them in /proc/cpuinfo. Signed-off-by: David Daney To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1877/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 2 ++ arch/mips/kernel/proc.c | 2 ++ 2 files changed, 4 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 68dae7b6b5db..f65d4c8c65a6 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -739,6 +739,8 @@ static inline unsigned int decode_config4(struct cpuinfo_mips *c) && cpu_has_tlb) c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40; + c->kscratch_mask = (config4 >> 16) & 0xff; + return config4 & MIPS_CONF_M; } diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index 4195abb55e59..e309665b6c81 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -74,6 +74,8 @@ static int show_cpuinfo(struct seq_file *m, void *v) ); seq_printf(m, "shadow register sets\t: %d\n", cpu_data[n].srsets); + seq_printf(m, "kscratch registers\t: %d\n", + hweight8(cpu_data[n].kscratch_mask)); seq_printf(m, "core\t\t\t: %d\n", cpu_data[n].core); sprintf(fmt, "VCE%%c exceptions\t\t: %s\n", -- cgit v1.2.3 From 3d8bfdd0307223de678962f1c1907a7cec549136 Mon Sep 17 00:00:00 2001 From: David Daney Date: Tue, 21 Dec 2010 14:19:11 -0800 Subject: MIPS: Use C0_KScratch (if present) to hold PGD pointer. Decide at runtime to use either Context or KScratch to hold the PGD pointer. Signed-off-by: David Daney To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1876/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index e97104302541..71350f7f2d88 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -1592,7 +1592,6 @@ void __cpuinit per_cpu_trap_init(void) #endif /* CONFIG_MIPS_MT_SMTC */ cpu_data[cpu].asid_cache = ASID_FIRST_VERSION; - TLBMISS_HANDLER_SETUP(); atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; @@ -1614,6 +1613,7 @@ void __cpuinit per_cpu_trap_init(void) write_c0_wired(0); } #endif /* CONFIG_MIPS_MT_SMTC */ + TLBMISS_HANDLER_SETUP(); } /* Install CPU exception handler */ -- cgit v1.2.3 From 94bb0c1ab293c298a8852e4f10c4215bad6daa9b Mon Sep 17 00:00:00 2001 From: David Daney Date: Tue, 28 Dec 2010 13:26:23 -0800 Subject: MIPS: jump label: Add MIPS support. In order not to be left behind, we add jump label support for MIPS. Tested on 64-bit big endian (Octeon), and 32-bit little endian (malta/qemu). Signed-off-by: David Daney To: linux-mips@linux-mips.org Cc: Steven Rostedt Cc: Jason Baron Patchwork: https://patchwork.linux-mips.org/patch/1923/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/Makefile | 2 ++ arch/mips/kernel/jump_label.c | 54 +++++++++++++++++++++++++++++++++++++++++++ arch/mips/kernel/module.c | 5 ++++ 3 files changed, 61 insertions(+) create mode 100644 arch/mips/kernel/jump_label.c (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 39773979ca6d..cedee2bcbd18 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -107,4 +107,6 @@ obj-$(CONFIG_MIPS_CPUFREQ) += cpufreq/ obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o +obj-$(CONFIG_JUMP_LABEL) += jump_label.o + CPPFLAGS_vmlinux.lds := $(KBUILD_CFLAGS) diff --git a/arch/mips/kernel/jump_label.c b/arch/mips/kernel/jump_label.c new file mode 100644 index 000000000000..6001610cfe55 --- /dev/null +++ b/arch/mips/kernel/jump_label.c @@ -0,0 +1,54 @@ +/* + * 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) 2010 Cavium Networks, Inc. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef HAVE_JUMP_LABEL + +#define J_RANGE_MASK ((1ul << 28) - 1) + +void arch_jump_label_transform(struct jump_entry *e, + enum jump_label_type type) +{ + union mips_instruction insn; + union mips_instruction *insn_p = + (union mips_instruction *)(unsigned long)e->code; + + /* Jump only works within a 256MB aligned region. */ + BUG_ON((e->target & ~J_RANGE_MASK) != (e->code & ~J_RANGE_MASK)); + + /* Target must have 4 byte alignment. */ + BUG_ON((e->target & 3) != 0); + + if (type == JUMP_LABEL_ENABLE) { + insn.j_format.opcode = j_op; + insn.j_format.target = (e->target & J_RANGE_MASK) >> 2; + } else { + insn.word = 0; /* nop */ + } + + get_online_cpus(); + mutex_lock(&text_mutex); + *insn_p = insn; + + flush_icache_range((unsigned long)insn_p, + (unsigned long)insn_p + sizeof(*insn_p)); + + mutex_unlock(&text_mutex); + put_online_cpus(); +} + +#endif /* HAVE_JUMP_LABEL */ diff --git a/arch/mips/kernel/module.c b/arch/mips/kernel/module.c index d87a72e9fac7..dd940b701963 100644 --- a/arch/mips/kernel/module.c +++ b/arch/mips/kernel/module.c @@ -30,6 +30,8 @@ #include #include #include +#include + #include /* MODULE_START */ struct mips_hi16 { @@ -382,6 +384,9 @@ int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *s; char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; + /* Make jump label nops. */ + jump_label_apply_nops(me); + INIT_LIST_HEAD(&me->arch.dbe_list); for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { if (strcmp("__dbe_table", secstrings + s->sh_name) != 0) -- cgit v1.2.3 From 1befdd5536e1500371f7f884d0f0ae528a519333 Mon Sep 17 00:00:00 2001 From: David Daney Date: Thu, 14 Oct 2010 12:36:49 -0700 Subject: MIPS: Implement __read_mostly Just do what everyone else is doing by placing __read_mostly things in the .data.read_mostly section. mips_io_port_base can not be read-only (const) and writable (__read_mostly) at the same time. One of them has to go, so I chose to eliminate the __read_mostly. It will still get stuck in a portion of memory that is not adjacent to things that are written, and thus not be on a dirty cache line, for whatever that is worth. Signed-off-by: David Daney To: linux-mips@linux-mips.org Patchwork: http://patchwork.linux-mips.org/patch/1702/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index acd3f2c49c06..8ad1d5679f14 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -70,7 +70,7 @@ static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE; * mips_io_port_base is the begin of the address space to which x86 style * I/O ports are mapped. */ -const unsigned long mips_io_port_base __read_mostly = -1; +const unsigned long mips_io_port_base = -1; EXPORT_SYMBOL(mips_io_port_base); static struct resource code_resource = { .name = "Kernel code", }; -- cgit v1.2.3