On Thu, Jul 21, 2016 at 11:26:55AM +0200, Andrew Jones wrote: > On Tue, Jul 19, 2016 at 02:53:06PM +0200, Alexander Gordeev wrote: > > Unlike x86, other architectures using generic ECAM PCI host > > do not have a luxury of PCI bus initialized by a BIOS and > > ready to use at start. Thus, we need allocate and assign > > resources to all devices, much like an architecture's > > firmware would do. > > > > There is no any sort of resource management for memory and > > io spaces, since only ones-per-BAR allocations are expected > > and no deallocations at all. > > > > Cc: Thomas Huth <thuth@xxxxxxxxxx> > > Cc: Andrew Jones <drjones@xxxxxxxxxx> > > Reviewed-by: Andrew Jones <drjones@xxxxxxxxxx> > > Signed-off-by: Alexander Gordeev <agordeev@xxxxxxxxxx> > > --- > > lib/asm-generic/pci-host-bridge.h | 26 ++++ > > lib/pci-host-generic.c | 295 ++++++++++++++++++++++++++++++++++++++ > > lib/pci-host-generic.h | 46 ++++++ > > lib/pci.c | 4 +- > > lib/pci.h | 3 + > > 5 files changed, 372 insertions(+), 2 deletions(-) > > create mode 100644 lib/asm-generic/pci-host-bridge.h > > create mode 100644 lib/pci-host-generic.c > > create mode 100644 lib/pci-host-generic.h > > > > diff --git a/lib/asm-generic/pci-host-bridge.h b/lib/asm-generic/pci-host-bridge.h > > new file mode 100644 > > index 000000000000..872df3a81310 > > --- /dev/null > > +++ b/lib/asm-generic/pci-host-bridge.h > > @@ -0,0 +1,26 @@ > > +#ifndef _ASM_PCI_HOST_BRIDGE_H_ > > +#define _ASM_PCI_HOST_BRIDGE_H_ > > +/* > > + * Copyright (C) 2016, Red Hat Inc, Alexander Gordeev <agordeev@xxxxxxxxxx> > > + * > > + * This work is licensed under the terms of the GNU LGPL, version 2. > > + */ > > +#include "libcflat.h" > > + > > +phys_addr_t pci_host_bridge_get_paddr(uint64_t addr); > > + > > +static inline > > +phys_addr_t pci_translate_addr(pcidevaddr_t __unused dev, uint64_t addr) > > +{ > > + /* > > + * Assume we only have single PCI host bridge in a system. > > + */ > > + return pci_host_bridge_get_paddr(addr); > > +} > > + > > +uint8_t pci_config_readb(pcidevaddr_t dev, uint8_t reg); > > +uint16_t pci_config_readw(pcidevaddr_t dev, uint8_t reg); > > +uint32_t pci_config_readl(pcidevaddr_t dev, uint8_t reg); > > +void pci_config_writel(pcidevaddr_t dev, uint8_t reg, uint32_t val); > > + > > +#endif > > diff --git a/lib/pci-host-generic.c b/lib/pci-host-generic.c > > new file mode 100644 > > index 000000000000..4a2716a33150 > > --- /dev/null > > +++ b/lib/pci-host-generic.c > > @@ -0,0 +1,295 @@ > > +/* > > + * Generic PCI host controller as described in PCI Bus Binding to Open Firmware > > + * > > + * Copyright (C) 2016, Red Hat Inc, Alexander Gordeev <agordeev@xxxxxxxxxx> > > + * > > + * This work is licensed under the terms of the GNU LGPL, version 2. > > + */ > > +#include "libcflat.h" > > +#include "devicetree.h" > > +#include "alloc.h" > > +#include "pci.h" > > +#include "asm/pci.h" > > +#include "asm/io.h" > > +#include "pci-host-generic.h" > > +#include <linux/pci_regs.h> > > + > > +static struct pci_host_bridge *pci_host_bridge; > > + > > +static int of_flags_to_pci_type(u32 of_flags) > > +{ > > + static int type_map[] = { > > + [1] = PCI_BASE_ADDRESS_SPACE_IO, > > + [2] = PCI_BASE_ADDRESS_MEM_TYPE_32, > > + [3] = PCI_BASE_ADDRESS_MEM_TYPE_64 > > + }; > > + int idx = (of_flags >> 24) & 0x03; > > + int res; > > + > > + assert(idx > 0); > > + res = type_map[idx]; > > + > > + if (of_flags & 0x40000000) > > + res |= PCI_BASE_ADDRESS_MEM_PREFETCH; > > + > > + return res; > > +} > > + > > +static int pci_bar_type(u32 bar) > > +{ > > + if (bar & PCI_BASE_ADDRESS_SPACE) > > + return PCI_BASE_ADDRESS_SPACE_IO; > > + else > > + return bar & (PCI_BASE_ADDRESS_MEM_TYPE_MASK | > > + PCI_BASE_ADDRESS_MEM_PREFETCH); > > +} > > + > > +/* > > + * Probe DT for a generic PCI host controller > > + * See kernel Documentation/devicetree/bindings/pci/host-generic-pci.txt > > + * and function gen_pci_probe() in drivers/pci/host/pci-host-generic.c > > + */ > > +static struct pci_host_bridge *pci_dt_probe(void) > > +{ > > + struct pci_host_bridge *host; > > + const void *fdt = dt_fdt(); > > + const struct fdt_property *prop; > > + struct dt_pbus_reg base; > > + struct dt_device dt_dev; > > + struct dt_bus dt_bus; > > + struct pci_addr_space *as; > > + fdt32_t *data; > > + u32 bus, bus_max; > > + u32 nac, nsc, nac_root, nsc_root; > > + int nr_range_cells, nr_addr_spaces; > > + int ret, node, len, i; > > + > > + if (!dt_available()) { > > + printf("No device tree found\n"); > > + return NULL; > > + } > > + > > + dt_bus_init_defaults(&dt_bus); > > + dt_device_init(&dt_dev, &dt_bus, NULL); > > + > > + node = fdt_path_offset(fdt, "/"); > > + assert(node >= 0); > > + > > + ret = dt_get_nr_cells(node, &nac_root, &nsc_root); > > + assert(ret == 0); > > + assert(nac_root == 1 || nac_root == 2); > > + > > + node = fdt_node_offset_by_compatible(fdt, node, > > + "pci-host-ecam-generic"); > > + if (node == -FDT_ERR_NOTFOUND) { > > + printf("No PCIe ECAM compatible controller found\n"); > > + return NULL; > > + } > > + assert(node >= 0); > > + > > + prop = fdt_get_property(fdt, node, "device_type", &len); > > + assert(prop && len == 4 && !strcmp((char *)prop->data, "pci")); > > + > > + dt_device_bind_node(&dt_dev, node); > > + ret = dt_pbus_get_base(&dt_dev, &base); > > + assert(ret == 0); > > + > > + prop = fdt_get_property(fdt, node, "bus-range", &len); > > + if (prop == NULL) { > > + assert(len == -FDT_ERR_NOTFOUND); > > + bus = 0x00; > > + bus_max = 0xff; > > + } else { > > + data = (fdt32_t *)prop->data; > > + bus = fdt32_to_cpu(data[0]); > > + bus_max = fdt32_to_cpu(data[1]); > > + assert(bus <= bus_max); > > + } > > + assert(bus_max < base.size / (1 << PCI_ECAM_BUS_SHIFT)); > > I see you kept the inequality, rather than my suggestion to change it to > assert(bus_max + 1 == base.size / (1 << PCI_ECAM_BUS_SHIFT)) Any reason > why? Because I do not read "bus-range" property description as it should match the host address space size. IOW, number of implemented busses which is less than host address space does not appear as a failure. > I'm not too worried about it though... -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html