xref: /openbmc/openpower-proc-control/targeting.cpp (revision a231ceb41e695cfc0a77699b15e5ea4281e212a9)
1 /**
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 
17 #include <endian.h>
18 #include <experimental/filesystem>
19 #include <phosphor-logging/elog.hpp>
20 #include <phosphor-logging/elog-errors.hpp>
21 #include <phosphor-logging/log.hpp>
22 #include <regex>
23 #include <xyz/openbmc_project/Common/File/error.hpp>
24 #include "targeting.hpp"
25 
26 
27 namespace openpower
28 {
29 namespace targeting
30 {
31 
32 using namespace phosphor::logging;
33 namespace fs = std::experimental::filesystem;
34 namespace file_error = sdbusplus::xyz::openbmc_project::Common::File::Error;
35 
36 int Target::getCFAMFD()
37 {
38     if (cfamFD.get() == nullptr)
39     {
40         cfamFD = std::make_unique<
41             openpower::util::FileDescriptor>(getCFAMPath());
42     }
43 
44     return cfamFD->get();
45 }
46 
47 std::unique_ptr<Target>& Targeting::getTarget(size_t pos)
48 {
49     auto search = [pos](const auto& t)
50     {
51         return t->getPos() == pos;
52     };
53 
54     auto target = find_if(targets.begin(), targets.end(), search);
55     if (target == targets.end())
56     {
57         throw std::runtime_error("Target not found: " + std::to_string(pos));
58     }
59     else
60     {
61         return *target;
62     }
63 }
64 
65 
66 static uint32_t noEndianSwap(uint32_t data)
67 {
68     return data;
69 }
70 
71 static uint32_t endianSwap(uint32_t data)
72 {
73     return htobe32(data);
74 }
75 
76 Targeting::Targeting(const std::string& fsiMasterDev,
77                      const std::string& fsiSlaveDir) :
78     fsiMasterPath(fsiMasterDev),
79     fsiSlaveBasePath(fsiSlaveDir)
80 {
81     swap_endian_t swapper = endianSwap;
82     std::regex exp{"fsi1/slave@([0-9]{2}):00", std::regex::extended};
83 
84     if (!fs::exists(fsiMasterPath))
85     {
86         std::regex expOld{"hub@00/slave@([0-9]{2}):00", std::regex::extended};
87 
88         //Fall back to old (4.7) path
89         exp = expOld;
90         fsiMasterPath = fsiMasterDevPathOld;
91         fsiSlaveBasePath = fsiSlaveBaseDirOld;
92 
93         //And don't swap the endianness of CFAM data
94         swapper = noEndianSwap;
95     }
96 
97     //Always create P0, the FSI master.
98     targets.push_back(std::make_unique<Target>(0, fsiMasterPath, swapper));
99     try
100     {
101         //Find the the remaining P9s dynamically based on which files show up
102         for (auto& file : fs::directory_iterator(fsiSlaveBasePath))
103         {
104             std::smatch match;
105             std::string path = file.path();
106             if (std::regex_search(path, match, exp))
107             {
108                 auto pos = atoi(match[1].str().c_str());
109                 if (pos == 0)
110                 {
111                     log<level::ERR>("Unexpected FSI slave device name found",
112                                     entry("DEVICE_NAME=%s", path.c_str()));
113                     continue;
114                 }
115 
116                 path += "/raw";
117 
118                 targets.push_back(std::make_unique<Target>(pos, path, swapper));
119             }
120         }
121     }
122     catch (fs::filesystem_error& e)
123     {
124         using metadata = xyz::openbmc_project::Common::File::Open;
125 
126         elog<file_error::Open>(
127                 metadata::ERRNO(e.code().value()),
128                 metadata::PATH(e.path1().c_str()));
129     }
130 
131     auto sortTargets = [](const std::unique_ptr<Target>& left,
132                           const std::unique_ptr<Target>& right)
133     {
134         return left->getPos() < right->getPos();
135     };
136     std::sort(targets.begin(), targets.end(), sortTargets);
137 }
138 
139 }
140 }
141