diff options
Diffstat (limited to 'usr/src/uts/i86pc/io/rootnex.c')
| -rw-r--r-- | usr/src/uts/i86pc/io/rootnex.c | 129 |
1 files changed, 66 insertions, 63 deletions
diff --git a/usr/src/uts/i86pc/io/rootnex.c b/usr/src/uts/i86pc/io/rootnex.c index 889c2f3300..54f0b0f69e 100644 --- a/usr/src/uts/i86pc/io/rootnex.c +++ b/usr/src/uts/i86pc/io/rootnex.c @@ -25,6 +25,7 @@ * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2011 Bayard G. Bell. All rights reserved. * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved. + * Copyright 2017 Joyent, Inc. */ /* @@ -818,9 +819,9 @@ static int rootnex_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, off_t offset, off_t len, caddr_t *vaddrp) { - struct regspec *rp, tmp_reg; + struct regspec *orp; + struct regspec64 rp = { 0 }; ddi_map_req_t mr = *mp; /* Get private copy of request */ - int error; mp = &mr; @@ -857,8 +858,8 @@ rootnex_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, off_t offset, "rootnex_map: Out of range rnumber <%d>, device <%s>"; #endif /* DDI_MAP_DEBUG */ - rp = i_ddi_rnumber_to_regspec(rdip, rnumber); - if (rp == NULL) { + orp = i_ddi_rnumber_to_regspec(rdip, rnumber); + if (orp == NULL) { #ifdef DDI_MAP_DEBUG cmn_err(CE_WARN, out_of_range, rnumber, ddi_get_name(rdip)); @@ -866,12 +867,34 @@ rootnex_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, off_t offset, return (DDI_ME_RNUMBER_RANGE); } - /* - * Convert the given ddi_map_req_t from rnumber to regspec... - */ - + rp.regspec_bustype = orp->regspec_bustype; + rp.regspec_addr = orp->regspec_addr; + rp.regspec_size = orp->regspec_size; mp->map_type = DDI_MT_REGSPEC; - mp->map_obj.rp = rp; + mp->map_flags |= DDI_MF_EXT_REGSPEC; + mp->map_obj.rp = (struct regspec *)&rp; + } + + /* + * Ensure that we are always using a 64-bit regspec regardless of what + * was passed into us. If the child driver is using a 64-bit regspec, + * then we need to make sure that we copy this to the local regspec64, + * rp. + */ + if (!(mp->map_flags & DDI_MF_EXT_REGSPEC)) { + orp = mp->map_obj.rp; + + rp.regspec_bustype = orp->regspec_bustype; + rp.regspec_addr = orp->regspec_addr; + rp.regspec_size = orp->regspec_size; + + mp->map_obj.rp = (struct regspec *)&rp; + mp->map_flags |= DDI_MF_EXT_REGSPEC; + } else if (mp->map_type != DDI_MT_RNUMBER) { + struct regspec64 *rp64; + rp64 = (struct regspec64 *)mp->map_obj.rp; + rp = *rp64; + mp->map_obj.rp = (struct regspec *)&rp; } /* @@ -880,13 +903,10 @@ rootnex_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, off_t offset, * XXX: (regardless of what's in the parent's range?) */ - tmp_reg = *(mp->map_obj.rp); /* Preserve underlying data */ - rp = mp->map_obj.rp = &tmp_reg; /* Use tmp_reg in request */ - #ifdef DDI_MAP_DEBUG cmn_err(CE_CONT, "rootnex: <%s,%s> <0x%x, 0x%x, 0x%d> offset %d len %d " "handle 0x%x\n", ddi_get_name(dip), ddi_get_name(rdip), - rp->regspec_bustype, rp->regspec_addr, rp->regspec_size, offset, + rp.regspec_bustype, rp.regspec_addr, rp.regspec_size, offset, len, mp->map_handlep); #endif /* DDI_MAP_DEBUG */ @@ -898,50 +918,44 @@ rootnex_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, off_t offset, * <bustype>1, addr=0, len=x>: x86-compatibility i/o */ - if (rp->regspec_bustype > 1 && rp->regspec_addr != 0) { + if (rp.regspec_bustype > 1 && rp.regspec_addr != 0) { cmn_err(CE_WARN, "<%s,%s> invalid register spec" - " <0x%x, 0x%x, 0x%x>", ddi_get_name(dip), - ddi_get_name(rdip), rp->regspec_bustype, - rp->regspec_addr, rp->regspec_size); + " <0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRIx64 ">", + ddi_get_name(dip), ddi_get_name(rdip), rp.regspec_bustype, + rp.regspec_addr, rp.regspec_size); return (DDI_ME_INVAL); } - if (rp->regspec_bustype > 1 && rp->regspec_addr == 0) { + if (rp.regspec_bustype > 1 && rp.regspec_addr == 0) { /* * compatibility i/o mapping */ - rp->regspec_bustype += (uint_t)offset; + rp.regspec_bustype += offset; } else { /* * Normal memory or i/o mapping */ - rp->regspec_addr += (uint_t)offset; + rp.regspec_addr += offset; } if (len != 0) - rp->regspec_size = (uint_t)len; + rp.regspec_size = len; #ifdef DDI_MAP_DEBUG - cmn_err(CE_CONT, " <%s,%s> <0x%x, 0x%x, 0x%d> offset %d " - "len %d handle 0x%x\n", ddi_get_name(dip), ddi_get_name(rdip), - rp->regspec_bustype, rp->regspec_addr, rp->regspec_size, - offset, len, mp->map_handlep); + cmn_err(CE_CONT, " <%s,%s> <0x%" PRIx64 ", 0x%" PRIx64 + ", 0x%" PRId64 "> offset %d len %d handle 0x%x\n", + ddi_get_name(dip), ddi_get_name(rdip), rp.regspec_bustype, + rp.regspec_addr, rp.regspec_size, offset, len, mp->map_handlep); #endif /* DDI_MAP_DEBUG */ + /* - * Apply any parent ranges at this level, if applicable. - * (This is where nexus specific regspec translation takes place. - * Use of this function is implicit agreement that translation is - * provided via ddi_apply_range.) + * The x86 root nexus does not have any notion of valid ranges of + * addresses. Its children have valid ranges, but because there are none + * for the nexus, we don't need to call i_ddi_apply_range(). Verify + * that is the case. */ - -#ifdef DDI_MAP_DEBUG - ddi_map_debug("applying range of parent <%s> to child <%s>...\n", - ddi_get_name(dip), ddi_get_name(rdip)); -#endif /* DDI_MAP_DEBUG */ - - if ((error = i_ddi_apply_range(dip, rdip, mp->map_obj.rp)) != 0) - return (error); + ASSERT0(sparc_pd_getnrng(dip)); switch (mp->map_op) { case DDI_MO_MAP_LOCKED: @@ -1022,23 +1036,20 @@ rootnex_map_fault(dev_info_t *dip, dev_info_t *rdip, struct hat *hat, } -/* - * rootnex_map_regspec() - * we don't support mapping of I/O cards above 4Gb - */ static int rootnex_map_regspec(ddi_map_req_t *mp, caddr_t *vaddrp) { rootnex_addr_t rbase; void *cvaddr; - uint_t npages, pgoffset; - struct regspec *rp; + uint64_t npages, pgoffset; + struct regspec64 *rp; ddi_acc_hdl_t *hp; ddi_acc_impl_t *ap; uint_t hat_acc_flags; paddr_t pbase; - rp = mp->map_obj.rp; + ASSERT(mp->map_flags & DDI_MF_EXT_REGSPEC); + rp = (struct regspec64 *)mp->map_obj.rp; hp = mp->map_handlep; #ifdef DDI_MAP_DEBUG @@ -1058,8 +1069,8 @@ rootnex_map_regspec(ddi_map_req_t *mp, caddr_t *vaddrp) if (rp->regspec_bustype > 1 && rp->regspec_addr != 0) { cmn_err(CE_WARN, "rootnex: invalid register spec" - " <0x%x, 0x%x, 0x%x>", rp->regspec_bustype, - rp->regspec_addr, rp->regspec_size); + " <0x%" PRIx64 ", 0x%" PRIx64", 0x%" PRIx64">", + rp->regspec_bustype, rp->regspec_addr, rp->regspec_size); return (DDI_FAILURE); } @@ -1208,21 +1219,18 @@ rootnex_map_regspec(ddi_map_req_t *mp, caddr_t *vaddrp) } -/* - * rootnex_unmap_regspec() - * - */ static int rootnex_unmap_regspec(ddi_map_req_t *mp, caddr_t *vaddrp) { caddr_t addr = (caddr_t)*vaddrp; - uint_t npages, pgoffset; - struct regspec *rp; + uint64_t npages, pgoffset; + struct regspec64 *rp; if (mp->map_flags & DDI_MF_DEVICE_MAPPING) return (0); - rp = mp->map_obj.rp; + ASSERT(mp->map_flags & DDI_MF_EXT_REGSPEC); + rp = (struct regspec64 *)mp->map_obj.rp; if (rp->regspec_size == 0) { #ifdef DDI_MAP_DEBUG @@ -1263,21 +1271,16 @@ rootnex_unmap_regspec(ddi_map_req_t *mp, caddr_t *vaddrp) return (DDI_SUCCESS); } - -/* - * rootnex_map_handle() - * - */ static int rootnex_map_handle(ddi_map_req_t *mp) { rootnex_addr_t rbase; ddi_acc_hdl_t *hp; - uint_t pgoffset; - struct regspec *rp; + uint64_t pgoffset; + struct regspec64 *rp; paddr_t pbase; - rp = mp->map_obj.rp; + rp = (struct regspec64 *)mp->map_obj.rp; #ifdef DDI_MAP_DEBUG ddi_map_debug( @@ -2171,7 +2174,7 @@ out: */ if ((sinfo->si_copybuf_req == 0) && (sinfo->si_sgl_size <= (unsigned)attr->dma_attr_sgllen) && - (dmao->dmao_size < dma->dp_maxxfer)) { + (dmao->dmao_size <= dma->dp_maxxfer)) { fast: /* * If the driver supports FMA, insert the handle in the FMA DMA @@ -2336,7 +2339,7 @@ rootnex_coredma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, rootnex_teardown_windows(dma); #if defined(__amd64) && !defined(__xpv) - if (IOMMU_USED(rdip)) + if (IOMMU_USED(rdip) && dma->dp_dvma_used) (void) iommulib_nexdma_unmapobject(dip, rdip, handle, &dma->dp_dvma); #endif |
