summaryrefslogtreecommitdiff
path: root/usr
diff options
context:
space:
mode:
authorRobert Mustacchi <rm@joyent.com>2016-12-15 00:21:15 +0000
committerRobert Mustacchi <rm@joyent.com>2016-12-23 19:13:56 +0000
commitde15e5b3cf5cbe29cd88bc9618e0514ecadfac5a (patch)
treed7a8958916f1253d9a5f2f8c63b516879f56a099 /usr
parent696b52570287ab2055ae727bddf6657c667fedbf (diff)
downloadillumos-joyent-de15e5b3cf5cbe29cd88bc9618e0514ecadfac5a.tar.gz
OS-1629 PCI addresses with physaddr > 0xffffffff can't be mapped in
OS-5860 pci/npe DDI_CTLOPS_REGSIZE should be 64-bit aware OS-5861 want OFF_MAX in the kernel OS-5859 unsupported 64-bit prefetch memory on pci-pci bridge Reviewed by: Patrick Mooney <patrick.mooney@joyent.com> Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com> Approved by: Jerry Jelinek <jerry.jelinek@joyent.com>
Diffstat (limited to 'usr')
-rw-r--r--usr/src/uts/common/sys/ddi_impldefs.h12
-rw-r--r--usr/src/uts/common/sys/ddimapreq.h18
-rw-r--r--usr/src/uts/common/sys/pci.h7
-rw-r--r--usr/src/uts/common/sys/types.h9
-rw-r--r--usr/src/uts/i86pc/io/pci/pci.c118
-rw-r--r--usr/src/uts/i86pc/io/pciex/npe.c102
-rw-r--r--usr/src/uts/i86pc/io/rootnex.c125
-rw-r--r--usr/src/uts/intel/io/pci/pci_boot.c99
-rw-r--r--usr/src/uts/intel/io/pci/pci_resource.c16
9 files changed, 294 insertions, 212 deletions
diff --git a/usr/src/uts/common/sys/ddi_impldefs.h b/usr/src/uts/common/sys/ddi_impldefs.h
index bfe2d855b6..4c02693dee 100644
--- a/usr/src/uts/common/sys/ddi_impldefs.h
+++ b/usr/src/uts/common/sys/ddi_impldefs.h
@@ -21,6 +21,7 @@
/*
* Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
+ * Copyright 2016 Joyent, Inc.
*/
#ifndef _SYS_DDI_IMPLDEFS_H
@@ -634,6 +635,17 @@ struct regspec {
};
/*
+ * This is a version of the above structure that works for 64-bit mappings and
+ * doesn't rely on overloading of fields as is done on SPARC. Eventually the
+ * struct regspec should be replaced with this.
+ */
+struct regspec64 {
+ uint64_t regspec_bustype; /* cookie for bus type it's on */
+ uint64_t regspec_addr; /* address of reg relative to bus */
+ uint64_t regspec_size; /* size of this register set */
+};
+
+/*
* This structure represents one piece of nexus bus space.
* It is used in an array for nexi with multiple bus spaces
* to define the childs offsets in the parents bus space.
diff --git a/usr/src/uts/common/sys/ddimapreq.h b/usr/src/uts/common/sys/ddimapreq.h
index c77b44e822..90dd9576f6 100644
--- a/usr/src/uts/common/sys/ddimapreq.h
+++ b/usr/src/uts/common/sys/ddimapreq.h
@@ -21,13 +21,12 @@
*/
/*
* Copyright (c) 1991-1994 Sun Microsystems, Inc.
+ * Copyright 2016 Joyent, Inc.
*/
#ifndef _SYS_DDIMAPREQ_H
#define _SYS_DDIMAPREQ_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/mman.h>
#include <sys/dditypes.h>
@@ -76,7 +75,7 @@ typedef struct {
ddi_map_op_t map_op;
ddi_map_type_t map_type;
ddi_map_obj_t map_obj;
- int map_flags; /* See below... */
+ uint_t map_flags; /* See below... */
int map_prot; /* Prot bits (see sys/mman.h) */
ddi_acc_hdl_t *map_handlep;
int map_vers;
@@ -102,6 +101,19 @@ typedef struct {
#define DDI_MF_KERNEL_MAPPING 0x2
#define DDI_MF_DEVICE_MAPPING 0x4
+/*
+ * The upper bits of map_flags are reserved for platform-specific flags. These
+ * start with the highest bit and then work their way down. Currently only one
+ * bit is used, and only on x86.
+ */
+ /*
+ * Indicates that there is an extended register
+ * specification (fully 64-bit aware) being used. This
+ * should only be used by children of the x86 root nexus
+ * driver.
+ */
+#define DDI_MF_EXT_REGSPEC 0x80000000
+
#endif /* _KERNEL */
/*
diff --git a/usr/src/uts/common/sys/pci.h b/usr/src/uts/common/sys/pci.h
index b069cb138a..de0cb3e808 100644
--- a/usr/src/uts/common/sys/pci.h
+++ b/usr/src/uts/common/sys/pci.h
@@ -21,6 +21,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2016 Joyent, Inc.
*/
#ifndef _SYS_PCI_H
@@ -105,7 +106,13 @@ extern "C" {
#define PCI_BCNF_BCNTRL_B2B_ENAB 0x0080
#define PCI_BCNF_IO_MASK 0xf0
+#define PCI_BCNF_IO_SHIFT 8
#define PCI_BCNF_MEM_MASK 0xfff0
+#define PCI_BCNF_MEM_SHIFT 16
+#define PCI_BCNF_ADDR_MASK 0x000f
+
+#define PCI_BCNF_IO_32BIT 0x01
+#define PCI_BCNF_PF_MEM_64BIT 0x01
/*
* Header type 2 (Cardbus) offsets
diff --git a/usr/src/uts/common/sys/types.h b/usr/src/uts/common/sys/types.h
index 06a0443b0d..3444f0858e 100644
--- a/usr/src/uts/common/sys/types.h
+++ b/usr/src/uts/common/sys/types.h
@@ -27,6 +27,7 @@
* Use is subject to license terms.
*
* Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2016 Joyent, Inc.
*/
#ifndef _SYS_TYPES_H
@@ -589,6 +590,14 @@ typedef unsigned long ulong;
#define ULLONG_MAX 18446744073709551615ULL
/* max of "unsigned long long int" */
+#if defined(_LP64) || _FILE_OFFSET_BITS == 32
+#define OFF_MIN LONG_MIN
+#define OFF_MAX LONG_MAX
+#elif _FILE_OFFSET_BITS == 64
+#define OFF_MIN LLONG_MIN
+#define OFF_MAX LLONG_MAX
+#endif /* _LP64 || _FILE_OFFSET_BITS == 32 */
+
#endif /* defined(_KERNEL) */
#define P_MYPID ((pid_t)0)
diff --git a/usr/src/uts/i86pc/io/pci/pci.c b/usr/src/uts/i86pc/io/pci/pci.c
index 122906945d..c974545e79 100644
--- a/usr/src/uts/i86pc/io/pci/pci.c
+++ b/usr/src/uts/i86pc/io/pci/pci.c
@@ -24,6 +24,7 @@
*/
/*
* Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
+ * Copyright 2016 Joyent, Inc.
*/
/*
@@ -330,16 +331,17 @@ pci_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
static int
pci_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
- off_t offset, off_t len, caddr_t *vaddrp)
+ off_t offset, off_t len, caddr_t *vaddrp)
{
- struct regspec reg;
+ struct regspec64 reg;
ddi_map_req_t mr;
ddi_acc_hdl_t *hp;
ddi_acc_impl_t *hdlp;
pci_regspec_t pci_reg;
pci_regspec_t *pci_rp;
int rnumber;
- int length;
+ uint64_t pci_rlength;
+ uint_t nelems;
pci_acc_cfblk_t *cfp;
int space;
pci_state_t *pcip;
@@ -378,15 +380,15 @@ pci_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
* make sure that everything is okay.
*/
if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip,
- DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
- (uint_t *)&length) != DDI_PROP_SUCCESS)
+ DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, &nelems) !=
+ DDI_PROP_SUCCESS)
return (DDI_FAILURE);
/*
* validate the register number.
*/
- length /= (sizeof (pci_regspec_t) / sizeof (int));
- if (rnumber >= length) {
+ nelems /= (sizeof (pci_regspec_t) / sizeof (int));
+ if (rnumber >= nelems) {
ddi_prop_free(pci_rp);
return (DDI_FAILURE);
}
@@ -416,14 +418,6 @@ pci_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
* check for unmap and unlock of address space
*/
if ((mp->map_op == DDI_MO_UNMAP) || (mp->map_op == DDI_MO_UNLOCK)) {
- /*
- * Adjust offset and length
- * A non-zero length means override the one in the regspec.
- */
- pci_rp->pci_phys_low += (uint_t)offset;
- if (len != 0)
- pci_rp->pci_size_low = len;
-
switch (space) {
case PCI_ADDR_CONFIG:
/* No work required on unmap of Config space */
@@ -434,13 +428,6 @@ pci_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
break;
case PCI_ADDR_MEM64:
- /*
- * MEM64 requires special treatment on map, to check
- * that the device is below 4G. On unmap, however,
- * we can assume that everything is OK... the map
- * must have succeeded.
- */
- /* FALLTHROUGH */
case PCI_ADDR_MEM32:
reg.regspec_bustype = 0;
break;
@@ -448,10 +435,24 @@ pci_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
default:
return (DDI_FAILURE);
}
- reg.regspec_addr = pci_rp->pci_phys_low;
- reg.regspec_size = pci_rp->pci_size_low;
- mp->map_obj.rp = &reg;
+ reg.regspec_addr = (uint64_t)pci_rp->pci_phys_mid << 32 |
+ (uint64_t)pci_rp->pci_phys_low;
+ reg.regspec_size = (uint64_t)pci_rp->pci_size_hi << 32 |
+ (uint64_t)pci_rp->pci_size_low;
+
+ /*
+ * Adjust offset and length
+ * A non-zero length means override the one in the regspec.
+ */
+ if (reg.regspec_addr + offset < MAX(reg.regspec_addr, offset))
+ return (DDI_FAILURE);
+ reg.regspec_addr += offset;
+ if (len != 0)
+ reg.regspec_size = len;
+
+ mp->map_obj.rp = (struct regspec *)&reg;
+ mp->map_flags |= DDI_MF_EXT_REGSPEC;
return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp));
}
@@ -486,21 +487,14 @@ pci_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
/*
* range check
*/
- if ((offset >= pci_rp->pci_size_low) ||
- (len > pci_rp->pci_size_low) ||
- (offset + len > pci_rp->pci_size_low)) {
+ pci_rlength = (uint64_t)pci_rp->pci_size_low |
+ (uint64_t)pci_rp->pci_size_hi << 32;
+ if ((offset >= pci_rlength) || (len > pci_rlength) ||
+ (offset + len > pci_rlength) || (offset + len < MAX(offset, len))) {
return (DDI_FAILURE);
}
/*
- * Adjust offset and length
- * A non-zero length means override the one in the regspec.
- */
- pci_rp->pci_phys_low += (uint_t)offset;
- if (len != 0)
- pci_rp->pci_size_low = len;
-
- /*
* convert the pci regsec into the generic regspec used by the
* parent root nexus driver.
*/
@@ -509,27 +503,29 @@ pci_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
reg.regspec_bustype = 1;
break;
case PCI_ADDR_MEM64:
- /*
- * We can't handle 64-bit devices that are mapped above
- * 4G or that are larger than 4G.
- */
- if (pci_rp->pci_phys_mid != 0 ||
- pci_rp->pci_size_hi != 0)
- return (DDI_FAILURE);
- /*
- * Other than that, we can treat them as 32-bit mappings
- */
- /* FALLTHROUGH */
case PCI_ADDR_MEM32:
reg.regspec_bustype = 0;
break;
default:
return (DDI_FAILURE);
}
- reg.regspec_addr = pci_rp->pci_phys_low;
- reg.regspec_size = pci_rp->pci_size_low;
- mp->map_obj.rp = &reg;
+ reg.regspec_addr = (uint64_t)pci_rp->pci_phys_mid << 32 |
+ (uint64_t)pci_rp->pci_phys_low;
+ reg.regspec_size = pci_rlength;
+
+ /*
+ * Adjust offset and length
+ * A non-zero length means override the one in the regspec.
+ */
+ if (reg.regspec_addr + offset < MAX(reg.regspec_addr, offset))
+ return (DDI_FAILURE);
+ reg.regspec_addr += offset;
+ if (len != 0)
+ reg.regspec_size = len;
+
+ mp->map_obj.rp = (struct regspec *)&reg;
+ mp->map_flags |= DDI_MF_EXT_REGSPEC;
return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp));
}
@@ -537,11 +533,10 @@ pci_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
/*ARGSUSED*/
static int
pci_ctlops(dev_info_t *dip, dev_info_t *rdip,
- ddi_ctl_enum_t ctlop, void *arg, void *result)
+ ddi_ctl_enum_t ctlop, void *arg, void *result)
{
pci_regspec_t *drv_regp;
uint_t reglen;
- int rn;
int totreg;
pci_state_t *pcip;
struct attachspec *asp;
@@ -582,12 +577,27 @@ pci_ctlops(dev_info_t *dip, dev_info_t *rdip,
if (ctlop == DDI_CTLOPS_NREGS)
*(int *)result = totreg;
else if (ctlop == DDI_CTLOPS_REGSIZE) {
+ uint64_t val;
+ int rn;
+
rn = *(int *)arg;
if (rn >= totreg) {
ddi_prop_free(drv_regp);
return (DDI_FAILURE);
}
- *(off_t *)result = drv_regp[rn].pci_size_low;
+ val = drv_regp[rn].pci_size_low |
+ (uint64_t)drv_regp[rn].pci_size_hi << 32;
+ if (val > OFF_MAX) {
+ int ce = CE_NOTE;
+#ifdef DEBUG
+ ce = CE_WARN;
+#endif
+ dev_err(rdip, ce, "failed to get register "
+ "size, value larger than OFF_MAX: 0x%"
+ PRIx64 "\n", val);
+ return (DDI_FAILURE);
+ }
+ *(off_t *)result = (off_t)val;
}
ddi_prop_free(drv_regp);
@@ -812,7 +822,7 @@ pci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
static int
pci_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
- int flags, char *name, caddr_t valuep, int *lengthp)
+ int flags, char *name, caddr_t valuep, int *lengthp)
{
return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip, prop_op, flags,
name, valuep, lengthp));
diff --git a/usr/src/uts/i86pc/io/pciex/npe.c b/usr/src/uts/i86pc/io/pciex/npe.c
index a0728cb7e2..4ef393ddb0 100644
--- a/usr/src/uts/i86pc/io/pciex/npe.c
+++ b/usr/src/uts/i86pc/io/pciex/npe.c
@@ -26,6 +26,7 @@
/*
* Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
+ * Copyright 2016 Joyent, Inc.
*/
/*
@@ -414,18 +415,18 @@ npe_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
off_t offset, off_t len, caddr_t *vaddrp)
{
int rnumber;
- int length;
int space;
ddi_acc_impl_t *ap;
ddi_acc_hdl_t *hp;
ddi_map_req_t mr;
pci_regspec_t pci_reg;
pci_regspec_t *pci_rp;
- struct regspec reg;
+ struct regspec64 reg;
pci_acc_cfblk_t *cfp;
int retval;
int64_t *ecfginfo;
uint_t nelem;
+ uint64_t pci_rlength;
mr = *mp; /* Get private copy of request */
mp = &mr;
@@ -452,15 +453,15 @@ npe_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
* make sure that everything is okay.
*/
if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip,
- DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
- (uint_t *)&length) != DDI_PROP_SUCCESS)
+ DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, &nelem) !=
+ DDI_PROP_SUCCESS)
return (DDI_FAILURE);
/*
* validate the register number.
*/
- length /= (sizeof (pci_regspec_t) / sizeof (int));
- if (rnumber >= length) {
+ nelem /= (sizeof (pci_regspec_t) / sizeof (int));
+ if (rnumber >= nelem) {
ddi_prop_free(pci_rp);
return (DDI_FAILURE);
}
@@ -517,13 +518,6 @@ npe_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
/* FALLTHROUGH */
case PCI_ADDR_MEM64:
- /*
- * MEM64 requires special treatment on map, to check
- * that the device is below 4G. On unmap, however,
- * we can assume that everything is OK... the map
- * must have succeeded.
- */
- /* FALLTHROUGH */
case PCI_ADDR_MEM32:
reg.regspec_bustype = 0;
break;
@@ -532,18 +526,23 @@ npe_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
return (DDI_FAILURE);
}
+ reg.regspec_addr = (uint64_t)pci_rp->pci_phys_mid << 32 |
+ (uint64_t)pci_rp->pci_phys_low;
+ reg.regspec_size = (uint64_t)pci_rp->pci_size_hi << 32 |
+ (uint64_t)pci_rp->pci_size_low;
+
/*
* Adjust offset and length
* A non-zero length means override the one in the regspec.
*/
- pci_rp->pci_phys_low += (uint_t)offset;
+ if (reg.regspec_addr + offset < MAX(reg.regspec_addr, offset))
+ return (DDI_FAILURE);
+ reg.regspec_addr += offset;
if (len != 0)
- pci_rp->pci_size_low = len;
-
- reg.regspec_addr = pci_rp->pci_phys_low;
- reg.regspec_size = pci_rp->pci_size_low;
+ reg.regspec_size = len;
- mp->map_obj.rp = &reg;
+ mp->map_obj.rp = (struct regspec *)&reg;
+ mp->map_flags |= DDI_MF_EXT_REGSPEC;
retval = ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp);
if (DDI_FM_ACC_ERR_CAP(ddi_fm_capable(rdip)) &&
mp->map_handlep->ah_acc.devacc_attr_access !=
@@ -624,21 +623,15 @@ npe_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
}
}
- length = pci_rp->pci_size_low;
-
/*
* range check
*/
- if ((offset >= length) || (len > length) || (offset + len > length))
+ pci_rlength = (uint64_t)pci_rp->pci_size_low |
+ (uint64_t)pci_rp->pci_size_hi << 32;
+ if ((offset >= pci_rlength) || (len > pci_rlength) ||
+ (offset + len > pci_rlength) || (offset + len < MAX(offset, len))) {
return (DDI_FAILURE);
-
- /*
- * Adjust offset and length
- * A non-zero length means override the one in the regspec.
- */
- pci_rp->pci_phys_low += (uint_t)offset;
- if (len != 0)
- pci_rp->pci_size_low = len;
+ }
/*
* convert the pci regsec into the generic regspec used by the
@@ -650,16 +643,6 @@ npe_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
break;
case PCI_ADDR_CONFIG:
case PCI_ADDR_MEM64:
- /*
- * We can't handle 64-bit devices that are mapped above
- * 4G or that are larger than 4G.
- */
- if (pci_rp->pci_phys_mid != 0 || pci_rp->pci_size_hi != 0)
- return (DDI_FAILURE);
- /*
- * Other than that, we can treat them as 32-bit mappings
- */
- /* FALLTHROUGH */
case PCI_ADDR_MEM32:
reg.regspec_bustype = 0;
break;
@@ -667,10 +650,23 @@ npe_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
return (DDI_FAILURE);
}
- reg.regspec_addr = pci_rp->pci_phys_low;
- reg.regspec_size = pci_rp->pci_size_low;
+ reg.regspec_addr = (uint64_t)pci_rp->pci_phys_mid << 32 |
+ (uint64_t)pci_rp->pci_phys_low;
+ reg.regspec_size = pci_rlength;
- mp->map_obj.rp = &reg;
+ /*
+ * Adjust offset and length
+ * A non-zero length means override the one in the regspec.
+ */
+ if (reg.regspec_addr + offset < MAX(reg.regspec_addr, offset))
+ return (DDI_FAILURE);
+ reg.regspec_addr += offset;
+ if (len != 0)
+ reg.regspec_size = len;
+
+
+ mp->map_obj.rp = (struct regspec *)&reg;
+ mp->map_flags |= DDI_MF_EXT_REGSPEC;
retval = ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp);
if (retval == DDI_SUCCESS) {
/*
@@ -705,9 +701,8 @@ npe_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
/*ARGSUSED*/
static int
npe_ctlops(dev_info_t *dip, dev_info_t *rdip,
- ddi_ctl_enum_t ctlop, void *arg, void *result)
+ ddi_ctl_enum_t ctlop, void *arg, void *result)
{
- int rn;
int totreg;
uint_t reglen;
pci_regspec_t *drv_regp;
@@ -750,12 +745,27 @@ npe_ctlops(dev_info_t *dip, dev_info_t *rdip,
if (ctlop == DDI_CTLOPS_NREGS)
*(int *)result = totreg;
else if (ctlop == DDI_CTLOPS_REGSIZE) {
+ uint64_t val;
+ int rn;
+
rn = *(int *)arg;
if (rn >= totreg) {
ddi_prop_free(drv_regp);
return (DDI_FAILURE);
}
- *(off_t *)result = drv_regp[rn].pci_size_low;
+ val = drv_regp[rn].pci_size_low |
+ (uint64_t)drv_regp[rn].pci_size_hi << 32;
+ if (val > OFF_MAX) {
+ int ce = CE_NOTE;
+#ifdef DEBUG
+ ce = CE_WARN;
+#endif
+ dev_err(rdip, ce, "failed to get register "
+ "size, value larger than OFF_MAX: 0x%"
+ PRIx64 "\n", val);
+ return (DDI_FAILURE);
+ }
+ *(off_t *)result = (off_t)val;
}
ddi_prop_free(drv_regp);
diff --git a/usr/src/uts/i86pc/io/rootnex.c b/usr/src/uts/i86pc/io/rootnex.c
index 889c2f3300..081c8afed0 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 2016 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(
diff --git a/usr/src/uts/intel/io/pci/pci_boot.c b/usr/src/uts/intel/io/pci/pci_boot.c
index a1b787c98c..5e29a66d04 100644
--- a/usr/src/uts/intel/io/pci/pci_boot.c
+++ b/usr/src/uts/intel/io/pci/pci_boot.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2015 Joyent, Inc.
+ * Copyright 2016 Joyent, Inc.
*/
#include <sys/types.h>
@@ -1082,8 +1082,16 @@ fix_ppb_res(uchar_t secbus, boolean_t prog_sub)
*/
io_base = pci_getb(bus, dev, func, PCI_BCNF_IO_BASE_LOW);
io_limit = pci_getb(bus, dev, func, PCI_BCNF_IO_LIMIT_LOW);
- io_base = (io_base & 0xf0) << 8;
- io_limit = ((io_limit & 0xf0) << 8) | 0xfff;
+ io_base = (io_base & PCI_BCNF_IO_MASK) << PCI_BCNF_IO_SHIFT;
+ io_limit = ((io_limit & PCI_BCNF_IO_MASK) << PCI_BCNF_IO_SHIFT) | 0xfff;
+ if ((io_base & PCI_BCNF_ADDR_MASK) == PCI_BCNF_IO_32BIT) {
+ uint16_t io_base_hi, io_limit_hi;
+ io_base_hi = pci_getw(bus, dev, func, PCI_BCNF_IO_BASE_HI);
+ io_limit_hi = pci_getw(bus, dev, func, PCI_BCNF_IO_LIMIT_HI);
+
+ io_base |= (uint_t)io_base_hi << 16;
+ io_limit |= (uint_t)io_limit_hi << 16;
+ }
/* Form list of all resources passed (avail + used) */
scratch_list = memlist_dup(pci_bus_res[secbus].io_avail);
@@ -2770,7 +2778,8 @@ add_ppb_props(dev_info_t *dip, uchar_t bus, uchar_t dev, uchar_t func,
{
char *dev_type;
int i;
- uint_t val, io_range[2], mem_range[2], pmem_range[2];
+ uint_t val;
+ uint64_t io_range[2], mem_range[2], pmem_range[2];
uchar_t secbus = pci_getb(bus, dev, func, PCI_BCNF_SECBUS);
uchar_t subbus = pci_getb(bus, dev, func, PCI_BCNF_SUBBUS);
uchar_t progclass;
@@ -2850,12 +2859,23 @@ add_ppb_props(dev_info_t *dip, uchar_t bus, uchar_t dev, uchar_t func,
* If it is unset, we disable i/o and mark it for reconfiguration in
* later passes by setting the base > limit
*/
- val = (uint_t)pci_getw(bus, dev, func, PCI_CONF_COMM);
+ val = (uint64_t)pci_getw(bus, dev, func, PCI_CONF_COMM);
if (val & PCI_COMM_IO) {
val = (uint_t)pci_getb(bus, dev, func, PCI_BCNF_IO_BASE_LOW);
- io_range[0] = ((val & 0xf0) << 8);
+ io_range[0] = ((val & PCI_BCNF_IO_MASK) << PCI_BCNF_IO_SHIFT);
val = (uint_t)pci_getb(bus, dev, func, PCI_BCNF_IO_LIMIT_LOW);
- io_range[1] = ((val & 0xf0) << 8) | 0xFFF;
+ io_range[1] = ((val & PCI_BCNF_IO_MASK) << PCI_BCNF_IO_SHIFT) |
+ 0xfff;
+ if ((io_range[0] & PCI_BCNF_ADDR_MASK) == PCI_BCNF_IO_32BIT) {
+ uint16_t io_base_hi, io_limit_hi;
+ io_base_hi = pci_getw(bus, dev, func,
+ PCI_BCNF_IO_BASE_HI);
+ io_limit_hi = pci_getw(bus, dev, func,
+ PCI_BCNF_IO_LIMIT_HI);
+
+ io_range[0] |= (uint32_t)io_base_hi << 16;
+ io_range[1] |= (uint32_t)io_limit_hi << 16;
+ }
} else {
io_range[0] = 0x9fff;
io_range[1] = 0x1000;
@@ -2869,31 +2889,23 @@ add_ppb_props(dev_info_t *dip, uchar_t bus, uchar_t dev, uchar_t func,
if (io_range[0] != 0 && io_range[0] < io_range[1]) {
memlist_insert(&pci_bus_res[secbus].io_avail,
- (uint64_t)io_range[0],
- (uint64_t)(io_range[1] - io_range[0] + 1));
+ io_range[0], (io_range[1] - io_range[0] + 1));
memlist_insert(&pci_bus_res[bus].io_used,
- (uint64_t)io_range[0],
- (uint64_t)(io_range[1] - io_range[0] + 1));
+ io_range[0], (io_range[1] - io_range[0] + 1));
if (pci_bus_res[bus].io_avail != NULL) {
(void) memlist_remove(&pci_bus_res[bus].io_avail,
- (uint64_t)io_range[0],
- (uint64_t)(io_range[1] - io_range[0] + 1));
+ io_range[0], (io_range[1] - io_range[0] + 1));
}
- dcmn_err(CE_NOTE, "bus %d io-range: 0x%x-%x",
+ dcmn_err(CE_NOTE, "bus %d io-range: 0x%" PRIx64 "-%" PRIx64,
secbus, io_range[0], io_range[1]);
- /* if 32-bit supported, make sure upper bits are not set */
- if ((val & 0xf) == 1 &&
- pci_getw(bus, dev, func, PCI_BCNF_IO_BASE_HI)) {
- cmn_err(CE_NOTE, "unsupported 32-bit IO address on"
- " pci-pci bridge [%d/%d/%d]", bus, dev, func);
- }
}
/* mem range */
val = (uint_t)pci_getw(bus, dev, func, PCI_BCNF_MEM_BASE);
- mem_range[0] = ((val & 0xFFF0) << 16);
+ mem_range[0] = ((val & PCI_BCNF_MEM_MASK) << PCI_BCNF_MEM_SHIFT);
val = (uint_t)pci_getw(bus, dev, func, PCI_BCNF_MEM_LIMIT);
- mem_range[1] = ((val & 0xFFF0) << 16) | 0xFFFFF;
+ mem_range[1] = ((val & PCI_BCNF_MEM_MASK) << PCI_BCNF_MEM_SHIFT) |
+ 0xfffff;
if (mem_range[0] != 0 && mem_range[0] < mem_range[1]) {
memlist_insert(&pci_bus_res[secbus].mem_avail,
(uint64_t)mem_range[0],
@@ -2908,15 +2920,23 @@ add_ppb_props(dev_info_t *dip, uchar_t bus, uchar_t dev, uchar_t func,
(void) memlist_remove(&pci_bus_res[bus].pmem_avail,
(uint64_t)mem_range[0],
(uint64_t)(mem_range[1] - mem_range[0] + 1));
- dcmn_err(CE_NOTE, "bus %d mem-range: 0x%x-%x",
+ dcmn_err(CE_NOTE, "bus %d mem-range: 0x%" PRIx64 "-%" PRIx64,
secbus, mem_range[0], mem_range[1]);
}
/* prefetchable memory range */
val = (uint_t)pci_getw(bus, dev, func, PCI_BCNF_PF_BASE_LOW);
- pmem_range[0] = ((val & 0xFFF0) << 16);
+ pmem_range[0] = ((val & PCI_BCNF_MEM_MASK) << PCI_BCNF_MEM_SHIFT);
val = (uint_t)pci_getw(bus, dev, func, PCI_BCNF_PF_LIMIT_LOW);
- pmem_range[1] = ((val & 0xFFF0) << 16) | 0xFFFFF;
+ pmem_range[1] = ((val & PCI_BCNF_MEM_MASK) << PCI_BCNF_MEM_SHIFT) |
+ 0xfffff;
+ if ((pmem_range[0] & PCI_BCNF_ADDR_MASK) == PCI_BCNF_PF_MEM_64BIT) {
+ uint32_t pf_addr_hi, pf_limit_hi;
+ pf_addr_hi = pci_getl(bus, dev, func, PCI_BCNF_PF_BASE_HIGH);
+ pf_limit_hi = pci_getl(bus, dev, func, PCI_BCNF_PF_LIMIT_HIGH);
+ pmem_range[0] |= (uint64_t)pf_addr_hi << 32;
+ pmem_range[1] |= (uint64_t)pf_limit_hi << 32;
+ }
if (pmem_range[0] != 0 && pmem_range[0] < pmem_range[1]) {
memlist_insert(&pci_bus_res[secbus].pmem_avail,
(uint64_t)pmem_range[0],
@@ -2931,14 +2951,8 @@ add_ppb_props(dev_info_t *dip, uchar_t bus, uchar_t dev, uchar_t func,
(void) memlist_remove(&pci_bus_res[bus].mem_avail,
(uint64_t)pmem_range[0],
(uint64_t)(pmem_range[1] - pmem_range[0] + 1));
- dcmn_err(CE_NOTE, "bus %d pmem-range: 0x%x-%x",
+ dcmn_err(CE_NOTE, "bus %d pmem-range: 0x%" PRIx64 "-%" PRIx64,
secbus, pmem_range[0], pmem_range[1]);
- /* if 64-bit supported, make sure upper bits are not set */
- if ((val & 0xf) == 1 &&
- pci_getl(bus, dev, func, PCI_BCNF_PF_BASE_HIGH)) {
- cmn_err(CE_NOTE, "unsupported 64-bit prefetch memory on"
- " pci-pci bridge [%d/%d/%d]", bus, dev, func);
- }
}
/*
@@ -3091,30 +3105,37 @@ add_bus_slot_names_prop(int bus)
* non-zero 'ppb' argument select PCI-PCI bridges versus root.
*/
static void
-memlist_to_ranges(void **rp, struct memlist *entry, int type, int ppb)
+memlist_to_ranges(void **rp, struct memlist *entry, uint_t type, int ppb)
{
ppb_ranges_t *ppb_rp = *rp;
pci_ranges_t *pci_rp = *rp;
while (entry != NULL) {
+ uint_t atype = type;
+ if ((type & PCI_REG_ADDR_M) == PCI_ADDR_MEM32 &&
+ (entry->ml_address >= UINT32_MAX ||
+ entry->ml_size >= UINT32_MAX)) {
+ atype &= ~PCI_ADDR_MEM32;
+ atype |= PCI_ADDR_MEM64;
+ }
if (ppb) {
- ppb_rp->child_high = ppb_rp->parent_high = type;
+ ppb_rp->child_high = ppb_rp->parent_high = atype;
ppb_rp->child_mid = ppb_rp->parent_mid =
- (uint32_t)(entry->ml_address >> 32); /* XXX */
+ (uint32_t)(entry->ml_address >> 32);
ppb_rp->child_low = ppb_rp->parent_low =
(uint32_t)entry->ml_address;
ppb_rp->size_high =
- (uint32_t)(entry->ml_size >> 32); /* XXX */
+ (uint32_t)(entry->ml_size >> 32);
ppb_rp->size_low = (uint32_t)entry->ml_size;
*rp = ++ppb_rp;
} else {
- pci_rp->child_high = type;
+ pci_rp->child_high = atype;
pci_rp->child_mid = pci_rp->parent_high =
- (uint32_t)(entry->ml_address >> 32); /* XXX */
+ (uint32_t)(entry->ml_address >> 32);
pci_rp->child_low = pci_rp->parent_low =
(uint32_t)entry->ml_address;
pci_rp->size_high =
- (uint32_t)(entry->ml_size >> 32); /* XXX */
+ (uint32_t)(entry->ml_size >> 32);
pci_rp->size_low = (uint32_t)entry->ml_size;
*rp = ++pci_rp;
}
diff --git a/usr/src/uts/intel/io/pci/pci_resource.c b/usr/src/uts/intel/io/pci/pci_resource.c
index a088deb456..fdaec100b8 100644
--- a/usr/src/uts/intel/io/pci/pci_resource.c
+++ b/usr/src/uts/intel/io/pci/pci_resource.c
@@ -473,15 +473,13 @@ mps_find_bus_res(int bus, int type, struct memlist **res)
sasmp = (struct sasm *)extp;
if (((int)sasmp->sasm_as_type) == type &&
((int)sasmp->sasm_bus_id) == bus) {
- if (sasmp->sasm_as_base_hi != 0 ||
- sasmp->sasm_as_len_hi != 0) {
- printf("64 bits address space\n");
- extp += SYS_AS_MAPPING_SIZE;
- break;
- }
- memlist_insert(res,
- (uint64_t)sasmp->sasm_as_base,
- sasmp->sasm_as_len);
+ uint64_t base, len;
+
+ base = (uint64_t)sasmp->sasm_as_base |
+ (uint64_t)sasmp->sasm_as_base_hi << 32;
+ len = (uint64_t)sasmp->sasm_as_len |
+ (uint64_t)sasmp->sasm_as_len_hi << 32;
+ memlist_insert(res, base, len);
res_cnt++;
}
extp += SYS_AS_MAPPING_SIZE;