blob: b68f6fbf920c030d389662ea3c916c8c28465f9d [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:
65 auto dir = driverName + "." + std::to_string(instance);
66 return debugPath / dir;
Brandon Wymanff5f3392017-08-11 17:43:22 -050067 break;
68 }
69}
70
Matt Spinlerba053482018-01-04 14:26:05 -060071std::string PMBus::getDeviceName()
72{
73 std::string name;
74 std::ifstream file;
75 auto path = basePath / "name";
76
77 file.exceptions(std::ifstream::failbit |
78 std::ifstream::badbit |
79 std::ifstream::eofbit);
80 try
81 {
82 file.open(path);
83 file >> name;
84 }
85 catch (std::exception& e)
86 {
87 log<level::ERR>("Unable to read PMBus device name",
88 entry("PATH=%s", path.c_str()));
89 }
90
91 return name;
92}
93
Matt Spinler57868bc2017-08-03 10:07:41 -050094bool PMBus::readBitInPage(const std::string& name,
95 size_t page,
96 Type type)
Matt Spinler015e3ad2017-08-01 11:20:47 -050097{
98 auto pagedBit = insertPageNum(name, page);
Matt Spinler57868bc2017-08-03 10:07:41 -050099 return readBit(pagedBit, type);
Matt Spinler015e3ad2017-08-01 11:20:47 -0500100}
101
Matt Spinler57868bc2017-08-03 10:07:41 -0500102bool PMBus::readBit(const std::string& name, Type type)
Matt Spinler015e3ad2017-08-01 11:20:47 -0500103{
104 unsigned long int value = 0;
105 std::ifstream file;
Brandon Wymanff5f3392017-08-11 17:43:22 -0500106 fs::path path = getPath(type);
Matt Spinler57868bc2017-08-03 10:07:41 -0500107
Matt Spinler015e3ad2017-08-01 11:20:47 -0500108 path /= name;
109
110 file.exceptions(std::ifstream::failbit |
111 std::ifstream::badbit |
112 std::ifstream::eofbit);
113
114 try
115 {
116 char* err = NULL;
117 std::string val{1, '\0'};
118
119 file.open(path);
120 file.read(&val[0], 1);
121
122 value = strtoul(val.c_str(), &err, 10);
123
124 if (*err)
125 {
126 log<level::ERR>("Invalid character in sysfs file",
127 entry("FILE=%s", path.c_str()),
128 entry("CONTENTS=%s", val.c_str()));
129
130 //Catch below and handle as a read failure
131 elog<InternalFailure>();
132 }
133 }
134 catch (std::exception& e)
135 {
136 auto rc = errno;
137
138 log<level::ERR>("Failed to read sysfs file",
Brandon Wymanf855e822017-08-08 18:04:47 -0500139 entry("FILENAME=%s", path.c_str()));
Matt Spinler015e3ad2017-08-01 11:20:47 -0500140
Matt Spinlerceacf942017-10-05 13:55:02 -0500141 using metadata = xyz::openbmc_project::Common::Device::ReadFailure;
142
143 elog<ReadFailure>(metadata::CALLOUT_ERRNO(rc),
144 metadata::CALLOUT_DEVICE_PATH(
145 fs::canonical(basePath).c_str()));
Matt Spinler015e3ad2017-08-01 11:20:47 -0500146 }
147
148 return value != 0;
149}
150
Brandon Wyman3b7b38b2017-09-25 16:43:45 -0500151bool PMBus::exists(const std::string& name, Type type)
152{
153 auto path = getPath(type);
154 path /= name;
155 return fs::exists(path);
156}
157
Brandon Wymanf855e822017-08-08 18:04:47 -0500158uint64_t PMBus::read(const std::string& name, Type type)
159{
160 uint64_t data = 0;
161 std::ifstream file;
162 auto path = getPath(type);
163 path /= name;
164
165 file.exceptions(std::ifstream::failbit |
166 std::ifstream::badbit |
167 std::ifstream::eofbit);
168
169 try
170 {
171 file.open(path);
172 file >> std::hex >> data;
173 }
174 catch (std::exception& e)
175 {
176 auto rc = errno;
177 log<level::ERR>("Failed to read sysfs file",
178 entry("FILENAME=%s", path.c_str()));
179
Matt Spinlerceacf942017-10-05 13:55:02 -0500180 using metadata = xyz::openbmc_project::Common::Device::ReadFailure;
Brandon Wymanf855e822017-08-08 18:04:47 -0500181
182 elog<ReadFailure>(metadata::CALLOUT_ERRNO(rc),
183 metadata::CALLOUT_DEVICE_PATH(
184 fs::canonical(basePath).c_str()));
185 }
186
187 return data;
188}
189
Matt Spinler57868bc2017-08-03 10:07:41 -0500190void PMBus::write(const std::string& name, int value, Type type)
Matt Spinler015e3ad2017-08-01 11:20:47 -0500191{
192 std::ofstream file;
Brandon Wymanff5f3392017-08-11 17:43:22 -0500193 fs::path path = getPath(type);
Matt Spinler57868bc2017-08-03 10:07:41 -0500194
Matt Spinler015e3ad2017-08-01 11:20:47 -0500195 path /= name;
196
197 file.exceptions(std::ofstream::failbit |
198 std::ofstream::badbit |
199 std::ofstream::eofbit);
200
201 try
202 {
203 file.open(path);
204 file << value;
205 }
206 catch (const std::exception& e)
207 {
208 auto rc = errno;
209
210 log<level::ERR>("Failed to write sysfs file",
Brandon Wymanf855e822017-08-08 18:04:47 -0500211 entry("FILENAME=%s", path.c_str()));
Matt Spinler015e3ad2017-08-01 11:20:47 -0500212
Matt Spinlerceacf942017-10-05 13:55:02 -0500213 using metadata = xyz::openbmc_project::Common::Device::WriteFailure;
214
215 elog<WriteFailure>(metadata::CALLOUT_ERRNO(rc),
216 metadata::CALLOUT_DEVICE_PATH(
217 fs::canonical(basePath).c_str()));
Matt Spinler015e3ad2017-08-01 11:20:47 -0500218 }
219}
220
Brandon Wymanff5f3392017-08-11 17:43:22 -0500221void PMBus::findHwmonDir()
Matt Spinler57868bc2017-08-03 10:07:41 -0500222{
223 fs::path path{basePath};
224 path /= "hwmon";
225
Brandon Wymanaad73e92017-08-16 16:27:54 -0500226 // Make sure the directory exists, otherwise for things that can be
227 // dynamically present or not present an exception will be thrown if the
228 // hwmon directory is not there, resulting in a program termination.
229 if (fs::is_directory(path))
Matt Spinler57868bc2017-08-03 10:07:41 -0500230 {
Brandon Wymanaad73e92017-08-16 16:27:54 -0500231 //look for <basePath>/hwmon/hwmonN/
232 for (auto& f : fs::directory_iterator(path))
Matt Spinler57868bc2017-08-03 10:07:41 -0500233 {
Brandon Wymanaad73e92017-08-16 16:27:54 -0500234 if ((f.path().filename().string().find("hwmon") !=
235 std::string::npos) &&
236 (fs::is_directory(f.path())))
237 {
238 hwmonDir = f.path().filename();
239 break;
240 }
Matt Spinler57868bc2017-08-03 10:07:41 -0500241 }
242 }
243
244 //Don't really want to crash here, just log it
245 //and let accesses fail later
Brandon Wymanff5f3392017-08-11 17:43:22 -0500246 if (hwmonDir.empty())
Matt Spinler57868bc2017-08-03 10:07:41 -0500247 {
Brandon Wymanaad73e92017-08-16 16:27:54 -0500248 log<level::INFO>("Unable to find hwmon directory "
249 "in device base path",
250 entry("DEVICE_PATH=%s", basePath.c_str()));
Matt Spinler57868bc2017-08-03 10:07:41 -0500251 }
252
253}
254
Matt Spinler015e3ad2017-08-01 11:20:47 -0500255}
256}