mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-30 03:35:56 -04:00
Merge tag 'loongarch-fixes-7.0-2' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
Pull LoongArch fixes from Huacai Chen: "Fix missing NULL checks for kstrdup(), workaround LS2K/LS7A GPU DMA hang bug, emit GNU_EH_FRAME for vDSO correctly, and fix some KVM-related bugs" * tag 'loongarch-fixes-7.0-2' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson: LoongArch: KVM: Fix base address calculation in kvm_eiointc_regs_access() LoongArch: KVM: Handle the case that EIOINTC's coremap is empty LoongArch: KVM: Make kvm_get_vcpu_by_cpuid() more robust LoongArch: vDSO: Emit GNU_EH_FRAME correctly LoongArch: Workaround LS2K/LS7A GPU DMA hang bug LoongArch: Fix missing NULL checks for kstrdup()
This commit is contained in:
@@ -41,4 +41,40 @@
|
||||
.cfi_endproc; \
|
||||
SYM_END(name, SYM_T_NONE)
|
||||
|
||||
/*
|
||||
* This is for the signal handler trampoline, which is used as the return
|
||||
* address of the signal handlers in userspace instead of called normally.
|
||||
* The long standing libgcc bug https://gcc.gnu.org/PR124050 requires a
|
||||
* nop between .cfi_startproc and the actual address of the trampoline, so
|
||||
* we cannot simply use SYM_FUNC_START.
|
||||
*
|
||||
* This wrapper also contains all the .cfi_* directives for recovering
|
||||
* the content of the GPRs and the "return address" (where the rt_sigreturn
|
||||
* syscall will jump to), assuming there is a struct rt_sigframe (where
|
||||
* a struct sigcontext containing those information we need to recover) at
|
||||
* $sp. The "DWARF for the LoongArch(TM) Architecture" manual states
|
||||
* column 0 is for $zero, but it does not make too much sense to
|
||||
* save/restore the hardware zero register. Repurpose this column here
|
||||
* for the return address (here it's not the content of $ra we cannot use
|
||||
* the default column 3).
|
||||
*/
|
||||
#define SYM_SIGFUNC_START(name) \
|
||||
.cfi_startproc; \
|
||||
.cfi_signal_frame; \
|
||||
.cfi_def_cfa 3, RT_SIGFRAME_SC; \
|
||||
.cfi_return_column 0; \
|
||||
.cfi_offset 0, SC_PC; \
|
||||
\
|
||||
.irp num, 1, 2, 3, 4, 5, 6, 7, 8, \
|
||||
9, 10, 11, 12, 13, 14, 15, 16, \
|
||||
17, 18, 19, 20, 21, 22, 23, 24, \
|
||||
25, 26, 27, 28, 29, 30, 31; \
|
||||
.cfi_offset \num, SC_REGS + \num * SZREG; \
|
||||
.endr; \
|
||||
\
|
||||
nop; \
|
||||
SYM_START(name, SYM_L_GLOBAL, SYM_A_ALIGN)
|
||||
|
||||
#define SYM_SIGFUNC_END(name) SYM_FUNC_END(name)
|
||||
|
||||
#endif
|
||||
|
||||
9
arch/loongarch/include/asm/sigframe.h
Normal file
9
arch/loongarch/include/asm/sigframe.h
Normal file
@@ -0,0 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
|
||||
#include <asm/siginfo.h>
|
||||
#include <asm/ucontext.h>
|
||||
|
||||
struct rt_sigframe {
|
||||
struct siginfo rs_info;
|
||||
struct ucontext rs_uctx;
|
||||
};
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/ftrace.h>
|
||||
#include <asm/sigframe.h>
|
||||
#include <vdso/datapage.h>
|
||||
|
||||
static void __used output_ptreg_defines(void)
|
||||
@@ -220,6 +221,7 @@ static void __used output_sc_defines(void)
|
||||
COMMENT("Linux sigcontext offsets.");
|
||||
OFFSET(SC_REGS, sigcontext, sc_regs);
|
||||
OFFSET(SC_PC, sigcontext, sc_pc);
|
||||
OFFSET(RT_SIGFRAME_SC, rt_sigframe, rs_uctx.uc_mcontext);
|
||||
BLANK();
|
||||
}
|
||||
|
||||
|
||||
@@ -42,16 +42,15 @@ static int __init init_cpu_fullname(void)
|
||||
int cpu, ret;
|
||||
char *cpuname;
|
||||
const char *model;
|
||||
struct device_node *root;
|
||||
|
||||
/* Parsing cpuname from DTS model property */
|
||||
root = of_find_node_by_path("/");
|
||||
ret = of_property_read_string(root, "model", &model);
|
||||
ret = of_property_read_string(of_root, "model", &model);
|
||||
if (ret == 0) {
|
||||
cpuname = kstrdup(model, GFP_KERNEL);
|
||||
if (!cpuname)
|
||||
return -ENOMEM;
|
||||
loongson_sysconf.cpuname = strsep(&cpuname, " ");
|
||||
}
|
||||
of_node_put(root);
|
||||
|
||||
if (loongson_sysconf.cpuname && !strncmp(loongson_sysconf.cpuname, "Loongson", 8)) {
|
||||
for (cpu = 0; cpu < NR_CPUS; cpu++)
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <asm/cpu-features.h>
|
||||
#include <asm/fpu.h>
|
||||
#include <asm/lbt.h>
|
||||
#include <asm/sigframe.h>
|
||||
#include <asm/ucontext.h>
|
||||
#include <asm/vdso.h>
|
||||
|
||||
@@ -51,11 +52,6 @@
|
||||
#define lock_lbt_owner() ({ preempt_disable(); pagefault_disable(); })
|
||||
#define unlock_lbt_owner() ({ pagefault_enable(); preempt_enable(); })
|
||||
|
||||
struct rt_sigframe {
|
||||
struct siginfo rs_info;
|
||||
struct ucontext rs_uctx;
|
||||
};
|
||||
|
||||
struct _ctx_layout {
|
||||
struct sctx_info *addr;
|
||||
unsigned int size;
|
||||
|
||||
@@ -83,7 +83,7 @@ static inline void eiointc_update_sw_coremap(struct loongarch_eiointc *s,
|
||||
|
||||
if (!(s->status & BIT(EIOINTC_ENABLE_CPU_ENCODE))) {
|
||||
cpuid = ffs(cpuid) - 1;
|
||||
cpuid = (cpuid >= 4) ? 0 : cpuid;
|
||||
cpuid = ((cpuid < 0) || (cpuid >= 4)) ? 0 : cpuid;
|
||||
}
|
||||
|
||||
vcpu = kvm_get_vcpu_by_cpuid(s->kvm, cpuid);
|
||||
@@ -472,34 +472,34 @@ static int kvm_eiointc_regs_access(struct kvm_device *dev,
|
||||
switch (addr) {
|
||||
case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END:
|
||||
offset = (addr - EIOINTC_NODETYPE_START) / 4;
|
||||
p = s->nodetype + offset * 4;
|
||||
p = (void *)s->nodetype + offset * 4;
|
||||
break;
|
||||
case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END:
|
||||
offset = (addr - EIOINTC_IPMAP_START) / 4;
|
||||
p = &s->ipmap + offset * 4;
|
||||
p = (void *)&s->ipmap + offset * 4;
|
||||
break;
|
||||
case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END:
|
||||
offset = (addr - EIOINTC_ENABLE_START) / 4;
|
||||
p = s->enable + offset * 4;
|
||||
p = (void *)s->enable + offset * 4;
|
||||
break;
|
||||
case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END:
|
||||
offset = (addr - EIOINTC_BOUNCE_START) / 4;
|
||||
p = s->bounce + offset * 4;
|
||||
p = (void *)s->bounce + offset * 4;
|
||||
break;
|
||||
case EIOINTC_ISR_START ... EIOINTC_ISR_END:
|
||||
offset = (addr - EIOINTC_ISR_START) / 4;
|
||||
p = s->isr + offset * 4;
|
||||
p = (void *)s->isr + offset * 4;
|
||||
break;
|
||||
case EIOINTC_COREISR_START ... EIOINTC_COREISR_END:
|
||||
if (cpu >= s->num_cpu)
|
||||
return -EINVAL;
|
||||
|
||||
offset = (addr - EIOINTC_COREISR_START) / 4;
|
||||
p = s->coreisr[cpu] + offset * 4;
|
||||
p = (void *)s->coreisr[cpu] + offset * 4;
|
||||
break;
|
||||
case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END:
|
||||
offset = (addr - EIOINTC_COREMAP_START) / 4;
|
||||
p = s->coremap + offset * 4;
|
||||
p = (void *)s->coremap + offset * 4;
|
||||
break;
|
||||
default:
|
||||
kvm_err("%s: unknown eiointc register, addr = %d\n", __func__, addr);
|
||||
|
||||
@@ -588,6 +588,9 @@ struct kvm_vcpu *kvm_get_vcpu_by_cpuid(struct kvm *kvm, int cpuid)
|
||||
{
|
||||
struct kvm_phyid_map *map;
|
||||
|
||||
if (cpuid < 0)
|
||||
return NULL;
|
||||
|
||||
if (cpuid >= KVM_MAX_PHYID)
|
||||
return NULL;
|
||||
|
||||
|
||||
@@ -5,9 +5,11 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/vgaarb.h>
|
||||
#include <linux/io-64-nonatomic-lo-hi.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/loongson.h>
|
||||
|
||||
@@ -15,6 +17,9 @@
|
||||
#define PCI_DEVICE_ID_LOONGSON_DC1 0x7a06
|
||||
#define PCI_DEVICE_ID_LOONGSON_DC2 0x7a36
|
||||
#define PCI_DEVICE_ID_LOONGSON_DC3 0x7a46
|
||||
#define PCI_DEVICE_ID_LOONGSON_GPU1 0x7a15
|
||||
#define PCI_DEVICE_ID_LOONGSON_GPU2 0x7a25
|
||||
#define PCI_DEVICE_ID_LOONGSON_GPU3 0x7a35
|
||||
|
||||
int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn,
|
||||
int reg, int len, u32 *val)
|
||||
@@ -99,3 +104,78 @@ static void pci_fixup_vgadev(struct pci_dev *pdev)
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_DC1, pci_fixup_vgadev);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_DC2, pci_fixup_vgadev);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_DC3, pci_fixup_vgadev);
|
||||
|
||||
#define CRTC_NUM_MAX 2
|
||||
#define CRTC_OUTPUT_ENABLE 0x100
|
||||
|
||||
static void loongson_gpu_fixup_dma_hang(struct pci_dev *pdev, bool on)
|
||||
{
|
||||
u32 i, val, count, crtc_offset, device;
|
||||
void __iomem *crtc_reg, *base, *regbase;
|
||||
static u32 crtc_status[CRTC_NUM_MAX] = { 0 };
|
||||
|
||||
base = pdev->bus->ops->map_bus(pdev->bus, pdev->devfn + 1, 0);
|
||||
device = readw(base + PCI_DEVICE_ID);
|
||||
|
||||
regbase = ioremap(readq(base + PCI_BASE_ADDRESS_0) & ~0xffull, SZ_64K);
|
||||
if (!regbase) {
|
||||
pci_err(pdev, "Failed to ioremap()\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (device) {
|
||||
case PCI_DEVICE_ID_LOONGSON_DC2:
|
||||
crtc_reg = regbase + 0x1240;
|
||||
crtc_offset = 0x10;
|
||||
break;
|
||||
case PCI_DEVICE_ID_LOONGSON_DC3:
|
||||
crtc_reg = regbase;
|
||||
crtc_offset = 0x400;
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < CRTC_NUM_MAX; i++, crtc_reg += crtc_offset) {
|
||||
val = readl(crtc_reg);
|
||||
|
||||
if (!on)
|
||||
crtc_status[i] = val;
|
||||
|
||||
/* No need to fixup if the status is off at startup. */
|
||||
if (!(crtc_status[i] & CRTC_OUTPUT_ENABLE))
|
||||
continue;
|
||||
|
||||
if (on)
|
||||
val |= CRTC_OUTPUT_ENABLE;
|
||||
else
|
||||
val &= ~CRTC_OUTPUT_ENABLE;
|
||||
|
||||
mb();
|
||||
writel(val, crtc_reg);
|
||||
|
||||
for (count = 0; count < 40; count++) {
|
||||
val = readl(crtc_reg) & CRTC_OUTPUT_ENABLE;
|
||||
if ((on && val) || (!on && !val))
|
||||
break;
|
||||
udelay(1000);
|
||||
}
|
||||
|
||||
pci_info(pdev, "DMA hang fixup at reg[0x%lx]: 0x%x\n",
|
||||
(unsigned long)crtc_reg & 0xffff, readl(crtc_reg));
|
||||
}
|
||||
|
||||
iounmap(regbase);
|
||||
}
|
||||
|
||||
static void pci_fixup_dma_hang_early(struct pci_dev *pdev)
|
||||
{
|
||||
loongson_gpu_fixup_dma_hang(pdev, false);
|
||||
}
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_GPU2, pci_fixup_dma_hang_early);
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_GPU3, pci_fixup_dma_hang_early);
|
||||
|
||||
static void pci_fixup_dma_hang_final(struct pci_dev *pdev)
|
||||
{
|
||||
loongson_gpu_fixup_dma_hang(pdev, true);
|
||||
}
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_GPU2, pci_fixup_dma_hang_final);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_GPU3, pci_fixup_dma_hang_final);
|
||||
|
||||
@@ -26,7 +26,7 @@ cflags-vdso := $(ccflags-vdso) \
|
||||
$(filter -W%,$(filter-out -Wa$(comma)%,$(KBUILD_CFLAGS))) \
|
||||
-std=gnu11 -fms-extensions -O2 -g -fno-strict-aliasing -fno-common -fno-builtin \
|
||||
-fno-stack-protector -fno-jump-tables -DDISABLE_BRANCH_PROFILING \
|
||||
$(call cc-option, -fno-asynchronous-unwind-tables) \
|
||||
$(call cc-option, -fasynchronous-unwind-tables) \
|
||||
$(call cc-option, -fno-stack-protector)
|
||||
aflags-vdso := $(ccflags-vdso) \
|
||||
-D__ASSEMBLY__ -Wa,-gdwarf-2
|
||||
@@ -41,7 +41,7 @@ endif
|
||||
|
||||
# VDSO linker flags.
|
||||
ldflags-y := -Bsymbolic --no-undefined -soname=linux-vdso.so.1 \
|
||||
$(filter -E%,$(KBUILD_CFLAGS)) -shared --build-id -T
|
||||
$(filter -E%,$(KBUILD_CFLAGS)) -shared --build-id --eh-frame-hdr -T
|
||||
|
||||
#
|
||||
# Shared build commands.
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
|
||||
#include <asm/regdef.h>
|
||||
#include <asm/asm.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
|
||||
.section .text
|
||||
.cfi_sections .debug_frame
|
||||
|
||||
SYM_FUNC_START(__vdso_rt_sigreturn)
|
||||
SYM_SIGFUNC_START(__vdso_rt_sigreturn)
|
||||
|
||||
li.w a7, __NR_rt_sigreturn
|
||||
syscall 0
|
||||
|
||||
SYM_FUNC_END(__vdso_rt_sigreturn)
|
||||
SYM_SIGFUNC_END(__vdso_rt_sigreturn)
|
||||
|
||||
Reference in New Issue
Block a user