summaryrefslogtreecommitdiffstats
path: root/targets.hpp
blob: 49e02ec193e33423bef9d1c8440b46f9f81ba6ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#pragma once

#include "env.hpp"
#include "fan_pwm.hpp"
#include "fan_speed.hpp"
#include "hwmonio.hpp"

#include <filesystem>
#include <memory>
#include <phosphor-logging/elog-errors.hpp>
#include <phosphor-logging/log.hpp>
#include <xyz/openbmc_project/Sensor/Device/error.hpp>

enum class targetType
{
    DEFAULT,
    RPM,
    PWM
};

static constexpr auto RPM_TARGET = "RPM";
static constexpr auto PWM_TARGET = "PWM";

/** @class Targets
 *  @brief Target type traits.
 *
 *  @tparam T - The target type.
 */
template <typename T>
struct Targets
{
    static void fail()
    {
        static_assert(sizeof(Targets) == -1, "Unsupported Target type");
    }
};

/**@brief Targets specialization for fan speed. */
template <>
struct Targets<hwmon::FanSpeed>
{
    static constexpr InterfaceType type = InterfaceType::FAN_SPEED;
};

template <>
struct Targets<hwmon::FanPwm>
{
    static constexpr InterfaceType type = InterfaceType::FAN_PWM;
};

/** @brief addTarget
 *
 *  Creates the target type interface
 *
 *  @tparam T - The target type
 *
 *  @param[in] sensor - A sensor type and name
 *  @param[in] ioAccess - hwmon sysfs access object
 *  @param[in] devPath - The /sys/devices sysfs path
 *  @param[in] info - The sdbusplus server connection and interfaces
 *
 *  @return A shared pointer to the target interface object
 *          Will be empty if no interface was created
 */
template <typename T>
std::shared_ptr<T> addTarget(const SensorSet::key_type& sensor,
                             const hwmonio::HwmonIO& ioAccess,
                             const std::string& devPath, ObjectInfo& info)
{
    std::shared_ptr<T> target;
    namespace fs = std::filesystem;

    auto& obj = std::get<Object>(info);
    auto& objPath = std::get<std::string>(info);
    auto type = Targets<T>::type;

    // Check if target sysfs file exists
    std::string sysfsFullPath;
    std::string targetName = sensor.first;
    std::string targetId = sensor.second;
    std::string entry = hwmon::entry::target;

    using namespace std::literals;
    const std::string pwm = "pwm"s;
    const std::string empty = ""s;

    if (InterfaceType::FAN_SPEED == type)
    {
        // If RPM_TARGET is set, use the specified pwm id
        auto id = env::getEnv("RPM_TARGET", sensor);
        if (!id.empty())
        {
            targetName = pwm;
            targetId = id;
        }
        entry = empty;
    }

    if (InterfaceType::FAN_PWM == type)
    {
        targetName = pwm;
        // If PWM_TARGET is set, use the specified pwm id
        auto id = env::getEnv("PWM_TARGET", sensor);
        if (!id.empty())
        {
            targetId = id;
        }
        entry = empty;
    }

    sysfsFullPath =
        sysfs::make_sysfs_path(ioAccess.path(), targetName, targetId, entry);
    if (fs::exists(sysfsFullPath))
    {
        auto useTarget = true;
        auto tmEnv = env::getEnv("TARGET_MODE");
        if (!tmEnv.empty())
        {
            std::string mode{tmEnv};
            std::transform(mode.begin(), mode.end(), mode.begin(), toupper);

            if (mode == RPM_TARGET)
            {
                if (type != InterfaceType::FAN_SPEED)
                {
                    useTarget = false;
                }
            }
            else if (mode == PWM_TARGET)
            {
                if (type != InterfaceType::FAN_PWM)
                {
                    useTarget = false;
                }
            }
            else
            {
                using namespace phosphor::logging;
                log<level::ERR>(
                    "Invalid TARGET_MODE env var found",
                    phosphor::logging::entry("TARGET_MODE=%s", tmEnv.c_str()),
                    phosphor::logging::entry("DEVPATH=%s", devPath.c_str()));
            }
        }

        if (useTarget)
        {
            uint32_t targetSpeed = 0;

            try
            {
                targetSpeed = ioAccess.read(targetName, targetId, entry,
                                            hwmonio::retries, hwmonio::delay);
            }
            catch (const std::system_error& e)
            {
                using namespace phosphor::logging;
                using namespace sdbusplus::xyz::openbmc_project::Sensor::
                    Device::Error;
                using metadata =
                    xyz::openbmc_project::Sensor::Device::ReadFailure;

                report<ReadFailure>(
                    metadata::CALLOUT_ERRNO(e.code().value()),
                    metadata::CALLOUT_DEVICE_PATH(devPath.c_str()));

                log<level::INFO>(
                    "Logging failing sysfs file",
                    phosphor::logging::entry("FILE=%s", sysfsFullPath.c_str()));
            }

            static constexpr bool deferSignals = true;
            auto& bus = *std::get<sdbusplus::bus::bus*>(info);

            // ioAccess.path() is a path like: /sys/class/hwmon/hwmon1
            target = std::make_shared<T>(
                std::move(std::make_unique<hwmonio::HwmonIO>(ioAccess.path())),
                devPath, targetId, bus, objPath.c_str(), deferSignals,
                targetSpeed);
            obj[type] = target;
        }
    }

    return target;
}
OpenPOWER on IntegriCloud