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, target->getPos(), errno);
55         throw std::runtime_error(msg);
56     }
57 
58     rc = write(target->getCFAMFD(), &data, cfamRegSize);
59     if (rc < 0)
60     {
61         //Future: use a different exception to create an error log
62         char msg[100];
63         sprintf(msg, "writeCFAMReg: Failed write to address 0x%X, "
64                 "processor %d. errno = %d",
65                 address, target->getPos(), errno);
66         throw std::runtime_error(msg);
67     }
68 }
69 
70 
71 cfam_data_t readReg(const std::unique_ptr<Target>& target,
72                     cfam_address_t address)
73 {
74     cfam_data_t data = 0;
75 
76     int rc = lseek(target->getCFAMFD(), makeOffset(address), SEEK_SET);
77     if (rc < 0)
78     {
79         //Future: use a different exception to create an error log
80         char msg[100];
81         sprintf(msg, "readCFAMReg: Failed seek for address 0x%X, "
82                 "processor %d.  errno = %d",
83                 address, target->getPos(), errno);
84         throw std::runtime_error(msg);
85     }
86 
87     rc = read(target->getCFAMFD(), &data, cfamRegSize);
88     if (rc < 0)
89     {
90         //Future: use a different exception to create an error log
91         char msg[100];
92         sprintf(msg, "readCFAMReg: Failed read for address 0x%X, "
93                 "processor %d. errno = %d",
94                 address, target->getPos(), errno);
95         throw std::runtime_error(msg);
96     }
97 
98     return data;
99 }
100 
101 
102 void writeRegWithMask(const std::unique_ptr<Target>& target,
103                       cfam_address_t address,
104                       cfam_data_t data,
105                       cfam_mask_t mask)
106 {
107     cfam_data_t readData = readReg(target, address);
108 
109     readData &= ~mask;
110     readData |= (data & mask);
111 
112     writeReg(target, address, readData);
113 }
114 
115 }
116 }
117 }
118