summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-x86/chassis/x86-power-control/0004-Protect-POST-Complete-GPIO-read.patch
blob: 8da9660ef8223fe379c3674182faecc502c53828 (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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
From 247bb976d0852af0a2e2c1fb6730876c01895487 Mon Sep 17 00:00:00 2001
From: rrv <rashmi.r.v@intel.com>
Date: Fri, 15 Oct 2021 10:29:01 +0530
Subject: [PATCH] Protect POST Complete GPIO read

In BRC/MRC platforms, due to ME BIOS limitation,
PostComplete GPIO pin cannot be locked. Hence
to nullify the impact to BMC, this change makes sure
that Post Complete monitor is based on espi reset.
for BRC and MRC platforms.

Tested:

Checked the OperatingSystemState property during all
conditions of AC ON, AC  cycle, DC cycle, DC OFF and DC ON,
and BMC reset. It works as expected.

Signed-off-by: rrv <rashmi.r.v@intel.com>
---
 power-control-x86/src/power_control.cpp | 155 ++++++++++++++++++++++++
 1 file changed, 155 insertions(+)

diff --git a/power-control-x86/src/power_control.cpp b/power-control-x86/src/power_control.cpp
index 5a8487e..28b296d 100644
--- a/power-control-x86/src/power_control.cpp
+++ b/power-control-x86/src/power_control.cpp
@@ -18,6 +18,7 @@
 #include <sys/sysinfo.h>
 #include <systemd/sd-journal.h>
 
+#include <boost/algorithm/string/predicate.hpp>
 #include <boost/asio/posix/stream_descriptor.hpp>
 #include <boost/container/flat_map.hpp>
 #include <boost/container/flat_set.hpp>
@@ -112,6 +113,11 @@ static gpiod::line nmiOutLine;
 
 static constexpr uint8_t beepPowerFail = 8;
 
+static uint16_t productId = 0;
+static constexpr uint16_t brcId = 160;
+static constexpr uint16_t mrcId = 161;
+static std::unique_ptr<sdbusplus::bus::match::match> productIdMatch;
+
 static void beep(const uint8_t& beepPriority)
 {
     std::cerr << "Beep with priority: " << (unsigned)beepPriority << "\n";
@@ -2029,6 +2035,11 @@ static void postCompleteHandler()
     {
         sendPowerControlEvent(Event::postCompleteAssert);
         osIface->set_property("OperatingSystemState", std::string("Standby"));
+        // return only when MRC or BRC platforms
+        if (productId == brcId || productId == mrcId)
+        {
+            return;
+        }
     }
     else
     {
@@ -2047,6 +2058,147 @@ static void postCompleteHandler()
             postCompleteHandler();
         });
 }
