Index: sys/dev/bhnd/bhnd.h =================================================================== --- sys/dev/bhnd/bhnd.h +++ sys/dev/bhnd/bhnd.h @@ -219,6 +219,94 @@ 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 @@ 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 @@ 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. * Index: sys/dev/bhnd/bhnd_bus_if.m =================================================================== --- sys/dev/bhnd/bhnd_bus_if.m +++ sys/dev/bhnd/bhnd_bus_if.m @@ -46,6 +46,7 @@ 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 @@ { 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 @@ 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. * Index: sys/dev/bhnd/bhnd_subr.c =================================================================== --- sys/dev/bhnd/bhnd_subr.c +++ sys/dev/bhnd/bhnd_subr.c @@ -2104,6 +2104,27 @@ 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, \ Index: sys/dev/bhnd/bhndb/bhndb.h =================================================================== --- sys/dev/bhnd/bhndb/bhndb.h +++ sys/dev/bhnd/bhndb/bhndb.h @@ -107,12 +107,13 @@ /** * 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 */ }; /** Index: sys/dev/bhnd/bhndb/bhndb.c =================================================================== --- sys/dev/bhnd/bhndb/bhndb.c +++ sys/dev/bhnd/bhndb/bhndb.c @@ -2039,14 +2039,94 @@ 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 @@ 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), Index: sys/dev/bhnd/bhndb/bhndb_pci.c =================================================================== --- sys/dev/bhnd/bhndb/bhndb_pci.c +++ sys/dev/bhnd/bhndb/bhndb_pci.c @@ -509,7 +509,7 @@ 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 */ Index: sys/dev/bhnd/bhndb/bhndb_pci_hwdata.c =================================================================== --- sys/dev/bhnd/bhndb/bhndb_pci_hwdata.c +++ sys/dev/bhnd/bhndb/bhndb_pci_hwdata.c @@ -45,6 +45,9 @@ #include #include +#include +#include + #include "bhndbvar.h" #include "bhndb_pcireg.h" @@ -100,6 +103,9 @@ }, BHNDB_REGWIN_TABLE_END }, + + /* DMA unsupported under generic configuration */ + .dma_translations = NULL, }; @@ -147,6 +153,9 @@ BHNDB_REGWIN_TABLE_END }, + + /* DMA unsupported under generic configuration */ + .dma_translations = NULL, }; /** @@ -319,6 +328,15 @@ }, 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 @@ 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 @@ 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 @@ 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 @@ 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 + } }; Index: sys/dev/bhnd/bhndb/bhndb_subr.c =================================================================== --- sys/dev/bhnd/bhndb/bhndb_subr.c +++ sys/dev/bhnd/bhndb/bhndb_subr.c @@ -41,6 +41,10 @@ #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 @@ } /* 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 @@ 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 @@ * 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 @@ 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 @@ 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 @@ { 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); } Index: sys/dev/bhnd/bhndb/bhndbvar.h =================================================================== --- sys/dev/bhnd/bhndb/bhndbvar.h +++ sys/dev/bhnd/bhndb/bhndbvar.h @@ -90,9 +90,11 @@ 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 @@ 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 */ }; /** Index: sys/dev/bhnd/cores/pci/bhnd_pcireg.h =================================================================== --- sys/dev/bhnd/cores/pci/bhnd_pcireg.h +++ sys/dev/bhnd/cores/pci/bhnd_pcireg.h @@ -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 */ Index: sys/dev/bhnd/cores/pcie2/bhnd_pcie2_reg.h =================================================================== --- sys/dev/bhnd/cores/pcie2/bhnd_pcie2_reg.h +++ sys/dev/bhnd/cores/pcie2/bhnd_pcie2_reg.h @@ -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 Index: sys/mips/broadcom/bhnd_nexus.c =================================================================== --- sys/mips/broadcom/bhnd_nexus.c +++ sys/mips/broadcom/bhnd_nexus.c @@ -55,6 +55,8 @@ #include #include +#include + #include "bcm_machdep.h" #include "bcm_mipsvar.h" @@ -194,6 +196,44 @@ 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 @@ 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),