diff options
author | Corey Swenson <cswenson@us.ibm.com> | 2014-09-08 15:56:45 -0500 |
---|---|---|
committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2014-10-17 14:12:26 -0500 |
commit | c9cf241bc97ff6aba866d6acf167fd910a0f39c5 (patch) | |
tree | 37f0ddf358ee5cf5aff393ceee9d3aafb4887f72 | |
parent | 1428a1fabd827dcc8b43fd0039bfc75d2712c190 (diff) | |
download | talos-hostboot-c9cf241bc97ff6aba866d6acf167fd910a0f39c5.tar.gz talos-hostboot-c9cf241bc97ff6aba866d6acf167fd910a0f39c5.zip |
BMC: VPD Caching in PNOR
For MVPD CVPD SPD, during presence detect VPD part number and
serial number are compared between PNOR and SEEPROM. Mismatch
triggers copy of VPD from SEEPROM to PNOR.
Change-Id: Ia0a7b3fdf80bc15aee05c1303efa406fffa318ce
RTC: 106885
Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/13233
Tested-by: Jenkins Server
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
25 files changed, 1710 insertions, 306 deletions
diff --git a/src/include/usr/devicefw/userif.H b/src/include/usr/devicefw/userif.H index 38cad8ea6..69d334634 100644 --- a/src/include/usr/devicefw/userif.H +++ b/src/include/usr/devicefw/userif.H @@ -37,6 +37,7 @@ #ifndef PARSER #include <stdint.h> #include <errl/errlentry.H> +#include <vpd/vpd_if.H> #include <targeting/common/targetservice.H> #endif // not PARSER @@ -98,7 +99,18 @@ namespace DeviceFW * by the device driver. */ #define DEVICE_SPD_ADDRESS( i_keyword )\ - DeviceFW::SPD, static_cast<uint64_t>(( i_keyword )) + DEVICE_SPD_FORCE_ADDRESS( i_keyword, VPD::AUTOSELECT ) + + /** + * Construct the device addressing parameters for the SPD device ops. + * @param[in] i_keyword - The keyword enumeration value to be accessed + * by the device driver. + * @param[in] i_location - The location to be used for + * accessing the keyword (PNOR/SEEPROM). + */ + #define DEVICE_SPD_FORCE_ADDRESS( i_keyword, i_location )\ + DeviceFW::SPD, static_cast<uint64_t>(( i_keyword )),\ + static_cast<uint64_t>(( i_location)) /** * Construct the device addressing parameters for the MAILBOX device. @@ -115,8 +127,20 @@ namespace DeviceFW * within the i_record Record to access. */ #define DEVICE_MVPD_ADDRESS( i_record, i_keyword )\ + DEVICE_MVPD_FORCE_ADDRESS( i_record, i_keyword, VPD::AUTOSELECT ) + + /** + * Construct the device addressing parameters for the MVPD device ops. + * @param[in] i_record - The enumeration of the MVPD record to access. + * @param[in] i_keyword - The enumeration of the MVPD keyword, located + * within the i_record Record to access. + * @param[in] i_location - The location of the data (PNOR/SEEPROM) + see vpd_if.H + */ + #define DEVICE_MVPD_FORCE_ADDRESS( i_record, i_keyword, i_location )\ DeviceFW::MVPD, static_cast<uint64_t>(( i_record )),\ - static_cast<uint64_t>(( i_keyword )) + static_cast<uint64_t>(( i_keyword )),\ + static_cast<uint64_t>(( i_location )) /** * Construct the device addressing parameters for the CVPD device ops. @@ -125,8 +149,20 @@ namespace DeviceFW * within the i_record Record to access. */ #define DEVICE_CVPD_ADDRESS( i_record, i_keyword )\ + DEVICE_CVPD_FORCE_ADDRESS( i_record, i_keyword, VPD::AUTOSELECT ) + + /** + * Construct the device addressing parameters for the CVPD device ops. + * @param[in] i_record - The enumeration of the CVPD record to access. + * @param[in] i_keyword - The enumeration of the CVPD keyword, located + * within the i_record Record to access. + * @param[in] i_location - The location of the data (PNOR/SEEPROM) + see vpd_if.H + */ + #define DEVICE_CVPD_FORCE_ADDRESS( i_record, i_keyword, i_location )\ DeviceFW::CVPD, static_cast<uint64_t>(( i_record )),\ - static_cast<uint64_t>(( i_keyword )) + static_cast<uint64_t>(( i_keyword )),\ + static_cast<uint64_t>(( i_location )) /** * Construct the device addressing parameters for the SCAN device ops. diff --git a/src/include/usr/fsi/fsi_reasoncodes.H b/src/include/usr/fsi/fsi_reasoncodes.H index c69085db0..de8930940 100644 --- a/src/include/usr/fsi/fsi_reasoncodes.H +++ b/src/include/usr/fsi/fsi_reasoncodes.H @@ -5,7 +5,9 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* COPYRIGHT International Business Machines Corp. 2011,2014 */ +/* Contributors Listed Below - COPYRIGHT 2011,2014 */ +/* [+] International Business Machines Corp. */ +/* */ /* */ /* Licensed under the Apache License, Version 2.0 (the "License"); */ /* you may not use this file except in compliance with the License. */ diff --git a/src/include/usr/vpd/mvpdenums.H b/src/include/usr/vpd/mvpdenums.H index 5186d9e20..668dc8cc1 100644 --- a/src/include/usr/vpd/mvpdenums.H +++ b/src/include/usr/vpd/mvpdenums.H @@ -5,7 +5,9 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* COPYRIGHT International Business Machines Corp. 2013,2014 */ +/* Contributors Listed Below - COPYRIGHT 2013,2014 */ +/* [+] International Business Machines Corp. */ +/* */ /* */ /* Licensed under the Apache License, Version 2.0 (the "License"); */ /* you may not use this file except in compliance with the License. */ diff --git a/src/include/usr/vpd/spdenums.H b/src/include/usr/vpd/spdenums.H index 43465e01d..fdd6ce530 100644 --- a/src/include/usr/vpd/spdenums.H +++ b/src/include/usr/vpd/spdenums.H @@ -5,7 +5,9 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* COPYRIGHT International Business Machines Corp. 2013,2014 */ +/* Contributors Listed Below - COPYRIGHT 2013,2014 */ +/* [+] International Business Machines Corp. */ +/* */ /* */ /* Licensed under the Apache License, Version 2.0 (the "License"); */ /* you may not use this file except in compliance with the License. */ diff --git a/src/include/usr/vpd/vpd_if.H b/src/include/usr/vpd/vpd_if.H index 6c216edcf..af8e501d5 100644 --- a/src/include/usr/vpd/vpd_if.H +++ b/src/include/usr/vpd/vpd_if.H @@ -29,30 +29,64 @@ namespace VPD { /** - * Load the runtime VPD image into memory + * @brief typdef for vpdRecord values + */ + typedef uint32_t vpdRecord; + /** + * @brief typdef for vpdKeyword values + */ + typedef uint32_t vpdKeyword; + /** + * @brief typdef for vpdCmdTarget values + */ + enum vpdCmdTarget + { + AUTOSELECT, + PNOR, + SEEPROM, + INVALID_LOCATION = 0xFFFF, + }; + + /** + * @brief Load the runtime VPD image into memory * @param[out] The physical address of the VPD image * @return error handle if there was an error */ errlHndl_t vpd_load_rt_image(uint64_t & o_vpd_addr); /** - * @brief this function checks to see if the given mvpd target - * is present - * + * @brief This function checks to see if the given mvpd target + * is present * @param[in] i_target - Target device to search for mvpd - * * @return bool - true if mvpd is present, false if it is not. */ bool mvpdPresent ( TARGETING::Target * i_target ); /** - * @brief this function checks to see if the given cvpd target - * is present - * + * @brief This function checks to see if the given cvpd target + * is present * @param[in] i_target - Target device to search for cvpd - * * @return bool - true if cvpd is present, false if it is not. */ bool cvpdPresent ( TARGETING::Target * i_target ); + + /** + * @brief This function checks if the PNOR cache for this target is in + * sync with the SEEPROM, if not it loads the PNOR cache from SEEPROM. + * @param[in] i_target - Target device + * @return errlHndl_t - NULL if successful, otherwise a pointer to the + * error log. + */ + errlHndl_t ensureCacheIsInSync ( TARGETING::Target * i_target ); + + /** + * @brief This function invalidates the VPD data in the PNOR cache. + * @param[in] i_target - Target device + * @return errlHndl_t - NULL if successful, otherwise a pointer to the + * error log. + */ + errlHndl_t invalidatePnorCache ( TARGETING::Target * i_target ); + }; //end vpd namespace + #endif diff --git a/src/include/usr/vpd/vpdreasoncodes.H b/src/include/usr/vpd/vpdreasoncodes.H index 435d30ab3..4ac5361b9 100644 --- a/src/include/usr/vpd/vpdreasoncodes.H +++ b/src/include/usr/vpd/vpdreasoncodes.H @@ -46,6 +46,8 @@ enum vpdModuleId VPD_INVALID_MODULE = 0x00, // Common VPD + VPD_WRITE_PNOR = 0x10, + VPD_ENSURE_CACHE_IS_IN_SYNC = 0x11, // IPVPD VPD_IPVPD_TRANSLATE_RECORD = 0x20, @@ -72,6 +74,7 @@ enum vpdModuleId VPD_SPD_GET_KEYWORD_ENTRY = 0x6C, VPD_SPD_WRITE_DATA = 0x6D, VPD_SPD_GET_MOD_TYPE = 0x6E, + VPD_SPD_FETCH_DATA = 0x6F, // Centaur FRU VPD @@ -121,7 +124,9 @@ enum vpdReasonCode VPD_INSUFFICIENT_SPACE_FOR_IMAGE = VPD_COMP_ID | 0x1b, VPD_MBOX_NOT_SUPPORTED_RT = VPD_COMP_ID | 0x1c, VPD_RECORD_INVALID_VHDR = VPD_COMP_ID | 0x30, - VPD_READ_CONFIG_NOT_SET = VPD_COMP_ID | 0x31, + VPD_READ_SOURCE_UNRESOLVED = VPD_COMP_ID | 0x31, + VPD_REMOVE_PAGES_FAIL = VPD_COMP_ID | 0x32, + VPD_UNEXPECTED_TARGET_TYPE = VPD_COMP_ID | 0x33, }; diff --git a/src/usr/fsi/fsipres.C b/src/usr/fsi/fsipres.C index dfc74c6a6..e47b67e7d 100644 --- a/src/usr/fsi/fsipres.C +++ b/src/usr/fsi/fsipres.C @@ -35,7 +35,6 @@ #include <targeting/common/predicates/predicatectm.H> #include <config.h> - extern trace_desc_t* g_trac_fsi; @@ -69,6 +68,7 @@ errlHndl_t procPresenceDetect(DeviceFW::OperationType i_opType, va_list i_args) { errlHndl_t l_errl = NULL; + uint32_t l_saved_plid = 0; if (unlikely(io_buflen < sizeof(bool))) { @@ -109,24 +109,50 @@ errlHndl_t procPresenceDetect(DeviceFW::OperationType i_opType, } // Next look for valid Module VPD + bool mvpd_present = false; bool check_for_mvpd = true; + #ifdef CONFIG_MVPD_READ_FROM_HW check_for_mvpd = fsi_present; -#endif // CONFIG_MVPD_READ_FROM_HW - - bool mvpd_present = false; +#endif if ( check_for_mvpd ) { mvpd_present = VPD::mvpdPresent( i_target ); } +#if defined(CONFIG_MVPD_READ_FROM_HW) && defined(CONFIG_MVPD_READ_FROM_PNOR) + if( mvpd_present ) + { + // Check if the VPD data in the PNOR matches the SEEPROM + l_errl = VPD::ensureCacheIsInSync( i_target ); + if( l_errl ) + { + // Save this plid to use later + l_saved_plid = l_errl->plid(); + mvpd_present = false; + + TRACFCOMP(g_trac_fsi,ERR_MRK "FSI::procPresenceDetect> Error during ensureCacheIsInSync (MVPD)" ); + errlCommit( l_errl, FSI_COMP_ID ); + } + } + else + { + // Invalidate MVPD in the PNOR + l_errl = VPD::invalidatePnorCache(i_target); + if (l_errl) + { + TRACFCOMP( g_trac_fsi, "Error invalidating MVPD in PNOR" ); + errlCommit( l_errl, FSI_COMP_ID ); + } + } +#endif // Finally compare the 2 methods if( fsi_present != mvpd_present ) { - TRACFCOMP(g_trac_fsi, - ERR_MRK "FSI::procPresenceDetect> FSI (=%d) and MVPD (=%d) do not agree for %.8X", + TRACFCOMP(g_trac_fsi, ERR_MRK "FSI::procPresenceDetect> " + "FSI (=%d) and MVPD (=%d) do not agree for %.8X", fsi_present, mvpd_present, TARGETING::get_huid(i_target)); /*@ * @errortype @@ -153,15 +179,20 @@ errlHndl_t procPresenceDetect(DeviceFW::OperationType i_opType, HWAS::GARD_NULL ); + // If there is a saved PLID, apply it to this error log + if (l_saved_plid) + { + l_errl->plid(l_saved_plid); + } + // Add FFDC for the target to an error log getFsiFFDC( FFDC_PRESENCE_FAIL, l_errl, i_target); - // Add FSI and VPD trace l_errl->collectTrace("FSI"); l_errl->collectTrace("VPD"); - // commit this log and move on + // Commit this log and move on errlCommit( l_errl, FSI_COMP_ID ); } @@ -200,6 +231,7 @@ errlHndl_t membPresenceDetect(DeviceFW::OperationType i_opType, va_list i_args) { errlHndl_t l_errl = NULL; + uint32_t l_saved_plid = 0; if (unlikely(io_buflen < sizeof(bool))) { @@ -227,24 +259,51 @@ errlHndl_t membPresenceDetect(DeviceFW::OperationType i_opType, bool fsi_present = isSlavePresent(i_target); // Next look for memb FRU VPD + bool cvpd_present = false; bool check_for_cvpd = true; + #ifdef CONFIG_CVPD_READ_FROM_HW check_for_cvpd = fsi_present; -#endif // CONFIG_CVPD_READ_FROM_HW - - bool cvpd_present = false; +#endif if ( check_for_cvpd ) { cvpd_present = VPD::cvpdPresent( i_target ); } +#if defined(CONFIG_CVPD_READ_FROM_HW) && defined(CONFIG_CVPD_READ_FROM_PNOR) + if( cvpd_present ) + { + // Check if the VPD data in the PNOR matches the SEEPROM + l_errl = VPD::ensureCacheIsInSync( i_target ); + if( l_errl ) + { + // Save this plid to use later + l_saved_plid = l_errl->plid(); + cvpd_present = false; + + TRACFCOMP(g_trac_fsi,ERR_MRK "FSI::procPresenceDetect> Error during ensureCacheIsInSync (CVPD)" ); + errlCommit( l_errl, FSI_COMP_ID ); + } + } + else + { + // FSI is not present, invalidate MVPD in the PNOR + l_errl = VPD::invalidatePnorCache(i_target); + if (l_errl) + { + TRACFCOMP( g_trac_fsi, "Error invalidating MVPD in PNOR" ); + errlCommit( l_errl, FSI_COMP_ID ); + } + } +#endif + // Finally compare the 2 methods if( fsi_present != cvpd_present ) { - TRACFCOMP(g_trac_fsi, - ERR_MRK "FSI::membPresenceDetect> FSI (=%d) and VPD (=%d) do not agree for %.8X", + TRACFCOMP(g_trac_fsi, ERR_MRK "FSI::membPresenceDetect> " + "FSI (=%d) and VPD (=%d) do not agree for %.8X", fsi_present, cvpd_present, TARGETING::get_huid(i_target)); /*@ * @errortype @@ -271,6 +330,12 @@ errlHndl_t membPresenceDetect(DeviceFW::OperationType i_opType, HWAS::GARD_NULL ); + // If there is a saved PLID, apply it to this error log + if (l_saved_plid) + { + l_errl->plid(l_saved_plid); + } + // Add FFDC for the target to an error log getFsiFFDC( FFDC_PRESENCE_FAIL, l_errl, i_target); diff --git a/src/usr/hwpf/hwp/mc_config/mc_config.C b/src/usr/hwpf/hwp/mc_config/mc_config.C index 80c03f475..d6c649333 100644 --- a/src/usr/hwpf/hwp/mc_config/mc_config.C +++ b/src/usr/hwpf/hwp/mc_config/mc_config.C @@ -81,6 +81,7 @@ #ifdef CONFIG_DJVPD_READ_FROM_HW #include <hwas/common/hwas.H> #include <hwas/common/hwasCommon.H> +#include <devicefw/driverif.H> #endif // CONFIG_DJVPD_READ_FROM_HW #ifdef CONFIG_PALMETTO_VDDR @@ -110,31 +111,63 @@ static errlHndl_t detect_present_dimms() { targetService().getAssociated( pCheckPres, pSys, TargetService::CHILD, TargetService::ALL, &predDimm ); - // Actually check for present DIMMs by PNOR or SPD, this function will - // prune missing DIMMs from its argument. - l_err = HWAS::platPresenceDetect(pCheckPres); - - if (l_err != NULL) - { - return l_err; - } - - // Mark remaining DIMMs as present. - // @todo RTC:111211, may need to handle turning the dimms off + // Check for present DIMMs + // @todo RTC:111211, this should be removed when Mike's FSI changes are in for (TargetHandleList::const_iterator pTarget_it = pCheckPres.begin(); pTarget_it != pCheckPres.end(); ++pTarget_it) { - // set HWAS state to show DIMM is present, functional. TARGETING::Target *target = *pTarget_it; - HwasState hwasState = target->getAttr<ATTR_HWAS_STATE>(); - hwasState.poweredOn = true; - hwasState.present = true; - hwasState.functional = true; - target->setAttr<ATTR_HWAS_STATE>( hwasState ); + + + // call deviceRead() to see if they are present + bool present = false; + size_t presentSize = sizeof(present); + l_err = deviceRead(target, &present, presentSize, + DEVICE_PRESENT_ADDRESS()); + + if (l_err != NULL) + { + TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, + "mc_config failed presence detect " + "target HUID %.8X", target->getAttr<ATTR_HUID>()); + + // commit the error but keep going + errlCommit(l_err, HWPF_COMP_ID); + + // target is not present - fall thru + present = false; + } + + if (present == true) + { + TRACDCOMP(ISTEPS_TRACE::g_trac_isteps_trace, + "mc_config detected present " + "target HUID %.8X", target->getAttr<ATTR_HUID>()); + + // set HWAS state to show DIMM is present, functional. + HwasState hwasState = target->getAttr<ATTR_HWAS_STATE>(); + hwasState.poweredOn = true; + hwasState.present = true; + hwasState.functional = true; + target->setAttr<ATTR_HWAS_STATE>( hwasState ); + } + else + { + TRACDCOMP(ISTEPS_TRACE::g_trac_isteps_trace, + "mc_config no presence target %.8X", + target->getAttr<ATTR_HUID>()); + + // set HWAS state to show DIMM is not present, not functional. + HwasState hwasState = target->getAttr<ATTR_HWAS_STATE>(); + hwasState.poweredOn = false; + hwasState.present = false; + hwasState.functional = false; + target->setAttr<ATTR_HWAS_STATE>( hwasState ); + } } - return l_err; + return NULL; } // Disable any MBAs that don't have any DIMMs under them, otherwise @@ -810,7 +843,7 @@ errlHndl_t call_mss_eff_grouping() (const_cast<TARGETING::Target*>(l_cpu_target)) ); TARGETING::TargetHandleList l_membufsList; - getChildAffinityTargets(l_membufsList, l_cpu_target, + getChildAffinityTargets(l_membufsList, l_cpu_target, CLASS_CHIP, TYPE_MEMBUF); std::vector<fapi::Target> l_associated_centaurs; diff --git a/src/usr/targeting/common/xmltohb/attribute_types_hb.xml b/src/usr/targeting/common/xmltohb/attribute_types_hb.xml index 235b19438..ab7df54d6 100644 --- a/src/usr/targeting/common/xmltohb/attribute_types_hb.xml +++ b/src/usr/targeting/common/xmltohb/attribute_types_hb.xml @@ -665,4 +665,31 @@ Final values for the following HTMG attributes will come from the MRW --> </attribute> <!-- end HTMGT attributes --> +<attribute> + <id>VPD_SWITCHES</id> + <description>Attribute storing VPD state information</description> + <complexType> + <description>VPD flags</description> + <field> + <name>pnorLoaded</name> + <description>Set when this target's VPD data has been loaded + into the PNOR. + </description> + <type>uint8_t</type> + <bits>1</bits> + <default>0</default> + </field> + <field> + <name>reserved</name> + <description>Reserved for future expansion</description> + <type>uint8_t</type> + <bits>7</bits> + <default>0</default> + </field> + </complexType> + <persistency>volatile-zeroed</persistency> + <readable/> + <writeable/> +</attribute> + </attributes> diff --git a/src/usr/targeting/common/xmltohb/target_types_hb.xml b/src/usr/targeting/common/xmltohb/target_types_hb.xml index 78f0504e2..fd662b5b6 100644 --- a/src/usr/targeting/common/xmltohb/target_types_hb.xml +++ b/src/usr/targeting/common/xmltohb/target_types_hb.xml @@ -86,6 +86,7 @@ <attribute> <id>HOMER_VIRT_ADDR</id> </attribute> + <attribute><id>VPD_SWITCHES</id></attribute> </targetTypeExtension> <targetTypeExtension> @@ -135,6 +136,7 @@ <attribute> <id>GPIO_INFO</id> </attribute> + <attribute><id>VPD_SWITCHES</id></attribute> </targetTypeExtension> <targetTypeExtension> @@ -144,4 +146,9 @@ </attribute> </targetTypeExtension> +<targetTypeExtension> + <id>lcard-dimm</id> + <attribute><id>VPD_SWITCHES</id></attribute> +</targetTypeExtension> + </attributes> diff --git a/src/usr/vpd/HBconfig b/src/usr/vpd/HBconfig index 76aeb7192..3995b1982 100644 --- a/src/usr/vpd/HBconfig +++ b/src/usr/vpd/HBconfig @@ -24,13 +24,11 @@ config CVPD_WRITE_TO_HW config MVPD_READ_FROM_PNOR default y - depends on !MVPD_READ_FROM_HW help Read Module VPD data from PNOR cache config MVPD_READ_FROM_HW - default y if !MVPD_READ_FROM_PNOR - depends on !MVPD_READ_FROM_PNOR + default n help Read Module VPD data from HW resources @@ -48,13 +46,11 @@ config MVPD_WRITE_TO_HW config DJVPD_READ_FROM_PNOR default y - depends on !DJVPD_READ_FROM_HW help Read Dimm JEDEC VPD/SPD data from PNOR cache config DJVPD_READ_FROM_HW - default y if !DJVPD_READ_FROM_PNOR - depends on !DJVPD_READ_FROM_PNOR + default n help Read Dimm JEDEC VPD/SPD data from HW resources diff --git a/src/usr/vpd/cvpd.C b/src/usr/vpd/cvpd.C index 406511fb7..0febca385 100644 --- a/src/usr/vpd/cvpd.C +++ b/src/usr/vpd/cvpd.C @@ -105,6 +105,7 @@ namespace CVPD IpVpdFacade::input_args_t args; args.record = ((cvpdRecord)va_arg( i_args, uint64_t )); args.keyword = ((cvpdKeyword)va_arg( i_args, uint64_t )); + args.location = ((VPD::vpdCmdTarget)va_arg( i_args, uint64_t )); TRACSSCOMP( g_trac_vpd, ENTER_MRK"cvpdRead()" ); @@ -157,6 +158,7 @@ namespace CVPD IpVpdFacade::input_args_t args; args.record = ((cvpdRecord)va_arg( i_args, uint64_t )); args.keyword = ((cvpdKeyword)va_arg( i_args, uint64_t )); + args.location = ((VPD::vpdCmdTarget)va_arg( i_args, uint64_t )); TRACSSCOMP( g_trac_vpd, ENTER_MRK"cvpdWrite()" ); diff --git a/src/usr/vpd/dimmPres.C b/src/usr/vpd/dimmPres.C index 32042fe6b..ca8b3f149 100755 --- a/src/usr/vpd/dimmPres.C +++ b/src/usr/vpd/dimmPres.C @@ -107,7 +107,8 @@ errlHndl_t dimmPresenceDetect( DeviceFW::OperationType i_opType, * @moduleid VPD::VPD_SPD_PRESENCE_DETECT * @userdata1 Buffer Length * @userdata2 <UNUSED> - * @devdesc Buffer for checking Presence Detect was not the correct size. + * @devdesc Buffer for checking Presence Detect + * was not the correct size. */ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, VPD::VPD_SPD_PRESENCE_DETECT, @@ -137,9 +138,17 @@ errlHndl_t dimmPresenceDetect( DeviceFW::OperationType i_opType, if ( membuf_parent.size() != 1 ) { present = false; + + // Invalidate the SPD in PNOR + err = VPD::invalidatePnorCache(i_target); + if (err) + { + TRACFCOMP( g_trac_spd, "Error invalidating SPD in PNOR" ); + } break; } #endif + present = spdPresent( i_target ); if( present == false ) @@ -153,6 +162,29 @@ errlHndl_t dimmPresenceDetect( DeviceFW::OperationType i_opType, INFO_MRK"Dimm was found to be present." ); } +#if defined(CONFIG_DJVPD_READ_FROM_HW) && defined(CONFIG_DJVPD_READ_FROM_PNOR) + if( present ) + { + // Check if the VPD data in the PNOR matches the SEEPROM + err = VPD::ensureCacheIsInSync( i_target ); + if( err ) + { + present = false; + + TRACFCOMP(g_trac_spd,ERR_MRK "dimmPresenceDetectt> Error during ensureCacheIsInSync (SPD)" ); + break; + } + } + else + { + // SPD is not present, invalidate the SPD in PNOR + err = VPD::invalidatePnorCache(i_target); + if (err) + { + TRACFCOMP( g_trac_spd, "Error invalidating SPD in PNOR" ); + } + } +#endif // copy present value into output buffer so caller can read it memcpy( io_buffer, &present, presentSz ); io_buflen = presentSz; diff --git a/src/usr/vpd/ipvpd.C b/src/usr/vpd/ipvpd.C index ed61de47a..f1ef73053 100644 --- a/src/usr/vpd/ipvpd.C +++ b/src/usr/vpd/ipvpd.C @@ -62,7 +62,11 @@ extern trace_desc_t* g_trac_vpd; // Globals // ---------------------------------------------- -static const uint64_t IPVPD_TOC_SIZE = 0x100; +static const uint64_t IPVPD_TOC_SIZE = 0x100; //256 +static const uint64_t IPVPD_TOC_ENTRY_SIZE = 8; +static const uint64_t IPVPD_TOC_INVALID_DATA = 0xFFFFFFFFFFFFFFFF; +static const uint32_t IPVPD_MAX_ENTRY_SIZE = (64 * 1024); + /** * @brief Constructor @@ -112,7 +116,6 @@ errlHndl_t IpVpdFacade::read ( TARGETING::Target * i_target, do { - // Get the Record/keyword names err = translateRecord(i_args.record, recordName); @@ -138,7 +141,6 @@ errlHndl_t IpVpdFacade::read ( TARGETING::Target * i_target, recordOffset, i_target, i_args ); - if( err ) { break; @@ -261,9 +263,322 @@ errlHndl_t IpVpdFacade::write ( TARGETING::Target * i_target, } // ------------------------------------------------------------------ +// IpVpdFacade::cmpPnorToSeeprom +// ------------------------------------------------------------------ +errlHndl_t IpVpdFacade::cmpPnorToSeeprom ( TARGETING::Target * i_target, + VPD::vpdRecord i_record, + VPD::vpdKeyword i_keyword, + bool &o_match ) +{ + errlHndl_t l_err = NULL; + + TRACSSCOMP( g_trac_vpd, ENTER_MRK"cmpPnorToSeeprom() " ); + + o_match = false; + + input_args_t l_pnorArgs; + l_pnorArgs.record = i_record; + l_pnorArgs.keyword = i_keyword; + l_pnorArgs.location = VPD::PNOR; + + input_args_t l_seepromArgs; + l_seepromArgs.record = i_record; + l_seepromArgs.keyword = i_keyword; + l_seepromArgs.location = VPD::SEEPROM; + + do + { + // Get the PNOR size + size_t l_sizePnor = 0; + l_err = read( i_target, + NULL, + l_sizePnor, + l_pnorArgs ); + if( l_err || (l_sizePnor == 0) ) + { + // PNOR may not be loaded, ignore the error + delete l_err; + l_err = NULL; + break; + } + + // Get the PNOR data + uint8_t l_dataPnor[l_sizePnor]; + l_err = read( i_target, + l_dataPnor, + l_sizePnor, + l_pnorArgs ); + if( l_err ) + { + break; + } + + // Get the SEEPROM size + size_t l_sizeSeeprom = 0; + l_err = read( i_target, + NULL, + l_sizeSeeprom, + l_seepromArgs ); + if( l_err || (l_sizeSeeprom == 0) ) + { + break; + } + + // Get the SEEPROM data + uint8_t l_dataSeeprom[l_sizeSeeprom]; + l_err = read( i_target, + l_dataSeeprom, + l_sizeSeeprom, + l_seepromArgs ); + if( l_err ) + { + break; + } + + // Compare the PNOR/SEEPROM size/data + if( l_sizePnor != l_sizeSeeprom ) + { + break; + } + if( memcmp( l_dataPnor, + l_dataSeeprom, + l_sizePnor ) != 0 ) + { + break; + } + + o_match = true; + + } while(0); + + TRACSSCOMP( g_trac_vpd, EXIT_MRK"cmpPnorToSeeprom()" ); + + return l_err; +} + +/* IPVPD PNOR FORMAT + |-----------------------------------------------------------|----| + |TOC0|TOC1|...........................................|TOC31| | + |-----------------------------------------------------------|TARG0 + |REC1DATA|.........................................|RECNDATA|64K | + |-----------------------------------------------------------|----| + |TOC0|TOC1|...........................................|TOC31| | + |-----------------------------------------------------------|TARG1 + |REC1DATA|.........................................|RECNDATA|64K | + |-----------------------------------------------------------|----| + |TOC0|TOC1|...........................................|TOC31| | + |-----------------------------------------------------------|TARG2 + |REC1DATA|.........................................|RECNDATA|64K | + |-----------------------------------------------------------|----| + ---- Till TARGN +*/ + +// ------------------------------------------------------------------ +// IpVpdFacade::loadPnor +// ------------------------------------------------------------------ +errlHndl_t IpVpdFacade::loadPnor ( TARGETING::Target * i_target ) +{ + errlHndl_t err = NULL; + + TRACSSCOMP( g_trac_vpd, ENTER_MRK"IpVpdFacade::loadPnor()" ); + + // Load PNOR TOC with invalid data + err = invalidatePnor( i_target ); + if( err ) + { + TRACFCOMP(g_trac_vpd, + "IpVpdFacade::loadPnor() Error invalidating PNOR Target %.8X", + TARGETING::get_huid(i_target)); + return err; + } + + // Temp data for entire VPD entry + uint8_t* tmpVpdPtr = new uint8_t[IPVPD_MAX_ENTRY_SIZE]; + + // Load the temp data with invalid TOC + uint64_t tocdata = IPVPD_TOC_INVALID_DATA; + for( uint32_t tocoffset = 0; + tocoffset < IPVPD_TOC_SIZE; + tocoffset += IPVPD_TOC_ENTRY_SIZE ) + { + memcpy( (tmpVpdPtr + tocoffset), + &tocdata, + IPVPD_TOC_ENTRY_SIZE ); + } + + // Load PNOR cache from SEEPROM + // Variables starting with p=PNOR, s=SEEPROM + + // Table of contents + tocData pTocEntry; + uint16_t pTocOffset = 0; + + // Records + uint16_t sRecOffset = 0; + uint16_t sRecLength = 0; + uint16_t pRecOffset = IPVPD_TOC_SIZE; // Records begin after TOC + input_args_t sRecArgs; + sRecArgs.location = VPD::SEEPROM; + + // Loop through all possible record types + for( uint32_t rec = 0; rec < iv_recSize; rec++ ) + { + sRecArgs.record = iv_vpdRecords[rec].record; + // Read the record offset from SEEPROM + err = findRecordOffsetSeeprom ( iv_vpdRecords[rec].recordName, + sRecOffset, + sRecLength, + i_target, + sRecArgs ); + if( err ) + { + TRACDCOMP(g_trac_vpd,"IpVpdFacade::loadPnor() " + "Did not find SEEPROM record %d recordName %s", + iv_vpdRecords[rec].record, iv_vpdRecords[rec].recordName); + // Not all records will be found, don't log the error + // @todo RTC 115944 Need specific list of records to check here + delete err; + err = NULL; + } + else + { + // Copy the record name to the toc structure asciiRec + memcpy( pTocEntry.asciiRec, + iv_vpdRecords[rec].recordName, + RECORD_BYTE_SIZE ); + + // Swap the bytes to match SEEPROM VPD format + pTocEntry.offset[0] = ((uint8_t*)(&pRecOffset))[1]; + pTocEntry.offset[1] = ((uint8_t*)(&pRecOffset))[0]; + + // Just a signature after every TOC entry + pTocEntry.unusedByte[0] = 0x5A; + pTocEntry.unusedByte[1] = 0x5A; + + // Write TOC to temp data + memcpy( (tmpVpdPtr + pTocOffset), + &pTocEntry, + IPVPD_TOC_ENTRY_SIZE ); + + // Read record data from SEEPROM, put it into temp data + uint8_t* pRecPtr = tmpVpdPtr + pRecOffset; + err = fetchData( sRecOffset, + sRecLength, + pRecPtr, + i_target, + sRecArgs.location ); + if( err ) + { + TRACFCOMP(g_trac_vpd,"IpVpdFacade::loadPnor() " + "Error reading record data, record %d recordName %s", + iv_vpdRecords[rec].record, + iv_vpdRecords[rec].recordName); + break; + } + + // Increment the PNOR TOC and record offsets + pTocOffset += IPVPD_TOC_ENTRY_SIZE; + pRecOffset += sRecLength; + } + } + + if( !err ) + { + // Setup info needed to write PNOR + VPD::pnorInformation pInfo; + pInfo.segmentSize = iv_vpdSectionSize; + pInfo.maxSegments = iv_vpdMaxSections; + pInfo.pnorSection = iv_pnorSection; + + // Write the entire PNOR entry + err = VPD::writePNOR( 0x0, // start offset + pRecOffset, // size + tmpVpdPtr, // data + i_target, + pInfo, + iv_cachePnorAddr, + &iv_mutex ); + if( err ) + { + TRACFCOMP(g_trac_vpd,"IpVpdFacade::loadPnor() " + "Error writing PNOR VPD data"); + } + } + else + { + // Error reading record data, invalidate the TOC + // Use different errl so we don't overwrite the original + errlHndl_t invErr = NULL; + invErr = invalidatePnor( i_target ); + if( invErr ) + { + TRACFCOMP(g_trac_vpd,"IpVpdFacade::loadPnor() " + "Error invalidating PNOR Target %.8X", + TARGETING::get_huid(i_target)); + delete invErr; + invErr = NULL; + } + } + + TRACSSCOMP( g_trac_vpd, EXIT_MRK"IpVpdFacade::loadPnor()" ); + + return err; +} + + +// ------------------------------------------------------------------ +// IpVpdFacade::invalidatePnor +// ------------------------------------------------------------------ +errlHndl_t IpVpdFacade::invalidatePnor ( TARGETING::Target * i_target ) +{ + errlHndl_t err = NULL; + + TRACSSCOMP( g_trac_vpd, ENTER_MRK"IpVpdFacade::invalidatePnor()" ); + + // Setup info needed to write PNOR + VPD::pnorInformation pInfo; + pInfo.segmentSize = iv_vpdSectionSize; + pInfo.maxSegments = iv_vpdMaxSections; + pInfo.pnorSection = iv_pnorSection; + + // Temp data for entire TOC + uint8_t* tmpTocPtr = new uint8_t[IPVPD_TOC_SIZE]; + + // Load the temp data with invalid TOC + uint64_t tocdata = IPVPD_TOC_INVALID_DATA; + for( uint32_t tocoffset = 0; + tocoffset < IPVPD_TOC_SIZE; + tocoffset += IPVPD_TOC_ENTRY_SIZE ) + { + memcpy( (tmpTocPtr + tocoffset), + &tocdata, + IPVPD_TOC_ENTRY_SIZE ); + } + + // Write the entire PNOR TOC + err = VPD::writePNOR( 0x0, // start offset + IPVPD_TOC_SIZE, // size + tmpTocPtr, // data + i_target, + pInfo, + iv_cachePnorAddr, + &iv_mutex ); + if( err ) + { + TRACFCOMP(g_trac_vpd, + "IpVpdFacade::invalidatePnor() Error writing PNOR TOC"); + return err; + } + + TRACSSCOMP( g_trac_vpd, EXIT_MRK"IpVpdFacade::invalidatePnor()" ); + + return err; +} + +// ------------------------------------------------------------------ // IpVpdFacade::translateRecord // ------------------------------------------------------------------ -errlHndl_t IpVpdFacade::translateRecord ( ipVpdRecord i_record, +errlHndl_t IpVpdFacade::translateRecord ( VPD::vpdRecord i_record, const char *& o_record ) { errlHndl_t err = NULL; @@ -284,8 +599,8 @@ errlHndl_t IpVpdFacade::translateRecord ( ipVpdRecord i_record, if( ( entry == &iv_vpdRecords[iv_recSize] )|| ( i_record != entry->record ) ) { - TRACFCOMP( g_trac_vpd, - ERR_MRK"IpVpdFacade::translateRecord: No matching Record (0x%04x) found!", + TRACFCOMP( g_trac_vpd, ERR_MRK"IpVpdFacade::translateRecord: " + "No matching Record (0x%04x) found!", i_record ); /*@ @@ -324,7 +639,7 @@ errlHndl_t IpVpdFacade::translateRecord ( ipVpdRecord i_record, // ------------------------------------------------------------------ // IpVpdFacade::translateKeyword // ------------------------------------------------------------------ -errlHndl_t IpVpdFacade::translateKeyword ( ipVpdKeyword i_keyword, +errlHndl_t IpVpdFacade::translateKeyword ( VPD::vpdKeyword i_keyword, const char *& o_keyword ) { errlHndl_t err = NULL; @@ -345,8 +660,8 @@ errlHndl_t IpVpdFacade::translateKeyword ( ipVpdKeyword i_keyword, if( ( entry == &iv_vpdKeywords[iv_keySize] ) || ( i_keyword != entry->keyword ) ) { - TRACFCOMP( g_trac_vpd, - ERR_MRK"IpVpdFacade::translateKeyword: No matching Keyword found!" ); + TRACFCOMP( g_trac_vpd, ERR_MRK"IpVpdFacade::translateKeyword: " + "No matching Keyword found!" ); /*@ * @errortype @@ -386,6 +701,7 @@ errlHndl_t IpVpdFacade::translateKeyword ( ipVpdKeyword i_keyword, return err; } + // ------------------------------------------------------------------ // IpVpdFacade::findRecordOffset // ------------------------------------------------------------------ @@ -396,38 +712,64 @@ errlHndl_t IpVpdFacade::findRecordOffset ( const char * i_record, { errlHndl_t err = NULL; - if ( iv_configInfo.vpdReadPNOR ) + // Determine the VPD source (PNOR/SEEPROM) + VPD::vpdCmdTarget vpdSource = VPD::AUTOSELECT; + bool configError = false; + configError = VPD::resolveVpdSource( i_target, + iv_configInfo.vpdReadPNOR, + iv_configInfo.vpdReadHW, + i_args.location, + vpdSource ); + // Get the record offset + if ( vpdSource == VPD::PNOR ) { - return findRecordOffsetPnor(i_record, o_offset, i_target, i_args); + err = findRecordOffsetPnor(i_record, o_offset, i_target, i_args); } - else if ( iv_configInfo.vpdReadHW ) + else if ( vpdSource == VPD::SEEPROM ) { - return findRecordOffsetSeeprom(i_record, o_offset, i_target, i_args); + uint16_t o_length; + err = findRecordOffsetSeeprom(i_record, + o_offset, + o_length, + i_target, + i_args); } else { - TRACFCOMP( g_trac_vpd, - ERR_MRK"IpVpdFacade::findRecordOffset:vpdReadPNOR and vpdReadHW false!"); + configError = true; + } + + if( configError ) + { + TRACFCOMP( g_trac_vpd, ERR_MRK"IpVpdFacade::findRecordOffset: " + "Error resolving VPD source (PNOR/SEEPROM)"); /*@ * @errortype - * @reasoncode VPD::VPD_READ_CONFIG_NOT_SET + * @reasoncode VPD::VPD_READ_SOURCE_UNRESOLVED * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE * @moduleid VPD::VPD_IPVPD_FIND_RECORD_OFFSET - * @userdata1 Target HUID - * @userdata2 <UNUSED> - * @devdesc Both VPD read PNOR and VPD read HW - * configs are set to false + * @userdata1[0:31] Target HUID + * @userdata1[32:63] Requested VPD Source Location + * @userdata2[0:31] CONFIG_<vpd>_READ_FROM_PNOR + * @userdata2[32:63] CONFIG_<vpd>_READ_FROM_HW + * @devdesc Unable to resolve the VPD + * source (PNOR or SEEPROM) */ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, VPD::VPD_IPVPD_FIND_RECORD_OFFSET, - VPD::VPD_READ_CONFIG_NOT_SET, - TARGETING::get_huid(i_target), - 0x0, + VPD::VPD_READ_SOURCE_UNRESOLVED, + TWO_UINT32_TO_UINT64( + TARGETING::get_huid(i_target), + i_args.location ), + TWO_UINT32_TO_UINT64( + iv_configInfo.vpdReadPNOR, + iv_configInfo.vpdReadHW ), true /*Add HB SW Callout*/ ); err->collectTrace( "VPD", 256 ); } - return NULL; + + return err; } @@ -436,8 +778,8 @@ errlHndl_t IpVpdFacade::findRecordOffset ( const char * i_record, // IpVpdFacade::hasVpdPresent // ------------------------------------------------------------------ bool IpVpdFacade::hasVpdPresent( TARGETING::Target * i_target, - uint64_t i_record, - uint64_t i_keyword ) + VPD::vpdRecord i_record, + VPD::vpdRecord i_keyword ) { errlHndl_t err = NULL; uint16_t recordOffset = 0x0; @@ -510,39 +852,41 @@ bool IpVpdFacade::recordPresent( const char * i_record, // 8 bytes per entry - 32 entries possible // Entry: // byte 0 - 3: ASCII Record Name - // byte 4 - 5: Size (byte swapped) + // byte 4 - 5: OFFSET (byte swapped) // byte 6 - 7: UNUSED // -------------------------------------- while( ( tmpOffset < IPVPD_TOC_SIZE ) && !matchFound ) { - //Read Record Name - err = fetchData( tmpOffset, - RECORD_BYTE_SIZE, - record, - i_target ); - tmpOffset += RECORD_BYTE_SIZE; + //Read Record Name + err = fetchData( tmpOffset, + RECORD_BYTE_SIZE, + record, + i_target, + VPD::AUTOSELECT ); + tmpOffset += RECORD_BYTE_SIZE; + + if( err ) + { + break; + } + if( !(memcmp(record, i_record, RECORD_BYTE_SIZE )) ) + { + matchFound = true; + + // Read the matching record's offset + err = fetchData( tmpOffset, + RECORD_ADDR_BYTE_SIZE, + &o_offset, + i_target, + VPD::AUTOSELECT ); if( err ) { break; } - - if( !(memcmp(record, i_record, RECORD_BYTE_SIZE )) ) - { - matchFound = true; - - // Read the matching record's offset - err = fetchData( tmpOffset, - RECORD_ADDR_BYTE_SIZE, - &o_offset, - i_target ); - if( err ) - { - break; - } - } - tmpOffset += (RECORD_ADDR_BYTE_SIZE + RECORD_TOC_UNUSED); + } + tmpOffset += (RECORD_ADDR_BYTE_SIZE + RECORD_TOC_UNUSED); } if( err ) @@ -580,9 +924,8 @@ errlHndl_t IpVpdFacade::findRecordOffsetPnor ( const char * i_record, if( !matchFound ) { - TRACFCOMP( g_trac_vpd, - ERR_MRK"IpVpdFacade::findRecordOffset: No matching\ - Record (%s) found in TOC!", + TRACFCOMP( g_trac_vpd, ERR_MRK"IpVpdFacade::findRecordOffsetPnor: " + "No matching Record (%s) found in TOC!", i_record ); /*@ @@ -622,7 +965,7 @@ errlHndl_t IpVpdFacade::findRecordOffsetPnor ( const char * i_record, o_offset = le16toh( offset ); TRACSSCOMP( g_trac_vpd, - EXIT_MRK"IpVpdFacade::findRecordOffset()" ); + EXIT_MRK"IpVpdFacade::findRecordOffsetPnor()" ); return err; } @@ -632,6 +975,7 @@ errlHndl_t IpVpdFacade::findRecordOffsetPnor ( const char * i_record, // ------------------------------------------------------------------ errlHndl_t IpVpdFacade::findRecordOffsetSeeprom ( const char * i_record, uint16_t & o_offset, + uint16_t & o_length, TARGETING::Target * i_target, input_args_t i_args ) { @@ -658,8 +1002,8 @@ errlHndl_t IpVpdFacade::findRecordOffsetSeeprom ( const char * i_record, (memcmp(toc_rec->record_name, "VTOC", sizeof(toc_rec->record_name)) != 0)) { - TRACFCOMP( g_trac_vpd, - ERR_MRK"IpVpdFacade::findRecordOffset: VHDR is invalid!"); + TRACFCOMP( g_trac_vpd, ERR_MRK"IpVpdFacade::findRecordOffsetSeeprom: " + "VHDR is invalid!"); /*@ * @errortype @@ -670,11 +1014,12 @@ errlHndl_t IpVpdFacade::findRecordOffsetSeeprom ( const char * i_record, * @userdata2 Target HUID * @devdesc The VHDR was invalid */ - err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, - VPD::VPD_IPVPD_FIND_RECORD_OFFSET_SEEPROM, - VPD::VPD_RECORD_INVALID_VHDR, - pt_len, - TARGETING::get_huid(i_target) ); + err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + VPD::VPD_IPVPD_FIND_RECORD_OFFSET_SEEPROM, + VPD::VPD_RECORD_INVALID_VHDR, + pt_len, + TARGETING::get_huid(i_target) ); // Could be the VPD of the target wasn't set up properly // -- DECONFIG so that we can possibly keep booting @@ -718,6 +1063,7 @@ errlHndl_t IpVpdFacade::findRecordOffsetSeeprom ( const char * i_record, { // Byte swap field on output, skip 'large resource' byte o_offset = le16toh( toc_rec->record_offset ) + 1; + o_length = le16toh( toc_rec->record_length ); found = true; break; } @@ -739,13 +1085,14 @@ errlHndl_t IpVpdFacade::findRecordOffsetSeeprom ( const char * i_record, * @userdata2 Target HUID * @devdesc The requested record was not found in the VPD VTOC. */ - err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, - VPD::VPD_IPVPD_FIND_RECORD_OFFSET_SEEPROM, - VPD::VPD_RECORD_NOT_FOUND, - TWO_UINT32_TO_UINT64(i_args.record, - i_args.keyword), - TARGETING::get_huid(i_target) ); - + err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + VPD::VPD_IPVPD_FIND_RECORD_OFFSET_SEEPROM, + VPD::VPD_RECORD_NOT_FOUND, + TWO_UINT32_TO_UINT64(i_args.record, + i_args.keyword), + TARGETING::get_huid(i_target) ); + // Could be the VPD of the target wasn't set up properly // -- DECONFIG so that we can possibly keep booting err->addHwCallout( i_target, @@ -822,7 +1169,8 @@ errlHndl_t IpVpdFacade::retrieveKeyword ( const char * i_keywordName, err = fetchData( i_offset+byteAddr, keywordSize, io_buffer, - i_target ); + i_target, + i_args.location ); if( err ) { break; @@ -845,42 +1193,65 @@ errlHndl_t IpVpdFacade::retrieveKeyword ( const char * i_keywordName, errlHndl_t IpVpdFacade::fetchData ( uint64_t i_byteAddr, size_t i_numBytes, void * o_data, - TARGETING::Target * i_target ) + TARGETING::Target * i_target, + VPD::vpdCmdTarget i_location ) { errlHndl_t err = NULL; - if ( iv_configInfo.vpdReadPNOR ) + // Determine the VPD source (PNOR/SEEPROM) + VPD::vpdCmdTarget vpdSource = VPD::AUTOSELECT; + bool configError = false; + configError = VPD::resolveVpdSource( i_target, + iv_configInfo.vpdReadPNOR, + iv_configInfo.vpdReadHW, + i_location, + vpdSource ); + + // Get the data + if ( vpdSource == VPD::PNOR ) { - return fetchDataFromPnor( i_byteAddr, i_numBytes, o_data, i_target ); + err = fetchDataFromPnor( i_byteAddr, i_numBytes, o_data, i_target ); } - else if ( iv_configInfo.vpdReadHW ) + else if ( vpdSource == VPD::SEEPROM ) { - return fetchDataFromEeprom( i_byteAddr, i_numBytes, o_data, i_target ); + err = fetchDataFromEeprom( i_byteAddr, i_numBytes, o_data, i_target ); } else { - TRACFCOMP( g_trac_vpd, - ERR_MRK"IpVpdFacade::fetchData:vpdReadPNOR and vpdReadHW false!"); + configError = true; + } + + if( configError ) + { + TRACFCOMP( g_trac_vpd, ERR_MRK"IpVpdFacade::fetchData: " + "Error resolving VPD source (PNOR/SEEPROM)"); /*@ * @errortype - * @reasoncode VPD::VPD_READ_CONFIG_NOT_SET + * @reasoncode VPD::VPD_READ_SOURCE_UNRESOLVED * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE * @moduleid VPD::VPD_IPVPD_FETCH_DATA - * @userdata1 Target HUID - * @userdata2 <UNUSED> - * @devdesc Both VPD read PNOR and VPD read HW - * configs are set to false + * @userdata1[0:31] Target HUID + * @userdata1[32:63] Requested VPD Source Location + * @userdata2[0:31] CONFIG_<vpd>_READ_FROM_PNOR + * @userdata2[32:63] CONFIG_<vpd>_READ_FROM_HW + * @devdesc Unable to resolve the VPD + * source (PNOR or SEEPROM) */ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, VPD::VPD_IPVPD_FETCH_DATA, - VPD::VPD_READ_CONFIG_NOT_SET, - TARGETING::get_huid(i_target), - 0x0, + VPD::VPD_READ_SOURCE_UNRESOLVED, + TWO_UINT32_TO_UINT64( + TARGETING::get_huid(i_target), + i_location ), + TWO_UINT32_TO_UINT64( + iv_configInfo.vpdReadPNOR, + iv_configInfo.vpdReadHW ), true /*Add HB SW Callout*/ ); err->collectTrace( "VPD", 256 ); } - return NULL; + + return err; } // ------------------------------------------------------------------ @@ -892,10 +1263,8 @@ errlHndl_t IpVpdFacade::fetchDataFromPnor ( uint64_t i_byteAddr, TARGETING::Target * i_target ) { errlHndl_t err = NULL; - TRACSSCOMP( g_trac_vpd, ENTER_MRK"IpVpdFacade::fetchDataFromPnor()" ); - do { // Call a function in the common VPD code @@ -932,7 +1301,6 @@ errlHndl_t IpVpdFacade::fetchDataFromEeprom ( uint64_t i_byteAddr, TARGETING::Target * i_target ) { errlHndl_t err = NULL; - TRACSSCOMP( g_trac_vpd, ENTER_MRK"IpVpdFacade::fetchDataFromEeprom()" ); @@ -987,9 +1355,9 @@ errlHndl_t IpVpdFacade::findKeywordAddr ( const char * i_keywordName, err = fetchData( offset, RECORD_ADDR_BYTE_SIZE, &recordSize, - i_target ); + i_target, + i_args.location ); offset += RECORD_ADDR_BYTE_SIZE; - if( err ) { break; @@ -1004,7 +1372,8 @@ errlHndl_t IpVpdFacade::findKeywordAddr ( const char * i_keywordName, err = fetchData( offset, RECORD_BYTE_SIZE, record, - i_target ); + i_target, + i_args.location ); offset += RECORD_BYTE_SIZE; if( err ) @@ -1014,8 +1383,9 @@ errlHndl_t IpVpdFacade::findKeywordAddr ( const char * i_keywordName, if( memcmp( record, i_recordName, RECORD_BYTE_SIZE ) ) { - TRACFCOMP( g_trac_vpd, - ERR_MRK"IpVpdFacade::findKeywordAddr: Record(%s) for offset (0x%04x) did not match expected record(%s)!", + TRACFCOMP( g_trac_vpd, ERR_MRK"IpVpdFacade::findKeywordAddr: " + "Record(%s) for offset (0x%04x) did not match " + "expected record(%s)!", record, i_offset, i_recordName ); @@ -1062,15 +1432,16 @@ errlHndl_t IpVpdFacade::findKeywordAddr ( const char * i_keywordName, // 2 bytes for the size value. while( ( offset < (recordSize + i_offset + RECORD_ADDR_BYTE_SIZE) ) ) { - TRACDCOMP( g_trac_vpd, - INFO_MRK"IpVpdFacade::findKeywordAddr: Looking for keyword, reading offset: 0x%04x", + TRACDCOMP( g_trac_vpd, INFO_MRK"IpVpdFacade::findKeywordAddr: " + "Looking for keyword, reading offset: 0x%04x", offset ); // read keyword name (2 bytes) err = fetchData( offset, KEYWORD_BYTE_SIZE, keyword, - i_target ); + i_target, + i_args.location ); offset += KEYWORD_BYTE_SIZE; if( err ) @@ -1078,8 +1449,8 @@ errlHndl_t IpVpdFacade::findKeywordAddr ( const char * i_keywordName, break; } - TRACDCOMP( g_trac_vpd, - INFO_MRK"IpVpdFacade::findKeywordAddr: Read keyword name: %s", + TRACDCOMP( g_trac_vpd, INFO_MRK"IpVpdFacade::findKeywordAddr: " + "Read keyword name: %s", keyword ); // Check if we're reading a '#' keyword. They have a 2 byte size @@ -1087,8 +1458,8 @@ errlHndl_t IpVpdFacade::findKeywordAddr ( const char * i_keywordName, bool isPoundKwd = false; if( !(memcmp( keyword, "#", 1 )) ) { - TRACDCOMP( g_trac_vpd, - INFO_MRK"IpVpdFacade::findKeywordAddr: Reading # keyword, adding 1 byte to size to read!" ); + TRACDCOMP( g_trac_vpd, INFO_MRK"IpVpdFacade::findKeywordAddr: " + "Reading # keyword, adding 1 byte to size to read!"); isPoundKwd = true; keywordLength++; } @@ -1097,7 +1468,8 @@ errlHndl_t IpVpdFacade::findKeywordAddr ( const char * i_keywordName, err = fetchData( offset, keywordLength, &keywordSize, - i_target ); + i_target, + i_args.location ); offset += keywordLength; if( err ) @@ -1115,8 +1487,8 @@ errlHndl_t IpVpdFacade::findKeywordAddr ( const char * i_keywordName, keywordSize = keywordSize >> 8; } - TRACDCOMP( g_trac_vpd, - INFO_MRK"IpVpdFacade::findKeywordAddr: Read keyword size: 0x%04x", + TRACDCOMP( g_trac_vpd, INFO_MRK"IpVpdFacade::findKeywordAddr: " + "Read keyword size: 0x%04x", keywordSize ); // if keyword equal i_keywordName @@ -1131,6 +1503,8 @@ errlHndl_t IpVpdFacade::findKeywordAddr ( const char * i_keywordName, if ( matchesFound == i_index + 1 ) { break; } + // set offset to next keyword (based on current keyword size) + offset += keywordSize; } else { @@ -1150,8 +1524,8 @@ errlHndl_t IpVpdFacade::findKeywordAddr ( const char * i_keywordName, if( matchesFound != i_index + 1 && NULL == err ) { - TRACFCOMP( g_trac_vpd, - ERR_MRK"IpVpdFacade::findKeywordAddr: No matching %s keyword found within %s record!", + TRACFCOMP( g_trac_vpd, ERR_MRK"IpVpdFacade::findKeywordAddr: " + "No matching %s keyword found within %s record!", i_keywordName, i_recordName ); @@ -1317,8 +1691,8 @@ errlHndl_t IpVpdFacade::checkBufferSize( size_t i_bufferSize, if( !(i_bufferSize >= i_expectedSize) ) { - TRACFCOMP( g_trac_vpd, - ERR_MRK"IpVpdFacade::checkBufferSize: Buffer size (%d) is not larger than expected size (%d)", + TRACFCOMP( g_trac_vpd, ERR_MRK"IpVpdFacade::checkBufferSize: " + "Buffer size (%d) is not larger than expected size (%d)", i_bufferSize, i_expectedSize ); diff --git a/src/usr/vpd/ipvpd.H b/src/usr/vpd/ipvpd.H index d59e84608..7b01f86a4 100644 --- a/src/usr/vpd/ipvpd.H +++ b/src/usr/vpd/ipvpd.H @@ -37,7 +37,7 @@ /** * @brief Base class for i/p-Series VPD - * + * */ class IpVpdFacade { @@ -59,7 +59,7 @@ class IpVpdFacade }; /** - * @brief Structure representing the format of each record + * @brief Structure representing the format of each record * in the PT keyword of the VTOC or VHDR. */ struct TocPtRecord { @@ -73,21 +73,13 @@ class IpVpdFacade } PACKED; /** - * @brief typdef for ipVpdRecord values - */ - typedef uint32_t ipVpdRecord; - /** - * @brief typdef for ipVpdKeyword values - */ - typedef uint32_t ipVpdKeyword; - - /** * @brief Structure for all VPD dd input parameter arguments */ typedef struct { - ipVpdRecord record; - ipVpdKeyword keyword; + VPD::vpdRecord record; + VPD::vpdKeyword keyword; + VPD::vpdCmdTarget location; } input_args_t; /** @@ -96,7 +88,7 @@ class IpVpdFacade */ typedef struct { - ipVpdRecord record; + VPD::vpdRecord record; char recordName[RECORD_BYTE_SIZE+1]; } recordInfo; @@ -104,7 +96,7 @@ class IpVpdFacade */ typedef struct { - ipVpdKeyword keyword; + VPD::vpdKeyword keyword; char keywordName[KEYWORD_BYTE_SIZE+1]; } keywordInfo; @@ -120,6 +112,23 @@ class IpVpdFacade } configInfo; /** + * @brief - Data Struct for TOC Entry + */ + struct tocData + { + tocData() + { + bzero(asciiRec, sizeof(asciiRec)); + bzero(offset, sizeof(offset)); + bzero(unusedByte, sizeof(unusedByte)); + } + + uint8_t asciiRec[RECORD_BYTE_SIZE]; + uint8_t offset[RECORD_ADDR_BYTE_SIZE]; + uint8_t unusedByte[RECORD_ADDR_BYTE_SIZE]; + }; + + /** * @brief Constructor * * @param[in] i_vpdSectionSize - Space allocated in PNOR for each @@ -219,9 +228,51 @@ class IpVpdFacade * @return - bool - true if vpd is present, false if it is not. */ bool hasVpdPresent ( TARGETING::Target * i_target, - uint64_t record, - uint64_t keyword ); + VPD::vpdRecord record, + VPD::vpdKeyword keyword ); + /** + * @brief This function compares the specified record/keyword + * in PNOR/SEEPROM and returns the result. A mismatch + * will not return an error. + * + * @param[in] i_target - Target device + * + * @param[in] i_record - Record to compare + * + * @param[in] i_keyword - Keyword to compare + * + * @param[out] o_match - Result of compare + * + * @return errlHndl_t - NULL if successful, otherwise a pointer to the + * error log. + */ + errlHndl_t cmpPnorToSeeprom ( TARGETING::Target * i_target, + VPD::vpdRecord i_record, + VPD::vpdKeyword i_keyword, + bool &o_match ); + + /** + * @brief This function will perform the steps required to load the + * MVPD data from SEEPROM into the PNOR cache. + * + * @param[in] i_target - Target device + * + * @return errlHndl_t - NULL if successful, otherwise a pointer to the + * error log. + */ + errlHndl_t loadPnor ( TARGETING::Target * i_target ); + + /** + * @brief This function will perform the steps required to invalidate + * the MVPD in the PNOR cache. + * + * @param[in] i_target - Target device + * + * @return errlHndl_t - NULL if successful, otherwise a pointer to the + * error log. + */ + errlHndl_t invalidatePnor ( TARGETING::Target * i_target ); protected: @@ -237,7 +288,7 @@ class IpVpdFacade * @return errHndl_t - NULL if successful, otherwise a pointer to the * error log. */ - errlHndl_t translateRecord ( ipVpdRecord i_record, + errlHndl_t translateRecord ( VPD::vpdRecord i_record, const char *& o_record ); /** @@ -252,7 +303,7 @@ class IpVpdFacade * @return errHndl_t - NULL if successful, otherwise a pointer to the * error log. */ - errlHndl_t translateKeyword ( ipVpdKeyword i_keyword, + errlHndl_t translateKeyword ( VPD::vpdKeyword i_keyword, const char *& o_keyword ); /** @@ -322,6 +373,8 @@ class IpVpdFacade * * @param[out] o_offset - The offset where the record is located. * + * @param[out] o_length - The length of the record. + * * @param[in] i_target - The target to retrieve the data for. * * @param[in] i_args - The input arguments. @@ -331,6 +384,7 @@ class IpVpdFacade */ errlHndl_t findRecordOffsetSeeprom ( const char * i_record, uint16_t & o_offset, + uint16_t & o_length, TARGETING::Target * i_target, input_args_t i_args ); @@ -385,7 +439,7 @@ class IpVpdFacade * * @param[in] i_buflen - Length of the buffer to be written * to the target's VPD area. This value should indicate the - * size of the io_buffer parameter that has been allocated. + * size of the io_buffer parameter that has been allocated. * * @param[in] i_args - The input arguments. * @@ -433,7 +487,7 @@ class IpVpdFacade size_t& o_keywordSize, uint64_t& o_byteAddr, input_args_t i_args ); - + /** * @brief This function calls the PNOR or EEPROM version of * the fetchData function based on the configInfo @@ -446,13 +500,16 @@ class IpVpdFacade * * @param[in] i_target - Target device. * + * @param[in] i_location - VPD location to fetch data from (PNOR/SEEPROM) + * * @return errHndl_t - NULL if successful, otherwise a pointer to the * error log. */ errlHndl_t fetchData ( uint64_t i_byteAddr, size_t i_numBytes, void * o_data, - TARGETING::Target * i_target ); + TARGETING::Target * i_target, + VPD::vpdCmdTarget i_location ); /** * @brief This function actually reads the data from PNOR @@ -504,7 +561,7 @@ class IpVpdFacade * @return bool - Whether or not the e2 value is larger than the e1 value. */ static bool compareKeywords ( const keywordInfo e1, - const keywordInfo e2 ); + const keywordInfo e2 ); /** * @brief This function compares 2 vpd keyword values. Used for binary @@ -517,7 +574,7 @@ class IpVpdFacade * @return bool - Whether or not the e2 value is larger than the e1 value. */ static bool compareRecords ( const recordInfo e1, - const recordInfo e2 ); + const recordInfo e2 ); /** * @brief This function compares sizes to be sure buffers are large enough @@ -554,25 +611,25 @@ class IpVpdFacade /** * @brief Pointer to array of VPD Record information - * + * */ const recordInfo* iv_vpdRecords; /** * @brief Number of VPD Records for current chip - * + * */ uint64_t iv_recSize; /** * @brief Pointer to array of VPD Keyword information - * + * */ const keywordInfo* iv_vpdKeywords; /** * @brief Number of VPD Keywords for current chip - * + * */ uint64_t iv_keySize; @@ -605,6 +662,7 @@ class IpVpdFacade * VPD data */ configInfo iv_configInfo; + }; diff --git a/src/usr/vpd/mvpd.C b/src/usr/vpd/mvpd.C index 6498e2561..9c3d6119f 100644 --- a/src/usr/vpd/mvpd.C +++ b/src/usr/vpd/mvpd.C @@ -103,6 +103,7 @@ namespace MVPD IpVpdFacade::input_args_t args; args.record = ((mvpdRecord)va_arg( i_args, uint64_t )); args.keyword = ((mvpdKeyword)va_arg( i_args, uint64_t )); + args.location = ((VPD::vpdCmdTarget)va_arg( i_args, uint64_t )); TRACSSCOMP( g_trac_vpd, ENTER_MRK"mvpdRead()" ); @@ -156,6 +157,7 @@ namespace MVPD IpVpdFacade::input_args_t args; args.record = ((mvpdRecord)va_arg( i_args, uint64_t )); args.keyword = ((mvpdKeyword)va_arg( i_args, uint64_t )); + args.location = ((VPD::vpdCmdTarget)va_arg( i_args, uint64_t )); TRACSSCOMP( g_trac_vpd, ENTER_MRK"mvpdWrite()" ); @@ -253,3 +255,4 @@ IpVpdFacade(MVPD::SECTION_SIZE, iv_configInfo.vpdWriteHW = false; #endif } + diff --git a/src/usr/vpd/mvpd.H b/src/usr/vpd/mvpd.H index b1b168cc6..591a2a250 100644 --- a/src/usr/vpd/mvpd.H +++ b/src/usr/vpd/mvpd.H @@ -5,7 +5,9 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* COPYRIGHT International Business Machines Corp. 2013,2014 */ +/* Contributors Listed Below - COPYRIGHT 2013,2014 */ +/* [+] International Business Machines Corp. */ +/* */ /* */ /* Licensed under the Apache License, Version 2.0 (the "License"); */ /* you may not use this file except in compliance with the License. */ @@ -159,4 +161,3 @@ class MvpdFacade: public IpVpdFacade }; #endif /* _MVPD_H */ - diff --git a/src/usr/vpd/runtime/rt_vpd.C b/src/usr/vpd/runtime/rt_vpd.C index 23faab34f..d907aee2e 100644 --- a/src/usr/vpd/runtime/rt_vpd.C +++ b/src/usr/vpd/runtime/rt_vpd.C @@ -5,7 +5,9 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* COPYRIGHT International Business Machines Corp. 2013,2014 */ +/* Contributors Listed Below - COPYRIGHT 2013,2014 */ +/* [+] International Business Machines Corp. */ +/* */ /* */ /* Licensed under the Apache License, Version 2.0 (the "License"); */ /* you may not use this file except in compliance with the License. */ @@ -331,4 +333,73 @@ errlHndl_t sendMboxWriteMsg ( size_t i_numBytes, return err; } +// ------------------------------------------------------------------ +// resolveVpdSource +// ------------------------------------------------------------------ +bool resolveVpdSource( TARGETING::Target * i_target, + bool i_readFromPnorEnabled, + bool i_readFromHwEnabled, + vpdCmdTarget i_vpdCmdTarget, + vpdCmdTarget& o_vpdSource ) +{ + bool badConfig = false; + o_vpdSource = VPD::INVALID_LOCATION; + + if( i_vpdCmdTarget == VPD::PNOR ) + { + if( i_readFromPnorEnabled ) + { + o_vpdSource = VPD::PNOR; + } + else + { + badConfig = true; + } + } + else if( i_vpdCmdTarget == VPD::SEEPROM ) + { + if( i_readFromHwEnabled ) + { + o_vpdSource = VPD::SEEPROM; + } + else + { + badConfig = true; + } + } + else + { + if( i_readFromPnorEnabled && + i_readFromHwEnabled ) + { + // PNOR needs to be loaded before we can use it + TARGETING::ATTR_VPD_SWITCHES_type vpdSwitches = + i_target->getAttr<TARGETING::ATTR_VPD_SWITCHES>(); + if( vpdSwitches.pnorLoaded ) + { + o_vpdSource = VPD::PNOR; + } + else + { + o_vpdSource = VPD::SEEPROM; + } + } + else if( i_readFromPnorEnabled ) + { + o_vpdSource = VPD::PNOR; + } + else if( i_readFromHwEnabled ) + { + o_vpdSource = VPD::SEEPROM; + } + else + { + badConfig = true; + } + } + + return badConfig; +} + + }; // end namepsace VPD diff --git a/src/usr/vpd/spd.C b/src/usr/vpd/spd.C index 4480b507c..18d4ed3ad 100755..100644 --- a/src/usr/vpd/spd.C +++ b/src/usr/vpd/spd.C @@ -112,11 +112,14 @@ bool compareEntries ( const KeywordData e1, * * @param[in] i_target - The target to read data from. * + * @param[in] i_location - The SPD source (PNOR/SEEPROM). + * * @return errlHndl_t - NULL if successful, otherwise a pointer * to the error log. */ errlHndl_t getMemType ( uint8_t & o_memType, - TARGETING::Target * i_target ); + TARGETING::Target * i_target, + VPD::vpdCmdTarget i_location ); /** * @brief This function will read the DIMM module type. @@ -127,12 +130,15 @@ errlHndl_t getMemType ( uint8_t & o_memType, * * @param[in] i_memType - The memory type * + * @param[in] i_location - The SPD source (PNOR/SEEPROM). + * * @return errlHndl_t - NULL if successful, otherwise a pointer * to the error log. */ errlHndl_t getModType ( modSpecTypes_t & o_memType, TARGETING::Target * i_target, - uint64_t i_memType ); + uint64_t i_memType, + VPD::vpdCmdTarget i_location ); /** * @brief This function will scan the table and return the entry @@ -149,7 +155,7 @@ errlHndl_t getModType ( modSpecTypes_t & o_memType, * @return errlHndl_t - NULL if successful, otherwise a pointer to * the error log. */ -errlHndl_t getKeywordEntry ( uint64_t i_keyword, +errlHndl_t getKeywordEntry ( VPD::vpdKeyword i_keyword, uint64_t i_memType, TARGETING::Target * i_target, const KeywordData *& o_entry ); @@ -176,7 +182,8 @@ errlHndl_t spdGetKeywordValue ( DeviceFW::OperationType i_opType, va_list i_args ) { errlHndl_t err = NULL; - uint64_t keyword = va_arg( i_args, uint64_t ); + VPD::vpdKeyword keyword = va_arg( i_args, uint64_t ); + VPD::vpdCmdTarget location = (VPD::vpdCmdTarget)va_arg( i_args, uint64_t ); TRACSSCOMP( g_trac_spd, ENTER_MRK"spdGetKeywordValue(), io_buflen: %d, keyword: 0x%04x", @@ -187,7 +194,8 @@ errlHndl_t spdGetKeywordValue ( DeviceFW::OperationType i_opType, // Read the Basic Memory Type uint8_t memType = 0x0; err = getMemType( memType, - i_target ); + i_target, + location ); if( err ) { @@ -214,7 +222,8 @@ errlHndl_t spdGetKeywordValue ( DeviceFW::OperationType i_opType, io_buffer, io_buflen, i_target, - memType ); + memType, + location ); if( err ) { @@ -289,7 +298,9 @@ errlHndl_t spdWriteKeywordValue ( DeviceFW::OperationType i_opType, va_list i_args ) { errlHndl_t err = NULL; - uint64_t keyword = va_arg( i_args, uint64_t ); + VPD::vpdKeyword keyword = va_arg( i_args, uint64_t ); + VPD::vpdCmdTarget location = + (VPD::vpdCmdTarget)va_arg( i_args, uint64_t ); TRACSSCOMP( g_trac_spd, ENTER_MRK"spdWriteKeywordValue()" ); @@ -299,7 +310,8 @@ errlHndl_t spdWriteKeywordValue ( DeviceFW::OperationType i_opType, // Get memory type uint8_t memType = 0x0; err = getMemType( memType, - i_target ); + i_target, + location ); if( err ) { @@ -313,7 +325,8 @@ errlHndl_t spdWriteKeywordValue ( DeviceFW::OperationType i_opType, io_buffer, io_buflen, i_target, - memType ); + memType, + location ); if( err ) { @@ -384,7 +397,8 @@ errlHndl_t spdWriteKeywordValue ( DeviceFW::OperationType i_opType, errlHndl_t spdFetchData ( uint64_t i_byteAddr, size_t i_numBytes, void * o_data, - TARGETING::Target * i_target ) + TARGETING::Target * i_target, + VPD::vpdCmdTarget i_location ) { errlHndl_t err = NULL; @@ -393,18 +407,35 @@ errlHndl_t spdFetchData ( uint64_t i_byteAddr, do { - if( likely( g_usePNOR ) ) + if( unlikely( !g_usePNOR ) ) { + err = spdReadBinaryFile( i_byteAddr, + i_numBytes, + o_data ); + break; + } + + bool readFromPnorEnabled = false; +#ifdef CONFIG_DJVPD_READ_FROM_PNOR + readFromPnorEnabled = true; +#endif + bool readFromHwEnabled = false; #ifdef CONFIG_DJVPD_READ_FROM_HW - // Need to read directly from target's EEPROM. - err = DeviceFW::deviceOp( DeviceFW::READ, - i_target, - o_data, - i_numBytes, - DEVICE_EEPROM_ADDRESS( - EEPROM::VPD_PRIMARY, - i_byteAddr ) ); -#elif CONFIG_DJVPD_READ_FROM_PNOR + readFromHwEnabled = true; +#endif + + // Determine the SPD source (PNOR/SEEPROM) + VPD::vpdCmdTarget vpdSource = VPD::AUTOSELECT; + bool configError = false; + configError = VPD::resolveVpdSource( i_target, + readFromPnorEnabled, + readFromHwEnabled, + i_location, + vpdSource ); + + // Get the data + if ( vpdSource == VPD::PNOR ) + { // Setup info needed to read from PNOR VPD::pnorInformation info; info.segmentSize = DIMM_SPD_SECTION_SIZE; @@ -417,23 +448,61 @@ errlHndl_t spdFetchData ( uint64_t i_byteAddr, info, g_spdPnorAddr, &g_spdMutex ); -#endif // CONFIG_DJVPD_READ_FROM_PNOR if( err ) { break; } } - else + else if ( vpdSource == VPD::SEEPROM ) { - err = spdReadBinaryFile( i_byteAddr, - i_numBytes, - o_data ); - + // Need to read directly from target's EEPROM. + err = DeviceFW::deviceOp( DeviceFW::READ, + i_target, + o_data, + i_numBytes, + DEVICE_EEPROM_ADDRESS( + EEPROM::VPD_PRIMARY, + i_byteAddr ) ); if( err ) { break; } } + else + { + configError = true; + } + + if( configError ) + { + TRACFCOMP( g_trac_spd, ERR_MRK"spdFetchData: " + "Error resolving VPD source (PNOR/SEEPROM)"); + + /*@ + * @errortype + * @reasoncode VPD::VPD_READ_SOURCE_UNRESOLVED + * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE + * @moduleid VPD::VPD_SPD_FETCH_DATA + * @userdata1[0:31] Target HUID + * @userdata1[32:63] Requested VPD Source Location + * @userdata2[0:31] CONFIG_DJVPD_READ_FROM_PNOR + * @userdata2[32:63] CONFIG_DJVPD_READ_FROM_HW + * @devdesc Unable to resolve the VPD + * source (PNOR or SEEPROM) + */ + err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + VPD::VPD_SPD_FETCH_DATA, + VPD::VPD_READ_SOURCE_UNRESOLVED, + TWO_UINT32_TO_UINT64( TARGETING::get_huid(i_target), + i_location ), + TWO_UINT32_TO_UINT64( readFromHwEnabled, + readFromHwEnabled ), + true /*Add HB SW Callout*/ ); + err->collectTrace( "VPD", 256 ); + break; + } + } while( 0 ); TRACSSCOMP( g_trac_spd, @@ -449,7 +518,8 @@ errlHndl_t spdFetchData ( uint64_t i_byteAddr, errlHndl_t spdWriteData ( uint64_t i_offset, size_t i_numBytes, void * i_data, - TARGETING::Target * i_target ) + TARGETING::Target * i_target, + VPD::vpdCmdTarget i_location ) { errlHndl_t err = NULL; @@ -480,8 +550,8 @@ errlHndl_t spdWriteData ( uint64_t i_offset, } else { - TRACFCOMP( g_trac_spd, - ERR_MRK"There is no way to write SPD when not using PNOR!" ); + TRACFCOMP( g_trac_spd, ERR_MRK"spdWriteData: " + "There is no way to write SPD when not using PNOR!" ); /*@ * @errortype @@ -518,11 +588,12 @@ errlHndl_t spdWriteData ( uint64_t i_offset, // ------------------------------------------------------------------ // spdGetValue // ------------------------------------------------------------------ -errlHndl_t spdGetValue ( uint64_t i_keyword, +errlHndl_t spdGetValue ( VPD::vpdKeyword i_keyword, void * io_buffer, size_t & io_buflen, TARGETING::Target * i_target, - uint64_t i_DDRRev ) + uint64_t i_DDRRev, + VPD::vpdCmdTarget i_location ) { errlHndl_t err = NULL; uint8_t * tmpBuffer = static_cast<uint8_t *>(io_buffer); @@ -579,7 +650,8 @@ errlHndl_t spdGetValue ( uint64_t i_keyword, // correct values are in place to actually request it err = checkModSpecificKeyword( (*entry), i_DDRRev, - i_target ); + i_target, + i_location ); if( err ) { @@ -603,7 +675,8 @@ errlHndl_t spdGetValue ( uint64_t i_keyword, err = spdSpecialCases( (*entry), io_buffer, i_target, - i_DDRRev ); + i_DDRRev, + i_location ); if (err) { @@ -616,7 +689,8 @@ errlHndl_t spdGetValue ( uint64_t i_keyword, err = spdFetchData( (*entry).offset, (*entry).length, tmpBuffer, - i_target ); + i_target, + i_location ); if( err ) { @@ -653,11 +727,12 @@ errlHndl_t spdGetValue ( uint64_t i_keyword, // ------------------------------------------------------------------ // spdWriteValue // ------------------------------------------------------------------ -errlHndl_t spdWriteValue ( uint64_t i_keyword, +errlHndl_t spdWriteValue ( VPD::vpdKeyword i_keyword, void * io_buffer, size_t & io_buflen, TARGETING::Target * i_target, - uint64_t i_DDRRev ) + uint64_t i_DDRRev, + VPD::vpdCmdTarget i_location ) { errlHndl_t err = NULL; @@ -758,8 +833,9 @@ errlHndl_t spdWriteValue ( uint64_t i_keyword, if( entry->bitMask ) { // Error if not writable - TRACFCOMP( g_trac_spd, - ERR_MRK"Trying to write keyword (0x%04x) that is not a full byte size", + TRACFCOMP( g_trac_spd, ERR_MRK"spdWriteValue: " + "Trying to write keyword (0x%04x) that is not " + "a full byte size", i_keyword ); /*@ @@ -795,7 +871,8 @@ errlHndl_t spdWriteValue ( uint64_t i_keyword, err = spdWriteData( entry->offset, io_buflen, io_buffer, - i_target ); + i_target, + i_location ); if( err ) { @@ -833,7 +910,7 @@ bool spdPresent ( TARGETING::Target * i_target ) { errlHndl_t err = NULL; bool pres = false; - + TRACSSCOMP( g_trac_spd, ENTER_MRK"spdPresent()" ); @@ -842,7 +919,8 @@ bool spdPresent ( TARGETING::Target * i_target ) // Read the Basic Memory Type uint8_t memType = 0x0; err = getMemType( memType, - i_target ); + i_target, + VPD::AUTOSELECT ); if( err ) { @@ -861,7 +939,7 @@ bool spdPresent ( TARGETING::Target * i_target ) pres = true; } } while( 0 ); - + return pres; } @@ -872,7 +950,8 @@ bool spdPresent ( TARGETING::Target * i_target ) // ------------------------------------------------------------------ errlHndl_t ddr3SpecialCases(const KeywordData & i_kwdData, void * io_buffer, - TARGETING::Target * i_target) + TARGETING::Target * i_target, + VPD::vpdCmdTarget i_location) { errlHndl_t err = NULL; uint8_t * tmpBuffer = static_cast<uint8_t *>(io_buffer); @@ -895,7 +974,8 @@ errlHndl_t ddr3SpecialCases(const KeywordData & i_kwdData, err = spdFetchData( i_kwdData.offset, 1, /* Read 1 byte at a time */ &tmpBuffer[0], - i_target ); + i_target, + i_location ); if( err ) break; @@ -910,7 +990,8 @@ errlHndl_t ddr3SpecialCases(const KeywordData & i_kwdData, err = spdFetchData( (i_kwdData.offset - 1), 1, /* Read 1 byte at a time */ &tmpBuffer[1], - i_target ); + i_target, + i_location ); break; // ================================================== @@ -920,7 +1001,8 @@ errlHndl_t ddr3SpecialCases(const KeywordData & i_kwdData, err = spdFetchData( i_kwdData.offset, 1, /* Read 1 byte at a time */ &tmpBuffer[0], - i_target ); + i_target, + i_location ); if( err ) break; @@ -935,13 +1017,14 @@ errlHndl_t ddr3SpecialCases(const KeywordData & i_kwdData, err = spdFetchData( (i_kwdData.offset + 2), 1, /* Read 1 byte at a time */ &tmpBuffer[1], - i_target ); + i_target, + i_location ); break; // ================================================== default: - TRACFCOMP( g_trac_spd, - ERR_MRK"Unknown keyword (0x%04x) for DDR3 special cases!", + TRACFCOMP( g_trac_spd, ERR_MRK"ddr3SpecialCases: " + "Unknown keyword (0x%04x) for DDR3 special cases!", i_kwdData.keyword ); /*@ @@ -976,7 +1059,8 @@ errlHndl_t ddr3SpecialCases(const KeywordData & i_kwdData, // ------------------------------------------------------------------ errlHndl_t ddr4SpecialCases(const KeywordData & i_kwdData, void * io_buffer, - TARGETING::Target * i_target) + TARGETING::Target * i_target, + VPD::vpdCmdTarget i_location) { errlHndl_t err = NULL; uint8_t * tmpBuffer = static_cast<uint8_t *>(io_buffer); @@ -1003,7 +1087,8 @@ errlHndl_t ddr4SpecialCases(const KeywordData & i_kwdData, err = spdFetchData( i_kwdData.offset, 1, /* Read 1 byte at a time */ &tmpBuffer[0], - i_target ); + i_target, + i_location ); if( err ) break; @@ -1018,7 +1103,8 @@ errlHndl_t ddr4SpecialCases(const KeywordData & i_kwdData, err = spdFetchData( (i_kwdData.offset - 1), 1, /* Read 1 byte at a time */ &tmpBuffer[1], - i_target ); + i_target, + i_location ); break; // ================================================== @@ -1028,7 +1114,8 @@ errlHndl_t ddr4SpecialCases(const KeywordData & i_kwdData, err = spdFetchData( i_kwdData.offset, 1, /* Read 1 byte at a time */ &tmpBuffer[0], - i_target ); + i_target, + i_location ); if( err ) break; @@ -1043,7 +1130,8 @@ errlHndl_t ddr4SpecialCases(const KeywordData & i_kwdData, err = spdFetchData( (i_kwdData.offset + 2), 1, /* Read 1 byte at a time */ &tmpBuffer[1], - i_target ); + i_target, + i_location ); break; // ================================================== @@ -1053,7 +1141,8 @@ errlHndl_t ddr4SpecialCases(const KeywordData & i_kwdData, err = spdFetchData( i_kwdData.offset, 1, /* Read 1 byte at a time */ &tmpBuffer[0], - i_target ); + i_target, + i_location ); if( err ) break; @@ -1061,7 +1150,8 @@ errlHndl_t ddr4SpecialCases(const KeywordData & i_kwdData, err = spdFetchData( (i_kwdData.offset - 1), 1, /* Read 1 byte at a time */ &tmpBuffer[1], - i_target ); + i_target, + i_location ); if( err ) break; @@ -1069,7 +1159,8 @@ errlHndl_t ddr4SpecialCases(const KeywordData & i_kwdData, err = spdFetchData( (i_kwdData.offset - 2), 1, /* Read 1 byte at a time */ &tmpBuffer[2], - i_target ); + i_target, + i_location ); if( err ) break; @@ -1077,13 +1168,14 @@ errlHndl_t ddr4SpecialCases(const KeywordData & i_kwdData, err = spdFetchData( (i_kwdData.offset - 3), 1, /* Read 1 byte at a time */ &tmpBuffer[3], - i_target ); + i_target, + i_location ); break; // ================================================== default: - TRACFCOMP( g_trac_spd, - ERR_MRK"Unknown keyword (0x%04x) for DDR4 special cases!", + TRACFCOMP( g_trac_spd, ERR_MRK"ddr4SpecialCases: " + "Unknown keyword (0x%04x) for DDR4 special cases!", i_kwdData.keyword ); /*@ @@ -1120,7 +1212,8 @@ errlHndl_t ddr4SpecialCases(const KeywordData & i_kwdData, errlHndl_t spdSpecialCases ( const KeywordData & i_kwdData, void * io_buffer, TARGETING::Target * i_target, - uint64_t i_DDRRev ) + uint64_t i_DDRRev, + VPD::vpdCmdTarget i_location ) { errlHndl_t err = NULL; @@ -1132,11 +1225,11 @@ errlHndl_t spdSpecialCases ( const KeywordData & i_kwdData, // Handle each of the special cases here if( SPD_DDR3 == i_DDRRev ) { - err = ddr3SpecialCases(i_kwdData,io_buffer,i_target); + err = ddr3SpecialCases(i_kwdData,io_buffer,i_target,i_location); } else if (SPD_DDR4 == i_DDRRev) { - err = ddr4SpecialCases(i_kwdData,io_buffer,i_target); + err = ddr4SpecialCases(i_kwdData,io_buffer,i_target,i_location); } else { @@ -1191,7 +1284,7 @@ errlHndl_t spdSpecialCases ( const KeywordData & i_kwdData, // ------------------------------------------------------------------ errlHndl_t spdCheckSize ( size_t i_bufferSz, size_t i_expBufferSz, - uint64_t i_keyword ) + VPD::vpdKeyword i_keyword ) { errlHndl_t err = NULL; @@ -1200,8 +1293,8 @@ errlHndl_t spdCheckSize ( size_t i_bufferSz, if( i_bufferSz < i_expBufferSz ) { TRACFCOMP( g_trac_spd, - ERR_MRK"Buffer Size (%d) for keyword (0x%04x) wasn't greater " - "than or equal to expected size (%d)", + ERR_MRK"Buffer Size (%d) for keyword (0x%04x) wasn't greater" + " than or equal to expected size (%d)", i_bufferSz, i_keyword, i_expBufferSz ); /*@ @@ -1286,8 +1379,8 @@ errlHndl_t spdReadBinaryFile ( uint64_t i_byteAddr, if( err ) { - TRACFCOMP( g_trac_spd, - ERR_MRK"Error getting starting address of binary SPD file: %s", + TRACFCOMP( g_trac_spd, ERR_MRK"spdReadBinaryFile: " + "Error getting starting address of binary SPD file: %s", fileName ); break; @@ -1300,8 +1393,8 @@ errlHndl_t spdReadBinaryFile ( uint64_t i_byteAddr, if( (i_byteAddr + i_numBytes) > fileSize ) { TRACFCOMP( g_trac_spd, - ERR_MRK"Unable to read %d bytes from %s at offset 0x%08x " - "because file size is only %d bytes!", + ERR_MRK"Unable to read %d bytes from %s at offset 0x%08x" + " because file size is only %d bytes!", i_numBytes, fileName, i_byteAddr, @@ -1377,7 +1470,8 @@ bool compareEntries ( const KeywordData e1, // ------------------------------------------------------------------ errlHndl_t checkModSpecificKeyword ( KeywordData i_kwdData, uint64_t i_memType, - TARGETING::Target * i_target ) + TARGETING::Target * i_target, + VPD::vpdCmdTarget i_location ) { errlHndl_t err = NULL; @@ -1395,7 +1489,7 @@ errlHndl_t checkModSpecificKeyword ( KeywordData i_kwdData, // Check that a Module Specific keyword is being accessed from a DIMM // of the correct Module Type. modSpecTypes_t modType = NA; - err = getModType(modType, i_target, i_memType); + err = getModType(modType, i_target, i_memType, i_location); if( err ) { @@ -1408,8 +1502,8 @@ errlHndl_t checkModSpecificKeyword ( KeywordData i_kwdData, if ((UMM != i_kwdData.modSpec) && (ALL != i_kwdData.modSpec) ) { - TRACFCOMP( g_trac_spd, - ERR_MRK"Keyword (0x%04x) is not valid with UMM modules!", + TRACFCOMP( g_trac_spd, ERR_MRK"checkModSpecificKeyword: " + "Keyword (0x%04x) is not valid with UMM modules!", i_kwdData.keyword ); /*@ * @errortype @@ -1454,8 +1548,8 @@ errlHndl_t checkModSpecificKeyword ( KeywordData i_kwdData, if ((RMM != i_kwdData.modSpec) && (ALL != i_kwdData.modSpec) ) { - TRACFCOMP( g_trac_spd, - ERR_MRK"Keyword (0x%04x) is not valid with RMM modules!", + TRACFCOMP( g_trac_spd, ERR_MRK"checkModSpecificKeyword: " + "Keyword (0x%04x) is not valid with RMM modules!", i_kwdData.keyword ); /*@ * @errortype @@ -1500,8 +1594,8 @@ errlHndl_t checkModSpecificKeyword ( KeywordData i_kwdData, if ((CMM != i_kwdData.modSpec) && (ALL != i_kwdData.modSpec) ) { - TRACFCOMP( g_trac_spd, - ERR_MRK"Keyword (0x%04x) is not valid with CMM modules!", + TRACFCOMP( g_trac_spd, ERR_MRK"checkModSpecificKeyword: " + "Keyword (0x%04x) is not valid with CMM modules!", i_kwdData.keyword ); /*@ * @errortype @@ -1546,8 +1640,8 @@ errlHndl_t checkModSpecificKeyword ( KeywordData i_kwdData, if ((LRMM != i_kwdData.modSpec) && (ALL != i_kwdData.modSpec) ) { - TRACFCOMP( g_trac_spd, - ERR_MRK"Keyword (0x%04x) is not valid with LRMM modules!", + TRACFCOMP( g_trac_spd, ERR_MRK"checkModSpecificKeyword: " + "Keyword (0x%04x) is not valid with LRMM modules!", i_kwdData.keyword ); /*@ * @errortype @@ -1588,11 +1682,11 @@ errlHndl_t checkModSpecificKeyword ( KeywordData i_kwdData, } else { - TRACFCOMP( g_trac_spd, - ERR_MRK"Module specific keyword could not be matched with an " + TRACFCOMP( g_trac_spd, ERR_MRK"checkModSpecificKeyword: " + "Module specific keyword could not be matched with an " "appropriate scenario!" ); - TRACFCOMP( g_trac_spd, - ERR_MRK" Mem Type: 0x%04x, Mod Type: 0x%04x, Keyword: 0x%04x", + TRACFCOMP( g_trac_spd, ERR_MRK + " Mem Type: 0x%04x, Mod Type: 0x%04x, Keyword: 0x%04x", i_memType, modType, i_kwdData.keyword ); @@ -1643,14 +1737,16 @@ errlHndl_t checkModSpecificKeyword ( KeywordData i_kwdData, // getMemType // ------------------------------------------------------------------ errlHndl_t getMemType ( uint8_t & o_memType, - TARGETING::Target * i_target ) + TARGETING::Target * i_target, + VPD::vpdCmdTarget i_location ) { errlHndl_t err = NULL; err = spdFetchData( MEM_TYPE_ADDR, MEM_TYPE_SZ, &o_memType, - i_target ); + i_target, + i_location ); TRACUCOMP( g_trac_spd, "SPD::getMemType() - MemType: 0x%02x, Error: %s", @@ -1665,7 +1761,8 @@ errlHndl_t getMemType ( uint8_t & o_memType, // ------------------------------------------------------------------ errlHndl_t getModType ( modSpecTypes_t & o_modType, TARGETING::Target * i_target, - uint64_t i_memType ) + uint64_t i_memType, + VPD::vpdCmdTarget i_location ) { errlHndl_t err = NULL; o_modType = NA; @@ -1674,7 +1771,8 @@ errlHndl_t getModType ( modSpecTypes_t & o_modType, err = spdFetchData( MOD_TYPE_ADDR, MOD_TYPE_SZ, &modTypeVal, - i_target ); + i_target, + i_location ); if (err) { @@ -1768,7 +1866,7 @@ errlHndl_t getModType ( modSpecTypes_t & o_modType, // ------------------------------------------------------------------ // getKeywordEntry // ------------------------------------------------------------------ -errlHndl_t getKeywordEntry ( uint64_t i_keyword, +errlHndl_t getKeywordEntry ( VPD::vpdKeyword i_keyword, uint64_t i_memType, TARGETING::Target * i_target, const KeywordData *& o_entry ) @@ -1878,4 +1976,181 @@ errlHndl_t getKeywordEntry ( uint64_t i_keyword, } -} // end namespace SPD +// ------------------------------------------------------------------ +// cmpPnorSeeprom +// ------------------------------------------------------------------ +errlHndl_t cmpPnorToSeeprom ( TARGETING::Target * i_target, + VPD::vpdKeyword i_keyword, + bool &o_match ) +{ + errlHndl_t err = NULL; + + TRACSSCOMP( g_trac_spd, ENTER_MRK"cmpPnorSeeprom()" ); + + o_match = false; + + do + { + // Read the Basic Memory Type + uint8_t memType = 0x0; + err = getMemType( memType, + i_target, + VPD::AUTOSELECT ); + if( err ) + { + break; + } + if(( SPD_DDR3 != memType ) && + ( SPD_DDR4 != memType )) + { + break; + } + + // Get the keyword size + size_t dataSize = 0; + if( SPD_DDR3 == memType ) + { + dataSize = ddr3Data[i_keyword].length; + } + else + { + dataSize = ddr4Data[i_keyword].length; + } + + // Read the keyword from PNOR + size_t sizePnor = dataSize; + uint8_t dataPnor[sizePnor]; + err = spdGetValue( i_keyword, + dataPnor, + sizePnor, + i_target, + memType, + VPD::PNOR ); + if( err ) + { + // PNOR may not be loaded, ignore the error + delete err; + err = NULL; + break; + } + + // Read the keyword from SEEPROM + size_t sizeSeeprom = dataSize; + uint8_t dataSeeprom[sizeSeeprom]; + err = spdGetValue( i_keyword, + dataSeeprom, + sizeSeeprom, + i_target, + memType, + VPD::SEEPROM ); + if( err ) + { + break; + } + + // Compare the PNOR/SEEPROM size/data + if( sizePnor != sizeSeeprom ) + { + break; + } + if( memcmp( dataPnor, dataSeeprom, sizePnor ) ) + { + break; + } + + o_match = true; + + } while(0); + + TRACSSCOMP( g_trac_spd, EXIT_MRK"cmpPnorSeeprom()" ); + + return err; + } + + +// ------------------------------------------------------------------ +// loadPnor +// ------------------------------------------------------------------ +errlHndl_t loadPnor ( TARGETING::Target * i_target ) +{ + errlHndl_t err = NULL; + + TRACSSCOMP( g_trac_spd, ENTER_MRK"loadPnorCache()" ); + + do + { + // Invalidate the SPD in PNOR + err = invalidatePnor( i_target ); + if( err ) + { + TRACFCOMP( g_trac_spd, + ERR_MRK"loadPnorCache: Error invalidating the SPD in PNOR" ); + break; + } + + // Load PNOR cache from SEEPROM + + // Read the entire SPD section from SEEPROM + uint8_t writeData[DIMM_SPD_SECTION_SIZE]; + err = spdFetchData ( 0x0, + DIMM_SPD_SECTION_SIZE, + writeData, + i_target, + VPD::SEEPROM ); + if( err ) + { + TRACFCOMP( g_trac_spd, + ERR_MRK"loadPnorCache: Error reading SEEPROM SPD data" ); + break; + } + + // Write the entire SPD section to PNOR + err = spdWriteData( 0x0, + DIMM_SPD_SECTION_SIZE, + writeData, + i_target, + VPD::PNOR ); + if( err ) + { + TRACFCOMP( g_trac_spd,ERR_MRK"loadPnorCache: Error writing PNOR SPD data" ); + break; + } + + } while(0); + + TRACSSCOMP( g_trac_spd, EXIT_MRK"loadPnorCache()" ); + + return err; +} + + +// ------------------------------------------------------------------ +// /*invalidatePnorCache*/ +// ------------------------------------------------------------------ +errlHndl_t invalidatePnor ( TARGETING::Target * i_target ) +{ + errlHndl_t err = NULL; + + TRACSSCOMP( g_trac_spd, ENTER_MRK"invalidatePnorCache()" ); + + // Write SPD section to all Fs + uint8_t writeData[DIMM_SPD_SECTION_SIZE]; + memset( writeData, 0xFF, DIMM_SPD_SECTION_SIZE ); + err = spdWriteData( 0x0, + DIMM_SPD_SECTION_SIZE, + writeData, + i_target, + VPD::PNOR ); + if( err ) + { + TRACFCOMP( g_trac_spd, ERR_MRK"invalidatePnorCache: " + "Error invalidating the SPD in PNOR" ); + } + + TRACSSCOMP( g_trac_spd, EXIT_MRK"invalidatePnorCache()" ); + + return err; +} + + +}; // end namespace SPD diff --git a/src/usr/vpd/spd.H b/src/usr/vpd/spd.H index 4ba41cc90..b47c78438 100755 --- a/src/usr/vpd/spd.H +++ b/src/usr/vpd/spd.H @@ -5,7 +5,9 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* COPYRIGHT International Business Machines Corp. 2012,2014 */ +/* Contributors Listed Below - COPYRIGHT 2013,2014 */ +/* [+] International Business Machines Corp. */ +/* */ /* */ /* Licensed under the Apache License, Version 2.0 (the "License"); */ /* you may not use this file except in compliance with the License. */ @@ -34,6 +36,7 @@ // Includes // ---------------------------------------------- #include <errl/errlentry.H> +#include <vpd/spdenums.H> #include "vpd.H" namespace SPD @@ -184,13 +187,16 @@ errlHndl_t spdWriteKeywordValue ( DeviceFW::OperationType i_opType, * * @param[in] i_target - The target DIMM to access. * + * @param[in] i_location - The SPD source (PNOR/SEEPROM). + * * @return errlHndl_t - NULL if successful, otherwise a pointer to the * error log. */ errlHndl_t spdFetchData ( uint64_t i_byteAddr, size_t i_numBytes, void * o_data, - TARGETING::Target * i_target ); + TARGETING::Target * i_target, + VPD::vpdCmdTarget i_location ); /** * @brief This function is a wrapper for writing the correct keyword. @@ -205,13 +211,16 @@ errlHndl_t spdFetchData ( uint64_t i_byteAddr, * * @param[in] i_target - The target DIMM to access. * + * @param[in] i_location - The SPD destination (PNOR/SEEPROM). + * * @return errlHndl_t - NULL if successful, otherwise a pointer to the * error log. */ errlHndl_t spdWriteData ( uint64_t i_offset, size_t i_numBytes, void * i_data, - TARGETING::Target * i_target ); + TARGETING::Target * i_target, + VPD::vpdCmdTarget i_location ); /** @@ -230,14 +239,17 @@ errlHndl_t spdWriteData ( uint64_t i_offset, * * @param[in] i_DDRRev - The DIMM DDR Revision. * + * @param[in] i_location - The SPD source (PNOR/SEEPROM). + * * @return errlHndl_t - NULL if successful, otherwise a pointer to the * error log. */ -errlHndl_t spdGetValue ( uint64_t i_keyword, +errlHndl_t spdGetValue ( VPD::vpdKeyword i_keyword, void * io_buffer, size_t & io_buflen, TARGETING::Target * i_target, - uint64_t i_DDRRev ); + uint64_t i_DDRRev, + VPD::vpdCmdTarget i_location ); /** @@ -256,14 +268,17 @@ errlHndl_t spdGetValue ( uint64_t i_keyword, * * @param[in] i_DDRRev - The DIMM DDR Revision. * + * @param[in] i_location - The SPD destination (PNOR/SEEPROM). + * * @return errlHndl_t - NULL if successful, otherwise a pointer to the * error log. */ -errlHndl_t spdWriteValue ( uint64_t i_keyword, +errlHndl_t spdWriteValue ( VPD::vpdKeyword i_keyword, void * io_buffer, size_t & io_buflen, TARGETING::Target * i_target, - uint64_t i_DDRRev ); + uint64_t i_DDRRev, + VPD::vpdCmdTarget i_location ); /** @@ -278,13 +293,16 @@ errlHndl_t spdWriteValue ( uint64_t i_keyword, * * @param[in] i_target - The target DIMM to access the data for. * + * @param[in] i_location - The SPD source/destination (PNOR/SEEPROM). + * * @return errlHndl_t - NULL if successful, otherwise a pointer to the * error log. */ errlHndl_t spdSpecialCases ( const KeywordData & i_kwdData, void * io_buffer, TARGETING::Target * i_target, - uint64_t i_DDRRev ); + uint64_t i_DDRRev, + VPD::vpdCmdTarget i_location ); /** * @brief This function checks to make sure that the buffer allocated @@ -302,7 +320,7 @@ errlHndl_t spdSpecialCases ( const KeywordData & i_kwdData, */ errlHndl_t spdCheckSize ( size_t i_bufferSz, size_t i_expBufferSz, - uint64_t i_keyword ); + VPD::vpdKeyword i_keyword ); /** * @brief This function will read a binary file from PNOR. This is @@ -372,12 +390,15 @@ errlHndl_t dimmPresenceDetect( DeviceFW::OperationType i_opType, * * @param[in] i_target - The chip target. * + * @param[in] i_location - The SPD source (PNOR/SEEPROM). + * * @return errlHndl_t - NULL if successful, otherwise a pointer to the error * log. */ errlHndl_t checkModSpecificKeyword ( KeywordData i_kwdData, uint64_t i_memType, - TARGETING::Target * i_target ); + TARGETING::Target * i_target, + VPD::vpdCmdTarget i_location ); /** * @brief This function is used to query the attribute code to get the VPD @@ -394,6 +415,44 @@ errlHndl_t getVpdLocation ( int64_t & o_vpdLocation, TARGETING::Target * i_target ); +/** + * @brief This function compares value of the keyword in PNOR/SEEPROM + * and returns the result + * + * @param[in] i_target - Target device + * + * @param [in] i_keyword - Keyword to compare + * + * @param [in] o_match - Result of keyword compare + * + * @return errlHndl_t - NULL if successful, otherwise a pointer to the + * error log. A mismatch will not return an error. + */ +errlHndl_t cmpPnorToSeeprom( TARGETING::Target * i_target, + VPD::vpdKeyword i_keyword, + bool &o_match ); + +/** + * @brief This function loads the SPD data from the SEEPROM into the PNOR cache + * + * @param[in] i_target - Target device + * + * @return errlHndl_t - NULL if successful, otherwise a pointer to the + * error log. + */ +errlHndl_t loadPnor ( TARGETING::Target * i_target ); + +/** + * @brief This function invalidates the SPD in the PNOR cache + * + * @param[in] i_target - Target device + * + * @return errlHndl_t - NULL if successful, otherwise a pointer to the + * error log. + */ +errlHndl_t invalidatePnor ( TARGETING::Target * i_target ); + + }; // end SPD namespace #endif // __SPD_H diff --git a/src/usr/vpd/test/cvpdtest.H b/src/usr/vpd/test/cvpdtest.H index 136e1fd9a..46975c88e 100755 --- a/src/usr/vpd/test/cvpdtest.H +++ b/src/usr/vpd/test/cvpdtest.H @@ -5,7 +5,9 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* COPYRIGHT International Business Machines Corp. 2013,2014 */ +/* Contributors Listed Below - COPYRIGHT 2013,2014 */ +/* [+] International Business Machines Corp. */ +/* */ /* */ /* Licensed under the Apache License, Version 2.0 (the "License"); */ /* you may not use this file except in compliance with the License. */ @@ -51,8 +53,8 @@ using namespace TARGETING; */ struct cvpdTestData { - IpVpdFacade::ipVpdRecord record; - IpVpdFacade::ipVpdRecord keyword; + VPD::vpdRecord record; + VPD::vpdRecord keyword; }; /** @@ -708,8 +710,8 @@ class CVPDTest: public CxxTest::TestSuite void testCvpdCheckStructOrder ( void ) { uint64_t fails = 0x0; - IpVpdFacade::ipVpdRecord prevRecord = CVPD::CVPD_FIRST_RECORD; - IpVpdFacade::ipVpdKeyword prevKeyword = CVPD::CVPD_FIRST_KEYWORD; + VPD::vpdRecord prevRecord = CVPD::CVPD_FIRST_RECORD; + VPD::vpdKeyword prevKeyword = CVPD::CVPD_FIRST_KEYWORD; TRACFCOMP( g_trac_vpd, ENTER_MRK"testCvpdCheckStructOrder()" ); diff --git a/src/usr/vpd/test/mvpdtest.H b/src/usr/vpd/test/mvpdtest.H index 28c683817..b89bc3637 100755 --- a/src/usr/vpd/test/mvpdtest.H +++ b/src/usr/vpd/test/mvpdtest.H @@ -5,7 +5,9 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* COPYRIGHT International Business Machines Corp. 2012,2014 */ +/* Contributors Listed Below - COPYRIGHT 2013,2014 */ +/* [+] International Business Machines Corp. */ +/* */ /* */ /* Licensed under the Apache License, Version 2.0 (the "License"); */ /* you may not use this file except in compliance with the License. */ @@ -51,8 +53,8 @@ using namespace TARGETING; */ struct mvpdTestData { - IpVpdFacade::ipVpdRecord record; - IpVpdFacade::ipVpdRecord keyword; + VPD::vpdRecord record; + VPD::vpdRecord keyword; }; /** @@ -859,8 +861,8 @@ class MVPDTest: public CxxTest::TestSuite void testMvpdCheckStructOrder ( void ) { uint64_t fails = 0x0; - IpVpdFacade::ipVpdRecord prevRecord = MVPD::MVPD_FIRST_RECORD; - IpVpdFacade::ipVpdKeyword prevKeyword = MVPD::MVPD_FIRST_KEYWORD; + VPD::vpdRecord prevRecord = MVPD::MVPD_FIRST_RECORD; + VPD::vpdKeyword prevKeyword = MVPD::MVPD_FIRST_KEYWORD; TRACFCOMP( g_trac_vpd, ENTER_MRK"testMvpdCheckStructOrder()" ); diff --git a/src/usr/vpd/test/spdtest.H b/src/usr/vpd/test/spdtest.H index 7a3739760..83de74c7f 100755 --- a/src/usr/vpd/test/spdtest.H +++ b/src/usr/vpd/test/spdtest.H @@ -5,7 +5,9 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* COPYRIGHT International Business Machines Corp. 2012,2014 */ +/* Contributors Listed Below - COPYRIGHT 2013,2014 */ +/* [+] International Business Machines Corp. */ +/* */ /* */ /* Licensed under the Apache License, Version 2.0 (the "License"); */ /* you may not use this file except in compliance with the License. */ @@ -937,7 +939,8 @@ class SPDTest: public CxxTest::TestSuite "valid for all types of modules. IGNORE!!" ); err = checkModSpecificKeyword( kwdData, memType, - theTarget ); + theTarget, + VPD::AUTOSELECT ); if( err ) { // This keyword isn't supported with this module type diff --git a/src/usr/vpd/vpd.C b/src/usr/vpd/vpd.C index 64fa99f3f..cb08625cc 100644..100755 --- a/src/usr/vpd/vpd.C +++ b/src/usr/vpd/vpd.C @@ -5,7 +5,9 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* COPYRIGHT International Business Machines Corp. 2013,2014 */ +/* Contributors Listed Below - COPYRIGHT 2013,2014 */ +/* [+] International Business Machines Corp. */ +/* */ /* */ /* Licensed under the Apache License, Version 2.0 (the "License"); */ /* you may not use this file except in compliance with the License. */ @@ -26,7 +28,12 @@ #include <errl/errludtarget.H> #include <vpd/vpdreasoncodes.H> #include <initservice/initserviceif.H> +#include <devicefw/driverif.H> +#include <sys/mm.h> #include "vpd.H" +#include "mvpd.H" +#include "cvpd.H" +#include "spd.H" // ---------------------------------------------- // Trace definitions @@ -238,6 +245,31 @@ errlHndl_t writePNOR ( uint64_t i_byteAddr, memcpy( (void*)(writeAddr), i_data, i_numBytes ); + + // @todo RTC:117042 - enable flush once PNOR writes supported + // Flush the page to make sure it gets to the PNOR +#if 0 + int rc = mm_remove_pages( FLUSH, (void*)addr, i_numBytes ); + if( rc ) + { + TRACFCOMP(g_trac_vpd,ERR_MRK"writePNOR() Error from mm_remove_pages, rc=%d",rc); + /*@ + * @errortype + * @moduleid VPD_WRITE_PNOR + * @reasoncode VPD_REMOVE_PAGES_FAIL + * @userdata1 Requested Address + * @userdata2 rc from mm_remove_pages + * @devdesc writePNOR mm_remove_pages FLUSH failed + */ + err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + VPD_WRITE_PNOR, + VPD_REMOVE_PAGES_FAIL, + addr, + TO_UINT64(rc), + true /*Add HB Software Callout*/ ); + } +#endif } while( 0 ); TRACSSCOMP( g_trac_vpd, @@ -322,4 +354,257 @@ errlHndl_t sendMboxWriteMsg ( size_t i_numBytes, } +// ------------------------------------------------------------------ +// resolveVpdSource +// ------------------------------------------------------------------ +bool resolveVpdSource( TARGETING::Target * i_target, + bool i_readFromPnorEnabled, + bool i_readFromHwEnabled, + vpdCmdTarget i_vpdCmdTarget, + vpdCmdTarget& o_vpdSource ) +{ + bool badConfig = false; + o_vpdSource = VPD::INVALID_LOCATION; + + if( i_vpdCmdTarget == VPD::PNOR ) + { + if( i_readFromPnorEnabled ) + { + o_vpdSource = VPD::PNOR; + } + else + { + badConfig = true; + TRACFCOMP(g_trac_vpd,"resolveVpdSource: VpdCmdTarget=PNOR but READ_FROM_PNOR is disabled"); + } + } + else if( i_vpdCmdTarget == VPD::SEEPROM ) + { + if( i_readFromHwEnabled ) + { + o_vpdSource = VPD::SEEPROM; + } + else + { + badConfig = true; + TRACFCOMP(g_trac_vpd,"resolveVpdSource: VpdCmdTarget=SEEPROM but READ_FROM_HW is disabled"); + } + } + else // i_vpdCmdTarget == VPD::AUTOSELECT + { + if( i_readFromPnorEnabled && + i_readFromHwEnabled ) + { + // PNOR needs to be loaded before we can use it + TARGETING::ATTR_VPD_SWITCHES_type vpdSwitches = + i_target->getAttr<TARGETING::ATTR_VPD_SWITCHES>(); + if( vpdSwitches.pnorLoaded ) + { + o_vpdSource = VPD::PNOR; + } + else + { + o_vpdSource = VPD::SEEPROM; + } + } + else if( i_readFromPnorEnabled ) + { + o_vpdSource = VPD::PNOR; + } + else if( i_readFromHwEnabled ) + { + o_vpdSource = VPD::SEEPROM; + } + else + { + badConfig = true; + TRACFCOMP(g_trac_vpd,"resolveVpdSource: READ_FROM_PNOR and READ_FROM_HW disabled"); + } + } + + return badConfig; +} + + +// ------------------------------------------------------------------ +// ensureCacheIsInSync +// ------------------------------------------------------------------ +errlHndl_t ensureCacheIsInSync ( TARGETING::Target * i_target ) +{ + errlHndl_t l_err = NULL; + + TRACSSCOMP( g_trac_vpd, ENTER_MRK"ensureCacheIsInSync() " ); + + IpVpdFacade& l_ipvpd = Singleton<MvpdFacade>::instance(); + + vpdRecord l_record = 0; + vpdKeyword l_keywordPN = 0; + vpdKeyword l_keywordSN = 0; + + TARGETING::TYPE l_type = i_target->getAttr<TARGETING::ATTR_TYPE>(); + + if( l_type == TARGETING::TYPE_PROC ) + { + l_record = MVPD::VINI; + l_keywordPN = MVPD::PN; + l_keywordSN = MVPD::SN; + } + else if( l_type == TARGETING::TYPE_MEMBUF ) + { + l_ipvpd = Singleton<CvpdFacade>::instance(); + l_record = CVPD::VINI; + l_keywordPN = CVPD::PN; + l_keywordSN = CVPD::SN; + } + else if( l_type == TARGETING::TYPE_DIMM ) + { + // SPD does not have a singleton instance + // SPD does not use records + l_keywordPN = SPD::MODULE_PART_NUMBER; + l_keywordSN = SPD::MODULE_SERIAL_NUMBER; + } + else + { + TRACFCOMP(g_trac_vpd,ERR_MRK"ensureCacheIsInSync() Unexpected target type, huid=0x%X",TARGETING::get_huid(i_target)); + /*@ + * @errortype + * @moduleid VPD_ENSURE_CACHE_IS_IN_SYNC + * @reasoncode VPD_UNEXPECTED_TARGET_TYPE + * @userdata1 Target HUID + * @userdata2 <UNUSED> + * @devdesc Unexpected target type + */ + l_err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + VPD_ENSURE_CACHE_IS_IN_SYNC, + VPD_UNEXPECTED_TARGET_TYPE, + TO_UINT64(TARGETING::get_huid(i_target)), + 0x0, + true /*Add HB Software Callout*/ ); + return l_err; + } + + do + { + // Compare the Part Numbers in PNOR/SEEPROM + bool l_matchPN = false; + if( ( l_type == TARGETING::TYPE_PROC ) || + ( l_type == TARGETING::TYPE_MEMBUF ) ) + { + l_err = l_ipvpd.cmpPnorToSeeprom( i_target, + l_record, + l_keywordPN, + l_matchPN ); + } + else if( l_type == TARGETING::TYPE_DIMM ) + { + l_err = SPD::cmpPnorToSeeprom( i_target, + l_keywordPN, + l_matchPN ); + } + if (l_err) + { + TRACFCOMP(g_trac_vpd,ERR_MRK"VPD::ensureCacheIsInSync: Error checking for PNOR/SEEPROM PN match"); + break; + } + + // Compare the Serial Numbers in PNOR/SEEPROM + bool l_matchSN = false; + if( ( l_type == TARGETING::TYPE_PROC ) || + ( l_type == TARGETING::TYPE_MEMBUF ) ) + { + l_err = l_ipvpd.cmpPnorToSeeprom( i_target, + l_record, + l_keywordSN, + l_matchSN ); + } + else if( l_type == TARGETING::TYPE_DIMM ) + { + l_err = SPD::cmpPnorToSeeprom( i_target, + l_keywordSN, + l_matchSN ); + } + if( l_err ) + { + TRACFCOMP(g_trac_vpd,ERR_MRK"VPD::ensureCacheIsInSync: Error checking for PNOR/SEEPROM SN match"); + break; + } + + // If we did not match, we need to load SEEPROM VPD data into PNOR + if( l_matchPN && l_matchSN ) + { + TRACFCOMP(g_trac_vpd,"VPD::ensureCacheIsInSync: PNOR_PN/SN = SEEPROM_PN/SN"); + } + else + { + TRACFCOMP(g_trac_vpd,"VPD::ensureCacheIsInSync: PNOR_PN/SN != SEEPROM_PN/SN, Loading PNOR from SEEPROM"); + + // @todo RTC 116553 - Need HCDB update call here + // Load the PNOR data from the SEEPROM + if( ( l_type == TARGETING::TYPE_PROC ) || + ( l_type == TARGETING::TYPE_MEMBUF ) ) + { + l_err = l_ipvpd.loadPnor( i_target ); + } + else if( l_type == TARGETING::TYPE_DIMM ) + { + l_err = SPD::loadPnor( i_target ); + } + if( l_err ) + { + TRACFCOMP(g_trac_vpd,"Error loading SEEPROM VPD into PNOR"); + break; + } + } + + // Set target attribute switch that says VPD is loaded into PNOR + TARGETING::ATTR_VPD_SWITCHES_type vpdSwitches = + i_target->getAttr<TARGETING::ATTR_VPD_SWITCHES>(); + vpdSwitches.pnorLoaded = 1; + i_target->setAttr<TARGETING::ATTR_VPD_SWITCHES>( vpdSwitches ); + + } while(0); + + TRACSSCOMP( g_trac_vpd, EXIT_MRK"ensureCacheIsInSync()" ); + + return l_err; +} + + +// ------------------------------------------------------------------ +// invalidatePnorCache +// ------------------------------------------------------------------ +errlHndl_t invalidatePnorCache ( TARGETING::Target * i_target ) +{ + errlHndl_t l_err = NULL; + + TRACSSCOMP( g_trac_vpd, ENTER_MRK"invalidatePnorCache() " ); + + TARGETING::TYPE l_type = i_target->getAttr<TARGETING::ATTR_TYPE>(); + + if( l_type == TARGETING::TYPE_PROC ) + { + l_err = Singleton<MvpdFacade>::instance().invalidatePnor( i_target ); + } + else if( l_type == TARGETING::TYPE_MEMBUF ) + { + l_err = Singleton<CvpdFacade>::instance().invalidatePnor( i_target ); + } + else if( l_type == TARGETING::TYPE_DIMM ) + { + l_err = SPD::invalidatePnor( i_target ); + } + + // Clear target attribute switch that says VPD is loaded into PNOR + TARGETING::ATTR_VPD_SWITCHES_type vpdSwitches = + i_target->getAttr<TARGETING::ATTR_VPD_SWITCHES>(); + vpdSwitches.pnorLoaded = 0; + i_target->setAttr<TARGETING::ATTR_VPD_SWITCHES>( vpdSwitches ); + + TRACSSCOMP( g_trac_vpd, EXIT_MRK"invalidatePnorCache()" ); + + return l_err; +} + + }; //end VPD namespace diff --git a/src/usr/vpd/vpd.H b/src/usr/vpd/vpd.H index 5f3e82011..d8972fb46 100644 --- a/src/usr/vpd/vpd.H +++ b/src/usr/vpd/vpd.H @@ -5,7 +5,9 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* COPYRIGHT International Business Machines Corp. 2013,2014 */ +/* Contributors Listed Below - COPYRIGHT 2013,2014 */ +/* [+] International Business Machines Corp. */ +/* */ /* */ /* Licensed under the Apache License, Version 2.0 (the "License"); */ /* you may not use this file except in compliance with the License. */ @@ -24,6 +26,7 @@ #define __VPD_H #include <pnor/pnorif.H> +#include <vpd/vpd_if.H> namespace VPD { @@ -190,6 +193,31 @@ errlHndl_t sendMboxWriteMsg ( size_t i_numBytes, VPD_MSG_TYPE i_type, VpdWriteMsg_t& i_record ); +/** + * @brief This function determines the VPD source (PNOR/SEEPROM) + * from configuration and target state information + * + * @param[in] i_target - Target device. + * + * @param[in] i_readFromPnorEnabled - Config value specifying + * whether PNOR reads are enabled for this VPD type + * + * @param[in] i_readFromHwEnabled - Config value specifying + * whether SEEPROM reads are enabled for this VPD type + * + * @param[in] i_location - The requested VPD source location + * (PNOR/SEEPROM) from the caller + * + * @param[out] o_source - The resolved VPD source to be accessed + * + * @return errHndl_t - NULL if successful, otherwise a pointer to the + * error log. + */ +bool resolveVpdSource( TARGETING::Target * i_target, + bool i_readFromPnorEnabled, + bool i_readFromHwEnabled, + vpdCmdTarget i_vpdCmdTarget, + vpdCmdTarget& o_vpdSource ); }; //end VPD namespace |