| #ifndef THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_HAL_FRU_SCANNER_I2C_H_ |
| #define THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_HAL_FRU_SCANNER_I2C_H_ |
| |
| #include <sys/types.h> |
| |
| #include <charconv> |
| #include <cstddef> |
| #include <cstdint> |
| #include <memory> |
| #include <optional> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "bus_topology.pb.h" |
| #include "absl/container/flat_hash_map.h" |
| #include "absl/container/flat_hash_set.h" |
| #include "absl/status/statusor.h" |
| #include "absl/strings/ascii.h" |
| #include "absl/strings/numbers.h" |
| #include "absl/strings/str_split.h" |
| #include "absl/strings/string_view.h" |
| #include "absl/strings/strip.h" |
| #include "absl/time/time.h" |
| #include "absl/types/span.h" |
| #include "io/ioctl.h" |
| #include "io/smbus/kernel_dev.h" |
| #include "io/smbus/smbus.h" |
| #include "time/clock.h" |
| #include "tlbmc/deterministic_bmc/i2c_walker/i2c_walker_interface.h" |
| #include "tlbmc/deterministic_bmc/i2c_walker/uhmm_i2c_walker.h" |
| #include "tlbmc/hal/fru_scanner.h" |
| #include "tlbmc/hal/sysfs/i2c.h" |
| #include "tlbmc/utils/fru_utils.h" |
| |
| namespace milotic_tlbmc { |
| |
| constexpr int kI2cFruScanStart = 0x50; |
| constexpr int kI2cFruScanEnd = 0x57; |
| |
| #ifdef TLBMC_FRU_SCAN_EXTRA_ADDRS |
| inline constexpr uint32_t kI2cFruScanExtraAddrsStorage[] = { |
| TLBMC_FRU_SCAN_EXTRA_ADDRS}; |
| inline constexpr absl::Span<const uint32_t> kI2cFruScanExtraAddrs = |
| kI2cFruScanExtraAddrsStorage; |
| #else |
| inline constexpr absl::Span<const uint32_t> kI2cFruScanExtraAddrs = {}; |
| #endif |
| |
| // Context for the scan. |
| struct ScanContext { |
| // Map of bus to addresses that have already been scanned. |
| absl::flat_hash_map<size_t, absl::flat_hash_set<size_t>> fru_addresses_list; |
| }; |
| |
| class FruScannerI2c : public FruScanner { |
| public: |
| struct Options { |
| std::string root_dir; |
| std::string i2c_dev_dir; |
| absl::flat_hash_map<size_t, std::optional<absl::flat_hash_set<size_t>>> |
| bus_block_list; |
| |
| // For deterministic BMC |
| bool deterministic_scan = false; |
| uhmm::I2cRoot i2c_root; |
| std::string i2c_devices_sysfs_dir; |
| |
| std::vector<uint32_t> extra_fru_scan_addresses = std::vector<uint32_t>( |
| kI2cFruScanExtraAddrs.begin(), kI2cFruScanExtraAddrs.end()); |
| }; |
| |
| static std::unique_ptr<FruScannerI2c> Create(const Options& options); |
| |
| absl::StatusOr<std::vector<std::unique_ptr<I2cFruInfo>>> ScanAllI2cFrus() |
| const override; |
| |
| absl::StatusOr<std::vector<std::unique_ptr<I2cSensorAssemblyFruInfo>>> |
| ScanAllI2cSensorAssemblyFru() const override; |
| |
| absl::StatusOr<std::unique_ptr<I2cFruInfo>> GetI2cFruInfoFromBus( |
| int bus, int address, absl::Duration delay_between_reads) const override; |
| |
| absl::StatusOr<std::unique_ptr<I2cFruInfo>> ScanDirectI2cFru( |
| int bus, int address, absl::Duration delay_between_reads) const; |
| |
| bool IsDeterministicScanEnabled() const { return deterministic_scan_; } |
| |
| protected: |
| FruScannerI2c( |
| absl::string_view root_dir, absl::string_view i2c_dev_dir, |
| bool deterministic_scan, uhmm::I2cRoot i2c_root, |
| absl::string_view i2c_devices_sysfs_dir, |
| const absl::flat_hash_map< |
| size_t, std::optional<absl::flat_hash_set<size_t>>>& bus_block_list, |
| std::vector<uint32_t> extra_fru_scan_addresses = std::vector<uint32_t>( |
| kI2cFruScanExtraAddrs.begin(), kI2cFruScanExtraAddrs.end())) |
| : root_dir_(root_dir), |
| deterministic_scan_(deterministic_scan), |
| uhmm_i2c_walker_(deterministic_bmc::UhmmI2cWalker::Create({ |
| .root_directory = root_dir_, |
| .i2c_root = i2c_root, |
| })), |
| i2c_root_(std::move(i2c_root)), |
| i2c_sysfs_(milotic_tlbmc::I2cSysfsConfig{ |
| .i2c_sysfs_path = std::string(i2c_devices_sysfs_dir)}), |
| bus_block_list_(bus_block_list), |
| sys_ioctl_(), |
| smbus_access_(std::make_unique<ecclesia::KernelSmbusAccess>( |
| std::string(i2c_dev_dir), &sys_ioctl_)), |
| extra_fru_scan_addresses_(std::move(extra_fru_scan_addresses)), |
| extra_fru_scan_addresses_set_(extra_fru_scan_addresses_.begin(), |
| extra_fru_scan_addresses_.end()) {} |
| |
| enum class AddressingMode { |
| k8Bit, |
| k16Bit, |
| kUnknown, |
| }; |
| |
| void FindI2CDevices(const absl::flat_hash_set<int>& i2c_buses, |
| BusMap& bus_map) const; |
| |
| std::pair<std::vector<uint8_t>, bool> ReadFruContentsFromI2c( |
| int i2c_bus, int address, |
| absl::Duration delay_between_reads = absl::ZeroDuration(), |
| bool* parsing_error = nullptr) const; |
| |
| // Reads 16-bit addressed FRU data using raw I2C block read |
| // (ReadBlock16BitAddr). This is atomic at the bus level. |
| int64_t Read16BitFru(const ecclesia::SmbusLocation& location, off_t offset, |
| absl::Span<uint8_t> outbuf, |
| absl::Duration delay_between_reads) const; |
| |
| // Reads FRU data using SMBus block read protocol (ReadBlockI2C). |
| // This is atomic for reads up to 32 bytes (SMBus limit). For larger reads, |
| // it chunks the read in user space, which is not fully atomic across chunks. |
| // Prefer this by default for efficiency and atomicity. |
| int64_t Read8BitFru(const ecclesia::SmbusLocation& location, off_t offset, |
| absl::Span<uint8_t> outbuf, |
| absl::Duration delay_between_reads) const; |
| |
| AddressingMode GetDeviceAddressingMode( |
| const ecclesia::SmbusLocation& location) const; |
| |
| // Returns the list of valid FRU addresses found on the given i2c bus. |
| // devices: Map of address to FRU data. |
| // skip_list: List of addresses to skip. |
| // root_found: List of addresses found at root bus. |
| absl::flat_hash_set<size_t> FindI2cEeproms( |
| int i2cBus, const std::shared_ptr<DeviceMap>& devices, |
| absl::string_view root_dir, |
| const absl::flat_hash_set<size_t>& root_blocked_addresses, |
| absl::flat_hash_set<size_t>& root_found_addresses) const; |
| |
| std::string root_dir_; |
| bool deterministic_scan_ = false; |
| std::unique_ptr<deterministic_bmc::I2cWalkerInterface> uhmm_i2c_walker_; |
| uhmm::I2cRoot i2c_root_; |
| I2cSysfs i2c_sysfs_; |
| const absl::flat_hash_map<size_t, std::optional<absl::flat_hash_set<size_t>>> |
| bus_block_list_; |
| ecclesia::SysIoctl sys_ioctl_; |
| std::unique_ptr<ecclesia::SmbusAccessInterface> smbus_access_; |
| ecclesia::Clock* clock_ = ecclesia::Clock::RealClock(); |
| std::vector<uint32_t> extra_fru_scan_addresses_; |
| absl::flat_hash_set<size_t> extra_fru_scan_addresses_set_; |
| }; |
| |
| } // namespace milotic_tlbmc |
| |
| #endif // THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_HAL_FRU_SCANNER_I2C_H_ |