1 /**
2  * Copyright © 2021 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 #pragma once
17 
18 #include "../zone.hpp"
19 #include "action.hpp"
20 #include "group.hpp"
21 #include "utils/pcie_card_metadata.hpp"
22 
23 #include <nlohmann/json.hpp>
24 
25 namespace phosphor::fan::control::json
26 {
27 
28 using json = nlohmann::json;
29 
30 class Manager;
31 
32 /**
33  * @class PCIeCardFloors - Action to set the PCIe card floor index parameter
34  *                          based on the PCIe cards plugged in the system.
35  *
36  *  - Loads PCIe card metadata files using the PCIeCardMetadata class.
37  *  - Watches for PCIe slots to be powered on (or off).
38  *  - Reads four properties off of the PCIeDevice interface on the powered
39  *    on cards.
40  *  - Looks up the floor index for the card by calling PCIeCardMetadata::lookup
41  *    and passing in the PCIeDevice properties.
42  *  - Sets the pcie_floor_index parameter with the highest floor index found.
43  *  - If no PCIe cards are found, it removes the parameter.
44  *  - If a card isn't recognized, it's ignored since it isn't considered a
45  *    hot card.
46  *  - If a powered on card has its own temperature sensor, then it doesn't
47  *    have a floor index.
48  *  - Since the slot powered on indications are all sent at once, it has a
49  *    small delay that gets started in each run() call that must expire
50  *    before the body of the action is run, so it only runs once.
51  *
52  *    The JSON configuration has two entries:
53  *    {
54  *       "settle_time": <time in s>
55  *       "use_config_specific_files": <true/false>
56  *    }
57  *
58  *    settle_time:
59  *      - Specifies how long to wait after run() is called before actually
60  *        running the action as a flurry of propertiesChanged signals
61  *        that trigger the action tend to come at once.
62  *      - Optional.  If not specified it defaults to zero.
63  *
64  *    use_config_specific_files:
65  *      - If true, will look for 'pcie_cards.json' files in the system
66  *        specific directories.
67  *      - See PCIeCardMetadata for details.
68  */
69 class PCIeCardFloors : public ActionBase, public ActionRegister<PCIeCardFloors>
70 {
71   public:
72     /* Name of this action */
73     static constexpr auto name = "pcie_card_floors";
74 
75     PCIeCardFloors() = delete;
76     PCIeCardFloors(const PCIeCardFloors&) = delete;
77     PCIeCardFloors(PCIeCardFloors&&) = delete;
78     PCIeCardFloors& operator=(const PCIeCardFloors&) = delete;
79     PCIeCardFloors& operator=(PCIeCardFloors&&) = delete;
80     ~PCIeCardFloors() = default;
81 
82     /**
83      * @brief Read in the action configuration
84      *
85      * @param[in] jsonObj - JSON configuration of this action
86      * @param[in] groups - Groups of dbus objects the action uses
87      */
88     PCIeCardFloors(const json& jsonObj, const std::vector<Group>& groups);
89 
90     /**
91      * @brief Run the action.
92      *
93      * Starts/restarts the settle timer and then calls execute()
94      * when it expires.  Done to handle the flood of slot powered
95      * on/off signals.
96      *
97      * @param[in] zone - Zone to run the action on
98      */
99     void run(Zone& zone) override;
100 
101   private:
102     /**
103      * @brief Runs the contents of the action when the settle timer expires.
104      *
105      * @param[in] zone - Zone to run the action on
106      */
107     void execute(Zone& zone);
108 
109     /**
110      * @brief Constructs the PCIeCardMetadata object to load the PCIe card
111      *        JSON files.
112      *
113      * @param[in] jsonObj - JSON configuration of this action
114      */
115     void loadCardJSON(const json& jsonObj);
116 
117     /**
118      * @brief Returns the D-Bus object path of the card plugged into
119      *        the slot represented by the slotPath D-Bus path.
120      *
121      * @param[in] slotPath - The D-Bus path of the PCIe slot object.
122      *
123      * @return const std::string& - The card object path.
124      */
125     const std::string& getCardFromSlot(const std::string& slotPath);
126 
127     /**
128      * @brief Returns the floor index (or temp sensor name) for the
129      *        card in the passed in slot.
130      *
131      * @param[in] slotPath - The D-Bus path of the PCIe slot object.
132      *
133      * @return optional<variant<int32_t, string>>
134      *  - The floor index or true for has temp sensor if found,
135      *    std::nullopt else.
136      */
137     std::optional<std::variant<int32_t, bool>>
138         getFloorIndexFromSlot(const std::string& slotPath);
139 
140     /**
141      * @brief Gets the hex PCIeDevice property value from the
142      *        manager object cache.
143      *
144      * @param[in] objectPath - The card object path
145      * @param[in] propertyName - The property to read
146      *
147      * @return uint16_t The property value
148      */
149     uint16_t getPCIeDeviceProperty(const std::string& objectPath,
150                                    const std::string& propertyName);
151 
152     /* The PCIe card metadata manager */
153     std::unique_ptr<PCIeCardMetadata> _cardMetadata;
154 
155     /* Cache map of PCIe slot paths to their plugged card paths */
156     std::unordered_map<std::string, std::string> _cards;
157 
158     /* Cache of all objects with a PCIeDevice interface. */
159     std::vector<std::string> _pcieDevices;
160 
161     std::chrono::seconds _settleTime{0};
162 
163     /* Timer to wait for slot plugs to settle down before running action */
164     std::unique_ptr<Timer> _settleTimer;
165 
166     /* Last status printed so only new messages get recorded */
167     std::string _lastStatus;
168 };
169 
170 } // namespace phosphor::fan::control::json
171