Index: sys/arm64/cavium/thunder_pcie_common.h =================================================================== --- sys/arm64/cavium/thunder_pcie_common.h +++ sys/arm64/cavium/thunder_pcie_common.h @@ -53,6 +53,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 @@ -43,6 +43,8 @@ #include #include +#include +#include #include #include @@ -83,7 +85,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) @@ -144,6 +145,8 @@ static void thunder_pem_write_config(device_t, u_int, u_int, u_int, u_int, uint32_t, int); static int thunder_pem_write_ivar(device_t, device_t, int, uintptr_t); +static int thunder_pem_activate_resource(device_t dev, device_t child, int type, int rid, + struct resource *r); /* Global handlers for SLI interface */ static bus_space_handle_t sli0_s2m_regx_base = 0; @@ -161,7 +164,7 @@ 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_activate_resource, thunder_pem_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), @@ -227,6 +230,49 @@ } static int +thunder_pem_activate_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) +{ + pci_addr_t map, testval, start, start_conv; + struct thunder_pem_softc *sc; + + sc = device_get_softc(dev); + + switch (type) { + case SYS_RES_IOPORT: + case SYS_RES_MEMORY: + + /* Read BAR manually to get resource address and size */ + pci_read_bar(child, rid, &map, &testval, NULL); + + /* Mask the information bits */ + if (PCI_BAR_MEM(map)) + map &= PCIM_BAR_MEM_BASE; + else + map &= PCIM_BAR_IO_BASE; + start_conv = start = map; + + /* Translate PHYS start address to host PCI if necessary */ + if (range_addr_is_pci(sc->ranges, start, 1) == 0) { + if (range_addr_is_phys(sc->ranges, start, 1) == 0) + break; + start_conv = range_addr_phys_to_pci(sc->ranges, start); + } + if (start == start_conv) + break; + if (bootverbose) + device_printf(dev, "translate rid[%x] 0x%lx->0x%lx\n", + rid, start, start_conv); + pci_write_bar(child, pci_find_bar(child, rid), start_conv); + break; + default: + break; + } + + return (bus_generic_activate_resource(dev, child, type, rid, r)); +} + +static int thunder_pem_identify(device_t dev) { struct thunder_pem_softc *sc; @@ -316,14 +362,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); @@ -367,24 +405,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); } @@ -405,23 +449,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 * @@ -453,15 +502,18 @@ goto fail; } - /* Translate PCI address to host PHYS */ + /* Translate PCI address to host PHYS if necessary */ + if (range_addr_is_phys(sc->ranges, start, count) != 0) + goto is_good; if (range_addr_is_pci(sc->ranges, start, count) == 0) goto fail; start = range_addr_pci_to_phys(sc->ranges, start); end = start + count - 1; +is_good: 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); } @@ -529,6 +581,8 @@ struct thunder_pem_softc *sc; int error; int rid; + int tuple; + uint64_t base, size; sc = device_get_softc(dev); sc->dev = dev; @@ -588,16 +642,34 @@ 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); /* 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); + + for (tuple = 0; tuple < RANGES_TUPLES_MAX; tuple++) { + base = sc->ranges[tuple].phys_base; + size = sc->ranges[tuple].size; + if ((base == 0) || (size == 0)) + continue; /* empty range element */ + + error = rman_manage_region(&sc->mem_rman, base, base + size - 1); + 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\n", + sc->ranges[0].pci_base, + sc->ranges[0].phys_base, + sc->ranges[0].size); + } + } if (thunder_pem_init(sc)) { device_printf(dev, "Failure during PEM init\n");