Prevent bus lockups in fru-device
Sometimes a bus can lock during scanning causing, not
allowing the fru-device to recover. Move the scanning
to an async-launch and give it a 5 second timer so that
it won't prevent startup of systems.
Tested-by: Found a system with a bus that locked during
i2c-detect -y <bus> and saw that this fixed
the issue
Change-Id: I87be33041b7dd30fcd38b155f28422c27d465a0b
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/src/FruDevice.cpp b/src/FruDevice.cpp
index 2a89c08..bb12c49 100644
--- a/src/FruDevice.cpp
+++ b/src/FruDevice.cpp
@@ -38,6 +38,7 @@
static size_t UNKNOWN_BUS_OBJECT_COUNT = 0;
constexpr size_t MAX_FRU_SIZE = 512;
constexpr size_t MAX_EEPROM_PAGE_INDEX = 255;
+constexpr size_t busTimeoutSeconds = 5;
const static constexpr char *BASEBOARD_FRU_LOCATION =
"/etc/fru/baseboard.fru.bin";
@@ -61,90 +62,102 @@
int get_bus_frus(int file, int first, int last, int bus,
std::shared_ptr<DeviceMap> devices)
{
- std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> block_data;
- for (int ii = first; ii <= last; ii++)
- {
- // Set slave address
- if (ioctl(file, I2C_SLAVE_FORCE, ii) < 0)
+ std::future<int> future = std::async(std::launch::async, [&]() {
+ std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> block_data;
+ for (int ii = first; ii <= last; ii++)
{
- std::cerr << "device at bus " << bus << "register " << ii
- << "busy\n";
- continue;
- }
- // probe
- else if (i2c_smbus_read_byte(file) < 0)
- {
- continue;
- }
- if (DEBUG)
- {
- std::cout << "something at bus " << bus << "addr " << ii << "\n";
- }
- if (i2c_smbus_read_i2c_block_data(file, 0x0, 0x8, block_data.data()) <
- 0)
- {
- std::cerr << "failed to read bus " << bus << " address " << ii
- << "\n";
- continue;
- }
- size_t sum = 0;
- for (int jj = 0; jj < 7; jj++)
- {
- sum += block_data[jj];
- }
- sum = (256 - sum) & 0xFF;
-
- // check the header checksum
- if (sum == block_data[7])
- {
- std::vector<char> device;
- device.insert(device.end(), block_data.begin(),
- block_data.begin() + 8);
-
- for (int jj = 1; jj <= FRU_AREAS.size(); jj++)
+ // Set slave address
+ if (ioctl(file, I2C_SLAVE_FORCE, ii) < 0)
{
- auto area_offset = device[jj];
- if (area_offset != 0)
- {
- area_offset *= 8;
- if (i2c_smbus_read_i2c_block_data(file, area_offset, 0x8,
- block_data.data()) < 0)
- {
- std::cerr << "failed to read bus " << bus << " address "
- << ii << "\n";
- return -1;
- }
- int length = block_data[1] * 8;
- device.insert(device.end(), block_data.begin(),
- block_data.begin() + 8);
- length -= 8;
- area_offset += 8;
+ std::cerr << "device at bus " << bus << "register " << ii
+ << "busy\n";
+ continue;
+ }
+ // probe
+ else if (i2c_smbus_read_byte(file) < 0)
+ {
+ continue;
+ }
- while (length > 0)
+ if (DEBUG)
+ {
+ std::cout << "something at bus " << bus << "addr " << ii
+ << "\n";
+ }
+ if (i2c_smbus_read_i2c_block_data(file, 0x0, 0x8,
+ block_data.data()) < 0)
+ {
+ std::cerr << "failed to read bus " << bus << " address " << ii
+ << "\n";
+ continue;
+ }
+ size_t sum = 0;
+ for (int jj = 0; jj < 7; jj++)
+ {
+ sum += block_data[jj];
+ }
+ sum = (256 - sum) & 0xFF;
+
+ // check the header checksum
+ if (sum == block_data[7])
+ {
+ std::vector<char> device;
+ device.insert(device.end(), block_data.begin(),
+ block_data.begin() + 8);
+
+ for (int jj = 1; jj <= FRU_AREAS.size(); jj++)
+ {
+ auto area_offset = device[jj];
+ if (area_offset != 0)
{
- auto to_get = std::min(0x20, length);
+ area_offset *= 8;
if (i2c_smbus_read_i2c_block_data(
- file, area_offset, to_get, block_data.data()) <
- 0)
+ file, area_offset, 0x8, block_data.data()) < 0)
{
std::cerr << "failed to read bus " << bus
<< " address " << ii << "\n";
return -1;
}
+ int length = block_data[1] * 8;
device.insert(device.end(), block_data.begin(),
- block_data.begin() + to_get);
- area_offset += to_get;
- length -= to_get;
+ block_data.begin() + 8);
+ length -= 8;
+ area_offset += 8;
+
+ while (length > 0)
+ {
+ auto to_get = std::min(0x20, length);
+ if (i2c_smbus_read_i2c_block_data(
+ file, area_offset, to_get,
+ block_data.data()) < 0)
+ {
+ std::cerr << "failed to read bus " << bus
+ << " address " << ii << "\n";
+ return -1;
+ }
+ device.insert(device.end(), block_data.begin(),
+ block_data.begin() + to_get);
+ area_offset += to_get;
+ length -= to_get;
+ }
}
}
+ devices->emplace(ii, device);
}
- (*devices).emplace(ii, device);
}
+ return 1;
+ });
+ std::future_status status =
+ future.wait_for(std::chrono::seconds(busTimeoutSeconds));
+ if (status == std::future_status::timeout)
+ {
+ std::cerr << "Error reading bus " << bus << "\n";
+ return -1;
}
- return 0;
+ return future.get();
}
static void FindI2CDevices(const std::vector<fs::path> &i2cBuses,