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     /**
102      * @brief Set the name of the owning Event.
103      *
104      * In the base class it's appending it to the action's unique name.  Don't
105      * do it for this action since there's only one instance of it so no need
106      * to distinguish it from ones under different events and also it just
107      * makes it uglier in the flight recorder.
108      */
109     void setEventName(const std::string& /*name*/) override
110     {}
111 
112   private:
113     /**
114      * @brief Runs the contents of the action when the settle timer expires.
115      */
116     void execute();
117 
118     /**
119      * @brief Constructs the PCIeCardMetadata object to load the PCIe card
120      *        JSON files.
121      *
122      * @param[in] jsonObj - JSON configuration of this action
123      */
124     void loadCardJSON(const json& jsonObj);
125 
126     /**
127      * @brief Returns the D-Bus object path of the card plugged into
128      *        the slot represented by the slotPath D-Bus path.
129      *
130      * @param[in] slotPath - The D-Bus path of the PCIe slot object.
131      *
132      * @return const std::string& - The card object path.
133      */
134     const std::string& getCardFromSlot(const std::string& slotPath);
135 
136     /**
137      * @brief Returns the floor index (or temp sensor name) for the
138      *        card in the passed in slot.
139      *
140      * @param[in] slotPath - The D-Bus path of the PCIe slot object.
141      *
142      * @return optional<variant<int32_t, string>>
143      *  - The floor index or true for has temp sensor if found,
144      *    std::nullopt else.
145      */
146     std::optional<std::variant<int32_t, bool>>
147         getFloorIndexFromSlot(const std::string& slotPath);
148 
149     /**
150      * @brief Gets the hex PCIeDevice property value from the
151      *        manager object cache.
152      *
153      * @param[in] objectPath - The card object path
154      * @param[in] propertyName - The property to read
155      *
156      * @return uint16_t The property value
157      */
158     uint16_t getPCIeDeviceProperty(const std::string& objectPath,
159                                    const std::string& propertyName);
160 
161     /* The PCIe card metadata manager */
162     std::unique_ptr<PCIeCardMetadata> _cardMetadata;
163 
164     /* Cache map of PCIe slot paths to their plugged card paths */
165     std::unordered_map<std::string, std::string> _cards;
166 
167     /* Cache of all objects with a PCIeDevice interface. */
168     std::vector<std::string> _pcieDevices;
169 
170     std::chrono::seconds _settleTime{0};
171 
172     /* Timer to wait for slot plugs to settle down before running action */
173     std::unique_ptr<Timer> _settleTimer;
174 
175     /* Last status printed so only new messages get recorded */
176     std::string _lastStatus;
177 };
178 
179 } // namespace phosphor::fan::control::json
180