Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
'sonic_platform_base.sonic_xcvr.api.public',
'sonic_platform_base.sonic_xcvr.codes',
'sonic_platform_base.sonic_xcvr.codes.public',
'sonic_platform_base.sonic_xcvr.utils',
'sonic_platform_base.sonic_xcvr.api.credo',
'sonic_platform_base.sonic_xcvr.mem_maps.credo',
'sonic_platform_base.sonic_xcvr.codes.credo',
Expand Down
6 changes: 6 additions & 0 deletions sonic_platform_base/sfp_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -479,3 +479,9 @@ def get_xcvr_api(self):
if self._xcvr_api is None:
self.refresh_xcvr_api()
return self._xcvr_api

def remove_xcvr_api(self):
"""
Removes the cached XcvrApi so that the next get_xcvr_api() call will refresh it.
"""
self._xcvr_api = None
37 changes: 35 additions & 2 deletions sonic_platform_base/sonic_xcvr/api/public/cmis.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from .cmisVDM import CmisVdmApi
import time
from collections import defaultdict
from ...utils.cache import read_only_cached_api_return

logger = logging.getLogger(__name__)
logger.addHandler(logging.NullHandler())
Expand Down Expand Up @@ -82,6 +83,16 @@ class CmisApi(XcvrApi):
LowPwrRequestSW = 4
LowPwrAllowRequestHW = 6

# Default caching enabled; control via classmethod
cache_enabled = True

@classmethod
def set_cache_enabled(cls, enabled: bool):
"""
Set the cache_enabled flag to control read_only_cached_api_return behavior.
"""
cls.cache_enabled = bool(enabled)

def __init__(self, xcvr_eeprom):
super(CmisApi, self).__init__(xcvr_eeprom)
self.vdm = CmisVdmApi(xcvr_eeprom) if not self.is_flat_memory() else None
Expand Down Expand Up @@ -152,12 +163,14 @@ def get_vdm_unfreeze_status(self):
'''
return self.xcvr_eeprom.read(consts.VDM_UNFREEZE_DONE)

@read_only_cached_api_return
def get_manufacturer(self):
'''
This function returns the manufacturer of the module
'''
return self.xcvr_eeprom.read(consts.VENDOR_NAME_FIELD)

@read_only_cached_api_return
def get_model(self):
'''
This function returns the part number of the module
Expand All @@ -170,42 +183,49 @@ def get_cable_length_type(self):
'''
return "Length Cable Assembly(m)"

@read_only_cached_api_return
def get_cable_length(self):
'''
This function returns the cable length of the module
'''
return self.xcvr_eeprom.read(consts.LENGTH_ASSEMBLY_FIELD)

@read_only_cached_api_return
def get_vendor_rev(self):
'''
This function returns the revision level for part number provided by vendor
'''
return self.xcvr_eeprom.read(consts.VENDOR_REV_FIELD)

@read_only_cached_api_return
def get_serial(self):
'''
This function returns the serial number of the module
'''
return self.xcvr_eeprom.read(consts.VENDOR_SERIAL_NO_FIELD)

@read_only_cached_api_return
def get_module_type(self):
'''
This function returns the SFF8024Identifier (module type / form-factor). Table 4-1 in SFF-8024 Rev4.6
'''
return self.xcvr_eeprom.read(consts.ID_FIELD)

@read_only_cached_api_return
def get_module_type_abbreviation(self):
'''
This function returns the SFF8024Identifier (module type / form-factor). Table 4-1 in SFF-8024 Rev4.6
'''
return self.xcvr_eeprom.read(consts.ID_ABBRV_FIELD)

@read_only_cached_api_return
def get_connector_type(self):
'''
This function returns module connector. Table 4-3 in SFF-8024 Rev4.6
'''
return self.xcvr_eeprom.read(consts.CONNECTOR_FIELD)

@read_only_cached_api_return
def get_module_hardware_revision(self):
'''
This function returns the module hardware revision
Expand All @@ -217,6 +237,7 @@ def get_module_hardware_revision(self):
hw_rev = [str(num) for num in [hw_major_rev, hw_minor_rev]]
return '.'.join(hw_rev)

@read_only_cached_api_return
def get_cmis_rev(self):
'''
This function returns the CMIS version the module complies to
Expand Down Expand Up @@ -531,6 +552,7 @@ def is_copper(self):
media_intf = self.get_module_media_type()
return media_intf == "passive_copper_media_interface" if media_intf else None

@read_only_cached_api_return
def is_flat_memory(self):
return self.xcvr_eeprom.read(consts.FLAT_MEM_FIELD) is not False

Expand Down Expand Up @@ -802,6 +824,7 @@ def get_tx_los(self):
tx_los_final.append(bool(tx_los[key]))
return tx_los_final

@read_only_cached_api_return
def get_tx_disable_support(self):
return not self.is_flat_memory() and self.xcvr_eeprom.read(consts.TX_DISABLE_SUPPORT_FIELD)

Expand Down Expand Up @@ -873,6 +896,7 @@ def set_power_override(self, power_override, power_set):
def get_transceiver_thresholds_support(self):
return not self.is_flat_memory()

@read_only_cached_api_return
def get_lpmode_support(self):
power_class = self.xcvr_eeprom.read(consts.POWER_CLASS_FIELD)
if power_class is None:
Expand Down Expand Up @@ -914,13 +938,15 @@ def get_module_media_interface(self):
else:
return 'Unknown media interface'

@read_only_cached_api_return
def is_coherent_module(self):
'''
Returns True if the module follow C-CMIS spec, False otherwise
'''
mintf = self.get_module_media_interface()
return False if 'ZR' not in mintf else True

@read_only_cached_api_return
def get_datapath_init_duration(self):
'''
This function returns the duration of datapath init
Expand All @@ -933,6 +959,7 @@ def get_datapath_init_duration(self):
value = float(duration)
return value * DATAPATH_INIT_DURATION_MULTIPLIER if value <= DATAPATH_INIT_DURATION_OVERRIDE_THRESHOLD else value

