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