| #ifndef THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_HOST_STATE_POWER_CONTROL_H_ |
| #define THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_HOST_STATE_POWER_CONTROL_H_ |
| |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| #include "absl/base/thread_annotations.h" |
| #include "absl/functional/any_invocable.h" |
| #include "absl/status/statusor.h" |
| #include "absl/synchronization/mutex.h" |
| #include "absl/time/time.h" |
| #include "boost/asio/executor_work_guard.hpp" // NOLINT: boost is commonly used in BMC |
| #include "boost/asio/io_context.hpp" // NOLINT: boost is commonly used in BMC |
| #include "boost/asio/steady_timer.hpp" // NOLINT: boost is commonly used in BMC |
| #include "thread/thread.h" |
| #include "time/clock.h" |
| #include "nlohmann/json.hpp" |
| #include "tlbmc/collector/gpio_collector.h" |
| #include "gpio_config.pb.h" |
| #include "power_control.pb.h" |
| #include "tlbmc/scheduler/scheduler.h" |
| |
| namespace milotic_tlbmc { |
| |
| class PowerControl { |
| public: |
| enum class PowerControlType { kGpio, kFileBased }; |
| struct RetryPolicy { |
| // Default retry policy is to retry 5 times with a 10 second interval |
| // between retries. |
| RetryPolicy() : max_retries(5), retry_interval(absl::Seconds(10)) {} |
| int max_retries; |
| absl::Duration retry_interval; |
| }; |
| |
| struct Params { |
| // Using a thread factory to allow us to switch to fibers in future when it |
| // gets open sourced. |
| ecclesia::ThreadFactoryInterface* thread_factory = |
| ecclesia::GetDefaultThreadFactory(); |
| ecclesia::Clock* clock = ecclesia::Clock::RealClock(); |
| PowerControlConfig power_control_config; |
| GpioCollector* gpio_collector; |
| |
| PowerControlType power_control_type = PowerControlType::kGpio; |
| |
| std::string host_power_file_path = "/var/lib/power-control/state.json"; |
| std::string os_state_file_path = "/var/lib/power-control/os-state.json"; |
| RetryPolicy retry_policy; |
| }; |
| |
| virtual ~PowerControl() = default; |
| |
| // SystemResetRequest is called when the system reset is requested. |
| virtual void SystemResetRequest([[maybe_unused]] SystemResetType reset_type, |
| [[maybe_unused]] absl::Duration delay) {}; |
| // Requests are called by client from SystemResetRequest |
| // For these requests, see go/power-control-graph for more details. |
| virtual void PowerCycleRequest() {}; |
| virtual void PowerOnRequest() {}; |
| virtual void PowerOffRequest() {}; |
| virtual void ResetRequest() {}; |
| virtual void GracefulPowerOffRequest() {}; |
| virtual void GracefulPowerCycleRequest() {}; |
| virtual HostState GetHostState() = 0; |
| |
| virtual void Start() {} |
| virtual void Stop() {} |
| virtual void RegisterHostPowerOnToOffCallback( |
| [[maybe_unused]] absl::AnyInvocable<void(bool) const> callback) {} |
| virtual void RegisterHostPowerOffToOnCallback( |
| [[maybe_unused]] absl::AnyInvocable<void(bool) const> callback) {} |
| virtual void RegisterHostOSInactiveToStandbyCallback( |
| [[maybe_unused]] absl::AnyInvocable<void(bool) const> callback) {} |
| virtual void RegisterHostOSStandbyToInactiveCallback( |
| [[maybe_unused]] absl::AnyInvocable<void(bool) const> callback) {} |
| virtual nlohmann::json ToJson() { return nlohmann::json(); }; |
| virtual absl::Time GetLastStateChangeTime() { return absl::InfinitePast(); } |
| }; |
| |
| struct PowerControlThreadManager { |
| explicit PowerControlThreadManager(ecclesia::Clock* clock) |
| : task_scheduler(std::make_unique<TaskScheduler>(clock)) {} |
| |
| ~PowerControlThreadManager(); |
| |
| std::vector<std::unique_ptr<ecclesia::ThreadInterface>> threads; |
| std::vector<std::shared_ptr<boost::asio::io_context>> io_contexts; |
| std::vector< |
| boost::asio::executor_work_guard<boost::asio::io_context::executor_type>> |
| work_guards; |
| std::unique_ptr<TaskScheduler> task_scheduler; |
| }; |
| |
| class PowerControlGpio : public PowerControl { |
| public: |
| static absl::StatusOr<std::unique_ptr<PowerControlGpio>> Create( |
| const Params& params); |
| |
| ~PowerControlGpio() override; |
| |
| HostState GetHostState() override { |
| absl::MutexLock lock(host_state_mutex_); |
| return host_state_; |
| } |
| |
| // PowerOkHandler is called when the power OK GPIO line changes. |
| void PowerOkHandler(GpioEventType event); |
| // PostCompleteHandler is called when the POST complete GPIO line changes. |
| void PostCompleteHandler(GpioEventType event); |
| |
| void SystemResetRequest(SystemResetType reset_type, |
| absl::Duration delay) override; |
| |
| void PowerOnRequest() override; |
| void PowerOffRequest() override; |
| void PowerCycleRequest() override; |
| void ResetRequest() override; |
| void GracefulPowerOffRequest() override; |
| void GracefulPowerCycleRequest() override; |
| nlohmann::json ToJson() override; |
| |
| // For testing only. Provide ability to cancel all timers in unit tests. |
| void CancelAllTimers() { |
| power_cycle_timer_.cancel(); |
| power_ok_watchdog_timer_.cancel(); |
| graceful_power_off_timer_.cancel(); |
| warm_reset_check_timer_.cancel(); |
| } |
| |
| absl::Time GetLastStateChangeTime() override; |
| |
| void Start() override; |
| |
| void RegisterHostPowerOnToOffCallback( |
| absl::AnyInvocable<void(bool) const> callback) |
| ABSL_LOCKS_EXCLUDED(power_state_callback_mutex_) override; |
| void RegisterHostPowerOffToOnCallback( |
| absl::AnyInvocable<void(bool) const> callback) |
| ABSL_LOCKS_EXCLUDED(power_state_callback_mutex_) override; |
| void RegisterHostOSInactiveToStandbyCallback( |
| absl::AnyInvocable<void(bool) const> callback) |
| ABSL_LOCKS_EXCLUDED(os_state_callback_mutex_) override; |
| void RegisterHostOSStandbyToInactiveCallback( |
| absl::AnyInvocable<void(bool) const> callback) |
| ABSL_LOCKS_EXCLUDED(os_state_callback_mutex_) override; |
| |
| protected: |
| PowerControlGpio(HostState host_state, |
| PowerControlConfig power_control_config, |
| GpioCollector* gpio_collector, |
| std::unique_ptr<PowerControlThreadManager>&& thread_manager, |
| boost::asio::steady_timer&& power_cycle_timer, |
| boost::asio::steady_timer&& power_ok_watchdog_timer, |
| boost::asio::steady_timer&& graceful_power_off_timer, |
| boost::asio::steady_timer&& warm_reset_check_timer, |
| ecclesia::Clock* clock = ecclesia::Clock::RealClock()); |
| |
| // For testing only. |
| explicit PowerControlGpio( |
| const std::shared_ptr<boost::asio::io_context>& io_context) |
| : power_cycle_timer_(*io_context), |
| power_ok_watchdog_timer_(*io_context), |
| graceful_power_off_timer_(*io_context), |
| warm_reset_check_timer_(*io_context), |
| clock_(ecclesia::Clock::RealClock()) {} |
| |
| private: |
| void SetPowerState(PowerState state) |
| ABSL_EXCLUSIVE_LOCKS_REQUIRED(host_state_mutex_); |
| |
| void StartPowerCycleTimer(); |
| void PowerCycleTimerExpired(); |
| |
| void StartPowerOKWatchdogTimer(); |
| void PowerOkWatchdogTimerExpired(); |
| |
| void StartGracefulPowerOffTimer(); |
| void GracefulPowerOffTimerExpired(); |
| |
| void StartWarmResetCheckTimer(); |
| void WarmResetCheckTimerExpired(); |
| |
| void PowerOn(); |
| void ForcePowerOff(); |
| void GracefulPowerOff(); |
| void Reset(); |
| |
| absl::Mutex host_state_mutex_; |
| absl::Mutex power_state_callback_mutex_; |
| absl::Mutex os_state_callback_mutex_; |
| HostState host_state_ ABSL_GUARDED_BY(host_state_mutex_); |
| PowerControlConfig power_control_config_; |
| |
| GpioCollector* gpio_collector_ = nullptr; |
| std::unique_ptr<PowerControlThreadManager> thread_manager_; |
| |
| boost::asio::steady_timer power_cycle_timer_; |
| boost::asio::steady_timer power_ok_watchdog_timer_; |
| boost::asio::steady_timer graceful_power_off_timer_; |
| boost::asio::steady_timer warm_reset_check_timer_; |
| |
| ecclesia::Clock* clock_; |
| absl::Time last_state_change_time_ ABSL_GUARDED_BY(host_state_mutex_) = |
| absl::InfinitePast(); |
| |
| std::vector<absl::AnyInvocable<void(bool) const>> |
| host_power_on_to_off_callbacks_ |
| ABSL_GUARDED_BY(power_state_callback_mutex_); |
| std::vector<absl::AnyInvocable<void(bool) const>> |
| host_power_off_to_on_callbacks_ |
| ABSL_GUARDED_BY(power_state_callback_mutex_); |
| std::vector<absl::AnyInvocable<void(bool) const>> |
| host_os_inactive_to_standby_callbacks_ |
| ABSL_GUARDED_BY(os_state_callback_mutex_); |
| std::vector<absl::AnyInvocable<void(bool) const>> |
| host_os_standby_to_inactive_callbacks_ |
| ABSL_GUARDED_BY(os_state_callback_mutex_); |
| }; |
| |
| } // namespace milotic_tlbmc |
| |
| #endif // THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_HOST_STATE_POWER_CONTROL_H_ |