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

Merge tag 'loongarch-5.20' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson

Pull LoongArch updates from Huacai Chen:

- Optimise getcpu() with vDSO

- PCI enablement on top of pci & irqchip changes

- Stack unwinder and stack trace support

- Some bug fixes and build error fixes

- Update the default config file

* tag 'loongarch-5.20' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson:
docs/zh_CN/LoongArch: Add I14 description
docs/LoongArch: Add I14 description
LoongArch: Update Loongson-3 default config file
LoongArch: Add USER_STACKTRACE support
LoongArch: Add STACKTRACE support
LoongArch: Add prologue unwinder support
LoongArch: Add guess unwinder support
LoongArch: Add vDSO syscall __vdso_getcpu()
LoongArch: Add PCI controller support
LoongArch: Parse MADT to get multi-processor information
LoongArch: Jump to the link address before enable PG
LoongArch: Requires __force attributes for any casts
LoongArch: Fix unsigned comparison with less than zero
LoongArch: Adjust arch/loongarch/Kconfig
LoongArch: cpuinfo: Fix a warning for CONFIG_CPUMASK_OFFSTACK

+1089 -63
+1 -1
Documentation/loongarch/introduction.rst
··· 221 221 =========== ========================== 222 222 223 223 Rd is the destination register operand, while Rj, Rk and Ra ("a" stands for 224 - "additional") are the source register operands. I8/I12/I16/I21/I26 are 224 + "additional") are the source register operands. I8/I12/I14/I16/I21/I26 are 225 225 immediate operands of respective width. The longer I21 and I26 are stored 226 226 in separate higher and lower parts in the instruction word, denoted by the "L" 227 227 and "H" suffixes.
+2 -2
Documentation/translations/zh_CN/loongarch/introduction.rst
··· 190 190 =========== ========================== 191 191 192 192 Opcode是指令操作码,Rj和Rk是源操作数(寄存器),Rd是目标操作数(寄存器),Ra是 193 - 4R-type格式特有的附加操作数(寄存器)。I8/I12/I16/I21/I26分别是8位/12位/16位/ 194 - 21位/26位的立即数。其中较长的21位和26位立即数在指令字中被分割为高位部分与低位 193 + 4R-type格式特有的附加操作数(寄存器)。I8/I12/I14/I16/I21/I26分别是8位/12位/14位/ 194 + 16位/21位/26位的立即数。其中较长的21位和26位立即数在指令字中被分割为高位部分与低位 195 195 部分,所以你们在这里的格式描述中能够看到I21L/I21H和I26L/I26H这样带后缀的表述。 196 196 197 197 指令列表
+17 -1
arch/loongarch/Kconfig
··· 2 2 config LOONGARCH 3 3 bool 4 4 default y 5 + select ACPI 5 6 select ACPI_GENERIC_GSI if ACPI 7 + select ACPI_MCFG if ACPI 6 8 select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI 7 9 select ARCH_BINFMT_ELF_STATE 8 10 select ARCH_ENABLE_MEMORY_HOTPLUG ··· 42 40 select ARCH_MIGHT_HAVE_PC_PARPORT 43 41 select ARCH_MIGHT_HAVE_PC_SERIO 44 42 select ARCH_SPARSEMEM_ENABLE 43 + select ARCH_STACKWALK 45 44 select ARCH_SUPPORTS_ACPI 46 45 select ARCH_SUPPORTS_ATOMIC_RMW 47 46 select ARCH_SUPPORTS_HUGETLBFS ··· 54 51 select ARCH_WANTS_NO_INSTR 55 52 select BUILDTIME_TABLE_SORT 56 53 select COMMON_CLK 54 + select EFI 57 55 select GENERIC_CLOCKEVENTS 58 56 select GENERIC_CMOS_UPDATE 59 57 select GENERIC_CPU_AUTOPROBE ··· 90 86 select HAVE_IRQ_TIME_ACCOUNTING 91 87 select HAVE_MOD_ARCH_SPECIFIC 92 88 select HAVE_NMI 89 + select HAVE_PCI 93 90 select HAVE_PERF_EVENTS 94 91 select HAVE_REGS_AND_STACK_ACCESS_API 95 92 select HAVE_RSEQ ··· 100 95 select HAVE_VIRT_CPU_ACCOUNTING_GEN if !SMP 101 96 select IRQ_FORCED_THREADING 102 97 select IRQ_LOONGARCH_CPU 98 + select MMU_GATHER_MERGE_VMAS if MMU 103 99 select MODULES_USE_ELF_RELA if MODULES 104 100 select NEED_PER_CPU_EMBED_FIRST_CHUNK 105 101 select NEED_PER_CPU_PAGE_FIRST_CHUNK 106 102 select OF 107 103 select OF_EARLY_FLATTREE 104 + select PCI 105 + select PCI_DOMAINS_GENERIC 106 + select PCI_ECAM if ACPI 107 + select PCI_LOONGSON 108 + select PCI_MSI_ARCH_FALLBACKS 108 109 select PERF_USE_VMALLOC 109 110 select RTC_LIB 111 + select SMP 110 112 select SPARSE_IRQ 111 113 select SYSCTL_EXCEPTION_TRACE 112 114 select SWIOTLB 113 115 select TRACE_IRQFLAGS_SUPPORT 114 116 select USE_PERCPU_NUMA_NODE_ID 117 + select USER_STACKTRACE_SUPPORT 115 118 select ZONE_DMA32 116 - select MMU_GATHER_MERGE_VMAS if MMU 117 119 118 120 config 32BIT 119 121 bool ··· 150 138 default "6" 151 139 152 140 config LOCKDEP_SUPPORT 141 + bool 142 + default y 143 + 144 + config STACKTRACE_SUPPORT 153 145 bool 154 146 default y 155 147
+29
arch/loongarch/Kconfig.debug
··· 1 + choice 2 + prompt "Choose kernel unwinder" 3 + default UNWINDER_PROLOGUE if KALLSYMS 4 + help 5 + This determines which method will be used for unwinding kernel stack 6 + traces for panics, oopses, bugs, warnings, perf, /proc/<pid>/stack, 7 + lockdep, and more. 8 + 9 + config UNWINDER_GUESS 10 + bool "Guess unwinder" 11 + help 12 + This option enables the "guess" unwinder for unwinding kernel stack 13 + traces. It scans the stack and reports every kernel text address it 14 + finds. Some of the addresses it reports may be incorrect. 15 + 16 + While this option often produces false positives, it can still be 17 + useful in many cases. 18 + 19 + config UNWINDER_PROLOGUE 20 + bool "Prologue unwinder" 21 + depends on KALLSYMS 22 + help 23 + This option enables the "prologue" unwinder for unwinding kernel stack 24 + traces. It unwind the stack frame based on prologue code analyze. Symbol 25 + information is needed, at least the address and length of each function. 26 + Some of the addresses it reports may be incorrect (but better than the 27 + Guess unwinder). 28 + 29 + endchoice
+2
arch/loongarch/Makefile
··· 47 47 load-y = 0x9000000000200000 48 48 bootvars-y = VMLINUX_LOAD_ADDRESS=$(load-y) 49 49 50 + drivers-$(CONFIG_PCI) += arch/loongarch/pci/ 51 + 50 52 KBUILD_AFLAGS += $(cflags-y) 51 53 KBUILD_CFLAGS += $(cflags-y) 52 54 KBUILD_CPPFLAGS += -DVMLINUX_LOAD_ADDRESS=$(load-y)
+33 -1
arch/loongarch/configs/loongson3_defconfig
··· 278 278 CONFIG_NET_ACT_NAT=m 279 279 CONFIG_NET_ACT_BPF=m 280 280 CONFIG_OPENVSWITCH=m 281 + CONFIG_VSOCKETS=m 282 + CONFIG_VIRTIO_VSOCKETS=m 281 283 CONFIG_NETLINK_DIAG=y 282 284 CONFIG_CGROUP_NET_PRIO=y 283 285 CONFIG_BT=m ··· 291 289 CONFIG_RFKILL=m 292 290 CONFIG_RFKILL_INPUT=y 293 291 CONFIG_NET_9P=y 292 + CONFIG_NET_9P_VIRTIO=y 294 293 CONFIG_CEPH_LIB=m 295 294 CONFIG_PCIEPORTBUS=y 296 295 CONFIG_HOTPLUG_PCI_PCIE=y ··· 311 308 CONFIG_UEVENT_HELPER=y 312 309 CONFIG_DEVTMPFS=y 313 310 CONFIG_DEVTMPFS_MOUNT=y 311 + CONFIG_FW_LOADER_COMPRESS=y 312 + CONFIG_FW_LOADER_COMPRESS_ZSTD=y 314 313 CONFIG_MTD=m 315 314 CONFIG_MTD_BLOCK=m 316 315 CONFIG_MTD_CFI=m ··· 333 328 CONFIG_BLK_DEV_NBD=m 334 329 CONFIG_BLK_DEV_RAM=y 335 330 CONFIG_BLK_DEV_RAM_SIZE=8192 331 + CONFIG_VIRTIO_BLK=y 336 332 CONFIG_BLK_DEV_RBD=m 337 333 CONFIG_BLK_DEV_NVME=y 334 + CONFIG_NVME_MULTIPATH=y 335 + CONFIG_NVME_RDMA=m 336 + CONFIG_NVME_FC=m 337 + CONFIG_NVME_TCP=m 338 + CONFIG_NVME_TARGET=m 339 + CONFIG_NVME_TARGET_PASSTHRU=y 340 + CONFIG_NVME_TARGET_LOOP=m 341 + CONFIG_NVME_TARGET_RDMA=m 342 + CONFIG_NVME_TARGET_FC=m 343 + CONFIG_NVME_TARGET_TCP=m 338 344 CONFIG_EEPROM_AT24=m 339 345 CONFIG_BLK_DEV_SD=y 340 346 CONFIG_BLK_DEV_SR=y ··· 375 359 CONFIG_TCM_QLA2XXX=m 376 360 CONFIG_SCSI_QLA_ISCSI=m 377 361 CONFIG_SCSI_LPFC=m 362 + CONFIG_SCSI_VIRTIO=m 378 363 CONFIG_ATA=y 379 364 CONFIG_SATA_AHCI=y 380 365 CONFIG_SATA_AHCI_PLATFORM=y ··· 420 403 CONFIG_RIONET=m 421 404 CONFIG_TUN=m 422 405 CONFIG_VETH=m 406 + CONFIG_VIRTIO_NET=m 423 407 # CONFIG_NET_VENDOR_3COM is not set 424 408 # CONFIG_NET_VENDOR_ADAPTEC is not set 425 409 # CONFIG_NET_VENDOR_AGERE is not set ··· 545 527 CONFIG_SERIAL_8250_RSA=y 546 528 CONFIG_SERIAL_NONSTANDARD=y 547 529 CONFIG_PRINTER=m 530 + CONFIG_VIRTIO_CONSOLE=y 548 531 CONFIG_IPMI_HANDLER=m 549 532 CONFIG_IPMI_DEVICE_INTERFACE=m 550 533 CONFIG_IPMI_SI=m 551 534 CONFIG_HW_RANDOM=y 535 + CONFIG_HW_RANDOM_VIRTIO=m 552 536 CONFIG_I2C_CHARDEV=y 553 537 CONFIG_I2C_PIIX4=y 554 538 CONFIG_I2C_GPIO=y ··· 588 568 CONFIG_DRM_AMDGPU_CIK=y 589 569 CONFIG_DRM_AMDGPU_USERPTR=y 590 570 CONFIG_DRM_AST=y 571 + CONFIG_DRM_QXL=m 572 + CONFIG_DRM_VIRTIO_GPU=m 591 573 CONFIG_FB=y 592 574 CONFIG_FB_EFI=y 593 575 CONFIG_FB_RADEON=y ··· 659 637 CONFIG_UIO_PDRV_GENIRQ=m 660 638 CONFIG_UIO_DMEM_GENIRQ=m 661 639 CONFIG_UIO_PCI_GENERIC=m 662 - # CONFIG_VIRTIO_MENU is not set 640 + CONFIG_VFIO=m 641 + CONFIG_VFIO_PCI=m 642 + CONFIG_VIRTIO_PCI=y 643 + CONFIG_VIRTIO_BALLOON=m 644 + CONFIG_VIRTIO_INPUT=m 645 + CONFIG_VIRTIO_MMIO=m 646 + CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y 647 + CONFIG_VHOST_NET=m 648 + CONFIG_VHOST_SCSI=m 649 + CONFIG_VHOST_VSOCK=m 663 650 CONFIG_COMEDI=m 664 651 CONFIG_COMEDI_PCI_DRIVERS=m 665 652 CONFIG_COMEDI_8255_PCI=m ··· 793 762 CONFIG_CRYPTO_USER_API_SKCIPHER=m 794 763 CONFIG_CRYPTO_USER_API_RNG=m 795 764 CONFIG_CRYPTO_USER_API_AEAD=m 765 + CONFIG_CRYPTO_DEV_VIRTIO=m 796 766 CONFIG_PRINTK_TIME=y 797 767 CONFIG_STRIP_ASM_SYMS=y 798 768 CONFIG_MAGIC_SYSRQ=y
+1 -1
arch/loongarch/include/asm/bootinfo.h
··· 28 28 struct loongson_system_configuration { 29 29 int nr_cpus; 30 30 int nr_nodes; 31 - int nr_io_pics; 32 31 int boot_cpu_id; 33 32 int cores_per_node; 34 33 int cores_per_package; 34 + unsigned long cores_io_master; 35 35 const char *cpuname; 36 36 }; 37 37
+11
arch/loongarch/include/asm/dma.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 4 + */ 5 + #ifndef __ASM_DMA_H 6 + #define __ASM_DMA_H 7 + 8 + #define MAX_DMA_ADDRESS PAGE_OFFSET 9 + #define MAX_DMA32_PFN (1UL << (32 - PAGE_SHIFT)) 10 + 11 + #endif
+52
arch/loongarch/include/asm/inst.h
··· 23 23 lu32id_op = 0x0b, 24 24 }; 25 25 26 + enum reg1i21_op { 27 + beqz_op = 0x10, 28 + bnez_op = 0x11, 29 + }; 30 + 26 31 enum reg2i12_op { 32 + addiw_op = 0x0a, 33 + addid_op = 0x0b, 27 34 lu52id_op = 0x0c, 35 + ldb_op = 0xa0, 36 + ldh_op = 0xa1, 37 + ldw_op = 0xa2, 38 + ldd_op = 0xa3, 39 + stb_op = 0xa4, 40 + sth_op = 0xa5, 41 + stw_op = 0xa6, 42 + std_op = 0xa7, 28 43 }; 29 44 30 45 enum reg2i16_op { 31 46 jirl_op = 0x13, 47 + beq_op = 0x16, 48 + bne_op = 0x17, 49 + blt_op = 0x18, 50 + bge_op = 0x19, 51 + bltu_op = 0x1a, 52 + bgeu_op = 0x1b, 32 53 }; 33 54 34 55 struct reg0i26_format { ··· 130 109 LOONGARCH_GPR_S8, 131 110 LOONGARCH_GPR_MAX 132 111 }; 112 + 113 + #define is_imm12_negative(val) is_imm_negative(val, 12) 114 + 115 + static inline bool is_imm_negative(unsigned long val, unsigned int bit) 116 + { 117 + return val & (1UL << (bit - 1)); 118 + } 119 + 120 + static inline bool is_branch_ins(union loongarch_instruction *ip) 121 + { 122 + return ip->reg1i21_format.opcode >= beqz_op && 123 + ip->reg1i21_format.opcode <= bgeu_op; 124 + } 125 + 126 + static inline bool is_ra_save_ins(union loongarch_instruction *ip) 127 + { 128 + /* st.d $ra, $sp, offset */ 129 + return ip->reg2i12_format.opcode == std_op && 130 + ip->reg2i12_format.rj == LOONGARCH_GPR_SP && 131 + ip->reg2i12_format.rd == LOONGARCH_GPR_RA && 132 + !is_imm12_negative(ip->reg2i12_format.immediate); 133 + } 134 + 135 + static inline bool is_stack_alloc_ins(union loongarch_instruction *ip) 136 + { 137 + /* addi.d $sp, $sp, -imm */ 138 + return ip->reg2i12_format.opcode == addid_op && 139 + ip->reg2i12_format.rj == LOONGARCH_GPR_SP && 140 + ip->reg2i12_format.rd == LOONGARCH_GPR_SP && 141 + is_imm12_negative(ip->reg2i12_format.immediate); 142 + } 133 143 134 144 u32 larch_insn_gen_lu32id(enum loongarch_gpr rd, int imm); 135 145 u32 larch_insn_gen_lu52id(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm);
-10
arch/loongarch/include/asm/irq.h
··· 82 82 #define GSI_MAX_PCH_IRQ (LOONGSON_PCH_IRQ_BASE + 256 - 1) 83 83 84 84 extern int find_pch_pic(u32 gsi); 85 - extern int eiointc_get_node(int id); 86 - 87 85 struct acpi_madt_lio_pic; 88 86 struct acpi_madt_eio_pic; 89 87 struct acpi_madt_ht_pic; ··· 98 100 struct acpi_madt_ht_pic *acpi_htvec); 99 101 int pch_lpc_acpi_init(struct irq_domain *parent, 100 102 struct acpi_madt_lpc_pic *acpi_pchlpc); 101 - #if IS_ENABLED(CONFIG_LOONGSON_PCH_MSI) 102 103 int pch_msi_acpi_init(struct irq_domain *parent, 103 104 struct acpi_madt_msi_pic *acpi_pchmsi); 104 - #else 105 - static inline int pch_msi_acpi_init(struct irq_domain *parent, 106 - struct acpi_madt_msi_pic *acpi_pchmsi) 107 - { 108 - return 0; 109 - } 110 - #endif 111 105 int pch_pic_acpi_init(struct irq_domain *parent, 112 106 struct acpi_madt_bio_pic *acpi_pchpic); 113 107 int find_pch_pic(u32 gsi);
-2
arch/loongarch/include/asm/page.h
··· 33 33 #include <linux/kernel.h> 34 34 #include <linux/pfn.h> 35 35 36 - #define MAX_DMA32_PFN (1UL << (32 - PAGE_SHIFT)) 37 - 38 36 /* 39 37 * It's normally defined only for FLATMEM config but it's 40 38 * used in our early mem init code for all memory models.
+25
arch/loongarch/include/asm/pci.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 4 + */ 5 + #ifndef _ASM_PCI_H 6 + #define _ASM_PCI_H 7 + 8 + #include <linux/ioport.h> 9 + #include <linux/list.h> 10 + #include <linux/types.h> 11 + #include <asm/io.h> 12 + 13 + #define PCIBIOS_MIN_IO 0x4000 14 + #define PCIBIOS_MIN_MEM 0x20000000 15 + #define PCIBIOS_MIN_CARDBUS_IO 0x4000 16 + 17 + #define HAVE_PCI_MMAP 18 + #define pcibios_assign_all_busses() 0 19 + 20 + extern phys_addr_t mcfg_addr_init(int node); 21 + 22 + /* generic pci stuff */ 23 + #include <asm-generic/pci.h> 24 + 25 + #endif /* _ASM_PCI_H */
+9
arch/loongarch/include/asm/processor.h
··· 101 101 unsigned long reg23, reg24, reg25, reg26; /* s0-s3 */ 102 102 unsigned long reg27, reg28, reg29, reg30, reg31; /* s4-s8 */ 103 103 104 + /* __schedule() return address / call frame address */ 105 + unsigned long sched_ra; 106 + unsigned long sched_cfa; 107 + 104 108 /* CSR registers */ 105 109 unsigned long csr_prmd; 106 110 unsigned long csr_crmd; ··· 133 129 struct loongarch_fpu fpu FPU_ALIGN; 134 130 }; 135 131 132 + #define thread_saved_ra(tsk) (tsk->thread.sched_ra) 133 + #define thread_saved_fp(tsk) (tsk->thread.sched_cfa) 134 + 136 135 #define INIT_THREAD { \ 137 136 /* \ 138 137 * Main processor registers \ ··· 152 145 .reg29 = 0, \ 153 146 .reg30 = 0, \ 154 147 .reg31 = 0, \ 148 + .sched_ra = 0, \ 149 + .sched_cfa = 0, \ 155 150 .csr_crmd = 0, \ 156 151 .csr_prmd = 0, \ 157 152 .csr_euen = 0, \
+20
arch/loongarch/include/asm/stacktrace.h
··· 10 10 #include <asm/loongarch.h> 11 11 #include <linux/stringify.h> 12 12 13 + enum stack_type { 14 + STACK_TYPE_UNKNOWN, 15 + STACK_TYPE_IRQ, 16 + STACK_TYPE_TASK, 17 + }; 18 + 19 + struct stack_info { 20 + enum stack_type type; 21 + unsigned long begin, end, next_sp; 22 + }; 23 + 24 + struct stack_frame { 25 + unsigned long fp; 26 + unsigned long ra; 27 + }; 28 + 29 + bool in_irq_stack(unsigned long stack, struct stack_info *info); 30 + bool in_task_stack(unsigned long stack, struct task_struct *task, struct stack_info *info); 31 + int get_stack_info(unsigned long stack, struct task_struct *task, struct stack_info *info); 32 + 13 33 #define STR_LONG_L __stringify(LONG_L) 14 34 #define STR_LONG_S __stringify(LONG_S) 15 35 #define STR_LONGSIZE __stringify(LONGSIZE)
+9 -5
arch/loongarch/include/asm/switch_to.h
··· 15 15 * @prev: The task previously executed. 16 16 * @next: The task to begin executing. 17 17 * @next_ti: task_thread_info(next). 18 + * @sched_ra: __schedule return address. 19 + * @sched_cfa: __schedule call frame address. 18 20 * 19 21 * This function is used whilst scheduling to save the context of prev & load 20 22 * the context of next. Returns prev. 21 23 */ 22 24 extern asmlinkage struct task_struct *__switch_to(struct task_struct *prev, 23 - struct task_struct *next, struct thread_info *next_ti); 25 + struct task_struct *next, struct thread_info *next_ti, 26 + void *sched_ra, void *sched_cfa); 24 27 25 28 /* 26 29 * For newly created kernel threads switch_to() will return to ··· 31 28 * That is, everything following __switch_to() will be skipped for new threads. 32 29 * So everything that matters to new threads should be placed before __switch_to(). 33 30 */ 34 - #define switch_to(prev, next, last) \ 35 - do { \ 36 - lose_fpu_inatomic(1, prev); \ 37 - (last) = __switch_to(prev, next, task_thread_info(next)); \ 31 + #define switch_to(prev, next, last) \ 32 + do { \ 33 + lose_fpu_inatomic(1, prev); \ 34 + (last) = __switch_to(prev, next, task_thread_info(next), \ 35 + __builtin_return_address(0), __builtin_frame_address(0)); \ 38 36 } while (0) 39 37 40 38 #endif /* _ASM_SWITCH_TO_H */
+2 -2
arch/loongarch/include/asm/uaccess.h
··· 229 229 static inline unsigned long __must_check 230 230 raw_copy_from_user(void *to, const void __user *from, unsigned long n) 231 231 { 232 - return __copy_user(to, from, n); 232 + return __copy_user(to, (__force const void *)from, n); 233 233 } 234 234 235 235 static inline unsigned long __must_check 236 236 raw_copy_to_user(void __user *to, const void *from, unsigned long n) 237 237 { 238 - return __copy_user(to, from, n); 238 + return __copy_user((__force void *)to, from, n); 239 239 } 240 240 241 241 #define INLINE_COPY_FROM_USER
+42
arch/loongarch/include/asm/unwind.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Most of this ideas comes from x86. 4 + * 5 + * Copyright (C) 2022 Loongson Technology Corporation Limited 6 + */ 7 + #ifndef _ASM_UNWIND_H 8 + #define _ASM_UNWIND_H 9 + 10 + #include <linux/sched.h> 11 + 12 + #include <asm/stacktrace.h> 13 + 14 + enum unwinder_type { 15 + UNWINDER_GUESS, 16 + UNWINDER_PROLOGUE, 17 + }; 18 + 19 + struct unwind_state { 20 + char type; /* UNWINDER_XXX */ 21 + struct stack_info stack_info; 22 + struct task_struct *task; 23 + bool first, error; 24 + unsigned long sp, pc, ra; 25 + }; 26 + 27 + void unwind_start(struct unwind_state *state, 28 + struct task_struct *task, struct pt_regs *regs); 29 + bool unwind_next_frame(struct unwind_state *state); 30 + unsigned long unwind_get_return_address(struct unwind_state *state); 31 + 32 + static inline bool unwind_done(struct unwind_state *state) 33 + { 34 + return state->stack_info.type == STACK_TYPE_UNKNOWN; 35 + } 36 + 37 + static inline bool unwind_error(struct unwind_state *state) 38 + { 39 + return state->error; 40 + } 41 + 42 + #endif /* _ASM_UNWIND_H */
+1
arch/loongarch/include/asm/vdso.h
··· 7 7 #ifndef __ASM_VDSO_H 8 8 #define __ASM_VDSO_H 9 9 10 + #include <linux/mm.h> 10 11 #include <linux/mm_types.h> 11 12 #include <vdso/datapage.h> 12 13
+14 -1
arch/loongarch/include/asm/vdso/vdso.h
··· 8 8 9 9 #include <asm/asm.h> 10 10 #include <asm/page.h> 11 + #include <asm/vdso.h> 12 + 13 + struct vdso_pcpu_data { 14 + u32 node; 15 + } ____cacheline_aligned_in_smp; 16 + 17 + struct loongarch_vdso_data { 18 + struct vdso_pcpu_data pdata[NR_CPUS]; 19 + struct vdso_data data[CS_BASES]; /* Arch-independent data */ 20 + }; 21 + 22 + #define VDSO_DATA_SIZE PAGE_ALIGN(sizeof(struct loongarch_vdso_data)) 11 23 12 24 static inline unsigned long get_vdso_base(void) 13 25 { ··· 36 24 37 25 static inline const struct vdso_data *get_vdso_data(void) 38 26 { 39 - return (const struct vdso_data *)(get_vdso_base() - PAGE_SIZE); 27 + return (const struct vdso_data *)(get_vdso_base() 28 + - VDSO_DATA_SIZE + SMP_CACHE_BYTES * NR_CPUS); 40 29 } 41 30 42 31 #endif /* __ASSEMBLY__ */
+4
arch/loongarch/kernel/Makefile
··· 15 15 obj-$(CONFIG_CPU_HAS_FPU) += fpu.o 16 16 17 17 obj-$(CONFIG_MODULES) += module.o module-sections.o 18 + obj-$(CONFIG_STACKTRACE) += stacktrace.o 18 19 19 20 obj-$(CONFIG_PROC_FS) += proc.o 20 21 21 22 obj-$(CONFIG_SMP) += smp.o 22 23 23 24 obj-$(CONFIG_NUMA) += numa.o 25 + 26 + obj-$(CONFIG_UNWINDER_GUESS) += unwind_guess.o 27 + obj-$(CONFIG_UNWINDER_PROLOGUE) += unwind_prologue.o 24 28 25 29 CPPFLAGS_vmlinux.lds := $(KBUILD_CFLAGS)
+38
arch/loongarch/kernel/acpi.c
··· 104 104 } 105 105 #endif 106 106 107 + static int __init 108 + acpi_parse_processor(union acpi_subtable_headers *header, const unsigned long end) 109 + { 110 + struct acpi_madt_core_pic *processor = NULL; 111 + 112 + processor = (struct acpi_madt_core_pic *)header; 113 + if (BAD_MADT_ENTRY(processor, end)) 114 + return -EINVAL; 115 + 116 + acpi_table_print_madt_entry(&header->common); 117 + #ifdef CONFIG_SMP 118 + set_processor_mask(processor->core_id, processor->flags); 119 + #endif 120 + 121 + return 0; 122 + } 123 + 124 + static int __init 125 + acpi_parse_eio_master(union acpi_subtable_headers *header, const unsigned long end) 126 + { 127 + static int core = 0; 128 + struct acpi_madt_eio_pic *eiointc = NULL; 129 + 130 + eiointc = (struct acpi_madt_eio_pic *)header; 131 + if (BAD_MADT_ENTRY(eiointc, end)) 132 + return -EINVAL; 133 + 134 + core = eiointc->node * CORES_PER_EIO_NODE; 135 + set_bit(core, &(loongson_sysconf.cores_io_master)); 136 + 137 + return 0; 138 + } 139 + 107 140 static void __init acpi_process_madt(void) 108 141 { 109 142 #ifdef CONFIG_SMP ··· 147 114 __cpu_logical_map[i] = -1; 148 115 } 149 116 #endif 117 + acpi_table_parse_madt(ACPI_MADT_TYPE_CORE_PIC, 118 + acpi_parse_processor, MAX_CORE_PIC); 119 + 120 + acpi_table_parse_madt(ACPI_MADT_TYPE_EIO_PIC, 121 + acpi_parse_eio_master, MAX_IO_PICS); 150 122 151 123 loongson_sysconf.nr_cpus = num_processors; 152 124 }
+2
arch/loongarch/kernel/asm-offsets.c
··· 103 103 OFFSET(THREAD_REG29, task_struct, thread.reg29); 104 104 OFFSET(THREAD_REG30, task_struct, thread.reg30); 105 105 OFFSET(THREAD_REG31, task_struct, thread.reg31); 106 + OFFSET(THREAD_SCHED_RA, task_struct, thread.sched_ra); 107 + OFFSET(THREAD_SCHED_CFA, task_struct, thread.sched_cfa); 106 108 OFFSET(THREAD_CSRCRMD, task_struct, 107 109 thread.csr_crmd); 108 110 OFFSET(THREAD_CSRPRMD, task_struct,
+11 -8
arch/loongarch/kernel/head.S
··· 21 21 csrwr t0, LOONGARCH_CSR_DMWIN0 22 22 li.d t0, CSR_DMW1_INIT # CA, PLV0, 0x9000 xxxx xxxx xxxx 23 23 csrwr t0, LOONGARCH_CSR_DMWIN1 24 + 25 + /* We might not get launched at the address the kernel is linked to, 26 + so we jump there. */ 27 + la.abs t0, 0f 28 + jr t0 29 + 0: 24 30 /* Enable PG */ 25 31 li.w t0, 0xb0 # PLV=0, IE=0, PG=1 26 32 csrwr t0, LOONGARCH_CSR_CRMD ··· 35 29 li.w t0, 0x00 # FPE=0, SXE=0, ASXE=0, BTE=0 36 30 csrwr t0, LOONGARCH_CSR_EUEN 37 31 38 - /* We might not get launched at the address the kernel is linked to, 39 - so we jump there. */ 40 - la.abs t0, 0f 41 - jr t0 42 - 0: 43 32 la t0, __bss_start # clear .bss 44 33 st.d zero, t0, 0 45 34 la t1, __bss_stop - LONGSIZE ··· 75 74 csrwr t0, LOONGARCH_CSR_DMWIN0 76 75 li.d t0, CSR_DMW1_INIT # CA, PLV0 77 76 csrwr t0, LOONGARCH_CSR_DMWIN1 77 + 78 + la.abs t0, 0f 79 + jr t0 80 + 0: 81 + /* Enable PG */ 78 82 li.w t0, 0xb0 # PLV=0, IE=0, PG=1 79 83 csrwr t0, LOONGARCH_CSR_CRMD 80 84 li.w t0, 0x04 # PLV=0, PIE=1, PWE=0 ··· 91 85 ld.d sp, t0, CPU_BOOT_STACK 92 86 ld.d tp, t0, CPU_BOOT_TINFO 93 87 94 - la.abs t0, 0f 95 - jr t0 96 - 0: 97 88 bl start_secondary 98 89 SYM_CODE_END(smpboot_entry) 99 90
+1 -1
arch/loongarch/kernel/proc.c
··· 106 106 { 107 107 unsigned long i = *pos; 108 108 109 - return i < NR_CPUS ? (void *)(i + 1) : NULL; 109 + return i < nr_cpu_ids ? (void *)(i + 1) : NULL; 110 110 } 111 111 112 112 static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+89 -1
arch/loongarch/kernel/process.c
··· 44 44 #include <asm/pgtable.h> 45 45 #include <asm/processor.h> 46 46 #include <asm/reg.h> 47 + #include <asm/unwind.h> 47 48 #include <asm/vdso.h> 48 49 49 50 /* ··· 135 134 childregs = (struct pt_regs *) childksp - 1; 136 135 /* Put the stack after the struct pt_regs. */ 137 136 childksp = (unsigned long) childregs; 137 + p->thread.sched_cfa = 0; 138 138 p->thread.csr_euen = 0; 139 139 p->thread.csr_crmd = csr_read32(LOONGARCH_CSR_CRMD); 140 140 p->thread.csr_prmd = csr_read32(LOONGARCH_CSR_PRMD); ··· 146 144 p->thread.reg23 = (unsigned long)args->fn; 147 145 p->thread.reg24 = (unsigned long)args->fn_arg; 148 146 p->thread.reg01 = (unsigned long)ret_from_kernel_thread; 147 + p->thread.sched_ra = (unsigned long)ret_from_kernel_thread; 149 148 memset(childregs, 0, sizeof(struct pt_regs)); 150 149 childregs->csr_euen = p->thread.csr_euen; 151 150 childregs->csr_crmd = p->thread.csr_crmd; ··· 163 160 164 161 p->thread.reg03 = (unsigned long) childregs; 165 162 p->thread.reg01 = (unsigned long) ret_from_fork; 163 + p->thread.sched_ra = (unsigned long) ret_from_fork; 166 164 167 165 /* 168 166 * New tasks lose permission to use the fpu. This accelerates context ··· 184 180 185 181 unsigned long __get_wchan(struct task_struct *task) 186 182 { 187 - return 0; 183 + unsigned long pc; 184 + struct unwind_state state; 185 + 186 + if (!try_get_task_stack(task)) 187 + return 0; 188 + 189 + unwind_start(&state, task, NULL); 190 + state.sp = thread_saved_fp(task); 191 + get_stack_info(state.sp, state.task, &state.stack_info); 192 + state.pc = thread_saved_ra(task); 193 + #ifdef CONFIG_UNWINDER_PROLOGUE 194 + state.type = UNWINDER_PROLOGUE; 195 + #endif 196 + for (; !unwind_done(&state); unwind_next_frame(&state)) { 197 + pc = unwind_get_return_address(&state); 198 + if (!pc) 199 + break; 200 + if (in_sched_functions(pc)) 201 + continue; 202 + break; 203 + } 204 + 205 + put_task_stack(task); 206 + 207 + return pc; 208 + } 209 + 210 + bool in_irq_stack(unsigned long stack, struct stack_info *info) 211 + { 212 + unsigned long nextsp; 213 + unsigned long begin = (unsigned long)this_cpu_read(irq_stack); 214 + unsigned long end = begin + IRQ_STACK_START; 215 + 216 + if (stack < begin || stack >= end) 217 + return false; 218 + 219 + nextsp = *(unsigned long *)end; 220 + if (nextsp & (SZREG - 1)) 221 + return false; 222 + 223 + info->begin = begin; 224 + info->end = end; 225 + info->next_sp = nextsp; 226 + info->type = STACK_TYPE_IRQ; 227 + 228 + return true; 229 + } 230 + 231 + bool in_task_stack(unsigned long stack, struct task_struct *task, 232 + struct stack_info *info) 233 + { 234 + unsigned long begin = (unsigned long)task_stack_page(task); 235 + unsigned long end = begin + THREAD_SIZE - 32; 236 + 237 + if (stack < begin || stack >= end) 238 + return false; 239 + 240 + info->begin = begin; 241 + info->end = end; 242 + info->next_sp = 0; 243 + info->type = STACK_TYPE_TASK; 244 + 245 + return true; 246 + } 247 + 248 + int get_stack_info(unsigned long stack, struct task_struct *task, 249 + struct stack_info *info) 250 + { 251 + task = task ? : current; 252 + 253 + if (!stack || stack & (SZREG - 1)) 254 + goto unknown; 255 + 256 + if (in_task_stack(stack, task, info)) 257 + return 0; 258 + 259 + if (task != current) 260 + goto unknown; 261 + 262 + if (in_irq_stack(stack, info)) 263 + return 0; 264 + 265 + unknown: 266 + info->type = STACK_TYPE_UNKNOWN; 267 + return -EINVAL; 188 268 } 189 269 190 270 unsigned long stack_top(void)
+1 -4
arch/loongarch/kernel/smp.c
··· 242 242 243 243 static bool io_master(int cpu) 244 244 { 245 - if (cpu == 0) 246 - return true; 247 - 248 - return false; 245 + return test_bit(cpu, &loongson_sysconf.cores_io_master); 249 246 } 250 247 251 248 int loongson3_cpu_disable(void)
+78
arch/loongarch/kernel/stacktrace.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Stack trace management functions 4 + * 5 + * Copyright (C) 2022 Loongson Technology Corporation Limited 6 + */ 7 + #include <linux/sched.h> 8 + #include <linux/stacktrace.h> 9 + #include <linux/uaccess.h> 10 + 11 + #include <asm/stacktrace.h> 12 + #include <asm/unwind.h> 13 + 14 + void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie, 15 + struct task_struct *task, struct pt_regs *regs) 16 + { 17 + unsigned long addr; 18 + struct pt_regs dummyregs; 19 + struct unwind_state state; 20 + 21 + regs = &dummyregs; 22 + 23 + if (task == current) { 24 + regs->regs[3] = (unsigned long)__builtin_frame_address(0); 25 + regs->csr_era = (unsigned long)__builtin_return_address(0); 26 + } else { 27 + regs->regs[3] = thread_saved_fp(task); 28 + regs->csr_era = thread_saved_ra(task); 29 + } 30 + 31 + regs->regs[1] = 0; 32 + for (unwind_start(&state, task, regs); 33 + !unwind_done(&state); unwind_next_frame(&state)) { 34 + addr = unwind_get_return_address(&state); 35 + if (!addr || !consume_entry(cookie, addr)) 36 + break; 37 + } 38 + } 39 + 40 + static int 41 + copy_stack_frame(unsigned long fp, struct stack_frame *frame) 42 + { 43 + int ret = 1; 44 + unsigned long err; 45 + unsigned long __user *user_frame_tail; 46 + 47 + user_frame_tail = (unsigned long *)(fp - sizeof(struct stack_frame)); 48 + if (!access_ok(user_frame_tail, sizeof(*frame))) 49 + return 0; 50 + 51 + pagefault_disable(); 52 + err = (__copy_from_user_inatomic(frame, user_frame_tail, sizeof(*frame))); 53 + if (err || (unsigned long)user_frame_tail >= frame->fp) 54 + ret = 0; 55 + pagefault_enable(); 56 + 57 + return ret; 58 + } 59 + 60 + void arch_stack_walk_user(stack_trace_consume_fn consume_entry, void *cookie, 61 + const struct pt_regs *regs) 62 + { 63 + unsigned long fp = regs->regs[22]; 64 + 65 + while (fp && !((unsigned long)fp & 0xf)) { 66 + struct stack_frame frame; 67 + 68 + frame.fp = 0; 69 + frame.ra = 0; 70 + if (!copy_stack_frame(fp, &frame)) 71 + break; 72 + if (!frame.ra) 73 + break; 74 + if (!consume_entry(cookie, frame.ra)) 75 + break; 76 + fp = frame.fp; 77 + } 78 + }
+2
arch/loongarch/kernel/switch.S
··· 21 21 22 22 cpu_save_nonscratch a0 23 23 stptr.d ra, a0, THREAD_REG01 24 + stptr.d a3, a0, THREAD_SCHED_RA 25 + stptr.d a4, a0, THREAD_SCHED_CFA 24 26 move tp, a2 25 27 cpu_restore_nonscratch a1 26 28
+1 -1
arch/loongarch/kernel/time.c
··· 135 135 136 136 int constant_clockevent_init(void) 137 137 { 138 - unsigned int irq; 138 + int irq; 139 139 unsigned int cpu = smp_processor_id(); 140 140 unsigned long min_delta = 0x600; 141 141 unsigned long max_delta = (1UL << 48) - 1;
+13 -11
arch/loongarch/kernel/traps.c
··· 43 43 #include <asm/stacktrace.h> 44 44 #include <asm/tlb.h> 45 45 #include <asm/types.h> 46 + #include <asm/unwind.h> 46 47 47 48 #include "access-helper.h" 48 49 ··· 65 64 const char *loglvl, bool user) 66 65 { 67 66 unsigned long addr; 68 - unsigned long *sp = (unsigned long *)(regs->regs[3] & ~3); 67 + struct unwind_state state; 68 + struct pt_regs *pregs = (struct pt_regs *)regs; 69 + 70 + if (!task) 71 + task = current; 72 + 73 + if (user_mode(regs)) 74 + state.type = UNWINDER_GUESS; 69 75 70 76 printk("%sCall Trace:", loglvl); 71 - #ifdef CONFIG_KALLSYMS 72 - printk("%s\n", loglvl); 73 - #endif 74 - while (!kstack_end(sp)) { 75 - if (__get_addr(&addr, sp++, user)) { 76 - printk("%s (Bad stack address)", loglvl); 77 - break; 78 - } 79 - if (__kernel_text_address(addr)) 80 - print_ip_sym(loglvl, addr); 77 + for (unwind_start(&state, task, pregs); 78 + !unwind_done(&state); unwind_next_frame(&state)) { 79 + addr = unwind_get_return_address(&state); 80 + print_ip_sym(loglvl, addr); 81 81 } 82 82 printk("%s\n", loglvl); 83 83 }
+67
arch/loongarch/kernel/unwind_guess.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2022 Loongson Technology Corporation Limited 4 + */ 5 + #include <linux/kernel.h> 6 + 7 + #include <asm/unwind.h> 8 + 9 + unsigned long unwind_get_return_address(struct unwind_state *state) 10 + { 11 + if (unwind_done(state)) 12 + return 0; 13 + else if (state->first) 14 + return state->pc; 15 + 16 + return *(unsigned long *)(state->sp); 17 + } 18 + EXPORT_SYMBOL_GPL(unwind_get_return_address); 19 + 20 + void unwind_start(struct unwind_state *state, struct task_struct *task, 21 + struct pt_regs *regs) 22 + { 23 + memset(state, 0, sizeof(*state)); 24 + 25 + if (regs) { 26 + state->sp = regs->regs[3]; 27 + state->pc = regs->csr_era; 28 + } 29 + 30 + state->task = task; 31 + state->first = true; 32 + 33 + get_stack_info(state->sp, state->task, &state->stack_info); 34 + 35 + if (!unwind_done(state) && !__kernel_text_address(state->pc)) 36 + unwind_next_frame(state); 37 + } 38 + EXPORT_SYMBOL_GPL(unwind_start); 39 + 40 + bool unwind_next_frame(struct unwind_state *state) 41 + { 42 + struct stack_info *info = &state->stack_info; 43 + unsigned long addr; 44 + 45 + if (unwind_done(state)) 46 + return false; 47 + 48 + if (state->first) 49 + state->first = false; 50 + 51 + do { 52 + for (state->sp += sizeof(unsigned long); 53 + state->sp < info->end; 54 + state->sp += sizeof(unsigned long)) { 55 + addr = *(unsigned long *)(state->sp); 56 + 57 + if (__kernel_text_address(addr)) 58 + return true; 59 + } 60 + 61 + state->sp = info->next_sp; 62 + 63 + } while (!get_stack_info(state->sp, state->task, info)); 64 + 65 + return false; 66 + } 67 + EXPORT_SYMBOL_GPL(unwind_next_frame);
+176
arch/loongarch/kernel/unwind_prologue.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2022 Loongson Technology Corporation Limited 4 + */ 5 + #include <linux/kallsyms.h> 6 + 7 + #include <asm/inst.h> 8 + #include <asm/ptrace.h> 9 + #include <asm/unwind.h> 10 + 11 + unsigned long unwind_get_return_address(struct unwind_state *state) 12 + { 13 + 14 + if (unwind_done(state)) 15 + return 0; 16 + else if (state->type) 17 + return state->pc; 18 + else if (state->first) 19 + return state->pc; 20 + 21 + return *(unsigned long *)(state->sp); 22 + 23 + } 24 + EXPORT_SYMBOL_GPL(unwind_get_return_address); 25 + 26 + static bool unwind_by_guess(struct unwind_state *state) 27 + { 28 + struct stack_info *info = &state->stack_info; 29 + unsigned long addr; 30 + 31 + for (state->sp += sizeof(unsigned long); 32 + state->sp < info->end; 33 + state->sp += sizeof(unsigned long)) { 34 + addr = *(unsigned long *)(state->sp); 35 + if (__kernel_text_address(addr)) 36 + return true; 37 + } 38 + 39 + return false; 40 + } 41 + 42 + static bool unwind_by_prologue(struct unwind_state *state) 43 + { 44 + struct stack_info *info = &state->stack_info; 45 + union loongarch_instruction *ip, *ip_end; 46 + unsigned long frame_size = 0, frame_ra = -1; 47 + unsigned long size, offset, pc = state->pc; 48 + 49 + if (state->sp >= info->end || state->sp < info->begin) 50 + return false; 51 + 52 + if (!kallsyms_lookup_size_offset(pc, &size, &offset)) 53 + return false; 54 + 55 + ip = (union loongarch_instruction *)(pc - offset); 56 + ip_end = (union loongarch_instruction *)pc; 57 + 58 + while (ip < ip_end) { 59 + if (is_stack_alloc_ins(ip)) { 60 + frame_size = (1 << 12) - ip->reg2i12_format.immediate; 61 + ip++; 62 + break; 63 + } 64 + ip++; 65 + } 66 + 67 + if (!frame_size) { 68 + if (state->first) 69 + goto first; 70 + 71 + return false; 72 + } 73 + 74 + while (ip < ip_end) { 75 + if (is_ra_save_ins(ip)) { 76 + frame_ra = ip->reg2i12_format.immediate; 77 + break; 78 + } 79 + if (is_branch_ins(ip)) 80 + break; 81 + ip++; 82 + } 83 + 84 + if (frame_ra < 0) { 85 + if (state->first) { 86 + state->sp = state->sp + frame_size; 87 + goto first; 88 + } 89 + return false; 90 + } 91 + 92 + if (state->first) 93 + state->first = false; 94 + 95 + state->pc = *(unsigned long *)(state->sp + frame_ra); 96 + state->sp = state->sp + frame_size; 97 + return !!__kernel_text_address(state->pc); 98 + 99 + first: 100 + state->first = false; 101 + if (state->pc == state->ra) 102 + return false; 103 + 104 + state->pc = state->ra; 105 + 106 + return !!__kernel_text_address(state->ra); 107 + } 108 + 109 + void unwind_start(struct unwind_state *state, struct task_struct *task, 110 + struct pt_regs *regs) 111 + { 112 + memset(state, 0, sizeof(*state)); 113 + 114 + if (regs && __kernel_text_address(regs->csr_era)) { 115 + state->pc = regs->csr_era; 116 + state->sp = regs->regs[3]; 117 + state->ra = regs->regs[1]; 118 + state->type = UNWINDER_PROLOGUE; 119 + } 120 + 121 + state->task = task; 122 + state->first = true; 123 + 124 + get_stack_info(state->sp, state->task, &state->stack_info); 125 + 126 + if (!unwind_done(state) && !__kernel_text_address(state->pc)) 127 + unwind_next_frame(state); 128 + } 129 + EXPORT_SYMBOL_GPL(unwind_start); 130 + 131 + bool unwind_next_frame(struct unwind_state *state) 132 + { 133 + struct stack_info *info = &state->stack_info; 134 + struct pt_regs *regs; 135 + unsigned long pc; 136 + 137 + if (unwind_done(state)) 138 + return false; 139 + 140 + do { 141 + switch (state->type) { 142 + case UNWINDER_GUESS: 143 + state->first = false; 144 + if (unwind_by_guess(state)) 145 + return true; 146 + break; 147 + 148 + case UNWINDER_PROLOGUE: 149 + if (unwind_by_prologue(state)) 150 + return true; 151 + 152 + if (info->type == STACK_TYPE_IRQ && 153 + info->end == state->sp) { 154 + regs = (struct pt_regs *)info->next_sp; 155 + pc = regs->csr_era; 156 + 157 + if (user_mode(regs) || !__kernel_text_address(pc)) 158 + return false; 159 + 160 + state->pc = pc; 161 + state->sp = regs->regs[3]; 162 + state->ra = regs->regs[1]; 163 + state->first = true; 164 + get_stack_info(state->sp, state->task, info); 165 + 166 + return true; 167 + } 168 + } 169 + 170 + state->sp = info->next_sp; 171 + 172 + } while (!get_stack_info(state->sp, state->task, info)); 173 + 174 + return false; 175 + } 176 + EXPORT_SYMBOL_GPL(unwind_next_frame);
+15 -10
arch/loongarch/kernel/vdso.c
··· 25 25 extern char vdso_start[], vdso_end[]; 26 26 27 27 /* Kernel-provided data used by the VDSO. */ 28 - static union loongarch_vdso_data { 29 - u8 page[PAGE_SIZE]; 30 - struct vdso_data data[CS_BASES]; 28 + static union { 29 + u8 page[VDSO_DATA_SIZE]; 30 + struct loongarch_vdso_data vdata; 31 31 } loongarch_vdso_data __page_aligned_data; 32 - struct vdso_data *vdso_data = loongarch_vdso_data.data; 32 + 33 33 static struct page *vdso_pages[] = { NULL }; 34 + struct vdso_data *vdso_data = loongarch_vdso_data.vdata.data; 35 + struct vdso_pcpu_data *vdso_pdata = loongarch_vdso_data.vdata.pdata; 34 36 35 37 static int vdso_mremap(const struct vm_special_mapping *sm, struct vm_area_struct *new_vma) 36 38 { ··· 57 55 58 56 static int __init init_vdso(void) 59 57 { 60 - unsigned long i, pfn; 58 + unsigned long i, cpu, pfn; 61 59 62 60 BUG_ON(!PAGE_ALIGNED(vdso_info.vdso)); 63 61 BUG_ON(!PAGE_ALIGNED(vdso_info.size)); 62 + 63 + for_each_possible_cpu(cpu) 64 + vdso_pdata[cpu].node = cpu_to_node(cpu); 64 65 65 66 pfn = __phys_to_pfn(__pa_symbol(vdso_info.vdso)); 66 67 for (i = 0; i < vdso_info.size / PAGE_SIZE; i++) ··· 98 93 99 94 /* 100 95 * Determine total area size. This includes the VDSO data itself 101 - * and the data page. 96 + * and the data pages. 102 97 */ 103 - vvar_size = PAGE_SIZE; 98 + vvar_size = VDSO_DATA_SIZE; 104 99 size = vvar_size + info->size; 105 100 106 101 data_addr = get_unmapped_area(NULL, vdso_base(), size, 0, 0); ··· 108 103 ret = data_addr; 109 104 goto out; 110 105 } 111 - vdso_addr = data_addr + PAGE_SIZE; 106 + vdso_addr = data_addr + VDSO_DATA_SIZE; 112 107 113 108 vma = _install_special_mapping(mm, data_addr, vvar_size, 114 109 VM_READ | VM_MAYREAD, ··· 120 115 121 116 /* Map VDSO data page. */ 122 117 ret = remap_pfn_range(vma, data_addr, 123 - virt_to_phys(vdso_data) >> PAGE_SHIFT, 124 - PAGE_SIZE, PAGE_READONLY); 118 + virt_to_phys(&loongarch_vdso_data) >> PAGE_SHIFT, 119 + vvar_size, PAGE_READONLY); 125 120 if (ret) 126 121 goto out; 127 122
+175
arch/loongarch/pci/acpi.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 4 + */ 5 + #include <linux/pci.h> 6 + #include <linux/acpi.h> 7 + #include <linux/init.h> 8 + #include <linux/irq.h> 9 + #include <linux/slab.h> 10 + #include <linux/pci-acpi.h> 11 + #include <linux/pci-ecam.h> 12 + 13 + #include <asm/pci.h> 14 + #include <asm/numa.h> 15 + #include <asm/loongson.h> 16 + 17 + struct pci_root_info { 18 + struct acpi_pci_root_info common; 19 + struct pci_config_window *cfg; 20 + }; 21 + 22 + void pcibios_add_bus(struct pci_bus *bus) 23 + { 24 + acpi_pci_add_bus(bus); 25 + } 26 + 27 + int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) 28 + { 29 + struct pci_config_window *cfg = bridge->bus->sysdata; 30 + struct acpi_device *adev = to_acpi_device(cfg->parent); 31 + struct device *bus_dev = &bridge->bus->dev; 32 + 33 + ACPI_COMPANION_SET(&bridge->dev, adev); 34 + set_dev_node(bus_dev, pa_to_nid(cfg->res.start)); 35 + 36 + return 0; 37 + } 38 + 39 + int acpi_pci_bus_find_domain_nr(struct pci_bus *bus) 40 + { 41 + struct pci_config_window *cfg = bus->sysdata; 42 + struct acpi_device *adev = to_acpi_device(cfg->parent); 43 + struct acpi_pci_root *root = acpi_driver_data(adev); 44 + 45 + return root->segment; 46 + } 47 + 48 + static void acpi_release_root_info(struct acpi_pci_root_info *ci) 49 + { 50 + struct pci_root_info *info; 51 + 52 + info = container_of(ci, struct pci_root_info, common); 53 + pci_ecam_free(info->cfg); 54 + kfree(ci->ops); 55 + kfree(info); 56 + } 57 + 58 + static int acpi_prepare_root_resources(struct acpi_pci_root_info *ci) 59 + { 60 + int status; 61 + struct resource_entry *entry, *tmp; 62 + struct acpi_device *device = ci->bridge; 63 + 64 + status = acpi_pci_probe_root_resources(ci); 65 + if (status > 0) { 66 + resource_list_for_each_entry_safe(entry, tmp, &ci->resources) { 67 + if (entry->res->flags & IORESOURCE_MEM) { 68 + entry->offset = ci->root->mcfg_addr & GENMASK_ULL(63, 40); 69 + entry->res->start |= entry->offset; 70 + entry->res->end |= entry->offset; 71 + } 72 + } 73 + return status; 74 + } 75 + 76 + resource_list_for_each_entry_safe(entry, tmp, &ci->resources) { 77 + dev_dbg(&device->dev, 78 + "host bridge window %pR (ignored)\n", entry->res); 79 + resource_list_destroy_entry(entry); 80 + } 81 + 82 + return 0; 83 + } 84 + 85 + /* 86 + * Lookup the bus range for the domain in MCFG, and set up config space 87 + * mapping. 88 + */ 89 + static struct pci_config_window * 90 + pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root) 91 + { 92 + int ret, bus_shift; 93 + u16 seg = root->segment; 94 + struct device *dev = &root->device->dev; 95 + struct resource cfgres; 96 + struct resource *bus_res = &root->secondary; 97 + struct pci_config_window *cfg; 98 + const struct pci_ecam_ops *ecam_ops; 99 + 100 + ret = pci_mcfg_lookup(root, &cfgres, &ecam_ops); 101 + if (ret < 0) { 102 + dev_err(dev, "%04x:%pR ECAM region not found, use default value\n", seg, bus_res); 103 + ecam_ops = &loongson_pci_ecam_ops; 104 + root->mcfg_addr = mcfg_addr_init(0); 105 + } 106 + 107 + bus_shift = ecam_ops->bus_shift ? : 20; 108 + 109 + cfgres.start = root->mcfg_addr + (bus_res->start << bus_shift); 110 + cfgres.end = cfgres.start + (resource_size(bus_res) << bus_shift) - 1; 111 + cfgres.flags = IORESOURCE_MEM; 112 + 113 + cfg = pci_ecam_create(dev, &cfgres, bus_res, ecam_ops); 114 + if (IS_ERR(cfg)) { 115 + dev_err(dev, "%04x:%pR error %ld mapping ECAM\n", seg, bus_res, PTR_ERR(cfg)); 116 + return NULL; 117 + } 118 + 119 + return cfg; 120 + } 121 + 122 + struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) 123 + { 124 + struct pci_bus *bus; 125 + struct pci_root_info *info; 126 + struct acpi_pci_root_ops *root_ops; 127 + int domain = root->segment; 128 + int busnum = root->secondary.start; 129 + 130 + info = kzalloc(sizeof(*info), GFP_KERNEL); 131 + if (!info) { 132 + pr_warn("pci_bus %04x:%02x: ignored (out of memory)\n", domain, busnum); 133 + return NULL; 134 + } 135 + 136 + root_ops = kzalloc(sizeof(*root_ops), GFP_KERNEL); 137 + if (!root_ops) { 138 + kfree(info); 139 + return NULL; 140 + } 141 + 142 + info->cfg = pci_acpi_setup_ecam_mapping(root); 143 + if (!info->cfg) { 144 + kfree(info); 145 + kfree(root_ops); 146 + return NULL; 147 + } 148 + 149 + root_ops->release_info = acpi_release_root_info; 150 + root_ops->prepare_resources = acpi_prepare_root_resources; 151 + root_ops->pci_ops = (struct pci_ops *)&info->cfg->ops->pci_ops; 152 + 153 + bus = pci_find_bus(domain, busnum); 154 + if (bus) { 155 + memcpy(bus->sysdata, info->cfg, sizeof(struct pci_config_window)); 156 + kfree(info); 157 + } else { 158 + struct pci_bus *child; 159 + 160 + bus = acpi_pci_root_create(root, root_ops, 161 + &info->common, info->cfg); 162 + if (!bus) { 163 + kfree(info); 164 + kfree(root_ops); 165 + return NULL; 166 + } 167 + 168 + pci_bus_size_bridges(bus); 169 + pci_bus_assign_resources(bus); 170 + list_for_each_entry(child, &bus->children, node) 171 + pcie_bus_configure_settings(child); 172 + } 173 + 174 + return bus; 175 + }
+101
arch/loongarch/pci/pci.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 4 + */ 5 + #include <linux/kernel.h> 6 + #include <linux/export.h> 7 + #include <linux/init.h> 8 + #include <linux/acpi.h> 9 + #include <linux/types.h> 10 + #include <linux/pci.h> 11 + #include <linux/vgaarb.h> 12 + #include <asm/loongson.h> 13 + 14 + #define PCI_DEVICE_ID_LOONGSON_HOST 0x7a00 15 + #define PCI_DEVICE_ID_LOONGSON_DC1 0x7a06 16 + #define PCI_DEVICE_ID_LOONGSON_DC2 0x7a36 17 + 18 + int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn, 19 + int reg, int len, u32 *val) 20 + { 21 + struct pci_bus *bus_tmp = pci_find_bus(domain, bus); 22 + 23 + if (bus_tmp) 24 + return bus_tmp->ops->read(bus_tmp, devfn, reg, len, val); 25 + return -EINVAL; 26 + } 27 + 28 + int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn, 29 + int reg, int len, u32 val) 30 + { 31 + struct pci_bus *bus_tmp = pci_find_bus(domain, bus); 32 + 33 + if (bus_tmp) 34 + return bus_tmp->ops->write(bus_tmp, devfn, reg, len, val); 35 + return -EINVAL; 36 + } 37 + 38 + phys_addr_t mcfg_addr_init(int node) 39 + { 40 + return (((u64)node << 44) | MCFG_EXT_PCICFG_BASE); 41 + } 42 + 43 + static int __init pcibios_init(void) 44 + { 45 + unsigned int lsize; 46 + 47 + /* 48 + * Set PCI cacheline size to that of the highest level in the 49 + * cache hierarchy. 50 + */ 51 + lsize = cpu_dcache_line_size(); 52 + lsize = cpu_vcache_line_size() ? : lsize; 53 + lsize = cpu_scache_line_size() ? : lsize; 54 + 55 + BUG_ON(!lsize); 56 + 57 + pci_dfl_cache_line_size = lsize >> 2; 58 + 59 + pr_debug("PCI: pci_cache_line_size set to %d bytes\n", lsize); 60 + 61 + return 0; 62 + } 63 + 64 + subsys_initcall(pcibios_init); 65 + 66 + int pcibios_device_add(struct pci_dev *dev) 67 + { 68 + int id; 69 + struct irq_domain *dom; 70 + 71 + id = pci_domain_nr(dev->bus); 72 + dom = irq_find_matching_fwnode(get_pch_msi_handle(id), DOMAIN_BUS_PCI_MSI); 73 + dev_set_msi_domain(&dev->dev, dom); 74 + 75 + return 0; 76 + } 77 + 78 + int pcibios_alloc_irq(struct pci_dev *dev) 79 + { 80 + if (acpi_disabled) 81 + return 0; 82 + if (pci_dev_msi_enabled(dev)) 83 + return 0; 84 + return acpi_pci_irq_enable(dev); 85 + } 86 + 87 + static void pci_fixup_vgadev(struct pci_dev *pdev) 88 + { 89 + struct pci_dev *devp = NULL; 90 + 91 + while ((devp = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, devp))) { 92 + if (devp->vendor != PCI_VENDOR_ID_LOONGSON) { 93 + vga_set_default_device(devp); 94 + dev_info(&pdev->dev, 95 + "Overriding boot device as %X:%X\n", 96 + devp->vendor, devp->device); 97 + } 98 + } 99 + } 100 + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_DC1, pci_fixup_vgadev); 101 + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_DC2, pci_fixup_vgadev);
+1 -1
arch/loongarch/vdso/Makefile
··· 6 6 ARCH_REL_TYPE_ABS := R_LARCH_32|R_LARCH_64|R_LARCH_MARK_LA|R_LARCH_JUMP_SLOT 7 7 include $(srctree)/lib/vdso/Makefile 8 8 9 - obj-vdso-y := elf.o vgettimeofday.o sigreturn.o 9 + obj-vdso-y := elf.o vgetcpu.o vgettimeofday.o sigreturn.o 10 10 11 11 # Common compiler flags between ABIs. 12 12 ccflags-vdso := \
+1
arch/loongarch/vdso/vdso.lds.S
··· 58 58 { 59 59 LINUX_5.10 { 60 60 global: 61 + __vdso_getcpu; 61 62 __vdso_clock_getres; 62 63 __vdso_clock_gettime; 63 64 __vdso_gettimeofday;
+43
arch/loongarch/vdso/vgetcpu.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Fast user context implementation of getcpu() 4 + */ 5 + 6 + #include <asm/vdso.h> 7 + #include <linux/getcpu.h> 8 + 9 + static __always_inline int read_cpu_id(void) 10 + { 11 + int cpu_id; 12 + 13 + __asm__ __volatile__( 14 + " rdtime.d $zero, %0\n" 15 + : "=r" (cpu_id) 16 + : 17 + : "memory"); 18 + 19 + return cpu_id; 20 + } 21 + 22 + static __always_inline const struct vdso_pcpu_data *get_pcpu_data(void) 23 + { 24 + return (struct vdso_pcpu_data *)(get_vdso_base() - VDSO_DATA_SIZE); 25 + } 26 + 27 + int __vdso_getcpu(unsigned int *cpu, unsigned int *node, struct getcpu_cache *unused) 28 + { 29 + int cpu_id; 30 + const struct vdso_pcpu_data *data; 31 + 32 + cpu_id = read_cpu_id(); 33 + 34 + if (cpu) 35 + *cpu = cpu_id; 36 + 37 + if (node) { 38 + data = get_pcpu_data(); 39 + *node = data[cpu_id].node; 40 + } 41 + 42 + return 0; 43 + }