124956598SShawn McCarney /**
224956598SShawn McCarney * Copyright © 2024 IBM Corporation
324956598SShawn McCarney *
424956598SShawn McCarney * Licensed under the Apache License, Version 2.0 (the "License");
524956598SShawn McCarney * you may not use this file except in compliance with the License.
624956598SShawn McCarney * You may obtain a copy of the License at
724956598SShawn McCarney *
824956598SShawn McCarney * http://www.apache.org/licenses/LICENSE-2.0
924956598SShawn McCarney *
1024956598SShawn McCarney * Unless required by applicable law or agreed to in writing, software
1124956598SShawn McCarney * distributed under the License is distributed on an "AS IS" BASIS,
1224956598SShawn McCarney * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1324956598SShawn McCarney * See the License for the specific language governing permissions and
1424956598SShawn McCarney * limitations under the License.
1524956598SShawn McCarney */
1624956598SShawn McCarney
1724956598SShawn McCarney #include "rail.hpp"
1824956598SShawn McCarney
1924956598SShawn McCarney #include "pmbus.hpp"
20f47a7a72SShawn McCarney #include "power_sequencer_device.hpp"
2124956598SShawn McCarney
2224956598SShawn McCarney #include <exception>
2324956598SShawn McCarney #include <format>
2424956598SShawn McCarney
2524956598SShawn McCarney namespace phosphor::power::sequencer
2624956598SShawn McCarney {
2724956598SShawn McCarney namespace status_vout = phosphor::pmbus::status_vout;
2824956598SShawn McCarney
isPresent(Services & services)2924956598SShawn McCarney bool Rail::isPresent(Services& services)
3024956598SShawn McCarney {
3124956598SShawn McCarney // Initially assume rail is present
3224956598SShawn McCarney bool present{true};
3324956598SShawn McCarney
3424956598SShawn McCarney // If presence data member contains an inventory path to check
3524956598SShawn McCarney if (presence)
3624956598SShawn McCarney {
3724956598SShawn McCarney const std::string& inventoryPath = *presence;
3824956598SShawn McCarney try
3924956598SShawn McCarney {
4024956598SShawn McCarney present = services.isPresent(inventoryPath);
4124956598SShawn McCarney }
4224956598SShawn McCarney catch (const std::exception& e)
4324956598SShawn McCarney {
4424956598SShawn McCarney throw std::runtime_error{std::format(
4524956598SShawn McCarney "Unable to determine presence of rail {} using inventory path {}: {}",
4624956598SShawn McCarney name, inventoryPath, e.what())};
4724956598SShawn McCarney }
4824956598SShawn McCarney }
4924956598SShawn McCarney
5024956598SShawn McCarney return present;
5124956598SShawn McCarney }
5224956598SShawn McCarney
getStatusWord(PowerSequencerDevice & device)5324956598SShawn McCarney uint16_t Rail::getStatusWord(PowerSequencerDevice& device)
5424956598SShawn McCarney {
5524956598SShawn McCarney uint16_t value{0};
5624956598SShawn McCarney try
5724956598SShawn McCarney {
5824956598SShawn McCarney verifyHasPage();
5924956598SShawn McCarney value = device.getStatusWord(*page);
6024956598SShawn McCarney }
6124956598SShawn McCarney catch (const std::exception& e)
6224956598SShawn McCarney {
6324956598SShawn McCarney throw std::runtime_error{
6424956598SShawn McCarney std::format("Unable to read STATUS_WORD value for rail {}: {}",
6524956598SShawn McCarney name, e.what())};
6624956598SShawn McCarney }
6724956598SShawn McCarney return value;
6824956598SShawn McCarney }
6924956598SShawn McCarney
getStatusVout(PowerSequencerDevice & device)7024956598SShawn McCarney uint8_t Rail::getStatusVout(PowerSequencerDevice& device)
7124956598SShawn McCarney {
7224956598SShawn McCarney uint8_t value{0};
7324956598SShawn McCarney try
7424956598SShawn McCarney {
7524956598SShawn McCarney verifyHasPage();
7624956598SShawn McCarney value = device.getStatusVout(*page);
7724956598SShawn McCarney }
7824956598SShawn McCarney catch (const std::exception& e)
7924956598SShawn McCarney {
8024956598SShawn McCarney throw std::runtime_error{
8124956598SShawn McCarney std::format("Unable to read STATUS_VOUT value for rail {}: {}",
8224956598SShawn McCarney name, e.what())};
8324956598SShawn McCarney }
8424956598SShawn McCarney return value;
8524956598SShawn McCarney }
8624956598SShawn McCarney
getReadVout(PowerSequencerDevice & device)8724956598SShawn McCarney double Rail::getReadVout(PowerSequencerDevice& device)
8824956598SShawn McCarney {
8924956598SShawn McCarney double value{0.0};
9024956598SShawn McCarney try
9124956598SShawn McCarney {
9224956598SShawn McCarney verifyHasPage();
9324956598SShawn McCarney value = device.getReadVout(*page);
9424956598SShawn McCarney }
9524956598SShawn McCarney catch (const std::exception& e)
9624956598SShawn McCarney {
9724956598SShawn McCarney throw std::runtime_error{std::format(
9824956598SShawn McCarney "Unable to read READ_VOUT value for rail {}: {}", name, e.what())};
9924956598SShawn McCarney }
10024956598SShawn McCarney return value;
10124956598SShawn McCarney }
10224956598SShawn McCarney
getVoutUVFaultLimit(PowerSequencerDevice & device)10324956598SShawn McCarney double Rail::getVoutUVFaultLimit(PowerSequencerDevice& device)
10424956598SShawn McCarney {
10524956598SShawn McCarney double value{0.0};
10624956598SShawn McCarney try
10724956598SShawn McCarney {
10824956598SShawn McCarney verifyHasPage();
10924956598SShawn McCarney value = device.getVoutUVFaultLimit(*page);
11024956598SShawn McCarney }
11124956598SShawn McCarney catch (const std::exception& e)
11224956598SShawn McCarney {
11324956598SShawn McCarney throw std::runtime_error{std::format(
11424956598SShawn McCarney "Unable to read VOUT_UV_FAULT_LIMIT value for rail {}: {}", name,
11524956598SShawn McCarney e.what())};
11624956598SShawn McCarney }
11724956598SShawn McCarney return value;
11824956598SShawn McCarney }
11924956598SShawn McCarney
hasPgoodFault(PowerSequencerDevice & device,Services & services,const std::vector<int> & gpioValues,std::map<std::string,std::string> & additionalData)12024956598SShawn McCarney bool Rail::hasPgoodFault(PowerSequencerDevice& device, Services& services,
12124956598SShawn McCarney const std::vector<int>& gpioValues,
12224956598SShawn McCarney std::map<std::string, std::string>& additionalData)
12324956598SShawn McCarney {
124*16275831SShawn McCarney return (hasPgoodFaultStatusVout(device, services, additionalData) ||
125*16275831SShawn McCarney hasPgoodFaultGPIO(device, services, gpioValues, additionalData) ||
126*16275831SShawn McCarney hasPgoodFaultOutputVoltage(device, services, additionalData));
12724956598SShawn McCarney }
12824956598SShawn McCarney
hasPgoodFaultStatusVout(PowerSequencerDevice & device,Services & services,std::map<std::string,std::string> & additionalData)12924956598SShawn McCarney bool Rail::hasPgoodFaultStatusVout(
13024956598SShawn McCarney PowerSequencerDevice& device, Services& services,
13124956598SShawn McCarney std::map<std::string, std::string>& additionalData)
13224956598SShawn McCarney {
13324956598SShawn McCarney bool hasFault{false};
13424956598SShawn McCarney
135*16275831SShawn McCarney // If rail is present and we are checking the value of STATUS_VOUT
136*16275831SShawn McCarney if (isPresent(services) && checkStatusVout)
13724956598SShawn McCarney {
13824956598SShawn McCarney // Read STATUS_VOUT value from device
13924956598SShawn McCarney uint8_t statusVout = getStatusVout(device);
14024956598SShawn McCarney
14124956598SShawn McCarney // Check if fault (non-warning) bits are set in value
14224956598SShawn McCarney if (statusVout & ~status_vout::WARNING_MASK)
14324956598SShawn McCarney {
14424956598SShawn McCarney hasFault = true;
14524956598SShawn McCarney services.logErrorMsg(std::format(
14624956598SShawn McCarney "Rail {} has fault bits set in STATUS_VOUT: {:#04x}", name,
14724956598SShawn McCarney statusVout));
14824956598SShawn McCarney additionalData.emplace("STATUS_VOUT",
14924956598SShawn McCarney std::format("{:#04x}", statusVout));
150*16275831SShawn McCarney storePgoodFaultDebugData(device, services, additionalData);
15124956598SShawn McCarney }
15224956598SShawn McCarney else if (statusVout != 0)
15324956598SShawn McCarney {
15424956598SShawn McCarney services.logInfoMsg(std::format(
15524956598SShawn McCarney "Rail {} has warning bits set in STATUS_VOUT: {:#04x}", name,
15624956598SShawn McCarney statusVout));
15724956598SShawn McCarney }
15824956598SShawn McCarney }
15924956598SShawn McCarney
16024956598SShawn McCarney return hasFault;
16124956598SShawn McCarney }
16224956598SShawn McCarney
hasPgoodFaultGPIO(PowerSequencerDevice & device,Services & services,const std::vector<int> & gpioValues,std::map<std::string,std::string> & additionalData)163*16275831SShawn McCarney bool Rail::hasPgoodFaultGPIO(PowerSequencerDevice& device, Services& services,
16424956598SShawn McCarney const std::vector<int>& gpioValues,
16524956598SShawn McCarney std::map<std::string, std::string>& additionalData)
16624956598SShawn McCarney {
16724956598SShawn McCarney bool hasFault{false};
16824956598SShawn McCarney
169*16275831SShawn McCarney // If rail is present and a GPIO is defined for checking pgood status
170*16275831SShawn McCarney if (isPresent(services) && gpio)
17124956598SShawn McCarney {
17224956598SShawn McCarney // Get GPIO value
17324956598SShawn McCarney unsigned int line = gpio->line;
17424956598SShawn McCarney bool activeLow = gpio->activeLow;
17524956598SShawn McCarney if (line >= gpioValues.size())
17624956598SShawn McCarney {
17724956598SShawn McCarney throw std::runtime_error{std::format(
17824956598SShawn McCarney "Invalid GPIO line offset {} for rail {}: Device only has {} GPIO values",
17924956598SShawn McCarney line, name, gpioValues.size())};
18024956598SShawn McCarney }
18124956598SShawn McCarney int value = gpioValues[line];
18224956598SShawn McCarney
18324956598SShawn McCarney // Check if value indicates pgood signal is not active
18424956598SShawn McCarney if ((activeLow && (value == 1)) || (!activeLow && (value == 0)))
18524956598SShawn McCarney {
18624956598SShawn McCarney hasFault = true;
18724956598SShawn McCarney services.logErrorMsg(std::format(
18824956598SShawn McCarney "Rail {} pgood GPIO line offset {} has inactive value {}", name,
18924956598SShawn McCarney line, value));
19024956598SShawn McCarney additionalData.emplace("GPIO_LINE", std::format("{}", line));
19124956598SShawn McCarney additionalData.emplace("GPIO_VALUE", std::format("{}", value));
192*16275831SShawn McCarney storePgoodFaultDebugData(device, services, additionalData);
19324956598SShawn McCarney }
19424956598SShawn McCarney }
19524956598SShawn McCarney
19624956598SShawn McCarney return hasFault;
19724956598SShawn McCarney }
19824956598SShawn McCarney
hasPgoodFaultOutputVoltage(PowerSequencerDevice & device,Services & services,std::map<std::string,std::string> & additionalData)19924956598SShawn McCarney bool Rail::hasPgoodFaultOutputVoltage(
20024956598SShawn McCarney PowerSequencerDevice& device, Services& services,
20124956598SShawn McCarney std::map<std::string, std::string>& additionalData)
20224956598SShawn McCarney {
20324956598SShawn McCarney bool hasFault{false};
20424956598SShawn McCarney
205*16275831SShawn McCarney // If rail is present and we are comparing output voltage to UV limit
206*16275831SShawn McCarney if (isPresent(services) && compareVoltageToLimit)
20724956598SShawn McCarney {
20824956598SShawn McCarney // Read output voltage and UV fault limit values from device
20924956598SShawn McCarney double vout = getReadVout(device);
21024956598SShawn McCarney double uvLimit = getVoutUVFaultLimit(device);
21124956598SShawn McCarney
21224956598SShawn McCarney // If output voltage is at or below UV fault limit
21324956598SShawn McCarney if (vout <= uvLimit)
21424956598SShawn McCarney {
21524956598SShawn McCarney hasFault = true;
21624956598SShawn McCarney services.logErrorMsg(std::format(
21724956598SShawn McCarney "Rail {} output voltage {}V is <= UV fault limit {}V", name,
21824956598SShawn McCarney vout, uvLimit));
21924956598SShawn McCarney additionalData.emplace("READ_VOUT", std::format("{}", vout));
22024956598SShawn McCarney additionalData.emplace("VOUT_UV_FAULT_LIMIT",
22124956598SShawn McCarney std::format("{}", uvLimit));
222*16275831SShawn McCarney storePgoodFaultDebugData(device, services, additionalData);
22324956598SShawn McCarney }
22424956598SShawn McCarney }
22524956598SShawn McCarney
22624956598SShawn McCarney return hasFault;
22724956598SShawn McCarney }
22824956598SShawn McCarney
verifyHasPage()229*16275831SShawn McCarney void Rail::verifyHasPage()
230*16275831SShawn McCarney {
231*16275831SShawn McCarney if (!page)
232*16275831SShawn McCarney {
233*16275831SShawn McCarney throw std::runtime_error{
234*16275831SShawn McCarney std::format("No PAGE number defined for rail {}", name)};
235*16275831SShawn McCarney }
236*16275831SShawn McCarney }
237*16275831SShawn McCarney
storePgoodFaultDebugData(PowerSequencerDevice & device,Services & services,std::map<std::string,std::string> & additionalData)23824956598SShawn McCarney void Rail::storePgoodFaultDebugData(
23924956598SShawn McCarney PowerSequencerDevice& device, Services& services,
24024956598SShawn McCarney std::map<std::string, std::string>& additionalData)
24124956598SShawn McCarney {
242*16275831SShawn McCarney services.logErrorMsg(std::format("Pgood fault detected in rail {}", name));
24324956598SShawn McCarney additionalData.emplace("RAIL_NAME", name);
24424956598SShawn McCarney if (page)
24524956598SShawn McCarney {
24624956598SShawn McCarney try
24724956598SShawn McCarney {
24824956598SShawn McCarney uint16_t statusWord = getStatusWord(device);
24924956598SShawn McCarney services.logInfoMsg(
25024956598SShawn McCarney std::format("Rail {} STATUS_WORD: {:#06x}", name, statusWord));
25124956598SShawn McCarney additionalData.emplace("STATUS_WORD",
25224956598SShawn McCarney std::format("{:#06x}", statusWord));
25324956598SShawn McCarney }
25424956598SShawn McCarney catch (...)
25524956598SShawn McCarney {
25624956598SShawn McCarney // Ignore error; don't interrupt pgood fault handling
25724956598SShawn McCarney }
25824956598SShawn McCarney }
25924956598SShawn McCarney }
26024956598SShawn McCarney
26124956598SShawn McCarney } // namespace phosphor::power::sequencer
262