Skip to content

Commit dba17c8

Browse files
authored
Firmware upgrade CLI support for QSFP-DD transceivers (#244)
* Changes to support CMIS firmware download CLI Signed-off-by: Prince George <[email protected]> * Address review comments
1 parent cd69212 commit dba17c8

File tree

4 files changed

+69
-121
lines changed

4 files changed

+69
-121
lines changed

sonic_platform_base/sonic_xcvr/api/public/cmis.py

+39-49
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ class CmisApi(XcvrApi):
2323

2424
def __init__(self, xcvr_eeprom):
2525
super(CmisApi, self).__init__(xcvr_eeprom)
26+
self.vdm = CmisVdmApi(xcvr_eeprom)
27+
self.cdb = CmisCdbApi(xcvr_eeprom)
2628

2729
def get_model(self):
2830
'''
@@ -684,13 +686,9 @@ def get_active_apsel_hostlane(self):
684686
'''
685687
This function returns the application select code that each host lane has
686688
'''
687-
apsel_dict = {}
688-
if self.is_flat_memory():
689-
for lane in range(1, self.NUM_CHANNELS+1):
690-
apsel_dict["%s%d" % (consts.ACTIVE_APSEL_HOSTLANE, lane)] = 'N/A'
691-
else:
692-
apsel_dict = self.xcvr_eeprom.read(consts.ACTIVE_APSEL_CODE)
693-
return apsel_dict
689+
if (self.is_flat_memory()):
690+
return {'{}{}'.format(consts.ACTIVE_APSEL_HOSTLANE, i) : 'N/A' for i in range(1, self.NUM_CHANNELS+1)}
691+
return self.xcvr_eeprom.read(consts.ACTIVE_APSEL_CODE)
694692

695693
def get_tx_config_power(self):
696694
'''
@@ -960,23 +958,10 @@ def set_loopback_mode(self, loopback_mode):
960958
else:
961959
return 'N/A'
962960

963-
964-
def get_cdb_api(self):
965-
self.cdb = CmisCdbApi(self.xcvr_eeprom)
966-
return self.cdb
967-
968-
def get_vdm_api(self):
969-
self.vdm = CmisVdmApi(self.xcvr_eeprom)
970-
return self.vdm
971-
972961
def get_vdm(self):
973962
'''
974963
This function returns all the VDM items, including real time monitor value, threholds and flags
975964
'''
976-
try:
977-
self.vdm
978-
except AttributeError:
979-
self.get_vdm_api()
980965
vdm = self.vdm.get_vdm_allpage() if not self.is_flat_memory() else {}
981966
return vdm
982967

@@ -1070,17 +1055,13 @@ def get_module_level_flag(self):
10701055
'custom_mon_flags': custom_mon_flags}
10711056
return module_flag
10721057

1073-
def get_module_fw_upgrade_feature(self, verbose = False):
1058+
def get_module_fw_mgmt_feature(self, verbose = False):
10741059
"""
10751060
This function obtains CDB features supported by the module from CDB command 0041h,
10761061
such as start header size, maximum block size, whether extended payload messaging
10771062
(page 0xA0 - 0xAF) or only local payload is supported. These features are important because
10781063
the following upgrade with depend on these parameters.
10791064
"""
1080-
try:
1081-
self.cdb
1082-
except AttributeError:
1083-
self.get_cdb_api()
10841065
txt = ''
10851066
# get fw upgrade features (CMD 0041h)
10861067
starttime = time.time()
@@ -1121,7 +1102,7 @@ def get_module_fw_upgrade_feature(self, verbose = False):
11211102
elapsedtime = time.time()-starttime
11221103
logger.info('Get module FW upgrade features time: %.2f s\n' %elapsedtime)
11231104
logger.info(txt)
1124-
return {'status': True, 'info': txt, 'result': (startLPLsize, maxblocksize, lplonly_flag, autopaging_flag, writelength)}
1105+
return {'status': True, 'info': txt, 'feature': (startLPLsize, maxblocksize, lplonly_flag, autopaging_flag, writelength)}
11251106

11261107
def get_module_fw_info(self):
11271108
"""
@@ -1131,14 +1112,8 @@ def get_module_fw_info(self):
11311112
Administrative Status: 1=committed, 0=uncommitted
11321113
Validity Status: 1 = invalid, 0 = valid
11331114
"""
1134-
try:
1135-
self.cdb
1136-
except AttributeError:
1137-
self.get_cdb_api()
11381115
txt = ''
11391116
# get fw info (CMD 0100h)
1140-
starttime = time.time()
1141-
txt += 'Get module FW info\n'
11421117
rpllen, rpl_chkcode, rpl = self.cdb.get_fw_info()
11431118
# password issue
11441119
if self.cdb.cdb_chkcode(rpl) != rpl_chkcode:
@@ -1172,6 +1147,10 @@ def get_module_fw_info(self):
11721147
ImageB = "N/A"
11731148
txt += 'Image B Version: %s\n' %ImageB
11741149

