diff options
| author | Zeng Chi <zengchi@kylinos.cn> | 2026-09-21 18:24:42 +0800 |
|---|---|---|
| committer | Sean Christopherson <seanjc@google.com> | 2026-09-22 08:36:16 -0700 |
| commit | 119e9db233ad0f4cbd4cfb9f9385a7bca378b37d (patch) | |
| tree | 660d50d4139cb750fbde1ae3432452c20726c99d /arch/m68k/virt | |
| download | linux-stable-119e9db233ad0f4cbd4cfb9f9385a7bca378b37d.tar.gz linux-stable-119e9db233ad0f4cbd4cfb9f9385a7bca378b37d.zip | |
KVM: Don't pre-reserve xarray entries when storing empty/NULL attributesgrafted
Skip the xarray reservation loop when clearing all memory attributes, as
storing NULL only erases the entry and never needs to allocate, so no
reservation (and no cleanup of a failed one) is required in that case.
Suggested-by: Sean Christopherson <seanjc@google.com>
Cc: David Ballesteros <davimaba.v@proton.me>
Signed-off-by: Zeng Chi <zengchi@kylinos.cn>
Link: https://patch.msgid.link/20260921102442.1232375-1-zeng_chi911@163.com
[sean: split to separate patch]
Signed-off-by: Sean Christopherson <seanjc@google.com>
Diffstat (limited to 'arch/m68k/virt')
| -rw-r--r-- | arch/m68k/virt/Makefile | 6 | ||||
| -rw-r--r-- | arch/m68k/virt/config.c | 92 | ||||
| -rw-r--r-- | arch/m68k/virt/ints.c | 154 | ||||
| -rw-r--r-- | arch/m68k/virt/platform.c | 94 |
4 files changed, 346 insertions, 0 deletions
diff --git a/arch/m68k/virt/Makefile b/arch/m68k/virt/Makefile new file mode 100644 index 000000000..54b9b2866 --- /dev/null +++ b/arch/m68k/virt/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Makefile for Linux arch/m68k/virt source directory +# + +obj-y := config.o ints.o platform.o diff --git a/arch/m68k/virt/config.c b/arch/m68k/virt/config.c new file mode 100644 index 000000000..b338e2a8d --- /dev/null +++ b/arch/m68k/virt/config.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/reboot.h> +#include <linux/serial_core.h> +#include <clocksource/timer-goldfish.h> + +#include <asm/bootinfo.h> +#include <asm/bootinfo-virt.h> +#include <asm/byteorder.h> +#include <asm/machdep.h> +#include <asm/virt.h> +#include <asm/config.h> + +struct virt_booter_data virt_bi_data; + +static void virt_get_model(char *str) +{ + /* str is 80 characters long */ + sprintf(str, "QEMU Virtual M68K Machine (%u.%u.%u)", + (u8)(virt_bi_data.qemu_version >> 24), + (u8)(virt_bi_data.qemu_version >> 16), + (u8)(virt_bi_data.qemu_version >> 8)); +} +static void virt_reset(void) +{ + do_kernel_restart(NULL); +} + +/* + * Parse a virtual-m68k-specific record in the bootinfo + */ + +int __init virt_parse_bootinfo(const struct bi_record *record) +{ + int unknown = 0; + const void *data = record->data; + + switch (be16_to_cpu(record->tag)) { + case BI_VIRT_QEMU_VERSION: + virt_bi_data.qemu_version = be32_to_cpup(data); + break; + case BI_VIRT_GF_PIC_BASE: + virt_bi_data.pic.mmio = be32_to_cpup(data); + data += 4; + virt_bi_data.pic.irq = be32_to_cpup(data); + break; + case BI_VIRT_GF_RTC_BASE: + virt_bi_data.rtc.mmio = be32_to_cpup(data); + data += 4; + virt_bi_data.rtc.irq = be32_to_cpup(data); + break; + case BI_VIRT_GF_TTY_BASE: + virt_bi_data.tty.mmio = be32_to_cpup(data); + data += 4; + virt_bi_data.tty.irq = be32_to_cpup(data); + break; + case BI_VIRT_CTRL_BASE: + virt_bi_data.ctrl.mmio = be32_to_cpup(data); + data += 4; + virt_bi_data.ctrl.irq = be32_to_cpup(data); + break; + case BI_VIRT_VIRTIO_BASE: + virt_bi_data.virtio.mmio = be32_to_cpup(data); + data += 4; + virt_bi_data.virtio.irq = be32_to_cpup(data); + break; + default: + unknown = 1; + break; + } + return unknown; +} + +static void __init virt_sched_init(void) +{ + goldfish_timer_init(virt_bi_data.rtc.irq, + (void __iomem *)virt_bi_data.rtc.mmio); +} + +void __init config_virt(void) +{ + char earlycon[24]; + + snprintf(earlycon, sizeof(earlycon), "early_gf_tty,0x%08x", + virt_bi_data.tty.mmio); + setup_earlycon(earlycon); + + mach_init_IRQ = virt_init_IRQ; + mach_sched_init = virt_sched_init; + mach_get_model = virt_get_model; + mach_reset = virt_reset; +} diff --git a/arch/m68k/virt/ints.c b/arch/m68k/virt/ints.c new file mode 100644 index 000000000..896aa6eb8 --- /dev/null +++ b/arch/m68k/virt/ints.c @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/sched/debug.h> +#include <linux/types.h> +#include <linux/ioport.h> + +#include <asm/hwtest.h> +#include <asm/irq.h> +#include <asm/irq_regs.h> +#include <asm/processor.h> +#include <asm/virt.h> + +#define GFPIC_REG_IRQ_PENDING 0x04 +#define GFPIC_REG_IRQ_DISABLE_ALL 0x08 +#define GFPIC_REG_IRQ_DISABLE 0x0c +#define GFPIC_REG_IRQ_ENABLE 0x10 + +static struct resource picres[6]; +static const char *picname[6] = { + "goldfish_pic.0", + "goldfish_pic.1", + "goldfish_pic.2", + "goldfish_pic.3", + "goldfish_pic.4", + "goldfish_pic.5" +}; + +/* + * 6 goldfish-pic for CPU IRQ #1 to IRQ #6 + * CPU IRQ #1 -> PIC #1 + * IRQ #1 to IRQ #31 -> unused + * IRQ #32 -> goldfish-tty + * CPU IRQ #2 -> PIC #2 + * IRQ #1 to IRQ #32 -> virtio-mmio from 1 to 32 + * CPU IRQ #3 -> PIC #3 + * IRQ #1 to IRQ #32 -> virtio-mmio from 33 to 64 + * CPU IRQ #4 -> PIC #4 + * IRQ #1 to IRQ #32 -> virtio-mmio from 65 to 96 + * CPU IRQ #5 -> PIC #5 + * IRQ #1 to IRQ #32 -> virtio-mmio from 97 to 128 + * CPU IRQ #6 -> PIC #6 + * IRQ #1 -> goldfish-timer + * IRQ #2 -> goldfish-rtc + * IRQ #3 to IRQ #32 -> unused + * CPU IRQ #7 -> NMI + */ + +static u32 gfpic_read(int pic, int reg) +{ + void __iomem *base = (void __iomem *)(virt_bi_data.pic.mmio + + pic * 0x1000); + + return ioread32be(base + reg); +} + +static void gfpic_write(u32 value, int pic, int reg) +{ + void __iomem *base = (void __iomem *)(virt_bi_data.pic.mmio + + pic * 0x1000); + + iowrite32be(value, base + reg); +} + +#define GF_PIC(irq) ((irq - IRQ_USER) / 32) +#define GF_IRQ(irq) ((irq - IRQ_USER) % 32) + +static void virt_irq_enable(struct irq_data *data) +{ + gfpic_write(BIT(GF_IRQ(data->irq)), GF_PIC(data->irq), + GFPIC_REG_IRQ_ENABLE); +} + +static void virt_irq_disable(struct irq_data *data) +{ + gfpic_write(BIT(GF_IRQ(data->irq)), GF_PIC(data->irq), + GFPIC_REG_IRQ_DISABLE); +} + +static unsigned int virt_irq_startup(struct irq_data *data) +{ + virt_irq_enable(data); + return 0; +} + +static irqreturn_t virt_nmi_handler(int irq, void *dev_id) +{ + static int in_nmi; + + if (READ_ONCE(in_nmi)) + return IRQ_HANDLED; + WRITE_ONCE(in_nmi, 1); + + pr_warn("Non-Maskable Interrupt\n"); + show_registers(get_irq_regs()); + + WRITE_ONCE(in_nmi, 0); + return IRQ_HANDLED; +} + +static struct irq_chip virt_irq_chip = { + .name = "virt", + .irq_enable = virt_irq_enable, + .irq_disable = virt_irq_disable, + .irq_startup = virt_irq_startup, + .irq_shutdown = virt_irq_disable, +}; + +static void goldfish_pic_irq(struct irq_desc *desc) +{ + u32 irq_pending; + unsigned int irq_num; + unsigned int pic = desc->irq_data.irq - 1; + + irq_pending = gfpic_read(pic, GFPIC_REG_IRQ_PENDING); + irq_num = IRQ_USER + pic * 32; + + do { + if (irq_pending & 1) + generic_handle_irq(irq_num); + ++irq_num; + irq_pending >>= 1; + } while (irq_pending); +} + +void __init virt_init_IRQ(void) +{ + unsigned int i; + + m68k_setup_irq_controller(&virt_irq_chip, handle_simple_irq, IRQ_USER, + NUM_VIRT_SOURCES - IRQ_USER); + + for (i = 0; i < 6; i++) { + + picres[i] = (struct resource) + DEFINE_RES_MEM_NAMED(virt_bi_data.pic.mmio + i * 0x1000, + 0x1000, picname[i]); + if (request_resource(&iomem_resource, &picres[i])) { + pr_err("Cannot allocate %s resource\n", picname[i]); + return; + } + + irq_set_chained_handler(virt_bi_data.pic.irq + i, + goldfish_pic_irq); + } + + if (request_irq(IRQ_AUTO_7, virt_nmi_handler, 0, "NMI", + virt_nmi_handler)) + pr_err("Couldn't register NMI\n"); +} diff --git a/arch/m68k/virt/platform.c b/arch/m68k/virt/platform.c new file mode 100644 index 000000000..764f556b4 --- /dev/null +++ b/arch/m68k/virt/platform.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/memblock.h> +#include <asm/virt.h> +#include <asm/irq.h> + +#define VIRTIO_BUS_NB 128 + +static struct platform_device * __init virt_virtio_init(unsigned int id) +{ + const struct resource res[] = { + DEFINE_RES_MEM(virt_bi_data.virtio.mmio + id * 0x200, 0x200), + DEFINE_RES_IRQ(virt_bi_data.virtio.irq + id), + }; + + return platform_device_register_simple("virtio-mmio", id, + res, ARRAY_SIZE(res)); +} + +static int __init virt_platform_init(void) +{ + const struct resource goldfish_tty_res[] = { + DEFINE_RES_MEM(virt_bi_data.tty.mmio, 1), + DEFINE_RES_IRQ(virt_bi_data.tty.irq), + }; + /* this is the second gf-rtc, the first one is used by the scheduler */ + const struct resource goldfish_rtc_res[] = { + DEFINE_RES_MEM(virt_bi_data.rtc.mmio + 0x1000, 0x1000), + DEFINE_RES_IRQ(virt_bi_data.rtc.irq + 1), + }; + const struct resource virt_ctrl_res[] = { + DEFINE_RES_MEM(virt_bi_data.ctrl.mmio, 0x100), + }; + struct platform_device *pdev1, *pdev2, *pdev3; + struct platform_device *pdevs[VIRTIO_BUS_NB]; + unsigned int i; + int ret = 0; + + if (!MACH_IS_VIRT) + return -ENODEV; + + /* We need this to have DMA'able memory provided to goldfish-tty */ + min_low_pfn = 0; + + pdev1 = platform_device_register_simple("goldfish_tty", + PLATFORM_DEVID_NONE, + goldfish_tty_res, + ARRAY_SIZE(goldfish_tty_res)); + if (IS_ERR(pdev1)) + return PTR_ERR(pdev1); + + pdev2 = platform_device_register_simple("goldfish_rtc", + PLATFORM_DEVID_NONE, + goldfish_rtc_res, + ARRAY_SIZE(goldfish_rtc_res)); + if (IS_ERR(pdev2)) { + ret = PTR_ERR(pdev2); + goto err_unregister_tty; + } + + pdev3 = platform_device_register_simple("qemu-virt-ctrl", + PLATFORM_DEVID_NONE, + virt_ctrl_res, + ARRAY_SIZE(virt_ctrl_res)); + if (IS_ERR(pdev3)) { + ret = PTR_ERR(pdev3); + goto err_unregister_rtc; + } + + for (i = 0; i < VIRTIO_BUS_NB; i++) { + pdevs[i] = virt_virtio_init(i); + if (IS_ERR(pdevs[i])) { + ret = PTR_ERR(pdevs[i]); + goto err_unregister_virtio; + } + } + + return 0; + +err_unregister_virtio: + while (i > 0) + platform_device_unregister(pdevs[--i]); + platform_device_unregister(pdev3); +err_unregister_rtc: + platform_device_unregister(pdev2); +err_unregister_tty: + platform_device_unregister(pdev1); + + return ret; +} + +arch_initcall(virt_platform_init); |
