Index: sys/arm64/cavium/thunder_pcie_common.h =================================================================== --- sys/arm64/cavium/thunder_pcie_common.h +++ sys/arm64/cavium/thunder_pcie_common.h @@ -54,6 +54,7 @@ uint32_t range_addr_is_pci(struct pcie_range *, uint64_t, uint64_t); uint32_t range_addr_is_phys(struct pcie_range *, uint64_t, uint64_t); +uint64_t range_addr_phys_to_pci(struct pcie_range *, uint64_t); uint64_t range_addr_pci_to_phys(struct pcie_range *, uint64_t); int thunder_common_alloc_msi(device_t, device_t, int, int, int *); int thunder_common_alloc_msix(device_t, device_t, int *); Index: sys/arm64/cavium/thunder_pcie_common.c =================================================================== --- sys/arm64/cavium/thunder_pcie_common.c +++ sys/arm64/cavium/thunder_pcie_common.c @@ -109,3 +109,25 @@ return (0); } +uint64_t +range_addr_phys_to_pci(struct pcie_range *ranges, uint64_t phys_addr) +{ + struct pcie_range *r; + uint64_t offset; + int tuple; + + /* Find physical address corresponding to given bus address */ + for (tuple = 0; tuple < RANGES_TUPLES_MAX; tuple++) { + r = &ranges[tuple]; + if (phys_addr >= r->phys_base && + phys_addr < (r->phys_base + r->size)) { + /* Given phys addr is in this range. + * Translate phys addr to bus addr. + */ + offset = phys_addr - r->phys_base; + return (r->pci_base + offset); + } + } + return (0); +} + Index: sys/arm64/cavium/thunder_pcie_pem.c =================================================================== --- sys/arm64/cavium/thunder_pcie_pem.c +++ sys/arm64/cavium/thunder_pcie_pem.c @@ -83,7 +83,6 @@ #define SLIX_S2M_REGX_ACC_SPACING 0x001000000000UL #define SLI_BASE 0x880000000000UL #define SLI_WINDOW_SPACING 0x004000000000UL -#define SLI_WINDOW_SIZE 0x0000FF000000UL #define SLI_PCI_OFFSET 0x001000000000UL #define SLI_NODE_SHIFT (44) #define SLI_NODE_MASK (3) @@ -111,9 +110,13 @@ #define RID_PEM_SPACE 1 +static int thunder_pem_activate_resource(device_t, device_t, int, int, + struct resource *); static struct resource * thunder_pem_alloc_resource(device_t, device_t, int, int *, rman_res_t, rman_res_t, rman_res_t, u_int); static int thunder_pem_attach(device_t); +static int thunder_pem_deactivate_resource(device_t, device_t, int, int, + struct resource *); static int thunder_pem_detach(device_t); static uint64_t thunder_pem_config_reg_read(struct thunder_pem_softc *, int); static int thunder_pem_link_init(struct thunder_pem_softc *); @@ -125,6 +128,7 @@ static void thunder_pem_release_all(device_t); static int thunder_pem_release_resource(device_t, device_t, int, int, struct resource *); +static struct rman * thunder_pem_rman(struct thunder_pem_softc *, int); static void thunder_pem_slix_s2m_regx_acc_modify(struct thunder_pem_softc *, int, int); static void thunder_pem_write_config(device_t, u_int, u_int, u_int, u_int, @@ -147,8 +151,8 @@ DEVMETHOD(bus_write_ivar, thunder_pem_write_ivar), DEVMETHOD(bus_alloc_resource, thunder_pem_alloc_resource), DEVMETHOD(bus_release_resource, thunder_pem_release_resource), - DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), - DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + DEVMETHOD(bus_activate_resource, thunder_pem_activate_resource), + DEVMETHOD(bus_deactivate_resource, thunder_pem_deactivate_resource), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), @@ -164,6 +168,7 @@ sizeof(struct thunder_pem_softc)); static devclass_t thunder_pem_devclass; +extern struct bus_space memmap_bus; DRIVER_MODULE(thunder_pem, pci, thunder_pem_driver, thunder_pem_devclass, 0, 0); MODULE_DEPEND(thunder_pem, pci, 1, 1, 1); @@ -215,6 +220,66 @@ } static int +thunder_pem_activate_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) +{ + int err; + bus_addr_t paddr; + bus_size_t psize; + bus_space_handle_t vaddr; + struct thunder_pem_softc *sc; + + if ((err = rman_activate_resource(r)) != 0) + return (err); + + sc = device_get_softc(dev); + + /* + * If this is a memory resource, map it into the kernel. + */ + if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) { + paddr = (bus_addr_t)rman_get_start(r); + psize = (bus_size_t)rman_get_size(r); + + paddr = range_addr_pci_to_phys(sc->ranges, paddr); + + err = bus_space_map(&memmap_bus, paddr, psize, 0, &vaddr); + if (err != 0) { + rman_deactivate_resource(r); + return (err); + } + rman_set_bustag(r, &memmap_bus); + rman_set_virtual(r, (void *)vaddr); + rman_set_bushandle(r, vaddr); + } + return (0); +} + +/* + * This function is an exact copy of nexus_deactivate_resource() + * Keep it up-to-date with all changes in nexus. To be removed + * once bus-mapping interface is developed. + */ +static int +thunder_pem_deactivate_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ + bus_size_t psize; + bus_space_handle_t vaddr; + + psize = (bus_size_t)rman_get_size(r); + vaddr = rman_get_bushandle(r); + + if (vaddr != 0) { + bus_space_unmap(&memmap_bus, vaddr, psize); + rman_set_virtual(r, NULL); + rman_set_bushandle(r, 0); + } + + return (rman_deactivate_resource(r)); +} + +static int thunder_pem_identify(device_t dev) { struct thunder_pem_softc *sc; @@ -304,14 +369,6 @@ return retval; } - retval = bus_space_map(sc->reg_bst, sc->sli_window_base, - SLI_WINDOW_SIZE, 0, &sc->pem_sli_base); - if (retval) { - device_printf(sc->dev, - "Unable to map RC%d pem_addr base address", sc->id); - return (ENOMEM); - } - /* To support 32-bit PCIe devices, set S2M_REGx_ACC[BA]=0x0 */ for (i = 0; i < SLI_ACC_REG_CNT; i++) { thunder_pem_slix_s2m_regx_acc_modify(sc, sc->sli_group, i); @@ -355,24 +412,30 @@ /* Calculate offset */ offset = (bus << PEM_BUS_SHIFT) | (slot << PEM_SLOT_SHIFT) | - (func << PEM_FUNC_SHIFT) | reg; + (func << PEM_FUNC_SHIFT); t = sc->reg_bst; h = sc->pem_sli_base; + bus_space_map(sc->reg_bst, sc->sli_window_base + offset, + PCIE_REGMAX, 0, &h); + switch (bytes) { case 1: - data = bus_space_read_1(t, h, offset); + data = bus_space_read_1(t, h, reg); break; case 2: - data = le16toh(bus_space_read_2(t, h, offset)); + data = le16toh(bus_space_read_2(t, h, reg)); break; case 4: - data = le32toh(bus_space_read_4(t, h, offset)); + data = le32toh(bus_space_read_4(t, h, reg)); break; default: - return (~0U); + data = ~0U; + break; } + bus_space_unmap(sc->reg_bst, h, PCIE_REGMAX); + return (data); } @@ -393,23 +456,28 @@ /* Calculate offset */ offset = (bus << PEM_BUS_SHIFT) | (slot << PEM_SLOT_SHIFT) | - (func << PEM_FUNC_SHIFT) | reg; + (func << PEM_FUNC_SHIFT); t = sc->reg_bst; h = sc->pem_sli_base; + bus_space_map(sc->reg_bst, sc->sli_window_base + offset, + PCIE_REGMAX, 0, &h); + switch (bytes) { case 1: - bus_space_write_1(t, h, offset, val); + bus_space_write_1(t, h, reg, val); break; case 2: - bus_space_write_2(t, h, offset, htole16(val)); + bus_space_write_2(t, h, reg, htole16(val)); break; case 4: - bus_space_write_4(t, h, offset, htole32(val)); + bus_space_write_4(t, h, reg, htole32(val)); break; default: - return; + break; } + + bus_space_unmap(sc->reg_bst, h, PCIE_REGMAX); } static struct resource * @@ -421,35 +489,28 @@ struct resource *res; device_t parent_dev; - switch (type) { - case SYS_RES_IOPORT: - rm = &sc->io_rman; - break; - case SYS_RES_MEMORY: - rm = &sc->mem_rman; - break; - default: + rm = thunder_pem_rman(sc, type); + if (rm == NULL) { /* Find parent device. On ThunderX we know an exact path. */ parent_dev = device_get_parent(device_get_parent(dev)); return (BUS_ALLOC_RESOURCE(parent_dev, dev, type, rid, start, end, count, flags)); }; - if ((start == 0UL) && (end == ~0UL)) { - device_printf(dev, - "Cannot allocate resource with unspecified range\n"); - goto fail; - } - - /* Translate PCI address to host PHYS */ - if (range_addr_is_pci(sc->ranges, start, count) == 0) - goto fail; - start = range_addr_pci_to_phys(sc->ranges, start); + /* + * We might get PHYS addresses here inherited from EFI. + * Convert to PCI if necessary. + */ + if ((start != 0UL) || (end != ~0UL)) { + if (range_addr_is_phys(sc->ranges, start, count)) { + start = range_addr_phys_to_pci(sc->ranges, start); end = start + count - 1; + } + } if (bootverbose) { device_printf(dev, - "rman_reserve_resource: start=%#lx, end=%#lx, count=%#lx\n", + "thunder_pem_alloc_resource: start=%#lx, end=%#lx, count=%#lx\n", start, end, count); } @@ -493,6 +554,22 @@ return (rman_release_resource(res)); } +static struct rman * +thunder_pem_rman(struct thunder_pem_softc *sc, int type) +{ + + switch (type) { + case SYS_RES_IOPORT: + return (&sc->io_rman); + case SYS_RES_MEMORY: + return (&sc->mem_rman); + default: + break; + } + + return (NULL); +} + static int thunder_pem_probe(device_t dev) { @@ -519,6 +596,9 @@ struct thunder_pem_softc *sc; int error; int rid; + int tuple; + uint64_t base, size; + struct rman *rman; sc = device_get_softc(dev); sc->dev = dev; @@ -591,16 +671,42 @@ sc->ranges[0].size = PCI_MEMORY_SIZE; sc->ranges[0].phys_base = sc->sli_window_base + SLI_PCI_OFFSET + sc->ranges[0].pci_base; - rman_manage_region(&sc->mem_rman, sc->ranges[0].phys_base, - sc->ranges[0].phys_base + sc->ranges[0].size - 1); + sc->ranges[0].flags = SYS_RES_MEMORY; /* Fill IO window */ sc->ranges[1].pci_base = PCI_IO_BASE; sc->ranges[1].size = PCI_IO_SIZE; sc->ranges[1].phys_base = sc->sli_window_base + SLI_PCI_OFFSET + sc->ranges[1].pci_base; - rman_manage_region(&sc->io_rman, sc->ranges[1].phys_base, - sc->ranges[1].phys_base + sc->ranges[1].size - 1); + sc->ranges[1].flags = SYS_RES_IOPORT; + + for (tuple = 0; tuple < RANGES_TUPLES_MAX; tuple++) { + base = sc->ranges[tuple].pci_base; + size = sc->ranges[tuple].size; + if (size == 0) + continue; /* empty range element */ + + rman = thunder_pem_rman(sc, sc->ranges[tuple].flags); + if (rman != NULL) + error = rman_manage_region(rman, base, + base + size - 1); + else + error = EINVAL; + if (error) { + device_printf(dev, + "rman_manage_region() failed. error = %d\n", error); + rman_fini(&sc->mem_rman); + return (error); + } + if (bootverbose) { + device_printf(dev, + "\tPCI addr: 0x%jx, CPU addr: 0x%jx, Size: 0x%jx, Flags:0x%jx\n", + sc->ranges[tuple].pci_base, + sc->ranges[tuple].phys_base, + sc->ranges[tuple].size, + sc->ranges[tuple].flags); + } + } if (thunder_pem_init(sc)) { device_printf(dev, "Failure during PEM init\n");