From 7e5310f216453d4be1f8bfd10be65c2ea250bf84 Mon Sep 17 00:00:00 2001 From: Zhu Donghong Date: Wed, 18 May 2022 15:23:55 +0800 Subject: [PATCH 01/50] anolis: irqchip: add sw64 chip3 builtin LPC interrupt controller driver ANBZ: #4688 This adds an irqchip driver for the secondary interrupt controllers based on sw64 chip3 cpu builtin LPC. Signed-off-by: Zhu Donghong Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- drivers/irqchip/Kconfig | 7 ++ drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-lpc.c | 137 +++++++++++++++++++++++++++++++++ drivers/mfd/lpc_sunway_chip3.c | 130 ------------------------------- 4 files changed, 145 insertions(+), 130 deletions(-) create mode 100644 drivers/irqchip/irq-lpc.c diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index ea9831e49e34..3c9405fc7dc3 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -9,6 +9,13 @@ config SW64_INTC The INTC controls devices interrupts and connects them to each core's local interrupt controller. +config SW64_CHIP3_LPC + bool "SW64 Chip3 Buildin LPC Interrupt Controller" + depends on SW64_CHIP3 + help + This enables support for the LPC interrupt controller bultin in + on chip3 series. + config IRQCHIP def_bool y depends on OF_IRQ diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index c0c8cbe8bd8d..585feca070a5 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_ARCH_SUNXI) += irq-sunxi-nmi.o obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o obj-$(CONFIG_ARM_GIC) += irq-gic.o irq-gic-common.o obj-$(CONFIG_SW64_INTC) += irq-intc-v1.o +obj-$(CONFIG_SW64_CHIP3_LPC) += irq-lpc.o obj-$(CONFIG_ARM_GIC_PM) += irq-gic-pm.o obj-$(CONFIG_ARCH_REALVIEW) += irq-gic-realview.o obj-$(CONFIG_ARM_GIC_V2M) += irq-gic-v2m.o diff --git a/drivers/irqchip/irq-lpc.c b/drivers/irqchip/irq-lpc.c new file mode 100644 index 000000000000..1cbf87478242 --- /dev/null +++ b/drivers/irqchip/irq-lpc.c @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include + +#define LPC_NR_IRQS 16 +#define LPC_IRQ 0x4 +#define LPC_IRQ_MASK 0x8 + +struct lpc_intc_data { + struct irq_domain *domain; + struct irq_chip_generic *gc; +}; + +static void lpc_irq_mask_ack(struct irq_data *data) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); + struct irq_chip_type *ct = irq_data_get_chip_type(data); + unsigned int mask = data->mask; + + irq_gc_lock(gc); + *ct->mask_cache |= mask; + irq_reg_writel(gc, *ct->mask_cache, ct->regs.mask); + irq_reg_writel(gc, mask, ct->regs.ack); + irq_gc_unlock(gc); +} + +static void lpc_irq_handler(struct irq_desc *desc) +{ + struct lpc_intc_data *b = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); + unsigned int irq; + u32 status; + + chained_irq_enter(chip, desc); + + status = irq_reg_readl(b->gc, LPC_IRQ); + + if (status == 0) { + raw_spin_lock(&desc->lock); + handle_bad_irq(desc); + raw_spin_unlock(&desc->lock); + goto out; + } + + while (status) { + irq = __ffs(status); + status &= ~BIT(irq); + generic_handle_irq(irq_find_mapping(b->domain, irq)); + } + +out: + chained_irq_exit(chip, desc); +} + +static int __init lpc_intc_of_init(struct device_node *np, + struct device_node *parent) +{ + unsigned int set = IRQ_NOPROBE | IRQ_LEVEL; + struct lpc_intc_data *data; + struct irq_chip_type *ct; + int parent_irq, ret; + void __iomem *base; + int hwirq = 0; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + base = of_iomap(np, 0); + if (!base) { + pr_err("failed to remap lpc intc registers\n"); + ret = -ENOMEM; + goto out_free; + } + + parent_irq = irq_of_parse_and_map(np, 0); + if (!parent_irq) { + pr_err("failed to find parent interrupt\n"); + ret = -EINVAL; + goto out_unmap; + } + + data->domain = irq_domain_add_linear(np, LPC_NR_IRQS, + &irq_generic_chip_ops, NULL); + if (!data->domain) { + ret = -ENOMEM; + goto out_unmap; + } + + /* Allocate a single Generic IRQ chip for this node */ + ret = irq_alloc_domain_generic_chips(data->domain, 16, 1, np->name, + handle_level_irq, 0, set, + IRQ_GC_INIT_MASK_CACHE); + if (ret) { + pr_err("failed to allocate generic irq chip\n"); + goto out_free_domain; + } + + /* Set the IRQ chaining logic */ + irq_set_chained_handler_and_data(parent_irq, + lpc_irq_handler, data); + + data->gc = irq_get_domain_generic_chip(data->domain, 0); + data->gc->reg_base = base; + data->gc->private = data; + + ct = data->gc->chip_types; + + ct->regs.ack = LPC_IRQ; + ct->regs.mask = LPC_IRQ_MASK; + ct->chip.irq_mask = irq_gc_mask_set_bit; + ct->chip.irq_unmask = irq_gc_mask_clr_bit; + ct->chip.irq_ack = irq_gc_ack_set_bit; + ct->chip.irq_mask_ack = lpc_irq_mask_ack; + + for (hwirq = 0 ; hwirq < 16 ; hwirq++) + irq_create_mapping(data->domain, hwirq); + + /* Enable LPC interrupts */ + writel(0xffffebdd, base + LPC_IRQ_MASK); + + return 0; + +out_free_domain: + irq_domain_remove(data->domain); +out_unmap: + iounmap(base); +out_free: + kfree(data); + return ret; +} +IRQCHIP_DECLARE(sw_lpc_intc, "sw64,lpc_intc", lpc_intc_of_init); diff --git a/drivers/mfd/lpc_sunway_chip3.c b/drivers/mfd/lpc_sunway_chip3.c index 793b557195c2..878aff87c992 100644 --- a/drivers/mfd/lpc_sunway_chip3.c +++ b/drivers/mfd/lpc_sunway_chip3.c @@ -75,53 +75,16 @@ enum { LPC_DMA_SWRST = 0x70, }; -enum { - LPC_IRQ0 = 0, /* 8254 Timer */ - LPC_IRQ1, /* Keyboard */ - LPC_IRQ2, /* Reserved */ - LPC_IRQ3, /* UART */ - LPC_IRQ4, /* UART */ - LPC_IRQ5, /* LPC Parallel Port2 */ - LPC_IRQ6, /* FDC-Floppy Disk Controller */ - LPC_IRQ7, /* LPT-Parallel Port1 */ - LPC_NR_IRQS, - LPC_IRQ8, /* RTC */ - LPC_IRQ9, /* Undefined */ - LPC_IRQ10, /* Undefined */ - LPC_IRQ11, /* Undefined */ - LPC_IRQ12, /* Mouse */ - LPC_IRQ13, /* Undefined */ - LPC_IRQ14, /* Undefined */ - LPC_IRQ15, /* Undefined */ -}; - struct lpc_chip3_adapter { void __iomem *hst_regs; struct device *dev; int irq; - struct irq_chip_generic *gc; unsigned int features; }; static struct resource superio_chip3_resources[] = { { .flags = IORESOURCE_IO, - }, { - .start = LPC_IRQ1, - .flags = IORESOURCE_IRQ, - .name = "i8042_kbd_irq", - }, { - .start = LPC_IRQ12, - .flags = IORESOURCE_IRQ, - .name = "i8042_aux_irq", - }, { - .start = LPC_IRQ5, - .flags = IORESOURCE_IRQ, - .name = "uart0_irq", - }, { - .start = LPC_IRQ4, - .flags = IORESOURCE_IRQ, - .name = "uart1_irq", } }; @@ -218,75 +181,9 @@ static void lpc_fw_flash_init(struct platform_device *pdev, } -static u32 lpc_do_irq(struct lpc_chip3_adapter *lpc_adapter) -{ - u32 irq_status = readl_relaxed(lpc_adapter->hst_regs + LPC_IRQ); - u32 ret = irq_status; - - DBG_LPC("%s irq_status=%#x\n", __func__, irq_status); - while (irq_status) { - int hwirq = fls(irq_status) - 1; - - generic_handle_irq(hwirq); - irq_status &= ~BIT(hwirq); - } - - lpc_writel(lpc_adapter->hst_regs, LPC_IRQ, ret); - return 1; -} - -static void lpc_irq_handler_mfd(struct irq_desc *desc) -{ - unsigned int irq = irq_desc_get_irq(desc); - struct lpc_chip3_adapter *lpc_adapter = irq_get_handler_data(irq); - u32 worked = 0; - - DBG_LPC("enter %s line:%d\n", __func__, __LINE__); - - worked = lpc_do_irq(lpc_adapter); - if (worked == IRQ_HANDLED) - dev_dbg(lpc_adapter->dev, "LPC irq handled.\n"); - - DBG_LPC("leave %s line:%d\n", __func__, __LINE__); -} - -static void lpc_unmask_interrupt_all(struct lpc_chip3_adapter *lpc_adapter) -{ - lpc_writel(lpc_adapter->hst_regs, LPC_IRQ_MASK, 0); -} - -static void lpc_irq_mask_ack(struct irq_data *d) -{ - struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); - struct irq_chip_type *ct = irq_data_get_chip_type(d); - u32 mask = d->mask; - - irq_gc_lock(gc); - *ct->mask_cache |= mask; - irq_reg_writel(gc, *ct->mask_cache, ct->regs.mask); - irq_reg_writel(gc, mask, ct->regs.ack); - irq_gc_unlock(gc); -} - -static void lpc_enable_irqs(struct lpc_chip3_adapter *lpc_adapter) -{ - int interrupt = 0; - - lpc_unmask_interrupt_all(lpc_adapter); - - interrupt = lpc_readl(lpc_adapter->hst_regs, LPC_IRQ); - - lpc_writel(lpc_adapter->hst_regs, LPC_CTL, 0x1600); - interrupt = lpc_readl(lpc_adapter->hst_regs, LPC_IRQ); -} - static int lpc_chip3_probe(struct platform_device *pdev) { int ret; - int num_ct = 1; - int irq_base; - struct irq_chip_generic *gc; - struct irq_chip_type *ct; struct lpc_chip3_adapter *lpc_adapter; struct resource *mem; @@ -312,32 +209,6 @@ static int lpc_chip3_probe(struct platform_device *pdev) lpc_adapter->dev = &pdev->dev; lpc_adapter->features = 0; - lpc_adapter->irq = platform_get_irq(pdev, 0); - if (lpc_adapter->irq < 0) { - dev_err(&pdev->dev, "no irq resource?\n"); - return lpc_adapter->irq; /* -ENXIO */ - } - - irq_base = LPC_IRQ0; - gc = irq_alloc_generic_chip("LPC_CHIP3", num_ct, irq_base, - lpc_adapter->hst_regs, handle_level_irq); - - ct = gc->chip_types; - ct->regs.mask = LPC_IRQ_MASK; - ct->regs.ack = LPC_IRQ; - ct->chip.irq_mask = irq_gc_mask_set_bit; - ct->chip.irq_unmask = irq_gc_mask_clr_bit; - ct->chip.irq_ack = irq_gc_ack_set_bit; - ct->chip.irq_mask_ack = lpc_irq_mask_ack; - irq_setup_generic_chip(gc, IRQ_MSK(LPC_NR_IRQS), 0, 0, - IRQ_NOPROBE | IRQ_LEVEL); - - lpc_adapter->gc = gc; - - irq_set_handler_data(lpc_adapter->irq, lpc_adapter); - irq_set_chained_handler(lpc_adapter->irq, - (irq_flow_handler_t) lpc_irq_handler_mfd); - lpc_enable(lpc_adapter); lpc_mem_flash_init(pdev, lpc_adapter); @@ -350,7 +221,6 @@ static int lpc_chip3_probe(struct platform_device *pdev) goto out_dev; dev_info(lpc_adapter->dev, "probe succeed !\n"); - lpc_enable_irqs(lpc_adapter); return ret; -- Gitee From c2688c19c9a8f13128725a271ab0759e051e6309 Mon Sep 17 00:00:00 2001 From: Zhu Donghong Date: Wed, 18 May 2022 15:24:50 +0800 Subject: [PATCH 02/50] anolis: sw64: add builtin LPC interrupt controller to chip3.dts ANBZ: #4688 This adds corresponding devicetree binding for LPC interrupt controllers on chip3 series cpu. Signed-off-by: Zhu Donghong Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/boot/dts/chip3.dts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/arch/sw_64/boot/dts/chip3.dts b/arch/sw_64/boot/dts/chip3.dts index be2e91ee3279..082506393ac9 100644 --- a/arch/sw_64/boot/dts/chip3.dts +++ b/arch/sw_64/boot/dts/chip3.dts @@ -32,12 +32,20 @@ spiclk: spiclk { }; - intc: interrupt-controller{ + intc: interrupt-controller { compatible = "sw64,sw6_irq_controller"; interrupt-controller; #interrupt-cells = <1>; }; + lpc_intc: interrupt-controller@0x8037 { + compatible = "sw64,lpc_intc"; + reg = <0x8037 0x40000000 0x0 0x8000>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&intc>; + interrupts = <2>; + }; uart: serial0@8033 { #address-cells = <2>; @@ -176,10 +184,8 @@ partition@0 { lpc: lpc@0x8037 { #address-cells = <2>; #size-cells = <2>; - compatible = "sw,sw6b_lpc"; + compatible = "sunway,chip3_lpc"; reg = <0x8037 0x40000000 0x0 0x8000>; - interrupt-parent=<&intc>; - interrupts = <2>; status = "okay"; }; @@ -202,6 +208,8 @@ ipmi-bt@0x8037 { device_type = "ipmi"; compatible = "ipmi-bt"; reg = <0x8037 0x100000e4 0x0 0x10>; + interrupt-parent=<&lpc_intc>; + interrupts = <10>; reg-size = <1>; reg-spacing = <1>; reg-shift = <0>; -- Gitee From 149868fecba589d055c68faa73f329c9b2c3ab15 Mon Sep 17 00:00:00 2001 From: He Chuyue Date: Thu, 19 May 2022 09:06:17 +0800 Subject: [PATCH 03/50] anolis: sw64: fix some structs related to pt_regs ANBZ: #4688 Because of previous modifications to struct pt_regs, this patch fixes struct pt_regs_offset, dbg_reg_def and perf_event_sw64_regs to keep them consistent. Signed-off-by: He Chuyue Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/uapi/asm/perf_regs.h | 7 +++++++ arch/sw_64/kernel/kgdb.c | 14 +++++++------- arch/sw_64/kernel/ptrace.c | 7 +++++++ 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/arch/sw_64/include/uapi/asm/perf_regs.h b/arch/sw_64/include/uapi/asm/perf_regs.h index 426ae642fcc8..1378a7397951 100644 --- a/arch/sw_64/include/uapi/asm/perf_regs.h +++ b/arch/sw_64/include/uapi/asm/perf_regs.h @@ -13,6 +13,13 @@ enum perf_event_sw64_regs { PERF_REG_SW64_R6, PERF_REG_SW64_R7, PERF_REG_SW64_R8, + PERF_REG_SW64_R9, + PERF_REG_SW64_R10, + PERF_REG_SW64_R11, + PERF_REG_SW64_R12, + PERF_REG_SW64_R13, + PERF_REG_SW64_R14, + PERF_REG_SW64_R15, PERF_REG_SW64_R19, PERF_REG_SW64_R20, PERF_REG_SW64_R21, diff --git a/arch/sw_64/kernel/kgdb.c b/arch/sw_64/kernel/kgdb.c index 491f287eede9..ac2f397f1609 100644 --- a/arch/sw_64/kernel/kgdb.c +++ b/arch/sw_64/kernel/kgdb.c @@ -34,13 +34,13 @@ struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = { { "r7", 8, offsetof(struct pt_regs, r7)}, { "r8", 8, offsetof(struct pt_regs, r8)}, - { "r9", 8, -1 }, - { "r10", 8, -1 }, - { "r11", 8, -1 }, - { "r12", 8, -1 }, - { "r13", 8, -1 }, - { "r14", 8, -1 }, - { "r15", 8, -1 }, + { "r9", 8, offsetof(struct pt_regs, r9)}, + { "r10", 8, offsetof(struct pt_regs, r10)}, + { "r11", 8, offsetof(struct pt_regs, r11)}, + { "r12", 8, offsetof(struct pt_regs, r12)}, + { "r13", 8, offsetof(struct pt_regs, r13)}, + { "r14", 8, offsetof(struct pt_regs, r14)}, + { "r15", 8, offsetof(struct pt_regs, r15)}, { "r16", 8, offsetof(struct pt_regs, r16)}, { "r17", 8, offsetof(struct pt_regs, r17)}, diff --git a/arch/sw_64/kernel/ptrace.c b/arch/sw_64/kernel/ptrace.c index ce41d89a54cb..94809804e23e 100644 --- a/arch/sw_64/kernel/ptrace.c +++ b/arch/sw_64/kernel/ptrace.c @@ -619,6 +619,13 @@ static const struct pt_regs_offset regoffset_table[] = { REG_OFFSET_NAME(r6), REG_OFFSET_NAME(r7), REG_OFFSET_NAME(r8), + REG_OFFSET_NAME(r9), + REG_OFFSET_NAME(r10), + REG_OFFSET_NAME(r11), + REG_OFFSET_NAME(r12), + REG_OFFSET_NAME(r13), + REG_OFFSET_NAME(r14), + REG_OFFSET_NAME(r15), REG_OFFSET_NAME(r19), REG_OFFSET_NAME(r20), REG_OFFSET_NAME(r21), -- Gitee From 637e48bd1757656b9427b9ae04788fc38dca69d6 Mon Sep 17 00:00:00 2001 From: He Chuyue Date: Tue, 24 May 2022 16:03:40 +0800 Subject: [PATCH 04/50] anolis: sw64: perf: add exclude_user and exclude_kernel support ANBZ: #4688 Although sw64 have no per-counter usr/os/guest/host bits, we can distinguish user and kernel by sample mode. Signed-off-by: He Chuyue Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/wrperfmon.h | 4 ++++ arch/sw_64/kernel/perf_event.c | 20 +++++++++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/arch/sw_64/include/asm/wrperfmon.h b/arch/sw_64/include/asm/wrperfmon.h index eaa6735b5a25..098702573bfc 100644 --- a/arch/sw_64/include/asm/wrperfmon.h +++ b/arch/sw_64/include/asm/wrperfmon.h @@ -38,6 +38,10 @@ #define PC1_MIN 0x0 #define PC1_MAX 0x37 +#define SW64_PERFCTRL_KM 2 +#define SW64_PERFCTRL_UM 3 +#define SW64_PERFCTRL_AM 4 + /* pc0 events */ #define PC0_INSTRUCTIONS 0x0 #define PC0_BRANCH_INSTRUCTIONS 0x3 diff --git a/arch/sw_64/kernel/perf_event.c b/arch/sw_64/kernel/perf_event.c index d2975e17f666..0d49224ba058 100644 --- a/arch/sw_64/kernel/perf_event.c +++ b/arch/sw_64/kernel/perf_event.c @@ -457,8 +457,8 @@ static void sw64_pmu_start(struct perf_event *event, int flags) hwc->state = 0; - /* counting in all modes, for both counters */ - wrperfmon(PERFMON_CMD_PM, 4); + /* counting in selected modes, for both counters */ + wrperfmon(PERFMON_CMD_PM, hwc->config_base); if (hwc->idx == PERFMON_PC0) { wrperfmon(PERFMON_CMD_EVENT_PC0, hwc->event_base); wrperfmon(PERFMON_CMD_ENABLE, PERFMON_ENABLE_ARGS_PC0); @@ -519,9 +519,12 @@ static int __hw_perf_event_init(struct perf_event *event) const struct sw64_perf_event *event_type; - /* SW64 do not have per-counter usr/os/guest/host bits */ - if (event->attr.exclude_user || event->attr.exclude_kernel || - event->attr.exclude_hv || event->attr.exclude_idle || + /* + * SW64 does not have per-counter usr/os/guest/host bits, + * we can distinguish exclude_user and exclude_kernel by + * sample mode. + */ + if (event->attr.exclude_hv || event->attr.exclude_idle || event->attr.exclude_host || event->attr.exclude_guest) return -EINVAL; @@ -553,6 +556,13 @@ static int __hw_perf_event_init(struct perf_event *event) hwc->event_base = attr->config & 0xff; /* event selector */ } + hwc->config_base = SW64_PERFCTRL_AM; + + if (attr->exclude_user) + hwc->config_base = SW64_PERFCTRL_KM; + if (attr->exclude_kernel) + hwc->config_base = SW64_PERFCTRL_UM; + hwc->config = attr->config; if (!is_sampling_event(event)) -- Gitee From 22d18a8b7dd7b6ec42d20eff183168a22d64d9b4 Mon Sep 17 00:00:00 2001 From: Hang Xiaoqian Date: Wed, 25 May 2022 10:54:25 +0800 Subject: [PATCH 05/50] anolis: sw64: change the value of physical_id in /proc/cpuinfo ANBZ: #4688 The value of physical_id in /proc/cpuinfo should be the socket_id of the processor. Signed-off-by: Hang Xiaoqian Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sw_64/kernel/setup.c b/arch/sw_64/kernel/setup.c index faae7cb3c5a1..4d39db5fb1ef 100644 --- a/arch/sw_64/kernel/setup.c +++ b/arch/sw_64/kernel/setup.c @@ -907,7 +907,7 @@ show_cpuinfo(struct seq_file *f, void *slot) "physical id\t: %d\n" "bogomips\t: %lu.%02lu\n", cpu_freq, cpu_data[i].tcache.size >> 10, - cpu_to_rcid(i), + cpu_topology[i].package_id, loops_per_jiffy / (500000/HZ), (loops_per_jiffy / (5000/HZ)) % 100); -- Gitee From aa3a1083734bc087c676159fd17a0867762edf44 Mon Sep 17 00:00:00 2001 From: Gu Zitao Date: Tue, 24 May 2022 15:28:27 +0800 Subject: [PATCH 06/50] anolis: sw64: add ARCH_TRACEHOOK and regset support ANBZ: #4688 By adding TRACEHOOK support, we can access register sets via PTRACE_GETREGSET and PTRACE_SETREGSET request. The user-visible regset struct user_pt_regs and user_fpsimd_state are added in this patch, and they can be accessed with NT_PRSTATUS and NT_PRFPREG respectively. Besides, PTRACE_{GET,SET}REGS and PTRACE_{GET,SET}FPREGS requests which are implemented in error have never been used on sw64, so we remove them completely. Signed-off-by: Gu Zitao Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/Kconfig | 1 + arch/sw_64/include/uapi/asm/ptrace.h | 18 ++- arch/sw_64/kernel/ptrace.c | 194 +++++++++++++-------------- 3 files changed, 111 insertions(+), 102 deletions(-) diff --git a/arch/sw_64/Kconfig b/arch/sw_64/Kconfig index b9e9b1588200..3f42542683f7 100644 --- a/arch/sw_64/Kconfig +++ b/arch/sw_64/Kconfig @@ -69,6 +69,7 @@ config SW64 select ARCH_HAS_SG_CHAIN select IRQ_FORCED_THREADING select GENERIC_IRQ_MIGRATION if SMP + select HAVE_ARCH_TRACEHOOK select HAVE_FUNCTION_TRACER select HAVE_DYNAMIC_FTRACE select HAVE_FTRACE_MCOUNT_RECORD diff --git a/arch/sw_64/include/uapi/asm/ptrace.h b/arch/sw_64/include/uapi/asm/ptrace.h index ac7ce6b6510b..1169d87c4b9c 100644 --- a/arch/sw_64/include/uapi/asm/ptrace.h +++ b/arch/sw_64/include/uapi/asm/ptrace.h @@ -2,10 +2,20 @@ #ifndef _UAPI_ASM_SW64_PTRACE_H #define _UAPI_ASM_SW64_PTRACE_H -#define PTRACE_GETREGS 12 /* get general purpose registers */ -#define PTRACE_SETREGS 13 /* set general purpose registers */ -#define PTRACE_GETFPREGS 14 /* get floating-point registers */ -#define PTRACE_SETFPREGS 15 /* set floating-point registers */ +/* + * User structures for general purpose, floating point and debug registers. + */ +struct user_pt_regs { + __u64 regs[31]; + __u64 pc; + __u64 pstate; +}; + +struct user_fpsimd_state { + __u64 vregs[124]; + __u64 fpcr; +}; + /* PTRACE_ATTACH is 16 */ /* PTRACE_DETACH is 17 */ diff --git a/arch/sw_64/kernel/ptrace.c b/arch/sw_64/kernel/ptrace.c index 94809804e23e..94fba3569781 100644 --- a/arch/sw_64/kernel/ptrace.c +++ b/arch/sw_64/kernel/ptrace.c @@ -7,6 +7,8 @@ #include #include +#include +#include #include #include @@ -270,123 +272,131 @@ void ptrace_disable(struct task_struct *child) user_disable_single_step(child); } -int ptrace_getregs(struct task_struct *child, __s64 __user *data) +static int gpr_get(struct task_struct *target, + const struct user_regset *regset, + struct membuf to) { - int ret, retval = 0; - int i; - unsigned long regval; + struct pt_regs *regs; + struct user_pt_regs uregs; + int i, ret; - if (!access_ok(data, sizeof(long) * 33)) - return -EIO; + regs = task_pt_regs(target); + for (i = 0; i < 30; i++) + uregs.regs[i] = *(__u64 *)((void *)regs + regoffsets[i]); + + uregs.regs[30] = task_thread_info(target)->pcb.usp; + uregs.pc = regs->pc; + uregs.pstate = regs->ps; + + ret = membuf_write(&to, &uregs, sizeof(uregs)); - /* r0-r15 */ - for (i = 0; i < 16; i++) { - regval = get_reg(child, i); - retval |= __put_user((long)regval, data + i); - } - /* r19-r28 */ - for (i = 19; i < 29; i++) { - regval = get_reg(child, i); - retval |= __put_user((long)regval, data + i - 3); - } - /*SP, PS ,PC,GP*/ - retval |= __put_user((long)(get_reg(child, REG_SP)), data + EF_SP); - retval |= __put_user((long)(get_reg(child, REG_PS)), data + EF_PS); - retval |= __put_user((long)(get_reg(child, REG_PC)), data + EF_PC); - retval |= __put_user((long)(get_reg(child, REG_GP)), data + EF_GP); - /* r16-r18 */ - retval |= __put_user((long)(get_reg(child, 16)), data + EF_A0); - retval |= __put_user((long)(get_reg(child, 17)), data + EF_A1); - retval |= __put_user((long)(get_reg(child, 18)), data + EF_A2); - - ret = retval ? -EIO : 0; return ret; } -int ptrace_setregs(struct task_struct *child, __s64 __user *data) +static int gpr_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) { - int ret, retval = 0; - int i; - unsigned long regval; + struct pt_regs *regs; + struct user_pt_regs uregs; + int i, ret; - if (!access_ok(data, sizeof(long) * 33)) - return -EIO; + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + &uregs, 0, sizeof(uregs)); + if (ret) + return ret; + + regs = task_pt_regs(target); + for (i = 0; i < 30; i++) + *(__u64 *)((void *)regs + regoffsets[i]) = uregs.regs[i]; + + task_thread_info(target)->pcb.usp = uregs.regs[30]; + regs->pc = uregs.pc; + regs->ps = uregs.pstate; - /* r0-r15 */ - for (i = 0; i < 16; i++) { - retval |= __get_user(regval, data + i); - ret = put_reg(child, i, regval); - } - /* r19-r28 */ - for (i = 19; i < 29; i++) { - retval |= __get_user(regval, data + i - 3); - ret = put_reg(child, i, regval); - } - /*SP, PS ,PC,GP*/ - retval |= __get_user(regval, data + EF_SP); - ret = put_reg(child, REG_SP, regval); - retval |= __get_user(regval, data + EF_PS); - ret = put_reg(child, REG_PS, regval); - retval |= __get_user(regval, data + EF_PC); - ret = put_reg(child, REG_PC, regval); - retval |= __get_user(regval, data + EF_GP); - ret = put_reg(child, REG_GP, regval); - /* r16-r18 */ - retval |= __get_user(regval, data + EF_A0); - ret = put_reg(child, 16, regval); - retval |= __get_user(regval, data + EF_A1); - ret = put_reg(child, 17, regval); - retval |= __get_user(regval, data + EF_A2); - ret = put_reg(child, 18, regval); - - ret = retval ? -EIO : 0; return 0; } -int ptrace_getfpregs(struct task_struct *child, __s64 __user *data) +static int fpr_get(struct task_struct *target, + const struct user_regset *regset, + struct membuf to) { - int ret, retval = 0; - int i; - unsigned long regval; + int ret; + struct user_fpsimd_state uregs; - if (!access_ok(data, sizeof(long) * 32)) - return -EIO; + memcpy(uregs.vregs, &target->thread.ctx_fp, + sizeof(struct context_fpregs)); - /* fp0-fp31 */ - for (i = 0; i < 32; i++) { - regval = get_reg(child, REG_F0 + i); - retval |= __put_user((long)regval, data + i); - } + uregs.fpcr = target->thread.fpcr; - ret = retval ? -EIO : 0; - return 0; + ret = membuf_write(&to, &uregs, sizeof(uregs)); + + return ret; } -int ptrace_setfpregs(struct task_struct *child, __s64 __user *data) +static int fpr_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) { - int ret, retval = 0; - int i; - unsigned long regval; + int ret; + struct user_fpsimd_state uregs; - if (!access_ok(data, sizeof(long) * 32)) - return -EIO; + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + &uregs, 0, sizeof(uregs)); - /* fp0-fp31 */ - for (i = 0; i < 32; i++) { - retval |= __get_user(regval, data + i); - ret = put_reg(child, REG_F0 + i, regval); - } + if (ret) + return ret; + + memcpy(&target->thread.ctx_fp, uregs.vregs, + sizeof(struct context_fpregs)); + + target->thread.fpcr = uregs.fpcr; return ret; } +enum sw64_regset { + REGSET_GPR, + REGSET_FPR, +}; + +static const struct user_regset sw64_regsets[] = { + [REGSET_GPR] = { + .core_note_type = NT_PRSTATUS, + .n = ELF_NGREG, + .size = sizeof(elf_greg_t), + .align = sizeof(elf_greg_t), + .regset_get = gpr_get, + .set = gpr_set + }, + [REGSET_FPR] = { + .core_note_type = NT_PRFPREG, + .n = sizeof(struct user_fpsimd_state) / sizeof(u64), + .size = sizeof(u64), + .align = sizeof(u64), + .regset_get = fpr_get, + .set = fpr_set + }, +}; + +static const struct user_regset_view user_sw64_view = { + .name = "sw64", .e_machine = EM_SW64, + .regsets = sw64_regsets, .n = ARRAY_SIZE(sw64_regsets) +}; + +const struct user_regset_view *task_user_regset_view(struct task_struct *task) +{ + return &user_sw64_view; +} + long arch_ptrace(struct task_struct *child, long request, unsigned long addr, unsigned long data) { unsigned long tmp; size_t copied; long ret; - void __user *datavp = (void __user *) data; switch (request) { /* When I and D space are separate, these will need to be fixed. */ @@ -416,18 +426,6 @@ long arch_ptrace(struct task_struct *child, long request, case PTRACE_POKEUSR: /* write the specified register */ ret = put_reg(child, addr, data); break; - case PTRACE_GETREGS: - ret = ptrace_getregs(child, datavp); - break; - case PTRACE_SETREGS: - ret = ptrace_setregs(child, datavp); - break; - case PTRACE_GETFPREGS: - ret = ptrace_getfpregs(child, datavp); - break; - case PTRACE_SETFPREGS: - ret = ptrace_setfpregs(child, datavp); - break; default: ret = ptrace_request(child, request, addr, data); break; -- Gitee From 47eed7083e413b538747b3ace3b083f1581f2fa6 Mon Sep 17 00:00:00 2001 From: He Sheng Date: Thu, 26 May 2022 11:00:48 +0800 Subject: [PATCH 07/50] anolis: sw64: merge user_fpsimd_state into thread_struct ANBZ: #4688 The user_fpsimd_state struct has been defined to hold fpu state which is also held in thread_struct. To reuse this struct, this patch makes a little change to user_fpsimd_state, then replace struct context_fpregs and fpcr of thread_struct. This patch also moves definition of task_pt_regs and mm_segment_t to appropriate headers to avoid compile errors. Signed-off-by: He Sheng Reviewed-by: Cui Wei Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/processor.h | 45 +-------- arch/sw_64/include/asm/ptrace.h | 4 - arch/sw_64/include/asm/thread_info.h | 5 + arch/sw_64/include/uapi/asm/ptrace.h | 8 +- arch/sw_64/kernel/asm-offsets.c | 67 +++++++------- arch/sw_64/kernel/fpu.S | 134 +++++++++++++-------------- arch/sw_64/kernel/process.c | 2 +- arch/sw_64/kernel/ptrace.c | 51 +++------- arch/sw_64/kernel/signal.c | 13 +-- arch/sw_64/kvm/entry.S | 40 ++++---- 10 files changed, 155 insertions(+), 214 deletions(-) diff --git a/arch/sw_64/include/asm/processor.h b/arch/sw_64/include/asm/processor.h index 67d3b4368987..08e8cc8e5428 100644 --- a/arch/sw_64/include/asm/processor.h +++ b/arch/sw_64/include/asm/processor.h @@ -9,6 +9,10 @@ #define _ASM_SW64_PROCESSOR_H #include /* for ADDR_LIMIT_32BIT */ +#include + +#define task_pt_regs(task) \ + ((struct pt_regs *) (task_stack_page(task) + 2 * PAGE_SIZE) - 1) /* * Returns current instruction pointer ("program counter"). @@ -37,47 +41,8 @@ #define TASK_UNMAPPED_BASE \ ((current->personality & ADDR_LIMIT_32BIT) ? 0x40000000 : UNMAPPED_BASE) -typedef struct { - unsigned long seg; -} mm_segment_t; - -struct context_fpregs { - unsigned long f0[4]; - unsigned long f1[4]; - unsigned long f2[4]; - unsigned long f3[4]; - unsigned long f4[4]; - unsigned long f5[4]; - unsigned long f6[4]; - unsigned long f7[4]; - unsigned long f8[4]; - unsigned long f9[4]; - unsigned long f10[4]; - unsigned long f11[4]; - unsigned long f12[4]; - unsigned long f13[4]; - unsigned long f14[4]; - unsigned long f15[4]; - unsigned long f16[4]; - unsigned long f17[4]; - unsigned long f18[4]; - unsigned long f19[4]; - unsigned long f20[4]; - unsigned long f21[4]; - unsigned long f22[4]; - unsigned long f23[4]; - unsigned long f24[4]; - unsigned long f25[4]; - unsigned long f26[4]; - unsigned long f27[4]; - unsigned long f28[4]; - unsigned long f29[4]; - unsigned long f30[4]; -} __aligned(32); /* 256 bits aligned for simd */ - struct thread_struct { - struct context_fpregs ctx_fp; - unsigned long fpcr; + struct user_fpsimd_state fpstate; /* Callee-saved registers */ unsigned long ra; unsigned long s[7]; /* s0 ~ s6 */ diff --git a/arch/sw_64/include/asm/ptrace.h b/arch/sw_64/include/asm/ptrace.h index 85f7a47fdee3..ac9943015663 100644 --- a/arch/sw_64/include/asm/ptrace.h +++ b/arch/sw_64/include/asm/ptrace.h @@ -3,10 +3,8 @@ #define _ASM_SW64_PTRACE_H #include -#include #include #include -#include #include /* @@ -65,8 +63,6 @@ struct pt_regs { #define kernel_stack_pointer(regs) (((regs->ps) >> 4) & (TASK_SIZE - 1)) #define instruction_pointer_set(regs, val) ((regs)->pc = val) -#define task_pt_regs(task) \ - ((struct pt_regs *) (task_stack_page(task) + 2 * PAGE_SIZE) - 1) #define current_pt_regs() \ ((struct pt_regs *) ((char *)current_thread_info() + 2 * PAGE_SIZE) - 1) diff --git a/arch/sw_64/include/asm/thread_info.h b/arch/sw_64/include/asm/thread_info.h index cffb09fc6262..33b95f815448 100644 --- a/arch/sw_64/include/asm/thread_info.h +++ b/arch/sw_64/include/asm/thread_info.h @@ -9,6 +9,11 @@ #include #include +typedef struct { + unsigned long seg; +} mm_segment_t; + + struct pcb_struct { unsigned long ksp; unsigned long usp; diff --git a/arch/sw_64/include/uapi/asm/ptrace.h b/arch/sw_64/include/uapi/asm/ptrace.h index 1169d87c4b9c..a45b10b8914a 100644 --- a/arch/sw_64/include/uapi/asm/ptrace.h +++ b/arch/sw_64/include/uapi/asm/ptrace.h @@ -11,9 +11,15 @@ struct user_pt_regs { __u64 pstate; }; +/* 256 bits aligned for simd */ +struct fpreg { + __u64 v[4] __attribute__((aligned(32))); +}; + struct user_fpsimd_state { - __u64 vregs[124]; + struct fpreg fp[31]; __u64 fpcr; + __u64 __reserved[3]; }; /* PTRACE_ATTACH is 16 */ diff --git a/arch/sw_64/kernel/asm-offsets.c b/arch/sw_64/kernel/asm-offsets.c index 5dc59346996f..0c7e1e26eb05 100644 --- a/arch/sw_64/kernel/asm-offsets.c +++ b/arch/sw_64/kernel/asm-offsets.c @@ -178,40 +178,39 @@ void foo(void) DEFINE(HOST_INT_R16, offsetof(struct host_int_args, r16)); BLANK(); - DEFINE(TASK_THREAD, offsetof(struct task_struct, thread)); - DEFINE(THREAD_CTX_FP, offsetof(struct thread_struct, ctx_fp)); - DEFINE(THREAD_FPCR, offsetof(struct thread_struct, fpcr)); - DEFINE(CTX_FP_F0, offsetof(struct context_fpregs, f0)); - DEFINE(CTX_FP_F1, offsetof(struct context_fpregs, f1)); - DEFINE(CTX_FP_F2, offsetof(struct context_fpregs, f2)); - DEFINE(CTX_FP_F3, offsetof(struct context_fpregs, f3)); - DEFINE(CTX_FP_F4, offsetof(struct context_fpregs, f4)); - DEFINE(CTX_FP_F5, offsetof(struct context_fpregs, f5)); - DEFINE(CTX_FP_F6, offsetof(struct context_fpregs, f6)); - DEFINE(CTX_FP_F7, offsetof(struct context_fpregs, f7)); - DEFINE(CTX_FP_F8, offsetof(struct context_fpregs, f8)); - DEFINE(CTX_FP_F9, offsetof(struct context_fpregs, f9)); - DEFINE(CTX_FP_F10, offsetof(struct context_fpregs, f10)); - DEFINE(CTX_FP_F11, offsetof(struct context_fpregs, f11)); - DEFINE(CTX_FP_F12, offsetof(struct context_fpregs, f12)); - DEFINE(CTX_FP_F13, offsetof(struct context_fpregs, f13)); - DEFINE(CTX_FP_F14, offsetof(struct context_fpregs, f14)); - DEFINE(CTX_FP_F15, offsetof(struct context_fpregs, f15)); - DEFINE(CTX_FP_F16, offsetof(struct context_fpregs, f16)); - DEFINE(CTX_FP_F17, offsetof(struct context_fpregs, f17)); - DEFINE(CTX_FP_F18, offsetof(struct context_fpregs, f18)); - DEFINE(CTX_FP_F19, offsetof(struct context_fpregs, f19)); - DEFINE(CTX_FP_F20, offsetof(struct context_fpregs, f20)); - DEFINE(CTX_FP_F21, offsetof(struct context_fpregs, f21)); - DEFINE(CTX_FP_F22, offsetof(struct context_fpregs, f22)); - DEFINE(CTX_FP_F23, offsetof(struct context_fpregs, f23)); - DEFINE(CTX_FP_F24, offsetof(struct context_fpregs, f24)); - DEFINE(CTX_FP_F25, offsetof(struct context_fpregs, f25)); - DEFINE(CTX_FP_F26, offsetof(struct context_fpregs, f26)); - DEFINE(CTX_FP_F27, offsetof(struct context_fpregs, f27)); - DEFINE(CTX_FP_F28, offsetof(struct context_fpregs, f28)); - DEFINE(CTX_FP_F29, offsetof(struct context_fpregs, f29)); - DEFINE(CTX_FP_F30, offsetof(struct context_fpregs, f30)); + OFFSET(TASK_THREAD, task_struct, thread); + OFFSET(TASK_THREAD_F0, task_struct, thread.fpstate.fp[0]); + OFFSET(TASK_THREAD_F1, task_struct, thread.fpstate.fp[1]); + OFFSET(TASK_THREAD_F2, task_struct, thread.fpstate.fp[2]); + OFFSET(TASK_THREAD_F3, task_struct, thread.fpstate.fp[3]); + OFFSET(TASK_THREAD_F4, task_struct, thread.fpstate.fp[4]); + OFFSET(TASK_THREAD_F5, task_struct, thread.fpstate.fp[5]); + OFFSET(TASK_THREAD_F6, task_struct, thread.fpstate.fp[6]); + OFFSET(TASK_THREAD_F7, task_struct, thread.fpstate.fp[7]); + OFFSET(TASK_THREAD_F8, task_struct, thread.fpstate.fp[8]); + OFFSET(TASK_THREAD_F9, task_struct, thread.fpstate.fp[9]); + OFFSET(TASK_THREAD_F10, task_struct, thread.fpstate.fp[10]); + OFFSET(TASK_THREAD_F11, task_struct, thread.fpstate.fp[11]); + OFFSET(TASK_THREAD_F12, task_struct, thread.fpstate.fp[12]); + OFFSET(TASK_THREAD_F13, task_struct, thread.fpstate.fp[13]); + OFFSET(TASK_THREAD_F14, task_struct, thread.fpstate.fp[14]); + OFFSET(TASK_THREAD_F15, task_struct, thread.fpstate.fp[15]); + OFFSET(TASK_THREAD_F16, task_struct, thread.fpstate.fp[16]); + OFFSET(TASK_THREAD_F17, task_struct, thread.fpstate.fp[17]); + OFFSET(TASK_THREAD_F18, task_struct, thread.fpstate.fp[18]); + OFFSET(TASK_THREAD_F19, task_struct, thread.fpstate.fp[19]); + OFFSET(TASK_THREAD_F20, task_struct, thread.fpstate.fp[20]); + OFFSET(TASK_THREAD_F21, task_struct, thread.fpstate.fp[21]); + OFFSET(TASK_THREAD_F22, task_struct, thread.fpstate.fp[22]); + OFFSET(TASK_THREAD_F23, task_struct, thread.fpstate.fp[23]); + OFFSET(TASK_THREAD_F24, task_struct, thread.fpstate.fp[24]); + OFFSET(TASK_THREAD_F25, task_struct, thread.fpstate.fp[25]); + OFFSET(TASK_THREAD_F26, task_struct, thread.fpstate.fp[26]); + OFFSET(TASK_THREAD_F27, task_struct, thread.fpstate.fp[27]); + OFFSET(TASK_THREAD_F28, task_struct, thread.fpstate.fp[28]); + OFFSET(TASK_THREAD_F29, task_struct, thread.fpstate.fp[29]); + OFFSET(TASK_THREAD_F30, task_struct, thread.fpstate.fp[30]); + OFFSET(TASK_THREAD_FPCR, task_struct, thread.fpstate.fpcr); BLANK(); OFFSET(TASK_THREAD_RA, task_struct, thread.ra); OFFSET(TASK_THREAD_S0, task_struct, thread.s[0]); diff --git a/arch/sw_64/kernel/fpu.S b/arch/sw_64/kernel/fpu.S index 25dcf4740525..3cb3bfab08e8 100644 --- a/arch/sw_64/kernel/fpu.S +++ b/arch/sw_64/kernel/fpu.S @@ -8,49 +8,46 @@ .set noat ENTRY(__fpstate_save) /* a0: prev task */ - ldi a0, TASK_THREAD(a0) - ldi t0, THREAD_CTX_FP(a0) - vstd $f0, CTX_FP_F0(t0) - vstd $f1, CTX_FP_F1(t0) - vstd $f2, CTX_FP_F2(t0) - vstd $f3, CTX_FP_F3(t0) - vstd $f4, CTX_FP_F4(t0) - vstd $f5, CTX_FP_F5(t0) - vstd $f6, CTX_FP_F6(t0) - vstd $f7, CTX_FP_F7(t0) - vstd $f8, CTX_FP_F8(t0) - vstd $f9, CTX_FP_F9(t0) - vstd $f10, CTX_FP_F10(t0) - vstd $f11, CTX_FP_F11(t0) - vstd $f12, CTX_FP_F12(t0) - vstd $f13, CTX_FP_F13(t0) - vstd $f14, CTX_FP_F14(t0) - vstd $f15, CTX_FP_F15(t0) - vstd $f16, CTX_FP_F16(t0) - vstd $f17, CTX_FP_F17(t0) - vstd $f18, CTX_FP_F18(t0) - vstd $f19, CTX_FP_F19(t0) - vstd $f20, CTX_FP_F20(t0) - vstd $f21, CTX_FP_F21(t0) - vstd $f22, CTX_FP_F22(t0) - vstd $f23, CTX_FP_F23(t0) - vstd $f24, CTX_FP_F24(t0) - vstd $f25, CTX_FP_F25(t0) - vstd $f26, CTX_FP_F26(t0) - vstd $f27, CTX_FP_F27(t0) + vstd $f0, TASK_THREAD_F0(a0) + vstd $f1, TASK_THREAD_F1(a0) + vstd $f2, TASK_THREAD_F2(a0) + vstd $f3, TASK_THREAD_F3(a0) + vstd $f4, TASK_THREAD_F4(a0) + vstd $f5, TASK_THREAD_F5(a0) + vstd $f6, TASK_THREAD_F6(a0) + vstd $f7, TASK_THREAD_F7(a0) + vstd $f8, TASK_THREAD_F8(a0) + vstd $f9, TASK_THREAD_F9(a0) + vstd $f10, TASK_THREAD_F10(a0) + vstd $f11, TASK_THREAD_F11(a0) + vstd $f12, TASK_THREAD_F12(a0) + vstd $f13, TASK_THREAD_F13(a0) + vstd $f14, TASK_THREAD_F14(a0) + vstd $f15, TASK_THREAD_F15(a0) + vstd $f16, TASK_THREAD_F16(a0) + vstd $f17, TASK_THREAD_F17(a0) + vstd $f18, TASK_THREAD_F18(a0) + vstd $f19, TASK_THREAD_F19(a0) + vstd $f20, TASK_THREAD_F20(a0) + vstd $f21, TASK_THREAD_F21(a0) + vstd $f22, TASK_THREAD_F22(a0) + vstd $f23, TASK_THREAD_F23(a0) + vstd $f24, TASK_THREAD_F24(a0) + vstd $f25, TASK_THREAD_F25(a0) + vstd $f26, TASK_THREAD_F26(a0) + vstd $f27, TASK_THREAD_F27(a0) rfpcr $f0 - vstd $f28, CTX_FP_F28(t0) - vstd $f29, CTX_FP_F29(t0) - vstd $f30, CTX_FP_F30(t0) - fstd $f0, THREAD_FPCR(a0) - vldd $f0, CTX_FP_F0(t0) + vstd $f28, TASK_THREAD_F28(a0) + vstd $f29, TASK_THREAD_F29(a0) + vstd $f30, TASK_THREAD_F30(a0) + fstd $f0, TASK_THREAD_FPCR(a0) + vldd $f0, TASK_THREAD_F0(a0) ret END(__fpstate_save) ENTRY(__fpstate_restore) /* a0: next task */ - ldi a0, TASK_THREAD(a0) - fldd $f0, THREAD_FPCR(a0) + fldd $f0, TASK_THREAD_FPCR(a0) wfpcr $f0 fimovd $f0, t1 and t1, 0x3, t1 @@ -70,37 +67,36 @@ $setfpec_1: $setfpec_2: setfpec2 $setfpec_over: - ldi t0, THREAD_CTX_FP(a0) - vldd $f0, CTX_FP_F0(t0) - vldd $f1, CTX_FP_F1(t0) - vldd $f2, CTX_FP_F2(t0) - vldd $f3, CTX_FP_F3(t0) - vldd $f4, CTX_FP_F4(t0) - vldd $f5, CTX_FP_F5(t0) - vldd $f6, CTX_FP_F6(t0) - vldd $f7, CTX_FP_F7(t0) - vldd $f8, CTX_FP_F8(t0) - vldd $f9, CTX_FP_F9(t0) - vldd $f10, CTX_FP_F10(t0) - vldd $f11, CTX_FP_F11(t0) - vldd $f12, CTX_FP_F12(t0) - vldd $f13, CTX_FP_F13(t0) - vldd $f14, CTX_FP_F14(t0) - vldd $f15, CTX_FP_F15(t0) - vldd $f16, CTX_FP_F16(t0) - vldd $f17, CTX_FP_F17(t0) - vldd $f18, CTX_FP_F18(t0) - vldd $f19, CTX_FP_F19(t0) - vldd $f20, CTX_FP_F20(t0) - vldd $f21, CTX_FP_F21(t0) - vldd $f22, CTX_FP_F22(t0) - vldd $f23, CTX_FP_F23(t0) - vldd $f24, CTX_FP_F24(t0) - vldd $f25, CTX_FP_F25(t0) - vldd $f26, CTX_FP_F26(t0) - vldd $f27, CTX_FP_F27(t0) - vldd $f28, CTX_FP_F28(t0) - vldd $f29, CTX_FP_F29(t0) - vldd $f30, CTX_FP_F30(t0) + vldd $f0, TASK_THREAD_F0(a0) + vldd $f1, TASK_THREAD_F1(a0) + vldd $f2, TASK_THREAD_F2(a0) + vldd $f3, TASK_THREAD_F3(a0) + vldd $f4, TASK_THREAD_F4(a0) + vldd $f5, TASK_THREAD_F5(a0) + vldd $f6, TASK_THREAD_F6(a0) + vldd $f7, TASK_THREAD_F7(a0) + vldd $f8, TASK_THREAD_F8(a0) + vldd $f9, TASK_THREAD_F9(a0) + vldd $f10, TASK_THREAD_F10(a0) + vldd $f11, TASK_THREAD_F11(a0) + vldd $f12, TASK_THREAD_F12(a0) + vldd $f13, TASK_THREAD_F13(a0) + vldd $f14, TASK_THREAD_F14(a0) + vldd $f15, TASK_THREAD_F15(a0) + vldd $f16, TASK_THREAD_F16(a0) + vldd $f17, TASK_THREAD_F17(a0) + vldd $f18, TASK_THREAD_F18(a0) + vldd $f19, TASK_THREAD_F19(a0) + vldd $f20, TASK_THREAD_F20(a0) + vldd $f21, TASK_THREAD_F21(a0) + vldd $f22, TASK_THREAD_F22(a0) + vldd $f23, TASK_THREAD_F23(a0) + vldd $f24, TASK_THREAD_F24(a0) + vldd $f25, TASK_THREAD_F25(a0) + vldd $f26, TASK_THREAD_F26(a0) + vldd $f27, TASK_THREAD_F27(a0) + vldd $f28, TASK_THREAD_F28(a0) + vldd $f29, TASK_THREAD_F29(a0) + vldd $f30, TASK_THREAD_F30(a0) ret END(__fpstate_restore) diff --git a/arch/sw_64/kernel/process.c b/arch/sw_64/kernel/process.c index 6b5f0f3a8345..308675d29c04 100644 --- a/arch/sw_64/kernel/process.c +++ b/arch/sw_64/kernel/process.c @@ -256,7 +256,7 @@ EXPORT_SYMBOL(dump_elf_task); int dump_elf_task_fp(elf_fpreg_t *dest, struct task_struct *task) { - memcpy(dest, &task->thread.ctx_fp, 32 * 8); + memcpy(dest, &task->thread.fpstate, 32 * 8); return 1; } EXPORT_SYMBOL(dump_elf_task_fp); diff --git a/arch/sw_64/kernel/ptrace.c b/arch/sw_64/kernel/ptrace.c index 94fba3569781..bdbd0d97a130 100644 --- a/arch/sw_64/kernel/ptrace.c +++ b/arch/sw_64/kernel/ptrace.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -55,9 +56,6 @@ enum { REG_GP = 29 }; -#define FP_REG(fp_regno, vector_regno) \ - (fp_regno * 32 + vector_regno * 8) - #define R(x) ((size_t) &((struct pt_regs *)0)->x) short regoffsets[32] = { @@ -91,8 +89,8 @@ static unsigned long zero; static unsigned long * get_reg_addr(struct task_struct *task, unsigned long regno) { - unsigned long *addr; - int fp_regno, vector_regno; + void *addr; + int fno, vno; switch (regno) { case USP: @@ -108,9 +106,8 @@ get_reg_addr(struct task_struct *task, unsigned long regno) addr = (void *)task_pt_regs(task) + regoffsets[regno]; break; case FPREG_BASE ... FPREG_END: - fp_regno = regno - FPREG_BASE; - vector_regno = 0; - addr = (void *)((unsigned long)&task->thread.ctx_fp + FP_REG(fp_regno, vector_regno)); + fno = regno - FPREG_BASE; + addr = &task->thread.fpstate.fp[fno].v[0]; break; case VECREG_BASE ... VECREG_END: /* @@ -121,12 +118,12 @@ get_reg_addr(struct task_struct *task, unsigned long regno) addr = &zero; break; } - fp_regno = (regno - VECREG_BASE) & 0x1f; - vector_regno = 1 + ((regno - VECREG_BASE) >> 5); - addr = (void *)((unsigned long)&task->thread.ctx_fp + FP_REG(fp_regno, vector_regno)); + fno = (regno - VECREG_BASE) & 0x1f; + vno = 1 + ((regno - VECREG_BASE) >> 5); + addr = &task->thread.fpstate.fp[fno].v[vno]; break; case FPCR: - addr = (void *)&task->thread.fpcr; + addr = &task->thread.fpstate.fpcr; break; case PC: addr = (void *)task_pt_regs(task) + PT_REGS_PC; @@ -322,17 +319,9 @@ static int fpr_get(struct task_struct *target, const struct user_regset *regset, struct membuf to) { - int ret; - struct user_fpsimd_state uregs; - - memcpy(uregs.vregs, &target->thread.ctx_fp, - sizeof(struct context_fpregs)); - - uregs.fpcr = target->thread.fpcr; - - ret = membuf_write(&to, &uregs, sizeof(uregs)); - return ret; + return membuf_write(&to, &target->thread.fpstate, + sizeof(struct user_fpsimd_state)); } static int fpr_set(struct task_struct *target, @@ -340,21 +329,9 @@ static int fpr_set(struct task_struct *target, unsigned int pos, unsigned int count, const void *kbuf, const void __user *ubuf) { - int ret; - struct user_fpsimd_state uregs; - - ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, - &uregs, 0, sizeof(uregs)); - - if (ret) - return ret; - - memcpy(&target->thread.ctx_fp, uregs.vregs, - sizeof(struct context_fpregs)); - - target->thread.fpcr = uregs.fpcr; - - return ret; + return user_regset_copyin(&pos, &count, &kbuf, &ubuf, + &target->thread.fpstate, 0, + sizeof(struct user_fpsimd_state)); } enum sw64_regset { diff --git a/arch/sw_64/kernel/signal.c b/arch/sw_64/kernel/signal.c index 887326812624..6a6203ccb04f 100644 --- a/arch/sw_64/kernel/signal.c +++ b/arch/sw_64/kernel/signal.c @@ -100,9 +100,10 @@ restore_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs) err |= __get_user(usp, sc->sc_regs+30); wrusp(usp); /* simd-fp */ - err |= __copy_from_user(¤t->thread.ctx_fp, - &sc->sc_fpregs, sizeof(struct context_fpregs)); - err |= __get_user(current->thread.fpcr, &sc->sc_fpcr); + err |= __copy_from_user(¤t->thread.fpstate, &sc->sc_fpregs, + offsetof(struct user_fpsimd_state, fpcr)); + err |= __get_user(current->thread.fpstate.fpcr, &sc->sc_fpcr); + if (likely(!err)) __fpstate_restore(current); @@ -230,9 +231,9 @@ setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, err |= __put_user(0, sc->sc_regs+31); /* simd-fp */ __fpstate_save(current); - err |= __copy_to_user(&sc->sc_fpregs, - ¤t->thread.ctx_fp, sizeof(struct context_fpregs)); - err |= __put_user(current->thread.fpcr, &sc->sc_fpcr); + err |= __copy_to_user(&sc->sc_fpregs, ¤t->thread.fpstate, + offsetof(struct user_fpsimd_state, fpcr)); + err |= __put_user(current->thread.fpstate.fpcr, &sc->sc_fpcr); err |= __put_user(regs->trap_a0, &sc->sc_traparg_a0); err |= __put_user(regs->trap_a1, &sc->sc_traparg_a1); diff --git a/arch/sw_64/kvm/entry.S b/arch/sw_64/kvm/entry.S index 1e089da5378e..0c02b68ee7d0 100644 --- a/arch/sw_64/kvm/entry.S +++ b/arch/sw_64/kvm/entry.S @@ -15,18 +15,16 @@ ENTRY(__sw64_vcpu_run) /* save host fpregs */ ldl $1, TI_TASK($8) - ldi $1, TASK_THREAD($1) rfpcr $f0 - fstd $f0, THREAD_FPCR($1) - ldi $1, THREAD_CTX_FP($1) - vstd $f2, CTX_FP_F2($1) - vstd $f3, CTX_FP_F3($1) - vstd $f4, CTX_FP_F4($1) - vstd $f5, CTX_FP_F5($1) - vstd $f6, CTX_FP_F6($1) - vstd $f7, CTX_FP_F7($1) - vstd $f8, CTX_FP_F8($1) - vstd $f9, CTX_FP_F9($1) + fstd $f0, TASK_THREAD_FPCR($1) + vstd $f2, TASK_THREAD_F2($1) + vstd $f3, TASK_THREAD_F3($1) + vstd $f4, TASK_THREAD_F4($1) + vstd $f5, TASK_THREAD_F5($1) + vstd $f6, TASK_THREAD_F6($1) + vstd $f7, TASK_THREAD_F7($1) + vstd $f8, TASK_THREAD_F8($1) + vstd $f9, TASK_THREAD_F9($1) ldi sp, -VCPU_RET_SIZE(sp) /* r16 = guest kvm_vcpu_arch.vcb struct pointer */ @@ -213,8 +211,7 @@ $g_setfpec_over: bic sp, $8, $8 /* restore host fpregs */ ldl $1, TI_TASK($8) - ldi $1, TASK_THREAD($1) - fldd $f0, THREAD_FPCR($1) + fldd $f0, TASK_THREAD_FPCR($1) wfpcr $f0 fimovd $f0, $2 and $2, 0x3, $2 @@ -234,15 +231,14 @@ $setfpec_1: $setfpec_2: setfpec2 $setfpec_over: - ldi $1, THREAD_CTX_FP($1) - vldd $f2, CTX_FP_F2($1) - vldd $f3, CTX_FP_F3($1) - vldd $f4, CTX_FP_F4($1) - vldd $f5, CTX_FP_F5($1) - vldd $f6, CTX_FP_F6($1) - vldd $f7, CTX_FP_F7($1) - vldd $f8, CTX_FP_F8($1) - vldd $f9, CTX_FP_F9($1) + vldd $f2, TASK_THREAD_F2($1) + vldd $f3, TASK_THREAD_F3($1) + vldd $f4, TASK_THREAD_F4($1) + vldd $f5, TASK_THREAD_F5($1) + vldd $f6, TASK_THREAD_F6($1) + vldd $f7, TASK_THREAD_F7($1) + vldd $f8, TASK_THREAD_F8($1) + vldd $f9, TASK_THREAD_F9($1) /* if $0 > 0, handle hcall */ bgt $0, $ret_to -- Gitee From 1c9a409b8dff6afad280b33e371221fe54687990 Mon Sep 17 00:00:00 2001 From: He Sheng Date: Fri, 27 May 2022 10:01:54 +0800 Subject: [PATCH 08/50] anolis: sw64: fix ptrace.h with types.h and NOT __ASSEMBLY__ ANBZ: #4688 It may report compile errors on some user apps if linux/types.h is nowhere to be included. And a __ASSEMBLY__ guard makes it work if included by assembly codes. Signed-off-by: He Sheng Reviewed-by: Cui Wei Signed-off-by: Gu Zitao --- arch/sw_64/include/uapi/asm/ptrace.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/sw_64/include/uapi/asm/ptrace.h b/arch/sw_64/include/uapi/asm/ptrace.h index a45b10b8914a..80bad067fc15 100644 --- a/arch/sw_64/include/uapi/asm/ptrace.h +++ b/arch/sw_64/include/uapi/asm/ptrace.h @@ -2,6 +2,9 @@ #ifndef _UAPI_ASM_SW64_PTRACE_H #define _UAPI_ASM_SW64_PTRACE_H +#include + +#ifndef __ASSEMBLY__ /* * User structures for general purpose, floating point and debug registers. */ @@ -21,6 +24,7 @@ struct user_fpsimd_state { __u64 fpcr; __u64 __reserved[3]; }; +#endif /* PTRACE_ATTACH is 16 */ /* PTRACE_DETACH is 17 */ -- Gitee From 49c1ddef59c28c82225fea9adf46c9aa90971ea5 Mon Sep 17 00:00:00 2001 From: He Sheng Date: Fri, 27 May 2022 10:09:44 +0800 Subject: [PATCH 09/50] anolis: sw64: rewrite elf core copy interfaces ANBZ: #4688 For gpreg, simplify dump method to make it easier to maintain. For fpreg, redefine elf_fpregset_t with struct user_fpsimd_state and add a arch-specific dump_fpu() method. Signed-off-by: He Sheng Reviewed-by: Cui Wei Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/elf.h | 34 +++++-------------- arch/sw_64/kernel/process.c | 66 ++++++++---------------------------- 2 files changed, 23 insertions(+), 77 deletions(-) diff --git a/arch/sw_64/include/asm/elf.h b/arch/sw_64/include/asm/elf.h index abecc5653eba..8c858cff5573 100644 --- a/arch/sw_64/include/asm/elf.h +++ b/arch/sw_64/include/asm/elf.h @@ -55,23 +55,18 @@ #define EF_SW64_32BIT 1 /* All addresses are below 2GB */ /* - * ELF register definitions.. - */ - -/* - * The legacy version of makes gregset_t 46 entries long. - * I have no idea why that is so. For now, we just leave it at 33 - * (32 general regs + processor status word). + * ELF register definitions. + * + * For now, we just leave it at 33 (32 general regs + processor status word). */ #define ELF_NGREG 33 -#define ELF_NFPREG 32 - typedef unsigned long elf_greg_t; typedef elf_greg_t elf_gregset_t[ELF_NGREG]; -typedef double elf_fpreg_t; -typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; +/* Same with user_fpsimd_state */ +#include +typedef struct user_fpsimd_state elf_fpregset_t; /* * This is used to ensure we don't load something for the wrong architecture. @@ -121,22 +116,9 @@ extern int arch_setup_additional_pages(struct linux_binprm *bprm, #ifdef __KERNEL__ struct pt_regs; -struct thread_info; struct task_struct; -extern void dump_elf_thread(elf_greg_t *dest, struct pt_regs *pt, - struct thread_info *ti); -#define ELF_CORE_COPY_REGS(DEST, REGS) \ - dump_elf_thread(DEST, REGS, current_thread_info()); - -/* Similar, but for a thread other than current. */ - -extern int dump_elf_task(elf_greg_t *dest, struct task_struct *task); -#define ELF_CORE_COPY_TASK_REGS(TASK, DEST) dump_elf_task(*(DEST), TASK) - -/* Similar, but for the FP registers. */ - -extern int dump_elf_task_fp(elf_fpreg_t *dest, struct task_struct *task); -#define ELF_CORE_COPY_FPREGS(TASK, DEST) dump_elf_task_fp(*(DEST), TASK) +extern void sw64_elf_core_copy_regs(elf_greg_t *dest, struct pt_regs *pt); +#define ELF_CORE_COPY_REGS(DEST, REGS) sw64_elf_core_copy_regs(DEST, REGS); /* * This yields a mask that user programs can use to figure out what diff --git a/arch/sw_64/kernel/process.c b/arch/sw_64/kernel/process.c index 308675d29c04..7a7578d530c6 100644 --- a/arch/sw_64/kernel/process.c +++ b/arch/sw_64/kernel/process.c @@ -200,66 +200,30 @@ copy_thread(unsigned long clone_flags, unsigned long usp, /* * Fill in the user structure for a ELF core dump. + * @regs: should be signal_pt_regs() or task_pt_reg(task) */ -void -dump_elf_thread(elf_greg_t *dest, struct pt_regs *pt, struct thread_info *ti) +void sw64_elf_core_copy_regs(elf_greg_t *dest, struct pt_regs *regs) { - dest[0] = pt->r0; - dest[1] = pt->r1; - dest[2] = pt->r2; - dest[3] = pt->r3; - dest[4] = pt->r4; - dest[5] = pt->r5; - dest[6] = pt->r6; - dest[7] = pt->r7; - dest[8] = pt->r8; - dest[9] = pt->r9; - dest[10] = pt->r10; - dest[11] = pt->r11; - dest[12] = pt->r12; - dest[13] = pt->r13; - dest[14] = pt->r14; - dest[15] = pt->r15; - dest[16] = pt->r16; - dest[17] = pt->r17; - dest[18] = pt->r18; - dest[19] = pt->r19; - dest[20] = pt->r20; - dest[21] = pt->r21; - dest[22] = pt->r22; - dest[23] = pt->r23; - dest[24] = pt->r24; - dest[25] = pt->r25; - dest[26] = pt->r26; - dest[27] = pt->r27; - dest[28] = pt->r28; - dest[29] = pt->gp; - dest[30] = ti == current_thread_info() ? rdusp() : ti->pcb.usp; - dest[31] = pt->pc; + int i; + struct thread_info *ti; - /* Once upon a time this was the PS value. Which is stupid - * since that is always 8 for usermode. Usurped for the more - * useful value of the thread's UNIQUE field. - */ - dest[32] = ti->pcb.unique; -} -EXPORT_SYMBOL(dump_elf_thread); + ti = (void *)((__u64)regs & ~(THREAD_SIZE - 1)); -int -dump_elf_task(elf_greg_t *dest, struct task_struct *task) -{ - dump_elf_thread(dest, task_pt_regs(task), task_thread_info(task)); - return 1; + for (i = 0; i < 30; i++) + dest[i] = *(__u64 *)((void *)regs + regoffsets[i]); + dest[30] = ti == current_thread_info() ? rdusp() : ti->pcb.usp; + dest[31] = regs->pc; + dest[32] = ti->pcb.unique; } -EXPORT_SYMBOL(dump_elf_task); +EXPORT_SYMBOL(sw64_elf_core_copy_regs); -int -dump_elf_task_fp(elf_fpreg_t *dest, struct task_struct *task) +/* Fill in the fpu structure for a core dump. */ +int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) { - memcpy(dest, &task->thread.fpstate, 32 * 8); + memcpy(fpu, ¤t->thread.fpstate, sizeof(*fpu)); return 1; } -EXPORT_SYMBOL(dump_elf_task_fp); +EXPORT_SYMBOL(dump_fpu); /* * Under heavy swap load I've seen this lose in an ugly way. So do -- Gitee From 4d39738cadbe062b20441b6105a983e60016e6b9 Mon Sep 17 00:00:00 2001 From: Wu Liliu Date: Tue, 31 May 2022 09:48:40 +0800 Subject: [PATCH 10/50] anolis: sw64: perf: add fp based stack trace support ANBZ: #4688 It used to obtain return address of function by scanning entire stack which lead to inaccurate result. This patch adds fp based stack trace support to improve efficiency and accuracy. Because toolchain is not ready yet, we take CONFIG_FRAME_POINTER to activate this support, and it should be disabled by default. Signed-off-by: Wu Liliu Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/stacktrace.h | 72 +++++++++++++++++++++++++ arch/sw_64/kernel/perf_event.c | 66 +++++++++++++++++++---- arch/sw_64/kernel/stacktrace.c | 83 +++++++++++++++++++++++++++++ 3 files changed, 210 insertions(+), 11 deletions(-) create mode 100644 arch/sw_64/include/asm/stacktrace.h diff --git a/arch/sw_64/include/asm/stacktrace.h b/arch/sw_64/include/asm/stacktrace.h new file mode 100644 index 000000000000..813aa5e7a91d --- /dev/null +++ b/arch/sw_64/include/asm/stacktrace.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _ASM_SW64_STACKTRACE_H +#define _ASM_SW64_STACKTRACE_H + +#include +#include +#include +#include +#include + +struct stackframe { + unsigned long pc; + unsigned long fp; +}; + +enum stack_type { + STACK_TYPE_UNKNOWN, + STACK_TYPE_TASK, +}; + +struct stack_info { + unsigned long low; + unsigned long high; + enum stack_type type; +}; + +/* The form of the top of the frame on the stack */ +struct stack_frame { + unsigned long return_address; + struct stack_frame *next_frame; +}; + +extern int unwind_frame(struct task_struct *tsk, struct stackframe *frame); +extern void walk_stackframe(struct task_struct *tsk, struct stackframe *frame, + int (*fn)(struct stackframe *, void *), void *data); + +static inline bool on_task_stack(struct task_struct *tsk, unsigned long sp, + struct stack_info *info) +{ + unsigned long low = (unsigned long)task_stack_page(tsk); + unsigned long high = low + THREAD_SIZE; + + if (sp < low || sp >= high) + return false; + + if (info) { + info->low = low; + info->high = high; + info->type = STACK_TYPE_TASK; + } + + return true; +} + +/* + * We can only safely access per-cpu stacks from current in a non-preemptible + * context. + */ +static inline bool on_accessible_stack(struct task_struct *tsk, + unsigned long sp, + struct stack_info *info) +{ + if (on_task_stack(tsk, sp, info)) + return true; + if (tsk != current || preemptible()) + return false; + + return false; +} + +#endif /* _ASM_SW64_STACKTRACE_H */ diff --git a/arch/sw_64/kernel/perf_event.c b/arch/sw_64/kernel/perf_event.c index 0d49224ba058..70f1f2781016 100644 --- a/arch/sw_64/kernel/perf_event.c +++ b/arch/sw_64/kernel/perf_event.c @@ -6,6 +6,7 @@ */ #include +#include /* For tracking PMCs and the hw events they monitor on each CPU. */ struct cpu_hw_events { @@ -247,10 +248,9 @@ static const struct sw64_perf_event *core3_map_cache_event(u64 config) */ static bool core3_raw_event_valid(u64 config) { - if ((config >= (PC0_RAW_BASE + PC0_MIN) && config <= (PC0_RAW_BASE + PC0_MAX)) || - (config >= (PC1_RAW_BASE + PC1_MIN) && config <= (PC1_RAW_BASE + PC1_MAX))) { + if ((config >= PC0_RAW_BASE && config <= (PC0_RAW_BASE + PC0_MAX)) || + (config >= PC1_RAW_BASE && config <= (PC1_RAW_BASE + PC1_MAX))) return true; - } pr_info("sw64 pmu: invalid raw event config %#llx\n", config); return false; @@ -697,6 +697,36 @@ bool valid_dy_addr(unsigned long addr) return ret; } +#ifdef CONFIG_FRAME_POINTER +void perf_callchain_user(struct perf_callchain_entry_ctx *entry, + struct pt_regs *regs) +{ + + struct stack_frame frame; + unsigned long __user *fp; + int err; + + perf_callchain_store(entry, regs->pc); + + fp = (unsigned long __user *)regs->r15; + + while (entry->nr < entry->max_stack && (unsigned long)fp < current->mm->start_stack) { + if (!access_ok(fp, sizeof(frame))) + break; + + pagefault_disable(); + err = __copy_from_user_inatomic(&frame, fp, sizeof(frame)); + pagefault_enable(); + + if (err) + break; + + if (valid_utext_addr(frame.return_address) || valid_dy_addr(frame.return_address)) + perf_callchain_store(entry, frame.return_address); + fp = (void __user *)frame.next_frame; + } +} +#else /* !CONFIG_FRAME_POINTER */ void perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs) { @@ -709,30 +739,44 @@ void perf_callchain_user(struct perf_callchain_entry_ctx *entry, while (entry->nr < entry->max_stack && usp < current->mm->start_stack) { if (!access_ok(usp, 8)) break; + pagefault_disable(); err = __get_user(user_addr, (unsigned long *)usp); pagefault_enable(); + if (err) break; + if (valid_utext_addr(user_addr) || valid_dy_addr(user_addr)) perf_callchain_store(entry, user_addr); usp = usp + 8; } } +#endif/* CONFIG_FRAME_POINTER */ + +/* + * Gets called by walk_stackframe() for every stackframe. This will be called + * whist unwinding the stackframe and is like a subroutine return so we use + * the PC. + */ +static int callchain_trace(struct stackframe *frame, void *data) +{ + struct perf_callchain_entry_ctx *entry = data; + + perf_callchain_store(entry, frame->pc); + + return 0; +} void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs) { - unsigned long *sp = (unsigned long *)current_thread_info()->pcb.ksp; - unsigned long addr; + struct stackframe frame; - perf_callchain_store(entry, regs->pc); + frame.fp = regs->r15; + frame.pc = regs->pc; - while (!kstack_end(sp) && entry->nr < entry->max_stack) { - addr = *sp++; - if (__kernel_text_address(addr)) - perf_callchain_store(entry, addr); - } + walk_stackframe(current, &frame, callchain_trace, entry); } /* diff --git a/arch/sw_64/kernel/stacktrace.c b/arch/sw_64/kernel/stacktrace.c index 41cdff5b4941..2671331717ba 100644 --- a/arch/sw_64/kernel/stacktrace.c +++ b/arch/sw_64/kernel/stacktrace.c @@ -8,7 +8,90 @@ #include #include #include +#include +#include +#include +/* + * sw_64 PCS assigns the frame pointer to r15. + * + * A simple function prologue looks like this: + * ldi sp,-xx(sp) + * stl ra,0(sp) + * stl fp,8(sp) + * mov sp,fp + * + * A simple function epilogue looks like this: + * mov fp,sp + * ldl ra,0(sp) + * ldl fp,8(sp) + * ldi sp,+xx(sp) + */ + +#ifdef CONFIG_FRAME_POINTER + +int unwind_frame(struct task_struct *tsk, struct stackframe *frame) +{ + unsigned long fp = frame->fp; + + if (fp & 0x7) + return -EINVAL; + + if (!tsk) + tsk = current; + + if (!on_accessible_stack(tsk, fp, NULL)) + return -EINVAL; + + frame->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp)); + frame->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp + 8)); + + /* + * Frames created upon entry from user have NULL FP and PC values, so + * don't bother reporting these. Frames created by __noreturn functions + * might have a valid FP even if PC is bogus, so only terminate where + * both are NULL. + */ + if (!frame->fp && !frame->pc) + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL_GPL(unwind_frame); + +void walk_stackframe(struct task_struct *tsk, struct stackframe *frame, + int (*fn)(struct stackframe *, void *), void *data) +{ + while (1) { + int ret; + + if (fn(frame, data)) + break; + ret = unwind_frame(tsk, frame); + if (ret < 0) + break; + } +} +EXPORT_SYMBOL_GPL(walk_stackframe); + +#else /* !CONFIG_FRAME_POINTER */ +void walk_stackframe(struct task_struct *tsk, struct stackframe *frame, + int (*fn)(struct stackframe *, void *), void *data) +{ + unsigned long *sp = (unsigned long *)current_thread_info()->pcb.ksp; + unsigned long addr; + struct perf_callchain_entry_ctx *entry = data; + + perf_callchain_store(entry, frame->pc); + while (!kstack_end(sp) && entry->nr < entry->max_stack) { + addr = *sp++; + if (__kernel_text_address(addr)) + perf_callchain_store(entry, addr); + } +} +EXPORT_SYMBOL_GPL(walk_stackframe); + +#endif/* CONFIG_FRAME_POINTER */ /* * Save stack-backtrace addresses into a stack_trace buffer. -- Gitee From a490ab9c14f243378535e05ebafa90f6d26e463d Mon Sep 17 00:00:00 2001 From: Xu Chenjiao Date: Tue, 31 May 2022 14:11:10 +0800 Subject: [PATCH 11/50] anolis: sw64: fix compile errors for NOT chip3 ANBZ: #4688 IO register DEVINT_WKEN, DEVINTWK_INTEN, PME_ENABLE_INTD_CORE0 and AER_ENABLE_INTD_CORE0 are only defined in chip3. This will lead to compile errors if other chip is selected. To avoid these errors, we define default set_devint_wken() and set_pcieport_service_irq() as weak symbols. Signed-off-by: Xu Chenjiao Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/chip/chip3/chip.c | 16 ++++++++++++++++ arch/sw_64/kernel/pci.c | 15 ++++----------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/arch/sw_64/chip/chip3/chip.c b/arch/sw_64/chip/chip3/chip.c index acd25fe99669..b73afc9c62ac 100644 --- a/arch/sw_64/chip/chip3/chip.c +++ b/arch/sw_64/chip/chip3/chip.c @@ -90,6 +90,22 @@ void setup_chip_clocksource(void) #endif } +void set_devint_wken(int node) +{ + unsigned long val; + + /* enable INTD wakeup */ + val = 0x80; + sw64_io_write(node, DEVINT_WKEN, val); + sw64_io_write(node, DEVINTWK_INTEN, val); +} + +void set_pcieport_service_irq(int node, int index) +{ + write_piu_ior0(node, index, PMEINTCONFIG, PME_ENABLE_INTD_CORE0); + write_piu_ior0(node, index, AERERRINTCONFIG, AER_ENABLE_INTD_CORE0); +} + static int chip3_get_cpu_nums(void) { unsigned long trkmode; diff --git a/arch/sw_64/kernel/pci.c b/arch/sw_64/kernel/pci.c index 401ee0b781be..a004ea9fde7f 100644 --- a/arch/sw_64/kernel/pci.c +++ b/arch/sw_64/kernel/pci.c @@ -600,15 +600,7 @@ sw64_init_host(unsigned long node, unsigned long index) } } -static void set_devint_wken(int node) -{ - unsigned long val; - - /* enable INTD wakeup */ - val = 0x80; - sw64_io_write(node, DEVINT_WKEN, val); - sw64_io_write(node, DEVINTWK_INTEN, val); -} +void __weak set_devint_wken(int node) {} void __init sw64_init_arch(void) { @@ -651,6 +643,8 @@ void __init sw64_init_arch(void) } } +void __weak set_pcieport_service_irq(int node, int index) {} + static void __init sw64_init_intx(struct pci_controller *hose) { unsigned long int_conf, node, val_node; @@ -679,8 +673,7 @@ static void __init sw64_init_intx(struct pci_controller *hose) if (sw64_chip_init->pci_init.set_intx) sw64_chip_init->pci_init.set_intx(node, index, int_conf); - write_piu_ior0(node, index, PMEINTCONFIG, PME_ENABLE_INTD_CORE0); - write_piu_ior0(node, index, AERERRINTCONFIG, AER_ENABLE_INTD_CORE0); + set_pcieport_service_irq(node, index); } void __init sw64_init_irq(void) -- Gitee From f9ab964e06da5bdbd53ab37752633b0a9517ea52 Mon Sep 17 00:00:00 2001 From: Xiong Aifei Date: Mon, 6 Jun 2022 15:24:44 +0800 Subject: [PATCH 12/50] anolis: sw64: gpu: correct low-level mmio memset/memcpy direct calls ANBZ: #4688 Driver codes of the direct calls, via the SIMD-optimized memset and memcpy functions, may raise DFAULT when using RX580 or R7 Series graphics card on sw64, so work around 'memset' references to '_memset_c_io' and 'memcpy' to 'memcpy_fromio'. Signed-off-by: Xiong Aifei Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 12 ++++++++++++ drivers/gpu/drm/radeon/vce_v1_0.c | 5 +++++ 2 files changed, 17 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index c36258d56b44..851d64e83166 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -1354,7 +1354,11 @@ static int gfx_v8_0_mec_init(struct amdgpu_device *adev) return r; } +#if IS_ENABLED(CONFIG_SW64) + _memset_c_io(hpd, 0, mec_hpd_size); +#else memset(hpd, 0, mec_hpd_size); +#endif amdgpu_bo_kunmap(adev->gfx.mec.hpd_eop_obj); amdgpu_bo_unreserve(adev->gfx.mec.hpd_eop_obj); @@ -4649,7 +4653,11 @@ static int gfx_v8_0_kiq_init_queue(struct amdgpu_ring *ring) vi_srbm_select(adev, 0, 0, 0, 0); mutex_unlock(&adev->srbm_mutex); } else { +#if IS_ENABLED(CONFIG_SW64) + _memset_c_io((void *)mqd, 0, sizeof(struct vi_mqd_allocation)); +#else memset((void *)mqd, 0, sizeof(struct vi_mqd_allocation)); +#endif ((struct vi_mqd_allocation *)mqd)->dynamic_cu_mask = 0xFFFFFFFF; ((struct vi_mqd_allocation *)mqd)->dynamic_rb_mask = 0xFFFFFFFF; mutex_lock(&adev->srbm_mutex); @@ -4660,7 +4668,11 @@ static int gfx_v8_0_kiq_init_queue(struct amdgpu_ring *ring) mutex_unlock(&adev->srbm_mutex); if (adev->gfx.mec.mqd_backup[mqd_idx]) +#if IS_ENABLED(CONFIG_SW64) + memcpy_fromio(adev->gfx.mec.mqd_backup[mqd_idx], mqd, sizeof(struct vi_mqd_allocation)); +#else memcpy(adev->gfx.mec.mqd_backup[mqd_idx], mqd, sizeof(struct vi_mqd_allocation)); +#endif } return 0; diff --git a/drivers/gpu/drm/radeon/vce_v1_0.c b/drivers/gpu/drm/radeon/vce_v1_0.c index bd75bbcf5bf6..fbd8a5d9a691 100644 --- a/drivers/gpu/drm/radeon/vce_v1_0.c +++ b/drivers/gpu/drm/radeon/vce_v1_0.c @@ -193,8 +193,13 @@ int vce_v1_0_load_fw(struct radeon_device *rdev, uint32_t *data) data[3] = sign->val[i].nonce[3]; data[4] = cpu_to_le32(le32_to_cpu(sign->len) + 64); +#if IS_ENABLED(CONFIG_SW64) + memset_io(&data[5], 0, 44); + memcpy_toio(&data[16], &sign[1], rdev->vce_fw->size - sizeof(*sign)); +#else memset(&data[5], 0, 44); memcpy(&data[16], &sign[1], rdev->vce_fw->size - sizeof(*sign)); +#endif data += (le32_to_cpu(sign->len) + 64) / 4; data[0] = sign->val[i].sigval[0]; -- Gitee From c53dc99198a8c931f303eff242e52becf6f605ae Mon Sep 17 00:00:00 2001 From: Xu Chenjiao Date: Mon, 6 Jun 2022 16:50:04 +0800 Subject: [PATCH 13/50] anolis: sw64: pcie: fix lack of PME and AER interrupt service routines ANBZ: #4688 On SW64 platform, we used to enable PME and AER interrupt by default, however, there is a risk that no body cares the interrupt routine when CONFIG_PCIE_PME=n or CONFIG_PCIEAER=n. So let's fix this problem. Signed-off-by: Xu Chenjiao Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/chip/chip3/chip.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/arch/sw_64/chip/chip3/chip.c b/arch/sw_64/chip/chip3/chip.c index b73afc9c62ac..2103d93a53a2 100644 --- a/arch/sw_64/chip/chip3/chip.c +++ b/arch/sw_64/chip/chip3/chip.c @@ -102,8 +102,11 @@ void set_devint_wken(int node) void set_pcieport_service_irq(int node, int index) { - write_piu_ior0(node, index, PMEINTCONFIG, PME_ENABLE_INTD_CORE0); - write_piu_ior0(node, index, AERERRINTCONFIG, AER_ENABLE_INTD_CORE0); + if (IS_ENABLED(CONFIG_PCIE_PME)) + write_piu_ior0(node, index, PMEINTCONFIG, PME_ENABLE_INTD_CORE0); + + if (IS_ENABLED(CONFIG_PCIEAER)) + write_piu_ior0(node, index, AERERRINTCONFIG, AER_ENABLE_INTD_CORE0); } static int chip3_get_cpu_nums(void) @@ -438,7 +441,7 @@ extern struct pci_controller *hose_head, **hose_tail; static void sw6_handle_intx(unsigned int offset) { struct pci_controller *hose; - unsigned long value, pme_value, aer_value; + unsigned long value; hose = hose_head; for (hose = hose_head; hose; hose = hose->next) { @@ -451,15 +454,20 @@ static void sw6_handle_intx(unsigned int offset) write_piu_ior0(hose->node, hose->index, INTACONFIG + (offset << 7), value); } - pme_value = read_piu_ior0(hose->node, hose->index, PMEINTCONFIG); - aer_value = read_piu_ior0(hose->node, hose->index, AERERRINTCONFIG); - if ((pme_value >> 63) || (aer_value >> 63)) { - handle_irq(hose->service_irq); + if (IS_ENABLED(CONFIG_PCIE_PME)) { + value = read_piu_ior0(hose->node, hose->index, PMEINTCONFIG); + if (value >> 63) { + handle_irq(hose->service_irq); + write_piu_ior0(hose->node, hose->index, PMEINTCONFIG, value); + } + } - if (pme_value >> 63) - write_piu_ior0(hose->node, hose->index, PMEINTCONFIG, pme_value); - if (aer_value >> 63) - write_piu_ior0(hose->node, hose->index, AERERRINTCONFIG, aer_value); + if (IS_ENABLED(CONFIG_PCIEAER)) { + value = read_piu_ior0(hose->node, hose->index, AERERRINTCONFIG); + if (value >> 63) { + handle_irq(hose->service_irq); + write_piu_ior0(hose->node, hose->index, AERERRINTCONFIG, value); + } } if (hose->iommu_enable) { -- Gitee From 7159c6a4aa9963fdae1b75a7259cf5e2d3b5ec1c Mon Sep 17 00:00:00 2001 From: Zheng Chongzhen Date: Wed, 15 Jun 2022 16:54:25 +0800 Subject: [PATCH 14/50] anolis: sw64: fix dma features for zx200 ANBZ: #4688 The device controllers of ZX200 chipset are all the 32-bit DMA capable device, so we add pci quirk function hook to set dev.bus_dma_limit to DMA_BIT_MASK(32) for all devices on the chipset, besides when CONFIG_SUNWAY_IOMMU=n, all these devices will use swiotlb dma_ops. Signed-off-by: Zheng Chongzhen Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/pci.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/sw_64/kernel/pci.c b/arch/sw_64/kernel/pci.c index a004ea9fde7f..7cc8b7d2d43b 100644 --- a/arch/sw_64/kernel/pci.c +++ b/arch/sw_64/kernel/pci.c @@ -691,3 +691,16 @@ sw64_init_pci(void) { common_init_pci(); } + +static int setup_bus_dma_cb(struct pci_dev *pdev, void *data) +{ + pdev->dev.bus_dma_limit = DMA_BIT_MASK(32); + return 0; +} + +static void fix_bus_dma_limit(struct pci_dev *dev) +{ + pci_walk_bus(dev->subordinate, setup_bus_dma_cb, NULL); + pr_info("Set zx200 bus_dma_limit to 32-bit\n"); +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ZHAOXIN, 0x071f, fix_bus_dma_limit); -- Gitee From c1ad22dcb04375e40d6ac66a2a50cc388f0273a3 Mon Sep 17 00:00:00 2001 From: Zheng Chongzhen Date: Wed, 15 Jun 2022 17:40:59 +0800 Subject: [PATCH 15/50] anolis: sw64: iommu: fix iommu interrupt handler ANBZ: #4688 When porting ZX200 chipset driver on SW64 platform, we meet an IOMMU exception show as follows: iommu_interrupt, iommu_status = 0xc8014000dffe0000, devid 0xa00, dva 0xdffe0000, 1Unable to handle kernel paging request at virtual address 0000000000000040 CPU 0 swapper/0(0): Oops 0 pc = [] ra = [] ps = 0001 Not tainted pc is at iommu_interrupt+0x140/0x3e0 ra is at iommu_interrupt+0xe4/0x3e0 v0 = 0000000000000051 t0 = c8014000dffe0000 t1 = 0000000000000000 t2 = 0000000000000000 t3 = 0000000000000000 t4 = 0000000000000001 t5 = 0000000000000001 t6 = 0000000000000000 t7 = ffffffff82948000 s0 = fff00003ffff0400 s1 = 0000000000000001 s2 = 0000000000000a00 s3 = 0000000000000a00 s4 = 00000000dffe0000 s5 = fff0000100680e80 s6 = ffffffff8294ba70 a0 = 0000000000000001 a1 = 0000000000000001 a2 = ffffffff8294b790 a3 = ffffffff8294b7a8 a4 = 0000000000000000 a5 = ffffffff82c5fb7a t8 = 0000000000000001 t9 = fffffffffffcac48 t10 = 0000000000000000 t11= 0000000000000000 pv = ffffffff809f4f10 at = ffffffff82bff6c0 gp = ffffffff82c1f510 sp = (____ptrval____) The root cause is that the device which raises iommu exception is not in the device list, then reference a null sdev will cause a page fualt. To work around this problem, we apply this patch by just clearing IOMMUEXCPT_STATUS and then go on. BTW, why the device raise IOMMU exception is not a valid device ID, it's a puzzling problem. Signed-off-by: Zheng Chongzhen Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- drivers/iommu/sw64/sunway_iommu.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/sw64/sunway_iommu.c b/drivers/iommu/sw64/sunway_iommu.c index 5797adf8fbc5..b6c8f1272d28 100644 --- a/drivers/iommu/sw64/sunway_iommu.c +++ b/drivers/iommu/sw64/sunway_iommu.c @@ -648,10 +648,21 @@ irqreturn_t iommu_interrupt(int irq, void *dev) type = (iommu_status >> 59) & 0x7; devid = (iommu_status >> 37) & 0xffff; dva = iommu_status & 0xffffffff; - sdev = search_dev_data(devid); - sdomain = sdev->domain; pr_info("%s, iommu_status = %#lx, devid %#lx, dva %#lx, ", __func__, iommu_status, devid, dva); + + sdev = search_dev_data(devid); + if (sdev == NULL) { + pr_info("no such dev!!!\n"); + + iommu_status &= ~(1UL << 62); + write_piu_ior0(hose->node, hose->index, + IOMMUEXCPT_STATUS, iommu_status); + + return IRQ_HANDLED; + } + + sdomain = sdev->domain; switch (type) { case DTE_LEVEL1: pr_info("invalid level1 dte, addr:%#lx, val:%#lx\n", @@ -674,7 +685,6 @@ irqreturn_t iommu_interrupt(int irq, void *dev) fetch_pte(sdomain, dva, PTE_LEVEL2_VAL)); iommu_status &= ~(1UL << 62); - iommu_status = iommu_status | (1UL << 63); write_piu_ior0(hose->node, hose->index, IOMMUEXCPT_STATUS, iommu_status); break; -- Gitee From 3dd7a5e09525b1c1d44555f27fc05736eb9c13ee Mon Sep 17 00:00:00 2001 From: Min Fanlei Date: Tue, 7 Jun 2022 15:12:25 +0800 Subject: [PATCH 16/50] anolis: sw64: kvm: fix incorrect page_ref_count() call ANBZ: #4688 The last page_ref_count() call will cause kernel panic if kvm memory pool is at the end of DRAM. This patch reorders the checks to avoid illegal atomic_read operation. Signed-off-by: Min Fanlei Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/setup.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/sw_64/kernel/setup.c b/arch/sw_64/kernel/setup.c index 4d39db5fb1ef..e20e215dd08a 100644 --- a/arch/sw_64/kernel/setup.c +++ b/arch/sw_64/kernel/setup.c @@ -1026,8 +1026,7 @@ static int __init sw64_kvm_pool_init(void) end_page = pfn_to_page((kvm_mem_base + kvm_mem_size - 1) >> PAGE_SHIFT); p = base_page; - while (page_ref_count(p) == 0 && - (unsigned long)p <= (unsigned long)end_page) { + while (p <= end_page && page_ref_count(p) == 0) { set_page_count(p, 1); page_mapcount_reset(p); SetPageReserved(p); -- Gitee From 0d3ac7a276a0b78e4d88503268779f2f68f27098 Mon Sep 17 00:00:00 2001 From: Yang Qiang Date: Wed, 8 Jun 2022 09:35:37 +0800 Subject: [PATCH 17/50] anolis: sw64: dtb: check address validity with physical address ANBZ: #4688 Due to sw64 ABI sepecification, a large kernel image may override the data structures of UEFI BIOS. To solve this problem, we have expanded UEFI BIOS to 1GB to make sure that runtime service code and data structures reside in the high address below 1GB which may be beyond ktext map. So fix it. Signed-off-by: Yang Qiang Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/setup.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/sw_64/kernel/setup.c b/arch/sw_64/kernel/setup.c index e20e215dd08a..85d172c32239 100644 --- a/arch/sw_64/kernel/setup.c +++ b/arch/sw_64/kernel/setup.c @@ -560,22 +560,20 @@ static void __init setup_machine_fdt(void) #ifdef CONFIG_USE_OF void *dt_virt; const char *name; - unsigned long phys_addr; /* Give a chance to select kernel builtin DTB firstly */ if (IS_ENABLED(CONFIG_SW64_BUILTIN_DTB)) dt_virt = (void *)__dtb_start; else { dt_virt = (void *)sunway_boot_params->dtb_start; - if (dt_virt < (void *)__bss_stop) { + if (virt_to_phys(dt_virt) < virt_to_phys(__bss_stop)) { pr_emerg("BUG: DTB has been corrupted by kernel image!\n"); while (true) cpu_relax(); } } - phys_addr = __phys_addr((unsigned long)dt_virt); - if (!phys_addr_valid(phys_addr) || + if (!phys_addr_valid(virt_to_phys(dt_virt)) || !early_init_dt_scan(dt_virt)) { pr_crit("\n" "Error: invalid device tree blob at virtual address %px\n" -- Gitee From 292d301528cd6c57cf96046603c4778061330239 Mon Sep 17 00:00:00 2001 From: He Chuyue Date: Wed, 8 Jun 2022 09:38:24 +0800 Subject: [PATCH 18/50] anolis: sw64: perf: fix the number of supported raw events ANBZ: #4688 According to CORE3B core software interface manual, the performance counter PC_1 on sw64 supports event index up to 0x3d. Now fix it, and remove some unused macros from wrperfmon.h. Signed-off-by: He Chuyue Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/wrperfmon.h | 4 +--- arch/sw_64/kernel/perf_event.c | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/sw_64/include/asm/wrperfmon.h b/arch/sw_64/include/asm/wrperfmon.h index 098702573bfc..15f7f6beb07c 100644 --- a/arch/sw_64/include/asm/wrperfmon.h +++ b/arch/sw_64/include/asm/wrperfmon.h @@ -33,10 +33,8 @@ #define PC0_RAW_BASE 0x0 #define PC1_RAW_BASE 0x100 -#define PC0_MIN 0x0 #define PC0_MAX 0xF -#define PC1_MIN 0x0 -#define PC1_MAX 0x37 +#define PC1_MAX 0x3D #define SW64_PERFCTRL_KM 2 #define SW64_PERFCTRL_UM 3 diff --git a/arch/sw_64/kernel/perf_event.c b/arch/sw_64/kernel/perf_event.c index 70f1f2781016..e9aae53a56f6 100644 --- a/arch/sw_64/kernel/perf_event.c +++ b/arch/sw_64/kernel/perf_event.c @@ -244,7 +244,7 @@ static const struct sw64_perf_event *core3_map_cache_event(u64 config) /* * r0xx for counter0, r1yy for counter1. - * According to the datasheet, 00 <= xx <= 0F, 00 <= yy <= 37 + * According to the datasheet, 00 <= xx <= 0F, 00 <= yy <= 3D */ static bool core3_raw_event_valid(u64 config) { -- Gitee From a6a1e8258162089782a30117b8cfcd80fbefc41b Mon Sep 17 00:00:00 2001 From: Zhu Donghong Date: Wed, 8 Jun 2022 09:49:30 +0800 Subject: [PATCH 19/50] anolis: drivers/irqchip: add sw64 interrupt controller support ANBZ: #4688 Add a driver for the SW64 implementation of the CPU interrupt controller(INTC). In fact, the INTC is just a software simulated module to connect global interrupt sources to the local interrupt controller on each core. In addition, we rename irq-lpc.c and SW64_CHIP3_LPC config. Signed-off-by: Zhu Donghong Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/Kconfig | 8 +- arch/sw_64/chip/chip3/Makefile | 1 - drivers/irqchip/Kconfig | 33 +++--- drivers/irqchip/Makefile | 4 +- drivers/irqchip/irq-intc-v1.c | 104 ------------------ .../irqchip/irq-sw64-intc-v2.c | 64 ++++++++++- .../{irq-lpc.c => irq-sw64-lpc-intc.c} | 0 7 files changed, 84 insertions(+), 130 deletions(-) delete mode 100644 drivers/irqchip/irq-intc-v1.c rename arch/sw_64/chip/chip3/irq_chip.c => drivers/irqchip/irq-sw64-intc-v2.c (59%) rename drivers/irqchip/{irq-lpc.c => irq-sw64-lpc-intc.c} (100%) diff --git a/arch/sw_64/Kconfig b/arch/sw_64/Kconfig index 3f42542683f7..823346dc21f5 100644 --- a/arch/sw_64/Kconfig +++ b/arch/sw_64/Kconfig @@ -235,6 +235,7 @@ config PLATFORM_XUELANG depends on SW64_CHIP3 select SPARSE_IRQ select SYS_HAS_EARLY_PRINTK + select SW64_INTC_V2 help Sunway chip3 board chipset @@ -737,15 +738,10 @@ endmenu menu "Boot options" -config SW64_IRQ_CHIP - bool - config USE_OF bool "Flattened Device Tree support" - select GENERIC_IRQ_CHIP - select IRQ_DOMAIN - select SW64_IRQ_CHIP select OF + select IRQ_DOMAIN help Include support for flattened device tree machine descriptions. diff --git a/arch/sw_64/chip/chip3/Makefile b/arch/sw_64/chip/chip3/Makefile index 2b7b5790003f..ba0ab3f67f98 100644 --- a/arch/sw_64/chip/chip3/Makefile +++ b/arch/sw_64/chip/chip3/Makefile @@ -4,5 +4,4 @@ obj-y := chip.o i2c-lib.o obj-$(CONFIG_PCI) += pci-quirks.o obj-$(CONFIG_PCI_MSI) += msi.o vt_msi.o -obj-$(CONFIG_SW64_IRQ_CHIP) += irq_chip.o obj-$(CONFIG_CPUFREQ_DEBUGFS) += cpufreq_debugfs.o diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 3c9405fc7dc3..d82835756d1e 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -1,21 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only menu "IRQ chip support" -config SW64_INTC - bool "SW64 Platform-Level Interrupt Controller" - depends on ACPI && SW64 - help - This enables support for the INTC chip found in SW systems. - The INTC controls devices interrupts and connects them to each - core's local interrupt controller. - -config SW64_CHIP3_LPC - bool "SW64 Chip3 Buildin LPC Interrupt Controller" - depends on SW64_CHIP3 - help - This enables support for the LPC interrupt controller bultin in - on chip3 series. - config IRQCHIP def_bool y depends on OF_IRQ @@ -26,6 +11,24 @@ config ARM_GIC select GENERIC_IRQ_MULTI_HANDLER select GENERIC_IRQ_EFFECTIVE_AFF_MASK +config SW64_INTC_V2 + bool "SW64 Interrupt Controller V2" + depends on SW64_CHIP3 + default y + select GENERIC_IRQ_CHIP + select IRQ_DOMAIN + help + This enables support for the INTC chip found in SW CHIP3 systems. + The INTC controls devices interrupts and connects them to each + core's local interrupt controller. + +config SW64_LPC_INTC + bool "SW64 cpu builtin LPC Interrupt Controller" + depends on SW64_INTC_V2 + help + Say yes here to add support for the SW64 cpu builtin LPC + IRQ controller. + config ARM_GIC_PM bool depends on PM diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 585feca070a5..f98111ccf423 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -27,8 +27,8 @@ obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o obj-$(CONFIG_ARCH_SUNXI) += irq-sunxi-nmi.o obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o obj-$(CONFIG_ARM_GIC) += irq-gic.o irq-gic-common.o -obj-$(CONFIG_SW64_INTC) += irq-intc-v1.o -obj-$(CONFIG_SW64_CHIP3_LPC) += irq-lpc.o +obj-$(CONFIG_SW64_INTC_V2) += irq-sw64-intc-v2.o +obj-$(CONFIG_SW64_LPC_INTC) += irq-sw64-lpc-intc.o obj-$(CONFIG_ARM_GIC_PM) += irq-gic-pm.o obj-$(CONFIG_ARCH_REALVIEW) += irq-gic-realview.o obj-$(CONFIG_ARM_GIC_V2M) += irq-gic-v2m.o diff --git a/drivers/irqchip/irq-intc-v1.c b/drivers/irqchip/irq-intc-v1.c deleted file mode 100644 index 4519e96526fb..000000000000 --- a/drivers/irqchip/irq-intc-v1.c +++ /dev/null @@ -1,104 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -static void fake_irq_mask(struct irq_data *data) -{ -} - -static void fake_irq_unmask(struct irq_data *data) -{ -} - -static struct irq_chip onchip_intc = { - .name = "SW fake Intc", - .irq_mask = fake_irq_mask, - .irq_unmask = fake_irq_unmask, -}; - -static int sw_intc_domain_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hw) -{ - irq_set_chip_and_handler(irq, &onchip_intc, handle_level_irq); - irq_set_status_flags(irq, IRQ_LEVEL); - return 0; -} - -static const struct irq_domain_ops intc_irq_domain_ops = { - .xlate = irq_domain_xlate_onecell, - .map = sw_intc_domain_map, -}; - -#ifdef CONFIG_ACPI - -static int __init -intc_parse_madt(union acpi_subtable_headers *header, - const unsigned long end) -{ - struct acpi_madt_io_sapic *its_entry; - static struct irq_domain *root_domain; - int intc_irqs = 8, irq_base = NR_IRQS_LEGACY; - irq_hw_number_t hwirq_base = 0; - int irq_start = -1; - - its_entry = (struct acpi_madt_io_sapic *)header; - - intc_irqs -= hwirq_base; /* calculate # of irqs to allocate */ - - irq_base = irq_alloc_descs(irq_start, 16, intc_irqs, - numa_node_id()); - if (irq_base < 0) { - WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", - irq_start); - irq_base = irq_start; - } - - root_domain = irq_domain_add_legacy(NULL, intc_irqs, irq_base, - hwirq_base, &intc_irq_domain_ops, NULL); - - if (!root_domain) - pr_err("Failed to create irqdomain"); - - irq_set_default_host(root_domain); - - sw64_io_write(0, MCU_DVC_INT_EN, 0xff); - - return 0; -} - -static int __init acpi_intc_init(void) -{ - int count = 0; - - count = acpi_table_parse_madt(ACPI_MADT_TYPE_IO_SAPIC, - intc_parse_madt, 0); - - if (count <= 0) { - pr_err("No valid intc entries exist\n"); - return -EINVAL; - } - return 0; -} -#else -static int __init acpi_intc_init(void) -{ - return 0; -} -#endif - -static int __init intc_init(void) -{ - acpi_intc_init(); - - return 0; -} -subsys_initcall(intc_init); diff --git a/arch/sw_64/chip/chip3/irq_chip.c b/drivers/irqchip/irq-sw64-intc-v2.c similarity index 59% rename from arch/sw_64/chip/chip3/irq_chip.c rename to drivers/irqchip/irq-sw64-intc-v2.c index 24dfa1e1a898..8640c4aa9506 100644 --- a/arch/sw_64/chip/chip3/irq_chip.c +++ b/drivers/irqchip/irq-sw64-intc-v2.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: GPL-2.0 #include #include - -#include +#include +#include +#include +#include static void fake_irq_mask(struct irq_data *data) { @@ -32,6 +34,64 @@ static const struct irq_domain_ops sw64_intc_domain_ops = { .map = sw64_intc_domain_map, }; +static int __init +intc_parse_madt(union acpi_subtable_headers *header, + const unsigned long end) +{ + struct acpi_madt_io_sapic *its_entry; + static struct irq_domain *root_domain; + int intc_irqs = 8, irq_base = NR_IRQS_LEGACY; + irq_hw_number_t hwirq_base = 0; + int irq_start = -1; + + its_entry = (struct acpi_madt_io_sapic *)header; + + intc_irqs -= hwirq_base; /* calculate # of irqs to allocate */ + + irq_base = irq_alloc_descs(irq_start, 16, intc_irqs, + numa_node_id()); + if (irq_base < 0) { + WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", + irq_start); + irq_base = irq_start; + } + + root_domain = irq_domain_add_legacy(NULL, intc_irqs, irq_base, + hwirq_base, &sw64_intc_domain_ops, NULL); + + if (!root_domain) + pr_err("Failed to create irqdomain"); + + irq_set_default_host(root_domain); + + sw64_io_write(0, MCU_DVC_INT_EN, 0xff); + + return 0; +} + +static int __init acpi_intc_init(void) +{ + int count = 0; + + count = acpi_table_parse_madt(ACPI_MADT_TYPE_IO_SAPIC, + intc_parse_madt, 0); + + if (count <= 0) { + pr_err("No valid intc entries exist\n"); + return -EINVAL; + } + return 0; +} + +static int __init intc_init(void) +{ + acpi_intc_init(); + + return 0; +} + +subsys_initcall(intc_init); + static struct irq_domain *root_domain; static int __init diff --git a/drivers/irqchip/irq-lpc.c b/drivers/irqchip/irq-sw64-lpc-intc.c similarity index 100% rename from drivers/irqchip/irq-lpc.c rename to drivers/irqchip/irq-sw64-lpc-intc.c -- Gitee From 5f15b61edf79b2f6f394ef13f94b73245c1adb16 Mon Sep 17 00:00:00 2001 From: Mao Minkai Date: Thu, 23 Jun 2022 14:11:05 +0800 Subject: [PATCH 20/50] anolis: sw64: fix __csum_and_copy when dest is not 8-byte aligned ANBZ: #4688 When destination is not 8-byte aligned, csum_partial_cfu_dest_unaligned() should be used to avoid kernel unaligned exception. Fixes: 2fcadd2861b4 ("sw64: optimize ip checksum calculation") Signed-off-by: Mao Minkai Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/lib/csum_partial_copy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/sw_64/lib/csum_partial_copy.c b/arch/sw_64/lib/csum_partial_copy.c index 441ae5575de5..5e5274e82b2b 100644 --- a/arch/sw_64/lib/csum_partial_copy.c +++ b/arch/sw_64/lib/csum_partial_copy.c @@ -128,9 +128,9 @@ static __wsum __csum_and_copy(const void __user *src, void *dst, int len) (const unsigned long __user *) src, (unsigned long *) dst, len-8); } else { - checksum = csum_partial_cfu_dest_aligned( + checksum = csum_partial_cfu_dest_unaligned( (const unsigned long __user *) src, - (unsigned long *) dst, len-8); + (unsigned long *) dst, doff, len-8); } return (__force __wsum)from64to16(checksum); } -- Gitee From d267f0a5ad86fc31147a0d6694a885f5e4da2160 Mon Sep 17 00:00:00 2001 From: Xiong Aifei Date: Wed, 15 Jun 2022 16:36:00 +0800 Subject: [PATCH 21/50] anolis: sw64: gpu: replace '_memset_c_io' by 'memset_io' ANBZ: #4688 Signed-off-by: Xiong Aifei Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 4 ++-- drivers/gpu/drm/radeon/radeon_vce.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 851d64e83166..28c4e1fe5cd4 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -1355,7 +1355,7 @@ static int gfx_v8_0_mec_init(struct amdgpu_device *adev) } #if IS_ENABLED(CONFIG_SW64) - _memset_c_io(hpd, 0, mec_hpd_size); + memset_io(hpd, 0, mec_hpd_size); #else memset(hpd, 0, mec_hpd_size); #endif @@ -4654,7 +4654,7 @@ static int gfx_v8_0_kiq_init_queue(struct amdgpu_ring *ring) mutex_unlock(&adev->srbm_mutex); } else { #if IS_ENABLED(CONFIG_SW64) - _memset_c_io((void *)mqd, 0, sizeof(struct vi_mqd_allocation)); + memset_io((void *)mqd, 0, sizeof(struct vi_mqd_allocation)); #else memset((void *)mqd, 0, sizeof(struct vi_mqd_allocation)); #endif diff --git a/drivers/gpu/drm/radeon/radeon_vce.c b/drivers/gpu/drm/radeon/radeon_vce.c index 68cc5a347d3b..b9680d38d924 100644 --- a/drivers/gpu/drm/radeon/radeon_vce.c +++ b/drivers/gpu/drm/radeon/radeon_vce.c @@ -240,7 +240,7 @@ int radeon_vce_resume(struct radeon_device *rdev) } #ifdef __sw_64__ - _memset_c_io(cpu_addr, 0, radeon_bo_size(rdev->vce.vcpu_bo)); + memset_io(cpu_addr, 0, radeon_bo_size(rdev->vce.vcpu_bo)); #else memset(cpu_addr, 0, radeon_bo_size(rdev->vce.vcpu_bo)); #endif -- Gitee From beb8268f29eb5eef6a011a0d846c7d0930bee5db Mon Sep 17 00:00:00 2001 From: He Chuyue Date: Tue, 14 Jun 2022 16:40:12 +0800 Subject: [PATCH 22/50] anolis: sw64: perf: fix raw event count ANBZ: #4688 To read raw event count, perf stat calls sw64_pmu_start() to start the event and then calls sw64_perf_event_set_period() to set a new period to sample over. It used to initialize hwc.prev_count and PMC with different values and this will result in error sample values. To fix this problem, initialize them to 0 consistently. Signed-off-by: He Chuyue Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/perf_event.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/arch/sw_64/kernel/perf_event.c b/arch/sw_64/kernel/perf_event.c index e9aae53a56f6..52ec34e33269 100644 --- a/arch/sw_64/kernel/perf_event.c +++ b/arch/sw_64/kernel/perf_event.c @@ -297,31 +297,33 @@ static int sw64_perf_event_set_period(struct perf_event *event, { long left = local64_read(&hwc->period_left); long period = hwc->sample_period; - int ret = 0; + int overflow = 0; + unsigned long value; if (unlikely(left <= -period)) { left = period; local64_set(&hwc->period_left, left); hwc->last_period = period; - ret = 1; + overflow = 1; } if (unlikely(left <= 0)) { left += period; local64_set(&hwc->period_left, left); hwc->last_period = period; - ret = 1; + overflow = 1; } if (left > (long)sw64_pmu->pmc_max_period) left = sw64_pmu->pmc_max_period; - local64_set(&hwc->prev_count, (unsigned long)(-left)); - sw64_write_pmc(idx, (unsigned long)(sw64_pmu->pmc_max_period - left)); + value = sw64_pmu->pmc_max_period - left; + local64_set(&hwc->prev_count, value); + sw64_write_pmc(idx, value); perf_event_update_userpage(event); - return ret; + return overflow; } /* -- Gitee From 9ef16fd912c66f784e8eac0efd8f535ecae5c477 Mon Sep 17 00:00:00 2001 From: Lu Feifei Date: Wed, 15 Jun 2022 14:59:23 +0800 Subject: [PATCH 23/50] anolis: sw64: add memhotplug support for guest os ANBZ: #4688 This patch introduces memory-hotplug support for guest os, and it should set CONFIG_KVM_MEMHOTLPUG=y on host to enable this feature. Currently, only 1GB memory-hotplug granularity is supported, and multiple granularity support will be implemented in the future. Signed-off-by: Lu Feifei Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/chip/chip3/chip.c | 5 + arch/sw_64/include/asm/hcall.h | 1 + arch/sw_64/include/asm/irq_impl.h | 1 + arch/sw_64/include/asm/kvm_asm.h | 3 + arch/sw_64/include/asm/kvm_host.h | 11 +- arch/sw_64/include/asm/memory.h | 1 + arch/sw_64/kvm/Kconfig | 7 + arch/sw_64/kvm/handle_exit.c | 5 + arch/sw_64/kvm/kvm-sw64.c | 113 ++++++++++++- arch/sw_64/mm/init.c | 9 ++ drivers/misc/Kconfig | 8 + drivers/misc/Makefile | 1 + drivers/misc/sunway-ged.c | 253 ++++++++++++++++++++++++++++++ 13 files changed, 410 insertions(+), 8 deletions(-) create mode 100644 drivers/misc/sunway-ged.c diff --git a/arch/sw_64/chip/chip3/chip.c b/arch/sw_64/chip/chip3/chip.c index 2103d93a53a2..02b369b2b37b 100644 --- a/arch/sw_64/chip/chip3/chip.c +++ b/arch/sw_64/chip/chip3/chip.c @@ -701,6 +701,11 @@ void handle_chip_irq(unsigned long type, unsigned long vector, handle_irq(type); set_irq_regs(old_regs); return; + case INT_VT_HOTPLUG: + old_regs = set_irq_regs(regs); + handle_irq(type); + set_irq_regs(old_regs); + return; case INT_PC0: perf_irq(PERFMON_PC0, regs); return; diff --git a/arch/sw_64/include/asm/hcall.h b/arch/sw_64/include/asm/hcall.h index 8117752b657e..b5438b477c87 100644 --- a/arch/sw_64/include/asm/hcall.h +++ b/arch/sw_64/include/asm/hcall.h @@ -18,6 +18,7 @@ enum HCALL_TYPE { HCALL_SWNET = 20, /* guest request swnet service */ HCALL_SWNET_IRQ = 21, /* guest request swnet intr */ HCALL_FATAL_ERROR = 22, /* guest fatal error, issued by hmcode */ + HCALL_MEMHOTPLUG = 23, /* guest memory hotplug event */ NR_HCALL }; diff --git a/arch/sw_64/include/asm/irq_impl.h b/arch/sw_64/include/asm/irq_impl.h index 3679793d8b65..b568efef6994 100644 --- a/arch/sw_64/include/asm/irq_impl.h +++ b/arch/sw_64/include/asm/irq_impl.h @@ -32,6 +32,7 @@ enum sw64_irq_type { INT_RTC = 9, INT_FAULT = 10, INT_VT_SERIAL = 12, + INT_VT_HOTPLUG = 13, INT_DEV = 17, INT_NMI = 18, INT_LEGACY = 31, diff --git a/arch/sw_64/include/asm/kvm_asm.h b/arch/sw_64/include/asm/kvm_asm.h index 4b851682188c..7e2c92ed4574 100644 --- a/arch/sw_64/include/asm/kvm_asm.h +++ b/arch/sw_64/include/asm/kvm_asm.h @@ -11,4 +11,7 @@ #define SW64_KVM_EXIT_RESTART 17 #define SW64_KVM_EXIT_FATAL_ERROR 22 +#ifdef CONFIG_KVM_MEMHOTPLUG +#define SW64_KVM_EXIT_MEMHOTPLUG 23 +#endif #endif /* _ASM_SW64_KVM_ASM_H */ diff --git a/arch/sw_64/include/asm/kvm_host.h b/arch/sw_64/include/asm/kvm_host.h index e4ebb993153c..6d292c086347 100644 --- a/arch/sw_64/include/asm/kvm_host.h +++ b/arch/sw_64/include/asm/kvm_host.h @@ -29,7 +29,7 @@ #include #define KVM_MAX_VCPUS 64 -#define KVM_USER_MEM_SLOTS 512 +#define KVM_USER_MEM_SLOTS 64 #define KVM_HALT_POLL_NS_DEFAULT 0 #define KVM_IRQCHIP_NUM_PINS 256 @@ -42,12 +42,16 @@ #define KVM_PAGES_PER_HPAGE(x) (KVM_HPAGE_SIZE(x) / PAGE_SIZE) struct kvm_arch_memory_slot { - + unsigned long host_phys_addr; + bool valid; }; struct kvm_arch { unsigned long host_phys_addr; unsigned long size; + + /* segment table */ + unsigned long *seg_pgd; }; @@ -100,6 +104,9 @@ struct kvm_vcpu_stat { u64 halt_poll_invalid; }; +#ifdef CONFIG_KVM_MEMHOTPLUG +void vcpu_mem_hotplug(struct kvm_vcpu *vcpu, unsigned long start_addr); +#endif int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, int exception_index, struct hcall_args *hargs); void vcpu_send_ipi(struct kvm_vcpu *vcpu, int target_vcpuid); diff --git a/arch/sw_64/include/asm/memory.h b/arch/sw_64/include/asm/memory.h index d3191165c7b5..b2b7492ae477 100644 --- a/arch/sw_64/include/asm/memory.h +++ b/arch/sw_64/include/asm/memory.h @@ -6,6 +6,7 @@ #include #endif +#define MIN_MEMORY_BLOCK_SIZE_VM_MEMHP (1UL << 30) #define NODE0_START (_TEXT_START - __START_KERNEL_map) #define MAX_PHYSMEM_BITS 48 diff --git a/arch/sw_64/kvm/Kconfig b/arch/sw_64/kvm/Kconfig index 230ac526911c..85323b48f564 100644 --- a/arch/sw_64/kvm/Kconfig +++ b/arch/sw_64/kvm/Kconfig @@ -42,6 +42,13 @@ config KVM_SW64_HOST Provides host support for SW64 processors. To compile this as a module, choose M here. +config KVM_MEMHOTPLUG + bool "Memory hotplug support for guest" + depends on KVM + help + Provides memory hotplug support for SW64 guest. + + source "drivers/vhost/Kconfig" endif # VIRTUALIZATION diff --git a/arch/sw_64/kvm/handle_exit.c b/arch/sw_64/kvm/handle_exit.c index 0d6806051fc7..5016bc0eddc2 100644 --- a/arch/sw_64/kvm/handle_exit.c +++ b/arch/sw_64/kvm/handle_exit.c @@ -34,6 +34,11 @@ int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, case SW64_KVM_EXIT_IPI: vcpu_send_ipi(vcpu, hargs->arg0); return 1; +#ifdef CONFIG_KVM_MEMHOTPLUG + case SW64_KVM_EXIT_MEMHOTPLUG: + vcpu_mem_hotplug(vcpu, hargs->arg0); + return 1; +#endif case SW64_KVM_EXIT_FATAL_ERROR: printk("Guest fatal error: Reason=[%lx], EXC_PC=[%lx], DVA=[%lx]", hargs->arg0, hargs->arg1, hargs->arg2); vcpu->run->exit_reason = KVM_EXIT_UNKNOWN; diff --git a/arch/sw_64/kvm/kvm-sw64.c b/arch/sw_64/kvm/kvm-sw64.c index 839ee83d57d5..af29d0ca8e7f 100644 --- a/arch/sw_64/kvm/kvm-sw64.c +++ b/arch/sw_64/kvm/kvm-sw64.c @@ -56,10 +56,18 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, struct kvm *kvm, int irq extern int __sw64_vcpu_run(struct vcpucb *vcb, struct kvm_regs *regs, struct hcall_args *args); -static unsigned long get_vpcr(unsigned long machine_mem_offset, unsigned long memory_size, unsigned long vpn) +#ifdef CONFIG_KVM_MEMHOTPLUG +static u64 get_vpcr_memhp(u64 seg_base, u64 vpn) { - return (machine_mem_offset >> 23) | ((memory_size >> 23) << 16) | ((vpn & HARDWARE_VPN_MASK) << 44); + return seg_base | ((vpn & HARDWARE_VPN_MASK) << 44); } +#else +static u64 get_vpcr(u64 hpa_base, u64 mem_size, u64 vpn) +{ + return (hpa_base >> 23) | ((mem_size >> 23) << 16) + | ((vpn & HARDWARE_VPN_MASK) << 44); +} +#endif static unsigned long __get_new_vpn_context(struct kvm_vcpu *vcpu, long cpu) { @@ -212,12 +220,38 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) { +#ifdef CONFIG_KVM_MEMHOTPLUG + unsigned long *seg_pgd; + + if (kvm->arch.seg_pgd != NULL) { + kvm_err("kvm_arch already initialized?\n"); + return -EINVAL; + } + + seg_pgd = alloc_pages_exact(PAGE_SIZE, GFP_KERNEL | __GFP_ZERO); + if (!seg_pgd) + return -ENOMEM; + + kvm->arch.seg_pgd = seg_pgd; +#endif + return 0; } void kvm_arch_destroy_vm(struct kvm *kvm) { int i; +#ifdef CONFIG_KVM_MEMHOTPLUG + void *seg_pgd = NULL; + + if (kvm->arch.seg_pgd) { + seg_pgd = READ_ONCE(kvm->arch.seg_pgd); + kvm->arch.seg_pgd = NULL; + } + + if (seg_pgd) + free_pages_exact(seg_pgd, PAGE_SIZE); +#endif for (i = 0; i < KVM_MAX_VCPUS; ++i) { if (kvm->vcpus[i]) { @@ -227,7 +261,6 @@ void kvm_arch_destroy_vm(struct kvm *kvm) } atomic_set(&kvm->online_vcpus, 0); - } long kvm_arch_dev_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) @@ -241,6 +274,22 @@ int kvm_arch_create_memslot(struct kvm *kvm, struct kvm_memory_slot *slot, return 0; } +#ifdef CONFIG_KVM_MEMHOTPLUG +static void setup_segment_table(struct kvm *kvm, + struct kvm_memory_slot *memslot, unsigned long addr, size_t size) +{ + unsigned long *seg_pgd = kvm->arch.seg_pgd; + unsigned int num_of_entry = size >> 30; + unsigned long base_hpa = addr >> 30; + int i; + + for (i = 0; i < num_of_entry; i++) { + *seg_pgd = base_hpa + i; + seg_pgd++; + } +} +#endif + int kvm_arch_prepare_memory_region(struct kvm *kvm, struct kvm_memory_slot *memslot, const struct kvm_userspace_memory_region *mem, @@ -253,8 +302,15 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, unsigned long ret; size_t size; - if (change == KVM_MR_FLAGS_ONLY) + if (change == KVM_MR_FLAGS_ONLY || change == KVM_MR_DELETE) + return 0; + +#ifndef CONFIG_KVM_MEMHOTPLUG + if (mem->guest_phys_addr) { + pr_info("%s, No KVM MEMHOTPLUG support!\n", __func__); return 0; + } +#endif if (test_bit(IO_MARK_BIT, &(mem->guest_phys_addr))) return 0; @@ -276,7 +332,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, if (!vm_file) { info = kzalloc(sizeof(struct vmem_info), GFP_KERNEL); - size = round_up(mem->memory_size, 8<<20); + size = round_up(mem->memory_size, 8 << 20); addr = gen_pool_alloc(sw64_kvm_pool, size); if (!addr) return -ENOMEM; @@ -291,6 +347,18 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, if (!vma) return -ENOMEM; +#ifdef CONFIG_KVM_MEMHOTPLUG + if (memslot->base_gfn == 0x0UL) { + setup_segment_table(kvm, memslot, addr, size); + kvm->arch.host_phys_addr = (u64)addr; + memslot->arch.host_phys_addr = addr; + } else { + /* used for memory hotplug */ + memslot->arch.host_phys_addr = addr; + memslot->arch.valid = false; + } +#endif + info->start = addr; info->size = size; vma->vm_private_data = (void *) info; @@ -308,8 +376,11 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, pr_info("guest phys addr = %#lx, size = %#lx\n", addr, vma->vm_end - vma->vm_start); + +#ifndef CONFIG_KVM_MEMHOTPLUG kvm->arch.host_phys_addr = (u64)addr; - kvm->arch.size = round_up(mem->memory_size, 8<<20); + kvm->arch.size = round_up(mem->memory_size, 8 << 20); +#endif memset(__va(addr), 0, 0x2000000); @@ -463,8 +534,14 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) /* Set guest vcb */ /* vpn will update later when vcpu is running */ if (vcpu->arch.vcb.vpcr == 0) { +#ifndef CONFIG_KVM_MEMHOTPLUG vcpu->arch.vcb.vpcr = get_vpcr(vcpu->kvm->arch.host_phys_addr, vcpu->kvm->arch.size, 0); +#else + unsigned long seg_base = virt_to_phys(vcpu->kvm->arch.seg_pgd); + + vcpu->arch.vcb.vpcr = get_vpcr_memhp(seg_base, 0); +#endif vcpu->arch.vcb.upcr = 0x7; } @@ -640,6 +717,30 @@ int kvm_dev_ioctl_check_extension(long ext) return r; } +#ifdef CONFIG_KVM_MEMHOTPLUG +void vcpu_mem_hotplug(struct kvm_vcpu *vcpu, unsigned long start_addr) +{ + struct kvm *kvm = vcpu->kvm; + struct kvm_memory_slot *slot; + unsigned long start_pfn = start_addr >> PAGE_SHIFT; + + kvm_for_each_memslot(slot, kvm_memslots(kvm)) { + if (start_pfn == slot->base_gfn) { + unsigned long *seg_pgd; + unsigned long num_of_entry = slot->npages >> 17; + unsigned long base_hpa = slot->arch.host_phys_addr; + int i; + + seg_pgd = kvm->arch.seg_pgd + (start_pfn >> 17); + for (i = 0; i < num_of_entry; i++) { + *seg_pgd = (base_hpa >> 30) + i; + seg_pgd++; + } + } + } +} +#endif + void vcpu_send_ipi(struct kvm_vcpu *vcpu, int target_vcpuid) { struct kvm_vcpu *target_vcpu = kvm_get_vcpu(vcpu->kvm, target_vcpuid); diff --git a/arch/sw_64/mm/init.c b/arch/sw_64/mm/init.c index 16d3da7beebe..82f2414ef7f7 100644 --- a/arch/sw_64/mm/init.c +++ b/arch/sw_64/mm/init.c @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -33,6 +34,14 @@ static pud_t vmalloc_pud[1024] __attribute__((__aligned__(PAGE_SIZE))); static phys_addr_t mem_start; static phys_addr_t mem_size_limit; +unsigned long memory_block_size_bytes(void) +{ + if (is_in_guest()) + return MIN_MEMORY_BLOCK_SIZE_VM_MEMHP; + else + return MIN_MEMORY_BLOCK_SIZE; +} + static int __init setup_mem_size(char *p) { char *oldp; diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index fafa8b0d8099..140716083ab8 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -351,6 +351,14 @@ config HMC6352 This driver provides support for the Honeywell HMC6352 compass, providing configuration and heading data via sysfs. +config SUNWAY_GED + tristate "sunway generic device driver for memhotplug" + depends on SW64 + depends on MEMORY_HOTPLUG + help + This driver provides support for sunway generic device driver for + memhotplug, providing configuration and heading data via sysfs. + config DS1682 tristate "Dallas DS1682 Total Elapsed Time Recorder with Alarm" depends on I2C diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index d23231e73330..3615763234a6 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o obj-$(CONFIG_DS1682) += ds1682.o obj-$(CONFIG_C2PORT) += c2port/ obj-$(CONFIG_HMC6352) += hmc6352.o +obj-$(CONFIG_SUNWAY_GED) += sunway-ged.o obj-y += eeprom/ obj-y += cb710/ obj-$(CONFIG_VMWARE_BALLOON) += vmw_balloon.o diff --git a/drivers/misc/sunway-ged.c b/drivers/misc/sunway-ged.c new file mode 100644 index 000000000000..b4e4ca315852 --- /dev/null +++ b/drivers/misc/sunway-ged.c @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* Generic Event Device for ACPI. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define OFFSET_START_ADDR 0 +#define OFFSET_LENGTH 8 +#define OFFSET_STATUS 16 +#define OFFSET_SLOT 24 + +/* Memory hotplug event */ +#define SUNWAY_MEMHOTPLUG_ADD 0x1 +#define SUNWAY_MEMHOTPLUG_REMOVE 0x2 + +struct sunway_memory_device { + struct sunway_ged_device *device; + unsigned int state; /* State of the memory device */ + struct list_head list; + + u64 start_addr; /* Memory Range start physical addr */ + u64 length; /* Memory Range length */ + u64 slot; /* Memory Range slot */ + unsigned int enabled:1; +}; + +struct sunway_ged_device { + struct device *dev; + void __iomem *membase; + void *driver_data; + spinlock_t lock; + struct list_head dev_list; +}; + +static int sunway_memory_enable_device(struct sunway_memory_device *mem_device) +{ + int num_enabled = 0; + int result = 0; + + if (mem_device->enabled) { /* just sanity check...*/ + num_enabled++; + goto out; + } + + /* + * If the memory block size is zero, please ignore it. + * Don't try to do the following memory hotplug flowchart. + */ + if (!mem_device->length) + goto out; + + lock_device_hotplug(); + /* suppose node = 0, fix me! */ + result = __add_memory(0, mem_device->start_addr, mem_device->length); + unlock_device_hotplug(); + /* + * If the memory block has been used by the kernel, add_memory() + * returns -EEXIST. If add_memory() returns the other error, it + * means that this memory block is not used by the kernel. + */ + if (result && result != -EEXIST) + goto out; + + mem_device->enabled = 1; + + /* + * Add num_enable even if add_memory() returns -EEXIST, so the + * device is bound to this driver. + */ + num_enabled++; +out: + if (!num_enabled) { + dev_err(mem_device->device->dev, "add_memory failed\n"); + return -EINVAL; + } + + return 0; +} + +static int sunway_memory_get_meminfo(struct sunway_memory_device *mem_device) +{ + struct sunway_ged_device *geddev; + + if (!mem_device) + return -EINVAL; + + if (mem_device->enabled) + return 0; + + geddev = mem_device->device; + + mem_device->start_addr = readq(geddev->membase + OFFSET_START_ADDR); + mem_device->length = readq(geddev->membase + OFFSET_LENGTH); + + return 0; +} + +static void sunway_memory_device_remove(struct sunway_ged_device *device) +{ + struct sunway_memory_device *mem_dev, *n; + unsigned long start_addr, length, slot; + + if (!device) + return; + + start_addr = readq(device->membase + OFFSET_START_ADDR); + length = readq(device->membase + OFFSET_LENGTH); + slot = readq(device->membase + OFFSET_SLOT); + + list_for_each_entry_safe(mem_dev, n, &device->dev_list, list) { + if (!mem_dev->enabled) + continue; + + if ((start_addr == mem_dev->start_addr) && + (length == mem_dev->length)) { + /* suppose node = 0, fix me! */ + remove_memory(0, start_addr, length); + list_del(&mem_dev->list); + kfree(mem_dev); + } + } + + writeq(slot, device->membase + OFFSET_SLOT); +} + +static int sunway_memory_device_add(struct sunway_ged_device *device) +{ + struct sunway_memory_device *mem_device; + int result; + + if (!device) + return -EINVAL; + + mem_device = kzalloc(sizeof(struct sunway_memory_device), GFP_KERNEL); + if (!mem_device) + return -ENOMEM; + + INIT_LIST_HEAD(&mem_device->list); + mem_device->device = device; + + /* Get the range from the IO */ + mem_device->start_addr = readq(device->membase + OFFSET_START_ADDR); + mem_device->length = readq(device->membase + OFFSET_LENGTH); + mem_device->slot = readq(device->membase + OFFSET_SLOT); + + result = sunway_memory_enable_device(mem_device); + if (result) { + dev_err(device->dev, "sunway_memory_enable_device() error\n"); + sunway_memory_device_remove(device); + + return result; + } + + list_add_tail(&mem_device->list, &device->dev_list); + dev_dbg(device->dev, "Memory device configured\n"); + + hcall(HCALL_MEMHOTPLUG, mem_device->start_addr, 0, 0); + + return 1; +} + +static irqreturn_t sunwayged_ist(int irq, void *data) +{ + struct sunway_ged_device *sunwayged_dev = data; + unsigned int status; + + status = readl(sunwayged_dev->membase + OFFSET_STATUS); + + /* through IO status to add or remove memory device */ + if (status & SUNWAY_MEMHOTPLUG_ADD) + sunway_memory_device_add(sunwayged_dev); + + if (status & SUNWAY_MEMHOTPLUG_REMOVE) + sunway_memory_device_remove(sunwayged_dev); + + return IRQ_HANDLED; +} + +static irqreturn_t sunwayged_irq_handler(int irq, void *data) +{ + return IRQ_WAKE_THREAD; +} + +static int sunwayged_probe(struct platform_device *pdev) +{ + struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + int irq = platform_get_irq(pdev, 0); + struct sunway_ged_device *geddev; + struct device *dev; + int irqflags; + + if (!regs) { + dev_err(dev, "no registers defined\n"); + return -EINVAL; + } + + geddev = devm_kzalloc(&pdev->dev, sizeof(*geddev), GFP_KERNEL); + if (!geddev) + return -ENOMEM; + + spin_lock_init(&geddev->lock); + geddev->membase = devm_ioremap(&pdev->dev, + regs->start, resource_size(regs)); + if (!geddev->membase) + return -ENOMEM; + + INIT_LIST_HEAD(&geddev->dev_list); + geddev->dev = &pdev->dev; + irqflags = IRQF_SHARED; + + if (request_threaded_irq(irq, sunwayged_irq_handler, sunwayged_ist, + irqflags, "SUNWAY:Ged", geddev)) { + dev_err(dev, "failed to setup event handler for irq %u\n", irq); + + return -EINVAL; + } + + platform_set_drvdata(pdev, geddev); + + return 0; +} + +static int sunwayged_remove(struct platform_device *pdev) +{ + return 0; +} + +static const struct of_device_id sunwayged_of_match[] = { + {.compatible = "sw6,sunway-ged", }, + { } +}; +MODULE_DEVICE_TABLE(of, sunwayged_of_match); + +static struct platform_driver sunwayged_platform_driver = { + .driver = { + .name = "sunway-ged", + .of_match_table = sunwayged_of_match, + }, + .probe = sunwayged_probe, + .remove = sunwayged_remove, +}; +module_platform_driver(sunwayged_platform_driver); + +MODULE_AUTHOR("Lu Feifei"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Sunway ged driver"); -- Gitee From 7dd315e3980c23e3eaad9129b718ebae1e55b87d Mon Sep 17 00:00:00 2001 From: Lu Feifei Date: Wed, 15 Jun 2022 14:59:51 +0800 Subject: [PATCH 24/50] anolis: sw64: add a misc device to chip_vt.dts for memory-hotplug ANBZ: #4688 This is an emulated device used to communicate with the memory-hotplug device on the qemu side, so the device is added to device tree for guest os. Signed-off-by: Lu Feifei Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/boot/dts/chip_vt.dts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/sw_64/boot/dts/chip_vt.dts b/arch/sw_64/boot/dts/chip_vt.dts index f0bcf1db1d08..abad29dee97e 100644 --- a/arch/sw_64/boot/dts/chip_vt.dts +++ b/arch/sw_64/boot/dts/chip_vt.dts @@ -34,5 +34,17 @@ uart: serial0@8801 { clock-frequency = <24000000>; status = "okay"; }; + misc: misc0@8036 { + #address-cells = <2>; + #size-cells = <2>; + compatible = "sw6,sunway-ged"; + reg = <0x8036 0x0 0x0 0x20>; + interrupt-parent=<&intc>; + interrupts = <13>; + reg-shift = <0>; + reg-io-width = <8>; + clock-frequency = <24000000>; + status = "okay"; + }; }; }; -- Gitee From 9da8d6a542353d86d061c132d0939979f7df02ca Mon Sep 17 00:00:00 2001 From: Yang Qiang Date: Mon, 20 Jun 2022 14:23:56 +0800 Subject: [PATCH 25/50] anolis: sw64: pci: fix maximum bus number for pci scan ANBZ: #4688 When PCI devices enable SRIOV function, the previous policy that uses pci_find_bus to locate PCI bus from a given domain and bus number may return false PCI bus number, so this patch fixes this patch. Signed-off-by: Yang Qiang Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/chip/chip3/chip.c | 13 +++++++------ arch/sw_64/kernel/pci.c | 18 +++++++++--------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/arch/sw_64/chip/chip3/chip.c b/arch/sw_64/chip/chip3/chip.c index 02b369b2b37b..84ca7ffcb2ef 100644 --- a/arch/sw_64/chip/chip3/chip.c +++ b/arch/sw_64/chip/chip3/chip.c @@ -178,18 +178,20 @@ int chip_pcie_configure(struct pci_controller *hose) struct pci_bus *bus, *top; struct list_head *next; unsigned int max_read_size, smallest_max_payload; - int max_payloadsize, iov_bus = 0; + int max_payloadsize; unsigned long rc_index, node; unsigned long piuconfig0, value; unsigned int pcie_caps_offset; unsigned int rc_conf_value; u16 devctl, new_values; bool rc_ari_disabled = false, found = false; + unsigned char bus_max_num; node = hose->node; rc_index = hose->index; smallest_max_payload = read_rc_conf(node, rc_index, RC_EXP_DEVCAP); smallest_max_payload &= PCI_EXP_DEVCAP_PAYLOAD; + bus_max_num = hose->busn_space->start; top = hose->bus; bus = top; @@ -200,6 +202,7 @@ int chip_pcie_configure(struct pci_controller *hose) /* end of this bus, go up or finish */ if (bus == top) break; + next = bus->self->bus_list.next; bus = bus->self->bus; continue; @@ -224,10 +227,8 @@ int chip_pcie_configure(struct pci_controller *hose) } } -#ifdef CONFIG_PCI_IOV - if (dev->is_physfn) - iov_bus += dev->sriov->max_VF_buses - dev->bus->number; -#endif + if (bus->busn_res.end > bus_max_num) + bus_max_num = bus->busn_res.end; /* Query device PCIe capability register */ pcie_caps_offset = dev->pcie_cap; @@ -306,7 +307,7 @@ int chip_pcie_configure(struct pci_controller *hose) pci_write_config_word(dev, pcie_caps_offset + PCI_EXP_DEVCTL, devctl); } - return iov_bus; + return bus_max_num; } static int chip3_check_pci_vt_linkup(unsigned long node, unsigned long index) diff --git a/arch/sw_64/kernel/pci.c b/arch/sw_64/kernel/pci.c index 7cc8b7d2d43b..fcc6e0f02a93 100644 --- a/arch/sw_64/kernel/pci.c +++ b/arch/sw_64/kernel/pci.c @@ -221,7 +221,7 @@ void __init common_init_pci(void) struct pci_bus *bus; unsigned int init_busnr; int need_domain_info = 0; - int ret, iov_bus; + int ret; unsigned long offset; /* Scan all of the recorded PCI controllers. */ @@ -257,20 +257,20 @@ void __init common_init_pci(void) bus = hose->bus = bridge->bus; hose->need_domain_info = need_domain_info; - while (pci_find_bus(pci_domain_nr(bus), last_bus)) - last_bus++; if (is_in_host()) - iov_bus = chip_pcie_configure(hose); - last_bus += iov_bus; + last_bus = chip_pcie_configure(hose); + else + while (pci_find_bus(pci_domain_nr(bus), last_bus)) + last_bus++; - hose->last_busno = hose->busn_space->end = last_bus - 1; + hose->last_busno = hose->busn_space->end = last_bus; init_busnr = read_rc_conf(hose->node, hose->index, RC_PRIMARY_BUS); init_busnr &= ~(0xff << 16); - init_busnr |= (last_bus - 1) << 16; + init_busnr |= last_bus << 16; write_rc_conf(hose->node, hose->index, RC_PRIMARY_BUS, init_busnr); - pci_bus_update_busn_res_end(bus, last_bus - 1); - + pci_bus_update_busn_res_end(bus, last_bus); + last_bus++; } pcibios_claim_console_setup(); -- Gitee From 520d5f642cb03075b5f04f23ae407b25010d49d5 Mon Sep 17 00:00:00 2001 From: Hang Xiaoqian Date: Mon, 20 Jun 2022 16:54:38 +0800 Subject: [PATCH 26/50] anolis: sw64: remove unaligned count ANBZ: #4688 In the case of highly concurrent unaligned processing, unaligned count may cause severe cache thrashing. However, unaligned count is not required, so remove it to reduce cache thrashing. Signed-off-by: Hang Xiaoqian Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/Makefile | 2 +- arch/sw_64/kernel/traps.c | 13 -------- arch/sw_64/kernel/unaligned.c | 56 ----------------------------------- 3 files changed, 1 insertion(+), 70 deletions(-) delete mode 100644 arch/sw_64/kernel/unaligned.c diff --git a/arch/sw_64/kernel/Makefile b/arch/sw_64/kernel/Makefile index c1e461e0ac56..94b63d6a286b 100644 --- a/arch/sw_64/kernel/Makefile +++ b/arch/sw_64/kernel/Makefile @@ -31,7 +31,7 @@ obj-$(CONFIG_HIBERNATION) += hibernate_asm.o hibernate.o obj-$(CONFIG_AUDIT) += audit.o obj-$(CONFIG_PCI) += pci_common.o obj-$(CONFIG_RELOCATABLE) += relocate.o -obj-$(CONFIG_DEBUG_FS) += unaligned.o segvdbg.o +obj-$(CONFIG_DEBUG_FS) += segvdbg.o obj-$(CONFIG_JUMP_LABEL) += jump_label.o ifndef CONFIG_PCI diff --git a/arch/sw_64/kernel/traps.c b/arch/sw_64/kernel/traps.c index a61c851967a9..d656eca5f961 100644 --- a/arch/sw_64/kernel/traps.c +++ b/arch/sw_64/kernel/traps.c @@ -320,11 +320,6 @@ do_entIF(unsigned long inst_type, struct pt_regs *regs) force_sig_fault(SIGILL, ILL_ILLOPC, (void __user *)regs->pc, 0); } -struct unaligned_stat { - unsigned long count, va, pc; -} unaligned[2]; - - asmlinkage void do_entUna(void *va, unsigned long opcode, unsigned long reg, struct pt_regs *regs) @@ -334,10 +329,6 @@ do_entUna(void *va, unsigned long opcode, unsigned long reg, unsigned long pc = regs->pc - 4; const struct exception_table_entry *fixup; - unaligned[0].count++; - unaligned[0].va = (unsigned long) va; - unaligned[0].pc = pc; - /* * We don't want to use the generic get/put unaligned macros as * we want to trap exceptions. Only if we actually get an @@ -666,10 +657,6 @@ do_entUnaUser(void __user *va, unsigned long opcode, if ((unsigned long)va >= TASK_SIZE) goto give_sigsegv; - ++unaligned[1].count; - unaligned[1].va = (unsigned long)va; - unaligned[1].pc = regs->pc - 4; - if ((1L << opcode) & OP_INT_MASK) { /* it's an integer load/store */ if (reg < 30) { diff --git a/arch/sw_64/kernel/unaligned.c b/arch/sw_64/kernel/unaligned.c deleted file mode 100644 index a1bbdab4a266..000000000000 --- a/arch/sw_64/kernel/unaligned.c +++ /dev/null @@ -1,56 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -/* - * Copyright (C) 2020 Mao Minkai - * Author: Mao Minkai - * - * This code is taken from arch/mips/kernel/segment.c - * Copyright (C) 2013 Imagination Technologies Ltd. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ - -#include -#include - -static int show_unaligned(struct seq_file *sf, void *v) -{ - extern struct unaligned_stat { - unsigned long count, va, pc; - } unaligned[2]; - - seq_printf(sf, "kernel unaligned acc\t: %ld (pc=%lx, va=%lx)\n", unaligned[0].count, unaligned[0].pc, unaligned[0].va); - seq_printf(sf, "user unaligned acc\t: %ld (pc=%lx, va=%lx)\n", unaligned[1].count, unaligned[1].pc, unaligned[1].va); - - return 0; -} - -static int unaligned_open(struct inode *inode, struct file *file) -{ - return single_open(file, show_unaligned, NULL); -} - -static const struct file_operations unaligned_fops = { - .open = unaligned_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init unaligned_info(void) -{ - struct dentry *unaligned; - - if (!sw64_debugfs_dir) - return -ENODEV; - - unaligned = debugfs_create_file("unaligned", S_IRUGO, - sw64_debugfs_dir, NULL, - &unaligned_fops); - if (!unaligned) - return -ENOMEM; - return 0; -} -device_initcall(unaligned_info); -- Gitee From 6e7ae3e1b824794f8eee8621608a2e5b4ddc7e58 Mon Sep 17 00:00:00 2001 From: Mao Minkai Date: Mon, 20 Jun 2022 16:58:09 +0800 Subject: [PATCH 27/50] anolis: sw64: fix simd version of memset ANBZ: #4688 In previous commit ("sw64: optimize simd version of memcpy and memset"), _nc instructions are used to improve performance, but the position of memb instruction in memset is wrong. Fix it. Fixes: ("sw64: optimize simd version of memcpy and memset") Signed-off-by: Mao Minkai Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/lib/deep-memset.S | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/sw_64/lib/deep-memset.S b/arch/sw_64/lib/deep-memset.S index ed2171c56d4d..7fbd529c72a8 100644 --- a/arch/sw_64/lib/deep-memset.S +++ b/arch/sw_64/lib/deep-memset.S @@ -99,12 +99,11 @@ $mod32_aligned: .align 5 $mod32_loop_nc: subl $18, 64, $18 - blt $18, $mod32_tail + blt $18, $mod32_tail_memb vstd_nc $f10, 0($16) vstd_nc $f10, 32($16) addl $16, 64, $16 br $31, $mod32_loop_nc - memb # required for _nc store instructions .align 5 $mod32_loop: @@ -115,6 +114,8 @@ $mod32_loop: addl $16, 64, $16 br $31, $mod32_loop +$mod32_tail_memb: + memb # required for _nc store instructions $mod32_tail: vldd $f10, 0($4) addl $sp, 64, $sp -- Gitee From 0105ff01ff71df852b07effa2f5d2f2a3031bf53 Mon Sep 17 00:00:00 2001 From: Zhu Donghong Date: Tue, 21 Jun 2022 14:47:33 +0800 Subject: [PATCH 28/50] anolis: sw64: deliver a hot reset to Root Complex with plugin JMicron 585 card ANBZ: #4688 On SW64 platform, JMicron 585 SATA card directly connected to Root Complex may raise DMA failure when reboot, so we force a hot reset to Root Complex to fix can not access JMicron 585 SATA card. Signed-off-by: Zhu Donghong Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/platform/platform_xuelang.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/sw_64/platform/platform_xuelang.c b/arch/sw_64/platform/platform_xuelang.c index 63a4b163e43e..ae8179b53b4c 100644 --- a/arch/sw_64/platform/platform_xuelang.c +++ b/arch/sw_64/platform/platform_xuelang.c @@ -26,9 +26,25 @@ extern void cpld_write(uint8_t slave_addr, uint8_t reg, uint8_t data); static void xuelang_kill_arch(int mode) { + struct pci_dev *pdev; + struct pci_controller *hose; + int val; + if (is_in_host()) { switch (mode) { case LINUX_REBOOT_CMD_RESTART: + pdev = pci_get_device(PCI_VENDOR_ID_JMICRON, + 0x0585, NULL); + if (pdev) { + hose = (struct pci_controller *)pdev->sysdata; + val = read_rc_conf(hose->node, hose->index, + RC_PORT_LINK_CTL); + write_rc_conf(hose->node, hose->index, + RC_PORT_LINK_CTL, val | 0x8); + write_rc_conf(hose->node, hose->index, + RC_PORT_LINK_CTL, val); + } + cpld_write(0x64, 0x00, 0xc3); mb(); break; -- Gitee From bd777eea8f4cafb968a129027cd7f3ac4b772c4c Mon Sep 17 00:00:00 2001 From: He Sheng Date: Wed, 21 Jul 2021 13:36:27 +0800 Subject: [PATCH 29/50] anolis: sw64: rename debugfs dir sw_64 to sw64 ANBZ: #4688 Signed-off-by: He Sheng Reviewed-by: Cui Wei Signed-off-by: Gu Zitao --- arch/sw_64/kernel/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sw_64/kernel/setup.c b/arch/sw_64/kernel/setup.c index 85d172c32239..0e93643539d3 100644 --- a/arch/sw_64/kernel/setup.c +++ b/arch/sw_64/kernel/setup.c @@ -976,7 +976,7 @@ static int __init debugfs_sw64(void) { struct dentry *d; - d = debugfs_create_dir("sw_64", NULL); + d = debugfs_create_dir("sw64", NULL); if (!d) return -ENOMEM; sw64_debugfs_dir = d; -- Gitee From b24f4cb3f4d2dca9f33b6521c2cf570a600ad049 Mon Sep 17 00:00:00 2001 From: Wu Liliu Date: Wed, 15 Jun 2022 11:00:09 +0800 Subject: [PATCH 30/50] anolis: sw64: reimplement show_stack() method ANBZ: #4688 It used to show stack information by SP, that means it has nothing to do with task, which is unexpected. In order to show stack of task, we improve the implementation of show_stack(). However, the original task struct does not have sp, so we add it into thread_struct and do something necessary in __switch_to. Meanwhile, walk_stackframe() can be reused, so refactor related codes for better support. Signed-off-by: Wu Liliu Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/processor.h | 1 + arch/sw_64/include/asm/stacktrace.h | 4 +- arch/sw_64/kernel/asm-offsets.c | 1 + arch/sw_64/kernel/entry.S | 6 +++ arch/sw_64/kernel/perf_event.c | 12 ++--- arch/sw_64/kernel/process.c | 1 + arch/sw_64/kernel/stacktrace.c | 78 +++++++++++++++++++++++------ arch/sw_64/kernel/traps.c | 58 ++++----------------- 8 files changed, 85 insertions(+), 76 deletions(-) diff --git a/arch/sw_64/include/asm/processor.h b/arch/sw_64/include/asm/processor.h index 08e8cc8e5428..886f28635dd4 100644 --- a/arch/sw_64/include/asm/processor.h +++ b/arch/sw_64/include/asm/processor.h @@ -45,6 +45,7 @@ struct thread_struct { struct user_fpsimd_state fpstate; /* Callee-saved registers */ unsigned long ra; + unsigned long sp; unsigned long s[7]; /* s0 ~ s6 */ }; #define INIT_THREAD { } diff --git a/arch/sw_64/include/asm/stacktrace.h b/arch/sw_64/include/asm/stacktrace.h index 813aa5e7a91d..ed691a72573b 100644 --- a/arch/sw_64/include/asm/stacktrace.h +++ b/arch/sw_64/include/asm/stacktrace.h @@ -32,8 +32,8 @@ struct stack_frame { }; extern int unwind_frame(struct task_struct *tsk, struct stackframe *frame); -extern void walk_stackframe(struct task_struct *tsk, struct stackframe *frame, - int (*fn)(struct stackframe *, void *), void *data); +extern void walk_stackframe(struct task_struct *tsk, struct pt_regs *regs, + int (*fn)(unsigned long, void *), void *data); static inline bool on_task_stack(struct task_struct *tsk, unsigned long sp, struct stack_info *info) diff --git a/arch/sw_64/kernel/asm-offsets.c b/arch/sw_64/kernel/asm-offsets.c index 0c7e1e26eb05..9e6c338a5edd 100644 --- a/arch/sw_64/kernel/asm-offsets.c +++ b/arch/sw_64/kernel/asm-offsets.c @@ -213,6 +213,7 @@ void foo(void) OFFSET(TASK_THREAD_FPCR, task_struct, thread.fpstate.fpcr); BLANK(); OFFSET(TASK_THREAD_RA, task_struct, thread.ra); + OFFSET(TASK_THREAD_SP, task_struct, thread.sp); OFFSET(TASK_THREAD_S0, task_struct, thread.s[0]); OFFSET(TASK_THREAD_S1, task_struct, thread.s[1]); OFFSET(TASK_THREAD_S2, task_struct, thread.s[2]); diff --git a/arch/sw_64/kernel/entry.S b/arch/sw_64/kernel/entry.S index 977c774ad799..f79c9a6ddf36 100644 --- a/arch/sw_64/kernel/entry.S +++ b/arch/sw_64/kernel/entry.S @@ -398,6 +398,7 @@ __switch_to: .prologue 0 /* Save context into prev->thread */ stl $26, TASK_THREAD_RA($17) + stl $30, TASK_THREAD_SP($17) stl $9, TASK_THREAD_S0($17) stl $10, TASK_THREAD_S1($17) stl $11, TASK_THREAD_S2($17) @@ -415,6 +416,11 @@ __switch_to: ldl $14, TASK_THREAD_S5($18) ldl $15, TASK_THREAD_S6($18) sys_call HMC_swpctx + /* + * SP has been saved and restored by HMC_swpctx, + * and restore it again here for future expansion. + */ + ldl $30, TASK_THREAD_SP($18) ldi $8, 0x3fff bic $sp, $8, $8 mov $17, $0 diff --git a/arch/sw_64/kernel/perf_event.c b/arch/sw_64/kernel/perf_event.c index 52ec34e33269..6e344239917b 100644 --- a/arch/sw_64/kernel/perf_event.c +++ b/arch/sw_64/kernel/perf_event.c @@ -761,24 +761,18 @@ void perf_callchain_user(struct perf_callchain_entry_ctx *entry, * whist unwinding the stackframe and is like a subroutine return so we use * the PC. */ -static int callchain_trace(struct stackframe *frame, void *data) +static int callchain_trace(unsigned long pc, void *data) { struct perf_callchain_entry_ctx *entry = data; - perf_callchain_store(entry, frame->pc); - + perf_callchain_store(entry, pc); return 0; } void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs) { - struct stackframe frame; - - frame.fp = regs->r15; - frame.pc = regs->pc; - - walk_stackframe(current, &frame, callchain_trace, entry); + walk_stackframe(NULL, regs, callchain_trace, entry); } /* diff --git a/arch/sw_64/kernel/process.c b/arch/sw_64/kernel/process.c index 7a7578d530c6..da721d4266ee 100644 --- a/arch/sw_64/kernel/process.c +++ b/arch/sw_64/kernel/process.c @@ -169,6 +169,7 @@ copy_thread(unsigned long clone_flags, unsigned long usp, childti->pcb.ksp = (unsigned long) childregs; childti->pcb.flags = 7; /* set FEN, clear everything else */ + p->thread.sp = (unsigned long) childregs; if (unlikely(p->flags & PF_KTHREAD)) { /* kernel thread */ diff --git a/arch/sw_64/kernel/stacktrace.c b/arch/sw_64/kernel/stacktrace.c index 2671331717ba..4e9acf99aaab 100644 --- a/arch/sw_64/kernel/stacktrace.c +++ b/arch/sw_64/kernel/stacktrace.c @@ -10,6 +10,8 @@ #include #include #include +#include + #include /* @@ -59,40 +61,84 @@ int unwind_frame(struct task_struct *tsk, struct stackframe *frame) } EXPORT_SYMBOL_GPL(unwind_frame); -void walk_stackframe(struct task_struct *tsk, struct stackframe *frame, - int (*fn)(struct stackframe *, void *), void *data) +void walk_stackframe(struct task_struct *tsk, struct pt_regs *regs, + int (*fn)(unsigned long, void *), void *data) { + unsigned long pc, fp; + + struct stackframe frame; + + if (regs) { + pc = regs->pc; + fp = regs->r15; + } else if (tsk == current || tsk == NULL) { + fp = (unsigned long)__builtin_frame_address(0); + pc = (unsigned long)walk_stackframe; + } else { + fp = tsk->thread.s[6]; + pc = tsk->thread.ra; + } + + if (!__kernel_text_address(pc) || fn(pc, data)) + return; + + frame.pc = pc; + frame.fp = fp; while (1) { int ret; - - if (fn(frame, data)) - break; - ret = unwind_frame(tsk, frame); + ret = unwind_frame(tsk, &frame); if (ret < 0) break; + + if (fn(frame.pc, data)) + break; } } EXPORT_SYMBOL_GPL(walk_stackframe); #else /* !CONFIG_FRAME_POINTER */ -void walk_stackframe(struct task_struct *tsk, struct stackframe *frame, - int (*fn)(struct stackframe *, void *), void *data) +void walk_stackframe(struct task_struct *tsk, struct pt_regs *regs, + int (*fn)(unsigned long, void *), void *data) { - unsigned long *sp = (unsigned long *)current_thread_info()->pcb.ksp; - unsigned long addr; - struct perf_callchain_entry_ctx *entry = data; + unsigned long *ksp; + unsigned long sp, pc; + + if (regs) { + sp = (unsigned long)(regs+1); + pc = regs->pc; + } else if (tsk == current || tsk == NULL) { + register unsigned long current_sp __asm__ ("$30"); + sp = current_sp; + pc = (unsigned long)walk_stackframe; + } else { + sp = tsk->thread.sp; + pc = tsk->thread.ra; + } - perf_callchain_store(entry, frame->pc); - while (!kstack_end(sp) && entry->nr < entry->max_stack) { - addr = *sp++; - if (__kernel_text_address(addr)) - perf_callchain_store(entry, addr); + ksp = (unsigned long *)sp; + + while (!kstack_end(ksp)) { + if (__kernel_text_address(pc) && fn(pc, data)) + break; + pc = (*ksp++) - 0x4; } } EXPORT_SYMBOL_GPL(walk_stackframe); #endif/* CONFIG_FRAME_POINTER */ +static int print_address_trace(unsigned long pc, void *data) +{ + print_ip_sym((const char *)data, pc); + return 0; +} + +void show_stack(struct task_struct *task, unsigned long *sp, const char *loglvl) +{ + pr_info("Trace:\n"); + walk_stackframe(task, NULL, print_address_trace, (void *)loglvl); +} + /* * Save stack-backtrace addresses into a stack_trace buffer. */ diff --git a/arch/sw_64/kernel/traps.c b/arch/sw_64/kernel/traps.c index d656eca5f961..4e95cab13daa 100644 --- a/arch/sw_64/kernel/traps.c +++ b/arch/sw_64/kernel/traps.c @@ -12,13 +12,20 @@ #include #include #include +#include #include +#include +#include +#include #include #include #include #include #include +#include +#include +#include #include "proto.h" @@ -68,53 +75,6 @@ dik_show_code(unsigned int *pc) printk("\n"); } -static void -dik_show_trace(unsigned long *sp, const char *loglvl) -{ - long i = 0; - unsigned long tmp; - - printk("%sTrace:\n", loglvl); - while (0x1ff8 & (unsigned long)sp) { - tmp = *sp; - sp++; - if (!__kernel_text_address(tmp)) - continue; - printk("%s[<%lx>] %pSR\n", loglvl, tmp, (void *)tmp); - if (i > 40) { - printk("%s ...", loglvl); - break; - } - } - printk("\n"); -} - -static int kstack_depth_to_print = 24; - -void show_stack(struct task_struct *task, unsigned long *sp, const char *loglvl) -{ - unsigned long *stack; - int i; - - /* - * debugging aid: "show_stack(NULL, NULL, KERN_EMERG);" prints the - * back trace for this cpu. - */ - if (sp == NULL) - sp = (unsigned long *)&sp; - - stack = sp; - for (i = 0; i < kstack_depth_to_print; i++) { - if (((long) stack & (THREAD_SIZE-1)) == 0) - break; - if (i && ((i % 4) == 0)) - printk("%s ", loglvl); - printk("%016lx ", *stack++); - } - printk("\n"); - dik_show_trace(sp, loglvl); -} - void die_if_kernel(char *str, struct pt_regs *regs, long err) { if (regs->ps & 8) @@ -125,7 +85,7 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err) printk("%s(%d): %s %ld\n", current->comm, task_pid_nr(current), str, err); dik_show_regs(regs); add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE); - dik_show_trace((unsigned long *)(regs+1), KERN_DEFAULT); + show_stack(current, NULL, KERN_EMERG); dik_show_code((unsigned int *)regs->pc); if (test_and_set_thread_flag(TIF_DIE_IF_KERNEL)) { @@ -535,7 +495,7 @@ do_entUna(void *va, unsigned long opcode, unsigned long reg, dik_show_regs(regs); dik_show_code((unsigned int *)pc); - dik_show_trace((unsigned long *)(regs+1), KERN_DEFAULT); + show_stack(current, NULL, KERN_EMERG); if (test_and_set_thread_flag(TIF_DIE_IF_KERNEL)) { printk("die_if_kernel recursion detected.\n"); -- Gitee From 62c4db004e32def2fa5b790ba349b3907c52a999 Mon Sep 17 00:00:00 2001 From: Wu Liliu Date: Tue, 21 Jun 2022 14:19:58 +0800 Subject: [PATCH 31/50] anolis: sw64: reimplement get_wchan() ANBZ: #4688 The get_wchan() always return 0 because `fp > sp` is false. This patch reimplements it entirely and fixes this error. Signed-off-by: Wu Liliu Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/process.c | 51 ---------------------------------- arch/sw_64/kernel/stacktrace.c | 22 +++++++++++++++ 2 files changed, 22 insertions(+), 51 deletions(-) diff --git a/arch/sw_64/kernel/process.c b/arch/sw_64/kernel/process.c index da721d4266ee..a75ae20205f3 100644 --- a/arch/sw_64/kernel/process.c +++ b/arch/sw_64/kernel/process.c @@ -226,57 +226,6 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) } EXPORT_SYMBOL(dump_fpu); -/* - * Under heavy swap load I've seen this lose in an ugly way. So do - * some extra sanity checking on the ranges we expect these pointers - * to be in so that we can fail gracefully. This is just for ps after - * all. -- r~ - */ - -unsigned long -thread_saved_pc(struct task_struct *t) -{ - unsigned long top, fp, sp; - - top = (unsigned long)task_stack_page(t) + 2 * PAGE_SIZE; - sp = task_thread_info(t)->pcb.ksp; - fp = t->thread.s[6]; - - if (fp > sp && fp < top) - return *(unsigned long *)fp; - - return 0; -} - -unsigned long -get_wchan(struct task_struct *p) -{ - unsigned long schedule_frame; - unsigned long pc, top, sp; - - if (!p || p == current || p->state == TASK_RUNNING) - return 0; - /* - * This one depends on the frame size of schedule(). Do a - * "disass schedule" in gdb to find the frame size. Also, the - * code assumes that sleep_on() follows immediately after - * interruptible_sleep_on() and that add_timer() follows - * immediately after interruptible_sleep(). Ugly, isn't it? - * Maybe adding a wchan field to task_struct would be better, - * after all... - */ - - pc = thread_saved_pc(p); - if (in_sched_functions(pc)) { - top = (unsigned long)task_stack_page(p) + 2 * PAGE_SIZE; - sp = task_thread_info(p)->pcb.ksp; - schedule_frame = p->thread.s[6]; - if (schedule_frame > sp && schedule_frame < top) - return ((unsigned long *)schedule_frame)[12]; - } - return pc; -} - unsigned long arch_randomize_brk(struct mm_struct *mm) { return randomize_page(mm->brk, 0x02000000); diff --git a/arch/sw_64/kernel/stacktrace.c b/arch/sw_64/kernel/stacktrace.c index 4e9acf99aaab..b51b1500c736 100644 --- a/arch/sw_64/kernel/stacktrace.c +++ b/arch/sw_64/kernel/stacktrace.c @@ -172,3 +172,25 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) trace->entries[trace->nr_entries++] = ULONG_MAX; } EXPORT_SYMBOL_GPL(save_stack_trace_tsk); + +static int save_pc(unsigned long pc, void *data) +{ + unsigned long *p = data; + *p = 0; + + if (!in_sched_functions(pc)) + *p = pc; + + return *p; +} + +unsigned long get_wchan(struct task_struct *tsk) +{ + unsigned long pc; + + if (!tsk || tsk == current || tsk->state == TASK_RUNNING) + return 0; + walk_stackframe(tsk, NULL, save_pc, &pc); + + return pc; +} -- Gitee From d0b7378a1fd24a51c12203f5cece363aa38be712 Mon Sep 17 00:00:00 2001 From: Wu Liliu Date: Fri, 24 Jun 2022 14:12:33 +0800 Subject: [PATCH 32/50] anolis: sw64: reimplement save_stack_trace() ANBZ: #4688 It used to save stack-backtrace addresses by SP, which is inaccurate. In order to implement this function accurately, we provide two ways to support it. Signed-off-by: Wu Liliu Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/stacktrace.c | 62 ++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/arch/sw_64/kernel/stacktrace.c b/arch/sw_64/kernel/stacktrace.c index b51b1500c736..7b5ddc78bd6d 100644 --- a/arch/sw_64/kernel/stacktrace.c +++ b/arch/sw_64/kernel/stacktrace.c @@ -139,40 +139,58 @@ void show_stack(struct task_struct *task, unsigned long *sp, const char *loglvl) walk_stackframe(task, NULL, print_address_trace, (void *)loglvl); } +#ifdef CONFIG_STACKTRACE /* * Save stack-backtrace addresses into a stack_trace buffer. */ -void save_stack_trace(struct stack_trace *trace) +struct stack_trace_data { + struct stack_trace *trace; + unsigned int nosched; +}; + +int save_trace(unsigned long pc, void *d) { - save_stack_trace_tsk(current, trace); -} -EXPORT_SYMBOL_GPL(save_stack_trace); + struct stack_trace_data *data = d; + struct stack_trace *trace = data->trace; + + if (data->nosched && in_sched_functions(pc)) + return 0; + if (trace->skip > 0) { + trace->skip--; + return 0; + } + trace->entries[trace->nr_entries++] = pc; + return (trace->nr_entries >= trace->max_entries); +} -void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) +static void __save_stack_trace(struct task_struct *tsk, + struct stack_trace *trace, unsigned int nosched) { - unsigned long *sp = (unsigned long *)task_thread_info(tsk)->pcb.ksp; - unsigned long addr; - - WARN_ON(trace->nr_entries || !trace->max_entries); - - while (!kstack_end(sp)) { - addr = *sp++; - if (__kernel_text_address(addr) && - !in_sched_functions(addr)) { - if (trace->skip > 0) - trace->skip--; - else - trace->entries[trace->nr_entries++] = addr; - if (trace->nr_entries >= trace->max_entries) - break; - } - } + struct stack_trace_data data; + + data.trace = trace; + data.nosched = nosched; + + walk_stackframe(tsk, NULL, save_trace, &data); + if (trace->nr_entries < trace->max_entries) trace->entries[trace->nr_entries++] = ULONG_MAX; } + +void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) +{ + __save_stack_trace(tsk, trace, 1); +} EXPORT_SYMBOL_GPL(save_stack_trace_tsk); +void save_stack_trace(struct stack_trace *trace) +{ + __save_stack_trace(current, trace, 0); +} +EXPORT_SYMBOL_GPL(save_stack_trace); +#endif + static int save_pc(unsigned long pc, void *data) { unsigned long *p = data; -- Gitee From a249b923026281a29f4bbb28bb758f3e45f55a97 Mon Sep 17 00:00:00 2001 From: Wang Yuanheng Date: Mon, 27 Jun 2022 09:02:01 +0800 Subject: [PATCH 33/50] anolis: sw64: kvm: enable binding_vcpu debug dynamically ANBZ: #4688 Add a bool debugfs file /sys/kernel/debug/sw_64/bind_vcpu, you can echo 1/Y to enable bind vcpu, or echo 0/N to disable it. Determin which node to bind the core according to the physical address assigned to the guest. Signed-off-by: Wang Yuanheng Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/Makefile | 2 +- arch/sw_64/kernel/bindvcpu.c | 29 +++++++++++++++++++++++++++++ arch/sw_64/kvm/kvm-sw64.c | 13 ++++++++++++- 3 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 arch/sw_64/kernel/bindvcpu.c diff --git a/arch/sw_64/kernel/Makefile b/arch/sw_64/kernel/Makefile index 94b63d6a286b..d4dc9e175d67 100644 --- a/arch/sw_64/kernel/Makefile +++ b/arch/sw_64/kernel/Makefile @@ -31,7 +31,7 @@ obj-$(CONFIG_HIBERNATION) += hibernate_asm.o hibernate.o obj-$(CONFIG_AUDIT) += audit.o obj-$(CONFIG_PCI) += pci_common.o obj-$(CONFIG_RELOCATABLE) += relocate.o -obj-$(CONFIG_DEBUG_FS) += segvdbg.o +obj-$(CONFIG_DEBUG_FS) += segvdbg.o bindvcpu.o obj-$(CONFIG_JUMP_LABEL) += jump_label.o ifndef CONFIG_PCI diff --git a/arch/sw_64/kernel/bindvcpu.c b/arch/sw_64/kernel/bindvcpu.c new file mode 100644 index 000000000000..611c395c144b --- /dev/null +++ b/arch/sw_64/kernel/bindvcpu.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 Wang Yuanheng + * Author: Wang Yuanheng + * + */ + +#include +#include +#include +#include +#include + +extern bool bind_vcpu_enabled; + +static int __init bind_vcpu_init(void) +{ + struct dentry *bindvcpu; + + if (!sw64_debugfs_dir) + return -ENODEV; + + bindvcpu = debugfs_create_bool("bind_vcpu", 0644, + sw64_debugfs_dir, &bind_vcpu_enabled); + if (!bindvcpu) + return -ENOMEM; + return 0; +} +late_initcall(bind_vcpu_init); diff --git a/arch/sw_64/kvm/kvm-sw64.c b/arch/sw_64/kvm/kvm-sw64.c index af29d0ca8e7f..de81f7efe01a 100644 --- a/arch/sw_64/kvm/kvm-sw64.c +++ b/arch/sw_64/kvm/kvm-sw64.c @@ -12,7 +12,7 @@ #include #include #include - +#include #include #include @@ -21,6 +21,7 @@ bool set_msi_flag; unsigned long sw64_kvm_last_vpn[NR_CPUS]; +__read_mostly bool bind_vcpu_enabled; #define cpu_last_vpn(cpuid) sw64_kvm_last_vpn[cpuid] #ifdef CONFIG_SUBARCH_C3B @@ -537,6 +538,16 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) #ifndef CONFIG_KVM_MEMHOTPLUG vcpu->arch.vcb.vpcr = get_vpcr(vcpu->kvm->arch.host_phys_addr, vcpu->kvm->arch.size, 0); + + if (unlikely(bind_vcpu_enabled)) { + int nid; + unsigned long end; + + end = vcpu->kvm->arch.host_phys_addr + vcpu->kvm->arch.size; + nid = pfn_to_nid(PHYS_PFN(vcpu->kvm->arch.host_phys_addr)); + if (pfn_to_nid(PHYS_PFN(end)) == nid) + set_cpus_allowed_ptr(vcpu->arch.tsk, node_to_cpumask_map[nid]); + } #else unsigned long seg_base = virt_to_phys(vcpu->kvm->arch.seg_pgd); -- Gitee From 59da3795c07201b6a9db2f26500d86217cb1a0e5 Mon Sep 17 00:00:00 2001 From: Gu Zitao Date: Tue, 28 Jun 2022 08:51:26 +0800 Subject: [PATCH 34/50] anolis: sw64: rename CONFIG_HAVE_GENERIC_GUP to CONFIG_HAVE_FAST_GUP ANBZ: #4688 This patch is a backport of commit 67a929e097b7 ("mm: rename CONFIG_HAVE_GENERIC_GUP to CONFIG_HAVE_FAST_GUP"). In order to use the generic GUP, let's do the same. Signed-off-by: Gu Zitao Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sw_64/Kconfig b/arch/sw_64/Kconfig index 823346dc21f5..c986f939c247 100644 --- a/arch/sw_64/Kconfig +++ b/arch/sw_64/Kconfig @@ -7,7 +7,7 @@ config SW64 select HAVE_OPROFILE select HAVE_PCSPKR_PLATFORM select HAVE_PERF_EVENTS - select HAVE_GENERIC_GUP + select HAVE_FAST_GUP select GENERIC_CLOCKEVENTS select GENERIC_IRQ_PROBE select GENERIC_IRQ_LEGACY -- Gitee From 2178a8e977e2779d7e00bca97b6cd625469c6255 Mon Sep 17 00:00:00 2001 From: Zhou Xuemei Date: Thu, 7 Jul 2022 17:19:10 +0800 Subject: [PATCH 35/50] anolis: sw64: fix floating point register corruption ANBZ: #4688 When csum_partial_copy_from_user is called in an interrupt, __copy_from_user will modify floating point register f10-f15 without restore register value. This will cause the value of the userspace register to be corrupted. Use memcpy() instead when called from kernel space. Signed-off-by: Zhou Xuemei Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/lib/csum_partial_copy.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/sw_64/lib/csum_partial_copy.c b/arch/sw_64/lib/csum_partial_copy.c index 5e5274e82b2b..742dd63cdb70 100644 --- a/arch/sw_64/lib/csum_partial_copy.c +++ b/arch/sw_64/lib/csum_partial_copy.c @@ -61,7 +61,11 @@ csum_partial_cfu_dest_aligned(const unsigned long __user *src, unsigned long checksum = ~0U; int err = 0; - err = __copy_from_user(dst, src, len+8); + if (likely(!uaccess_kernel())) + err = __copy_from_user(dst, src, len + 8); + else + memcpy(dst, src, len + 8); + while (len > 0) { word = *dst; checksum += word; @@ -89,7 +93,10 @@ csum_partial_cfu_dest_unaligned(const unsigned long __user *src, unsigned long checksum = ~0U; int err = 0; - err = __copy_from_user(dst, src, len+8); + if (likely(!uaccess_kernel())) + err = __copy_from_user(dst, src, len + 8); + else + memcpy(dst, src, len + 8); dst = (unsigned long *)((unsigned long)dst & (~7UL)); word = *dst; -- Gitee From 2ac07215749006117d066fa3b1eb6f18e3ef4e63 Mon Sep 17 00:00:00 2001 From: Wu Liliu Date: Thu, 23 Jun 2022 14:31:07 +0800 Subject: [PATCH 36/50] anolis: sw64: check processor state by user_mode(regs) ANBZ: #4688 The `regs->ps & 8` and `regs->ps & ~IPL_MAX` don't have a clear meaning. We replace them with user_mode(regs) and !user_mode(regs), and reserve regs->ps[63:4] for future extension. Signed-off-by: Wu Liliu Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/traps.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/sw_64/kernel/traps.c b/arch/sw_64/kernel/traps.c index 4e95cab13daa..8c7fdeeef491 100644 --- a/arch/sw_64/kernel/traps.c +++ b/arch/sw_64/kernel/traps.c @@ -77,7 +77,7 @@ dik_show_code(unsigned int *pc) void die_if_kernel(char *str, struct pt_regs *regs, long err) { - if (regs->ps & 8) + if (user_mode(regs)) return; #ifdef CONFIG_SMP printk("CPU %d ", hard_smp_processor_id()); @@ -149,7 +149,7 @@ do_entIF(unsigned long inst_type, struct pt_regs *regs) type = inst_type & 0xffffffff; inst = inst_type >> 32; - if ((regs->ps & ~IPL_MAX) == 0 && type != 4) { + if (!user_mode(regs) && type != 4) { if (type == 1) { const unsigned int *data = (const unsigned int *) regs->pc; @@ -253,7 +253,7 @@ do_entIF(unsigned long inst_type, struct pt_regs *regs) if (notify_die(DIE_UPROBE_XOL, "uprobe_xol", regs, 0, 0, SIGTRAP) == NOTIFY_STOP) return; } - if ((regs->ps & ~IPL_MAX) == 0) + if (!user_mode(regs)) die_if_kernel("Instruction fault", regs, type); break; -- Gitee From fb3314dcd66ce11766399cf1929c7364997e2287 Mon Sep 17 00:00:00 2001 From: Wu Liliu Date: Tue, 12 Jul 2022 14:49:24 +0800 Subject: [PATCH 37/50] anolis: sw64: reimplement die_if_kernel() ANBZ: #4688 In the original implementation, incorrent printing may occur when multiple processes die at the same time. To fix this, we use lock. Signed-off-by: Wu Liliu Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/proto.h | 2 +- arch/sw_64/kernel/traps.c | 50 ++++++++++++++++++++++++++------------- arch/sw_64/mm/fault.c | 4 ++-- 3 files changed, 37 insertions(+), 19 deletions(-) diff --git a/arch/sw_64/kernel/proto.h b/arch/sw_64/kernel/proto.h index 189074f8bd5c..f2b77d370da1 100644 --- a/arch/sw_64/kernel/proto.h +++ b/arch/sw_64/kernel/proto.h @@ -13,7 +13,7 @@ extern int ptrace_cancel_bpt(struct task_struct *child); /* traps.c */ extern void dik_show_regs(struct pt_regs *regs); -extern void die_if_kernel(char *str, struct pt_regs *regs, long err); +extern void die(char *str, struct pt_regs *regs, long err); /* timer.c */ extern void setup_timer(void); diff --git a/arch/sw_64/kernel/traps.c b/arch/sw_64/kernel/traps.c index 8c7fdeeef491..5f2348dd087f 100644 --- a/arch/sw_64/kernel/traps.c +++ b/arch/sw_64/kernel/traps.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include #include @@ -75,33 +77,47 @@ dik_show_code(unsigned int *pc) printk("\n"); } -void die_if_kernel(char *str, struct pt_regs *regs, long err) +static DEFINE_SPINLOCK(die_lock); + +void die(char *str, struct pt_regs *regs, long err) { - if (user_mode(regs)) - return; + static int die_counter; + unsigned long flags; + int ret; + + oops_enter(); + + spin_lock_irqsave(&die_lock, flags); + console_verbose(); + bust_spinlocks(1); + + pr_emerg("%s [#%d]\n", str, ++die_counter); + #ifdef CONFIG_SMP printk("CPU %d ", hard_smp_processor_id()); #endif printk("%s(%d): %s %ld\n", current->comm, task_pid_nr(current), str, err); + + ret = notify_die(DIE_OOPS, str, regs, err, 0, SIGSEGV); + + print_modules(); dik_show_regs(regs); - add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE); show_stack(current, NULL, KERN_EMERG); - dik_show_code((unsigned int *)regs->pc); - if (test_and_set_thread_flag(TIF_DIE_IF_KERNEL)) { - printk("die_if_kernel recursion detected.\n"); - local_irq_enable(); - while (1) - asm("nop"); - } + bust_spinlocks(0); + add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE); + spin_unlock_irqrestore(&die_lock, flags); + oops_exit(); if (kexec_should_crash(current)) crash_kexec(regs); - + if (in_interrupt()) + panic("Fatal exception in interrupt"); if (panic_on_oops) panic("Fatal exception"); - do_exit(SIGSEGV); + if (ret != NOTIFY_STOP) + do_exit(SIGSEGV); } #ifndef CONFIG_MATHEMU @@ -135,7 +151,9 @@ do_entArith(unsigned long summary, unsigned long write_mask, if (si_code == 0) return; } - die_if_kernel("Arithmetic fault", regs, 0); + + if (!user_mode(regs)) + die("Arithmetic fault", regs, 0); force_sig_fault(SIGFPE, si_code, (void __user *)regs->pc, 0); } @@ -161,7 +179,7 @@ do_entIF(unsigned long inst_type, struct pt_regs *regs) notify_die(0, "kgdb trap", regs, 0, 0, SIGTRAP); return; } - die_if_kernel((type == 1 ? "Kernel Bug" : "Instruction fault"), + die((type == 1 ? "Kernel Bug" : "Instruction fault"), regs, type); } @@ -254,7 +272,7 @@ do_entIF(unsigned long inst_type, struct pt_regs *regs) return; } if (!user_mode(regs)) - die_if_kernel("Instruction fault", regs, type); + die("Instruction fault", regs, type); break; case 3: /* FEN fault */ diff --git a/arch/sw_64/mm/fault.c b/arch/sw_64/mm/fault.c index d596fc50772d..15fd65b1b754 100644 --- a/arch/sw_64/mm/fault.c +++ b/arch/sw_64/mm/fault.c @@ -31,7 +31,7 @@ static inline int notify_page_fault(struct pt_regs *regs, unsigned long mmcsr) } #endif -extern void die_if_kernel(char *, struct pt_regs *, long); +extern void die(char *, struct pt_regs *, long); extern void dik_show_regs(struct pt_regs *regs); void show_all_vma(void) @@ -301,7 +301,7 @@ do_page_fault(unsigned long address, unsigned long mmcsr, */ pr_alert("Unable to handle kernel paging request at virtual address %016lx\n", address); - die_if_kernel("Oops", regs, cause); + die("Oops", regs, cause); do_exit(SIGKILL); /* -- Gitee From 6e43ad400cd7665659d4a6f850ea14aad78bfe89 Mon Sep 17 00:00:00 2001 From: Mao Minkai Date: Tue, 12 Jul 2022 16:05:32 +0800 Subject: [PATCH 38/50] anolis: sw64: adjust make rules to avoid compile error ANBZ: #4688 Fix compile errors when CONFIG_NUMA or CONFIG_SPARSEMEM is not set. Some make rules are changed to avoid potential compile errors. Signed-off-by: Mao Minkai Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/Kconfig | 1 + arch/sw_64/kernel/Makefile | 6 +++++- arch/sw_64/kvm/Kconfig | 2 +- arch/sw_64/kvm/kvm-sw64.c | 8 ++++++-- arch/sw_64/mm/init.c | 2 ++ arch/sw_64/mm/physaddr.c | 1 + 6 files changed, 16 insertions(+), 4 deletions(-) diff --git a/arch/sw_64/Kconfig b/arch/sw_64/Kconfig index c986f939c247..480ee2779001 100644 --- a/arch/sw_64/Kconfig +++ b/arch/sw_64/Kconfig @@ -98,6 +98,7 @@ config SW64 select HAVE_REGS_AND_STACK_ACCESS_API select ARCH_HAS_PTE_SPECIAL select HARDIRQS_SW_RESEND + select MEMORY_HOTPLUG_SPARSE if MEMORY_HOTPLUG config LOCKDEP_SUPPORT def_bool y diff --git a/arch/sw_64/kernel/Makefile b/arch/sw_64/kernel/Makefile index d4dc9e175d67..8cc09dd8fdbc 100644 --- a/arch/sw_64/kernel/Makefile +++ b/arch/sw_64/kernel/Makefile @@ -31,9 +31,13 @@ obj-$(CONFIG_HIBERNATION) += hibernate_asm.o hibernate.o obj-$(CONFIG_AUDIT) += audit.o obj-$(CONFIG_PCI) += pci_common.o obj-$(CONFIG_RELOCATABLE) += relocate.o -obj-$(CONFIG_DEBUG_FS) += segvdbg.o bindvcpu.o +obj-$(CONFIG_DEBUG_FS) += segvdbg.o obj-$(CONFIG_JUMP_LABEL) += jump_label.o +ifeq ($(CONFIG_DEBUG_FS)$(CONFIG_NUMA),yy) +obj-y += bindvcpu.o +endif + ifndef CONFIG_PCI obj-y += pci-noop.o endif diff --git a/arch/sw_64/kvm/Kconfig b/arch/sw_64/kvm/Kconfig index 85323b48f564..4b6201ff5dc8 100644 --- a/arch/sw_64/kvm/Kconfig +++ b/arch/sw_64/kvm/Kconfig @@ -44,7 +44,7 @@ config KVM_SW64_HOST config KVM_MEMHOTPLUG bool "Memory hotplug support for guest" - depends on KVM + depends on KVM && MEMORY_HOTPLUG help Provides memory hotplug support for SW64 guest. diff --git a/arch/sw_64/kvm/kvm-sw64.c b/arch/sw_64/kvm/kvm-sw64.c index de81f7efe01a..8ba7e18698b3 100644 --- a/arch/sw_64/kvm/kvm-sw64.c +++ b/arch/sw_64/kvm/kvm-sw64.c @@ -21,7 +21,9 @@ bool set_msi_flag; unsigned long sw64_kvm_last_vpn[NR_CPUS]; +#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_NUMA) __read_mostly bool bind_vcpu_enabled; +#endif #define cpu_last_vpn(cpuid) sw64_kvm_last_vpn[cpuid] #ifdef CONFIG_SUBARCH_C3B @@ -539,6 +541,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) vcpu->arch.vcb.vpcr = get_vpcr(vcpu->kvm->arch.host_phys_addr, vcpu->kvm->arch.size, 0); +#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_NUMA) if (unlikely(bind_vcpu_enabled)) { int nid; unsigned long end; @@ -548,11 +551,12 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) if (pfn_to_nid(PHYS_PFN(end)) == nid) set_cpus_allowed_ptr(vcpu->arch.tsk, node_to_cpumask_map[nid]); } -#else +#endif +#else /* !CONFIG_KVM_MEMHOTPLUG */ unsigned long seg_base = virt_to_phys(vcpu->kvm->arch.seg_pgd); vcpu->arch.vcb.vpcr = get_vpcr_memhp(seg_base, 0); -#endif +#endif /* CONFIG_KVM_MEMHOTPLUG */ vcpu->arch.vcb.upcr = 0x7; } diff --git a/arch/sw_64/mm/init.c b/arch/sw_64/mm/init.c index 82f2414ef7f7..e0096a0b432a 100644 --- a/arch/sw_64/mm/init.c +++ b/arch/sw_64/mm/init.c @@ -34,6 +34,7 @@ static pud_t vmalloc_pud[1024] __attribute__((__aligned__(PAGE_SIZE))); static phys_addr_t mem_start; static phys_addr_t mem_size_limit; +#ifdef CONFIG_MEMORY_HOTPLUG_SPARSE unsigned long memory_block_size_bytes(void) { if (is_in_guest()) @@ -41,6 +42,7 @@ unsigned long memory_block_size_bytes(void) else return MIN_MEMORY_BLOCK_SIZE; } +#endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */ static int __init setup_mem_size(char *p) { diff --git a/arch/sw_64/mm/physaddr.c b/arch/sw_64/mm/physaddr.c index 26769f0bf7bf..17840f4ef40b 100644 --- a/arch/sw_64/mm/physaddr.c +++ b/arch/sw_64/mm/physaddr.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include #include +#include #include unsigned long __phys_addr(unsigned long x) -- Gitee From 56c59b6e6bbe9c4c40b2314b563b9888e6d07672 Mon Sep 17 00:00:00 2001 From: Lu Feifei Date: Fri, 15 Jul 2022 13:47:08 +0800 Subject: [PATCH 39/50] anolis: sw64: delete run_mode in struct cpu_desc_t ANBZ: #4688 Signed-off-by: Lu Feifei Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/hw_init.h | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/sw_64/include/asm/hw_init.h b/arch/sw_64/include/asm/hw_init.h index f60a58570a92..71b569b6ec98 100644 --- a/arch/sw_64/include/asm/hw_init.h +++ b/arch/sw_64/include/asm/hw_init.h @@ -45,7 +45,6 @@ struct cpu_desc_t { char vendor_id[16]; char model_id[64]; unsigned long frequency; - __u8 run_mode; } __randomize_layout; #define MAX_NUMSOCKETS 8 -- Gitee From 8212a8f7c973015c0050b956bbd5c5c514c78716 Mon Sep 17 00:00:00 2001 From: Gu Zitao Date: Fri, 15 Jul 2022 11:06:06 +0800 Subject: [PATCH 40/50] anolis: sw64: fix compile error and warning for CONFIG_SMP=n ANBZ: #4688 Signed-off-by: Gu Zitao Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/process.c | 2 +- arch/sw_64/kernel/time.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/sw_64/kernel/process.c b/arch/sw_64/kernel/process.c index a75ae20205f3..2508c55311ca 100644 --- a/arch/sw_64/kernel/process.c +++ b/arch/sw_64/kernel/process.c @@ -52,7 +52,7 @@ void arch_cpu_idle(void) static void common_shutdown_1(void *generic_ptr) { struct halt_info *how = (struct halt_info *)generic_ptr; - int cpuid = smp_processor_id(); + int cpuid __maybe_unused = smp_processor_id(); /* No point in taking interrupts anymore. */ local_irq_disable(); diff --git a/arch/sw_64/kernel/time.c b/arch/sw_64/kernel/time.c index 15035a01e48a..0be676c80be4 100644 --- a/arch/sw_64/kernel/time.c +++ b/arch/sw_64/kernel/time.c @@ -4,6 +4,9 @@ #include #include #include +#ifndef CONFIG_SMP +#include +#endif #include -- Gitee From be0b4d0f01c14a2f1ad2a940fd6c9ad8a482070f Mon Sep 17 00:00:00 2001 From: Gu Zitao Date: Thu, 14 Jul 2022 10:00:10 +0800 Subject: [PATCH 41/50] anolis: sw64: add MIGHT_HAVE_PC_SERIO option to control selection of i8042 ANBZ: #4688 Since using i8042 drivers on sw64 would cause kernel crash, we add MIGHT_HAVE_PC_SERIO option to control selection of i8042. Signed-off-by: Gu Zitao Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/Kconfig | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/sw_64/Kconfig b/arch/sw_64/Kconfig index 480ee2779001..0c71e07f6f1b 100644 --- a/arch/sw_64/Kconfig +++ b/arch/sw_64/Kconfig @@ -14,7 +14,6 @@ config SW64 select GENERIC_IRQ_SHOW select ARCH_WANT_IPC_PARSE_VERSION select ARCH_HAVE_NMI_SAFE_CMPXCHG - select ARCH_MIGHT_HAVE_PC_SERIO select ARCH_NO_PREEMPT select ARCH_USE_CMPXCHG_LOCKREF select GENERIC_SMP_IDLE_THREAD @@ -242,6 +241,11 @@ config PLATFORM_XUELANG endchoice +config MIGHT_HAVE_PC_SERIO + bool "Use PC serio device i8042" + select ARCH_MIGHT_HAVE_PC_SERIO + default n + endmenu config LOCK_MEMB -- Gitee From 7f8c2b6a4411884cdfb5e149f92de45c7cc4a6fa Mon Sep 17 00:00:00 2001 From: Zhou Xuemei Date: Mon, 1 Aug 2022 13:40:25 +0800 Subject: [PATCH 42/50] anolis: sw64: pci: consolidate PCI config entry in drivers/pci ANBZ: #4688 According to commit eb01d42a7778 ("PCI: consolidate PCI config entry in drivers/pci"), use PCI config entry in drivers/pci instead of arch/sw64. Signed-off-by: Zhou Xuemei Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/Kconfig | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/arch/sw_64/Kconfig b/arch/sw_64/Kconfig index 0c71e07f6f1b..d4e641b73883 100644 --- a/arch/sw_64/Kconfig +++ b/arch/sw_64/Kconfig @@ -92,6 +92,8 @@ config SW64 select ACPI_REDUCED_HARDWARE_ONLY select GENERIC_TIME_VSYSCALL select SET_FS + select HAVE_PCI + select GENERIC_PCI_IOMAP if PCI select PCI_MSI_ARCH_FALLBACKS select DMA_OPS if PCI select HAVE_REGS_AND_STACK_ACCESS_API @@ -515,17 +517,6 @@ config ISA_DMA_API bool default y -config PCI - bool "PCI Support" - depends on SW64 - select GENERIC_PCI_IOMAP - default y - help - Find out whether you have a PCI motherboard. PCI is the name of a - bus system, i.e. the way the CPU talks to the other stuff inside - your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or - VESA. If you have PCI, say Y, otherwise N. - config PCI_DOMAINS def_bool PCI @@ -730,7 +721,6 @@ config HZ int "HZ of the short timer" default 500 -source "drivers/pci/Kconfig" source "drivers/eisa/Kconfig" source "drivers/pcmcia/Kconfig" -- Gitee From 676855d9b6dbe7973a8530c3cbe55d360ad224ab Mon Sep 17 00:00:00 2001 From: Zhou Xuemei Date: Mon, 27 Jun 2022 11:15:02 +0800 Subject: [PATCH 43/50] anolis: sw64: gpu: use memset_io and memcpy_toio/fromio for iomem ANBZ: #4688 Signed-off-by: Zhou Xuemei Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c | 8 +++++ drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 29 +++++++++++++++--- drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 42 ++++++++++++++++++++++----- 3 files changed, 67 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c index 04eaf3a8fddb..946f25f1079f 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c @@ -2816,7 +2816,11 @@ static int gfx_v7_0_mec_init(struct amdgpu_device *adev) } /* clear memory. Not sure if this is required or not */ +#if IS_ENABLED(CONFIG_SW64) + memset_io(hpd, 0, mec_hpd_size); +#else memset(hpd, 0, mec_hpd_size); +#endif amdgpu_bo_kunmap(adev->gfx.mec.hpd_eop_obj); amdgpu_bo_unreserve(adev->gfx.mec.hpd_eop_obj); @@ -2926,7 +2930,11 @@ static void gfx_v7_0_mqd_init(struct amdgpu_device *adev, u64 wb_gpu_addr; /* init the mqd struct */ +#if IS_ENABLED(CONFIG_SW64) + memset_io(mqd, 0, sizeof(struct cik_mqd)); +#else memset(mqd, 0, sizeof(struct cik_mqd)); +#endif mqd->header = 0xC0310800; mqd->compute_static_thread_mgmt_se0 = 0xffffffff; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 28c4e1fe5cd4..0ac2c33a0667 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -4641,8 +4641,13 @@ static int gfx_v8_0_kiq_init_queue(struct amdgpu_ring *ring) if (amdgpu_in_reset(adev)) { /* for GPU_RESET case */ /* reset MQD to a clean status */ - if (adev->gfx.mec.mqd_backup[mqd_idx]) + if (adev->gfx.mec.mqd_backup[mqd_idx]) { +#if IS_ENABLED(CONFIG_SW64) + memcpy_toio(mqd, adev->gfx.mec.mqd_backup[mqd_idx], sizeof(struct vi_mqd_allocation)); +#else memcpy(mqd, adev->gfx.mec.mqd_backup[mqd_idx], sizeof(struct vi_mqd_allocation)); +#endif + } /* reset ring buffer */ ring->wptr = 0; @@ -4667,12 +4672,13 @@ static int gfx_v8_0_kiq_init_queue(struct amdgpu_ring *ring) vi_srbm_select(adev, 0, 0, 0, 0); mutex_unlock(&adev->srbm_mutex); - if (adev->gfx.mec.mqd_backup[mqd_idx]) + if (adev->gfx.mec.mqd_backup[mqd_idx]) { #if IS_ENABLED(CONFIG_SW64) memcpy_fromio(adev->gfx.mec.mqd_backup[mqd_idx], mqd, sizeof(struct vi_mqd_allocation)); #else memcpy(adev->gfx.mec.mqd_backup[mqd_idx], mqd, sizeof(struct vi_mqd_allocation)); #endif + } } return 0; @@ -4685,7 +4691,11 @@ static int gfx_v8_0_kcq_init_queue(struct amdgpu_ring *ring) int mqd_idx = ring - &adev->gfx.compute_ring[0]; if (!amdgpu_in_reset(adev) && !adev->in_suspend) { +#if IS_ENABLED(CONFIG_SW64) + memset_io((void *)mqd, 0, sizeof(struct vi_mqd_allocation)); +#else memset((void *)mqd, 0, sizeof(struct vi_mqd_allocation)); +#endif ((struct vi_mqd_allocation *)mqd)->dynamic_cu_mask = 0xFFFFFFFF; ((struct vi_mqd_allocation *)mqd)->dynamic_rb_mask = 0xFFFFFFFF; mutex_lock(&adev->srbm_mutex); @@ -4694,12 +4704,23 @@ static int gfx_v8_0_kcq_init_queue(struct amdgpu_ring *ring) vi_srbm_select(adev, 0, 0, 0, 0); mutex_unlock(&adev->srbm_mutex); - if (adev->gfx.mec.mqd_backup[mqd_idx]) + if (adev->gfx.mec.mqd_backup[mqd_idx]) { +#if IS_ENABLED(CONFIG_SW64) + memcpy_fromio(adev->gfx.mec.mqd_backup[mqd_idx], mqd, sizeof(struct vi_mqd_allocation)); +#else memcpy(adev->gfx.mec.mqd_backup[mqd_idx], mqd, sizeof(struct vi_mqd_allocation)); +#endif + } } else if (amdgpu_in_reset(adev)) { /* for GPU_RESET case */ /* reset MQD to a clean status */ - if (adev->gfx.mec.mqd_backup[mqd_idx]) + if (adev->gfx.mec.mqd_backup[mqd_idx]) { +#if IS_ENABLED(CONFIG_SW64) + memcpy_toio(mqd, adev->gfx.mec.mqd_backup[mqd_idx], sizeof(struct vi_mqd_allocation)); +#else memcpy(mqd, adev->gfx.mec.mqd_backup[mqd_idx], sizeof(struct vi_mqd_allocation)); +#endif + } + /* reset ring buffer */ ring->wptr = 0; amdgpu_ring_clear_ring(ring); diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index c621ebd90031..c8d1245bfc2b 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -1978,7 +1978,11 @@ static int gfx_v9_0_mec_init(struct amdgpu_device *adev) return r; } +#if IS_ENABLED(CONFIG_SW64) + memset_io(hpd, 0, mec_hpd_size); +#else memset(hpd, 0, mec_hpd_size); +#endif amdgpu_bo_kunmap(adev->gfx.mec.hpd_eop_obj); amdgpu_bo_unreserve(adev->gfx.mec.hpd_eop_obj); @@ -3724,10 +3728,11 @@ static int gfx_v9_0_kiq_init_queue(struct amdgpu_ring *ring) if (amdgpu_in_reset(adev)) { /* for GPU_RESET case */ /* reset MQD to a clean status */ if (adev->gfx.mec.mqd_backup[mqd_idx]) { - if (IS_ENABLED(CONFIG_SW64)) - memcpy_toio(mqd, adev->gfx.mec.mqd_backup[mqd_idx], sizeof(struct v9_mqd_allocation)); - else - memcpy(mqd, adev->gfx.mec.mqd_backup[mqd_idx], sizeof(struct v9_mqd_allocation)); +#if IS_ENABLED(CONFIG_SW64) + memcpy_toio(mqd, adev->gfx.mec.mqd_backup[mqd_idx], sizeof(struct v9_mqd_allocation)); +#else + memcpy(mqd, adev->gfx.mec.mqd_backup[mqd_idx], sizeof(struct v9_mqd_allocation)); +#endif } /* reset ring buffer */ @@ -3740,7 +3745,11 @@ static int gfx_v9_0_kiq_init_queue(struct amdgpu_ring *ring) soc15_grbm_select(adev, 0, 0, 0, 0); mutex_unlock(&adev->srbm_mutex); } else { +#if IS_ENABLED(CONFIG_SW64) + memset_io((void *)mqd, 0, sizeof(struct v9_mqd_allocation)); +#else memset((void *)mqd, 0, sizeof(struct v9_mqd_allocation)); +#endif ((struct v9_mqd_allocation *)mqd)->dynamic_cu_mask = 0xFFFFFFFF; ((struct v9_mqd_allocation *)mqd)->dynamic_rb_mask = 0xFFFFFFFF; mutex_lock(&adev->srbm_mutex); @@ -3751,10 +3760,11 @@ static int gfx_v9_0_kiq_init_queue(struct amdgpu_ring *ring) mutex_unlock(&adev->srbm_mutex); if (adev->gfx.mec.mqd_backup[mqd_idx]) { - if (IS_ENABLED(CONFIG_SW64)) - memcpy_fromio(adev->gfx.mec.mqd_backup[mqd_idx], mqd, sizeof(struct v9_mqd_allocation)); - else - memcpy(adev->gfx.mec.mqd_backup[mqd_idx], mqd, sizeof(struct v9_mqd_allocation)); +#if IS_ENABLED(CONFIG_SW64) + memcpy_fromio(adev->gfx.mec.mqd_backup[mqd_idx], mqd, sizeof(struct v9_mqd_allocation)); +#else + memcpy(adev->gfx.mec.mqd_backup[mqd_idx], mqd, sizeof(struct v9_mqd_allocation)); +#endif } } @@ -3768,7 +3778,11 @@ static int gfx_v9_0_kcq_init_queue(struct amdgpu_ring *ring) int mqd_idx = ring - &adev->gfx.compute_ring[0]; if (!amdgpu_in_reset(adev) && !adev->in_suspend) { +#if IS_ENABLED(CONFIG_SW64) + memset_io((void *)mqd, 0, sizeof(struct v9_mqd_allocation)); +#else memset((void *)mqd, 0, sizeof(struct v9_mqd_allocation)); +#endif ((struct v9_mqd_allocation *)mqd)->dynamic_cu_mask = 0xFFFFFFFF; ((struct v9_mqd_allocation *)mqd)->dynamic_rb_mask = 0xFFFFFFFF; mutex_lock(&adev->srbm_mutex); @@ -3778,11 +3792,23 @@ static int gfx_v9_0_kcq_init_queue(struct amdgpu_ring *ring) mutex_unlock(&adev->srbm_mutex); if (adev->gfx.mec.mqd_backup[mqd_idx]) + if (adev->gfx.mec.mqd_backup[mqd_idx]) { +#if IS_ENABLED(CONFIG_SW64) + memcpy_fromio(adev->gfx.mec.mqd_backup[mqd_idx], mqd, sizeof(struct v9_mqd_allocation)); +#else memcpy(adev->gfx.mec.mqd_backup[mqd_idx], mqd, sizeof(struct v9_mqd_allocation)); +#endif + } } else if (amdgpu_in_reset(adev)) { /* for GPU_RESET case */ /* reset MQD to a clean status */ if (adev->gfx.mec.mqd_backup[mqd_idx]) + if (adev->gfx.mec.mqd_backup[mqd_idx]) { +#if IS_ENABLED(CONFIG_SW64) + memcpy_toio(mqd, adev->gfx.mec.mqd_backup[mqd_idx], sizeof(struct v9_mqd_allocation)); +#else memcpy(mqd, adev->gfx.mec.mqd_backup[mqd_idx], sizeof(struct v9_mqd_allocation)); +#endif + } /* reset ring buffer */ ring->wptr = 0; -- Gitee From 8c2719b44843d5f4ebb6fa782225bfe440f395f2 Mon Sep 17 00:00:00 2001 From: He Sheng Date: Tue, 19 Jul 2022 09:00:02 +0800 Subject: [PATCH 44/50] anolis: sw64: always use cpu_data and simplify it ANBZ: #4688 Make use of cpu_data no matter SMP is yes or no, and remove unused fields from it. After that, some function calls can be simplified. Signed-off-by: He Sheng Reviewed-by: Cui Wei Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/hw_init.h | 7 ++----- arch/sw_64/include/asm/mmu_context.h | 5 ----- arch/sw_64/kernel/setup.c | 21 ++++++++++++++++----- arch/sw_64/kernel/smp.c | 27 ++------------------------- arch/sw_64/kernel/time.c | 6 +----- arch/sw_64/mm/fault.c | 9 +-------- 6 files changed, 22 insertions(+), 53 deletions(-) diff --git a/arch/sw_64/include/asm/hw_init.h b/arch/sw_64/include/asm/hw_init.h index 71b569b6ec98..de9f93f9b26e 100644 --- a/arch/sw_64/include/asm/hw_init.h +++ b/arch/sw_64/include/asm/hw_init.h @@ -23,11 +23,6 @@ struct cpuinfo_sw64 { int need_new_asn; int asn_lock; unsigned long ipi_count; - unsigned long prof_multiplier; - unsigned long prof_counter; - unsigned char mcheck_expected; - unsigned char mcheck_taken; - unsigned char mcheck_extra; struct cache_desc icache; /* Primary I-cache */ struct cache_desc dcache; /* Primary D or combined I/D cache */ struct cache_desc scache; /* Secondary cache */ @@ -73,6 +68,8 @@ struct memmap_entry { }; extern struct cpuinfo_sw64 cpu_data[NR_CPUS]; +extern void store_cpu_data(int cpu); + extern struct cpu_desc_t cpu_desc; extern struct socket_desc_t socket_desc[MAX_NUMSOCKETS]; extern int memmap_nr; diff --git a/arch/sw_64/include/asm/mmu_context.h b/arch/sw_64/include/asm/mmu_context.h index d6cd01d55712..a797673273af 100644 --- a/arch/sw_64/include/asm/mmu_context.h +++ b/arch/sw_64/include/asm/mmu_context.h @@ -60,12 +60,7 @@ __reload_thread(struct pcb_struct *pcb) */ #include -#ifdef CONFIG_SMP #define cpu_last_asn(cpuid) (cpu_data[cpuid].last_asn) -#else -extern unsigned long last_asn; -#define cpu_last_asn(cpuid) last_asn -#endif /* CONFIG_SMP */ #define ASN_FIRST_VERSION (1UL << WIDTH_HARDWARE_ASN) #define HARDWARE_ASN_MASK ((1UL << WIDTH_HARDWARE_ASN) - 1) diff --git a/arch/sw_64/kernel/setup.c b/arch/sw_64/kernel/setup.c index 0e93643539d3..39103e4edee4 100644 --- a/arch/sw_64/kernel/setup.c +++ b/arch/sw_64/kernel/setup.c @@ -28,9 +28,10 @@ #include #include -#include #include #include +#include +#include #include "proto.h" #include "pci_impl.h" @@ -137,6 +138,17 @@ struct screen_info screen_info = { }; EXPORT_SYMBOL(screen_info); +/* + * Move global data into per-processor storage. + */ +void store_cpu_data(int cpu) +{ + cpu_data[cpu].loops_per_jiffy = loops_per_jiffy; + cpu_data[cpu].last_asn = ASN_FIRST_VERSION; + cpu_data[cpu].need_new_asn = 0; + cpu_data[cpu].asn_lock = 0; +} + #ifdef CONFIG_KEXEC void *kexec_control_page; @@ -859,13 +871,12 @@ setup_arch(char **cmdline_p) /* Default root filesystem to sda2. */ ROOT_DEV = Root_SDA2; - /* - * Identify the flock of penguins. - */ - #ifdef CONFIG_SMP setup_smp(); +#else + store_cpu_data(0); #endif + #ifdef CONFIG_NUMA cpu_set_node(); #endif diff --git a/arch/sw_64/kernel/smp.c b/arch/sw_64/kernel/smp.c index fb915d166069..1004e9e3be27 100644 --- a/arch/sw_64/kernel/smp.c +++ b/arch/sw_64/kernel/smp.c @@ -59,29 +59,6 @@ EXPORT_SYMBOL(smp_num_cpus); #define send_sleep_interrupt(cpu) send_ipi((cpu), II_SLEEP) #define send_wakeup_interrupt(cpu) send_ipi((cpu), II_WAKE) -/* - * Called by both boot and secondaries to move global data into - * per-processor storage. - */ -static inline void __init -smp_store_cpu_info(int cpuid) -{ - cpu_data[cpuid].loops_per_jiffy = loops_per_jiffy; - cpu_data[cpuid].last_asn = ASN_FIRST_VERSION; - cpu_data[cpuid].need_new_asn = 0; - cpu_data[cpuid].asn_lock = 0; -} - -/* - * Ideally sets up per-cpu profiling hooks. Doesn't do much now... - */ -static inline void __init -smp_setup_percpu_timer(int cpuid) -{ - setup_timer(); - cpu_data[cpuid].prof_counter = 1; - cpu_data[cpuid].prof_multiplier = 1; -} static void __init wait_boot_cpu_to_stop(int cpuid) { @@ -128,7 +105,7 @@ void smp_callin(void) wrent(entInt, 0); /* Get our local ticker going. */ - smp_setup_percpu_timer(cpuid); + setup_timer(); /* All kernel threads share the same mm context. */ mmgrab(&init_mm); @@ -298,7 +275,7 @@ void __init setup_smp(void) __cpu_to_rcid[num] = i; __rcid_to_cpu[i] = num; set_cpu_possible(num, true); - smp_store_cpu_info(num); + store_cpu_data(num); if (!cpumask_test_cpu(i, &cpu_offline)) set_cpu_present(num, true); num++; diff --git a/arch/sw_64/kernel/time.c b/arch/sw_64/kernel/time.c index 0be676c80be4..6a4c8a31465c 100644 --- a/arch/sw_64/kernel/time.c +++ b/arch/sw_64/kernel/time.c @@ -96,10 +96,6 @@ void setup_clocksource(void) } #endif /* !CONFIG_SMP */ -void __init common_init_rtc(void) -{ - setup_timer(); -} void __init time_init(void) @@ -114,7 +110,7 @@ time_init(void) setup_clocksource(); of_clk_init(NULL); /* Startup the timer source. */ - common_init_rtc(); + setup_timer(); } void calibrate_delay(void) diff --git a/arch/sw_64/mm/fault.c b/arch/sw_64/mm/fault.c index 15fd65b1b754..3255de5f0019 100644 --- a/arch/sw_64/mm/fault.c +++ b/arch/sw_64/mm/fault.c @@ -64,13 +64,7 @@ void show_all_vma(void) /* * Force a new ASN for a task. */ - -#ifndef CONFIG_SMP -unsigned long last_asn = ASN_FIRST_VERSION; -#endif - -void -__load_new_mm_context(struct mm_struct *next_mm) +void __load_new_mm_context(struct mm_struct *next_mm) { unsigned long mmc; struct pcb_struct *pcb; @@ -85,7 +79,6 @@ __load_new_mm_context(struct mm_struct *next_mm) __reload_thread(pcb); } - /* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to handle_mm_fault(). -- Gitee From 1571a9d0dcbee8b5d24576149ada3b40041bb4db Mon Sep 17 00:00:00 2001 From: He Chuyue Date: Tue, 19 Jul 2022 15:33:26 +0800 Subject: [PATCH 45/50] anolis: sw64: simplify do_entInt() ANBZ: #4688 It has already disabled interrupt in hmcode and it's unnecessary to disable again in do_entInt(). This way, do_entInt() is a wrapper of handle_chip_irq(), so simplify it. Signed-off-by: He Chuyue Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/chip/chip3/chip.c | 5 +++-- arch/sw_64/include/asm/irq_impl.h | 4 +--- arch/sw_64/kernel/irq_sw64.c | 9 --------- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/arch/sw_64/chip/chip3/chip.c b/arch/sw_64/chip/chip3/chip.c index 84ca7ffcb2ef..8697891e3930 100644 --- a/arch/sw_64/chip/chip3/chip.c +++ b/arch/sw_64/chip/chip3/chip.c @@ -656,8 +656,8 @@ static void handle_dev_int(struct pt_regs *regs) sw64_io_write(node, DEV_INT_CONFIG, config_val); } -void handle_chip_irq(unsigned long type, unsigned long vector, - unsigned long irq_arg, struct pt_regs *regs) +asmlinkage void do_entInt(unsigned long type, unsigned long vector, + unsigned long irq_arg, struct pt_regs *regs) { struct pt_regs *old_regs; @@ -738,6 +738,7 @@ void handle_chip_irq(unsigned long type, unsigned long vector, } pr_crit("PC = %016lx PS = %04lx\n", regs->pc, regs->ps); } +EXPORT_SYMBOL(do_entInt); /* * Early fix up the chip3 Root Complex settings diff --git a/arch/sw_64/include/asm/irq_impl.h b/arch/sw_64/include/asm/irq_impl.h index b568efef6994..48dbc486a126 100644 --- a/arch/sw_64/include/asm/irq_impl.h +++ b/arch/sw_64/include/asm/irq_impl.h @@ -41,10 +41,8 @@ enum sw64_irq_type { extern struct irqaction timer_irqaction; extern void init_rtc_irq(irq_handler_t handler); extern void handle_irq(int irq); -extern void handle_ipi(struct pt_regs *); +extern void handle_ipi(struct pt_regs *regs); extern void __init sw64_init_irq(void); extern irqreturn_t timer_interrupt(int irq, void *dev); -extern void handle_chip_irq(unsigned long type, unsigned long vector, - unsigned long irq_arg, struct pt_regs *regs); #endif diff --git a/arch/sw_64/kernel/irq_sw64.c b/arch/sw_64/kernel/irq_sw64.c index 8ab845d153eb..88809fa531dd 100644 --- a/arch/sw_64/kernel/irq_sw64.c +++ b/arch/sw_64/kernel/irq_sw64.c @@ -9,15 +9,6 @@ #include #include -asmlinkage void -do_entInt(unsigned long type, unsigned long vector, - unsigned long irq_arg, struct pt_regs *regs) -{ - local_irq_disable(); - handle_chip_irq(type, vector, irq_arg, regs); -} -EXPORT_SYMBOL(do_entInt); - void __init init_IRQ(void) { -- Gitee From a98f594b26210275199775efa568e2aba66d2712 Mon Sep 17 00:00:00 2001 From: Wang Yuanheng Date: Wed, 20 Jul 2022 15:55:57 +0800 Subject: [PATCH 46/50] anolis: sw64: fix compile errors when CONFIG_KVM=m ANBZ: #4688 Export symbol for bind_vcpu_enabled to fix compile errors when CONFIG_KVM=m. Signed-off-by: Wang Yuanheng Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/bindvcpu.c | 3 ++- arch/sw_64/kvm/kvm-sw64.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/sw_64/kernel/bindvcpu.c b/arch/sw_64/kernel/bindvcpu.c index 611c395c144b..46617eb68b7a 100644 --- a/arch/sw_64/kernel/bindvcpu.c +++ b/arch/sw_64/kernel/bindvcpu.c @@ -11,7 +11,8 @@ #include #include -extern bool bind_vcpu_enabled; +__read_mostly bool bind_vcpu_enabled; +EXPORT_SYMBOL(bind_vcpu_enabled); static int __init bind_vcpu_init(void) { diff --git a/arch/sw_64/kvm/kvm-sw64.c b/arch/sw_64/kvm/kvm-sw64.c index 8ba7e18698b3..9d209141820c 100644 --- a/arch/sw_64/kvm/kvm-sw64.c +++ b/arch/sw_64/kvm/kvm-sw64.c @@ -22,7 +22,7 @@ bool set_msi_flag; unsigned long sw64_kvm_last_vpn[NR_CPUS]; #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_NUMA) -__read_mostly bool bind_vcpu_enabled; +extern bool bind_vcpu_enabled; #endif #define cpu_last_vpn(cpuid) sw64_kvm_last_vpn[cpuid] -- Gitee From 9805d6c0da6a71a58a7150c2c9219a4d116f704a Mon Sep 17 00:00:00 2001 From: Du Yilong Date: Mon, 25 Jul 2022 14:24:36 +0800 Subject: [PATCH 47/50] anolis: sw64: kvm: expand the number of SWVM_IRQS ANBZ: #4688 As more devices are hot-plugged in a guest os, it will fail to respond interrupts because of insufficient interrupt resource and appear to be stuck. To fix this issue, expand the maximum number of irq supported to 256. Signed-off-by: Du Yilong Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/uapi/asm/kvm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sw_64/include/uapi/asm/kvm.h b/arch/sw_64/include/uapi/asm/kvm.h index ff1b6e7f096f..126c2a1d7411 100644 --- a/arch/sw_64/include/uapi/asm/kvm.h +++ b/arch/sw_64/include/uapi/asm/kvm.h @@ -5,7 +5,7 @@ /* * KVM SW specific structures and definitions. */ -#define SWVM_IRQS 64 +#define SWVM_IRQS 256 enum SW64_KVM_IRQ { SW64_KVM_IRQ_IPI = 27, SW64_KVM_IRQ_TIMER = 9, -- Gitee From f801f1c3855de78941a303e1b74e3a93be25dc03 Mon Sep 17 00:00:00 2001 From: Mao Minkai Date: Tue, 26 Jul 2022 10:02:06 +0800 Subject: [PATCH 48/50] anolis: sw64: fix deep-copy_user by deep-copy_template ANBZ: #4688 Some fp registers are clobbered in deep-copy_user() because this function was assumed to be used only in normal task context and to be safe to clobber caller-save fp registers. However, these assumptions have been proven wrong. Since deep-copy_user() is basically a deep-memcpy() with exception handling, a deep-copy_template() is now used to implement these two functions. Different macro defines and entry/exit code are used by deep-copy_user() and deep-memcpy(). Signed-off-by: Mao Minkai Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/lib/deep-copy_template.S | 299 +++++++++++++++++++++++++ arch/sw_64/lib/deep-copy_user.S | 332 +--------------------------- arch/sw_64/lib/deep-memcpy.S | 297 +------------------------ 3 files changed, 309 insertions(+), 619 deletions(-) create mode 100644 arch/sw_64/lib/deep-copy_template.S diff --git a/arch/sw_64/lib/deep-copy_template.S b/arch/sw_64/lib/deep-copy_template.S new file mode 100644 index 000000000000..8355ecf8a905 --- /dev/null +++ b/arch/sw_64/lib/deep-copy_template.S @@ -0,0 +1,299 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * template for memcpy and copy_user with SIMD + * + * $16: current store address + * $17: current load address + * $18: current bytes left to copy + * + */ + +#define NC_STORE_THRESHOLD 2048 + +#define SAVE_SIMD_REGS \ + ldi $sp, -0x60($sp); \ + addl $sp, 0x1f, $23; \ + bic $23, 0x1f, $23; \ + vstd $f1, 0($23); \ + vstd $f2, 0x20($23) + +#define RESTORE_SIMD_REGS \ + addl $sp, 0x1f, $23; \ + bic $23, 0x1f, $23; \ + vldd $f1, 0($23); \ + vldd $f2, 0x20($23); \ + ldi $sp, 0x60($sp) + +#define SAVE_SIMD_U_REGS \ + ldi $sp, -0x120($sp); \ + addl $sp, 0x1f, $23; \ + bic $23, 0x1f, $23; \ + vstd $f1, 0($23); \ + vstd $f2, 0x20($23); \ + vstd $f4, 0x40($23); \ + vstd $f5, 0x60($23); \ + vstd $f10, 0x80($23); \ + vstd $f11, 0xa0($23); \ + vstd $f20, 0xc0($23); \ + vstd $f21, 0xe0($23) + +#define RESTORE_SIMD_U_REGS \ + addl $sp, 0x1f, $23; \ + bic $23, 0x1f, $23; \ + vldd $f1, 0($23); \ + vldd $f2, 0x20($23); \ + vldd $f4, 0x40($23); \ + vldd $f5, 0x60($23); \ + vldd $f10, 0x80($23); \ + vldd $f11, 0xa0($23); \ + vldd $f20, 0xc0($23); \ + vldd $f21, 0xe0($23); \ + ldi $sp, 0x120($sp) + + ble $18, $out + and $16, 7, $1 + beq $1, $dest_aligned_8 + + .align 4 +$byte_loop_head: + FIXUP_LDST( ldbu $2, 0($17) ) + subl $18, 1, $18 + addl $17, 1, $17 + FIXUP_LDST( stb $2, 0($16) ) + addl $16, 1, $16 + ble $18, $out + and $16, 7, $1 + bne $1, $byte_loop_head + +$dest_aligned_8: + and $17, 7, $4 + subl $18, 16, $18 + blt $18, $quad_end + subl $18, 64, $18 + blt $18, $simd_end + and $16, 31, $1 + beq $1, $dest_aligned_32 + bne $4, $quad_u_loop_head + + .align 5 +$quad_loop_head: + FIXUP_LDST( ldl $2, 0($17) ) + subl $18, 8, $18 + addl $17, 8, $17 + FIXUP_LDST( stl $2, 0($16) ) + addl $16, 8, $16 + and $16, 31, $1 + blt $18, $simd_end + beq $16, $dest_aligned_32 + br $31, $quad_loop_head + +$dest_aligned_32: + and $17, 31, $5 + bne $5, $prep_simd_u_loop + +$prep_simd_loop: + SAVE_SIMD_REGS + ldi $1, NC_STORE_THRESHOLD($31) + cmple $18, $1, $1 + bne $1, $simd_loop + + .align 5 +$simd_loop_nc: + fillcs 128 * 5($17) + FIXUP_LDST( vldd $f1, 0($17) ) + FIXUP_LDST( vldd $f2, 32($17) ) + subl $18, 64, $18 + addl $17, 64, $17 + FIXUP_LDST( vstd_nc $f1, 0($16) ) + FIXUP_LDST( vstd_nc $f2, 32($16) ) + addl $16, 64, $16 + bge $18, $simd_loop_nc + memb # required for _nc store instructions + br $31, $simd_loop_end + + .align 5 +$simd_loop: + fillcs 128 * 5($17) + FIXUP_LDST( vldd $f1, 0($17) ) + FIXUP_LDST( vldd $f2, 32($17) ) + subl $18, 64, $18 + addl $17, 64, $17 + FIXUP_LDST( vstd $f1, 0($16) ) + FIXUP_LDST( vstd $f2, 32($16) ) + addl $16, 64, $16 + bge $18, $simd_loop + +$simd_loop_end: + addl $18, 64, $1 + cmplt $1, 32, $1 + bne $1, $no_more_simd + FIXUP_LDST( vldd $f1, 0($17) ) + subl $18, 32, $18 + addl $17, 32, $17 + FIXUP_LDST( vstd $f1, 0($16) ) + addl $16, 32, $16 + +$no_more_simd: + RESTORE_SIMD_REGS + +$simd_end: + addl $18, 64, $18 + blt $18, $quad_end + bne $4, $prep_quad_u_loop_tail + + .align 4 +$quad_loop_tail: + FIXUP_LDST( ldl $2, 0($17) ) + FIXUP_LDST( ldl $3, 8($17) ) + subl $18, 16, $18 + addl $17, 16, $17 + FIXUP_LDST( stl $2, 0($16) ) + FIXUP_LDST( stl $3, 8($16) ) + addl $16, 16, $16 + bge $18, $quad_loop_tail + +$quad_end: + addl $18, 16, $18 + ble $18, $out + cmplt $18, 8, $1 + bne $1, $byte_loop_tail + bne $4, $move_one_quad_u + +$move_one_quad: + FIXUP_LDST( ldl $2, 0($17) ) + subl $18, 8, $18 + addl $17, 8, $17 + FIXUP_LDST( stl $2, 0($16) ) + addl $16, 8, $16 + ble $18, $out + + .align 4 +$byte_loop_tail: + FIXUP_LDST( ldbu $2, 0($17) ) + subl $18, 1, $18 + addl $17, 1, $17 + FIXUP_LDST( stb $2, 0($16) ) + addl $16, 1, $16 + bgt $18, $byte_loop_tail + br $31, $out + +/* misaligned src and dst */ + .align 5 +$quad_u_loop_head: + FIXUP_LDST( ldl_u $2, 0($17) ) + FIXUP_LDST( ldl_u $3, 7($17) ) + subl $18, 8, $18 + addl $17, 8, $17 + extll $2, $4, $2 + exthl $3, $4, $3 + bis $2, $3, $2 + FIXUP_LDST( stl $2, 0($16) ) + addl $16, 8, $16 + blt $18, $simd_end + beq $16, $dest_aligned_32 + br $31, $quad_u_loop_head + +$prep_simd_u_loop: + SAVE_SIMD_U_REGS + andnot $17, 31, $3 + ldi $2, 256($31) + sll $5, 3, $1 + subl $2, $1, $2 + sll $1, 29, $1 + sll $2, 29, $2 + ifmovd $1, $f1 + ifmovd $2, $f2 + FIXUP_LDST( vldd $f4, 0($3) ) + ldi $1, NC_STORE_THRESHOLD($31) + cmple $18, $1, $1 + bne $1, $simd_u_loop + + .align 5 +$simd_u_loop_nc: + FIXUP_LDST( vldd $f5, 32($3) ) + fillcs 128 * 5($3) + srlow $f4, $f1, $f10 + sllow $f5, $f2, $f11 + vlogfc $f10, $f11, $f31, $f10 + FIXUP_LDST( vldd $f4, 64($3) ) + srlow $f5, $f1, $f20 + sllow $f4, $f2, $f21 + vlogfc $f20, $f21, $f31, $f20 + FIXUP_LDST( vstd_nc $f10, 0($16) ) + FIXUP_LDST( vstd_nc $f20, 32($16) ) + subl $18, 64, $18 + addl $3, 64, $3 + addl $16, 64, $16 + bge $18, $simd_u_loop_nc + memb # required for _nc store instructions + br $31, $simd_u_loop_end + + .align 5 +$simd_u_loop: + FIXUP_LDST( vldd $f5, 32($3) ) + fillcs 128 * 5($3) + srlow $f4, $f1, $f10 + sllow $f5, $f2, $f11 + vlogfc $f10, $f11, $f31, $f10 + FIXUP_LDST( vldd $f4, 64($3) ) + srlow $f5, $f1, $f20 + sllow $f4, $f2, $f21 + vlogfc $f20, $f21, $f31, $f20 + FIXUP_LDST( vstd $f10, 0($16) ) + FIXUP_LDST( vstd $f20, 32($16) ) + subl $18, 64, $18 + addl $3, 64, $3 + addl $16, 64, $16 + bge $18, $simd_u_loop + +$simd_u_loop_end: + addl $18, 64, $1 + cmplt $1, 32, $1 + bne $1, $no_more_simd_u + FIXUP_LDST( vldd $f5, 32($3) ) + srlow $f4, $f1, $f10 + sllow $f5, $f2, $f11 + vlogfc $f10, $f11, $f31, $f10 + FIXUP_LDST( vstd $f10, 0($16) ) + subl $18, 32, $18 + addl $3, 32, $3 + addl $16, 32, $16 + +$no_more_simd_u: + RESTORE_SIMD_U_REGS + bis $3, $5, $17 + br $31, $simd_end + +$prep_quad_u_loop_tail: + FIXUP_LDST( ldl_u $2, 0($17) ) + .align 5 +$quad_u_loop_tail: + FIXUP_LDST( ldl_u $3, 8($17) ) + extll $2, $4, $22 + exthl $3, $4, $23 + bis $22, $23, $22 + FIXUP_LDST( stl $22, 0($16) ) + FIXUP_LDST( ldl_u $2, 16($17) ) + extll $3, $4, $24 + exthl $2, $4, $25 + bis $24, $25, $24 + FIXUP_LDST( stl $24, 8($16) ) + subl $18, 16, $18 + addl $17, 16, $17 + addl $16, 16, $16 + bge $18, $quad_u_loop_tail + br $31, $quad_end + +$move_one_quad_u: + FIXUP_LDST( ldl_u $2, 0($17) ) + FIXUP_LDST( ldl_u $3, 8($17) ) + subl $18, 8, $18 + addl $17, 8, $17 + extll $2, $4, $22 + exthl $3, $4, $23 + bis $22, $23, $22 + FIXUP_LDST( stl $22, 0($16) ) + addl $16, 8, $16 + ble $18, $out + br $31, $byte_loop_tail diff --git a/arch/sw_64/lib/deep-copy_user.S b/arch/sw_64/lib/deep-copy_user.S index 631246c68bab..145e1cc6ba18 100644 --- a/arch/sw_64/lib/deep-copy_user.S +++ b/arch/sw_64/lib/deep-copy_user.S @@ -1,342 +1,22 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copy to/from user space, handling exceptions as we go.. This - * isn't exactly pretty. - * - * This is essentially the same as "memcpy()", but with a few twists. - * Notably, we have to make sure that $18 is always up-to-date and - * contains the right "bytes left to copy" value (and that it is updated - * only _after_ a successful copy). There is also some rather minor - * exception setup stuff.. - * - * Inputs: - * length in $18 - * destination address in $16 - * source address in $17 - * return address in $26 - * - * Outputs: - * bytes left to copy in $0 - * - * Clobbers: - * $1,$2,$3,$4,$5,$16,$17 - * - */ -/* Author: Copy_user simd version 1.1 (20190904) by Gao Xiuwu. -*/ #include /* Allow an exception for an insn; exit if we get one. */ -#define EXI(x, y...) \ - 99: x, ##y; \ +#define FIXUP_LDST(x, y) \ + 99: x, y; \ .section __ex_table, "a"; \ .long 99b - .; \ - ldi $31, $exitin-99b($31); \ + ldi $31, $out-99b($31); \ .previous -#define EXO(x,y...) \ - 99: x, ##y; \ - .section __ex_table, "a"; \ - .long 99b - .; \ - ldi $31, $exitout-99b($31); \ - .previous - - .set noat - .align 4 .globl __copy_user .ent __copy_user - __copy_user: .prologue 0 - subl $18, 32, $1 - beq $18, $zerolength - - and $16, 7, $3 - ble $1, $onebyteloop - beq $3, $destaligned - subl $3, 8, $3 -/* - * The fetcher stall also hides the 1 cycle cross-cluster stall for $3 (L --> U) - * This loop aligns the destination a byte at a time - * We know we have at least one trip through this loop - */ -$aligndest: - EXI(ldbu $1, 0($17)) - addl $16, 1, $16 - addl $3, 1, $3 - -/* - * the -1 is to compensate for the inc($16) done in a previous quadpack - * which allows us zero dependencies within either quadpack in the loop - */ - EXO(stb $1, -1($16)) - addl $17, 1, $17 - subl $18, 1, $18 - bne $3, $aligndest - -/* - * If we fell through into here, we have a minimum of 33 - 7 bytes - * If we arrived via branch, we have a minimum of 32 bytes - */ -$destaligned: - and $17, 7, $1 - bic $18, 7, $4 - #EXI(ldl_u $3, 0($17)) - beq $1, $quadaligned - -#ifndef MISQUAD_SCALAR -$misquad: - and $16, 31, $1 - beq $1, $dest32Baligned - -$align_32B: - EXI(ldbu $1, 0($17)) - addl $17, 1, $17 - EXO(stb $1, 0($16)) - subl $18, 1, $18 - addl $16, 1, $16 - and $16, 31, $1 - beq $18, $exitout - bne $1, $align_32B - -$dest32Baligned: - ldi $2, 256($31) - andnot $17, 31, $3 - EXI(vldd $f10, 0($3)) - and $17, 31, $5 - sll $5, 3, $5 - subw $2, $5, $4 - ifmovs $5, $f15 - ifmovs $4, $f14 - - cmple $18, 63, $1 - bne $1, $misalign_tail_simd - -$misalign_body_simd: - EXI(vldd $f11, 32($3)) - fillcs 128*5($3) - - srlow $f10, $f15, $f12 - sllow $f11, $f14, $f13 - #fillde 128*5($16) - vlogfc $f12, $f13, $f31, $f12 - - EXI(vldd $f10, 64($3)) - srlow $f11, $f15, $f22 - sllow $f10, $f14, $f23 - vlogfc $f22, $f23, $f31, $f22 - - EXO(vstd $f12, 0($16)) - EXO(vstd $f22, 32($16)) - - addl $16, 64, $16 - addl $3, 64, $3 - subl $18, 64, $18 - - cmple $18, 63, $1 - beq $1, $misalign_body_simd - br $misalign_tail_simd - -$misalign_tail_simd: - cmple $18, 31, $1 - bne $1, $before_misalign_tail_quads - - EXI(vldd $f11, 32($3)) - srlow $f10, $f15, $f12 - sllow $f11, $f14, $f13 - vlogfc $f12, $f13, $f31, $f12 - - EXO(vstd $f12, 0($16)) - - subl $18, 32, $18 - addl $16, 32, $16 - addl $3, 32, $3 - vfmov $f11, $f10 - -$before_misalign_tail_quads: - srlow $f10, $f15, $f12 - s8subl $18, $4, $1 - ble $1, $tail_quads - - EXI(vldd $f11, 32($3)) - sllow $f11, $f14, $f13 - vlogfc $f12, $f13, $f31, $f12 - -$tail_quads: - subl $18, 8, $1 - blt $1, $less_than_8 - -$move_a_quad: - fimovd $f12, $1 - srlow $f12, 64, $f12 - - EXO(stl $1, 0($16)) - subl $18, 8, $18 - addl $16, 8, $16 - subl $18, 8, $1 - bge $1, $move_a_quad - -$less_than_8: - .align 4 - beq $18, $exitout - fimovd $f12, $1 - -$tail_bytes: - EXO(stb $1, 0($16)) - subl $18, 1, $18 - srl $1, 8, $1 - addl $16, 1, $16 - bgt $18, $tail_bytes - br $exitout -#else - -/* - * In the worst case, we've just executed an ldl_u here from 0($17) - * and we'll repeat it once if we take the branch - */ - -/* Misaligned quadword loop - not unrolled. Leave it that way. */ -$misquad: - EXI(ldl_u $2, 8($17)) - subl $4, 8, $4 - extll $3, $17, $3 - exthl $2, $17, $1 - - bis $3, $1, $1 - EXO(stl $1, 0($16)) - addl $17, 8, $17 - subl $18, 8, $18 - - addl $16, 8, $16 - bis $2, $2, $3 - bne $4, $misquad - - beq $18, $zerolength - -/* We know we have at least one trip through the byte loop */ - EXI(ldbu $2, 0($17)) - addl $16, 1, $16 - br $31, $dirtyentry -#endif -/* Do the trailing byte loop load, then hop into the store part of the loop */ - -/* - * A minimum of (33 - 7) bytes to do a quad at a time. - * Based upon the usage context, it's worth the effort to unroll this loop - * $18 - number of bytes to be moved - * $4 - number of bytes to move as quadwords - * $16 is current destination address - * $17 is current source address - */ - -$quadaligned: - and $16, 31, $1 - beq $1, $quadaligned_dest32Baligned - -$quadaligned_align_32B: - EXI(ldl $1, 0($17)) - addl $17, 8, $17 - EXO(stl $1, 0($16)) - subl $18, 8, $18 - subl $4, 8, $4 - addl $16, 8, $16 - and $16, 31, $1 - beq $4, $onebyteloop - bne $1, $quadaligned_align_32B - -$quadaligned_dest32Baligned: - and $17, 31, $2 - bne $2, $dest32Baligned - -$quad32Bailgned: - subl $4, 64, $2 - blt $2, $onequad - -/* - * There is a significant assumption here that the source and destination - * addresses differ by more than 32 bytes. In this particular case, a - * sparsity of registers further bounds this to be a minimum of 8 bytes. - * But if this isn't met, then the output result will be incorrect. - * Furthermore, due to a lack of available registers, we really can't - * unroll this to be an 8x loop (which would enable us to use the wh64 - * instruction memory hint instruction). - */ - -$simd_quadalign_unroll2: - fillcs 128 * 5($17) - EXI(vldd $f22, 0($17)) - EXI(vldd $f23, 32($17)) - EXO(vstd $f22, 0($16)) - EXO(vstd $f23, 32($16)) - #fillde 128 * 5($16) - subl $4, 64, $4 - subl $18, 64, $18 - addl $17, 64, $17 - addl $16, 64, $16 - subl $4, 64, $3 - bge $3, $simd_quadalign_unroll2 - bne $4, $onequad - br $31, $noquads - -$onequad: - EXI(ldl $1, 0($17)) - subl $4, 8, $4 - addl $17, 8, $17 - - EXO(stl $1, 0($16)) - subl $18, 8, $18 - addl $16, 8, $16 - bne $4, $onequad - -$noquads: - beq $18, $zerolength - -/* - * For small copies (or the tail of a larger copy), do a very simple byte loop. - * There's no point in doing a lot of complex alignment calculations to try to - * to quadword stuff for a small amount of data. - * $18 - remaining number of bytes left to copy - * $16 - current dest addr - * $17 - current source addr - */ - -$onebyteloop: - EXI(ldbu $2, 0($17)) - addl $16, 1, $16 - -$dirtyentry: -/* - * the -1 is to compensate for the inc($16) done in a previous quadpack - * which allows us zero dependencies within either quadpack in the loop - */ - EXO(stb $2, -1($16)) - addl $17, 1, $17 - subl $18, 1, $18 - bgt $18, $onebyteloop - -$zerolength: -$exitout: +#include "deep-copy_template.S" +$out: bis $31, $18, $0 - ret $31, ($26), 1 - -$exitin: - - /* A stupid byte-by-byte zeroing of the rest of the output - * buffer. This cures security holes by never leaving - * random kernel data around to be copied elsewhere. - */ - - mov $18, $1 - -$101: - EXO(stb $31, 0($16)) - subl $1, 1, $1 - addl $16, 1, $16 - bgt $1, $101 - - bis $31, $18, $0 - ret $31, ($26), 1 - + ret .end __copy_user EXPORT_SYMBOL(__copy_user) diff --git a/arch/sw_64/lib/deep-memcpy.S b/arch/sw_64/lib/deep-memcpy.S index 83c726d42778..c4b5bf3d26df 100644 --- a/arch/sw_64/lib/deep-memcpy.S +++ b/arch/sw_64/lib/deep-memcpy.S @@ -2,307 +2,18 @@ #include -#define NC_STORE_THRESHOLD 2048 +#define FIXUP_LDST(x, y) \ + x, y -#define SAVE_SIMD_REGS \ - ldi $sp, -0x60($sp); \ - addl $sp, 0x1f, $23; \ - bic $23, 0x1f, $23; \ - vstd $f1, 0($23); \ - vstd $f2, 0x20($23) - -#define RESTORE_SIMD_REGS \ - addl $sp, 0x1f, $23; \ - bic $23, 0x1f, $23; \ - vldd $f1, 0($23); \ - vldd $f2, 0x20($23); \ - ldi $sp, 0x60($sp) - -#define SAVE_SIMD_U_REGS \ - ldi $sp, -0x120($sp); \ - addl $sp, 0x1f, $23; \ - bic $23, 0x1f, $23; \ - vstd $f1, 0($23); \ - vstd $f2, 0x20($23); \ - vstd $f4, 0x40($23); \ - vstd $f5, 0x60($23); \ - vstd $f10, 0x80($23); \ - vstd $f11, 0xa0($23); \ - vstd $f20, 0xc0($23); \ - vstd $f21, 0xe0($23) - -#define RESTORE_SIMD_U_REGS \ - addl $sp, 0x1f, $23; \ - bic $23, 0x1f, $23; \ - vldd $f1, 0($23); \ - vldd $f2, 0x20($23); \ - vldd $f4, 0x40($23); \ - vldd $f5, 0x60($23); \ - vldd $f10, 0x80($23); \ - vldd $f11, 0xa0($23); \ - vldd $f20, 0xc0($23); \ - vldd $f21, 0xe0($23); \ - ldi $sp, 0x120($sp) - - .set noat - .align 4 .globl memcpy .ent memcpy memcpy: .frame $30, 0, $26, 0 .prologue 0 - mov $16, $0 - ble $18, $out - and $16, 7, $1 - beq $1, $dest_aligned_8 - - .align 4 -$byte_loop_head: - ldbu $2, 0($17) - subl $18, 1, $18 - addl $17, 1, $17 - stb $2, 0($16) - addl $16, 1, $16 - ble $18, $out - and $16, 7, $1 - bne $1, $byte_loop_head - -$dest_aligned_8: - and $17, 7, $4 - subl $18, 16, $18 - blt $18, $quad_end - subl $18, 64, $18 - blt $18, $simd_end - and $16, 31, $1 - beq $1, $dest_aligned_32 - bne $4, $quad_u_loop_head - - .align 5 -$quad_loop_head: - ldl $2, 0($17) - subl $18, 8, $18 - addl $17, 8, $17 - stl $2, 0($16) - addl $16, 8, $16 - and $16, 31, $1 - blt $18, $simd_end - beq $16, $dest_aligned_32 - br $31, $quad_loop_head - -$dest_aligned_32: - and $17, 31, $5 - bne $5, $prep_simd_u_loop - -$prep_simd_loop: - SAVE_SIMD_REGS - ldi $1, NC_STORE_THRESHOLD($31) - cmple $18, $1, $1 - bne $1, $simd_loop - - .align 5 -$simd_loop_nc: - fillcs 128 * 5($17) - vldd $f1, 0($17) - vldd $f2, 32($17) - subl $18, 64, $18 - addl $17, 64, $17 - vstd_nc $f1, 0($16) - vstd_nc $f2, 32($16) - addl $16, 64, $16 - bge $18, $simd_loop_nc - memb # required for _nc store instructions - br $31, $simd_loop_end - - .align 5 -$simd_loop: - fillcs 128 * 5($17) - vldd $f1, 0($17) - vldd $f2, 32($17) - subl $18, 64, $18 - addl $17, 64, $17 - vstd $f1, 0($16) - vstd $f2, 32($16) - addl $16, 64, $16 - bge $18, $simd_loop - -$simd_loop_end: - addl $18, 64, $1 - cmplt $1, 32, $1 - bne $1, $no_more_simd - vldd $f1, 0($17) - subl $18, 32, $18 - addl $17, 32, $17 - vstd $f1, 0($16) - addl $16, 32, $16 - -$no_more_simd: - RESTORE_SIMD_REGS - -$simd_end: - addl $18, 64, $18 - blt $18, $quad_end - bne $4, $prep_quad_u_loop_tail - - .align 4 -$quad_loop_tail: - ldl $2, 0($17) - ldl $3, 8($17) - subl $18, 16, $18 - addl $17, 16, $17 - stl $2, 0($16) - stl $3, 8($16) - addl $16, 16, $16 - bge $18, $quad_loop_tail - -$quad_end: - addl $18, 16, $18 - ble $18, $out - cmplt $18, 8, $1 - bne $1, $byte_loop_tail - bne $4, $move_one_quad_u - -$move_one_quad: - ldl $2, 0($17) - subl $18, 8, $18 - addl $17, 8, $17 - stl $2, 0($16) - addl $16, 8, $16 - ble $18, $out - - .align 4 -$byte_loop_tail: - ldbu $2, 0($17) - subl $18, 1, $18 - addl $17, 1, $17 - stb $2, 0($16) - addl $16, 1, $16 - bgt $18, $byte_loop_tail - +#include "deep-copy_template.S" $out: - ret $31, ($26), 1 - - - - .align 5 -$quad_u_loop_head: - ldl_u $2, 0($17) - ldl_u $3, 7($17) - subl $18, 8, $18 - addl $17, 8, $17 - extll $2, $4, $2 - exthl $3, $4, $3 - bis $2, $3, $2 - stl $2, 0($16) - addl $16, 8, $16 - blt $18, $simd_end - beq $16, $dest_aligned_32 - br $31, $quad_u_loop_head - -$prep_simd_u_loop: - SAVE_SIMD_U_REGS - andnot $17, 31, $3 - ldi $2, 256($31) - sll $5, 3, $1 - subl $2, $1, $2 - sll $1, 29, $1 - sll $2, 29, $2 - ifmovd $1, $f1 - ifmovd $2, $f2 - vldd $f4, 0($3) - ldi $1, NC_STORE_THRESHOLD($31) - cmple $18, $1, $1 - bne $1, $simd_u_loop - - .align 5 -$simd_u_loop_nc: - vldd $f5, 32($3) - fillcs 128 * 5($3) - srlow $f4, $f1, $f10 - sllow $f5, $f2, $f11 - vlogfc $f10, $f11, $f31, $f10 - vldd $f4, 64($3) - srlow $f5, $f1, $f20 - sllow $f4, $f2, $f21 - vlogfc $f20, $f21, $f31, $f20 - vstd_nc $f10, 0($16) - vstd_nc $f20, 32($16) - subl $18, 64, $18 - addl $3, 64, $3 - addl $16, 64, $16 - bge $18, $simd_u_loop_nc - memb # required for _nc store instructions - br $31, $simd_u_loop_end - - .align 5 -$simd_u_loop: - vldd $f5, 32($3) - fillcs 128 * 5($3) - srlow $f4, $f1, $f10 - sllow $f5, $f2, $f11 - vlogfc $f10, $f11, $f31, $f10 - vldd $f4, 64($3) - srlow $f5, $f1, $f20 - sllow $f4, $f2, $f21 - vlogfc $f20, $f21, $f31, $f20 - vstd $f10, 0($16) - vstd $f20, 32($16) - subl $18, 64, $18 - addl $3, 64, $3 - addl $16, 64, $16 - bge $18, $simd_u_loop - -$simd_u_loop_end: - addl $18, 64, $1 - cmplt $1, 32, $1 - bne $1, $no_more_simd_u - vldd $f5, 32($3) - srlow $f4, $f1, $f10 - sllow $f5, $f2, $f11 - vlogfc $f10, $f11, $f31, $f10 - vstd $f10, 0($16) - subl $18, 32, $18 - addl $3, 32, $3 - addl $16, 32, $16 - -$no_more_simd_u: - RESTORE_SIMD_U_REGS - bis $3, $5, $17 - br $31, $simd_end - -$prep_quad_u_loop_tail: - ldl_u $2, 0($17) - .align 5 -$quad_u_loop_tail: - ldl_u $3, 8($17) - extll $2, $4, $22 - exthl $3, $4, $23 - bis $22, $23, $22 - stl $22, 0($16) - ldl_u $2, 16($17) - extll $3, $4, $24 - exthl $2, $4, $25 - bis $24, $25, $24 - stl $24, 8($16) - subl $18, 16, $18 - addl $17, 16, $17 - addl $16, 16, $16 - bge $18, $quad_u_loop_tail - br $31, $quad_end - -$move_one_quad_u: - ldl_u $2, 0($17) - ldl_u $3, 8($17) - subl $18, 8, $18 - addl $17, 8, $17 - extll $2, $4, $22 - exthl $3, $4, $23 - bis $22, $23, $22 - stl $22, 0($16) - addl $16, 8, $16 - ble $18, $out - br $31, $byte_loop_tail - + ret .end memcpy EXPORT_SYMBOL(memcpy) __memcpy = memcpy -- Gitee From f5aa9604474b946d4a5c7cbd8225d9c0e86c6c5e Mon Sep 17 00:00:00 2001 From: Mao Minkai Date: Tue, 26 Jul 2022 10:03:58 +0800 Subject: [PATCH 49/50] anolis: sw64: remove context check in csum_partial_copy_from_user() ANBZ: #4688 In previous patch, we fixed deep-copy_user(). It's now safe to use it in any context, so no need to check. Signed-off-by: Mao Minkai Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/lib/csum_partial_copy.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/arch/sw_64/lib/csum_partial_copy.c b/arch/sw_64/lib/csum_partial_copy.c index 742dd63cdb70..1a8c18757e09 100644 --- a/arch/sw_64/lib/csum_partial_copy.c +++ b/arch/sw_64/lib/csum_partial_copy.c @@ -61,10 +61,7 @@ csum_partial_cfu_dest_aligned(const unsigned long __user *src, unsigned long checksum = ~0U; int err = 0; - if (likely(!uaccess_kernel())) - err = __copy_from_user(dst, src, len + 8); - else - memcpy(dst, src, len + 8); + err = __copy_from_user(dst, src, len+8); while (len > 0) { word = *dst; @@ -93,10 +90,7 @@ csum_partial_cfu_dest_unaligned(const unsigned long __user *src, unsigned long checksum = ~0U; int err = 0; - if (likely(!uaccess_kernel())) - err = __copy_from_user(dst, src, len + 8); - else - memcpy(dst, src, len + 8); + err = __copy_from_user(dst, src, len+8); dst = (unsigned long *)((unsigned long)dst & (~7UL)); word = *dst; -- Gitee From 36ed3ec906d6eb8896bb7ec005155568d32b6503 Mon Sep 17 00:00:00 2001 From: Wu Liliu Date: Tue, 26 Jul 2022 17:41:11 +0800 Subject: [PATCH 50/50] anolis: sw64: rename dik_* methods ANBZ: #4688 Since die_if_kernel() has been removed, the prefix `dik_` is not appropriate. Remove this prefix and simplify the implementation if there is no one to forward the exception to. Signed-off-by: Wu Liliu Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/process.c | 11 ----------- arch/sw_64/kernel/proto.h | 2 +- arch/sw_64/kernel/ptrace.c | 2 +- arch/sw_64/kernel/traps.c | 31 +++++++------------------------ arch/sw_64/mm/fault.c | 4 ++-- 5 files changed, 11 insertions(+), 39 deletions(-) diff --git a/arch/sw_64/kernel/process.c b/arch/sw_64/kernel/process.c index 2508c55311ca..4d223a7255bb 100644 --- a/arch/sw_64/kernel/process.c +++ b/arch/sw_64/kernel/process.c @@ -102,17 +102,6 @@ void machine_power_off(void) } -/* Used by sysrq-p, among others. I don't believe r9-r15 are ever - * saved in the context it's used. - */ - -void -show_regs(struct pt_regs *regs) -{ - show_regs_print_info(KERN_DEFAULT); - dik_show_regs(regs); -} - /* * Re-start a thread when doing execve() */ diff --git a/arch/sw_64/kernel/proto.h b/arch/sw_64/kernel/proto.h index f2b77d370da1..f84629ec05ea 100644 --- a/arch/sw_64/kernel/proto.h +++ b/arch/sw_64/kernel/proto.h @@ -12,7 +12,7 @@ extern int ptrace_set_bpt(struct task_struct *child); extern int ptrace_cancel_bpt(struct task_struct *child); /* traps.c */ -extern void dik_show_regs(struct pt_regs *regs); +extern void show_regs(struct pt_regs *regs); extern void die(char *str, struct pt_regs *regs, long err); /* timer.c */ diff --git a/arch/sw_64/kernel/ptrace.c b/arch/sw_64/kernel/ptrace.c index bdbd0d97a130..064296711b2f 100644 --- a/arch/sw_64/kernel/ptrace.c +++ b/arch/sw_64/kernel/ptrace.c @@ -487,7 +487,7 @@ int do_match(unsigned long address, unsigned long mmcsr, long cause, struct pt_r case MMCSR__DA_MATCH: case MMCSR__DV_MATCH: case MMCSR__DAV_MATCH: - dik_show_regs(regs); + show_regs(regs); if (!(current->ptrace & PT_PTRACED)) { printk(" pid %d %s not be ptraced, return\n", current->pid, current->comm); diff --git a/arch/sw_64/kernel/traps.c b/arch/sw_64/kernel/traps.c index 5f2348dd087f..9915160d95d2 100644 --- a/arch/sw_64/kernel/traps.c +++ b/arch/sw_64/kernel/traps.c @@ -31,8 +31,10 @@ #include "proto.h" -void dik_show_regs(struct pt_regs *regs) +void show_regs(struct pt_regs *regs) { + show_regs_print_info(KERN_DEFAULT); + printk("pc = [<%016lx>] ra = [<%016lx>] ps = %04lx %s\n", regs->pc, regs->r26, regs->ps, print_tainted()); printk("pc is at %pSR\n", (void *)regs->pc); @@ -62,8 +64,7 @@ void dik_show_regs(struct pt_regs *regs) printk("gp = %016lx sp = %p\n", regs->gp, regs+1); } -static void -dik_show_code(unsigned int *pc) +static void show_code(unsigned int *pc) { long i; unsigned int insn; @@ -93,15 +94,11 @@ void die(char *str, struct pt_regs *regs, long err) pr_emerg("%s [#%d]\n", str, ++die_counter); -#ifdef CONFIG_SMP - printk("CPU %d ", hard_smp_processor_id()); -#endif - printk("%s(%d): %s %ld\n", current->comm, task_pid_nr(current), str, err); - ret = notify_die(DIE_OOPS, str, regs, err, 0, SIGSEGV); print_modules(); - dik_show_regs(regs); + show_regs(regs); + show_code((unsigned int *)regs->pc); show_stack(current, NULL, KERN_EMERG); bust_spinlocks(0); @@ -508,21 +505,7 @@ do_entUna(void *va, unsigned long opcode, unsigned long reg, * Since the registers are in a weird format, dump them ourselves. */ - printk("%s(%d): unhandled unaligned exception\n", - current->comm, task_pid_nr(current)); - - dik_show_regs(regs); - dik_show_code((unsigned int *)pc); - show_stack(current, NULL, KERN_EMERG); - - if (test_and_set_thread_flag(TIF_DIE_IF_KERNEL)) { - printk("die_if_kernel recursion detected.\n"); - local_irq_enable(); - while (1) - asm("nop"); - } - do_exit(SIGSEGV); - + die("Unhandled unaligned exception", regs, error); } /* diff --git a/arch/sw_64/mm/fault.c b/arch/sw_64/mm/fault.c index 3255de5f0019..541e30b4b84c 100644 --- a/arch/sw_64/mm/fault.c +++ b/arch/sw_64/mm/fault.c @@ -32,7 +32,7 @@ static inline int notify_page_fault(struct pt_regs *regs, unsigned long mmcsr) #endif extern void die(char *, struct pt_regs *, long); -extern void dik_show_regs(struct pt_regs *regs); +extern void show_regs(struct pt_regs *regs); void show_all_vma(void) { @@ -325,7 +325,7 @@ do_page_fault(unsigned long address, unsigned long mmcsr, if (unlikely(segv_debug_enabled)) { pr_info("fault: want to send_segv: pid %d, cause = %#lx, mmcsr = %#lx, address = %#lx, pc %#lx\n", current->pid, cause, mmcsr, address, regs->pc); - dik_show_regs(regs); + show_regs(regs); show_all_vma(); } -- Gitee