Skip to content

Commit 6f30c0f

Browse files
authored
Cdb fw upgrade (#308)
* [Cloudlight] QSFP-DD FW upgrade doesn't work (#257) - Description cdb1_chkstatus will crash when i2c NACK or timeout. - Motivation and Context I2C of transceiver might NACK or stretching when FW upgrade, assuming "None" means "CdbIsBusy" until timeout. * [Cloudlight] QSFP-DD FW upgrade doesn't work (#257) - Description Waiting a delay in "run_fw_image" to ensure it is really executed. Return a special package when get none in "get_module_fw_info". - Motivation and Context "run_fw_image" will be executed after a delay which according to run cmd, waiting the delay in "run_fw_image" to avoid aother cmd sent before it really executing. CDB cmds will maybe cause several seconds NACK or stretching on i2c bus depend on implementation of module vendor, handling this situation for compatible with different implementation. * [Cloudlight] QSFP-DD FW upgrade doesn't work (#257) - Description Using real length to replace fixed number in "block_write_epl" function. - Motivation and Context To avoid a wrong epl length used in module. * Update unit tests for cmis. Test : Creating "get_module_fw_info" test.
1 parent 208fe2f commit 6f30c0f

File tree

3 files changed

+31
-2
lines changed

3 files changed

+31
-2
lines changed

sonic_platform_base/sonic_xcvr/api/public/cmis.py

+4
Original file line numberDiff line numberDiff line change
@@ -1184,6 +1184,10 @@ def get_module_fw_info(self):
11841184

11851185
# get fw info (CMD 0100h)
11861186
rpllen, rpl_chkcode, rpl = self.cdb.get_fw_info()
1187+
# Interface NACK or timeout
1188+
if (rpllen is None) or (rpl_chkcode is None):
1189+
return {'status': False, 'info': "Interface fail", 'result': 0} # Return result 0 for distinguishing CDB is maybe in busy or failure.
1190+
11871191
# password issue
11881192
if self.cdb.cdb_chkcode(rpl) != rpl_chkcode:
11891193
string = 'Get module FW info: Need to enter password\n'

sonic_platform_base/sonic_xcvr/api/public/cmisCDB.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,12 @@ def cdb1_chkstatus(self):
121121
30h-3Fh=Custom
122122
'''
123123
status = self.xcvr_eeprom.read(consts.CDB1_STATUS)
124-
is_busy = bool((status >> 7) & 0x1)
124+
is_busy = bool(((0x80 if status is None else status) >> 7) & 0x1)
125125
cnt = 0
126126
while is_busy and cnt < MAX_WAIT:
127127
time.sleep(0.1)
128128
status = self.xcvr_eeprom.read(consts.CDB1_STATUS)
129-
is_busy = bool((status >> 7) & 0x1)
129+
is_busy = bool(((0x80 if status is None else status) >> 7) & 0x1)
130130
cnt += 1
131131
return status
132132

@@ -382,6 +382,8 @@ def block_write_epl(self, addr, data, autopaging_flag, writelength):
382382
cmd = bytearray(b'\x01\x04\x08\x00\x04\x00\x00\x00')
383383
addr_byte = struct.pack('>L',addr)
384384
cmd += addr_byte
385+
cmd[130-INIT_OFFSET] = (epl_len >> 8) & 0xff
386+
cmd[131-INIT_OFFSET] = epl_len & 0xff
385387
cmd[133-INIT_OFFSET] = self.cdb_chkcode(cmd)
386388
self.write_cdb(cmd)
387389
status = self.cdb1_chkstatus()
@@ -433,6 +435,7 @@ def run_fw_image(self, mode = 0x01):
433435
cmd[137-INIT_OFFSET] = mode
434436
cmd[138-INIT_OFFSET] = 2 # Delay to Reset 512 ms
435437
cmd[133-INIT_OFFSET] = self.cdb_chkcode(cmd)
438+
delay = int.from_bytes(cmd[138-INIT_OFFSET:138+2-INIT_OFFSET], byteorder='big') + 50 # Add few ms on setting time.
436439
self.write_cdb(cmd)
437440
status = self.cdb1_chkstatus()
438441
if (status != 0x1):
@@ -444,6 +447,7 @@ def run_fw_image(self, mode = 0x01):
444447
else:
445448
txt = 'Run firmware status: Success'
446449
logger.info(txt)
450+
time.sleep(delay/1000) # Wait "delay time" to avoid other cmd sent before "run_fw_image" start.
447451
return status
448452

449453
# Commit FW image

tests/sonic_xcvr/test_cmis.py

+21
Original file line numberDiff line numberDiff line change
@@ -996,6 +996,27 @@ def test_get_module_level_flag(self, mock_response, expected):
996996
result = self.api.get_module_level_flag()
997997
assert result == expected
998998

999+
@pytest.mark.parametrize("mock_response, expected", [
1000+
((128, 1, [0] * 128), {'status': True, 'info': "", 'result': 0}),
1001+
((None, 1, [0] * 128), {'status': False, 'info': "", 'result': 0}),
1002+
((128, None, [0] * 128), {'status': False, 'info': "", 'result': 0}),
1003+
((128, 0, [0] * 128), {'status': False, 'info': "", 'result': None}),
1004+
])
1005+
def test_get_module_fw_info(self, mock_response, expected):
1006+
self.api.cdb = MagicMock()
1007+
self.api.cdb.cdb_chkcode = MagicMock()
1008+
self.api.cdb.cdb_chkcode.return_value = 1
1009+
self.api.get_module_active_firmware = MagicMock()
1010+
self.api.get_module_active_firmware.return_value = "1.0"
1011+
self.api.get_module_inactive_firmware = MagicMock()
1012+
self.api.get_module_inactive_firmware.return_value = "1.1"
1013+
self.api.cdb.get_fw_info = MagicMock()
1014+
self.api.cdb.get_fw_info.return_value = mock_response
1015+
result = self.api.get_module_fw_info()
1016+
if result['status'] == False: # Check 'result' when 'status' == False for distinguishing error type.
1017+
assert result['result'] == expected['result']
1018+
assert result['status'] == expected['status']
1019+
9991020
@pytest.mark.parametrize("input_param, mock_response, expected", [
10001021
(1, 1, (True, 'Module FW run: Success\n')),
10011022
(1, 64, (False, 'Module FW run: Fail\nFW_run_status 64\n')),

0 commit comments

Comments
 (0)