diff --git a/sonic_platform_base/sonic_xcvr/api/public/sff8636.py b/sonic_platform_base/sonic_xcvr/api/public/sff8636.py index 6d138e01d..c09f8ddab 100644 --- a/sonic_platform_base/sonic_xcvr/api/public/sff8636.py +++ b/sonic_platform_base/sonic_xcvr/api/public/sff8636.py @@ -12,6 +12,7 @@ class Sff8636Api(XcvrApi): NUM_CHANNELS = 4 + POWER_CLASS_PREFIX = "Power Class " def __init__(self, xcvr_eeprom): super(Sff8636Api, self).__init__(xcvr_eeprom) @@ -403,3 +404,46 @@ def get_lpmode(self): # Since typically optics come up by default set to high power, in this case, # power_override not being set, function will return high power mode. return power_set and power_override + + def get_power_class(self): + ''' + Retrieves power class of the module. + + Returns: + int: Power class of the module, -1 if it fails + ''' + power_class_str = self.xcvr_eeprom.read(consts.POWER_CLASS_FIELD) + power_class = -1 + + if power_class_str is None: + return power_class + if not power_class_str.startswith(self.POWER_CLASS_PREFIX): + return power_class + + prefix_len = len(self.POWER_CLASS_PREFIX) + power_class = int(power_class_str[prefix_len:prefix_len + 1]) + + return power_class + + def set_high_power_class(self, enable): + ''' + This function sets high power class for the module if needed. + It is only applicable for power class >= 5. + + Args: + enable (bool): True to enable high power class, False to disable + + Returns: + bool: True if the provision succeeds, False if it fails + ''' + power_class = self.get_power_class() + ret = True + + if power_class < 5: + return ret + elif power_class >= 8: + ret = self.xcvr_eeprom.write(consts.HIGH_POWER_CLASS_ENABLE_CLASS_8, enable) + else: # Power class 5, 6, 7 + ret = self.xcvr_eeprom.write(consts.HIGH_POWER_CLASS_ENABLE_CLASS_5_TO_7, enable) + + return ret diff --git a/sonic_platform_base/sonic_xcvr/api/xcvr_api.py b/sonic_platform_base/sonic_xcvr/api/xcvr_api.py index c49bf64f9..341a3ebaa 100644 --- a/sonic_platform_base/sonic_xcvr/api/xcvr_api.py +++ b/sonic_platform_base/sonic_xcvr/api/xcvr_api.py @@ -637,3 +637,14 @@ def get_error_description(self): """ raise NotImplementedError + def set_high_power_class(self, enable): + """ + This function sets high power class for the module if needed. + + Args: + enable (bool): True to enable high power class, False to disable + + Returns: + bool: True if the provision succeeds, False if it fails + """ + raise NotImplementedError diff --git a/sonic_platform_base/sonic_xcvr/fields/consts.py b/sonic_platform_base/sonic_xcvr/fields/consts.py index cca473b9a..d8f292c3a 100644 --- a/sonic_platform_base/sonic_xcvr/fields/consts.py +++ b/sonic_platform_base/sonic_xcvr/fields/consts.py @@ -104,6 +104,8 @@ POWER_CTRL_FIELD = "Power Control" POWER_OVERRIDE_FIELD = "Power Override" POWER_SET_FIELD = "Power Set" +HIGH_POWER_CLASS_ENABLE_CLASS_5_TO_7 = "High Power Class Enable (Class 5-7)" +HIGH_POWER_CLASS_ENABLE_CLASS_8 = "High Power Class Enable (Class 8)" # SFF-8636 diff --git a/sonic_platform_base/sonic_xcvr/mem_maps/public/sff8636.py b/sonic_platform_base/sonic_xcvr/mem_maps/public/sff8636.py index 2a9032877..f25e61116 100644 --- a/sonic_platform_base/sonic_xcvr/mem_maps/public/sff8636.py +++ b/sonic_platform_base/sonic_xcvr/mem_maps/public/sff8636.py @@ -128,6 +128,8 @@ def __init__(self, codes): self.POWER_CTRL = NumberRegField(consts.POWER_CTRL_FIELD, self.get_addr(0, 93), RegBitField(consts.POWER_OVERRIDE_FIELD, 0, ro=False), RegBitField(consts.POWER_SET_FIELD, 1, ro=False), + RegBitField(consts.HIGH_POWER_CLASS_ENABLE_CLASS_5_TO_7, 2, ro=False), + RegBitField(consts.HIGH_POWER_CLASS_ENABLE_CLASS_8, 3, ro=False), ro=False ) diff --git a/tests/sonic_xcvr/test_sff8636.py b/tests/sonic_xcvr/test_sff8636.py index 7a566bc2d..23ca92a99 100644 --- a/tests/sonic_xcvr/test_sff8636.py +++ b/tests/sonic_xcvr/test_sff8636.py @@ -156,6 +156,43 @@ def test_set_lpmode(self): self.api.get_power_override_support.return_value = False assert not self.api.set_lpmode(True) + def test_set_high_power_class(self): + with patch.object(self.api, 'get_power_class', new=MagicMock()) as mock_get_power_class, \ + patch.object(self.api, 'xcvr_eeprom', new=MagicMock()) as mock_eeprom: + + # Mock read method + mock_eeprom.read = MagicMock() + mock_get_power_class.return_value = 4 + + # Test low power class + mock_eeprom.read.return_value = 1 + assert self.api.set_high_power_class(True) + + # Test high power class 5-7 + mock_get_power_class.return_value = 5 + assert self.api.set_high_power_class(True) + + # Test high power class 8 + mock_get_power_class.return_value = 8 + assert self.api.set_high_power_class(True) + + # Test high power class disable + mock_get_power_class.return_value = 8 + assert self.api.set_high_power_class(False) + + def test_get_power_class(self): + with patch.object(self.api, 'xcvr_eeprom') as mock_eeprom: + mock_eeprom.read = MagicMock() + + mock_eeprom.read.return_value = "Power Class 1 Module (1.5W max.)" + assert self.api.get_power_class() == 1 + + mock_eeprom.read.return_value = "XYZ" + assert self.api.get_power_class() == -1 + + mock_eeprom.read.return_value = None + assert self.api.get_power_class() == -1 + @pytest.mark.parametrize("mock_response, expected",[ ( [