1 /**
2  * Copyright © 2019 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 "mru.hpp"
17 
18 #include <phosphor-logging/log.hpp>
19 
20 namespace openpower
21 {
22 namespace pels
23 {
24 namespace src
25 {
26 
27 using namespace phosphor::logging;
28 
29 // The MRU substructure supports up to 15 MRUs.
30 static constexpr size_t maxMRUs = 15;
31 
32 MRU::MRU(Stream& pel)
33 {
34     pel >> _type >> _size >> _flags >> _reserved4B;
35 
36     size_t numMRUs = _flags & 0xF;
37 
38     for (size_t i = 0; i < numMRUs; i++)
39     {
40         MRUCallout mru;
41         pel >> mru.priority;
42         pel >> mru.id;
43         _mrus.push_back(std::move(mru));
44     }
45 
46     size_t actualSize = sizeof(_type) + sizeof(_size) + sizeof(_flags) +
47                         sizeof(_reserved4B) +
48                         (sizeof(MRUCallout) * _mrus.size());
49     if (_size != actualSize)
50     {
51         log<level::WARNING>("MRU callout section in PEL has listed size that "
52                             "doesn't match actual size",
53                             entry("SUBSTRUCTURE_SIZE=%lu", _size),
54                             entry("NUM_MRUS=%lu", _mrus.size()),
55                             entry("ACTUAL_SIZE=%lu", actualSize));
56     }
57 }
58 
59 MRU::MRU(const std::vector<MRUCallout>& mrus)
60 {
61     if (mrus.empty())
62     {
63         log<level::ERR>("Trying to create a MRU section with no MRUs");
64         throw std::runtime_error{"Trying to create a MRU section with no MRUs"};
65     }
66 
67     _mrus = mrus;
68     if (_mrus.size() > maxMRUs)
69     {
70         _mrus.resize(maxMRUs);
71     }
72 
73     _type = substructureType;
74     _size = sizeof(_type) + sizeof(_size) + sizeof(_flags) +
75             sizeof(_reserved4B) + (sizeof(MRUCallout) * _mrus.size());
76     _flags = _mrus.size();
77     _reserved4B = 0;
78 }
79 
80 void MRU::flatten(Stream& pel) const
81 {
82     pel << _type << _size << _flags << _reserved4B;
83 
84     for (auto& mru : _mrus)
85     {
86         pel << mru.priority;
87         pel << mru.id;
88     }
89 }
90 } // namespace src
91 } // namespace pels
92 } // namespace openpower
93