summaryrefslogtreecommitdiffstats
path: root/sys/arm64
diff options
context:
space:
mode:
authorwma <wma@FreeBSD.org>2016-03-02 08:39:59 +0000
committerwma <wma@FreeBSD.org>2016-03-02 08:39:59 +0000
commit486a6ad7e085b98f5fa71ca32860e1da0a8f5e7e (patch)
tree9c78d8e63838ab41b114b759267d4979aa17c519 /sys/arm64
parent0b49e8be12cef3ef5a660191f2960b680dc19028 (diff)
downloadFreeBSD-src-486a6ad7e085b98f5fa71ca32860e1da0a8f5e7e.zip
FreeBSD-src-486a6ad7e085b98f5fa71ca32860e1da0a8f5e7e.tar.gz
Improve ThunderX PEM driver to work on pass2 revision
Things changed: * do not allocate 4GB of SLI space, because it's the waste of system resources. Allocate only small portions when needed. * provide own implementation of activate_resource which performs address translation between PCI bus and host PA address space. This is temporary solution, should be replaced by bus_map_resource once implemented. Obtained from: Semihalf Sponsored by: Cavium Approved by: cognet (mentor) Reviewed by: jhb Differential revision: https://reviews.freebsd.org/D5294
Diffstat (limited to 'sys/arm64')
-rw-r--r--sys/arm64/cavium/thunder_pcie_common.c22
-rw-r--r--sys/arm64/cavium/thunder_pcie_common.h1
-rw-r--r--sys/arm64/cavium/thunder_pcie_pem.c221
3 files changed, 200 insertions, 44 deletions
diff --git a/sys/arm64/cavium/thunder_pcie_common.c b/sys/arm64/cavium/thunder_pcie_common.c
index 2068070..a852222 100644
--- a/sys/arm64/cavium/thunder_pcie_common.c
+++ b/sys/arm64/cavium/thunder_pcie_common.c
@@ -106,6 +106,28 @@ range_addr_is_phys(struct pcie_range *ranges, uint64_t addr, uint64_t size)
}
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 < MAX_RANGES_TUPLES; 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);
+}
+
+uint64_t
range_addr_pci_to_phys(struct pcie_range *ranges, uint64_t pci_addr)
{
struct pcie_range *r;
diff --git a/sys/arm64/cavium/thunder_pcie_common.h b/sys/arm64/cavium/thunder_pcie_common.h
index b0df621..057dff5 100644
--- a/sys/arm64/cavium/thunder_pcie_common.h
+++ b/sys/arm64/cavium/thunder_pcie_common.h
@@ -36,6 +36,7 @@ MALLOC_DECLARE(M_THUNDER_PCIE);
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_pcie_identify_ecam(device_t, int *);
diff --git a/sys/arm64/cavium/thunder_pcie_pem.c b/sys/arm64/cavium/thunder_pcie_pem.c
index 02eb41c..8679850 100644
--- a/sys/arm64/cavium/thunder_pcie_pem.c
+++ b/sys/arm64/cavium/thunder_pcie_pem.c
@@ -93,7 +93,6 @@ __FBSDID("$FreeBSD$");
#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)
@@ -121,9 +120,15 @@ __FBSDID("$FreeBSD$");
#define RID_PEM_SPACE 1
+static int thunder_pem_activate_resource(device_t, device_t, int, int,
+ struct resource *);
+static int thunder_pem_adjust_resource(device_t, device_t, int,
+ struct resource *, rman_res_t, rman_res_t);
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 *);
@@ -135,6 +140,7 @@ static int thunder_pem_read_ivar(device_t, device_t, int, uintptr_t *);
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,
@@ -157,8 +163,9 @@ static device_method_t thunder_pem_methods[] = {
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_adjust_resource, thunder_pem_adjust_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),
@@ -174,6 +181,7 @@ DEFINE_CLASS_0(pcib, thunder_pem_driver, thunder_pem_methods,
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);
@@ -225,6 +233,88 @@ thunder_pem_write_ivar(device_t dev, device_t child, int index,
}
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_adjust_resource(device_t dev, device_t child, int type,
+ struct resource *res, rman_res_t start, rman_res_t end)
+{
+ struct thunder_pem_softc *sc;
+ struct rman *rm;
+
+ sc = device_get_softc(dev);
+
+ rm = thunder_pem_rman(sc, type);
+ if (rm == NULL)
+ return (bus_generic_adjust_resource(dev, child, type, res,
+ start, end));
+ if (!rman_is_region_manager(res, rm))
+ /*
+ * This means a child device has a memory or I/O
+ * resource not from you which shouldn't happen.
+ */
+ return (EINVAL);
+ return (rman_adjust_resource(res, start, end));
+}
+
+static int
thunder_pem_identify(device_t dev)
{
struct thunder_pem_softc *sc;
@@ -314,14 +404,6 @@ thunder_pem_init(struct thunder_pem_softc *sc)
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);
@@ -365,24 +447,30 @@ thunder_pem_read_config(device_t dev, u_int bus, u_int slot,
/* 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);
}
@@ -403,23 +491,28 @@ thunder_pem_write_config(device_t dev, u_int bus, u_int slot,
/* 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 *
@@ -431,35 +524,30 @@ thunder_pem_alloc_resource(device_t dev, device_t child, int type, int *rid,
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 (RMAN_IS_DEFAULT_RANGE(start, end)) {
- 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);
- end = start + count - 1;
+ if (!RMAN_IS_DEFAULT_RANGE(start, end)) {
+ /*
+ * We might get PHYS addresses here inherited from EFI.
+ * Convert to PCI if necessary.
+ */
+ 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);
}
@@ -503,6 +591,22 @@ thunder_pem_release_resource(device_t dev, device_t child, int type, int rid,
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)
{
@@ -529,6 +633,9 @@ thunder_pem_attach(device_t dev)
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;
@@ -601,16 +708,42 @@ thunder_pem_attach(device_t dev)
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 < MAX_RANGES_TUPLES; 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");
OpenPOWER on IntegriCloud