svn commit: r326080 - in head/sys: dev/bhnd dev/bhnd/bhndb dev/bhnd/cores/pci dev/bhnd/cores/pcie2 mips/broadcom
Landon J. Fuller
landonf at FreeBSD.org
Tue Nov 21 23:25:25 UTC 2017
Author: landonf
Date: Tue Nov 21 23:25:22 2017
New Revision: 326080
URL: https://svnweb.freebsd.org/changeset/base/326080
Log:
bhnd(4): Add support for querying DMA address translation parameters
BHND Wi-Fi chipsets and SoCs share a common DMA engine, operating within
backplane address space. To support host DMA on Wi-Fi chipsets, the bridge
core maps host address space onto the backplane; any host addresses must
be translated to their corresponding backplane address.
- Defines a new bhnd_get_dma_translation(9) API to support querying DMA
address translation parameters from the bhnd(4) bus.
- Extends bhndb(4) to provide DMA translation descriptors from a DMA
address translation table defined in the host bridge-specific
bhndb_hwcfg.
- Defines bhndb(4) DMA address translation tables for all supported host
bridge cores.
- Extends mips/broadcom's bhnd_nexus driver to return an identity (no-op)
DMA translation descriptor; no translation is required when addressing
the SoC backplane.
Approved by: adrian (mentor)
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D12582
Modified:
head/sys/dev/bhnd/bhnd.h
head/sys/dev/bhnd/bhnd_bus_if.m
head/sys/dev/bhnd/bhnd_subr.c
head/sys/dev/bhnd/bhndb/bhndb.c
head/sys/dev/bhnd/bhndb/bhndb.h
head/sys/dev/bhnd/bhndb/bhndb_pci.c
head/sys/dev/bhnd/bhndb/bhndb_pci_hwdata.c
head/sys/dev/bhnd/bhndb/bhndb_subr.c
head/sys/dev/bhnd/bhndb/bhndbvar.h
head/sys/dev/bhnd/cores/pci/bhnd_pcireg.h
head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2_reg.h
head/sys/mips/broadcom/bhnd_nexus.c
Modified: head/sys/dev/bhnd/bhnd.h
==============================================================================
--- head/sys/dev/bhnd/bhnd.h Tue Nov 21 23:15:20 2017 (r326079)
+++ head/sys/dev/bhnd/bhnd.h Tue Nov 21 23:25:22 2017 (r326080)
@@ -220,6 +220,94 @@ struct bhnd_core_info {
};
/**
+ * bhnd(4) DMA address widths.
+ */
+typedef enum {
+ BHND_DMA_ADDR_30BIT = 30, /**< 30-bit DMA */
+ BHND_DMA_ADDR_32BIT = 32, /**< 32-bit DMA */
+ BHND_DMA_ADDR_64BIT = 64, /**< 64-bit DMA */
+} bhnd_dma_addrwidth;
+
+/**
+ * Convert an address width (in bits) to its corresponding mask.
+ */
+#define BHND_DMA_ADDR_BITMASK(_width) \
+ ((_width >= 64) ? ~0ULL : \
+ (_width == 0) ? 0x0 : \
+ ((1ULL << (_width)) - 1)) \
+
+/**
+ * bhnd(4) DMA address translation descriptor.
+ */
+struct bhnd_dma_translation {
+ /**
+ * Host-to-device physical address translation.
+ *
+ * This may be added to the host physical address to produce a device
+ * DMA address.
+ */
+ bhnd_addr_t base_addr;
+
+ /**
+ * Device-addressable address mask.
+ *
+ * This defines the device's DMA address range, excluding any bits
+ * reserved for mapping the address to the base_addr.
+ */
+ bhnd_addr_t addr_mask;
+
+ /**
+ * Device-addressable extended address mask.
+ *
+ * If a per-core bhnd(4) DMA engine supports the 'addrext' control
+ * field, it can be used to provide address bits excluded by addr_mask.
+ *
+ * Support for DMA extended address changes – including coordination
+ * with the core providing DMA translation – is handled transparently by
+ * the DMA engine. For example, on PCI(e) Wi-Fi chipsets, the Wi-Fi
+ * core DMA engine will (in effect) update the PCI core's DMA
+ * sbtopcitranslation base address to map the full address prior to
+ * performing a DMA transaction.
+ */
+ bhnd_addr_t addrext_mask;
+
+ /**
+ * Translation flags (see bhnd_dma_translation_flags)
+ */
+ uint32_t flags;
+};
+
+#define BHND_DMA_TRANSLATION_TABLE_END { 0, 0, 0, 0 }
+
+#define BHND_DMA_IS_TRANSLATION_TABLE_END(_dt) \
+ ((_dt)->base_addr == 0 && (_dt)->addr_mask == 0 && \
+ (_dt)->addrext_mask == 0 && (_dt)->flags == 0)
+
+/**
+ * bhnd(4) DMA address translation flags.
+ */
+enum bhnd_dma_translation_flags {
+ /**
+ * The translation remaps the device's physical address space.
+ *
+ * This is used in conjunction with BHND_DMA_TRANSLATION_BYTESWAPPED to
+ * define a DMA translation that provides byteswapped access to
+ * physical memory on big-endian MIPS SoCs.
+ */
+ BHND_DMA_TRANSLATION_PHYSMAP = (1<<0),
+
+ /**
+ * Provides a byte-swapped mapping; write requests will be byte-swapped
+ * before being written to memory, and read requests will be
+ * byte-swapped before being returned.
+ *
+ * This is primarily used to perform efficient byte swapping of DMA
+ * data on embedded MIPS SoCs executing in big-endian mode.
+ */
+ BHND_DMA_TRANSLATION_BYTESWAPPED = (1<<1),
+};
+
+/**
* A bhnd(4) bus resource.
*
* This provides an abstract interface to per-core resources that may require
@@ -512,6 +600,10 @@ int bhnd_bus_generic_get_nvram_var(device_t dev,
bhnd_nvram_type type);
const struct bhnd_chipid *bhnd_bus_generic_get_chipid(device_t dev,
device_t child);
+int bhnd_bus_generic_get_dma_translation(
+ device_t dev, device_t child, u_int width,
+ uint32_t flags, bus_dma_tag_t *dmat,
+ struct bhnd_dma_translation *translation);
int bhnd_bus_generic_read_board_info(device_t dev,
device_t child,
struct bhnd_board_info *info);
@@ -840,6 +932,38 @@ bhnd_pwrctl_ungate_clock(device_t dev, bhnd_clock cloc
static inline bhnd_attach_type
bhnd_get_attach_type (device_t dev) {
return (BHND_BUS_GET_ATTACH_TYPE(device_get_parent(dev), dev));
+}
+
+/**
+ * Find the best available DMA address translation capable of mapping a
+ * physical host address to a BHND DMA device address of @p width with
+ * @p flags.
+ *
+ * @param dev A bhnd bus child device.
+ * @param width The address width within which the translation window must
+ * reside (see BHND_DMA_ADDR_*).
+ * @param flags Required translation flags (see BHND_DMA_TRANSLATION_*).
+ * @param[out] dmat On success, will be populated with a DMA tag specifying the
+ * @p translation DMA address restrictions. This argment may be NULL if the DMA
+ * tag is not desired.
+ * the set of valid host DMA addresses reachable via @p translation.
+ * @param[out] translation On success, will be populated with a DMA address
+ * translation descriptor for @p child. This argment may be NULL if the
+ * descriptor is not desired.
+ *
+ * @retval 0 success
+ * @retval ENODEV If DMA is not supported.
+ * @retval ENOENT If no DMA translation matching @p width and @p flags is
+ * available.
+ * @retval non-zero If determining the DMA address translation for @p child
+ * otherwise fails, a regular unix error code will be returned.
+ */
+static inline int
+bhnd_get_dma_translation(device_t dev, u_int width, uint32_t flags,
+ bus_dma_tag_t *dmat, struct bhnd_dma_translation *translation)
+{
+ return (BHND_BUS_GET_DMA_TRANSLATION(device_get_parent(dev), dev, width,
+ flags, dmat, translation));
}
/**
Modified: head/sys/dev/bhnd/bhnd_bus_if.m
==============================================================================
--- head/sys/dev/bhnd/bhnd_bus_if.m Tue Nov 21 23:15:20 2017 (r326079)
+++ head/sys/dev/bhnd/bhnd_bus_if.m Tue Nov 21 23:25:22 2017 (r326080)
@@ -46,6 +46,7 @@ HEADER {
struct bhnd_board_info;
struct bhnd_core_info;
struct bhnd_chipid;
+ struct bhnd_dma_translation;
struct bhnd_devinfo;
struct bhnd_resource;
}
@@ -112,7 +113,7 @@ CODE {
{
panic("bhnd_bus_get_attach_type unimplemented");
}
-
+
static bhnd_clksrc
bhnd_bus_null_pwrctl_get_clksrc(device_t dev, device_t child,
bhnd_clock clock)
@@ -478,6 +479,41 @@ METHOD bhnd_attach_type get_attach_type {
device_t dev;
device_t child;
} DEFAULT bhnd_bus_null_get_attach_type;
+
+
+/**
+ * Find the best available DMA address translation capable of mapping a
+ * physical host address to a BHND DMA device address of @p width with
+ * @p flags.
+ *
+ * @param dev The parent of @p child.
+ * @param child The bhnd device requesting the DMA address translation.
+ * @param width The address width within which the translation window must
+ * reside (see BHND_DMA_ADDR_*).
+ * @param flags Required translation flags (see BHND_DMA_TRANSLATION_*).
+ * @param[out] dmat On success, will be populated with a DMA tag specifying the
+ * @p translation DMA address restrictions. This argment may be NULL if the DMA
+ * tag is not desired.
+ * the set of valid host DMA addresses reachable via @p translation.
+ * @param[out] translation On success, will be populated with a DMA address
+ * translation descriptor for @p child. This argment may be NULL if the
+ * descriptor is not desired.
+ *
+ * @retval 0 success
+ * @retval ENODEV If DMA is not supported.
+ * @retval ENOENT If no DMA translation matching @p width and @p flags is
+ * available.
+ * @retval non-zero If determining the DMA address translation for @p child
+ * otherwise fails, a regular unix error code will be returned.
+ */
+METHOD int get_dma_translation {
+ device_t dev;
+ device_t child;
+ u_int width;
+ uint32_t flags;
+ bus_dma_tag_t *dmat;
+ struct bhnd_dma_translation *translation;
+} DEFAULT bhnd_bus_generic_get_dma_translation;
/**
* Attempt to read the BHND board identification from the parent bus.
Modified: head/sys/dev/bhnd/bhnd_subr.c
==============================================================================
--- head/sys/dev/bhnd/bhnd_subr.c Tue Nov 21 23:15:20 2017 (r326079)
+++ head/sys/dev/bhnd/bhnd_subr.c Tue Nov 21 23:25:22 2017 (r326080)
@@ -2104,6 +2104,27 @@ bhnd_bus_generic_get_chipid(device_t dev, device_t chi
panic("missing BHND_BUS_GET_CHIPID()");
}
+/**
+ * Helper function for implementing BHND_BUS_GET_DMA_TRANSLATION().
+ *
+ * If a parent device is available, this implementation delegates the
+ * request to the BHND_BUS_GET_DMA_TRANSLATION() method on the parent of @p dev.
+ *
+ * If no parent device is available, this implementation will panic.
+ */
+int
+bhnd_bus_generic_get_dma_translation(device_t dev, device_t child, u_int width,
+ uint32_t flags, bus_dma_tag_t *dmat,
+ struct bhnd_dma_translation *translation)
+{
+ if (device_get_parent(dev) != NULL) {
+ return (BHND_BUS_GET_DMA_TRANSLATION(device_get_parent(dev),
+ child, width, flags, dmat, translation));
+ }
+
+ panic("missing BHND_BUS_GET_DMA_TRANSLATION()");
+}
+
/* nvram board_info population macros for bhnd_bus_generic_read_board_info() */
#define BHND_GV(_dest, _name) \
bhnd_nvram_getvar_uint(child, BHND_NVAR_ ## _name, &_dest, \
Modified: head/sys/dev/bhnd/bhndb/bhndb.c
==============================================================================
--- head/sys/dev/bhnd/bhndb/bhndb.c Tue Nov 21 23:15:20 2017 (r326079)
+++ head/sys/dev/bhnd/bhndb/bhndb.c Tue Nov 21 23:25:22 2017 (r326080)
@@ -2040,13 +2040,93 @@ bhndb_remap_intr(device_t dev, device_t child, u_int i
}
/**
+ * Default bhndb(4) implementation of BHND_BUS_GET_DMA_TRANSLATION().
+ */
+static inline int
+bhndb_get_dma_translation(device_t dev, device_t child, u_int width,
+ uint32_t flags, bus_dma_tag_t *dmat,
+ struct bhnd_dma_translation *translation)
+{
+ struct bhndb_softc *sc;
+ const struct bhndb_hwcfg *hwcfg;
+ const struct bhnd_dma_translation *match;
+ bus_dma_tag_t match_dmat;
+ bhnd_addr_t addr_mask, match_addr_mask;
+
+ sc = device_get_softc(dev);
+ hwcfg = sc->bus_res->cfg;
+
+ /* Is DMA supported? */
+ if (sc->bus_res->res->dma_tags == NULL)
+ return (ENODEV);
+
+ /* Find the best matching descriptor for the requested type */
+ addr_mask = BHND_DMA_ADDR_BITMASK(width);
+
+ match = NULL;
+ match_addr_mask = 0x0;
+ match_dmat = NULL;
+
+ for (size_t i = 0; i < sc->bus_res->res->num_dma_tags; i++) {
+ const struct bhnd_dma_translation *dwin;
+ bhnd_addr_t masked;
+
+ dwin = &hwcfg->dma_translations[i];
+
+ /* The base address must be device addressable */
+ if ((dwin->base_addr & addr_mask) != dwin->base_addr)
+ continue;
+
+ /* The flags must match */
+ if ((dwin->flags & flags) != flags)
+ continue;
+
+ /* The window must cover at least part of our addressable
+ * range */
+ masked = (dwin->addr_mask | dwin->addrext_mask) & addr_mask;
+ if (masked == 0)
+ continue;
+
+ /* Is this a better match? */
+ if (match == NULL || masked > match_addr_mask) {
+ match = dwin;
+ match_addr_mask = masked;
+ match_dmat = sc->bus_res->res->dma_tags[i];
+ }
+ }
+
+ if (match == NULL || match_addr_mask == 0)
+ return (ENOENT);
+
+ if (dmat != NULL)
+ *dmat = match_dmat;
+
+ if (translation != NULL)
+ *translation = *match;
+
+ return (0);
+}
+
+/**
* Default bhndb(4) implementation of BUS_GET_DMA_TAG().
*/
static bus_dma_tag_t
bhndb_get_dma_tag(device_t dev, device_t child)
{
- // TODO
- return (NULL);
+ struct bhndb_softc *sc = device_get_softc(dev);
+
+ /*
+ * A bridge may have multiple DMA translation descriptors, each with
+ * their own incompatible restrictions; drivers should in general call
+ * BHND_BUS_GET_DMA_TRANSLATION() to fetch both the best available DMA
+ * translation, and its corresponding DMA tag.
+ *
+ * Child drivers that do not use BHND_BUS_GET_DMA_TRANSLATION() are
+ * responsible for creating their own restricted DMA tag; since we
+ * cannot do this for them in BUS_GET_DMA_TAG(), we simply return the
+ * bridge parent's DMA tag directly;
+ */
+ return (bus_get_dma_tag(sc->parent_dev));
}
static device_method_t bhndb_methods[] = {
@@ -2102,6 +2182,7 @@ static device_method_t bhndb_methods[] = {
DEVMETHOD(bhnd_bus_get_nvram_var, bhnd_bus_generic_get_nvram_var),
DEVMETHOD(bhnd_bus_map_intr, bhndb_bhnd_map_intr),
DEVMETHOD(bhnd_bus_unmap_intr, bhndb_bhnd_unmap_intr),
+ DEVMETHOD(bhnd_bus_get_dma_translation, bhndb_get_dma_translation),
DEVMETHOD(bhnd_bus_get_service_registry,bhndb_get_service_registry),
DEVMETHOD(bhnd_bus_register_provider, bhnd_bus_generic_sr_register_provider),
Modified: head/sys/dev/bhnd/bhndb/bhndb.h
==============================================================================
--- head/sys/dev/bhnd/bhndb/bhndb.h Tue Nov 21 23:15:20 2017 (r326079)
+++ head/sys/dev/bhnd/bhndb/bhndb.h Tue Nov 21 23:25:22 2017 (r326080)
@@ -107,12 +107,13 @@ struct bhndb_regwin {
/**
* Bridge hardware configuration.
*
- * Provides the bridge's register/address mappings, and the resources
- * via which those mappings may be accessed.
+ * Provides the bridge's DMA address translation descriptions, register/address
+ * mappings, and the resources via which those mappings may be accessed.
*/
struct bhndb_hwcfg {
- const struct resource_spec *resource_specs;
- const struct bhndb_regwin *register_windows;
+ const struct resource_spec *resource_specs; /**< resources required by our register windows */
+ const struct bhndb_regwin *register_windows; /**< register window table */
+ const struct bhnd_dma_translation *dma_translations; /**< DMA address translation table, or NULL if DMA is not supported */
};
/**
Modified: head/sys/dev/bhnd/bhndb/bhndb_pci.c
==============================================================================
--- head/sys/dev/bhnd/bhndb/bhndb_pci.c Tue Nov 21 23:15:20 2017 (r326079)
+++ head/sys/dev/bhnd/bhndb/bhndb_pci.c Tue Nov 21 23:25:22 2017 (r326080)
@@ -509,7 +509,7 @@ bhndb_pci_read_core_table(device_t dev, struct bhnd_ch
hint = BHNDB_BUS_GET_CHIPID(parent_dev, dev);
/* Allocate our host resources */
- if ((error = bhndb_alloc_host_resources(parent_dev, cfg, &hr)))
+ if ((error = bhndb_alloc_host_resources(&hr, dev, parent_dev, cfg)))
return (error);
/* Initialize our erom I/O state */
Modified: head/sys/dev/bhnd/bhndb/bhndb_pci_hwdata.c
==============================================================================
--- head/sys/dev/bhnd/bhndb/bhndb_pci_hwdata.c Tue Nov 21 23:15:20 2017 (r326079)
+++ head/sys/dev/bhnd/bhndb/bhndb_pci_hwdata.c Tue Nov 21 23:25:22 2017 (r326080)
@@ -45,6 +45,9 @@ __FBSDID("$FreeBSD$");
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
+#include <dev/bhnd/cores/pci/bhnd_pcireg.h>
+#include <dev/bhnd/cores/pcie2/bhnd_pcie2_reg.h>
+
#include "bhndbvar.h"
#include "bhndb_pcireg.h"
@@ -100,6 +103,9 @@ const struct bhndb_hwcfg bhndb_pci_siba_generic_hwcfg
},
BHNDB_REGWIN_TABLE_END
},
+
+ /* DMA unsupported under generic configuration */
+ .dma_translations = NULL,
};
@@ -147,6 +153,9 @@ const struct bhndb_hwcfg bhndb_pci_bcma_generic_hwcfg
BHNDB_REGWIN_TABLE_END
},
+
+ /* DMA unsupported under generic configuration */
+ .dma_translations = NULL,
};
/**
@@ -319,6 +328,15 @@ static const struct bhndb_hwcfg bhndb_pci_hwcfg_v0 = {
},
BHNDB_REGWIN_TABLE_END
},
+
+ .dma_translations = (const struct bhnd_dma_translation[]) {
+ {
+ .base_addr = BHND_PCI_DMA32_TRANSLATION,
+ .addr_mask = ~BHND_PCI_DMA32_MASK,
+ .addrext_mask = BHND_PCI_DMA32_MASK
+ },
+ BHND_DMA_TRANSLATION_TABLE_END
+ }
};
/**
@@ -385,6 +403,15 @@ static const struct bhndb_hwcfg bhndb_pci_hwcfg_v1_pci
BHNDB_REGWIN_TABLE_END
},
+
+ .dma_translations = (const struct bhnd_dma_translation[]) {
+ {
+ .base_addr = BHND_PCI_DMA32_TRANSLATION,
+ .addr_mask = ~BHND_PCI_DMA32_MASK,
+ .addrext_mask = BHND_PCI_DMA32_MASK
+ },
+ BHND_DMA_TRANSLATION_TABLE_END
+ }
};
/**
@@ -451,6 +478,20 @@ static const struct bhndb_hwcfg bhndb_pci_hwcfg_v1_pci
BHNDB_REGWIN_TABLE_END
},
+
+ .dma_translations = (const struct bhnd_dma_translation[]) {
+ {
+ .base_addr = BHND_PCIE_DMA32_TRANSLATION,
+ .addr_mask = ~BHND_PCIE_DMA32_MASK,
+ .addrext_mask = BHND_PCIE_DMA32_MASK
+ },
+ {
+ .base_addr = BHND_PCIE_DMA64_TRANSLATION,
+ .addr_mask = ~BHND_PCIE_DMA64_MASK,
+ .addrext_mask = 0
+ },
+ BHND_DMA_TRANSLATION_TABLE_END
+ }
};
/**
@@ -520,6 +561,20 @@ static const struct bhndb_hwcfg bhndb_pci_hwcfg_v2 = {
BHNDB_REGWIN_TABLE_END
},
+
+ .dma_translations = (const struct bhnd_dma_translation[]) {
+ {
+ .base_addr = BHND_PCIE_DMA32_TRANSLATION,
+ .addr_mask = ~BHND_PCIE_DMA32_MASK,
+ .addrext_mask = BHND_PCIE_DMA32_MASK
+ },
+ {
+ .base_addr = BHND_PCIE_DMA64_TRANSLATION,
+ .addr_mask = ~BHND_PCIE_DMA64_MASK,
+ .addrext_mask = 0
+ },
+ BHND_DMA_TRANSLATION_TABLE_END
+ }
};
/**
@@ -589,4 +644,13 @@ static const struct bhndb_hwcfg bhndb_pci_hwcfg_v3 = {
BHNDB_REGWIN_TABLE_END
},
+
+ .dma_translations = (const struct bhnd_dma_translation[]) {
+ {
+ .base_addr = BHND_PCIE2_DMA64_TRANSLATION,
+ .addr_mask = ~BHND_PCIE2_DMA64_MASK,
+ .addrext_mask = 0
+ },
+ BHND_DMA_TRANSLATION_TABLE_END
+ }
};
Modified: head/sys/dev/bhnd/bhndb/bhndb_subr.c
==============================================================================
--- head/sys/dev/bhnd/bhndb/bhndb_subr.c Tue Nov 21 23:15:20 2017 (r326079)
+++ head/sys/dev/bhnd/bhndb/bhndb_subr.c Tue Nov 21 23:25:22 2017 (r326080)
@@ -41,6 +41,10 @@ __FBSDID("$FreeBSD$");
#include "bhndb_private.h"
#include "bhndbvar.h"
+static int bhndb_dma_tag_create(device_t dev, bus_dma_tag_t parent_dmat,
+ const struct bhnd_dma_translation *translation,
+ bus_dma_tag_t *dmat);
+
/**
* Attach a BHND bridge device to @p parent.
*
@@ -402,7 +406,7 @@ bhndb_alloc_resources(device_t dev, device_t parent_de
}
/* Allocate host resources */
- error = bhndb_alloc_host_resources(parent_dev, r->cfg, &r->res);
+ error = bhndb_alloc_host_resources(&r->res, dev, parent_dev, r->cfg);
if (error) {
device_printf(r->dev,
"could not allocate host resources on %s: %d\n",
@@ -494,6 +498,65 @@ failed:
}
/**
+ * Create a new DMA tag for the given @p translation.
+ *
+ * @param dev The bridge device.
+ * @param parent_dmat The parent DMA tag, or NULL if none.
+ * @param translation The DMA translation for which a DMA tag will
+ * be created.
+ * @param[out] dmat On success, the newly created DMA tag.
+ *
+ * @retval 0 success
+ * @retval non-zero if creating the new DMA tag otherwise fails, a regular
+ * unix error code will be returned.
+ */
+static int
+bhndb_dma_tag_create(device_t dev, bus_dma_tag_t parent_dmat,
+ const struct bhnd_dma_translation *translation, bus_dma_tag_t *dmat)
+{
+ bus_dma_tag_t translation_tag;
+ bhnd_addr_t dt_mask;
+ bus_addr_t boundary;
+ bus_addr_t lowaddr, highaddr;
+ int error;
+
+ highaddr = BUS_SPACE_MAXADDR;
+ boundary = 0;
+
+ /* Determine full addressable mask */
+ dt_mask = (translation->addr_mask | translation->addrext_mask);
+ KASSERT(dt_mask != 0, ("DMA addr_mask invalid: %#jx",
+ (uintmax_t)dt_mask));
+
+ /* (addr_mask|addrext_mask) is our maximum supported address */
+ lowaddr = MIN(dt_mask, BUS_SPACE_MAXADDR);
+
+ /* Do we need to to avoid crossing a DMA translation window boundary? */
+ if (translation->addr_mask < BUS_SPACE_MAXADDR) {
+ /* round down to nearest power of two */
+ boundary = translation->addr_mask & (~1ULL);
+ }
+
+ /* Create our DMA tag */
+ error = bus_dma_tag_create(parent_dmat,
+ 1, /* alignment */
+ boundary, lowaddr, highaddr,
+ NULL, NULL, /* filter, filterarg */
+ BUS_SPACE_MAXSIZE, 0, /* maxsize, nsegments */
+ BUS_SPACE_MAXSIZE, 0, /* maxsegsize, flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &translation_tag);
+ if (error) {
+ device_printf(dev, "failed to create bridge DMA tag: %d\n",
+ error);
+ return (error);
+ }
+
+ *dmat = translation_tag;
+ return (0);
+}
+
+/**
* Deallocate the given bridge resource structure and any associated resources.
*
* @param br Resource state to be deallocated.
@@ -571,31 +634,80 @@ bhndb_free_resources(struct bhndb_resources *br)
* On success, the caller assumes ownership of the allocated host resources,
* which must be freed via bhndb_release_host_resources().
*
- * @param dev The device to be used when allocating resources
- * (e.g. via bus_alloc_resources()).
+ * @param[out] resources On success, the allocated host resources.
+ * @param dev The bridge device.
+ * @param parent_dev The parent device from which host resources
+ * should be allocated (e.g. via
+ * bus_alloc_resources()).
* @param hwcfg The hardware configuration defining the host
* resources to be allocated
- * @param[out] resources On success, the allocated host resources.
*/
int
-bhndb_alloc_host_resources(device_t dev, const struct bhndb_hwcfg *hwcfg,
- struct bhndb_host_resources **resources)
+bhndb_alloc_host_resources(struct bhndb_host_resources **resources,
+ device_t dev, device_t parent_dev, const struct bhndb_hwcfg *hwcfg)
{
- struct bhndb_host_resources *hr;
- size_t nres;
- int error;
+ struct bhndb_host_resources *hr;
+ const struct bhnd_dma_translation *dt;
+ bus_dma_tag_t parent_dmat;
+ size_t nres, ndt;
+ int error;
+ parent_dmat = bus_get_dma_tag(parent_dev);
+
hr = malloc(sizeof(*hr), M_BHND, M_WAITOK);
- hr->owner = dev;
+ hr->owner = parent_dev;
hr->cfg = hwcfg;
hr->resource_specs = NULL;
hr->resources = NULL;
+ hr->dma_tags = NULL;
+ hr->num_dma_tags = 0;
/* Determine our bridge resource count from the hardware config. */
nres = 0;
for (size_t i = 0; hwcfg->resource_specs[i].type != -1; i++)
nres++;
+ /* Determine the total count and validate our DMA translation table. */
+ ndt = 0;
+ for (dt = hwcfg->dma_translations; dt != NULL &&
+ !BHND_DMA_IS_TRANSLATION_TABLE_END(dt); dt++)
+ {
+ /* Validate the defined translation */
+ if ((dt->base_addr & dt->addr_mask) != 0) {
+ device_printf(dev, "invalid DMA translation; base "
+ "address %#jx overlaps address mask %#jx",
+ (uintmax_t)dt->base_addr, (uintmax_t)dt->addr_mask);
+
+ error = EINVAL;
+ goto failed;
+ }
+
+ if ((dt->addrext_mask & dt->addr_mask) != 0) {
+ device_printf(dev, "invalid DMA translation; addrext "
+ "mask %#jx overlaps address mask %#jx",
+ (uintmax_t)dt->addrext_mask,
+ (uintmax_t)dt->addr_mask);
+
+ error = EINVAL;
+ goto failed;
+ }
+
+ /* Increment our entry count */
+ ndt++;
+ }
+
+ /* Allocate our DMA tags */
+ hr->dma_tags = malloc(sizeof(*hr->dma_tags) * ndt, M_BHND,
+ M_WAITOK|M_ZERO);
+ for (size_t i = 0; i < ndt; i++) {
+ error = bhndb_dma_tag_create(dev, parent_dmat,
+ &hwcfg->dma_translations[i], &hr->dma_tags[i]);
+ if (error)
+ goto failed;
+
+ hr->num_dma_tags++;
+ }
+
/* Allocate space for a non-const copy of our resource_spec
* table; this will be updated with the RIDs assigned by
* bus_alloc_resources. */
@@ -617,7 +729,7 @@ bhndb_alloc_host_resources(device_t dev, const struct
hr->resources);
if (error) {
device_printf(dev, "could not allocate bridge resources via "
- "%s: %d\n", device_get_nameunit(dev), error);
+ "%s: %d\n", device_get_nameunit(parent_dev), error);
goto failed;
}
@@ -631,6 +743,12 @@ failed:
if (hr->resources != NULL)
free(hr->resources, M_BHND);
+ for (size_t i = 0; i < hr->num_dma_tags; i++)
+ bus_dma_tag_destroy(hr->dma_tags[i]);
+
+ if (hr->dma_tags != NULL)
+ free(hr->dma_tags, M_BHND);
+
free(hr, M_BHND);
return (error);
@@ -646,8 +764,12 @@ bhndb_release_host_resources(struct bhndb_host_resourc
{
bus_release_resources(hr->owner, hr->resource_specs, hr->resources);
+ for (size_t i = 0; i < hr->num_dma_tags; i++)
+ bus_dma_tag_destroy(hr->dma_tags[i]);
+
free(hr->resources, M_BHND);
free(hr->resource_specs, M_BHND);
+ free(hr->dma_tags, M_BHND);
free(hr, M_BHND);
}
Modified: head/sys/dev/bhnd/bhndb/bhndbvar.h
==============================================================================
--- head/sys/dev/bhnd/bhndb/bhndbvar.h Tue Nov 21 23:15:20 2017 (r326079)
+++ head/sys/dev/bhnd/bhndb/bhndbvar.h Tue Nov 21 23:25:22 2017 (r326080)
@@ -90,9 +90,11 @@ struct bhndb_intr_isrc *bhndb_alloc_intr_isrc(device_
void bhndb_free_intr_isrc(
struct bhndb_intr_isrc *isrc);
-int bhndb_alloc_host_resources(device_t dev,
- const struct bhndb_hwcfg *hwcfg,
- struct bhndb_host_resources **resources);
+int bhndb_alloc_host_resources(
+ struct bhndb_host_resources **resources,
+ device_t dev, device_t parent_dev,
+ const struct bhndb_hwcfg *hwcfg);
+
void bhndb_release_host_resources(
struct bhndb_host_resources *resources);
struct resource *bhndb_host_resource_for_range(
@@ -161,6 +163,9 @@ struct bhndb_host_resources {
const struct bhndb_hwcfg *cfg; /**< bridge hardware configuration */
struct resource_spec *resource_specs; /**< resource specification table */
struct resource **resources; /**< allocated resource table */
+ bus_dma_tag_t *dma_tags; /**< DMA tags for all hwcfg DMA translations, or NULL
+ if DMA is not supported */
+ size_t num_dma_tags; /**< DMA tag count */
};
/**
Modified: head/sys/dev/bhnd/cores/pci/bhnd_pcireg.h
==============================================================================
--- head/sys/dev/bhnd/cores/pci/bhnd_pcireg.h Tue Nov 21 23:15:20 2017 (r326079)
+++ head/sys/dev/bhnd/cores/pci/bhnd_pcireg.h Tue Nov 21 23:25:22 2017 (r326080)
@@ -29,15 +29,15 @@
* PCI/PCIe-Gen1 DMA Constants
*/
-#define BHND_PCI_DMA32_TRANSLATION 0x40000000 /* Client Mode sb2pcitranslation2 (1 GB) */
-#define BHND_PCI_DMA32_SZ 0x40000000 /* Client Mode sb2pcitranslation2 size in bytes */
+#define BHND_PCI_DMA32_TRANSLATION 0x40000000 /**< PCI DMA32 address translation (sbtopci2) */
+#define BHND_PCI_DMA32_MASK BHND_PCI_SBTOPCI2_MASK /**< PCI DMA32 translation mask */
-#define BHND_PCIE_DMA32_TRANSLATION BHND_PCI_DMA32_TRANSLATION
-#define BHND_PCIE_DMA32_SZ BHND_PCI_DMA32_SZ
+#define BHND_PCIE_DMA32_TRANSLATION 0x80000000 /**< PCIe-Gen1 DMA32 address translation (sb2pcitranslation2) */
+#define BHND_PCIE_DMA32_MASK BHND_PCIE_SBTOPCI2_MASK /**< PCIe-Gen1 DMA32 translation mask */
-#define BHND_PCIE_DMA64_L32 0x00000000 /**< 64-bit client mode sb2pcitranslation2 (2 ZettaBytes, low 32 bits) */
-#define BHND_PCIE_DMA64_H32 0x80000000 /**< 64-bit client mode sb2pcitranslation2 (2 ZettaBytes, high 32 bits) */
-
+#define BHND_PCIE_DMA64_TRANSLATION _BHND_PCIE_DMA64(TRANSLATION) /**< PCIe-Gen1 DMA64 address translation (sb2pcitranslation2) */
+#define BHND_PCIE_DMA64_MASK _BHND_PCIE_DMA64(MASK) /**< PCIe-Gen1 DMA64 translation mask */
+#define _BHND_PCIE_DMA64(_x) ((uint64_t)BHND_PCIE_DMA32_ ## _x << 32)
/*
* PCI Core Registers
*/
Modified: head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2_reg.h
==============================================================================
--- head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2_reg.h Tue Nov 21 23:15:20 2017 (r326079)
+++ head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2_reg.h Tue Nov 21 23:25:22 2017 (r326080)
@@ -24,6 +24,17 @@
#ifndef _BHND_CORES_PCIE2_BHND_PCIE2_REG_H_
#define _BHND_CORES_PCIE2_BHND_PCIE2_REG_H_
+/*
+ * PCIe-Gen2 DMA Constants
+ */
+
+#define BHND_PCIE2_DMA64_TRANSLATION 0x8000000000000000 /**< PCIe-Gen2 DMA64 address translation */
+#define BHND_PCIE2_DMA64_MASK 0xc000000000000000 /**< PCIe-Gen2 DMA64 translation mask */
+
+/*
+ * PCIe-Gen2 Core Registers
+ */
+
#define BHND_PCIE2_CLK_CONTROL 0x000
#define BHND_PCIE2_RC_PM_CONTROL 0x004
Modified: head/sys/mips/broadcom/bhnd_nexus.c
==============================================================================
--- head/sys/mips/broadcom/bhnd_nexus.c Tue Nov 21 23:15:20 2017 (r326079)
+++ head/sys/mips/broadcom/bhnd_nexus.c Tue Nov 21 23:25:22 2017 (r326080)
@@ -55,6 +55,8 @@ __FBSDID("$FreeBSD$");
#include <dev/bhnd/bhndvar.h>
#include <dev/bhnd/bhnd_ids.h>
+#include <dev/bhnd/cores/chipc/chipcreg.h>
+
#include "bcm_machdep.h"
#include "bcm_mipsvar.h"
@@ -194,6 +196,44 @@ bhnd_nexus_unmap_intr(device_t dev, device_t child, rm
intr_unmap_irq(irq);
}
+/**
+ * Default bhnd_nexus implementation of BHND_BUS_GET_DMA_TRANSLATION().
+ */
+static int
+bhnd_nexus_get_dma_translation(device_t dev, device_t child,
+ u_int width, uint32_t flags, bus_dma_tag_t *dmat,
+ struct bhnd_dma_translation *translation)
+{
+ struct bcm_platform *bp = bcm_get_platform();
+
+ /* We don't (currently) support any flags */
+ if (flags != 0x0)
+ return (ENOENT);
+
+ KASSERT(width > 0 && width <= BHND_DMA_ADDR_64BIT,
+ ("invalid width %u", width));
+
+ if (width > BHND_DMA_ADDR_32BIT) {
+ /* Backplane must support 64-bit addressing */
+ if (!(bp->cc_caps & CHIPC_CAP_BKPLN64))
+ return (ENOENT);
+ }
+
+ /* No DMA address translation required */
+ if (dmat != NULL)
+ *dmat = bus_get_dma_tag(dev);
+
+ if (translation != NULL) {
+ *translation = (struct bhnd_dma_translation) {
+ .base_addr = 0x0,
+ .addr_mask = BHND_DMA_ADDR_BITMASK(width),
+ .addrext_mask = 0
+ };
+ }
+
+ return (0);
+}
+
static device_method_t bhnd_nexus_methods[] = {
/* bhnd interface */
DEVMETHOD(bhnd_bus_get_service_registry,bhnd_nexus_get_service_registry),
@@ -206,6 +246,7 @@ static device_method_t bhnd_nexus_methods[] = {
DEVMETHOD(bhnd_bus_is_hw_disabled, bhnd_nexus_is_hw_disabled),
DEVMETHOD(bhnd_bus_get_attach_type, bhnd_nexus_get_attach_type),
DEVMETHOD(bhnd_bus_get_chipid, bhnd_nexus_get_chipid),
+ DEVMETHOD(bhnd_bus_get_dma_translation, bhnd_nexus_get_dma_translation),
DEVMETHOD(bhnd_bus_get_intr_domain, bhnd_bus_generic_get_intr_domain),
DEVMETHOD(bhnd_bus_map_intr, bhnd_nexus_map_intr),
DEVMETHOD(bhnd_bus_unmap_intr, bhnd_nexus_unmap_intr),
More information about the svn-src-head
mailing list