// ------------------------------------------------------------------ // getPnorAddr // ------------------------------------------------------------------ errlHndl_t getPnorAddr ( pnorInformation & i_pnorInfo, uint64_t &io_cachedAddr, mutex_t * i_mutex ) { errlHndl_t err = NULL; PNOR::SectionInfo_t info; TRACSSCOMP( g_trac_vpd, ENTER_MRK"getPnorAddr()" ); do { // Get SPD PNOR section info from PNOR RP err = PNOR::getSectionInfo( i_pnorInfo.pnorSection, info ); if( err ) { break; } // Set the globals appropriately mutex_lock( i_mutex ); io_cachedAddr = info.vaddr; mutex_unlock( i_mutex ); } while( 0 ); TRACSSCOMP( g_trac_vpd, EXIT_MRK"getPnorAddr() - addr: 0x%08x", io_cachedAddr ); return 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; }
// ------------------------------------------------------------------ // Fake readPNOR - image is in memory // ------------------------------------------------------------------ errlHndl_t readPNOR ( uint64_t i_byteAddr, size_t i_numBytes, void * o_data, TARGETING::Target * i_target, pnorInformation & i_pnorInfo, uint64_t &io_cachedAddr, mutex_t * i_mutex ) { errlHndl_t err = NULL; int64_t vpdLocation = 0; uint64_t addr = 0x0; const char * readAddr = NULL; TRACSSCOMP( g_trac_vpd, ENTER_MRK"RT fake readPNOR()" ); do { // fake getPnorAddr gets memory address of VPD err = getPnorAddr(i_pnorInfo, io_cachedAddr, i_mutex ); if(err) { break; } addr = io_cachedAddr; err = getVpdLocation( vpdLocation, i_target); if(err) { break; } // Add Offset for target vpd location addr += (vpdLocation * i_pnorInfo.segmentSize); // Add keyword offset addr += i_byteAddr; TRACUCOMP( g_trac_vpd, INFO_MRK"Address to read: 0x%08x", addr ); readAddr = reinterpret_cast<const char *>( addr ); memcpy( o_data, readAddr, i_numBytes ); } while(0); TRACSSCOMP( g_trac_vpd, EXIT_MRK"RT fake readPNOR()" ); return err; }
/** * @brief This function will perform the steps required to do a write to * the Hostboot DVPD data. * * @param[in] i_opType - Operation Type - See DeviceFW::OperationType in * driververif.H * * @param[in] i_target - Processor Target device * * @param [in/out] io_buffer - Pointer to the data that was read from * the target device. It will also be used to contain data to * be written to the device. * * @param [in/out] io_buflen - Length of the buffer to be read or written * to/from the target. This value should indicate the size of the * io_buffer parameter that has been allocated. Being returned it * will indicate the number of valid bytes in the buffer being * returned. * * @param [in] i_accessType - Access Type - See DeviceFW::AccessType in * usrif.H * * @param [in] i_args - This is an argument list for the device driver * framework. * * @return errlHndl_t - NULL if successful, otherwise a pointer to the * error log. */ errlHndl_t dvpdWrite ( DeviceFW::OperationType i_opType, TARGETING::Target * i_target, void * io_buffer, size_t & io_buflen, int64_t i_accessType, va_list i_args ) { errlHndl_t err = NULL; IpVpdFacade::input_args_t args; args.record = ((dvpdRecord)va_arg( i_args, uint64_t )); args.keyword = ((dvpdKeyword)va_arg( i_args, uint64_t )); args.location = ((VPD::vpdCmdTarget)va_arg( i_args, uint64_t )); TRACSSCOMP( g_trac_vpd, ENTER_MRK"dvpdWrite(0x%.8X):rec=%d,kw=%d,loc=%d", TARGETING::get_huid(i_target), args.record, args.keyword, args.location); err = Singleton<DvpdFacade>::instance().write(i_target, io_buffer, io_buflen, args); return err; }
// ------------------------------------------------------------------ // getVpdLocation // ------------------------------------------------------------------ errlHndl_t getVpdLocation ( int64_t & o_vpdLocation, TARGETING::Target * i_target ) { errlHndl_t err = NULL; TRACSSCOMP( g_trac_vpd, ENTER_MRK"getVpdLocation()" ); o_vpdLocation = i_target->getAttr<TARGETING::ATTR_VPD_REC_NUM>(); TRACUCOMP( g_trac_vpd, INFO_MRK"Using VPD location: %d", o_vpdLocation ); TRACSSCOMP( g_trac_vpd, EXIT_MRK"getVpdLocation()" ); return err; }
/** * @brief This function will perform the steps required to do a read from * the Hostboot DVPD data. * * @param[in] i_opType - Operation Type - See DeviceFW::OperationType in * driververif.H * * @param[in] i_target - Processor Target device * * @param [in/out] io_buffer - Pointer to the data that was read from * the target device. This parameter, when set to NULL, will return * the keyword size value in io_buflen. * * @param [in/out] io_buflen - Length of the buffer to be read or written * to/from the target. This value should indicate the size of the * io_buffer parameter that has been allocated. Being returned it * will indicate the number of valid bytes in the buffer being * returned. This parameter will contain the size of a keyword when * the io_buffer parameter is passed in NULL. * * @param [in] i_accessType - Access Type - See DeviceFW::AccessType in * usrif.H * * @param [in] i_args - This is an argument list for the device driver * framework. * * @return errlHndl_t - NULL if successful, otherwise a pointer to the * error log. */ errlHndl_t dvpdRead ( DeviceFW::OperationType i_opType, TARGETING::Target * i_target, void * io_buffer, size_t & io_buflen, int64_t i_accessType, va_list i_args ) { errlHndl_t err = NULL; IpVpdFacade::input_args_t args; args.record = ((dvpdRecord)va_arg( i_args, uint64_t )); args.keyword = ((dvpdKeyword)va_arg( i_args, uint64_t )); args.location = ((VPD::vpdCmdTarget)va_arg( i_args, uint64_t )); TRACSSCOMP( g_trac_vpd, ENTER_MRK"dvpdRead(0x%.8X):rec=%d,kw=%d,loc=%d", TARGETING::get_huid(i_target), args.record, args.keyword, args.location); #ifdef CONFIG_SECUREBOOT // Load the secure section just in case if we're using it bool l_didload = false; err = Singleton<DvpdFacade>::instance(). loadUnloadSecureSection( args, i_target, true, l_didload ); #endif if( !err ) { err = Singleton<DvpdFacade>::instance().read(i_target, io_buffer, io_buflen, args); } #ifdef CONFIG_SECUREBOOT if( l_didload ) { errlHndl_t err2 = Singleton<DvpdFacade>::instance(). loadUnloadSecureSection( args, i_target, false, l_didload ); if( err2 && !err ) { err = err2; err2 = nullptr; } else if( err2 ) { err2->plid(err->plid()); errlCommit( err2, VPD_COMP_ID ); } } #endif return err; }
// -------------------------------------------------------- // Presence Detection //--------------------------------------------------------- bool VPD::cvpdPresent( TARGETING::Target * i_target ) { TRACSSCOMP( g_trac_vpd, ENTER_MRK"cvpdPresent()"); #if(defined( CONFIG_MEMVPD_READ_FROM_HW ) && !defined( __HOSTBOOT_RUNTIME) ) return EEPROM::eepromPresence( i_target ); #else return Singleton<CvpdFacade>::instance().hasVpdPresent( i_target, CVPD::VEIR, CVPD::PF ); #endif }
bool DVPD::dvpdPresent( TARGETING::Target * i_target ) { TRACSSCOMP( g_trac_vpd, ENTER_MRK"dvpdPresent()"); #if(defined( CONFIG_MEMVPD_READ_FROM_HW ) && !defined( __HOSTBOOT_RUNTIME) ) return EEPROM::eepromPresence( i_target ); #else return Singleton<DvpdFacade>::instance().hasVpdPresent( i_target, //TODO RTC 144519 Update recod/keyword once records/keywords defined // to be used as "sniff test" that vpd is readable. CVPD::VEIR, CVPD::PF ); #endif }
/** * @brief This function will perform the steps required to do a read from * the Hostboot MVPD data. * * @param[in] i_opType - Operation Type - See DeviceFW::OperationType in * driververif.H * * @param[in] i_target - Processor Target device * * @param [in/out] io_buffer - Pointer to the data that was read from * the target device. This parameter, when set to NULL, will return * the keyword size value in io_buflen. * * @param [in/out] io_buflen - Length of the buffer to be read or written * to/from the target. This value should indicate the size of the * io_buffer parameter that has been allocated. Being returned it * will indicate the number of valid bytes in the buffer being * returned. This parameter will contain the size of a keyword when * the io_buffer parameter is passed in NULL. * * @param [in] i_accessType - Access Type - See DeviceFW::AccessType in * usrif.H * * @param [in] i_args - This is an argument list for the device driver * framework. * * @return errlHndl_t - NULL if successful, otherwise a pointer to the * error log. */ errlHndl_t mvpdRead ( DeviceFW::OperationType i_opType, TARGETING::Target * i_target, void * io_buffer, size_t & io_buflen, int64_t i_accessType, va_list i_args ) { errlHndl_t err = NULL; IpVpdFacade::input_args_t args; args.record = ((mvpdRecord)va_arg( i_args, uint64_t )); args.keyword = ((mvpdKeyword)va_arg( i_args, uint64_t )); TRACSSCOMP( g_trac_vpd, ENTER_MRK"mvpdRead()" ); err = Singleton<MvpdFacade>::instance().read(i_target, io_buffer, io_buflen, args); return err; }
// ------------------------------------------------------------------ // 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; }
// ------------------------------------------------------------------ // sendMboxWriteMsg // ------------------------------------------------------------------ errlHndl_t sendMboxWriteMsg ( size_t i_numBytes, void * i_data, TARGETING::Target * i_target, VPD_MSG_TYPE i_type, VpdWriteMsg_t& i_record ) { errlHndl_t l_err = NULL; msg_t* msg = NULL; TRACSSCOMP( g_trac_vpd, ENTER_MRK"sendMboxWriteMsg()" ); do { //Create a mailbox message to send to FSP msg = msg_allocate(); msg->type = i_type; msg->data[0] = i_record.data0; msg->data[1] = i_numBytes; //Copy the data into the message msg->extra_data = malloc( i_numBytes ); memcpy( msg->extra_data, i_data, i_numBytes ); TRACFCOMP( g_trac_vpd, INFO_MRK"sendMboxWriteMsg: Send msg to FSP to write VPD type %.8X, record %d, offset 0x%X", i_type, i_record.rec_num, i_record.offset ); //We only send VPD update when we have SP Base Services if( !INITSERVICE::spBaseServicesEnabled() ) { TRACFCOMP(g_trac_vpd, INFO_MRK "No SP Base Services, skipping VPD write"); TRACFBIN( g_trac_vpd, "msg=", msg, sizeof(msg_t) ); TRACFBIN( g_trac_vpd, "extra=", msg->extra_data, i_numBytes ); free (msg->extra_data); msg_free( msg ); break; } l_err = MBOX::send( MBOX::FSP_VPD_MSGQ, msg ); if( l_err ) { TRACFCOMP(g_trac_vpd, ERR_MRK "Failed sending VPD to FSP for %.8X", TARGETING::get_huid(i_target)); ERRORLOG::ErrlUserDetailsTarget(i_target).addToLog(l_err); l_err->collectTrace("VPD",1024); if( VPD_WRITE_DIMM == i_type ) { l_err->collectTrace("SPD",1024); } // just commit the log and move on, nothing else to do errlCommit( l_err, VPD_COMP_ID ); l_err = NULL; free( msg->extra_data ); msg->extra_data = NULL; msg_free( msg ); } } while( 0 ); TRACSSCOMP( g_trac_vpd, EXIT_MRK"sendMboxWriteMsg()" ); return l_err; }
// ------------------------------------------------------------------ // writePNOR // ------------------------------------------------------------------ errlHndl_t writePNOR ( uint64_t i_byteAddr, size_t i_numBytes, void * i_data, TARGETING::Target * i_target, pnorInformation & i_pnorInfo, uint64_t &io_cachedAddr, mutex_t * i_mutex ) { errlHndl_t err = NULL; int64_t vpdLocation = 0; uint64_t addr = 0x0; const char * writeAddr = NULL; TRACSSCOMP( g_trac_vpd, ENTER_MRK"writePNOR()" ); do { // Check if we have the PNOR addr cached. if( 0x0 == io_cachedAddr ) { err = getPnorAddr( i_pnorInfo, io_cachedAddr, i_mutex ); if( err ) { break; } } addr = io_cachedAddr; // Find vpd location of the target err = getVpdLocation( vpdLocation, i_target ); if( err ) { break; } // Offset cached address by vpd location multiplier addr += (vpdLocation * i_pnorInfo.segmentSize); // Now offset into that chunk of data by i_byteAddr addr += i_byteAddr; //TODO: Validate write is within bounds of appropriate PNOR // partition/section. RTC: 51807 TRACUCOMP( g_trac_vpd, INFO_MRK"Address to write: 0x%08x", addr ); // Write the data writeAddr = reinterpret_cast<const char*>( addr ); 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, EXIT_MRK"writePNOR()" ); return err; }
// ------------------------------------------------------------------ // readPNOR // ------------------------------------------------------------------ errlHndl_t readPNOR ( uint64_t i_byteAddr, size_t i_numBytes, void * o_data, TARGETING::Target * i_target, pnorInformation & i_pnorInfo, uint64_t &io_cachedAddr, mutex_t * i_mutex ) { errlHndl_t err = NULL; int64_t vpdLocation = 0; uint64_t addr = 0x0; const char * readAddr = NULL; TRACSSCOMP( g_trac_vpd, ENTER_MRK"readPNOR()" ); do { // Check if we have the PNOR addr cached. if( 0x0 == io_cachedAddr ) { err = getPnorAddr( i_pnorInfo, io_cachedAddr, i_mutex ); if( err ) { break; } } addr = io_cachedAddr; // Find vpd location of the target err = getVpdLocation( vpdLocation, i_target ); if( err ) { break; } // Offset cached address by vpd location multiplier addr += (vpdLocation * i_pnorInfo.segmentSize); // Now offset into that chunk of data by i_byteAddr addr += i_byteAddr; TRACUCOMP( g_trac_vpd, INFO_MRK"Address to read: 0x%08x", addr ); //TODO: Validate write is within bounds of appropriate PNOR // partition/section. RTC: 51807 // Pull the data readAddr = reinterpret_cast<const char*>( addr ); memcpy( o_data, readAddr, i_numBytes ); } while( 0 ); TRACSSCOMP( g_trac_vpd, EXIT_MRK"readPNOR()" ); return err; }
/** * @brief Performs a presence detect operation on MCSs * * Although not a physical part, presence detect confirms access * to direct access memory vpd. * * @param[in] i_opType Operation type, see DeviceFW::OperationType * in driverif.H * @param[in] i_target Presence detect target * @param[in/out] io_buffer Read: Pointer to output data storage * Write: Pointer to input data storage * @param[in/out] io_buflen Input: size of io_buffer (in bytes, always 1) * Output: Success = 1, Failure = 0 * @param[in] i_accessType DeviceFW::AccessType enum (userif.H) * @param[in] i_args This is an argument list for DD framework. * In this function, there are no arguments. * @return errlHndl_t */ errlHndl_t directMemoryPresenceDetect(DeviceFW::OperationType i_opType, TARGETING::Target* i_target, void* io_buffer, size_t& io_buflen, int64_t i_accessType, va_list i_args) { errlHndl_t l_errl = NULL; bool dvpd_present = false; TRACSSCOMP(g_trac_vpd, ENTER_MRK "directMemoryPresenceDetect"); if (unlikely(io_buflen < sizeof(bool))) { TRACFCOMP(g_trac_vpd, ERR_MRK "directMemoryPresenceDetect> Invalid data length: %d", io_buflen); /*@ * @errortype * @moduleid VPD::VPD_DVPD_PRESENCEDETECT * @reasoncode VPD::VPD_INVALID_LENGTH * @userdata1 Data Length * @devdesc presenceDetect> Invalid data length (!= 1 bytes) */ l_errl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, VPD::VPD_DVPD_PRESENCEDETECT, VPD::VPD_INVALID_LENGTH, TO_UINT64(io_buflen), true /*SW error*/); io_buflen = 0; return l_errl; } dvpd_present = DVPD::dvpdPresent( i_target ); #if defined(CONFIG_MEMVPD_READ_FROM_HW) && defined(CONFIG_MEMVPD_READ_FROM_PNOR) //skipping cache sync when dvpd is present as it will be taken care by node //vpd if( !dvpd_present ) { TRACFCOMP(g_trac_vpd, ERR_MRK "directMemoryPresenceDetect> failed presence detect"); // Defer invalidating DVPD in the PNOR in case another target might be // sharing this VPD_REC_NUM. Check all targets sharing this // VPD_REC_NUM after target discovery in VPD::validateSharedPnorCache. // Ensure the VPD_SWITCHES cache valid bit is invalid at this point. TARGETING::ATTR_VPD_SWITCHES_type vpdSwitches = i_target->getAttr<TARGETING::ATTR_VPD_SWITCHES>(); vpdSwitches.pnorCacheValid = 0; i_target->setAttr<TARGETING::ATTR_VPD_SWITCHES>( vpdSwitches ); } #endif memcpy(io_buffer, &dvpd_present, sizeof(dvpd_present)); io_buflen = sizeof(dvpd_present); TRACSSCOMP(g_trac_vpd, EXIT_MRK "directMemoryPresenceDetect = %d",dvpd_present); return NULL; }
// ------------------------------------------------------------------ // dimmPresenceDetect // ------------------------------------------------------------------ errlHndl_t dimmPresenceDetect( DeviceFW::OperationType i_opType, TARGETING::Target * i_target, void * io_buffer, size_t & io_buflen, int64_t i_accessType, va_list i_args ) { errlHndl_t err = NULL; bool present = false; size_t presentSz = sizeof(present); TRACSSCOMP( g_trac_spd, ENTER_MRK"dimmPresenceDetect()" ); do { // Check to be sure that the buffer is big enough. if( !(io_buflen >= sizeof(bool)) ) { TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() - Invalid Data Length: %d", io_buflen ); /*@ * @errortype * @reasoncode VPD::VPD_INSUFFICIENT_BUFFER_SIZE * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE * @moduleid VPD::VPD_SPD_PRESENCE_DETECT * @userdata1 Buffer Length * @userdata2 <UNUSED> * @devdesc Buffer for checking Presence Detect * was not the correct size. */ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, VPD::VPD_SPD_PRESENCE_DETECT, VPD::VPD_INSUFFICIENT_BUFFER_SIZE, TO_UINT64(io_buflen), 0x0, true /*Add HB Software Callout*/); err->collectTrace( "SPD", 256); break; } // Is the target present #ifdef CONFIG_DJVPD_READ_FROM_HW // Check if the parent MBA/MEMBUF is present. If it is not then // no reason to check the DIMM which would otherwise generate // tons of FSI errors. We can't just check if parent MBA // is functional because DIMM presence detect is called before // the parent MBA/MEMBUF is set as present/functional. TARGETING::TargetHandleList membufList; TARGETING::PredicateCTM membufPred( TARGETING::CLASS_CHIP, TARGETING::TYPE_MEMBUF ); TARGETING::targetService().getAssociated( membufList, i_target, TARGETING::TargetService::PARENT_BY_AFFINITY, TARGETING::TargetService::ALL, &membufPred); bool parentPresent = false; const TARGETING::TargetHandle_t membufTarget = *(membufList.begin()); err = deviceRead(membufTarget, &parentPresent, presentSz, DEVICE_PRESENT_ADDRESS()); if (err) { TRACFCOMP( g_trac_spd, "Error reading parent MEMBUF present: huid 0x%X DIMM huid 0x%X", TARGETING::get_huid(membufTarget), TARGETING::get_huid(i_target) ); break; } if (!parentPresent) { 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 ) { TRACUCOMP( g_trac_spd, INFO_MRK"Dimm was found to be NOT present." ); } else { TRACUCOMP( g_trac_spd, 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 if( present && !err ) { //Fsp sets PN/SN so if there is none, do it here if(!INITSERVICE::spBaseServicesEnabled()) { //populate serial and part number attributes SPD::setPartAndSerialNumberAttributes( i_target ); } // Read ATTR_CLEAR_DIMM_SPD_ENABLE attribute TARGETING::Target* l_sys = NULL; TARGETING::targetService().getTopLevelTarget(l_sys); TARGETING::ATTR_CLEAR_DIMM_SPD_ENABLE_type l_clearSPD = l_sys->getAttr<TARGETING::ATTR_CLEAR_DIMM_SPD_ENABLE>(); // If SPD clear is enabled then write 0's into magic word for // DIMM_BAD_DQ_DATA keyword // Note: If there's an error from performing the clearing, // just log the error and continue. if (l_clearSPD) { size_t l_size = 0; // Do a read to get the DIMM_BAD_DQ_DATA keyword size err = deviceRead(i_target, NULL, l_size, DEVICE_SPD_ADDRESS( DIMM_BAD_DQ_DATA )); if (err) { TRACFCOMP(g_trac_spd, "dimmPresenceDetect - " "Error reading DIMM_BAD_DQ_DATA keyword size"); errlCommit( err, VPD_COMP_ID ); } else { // Clear the data TRACFCOMP( g_trac_spd, "Clearing out BAD_DQ_DATA SPD on " "DIMM HUID 0x%X", TARGETING::get_huid(i_target)); uint8_t * l_data = static_cast<uint8_t*>(malloc( l_size )); memset(l_data, 0, l_size); err = deviceWrite(i_target, l_data, l_size, DEVICE_SPD_ADDRESS( DIMM_BAD_DQ_DATA )); if (err) { TRACFCOMP( g_trac_spd, "Error trying to clear SPD on " "DIMM HUID 0x%X", TARGETING::get_huid(i_target)); errlCommit( err, VPD_COMP_ID ); } // Free the memory if (NULL != l_data) { free(l_data); } } } } // copy present value into output buffer so caller can read it memcpy( io_buffer, &present, presentSz ); io_buflen = presentSz; } while( 0 ); TRACSSCOMP( g_trac_spd, EXIT_MRK"dimmPresenceDetect()" ); return err; } // end dimmPresenceDetect
// ------------------------------------------------------------------ // dimmPresenceDetect // ------------------------------------------------------------------ errlHndl_t dimmPresenceDetect( DeviceFW::OperationType i_opType, TARGETING::Target * i_target, void * io_buffer, size_t & io_buflen, int64_t i_accessType, va_list i_args ) { errlHndl_t err = NULL; bool present = false; size_t presentSz = sizeof(present); TRACSSCOMP( g_trac_spd, ENTER_MRK"dimmPresenceDetect() " "DIMM HUID 0x%X", TARGETING::get_huid(i_target)); do { // Check to be sure that the buffer is big enough. if( !(io_buflen >= sizeof(bool)) ) { TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() " "Invalid Data Length: %d", io_buflen ); /*@ * @errortype * @reasoncode VPD::VPD_INSUFFICIENT_BUFFER_SIZE * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE * @moduleid VPD::VPD_SPD_PRESENCE_DETECT * @userdata1 Buffer Length * @userdata2 <UNUSED> * @devdesc Buffer for checking Presence Detect * was not the correct size. */ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, VPD::VPD_SPD_PRESENCE_DETECT, VPD::VPD_INSUFFICIENT_BUFFER_SIZE, TO_UINT64(io_buflen), 0x0, true /*Add HB Software Callout*/); err->collectTrace( "SPD", 256); break; } // Is the target present? #ifdef CONFIG_DJVPD_READ_FROM_HW // Check if the i2c master is present. // If it is not then no reason to check the DIMM which would // otherwise generate tons of FSI errors. // We can't just check if parent MCA or MBA // is functional because DIMM presence detect is called before // the parent MCS/MCA or MBA/MEMBUF is set as present/functional. bool l_i2cMasterPresent = false; do { // get eeprom vpd primary info TARGETING::EepromVpdPrimaryInfo eepromData; if( !(i_target-> tryGetAttr<TARGETING::ATTR_EEPROM_VPD_PRIMARY_INFO> ( eepromData ) ) ) { TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() " "Error: no eeprom vpd primary info" ); break; } // find i2c master target TARGETING::TargetService& tS = TARGETING::targetService(); bool exists = false; tS.exists( eepromData.i2cMasterPath, exists ); if( !exists ) { TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() " "i2cMasterPath attribute path doesn't exist"); break; } // Since it exists, convert to a target TARGETING::Target * l_i2cMasterTarget = tS.toTarget( eepromData.i2cMasterPath ); if( NULL == l_i2cMasterTarget ) { TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() " "i2cMasterPath target is NULL"); break; } TRACSSCOMP( g_trac_spd, "dimmPresenceDetect() " "i2c master HUID 0x%X", TARGETING::get_huid(l_i2cMasterTarget)); // Check if present TARGETING::Target* masterProcTarget = NULL; TARGETING::targetService().masterProcChipTargetHandle( masterProcTarget ); // Master proc is taken as always present. Validate other targets. if (l_i2cMasterTarget != masterProcTarget) { l_i2cMasterPresent = FSI::isSlavePresent(l_i2cMasterTarget); if( !l_i2cMasterPresent ) { TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() " "isSlavePresent failed"); break; } } l_i2cMasterPresent = true; } while (0); if (!l_i2cMasterPresent) { present = false; // Invalidate the SPD in PNOR err = VPD::invalidatePnorCache(i_target); if (err) { TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() " "Error invalidating SPD in PNOR" ); } break; } #endif present = spdPresent( i_target ); if( present == false ) { TRACUCOMP( g_trac_spd, INFO_MRK"dimmPresenceDetect() " "Dimm was found to be NOT present." ); } else { TRACUCOMP( g_trac_spd, INFO_MRK"dimmPresenceDetect() " "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"dimmPresenceDetect() " "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, ERR_MRK"dimmPresenceDetect() " "Error invalidating SPD in PNOR" ); } } #endif if( present && !err ) { //Fsp sets PN/SN so if there is none, do it here if(!INITSERVICE::spBaseServicesEnabled()) { //populate serial and part number attributes SPD::setPartAndSerialNumberAttributes( i_target ); } // Read ATTR_CLEAR_DIMM_SPD_ENABLE attribute TARGETING::Target* l_sys = NULL; TARGETING::targetService().getTopLevelTarget(l_sys); TARGETING::ATTR_CLEAR_DIMM_SPD_ENABLE_type l_clearSPD = l_sys->getAttr<TARGETING::ATTR_CLEAR_DIMM_SPD_ENABLE>(); // If SPD clear is enabled then write 0's into magic word for // DIMM_BAD_DQ_DATA keyword // Note: If there's an error from performing the clearing, // just log the error and continue. if (l_clearSPD) { size_t l_size = 0; // Do a read to get the DIMM_BAD_DQ_DATA keyword size err = deviceRead(i_target, NULL, l_size, DEVICE_SPD_ADDRESS( DIMM_BAD_DQ_DATA )); if (err) { TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() " "Error reading DIMM_BAD_DQ_DATA keyword size"); errlCommit( err, VPD_COMP_ID ); } else { // Clear the data TRACFCOMP( g_trac_spd, "Clearing out BAD_DQ_DATA SPD on " "DIMM HUID 0x%X", TARGETING::get_huid(i_target)); uint8_t * l_data = static_cast<uint8_t*>(malloc( l_size )); memset(l_data, 0, l_size); err = deviceWrite(i_target, l_data, l_size, DEVICE_SPD_ADDRESS( DIMM_BAD_DQ_DATA )); if (err) { TRACFCOMP(g_trac_spd, ERR_MRK"dimmPresenceDetect() " "Error trying to clear SPD on DIMM HUID 0x%X", TARGETING::get_huid(i_target)); errlCommit( err, VPD_COMP_ID ); } // Free the memory if (NULL != l_data) { free(l_data); } } } } // copy present value into output buffer so caller can read it memcpy( io_buffer, &present, presentSz ); io_buflen = presentSz; } while( 0 ); TRACSSCOMP( g_trac_spd, EXIT_MRK"dimmPresenceDetect()" ); return err; } // end dimmPresenceDetect