From 4be3d2f3966b9f010bb997dcab25e7af489a841e Mon Sep 17 00:00:00 2001 From: Zi Shen Lim Date: Wed, 31 Oct 2012 12:01:28 +0000 Subject: MIPS: perf: Add XLP support for hardware perf. Add support for XLP performance counters register in perf. Update mips/Kconfig so that perf events can be selected for XLP. Signed-off-by: Zi Shen Lim Signed-off-by: Jayachandran C Patchwork: http://patchwork.linux-mips.org/patch/4457 Signed-off-by: John Crispin --- arch/mips/kernel/perf_event_mipsxx.c | 124 +++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/perf_event_mipsxx.c b/arch/mips/kernel/perf_event_mipsxx.c index a9b995dcf69..b14c14d90fc 100644 --- a/arch/mips/kernel/perf_event_mipsxx.c +++ b/arch/mips/kernel/perf_event_mipsxx.c @@ -840,6 +840,16 @@ static const struct mips_perf_event bmips5000_event_map [PERF_COUNT_HW_BRANCH_MISSES] = { 0x02, CNTR_ODD, T }, }; +static const struct mips_perf_event xlp_event_map[PERF_COUNT_HW_MAX] = { + [PERF_COUNT_HW_CPU_CYCLES] = { 0x01, CNTR_ALL }, + [PERF_COUNT_HW_INSTRUCTIONS] = { 0x18, CNTR_ALL }, /* PAPI_TOT_INS */ + [PERF_COUNT_HW_CACHE_REFERENCES] = { 0x04, CNTR_ALL }, /* PAPI_L1_ICA */ + [PERF_COUNT_HW_CACHE_MISSES] = { 0x07, CNTR_ALL }, /* PAPI_L1_ICM */ + [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = { 0x1b, CNTR_ALL }, /* PAPI_BR_CN */ + [PERF_COUNT_HW_BRANCH_MISSES] = { 0x1c, CNTR_ALL }, /* PAPI_BR_MSP */ + [PERF_COUNT_HW_BUS_CYCLES] = { UNSUPPORTED_PERF_EVENT_ID }, +}; + /* 24K/34K/1004K cores can share the same cache event map. */ static const struct mips_perf_event mipsxxcore_cache_map [PERF_COUNT_HW_CACHE_MAX] @@ -1092,6 +1102,100 @@ static const struct mips_perf_event octeon_cache_map }, }; +static const struct mips_perf_event xlp_cache_map + [PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX] = { +[C(L1D)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = { 0x31, CNTR_ALL }, /* PAPI_L1_DCR */ + [C(RESULT_MISS)] = { 0x30, CNTR_ALL }, /* PAPI_L1_LDM */ + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = { 0x2f, CNTR_ALL }, /* PAPI_L1_DCW */ + [C(RESULT_MISS)] = { 0x2e, CNTR_ALL }, /* PAPI_L1_STM */ + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, + [C(RESULT_MISS)] = { UNSUPPORTED_PERF_EVENT_ID }, + }, +}, +[C(L1I)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = { 0x04, CNTR_ALL }, /* PAPI_L1_ICA */ + [C(RESULT_MISS)] = { 0x07, CNTR_ALL }, /* PAPI_L1_ICM */ + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, + [C(RESULT_MISS)] = { UNSUPPORTED_PERF_EVENT_ID }, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, + [C(RESULT_MISS)] = { UNSUPPORTED_PERF_EVENT_ID }, + }, +}, +[C(LL)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = { 0x35, CNTR_ALL }, /* PAPI_L2_DCR */ + [C(RESULT_MISS)] = { 0x37, CNTR_ALL }, /* PAPI_L2_LDM */ + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = { 0x34, CNTR_ALL }, /* PAPI_L2_DCA */ + [C(RESULT_MISS)] = { 0x36, CNTR_ALL }, /* PAPI_L2_DCM */ + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, + [C(RESULT_MISS)] = { UNSUPPORTED_PERF_EVENT_ID }, + }, +}, +[C(DTLB)] = { + /* + * Only general DTLB misses are counted use the same event for + * read and write. + */ + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, + [C(RESULT_MISS)] = { 0x2d, CNTR_ALL }, /* PAPI_TLB_DM */ + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, + [C(RESULT_MISS)] = { 0x2d, CNTR_ALL }, /* PAPI_TLB_DM */ + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, + [C(RESULT_MISS)] = { UNSUPPORTED_PERF_EVENT_ID }, + }, +}, +[C(ITLB)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, + [C(RESULT_MISS)] = { 0x08, CNTR_ALL }, /* PAPI_TLB_IM */ + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, + [C(RESULT_MISS)] = { 0x08, CNTR_ALL }, /* PAPI_TLB_IM */ + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, + [C(RESULT_MISS)] = { UNSUPPORTED_PERF_EVENT_ID }, + }, +}, +[C(BPU)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, + [C(RESULT_MISS)] = { 0x25, CNTR_ALL }, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, + [C(RESULT_MISS)] = { UNSUPPORTED_PERF_EVENT_ID }, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, + [C(RESULT_MISS)] = { UNSUPPORTED_PERF_EVENT_ID }, + }, +}, +}; + #ifdef CONFIG_MIPS_MT_SMP static void check_and_calc_range(struct perf_event *event, const struct mips_perf_event *pev) @@ -1444,6 +1548,20 @@ static const struct mips_perf_event *octeon_pmu_map_raw_event(u64 config) return &raw_event; } +static const struct mips_perf_event *xlp_pmu_map_raw_event(u64 config) +{ + unsigned int raw_id = config & 0xff; + + /* Only 1-63 are defined */ + if ((raw_id < 0x01) || (raw_id > 0x3f)) + return ERR_PTR(-EOPNOTSUPP); + + raw_event.cntr_mask = CNTR_ALL; + raw_event.event_id = raw_id; + + return &raw_event; +} + static int __init init_hw_perf_events(void) { @@ -1522,6 +1640,12 @@ init_hw_perf_events(void) mipspmu.general_event_map = &bmips5000_event_map; mipspmu.cache_event_map = &bmips5000_cache_map; break; + case CPU_XLP: + mipspmu.name = "xlp"; + mipspmu.general_event_map = &xlp_event_map; + mipspmu.cache_event_map = &xlp_cache_map; + mipspmu.map_raw_event = xlp_pmu_map_raw_event; + break; default: pr_cont("Either hardware does not support performance " "counters, or not yet implemented.\n"); -- cgit v1.2.3-18-g5258 From 088b530a07ad64b25cc28ad84d879af0859f9bf5 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 16 Oct 2012 22:20:25 +0200 Subject: MIPS: N32: Remove unused defines. Signed-off-by: Ralf Baechle --- arch/mips/kernel/scall64-n32.S | 6 ------ 1 file changed, 6 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index f6ba8381ee0..9c721dd84ba 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -17,12 +17,6 @@ #include #include -/* This duplicates the definition from */ -#define PT_TRACESYS 0x00000002 /* tracing system calls */ - -/* This duplicates the definition from */ -#define SIGILL 4 /* Illegal instruction (ANSI). */ - #ifndef CONFIG_MIPS32_O32 /* No O32, so define handle_sys here */ #define handle_sysn32 handle_sys -- cgit v1.2.3-18-g5258 From 970d032fec3f9687446595ee2569fb70b858a69f Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 18 Oct 2012 13:54:15 +0200 Subject: MIPS: Transparent Huge Pages support Signed-off-by: Ralf Baechle --- arch/mips/kernel/mips_ksyms.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c index 3fc1691110d..1ba8933683a 100644 --- a/arch/mips/kernel/mips_ksyms.c +++ b/arch/mips/kernel/mips_ksyms.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include -- cgit v1.2.3-18-g5258 From 90c9e79f5dc5af4ea16ad56dda8b648d21037486 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 2 Nov 2012 15:38:34 +0100 Subject: MIPS: Remove leftovers from the IRIX binary compat code. 2957c9e61ee9c37e7ebf2c8acab03e073fe942fd (kernel.org) rsp. b934da913f236bca00c41d9e386e980586000461 (lmo) [[MIPS] IRIX: Goodbye and thanks for all the fish] left two fields in struct thread_struct which were only being used for the IRIX compat code. Remove them. Signed-off-by: Ralf Baechle --- arch/mips/kernel/asm-offsets.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c index 0c4bce4882a..9690998d4ef 100644 --- a/arch/mips/kernel/asm-offsets.c +++ b/arch/mips/kernel/asm-offsets.c @@ -125,10 +125,6 @@ void output_thread_defines(void) thread.cp0_baduaddr); OFFSET(THREAD_ECODE, task_struct, \ thread.error_code); - OFFSET(THREAD_TRAMP, task_struct, \ - thread.irix_trampoline); - OFFSET(THREAD_OLDCTX, task_struct, \ - thread.irix_oldctx); BLANK(); } -- cgit v1.2.3-18-g5258 From 9ec9b5ac239ebfff333c25c4a7d34649cb29e4e4 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 6 Nov 2012 14:27:19 +0100 Subject: MIPS: Fix harmlessly missing else statement. The actual bug is a missing else statement - but really this should be expressed using a switch() statement. Found by Al Viro who writes "the funny thing is, it *does* work only because r2 is syscall number and syscall number around 512 => return value being ENOSYS and not one of ERESTART... so we really can't hit the first if and emerge from it with ERESTART_RESTARTBLOCK. still wrong to write it that way..." Signed-off-by: Ralf Baechle --- arch/mips/kernel/signal.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 0e1a5b8ae81..b6aa7703501 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -568,17 +568,20 @@ static void do_signal(struct pt_regs *regs) } if (regs->regs[0]) { - if (regs->regs[2] == ERESTARTNOHAND || - regs->regs[2] == ERESTARTSYS || - regs->regs[2] == ERESTARTNOINTR) { + switch (regs->regs[2]) { + case ERESTARTNOHAND: + case ERESTARTSYS: + case ERESTARTNOINTR: regs->regs[2] = regs->regs[0]; regs->regs[7] = regs->regs[26]; regs->cp0_epc -= 4; - } - if (regs->regs[2] == ERESTART_RESTARTBLOCK) { + break; + + case ERESTART_RESTARTBLOCK: regs->regs[2] = current->thread.abi->restart; regs->regs[7] = regs->regs[26]; regs->cp0_epc -= 4; + break; } regs->regs[0] = 0; /* Don't deal with this again. */ } -- cgit v1.2.3-18-g5258 From 7aa1c8f47e7e792d11f898cbdddaf6fa21ff08cc Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 11 Oct 2012 18:14:58 +0200 Subject: MIPS: kdump: Add support [ralf@linux-mips.org: Original patch by Maxim Uvarov with plenty of further shining, polishing, debugging and testing by me.] Signed-off-by: Maxim Uvarov Cc: linux-mips@linux-mips.org Cc: kexec@lists.infradead.org Cc: horms@verge.net.au Patchwork: https://patchwork.linux-mips.org/patch/1025/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/Makefile | 3 +- arch/mips/kernel/crash.c | 71 ++++++++++++++++++++++++++++++ arch/mips/kernel/crash_dump.c | 77 +++++++++++++++++++++++++++++++++ arch/mips/kernel/machine_kexec.c | 33 ++++++++++++-- arch/mips/kernel/relocate_kernel.S | 88 +++++++++++++++++++++++++++++++++++++- arch/mips/kernel/setup.c | 56 ++++++++++++++++++++++++ arch/mips/kernel/smp.c | 17 ++++++++ arch/mips/kernel/traps.c | 4 ++ 8 files changed, 343 insertions(+), 6 deletions(-) create mode 100644 arch/mips/kernel/crash.c create mode 100644 arch/mips/kernel/crash_dump.c (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 8b28bc4e14e..764597b5fb5 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -80,7 +80,8 @@ obj-$(CONFIG_I8253) += i8253.o obj-$(CONFIG_GPIO_TXX9) += gpio_txx9.o -obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o +obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o +obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_SPINLOCK_TEST) += spinlock_test.o obj-$(CONFIG_MIPS_MACHINE) += mips_machine.o diff --git a/arch/mips/kernel/crash.c b/arch/mips/kernel/crash.c new file mode 100644 index 00000000000..0f53c39324b --- /dev/null +++ b/arch/mips/kernel/crash.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* This keeps a track of which one is crashing cpu. */ +static int crashing_cpu = -1; +static cpumask_t cpus_in_crash = CPU_MASK_NONE; + +#ifdef CONFIG_SMP +static void crash_shutdown_secondary(void *ignore) +{ + struct pt_regs *regs; + int cpu = smp_processor_id(); + + regs = task_pt_regs(current); + + if (!cpu_online(cpu)) + return; + + local_irq_disable(); + if (!cpu_isset(cpu, cpus_in_crash)) + crash_save_cpu(regs, cpu); + cpu_set(cpu, cpus_in_crash); + + while (!atomic_read(&kexec_ready_to_reboot)) + cpu_relax(); + relocated_kexec_smp_wait(NULL); + /* NOTREACHED */ +} + +static void crash_kexec_prepare_cpus(void) +{ + unsigned int msecs; + + unsigned int ncpus = num_online_cpus() - 1;/* Excluding the panic cpu */ + + dump_send_ipi(crash_shutdown_secondary); + smp_wmb(); + + /* + * The crash CPU sends an IPI and wait for other CPUs to + * respond. Delay of at least 10 seconds. + */ + pr_emerg("Sending IPI to other cpus...\n"); + msecs = 10000; + while ((cpus_weight(cpus_in_crash) < ncpus) && (--msecs > 0)) { + cpu_relax(); + mdelay(1); + } +} + +#else /* !defined(CONFIG_SMP) */ +static void crash_kexec_prepare_cpus(void) {} +#endif /* !defined(CONFIG_SMP) */ + +void default_machine_crash_shutdown(struct pt_regs *regs) +{ + local_irq_disable(); + crashing_cpu = smp_processor_id(); + crash_save_cpu(regs, crashing_cpu); + crash_kexec_prepare_cpus(); + cpu_set(crashing_cpu, cpus_in_crash); +} diff --git a/arch/mips/kernel/crash_dump.c b/arch/mips/kernel/crash_dump.c new file mode 100644 index 00000000000..d9ec3898f9f --- /dev/null +++ b/arch/mips/kernel/crash_dump.c @@ -0,0 +1,77 @@ +#include +#include +#include +#include + +unsigned long long elfcorehdr_addr = ELFCORE_ADDR_MAX; + +static int __init parse_savemaxmem(char *p) +{ + if (p) + saved_max_pfn = (memparse(p, &p) >> PAGE_SHIFT) - 1; + + return 1; +} +__setup("savemaxmem=", parse_savemaxmem); + + +static void *kdump_buf_page; + +/** + * copy_oldmem_page - copy one page from "oldmem" + * @pfn: page frame number to be copied + * @buf: target memory address for the copy; this can be in kernel address + * space or user address space (see @userbuf) + * @csize: number of bytes to copy + * @offset: offset in bytes into the page (based on pfn) to begin the copy + * @userbuf: if set, @buf is in user address space, use copy_to_user(), + * otherwise @buf is in kernel address space, use memcpy(). + * + * Copy a page from "oldmem". For this page, there is no pte mapped + * in the current kernel. + * + * Calling copy_to_user() in atomic context is not desirable. Hence first + * copying the data to a pre-allocated kernel page and then copying to user + * space in non-atomic context. + */ +ssize_t copy_oldmem_page(unsigned long pfn, char *buf, + size_t csize, unsigned long offset, int userbuf) +{ + void *vaddr; + + if (!csize) + return 0; + + vaddr = kmap_atomic_pfn(pfn); + + if (!userbuf) { + memcpy(buf, (vaddr + offset), csize); + kunmap_atomic(vaddr); + } else { + if (!kdump_buf_page) { + pr_warning("Kdump: Kdump buffer page not allocated\n"); + + return -EFAULT; + } + copy_page(kdump_buf_page, vaddr); + kunmap_atomic(vaddr); + if (copy_to_user(buf, (kdump_buf_page + offset), csize)) + return -EFAULT; + } + + return csize; +} + +static int __init kdump_buf_page_init(void) +{ + int ret = 0; + + kdump_buf_page = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!kdump_buf_page) { + pr_warning("Kdump: Failed to allocate kdump buffer page\n"); + ret = -ENOMEM; + } + + return ret; +} +arch_initcall(kdump_buf_page_init); diff --git a/arch/mips/kernel/machine_kexec.c b/arch/mips/kernel/machine_kexec.c index 85beb9b0b2d..992e18474da 100644 --- a/arch/mips/kernel/machine_kexec.c +++ b/arch/mips/kernel/machine_kexec.c @@ -5,7 +5,7 @@ * This source code is licensed under the GNU General Public License, * Version 2. See the file COPYING for more details. */ - +#include #include #include #include @@ -19,9 +19,19 @@ extern const size_t relocate_new_kernel_size; extern unsigned long kexec_start_address; extern unsigned long kexec_indirection_page; +int (*_machine_kexec_prepare)(struct kimage *) = NULL; +void (*_machine_kexec_shutdown)(void) = NULL; +void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL; +#ifdef CONFIG_SMP +void (*relocated_kexec_smp_wait) (void *); +atomic_t kexec_ready_to_reboot = ATOMIC_INIT(0); +#endif + int machine_kexec_prepare(struct kimage *kimage) { + if (_machine_kexec_prepare) + return _machine_kexec_prepare(kimage); return 0; } @@ -33,14 +43,20 @@ machine_kexec_cleanup(struct kimage *kimage) void machine_shutdown(void) { + if (_machine_kexec_shutdown) + _machine_kexec_shutdown(); } void machine_crash_shutdown(struct pt_regs *regs) { + if (_machine_crash_shutdown) + _machine_crash_shutdown(regs); + else + default_machine_crash_shutdown(regs); } -typedef void (*noretfun_t)(void) __attribute__((noreturn)); +typedef void (*noretfun_t)(void) __noreturn; void machine_kexec(struct kimage *image) @@ -52,7 +68,9 @@ machine_kexec(struct kimage *image) reboot_code_buffer = (unsigned long)page_address(image->control_code_page); - kexec_start_address = image->start; + kexec_start_address = + (unsigned long) phys_to_virt(image->start); + kexec_indirection_page = (unsigned long) phys_to_virt(image->head & PAGE_MASK); @@ -63,7 +81,7 @@ machine_kexec(struct kimage *image) * The generic kexec code builds a page list with physical * addresses. they are directly accessible through KSEG0 (or * CKSEG0 or XPHYS if on 64bit system), hence the - * pys_to_virt() call. + * phys_to_virt() call. */ for (ptr = &image->head; (entry = *ptr) && !(entry &IND_DONE); ptr = (entry & IND_INDIRECTION) ? @@ -81,5 +99,12 @@ machine_kexec(struct kimage *image) printk("Will call new kernel at %08lx\n", image->start); printk("Bye ...\n"); __flush_cache_all(); +#ifdef CONFIG_SMP + /* All secondary cpus now may jump to kexec_wait cycle */ + relocated_kexec_smp_wait = reboot_code_buffer + + (void *)(kexec_smp_wait - relocate_new_kernel); + smp_wmb(); + atomic_set(&kexec_ready_to_reboot, 1); +#endif ((noretfun_t) reboot_code_buffer)(); } diff --git a/arch/mips/kernel/relocate_kernel.S b/arch/mips/kernel/relocate_kernel.S index 87481f916a6..0b108587f06 100644 --- a/arch/mips/kernel/relocate_kernel.S +++ b/arch/mips/kernel/relocate_kernel.S @@ -15,6 +15,11 @@ #include LEAF(relocate_new_kernel) + PTR_L a0, arg0 + PTR_L a1, arg1 + PTR_L a2, arg2 + PTR_L a3, arg3 + PTR_L s0, kexec_indirection_page PTR_L s1, kexec_start_address @@ -26,7 +31,6 @@ process_entry: and s3, s2, 0x1 beq s3, zero, 1f and s4, s2, ~0x1 /* store destination addr in s4 */ - move a0, s4 b process_entry 1: @@ -60,10 +64,92 @@ copy_word: b process_entry done: +#ifdef CONFIG_SMP + /* kexec_flag reset is signal to other CPUs what kernel + was moved to it's location. Note - we need relocated address + of kexec_flag. */ + + bal 1f + 1: move t1,ra; + PTR_LA t2,1b + PTR_LA t0,kexec_flag + PTR_SUB t0,t0,t2; + PTR_ADD t0,t1,t0; + LONG_S zero,(t0) +#endif + + sync /* jump to kexec_start_address */ j s1 END(relocate_new_kernel) +#ifdef CONFIG_SMP +/* + * Other CPUs should wait until code is relocated and + * then start at entry (?) point. + */ +LEAF(kexec_smp_wait) + PTR_L a0, s_arg0 + PTR_L a1, s_arg1 + PTR_L a2, s_arg2 + PTR_L a3, s_arg3 + PTR_L s1, kexec_start_address + + /* Non-relocated address works for args and kexec_start_address ( old + * kernel is not overwritten). But we need relocated address of + * kexec_flag. + */ + + bal 1f +1: move t1,ra; + PTR_LA t2,1b + PTR_LA t0,kexec_flag + PTR_SUB t0,t0,t2; + PTR_ADD t0,t1,t0; + +1: LONG_L s0, (t0) + bne s0, zero,1b + + sync + j s1 + END(kexec_smp_wait) +#endif + +#ifdef __mips64 + /* all PTR's must be aligned to 8 byte in 64-bit mode */ + .align 3 +#endif + +/* All parameters to new kernel are passed in registers a0-a3. + * kexec_args[0..3] are uses to prepare register values. + */ + +kexec_args: + EXPORT(kexec_args) +arg0: PTR 0x0 +arg1: PTR 0x0 +arg2: PTR 0x0 +arg3: PTR 0x0 + .size kexec_args,PTRSIZE*4 + +#ifdef CONFIG_SMP +/* + * Secondary CPUs may have different kernel parameters in + * their registers a0-a3. secondary_kexec_args[0..3] are used + * to prepare register values. + */ +secondary_kexec_args: + EXPORT(secondary_kexec_args) +s_arg0: PTR 0x0 +s_arg1: PTR 0x0 +s_arg2: PTR 0x0 +s_arg3: PTR 0x0 + .size secondary_kexec_args,PTRSIZE*4 +kexec_flag: + LONG 0x1 + +#endif + kexec_start_address: EXPORT(kexec_start_address) PTR 0x0 diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 290dc6a1d7a..8c41187801c 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -536,12 +537,64 @@ static void __init arch_mem_init(char **cmdline_p) } bootmem_init(); +#ifdef CONFIG_KEXEC + if (crashk_res.start != crashk_res.end) + reserve_bootmem(crashk_res.start, + crashk_res.end - crashk_res.start + 1, + BOOTMEM_DEFAULT); +#endif device_tree_init(); sparse_init(); plat_swiotlb_setup(); paging_init(); } +#ifdef CONFIG_KEXEC +static inline unsigned long long get_total_mem(void) +{ + unsigned long long total; + + total = max_pfn - min_low_pfn; + return total << PAGE_SHIFT; +} + +static void __init mips_parse_crashkernel(void) +{ + unsigned long long total_mem; + unsigned long long crash_size, crash_base; + int ret; + + total_mem = get_total_mem(); + ret = parse_crashkernel(boot_command_line, total_mem, + &crash_size, &crash_base); + if (ret != 0 || crash_size <= 0) + return; + + crashk_res.start = crash_base; + crashk_res.end = crash_base + crash_size - 1; +} + +static void __init request_crashkernel(struct resource *res) +{ + int ret; + + ret = request_resource(res, &crashk_res); + if (!ret) + pr_info("Reserving %ldMB of memory at %ldMB for crashkernel\n", + (unsigned long)((crashk_res.end - + crashk_res.start + 1) >> 20), + (unsigned long)(crashk_res.start >> 20)); +} +#else /* !defined(CONFIG_KEXEC) */ +static void __init mips_parse_crashkernel(void) +{ +} + +static void __init request_crashkernel(struct resource *res) +{ +} +#endif /* !defined(CONFIG_KEXEC) */ + static void __init resource_init(void) { int i; @@ -557,6 +610,8 @@ static void __init resource_init(void) /* * Request address space for all standard RAM. */ + mips_parse_crashkernel(); + for (i = 0; i < boot_mem_map.nr_map; i++) { struct resource *res; unsigned long start, end; @@ -593,6 +648,7 @@ static void __init resource_init(void) */ request_resource(res, &code_resource); request_resource(res, &data_resource); + request_crashkernel(res); } } diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 9005bf9fb85..2e6374a589e 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -386,3 +386,20 @@ void flush_tlb_one(unsigned long vaddr) EXPORT_SYMBOL(flush_tlb_page); EXPORT_SYMBOL(flush_tlb_one); + +#if defined(CONFIG_KEXEC) +void (*dump_ipi_function_ptr)(void *) = NULL; +void dump_send_ipi(void (*dump_ipi_callback)(void *)) +{ + int i; + int cpu = smp_processor_id(); + + dump_ipi_function_ptr = dump_ipi_callback; + smp_mb(); + for_each_online_cpu(i) + if (i != cpu) + mp_ops->send_ipi_single(i, SMP_DUMP); + +} +EXPORT_SYMBOL(dump_send_ipi); +#endif diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 9be3df1fa8a..da0c29422cf 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -13,6 +13,7 @@ */ #include #include +#include #include #include #include @@ -409,6 +410,9 @@ void __noreturn die(const char *str, struct pt_regs *regs) panic("Fatal exception"); } + if (regs && kexec_should_crash(current)) + crash_kexec(regs); + do_exit(sig); } -- cgit v1.2.3-18-g5258 From abe77f90dc9c65a7c9a4d61c2cbb8db4d5566e4f Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 25 Oct 2012 16:23:31 +0200 Subject: MIPS: Octeon: Add kexec and kdump support [ralf@linux-mips.org: Original patch by Maxim Uvarov with plenty of further shining, polishing, debugging and testing by me.] Signed-off-by: Maxim Uvarov Cc: linux-mips@linux-mips.org Cc: kexec@lists.infradead.org Cc: horms@verge.net.au Patchwork: https://patchwork.linux-mips.org/patch/1026/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/crash_dump.c | 2 -- arch/mips/kernel/relocate_kernel.S | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/crash_dump.c b/arch/mips/kernel/crash_dump.c index d9ec3898f9f..35bed0d2342 100644 --- a/arch/mips/kernel/crash_dump.c +++ b/arch/mips/kernel/crash_dump.c @@ -3,8 +3,6 @@ #include #include -unsigned long long elfcorehdr_addr = ELFCORE_ADDR_MAX; - static int __init parse_savemaxmem(char *p) { if (p) diff --git a/arch/mips/kernel/relocate_kernel.S b/arch/mips/kernel/relocate_kernel.S index 0b108587f06..e4142c5f7c2 100644 --- a/arch/mips/kernel/relocate_kernel.S +++ b/arch/mips/kernel/relocate_kernel.S @@ -78,7 +78,19 @@ done: LONG_S zero,(t0) #endif +#ifdef CONFIG_CPU_CAVIUM_OCTEON + /* We need to flush I-cache before jumping to new kernel. + * Unfortunatelly, this code is cpu-specific. + */ + .set push + .set noreorder + syncw + syncw + synci 0($0) + .set pop +#else sync +#endif /* jump to kexec_start_address */ j s1 END(relocate_new_kernel) @@ -110,7 +122,14 @@ LEAF(kexec_smp_wait) 1: LONG_L s0, (t0) bne s0, zero,1b +#ifdef CONFIG_CPU_CAVIUM_OCTEON + .set push + .set noreorder + synci 0($0) + .set pop +#else sync +#endif j s1 END(kexec_smp_wait) #endif -- cgit v1.2.3-18-g5258 From d7ea335c05ba7c013615d1e0d5a71459eb4195e8 Mon Sep 17 00:00:00 2001 From: "Steven J. Hill" Date: Wed, 14 Nov 2012 23:34:17 -0600 Subject: MIPS: Remove usage of CSRC_R4K_LIB config option. Manuel Lauss writes: I introduced it as a fallback because early revisions of Alchemy hardware we shipped had a non-functional 32kHz timer and had to rely on the r4k timer instead. Previously the r4k timer was initialized regardless, but it's useless with the "wait" instruction. So long story short: I need either the on-chip 32kHz timer OR the r4k timer if the 32kHz one is unusable, but not both, and r4k timer is useless when au1k_idle is in use. The current in-kernel Alchemy boards all work with the 32kHz timer, so I'm not against removing R4K_LIB symbols. Signed-off-by: Steven J. Hill Signed-off-by: Ralf Baechle --- arch/mips/kernel/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 764597b5fb5..d9abe17b355 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -25,7 +25,7 @@ obj-$(CONFIG_CEVT_TXX9) += cevt-txx9.o obj-$(CONFIG_CSRC_BCM1480) += csrc-bcm1480.o obj-$(CONFIG_CSRC_IOASIC) += csrc-ioasic.o obj-$(CONFIG_CSRC_POWERTV) += csrc-powertv.o -obj-$(CONFIG_CSRC_R4K_LIB) += csrc-r4k.o +obj-$(CONFIG_CSRC_R4K) += csrc-r4k.o obj-$(CONFIG_CSRC_SB1250) += csrc-sb1250.o obj-$(CONFIG_SYNC_R4K) += sync-r4k.o -- cgit v1.2.3-18-g5258 From f772cdb2bd544eeb3e83a8bb42629d155c1b53fd Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 30 Nov 2012 17:27:27 +0100 Subject: MIPS: Remove usage of CEVT_R4K_LIB config option. Manuel Lauss writes: I introduced it as a fallback because early revisions of Alchemy hardware we shipped had a non-functional 32kHz timer and had to rely on the r4k timer instead. Previously the r4k timer was initialized regardless, but it's useless with the "wait" instruction. So long story short: I need either the on-chip 32kHz timer OR the r4k timer if the 32kHz one is unusable, but not both, and r4k timer is useless when au1k_idle is in use. The current in-kernel Alchemy boards all work with the 32kHz timer, so I'm not against removing R4K_LIB symbols. Signed-off-by: Ralf Baechle --- arch/mips/kernel/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index d9abe17b355..540dff8c721 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -16,7 +16,7 @@ CFLAGS_REMOVE_perf_event_mipsxx.o = -pg endif obj-$(CONFIG_CEVT_BCM1480) += cevt-bcm1480.o -obj-$(CONFIG_CEVT_R4K_LIB) += cevt-r4k.o +obj-$(CONFIG_CEVT_R4K) += cevt-r4k.o obj-$(CONFIG_MIPS_MT_SMTC) += cevt-smtc.o obj-$(CONFIG_CEVT_DS1287) += cevt-ds1287.o obj-$(CONFIG_CEVT_GT641XX) += cevt-gt641xx.o -- cgit v1.2.3-18-g5258 From b88fb18e7e0e17d517c5267de938c1a35a063a97 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 10 Dec 2012 15:56:44 +0100 Subject: MIPS: MT: Fix build with CONFIG_UIDGID_STRICT_TYPE_CHECKS=y When CONFIG_UIDGID_STRICT_TYPE_CHECKS is enabled, plain integer checking between different uids/gids is explicitely turned into a build failure by making the k{uid,gid}_t types a structure containing a value: arch/mips/kernel/mips-mt-fpaff.c: In function 'check_same_owner': arch/mips/kernel/mips-mt-fpaff.c:53:22: error: invalid operands to binary == (have 'kuid_t' and 'kuid_t') arch/mips/kernel/mips-mt-fpaff.c:54:15: error: invalid operands to binary == (have 'kuid_t' and 'kuid_t') In order to ensure proper comparison between uids, using the helper function uid_eq() which performs the right thing whenever this config option is turned on or off. Signed-off-by: Florian Fainelli Patchwork: https://patchwork.linux-mips.org/patch/4717/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/mips-mt-fpaff.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/mips-mt-fpaff.c b/arch/mips/kernel/mips-mt-fpaff.c index 33f63bab478..fd814e08c94 100644 --- a/arch/mips/kernel/mips-mt-fpaff.c +++ b/arch/mips/kernel/mips-mt-fpaff.c @@ -50,8 +50,8 @@ static bool check_same_owner(struct task_struct *p) rcu_read_lock(); pcred = __task_cred(p); - match = (cred->euid == pcred->euid || - cred->euid == pcred->uid); + match = (uid_eq(cred->euid, pcred->euid) || + uid_eq(cred->euid, pcred->uid)); rcu_read_unlock(); return match; } -- cgit v1.2.3-18-g5258 From 8add1ecb81f541ef2fcb0b85a5470ad9ecfb4a84 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Mon, 13 Aug 2012 20:52:24 +0800 Subject: MIPS: Fix poweroff failure when HOTPLUG_CPU configured. When poweroff machine, kernel_power_off() call disable_nonboot_cpus(). And if we have HOTPLUG_CPU configured, disable_nonboot_cpus() is not an empty function but attempt to actually disable the nonboot cpus. Since system state is SYSTEM_POWER_OFF, play_dead() won't be called and thus disable_nonboot_cpus() hangs. Therefore, we make this patch to avoid poweroff failure. Signed-off-by: Huacai Chen Signed-off-by: Hongliang Tao Signed-off-by: Hua Yan Cc: Yong Zhang Cc: stable@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: Fuxin Zhang Cc: Zhangjin Wu Patchwork: https://patchwork.linux-mips.org/patch/4211/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/process.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index e9a5fd7277f..69b17a92004 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -72,9 +72,7 @@ void __noreturn cpu_idle(void) } } #ifdef CONFIG_HOTPLUG_CPU - if (!cpu_online(cpu) && !cpu_isset(cpu, cpu_callin_map) && - (system_state == SYSTEM_RUNNING || - system_state == SYSTEM_BOOTING)) + if (!cpu_online(cpu) && !cpu_isset(cpu, cpu_callin_map)) play_dead(); #endif rcu_idle_exit(); -- cgit v1.2.3-18-g5258 From 051ff44a8b508f8e8e342db3220d5ad8296c19ce Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Tue, 6 Mar 2012 20:28:54 +0000 Subject: MIPS: Handle COP3 Unusable exception as COP1X for FP emulation Our FP emulator is hardcoded for the MIPS IV FP instruction set and does not match the FP ISA with the general ISA. However for the few MIPS IV FP instructions that use the COP1X major opcode it relies on the Coprocessor Unusable exception to be delivered as a COP1 rather than COP3 exception. This includes indexed transfer (LDXC1, etc.) and FP multiply-accumulate (MADD.D, etc.) instructions. All the MIPS I, II, III and IV processors and some newer chips that do not implement the FPU use the COP3 exception however. Therefore I believe the kernel should follow and redirect any COP3 Unusable traps to the emulator unless an actual FPU part or core is present. This is a change that implements it. Any minor opcode encodings that are not recognised as valid FP instructions are rejected by the emulator and will result in a SIGILL signal being delivered as they currently do. We do not support vendor-specific coprocessor 3 implementations supported with MIPS I and MIPS II ISA processors; we never set CP0.Status.CU3. [Ralf: On MIPS IV processors the kernel always enables the XX bit which replaces the CU3 bit off earlier architecture revisions.] If matching between the CPU and the FPU ISA is considered required one day, this can still be done in the emulator itself. I think the CpU exception dispatcher is not the right place to do this anyway, as there are further differences between MIPS I, MIPS II, MIPS III, MIPS IV and MIPS32 FP ISAs. Corresponding explanation of this implementation is included within the change itself. Signed-off-by: Maciej W. Rozycki Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/project/linux-mips/list/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index da0c29422cf..cf7ac5483f5 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -1025,6 +1025,24 @@ asmlinkage void do_cpu(struct pt_regs *regs) return; + case 3: + /* + * Old (MIPS I and MIPS II) processors will set this code + * for COP1X opcode instructions that replaced the original + * COP3 space. We don't limit COP1 space instructions in + * the emulator according to the CPU ISA, so we want to + * treat COP1X instructions consistently regardless of which + * code the CPU chose. Therefore we redirect this trap to + * the FP emulator too. + * + * Then some newer FPU-less processors use this code + * erroneously too, so they are covered by this choice + * as well. + */ + if (raw_cpu_has_fpu) + break; + /* Fall through. */ + case 1: if (used_math()) /* Using the FPU again. */ own_fpu(1); @@ -1048,9 +1066,6 @@ asmlinkage void do_cpu(struct pt_regs *regs) case 2: raw_notifier_call_chain(&cu2_chain, CU2_EXCEPTION, regs); return; - - case 3: - break; } force_sig(SIGILL, current); -- cgit v1.2.3-18-g5258 From bdf20507da11a9a5b32ef04fa09f352828189aef Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 11 Dec 2012 21:02:55 +0100 Subject: MIPS: PMC-Sierra Yosemite: Remove support. Nobody seems to be interested anymore and upstream also never had an ethernet driver. Signed-off-by: Ralf Baechle --- arch/mips/kernel/Makefile | 1 - arch/mips/kernel/irq-rm9000.c | 106 ------------------------------------------ 2 files changed, 107 deletions(-) delete mode 100644 arch/mips/kernel/irq-rm9000.c (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 540dff8c721..007c33d7371 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -58,7 +58,6 @@ obj-$(CONFIG_MIPS_VPE_APSP_API) += rtlx.o obj-$(CONFIG_I8259) += i8259.o obj-$(CONFIG_IRQ_CPU) += irq_cpu.o obj-$(CONFIG_IRQ_CPU_RM7K) += irq-rm7000.o -obj-$(CONFIG_IRQ_CPU_RM9K) += irq-rm9000.o obj-$(CONFIG_MIPS_MSC) += irq-msc01.o obj-$(CONFIG_IRQ_TXX9) += irq_txx9.o obj-$(CONFIG_IRQ_GT641XX) += irq-gt641xx.o diff --git a/arch/mips/kernel/irq-rm9000.c b/arch/mips/kernel/irq-rm9000.c deleted file mode 100644 index 1282b9ae81c..00000000000 --- a/arch/mips/kernel/irq-rm9000.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2003 Ralf Baechle - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * Handler for RM9000 extended interrupts. These are a non-standard - * feature so we handle them separately from standard interrupts. - */ -#include -#include -#include -#include -#include - -#include -#include - -static inline void unmask_rm9k_irq(struct irq_data *d) -{ - set_c0_intcontrol(0x1000 << (d->irq - RM9K_CPU_IRQ_BASE)); -} - -static inline void mask_rm9k_irq(struct irq_data *d) -{ - clear_c0_intcontrol(0x1000 << (d->irq - RM9K_CPU_IRQ_BASE)); -} - -static inline void rm9k_cpu_irq_enable(struct irq_data *d) -{ - unsigned long flags; - - local_irq_save(flags); - unmask_rm9k_irq(d); - local_irq_restore(flags); -} - -/* - * Performance counter interrupts are global on all processors. - */ -static void local_rm9k_perfcounter_irq_startup(void *args) -{ - rm9k_cpu_irq_enable(args); -} - -static unsigned int rm9k_perfcounter_irq_startup(struct irq_data *d) -{ - on_each_cpu(local_rm9k_perfcounter_irq_startup, d, 1); - - return 0; -} - -static void local_rm9k_perfcounter_irq_shutdown(void *args) -{ - unsigned long flags; - - local_irq_save(flags); - mask_rm9k_irq(args); - local_irq_restore(flags); -} - -static void rm9k_perfcounter_irq_shutdown(struct irq_data *d) -{ - on_each_cpu(local_rm9k_perfcounter_irq_shutdown, d, 1); -} - -static struct irq_chip rm9k_irq_controller = { - .name = "RM9000", - .irq_ack = mask_rm9k_irq, - .irq_mask = mask_rm9k_irq, - .irq_mask_ack = mask_rm9k_irq, - .irq_unmask = unmask_rm9k_irq, - .irq_eoi = unmask_rm9k_irq -}; - -static struct irq_chip rm9k_perfcounter_irq = { - .name = "RM9000", - .irq_startup = rm9k_perfcounter_irq_startup, - .irq_shutdown = rm9k_perfcounter_irq_shutdown, - .irq_ack = mask_rm9k_irq, - .irq_mask = mask_rm9k_irq, - .irq_mask_ack = mask_rm9k_irq, - .irq_unmask = unmask_rm9k_irq, -}; - -unsigned int rm9000_perfcount_irq; - -EXPORT_SYMBOL(rm9000_perfcount_irq); - -void __init rm9k_cpu_irq_init(void) -{ - int base = RM9K_CPU_IRQ_BASE; - int i; - - clear_c0_intcontrol(0x0000f000); /* Mask all */ - - for (i = base; i < base + 4; i++) - irq_set_chip_and_handler(i, &rm9k_irq_controller, - handle_level_irq); - - rm9000_perfcount_irq = base + 1; - irq_set_chip_and_handler(rm9000_perfcount_irq, &rm9k_perfcounter_irq, - handle_percpu_irq); -} -- cgit v1.2.3-18-g5258