Skip to content

Commit

Permalink
MIPS: KVM: Add kvm support for Loongson-3 (Guest Side)
Browse files Browse the repository at this point in the history
Signed-off-by: Huacai Chen <chenhc@lemote.com>
  • Loading branch information
chenhuacai committed Jun 23, 2020
1 parent 2af5398 commit f31b7c1
Show file tree
Hide file tree
Showing 14 changed files with 361 additions and 10 deletions.
2 changes: 1 addition & 1 deletion arch/mips/boot/dts/loongson/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
dtb-$(CONFIG_CPU_LOONGSON3) += loongson3_ls2h.dtb loongson3_ls7a.dtb loongson3_rs780.dtb
dtb-$(CONFIG_CPU_LOONGSON3) += loongson3_ls2h.dtb loongson3_ls7a.dtb loongson3_rs780.dtb loongson3_virtual.dtb

obj-y += $(patsubst %.dtb, %.dtb.o, $(dtb-y))
46 changes: 46 additions & 0 deletions arch/mips/boot/dts/loongson/loongson3_virtual.dts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
#include "loongson3.dtsi"
/ {
model = "loongson,generic";
compatible = "loongson,loongson3";
#address-cells = <2>;
#size-cells = <2>;

memory {
name = "memory";
device_type = "memory";
};

cpuic: interrupt-controller {
compatible = "mti,cpu-interrupt-controller";
interrupt-controller;
#interrupt-cells = <1>;
};

platic: interrupt-controller@3ff01400 {
compatible = "loongson,liointc-1.0";
interrupt-controller;
#interrupt-cells = <1>;
interrupts = <3>;
interrupt-parent = <&cpuic>;
};

platform {
compatible = "loongson,nbus", "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges = <0x00000000 0x0 0x00000000 0x20000000>;

rtc0: rtc@10081000 {
compatible = "google,goldfish-rtc";
reg = <0x10081000 0x1000>;
interrupts = <17>;
interrupt-parent = <&platic>;
};
};

hypervisor {
compatible = "linux,kvm";
};
};
1 change: 1 addition & 0 deletions arch/mips/include/asm/mach-loongson64/boot_param.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ extern void *loongson_fdt_blob;
extern u32 __dtb_loongson3_ls2h_begin[];
extern u32 __dtb_loongson3_ls7a_begin[];
extern u32 __dtb_loongson3_rs780_begin[];
extern u32 __dtb_loongson3_virtual_begin[];
extern struct efi_memory_map_loongson *loongson_memmap;
extern struct loongson_system_configuration loongson_sysconf;

Expand Down
12 changes: 9 additions & 3 deletions arch/mips/include/asm/mach-loongson64/loongson-pch.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,9 +192,10 @@
/* ============== Data structrues =============== */

enum b_type { /* BoardType(BridgeType) */
LS2H = 1,
LS7A = 2,
RS780E = 3
LS2H = 1,
LS7A = 2,
RS780E = 3,
VIRTUAL = 4
};

struct platform_controller_hub {
Expand All @@ -216,6 +217,7 @@ struct platform_controller_hub {
extern struct platform_controller_hub ls2h_pch;
extern struct platform_controller_hub ls7a_pch;
extern struct platform_controller_hub rs780_pch;
extern struct platform_controller_hub virtual_pch;
extern struct platform_controller_hub *loongson_pch;

extern bool cpu_support_msi(void);
Expand All @@ -241,4 +243,8 @@ extern int rs780_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin);
extern int rs780_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc);
extern void rs780_teardown_msi_irq(unsigned int irq);

extern struct pci_ops virtio_pci_ops;
extern void virtio_init_irq(void);
extern void virtio_irq_dispatch(void);

#endif
7 changes: 5 additions & 2 deletions arch/mips/loongson64/common/env.c
Original file line number Diff line number Diff line change
Expand Up @@ -186,15 +186,18 @@ void __init prom_init_env(void)
hw_coherentio = !eirq_source->dma_noncoherent;
pr_info("BIOS configured I/O coherency: %s\n", hw_coherentio?"ON":"OFF");

