| /* |
| * Copyright 2023 Google LLC |
| * |
| * 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. |
| */ |
| #include "soc-reset-me.hpp" |
| |
| #include "phosphor-logging/lg2/flags.hpp" |
| |
| #include <phosphor-logging/lg2.hpp> |
| |
| #include <chrono> |
| #include <exception> |
| #include <string> |
| #include <variant> |
| using namespace std::literals; |
| namespace pldm_oem_google |
| { |
| namespace soc_reset_me |
| { |
| |
| std::optional<SocId> PeerSoCId::socId; |
| |
| // mapping pldmd command line --instance input to PeerSoCId |
| // siliently ignore invaild input and leave PeerSoCId unset |
| // current mapping policy: |
| // instance 0 => cn1, instance 1 => cn2 |
| bool PeerSoCId::setWithPldmdInstanceParam(const std::string& instance) |
| { |
| bool ret = false; |
| try |
| { |
| auto id = std::stoi(instance); |
| switch (id) |
| { |
| case 0: |
| { |
| ret = Set(SocId::cn1); |
| } |
| break; |
| case 1: |
| { |
| ret = Set(SocId::cn2); |
| } |
| break; |
| } |
| } |
| catch (const std::exception& e) |
| {} |
| return ret; |
| } |
| |
| static constexpr struct ResetDBusParams socResetDbusParamsCn1 = { |
| .conn = "xyz.openbmc_project.State.Host1", |
| .path = "/xyz/openbmc_project/state/host1", |
| .intf = "xyz.openbmc_project.State.Host", |
| .prop = "RequestedHostTransition", |
| }; |
| const ResetDBusParams* cn1DbusParams() |
| { |
| return &socResetDbusParamsCn1; |
| } |
| |
| static constexpr struct ResetDBusParams socResetDbusParamsCn2 = { |
| .conn = "xyz.openbmc_project.State.Host2", |
| .path = "/xyz/openbmc_project/state/host2", |
| .intf = "xyz.openbmc_project.State.Host", |
| .prop = "RequestedHostTransition", |
| }; |
| const ResetDBusParams* cn2DbusParams() |
| { |
| return &socResetDbusParamsCn2; |
| } |
| |
| SocResetMeHandler::SocResetMeHandler(const SocId id, sdbusplus::bus_t&& b) : |
| socId(id), bus(std::forward<sdbusplus::bus_t>(b)), |
| quiescentEnd(std::chrono::steady_clock::now()) |
| { |
| switch (socId) |
| { |
| case SocId::cn1: |
| dbusParams = &socResetDbusParamsCn1; |
| break; |
| case SocId::cn2: |
| dbusParams = &socResetDbusParamsCn2; |
| break; |
| default: |
| throw InvalidSoCIdException(static_cast<int>(socId)); |
| } |
| } |
| |
| void SocResetMeHandler::handle( |
| [[maybe_unused]] uint8_t requesterTid, |
| [[maybe_unused]] const struct pldm_event_oem_google_soc_reset_me* |
| resetMeMsg, |
| [[maybe_unused]] size_t resetMeMsgLen) |
| { |
| auto requestTime = std::chrono::steady_clock::now(); |
| auto resetReason = std::string(reinterpret_cast<const char*>(resetMeMsg) + |
| sizeof(*resetMeMsg), |
| resetMeMsg->descLen); |
| logRequest(resetMeMsg->internalInfo, resetMeMsg->resetType, |
| resetMeMsg->resetQuiesent, resetReason); |
| // Handle the event |
| if (requestTime <= quiescentEnd) |
| { |
| logRequestIgnored(requestTime); |
| return; |
| } |
| |
| this->resetSoC(resetMeMsg->resetType); |
| |
| quiescentEnd = std::chrono::steady_clock::now() + |
| std::chrono::seconds(resetMeMsg->resetQuiesent); |
| |
| logRequestIssued(requestTime); |
| } |
| |
| std::string SocResetMeHandler::requestedHostTransition( |
| [[maybe_unused]] const uint16_t resetType) |
| { |
| return "xyz.openbmc_project.State.Host.Transition.Reboot"; |
| } |
| |
| void SocResetMeHandler::resetSoC(const uint16_t resetType) |
| { |
| // Create a D-Bus method call to set the property |
| auto methodCall = bus.new_method_call(dbusParams->conn, dbusParams->path, |
| "org.freedesktop.DBus.Properties", |
| "Set"); |
| |
| methodCall.append( |
| dbusParams->intf, dbusParams->prop, |
| std::variant<std::string>{this->requestedHostTransition(resetType)}); |
| |
| bus.call(methodCall); |
| } |
| |
| void SocResetMeHandler::logRequest(uint64_t internalInfo, uint16_t resetType, |
| uint32_t quiescentPeriod, |
| const std::string& resetReason) const |
| { |
| lg2::info( |
| "SOC_RESET_ME requested from {SOC_RESET_ME_SOCID}: {SOC_RESET_ME_RESET_REASON}", |
| "SOC_RESET_ME", "request"sv, "SOC_RESET_ME_SOCID", |
| static_cast<int>(socId), "SOC_RESET_ME_INTERNAL_INFO", |
| (lg2::hex | lg2::field64), internalInfo, "SOC_RESET_ME_RESET_TYPE", |
| resetType, "SOC_RESET_ME_QUIESCENT_PERIOD", quiescentPeriod, |
| "SOC_RESET_ME_RESET_REASON", resetReason); |
| } |
| |
| void SocResetMeHandler::logRequestIgnored( |
| const ResetTimeStamp& requestTime) const |
| { |
| lg2::info( |
| "SOC_RESET_ME request from {SOC_RESET_ME_SOCID}@{SOC_RESET_ME_REQUEST_AT} ignored", |
| "SOC_RESET_ME", "ignored"sv, "SOC_RESET_ME_SOCID", |
| static_cast<int>(socId), "SOC_RESET_ME_REQUEST_AT", |
| duration_cast<std::chrono::seconds>(requestTime.time_since_epoch()) |
| .count(), |
| "SOC_RESET_ME_QUIESCENT_END", |
| duration_cast<std::chrono::seconds>(quiescentEnd.time_since_epoch()) |
| .count()); |
| } |
| |
| void SocResetMeHandler::logRequestIssued( |
| const ResetTimeStamp& requestTime) const |
| { |
| lg2::info( |
| "SOC_RESET_ME request from {SOC_RESET_ME_SOCID}@{SOC_RESET_ME_REQUEST_AT} issued", |
| "SOC_RESET_ME", "issued"sv, "SOC_RESET_ME_SOCID", |
| static_cast<int>(socId), "SOC_RESET_ME_REQUEST_AT", |
| duration_cast<std::chrono::seconds>(requestTime.time_since_epoch()) |
| .count(), |
| "SOC_RESET_ME_QUIESCENT_END", |
| duration_cast<std::chrono::seconds>(quiescentEnd.time_since_epoch()) |
| .count()); |
| } |
| |
| } // namespace soc_reset_me |
| } // namespace pldm_oem_google |