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