[AS7712-32X] Add to support PDDF (#8040)
* [AS7712-32X] Add to support PDDF Signed-off-by: Jostar Yang <jostar_yang@accton.com.tw> * Fix LGTM alerts * Fix AS7712-32X xcvrd busy issue Co-authored-by: Jostar Yang <jostar_yang@accton.com.tw>
This commit is contained in:
parent
f9a29ef056
commit
519dcde939
device/accton/x86_64-accton_as7712_32x-r0
platform/broadcom/sonic-platform-modules-accton
as7712-32x
service
sonic_platform
__init__.pychassis.pycomponent.pyeeprom.pyevent.pyfan.pyplatform.pypsu.pysfp.pythermal.pywatchdog.py
sonic_platform_setup.pyutils
debian
@ -0,0 +1,54 @@
|
||||
{
|
||||
"PSU":
|
||||
{
|
||||
"psu_present":
|
||||
{
|
||||
"i2c":
|
||||
{
|
||||
"valmap": { "1":true, "0":false }
|
||||
}
|
||||
},
|
||||
|
||||
"psu_power_good":
|
||||
{
|
||||
"i2c":
|
||||
{
|
||||
"valmap": { "1": true, "0":false }
|
||||
}
|
||||
},
|
||||
|
||||
"psu_fan_dir":
|
||||
{
|
||||
"i2c":
|
||||
{
|
||||
"valmap": { "F2B":"EXHAUST", "B2F":"INTAKE" }
|
||||
}
|
||||
},
|
||||
|
||||
"PSU_FAN_MAX_SPEED":"18000"
|
||||
},
|
||||
|
||||
"FAN":
|
||||
{
|
||||
"direction":
|
||||
{
|
||||
"i2c":
|
||||
{
|
||||
"valmap": {"1":"EXHAUST", "0":"INTAKE"}
|
||||
}
|
||||
},
|
||||
|
||||
"present":
|
||||
{
|
||||
"i2c":
|
||||
{
|
||||
"valmap": {"1":true, "0":false}
|
||||
}
|
||||
},
|
||||
|
||||
"duty_cycle_to_pwm": "lambda dc: ((dc*100.0)/625 - 1)",
|
||||
|
||||
"pwm_to_duty_cycle": "lambda pwm: math.ceil(((pwm+1)*625.0)/100)"
|
||||
}
|
||||
|
||||
}
|
1792
device/accton/x86_64-accton_as7712_32x-r0/pddf/pddf-device.json
Normal file
1792
device/accton/x86_64-accton_as7712_32x-r0/pddf/pddf-device.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
{
|
||||
"skip_ledd": true,
|
||||
"skip_thermalctld": true
|
||||
"skip_thermalctld": true,
|
||||
"skip_pcied": true
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,16 @@
|
||||
[Unit]
|
||||
Description=Accton AS7712 Platform Monitoring service
|
||||
Before=pmon.service
|
||||
After=pddf-platform-init.service
|
||||
DefaultDependencies=no
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/local/bin/accton_as7712_pddf_monitor.py
|
||||
KillSignal=SIGKILL
|
||||
SuccessExitStatus=SIGKILL
|
||||
|
||||
# Resource Limitations
|
||||
LimitCORE=infinity
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
@ -0,0 +1 @@
|
||||
../../../../pddf/i2c/service/pddf-platform-init.service
|
@ -0,0 +1,3 @@
|
||||
# All the derived classes for PDDF
|
||||
__all__ = ["platform", "chassis", "sfp", "psu", "thermal"]
|
||||
from . import platform
|
@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#############################################################################
|
||||
# PDDF
|
||||
# Module contains an implementation of SONiC Chassis API
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
try:
|
||||
import sys
|
||||
from sonic_platform_pddf_base.pddf_chassis import PddfChassis
|
||||
from .event import SfpEvent
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
NUM_COMPONENT = 4
|
||||
|
||||
class Chassis(PddfChassis):
|
||||
"""
|
||||
PDDF Platform-specific Chassis class
|
||||
"""
|
||||
|
||||
def __init__(self, pddf_data=None, pddf_plugin_data=None):
|
||||
PddfChassis.__init__(self, pddf_data, pddf_plugin_data)
|
||||
self.__initialize_components()
|
||||
self._sfpevent = SfpEvent(self.get_all_sfps())
|
||||
|
||||
def __initialize_components(self):
|
||||
from sonic_platform.component import Component
|
||||
for index in range(NUM_COMPONENT):
|
||||
component = Component(index)
|
||||
self._component_list.append(component)
|
||||
|
||||
# Provide the functions/variables below for which implementation is to be overwritten
|
||||
def get_change_event(self, timeout=0):
|
||||
return self._sfpevent.get_sfp_event(timeout)
|
||||
|
||||
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 derived from SfpBase representing the specified sfp
|
||||
"""
|
||||
sfp = None
|
||||
|
||||
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
|
@ -0,0 +1,115 @@
|
||||
#############################################################################
|
||||
#
|
||||
# Component contains an implementation of SONiC Platform Base API and
|
||||
# provides the components firmware management function
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
try:
|
||||
import subprocess
|
||||
from sonic_platform_base.component_base import ComponentBase
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
CPLD_ADDR_MAPPING = {
|
||||
"CPLD1": ['4', '0x60'],
|
||||
"CPLD2": ['5', '0x62'],
|
||||
"CPLD3": ['6', '0x64']
|
||||
}
|
||||
SYSFS_PATH = "/sys/bus/i2c/devices/"
|
||||
BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version"
|
||||
COMPONENT_LIST= [
|
||||
("CPLD1", "CPLD 1"),
|
||||
("CPLD2", "CPLD 2"),
|
||||
("CPLD3", "CPLD 3"),
|
||||
("BIOS", "Basic Input/Output System")
|
||||
|
||||
]
|
||||
|
||||
class Component(ComponentBase):
|
||||
"""Platform-specific Component class"""
|
||||
|
||||
DEVICE_TYPE = "component"
|
||||
|
||||
def __init__(self, component_index=0):
|
||||
self.index = component_index
|
||||
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 Exception:
|
||||
return False
|
||||
return True
|
||||
|
||||
def __get_bios_version(self):
|
||||
# Retrieves the BIOS firmware version
|
||||
try:
|
||||
with open(BIOS_VERSION_PATH, 'r') as fd:
|
||||
bios_version = fd.read()
|
||||
return bios_version.strip()
|
||||
except Exception as e:
|
||||
return None
|
||||
|
||||
def __get_cpld_version(self):
|
||||
# Retrieves the CPLD firmware version
|
||||
cpld_version = dict()
|
||||
for cpld_name in CPLD_ADDR_MAPPING:
|
||||
cmd = "i2cget -f -y {0} {1} 0x1".format(CPLD_ADDR_MAPPING[cpld_name][0], CPLD_ADDR_MAPPING[cpld_name][1])
|
||||
status, value = subprocess.getstatusoutput(cmd)
|
||||
if not status:
|
||||
cpld_version_raw = value.rstrip()
|
||||
cpld_version[cpld_name] = "{}".format(int(cpld_version_raw,16))
|
||||
|
||||
return cpld_version
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the component
|
||||
Returns:
|
||||
A string containing the name of the component
|
||||
"""
|
||||
return COMPONENT_LIST[self.index][0]
|
||||
|
||||
def get_description(self):
|
||||
"""
|
||||
Retrieves the description of the component
|
||||
Returns:
|
||||
A string containing the description of the component
|
||||
"""
|
||||
return COMPONENT_LIST[self.index][1]
|
||||
|
||||
def get_firmware_version(self):
|
||||
"""
|
||||
Retrieves the firmware version of module
|
||||
Returns:
|
||||
string: The firmware versions of the module
|
||||
"""
|
||||
fw_version = None
|
||||
|
||||
if self.name == "BIOS":
|
||||
fw_version = self.__get_bios_version()
|
||||
elif "CPLD" in self.name:
|
||||
cpld_version = self.__get_cpld_version()
|
||||
fw_version = cpld_version.get(self.name)
|
||||
|
||||
return fw_version
|
||||
|
||||
def install_firmware(self, image_path):
|
||||
"""
|
||||
Install firmware to module
|
||||
Args:
|
||||
image_path: A string, path to firmware image
|
||||
Returns:
|
||||
A boolean, True if install successfully, False if not
|
||||
"""
|
||||
raise NotImplementedError
|
@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
try:
|
||||
from sonic_platform_pddf_base.pddf_eeprom import PddfEeprom
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
|
||||
class Eeprom(PddfEeprom):
|
||||
|
||||
def __init__(self, pddf_data=None, pddf_plugin_data=None):
|
||||
PddfEeprom.__init__(self, pddf_data, pddf_plugin_data)
|
||||
|
||||
# Provide the functions/variables below for which implementation is to be overwritten
|
@ -0,0 +1,60 @@
|
||||
try:
|
||||
import time
|
||||
from sonic_py_common.logger import Logger
|
||||
except ImportError as e:
|
||||
raise ImportError(repr(e) + " - required module not found")
|
||||
|
||||
POLL_INTERVAL_IN_SEC = 1
|
||||
|
||||
class SfpEvent:
|
||||
''' Listen to insert/remove sfp events '''
|
||||
|
||||
def __init__(self, sfp_list):
|
||||
self._sfp_list = sfp_list
|
||||
self._logger = Logger()
|
||||
self._sfp_change_event_data = {'present': 0}
|
||||
|
||||
def get_presence_bitmap(self):
|
||||
bitmap = 0
|
||||
for sfp in self._sfp_list:
|
||||
modpres = sfp.get_presence()
|
||||
i=sfp.get_position_in_parent() - 1
|
||||
if modpres:
|
||||
bitmap = bitmap | (1 << i)
|
||||
return bitmap
|
||||
|
||||
def get_sfp_event(self, timeout=2000):
|
||||
port_dict = {}
|
||||
change_dict = {}
|
||||
change_dict['sfp'] = port_dict
|
||||
|
||||
if timeout < 1000:
|
||||
cd_ms = 1000
|
||||
else:
|
||||
cd_ms = timeout
|
||||
|
||||
while cd_ms > 0:
|
||||
bitmap = self.get_presence_bitmap()
|
||||
changed_ports = self._sfp_change_event_data['present'] ^ bitmap
|
||||
if changed_ports != 0:
|
||||
break
|
||||
time.sleep(POLL_INTERVAL_IN_SEC)
|
||||
# timeout=0 means wait for event forever
|
||||
if timeout != 0:
|
||||
cd_ms = cd_ms - POLL_INTERVAL_IN_SEC * 1000
|
||||
|
||||
if changed_ports != 0:
|
||||
for sfp in self._sfp_list:
|
||||
i=sfp.get_position_in_parent() - 1
|
||||
if (changed_ports & (1 << i)):
|
||||
if (bitmap & (1 << i)) == 0:
|
||||
port_dict[i+1] = '0'
|
||||
else:
|
||||
port_dict[i+1] = '1'
|
||||
|
||||
|
||||
# Update the cache dict
|
||||
self._sfp_change_event_data['present'] = bitmap
|
||||
return True, change_dict
|
||||
else:
|
||||
return True, change_dict
|
@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
|
||||
try:
|
||||
from sonic_platform_pddf_base.pddf_fan import PddfFan
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
|
||||
class Fan(PddfFan):
|
||||
"""PDDF Platform-Specific Fan class"""
|
||||
|
||||
def __init__(self, tray_idx, fan_idx=0, pddf_data=None, pddf_plugin_data=None, is_psu_fan=False, psu_index=0):
|
||||
# idx is 0-based
|
||||
PddfFan.__init__(self, tray_idx, fan_idx, pddf_data, pddf_plugin_data, is_psu_fan, psu_index)
|
||||
|
||||
# Provide the functions/variables below for which implementation is to be overwritten e.g.
|
||||
#def get_name(self):
|
||||
## Since AS7712 has two fans in a tray, modifying this function to return proper name
|
||||
#if self.is_psu_fan:
|
||||
#return "PSU_FAN{}".format(self.fan_index)
|
||||
#else:
|
||||
#return "Fantray{}_{}".format(self.fantray_index, {1:'Front', 2:'Rear'}.get(self.fan_index,'none'))
|
||||
|
@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#############################################################################
|
||||
# PDDF
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the platform information
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
|
||||
try:
|
||||
from sonic_platform_pddf_base.pddf_platform import PddfPlatform
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
|
||||
class Platform(PddfPlatform):
|
||||
"""
|
||||
PDDF Platform-Specific Platform Class
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
PddfPlatform.__init__(self)
|
||||
|
||||
# Provide the functions/variables below for which implementation is to be overwritten
|
@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
|
||||
|
||||
try:
|
||||
from sonic_platform_pddf_base.pddf_psu import PddfPsu
|
||||
except ImportError as e:
|
||||
raise ImportError (str(e) + "- required module not found")
|
||||
|
||||
|
||||
class Psu(PddfPsu):
|
||||
"""PDDF Platform-Specific PSU class"""
|
||||
|
||||
PLATFORM_PSU_CAPACITY = 650
|
||||
|
||||
def __init__(self, index, pddf_data=None, pddf_plugin_data=None):
|
||||
PddfPsu.__init__(self, index, pddf_data, pddf_plugin_data)
|
||||
|
||||
# Provide the functions/variables below for which implementation is to be overwritten
|
||||
def get_capacity(self):
|
||||
"""
|
||||
Gets the capacity (maximum output power) of the PSU in watts
|
||||
|
||||
Returns:
|
||||
An integer, the capacity of PSU
|
||||
"""
|
||||
return (self.PLATFORM_PSU_CAPACITY)
|
||||
|
||||
def get_type(self):
|
||||
"""
|
||||
Gets the type of the PSU
|
||||
|
||||
Returns:
|
||||
A string, the type of PSU (AC/DC)
|
||||
"""
|
||||
ptype = "AC"
|
||||
# Currently the platform supports only AC type of PSUs
|
||||
try:
|
||||
import sonic_platform.platform
|
||||
ch=sonic_platform.platform.Platform().get_chassis()
|
||||
e=ch.sys_eeprom.read_eeprom()
|
||||
ret, prod_name = ch.sys_eeprom.get_tlv_field(e,0x21)
|
||||
if ret:
|
||||
prod_name = prod_name[2].decode('ascii')
|
||||
#print "Product name is {}".format(prod_name)
|
||||
if '48V' in prod_name:
|
||||
ptype = 'DC'
|
||||
except Exception as e:
|
||||
print("Error while trying to read syseeprom to get PSU type - {}".format(repr(e)))
|
||||
|
||||
return ptype
|
@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
try:
|
||||
from sonic_platform_pddf_base.pddf_sfp import PddfSfp
|
||||
except ImportError as e:
|
||||
raise ImportError (str(e) + "- required module not found")
|
||||
|
||||
|
||||
class Sfp(PddfSfp):
|
||||
"""
|
||||
PDDF Platform-Specific Sfp class
|
||||
"""
|
||||
|
||||
def __init__(self, index, pddf_data=None, pddf_plugin_data=None):
|
||||
PddfSfp.__init__(self, index, pddf_data, pddf_plugin_data)
|
||||
|
||||
# Provide the functions/variables below for which implementation is to be overwritten
|
||||
def get_position_in_parent(self):
|
||||
"""Retrieves 1-based relative physical position in parent device."""
|
||||
return self.port_index
|
@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
|
||||
try:
|
||||
from sonic_platform_pddf_base.pddf_thermal import PddfThermal
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
|
||||
|
||||
class Thermal(PddfThermal):
|
||||
"""PDDF Platform-Specific Thermal class"""
|
||||
|
||||
def __init__(self, index, pddf_data=None, pddf_plugin_data=None):
|
||||
PddfThermal.__init__(self, index, pddf_data, pddf_plugin_data)
|
||||
|
||||
# Provide the functions/variables below for which implementation is to be overwritten
|
@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#############################################################################
|
||||
#
|
||||
# Module contains an implementation of platform specific watchdog API's
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
try:
|
||||
from sonic_platform_pddf_base.pddf_watchdog import PddfWatchdog
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
|
||||
class Watchdog(PddfWatchdog):
|
||||
"""
|
||||
PDDF Platform-specific Chassis class
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
PddfWatchdog.__init__(self)
|
||||
self.timeout = 180
|
||||
|
||||
# Provide the functions/variables below for which implementation is to be overwritten
|
@ -0,0 +1,25 @@
|
||||
from setuptools import setup
|
||||
|
||||
setup(
|
||||
name='sonic-platform',
|
||||
version='1.0',
|
||||
description='SONiC platform API implementation on Accton Platforms using PDDF',
|
||||
license='Apache 2.0',
|
||||
author='SONiC Team',
|
||||
author_email='linuxnetdev@microsoft.com',
|
||||
url='https://github.com/Azure/sonic-buildimage',
|
||||
packages=['sonic_platform'],
|
||||
classifiers=[
|
||||
'Development Status :: 3 - Alpha',
|
||||
'Environment :: Plugins',
|
||||
'Intended Audience :: Developers',
|
||||
'Intended Audience :: Information Technology',
|
||||
'Intended Audience :: System Administrators',
|
||||
'License :: OSI Approved :: Apache Software License',
|
||||
'Natural Language :: English',
|
||||
'Operating System :: POSIX :: Linux',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Topic :: Utilities',
|
||||
],
|
||||
keywords='sonic SONiC platform PLATFORM',
|
||||
)
|
@ -0,0 +1,264 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (C) 2017 Accton Technology Corporation
|
||||
#
|
||||
# This program 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, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# HISTORY:
|
||||
# mm/dd/yyyy (A.D.)
|
||||
# 11/13/2017: Polly Hsu, Create
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
try:
|
||||
import sys
|
||||
import getopt
|
||||
import logging
|
||||
import logging.config
|
||||
import logging.handlers
|
||||
import signal
|
||||
import time # this is only being used as part of the example
|
||||
import subprocess
|
||||
from sonic_platform import platform
|
||||
except ImportError as e:
|
||||
raise ImportError('%s - required module not found' % str(e))
|
||||
|
||||
# Deafults
|
||||
VERSION = '1.0'
|
||||
FUNCTION_NAME = 'accton_as7712_monitor'
|
||||
DUTY_MAX = 100
|
||||
|
||||
fan_state = [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2] # init state=2, insert=1, remove=0
|
||||
# For AC power Front to Back :
|
||||
# If any fan fail, please fan speed register to 15
|
||||
# The max value of Fan speed register is 9
|
||||
# [LM75(48) + LM75(49) + LM75(4A)] > 174 => set Fan speed value from 4 to 5
|
||||
# [LM75(48) + LM75(49) + LM75(4A)] > 182 => set Fan speed value from 5 to 7
|
||||
# [LM75(48) + LM75(49) + LM75(4A)] > 190 => set Fan speed value from 7 to 9
|
||||
#
|
||||
# [LM75(48) + LM75(49) + LM75(4A)] < 170 => set Fan speed value from 5 to 4
|
||||
# [LM75(48) + LM75(49) + LM75(4A)] < 178 => set Fan speed value from 7 to 5
|
||||
# [LM75(48) + LM75(49) + LM75(4A)] < 186 => set Fan speed value from 9 to 7
|
||||
#
|
||||
#
|
||||
# For AC power Back to Front :
|
||||
# If any fan fail, please fan speed register to 15
|
||||
# The max value of Fan speed register is 10
|
||||
# [LM75(48) + LM75(49) + LM75(4A)] > 140 => set Fan speed value from 4 to 5
|
||||
# [LM75(48) + LM75(49) + LM75(4A)] > 150 => set Fan speed value from 5 to 7
|
||||
# [LM75(48) + LM75(49) + LM75(4A)] > 160 => set Fan speed value from 7 to 10
|
||||
#
|
||||
# [LM75(48) + LM75(49) + LM75(4A)] < 135 => set Fan speed value from 5 to 4
|
||||
# [LM75(48) + LM75(49) + LM75(4A)] < 145 => set Fan speed value from 7 to 5
|
||||
# [LM75(48) + LM75(49) + LM75(4A)] < 155 => set Fan speed value from 10 to 7
|
||||
#
|
||||
|
||||
# 2.If no matched fan speed is found from the policy,
|
||||
# use FAN_DUTY_CYCLE_MIN as default speed
|
||||
# Get current temperature
|
||||
# 4.Decision 3: Decide new fan speed depend on fan direction/current fan speed/temperature
|
||||
|
||||
|
||||
def as7712_set_fan_duty_cycle(dc):
|
||||
# PWM register is same for all the FANs
|
||||
if dc < 0 or dc > 100:
|
||||
print("Error: Wrong duty cycle value %d" % (dc))
|
||||
return -1
|
||||
|
||||
platform_chassis.get_fan(0).set_speed(dc)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
# Make a class we can use to capture stdout and sterr in the log
|
||||
platform_chassis = None
|
||||
|
||||
|
||||
class accton_as7712_monitor(object):
|
||||
# static temp var
|
||||
_ori_temp = 0
|
||||
_new_perc = 0
|
||||
_ori_perc = 0
|
||||
|
||||
llog = logging.getLogger("["+FUNCTION_NAME+"]")
|
||||
|
||||
def __init__(self, log_console, log_file):
|
||||
"""Needs a logger and a logger level."""
|
||||
|
||||
formatter = logging.Formatter('%(name)s %(message)s')
|
||||
sys_handler = logging.handlers.SysLogHandler(address='/dev/log')
|
||||
sys_handler.setFormatter(formatter)
|
||||
sys_handler.ident = 'common'
|
||||
sys_handler.setLevel(logging.WARNING) # only fatal for syslog
|
||||
self.llog.addHandler(sys_handler)
|
||||
self.llog.setLevel(logging.DEBUG)
|
||||
|
||||
if log_file:
|
||||
fh = logging.FileHandler(log_file)
|
||||
fh.setLevel(logging.INFO)
|
||||
formatter = logging.Formatter('%(asctime)-15s %(name)s %(message)s')
|
||||
fh.setFormatter(formatter)
|
||||
self.llog.addHandler(fh)
|
||||
|
||||
# set up logging to console
|
||||
if log_console:
|
||||
console = logging.StreamHandler()
|
||||
console.setLevel(logging.DEBUG) # For debugging
|
||||
formatter = logging.Formatter('%(asctime)-15s %(name)s %(message)s')
|
||||
console.setFormatter(formatter)
|
||||
self.llog.addHandler(console)
|
||||
|
||||
def manage_fans(self):
|
||||
fan_policy_f2b = {
|
||||
0: [32, 0, 174000],
|
||||
1: [38, 170000, 182000],
|
||||
2: [50, 178000, 190000],
|
||||
3: [63, 186000, 0],
|
||||
}
|
||||
fan_policy_b2f = {
|
||||
0: [32, 0, 140000],
|
||||
1: [38, 135000, 150000],
|
||||
2: [50, 145000, 160000],
|
||||
3: [69, 155000, 0],
|
||||
}
|
||||
|
||||
global fan_state
|
||||
global platform_chassis
|
||||
FAN_STATE_REMOVE = 0
|
||||
FAN_STATE_INSERT = 1
|
||||
|
||||
get_temp = 0
|
||||
for t in range(0, 3):
|
||||
get_temp = get_temp + platform_chassis.get_thermal(t).get_temperature()*1000
|
||||
|
||||
cur_duty_cycle = 0
|
||||
|
||||
for x in range(platform_chassis.get_num_fans()):
|
||||
fan_status = platform_chassis.get_fan(x).get_status()
|
||||
fan_present = platform_chassis.get_fan(x).get_presence()
|
||||
|
||||
if fan_present == 1:
|
||||
if fan_state[x] != 1:
|
||||
fan_state[x] = FAN_STATE_INSERT
|
||||
#self.llog.debug("FAN-%d present is detected", x)
|
||||
else:
|
||||
if fan_state[x] != 0:
|
||||
fan_state[x] = FAN_STATE_REMOVE
|
||||
self.llog.warning("Alarm for FAN-%d absent is detected", x)
|
||||
|
||||
if fan_status is None:
|
||||
self.llog.warning('SET new_perc to %d (FAN stauts is None. fan_num:%d)', DUTY_MAX, x)
|
||||
as7712_set_fan_duty_cycle(DUTY_MAX)
|
||||
|
||||
if fan_status is False:
|
||||
self.llog.warning('SET new_perc to %d (FAN fault. fan_num:%d)', DUTY_MAX, x)
|
||||
as7712_set_fan_duty_cycle(DUTY_MAX)
|
||||
|
||||
#self.llog.debug('INFO. fan_status is True (fan_num:%d)', x)
|
||||
|
||||
# Determine the current fan duty cycle from a working fan
|
||||
if not cur_duty_cycle:
|
||||
cur_duty_cycle = platform_chassis.get_fan(x).get_speed()
|
||||
|
||||
if fan_status is not None and fan_status is not False:
|
||||
# Assuming all the fans have the same direction
|
||||
fan_dir = platform_chassis.get_fan(0).get_direction()
|
||||
if fan_dir == 1:
|
||||
policy = fan_policy_f2b
|
||||
else:
|
||||
policy = fan_policy_b2f
|
||||
|
||||
new_duty_cycle = cur_duty_cycle
|
||||
|
||||
for x in range(0, 4):
|
||||
if x == 4:
|
||||
as7712_set_fan_duty_cycle(policy[0][0])
|
||||
break
|
||||
|
||||
if get_temp > policy[x][2] and x != 3:
|
||||
new_duty_cycle = policy[x+1][0]
|
||||
self.llog.debug('THERMAL temp UP, temp %d > %d , new_duty_cycle=%d',
|
||||
get_temp, policy[x][2], new_duty_cycle)
|
||||
elif get_temp < policy[x][1]:
|
||||
new_duty_cycle = policy[x-1][0]
|
||||
self.llog.debug('THERMAL temp down, temp %d < %d , new_duty_cycle=%d',
|
||||
get_temp, policy[x][1], new_duty_cycle)
|
||||
break
|
||||
|
||||
if new_duty_cycle == cur_duty_cycle:
|
||||
return True
|
||||
else:
|
||||
if (new_duty_cycle == policy[3][0]) and (cur_duty_cycle < policy[3][0]):
|
||||
self.llog.warning('Alarm for temperature high is detected')
|
||||
elif (new_duty_cycle < policy[3][0]) and (cur_duty_cycle == policy[3][0]):
|
||||
self.llog.warning('Alarm for temperature high is cleared')
|
||||
else:
|
||||
pass
|
||||
|
||||
self.llog.debug('set new_duty_cycle=%d (old dc: %d)', new_duty_cycle, cur_duty_cycle)
|
||||
as7712_set_fan_duty_cycle(new_duty_cycle)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def sig_handler(signum, frame):
|
||||
logging.critical('INFO:Cause signal %d, set fan speed max.', signum)
|
||||
as7712_set_fan_duty_cycle(DUTY_MAX)
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def main(argv):
|
||||
|
||||
log_console = 0
|
||||
log_file = ""
|
||||
|
||||
if len(sys.argv) != 1:
|
||||
try:
|
||||
opts, args = getopt.getopt(argv, 'hdl')
|
||||
except getopt.GetoptError:
|
||||
print('Usage: %s [-d] [-l]' % sys.argv[0])
|
||||
return 0
|
||||
for opt, arg in opts:
|
||||
if opt == '-h':
|
||||
print('Usage: %s [-d] [-l]' % sys.argv[0])
|
||||
return 0
|
||||
elif opt in ('-d'):
|
||||
log_console = 1
|
||||
elif opt in ('-l'):
|
||||
log_file = '%s.log' % sys.argv[0]
|
||||
|
||||
signal.signal(signal.SIGINT, sig_handler)
|
||||
signal.signal(signal.SIGTERM, sig_handler)
|
||||
|
||||
global platform_chassis
|
||||
platform_chassis = platform.Platform().get_chassis()
|
||||
|
||||
# Disable the fan watchdog
|
||||
status, output = subprocess.getstatusoutput('i2cset -f -y 2 0x66 0x33 0x0')
|
||||
if status:
|
||||
print("Error: Unable to disable fan speed watchdog")
|
||||
|
||||
# Set any smaple speed of 100%
|
||||
as7712_set_fan_duty_cycle(100)
|
||||
|
||||
# Start the monitoring
|
||||
monitor = accton_as7712_monitor(log_console, log_file)
|
||||
# Loop forever, doing something useful hopefully:
|
||||
while True:
|
||||
monitor.manage_fans()
|
||||
time.sleep(10)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[1:])
|
@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env python
|
||||
# Script to stop and start the respective platforms default services.
|
||||
# This will be used while switching the pddf->non-pddf mode and vice versa
|
||||
import commands
|
||||
|
||||
def check_pddf_support():
|
||||
return True
|
||||
|
||||
def stop_platform_svc():
|
||||
status, output = commands.getstatusoutput("systemctl stop as7712-platform-init.service")
|
||||
if status:
|
||||
print("Stop as7712-platform-init.service failed %d"%status)
|
||||
return False
|
||||
status, output = commands.getstatusoutput("systemctl disable as7712-platform-init.service")
|
||||
if status:
|
||||
print("Disable as7712-platform-init.service failed %d"%status)
|
||||
return False
|
||||
|
||||
status, output = commands.getstatusoutput("/usr/local/bin/accton_as7712_util.py clean")
|
||||
if status:
|
||||
print("accton_as7712_util.py clean command failed %d"%status)
|
||||
return False
|
||||
|
||||
# HACK , stop the pddf-platform-init service if it is active
|
||||
status, output = commands.getstatusoutput("systemctl stop pddf-platform-init.service")
|
||||
if status:
|
||||
print("Stop pddf-platform-init.service along with other platform serives failed %d"%status)
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def start_platform_svc():
|
||||
status, output = commands.getstatusoutput("/usr/local/bin/accton_as7712_util.py install")
|
||||
if status:
|
||||
print("accton_as7712_util.py install command failed %d"%status)
|
||||
return False
|
||||
|
||||
status, output = commands.getstatusoutput("systemctl enable as7712-platform-init.service")
|
||||
if status:
|
||||
print("Enable as7712-platform-init.service failed %d"%status)
|
||||
return False
|
||||
status, output = commands.getstatusoutput("systemctl start as7712-platform-init.service")
|
||||
if status:
|
||||
print("Start as7712-platform-init.service failed %d"%status)
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def start_platform_pddf():
|
||||
status, output = commands.getstatusoutput("systemctl start pddf-platform-init.service")
|
||||
if status:
|
||||
print("Start pddf-platform-init.service failed %d"%status)
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def stop_platform_pddf():
|
||||
status, output = commands.getstatusoutput("systemctl stop pddf-platform-init.service")
|
||||
if status:
|
||||
print("Stop pddf-platform-init.service failed %d"%status)
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def main():
|
||||
pass
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
@ -0,0 +1 @@
|
||||
as7712-32x/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_as7712_32x-r0/pddf
|
@ -0,0 +1,8 @@
|
||||
# Special arrangement to make PDDF mode default
|
||||
# Disable monitor, monitor-fan, monitor-psu (not enabling them would imply they will be disabled by default)
|
||||
# Enable pddf-platform-monitor
|
||||
depmod -a
|
||||
systemctl enable pddf-platform-init.service
|
||||
systemctl start pddf-platform-init.service
|
||||
systemctl enable as7712-pddf-platform-monitor.service
|
||||
systemctl start as7712-pddf-platform-monitor.service
|
Reference in New Issue
Block a user