diff options
author | Robert Mustacchi <rm@joyent.com> | 2016-12-15 00:21:15 +0000 |
---|---|---|
committer | Robert Mustacchi <rm@joyent.com> | 2016-12-23 19:13:56 +0000 |
commit | de15e5b3cf5cbe29cd88bc9618e0514ecadfac5a (patch) | |
tree | d7a8958916f1253d9a5f2f8c63b516879f56a099 /usr | |
parent | 696b52570287ab2055ae727bddf6657c667fedbf (diff) | |
download | illumos-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.h | 12 | ||||
-rw-r--r-- | usr/src/uts/common/sys/ddimapreq.h | 18 | ||||
-rw-r--r-- | usr/src/uts/common/sys/pci.h | 7 | ||||
-rw-r--r-- | usr/src/uts/common/sys/types.h | 9 | ||||
-rw-r--r-- | usr/src/uts/i86pc/io/pci/pci.c | 118 | ||||
-rw-r--r-- | usr/src/uts/i86pc/io/pciex/npe.c | 102 | ||||
-rw-r--r-- | usr/src/uts/i86pc/io/rootnex.c | 125 | ||||
-rw-r--r-- | usr/src/uts/intel/io/pci/pci_boot.c | 99 | ||||
-rw-r--r-- | usr/src/uts/intel/io/pci/pci_resource.c | 16 |
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.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 *)® + 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.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 *)® + 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 = ® + mp->map_obj.rp = (struct regspec *)® + 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 = ® + /* + * 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 *)® + 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; |