if (strstr(eboard->name,"2H")) {
if (strstr(eboard->name,"VIRT")) {
loongson_pch = &virtual_pch;
loongson_fdt_blob = __dtb_loongson3_virtual_begin;
} else if (strstr(eboard->name,"2H")) {
loongson_pch = &ls2h_pch;
loongson_sysconf.ec_sci_irq = 0x80;
loongson_fdt_blob = __dtb_loongson3_ls2h_begin;
} else if (strstr(eboard->name,"7A")) {
loongson_pch = &ls7a_pch;
loongson_sysconf.ec_sci_irq = 0x7b;
loongson_fdt_blob = __dtb_loongson3_ls7a_begin;
} else {
} else { /* Default to RS780 because of missing "780" */
loongson_pch = &rs780_pch;
loongson_sysconf.ec_sci_irq = 0x07;
loongson_fdt_blob = __dtb_loongson3_rs780_begin;
Expand Down
1 change: 1 addition & 0 deletions arch/mips/loongson64/common/rtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ static int __init loongson_rtc_platform_init(void)
case LS2H:
case LS7A:
case RS780E:
case VIRTUAL:
break;
default:
platform_device_register(&loongson_rtc_device);
Expand Down
2 changes: 1 addition & 1 deletion arch/mips/loongson64/loongson-3/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#
obj-y += irq.o cop2-ex.o platform.o acpi_init.o dma.o clock.o constant_timer.o ec_wpce775l.o \
ls2h-irq.o ls2h-platform.o ls7a-irq.o ls7a-platform.o rs780-irq.o rs780-platform.o \
workarounds.o
virtual-irq.o virtual-platform.o workarounds.o

obj-$(CONFIG_SMP) += smp.o

Expand Down
14 changes: 14 additions & 0 deletions arch/mips/loongson64/loongson-3/dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,16 @@ static phys_addr_t loongson_rs780_dma_to_phys(struct device *dev, dma_addr_t dad
return ((nid << 37) ^ daddr) | (nid << 44);
}

static dma_addr_t loongson_virtio_phys_to_dma(struct device *dev, phys_addr_t paddr)
{
return paddr;
}

static phys_addr_t loongson_virtio_dma_to_phys(struct device *dev, dma_addr_t daddr)
{
return daddr;
}

struct loongson_addr_xlate_ops {
dma_addr_t (*phys_to_dma)(struct device *dev, phys_addr_t paddr);
phys_addr_t (*dma_to_phys)(struct device *dev, dma_addr_t daddr);
Expand Down Expand Up @@ -294,5 +304,9 @@ void __init plat_swiotlb_setup(void)
xlate_ops.phys_to_dma = loongson_rs780_phys_to_dma;
xlate_ops.dma_to_phys = loongson_rs780_dma_to_phys;
break;
default:
xlate_ops.phys_to_dma = loongson_virtio_phys_to_dma;
xlate_ops.dma_to_phys = loongson_virtio_dma_to_phys;
break;
}
}
5 changes: 5 additions & 0 deletions arch/mips/loongson64/loongson-3/hpet.c
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,8 @@ void __init setup_hpet_timer(void)
hpet_mmio_base = RS780_HPET_BASE;
hpet_irq_flags = 0;
break;
default:
return;
}

