diff --git a/device/barefoot/x86_64-accton_as9516_32d-r0/platform.json b/device/barefoot/x86_64-accton_as9516_32d-r0/platform.json index b92b929fb997..044d5a2c025b 100644 --- a/device/barefoot/x86_64-accton_as9516_32d-r0/platform.json +++ b/device/barefoot/x86_64-accton_as9516_32d-r0/platform.json @@ -61,6 +61,45 @@ { "name": "com_e_driver-i2c-4-33:memory-temp" }, + { + "name": "tmp75-i2c-3-48:chip-temp" + }, + { + "name": "tmp75-i2c-3-49:exhaust2-temp" + }, + { + "name": "tmp75-i2c-3-4a:exhaust-temp" + }, + { + "name": "tmp75-i2c-3-4b:intake-temp" + }, + { + "name": "tmp75-i2c-3-4c:tofino-temp" + }, + { + "name": "tmp75-i2c-3-4d:intake2-temp" + }, + { + "name": "coretemp-isa-0000:package-id-0" + }, + { + "name": "coretemp-isa-0000:core-0" + }, + { + "name": "coretemp-isa-0000:core-1" + }, + { + "name": "coretemp-isa-0000:core-2" + }, + { + "name": "coretemp-isa-0000:core-3" + }, + { + "name": "psu_driver-i2c-7-59:psu2-temp1" + }, + { + "name": "psu_driver-i2c-7-59:psu2-temp2" + }, { "name": "psu_driver-i2c-7-59:psu2-temp1" }, diff --git a/device/barefoot/x86_64-accton_as9516_32d-r0/thermal_thresholds.json b/device/barefoot/x86_64-accton_as9516_32d-r0/thermal_thresholds.json new file mode 100644 index 000000000000..fce7b337ea2f --- /dev/null +++ b/device/barefoot/x86_64-accton_as9516_32d-r0/thermal_thresholds.json @@ -0,0 +1,52 @@ +{ + "thermals": [ + { + "com_e_driver-i2c-4-33:cpu-temp" : [99.0, 89.0, 11.0, 1.0] + }, + { + "com_e_driver-i2c-4-33:memory-temp" : [85.0, 75.0, 11.0, 1.0] + }, + { + "tmp75-i2c-3-48:chip-temp" : [90.0, 80.0, 11.0, 1.0] + }, + { + "tmp75-i2c-3-49:exhaust2-temp" : [80.0, 70.0, 11.0, 1.0] + }, + { + "tmp75-i2c-3-4a:exhaust-temp" : [60.0, 50.0, 11.0, 1.0] + }, + { + "tmp75-i2c-3-4b:intake-temp" : [60.0, 50.0, 11.0, 1.0] + }, + { + "tmp75-i2c-3-4c:tofino-temp" : [99.0, 89.0, 11.0, 1.0] + }, + { + "tmp75-i2c-3-4d:intake2-temp" : [60.0, 50.0, 11.0, 1.0] + }, + { + "coretemp-isa-0000:package-id-0" : [80.0, 70.0, 11.0, 1.0] + }, + { + "coretemp-isa-0000:core-0" : [99.0, 89.0, 11.0, 1.0] + }, + { + "coretemp-isa-0000:core-1" : [99.0, 89.0, 11.0, 1.0] + }, + { + "coretemp-isa-0000:core-2" : [99.0, 89.0, 11.0, 1.0] + }, + { + "coretemp-isa-0000:core-3" : [99.0, 89.0, 11.0, 1.0] + }, + { + "psu_driver-i2c-7-59:psu2-temp1" : [60.0, 50.0, 11.0, 1.0] + }, + { + "psu_driver-i2c-7-59:psu2-temp2" : [60.0, 50.0, 11.0, 1.0] + }, + { + "psu_driver-i2c-7-59:psu2-temp3" : [60.0, 50.0, 11.0, 1.0] + } + ] +} \ No newline at end of file diff --git a/device/barefoot/x86_64-accton_wedge100bf_32x-r0/platform.json b/device/barefoot/x86_64-accton_wedge100bf_32x-r0/platform.json index 769386a14ce0..287e419ce8e7 100644 --- a/device/barefoot/x86_64-accton_wedge100bf_32x-r0/platform.json +++ b/device/barefoot/x86_64-accton_wedge100bf_32x-r0/platform.json @@ -49,38 +49,41 @@ } ], "thermals": [ + { + "name": "com_e_driver-i2c-4-33:cpu-temp" + }, { "name": "com_e_driver-i2c-4-33:memory-temp" }, { - "name": "com_e_driver-i2c-4-33:cpu-temp" + "name": "psu_driver-i2c-7-59:psu2-temp1" }, { - "name": "pfe1100-i2c-7-59:temp1" + "name": "psu_driver-i2c-7-59:psu2-temp2" }, { - "name": "pfe1100-i2c-7-59:temp2" + "name": "psu_driver-i2c-7-5a:psu1-temp1" }, { - "name": "pfe1100-i2c-7-5a:temp1" + "name": "psu_driver-i2c-7-5a:psu1-temp2" }, { - "name": "pfe1100-i2c-7-5a:temp2" + "name": "tmp75-i2c-3-48:chip-temp" }, { - "name": "tmp75-i2c-3-48:outlet-middle-temp" + "name": "tmp75-i2c-3-49:exhaust2-temp" }, { - "name": "tmp75-i2c-3-49:inlet-middle-temp" + "name": "tmp75-i2c-3-4a:exhaust-temp" }, { - "name": "tmp75-i2c-3-4a:inlet-left-temp" + "name": "tmp75-i2c-3-4b:intake-temp" }, { - "name": "tmp75-i2c-3-4b:switch-temp" + "name": "tmp75-i2c-3-4c:tofino-temp" }, { - "name": "tmp75-i2c-3-4c:inlet-right-temp" + "name": "tmp75-i2c-3-4d:intake2-temp" }, { "name": "tmp75-i2c-8-48:outlet-right-temp" @@ -88,6 +91,9 @@ { "name": "tmp75-i2c-8-49:outlet-left-temp" }, + { + "name": "pch_haswell-virtual-0:temp1" + }, { "name": "coretemp-isa-0000:package-id-0" }, @@ -102,9 +108,6 @@ }, { "name": "coretemp-isa-0000:core-3" - }, - { - "name": "pch_haswell-virtual-0:temp1" } ], "sfps": [ diff --git a/device/barefoot/x86_64-accton_wedge100bf_32x-r0/thermal_thresholds.json b/device/barefoot/x86_64-accton_wedge100bf_32x-r0/thermal_thresholds.json new file mode 100644 index 000000000000..bee961a84411 --- /dev/null +++ b/device/barefoot/x86_64-accton_wedge100bf_32x-r0/thermal_thresholds.json @@ -0,0 +1,64 @@ +{ + "thermals": [ + { + "com_e_driver-i2c-4-33:cpu-temp" : [99.0, 89.0, 11.0, 1.0] + }, + { + "com_e_driver-i2c-4-33:memory-temp" : [85.0, 75.0, 11.0, 1.0] + }, + { + "psu_driver-i2c-7-59:psu2-temp1" : [50.0, 40.0, 11.0, 1.0] + }, + { + "psu_driver-i2c-7-59:psu2-temp2" : [90.0, 80.0, 11.0, 1.0] + }, + { + "psu_driver-i2c-7-5a:psu1-temp1" : [50.0, 40.0, 11.0, 1.0] + }, + { + "psu_driver-i2c-7-5a:psu1-temp2" : [90.0, 80.0, 11.0, 1.0] + }, + { + "tmp75-i2c-3-48:chip-temp" : [90.0, 80.0, 11.0, 1.0] + }, + { + "tmp75-i2c-3-49:exhaust2-temp" : [80.0, 70.0, 11.0, 1.0] + }, + { + "tmp75-i2c-3-4a:exhaust-temp" : [60.0, 50.0, 11.0, 1.0] + }, + { + "tmp75-i2c-3-4b:intake-temp" : [60.0, 50.0, 11.0, 1.0] + }, + { + "tmp75-i2c-3-4c:tofino-temp" : [99.0, 89.0, 11.0, 1.0] + }, + { + "tmp75-i2c-3-4d:intake2-temp" : [60.0, 50.0, 11.0, 1.0] + }, + { + "tmp75-i2c-8-48:outlet-right-temp" : [60.0, 50.0, 11.0, 1.0] + }, + { + "tmp75-i2c-8-49:outlet-left-temp" : [60.0, 50.0, 11.0, 1.0] + }, + { + "pch_haswell-virtual-0:temp1" : [60.0, 50.0, 11.0, 1.0] + }, + { + "coretemp-isa-0000:package-id-0" : [80.0, 70.0, 11.0, 1.0] + }, + { + "coretemp-isa-0000:core-0" : [99.0, 89.0, 11.0, 1.0] + }, + { + "coretemp-isa-0000:core-1" : [99.0, 89.0, 11.0, 1.0] + }, + { + "coretemp-isa-0000:core-2" : [99.0, 89.0, 11.0, 1.0] + }, + { + "coretemp-isa-0000:core-3" : [99.0, 89.0, 11.0, 1.0] + } + ] +} \ No newline at end of file diff --git a/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/chassis.py b/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/chassis.py index fac75ae518a9..9552ad5fd070 100644 --- a/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/chassis.py +++ b/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/chassis.py @@ -10,6 +10,7 @@ from sonic_platform.fan_drawer import fan_drawer_list_get from sonic_platform.thermal import thermal_list_get from eeprom import Eeprom + from sonic_platform.thermal_manager import ThermalManager from sonic_platform.platform_thrift_client import pltfm_mgr_ready from sonic_platform.platform_thrift_client import thrift_try @@ -40,6 +41,12 @@ def __init__(self): self.__thermals = None self.__psu_list = None self.__sfp_list = None + self.__thermal_mngr = None + self.__polling_thermal_time = 30 + + self.ready = False + self.phy_port_cur_state = {} + self.qsfp_interval = self.QSFP_CHECK_INTERVAL self.ready = False self.phy_port_cur_state = {} @@ -111,6 +118,16 @@ def _sfp_list(self): def _sfp_list(self, value): pass + @property + def _thermal_mngr(self): + if self.__thermal_mngr is None: + self.__thermal_mngr = ThermalManager(self.__polling_thermal_time) + return self.__thermal_mngr + + @_thermal_mngr.setter + def _thermal_mngr(self, value): + self.__thermal_mngr = ThermalManager(value) + def __update_port_info(self): def qsfp_max_port_get(client): return client.pltfm_mgr.pltfm_mgr_qsfp_get_max_port() @@ -333,3 +350,10 @@ def get_status_led(self): specified. """ return self.system_led + + def get_thermal_manager(self): + return self._thermal_mngr + + def __del__(self): + if self.__thermal_mngr is not None: + self.__thermal_mngr.stop() diff --git a/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/sfp.py b/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/sfp.py index f5d800b749c9..572db5dc3227 100644 --- a/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/sfp.py +++ b/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/sfp.py @@ -2,47 +2,81 @@ try: import os - from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase - from sonic_platform.platform_thrift_client import thrift_try - from sonic_platform.platform_thrift_client import pltfm_mgr_try -except ImportError as e: - raise ImportError (str(e) + "- required module not found") + import sys + import time -SFP_TYPE = "SFP" -QSFP_TYPE = "QSFP" -QSFP_DD_TYPE = "QSFP_DD" + import tempfile + from contextlib import contextmanager + from copy import copy + sys.path.append(os.path.dirname(__file__)) -class Sfp(SfpOptoeBase): - """ - BFN Platform-specific SFP class - """ + from .platform_thrift_client import ThriftClient + from .platform_thrift_client import thrift_try + from .platform_thrift_client import pltfm_mgr_try - SFP_EEPROM_PATH = "/var/run/platform/sfp/" - - def __init__(self, port_num): - SfpOptoeBase.__init__(self) - self.index = port_num - self.port_num = port_num - self.sfp_type = QSFP_TYPE - - if not os.path.exists(self.SFP_EEPROM_PATH): - try: - os.makedirs(self.SFP_EEPROM_PATH) - except OSError as e: - if e.errno != errno.EEXIST: - raise + from sonic_platform_base.sfp_base import SfpBase + from sonic_platform_base.sonic_sfp.sfputilbase import SfpUtilBase +except ImportError as e: + raise ImportError (str(e) + "- required module not found") - self.eeprom_path = self.SFP_EEPROM_PATH + "sfp{}-eeprom-cache".format(self.index) +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" + + PORT_START = 1 + PORT_END = 0 + PORTS_IN_BLOCK = 0 + QSFP_PORT_START = 1 + QSFP_PORT_END = 0 + EEPROM_OFFSET = 0 + QSFP_CHECK_INTERVAL = 4 + + @property + def port_start(self): + self.update_port_info() + return self.PORT_START + + @property + def port_end(self): + self.update_port_info() + return self.PORT_END + + @property + def qsfp_ports(self): + self.update_port_info() + return range(self.QSFP_PORT_START, self.PORTS_IN_BLOCK + 1) + + @property + def port_to_eeprom_mapping(self): + print("dependency on sysfs has been removed") + raise Exception() + + def __init__(self): + self.ready = False + self.phy_port_dict = {'-1': 'system_not_ready'} + self.phy_port_cur_state = {} + self.qsfp_interval = self.QSFP_CHECK_INTERVAL + + SfpUtilBase.__init__(self) + + def update_port_info(self): + def qsfp_max_port_get(client): + return client.pltfm_mgr.pltfm_mgr_qsfp_get_max_port(); + + if self.QSFP_PORT_END == 0: + self.QSFP_PORT_END = thrift_try(qsfp_max_port_get) + self.PORT_END = self.QSFP_PORT_END + self.PORTS_IN_BLOCK = self.QSFP_PORT_END + + def get_presence(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False - def get_presence(self): - """ - Retrieves the presence of the sfp - """ presence = False def qsfp_presence_get(client): - return client.pltfm_mgr.pltfm_mgr_qsfp_presence_get(self.index) + return client.pltfm_mgr.pltfm_mgr_qsfp_presence_get(port_num) try: presence = thrift_try(qsfp_presence_get) @@ -52,41 +86,202 @@ def qsfp_presence_get(client): return presence - def get_lpmode(self): - """ - Retrieves the lpmode (low power mode) status of this SFP - """ + def get_low_power_mode(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + def qsfp_lpmode_get(client): - return client.pltfm_mgr.pltfm_mgr_qsfp_lpmode_get(self.index) + return client.pltfm_mgr.pltfm_mgr_qsfp_lpmode_get(port_num) - return thrift_try(qsfp_lpmode_get) + lpmode = thrift_try(qsfp_lpmode_get) + + return lpmode + + def set_low_power_mode(self, port_num, lpmode): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False - def set_lpmode(self, lpmode): - """ - Sets the lpmode (low power mode) of SFP - """ def qsfp_lpmode_set(client): - return client.pltfm_mgr.pltfm_mgr_qsfp_lpmode_set(self.index, lpmode) + return client.pltfm_mgr.pltfm_mgr_qsfp_lpmode_set(port_num, lpmode) status = thrift_try(qsfp_lpmode_set) + return (status == 0) - def get_eeprom_path(self): + def reset(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + def qsfp_reset(client): + client.pltfm_mgr.pltfm_mgr_qsfp_reset(port_num, True) + return client.pltfm_mgr.pltfm_mgr_qsfp_reset(port_num, False) + + err = thrift_try(qsfp_reset) + + return not err + + def check_transceiver_change(self): + if not self.ready: + return + + self.phy_port_dict = {} + + try: + client = ThriftClient().open() + except Exception: + return + + # Get presence of each SFP + for port in range(self.port_start, self.port_end + 1): + try: + sfp_resent = client.pltfm_mgr.pltfm_mgr_qsfp_presence_get(port) + except Exception: + sfp_resent = False + sfp_state = '1' if sfp_resent else '0' + + if port in self.phy_port_cur_state: + if self.phy_port_cur_state[port] != sfp_state: + self.phy_port_dict[port] = sfp_state + else: + self.phy_port_dict[port] = sfp_state + + # Update port current state + self.phy_port_cur_state[port] = sfp_state + + client.close() + + def get_transceiver_change_event(self, timeout=0): + forever = False + if timeout == 0: + forever = True + elif timeout > 0: + timeout = timeout / float(1000) # Convert to secs + else: + print("get_transceiver_change_event:Invalid timeout value", timeout) + return False, {} + + while forever or timeout > 0: + if not self.ready: + try: + with ThriftClient(): pass + except Exception: + pass + else: + self.ready = True + self.phy_port_dict = {} + break + elif self.qsfp_interval == 0: + self.qsfp_interval = self.QSFP_CHECK_INTERVAL + + # Process transceiver plug-in/out event + self.check_transceiver_change() + + # Break if tranceiver state has changed + if bool(self.phy_port_dict): + break + + if timeout: + timeout -= 1 + + if self.qsfp_interval: + self.qsfp_interval -= 1 + + time.sleep(1) + + return self.ready, self.phy_port_dict + + @contextmanager + def eeprom_action(self): + u = copy(self) + with tempfile.NamedTemporaryFile() as f: + u.eeprom_path = f.name + yield u + + def _sfp_eeprom_present(self, client_eeprompath, offset): + return client_eeprompath and super(SfpUtil, self)._sfp_eeprom_present(client_eeprompath, offset) + + def _get_port_eeprom_path(self, port_num, devid): def qsfp_info_get(client): - return client.pltfm_mgr.pltfm_mgr_qsfp_info_get(self.index) + return client.pltfm_mgr.pltfm_mgr_qsfp_info_get(port_num) - if self.get_presence(): + if self.get_presence(port_num): eeprom_hex = thrift_try(qsfp_info_get) eeprom_raw = bytearray.fromhex(eeprom_hex) - with open(self.eeprom_path, 'wb') as fp: - fp.write(eeprom_raw) + with open(self.eeprom_path, 'wb') as eeprom_cache: + eeprom_cache.write(eeprom_raw) return self.eeprom_path return None - def write_eeprom(self, offset, num_bytes, write_buffer): - # Not supported at the moment - return False +class Sfp(SfpBase): + """Platform-specific Sfp class""" + + sfputil = SfpUtil() + + @staticmethod + def port_start(): + return Sfp.sfputil.port_start + + @staticmethod + def port_end(): + return Sfp.sfputil.port_end + + @staticmethod + def qsfp_ports(): + return Sfp.sfputil.qsfp_ports() + + @staticmethod + def get_transceiver_change_event(timeout=0): + return Sfp.sfputil.get_transceiver_change_event() + + def __init__(self, port_num): + self.port_num = port_num + SfpBase.__init__(self) + + def get_presence(self): + with Sfp.sfputil.eeprom_action() as u: + return u.get_presence(self.port_num) + + def get_lpmode(self): + with Sfp.sfputil.eeprom_action() as u: + return u.get_low_power_mode(self.port_num) + + def set_lpmode(self, lpmode): + with Sfp.sfputil.eeprom_action() as u: + return u.set_low_power_mode(self.port_num, lpmode) + + def reset(self): + return Sfp.sfputil.reset(self.port_num) + + def get_transceiver_info(self): + with Sfp.sfputil.eeprom_action() as u: + return u.get_transceiver_info_dict(self.port_num) + + def get_transceiver_bulk_status(self): + with Sfp.sfputil.eeprom_action() as u: + return u.get_transceiver_dom_info_dict(self.port_num) + + def get_transceiver_threshold_info(self): + with Sfp.sfputil.eeprom_action() as u: + return u.get_transceiver_dom_threshold_info_dict(self.port_num) + + def get_change_event(self, timeout=0): + return Sfp.get_transceiver_change_event(timeout) + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + def qsfp_model_get(client): + return client.pltfm_mgr.pltfm_mgr_qsfp_info_get(self.port_num) + + _, status = pltfm_mgr_try(qsfp_model_get, False) + return status def get_name(self): """ @@ -94,114 +289,92 @@ def get_name(self): Returns: string: The name of the device """ - return "sfp{}".format(self.index) + return "sfp{}".format(self.port_num) def get_reset_status(self): - """ - Retrieves the reset status of SFP - """ def get_qsfp_reset(pltfm_mgr): - return pltfm_mgr.pltfm_mgr_qsfp_reset_get(self.index) + return pltfm_mgr.pltfm_mgr_qsfp_reset_get(self.port_num) _, status = pltfm_mgr_try(get_qsfp_reset, False) return status - def reset(self): - """ - Reset SFP and return all user module settings to their default srate. - """ - def qsfp_reset(client): - client.pltfm_mgr.pltfm_mgr_qsfp_reset(self.index, True) - return client.pltfm_mgr.pltfm_mgr_qsfp_reset(self.index, False) - - err = thrift_try(qsfp_reset) - return not err + def get_rx_los(self): + def get_qsfp_rx_los(pltfm_mgr): + return pltfm_mgr.pltfm_mgr_qsfp_chan_rx_los_get(self.port_num) + _, status = pltfm_mgr_try(get_qsfp_rx_los, False) + return status - def get_status(self): - """ - Retrieves the operational status of the device - """ - reset = self.get_reset_status() + def get_rx_power(self): + def get_qsfp_rx_power(pltfm_mgr): + return pltfm_mgr.pltfm_mgr_qsfp_chan_rx_pwr_get(self.port_num) + _, status = pltfm_mgr_try(get_qsfp_rx_power, False) + return status - if reset: - status = False - else: - status = True + def get_temperature(self): + def get_qsfp_temperature(pltfm_mgr): + return pltfm_mgr.pltfm_mgr_qsfp_temperature_get(self.port_num) + _, status = pltfm_mgr_try(get_qsfp_temperature, False) + return status + + def get_transceiver_threshold_info(self): + def get_qsfp_threshold(pltfm_mgr): + return pltfm_mgr.pltfm_mgr_qsfp_thresholds_get(self.port_num) + _, status = pltfm_mgr_try(get_qsfp_threshold, False) return status - def get_position_in_parent(self): - """ - Retrieves 1-based relative physical position in parent device. - Returns: - integer: The 1-based relative physical position in parent - device or -1 if cannot determine the position - """ - return self.index + def get_tx_bias(self): + def get_qsfp_tx_bias(pltfm_mgr): + return pltfm_mgr.pltfm_mgr_qsfp_chan_tx_bias_get(self.port_num) + _, status = pltfm_mgr_try(get_qsfp_tx_bias, False) + return status + + def get_tx_fault(self): + def get_qsfp_tx_fault(pltfm_mgr): + return pltfm_mgr.pltfm_mgr_qsfp_chan_tx_fault_get(self.port_num) + _, status = pltfm_mgr_try(get_qsfp_tx_fault, False) + return status - def is_replaceable(self): - """ - Indicate whether this device is replaceable. - Returns: - bool: True if it is replaceable. - """ - return True + def get_tx_power(self): + def get_qsfp_tx_power(pltfm_mgr): + return pltfm_mgr.pltfm_mgr_qsfp_chan_tx_pwr_get(self.port_num) + _, status = pltfm_mgr_try(get_qsfp_tx_power, False) + return status - def get_error_description(self): - """ - Retrives the error descriptions of the SFP module - Returns: - String that represents the current error descriptions of vendor specific errors - In case there are multiple errors, they should be joined by '|', - like: "Bad EEPROM|Unsupported cable" - """ - if not self.get_presence(): - return self.SFP_STATUS_UNPLUGGED - return self.SFP_STATUS_OK + def get_voltage(self): + def get_qsfp_voltage(pltfm_mgr): + return pltfm_mgr.pltfm_mgr_qsfp_voltage_get(self.port_num) + _, status = pltfm_mgr_try(get_qsfp_voltage, False) + return status - def tx_disable(self, tx_disable): - """ - Disable SFP TX for all channels - Args: - tx_disable : A Boolean, True to enable tx_disable mode, False to disable - tx_disable mode. - Returns: - A boolean, True if tx_disable is set successfully, False if not - """ - if self.sfp_type == QSFP_TYPE: - return self.tx_disable_channel(0xF, tx_disable) - return False + def get_power_override(self): + def get_qsfp_power_override(pltfm_mgr): + return pltfm_mgr.pltfm_mgr_qsfp_pwr_override_get(self.port_num) + _, status = pltfm_mgr_try(get_qsfp_power_override, False) + return status - def tx_disable_channel(self, channel, disable): - """ - Sets the tx_disable for specified SFP channels + def tx_disable(self): + def get_qsfp_tx_disable(pltfm_mgr): + return pltfm_mgr.pltfm_mgr_qsfp_tx_is_disabled() + _, status = pltfm_mgr_try(get_qsfp_tx_disable, False) + return status - Args: - channel : A hex of 4 bits (bit 0 to bit 3) which represent channel 0 to 3, - e.g. 0x5 for channel 0 and channel 2. - disable : A boolean, True to disable TX channels specified in channel, - False to enable + def tx_disable_channel(self): + def get_qsfp_tx_disable_channel(pltfm_mgr): + return pltfm_mgr.pltfm_mgr_qsfp_tx_disable() + _, status = pltfm_mgr_try(get_qsfp_tx_disable_channel, False) + return status + def is_replaceable(self): + """ + Indicate whether this device is replaceable. Returns: - A boolean, True if successful, False if not + bool: True if it is replaceable. """ - def qsfp_tx_disable_channel(client): - return client.pltfm_mgr.pltfm_mgr_qsfp_tx_disable(self.index, channel, disable) - - if self.sfp_type == QSFP_TYPE: - status = thrift_try(qsfp_tx_disable_channel) - return (status == 0) - return False - - def get_power_override(self): - def get_qsfp_power_override(pltfm_mgr): - return pltfm_mgr.pltfm_mgr_qsfp_pwr_override_get(self.index) - _, pwr_override = pltfm_mgr_try(get_qsfp_power_override) - return pwr_override - - def set_power_override(self, power_override, power_set): - def set_qsfp_power_override(pltfm_mgr): - return pltfm_mgr.pltfm_mgr_qsfp_pwr_override_set( - self.index, power_override, power_set - ) - _, status = pltfm_mgr_try(set_qsfp_power_override) - return status + return True + +def sfp_list_get(): + sfp_list = [] + for index in range(Sfp.port_start(), Sfp.port_end() + 1): + sfp_node = Sfp(index) + sfp_list.append(sfp_node) + return sfp_list diff --git a/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/thermal.py b/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/thermal.py index ef3c571ac301..78ddee039c80 100644 --- a/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/thermal.py +++ b/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/thermal.py @@ -1,8 +1,11 @@ try: import subprocess - + from collections import namedtuple + import json from bfn_extensions.platform_sensors import platform_sensors_get from sonic_platform_base.thermal_base import ThermalBase + from sonic_py_common import device_info + import logging except ImportError as e: raise ImportError (str(e) + "- required module not found") @@ -18,6 +21,8 @@ temp2_input: 37.000 ... ''' +Threshold = namedtuple('Threshold', ['crit', 'max', 'min', 'alarm'], defaults=[0.1]*4) + def _sensors_chip_parsed(data: str): def kv(line): k, v, *_ = [t.strip(': ') for t in line.split(':') if t] + [''] @@ -68,27 +73,88 @@ def _value_get(d: dict, key_prefix, key_suffix=''): # Thermal -> ThermalBase -> DeviceBase class Thermal(ThermalBase): + _thresholds = dict() + _max_temperature = 100.0 + _min_temperature = 0.0 + _min_high_threshold_temperature = 35.0 + def __init__(self, chip, label, index = 0): self.__chip = chip self.__label = label self.__name = f"{chip}:{label}".lower().replace(' ', '-') self.__collect_temp = [] self.__index = index + self.__high_threshold = None + self.__low_threshold = None + f = None + try: + path = device_info.get_path_to_platform_dir() + '/' + 'thermal_thresholds.json' + f = open(path) + except: + logging.warning('can not open the file') + if f is not None: + self.__get_thresholds(f) + + def __get_thresholds(self, f): + def_threshold_json = json.load(f) + all_data = def_threshold_json["thermals"] + for i in all_data: + for key, value in i.items(): + self._thresholds[key] = Threshold(*value) + + def check_in_range(self, temperature): + temp_f = float(temperature) + return temp_f > self._min_temperature and temp_f <= self._max_temperature + + def check_high_threshold(self, temperature, attr_suffix): + temp_f = float(temperature) + check_range = True + if attr_suffix == 'max': + if temp_f < self._min_high_threshold_temperature: + if self.__name in self._thresholds: + temp = self._thresholds[self.__name].max + self.set_high_threshold(temp) + check_range = False + return check_range def __get(self, attr_prefix, attr_suffix): sensor_data = _sensors_get().get(self.__chip, {}).get(self.__label, {}) value = _value_get(sensor_data, attr_prefix, attr_suffix) - return value if value is not None else -999.9 + if value is not None and self.check_in_range(value) and self.check_high_threshold(value, attr_suffix): + return value + elif self.__name in self._thresholds and attr_prefix == 'temp': + if attr_suffix == 'crit': + return self._thresholds[self.__name].crit + elif attr_suffix == 'max': + if self.__high_threshold is None: + return self._thresholds[self.__name].max + else: + return self.__high_threshold + elif attr_suffix == 'min': + if self.__low_threshold is None: + return self._thresholds[self.__name].min + else: + return self.__low_threshold + elif attr_suffix == 'alarm': + return self._thresholds[self.__name].alarm + else: + return 1.0 + else: + return 0.05 # ThermalBase interface methods: def get_temperature(self) -> float: temp = self.__get('temp', 'input') self.__collect_temp.append(float(temp)) self.__collect_temp.sort() + if len(self.__collect_temp) == 3: + del self.__collect_temp[1] return float(temp) def get_high_threshold(self) -> float: - return float(self.__get('temp', 'max')) + if self.__high_threshold is None: + return float(self.__get('temp', 'max')) + return float(self.__high_threshold) def get_high_critical_threshold(self) -> float: return float(self.__get('temp', 'crit')) @@ -113,28 +179,38 @@ def is_replaceable(self): return False def get_low_threshold(self) -> float: - return float(self.__get('temp', 'min')) + if self.__low_threshold is None: + return float(self.__get('temp', 'min')) + return float(self.__low_threshold) def get_serial(self): return 'N/A' def get_minimum_recorded(self) -> float: - temp = self.__collect_temp[0] if len(self.__collect_temp) > 0 else 0.1 + temp = self.__collect_temp[0] if len(self.__collect_temp) > 0 else self.get_temperature() + temp = temp if temp <= 100.0 else 100.0 temp = temp if temp > 0.0 else 0.1 return float(temp) def get_maximum_recorded(self) -> float: - temp = self.__collect_temp[-1] if len(self.__collect_temp) > 0 else 100.0 + temp = self.__collect_temp[-1] if len(self.__collect_temp) > 0 else self.get_temperature() temp = temp if temp <= 100.0 else 100.0 + temp = temp if temp > 0.0 else 0.1 return float(temp) def get_position_in_parent(self): return self.__index def set_high_threshold(self, temperature): + if self.check_in_range(temperature): + self.__high_threshold = temperature + return True return False def set_low_threshold(self, temperature): + if self.check_in_range(temperature): + self.__low_threshold = temperature + return True return False def thermal_list_get(): diff --git a/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/thermal_manager.py b/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/thermal_manager.py new file mode 100644 index 000000000000..1f932f2d3ce6 --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/thermal_manager.py @@ -0,0 +1,67 @@ +try: + from threading import Timer +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + +class ThermalManager(): + def __init__(self, polling_time = 30.0): + self.__polling_thermal_time = polling_time + self.__thermals = None + self.__timer = None + self.__chassis = None + + def start(self): + self.work() + self.__timer = Timer(self.__polling_thermal_time, self.start) + self.__timer.start() + + def work(self): + if self.__chassis is not None: + self.__thermals = self.__chassis._thermal_list + for term in self.__thermals: + self.check(term) + + def check(self, sensor): + temperature = sensor.get_temperature() + if temperature is not None: + temp_high = sensor.get_high_threshold() + temp_low = sensor.get_low_threshold() + if temp_high > -999.0: + if temperature > temp_high: + print('Sensor ', sensor.get_name(), ' temperature more then', temp_high, '!!!') + else: + print('Sensor ', sensor.get_name(), ' has no high temperature threshold') + + if temp_low > -999.0: + if temperature < temp_low: + print('Sensor ', sensor.get_name(), ' temperature less then', temp_low, '!!!') + else: + print('Sensor ', sensor.get_name(), ' has no low temperature threshold') + + def stop(self): + if self.__timer is not None: + self.__timer.cancel() + + def __del__(self): + if self.__timer is not None: + self.__timer.cancel() + + # for compatibility with old version + def run_policy(self, chassis_def): + self.__chassis = chassis_def + + def get_interval(self): + return self.__polling_thermal_time + + def initialize(self): + pass + + def load(self, json_file): + pass + + def init_thermal_algorithm(self, chassis_def): + self.__chassis = chassis_def + self.start() + + def deinitialize(self): + self.stop()