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