Skip to content

Commit

Permalink
[Mellanox] Enhance Platform API to support SN2201 - RJ45 ports and ne…
Browse files Browse the repository at this point in the history
…w components mgmt. (sonic-net#10377)

* Support new platform SN2201 and RJ45 port

Signed-off-by: Kebo Liu <kebol@nvidia.com>

* remove unused import and redundant function

Signed-off-by: Kebo Liu <kebol@nvidia.com>

* fix error introduced by rebase

Signed-off-by: Kebo Liu <kebol@nvidia.com>

* Revert the special handling of RJ45 ports (#56)

* Revert the special handling of RJ45 ports

sfp.py
sfp_event.py
chassis.py

Signed-off-by: Stephen Sun <stephens@nvidia.com>

* Remove deadcode

Signed-off-by: Stephen Sun <stephens@nvidia.com>

* Support CPLD update for SN2201

A new class is introduced, deriving from ComponentCPLD and overloading _install_firmware
Change _install_firmware from private (starting with __) to protected, making it overloadable

Signed-off-by: Stephen Sun <stephens@nvidia.com>

* Initialize component BIOS/CPLD

Signed-off-by: Stephen Sun <stephens@nvidia.com>

* Remove swb_amb which doesn't on DVT board any more

Signed-off-by: Stephen Sun <stephens@nvidia.com>

* Remove the unexisted sensor - switch board ambient - from platform.json

Signed-off-by: Stephen Sun <stephens@nvidia.com>

* Do not report error on receiving unknown status on RJ45 ports

Translate it to disconnect for RJ45 ports
Report error for xSFP ports

Signed-off-by: Stephen Sun <stephens@nvidia.com>

* Add reinit for RJ45 to avoid exception

Signed-off-by: Stephen Sun <stephens@nvidia.com>

Co-authored-by: Stephen Sun <5379172+stephenxs@users.noreply.github.com>
Co-authored-by: Stephen Sun <stephens@nvidia.com>
  • Loading branch information
3 people authored and yxieca committed Jul 28, 2022
1 parent 71f47ed commit 2f59460
Show file tree
Hide file tree
Showing 15 changed files with 569 additions and 65 deletions.
3 changes: 0 additions & 3 deletions device/mellanox/x86_64-nvidia_sn2201-r0/platform.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,6 @@
{
"name": "Ambient CPU Board Temp"
},
{
"name": "Ambient Switch Board Temp"
},
{
"name": "CPU Pack Temp"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"component": {
"ONIE": { },
"SSD": { },
"BIOS": { },
"CPLD1": { },
"CPLD2": { }
}
Expand Down
33 changes: 25 additions & 8 deletions platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,17 @@
from sonic_py_common.logger import Logger
import os
from functools import reduce

from .utils import extract_RJ45_ports_index
from . import utils
from .device_data import DeviceDataManager
from .sfp import SFP, RJ45Port, deinitialize_sdk_handle
except ImportError as e:
raise ImportError (str(e) + "- required module not found")

MAX_SELECT_DELAY = 3600

RJ45_TYPE = "RJ45"

DMI_FILE = '/sys/firmware/dmi/entries/2-0/raw'
DMI_HEADER_LEN = 15
DMI_PRODUCT_NAME = "Product Name"
Expand Down Expand Up @@ -106,6 +109,10 @@ def __init__(self):
self.sfp_initialized_count = 0
self.sfp_event = None
self.reboot_cause_initialized = False

# Build the RJ45 port list from platform.json and hwsku.json
self.RJ45_port_list = extract_RJ45_ports_index()

logger.log_info("Chassis loaded successfully")

def __del__(self):
Expand Down Expand Up @@ -242,22 +249,31 @@ def initialize_single_sfp(self, index):

if not self._sfp_list[index]:
from .sfp import SFP
self._sfp_list[index] = SFP(index)
if self.RJ45_port_list and index in self.RJ45_port_list:
self._sfp_list[index] = RJ45Port(index)
else:
self._sfp_list[index] = SFP(index)
self.sfp_initialized_count += 1

def initialize_sfp(self):
if not self._sfp_list:
from .sfp import SFP
sfp_count = self.get_num_sfps()
for index in range(sfp_count):
sfp_module = SFP(index)
if self.RJ45_port_list and index in self.RJ45_port_list:
sfp_module = RJ45Port(index)
else:
sfp_module = SFP(index)
self._sfp_list.append(sfp_module)
self.sfp_initialized_count = sfp_count
elif self.sfp_initialized_count != len(self._sfp_list):
from .sfp import SFP
for index in range(len(self._sfp_list)):
if self._sfp_list[index] is None:
self._sfp_list[index] = SFP(index)
if self.RJ45_port_list and index in self.RJ45_port_list:
self._sfp_list[index] = RJ45Port(index)
else:
self._sfp_list[index] = SFP(index)
self.sfp_initialized_count = len(self._sfp_list)

def get_num_sfps(self):
Expand Down Expand Up @@ -324,7 +340,7 @@ def get_change_event(self, timeout=0):
# Initialize SFP event first
if not self.sfp_event:
from .sfp_event import sfp_event
self.sfp_event = sfp_event()
self.sfp_event = sfp_event(self.RJ45_port_list)
self.sfp_event.initialize()

wait_for_ever = (timeout == 0)
Expand All @@ -340,7 +356,8 @@ def get_change_event(self, timeout=0):
status = self.sfp_event.check_sfp_status(port_dict, error_dict, timeout)

if status:
self.reinit_sfps(port_dict)
if port_dict:
self.reinit_sfps(port_dict)
result_dict = {'sfp':port_dict}
if error_dict:
result_dict['sfp_error'] = error_dict
Expand Down Expand Up @@ -515,8 +532,8 @@ def initialize_components(self):
from .component import ComponentONIE, ComponentSSD, ComponentBIOS, ComponentCPLD
self._component_list.append(ComponentONIE())
self._component_list.append(ComponentSSD())
self._component_list.append(ComponentBIOS())
self._component_list.extend(ComponentCPLD.get_component_list())
self._component_list.append(DeviceDataManager.get_bios_component())
self._component_list.extend(DeviceDataManager.get_cpld_component_list())

def get_num_components(self):
"""
Expand Down
71 changes: 66 additions & 5 deletions platform/mellanox/mlnx-platform-api/sonic_platform/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import glob
import tempfile
import subprocess
from sonic_py_common import device_info
if sys.version_info[0] > 2:
import configparser
else:
Expand Down Expand Up @@ -136,7 +137,17 @@ class ONIEUpdater(object):

ONIE_IMAGE_INFO_COMMAND = '/bin/bash {} -q -i'

# Upgrading fireware from ONIE is not supported from the beginning on some platforms, like SN2700.
# There is a logic to check the ONIE version in order to know whether it is supported.
# If it is not supported, we will not proceed and print some error message.
# For SN2201, upgrading fireware from ONIE is supported from day one so we do not need to check it.
PLATFORM_ALWAYS_SUPPORT_UPGRADE = ['x86_64-nvidia_sn2201-r0']

BIOS_UPDATE_FILE_EXT = '.rom'


def __init__(self):
self.platform = device_info.get_platform()

def __add_prefix(self, image_path):
if self.BIOS_UPDATE_FILE_EXT not in image_path:
Expand Down Expand Up @@ -336,6 +347,9 @@ def update_firmware(self, image_path, allow_reboot=True):
raise

def is_non_onie_firmware_update_supported(self):
if self.platform in self.PLATFORM_ALWAYS_SUPPORT_UPGRADE:
return True

current_version = self.get_onie_version()
_, _, major1, minor1, release1, _ = self.parse_onie_version(current_version)
version1 = int("{}{}{}".format(major1, minor1, release1))
Expand Down Expand Up @@ -698,6 +712,37 @@ def update_firmware(self, image_path):
self.__install_firmware(image_path)


class ComponentBIOSSN2201(Component):
COMPONENT_NAME = 'BIOS'
COMPONENT_DESCRIPTION = 'BIOS - Basic Input/Output System'

BIOS_VERSION_COMMAND = 'dmidecode -t0'

def __init__(self):
super(ComponentBIOSSN2201, self).__init__()

self.name = self.COMPONENT_NAME
self.description = self.COMPONENT_DESCRIPTION

def get_firmware_version(self):
cmd = self.BIOS_VERSION_COMMAND

try:
output = subprocess.check_output(cmd.split(),
stderr=subprocess.STDOUT,
universal_newlines=True).rstrip('\n')
except subprocess.CalledProcessError as e:
raise RuntimeError("Failed to get {} version: {}".format(self.name, str(e)))

match = re.search('Version: (.*)', output)
if match:
version = match.group(1)
else:
version = 'Unknown version'

return version


class ComponentCPLD(Component):
COMPONENT_NAME = 'CPLD{}'
COMPONENT_DESCRIPTION = 'CPLD - Complex Programmable Logic Device'
Expand Down Expand Up @@ -744,7 +789,7 @@ def __get_mst_device(self):

return mst_dev_list[0]

def __install_firmware(self, image_path):
def _install_firmware(self, image_path):
if not self._check_file_validity(image_path):
return False

Expand Down Expand Up @@ -830,9 +875,9 @@ def install_firmware(self, image_path):
burn_firmware = mpfa.get_metadata().get('firmware', 'burn')

print("INFO: Processing {} burn file: firmware install".format(self.name))
return self.__install_firmware(os.path.join(mpfa.get_path(), burn_firmware))
return self._install_firmware(os.path.join(mpfa.get_path(), burn_firmware))
else:
return self.__install_firmware(image_path)
return self._install_firmware(image_path)

def update_firmware(self, image_path):
with MPFAManager(image_path) as mpfa:
Expand All @@ -845,11 +890,11 @@ def update_firmware(self, image_path):
refresh_firmware = mpfa.get_metadata().get('firmware', 'refresh')

print("INFO: Processing {} burn file: firmware install".format(self.name))
if not self.__install_firmware(os.path.join(mpfa.get_path(), burn_firmware)):
if not self._install_firmware(os.path.join(mpfa.get_path(), burn_firmware)):
return

print("INFO: Processing {} refresh file: firmware update".format(self.name))
self.__install_firmware(os.path.join(mpfa.get_path(), refresh_firmware))
self._install_firmware(os.path.join(mpfa.get_path(), refresh_firmware))

@classmethod
def get_component_list(cls):
Expand All @@ -862,3 +907,19 @@ def get_component_list(cls):
component_list.append(cls(cpld_idx))

return component_list


class ComponentCPLDSN2201(ComponentCPLD):
CPLD_FIRMWARE_UPDATE_COMMAND = 'cpldupdate --gpio {} --uncustomized --print-progress'

def _install_firmware(self, image_path):
cmd = self.CPLD_FIRMWARE_UPDATE_COMMAND.format(image_path)

try:
print("INFO: Installing {} firmware update: path={}".format(self.name, image_path))
subprocess.check_call(cmd.split(), universal_newlines=True)
except subprocess.CalledProcessError as e:
print("ERROR: Failed to update {} firmware: {}".format(self.name, str(e)))
return False

return True
21 changes: 19 additions & 2 deletions platform/mellanox/mlnx-platform-api/sonic_platform/device_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,7 @@
'thermal': {
"capability": {
"comex_amb": False,
"cpu_amb": True,
"swb_amb": True
"cpu_amb": True
}
}
},
Expand Down Expand Up @@ -281,3 +280,21 @@ def get_cpu_thermal_threshold(cls):
return None, None

return thermal_data.get('cpu_threshold', (None, None))

@classmethod
def get_bios_component(cls):
from .component import ComponentBIOS, ComponentBIOSSN2201
if cls.get_platform_name() in ['x86_64-nvidia_sn2201-r0']:
# For SN2201, special chass is required for handle BIOS
# Currently, only fetching BIOS version is supported
return ComponentBIOSSN2201()
return ComponentBIOS()

@classmethod
def get_cpld_component_list(cls):
from .component import ComponentCPLD, ComponentCPLDSN2201
if cls.get_platform_name() in ['x86_64-nvidia_sn2201-r0']:
# For SN2201, special chass is required for handle BIOS
# Currently, only fetching BIOS version is supported
return ComponentCPLDSN2201.get_component_list()
return ComponentCPLD.get_component_list()
Loading

0 comments on commit 2f59460

Please sign in to comment.