1150+
if rpllen > 77:
1151+
factory_image = '%d.%d.%d' % (rpl[74], rpl[75], ((rpl[76] << 8) | rpl[77]))
1152+
txt += 'Factory Image Version: %s\n' %factory_image
1153+
11751154
if ImageARunning == 1:
11761155
RunningImage = 'A'
11771156
elif ImageBRunning == 1:
@@ -1184,15 +1163,22 @@ def get_module_fw_info(self):
11841163
CommittedImage = 'B'
11851164
else:
11861165
CommittedImage = 'N/A'
1187-
txt += 'Running Image: %s; Committed Image: %s\n' %(RunningImage, CommittedImage)
1166+
txt += 'Running Image: %s\n' % (RunningImage)
1167+
txt += 'Committed Image: %s\n' % (CommittedImage)
1168+
txt += 'Active Firmware: {}\n'.format(self.get_module_active_firmware())
1169+
txt += 'Inactive Firmware: {}\n'.format(self.get_module_inactive_firmware())
11881170
else:
11891171
txt += 'Reply payload check code error\n'
11901172
return {'status': False, 'info': txt, 'result': None}
1191-
elapsedtime = time.time()-starttime
1192-
logger.info('Get module FW info time: %.2f s\n' %elapsedtime)
1193-
logger.info(txt)
11941173
return {'status': True, 'info': txt, 'result': (ImageA, ImageARunning, ImageACommitted, ImageAValid, ImageB, ImageBRunning, ImageBCommitted, ImageBValid)}
11951174

