[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:
Wirut Getbamrung 2020-09-17 22:56:52 +07:00 committed by GitHub
parent ae9a86fac4
commit 47316de5c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 861 additions and 714 deletions

View File

@ -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

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
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

View File

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

View File

@ -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

View File

@ -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 = ""

View File

@ -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

View File

@ -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

View File

@ -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),

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 $?