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