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
This commit is contained in:
Landon J. Fuller 2017-11-21 23:25:22 +00:00
parent caeff9a3c2
commit 9ed453245b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=326080
12 changed files with 535 additions and 29 deletions

View File

@ -219,6 +219,94 @@ struct bhnd_core_info {
int unit; /**< bus-assigned core unit */
};
/**
* 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.
*
@ -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);
@ -842,6 +934,38 @@ 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));
}
/**
* Attempt to read the BHND board identification from the bhnd bus.
*

View File

@ -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)
@ -479,6 +480,41 @@ METHOD bhnd_attach_type get_attach_type {
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.
*

View File

@ -2104,6 +2104,27 @@ bhnd_bus_generic_get_chipid(device_t dev, device_t child)
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, \

View File

@ -2039,14 +2039,94 @@ bhndb_remap_intr(device_t dev, device_t child, u_int irq)
return (ENXIO);
}
/**
* 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),

View File

@ -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 */
};
/**

View File

@ -509,7 +509,7 @@ bhndb_pci_read_core_table(device_t dev, struct bhnd_chipid *chipid,
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 */

View File

@ -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_pcie = {
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
}
};

View File

@ -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_dev,
}
/* 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",
@ -493,6 +497,65 @@ bhndb_alloc_resources(device_t dev, device_t parent_dev,
return (NULL);
}
/**
* 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.
*
@ -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 bhndb_hwcfg *hwcfg,
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 @@ bhndb_alloc_host_resources(device_t dev, const struct bhndb_hwcfg *hwcfg,
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_resources *hr)
{
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);
}

View File

@ -90,9 +90,11 @@ struct bhndb_intr_isrc *bhndb_alloc_intr_isrc(device_t owner, int rid,
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 */
};
/**

View File

@ -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_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_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_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
*/

View File

@ -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

View File

@ -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, rman_res_t irq)
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),