[kvm-unit-tests PATCH 04/11] arm/pci: Allocate and assign memory/io space resources

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

 



Cc: Andrew Jones <drjones@xxxxxxxxxx>
Signed-off-by: Alexander Gordeev <agordeev@xxxxxxxxxx>
---
 lib/pci-host-generic.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 69 insertions(+), 2 deletions(-)

diff --git a/lib/pci-host-generic.c b/lib/pci-host-generic.c
index b783d29..f3161f8 100644
--- a/lib/pci-host-generic.c
+++ b/lib/pci-host-generic.c
@@ -19,6 +19,11 @@
 	     dev >= 0;					\
 	     dev = find_next_dev(pci, dev, &conf))
 
+static pci_res_type_t flags_to_type(u32 of_flags)
+{
+	return ((of_flags & 0x40000000) >> 28) | ((of_flags >> 24) & 0x03);
+}
+
 static u8 pci_config_readb(const void *conf, int off)
 {
 	return readb(conf + off);
@@ -255,11 +260,66 @@ static bool pci_get_bar(void *conf, int bar, pci_res_type_t *type,
 	return true;
 }
 
+static void pci_set_bar(void *conf, int bar, phys_addr_t addr, bool is64)
+{
+	int off = PCI_BASE_ADDRESS_0 + (bar * 4);
+
+	pci_config_writel(addr, conf, off);
+	if (is64)
+		pci_config_writel(addr >> 32, conf, off + 4);
+}
+
+static struct pci_addr_space *pci_find_res(struct pci_host_bridge *host,
+					   pci_res_type_t type)
+{
+	struct pci_addr_space *as = &host->addr_space[0];
+	int i;
+
+	for (i = 0; i < host->nr_addr_spaces; i++, as++) {
+		if (flags_to_type(as->of_flags) == type)
+			return as;
+	}
+
+	return NULL;
+}
+
+static phys_addr_t pci_align_res_size(phys_addr_t size, pci_res_type_t type)
+{
+	phys_addr_t mask;
+
+	if (type == PCI_RES_TYPE_IO)
+		mask = PCI_BASE_ADDRESS_IO_MASK;
+	else
+		mask = PCI_BASE_ADDRESS_MEM_MASK;
+
+	return (size + ~mask) & mask;
+}
+
+static phys_addr_t pci_alloc_res(struct pci_host_bridge *host,
+				 pci_res_type_t type, u64 size)
+{
+	struct pci_addr_space *res;
+	phys_addr_t addr;
+
+	assert(res = pci_find_res(host, type));
+
+	size = pci_align_res_size(size, type);
+	assert(res->alloc + size <= res->pci_range.size);
+
+	addr = res->pci_range.start + res->alloc;
+	res->alloc += size;
+
+	return addr;
+}
+
 int pci_bus_scan(struct pci *pci)
 {
 	void *conf;
+	phys_addr_t addr;
+	u64 size;
 	pci_res_type_t type;
 	bool is64;
+	u32 cmd = PCI_COMMAND_SERR;
 	int bar;
 	int dev;
 	int nr_dev = 0;
@@ -271,13 +331,20 @@ int pci_bus_scan(struct pci *pci)
 			continue;
 
 		for (bar = 0; bar < PCI_HEADER_TYPE_NORMAL_NUM_BARS; bar++) {
-			if (!pci_get_bar(conf, bar, &type, NULL, NULL, &is64))
+			if (!pci_get_bar(conf, bar, &type, NULL, &size, &is64))
 				break;
+			addr = pci_alloc_res(pci->sysdata, type, size);
+			pci_set_bar(conf, bar, addr, is64);
 			if (is64)
 				bar++;
+
+			if (type == PCI_RES_TYPE_IO)
+				cmd |= PCI_COMMAND_IO;
+			else
+				cmd |= PCI_COMMAND_MEMORY;
 		}
 
-		pci_config_writel(PCI_COMMAND_SERR, conf, PCI_COMMAND);
+		pci_config_writel(cmd, conf, PCI_COMMAND);
 		nr_dev++;
 	}
 
-- 
1.8.3.1

_______________________________________________
kvmarm mailing list
kvmarm@xxxxxxxxxxxxxxxxxxxxx
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm



[Index of Archives]     [Linux KVM]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux