diff --git a/sonic_platform_base/sonic_xcvr/api/public/cmis.py b/sonic_platform_base/sonic_xcvr/api/public/cmis.py index ad9765620..8ca244a02 100644 --- a/sonic_platform_base/sonic_xcvr/api/public/cmis.py +++ b/sonic_platform_base/sonic_xcvr/api/public/cmis.py @@ -1147,6 +1147,11 @@ def set_loopback_mode(self, loopback_mode, lane_mask = 0xff): media_input_support = loopback_capability['media_side_input_loopback_supported'] media_output_support = loopback_capability['media_side_output_loopback_supported'] + if lane_mask != 0xff: + if any([loopback_capability['per_lane_host_loopback_supported'] is False and 'host' in loopback_mode, + loopback_capability['per_lane_media_loopback_supported'] is False and 'media' in loopback_mode]): + return False + if 'none' in loopback_mode: if loopback_mode == 'none': status_host_input = self.xcvr_eeprom.write(consts.HOST_INPUT_LOOPBACK, 0) @@ -1167,6 +1172,11 @@ def set_loopback_mode(self, loopback_mode, lane_mask = 0xff): if loopback_mode == 'media-side-output-none': return self.xcvr_eeprom.write(consts.MEDIA_OUTPUT_LOOPBACK, media_output_val & ~lane_mask) else: + if loopback_capability['simultaneous_host_media_loopback_supported'] is False: + if any(['host' in loopback_mode and (media_input_val or media_output_val), + 'media' in loopback_mode and (host_input_val or host_output_val)]): + return False + if loopback_mode == 'host-side-input' and host_input_support: return self.xcvr_eeprom.write(consts.HOST_INPUT_LOOPBACK, host_input_val | lane_mask) diff --git a/tests/sonic_xcvr/test_cmis.py b/tests/sonic_xcvr/test_cmis.py index e1cc5c38c..eaac98703 100644 --- a/tests/sonic_xcvr/test_cmis.py +++ b/tests/sonic_xcvr/test_cmis.py @@ -1052,45 +1052,79 @@ def test_get_loopback_capability(self, mock_response, expected): result = self.api.get_loopback_capability() assert result == expected - @pytest.mark.parametrize("input_param, mock_response",[ - ('none', { + @pytest.mark.parametrize("input_param, mock_response, expected",[ + (['none',0x0f], { 'host_side_input_loopback_supported': True, 'host_side_output_loopback_supported': True, 'media_side_input_loopback_supported': True, - 'media_side_output_loopback_supported': True - }), - ('host-side-input', { + 'media_side_output_loopback_supported': True, + 'simultaneous_host_media_loopback_supported': True, + 'per_lane_host_loopback_supported': True, + 'per_lane_media_loopback_supported': True + }, True), + (['host-side-input', 0x0f], { 'host_side_input_loopback_supported': True, 'host_side_output_loopback_supported': True, 'media_side_input_loopback_supported': True, - 'media_side_output_loopback_supported': True - }), - ('host-side-output', { + 'media_side_output_loopback_supported': True, + 'simultaneous_host_media_loopback_supported': True, + 'per_lane_host_loopback_supported': True, + 'per_lane_media_loopback_supported': True + }, True), + (['host-side-output', 0x0f], { 'host_side_input_loopback_supported': True, 'host_side_output_loopback_supported': True, 'media_side_input_loopback_supported': True, - 'media_side_output_loopback_supported': True - }), - ('media-side-input', { + 'media_side_output_loopback_supported': True, + 'simultaneous_host_media_loopback_supported': False, + 'per_lane_host_loopback_supported': True, + 'per_lane_media_loopback_supported': True + }, False), + (['host-side-output', 0x0f], { 'host_side_input_loopback_supported': True, 'host_side_output_loopback_supported': True, 'media_side_input_loopback_supported': True, - 'media_side_output_loopback_supported': True - }), - ('media-side-output', { + 'media_side_output_loopback_supported': True, + 'simultaneous_host_media_loopback_supported': True, + 'per_lane_host_loopback_supported': False, + 'per_lane_media_loopback_supported': True + }, False), + (['media-side-input', 0x0f], { 'host_side_input_loopback_supported': True, 'host_side_output_loopback_supported': True, 'media_side_input_loopback_supported': True, - 'media_side_output_loopback_supported': True - }), - ( - 'none', None - ) - ]) - def test_set_loopback_mode(self, input_param, mock_response): + 'media_side_output_loopback_supported': True, + 'simultaneous_host_media_loopback_supported': True, + 'per_lane_host_loopback_supported': True, + 'per_lane_media_loopback_supported': True + }, True), + (['media-side-output', 0x0f], { + 'host_side_input_loopback_supported': True, + 'host_side_output_loopback_supported': True, + 'media_side_input_loopback_supported': True, + 'media_side_output_loopback_supported': True, + 'simultaneous_host_media_loopback_supported': False, + 'per_lane_host_loopback_supported': False, + 'per_lane_media_loopback_supported': False + }, False), + (['media-side-output', 0x0f], { + 'host_side_input_loopback_supported': False, + 'host_side_output_loopback_supported': False, + 'media_side_input_loopback_supported': False, + 'media_side_output_loopback_supported': False, + 'simultaneous_host_media_loopback_supported': True, + 'per_lane_host_loopback_supported': True, + 'per_lane_media_loopback_supported': True + }, False), + (['none', 0x0F], None, False) + ]) + def test_set_loopback_mode(self, input_param, mock_response, expected): self.api.get_loopback_capability = MagicMock() self.api.get_loopback_capability.return_value = mock_response - self.api.set_loopback_mode(input_param) + self.api.xcvr_eeprom.read = MagicMock() + self.api.xcvr_eeprom.read.side_effect = [0xf0,0,0xf0,0] + result = self.api.set_loopback_mode(input_param[0], input_param[1]) + assert result == expected @pytest.mark.parametrize("mock_response, expected",[ (