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 #include <unistd.h> 17 #include "cfam_access.hpp" 18 #include "targeting.hpp" 19 20 namespace openpower 21 { 22 namespace cfam 23 { 24 namespace access 25 { 26 27 constexpr auto cfamRegSize = 4; 28 29 using namespace openpower::targeting; 30 using namespace openpower::util; 31 32 /** 33 * Converts the CFAM register address used by the calling 34 * code (because that's how it is in the spec) to the address 35 * required by the device driver. 36 */ 37 static inline cfam_address_t makeOffset(cfam_address_t address) 38 { 39 return (address & 0xFC00) | ((address & 0x03FF) << 2); 40 } 41 42 43 void writeReg(const std::unique_ptr<Target>& target, 44 cfam_address_t address, 45 cfam_data_t data) 46 { 47 int rc = lseek(target->getCFAMFD(), makeOffset(address), SEEK_SET); 48 if (rc < 0) 49 { 50 //Future: use a different exception to create an error log 51 char msg[100]; 52 sprintf(msg, "writeCFAMReg: Failed seek for address 0x%X, " 53 "processor %d. errno = %d", 54 address, static_cast<int>(target->getPos()), errno); 55 throw std::runtime_error(msg); 56 } 57 58 data = target->swapEndian(data); 59 60 rc = write(target->getCFAMFD(), &data, cfamRegSize); 61 if (rc < 0) 62 { 63 //Future: use a different exception to create an error log 64 char msg[100]; 65 sprintf(msg, "writeCFAMReg: Failed write to address 0x%X, " 66 "processor %d. errno = %d", 67 address, static_cast<int>(target->getPos()), errno); 68 throw std::runtime_error(msg); 69 } 70 } 71 72 73 cfam_data_t readReg(const std::unique_ptr<Target>& target, 74 cfam_address_t address) 75 { 76 cfam_data_t data = 0; 77 78 int rc = lseek(target->getCFAMFD(), makeOffset(address), SEEK_SET); 79 if (rc < 0) 80 { 81 //Future: use a different exception to create an error log 82 char msg[100]; 83 sprintf(msg, "readCFAMReg: Failed seek for address 0x%X, " 84 "processor %d. errno = %d", 85 address, static_cast<int>(target->getPos()), errno); 86 throw std::runtime_error(msg); 87 } 88 89 rc = read(target->getCFAMFD(), &data, cfamRegSize); 90 if (rc < 0) 91 { 92 //Future: use a different exception to create an error log 93 char msg[100]; 94 sprintf(msg, "readCFAMReg: Failed read for address 0x%X, " 95 "processor %d. errno = %d", 96 address, static_cast<int>(target->getPos()), errno); 97 throw std::runtime_error(msg); 98 } 99 100 return target->swapEndian(data); 101 } 102 103 104 void writeRegWithMask(const std::unique_ptr<Target>& target, 105 cfam_address_t address, 106 cfam_data_t data, 107 cfam_mask_t mask) 108 { 109 cfam_data_t readData = readReg(target, address); 110 111 readData &= ~mask; 112 readData |= (data & mask); 113 114 writeReg(target, address, readData); 115 } 116 117 } 118 } 119 } 120