Skip to content

[device/celestica]: Add xcvrd event support for Haliburton #6517

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

Merged
merged 6 commits into from
Mar 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
205 changes: 177 additions & 28 deletions device/celestica/x86_64-cel_e1031-r0/sonic_platform/chassis.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,11 @@
import json

try:
from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper
from sonic_platform_base.chassis_base import ChassisBase
from sonic_platform.fan import Fan
from sonic_platform.psu import Psu
from sonic_platform.component import Component
from sonic_platform.thermal import Thermal
from sonic_platform.sfp import Sfp
from sonic_platform.eeprom import Tlv
from sonic_py_common import device_info
from .event import SfpEvent
from .helper import APIHelper
except ImportError as e:
raise ImportError(str(e) + "- required module not found")

Expand All @@ -40,29 +38,62 @@ class Chassis(ChassisBase):

def __init__(self):
ChassisBase.__init__(self)
self.config_data = {}
self._api_helper = APIHelper()
self.sfp_module_initialized = False
self.__initialize_eeprom()
self.is_host = self._api_helper.is_host()


if not self.is_host:
self.__initialize_fan()
self.__initialize_psu()
self.__initialize_thermals()
else:
self.__initialize_components()

self._reboot_cause_path = HOST_REBOOT_CAUSE_PATH if self.__is_host(
) else PMON_REBOOT_CAUSE_PATH

def __initialize_sfp(self):
sfputil_helper = SfpUtilHelper()
port_config_file_path = device_info.get_path_to_port_config_file()
sfputil_helper.read_porttab_mappings(port_config_file_path, 0)

from sonic_platform.sfp import Sfp
for index in range(0, NUM_SFP):
name_idx = 0 if index+1 == NUM_SFP else index+1
sfp = Sfp(index, sfputil_helper.logical[name_idx])
self._sfp_list.append(sfp)
self.sfp_module_initialized = True

def __initialize_psu(self):
from sonic_platform.psu import Psu
for index in range(0, NUM_PSU):
psu = Psu(index)
self._psu_list.append(psu)

def __initialize_fan(self):
from sonic_platform.fan import Fan
for fant_index in range(0, NUM_FAN_TRAY):
for fan_index in range(0, NUM_FAN):
fan = Fan(fant_index, fan_index)
self._fan_list.append(fan)
for index in range(0, NUM_PSU):
psu = Psu(index)
self._psu_list.append(psu)

def __initialize_thermals(self):
from sonic_platform.thermal import Thermal
for index in range(0, NUM_THERMAL):
thermal = Thermal(index)
self._thermal_list.append(thermal)
# sfp index start from 1
self._sfp_list.append(None)
for index in range(1, NUM_SFP+1):
sfp = Sfp(index)
self._sfp_list.append(sfp)

def __initialize_eeprom(self):
from sonic_platform.eeprom import Tlv
self._eeprom = Tlv()

def __initialize_components(self):
from sonic_platform.component import Component
for index in range(0, NUM_COMPONENT):
component = Component(index)
self._component_list.append(component)
self._reboot_cause_path = HOST_REBOOT_CAUSE_PATH if self.__is_host(
) else PMON_REBOOT_CAUSE_PATH

self._eeprom = Tlv()

