1 /** 2 * Copyright (C) 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 "cfam_access.hpp" 17 18 #include "targeting.hpp" 19 20 #include <unistd.h> 21 22 #include <phosphor-logging/elog-errors.hpp> 23 #include <phosphor-logging/elog.hpp> 24 #include <xyz/openbmc_project/Common/Device/error.hpp> 25 #include <xyz/openbmc_project/Common/File/error.hpp> 26 27 namespace openpower 28 { 29 namespace cfam 30 { 31 namespace access 32 { 33 34 constexpr auto cfamRegSize = 4; 35 36 using namespace openpower::targeting; 37 using namespace openpower::util; 38 namespace file_error = sdbusplus::xyz::openbmc_project::Common::File::Error; 39 namespace device_error = sdbusplus::xyz::openbmc_project::Common::Device::Error; 40 41 /** 42 * Converts the CFAM register address used by the calling 43 * code (because that's how it is in the spec) to the address 44 * required by the device driver. 45 */ 46 static inline cfam_address_t makeOffset(cfam_address_t address) 47 { 48 return (address & 0xFC00) | ((address & 0x03FF) << 2); 49 } 50 51 void writeReg(const std::unique_ptr<Target>& target, cfam_address_t address, 52 cfam_data_t data) 53 { 54 using namespace phosphor::logging; 55 int rc = lseek(target->getCFAMFD(), makeOffset(address), SEEK_SET); 56 if (rc < 0) 57 { 58 log<level::ERR>("Failed seeking on a processor CFAM", 59 entry("CFAM_ADDRESS=0x%X", address)); 60 61 using metadata = xyz::openbmc_project::Common::File::Seek; 62 63 elog<file_error::Seek>(metadata::OFFSET(makeOffset(address)), 64 metadata::WHENCE(SEEK_SET), 65 metadata::ERRNO(errno), 66 metadata::PATH(target->getCFAMPath().c_str())); 67 } 68 69 data = htobe32(data); 70 71 rc = write(target->getCFAMFD(), &data, cfamRegSize); 72 if (rc < 0) 73 { 74 using metadata = xyz::openbmc_project::Common::Device::WriteFailure; 75 76 elog<device_error::WriteFailure>( 77 metadata::CALLOUT_ERRNO(errno), 78 metadata::CALLOUT_DEVICE_PATH(target->getCFAMPath().c_str())); 79 } 80 } 81 82 cfam_data_t readReg(const std::unique_ptr<Target>& target, 83 cfam_address_t address) 84 { 85 using namespace phosphor::logging; 86 87 cfam_data_t data = 0; 88 89 int rc = lseek(target->getCFAMFD(), makeOffset(address), SEEK_SET); 90 if (rc < 0) 91 { 92 log<level::ERR>("Failed seeking on a processor CFAM", 93 entry("CFAM_ADDRESS=0x%X", address)); 94 95 using metadata = xyz::openbmc_project::Common::File::Seek; 96 97 elog<file_error::Seek>(metadata::OFFSET(makeOffset(address)), 98 metadata::WHENCE(SEEK_SET), 99 metadata::ERRNO(errno), 100 metadata::PATH(target->getCFAMPath().c_str())); 101 } 102 103 rc = read(target->getCFAMFD(), &data, cfamRegSize); 104 if (rc < 0) 105 { 106 using metadata = xyz::openbmc_project::Common::Device::ReadFailure; 107 108 elog<device_error::ReadFailure>( 109 metadata::CALLOUT_ERRNO(errno), 110 metadata::CALLOUT_DEVICE_PATH(target->getCFAMPath().c_str())); 111 } 112 113 return be32toh(data); 114 } 115 116 void writeRegWithMask(const std::unique_ptr<Target>& target, 117 cfam_address_t address, cfam_data_t data, 118 cfam_mask_t mask) 119 { 120 cfam_data_t readData = readReg(target, address); 121 122 readData &= ~mask; 123 readData |= (data & mask); 124 125 writeReg(target, address, readData); 126 } 127 128 } // namespace access 129 } // namespace cfam 130 } // namespace openpower 131