xref: /openbmc/openpower-proc-control/cfam_access.cpp (revision e84b4ddb671d97cb4725ee2de18979c69e42b971)
1 /**
2  * Copyright (C) 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 <phosphor-logging/elog.hpp>
17 #include <phosphor-logging/elog-errors.hpp>
18 #include <xyz/openbmc_project/Common/Device/error.hpp>
19 #include <xyz/openbmc_project/Common/File/error.hpp>
20 #include <unistd.h>
21 #include "cfam_access.hpp"
22 #include "targeting.hpp"
23 
24 namespace openpower
25 {
26 namespace cfam
27 {
28 namespace access
29 {
30 
31 constexpr auto cfamRegSize = 4;
32 
33 using namespace openpower::targeting;
34 using namespace openpower::util;
35 namespace file_error = sdbusplus::xyz::openbmc_project::
36         Common::File::Error;
37 namespace device_error = sdbusplus::xyz::openbmc_project::
38         Common::Device::Error;
39 
40 /**
41  * Converts the CFAM register address used by the calling
42  * code (because that's how it is in the spec) to the address
43  * required by the device driver.
44  */
45 static inline cfam_address_t makeOffset(cfam_address_t address)
46 {
47     return (address & 0xFC00) | ((address & 0x03FF) << 2);
48 }
49 
50 
51 void writeReg(const std::unique_ptr<Target>& target,
52               cfam_address_t address,
53               cfam_data_t data)
54 {
55     using namespace phosphor::logging;
56     int rc = lseek(target->getCFAMFD(), makeOffset(address), SEEK_SET);
57     if (rc < 0)
58     {
59         log<level::ERR>("Failed seeking on a processor CFAM",
60                 entry("CFAM_ADDRESS=0x%X", address));
61 
62         using metadata = xyz::openbmc_project::Common::File::Seek;
63 
64         elog<file_error::Seek>(
65                 metadata::OFFSET(makeOffset(address)),
66                 metadata::WHENCE(SEEK_SET),
67                 metadata::ERRNO(errno),
68                 metadata::PATH(target->getCFAMPath().c_str()));
69     }
70 
71     data = target->swapEndian(data);
72 
73     rc = write(target->getCFAMFD(), &data, cfamRegSize);
74     if (rc < 0)
75     {
76         using metadata = xyz::openbmc_project::Common::Device::WriteFailure;
77 
78         elog<device_error::WriteFailure>(
79                 metadata::CALLOUT_ERRNO(errno),
80                 metadata::CALLOUT_DEVICE_PATH(
81                         target->getCFAMPath().c_str()));
82     }
83 }
84 
85 
86 cfam_data_t readReg(const std::unique_ptr<Target>& target,
87                     cfam_address_t address)
88 {
89     using namespace phosphor::logging;
90 
91     cfam_data_t data = 0;
92 
93     int rc = lseek(target->getCFAMFD(), makeOffset(address), SEEK_SET);
94     if (rc < 0)
95     {
96         log<level::ERR>("Failed seeking on a processor CFAM",
97                 entry("CFAM_ADDRESS=0x%X", address));
98 
99         using metadata = xyz::openbmc_project::Common::File::Seek;
100 
101         elog<file_error::Seek>(
102                 metadata::OFFSET(makeOffset(address)),
103                 metadata::WHENCE(SEEK_SET),
104                 metadata::ERRNO(errno),
105                 metadata::PATH(target->getCFAMPath().c_str()));
106     }
107 
108     rc = read(target->getCFAMFD(), &data, cfamRegSize);
109     if (rc < 0)
110     {
111         using metadata = xyz::openbmc_project::Common::Device::ReadFailure;
112 
113         elog<device_error::ReadFailure>(
114             metadata::CALLOUT_ERRNO(errno),
115             metadata::CALLOUT_DEVICE_PATH(target->getCFAMPath().c_str()));
116     }
117 
118     return target->swapEndian(data);
119 }
120 
121 
122 void writeRegWithMask(const std::unique_ptr<Target>& target,
123                       cfam_address_t address,
124                       cfam_data_t data,
125                       cfam_mask_t mask)
126 {
127     cfam_data_t readData = readReg(target, address);
128 
129     readData &= ~mask;
130     readData |= (data & mask);
131 
132     writeReg(target, address, readData);
133 }
134 
135 }
136 }
137 }
138