blob: 47560a09f7121098da825c609035d0db3830d1ff [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 Spinler57868bc2017-08-03 10:07:41 -050071bool PMBus::readBitInPage(const std::string& name,
72 size_t page,
73 Type type)
Matt Spinler015e3ad2017-08-01 11:20:47 -050074{
75 auto pagedBit = insertPageNum(name, page);
Matt Spinler57868bc2017-08-03 10:07:41 -050076 return readBit(pagedBit, type);
Matt Spinler015e3ad2017-08-01 11:20:47 -050077}
78
Matt Spinler57868bc2017-08-03 10:07:41 -050079bool PMBus::readBit(const std::string& name, Type type)
Matt Spinler015e3ad2017-08-01 11:20:47 -050080{
81 unsigned long int value = 0;
82 std::ifstream file;
Brandon Wymanff5f3392017-08-11 17:43:22 -050083 fs::path path = getPath(type);
Matt Spinler57868bc2017-08-03 10:07:41 -050084
Matt Spinler015e3ad2017-08-01 11:20:47 -050085 path /= name;
86
87 file.exceptions(std::ifstream::failbit |
88 std::ifstream::badbit |
89 std::ifstream::eofbit);
90
91 try
92 {
93 char* err = NULL;
94 std::string val{1, '\0'};
95
96 file.open(path);
97 file.read(&val[0], 1);
98
99 value = strtoul(val.c_str(), &err, 10);
100
101 if (*err)
102 {
103 log<level::ERR>("Invalid character in sysfs file",
104 entry("FILE=%s", path.c_str()),
105 entry("CONTENTS=%s", val.c_str()));
106
107 //Catch below and handle as a read failure
108 elog<InternalFailure>();
109 }
110 }
111 catch (std::exception& e)
112 {
113 auto rc = errno;
114
115 log<level::ERR>("Failed to read sysfs file",
Brandon Wymanf855e822017-08-08 18:04:47 -0500116 entry("FILENAME=%s", path.c_str()));
Matt Spinler015e3ad2017-08-01 11:20:47 -0500117
Matt Spinlerceacf942017-10-05 13:55:02 -0500118 using metadata = xyz::openbmc_project::Common::Device::ReadFailure;
119
120 elog<ReadFailure>(metadata::CALLOUT_ERRNO(rc),
121 metadata::CALLOUT_DEVICE_PATH(
122 fs::canonical(basePath).c_str()));
Matt Spinler015e3ad2017-08-01 11:20:47 -0500123 }
124
125 return value != 0;
126}
127
Brandon Wyman3b7b38b2017-09-25 16:43:45 -0500128bool PMBus::exists(const std::string& name, Type type)
129{
130 auto path = getPath(type);
131 path /= name;
132 return fs::exists(path);
133}
134
Brandon Wymanf855e822017-08-08 18:04:47 -0500135uint64_t PMBus::read(const std::string& name, Type type)
136{
137 uint64_t data = 0;
138 std::ifstream file;
139 auto path = getPath(type);
140 path /= name;
141
142 file.exceptions(std::ifstream::failbit |
143 std::ifstream::badbit |
144 std::ifstream::eofbit);
145
146 try
147 {
148 file.open(path);
149 file >> std::hex >> data;
150 }
151 catch (std::exception& e)
152 {
153 auto rc = errno;
154 log<level::ERR>("Failed to read sysfs file",
155 entry("FILENAME=%s", path.c_str()));
156
Matt Spinlerceacf942017-10-05 13:55:02 -0500157 using metadata = xyz::openbmc_project::Common::Device::ReadFailure;
Brandon Wymanf855e822017-08-08 18:04:47 -0500158
159 elog<ReadFailure>(metadata::CALLOUT_ERRNO(rc),
160 metadata::CALLOUT_DEVICE_PATH(
161 fs::canonical(basePath).c_str()));
162 }
163
164 return data;
165}
166
Matt Spinler57868bc2017-08-03 10:07:41 -0500167void PMBus::write(const std::string& name, int value, Type type)
Matt Spinler015e3ad2017-08-01 11:20:47 -0500168{
169 std::ofstream file;
Brandon Wymanff5f3392017-08-11 17:43:22 -0500170 fs::path path = getPath(type);
Matt Spinler57868bc2017-08-03 10:07:41 -0500171
Matt Spinler015e3ad2017-08-01 11:20:47 -0500172 path /= name;
173
174 file.exceptions(std::ofstream::failbit |
175 std::ofstream::badbit |
176 std::ofstream::eofbit);
177
178 try
179 {
180 file.open(path);
181 file << value;
182 }
183 catch (const std::exception& e)
184 {
185 auto rc = errno;
186
187 log<level::ERR>("Failed to write sysfs file",
Brandon Wymanf855e822017-08-08 18:04:47 -0500188 entry("FILENAME=%s", path.c_str()));
Matt Spinler015e3ad2017-08-01 11:20:47 -0500189
Matt Spinlerceacf942017-10-05 13:55:02 -0500190 using metadata = xyz::openbmc_project::Common::Device::WriteFailure;
191
192 elog<WriteFailure>(metadata::CALLOUT_ERRNO(rc),
193 metadata::CALLOUT_DEVICE_PATH(
194 fs::canonical(basePath).c_str()));
Matt Spinler015e3ad2017-08-01 11:20:47 -0500195 }
196}
197
Brandon Wymanff5f3392017-08-11 17:43:22 -0500198void PMBus::findHwmonDir()
Matt Spinler57868bc2017-08-03 10:07:41 -0500199{
200 fs::path path{basePath};
201 path /= "hwmon";
202
Brandon Wymanaad73e92017-08-16 16:27:54 -0500203 // Make sure the directory exists, otherwise for things that can be
204 // dynamically present or not present an exception will be thrown if the
205 // hwmon directory is not there, resulting in a program termination.
206 if (fs::is_directory(path))
Matt Spinler57868bc2017-08-03 10:07:41 -0500207 {
Brandon Wymanaad73e92017-08-16 16:27:54 -0500208 //look for <basePath>/hwmon/hwmonN/
209 for (auto& f : fs::directory_iterator(path))
Matt Spinler57868bc2017-08-03 10:07:41 -0500210 {
Brandon Wymanaad73e92017-08-16 16:27:54 -0500211 if ((f.path().filename().string().find("hwmon") !=
212 std::string::npos) &&
213 (fs::is_directory(f.path())))
214 {
215 hwmonDir = f.path().filename();
216 break;
217 }
Matt Spinler57868bc2017-08-03 10:07:41 -0500218 }
219 }
220
221 //Don't really want to crash here, just log it
222 //and let accesses fail later
Brandon Wymanff5f3392017-08-11 17:43:22 -0500223 if (hwmonDir.empty())
Matt Spinler57868bc2017-08-03 10:07:41 -0500224 {
Brandon Wymanaad73e92017-08-16 16:27:54 -0500225 log<level::INFO>("Unable to find hwmon directory "
226 "in device base path",
227 entry("DEVICE_PATH=%s", basePath.c_str()));
Matt Spinler57868bc2017-08-03 10:07:41 -0500228 }
229
230}
231
Matt Spinler015e3ad2017-08-01 11:20:47 -0500232}
233}