blob: 6ec496551a858842ffa7b547aa863ce1ca8ca3b5 [file] [log] [blame]
Matt Spinler015e3ad2017-08-01 11:20:47 -05001/**
2 * Copyright © 2017 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include <experimental/filesystem>
17#include <fstream>
18#include <phosphor-logging/elog.hpp>
19#include <phosphor-logging/elog-errors.hpp>
20#include <xyz/openbmc_project/Common/error.hpp>
Matt Spinlerceacf942017-10-05 13:55:02 -050021#include <xyz/openbmc_project/Common/Device/error.hpp>
Matt Spinler015e3ad2017-08-01 11:20:47 -050022#include "pmbus.hpp"
23
24namespace witherspoon
25{
26namespace pmbus
27{
28
29using namespace phosphor::logging;
30using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Matt Spinlerceacf942017-10-05 13:55:02 -050031using namespace sdbusplus::xyz::openbmc_project::Common::Device::Error;
Matt Spinler015e3ad2017-08-01 11:20:47 -050032namespace fs = std::experimental::filesystem;
33
34std::string PMBus::insertPageNum(const std::string& templateName,
35 size_t page)
36{
37 auto name = templateName;
38
39 //insert the page where the P was
40 auto pos = name.find('P');
41 if (pos != std::string::npos)
42 {
43 name.replace(pos, 1, std::to_string(page));
44 }
45
46 return name;
47}
48
Brandon Wymanff5f3392017-08-11 17:43:22 -050049fs::path PMBus::getPath(Type type)
50{
51 switch (type)
52 {
53 default:
Brandon Wymanf855e822017-08-08 18:04:47 -050054 /* fall through */
Brandon Wymanff5f3392017-08-11 17:43:22 -050055 case Type::Base:
56 return basePath;
57 break;
58 case Type::Hwmon:
59 return basePath / "hwmon" / hwmonDir;
60 break;
61 case Type::Debug:
Matt Spinler8f0d9532017-08-21 11:22:37 -050062 return debugPath / "pmbus" / hwmonDir;
63 break;
64 case Type::DeviceDebug:
Matt Spinler4dc46782018-01-04 14:29:16 -060065 {
Matt Spinler8f0d9532017-08-21 11:22:37 -050066 auto dir = driverName + "." + std::to_string(instance);
67 return debugPath / dir;
Brandon Wymanff5f3392017-08-11 17:43:22 -050068 break;
Matt Spinler4dc46782018-01-04 14:29:16 -060069 }
70 case Type::HwmonDeviceDebug:
71 return debugPath / "pmbus" / hwmonDir / getDeviceName();
72 break;
Brandon Wymanff5f3392017-08-11 17:43:22 -050073 }
74}
75
Matt Spinlerba053482018-01-04 14:26:05 -060076std::string PMBus::getDeviceName()
77{
78 std::string name;
79 std::ifstream file;
80 auto path = basePath / "name";
81
82 file.exceptions(std::ifstream::failbit |
83 std::ifstream::badbit |
84 std::ifstream::eofbit);
85 try
86 {
87 file.open(path);
88 file >> name;
89 }
90 catch (std::exception& e)
91 {
92 log<level::ERR>("Unable to read PMBus device name",
93 entry("PATH=%s", path.c_str()));
94 }
95
96 return name;
97}
98
Matt Spinler57868bc2017-08-03 10:07:41 -050099bool PMBus::readBitInPage(const std::string& name,
100 size_t page,
101 Type type)
Matt Spinler015e3ad2017-08-01 11:20:47 -0500102{
103 auto pagedBit = insertPageNum(name, page);
Matt Spinler57868bc2017-08-03 10:07:41 -0500104 return readBit(pagedBit, type);
Matt Spinler015e3ad2017-08-01 11:20:47 -0500105}
106
Matt Spinler57868bc2017-08-03 10:07:41 -0500107bool PMBus::readBit(const std::string& name, Type type)
Matt Spinler015e3ad2017-08-01 11:20:47 -0500108{
109 unsigned long int value = 0;
110 std::ifstream file;
Brandon Wymanff5f3392017-08-11 17:43:22 -0500111 fs::path path = getPath(type);
Matt Spinler57868bc2017-08-03 10:07:41 -0500112
Matt Spinler015e3ad2017-08-01 11:20:47 -0500113 path /= name;
114
115 file.exceptions(std::ifstream::failbit |
116 std::ifstream::badbit |
117 std::ifstream::eofbit);
118
119 try
120 {
121 char* err = NULL;
122 std::string val{1, '\0'};
123
124 file.open(path);
125 file.read(&val[0], 1);
126
127 value = strtoul(val.c_str(), &err, 10);
128
129 if (*err)
130 {
131 log<level::ERR>("Invalid character in sysfs file",
132 entry("FILE=%s", path.c_str()),
133 entry("CONTENTS=%s", val.c_str()));
134
135 //Catch below and handle as a read failure
136 elog<InternalFailure>();
137 }
138 }
139 catch (std::exception& e)
140 {
141 auto rc = errno;
142
143 log<level::ERR>("Failed to read sysfs file",
Brandon Wymanf855e822017-08-08 18:04:47 -0500144 entry("FILENAME=%s", path.c_str()));
Matt Spinler015e3ad2017-08-01 11:20:47 -0500145
Matt Spinlerceacf942017-10-05 13:55:02 -0500146 using metadata = xyz::openbmc_project::Common::Device::ReadFailure;
147
148 elog<ReadFailure>(metadata::CALLOUT_ERRNO(rc),
149 metadata::CALLOUT_DEVICE_PATH(
150 fs::canonical(basePath).c_str()));
Matt Spinler015e3ad2017-08-01 11:20:47 -0500151 }
152
153 return value != 0;
154}
155
Brandon Wyman3b7b38b2017-09-25 16:43:45 -0500156bool PMBus::exists(const std::string& name, Type type)
157{
158 auto path = getPath(type);
159 path /= name;
160 return fs::exists(path);
161}
162
Brandon Wymanf855e822017-08-08 18:04:47 -0500163uint64_t PMBus::read(const std::string& name, Type type)
164{
165 uint64_t data = 0;
166 std::ifstream file;
167 auto path = getPath(type);
168 path /= name;
169
170 file.exceptions(std::ifstream::failbit |
171 std::ifstream::badbit |
172 std::ifstream::eofbit);
173
174 try
175 {
176 file.open(path);
177 file >> std::hex >> data;
178 }
179 catch (std::exception& e)
180 {
181 auto rc = errno;
182 log<level::ERR>("Failed to read sysfs file",
183 entry("FILENAME=%s", path.c_str()));
184
Matt Spinlerceacf942017-10-05 13:55:02 -0500185 using metadata = xyz::openbmc_project::Common::Device::ReadFailure;
Brandon Wymanf855e822017-08-08 18:04:47 -0500186
187 elog<ReadFailure>(metadata::CALLOUT_ERRNO(rc),
188 metadata::CALLOUT_DEVICE_PATH(
189 fs::canonical(basePath).c_str()));
190 }
191
192 return data;
193}
194
Matt Spinler57868bc2017-08-03 10:07:41 -0500195void PMBus::write(const std::string& name, int value, Type type)
Matt Spinler015e3ad2017-08-01 11:20:47 -0500196{
197 std::ofstream file;
Brandon Wymanff5f3392017-08-11 17:43:22 -0500198 fs::path path = getPath(type);
Matt Spinler57868bc2017-08-03 10:07:41 -0500199
Matt Spinler015e3ad2017-08-01 11:20:47 -0500200 path /= name;
201
202 file.exceptions(std::ofstream::failbit |
203 std::ofstream::badbit |
204 std::ofstream::eofbit);
205
206 try
207 {
208 file.open(path);
209 file << value;
210 }
211 catch (const std::exception& e)
212 {
213 auto rc = errno;
214
215 log<level::ERR>("Failed to write sysfs file",
Brandon Wymanf855e822017-08-08 18:04:47 -0500216 entry("FILENAME=%s", path.c_str()));
Matt Spinler015e3ad2017-08-01 11:20:47 -0500217
Matt Spinlerceacf942017-10-05 13:55:02 -0500218 using metadata = xyz::openbmc_project::Common::Device::WriteFailure;
219
220 elog<WriteFailure>(metadata::CALLOUT_ERRNO(rc),
221 metadata::CALLOUT_DEVICE_PATH(
222 fs::canonical(basePath).c_str()));
Matt Spinler015e3ad2017-08-01 11:20:47 -0500223 }
224}
225
Brandon Wymanff5f3392017-08-11 17:43:22 -0500226void PMBus::findHwmonDir()
Matt Spinler57868bc2017-08-03 10:07:41 -0500227{
228 fs::path path{basePath};
229 path /= "hwmon";
230
Brandon Wymanaad73e92017-08-16 16:27:54 -0500231 // Make sure the directory exists, otherwise for things that can be
232 // dynamically present or not present an exception will be thrown if the
233 // hwmon directory is not there, resulting in a program termination.
234 if (fs::is_directory(path))
Matt Spinler57868bc2017-08-03 10:07:41 -0500235 {
Brandon Wymanaad73e92017-08-16 16:27:54 -0500236 //look for <basePath>/hwmon/hwmonN/
237 for (auto& f : fs::directory_iterator(path))
Matt Spinler57868bc2017-08-03 10:07:41 -0500238 {
Brandon Wymanaad73e92017-08-16 16:27:54 -0500239 if ((f.path().filename().string().find("hwmon") !=
240 std::string::npos) &&
241 (fs::is_directory(f.path())))
242 {
243 hwmonDir = f.path().filename();
244 break;
245 }
Matt Spinler57868bc2017-08-03 10:07:41 -0500246 }
247 }
248
249 //Don't really want to crash here, just log it
250 //and let accesses fail later
Brandon Wymanff5f3392017-08-11 17:43:22 -0500251 if (hwmonDir.empty())
Matt Spinler57868bc2017-08-03 10:07:41 -0500252 {
Brandon Wymanaad73e92017-08-16 16:27:54 -0500253 log<level::INFO>("Unable to find hwmon directory "
254 "in device base path",
255 entry("DEVICE_PATH=%s", basePath.c_str()));
Matt Spinler57868bc2017-08-03 10:07:41 -0500256 }
257
258}
259
Matt Spinler015e3ad2017-08-01 11:20:47 -0500260}
261}