diff --git a/sonic-xcvrd/tests/test_xcvrd.py b/sonic-xcvrd/tests/test_xcvrd.py index e15f4574a..313a60023 100644 --- a/sonic-xcvrd/tests/test_xcvrd.py +++ b/sonic-xcvrd/tests/test_xcvrd.py @@ -796,14 +796,16 @@ def test_CmisManagerTask_task_worker(self, mock_chassis): 'module_media_interface_id': '400GBASE-DR4 (Cl 124)', 'media_lane_count': 4, 'host_lane_count': 8, - 'host_lane_assignment_options': 1 + 'host_lane_assignment_options': 1, + 'media_lane_assignment_options': 1 }, 2: { 'host_electrical_interface_id': '100GAUI-2 C2M (Annex 135G)', 'module_media_interface_id': '100G-FR/100GBASE-FR1 (Cl 140)', 'media_lane_count': 1, 'host_lane_count': 2, - 'host_lane_assignment_options': 85 + 'host_lane_assignment_options': 85, + 'media_lane_assignment_options': 15 } }) mock_xcvr_api.get_module_state = MagicMock(return_value='ModuleReady') diff --git a/sonic-xcvrd/xcvrd/xcvrd.py b/sonic-xcvrd/xcvrd/xcvrd.py index 79d8c4f2c..e052e4cc1 100644 --- a/sonic-xcvrd/xcvrd/xcvrd.py +++ b/sonic-xcvrd/xcvrd/xcvrd.py @@ -1132,6 +1132,45 @@ def get_cmis_host_lanes_mask(self, api, appl, host_lane_count, subport): return host_lanes_mask + def get_cmis_media_lanes_mask(self, api, appl, lport, subport): + """ + Retrieves mask of active media lanes based on appl, lport and subport + + Args: + api: + XcvrApi object + appl: + Integer, the transceiver-specific application code + lport: + String, logical port name + subport: + Integer, 1-based logical port number of the physical port after breakout + 0 means port is a non-breakout port + + Returns: + Integer, a mask of the active lanes on the media side + e.g. 0xf for lane 0, lane 1, lane 2 and lane 3. + """ + media_lanes_mask = 0 + media_lane_count = self.port_dict[lport]['media_lane_count'] + media_lane_assignment_option = self.port_dict[lport]['media_lane_assignment_options'] + + if appl < 1 or media_lane_count <= 0 or subport < 0: + self.log_error("Invalid input to get media lane mask - appl {} media_lane_count {} " + "lport {} subport {}!".format(appl, media_lane_count, lport, subport)) + return media_lanes_mask + + media_lane_start_bit = (media_lane_count * (0 if subport == 0 else subport - 1)) + if media_lane_assignment_option & (1 << media_lane_start_bit): + media_lanes_mask = ((1 << media_lane_count) - 1) << media_lane_start_bit + else: + self.log_error("Unable to find starting media lane - media_lane_assignment_option {}" + " media_lane_start_bit {} media_lane_count {} lport {} subport {} appl {}!".format( + media_lane_assignment_option, media_lane_start_bit, media_lane_count, + lport, subport, appl)) + + return media_lanes_mask + def is_cmis_application_update_required(self, api, app_new, host_lanes_mask): """ Check if the CMIS application update is required @@ -1515,13 +1554,28 @@ def task_worker(self): self.port_dict[lport]['cmis_state'] = self.CMIS_STATE_FAILED continue host_lanes_mask = self.port_dict[lport]['host_lanes_mask'] - self.log_notice("{}: Setting lanemask=0x{:x}".format(lport, host_lanes_mask)) + self.log_notice("{}: Setting host_lanemask=0x{:x}".format(lport, host_lanes_mask)) + + self.port_dict[lport]['media_lane_count'] = int(api.get_media_lane_count(appl)) + self.port_dict[lport]['media_lane_assignment_options'] = int(api.get_media_lane_assignment_option(appl)) + media_lane_count = self.port_dict[lport]['media_lane_count'] + media_lane_assignment_options = self.port_dict[lport]['media_lane_assignment_options'] + self.port_dict[lport]['media_lanes_mask'] = self.get_cmis_media_lanes_mask(api, + appl, lport, subport) + if self.port_dict[lport]['media_lanes_mask'] <= 0: + self.log_error("{}: Invalid media lane mask received - media_lane_count {} " + "media_lane_assignment_options {} lport{} subport {}" + " appl {}!".format(media_lane_count,media_lane_assignment_options,lport,subport,appl)) + self.port_dict[lport]['cmis_state'] = self.CMIS_STATE_FAILED + continue + media_lanes_mask = self.port_dict[lport]['media_lanes_mask'] + self.log_notice("{}: Setting media_lanemask=0x{:x}".format(lport, media_lanes_mask)) if self.port_dict[lport]['host_tx_ready'] != 'true' or \ self.port_dict[lport]['admin_status'] != 'up': self.log_notice("{} Forcing Tx laser OFF".format(lport)) # Force DataPath re-init - api.tx_disable_channel(host_lanes_mask, True) + api.tx_disable_channel(media_lanes_mask, True) self.port_dict[lport]['cmis_state'] = self.CMIS_STATE_READY continue # Configure the target output power if ZR module @@ -1556,7 +1610,8 @@ def task_worker(self): api.set_datapath_deinit(host_lanes_mask) # D.1.3 Software Configuration and Initialization - if not api.tx_disable_channel(host_lanes_mask, True): + media_lanes_mask = self.port_dict[lport]['media_lanes_mask'] + if not api.tx_disable_channel(media_lanes_mask, True): self.log_notice("{}: unable to turn off tx power with host_lanes_mask {}".format(lport, host_lanes_mask)) self.port_dict[lport]['cmis_retries'] = retries + 1 continue @@ -1637,7 +1692,8 @@ def task_worker(self): continue # Turn ON the laser - api.tx_disable_channel(host_lanes_mask, False) + media_lanes_mask = self.port_dict[lport]['media_lanes_mask'] + api.tx_disable_channel(media_lanes_mask, False) self.log_notice("{}: Turning ON tx power".format(lport)) self.port_dict[lport]['cmis_state'] = self.CMIS_STATE_DP_ACTIVATE elif state == self.CMIS_STATE_DP_ACTIVATE: