-
Notifications
You must be signed in to change notification settings - Fork 3
[device/celestica]: Add support for xcvrd daemon in silverstone #91
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
base: 201811-TH3
Are you sure you want to change the base?
Changes from 6 commits
f98ba0e
e9f3fb1
3d1b648
8400496
1c4e42f
3e5c896
1f49835
4f8dbca
3614955
504e2a1
0226ded
d6d0e5c
5241e6a
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 |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| #!/bin/bash | ||
|
|
||
| # Configure transceiver module into 4x100G breakout mode | ||
| # so that each 100G ports can be operated independently | ||
|
|
||
| # Usage: | ||
| # ./cmis4_init.sh $port_i2c_no | ||
| # | ||
| port=$1 | ||
|
|
||
| # "=========================================================================" | ||
| # "Init CMIS 4.0 module in port $port" | ||
| # "=========================================================================" | ||
|
|
||
| # "-------------------------------------------------------------------------" | ||
| # " Set page 00h before start configuration..." | ||
| # "-------------------------------------------------------------------------" | ||
| sudo i2cset -f -y $port 0x50 0x7f 0 | ||
|
|
||
| # "-------------------------------------------------------------------------" | ||
| # "step 1. SW reset module" | ||
| # "-------------------------------------------------------------------------" | ||
| sudo i2cset -f -y $port 0x50 26 0x08 | ||
| sleep 0.2 | ||
|
|
||
| # "-------------------------------------------------------------------------" | ||
| # "step 2. deinitialize datapath" | ||
| # "-------------------------------------------------------------------------" | ||
| sudo i2cset -f -y $port 0x50 127 0x10 | ||
| sudo i2cset -f -y $port 0x50 128 0xff | ||
|
|
||
| # "-------------------------------------------------------------------------" | ||
| # "step 3. enable hi-power mode" | ||
| # "-------------------------------------------------------------------------" | ||
| sudo i2cset -f -y $port 0x50 26 0x00 | ||
| sleep 0.2 | ||
|
|
||
| # "-------------------------------------------------------------------------" | ||
| # "step 4. Datapath configuration" | ||
| # "step 4.a. Write to upper page 10h bytes 145 - 152 to select 100G-FR" | ||
| # " application on all host lane" | ||
| # "-------------------------------------------------------------------------" | ||
| sudo i2cset -f -y $port 0x50 0x7f 0x10 | ||
| # "write 145 - 152" | ||
| sudo i2cset -f -y $port 0x50 0x91 0x21 | ||
| sudo i2cset -f -y $port 0x50 0x92 0x21 | ||
| sudo i2cset -f -y $port 0x50 0x93 0x25 | ||
| sudo i2cset -f -y $port 0x50 0x94 0x25 | ||
| sudo i2cset -f -y $port 0x50 0x95 0x29 | ||
| sudo i2cset -f -y $port 0x50 0x96 0x29 | ||
| sudo i2cset -f -y $port 0x50 0x97 0x2d | ||
| sudo i2cset -f -y $port 0x50 0x98 0x2d | ||
|
|
||
| # "-------------------------------------------------------------------------" | ||
| # "step 4.b. Write 0xff to page 10h byte 143" | ||
| # " Apply DataPathInit..." | ||
| # "-------------------------------------------------------------------------" | ||
| sudo i2cset -f -y $port 0x50 0x7f 0x10 | ||
| sudo i2cset -f -y $port 0x50 0x8f 0xff | ||
| sleep 0.2 | ||
|
|
||
| # "-------------------------------------------------------------------------" | ||
| # "step 4.c. Check configuration errors codes in page 11h byte 202 - 205" | ||
| # "-------------------------------------------------------------------------" | ||
| sudo i2cset -f -y $port 0x50 0x7f 0x11 | ||
|
|
||
| # "-------------------------------------------------------------------------" | ||
| # "step 5. Datapath activation Write the corresponding values to upper page" | ||
| # " 10h byte 128 (to power up the DP lanes)" | ||
| # "-------------------------------------------------------------------------" | ||
| sudo i2cset -f -y $port 0x50 0x7f 0x10 | ||
| sudo i2cset -f -y $port 0x50 0x80 0x00 | ||
|
|
||
| sudo i2cset -f -y $port 0x50 0x7f 0 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| #!/bin/bash | ||
|
|
||
| # Configure transceiver module into 1x400G mode | ||
|
|
||
| # Usage: | ||
| # ./cmis4_init.sh $port_i2c_no | ||
| # | ||
| port=$1 | ||
|
|
||
| # "=========================================================================" | ||
| # "Init CMIS 4.0 module in port $port" | ||
| # "=========================================================================" | ||
|
|
||
| # "-------------------------------------------------------------------------" | ||
| # " Set page 00h before start configuration..." | ||
| # "-------------------------------------------------------------------------" | ||
| sudo i2cset -f -y $port 0x50 0x7f 0 | ||
|
|
||
| # "-------------------------------------------------------------------------" | ||
| # "step 1. SW reset module" | ||
| # "-------------------------------------------------------------------------" | ||
| sudo i2cset -f -y $port 0x50 26 0x08 | ||
| sleep 0.2 | ||
|
|
||
| # "-------------------------------------------------------------------------" | ||
| # "step 2. deinitialize datapath" | ||
| # "-------------------------------------------------------------------------" | ||
| sudo i2cset -f -y $port 0x50 127 0x10 | ||
| sudo i2cset -f -y $port 0x50 128 0xff | ||
|
|
||
| # "-------------------------------------------------------------------------" | ||
| # "step 3. enable hi-power mode" | ||
| # "-------------------------------------------------------------------------" | ||
| sudo i2cset -f -y $port 0x50 26 0x00 | ||
| sleep 0.2 | ||
|
|
||
| # "-------------------------------------------------------------------------" | ||
| # "step 4. Datapath configuration" | ||
| # "step 4.a. Write 0xff to page 10h byte 143" | ||
| # " Apply DataPathInit..." | ||
| # "-------------------------------------------------------------------------" | ||
| sudo i2cset -f -y $port 0x50 0x7f 0x10 | ||
| sudo i2cset -f -y $port 0x50 0x8f 0xff | ||
| sleep 0.2 | ||
|
|
||
| # "-------------------------------------------------------------------------" | ||
| # "step 4.b. Check configuration errors codes in page 11h byte 202 - 205" | ||
| # "-------------------------------------------------------------------------" | ||
| sudo i2cset -f -y $port 0x50 0x7f 0x11 | ||
|
|
||
| # "-------------------------------------------------------------------------" | ||
| # "step 5. Datapath activation Write the corresponding values to upper page" | ||
| # " 10h byte 128 (to power up the DP lanes)" | ||
| # "-------------------------------------------------------------------------" | ||
| sudo i2cset -f -y $port 0x50 0x7f 0x10 | ||
| sudo i2cset -f -y $port 0x50 0x80 0x00 | ||
|
|
||
| sudo i2cset -f -y $port 0x50 0x7f 0 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,7 +5,9 @@ | |
|
|
||
| try: | ||
| import time | ||
| import subprocess | ||
| from sonic_platform_base.sonic_sfp.sfputilbase import SfpUtilBase | ||
| from sonic_platform_base.sonic_sfp.sff8024 import type_of_transceiver | ||
| from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId, sff8472Dom | ||
| from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId, sff8436Dom | ||
| from sonic_platform_base.sonic_sfp.inf8628 import inf8628InterfaceId | ||
|
|
@@ -15,6 +17,12 @@ | |
| raise ImportError("%s - required module not found" % str(e)) | ||
|
|
||
|
|
||
| PLATFORM_ROOT_PATH = '/usr/share/sonic/device' | ||
| SONIC_CFGGEN_PATH = '/usr/local/bin/sonic-cfggen' | ||
| HWSKU_KEY = 'DEVICE_METADATA.localhost.hwsku' | ||
| PLATFORM_KEY = 'DEVICE_METADATA.localhost.platform' | ||
|
|
||
|
|
||
| class QSFPDDDomPaser(qsfp_dd_Dom): | ||
|
|
||
| def __init__(self, eeprom_raw_data): | ||
|
|
@@ -174,6 +182,94 @@ def get_data_pretty(self): | |
| return sffbase.get_data_pretty(self, self.dom_data) | ||
|
|
||
|
|
||
| class SfpEvent: | ||
| ''' Listen to insert/remove sfp events ''' | ||
|
|
||
| PATH_INT_SYSFS = "{0}/{port_name}/qsfp_isr_flags" | ||
| PATH_INTMASK_SYSFS = "{0}/{port_name}/qsfp_isr_mask" | ||
| PATH_PRS_SYSFS = "{0}/{port_name}/qsfp_modprs" | ||
| PRESENT_EN = 0x01 | ||
|
|
||
| def __init__(self, num_port, port_info_path): | ||
| self.num_sfp = num_port | ||
| self.port_info_path = port_info_path | ||
| self.__initialize_interrupts() | ||
|
|
||
| def __initialize_interrupts(self): | ||
| # Initial Interrupt MASK for QSFP, SFP | ||
| sfp_info_obj = {} | ||
|
|
||
| for index in range(self.num_sfp): | ||
| port_num = index + 1 | ||
| port_name = "QSFP{}".format(port_num) | ||
|
|
||
| sfp_info_obj[index] = {} | ||
| sfp_info_obj[index]['intmask_sysfs'] = self.PATH_INTMASK_SYSFS.format( | ||
| self.port_info_path, | ||
| port_name=port_name) | ||
|
|
||
| sfp_info_obj[index]['int_sysfs'] = self.PATH_INT_SYSFS.format( | ||
| self.port_info_path, | ||
| port_name=port_name) | ||
|
|
||
| sfp_info_obj[index]['prs_sysfs'] = self.PATH_PRS_SYSFS.format( | ||
| self.port_info_path, | ||
| port_name=port_name) | ||
|
|
||
| self._write_file( | ||
| sfp_info_obj[index]["intmask_sysfs"], hex(self.PRESENT_EN)) | ||
|
|
||
| self.sfp_info_obj = sfp_info_obj | ||
|
|
||
| def _write_file(self, file_path, data): | ||
| try: | ||
| with open(file_path, 'w') as fd: | ||
| fd.write(str(data)) | ||
| return True | ||
| except Exception as e: | ||
| print "Error: unable to read file: %s" % str(e) | ||
| return False | ||
|
|
||
| def _read_txt_file(self, file_path): | ||
| try: | ||
| with open(file_path, 'r') as fd: | ||
| data = fd.read() | ||
| return data.strip() | ||
| except IOError as e: | ||
| print "Error: unable to read file: %s" % str(e) | ||
| return None | ||
|
|
||
| def _is_port_device_present(self, port_idx): | ||
| prs_path = self.sfp_info_obj[port_idx]["prs_sysfs"] | ||
| is_present = 0 | ||
| try: | ||
| is_present = 1 - int(self._read_txt_file(prs_path)) | ||
| except Exception as e: | ||
| print "Error: invaid data in device present sysfs: %s" % str(e) | ||
| return is_present | ||
|
|
||
| def _clear_event_flag(self, path): | ||
| self._write_file(path, hex(0xff)) | ||
| time.sleep(0.1) | ||
| self._write_file(path, hex(0x0)) | ||
|
|
||
| def update_port_event_object(self, interrup_devices, port_dict): | ||
| for port_idx in interrup_devices: | ||
| device_id = str(port_idx + 1) | ||
| port_dict[device_id] = str(self._is_port_device_present(port_idx)) | ||
| return port_dict | ||
|
|
||
| def check_all_port_interrupt_event(self): | ||
| interrupt_devices = {} | ||
| for i in range(self.num_sfp): | ||
| int_sysfs = self.sfp_info_obj[i]["int_sysfs"] | ||
| interrupt_flags = self._read_txt_file(int_sysfs) | ||
|
||
| if interrupt_flags == '0x01': | ||
| interrupt_devices[i] = 1 | ||
| self._clear_event_flag(int_sysfs) | ||
| return interrupt_devices | ||
|
|
||
|
|
||
| class SfpUtil(SfpUtilBase): | ||
| """Platform-specific SfpUtil class""" | ||
|
|
||
|
|
@@ -184,10 +280,15 @@ class SfpUtil(SfpUtilBase): | |
| SFP_PORT_START = 33 | ||
| SFP_PORT_END = 34 | ||
|
|
||
| NUM_OSFP = 32 | ||
|
|
||
| EEPROM_OFFSET = 9 | ||
| PORT_INFO_PATH = '/sys/class/silverstone_fpga' | ||
| QSFP_DD_DOM_OFFSET = 2304 | ||
|
|
||
| # polling interval in seconds | ||
| POLL_INTERVAL = 1 | ||
|
||
|
|
||
| _port_name = "" | ||
| _port_to_eeprom_mapping = {} | ||
| _port_to_i2cbus_mapping = {} | ||
|
|
@@ -344,11 +445,96 @@ def reset(self, port_num): | |
|
|
||
| return True | ||
|
|
||
| def _run_command(self, cmd): | ||
| status = True | ||
| result = "" | ||
| try: | ||
| p = subprocess.Popen( | ||
| cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||
| raw_data, err = p.communicate() | ||
| if err == '': | ||
| result = raw_data.strip() | ||
| except Exception as e: | ||
| print "Error: unable to run command: %s" % str(e) | ||
| status = False | ||
| return status, result | ||
|
|
||
| def _init_cmis_module(self, int_sfp, init_script): | ||
| # Workaround script for cmis module | ||
| for port_num in int_sfp: | ||
| # Check if it's the module insert event. | ||
| if int_sfp[port_num] == '1': | ||
|
||
| i2c_num = int(port_num) + self.EEPROM_OFFSET | ||
|
|
||
| # run cmis init script | ||
| init_cmd = "bash {} {}".format(init_script, i2c_num) | ||
| self._run_command(init_cmd) | ||
|
|
||
| def _get_platform_and_hwsku(self): | ||
| try: | ||
| proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-H', '-v', PLATFORM_KEY], | ||
| stdout=subprocess.PIPE, | ||
| shell=False, | ||
| stderr=subprocess.STDOUT) | ||
| stdout = proc.communicate()[0] | ||
| proc.wait() | ||
| platform = stdout.rstrip('\n') | ||
|
|
||
| proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-d', '-v', HWSKU_KEY], | ||
| stdout=subprocess.PIPE, | ||
| shell=False, | ||
| stderr=subprocess.STDOUT) | ||
| stdout = proc.communicate()[0] | ||
| proc.wait() | ||
| hwsku = stdout.rstrip('\n') | ||
| except OSError, e: | ||
| raise OSError("Cannot detect platform") | ||
|
|
||
| return (platform, hwsku) | ||
|
|
||
| def get_path_to_cmis_init_file(self): | ||
| (platform, hwsku) = self._get_platform_and_hwsku() | ||
| platform_path = "/".join([PLATFORM_ROOT_PATH, platform]) | ||
| hwsku_path = "/".join([platform_path, hwsku]) | ||
| cmis_init_file_path = "/".join([hwsku_path, "cmis-init.sh"]) | ||
| return cmis_init_file_path | ||
|
|
||
| def get_transceiver_change_event(self, timeout=0): | ||
| """ | ||
| TBD | ||
| :param timeout in milliseconds. The method is a blocking call. When timeout is | ||
| zero, it only returns when there is change event, i.e., transceiver plug-in/out | ||
| event. When timeout is non-zero, the function can also return when the timer expires. | ||
| When timer expires, the return status is True and events is empty. | ||
| :returns: (status, events) | ||
| :status: Boolean, True if call successful and no system level event/error occurred, | ||
| False if call not success or system level event/error occurred. | ||
| :events: dictionary for physical port index and the SFP status, | ||
| status='1' represent plug in, '0' represent plug out like {'0': '1', '31':'0'} | ||
| when it comes to system level event/error, the index will be '-1', | ||
| and status can be 'system_not_ready', 'system_become_ready', 'system_fail', | ||
| like {'-1':'system_not_ready'}. | ||
| """ | ||
| raise NotImplementedError | ||
| cmis_init_script = self.get_path_to_cmis_init_file() | ||
| sfp_event = SfpEvent(self.NUM_OSFP, self.PORT_INFO_PATH) | ||
| start_milli_time = int(round(time.time() * 1000)) | ||
| timeout_in_sec = timeout/1000.0 | ||
| int_sfp = {} | ||
|
|
||
| sleep_time = min( | ||
| timeout_in_sec, self.POLL_INTERVAL) if timeout_in_sec != 0 else self.POLL_INTERVAL | ||
| while True: | ||
| chk_sfp = sfp_event.check_all_port_interrupt_event() | ||
| int_sfp = sfp_event.update_port_event_object( | ||
| chk_sfp, int_sfp) if chk_sfp else int_sfp | ||
|
|
||
| current_milli_time = int(round(time.time() * 1000)) | ||
| if int_sfp or (timeout != 0 and current_milli_time - start_milli_time > timeout): | ||
| self._init_cmis_module(int_sfp, cmis_init_script) | ||
| break | ||
|
|
||
| time.sleep(sleep_time) | ||
|
|
||
| return True, int_sfp | ||
|
|
||
| def get_qsfp_data(self, eeprom_ifraw): | ||
| sfp_data = {} | ||
|
|
@@ -379,7 +565,7 @@ def get_eeprom_dict(self, port_num): | |
| sfp_data['interface'] = sfpi_obj.get_data_pretty() | ||
|
|
||
| # check if it is a 100G module | ||
| if sfp_data['interface']['data']['Identifier'] == 'QSFP28 or later': | ||
| if sfp_data['interface']['data']['Identifier'] not in [type_of_transceiver['18'], type_of_transceiver['19']]: | ||
| return self.get_qsfp_data(eeprom_ifraw) | ||
|
|
||
| sfpd_obj = QSFPDDDomPaser( | ||
|
|
||
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.
make this function return true or false, not a number that could be anything.