[tip:tools/kvm] kvm tools: ARM: generate an fdt node for our PCI emulation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Commit-ID:  841079aef94c3c11674d9bb9d30a5dd62e47673f
Gitweb:     http://git.kernel.org/tip/841079aef94c3c11674d9bb9d30a5dd62e47673f
Author:     Will Deacon <will.deacon@xxxxxxx>
AuthorDate: Tue, 4 Feb 2014 16:54:03 +0000
Committer:  Pekka Enberg <penberg@xxxxxxxxxx>
CommitDate: Sun, 16 Feb 2014 21:55:01 +0200

kvm tools: ARM: generate an fdt node for our PCI emulation

This patch factors out some of the openfirmware PCI binding definitions
from the powerpc spapr PCI code and uses them to generate appropriate
FDT properties for the PCI node on ARM.

Signed-off-by: Will Deacon <will.deacon@xxxxxxx>
Signed-off-by: Pekka Enberg <penberg@xxxxxxxxxx>
---
 tools/kvm/Makefile                     |   2 +-
 tools/kvm/arm/fdt.c                    |   4 ++
 tools/kvm/arm/include/arm-common/pci.h |   6 ++
 tools/kvm/arm/pci.c                    | 118 +++++++++++++++++++++++++++++++++
 tools/kvm/include/kvm/of_pci.h         |  44 ++++++++++++
 5 files changed, 173 insertions(+), 1 deletion(-)

diff --git a/tools/kvm/Makefile b/tools/kvm/Makefile
index 29f1822..b872651 100644
--- a/tools/kvm/Makefile
+++ b/tools/kvm/Makefile
@@ -158,7 +158,7 @@ endif
 
 # ARM
 OBJS_ARM_COMMON		:= arm/fdt.o arm/gic.o arm/ioport.o arm/irq.o \
-			   arm/kvm.o arm/kvm-cpu.o arm/timer.o
+			   arm/kvm.o arm/kvm-cpu.o arm/pci.o arm/timer.o
 HDRS_ARM_COMMON		:= arm/include
 ifeq ($(ARCH), arm)
 	DEFINES		+= -DCONFIG_ARM
diff --git a/tools/kvm/arm/fdt.c b/tools/kvm/arm/fdt.c
index 9a34d98..d90fc9e 100644
--- a/tools/kvm/arm/fdt.c
+++ b/tools/kvm/arm/fdt.c
@@ -5,6 +5,7 @@
 #include "kvm/virtio-mmio.h"
 
 #include "arm-common/gic.h"
+#include "arm-common/pci.h"
 
 #include <stdbool.h>
 
@@ -155,6 +156,9 @@ static int setup_fdt(struct kvm *kvm)
 		dev_hdr = device__next_dev(dev_hdr);
 	}
 
+	/* PCI host controller */
+	pci__generate_fdt_nodes(fdt, gic_phandle);
+
 	/* PSCI firmware */
 	_FDT(fdt_begin_node(fdt, "psci"));
 	_FDT(fdt_property_string(fdt, "compatible", "arm,psci"));
