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