From 2a8bfa61f21e2e1d39284ab966fba02048c1019f Mon Sep 17 00:00:00 2001 From: Dante Su Date: Thu, 2 Dec 2021 07:01:11 +0000 Subject: [PATCH 1/9] Rebased and squashed Signed-off-by: Dante Su --- sonic_platform_base/sfp_base.py | 14 + .../sonic_xcvr/api/public/cmis.py | 302 +++++++++++++++++- .../sonic_xcvr/api/public/cmisCDB.py | 2 +- .../sonic_xcvr/fields/consts.py | 7 + .../sonic_xcvr/fields/public/cmis.py | 59 ++++ .../sonic_xcvr/mem_maps/public/cmis.py | 14 + .../sonic_xcvr/sfp_optoe_base.py | 114 +++++++ tests/sonic_xcvr/test_cmis.py | 2 + 8 files changed, 510 insertions(+), 4 deletions(-) diff --git a/sonic_platform_base/sfp_base.py b/sonic_platform_base/sfp_base.py index d6e735487..e8bb29814 100644 --- a/sonic_platform_base/sfp_base.py +++ b/sonic_platform_base/sfp_base.py @@ -17,6 +17,12 @@ class SfpBase(device_base.DeviceBase): # Device type definition. Note, this is a constant. DEVICE_TYPE = "sfp" + # SFP port type. Please note this is the cage type rather than transceiver type. + SFP_PORT_TYPE_UNSPECIFIED = "UNSPECIFIED" + SFP_PORT_TYPE_SFP = "SFP" + SFP_PORT_TYPE_QSFP = "QSFP" + SFP_PORT_TYPE_QSFPDD = "QSFP_DD" + # Generic error types definition SFP_STATUS_INITIALIZING = 'Initializing' SFP_STATUS_OK = 'OK' @@ -59,6 +65,14 @@ def __init__(self): self._xcvr_api_factory = XcvrApiFactory(self.read_eeprom, self.write_eeprom) self._xcvr_api = None + def get_port_type(self): + """ + Retrieves the port/cage type of this SFP + Returns: + A string, the port/cage type of this SFP + """ + return self.SFP_PORT_TYPE_UNSPECIFIED + def get_num_thermals(self): """ Retrieves the number of thermals available on this SFP diff --git a/sonic_platform_base/sonic_xcvr/api/public/cmis.py b/sonic_platform_base/sonic_xcvr/api/public/cmis.py index d065f219d..8a0cbf195 100644 --- a/sonic_platform_base/sonic_xcvr/api/public/cmis.py +++ b/sonic_platform_base/sonic_xcvr/api/public/cmis.py @@ -8,7 +8,9 @@ from ...fields import consts from ..xcvr_api import XcvrApi +import ast import logging +from ...codes.public.cmis import CmisCodes from ...fields import consts from ..xcvr_api import XcvrApi from .cmisCDB import CmisCdbApi @@ -135,8 +137,7 @@ def get_transceiver_info(self): "specification_compliance": admin_info[consts.MEDIA_TYPE_FIELD], "vendor_date": admin_info[consts.VENDOR_DATE_FIELD], "vendor_oui": admin_info[consts.VENDOR_OUI_FIELD], - # TODO - "application_advertisement": "N/A", + "application_advertisement": admin_info.get(consts.APPLS_ADVT_FIELD, "N/A") } xcvr_info['host_electrical_interface'] = self.get_host_electrical_interface() xcvr_info['media_interface_code'] = self.get_module_media_interface() @@ -903,6 +904,9 @@ def set_lpmode(self, lpmode): lpmode_val = self.xcvr_eeprom.read(consts.MODULE_LEVEL_CONTROL) if lpmode_val is not None: + # Turn on software control mode + if self.xcvr_eeprom.read(consts.CMIS_MAJOR_REVISION) >= 4: + lpmode_val = lpmode_val & ~(1 << 6) # LowPwrAllowRequestHW if lpmode is True: lpmode_val = lpmode_val | (1 << 4) self.xcvr_eeprom.write(consts.MODULE_LEVEL_CONTROL, lpmode_val) @@ -914,7 +918,7 @@ def set_lpmode(self, lpmode): time.sleep(1) lpmode = self.xcvr_eeprom.read(consts.TRANS_MODULE_STATUS_FIELD) if lpmode is not None: - if lpmode.get('ModuleState') == 'ModuleReady': + if lpmode.get('ModuleState') in ['ModulePwrUp', 'ModuleReady']: return True return False return False @@ -1745,4 +1749,296 @@ def get_transceiver_loopback(self): for lane in range(1, self.NUM_CHANNELS+1): trans_loopback['host_input_loopback_lane%d' % lane] = 'N/A' return trans_loopback + + def set_datapath_init(self, host_lanemask): + """ + Put the datapath into the initialized state + + Args: + host_lanemask: Integer, a bitmask of the lanes on the system/host side + e.g. 0x5 for lane 0 and lane 2. + + Returns: + Boolean, true if success otherwise false + """ + cmis_major = self.xcvr_eeprom.read(consts.CMIS_MAJOR_REVISION) + data = self.xcvr_eeprom.read(consts.DATAPATH_DEINIT_FIELD) + for lane in range(self.NUM_CHANNELS): + if (1 << lane) & host_lanemask == 0: + continue + if cmis_major >= 4: # CMIS v4 onwards + data &= ~(1 << lane) + else: # CMIS v3 + data |= (1 << lane) + self.xcvr_eeprom.write(consts.DATAPATH_DEINIT_FIELD, data) + + def set_datapath_deinit(self, host_lanemask): + """ + Put the datapath into the de-initialized state + + Args: + host_lanemask: Integer, a bitmask of the lanes on the system/host side + e.g. 0x5 for lane 0 and lane 2. + + Returns: + Boolean, true if success otherwise false + """ + cmis_major = self.xcvr_eeprom.read(consts.CMIS_MAJOR_REVISION) + data = self.xcvr_eeprom.read(consts.DATAPATH_DEINIT_FIELD) + for lane in range(self.NUM_CHANNELS): + if (1 << lane) & host_lanemask == 0: + continue + if cmis_major >= 4: # CMIS v4 onwards + data |= (1 << lane) + else: # CMIS v3 + data &= ~(1 << lane) + self.xcvr_eeprom.write(consts.DATAPATH_DEINIT_FIELD, data) + + def get_host_speed(self, ifname): + """ + Get the port speed from the host interface name + + Args: + ifname: String, host interface name + + Returns: + Integer, the port speed if success otherwise 0 + """ + # see HOST_ELECTRICAL_INTERFACE of sff8024.py + speed = 0 + if '400G' in ifname: + speed = 400000 + elif '200G' in ifname: + speed = 200000 + elif '100G' in ifname or 'CAUI-4' in ifname: + speed = 100000 + elif '50G' in ifname or 'LAUI-2' in ifname: + speed = 50000 + elif '40G' in ifname or 'XLAUI' in ifname or 'XLPPI' in ifname: + speed = 40000 + elif '25G' in ifname: + speed = 25000 + elif '10G' in ifname or 'SFI' in ifname or 'XFI' in ifname: + speed = 10000 + elif '1000BASE' in ifname: + speed = 1000 + return speed + + def get_cmis_state(self): + """ + Get the CMIS states + + Returns: + Dictionary, the states of module, config error and datapath + """ + state = { + 'module_state': self.get_module_state(), + 'config_state': self.get_config_datapath_hostlane_status(), + 'datapath_state': self.get_datapath_state() + } + return state + + def get_cmis_application_selected(self, host_lane): + """ + Get the CMIS selected application code of a host lane + + Args: + host_lane: + Integer, the lane id on the host/system side + + Returns: + Integer, the transceiver-specific application code + """ + ap_code = 0 + if host_lane in range(self.NUM_CHANNELS) and not self.is_flat_memory(): + field = "{}_{}_{}".format(consts.STAGED_CTRL_APSEL_FIELD, 0, host_lane + 1) + ap_code = self.xcvr_eeprom.read(field) >> 4 + + return (ap_code & 0xf) + + def get_cmis_application_matched(self, host_speed, host_lanemask): + """ + Get the CMIS application code that matches the specified host side configurations + + Args: + host_speed: + Integer, the port speed of the host interface + host_lanemask: + Integer, a bitmask of the lanes on the host side + e.g. 0x5 for lane 0 and lane 2. + + Returns: + Integer, the transceiver-specific application code + """ + if host_speed == 0 or host_lanemask == 0: + return 0 + + host_lane_count = 0 + for lane in range(self.NUM_CHANNELS): + if (1 << lane) & host_lanemask == 0: + continue + host_lane_count += 1 + + appl_code = 0 + appl_dict = self.xcvr_eeprom.read(consts.APPLS_ADVT_FIELD) + if appl_dict is None or appl_dict.strip() in ["None", "{}", ""]: + return 0 + appl_dict = ast.literal_eval(appl_dict) + for c in appl_dict.keys(): + d = appl_dict[c] + if d.get('host_lane_count') != host_lane_count: + continue + if self.get_host_speed(d.get('host_electrical_interface_id')) != host_speed: + continue + appl_code = c + break + + return (appl_code & 0xf) + + def has_cmis_application_update(self, host_speed, host_lanemask): + """ + Check for CMIS application update and retrieve the new application code + + Args: + host_speed: + Integer, the port speed of the host interface + host_lanemask: + Integer, a bitmask of the lanes on the host side + e.g. 0x5 for lane 0 and lane 2. + + Returns: + (has_update, new_appl) + """ + if host_speed == 0 or host_lanemask == 0 or self.is_flat_memory(): + return (False, 1) + + app_new = self.get_cmis_application_matched(host_speed, host_lanemask) + if app_new != 1 or host_lanemask != (1 << self.NUM_CHANNELS) - 1: + logger.info("Non-default application is not supported") + return (False, 1) + + app_old = 0 + for lane in range(self.NUM_CHANNELS): + if (1 << lane) & host_lanemask == 0: + continue + if app_old == 0: + app_old = self.get_cmis_application_selected(lane) + elif app_old != self.get_cmis_application_selected(lane): + logger.info("Not all the lanes are in the same application mode") + logger.info("Forcing application update...") + return (True, app_new) + + if app_old == app_new: + skip = True + dp_state = self.get_datapath_state() + conf_state = self.get_config_datapath_hostlane_status() + for lane in range(self.NUM_CHANNELS): + if (1 << lane) & host_lanemask == 0: + continue + name = "DP{}State".format(lane + 1) + if dp_state[name] != CmisCodes.DATAPATH_STATE[4]: + skip = False + break + name = "ConfigStatusLane{}".format(lane + 1) + if conf_state[name] != CmisCodes.CONFIG_STATUS[1]: + skip = False + break + if skip: + return (False, app_old) + + return (True, app_new) + + def set_cmis_application_stop(self, host_lanemask): + """ + Deinitialize the datapath and turn off Tx power to the associated line lanes + + Args: + host_lanemask: + Integer, a bitmask of the lanes on the host side + e.g. 0x5 for lane 0 and lane 2. + + Returns: + Boolean, true if success otherwise false + """ + # D.2.2 Software Deinitialization + self.set_datapath_deinit(host_lanemask) + self.set_lpmode(True) + + # D.1.3 Software Configuration and Initialization + self.tx_disable_channel(host_lanemask, True) + self.set_lpmode(False) + return True + + def set_cmis_application_apsel(self, host_lanemask, appl_code): + """ + Update the selected application code to the specified host lanes + + Args: + host_lanemask: + Integer, a bitmask of the lanes on the host side + e.g. 0x5 for lane 0 and lane 2. + appl_code: + Integer, the desired application code + + Returns: + Boolean, true if success otherwise false + """ + # Update the application selection + for lane in range(self.NUM_CHANNELS): + if (1 << lane) & host_lanemask == 0: + continue + addr = "{}_{}_{}".format(consts.STAGED_CTRL_APSEL_FIELD, 0, lane + 1) + data = appl_code << 4 + self.xcvr_eeprom.write(addr, data) + + # Apply DataPathInit + return self.xcvr_eeprom.write("%s_%d" % (consts.STAGED_CTRL_APPLY_DPINIT_FIELD, 0), host_lanemask) + + def set_cmis_application_start(self, host_lanemask): + """ + Initialize the datapath associated with the specified host lanes, while the Tx power + state of the line side will not be updated. + + Args: + host_lanemask: + Integer, a bitmask of the lanes on the host side + e.g. 0x5 for lane 0 and lane 2. + + Returns: + Boolean, true if success otherwise false + """ + return self.set_datapath_init(host_lanemask) + + def set_cmis_application_txon(self, host_lanemask): + """ + Turn on Tx power of the lanes on the line side associated with the specified host lanes + + Args: + host_lanemask: + Integer, a bitmask of the lanes on the host side + e.g. 0x5 for lane 0 and lane 2. + + Returns: + Boolean, true if success otherwise false + """ + self.tx_disable_channel(host_lanemask, False) + + def get_error_description(self): + dp_state = self.get_datapath_state() + conf_state = self.get_config_datapath_hostlane_status() + for lane in range(self.NUM_CHANNELS): + name = "DP{}State".format(lane + 1) + if dp_state[name] != CmisCodes.DATAPATH_STATE[4]: + return dp_state[name] + + name = "ConfigStatusLane{}".format(lane + 1) + if conf_state[name] != CmisCodes.CONFIG_STATUS[1]: + return conf_state[name] + + state = self.get_module_state() + if state != CmisCodes.MODULE_STATE[3]: + return state + + return None + # TODO: other XcvrApi methods diff --git a/sonic_platform_base/sonic_xcvr/api/public/cmisCDB.py b/sonic_platform_base/sonic_xcvr/api/public/cmisCDB.py index ad321ad30..c3a9c1e15 100644 --- a/sonic_platform_base/sonic_xcvr/api/public/cmisCDB.py +++ b/sonic_platform_base/sonic_xcvr/api/public/cmisCDB.py @@ -26,7 +26,7 @@ def __init__(self, xcvr_eeprom): super(CmisCdbApi, self).__init__(xcvr_eeprom) self.cdb_instance_supported = self.xcvr_eeprom.read(consts.CDB_SUPPORT) self.failed_status_dict = self.xcvr_eeprom.mem_map.codes.CDB_FAIL_STATUS - assert self.cdb_instance_supported != 0 + #assert self.cdb_instance_supported != 0 def cdb1_chkflags(self): ''' diff --git a/sonic_platform_base/sonic_xcvr/fields/consts.py b/sonic_platform_base/sonic_xcvr/fields/consts.py index a675dddb1..bf8205d92 100644 --- a/sonic_platform_base/sonic_xcvr/fields/consts.py +++ b/sonic_platform_base/sonic_xcvr/fields/consts.py @@ -270,6 +270,7 @@ TRANS_CONFIG_FIELD = "TransceiverConfig" MODULE_LEVEL_CONTROL = "ModuleControl" +APPLS_ADVT_FIELD = "Applications Advertisement" CTRLS_ADVT_FIELD = "Supported Controls Advertisement" FLAGS_ADVT_FIELD = "Supported Flags Advertisement" PAGE_SUPPORT_ADVT_FIELD = "Supported Pages Advertisement" @@ -278,6 +279,7 @@ LANE_MON_ADVT_FIELD = "Supported Lane Monitor Advertisement" LANE_DATAPATH_CTRL_FIELD = "Lane Control and Data Path Control" LANE_DATAPATH_STATUS_FIELD = "Lane Status and Data Path Status" +DATAPATH_DEINIT_FIELD = "Data Path Deinit" LEN_MULT_FIELD = "LengthMultiplier" MAX_POWER_FIELD = "MaxPower" MGMT_CHAR_FIELD = "Management Characteristics" @@ -285,6 +287,11 @@ MODULE_CHAR_ADVT_FIELD = "Module Characteristics Advertising" +STAGED_CTRL_FIELD = "Staged Control Set" +STAGED_CTRL_APPLY_DPINIT_FIELD = "Staged Control Set Apply DataPathInit" +STAGED_CTRL_APPLY_IMMEDIATE_FIELD = "Staged Control Set Apply Immediate" +STAGED_CTRL_APSEL_FIELD = "Staged Control Set ApSel" + # C-CMIS # Module configuration support fields diff --git a/sonic_platform_base/sonic_xcvr/fields/public/cmis.py b/sonic_platform_base/sonic_xcvr/fields/public/cmis.py index 88806b1d5..271b1e00a 100644 --- a/sonic_platform_base/sonic_xcvr/fields/public/cmis.py +++ b/sonic_platform_base/sonic_xcvr/fields/public/cmis.py @@ -1,5 +1,7 @@ from ..xcvr_field import NumberRegField +from ..xcvr_field import RegField from .. import consts +from ...codes.public.sff8024 import Sff8024 class CableLenField(NumberRegField): def __init__(self, name, offset, *fields, **kwargs): @@ -11,3 +13,60 @@ def decode(self, raw_data, **decoded_deps): len_mult = decoded_deps.get(consts.LEN_MULT_FIELD) mult = 10 ** (len_mult - 1) return base_len * mult + +class ApplicationAdvertField(RegField): + """ + Interprets application advertising bytes as a string + """ + def __init__(self, name, offset, *fields, **kwargs): + super(ApplicationAdvertField, self).__init__(name, offset, *fields, **kwargs) + self.size = kwargs.get("size") + + def decode(self, raw_data, **decoded_deps): + media_dict = { + 1: Sff8024.NM_850_MEDIA_INTERFACE, + 2: Sff8024.SM_MEDIA_INTERFACE, + 3: Sff8024.PASSIVE_COPPER_MEDIA_INTERFACE, + 4: Sff8024.ACTIVE_CABLE_MEDIA_INTERFACE, + 5: Sff8024.BASE_T_MEDIA_INTERFACE + } + + # Select the media dictionary based on media type(i.e. BYTE 85) + media_if_dict = media_dict.get(raw_data[0]) + host_if_dict = Sff8024.HOST_ELECTRICAL_INTERFACE + + if media_if_dict is None: + return None + + idx = 1 + pos = 1 + dat = {} + while pos < self.size: + appl = { } + + code = raw_data[pos+0] + if code in [0x00, 0xff]: + break + if code in host_if_dict: + appl['host_electrical_interface_id'] = host_if_dict[code] + else: + appl['host_electrical_interface_id'] = 'Unknown' + + code = raw_data[pos+1] + if code in [0x00, 0xff]: + break + if code in media_if_dict: + appl['module_media_interface_id'] = media_if_dict[code] + else: + appl['module_media_interface_id'] = 'Unknown' + + appl['host_lane_count'] = raw_data[pos+2] >> 4 + appl['media_lane_count'] = raw_data[pos+2] & 0xf + appl['host_lane_assignment_options'] = raw_data[pos+3] + appl['media_lane_assignment_options'] = None + + dat[idx] = appl + idx += 1 + pos += 4 + + return str(dat) diff --git a/sonic_platform_base/sonic_xcvr/mem_maps/public/cmis.py b/sonic_platform_base/sonic_xcvr/mem_maps/public/cmis.py index 2586ee662..0f72f54e9 100644 --- a/sonic_platform_base/sonic_xcvr/mem_maps/public/cmis.py +++ b/sonic_platform_base/sonic_xcvr/mem_maps/public/cmis.py @@ -16,6 +16,7 @@ ) from ...fields import consts from ...fields.public.cmis import CableLenField +from ...fields.public.cmis import ApplicationAdvertField class CmisMemMap(XcvrMemMap): def __init__(self, codes): @@ -29,6 +30,7 @@ def __init__(self, codes): # Should contain ONLY Lower page fields self.ADMIN_INFO = RegGroupField(consts.ADMIN_INFO_FIELD, + ApplicationAdvertField(consts.APPLS_ADVT_FIELD, self.getaddr(0x0, 85), size=33), CodeRegField(consts.ID_FIELD, self.getaddr(0x0, 0), self.codes.XCVR_IDENTIFIERS), CodeRegField(consts.ID_ABBRV_FIELD, self.getaddr(0x0, 128), self.codes.XCVR_IDENTIFIER_ABBRV), StringRegField(consts.VENDOR_NAME_FIELD, self.getaddr(0x0, 129), size=16), @@ -170,6 +172,7 @@ def __init__(self, codes): ) self.LANE_DATAPATH_CTRL = RegGroupField(consts.LANE_DATAPATH_CTRL_FIELD, + NumberRegField(consts.DATAPATH_DEINIT_FIELD, self.getaddr(0x10, 128), ro=False), NumberRegField(consts.TX_DISABLE_FIELD, self.getaddr(0x10, 130), ro=False) ) @@ -365,6 +368,17 @@ def __init__(self, codes): NumberRegField(consts.CDB_RPL_LENGTH, self.getaddr(0x9f, 134), size=1, ro=False), NumberRegField(consts.CDB_RPL_CHKCODE, self.getaddr(0x9f, 135), size=1, ro=False), ) + + self.STAGED_CTRL = RegGroupField(consts.STAGED_CTRL_FIELD, + NumberRegField("%s_%d" % (consts.STAGED_CTRL_APPLY_DPINIT_FIELD, 0), + self.getaddr(0x10, 143), ro=False), + NumberRegField("%s_%d" % (consts.STAGED_CTRL_APPLY_IMMEDIATE_FIELD, 0), + self.getaddr(0x10, 144), ro=False), + *(NumberRegField("%s_%d_%d" % (consts.STAGED_CTRL_APSEL_FIELD, 0, lane), + self.getaddr(0x10, 144 + lane), ro=False) + for lane in range(1, 9)) + ) + # TODO: add remaining fields def getaddr(self, page, offset, page_size=128): diff --git a/sonic_platform_base/sonic_xcvr/sfp_optoe_base.py b/sonic_platform_base/sonic_xcvr/sfp_optoe_base.py index 829022456..e5323b045 100644 --- a/sonic_platform_base/sonic_xcvr/sfp_optoe_base.py +++ b/sonic_platform_base/sonic_xcvr/sfp_optoe_base.py @@ -187,3 +187,117 @@ def write_eeprom(self, offset, num_bytes, write_buffer): except (OSError, IOError): return False return True + + def get_lpmode(self): + api = self.get_xcvr_api() + return api.get_lpmode() if api is not None else False + + def set_lpmode(self, lpmode): + api = self.get_xcvr_api() + return api.set_lpmode(lpmode) if api is not None else False + + def get_module_state(self): + api = self.get_xcvr_api() + return api.get_module_state() if api is not None else None + + def get_error_description(self): + api = self.get_xcvr_api() + return api.get_error_description() if api is not None else None + + def is_flat_memory(self): + api = self.get_xcvr_api() + return api.is_flat_memory() if api is not None else True + + def get_cmis_state(self): + """ + Retrieve the CMIS transceiver states including ModuleState, DataPath and ConfigError + """ + api = self.get_xcvr_api() + return api.get_cmis_state() if api is not None else None + + def has_cmis_application_update(self, host_speed, host_lanes): + """ + Check for CMIS application update and the new application code + + Args: + host_speed: + Integer, the port speed of the host interface + host_lanes: + Integer List, a list of the 0-based lane indexes of the host interface + + Returns: + (updated, appl_code) + """ + api = self.get_xcvr_api() + if api is not None: + return api.has_cmis_application_update(host_speed, host_lanes) + return (False, 1) + + def set_cmis_application_stop(self, host_lanes): + """ + (Stage 1) Data Path Deinitialization Tx power disable + + Args: + host_lanes: + Integer List, a list of the 0-based lane indexes of the host interface + + Returns: + A boolean, True if successful, False if not + """ + ret = False + api = self.get_xcvr_api() + if api is not None: + ret = api.set_cmis_application_stop(host_lanes) + return ret + + def set_cmis_application_apsel(self, host_lanes, appl_code=1): + """ + (Stage 2) Update the application selection + + Args: + host_lanes: + Integer List, a list of the 0-based lane indexes of the host interface + appl_code: + Integer, the desired application code + + Returns: + A boolean, True if successful, False if not + """ + ret = False + api = self.get_xcvr_api() + if api is not None: + ret = api.set_cmis_application_apsel(host_lanes, appl_code) + return ret + + def set_cmis_application_start(self, host_lanes): + """ + (Stage 3) Initialize the new data path + + Args: + host_lanes: + Integer List, a list of the 0-based lane indexes of the host interface + + Returns: + A boolean, True if successful, False if not + """ + ret = False + api = self.get_xcvr_api() + if api is not None: + ret = api.set_cmis_application_start(host_lanes) + return ret + + def set_cmis_application_txon(self, host_lanes): + """ + (Stage 4) Initialize the new data path + Args: + host_lanes: + Integer List, a list of the 0-based lane indexes of the host interface + + Returns: + A boolean, True if successful, False if not + """ + ret = False + api = self.get_xcvr_api() + if api is not None: + ret = api.set_cmis_application_txon(host_lanes) + return ret diff --git a/tests/sonic_xcvr/test_cmis.py b/tests/sonic_xcvr/test_cmis.py index 2c0d730d3..881035154 100644 --- a/tests/sonic_xcvr/test_cmis.py +++ b/tests/sonic_xcvr/test_cmis.py @@ -1132,6 +1132,8 @@ def test_get_transceiver_info(self, mock_response, expected): self.api.get_module_media_type.return_value = mock_response[13] self.api.get_module_hardware_revision = MagicMock() self.api.get_module_hardware_revision.return_value = '0.0' + self.api.is_flat_memory = MagicMock() + self.api.is_flat_memory.return_value = False result = self.api.get_transceiver_info() assert result == expected From a1a01cda56a37425dac5e14433efb324a6939616 Mon Sep 17 00:00:00 2001 From: Dante Su Date: Thu, 2 Dec 2021 08:49:55 +0000 Subject: [PATCH 2/9] address review comments Signed-off-by: Dante Su --- sonic_platform_base/sfp_base.py | 14 ---- .../sonic_xcvr/fields/public/cmis.py | 1 - .../sonic_xcvr/sfp_optoe_base.py | 84 +++++++++++-------- 3 files changed, 50 insertions(+), 49 deletions(-) diff --git a/sonic_platform_base/sfp_base.py b/sonic_platform_base/sfp_base.py index e8bb29814..d6e735487 100644 --- a/sonic_platform_base/sfp_base.py +++ b/sonic_platform_base/sfp_base.py @@ -17,12 +17,6 @@ class SfpBase(device_base.DeviceBase): # Device type definition. Note, this is a constant. DEVICE_TYPE = "sfp" - # SFP port type. Please note this is the cage type rather than transceiver type. - SFP_PORT_TYPE_UNSPECIFIED = "UNSPECIFIED" - SFP_PORT_TYPE_SFP = "SFP" - SFP_PORT_TYPE_QSFP = "QSFP" - SFP_PORT_TYPE_QSFPDD = "QSFP_DD" - # Generic error types definition SFP_STATUS_INITIALIZING = 'Initializing' SFP_STATUS_OK = 'OK' @@ -65,14 +59,6 @@ def __init__(self): self._xcvr_api_factory = XcvrApiFactory(self.read_eeprom, self.write_eeprom) self._xcvr_api = None - def get_port_type(self): - """ - Retrieves the port/cage type of this SFP - Returns: - A string, the port/cage type of this SFP - """ - return self.SFP_PORT_TYPE_UNSPECIFIED - def get_num_thermals(self): """ Retrieves the number of thermals available on this SFP diff --git a/sonic_platform_base/sonic_xcvr/fields/public/cmis.py b/sonic_platform_base/sonic_xcvr/fields/public/cmis.py index 271b1e00a..bf8f06c6a 100644 --- a/sonic_platform_base/sonic_xcvr/fields/public/cmis.py +++ b/sonic_platform_base/sonic_xcvr/fields/public/cmis.py @@ -63,7 +63,6 @@ def decode(self, raw_data, **decoded_deps): appl['host_lane_count'] = raw_data[pos+2] >> 4 appl['media_lane_count'] = raw_data[pos+2] & 0xf appl['host_lane_assignment_options'] = raw_data[pos+3] - appl['media_lane_assignment_options'] = None dat[idx] = appl idx += 1 diff --git a/sonic_platform_base/sonic_xcvr/sfp_optoe_base.py b/sonic_platform_base/sonic_xcvr/sfp_optoe_base.py index e5323b045..3bf8f4989 100644 --- a/sonic_platform_base/sonic_xcvr/sfp_optoe_base.py +++ b/sonic_platform_base/sonic_xcvr/sfp_optoe_base.py @@ -196,15 +196,24 @@ def set_lpmode(self, lpmode): api = self.get_xcvr_api() return api.set_lpmode(lpmode) if api is not None else False - def get_module_state(self): - api = self.get_xcvr_api() - return api.get_module_state() if api is not None else None - def get_error_description(self): + ''' + Retrives the error descriptions of the SFP module + ''' api = self.get_xcvr_api() return api.get_error_description() if api is not None else None + def get_module_state(self): + ''' + This function returns the module state + ''' + api = self.get_xcvr_api() + return api.get_module_state() if api is not None else None + def is_flat_memory(self): + ''' + This function returns the memory type + ''' api = self.get_xcvr_api() return api.is_flat_memory() if api is not None else True @@ -215,89 +224,96 @@ def get_cmis_state(self): api = self.get_xcvr_api() return api.get_cmis_state() if api is not None else None - def has_cmis_application_update(self, host_speed, host_lanes): + def has_cmis_application_update(self, host_speed, host_lanemask): """ - Check for CMIS application update and the new application code + Check for CMIS application update and retrieve the new application code Args: host_speed: Integer, the port speed of the host interface - host_lanes: - Integer List, a list of the 0-based lane indexes of the host interface + host_lanemask: + Integer, a bitmask of the lanes on the host side + e.g. 0x5 for lane 0 and lane 2. Returns: - (updated, appl_code) + (has_update, new_appl) """ api = self.get_xcvr_api() if api is not None: - return api.has_cmis_application_update(host_speed, host_lanes) + return api.has_cmis_application_update(host_speed, host_lanemask) return (False, 1) - def set_cmis_application_stop(self, host_lanes): + def set_cmis_application_stop(self, host_lanemask): """ - (Stage 1) Data Path Deinitialization Tx power disable + Deinitialize the datapath and turn off Tx power to the associated line lanes Args: - host_lanes: - Integer List, a list of the 0-based lane indexes of the host interface + host_lanemask: + Integer, a bitmask of the lanes on the host side + e.g. 0x5 for lane 0 and lane 2. Returns: - A boolean, True if successful, False if not + Boolean, true if success otherwise false """ ret = False api = self.get_xcvr_api() if api is not None: - ret = api.set_cmis_application_stop(host_lanes) + ret = api.set_cmis_application_stop(host_lanemask) return ret - def set_cmis_application_apsel(self, host_lanes, appl_code=1): + def set_cmis_application_apsel(self, host_lanemask, appl_code): """ - (Stage 2) Update the application selection + Update the selected application code to the specified host lanes Args: - host_lanes: - Integer List, a list of the 0-based lane indexes of the host interface + host_lanemask: + Integer, a bitmask of the lanes on the host side + e.g. 0x5 for lane 0 and lane 2. appl_code: Integer, the desired application code Returns: - A boolean, True if successful, False if not + Boolean, true if success otherwise false """ ret = False api = self.get_xcvr_api() if api is not None: - ret = api.set_cmis_application_apsel(host_lanes, appl_code) + ret = api.set_cmis_application_apsel(host_lanemask, appl_code) return ret - def set_cmis_application_start(self, host_lanes): + def set_cmis_application_start(self, host_lanemask): """ - (Stage 3) Initialize the new data path + Initialize the datapath associated with the specified host lanes, while the Tx power + state of the line side will not be updated. Args: - host_lanes: - Integer List, a list of the 0-based lane indexes of the host interface + host_lanemask: + Integer, a bitmask of the lanes on the host side + e.g. 0x5 for lane 0 and lane 2. Returns: - A boolean, True if successful, False if not + Boolean, true if success otherwise false """ ret = False api = self.get_xcvr_api() if api is not None: - ret = api.set_cmis_application_start(host_lanes) + ret = api.set_cmis_application_start(host_lanemask) return ret - def set_cmis_application_txon(self, host_lanes): + def set_cmis_application_txon(self, host_lanemask): """ - (Stage 4) Initialize the new data path + Turn on Tx power of the lanes on the line side associated with the specified host lanes + Args: - host_lanes: - Integer List, a list of the 0-based lane indexes of the host interface + host_lanemask: + Integer, a bitmask of the lanes on the host side + e.g. 0x5 for lane 0 and lane 2. Returns: - A boolean, True if successful, False if not + Boolean, true if success otherwise false """ ret = False api = self.get_xcvr_api() if api is not None: - ret = api.set_cmis_application_txon(host_lanes) + ret = api.set_cmis_application_txon(host_lanemask) return ret From f53683d64532865be5b72ea10407910a1e9aab0f Mon Sep 17 00:00:00 2001 From: Dante Su Date: Thu, 2 Dec 2021 10:46:44 +0000 Subject: [PATCH 3/9] Fix LGTM warnings and address review comments Signed-off-by: Dante Su --- .../sonic_xcvr/api/public/cmis.py | 74 ++++--------- .../sonic_xcvr/sfp_optoe_base.py | 102 +++++++----------- 2 files changed, 59 insertions(+), 117 deletions(-) diff --git a/sonic_platform_base/sonic_xcvr/api/public/cmis.py b/sonic_platform_base/sonic_xcvr/api/public/cmis.py index 8a0cbf195..8948f5913 100644 --- a/sonic_platform_base/sonic_xcvr/api/public/cmis.py +++ b/sonic_platform_base/sonic_xcvr/api/public/cmis.py @@ -877,6 +877,22 @@ def reset_module(self, reset = False): else: return True + def reset(self): + """ + Reset SFP and return all user module settings to their default srate. + + Returns: + A boolean, True if successful, False if not + """ + mask = (1 << 3) + byte = self.xcvr_eeprom.read(consts.MODULE_LEVEL_CONTROL) + if self.xcvr_eeprom.write(consts.MODULE_LEVEL_CONTROL, mask | byte): + for retries in range(5): + time.sleep(1) + if self.get_module_state() != 'Unknown': + return True + return False + def get_lpmode(self): ''' Retrieves Low power module status @@ -1750,9 +1766,9 @@ def get_transceiver_loopback(self): trans_loopback['host_input_loopback_lane%d' % lane] = 'N/A' return trans_loopback - def set_datapath_init(self, host_lanemask): + def set_cmis_datapath_init(self, host_lanemask): """ - Put the datapath into the initialized state + Put the CMIS datapath into the initialized state Args: host_lanemask: Integer, a bitmask of the lanes on the system/host side @@ -1772,9 +1788,9 @@ def set_datapath_init(self, host_lanemask): data |= (1 << lane) self.xcvr_eeprom.write(consts.DATAPATH_DEINIT_FIELD, data) - def set_datapath_deinit(self, host_lanemask): + def set_cmis_datapath_deinit(self, host_lanemask): """ - Put the datapath into the de-initialized state + Put the CMIS datapath into the de-initialized state Args: host_lanemask: Integer, a bitmask of the lanes on the system/host side @@ -1948,27 +1964,6 @@ def has_cmis_application_update(self, host_speed, host_lanemask): return (True, app_new) - def set_cmis_application_stop(self, host_lanemask): - """ - Deinitialize the datapath and turn off Tx power to the associated line lanes - - Args: - host_lanemask: - Integer, a bitmask of the lanes on the host side - e.g. 0x5 for lane 0 and lane 2. - - Returns: - Boolean, true if success otherwise false - """ - # D.2.2 Software Deinitialization - self.set_datapath_deinit(host_lanemask) - self.set_lpmode(True) - - # D.1.3 Software Configuration and Initialization - self.tx_disable_channel(host_lanemask, True) - self.set_lpmode(False) - return True - def set_cmis_application_apsel(self, host_lanemask, appl_code): """ Update the selected application code to the specified host lanes @@ -1994,35 +1989,6 @@ def set_cmis_application_apsel(self, host_lanemask, appl_code): # Apply DataPathInit return self.xcvr_eeprom.write("%s_%d" % (consts.STAGED_CTRL_APPLY_DPINIT_FIELD, 0), host_lanemask) - def set_cmis_application_start(self, host_lanemask): - """ - Initialize the datapath associated with the specified host lanes, while the Tx power - state of the line side will not be updated. - - Args: - host_lanemask: - Integer, a bitmask of the lanes on the host side - e.g. 0x5 for lane 0 and lane 2. - - Returns: - Boolean, true if success otherwise false - """ - return self.set_datapath_init(host_lanemask) - - def set_cmis_application_txon(self, host_lanemask): - """ - Turn on Tx power of the lanes on the line side associated with the specified host lanes - - Args: - host_lanemask: - Integer, a bitmask of the lanes on the host side - e.g. 0x5 for lane 0 and lane 2. - - Returns: - Boolean, true if success otherwise false - """ - self.tx_disable_channel(host_lanemask, False) - def get_error_description(self): dp_state = self.get_datapath_state() conf_state = self.get_config_datapath_hostlane_status() diff --git a/sonic_platform_base/sonic_xcvr/sfp_optoe_base.py b/sonic_platform_base/sonic_xcvr/sfp_optoe_base.py index 3bf8f4989..677a6076a 100644 --- a/sonic_platform_base/sonic_xcvr/sfp_optoe_base.py +++ b/sonic_platform_base/sonic_xcvr/sfp_optoe_base.py @@ -188,27 +188,27 @@ def write_eeprom(self, offset, num_bytes, write_buffer): return False return True - def get_lpmode(self): - api = self.get_xcvr_api() - return api.get_lpmode() if api is not None else False + def reset(self): + """ + Reset SFP and return all user module settings to their default srate. - def set_lpmode(self, lpmode): + Returns: + A boolean, True if successful, False if not + """ api = self.get_xcvr_api() - return api.set_lpmode(lpmode) if api is not None else False + return api.reset() if api is not None else False def get_error_description(self): - ''' + """ Retrives the error descriptions of the SFP module - ''' - api = self.get_xcvr_api() - return api.get_error_description() if api is not None else None - def get_module_state(self): - ''' - This function returns the module state - ''' + Returns: + String that represents the current error descriptions of vendor specific errors + In case there are multiple errors, they should be joined by '|', + like: "Bad EEPROM|Unsupported cable" + """ api = self.get_xcvr_api() - return api.get_module_state() if api is not None else None + return api.get_error_description() if api is not None else None def is_flat_memory(self): ''' @@ -219,95 +219,71 @@ def is_flat_memory(self): def get_cmis_state(self): """ - Retrieve the CMIS transceiver states including ModuleState, DataPath and ConfigError - """ - api = self.get_xcvr_api() - return api.get_cmis_state() if api is not None else None - - def has_cmis_application_update(self, host_speed, host_lanemask): - """ - Check for CMIS application update and retrieve the new application code - - Args: - host_speed: - Integer, the port speed of the host interface - host_lanemask: - Integer, a bitmask of the lanes on the host side - e.g. 0x5 for lane 0 and lane 2. + Get the CMIS states Returns: - (has_update, new_appl) + Dictionary, the states of module, config error and datapath """ api = self.get_xcvr_api() - if api is not None: - return api.has_cmis_application_update(host_speed, host_lanemask) - return (False, 1) + return api.get_cmis_state() if api is not None else None - def set_cmis_application_stop(self, host_lanemask): + def set_cmis_datapath_init(self, host_lanemask): """ - Deinitialize the datapath and turn off Tx power to the associated line lanes + Put the CMIS datapath into the initialized state Args: - host_lanemask: - Integer, a bitmask of the lanes on the host side - e.g. 0x5 for lane 0 and lane 2. + host_lanemask: Integer, a bitmask of the lanes on the system/host side + e.g. 0x5 for lane 0 and lane 2. Returns: Boolean, true if success otherwise false """ - ret = False api = self.get_xcvr_api() - if api is not None: - ret = api.set_cmis_application_stop(host_lanemask) - return ret + return api.set_cmis_datapath_init(host_lanemask) if api is not None else False - def set_cmis_application_apsel(self, host_lanemask, appl_code): + def set_cmis_datapath_deinit(self, host_lanemask): """ - Update the selected application code to the specified host lanes + Put the CMIS datapath into the de-initialized state Args: - host_lanemask: - Integer, a bitmask of the lanes on the host side - e.g. 0x5 for lane 0 and lane 2. - appl_code: - Integer, the desired application code + host_lanemask: Integer, a bitmask of the lanes on the system/host side + e.g. 0x5 for lane 0 and lane 2. Returns: Boolean, true if success otherwise false """ - ret = False api = self.get_xcvr_api() - if api is not None: - ret = api.set_cmis_application_apsel(host_lanemask, appl_code) - return ret + return api.set_cmis_datapath_deinit(host_lanemask) if api is not None else False - def set_cmis_application_start(self, host_lanemask): + def has_cmis_application_update(self, host_speed, host_lanemask): """ - Initialize the datapath associated with the specified host lanes, while the Tx power - state of the line side will not be updated. + Check for CMIS application update and retrieve the new application code Args: + host_speed: + Integer, the port speed of the host interface host_lanemask: Integer, a bitmask of the lanes on the host side e.g. 0x5 for lane 0 and lane 2. Returns: - Boolean, true if success otherwise false + (has_update, new_appl) """ - ret = False api = self.get_xcvr_api() if api is not None: - ret = api.set_cmis_application_start(host_lanemask) - return ret + return api.has_cmis_application_update(host_speed, host_lanemask) + return (False, 1) - def set_cmis_application_txon(self, host_lanemask): + def set_cmis_application_apsel(self, host_lanemask, appl_code): """ - Turn on Tx power of the lanes on the line side associated with the specified host lanes + Update the selected application code to the specified host lanes Args: host_lanemask: Integer, a bitmask of the lanes on the host side e.g. 0x5 for lane 0 and lane 2. + appl_code: + Integer, the desired application code Returns: Boolean, true if success otherwise false @@ -315,5 +291,5 @@ def set_cmis_application_txon(self, host_lanemask): ret = False api = self.get_xcvr_api() if api is not None: - ret = api.set_cmis_application_txon(host_lanemask) + ret = api.set_cmis_application_apsel(host_lanemask, appl_code) return ret From dd0de8d3484596241a2983768840e9e09ca48e72 Mon Sep 17 00:00:00 2001 From: Dante Su Date: Fri, 3 Dec 2021 02:46:28 +0000 Subject: [PATCH 4/9] address review comments Signed-off-by: Dante Su --- .../sonic_xcvr/api/public/cmis.py | 257 +++++++----------- .../sonic_xcvr/fields/public/cmis.py | 57 ---- .../sonic_xcvr/mem_maps/public/cmis.py | 52 +++- .../sonic_xcvr/sfp_optoe_base.py | 86 +----- 4 files changed, 146 insertions(+), 306 deletions(-) diff --git a/sonic_platform_base/sonic_xcvr/api/public/cmis.py b/sonic_platform_base/sonic_xcvr/api/public/cmis.py index 8948f5913..362d6de14 100644 --- a/sonic_platform_base/sonic_xcvr/api/public/cmis.py +++ b/sonic_platform_base/sonic_xcvr/api/public/cmis.py @@ -8,9 +8,9 @@ from ...fields import consts from ..xcvr_api import XcvrApi -import ast import logging from ...codes.public.cmis import CmisCodes +from ...codes.public.sff8024 import Sff8024 from ...fields import consts from ..xcvr_api import XcvrApi from .cmisCDB import CmisCdbApi @@ -52,6 +52,12 @@ def get_module_type(self): ''' return self.xcvr_eeprom.read(consts.ID_FIELD) + 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) + def get_connector_type(self): ''' This function returns module connector. Table 4-3 in SFF-8024 Rev4.6 @@ -136,9 +142,10 @@ def get_transceiver_info(self): "nominal_bit_rate": 0, # Not supported "specification_compliance": admin_info[consts.MEDIA_TYPE_FIELD], "vendor_date": admin_info[consts.VENDOR_DATE_FIELD], - "vendor_oui": admin_info[consts.VENDOR_OUI_FIELD], - "application_advertisement": admin_info.get(consts.APPLS_ADVT_FIELD, "N/A") + "vendor_oui": admin_info[consts.VENDOR_OUI_FIELD] } + appl_advt = self.get_application_advertisement() + xcvr_info['application_advertisement'] = str(appl_advt) if len(appl_advt) > 0 else 'N/A' xcvr_info['host_electrical_interface'] = self.get_host_electrical_interface() xcvr_info['media_interface_code'] = self.get_module_media_interface() xcvr_info['host_lane_count'] = self.get_host_lane_count() @@ -879,14 +886,12 @@ def reset_module(self, reset = False): def reset(self): """ - Reset SFP and return all user module settings to their default srate. + Reset SFP and return all user module settings to their default state. Returns: A boolean, True if successful, False if not """ - mask = (1 << 3) - byte = self.xcvr_eeprom.read(consts.MODULE_LEVEL_CONTROL) - if self.xcvr_eeprom.write(consts.MODULE_LEVEL_CONTROL, mask | byte): + if self.reset_module(True): for retries in range(5): time.sleep(1) if self.get_module_state() != 'Unknown': @@ -934,7 +939,7 @@ def set_lpmode(self, lpmode): time.sleep(1) lpmode = self.xcvr_eeprom.read(consts.TRANS_MODULE_STATUS_FIELD) if lpmode is not None: - if lpmode.get('ModuleState') in ['ModulePwrUp', 'ModuleReady']: + if lpmode.get('ModuleState') == 'ModuleReady': return True return False return False @@ -1766,13 +1771,14 @@ def get_transceiver_loopback(self): trans_loopback['host_input_loopback_lane%d' % lane] = 'N/A' return trans_loopback - def set_cmis_datapath_init(self, host_lanemask): + def set_datapath_init(self, channel): """ Put the CMIS datapath into the initialized state Args: - host_lanemask: Integer, a bitmask of the lanes on the system/host side - e.g. 0x5 for lane 0 and lane 2. + channel: + Integer, a bitmask of the lanes on the host side + e.g. 0x5 for lane 0 and lane 2. Returns: Boolean, true if success otherwise false @@ -1780,7 +1786,7 @@ def set_cmis_datapath_init(self, host_lanemask): cmis_major = self.xcvr_eeprom.read(consts.CMIS_MAJOR_REVISION) data = self.xcvr_eeprom.read(consts.DATAPATH_DEINIT_FIELD) for lane in range(self.NUM_CHANNELS): - if (1 << lane) & host_lanemask == 0: + if ((1 << lane) & channel) == 0: continue if cmis_major >= 4: # CMIS v4 onwards data &= ~(1 << lane) @@ -1788,13 +1794,14 @@ def set_cmis_datapath_init(self, host_lanemask): data |= (1 << lane) self.xcvr_eeprom.write(consts.DATAPATH_DEINIT_FIELD, data) - def set_cmis_datapath_deinit(self, host_lanemask): + def set_datapath_deinit(self, channel): """ Put the CMIS datapath into the de-initialized state Args: - host_lanemask: Integer, a bitmask of the lanes on the system/host side - e.g. 0x5 for lane 0 and lane 2. + channel: + Integer, a bitmask of the lanes on the host side + e.g. 0x5 for lane 0 and lane 2. Returns: Boolean, true if success otherwise false @@ -1802,7 +1809,7 @@ def set_cmis_datapath_deinit(self, host_lanemask): cmis_major = self.xcvr_eeprom.read(consts.CMIS_MAJOR_REVISION) data = self.xcvr_eeprom.read(consts.DATAPATH_DEINIT_FIELD) for lane in range(self.NUM_CHANNELS): - if (1 << lane) & host_lanemask == 0: + if ((1 << lane) & channel) == 0: continue if cmis_major >= 4: # CMIS v4 onwards data |= (1 << lane) @@ -1810,166 +1817,86 @@ def set_cmis_datapath_deinit(self, host_lanemask): data &= ~(1 << lane) self.xcvr_eeprom.write(consts.DATAPATH_DEINIT_FIELD, data) - def get_host_speed(self, ifname): - """ - Get the port speed from the host interface name - - Args: - ifname: String, host interface name - - Returns: - Integer, the port speed if success otherwise 0 - """ - # see HOST_ELECTRICAL_INTERFACE of sff8024.py - speed = 0 - if '400G' in ifname: - speed = 400000 - elif '200G' in ifname: - speed = 200000 - elif '100G' in ifname or 'CAUI-4' in ifname: - speed = 100000 - elif '50G' in ifname or 'LAUI-2' in ifname: - speed = 50000 - elif '40G' in ifname or 'XLAUI' in ifname or 'XLPPI' in ifname: - speed = 40000 - elif '25G' in ifname: - speed = 25000 - elif '10G' in ifname or 'SFI' in ifname or 'XFI' in ifname: - speed = 10000 - elif '1000BASE' in ifname: - speed = 1000 - return speed - - def get_cmis_state(self): + def get_application_advertisement(self): """ - Get the CMIS states + Get the application advertisement of the CMIS transceiver Returns: - Dictionary, the states of module, config error and datapath + Dictionary, the application advertisement """ - state = { - 'module_state': self.get_module_state(), - 'config_state': self.get_config_datapath_hostlane_status(), - 'datapath_state': self.get_datapath_state() + map = { + Sff8024.MODULE_MEDIA_TYPE[1]: consts.MODULE_MEDIA_INTERFACE_850NM, + Sff8024.MODULE_MEDIA_TYPE[2]: consts.MODULE_MEDIA_INTERFACE_SM, + Sff8024.MODULE_MEDIA_TYPE[3]: consts.MODULE_MEDIA_INTERFACE_PASSIVE_COPPER, + Sff8024.MODULE_MEDIA_TYPE[4]: consts.MODULE_MEDIA_INTERFACE_ACTIVE_CABLE, + Sff8024.MODULE_MEDIA_TYPE[5]: consts.MODULE_MEDIA_INTERFACE_BASE_T } - return state - def get_cmis_application_selected(self, host_lane): + ret = {} + dic = self.xcvr_eeprom.read(consts.APPLS_ADVT_FIELD) + for app in range(1, 16): + buf = {} + + key = "{}_{}".format(consts.HOST_ELECTRICAL_INTERFACE, app) + val = dic.get(key) + if val in [None, 'Unknown', 'Undefined']: + break + buf['host_electrical_interface_id'] = val + + prefix = map.get(self.xcvr_eeprom.read(consts.MEDIA_TYPE_FIELD)) + if prefix is None: + break + key = "{}_{}".format(prefix, app) + val = dic.get(key) + if val in [None, 'Unknown', 'Undefined']: + break + buf['module_media_interface_id'] = val + + key = "{}_{}".format(consts.MEDIA_LANE_COUNT, app) + val = dic.get(key) + if val is None: + break + buf['media_lane_count'] = val + + key = "{}_{}".format(consts.HOST_LANE_COUNT, app) + val = dic.get(key) + if val is None: + break + buf['host_lane_count'] = val + + key = "{}_{}".format(consts.HOST_LANE_ASSIGNMENT_OPTION, app) + val = dic.get(key) + if val is None: + break + buf['host_lane_assignment_options'] = val + + ret[app] = buf + return ret + + def get_application(self, lane): """ Get the CMIS selected application code of a host lane Args: - host_lane: - Integer, the lane id on the host/system side + lane: + Integer, the zero-based lane id on the host side Returns: Integer, the transceiver-specific application code """ - ap_code = 0 - if host_lane in range(self.NUM_CHANNELS) and not self.is_flat_memory(): - field = "{}_{}_{}".format(consts.STAGED_CTRL_APSEL_FIELD, 0, host_lane + 1) - ap_code = self.xcvr_eeprom.read(field) >> 4 + appl = 0 + if lane in range(self.NUM_CHANNELS) and not self.is_flat_memory(): + name = "{}_{}_{}".format(consts.STAGED_CTRL_APSEL_FIELD, 0, lane + 1) + appl = self.xcvr_eeprom.read(name) >> 4 - return (ap_code & 0xf) + return (appl & 0xf) - def get_cmis_application_matched(self, host_speed, host_lanemask): + def set_application(self, channel, appl_code): """ - Get the CMIS application code that matches the specified host side configurations + Update the selected application code to the specified lanes on the host side Args: - host_speed: - Integer, the port speed of the host interface - host_lanemask: - Integer, a bitmask of the lanes on the host side - e.g. 0x5 for lane 0 and lane 2. - - Returns: - Integer, the transceiver-specific application code - """ - if host_speed == 0 or host_lanemask == 0: - return 0 - - host_lane_count = 0 - for lane in range(self.NUM_CHANNELS): - if (1 << lane) & host_lanemask == 0: - continue - host_lane_count += 1 - - appl_code = 0 - appl_dict = self.xcvr_eeprom.read(consts.APPLS_ADVT_FIELD) - if appl_dict is None or appl_dict.strip() in ["None", "{}", ""]: - return 0 - appl_dict = ast.literal_eval(appl_dict) - for c in appl_dict.keys(): - d = appl_dict[c] - if d.get('host_lane_count') != host_lane_count: - continue - if self.get_host_speed(d.get('host_electrical_interface_id')) != host_speed: - continue - appl_code = c - break - - return (appl_code & 0xf) - - def has_cmis_application_update(self, host_speed, host_lanemask): - """ - Check for CMIS application update and retrieve the new application code - - Args: - host_speed: - Integer, the port speed of the host interface - host_lanemask: - Integer, a bitmask of the lanes on the host side - e.g. 0x5 for lane 0 and lane 2. - - Returns: - (has_update, new_appl) - """ - if host_speed == 0 or host_lanemask == 0 or self.is_flat_memory(): - return (False, 1) - - app_new = self.get_cmis_application_matched(host_speed, host_lanemask) - if app_new != 1 or host_lanemask != (1 << self.NUM_CHANNELS) - 1: - logger.info("Non-default application is not supported") - return (False, 1) - - app_old = 0 - for lane in range(self.NUM_CHANNELS): - if (1 << lane) & host_lanemask == 0: - continue - if app_old == 0: - app_old = self.get_cmis_application_selected(lane) - elif app_old != self.get_cmis_application_selected(lane): - logger.info("Not all the lanes are in the same application mode") - logger.info("Forcing application update...") - return (True, app_new) - - if app_old == app_new: - skip = True - dp_state = self.get_datapath_state() - conf_state = self.get_config_datapath_hostlane_status() - for lane in range(self.NUM_CHANNELS): - if (1 << lane) & host_lanemask == 0: - continue - name = "DP{}State".format(lane + 1) - if dp_state[name] != CmisCodes.DATAPATH_STATE[4]: - skip = False - break - name = "ConfigStatusLane{}".format(lane + 1) - if conf_state[name] != CmisCodes.CONFIG_STATUS[1]: - skip = False - break - if skip: - return (False, app_old) - - return (True, app_new) - - def set_cmis_application_apsel(self, host_lanemask, appl_code): - """ - Update the selected application code to the specified host lanes - - Args: - host_lanemask: + channel: Integer, a bitmask of the lanes on the host side e.g. 0x5 for lane 0 and lane 2. appl_code: @@ -1979,20 +1906,28 @@ def set_cmis_application_apsel(self, host_lanemask, appl_code): Boolean, true if success otherwise false """ # Update the application selection + lane_first = -1 for lane in range(self.NUM_CHANNELS): - if (1 << lane) & host_lanemask == 0: + if ((1 << lane) & channel) == 0: continue + if lane_first < 0: + lane_first = lane addr = "{}_{}_{}".format(consts.STAGED_CTRL_APSEL_FIELD, 0, lane + 1) - data = appl_code << 4 + data = (appl_code << 4) | (lane_first << 1) self.xcvr_eeprom.write(addr, data) # Apply DataPathInit - return self.xcvr_eeprom.write("%s_%d" % (consts.STAGED_CTRL_APPLY_DPINIT_FIELD, 0), host_lanemask) + return self.xcvr_eeprom.write("%s_%d" % (consts.STAGED_CTRL_APPLY_DPINIT_FIELD, 0), channel) + + def get_num_channels(self): + if self.get_module_type_abbreviation() == 'QSFP+C': + return 4 + return self.NUM_CHANNELS def get_error_description(self): dp_state = self.get_datapath_state() conf_state = self.get_config_datapath_hostlane_status() - for lane in range(self.NUM_CHANNELS): + for lane in range(self.get_num_channels()): name = "DP{}State".format(lane + 1) if dp_state[name] != CmisCodes.DATAPATH_STATE[4]: return dp_state[name] diff --git a/sonic_platform_base/sonic_xcvr/fields/public/cmis.py b/sonic_platform_base/sonic_xcvr/fields/public/cmis.py index bf8f06c6a..e949104c6 100644 --- a/sonic_platform_base/sonic_xcvr/fields/public/cmis.py +++ b/sonic_platform_base/sonic_xcvr/fields/public/cmis.py @@ -1,7 +1,6 @@ from ..xcvr_field import NumberRegField from ..xcvr_field import RegField from .. import consts -from ...codes.public.sff8024 import Sff8024 class CableLenField(NumberRegField): def __init__(self, name, offset, *fields, **kwargs): @@ -13,59 +12,3 @@ def decode(self, raw_data, **decoded_deps): len_mult = decoded_deps.get(consts.LEN_MULT_FIELD) mult = 10 ** (len_mult - 1) return base_len * mult - -class ApplicationAdvertField(RegField): - """ - Interprets application advertising bytes as a string - """ - def __init__(self, name, offset, *fields, **kwargs): - super(ApplicationAdvertField, self).__init__(name, offset, *fields, **kwargs) - self.size = kwargs.get("size") - - def decode(self, raw_data, **decoded_deps): - media_dict = { - 1: Sff8024.NM_850_MEDIA_INTERFACE, - 2: Sff8024.SM_MEDIA_INTERFACE, - 3: Sff8024.PASSIVE_COPPER_MEDIA_INTERFACE, - 4: Sff8024.ACTIVE_CABLE_MEDIA_INTERFACE, - 5: Sff8024.BASE_T_MEDIA_INTERFACE - } - - # Select the media dictionary based on media type(i.e. BYTE 85) - media_if_dict = media_dict.get(raw_data[0]) - host_if_dict = Sff8024.HOST_ELECTRICAL_INTERFACE - - if media_if_dict is None: - return None - - idx = 1 - pos = 1 - dat = {} - while pos < self.size: - appl = { } - - code = raw_data[pos+0] - if code in [0x00, 0xff]: - break - if code in host_if_dict: - appl['host_electrical_interface_id'] = host_if_dict[code] - else: - appl['host_electrical_interface_id'] = 'Unknown' - - code = raw_data[pos+1] - if code in [0x00, 0xff]: - break - if code in media_if_dict: - appl['module_media_interface_id'] = media_if_dict[code] - else: - appl['module_media_interface_id'] = 'Unknown' - - appl['host_lane_count'] = raw_data[pos+2] >> 4 - appl['media_lane_count'] = raw_data[pos+2] & 0xf - appl['host_lane_assignment_options'] = raw_data[pos+3] - - dat[idx] = appl - idx += 1 - pos += 4 - - return str(dat) diff --git a/sonic_platform_base/sonic_xcvr/mem_maps/public/cmis.py b/sonic_platform_base/sonic_xcvr/mem_maps/public/cmis.py index 0f72f54e9..28c607d99 100644 --- a/sonic_platform_base/sonic_xcvr/mem_maps/public/cmis.py +++ b/sonic_platform_base/sonic_xcvr/mem_maps/public/cmis.py @@ -16,7 +16,6 @@ ) from ...fields import consts from ...fields.public.cmis import CableLenField -from ...fields.public.cmis import ApplicationAdvertField class CmisMemMap(XcvrMemMap): def __init__(self, codes): @@ -30,7 +29,6 @@ def __init__(self, codes): # Should contain ONLY Lower page fields self.ADMIN_INFO = RegGroupField(consts.ADMIN_INFO_FIELD, - ApplicationAdvertField(consts.APPLS_ADVT_FIELD, self.getaddr(0x0, 85), size=33), CodeRegField(consts.ID_FIELD, self.getaddr(0x0, 0), self.codes.XCVR_IDENTIFIERS), CodeRegField(consts.ID_ABBRV_FIELD, self.getaddr(0x0, 128), self.codes.XCVR_IDENTIFIER_ABBRV), StringRegField(consts.VENDOR_NAME_FIELD, self.getaddr(0x0, 129), size=16), @@ -53,6 +51,54 @@ def __init__(self, codes): ), CodeRegField(consts.CONNECTOR_FIELD, self.getaddr(0x0, 203), self.codes.CONNECTORS), + + RegGroupField(consts.APPLS_ADVT_FIELD, + *(CodeRegField("%s_%d" % (consts.HOST_ELECTRICAL_INTERFACE, app), self.getaddr(0x0, 86 + 4 * (app - 1)), self.codes.HOST_ELECTRICAL_INTERFACE) + for app in range(1, 9)), + *(CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_850NM, app), self.getaddr(0x0, 87 + 4 * (app - 1)), self.codes.NM_850_MEDIA_INTERFACE) + for app in range(1, 9)), + *(CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_SM, app), self.getaddr(0x0, 87 + 4 * (app - 1)), self.codes.SM_MEDIA_INTERFACE) + for app in range(1, 9)), + *(CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_PASSIVE_COPPER, app), self.getaddr(0x0, 87 + 4 * (app - 1)), self.codes.PASSIVE_COPPER_MEDIA_INTERFACE) + for app in range(1, 9)), + *(CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_ACTIVE_CABLE, app), self.getaddr(0x0, 87 + 4 * (app - 1)), self.codes.ACTIVE_CABLE_MEDIA_INTERFACE) + for app in range(1, 9)), + *(CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_BASE_T, app), self.getaddr(0x0, 87 + 4 * (app - 1)), self.codes.BASE_T_MEDIA_INTERFACE) + for app in range(1, 9)), + *(NumberRegField("%s_%d" % (consts.MEDIA_LANE_COUNT, app), self.getaddr(0x0, 88 + 4 * (app - 1)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (0, 4))) + for app in range(1, 9)), + *(NumberRegField("%s_%d" % (consts.HOST_LANE_COUNT, app), self.getaddr(0x0, 88 + 4 * (app - 1)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (4, 8))) + for app in range(1, 9)), + *(NumberRegField("%s_%d" % (consts.HOST_LANE_ASSIGNMENT_OPTION, app), self.getaddr(0x0, 89 + 4 * (app - 1)), format="B", size=1) + for app in range(1, 9)), + + *(NumberRegField("%s_%d" % (consts.MEDIA_LANE_ASSIGNMENT_OPTION, app), self.getaddr(0x1, 176 + (app - 1)), format="B", size=1) + for app in range(1, 16)), + + *(CodeRegField("%s_%d" % (consts.HOST_ELECTRICAL_INTERFACE, app), self.getaddr(0x1, 223 + 4 * (app - 9)), self.codes.HOST_ELECTRICAL_INTERFACE) + for app in range(9, 16)), + *(CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_850NM, app), self.getaddr(0x1, 224 + 4 * (app - 9)), self.codes.NM_850_MEDIA_INTERFACE) + for app in range(9, 16)), + *(CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_SM, app), self.getaddr(0x1, 224 + 4 * (app - 9)), self.codes.SM_MEDIA_INTERFACE) + for app in range(9, 16)), + *(CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_PASSIVE_COPPER, app), self.getaddr(0x1, 224 + 4 * (app - 9)), self.codes.PASSIVE_COPPER_MEDIA_INTERFACE) + for app in range(9, 16)), + *(CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_ACTIVE_CABLE, app), self.getaddr(0x1, 224 + 4 * (app - 9)), self.codes.ACTIVE_CABLE_MEDIA_INTERFACE) + for app in range(9, 16)), + *(CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_BASE_T, app), self.getaddr(0x1, 224 + 4 * (app - 9)), self.codes.BASE_T_MEDIA_INTERFACE) + for app in range(9, 16)), + *(NumberRegField("%s_%d" % (consts.MEDIA_LANE_COUNT, app), self.getaddr(0x1, 225 + 4 * (app - 9)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (0, 4))) + for app in range(9, 16)), + *(NumberRegField("%s_%d" % (consts.HOST_LANE_COUNT, app), self.getaddr(0x1, 225 + 4 * (app - 9)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (4, 8))) + for app in range(9, 16)), + *(NumberRegField("%s_%d" % (consts.HOST_LANE_ASSIGNMENT_OPTION, app), self.getaddr(0x1, 226 + 4 * (app - 9)), format="B", size=1) + for app in range(9, 16)), + ), + CodeRegField(consts.HOST_ELECTRICAL_INTERFACE, self.getaddr(0x0, 86), self.codes.HOST_ELECTRICAL_INTERFACE), CodeRegField(consts.MEDIA_TYPE_FIELD, self.getaddr(0x0, 85), self.codes.MODULE_MEDIA_TYPE), CodeRegField(consts.MODULE_MEDIA_INTERFACE_850NM, self.getaddr(0x0, 87), self.codes.NM_850_MEDIA_INTERFACE), @@ -369,7 +415,7 @@ def __init__(self, codes): NumberRegField(consts.CDB_RPL_CHKCODE, self.getaddr(0x9f, 135), size=1, ro=False), ) - self.STAGED_CTRL = RegGroupField(consts.STAGED_CTRL_FIELD, + self.STAGED_CTRL0 = RegGroupField("%s_%d" % (consts.STAGED_CTRL_FIELD, 0), NumberRegField("%s_%d" % (consts.STAGED_CTRL_APPLY_DPINIT_FIELD, 0), self.getaddr(0x10, 143), ro=False), NumberRegField("%s_%d" % (consts.STAGED_CTRL_APPLY_IMMEDIATE_FIELD, 0), diff --git a/sonic_platform_base/sonic_xcvr/sfp_optoe_base.py b/sonic_platform_base/sonic_xcvr/sfp_optoe_base.py index 677a6076a..4bc62967b 100644 --- a/sonic_platform_base/sonic_xcvr/sfp_optoe_base.py +++ b/sonic_platform_base/sonic_xcvr/sfp_optoe_base.py @@ -190,7 +190,7 @@ def write_eeprom(self, offset, num_bytes, write_buffer): def reset(self): """ - Reset SFP and return all user module settings to their default srate. + Reset SFP and return all user module settings to their default state. Returns: A boolean, True if successful, False if not @@ -209,87 +209,3 @@ def get_error_description(self): """ api = self.get_xcvr_api() return api.get_error_description() if api is not None else None - - def is_flat_memory(self): - ''' - This function returns the memory type - ''' - api = self.get_xcvr_api() - return api.is_flat_memory() if api is not None else True - - def get_cmis_state(self): - """ - Get the CMIS states - - Returns: - Dictionary, the states of module, config error and datapath - """ - api = self.get_xcvr_api() - return api.get_cmis_state() if api is not None else None - - def set_cmis_datapath_init(self, host_lanemask): - """ - Put the CMIS datapath into the initialized state - - Args: - host_lanemask: Integer, a bitmask of the lanes on the system/host side - e.g. 0x5 for lane 0 and lane 2. - - Returns: - Boolean, true if success otherwise false - """ - api = self.get_xcvr_api() - return api.set_cmis_datapath_init(host_lanemask) if api is not None else False - - def set_cmis_datapath_deinit(self, host_lanemask): - """ - Put the CMIS datapath into the de-initialized state - - Args: - host_lanemask: Integer, a bitmask of the lanes on the system/host side - e.g. 0x5 for lane 0 and lane 2. - - Returns: - Boolean, true if success otherwise false - """ - api = self.get_xcvr_api() - return api.set_cmis_datapath_deinit(host_lanemask) if api is not None else False - - def has_cmis_application_update(self, host_speed, host_lanemask): - """ - Check for CMIS application update and retrieve the new application code - - Args: - host_speed: - Integer, the port speed of the host interface - host_lanemask: - Integer, a bitmask of the lanes on the host side - e.g. 0x5 for lane 0 and lane 2. - - Returns: - (has_update, new_appl) - """ - api = self.get_xcvr_api() - if api is not None: - return api.has_cmis_application_update(host_speed, host_lanemask) - return (False, 1) - - def set_cmis_application_apsel(self, host_lanemask, appl_code): - """ - Update the selected application code to the specified host lanes - - Args: - host_lanemask: - Integer, a bitmask of the lanes on the host side - e.g. 0x5 for lane 0 and lane 2. - appl_code: - Integer, the desired application code - - Returns: - Boolean, true if success otherwise false - """ - ret = False - api = self.get_xcvr_api() - if api is not None: - ret = api.set_cmis_application_apsel(host_lanemask, appl_code) - return ret From 8c74905b7d86c8d3358410598142ee40cf2fe30b Mon Sep 17 00:00:00 2001 From: Dante Su Date: Fri, 3 Dec 2021 08:53:37 +0000 Subject: [PATCH 5/9] fix the LGTM warning Signed-off-by: Dante Su --- sonic_platform_base/sonic_xcvr/fields/public/cmis.py | 1 - 1 file changed, 1 deletion(-) diff --git a/sonic_platform_base/sonic_xcvr/fields/public/cmis.py b/sonic_platform_base/sonic_xcvr/fields/public/cmis.py index e949104c6..88806b1d5 100644 --- a/sonic_platform_base/sonic_xcvr/fields/public/cmis.py +++ b/sonic_platform_base/sonic_xcvr/fields/public/cmis.py @@ -1,5 +1,4 @@ from ..xcvr_field import NumberRegField -from ..xcvr_field import RegField from .. import consts class CableLenField(NumberRegField): From 26c95e6e2d032dc4b8044d78fc47012ff4a16c01 Mon Sep 17 00:00:00 2001 From: Dante Su Date: Fri, 3 Dec 2021 10:03:47 +0000 Subject: [PATCH 6/9] Drop BIT6 clear from set_lpmode() Signed-off-by: Dante Su --- sonic_platform_base/sonic_xcvr/api/public/cmis.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/sonic_platform_base/sonic_xcvr/api/public/cmis.py b/sonic_platform_base/sonic_xcvr/api/public/cmis.py index 362d6de14..1cfafa483 100644 --- a/sonic_platform_base/sonic_xcvr/api/public/cmis.py +++ b/sonic_platform_base/sonic_xcvr/api/public/cmis.py @@ -925,9 +925,6 @@ def set_lpmode(self, lpmode): lpmode_val = self.xcvr_eeprom.read(consts.MODULE_LEVEL_CONTROL) if lpmode_val is not None: - # Turn on software control mode - if self.xcvr_eeprom.read(consts.CMIS_MAJOR_REVISION) >= 4: - lpmode_val = lpmode_val & ~(1 << 6) # LowPwrAllowRequestHW if lpmode is True: lpmode_val = lpmode_val | (1 << 4) self.xcvr_eeprom.write(consts.MODULE_LEVEL_CONTROL, lpmode_val) From 54ca77ecfa9534f81e84f0578893564d43f2b14a Mon Sep 17 00:00:00 2001 From: Dante Su Date: Mon, 6 Dec 2021 13:50:20 +0000 Subject: [PATCH 7/9] Fix python2 compatibility issues in pytest Signed-off-by: Dante Su --- .../sonic_xcvr/mem_maps/public/cmis.py | 246 +++++++++++++++--- 1 file changed, 204 insertions(+), 42 deletions(-) diff --git a/sonic_platform_base/sonic_xcvr/mem_maps/public/cmis.py b/sonic_platform_base/sonic_xcvr/mem_maps/public/cmis.py index 28c607d99..3d8459b77 100644 --- a/sonic_platform_base/sonic_xcvr/mem_maps/public/cmis.py +++ b/sonic_platform_base/sonic_xcvr/mem_maps/public/cmis.py @@ -53,50 +53,212 @@ def __init__(self, codes): CodeRegField(consts.CONNECTOR_FIELD, self.getaddr(0x0, 203), self.codes.CONNECTORS), RegGroupField(consts.APPLS_ADVT_FIELD, - *(CodeRegField("%s_%d" % (consts.HOST_ELECTRICAL_INTERFACE, app), self.getaddr(0x0, 86 + 4 * (app - 1)), self.codes.HOST_ELECTRICAL_INTERFACE) - for app in range(1, 9)), - *(CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_850NM, app), self.getaddr(0x0, 87 + 4 * (app - 1)), self.codes.NM_850_MEDIA_INTERFACE) - for app in range(1, 9)), - *(CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_SM, app), self.getaddr(0x0, 87 + 4 * (app - 1)), self.codes.SM_MEDIA_INTERFACE) - for app in range(1, 9)), - *(CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_PASSIVE_COPPER, app), self.getaddr(0x0, 87 + 4 * (app - 1)), self.codes.PASSIVE_COPPER_MEDIA_INTERFACE) - for app in range(1, 9)), - *(CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_ACTIVE_CABLE, app), self.getaddr(0x0, 87 + 4 * (app - 1)), self.codes.ACTIVE_CABLE_MEDIA_INTERFACE) - for app in range(1, 9)), - *(CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_BASE_T, app), self.getaddr(0x0, 87 + 4 * (app - 1)), self.codes.BASE_T_MEDIA_INTERFACE) - for app in range(1, 9)), - *(NumberRegField("%s_%d" % (consts.MEDIA_LANE_COUNT, app), self.getaddr(0x0, 88 + 4 * (app - 1)), - *(RegBitField("Bit%d" % (bit), bit) for bit in range (0, 4))) - for app in range(1, 9)), - *(NumberRegField("%s_%d" % (consts.HOST_LANE_COUNT, app), self.getaddr(0x0, 88 + 4 * (app - 1)), - *(RegBitField("Bit%d" % (bit), bit) for bit in range (4, 8))) - for app in range(1, 9)), - *(NumberRegField("%s_%d" % (consts.HOST_LANE_ASSIGNMENT_OPTION, app), self.getaddr(0x0, 89 + 4 * (app - 1)), format="B", size=1) - for app in range(1, 9)), + CodeRegField("%s_%d" % (consts.HOST_ELECTRICAL_INTERFACE, 1), self.getaddr(0x0, 86 + 4 * (1 - 1)), self.codes.HOST_ELECTRICAL_INTERFACE), + CodeRegField("%s_%d" % (consts.HOST_ELECTRICAL_INTERFACE, 2), self.getaddr(0x0, 86 + 4 * (2 - 1)), self.codes.HOST_ELECTRICAL_INTERFACE), + CodeRegField("%s_%d" % (consts.HOST_ELECTRICAL_INTERFACE, 3), self.getaddr(0x0, 86 + 4 * (3 - 1)), self.codes.HOST_ELECTRICAL_INTERFACE), + CodeRegField("%s_%d" % (consts.HOST_ELECTRICAL_INTERFACE, 4), self.getaddr(0x0, 86 + 4 * (4 - 1)), self.codes.HOST_ELECTRICAL_INTERFACE), + CodeRegField("%s_%d" % (consts.HOST_ELECTRICAL_INTERFACE, 5), self.getaddr(0x0, 86 + 4 * (5 - 1)), self.codes.HOST_ELECTRICAL_INTERFACE), + CodeRegField("%s_%d" % (consts.HOST_ELECTRICAL_INTERFACE, 6), self.getaddr(0x0, 86 + 4 * (6 - 1)), self.codes.HOST_ELECTRICAL_INTERFACE), + CodeRegField("%s_%d" % (consts.HOST_ELECTRICAL_INTERFACE, 7), self.getaddr(0x0, 86 + 4 * (7 - 1)), self.codes.HOST_ELECTRICAL_INTERFACE), + CodeRegField("%s_%d" % (consts.HOST_ELECTRICAL_INTERFACE, 8), self.getaddr(0x0, 86 + 4 * (8 - 1)), self.codes.HOST_ELECTRICAL_INTERFACE), + CodeRegField("%s_%d" % (consts.HOST_ELECTRICAL_INTERFACE, 9), self.getaddr(0x1, 223 + 4 * (9 - 9)), self.codes.HOST_ELECTRICAL_INTERFACE), + CodeRegField("%s_%d" % (consts.HOST_ELECTRICAL_INTERFACE, 10), self.getaddr(0x1, 223 + 4 * (10 - 9)), self.codes.HOST_ELECTRICAL_INTERFACE), + CodeRegField("%s_%d" % (consts.HOST_ELECTRICAL_INTERFACE, 11), self.getaddr(0x1, 223 + 4 * (11 - 9)), self.codes.HOST_ELECTRICAL_INTERFACE), + CodeRegField("%s_%d" % (consts.HOST_ELECTRICAL_INTERFACE, 12), self.getaddr(0x1, 223 + 4 * (12 - 9)), self.codes.HOST_ELECTRICAL_INTERFACE), + CodeRegField("%s_%d" % (consts.HOST_ELECTRICAL_INTERFACE, 13), self.getaddr(0x1, 223 + 4 * (13 - 9)), self.codes.HOST_ELECTRICAL_INTERFACE), + CodeRegField("%s_%d" % (consts.HOST_ELECTRICAL_INTERFACE, 14), self.getaddr(0x1, 223 + 4 * (14 - 9)), self.codes.HOST_ELECTRICAL_INTERFACE), + CodeRegField("%s_%d" % (consts.HOST_ELECTRICAL_INTERFACE, 15), self.getaddr(0x1, 223 + 4 * (15 - 9)), self.codes.HOST_ELECTRICAL_INTERFACE), + + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_850NM, 1), self.getaddr(0x0, 87 + 4 * (1 - 1)), self.codes.NM_850_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_850NM, 2), self.getaddr(0x0, 87 + 4 * (2 - 1)), self.codes.NM_850_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_850NM, 3), self.getaddr(0x0, 87 + 4 * (3 - 1)), self.codes.NM_850_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_850NM, 4), self.getaddr(0x0, 87 + 4 * (4 - 1)), self.codes.NM_850_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_850NM, 5), self.getaddr(0x0, 87 + 4 * (5 - 1)), self.codes.NM_850_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_850NM, 6), self.getaddr(0x0, 87 + 4 * (6 - 1)), self.codes.NM_850_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_850NM, 7), self.getaddr(0x0, 87 + 4 * (7 - 1)), self.codes.NM_850_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_850NM, 8), self.getaddr(0x0, 87 + 4 * (8 - 1)), self.codes.NM_850_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_850NM, 9), self.getaddr(0x1, 224 + 4 * (9 - 9)), self.codes.NM_850_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_850NM, 10), self.getaddr(0x1, 224 + 4 * (10 - 9)), self.codes.NM_850_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_850NM, 11), self.getaddr(0x1, 224 + 4 * (11 - 9)), self.codes.NM_850_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_850NM, 12), self.getaddr(0x1, 224 + 4 * (12 - 9)), self.codes.NM_850_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_850NM, 13), self.getaddr(0x1, 224 + 4 * (13 - 9)), self.codes.NM_850_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_850NM, 14), self.getaddr(0x1, 224 + 4 * (14 - 9)), self.codes.NM_850_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_850NM, 15), self.getaddr(0x1, 224 + 4 * (15 - 9)), self.codes.NM_850_MEDIA_INTERFACE), + + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_SM, 1), self.getaddr(0x0, 87 + 4 * (1 - 1)), self.codes.SM_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_SM, 2), self.getaddr(0x0, 87 + 4 * (2 - 1)), self.codes.SM_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_SM, 3), self.getaddr(0x0, 87 + 4 * (3 - 1)), self.codes.SM_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_SM, 4), self.getaddr(0x0, 87 + 4 * (4 - 1)), self.codes.SM_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_SM, 5), self.getaddr(0x0, 87 + 4 * (5 - 1)), self.codes.SM_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_SM, 6), self.getaddr(0x0, 87 + 4 * (6 - 1)), self.codes.SM_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_SM, 7), self.getaddr(0x0, 87 + 4 * (7 - 1)), self.codes.SM_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_SM, 8), self.getaddr(0x0, 87 + 4 * (8 - 1)), self.codes.SM_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_SM, 9), self.getaddr(0x1, 224 + 4 * (9 - 9)), self.codes.SM_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_SM, 10), self.getaddr(0x1, 224 + 4 * (10 - 9)), self.codes.SM_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_SM, 11), self.getaddr(0x1, 224 + 4 * (11 - 9)), self.codes.SM_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_SM, 12), self.getaddr(0x1, 224 + 4 * (12 - 9)), self.codes.SM_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_SM, 13), self.getaddr(0x1, 224 + 4 * (13 - 9)), self.codes.SM_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_SM, 14), self.getaddr(0x1, 224 + 4 * (14 - 9)), self.codes.SM_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_SM, 15), self.getaddr(0x1, 224 + 4 * (15 - 9)), self.codes.SM_MEDIA_INTERFACE), + + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_PASSIVE_COPPER, 1), self.getaddr(0x0, 87 + 4 * (1 - 1)), self.codes.PASSIVE_COPPER_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_PASSIVE_COPPER, 2), self.getaddr(0x0, 87 + 4 * (2 - 1)), self.codes.PASSIVE_COPPER_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_PASSIVE_COPPER, 3), self.getaddr(0x0, 87 + 4 * (3 - 1)), self.codes.PASSIVE_COPPER_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_PASSIVE_COPPER, 4), self.getaddr(0x0, 87 + 4 * (4 - 1)), self.codes.PASSIVE_COPPER_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_PASSIVE_COPPER, 5), self.getaddr(0x0, 87 + 4 * (5 - 1)), self.codes.PASSIVE_COPPER_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_PASSIVE_COPPER, 6), self.getaddr(0x0, 87 + 4 * (6 - 1)), self.codes.PASSIVE_COPPER_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_PASSIVE_COPPER, 7), self.getaddr(0x0, 87 + 4 * (7 - 1)), self.codes.PASSIVE_COPPER_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_PASSIVE_COPPER, 8), self.getaddr(0x0, 87 + 4 * (8 - 1)), self.codes.PASSIVE_COPPER_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_PASSIVE_COPPER, 9), self.getaddr(0x1, 224 + 4 * (9 - 9)), self.codes.PASSIVE_COPPER_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_PASSIVE_COPPER, 10), self.getaddr(0x1, 224 + 4 * (10 - 9)), self.codes.PASSIVE_COPPER_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_PASSIVE_COPPER, 11), self.getaddr(0x1, 224 + 4 * (11 - 9)), self.codes.PASSIVE_COPPER_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_PASSIVE_COPPER, 12), self.getaddr(0x1, 224 + 4 * (12 - 9)), self.codes.PASSIVE_COPPER_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_PASSIVE_COPPER, 13), self.getaddr(0x1, 224 + 4 * (13 - 9)), self.codes.PASSIVE_COPPER_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_PASSIVE_COPPER, 14), self.getaddr(0x1, 224 + 4 * (14 - 9)), self.codes.PASSIVE_COPPER_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_PASSIVE_COPPER, 15), self.getaddr(0x1, 224 + 4 * (15 - 9)), self.codes.PASSIVE_COPPER_MEDIA_INTERFACE), + + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_ACTIVE_CABLE, 1), self.getaddr(0x0, 87 + 4 * (1 - 1)), self.codes.ACTIVE_CABLE_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_ACTIVE_CABLE, 2), self.getaddr(0x0, 87 + 4 * (2 - 1)), self.codes.ACTIVE_CABLE_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_ACTIVE_CABLE, 3), self.getaddr(0x0, 87 + 4 * (3 - 1)), self.codes.ACTIVE_CABLE_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_ACTIVE_CABLE, 4), self.getaddr(0x0, 87 + 4 * (4 - 1)), self.codes.ACTIVE_CABLE_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_ACTIVE_CABLE, 5), self.getaddr(0x0, 87 + 4 * (5 - 1)), self.codes.ACTIVE_CABLE_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_ACTIVE_CABLE, 6), self.getaddr(0x0, 87 + 4 * (6 - 1)), self.codes.ACTIVE_CABLE_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_ACTIVE_CABLE, 7), self.getaddr(0x0, 87 + 4 * (7 - 1)), self.codes.ACTIVE_CABLE_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_ACTIVE_CABLE, 8), self.getaddr(0x0, 87 + 4 * (8 - 1)), self.codes.ACTIVE_CABLE_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_ACTIVE_CABLE, 9), self.getaddr(0x1, 224 + 4 * (9 - 9)), self.codes.ACTIVE_CABLE_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_ACTIVE_CABLE, 10), self.getaddr(0x1, 224 + 4 * (10 - 9)), self.codes.ACTIVE_CABLE_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_ACTIVE_CABLE, 11), self.getaddr(0x1, 224 + 4 * (11 - 9)), self.codes.ACTIVE_CABLE_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_ACTIVE_CABLE, 12), self.getaddr(0x1, 224 + 4 * (12 - 9)), self.codes.ACTIVE_CABLE_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_ACTIVE_CABLE, 13), self.getaddr(0x1, 224 + 4 * (13 - 9)), self.codes.ACTIVE_CABLE_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_ACTIVE_CABLE, 14), self.getaddr(0x1, 224 + 4 * (14 - 9)), self.codes.ACTIVE_CABLE_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_ACTIVE_CABLE, 15), self.getaddr(0x1, 224 + 4 * (15 - 9)), self.codes.ACTIVE_CABLE_MEDIA_INTERFACE), + + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_BASE_T, 1), self.getaddr(0x0, 87 + 4 * (1 - 1)), self.codes.BASE_T_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_BASE_T, 2), self.getaddr(0x0, 87 + 4 * (2 - 1)), self.codes.BASE_T_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_BASE_T, 3), self.getaddr(0x0, 87 + 4 * (3 - 1)), self.codes.BASE_T_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_BASE_T, 4), self.getaddr(0x0, 87 + 4 * (4 - 1)), self.codes.BASE_T_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_BASE_T, 5), self.getaddr(0x0, 87 + 4 * (5 - 1)), self.codes.BASE_T_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_BASE_T, 6), self.getaddr(0x0, 87 + 4 * (6 - 1)), self.codes.BASE_T_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_BASE_T, 7), self.getaddr(0x0, 87 + 4 * (7 - 1)), self.codes.BASE_T_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_BASE_T, 8), self.getaddr(0x0, 87 + 4 * (8 - 1)), self.codes.BASE_T_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_BASE_T, 9), self.getaddr(0x1, 224 + 4 * (9 - 9)), self.codes.BASE_T_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_BASE_T, 10), self.getaddr(0x1, 224 + 4 * (10 - 9)), self.codes.BASE_T_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_BASE_T, 11), self.getaddr(0x1, 224 + 4 * (11 - 9)), self.codes.BASE_T_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_BASE_T, 12), self.getaddr(0x1, 224 + 4 * (12 - 9)), self.codes.BASE_T_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_BASE_T, 13), self.getaddr(0x1, 224 + 4 * (13 - 9)), self.codes.BASE_T_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_BASE_T, 14), self.getaddr(0x1, 224 + 4 * (14 - 9)), self.codes.BASE_T_MEDIA_INTERFACE), + CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_BASE_T, 15), self.getaddr(0x1, 224 + 4 * (15 - 9)), self.codes.BASE_T_MEDIA_INTERFACE), + + NumberRegField("%s_%d" % (consts.MEDIA_LANE_COUNT, 1), self.getaddr(0x0, 88 + 4 * (1 - 1)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (0, 4)) + ), + NumberRegField("%s_%d" % (consts.MEDIA_LANE_COUNT, 2), self.getaddr(0x0, 88 + 4 * (2 - 1)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (0, 4)) + ), + NumberRegField("%s_%d" % (consts.MEDIA_LANE_COUNT, 3), self.getaddr(0x0, 88 + 4 * (3 - 1)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (0, 4)) + ), + NumberRegField("%s_%d" % (consts.MEDIA_LANE_COUNT, 4), self.getaddr(0x0, 88 + 4 * (4 - 1)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (0, 4)) + ), + NumberRegField("%s_%d" % (consts.MEDIA_LANE_COUNT, 5), self.getaddr(0x0, 88 + 4 * (5 - 1)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (0, 4)) + ), + NumberRegField("%s_%d" % (consts.MEDIA_LANE_COUNT, 6), self.getaddr(0x0, 88 + 4 * (6 - 1)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (0, 4)) + ), + NumberRegField("%s_%d" % (consts.MEDIA_LANE_COUNT, 7), self.getaddr(0x0, 88 + 4 * (7 - 1)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (0, 4)) + ), + NumberRegField("%s_%d" % (consts.MEDIA_LANE_COUNT, 8), self.getaddr(0x0, 88 + 4 * (8 - 1)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (0, 4)) + ), + NumberRegField("%s_%d" % (consts.MEDIA_LANE_COUNT, 9), self.getaddr(0x1, 225 + 4 * (9 - 9)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (0, 4)) + ), + NumberRegField("%s_%d" % (consts.MEDIA_LANE_COUNT, 10), self.getaddr(0x1, 225 + 4 * (10 - 9)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (0, 4)) + ), + NumberRegField("%s_%d" % (consts.MEDIA_LANE_COUNT, 11), self.getaddr(0x1, 225 + 4 * (11 - 9)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (0, 4)) + ), + NumberRegField("%s_%d" % (consts.MEDIA_LANE_COUNT, 12), self.getaddr(0x1, 225 + 4 * (12 - 9)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (0, 4)) + ), + NumberRegField("%s_%d" % (consts.MEDIA_LANE_COUNT, 13), self.getaddr(0x1, 225 + 4 * (13 - 9)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (0, 4)) + ), + NumberRegField("%s_%d" % (consts.MEDIA_LANE_COUNT, 14), self.getaddr(0x1, 225 + 4 * (14 - 9)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (0, 4)) + ), + NumberRegField("%s_%d" % (consts.MEDIA_LANE_COUNT, 15), self.getaddr(0x1, 225 + 4 * (15 - 9)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (0, 4)) + ), + + NumberRegField("%s_%d" % (consts.HOST_LANE_COUNT, 1), self.getaddr(0x0, 88 + 4 * (1 - 1)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (4, 8)) + ), + NumberRegField("%s_%d" % (consts.HOST_LANE_COUNT, 2), self.getaddr(0x0, 88 + 4 * (2 - 1)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (4, 8)) + ), + NumberRegField("%s_%d" % (consts.HOST_LANE_COUNT, 3), self.getaddr(0x0, 88 + 4 * (3 - 1)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (4, 8)) + ), + NumberRegField("%s_%d" % (consts.HOST_LANE_COUNT, 4), self.getaddr(0x0, 88 + 4 * (4 - 1)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (4, 8)) + ), + NumberRegField("%s_%d" % (consts.HOST_LANE_COUNT, 5), self.getaddr(0x0, 88 + 4 * (5 - 1)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (4, 8)) + ), + NumberRegField("%s_%d" % (consts.HOST_LANE_COUNT, 6), self.getaddr(0x0, 88 + 4 * (6 - 1)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (4, 8)) + ), + NumberRegField("%s_%d" % (consts.HOST_LANE_COUNT, 7), self.getaddr(0x0, 88 + 4 * (7 - 1)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (4, 8)) + ), + NumberRegField("%s_%d" % (consts.HOST_LANE_COUNT, 8), self.getaddr(0x0, 88 + 4 * (8 - 1)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (4, 8)) + ), + NumberRegField("%s_%d" % (consts.HOST_LANE_COUNT, 9), self.getaddr(0x1, 225 + 4 * (9 - 9)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (4, 8)) + ), + NumberRegField("%s_%d" % (consts.HOST_LANE_COUNT, 10), self.getaddr(0x1, 225 + 4 * (10 - 9)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (4, 8)) + ), + NumberRegField("%s_%d" % (consts.HOST_LANE_COUNT, 11), self.getaddr(0x1, 225 + 4 * (11 - 9)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (4, 8)) + ), + NumberRegField("%s_%d" % (consts.HOST_LANE_COUNT, 12), self.getaddr(0x1, 225 + 4 * (12 - 9)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (4, 8)) + ), + NumberRegField("%s_%d" % (consts.HOST_LANE_COUNT, 13), self.getaddr(0x1, 225 + 4 * (13 - 9)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (4, 8)) + ), + NumberRegField("%s_%d" % (consts.HOST_LANE_COUNT, 14), self.getaddr(0x1, 225 + 4 * (14 - 9)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (4, 8)) + ), + NumberRegField("%s_%d" % (consts.HOST_LANE_COUNT, 15), self.getaddr(0x1, 225 + 4 * (15 - 9)), + *(RegBitField("Bit%d" % (bit), bit) for bit in range (4, 8)) + ), + + NumberRegField("%s_%d" % (consts.HOST_LANE_ASSIGNMENT_OPTION, 1), self.getaddr(0x0, 89 + 4 * (1 - 1)), format="B", size=1), + NumberRegField("%s_%d" % (consts.HOST_LANE_ASSIGNMENT_OPTION, 2), self.getaddr(0x0, 89 + 4 * (2 - 1)), format="B", size=1), + NumberRegField("%s_%d" % (consts.HOST_LANE_ASSIGNMENT_OPTION, 3), self.getaddr(0x0, 89 + 4 * (3 - 1)), format="B", size=1), + NumberRegField("%s_%d" % (consts.HOST_LANE_ASSIGNMENT_OPTION, 4), self.getaddr(0x0, 89 + 4 * (4 - 1)), format="B", size=1), + NumberRegField("%s_%d" % (consts.HOST_LANE_ASSIGNMENT_OPTION, 5), self.getaddr(0x0, 89 + 4 * (5 - 1)), format="B", size=1), + NumberRegField("%s_%d" % (consts.HOST_LANE_ASSIGNMENT_OPTION, 6), self.getaddr(0x0, 89 + 4 * (6 - 1)), format="B", size=1), + NumberRegField("%s_%d" % (consts.HOST_LANE_ASSIGNMENT_OPTION, 7), self.getaddr(0x0, 89 + 4 * (7 - 1)), format="B", size=1), + NumberRegField("%s_%d" % (consts.HOST_LANE_ASSIGNMENT_OPTION, 8), self.getaddr(0x0, 89 + 4 * (8 - 1)), format="B", size=1), + NumberRegField("%s_%d" % (consts.HOST_LANE_ASSIGNMENT_OPTION, 9), self.getaddr(0x1, 226 + 4 * (9 - 1)), format="B", size=1), + NumberRegField("%s_%d" % (consts.HOST_LANE_ASSIGNMENT_OPTION, 10), self.getaddr(0x1, 226 + 4 * (10 - 1)), format="B", size=1), + NumberRegField("%s_%d" % (consts.HOST_LANE_ASSIGNMENT_OPTION, 11), self.getaddr(0x1, 226 + 4 * (11 - 1)), format="B", size=1), + NumberRegField("%s_%d" % (consts.HOST_LANE_ASSIGNMENT_OPTION, 12), self.getaddr(0x1, 226 + 4 * (12 - 1)), format="B", size=1), + NumberRegField("%s_%d" % (consts.HOST_LANE_ASSIGNMENT_OPTION, 13), self.getaddr(0x1, 226 + 4 * (13 - 1)), format="B", size=1), + NumberRegField("%s_%d" % (consts.HOST_LANE_ASSIGNMENT_OPTION, 14), self.getaddr(0x1, 226 + 4 * (14 - 1)), format="B", size=1), + NumberRegField("%s_%d" % (consts.HOST_LANE_ASSIGNMENT_OPTION, 15), self.getaddr(0x1, 226 + 4 * (15 - 1)), format="B", size=1), *(NumberRegField("%s_%d" % (consts.MEDIA_LANE_ASSIGNMENT_OPTION, app), self.getaddr(0x1, 176 + (app - 1)), format="B", size=1) - for app in range(1, 16)), - - *(CodeRegField("%s_%d" % (consts.HOST_ELECTRICAL_INTERFACE, app), self.getaddr(0x1, 223 + 4 * (app - 9)), self.codes.HOST_ELECTRICAL_INTERFACE) - for app in range(9, 16)), - *(CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_850NM, app), self.getaddr(0x1, 224 + 4 * (app - 9)), self.codes.NM_850_MEDIA_INTERFACE) - for app in range(9, 16)), - *(CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_SM, app), self.getaddr(0x1, 224 + 4 * (app - 9)), self.codes.SM_MEDIA_INTERFACE) - for app in range(9, 16)), - *(CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_PASSIVE_COPPER, app), self.getaddr(0x1, 224 + 4 * (app - 9)), self.codes.PASSIVE_COPPER_MEDIA_INTERFACE) - for app in range(9, 16)), - *(CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_ACTIVE_CABLE, app), self.getaddr(0x1, 224 + 4 * (app - 9)), self.codes.ACTIVE_CABLE_MEDIA_INTERFACE) - for app in range(9, 16)), - *(CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_BASE_T, app), self.getaddr(0x1, 224 + 4 * (app - 9)), self.codes.BASE_T_MEDIA_INTERFACE) - for app in range(9, 16)), - *(NumberRegField("%s_%d" % (consts.MEDIA_LANE_COUNT, app), self.getaddr(0x1, 225 + 4 * (app - 9)), - *(RegBitField("Bit%d" % (bit), bit) for bit in range (0, 4))) - for app in range(9, 16)), - *(NumberRegField("%s_%d" % (consts.HOST_LANE_COUNT, app), self.getaddr(0x1, 225 + 4 * (app - 9)), - *(RegBitField("Bit%d" % (bit), bit) for bit in range (4, 8))) - for app in range(9, 16)), - *(NumberRegField("%s_%d" % (consts.HOST_LANE_ASSIGNMENT_OPTION, app), self.getaddr(0x1, 226 + 4 * (app - 9)), format="B", size=1) - for app in range(9, 16)), + for app in range(1, 16)) ), CodeRegField(consts.HOST_ELECTRICAL_INTERFACE, self.getaddr(0x0, 86), self.codes.HOST_ELECTRICAL_INTERFACE), From 54cd97a5a61550c657ec174ca564106aacb068a9 Mon Sep 17 00:00:00 2001 From: Dante Su Date: Tue, 7 Dec 2021 04:07:00 +0000 Subject: [PATCH 8/9] improve CMIS test coverage and address review comments Signed-off-by: Dante Su --- .../sonic_xcvr/api/public/cmis.py | 20 ++- tests/sonic_xcvr/test_cmis.py | 149 +++++++++++++++++- 2 files changed, 158 insertions(+), 11 deletions(-) diff --git a/sonic_platform_base/sonic_xcvr/api/public/cmis.py b/sonic_platform_base/sonic_xcvr/api/public/cmis.py index 1cfafa483..7d78b7c8f 100644 --- a/sonic_platform_base/sonic_xcvr/api/public/cmis.py +++ b/sonic_platform_base/sonic_xcvr/api/public/cmis.py @@ -892,10 +892,14 @@ def reset(self): A boolean, True if successful, False if not """ if self.reset_module(True): + # minimum waiting time for the TWI to be functional again + time.sleep(2) + # buffer time for retries in range(5): - time.sleep(1) - if self.get_module_state() != 'Unknown': + state = self.get_module_state() + if state in ['ModuleReady']: return True + time.sleep(1) return False def get_lpmode(self): @@ -1916,15 +1920,15 @@ def set_application(self, channel, appl_code): # Apply DataPathInit return self.xcvr_eeprom.write("%s_%d" % (consts.STAGED_CTRL_APPLY_DPINIT_FIELD, 0), channel) - def get_num_channels(self): - if self.get_module_type_abbreviation() == 'QSFP+C': - return 4 - return self.NUM_CHANNELS - def get_error_description(self): dp_state = self.get_datapath_state() conf_state = self.get_config_datapath_hostlane_status() - for lane in range(self.get_num_channels()): + for lane in range(self.NUM_CHANNELS): + name = "{}_{}_{}".format(consts.STAGED_CTRL_APSEL_FIELD, 0, lane + 1) + appl = self.xcvr_eeprom.read(name) + if (appl is None) or ((appl >> 4) == 0): + continue + name = "DP{}State".format(lane + 1) if dp_state[name] != CmisCodes.DATAPATH_STATE[4]: return dp_state[name] diff --git a/tests/sonic_xcvr/test_cmis.py b/tests/sonic_xcvr/test_cmis.py index 881035154..bfda03619 100644 --- a/tests/sonic_xcvr/test_cmis.py +++ b/tests/sonic_xcvr/test_cmis.py @@ -4,7 +4,8 @@ from sonic_platform_base.sonic_xcvr.mem_maps.public.cmis import CmisMemMap from sonic_platform_base.sonic_xcvr.xcvr_eeprom import XcvrEeprom from sonic_platform_base.sonic_xcvr.codes.public.cmis import CmisCodes -from sonic_platform_base.sonic_xcvr.fields.consts import LENGTH_ASSEMBLY_FIELD, LEN_MULT_FIELD +from sonic_platform_base.sonic_xcvr.codes.public.sff8024 import Sff8024 +from sonic_platform_base.sonic_xcvr.fields import consts class TestCmis(object): codes = CmisCodes @@ -825,6 +826,17 @@ def test_get_supported_power_config(self, mock_response, expected): def test_reset_module(self): self.api.reset_module(True) + def test_reset(self): + self.api.xcvr_eeprom.write = MagicMock() + self.api.get_module_state = MagicMock() + self.api.get_module_state.return_value = 'ModuleReady' + result = self.api.reset() + assert result + assert self.api.xcvr_eeprom.write.call_count == 1 + kall = self.api.xcvr_eeprom.write.call_args + assert kall is not None + assert kall[0] == (consts.MODULE_LEVEL_CONTROL, 0x8) + def test_set_low_power(self): self.api.is_flat_memory = MagicMock() self.api.is_flat_memory.return_value = False @@ -1886,9 +1898,140 @@ def test_get_transceiver_loopback(self, mock_response, expected): assert result == expected def test_cable_len(self): - cable_len_field = self.mem_map.get_field(LENGTH_ASSEMBLY_FIELD) + cable_len_field = self.mem_map.get_field(consts.LENGTH_ASSEMBLY_FIELD) data = bytearray([0xFF]) - dep = {LEN_MULT_FIELD: 0b11} + dep = {consts.LEN_MULT_FIELD: 0b11} decoded = cable_len_field.decode(data, **dep) assert decoded == 6300 + def test_set_datapath_init(self): + self.api.xcvr_eeprom.write = MagicMock() + self.api.xcvr_eeprom.read = MagicMock() + + self.api.xcvr_eeprom.read.side_effect = [0x3, 0x00] + self.api.set_datapath_init(0xff) + kall = self.api.xcvr_eeprom.write.call_args + assert kall is not None + assert kall[0] == (consts.DATAPATH_DEINIT_FIELD, 0xff) + + self.api.xcvr_eeprom.read.side_effect = [0x4, 0x00] + self.api.set_datapath_init(0xff) + kall = self.api.xcvr_eeprom.write.call_args + assert kall is not None + assert kall[0] == (consts.DATAPATH_DEINIT_FIELD, 0x00) + + def test_set_datapath_deinit(self): + self.api.xcvr_eeprom.write = MagicMock() + self.api.xcvr_eeprom.read = MagicMock() + + self.api.xcvr_eeprom.read.side_effect = [0x3, 0x00] + self.api.set_datapath_deinit(0xff) + kall = self.api.xcvr_eeprom.write.call_args + assert kall is not None + assert kall[0] == (consts.DATAPATH_DEINIT_FIELD, 0x00) + + self.api.xcvr_eeprom.read.side_effect = [0x4, 0x00] + self.api.set_datapath_deinit(0xff) + kall = self.api.xcvr_eeprom.write.call_args + assert kall is not None + assert kall[0] == (consts.DATAPATH_DEINIT_FIELD, 0xff) + + def test_get_application_advertisement(self): + self.api.xcvr_eeprom.read = MagicMock() + self.api.xcvr_eeprom.read.side_effect = [ + { + consts.HOST_ELECTRICAL_INTERFACE + "_1": "400GAUI-8 C2M (Annex 120E)", + consts.MODULE_MEDIA_INTERFACE_SM + "_1": "400GBASE-DR4 (Cl 124)", + consts.MEDIA_LANE_COUNT + "_1": 4, + consts.HOST_LANE_COUNT + "_1": 8, + consts.HOST_LANE_ASSIGNMENT_OPTION + "_1": 0x01 + }, + Sff8024.MODULE_MEDIA_TYPE[2] + ] + result = self.api.get_application_advertisement() + + assert len(result) == 1 + assert result[1]['host_electrical_interface_id'] == '400GAUI-8 C2M (Annex 120E)' + assert result[1]['module_media_interface_id'] == '400GBASE-DR4 (Cl 124)' + assert result[1]['host_lane_count'] == 8 + assert result[1]['media_lane_count'] == 4 + assert result[1]['host_lane_assignment_options'] == 0x01 + + def test_get_application(self): + self.api.xcvr_eeprom.read = MagicMock() + self.api.xcvr_eeprom.read.return_value = 0x20 + + self.api.is_flat_memory = MagicMock() + self.api.is_flat_memory.return_value = False + appl = self.api.get_application(0) + assert appl == 2 + + appl = self.api.get_application(2) + assert appl == 2 + + appl = self.api.get_application(self.api.NUM_CHANNELS) + assert appl == 0 + + self.api.is_flat_memory.return_value = True + appl = self.api.get_application(0) + assert appl == 0 + + appl = self.api.get_application(2) + assert appl == 0 + + appl = self.api.get_application(self.api.NUM_CHANNELS) + assert appl == 0 + + def test_set_application(self): + self.api.xcvr_eeprom.write = MagicMock() + + self.api.xcvr_eeprom.write.call_count = 0 + self.api.set_application(0x00, 1) + assert self.api.xcvr_eeprom.write.call_count == 1 + + self.api.xcvr_eeprom.write.call_count = 0 + self.api.set_application(0x01, 1) + assert self.api.xcvr_eeprom.write.call_count == 1 + 1 + + self.api.xcvr_eeprom.write.call_count = 0 + self.api.set_application(0x0f, 1) + assert self.api.xcvr_eeprom.write.call_count == 4 + 1 + + self.api.xcvr_eeprom.write.call_count = 0 + self.api.set_application(0xff, 1) + assert self.api.xcvr_eeprom.write.call_count == 8 + 1 + + self.api.xcvr_eeprom.write.call_count = 0 + self.api.set_application(0x7fffffff, 1) + assert self.api.xcvr_eeprom.write.call_count == self.api.NUM_CHANNELS + 1 + + def test_get_error_description(self): + self.api.get_module_state = MagicMock() + self.api.get_module_state.return_value = 'ModuleReady' + self.api.get_datapath_state = MagicMock() + self.api.get_datapath_state.return_value = { + 'DP1State': 'DataPathActivated', + 'DP2State': 'DataPathActivated', + 'DP3State': 'DataPathActivated', + 'DP4State': 'DataPathActivated', + 'DP5State': 'DataPathActivated', + 'DP6State': 'DataPathActivated', + 'DP7State': 'DataPathActivated', + 'DP8State': 'DataPathActivated' + } + self.api.get_config_datapath_hostlane_status = MagicMock() + self.api.get_config_datapath_hostlane_status.return_value = { + 'ConfigStatusLane1': 'ConfigSuccess', + 'ConfigStatusLane2': 'ConfigSuccess', + 'ConfigStatusLane3': 'ConfigSuccess', + 'ConfigStatusLane4': 'ConfigSuccess', + 'ConfigStatusLane5': 'ConfigSuccess', + 'ConfigStatusLane6': 'ConfigSuccess', + 'ConfigStatusLane7': 'ConfigSuccess', + 'ConfigStatusLane8': 'ConfigSuccess' + } + self.api.xcvr_eeprom.read = MagicMock() + self.api.xcvr_eeprom.read.return_value = 0x10 + + result = self.api.get_error_description() + assert result is None From bea277e4138f820c56f996d143c33c33fb3496a5 Mon Sep 17 00:00:00 2001 From: Dante Su Date: Tue, 7 Dec 2021 05:52:49 +0000 Subject: [PATCH 9/9] reset(): add ModuleLowPwr into the checker Signed-off-by: Dante Su --- sonic_platform_base/sonic_xcvr/api/public/cmis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonic_platform_base/sonic_xcvr/api/public/cmis.py b/sonic_platform_base/sonic_xcvr/api/public/cmis.py index 7d78b7c8f..e03622d6b 100644 --- a/sonic_platform_base/sonic_xcvr/api/public/cmis.py +++ b/sonic_platform_base/sonic_xcvr/api/public/cmis.py @@ -897,7 +897,7 @@ def reset(self): # buffer time for retries in range(5): state = self.get_module_state() - if state in ['ModuleReady']: + if state in ['ModuleReady', 'ModuleLowPwr']: return True time.sleep(1) return False