diff --git a/tools/kvm/arm/include/arm-common/pci.h b/tools/kvm/arm/include/arm-common/pci.h
new file mode 100644
index 0000000..ee87725
--- /dev/null
+++ b/tools/kvm/arm/include/arm-common/pci.h
@@ -0,0 +1,6 @@
+#ifndef ARM_COMMON__PCI_H
+#define ARM_COMMON__PCI_H
+
+void pci__generate_fdt_nodes(void *fdt, u32 gic_phandle);
+
+#endif /* ARM_COMMON__PCI_H */
diff --git a/tools/kvm/arm/pci.c b/tools/kvm/arm/pci.c
new file mode 100644
index 0000000..ce1932e
--- /dev/null
+++ b/tools/kvm/arm/pci.c
@@ -0,0 +1,118 @@
+#include "kvm/devices.h"
+#include "kvm/fdt.h"
+#include "kvm/of_pci.h"
+#include "kvm/pci.h"
+#include "kvm/util.h"
+
+#include "arm-common/pci.h"
+
+/*
+ * An entry in the interrupt-map table looks like:
+ * <pci unit address> <pci interrupt pin> <gic phandle> <gic interrupt>
+ */
+
+struct of_gic_irq {
+	u32 type, num, flags;
+} __attribute__((packed));
+
+struct of_interrupt_map_entry {
+	struct of_pci_irq_mask		pci_irq_mask;
+	u32				gic_phandle;
+	struct of_gic_irq		gic_irq;
+} __attribute__((packed));
+
+void pci__generate_fdt_nodes(void *fdt, u32 gic_phandle)
+{
+	struct device_header *dev_hdr;
+	struct of_interrupt_map_entry irq_map[OF_PCI_IRQ_MAP_MAX];
+	unsigned nentries = 0;
+	/* Describe the memory ranges (config and memory) */
+	struct of_pci_ranges_entry ranges[] = {
+		{
+			.pci_addr = {
+				.hi	= cpu_to_fdt32(of_pci_b_ss(OF_PCI_SS_CONFIG)),
+				.mid	= 0,
+				.lo	= 0,
+			},
+			.cpu_addr	= cpu_to_fdt64(KVM_PCI_CFG_AREA),
+			.length		= cpu_to_fdt64(ARM_PCI_CFG_SIZE),
+		},
+		{
+			.pci_addr = {
+				.hi	= cpu_to_fdt32(of_pci_b_ss(OF_PCI_SS_IO)),
+				.mid	= 0,
+				.lo	= 0,
+			},
+			.cpu_addr	= cpu_to_fdt64(KVM_IOPORT_AREA),
+			.length		= cpu_to_fdt64(ARM_IOPORT_SIZE),
+		},
+		{
+			.pci_addr = {
+				.hi	= cpu_to_fdt32(of_pci_b_ss(OF_PCI_SS_M32)),
+				.mid	= 0,
+				.lo	= 0,
+			},
+			.cpu_addr	= cpu_to_fdt64(KVM_PCI_MMIO_AREA),
+			.length		= cpu_to_fdt64(ARM_PCI_MMIO_SIZE),
+		},
+	};
+
+	/* Boilerplate PCI properties */
+	_FDT(fdt_begin_node(fdt, "pci"));
+	_FDT(fdt_property_cell(fdt, "#address-cells", 0x3));
+	_FDT(fdt_property_cell(fdt, "#size-cells", 0x2));
+	_FDT(fdt_property_cell(fdt, "#interrupt-cells", 0x1));
+	_FDT(fdt_property_string(fdt, "compatible", "linux,pci-virt"));
+
+	_FDT(fdt_property(fdt, "ranges", ranges, sizeof(ranges)));
+
+	/* Generate the interrupt map ... */
+	dev_hdr = device__first_dev(DEVICE_BUS_PCI);
+	while (dev_hdr && nentries < ARRAY_SIZE(irq_map)) {
+		struct of_interrupt_map_entry *entry = &irq_map[nentries];
+		struct pci_device_header *pci_hdr = dev_hdr->data;
+		u8 dev_num = dev_hdr->dev_num;
+		u8 pin = pci_hdr->irq_pin;
+		u8 irq = pci_hdr->irq_line;
+
+		*entry = (struct of_interrupt_map_entry) {
+			.pci_irq_mask = {
+				.pci_addr = {
+					.hi	= cpu_to_fdt32(of_pci_b_ddddd(dev_num)),
+					.mid	= 0,
+					.lo	= 0,
+				},
+				.pci_pin	= cpu_to_fdt32(pin),
+			},
+			.gic_phandle	= cpu_to_fdt32(gic_phandle),
+			.gic_irq = {
+				.type	= cpu_to_fdt32(GIC_FDT_IRQ_TYPE_SPI),
+				.num	= cpu_to_fdt32(irq - GIC_SPI_IRQ_BASE),
+				.flags	= cpu_to_fdt32(GIC_FDT_IRQ_FLAGS_EDGE_LO_HI),
+			},
+		};
+
+		nentries++;
+		dev_hdr = device__next_dev(dev_hdr);
+	}
+
+	_FDT(fdt_property(fdt, "interrupt-map", irq_map,
+			  sizeof(struct of_interrupt_map_entry) * nentries));
+
+	/* ... and the corresponding mask. */
+	if (nentries) {
+		struct of_pci_irq_mask irq_mask = {
+			.pci_addr = {
+				.hi	= cpu_to_fdt32(of_pci_b_ddddd(-1)),
+				.mid	= 0,
+				.lo	= 0,
+			},
+			.pci_pin	= cpu_to_fdt32(7),
+		};
+
+		_FDT(fdt_property(fdt, "interrupt-map-mask", &irq_mask,
+				  sizeof(irq_mask)));
+	}
+
+	_FDT(fdt_end_node(fdt));
+}
diff --git a/tools/kvm/include/kvm/of_pci.h b/tools/kvm/include/kvm/of_pci.h
new file mode 100644
index 0000000..c8187ab
--- /dev/null
+++ b/tools/kvm/include/kvm/of_pci.h
@@ -0,0 +1,44 @@
+#ifndef KVM__OF_PCI_H
+#define KVM__OF_PCI_H
+
+#include <linux/types.h>
+
+/*
+ * Definitions for implementing parts of the OpenFirmware PCI Bus Binding
+ * Specification (IEEE Std 1275-1994).
+ */
+
+struct of_pci_unit_address {
+	u32 hi, mid, lo;
+} __attribute__((packed));
+
+struct of_pci_irq_mask {
+	struct of_pci_unit_address	pci_addr;
+	u32				pci_pin;
+} __attribute__((packed));
+
+struct of_pci_ranges_entry {
+	struct of_pci_unit_address	pci_addr;
+	u64				cpu_addr;
+	u64				length;
+} __attribute__((packed));
+
+/* Macros to operate with address in OF binding to PCI */
+#define __b_x(x, p, l)		(((x) & ((1<<(l))-1)) << (p))
+#define of_pci_b_n(x)		__b_x((x), 31, 1)	/* 0 if relocatable */
+#define of_pci_b_p(x)		__b_x((x), 30, 1)	/* 1 if prefetchable */
+#define of_pci_b_t(x)		__b_x((x), 29, 1)	/* 1 if the address is aliased */
+#define of_pci_b_ss(x)		__b_x((x), 24, 2)	/* the space code */
+#define of_pci_b_bbbbbbbb(x)	__b_x((x), 16, 8)	/* bus number */
+#define of_pci_b_ddddd(x)	__b_x((x), 11, 5)	/* device number */
+#define of_pci_b_fff(x)		__b_x((x), 8, 3)	/* function number */
+#define of_pci_b_rrrrrrrr(x)	__b_x((x), 0, 8)	/* register number */
+
+#define OF_PCI_SS_CONFIG	0
+#define OF_PCI_SS_IO		1
+#define OF_PCI_SS_M32		2
+#define OF_PCI_SS_M64		3
+
+#define OF_PCI_IRQ_MAP_MAX	256	/* 5 bit device + 3 bit pin */
+
+#endif /* KVM__OF_PCI_H */
--
To unsubscribe from this list: send the line "unsubscribe linux-tip-commits" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Stable Commits]     [Linux Stable Kernel]     [Linux Kernel]     [Linux USB Devel]     [Linux Video &Media]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]

  Powered by Linux