hpet_setup();
Expand Down Expand Up @@ -300,6 +302,9 @@ static struct clocksource csrc_hpet = {

int __init init_hpet_clocksource(void)
{
if (!hpet_mmio_base)
return -ENODEV;

csrc_hpet.mult = clocksource_hz2mult(hpet_freq, csrc_hpet.shift);
return clocksource_register_hz(&csrc_hpet, hpet_freq);
}
Expand Down
105 changes: 105 additions & 0 deletions arch/mips/loongson64/loongson-3/virtual-irq.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2020, Huacai Chen <chenhc@lemote.com>
* Copyright (C) 2020, Jiaxun Yang <jiaxun.yang@flygoat.com>
* Loongson Local IO Interrupt Controller support
*/

#include <linux/interrupt.h>
#include <linux/irqchip.h>
#include <linux/module.h>
#include <irq.h>
#include <loongson.h>
#include <loongson-pch.h>

#define VIRT_LIOINTC_BASE NR_IRQS_LEGACY
#define LOONGSON_INT_STATUS LOONGSON3_REG32(LOONGSON3_REG_BASE, LOONGSON_INT_ROUTER_OFFSET + 0x20)

static DEFINE_RAW_SPINLOCK(pch_irq_lock);

static void mask_pch_irq(struct irq_data *d)
{
int irq_nr;

raw_spin_lock(&pch_irq_lock);
irq_nr = d->irq - VIRT_LIOINTC_BASE;
LOONGSON_INT_ROUTER_INTENCLR = (1 << irq_nr);
raw_spin_unlock(&pch_irq_lock);
}

static void unmask_pch_irq(struct irq_data *d)
{
int irq_nr;

raw_spin_lock(&pch_irq_lock);
irq_nr = d->irq - VIRT_LIOINTC_BASE;
LOONGSON_INT_ROUTER_INTENSET = (1 << irq_nr);
raw_spin_unlock(&pch_irq_lock);
}

static struct irq_chip pch_irq_chip = {
.name = "Loongson",
.irq_mask = mask_pch_irq,
.irq_unmask = unmask_pch_irq,
.irq_set_affinity = plat_set_irq_affinity,
.flags = IRQCHIP_MASK_ON_SUSPEND,
};

void virtio_irq_dispatch(void)
{
u32 pending;

pending = LOONGSON_INT_STATUS;

if (!pending)
spurious_interrupt();

while (pending) {
int irq = __ffs(pending);

do_IRQ(VIRT_LIOINTC_BASE + irq);
pending &= ~BIT(irq);
}
}

static struct irqaction cascade_irqaction = {
.handler = no_action,
.flags = IRQF_NO_SUSPEND,
.name = "cascade",
};

void virtio_init_irq(void)
{
int i;

LOONGSON_INT_ROUTER_INTENCLR = 0xffffffff;

/* Route UART int to cpu Core0 INT0 */
LOONGSON_INT_ROUTER_ENTRY(0) =
LOONGSON_INT_COREx_INTy(loongson_sysconf.boot_cpu_id, 0);

/* Route others to Core0 INT1 (IP3) */
for (i = 1; i < 32; i++)
LOONGSON_INT_ROUTER_ENTRY(i) =
LOONGSON_INT_COREx_INTy(loongson_sysconf.boot_cpu_id, 1);

setup_irq(VIRT_LIOINTC_BASE, &cascade_irqaction);
}

int __init liointc_of_init(struct device_node *node, struct device_node *parent)
{
int i = 0;

irq_alloc_descs(-1, VIRT_LIOINTC_BASE, 32, 0);
irq_domain_add_legacy(node, 32, VIRT_LIOINTC_BASE,
VIRT_LIOINTC_BASE, &irq_domain_simple_ops, NULL);

for (i = VIRT_LIOINTC_BASE; i < VIRT_LIOINTC_BASE + 32; i++) {
irq_set_noprobe(i);
irq_set_chip_and_handler(i, &pch_irq_chip, handle_level_irq);
}

return 0;
}

IRQCHIP_DECLARE(loongson_liointc_1_0, "loongson,liointc-1.0", liointc_of_init);
72 changes: 72 additions & 0 deletions arch/mips/loongson64/loongson-3/virtual-platform.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright (C) 2013, Loongson Technology Corporation Limited, Inc.
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
*/
#include <linux/init.h>
#include <asm/io.h>
#include <pci.h>
#include <boot_param.h>
#include <loongson-pch.h>

#include <linux/i2c.h>
#include <linux/serial_8250.h>
#include <linux/platform_device.h>

void pci_no_msi(void);

static void virtio_early_config(void)
{
pci_no_msi();
}

static struct resource pci_mem_resource = {
.name = "pci memory space",
.flags = IORESOURCE_MEM,
};

static struct resource pci_io_resource = {
.name = "pci io space",
.flags = IORESOURCE_IO,
};

static struct pci_controller virtio_pci_controller = {
.pci_ops = &virtio_pci_ops,
.io_resource = &pci_io_resource,
.mem_resource = &pci_mem_resource,
.mem_offset = 0x00000000UL,
.io_offset = 0x00000000UL,
};

static void __init virtio_arch_initcall(void)
{
pci_mem_resource.start = loongson_sysconf.pci_mem_start_addr;
pci_mem_resource.end = loongson_sysconf.pci_mem_end_addr;
pci_io_resource.start = LOONGSON_PCI_IO_START;
pci_io_resource.end = 0x3ffff;
ioport_resource.end = 0xfffff;
virtio_pci_controller.io_map_base = mips_io_port_base;
register_pci_controller(&virtio_pci_controller);
}

static void __init virtio_device_initcall(void)
{
}

struct platform_controller_hub virtual_pch = {
.type = VIRTUAL,
.pcidev_max_funcs = 7,
.early_config = virtio_early_config,
.init_irq = virtio_init_irq,
.irq_dispatch = virtio_irq_dispatch,
.pch_arch_initcall = virtio_arch_initcall,
.pch_device_initcall = virtio_device_initcall,
};
2 changes: 1 addition & 1 deletion arch/mips/pci/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ obj-$(CONFIG_LASAT) += pci-lasat.o
obj-$(CONFIG_MIPS_COBALT) += fixup-cobalt.o
obj-$(CONFIG_LEMOTE_FULOONG2E) += fixup-fuloong2e.o ops-loongson2.o
obj-$(CONFIG_LEMOTE_MACH2F) += fixup-lemote2f.o ops-loongson2.o
obj-$(CONFIG_LOONGSON_MACH3X) += fixup-loongson3.o ops-loongson3-ls2h.o ops-loongson3-ls7a.o ops-loongson3-rs780.o
obj-$(CONFIG_LOONGSON_MACH3X) += fixup-loongson3.o ops-loongson3-ls2h.o ops-loongson3-ls7a.o ops-loongson3-rs780.o ops-loongson3-virtio.o
obj-$(CONFIG_MIPS_MALTA) += fixup-malta.o pci-malta.o
obj-$(CONFIG_PMC_MSP7120_GW) += fixup-pmcmsp.o ops-pmcmsp.o
obj-$(CONFIG_PMC_MSP7120_EVAL) += fixup-pmcmsp.o ops-pmcmsp.o
Expand Down
17 changes: 15 additions & 2 deletions arch/mips/pci/fixup-loongson3.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@
*/

#include <linux/pci.h>
#include <irq.h>
#include <asm/irq.h>
#include <boot_param.h>
#include <loongson-pch.h>
#include <workarounds.h>

static void print_fixup_info(const struct pci_dev *pdev)
Expand All @@ -34,10 +35,22 @@ static void print_fixup_info(const struct pci_dev *pdev)
pdev->vendor, pdev->device, pdev->irq);
}

#define VIRT_PCI_IRQ_BASE (NR_IRQS_LEGACY + 2)

int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
print_fixup_info(dev);
return dev->irq;

switch (loongson_pch->type) {
case LS2H:
case LS7A:
case RS780E:
return dev->irq;
case VIRTUAL:
default:
/* Use the same swizzle method as QEMU */
return VIRT_PCI_IRQ_BASE + (slot + pin - 1) % 4;
}
}

static void pci_fixup_radeon(struct pci_dev *pdev)
Expand Down
Loading

0 comments on commit f31b7c1

Please sign in to comment.