[device/celestica]: Update DX010 platform APIS on 201911 branch (#5416)

* [device/celestica]: DX010 platform API update (#4608)

- Fix fancontrol.service path
- Fix return temp format in thermal API
- Improve init time in chassis API
- Upgrade sfp API

* [device/celestica]: Update DX010 reboot cause API (#4678)

- Add more cases support in DX010 reboot cause API
    - Add Thermal Overload reboot cause support
    - Add new Watchdog reboot cause support

* [device/celestica]: using sonic-py-common package
This commit is contained in:
Wirut Getbamrung 2020-09-25 00:20:15 +07:00 committed by GitHub
parent 6ae77f87cc
commit 10534a39eb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 1985 additions and 1205 deletions

View File

@ -9,3 +9,5 @@ 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 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 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 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

View File

@ -9,4 +9,5 @@ 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 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 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 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

View File

@ -1,2 +1,2 @@
__all__ = ["platform", "chassis"] import chassis
from sonic_platform import * import platform

View File

@ -8,20 +8,10 @@
# #
############################################################################# #############################################################################
import sys
import re
import os
import subprocess
import json
try: try:
import sys
from sonic_platform_base.chassis_base import ChassisBase from sonic_platform_base.chassis_base import ChassisBase
from sonic_platform.fan import Fan from helper import APIHelper
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
except ImportError as e: except ImportError as e:
raise ImportError(str(e) + "- required module not found") raise ImportError(str(e) + "- required module not found")
@ -33,9 +23,9 @@ NUM_SFP = 32
NUM_COMPONENT = 5 NUM_COMPONENT = 5
RESET_REGISTER = "0x103" RESET_REGISTER = "0x103"
HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/" HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/"
PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/"
REBOOT_CAUSE_FILE = "reboot-cause.txt" REBOOT_CAUSE_FILE = "reboot-cause.txt"
PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt" PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt"
GETREG_PATH = "/sys/devices/platform/dx010_cpld/getreg"
HOST_CHK_CMD = "docker > /dev/null 2>&1" HOST_CHK_CMD = "docker > /dev/null 2>&1"
@ -44,39 +34,54 @@ class Chassis(ChassisBase):
def __init__(self): def __init__(self):
ChassisBase.__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()
def __initialize_sfp(self):
from sonic_platform.sfp import Sfp
for index in range(0, NUM_SFP):
sfp = Sfp(index)
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 fant_index in range(0, NUM_FAN_TRAY):
for fan_index in range(0, NUM_FAN): for fan_index in range(0, NUM_FAN):
fan = Fan(fant_index, fan_index) fan = Fan(fant_index, fan_index)
self._fan_list.append(fan) self._fan_list.append(fan)
for index in range(0, NUM_PSU):
psu = Psu(index) def __initialize_thermals(self):
self._psu_list.append(psu) from sonic_platform.thermal import Thermal
for index in range(0, NUM_THERMAL): for index in range(0, NUM_THERMAL):
thermal = Thermal(index) thermal = Thermal(index)
self._thermal_list.append(thermal) self._thermal_list.append(thermal)
# sfp index start from 1
for index in range(0, NUM_SFP): def __initialize_eeprom(self):
sfp = Sfp(index) from sonic_platform.eeprom import Tlv
self._sfp_list.append(sfp) self._eeprom = Tlv()
def __initialize_components(self):
from sonic_platform.component import Component
for index in range(0, NUM_COMPONENT): for index in range(0, NUM_COMPONENT):
component = Component(index) component = Component(index)
self._component_list.append(component) self._component_list.append(component)
self._eeprom = Tlv()
def __is_host(self):
return os.system(HOST_CHK_CMD) == 0
def __read_txt_file(self, file_path):
try:
with open(file_path, 'r') as fd:
data = fd.read()
return data.strip()
except IOError:
pass
return None
def get_base_mac(self): def get_base_mac(self):
""" """
Retrieves the base MAC address for the chassis Retrieves the base MAC address for the chassis
@ -107,44 +112,98 @@ class Chassis(ChassisBase):
def get_reboot_cause(self): def get_reboot_cause(self):
""" """
Retrieves the cause of the previous reboot Retrieves the cause of the previous reboot
Returns: Returns:
A tuple (string, string) where the first element is a string A tuple (string, string) where the first element is a string
containing the cause of the previous reboot. This string must be containing the cause of the previous reboot. This string must be
one of the predefined strings in this class. If the first string one of the predefined strings in this class. If the first string
is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used
to pass a description of the reboot cause. to pass a description of the reboot cause.
REBOOT_CAUSE_POWER_LOSS = "Power Loss"
REBOOT_CAUSE_THERMAL_OVERLOAD_CPU = "Thermal Overload: CPU"
REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC = "Thermal Overload: ASIC"
REBOOT_CAUSE_THERMAL_OVERLOAD_OTHER = "Thermal Overload: Other"
REBOOT_CAUSE_INSUFFICIENT_FAN_SPEED = "Insufficient Fan Speed"
REBOOT_CAUSE_WATCHDOG = "Watchdog"
REBOOT_CAUSE_HARDWARE_OTHER = "Hardware - Other"
REBOOT_CAUSE_NON_HARDWARE = "Non-Hardware"
""" """
description = 'None' reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE)
reboot_cause = self.REBOOT_CAUSE_HARDWARE_OTHER sw_reboot_cause = self._api_helper.read_txt_file(
reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE) if self.__is_host(
) else PMON_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE
prev_reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + PREV_REBOOT_CAUSE_FILE) if self.__is_host(
) else PMON_REBOOT_CAUSE_PATH + PREV_REBOOT_CAUSE_FILE
hw_reboot_cause = self._component_list[0].get_register_value(RESET_REGISTER)
sw_reboot_cause = self.__read_txt_file(
reboot_cause_path) or "Unknown" reboot_cause_path) or "Unknown"
prev_sw_reboot_cause = self.__read_txt_file( hw_reboot_cause = self._api_helper.get_cpld_reg_value(
prev_reboot_cause_path) or "Unknown" GETREG_PATH, RESET_REGISTER)
if sw_reboot_cause == "Unknown" and (prev_sw_reboot_cause == "Unknown" or prev_sw_reboot_cause == self.REBOOT_CAUSE_POWER_LOSS) and hw_reboot_cause == "0x11": prev_reboot_cause = {
reboot_cause = self.REBOOT_CAUSE_POWER_LOSS '0x11': (self.REBOOT_CAUSE_POWER_LOSS, 'Power on reset'),
elif sw_reboot_cause != "Unknown" and hw_reboot_cause == "0x11": '0x22': (self.REBOOT_CAUSE_HARDWARE_OTHER, 'CPLD_WD_RESET'),
reboot_cause = self.REBOOT_CAUSE_NON_HARDWARE '0x33': (self.REBOOT_CAUSE_HARDWARE_OTHER, 'Power cycle reset triggered by CPU'),
description = sw_reboot_cause '0x44': (self.REBOOT_CAUSE_HARDWARE_OTHER, 'Power cycle reset triggered by reset button'),
elif prev_reboot_cause_path != "Unknown" and hw_reboot_cause == "0x11": '0x55': (self.REBOOT_CAUSE_THERMAL_OVERLOAD_CPU, ''),
reboot_cause = self.REBOOT_CAUSE_NON_HARDWARE '0x66': (self.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC, ''),
description = prev_sw_reboot_cause '0x77': (self.REBOOT_CAUSE_WATCHDOG, '')
elif hw_reboot_cause == "0x22": }.get(hw_reboot_cause, (self.REBOOT_CAUSE_HARDWARE_OTHER, 'Unknown reason'))
reboot_cause = self.REBOOT_CAUSE_WATCHDOG,
else:
reboot_cause = self.REBOOT_CAUSE_HARDWARE_OTHER
description = 'Unknown reason'
return (reboot_cause, description) if sw_reboot_cause != 'Unknown' and hw_reboot_cause == '0x11':
prev_reboot_cause = (
self.REBOOT_CAUSE_NON_HARDWARE, sw_reboot_cause)
return prev_reboot_cause
##############################################################
######################## 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
##############################################################
####################### Other methods ########################
##############################################################
def get_watchdog(self): def get_watchdog(self):
""" """
@ -159,23 +218,46 @@ class Chassis(ChassisBase):
return self._watchdog return self._watchdog
def get_sfp(self, index): ##############################################################
""" ###################### Device methods ########################
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
try: def get_name(self):
# The index will start from 1 """
sfp = self._sfp_list[index-1] Retrieves the name of the device
except IndexError: Returns:
sys.stderr.write("SFP index {} out of range (1-{})\n".format( string: The name of the device
index, len(self._sfp_list))) """
return sfp 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.get_serial_number()
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

View File

@ -8,14 +8,13 @@
# #
############################################################################# #############################################################################
import json
import os.path import os.path
import shutil import shutil
import shlex
import subprocess import subprocess
try: try:
from sonic_platform_base.component_base import ComponentBase from sonic_platform_base.component_base import ComponentBase
from helper import APIHelper
except ImportError as e: except ImportError as e:
raise ImportError(str(e) + "- required module not found") raise ImportError(str(e) + "- required module not found")
@ -29,7 +28,8 @@ CPLD_ADDR_MAPPING = {
GETREG_PATH = "/sys/devices/platform/dx010_cpld/getreg" GETREG_PATH = "/sys/devices/platform/dx010_cpld/getreg"
BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version" BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version"
COMPONENT_NAME_LIST = ["CPLD1", "CPLD2", "CPLD3", "CPLD4", "BIOS"] COMPONENT_NAME_LIST = ["CPLD1", "CPLD2", "CPLD3", "CPLD4", "BIOS"]
COMPONENT_DES_LIST = ["CPLD1", "CPLD2", "CPLD3", "CPLD4", "Basic Input/Output System"] COMPONENT_DES_LIST = ["Used for managing the CPU",
"Used for managing QSFP+ ports (1-10)", "Used for managing QSFP+ ports (11-20)", "Used for managing QSFP+ ports (22-32)", "Basic Input/Output System"]
class Component(ComponentBase): class Component(ComponentBase):
@ -40,24 +40,9 @@ class Component(ComponentBase):
def __init__(self, component_index): def __init__(self, component_index):
ComponentBase.__init__(self) ComponentBase.__init__(self)
self.index = component_index self.index = component_index
self._api_helper = APIHelper()
self.name = self.get_name() self.name = self.get_name()
def __run_command(self, command):
# Run bash command and print output to stdout
try:
process = subprocess.Popen(
shlex.split(command), stdout=subprocess.PIPE)
while True:
output = process.stdout.readline()
if output == '' and process.poll() is not None:
break
rc = process.poll()
if rc != 0:
return False
except:
return False
return True
def __get_bios_version(self): def __get_bios_version(self):
# Retrieves the BIOS firmware version # Retrieves the BIOS firmware version
try: try:

View File

@ -14,6 +14,7 @@ import os.path
try: try:
from sonic_platform_base.fan_base import FanBase from sonic_platform_base.fan_base import FanBase
from helper import APIHelper
except ImportError as e: except ImportError as e:
raise ImportError(str(e) + "- required module not found") raise ImportError(str(e) + "- required module not found")
@ -38,13 +39,16 @@ PSU_I2C_MAPPING = {
"addr": "5b" "addr": "5b"
}, },
} }
NULL_VAL = "N/A"
class Fan(FanBase): class Fan(FanBase):
"""Platform-specific Fan class""" """Platform-specific Fan class"""
def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0): def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0):
FanBase.__init__(self)
self.fan_index = fan_index self.fan_index = fan_index
self._api_helper = APIHelper()
self.fan_tray_index = fan_tray_index self.fan_tray_index = fan_tray_index
self.is_psu_fan = is_psu_fan self.is_psu_fan = is_psu_fan
if self.is_psu_fan: if self.is_psu_fan:
@ -75,16 +79,6 @@ class Fan(FanBase):
{'prs': 14, 'dir': 19, 'color': {'red': 37, 'green': 38}}, # 4 {'prs': 14, 'dir': 19, 'color': {'red': 37, 'green': 38}}, # 4
{'prs': 12, 'dir': 17, 'color': {'red': 33, 'green': 34}}, # 5 {'prs': 12, 'dir': 17, 'color': {'red': 33, 'green': 34}}, # 5
] ]
FanBase.__init__(self)
def __read_txt_file(self, file_path):
try:
with open(file_path, 'r') as fd:
data = fd.read()
return data.strip()
except IOError:
pass
return ""
def __write_txt_file(self, file_path, value): def __write_txt_file(self, file_path, value):
try: try:
@ -105,7 +99,7 @@ class Fan(FanBase):
def __get_gpio_base(self): def __get_gpio_base(self):
for r in os.listdir(GPIO_DIR): for r in os.listdir(GPIO_DIR):
label_path = os.path.join(GPIO_DIR, r, "label") label_path = os.path.join(GPIO_DIR, r, "label")
if "gpiochip" in r and GPIO_LABEL in self.__read_txt_file(label_path): if "gpiochip" in r and GPIO_LABEL in self._api_helper.read_txt_file(label_path):
return int(r[8:], 10) return int(r[8:], 10)
return 216 # Reserve return 216 # Reserve
@ -113,7 +107,7 @@ class Fan(FanBase):
gpio_base = self.dx010_fan_gpio[0]['base'] gpio_base = self.dx010_fan_gpio[0]['base']
gpio_dir = GPIO_DIR + '/gpio' + str(gpio_base+pinnum) gpio_dir = GPIO_DIR + '/gpio' + str(gpio_base+pinnum)
gpio_file = gpio_dir + "/value" gpio_file = gpio_dir + "/value"
retval = self.__read_txt_file(gpio_file) retval = self._api_helper.read_txt_file(gpio_file)
return retval.rstrip('\r\n') return retval.rstrip('\r\n')
def __set_gpio_value(self, pinnum, value=0): def __set_gpio_value(self, pinnum, value=0):
@ -154,7 +148,8 @@ class Fan(FanBase):
fan_speed_sysfs_name = "fan{}_input".format(self.fan_index+1) fan_speed_sysfs_name = "fan{}_input".format(self.fan_index+1)
fan_speed_sysfs_path = self.__search_file_by_name( fan_speed_sysfs_path = self.__search_file_by_name(
self.psu_hwmon_path, fan_speed_sysfs_name) self.psu_hwmon_path, fan_speed_sysfs_name)
fan_speed_rpm = self.__read_txt_file(fan_speed_sysfs_path) or 0 fan_speed_rpm = self._api_helper.read_txt_file(
fan_speed_sysfs_path) or 0
fan_speed_raw = float(fan_speed_rpm)/PSU_FAN_MAX_RPM * 100 fan_speed_raw = float(fan_speed_rpm)/PSU_FAN_MAX_RPM * 100
speed = math.ceil(float(fan_speed_rpm) * 100 / PSU_FAN_MAX_RPM) speed = math.ceil(float(fan_speed_rpm) * 100 / PSU_FAN_MAX_RPM)
elif self.get_presence(): elif self.get_presence():
@ -164,7 +159,7 @@ class Fan(FanBase):
sysfs_path = "%s%s/%s" % ( sysfs_path = "%s%s/%s" % (
EMC2305_PATH, device, EMC2305_FAN_INPUT) EMC2305_PATH, device, EMC2305_FAN_INPUT)
sysfs_path = sysfs_path.format(fan_index[self.fan_tray_index]) sysfs_path = sysfs_path.format(fan_index[self.fan_tray_index])
raw = self.__read_txt_file(sysfs_path).strip('\r\n') raw = self._api_helper.read_txt_file(sysfs_path).strip('\r\n')
pwm = int(raw, 10) if raw else 0 pwm = int(raw, 10) if raw else 0
speed = math.ceil(float(pwm * 100 / EMC2305_MAX_PWM)) speed = math.ceil(float(pwm * 100 / EMC2305_MAX_PWM))
@ -183,19 +178,7 @@ class Fan(FanBase):
0 : when PWM mode is use 0 : when PWM mode is use
pwm : when pwm mode is not use pwm : when pwm mode is not use
""" """
target = 0 return 'N/A'
if not self.is_psu_fan:
chip = self.emc2305_chip_mapping[self.fan_index]
device = chip['device']
fan_index = chip['index_map']
sysfs_path = "%s%s/%s" % (
EMC2305_PATH, device, EMC2305_FAN_TARGET)
sysfs_path = sysfs_path.format(fan_index[self.fan_tray_index])
raw = self.__read_txt_file(sysfs_path).strip('\r\n')
pwm = int(raw, 10) if raw else 0
target = math.ceil(float(pwm) * 100 / EMC2305_MAX_PWM)
return target
def get_speed_tolerance(self): def get_speed_tolerance(self):
""" """
@ -284,11 +267,43 @@ class Fan(FanBase):
def get_presence(self): def get_presence(self):
""" """
Retrieves the presence of the PSU Retrieves the presence of the FAN
Returns: Returns:
bool: True if PSU is present, False if not bool: True if FAN is present, False if not
""" """
present_str = self.__get_gpio_value( present_str = self.__get_gpio_value(
self.dx010_fan_gpio[self.fan_tray_index+1]['prs']) self.dx010_fan_gpio[self.fan_tray_index+1]['prs'])
return int(present_str, 10) == 0 if not self.is_psu_fan else True return int(present_str, 10) == 0 if not self.is_psu_fan else True
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
if self.is_psu_fan:
return NULL_VAL
model = NULL_VAL
return model
def get_serial(self):
"""
Retrieves the serial number of the device
Returns:
string: Serial number of device
"""
if self.is_psu_fan:
return NULL_VAL
serial = NULL_VAL
return 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 self.get_presence() and self.get_speed() > 0

View File

@ -0,0 +1,134 @@
#!/usr/bin/env python
import os
import struct
import subprocess
from sonic_py_common import device_info
from mmap import *
HOST_CHK_CMD = "docker > /dev/null 2>&1"
EMPTY_STRING = ""
class APIHelper():
def __init__(self):
(self.platform, self.hwsku) = device_info.get_platform_and_hwsku()
def is_host(self):
return os.system(HOST_CHK_CMD) == 0
def pci_get_value(self, resource, offset):
status = True
result = ""
try:
fd = os.open(resource, os.O_RDWR)
mm = mmap(fd, 0)
mm.seek(int(offset))
read_data_stream = mm.read(4)
result = struct.unpack('I', read_data_stream)
except:
status = False
return status, result
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:
status = False
return status, result
def run_interactive_command(self, cmd):
try:
os.system(cmd)
except:
return False
return True
def read_txt_file(self, file_path):
try:
with open(file_path, 'r') as fd:
data = fd.read()
return data.strip()
except IOError:
pass
return None
def read_one_line_file(self, file_path):
try:
with open(file_path, 'r') as fd:
data = fd.readline()
return data.strip()
except IOError:
pass
return None
def write_txt_file(self, file_path, value):
try:
with open(file_path, 'w') as fd:
fd.write(str(value))
except Exception:
return False
return True
def get_cpld_reg_value(self, getreg_path, register):
cmd = "echo {1} > {0}; cat {0}".format(getreg_path, register)
status, result = self.run_command(cmd)
return result if status else None
def ipmi_raw(self, netfn, cmd):
status = True
result = ""
try:
cmd = "ipmitool raw {} {}".format(str(netfn), str(cmd))
p = subprocess.Popen(
cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
raw_data, err = p.communicate()
if err == '':
result = raw_data.strip()
else:
status = False
except:
status = False
return status, result
def ipmi_fru_id(self, id, key=None):
status = True
result = ""
try:
cmd = "ipmitool fru print {}".format(str(
id)) if not key else "ipmitool fru print {0} | grep '{1}' ".format(str(id), str(key))
p = subprocess.Popen(
cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
raw_data, err = p.communicate()
if err == '':
result = raw_data.strip()
else:
status = False
except:
status = False
return status, result
def ipmi_set_ss_thres(self, id, threshold_key, value):
status = True
result = ""
try:
cmd = "ipmitool sensor thresh '{}' {} {}".format(
str(id), str(threshold_key), str(value))
p = subprocess.Popen(
cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
raw_data, err = p.communicate()
if err == '':
result = raw_data.strip()
else:
status = False
except:
status = False
return status, result

View File

@ -14,6 +14,7 @@ import sonic_platform
try: try:
from sonic_platform_base.psu_base import PsuBase from sonic_platform_base.psu_base import PsuBase
from sonic_platform.fan import Fan from sonic_platform.fan import Fan
from helper import APIHelper
except ImportError as e: except ImportError as e:
raise ImportError(str(e) + "- required module not found") raise ImportError(str(e) + "- required module not found")
@ -41,6 +42,7 @@ class Psu(PsuBase):
def __init__(self, psu_index): def __init__(self, psu_index):
PsuBase.__init__(self) PsuBase.__init__(self)
self.index = psu_index self.index = psu_index
self._api_helper = APIHelper()
self.green_led_path = GREEN_LED_PATH.format(self.index+1) self.green_led_path = GREEN_LED_PATH.format(self.index+1)
self.dx010_psu_gpio = [ self.dx010_psu_gpio = [
{'base': self.__get_gpio_base()}, {'base': self.__get_gpio_base()},
@ -54,27 +56,18 @@ class Psu(PsuBase):
fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index) fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index)
self._fan_list.append(fan) self._fan_list.append(fan)
def __read_txt_file(self, file_path):
try:
with open(file_path, 'r') as fd:
data = fd.read()
return data.strip()
except IOError:
pass
return ""
def __search_file_by_contain(self, directory, search_str, file_start): def __search_file_by_contain(self, directory, search_str, file_start):
for dirpath, dirnames, files in os.walk(directory): for dirpath, dirnames, files in os.walk(directory):
for name in files: for name in files:
file_path = os.path.join(dirpath, name) file_path = os.path.join(dirpath, name)
if name.startswith(file_start) and search_str in self.__read_txt_file(file_path): if name.startswith(file_start) and search_str in self._api_helper.read_txt_file(file_path):
return file_path return file_path
return None return None
def __get_gpio_base(self): def __get_gpio_base(self):
for r in os.listdir(GPIO_DIR): for r in os.listdir(GPIO_DIR):
label_path = os.path.join(GPIO_DIR, r, "label") label_path = os.path.join(GPIO_DIR, r, "label")
if "gpiochip" in r and GPIO_LABEL in self.__read_txt_file(label_path): if "gpiochip" in r and GPIO_LABEL in self._api_helper.read_txt_file(label_path):
return int(r[8:], 10) return int(r[8:], 10)
return 216 # Reserve return 216 # Reserve
@ -82,7 +75,7 @@ class Psu(PsuBase):
gpio_base = self.dx010_psu_gpio[0]['base'] gpio_base = self.dx010_psu_gpio[0]['base']
gpio_dir = GPIO_DIR + '/gpio' + str(gpio_base+pinnum) gpio_dir = GPIO_DIR + '/gpio' + str(gpio_base+pinnum)
gpio_file = gpio_dir + "/value" gpio_file = gpio_dir + "/value"
retval = self.__read_txt_file(gpio_file) retval = self._api_helper.read_txt_file(gpio_file)
return retval.rstrip('\r\n') return retval.rstrip('\r\n')
def get_voltage(self): def get_voltage(self):
@ -104,7 +97,7 @@ class Psu(PsuBase):
in_num = filter(str.isdigit, basename) in_num = filter(str.isdigit, basename)
vout_path = os.path.join( vout_path = os.path.join(
dir_name, voltage_name.format(in_num)) dir_name, voltage_name.format(in_num))
vout_val = self.__read_txt_file(vout_path) vout_val = self._api_helper.read_txt_file(vout_path)
psu_voltage = float(vout_val) / 1000 psu_voltage = float(vout_val) / 1000
return psu_voltage return psu_voltage
@ -127,7 +120,7 @@ class Psu(PsuBase):
cur_num = filter(str.isdigit, basename) cur_num = filter(str.isdigit, basename)
cur_path = os.path.join( cur_path = os.path.join(
dir_name, current_name.format(cur_num)) dir_name, current_name.format(cur_num))
cur_val = self.__read_txt_file(cur_path) cur_val = self._api_helper.read_txt_file(cur_path)
psu_current = float(cur_val) / 1000 psu_current = float(cur_val) / 1000
return psu_current return psu_current
@ -150,7 +143,7 @@ class Psu(PsuBase):
pw_num = filter(str.isdigit, basename) pw_num = filter(str.isdigit, basename)
pw_path = os.path.join( pw_path = os.path.join(
dir_name, current_name.format(pw_num)) dir_name, current_name.format(pw_num))
pw_val = self.__read_txt_file(pw_path) pw_val = self._api_helper.read_txt_file(pw_path)
psu_power = float(pw_val) / 1000000 psu_power = float(pw_val) / 1000000
return psu_power return psu_power
@ -196,7 +189,7 @@ class Psu(PsuBase):
Returns: Returns:
A string, one of the predefined STATUS_LED_COLOR_* strings above A string, one of the predefined STATUS_LED_COLOR_* strings above
""" """
status = self.__read_txt_file(self.green_led_path) status = self._api_helper.read_txt_file(self.green_led_path)
status_str = { status_str = {
'255': self.STATUS_LED_COLOR_GREEN, '255': self.STATUS_LED_COLOR_GREEN,
'0': self.STATUS_LED_COLOR_OFF '0': self.STATUS_LED_COLOR_OFF

File diff suppressed because it is too large Load Diff

View File

@ -14,6 +14,7 @@ import os.path
try: try:
from sonic_platform_base.thermal_base import ThermalBase from sonic_platform_base.thermal_base import ThermalBase
from helper import APIHelper
except ImportError as e: except ImportError as e:
raise ImportError(str(e) + "- required module not found") raise ImportError(str(e) + "- required module not found")
@ -27,6 +28,7 @@ class Thermal(ThermalBase):
def __init__(self, thermal_index): def __init__(self, thermal_index):
self.index = thermal_index self.index = thermal_index
self._api_helper = APIHelper()
# Add thermal name # Add thermal name
self.THERMAL_NAME_LIST.append("Front-panel temp sensor 1") self.THERMAL_NAME_LIST.append("Front-panel temp sensor 1")
@ -48,19 +50,11 @@ class Thermal(ThermalBase):
self.ss_key = self.THERMAL_NAME_LIST[self.index] self.ss_key = self.THERMAL_NAME_LIST[self.index]
self.ss_index = 1 self.ss_index = 1
def __read_txt_file(self, file_path):
try:
with open(file_path, 'r') as fd:
data = fd.read()
return data.strip()
except IOError:
pass
def __get_temp(self, temp_file): 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.__read_txt_file(temp_file_path) raw_temp = self._api_helper.read_txt_file(temp_file_path)
temp = float(raw_temp)/1000 temp = float(raw_temp)/1000
return "{:.3f}".format(temp) return float("{:.3f}".format(temp))
def __set_threshold(self, file_name, temperature): 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)

View File

@ -7,115 +7,79 @@
# #
############################################################################# #############################################################################
import ctypes import ctypes
import fcntl
import os import os
import subprocess import subprocess
import time import time
import array
try: try:
from sonic_platform_base.watchdog_base import WatchdogBase from sonic_platform_base.watchdog_base import WatchdogBase
from helper import APIHelper
except ImportError as e: except ImportError as e:
raise ImportError(str(e) + "- required module not found") raise ImportError(str(e) + "- required module not found")
""" ioctl constants """ PLATFORM_CPLD_PATH = '/sys/devices/platform/dx010_cpld'
IO_WRITE = 0x40000000 GETREG_FILE = 'getreg'
IO_READ = 0x80000000 SETREG_FILE = 'setreg'
IO_READ_WRITE = 0xC0000000 WDT_ENABLE_REG = '0x141'
IO_SIZE_INT = 0x00040000 WDT_TIMER_L_BIT_REG = '0x142'
IO_SIZE_40 = 0x00280000 WDT_TIMER_M_BIT_REG = '0x143'
IO_TYPE_WATCHDOG = ord('W') << 8 WDT_TIMER_H_BIT_REG = '0x144'
WDT_KEEP_ALVIVE_REG = '0x145'
WDR_INT = IO_READ | IO_SIZE_INT | IO_TYPE_WATCHDOG ENABLE_CMD = '0x1'
WDR_40 = IO_READ | IO_SIZE_40 | IO_TYPE_WATCHDOG DISABLE_CMD = '0x0'
WDWR_INT = IO_READ_WRITE | IO_SIZE_INT | IO_TYPE_WATCHDOG
""" Watchdog ioctl commands """
WDIOC_GETSUPPORT = 0 | WDR_40
WDIOC_GETSTATUS = 1 | WDR_INT
WDIOC_GETBOOTSTATUS = 2 | WDR_INT
WDIOC_GETTEMP = 3 | WDR_INT
WDIOC_SETOPTIONS = 4 | WDR_INT
WDIOC_KEEPALIVE = 5 | WDR_INT
WDIOC_SETTIMEOUT = 6 | WDWR_INT
WDIOC_GETTIMEOUT = 7 | WDR_INT
WDIOC_SETPRETIMEOUT = 8 | WDWR_INT
WDIOC_GETPRETIMEOUT = 9 | WDR_INT
WDIOC_GETTIMELEFT = 10 | WDR_INT
""" Watchdog status constants """
WDIOS_DISABLECARD = 0x0001
WDIOS_ENABLECARD = 0x0002
WDT_COMMON_ERROR = -1 WDT_COMMON_ERROR = -1
WD_MAIN_IDENTITY = "iTCO_wdt"
WDT_SYSFS_PATH = "/sys/class/watchdog/"
class Watchdog(WatchdogBase): class Watchdog(WatchdogBase):
def __init__(self): def __init__(self):
# Init helper
self._api_helper = APIHelper()
# Init cpld reg path
self.setreg_path = os.path.join(PLATFORM_CPLD_PATH, SETREG_FILE)
self.getreg_path = os.path.join(PLATFORM_CPLD_PATH, GETREG_FILE)
self.watchdog, self.wdt_main_dev_name = self._get_wdt()
self.status_path = "/sys/class/watchdog/%s/status" % self.wdt_main_dev_name
self.state_path = "/sys/class/watchdog/%s/state" % self.wdt_main_dev_name
self.timeout_path = "/sys/class/watchdog/%s/timeout" % self.wdt_main_dev_name
# Set default value # Set default value
self._disable() self._disable()
self.armed = False self.armed = False
self.timeout = self._gettimeout(self.timeout_path) self.timeout = self._gettimeout()
def _is_wd_main(self, dev):
"""
Checks watchdog identity
"""
identity = self._read_file(
"{}/{}/identity".format(WDT_SYSFS_PATH, dev))
return identity == WD_MAIN_IDENTITY
def _get_wdt(self):
"""
Retrieves watchdog device
"""
wdt_main_dev_list = [dev for dev in os.listdir(
"/dev/") if dev.startswith("watchdog") and self._is_wd_main(dev)]
if not wdt_main_dev_list:
return None
wdt_main_dev_name = wdt_main_dev_list[0]
watchdog_device_path = "/dev/{}".format(wdt_main_dev_name)
watchdog = os.open(watchdog_device_path, os.O_RDWR)
return watchdog, wdt_main_dev_name
def _read_file(self, file_path):
"""
Read text file
"""
try:
with open(file_path, "r") as fd:
txt = fd.read()
except IOError:
return WDT_COMMON_ERROR
return txt.strip()
def _enable(self): def _enable(self):
""" """
Turn on the watchdog timer Turn on the watchdog timer
""" """
req = array.array('h', [WDIOS_ENABLECARD]) # echo 0x141 0x1 > /sys/devices/platform/dx010_cpld/setreg
fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False) enable_val = '{} {}'.format(WDT_ENABLE_REG, ENABLE_CMD)
return self._api_helper.write_txt_file(self.setreg_path, enable_val)
def _disable(self): def _disable(self):
""" """
Turn off the watchdog timer Turn off the watchdog timer
""" """
req = array.array('h', [WDIOS_DISABLECARD]) # echo 0x141 0x0 > /sys/devices/platform/dx010_cpld/setreg
fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False) disable_val = '{} {}'.format(WDT_ENABLE_REG, DISABLE_CMD)
return self._api_helper.write_txt_file(self.setreg_path, disable_val)
def _keepalive(self): def _keepalive(self):
""" """
Keep alive watchdog timer Keep alive watchdog timer
""" """
fcntl.ioctl(self.watchdog, WDIOC_KEEPALIVE) # echo 0x145 0x1 > /sys/devices/platform/dx010_cpld/setreg
enable_val = '{} {}'.format(WDT_KEEP_ALVIVE_REG, ENABLE_CMD)
return self._api_helper.write_txt_file(self.setreg_path, enable_val)
def _get_level_hex(self, sub_hex):
sub_hex_str = sub_hex.replace("x", "0")
return hex(int(sub_hex_str, 16))
def _seconds_to_lmh_hex(self, seconds):
ms = seconds*1000 # calculate timeout in ms format
hex_str = hex(ms)
l = self._get_level_hex(hex_str[-2:])
m = self._get_level_hex(hex_str[-4:-2])
h = self._get_level_hex(hex_str[-6:-4])
return (l, m, h)
def _settimeout(self, seconds): def _settimeout(self, seconds):
""" """
@ -123,29 +87,35 @@ class Watchdog(WatchdogBase):
@param seconds - timeout in seconds @param seconds - timeout in seconds
@return is the actual set timeout @return is the actual set timeout
""" """
req = array.array('I', [seconds]) # max = 0xffffff = 16777.215 seconds
fcntl.ioctl(self.watchdog, WDIOC_SETTIMEOUT, req, True)
return int(req[0])
def _gettimeout(self, timeout_path): (l, m, h) = self._seconds_to_lmh_hex(seconds)
set_h_val = '{} {}'.format(WDT_TIMER_H_BIT_REG, h)
set_m_val = '{} {}'.format(WDT_TIMER_M_BIT_REG, m)
set_l_val = '{} {}'.format(WDT_TIMER_L_BIT_REG, l)
self._api_helper.write_txt_file(self.setreg_path, set_h_val)
self._api_helper.write_txt_file(self.setreg_path, set_m_val)
self._api_helper.write_txt_file(self.setreg_path, set_l_val)
return seconds
def _gettimeout(self):
""" """
Get watchdog timeout Get watchdog timeout
@return watchdog timeout @return watchdog timeout
""" """
req = array.array('I', [0])
fcntl.ioctl(self.watchdog, WDIOC_GETTIMEOUT, req, True)
return int(req[0]) h_bit = self._api_helper.get_cpld_reg_value(
self.getreg_path, WDT_TIMER_H_BIT_REG)
m_bit = self._api_helper.get_cpld_reg_value(
self.getreg_path, WDT_TIMER_M_BIT_REG)
l_bit = self._api_helper.get_cpld_reg_value(
self.getreg_path, WDT_TIMER_L_BIT_REG)
def _gettimeleft(self): hex_time = '0x{}{}{}'.format(h_bit[2:], m_bit[2:], l_bit[2:])
""" ms = int(hex_time, 16)
Get time left before watchdog timer expires return int(float(ms)/1000)
@return time left in seconds
"""
req = array.array('I', [0])
fcntl.ioctl(self.watchdog, WDIOC_GETTIMELEFT, req, True)
return int(req[0])
################################################################# #################################################################
@ -169,12 +139,15 @@ class Watchdog(WatchdogBase):
try: try:
if self.timeout != seconds: if self.timeout != seconds:
self.timeout = self._settimeout(seconds) self.timeout = self._settimeout(seconds)
if self.armed: if self.armed:
self._keepalive() self._keepalive()
else: else:
self._enable() self._enable()
self.armed = True self.armed = True
ret = self.timeout ret = self.timeout
self.arm_timestamp = time.time()
except IOError as e: except IOError as e:
pass pass
@ -215,19 +188,4 @@ class Watchdog(WatchdogBase):
watchdog timer. If the watchdog is not armed, returns -1. watchdog timer. If the watchdog is not armed, returns -1.
""" """
timeleft = WDT_COMMON_ERROR return int(self.timeout - (time.time() - self.arm_timestamp)) if self.armed else WDT_COMMON_ERROR
if self.armed:
try:
timeleft = self._gettimeleft()
except IOError:
pass
return timeleft
def __del__(self):
"""
Close watchdog
"""
os.close(self.watchdog)

View File

@ -2,7 +2,8 @@ dx010/scripts/dx010_check_qsfp.sh usr/local/bin
dx010/cfg/dx010-modules.conf etc/modules-load.d dx010/cfg/dx010-modules.conf etc/modules-load.d
dx010/systemd/platform-modules-dx010.service lib/systemd/system dx010/systemd/platform-modules-dx010.service lib/systemd/system
dx010/scripts/fancontrol.sh etc/init.d dx010/scripts/fancontrol.sh etc/init.d
services/fancontrol/fancontrol.service lib/systemd/system dx010/scripts/fancontrol.service lib/systemd/system
dx010/scripts/thermal_overload_control.sh usr/local/bin
services/fancontrol/fancontrol usr/local/bin services/fancontrol/fancontrol usr/local/bin
dx010/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/x86_64-cel_seastone-r0 dx010/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/x86_64-cel_seastone-r0
services/platform_api/platform_api_mgnt.sh usr/local/bin services/platform_api/platform_api_mgnt.sh usr/local/bin

View File

@ -1,7 +1,7 @@
haliburton/cfg/haliburton-modules.conf etc/modules-load.d haliburton/cfg/haliburton-modules.conf etc/modules-load.d
haliburton/systemd/platform-modules-haliburton.service lib/systemd/system haliburton/systemd/platform-modules-haliburton.service lib/systemd/system
haliburton/script/fancontrol.sh etc/init.d haliburton/script/fancontrol.sh etc/init.d
services/fancontrol/fancontrol.service lib/systemd/system haliburton/script/fancontrol.service lib/systemd/system
services/fancontrol/fancontrol usr/local/bin services/fancontrol/fancontrol usr/local/bin
haliburton/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/x86_64-cel_e1031-r0 haliburton/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/x86_64-cel_e1031-r0
services/platform_api/platform_api_mgnt.sh usr/local/bin services/platform_api/platform_api_mgnt.sh usr/local/bin

View File

@ -76,42 +76,52 @@
#define PORT_SFPP1 33 #define PORT_SFPP1 33
#define PORT_SFPP2 34 #define PORT_SFPP2 34
#define PORT_ID_BANK1 0x210
#define PORT_ID_BANK2 0x290
#define PORT_ID_BANK3 0x390
#define OPCODE_ID_BANK1 0x211 #define CPLD_I2C_CLK_100Khz_BIT BIT(6)
#define OPCODE_ID_BANK2 0x291 #define CPLD_I2C_DATA_SZ_MASK GENMASK(7,4)
#define OPCODE_ID_BANK3 0x391 #define CPLD_I2C_CMD_SZ_MASK GENMASK(1,0)
#define CPLD_I2C_ERR BIT(7)
#define CPLD_I2C_BUSY BIT(6)
#define CPLD_I2C_RST_BIT BIT(0)
#define CPLD_I2C_RESET 0
#define CPLD_I2C_UNRESET 1
#define CPLD_I2C_DATA_SZ_MAX 8
#define CPLD_I2C_CMD_SZ_MAX 3
#define DEVADDR_ID_BANK1 0x212
#define DEVADDR_ID_BANK2 0x292
#define DEVADDR_ID_BANK3 0x392
#define CMDBYT_ID_BANK1 0x213 #define CPLD_I2C_BANK1_BASE 0x210
#define CMDBYT_ID_BANK2 0x293 #define CPLD_I2C_BANK2_BASE 0x290
#define CMDBYT_ID_BANK3 0x393 #define CPLD_I2C_BANK3_BASE 0x390
#define WRITE_ID_BANK1 0x220 #define I2C_PORT_ID 0x0
#define WRITE_ID_BANK2 0x2A0 #define I2C_OPCODE 0x1
#define WRITE_ID_BANK3 0x3A0 #define I2C_DEV_ADDR 0x2
#define I2C_CMD_BYT0 0x3
#define I2C_SSR 0x6
#define I2C_WRITE_DATA 0x10
#define I2C_READ_DATA 0x20
#define READ_ID_BANK1 0x230 /*
#define READ_ID_BANK2 0x2B0 * private data to send to I2C core
#define READ_ID_BANK3 0x3B0 */
struct current_xfer {
#define SSRR_ID_BANK1 0x216 u8 addr;
#define SSRR_ID_BANK2 0x296 u8 cmd[CPLD_I2C_CMD_SZ_MAX];
#define SSRR_ID_BANK3 0x396 u8 cmd_len;
u8 data_len;
#define HST_CNTL2_QUICK 0x00 union i2c_smbus_data *data;
#define HST_CNTL2_BYTE 0x01 };
#define HST_CNTL2_BYTE_DATA 0x02
#define HST_CNTL2_WORD_DATA 0x03
#define HST_CNTL2_BLOCK 0x05
/*
* private data of I2C adapter
* base_addr: Base address of this I2C adapter core.
* port_id: The port ID, use to mux an i2c core to a font panel port.
* current_xfer: The struct carry current data setup of current smbus transfer.
*/
struct dx010_i2c_data { struct dx010_i2c_data {
int base_addr;
int portid; int portid;
struct current_xfer curr_xfer;
}; };
struct dx010_cpld_data { struct dx010_cpld_data {
@ -364,179 +374,210 @@ static struct platform_device cel_dx010_lpc_dev = {
} }
}; };
// TODO: Refactoring this function with helper functions.
static s32 cpld_smbus_transfer(struct dx010_i2c_data *priv) {
/** u8 val;
* Read eeprom of QSFP device. s32 error;
* @param a i2c adapter. unsigned long ioBase;
* @param addr address to read. short portid, opcode, devaddr, cmdbyte0, ssr, writedata, readdata;
* @param new_data QSFP port number struct. union i2c_smbus_data *data;
* @param cmd i2c command.
* @return 0 if not error, else the error code.
*/
static int i2c_read_eeprom(struct i2c_adapter *a, u16 addr,
struct dx010_i2c_data *new_data, u8 cmd, union i2c_smbus_data *data){
u32 reg; error = -EIO;
int ioBase=0;
char byte;
short temp;
short portid, opcode, devaddr, cmdbyte0, ssrr, writedata, readdata;
__u16 word_data;
int error = -EIO;
mutex_lock(&cpld_data->cpld_lock); mutex_lock(&cpld_data->cpld_lock);
if (((new_data->portid >= PORT_BANK1_START) ioBase = priv->base_addr;
&& (new_data->portid <= PORT_BANK1_END)) data = priv->curr_xfer.data;
|| (new_data->portid == PORT_SFPP1)
|| (new_data->portid == PORT_SFPP2))
{
portid = PORT_ID_BANK1;
opcode = OPCODE_ID_BANK1;
devaddr = DEVADDR_ID_BANK1;
cmdbyte0 = CMDBYT_ID_BANK1;
ssrr = SSRR_ID_BANK1;
writedata = WRITE_ID_BANK1;
readdata = READ_ID_BANK1;
}else if ((new_data->portid >= PORT_BANK2_START) && (new_data->portid <= PORT_BANK2_END)){
portid = PORT_ID_BANK2;
opcode = OPCODE_ID_BANK2;
devaddr = DEVADDR_ID_BANK2;
cmdbyte0 = CMDBYT_ID_BANK2;
ssrr = SSRR_ID_BANK2;
writedata = WRITE_ID_BANK2;
readdata = READ_ID_BANK2;
}else if ((new_data->portid >= PORT_BANK3_START) && (new_data->portid <= PORT_BANK3_END)){
portid = PORT_ID_BANK3;
opcode = OPCODE_ID_BANK3;
devaddr = DEVADDR_ID_BANK3;
cmdbyte0 = CMDBYT_ID_BANK3;
ssrr = SSRR_ID_BANK3;
writedata = WRITE_ID_BANK3;
readdata = READ_ID_BANK3;
}else{
/* Invalid parameter! */
error = -EINVAL;
goto exit;
}
while ((inb(ioBase + ssrr) & 0x40)); portid = ioBase + I2C_PORT_ID;
if ((inb(ioBase + ssrr) & 0x80) == 0x80) { opcode = ioBase + I2C_OPCODE;
error = -EIO; devaddr = ioBase + I2C_DEV_ADDR;
/* Read error reset the port */ cmdbyte0 = ioBase + I2C_CMD_BYT0;
outb(0x00, ioBase + ssrr); ssr = ioBase + I2C_SSR;
udelay(3000); writedata = ioBase + I2C_WRITE_DATA;
outb(0x01, ioBase + ssrr); readdata = ioBase + I2C_READ_DATA;
goto exit;
}
byte = 0x40 +new_data->portid; /* Wait for the core to be free */
reg = cmd; pr_debug("CPLD_I2C Wait busy bit(6) to be cleared\n");
outb(byte, ioBase + portid); do {
outb(reg,ioBase + cmdbyte0); val = inb(ssr);
byte = 33; if ((val & CPLD_I2C_BUSY) == 0)
outb(byte, ioBase + opcode); break;
addr = addr << 1;
addr |= 0x01;
outb(addr, ioBase + devaddr);
while ((inb(ioBase + ssrr) & 0x40))
{
udelay(100); udelay(100);
} } while (true); // Risky - add timeout
if ((inb(ioBase + ssrr) & 0x80) == 0x80) { /*
/* Read error reset the port */ * If any error happen here, we do soft-reset
error = -EIO; * and check the BUSY/ERROR again.
outb(0x00, ioBase + ssrr); */
pr_debug("CPLD_I2C Check error bit(7)\n");
if (val & CPLD_I2C_ERR) {
pr_debug("CPLD_I2C Error, try soft-reset\n");
outb(CPLD_I2C_RESET, ssr);
udelay(3000); udelay(3000);
outb(0x01, ioBase + ssrr); outb(CPLD_I2C_UNRESET, ssr);
goto exit;
val = inb(ssr);
if (val & (CPLD_I2C_BUSY | CPLD_I2C_ERR)) {
pr_debug("CPLD_I2C Error, core busy after reset\n");
error = -EIO;
goto exit_unlock;
}
} }
temp = ioBase + readdata; /* Configure PortID */
word_data = inb(temp); val = priv->portid | CPLD_I2C_CLK_100Khz_BIT;
word_data |= (inb(++temp) << 8); outb(val, portid);
pr_debug("CPLD_I2C Write PortID 0x%x\n", val);
mutex_unlock(&cpld_data->cpld_lock); /* Configure OP_Code */
data->word = word_data; val = (priv->curr_xfer.data_len << 4) & CPLD_I2C_DATA_SZ_MASK;
return 0; val |= (priv->curr_xfer.cmd_len & CPLD_I2C_CMD_SZ_MASK);
outb(val, opcode);
pr_debug("CPLD_I2C Write OP_Code 0x%x\n", val);
exit: /* Configure CMD_Byte */
outb(priv->curr_xfer.cmd[0], cmdbyte0);
pr_debug("CPLD_I2C Write CMD_Byte 0x%x\n", priv->curr_xfer.cmd[0]);
/* Configure write data buffer */
if ((priv->curr_xfer.addr & BIT(0)) == I2C_SMBUS_WRITE){
pr_debug("CPLD_I2C Write WR_DATA buffer\n");
switch(priv->curr_xfer.data_len){
case 1:
outb(data->byte, writedata);
break;
case 2:
outb(data->block[0], writedata);
outb(data->block[1], ++writedata);
break;
}
}
/* Start transfer, write the device address register */
pr_debug("CPLD_I2C Write DEV_ADDR 0x%x\n", priv->curr_xfer.addr);
outb(priv->curr_xfer.addr, devaddr);
/* Wait for transfer finish */
pr_debug("CPLD_I2C Wait busy bit(6) to be cleared\n");
do {
val = inb(ssr);
if ((val & CPLD_I2C_BUSY) == 0)
break;
udelay(100);
} while (true); // Risky - add timeout
pr_debug("CPLD_I2C Check error bit(7)\n");
if (val & CPLD_I2C_ERR) {
error = -EIO;
goto exit_unlock;
}
/* Get the data from buffer */
if ((priv->curr_xfer.addr & BIT(0)) == I2C_SMBUS_READ){
pr_debug("CPLD_I2C Read RD_DATA buffer\n");
switch (priv->curr_xfer.data_len) {
case 1:
data->byte = inb(readdata);
break;
case 2:
data->block[0] = inb(readdata);
data->block[1] = inb(++readdata);
break;
}
}
error = 0;
exit_unlock:
pr_debug("CPLD_I2C Exit with %d\n", error);
mutex_unlock(&cpld_data->cpld_lock); mutex_unlock(&cpld_data->cpld_lock);
return error; return error;
} }
static int dx010_i2c_access(struct i2c_adapter *a, u16 addr, /*
unsigned short flags, char rw, u8 cmd, * dx010_smbus_xfer - execute LPC-SMBus transfer
int size, union i2c_smbus_data *data) * Returns a negative errno code else zero on success.
{ */
static s32 dx010_smbus_xfer(struct i2c_adapter *adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data *data) {
int error = 0; int error = 0;
struct dx010_i2c_data *priv;
struct dx010_i2c_data *new_data; priv = i2c_get_adapdata(adap);
/* Write the command register */ pr_debug("smbus_xfer called RW:%x CMD:%x SIZE:0x%x",
new_data = i2c_get_adapdata(a); read_write, command, size);
priv->curr_xfer.addr = (addr << 1) | read_write;
priv->curr_xfer.data = data;
/* Map the size to what the chip understands */ /* Map the size to what the chip understands */
switch (size) { switch (size) {
case I2C_SMBUS_QUICK:
size = HST_CNTL2_QUICK;
break;
case I2C_SMBUS_BYTE: case I2C_SMBUS_BYTE:
size = HST_CNTL2_BYTE; priv->curr_xfer.cmd_len = 0;
priv->curr_xfer.data_len = 1;
break; break;
case I2C_SMBUS_BYTE_DATA: case I2C_SMBUS_BYTE_DATA:
size = HST_CNTL2_BYTE_DATA; priv->curr_xfer.cmd_len = 1;
priv->curr_xfer.data_len = 1;
priv->curr_xfer.cmd[0] = command;
break; break;
case I2C_SMBUS_WORD_DATA: case I2C_SMBUS_WORD_DATA:
size = HST_CNTL2_WORD_DATA; priv->curr_xfer.cmd_len = 1;
break; priv->curr_xfer.data_len = 2;
case I2C_SMBUS_BLOCK_DATA: priv->curr_xfer.cmd[0] = command;
size = HST_CNTL2_BLOCK;
break; break;
default: default:
dev_warn(&a->dev, "Unsupported transaction %d\n", size); dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
error = -EOPNOTSUPP; error = -EOPNOTSUPP;
goto Done; goto Done;
} }
switch (size) { error = cpld_smbus_transfer(priv);
case HST_CNTL2_BYTE: /* Result put in SMBHSTDAT0 */
break;
case HST_CNTL2_BYTE_DATA:
break;
case HST_CNTL2_WORD_DATA:
if( 0 == i2c_read_eeprom(a,addr,new_data,cmd,data)){
error = 0;
}else{
error = -EIO;
}
break;
}
Done: Done:
return error; return error;
} }
static u32 dx010_i2c_func(struct i2c_adapter *a) // TODO: Add support for I2C_FUNC_SMBUS_PROC_CALL and I2C_FUNC_SMBUS_I2C_BLOCK
{ static u32 dx010_i2c_func(struct i2c_adapter *a) {
return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | return I2C_FUNC_SMBUS_READ_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_BLOCK_DATA; I2C_FUNC_SMBUS_WORD_DATA;
} }
static const struct i2c_algorithm dx010_i2c_algorithm = { static const struct i2c_algorithm dx010_i2c_algorithm = {
.smbus_xfer = dx010_i2c_access, .smbus_xfer = dx010_smbus_xfer,
.functionality = dx010_i2c_func, .functionality = dx010_i2c_func,
}; };
static struct i2c_adapter * cel_dx010_i2c_init(struct platform_device *pdev, int portid) static struct i2c_adapter *cel_dx010_i2c_init(struct platform_device *pdev, int portid)
{ {
int error; int error;
int base_addr;
struct i2c_adapter *new_adapter; struct i2c_adapter *new_adapter;
struct dx010_i2c_data *new_data; struct dx010_i2c_data *priv;
switch (portid) {
case PORT_SFPP1 ... PORT_SFPP2:
case PORT_BANK1_START ... PORT_BANK1_END:
base_addr = CPLD_I2C_BANK1_BASE;
break;
case PORT_BANK2_START ... PORT_BANK2_END:
base_addr = CPLD_I2C_BANK2_BASE;
break;
case PORT_BANK3_START ... PORT_BANK3_END:
base_addr = CPLD_I2C_BANK3_BASE;
break;
default:
dev_err(&pdev->dev, "Invalid port adapter ID: %d\n", portid);
goto error_exit;
}
new_adapter = kzalloc(sizeof(*new_adapter), GFP_KERNEL); new_adapter = kzalloc(sizeof(*new_adapter), GFP_KERNEL);
if (!new_adapter) if (!new_adapter)
@ -544,31 +585,39 @@ static struct i2c_adapter * cel_dx010_i2c_init(struct platform_device *pdev, int
new_adapter->dev.parent = &pdev->dev; new_adapter->dev.parent = &pdev->dev;
new_adapter->owner = THIS_MODULE; new_adapter->owner = THIS_MODULE;
new_adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; new_adapter->class = I2C_CLASS_DEPRECATED;
new_adapter->algo = &dx010_i2c_algorithm; new_adapter->algo = &dx010_i2c_algorithm;
snprintf(new_adapter->name, sizeof(new_adapter->name), snprintf(new_adapter->name, sizeof(new_adapter->name),
"SMBus dx010 i2c Adapter portid@%04x", portid); "SMBus dx010 i2c Adapter port %d", portid);
new_data = kzalloc(sizeof(*new_data), GFP_KERNEL); priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!new_data) if (!priv) {
return NULL; goto free_adap;
}
new_data->portid = portid; priv->portid = portid;
priv->base_addr = base_addr;
i2c_set_adapdata(new_adapter,new_data);
i2c_set_adapdata(new_adapter, priv);
error = i2c_add_adapter(new_adapter); error = i2c_add_adapter(new_adapter);
if(error) if(error)
return NULL; goto free_data;
return new_adapter; return new_adapter;
free_adap:
kzfree(new_adapter);
free_data:
kzfree(priv);
error_exit:
return NULL;
}; };
static int cel_dx010_lpc_drv_probe(struct platform_device *pdev) static int cel_dx010_lpc_drv_probe(struct platform_device *pdev)
{ {
struct resource *res; struct resource *res;
int ret =0; int ret = 0;
int portid_count; int portid_count;
cpld_data = devm_kzalloc(&pdev->dev, sizeof(struct dx010_cpld_data), cpld_data = devm_kzalloc(&pdev->dev, sizeof(struct dx010_cpld_data),

View File

@ -0,0 +1,12 @@
[Unit]
Description=fan speed regulator
After=platform-modules-dx010.service
Before=pmon.service
[Service]
ExecStart=-/etc/init.d/fancontrol.sh start
ExecStop=-/etc/init.d/fancontrol.sh stop
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,75 @@
#!/bin/bash
#
# Copyright 2020-present Celestica. All Rights Reserved.
#
# This program file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
#
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin
SETREG_FILE=/sys/devices/platform/dx010_cpld/setreg
TOVERREG=0x140
CPUOVER=0xa1
ASICOVER=0xa2
prog="$0"
command="$1"
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root"
exit 1
fi
usage() {
echo "Usage: thermal_overload_control.sh [option] <command>"
echo
echo "Options:"
echo " -h, --help : to print this message."
echo
echo "Commands:"
echo
echo " cpu: To enabling CPU thermal overload handler"
echo
echo " asic : To enabling ASIC thermal overload handler"
echo
}
cpu_overload() {
logger "Enable CPU thermal overload control"
set_reg=`echo ${TOVERREG} ${CPUOVER} > ${SETREG_FILE}`
}
asic_overload() {
logger "Enable ASIC thermal overload control"
set_reg=`echo ${TOVERREG} ${ASICOVER} > ${SETREG_FILE}`
}
if [ $# -lt 1 ]; then
usage
exit -1
fi
case "$command" in
-h | --help)
usage
;;
cpu)
cpu_overload
;;
asic)
asic_overload
;;
*)
usage
exit -1
;;
esac
exit $?

View File

@ -39,6 +39,7 @@
# #
PIDFILE="/var/run/fancontrol.pid" PIDFILE="/var/run/fancontrol.pid"
THERMAL_OVERLOAD_CONTROL_FILE="/usr/local/bin/thermal_overload_control.sh"
#DEBUG=1 #DEBUG=1
MAX=255 MAX=255
@ -68,6 +69,8 @@ function LoadConfig
MINPWM=`egrep '^MINPWM=.*$' $1 | sed -e 's/MINPWM=//g'` MINPWM=`egrep '^MINPWM=.*$' $1 | sed -e 's/MINPWM=//g'`
MAXPWM=`egrep '^MAXPWM=.*$' $1 | sed -e 's/MAXPWM=//g'` MAXPWM=`egrep '^MAXPWM=.*$' $1 | sed -e 's/MAXPWM=//g'`
THYST=`egrep '^THYST=.*$' $1 | sed -e 's/THYST=//g'` THYST=`egrep '^THYST=.*$' $1 | sed -e 's/THYST=//g'`
MAXTEMPCRIT=`egrep '^MAXTEMPCRIT=.*$' $1 | sed -e 's/MAXTEMPCRIT=//g'`
MAXTEMPTYPE=`egrep '^MAXTEMPTYPE=.*$' $1 | sed -e 's/MAXTEMPTYPE=//g'`
echo echo
# Check whether all mandatory settings are set # Check whether all mandatory settings are set
if [[ -z ${INTERVAL} || -z ${FCTEMPS} || -z ${MINTEMP} || -z ${MAXTEMP} || -z ${MINSTART} || -z ${MINSTOP} ]] if [[ -z ${INTERVAL} || -z ${FCTEMPS} || -z ${MINTEMP} || -z ${MAXTEMP} || -z ${MINSTART} || -z ${MINSTOP} ]]
@ -158,6 +161,23 @@ function LoadConfig
let fcvcount=fcvcount+1 let fcvcount=fcvcount+1
done done
echo echo
let tscount=0
for ts in $MAXTEMPCRIT
do
CSTEMP[$tscount]=`echo $ts | cut -d '=' -f1`
CSMAXTEMPCRIT[$tscount]=`echo $ts | cut -d '=' -f2`
CSMAXTEMPTYPE=($(echo $MAXTEMPTYPE |sed -e 's/ /\n/g'| cut -d'=' -f2))
echo
echo "Settings for ${CSMAXTEMPTYPE[$tscount]} temperature sensor:"
echo " Depends on ${CSTEMP[$tscount]}"
echo " MAXTEMPCRIT=${CSMAXTEMPCRIT[$tscount]}"
let tscount=tscount+1
done
echo
} }
function CheckFanFault() function CheckFanFault()
@ -175,6 +195,28 @@ function CheckFanFault()
return 0 return 0
} }
function CheckTempOver()
{
let tempcount=0
while (( $tempcount < ${#CSTEMP[@]} )) # go through all temp.
do
ctemp=`cat ${CSTEMP[$tempcount]}`
let maxcrit="${CSMAXTEMPCRIT[$tempcount]}*1000"
if [ $ctemp -ge $maxcrit ]
then
logger "Thermal overload : ${CSMAXTEMPTYPE[$tempcount]} temperature ${ctemp} > ${maxcrit}"
if [ -f "$THERMAL_OVERLOAD_CONTROL_FILE" ]
then
toc_cmd="${THERMAL_OVERLOAD_CONTROL_FILE} ${CSMAXTEMPTYPE[$tempcount],,}"
bash $toc_cmd
exit 1
fi
fi
let tempcount=$tempcount+1
done
return 0
}
function DevicePath() function DevicePath()
{ {
if [ -h "$1/device" ] if [ -h "$1/device" ]
@ -475,6 +517,9 @@ function UpdateFanSpeeds
continue continue
fi fi
#check thermal overload
CheckTempOver
read tval < ${tsens} read tval < ${tsens}
if [ $? -ne 0 ] if [ $? -ne 0 ]
then then