@read_only_cached_api_return
def get_datapath_deinit_duration(self):
'''
This function returns the duration of datapath deinit
Expand All @@ -942,6 +969,7 @@ def get_datapath_deinit_duration(self):
duration = self.xcvr_eeprom.read(consts.DP_PATH_DEINIT_DURATION)
return float(duration) if duration is not None else 0

@read_only_cached_api_return
def get_datapath_tx_turnon_duration(self):
'''
This function returns the duration of datapath tx turnon
Expand All @@ -951,6 +979,7 @@ def get_datapath_tx_turnon_duration(self):
duration = self.xcvr_eeprom.read(consts.DP_TX_TURNON_DURATION)
return float(duration) if duration is not None else 0

@read_only_cached_api_return
def get_datapath_tx_turnoff_duration(self):
'''
This function returns the duration of datapath tx turnoff
Expand All @@ -960,6 +989,7 @@ def get_datapath_tx_turnoff_duration(self):
duration = self.xcvr_eeprom.read(consts.DP_TX_TURNOFF_DURATION)
return float(duration) if duration is not None else 0

@read_only_cached_api_return
def get_module_pwr_up_duration(self):
'''
This function returns the duration of module power up
Expand All @@ -969,6 +999,7 @@ def get_module_pwr_up_duration(self):
duration = self.xcvr_eeprom.read(consts.MODULE_PWRUP_DURATION)
return float(duration) if duration is not None else 0

@read_only_cached_api_return
def get_module_pwr_down_duration(self):
'''
This function returns the duration of module power down
Expand Down Expand Up @@ -1587,7 +1618,6 @@ def get_module_level_flag(self):
'aux2_low_alarm_flag': aux2_low_alarm_flag,
'aux2_high_warn_flag': aux2_high_warn_flag,
'aux2_low_warn_flag': aux2_low_warn_flag}

aux1_high_alarm_flag = bool((module_flag_byte2 >> 0) & 0x1)
aux1_low_alarm_flag = bool((module_flag_byte2 >> 1) & 0x1)
aux1_high_warn_flag = bool((module_flag_byte2 >> 2) & 0x1)
Expand Down Expand Up @@ -2670,6 +2700,7 @@ def get_datapath_deinit(self):
return None
return [bool(datapath_deinit & (1 << lane)) for lane in range(self.NUM_CHANNELS)]

@read_only_cached_api_return
def get_application_advertisement(self):
"""
Get the application advertisement of the CMIS transceiver
Expand Down Expand Up @@ -2699,6 +2730,8 @@ def get_application_advertisement(self):
logger.error('Failed to read APPLS_ADVT_FIELD_PAGE01: ' + str(e))
return ret

media_type = self.xcvr_eeprom.read(consts.MEDIA_TYPE_FIELD)
prefix = map.get(media_type)
for app in range(1, 16):
buf = {}

Expand All @@ -2708,7 +2741,6 @@ def get_application_advertisement(self):
continue
buf['host_electrical_interface_id'] = val

prefix = map.get(self.xcvr_eeprom.read(consts.MEDIA_TYPE_FIELD))
if prefix is None:
continue
key = "{}_{}".format(prefix, app)
Expand Down Expand Up @@ -3175,3 +3207,4 @@ def get_error_description(self):
return 'OK'

# TODO: other XcvrApi methods

Empty file modified sonic_platform_base/sonic_xcvr/mem_maps/public/cmis.py
100644 → 100755
Empty file.
1 change: 1 addition & 0 deletions sonic_platform_base/sonic_xcvr/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# utils package for transceiver common utilities
19 changes: 19 additions & 0 deletions sonic_platform_base/sonic_xcvr/utils/cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from collections import abc
import os

def read_only_cached_api_return(func):
"""Cache until func() returns a non-None, non-empty collections cache_value."""
cache_name = f'_{func.__name__}_cache'
def wrapper(self):
if not self.cache_enabled:
return func(self)
if not hasattr(self, cache_name):
cache_value = func(self)
setattr(self, cache_name, cache_value)
else:
cache_value = getattr(self, cache_name)
if cache_value is None or (isinstance(cache_value, abc.Iterable) and not cache_value):
cache_value = func(self)
setattr(self, cache_name, cache_value)
return cache_value
return wrapper
Loading
Loading