MIPS: paravirt: Add pci controller for virtio
authorDavid Daney <david.daney@cavium.com>
Wed, 28 May 2014 21:52:14 +0000 (23:52 +0200)
committerRalf Baechle <ralf@linux-mips.org>
Mon, 2 Jun 2014 10:34:20 +0000 (12:34 +0200)
Signed-off-by: David Daney <david.daney@cavium.com>
Signed-off-by: Andreas Herrmann <andreas.herrmann@caviumnetworks.com>
Cc: linux-mips@linux-mips.org
Cc: James Hogan <james.hogan@imgtec.com>
Cc: kvm@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/7011/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/Kconfig
arch/mips/paravirt/Kconfig [new file with mode: 0644]
arch/mips/pci/Makefile
arch/mips/pci/pci-virtio-guest.c [new file with mode: 0644]

index 78b558f..e41f32b 100644 (file)
@@ -825,6 +825,7 @@ source "arch/mips/cavium-octeon/Kconfig"
 source "arch/mips/loongson/Kconfig"
 source "arch/mips/loongson1/Kconfig"
 source "arch/mips/netlogic/Kconfig"
+source "arch/mips/paravirt/Kconfig"
 
 endmenu
 
diff --git a/arch/mips/paravirt/Kconfig b/arch/mips/paravirt/Kconfig
new file mode 100644 (file)
index 0000000..ecae586
--- /dev/null
@@ -0,0 +1,6 @@
+if MIPS_PARAVIRT
+
+config MIPS_PCI_VIRTIO
+       def_bool y
+
+endif #  MIPS_PARAVIRT
index d61138a..ff8a553 100644 (file)
@@ -21,7 +21,7 @@ obj-$(CONFIG_BCM63XX)         += pci-bcm63xx.o fixup-bcm63xx.o \
 obj-$(CONFIG_MIPS_ALCHEMY)     += pci-alchemy.o
 obj-$(CONFIG_SOC_AR71XX)       += pci-ar71xx.o
 obj-$(CONFIG_PCI_AR724X)       += pci-ar724x.o
-
+obj-$(CONFIG_MIPS_PCI_VIRTIO)  += pci-virtio-guest.o
 #
 # These are still pretty much in the old state, watch, go blind.
 #
diff --git a/arch/mips/pci/pci-virtio-guest.c b/arch/mips/pci/pci-virtio-guest.c
new file mode 100644 (file)
index 0000000..40a078b
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2013 Cavium, Inc.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+
+#include <uapi/asm/bitfield.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+
+#define PCI_CONFIG_ADDRESS     0xcf8
+#define PCI_CONFIG_DATA                0xcfc
+
+union pci_config_address {
+       struct {
+               __BITFIELD_FIELD(unsigned enable_bit      : 1,  /* 31       */
+               __BITFIELD_FIELD(unsigned reserved        : 7,  /* 30 .. 24 */
+               __BITFIELD_FIELD(unsigned bus_number      : 8,  /* 23 .. 16 */
+               __BITFIELD_FIELD(unsigned devfn_number    : 8,  /* 15 .. 8  */
+               __BITFIELD_FIELD(unsigned register_number : 8,  /* 7  .. 0  */
+               )))));
+       };
+       u32 w;
+};
+
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+       return 0;
+}
+
+int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+       return ((pin + slot) % 4)+ MIPS_IRQ_PCIA;
+}
+
+static void pci_virtio_guest_write_config_addr(struct pci_bus *bus,
+                                       unsigned int devfn, int reg)
+{
+       union pci_config_address pca = { .w = 0 };
+
+       pca.register_number = reg;
+       pca.devfn_number = devfn;
+       pca.bus_number = bus->number;
+       pca.enable_bit = 1;
+
+       outl(pca.w, PCI_CONFIG_ADDRESS);
+}
+
+static int pci_virtio_guest_write_config(struct pci_bus *bus,
+               unsigned int devfn, int reg, int size, u32 val)
+{
+       pci_virtio_guest_write_config_addr(bus, devfn, reg);
+
+       switch (size) {
+       case 1:
+               outb(val, PCI_CONFIG_DATA + (reg & 3));
+               break;
+       case 2:
+               outw(val, PCI_CONFIG_DATA + (reg & 2));
+               break;
+       case 4:
+               outl(val, PCI_CONFIG_DATA);
+               break;
+       }
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_virtio_guest_read_config(struct pci_bus *bus, unsigned int devfn,
+                                       int reg, int size, u32 *val)
+{
+       pci_virtio_guest_write_config_addr(bus, devfn, reg);
+
+       switch (size) {
+       case 1:
+               *val = inb(PCI_CONFIG_DATA + (reg & 3));
+               break;
+       case 2:
+               *val = inw(PCI_CONFIG_DATA + (reg & 2));
+               break;
+       case 4:
+               *val = inl(PCI_CONFIG_DATA);
+               break;
+       }
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops pci_virtio_guest_ops = {
+       .read  = pci_virtio_guest_read_config,
+       .write = pci_virtio_guest_write_config,
+};
+
+static struct resource pci_virtio_guest_mem_resource = {
+       .name = "Virtio MEM",
+       .flags = IORESOURCE_MEM,
+       .start  = 0x10000000,
+       .end    = 0x1dffffff
+};
+
+static struct resource pci_virtio_guest_io_resource = {
+       .name = "Virtio IO",
+       .flags = IORESOURCE_IO,
+       .start  = 0,
+       .end    = 0xffff
+};
+
+static struct pci_controller pci_virtio_guest_controller = {
+       .pci_ops = &pci_virtio_guest_ops,
+       .mem_resource = &pci_virtio_guest_mem_resource,
+       .io_resource = &pci_virtio_guest_io_resource,
+};
+
+static int __init pci_virtio_guest_setup(void)
+{
+       pr_err("pci_virtio_guest_setup\n");
+
+       /* Virtio comes pre-assigned */
+       pci_set_flags(PCI_PROBE_ONLY);
+
+       pci_virtio_guest_controller.io_map_base = mips_io_port_base;
+       register_pci_controller(&pci_virtio_guest_controller);
+       return 0;
+}
+arch_initcall(pci_virtio_guest_setup);