Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'mips-fixes_7.0_1' of git://git.kernel.org/pub/scm/linux/kernel/git/mips/linux

Pull MIPS fixes from Thomas Bogendoerfer:

- Fix TLB uniquification for systems with TLB not initialised by
firmware

- Fix allocation in TLB uniquification

- Fix SiByte cache initialisation

- Check uart parameters from firmware on Loongson64 systems

- Fix clock id mismatch for Ralink SoCs

- Fix GCC version check for __mutli3 workaround

* tag 'mips-fixes_7.0_1' of git://git.kernel.org/pub/scm/linux/kernel/git/mips/linux:
mips: mm: Allocate tlb_vpn array atomically
MIPS: mm: Rewrite TLB uniquification for the hidden bit feature
MIPS: mm: Suppress TLB uniquification on EHINV hardware
MIPS: Always record SEGBITS in cpu_data.vmbits
MIPS: Fix the GCC version check for `__multi3' workaround
MIPS: SiByte: Bring back cache initialisation
mips: ralink: update CPU clock index
MIPS: Loongson64: env: Check UARTs passed by LEFI cautiously

+269 -73
-1
arch/mips/include/asm/cpu-features.h
··· 484 484 # endif 485 485 # ifndef cpu_vmbits 486 486 # define cpu_vmbits cpu_data[0].vmbits 487 - # define __NEED_VMBITS_PROBE 488 487 # endif 489 488 #endif 490 489
-2
arch/mips/include/asm/cpu-info.h
··· 80 80 int srsets; /* Shadow register sets */ 81 81 int package;/* physical package number */ 82 82 unsigned int globalnumber; 83 - #ifdef CONFIG_64BIT 84 83 int vmbits; /* Virtual memory size in bits */ 85 - #endif 86 84 void *data; /* Additional data */ 87 85 unsigned int watch_reg_count; /* Number that exist */ 88 86 unsigned int watch_reg_use_cnt; /* Usable by ptrace */
+2
arch/mips/include/asm/mipsregs.h
··· 1871 1871 1872 1872 #define read_c0_entryhi() __read_ulong_c0_register($10, 0) 1873 1873 #define write_c0_entryhi(val) __write_ulong_c0_register($10, 0, val) 1874 + #define read_c0_entryhi_64() __read_64bit_c0_register($10, 0) 1875 + #define write_c0_entryhi_64(val) __write_64bit_c0_register($10, 0, val) 1874 1876 1875 1877 #define read_c0_guestctl1() __read_32bit_c0_register($10, 4) 1876 1878 #define write_c0_guestctl1(val) __write_32bit_c0_register($10, 4, val)
+8 -5
arch/mips/kernel/cpu-probe.c
··· 210 210 211 211 static inline void cpu_probe_vmbits(struct cpuinfo_mips *c) 212 212 { 213 - #ifdef __NEED_VMBITS_PROBE 214 - write_c0_entryhi(0x3fffffffffffe000ULL); 215 - back_to_back_c0_hazard(); 216 - c->vmbits = fls64(read_c0_entryhi() & 0x3fffffffffffe000ULL); 217 - #endif 213 + int vmbits = 31; 214 + 215 + if (cpu_has_64bits) { 216 + write_c0_entryhi_64(0x3fffffffffffe000ULL); 217 + back_to_back_c0_hazard(); 218 + vmbits = fls64(read_c0_entryhi_64() & 0x3fffffffffffe000ULL); 219 + } 220 + c->vmbits = vmbits; 218 221 } 219 222 220 223 static void set_isa(struct cpuinfo_mips *c, unsigned int isa)
+2
arch/mips/kernel/cpu-r3k-probe.c
··· 137 137 else 138 138 cpu_set_nofpu_opts(c); 139 139 140 + c->vmbits = 31; 141 + 140 142 reserve_exception_space(0, 0x400); 141 143 } 142 144
+3 -3
arch/mips/lib/multi3.c
··· 4 4 #include "libgcc.h" 5 5 6 6 /* 7 - * GCC 7 & older can suboptimally generate __multi3 calls for mips64r6, so for 7 + * GCC 9 & older can suboptimally generate __multi3 calls for mips64r6, so for 8 8 * that specific case only we implement that intrinsic here. 9 9 * 10 10 * See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82981 11 11 */ 12 - #if defined(CONFIG_64BIT) && defined(CONFIG_CPU_MIPSR6) && (__GNUC__ < 8) 12 + #if defined(CONFIG_64BIT) && defined(CONFIG_CPU_MIPSR6) && (__GNUC__ < 10) 13 13 14 14 /* multiply 64-bit values, low 64-bits returned */ 15 15 static inline long long notrace dmulu(long long a, long long b) ··· 51 51 } 52 52 EXPORT_SYMBOL(__multi3); 53 53 54 - #endif /* 64BIT && CPU_MIPSR6 && GCC7 */ 54 + #endif /* 64BIT && CPU_MIPSR6 && GCC9 */
+17 -1
arch/mips/loongson64/env.c
··· 17 17 #include <linux/dma-map-ops.h> 18 18 #include <linux/export.h> 19 19 #include <linux/libfdt.h> 20 + #include <linux/minmax.h> 20 21 #include <linux/pci_ids.h> 22 + #include <linux/serial_core.h> 21 23 #include <linux/string_choices.h> 22 24 #include <asm/bootinfo.h> 23 25 #include <loongson.h> ··· 108 106 109 107 is_loongson64g = (read_c0_prid() & PRID_IMP_MASK) == PRID_IMP_LOONGSON_64G; 110 108 111 - for (i = 0; i < system->nr_uarts; i++) { 109 + for (i = 0; i < min(system->nr_uarts, MAX_UARTS); i++) { 112 110 uartdev = &system->uarts[i]; 111 + 112 + /* 113 + * Some firmware does not set nr_uarts properly and passes empty 114 + * items. Ignore them silently. 115 + */ 116 + if (uartdev->uart_base == 0) 117 + continue; 118 + 119 + /* Our DT only works with UPIO_MEM. */ 120 + if (uartdev->iotype != UPIO_MEM) { 121 + pr_warn("Ignore UART 0x%llx with iotype %u passed by firmware\n", 122 + uartdev->uart_base, uartdev->iotype); 123 + continue; 124 + } 113 125 114 126 ret = lefi_fixup_fdt_serial(fdt_buf, uartdev->uart_base, 115 127 uartdev->uartclk);
+2 -1
arch/mips/mm/cache.c
··· 207 207 { 208 208 if (IS_ENABLED(CONFIG_CPU_R3000) && cpu_has_3k_cache) 209 209 r3k_cache_init(); 210 - if (IS_ENABLED(CONFIG_CPU_R4K_CACHE_TLB) && cpu_has_4k_cache) 210 + if ((IS_ENABLED(CONFIG_CPU_R4K_CACHE_TLB) || 211 + IS_ENABLED(CONFIG_CPU_SB1)) && cpu_has_4k_cache) 211 212 r4k_cache_init(); 212 213 213 214 if (IS_ENABLED(CONFIG_CPU_CAVIUM_OCTEON) && cpu_has_octeon_cache)
+231 -56
arch/mips/mm/tlb-r4k.c
··· 13 13 #include <linux/sched.h> 14 14 #include <linux/smp.h> 15 15 #include <linux/memblock.h> 16 + #include <linux/minmax.h> 16 17 #include <linux/mm.h> 17 18 #include <linux/hugetlb.h> 18 19 #include <linux/export.h> ··· 25 24 #include <asm/hazards.h> 26 25 #include <asm/mmu_context.h> 27 26 #include <asm/tlb.h> 27 + #include <asm/tlbdebug.h> 28 28 #include <asm/tlbex.h> 29 29 #include <asm/tlbmisc.h> 30 30 #include <asm/setup.h> ··· 513 511 __setup("ntlb=", set_ntlb); 514 512 515 513 516 - /* Comparison function for EntryHi VPN fields. */ 517 - static int r4k_vpn_cmp(const void *a, const void *b) 514 + /* The start bit position of VPN2 and Mask in EntryHi/PageMask registers. */ 515 + #define VPN2_SHIFT 13 516 + 517 + /* Read full EntryHi even with CONFIG_32BIT. */ 518 + static inline unsigned long long read_c0_entryhi_native(void) 518 519 { 519 - long v = *(unsigned long *)a - *(unsigned long *)b; 520 - int s = sizeof(long) > sizeof(int) ? sizeof(long) * 8 - 1: 0; 521 - return s ? (v != 0) | v >> s : v; 520 + return cpu_has_64bits ? read_c0_entryhi_64() : read_c0_entryhi(); 521 + } 522 + 523 + /* Write full EntryHi even with CONFIG_32BIT. */ 524 + static inline void write_c0_entryhi_native(unsigned long long v) 525 + { 526 + if (cpu_has_64bits) 527 + write_c0_entryhi_64(v); 528 + else 529 + write_c0_entryhi(v); 530 + } 531 + 532 + /* TLB entry state for uniquification. */ 533 + struct tlbent { 534 + unsigned long long wired:1; 535 + unsigned long long global:1; 536 + unsigned long long asid:10; 537 + unsigned long long vpn:51; 538 + unsigned long long pagesz:5; 539 + unsigned long long index:14; 540 + }; 541 + 542 + /* 543 + * Comparison function for TLB entry sorting. Place wired entries first, 544 + * then global entries, then order by the increasing VPN/ASID and the 545 + * decreasing page size. This lets us avoid clashes with wired entries 546 + * easily and get entries for larger pages out of the way first. 547 + * 548 + * We could group bits so as to reduce the number of comparisons, but this 549 + * is seldom executed and not performance-critical, so prefer legibility. 550 + */ 551 + static int r4k_entry_cmp(const void *a, const void *b) 552 + { 553 + struct tlbent ea = *(struct tlbent *)a, eb = *(struct tlbent *)b; 554 + 555 + if (ea.wired > eb.wired) 556 + return -1; 557 + else if (ea.wired < eb.wired) 558 + return 1; 559 + else if (ea.global > eb.global) 560 + return -1; 561 + else if (ea.global < eb.global) 562 + return 1; 563 + else if (ea.vpn < eb.vpn) 564 + return -1; 565 + else if (ea.vpn > eb.vpn) 566 + return 1; 567 + else if (ea.asid < eb.asid) 568 + return -1; 569 + else if (ea.asid > eb.asid) 570 + return 1; 571 + else if (ea.pagesz > eb.pagesz) 572 + return -1; 573 + else if (ea.pagesz < eb.pagesz) 574 + return 1; 575 + else 576 + return 0; 577 + } 578 + 579 + /* 580 + * Fetch all the TLB entries. Mask individual VPN values retrieved with 581 + * the corresponding page mask and ignoring any 1KiB extension as we'll 582 + * be using 4KiB pages for uniquification. 583 + */ 584 + static void __ref r4k_tlb_uniquify_read(struct tlbent *tlb_vpns, int tlbsize) 585 + { 586 + int start = num_wired_entries(); 587 + unsigned long long vpn_mask; 588 + bool global; 589 + int i; 590 + 591 + vpn_mask = GENMASK(current_cpu_data.vmbits - 1, VPN2_SHIFT); 592 + vpn_mask |= cpu_has_64bits ? 3ULL << 62 : 1 << 31; 593 + 594 + for (i = 0; i < tlbsize; i++) { 595 + unsigned long long entryhi, vpn, mask, asid; 596 + unsigned int pagesz; 597 + 598 + write_c0_index(i); 599 + mtc0_tlbr_hazard(); 600 + tlb_read(); 601 + tlb_read_hazard(); 602 + 603 + global = !!(read_c0_entrylo0() & ENTRYLO_G); 604 + entryhi = read_c0_entryhi_native(); 605 + mask = read_c0_pagemask(); 606 + 607 + asid = entryhi & cpu_asid_mask(&current_cpu_data); 608 + vpn = (entryhi & vpn_mask & ~mask) >> VPN2_SHIFT; 609 + pagesz = ilog2((mask >> VPN2_SHIFT) + 1); 610 + 611 + tlb_vpns[i].global = global; 612 + tlb_vpns[i].asid = global ? 0 : asid; 613 + tlb_vpns[i].vpn = vpn; 614 + tlb_vpns[i].pagesz = pagesz; 615 + tlb_vpns[i].wired = i < start; 616 + tlb_vpns[i].index = i; 617 + } 618 + } 619 + 620 + /* 621 + * Write unique values to all but the wired TLB entries each, using 622 + * the 4KiB page size. This size might not be supported with R6, but 623 + * EHINV is mandatory for R6, so we won't ever be called in that case. 624 + * 625 + * A sorted table is supplied with any wired entries at the beginning, 626 + * followed by any global entries, and then finally regular entries. 627 + * We start at the VPN and ASID values of zero and only assign user 628 + * addresses, therefore guaranteeing no clash with addresses produced 629 + * by UNIQUE_ENTRYHI. We avoid any VPN values used by wired or global 630 + * entries, by increasing the VPN value beyond the span of such entry. 631 + * 632 + * When a VPN/ASID clash is found with a regular entry we increment the 633 + * ASID instead until no VPN/ASID clash has been found or the ASID space 634 + * has been exhausted, in which case we increase the VPN value beyond 635 + * the span of the largest clashing entry. 636 + * 637 + * We do not need to be concerned about FTLB or MMID configurations as 638 + * those are required to implement the EHINV feature. 639 + */ 640 + static void __ref r4k_tlb_uniquify_write(struct tlbent *tlb_vpns, int tlbsize) 641 + { 642 + unsigned long long asid, vpn, vpn_size, pagesz; 643 + int widx, gidx, idx, sidx, lidx, i; 644 + 645 + vpn_size = 1ULL << (current_cpu_data.vmbits - VPN2_SHIFT); 646 + pagesz = ilog2((PM_4K >> VPN2_SHIFT) + 1); 647 + 648 + write_c0_pagemask(PM_4K); 649 + write_c0_entrylo0(0); 650 + write_c0_entrylo1(0); 651 + 652 + asid = 0; 653 + vpn = 0; 654 + widx = 0; 655 + gidx = 0; 656 + for (sidx = 0; sidx < tlbsize && tlb_vpns[sidx].wired; sidx++) 657 + ; 658 + for (lidx = sidx; lidx < tlbsize && tlb_vpns[lidx].global; lidx++) 659 + ; 660 + idx = gidx = sidx + 1; 661 + for (i = sidx; i < tlbsize; i++) { 662 + unsigned long long entryhi, vpn_pagesz = 0; 663 + 664 + while (1) { 665 + if (WARN_ON(vpn >= vpn_size)) { 666 + dump_tlb_all(); 667 + /* Pray local_flush_tlb_all() will cope. */ 668 + return; 669 + } 670 + 671 + /* VPN must be below the next wired entry. */ 672 + if (widx < sidx && vpn >= tlb_vpns[widx].vpn) { 673 + vpn = max(vpn, 674 + (tlb_vpns[widx].vpn + 675 + (1ULL << tlb_vpns[widx].pagesz))); 676 + asid = 0; 677 + widx++; 678 + continue; 679 + } 680 + /* VPN must be below the next global entry. */ 681 + if (gidx < lidx && vpn >= tlb_vpns[gidx].vpn) { 682 + vpn = max(vpn, 683 + (tlb_vpns[gidx].vpn + 684 + (1ULL << tlb_vpns[gidx].pagesz))); 685 + asid = 0; 686 + gidx++; 687 + continue; 688 + } 689 + /* Try to find a free ASID so as to conserve VPNs. */ 690 + if (idx < tlbsize && vpn == tlb_vpns[idx].vpn && 691 + asid == tlb_vpns[idx].asid) { 692 + unsigned long long idx_pagesz; 693 + 694 + idx_pagesz = tlb_vpns[idx].pagesz; 695 + vpn_pagesz = max(vpn_pagesz, idx_pagesz); 696 + do 697 + idx++; 698 + while (idx < tlbsize && 699 + vpn == tlb_vpns[idx].vpn && 700 + asid == tlb_vpns[idx].asid); 701 + asid++; 702 + if (asid > cpu_asid_mask(&current_cpu_data)) { 703 + vpn += vpn_pagesz; 704 + asid = 0; 705 + vpn_pagesz = 0; 706 + } 707 + continue; 708 + } 709 + /* VPN mustn't be above the next regular entry. */ 710 + if (idx < tlbsize && vpn > tlb_vpns[idx].vpn) { 711 + vpn = max(vpn, 712 + (tlb_vpns[idx].vpn + 713 + (1ULL << tlb_vpns[idx].pagesz))); 714 + asid = 0; 715 + idx++; 716 + continue; 717 + } 718 + break; 719 + } 720 + 721 + entryhi = (vpn << VPN2_SHIFT) | asid; 722 + write_c0_entryhi_native(entryhi); 723 + write_c0_index(tlb_vpns[i].index); 724 + mtc0_tlbw_hazard(); 725 + tlb_write_indexed(); 726 + 727 + tlb_vpns[i].asid = asid; 728 + tlb_vpns[i].vpn = vpn; 729 + tlb_vpns[i].pagesz = pagesz; 730 + 731 + asid++; 732 + if (asid > cpu_asid_mask(&current_cpu_data)) { 733 + vpn += 1ULL << pagesz; 734 + asid = 0; 735 + } 736 + } 522 737 } 523 738 524 739 /* ··· 746 527 { 747 528 int tlbsize = current_cpu_data.tlbsize; 748 529 bool use_slab = slab_is_available(); 749 - int start = num_wired_entries(); 750 530 phys_addr_t tlb_vpn_size; 751 - unsigned long *tlb_vpns; 752 - unsigned long vpn_mask; 753 - int cnt, ent, idx, i; 754 - 755 - vpn_mask = GENMASK(cpu_vmbits - 1, 13); 756 - vpn_mask |= IS_ENABLED(CONFIG_64BIT) ? 3ULL << 62 : 1 << 31; 531 + struct tlbent *tlb_vpns; 757 532 758 533 tlb_vpn_size = tlbsize * sizeof(*tlb_vpns); 759 534 tlb_vpns = (use_slab ? 760 - kmalloc(tlb_vpn_size, GFP_KERNEL) : 535 + kmalloc(tlb_vpn_size, GFP_ATOMIC) : 761 536 memblock_alloc_raw(tlb_vpn_size, sizeof(*tlb_vpns))); 762 537 if (WARN_ON(!tlb_vpns)) 763 538 return; /* Pray local_flush_tlb_all() is good enough. */ 764 539 765 540 htw_stop(); 766 541 767 - for (i = start, cnt = 0; i < tlbsize; i++, cnt++) { 768 - unsigned long vpn; 542 + r4k_tlb_uniquify_read(tlb_vpns, tlbsize); 769 543 770 - write_c0_index(i); 771 - mtc0_tlbr_hazard(); 772 - tlb_read(); 773 - tlb_read_hazard(); 774 - vpn = read_c0_entryhi(); 775 - vpn &= vpn_mask & PAGE_MASK; 776 - tlb_vpns[cnt] = vpn; 544 + sort(tlb_vpns, tlbsize, sizeof(*tlb_vpns), r4k_entry_cmp, NULL); 777 545 778 - /* Prevent any large pages from overlapping regular ones. */ 779 - write_c0_pagemask(read_c0_pagemask() & PM_DEFAULT_MASK); 780 - mtc0_tlbw_hazard(); 781 - tlb_write_indexed(); 782 - tlbw_use_hazard(); 783 - } 784 - 785 - sort(tlb_vpns, cnt, sizeof(tlb_vpns[0]), r4k_vpn_cmp, NULL); 546 + r4k_tlb_uniquify_write(tlb_vpns, tlbsize); 786 547 787 548 write_c0_pagemask(PM_DEFAULT_MASK); 788 - write_c0_entrylo0(0); 789 - write_c0_entrylo1(0); 790 - 791 - idx = 0; 792 - ent = tlbsize; 793 - for (i = start; i < tlbsize; i++) 794 - while (1) { 795 - unsigned long entryhi, vpn; 796 - 797 - entryhi = UNIQUE_ENTRYHI(ent); 798 - vpn = entryhi & vpn_mask & PAGE_MASK; 799 - 800 - if (idx >= cnt || vpn < tlb_vpns[idx]) { 801 - write_c0_entryhi(entryhi); 802 - write_c0_index(i); 803 - mtc0_tlbw_hazard(); 804 - tlb_write_indexed(); 805 - ent++; 806 - break; 807 - } else if (vpn == tlb_vpns[idx]) { 808 - ent++; 809 - } else { 810 - idx++; 811 - } 812 - } 813 549 814 550 tlbw_use_hazard(); 815 551 htw_start(); ··· 814 640 temp_tlb_entry = current_cpu_data.tlbsize - 1; 815 641 816 642 /* From this point on the ARC firmware is dead. */ 817 - r4k_tlb_uniquify(); 643 + if (!cpu_has_tlbinv) 644 + r4k_tlb_uniquify(); 818 645 local_flush_tlb_all(); 819 646 820 647 /* Did I tell you that ARC SUCKS? */
+4 -4
arch/mips/ralink/clk.c
··· 21 21 { 22 22 switch (ralink_soc) { 23 23 case RT2880_SOC: 24 - *idx = 0; 24 + *idx = 1; 25 25 return "ralink,rt2880-sysc"; 26 26 case RT3883_SOC: 27 - *idx = 0; 27 + *idx = 1; 28 28 return "ralink,rt3883-sysc"; 29 29 case RT305X_SOC_RT3050: 30 - *idx = 0; 30 + *idx = 1; 31 31 return "ralink,rt3050-sysc"; 32 32 case RT305X_SOC_RT3052: 33 - *idx = 0; 33 + *idx = 1; 34 34 return "ralink,rt3052-sysc"; 35 35 case RT305X_SOC_RT3350: 36 36 *idx = 1;