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