def __is_host(self):
return os.system(HOST_CHK_CMD) == 0
Expand All @@ -85,14 +116,6 @@ def get_base_mac(self):
"""
return self._eeprom.get_mac()

def get_serial(self):
"""
Retrieves the hardware serial number for the chassis
Returns:
A string containing the hardware serial number for this chassis.
"""
return self._eeprom.get_serial()

def get_system_eeprom_info(self):
"""
Retrieves the full content of system EEPROM information for the chassis
Expand All @@ -116,7 +139,8 @@ def get_reboot_cause(self):
"""
description = 'None'
reboot_cause = self.REBOOT_CAUSE_HARDWARE_OTHER
hw_reboot_cause = self._component_list[0].get_register_value(RESET_REGISTER)
hw_reboot_cause = self._component_list[0].get_register_value(
RESET_REGISTER)
sw_reboot_cause = self.__read_txt_file(
self._reboot_cause_path) or "Unknown"

Expand Down Expand Up @@ -145,3 +169,128 @@ def get_watchdog(self):
self._watchdog = Watchdog()

return self._watchdog

def get_change_event(self, timeout=0):
"""
Returns a nested dictionary containing all devices which have
experienced a change at chassis level
Args:
timeout: Timeout in milliseconds (optional). If timeout == 0,
this method will block until a change is detected.
Returns:
(bool, dict):
- True if call successful, False if not;
- A nested dictionary where key is a device type,
value is a dictionary with key:value pairs in the format of
{'device_id':'device_event'},
where device_id is the device ID for this device and
device_event,
status='1' represents device inserted,
status='0' represents device removed.
Ex. {'fan':{'0':'0', '2':'1'}, 'sfp':{'11':'0'}}
indicates that fan 0 has been removed, fan 2
has been inserted and sfp 11 has been removed.
"""
# SFP event
if not self.sfp_module_initialized:
self.__initialize_sfp()

sfp_event = SfpEvent(self._sfp_list).get_sfp_event(timeout)
if sfp_event:
return True, {'sfp': sfp_event}

return False, {'sfp': {}}

##############################################################
######################## SFP methods #########################
##############################################################

def get_num_sfps(self):
"""
Retrieves the number of sfps available on this chassis
Returns:
An integer, the number of sfps available on this chassis
"""
if not self.sfp_module_initialized:
self.__initialize_sfp()

return len(self._sfp_list)

def get_all_sfps(self):
"""
Retrieves all sfps available on this chassis
Returns:
A list of objects derived from SfpBase representing all sfps
available on this chassis
"""
if not self.sfp_module_initialized:
self.__initialize_sfp()

return self._sfp_list

def get_sfp(self, index):
"""
Retrieves sfp represented by (1-based) index <index>
Args:
index: An integer, the index (1-based) of the sfp to retrieve.
The index should be the sequence of a physical port in a chassis,
starting from 1.
For example, 1 for Ethernet0, 2 for Ethernet4 and so on.
Returns:
An object dervied from SfpBase representing the specified sfp
"""
sfp = None
if not self.sfp_module_initialized:
self.__initialize_sfp()

try:
# The index will start from 1
sfp = self._sfp_list[index-1]
except IndexError:
sys.stderr.write("SFP index {} out of range (1-{})\n".format(
index, len(self._sfp_list)))
return sfp

##############################################################
###################### Device methods ########################
##############################################################

def get_name(self):
"""
Retrieves the name of the device
Returns:
string: The name of the device
"""
return self._api_helper.hwsku

def get_presence(self):
"""
Retrieves the presence of the Chassis
Returns:
bool: True if Chassis is present, False if not
"""
return True

def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
return self._eeprom.get_pn()

def get_serial(self):
"""
Retrieves the serial number of the device
Returns:
string: Serial number of device
"""
return self._eeprom.get_serial()

def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
return True
62 changes: 62 additions & 0 deletions device/celestica/x86_64-cel_e1031-r0/sonic_platform/event.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
try:
import time
import select
from .helper import APIHelper
from sonic_py_common.logger import Logger
except ImportError as e:
raise ImportError(repr(e) + " - required module not found")


class SfpEvent:
''' Listen to insert/remove sfp events '''

SFP_NUM_START = 49
DELAY = 0.05
INT_PATH = '/sys/devices/platform/e1031.smc/SFP/modabs_int'
GPIO_SUS7 = '/sys/devices/platform/hlx-ich.0/sci_int_gpio_sus7'

def __init__(self, sfp_list):
self._api_helper = APIHelper()
self._sfp_list = sfp_list
self._logger = Logger()

# clear interrupt
self._api_helper.read_one_line_file(self.INT_PATH)

def get_sfp_event(self, timeout):
epoll = select.epoll()
port_dict = {}
timeout_sec = timeout/1000

try:
# We get notified when there is an SCI interrupt from GPIO SUS7
fd = open(self.GPIO_SUS7, "r")
fd.read()

epoll.register(fd.fileno(), select.EPOLLIN & select.EPOLLET)
events = epoll.poll(timeout=timeout_sec if timeout != 0 else -1)
if events:
# Read the QSFP ABS interrupt & status registers
port_changes = self._api_helper.read_one_line_file(
self.INT_PATH)
changes = int(port_changes, 16)
for sfp in self._sfp_list:
if sfp.port_num < self.SFP_NUM_START:
continue

change = (changes >> sfp.port_num-self.SFP_NUM_START) & 1
if change == 1:
time.sleep(self.DELAY)
port_status = sfp.get_presence()
port_dict[str(sfp.port_num)] = '1' if port_status else '0'

return port_dict
except Exception as e:
self._logger.log_error("Failed to detect SfpEvent - " + repr(e))
return False

finally:
fd.close()
epoll.close()

return False
8 changes: 8 additions & 0 deletions device/celestica/x86_64-cel_e1031-r0/sonic_platform/fan.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,3 +247,11 @@ def get_presence(self):
present_str = self.__read_txt_file(fan_direction_file) or '1'

return int(present_str) == 0 if not self.is_psu_fan else True

def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
return self.get_presence() and self.get_speed() > 0
Loading