aboutsummaryrefslogtreecommitdiff
path: root/arch/mips/pci/pci-virtio-guest.c
diff options
context:
space:
mode:
authorDavid Daney2014-05-28 23:52:14 +0200
committerRalf Baechle2014-06-02 12:34:20 +0200
commitae6e7e635c2c9aa5aa5c03f5ac39e9d84fc0ee09 (patch)
tree76c1c92639f115fa1427a12644ca14e1c5ea24fd /arch/mips/pci/pci-virtio-guest.c
parent18280edafef1b8ffc920743eddaf6cf6612b1509 (diff)
MIPS: paravirt: Add pci controller for virtio
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>
Diffstat (limited to 'arch/mips/pci/pci-virtio-guest.c')
-rw-r--r--arch/mips/pci/pci-virtio-guest.c131
1 files changed, 131 insertions, 0 deletions
diff --git a/arch/mips/pci/pci-virtio-guest.c b/arch/mips/pci/pci-virtio-guest.c
new file mode 100644
index 000000000000..40a078bc4617
--- /dev/null
+++ b/arch/mips/pci/pci-virtio-guest.c
@@ -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);