1175+
def cdb_run_firmware(self, mode = 0x01):
1176+
# run module FW (CMD 0109h)
1177+
return self.cdb.run_fw_image(mode)
1178+
1179+
def cdb_commit_firmware(self):
1180+
return self.cdb.commit_fw_image()
1181+
11961182
def module_fw_run(self, mode = 0x01):
11971183
"""
11981184
This command is used to start and run a selected image.
@@ -1209,10 +1195,6 @@ def module_fw_run(self, mode = 0x01):
12091195
This function returns True if firmware run successfully completes.
12101196
Otherwise it will return False.
12111197
"""
1212-
try:
1213-
self.cdb
1214-
except AttributeError:
1215-
self.get_cdb_api()
12161198
# run module FW (CMD 0109h)
12171199
txt = ''
12181200
starttime = time.time()
@@ -1244,10 +1226,6 @@ def module_fw_commit(self):
12441226
This function returns True if firmware commit successfully completes.
12451227
Otherwise it will return False.
12461228
"""
1247-
try:
1248-
self.cdb
1249-
except AttributeError:
1250-
self.get_cdb_api()
12511229
txt = ''
12521230
# commit module FW (CMD 010Ah)
12531231
starttime = time.time()
@@ -1271,6 +1249,22 @@ def module_fw_commit(self):
12711249
logger.info(txt)
12721250
return True, txt
12731251

1252+
def cdb_firmware_download_complete(self):
1253+
# complete FW download (CMD 0107h)
1254+
return self.cdb.validate_fw_image()
1255+
1256+
def cdb_start_firmware_download(self, startLPLsize, startdata, imagesize):
1257+
return self.cdb.start_fw_download(startLPLsize, bytearray(startdata), imagesize)
1258+
1259+
def cdb_lpl_block_write(self, address, data):
1260+
return self.cdb.block_write_lpl(address, data)
1261+
1262+
def cdb_epl_block_write(self, address, data, autopaging_flag, writelength):
1263+
return self.cdb.block_write_epl(address, data, autopaging_flag, writelength)
1264+
1265+
def cdb_enter_host_password(self, password):
1266+
return self.cdb.module_enter_password(password)
1267+
12741268
def module_fw_download(self, startLPLsize, maxblocksize, lplonly_flag, autopaging_flag, writelength, imagepath):
12751269
"""
12761270
This function performs the download of a firmware image to module eeprom
@@ -1289,10 +1283,6 @@ def module_fw_download(self, startLPLsize, maxblocksize, lplonly_flag, autopagin
12891283
12901284
This function returns True if download successfully completes. Otherwise it will return False where it fails.
12911285
"""
1292-
try:
1293-
self.cdb
1294-
except AttributeError:
1295-
self.get_cdb_api()
12961286
txt = ''
12971287
# start fw download (CMD 0101h)
12981288
starttime = time.time()
@@ -1399,7 +1389,7 @@ def module_fw_upgrade(self, imagepath):
13991389
_, _, _, _, _, _, _, _ = result['result']
14001390
except (ValueError, TypeError):
14011391
return result['status'], result['info']
1402-
result = self.get_module_fw_upgrade_feature()
1392+
result = self.get_module_fw_mgmt_feature()
14031393
try:
14041394
startLPLsize, maxblocksize, lplonly_flag, autopaging_flag, writelength = result['result']
14051395
except (ValueError, TypeError):

sonic_platform_base/sonic_xcvr/api/public/cmisCDB.py

+18-19
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def __init__(self, xcvr_eeprom):
2727
self.cdb_instance_supported = self.xcvr_eeprom.read(consts.CDB_SUPPORT)
2828
self.failed_status_dict = self.xcvr_eeprom.mem_map.codes.CDB_FAIL_STATUS
2929
assert self.cdb_instance_supported != 0
30-
30+
3131
def cdb1_chkflags(self):
3232
'''
3333
This function detects if there is datapath or module firmware fault.
@@ -64,14 +64,14 @@ def cdb1_chkflags(self):
6464
return False
6565
else:
6666
return True
67-
67+
6868
def cdb_chkcode(self, cmd):
6969
'''
7070
This function calculates and returns the checksum of a CDB command
7171
'''
7272
checksum = 0
7373
for byte in cmd:
74-
checksum += byte
74+
checksum += byte
7575
return 0xff - (checksum & 0xff)
7676

7777
def cdb1_chkstatus(self):
@@ -140,7 +140,7 @@ def write_cdb(self, cmd):
140140
def read_cdb(self):
141141
'''
142142
This function reads the reply of a CDB command from page 0x9f.
143-
It returns the reply message of a CDB command.
143+
It returns the reply message of a CDB command.
144144
rpllen is the length (number of bytes) of rpl
145145
rpl_chkcode is the check code of rpl and can be calculated by cdb_chkcode()
146146
rpl is the reply message.
@@ -162,7 +162,7 @@ def query_cdb_status(self):
162162
self.write_cdb(cmd)
163163
status = self.cdb1_chkstatus()
164164
if (status != 0x1):
165-
if status > 127:
165+
if status > 127:
166166
txt = 'Query CDB status: Busy'
167167
else:
168168
status_txt = self.failed_status_dict.get(status & 0x3f, "Unknown")
@@ -186,7 +186,7 @@ def module_enter_password(self, psw = 0x00001011):
186186
self.write_cdb(cmd)
187187
status = self.cdb1_chkstatus()
188188
if (status != 0x1):
189-
if status > 127:
189+
if status > 127:
190190
txt = 'Enter password status: Busy'
191191
else:
192192
status_txt = self.failed_status_dict.get(status & 0x3f, "Unknown")
@@ -206,7 +206,7 @@ def get_module_feature(self):
206206
self.write_cdb(cmd)
207207
status = self.cdb1_chkstatus()
208208
if (status != 0x1):
209-
if status > 127:
209+
if status > 127:
210210
txt = 'Get module feature status: Busy'
211211
else:
212212
status_txt = self.failed_status_dict.get(status & 0x3f, "Unknown")
@@ -227,7 +227,7 @@ def get_fw_management_features(self):
227227
self.write_cdb(cmd)
228228
status = self.cdb1_chkstatus()
229229
if (status != 0x1):
230-
if status > 127:
230+
if status > 127:
231231
txt = 'Get firmware management feature status: Busy'
232232
else:
233233
status_txt = self.failed_status_dict.get(status & 0x3f, "Unknown")
@@ -240,17 +240,16 @@ def get_fw_management_features(self):
240240
# Get FW info
241241
def get_fw_info(self):
242242
'''
243-
This command returns the firmware versions and firmware default running
243+
This command returns the firmware versions and firmware default running
244244
images that reside in the module
245245
It returns the reply message of this CDB command 0100h.
246246
'''
247-
# self.module_enter_password(0x00000000)
248247
cmd = bytearray(b'\x01\x00\x00\x00\x00\x00\x00\x00')
249248
cmd[133-INIT_OFFSET] = self.cdb_chkcode(cmd)
250249
self.write_cdb(cmd)
251250
status = self.cdb1_chkstatus()
252251
if (status != 0x1):
253-
if status > 127:
252+
if status > 127:
254253
txt = 'Get firmware info status: Busy'
255254
else:
256255
status_txt = self.failed_status_dict.get(status & 0x3f, "Unknown")
@@ -281,7 +280,7 @@ def start_fw_download(self, startLPLsize, header, imagesize):
281280
time.sleep(2)
282281
status = self.cdb1_chkstatus()
283282
if (status != 0x1):
284-
if status > 127:
283+
if status > 127:
285284
txt = 'Start firmware download status: Busy'
286285
else:
287286
status_txt = self.failed_status_dict.get(status & 0x3f, "Unknown")
@@ -304,7 +303,7 @@ def abort_fw_download(self):
304303
self.write_cdb(cmd)
305304
status = self.cdb1_chkstatus()
306305
if (status != 0x1):
307-
if status > 127:
306+
if status > 127:
308307
txt = 'Abort firmware download status: Busy'
309308
else:
310309
status_txt = self.failed_status_dict.get(status & 0x3f, "Unknown")
@@ -320,7 +319,7 @@ def block_write_lpl(self, addr, data):
320319
This command writes one block of the firmware image into the LPL
321320
It returns the status of CDB command 0103h
322321
'''
323-
# lpl_len includes 136-139, four bytes, data is 116-byte long.
322+
# lpl_len includes 136-139, four bytes, data is 116-byte long.
324323
lpl_len = len(data) + 4
325324
cmd = bytearray(b'\x01\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
326325
cmd[132-INIT_OFFSET] = lpl_len & 0xff
@@ -335,7 +334,7 @@ def block_write_lpl(self, addr, data):
335334
self.write_cdb(cmd)
336335
status = self.cdb1_chkstatus()
337336
if (status != 0x1):
338-
if status > 127:
337+
if status > 127:
339338
txt = 'LPL firmware download status: Busy'
340339
else:
341340
status_txt = self.failed_status_dict.get(status & 0x3f, "Unknown")
@@ -387,7 +386,7 @@ def block_write_epl(self, addr, data, autopaging_flag, writelength):
387386
self.write_cdb(cmd)
388387
status = self.cdb1_chkstatus()
389388
if (status != 0x1):
390-
if status > 127:
389+
if status > 127:
391390
txt = 'EPL firmware download status: Busy'
392391
else:
393392
status_txt = self.failed_status_dict.get(status & 0x3f, "Unknown")
@@ -409,7 +408,7 @@ def validate_fw_image(self):
409408
self.write_cdb(cmd)
410409
status = self.cdb1_chkstatus()
411410
if (status != 0x1):
412-
if status > 127:
411+
if status > 127:
413412
txt = 'Firmware download complete status: Busy'
414413
else:
415414
status_txt = self.failed_status_dict.get(status & 0x3f, "Unknown")
@@ -437,7 +436,7 @@ def run_fw_image(self, mode = 0x01):
437436
self.write_cdb(cmd)
438437
status = self.cdb1_chkstatus()
439438
if (status != 0x1):
440-
if status > 127:
439+
if status > 127:
441440
txt = 'Run firmware status: Busy'
442441
else:
443442
status_txt = self.failed_status_dict.get(status & 0x3f, "Unknown")
@@ -467,7 +466,7 @@ def commit_fw_image(self):
467466
self.write_cdb(cmd)
468467
status = self.cdb1_chkstatus()
469468
if (status != 0x1):
470-
if status > 127:
469+
if status > 127:
471470
txt = 'Commit firmware status: Busy'
472471
else:
473472
status_txt = self.failed_status_dict.get(status & 0x3f, "Unknown")

sonic_platform_base/sonic_xcvr/sfp_optoe_base.py

+10-1
Original file line numberDiff line numberDiff line change
@@ -139,13 +139,22 @@ def get_lpmode(self):
139139

140140
def set_lpmode(self, lpmode):
141141
"""
142-
This common API is applicable only for CMIS as Low Power mode can be controlled
142+
This common API is applicable only for CMIS as Low Power mode can be controlled
143143
via EEPROM registers.For other media types like QSFP28/QSFP+ etc., platform
144144
vendors has to implement accordingly.
145145
"""
146146
api = self.get_xcvr_api()
147147
return api.set_lp_mode(lpmode) if api is not None else None
148148

149+
def set_optoe_write_max(self, write_max):
150+
sys_path = self.get_eeprom_path()
151+
sys_path = sys_path.replace("eeprom", "write_max")
152+
try:
153+
with open(sys_path, mode='w') as f:
154+
f.write(str(write_max))
155+
except (OSError, IOError):
156+
pass
157+
149158
def read_eeprom(self, offset, num_bytes):
150159
try:
151160
with open(self.get_eeprom_path(), mode='rb', buffering=0) as f:

0 commit comments

Comments
 (0)