1 #include "eeprom_device_software_manager.hpp" 2 3 #include "common/include/dbus_helper.hpp" 4 #include "eeprom_device.hpp" 5 6 #include <phosphor-logging/lg2.hpp> 7 #include <sdbusplus/async.hpp> 8 #include <xyz/openbmc_project/ObjectMapper/client.hpp> 9 10 #include <fstream> 11 #include <optional> 12 #include <sstream> 13 14 PHOSPHOR_LOG2_USING; 15 16 namespace SoftwareInf = phosphor::software; 17 18 const std::vector<std::string> emConfigTypes = {"PT5161LFirmware"}; 19 20 void EEPROMDeviceSoftwareManager::start() 21 { 22 std::vector<std::string> configIntfs; 23 configIntfs.reserve(emConfigTypes.size()); 24 25 std::transform(emConfigTypes.begin(), emConfigTypes.end(), 26 std::back_inserter(configIntfs), 27 [](const std::string& type) { 28 return "xyz.openbmc_project.Configuration." + type; 29 }); 30 31 ctx.spawn(initDevices(configIntfs)); 32 ctx.run(); 33 } 34 35 sdbusplus::async::task<bool> EEPROMDeviceSoftwareManager::initDevice( 36 const std::string& service, const std::string& path, SoftwareConfig& config) 37 { 38 const std::string configIface = 39 "xyz.openbmc_project.Configuration." + config.configType; 40 41 std::optional<uint64_t> bus = co_await dbusGetRequiredProperty<uint64_t>( 42 ctx, service, path, configIface, "Bus"); 43 44 std::optional<uint64_t> address = 45 co_await dbusGetRequiredProperty<uint64_t>(ctx, service, path, 46 configIface, "Address"); 47 48 std::optional<std::string> type = 49 co_await dbusGetRequiredProperty<std::string>(ctx, service, path, 50 configIface, "Type"); 51 52 std::optional<std::string> fwDevice = 53 co_await dbusGetRequiredProperty<std::string>( 54 ctx, service, path, configIface, "FirmwareDevice"); 55 56 if (!bus.has_value() || !address.has_value() || !type.has_value() || 57 !fwDevice.has_value()) 58 { 59 error("Missing EEPROM device config property"); 60 co_return false; 61 } 62 63 debug("EEPROM Device: Bus={BUS}, Address={ADDR}, Type={TYPE}, " 64 "Firmware Device={DEVICE}", 65 "BUS", bus.value(), "ADDR", address.value(), "TYPE", type.value(), 66 "DEVICE", fwDevice.value()); 67 68 std::unique_ptr<DeviceVersion> deviceVersion = 69 getVersionProvider(type.value(), bus.value(), address.value()); 70 71 if (!deviceVersion) 72 { 73 error("Failed to get version provider for chip type: {CHIP}", "CHIP", 74 type.value()); 75 co_return false; 76 } 77 78 std::string version = deviceVersion->getVersion(); 79 80 using ObjectMapper = 81 sdbusplus::client::xyz::openbmc_project::ObjectMapper<>; 82 83 auto mapper = ObjectMapper(ctx) 84 .service(ObjectMapper::default_service) 85 .path(ObjectMapper::instance_path); 86 87 auto res = 88 co_await mapper.get_sub_tree("/xyz/openbmc_project/inventory", 0, {}); 89 90 bus.reset(); 91 address.reset(); 92 type.reset(); 93 94 for (auto& [p, v] : res) 95 { 96 if (!p.ends_with(fwDevice.value())) 97 { 98 continue; 99 } 100 101 for (auto& [s, ifaces] : v) 102 { 103 for (std::string& iface : ifaces) 104 { 105 if (iface.starts_with("xyz.openbmc_project.Configuration.")) 106 { 107 bus = co_await dbusGetRequiredProperty<uint64_t>( 108 ctx, s, p, iface, "Bus"); 109 110 address = co_await dbusGetRequiredProperty<uint64_t>( 111 ctx, s, p, iface, "Address"); 112 113 type = co_await dbusGetRequiredProperty<std::string>( 114 ctx, s, p, iface, "Type"); 115 break; 116 } 117 } 118 if (bus.has_value() && address.has_value() && type.has_value()) 119 { 120 break; 121 } 122 } 123 break; 124 } 125 126 if (!bus.has_value() || !address.has_value() || !type.has_value()) 127 { 128 error("Missing EEPROM config property"); 129 co_return false; 130 } 131 132 debug("EEPROM: Bus={BUS}, Address={ADDR}, Type={TYPE}", "BUS", bus.value(), 133 "ADDR", address.value(), "TYPE", type.value()); 134 135 const std::string configIfaceMux = configIface + ".MuxOutputs"; 136 std::vector<std::string> gpioLines; 137 std::vector<bool> gpioPolarities; 138 139 for (size_t i = 0; true; i++) 140 { 141 const std::string iface = configIfaceMux + std::to_string(i); 142 143 std::optional<std::string> name = 144 co_await dbusGetRequiredProperty<std::string>(ctx, service, path, 145 iface, "Name"); 146 147 std::optional<std::string> polarity = 148 co_await dbusGetRequiredProperty<std::string>(ctx, service, path, 149 iface, "Polarity"); 150 151 if (!name.has_value() || !polarity.has_value()) 152 { 153 break; 154 } 155 156 gpioLines.push_back(name.value()); 157 gpioPolarities.push_back(polarity.value() == "High"); 158 } 159 160 for (size_t i = 0; i < gpioLines.size(); i++) 161 { 162 debug("Mux gpio {NAME} polarity = {VALUE}", "NAME", gpioLines[i], 163 "VALUE", gpioPolarities[i]); 164 } 165 166 auto eepromDevice = std::make_unique<EEPROMDevice>( 167 ctx, static_cast<uint16_t>(bus.value()), 168 static_cast<uint8_t>(address.value()), type.value(), gpioLines, 169 gpioPolarities, std::move(deviceVersion), config, this); 170 171 std::unique_ptr<SoftwareInf::Software> software = 172 std::make_unique<SoftwareInf::Software>(ctx, *eepromDevice); 173 174 software->setVersion(version.empty() ? "Unknown" : version); 175 176 std::set<RequestedApplyTimes> allowedApplyTimes = { 177 RequestedApplyTimes::Immediate, RequestedApplyTimes::OnReset}; 178 179 software->enableUpdate(allowedApplyTimes); 180 181 eepromDevice->softwareCurrent = std::move(software); 182 183 devices.insert({config.objectPath, std::move(eepromDevice)}); 184 185 co_return true; 186 } 187 188 int main() 189 { 190 sdbusplus::async::context ctx; 191 192 EEPROMDeviceSoftwareManager eepromDeviceSoftwareManager(ctx); 193 194 eepromDeviceSoftwareManager.start(); 195 return 0; 196 } 197