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