Skip to content

Commit

Permalink
[platform-celestica] - Implement FAN APIs based on the new platform A…
Browse files Browse the repository at this point in the history
…PI (#2739)

* [platform/cel] Implement FAN APIs based on the new platform API

* [platform/cel] Move platform api to under device platform

* [platform/cel] Remove rule to build platform api python wheel
  • Loading branch information
Wirut Getbamrung authored and lguohan committed May 9, 2019
1 parent b7235fc commit 38ad2a8
Show file tree
Hide file tree
Showing 10 changed files with 790 additions and 23 deletions.
Empty file.
108 changes: 108 additions & 0 deletions device/celestica/x86_64-cel_e1031-r0/sonic_platform/chassis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#!/usr/bin/env python

#############################################################################
# Celestica
#
# Module contains an implementation of SONiC Platform Base API and
# provides the Chassis information which are available in the platform
#
#############################################################################

import sys
import re
import os
import subprocess
import json

try:
from sonic_platform_base.chassis_base import ChassisBase
from sonic_platform.fan import Fan
except ImportError as e:
raise ImportError(str(e) + "- required module not found")

MMC_CPLD_ADDR = '0x100'
BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version"
CONFIG_DB_PATH = "/etc/sonic/config_db.json"
SMC_CPLD_PATH = "/sys/devices/platform/e1031.smc/version"
MMC_CPLD_PATH = "/sys/devices/platform/e1031.smc/getreg"
NUM_FAN = 3


class Chassis(ChassisBase):
"""Platform-specific Chassis class"""

def __init__(self):
self.config_data = {}
for index in range(0, NUM_FAN):
fan = Fan(index)
self._fan_list.append(fan)
ChassisBase.__init__(self)

def __get_register_value(self, path, register):
cmd = "echo {1} > {0}; cat {0}".format(path, register)
p = subprocess.Popen(
cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
raw_data, err = p.communicate()
if err is not '':
return 'None'
else:
return raw_data.strip()

def __read_config_db(self):
try:
with open(CONFIG_DB_PATH, 'r') as fd:
data = json.load(fd)
return data
except IOError:
raise IOError("Unable to open config_db file !")

def get_base_mac(self):
"""
Retrieves the base MAC address for the chassis
Returns:
A string containing the MAC address in the format
'XX:XX:XX:XX:XX:XX'
"""
try:
self.config_data = self.__read_config_db()
base_mac = self.config_data["DEVICE_METADATA"]["localhost"]["mac"]
return str(base_mac)
except KeyError:
raise KeyError("Base MAC not found")

def get_component_versions(self):
"""
Retrieves platform-specific hardware/firmware versions for chassis
componenets such as BIOS, CPLD, FPGA, etc.
Returns:
A string containing platform-specific component versions
"""

component_versions = dict()

# Get BIOS version
try:
with open(BIOS_VERSION_PATH, 'r') as fd:
bios_version = fd.read()
except IOError:
raise IOError("Unable to open version file !")

# Get CPLD version
cpld_version = dict()

with open(SMC_CPLD_PATH, 'r') as fd:
smc_cpld_version = fd.read()
smc_cpld_version = 'None' if smc_cpld_version is 'None' else "{}.{}".format(
int(smc_cpld_version[2], 16), int(smc_cpld_version[3], 16))

mmc_cpld_version = self.__get_register_value(
MMC_CPLD_PATH, MMC_CPLD_ADDR)
mmc_cpld_version = 'None' if mmc_cpld_version is 'None' else "{}.{}".format(
int(mmc_cpld_version[2], 16), int(mmc_cpld_version[3], 16))

cpld_version["SMC"] = smc_cpld_version
cpld_version["MMC"] = mmc_cpld_version

component_versions["CPLD"] = cpld_version
component_versions["BIOS"] = bios_version.strip()
return str(component_versions)
183 changes: 183 additions & 0 deletions device/celestica/x86_64-cel_e1031-r0/sonic_platform/fan.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
#!/usr/bin/env python

#############################################################################
# Celestica
#
# Module contains an implementation of SONiC Platform Base API and
# provides the fan status which are available in the platform
#
#############################################################################

import json
import math
import os.path

try:
from sonic_platform_base.fan_base import FanBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")

EMC2305_FAN_PATH = "/sys/bus/i2c/drivers/emc2305/"
FAN_PATH = "/sys/devices/platform/e1031.smc/"
SYS_GPIO_DIR = "/sys/class/gpio"
EMC2305_MAX_PWM = 255
EMC2305_FAN_PWM = "pwm{}"
EMC2305_FAN_TARGET = "fan{}_target"
EMC2305_FAN_INPUT = "pwm{}"


class Fan(FanBase):
"""Platform-specific Fan class"""

def __init__(self, fan_index):
self.index = fan_index
self.config_data = {}
self.fan_speed = 0

# e1031 fan attributes
# Single emc2305 chip located at i2c-23-4d
# to control a fan module
self.e1031_emc2305_chip = [
{
'device': "23-004d",
'index_map': [1, 2, 4]
}
]

# TODO: Add fan presence status in sysfs
self.fan_e1031_presence = "fan{}_prs"
self.fan_e1031_direction = "fan{}_dir"
self.fan_e1031_led = "fan{}_led"
self.fan_e1031_led_col_map = {
self.STATUS_LED_COLOR_GREEN: "green",
self.STATUS_LED_COLOR_RED: "amber",
self.STATUS_LED_COLOR_OFF: "off"
}
FanBase.__init__(self)

def get_direction(self):

direction = self.FAN_DIRECTION_INTAKE

try:
fan_direction_file = (FAN_PATH +
self.fan_e1031_direction.format(self.index+1))
with open(fan_direction_file, 'r') as file:
raw = file.read().strip('\r\n')
if str(raw).upper() == "F2B":
direction = self.FAN_DIRECTION_INTAKE
else:
direction = self.FAN_DIRECTION_EXHAUST
except IOError:
return False

return direction

def get_speed(self):
"""
E1031 platform specific data:
speed = pwm_in/255*100
"""
# TODO: Seperate PSU's fan and main fan class
if self.fan_speed != 0:
return self.fan_speed
else:
speed = 0
pwm = []
emc2305_chips = self.e1031_emc2305_chip

for chip in emc2305_chips:
device = chip['device']
fan_index = chip['index_map']
sysfs_path = "%s%s/%s" % (
EMC2305_FAN_PATH, device, EMC2305_FAN_INPUT)
sysfs_path = sysfs_path.format(fan_index[self.index])
try:
with open(sysfs_path, 'r') as file:
raw = file.read().strip('\r\n')
pwm.append(int(raw, 10))
except IOError:
raise IOError("Unable to open " + sysfs_path)

speed = math.ceil(
float(pwm[0]) * 100 / EMC2305_MAX_PWM)

return int(speed)

def get_target_speed(self):
"""
E1031 platform specific data:
speed_pc = pwm_target/255*100
0 : when PWM mode is use
pwm : when pwm mode is not use
"""
target = 0
pwm = []
emc2305_chips = self.e1031_emc2305_chip

for chip in emc2305_chips:
device = chip['device']
fan_index = chip['index_map']
sysfs_path = "%s%s/%s" % (
EMC2305_FAN_PATH, device, EMC2305_FAN_TARGET)
sysfs_path = sysfs_path.format(fan_index[self.index])
try:
with open(sysfs_path, 'r') as file:
raw = file.read().strip('\r\n')
pwm.append(int(raw, 10))
except IOError:
raise IOError("Unable to open " + sysfs_path)

target = pwm[0] * 100 / EMC2305_MAX_PWM

return target

def get_speed_tolerance(self):
"""
Retrieves the speed tolerance of the fan
Returns:
An integer, the percentage of variance from target speed which is
considered tolerable
"""
return 10

def set_speed(self, speed):
"""
Depends on pwm or target mode is selected:
1) pwm = speed_pc * 255 <-- Currently use this mode.
2) target_pwm = speed_pc * 100 / 255
2.1) set pwm{}_enable to 3
"""
pwm = speed * 255 / 100
emc2305_chips = self.e1031_emc2305_chip

for chip in emc2305_chips:
device = chip['device']
fan_index = chip['index_map']
sysfs_path = "%s%s/%s" % (
EMC2305_FAN_PATH, device, EMC2305_FAN_PWM)
sysfs_path = sysfs_path.format(fan_index[self.index])
try:
with open(sysfs_path, 'w') as file:
file.write(str(int(pwm)))
except IOError:
return False

return True

def set_status_led(self, color):

try:
fan_led_file = (FAN_PATH +
self.fan_e1031_led.format(self.index+1))
with open(fan_led_file, 'r') as file:
file.write(self.fan_e1031_led_col_map[color])
except IOError:
return False

return True
23 changes: 23 additions & 0 deletions device/celestica/x86_64-cel_e1031-r0/sonic_platform/platform.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/env python

#############################################################################
# Celestica
#
# Module contains an implementation of SONiC Platform Base API and
# provides the platform information
#
#############################################################################

try:
from sonic_platform_base.platform_base import PlatformBase
from sonic_platform.chassis import Chassis
except ImportError as e:
raise ImportError(str(e) + "- required module not found")


class Platform(PlatformBase):
"""Platform-specific Platform class"""

def __init__(self):
PlatformBase.__init__(self)
self._chassis = Chassis()
Empty file.
Loading

0 comments on commit 38ad2a8

Please sign in to comment.