summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZhi-Jun Robin Fu <Zhijun.Fu@Sun.COM>2010-04-22 15:10:46 +0800
committerZhi-Jun Robin Fu <Zhijun.Fu@Sun.COM>2010-04-22 15:10:46 +0800
commit8d7fafffed373567f52062b634e61fd50858b8d9 (patch)
treecb77823b1668cdc1d8277f0e4ffa5858f2a721fc
parentc6698ca1e2450f37cc5ee4cdded3e5472088ba41 (diff)
downloadillumos-joyent-8d7fafffed373567f52062b634e61fd50858b8d9.tar.gz
6910668 the code for 6831378 should do better error handling
-rw-r--r--usr/src/cmd/pcitool/pcitool.c13
-rw-r--r--usr/src/uts/i86pc/Makefile.files4
-rw-r--r--usr/src/uts/i86pc/io/pci/pci_tools.c18
-rw-r--r--usr/src/uts/i86pc/os/pci_cfgacc_x86.c117
-rw-r--r--usr/src/uts/i86pc/os/pci_cfgspace.c16
-rw-r--r--usr/src/uts/i86pc/os/pci_mech1_amd.c185
-rw-r--r--usr/src/uts/i86pc/sys/pci_cfgspace_impl.h17
-rw-r--r--usr/src/uts/sun4u/io/pciex/pci_cfgacc_4u.c33
-rw-r--r--usr/src/uts/sun4v/io/pciex/pci_cfgacc_4v.c35
9 files changed, 338 insertions, 100 deletions
diff --git a/usr/src/cmd/pcitool/pcitool.c b/usr/src/cmd/pcitool/pcitool.c
index 4f575eae08..951980ef4a 100644
--- a/usr/src/cmd/pcitool/pcitool.c
+++ b/usr/src/cmd/pcitool/pcitool.c
@@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/* This file is the main module for the pcitool. */
@@ -476,7 +475,7 @@ supports_ari(int fd, uint8_t bus_no)
cfg_prg.func_no = func_no;
cfg_prg.barnum = 0;
cfg_prg.user_version = PCITOOL_VERSION;
- cfg_prg.offset = PCI_CONF_COMM;
+ cfg_prg.offset = 0;
cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 + PCITOOL_ACC_ATTR_ENDN_LTL;
if (ioctl(fd, PCITOOL_DEVICE_GET_REG, &cfg_prg) != SUCCESS) {
@@ -484,7 +483,15 @@ supports_ari(int fd, uint8_t bus_no)
}
data = (uint32_t)cfg_prg.data;
+ if (data == (uint32_t)(-1))
+ return (FAILURE);
+ cfg_prg.offset = PCI_CONF_COMM;
+ if (ioctl(fd, PCITOOL_DEVICE_GET_REG, &cfg_prg) != SUCCESS) {
+ return (FAILURE);
+ }
+
+ data = (uint32_t)cfg_prg.data;
if (!((data >> 16) & PCI_STAT_CAP))
return (FAILURE);
diff --git a/usr/src/uts/i86pc/Makefile.files b/usr/src/uts/i86pc/Makefile.files
index eeaaa379ab..8156574ad1 100644
--- a/usr/src/uts/i86pc/Makefile.files
+++ b/usr/src/uts/i86pc/Makefile.files
@@ -20,8 +20,7 @@
#
#
-# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
#
# This Makefile defines file modules in the directory uts/i86pc
# and its children. These are the source files which are i86pc
@@ -101,6 +100,7 @@ CORE_OBJS += \
pci_cfgacc_x86.o \
pci_cfgspace.o \
pci_mech1.o \
+ pci_mech1_amd.o \
pci_mech2.o \
pci_neptune.o \
pci_orion.o \
diff --git a/usr/src/uts/i86pc/io/pci/pci_tools.c b/usr/src/uts/i86pc/io/pci/pci_tools.c
index 2dea113932..1100e63d0b 100644
--- a/usr/src/uts/i86pc/io/pci/pci_tools.c
+++ b/usr/src/uts/i86pc/io/pci/pci_tools.c
@@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#include <sys/types.h>
@@ -557,7 +556,20 @@ pcitool_cfg_access(pcitool_reg_t *prg, boolean_t write_flag,
pci_cfgacc_acc(&req);
} else {
pci_cfgacc_acc(&req);
- local_data = VAL64(&req);
+ switch (size) {
+ case 1:
+ local_data = VAL8(&req);
+ break;
+ case 2:
+ local_data = VAL16(&req);
+ break;
+ case 4:
+ local_data = VAL32(&req);
+ break;
+ case 8:
+ local_data = VAL64(&req);
+ break;
+ }
if (big_endian) {
prg->data =
pcitool_swap_endian(local_data, size);
diff --git a/usr/src/uts/i86pc/os/pci_cfgacc_x86.c b/usr/src/uts/i86pc/os/pci_cfgacc_x86.c
index 184e41d6ed..f643354245 100644
--- a/usr/src/uts/i86pc/os/pci_cfgacc_x86.c
+++ b/usr/src/uts/i86pc/os/pci_cfgacc_x86.c
@@ -20,8 +20,7 @@
*/
/*
- * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#include <sys/systm.h>
@@ -32,6 +31,7 @@
#include <sys/sysmacros.h>
#include <sys/x86_archext.h>
#include <sys/pci.h>
+#include <sys/cmn_err.h>
#include <vm/hat_i86.h>
#include <vm/seg_kmem.h>
#include <vm/kboot_mmu.h>
@@ -73,22 +73,20 @@ pci_cfgacc_map(paddr_t phys_addr)
* Note: no need to unmap first, clear_boot_mappings() will
* do that for us.
*/
- if (pci_cfgacc_virt_base < (caddr_t)kernelbase) {
- if ((pci_cfgacc_virt_base = vmem_alloc(heap_arena,
- MMU_PAGESIZE, VM_NOSLEEP)) == NULL)
- return (NULL);
- }
+ if (pci_cfgacc_virt_base < (caddr_t)kernelbase)
+ pci_cfgacc_virt_base = vmem_alloc(heap_arena,
+ MMU_PAGESIZE, VM_SLEEP);
+
hat_devload(kas.a_hat, pci_cfgacc_virt_base,
MMU_PAGESIZE, pfn, PROT_READ | PROT_WRITE |
HAT_STRICTORDER, HAT_LOAD_LOCK);
} else {
paddr_t pa_base = P2ALIGN(phys_addr, MMU_PAGESIZE);
- if (pci_cfgacc_virt_base == NULL) {
- if ((pci_cfgacc_virt_base = (caddr_t)
- alloc_vaddr(MMU_PAGESIZE, MMU_PAGESIZE)) == NULL)
- return (NULL);
- }
+ if (pci_cfgacc_virt_base == NULL)
+ pci_cfgacc_virt_base =
+ (caddr_t)alloc_vaddr(MMU_PAGESIZE, MMU_PAGESIZE);
+
kbm_map((uintptr_t)pci_cfgacc_virt_base, pa_base, 0, 0);
}
@@ -106,18 +104,14 @@ pci_cfgacc_unmap()
static void
pci_cfgacc_io(pci_cfgacc_req_t *req)
{
- uint8_t bus, dev, func, ioacc_offset;
-
- if (req->offset > 0xff) {
- if (!req->write)
- VAL64(req) = (uint64_t)-1;
- return;
- }
+ uint8_t bus, dev, func;
+ uint16_t ioacc_offset; /* 4K config access with IO ECS */
bus = PCI_BDF_BUS(req->bdf);
dev = PCI_BDF_DEV(req->bdf);
func = PCI_BDF_FUNC(req->bdf);
ioacc_offset = req->offset;
+
switch (req->size) {
case 1:
if (req->write)
@@ -143,26 +137,33 @@ pci_cfgacc_io(pci_cfgacc_req_t *req)
VAL32(req) = (*pci_getl_func)(bus, dev, func,
ioacc_offset);
break;
- default:
- return;
+ case 8:
+ if (req->write) {
+ (*pci_putl_func)(bus, dev, func,
+ ioacc_offset, VAL64(req) & 0xffffffff);
+ (*pci_putl_func)(bus, dev, func,
+ ioacc_offset + 4, VAL64(req) >> 32);
+ } else {
+ VAL64(req) = (*pci_getl_func)(bus, dev, func,
+ ioacc_offset);
+ VAL64(req) |= (uint64_t)(*pci_getl_func)(bus, dev, func,
+ ioacc_offset + 4) << 32;
+ }
+ break;
}
}
-static int
+static void
pci_cfgacc_mmio(pci_cfgacc_req_t *req)
{
caddr_t vaddr;
paddr_t paddr;
- int rval = DDI_SUCCESS;
paddr = (paddr_t)req->bdf << 12;
paddr += mcfg_mem_base + req->offset;
mutex_enter(&pcicfg_mmio_mutex);
- if ((vaddr = pci_cfgacc_map(paddr)) == NULL) {
- mutex_exit(&pcicfg_mmio_mutex);
- return (DDI_FAILURE);
- }
+ vaddr = pci_cfgacc_map(paddr);
switch (req->size) {
case 1:
@@ -189,56 +190,56 @@ pci_cfgacc_mmio(pci_cfgacc_req_t *req)
else
VAL64(req) = *((uint64_t *)vaddr);
break;
- default:
- rval = DDI_FAILURE;
}
pci_cfgacc_unmap();
mutex_exit(&pcicfg_mmio_mutex);
-
- return (rval);
}
static boolean_t
-pci_cfgacc_valid(pci_cfgacc_req_t *req)
+pci_cfgacc_valid(pci_cfgacc_req_t *req, uint16_t maxoffset)
{
- return (IS_P2ALIGNED(req->offset, req->size) &&
- (req->offset < PCIE_CFG_SPACE_SIZE));
+ int sz = req->size;
+
+ if (IS_P2ALIGNED(req->offset, sz) &&
+ (req->offset < maxoffset) &&
+ ((sz & 0xf) && ISP2(sz)))
+ return (B_TRUE);
+
+ cmn_err(CE_WARN, "illegal PCI request: offset = %x, size = %d",
+ req->offset, sz);
+ return (B_FALSE);
}
void
-pci_cfgacc_acc(pci_cfgacc_req_t *req)
+pci_cfgacc_check_io(pci_cfgacc_req_t *req)
{
uint8_t bus;
- if (!req->write)
- VAL64(req) = 0;
-
- if (!pci_cfgacc_valid(req)) {
- if (!req->write)
- VAL64(req) = (uint64_t)-1;
- return;
- }
-
bus = PCI_BDF_BUS(req->bdf);
- if (pci_cfgacc_force_io || (mcfg_mem_base == NULL) ||
- (bus < mcfg_bus_start) || (bus > mcfg_bus_end))
- goto ioacc;
- if (req->ioacc)
- goto ioacc;
+ if (pci_cfgacc_force_io || (mcfg_mem_base == NULL) ||
+ (bus < mcfg_bus_start) || (bus > mcfg_bus_end) ||
+ pci_cfgacc_find_workaround(req->bdf))
+ req->ioacc = B_TRUE;
+}
- /* check if workaround is needed */
- if (pci_cfgacc_find_workaround(req->bdf))
- goto ioacc;
+void
+pci_cfgacc_acc(pci_cfgacc_req_t *req)
+{
+ extern uint_t pci_iocfg_max_offset;
- if (pci_cfgacc_mmio(req) != DDI_SUCCESS)
- goto ioacc;
+ if (!req->write)
+ VAL64(req) = (uint64_t)-1;
- return;
+ pci_cfgacc_check_io(req);
-ioacc:
- pci_cfgacc_io(req);
- req->ioacc = B_TRUE;
+ if (req->ioacc) {
+ if (pci_cfgacc_valid(req, pci_iocfg_max_offset))
+ pci_cfgacc_io(req);
+ } else {
+ if (pci_cfgacc_valid(req, PCIE_CFG_SPACE_SIZE))
+ pci_cfgacc_mmio(req);
+ }
}
typedef struct cfgacc_bus_range {
diff --git a/usr/src/uts/i86pc/os/pci_cfgspace.c b/usr/src/uts/i86pc/os/pci_cfgspace.c
index cf93bfeff0..abfec8854b 100644
--- a/usr/src/uts/i86pc/os/pci_cfgspace.c
+++ b/usr/src/uts/i86pc/os/pci_cfgspace.c
@@ -20,8 +20,7 @@
*/
/*
- * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -64,6 +63,11 @@ uint8_t mcfg_bus_start = 0;
uint8_t mcfg_bus_end = 0xff;
/*
+ * Maximum offset in config space when not using MMIO
+ */
+uint_t pci_iocfg_max_offset = 0xff;
+
+/*
* These function pointers lead to the actual implementation routines
* for configuration space access. Normally they lead to either the
* pci_mech1_* or pci_mech2_* routines, but they can also lead to
@@ -173,6 +177,14 @@ pci_check(void)
pci_putb_func = pci_orion_putb;
pci_putw_func = pci_orion_putw;
pci_putl_func = pci_orion_putl;
+ } else if (pci_check_amd_ioecs()) {
+ pci_getb_func = pci_mech1_amd_getb;
+ pci_getw_func = pci_mech1_amd_getw;
+ pci_getl_func = pci_mech1_amd_getl;
+ pci_putb_func = pci_mech1_amd_putb;
+ pci_putw_func = pci_mech1_amd_putw;
+ pci_putl_func = pci_mech1_amd_putl;
+ pci_iocfg_max_offset = 0xfff;
} else {
pci_getb_func = pci_mech1_getb;
pci_getw_func = pci_mech1_getw;
diff --git a/usr/src/uts/i86pc/os/pci_mech1_amd.c b/usr/src/uts/i86pc/os/pci_mech1_amd.c
new file mode 100644
index 0000000000..d45408731b
--- /dev/null
+++ b/usr/src/uts/i86pc/os/pci_mech1_amd.c
@@ -0,0 +1,185 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2010 Advanced Micro Devices, Inc.
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/*
+ * PCI Mechanism 1 low-level routines with ECS support for AMD family >= 0x10
+ */
+
+#include <sys/controlregs.h>
+#include <sys/cpuvar.h>
+#include <sys/types.h>
+#include <sys/pci.h>
+#include <sys/pci_impl.h>
+#include <sys/sunddi.h>
+#include <sys/pci_cfgspace_impl.h>
+#include <sys/x86_archext.h>
+
+boolean_t
+pci_check_amd_ioecs(void)
+{
+ struct cpuid_regs cp;
+ int family;
+
+ if ((x86_feature & X86_CPUID) == 0)
+ return (B_FALSE);
+
+ /*
+ * Get the CPU vendor string from CPUID.
+ * This PCI mechanism only applies to AMD CPUs.
+ */
+ cp.cp_eax = 0;
+ (void) __cpuid_insn(&cp);
+
+ if ((cp.cp_ebx != 0x68747541) || /* Auth */
+ (cp.cp_edx != 0x69746e65) || /* enti */
+ (cp.cp_ecx != 0x444d4163)) /* cAMD */
+ return (B_FALSE);
+
+ /*
+ * Get the CPU family from CPUID.
+ * This PCI mechanism is only available on family 0x10 or higher.
+ */
+ cp.cp_eax = 1;
+ (void) __cpuid_insn(&cp);
+ family = ((cp.cp_eax >> 8) & 0xf) + ((cp.cp_eax >> 20) & 0xff);
+
+ if (family < 0x10)
+ return (B_FALSE);
+
+ /*
+ * Set the EnableCf8ExtCfg bit in the Northbridge Configuration Register
+ * to enable accessing PCI ECS using in/out instructions.
+ */
+ wrmsr(MSR_AMD_NB_CFG, rdmsr(MSR_AMD_NB_CFG) | AMD_GH_NB_CFG_EN_ECS);
+ return (B_TRUE);
+}
+
+/*
+ * Macro to setup PCI Extended Configuration Space (ECS) address to give to
+ * "in/out" instructions
+ */
+#define PCI_CADDR1_ECS(b, d, f, r) \
+ (PCI_CADDR1((b), (d), (f), (r)) | ((((r) >> 8) & 0xf) << 24))
+
+/*
+ * Per PCI 2.1 section 3.7.4.1 and PCI-PCI Bridge Architecture 1.0 section
+ * 5.3.1.2: dev=31 func=7 reg=0 means a special cycle. We don't want to
+ * trigger that by accident, so we pretend that dev 31, func 7 doesn't
+ * exist. If we ever want special cycle support, we'll add explicit
+ * special cycle support.
+ */
+
+uint8_t
+pci_mech1_amd_getb(int bus, int device, int function, int reg)
+{
+ uint8_t val;
+
+ if (device == PCI_MECH1_SPEC_CYCLE_DEV &&
+ function == PCI_MECH1_SPEC_CYCLE_FUNC) {
+ return (0xff);
+ }
+
+ mutex_enter(&pcicfg_mutex);
+ outl(PCI_CONFADD, PCI_CADDR1_ECS(bus, device, function, reg));
+ val = inb(PCI_CONFDATA | (reg & 0x3));
+ mutex_exit(&pcicfg_mutex);
+ return (val);
+}
+
+uint16_t
+pci_mech1_amd_getw(int bus, int device, int function, int reg)
+{
+ uint16_t val;
+
+ if (device == PCI_MECH1_SPEC_CYCLE_DEV &&
+ function == PCI_MECH1_SPEC_CYCLE_FUNC) {
+ return (0xffff);
+ }
+
+ mutex_enter(&pcicfg_mutex);
+ outl(PCI_CONFADD, PCI_CADDR1_ECS(bus, device, function, reg));
+ val = inw(PCI_CONFDATA | (reg & 0x2));
+ mutex_exit(&pcicfg_mutex);
+ return (val);
+}
+
+uint32_t
+pci_mech1_amd_getl(int bus, int device, int function, int reg)
+{
+ uint32_t val;
+
+ if (device == PCI_MECH1_SPEC_CYCLE_DEV &&
+ function == PCI_MECH1_SPEC_CYCLE_FUNC) {
+ return (0xffffffffu);
+ }
+
+ mutex_enter(&pcicfg_mutex);
+ outl(PCI_CONFADD, PCI_CADDR1_ECS(bus, device, function, reg));
+ val = inl(PCI_CONFDATA);
+ mutex_exit(&pcicfg_mutex);
+ return (val);
+}
+
+void
+pci_mech1_amd_putb(int bus, int device, int function, int reg, uint8_t val)
+{
+ if (device == PCI_MECH1_SPEC_CYCLE_DEV &&
+ function == PCI_MECH1_SPEC_CYCLE_FUNC) {
+ return;
+ }
+
+ mutex_enter(&pcicfg_mutex);
+ outl(PCI_CONFADD, PCI_CADDR1_ECS(bus, device, function, reg));
+ outb(PCI_CONFDATA | (reg & 0x3), val);
+ mutex_exit(&pcicfg_mutex);
+}
+
+void
+pci_mech1_amd_putw(int bus, int device, int function, int reg, uint16_t val)
+{
+ if (device == PCI_MECH1_SPEC_CYCLE_DEV &&
+ function == PCI_MECH1_SPEC_CYCLE_FUNC) {
+ return;
+ }
+
+ mutex_enter(&pcicfg_mutex);
+ outl(PCI_CONFADD, PCI_CADDR1_ECS(bus, device, function, reg));
+ outw(PCI_CONFDATA | (reg & 0x2), val);
+ mutex_exit(&pcicfg_mutex);
+}
+
+void
+pci_mech1_amd_putl(int bus, int device, int function, int reg, uint32_t val)
+{
+ if (device == PCI_MECH1_SPEC_CYCLE_DEV &&
+ function == PCI_MECH1_SPEC_CYCLE_FUNC) {
+ return;
+ }
+
+ mutex_enter(&pcicfg_mutex);
+ outl(PCI_CONFADD, PCI_CADDR1_ECS(bus, device, function, reg));
+ outl(PCI_CONFDATA, val);
+ mutex_exit(&pcicfg_mutex);
+}
diff --git a/usr/src/uts/i86pc/sys/pci_cfgspace_impl.h b/usr/src/uts/i86pc/sys/pci_cfgspace_impl.h
index 76cc353f1c..3eaf621efd 100644
--- a/usr/src/uts/i86pc/sys/pci_cfgspace_impl.h
+++ b/usr/src/uts/i86pc/sys/pci_cfgspace_impl.h
@@ -20,8 +20,7 @@
*/
/*
- * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#ifndef _SYS_PCI_CFGSPACE_IMPL_H
@@ -47,6 +46,20 @@ extern void pci_mech1_putw(int bus, int dev, int func, int reg, uint16_t val);
extern void pci_mech1_putl(int bus, int dev, int func, int reg, uint32_t val);
/*
+ * AMD family >= 0x10 Mechanism 1 routines with ECS support
+ */
+extern boolean_t pci_check_amd_ioecs(void);
+extern uint8_t pci_mech1_amd_getb(int bus, int dev, int func, int reg);
+extern uint16_t pci_mech1_amd_getw(int bus, int dev, int func, int reg);
+extern uint32_t pci_mech1_amd_getl(int bus, int dev, int func, int reg);
+extern void pci_mech1_amd_putb(int bus, int dev, int func, int reg,
+ uint8_t val);
+extern void pci_mech1_amd_putw(int bus, int dev, int func, int reg,
+ uint16_t val);
+extern void pci_mech1_amd_putl(int bus, int dev, int func, int reg,
+ uint32_t val);
+
+/*
* Generic Mechanism 2 routines
*/
extern uint8_t pci_mech2_getb(int bus, int dev, int func, int reg);
diff --git a/usr/src/uts/sun4u/io/pciex/pci_cfgacc_4u.c b/usr/src/uts/sun4u/io/pciex/pci_cfgacc_4u.c
index 65296bec24..9d12a74ce6 100644
--- a/usr/src/uts/sun4u/io/pciex/pci_cfgacc_4u.c
+++ b/usr/src/uts/sun4u/io/pciex/pci_cfgacc_4u.c
@@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#include <sys/sunddi.h>
@@ -43,11 +42,16 @@
static boolean_t
pci_cfgacc_valid(pci_cfgacc_req_t *req)
{
- /* do not support 64 bit pci config space access */
- return (IS_P2ALIGNED(req->offset, req->size) &&
+ int sz = req->size;
+
+ if (IS_P2ALIGNED(req->offset, sz) &&
(req->offset < PCIE_CFG_SPACE_SIZE) &&
- ((req->size == 1) || (req->size == 2) ||
- (req->size == 4) || (req->size == 8)));
+ ((sz & 0xf) && ISP2(sz)))
+ return (B_TRUE);
+
+ cmn_err(CE_WARN, "illegal PCI request: offset = %x, size = %d",
+ req->offset, sz);
+ return (B_FALSE);
}
/*
@@ -60,8 +64,8 @@ pci_cfgacc_get(dev_info_t *dip, uint16_t bdf, uint16_t offset, uint8_t size)
uint64_t base_addr;
uint64_t val;
- if ((bus_p = PCIE_DIP2DOWNBUS(dip)) == NULL)
- return ((uint64_t)-1);
+ bus_p = PCIE_DIP2DOWNBUS(dip);
+ ASSERT(bus_p != NULL);
base_addr = bus_p->bus_cfgacc_base;
base_addr += RC_BDF_TO_CFGADDR(bdf, offset);
@@ -93,8 +97,8 @@ pci_cfgacc_set(dev_info_t *dip, uint16_t bdf, uint16_t offset, uint8_t size,
pcie_bus_t *bus_p;
uint64_t base_addr;
- if ((bus_p = PCIE_DIP2DOWNBUS(dip)) == NULL)
- return;
+ bus_p = PCIE_DIP2DOWNBUS(dip);
+ ASSERT(bus_p != NULL);
base_addr = bus_p->bus_cfgacc_base;
base_addr += RC_BDF_TO_CFGADDR(bdf, offset);
@@ -122,12 +126,11 @@ pci_cfgacc_set(dev_info_t *dip, uint16_t bdf, uint16_t offset, uint8_t size,
void
pci_cfgacc_acc(pci_cfgacc_req_t *req)
{
- /* is request valid? */
- if (!pci_cfgacc_valid(req)) {
- if (!req->write)
- VAL64(req) = (uint64_t)-1;
+ if (!req->write)
+ VAL64(req) = (uint64_t)-1;
+
+ if (!pci_cfgacc_valid(req))
return;
- }
if (req->write) {
pci_cfgacc_set(req->rcdip, req->bdf, req->offset,
diff --git a/usr/src/uts/sun4v/io/pciex/pci_cfgacc_4v.c b/usr/src/uts/sun4v/io/pciex/pci_cfgacc_4v.c
index 653de54b4c..9818ac0ce6 100644
--- a/usr/src/uts/sun4v/io/pciex/pci_cfgacc_4v.c
+++ b/usr/src/uts/sun4v/io/pciex/pci_cfgacc_4v.c
@@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -48,11 +47,16 @@
static boolean_t
pci_cfgacc_valid(pci_cfgacc_req_t *req)
{
- /* do not support 64 bit pci config space access */
- return (IS_P2ALIGNED(req->offset, req->size) &&
+ int sz = req->size;
+
+ if (IS_P2ALIGNED(req->offset, sz) &&
(req->offset < PCIE_CFG_SPACE_SIZE) &&
- ((req->size == 1) || (req->size == 2) ||
- (req->size == 4) || (req->size == 8)));
+ ((sz & 0xf) && ISP2(sz)))
+ return (B_TRUE);
+
+ cmn_err(CE_WARN, "illegal PCI request: offset = %x, size = %d",
+ req->offset, sz);
+ return (B_FALSE);
}
/*
@@ -66,8 +70,8 @@ pci_cfgacc_get(dev_info_t *dip, uint16_t bdf, uint16_t offset, uint8_t size)
uint64_t devaddr;
uint64_t data = 0;
- if ((bus_p = PCIE_DIP2DOWNBUS(dip)) == NULL)
- return ((uint64_t)-1);
+ bus_p = PCIE_DIP2DOWNBUS(dip);
+ ASSERT(bus_p != NULL);
devhdl = bus_p->bus_cfgacc_base;
devaddr = ((uint64_t)bdf) << RC_RA_BDF_SHIFT;
@@ -87,8 +91,8 @@ pci_cfgacc_set(dev_info_t *dip, uint16_t bdf, uint16_t offset, uint8_t size,
uint64_t devaddr;
pci_cfg_data_t wdata = { 0 };
- if ((bus_p = PCIE_DIP2DOWNBUS(dip)) == NULL)
- return;
+ bus_p = PCIE_DIP2DOWNBUS(dip);
+ ASSERT(bus_p != NULL);
devhdl = bus_p->bus_cfgacc_base;
devaddr = ((uint64_t)bdf) << RC_RA_BDF_SHIFT;
@@ -100,12 +104,11 @@ pci_cfgacc_set(dev_info_t *dip, uint16_t bdf, uint16_t offset, uint8_t size,
void
pci_cfgacc_acc(pci_cfgacc_req_t *req)
{
- /* is request valid? */
- if (!pci_cfgacc_valid(req)) {
- if (!req->write)
- VAL64(req) = (uint64_t)-1;
+ if (!req->write)
+ VAL64(req) = (uint64_t)-1;
+
+ if (!pci_cfgacc_valid(req))
return;
- }
if (req->write) {
pci_cfgacc_set(req->rcdip, req->bdf, req->offset,
@@ -123,6 +126,8 @@ pci_cfgacc_acc(pci_cfgacc_req_t *req)
case 4:
VAL32(req) = (uint32_t)VAL64(req);
break;
+ case 8:
+ /* fall through, no special handling needed */
default:
break;
}