summaryrefslogtreecommitdiff
path: root/usr/src/uts/i86pc/io/rootnex.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/i86pc/io/rootnex.c')
-rw-r--r--usr/src/uts/i86pc/io/rootnex.c129
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