Skip to content
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

[device/celestica]: Add thermalctld support on DX010 platform APIs #6089

Merged
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
3 changes: 1 addition & 2 deletions device/celestica/x86_64-cel_seastone-r0/fancontrol-B2F
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,4 @@ MINSTOP=13-002e/pwm1=89 13-002e/pwm2=89 13-002e/pwm3=89 13-002e/pwm4=89 13-002e/
MINPWM=13-002e/pwm1=89 13-002e/pwm2=89 13-002e/pwm3=89 13-002e/pwm4=89 13-002e/pwm5=89 13-004d/pwm1=89 13-004d/pwm2=89 13-004d/pwm3=89 13-004d/pwm4=89 13-004d/pwm5=89
MAXPWM=13-002e/pwm1=255 13-002e/pwm2=255 13-002e/pwm3=255 13-002e/pwm4=255 13-002e/pwm5=255 13-004d/pwm1=255 13-004d/pwm2=255 13-004d/pwm3=255 13-004d/pwm4=255 13-004d/pwm5=255
THYST=13-002e/pwm1=3 13-002e/pwm2=3 13-002e/pwm3=3 13-002e/pwm4=3 13-002e/pwm5=3 13-004d/pwm1=3 13-004d/pwm2=3 13-004d/pwm3=3 13-004d/pwm4=3 13-004d/pwm5=3
MAXTEMPCRIT=/sys/bus/i2c/devices/7-004a/hwmon/hwmon*/temp1_input=65 /sys/bus/i2c/devices/14-0048/hwmon/hwmon*/temp1_input=75
MAXTEMPTYPE=/sys/bus/i2c/devices/7-004a/hwmon/hwmon*/temp1_input=ASIC /sys/bus/i2c/devices/14-0048/hwmon/hwmon*/temp1_input=CPU

3 changes: 1 addition & 2 deletions device/celestica/x86_64-cel_seastone-r0/fancontrol-F2B
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,4 @@ MINSTOP=13-002e/pwm1=89 13-002e/pwm2=89 13-002e/pwm3=89 13-002e/pwm4=89 13-002e/
MINPWM=13-002e/pwm1=89 13-002e/pwm2=89 13-002e/pwm3=89 13-002e/pwm4=89 13-002e/pwm5=89 13-004d/pwm1=89 13-004d/pwm2=89 13-004d/pwm3=89 13-004d/pwm4=89 13-004d/pwm5=89
MAXPWM=13-002e/pwm1=255 13-002e/pwm2=255 13-002e/pwm3=255 13-002e/pwm4=255 13-002e/pwm5=255 13-004d/pwm1=255 13-004d/pwm2=255 13-004d/pwm3=255 13-004d/pwm4=255 13-004d/pwm5=255
THYST=13-002e/pwm1=3 13-002e/pwm2=3 13-002e/pwm3=3 13-002e/pwm4=3 13-002e/pwm5=3 13-004d/pwm1=3 13-004d/pwm2=3 13-004d/pwm3=3 13-004d/pwm4=3 13-004d/pwm5=3
MAXTEMPCRIT=/sys/bus/i2c/devices/7-004a/hwmon/hwmon*/temp1_input=75 /sys/bus/i2c/devices/14-0048/hwmon/hwmon*/temp1_input=75
MAXTEMPTYPE=/sys/bus/i2c/devices/7-004a/hwmon/hwmon*/temp1_input=ASIC /sys/bus/i2c/devices/14-0048/hwmon/hwmon*/temp1_input=CPU

Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,9 @@ def __initialize_fan(self):

def __initialize_thermals(self):
from sonic_platform.thermal import Thermal
airflow = self.__get_air_flow()
for index in range(0, NUM_THERMAL):
thermal = Thermal(index)
thermal = Thermal(index, airflow)
self._thermal_list.append(thermal)

