summaryrefslogtreecommitdiffstats
path: root/cfam_access.cpp
blob: d1d5c8fcea382d8c6dad688994199c1af5060c48 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/**
 * Copyright © 2017 IBM Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <unistd.h>
#include "cfam_access.hpp"
#include "targeting.hpp"
#include <phosphor-logging/elog.hpp>
#include "elog-errors.hpp"

namespace openpower
{
namespace cfam
{
namespace access
{

constexpr auto cfamRegSize = 4;

using namespace openpower::targeting;
using namespace openpower::util;

/**
 * Converts the CFAM register address used by the calling
 * code (because that's how it is in the spec) to the address
 * required by the device driver.
 */
static inline cfam_address_t makeOffset(cfam_address_t address)
{
    return (address & 0xFC00) | ((address & 0x03FF) << 2);
}


void writeReg(const std::unique_ptr<Target>& target,
              cfam_address_t address,
              cfam_data_t data)
{
    using namespace phosphor::logging;
    int rc = lseek(target->getCFAMFD(), makeOffset(address), SEEK_SET);
    if (rc < 0)
    {
        elog<org::open_power::Proc::CFAM::SeekFailure>(
            org::open_power::Proc::CFAM::SeekFailure::ERRNO(errno),
            org::open_power::Proc::CFAM::SeekFailure::ADDRESS(address),
            org::open_power::Proc::CFAM::SeekFailure::OFFSET(makeOffset(address)),
            org::open_power::Proc::CFAM::SeekFailure::PATH(target->getCFAMPath().c_str()));
    }

    data = target->swapEndian(data);

    rc = write(target->getCFAMFD(), &data, cfamRegSize);
    if (rc < 0)
    {
        elog<org::open_power::Proc::CFAM::WriteFailure>(
            org::open_power::Proc::CFAM::WriteFailure::CALLOUT_ERRNO(errno),
            org::open_power::Proc::CFAM::WriteFailure::CALLOUT_DEVICE_PATH(
                target->getCFAMPath().c_str()));
    }
}


cfam_data_t readReg(const std::unique_ptr<Target>& target,
                    cfam_address_t address)
{
    using namespace phosphor::logging;

    cfam_data_t data = 0;

    int rc = lseek(target->getCFAMFD(), makeOffset(address), SEEK_SET);
    if (rc < 0)
    {
        elog<org::open_power::Proc::CFAM::SeekFailure>(
            org::open_power::Proc::CFAM::SeekFailure::ERRNO(errno),
            org::open_power::Proc::CFAM::SeekFailure::ADDRESS(address),
            org::open_power::Proc::CFAM::SeekFailure::OFFSET(makeOffset(address)),
            org::open_power::Proc::CFAM::SeekFailure::PATH(target->getCFAMPath().c_str()));
    }

    rc = read(target->getCFAMFD(), &data, cfamRegSize);
    if (rc < 0)
    {
        elog<org::open_power::Proc::CFAM::ReadFailure>(
            org::open_power::Proc::CFAM::WriteFailure::CALLOUT_ERRNO(errno),
            org::open_power::Proc::CFAM::WriteFailure::CALLOUT_DEVICE_PATH(
                target->getCFAMPath().c_str()));
    }

    return target->swapEndian(data);
}


void writeRegWithMask(const std::unique_ptr<Target>& target,
                      cfam_address_t address,
                      cfam_data_t data,
                      cfam_mask_t mask)
{
    cfam_data_t readData = readReg(target, address);

    readData &= ~mask;
    readData |= (data & mask);

    writeReg(target, address, readData);
}

}
}
}
OpenPOWER on IntegriCloud