summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Adamson, SD OSSD <Alan.Adamson@Sun.COM>2008-09-15 10:45:20 -0700
committerAlan Adamson, SD OSSD <Alan.Adamson@Sun.COM>2008-09-15 10:45:20 -0700
commit0114761d17f41c0b83189e4bf95e6b789e7ba99e (patch)
tree4fd16ad5d3b3f4cc747faf57ee734e898fef7f04
parent02c8f3f039188ad827739e040dd0e6f6de8fd943 (diff)
downloadillumos-joyent-0114761d17f41c0b83189e4bf95e6b789e7ba99e.tar.gz
6449810 PCI Express framework performance enhancement
-rw-r--r--usr/src/uts/common/io/pcie.c354
-rw-r--r--usr/src/uts/common/sys/pcie.h4
-rw-r--r--usr/src/uts/common/sys/pcie_impl.h14
-rw-r--r--usr/src/uts/sun4/io/px/px.c48
-rw-r--r--usr/src/uts/sun4/io/px/px_debug.h7
-rw-r--r--usr/src/uts/sun4/io/px/px_lib.h7
-rw-r--r--usr/src/uts/sun4u/io/px/px_hlib.c35
-rw-r--r--usr/src/uts/sun4u/io/px/px_lib4u.c102
-rw-r--r--usr/src/uts/sun4v/Makefile.files4
-rw-r--r--usr/src/uts/sun4v/io/px/px_lib4v.c22
-rw-r--r--usr/src/uts/sun4v/io/px/px_lib4v.h8
-rw-r--r--usr/src/uts/sun4v/io/px/px_libhv.c135
12 files changed, 682 insertions, 58 deletions
diff --git a/usr/src/uts/common/io/pcie.c b/usr/src/uts/common/io/pcie.c
index e11e96b597..c0328b4e07 100644
--- a/usr/src/uts/common/io/pcie.c
+++ b/usr/src/uts/common/io/pcie.c
@@ -23,8 +23,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/sysmacros.h>
#include <sys/types.h>
#include <sys/kmem.h>
@@ -110,9 +108,7 @@ ushort_t pcie_base_err_default =
PCIE_DEVCTL_UR_REPORTING_EN;
/* PCI-Express Device Control Register */
-uint16_t pcie_devctl_default =
- PCIE_DEVCTL_RO_EN |
- PCIE_DEVCTL_MAX_PAYLOAD_128 |
+uint16_t pcie_devctl_default = PCIE_DEVCTL_RO_EN |
PCIE_DEVCTL_MAX_READ_REQ_512;
/* PCI-Express AER Root Control Register */
@@ -166,13 +162,22 @@ uint32_t pcie_aer_suce_severity = PCIE_AER_SUCE_SERR_ASSERT | \
PCIE_AER_SUCE_UC_ADDR_ERR | PCIE_AER_SUCE_UC_ATTR_ERR | \
PCIE_AER_SUCE_USC_MSG_DATA_ERR;
+int pcie_max_mps = PCIE_DEVCTL_MAX_PAYLOAD_4096 >> 5;
+
+static void pcie_scan_mps(dev_info_t *rc_dip, dev_info_t *dip,
+ int *max_supported);
+static int pcie_get_max_supported(dev_info_t *dip, void *arg);
+static int pcie_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec,
+ caddr_t *addrp, ddi_acc_handle_t *handlep);
+static void pcie_unmap_phys(ddi_acc_handle_t *handlep, pci_regspec_t *ph);
+
/*
* modload support
*/
extern struct mod_ops mod_miscops;
struct modlmisc modlmisc = {
&mod_miscops, /* Type of module */
- "PCIE: PCI Express Architecture %I%"
+ "PCIE: PCI framework"
};
struct modlinkage modlinkage = {
@@ -335,6 +340,9 @@ pcie_initchild(dev_info_t *cdip)
pcie_enable_errors(cdip);
}
+ if (pcie_initchild_mps(cdip) == DDI_FAILURE)
+ return (DDI_FAILURE);
+
return (DDI_SUCCESS);
}
@@ -668,6 +676,20 @@ pcie_init_bus(dev_info_t *cdip)
pcie_init_pfd(cdip);
+ /*
+ * If it is a Root Port, perform a fabric scan to determine
+ * the Max Payload Size for the fabric.
+ */
+ if (PCIE_IS_RP(bus_p)) {
+ int max_supported = pcie_max_mps;
+
+ (void) pcie_get_fabric_mps(ddi_get_parent(cdip), cdip,
+ &max_supported);
+
+ bus_p->bus_mps = max_supported;
+ } else
+ bus_p->bus_mps = -1;
+
PCIE_DBG("Add %s(dip 0x%p, bdf 0x%x, secbus 0x%x)\n",
ddi_driver_name(cdip), (void *)cdip, bus_p->bus_bdf,
bus_p->bus_bdg_secbus);
@@ -750,8 +772,12 @@ pcie_enable_errors(dev_info_t *dip)
*/
if ((reg16 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL)) !=
PCI_CAP_EINVAL16) {
- tmp16 = pcie_devctl_default | (pcie_base_err_default &
- (~PCIE_DEVCTL_CE_REPORTING_EN));
+ tmp16 = (reg16 & (PCIE_DEVCTL_MAX_READ_REQ_MASK |
+ PCIE_DEVCTL_MAX_PAYLOAD_MASK)) |
+ (pcie_devctl_default & ~(PCIE_DEVCTL_MAX_READ_REQ_MASK |
+ PCIE_DEVCTL_MAX_PAYLOAD_MASK)) |
+ (pcie_base_err_default & (~PCIE_DEVCTL_CE_REPORTING_EN));
+
PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, tmp16);
PCIE_DBG_CAP(dip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, reg16);
}
@@ -1109,6 +1135,318 @@ pcie_is_link_disabled(dev_info_t *dip)
return (B_FALSE);
}
+/*
+ * Initialize the Maximum Payload Size of a device.
+ *
+ * cdip - dip of device.
+ *
+ * returns - DDI_SUCCESS or DDI_FAILURE
+ */
+int
+pcie_initchild_mps(dev_info_t *cdip)
+{
+ int max_payload_size;
+ pcie_bus_t *bus_p;
+ dev_info_t *pdip = ddi_get_parent(cdip);
+
+ bus_p = PCIE_DIP2BUS(cdip);
+ if (bus_p == NULL) {
+ PCIE_DBG("%s: BUS not found.\n",
+ ddi_driver_name(cdip));
+ return (DDI_FAILURE);
+ }
+
+ if (PCIE_IS_RP(bus_p)) {
+ /*
+ * If this device is a root port, then the mps scan
+ * saved the mps in the root ports bus_p.
+ */
+ max_payload_size = bus_p->bus_mps;
+ } else {
+ /*
+ * If the device is not a root port, then the mps of
+ * its parent should be used.
+ */
+ pcie_bus_t *parent_bus_p = PCIE_DIP2BUS(pdip);
+ max_payload_size = parent_bus_p->bus_mps;
+ }
+
+ if (PCIE_IS_PCIE(bus_p) && (max_payload_size >= 0)) {
+ pcie_bus_t *rootp_bus_p = PCIE_DIP2BUS(bus_p->bus_rp_dip);
+ uint16_t mask, dev_ctrl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL),
+ mps = PCIE_CAP_GET(16, bus_p, PCIE_DEVCAP) &
+ PCIE_DEVCAP_MAX_PAYLOAD_MASK;
+
+ mps = MIN(mps, (uint16_t)max_payload_size);
+
+ /*
+ * If the MPS to be set is less than the root ports
+ * MPS, then MRRS will have to be set the same as MPS.
+ */
+ mask = ((mps < rootp_bus_p->bus_mps) ?
+ PCIE_DEVCTL_MAX_READ_REQ_MASK : 0) |
+ PCIE_DEVCTL_MAX_PAYLOAD_MASK;
+
+ dev_ctrl &= ~mask;
+ mask = ((mps < rootp_bus_p->bus_mps)
+ ? mps << PCIE_DEVCTL_MAX_READ_REQ_SHIFT : 0)
+ | (mps << PCIE_DEVCTL_MAX_PAYLOAD_SHIFT);
+
+ dev_ctrl |= mask;
+
+ PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, dev_ctrl);
+
+ bus_p->bus_mps = mps;
+ }
+ return (DDI_SUCCESS);
+}
+
+/*
+ * Scans a device tree/branch for a maximum payload size capabilities.
+ *
+ * rc_dip - dip of Root Complex.
+ * dip - dip of device where scan will begin.
+ * max_supported (IN) - maximum allowable MPS.
+ * max_supported (OUT) - maximum payload size capability of fabric.
+ */
+void
+pcie_get_fabric_mps(dev_info_t *rc_dip, dev_info_t *dip, int *max_supported)
+{
+ /*
+ * Perform a fabric scan to obtain Maximum Payload Capabilities
+ */
+ (void) pcie_scan_mps(rc_dip, dip, max_supported);
+
+ PCIE_DBG("MPS: Highest Common MPS= %x\n", max_supported);
+}
+
+/*
+ * Scans fabric and determines Maximum Payload Size based on
+ * highest common denominator alogorithm
+ */
+static void
+pcie_scan_mps(dev_info_t *rc_dip, dev_info_t *dip, int *max_supported)
+{
+ int circular_count;
+ pcie_max_supported_t max_pay_load_supported;
+
+ max_pay_load_supported.dip = rc_dip;
+ max_pay_load_supported.highest_common_mps = *max_supported;
+
+ ndi_devi_enter(rc_dip, &circular_count);
+ ddi_walk_devs(dip, pcie_get_max_supported,
+ (void *)&max_pay_load_supported);
+ ndi_devi_exit(rc_dip, circular_count);
+
+ *max_supported = max_pay_load_supported.highest_common_mps;
+}
+
+/*
+ * Called as part of the Maximum Payload Size scan.
+ */
+static int
+pcie_get_max_supported(dev_info_t *dip, void *arg)
+{
+ uint32_t max_supported;
+ uint16_t cap_ptr;
+ pcie_max_supported_t *current = (pcie_max_supported_t *)arg;
+ pci_regspec_t *reg;
+ int rlen;
+ caddr_t virt;
+ ddi_acc_handle_t config_handle;
+
+ if (ddi_get_child(current->dip) == NULL) {
+ return (DDI_WALK_CONTINUE);
+ }
+
+ if (pcie_dev(dip) == DDI_FAILURE) {
+ PCIE_DBG("MPS: pcie_get_max_supported: %s: "
+ "Not a PCIe dev\n", ddi_driver_name(dip));
+ return (DDI_WALK_CONTINUE);
+ }
+
+ if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
+ (caddr_t)&reg, &rlen) != DDI_PROP_SUCCESS) {
+ PCIE_DBG("MPS: pcie_get_max_supported: %s: "
+ "Can not read reg\n", ddi_driver_name(dip));
+ return (DDI_WALK_CONTINUE);
+ }
+
+ if (pcie_map_phys(ddi_get_child(current->dip), reg, &virt,
+ &config_handle) != DDI_SUCCESS) {
+ PCIE_DBG("MPS: pcie_get_max_supported: %s: pcie_map_phys "
+ "failed\n", ddi_driver_name(dip));
+ return (DDI_WALK_CONTINUE);
+ }
+
+ if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, &cap_ptr)) ==
+ DDI_FAILURE) {
+ pcie_unmap_phys(&config_handle, reg);
+ return (DDI_WALK_CONTINUE);
+ }
+
+ max_supported = PCI_CAP_GET16(config_handle, NULL, cap_ptr,
+ PCIE_DEVCAP) & PCIE_DEVCAP_MAX_PAYLOAD_MASK;
+
+ PCIE_DBG("PCIE MPS: %s: MPS Capabilities %x\n", ddi_driver_name(dip),
+ max_supported);
+
+ if (max_supported < current->highest_common_mps)
+ current->highest_common_mps = max_supported;
+
+ pcie_unmap_phys(&config_handle, reg);
+
+ return (DDI_WALK_CONTINUE);
+}
+
+/*
+ * Determines if there are any root ports attached to a root complex.
+ *
+ * dip - dip of root complex
+ *
+ * Returns - DDI_SUCCESS if there is at least one root port otherwise
+ * DDI_FAILURE.
+ */
+int
+pcie_root_port(dev_info_t *dip)
+{
+ int port_type;
+ uint16_t cap_ptr;
+ ddi_acc_handle_t config_handle;
+ dev_info_t *cdip = ddi_get_child(dip);
+
+ /*
+ * Determine if any of the children of the passed in dip
+ * are root ports.
+ */
+ for (; cdip; cdip = ddi_get_next_sibling(cdip)) {
+
+ if (pci_config_setup(cdip, &config_handle) != DDI_SUCCESS)
+ continue;
+
+ if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E,
+ &cap_ptr)) == DDI_FAILURE) {
+ pci_config_teardown(&config_handle);
+ continue;
+ }
+
+ port_type = PCI_CAP_GET16(config_handle, NULL, cap_ptr,
+ PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
+
+ pci_config_teardown(&config_handle);
+
+ if (port_type == PCIE_PCIECAP_DEV_TYPE_ROOT)
+ return (DDI_SUCCESS);
+ }
+
+ /* No root ports were found */
+
+ return (DDI_FAILURE);
+}
+
+/*
+ * Function that determines if a device a PCIe device.
+ *
+ * dip - dip of device.
+ *
+ * returns - DDI_SUCCESS if device is a PCIe device, otherwise DDI_FAILURE.
+ */
+int
+pcie_dev(dev_info_t *dip)
+{
+ /* get parent device's device_type property */
+ char *device_type;
+ int rc = DDI_FAILURE;
+ dev_info_t *pdip = ddi_get_parent(dip);
+
+ if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
+ DDI_PROP_DONTPASS, "device_type", &device_type)
+ != DDI_PROP_SUCCESS) {
+ return (DDI_FAILURE);
+ }
+
+ if (strcmp(device_type, "pciex") == 0)
+ rc = DDI_SUCCESS;
+ else
+ rc = DDI_FAILURE;
+
+ ddi_prop_free(device_type);
+ return (rc);
+}
+
+/*
+ * Function to map in a device's memory space.
+ */
+static int
+pcie_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec,
+ caddr_t *addrp, ddi_acc_handle_t *handlep)
+{
+ ddi_map_req_t mr;
+ ddi_acc_hdl_t *hp;
+ int result;
+ ddi_device_acc_attr_t attr;
+
+ attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
+ attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
+ attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
+ attr.devacc_attr_access = DDI_CAUTIOUS_ACC;
+
+ *handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL);
+ hp = impl_acc_hdl_get(*handlep);
+ hp->ah_vers = VERS_ACCHDL;
+ hp->ah_dip = dip;
+ hp->ah_rnumber = 0;
+ hp->ah_offset = 0;
+ hp->ah_len = 0;
+ hp->ah_acc = attr;
+
+ mr.map_op = DDI_MO_MAP_LOCKED;
+ mr.map_type = DDI_MT_REGSPEC;
+ mr.map_obj.rp = (struct regspec *)phys_spec;
+ mr.map_prot = PROT_READ | PROT_WRITE;
+ mr.map_flags = DDI_MF_KERNEL_MAPPING;
+ mr.map_handlep = hp;
+ mr.map_vers = DDI_MAP_VERSION;
+
+ result = ddi_map(dip, &mr, 0, 0, addrp);
+
+ if (result != DDI_SUCCESS) {
+ impl_acc_hdl_free(*handlep);
+ *handlep = (ddi_acc_handle_t)NULL;
+ } else {
+ hp->ah_addr = *addrp;
+ }
+
+ return (result);
+}
+
+/*
+ * Map out memory that was mapped in with pcie_map_phys();
+ */
+static void
+pcie_unmap_phys(ddi_acc_handle_t *handlep, pci_regspec_t *ph)
+{
+ ddi_map_req_t mr;
+ ddi_acc_hdl_t *hp;
+
+ hp = impl_acc_hdl_get(*handlep);
+ ASSERT(hp);
+
+ mr.map_op = DDI_MO_UNMAP;
+ mr.map_type = DDI_MT_REGSPEC;
+ mr.map_obj.rp = (struct regspec *)ph;
+ mr.map_prot = PROT_READ | PROT_WRITE;
+ mr.map_flags = DDI_MF_KERNEL_MAPPING;
+ mr.map_handlep = hp;
+ mr.map_vers = DDI_MAP_VERSION;
+
+ (void) ddi_map(hp->ah_dip, &mr, hp->ah_offset,
+ hp->ah_len, &hp->ah_addr);
+
+ impl_acc_hdl_free(*handlep);
+ *handlep = (ddi_acc_handle_t)NULL;
+}
+
#ifdef DEBUG
static void
diff --git a/usr/src/uts/common/sys/pcie.h b/usr/src/uts/common/sys/pcie.h
index d840e1358b..7a3ee85d68 100644
--- a/usr/src/uts/common/sys/pcie.h
+++ b/usr/src/uts/common/sys/pcie.h
@@ -26,8 +26,6 @@
#ifndef _SYS_PCIE_H
#define _SYS_PCIE_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -150,6 +148,7 @@ extern "C" {
#define PCIE_DEVCTL_MAX_PAYLOAD_2048 0x80
#define PCIE_DEVCTL_MAX_PAYLOAD_4096 0xA0
#define PCIE_DEVCTL_MAX_PAYLOAD_MASK 0xE0 /* Max_Payload_Size */
+#define PCIE_DEVCTL_MAX_PAYLOAD_SHIFT 0x5
#define PCIE_DEVCTL_EXT_TAG_FIELD_EN 0x100 /* Extended Tag Field Enable */
#define PCIE_DEVCTL_PHTM_FUNC_EN 0x200 /* Phantom Functions Enable */
@@ -163,6 +162,7 @@ extern "C" {
#define PCIE_DEVCTL_MAX_READ_REQ_2048 0x4000
#define PCIE_DEVCTL_MAX_READ_REQ_4096 0x5000
#define PCIE_DEVCTL_MAX_READ_REQ_MASK 0x7000 /* Max_Read_Request_Size */
+#define PCIE_DEVCTL_MAX_READ_REQ_SHIFT 0xC
/*
* Device Status Register (2 bytes)
diff --git a/usr/src/uts/common/sys/pcie_impl.h b/usr/src/uts/common/sys/pcie_impl.h
index 7e3ec25479..34e4385928 100644
--- a/usr/src/uts/common/sys/pcie_impl.h
+++ b/usr/src/uts/common/sys/pcie_impl.h
@@ -26,8 +26,6 @@
#ifndef _SYS_PCIE_IMPL_H
#define _SYS_PCIE_IMPL_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -268,6 +266,8 @@ typedef struct pcie_bus {
/* Cache of last fault data */
pf_data_t *bus_pfd;
+
+ int bus_mps; /* Maximum Payload Size */
} pcie_bus_t;
struct pf_data {
@@ -334,6 +334,11 @@ typedef struct pf_impl {
#define PCIE_PCIECAP_DEV_TYPE_RC_PSEUDO 0x100
+typedef struct {
+ dev_info_t *dip;
+ int highest_common_mps;
+} pcie_max_supported_t;
+
/* PCIe Friendly Functions */
extern int pcie_initchild(dev_info_t *dip);
extern void pcie_uninitchild(dev_info_t *dip);
@@ -354,6 +359,11 @@ extern boolean_t pcie_is_child(dev_info_t *dip, dev_info_t *rdip);
extern int pcie_get_bdf_from_dip(dev_info_t *dip, pcie_req_id_t *bdf);
extern dev_info_t *pcie_get_my_childs_dip(dev_info_t *dip, dev_info_t *rdip);
extern uint32_t pcie_get_bdf_for_dma_xfer(dev_info_t *dip, dev_info_t *rdip);
+extern int pcie_dev(dev_info_t *dip);
+extern void pcie_get_fabric_mps(dev_info_t *rc_dip, dev_info_t *dip,
+ int *max_supported);
+extern int pcie_root_port(dev_info_t *dip);
+extern int pcie_initchild_mps(dev_info_t *dip);
extern uint32_t pcie_get_aer_uce_mask();
extern uint32_t pcie_get_aer_ce_mask();
diff --git a/usr/src/uts/sun4/io/px/px.c b/usr/src/uts/sun4/io/px/px.c
index 21fc16e426..6102ab379f 100644
--- a/usr/src/uts/sun4/io/px/px.c
+++ b/usr/src/uts/sun4/io/px/px.c
@@ -23,8 +23,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* PCI Express nexus driver interface
*/
@@ -61,6 +59,10 @@ static void px_cb_detach(px_t *);
static int px_pwr_setup(dev_info_t *dip);
static void px_pwr_teardown(dev_info_t *dip);
+static void px_set_mps(px_t *px_p);
+
+extern int pcie_max_mps;
+
extern errorq_t *pci_target_queue;
/*
@@ -128,7 +130,7 @@ extern struct mod_ops mod_driverops;
static struct modldrv modldrv = {
&mod_driverops, /* Type of module - driver */
- "PCI Express nexus driver %I%", /* Name of module. */
+ "PCI Express nexus driver", /* Name of module. */
&px_ops, /* driver ops */
};
@@ -319,6 +321,8 @@ px_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
(void) px_init_hotplug(px_p);
+ (void) px_set_mps(px_p);
+
/*
* Create the "devctl" node for hotplug and pcitool support.
* For non-hotplug bus, we still need ":devctl" to
@@ -1438,3 +1442,41 @@ px_uninit_hotplug(dev_info_t *dip)
return (DDI_SUCCESS);
}
+
+static void
+px_set_mps(px_t *px_p)
+{
+ dev_info_t *dip;
+ pcie_bus_t *bus_p;
+ int max_supported;
+
+ dip = px_p->px_dip;
+ bus_p = PCIE_DIP2BUS(dip);
+
+ bus_p->bus_mps = -1;
+
+ if (pcie_root_port(dip) == DDI_FAILURE) {
+ if (px_lib_get_root_complex_mps(px_p, dip,
+ &max_supported) < 0) {
+
+ DBG(DBG_MPS, dip, "MPS: Can not get RC MPS\n");
+ return;
+ }
+
+ DBG(DBG_MPS, dip, "MPS: Root Complex MPS Cap of = %x\n",
+ max_supported);
+
+ if (pcie_max_mps < max_supported)
+ max_supported = pcie_max_mps;
+
+ (void) pcie_get_fabric_mps(dip, ddi_get_child(dip),
+ &max_supported);
+
+ bus_p->bus_mps = max_supported;
+
+ (void) px_lib_set_root_complex_mps(px_p, dip, bus_p->bus_mps);
+
+ DBG(DBG_MPS, dip, "MPS: Root Complex MPS Set to = %x\n",
+ bus_p->bus_mps);
+ }
+}
diff --git a/usr/src/uts/sun4/io/px/px_debug.h b/usr/src/uts/sun4/io/px/px_debug.h
index dc3fb2c6c7..73fdb31779 100644
--- a/usr/src/uts/sun4/io/px/px_debug.h
+++ b/usr/src/uts/sun4/io/px/px_debug.h
@@ -19,15 +19,13 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_PX_DEBUG_H
#define _SYS_PX_DEBUG_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -103,8 +101,9 @@ typedef enum { /* same sequence as px_debug_sym[] */
/* 52 */ DBG_TOOLS,
/* 53 */ DBG_PHYS_ACC,
+ /* 54 */ DBG_HP,
+ /* 55 */ DBG_MPS
- /* 54 */ DBG_HP
} px_debug_bit_t;
#define DBG_BITS 6
diff --git a/usr/src/uts/sun4/io/px/px_lib.h b/usr/src/uts/sun4/io/px/px_lib.h
index c93edbbe6c..56915549c5 100644
--- a/usr/src/uts/sun4/io/px/px_lib.h
+++ b/usr/src/uts/sun4/io/px/px_lib.h
@@ -19,15 +19,13 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_PX_LIB_H
#define _SYS_PX_LIB_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -211,6 +209,9 @@ extern void px_hp_intr_redist(px_t *px_p);
extern boolean_t px_lib_is_in_drain_state(px_t *px_p);
extern pcie_req_id_t px_lib_get_bdf(px_t *px_p);
+extern int px_lib_get_root_complex_mps(px_t *px_p, dev_info_t *dip, int *mps);
+extern int px_lib_set_root_complex_mps(px_t *px_p, dev_info_t *dip, int mps);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/uts/sun4u/io/px/px_hlib.c b/usr/src/uts/sun4u/io/px/px_hlib.c
index fec37a18ea..cce7e1029f 100644
--- a/usr/src/uts/sun4u/io/px/px_hlib.c
+++ b/usr/src/uts/sun4u/io/px/px_hlib.c
@@ -23,8 +23,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <sys/cmn_err.h>
#include <sys/vmsystm.h>
@@ -175,6 +173,9 @@ static void msiq_resume(devhandle_t dev_hdl, pxu_t *pxu_p);
static void jbc_init(caddr_t xbc_csr_base, pxu_t *pxu_p);
static void ubc_init(caddr_t xbc_csr_base, pxu_t *pxu_p);
+extern int px_acknak_timer_table[LINK_MAX_PKT_ARR_SIZE][LINK_WIDTH_ARR_SIZE];
+extern int px_replay_timer_table[LINK_MAX_PKT_ARR_SIZE][LINK_WIDTH_ARR_SIZE];
+
/*
* Initialize the bus, but do not enable interrupts.
*/
@@ -734,32 +735,6 @@ lpu_init(caddr_t csr_base, pxu_t *pxu_p)
uint64_t val;
/*
- * ACKNAK Latency Threshold Table.
- * See Fire PRM 2.0 section 1.2.12.2, table 1-17.
- */
- int acknak_timer_table[LINK_MAX_PKT_ARR_SIZE][LINK_WIDTH_ARR_SIZE] = {
- {0xED, 0x49, 0x43, 0x30},
- {0x1A0, 0x76, 0x6B, 0x48},
- {0x22F, 0x9A, 0x56, 0x56},
- {0x42F, 0x11A, 0x96, 0x96},
- {0x82F, 0x21A, 0x116, 0x116},
- {0x102F, 0x41A, 0x216, 0x216}
- };
-
- /*
- * TxLink Replay Timer Latency Table
- * See Fire PRM 2.0 sections 1.2.12.3, table 1-18.
- */
- int replay_timer_table[LINK_MAX_PKT_ARR_SIZE][LINK_WIDTH_ARR_SIZE] = {
- {0x379, 0x112, 0xFC, 0xB4},
- {0x618, 0x1BA, 0x192, 0x10E},
- {0x831, 0x242, 0x143, 0x143},
- {0xFB1, 0x422, 0x233, 0x233},
- {0x1EB0, 0x7E1, 0x412, 0x412},
- {0x3CB0, 0xF61, 0x7D2, 0x7D2}
- };
-
- /*
* Get the Link Width. See table above LINK_WIDTH_ARR_SIZE #define
* Only Link Widths of x1, x4, and x8 are supported.
* If any width is reported other than x8, set default to x8.
@@ -1031,7 +1006,7 @@ lpu_init(caddr_t csr_base, pxu_t *pxu_p)
/*
* CSR_V LPU_TXLINK_FREQUENT_NAK_LATENCY_TIMER_THRESHOLD
*/
- val = acknak_timer_table[max_payload][link_width];
+ val = px_acknak_timer_table[max_payload][link_width];
CSR_XS(csr_base, LPU_TXLINK_FREQUENT_NAK_LATENCY_TIMER_THRESHOLD, val);
DBG(DBG_LPU, NULL, "lpu_init - "
@@ -1048,7 +1023,7 @@ lpu_init(caddr_t csr_base, pxu_t *pxu_p)
/*
* CSR_V LPU_TXLINK_REPLAY_TIMER_THRESHOLD
*/
- val = replay_timer_table[max_payload][link_width];
+ val = px_replay_timer_table[max_payload][link_width];
CSR_XS(csr_base, LPU_TXLINK_REPLAY_TIMER_THRESHOLD, val);
DBG(DBG_LPU, NULL,
diff --git a/usr/src/uts/sun4u/io/px/px_lib4u.c b/usr/src/uts/sun4u/io/px/px_lib4u.c
index 0573a88a85..a9e1388722 100644
--- a/usr/src/uts/sun4u/io/px/px_lib4u.c
+++ b/usr/src/uts/sun4u/io/px/px_lib4u.c
@@ -69,6 +69,31 @@ static boolean_t px_cpr_callb(void *arg, int code);
static uint_t px_cb_intr(caddr_t arg);
/*
+ * ACKNAK Latency Threshold Table.
+ * See Fire PRM 2.0 section 1.2.12.2, table 1-17.
+ */
+int px_acknak_timer_table[LINK_MAX_PKT_ARR_SIZE][LINK_WIDTH_ARR_SIZE] = {
+ {0xED, 0x49, 0x43, 0x30},
+ {0x1A0, 0x76, 0x6B, 0x48},
+ {0x22F, 0x9A, 0x56, 0x56},
+ {0x42F, 0x11A, 0x96, 0x96},
+ {0x82F, 0x21A, 0x116, 0x116},
+ {0x102F, 0x41A, 0x216, 0x216}
+};
+
+/*
+ * TxLink Replay Timer Latency Table
+ * See Fire PRM 2.0 sections 1.2.12.3, table 1-18.
+ */
+int px_replay_timer_table[LINK_MAX_PKT_ARR_SIZE][LINK_WIDTH_ARR_SIZE] = {
+ {0x379, 0x112, 0xFC, 0xB4},
+ {0x618, 0x1BA, 0x192, 0x10E},
+ {0x831, 0x242, 0x143, 0x143},
+ {0xFB1, 0x422, 0x233, 0x233},
+ {0x1EB0, 0x7E1, 0x412, 0x412},
+ {0x3CB0, 0xF61, 0x7D2, 0x7D2}
+};
+/*
* px_lib_map_registers
*
* This function is called from the attach routine to map the registers
@@ -2605,3 +2630,80 @@ px_lib_get_bdf(px_t *px_p)
return (bdf);
}
+
+/*ARGSUSED*/
+int
+px_lib_get_root_complex_mps(px_t *px_p, dev_info_t *dip, int *mps)
+{
+ pxu_t *pxu_p;
+ caddr_t csr_base;
+
+ pxu_p = (pxu_t *)px_p->px_plat_p;
+
+ if (pxu_p == NULL)
+ return (DDI_FAILURE);
+
+ csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR];
+
+
+ *mps = CSR_XR(csr_base, TLU_DEVICE_CAPABILITIES) &
+ TLU_DEVICE_CAPABILITIES_MPS_MASK;
+
+ return (DDI_SUCCESS);
+}
+
+/*ARGSUSED*/
+int
+px_lib_set_root_complex_mps(px_t *px_p, dev_info_t *dip, int mps)
+{
+ pxu_t *pxu_p;
+ caddr_t csr_base;
+ uint64_t dev_ctrl;
+ int link_width, val;
+ px_chip_type_t chip_type = px_identity_init(px_p);
+
+ pxu_p = (pxu_t *)px_p->px_plat_p;
+
+ if (pxu_p == NULL)
+ return (DDI_FAILURE);
+
+ csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR];
+
+ dev_ctrl = CSR_XR(csr_base, TLU_DEVICE_CONTROL);
+ dev_ctrl |= (mps << TLU_DEVICE_CONTROL_MPS);
+
+ CSR_XS(csr_base, TLU_DEVICE_CONTROL, dev_ctrl);
+
+ link_width = CSR_FR(csr_base, TLU_LINK_STATUS, WIDTH);
+
+ /*
+ * Convert link_width to match timer array configuration.
+ */
+ switch (link_width) {
+ case 1:
+ link_width = 0;
+ break;
+ case 4:
+ link_width = 1;
+ break;
+ case 8:
+ link_width = 2;
+ break;
+ case 16:
+ link_width = 3;
+ break;
+ default:
+ link_width = 0;
+ }
+
+ val = px_replay_timer_table[mps][link_width];
+ CSR_XS(csr_base, LPU_TXLINK_REPLAY_TIMER_THRESHOLD, val);
+
+ if (chip_type == PX_CHIP_OBERON)
+ return (DDI_SUCCESS);
+
+ val = px_acknak_timer_table[mps][link_width];
+ CSR_XS(csr_base, LPU_TXLINK_FREQUENT_NAK_LATENCY_TIMER_THRESHOLD, val);
+
+ return (DDI_SUCCESS);
+}
diff --git a/usr/src/uts/sun4v/Makefile.files b/usr/src/uts/sun4v/Makefile.files
index 6582e2e8de..4055ca40a2 100644
--- a/usr/src/uts/sun4v/Makefile.files
+++ b/usr/src/uts/sun4v/Makefile.files
@@ -23,8 +23,6 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
# This Makefile defines all file modules for the directory uts/sun4v
# and it's children. These are the source files which are sun4u
# "implementation architecture" dependent.
@@ -115,7 +113,7 @@ SPECIAL_OBJS += intrq.o
# driver modules
#
ROOTNEX_OBJS += mach_rootnex.o
-PX_OBJS += px_lib4v.o px_err.o px_tools_4v.o px_hcall.o
+PX_OBJS += px_lib4v.o px_err.o px_tools_4v.o px_hcall.o px_libhv.o
FPC_OBJS += fpc-impl-4v.o fpc-asm-4v.o
N2PIUPC_OBJS += n2piupc.o n2piupc_tables.o n2piupc_kstats.o \
n2piupc_biterr.o n2piupc_asm.o
diff --git a/usr/src/uts/sun4v/io/px/px_lib4v.c b/usr/src/uts/sun4v/io/px/px_lib4v.c
index ae9cded6de..2301ccf2b4 100644
--- a/usr/src/uts/sun4v/io/px/px_lib4v.c
+++ b/usr/src/uts/sun4v/io/px/px_lib4v.c
@@ -1994,3 +1994,25 @@ px_lib_get_bdf(px_t *px_p)
{
return (0x0000);
}
+
+int
+px_lib_get_root_complex_mps(px_t *px_p, dev_info_t *dip, int *mps)
+{
+ pci_device_t bdf = px_lib_get_bdf(px_p);
+
+ if (hvio_get_rp_mps_cap(DIP_TO_HANDLE(dip), bdf, mps) == H_EOK)
+ return (DDI_SUCCESS);
+ else
+ return (DDI_FAILURE);
+}
+
+int
+px_lib_set_root_complex_mps(px_t *px_p, dev_info_t *dip, int mps)
+{
+ pci_device_t bdf = px_lib_get_bdf(px_p);
+
+ if (hvio_set_rp_mps(DIP_TO_HANDLE(dip), bdf, mps) == H_EOK)
+ return (DDI_SUCCESS);
+ else
+ return (DDI_FAILURE);
+}
diff --git a/usr/src/uts/sun4v/io/px/px_lib4v.h b/usr/src/uts/sun4v/io/px/px_lib4v.h
index 5dfb4a7e94..637c9f4872 100644
--- a/usr/src/uts/sun4v/io/px/px_lib4v.h
+++ b/usr/src/uts/sun4v/io/px/px_lib4v.h
@@ -19,15 +19,13 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_PX_LIB4V_H
#define _SYS_PX_LIB4V_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -183,6 +181,10 @@ extern uint64_t hvio_peek(devhandle_t dev_hdl, r_addr_t ra, size_t size,
uint32_t *status, uint64_t *data_p);
extern uint64_t hvio_poke(devhandle_t dev_hdl, r_addr_t ra, size_t size,
uint64_t data, pci_device_t bdf, uint32_t *wrt_stat);
+extern uint64_t hvio_get_rp_mps_cap(devhandle_t dev_hdl, pci_device_t bdf,
+ int32_t *mps_cap);
+extern uint64_t hvio_set_rp_mps(devhandle_t dev_hdl, pci_device_t bdf,
+ int32_t mps);
/*
* Priviledged physical access:
diff --git a/usr/src/uts/sun4v/io/px/px_libhv.c b/usr/src/uts/sun4v/io/px/px_libhv.c
new file mode 100644
index 0000000000..7d15b1caf2
--- /dev/null
+++ b/usr/src/uts/sun4v/io/px/px_libhv.c
@@ -0,0 +1,135 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/ddi.h>
+#include <sys/async.h>
+#include <sys/sunddi.h>
+#include <sys/ddifm.h>
+#include <sys/fm/protocol.h>
+#include <sys/vmem.h>
+#include <sys/intr.h>
+#include <sys/ivintr.h>
+#include <sys/errno.h>
+#include <sys/hypervisor_api.h>
+#include <sys/hsvc.h>
+#include <px_obj.h>
+#include <sys/machsystm.h>
+#include "px_lib4v.h"
+
+#define MPS_SET 0
+#define MPS_GET 1
+
+static uint64_t hvio_rp_mps(devhandle_t dev_hdl, pci_device_t bdf, int32_t *mps,
+ int op);
+
+uint64_t
+hvio_get_rp_mps_cap(devhandle_t dev_hdl, pci_device_t bdf, int32_t *mps_cap)
+{
+ return (hvio_rp_mps(dev_hdl, bdf, mps_cap, MPS_GET));
+}
+
+uint64_t
+hvio_set_rp_mps(devhandle_t dev_hdl, pci_device_t bdf, int32_t mps)
+{
+ return (hvio_rp_mps(dev_hdl, bdf, &mps, MPS_SET));
+}
+
+uint64_t
+hvio_rp_mps(devhandle_t dev_hdl, pci_device_t bdf, int32_t *mps, int op)
+{
+ uint32_t data;
+ uint32_t hdr, hdr_next_ptr, hdr_cap_id;
+ uint16_t offset = PCI_CONF_STAT;
+ int deadcount = 0;
+ pci_cfg_data_t dataw;
+
+ if ((hvio_config_get(dev_hdl, bdf, PCI_CONF_VENID, 4,
+ (pci_cfg_data_t *)&data)) != H_EOK)
+ return (H_ENOACCESS);
+
+ if ((data & 0xffff) != 0x108e)
+ return (H_ENOACCESS);
+
+ if ((hvio_config_get(dev_hdl, bdf, PCI_CONF_COMM, 4,
+ (pci_cfg_data_t *)&hdr)) != H_EOK)
+ return (H_ENOACCESS);
+
+ if (!(hdr & (PCI_STAT_CAP << 16)))
+ return (H_ENOACCESS);
+
+ (void) hvio_config_get(dev_hdl, bdf, PCI_CONF_CAP_PTR, 4,
+ (pci_cfg_data_t *)&hdr);
+
+ hdr_next_ptr = hdr & 0xFF;
+ hdr_cap_id = 0;
+
+ while ((hdr_next_ptr != PCI_CAP_NEXT_PTR_NULL) &&
+ (hdr_cap_id != PCI_CAP_ID_PCI_E)) {
+
+ offset = hdr_next_ptr;
+
+ if (hdr_next_ptr < 0x40)
+ break;
+
+ (void) hvio_config_get(dev_hdl, bdf, hdr_next_ptr, 4,
+ (pci_cfg_data_t *)&hdr);
+
+ hdr_next_ptr = (hdr >> 8) & 0xFF;
+ hdr_cap_id = hdr & 0xFF;
+
+ if (deadcount++ > 100)
+ break;
+ }
+
+ if (hdr_cap_id != PCI_CAP_ID_PCI_E)
+ return (H_ENOACCESS);
+
+ if (op == MPS_SET) {
+
+ /* Write the MPS */
+
+ (void) hvio_config_get(dev_hdl, bdf, offset + PCIE_DEVCTL,
+ 4, (pci_cfg_data_t *)&data);
+
+ data = (data & 0xffffff1f) | (*mps << 5);
+
+ dataw.qw = (uint32_t)data;
+
+ (void) hvio_config_put(dev_hdl, bdf, offset + PCIE_DEVCTL,
+ 4, dataw);
+ } else {
+
+ /* Read the MPS Capabilities */
+
+ (void) hvio_config_get(dev_hdl, bdf, offset + PCIE_DEVCAP,
+ 4, (pci_cfg_data_t *)&data);
+
+ *mps = data & 0x7;
+ }
+
+ return (H_EOK);
+}