def __initialize_eeprom(self):
Expand All @@ -80,6 +81,11 @@ def __initialize_components(self):
component = Component(index)
self._component_list.append(component)

def __get_air_flow(self):
air_flow_path = '/usr/share/sonic/device/{}/fan_airflow'.format(self._api_helper.platform) if self.is_host else '/usr/share/sonic/platform/fan_airflow'
air_flow = self._api_helper.read_one_line_file(air_flow_path)
return air_flow or 'B2F'

def get_base_mac(self):
"""
Retrieves the base MAC address for the chassis
Expand Down Expand Up @@ -251,3 +257,7 @@ def get_status(self):
A boolean value, True if device is operating properly, False if not
"""
return True

def get_thermal_manager(self):
from .thermal_manager import ThermalManager
return ThermalManager
18 changes: 17 additions & 1 deletion device/celestica/x86_64-cel_seastone-r0/sonic_platform/fan.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,4 +304,20 @@ def get_status(self):
Returns:
A boolean value, True if device is operating properly, False if not
"""
return self.get_presence() and self.get_speed() > 0
status = 1
if self.is_psu_fan:
fan_fault_sysfs_name = "fan1_fault"
fan_fault_sysfs_path = self.__search_file_by_name(
self.psu_hwmon_path, fan_fault_sysfs_name)
status = self._api_helper.read_one_line_file(fan_fault_sysfs_path)

elif self.get_presence():
chip = self.emc2305_chip_mapping[self.fan_index]
device = chip['device']
fan_index = chip['index_map']
sysfs_path = "%s%s/%s" % (
EMC2305_PATH, device, 'fan{}_fault')
sysfs_path = sysfs_path.format(fan_index[self.fan_tray_index])
status = self._api_helper.read_one_line_file(sysfs_path)

return False if int(status) != 0 else True
144 changes: 114 additions & 30 deletions device/celestica/x86_64-cel_seastone-r0/sonic_platform/thermal.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,46 +16,75 @@
except ImportError as e:
raise ImportError(str(e) + "- required module not found")

THERMAL_INFO = {
0: {
"F2B_max": 50,
"B2F_max": 55,
"postion": "asic",
"name": "Front-panel temp sensor 1",
"i2c_path": "i2c-5/5-0048/hwmon/hwmon1", # u4 system-inlet
},
1: {
"F2B_max": 50,
"B2F_max": 55,
"postion": "asic",
"name": "Front-panel temp sensor 2",
"i2c_path": "i2c-6/6-0049/hwmon/hwmon2", # u2 system-inlet
},
2: {
"F2B_max": 70,
"F2B_max_crit": 75,
"B2F_max": 60,
"B2F_max_crit": 65,
"postion": "asic",
"name": "ASIC temp sensor",
"i2c_path": "i2c-7/7-004a/hwmon/hwmon3", # u44 bmc56960-on-board
},
3: {
"F2B_max": 70,
"F2B_max_crit": 75,
"B2F_max": 70,
"B2F_max_crit": 75,
"postion": "cpu",
"name": "Rear-panel temp sensor 1",
"i2c_path": "i2c-14/14-0048/hwmon/hwmon4", # u9200 cpu-on-board
},
4: {
"F2B_max": 70,
"B2F_max": 55,
"postion": "cpu",
"name": "Rear-panel temp sensor 2",
"i2c_path": "i2c-15/15-004e/hwmon/hwmon5" # u9201 system-outlet
}
}
NULL_VAL = "N/A"
I2C_ADAPTER_PATH = "/sys/class/i2c-adapter"


class Thermal(ThermalBase):
"""Platform-specific Thermal class"""

THERMAL_NAME_LIST = []
I2C_ADAPTER_PATH = "/sys/class/i2c-adapter"
SS_CONFIG_PATH = "/usr/share/sonic/device/x86_64-cel_seastone-r0/sensors.conf"

def __init__(self, thermal_index):
def __init__(self, thermal_index, airflow):
self.index = thermal_index
self._api_helper = APIHelper()

# Add thermal name
self.THERMAL_NAME_LIST.append("Front-panel temp sensor 1")
self.THERMAL_NAME_LIST.append("Front-panel temp sensor 2")
self.THERMAL_NAME_LIST.append("ASIC temp sensor")
self.THERMAL_NAME_LIST.append("Rear-panel temp sensor 1")
self.THERMAL_NAME_LIST.append("Rear-panel temp sensor 2")

# Set hwmon path
i2c_path = {
0: "i2c-5/5-0048/hwmon/hwmon1", # u4 system-inlet
1: "i2c-6/6-0049/hwmon/hwmon2", # u2 system-inlet
2: "i2c-7/7-004a/hwmon/hwmon3", # u44 bmc56960-on-board
3: "i2c-14/14-0048/hwmon/hwmon4", # u9200 cpu-on-board
4: "i2c-15/15-004e/hwmon/hwmon5" # u9201 system-outlet
}.get(self.index, None)

self.hwmon_path = "{}/{}".format(self.I2C_ADAPTER_PATH, i2c_path)
self.ss_key = self.THERMAL_NAME_LIST[self.index]
self._airflow = airflow
self._thermal_info = THERMAL_INFO[self.index]
self._hwmon_path = "{}/{}".format(I2C_ADAPTER_PATH,
self._thermal_info["i2c_path"])
self.name = self.get_name()
self.postion = self._thermal_info["postion"]
self.ss_index = 1

def __get_temp(self, temp_file):
temp_file_path = os.path.join(self.hwmon_path, temp_file)
temp_file_path = os.path.join(self._hwmon_path, temp_file)
raw_temp = self._api_helper.read_txt_file(temp_file_path)
temp = float(raw_temp)/1000
return float("{:.3f}".format(temp))

def __set_threshold(self, file_name, temperature):
temp_file_path = os.path.join(self.hwmon_path, file_name)
temp_file_path = os.path.join(self._hwmon_path, file_name)
try:
with open(temp_file_path, 'w') as fd:
fd.write(str(temperature))
Expand All @@ -80,8 +109,17 @@ def get_high_threshold(self):
A float number, the high threshold temperature of thermal in Celsius
up to nearest thousandth of one degree Celsius, e.g. 30.125
"""
temp_file = "temp{}_max".format(self.ss_index)
return self.__get_temp(temp_file)
max_crit_key = '{}_max'.format(self._airflow)
return self._thermal_info.get(max_crit_key, None)

