-
Notifications
You must be signed in to change notification settings - Fork 217
[sfp-refactoring] Initial support for CMIS application initialization #219
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
2a8bfa6
a1a01cd
f53683d
dd0de8d
8c74905
26c95e6
54ca77e
54cd97a
bea277e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,8 @@ | |
| from ..xcvr_api import XcvrApi | ||
|
|
||
| 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 | ||
|
|
@@ -50,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 | ||
|
|
@@ -134,10 +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], | ||
| # TODO | ||
| "application_advertisement": "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() | ||
|
|
@@ -876,6 +884,24 @@ def reset_module(self, reset = False): | |
| else: | ||
| return True | ||
|
|
||
| def reset(self): | ||
| """ | ||
| Reset SFP and return all user module settings to their default state. | ||
|
|
||
| Returns: | ||
| 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): | ||
| state = self.get_module_state() | ||
| if state in ['ModuleReady', 'ModuleLowPwr']: | ||
| return True | ||
| time.sleep(1) | ||
| return False | ||
|
|
||
| def get_lpmode(self): | ||
| ''' | ||
| Retrieves Low power module status | ||
|
|
@@ -1745,4 +1771,176 @@ 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, channel): | ||
| """ | ||
| Put the CMIS datapath into the initialized state | ||
|
|
||
| Args: | ||
| 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 | ||
| """ | ||
| 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) & channel) == 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, channel): | ||
| """ | ||
| Put the CMIS datapath into the de-initialized state | ||
|
|
||
| Args: | ||
| 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 | ||
| """ | ||
| 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) & channel) == 0: | ||
| continue | ||
| if cmis_major >= 4: # CMIS v4 onwards | ||
prgeor marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| data |= (1 << lane) | ||
| else: # CMIS v3 | ||
| data &= ~(1 << lane) | ||
| self.xcvr_eeprom.write(consts.DATAPATH_DEINIT_FIELD, data) | ||
|
|
||
| def get_application_advertisement(self): | ||
| """ | ||
| Get the application advertisement of the CMIS transceiver | ||
|
|
||
| Returns: | ||
| Dictionary, the application advertisement | ||
| """ | ||
| 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 | ||
| } | ||
|
|
||
| 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: | ||
| lane: | ||
| Integer, the zero-based lane id on the host side | ||
|
|
||
| Returns: | ||
| Integer, the transceiver-specific application code | ||
| """ | ||
| 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 (appl & 0xf) | ||
|
|
||
| def set_application(self, channel, appl_code): | ||
| """ | ||
| Update the selected application code to the specified lanes on the host side | ||
|
|
||
| Args: | ||
| channel: | ||
| 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 | ||
| lane_first = -1 | ||
| for lane in range(self.NUM_CHANNELS): | ||
| 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) | (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), channel) | ||
|
|
||
| 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): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you define a function (get_cmis_num_channels()) to get the count?. Optics like DR4 has only 4 channels. we can't assume 8 as default number of channels.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done, but please note these are host lanes connected to the MAC/ASIC, hence it's 8 lanes in DR4, as to QSFP+ CMIS, it's most likely 4 lanes. e.g. Here is an example of INNOLIGHT 400G DR4, the ConfigError reside at 0x94a, while DPState are at 0x900 |
||
| 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 | ||
|
Comment on lines
+1927
to
+1930
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this api should return error state of datapath and module any time it is called. but looks like that is not the case.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It does return the failure in the current application init sequence. |
||
|
|
||
| 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 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This leads to a crash on my 400G DR4 optic (CMIS v4, AVAGO#AFCT-93DRPHZ-AZ2) |
||
|
|
||
| def cdb1_chkflags(self): | ||
| ''' | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please remove duplicate https://github.com/Azure/sonic-platform-common/blob/master/sonic_platform_base/sonic_xcvr/api/public/cmis.py#L867 or reuse the same
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done