/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* $Source: src/import/chips/p9a/procedures/hwp/memory/lib/freq/axone_sync.C $ */ /* */ /* OpenPOWER HostBoot Project */ /* */ /* Contributors Listed Below - COPYRIGHT 2019 */ /* [+] 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. */ /* You may obtain a copy of the License at */ /* */ /* http://www.apache.org/licenses/LICENSE-2.0 */ /* */ /* Unless required by applicable law or agreed to in writing, software */ /* distributed under the License is distributed on an "AS IS" BASIS, */ /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ /* implied. See the License for the specific language governing */ /* permissions and limitations under the License. */ /* */ /* IBM_PROLOG_END_TAG */ /// /// @file axone_sync.C /// @brief Synchronous function implementations for Axone /// // *HWP HWP Owner: Andre Marin // *HWP HWP Backup: Louis Stermole // *HWP Team: Memory // *HWP Level: 3 // *HWP Consumed by: HB:FSP #include #include #include #include #include // Memory libraries #include #include #include // Generic libraries #include #include #include #include #include #include #include #include #include namespace mss { /// /// @brief Retrieves a mapping of MSS frequency values per port target /// @param[in] i_targets vector of port targets /// @param[out] o_freq_map dimm speed map = (port target, frequency) /// @param[out] o_is_speed_equal holds whether map dimm speed is equal /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode dimm_speed_map(const std::vector< fapi2::Target >& i_targets, std::map< fapi2::Target, uint64_t >& o_freq_map, speed_equality& o_is_speed_equal) { o_freq_map.clear(); // The find_if loop is meant to find the "first" good (non-zero) freq value // so I can compare it against all other freq values from the MEM_PORT vector // I am checking to make sure I don't get a value of 0 // Since Cronus can hand me back a MEM_PORT w/no DIMMs // Which would give ATTR_MSS_FREQ value of 0 in p9_mss_freq uint64_t l_comparator = 0; fapi2::ReturnCode l_rc(fapi2::FAPI2_RC_FALSE); const auto l_found_comp = std::find_if(i_targets.begin(), i_targets.end(), [&l_rc, &l_comparator] (const fapi2::Target& i_target)->bool { l_rc = mss::attr::get_freq(i_target, l_comparator); return l_comparator != 0; }); // Getting error cross initializing with the Assert // find_if should work if passed in an empty vector. begin() and end() will match and it'll exit without trying freq() FAPI_ASSERT( !i_targets.empty(), fapi2::MSS_EMPTY_FREQ_TARGET_VECTOR_PASSED(), "Empty MEM_PORT target vector found when constructing dimm speed mapping!" ); FAPI_TRY(l_rc, "Failed accessor mss::freq()"); // If all MEM_PORTs are 0 we go no further // We shouldn't get here though. We check for DIMMS in freq_system. If no DIMMS, we exit // We can assume if there is a dimm configured at this point (after mss_freq) // It has a valid freq // Thus, this shouldn't ever happen, but let's check anyways FAPI_ASSERT( l_found_comp != i_targets.end(), fapi2::MSS_ALL_TARGETS_HAVE_0_FREQ() .set_VECTOR_SIZE(i_targets.size()), "All MEM_PORTs have 0 MSS_FREQ, but there are dimms?"); // DIMM speed is equal until we deduce otherwise o_is_speed_equal = speed_equality::EQUAL_DIMM_SPEEDS; // Make sure to stick the first one we found in the freq map. o_freq_map.emplace( std::make_pair(*l_found_comp, l_comparator) ); // Loop through all MEM_PORTs and store dimm speeds // Starting from 1st known good freq (non-zero) value // I found above to avoid double looping target vector for (auto l_iter = l_found_comp + 1; l_iter != i_targets.end(); ++l_iter) { uint64_t l_dimm_speed = 0; FAPI_TRY( mss::attr::get_freq(*l_iter, l_dimm_speed), "Failed accessor to mss_freq" ); // In FW, parents are deconfigured if they have no children // So there is no way to get a MEM_PORT w/no DIMMs. // This isn't true for Cronus so I am skipping map // insertion and check for dimm speed equality // to avoid incorrect settings if( l_dimm_speed != 0) { // At least one mismatch freq value occurred if(l_comparator != l_dimm_speed) { o_is_speed_equal = speed_equality::NOT_EQUAL_DIMM_SPEEDS; } FAPI_INF("%s: Dimm speed %d MT/s", c_str(*l_iter), l_dimm_speed); o_freq_map.emplace( std::make_pair(*l_iter, l_dimm_speed) ); } } // Idiot check - most certainly a programming error FAPI_ASSERT( o_freq_map.size() != 0, fapi2::MSS_ERROR_FINDING_DIMM_SPEED_MAP(), "freq system freq map is empty? found port: %s", mss::c_str(*l_found_comp) ); fapi_try_exit: return fapi2::current_err; } /// /// @brief Deconfigures MEM_PORT targets /// @param[in] i_target the port target /// @param[in] i_dimm_speed dimm speed in MT/s /// @param[in] i_max_freq maximum dimm freq in MT/s of freq domain /// @return true if hardware was deconfigured /// bool deconfigure(const fapi2::Target& i_target, const uint64_t i_dimm_speed, const uint32_t i_max_freq) { bool l_is_hw_deconfigured = (i_dimm_speed != i_max_freq); MSS_ASSERT_NOEXIT(!l_is_hw_deconfigured, fapi2::MSS_FREQ_NOT_EQUAL_MAX_DOMAIN_FREQ() .set_MSS_FREQ(i_dimm_speed) .set_DOMAIN_FREQ(i_max_freq) .set_DOMAIN_TARGET(i_target), "Deconfiguring %s due to unequal frequencies: this port: %d, Max in freq domain: %d", mss::c_str(i_target), i_dimm_speed, i_max_freq ); return l_is_hw_deconfigured; } /// /// @brief Selects synchronous mode and performs requirements enforced by selected port frequency /// @param[in] i_freq_map dimm speed mapping /// @param[in] i_equal_dimm_speed tracks whether map has equal dimm speeds /// @param[in] i_omi_freq OMI frequency /// @param[out] o_selected_sync_mode final synchronous mode /// @param[out] o_selected_omi_freq final freq selected, only valid if final sync mode is in-sync /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode select_sync_mode(const std::map< fapi2::Target, uint64_t >& i_freq_map, const speed_equality i_equal_dimm_speed, const uint32_t i_omi_freq, uint8_t& o_selected_sync_mode, uint64_t& o_selected_omi_freq) { FAPI_INF("---- In select_sync_mode ----"); switch(i_equal_dimm_speed) { // If we have a port which has resolved to equal speeds ... case speed_equality::EQUAL_DIMM_SPEEDS: { // Return back the resulting speed. It doesn't matter which we select from the map as they're all equal // If we end up not in sync in the conditional below, thats ok - this parameter is ignored by the // caller if we're not in sync mode const auto l_ddr_freq = i_freq_map.begin()->second; FAPI_TRY(convert_ddr_freq_to_omi_freq(i_freq_map.begin()->first, l_ddr_freq, o_selected_omi_freq)); // When we selected ATTR_MSS_FREQ, we made sure that we didn't // select a DIMM freq the OMI couldn't support. o_selected_sync_mode = fapi2::ENUM_ATTR_MC_SYNC_MODE_IN_SYNC; // On Cronus if the o_selected_omi_freq != i_omi_freq we've got a mismatch. Note that p9a_mss_freq ensures // we don't select an invalid freq, but doesn't ensure we select the current OMI freq. #ifndef __HOSTBOOT_MODULE FAPI_ASSERT(o_selected_omi_freq == i_omi_freq, fapi2::P9A_MSS_FAILED_SYNC_MODE() .set_OMI_FREQ(i_omi_freq) .set_MEM_FREQ(o_selected_omi_freq), "The DIMM freq (%d) and the OMI freq (%d) don't align", o_selected_omi_freq, i_omi_freq); #endif return fapi2::FAPI2_RC_SUCCESS; break; } case speed_equality::NOT_EQUAL_DIMM_SPEEDS: { // When we selected ATTR_MSS_FREQ, we made sure that we didn't // select a DIMM freq the OMI couldn't support. That means that the fastest of the ports // is the one that rules the roost (the OMI can support it too.) So find that, and set it to // the selected frequency. Then deconfigure the slower port (unless we're in Cronus in which // case we just bomb out.) #ifdef __HOSTBOOT_MODULE uint64_t l_max_dimm_speed = 0; fapi2::Target l_fastest_port_target = i_freq_map.begin()->first; std::for_each(i_freq_map.begin(), i_freq_map.end(), [&l_max_dimm_speed](const std::pair, uint64_t>& m) { l_max_dimm_speed = std::max(l_max_dimm_speed, m.second); l_fastest_port_target = m.first; }); std::for_each(i_freq_map.begin(), i_freq_map.end(), [&l_max_dimm_speed](const std::pair, uint64_t>& m) { deconfigure(m.first, m.second, l_max_dimm_speed); }); o_selected_sync_mode = fapi2::ENUM_ATTR_MC_SYNC_MODE_IN_SYNC; FAPI_TRY(convert_ddr_freq_to_omi_freq(l_fastest_port_target, l_max_dimm_speed, o_selected_omi_freq)); return fapi2::FAPI2_RC_SUCCESS; #else // Cronus only FAPI_ASSERT(false, fapi2::P9A_MSS_FAILED_SYNC_MODE() .set_OMI_FREQ(i_omi_freq), "DIMM speeds differ from OMI speed %d", i_omi_freq); #endif break; } default: // Switches on an enum class // The only valid speed_equality values are NOT_EQUAL and EQUAL. // If it's something else ,I think it's a code error and really shouldn't be possible, thus fapi2::Assert below FAPI_ERR("Invalid speed_equality parameter!"); fapi2::Assert(false); break; }// end switch return fapi2::FAPI2_RC_SUCCESS; #ifndef __HOSTBOOT_MODULE fapi_try_exit: return fapi2::current_err; #endif } }// mss