Skip to content

Commit aa32bef

Browse files
authored
CDB Refactor (#584)
Description Refactor existing CDB support for firmware management to make it more modular and fungible to add newer CDB support beyond firmware management support Motivation and Context The Scope of CDB support for CMIS optics is going beyond just supporting optics firmware download. Support for VCS control via CDB is newly added support with many more features in future to be added via CDB protocol. This needs a refactor of existing CDB code to make it more modular and fungible to add newer CDB support beyond firmware management support
1 parent f1c3907 commit aa32bef

File tree

18 files changed

+2261
-31
lines changed

18 files changed

+2261
-31
lines changed

sonic_platform_base/sonic_xcvr/api/public/c_cmis.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@
5555
})
5656

5757
class CCmisApi(CmisApi):
58-
def __init__(self, xcvr_eeprom):
59-
super(CCmisApi, self).__init__(xcvr_eeprom)
58+
def __init__(self, xcvr_eeprom, cdb):
59+
super(CCmisApi, self).__init__(xcvr_eeprom, cdb)
6060

6161
def _get_vdm_key_to_db_prefix_map(self):
6262
combined_map = {**CMIS_VDM_KEY_TO_DB_PREFIX_KEY_MAP, **C_CMIS_DELTA_VDM_KEY_TO_DB_PREFIX_KEY_MAP}

