Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
192 changes: 189 additions & 3 deletions device/celestica/x86_64-cel_silverstone-r0/plugins/sfputil.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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):
Expand Down Expand Up @@ -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):
Copy link
Copy Markdown
Owner

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.

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)
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same thing here.

if interrupt_flags == '0x01':
interrupt_devices[i] = 1
self._clear_event_flag(int_sysfs)
return interrupt_devices


class SfpUtil(SfpUtilBase):
"""Platform-specific SfpUtil class"""

Expand All @@ -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
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this seconds or miliseconds, please make a comment.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated


_port_name = ""
_port_to_eeprom_mapping = {}
_port_to_i2cbus_mapping = {}
Expand Down Expand Up @@ -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':
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make a comment here, and what "1" means?

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 = {}
Expand Down Expand Up @@ -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(
Expand Down
Loading