blob: d1d5c8fcea382d8c6dad688994199c1af5060c48 [file] [log] [blame]
Matt Spinler0c0eeff2017-02-28 10:06:56 -06001/**
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>
Matt Spinler0c0eeff2017-02-28 10:06:56 -060017#include "cfam_access.hpp"
18#include "targeting.hpp"
Dhruvaraj Subhashchandran18b07862017-04-26 07:13:35 -050019#include <phosphor-logging/elog.hpp>
20#include "elog-errors.hpp"
Matt Spinler0c0eeff2017-02-28 10:06:56 -060021
22namespace openpower
23{
24namespace cfam
25{
26namespace access
27{
28
29constexpr auto cfamRegSize = 4;
30
31using namespace openpower::targeting;
Matt Spinlerc3bffed2017-03-10 09:05:30 -060032using namespace openpower::util;
Matt Spinler0c0eeff2017-02-28 10:06:56 -060033
34/**
35 * Converts the CFAM register address used by the calling
36 * code (because that's how it is in the spec) to the address
37 * required by the device driver.
38 */
39static inline cfam_address_t makeOffset(cfam_address_t address)
40{
41 return (address & 0xFC00) | ((address & 0x03FF) << 2);
42}
43
44
45void writeReg(const std::unique_ptr<Target>& target,
46 cfam_address_t address,
47 cfam_data_t data)
48{
Dhruvaraj Subhashchandran18b07862017-04-26 07:13:35 -050049 using namespace phosphor::logging;
Matt Spinlerc3bffed2017-03-10 09:05:30 -060050 int rc = lseek(target->getCFAMFD(), makeOffset(address), SEEK_SET);
Matt Spinler0c0eeff2017-02-28 10:06:56 -060051 if (rc < 0)
52 {
Dhruvaraj Subhashchandran18b07862017-04-26 07:13:35 -050053 elog<org::open_power::Proc::CFAM::SeekFailure>(
54 org::open_power::Proc::CFAM::SeekFailure::ERRNO(errno),
55 org::open_power::Proc::CFAM::SeekFailure::ADDRESS(address),
56 org::open_power::Proc::CFAM::SeekFailure::OFFSET(makeOffset(address)),
57 org::open_power::Proc::CFAM::SeekFailure::PATH(target->getCFAMPath().c_str()));
Matt Spinler0c0eeff2017-02-28 10:06:56 -060058 }
59
Edward A. James8316b772017-04-24 14:20:48 -050060 data = target->swapEndian(data);
61
Matt Spinlerc3bffed2017-03-10 09:05:30 -060062 rc = write(target->getCFAMFD(), &data, cfamRegSize);
Matt Spinler0c0eeff2017-02-28 10:06:56 -060063 if (rc < 0)
64 {
Dhruvaraj Subhashchandran18b07862017-04-26 07:13:35 -050065 elog<org::open_power::Proc::CFAM::WriteFailure>(
66 org::open_power::Proc::CFAM::WriteFailure::CALLOUT_ERRNO(errno),
67 org::open_power::Proc::CFAM::WriteFailure::CALLOUT_DEVICE_PATH(
68 target->getCFAMPath().c_str()));
Matt Spinler0c0eeff2017-02-28 10:06:56 -060069 }
70}
71
72
73cfam_data_t readReg(const std::unique_ptr<Target>& target,
74 cfam_address_t address)
75{
Dhruvaraj Subhashchandran18b07862017-04-26 07:13:35 -050076 using namespace phosphor::logging;
77
Matt Spinler0c0eeff2017-02-28 10:06:56 -060078 cfam_data_t data = 0;
79
Matt Spinlerc3bffed2017-03-10 09:05:30 -060080 int rc = lseek(target->getCFAMFD(), makeOffset(address), SEEK_SET);
Matt Spinler0c0eeff2017-02-28 10:06:56 -060081 if (rc < 0)
82 {
Dhruvaraj Subhashchandran18b07862017-04-26 07:13:35 -050083 elog<org::open_power::Proc::CFAM::SeekFailure>(
84 org::open_power::Proc::CFAM::SeekFailure::ERRNO(errno),
85 org::open_power::Proc::CFAM::SeekFailure::ADDRESS(address),
86 org::open_power::Proc::CFAM::SeekFailure::OFFSET(makeOffset(address)),
87 org::open_power::Proc::CFAM::SeekFailure::PATH(target->getCFAMPath().c_str()));
Matt Spinler0c0eeff2017-02-28 10:06:56 -060088 }
89
Matt Spinlerc3bffed2017-03-10 09:05:30 -060090 rc = read(target->getCFAMFD(), &data, cfamRegSize);
Matt Spinler0c0eeff2017-02-28 10:06:56 -060091 if (rc < 0)
92 {
Dhruvaraj Subhashchandran18b07862017-04-26 07:13:35 -050093 elog<org::open_power::Proc::CFAM::ReadFailure>(
94 org::open_power::Proc::CFAM::WriteFailure::CALLOUT_ERRNO(errno),
95 org::open_power::Proc::CFAM::WriteFailure::CALLOUT_DEVICE_PATH(
96 target->getCFAMPath().c_str()));
Matt Spinler0c0eeff2017-02-28 10:06:56 -060097 }
98
Edward A. James8316b772017-04-24 14:20:48 -050099 return target->swapEndian(data);
Matt Spinler0c0eeff2017-02-28 10:06:56 -0600100}
101
102
103void writeRegWithMask(const std::unique_ptr<Target>& target,
104 cfam_address_t address,
105 cfam_data_t data,
106 cfam_mask_t mask)
107{
108 cfam_data_t readData = readReg(target, address);
109
110 readData &= ~mask;
111 readData |= (data & mask);
112
113 writeReg(target, address, readData);
114}
115
116}
117}
118}