sonic_platform_base/sonic_xcvr/api/public/cmis.py

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,14 @@ def set_cache_enabled(cls, enabled: bool):
121121
"""
122122
cls.cache_enabled = bool(enabled)
123123

124-
def __init__(self, xcvr_eeprom):
124+
def __init__(self, xcvr_eeprom, cdb_fw_hdlr=None):
125125
super(CmisApi, self).__init__(xcvr_eeprom)
126126
self.vdm = CmisVdmApi(xcvr_eeprom) if not self.is_flat_memory() else None
127-
self.cdb = CmisCdbApi(xcvr_eeprom) if not self.is_flat_memory() else None
127+
self.cdb = CmisCdbApi(xcvr_eeprom) if self.is_cdb_supported() else None
128+
self.cdb_fw_hdlr = cdb_fw_hdlr if self.is_cdb_supported() else None
129+
130+
def get_cdb_fw_handler(self):
131+
return self.cdb_fw_hdlr
128132

129133
def _get_vdm_key_to_db_prefix_map(self):
130134
return CMIS_VDM_KEY_TO_DB_PREFIX_KEY_MAP
@@ -161,8 +165,8 @@ def _update_vdm_dict(self, dict_to_update, new_key, vdm_raw_dict, vdm_observable
161165
def freeze_vdm_stats(self):
162166
'''
163167
This function freeze all the vdm statistics reporting registers.
164-
When raised by the host, causes the module to freeze and hold all
165-
reported statistics reporting registers (minimum, maximum and
168+
When raised by the host, causes the module to freeze and hold all
169+
reported statistics reporting registers (minimum, maximum and
166170
average values)in Pages 24h-27h.
167171
168172
Returns True if the provision succeeds and False incase of failure.
@@ -180,9 +184,9 @@ def get_vdm_freeze_status(self):
180184
def unfreeze_vdm_stats(self):
181185
'''
182186
This function unfreeze all the vdm statistics reporting registers.
183-
When freeze is ceased by the host, releases the freeze request, allowing the
187+
When freeze is ceased by the host, releases the freeze request, allowing the
184188
reported minimum, maximum and average values to update again.
185-
189+
186190
Returns True if the provision succeeds and False incase of failure.
187191
'''
188192
return self.xcvr_eeprom.write(consts.VDM_CONTROL, VDM_UNFREEZE)
@@ -370,7 +374,7 @@ def get_transceiver_info_firmware_versions(self):
370374
( _, _, _, _, _, _, _, _, ActiveFirmware, InactiveFirmware) = result['result']
371375
except (ValueError, TypeError):
372376
return return_dict
373-
377+
374378
return_dict["active_firmware"] = ActiveFirmware
375379
return_dict["inactive_firmware"] = InactiveFirmware
376380
return return_dict
@@ -1067,10 +1071,10 @@ def get_media_lane_count(self, appl=1):
10671071
'''
10681072
if self.is_flat_memory():
10691073
return 0
1070-
1074+
10711075
if (appl <= 0):
10721076
return 0
1073-
1077+
10741078
appl_advt = self.get_application_advertisement()
10751079
return appl_advt[appl]['media_lane_count'] if len(appl_advt) >= appl else 0
10761080

@@ -1103,10 +1107,10 @@ def get_media_lane_assignment_option(self, appl=1):
11031107
'''
11041108
if self.is_flat_memory():
11051109
return 'N/A'
1106-
1110+
11071111
if (appl <= 0):
11081112
return 0
1109-
1113+
11101114
appl_advt = self.get_application_advertisement()
11111115
return appl_advt[appl]['media_lane_assignment_options'] if len(appl_advt) >= appl else 0
11121116

@@ -1605,6 +1609,22 @@ def set_loopback_mode(self, loopback_mode, lane_mask = 0xff, enable = False):
16051609
logger.error('Invalid loopback mode:%s, lane_mask:%#x', loopback_mode, lane_mask)
16061610
return False
16071611

1612+
def is_cdb_supported(self):
1613+
'''
1614+
This function returns whether CDB is supported
1615+
'''
1616+
if self.is_flat_memory():
1617+
return False
1618+
1619+
cdb_inst = self.xcvr_eeprom.read(consts.CDB_SUPPORT)
1620+
if cdb_inst is None:
1621+
return False
1622+
1623+
if cdb_inst == 1 or cdb_inst == 2:
1624+
return True
1625+
1626+
return False
1627+
16081628
def is_transceiver_vdm_supported(self):
16091629
'''
16101630
This function returns whether VDM is supported
@@ -2346,7 +2366,7 @@ def get_transceiver_vdm_real_value(self):
23462366
biasyq{lane_num} = FLOAT ; modulator bias yq in percentage
23472367
biasyp{lane_num} = FLOAT ; modulator bias yq in percentage
23482368
cdshort{lane_num} = FLOAT ; chromatic dispersion, high granularity, short link in ps/nm
2349-
cdlong{lane_num} = FLOAT ; chromatic dispersion, high granularity, long link in ps/nm
2369+
cdlong{lane_num} = FLOAT ; chromatic dispersion, high granularity, long link in ps/nm
23502370
dgd{lane_num} = FLOAT ; differential group delay in ps
23512371
sopmd{lane_num} = FLOAT ; second order polarization mode dispersion in ps^2
23522372
soproc{lane_num} = FLOAT ; state of polarization rate of change in krad/s
@@ -2375,7 +2395,7 @@ def get_transceiver_vdm_thresholds(self):
23752395
Returns:
23762396
A dict containing the following keys/values :
23772397
========================================================================
2378-
xxx refers to HALARM/LALARM/HWARN/LWARN threshold
2398+
xxx refers to HALARM/LALARM/HWARN/LWARN threshold
23792399
;Defines Transceiver VDM high/low alarm/warning threshold for a port
23802400
key = TRANSCEIVER_VDM_XXX_THRESHOLD|ifname ; information module VDM high/low alarm/warning threshold on port
23812401
; field = value
@@ -2698,7 +2718,7 @@ def decommission_all_datapaths(self):
26982718
name = "DP{}State".format(lane + 1)
26992719
if dp_state[name] != 'DataPathDeactivated':
27002720
return False
2701-
2721+
27022722
name = "ConfigStatusLane{}".format(lane + 1)
27032723
if config_state[name] != 'ConfigSuccess':
27042724
return False
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
"""
2+
cdb.py
3+
4+
CDB Command handler
5+
"""
6+
7+
import time
8+
from ..fields import cdb_consts
9+
from ..xcvr_eeprom import XcvrEeprom
10+
11+
class CdbCmdHandler(XcvrEeprom):
12+
def __init__(self, reader, writer, mem_map):
13+
super(CdbCmdHandler, self).__init__(reader, writer, mem_map)
14+
15+
def read_reply(self, cdb_cmd_id):
16+
"""
17+
Read a reply from the CDB
18+
"""
19+
cdb_cmd = self.mem_map.get_cdb_cmd(cdb_cmd_id)
20+
reply_field = cdb_cmd.get_reply_field()
21+
if reply_field is not None:
22+
return self.read(reply_field)
23+
return None
24+
25+
def write_cmd(self, cdb_cmd_id, payload=None):
26+
"""
27+
Write CDB command
28+
"""
29+
cdb_cmd = self.mem_map.get_cdb_cmd(cdb_cmd_id)
30+
if payload is not None:
31+
bytes = cdb_cmd.encode(payload)
32+
else:
33+
bytes = cdb_cmd.encode()
34+
# TODO Check the module capability CdbCommandTriggerMethod to write in single I2C transaction
35+
# Write the bytes starting from the 3rd byte(0x9F:130)
36+
self.writer(cdb_cmd.getaddr() + 2, len(bytes) - 2, bytes[2:])
37+
# Finally write the first two CMD bytes to trigger CDB processing
38+
return self.writer(cdb_cmd.getaddr(), 2, bytes[:2])
39+
40+
def write_epl_page(self, page, data):
41+
"""
42+
Write a page of data to the EPL page
43+
"""
44+
# Write the data to the specified page and offset
45+
assert len(data) <= cdb_consts.PAGE_SIZE, \
46+
"Data length exceeds page size"
47+
assert page >= cdb_consts.EPL_PAGE, \
48+
"Page number must be greater than or equal to 0xA0"
49+
return self.write_raw((page * cdb_consts.PAGE_SIZE) + 128, len(data), data)
50+
51+
52+
def wait_for_cdb_status(self, timeout=None):
53+
"""
54+
Wait for CDB status to be ready
55+
Returns False if failed to get the status
56+
True otherwise
57+
"""
58+
delay = 0
59+
if timeout is None:
60+
timeout = cdb_consts.CDB_MAX_ACCESS_HOLD_OFF_PERIOD + 5000 # 5 sec safety margin
61+
status = None
62+
63+
assert timeout > delay, "Timeout must be greater than delay"
64+
65+
while (delay < timeout):
66+
time.sleep(cdb_consts.CDB_MAX_CAPTURE_TIME / 1000)
67+
delay += cdb_consts.CDB_MAX_CAPTURE_TIME
68+
69+
status = self.read(cdb_consts.CDB1_CMD_STATUS)
70+
if (status is None) or \
71+
(True == status[cdb_consts.CDB1_IS_BUSY]):
72+
continue
73+
74+
if (True == status[cdb_consts.CDB1_HAS_FAILED]):
75+
break
76+
77+
if (False == status[cdb_consts.CDB1_IS_BUSY]) and \
78+
(False == status[cdb_consts.CDB1_HAS_FAILED]):
79+
break
80+
81+
if delay >= timeout or status is None:
82+
return [False, status]
83+
84+
return [True, status]
85+
86+
def send_cmd(self, cdb_cmd_id, payload=None, timeout=None):
87+
"""
88+
Send CDB command, wait for completion and check status
89+
"""
90+
# Write the command to the CDB
91+
if True != self.write_cmd(cdb_cmd_id, payload):
92+
print(f"Failed to write CDB command: {cdb_cmd_id}")
93+
return None
94+
95+
# Wait for the command to complete
96+
ret, status = self.wait_for_cdb_status(timeout)
97+
if not ret:
98+
print(f"CDB command: {cdb_cmd_id} failed to complete or read status")
99+
return None
100+
101+
is_busy = status[cdb_consts.CDB1_IS_BUSY]
102+
if True == is_busy:
103+
print(f"CDB command: {cdb_cmd_id} is busy with status: {status[cdb_consts.CDB1_STATUS]}")
104+
return False
105+
106+
is_failed = status[cdb_consts.CDB1_HAS_FAILED]
107+
if True == is_failed:
108+
print(f"CDB command: {cdb_cmd_id} failed with status: {status[cdb_consts.CDB1_STATUS]}")
109+
return False
110+
111+
return status[cdb_consts.CDB1_STATUS] == 0x1
112+
113+
def get_last_cmd_status(self):
114+
"""
115+
Get the status of the last CDB command
116+
Returns None if Module failed to reply to I2C command
117+
"""
118+
status = self.read(cdb_consts.CDB1_COMMAND_RESULT)
119+
return status
120+
121+
def write_lpl_block(self, blkaddr, blkdata):
122+
"""
123+
Write LPL block
124+
"""
125+
payload = {
126+
"blkaddr" : blkaddr,
127+
"blkdata" : blkdata
128+
}
129+
# Send the CDB write firmware LPL command
130+
if True != self.write_cmd(cdb_consts.CDB_WRITE_FIRMWARE_LPL_CMD, payload):
131+
status = self.get_last_cmd_status()
132+
print(f"Write LPL block status: {status}")
133+
134+
def write_epl_pages(self, blkdata):
135+
"""
136+
Write EPL pages starting from page 0xA0
137+
"""
138+
pages = len(blkdata) // cdb_consts.PAGE_SIZE
139+
assert pages <= cdb_consts.EPL_MAX_PAGES, "Data exceeds maximum number of EPL pages"
140+
141+
for page in range(pages):
142+
page_data = blkdata[page * cdb_consts.PAGE_SIZE : (page + 1) * cdb_consts.PAGE_SIZE]
143+
assert True == self.write_epl_page(page + cdb_consts.EPL_PAGE, page_data)
144+
145+
# Handle any remaining data that doesn't fit into a full page
146+
if len(blkdata) % cdb_consts.PAGE_SIZE != 0:
147+
remaining_data = blkdata[pages * cdb_consts.PAGE_SIZE:]
148+
assert True == self.write_epl_page(pages + cdb_consts.EPL_PAGE, remaining_data)
149+
150+
def write_epl_block(self, blkaddr, blkdata):
151+
"""
152+
Write EPL block
153+
"""
154+
payload = {
155+
"blkaddr" : blkaddr,
156+
"blkdata" : blkdata
157+
}
158+
159+
# Send the CDB write firmware EPL command
160+
return self.send_cmd(cdb_consts.CDB_WRITE_FIRMWARE_EPL_CMD, payload)

0 commit comments

Comments
 (0)