+
+static void getEspiPlatformReset()
+{
+
+    static std::unique_ptr<sdbusplus::bus::match::match> eSpiMatch =
+        std::make_unique<sdbusplus::bus::match::match>(
+            *conn,
+            "type='signal',interface='org.freedesktop.DBus.Properties',"
+            "member='PropertiesChanged',arg0namespace='xyz.openbmc_project."
+            "State.Host.Misc'",
+            [](sdbusplus::message::message& msg) {
+                std::string interfaceName;
+                boost::container::flat_map<std::string,
+                                           std::variant<bool, std::string>>
+                    propertiesChanged;
+                try
+                {
+                    msg.read(interfaceName, propertiesChanged);
+                    if (propertiesChanged.begin()->first == "ESpiPlatformReset")
+                    {
+                        bool value =
+                            std::get<bool>(propertiesChanged.begin()->second);
+                        phosphor::logging::log<phosphor::logging::level::INFO>(
+                            "ESpiPlatformReset propertiesChanged",
+                            phosphor::logging::entry("VALUE= %d", value));
+                        if (value)
+                        {
+                            postCompleteHandler();
+                        }
+                    }
+                }
+                catch (std::exception& e)
+                {
+                    std::cerr << "Unable to read  ESpiPlatformReset \n";
+                    return;
+                }
+            });
+}
+
+static void getProductId(const std::string& baseboardObjPath)
+{
+    // Check if it's already on DBus
+    conn->async_method_call(
+        [](boost::system::error_code ec,
+           const std::variant<uint64_t>& prodIdProperty) {
+            if (ec)
+            {
+                return;
+            }
+            const uint64_t* prodId = std::get_if<uint64_t>(&prodIdProperty);
+            if (prodId == nullptr)
+            {
+                std::cerr << "Unable to read power restore delay value\n";
+                return;
+            }
+            // Reset the signal
+            productIdMatch.reset();
+            productId = static_cast<uint16_t>(*prodId);
+            if (productId == brcId || productId == mrcId)
+            {
+                getEspiPlatformReset();
+            };
+        },
+        "xyz.openbmc_project.EntityManager", baseboardObjPath,
+        "org.freedesktop.DBus.Properties", "Get",
+        "xyz.openbmc_project.Inventory.Item.Board.Motherboard", "ProductId");
+}
+
+static void checkProductId()
+{
+    productIdMatch = std::make_unique<sdbusplus::bus::match::match>(
+        *conn,
+        "type='signal',interface='org.freedesktop.DBus.Properties',"
+        "member='PropertiesChanged',arg0namespace='xyz.openbmc_project."
+        "Inventory.Item.Board.Motherboard'",
+        [](sdbusplus::message::message& msg) {
+            std::string interfaceName;
+            boost::container::flat_map<std::string,
+                                       std::variant<uint64_t, std::string>>
+                propertiesChanged;
+            try
+            {
+                msg.read(interfaceName, propertiesChanged);
+                if (propertiesChanged.begin()->first == "ProductId")
+                {
+                    productId = static_cast<uint16_t>(
+                        std::get<uint64_t>(propertiesChanged.begin()->second));
+                    phosphor::logging::log<phosphor::logging::level::INFO>(
+                        "ProductId propertiesChanged",
+                        phosphor::logging::entry(" PRODUCTID= %d", productId));
+                }
+            }
+            catch (std::exception& e)
+            {
+                std::cerr << "Unable to read  ProductId \n";
+                productIdMatch.reset();
+                return;
+            }
+            // Reset the signal
+            productIdMatch.reset();
+            // monitor the eSpiplatform reset only BRC OR MRC
+            // platforms
+            if (productId == brcId || productId == mrcId)
+            {
+                getEspiPlatformReset();
+            }
+        });
+
+    // get the MRC/BRC board path.
+    conn->async_method_call(
+        [](boost::system::error_code ec, std::vector<std::string>& subtree) {
+            if (ec)
+            {
+                phosphor::logging::log<phosphor::logging::level::ERR>(
+                    "dbus call failed in getSubTree of board interface.",
+                    phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
+                return;
+            }
+            const std::string match = "board";
+            for (const std::string& objpath : subtree)
+            {
+                // Iterate over all retrieved ObjectPaths.
+                if (!boost::ends_with(objpath, match))
+                {
+                    // Just move to next path.
+                    continue;
+                }
+
+                // Baseboard object path found
+                getProductId(objpath);
+                return;
+            }
+        },
+        "xyz.openbmc_project.ObjectMapper",
+        "/xyz/openbmc_project/object_mapper",
+        "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
+        "/xyz/openbmc_project/inventory", 0,
+        std::array<const char*, 1>{
+            "xyz.openbmc_project.Inventory.Item.Board.Motherboard"});
+}
+
 } // namespace power_control
 
 int main(int argc, char* argv[])
@@ -2123,6 +2275,9 @@ int main(int argc, char* argv[])
         "ID_BUTTON", power_control::idButtonHandler,
         power_control::idButtonLine, power_control::idButtonEvent);
 
+    // Read productId from Dbus and check
+    power_control::checkProductId();
+
     // Request POST_COMPLETE GPIO events
     if (!power_control::requestGPIOEvents(
             "POST_COMPLETE", power_control::postCompleteHandler,
-- 
2.17.1