def get_low_threshold(self):
"""
Retrieves the low threshold temperature of thermal
Returns:
A float number, the low threshold temperature of thermal in Celsius
up to nearest thousandth of one degree Celsius, e.g. 30.125
"""
return 0.0

def set_high_threshold(self, temperature):
"""
Expand All @@ -102,7 +140,7 @@ def set_high_threshold(self, temperature):
f.seek(0)
ss_found = False
for idx, val in enumerate(content):
if self.ss_key in val:
if self.name in val:
ss_found = True
elif ss_found and temp_file in val:
content[idx] = " set {} {}\n".format(
Expand All @@ -115,13 +153,43 @@ def set_high_threshold(self, temperature):

return is_set & file_set

def set_low_threshold(self, temperature):
"""
Sets the low threshold temperature of thermal
Args :
temperature: A float number up to nearest thousandth of one degree Celsius,
e.g. 30.125
Returns:
A boolean, True if threshold is set successfully, False if not
"""
return False

def get_high_critical_threshold(self):
"""
Retrieves the high critical threshold temperature of thermal
Returns:
A float number, the high critical threshold temperature of thermal in Celsius
up to nearest thousandth of one degree Celsius, e.g. 30.125
"""
max_crit_key = '{}_max_crit'.format(self._airflow)
return self._thermal_info.get(max_crit_key, None)

def get_low_critical_threshold(self):
"""
Retrieves the low critical threshold temperature of thermal
Returns:
A float number, the low critical threshold temperature of thermal in Celsius
up to nearest thousandth of one degree Celsius, e.g. 30.125
"""
return 0.0

def get_name(self):
"""
Retrieves the name of the thermal device
Returns:
string: The name of the thermal device
"""
return self.THERMAL_NAME_LIST[self.index]
return self._thermal_info["name"]

def get_presence(self):
"""
Expand All @@ -130,9 +198,25 @@ def get_presence(self):
bool: True if PSU is present, False if not
"""
temp_file = "temp{}_input".format(self.ss_index)
temp_file_path = os.path.join(self.hwmon_path, temp_file)
temp_file_path = os.path.join(self._hwmon_path, temp_file)
return os.path.isfile(temp_file_path)

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

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

def get_status(self):
"""
Retrieves the operational status of the device
Expand All @@ -143,7 +227,7 @@ def get_status(self):
return False

