Store mac to eeprom enhancement
1. Add delay after write mac to eeprom before read back to verify.
Issue: Some eeprom has timing requirement to allow internal write cycle
to complete.
2. Make sure MAC address are written within one EEPROM page.
Issue: Block write rolls over back to start of same page. Use 8bytes as
page size. It works also on 16byte page device.
3. Add mac header and checksum for mac record.
Tested:
Write MAC and Read MAC commands complete successfully
ipmitool raw 0x30 0xa1 0x00 0x56 0xd5 0xa9 0x8a 0xbd x3e
ipmitool raw 0x30 0xa2 0x00
01 56 d5 a9 8a bd 3e
i2cdump to verify eeprom data
root@bmc-mac56d5a98abd3e:~# i2cdump -y 11 0x52
No size specified (using byte-data access)
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
e0: 40 56 d5 a9 8a bd 3e 67 40 56 d5 a9 8a bd 3e 67 @V????>g@V????>g
f0: 40 56 d5 a9 8a bd 3e 67 ff ff ff ff ff ff ff ff @V????>g........
Signed-off-by: Zhikui Ren <zhikui.ren@intel.com>
Change-Id: Ib62e274fe22ec5cbc134239efb06bb528178f601
diff --git a/src/manufacturingcommands.cpp b/src/manufacturingcommands.cpp
index c44aa70..15bfc7f 100644
--- a/src/manufacturingcommands.cpp
+++ b/src/manufacturingcommands.cpp
@@ -880,10 +880,26 @@
return false;
}
+static constexpr uint64_t fruEnd = 0xff;
+// write rolls over within current page, need to keep mac within a page
+static constexpr uint64_t fruPageSize = 0x8;
+// MAC record struct: HEADER, MAC DATA, CheckSum
+static constexpr uint64_t macRecordSize = maxEthSize + 2;
+static_assert(fruPageSize >= macRecordSize,
+ "macRecordSize greater than eeprom page size");
+static constexpr uint8_t macHeader = 0x40;
+// Calculate new checksum for fru info area
+static uint8_t calculateChecksum(std::vector<uint8_t>::const_iterator iter,
+ std::vector<uint8_t>::const_iterator end)
+{
+ constexpr int checksumMod = 256;
+ uint8_t sum = std::accumulate(iter, end, static_cast<uint8_t>(0));
+ return (checksumMod - sum) % checksumMod;
+}
+
bool readMacFromFru(ipmi::Context::ptr ctx, uint8_t macIndex,
std::array<uint8_t, maxEthSize>& ethData)
{
- constexpr uint64_t fruEnd = 0xff;
uint64_t macOffset = fruEnd;
uint64_t fruBus = 0;
uint64_t fruAddress = 0;
@@ -896,23 +912,31 @@
phosphor::logging::entry("ADDRESS=%d",
static_cast<uint8_t>(fruAddress)));
- macOffset += macIndex * maxEthSize;
- if ((macOffset + maxEthSize) > fruEnd)
+ if (macOffset % fruPageSize)
+ {
+ macOffset = (macOffset / fruPageSize + 1) * fruPageSize;
+ }
+ macOffset += macIndex * fruPageSize;
+ if ((macOffset + macRecordSize) > fruEnd)
{
phosphor::logging::log<phosphor::logging::level::ERR>(
"ERROR: read fru mac failed, offset invalid");
return false;
}
std::vector<uint8_t> writeData;
- writeData.push_back(static_cast<uint8_t>(macOffset & 0xff));
- std::vector<uint8_t> readBuf(maxEthSize);
+ writeData.push_back(static_cast<uint8_t>(macOffset));
+ std::vector<uint8_t> readBuf(macRecordSize);
std::string i2cBus = "/dev/i2c-" + std::to_string(fruBus);
ipmi::Cc retI2C =
ipmi::i2cWriteRead(i2cBus, fruAddress, writeData, readBuf);
if (retI2C == ipmi::ccSuccess)
{
- std::copy(readBuf.begin(), readBuf.end(), ethData.data());
- return true;
+ uint8_t cs = calculateChecksum(readBuf.cbegin(), readBuf.cend());
+ if (cs == 0)
+ {
+ std::copy(++readBuf.begin(), --readBuf.end(), ethData.data());
+ return true;
+ }
}
}
return false;
@@ -921,7 +945,6 @@
ipmi::Cc writeMacToFru(ipmi::Context::ptr ctx, uint8_t macIndex,
std::array<uint8_t, maxEthSize>& ethData)
{
- constexpr uint64_t fruEnd = 0xff;
uint64_t macOffset = fruEnd;
uint64_t fruBus = 0;
uint64_t fruAddress = 0;
@@ -934,33 +957,54 @@
phosphor::logging::entry("ADDRESS=%d",
static_cast<uint8_t>(fruAddress)));
- macOffset += macIndex * maxEthSize;
- if ((macOffset + maxEthSize) > fruEnd)
+ if (macOffset % fruPageSize)
+ {
+ macOffset = (macOffset / fruPageSize + 1) * fruPageSize;
+ }
+ macOffset += macIndex * fruPageSize;
+ if ((macOffset + macRecordSize) > fruEnd)
{
phosphor::logging::log<phosphor::logging::level::ERR>(
"ERROR: write mac fru failed, offset invalid.");
return ipmi::ccParmOutOfRange;
}
std::vector<uint8_t> writeData;
- writeData.push_back(static_cast<uint8_t>(macOffset & 0xff));
+ writeData.reserve(macRecordSize + 1); // include start location
+ writeData.push_back(static_cast<uint8_t>(macOffset));
+ writeData.push_back(macHeader);
std::for_each(ethData.cbegin(), ethData.cend(),
[&](uint8_t i) { writeData.push_back(i); });
+ uint8_t macCheckSum =
+ calculateChecksum(++writeData.cbegin(), writeData.cend());
+ writeData.push_back(macCheckSum);
std::string i2cBus = "/dev/i2c-" + std::to_string(fruBus);
std::vector<uint8_t> readBuf;
ipmi::Cc ret =
ipmi::i2cWriteRead(i2cBus, fruAddress, writeData, readBuf);
+
switch (ret)
{
case ipmi::ccSuccess:
// chip is write protected, if write is success but fails verify
writeData.resize(1);
- readBuf.resize(maxEthSize);
- if (ipmi::ccSuccess ==
- ipmi::i2cWriteRead(i2cBus, fruAddress, writeData, readBuf))
+ readBuf.resize(maxEthSize + 1); // include macHeader
+ // Wait for internal write cycle to complete
+ // example: ATMEL 24c0x chip has Twr spec as 5ms
+
+ // Ideally we want yield wait, but currently following code
+ // crash with "thread not supported"
+ // boost::asio::deadline_timer timer(
+ // boost::asio::get_associated_executor(ctx->yield),
+ // boost::posix_time::seconds(1));
+ // timer.async_wait(ctx->yield);
+ // use usleep as temp WA
+ usleep(5000);
+ if (ipmi::i2cWriteRead(i2cBus, fruAddress, writeData,
+ readBuf) == ipmi::ccSuccess)
{
if (std::equal(ethData.begin(), ethData.end(),
- readBuf.begin()))
+ ++readBuf.begin())) // skip macHeader
{
return ipmi::ccSuccess;
}