Skip to content

Commit

Permalink
Fix xcvrd to support 400G ZR optic (#293)
Browse files Browse the repository at this point in the history
* Fix xcvrd to support 400G ZR/DR optics

* Fix xcvrd to support 400G ZR/DR optics

* Revert changes in DomInfoUpdateTask::on_port_config_change

* Fix xcvrd test after modifying on_port_config_change

* Call get_datapath_init_duration to get the init expiration time.

* Address comments

1. Clean up comments.
2. Revert port breakout fix and corresponding test change.
3. Check deinit duration for deinit case
4. Check datapath init pending

* 1. Revert changes in on_port_update_event
2. check DpInitPending on module which supports CMIS 5.0
3. Specify sec in return value

* Add code coverage

* Add log for DpInit/DpDeinit duration
  • Loading branch information
abohanyang authored Oct 20, 2022
1 parent 23b6970 commit 4ea12cf
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 5 deletions.
13 changes: 13 additions & 0 deletions sonic-xcvrd/tests/test_xcvrd.py
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,19 @@ def test_CmisManagerTask_task_worker(self, mock_chassis):
mock_xcvr_api.get_tx_config_power = MagicMock(return_value=0)
mock_xcvr_api.get_laser_config_freq = MagicMock(return_value=0)
mock_xcvr_api.get_module_type_abbreviation = MagicMock(return_value='QSFP-DD')
mock_xcvr_api.get_datapath_init_duration = MagicMock(return_value=60000.0)
mock_xcvr_api.get_datapath_deinit_duration = MagicMock(return_value=600000.0)
mock_xcvr_api.get_cmis_rev = MagicMock(return_value='5.0')
mock_xcvr_api.get_dpinit_pending = MagicMock(return_value={
'DPInitPending1': True,
'DPInitPending2': True,
'DPInitPending3': True,
'DPInitPending4': True,
'DPInitPending5': True,
'DPInitPending6': True,
'DPInitPending7': True,
'DPInitPending8': True
})
mock_xcvr_api.get_application_advertisement = MagicMock(return_value={
1: {
'host_electrical_interface_id': '400GAUI-8 C2M (Annex 120E)',
Expand Down
51 changes: 46 additions & 5 deletions sonic-xcvrd/xcvrd/xcvrd.py
Original file line number Diff line number Diff line change
Expand Up @@ -1073,6 +1073,12 @@ def get_cmis_application_desired(self, api, channel, speed):

return (appl_code & 0xf)

def get_cmis_dp_init_duration_secs(self, api):
return api.get_datapath_init_duration()/1000

def get_cmis_dp_deinit_duration_secs(self, api):
return api.get_datapath_deinit_duration()/1000

def is_cmis_application_update_required(self, api, channel, speed):
"""
Check if the CMIS application update is required
Expand Down Expand Up @@ -1176,6 +1182,32 @@ def check_config_error(self, api, channel, states):

return done

def check_datapath_init_pending(self, api, channel):
"""
Check if the CMIS datapath init is pending
Args:
api:
XcvrApi object
channel:
Integer, a bitmask of the lanes on the host side
e.g. 0x5 for lane 0 and lane 2.
Returns:
Boolean, true if all lanes are pending datapath init, otherwise false
"""
pending = True
dpinit_pending_dict = api.get_dpinit_pending()
for lane in range(self.CMIS_NUM_CHANNELS):
if ((1 << lane) & channel) == 0:
continue
key = "DPInitPending{}".format(lane + 1)
if not dpinit_pending_dict[key]:
pending = False
break

return pending

def check_datapath_state(self, api, channel, states):
"""
Check if the CMIS datapath states are in the specified state
Expand Down Expand Up @@ -1458,7 +1490,9 @@ def task_worker(self):
# TODO: Make sure this doesn't impact other datapaths
api.set_lpmode(False)
self.port_dict[lport]['cmis_state'] = self.CMIS_STATE_AP_CONF
self.port_dict[lport]['cmis_expired'] = now + datetime.timedelta(seconds=self.CMIS_DEF_EXPIRED)
dpDeinitDuration = self.get_cmis_dp_deinit_duration_secs(api)
self.log_notice("{} DpDeinit duration {} secs".format(lport, dpDeinitDuration))
self.port_dict[lport]['cmis_expired'] = now + datetime.timedelta(seconds=dpDeinitDuration)
elif state == self.CMIS_STATE_AP_CONF:
# TODO: Use fine grained time when the CMIS memory map is available
if not self.check_module_state(api, ['ModuleReady']):
Expand Down Expand Up @@ -1494,8 +1528,14 @@ def task_worker(self):
self.force_cmis_reinit(lport, retries + 1)
continue

# TODO: Use fine grained time when the CMIS memory map is available
self.port_dict[lport]['cmis_expired'] = now + datetime.timedelta(seconds=self.CMIS_DEF_EXPIRED)
if getattr(api, 'get_cmis_rev', None):
# Check datapath init pending on module that supports CMIS 5.x
majorRev = int(api.get_cmis_rev().split('.')[0])
if majorRev >= 5 and not self.check_datapath_init_pending(api, host_lanes):
self.log_notice("{}: datapath init not pending".format(lport))
self.force_cmis_reinit(lport, retries + 1)
continue

self.port_dict[lport]['cmis_state'] = self.CMIS_STATE_DP_INIT
elif state == self.CMIS_STATE_DP_INIT:
if not self.check_config_error(api, host_lanes, ['ConfigSuccess']):
Expand All @@ -1515,8 +1555,9 @@ def task_worker(self):

# D.1.3 Software Configuration and Initialization
api.set_datapath_init(host_lanes)
# TODO: Use fine grained timeout when the CMIS memory map is available
self.port_dict[lport]['cmis_expired'] = now + datetime.timedelta(seconds=self.CMIS_DEF_EXPIRED)
dpInitDuration = self.get_cmis_dp_init_duration_secs(api)
self.log_notice("{} DpInit duration {} secs".format(lport, dpInitDuration))
self.port_dict[lport]['cmis_expired'] = now + datetime.timedelta(seconds=dpInitDuration)
self.port_dict[lport]['cmis_state'] = self.CMIS_STATE_DP_TXON
elif state == self.CMIS_STATE_DP_TXON:
if not self.check_datapath_state(api, host_lanes, ['DataPathInitialized']):
Expand Down

0 comments on commit 4ea12cf

Please sign in to comment.