xref: /openbmc/openpower-proc-control/cfam_access.cpp (revision 8316b77b67aac9dea3e7281e2455ad80f509a5b3)
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