[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
This commit is contained in:
parent
ae9a86fac4
commit
47316de5c4
@ -8,4 +8,6 @@ MINSTART=13-002e/pwm1=89 13-002e/pwm2=89 13-002e/pwm3=89 13-002e/pwm4=89 13-002e
|
||||
MINSTOP=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
|
||||
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
|
||||
|
@ -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
|
||||
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
|
||||
|
@ -1,2 +1,2 @@
|
||||
__all__ = ["platform", "chassis"]
|
||||
from sonic_platform import *
|
||||
import chassis
|
||||
import platform
|
||||
|
@ -23,9 +23,9 @@ NUM_SFP = 32
|
||||
NUM_COMPONENT = 5
|
||||
RESET_REGISTER = "0x103"
|
||||
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"
|
||||
PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt"
|
||||
GETREG_PATH = "/sys/devices/platform/dx010_cpld/getreg"
|
||||
HOST_CHK_CMD = "docker > /dev/null 2>&1"
|
||||
|
||||
|
||||
@ -118,35 +118,38 @@ class Chassis(ChassisBase):
|
||||
one of the predefined strings in this class. If the first string
|
||||
is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used
|
||||
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 = self.REBOOT_CAUSE_HARDWARE_OTHER
|
||||
|
||||
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)
|
||||
|
||||
reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE)
|
||||
sw_reboot_cause = self._api_helper.read_txt_file(
|
||||
reboot_cause_path) or "Unknown"
|
||||
prev_sw_reboot_cause = self._api_helper.read_txt_file(
|
||||
prev_reboot_cause_path) or "Unknown"
|
||||
hw_reboot_cause = self._api_helper.get_cpld_reg_value(
|
||||
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":
|
||||
reboot_cause = self.REBOOT_CAUSE_POWER_LOSS
|
||||
elif sw_reboot_cause != "Unknown" and hw_reboot_cause == "0x11":
|
||||
reboot_cause = self.REBOOT_CAUSE_NON_HARDWARE
|
||||
description = sw_reboot_cause
|
||||
elif prev_reboot_cause_path != "Unknown" and hw_reboot_cause == "0x11":
|
||||
reboot_cause = self.REBOOT_CAUSE_NON_HARDWARE
|
||||
description = prev_sw_reboot_cause
|
||||
elif hw_reboot_cause == "0x22":
|
||||
reboot_cause = self.REBOOT_CAUSE_WATCHDOG,
|
||||
else:
|
||||
reboot_cause = self.REBOOT_CAUSE_HARDWARE_OTHER
|
||||
description = 'Unknown reason'
|
||||
prev_reboot_cause = {
|
||||
'0x11': (self.REBOOT_CAUSE_POWER_LOSS, 'Power on reset'),
|
||||
'0x22': (self.REBOOT_CAUSE_HARDWARE_OTHER, 'CPLD_WD_RESET'),
|
||||
'0x33': (self.REBOOT_CAUSE_HARDWARE_OTHER, 'Power cycle reset triggered by CPU'),
|
||||
'0x44': (self.REBOOT_CAUSE_HARDWARE_OTHER, 'Power cycle reset triggered by reset button'),
|
||||
'0x55': (self.REBOOT_CAUSE_THERMAL_OVERLOAD_CPU, ''),
|
||||
'0x66': (self.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC, ''),
|
||||
'0x77': (self.REBOOT_CAUSE_WATCHDOG, '')
|
||||
}.get(hw_reboot_cause, (self.REBOOT_CAUSE_HARDWARE_OTHER, '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 #########################
|
||||
@ -229,9 +232,9 @@ class Chassis(ChassisBase):
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the PSU
|
||||
Retrieves the presence of the Chassis
|
||||
Returns:
|
||||
bool: True if PSU is present, False if not
|
||||
bool: True if Chassis is present, False if not
|
||||
"""
|
||||
return True
|
||||
|
||||
|
@ -70,6 +70,19 @@ class APIHelper():
|
||||
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 = ""
|
||||
|
@ -7,115 +7,79 @@
|
||||
#
|
||||
#############################################################################
|
||||
import ctypes
|
||||
import fcntl
|
||||
import os
|
||||
import subprocess
|
||||
import time
|
||||
import array
|
||||
|
||||
try:
|
||||
from sonic_platform_base.watchdog_base import WatchdogBase
|
||||
from helper import APIHelper
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
""" ioctl constants """
|
||||
IO_WRITE = 0x40000000
|
||||
IO_READ = 0x80000000
|
||||
IO_READ_WRITE = 0xC0000000
|
||||
IO_SIZE_INT = 0x00040000
|
||||
IO_SIZE_40 = 0x00280000
|
||||
IO_TYPE_WATCHDOG = ord('W') << 8
|
||||
|
||||
WDR_INT = IO_READ | IO_SIZE_INT | IO_TYPE_WATCHDOG
|
||||
WDR_40 = IO_READ | IO_SIZE_40 | IO_TYPE_WATCHDOG
|
||||
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
|
||||
|
||||
PLATFORM_CPLD_PATH = '/sys/devices/platform/dx010_cpld'
|
||||
GETREG_FILE = 'getreg'
|
||||
SETREG_FILE = 'setreg'
|
||||
WDT_ENABLE_REG = '0x141'
|
||||
WDT_TIMER_L_BIT_REG = '0x142'
|
||||
WDT_TIMER_M_BIT_REG = '0x143'
|
||||
WDT_TIMER_H_BIT_REG = '0x144'
|
||||
WDT_KEEP_ALVIVE_REG = '0x145'
|
||||
ENABLE_CMD = '0x1'
|
||||
DISABLE_CMD = '0x0'
|
||||
WDT_COMMON_ERROR = -1
|
||||
WD_MAIN_IDENTITY = "iTCO_wdt"
|
||||
WDT_SYSFS_PATH = "/sys/class/watchdog/"
|
||||
|
||||
|
||||
class Watchdog(WatchdogBase):
|
||||
|
||||
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
|
||||
self._disable()
|
||||
self.armed = False
|
||||
self.timeout = self._gettimeout(self.timeout_path)
|
||||
|
||||
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()
|
||||
self.timeout = self._gettimeout()
|
||||
|
||||
def _enable(self):
|
||||
"""
|
||||
Turn on the watchdog timer
|
||||
"""
|
||||
req = array.array('h', [WDIOS_ENABLECARD])
|
||||
fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False)
|
||||
# echo 0x141 0x1 > /sys/devices/platform/dx010_cpld/setreg
|
||||
enable_val = '{} {}'.format(WDT_ENABLE_REG, ENABLE_CMD)
|
||||
return self._api_helper.write_txt_file(self.setreg_path, enable_val)
|
||||
|
||||
def _disable(self):
|
||||
"""
|
||||
Turn off the watchdog timer
|
||||
"""
|
||||
req = array.array('h', [WDIOS_DISABLECARD])
|
||||
fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False)
|
||||
# echo 0x141 0x0 > /sys/devices/platform/dx010_cpld/setreg
|
||||
disable_val = '{} {}'.format(WDT_ENABLE_REG, DISABLE_CMD)
|
||||
return self._api_helper.write_txt_file(self.setreg_path, disable_val)
|
||||
|
||||
def _keepalive(self):
|
||||
"""
|
||||
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):
|
||||
"""
|
||||
@ -123,29 +87,35 @@ class Watchdog(WatchdogBase):
|
||||
@param seconds - timeout in seconds
|
||||
@return is the actual set timeout
|
||||
"""
|
||||
req = array.array('I', [seconds])
|
||||
fcntl.ioctl(self.watchdog, WDIOC_SETTIMEOUT, req, True)
|
||||
return int(req[0])
|
||||
# max = 0xffffff = 16777.215 seconds
|
||||
|
||||
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
|
||||
@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):
|
||||
"""
|
||||
Get time left before watchdog timer expires
|
||||
@return time left in seconds
|
||||
"""
|
||||
req = array.array('I', [0])
|
||||
fcntl.ioctl(self.watchdog, WDIOC_GETTIMELEFT, req, True)
|
||||
|
||||
return int(req[0])
|
||||
hex_time = '0x{}{}{}'.format(h_bit[2:], m_bit[2:], l_bit[2:])
|
||||
ms = int(hex_time, 16)
|
||||
return int(float(ms)/1000)
|
||||
|
||||
#################################################################
|
||||
|
||||
@ -169,12 +139,15 @@ class Watchdog(WatchdogBase):
|
||||
try:
|
||||
if self.timeout != seconds:
|
||||
self.timeout = self._settimeout(seconds)
|
||||
|
||||
if self.armed:
|
||||
self._keepalive()
|
||||
else:
|
||||
self._enable()
|
||||
self.armed = True
|
||||
|
||||
ret = self.timeout
|
||||
self.arm_timestamp = time.time()
|
||||
except IOError as e:
|
||||
pass
|
||||
|
||||
@ -215,19 +188,4 @@ class Watchdog(WatchdogBase):
|
||||
watchdog timer. If the watchdog is not armed, returns -1.
|
||||
"""
|
||||
|
||||
timeleft = WDT_COMMON_ERROR
|
||||
|
||||
if self.armed:
|
||||
try:
|
||||
timeleft = self._gettimeleft()
|
||||
except IOError:
|
||||
pass
|
||||
|
||||
return timeleft
|
||||
|
||||
def __del__(self):
|
||||
"""
|
||||
Close watchdog
|
||||
"""
|
||||
|
||||
os.close(self.watchdog)
|
||||
return int(self.timeout - (time.time() - self.arm_timestamp)) if self.armed else WDT_COMMON_ERROR
|
||||
|
@ -3,6 +3,7 @@ dx010/cfg/dx010-modules.conf etc/modules-load.d
|
||||
dx010/systemd/platform-modules-dx010.service lib/systemd/system
|
||||
dx010/scripts/fancontrol.sh etc/init.d
|
||||
dx010/scripts/fancontrol.service lib/systemd/system
|
||||
dx010/scripts/thermal_overload_control.sh 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
|
||||
services/platform_api/platform_api_mgnt.sh usr/local/bin
|
||||
|
@ -76,42 +76,52 @@
|
||||
#define PORT_SFPP1 33
|
||||
#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 OPCODE_ID_BANK2 0x291
|
||||
#define OPCODE_ID_BANK3 0x391
|
||||
#define CPLD_I2C_CLK_100Khz_BIT BIT(6)
|
||||
#define CPLD_I2C_DATA_SZ_MASK GENMASK(7,4)
|
||||
#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 CMDBYT_ID_BANK2 0x293
|
||||
#define CMDBYT_ID_BANK3 0x393
|
||||
#define CPLD_I2C_BANK1_BASE 0x210
|
||||
#define CPLD_I2C_BANK2_BASE 0x290
|
||||
#define CPLD_I2C_BANK3_BASE 0x390
|
||||
|
||||
#define WRITE_ID_BANK1 0x220
|
||||
#define WRITE_ID_BANK2 0x2A0
|
||||
#define WRITE_ID_BANK3 0x3A0
|
||||
#define I2C_PORT_ID 0x0
|
||||
#define I2C_OPCODE 0x1
|
||||
#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
|
||||
#define READ_ID_BANK3 0x3B0
|
||||
|
||||
#define SSRR_ID_BANK1 0x216
|
||||
#define SSRR_ID_BANK2 0x296
|
||||
#define SSRR_ID_BANK3 0x396
|
||||
|
||||
#define HST_CNTL2_QUICK 0x00
|
||||
#define HST_CNTL2_BYTE 0x01
|
||||
#define HST_CNTL2_BYTE_DATA 0x02
|
||||
#define HST_CNTL2_WORD_DATA 0x03
|
||||
#define HST_CNTL2_BLOCK 0x05
|
||||
/*
|
||||
* private data to send to I2C core
|
||||
*/
|
||||
struct current_xfer {
|
||||
u8 addr;
|
||||
u8 cmd[CPLD_I2C_CMD_SZ_MAX];
|
||||
u8 cmd_len;
|
||||
u8 data_len;
|
||||
union i2c_smbus_data *data;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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 {
|
||||
int base_addr;
|
||||
int portid;
|
||||
struct current_xfer curr_xfer;
|
||||
};
|
||||
|
||||
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) {
|
||||
|
||||
/**
|
||||
* Read eeprom of QSFP device.
|
||||
* @param a i2c adapter.
|
||||
* @param addr address to read.
|
||||
* @param new_data QSFP port number struct.
|
||||
* @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){
|
||||
u8 val;
|
||||
s32 error;
|
||||
unsigned long ioBase;
|
||||
short portid, opcode, devaddr, cmdbyte0, ssr, writedata, readdata;
|
||||
union i2c_smbus_data *data;
|
||||
|
||||
u32 reg;
|
||||
int ioBase=0;
|
||||
char byte;
|
||||
short temp;
|
||||
short portid, opcode, devaddr, cmdbyte0, ssrr, writedata, readdata;
|
||||
__u16 word_data;
|
||||
int error = -EIO;
|
||||
error = -EIO;
|
||||
|
||||
mutex_lock(&cpld_data->cpld_lock);
|
||||
|
||||
if (((new_data->portid >= PORT_BANK1_START)
|
||||
&& (new_data->portid <= PORT_BANK1_END))
|
||||
|| (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;
|
||||
}
|
||||
ioBase = priv->base_addr;
|
||||
data = priv->curr_xfer.data;
|
||||
|
||||
while ((inb(ioBase + ssrr) & 0x40));
|
||||
if ((inb(ioBase + ssrr) & 0x80) == 0x80) {
|
||||
error = -EIO;
|
||||
/* Read error reset the port */
|
||||
outb(0x00, ioBase + ssrr);
|
||||
udelay(3000);
|
||||
outb(0x01, ioBase + ssrr);
|
||||
goto exit;
|
||||
}
|
||||
portid = ioBase + I2C_PORT_ID;
|
||||
opcode = ioBase + I2C_OPCODE;
|
||||
devaddr = ioBase + I2C_DEV_ADDR;
|
||||
cmdbyte0 = ioBase + I2C_CMD_BYT0;
|
||||
ssr = ioBase + I2C_SSR;
|
||||
writedata = ioBase + I2C_WRITE_DATA;
|
||||
readdata = ioBase + I2C_READ_DATA;
|
||||
|
||||
byte = 0x40 +new_data->portid;
|
||||
reg = cmd;
|
||||
outb(byte, ioBase + portid);
|
||||
outb(reg,ioBase + cmdbyte0);
|
||||
byte = 33;
|
||||
outb(byte, ioBase + opcode);
|
||||
addr = addr << 1;
|
||||
addr |= 0x01;
|
||||
outb(addr, ioBase + devaddr);
|
||||
while ((inb(ioBase + ssrr) & 0x40))
|
||||
{
|
||||
/* Wait for the core to be free */
|
||||
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
|
||||
|
||||
if ((inb(ioBase + ssrr) & 0x80) == 0x80) {
|
||||
/* Read error reset the port */
|
||||
error = -EIO;
|
||||
outb(0x00, ioBase + ssrr);
|
||||
/*
|
||||
* If any error happen here, we do soft-reset
|
||||
* and check the BUSY/ERROR again.
|
||||
*/
|
||||
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);
|
||||
outb(0x01, ioBase + ssrr);
|
||||
goto exit;
|
||||
outb(CPLD_I2C_UNRESET, ssr);
|
||||
|
||||
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;
|
||||
word_data = inb(temp);
|
||||
word_data |= (inb(++temp) << 8);
|
||||
/* Configure PortID */
|
||||
val = priv->portid | CPLD_I2C_CLK_100Khz_BIT;
|
||||
outb(val, portid);
|
||||
pr_debug("CPLD_I2C Write PortID 0x%x\n", val);
|
||||
|
||||
mutex_unlock(&cpld_data->cpld_lock);
|
||||
data->word = word_data;
|
||||
return 0;
|
||||
/* Configure OP_Code */
|
||||
val = (priv->curr_xfer.data_len << 4) & CPLD_I2C_DATA_SZ_MASK;
|
||||
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);
|
||||
return error;
|
||||
|
||||
}
|
||||
|
||||
static int dx010_i2c_access(struct i2c_adapter *a, u16 addr,
|
||||
unsigned short flags, char rw, u8 cmd,
|
||||
int size, union i2c_smbus_data *data)
|
||||
{
|
||||
/*
|
||||
* dx010_smbus_xfer - execute LPC-SMBus transfer
|
||||
* 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;
|
||||
struct dx010_i2c_data *priv;
|
||||
|
||||
struct dx010_i2c_data *new_data;
|
||||
priv = i2c_get_adapdata(adap);
|
||||
|
||||
/* Write the command register */
|
||||
new_data = i2c_get_adapdata(a);
|
||||
pr_debug("smbus_xfer called RW:%x CMD:%x SIZE:0x%x",
|
||||
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 */
|
||||
switch (size) {
|
||||
case I2C_SMBUS_QUICK:
|
||||
size = HST_CNTL2_QUICK;
|
||||
break;
|
||||
case I2C_SMBUS_BYTE:
|
||||
size = HST_CNTL2_BYTE;
|
||||
break;
|
||||
priv->curr_xfer.cmd_len = 0;
|
||||
priv->curr_xfer.data_len = 1;
|
||||
break;
|
||||
case I2C_SMBUS_BYTE_DATA:
|
||||
size = HST_CNTL2_BYTE_DATA;
|
||||
break;
|
||||
priv->curr_xfer.cmd_len = 1;
|
||||
priv->curr_xfer.data_len = 1;
|
||||
priv->curr_xfer.cmd[0] = command;
|
||||
break;
|
||||
case I2C_SMBUS_WORD_DATA:
|
||||
size = HST_CNTL2_WORD_DATA;
|
||||
break;
|
||||
case I2C_SMBUS_BLOCK_DATA:
|
||||
size = HST_CNTL2_BLOCK;
|
||||
break;
|
||||
priv->curr_xfer.cmd_len = 1;
|
||||
priv->curr_xfer.data_len = 2;
|
||||
priv->curr_xfer.cmd[0] = command;
|
||||
break;
|
||||
default:
|
||||
dev_warn(&a->dev, "Unsupported transaction %d\n", size);
|
||||
dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
|
||||
error = -EOPNOTSUPP;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
switch (size) {
|
||||
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;
|
||||
}
|
||||
error = cpld_smbus_transfer(priv);
|
||||
|
||||
Done:
|
||||
return error;
|
||||
}
|
||||
|
||||
static u32 dx010_i2c_func(struct i2c_adapter *a)
|
||||
{
|
||||
return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
|
||||
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
|
||||
I2C_FUNC_SMBUS_BLOCK_DATA;
|
||||
// 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_READ_BYTE |
|
||||
I2C_FUNC_SMBUS_BYTE_DATA |
|
||||
I2C_FUNC_SMBUS_WORD_DATA;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm dx010_i2c_algorithm = {
|
||||
.smbus_xfer = dx010_i2c_access,
|
||||
.smbus_xfer = dx010_smbus_xfer,
|
||||
.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 base_addr;
|
||||
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);
|
||||
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->owner = THIS_MODULE;
|
||||
new_adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
|
||||
new_adapter->class = I2C_CLASS_DEPRECATED;
|
||||
new_adapter->algo = &dx010_i2c_algorithm;
|
||||
|
||||
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);
|
||||
if (!new_data)
|
||||
return NULL;
|
||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv) {
|
||||
goto free_adap;
|
||||
}
|
||||
|
||||
new_data->portid = portid;
|
||||
|
||||
i2c_set_adapdata(new_adapter,new_data);
|
||||
priv->portid = portid;
|
||||
priv->base_addr = base_addr;
|
||||
|
||||
i2c_set_adapdata(new_adapter, priv);
|
||||
error = i2c_add_adapter(new_adapter);
|
||||
if(error)
|
||||
return NULL;
|
||||
goto free_data;
|
||||
|
||||
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)
|
||||
{
|
||||
struct resource *res;
|
||||
int ret =0;
|
||||
int ret = 0;
|
||||
int portid_count;
|
||||
|
||||
cpld_data = devm_kzalloc(&pdev->dev, sizeof(struct dx010_cpld_data),
|
||||
|
@ -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 $?
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user