1 #pragma once
2 
3 #include <fstream>
4 #include <experimental/filesystem>
5 #include "occ_events.hpp"
6 #include "occ_errors.hpp"
7 #include "occ_presence.hpp"
8 #include "config.h"
9 
10 namespace open_power
11 {
12 namespace occ
13 {
14 
15 class Manager;
16 class Status;
17 namespace fs = std::experimental::filesystem;
18 
19 /** @class Device
20  *  @brief Binds and unbinds the OCC driver upon request
21  */
22 class Device
23 {
24     public:
25         Device() = delete;
26         ~Device() = default;
27         Device(const Device&) = delete;
28         Device& operator=(const Device&) = delete;
29         Device(Device&&) = default;
30         Device& operator=(Device&&) = default;
31 
32         /** @brief Constructs the Device object
33          *
34          *  @param[in] event    - Unique ptr reference to sd_event
35          *  @param[in] name     - OCC instance name
36          *  @param[in] manager  - OCC manager instance
37          *  @param[in] callback - Optional callback on errors
38          */
39         Device(EventPtr& event,
40                const std::string& name,
41                const Manager& manager,
42                Status& status,
43                std::function<void(bool)> callBack = nullptr) :
44 #ifdef I2C_OCC
45             config(name),
46 #else
47             config(name + '-' + "dev0"),
48 #endif
49             errorFile(fs::path(config) / "occ_error"),
50             statusObject(status),
51             error(event, errorFile, callBack),
52             presence(event,
53                      fs::path(config) / "occs_present",
54                      manager,
55                      callBack),
56             throttleProcTemp(
57                 event,
58                 fs::path(config) / "occ_dvfs_ot",
59                 std::bind(std::mem_fn(&Device::throttleProcTempCallback),
60                           this,
61                           std::placeholders::_1)),
62             throttleProcPower(
63                 event,
64                 fs::path(config) / "occ_dvfs_power",
65                 std::bind(std::mem_fn(&Device::throttleProcPowerCallback),
66                           this,
67                           std::placeholders::_1)),
68             throttleMemTemp(
69                 event,
70                 fs::path(config) / "occ_mem_throttle",
71                 std::bind(std::mem_fn(&Device::throttleMemTempCallback),
72                           this,
73                           std::placeholders::_1))
74         {
75             // Nothing to do here
76         }
77 
78         /** @brief Binds device to the OCC driver */
79         inline void bind()
80         {
81             // Bind the device
82             return write(bindPath, config);
83         }
84 
85         /** @brief Un-binds device from the OCC driver */
86         inline void unBind()
87         {
88            // Unbind the device
89            return write(unBindPath, config);
90         }
91 
92         /** @brief Returns if device is already bound.
93          *
94          *  On device bind, a soft link by the name $config
95          *  gets created in OCC_HWMON_PATH and gets removed
96          *  on unbind
97          *
98          *  @return true if bound, else false
99          */
100         inline bool bound() const
101         {
102             return fs::exists(OCC_HWMON_PATH + config);
103         }
104 
105         /** @brief Starts to monitor for errors */
106         inline void addErrorWatch()
107         {
108             if (master())
109             {
110                 presence.addWatch();
111             }
112 
113             throttleProcTemp.addWatch();
114             throttleProcPower.addWatch();
115             throttleMemTemp.addWatch();
116             error.addWatch();
117         }
118 
119         /** @brief stops monitoring for errors */
120         inline void removeErrorWatch()
121         {
122             // we can always safely remove watch even if we don't add it
123             presence.removeWatch();
124             error.removeWatch();
125             error.removeWatch();
126             throttleMemTemp.removeWatch();
127             throttleProcPower.removeWatch();
128             throttleProcTemp.removeWatch();
129         }
130 
131     private:
132         /** @brief Config value to be used to do bind and unbind */
133         const std::string config;
134 
135         /** @brief This file contains 0 for success, non-zero for errors */
136         const fs::path errorFile;
137 
138         /**  @brief To bind the device to the OCC driver, do:
139          *
140          *    Write occ<#>-dev0 to: /sys/bus/platform/drivers/occ-hwmon/bind
141          */
142         static fs::path bindPath;
143 
144         /**  @brief To un-bind the device from the OCC driver, do:
145          *    Write occ<#>-dev0 to: /sys/bus/platform/drivers/occ-hwmon/unbind
146          */
147         static fs::path unBindPath;
148 
149         /**  Store the associated Status instance */
150         Status& statusObject;
151 
152         /** Abstraction of error monitoring */
153         Error error;
154 
155         /** Abstraction of OCC presence monitoring */
156         Presence presence;
157 
158         /** Error instances for watching for throttling events */
159         Error throttleProcTemp;
160         Error throttleProcPower;
161         Error throttleMemTemp;
162 
163         /** @brief file writer to achieve bind and unbind
164          *
165          *  @param[in] filename - Name of file to be written
166          *  @param[in] data     - Data to be written to
167          *  @return             - None
168          */
169         void write(const fs::path& fileName, const std::string& data)
170         {
171             // If there is an error, move the exception all the way up
172             std::ofstream file(fileName, std::ios::out);
173             file << data;
174             file.close();
175             return;
176         }
177 
178         /** @brief Returns if device represents the master OCC */
179         bool master() const;
180 
181         /** @brief callback for the proc temp throttle event
182          *
183          *  @param[in] error - True if an error is reported, false otherwise
184          */
185         void throttleProcTempCallback(bool error);
186 
187         /** @brief callback for the proc power throttle event
188          *
189          *  @param[in] error - True if an error is reported, false otherwise
190          */
191         void throttleProcPowerCallback(bool error);
192 
193         /** @brief callback for the proc temp throttle event
194          *
195          *  @param[in] error - True if an error is reported, false otherwise
196          */
197         void throttleMemTempCallback(bool error);
198 };
199 
200 } // namespace occ
201 } // namespace open_power
202