diff options
author | Linus Torvalds | 2019-03-05 11:28:25 -0800 |
---|---|---|
committer | Linus Torvalds | 2019-03-05 11:28:25 -0800 |
commit | d9862cfbe2099deb83f0e9c1932c91f2d9c50464 (patch) | |
tree | 7092ef41113269f30b5429868a9d161e171c746d /arch/mips/kernel | |
parent | 8feed3efa8022107bcb3432ac3ec9917e078ae70 (diff) | |
parent | aeb669d41ffabb91b1542f1f802cb12a989fced0 (diff) |
Merge tag 'mips_5.1' of git://git.kernel.org/pub/scm/linux/kernel/git/mips/linux
Pull MIPS updates from Paul Burton:
- Support for the MIPSr6 MemoryMapID register & Global INValidate TLB
(GINVT) instructions, allowing for more efficient TLB maintenance
when running on a CPU such as the I6500 that supports these.
- Enable huge page support for MIPS64r6.
- Optimize post-DMA cache sync by removing that code entirely for
kernel configurations in which we know it won't be needed.
- The number of pages allocated for interrupt stacks is now calculated
correctly, where before we would wastefully allocate too much memory
in some configurations.
- The ath79 platform migrates to devicetree.
- The bcm47xx platform sees fixes for the Buffalo WHR-G54S board.
- The ingenic/jz4740 platform gains support for appended devicetrees.
- The cavium_octeon, lantiq, loongson32 & sgi-ip27 platforms all see
cleanups as do various pieces of core architecture code.
* tag 'mips_5.1' of git://git.kernel.org/pub/scm/linux/kernel/git/mips/linux: (66 commits)
MIPS: lantiq: Remove separate GPHY Firmware loader
MIPS: ingenic: Add support for appended devicetree
MIPS: SGI-IP27: rework HUB interrupts
MIPS: SGI-IP27: do boot CPU init later
MIPS: SGI-IP27: do xtalk scanning later
MIPS: SGI-IP27: use pr_info/pr_emerg and pr_cont to fix output
MIPS: SGI-IP27: clean up bridge access and header files
MIPS: SGI-IP27: get rid of volatile and hubreg_t
MIPS: irq: Allocate accurate order pages for irq stack
MIPS: dma-noncoherent: Remove bogus condition in dma_sync_phys()
MIPS: eBPF: Remove REG_32BIT_ZERO_EX
MIPS: eBPF: Always return sign extended 32b values
MIPS: CM: Fix indentation
MIPS: BCM47XX: Fix/improve Buffalo WHR-G54S support
MIPS: OCTEON: program rx/tx-delay always from DT
MIPS: OCTEON: delete board-specific link status
MIPS: OCTEON: don't lie about interface type of CN3005 board
MIPS: OCTEON: warn if deprecated link status is being used
MIPS: OCTEON: add fixed-link nodes to in-kernel device tree
MIPS: Delete unused flush_cache_sigtramp()
...
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r-- | arch/mips/kernel/cpu-probe.c | 55 | ||||
-rw-r--r-- | arch/mips/kernel/irq.c | 4 | ||||
-rw-r--r-- | arch/mips/kernel/mips-cm.c | 4 | ||||
-rw-r--r-- | arch/mips/kernel/mips-r2-to-r6-emul.c | 21 | ||||
-rw-r--r-- | arch/mips/kernel/segment.c | 15 | ||||
-rw-r--r-- | arch/mips/kernel/setup.c | 7 | ||||
-rw-r--r-- | arch/mips/kernel/smp.c | 69 | ||||
-rw-r--r-- | arch/mips/kernel/spinlock_test.c | 21 | ||||
-rw-r--r-- | arch/mips/kernel/traps.c | 4 | ||||
-rw-r--r-- | arch/mips/kernel/unaligned.c | 17 |
10 files changed, 137 insertions, 80 deletions
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 95b18a194f53..d5e335e6846a 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -872,10 +872,19 @@ static inline unsigned int decode_config4(struct cpuinfo_mips *c) static inline unsigned int decode_config5(struct cpuinfo_mips *c) { - unsigned int config5; + unsigned int config5, max_mmid_width; + unsigned long asid_mask; config5 = read_c0_config5(); config5 &= ~(MIPS_CONF5_UFR | MIPS_CONF5_UFE); + + if (cpu_has_mips_r6) { + if (!__builtin_constant_p(cpu_has_mmid) || cpu_has_mmid) + config5 |= MIPS_CONF5_MI; + else + config5 &= ~MIPS_CONF5_MI; + } + write_c0_config5(config5); if (config5 & MIPS_CONF5_EVA) @@ -894,6 +903,50 @@ static inline unsigned int decode_config5(struct cpuinfo_mips *c) if (config5 & MIPS_CONF5_CRCP) elf_hwcap |= HWCAP_MIPS_CRC32; + if (cpu_has_mips_r6) { + /* Ensure the write to config5 above takes effect */ + back_to_back_c0_hazard(); + + /* Check whether we successfully enabled MMID support */ + config5 = read_c0_config5(); + if (config5 & MIPS_CONF5_MI) + c->options |= MIPS_CPU_MMID; + + /* + * Warn if we've hardcoded cpu_has_mmid to a value unsuitable + * for the CPU we're running on, or if CPUs in an SMP system + * have inconsistent MMID support. + */ + WARN_ON(!!cpu_has_mmid != !!(config5 & MIPS_CONF5_MI)); + + if (cpu_has_mmid) { + write_c0_memorymapid(~0ul); + back_to_back_c0_hazard(); + asid_mask = read_c0_memorymapid(); + + /* + * We maintain a bitmap to track MMID allocation, and + * need a sensible upper bound on the size of that + * bitmap. The initial CPU with MMID support (I6500) + * supports 16 bit MMIDs, which gives us an 8KiB + * bitmap. The architecture recommends that hardware + * support 32 bit MMIDs, which would give us a 512MiB + * bitmap - that's too big in most cases. + * + * Cap MMID width at 16 bits for now & we can revisit + * this if & when hardware supports anything wider. + */ + max_mmid_width = 16; + if (asid_mask > GENMASK(max_mmid_width - 1, 0)) { + pr_info("Capping MMID width at %d bits", + max_mmid_width); + asid_mask = GENMASK(max_mmid_width - 1, 0); + } + + set_cpu_asid_mask(c, asid_mask); + } + } + return config5 & MIPS_CONF_M; } diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c index ba150c755fcc..85b6c60f285d 100644 --- a/arch/mips/kernel/irq.c +++ b/arch/mips/kernel/irq.c @@ -52,6 +52,7 @@ asmlinkage void spurious_interrupt(void) void __init init_IRQ(void) { int i; + unsigned int order = get_order(IRQ_STACK_SIZE); for (i = 0; i < NR_IRQS; i++) irq_set_noprobe(i); @@ -62,8 +63,7 @@ void __init init_IRQ(void) arch_init_irq(); for_each_possible_cpu(i) { - int irq_pages = IRQ_STACK_SIZE / PAGE_SIZE; - void *s = (void *)__get_free_pages(GFP_KERNEL, irq_pages); + void *s = (void *)__get_free_pages(GFP_KERNEL, order); irq_stack[i] = s; pr_debug("CPU%d IRQ stack at 0x%p - 0x%p\n", i, diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c index 7f3f136572de..537e8d091874 100644 --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c @@ -382,8 +382,8 @@ void mips_cm_error_report(void) sc_bit ? "True" : "False", cm2_cmd[cmd_bits], sport_bits); } - pr_err("CM_ERROR=%08llx %s <%s>\n", cm_error, - cm2_causes[cause], buf); + pr_err("CM_ERROR=%08llx %s <%s>\n", cm_error, + cm2_causes[cause], buf); pr_err("CM_ADDR =%08llx\n", cm_addr); pr_err("CM_OTHER=%08llx %s\n", cm_other, cm2_causes[ocause]); } else { /* CM3 */ diff --git a/arch/mips/kernel/mips-r2-to-r6-emul.c b/arch/mips/kernel/mips-r2-to-r6-emul.c index c50c89a978f1..b4d210bfcdae 100644 --- a/arch/mips/kernel/mips-r2-to-r6-emul.c +++ b/arch/mips/kernel/mips-r2-to-r6-emul.c @@ -2351,23 +2351,10 @@ DEFINE_SHOW_ATTRIBUTE(mipsr2_clear); static int __init mipsr2_init_debugfs(void) { - struct dentry *mipsr2_emul; - - if (!mips_debugfs_dir) - return -ENODEV; - - mipsr2_emul = debugfs_create_file("r2_emul_stats", S_IRUGO, - mips_debugfs_dir, NULL, - &mipsr2_emul_fops); - if (!mipsr2_emul) - return -ENOMEM; - - mipsr2_emul = debugfs_create_file("r2_emul_stats_clear", S_IRUGO, - mips_debugfs_dir, NULL, - &mipsr2_clear_fops); - if (!mipsr2_emul) - return -ENOMEM; - + debugfs_create_file("r2_emul_stats", S_IRUGO, mips_debugfs_dir, NULL, + &mipsr2_emul_fops); + debugfs_create_file("r2_emul_stats_clear", S_IRUGO, mips_debugfs_dir, + NULL, &mipsr2_clear_fops); return 0; } diff --git a/arch/mips/kernel/segment.c b/arch/mips/kernel/segment.c index 2703f218202e..0a9bd7b0983b 100644 --- a/arch/mips/kernel/segment.c +++ b/arch/mips/kernel/segment.c @@ -95,18 +95,9 @@ static const struct file_operations segments_fops = { static int __init segments_info(void) { - struct dentry *segments; - - if (cpu_has_segments) { - if (!mips_debugfs_dir) - return -ENODEV; - - segments = debugfs_create_file("segments", S_IRUGO, - mips_debugfs_dir, NULL, - &segments_fops); - if (!segments) - return -ENOMEM; - } + if (cpu_has_segments) + debugfs_create_file("segments", S_IRUGO, mips_debugfs_dir, NULL, + &segments_fops); return 0; } diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index d2e5a5ad0e6f..5151532ad959 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -1011,12 +1011,7 @@ unsigned long fw_passed_dtb; struct dentry *mips_debugfs_dir; static int __init debugfs_mips(void) { - struct dentry *d; - - d = debugfs_create_dir("mips", NULL); - if (!d) - return -ENOMEM; - mips_debugfs_dir = d; + mips_debugfs_dir = debugfs_create_dir("mips", NULL); return 0; } arch_initcall(debugfs_mips); diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index d84b9066b465..bc4bb3c6bd00 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -39,6 +39,7 @@ #include <linux/atomic.h> #include <asm/cpu.h> +#include <asm/ginvt.h> #include <asm/processor.h> #include <asm/idle.h> #include <asm/r4k-timer.h> @@ -443,6 +444,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus) /* preload SMP state for boot cpu */ void smp_prepare_boot_cpu(void) { + if (mp_ops->prepare_boot_cpu) + mp_ops->prepare_boot_cpu(); set_cpu_possible(0, true); set_cpu_online(0, true); } @@ -482,12 +485,21 @@ static void flush_tlb_all_ipi(void *info) void flush_tlb_all(void) { + if (cpu_has_mmid) { + htw_stop(); + ginvt_full(); + sync_ginv(); + instruction_hazard(); + htw_start(); + return; + } + on_each_cpu(flush_tlb_all_ipi, NULL, 1); } static void flush_tlb_mm_ipi(void *mm) { - local_flush_tlb_mm((struct mm_struct *)mm); + drop_mmu_context((struct mm_struct *)mm); } /* @@ -530,17 +542,22 @@ void flush_tlb_mm(struct mm_struct *mm) { preempt_disable(); - if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) { + if (cpu_has_mmid) { + /* + * No need to worry about other CPUs - the ginvt in + * drop_mmu_context() will be globalized. + */ + } else if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) { smp_on_other_tlbs(flush_tlb_mm_ipi, mm); } else { unsigned int cpu; for_each_online_cpu(cpu) { if (cpu != smp_processor_id() && cpu_context(cpu, mm)) - cpu_context(cpu, mm) = 0; + set_cpu_context(cpu, mm, 0); } } - local_flush_tlb_mm(mm); + drop_mmu_context(mm); preempt_enable(); } @@ -561,9 +578,26 @@ static void flush_tlb_range_ipi(void *info) void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { struct mm_struct *mm = vma->vm_mm; + unsigned long addr; + u32 old_mmid; preempt_disable(); - if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) { + if (cpu_has_mmid) { + htw_stop(); + old_mmid = read_c0_memorymapid(); + write_c0_memorymapid(cpu_asid(0, mm)); + mtc0_tlbw_hazard(); + addr = round_down(start, PAGE_SIZE * 2); + end = round_up(end, PAGE_SIZE * 2); + do { + ginvt_va_mmid(addr); + sync_ginv(); + addr += PAGE_SIZE * 2; + } while (addr < end); + write_c0_memorymapid(old_mmid); + instruction_hazard(); + htw_start(); + } else if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) { struct flush_tlb_data fd = { .vma = vma, .addr1 = start, @@ -571,6 +605,7 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned l }; smp_on_other_tlbs(flush_tlb_range_ipi, &fd); + local_flush_tlb_range(vma, start, end); } else { unsigned int cpu; int exec = vma->vm_flags & VM_EXEC; @@ -583,10 +618,10 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned l * mm has been completely unused by that CPU. */ if (cpu != smp_processor_id() && cpu_context(cpu, mm)) - cpu_context(cpu, mm) = !exec; + set_cpu_context(cpu, mm, !exec); } + local_flush_tlb_range(vma, start, end); } - local_flush_tlb_range(vma, start, end); preempt_enable(); } @@ -616,14 +651,28 @@ static void flush_tlb_page_ipi(void *info) void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) { + u32 old_mmid; + preempt_disable(); - if ((atomic_read(&vma->vm_mm->mm_users) != 1) || (current->mm != vma->vm_mm)) { + if (cpu_has_mmid) { + htw_stop(); + old_mmid = read_c0_memorymapid(); + write_c0_memorymapid(cpu_asid(0, vma->vm_mm)); + mtc0_tlbw_hazard(); + ginvt_va_mmid(page); + sync_ginv(); + write_c0_memorymapid(old_mmid); + instruction_hazard(); + htw_start(); + } else if ((atomic_read(&vma->vm_mm->mm_users) != 1) || + (current->mm != vma->vm_mm)) { struct flush_tlb_data fd = { .vma = vma, .addr1 = page, }; smp_on_other_tlbs(flush_tlb_page_ipi, &fd); + local_flush_tlb_page(vma, page); } else { unsigned int cpu; @@ -635,10 +684,10 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) * by that CPU. */ if (cpu != smp_processor_id() && cpu_context(cpu, vma->vm_mm)) - cpu_context(cpu, vma->vm_mm) = 1; + set_cpu_context(cpu, vma->vm_mm, 1); } + local_flush_tlb_page(vma, page); } - local_flush_tlb_page(vma, page); preempt_enable(); } diff --git a/arch/mips/kernel/spinlock_test.c b/arch/mips/kernel/spinlock_test.c index eaed550e79a2..ab4e3e1b138d 100644 --- a/arch/mips/kernel/spinlock_test.c +++ b/arch/mips/kernel/spinlock_test.c @@ -118,23 +118,10 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_multi, multi_get, NULL, "%llu\n"); static int __init spinlock_test(void) { - struct dentry *d; - - if (!mips_debugfs_dir) - return -ENODEV; - - d = debugfs_create_file("spin_single", S_IRUGO, - mips_debugfs_dir, NULL, - &fops_ss); - if (!d) - return -ENOMEM; - - d = debugfs_create_file("spin_multi", S_IRUGO, - mips_debugfs_dir, NULL, - &fops_multi); - if (!d) - return -ENOMEM; - + debugfs_create_file("spin_single", S_IRUGO, mips_debugfs_dir, NULL, + &fops_ss); + debugfs_create_file("spin_multi", S_IRUGO, mips_debugfs_dir, NULL, + &fops_multi); return 0; } device_initcall(spinlock_test); diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index cbab46004e99..42d411125690 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -2223,7 +2223,9 @@ void per_cpu_trap_init(bool is_boot_cpu) cp0_fdc_irq = -1; } - if (!cpu_data[cpu].asid_cache) + if (cpu_has_mmid) + cpu_data[cpu].asid_cache = 0; + else if (!cpu_data[cpu].asid_cache) cpu_data[cpu].asid_cache = asid_first_version(cpu); mmgrab(&init_mm); diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index 595ca9c85111..76e33f940971 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c @@ -89,6 +89,7 @@ #include <asm/fpu.h> #include <asm/fpu_emulator.h> #include <asm/inst.h> +#include <asm/mmu_context.h> #include <linux/uaccess.h> #define STR(x) __STR(x) @@ -2374,18 +2375,10 @@ sigbus: #ifdef CONFIG_DEBUG_FS static int __init debugfs_unaligned(void) { - struct dentry *d; - - if (!mips_debugfs_dir) - return -ENODEV; - d = debugfs_create_u32("unaligned_instructions", S_IRUGO, - mips_debugfs_dir, &unaligned_instructions); - if (!d) - return -ENOMEM; - d = debugfs_create_u32("unaligned_action", S_IRUGO | S_IWUSR, - mips_debugfs_dir, &unaligned_action); - if (!d) - return -ENOMEM; + debugfs_create_u32("unaligned_instructions", S_IRUGO, mips_debugfs_dir, + &unaligned_instructions); + debugfs_create_u32("unaligned_action", S_IRUGO | S_IWUSR, + mips_debugfs_dir, &unaligned_action); return 0; } arch_initcall(debugfs_unaligned); |