Hi Laurent, On Sat, Jan 29, 2022 at 7:42 PM Laurent Vivier <laurent@xxxxxxxxx> wrote: > This machine allows to have up to 3.2 GiB and 128 Virtio devices. > > It is based on android goldfish devices. > > Signed-off-by: Laurent Vivier <laurent@xxxxxxxxx> Thanks for your patch! > --- a/arch/m68k/Kconfig.machine > +++ b/arch/m68k/Kconfig.machine > @@ -149,6 +149,23 @@ config SUN3 > > If you don't want to compile a kernel exclusively for a Sun 3, say N. > > +config VIRT > + bool "Virtual M68k Machine support" > + depends on MMU > + select GENERIC_CLOCKEVENTS > + select M68040 > + select MMU_MOTOROLA if MMU > + select RTC_CLASS > + select GOLDFISH > + select RTC_DRV_GOLDFISH > + select GOLDFISH_TIMER > + select GOLDFISH_TTY > + select TTY > + select VIRTIO_MMIO Please sort alphabetically. > + help > + This options enable a pure virtual machine based on m68k, > + VIRTIO MMIO devices and GOLDFISH interfaces (TTY, RTC, PIC) > + > config PILOT > bool > > --- /dev/null > +++ b/arch/m68k/include/asm/virt.h > @@ -0,0 +1,25 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +#ifndef __ASM_VIRT_H > +#define __ASM_VIRT_H > + > +#define NUM_VIRT_SOURCES 200 > + > +struct virt_booter_device_data { > + unsigned long mmio; > + unsigned long irq; Probably you want to make these explicitly sized (u32)? Or perhaps mmio should be void __iomem *, to avoid some casts (at expense of other casts)? > +}; > + > +struct virt_booter_data { > + unsigned long qemu_version; u32? > + struct virt_booter_device_data pic; > + struct virt_booter_device_data rtc; > + struct virt_booter_device_data tty; > + struct virt_booter_device_data ctrl; > + struct virt_booter_device_data virtio; > +}; > + > +extern struct virt_booter_data virt_bi_data; > + > +extern void __init virt_init_IRQ(void); > + > +#endif > --- a/arch/m68k/mm/kmap.c > +++ b/arch/m68k/mm/kmap.c > @@ -179,6 +179,12 @@ void __iomem *__ioremap(unsigned long physaddr, unsigned long size, int cachefla > return (void __iomem *)physaddr; > } > #endif > +#ifdef CONFIG_VIRT > + if (MACH_IS_VIRT) { > + if (physaddr >= 0xff000000 && cacheflag == IOMAP_NOCACHE_SER) > + return (void __iomem *)physaddr; > + } > +#endif > #ifdef CONFIG_COLDFIRE > if (__cf_internalio(physaddr)) > return (void __iomem *) physaddr; > @@ -292,18 +298,21 @@ EXPORT_SYMBOL(__ioremap); > */ > void iounmap(void __iomem *addr) > { > -#ifdef CONFIG_AMIGA > - if ((!MACH_IS_AMIGA) || > - (((unsigned long)addr < 0x40000000) || > - ((unsigned long)addr > 0x60000000))) > - free_io_area((__force void *)addr); > -#else > +#if defined(CONFIG_AMIGA) "#ifdef CONFIG_AMIGA" was fine > + if (MACH_IS_AMIGA && > + ((unsigned long)addr >= 0x40000000) && > + ((unsigned long)addr < 0x60000000)) > + return; > +#endif > +#if defined(CONFIG_VIRT) #ifdef CONFIG_VIRT > + if (MACH_IS_VIRT && (unsigned long)addr >= 0xff000000) > + return; > +#endif > #ifdef CONFIG_COLDFIRE > if (cf_internalio(addr)) > return; > #endif > free_io_area((__force void *)addr); > -#endif > } > EXPORT_SYMBOL(iounmap); > > --- /dev/null > +++ b/arch/m68k/virt/config.c > @@ -0,0 +1,130 @@ > +// SPDX-License-Identifier: GPL-2.0 > + > +#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; > + > +#define VIRT_CTRL_REG_FEATURES 0x00 > +#define VIRT_CTRL_REG_CMD 0x04 > + > +static struct resource ctrlres; > + > +enum { > + CMD_NOOP, > + CMD_RESET, > + CMD_HALT, > + CMD_PANIC, > +}; > + > +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_halt(void) > +{ > + void __iomem *base = (void *)virt_bi_data.ctrl.mmio; "(void __iomem *)" everywhere, else sparse complains (make C=1) > + > + iowrite32be(CMD_HALT, base + VIRT_CTRL_REG_CMD); > + local_irq_disable(); > + while (1) > + ; > +} > --- /dev/null > +++ b/arch/m68k/virt/ints.c > @@ -0,0 +1,153 @@ > +// 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/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 > + > +extern void show_registers(struct pt_regs *regs); > + > +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 *)(virt_bi_data.pic.mmio + pic * 0x1000); (void __iomem *) > + > + return ioread32be(base + reg); > +} > + > +static void gfpic_write(u32 value, int pic, int reg) > +{ > + void __iomem *base = (void *)(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(1 << GF_IRQ(data->irq), GF_PIC(data->irq), "1U". Or perhaps "BIT(GF_IRQ(data->irq)"? > + GFPIC_REG_IRQ_ENABLE); > +} > + > +static void virt_irq_disable(struct irq_data *data) > +{ > + gfpic_write(1 << GF_IRQ(data->irq), GF_PIC(data->irq), likewise > + GFPIC_REG_IRQ_DISABLE); > +} void goldfish_pic_irq(struct irq_desc *desc) > +{ > + u32 irq_pending; > + int irq_num; unsigned int > + int pic = desc->irq_data.irq - 1; unsigned int > + > + 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) > +{ > + int pic; unsigned int i > + > + m68k_setup_irq_controller(&virt_irq_chip, handle_simple_irq, IRQ_USER, > + NUM_VIRT_SOURCES - IRQ_USER); > + > + for (pic = 0; pic < 6; pic++) { > + > + picres[pic] = (struct resource) > + DEFINE_RES_MEM_NAMED(virt_bi_data.pic.mmio + pic * 0x1000, > + 0x1000, picname[pic]); > + if (request_resource(&iomem_resource, &picres[pic])) { > + pr_err("Cannot allocate %s resource\n", picname[pic]); > + return; > + } > + > + irq_set_chained_handler(virt_bi_data.pic.irq + pic, > + goldfish_pic_irq); > + } > + > + if (request_irq(IRQ_AUTO_7, virt_nmi_handler, 0, "NMI", > + virt_nmi_handler)) > + pr_err("Couldn't register NMI\n"); > +} > --- /dev/null > +++ b/arch/m68k/virt/platform.c > @@ -0,0 +1,72 @@ > +// 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 int __init virt_virtio_init(int id) 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), > + }; > + struct platform_device *pdev; > + > + pdev = platform_device_register_simple("virtio-mmio", id, > + res, ARRAY_SIZE(res)); > + if (IS_ERR(pdev)) > + return PTR_ERR(pdev); > + > + return 0; > +} > + > +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), > + }; > + struct platform_device *pdev; > + int i; unsigned int > + > + if (!MACH_IS_VIRT) > + return -ENODEV; > + > + /* We need this to have DMA'able memory provided to goldfish-tty */ > + min_low_pfn = 0; > + > + pdev = platform_device_register_simple("goldfish_tty", > + PLATFORM_DEVID_NONE, > + goldfish_tty_res, > + ARRAY_SIZE(goldfish_tty_res)); > + if (IS_ERR(pdev)) > + return PTR_ERR(pdev); > + > + pdev = platform_device_register_simple("goldfish_rtc", > + PLATFORM_DEVID_NONE, > + goldfish_rtc_res, > + ARRAY_SIZE(goldfish_rtc_res)); > + if (IS_ERR(pdev)) > + return PTR_ERR(pdev); > + > + for (i = 0; i < VIRTIO_BUS_NB; i++) { > + int err; > + > + err = virt_virtio_init(i); > + if (err) > + return err; > + } > + > + return 0; > +} Gr{oetje,eeting}s, Geert -- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@xxxxxxxxxxxxxx In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds