diff options
author | Alan Adamson, SD OSSD <Alan.Adamson@Sun.COM> | 2008-09-15 10:45:20 -0700 |
---|---|---|
committer | Alan Adamson, SD OSSD <Alan.Adamson@Sun.COM> | 2008-09-15 10:45:20 -0700 |
commit | 0114761d17f41c0b83189e4bf95e6b789e7ba99e (patch) | |
tree | 4fd16ad5d3b3f4cc747faf57ee734e898fef7f04 | |
parent | 02c8f3f039188ad827739e040dd0e6f6de8fd943 (diff) | |
download | illumos-joyent-0114761d17f41c0b83189e4bf95e6b789e7ba99e.tar.gz |
6449810 PCI Express framework performance enhancement
-rw-r--r-- | usr/src/uts/common/io/pcie.c | 354 | ||||
-rw-r--r-- | usr/src/uts/common/sys/pcie.h | 4 | ||||
-rw-r--r-- | usr/src/uts/common/sys/pcie_impl.h | 14 | ||||
-rw-r--r-- | usr/src/uts/sun4/io/px/px.c | 48 | ||||
-rw-r--r-- | usr/src/uts/sun4/io/px/px_debug.h | 7 | ||||
-rw-r--r-- | usr/src/uts/sun4/io/px/px_lib.h | 7 | ||||
-rw-r--r-- | usr/src/uts/sun4u/io/px/px_hlib.c | 35 | ||||
-rw-r--r-- | usr/src/uts/sun4u/io/px/px_lib4u.c | 102 | ||||
-rw-r--r-- | usr/src/uts/sun4v/Makefile.files | 4 | ||||
-rw-r--r-- | usr/src/uts/sun4v/io/px/px_lib4v.c | 22 | ||||
-rw-r--r-- | usr/src/uts/sun4v/io/px/px_lib4v.h | 8 | ||||
-rw-r--r-- | usr/src/uts/sun4v/io/px/px_libhv.c | 135 |
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)®, &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); +} |