fault_file = "temp{}_fault".format(self.ss_index)
fault_file_path = os.path.join(self.hwmon_path, fault_file)
fault_file_path = os.path.join(self._hwmon_path, fault_file)
if not os.path.isfile(fault_file_path):
return True

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@

from sonic_platform_base.sonic_thermal_control.thermal_action_base import ThermalPolicyActionBase
from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object
from .thermal_infos import ChassisInfo
from .helper import APIHelper


@thermal_json_object('thermal_control.control')
class ControlThermalAlgoAction(ThermalPolicyActionBase):
"""
Action to control the thermal control algorithm
"""
# JSON field definition
JSON_FIELD_STATUS = 'status'

def __init__(self):
self.status = True

def load_from_json(self, json_obj):
"""
Construct ControlThermalAlgoAction via JSON. JSON example:
{
"type": "thermal_control.control"
"status": "true"
}
:param json_obj: A JSON object representing a ControlThermalAlgoAction action.
:return:
"""
if ControlThermalAlgoAction.JSON_FIELD_STATUS in json_obj:
status_str = json_obj[ControlThermalAlgoAction.JSON_FIELD_STATUS].lower()
if status_str == 'true':
self.status = True
elif status_str == 'false':
self.status = False
else:
raise ValueError('Invalid {} field value, please specify true of false'.
format(ControlThermalAlgoAction.JSON_FIELD_STATUS))
else:
raise ValueError('ControlThermalAlgoAction '
'missing mandatory field {} in JSON policy file'.
format(ControlThermalAlgoAction.JSON_FIELD_STATUS))

def execute(self, thermal_info_dict):
"""
Disable thermal control algorithm
:param thermal_info_dict: A dictionary stores all thermal information.
:return:
"""
if ChassisInfo.INFO_NAME in thermal_info_dict:
chassis_info_obj = thermal_info_dict[ChassisInfo.INFO_NAME]
chassis = chassis_info_obj.get_chassis()
thermal_manager = chassis.get_thermal_manager()
if self.status:
thermal_manager.start_thermal_control_algorithm()
else:
thermal_manager.stop_thermal_control_algorithm()


@thermal_json_object('switch.power_cycling')
class SwitchPolicyAction(ThermalPolicyActionBase):
"""
Base class for thermal action. Once all thermal conditions in a thermal policy are matched,
all predefined thermal action will be executed.
"""

def execute(self, thermal_info_dict):
"""
Take action when thermal condition matches. For example, power cycle the switch.
:param thermal_info_dict: A dictionary stores all thermal information.
:return:
"""
thermal_overload_position_path = '/tmp/thermal_overload_position'
thermal_overload_position = APIHelper().read_one_line_file(
thermal_overload_position_path)

cmd = 'bash /usr/share/sonic/platform/thermal_overload_control.sh {}'.format(
thermal_overload_position)
APIHelper().run_command(cmd)
Loading