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