From a3dd3f55f9163e80d5f10a4dd0d33fe66464e581 Mon Sep 17 00:00:00 2001 From: fk410167 <51665572+fk410167@users.noreply.github.com> Date: Thu, 12 Nov 2020 23:52:38 +0530 Subject: [PATCH] Platform Driver Developement Framework (PDDF) (#4756) This change introduces PDDF which is described here: https://github.com/Azure/SONiC/pull/536 Most of the platform bring up effort goes in developing the platform device drivers, SONiC platform APIs and validating them. Typically each platform vendor writes their own drivers and platform APIs which is very tailor made to that platform. This involves writing code, building, installing it on the target platform devices and testing. Many of the details of the platform are hard coded into these drivers, from the HW spec. They go through this cycle repetitively till everything works fine, and is validated before upstreaming the code. PDDF aims to make this platform driver and platform APIs development process much simpler by providing a data driven development framework. This is enabled by: JSON descriptor files for platform data Generic data-driven drivers for various devices Generic SONiC platform APIs Vendor specific extensions for customisation and extensibility Signed-off-by: Fuzail Khan --- build_debian.sh | 1 + device/common/pddf/plugins/eeprom.py | 27 + device/common/pddf/plugins/fanutil.py | 202 ++ device/common/pddf/plugins/ledutil.py | 58 + device/common/pddf/plugins/psuutil.py | 272 +++ device/common/pddf/plugins/sfputil.py | 237 ++ device/common/pddf/plugins/sysstatutil.py | 85 + device/common/pddf/plugins/thermalutil.py | 74 + dockers/docker-platform-monitor/Dockerfile.j2 | 3 +- .../build_templates/sonic_debian_extension.j2 | 8 + platform/broadcom/one-image.mk | 1 + platform/pddf/README.md | 19 + platform/pddf/i2c/Makefile | 1 + platform/pddf/i2c/debian/changelog | 12 + platform/pddf/i2c/debian/compat | 1 + platform/pddf/i2c/debian/control | 12 + platform/pddf/i2c/debian/rules | 75 + platform/pddf/i2c/modules/Makefile | 1 + platform/pddf/i2c/modules/client/Makefile | 3 + .../i2c/modules/client/pddf_client_module.c | 330 +++ platform/pddf/i2c/modules/cpld/Makefile | 4 + .../pddf/i2c/modules/cpld/driver/Makefile | 5 + .../modules/cpld/driver/pddf_cpld_driver.c | 230 ++ .../pddf/i2c/modules/cpld/pddf_cpld_module.c | 219 ++ platform/pddf/i2c/modules/cpldmux/Makefile | 4 + .../pddf/i2c/modules/cpldmux/driver/Makefile | 4 + .../cpldmux/driver/pddf_cpldmux_driver.c | 209 ++ .../i2c/modules/cpldmux/pddf_cpldmux_module.c | 254 +++ platform/pddf/i2c/modules/fan/Makefile | 4 + platform/pddf/i2c/modules/fan/driver/Makefile | 6 + .../i2c/modules/fan/driver/pddf_fan_api.c | 526 +++++ .../i2c/modules/fan/driver/pddf_fan_driver.c | 496 +++++ .../pddf/i2c/modules/fan/pddf_fan_module.c | 280 +++ platform/pddf/i2c/modules/gpio/Makefile | 4 + .../pddf/i2c/modules/gpio/pddf_gpio_module.c | 223 ++ .../i2c/modules/include/pddf_client_defs.h | 135 ++ .../pddf/i2c/modules/include/pddf_cpld_defs.h | 31 + .../i2c/modules/include/pddf_cpldmux_defs.h | 76 + .../pddf/i2c/modules/include/pddf_fan_api.h | 37 + .../pddf/i2c/modules/include/pddf_fan_defs.h | 91 + .../i2c/modules/include/pddf_fan_driver.h | 107 + .../pddf/i2c/modules/include/pddf_gpio_defs.h | 30 + .../pddf/i2c/modules/include/pddf_led_defs.h | 120 + .../pddf/i2c/modules/include/pddf_mux_defs.h | 31 + .../pddf/i2c/modules/include/pddf_psu_api.h | 41 + .../pddf/i2c/modules/include/pddf_psu_defs.h | 90 + .../i2c/modules/include/pddf_psu_driver.h | 65 + .../i2c/modules/include/pddf_sysstatus_defs.h | 51 + .../pddf/i2c/modules/include/pddf_xcvr_api.h | 44 + .../pddf/i2c/modules/include/pddf_xcvr_defs.h | 121 + platform/pddf/i2c/modules/led/Makefile | 4 + .../pddf/i2c/modules/led/pddf_led_module.c | 659 ++++++ platform/pddf/i2c/modules/mux/Makefile | 4 + .../pddf/i2c/modules/mux/pddf_mux_module.c | 211 ++ platform/pddf/i2c/modules/psu/Makefile | 4 + platform/pddf/i2c/modules/psu/driver/Makefile | 6 + .../i2c/modules/psu/driver/pddf_psu_api.c | 707 ++++++ .../i2c/modules/psu/driver/pddf_psu_driver.c | 381 ++++ .../pddf/i2c/modules/psu/pddf_psu_module.c | 283 +++ platform/pddf/i2c/modules/sysstatus/Makefile | 4 + .../modules/sysstatus/pddf_sysstatus_module.c | 235 ++ platform/pddf/i2c/modules/xcvr/Makefile | 4 + .../pddf/i2c/modules/xcvr/driver/Makefile | 7 + .../i2c/modules/xcvr/driver/pddf_xcvr_api.c | 909 ++++++++ .../modules/xcvr/driver/pddf_xcvr_driver.c | 296 +++ .../pddf/i2c/modules/xcvr/pddf_xcvr_module.c | 275 +++ .../i2c/service/pddf-platform-init.service | 13 + platform/pddf/i2c/setup.py | 14 + platform/pddf/i2c/utils/pddf_util.py | 605 +++++ platform/pddf/i2c/utils/pddfparse.py | 1949 +++++++++++++++++ platform/pddf/i2c/utils/schema/CPLD.schema | 67 + platform/pddf/i2c/utils/schema/CPU.schema | 80 + platform/pddf/i2c/utils/schema/EEPROM.schema | 93 + platform/pddf/i2c/utils/schema/FAN.schema | 113 + platform/pddf/i2c/utils/schema/FAN_BMC.schema | 69 + platform/pddf/i2c/utils/schema/LED.schema | 120 + platform/pddf/i2c/utils/schema/MUX.schema | 97 + .../pddf/i2c/utils/schema/PSU-PMBUS.schema | 109 + platform/pddf/i2c/utils/schema/PSU.schema | 81 + platform/pddf/i2c/utils/schema/PSU_BMC.schema | 336 +++ platform/pddf/i2c/utils/schema/QSFP.schema | 92 + platform/pddf/i2c/utils/schema/SMBUS.schema | 128 ++ platform/pddf/i2c/utils/schema/SYSSTAT.schema | 285 +++ .../pddf/i2c/utils/schema/TEMP_SENSOR.schema | 102 + .../i2c/utils/schema/TEMP_SENSOR_BMC.schema | 143 ++ platform/pddf/platform-api-pddf-base.dep | 9 + platform/pddf/platform-api-pddf-base.mk | 15 + platform/pddf/platform-api-pddf-base/setup.py | 30 + .../sonic_platform_pddf_base/__init__.py | 0 .../sonic_platform_pddf_base/pddf_chassis.py | 516 +++++ .../sonic_platform_pddf_base/pddf_eeprom.py | 124 ++ .../sonic_platform_pddf_base/pddf_fan.py | 332 +++ .../sonic_platform_pddf_base/pddf_platform.py | 37 + .../sonic_platform_pddf_base/pddf_psu.py | 298 +++ .../sonic_platform_pddf_base/pddf_sfp.py | 1390 ++++++++++++ .../sonic_platform_pddf_base/pddf_thermal.py | 174 ++ .../sonic_platform_pddf_base/pddfparse.py | 1508 +++++++++++++ .../sonic_platform_ref/__init__.py | 7 + .../sonic_platform_ref/chassis.py | 22 + .../sonic_platform_ref/eeprom.py | 14 + .../sonic_platform_ref/fan.py | 17 + .../sonic_platform_ref/platform.py | 25 + .../sonic_platform_ref/psu.py | 16 + .../sonic_platform_ref/sfp.py | 17 + .../sonic_platform_ref/thermal.py | 17 + platform/pddf/platform-modules-pddf.dep | 10 + platform/pddf/platform-modules-pddf.mk | 12 + platform/pddf/rules.dep | 3 + platform/pddf/rules.mk | 3 + rules/config | 4 + rules/docker-platform-monitor.mk | 4 + slave.mk | 16 + 112 files changed, 18064 insertions(+), 1 deletion(-) create mode 100755 device/common/pddf/plugins/eeprom.py create mode 100755 device/common/pddf/plugins/fanutil.py create mode 100755 device/common/pddf/plugins/ledutil.py create mode 100755 device/common/pddf/plugins/psuutil.py create mode 100755 device/common/pddf/plugins/sfputil.py create mode 100755 device/common/pddf/plugins/sysstatutil.py create mode 100755 device/common/pddf/plugins/thermalutil.py create mode 100644 platform/pddf/README.md create mode 100644 platform/pddf/i2c/Makefile create mode 100755 platform/pddf/i2c/debian/changelog create mode 100644 platform/pddf/i2c/debian/compat create mode 100755 platform/pddf/i2c/debian/control create mode 100755 platform/pddf/i2c/debian/rules create mode 100644 platform/pddf/i2c/modules/Makefile create mode 100644 platform/pddf/i2c/modules/client/Makefile create mode 100644 platform/pddf/i2c/modules/client/pddf_client_module.c create mode 100644 platform/pddf/i2c/modules/cpld/Makefile create mode 100644 platform/pddf/i2c/modules/cpld/driver/Makefile create mode 100755 platform/pddf/i2c/modules/cpld/driver/pddf_cpld_driver.c create mode 100644 platform/pddf/i2c/modules/cpld/pddf_cpld_module.c create mode 100644 platform/pddf/i2c/modules/cpldmux/Makefile create mode 100644 platform/pddf/i2c/modules/cpldmux/driver/Makefile create mode 100755 platform/pddf/i2c/modules/cpldmux/driver/pddf_cpldmux_driver.c create mode 100644 platform/pddf/i2c/modules/cpldmux/pddf_cpldmux_module.c create mode 100644 platform/pddf/i2c/modules/fan/Makefile create mode 100644 platform/pddf/i2c/modules/fan/driver/Makefile create mode 100644 platform/pddf/i2c/modules/fan/driver/pddf_fan_api.c create mode 100644 platform/pddf/i2c/modules/fan/driver/pddf_fan_driver.c create mode 100644 platform/pddf/i2c/modules/fan/pddf_fan_module.c create mode 100644 platform/pddf/i2c/modules/gpio/Makefile create mode 100644 platform/pddf/i2c/modules/gpio/pddf_gpio_module.c create mode 100644 platform/pddf/i2c/modules/include/pddf_client_defs.h create mode 100644 platform/pddf/i2c/modules/include/pddf_cpld_defs.h create mode 100644 platform/pddf/i2c/modules/include/pddf_cpldmux_defs.h create mode 100644 platform/pddf/i2c/modules/include/pddf_fan_api.h create mode 100644 platform/pddf/i2c/modules/include/pddf_fan_defs.h create mode 100644 platform/pddf/i2c/modules/include/pddf_fan_driver.h create mode 100644 platform/pddf/i2c/modules/include/pddf_gpio_defs.h create mode 100644 platform/pddf/i2c/modules/include/pddf_led_defs.h create mode 100644 platform/pddf/i2c/modules/include/pddf_mux_defs.h create mode 100644 platform/pddf/i2c/modules/include/pddf_psu_api.h create mode 100644 platform/pddf/i2c/modules/include/pddf_psu_defs.h create mode 100644 platform/pddf/i2c/modules/include/pddf_psu_driver.h create mode 100644 platform/pddf/i2c/modules/include/pddf_sysstatus_defs.h create mode 100644 platform/pddf/i2c/modules/include/pddf_xcvr_api.h create mode 100644 platform/pddf/i2c/modules/include/pddf_xcvr_defs.h create mode 100644 platform/pddf/i2c/modules/led/Makefile create mode 100644 platform/pddf/i2c/modules/led/pddf_led_module.c create mode 100644 platform/pddf/i2c/modules/mux/Makefile create mode 100644 platform/pddf/i2c/modules/mux/pddf_mux_module.c create mode 100644 platform/pddf/i2c/modules/psu/Makefile create mode 100644 platform/pddf/i2c/modules/psu/driver/Makefile create mode 100644 platform/pddf/i2c/modules/psu/driver/pddf_psu_api.c create mode 100644 platform/pddf/i2c/modules/psu/driver/pddf_psu_driver.c create mode 100644 platform/pddf/i2c/modules/psu/pddf_psu_module.c create mode 100644 platform/pddf/i2c/modules/sysstatus/Makefile create mode 100644 platform/pddf/i2c/modules/sysstatus/pddf_sysstatus_module.c create mode 100644 platform/pddf/i2c/modules/xcvr/Makefile create mode 100644 platform/pddf/i2c/modules/xcvr/driver/Makefile create mode 100644 platform/pddf/i2c/modules/xcvr/driver/pddf_xcvr_api.c create mode 100644 platform/pddf/i2c/modules/xcvr/driver/pddf_xcvr_driver.c create mode 100644 platform/pddf/i2c/modules/xcvr/pddf_xcvr_module.c create mode 100644 platform/pddf/i2c/service/pddf-platform-init.service create mode 100755 platform/pddf/i2c/setup.py create mode 100755 platform/pddf/i2c/utils/pddf_util.py create mode 100755 platform/pddf/i2c/utils/pddfparse.py create mode 100644 platform/pddf/i2c/utils/schema/CPLD.schema create mode 100644 platform/pddf/i2c/utils/schema/CPU.schema create mode 100644 platform/pddf/i2c/utils/schema/EEPROM.schema create mode 100644 platform/pddf/i2c/utils/schema/FAN.schema create mode 100644 platform/pddf/i2c/utils/schema/FAN_BMC.schema create mode 100644 platform/pddf/i2c/utils/schema/LED.schema create mode 100644 platform/pddf/i2c/utils/schema/MUX.schema create mode 100644 platform/pddf/i2c/utils/schema/PSU-PMBUS.schema create mode 100644 platform/pddf/i2c/utils/schema/PSU.schema create mode 100644 platform/pddf/i2c/utils/schema/PSU_BMC.schema create mode 100644 platform/pddf/i2c/utils/schema/QSFP.schema create mode 100644 platform/pddf/i2c/utils/schema/SMBUS.schema create mode 100644 platform/pddf/i2c/utils/schema/SYSSTAT.schema create mode 100644 platform/pddf/i2c/utils/schema/TEMP_SENSOR.schema create mode 100644 platform/pddf/i2c/utils/schema/TEMP_SENSOR_BMC.schema create mode 100644 platform/pddf/platform-api-pddf-base.dep create mode 100644 platform/pddf/platform-api-pddf-base.mk create mode 100755 platform/pddf/platform-api-pddf-base/setup.py create mode 100644 platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/__init__.py create mode 100755 platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_chassis.py create mode 100644 platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_eeprom.py create mode 100755 platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_fan.py create mode 100755 platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_platform.py create mode 100755 platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_psu.py create mode 100755 platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_sfp.py create mode 100755 platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_thermal.py create mode 100755 platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddfparse.py create mode 100644 platform/pddf/platform-api-pddf-base/sonic_platform_ref/__init__.py create mode 100644 platform/pddf/platform-api-pddf-base/sonic_platform_ref/chassis.py create mode 100644 platform/pddf/platform-api-pddf-base/sonic_platform_ref/eeprom.py create mode 100644 platform/pddf/platform-api-pddf-base/sonic_platform_ref/fan.py create mode 100644 platform/pddf/platform-api-pddf-base/sonic_platform_ref/platform.py create mode 100644 platform/pddf/platform-api-pddf-base/sonic_platform_ref/psu.py create mode 100644 platform/pddf/platform-api-pddf-base/sonic_platform_ref/sfp.py create mode 100644 platform/pddf/platform-api-pddf-base/sonic_platform_ref/thermal.py create mode 100644 platform/pddf/platform-modules-pddf.dep create mode 100644 platform/pddf/platform-modules-pddf.mk create mode 100644 platform/pddf/rules.dep create mode 100644 platform/pddf/rules.mk diff --git a/build_debian.sh b/build_debian.sh index 5c705bfe7e..08a4030cb4 100755 --- a/build_debian.sh +++ b/build_debian.sh @@ -277,6 +277,7 @@ sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y in python \ python-setuptools \ python3-setuptools \ + python-jsonschema \ python-apt \ traceroute \ iputils-ping \ diff --git a/device/common/pddf/plugins/eeprom.py b/device/common/pddf/plugins/eeprom.py new file mode 100755 index 0000000000..7671c50bd3 --- /dev/null +++ b/device/common/pddf/plugins/eeprom.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python + +try: + import os + import sys + import json + sys.path.append('/usr/share/sonic/platform/plugins') + import pddfparse + #from sonic_eeprom import eeprom_base + from sonic_eeprom import eeprom_tlvinfo +except ImportError, e: + raise ImportError (str(e) + "- required module not found") + + +class board(eeprom_tlvinfo.TlvInfoDecoder): + _TLV_INFO_MAX_LEN = 256 + def __init__(self, name, path, cpld_root, ro): + global pddf_obj + global plugin_data + with open(os.path.join(os.path.dirname(os.path.realpath(__file__)) + '/../pddf/pd-plugin.json')) as pd: + plugin_data = json.load(pd) + + pddf_obj = pddfparse.PddfParse() + # system EEPROM always has device name EEPROM1 + self.eeprom_path = pddf_obj.get_path("EEPROM1", "eeprom") + super(board, self).__init__(self.eeprom_path, 0, '', True) + diff --git a/device/common/pddf/plugins/fanutil.py b/device/common/pddf/plugins/fanutil.py new file mode 100755 index 0000000000..2701fa5f23 --- /dev/null +++ b/device/common/pddf/plugins/fanutil.py @@ -0,0 +1,202 @@ +#!/usr/bin/env python + + +# Sample pddf_fanutil file +# All the supported FAN SysFS aattributes are +#- fan_present +#- fan_direction +#- fan_input +#- fan_pwm +#- fan_fault +# where idx is in the range [1-12] +# + + +import os.path +import sys +sys.path.append('/usr/share/sonic/platform/plugins') +import pddfparse +import json + +try: + from sonic_fan.fan_base import FanBase +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + +class FanUtil(FanBase): + """PDDF generic FAN util class""" + + def __init__(self): + FanBase.__init__(self) + global pddf_obj + global plugin_data + with open(os.path.join(os.path.dirname(os.path.realpath(__file__)) + '/../pddf/pd-plugin.json')) as pd: + plugin_data = json.load(pd) + + pddf_obj = pddfparse.PddfParse() + self.platform = pddf_obj.get_platform() + + self.num_fans = (self.platform['num_fantrays'] * self.platform['num_fans_pertray'] ) + + def get_num_fans(self): + return self.num_fans + + def get_presence(self, idx): + # 1 based fan index + if idx<1 or idx>self.num_fans: + print "Invalid fan index %d\n"%idx + return False + + attr_name = "fan"+ str(idx) +"_present" + output = pddf_obj.get_attr_name_output("FAN-CTRL", attr_name) + if not output: + return False + + mode = output['mode'] + presence = output['status'].rstrip() + + vmap = plugin_data['FAN']['present'][mode]['valmap'] + + if presence in vmap: + status = vmap[presence] + else: + status = False + + return status + + def get_status(self, idx): + # 1 based fan index + if idx<1 or idx>self.num_fans: + print "Invalid fan index %d\n"%idx + return False + + speed = self.get_speed(idx) + status = True if (speed != 0) else False + return status + + def get_direction(self, idx): + # 1 based fan index + if idx<1 or idx>self.num_fans: + print "Invalid fan index %d\n"%idx + return None + + attr = "fan" + str(idx) + "_direction" + output = pddf_obj.get_attr_name_output("FAN-CTRL", attr) + if not output: + return None + + mode = output['mode'] + val = output['status'] + + val = val.rstrip() + vmap = plugin_data['FAN']['direction'][mode]['valmap'] + + + if val in vmap: + direction = vmap[val] + else: + direction = val + + return direction + + def get_directions(self): + num_fan = self.get_num_fan(); + + for i in range(1, num_fan+1): + attr = "fan" + str(i) + "_direction" + output = pddf_obj.get_attr_name_output("FAN-CTRL", attr) + if not output: + return None + + mode = output['mode'] + val = output['status'] + + val = val.rstrip() + vmap = plugin_data['FAN']['direction'][mode]['valmap'] + + direction = vmap[str(val)] + + print "FAN-%d direction is %s"%(i, direction) + + return 0 + + def get_speed(self, idx): + # 1 based fan index + if idx<1 or idx>self.num_fans: + print "Invalid fan index %d\n"%idx + return 0 + + attr = "fan" + str(idx) + "_input" + output = pddf_obj.get_attr_name_output("FAN-CTRL", attr) + if not output: + return 0 + + #mode = output['mode'] + val = output['status'].rstrip() + + if val.isalpha(): + return 0 + else: + rpm_speed = int(float(val)) + + return rpm_speed + + def get_speeds(self): + num_fan = self.get_num_fan(); + ret = "FAN_INDEX\t\tRPM\n" + + for i in range(1, num_fan+1): + attr1 = "fan" + str(i) + "_input" + output = pddf_obj.get_attr_name_output("FAN-CTRL", attr1) + if not output: + return "" + + #mode = output['mode'] + val = output['status'].rstrip() + + if val.isalpha(): + frpm = 0 + else: + frpm = int(val) + + ret += "FAN-%d\t\t\t%d\n"%(i, frpm) + + return ret + + def set_speed(self, val): + if val<0 or val>100: + print "Error: Invalid speed %d. Please provide a valid speed percentage"%val + return False + + num_fan = self.num_fans + if 'duty_cycle_to_pwm' not in plugin_data['FAN']: + print "Setting fan speed is not allowed !" + return False + else: + duty_cycle_to_pwm = eval(plugin_data['FAN']['duty_cycle_to_pwm']) + pwm = duty_cycle_to_pwm(val) + print "New Speed: %d%% - PWM value to be set is %d\n"%(val,pwm) + + for i in range(1, num_fan+1): + attr = "fan" + str(i) + "_pwm" + node = pddf_obj.get_path("FAN-CTRL", attr) + if node is None: + return False + try: + with open(node, 'w') as f: + f.write(str(pwm)) + except IOError: + return False + + return True + + def dump_sysfs(self): + return pddf_obj.cli_dump_dsysfs('fan') + + def get_change_event(self): + """ + TODO: This function need to be implemented + when decide to support monitoring FAN(fand) + on this platform. + """ + raise NotImplementedError diff --git a/device/common/pddf/plugins/ledutil.py b/device/common/pddf/plugins/ledutil.py new file mode 100755 index 0000000000..adbfe9cc62 --- /dev/null +++ b/device/common/pddf/plugins/ledutil.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python + +import sys +sys.path.append('/usr/share/sonic/platform/plugins') +import pddfparse + +class LedUtil: + color_map = { + "STATUS_LED_COLOR_GREEN" : "on", + "STATUS_LED_COLOR_RED" : "faulty", + "STATUS_LED_COLOR_OFF" : "off" + } + + def __init__(self): + global pddf_obj + pddf_obj = pddfparse.PddfParse() + self.path="pddf/devices/led" + self.cur_state_path="pddf/devices/led/cur_state" + + def set_status_led(self, led_device_name, color, color_state="SOLID"): + if (not led_device_name in pddf_obj.data.keys()): + status="ERROR: " + led_device_name + " is not configured" + return (status) + + if (not color in self.color_map.keys()): + status="ERROR: Invalid color" + return (status) + + index=pddf_obj.data[led_device_name]['dev_attr']['index'] + pddf_obj.create_attr('device_name', led_device_name, self.path) + pddf_obj.create_attr('index', index, self.path) + pddf_obj.create_attr('color', self.color_map[color], self.cur_state_path) + pddf_obj.create_attr('color_state', color_state, self.cur_state_path) + pddf_obj.create_attr('dev_ops', 'set_status', self.path) + return ("Executed") + + def get_status_led(self, led_device_name): + if (not led_device_name in pddf_obj.data.keys()): + status="ERROR: " + led_device_name + " is not configured" + return (status) + + index=pddf_obj.data[led_device_name]['dev_attr']['index'] + pddf_obj.create_attr('device_name', led_device_name, self.path) + pddf_obj.create_attr('index', index, self.path) + pddf_obj.create_attr('dev_ops', 'get_status', self.path) + color_f="/sys/kernel/" + self.cur_state_path +"/color" + color_state_f="/sys/kernel/" + self.cur_state_path +"/color_state" + + try: + with open(color_f, 'r') as f: + color = f.read().strip("\r\n") + with open(color_state_f, 'r') as f: + color_state = f.read().strip("\r\n") + except IOError: + status="ERROR :" + color_f + " open failed" + return (status) + status = "%s-%s:\t%s %s\n"%(led_device_name, index, color, color_state) + return (status) diff --git a/device/common/pddf/plugins/psuutil.py b/device/common/pddf/plugins/psuutil.py new file mode 100755 index 0000000000..01cf4b126e --- /dev/null +++ b/device/common/pddf/plugins/psuutil.py @@ -0,0 +1,272 @@ +#!/usr/bin/env python +# +# Sample pddf_psuutil file +# +# All the supported PSU SysFS aattributes are +#- psu_present +#- psu_model_name +#- psu_power_good +#- psu_mfr_id +#- psu_serial_num +#- psu_fan_dir +#- psu_v_out +#- psu_i_out +#- psu_p_out +#- psu_fan1_speed_rpm +# + +import os.path +import sys +sys.path.append('/usr/share/sonic/platform/plugins') +import pddfparse +import json + +try: + from sonic_psu.psu_base import PsuBase +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + + +class PsuUtil(PsuBase): + """PDDF generic PSU util class""" + + def __init__(self): + PsuBase.__init__(self) + global pddf_obj + global plugin_data + with open(os.path.join(os.path.dirname(os.path.realpath(__file__)) + '/../pddf/pd-plugin.json')) as pd: + plugin_data = json.load(pd) + + pddf_obj = pddfparse.PddfParse() + self.platform = pddf_obj.get_platform() + + def get_num_psus(self): + return int(self.platform['num_psus']) + + def get_psu_status(self, index): + if index is None: + return False + + device = "PSU" + "%d"%index + output = pddf_obj.get_attr_name_output(device, "psu_power_good") + if not output: + return False + + mode = output['mode'] + val = output['status'] + + val = val.rstrip() + vmap = plugin_data['PSU']['psu_power_good'][mode]['valmap'] + + if val in vmap: + return vmap[val] + else: + return False + + def get_psu_presence(self, index): + if index is None: + return False + + status = 0 + device = "PSU" + "%d"%index + output = pddf_obj.get_attr_name_output(device, "psu_present") + if not output: + return False + + mode = output['mode'] + status = output['status'] + + vmap = plugin_data['PSU']['psu_present'][mode]['valmap'] + + if status.rstrip('\n') in vmap: + return vmap[status.rstrip('\n')] + else: + return False + + def get_powergood_status(self, idx): + if idx is None: + return False + + if idx<1 or idx>self.platform['num_psus']: + print "Invalid index %d\n"%idx + return False + + device = "PSU"+"%d"%(idx) + output = pddf_obj.get_attr_name_output(device, "psu_power_good") + if not output: + return False + + mode = output['mode'] + status = output ['status'] + + vmap = plugin_data['PSU']['psu_power_good'][mode]['valmap'] + + if status.rstrip('\n') in vmap: + return vmap[status.rstrip('\n')] + else: + return False + + def get_model(self, idx): + if idx is None: + return None + + if idx<1 or idx>self.platform['num_psus']: + print "Invalid index %d\n"%idx + return None + + device = "PSU"+"%d"%(idx) + output = pddf_obj.get_attr_name_output(device, "psu_model_name") + if not output: + return None + + model = output['status'] + + # strip_non_ascii + stripped = (c for c in model if 0 < ord(c) < 127) + model = ''.join(stripped) + + return model.rstrip('\n') + + def get_mfr_id(self, idx): + if idx is None: + return None + + if idx<1 or idx>self.platform['num_psus']: + print "Invalid index %d\n"%idx + return None + + device = "PSU"+"%d"%(idx) + output = pddf_obj.get_attr_name_output(device, "psu_mfr_id") + if not output: + return None + + mfr = output['status'] + + return mfr.rstrip('\n') + + def get_serial(self, idx): + if idx is None: + return None + + if idx<1 or idx>self.platform['num_psus']: + print "Invalid index %d\n"%idx + return None + + device = "PSU"+"%d"%(idx) + output = pddf_obj.get_attr_name_output(device, "psu_serial_num") + if not output: + return None + + serial = output['status'] + + return serial.rstrip('\n') + + def get_direction(self, idx): + if idx is None: + return None + + if idx<1 or idx>self.platform['num_psus']: + print "Invalid index %d\n"%idx + return None + + device = "PSU"+"%d"%(idx) + output = pddf_obj.get_attr_name_output(device, "psu_fan_dir") + if not output: + return None + + mode = output['mode'] + direction = output['status'].rstrip('\n') + + vmap = plugin_data['PSU']['psu_fan_dir'][mode]['valmap'] + if direction in vmap: + airflow_dir_real = vmap[direction] + else: + airflow_dir_real = direction + + return airflow_dir_real + + def get_output_voltage(self, idx): + if idx is None: + return 0.0 + + if idx<1 or idx>self.platform['num_psus']: + print "Invalid index %d\n"%idx + return 0.0 + + device = "PSU"+"%d"%(idx) + output = pddf_obj.get_attr_name_output(device, "psu_v_out") + if not output: + return 0.0 + + v_out = output['status'] + + # value returned by the psu driver is in mV + return float(v_out)/1000 + + def get_output_current(self, idx): + if idx is None: + return 0.0 + + if idx<1 or idx>self.platform['num_psus']: + print "Invalid index %d\n"%idx + return 0.0 + + device = "PSU"+"%d"%(idx) + output = pddf_obj.get_attr_name_output(device, "psu_i_out") + if not output: + return 0.0 + + i_out = output['status'] + + # current in mA + return float(i_out)/1000 + + def get_output_power(self, idx): + if idx is None: + return 0.0 + + if idx<1 or idx>self.platform['num_psus']: + print "Invalid index %d\n"%idx + return 0.0 + + device = "PSU"+"%d"%(idx) + output = pddf_obj.get_attr_name_output(device, "psu_p_out") + if not output: + return 0.0 + + p_out = output['status'] + + # power is returned in micro watts + return float(p_out)/1000000 + + def get_fan_rpm(self, idx, fan_idx): + if idx is None or fan_idx is None: + return 0 + + if idx<1 or idx>self.platform['num_psus']: + print "Invalid index %d\n"%idx + return 0 + + + device = "PSU"+"%d"%(idx) + num_fans = pddf_obj.get_num_psu_fans(device) + + if fan_idx<1 or fan_idx>num_fans: + print "Invalid PSU-fan index %d\n"%fan_idx + return 0 + + output = pddf_obj.get_attr_name_output(device, "psu_fan"+str(fan_idx)+"_speed_rpm") + if not output: + return 0 + + #mode = output['mode'] + output['status'] = output['status'].rstrip() + if output['status'].isalpha(): + return 0 + else: + speed = int(output['status']) + + return speed + + def dump_sysfs(self): + return pddf_obj.cli_dump_dsysfs('psu') diff --git a/device/common/pddf/plugins/sfputil.py b/device/common/pddf/plugins/sfputil.py new file mode 100755 index 0000000000..394aff1c42 --- /dev/null +++ b/device/common/pddf/plugins/sfputil.py @@ -0,0 +1,237 @@ +#!/usr/bin/env python + +import os.path +import sys +sys.path.append('/usr/share/sonic/platform/plugins') +import pddfparse +import json + +try: + import time + from ctypes import create_string_buffer + from sonic_sfp.sfputilbase import SfpUtilBase +except ImportError, e: + raise ImportError (str(e) + "- required module not found") + +class SfpUtil(SfpUtilBase): + """Platform generic PDDF SfpUtil class""" + + _port_to_eeprom_mapping = {} + _port_start = 0 + _port_end = 0 + _port_to_type_mapping = {} + _qsfp_ports = [] + _sfp_ports = [] + + def __init__(self): + SfpUtilBase.__init__(self) + global pddf_obj + global plugin_data + with open(os.path.join(os.path.dirname(os.path.realpath(__file__)) + '/../pddf/pd-plugin.json')) as pd: + plugin_data = json.load(pd) + + pddf_obj = pddfparse.PddfParse() + self.platform = pddf_obj.get_platform() + self._port_start = 0 + self._port_end = self.get_num_ports() + + for port_num in range(self._port_start, self._port_end): + device = "PORT" + "%d"%(port_num+1) + port_eeprom_path = pddf_obj.get_path(device,"eeprom") + self._port_to_eeprom_mapping[port_num] = port_eeprom_path + port_type = pddf_obj.get_device_type(device) + self._port_to_type_mapping[port_num] = port_type + self.populate_port_type(port_num) + + def get_num_ports(self): + return int(self.platform['num_ports']) + + def is_valid_port(self, port_num): + if port_num < self._port_start or port_num > self._port_end: + return False + else: + return True + + def get_presence(self, port_num): + if port_num < self._port_start or port_num > self._port_end: + return False + + device = "PORT" + "%d"%(port_num+1) + output = pddf_obj.get_attr_name_output(device, 'xcvr_present') + if not output: + return False + + #mode = output['mode'] + modpres = output['status'].rstrip() + if 'XCVR' in plugin_data: + if 'xcvr_present' in plugin_data['XCVR']: + ptype = self._port_to_type_mapping[port_num] + vtype = 'valmap-'+ptype + if vtype in plugin_data['XCVR']['xcvr_present']: + vmap = plugin_data['XCVR']['xcvr_present'][vtype] + if modpres in vmap: + return vmap[modpres] + else: + return False + # if plugin_data doesn't specify anything regarding Transceivers + if modpres == '1': + return True + + return False + + def populate_port_type(self, port): + if self._port_to_type_mapping[port] == 'QSFP' or self._port_to_type_mapping[port] == 'QSFP28': + self._qsfp_ports.append(port) + elif self._port_to_type_mapping[port] == 'SFP' or self._port_to_type_mapping[port] == 'SFP28': + self._sfp_ports.append(port) + + @property + def port_start(self): + return self._port_start + + @property + def port_end(self): + return (self._port_end - 1) + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + @property + def qsfp_ports(self): + return self._qsfp_ports + + def reset(self, port_num): + if port_num < self._port_start or port_num > self._port_end: + return False + + device = "PORT" + "%d"%(port_num+1) + port_ps = pddf_obj.get_path(device,"xcvr_reset") + if port_ps is None: + return False + + try: + reg_file = open(port_ps, 'w') + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + try: + reg_file.seek(0) + reg_file.write('1') + time.sleep(1) + reg_file.seek(0) + reg_file.write('0') + reg_file.close() + return True + except IOError as e: + return False + + def get_low_power_mode(self, port_num): + # Check for invalid port_num + if port_num < self._port_start or port_num > self._port_end: + return False + + if not self.get_presence(port_num): + return False + + device = "PORT" + "%d"%(port_num+1) + output = pddf_obj.get_attr_name_output(device, 'xcvr_lpmode') + if not output: + if port_num not in self.qsfp_ports: + return False # Read from eeprom only for QSFP ports + try: + eeprom = None + eeprom = open(self.port_to_eeprom_mapping[port_num], "rb") + # check for valid connector type + eeprom.seek(2) + ctype = eeprom.read(1) + if ctype in ['21','23']: + return False + + eeprom.seek(93) + lpmode = ord(eeprom.read(1)) + + if ((lpmode & 0x3) == 0x3): + return True # Low Power Mode if "Power override" bit is 1 and "Power set" bit is 1 + else: + return False # High Power Mode if one of the following conditions is matched: + # 1. "Power override" bit is 0 + # 2. "Power override" bit is 1 and "Power set" bit is 0 + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + finally: + if eeprom is not None: + eeprom.close() + time.sleep(0.01) + else: + #mode = output['mode'] + status = int(output['status'].rstrip()) + + if status == 1: + return True + else: + return False + + def set_low_power_mode(self, port_num, lpmode): + # Check for invalid port_num + if port_num < self._port_start or port_num > self._port_end: + return False + + if not self.get_presence(port_num): + return False # Port is not present, unable to set the eeprom + + device = "PORT" + "%d"%(port_num+1) + port_ps = pddf_obj.get_path(device,"xcvr_lpmode") + if port_ps is None: + if port_num not in self.qsfp_ports: + return False # Write to eeprom only for QSFP ports + try: + eeprom = None + eeprom = open(self.port_to_eeprom_mapping[port_num], "r+b") + # check for valid connector type + eeprom.seek(2) + ctype = eeprom.read(1) + if ctype in ['21','23']: + return False + + # Fill in write buffer + regval = 0x3 if lpmode else 0x1 # 0x3:Low Power Mode, 0x1:High Power Mode + buffer = create_string_buffer(1) + buffer[0] = chr(regval) + + # Write to eeprom + eeprom.seek(93) + eeprom.write(buffer[0]) + return True + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + finally: + if eeprom is not None: + eeprom.close() + time.sleep(0.01) + else: + try: + f = open(port_ps, 'w') + if lpmode: + f.write('1') + else: + f.write('0') + f.close() + return True + except IOError as e: + return False + + def get_transceiver_change_event(self): + """ + TODO: This function need to be implemented + when decide to support monitoring SFP(Xcvrd) + on this platform. + """ + raise NotImplementedError + + + def dump_sysfs(self): + return pddf_obj.cli_dump_dsysfs('xcvr') diff --git a/device/common/pddf/plugins/sysstatutil.py b/device/common/pddf/plugins/sysstatutil.py new file mode 100755 index 0000000000..e8b3e80086 --- /dev/null +++ b/device/common/pddf/plugins/sysstatutil.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python + +import os.path +import sys +sys.path.append('/usr/share/sonic/platform/plugins') +import pddfparse +import json + +class SYSStatusUtil(): + """Platform-specific SYSStatus class""" + def __init__(self): + global pddf_obj + global plugin_data + with open(os.path.join(os.path.dirname(os.path.realpath(__file__)) + '/../pddf/pd-plugin.json')) as pd: + plugin_data = json.load(pd) + + pddf_obj = pddfparse.PddfParse() + + def get_board_info(self): + device = "SYSSTATUS" + node = pddf_obj.get_path(device,"board_info") + if node is None: + return False + try: + with open(node, 'r') as f: + status = f.read() + print "board_info : %s" %status + except IOError: + return False + + def get_cpld_versio(self): + device = "SYSSTATUS" + node = pddf_obj.get_path(device,"cpld1_version") + if node is None: + return False + try: + with open(node, 'r') as f: + status = f.read() + print "cpld1_version : %s" %status + except IOError: + return False + + def get_power_module_status(self): + device = "SYSSTATUS" + node = pddf_obj.get_path(device,"power_module_status") + if node is None: + return False + try: + with open(node, 'r') as f: + status = f.read() + print "power_module_status : %s" %status + except IOError: + return False + + + def get_system_reset_status(self): + device = "SYSSTATUS" + for i in range(1,8): + node = pddf_obj.get_path(device,"system_reset"+str(i)) + if node is None: + return False + try: + with open(node, 'r') as f: + status = f.read() + print "system_reset%s : %s" %(i, status) + except IOError: + print "system_reset%s not supported" %i + + + def get_misc_status(self): + device = "SYSSTATUS" + for i in range(1,3): + node = pddf_obj.get_path(device,"misc"+str(i)) + if node is None: + return False + try: + with open(node, 'r') as f: + status = f.read() + print "misc%s : %s" %(i, status) + except IOError: + print "system_reset%s not supported" %i + + + def dump_sysfs(self): + return pddf_obj.cli_dump_dsysfs('sys-status') diff --git a/device/common/pddf/plugins/thermalutil.py b/device/common/pddf/plugins/thermalutil.py new file mode 100755 index 0000000000..ebf29608a4 --- /dev/null +++ b/device/common/pddf/plugins/thermalutil.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python + +import os.path +import sys +import json +sys.path.append('/usr/share/sonic/platform/plugins') +import pddfparse + +class ThermalUtil: + def __init__(self): + global pddf_obj + global plugin_data + with open(os.path.join(os.path.dirname(os.path.realpath(__file__)) + '/../pddf/pd-plugin.json')) as pd: + plugin_data = json.load(pd) + + pddf_obj = pddfparse.PddfParse() + self.platform = pddf_obj.get_platform() + self.num_thermals = self.platform['num_temps'] + self.info=[] + + def get_num_thermals(self): + return (self.num_thermals) + + def get_thermal_info(self): + list=[] + pddf_obj.get_device_list(list, "TEMP_SENSOR") + list.sort() + for dev in list: + data={} + device_name = dev['dev_info']['device_name'] + topo_info = dev['i2c']['topo_info'] + label="%s-i2c-%d-%x" % (topo_info['dev_type'], int(topo_info['parent_bus'], 0), int(topo_info['dev_addr'], 0)) + attr_list = dev['i2c']['attr_list'] + data['device_name']=device_name + data['label']=label + for attr in attr_list: + attr_name = attr['attr_name'] + node = pddf_obj.get_path(device_name, attr_name) + if node is None: + return False + try: + with open(node, 'r') as f: + attr_value = int(f.read()) + except IOError: + return False + data[attr_name] = attr_value/float(1000) + self.info.append(data) + + def show_thermal_temp_values(self, idx): + if idx<1 or idx>self.num_thermals: + print "Invalid temperature sensor idx %d"%idx + return None + self.get_thermal_info() + thermal_name = "TEMP"+"%d"%idx + label="" + value="" + for temp in self.info: + if thermal_name==temp['device_name']: + label = temp['label'] + value = "temp1\t %+.1f C (high = %+.1f C, hyst = %+.1f C)" % (temp['temp1_input'], temp['temp1_max'], temp['temp1_max_hyst']) + else: + continue + + return (label, value) + + def show_temp_values(self): + self.get_thermal_info() + for temp in self.info: + print temp['label'] + print "temp1\t %+.1f C (high = %+.1f C, hyst = %+.1f C)" % (temp['temp1_input'], temp['temp1_max'], temp['temp1_max_hyst']) + + + def dump_sysfs(self): + return pddf_obj.cli_dump_dsysfs('temp-sensors') diff --git a/dockers/docker-platform-monitor/Dockerfile.j2 b/dockers/docker-platform-monitor/Dockerfile.j2 index 0dd5b8fc75..7659ee4d35 100755 --- a/dockers/docker-platform-monitor/Dockerfile.j2 +++ b/dockers/docker-platform-monitor/Dockerfile.j2 @@ -19,7 +19,8 @@ RUN apt-get update && \ python-smbus \ ethtool \ dmidecode \ - i2c-tools + i2c-tools \ + python-jsonschema # On Arista devices, the sonic_platform wheel is not installed in the container. # Instead, the installation directory is mounted from the host OS. However, this method diff --git a/files/build_templates/sonic_debian_extension.j2 b/files/build_templates/sonic_debian_extension.j2 index 7b8299fda1..0fe1043fcb 100644 --- a/files/build_templates/sonic_debian_extension.j2 +++ b/files/build_templates/sonic_debian_extension.j2 @@ -178,6 +178,14 @@ sudo cp {{platform_common_py2_wheel_path}} $FILESYSTEM_ROOT/$PLATFORM_COMMON_PY2 sudo https_proxy=$https_proxy LANG=C chroot $FILESYSTEM_ROOT pip2 install $PLATFORM_COMMON_PY2_WHEEL_NAME sudo rm -rf $FILESYSTEM_ROOT/$PLATFORM_COMMON_PY2_WHEEL_NAME +{% if pddf_support == "y" %} +# Install pddf-platform-api-base Python 2 package +PLATFORM_PDDF_COMMON_PY2_WHEEL_NAME=$(basename {{pddf_platform_api_base_py2_wheel_path}}) +sudo cp {{pddf_platform_api_base_py2_wheel_path}} $FILESYSTEM_ROOT/$PLATFORM_PDDF_COMMON_PY2_WHEEL_NAME +sudo https_proxy=$https_proxy LANG=C chroot $FILESYSTEM_ROOT pip install $PLATFORM_PDDF_COMMON_PY2_WHEEL_NAME +sudo rm -rf $FILESYSTEM_ROOT/$PLATFORM_PDDF_COMMON_PY2_WHEEL_NAME +{% endif %} + # Install system-health Python 2 package SYSTEM_HEALTH_PY2_WHEEL_NAME=$(basename {{system_health_py2_wheel_path}}) sudo cp {{system_health_py2_wheel_path}} $FILESYSTEM_ROOT/$SYSTEM_HEALTH_PY2_WHEEL_NAME diff --git a/platform/broadcom/one-image.mk b/platform/broadcom/one-image.mk index 538461b4db..f557f17c7c 100644 --- a/platform/broadcom/one-image.mk +++ b/platform/broadcom/one-image.mk @@ -4,6 +4,7 @@ SONIC_ONE_IMAGE = sonic-broadcom.bin $(SONIC_ONE_IMAGE)_MACHINE = broadcom $(SONIC_ONE_IMAGE)_IMAGE_TYPE = onie $(SONIC_ONE_IMAGE)_INSTALLS += $(BRCM_OPENNSL_KERNEL) +$(SONIC_ONE_IMAGE)_INSTALLS += $(PDDF_PLATFORM_MODULE) $(SONIC_ONE_IMAGE)_INSTALLS += $(SYSTEMD_SONIC_GENERATOR) $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \ $(DELL_Z9264F_PLATFORM_MODULE) \ diff --git a/platform/pddf/README.md b/platform/pddf/README.md new file mode 100644 index 0000000000..b46bb6780b --- /dev/null +++ b/platform/pddf/README.md @@ -0,0 +1,19 @@ + Platform Driver Development Framework (PDDF) is part of SONiC Platform Development Kit (PDK) which optimizes the platform developement. + + SONiC PDDF (Platform driver development framework) supports the following HW devices on a given platform: + + - Fan + - PSU + - System EEPROM + - CPLD + - CPLDMUX + - GPIO + - Optic Transceivers + - System LED control via CPLD + - System Status Registers in CPLD + - Temp Sensors + + This folder for the PDDF consists of the following: + + - PDDF python utility scripts + - Generic PDDF HW device drivers in kernel space diff --git a/platform/pddf/i2c/Makefile b/platform/pddf/i2c/Makefile new file mode 100644 index 0000000000..1486370b50 --- /dev/null +++ b/platform/pddf/i2c/Makefile @@ -0,0 +1 @@ +subdir-m := modules diff --git a/platform/pddf/i2c/debian/changelog b/platform/pddf/i2c/debian/changelog new file mode 100755 index 0000000000..505184c1fd --- /dev/null +++ b/platform/pddf/i2c/debian/changelog @@ -0,0 +1,12 @@ +sonic-pddf-platform-modules (1.1) unstable; urgency=low + + * Enhancing PDDF: Added support for cpldmux, gpio and some extra attributes + + -- Broadcom Wed, 10 Jun 2020 10:10:10 -0800 + +sonic-pddf-platform-modules (1.0) unstable; urgency=low + + * Basic tempelate for PDDF + * Initial release + + -- Broadcom Wed, 26 Jun 2019 10:10:10 -0800 diff --git a/platform/pddf/i2c/debian/compat b/platform/pddf/i2c/debian/compat new file mode 100644 index 0000000000..ec635144f6 --- /dev/null +++ b/platform/pddf/i2c/debian/compat @@ -0,0 +1 @@ +9 diff --git a/platform/pddf/i2c/debian/control b/platform/pddf/i2c/debian/control new file mode 100755 index 0000000000..afd96c3d26 --- /dev/null +++ b/platform/pddf/i2c/debian/control @@ -0,0 +1,12 @@ +Source: sonic-pddf-platform-modules +Section: main +Priority: extra +Maintainer: Broadcom +Build-Depends: debhelper (>= 9), bzip2 +Standards-Version: 3.9.3 + +Package: sonic-platform-pddf +Architecture: amd64 +Description: kernel modules for platform devices such as psu, fan, sfp, led + + diff --git a/platform/pddf/i2c/debian/rules b/platform/pddf/i2c/debian/rules new file mode 100755 index 0000000000..35fca9a784 --- /dev/null +++ b/platform/pddf/i2c/debian/rules @@ -0,0 +1,75 @@ +#!/usr/bin/make -f +# -*- makefile -*- +# Sample debian/rules that uses debhelper. +# This file was originally written by Joey Hess and Craig Small. +# As a special exception, when this file is copied by dh-make into a +# dh-make output file, you may use that output file without restriction. +# This special exception was added by Craig Small in version 0.37 of dh-make. +include /usr/share/dpkg/pkg-info.mk + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +export INSTALL_MOD_DIR:=extra + +PYTHON ?= python2 + +PACKAGE_PRE_NAME := sonic-platform-pddf +KVERSION ?= $(shell uname -r) +KERNEL_SRC := /lib/modules/$(KVERSION) +MOD_SRC_DIR:= $(shell pwd) +MODULE_DIRS:= client cpld cpld/driver cpldmux cpldmux/driver fan fan/driver fan/vendor_api mux gpio led psu psu/driver sysstatus xcvr xcvr/driver +MODULE_DIR:= modules +UTILS_DIR := utils +SERVICE_DIR := service + +%: + echo =================RUNNING $@============= + dh $@ --with systemd,python2,python3 --buildsystem=pybuild + +clean: + echo ============CLEANING================= + dh_testdir + dh_testroot + dh_clean + make -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR) clean + +build: + make modules -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR); \ + $(PYTHON) $(MOD_SRC_DIR)/setup.py build; \ + +binary: binary-arch binary-indep + # Nothing to do + +binary-arch: + # Nothing to do + +binary-indep: + dh_testdir + dh_installdirs + dh_installdirs -p$(PACKAGE_PRE_NAME) $(KERNEL_SRC)/$(INSTALL_MOD_DIR); \ + dh_installdirs -p$(PACKAGE_PRE_NAME) usr/local/bin; \ + # Custom package commands + (for mod in $(MODULE_DIRS); do \ + cp $(MOD_SRC_DIR)/$(MODULE_DIR)/$${mod}/*.ko debian/$(PACKAGE_PRE_NAME)/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \ + done) ; \ + cp -r $(MOD_SRC_DIR)/$(UTILS_DIR)/* debian/$(PACKAGE_PRE_NAME)/usr/local/bin/; \ + $(PYTHON) $(MOD_SRC_DIR)/setup.py install --root=$(MOD_SRC_DIR)/debian/$(PACKAGE_PRE_NAME) --install-layout=deb; + + # Resuming debhelper scripts + dh_testroot + dh_install + dh_installchangelogs + dh_installdocs + dh_systemd_enable + dh_installinit + dh_systemd_start + dh_link + dh_fixperms + dh_compress + dh_strip + dh_installdeb + dh_gencontrol + dh_md5sums + dh_builddeb +.PHONY: build binary binary-arch binary-indep clean diff --git a/platform/pddf/i2c/modules/Makefile b/platform/pddf/i2c/modules/Makefile new file mode 100644 index 0000000000..67d3726c32 --- /dev/null +++ b/platform/pddf/i2c/modules/Makefile @@ -0,0 +1 @@ +subdir-m := client cpld cpldmux xcvr mux gpio psu fan led sysstatus diff --git a/platform/pddf/i2c/modules/client/Makefile b/platform/pddf/i2c/modules/client/Makefile new file mode 100644 index 0000000000..c841a144f2 --- /dev/null +++ b/platform/pddf/i2c/modules/client/Makefile @@ -0,0 +1,3 @@ +obj-m:= pddf_client_module.o + +ccflags-y := -I$(M)/modules/include diff --git a/platform/pddf/i2c/modules/client/pddf_client_module.c b/platform/pddf/i2c/modules/client/pddf_client_module.c new file mode 100644 index 0000000000..f36596dbe9 --- /dev/null +++ b/platform/pddf/i2c/modules/client/pddf_client_module.c @@ -0,0 +1,330 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * A pddf kernel module to create access-data attributes for client creation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pddf_client_defs.h" + + + +NEW_DEV_ATTR pddf_data={0}; +EXPORT_SYMBOL(pddf_data); +int showall = 0; + + +/* CLIENT CREATION DATA ATTR LIST */ +PDDF_DATA_ATTR(i2c_type, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_CHAR, 32, (void*)&pddf_data.i2c_type, NULL); +PDDF_DATA_ATTR(i2c_name, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_CHAR, 32, (void*)&pddf_data.i2c_name, NULL); +PDDF_DATA_ATTR(parent_bus, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_HEX, sizeof(int), (void*)&pddf_data.parent_bus, NULL); +PDDF_DATA_ATTR(dev_type, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_CHAR, 32, (void*)&pddf_data.dev_type, NULL); +PDDF_DATA_ATTR(dev_id, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_DEC, sizeof(int), (void*)&pddf_data.dev_id, NULL); +PDDF_DATA_ATTR(dev_addr, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_HEX, sizeof(int), (void*)&pddf_data.dev_addr, NULL); +PDDF_DATA_ATTR(error, S_IRUGO, show_error_code, NULL, PDDF_INT_DEC, sizeof(int), (void*)&pddf_data.error, (void*)&pddf_data.errstr); + + + +static struct attribute *pddf_clients_data_attributes[] = { + &attr_i2c_type.dev_attr.attr, + &attr_i2c_name.dev_attr.attr, + &attr_parent_bus.dev_attr.attr, + &attr_dev_type.dev_attr.attr, + &attr_dev_id.dev_attr.attr, + &attr_dev_addr.dev_attr.attr, + &attr_error.dev_attr.attr, + NULL +}; + +struct attribute_group pddf_clients_data_group = { + .attrs = pddf_clients_data_attributes, +}; +EXPORT_SYMBOL(pddf_clients_data_group); + + + +PDDF_DATA_ATTR(showall, S_IRUGO, show_all_devices, NULL, PDDF_INT_DEC, sizeof(int), (void *)&showall, NULL); + +static struct attribute *pddf_allclients_data_attributes[] = { + &attr_showall.dev_attr.attr, + NULL +}; +struct attribute_group pddf_allclients_data_group = { + .attrs = pddf_allclients_data_attributes, +}; + + + + + +void set_attr_data(void * ptr) +{ + pddf_data.data=ptr; +} + +ssize_t show_all_devices(struct device *dev, struct device_attribute *da, char *buf) +{ + int ret = 0; + PDDF_ATTR *pptr = (PDDF_ATTR *)da; + int *ptr = (int *)pptr->addr; + + traverse_device_table(); + ret = sprintf(buf, "Total Devices: %d\n", *ptr); + + return ret; +} + +ssize_t show_error_code(struct device *dev, struct device_attribute *da, char *buf) +{ + int ret = 0; + PDDF_ATTR *pptr = (PDDF_ATTR *)da; + NEW_DEV_ATTR *ptr = ( NEW_DEV_ATTR *)pptr->addr; + + ret = sprintf(buf, "0x%x:%s\n", (ptr->error), ptr->errstr); + + return ret; +} + +void set_error_code(int ecode, char *estr) +{ + pddf_data.error = ecode; + strcpy(pddf_data.errstr, estr); + return; +} +EXPORT_SYMBOL(set_error_code); + +ssize_t show_pddf_data(struct device *dev, struct device_attribute *da, char *buf) +{ + int ret = 0; + PDDF_ATTR *ptr = (PDDF_ATTR *)da; + /*pddf_dbg(KERN_ERR "[ READ ] DATA ATTR PTR TYPE:%d, ADDR=%p\n", ptr->type, ptr->addr);*/ + switch(ptr->type) + { + case PDDF_CHAR: + ret = sprintf(buf, "%s\n", ptr->addr); + break; + case PDDF_UCHAR: + ret = sprintf(buf, "%d\n", *(unsigned char*)(ptr->addr)); + break; + case PDDF_INT_DEC: + ret = sprintf(buf, "%d\n", *(int*)(ptr->addr)); + break; + case PDDF_INT_HEX: + ret = sprintf(buf, "0x%x\n", *(int*)(ptr->addr)); + break; + case PDDF_USHORT: + ret = sprintf(buf, "0x%x\n", *(unsigned short *)(ptr->addr)); + break; + case PDDF_UINT32: + ret = sprintf(buf, "0x%x\n", *(uint32_t *)(ptr->addr)); + break; + default: + break; + } + + return ret; +} +EXPORT_SYMBOL(show_pddf_data); + +ssize_t store_pddf_data(struct device *dev, struct device_attribute *da, const char *buf, size_t count) +{ + int ret = 0, num = 0; + + + PDDF_ATTR *ptr = (PDDF_ATTR *)da; + + switch(ptr->type) + { + case PDDF_CHAR: + strncpy(ptr->addr, buf, strlen(buf)-1); // to discard newline char form buf + ptr->addr[strlen(buf)-1] = '\0'; + break; + case PDDF_UCHAR: + ret = kstrtoint(buf,10,&num); + if (ret==0) + *(unsigned char *)(ptr->addr) = (unsigned char)num; + break; + case PDDF_INT_DEC: + ret = kstrtoint(buf,10,&num); + if (ret==0) + *(int *)(ptr->addr) = num; + break; + case PDDF_INT_HEX: + ret = kstrtoint(buf,16,&num); + if (ret==0) + *(int *)(ptr->addr) = num; + break; + case PDDF_USHORT: + ret = kstrtoint(buf,16,&num); + if (ret==0) + *(unsigned short *)(ptr->addr) = (unsigned short)num; + break; + case PDDF_UINT32: + ret = kstrtoint(buf,16,&num); + if (ret==0) + *(uint32_t *)(ptr->addr) = (uint32_t)num; + break; + default: + break; + } + + return count; +} +EXPORT_SYMBOL(store_pddf_data); + + + +DEFINE_HASHTABLE(htable, 8); + +int get_hash(char *name) +{ + int i=0; + int hash=0; + for(i=0; iname, name); + hdev->data = ptr; + pddf_dbg(CLIENT, KERN_ERR "%s: Adding ptr 0x%p to the hash table\n", __FUNCTION__, ptr); + hash_add(htable, &hdev->node, get_hash(hdev->name)); +} +EXPORT_SYMBOL(add_device_table); + +void* get_device_table(char *name) +{ + PDEVICE *dev=NULL; + int i=0; + + hash_for_each(htable, i, dev, node) { + if(strcmp(dev->name, name)==0) { + return (void *)dev->data; + } + } + + return NULL; +} +EXPORT_SYMBOL(get_device_table); + +void delete_device_table(char *name) +{ + PDEVICE *dev=NULL; + int i=0; + + hash_for_each(htable, i, dev, node) { + if(strcmp(dev->name, name)==0) { + pddf_dbg(CLIENT, KERN_ERR "found entry to delete: %s 0x%p\n", dev->name, dev->data); + hash_del(&(dev->node)); + } + } + return; +} +EXPORT_SYMBOL(delete_device_table); + +void traverse_device_table(void ) +{ + PDEVICE *dev=NULL; + int i=0; + hash_for_each(htable, i, dev, node) { + pddf_dbg(CLIENT, KERN_ERR "Entry[%d]: %s : 0x%p\n", i, dev->name, dev->data); + } + showall = i; +} +EXPORT_SYMBOL(traverse_device_table); + +struct kobject *device_kobj; +static struct kobject *pddf_kobj; + +struct kobject *get_device_i2c_kobj(void) +{ + return device_kobj; +} + +EXPORT_SYMBOL(get_device_i2c_kobj); + +int __init pddf_data_init(void) +{ + int ret = 0; + + + pddf_dbg(CLIENT, "PDDF_DATA MODULE.. init\n"); + + pddf_kobj = kobject_create_and_add("pddf", kernel_kobj); + if(!pddf_kobj) { + return -ENOMEM; + } + device_kobj = kobject_create_and_add("devices", pddf_kobj); + if(!device_kobj) { + return -ENOMEM; + } + + init_device_table(); + + ret = sysfs_create_group(device_kobj, &pddf_allclients_data_group); + if (ret) + { + kobject_put(device_kobj); + return ret; + } + pddf_dbg(CLIENT, "CREATED PDDF ALLCLIENTS CREATION SYSFS GROUP\n"); + + + + return ret; +} + +void __exit pddf_data_exit(void) +{ + + pddf_dbg(CLIENT, "PDDF_DATA MODULE.. exit\n"); + sysfs_remove_group(device_kobj, &pddf_allclients_data_group); + + kobject_put(device_kobj); + kobject_put(pddf_kobj); + pddf_dbg(CLIENT, KERN_ERR "%s: Removed the kernle object for 'pddf' and 'device' \n", __FUNCTION__); + return; +} + +module_init(pddf_data_init); +module_exit(pddf_data_exit); + +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("pddf data"); +MODULE_LICENSE("GPL"); + diff --git a/platform/pddf/i2c/modules/cpld/Makefile b/platform/pddf/i2c/modules/cpld/Makefile new file mode 100644 index 0000000000..c6182ef4f9 --- /dev/null +++ b/platform/pddf/i2c/modules/cpld/Makefile @@ -0,0 +1,4 @@ +subdir-m := driver +obj-m := pddf_cpld_module.o + +CFLAGS_$(obj-m):= -I$(M)/modules/include diff --git a/platform/pddf/i2c/modules/cpld/driver/Makefile b/platform/pddf/i2c/modules/cpld/driver/Makefile new file mode 100644 index 0000000000..42704c2cfa --- /dev/null +++ b/platform/pddf/i2c/modules/cpld/driver/Makefile @@ -0,0 +1,5 @@ +TARGET = pddf_cpld_driver +obj-m := $(TARGET).o + + +ccflags-y := -I$(M)/modules/include diff --git a/platform/pddf/i2c/modules/cpld/driver/pddf_cpld_driver.c b/platform/pddf/i2c/modules/cpld/driver/pddf_cpld_driver.c new file mode 100755 index 0000000000..a34c370b9a --- /dev/null +++ b/platform/pddf/i2c/modules/cpld/driver/pddf_cpld_driver.c @@ -0,0 +1,230 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * A pddf kernel driver module for CPLD + */ + +#include +#include +#include +#include +#include +#include "pddf_cpld_defs.h" + +extern PDDF_CPLD_DATA pddf_cpld_data; + + +static LIST_HEAD(cpld_client_list); +static struct mutex list_lock; + +struct cpld_client_node { + struct i2c_client *client; + struct list_head list; +}; + +int board_i2c_cpld_read(unsigned short cpld_addr, u8 reg) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int ret = -EPERM; + + //hw_preaccess_func_cpld_mux_default((uint32_t)cpld_addr, NULL); + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client->addr == cpld_addr) { + ret = i2c_smbus_read_byte_data(cpld_node->client, reg); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(board_i2c_cpld_read); + +int board_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int ret = -EIO; + + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client->addr == cpld_addr) { + ret = i2c_smbus_write_byte_data(cpld_node->client, reg, value); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(board_i2c_cpld_write); + +ssize_t regval_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + int len = 0; + struct i2c_client *client = to_i2c_client(dev); + + mutex_lock(&pddf_cpld_data.cpld_lock); + // Put code here to read the register value and print it + if (pddf_cpld_data.reg_addr!=0) + len = sprintf(buf, "0x%2.2x\n", board_i2c_cpld_read(client->addr, pddf_cpld_data.reg_addr)); + else + len = sprintf(buf, "xx\n"); + + mutex_unlock(&pddf_cpld_data.cpld_lock); + return len; +} + +static DEVICE_ATTR_RO(regval); + +static struct attribute *cpld_attrs[] = { + &dev_attr_regval.attr, + NULL, +}; + +static struct attribute_group cpld_attribute_group = { + .attrs = cpld_attrs, +}; + + + + +/* Addresses scanned for board_i2c_cpld + */ +static const unsigned short normal_i2c[] = { 0x31, 0x32, 0x33, 0x35, 0x60, 0x61, 0x62, 0x64, I2C_CLIENT_END }; + +static void board_i2c_cpld_add_client(struct i2c_client *client) +{ + struct cpld_client_node *node = kzalloc(sizeof(struct cpld_client_node), GFP_KERNEL); + + if (!node) { + dev_dbg(&client->dev, "Can't allocate cpld_client_node (0x%x)\n", client->addr); + return; + } + + node->client = client; + + mutex_lock(&list_lock); + list_add(&node->list, &cpld_client_list); + mutex_unlock(&list_lock); +} + +static void board_i2c_cpld_remove_client(struct i2c_client *client) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int found = 0; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client == client) { + found = 1; + break; + } + } + + if (found) { + list_del(list_node); + kfree(cpld_node); + } + + mutex_unlock(&list_lock); +} + +static int board_i2c_cpld_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + int status; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_dbg(&client->dev, "i2c_check_functionality failed (0x%x)\n", client->addr); + status = -EIO; + goto exit; + } + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &cpld_attribute_group); + if (status) { + goto exit; + } + + dev_dbg(&client->dev, "chip found\n"); + board_i2c_cpld_add_client(client); + + return 0; + +exit: + return status; +} + +static int board_i2c_cpld_remove(struct i2c_client *client) +{ + sysfs_remove_group(&client->dev.kobj, &cpld_attribute_group); + board_i2c_cpld_remove_client(client); + + return 0; +} + +static const struct i2c_device_id board_i2c_cpld_id[] = { + { "i2c_cpld", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, board_i2c_cpld_id); + +static struct i2c_driver board_i2c_cpld_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "i2c_cpld", + }, + .probe = board_i2c_cpld_probe, + .remove = board_i2c_cpld_remove, + .id_table = board_i2c_cpld_id, + .address_list = normal_i2c, +}; + +static int __init board_i2c_cpld_init(void) +{ + mutex_init(&list_lock); + return i2c_add_driver(&board_i2c_cpld_driver); +} + +static void __exit board_i2c_cpld_exit(void) +{ + i2c_del_driver(&board_i2c_cpld_driver); +} + +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("board_i2c_cpld driver"); +MODULE_LICENSE("GPL"); + +module_init(board_i2c_cpld_init); +module_exit(board_i2c_cpld_exit); diff --git a/platform/pddf/i2c/modules/cpld/pddf_cpld_module.c b/platform/pddf/i2c/modules/cpld/pddf_cpld_module.c new file mode 100644 index 0000000000..af15e39026 --- /dev/null +++ b/platform/pddf/i2c/modules/cpld/pddf_cpld_module.c @@ -0,0 +1,219 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * + * A pddf kernel module to create I2C client for a CPLD + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pddf_client_defs.h" +#include "pddf_cpld_defs.h" + +PDDF_CPLD_DATA pddf_cpld_data={0}; +EXPORT_SYMBOL(pddf_cpld_data); + +static ssize_t do_device_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count); +static ssize_t store_pddf_cpld_data(struct device *dev, struct device_attribute *da, const char *buf, size_t count); +ssize_t show_pddf_cpld_data(struct device *dev, struct device_attribute *da, char *buf); + +extern void *get_device_table(char *name); +extern void delete_device_table(char *name); + + +/* MUX CLIENT DATA */ +PDDF_DATA_ATTR(dev_ops, S_IWUSR, NULL, do_device_operation, PDDF_CHAR, 8, NULL, (void*)&pddf_data); +PDDF_DATA_ATTR(reg_addr, S_IWUSR|S_IRUGO, show_pddf_cpld_data, store_pddf_cpld_data, PDDF_USHORT, sizeof(unsigned short), (void*)&pddf_cpld_data.reg_addr, NULL); + + + +static struct attribute *cpld_attributes[] = { + &attr_dev_ops.dev_attr.attr, + &attr_reg_addr.dev_attr.attr, + NULL +}; + +static const struct attribute_group pddf_cpld_client_data_group = { + .attrs = cpld_attributes, +}; + + +static ssize_t store_pddf_cpld_data(struct device *dev, struct device_attribute *da, const char *buf, size_t count) +{ + int ret = 0; + int num = 0; + PDDF_ATTR *ptr = (PDDF_ATTR *)da; + + ret = kstrtoint(buf,16,&num); + if (ret==0) + { + mutex_lock(&pddf_cpld_data.cpld_lock); + *(unsigned short *)(ptr->addr) = (unsigned short)num; + mutex_unlock(&pddf_cpld_data.cpld_lock); + pddf_dbg(CPLD, KERN_ERR "Stored value: 0x%x, num: 0x%x\n", *(int*)(ptr->addr), num); + } + + return count; +} +EXPORT_SYMBOL(store_pddf_cpld_data); + +ssize_t show_pddf_cpld_data(struct device *dev, struct device_attribute *da, char *buf) +{ + int ret = 0; + PDDF_ATTR *ptr = (PDDF_ATTR *)da; + pddf_dbg(CPLD, KERN_ERR "[ READ ] DATA ATTR PTR TYPE:%d, ADDR=%p\n", ptr->type, ptr->addr); + + mutex_lock(&pddf_cpld_data.cpld_lock); + ret = sprintf(buf, "0x%x\n", *(unsigned short *)(ptr->addr)); + mutex_unlock(&pddf_cpld_data.cpld_lock); + + return ret; +} +EXPORT_SYMBOL(show_pddf_cpld_data); + +static ssize_t do_device_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count) +{ + PDDF_ATTR *ptr = (PDDF_ATTR *)da; + NEW_DEV_ATTR *device_ptr = (NEW_DEV_ATTR *)(ptr->data); + struct i2c_adapter *adapter; + static struct i2c_board_info board_info; + struct i2c_client *client_ptr; + + if (strncmp(buf, "add", strlen(buf)-1)==0) + { + adapter = i2c_get_adapter(device_ptr->parent_bus); + + if (strncmp(device_ptr->dev_type, "i2c_cpld", strlen("i2c_cpld"))==0) + { + board_info = (struct i2c_board_info) { + .platform_data = (void *)NULL, + }; + + board_info.addr = device_ptr->dev_addr; + strcpy(board_info.type, device_ptr->dev_type); + + /*pddf_dbg(KERN_ERR "Creating a client %s on 0x%x, platform_data 0x%x\n", board_info.type, board_info.addr, board_info.platform_data);*/ + client_ptr = i2c_new_device(adapter, &board_info); + + if (client_ptr != NULL) { + i2c_put_adapter(adapter); + pddf_dbg(CPLD, KERN_ERR "Created %s client: 0x%p\n", device_ptr->i2c_name, (void *)client_ptr); + add_device_table(device_ptr->i2c_name, (void*)client_ptr); + } + else { + i2c_put_adapter(adapter); + goto free_data; + } + + } + else + { + printk(KERN_ERR "%s: Unsupported type of cpld - unable to add i2c client\n", __FUNCTION__); + } + } + else if (strncmp(buf, "delete", strlen(buf)-1)==0) + { + /*Get the i2c_client handle for the created client*/ + client_ptr = (struct i2c_client *)get_device_table(device_ptr->i2c_name); + if (client_ptr) + { + pddf_dbg(CPLD, KERN_ERR "Removing %s client: 0x%p\n", device_ptr->i2c_name, (void *)client_ptr); + i2c_unregister_device(client_ptr); + delete_device_table(device_ptr->i2c_name); + } + else + { + printk(KERN_ERR "Unable to get the client handle for %s\n", device_ptr->i2c_name); + } + } + else + { + printk(KERN_ERR "PDDF_ERROR: %s: Invalid value for dev_ops %s", __FUNCTION__, buf); + } + +free_data: + /*TODO: free the device_ptr->data is dynamically allocated*/ + memset(device_ptr, 0 , sizeof(NEW_DEV_ATTR)); + + return count; +} + + +static struct kobject *cpld_kobj; + +int __init cpld_data_init(void) +{ + struct kobject *device_kobj; + int ret = 0; + + + pddf_dbg(CPLD, "CPLD_DATA MODULE.. init\n"); + + device_kobj = get_device_i2c_kobj(); + if(!device_kobj) + return -ENOMEM; + + cpld_kobj = kobject_create_and_add("cpld", device_kobj); + if(!cpld_kobj) + return -ENOMEM; + + + ret = sysfs_create_group(cpld_kobj, &pddf_clients_data_group); + if (ret) + { + kobject_put(cpld_kobj); + return ret; + } + pddf_dbg(CPLD, "CREATED PDDF I2C CLIENTS CREATION SYSFS GROUP\n"); + + mutex_init(&pddf_cpld_data.cpld_lock); + + ret = sysfs_create_group(cpld_kobj, &pddf_cpld_client_data_group); + if (ret) + { + sysfs_remove_group(cpld_kobj, &pddf_clients_data_group); + kobject_put(cpld_kobj); + return ret; + } + pddf_dbg(CPLD, "CREATED PDDF I2C CLIENTS CREATION SYSFS GROUP\n"); + return ret; +} + +void __exit cpld_data_exit(void) +{ + pddf_dbg(CPLD, "CPLD_DATA MODULE.. exit\n"); + sysfs_remove_group(cpld_kobj, &pddf_cpld_client_data_group); + sysfs_remove_group(cpld_kobj, &pddf_clients_data_group); + kobject_put(cpld_kobj); + pddf_dbg(CPLD, KERN_ERR "%s: Removed the kobjects for 'cpld'\n",__FUNCTION__); + return; +} + +module_init(cpld_data_init); +module_exit(cpld_data_exit); + +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("cpld platform data"); +MODULE_LICENSE("GPL"); diff --git a/platform/pddf/i2c/modules/cpldmux/Makefile b/platform/pddf/i2c/modules/cpldmux/Makefile new file mode 100644 index 0000000000..53816b98f7 --- /dev/null +++ b/platform/pddf/i2c/modules/cpldmux/Makefile @@ -0,0 +1,4 @@ +subdir-m := driver +obj-m := pddf_cpldmux_module.o + +CFLAGS_$(obj-m):= -I$(M)/modules/include diff --git a/platform/pddf/i2c/modules/cpldmux/driver/Makefile b/platform/pddf/i2c/modules/cpldmux/driver/Makefile new file mode 100644 index 0000000000..2c6aa6e60e --- /dev/null +++ b/platform/pddf/i2c/modules/cpldmux/driver/Makefile @@ -0,0 +1,4 @@ +TARGET = pddf_cpldmux_driver +obj-m := $(TARGET).o + +ccflags-y := -I$(M)/modules/include diff --git a/platform/pddf/i2c/modules/cpldmux/driver/pddf_cpldmux_driver.c b/platform/pddf/i2c/modules/cpldmux/driver/pddf_cpldmux_driver.c new file mode 100755 index 0000000000..c9df1a60c1 --- /dev/null +++ b/platform/pddf/i2c/modules/cpldmux/driver/pddf_cpldmux_driver.c @@ -0,0 +1,209 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * A pddf kernel driver module for CPLDMUX + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "pddf_client_defs.h" +#include "pddf_cpldmux_defs.h" + +extern PDDF_CPLDMUX_DATA pddf_cpldmux_data; + +/* Users may overwrite these select and delsect functions as per their requirements + * by overwriting them in custom driver + */ +PDDF_CPLDMUX_OPS pddf_cpldmux_ops = { + .select = pddf_cpldmux_select_default, + .deselect = NULL, /* pddf_cpldmux_deselct_default */ +}; +EXPORT_SYMBOL(pddf_cpldmux_ops); + + +/* NOTE: Never use i2c_smbus_write_byte_data() or i2c_smbus_xfer() since these operations + * locks the parent bus which might lead to mutex deadlock. + */ +static int cpldmux_byte_write(struct i2c_client *client, u8 regaddr, u8 val) +{ + union i2c_smbus_data data; + + data.byte = val; + return client->adapter->algo->smbus_xfer(client->adapter, client->addr, + client->flags, + I2C_SMBUS_WRITE, + regaddr, I2C_SMBUS_BYTE_DATA, &data); +} + +int pddf_cpldmux_select_default(struct i2c_mux_core *muxc, uint32_t chan) +{ + PDDF_CPLDMUX_PRIV_DATA *private = i2c_mux_priv(muxc); + PDDF_CPLDMUX_PDATA *pdata = NULL; + PDDF_CPLDMUX_CHAN_DATA *sdata = NULL; + int ret = 0; + + /* Select the chan_data based upon the chan */ + pdata = &private->data; + if (chan>=pdata->num_chan) + { + printk(KERN_ERR "%s: wrong channel number %d, supported channels %d\n",__FUNCTION__, chan, pdata->num_chan); + return 0; + } + + if ( (pdata->chan_cache!=1) || (private->last_chan!=chan) ) + { + sdata = &pdata->chan_data[chan]; + pddf_dbg(CPLDMUX, KERN_ERR "%s: Writing 0x%x at 0x%x offset of cpld 0x%x to enable chan %d\n", __FUNCTION__, sdata->cpld_sel, sdata->cpld_offset, sdata->cpld_devaddr, chan); + ret = cpldmux_byte_write(pdata->cpld, sdata->cpld_offset, (uint8_t)(sdata->cpld_sel & 0xff)); + private->last_chan = chan; + } + + return ret; +} + +int pddf_cpldmux_deselect_default(struct i2c_mux_core *muxc, uint32_t chan) +{ + PDDF_CPLDMUX_PRIV_DATA *private = i2c_mux_priv(muxc); + PDDF_CPLDMUX_PDATA *pdata = NULL; + PDDF_CPLDMUX_CHAN_DATA *sdata = NULL; + int ret = 0; + + /* Select the chan_data based upon the chan */ + pdata = &private->data; + if (chan>=pdata->num_chan) + { + printk(KERN_ERR "%s: wrong channel number %d, supported channels %d\n",__FUNCTION__, chan, pdata->num_chan); + return 0; + } + sdata = &pdata->chan_data[chan]; + + pddf_dbg(CPLDMUX, KERN_ERR "%s: Writing 0x%x at 0x%x offset of cpld 0x%x to disable chan %d", __FUNCTION__, sdata->cpld_desel, sdata->cpld_offset, sdata->cpld_devaddr, chan); + ret = cpldmux_byte_write(pdata->cpld, sdata->cpld_offset, (uint8_t)(sdata->cpld_desel)); + return ret; +} + +static int cpld_mux_probe(struct platform_device *pdev) +{ + struct i2c_mux_core *muxc; + PDDF_CPLDMUX_PRIV_DATA *private; + PDDF_CPLDMUX_PDATA *pdata; + struct i2c_adapter *adap; + int i, ret, ndev; + + pdata = pdev->dev.platform_data; + if (!pdata) { + dev_err(&pdev->dev, "CPLDMUX platform data not found\n"); + return -ENODEV; + } + private = (PDDF_CPLDMUX_PRIV_DATA *)kzalloc(sizeof(PDDF_CPLDMUX_PRIV_DATA) , GFP_KERNEL); + if (!private) { + printk(KERN_ERR "Failed to allocate memory for priv data\n"); + return -ENOMEM; + } + + private->last_chan = 0xff; /*Giving imaginary high value so that proper channel is selected at first iteration*/ + memcpy(&private->data, pdata, sizeof(PDDF_CPLDMUX_PDATA)); + + adap = i2c_get_adapter(pdata->parent_bus); + if (!adap) { + kfree(private); + dev_err(&pdev->dev, "Parent adapter (%d) not found\n", pdata->parent_bus); + return -ENODEV; + } + ndev = pdata->num_chan; + + muxc = i2c_mux_alloc(adap, &pdev->dev, ndev, 0, 0, pddf_cpldmux_ops.select, pddf_cpldmux_ops.deselect); + if (!muxc) { + ret = -ENOMEM; + goto alloc_failed; + } + muxc->priv = private; + platform_set_drvdata(pdev, muxc); + + for (i = 0; i < ndev; i++) + { + int nr = pdata->base_chan + i; + unsigned int class = 0; + ret = i2c_mux_add_adapter(muxc, nr, i, class); + if (ret) { + dev_err(&pdev->dev, "Failed to add adapter %d\n", i); + goto add_adapter_failed; + } + } + dev_info(&pdev->dev, "%d port mux on %s adapter\n", ndev, adap->name); + return 0; + +add_adapter_failed: + i2c_mux_del_adapters(muxc); +alloc_failed: + kfree(private); + i2c_put_adapter(adap); + return ret; +} + +static int cpld_mux_remove(struct platform_device *pdev) +{ + struct i2c_mux_core *muxc = platform_get_drvdata(pdev); + struct i2c_adapter *adap = muxc->parent; + PDDF_CPLDMUX_PDATA *cpldmux_pdata = pdev->dev.platform_data; + + i2c_mux_del_adapters(muxc); + if (muxc->priv) + kfree(muxc->priv); + i2c_put_adapter(adap); + + if (cpldmux_pdata) { + pddf_dbg(CPLDMUX, KERN_DEBUG "%s: Freeing cpldmux platform data\n", __FUNCTION__); + kfree(cpldmux_pdata); + } + + return 0; +} + +static struct platform_driver cpld_mux_driver = { + .probe = cpld_mux_probe, + .remove = cpld_mux_remove, /* TODO */ + .driver = { + .owner = THIS_MODULE, + .name = "cpld_mux", + }, +}; + +static int __init board_i2c_cpldmux_init(void) +{ + int ret; + ret = platform_driver_register(&cpld_mux_driver); + if (ret) { + printk(KERN_WARNING "Fail to register swpld mux driver\n"); + } + return (ret); +} + +static void __exit board_i2c_cpldmux_exit(void) +{ + platform_driver_unregister(&cpld_mux_driver); +} + +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("board_i2c_cpldmux driver"); +MODULE_LICENSE("GPL"); + +module_init(board_i2c_cpldmux_init); +module_exit(board_i2c_cpldmux_exit); diff --git a/platform/pddf/i2c/modules/cpldmux/pddf_cpldmux_module.c b/platform/pddf/i2c/modules/cpldmux/pddf_cpldmux_module.c new file mode 100644 index 0000000000..f99def3158 --- /dev/null +++ b/platform/pddf/i2c/modules/cpldmux/pddf_cpldmux_module.c @@ -0,0 +1,254 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * + * PDDF generic module for cpldmux device + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pddf_client_defs.h" +#include "pddf_cpldmux_defs.h" + +PDDF_CPLDMUX_DATA pddf_cpldmux_data={0}; +PDDF_CPLDMUX_CHAN_DATA pddf_cpldmux_chan_data={0}; +EXPORT_SYMBOL(pddf_cpldmux_data); + +static ssize_t do_device_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count); +static ssize_t do_chan_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count); + +extern void *get_device_table(char *name); +extern void delete_device_table(char *name); + + +/* CPLDMUX CLIENT DATA */ +PDDF_DATA_ATTR(dev_ops, S_IWUSR, NULL, do_device_operation, PDDF_CHAR, 8, (void*)&pddf_cpldmux_data, (void*)&pddf_data); +PDDF_DATA_ATTR(chan_ops, S_IWUSR, NULL, do_chan_operation, PDDF_CHAR, 8, (void*)&pddf_cpldmux_data, NULL); +PDDF_DATA_ATTR(base_chan, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_HEX, sizeof(int), (void*)&pddf_cpldmux_data.base_chan, NULL); +PDDF_DATA_ATTR(num_chan, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_DEC, sizeof(int), (void*)&pddf_cpldmux_data.num_chan, NULL); +PDDF_DATA_ATTR(chan_cache, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_DEC, sizeof(int), (void*)&pddf_cpldmux_data.chan_cache, NULL); +PDDF_DATA_ATTR(cpld_name, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_CHAR, 32, (void*)&pddf_cpldmux_data.cpld_name, NULL); +PDDF_DATA_ATTR(chan, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_DEC, sizeof(int), (void*)&pddf_cpldmux_chan_data.chan_num, NULL); +PDDF_DATA_ATTR(dev, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_CHAR, 128, (void*)&pddf_cpldmux_chan_data.chan_device, NULL); +PDDF_DATA_ATTR(cpld_devaddr, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_HEX, sizeof(int), (void*)&pddf_cpldmux_chan_data.cpld_devaddr, NULL); +PDDF_DATA_ATTR(cpld_offset, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_HEX, sizeof(int), (void*)&pddf_cpldmux_chan_data.cpld_offset, NULL); +PDDF_DATA_ATTR(cpld_sel, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_HEX, sizeof(int), (void*)&pddf_cpldmux_chan_data.cpld_sel, NULL); +PDDF_DATA_ATTR(cpld_desel, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_HEX, sizeof(int), (void*)&pddf_cpldmux_chan_data.cpld_desel, NULL); + + +static struct attribute *cpldmux_attributes[] = { + &attr_dev_ops.dev_attr.attr, + &attr_chan_ops.dev_attr.attr, + &attr_base_chan.dev_attr.attr, + &attr_num_chan.dev_attr.attr, + &attr_chan_cache.dev_attr.attr, + &attr_cpld_name.dev_attr.attr, + &attr_chan.dev_attr.attr, + &attr_dev.dev_attr.attr, + &attr_cpld_devaddr.dev_attr.attr, + &attr_cpld_offset.dev_attr.attr, + &attr_cpld_sel.dev_attr.attr, + &attr_cpld_desel.dev_attr.attr, + NULL +}; + +static const struct attribute_group pddf_cpldmux_client_data_group = { + .attrs = cpldmux_attributes, +}; + + + +static ssize_t do_chan_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count) +{ + PDDF_ATTR *ptr = (PDDF_ATTR *)da; + PDDF_CPLDMUX_DATA *cpldmux_data = (PDDF_CPLDMUX_DATA *)(ptr->addr); + int index; + + pddf_dbg(CPLDMUX, KERN_ERR "%s: Adding channel %d\n", __FUNCTION__, pddf_cpldmux_chan_data.chan_num); + index = pddf_cpldmux_chan_data.chan_num; + cpldmux_data->chan_data[index] = pddf_cpldmux_chan_data; + + memset(&pddf_cpldmux_chan_data, 0, sizeof(pddf_cpldmux_chan_data)); + + + return count; +} + +static ssize_t do_device_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count) +{ + PDDF_ATTR *ptr = (PDDF_ATTR *)da; + NEW_DEV_ATTR *device_ptr = (NEW_DEV_ATTR *)(ptr->data); + PDDF_CPLDMUX_DATA *cpldmux_data = (PDDF_CPLDMUX_DATA *)(ptr->addr); + PDDF_CPLDMUX_PDATA *cpldmux_platform_data = NULL; + struct platform_device *plat_dev = NULL; + struct i2c_client *client_ptr = NULL; + int ret=0, i=0; + + if (strncmp(buf, "add", strlen(buf)-1)==0) + { + if (strncmp(device_ptr->dev_type, "cpld_mux", strlen("cpld_mux"))==0) + { + /*Get the i2c_client handle for the CPLD which drives this cpldmux*/ + client_ptr = (struct i2c_client *)get_device_table(cpldmux_data->cpld_name); + if (client_ptr==NULL) + { + pddf_dbg(CPLDMUX, KERN_ERR "Unable to get the CPLD client %s for %s cpldmux\n", cpldmux_data->cpld_name, device_ptr->i2c_name); + printk(KERN_ERR "Unable to get the CPLD client %s for %s cpldmux\n", cpldmux_data->cpld_name, device_ptr->i2c_name); + goto clear_data; + } + + /* Allocate the cpldmux_platform_data */ + cpldmux_platform_data = (PDDF_CPLDMUX_PDATA *)kzalloc( sizeof(PDDF_CPLDMUX_PDATA) + cpldmux_data->num_chan*sizeof(PDDF_CPLDMUX_CHAN_DATA), GFP_KERNEL ); + cpldmux_platform_data->chan_data = (PDDF_CPLDMUX_CHAN_DATA *)(cpldmux_platform_data+1); + + cpldmux_platform_data->parent_bus = device_ptr->parent_bus; + cpldmux_platform_data->base_chan = cpldmux_data->base_chan; + cpldmux_platform_data->num_chan = cpldmux_data->num_chan; + cpldmux_platform_data->chan_cache = cpldmux_data->chan_cache; + cpldmux_platform_data->cpld = client_ptr; + for (i=0; inum_chan; i++) + { + cpldmux_platform_data->chan_data[i] = cpldmux_data->chan_data[i]; + } + + plat_dev = platform_device_alloc(device_ptr->dev_type, device_ptr->dev_id); + + plat_dev->dev.platform_data = cpldmux_platform_data; + + pddf_dbg(CPLDMUX, KERN_ERR "Creating a %s platform_device 0x%p, platform_data 0x%p\n", plat_dev->name, (void *)plat_dev, (void *)cpldmux_platform_data); + ret = platform_device_add(plat_dev); + if (ret) + { + pddf_dbg(CPLDMUX, KERN_ERR "Unable to create cpld_mux (%s) device: Error %d\n", device_ptr->i2c_name, ret); + goto free_data; + } + else + { + add_device_table(device_ptr->i2c_name, (void *)plat_dev); + } + + } + else + { + printk(KERN_ERR "%s: Unsupported type of cpldmux - unable to add i2c client\n", __FUNCTION__); + } + } + else if (strncmp(buf, "delete", strlen(buf)-1)==0) + { + /*Get the i2c_client handle for the created client*/ + plat_dev = (struct platform_device *)get_device_table(device_ptr->i2c_name); + if (plat_dev) + { + pddf_dbg(CPLDMUX, KERN_ERR "Removing %s device: 0x%p\n", device_ptr->i2c_name, (void *)plat_dev); + pddf_dbg(CPLDMUX, KERN_ERR "Freeing the memory held by device: 0x%p\n", (void *)plat_dev); + platform_device_del(plat_dev); + delete_device_table(device_ptr->i2c_name); + } + else + { + printk(KERN_ERR "Unable to get the client handle for %s\n", device_ptr->i2c_name); + } + } + else + { + printk(KERN_ERR "PDDF_ERROR: %s: Invalid value for dev_ops %s", __FUNCTION__, buf); + } + goto clear_data; + +free_data: + /* Free the allocated memory for platform and channel data */ + cpldmux_platform_data = plat_dev->dev.platform_data; + if (cpldmux_platform_data) + { + printk(KERN_ERR "%s: Unable to register a cpldmux device. Freeing the platform data\n", __FUNCTION__); + kfree(cpldmux_platform_data); + } + + /* Put the platform device structure */ + platform_device_put(plat_dev); +clear_data: + memset(cpldmux_data, 0, sizeof(PDDF_CPLDMUX_DATA)); + /*TODO: free the data device_ptr->data if data is dynamically allocated*/ + memset(device_ptr, 0, sizeof(NEW_DEV_ATTR)); + return count; +} + + +static struct kobject *cpldmux_kobj; + +int __init cpldmux_data_init(void) +{ + struct kobject *device_kobj; + int ret = 0; + + + pddf_dbg(CPLDMUX, "CPLDMUX_DATA MODULE.. init\n"); + + device_kobj = get_device_i2c_kobj(); + if(!device_kobj) + return -ENOMEM; + + cpldmux_kobj = kobject_create_and_add("cpldmux", device_kobj); + if(!cpldmux_kobj) + return -ENOMEM; + + + ret = sysfs_create_group(cpldmux_kobj, &pddf_clients_data_group); + if (ret) + { + kobject_put(cpldmux_kobj); + return ret; + } + pddf_dbg(CPLDMUX, "CREATED PDDF I2C CLIENTS CREATION SYSFS GROUP\n"); + + + ret = sysfs_create_group(cpldmux_kobj, &pddf_cpldmux_client_data_group); + if (ret) + { + sysfs_remove_group(cpldmux_kobj, &pddf_clients_data_group); + kobject_put(cpldmux_kobj); + return ret; + } + pddf_dbg(CPLDMUX, "CREATED PDDF I2C CLIENTS CREATION SYSFS GROUP\n"); + return ret; +} + +void __exit cpldmux_data_exit(void) +{ + pddf_dbg(CPLDMUX, "CPLDMUX_DATA MODULE.. exit\n"); + sysfs_remove_group(cpldmux_kobj, &pddf_cpldmux_client_data_group); + sysfs_remove_group(cpldmux_kobj, &pddf_clients_data_group); + kobject_put(cpldmux_kobj); + pddf_dbg(CPLDMUX, KERN_ERR "%s: Removed the kobjects for 'cpldmux'\n",__FUNCTION__); + return; +} + +module_init(cpldmux_data_init); +module_exit(cpldmux_data_exit); + +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("cpldmux platform data"); +MODULE_LICENSE("GPL"); diff --git a/platform/pddf/i2c/modules/fan/Makefile b/platform/pddf/i2c/modules/fan/Makefile new file mode 100644 index 0000000000..94b6b146c5 --- /dev/null +++ b/platform/pddf/i2c/modules/fan/Makefile @@ -0,0 +1,4 @@ +subdir-m := driver +obj-m := pddf_fan_module.o + +CFLAGS_$(obj-m):= -I$(M)/modules/include diff --git a/platform/pddf/i2c/modules/fan/driver/Makefile b/platform/pddf/i2c/modules/fan/driver/Makefile new file mode 100644 index 0000000000..c94f217d3b --- /dev/null +++ b/platform/pddf/i2c/modules/fan/driver/Makefile @@ -0,0 +1,6 @@ +TARGET := pddf_fan_driver_module +obj-m := $(TARGET).o + +$(TARGET)-objs := pddf_fan_api.o pddf_fan_driver.o + +ccflags-y := -I$(M)/modules/include diff --git a/platform/pddf/i2c/modules/fan/driver/pddf_fan_api.c b/platform/pddf/i2c/modules/fan/driver/pddf_fan_api.c new file mode 100644 index 0000000000..167b0e1833 --- /dev/null +++ b/platform/pddf/i2c/modules/fan/driver/pddf_fan_api.c @@ -0,0 +1,526 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * + * Description of various APIs related to FAN component + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pddf_fan_defs.h" +#include "pddf_fan_driver.h" + +/*#define FAN_DEBUG*/ +#ifdef FAN_DEBUG +#define fan_dbg(...) printk(__VA_ARGS__) +#else +#define fan_dbg(...) +#endif + +extern void *get_device_table(char *name); + +void get_fan_duplicate_sysfs(int idx, char *str) +{ + switch (idx) + { + default: + break; + } + + return; +} + + +int fan_update_hw(struct device *dev, struct fan_attr_info *info, FAN_DATA_ATTR *udata) +{ + int status = 0; + struct i2c_client *client = to_i2c_client(dev); + FAN_SYSFS_ATTR_DATA *sysfs_attr_data = NULL; + + + mutex_lock(&info->update_lock); + + sysfs_attr_data = udata->access_data; + if (sysfs_attr_data->pre_set != NULL) + { + status = (sysfs_attr_data->pre_set)(client, udata, info); + if (status!=0) + printk(KERN_ERR "%s: pre_set function fails for %s attribute\n", __FUNCTION__, udata->aname); + } + if (sysfs_attr_data->do_set != NULL) + { + status = (sysfs_attr_data->do_set)(client, udata, info); + if (status!=0) + printk(KERN_ERR "%s: do_set function fails for %s attribute\n", __FUNCTION__, udata->aname); + + } + if (sysfs_attr_data->post_set != NULL) + { + status = (sysfs_attr_data->post_set)(client, udata, info); + if (status!=0) + printk(KERN_ERR "%s: post_set function fails for %s attribute\n", __FUNCTION__, udata->aname); + } + + mutex_unlock(&info->update_lock); + + return 0; +} + +int fan_update_attr(struct device *dev, struct fan_attr_info *info, FAN_DATA_ATTR *udata) +{ + int status = 0; + struct i2c_client *client = to_i2c_client(dev); + FAN_SYSFS_ATTR_DATA *sysfs_attr_data = NULL; + + + mutex_lock(&info->update_lock); + + if (time_after(jiffies, info->last_updated + HZ + HZ / 2) || !info->valid) + { + dev_dbg(&client->dev, "Starting pddf_fan update\n"); + info->valid = 0; + + sysfs_attr_data = udata->access_data; + if (sysfs_attr_data->pre_get != NULL) + { + status = (sysfs_attr_data->pre_get)(client, udata, info); + if (status!=0) + printk(KERN_ERR "%s: pre_get function fails for %s attribute\n", __FUNCTION__, udata->aname); + } + if (sysfs_attr_data->do_get != NULL) + { + status = (sysfs_attr_data->do_get)(client, udata, info); + if (status!=0) + printk(KERN_ERR "%s: do_get function fails for %s attribute\n", __FUNCTION__, udata->aname); + + } + if (sysfs_attr_data->post_get != NULL) + { + status = (sysfs_attr_data->post_get)(client, udata, info); + if (status!=0) + printk(KERN_ERR "%s: post_get function fails for %s attribute\n", __FUNCTION__, udata->aname); + } + + + info->last_updated = jiffies; + info->valid = 1; + } + + mutex_unlock(&info->update_lock); + + return 0; +} + +ssize_t fan_show_default(struct device *dev, struct device_attribute *da, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct fan_data *data = i2c_get_clientdata(client); + FAN_PDATA *pdata = (FAN_PDATA *)(client->dev.platform_data); + FAN_DATA_ATTR *usr_data = NULL; + struct fan_attr_info *attr_info = NULL; + int i, status=0; + char new_str[ATTR_NAME_LEN] = ""; + FAN_SYSFS_ATTR_DATA *ptr = NULL; + + for (i=0;inum_attr;i++) + { + ptr = (FAN_SYSFS_ATTR_DATA *)pdata->fan_attrs[i].access_data; + get_fan_duplicate_sysfs(ptr->index , new_str); + if (strcmp(attr->dev_attr.attr.name, pdata->fan_attrs[i].aname) == 0 || strcmp(attr->dev_attr.attr.name, new_str) == 0) + { + attr_info = &data->attr_info[i]; + usr_data = &pdata->fan_attrs[i]; + strcpy(new_str, ""); + } + } + + if (attr_info==NULL || usr_data==NULL) + { + printk(KERN_ERR "%s is not supported attribute for this client\n", usr_data->aname); + goto exit; + } + + fan_update_attr(dev, attr_info, usr_data); + + /*Decide the o/p based on attribute type */ + switch(attr->index) + { + case FAN1_PRESENT: + case FAN2_PRESENT: + case FAN3_PRESENT: + case FAN4_PRESENT: + case FAN5_PRESENT: + case FAN6_PRESENT: + case FAN7_PRESENT: + case FAN8_PRESENT: + case FAN9_PRESENT: + case FAN10_PRESENT: + case FAN11_PRESENT: + case FAN12_PRESENT: + case FAN1_DIRECTION: + case FAN2_DIRECTION: + case FAN3_DIRECTION: + case FAN4_DIRECTION: + case FAN5_DIRECTION: + case FAN6_DIRECTION: + case FAN7_DIRECTION: + case FAN8_DIRECTION: + case FAN9_DIRECTION: + case FAN10_DIRECTION: + case FAN11_DIRECTION: + case FAN12_DIRECTION: + case FAN1_INPUT: + case FAN2_INPUT: + case FAN3_INPUT: + case FAN4_INPUT: + case FAN5_INPUT: + case FAN6_INPUT: + case FAN7_INPUT: + case FAN8_INPUT: + case FAN9_INPUT: + case FAN10_INPUT: + case FAN11_INPUT: + case FAN12_INPUT: + case FAN1_PWM: + case FAN2_PWM: + case FAN3_PWM: + case FAN4_PWM: + case FAN5_PWM: + case FAN6_PWM: + case FAN7_PWM: + case FAN8_PWM: + case FAN9_PWM: + case FAN10_PWM: + case FAN11_PWM: + case FAN12_PWM: + case FAN1_FAULT: + case FAN2_FAULT: + case FAN3_FAULT: + case FAN4_FAULT: + case FAN5_FAULT: + case FAN6_FAULT: + case FAN7_FAULT: + case FAN8_FAULT: + case FAN9_FAULT: + case FAN10_FAULT: + case FAN11_FAULT: + case FAN12_FAULT: + status = attr_info->val.intval; + break; + default: + fan_dbg(KERN_ERR "%s: Unable to find the attribute index for %s\n", __FUNCTION__, usr_data->aname); + status = 0; + } + +exit: + return sprintf(buf, "%d\n", status); +} + + +ssize_t fan_store_default(struct device *dev, struct device_attribute *da, const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct fan_data *data = i2c_get_clientdata(client); + FAN_PDATA *pdata = (FAN_PDATA *)(client->dev.platform_data); + FAN_DATA_ATTR *usr_data = NULL; + struct fan_attr_info *attr_info = NULL; + int i, ret ; + uint32_t val; + + for (i=0;inum_attr;i++) + { + if (strcmp(data->attr_info[i].name, attr->dev_attr.attr.name) == 0 && strcmp(pdata->fan_attrs[i].aname, attr->dev_attr.attr.name) == 0) + { + attr_info = &data->attr_info[i]; + usr_data = &pdata->fan_attrs[i]; + } + } + + if (attr_info==NULL || usr_data==NULL) { + printk(KERN_ERR "%s is not supported attribute for this client\n", attr->dev_attr.attr.name); + goto exit; + } + + switch(attr->index) + { + case FAN1_PWM: + case FAN2_PWM: + case FAN3_PWM: + case FAN4_PWM: + case FAN5_PWM: + case FAN6_PWM: + case FAN7_PWM: + case FAN8_PWM: + case FAN9_PWM: + case FAN10_PWM: + case FAN11_PWM: + case FAN12_PWM: + ret = kstrtoint(buf, 10, &val); + if (ret) + { + printk(KERN_ERR "%s: Unable to convert string into value for %s\n", __FUNCTION__, usr_data->aname); + return ret; + } + /*Update the value of attr_info here, and use it to update the HW values*/ + attr_info->val.intval = val; + break; + default: + printk(KERN_ERR "%s: Unable to find the attr index for %s\n", __FUNCTION__, usr_data->aname); + goto exit; + } + + fan_dbg(KERN_ERR "%s: pwm to be set is %d\n", __FUNCTION__, val); + fan_update_hw(dev, attr_info, usr_data); + +exit: + return count; +} + +int fan_cpld_client_read(FAN_DATA_ATTR *udata) +{ + int status = -1; + + if (udata!=NULL) + { + if (udata->len==1) + { + status = board_i2c_cpld_read(udata->devaddr , udata->offset); + } + else + { + /* Get the I2C client for the CPLD */ + struct i2c_client *client_ptr=NULL; + client_ptr = (struct i2c_client *)get_device_table(udata->devname); + if (client_ptr) + { + if (udata->len==2) + { + status = i2c_smbus_read_word_swapped(client_ptr, udata->offset); + } + else + printk(KERN_ERR "PDDF_FAN: Doesn't support block CPLD read yet"); + } + else + printk(KERN_ERR "Unable to get the client handle for %s\n", udata->devname); + } + + } + + return status; +} + + +int sonic_i2c_get_fan_present_default(void *client, FAN_DATA_ATTR *udata, void *info) +{ + int status = 0; + int val = 0; + struct fan_attr_info *painfo = (struct fan_attr_info *)info; + + if (strcmp(udata->devtype, "cpld") == 0) + { + val = fan_cpld_client_read(udata); + } + else + { + val = i2c_smbus_read_byte_data((struct i2c_client *)client, udata->offset); + } + + painfo->val.intval = ((val & udata->mask) == udata->cmpval); + + + return status; +} + +int sonic_i2c_get_fan_rpm_default(void *client, FAN_DATA_ATTR *udata, void *info) +{ + int status = 0; + uint32_t val = 0; + struct fan_attr_info *painfo = (struct fan_attr_info *)info; + + if (strcmp(udata->devtype, "cpld") == 0) + { + val = fan_cpld_client_read(udata); + } + else + { + if (udata->len == 1) + { + val = i2c_smbus_read_byte_data((struct i2c_client *)client, udata->offset); + } + else if (udata->len ==2) + { + val = i2c_smbus_read_word_swapped((struct i2c_client *)client, udata->offset); + + } + } + + if (udata->is_divisor) + painfo->val.intval = udata->mult / (val >> 3); + else + painfo->val.intval = udata->mult * val; + + return status; +} + + +int sonic_i2c_get_fan_direction_default(void *client, FAN_DATA_ATTR *udata, void *info) +{ + int status = 0; + uint32_t val = 0; + struct fan_attr_info *painfo = (struct fan_attr_info *)info; + + if (strcmp(udata->devtype, "cpld") == 0) + { + val = fan_cpld_client_read(udata); + } + else + { + val = i2c_smbus_read_byte_data((struct i2c_client *)client, udata->offset); + } + painfo->val.intval = ((val & udata->mask) == udata->cmpval); + + return status; +} + + +int sonic_i2c_set_fan_pwm_default(struct i2c_client *client, FAN_DATA_ATTR *udata, void *info) +{ + int status = 0; + uint32_t val = 0; + struct fan_attr_info *painfo = (struct fan_attr_info *)info; + + val = painfo->val.intval & udata->mask; + + if (val > 255) + { + return -EINVAL; + } + + if (strcmp(udata->devtype, "cpld") == 0) + { + if (udata->len==1) + { + status = board_i2c_cpld_write(udata->devaddr , udata->offset, val); + } + else + { + /* Get the I2C client for the CPLD */ + struct i2c_client *client_ptr=NULL; + client_ptr = (struct i2c_client *)get_device_table(udata->devname); + if (client_ptr) + { + if (udata->len==2) + { + uint8_t val_lsb = val & 0xFF; + uint8_t val_hsb = (val >> 8) & 0xFF; + /* TODO: Check this logic for LE and BE */ + i2c_smbus_write_byte_data(client, udata->offset, val_lsb); + i2c_smbus_write_byte_data(client, udata->offset+1, val_hsb); + } + else + printk(KERN_ERR "PDDF_FAN: Doesn't support block CPLD write yet"); + } + else + printk(KERN_ERR "Unable to get the client handle for %s\n", udata->devname); + } + + } + else + { + if (udata->len == 1) + i2c_smbus_write_byte_data(client, udata->offset, val); + else if (udata->len == 2) + { + uint8_t val_lsb = val & 0xFF; + uint8_t val_hsb = (val >> 8) & 0xFF; + /* TODO: Check this logic for LE and BE */ + i2c_smbus_write_byte_data(client, udata->offset, val_lsb); + i2c_smbus_write_byte_data(client, udata->offset+1, val_hsb); + } + else + { + printk(KERN_DEBUG "%s: pwm should be of len 1/2 bytes. Not setting the pwm as the length is %d\n", __FUNCTION__, udata->len); + } + } + + return status; +} + + +int sonic_i2c_get_fan_pwm_default(void *client, FAN_DATA_ATTR *udata, void *info) +{ + int status = 0; + uint32_t val = 0; + struct fan_attr_info *painfo = (struct fan_attr_info *)info; + + if (strcmp(udata->devtype, "cpld") == 0) + { + val = fan_cpld_client_read(udata); + } + else + { + if (udata->len == 1) + { + val = i2c_smbus_read_byte_data((struct i2c_client *)client, udata->offset); + } + else if (udata->len ==2) + { + val = i2c_smbus_read_word_swapped((struct i2c_client *)client, udata->offset); + + } + } + + val = val & udata->mask; + painfo->val.intval = val; + return status; +} + +int sonic_i2c_get_fan_fault_default(void *client, FAN_DATA_ATTR *udata, void *info) +{ + int status = 0; + uint32_t val = 0; + struct fan_attr_info *painfo = (struct fan_attr_info *)info; + + /*Assuming fan fault to be denoted by 1 byte only*/ + if (strcmp(udata->devtype, "cpld") == 0) + { + val = fan_cpld_client_read(udata); + } + else + { + val = i2c_smbus_read_byte_data((struct i2c_client *)client, udata->offset); + } + + val = val & udata->mask; + painfo->val.intval = val; + return status; +} + + +int pddf_fan_post_probe_default(struct i2c_client *client, const struct i2c_device_id *dev_id) +{ + + /*Dummy func for now - check the respective platform modules*/ + return 0; +} diff --git a/platform/pddf/i2c/modules/fan/driver/pddf_fan_driver.c b/platform/pddf/i2c/modules/fan/driver/pddf_fan_driver.c new file mode 100644 index 0000000000..da8275fccd --- /dev/null +++ b/platform/pddf/i2c/modules/fan/driver/pddf_fan_driver.c @@ -0,0 +1,496 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * + * A pddf kernel driver module for a FAN controller + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pddf_client_defs.h" +#include "pddf_fan_defs.h" +#include "pddf_fan_driver.h" +#include "pddf_fan_api.h" + +#define DRVNAME "pddf_fan" + +struct pddf_ops_t pddf_fan_ops = { + .pre_init = NULL, + .post_init = NULL, + + .pre_probe = NULL, + .post_probe = pddf_fan_post_probe_default, + + .pre_remove = NULL, + .post_remove = NULL, + + .pre_exit = NULL, + .post_exit = NULL, +}; +EXPORT_SYMBOL(pddf_fan_ops); + + + +FAN_SYSFS_ATTR_DATA data_fan1_present = {FAN1_PRESENT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_present_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan1_present); +FAN_SYSFS_ATTR_DATA data_fan2_present = {FAN2_PRESENT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_present_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan2_present); +FAN_SYSFS_ATTR_DATA data_fan3_present = {FAN3_PRESENT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_present_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan3_present); +FAN_SYSFS_ATTR_DATA data_fan4_present = {FAN4_PRESENT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_present_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan4_present); +FAN_SYSFS_ATTR_DATA data_fan5_present = {FAN5_PRESENT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_present_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan5_present); +FAN_SYSFS_ATTR_DATA data_fan6_present = {FAN6_PRESENT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_present_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan6_present); +FAN_SYSFS_ATTR_DATA data_fan7_present = {FAN7_PRESENT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_present_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan7_present); +FAN_SYSFS_ATTR_DATA data_fan8_present = {FAN8_PRESENT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_present_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan8_present); +FAN_SYSFS_ATTR_DATA data_fan9_present = {FAN9_PRESENT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_present_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan9_present); +FAN_SYSFS_ATTR_DATA data_fan10_present = {FAN10_PRESENT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_present_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan10_present); +FAN_SYSFS_ATTR_DATA data_fan11_present = {FAN11_PRESENT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_present_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan11_present); +FAN_SYSFS_ATTR_DATA data_fan12_present = {FAN12_PRESENT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_present_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan12_present); + + +FAN_SYSFS_ATTR_DATA data_fan1_direction = {FAN1_DIRECTION, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_direction_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan1_direction); +FAN_SYSFS_ATTR_DATA data_fan2_direction = {FAN2_DIRECTION, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_direction_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan2_direction); +FAN_SYSFS_ATTR_DATA data_fan3_direction = {FAN3_DIRECTION, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_direction_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan3_direction); +FAN_SYSFS_ATTR_DATA data_fan4_direction = {FAN4_DIRECTION, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_direction_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan4_direction); +FAN_SYSFS_ATTR_DATA data_fan5_direction = {FAN5_DIRECTION, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_direction_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan5_direction); +FAN_SYSFS_ATTR_DATA data_fan6_direction = {FAN6_DIRECTION, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_direction_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan6_direction); +FAN_SYSFS_ATTR_DATA data_fan7_direction = {FAN7_DIRECTION, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_direction_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan7_direction); +FAN_SYSFS_ATTR_DATA data_fan8_direction = {FAN8_DIRECTION, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_direction_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan8_direction); +FAN_SYSFS_ATTR_DATA data_fan9_direction = {FAN9_DIRECTION, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_direction_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan9_direction); +FAN_SYSFS_ATTR_DATA data_fan10_direction = {FAN10_DIRECTION, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_direction_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan10_direction); +FAN_SYSFS_ATTR_DATA data_fan11_direction = {FAN11_DIRECTION, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_direction_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan11_direction); +FAN_SYSFS_ATTR_DATA data_fan12_direction = {FAN12_DIRECTION, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_direction_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan12_direction); + + +FAN_SYSFS_ATTR_DATA data_fan1_input = {FAN1_INPUT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_rpm_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan1_input); +FAN_SYSFS_ATTR_DATA data_fan2_input = {FAN2_INPUT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_rpm_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan2_input); +FAN_SYSFS_ATTR_DATA data_fan3_input = {FAN3_INPUT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_rpm_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan3_input); +FAN_SYSFS_ATTR_DATA data_fan4_input = {FAN4_INPUT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_rpm_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan4_input); +FAN_SYSFS_ATTR_DATA data_fan5_input = {FAN5_INPUT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_rpm_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan5_input); +FAN_SYSFS_ATTR_DATA data_fan6_input = {FAN6_INPUT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_rpm_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan6_input); +FAN_SYSFS_ATTR_DATA data_fan7_input = {FAN7_INPUT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_rpm_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan7_input); +FAN_SYSFS_ATTR_DATA data_fan8_input = {FAN8_INPUT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_rpm_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan8_input); +FAN_SYSFS_ATTR_DATA data_fan9_input = {FAN9_INPUT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_rpm_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan9_input); +FAN_SYSFS_ATTR_DATA data_fan10_input = {FAN10_INPUT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_rpm_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan10_input); +FAN_SYSFS_ATTR_DATA data_fan11_input = {FAN11_INPUT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_rpm_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan11_input); +FAN_SYSFS_ATTR_DATA data_fan12_input = {FAN12_INPUT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_rpm_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan12_input); + + +FAN_SYSFS_ATTR_DATA data_fan1_pwm = {FAN1_PWM, S_IRUGO | S_IWUSR, fan_show_default, NULL, sonic_i2c_get_fan_pwm_default, NULL, fan_store_default, NULL, sonic_i2c_set_fan_pwm_default, NULL, NULL}; +EXPORT_SYMBOL(data_fan1_pwm); +FAN_SYSFS_ATTR_DATA data_fan2_pwm = {FAN2_PWM, S_IRUGO | S_IWUSR, fan_show_default, NULL, sonic_i2c_get_fan_pwm_default, NULL, fan_store_default, NULL, sonic_i2c_set_fan_pwm_default, NULL, NULL}; +EXPORT_SYMBOL(data_fan2_pwm); +FAN_SYSFS_ATTR_DATA data_fan3_pwm = {FAN3_PWM, S_IRUGO | S_IWUSR, fan_show_default, NULL, sonic_i2c_get_fan_pwm_default, NULL, fan_store_default, NULL, sonic_i2c_set_fan_pwm_default, NULL, NULL}; +EXPORT_SYMBOL(data_fan3_pwm); +FAN_SYSFS_ATTR_DATA data_fan4_pwm = {FAN4_PWM, S_IRUGO | S_IWUSR, fan_show_default, NULL, sonic_i2c_get_fan_pwm_default, NULL, fan_store_default, NULL, sonic_i2c_set_fan_pwm_default, NULL, NULL}; +EXPORT_SYMBOL(data_fan4_pwm); +FAN_SYSFS_ATTR_DATA data_fan5_pwm = {FAN5_PWM, S_IRUGO | S_IWUSR, fan_show_default, NULL, sonic_i2c_get_fan_pwm_default, NULL, fan_store_default, NULL, sonic_i2c_set_fan_pwm_default, NULL, NULL}; +EXPORT_SYMBOL(data_fan5_pwm); +FAN_SYSFS_ATTR_DATA data_fan6_pwm = {FAN6_PWM, S_IRUGO | S_IWUSR, fan_show_default, NULL, sonic_i2c_get_fan_pwm_default, NULL, fan_store_default, NULL, sonic_i2c_set_fan_pwm_default, NULL, NULL}; +EXPORT_SYMBOL(data_fan6_pwm); +FAN_SYSFS_ATTR_DATA data_fan7_pwm = {FAN7_PWM, S_IRUGO | S_IWUSR, fan_show_default, NULL, sonic_i2c_get_fan_pwm_default, NULL, fan_store_default, NULL, sonic_i2c_set_fan_pwm_default, NULL, NULL}; +EXPORT_SYMBOL(data_fan7_pwm); +FAN_SYSFS_ATTR_DATA data_fan8_pwm = {FAN8_PWM, S_IRUGO | S_IWUSR, fan_show_default, NULL, sonic_i2c_get_fan_pwm_default, NULL, fan_store_default, NULL, sonic_i2c_set_fan_pwm_default, NULL, NULL}; +EXPORT_SYMBOL(data_fan8_pwm); +FAN_SYSFS_ATTR_DATA data_fan9_pwm = {FAN9_PWM, S_IRUGO | S_IWUSR, fan_show_default, NULL, sonic_i2c_get_fan_pwm_default, NULL, fan_store_default, NULL, sonic_i2c_set_fan_pwm_default, NULL, NULL}; +EXPORT_SYMBOL(data_fan9_pwm); +FAN_SYSFS_ATTR_DATA data_fan10_pwm = {FAN10_PWM, S_IRUGO | S_IWUSR, fan_show_default, NULL, sonic_i2c_get_fan_pwm_default, NULL, fan_store_default, NULL, sonic_i2c_set_fan_pwm_default, NULL, NULL}; +EXPORT_SYMBOL(data_fan10_pwm); +FAN_SYSFS_ATTR_DATA data_fan11_pwm = {FAN11_PWM, S_IRUGO | S_IWUSR, fan_show_default, NULL, sonic_i2c_get_fan_pwm_default, NULL, fan_store_default, NULL, sonic_i2c_set_fan_pwm_default, NULL, NULL}; +EXPORT_SYMBOL(data_fan11_pwm); +FAN_SYSFS_ATTR_DATA data_fan12_pwm = {FAN12_PWM, S_IRUGO | S_IWUSR, fan_show_default, NULL, sonic_i2c_get_fan_pwm_default, NULL, fan_store_default, NULL, sonic_i2c_set_fan_pwm_default, NULL, NULL}; +EXPORT_SYMBOL(data_fan12_pwm); + + +FAN_SYSFS_ATTR_DATA data_fan1_fault = {FAN1_FAULT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_fault_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan1_fault); +FAN_SYSFS_ATTR_DATA data_fan2_fault = {FAN2_FAULT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_fault_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan2_fault); +FAN_SYSFS_ATTR_DATA data_fan3_fault = {FAN3_FAULT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_fault_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan3_fault); +FAN_SYSFS_ATTR_DATA data_fan4_fault = {FAN4_FAULT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_fault_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan4_fault); +FAN_SYSFS_ATTR_DATA data_fan5_fault = {FAN5_FAULT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_fault_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan5_fault); +FAN_SYSFS_ATTR_DATA data_fan6_fault = {FAN6_FAULT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_fault_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan6_fault); +FAN_SYSFS_ATTR_DATA data_fan7_fault = {FAN7_FAULT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_fault_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan7_fault); +FAN_SYSFS_ATTR_DATA data_fan8_fault = {FAN8_FAULT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_fault_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan8_fault); +FAN_SYSFS_ATTR_DATA data_fan9_fault = {FAN9_FAULT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_fault_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan9_fault); +FAN_SYSFS_ATTR_DATA data_fan10_fault = {FAN10_FAULT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_fault_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan10_fault); +FAN_SYSFS_ATTR_DATA data_fan11_fault = {FAN11_FAULT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_fault_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan11_fault); +FAN_SYSFS_ATTR_DATA data_fan12_fault = {FAN12_FAULT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_fault_default, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(data_fan12_fault); + + +FAN_SYSFS_ATTR_DATA_ENTRY fan_sysfs_attr_data_tbl[]= +{ + { "fan1_present", &data_fan1_present}, + { "fan2_present", &data_fan2_present}, + { "fan3_present", &data_fan3_present}, + { "fan4_present", &data_fan4_present}, + { "fan5_present", &data_fan5_present}, + { "fan6_present", &data_fan6_present}, + { "fan7_present", &data_fan7_present}, + { "fan8_present", &data_fan8_present}, + { "fan9_present", &data_fan9_present}, + { "fan10_present", &data_fan10_present}, + { "fan11_present", &data_fan11_present}, + { "fan12_present", &data_fan12_present}, + { "fan1_direction", &data_fan1_direction}, + { "fan2_direction", &data_fan2_direction}, + { "fan3_direction", &data_fan3_direction}, + { "fan4_direction", &data_fan4_direction}, + { "fan5_direction", &data_fan5_direction}, + { "fan6_direction", &data_fan6_direction}, + { "fan7_direction", &data_fan7_direction}, + { "fan8_direction", &data_fan8_direction}, + { "fan9_direction", &data_fan9_direction}, + { "fan10_direction", &data_fan10_direction}, + { "fan11_direction", &data_fan11_direction}, + { "fan12_direction", &data_fan12_direction}, + { "fan1_input", &data_fan1_input}, + { "fan2_input", &data_fan2_input}, + { "fan3_input", &data_fan3_input}, + { "fan4_input", &data_fan4_input}, + { "fan5_input", &data_fan5_input}, + { "fan6_input", &data_fan6_input}, + { "fan7_input", &data_fan7_input}, + { "fan8_input", &data_fan8_input}, + { "fan9_input", &data_fan9_input}, + { "fan10_input", &data_fan10_input}, + { "fan11_input", &data_fan11_input}, + { "fan12_input", &data_fan12_input}, + { "fan1_pwm", &data_fan1_pwm}, + { "fan2_pwm", &data_fan2_pwm}, + { "fan3_pwm", &data_fan3_pwm}, + { "fan4_pwm", &data_fan4_pwm}, + { "fan5_pwm", &data_fan5_pwm}, + { "fan6_pwm", &data_fan6_pwm}, + { "fan7_pwm", &data_fan7_pwm}, + { "fan8_pwm", &data_fan8_pwm}, + { "fan9_pwm", &data_fan9_pwm}, + { "fan10_pwm", &data_fan10_pwm}, + { "fan11_pwm", &data_fan11_pwm}, + { "fan12_pwm", &data_fan12_pwm}, + { "fan1_fault", &data_fan1_fault}, + { "fan2_fault", &data_fan2_fault}, + { "fan3_fault", &data_fan3_fault}, + { "fan4_fault", &data_fan4_fault}, + { "fan5_fault", &data_fan5_fault}, + { "fan6_fault", &data_fan6_fault}, + { "fan7_fault", &data_fan7_fault}, + { "fan8_fault", &data_fan8_fault}, + { "fan9_fault", &data_fan9_fault}, + { "fan10_fault", &data_fan10_fault}, + { "fan11_fault", &data_fan11_fault}, + { "fan12_fault", &data_fan12_fault}, +}; + +void *get_fan_access_data(char *name) +{ + int i=0; + for(i=0; i<(sizeof(fan_sysfs_attr_data_tbl)/sizeof(fan_sysfs_attr_data_tbl[0])); i++) + { + if(strcmp(name, fan_sysfs_attr_data_tbl[i].name) ==0) + { + return &fan_sysfs_attr_data_tbl[i]; + } + } + return NULL; +} +EXPORT_SYMBOL(get_fan_access_data); + + + +static int pddf_fan_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + struct fan_data *data; + int status=0,i,num, j=0; + FAN_PDATA *fan_platform_data; + FAN_DATA_ATTR *data_attr; + FAN_SYSFS_ATTR_DATA_ENTRY *sysfs_data_entry; + char new_str[ATTR_NAME_LEN] = ""; + + if (client == NULL) { + printk("NULL Client.. \n"); + goto exit; + } + + if (pddf_fan_ops.pre_probe) + { + status = (pddf_fan_ops.pre_probe)(client, dev_id); + if (status != 0) + goto exit; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + status = -EIO; + goto exit; + } + + /* Add support for a pre probe function */ + data = kzalloc(sizeof(struct fan_data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + dev_info(&client->dev, "chip found\n"); + + + /*Take control of the platform data*/ + fan_platform_data = (FAN_PDATA *)(client->dev.platform_data); + num = fan_platform_data->len; + data->num_attr = num; + + for (i=0;ifan_attrs + i; + sysfs_data_entry = get_fan_access_data(data_attr->aname); + if (sysfs_data_entry == NULL) + { + printk(KERN_ERR "%s: Wrong attribute name provided by user '%s'\n", __FUNCTION__, data_attr->aname); + continue; + } + + dy_ptr = (struct sensor_device_attribute *)kzalloc(sizeof(struct sensor_device_attribute)+ATTR_NAME_LEN, GFP_KERNEL); + dy_ptr->dev_attr.attr.name = (char *)&dy_ptr[1]; + strcpy((char *)dy_ptr->dev_attr.attr.name, data_attr->aname); + dy_ptr->dev_attr.attr.mode = sysfs_data_entry->a_ptr->mode; + dy_ptr->dev_attr.show = sysfs_data_entry->a_ptr->show; + dy_ptr->dev_attr.store = sysfs_data_entry->a_ptr->store; + dy_ptr->index = sysfs_data_entry->a_ptr->index; + + data->fan_attribute_list[i] = &dy_ptr->dev_attr.attr; + strcpy(data->attr_info[i].name, data_attr->aname); + data->attr_info[i].valid = 0; + mutex_init(&data->attr_info[i].update_lock); + + /*Create a duplicate entry*/ + get_fan_duplicate_sysfs(dy_ptr->index, new_str); + if (strcmp(new_str,"")) + { + dy_ptr = (struct sensor_device_attribute *)kzalloc(sizeof(struct sensor_device_attribute)+ATTR_NAME_LEN, GFP_KERNEL); + dy_ptr->dev_attr.attr.name = (char *)&dy_ptr[1]; + strcpy((char *)dy_ptr->dev_attr.attr.name, new_str); + dy_ptr->dev_attr.attr.mode = sysfs_data_entry->a_ptr->mode; + dy_ptr->dev_attr.show = sysfs_data_entry->a_ptr->show; + dy_ptr->dev_attr.store = sysfs_data_entry->a_ptr->store; + dy_ptr->index = sysfs_data_entry->a_ptr->index; + + data->fan_attribute_list[num+j] = &dy_ptr->dev_attr.attr; + j++; + strcpy(new_str, ""); + } + } + data->fan_attribute_list[i+j] = NULL; + data->fan_attribute_group.attrs = data->fan_attribute_list; + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &data->fan_attribute_group); + if (status) { + goto exit_free; + } + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + dev_info(&client->dev, "%s: fan '%s'\n", + dev_name(data->hwmon_dev), client->name); + + /* Add a support for post probe function */ + if (pddf_fan_ops.post_probe) + { + status = (pddf_fan_ops.post_probe)(client, dev_id); + if (status != 0) + goto exit_remove; + } + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &data->fan_attribute_group); +exit_free: + /* Free all the allocated attributes */ + for (i=0; data->fan_attribute_list[i]!=NULL; i++) + { + struct sensor_device_attribute *ptr = (struct sensor_device_attribute *)data->fan_attribute_list[i]; + kfree(ptr); + } + pddf_dbg(FAN, KERN_ERR "%s: Freed all the memory allocated for attributes\n", __FUNCTION__); + kfree(data); +exit: + return status; +} + +static int pddf_fan_remove(struct i2c_client *client) +{ + int i = 0, ret = 0; + struct sensor_device_attribute *ptr = NULL; + struct fan_data *data = i2c_get_clientdata(client); + FAN_PDATA *platdata = (FAN_PDATA *)client->dev.platform_data; + FAN_DATA_ATTR *platdata_sub = platdata->fan_attrs; + + if (pddf_fan_ops.pre_remove) + { + ret = (pddf_fan_ops.pre_remove)(client); + if (ret!=0) + printk(KERN_ERR "FAN pre_remove function failed\n"); + } + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &data->fan_attribute_group); + for (i=0; data->fan_attribute_list[i]!=NULL; i++) + { + ptr = (struct sensor_device_attribute *)data->fan_attribute_list[i]; + kfree(ptr); + } + pddf_dbg(FAN, KERN_ERR "%s: Freed all the memory allocated for attributes\n", __FUNCTION__); + kfree(data); + + if (platdata_sub) { + printk(KERN_DEBUG "%s: Freeing platform subdata\n", __FUNCTION__); + kfree(platdata_sub); + } + if (platdata) { + printk(KERN_DEBUG "%s: Freeing platform data\n", __FUNCTION__); + kfree(platdata); + } + + if (pddf_fan_ops.post_remove) + { + ret = (pddf_fan_ops.post_remove)(client); + if (ret!=0) + printk(KERN_ERR "FAN post_remove function failed\n"); + } + + return 0; +} + +/* Addresses to scan */ +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static const struct i2c_device_id pddf_fan_id[] = { + { "fan_ctrl", 0 }, + { "fan_cpld", 1 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, pddf_fan_id); + +static struct i2c_driver pddf_fan_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = DRVNAME, + }, + .probe = pddf_fan_probe, + .remove = pddf_fan_remove, + .id_table = pddf_fan_id, + .address_list = normal_i2c, +}; + +static int __init pddf_fan_init(void) +{ + int status = 0; + + if (pddf_fan_ops.pre_init) + { + status = (pddf_fan_ops.pre_init)(); + if (status!=0) + return status; + } + + status = i2c_add_driver(&pddf_fan_driver); + if (status!=0) + return status; + + if (pddf_fan_ops.post_init) + { + status = (pddf_fan_ops.post_init)(); + if (status!=0) + return status; + } + return status; + +} + +static void __exit pddf_fan_exit(void) +{ + if (pddf_fan_ops.pre_exit) (pddf_fan_ops.pre_exit)(); + i2c_del_driver(&pddf_fan_driver); + if (pddf_fan_ops.post_exit) (pddf_fan_ops.post_exit)(); +} + +module_init(pddf_fan_init); +module_exit(pddf_fan_exit); + +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("pddf_fan driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/pddf/i2c/modules/fan/pddf_fan_module.c b/platform/pddf/i2c/modules/fan/pddf_fan_module.c new file mode 100644 index 0000000000..b910d6b4a3 --- /dev/null +++ b/platform/pddf/i2c/modules/fan/pddf_fan_module.c @@ -0,0 +1,280 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * + * A pddf kernel module to create I2C client for FAN controller + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pddf_client_defs.h" +#include "pddf_fan_defs.h" + + +static ssize_t do_attr_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count); +static ssize_t do_device_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count); +extern void *get_fan_access_data(char *); +extern void* get_device_table(char *name); +extern void delete_device_table(char *name); + +FAN_DATA fan_data = {0}; + + + +/* FAN CLIENT DATA */ +PDDF_DATA_ATTR(num_fantrays, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_DEC, sizeof(int), (void*)&fan_data.num_fantrays, NULL); + +PDDF_DATA_ATTR(attr_name, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_CHAR, 32, (void*)&fan_data.fan_attr.aname, NULL); +PDDF_DATA_ATTR(attr_devtype, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_CHAR, 8, (void*)&fan_data.fan_attr.devtype, NULL); +PDDF_DATA_ATTR(attr_devname, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_CHAR, 8, (void*)&fan_data.fan_attr.devname, NULL); +PDDF_DATA_ATTR(attr_devaddr, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32, sizeof(uint32_t), (void*)&fan_data.fan_attr.devaddr, NULL); +PDDF_DATA_ATTR(attr_offset, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32, sizeof(uint32_t), (void*)&fan_data.fan_attr.offset, NULL); +PDDF_DATA_ATTR(attr_mask, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32, sizeof(uint32_t), (void*)&fan_data.fan_attr.mask, NULL); +PDDF_DATA_ATTR(attr_cmpval, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32, sizeof(uint32_t), (void*)&fan_data.fan_attr.cmpval, NULL); +PDDF_DATA_ATTR(attr_len, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_DEC, sizeof(int), (void*)&fan_data.fan_attr.len, NULL); +PDDF_DATA_ATTR(attr_mult, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_DEC, sizeof(int), (void*)&fan_data.fan_attr.mult, NULL); +PDDF_DATA_ATTR(attr_is_divisor, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UCHAR, sizeof(unsigned char), (void*)&fan_data.fan_attr.is_divisor, NULL); +PDDF_DATA_ATTR(attr_ops, S_IWUSR, NULL, do_attr_operation, PDDF_CHAR, 8, (void*)&fan_data, NULL); +PDDF_DATA_ATTR(dev_ops, S_IWUSR, NULL, do_device_operation, PDDF_CHAR, 8, (void*)&fan_data, (void*)&pddf_data); + + + +static struct attribute *fan_attributes[] = { + &attr_num_fantrays.dev_attr.attr, + &attr_attr_name.dev_attr.attr, + &attr_attr_devtype.dev_attr.attr, + &attr_attr_devname.dev_attr.attr, + &attr_attr_devaddr.dev_attr.attr, + &attr_attr_offset.dev_attr.attr, + &attr_attr_mask.dev_attr.attr, + &attr_attr_cmpval.dev_attr.attr, + &attr_attr_len.dev_attr.attr, + &attr_attr_mult.dev_attr.attr, + &attr_attr_is_divisor.dev_attr.attr, + &attr_attr_ops.dev_attr.attr, + &attr_dev_ops.dev_attr.attr, + NULL +}; + +static const struct attribute_group pddf_fan_client_data_group = { + .attrs = fan_attributes, +}; + + +static ssize_t do_attr_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count) +{ + PDDF_ATTR *ptr = (PDDF_ATTR *)da; + FAN_DATA *fdata = (FAN_DATA *)(ptr->addr); + FAN_SYSFS_ATTR_DATA_ENTRY *entry_ptr; + + + fdata->fan_attrs[fdata->len] = fdata->fan_attr; + entry_ptr = get_fan_access_data(fdata->fan_attrs[fdata->len].aname); + if (entry_ptr != NULL && entry_ptr->a_ptr != NULL) + { + fdata->fan_attrs[fdata->len].access_data = entry_ptr->a_ptr ; + } + + fdata->len++; + memset(&fdata->fan_attr, 0, sizeof(fdata->fan_attr)); + + + return count; +} + +struct i2c_board_info *i2c_get_fan_board_info(FAN_DATA *fdata, NEW_DEV_ATTR *cdata) +{ + int num = fdata->len; + int i = 0; + static struct i2c_board_info board_info; + FAN_PDATA *fan_platform_data; + + if (strcmp(cdata->dev_type, "fan_ctrl")==0 || + strcmp(cdata->dev_type, "fan_eeprom")==0 || + strcmp(cdata->dev_type, "fan_cpld")==0 ) + { + /* Allocate the fan_platform_data */ + fan_platform_data = (FAN_PDATA *)kzalloc(sizeof(FAN_PDATA), GFP_KERNEL); + fan_platform_data->fan_attrs = (FAN_DATA_ATTR *)kzalloc(num*sizeof(FAN_DATA_ATTR), GFP_KERNEL); + + + fan_platform_data->num_fantrays = fdata->num_fantrays; + fan_platform_data->len = fdata->len; + + for (i=0;ifan_attrs[i] = fdata->fan_attrs[i]; + } + + board_info = (struct i2c_board_info) { + .platform_data = fan_platform_data, + }; + + board_info.addr = cdata->dev_addr; + strcpy(board_info.type, cdata->dev_type); + } + else + { + printk(KERN_ERR "%s:Unknown type of device %s. Unable to create I2C client for it\n",__FUNCTION__, cdata->dev_type); + } + + return &board_info; +} + + +static ssize_t do_device_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count) +{ + PDDF_ATTR *ptr = (PDDF_ATTR *)da; + FAN_DATA *fdata = (FAN_DATA *)(ptr->addr); + NEW_DEV_ATTR *cdata = (NEW_DEV_ATTR *)(ptr->data); + struct i2c_adapter *adapter; + struct i2c_board_info *board_info; + struct i2c_client *client_ptr; + + if (strncmp(buf, "add", strlen(buf)-1)==0) + { + adapter = i2c_get_adapter(cdata->parent_bus); + board_info = i2c_get_fan_board_info(fdata, cdata); + + /* Populate the platform data for fan */ + client_ptr = i2c_new_device(adapter, board_info); + + if(client_ptr != NULL) + { + i2c_put_adapter(adapter); + pddf_dbg(FAN, KERN_ERR "Created a %s client: 0x%p\n", cdata->i2c_name, (void *)client_ptr); + add_device_table(cdata->i2c_name, (void*)client_ptr); + } + else + { + i2c_put_adapter(adapter); + goto free_data; + } + } + else if (strncmp(buf, "delete", strlen(buf)-1)==0) + { + /*Get the i2c_client handle for the created client*/ + client_ptr = (struct i2c_client *)get_device_table(cdata->i2c_name); + if (client_ptr) + { + pddf_dbg(FAN, KERN_ERR "Removing %s client: 0x%p\n", cdata->i2c_name, (void *)client_ptr); + i2c_unregister_device(client_ptr); + delete_device_table(cdata->i2c_name); + } + else + { + printk(KERN_ERR "Unable to get the client handle for %s\n", cdata->i2c_name); + } + } + else + { + printk(KERN_ERR "PDDF_ERROR: %s: Invalid value for dev_ops %s", __FUNCTION__, buf); + } + + goto clear_data; + +free_data: + if (board_info->platform_data) + { + FAN_PDATA *fan_platform_data = board_info->platform_data; + if (fan_platform_data->fan_attrs) + { + printk(KERN_ERR "%s: Unable to create i2c client. Freeing the platform subdata\n", __FUNCTION__); + kfree(fan_platform_data->fan_attrs); + } + printk(KERN_ERR "%s: Unable to create i2c client. Freeing the platform data\n", __FUNCTION__); + kfree(fan_platform_data); + } +clear_data: + memset(fdata, 0, sizeof(FAN_DATA)); + /*TODO: free the data cdata->data if data is dynal=mically allocated*/ + memset(cdata, 0, sizeof(NEW_DEV_ATTR)); + return count; +} + + +static struct kobject *fan_kobj; +static struct kobject *i2c_kobj; + +int __init pddf_data_init(void) +{ + struct kobject *device_kobj; + int ret = 0; + + + pddf_dbg(FAN, "PDDF FAN MODULE.. init\n"); + + device_kobj = get_device_i2c_kobj(); + if(!device_kobj) + return -ENOMEM; + + fan_kobj = kobject_create_and_add("fan", device_kobj); + if(!fan_kobj) + return -ENOMEM; + i2c_kobj = kobject_create_and_add("i2c", fan_kobj); + if(!i2c_kobj) + return -ENOMEM; + + ret = sysfs_create_group(i2c_kobj, &pddf_clients_data_group); + if (ret) + { + kobject_put(i2c_kobj); + kobject_put(fan_kobj); + return ret; + } + pddf_dbg(FAN, "CREATED FAN I2C CLIENTS CREATION SYSFS GROUP\n"); + + ret = sysfs_create_group(i2c_kobj, &pddf_fan_client_data_group); + if (ret) + { + sysfs_remove_group(i2c_kobj, &pddf_clients_data_group); + kobject_put(i2c_kobj); + kobject_put(fan_kobj); + return ret; + } + pddf_dbg(FAN, "CREATED PDDF FAN DATA SYSFS GROUP\n"); + + + + return ret; +} + +void __exit pddf_data_exit(void) +{ + pddf_dbg(FAN, "PDDF FAN MODULE.. exit\n"); + sysfs_remove_group(i2c_kobj, &pddf_fan_client_data_group); + sysfs_remove_group(i2c_kobj, &pddf_clients_data_group); + kobject_put(i2c_kobj); + kobject_put(fan_kobj); + pddf_dbg(FAN, KERN_ERR "%s: Removed the kobjects for 'i2c' and 'fan'\n",__FUNCTION__); + return; +} + +module_init(pddf_data_init); +module_exit(pddf_data_exit); + +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("fan platform data"); +MODULE_LICENSE("GPL"); diff --git a/platform/pddf/i2c/modules/gpio/Makefile b/platform/pddf/i2c/modules/gpio/Makefile new file mode 100644 index 0000000000..6d48c58847 --- /dev/null +++ b/platform/pddf/i2c/modules/gpio/Makefile @@ -0,0 +1,4 @@ + +obj-m := pddf_gpio_module.o + +CFLAGS_$(obj-m):= -I$(M)/modules/include diff --git a/platform/pddf/i2c/modules/gpio/pddf_gpio_module.c b/platform/pddf/i2c/modules/gpio/pddf_gpio_module.c new file mode 100644 index 0000000000..afd37c3927 --- /dev/null +++ b/platform/pddf/i2c/modules/gpio/pddf_gpio_module.c @@ -0,0 +1,223 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * + * PDDF generic kernle module to create the I2C client for pca955x type of GPIO module + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pddf_client_defs.h" +#include "pddf_gpio_defs.h" + + +static ssize_t do_device_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count); +extern void* get_device_table(char *name); +extern void delete_device_table(char *name); + +static int base_gpio_num = 0xf0; +GPIO_DATA gpio_data = {0}; + +/* GPIO CLIENT DATA */ +PDDF_DATA_ATTR(gpio_base, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_HEX, sizeof(int), (void*)&gpio_data.gpio_base, NULL); +PDDF_DATA_ATTR(dev_ops, S_IWUSR, NULL, do_device_operation, PDDF_CHAR, 8, (void*)&gpio_data, (void*)&pddf_data); + + + +static struct attribute *gpio_attributes[] = { + &attr_gpio_base.dev_attr.attr, + &attr_dev_ops.dev_attr.attr, + NULL +}; + +static const struct attribute_group pddf_gpio_client_data_group = { + .attrs = gpio_attributes, +}; + + +struct i2c_board_info *i2c_get_gpio_board_info(GPIO_DATA* mdata, NEW_DEV_ATTR *device_data) +{ + static struct i2c_board_info board_info; + struct pca953x_platform_data *gpio_platform_data=NULL; + int def_num_gpios, base; + + gpio_platform_data = (struct pca953x_platform_data *)kzalloc(sizeof (struct pca953x_platform_data), GFP_KERNEL); + + if (strncmp(device_data->dev_type, "pca9554", strlen("pca9554")) == 0 || + strncmp(device_data->dev_type, "pca9534", strlen("pca9534")) == 0 || + strncmp(device_data->dev_type, "pca9538", strlen("pca9538")) == 0) + def_num_gpios = 0x8; + else if (strncmp(device_data->dev_type, "pca9555", strlen("pca9555")) == 0 || + strncmp(device_data->dev_type, "pca9535", strlen("pca9535")) == 0 || + strncmp(device_data->dev_type, "pca9539", strlen("pca9539")) == 0 || + strncmp(device_data->dev_type, "pca9575", strlen("pca9575")) == 0) + def_num_gpios = 0x10; + else if (strncmp(device_data->dev_type, "pca9698", strlen("pca9698")) == 0 || + strncmp(device_data->dev_type, "pca9505", strlen("pca9505")) == 0) + def_num_gpios = 0x28; + else + { + printk(KERN_ERR "%s: Unknown type of gpio device\n", __FUNCTION__); + return NULL; + } + + if(mdata->gpio_base == 0) { + base = base_gpio_num; + base_gpio_num += def_num_gpios; + } + else { + base = mdata->gpio_base; + } + + gpio_platform_data->gpio_base = base; + + board_info = (struct i2c_board_info) { + .platform_data = gpio_platform_data, + }; + + board_info.addr = device_data->dev_addr; + strcpy(board_info.type, device_data->dev_type); + + return &board_info; +} + + +static ssize_t do_device_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count) +{ + PDDF_ATTR *ptr = (PDDF_ATTR *)da; + GPIO_DATA *gpio_ptr = (GPIO_DATA *)(ptr->addr); + NEW_DEV_ATTR *device_ptr = (NEW_DEV_ATTR *)(ptr->data); + struct i2c_adapter *adapter; + struct i2c_board_info *board_info; + struct i2c_client *client_ptr; + + if (strncmp(buf, "add", strlen(buf)-1)==0) + { + adapter = i2c_get_adapter(device_ptr->parent_bus); + board_info = i2c_get_gpio_board_info(gpio_ptr, device_ptr); + + /*pddf_dbg(KERN_ERR "Creating a client %s on 0x%x, platform_data 0x%x\n", board_info->type, board_info->addr, board_info->platform_data);*/ + client_ptr = i2c_new_device(adapter, board_info); + + i2c_put_adapter(adapter); + if (client_ptr != NULL) + { + pddf_dbg(GPIO, KERN_ERR "Created %s client: 0x%p\n", device_ptr->i2c_name, (void *)client_ptr); + add_device_table(device_ptr->i2c_name, (void*)client_ptr); + } + else + { + kfree(board_info); + goto free_data; + } + } + else if (strncmp(buf, "delete", strlen(buf)-1)==0) + { + /*Get the i2c_client handle for the created client*/ + client_ptr = (struct i2c_client *)get_device_table(device_ptr->i2c_name); + if (client_ptr) + { + struct pca953x_platform_data *gpio_platform_data = (struct pca953x_platform_data *)client_ptr->dev.platform_data; + pddf_dbg(GPIO, KERN_ERR "Removing %s client: 0x%p\n", device_ptr->i2c_name, (void *)client_ptr); + i2c_unregister_device(client_ptr); + /*TODO: Nullyfy the platform data*/ + if (gpio_platform_data) + kfree(gpio_platform_data); + delete_device_table(device_ptr->i2c_name); + } + else + { + printk(KERN_ERR "Unable to get the client handle for %s\n", device_ptr->i2c_name); + } + } + else + { + printk(KERN_ERR "PDDF_ERROR: %s: Invalid value for dev_ops %s", __FUNCTION__, buf); + } + +free_data: + memset(gpio_ptr, 0, sizeof(GPIO_DATA)); + /*TODO: free the device_ptr->data is dynamically allocated*/ + memset(device_ptr, 0 , sizeof(NEW_DEV_ATTR)); + + return count; +} + + +static struct kobject *gpio_kobj; + +int __init gpio_data_init(void) +{ + struct kobject *device_kobj; + int ret = 0; + + + pddf_dbg(GPIO, "GPIO_DATA MODULE.. init\n"); + + device_kobj = get_device_i2c_kobj(); + if(!device_kobj) + return -ENOMEM; + + gpio_kobj = kobject_create_and_add("gpio", device_kobj); + if(!gpio_kobj) + return -ENOMEM; + + + ret = sysfs_create_group(gpio_kobj, &pddf_clients_data_group); + if (ret) + { + kobject_put(gpio_kobj); + return ret; + } + pddf_dbg(GPIO, "CREATED PDDF I2C CLIENTS CREATION SYSFS GROUP\n"); + + ret = sysfs_create_group(gpio_kobj, &pddf_gpio_client_data_group); + if (ret) + { + sysfs_remove_group(gpio_kobj, &pddf_clients_data_group); + kobject_put(gpio_kobj); + return ret; + } + pddf_dbg(GPIO, "CREATED GPIO DATA SYSFS GROUP\n"); + + return ret; +} + +void __exit gpio_data_exit(void) +{ + pddf_dbg(GPIO, "GPIO_DATA MODULE.. exit\n"); + sysfs_remove_group(gpio_kobj, &pddf_gpio_client_data_group); + sysfs_remove_group(gpio_kobj, &pddf_clients_data_group); + kobject_put(gpio_kobj); + pddf_dbg(GPIO, KERN_ERR "%s: Removed the kobjects for 'gpio'\n",__FUNCTION__); + return; +} + +module_init(gpio_data_init); +module_exit(gpio_data_exit); + +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("gpio platform data"); +MODULE_LICENSE("GPL"); diff --git a/platform/pddf/i2c/modules/include/pddf_client_defs.h b/platform/pddf/i2c/modules/include/pddf_client_defs.h new file mode 100644 index 0000000000..1c98a73e6e --- /dev/null +++ b/platform/pddf/i2c/modules/include/pddf_client_defs.h @@ -0,0 +1,135 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * + * Description: + * Platform I2C client defines/structures header file + */ + +#ifndef __PDDF_CLIENT_DEFS_H__ +#define __PDDF_CLIENT_DEFS_H__ + +#include + +#define PSU "PDDF_PSU" +#define LED "PDDF_LED" +#define FAN "PDDF_FAN" +#define CLIENT "PDDF_CLIENT" +#define CPLD "PDDF_CPLD" +#define CPLDMUX "PDDF_CPLDMUX" +#define MUX "PDDF_MUX" +#define GPIO "PDDF_GPIO" +#define SYSSTATUS "PDDF_SYSSTATUS" +#define XCVR "PDDF_XCVR" + +#define PDDF_DEBUG +#ifdef PDDF_DEBUG +#define pddf_dbg(filter,...) printk("%s\t", filter); printk(KERN_CONT __VA_ARGS__) +#else +#define pddf_dbg(...) +#endif + + +#define GEN_NAME_SIZE 32 +#define ERR_STR_SIZE 128 + + +typedef struct pddf_data_attribute{ + struct device_attribute dev_attr; + int type; + int len; + char *addr; + char *data; +}PDDF_ATTR; + +#define PDDF_DATA_ATTR(_name, _mode, _show, _store, _type, _len, _addr, _data) \ + struct pddf_data_attribute attr_##_name = { .dev_attr = __ATTR(_name, _mode, _show, _store), \ + .type = _type , \ + .len = _len , \ + .addr = _addr, \ + .data = _data } + + +enum attribute_data_type { + PDDF_CHAR, + PDDF_UCHAR, + PDDF_INT_HEX, // integer represented in HEX + PDDF_INT_DEC, // integer represented in DECIMAL + PDDF_USHORT, // HEX + PDDF_UINT32 // HEX +}; + + + + + +// PSU Specific details + +typedef struct NEW_DEV_ATTR +{ + char i2c_type[GEN_NAME_SIZE]; + char i2c_name[GEN_NAME_SIZE]; + int parent_bus; + char dev_type[GEN_NAME_SIZE]; + int dev_id; + int dev_addr; + char *data; + int error; + char errstr[ERR_STR_SIZE]; + +}NEW_DEV_ATTR; +extern NEW_DEV_ATTR pddf_data; + +extern struct attribute_group pddf_clients_data_group; +extern ssize_t store_pddf_data(struct device *dev, struct device_attribute *da, const char *buf, size_t count); +extern ssize_t show_pddf_data(struct device *dev, struct device_attribute *da, char *buf); +struct kobject* get_device_i2c_kobj(void); +void set_attr_data(void * ptr); +void set_error_code(int, char *); +ssize_t show_error_code(struct device *dev, struct device_attribute *da, char *buf); +ssize_t show_all_devices(struct device *dev, struct device_attribute *da, char *buf); +void traverse_device_table(void ); + + + +/*Various Ops hook which can be used by vendors to provide some deviation from usual pddf functionality*/ +struct pddf_ops_t +{ + /*Module init ops*/ + int (*pre_init)(void); + int (*post_init)(void); + /*probe ops*/ + int (*pre_probe)(struct i2c_client *, const struct i2c_device_id *); + int (*post_probe)(struct i2c_client *, const struct i2c_device_id *); + /*remove ops*/ + int (*pre_remove)(struct i2c_client *); + int (*post_remove)(struct i2c_client *); + /*Module exit ops*/ + void (*pre_exit)(void); + void (*post_exit)(void); +}; + + +typedef struct PDEVICE +{ + struct hlist_node node; + char name[GEN_NAME_SIZE]; + void *data; + +}PDEVICE; + +void add_device_table(char *name, void *ptr); + + +#endif diff --git a/platform/pddf/i2c/modules/include/pddf_cpld_defs.h b/platform/pddf/i2c/modules/include/pddf_cpld_defs.h new file mode 100644 index 0000000000..c312f3277f --- /dev/null +++ b/platform/pddf/i2c/modules/include/pddf_cpld_defs.h @@ -0,0 +1,31 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * + * Description: + * Platform CPLD defines/structures header file + */ + +#ifndef __PDDF_CPLD_DEFS_H__ +#define __PDDF_CPLD_DEFS_H__ + +/* CPLD DATA - DATA FOR CPLD CLIENT READ/WRITE*/ +typedef struct CPLD_DATA +{ + struct mutex cpld_lock; + uint16_t reg_addr; +}PDDF_CPLD_DATA; + + +#endif diff --git a/platform/pddf/i2c/modules/include/pddf_cpldmux_defs.h b/platform/pddf/i2c/modules/include/pddf_cpldmux_defs.h new file mode 100644 index 0000000000..ab2aa901c8 --- /dev/null +++ b/platform/pddf/i2c/modules/include/pddf_cpldmux_defs.h @@ -0,0 +1,76 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * + * Description: + * Platform CPLDMUX defines/structures header file + */ + +#ifndef __PDDF_CPLDMUX_DEFS_H__ +#define __PDDF_CPLDMUX_DEFS_H__ + +#include + +#define MAX_CPLDMUX_CHAN 64 + +typedef struct CPLDMUX_CHAN_DATA +{ + int chan_num; + char chan_device[128]; /* Could be multiple devices, mentioned as " " seperated array */ + int cpld_devaddr; + int cpld_offset; + int cpld_sel; + int cpld_desel; +}PDDF_CPLDMUX_CHAN_DATA; + +/* CPLDMUX DATA - DATA FOR CPLDMUX CLIENT*/ +typedef struct CPLDMUX_DATA +{ + int base_chan; + int num_chan; + int chan_cache; + uint32_t cpld_addr; + char cpld_name[32]; + PDDF_CPLDMUX_CHAN_DATA chan_data[MAX_CPLDMUX_CHAN]; +}PDDF_CPLDMUX_DATA; + +typedef struct CPLDMUX_PDATA +{ + int parent_bus; + int base_chan; + int num_chan; + int chan_cache; + struct i2c_client *cpld; + PDDF_CPLDMUX_CHAN_DATA *chan_data; +}PDDF_CPLDMUX_PDATA; + +typedef struct CPLDMUX_PRIV_DATA{ + struct i2c_adapter *parent; + uint32_t last_chan; /* Will be used in case channel caching is enabled */ + PDDF_CPLDMUX_PDATA data; +}PDDF_CPLDMUX_PRIV_DATA; + +typedef struct pldmux_ops_t +{ + int (*select)(struct i2c_mux_core *muxc, uint32_t chan); + int (*deselect)(struct i2c_mux_core *muxc, uint32_t chan); +}PDDF_CPLDMUX_OPS; + +int pddf_cpldmux_select_default(struct i2c_mux_core *muxc, uint32_t chan); +int pddf_cpldmux_deselect_default(struct i2c_mux_core *muxc, uint32_t chan); + +extern int board_i2c_cpld_read(unsigned short cpld_addr, u8 reg); +extern int board_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); + +#endif diff --git a/platform/pddf/i2c/modules/include/pddf_fan_api.h b/platform/pddf/i2c/modules/include/pddf_fan_api.h new file mode 100644 index 0000000000..45b7751ccd --- /dev/null +++ b/platform/pddf/i2c/modules/include/pddf_fan_api.h @@ -0,0 +1,37 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * + * 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 2 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. + * + * Description + * FAN driver api declarations + */ + +#ifndef __PDDF_FAN_API_H__ +#define __PDDF_FAN_API_H__ + +extern int pddf_fan_post_probe_default(struct i2c_client *client, const struct i2c_device_id *dev_id); + +extern void get_fan_duplicate_sysfs(int idx, char *str); +extern ssize_t fan_show_default(struct device *dev, struct device_attribute *da, char *buf); +extern ssize_t fan_store_default(struct device *dev, struct device_attribute *da, const char *buf, size_t count); + + +extern int sonic_i2c_get_fan_present_default(void *client, FAN_DATA_ATTR *adata, void *data); +extern int sonic_i2c_get_fan_rpm_default(void *client, FAN_DATA_ATTR *adata, void *data); +extern int sonic_i2c_get_fan_direction_default(void *client, FAN_DATA_ATTR *adata, void *data); +extern int sonic_i2c_get_fan_pwm_default(void *client, FAN_DATA_ATTR *adata, void *data); +extern int sonic_i2c_get_fan_fault_default(void *client, FAN_DATA_ATTR *adata, void *data); +extern int sonic_i2c_set_fan_pwm_default(void *client, FAN_DATA_ATTR *adata, void *data); + +#endif diff --git a/platform/pddf/i2c/modules/include/pddf_fan_defs.h b/platform/pddf/i2c/modules/include/pddf_fan_defs.h new file mode 100644 index 0000000000..7765e54462 --- /dev/null +++ b/platform/pddf/i2c/modules/include/pddf_fan_defs.h @@ -0,0 +1,91 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * + * Description: + * Platform FAN defines/structures header file + */ + +#ifndef __PDDF_FAN_DEFS_H__ +#define __PDDF_FAN_DEFS_H__ + + +#define MAX_NUM_FAN 6 +#define MAX_FAN_ATTRS 128 +#define ATTR_NAME_LEN 32 +#define STR_ATTR_SIZE 32 +#define DEV_TYPE_LEN 32 + +/* Each client has this additional data + */ + +typedef struct FAN_DATA_ATTR +{ + char aname[ATTR_NAME_LEN]; // attr name, taken from enum fan_sysfs_attributes + char devtype[DEV_TYPE_LEN]; // Type of FAN controller, i.e EMC2305, EMC2302, or FAN-CPLD etc + char devname[DEV_TYPE_LEN]; // Name of the device from where this informatin is to be read + uint32_t devaddr; + uint32_t offset; + uint32_t mask; + uint32_t cmpval; + uint32_t len; + int mult; // Multiplication factor to get the actual data + uint8_t is_divisor; // Check if the value is a divisor and mult is dividend + void *access_data; + +}FAN_DATA_ATTR; + + +typedef struct FAN_SYSFS_ATTR_DATA +{ + int index; + unsigned short mode; + ssize_t (*show)(struct device *dev, struct device_attribute *da, char *buf); + int (*pre_get)(void *client, FAN_DATA_ATTR *adata, void *data); + int (*do_get)(void *client, FAN_DATA_ATTR *adata, void *data); + int (*post_get)(void *client, FAN_DATA_ATTR *adata, void *data); + ssize_t (*store)(struct device *dev, struct device_attribute *da, const char *buf, size_t count); + int (*pre_set)(void *client, FAN_DATA_ATTR *adata, void *data); + int (*do_set)(void *client, FAN_DATA_ATTR *adata, void *data); + int (*post_set)(void *client, FAN_DATA_ATTR *adata, void *data); + void *data; +} FAN_SYSFS_ATTR_DATA; + +typedef struct FAN_SYSFS_ATTR_DATA_ENTRY +{ + char name[ATTR_NAME_LEN]; + FAN_SYSFS_ATTR_DATA *a_ptr; +} FAN_SYSFS_ATTR_DATA_ENTRY; + + +/* FAN CLIENT DATA - PLATFORM DATA FOR FAN CLIENT */ +typedef struct FAN_DATA +{ + int num_fantrays; // num of fans controlled by this fan client + FAN_DATA_ATTR fan_attr; + int len; // no of valid attributes for this fan client + FAN_DATA_ATTR fan_attrs[MAX_FAN_ATTRS]; +}FAN_DATA; + +typedef struct FAN_PDATA +{ + int num_fantrays; // num of fans controlled by this fan client + int len; // no of valid attributes for this fan client + FAN_DATA_ATTR *fan_attrs; +}FAN_PDATA; + +extern int board_i2c_cpld_read(unsigned short cpld_addr, u8 reg); +extern int board_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); + +#endif diff --git a/platform/pddf/i2c/modules/include/pddf_fan_driver.h b/platform/pddf/i2c/modules/include/pddf_fan_driver.h new file mode 100644 index 0000000000..8404db2078 --- /dev/null +++ b/platform/pddf/i2c/modules/include/pddf_fan_driver.h @@ -0,0 +1,107 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * + * Description + * FAN driver related data structures + */ +#ifndef __PDDF_FAN_DRIVER_H__ +#define __PDDF_FAN_DRIVER_H__ + +enum fan_sysfs_attributes { + FAN1_PRESENT, + FAN2_PRESENT, + FAN3_PRESENT, + FAN4_PRESENT, + FAN5_PRESENT, + FAN6_PRESENT, + FAN7_PRESENT, + FAN8_PRESENT, + FAN9_PRESENT, + FAN10_PRESENT, + FAN11_PRESENT, + FAN12_PRESENT, + FAN1_DIRECTION, + FAN2_DIRECTION, + FAN3_DIRECTION, + FAN4_DIRECTION, + FAN5_DIRECTION, + FAN6_DIRECTION, + FAN7_DIRECTION, + FAN8_DIRECTION, + FAN9_DIRECTION, + FAN10_DIRECTION, + FAN11_DIRECTION, + FAN12_DIRECTION, + FAN1_INPUT, + FAN2_INPUT, + FAN3_INPUT, + FAN4_INPUT, + FAN5_INPUT, + FAN6_INPUT, + FAN7_INPUT, + FAN8_INPUT, + FAN9_INPUT, + FAN10_INPUT, + FAN11_INPUT, + FAN12_INPUT, + FAN1_PWM, + FAN2_PWM, + FAN3_PWM, + FAN4_PWM, + FAN5_PWM, + FAN6_PWM, + FAN7_PWM, + FAN8_PWM, + FAN9_PWM, + FAN10_PWM, + FAN11_PWM, + FAN12_PWM, + FAN1_FAULT, + FAN2_FAULT, + FAN3_FAULT, + FAN4_FAULT, + FAN5_FAULT, + FAN6_FAULT, + FAN7_FAULT, + FAN8_FAULT, + FAN9_FAULT, + FAN10_FAULT, + FAN11_FAULT, + FAN12_FAULT, + FAN_MAX_ATTR +}; +/* Each client has this additional data */ +struct fan_attr_info { + char name[ATTR_NAME_LEN]; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + union { + char strval[STR_ATTR_SIZE]; + int intval; + u16 shortval; + u8 charval; + }val; +}; + +struct fan_data { + struct device *hwmon_dev; + int num_attr; + struct attribute *fan_attribute_list[MAX_FAN_ATTRS]; + struct attribute_group fan_attribute_group; + struct fan_attr_info attr_info[MAX_FAN_ATTRS]; +}; + +#endif diff --git a/platform/pddf/i2c/modules/include/pddf_gpio_defs.h b/platform/pddf/i2c/modules/include/pddf_gpio_defs.h new file mode 100644 index 0000000000..a8ee00189b --- /dev/null +++ b/platform/pddf/i2c/modules/include/pddf_gpio_defs.h @@ -0,0 +1,30 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * + * Description: + * Platform GPIO defines/structures header file + */ + +#ifndef __PAL_GPIO_DEFS_H__ +#define __PAL_GPIO_DEFS_H__ + +#include +/* GPIO CLIENT DATA*/ +typedef struct GPIO_DATA +{ + int gpio_base; // base bus number of the gpio pins +}GPIO_DATA; + +#endif diff --git a/platform/pddf/i2c/modules/include/pddf_led_defs.h b/platform/pddf/i2c/modules/include/pddf_led_defs.h new file mode 100644 index 0000000000..1603f8c5af --- /dev/null +++ b/platform/pddf/i2c/modules/include/pddf_led_defs.h @@ -0,0 +1,120 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * + * Description + * Platform LED related defines and structures + */ + + +/***************************************** + * kobj list + *****************************************/ + +struct kobject *platform_kobj=NULL; +struct kobject *led_kobj=NULL; + +struct kobject *state_attr_kobj=NULL; +struct kobject *cur_state_kobj=NULL; + +/***************************************** + * Static Data provided from user + * space JSON data file + *****************************************/ +#define NAME_SIZE 32 +typedef enum { + STATUS_LED_COLOR_GREEN, + STATUS_LED_COLOR_GREEN_BLINK, + STATUS_LED_COLOR_RED, + STATUS_LED_COLOR_RED_BLINK, + STATUS_LED_COLOR_AMBER, + STATUS_LED_COLOR_AMBER_BLINK, + STATUS_LED_COLOR_BLUE, + STATUS_LED_COLOR_BLUE_BLINK, + STATUS_LED_COLOR_OFF, + MAX_LED_STATUS +}LED_STATUS; + +char* LED_STATUS_STR[] = { + "STATUS_LED_COLOR_GREEN", + "STATUS_LED_COLOR_GREEN_BLINK", + "STATUS_LED_COLOR_RED", + "STATUS_LED_COLOR_RED_BLINK", + "STATUS_LED_COLOR_AMBER", + "STATUS_LED_COLOR_AMBER_BLINK", + "STATUS_LED_COLOR_BLUE", + "STATUS_LED_COLOR_BLUE_BLINK", + "STATUS_LED_COLOR_OFF" +}; + + +typedef struct +{ + char bits[NAME_SIZE]; + int pos; + int mask_bits; +}MASK_BITS; + +typedef struct +{ + int swpld_addr; + int swpld_addr_offset; + MASK_BITS bits; + unsigned short value; +} LED_DATA; + +typedef struct +{ + int state; + char color[NAME_SIZE]; +} CUR_STATE_DATA; + +typedef struct +{ + CUR_STATE_DATA cur_state; + char device_name[NAME_SIZE]; + int index; + LED_DATA data[MAX_LED_STATUS]; + int swpld_addr; + int swpld_addr_offset; +} LED_OPS_DATA; + +typedef enum{ + LED_SYS, + LED_PSU, + LED_FAN, + LED_FANTRAY, + LED_DIAG, + LED_LOC, + LED_TYPE_MAX +} LED_TYPE; +char* LED_TYPE_STR[LED_TYPE_MAX] = +{ + "LED_SYS", + "LED_PSU", + "LED_FAN", + "LED_FANTRAY", + "LED_DIAG", + "LED_LOC", +}; + +/***************************************** + * Data exported from kernel for + * user space plugin to get/set + *****************************************/ +#define PDDF_LED_DATA_ATTR( _prefix, _name, _mode, _show, _store, _type, _len, _addr) \ + struct pddf_data_attribute pddf_dev_##_prefix##_attr_##_name = { .dev_attr = __ATTR(_name, _mode, _show, _store), \ + .type = _type , \ + .len = _len , \ + .addr = _addr } diff --git a/platform/pddf/i2c/modules/include/pddf_mux_defs.h b/platform/pddf/i2c/modules/include/pddf_mux_defs.h new file mode 100644 index 0000000000..c58a00e972 --- /dev/null +++ b/platform/pddf/i2c/modules/include/pddf_mux_defs.h @@ -0,0 +1,31 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * + * Description: + * Platform MUX defines/structures header file + */ + +#ifndef __PAL_MUX_DEFS_H__ +#define __PAL_MUX_DEFS_H__ + +#include + +/* MUX CLIENT DATA - PLATFORM DATA FOR PSU CLIENT */ +typedef struct MUX_DATA +{ + int virt_bus; // Virtual base bus number of the mux channels +}MUX_DATA; + +#endif diff --git a/platform/pddf/i2c/modules/include/pddf_psu_api.h b/platform/pddf/i2c/modules/include/pddf_psu_api.h new file mode 100644 index 0000000000..762863f028 --- /dev/null +++ b/platform/pddf/i2c/modules/include/pddf_psu_api.h @@ -0,0 +1,41 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * + * Description + * PSU driver related api declarations + */ + +#ifndef __PDDF_PSU_API_H__ +#define __PDDF_PSU_API_H__ + +extern void get_psu_duplicate_sysfs(int idx, char *str); +extern ssize_t psu_show_default(struct device *dev, struct device_attribute *da, char *buf); +extern ssize_t psu_store_default(struct device *dev, struct device_attribute *da, const char *buf, size_t count); + +extern int sonic_i2c_get_psu_present_default(void *client, PSU_DATA_ATTR *adata, void *data); +extern int sonic_i2c_get_psu_power_good_default(void *client, PSU_DATA_ATTR *adata, void *data); +extern int sonic_i2c_get_psu_model_name_default(void *client, PSU_DATA_ATTR *adata, void *data); +extern int sonic_i2c_get_psu_mfr_id_default(void *client, PSU_DATA_ATTR *adata, void *data); +extern int sonic_i2c_get_psu_serial_num_default(void *client, PSU_DATA_ATTR *adata, void *data); +extern int sonic_i2c_get_psu_fan_dir_default(void *client, PSU_DATA_ATTR *adata, void *data); +extern int sonic_i2c_get_psu_v_out_default(void *client, PSU_DATA_ATTR *adata, void *data); +extern int sonic_i2c_get_psu_i_out_default(void *client, PSU_DATA_ATTR *adata, void *data); +extern int sonic_i2c_get_psu_p_out_default(void *client, PSU_DATA_ATTR *adata, void *data); +extern int sonic_i2c_get_psu_fan1_speed_rpm_default(void *client, PSU_DATA_ATTR *adata, void *data); +extern int sonic_i2c_get_psu_temp1_input_default(void *client, PSU_DATA_ATTR *adata, void *data); +extern int sonic_i2c_get_psu_v_in_default(void *client, PSU_DATA_ATTR *adata, void *data); +extern int sonic_i2c_get_psu_i_in_default(void *client, PSU_DATA_ATTR *adata, void *data); + +#endif diff --git a/platform/pddf/i2c/modules/include/pddf_psu_defs.h b/platform/pddf/i2c/modules/include/pddf_psu_defs.h new file mode 100644 index 0000000000..60e81a9f58 --- /dev/null +++ b/platform/pddf/i2c/modules/include/pddf_psu_defs.h @@ -0,0 +1,90 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * + * Description: + * Platform PSU defines/structures header file + */ + +#ifndef __PDDF_PSU_DEFS_H__ +#define __PDDF_PSU_DEFS_H__ + + +#define MAX_NUM_PSU 5 +#define MAX_PSU_ATTRS 32 +#define ATTR_NAME_LEN 32 +#define STR_ATTR_SIZE 32 +#define DEV_TYPE_LEN 32 + +/* Each client has this additional data + */ + +typedef struct PSU_DATA_ATTR +{ + char aname[ATTR_NAME_LEN]; // attr name, taken from enum psu_sysfs_attributes + char devtype[DEV_TYPE_LEN]; // either a 'eeprom' or 'cpld', or 'pmbus' attribute + char devname[DEV_TYPE_LEN]; // Name of the device from where this sysfs attr is read + uint32_t devaddr; + uint32_t offset; + uint32_t mask; + uint32_t cmpval; + uint32_t len; + void *access_data; + +}PSU_DATA_ATTR; + +typedef struct PSU_SYSFS_ATTR_DATA +{ + int index; + unsigned short mode; + ssize_t (*show)(struct device *dev, struct device_attribute *da, char *buf); + int (*pre_get)(void *client, PSU_DATA_ATTR *adata, void *data); + int (*do_get)(void *client, PSU_DATA_ATTR *adata, void *data); + int (*post_get)(void *client, PSU_DATA_ATTR *adata, void *data); + ssize_t (*store)(struct device *dev, struct device_attribute *da, const char *buf, size_t count); + int (*pre_set)(void *client, PSU_DATA_ATTR *adata, void *data); + int (*do_set)(void *client, PSU_DATA_ATTR *adata, void *data); + int (*post_set)(void *client, PSU_DATA_ATTR *adata, void *data); + void *data; +} PSU_SYSFS_ATTR_DATA; + +typedef struct PSU_SYSFS_ATTR_DATA_ENTRY +{ + char name[ATTR_NAME_LEN]; + PSU_SYSFS_ATTR_DATA *a_ptr; +} PSU_SYSFS_ATTR_DATA_ENTRY; + + +/* PSU CLIENT DATA - PLATFORM DATA FOR PSU CLIENT */ +typedef struct PSU_DATA +{ + int idx; // psu index + int num_psu_fans; + PSU_DATA_ATTR psu_attr; + int len; // no of valid attributes for this psu client + PSU_DATA_ATTR psu_attrs[MAX_PSU_ATTRS]; +}PSU_DATA; + +typedef struct PSU_PDATA +{ + int idx; // psu index + int num_psu_fans; // num of fans supported by the PSU + int len; // no of valid attributes for this psu client + PSU_DATA_ATTR *psu_attrs; +}PSU_PDATA; + +extern int board_i2c_cpld_read(unsigned short cpld_addr, u8 reg); +extern int board_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); + +#endif diff --git a/platform/pddf/i2c/modules/include/pddf_psu_driver.h b/platform/pddf/i2c/modules/include/pddf_psu_driver.h new file mode 100644 index 0000000000..a2aa3f41d3 --- /dev/null +++ b/platform/pddf/i2c/modules/include/pddf_psu_driver.h @@ -0,0 +1,65 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * + * Description + * PSU driver data structures + */ +#ifndef __PDDF_PSU_DRIVER_H__ +#define __PDDF_PSU_DRIVER_H__ + +enum psu_sysfs_attributes { + PSU_PRESENT, + PSU_MODEL_NAME, + PSU_POWER_GOOD, + PSU_MFR_ID, + PSU_SERIAL_NUM, + PSU_FAN_DIR, + PSU_V_OUT, + PSU_I_OUT, + PSU_P_OUT, /* This is in micro watts to comply with lm-sensors */ + PSU_FAN1_SPEED, + PSU_TEMP1_INPUT, + PSU_V_IN, + PSU_I_IN, + PSU_ATTR_MAX +}; + + +/* Every client has psu_data which is divided into per attribute data */ +struct psu_attr_info { + char name[ATTR_NAME_LEN]; + struct mutex update_lock; + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 status; + union { + char strval[STR_ATTR_SIZE]; + int intval; + u16 shortval; + u8 charval; + }val; +}; +struct psu_data { + struct device *hwmon_dev; + u8 index; + int num_psu_fans; + int num_attr; + struct attribute *psu_attribute_list[MAX_PSU_ATTRS]; + struct attribute_group psu_attribute_group; + struct psu_attr_info attr_info[MAX_PSU_ATTRS]; +}; + + +#endif diff --git a/platform/pddf/i2c/modules/include/pddf_sysstatus_defs.h b/platform/pddf/i2c/modules/include/pddf_sysstatus_defs.h new file mode 100644 index 0000000000..fd23f214d2 --- /dev/null +++ b/platform/pddf/i2c/modules/include/pddf_sysstatus_defs.h @@ -0,0 +1,51 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * + * Description + * Platform system status module structures + */ + +#ifndef __PDDF_SYSSTATUS_DEFS_H__ +#define __PDDF_SYSSTATUS_DEFS_H__ + + +#define ATTR_NAME_LEN 32 +#define MAX_ATTRS 32 + + +/* SYSSTATUS CLIENT DATA - PLATFORM DATA FOR SYSSTATUS CLIENT */ +typedef struct SYSSTATUS_ADDR_ATTR +{ + char aname[ATTR_NAME_LEN]; // attr name + uint32_t devaddr; + uint32_t offset; + uint32_t mask; + uint32_t len; + +}SYSSTATUS_ADDR_ATTR; + + +typedef struct SYSSTATUS_DATA +{ + int len; + SYSSTATUS_ADDR_ATTR sysstatus_addr_attr; + SYSSTATUS_ADDR_ATTR sysstatus_addr_attrs[MAX_ATTRS]; + +}SYSSTATUS_DATA; + + + + +#endif diff --git a/platform/pddf/i2c/modules/include/pddf_xcvr_api.h b/platform/pddf/i2c/modules/include/pddf_xcvr_api.h new file mode 100644 index 0000000000..4a1ce00d55 --- /dev/null +++ b/platform/pddf/i2c/modules/include/pddf_xcvr_api.h @@ -0,0 +1,44 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * + * Description + * Optics driver related api declarations + */ +#ifndef __PDDF_XCVR_API_H__ +#define __PDDF_XCVR_API_H__ + +extern int sonic_i2c_get_mod_pres(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data); +extern int sonic_i2c_get_mod_reset(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data); +extern int sonic_i2c_get_mod_intr_status(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data); +extern int sonic_i2c_get_mod_lpmode(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data); +extern int sonic_i2c_get_mod_rxlos(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data); +extern int sonic_i2c_get_mod_txdisable(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data); +extern int sonic_i2c_get_mod_txfault(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data); +extern int sonic_i2c_set_mod_lpmode(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data); +extern int sonic_i2c_set_mod_reset(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data); +extern int sonic_i2c_set_mod_txdisable(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data); + +extern ssize_t get_module_presence(struct device *dev, struct device_attribute *da, char *buf); +extern ssize_t get_module_reset(struct device *dev, struct device_attribute *da, char *buf); +extern ssize_t set_module_reset(struct device *dev, struct device_attribute *da, const char *buf, size_t count); +extern ssize_t get_module_intr_status(struct device *dev, struct device_attribute *da, char *buf); +extern ssize_t get_module_lpmode(struct device *dev, struct device_attribute *da, char *buf); +extern ssize_t set_module_lpmode(struct device *dev, struct device_attribute *da, const char *buf, size_t count); +extern ssize_t get_module_rxlos(struct device *dev, struct device_attribute *da, char *buf); +extern ssize_t get_module_txdisable(struct device *dev, struct device_attribute *da, char *buf); +extern ssize_t set_module_txdisable(struct device *dev, struct device_attribute *da, const char *buf, size_t count); +extern ssize_t get_module_txfault(struct device *dev, struct device_attribute *da, char *buf); + +#endif diff --git a/platform/pddf/i2c/modules/include/pddf_xcvr_defs.h b/platform/pddf/i2c/modules/include/pddf_xcvr_defs.h new file mode 100644 index 0000000000..63de2eeae0 --- /dev/null +++ b/platform/pddf/i2c/modules/include/pddf_xcvr_defs.h @@ -0,0 +1,121 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * + * Description: + * Platform SFP defines/structures header file + */ + +#ifndef __PDDF_XCVR_DEFS_H__ +#define __PDDF_XCVR_DEFS_H__ + + +#define MAX_NUM_XCVR 5 +#define MAX_XCVR_ATTRS 20 + + +typedef struct XCVR_ATTR +{ + char aname[32]; // attr name, taken from enum xcvr_sysfs_attributes + char devtype[32]; // either a 'eeprom' or 'cpld', or 'pmbus' attribute + char devname[32]; // name of the device from where this sysfs is to be read + uint32_t devaddr; + uint32_t offset; + uint32_t mask; + uint32_t cmpval; + uint32_t len; + + int (*pre_access)(void *client, void *data); + int (*do_access)(void *client, void *data); + int (*post_access)(void *client, void *data); + +}XCVR_ATTR; + +/* XCVR CLIENT DATA - PLATFORM DATA FOR XCVR CLIENT */ +typedef struct XCVR_DATA +{ + int idx; // xcvr index + XCVR_ATTR xcvr_attr; + int len; // no of valid attributes for this xcvr client + XCVR_ATTR xcvr_attrs[MAX_XCVR_ATTRS]; +}XCVR_DATA; + +typedef struct XCVR_PDATA +{ + int idx; // xcvr index + unsigned short addr; // i2c address of the device + int len; // no of valid attributes for this xcvr client + XCVR_ATTR *xcvr_attrs; +}XCVR_PDATA; + + +#define BIT_INDEX(i) (1ULL << (i)) + +/* List of valid port types */ +typedef enum xcvr_port_type_e { + PDDF_PORT_TYPE_INVALID, + PDDF_PORT_TYPE_NOT_PRESENT, + PDDF_PORT_TYPE_SFP, + PDDF_PORT_TYPE_SFP_PLUS, + PDDF_PORT_TYPE_QSFP, + PDDF_PORT_TYPE_QSFP_PLUS, + PDDF_PORT_TYPE_QSFP28 +} xcvr_port_type_t; + +/* Each client has this additional data + */ +struct xcvr_data { + struct device *xdev; + struct mutex update_lock; + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + int index; /* port index */ + xcvr_port_type_t port_type; + uint32_t modpres; + uint32_t reset; + uint32_t intr_status; + uint32_t lpmode; + uint32_t rxlos; + uint32_t txdisable; + uint32_t txfault; +}; + +typedef struct XCVR_SYSFS_ATTR_OPS +{ + int index; + ssize_t (*show)(struct device *dev, struct device_attribute *da, char *buf); + int (*pre_get)(struct i2c_client *client, XCVR_ATTR *adata, struct xcvr_data *data); + int (*do_get)(struct i2c_client *client, XCVR_ATTR *adata, struct xcvr_data *data); + int (*post_get)(struct i2c_client *client, XCVR_ATTR *adata, struct xcvr_data *data); + ssize_t (*store)(struct device *dev, struct device_attribute *da, const char *buf, size_t count); + int (*pre_set)(struct i2c_client *client, XCVR_ATTR *adata, struct xcvr_data *data); + int (*do_set)(struct i2c_client *client, XCVR_ATTR *adata, struct xcvr_data *data); + int (*post_set)(struct i2c_client *client, XCVR_ATTR *adata, struct xcvr_data *data); +} XCVR_SYSFS_ATTR_OPS; + +enum xcvr_sysfs_attributes { + XCVR_PRESENT, + XCVR_RESET, + XCVR_INTR_STATUS, + XCVR_LPMODE, + XCVR_RXLOS, + XCVR_TXDISABLE, + XCVR_TXFAULT, + XCVR_ATTR_MAX +}; + +extern int board_i2c_cpld_read(unsigned short cpld_addr, u8 reg); +extern int board_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); + +#endif diff --git a/platform/pddf/i2c/modules/led/Makefile b/platform/pddf/i2c/modules/led/Makefile new file mode 100644 index 0000000000..0c450ec70b --- /dev/null +++ b/platform/pddf/i2c/modules/led/Makefile @@ -0,0 +1,4 @@ +TARGET := pddf_led_module +obj-m := $(TARGET).o + +CFLAGS_$(obj-m):= -I$(M)/modules/include diff --git a/platform/pddf/i2c/modules/led/pddf_led_module.c b/platform/pddf/i2c/modules/led/pddf_led_module.c new file mode 100644 index 0000000000..362467e5ab --- /dev/null +++ b/platform/pddf/i2c/modules/led/pddf_led_module.c @@ -0,0 +1,659 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * + * A pddf kernel module to manage various LEDs of a switch + */ + +#include +#include +#include +#include +#include +#include +#include "pddf_led_defs.h" +#include "pddf_client_defs.h" +#include +#include +#include + +#define DEBUG 0 +LED_OPS_DATA sys_led_ops_data[1]={0}; +LED_OPS_DATA* psu_led_ops_data=NULL; +LED_OPS_DATA diag_led_ops_data[1]= {0}; +LED_OPS_DATA fan_led_ops_data[1]= {0}; +LED_OPS_DATA loc_led_ops_data[1]= {0}; +LED_OPS_DATA* fantray_led_ops_data=NULL; +LED_OPS_DATA temp_data={0}; +LED_OPS_DATA* dev_list[LED_TYPE_MAX] = { + sys_led_ops_data, + NULL, + fan_led_ops_data, + NULL, + diag_led_ops_data, + loc_led_ops_data, +}; +int num_psus = 0; +int num_fantrays = 0; + +extern int board_i2c_cpld_read(unsigned short cpld_addr, u8 reg); +extern int board_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); +extern ssize_t show_pddf_data(struct device *dev, struct device_attribute *da, char *buf); +extern ssize_t store_pddf_data(struct device *dev, struct device_attribute *da, const char *buf, size_t count); + +static LED_STATUS find_state_index(const char* state_str) { + int index; + char *ptr = (char *)state_str; + while (*ptr && *ptr!= '\n' && *ptr !='\0') ptr++; + *ptr='\0'; + for ( index = 0; index < MAX_LED_STATUS; index++) { + /*int rc = strcmp(state_str, LED_STATUS_STR[index]) ;*/ + if (strcmp(state_str, LED_STATUS_STR[index]) == 0 ) { + return index; + } + } + return MAX_LED_STATUS; +} + +static LED_TYPE get_dev_type(char* name) +{ + LED_TYPE ret = LED_TYPE_MAX; + if(strcasecmp(name, "SYS_LED")==0) { + ret = LED_SYS; + } else if(strcasecmp(name, "FAN_LED")==0) { + ret = LED_FAN; + } else if(strstr(name, "PSU_LED")) { + ret = LED_PSU; + } else if(strcasecmp(name, "DIAG_LED")==0) { + ret = LED_DIAG; + } else if(strcasecmp(name, "LOC_LED")==0) { + ret = LED_LOC; + } else if(strstr(name, "FANTRAY_LED")) { + ret = LED_FANTRAY; + } +#if DEBUG > 1 + pddf_dbg(LED, KERN_INFO "LED get_dev_type: %s; %d\n", name, ret); +#endif + return (ret); +} +static int dev_index_check(LED_TYPE type, int index) +{ +#if DEBUG + pddf_dbg(LED, "dev_index_check: type:%s index:%d num_psus:%d num_fantrays:%d\n", + LED_TYPE_STR[type], index, num_psus, num_fantrays); +#endif + switch(type) + { + case LED_PSU: + if(index >= num_psus) return (-1); + break; + case LED_FANTRAY: + if(index >= num_fantrays) return (-1); + break; + default: + if(index >= 1) return (-1); + break; + } + return (0); +} + +static LED_OPS_DATA* find_led_ops_data(struct device_attribute *da) +{ + struct pddf_data_attribute *_ptr = (struct pddf_data_attribute *)da; + LED_OPS_DATA* ptr=(LED_OPS_DATA*)_ptr->addr; + LED_TYPE led_type; + if(!ptr || strlen(ptr->device_name)==0 ) return(NULL); + + + if((led_type=get_dev_type(ptr->device_name))==LED_TYPE_MAX) { + printk(KERN_ERR "PDDF_LED ERROR *%s Unsupported Led Type\n", __func__); + return(NULL); + } + if(dev_index_check(led_type, ptr->index)==-1) { + printk(KERN_ERR "PDDF_LED ERROR %s invalid index: %d for type:%s\n", __func__, ptr->index, ptr->device_name); + return(NULL); + } +#if DEBUG > 1 + pddf_dbg(LED, "find_led_ops_data: name:%s; index=%d tempAddr:%p actualAddr:%p\n", + ptr->device_name, ptr->index, ptr, dev_list[led_type]+ptr->index); +#endif + return (dev_list[led_type]+ptr->index); +} + +static void print_led_data(LED_OPS_DATA *ptr, LED_STATUS state) +{ + int i = 0; + if(!ptr) return ; + pddf_dbg(LED, KERN_INFO "Print %s index:%d num_psus:%d num_fantrays:%d ADDR=%p\n", + ptr->device_name, ptr->index, num_psus, num_fantrays, ptr); + pddf_dbg(LED, KERN_INFO "\tindex: %d\n", ptr->index); + pddf_dbg(LED, KERN_INFO "\tcur_state: %d; %s \n", ptr->cur_state.state, ptr->cur_state.color); + for (i = 0; i< MAX_LED_STATUS; i++) { + if(ptr->data[i].swpld_addr && (i == state || state == -1)) { + pddf_dbg(LED, KERN_INFO "\t\t[%s]: addr/offset:0x%x;0x%x color:%s; value:%x; mask_bits: 0x%x; pos:%d\n", + LED_STATUS_STR[i], + ptr->data[i].swpld_addr, ptr->data[i].swpld_addr_offset, + LED_STATUS_STR[i], ptr->data[i].value, ptr->data[i].bits.mask_bits, ptr->data[i].bits.pos); + } + } +} + +ssize_t get_status_led(struct device_attribute *da) +{ + int ret=0; + struct pddf_data_attribute *_ptr = (struct pddf_data_attribute *)da; + LED_OPS_DATA* temp_data_ptr=(LED_OPS_DATA*)_ptr->addr; + LED_OPS_DATA* ops_ptr=find_led_ops_data(da); + uint32_t color_val=0, sys_val=0; + int state=0; + if (!ops_ptr) { + pddf_dbg(LED, KERN_ERR "ERROR %s: Cannot find LED Ptr", __func__); + return (-1); + } + if (ops_ptr->swpld_addr == 0x0) { + pddf_dbg(LED, KERN_ERR "ERROR %s: device: %s %d not configured\n", __func__, + temp_data_ptr->device_name, temp_data_ptr->index); + return (-1); + } + sys_val = board_i2c_cpld_read(ops_ptr->swpld_addr, ops_ptr->swpld_addr_offset); + if (sys_val < 0) + return sys_val; + + strcpy(temp_data.cur_state.color, "None"); + for (state=0; statedata[state].bits.mask_bits); + if ((color_val ^ (ops_ptr->data[state].value<data[state].bits.pos))==0) { + strcpy(temp_data.cur_state.color, LED_STATUS_STR[state]); + } + } +#if DEBUG > 1 + pddf_dbg(LED, KERN_ERR "Get : %s:%d addr/offset:0x%x; 0x%x value=0x%x [%s]\n", + ops_ptr->device_name, ops_ptr->index, + ops_ptr->swpld_addr, ops_ptr->swpld_addr_offset, sys_val, + temp_data.cur_state.color); +#endif + + return(ret); +} + +ssize_t set_status_led(struct device_attribute *da) +{ + int ret=0; + uint32_t sys_val=0, new_val=0; + LED_STATUS cur_state = MAX_LED_STATUS; + struct pddf_data_attribute *_ptr = (struct pddf_data_attribute *)da; + LED_OPS_DATA* temp_data_ptr=(LED_OPS_DATA*)_ptr->addr; + LED_OPS_DATA* ops_ptr=find_led_ops_data(da); + char* _buf=temp_data_ptr->cur_state.color; + + if (!ops_ptr) { + pddf_dbg(LED, KERN_ERR "PDDF_LED ERROR %s: Cannot find LED Ptr", __func__); + return (-1); + } + if (ops_ptr->swpld_addr == 0x0) { + pddf_dbg(LED, KERN_ERR "PDDF_LED ERROR %s: device: %s %d not configured\n", + __func__, ops_ptr->device_name, ops_ptr->index); + return (-1); + } + pddf_dbg(LED, KERN_ERR "%s: Set [%s;%d] color[%s]\n", __func__, + temp_data_ptr->device_name, temp_data_ptr->index, + temp_data_ptr->cur_state.color); + cur_state = find_state_index(_buf); + + if (cur_state == MAX_LED_STATUS) { + pddf_dbg(LED, KERN_ERR "ERROR %s: not supported: %s\n", _buf, __func__); + return (-1); + } + + if(ops_ptr->data[cur_state].swpld_addr != 0x0) { + sys_val = board_i2c_cpld_read(ops_ptr->swpld_addr, ops_ptr->swpld_addr_offset); + if (sys_val < 0) + return sys_val; + + new_val = (sys_val & ops_ptr->data[cur_state].bits.mask_bits) | + (ops_ptr->data[cur_state].value << ops_ptr->data[cur_state].bits.pos); + + } else { + pddf_dbg(LED, KERN_ERR "ERROR %s: %s %d state %d; %s not configured\n",__func__, + ops_ptr->device_name, ops_ptr->index, cur_state, _buf); + return (-1); + } + + board_i2c_cpld_write(ops_ptr->swpld_addr, ops_ptr->swpld_addr_offset, new_val); + pddf_dbg(LED, KERN_INFO "Set color:%s; 0x%x:0x%x sys_val:0x%x new_val:0x%x read:0x%x\n", + LED_STATUS_STR[cur_state], + ops_ptr->swpld_addr, ops_ptr->swpld_addr_offset, + sys_val, new_val, + ret = board_i2c_cpld_read(ops_ptr->swpld_addr, ops_ptr->swpld_addr_offset)); + if (ret < 0) + { + pddf_dbg(LED, KERN_ERR "PDDF_LED ERROR %s: Error %d in reading from cpld(0x%x) offset 0x%x\n", __FUNCTION__, ret, ops_ptr->swpld_addr, ops_ptr->swpld_addr_offset); + return ret; + } + return(ret); +} + + +ssize_t show_pddf_data(struct device *dev, struct device_attribute *da, + char *buf) +{ + int ret = 0; + struct pddf_data_attribute *ptr = (struct pddf_data_attribute *)da; + switch(ptr->type) + { + case PDDF_CHAR: + ret = sprintf(buf, "%s\n", ptr->addr); + break; + case PDDF_INT_DEC: + ret = sprintf(buf, "%d\n", *(int*)(ptr->addr)); + break; + case PDDF_INT_HEX: + ret = sprintf(buf, "0x%x\n", *(int*)(ptr->addr)); + break; + case PDDF_USHORT: + ret = sprintf(buf, "0x%x\n", *(unsigned short *)(ptr->addr)); + break; + case PDDF_UINT32: + ret = sprintf(buf, "0x%x\n", *(uint32_t *)(ptr->addr)); + break; + default: + break; + } +#if DEBUG > 1 + pddf_dbg(LED, "[ READ ] DATA ATTR PTR [%s] TYPE:%d, Value:[%s]\n", + ptr->dev_attr.attr.name, ptr->type, buf); +#endif + return ret; +} + +ssize_t store_pddf_data(struct device *dev, struct device_attribute *da, const char *buf, size_t count) +{ + int ret = 0, num = 0; + struct pddf_data_attribute *ptr = (struct pddf_data_attribute *)da; + switch(ptr->type) + { + case PDDF_CHAR: + strncpy(ptr->addr, buf, strlen(buf)-1); // to discard newline char form buf + ptr->addr[strlen(buf)-1] = '\0'; +#if DEBUG + pddf_dbg(LED, KERN_ERR "[ WRITE ] ATTR PTR [%s] PDDF_CHAR VALUE:%s\n", + ptr->dev_attr.attr.name, ptr->addr); +#endif + break; + case PDDF_INT_DEC: + ret = kstrtoint(buf,10,&num); + if (ret==0) + *(int *)(ptr->addr) = num; +#if DEBUG + pddf_dbg(LED, KERN_ERR "[ WRITE ] ATTR PTR [%s] PDDF_DEC VALUE:%d\n", + ptr->dev_attr.attr.name, *(int *)(ptr->addr)); +#endif + break; + case PDDF_INT_HEX: + ret = kstrtoint(buf,16,&num); + if (ret==0) + *(int *)(ptr->addr) = num; +#if DEBUG + pddf_dbg(LED, KERN_ERR "[ WRITE ] ATTR PTR [%s] PDDF_HEX VALUE:0x%x\n", + ptr->dev_attr.attr.name, *(int *)(ptr->addr)); +#endif + break; + case PDDF_USHORT: + ret = kstrtoint(buf,16,&num); + if (ret==0) + *(unsigned short *)(ptr->addr) = (unsigned short)num; +#if DEBUG + pddf_dbg(LED, KERN_ERR "[ WRITE ] ATTR PTR [%s] PDDF_USHORT VALUE:%x\n", + ptr->dev_attr.attr.name, *(unsigned short *)(ptr->addr)); +#endif + break; + case PDDF_UINT32: + ret = kstrtoint(buf,16,&num); + if (ret==0) + *(uint32_t *)(ptr->addr) = (uint32_t)num; +#if DEBUG + pddf_dbg(LED, KERN_ERR "[ WRITE ] ATTR PTR [%s] PDDF_UINT32 VALUE:%d\n", + ptr->dev_attr.attr.name, *(uint32_t *)(ptr->addr)); +#endif + break; + default: + break; + } + return count; +} + +static int load_led_ops_data(struct device_attribute *da, LED_STATUS state) +{ + struct pddf_data_attribute *_ptr = (struct pddf_data_attribute *)da; + LED_OPS_DATA* ptr=(LED_OPS_DATA*)_ptr->addr; + LED_TYPE led_type; + LED_OPS_DATA* ops_ptr=NULL; + if(!ptr || strlen(ptr->device_name)==0 ) { + pddf_dbg(LED, KERN_INFO "SYSTEM_LED: load_led_ops_data return -1 device_name:%s\n", ptr? ptr->device_name:"NULL"); + return(-1); + } + if(ptr->device_name) + { + pddf_dbg(LED, KERN_INFO "[%s]: load_led_ops_data: index=%d addr=0x%x;0x%x valu=0x%x\n", + ptr->device_name, ptr->index, ptr->swpld_addr, ptr->swpld_addr_offset, ptr->data[0].value); + } + if((led_type=get_dev_type(ptr->device_name))==LED_TYPE_MAX) { + pddf_dbg(LED, KERN_ERR "PDDF_LED ERROR *%s Unsupported Led Type\n", __func__); + return(-1); + } + if(dev_index_check(led_type, ptr->index)==-1) { + pddf_dbg(LED, KERN_ERR "PDDF_LED ERROR %s invalid index: %d for type:%d\n", __func__, ptr->index, led_type); + return(-1); + } + ops_ptr = dev_list[led_type]+ptr->index; + + memcpy(ops_ptr->device_name, ptr->device_name, sizeof(ops_ptr->device_name)); + ops_ptr->index = ptr->index; + memcpy(&ops_ptr->data[state], &ptr->data[0], sizeof(LED_DATA)); + ops_ptr->data[state].swpld_addr = ptr->swpld_addr; + ops_ptr->data[state].swpld_addr_offset = ptr->swpld_addr_offset; + ops_ptr->swpld_addr = ptr->swpld_addr; + ops_ptr->swpld_addr_offset = ptr->swpld_addr_offset; + + print_led_data(dev_list[led_type]+ptr->index, state); + + memset(ptr, 0, sizeof(LED_OPS_DATA)); + return (0); +} + +static int show_led_ops_data(struct device_attribute *da) +{ + LED_OPS_DATA* ops_ptr=find_led_ops_data(da); + print_led_data(ops_ptr, -1); + return(0); +} + +static int verify_led_ops_data(struct device_attribute *da) +{ + struct pddf_data_attribute *_ptr = (struct pddf_data_attribute *)da; + LED_OPS_DATA* ptr=(LED_OPS_DATA*)_ptr->addr; + LED_OPS_DATA* ops_ptr=find_led_ops_data(da); + + if(ops_ptr) + memcpy(ptr, ops_ptr, sizeof(LED_OPS_DATA)); + else + { + pddf_dbg(LED, "SYSTEM_LED: verify_led_ops_data: Failed to find ops_ptr name:%s; index=%d\n", ptr->device_name, ptr->index); + } + return (0); +} + + +ssize_t dev_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count) +{ +#if DEBUG + pddf_dbg(LED, KERN_INFO "dev_operation [%s]\n", buf); +#endif + if(strstr(buf, "STATUS_LED_COLOR")!= NULL) { + LED_STATUS index = find_state_index(buf); + if (index < MAX_LED_STATUS ) { + load_led_ops_data(da, index); + } else { + printk(KERN_ERR "PDDF_ERROR %s: Invalid state for dev_ops %s", __FUNCTION__, buf); + } + } + else if(strncmp(buf, "show", strlen("show"))==0 ) { + show_led_ops_data(da); + } + else if(strncmp(buf, "verify", strlen("verify"))==0 ) { + verify_led_ops_data(da); + } + else if(strncmp(buf, "get_status", strlen("get_status"))==0 ) { + get_status_led(da); + } + else if(strncmp(buf, "set_status", strlen("set_status"))==0 ) { + set_status_led(da); + } + else { + printk(KERN_ERR "PDDF_ERROR %s: Invalid value for dev_ops %s", __FUNCTION__, buf); + } + return(count); +} + +ssize_t store_config_data(struct device *dev, struct device_attribute *da, const char *buf, size_t count) +{ + int ret, num; + struct pddf_data_attribute *ptr = (struct pddf_data_attribute *)da; + if(strncmp(ptr->dev_attr.attr.name, "num_psus", strlen("num_psus"))==0 ) { + ret = kstrtoint(buf,10,&num); + if (ret==0) + *(int *)(ptr->addr) = num; + if(psu_led_ops_data == NULL) { + if ((psu_led_ops_data = kzalloc(num * sizeof(LED_OPS_DATA), GFP_KERNEL)) == NULL) { + printk(KERN_ERR "PDDF_LED ERROR failed to allocate memory for PSU LED\n"); + return (count); + } + pddf_dbg(LED, "Allocate PSU LED Memory ADDR=%p\n", psu_led_ops_data); + dev_list[LED_PSU]=psu_led_ops_data; + } +#if DEBUG + pddf_dbg(LED, "[ WRITE ] ATTR CONFIG [%s] VALUE:%d; %d\n", + ptr->dev_attr.attr.name, num, num_psus); +#endif + return(count); + } + if(strncmp(ptr->dev_attr.attr.name, "num_fantrays", strlen("num_fantrays"))==0 ) { + ret = kstrtoint(buf,10,&num); + if (ret==0) + *(int *)(ptr->addr) = num; + if (fantray_led_ops_data == NULL) { + if ((fantray_led_ops_data = kzalloc(num * sizeof(LED_OPS_DATA), GFP_KERNEL)) == NULL) { + printk(KERN_ERR "PDDF_LED ERROR failed to allocate memory for FANTRAY LED\n"); + return (count); + } + pddf_dbg(LED, "Allocate FanTray LED Memory ADDR=%p\n", fantray_led_ops_data); + dev_list[LED_FANTRAY]=fantray_led_ops_data; + } +#if DEBUG + pddf_dbg(LED, "[ WRITE ] ATTR CONFIG [%s] VALUE:%d; %d\n", + ptr->dev_attr.attr.name, num, num_fantrays); +#endif + return(count); + } + return (count); +} + +ssize_t store_bits_data(struct device *dev, struct device_attribute *da, const char *buf, size_t count) +{ + int len = 0, num1 = 0, num2 = 0, i=0, rc1=0, rc2=0; + char mask=0xFF; + char *pptr=NULL; + char bits[NAME_SIZE]; + struct pddf_data_attribute *ptr = (struct pddf_data_attribute *)da; + MASK_BITS* bits_ptr=(MASK_BITS*)(ptr->addr); + strncpy(bits_ptr->bits, buf, strlen(buf)-1); // to discard newline char form buf + bits_ptr->bits[strlen(buf)-1] = '\0'; + if((pptr=strstr(buf,":")) != NULL) { + len=pptr-buf; + sprintf(bits, buf); + bits[len]='\0'; + rc1=kstrtoint(bits,16,&num1); + if (rc1==0) + { + sprintf(bits, ++pptr); + rc2=kstrtoint(bits,16,&num2); + if (rc2==0) + { + for (i=num2; i<=num1; i++) { + mask &= ~(1 << i); + } + bits_ptr->mask_bits = mask; + bits_ptr->pos = num2; + } + } + } else { + rc1=kstrtoint(buf,16,&num1); + if (rc1==0) + { + bits_ptr->mask_bits = mask & ~(1 << num1); + bits_ptr->pos = num1; + } + } +#if DEBUG + pddf_dbg(LED, KERN_ERR "[ WRITE ] ATTR PTR Bits [%s] VALUE:%s mask:0x%x; pos:0x%x\n", + ptr->dev_attr.attr.name, bits_ptr->bits, bits_ptr->mask_bits, bits_ptr->pos); +#endif + return (count); +} + +/************************************************************************** + * platform/ attributes + **************************************************************************/ +PDDF_LED_DATA_ATTR(platform, num_psus, S_IWUSR|S_IRUGO, show_pddf_data, + store_config_data, PDDF_INT_DEC, sizeof(int), (void*)&num_psus); +PDDF_LED_DATA_ATTR(platform, num_fantrays, S_IWUSR|S_IRUGO, show_pddf_data, + store_config_data, PDDF_INT_DEC, sizeof(int), (void*)&num_fantrays); + +struct attribute* attrs_platform[]={ + &pddf_dev_platform_attr_num_psus.dev_attr.attr, + &pddf_dev_platform_attr_num_fantrays.dev_attr.attr, + NULL, +}; +struct attribute_group attr_group_platform={ + .attrs = attrs_platform, +}; + +/************************************************************************** + * led/ attributes + **************************************************************************/ +PDDF_LED_DATA_ATTR(dev, device_name, S_IWUSR|S_IRUGO, show_pddf_data, + store_pddf_data, PDDF_CHAR, NAME_SIZE, (void*)&temp_data.device_name); +PDDF_LED_DATA_ATTR(dev, index, S_IWUSR|S_IRUGO, show_pddf_data, + store_pddf_data, PDDF_INT_DEC, sizeof(int), (void*)&temp_data.index); +PDDF_LED_DATA_ATTR(dev, swpld_addr, S_IWUSR|S_IRUGO, show_pddf_data, + store_pddf_data, PDDF_INT_HEX, sizeof(int), (void*)&temp_data.swpld_addr); +PDDF_LED_DATA_ATTR(dev, swpld_addr_offset, S_IWUSR|S_IRUGO, show_pddf_data, + store_pddf_data, PDDF_INT_HEX, sizeof(int), (void*)&temp_data.swpld_addr_offset); +PDDF_LED_DATA_ATTR(dev, dev_ops , S_IWUSR, NULL, + dev_operation, PDDF_CHAR, NAME_SIZE, (void*)&temp_data); + +struct attribute* attrs_dev[]={ + &pddf_dev_dev_attr_device_name.dev_attr.attr, + &pddf_dev_dev_attr_index.dev_attr.attr, + &pddf_dev_dev_attr_swpld_addr.dev_attr.attr, + &pddf_dev_dev_attr_swpld_addr_offset.dev_attr.attr, + &pddf_dev_dev_attr_dev_ops.dev_attr.attr, + NULL, +}; +struct attribute_group attr_group_dev={ + .attrs = attrs_dev, +}; + +/************************************************************************** + * state_attr/ attributes + **************************************************************************/ +#define LED_DEV_STATE_ATTR_GROUP(name, func) \ + PDDF_LED_DATA_ATTR(name, bits, S_IWUSR|S_IRUGO, show_pddf_data, \ + store_bits_data, PDDF_CHAR, NAME_SIZE, func.bits.bits); \ + PDDF_LED_DATA_ATTR(name, value, S_IWUSR|S_IRUGO, show_pddf_data, \ + store_pddf_data, PDDF_USHORT, sizeof(unsigned short), func.value); \ + struct attribute* attrs_##name[]={ \ + &pddf_dev_##name##_attr_bits.dev_attr.attr, \ + &pddf_dev_##name##_attr_value.dev_attr.attr, \ + NULL, \ + }; \ + struct attribute_group attr_group_##name={ \ + .attrs = attrs_##name, \ + }; \ + + +LED_DEV_STATE_ATTR_GROUP(state_attr, (void*)&temp_data.data[0]) + +/************************************************************************** + * cur_state/ attributes + **************************************************************************/ +PDDF_LED_DATA_ATTR(cur_state, color, S_IWUSR|S_IRUGO, show_pddf_data, + store_pddf_data, PDDF_CHAR, NAME_SIZE, (void*)&temp_data.cur_state.color); + +struct attribute* attrs_cur_state[]={ + &pddf_dev_cur_state_attr_color.dev_attr.attr, + NULL, +}; +struct attribute_group attr_group_cur_state={ + .attrs = attrs_cur_state, +}; + +/*************************************************************************/ +#define KOBJ_FREE(obj) \ + if(obj) kobject_put(obj); \ + +void free_kobjs(void) +{ + KOBJ_FREE(cur_state_kobj) + KOBJ_FREE(state_attr_kobj) + KOBJ_FREE(led_kobj) + KOBJ_FREE(platform_kobj) +} + +int KBOJ_CREATE(char* name, struct kobject* parent, struct kobject** child) +{ + if (parent) { + *child = kobject_create_and_add(name, parent); + } else { + printk(KERN_ERR "PDDF_LED ERROR to create %s kobj; null parent\n", name); + free_kobjs(); + return (-ENOMEM); + } + return (0); +} + +int LED_DEV_ATTR_CREATE(struct kobject *kobj, const struct attribute_group *attr, const char* name) +{ + int status = sysfs_create_group(kobj, attr); + if(status) { + pddf_dbg(LED, KERN_ERR "Driver ERROR: sysfs_create %s failed rc=%d\n", name, status); + } + return (status); +} + + +static int __init led_init(void) { + struct kobject *device_kobj; + pddf_dbg(LED, KERN_INFO "PDDF GENERIC LED MODULE init..\n"); + + device_kobj = get_device_i2c_kobj(); + if(!device_kobj) + return -ENOMEM; + + KBOJ_CREATE("platform", device_kobj, &platform_kobj); + KBOJ_CREATE("led", device_kobj, &led_kobj); + KBOJ_CREATE("state_attr", led_kobj, &state_attr_kobj); + KBOJ_CREATE("cur_state", led_kobj, &cur_state_kobj); + + LED_DEV_ATTR_CREATE(platform_kobj, &attr_group_platform, "attr_group_platform"); + LED_DEV_ATTR_CREATE(led_kobj, &attr_group_dev, "attr_group_dev"); + LED_DEV_ATTR_CREATE(state_attr_kobj, &attr_group_state_attr, "attr_group_state_attr"); + LED_DEV_ATTR_CREATE(cur_state_kobj, &attr_group_cur_state, "attr_group_cur_state"); + return (0); +} + + +static void __exit led_exit(void) { + pddf_dbg(LED, "PDDF GENERIC LED MODULE exit..\n"); + free_kobjs(); + if(psu_led_ops_data) kfree(psu_led_ops_data); + if(fantray_led_ops_data) kfree(fantray_led_ops_data); +} + +module_init(led_init); +module_exit(led_exit); + +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("led driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/pddf/i2c/modules/mux/Makefile b/platform/pddf/i2c/modules/mux/Makefile new file mode 100644 index 0000000000..486e703343 --- /dev/null +++ b/platform/pddf/i2c/modules/mux/Makefile @@ -0,0 +1,4 @@ + +obj-m := pddf_mux_module.o + +CFLAGS_$(obj-m):= -I$(M)/modules/include diff --git a/platform/pddf/i2c/modules/mux/pddf_mux_module.c b/platform/pddf/i2c/modules/mux/pddf_mux_module.c new file mode 100644 index 0000000000..b0cd9e761c --- /dev/null +++ b/platform/pddf/i2c/modules/mux/pddf_mux_module.c @@ -0,0 +1,211 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * + * A pddf kernel module to create I2C client for pca954x type of multiplexer + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pddf_client_defs.h" +#include "pddf_mux_defs.h" + + +static ssize_t do_device_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count); +extern void* get_device_table(char *name); +extern void delete_device_table(char *name); + + +MUX_DATA mux_data = {0}; + +/* MUX CLIENT DATA */ +PDDF_DATA_ATTR(virt_bus, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_HEX, sizeof(int), (void*)&mux_data.virt_bus, NULL); +PDDF_DATA_ATTR(dev_ops, S_IWUSR, NULL, do_device_operation, PDDF_CHAR, 8, (void*)&mux_data, (void*)&pddf_data); + + + +static struct attribute *mux_attributes[] = { + &attr_virt_bus.dev_attr.attr, + &attr_dev_ops.dev_attr.attr, + NULL +}; + +static const struct attribute_group pddf_mux_client_data_group = { + .attrs = mux_attributes, +}; + +struct i2c_board_info *i2c_get_mux_board_info(MUX_DATA* mdata, NEW_DEV_ATTR *device_data) +{ + static struct i2c_board_info board_info; + static struct pca954x_platform_mode platform_modes[8]; + static struct pca954x_platform_data mux_platform_data; + int num_modes, i; + + if (strncmp(device_data->dev_type, "pca9548", strlen("pca9548")) == 0) + num_modes = 8; + else if (strncmp(device_data->dev_type, "pca9546", strlen("pca9546")) == 0) + num_modes = 6; + else + { + printk(KERN_ERR "%s: Unknown type of mux device\n", __FUNCTION__); + return NULL; + } + + for(i = 0; i < num_modes; i++) { + platform_modes[i] = (struct pca954x_platform_mode) { + .adap_id = (mdata->virt_bus + i), + .deselect_on_exit = 1, + }; + } + + mux_platform_data = (struct pca954x_platform_data) { + .modes = platform_modes, + .num_modes = num_modes, + }; + + board_info = (struct i2c_board_info) { + .platform_data = &mux_platform_data, + }; + + board_info.addr = device_data->dev_addr; + strcpy(board_info.type, device_data->dev_type); + + return &board_info; +} + + +static ssize_t do_device_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count) +{ + PDDF_ATTR *ptr = (PDDF_ATTR *)da; + MUX_DATA *mux_ptr = (MUX_DATA *)(ptr->addr); + NEW_DEV_ATTR *device_ptr = (NEW_DEV_ATTR *)(ptr->data); + struct i2c_adapter *adapter; + struct i2c_board_info *board_info; + struct i2c_client *client_ptr; + + if (strncmp(buf, "add", strlen(buf)-1)==0) + { + adapter = i2c_get_adapter(device_ptr->parent_bus); + board_info = i2c_get_mux_board_info(mux_ptr, device_ptr); + + client_ptr = i2c_new_device(adapter, board_info); + + if (client_ptr != NULL) + { + i2c_put_adapter(adapter); + pddf_dbg(MUX, KERN_ERR "Created %s client: 0x%p\n", device_ptr->i2c_name, (void *)client_ptr); + add_device_table(device_ptr->i2c_name, (void*)client_ptr); + } + else + { + i2c_put_adapter(adapter); + goto free_data; + } + } + else if (strncmp(buf, "delete", strlen(buf)-1)==0) + { + /*Get the i2c_client handle for the created client*/ + client_ptr = (struct i2c_client *)get_device_table(device_ptr->i2c_name); + if (client_ptr) + { + pddf_dbg(MUX, KERN_ERR "Removing %s client: 0x%p\n", device_ptr->i2c_name, (void *)client_ptr); + i2c_unregister_device(client_ptr); + /*TODO: Nullyfy the platform data*/ + delete_device_table(device_ptr->i2c_name); + } + else + { + printk(KERN_ERR "Unable to get the client handle for %s\n", device_ptr->i2c_name); + } + } + else + { + printk(KERN_ERR "PDDF_ERROR: %s: Invalid value for dev_ops %s", __FUNCTION__, buf); + } + +free_data: + memset(mux_ptr, 0, sizeof(MUX_DATA)); + /*TODO: free the device_ptr->data is dynamically allocated*/ + memset(device_ptr, 0 , sizeof(NEW_DEV_ATTR)); + + return count; +} + + +static struct kobject *mux_kobj; + +int __init mux_data_init(void) +{ + struct kobject *device_kobj; + int ret = 0; + + + pddf_dbg(MUX, "MUX_DATA MODULE.. init\n"); + + device_kobj = get_device_i2c_kobj(); + if(!device_kobj) + return -ENOMEM; + + mux_kobj = kobject_create_and_add("mux", device_kobj); + if(!mux_kobj) + return -ENOMEM; + + + ret = sysfs_create_group(mux_kobj, &pddf_clients_data_group); + if (ret) + { + kobject_put(mux_kobj); + return ret; + } + pddf_dbg(MUX, "CREATED PDDF I2C CLIENTS CREATION SYSFS GROUP\n"); + + ret = sysfs_create_group(mux_kobj, &pddf_mux_client_data_group); + if (ret) + { + sysfs_remove_group(mux_kobj, &pddf_clients_data_group); + kobject_put(mux_kobj); + return ret; + } + pddf_dbg(MUX, "CREATED MUX DATA SYSFS GROUP\n"); + + return ret; +} + +void __exit mux_data_exit(void) +{ + pddf_dbg(MUX, "MUX_DATA MODULE.. exit\n"); + sysfs_remove_group(mux_kobj, &pddf_mux_client_data_group); + sysfs_remove_group(mux_kobj, &pddf_clients_data_group); + kobject_put(mux_kobj); + pddf_dbg(MUX, KERN_ERR "%s: Removed the kobjects for 'mux'\n",__FUNCTION__); + return; +} + +module_init(mux_data_init); +module_exit(mux_data_exit); + +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("mux platform data"); +MODULE_LICENSE("GPL"); diff --git a/platform/pddf/i2c/modules/psu/Makefile b/platform/pddf/i2c/modules/psu/Makefile new file mode 100644 index 0000000000..04db30dfb4 --- /dev/null +++ b/platform/pddf/i2c/modules/psu/Makefile @@ -0,0 +1,4 @@ +subdir-m := driver +obj-m := pddf_psu_module.o + +CFLAGS_$(obj-m):= -I$(M)/modules/include diff --git a/platform/pddf/i2c/modules/psu/driver/Makefile b/platform/pddf/i2c/modules/psu/driver/Makefile new file mode 100644 index 0000000000..86d5080513 --- /dev/null +++ b/platform/pddf/i2c/modules/psu/driver/Makefile @@ -0,0 +1,6 @@ +TARGET = pddf_psu_driver_module +obj-m := $(TARGET).o + +$(TARGET)-objs := pddf_psu_api.o pddf_psu_driver.o + +ccflags-y := -I$(M)/modules/include diff --git a/platform/pddf/i2c/modules/psu/driver/pddf_psu_api.c b/platform/pddf/i2c/modules/psu/driver/pddf_psu_api.c new file mode 100644 index 0000000000..b6b5e306a0 --- /dev/null +++ b/platform/pddf/i2c/modules/psu/driver/pddf_psu_api.c @@ -0,0 +1,707 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * + * Description of various APIs related to PSU component + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pddf_psu_defs.h" +#include "pddf_psu_driver.h" + + +/*#define PSU_DEBUG*/ +#ifdef PSU_DEBUG +#define psu_dbg(...) printk(__VA_ARGS__) +#else +#define psu_dbg(...) +#endif + + +void get_psu_duplicate_sysfs(int idx, char *str) +{ + switch (idx) + { + case PSU_V_OUT: + strcpy(str, "in3_input"); + break; + case PSU_I_OUT: + strcpy(str, "curr2_input"); + break; + case PSU_P_OUT: + strcpy(str, "power2_input"); + break; + case PSU_FAN1_SPEED: + strcpy(str, "fan1_input"); + break; + case PSU_TEMP1_INPUT: + strcpy(str, "temp1_input"); + break; + default: + break; + } + + return; +} + +static int two_complement_to_int(u16 data, u8 valid_bit, int mask) +{ + u16 valid_data = data & mask; + bool is_negative = valid_data >> (valid_bit - 1); + + return is_negative ? (-(((~valid_data) & mask) + 1)) : valid_data; +} + +int psu_update_hw(struct device *dev, struct psu_attr_info *info, PSU_DATA_ATTR *udata) +{ + int status = 0; + struct i2c_client *client = to_i2c_client(dev); + PSU_SYSFS_ATTR_DATA *sysfs_attr_data = NULL; + + + mutex_lock(&info->update_lock); + + sysfs_attr_data = udata->access_data; + if (sysfs_attr_data->pre_set != NULL) + { + status = (sysfs_attr_data->pre_set)(client, udata, info); + if (status!=0) + printk(KERN_ERR "%s: pre_set function fails for %s attribute\n", __FUNCTION__, udata->aname); + } + if (sysfs_attr_data->do_set != NULL) + { + status = (sysfs_attr_data->do_set)(client, udata, info); + if (status!=0) + printk(KERN_ERR "%s: do_set function fails for %s attribute\n", __FUNCTION__, udata->aname); + + } + if (sysfs_attr_data->post_set != NULL) + { + status = (sysfs_attr_data->post_set)(client, udata, info); + if (status!=0) + printk(KERN_ERR "%s: post_set function fails for %s attribute\n", __FUNCTION__, udata->aname); + } + + mutex_unlock(&info->update_lock); + + return 0; +} + + +int psu_update_attr(struct device *dev, struct psu_attr_info *data, PSU_DATA_ATTR *udata) +{ + int status = 0; + struct i2c_client *client = to_i2c_client(dev); + PSU_SYSFS_ATTR_DATA *sysfs_attr_data=NULL; + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || !data->valid) + { + dev_dbg(&client->dev, "Starting update for %s\n", data->name); + + sysfs_attr_data = udata->access_data; + if (sysfs_attr_data->pre_get != NULL) + { + status = (sysfs_attr_data->pre_get)(client, udata, data); + if (status!=0) + printk(KERN_ERR "%s: pre_get function fails for %s attribute\n", __FUNCTION__, udata->aname); + } + if (sysfs_attr_data->do_get != NULL) + { + status = (sysfs_attr_data->do_get)(client, udata, data); + if (status!=0) + printk(KERN_ERR "%s: do_get function fails for %s attribute\n", __FUNCTION__, udata->aname); + + } + if (sysfs_attr_data->post_get != NULL) + { + status = (sysfs_attr_data->post_get)(client, udata, data); + if (status!=0) + printk(KERN_ERR "%s: post_get function fails for %s attribute\n", __FUNCTION__, udata->aname); + } + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + return 0; +} + +ssize_t psu_show_default(struct device *dev, struct device_attribute *da, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct psu_data *data = i2c_get_clientdata(client); + PSU_PDATA *pdata = (PSU_PDATA *)(client->dev.platform_data); + PSU_DATA_ATTR *usr_data = NULL; + struct psu_attr_info *sysfs_attr_info = NULL; + int i, status=0; + u16 value = 0; + int exponent, mantissa; + int multiplier = 1000; + char new_str[ATTR_NAME_LEN] = ""; + PSU_SYSFS_ATTR_DATA *ptr = NULL; + + for (i=0;inum_attr;i++) + { + ptr = (PSU_SYSFS_ATTR_DATA *)pdata->psu_attrs[i].access_data; + get_psu_duplicate_sysfs(ptr->index , new_str); + if ( strcmp(attr->dev_attr.attr.name, pdata->psu_attrs[i].aname) == 0 || strcmp(attr->dev_attr.attr.name, new_str) == 0 ) + { + sysfs_attr_info = &data->attr_info[i]; + usr_data = &pdata->psu_attrs[i]; + strcpy(new_str, ""); + } + } + + if (sysfs_attr_info==NULL || usr_data==NULL) + { + printk(KERN_ERR "%s is not supported attribute for this client\n", attr->dev_attr.attr.name); + goto exit; + } + + psu_update_attr(dev, sysfs_attr_info, usr_data); + + switch(attr->index) + { + case PSU_PRESENT: + case PSU_POWER_GOOD: + status = sysfs_attr_info->val.intval; + return sprintf(buf, "%d\n", status); + break; + case PSU_MODEL_NAME: + case PSU_MFR_ID: + case PSU_SERIAL_NUM: + case PSU_FAN_DIR: + return sprintf(buf, "%s\n", sysfs_attr_info->val.strval); + break; + case PSU_V_OUT: + case PSU_I_OUT: + case PSU_V_IN: + case PSU_I_IN: + multiplier = 1000; + value = sysfs_attr_info->val.shortval; + exponent = two_complement_to_int(value >> 11, 5, 0x1f); + mantissa = two_complement_to_int(value & 0x7ff, 11, 0x7ff); + if (exponent >= 0) + return sprintf(buf, "%d\n", (mantissa << exponent) * multiplier); + else + return sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); + + break; + case PSU_P_OUT: + multiplier = 1000000; + value = sysfs_attr_info->val.shortval; + exponent = two_complement_to_int(value >> 11, 5, 0x1f); + mantissa = two_complement_to_int(value & 0x7ff, 11, 0x7ff); + if (exponent >= 0) + return sprintf(buf, "%d\n", (mantissa << exponent) * multiplier); + else + return sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); + + break; + case PSU_FAN1_SPEED: + value = sysfs_attr_info->val.shortval; + exponent = two_complement_to_int(value >> 11, 5, 0x1f); + mantissa = two_complement_to_int(value & 0x7ff, 11, 0x7ff); + if (exponent >= 0) + return sprintf(buf, "%d\n", (mantissa << exponent)); + else + return sprintf(buf, "%d\n", (mantissa) / (1 << -exponent)); + + break; + case PSU_TEMP1_INPUT: + multiplier = 1000; + value = sysfs_attr_info->val.shortval; + exponent = two_complement_to_int(value >> 11, 5, 0x1f); + mantissa = two_complement_to_int(value & 0x7ff, 11, 0x7ff); + if (exponent >= 0) + return sprintf(buf, "%d\n", (mantissa << exponent) * multiplier); + else + return sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); + + break; + default: + printk(KERN_ERR "%s: Unable to find attribute index for %s\n", __FUNCTION__, usr_data->aname); + goto exit; + } + +exit: + return sprintf(buf, "%d\n", status); +} + + +ssize_t psu_store_default(struct device *dev, struct device_attribute *da, const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct psu_data *data = i2c_get_clientdata(client); + PSU_PDATA *pdata = (PSU_PDATA *)(client->dev.platform_data); + PSU_DATA_ATTR *usr_data = NULL; + struct psu_attr_info *sysfs_attr_info = NULL; + int i; + + for (i=0;inum_attr;i++) + { + if (strcmp(data->attr_info[i].name, attr->dev_attr.attr.name) == 0 && strcmp(pdata->psu_attrs[i].aname, attr->dev_attr.attr.name) == 0) + { + sysfs_attr_info = &data->attr_info[i]; + usr_data = &pdata->psu_attrs[i]; + } + } + + if (sysfs_attr_info==NULL || usr_data==NULL) { + printk(KERN_ERR "%s is not supported attribute for this client\n", attr->dev_attr.attr.name); + goto exit; + } + + switch(attr->index) + { + /*No write attributes for now in PSU*/ + default: + goto exit; + } + + psu_update_hw(dev, sysfs_attr_info, usr_data); + +exit: + return count; +} + +int sonic_i2c_get_psu_present_default(void *client, PSU_DATA_ATTR *adata, void *data) +{ + int status = 0; + int val = 0; + struct psu_attr_info *padata = (struct psu_attr_info *)data; + + + if (strncmp(adata->devtype, "cpld", strlen("cpld")) == 0) + { + val = board_i2c_cpld_read(adata->devaddr , adata->offset); + if (val < 0) + return val; + padata->val.intval = ((val & adata->mask) == adata->cmpval); + psu_dbg(KERN_ERR "%s: status_value = 0x%x\n", __FUNCTION__, padata->val.intval); + } + + return status; +} + +int sonic_i2c_get_psu_power_good_default(void *client, PSU_DATA_ATTR *adata, void *data) +{ + int status = 0; + int val = 0; + struct psu_attr_info *padata = (struct psu_attr_info *)data; + + if (strncmp(adata->devtype, "cpld", strlen("cpld")) == 0) + { + val = board_i2c_cpld_read(adata->devaddr , adata->offset); + if (val < 0) + return val; + padata->val.intval = ((val & adata->mask) == adata->cmpval); + psu_dbg(KERN_ERR "%s: status_value = 0x%x\n", __FUNCTION__, padata->val.intval); + } + + return status; +} + +int sonic_i2c_get_psu_model_name_default(void *client, PSU_DATA_ATTR *adata, void *data) +{ + int status = 0, retry = 10; + struct psu_attr_info *padata = (struct psu_attr_info *)data; + char model[32]=""; //temporary placeholder for model name + uint8_t offset = (uint8_t)adata->offset; + int data_len = adata->len; + + while (retry) + { + status = i2c_smbus_read_i2c_block_data((struct i2c_client *)client, offset, data_len-1, model); + if (unlikely(status<0)) + { + msleep(60); + retry--; + continue; + } + break; + } + + if (status < 0) + { + model[0] = '\0'; + dev_dbg(&((struct i2c_client *)client)->dev, "unable to read model name from (0x%x)\n", ((struct i2c_client *)client)->addr); + } + else + { + model[data_len-1] = '\0'; + } + + if (strncmp(adata->devtype, "pmbus", strlen("pmbus")) == 0) + strncpy(padata->val.strval, model+1, data_len-1); + else + strncpy(padata->val.strval, model, data_len); + + psu_dbg(KERN_ERR "%s: status = %d, model_name : %s\n", __FUNCTION__, status, padata->val.strval); + return 0; +} + +int sonic_i2c_get_psu_mfr_id_default(void *client, PSU_DATA_ATTR *adata, void *data) +{ + + int status = 0, retry = 10; + struct psu_attr_info *padata = (struct psu_attr_info *)data; + char mfr_id[16] = ""; // temporary place holder for mfr_id + uint8_t offset = (uint8_t)adata->offset; + int data_len = adata->len; + + while (retry) + { + status = i2c_smbus_read_i2c_block_data((struct i2c_client *)client, offset, data_len-1, mfr_id); + if (unlikely(status<0)) + { + msleep(60); + retry--; + continue; + } + break; + } + + if (status < 0) + { + mfr_id[0] = '\0'; + dev_dbg(&((struct i2c_client *)client)->dev, "unable to read mfr_id from (0x%x)\n", ((struct i2c_client *)client)->addr); + } + else + { + mfr_id[data_len-1] = '\0'; + } + + if (strncmp(adata->devtype, "pmbus", strlen("pmbus")) == 0) + strncpy(padata->val.strval, mfr_id+1, data_len-1); + else + strncpy(padata->val.strval, mfr_id, data_len); + + psu_dbg(KERN_ERR "%s: status = %d, mfr_id : %s\n", __FUNCTION__, status, padata->val.strval); + return 0; +} + +int sonic_i2c_get_psu_serial_num_default(void *client, PSU_DATA_ATTR *adata, void *data) +{ + + int status = 0, retry = 10; + struct psu_attr_info *padata = (struct psu_attr_info *)data; + char serial[32] = ""; // temporary string to store the serial num + uint8_t offset = (uint8_t)adata->offset; + int data_len = adata->len; + + while (retry) + { + status = i2c_smbus_read_i2c_block_data((struct i2c_client *)client, offset, data_len-1, serial); + if (unlikely(status<0)) + { + msleep(60); + retry--; + continue; + } + break; + } + + if (status < 0) + { + serial[0] = '\0'; + dev_dbg(&((struct i2c_client *)client)->dev, "unable to read serial num from (0x%x)\n", ((struct i2c_client *)client)->addr); + } + else + { + serial[data_len-1] = '\0'; + } + + if (strncmp(adata->devtype, "pmbus", strlen("pmbus")) == 0) + strncpy(padata->val.strval, serial+1, data_len-1); + else + strncpy(padata->val.strval, serial, data_len); + + psu_dbg(KERN_ERR "%s: status = %d, serial_num : %s\n", __FUNCTION__, status, padata->val.strval); + return 0; +} + +int sonic_i2c_get_psu_fan_dir_default(void *client, PSU_DATA_ATTR *adata, void *data) +{ + + int status = 0, retry = 10; + struct psu_attr_info *padata = (struct psu_attr_info *)data; + char fan_dir[5] = ""; + uint8_t offset = (uint8_t)adata->offset; + int data_len = adata->len; + + while (retry) + { + status = i2c_smbus_read_i2c_block_data((struct i2c_client *)client, offset, data_len-1, fan_dir); + if (unlikely(status<0)) + { + msleep(60); + retry--; + continue; + } + break; + } + + if (status < 0) + { + fan_dir[0] = '\0'; + dev_dbg(&((struct i2c_client *)client)->dev, "unable to read fan_dir from (0x%x)\n", ((struct i2c_client *)client)->addr); + } + else + { + fan_dir[data_len-1] = '\0'; + } + + if (strncmp(adata->devtype, "pmbus", strlen("pmbus")) == 0) + strncpy(padata->val.strval, fan_dir+1, data_len-1); + else + strncpy(padata->val.strval, fan_dir, data_len); + + psu_dbg(KERN_ERR "%s: status = %d, fan_dir : %s\n", __FUNCTION__, status, padata->val.strval); + return 0; +} + +int sonic_i2c_get_psu_v_out_default(void *client, PSU_DATA_ATTR *adata, void *data) +{ + + int status = 0, retry = 10; + struct psu_attr_info *padata = (struct psu_attr_info *)data; + uint8_t offset = (uint8_t)adata->offset; + + while (retry) { + status = i2c_smbus_read_word_data((struct i2c_client *)client, offset); + if (unlikely(status < 0)) { + msleep(60); + retry--; + continue; + } + break; + } + + if (status < 0) + { + padata->val.shortval = 0; + dev_dbg(&((struct i2c_client *)client)->dev, "unable to read v_out from (0x%x)\n", ((struct i2c_client *)client)->addr); + } + else + { + padata->val.shortval = status; + } + + psu_dbg(KERN_ERR "%s: v_out : %d\n", __FUNCTION__, padata->val.shortval); + return 0; +} + +int sonic_i2c_get_psu_i_out_default(void *client, PSU_DATA_ATTR *adata, void *data) +{ + + int status = 0, retry = 10; + struct psu_attr_info *padata = (struct psu_attr_info *)data; + uint8_t offset = (uint8_t)adata->offset; + + while (retry) { + status = i2c_smbus_read_word_data((struct i2c_client *)client, offset); + if (unlikely(status < 0)) { + msleep(60); + retry--; + continue; + } + break; + } + + if (status < 0) + { + padata->val.shortval = 0; + dev_dbg(&((struct i2c_client *)client)->dev, "unable to read i_out from (0x%x)\n", ((struct i2c_client *)client)->addr); + } + else + { + padata->val.shortval = status; + } + + psu_dbg(KERN_ERR "%s: i_out : %d\n", __FUNCTION__, padata->val.shortval); + return 0; +} + +int sonic_i2c_get_psu_p_out_default(void *client, PSU_DATA_ATTR *adata, void *data) +{ + + int status = 0, retry = 10; + struct psu_attr_info *padata = (struct psu_attr_info *)data; + uint8_t offset = (uint8_t)adata->offset; + + while (retry) { + status = i2c_smbus_read_word_data((struct i2c_client *)client, offset); + if (unlikely(status < 0)) { + msleep(60); + retry--; + continue; + } + break; + } + + if (status < 0) + { + padata->val.shortval = 0; + dev_dbg(&((struct i2c_client *)client)->dev, "unable to read p_out from (0x%x)\n", ((struct i2c_client *)client)->addr); + } + else + { + padata->val.shortval = status; + } + + psu_dbg(KERN_ERR "%s: p_out : %d\n", __FUNCTION__, padata->val.shortval); + return 0; +} + +int sonic_i2c_get_psu_v_in_default(void *client, PSU_DATA_ATTR *adata, void *data) +{ + + int status = 0, retry = 10; + struct psu_attr_info *padata = (struct psu_attr_info *)data; + uint8_t offset = (uint8_t)adata->offset; + + while (retry) { + status = i2c_smbus_read_word_data((struct i2c_client *)client, offset); + if (unlikely(status < 0)) { + msleep(60); + retry--; + continue; + } + break; + } + + if (status < 0) + { + padata->val.shortval = 0; + dev_dbg(&((struct i2c_client *)client)->dev, "unable to read v_in from (0x%x)\n", ((struct i2c_client *)client)->addr); + } + else + { + padata->val.shortval = status; + } + + psu_dbg(KERN_ERR "%s: v_in : %d\n", __FUNCTION__, padata->val.shortval); + return 0; +} + +int sonic_i2c_get_psu_i_in_default(void *client, PSU_DATA_ATTR *adata, void *data) +{ + + int status = 0, retry = 10; + struct psu_attr_info *padata = (struct psu_attr_info *)data; + uint8_t offset = (uint8_t)adata->offset; + + while (retry) { + status = i2c_smbus_read_word_data((struct i2c_client *)client, offset); + if (unlikely(status < 0)) { + msleep(60); + retry--; + continue; + } + break; + } + + if (status < 0) + { + padata->val.shortval = 0; + dev_dbg(&((struct i2c_client *)client)->dev, "unable to read i_in from (0x%x)\n", ((struct i2c_client *)client)->addr); + } + else + { + padata->val.shortval = status; + } + + psu_dbg(KERN_ERR "%s: i_in : %d\n", __FUNCTION__, padata->val.shortval); + return 0; +} + +int sonic_i2c_get_psu_fan1_speed_rpm_default(void *client, PSU_DATA_ATTR *adata, void *data) +{ + + int status = 0, retry = 10; + struct psu_attr_info *padata = (struct psu_attr_info *)data; + uint8_t offset = (uint8_t)adata->offset; + + while (retry) { + status = i2c_smbus_read_word_data((struct i2c_client *)client, offset); + if (unlikely(status < 0)) { + msleep(60); + retry--; + continue; + } + break; + } + + if (status < 0) + { + padata->val.shortval = 0; + dev_dbg(&((struct i2c_client *)client)->dev, "unable to read fan1_speed_rpm from (0x%x)\n", ((struct i2c_client *)client)->addr); + } + else + { + padata->val.shortval = status; + } + + psu_dbg(KERN_ERR "%s: fan1_speed_rpm : %d\n", __FUNCTION__, padata->val.shortval); + return 0; +} + +int sonic_i2c_get_psu_temp1_input_default(void *client, PSU_DATA_ATTR *adata, void *data) +{ + + int status = 0, retry = 10; + struct psu_attr_info *padata = (struct psu_attr_info *)data; + uint8_t offset = (uint8_t)adata->offset; + + while (retry) { + status = i2c_smbus_read_word_data((struct i2c_client *)client, offset); + if (unlikely(status < 0)) { + msleep(60); + retry--; + continue; + } + break; + } + + if (status < 0) + { + padata->val.shortval = 0; + dev_dbg(&((struct i2c_client *)client)->dev, "unable to read temp1_input from (0x%x)\n", ((struct i2c_client *)client)->addr); + } + else + { + padata->val.shortval = status; + } + + psu_dbg(KERN_ERR "%s: temp1_input : %d\n", __FUNCTION__, padata->val.shortval); + return 0; +} diff --git a/platform/pddf/i2c/modules/psu/driver/pddf_psu_driver.c b/platform/pddf/i2c/modules/psu/driver/pddf_psu_driver.c new file mode 100644 index 0000000000..ad71e45eca --- /dev/null +++ b/platform/pddf/i2c/modules/psu/driver/pddf_psu_driver.c @@ -0,0 +1,381 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * + * A pddf kernel module driver for PSU + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pddf_client_defs.h" +#include "pddf_psu_defs.h" +#include "pddf_psu_driver.h" +#include "pddf_psu_api.h" + + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +struct pddf_ops_t pddf_psu_ops = { + .pre_init = NULL, + .post_init = NULL, + + .pre_probe = NULL, + .post_probe = NULL, + + .pre_remove = NULL, + .post_remove = NULL, + + .pre_exit = NULL, + .post_exit = NULL, +}; +EXPORT_SYMBOL(pddf_psu_ops); + + +PSU_SYSFS_ATTR_DATA access_psu_present = {PSU_PRESENT, S_IRUGO, psu_show_default, NULL, sonic_i2c_get_psu_present_default, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(access_psu_present); + +PSU_SYSFS_ATTR_DATA access_psu_model_name = {PSU_MODEL_NAME, S_IRUGO, psu_show_default, NULL, sonic_i2c_get_psu_model_name_default, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(access_psu_model_name); + +PSU_SYSFS_ATTR_DATA access_psu_power_good = {PSU_POWER_GOOD, S_IRUGO, psu_show_default, NULL, sonic_i2c_get_psu_power_good_default, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(access_psu_power_good); + +PSU_SYSFS_ATTR_DATA access_psu_mfr_id = {PSU_MFR_ID, S_IRUGO, psu_show_default, NULL, sonic_i2c_get_psu_mfr_id_default, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(access_psu_mfr_id); + +PSU_SYSFS_ATTR_DATA access_psu_serial_num = {PSU_SERIAL_NUM, S_IRUGO, psu_show_default, NULL, sonic_i2c_get_psu_serial_num_default, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(access_psu_serial_num); + +PSU_SYSFS_ATTR_DATA access_psu_fan_dir = {PSU_FAN_DIR, S_IRUGO, psu_show_default, NULL, sonic_i2c_get_psu_fan_dir_default, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(access_psu_fan_dir); + +PSU_SYSFS_ATTR_DATA access_psu_v_out = {PSU_V_OUT, S_IRUGO, psu_show_default, NULL, sonic_i2c_get_psu_v_out_default, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(access_psu_v_out); + +PSU_SYSFS_ATTR_DATA access_psu_i_out = {PSU_I_OUT, S_IRUGO, psu_show_default, NULL, sonic_i2c_get_psu_i_out_default, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(access_psu_i_out); + +PSU_SYSFS_ATTR_DATA access_psu_p_out = {PSU_P_OUT, S_IRUGO, psu_show_default, NULL, sonic_i2c_get_psu_p_out_default, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(access_psu_p_out); + +PSU_SYSFS_ATTR_DATA access_psu_fan1_speed_rpm = {PSU_FAN1_SPEED, S_IRUGO, psu_show_default, NULL, sonic_i2c_get_psu_fan1_speed_rpm_default, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(access_psu_fan1_speed_rpm); + +PSU_SYSFS_ATTR_DATA access_psu_temp1_input = {PSU_TEMP1_INPUT, S_IRUGO, psu_show_default, NULL, sonic_i2c_get_psu_temp1_input_default, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(access_psu_temp1_input); + +PSU_SYSFS_ATTR_DATA access_psu_v_in = {PSU_V_IN, S_IRUGO, psu_show_default, NULL, sonic_i2c_get_psu_v_in_default, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(access_psu_v_in); + +PSU_SYSFS_ATTR_DATA access_psu_i_in = {PSU_I_IN, S_IRUGO, psu_show_default, NULL, sonic_i2c_get_psu_i_in_default, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(access_psu_i_in); + + +PSU_SYSFS_ATTR_DATA_ENTRY psu_sysfs_attr_data_tbl[]= +{ + { "psu_present", &access_psu_present}, + { "psu_model_name", &access_psu_model_name}, + { "psu_power_good" , &access_psu_power_good}, + { "psu_mfr_id" , &access_psu_mfr_id}, + { "psu_serial_num" , &access_psu_serial_num}, + { "psu_fan_dir" , &access_psu_fan_dir}, + { "psu_v_out" , &access_psu_v_out}, + { "psu_i_out" , &access_psu_i_out}, + { "psu_p_out" , &access_psu_p_out}, + { "psu_fan1_speed_rpm" , &access_psu_fan1_speed_rpm}, + { "psu_temp1_input" , &access_psu_temp1_input}, + { "psu_v_in" , &access_psu_v_in}, + { "psu_i_in" , &access_psu_i_in} +}; + +void *get_psu_access_data(char *name) +{ + int i=0; + for(i=0; i<(sizeof(psu_sysfs_attr_data_tbl)/sizeof(psu_sysfs_attr_data_tbl[0])); i++) + { + if(strcmp(name, psu_sysfs_attr_data_tbl[i].name) ==0) + { + return &psu_sysfs_attr_data_tbl[i]; + } + } + return NULL; +} +EXPORT_SYMBOL(get_psu_access_data); + + +static int psu_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + struct psu_data *data; + int status =0; + int i,num, j=0; + PSU_PDATA *psu_platform_data; + PSU_DATA_ATTR *data_attr; + PSU_SYSFS_ATTR_DATA_ENTRY *sysfs_data_entry; + char new_str[ATTR_NAME_LEN] = ""; + + + if (client == NULL) { + printk("NULL Client.. \n"); + goto exit; + } + + if (pddf_psu_ops.pre_probe) + { + status = (pddf_psu_ops.pre_probe)(client, dev_id); + if (status != 0) + goto exit; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) { + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(struct psu_data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + dev_info(&client->dev, "chip found\n"); + + /* Take control of the platform data */ + psu_platform_data = (PSU_PDATA *)(client->dev.platform_data); + num = psu_platform_data->len; + data->index = psu_platform_data->idx - 1; + data->num_psu_fans = psu_platform_data->num_psu_fans; + data->num_attr = num; + + + + /* Create and Add supported attr in the 'attributes' list */ + for (i=0; ipsu_attrs + i; + sysfs_data_entry = get_psu_access_data(data_attr->aname); + if (sysfs_data_entry == NULL) + { + printk(KERN_ERR "%s: Wrong attribute name provided by user '%s'\n", __FUNCTION__, data_attr->aname); + continue; + } + + dy_ptr = (struct sensor_device_attribute *)kzalloc(sizeof(struct sensor_device_attribute)+ATTR_NAME_LEN, GFP_KERNEL); + dy_ptr->dev_attr.attr.name = (char *)&dy_ptr[1]; + strcpy((char *)dy_ptr->dev_attr.attr.name, data_attr->aname); + dy_ptr->dev_attr.attr.mode = sysfs_data_entry->a_ptr->mode; + dy_ptr->dev_attr.show = sysfs_data_entry->a_ptr->show; + dy_ptr->dev_attr.store = sysfs_data_entry->a_ptr->store; + dy_ptr->index = sysfs_data_entry->a_ptr->index; + + data->psu_attribute_list[i] = &dy_ptr->dev_attr.attr; + strcpy(data->attr_info[i].name, data_attr->aname); + data->attr_info[i].valid = 0; + mutex_init(&data->attr_info[i].update_lock); + + /*Create a duplicate entry*/ + get_psu_duplicate_sysfs(dy_ptr->index, new_str); + if (strcmp(new_str,"")) + { + dy_ptr = (struct sensor_device_attribute *)kzalloc(sizeof(struct sensor_device_attribute)+ATTR_NAME_LEN, GFP_KERNEL); + dy_ptr->dev_attr.attr.name = (char *)&dy_ptr[1]; + strcpy((char *)dy_ptr->dev_attr.attr.name, new_str); + dy_ptr->dev_attr.attr.mode = sysfs_data_entry->a_ptr->mode; + dy_ptr->dev_attr.show = sysfs_data_entry->a_ptr->show; + dy_ptr->dev_attr.store = sysfs_data_entry->a_ptr->store; + dy_ptr->index = sysfs_data_entry->a_ptr->index; + + data->psu_attribute_list[num+j] = &dy_ptr->dev_attr.attr; + j++; + strcpy(new_str,""); + } + } + data->psu_attribute_list[i+j] = NULL; + data->psu_attribute_group.attrs = data->psu_attribute_list; + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &data->psu_attribute_group); + if (status) { + goto exit_free; + } + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + dev_info(&client->dev, "%s: psu '%s'\n", + dev_name(data->hwmon_dev), client->name); + + /* Add a support for post probe function */ + if (pddf_psu_ops.post_probe) + { + status = (pddf_psu_ops.post_probe)(client, dev_id); + if (status != 0) + goto exit_remove; + } + + return 0; + + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &data->psu_attribute_group); +exit_free: + /* Free all the allocated attributes */ + for (i=0;data->psu_attribute_list[i]!=NULL;i++) + { + struct sensor_device_attribute *ptr = (struct sensor_device_attribute *)data->psu_attribute_list[i]; + kfree(ptr); + data->psu_attribute_list[i] = NULL; + pddf_dbg(PSU, KERN_ERR "%s: Freed all the memory allocated for attributes\n", __FUNCTION__); + } + kfree(data); +exit: + return status; +} + +static int psu_remove(struct i2c_client *client) +{ + int i=0, ret = 0; + struct psu_data *data = i2c_get_clientdata(client); + PSU_PDATA *platdata = (PSU_PDATA *)client->dev.platform_data; // use dev_get_platdata() + PSU_DATA_ATTR *platdata_sub = platdata->psu_attrs; + struct sensor_device_attribute *ptr = NULL; + + if (pddf_psu_ops.pre_remove) + { + ret = (pddf_psu_ops.pre_remove)(client); + if (ret!=0) + printk(KERN_ERR "FAN pre_remove function failed\n"); + } + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &data->psu_attribute_group); + for (i=0; data->psu_attribute_list[i]!=NULL; i++) + { + ptr = (struct sensor_device_attribute *)data->psu_attribute_list[i]; + kfree(ptr); + data->psu_attribute_list[i] = NULL; + } + pddf_dbg(PSU, KERN_ERR "%s: Freed all the memory allocated for attributes\n", __FUNCTION__); + kfree(data); + if (platdata_sub) { + printk(KERN_DEBUG "%s: Freeing platform subdata\n", __FUNCTION__); + kfree(platdata_sub); + } + if (platdata) { + printk(KERN_DEBUG "%s: Freeing platform data\n", __FUNCTION__); + kfree(platdata); + } + + if (pddf_psu_ops.post_remove) + { + ret = (pddf_psu_ops.post_remove)(client); + if (ret!=0) + printk(KERN_ERR "FAN post_remove function failed\n"); + } + + return ret; +} + +enum psu_intf +{ + eeprom_intf, + smbus_intf +}; + +static const struct i2c_device_id psu_id[] = { + {"psu_eeprom", eeprom_intf}, + {"psu_pmbus", smbus_intf}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, psu_id); + +static struct i2c_driver psu_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "psu", + }, + .probe = psu_probe, + .remove = psu_remove, + .id_table = psu_id, + .address_list = normal_i2c, +}; + +int example_fun(void) +{ + pddf_dbg(PSU, KERN_ERR "CALLING FUN...\n"); + return 0; +} +EXPORT_SYMBOL(example_fun); + + +int psu_init(void) +{ + int status = 0; + + if (pddf_psu_ops.pre_init) + { + status = (pddf_psu_ops.pre_init)(); + if (status!=0) + return status; + } + + pddf_dbg(PSU, KERN_ERR "GENERIC_PSU_DRIVER.. init Invoked..\n"); + status = i2c_add_driver(&psu_driver); + if (status!=0) + return status; + + if (pddf_psu_ops.post_init) + { + status = (pddf_psu_ops.post_init)(); + if (status!=0) + return status; + } + + return status; +} +EXPORT_SYMBOL(psu_init); + +void __exit psu_exit(void) +{ + pddf_dbg(PSU, "GENERIC_PSU_DRIVER.. exit\n"); + if (pddf_psu_ops.pre_exit) (pddf_psu_ops.pre_exit)(); + i2c_del_driver(&psu_driver); + if (pddf_psu_ops.post_exit) (pddf_psu_ops.post_exit)(); +} +EXPORT_SYMBOL(psu_exit); + +module_init(psu_init); +module_exit(psu_exit); + +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("psu driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/pddf/i2c/modules/psu/pddf_psu_module.c b/platform/pddf/i2c/modules/psu/pddf_psu_module.c new file mode 100644 index 0000000000..cf9713b407 --- /dev/null +++ b/platform/pddf/i2c/modules/psu/pddf_psu_module.c @@ -0,0 +1,283 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * + * A pddf kernel module to create I2C client for PSU + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pddf_client_defs.h" +#include "pddf_psu_defs.h" + + +static ssize_t do_attr_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count); +static ssize_t do_device_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count); +extern void *get_psu_access_data(char *); +extern void* get_device_table(char *name); +extern void delete_device_table(char *name); + +PSU_DATA psu_data = {0}; + + + +/* PSU CLIENT DATA */ +PDDF_DATA_ATTR(psu_idx, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_DEC, sizeof(int), (void*)&psu_data.idx, NULL); +PDDF_DATA_ATTR(psu_fans, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_DEC, sizeof(int), (void*)&psu_data.num_psu_fans, NULL); + +PDDF_DATA_ATTR(attr_name, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_CHAR, 32, (void*)&psu_data.psu_attr.aname, NULL); +PDDF_DATA_ATTR(attr_devtype, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_CHAR, 8, (void*)&psu_data.psu_attr.devtype, NULL); +PDDF_DATA_ATTR(attr_devname, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_CHAR, 8, (void*)&psu_data.psu_attr.devname, NULL); +PDDF_DATA_ATTR(attr_devaddr, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32, sizeof(uint32_t), (void*)&psu_data.psu_attr.devaddr, NULL); +PDDF_DATA_ATTR(attr_offset, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32, sizeof(uint32_t), (void*)&psu_data.psu_attr.offset, NULL); +PDDF_DATA_ATTR(attr_mask, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32, sizeof(uint32_t), (void*)&psu_data.psu_attr.mask, NULL); +PDDF_DATA_ATTR(attr_cmpval, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32, sizeof(uint32_t), (void*)&psu_data.psu_attr.cmpval, NULL); +PDDF_DATA_ATTR(attr_len, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_DEC, sizeof(int), (void*)&psu_data.psu_attr.len, NULL); +PDDF_DATA_ATTR(attr_ops, S_IWUSR, NULL, do_attr_operation, PDDF_CHAR, 8, (void*)&psu_data, NULL); +PDDF_DATA_ATTR(dev_ops, S_IWUSR, NULL, do_device_operation, PDDF_CHAR, 8, (void*)&psu_data, (void*)&pddf_data); + + + +static struct attribute *psu_attributes[] = { + &attr_psu_idx.dev_attr.attr, + &attr_psu_fans.dev_attr.attr, + + &attr_attr_name.dev_attr.attr, + &attr_attr_devtype.dev_attr.attr, + &attr_attr_devname.dev_attr.attr, + &attr_attr_devaddr.dev_attr.attr, + &attr_attr_offset.dev_attr.attr, + &attr_attr_mask.dev_attr.attr, + &attr_attr_cmpval.dev_attr.attr, + &attr_attr_len.dev_attr.attr, + &attr_attr_ops.dev_attr.attr, + &attr_dev_ops.dev_attr.attr, + NULL +}; + +static const struct attribute_group pddf_psu_client_data_group = { + .attrs = psu_attributes, +}; + + +static ssize_t do_attr_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count) +{ + PDDF_ATTR *ptr = (PDDF_ATTR *)da; + PSU_DATA *pdata = (PSU_DATA *)(ptr->addr); + PSU_SYSFS_ATTR_DATA_ENTRY *access_ptr; + + + pdata->psu_attrs[pdata->len] = pdata->psu_attr; + access_ptr = get_psu_access_data(pdata->psu_attrs[pdata->len].aname); + if (access_ptr != NULL && access_ptr->a_ptr != NULL) + { + pdata->psu_attrs[pdata->len].access_data = access_ptr->a_ptr ; + } + + + pdata->len++; + memset(&pdata->psu_attr, 0, sizeof(pdata->psu_attr)); + + + return count; +} + +struct i2c_board_info *i2c_get_psu_board_info(PSU_DATA *pdata, NEW_DEV_ATTR *cdata) +{ + int num = pdata->len; + int i = 0; + static struct i2c_board_info board_info; + PSU_PDATA *psu_platform_data; + + + if (strcmp(cdata->dev_type, "psu_pmbus")==0 || strcmp(cdata->dev_type, "psu_eeprom")==0 ) + { + /* Allocate the psu_platform_data */ + psu_platform_data = (PSU_PDATA *)kzalloc(sizeof(PSU_PDATA), GFP_KERNEL); + psu_platform_data->psu_attrs = (PSU_DATA_ATTR *)kzalloc(num*sizeof(PSU_DATA_ATTR), GFP_KERNEL); + + + psu_platform_data->idx = pdata->idx; + psu_platform_data->num_psu_fans = pdata->num_psu_fans; + psu_platform_data->len = pdata->len; + + for (i=0;ipsu_attrs[i] = pdata->psu_attrs[i]; + } + + board_info = (struct i2c_board_info) { + .platform_data = psu_platform_data, + }; + + board_info.addr = cdata->dev_addr; + strcpy(board_info.type, cdata->dev_type); + } + else + { + printk(KERN_ERR "%s:Unknown type of device %s. Unable to clreate I2C client for it\n",__FUNCTION__, cdata->dev_type); + } + + return &board_info; +} + + +static ssize_t do_device_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count) +{ + PDDF_ATTR *ptr = (PDDF_ATTR *)da; + PSU_DATA *pdata = (PSU_DATA *)(ptr->addr); + NEW_DEV_ATTR *cdata = (NEW_DEV_ATTR *)(ptr->data); + struct i2c_adapter *adapter; + struct i2c_board_info *board_info; + struct i2c_client *client_ptr; + + + if (strncmp(buf, "add", strlen(buf)-1)==0) + { + adapter = i2c_get_adapter(cdata->parent_bus); + board_info = i2c_get_psu_board_info(pdata, cdata); + + /* Populate the platform data for psu */ + client_ptr = i2c_new_device(adapter, board_info); + + if(client_ptr != NULL) + { + i2c_put_adapter(adapter); + pddf_dbg(PSU, KERN_ERR "Created a %s client: 0x%p\n", cdata->i2c_name , (void *)client_ptr); + add_device_table(cdata->i2c_name, (void*)client_ptr); + } + else + { + i2c_put_adapter(adapter); + goto free_data; + } + } + else if (strncmp(buf, "delete", strlen(buf)-1)==0) + { + /*Get the i2c_client handle for the created client*/ + client_ptr = (struct i2c_client *)get_device_table(cdata->i2c_name); + if (client_ptr) + { + pddf_dbg(PSU, KERN_ERR "Removing %s client: 0x%p\n", cdata->i2c_name, (void *)client_ptr); + i2c_unregister_device(client_ptr); + delete_device_table(cdata->i2c_name); + } + else + { + printk(KERN_ERR "Unable to get the client handle for %s\n", cdata->i2c_name); + } + + } + else + { + printk(KERN_ERR "PDDF_ERROR: %s: Invalid value for dev_ops %s", __FUNCTION__, buf); + } + + goto clear_data; + +free_data: + if (board_info->platform_data) + { + PSU_PDATA *psu_platform_data = board_info->platform_data; + if (psu_platform_data->psu_attrs) + { + printk(KERN_ERR "%s: Unable to create i2c client. Freeing the platform subdata\n", __FUNCTION__); + kfree(psu_platform_data->psu_attrs); + } + printk(KERN_ERR "%s: Unable to create i2c client. Freeing the platform data\n", __FUNCTION__); + kfree(psu_platform_data); + } + +clear_data: + memset(pdata, 0, sizeof(PSU_DATA)); + /*TODO: free the data cdata->data if data is dynal=mically allocated*/ + memset(cdata, 0, sizeof(NEW_DEV_ATTR)); + return count; +} + + +static struct kobject *psu_kobj; +static struct kobject *i2c_kobj; + +int __init pddf_data_init(void) +{ + struct kobject *device_kobj; + int ret = 0; + + + pddf_dbg(PSU, "PDDF_DATA MODULE.. init\n"); + + device_kobj = get_device_i2c_kobj(); + if(!device_kobj) + return -ENOMEM; + + psu_kobj = kobject_create_and_add("psu", device_kobj); + if(!psu_kobj) + return -ENOMEM; + i2c_kobj = kobject_create_and_add("i2c", psu_kobj); + if(!i2c_kobj) + return -ENOMEM; + + ret = sysfs_create_group(i2c_kobj, &pddf_clients_data_group); + if (ret) + { + kobject_put(i2c_kobj); + kobject_put(psu_kobj); + return ret; + } + pddf_dbg(PSU, "CREATED PSU I2C CLIENTS CREATION SYSFS GROUP\n"); + + ret = sysfs_create_group(i2c_kobj, &pddf_psu_client_data_group); + if (ret) + { + sysfs_remove_group(i2c_kobj, &pddf_clients_data_group); + kobject_put(i2c_kobj); + kobject_put(psu_kobj); + return ret; + } + pddf_dbg(PSU, "CREATED PDDF PSU DATA SYSFS GROUP\n"); + + return ret; +} + +void __exit pddf_data_exit(void) +{ + + pddf_dbg(PSU, "PDDF_DATA MODULE.. exit\n"); + sysfs_remove_group(i2c_kobj, &pddf_psu_client_data_group); + sysfs_remove_group(i2c_kobj, &pddf_clients_data_group); + kobject_put(i2c_kobj); + kobject_put(psu_kobj); + pddf_dbg(PSU, KERN_ERR "%s: Removed the kobjects for 'i2c' and 'psu'\n",__FUNCTION__); + + return; +} + +module_init(pddf_data_init); +module_exit(pddf_data_exit); + +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("psu platform data"); +MODULE_LICENSE("GPL"); diff --git a/platform/pddf/i2c/modules/sysstatus/Makefile b/platform/pddf/i2c/modules/sysstatus/Makefile new file mode 100644 index 0000000000..150d160eae --- /dev/null +++ b/platform/pddf/i2c/modules/sysstatus/Makefile @@ -0,0 +1,4 @@ +TARGET := pddf_sysstatus_module +obj-m := $(TARGET).o + +CFLAGS_$(obj-m):= -I$(M)/modules/include diff --git a/platform/pddf/i2c/modules/sysstatus/pddf_sysstatus_module.c b/platform/pddf/i2c/modules/sysstatus/pddf_sysstatus_module.c new file mode 100644 index 0000000000..bd892d9242 --- /dev/null +++ b/platform/pddf/i2c/modules/sysstatus/pddf_sysstatus_module.c @@ -0,0 +1,235 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * + * A pddf kernel module for system status registers + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pddf_client_defs.h" +#include "pddf_sysstatus_defs.h" + + + +SYSSTATUS_DATA sysstatus_data = {0}; + +extern int board_i2c_cpld_read(unsigned short cpld_addr, u8 reg); +extern int board_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); + +static ssize_t do_attr_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count); +ssize_t show_sysstatus_data(struct device *dev, struct device_attribute *da, char *buf); + + +PDDF_DATA_ATTR(attr_name, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_CHAR, 32, + (void*)&sysstatus_data.sysstatus_addr_attr.aname, NULL); +PDDF_DATA_ATTR(attr_devaddr, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32, + sizeof(uint32_t), (void*)&sysstatus_data.sysstatus_addr_attr.devaddr , NULL); +PDDF_DATA_ATTR(attr_offset, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32, + sizeof(uint32_t), (void*)&sysstatus_data.sysstatus_addr_attr.offset, NULL); +PDDF_DATA_ATTR(attr_mask, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32, + sizeof(uint32_t), (void*)&sysstatus_data.sysstatus_addr_attr.mask , NULL); +PDDF_DATA_ATTR(attr_len, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32, + sizeof(uint32_t), (void*)&sysstatus_data.sysstatus_addr_attr.len , NULL); +PDDF_DATA_ATTR(attr_ops, S_IWUSR, NULL, do_attr_operation, PDDF_CHAR, 8, (void*)&sysstatus_data, NULL); + + + +static struct attribute *sysstatus_addr_attributes[] = { + &attr_attr_name.dev_attr.attr, + &attr_attr_devaddr.dev_attr.attr, + &attr_attr_offset.dev_attr.attr, + &attr_attr_mask.dev_attr.attr, + &attr_attr_len.dev_attr.attr, + &attr_attr_ops.dev_attr.attr, + NULL +}; + +PDDF_DATA_ATTR(board_info, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, 32, NULL, NULL); +PDDF_DATA_ATTR(cpld1_version, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, sizeof(uint32_t), NULL, NULL); +PDDF_DATA_ATTR(cpld2_version, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, sizeof(uint32_t), NULL, NULL); +PDDF_DATA_ATTR(cpld3_version, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, sizeof(uint32_t), NULL, NULL); +PDDF_DATA_ATTR(power_module_status, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, sizeof(uint32_t), NULL, NULL); +PDDF_DATA_ATTR(system_reset1, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, sizeof(uint32_t), NULL, NULL); +PDDF_DATA_ATTR(system_reset2, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, sizeof(uint32_t), NULL, NULL); +PDDF_DATA_ATTR(system_reset3, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, sizeof(uint32_t), NULL, NULL); +PDDF_DATA_ATTR(system_reset4, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, sizeof(uint32_t), NULL, NULL); +PDDF_DATA_ATTR(system_reset5, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, sizeof(uint32_t), NULL, NULL); +PDDF_DATA_ATTR(system_reset6, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, sizeof(uint32_t), NULL, NULL); +PDDF_DATA_ATTR(system_reset7, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, sizeof(uint32_t), NULL, NULL); +PDDF_DATA_ATTR(system_reset8, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, sizeof(uint32_t), NULL, NULL); +PDDF_DATA_ATTR(misc1, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, sizeof(uint32_t), NULL, NULL); +PDDF_DATA_ATTR(misc2, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, sizeof(uint32_t), NULL, NULL); +PDDF_DATA_ATTR(misc3, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, sizeof(uint32_t), NULL, NULL); + + + +static struct attribute *sysstatus_data_attributes[] = { + &attr_board_info.dev_attr.attr, + &attr_cpld1_version.dev_attr.attr, + &attr_cpld2_version.dev_attr.attr, + &attr_cpld3_version.dev_attr.attr, + &attr_power_module_status.dev_attr.attr, + &attr_system_reset1.dev_attr.attr, + &attr_system_reset2.dev_attr.attr, + &attr_system_reset3.dev_attr.attr, + &attr_system_reset4.dev_attr.attr, + &attr_system_reset5.dev_attr.attr, + &attr_system_reset6.dev_attr.attr, + &attr_system_reset7.dev_attr.attr, + &attr_system_reset8.dev_attr.attr, + &attr_misc1.dev_attr.attr, + &attr_misc2.dev_attr.attr, + &attr_misc3.dev_attr.attr, + NULL +}; + + + +static const struct attribute_group pddf_sysstatus_addr_group = { + .attrs = sysstatus_addr_attributes, +}; + + +static const struct attribute_group pddf_sysstatus_data_group = { + .attrs = sysstatus_data_attributes, +}; + + +static struct kobject *sysstatus_addr_kobj; +static struct kobject *sysstatus_data_kobj; + + + +ssize_t show_sysstatus_data(struct device *dev, struct device_attribute *da, char *buf) +{ + + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + + SYSSTATUS_DATA *data = &sysstatus_data; + struct SYSSTATUS_ADDR_ATTR *sysstatus_addr_attrs = NULL; + int i, status ; + + + for (i=0;isysstatus_addr_attrs[i].aname, attr->dev_attr.attr.name) == 0 ) + { + sysstatus_addr_attrs = &data->sysstatus_addr_attrs[i]; + + } + } + + if (sysstatus_addr_attrs==NULL ) + { + printk(KERN_DEBUG "%s is not supported attribute for this client\n",data->sysstatus_addr_attrs[i].aname); + status = 0; + } + else + { + status = board_i2c_cpld_read( sysstatus_addr_attrs->devaddr, sysstatus_addr_attrs->offset); + } + + return sprintf(buf, "0x%x\n", (status&sysstatus_addr_attrs->mask)); + +} + + + +static ssize_t do_attr_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count) +{ + PDDF_ATTR *ptr = (PDDF_ATTR *)da; + SYSSTATUS_DATA *pdata = (SYSSTATUS_DATA *)(ptr->addr); + + pdata->sysstatus_addr_attrs[pdata->len] = pdata->sysstatus_addr_attr; + pdata->len++; + pddf_dbg(SYSSTATUS, KERN_ERR "%s: Populating the data for %s\n", __FUNCTION__, pdata->sysstatus_addr_attr.aname); + memset(&pdata->sysstatus_addr_attr, 0, sizeof(pdata->sysstatus_addr_attr)); + + + return count; +} + + + + +int __init sysstatus_data_init(void) +{ + struct kobject *device_kobj; + int ret = 0; + + + pddf_dbg(SYSSTATUS, "PDDF SYSSTATUS MODULE.. init\n"); + + device_kobj = get_device_i2c_kobj(); + if(!device_kobj) + return -ENOMEM; + + sysstatus_addr_kobj = kobject_create_and_add("sysstatus", device_kobj); + if(!sysstatus_addr_kobj) + return -ENOMEM; + + sysstatus_data_kobj = kobject_create_and_add("sysstatus_data", sysstatus_addr_kobj); + if(!sysstatus_data_kobj) + return -ENOMEM; + + + ret = sysfs_create_group(sysstatus_addr_kobj, &pddf_sysstatus_addr_group); + if (ret) + { + kobject_put(sysstatus_addr_kobj); + return ret; + } + + ret = sysfs_create_group(sysstatus_data_kobj, &pddf_sysstatus_data_group); + if (ret) + { + sysfs_remove_group(sysstatus_addr_kobj, &pddf_sysstatus_addr_group); + kobject_put(sysstatus_data_kobj); + kobject_put(sysstatus_addr_kobj); + return ret; + } + + + return ret; +} + +void __exit sysstatus_data_exit(void) +{ + pddf_dbg(SYSSTATUS, "PDDF SYSSTATUS MODULE.. exit\n"); + sysfs_remove_group(sysstatus_data_kobj, &pddf_sysstatus_data_group); + sysfs_remove_group(sysstatus_addr_kobj, &pddf_sysstatus_addr_group); + kobject_put(sysstatus_data_kobj); + kobject_put(sysstatus_addr_kobj); + pddf_dbg(SYSSTATUS, KERN_ERR "%s: Removed the kobjects for 'SYSSTATUS'\n",__FUNCTION__); + return; +} + +module_init(sysstatus_data_init); +module_exit(sysstatus_data_exit); + +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("SYSSTATUS platform data"); +MODULE_LICENSE("GPL"); diff --git a/platform/pddf/i2c/modules/xcvr/Makefile b/platform/pddf/i2c/modules/xcvr/Makefile new file mode 100644 index 0000000000..e72ad6b442 --- /dev/null +++ b/platform/pddf/i2c/modules/xcvr/Makefile @@ -0,0 +1,4 @@ +subdir-m := driver +obj-m := pddf_xcvr_module.o + +CFLAGS_$(obj-m):= -I$(M)/modules/include diff --git a/platform/pddf/i2c/modules/xcvr/driver/Makefile b/platform/pddf/i2c/modules/xcvr/driver/Makefile new file mode 100644 index 0000000000..0b381d1fc2 --- /dev/null +++ b/platform/pddf/i2c/modules/xcvr/driver/Makefile @@ -0,0 +1,7 @@ +TARGET = pddf_xcvr_driver_module + +obj-m := $(TARGET).o + +$(TARGET)-objs := pddf_xcvr_api.o pddf_xcvr_driver.o + +ccflags-y := -I$(M)/modules/include diff --git a/platform/pddf/i2c/modules/xcvr/driver/pddf_xcvr_api.c b/platform/pddf/i2c/modules/xcvr/driver/pddf_xcvr_api.c new file mode 100644 index 0000000000..ddb7a1b3a2 --- /dev/null +++ b/platform/pddf/i2c/modules/xcvr/driver/pddf_xcvr_api.c @@ -0,0 +1,909 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * + * Description of various APIs related to transciever component + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pddf_xcvr_defs.h" + +/*#define SFP_DEBUG*/ +#ifdef SFP_DEBUG +#define sfp_dbg(...) printk(__VA_ARGS__) +#else +#define sfp_dbg(...) +#endif + +extern XCVR_SYSFS_ATTR_OPS xcvr_ops[]; +extern void *get_device_table(char *name); + +int get_xcvr_module_attr_data(struct i2c_client *client, struct device *dev, + struct device_attribute *da); + +int xcvr_i2c_cpld_read(XCVR_ATTR *info) +{ + int status = -1; + + if (info!=NULL) + { + if (info->len==1) + { + status = board_i2c_cpld_read(info->devaddr , info->offset); + } + else + { + /* Get the I2C client for the CPLD */ + struct i2c_client *client_ptr=NULL; + client_ptr = (struct i2c_client *)get_device_table(info->devname); + if (client_ptr) + { + if (info->len==2) + { + status = i2c_smbus_read_word_swapped(client_ptr, info->offset); + } + else + printk(KERN_ERR "PDDF_XCVR: Doesn't support block CPLD read yet"); + } + else + printk(KERN_ERR "Unable to get the client handle for %s\n", info->devname); + } + + } + + return status; +} + +int sonic_i2c_get_mod_pres(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data) +{ + int status = 0; + uint32_t modpres = 0; + + if ( strcmp(info->devtype, "cpld") == 0) + { + status = xcvr_i2c_cpld_read(info); + + if (status < 0) + return status; + else + { + modpres = ((status & BIT_INDEX(info->mask)) == info->cmpval) ? 1 : 0; + sfp_dbg(KERN_INFO "\nMod presence :0x%x, reg_value = 0x%x, devaddr=0x%x, mask=0x%x, offset=0x%x\n", modpres, status, info->devaddr, info->mask, info->offset); + } + } + else if(strcmp(info->devtype, "eeprom") == 0) + { + /* get client client for eeprom - Not Applicable */ + } + data->modpres = modpres; + + return 0; +} + +int sonic_i2c_get_mod_reset(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data) +{ + int status = 0; + uint32_t modreset=0; + + if (strcmp(info->devtype, "cpld") == 0) + { + status = xcvr_i2c_cpld_read(info); + if (status < 0) + return status; + else + { + modreset = ((status & BIT_INDEX(info->mask)) == info->cmpval) ? 1 : 0; + sfp_dbg(KERN_INFO "\nMod Reset :0x%x, reg_value = 0x%x\n", modreset, status); + } + } + else if(strcmp(info->devtype, "eeprom") == 0) + { + /* get client client for eeprom - Not Applicable */ + } + + data->reset = modreset; + return 0; +} + +int sonic_i2c_get_mod_intr_status(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data) +{ + int status = 0; + uint32_t mod_intr = 0; + + if (strcmp(info->devtype, "cpld") == 0) + { + status = xcvr_i2c_cpld_read(info); + if (status < 0) + return status; + else + { + mod_intr = ((status & BIT_INDEX(info->mask)) == info->cmpval) ? 1 : 0; + sfp_dbg(KERN_INFO "\nModule Interrupt :0x%x, reg_value = 0x%x\n", mod_intr, status); + } + } + else if(strcmp(info->devtype, "eeprom") == 0) + { + /* get client client for eeprom - Not Applicable */ + } + + data->intr_status = mod_intr; + return 0; +} + + +int sonic_i2c_get_mod_lpmode(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data) +{ + int status = 0; + uint32_t lpmode = 0; + + if (strcmp(info->devtype, "cpld") == 0) + { + status = xcvr_i2c_cpld_read(info); + if (status < 0) + return status; + else + { + lpmode = ((status & BIT_INDEX(info->mask)) == info->cmpval) ? 1 : 0; + sfp_dbg(KERN_INFO "\nModule LPmode :0x%x, reg_value = 0x%x\n", lpmode, status); + } + } + else if (strcmp(info->devtype, "eeprom") == 0) + { + /* get client client for eeprom - Not Applicable */ + } + + data->lpmode = lpmode; + return 0; +} + +int sonic_i2c_get_mod_rxlos(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data) +{ + int status = 0; + uint32_t rxlos = 0; + + + if (strcmp(info->devtype, "cpld") == 0) + { + status = xcvr_i2c_cpld_read(info); + if (status < 0) + return status; + else + { + rxlos = ((status & BIT_INDEX(info->mask)) == info->cmpval) ? 1 : 0; + sfp_dbg(KERN_INFO "\nModule RxLOS :0x%x, reg_value = 0x%x\n", rxlos, status); + } + } + data->rxlos = rxlos; + + return 0; +} + +int sonic_i2c_get_mod_txdisable(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data) +{ + int status = 0; + uint32_t txdis = 0; + + if (strcmp(info->devtype, "cpld") == 0) + { + status = xcvr_i2c_cpld_read(info); + if (status < 0) + return status; + else + { + txdis = ((status & BIT_INDEX(info->mask)) == info->cmpval) ? 1 : 0; + sfp_dbg(KERN_INFO "\nModule TxDisable :0x%x, reg_value = 0x%x\n", txdis, status); + } + } + data->txdisable = txdis; + + return 0; +} + +int sonic_i2c_get_mod_txfault(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data) +{ + int status = 0; + uint32_t txflt = 0; + + if (strcmp(info->devtype, "cpld") == 0) + { + status = xcvr_i2c_cpld_read(info); + if (status < 0) + return status; + else + { + txflt = ((status & BIT_INDEX(info->mask)) == info->cmpval) ? 1 : 0; + sfp_dbg(KERN_INFO "\nModule TxFault :0x%x, reg_value = 0x%x\n", txflt, status); + } + + } + data->txfault = txflt; + + return 0; +} + +int sonic_i2c_set_mod_reset(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data) +{ + int status = 0; + unsigned int val_mask = 0, dnd_value = 0; + uint32_t reg; + struct i2c_client *client_ptr=NULL; + + if (strcmp(info->devtype, "cpld") == 0) + { + val_mask = BIT_INDEX(info->mask); + /* Get the I2C client for the CPLD */ + client_ptr = (struct i2c_client *)get_device_table(info->devname); + + if (client_ptr) + { + if (info->len == 1) + status = board_i2c_cpld_read(info->devaddr , info->offset); + else if (info->len == 2) + status = i2c_smbus_read_word_data(client_ptr, info->offset); + else + { + printk(KERN_ERR "PDDF_XCVR: Doesn't support block CPLD read yet"); + status = -1; + } + } + else + { + printk(KERN_ERR "Unable to get the client handle for %s\n", info->devname); + status = -1; + } + /*printk(KERN_ERR "sonic_i2c_set_mod_reset:client_ptr=0x%x, status=0x%x, offset=0x%x, len=%d\n", client_ptr, status, info->offset, info->len);*/ + + if (status < 0) + return status; + else + { + dnd_value = status & ~val_mask; + if (((data->reset == 1) && (info->cmpval != 0)) || ((data->reset == 0) && (info->cmpval == 0))) + reg = dnd_value | val_mask; + else + reg = dnd_value; + if (info->len == 1) + status = board_i2c_cpld_write(info->devaddr, info->offset, (uint8_t)reg); + else if (info->len == 2) + status = i2c_smbus_write_word_swapped(client_ptr, info->offset, (uint16_t)reg); + else + { + printk(KERN_ERR "PDDF_XCVR: Doesn't support block CPLD write yet"); + status = -1; + } + } + } + + return status; +} + +int sonic_i2c_set_mod_lpmode(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data) +{ + int status = 0; + unsigned int val_mask = 0, dnd_value = 0; + uint32_t reg; + struct i2c_client *client_ptr=NULL; + + if (strcmp(info->devtype, "cpld") == 0) + { + val_mask = BIT_INDEX(info->mask); + /* Get the I2C client for the CPLD */ + client_ptr = (struct i2c_client *)get_device_table(info->devname); + + if (client_ptr) + { + if (info->len == 1) + status = board_i2c_cpld_read(info->devaddr , info->offset); + else if (info->len == 2) + status = i2c_smbus_read_word_data(client_ptr, info->offset); + else + { + printk(KERN_ERR "PDDF_XCVR: Doesn't support block CPLD read yet"); + status = -1; + } + } + else + { + printk(KERN_ERR "Unable to get the client handle for %s\n", info->devname); + status = -1; + } + + if (status < 0) + return status; + else + { + dnd_value = status & ~val_mask; + if (((data->lpmode == 1) && (info->cmpval != 0)) || ((data->lpmode == 0) && (info->cmpval == 0))) + reg = dnd_value | val_mask; + else + reg = dnd_value; + if (info->len == 1) + status = board_i2c_cpld_write(info->devaddr, info->offset, (uint8_t)reg); + else if (info->len == 2) + status = i2c_smbus_write_word_swapped(client_ptr, info->offset, (uint16_t)reg); + else + { + printk(KERN_ERR "PDDF_XCVR: Doesn't support block CPLD write yet"); + status = -1; + } + } + } + + return status; +} + +int sonic_i2c_set_mod_txdisable(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data) +{ + int status = 0; + unsigned int val_mask = 0, dnd_value = 0; + uint32_t reg; + struct i2c_client *client_ptr=NULL; + + if (strcmp(info->devtype, "cpld") == 0) + { + val_mask = BIT_INDEX(info->mask); + /* Get the I2C client for the CPLD */ + client_ptr = (struct i2c_client *)get_device_table(info->devname); + + if (client_ptr) + { + if (info->len == 1) + status = board_i2c_cpld_read(info->devaddr , info->offset); + else if (info->len == 2) + status = i2c_smbus_read_word_data(client_ptr, info->offset); + else + { + printk(KERN_ERR "PDDF_XCVR: Doesn't support block CPLD read yet"); + status = -1; + } + } + else + { + printk(KERN_ERR "Unable to get the client handle for %s\n", info->devname); + status = -1; + } + + if (status < 0) + return status; + else + { + dnd_value = status & ~val_mask; + if (((data->txdisable == 1) && (info->cmpval != 0)) || ((data->txdisable == 0) && (info->cmpval == 0))) + reg = dnd_value | val_mask; + else + reg = dnd_value; + if (info->len == 1) + status = board_i2c_cpld_write(info->devaddr, info->offset, (uint8_t)reg); + else if (info->len == 2) + status = i2c_smbus_write_word_swapped(client_ptr, info->offset, (uint16_t)reg); + else + { + printk(KERN_ERR "PDDF_XCVR: Doesn't support block CPLD write yet"); + status = -1; + } + } + } + + return status; +} + +ssize_t get_module_presence(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct xcvr_data *data = i2c_get_clientdata(client); + XCVR_PDATA *pdata = (XCVR_PDATA *)(client->dev.platform_data); + XCVR_ATTR *attr_data = NULL; + XCVR_SYSFS_ATTR_OPS *attr_ops = NULL; + int status = 0, i; + + for (i=0; ilen; i++) + { + attr_data = &pdata->xcvr_attrs[i]; + if (strcmp(attr_data->aname, attr->dev_attr.attr.name) == 0) + { + attr_ops = &xcvr_ops[attr->index]; + + mutex_lock(&data->update_lock); + if (attr_ops->pre_get != NULL) + { + status = (attr_ops->pre_get)(client, attr_data, data); + if (status!=0) + printk(KERN_ERR "%s: pre_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname); + } + if (attr_ops->do_get != NULL) + { + status = (attr_ops->do_get)(client, attr_data, data); + if (status!=0) + printk(KERN_ERR "%s: do_get function fails for %s attribute. ret %d\n", __FUNCTION__, attr_data->aname, status); + + } + if (attr_ops->post_get != NULL) + { + status = (attr_ops->post_get)(client, attr_data, data); + if (status!=0) + printk(KERN_ERR "%s: post_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname); + } + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", data->modpres); + } + } + return sprintf(buf, "%s",""); +} + +ssize_t get_module_reset(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct xcvr_data *data = i2c_get_clientdata(client); + XCVR_PDATA *pdata = (XCVR_PDATA *)(client->dev.platform_data); + XCVR_ATTR *attr_data = NULL; + XCVR_SYSFS_ATTR_OPS *attr_ops = NULL; + int status = 0, i; + + for (i=0; ilen; i++) + { + attr_data = &pdata->xcvr_attrs[i]; + if (strcmp(attr_data->aname, attr->dev_attr.attr.name) == 0) + { + attr_ops = &xcvr_ops[attr->index]; + + mutex_lock(&data->update_lock); + if (attr_ops->pre_get != NULL) + { + status = (attr_ops->pre_get)(client, attr_data, data); + if (status!=0) + printk(KERN_ERR "%s: pre_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname); + } + if (attr_ops->do_get != NULL) + { + status = (attr_ops->do_get)(client, attr_data, data); + if (status!=0) + printk(KERN_ERR "%s: do_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname); + + } + if (attr_ops->post_get != NULL) + { + status = (attr_ops->post_get)(client, attr_data, data); + if (status!=0) + printk(KERN_ERR "%s: post_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname); + } + + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", data->reset); + } + } + return sprintf(buf, "%s",""); +} + +ssize_t set_module_reset(struct device *dev, struct device_attribute *da, const char *buf, + size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct xcvr_data *data = i2c_get_clientdata(client); + XCVR_PDATA *pdata = (XCVR_PDATA *)(client->dev.platform_data); + XCVR_ATTR *attr_data = NULL; + XCVR_SYSFS_ATTR_OPS *attr_ops = NULL; + int status = 0, i; + unsigned int set_value; + + for (i=0; ilen; i++) + { + attr_data = &pdata->xcvr_attrs[i]; + if (strcmp(attr_data->aname, attr->dev_attr.attr.name) == 0) + { + attr_ops = &xcvr_ops[attr->index]; + if(kstrtoint(buf, 10, &set_value)) + return -EINVAL; + if ((set_value != 1) && (set_value != 0)) + return -EINVAL; + + data->reset = set_value; + + mutex_lock(&data->update_lock); + + if (attr_ops->pre_set != NULL) + { + status = (attr_ops->pre_set)(client, attr_data, data); + if (status!=0) + printk(KERN_ERR "%s: pre_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname); + } + if (attr_ops->do_set != NULL) + { + status = (attr_ops->do_set)(client, attr_data, data); + if (status!=0) + printk(KERN_ERR "%s: do_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname); + + } + if (attr_ops->post_set != NULL) + { + status = (attr_ops->post_set)(client, attr_data, data); + if (status!=0) + printk(KERN_ERR "%s: post_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname); + } + mutex_unlock(&data->update_lock); + + return count; + } + } + return -EINVAL; +} + +ssize_t get_module_intr_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct xcvr_data *data = i2c_get_clientdata(client); + XCVR_PDATA *pdata = (XCVR_PDATA *)(client->dev.platform_data); + XCVR_ATTR *attr_data = NULL; + XCVR_SYSFS_ATTR_OPS *attr_ops = NULL; + int status = 0, i; + + for (i=0; ilen; i++) + { + attr_data = &pdata->xcvr_attrs[i]; + if (strcmp(attr_data->aname, attr->dev_attr.attr.name) == 0) + { + attr_ops = &xcvr_ops[attr->index]; + + mutex_lock(&data->update_lock); + if (attr_ops->pre_get != NULL) + { + status = (attr_ops->pre_get)(client, attr_data, data); + if (status!=0) + printk(KERN_ERR "%s: pre_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname); + } + if (attr_ops->do_get != NULL) + { + status = (attr_ops->do_get)(client, attr_data, data); + if (status!=0) + printk(KERN_ERR "%s: do_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname); + + } + if (attr_ops->post_get != NULL) + { + status = (attr_ops->post_get)(client, attr_data, data); + if (status!=0) + printk(KERN_ERR "%s: post_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname); + } + + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", data->intr_status); + } + } + return sprintf(buf, "%s",""); +} + +int get_xcvr_module_attr_data(struct i2c_client *client, struct device *dev, + struct device_attribute *da) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + XCVR_PDATA *pdata = (XCVR_PDATA *)(client->dev.platform_data); + XCVR_ATTR *attr_data = NULL; + int i; + + for (i=0; i < pdata->len; i++) + { + attr_data = &pdata->xcvr_attrs[i]; + if (strcmp(attr_data->aname, attr->dev_attr.attr.name) == 0) + { + return i; + } + } + return -1; +} + +ssize_t get_module_lpmode(struct device *dev, struct device_attribute *da, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + XCVR_PDATA *pdata = (XCVR_PDATA *)(client->dev.platform_data); + struct xcvr_data *data = i2c_get_clientdata(client); + XCVR_ATTR *attr_data = NULL; + XCVR_SYSFS_ATTR_OPS *attr_ops = NULL; + int idx, status = 0; + + idx = get_xcvr_module_attr_data(client, dev, da); + + if (idx>=0) attr_data = &pdata->xcvr_attrs[idx]; + + if (attr_data!=NULL) + { + + attr_ops = &xcvr_ops[attr->index]; + + mutex_lock(&data->update_lock); + if (attr_ops->pre_get != NULL) + { + status = (attr_ops->pre_get)(client, attr_data, data); + if (status!=0) + printk(KERN_ERR "%s: pre_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname); + } + if (attr_ops->do_get != NULL) + { + status = (attr_ops->do_get)(client, attr_data, data); + if (status!=0) + printk(KERN_ERR "%s: do_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname); + + } + if (attr_ops->post_get != NULL) + { + status = (attr_ops->post_get)(client, attr_data, data); + if (status!=0) + printk(KERN_ERR "%s: post_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname); + } + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", data->lpmode); + } + else + return sprintf(buf,"%s",""); +} + +ssize_t set_module_lpmode(struct device *dev, struct device_attribute *da, const char *buf, + size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct xcvr_data *data = i2c_get_clientdata(client); + XCVR_PDATA *pdata = (XCVR_PDATA *)(client->dev.platform_data); + int idx, status = 0; + uint32_t set_value; + XCVR_ATTR *attr_data = NULL; + XCVR_SYSFS_ATTR_OPS *attr_ops = NULL; + + idx = get_xcvr_module_attr_data(client, dev, da); + + if (idx>=0) attr_data = &pdata->xcvr_attrs[idx]; + + if (attr_data!=NULL) + { + attr_ops = &xcvr_ops[attr->index]; + if(kstrtoint(buf, 10, &set_value)) + return -EINVAL; + if ((set_value != 1) && (set_value != 0)) + return -EINVAL; + + data->lpmode = set_value; + + mutex_lock(&data->update_lock); + + if (attr_ops->pre_set != NULL) + { + status = (attr_ops->pre_set)(client, attr_data, data); + if (status!=0) + printk(KERN_ERR "%s: pre_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname); + } + if (attr_ops->do_set != NULL) + { + status = (attr_ops->do_set)(client, attr_data, data); + if (status!=0) + printk(KERN_ERR "%s: do_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname); + + } + if (attr_ops->post_set != NULL) + { + status = (attr_ops->post_set)(client, attr_data, data); + if (status!=0) + printk(KERN_ERR "%s: post_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname); + } + mutex_unlock(&data->update_lock); + } + return count; +} + +ssize_t get_module_rxlos(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct xcvr_data *data = i2c_get_clientdata(client); + XCVR_PDATA *pdata = (XCVR_PDATA *)(client->dev.platform_data); + int idx, status = 0; + XCVR_ATTR *attr_data = NULL; + XCVR_SYSFS_ATTR_OPS *attr_ops = NULL; + + idx = get_xcvr_module_attr_data(client, dev, da); + + if (idx>=0) attr_data = &pdata->xcvr_attrs[idx]; + + if (attr_data!=NULL) + { + attr_ops = &xcvr_ops[attr->index]; + + mutex_lock(&data->update_lock); + if (attr_ops->pre_get != NULL) + { + status = (attr_ops->pre_get)(client, attr_data, data); + if (status!=0) + printk(KERN_ERR "%s: pre_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname); + } + if (attr_ops->do_get != NULL) + { + status = (attr_ops->do_get)(client, attr_data, data); + if (status!=0) + printk(KERN_ERR "%s: do_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname); + + } + if (attr_ops->post_get != NULL) + { + status = (attr_ops->post_get)(client, attr_data, data); + if (status!=0) + printk(KERN_ERR "%s: post_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname); + } + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", data->rxlos); + } + else + return sprintf(buf,"%s",""); +} + +ssize_t get_module_txdisable(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct xcvr_data *data = i2c_get_clientdata(client); + XCVR_PDATA *pdata = (XCVR_PDATA *)(client->dev.platform_data); + int idx, status = 0; + XCVR_ATTR *attr_data = NULL; + XCVR_SYSFS_ATTR_OPS *attr_ops = NULL; + + idx = get_xcvr_module_attr_data(client, dev, da); + + if (idx>=0) attr_data = &pdata->xcvr_attrs[idx]; + + if (attr_data!=NULL) + { + attr_ops = &xcvr_ops[attr->index]; + + mutex_lock(&data->update_lock); + if (attr_ops->pre_get != NULL) + { + status = (attr_ops->pre_get)(client, attr_data, data); + if (status!=0) + printk(KERN_ERR "%s: pre_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname); + } + if (attr_ops->do_get != NULL) + { + status = (attr_ops->do_get)(client, attr_data, data); + if (status!=0) + printk(KERN_ERR "%s: do_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname); + + } + if (attr_ops->post_get != NULL) + { + status = (attr_ops->post_get)(client, attr_data, data); + if (status!=0) + printk(KERN_ERR "%s: post_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname); + } + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", data->txdisable); + } + else + return sprintf(buf,"%s",""); +} + +ssize_t set_module_txdisable(struct device *dev, struct device_attribute *da, const char *buf, + size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct xcvr_data *data = i2c_get_clientdata(client); + XCVR_PDATA *pdata = (XCVR_PDATA *)(client->dev.platform_data); + int idx, status = 0; + uint32_t set_value; + XCVR_ATTR *attr_data = NULL; + XCVR_SYSFS_ATTR_OPS *attr_ops = NULL; + + idx = get_xcvr_module_attr_data(client, dev, da); + + if (idx>=0) attr_data = &pdata->xcvr_attrs[idx]; + + if (attr_data!=NULL) + { + attr_ops = &xcvr_ops[attr->index]; + if(kstrtoint(buf, 10, &set_value)) + return -EINVAL; + if ((set_value != 1) && (set_value != 0)) + return -EINVAL; + + data->txdisable = set_value; + + mutex_lock(&data->update_lock); + + if (attr_ops->pre_set != NULL) + { + status = (attr_ops->pre_set)(client, attr_data, data); + if (status!=0) + printk(KERN_ERR "%s: pre_set function fails for %s attribute\n", __FUNCTION__, attr_data->aname); + } + if (attr_ops->do_set != NULL) + { + status = (attr_ops->do_set)(client, attr_data, data); + if (status!=0) + printk(KERN_ERR "%s: do_set function fails for %s attribute\n", __FUNCTION__, attr_data->aname); + + } + if (attr_ops->post_set != NULL) + { + status = (attr_ops->post_set)(client, attr_data, data); + if (status!=0) + printk(KERN_ERR "%s: post_set function fails for %s attribute\n", __FUNCTION__, attr_data->aname); + } + mutex_unlock(&data->update_lock); + } + return count; +} + +ssize_t get_module_txfault(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + XCVR_PDATA *pdata = (XCVR_PDATA *)(client->dev.platform_data); + struct xcvr_data *data = i2c_get_clientdata(client); + int idx, status = 0; + XCVR_ATTR *attr_data = NULL; + XCVR_SYSFS_ATTR_OPS *attr_ops = NULL; + + idx = get_xcvr_module_attr_data(client, dev, da); + + if (idx>=0) attr_data = &pdata->xcvr_attrs[idx]; + + if (attr_data!=NULL) + { + attr_ops = &xcvr_ops[attr->index]; + + mutex_lock(&data->update_lock); + if (attr_ops->pre_get != NULL) + { + status = (attr_ops->pre_get)(client, attr_data, data); + if (status!=0) + printk(KERN_ERR "%s: pre_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname); + } + if (attr_ops->do_get != NULL) + { + status = (attr_ops->do_get)(client, attr_data, data); + if (status!=0) + printk(KERN_ERR "%s: do_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname); + + } + if (attr_ops->post_get != NULL) + { + status = (attr_ops->post_get)(client, attr_data, data); + if (status!=0) + printk(KERN_ERR "%s: post_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname); + } + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", data->txfault); + } + return sprintf(buf,"%s",""); +} diff --git a/platform/pddf/i2c/modules/xcvr/driver/pddf_xcvr_driver.c b/platform/pddf/i2c/modules/xcvr/driver/pddf_xcvr_driver.c new file mode 100644 index 0000000000..142d38a2ff --- /dev/null +++ b/platform/pddf/i2c/modules/xcvr/driver/pddf_xcvr_driver.c @@ -0,0 +1,296 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * + * A pddf kernel driver module for Optic component + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pddf_client_defs.h" +#include "pddf_xcvr_defs.h" +#include "pddf_xcvr_api.h" + + +struct pddf_ops_t pddf_xcvr_ops = { + .pre_init = NULL, + .post_init = NULL, + + .pre_probe = NULL, + .post_probe = NULL, + + .pre_remove = NULL, + .post_remove = NULL, + + .pre_exit = NULL, + .post_exit = NULL, +}; +EXPORT_SYMBOL(pddf_xcvr_ops); + +XCVR_SYSFS_ATTR_OPS xcvr_ops[XCVR_ATTR_MAX] = { + {XCVR_PRESENT, get_module_presence, NULL, sonic_i2c_get_mod_pres, NULL, NULL, NULL, NULL, NULL}, + {XCVR_RESET, get_module_reset, NULL, sonic_i2c_get_mod_reset, NULL, set_module_reset, NULL, sonic_i2c_set_mod_reset, NULL}, + {XCVR_INTR_STATUS, get_module_intr_status, NULL, sonic_i2c_get_mod_intr_status, NULL, NULL, NULL, NULL, NULL}, + {XCVR_LPMODE, get_module_lpmode, NULL, sonic_i2c_get_mod_lpmode, NULL, set_module_lpmode, NULL, sonic_i2c_set_mod_lpmode, NULL}, + {XCVR_RXLOS, get_module_rxlos, NULL, sonic_i2c_get_mod_rxlos, NULL, NULL, NULL, NULL, NULL}, + {XCVR_TXDISABLE, get_module_txdisable, NULL, sonic_i2c_get_mod_txdisable, NULL, set_module_txdisable, NULL, sonic_i2c_set_mod_txdisable, NULL}, + {XCVR_TXFAULT, get_module_txfault, NULL, sonic_i2c_get_mod_txfault, NULL, NULL, NULL, NULL, NULL}, +}; +EXPORT_SYMBOL(xcvr_ops); + + +/* sysfs attributes + */ +static SENSOR_DEVICE_ATTR(xcvr_present, S_IWUSR|S_IRUGO, get_module_presence, NULL, XCVR_PRESENT); +static SENSOR_DEVICE_ATTR(xcvr_reset, S_IWUSR|S_IRUGO, get_module_reset, set_module_reset, XCVR_RESET); +static SENSOR_DEVICE_ATTR(xcvr_intr_status, S_IWUSR|S_IRUGO, get_module_intr_status, NULL, XCVR_INTR_STATUS); +static SENSOR_DEVICE_ATTR(xcvr_lpmode, S_IWUSR|S_IRUGO, get_module_lpmode, set_module_lpmode, XCVR_LPMODE); +static SENSOR_DEVICE_ATTR(xcvr_rxlos, S_IWUSR|S_IRUGO, get_module_rxlos, NULL, XCVR_RXLOS); +static SENSOR_DEVICE_ATTR(xcvr_txdisable, S_IWUSR|S_IRUGO, get_module_txdisable, set_module_txdisable, XCVR_TXDISABLE); +static SENSOR_DEVICE_ATTR(xcvr_txfault, S_IWUSR|S_IRUGO, get_module_txfault, NULL, XCVR_TXFAULT); + +/* List of all the xcvr attribute structures + * to get name, use sensor_dev_attr_<>.dev_attr.attr.name + * to get the id, use sensor_dev_attr_<>.dev_attr.index + */ +static struct sensor_device_attribute *xcvr_attr_list[MAX_XCVR_ATTRS] = { + &sensor_dev_attr_xcvr_present, + &sensor_dev_attr_xcvr_reset, + &sensor_dev_attr_xcvr_intr_status, + &sensor_dev_attr_xcvr_lpmode, + &sensor_dev_attr_xcvr_rxlos, + &sensor_dev_attr_xcvr_txdisable, + &sensor_dev_attr_xcvr_txfault, +}; + +static struct attribute *xcvr_attributes[MAX_XCVR_ATTRS] = {NULL}; + +static const struct attribute_group xcvr_group = { + .attrs = xcvr_attributes, +}; + +static int xcvr_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + struct xcvr_data *data; + int status =0; + int i,j,num; + XCVR_PDATA *xcvr_platform_data; + XCVR_ATTR *attr_data; + + if (client == NULL) { + pddf_dbg(XCVR, "NULL Client.. \n"); + goto exit; + } + + if (pddf_xcvr_ops.pre_probe) + { + status = (pddf_xcvr_ops.pre_probe)(client, dev_id); + if (status != 0) + goto exit; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) { + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(struct xcvr_data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + data->valid = 0; + + dev_info(&client->dev, "chip found\n"); + + /* Take control of the platform data */ + xcvr_platform_data = (XCVR_PDATA *)(client->dev.platform_data); + num = xcvr_platform_data->len; + data->index = xcvr_platform_data->idx - 1; + mutex_init(&data->update_lock); + + /* Add supported attr in the 'attributes' list */ + for (i=0; ixcvr_attrs + i; + for(j=0;jdev_attr.attr; + + if (strncmp(aptr->name, attr_data->aname, strlen(attr_data->aname))==0) + break; + } + + if (jdev_attr.attr; + + } + xcvr_attributes[i] = NULL; + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &xcvr_group); + if (status) { + goto exit_free; + } + + data->xdev = hwmon_device_register(&client->dev); + if (IS_ERR(data->xdev)) { + status = PTR_ERR(data->xdev); + goto exit_remove; + } + + dev_info(&client->dev, "%s: xcvr '%s'\n", + dev_name(data->xdev), client->name); + + /* Add a support for post probe function */ + if (pddf_xcvr_ops.post_probe) + { + status = (pddf_xcvr_ops.post_probe)(client, dev_id); + if (status != 0) + goto exit_remove; + } + + + return 0; + + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &xcvr_group); +exit_free: + kfree(data); +exit: + + return status; +} + +static int xcvr_remove(struct i2c_client *client) +{ + int ret = 0; + struct xcvr_data *data = i2c_get_clientdata(client); + XCVR_PDATA *platdata = (XCVR_PDATA *)client->dev.platform_data; + XCVR_ATTR *platdata_sub = platdata->xcvr_attrs; + + if (pddf_xcvr_ops.pre_remove) + { + ret = (pddf_xcvr_ops.pre_remove)(client); + if (ret!=0) + printk(KERN_ERR "FAN pre_remove function failed\n"); + } + + hwmon_device_unregister(data->xdev); + sysfs_remove_group(&client->dev.kobj, &xcvr_group); + kfree(data); + + if (platdata_sub) { + pddf_dbg(XCVR, KERN_DEBUG "%s: Freeing platform subdata\n", __FUNCTION__); + kfree(platdata_sub); + } + if (platdata) { + pddf_dbg(XCVR, KERN_DEBUG "%s: Freeing platform data\n", __FUNCTION__); + kfree(platdata); + } + + if (pddf_xcvr_ops.post_remove) + { + ret = (pddf_xcvr_ops.post_remove)(client); + if (ret!=0) + printk(KERN_ERR "FAN post_remove function failed\n"); + } + + return 0; +} + +enum xcvr_intf +{ + XCVR_CTRL_INTF, +}; + +static const struct i2c_device_id xcvr_ids[] = { + { "pddf_xcvr", XCVR_CTRL_INTF }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, xcvr_ids); + +static struct i2c_driver xcvr_driver = { + /*.class = I2C_CLASS_HWMON,*/ + .driver = { + .name = "xcvr", + .owner = THIS_MODULE, + }, + .probe = xcvr_probe, + .remove = xcvr_remove, + .id_table = xcvr_ids, +}; + + +/*int __init xcvr_init(void)*/ +int xcvr_init(void) +{ + int ret = 0; + + if (pddf_xcvr_ops.pre_init) + { + ret = (pddf_xcvr_ops.pre_init)(); + if (ret!=0) + return ret; + } + + pddf_dbg(XCVR, KERN_ERR "PDDF XCVR DRIVER.. init Invoked..\n"); + ret = i2c_add_driver(&xcvr_driver); + if (ret!=0) + return ret; + + if (pddf_xcvr_ops.post_init) + { + ret = (pddf_xcvr_ops.post_init)(); + if (ret!=0) + return ret; + } + + return ret; +} +EXPORT_SYMBOL(xcvr_init); + +void __exit xcvr_exit(void) +{ + pddf_dbg(XCVR, "PDDF XCVR DRIVER.. exit\n"); + if (pddf_xcvr_ops.pre_exit) (pddf_xcvr_ops.pre_exit)(); + i2c_del_driver(&xcvr_driver); + if (pddf_xcvr_ops.post_exit) (pddf_xcvr_ops.post_exit)(); + +} +EXPORT_SYMBOL(xcvr_exit); + +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("Driver for transceiver operations"); +MODULE_LICENSE("GPL"); + +module_init(xcvr_init); +module_exit(xcvr_exit); diff --git a/platform/pddf/i2c/modules/xcvr/pddf_xcvr_module.c b/platform/pddf/i2c/modules/xcvr/pddf_xcvr_module.c new file mode 100644 index 0000000000..65c555b742 --- /dev/null +++ b/platform/pddf/i2c/modules/xcvr/pddf_xcvr_module.c @@ -0,0 +1,275 @@ +/* + * Copyright 2019 Broadcom. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + * + * 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 2 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. + * + * + * A pddf kernel module to create i2C client for optics + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pddf_client_defs.h" +#include "pddf_xcvr_defs.h" + +static ssize_t do_attr_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count); +static ssize_t do_device_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count); +extern void* get_device_table(char *name); +extern void delete_device_table(char *name); + +XCVR_DATA xcvr_data = {0}; + +/* XCVR CLIENT DATA */ +PDDF_DATA_ATTR(dev_idx, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_DEC, sizeof(int), (void*)&xcvr_data.idx, NULL); + +PDDF_DATA_ATTR(attr_name, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_CHAR, 32, (void*)&xcvr_data.xcvr_attr.aname, NULL); +PDDF_DATA_ATTR(attr_devtype, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_CHAR, 8, (void*)&xcvr_data.xcvr_attr.devtype, NULL); +PDDF_DATA_ATTR(attr_devname, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_CHAR, 8, (void*)&xcvr_data.xcvr_attr.devname, NULL); +PDDF_DATA_ATTR(attr_devaddr, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32, sizeof(uint32_t), (void*)&xcvr_data.xcvr_attr.devaddr, NULL); +PDDF_DATA_ATTR(attr_offset, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32, sizeof(uint32_t), (void*)&xcvr_data.xcvr_attr.offset, NULL); +PDDF_DATA_ATTR(attr_mask, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32, sizeof(uint32_t), (void*)&xcvr_data.xcvr_attr.mask, NULL); +PDDF_DATA_ATTR(attr_cmpval, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32, sizeof(uint32_t), (void*)&xcvr_data.xcvr_attr.cmpval, NULL); +PDDF_DATA_ATTR(attr_len, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_DEC, sizeof(int), (void*)&xcvr_data.xcvr_attr.len, NULL); +PDDF_DATA_ATTR(attr_ops, S_IWUSR, NULL, do_attr_operation, PDDF_CHAR, 8, (void*)&xcvr_data, NULL); +PDDF_DATA_ATTR(dev_ops, S_IWUSR, NULL, do_device_operation, PDDF_CHAR, 8, (void*)&xcvr_data, (void*)&pddf_data); + + +static struct attribute *xcvr_attributes[] = { + &attr_dev_idx.dev_attr.attr, + + &attr_attr_name.dev_attr.attr, + &attr_attr_devtype.dev_attr.attr, + &attr_attr_devname.dev_attr.attr, + &attr_attr_devaddr.dev_attr.attr, + &attr_attr_offset.dev_attr.attr, + &attr_attr_mask.dev_attr.attr, + &attr_attr_cmpval.dev_attr.attr, + &attr_attr_len.dev_attr.attr, + &attr_attr_ops.dev_attr.attr, + &attr_dev_ops.dev_attr.attr, + NULL +}; + +static const struct attribute_group pddf_xcvr_client_data_group = { + .attrs = xcvr_attributes, +}; + + +static ssize_t do_attr_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count) +{ + PDDF_ATTR *ptr = (PDDF_ATTR *)da; + XCVR_DATA *pdata = (XCVR_DATA *)(ptr->addr); + + pdata->xcvr_attrs[pdata->len] = pdata->xcvr_attr; + pdata->len++; + memset(&pdata->xcvr_attr, 0, sizeof(pdata->xcvr_attr)); + + + return count; +} + +/*PDDF_DATA_ATTR(dev_ops, S_IWUSR, NULL, do_device_operation, PDDF_CHAR, 8, (void*)&pddf_attr, (void*)NULL);*/ +static ssize_t do_device_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count) +{ + int i = 0; + PDDF_ATTR *ptr = (PDDF_ATTR *)da; + XCVR_DATA *pdata = (XCVR_DATA *)(ptr->addr); + NEW_DEV_ATTR *cdata = (NEW_DEV_ATTR *)(ptr->data); + + struct i2c_adapter *adapter; + struct i2c_board_info board_info; + struct i2c_client *client_ptr; + + /* Populate the platform data for xcvr */ + if (strncmp(buf, "add", strlen(buf)-1)==0) + { + if (strcmp(cdata->dev_type, "pddf_xcvr")==0) + { + int num = pdata->len; + XCVR_PDATA *xcvr_platform_data; + + adapter = i2c_get_adapter(cdata->parent_bus); + /* Allocate the xcvr_platform_data */ + xcvr_platform_data = (XCVR_PDATA *)kzalloc(sizeof(XCVR_PDATA), GFP_KERNEL); + xcvr_platform_data->xcvr_attrs = (XCVR_ATTR *)kzalloc(num*sizeof(XCVR_ATTR), GFP_KERNEL); + + + xcvr_platform_data->idx = pdata->idx; + xcvr_platform_data->len = pdata->len; + + for (i=0;ixcvr_attrs[i] = pdata->xcvr_attrs[i]; + } + + board_info = (struct i2c_board_info) { + .platform_data = xcvr_platform_data, + }; + + board_info.addr = cdata->dev_addr; + strcpy(board_info.type, cdata->dev_type); + + client_ptr = i2c_new_device(adapter, &board_info); + if (client_ptr != NULL) { + i2c_put_adapter(adapter); + pddf_dbg(XCVR, KERN_ERR "Created a %s client: 0x%p\n", cdata->i2c_name, (void *)client_ptr); + add_device_table(cdata->i2c_name, (void*)client_ptr); + } + else + { + i2c_put_adapter(adapter); + goto free_data; + } + } + else if((strcmp(cdata->dev_type, "optoe1")==0) || (strcmp(cdata->dev_type, "optoe2")==0)) + { + + adapter = i2c_get_adapter(cdata->parent_bus); + board_info = (struct i2c_board_info) { + .platform_data = (void *)NULL, + }; + + board_info.addr = cdata->dev_addr; + strcpy(board_info.type, cdata->dev_type); + + client_ptr = i2c_new_device(adapter, &board_info); + if(client_ptr != NULL) { + i2c_put_adapter(adapter); + pddf_dbg(XCVR, KERN_ERR "Created %s, type:%s client: 0x%p\n", cdata->i2c_name, cdata->dev_type, (void *)client_ptr); + add_device_table(cdata->i2c_name, (void*)client_ptr); + } + else + { + i2c_put_adapter(adapter); + printk(KERN_ERR "Error creating a client %s on 0x%x, client_ptr:0x%p\n", board_info.type, board_info.addr, (void *)client_ptr); + goto free_data; + } + } + else + { + printk(KERN_ERR "%s:Unknown type of device %s. Unable to create I2C client for it\n",__FUNCTION__, cdata->dev_type); + } + } + else if (strncmp(buf, "delete", strlen(buf)-1)==0) + { + /*Get the i2c_client handle for the created client*/ + client_ptr = (struct i2c_client *)get_device_table(cdata->i2c_name); + if (client_ptr) + { + pddf_dbg(XCVR, KERN_ERR "Removing %s client: 0x%p\n", cdata->i2c_name, (void *)client_ptr); + i2c_unregister_device(client_ptr); + delete_device_table(cdata->i2c_name); + } + else + { + pddf_dbg(XCVR, KERN_ERR "Unable to get the client handle for %s\n", cdata->i2c_name); + } + } + else + { + printk(KERN_ERR "PDDF_ERROR: %s: Invalid value for dev_ops %s", __FUNCTION__, buf); + } + + goto clear_data; + +free_data: + if (board_info.platform_data) + { + XCVR_PDATA *xcvr_platform_data = board_info.platform_data; + if (xcvr_platform_data->xcvr_attrs) + { + printk(KERN_ERR "%s: Unable to create i2c client. Freeing the platform subdata\n", __FUNCTION__); + kfree(xcvr_platform_data->xcvr_attrs); + } + printk(KERN_ERR "%s: Unable to create i2c client. Freeing the platform data\n", __FUNCTION__); + kfree(xcvr_platform_data); + } + +clear_data: + memset(pdata, 0, sizeof(XCVR_DATA)); + /*TODO: free the data cdata->data if data is dynal=mically allocated*/ + memset(cdata, 0, sizeof(NEW_DEV_ATTR)); + return count; +} + +struct kobject *xcvr_kobj; +struct kobject *i2c_kobj; +int __init pddf_data_init(void) +{ + struct kobject *device_kobj; + int ret = 0; + + pddf_dbg(XCVR, KERN_ERR "XCVR PDDF MODULE.. init\n"); + + device_kobj = get_device_i2c_kobj(); + if(!device_kobj) + return -ENOMEM; + + xcvr_kobj = kobject_create_and_add("xcvr", device_kobj); + if(!xcvr_kobj) + return -ENOMEM; + i2c_kobj = kobject_create_and_add("i2c", xcvr_kobj); + if(!i2c_kobj) + return -ENOMEM; + + ret = sysfs_create_group(i2c_kobj, &pddf_clients_data_group); + if (ret) + { + kobject_put(i2c_kobj); + kobject_put(xcvr_kobj); + return ret; + } + pddf_dbg(XCVR, "CREATED SFP I2C CLIENTS CREATION SYSFS GROUP\n"); + + ret = sysfs_create_group(i2c_kobj, &pddf_xcvr_client_data_group); + if (ret) + { + sysfs_remove_group(i2c_kobj, &pddf_clients_data_group); + kobject_put(i2c_kobj); + kobject_put(xcvr_kobj); + return ret; + } + pddf_dbg(XCVR, "CREATED PDDF SFP DATA SYSFS GROUP\n"); + + return ret; +} + +void __exit pddf_data_exit(void) +{ + + pddf_dbg(XCVR, "XCVR PDDF MODULE.. exit\n"); + sysfs_remove_group(i2c_kobj, &pddf_xcvr_client_data_group); + sysfs_remove_group(i2c_kobj, &pddf_clients_data_group); + kobject_put(i2c_kobj); + kobject_put(xcvr_kobj); + pddf_dbg(XCVR, KERN_ERR "%s: Removed the kobjects for 'i2c' and 'xcvr'\n",__FUNCTION__); + + return; +} + +module_init(pddf_data_init); +module_exit(pddf_data_exit); + +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("sfp platform data"); +MODULE_LICENSE("GPL"); diff --git a/platform/pddf/i2c/service/pddf-platform-init.service b/platform/pddf/i2c/service/pddf-platform-init.service new file mode 100644 index 0000000000..ccb8d1110f --- /dev/null +++ b/platform/pddf/i2c/service/pddf-platform-init.service @@ -0,0 +1,13 @@ +[Unit] +Description=PDDF module and device initialization service +Before=pmon.service +DefaultDependencies=no + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/pddf_util.py install +ExecStop=/usr/local/bin/pddf_util.py clean +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target diff --git a/platform/pddf/i2c/setup.py b/platform/pddf/i2c/setup.py new file mode 100755 index 0000000000..04da78cd53 --- /dev/null +++ b/platform/pddf/i2c/setup.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python + +from setuptools import setup +import os + +setup( + name='pddf-platform', + version='%s' % os.environ.get('PLATFORM_MODULE_VERSION', '1.0'), + description='Module to initialize Platform', + packages=[ + 'modules', + ], +) + diff --git a/platform/pddf/i2c/utils/pddf_util.py b/platform/pddf/i2c/utils/pddf_util.py new file mode 100755 index 0000000000..127f37d6b2 --- /dev/null +++ b/platform/pddf/i2c/utils/pddf_util.py @@ -0,0 +1,605 @@ +#!/usr/bin/env python + + +""" +Usage: %(scriptName)s [options] command object + +options: + -h | --help : this help message + -d | --debug : run with debug mode + -f | --force : ignore error during installation or clean +command: + install : install drivers and generate related sysfs nodes + clean : uninstall drivers and remove related sysfs nodes + switch-pddf : switch to pddf mode, installing pddf drivers and generating sysfs nodes + switch-nonpddf : switch to per platform, non-pddf mode +""" + +import commands +import logging +import getopt +import os +import shutil +import subprocess +import sys + +import pddfparse + +PLATFORM_ROOT_PATH = '/usr/share/sonic/device' +SONIC_CFGGEN_PATH = '/usr/local/bin/sonic-cfggen' +HWSKU_KEY = 'DEVICE_METADATA.localhost.hwsku' +PLATFORM_KEY = 'DEVICE_METADATA.localhost.platform' + +PROJECT_NAME = 'PDDF' +version = '1.1' +verbose = False +DEBUG = False +args = [] +ALL_DEVICE = {} +FORCE = 0 +kos = [] +perm_kos = [] +devs = [] + +# Instantiate the class pddf_obj +try: + pddf_obj = pddfparse.PddfParse() +except Exception as e: + print "%s" % str(e) + sys.exit() + + + +if DEBUG == True: + print sys.argv[0] + print 'ARGV :', sys.argv[1:] + +def main(): + global DEBUG + global args + global FORCE + global kos + + if len(sys.argv)<2: + show_help() + + options, args = getopt.getopt(sys.argv[1:], 'hdf', ['help', + 'debug', + 'force', + ]) + if DEBUG == True: + print options + print args + print len(sys.argv) + + # generate the KOS list from pddf device JSON file + if 'std_perm_kos' in pddf_obj.data['PLATFORM'].keys(): + kos.extend(pddf_obj.data['PLATFORM']['std_perm_kos']) + perm_kos.extend(pddf_obj.data['PLATFORM']['std_perm_kos']) + kos.extend(pddf_obj.data['PLATFORM']['std_kos']) + kos.extend(pddf_obj.data['PLATFORM']['pddf_kos']) + + kos = ['modprobe '+i for i in kos] + + if 'custom_kos' in pddf_obj.data['PLATFORM']: + custom_kos = pddf_obj.data['PLATFORM']['custom_kos'] + kos.extend(['modprobe -f '+i for i in custom_kos]) + + for opt, arg in options: + if opt in ('-h', '--help'): + show_help() + elif opt in ('-d', '--debug'): + DEBUG = True + logging.basicConfig(level=logging.INFO) + elif opt in ('-f', '--force'): + FORCE = 1 + else: + logging.info('no option') + for arg in args: + if arg == 'install': + do_install() + elif arg == 'clean': + do_uninstall() + elif arg == 'switch-pddf': + do_switch_pddf() + elif arg == 'switch-nonpddf': + do_switch_nonpddf() + else: + show_help() + + return 0 + +def show_help(): + print __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]} + sys.exit(0) + +def my_log(txt): + if DEBUG == True: + print "[PDDF]"+txt + return + +def log_os_system(cmd, show): + logging.info('Run :'+cmd) + status, output = commands.getstatusoutput(cmd) + my_log (cmd +"with result:" + str(status)) + my_log (" output:"+output) + if status: + logging.info('Failed :'+cmd) + if show: + print('Failed :'+cmd) + return status, output + +def driver_check(): + ret, lsmod = log_os_system("lsmod| grep pddf", 0) + if ret: + return False + logging.info('mods:'+lsmod) + if len(lsmod) ==0: + return False + return True + + +# Returns platform and HW SKU +def get_platform_and_hwsku(): + try: + proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-H', '-v', PLATFORM_KEY], + stdout=subprocess.PIPE, + shell=False, + stderr=subprocess.STDOUT) + stdout = proc.communicate()[0] + proc.wait() + platform = stdout.rstrip('\n') + + proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-d', '-v', HWSKU_KEY], + stdout=subprocess.PIPE, + shell=False, + stderr=subprocess.STDOUT) + stdout = proc.communicate()[0] + proc.wait() + hwsku = stdout.rstrip('\n') + except OSError, e: + raise OSError("Cannot detect platform") + + return (platform, hwsku) + +def get_path_to_device(): + # Get platform and hwsku + (platform, hwsku) = get_platform_and_hwsku() + + # Load platform module from source + platform_path = "/".join([PLATFORM_ROOT_PATH, platform]) + + return platform_path + +def get_path_to_pddf_plugin(): + pddf_path = "/".join([PLATFORM_ROOT_PATH, "pddf/plugins"]) + return pddf_path + +def config_pddf_utils(): + device_path = get_path_to_device() + pddf_path = get_path_to_pddf_plugin() + + # ########################################################################## + SONIC_PLATFORM_BSP_WHL_PKG = "/".join([device_path, 'sonic_platform-1.0-py2-none-any.whl']) + SONIC_PLATFORM_PDDF_WHL_PKG = "/".join([device_path, 'pddf', 'sonic_platform-1.0-py2-none-any.whl']) + SONIC_PLATFORM_BSP_WHL_PKG_BK = "/".join([device_path, 'sonic_platform-1.0-py2-none-any.whl.orig']) + status, output = log_os_system("pip show sonic-platform > /dev/null 2>&1", 1) + if status: + if os.path.exists(SONIC_PLATFORM_PDDF_WHL_PKG): + # Platform API 2.0 is supported + if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG): + # bsp whl pkg is present but not installed on host + if not os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_BK): + log_os_system('mv '+SONIC_PLATFORM_BSP_WHL_PKG+' '+SONIC_PLATFORM_BSP_WHL_PKG_BK, 1) + # PDDF whl package exist ... this must be the whl package created from + # PDDF 2.0 ref API classes and some changes on top of it ... install it + shutil.copy(SONIC_PLATFORM_PDDF_WHL_PKG, SONIC_PLATFORM_BSP_WHL_PKG) + print "Attemting to install the PDDF sonic_platform wheel package ..." + status, output = log_os_system("pip install "+ SONIC_PLATFORM_BSP_WHL_PKG, 1) + if status: + print "Error: Failed to install {}".format(SONIC_PLATFORM_BSP_WHL_PKG) + return status + else: + print "Successfully installed {} package".format(SONIC_PLATFORM_BSP_WHL_PKG) + else: + # PDDF with platform APIs 1.5 must be supported + device_plugin_path = "/".join([device_path, "plugins"]) + backup_path = "/".join([device_plugin_path, "orig"]) + print "Loading PDDF generic plugins (1.0)" + if os.path.exists(backup_path) is False: + os.mkdir(backup_path) + log_os_system("mv "+device_plugin_path+"/*.*"+" "+backup_path, 0) + + for item in os.listdir(pddf_path): + shutil.copy(pddf_path+"/"+item, device_plugin_path+"/"+item) + + shutil.copy('/usr/local/bin/pddfparse.py', device_plugin_path+"/pddfparse.py") + + else: + # sonic_platform whl pkg is installed 2 possibilities, 1) bsp 2.0 classes + # are installed, 2) system rebooted and either pddf/bsp 2.0 classes are already installed + if os.path.exists(SONIC_PLATFORM_PDDF_WHL_PKG): + if not os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_BK): + # bsp 2.0 classes are installed. Take a backup and copy pddf 2.0 whl pkg + log_os_system('mv '+SONIC_PLATFORM_BSP_WHL_PKG+' '+SONIC_PLATFORM_BSP_WHL_PKG_BK, 1) + shutil.copy(SONIC_PLATFORM_PDDF_WHL_PKG, SONIC_PLATFORM_BSP_WHL_PKG) + # uninstall the existing bsp whl pkg + status, output = log_os_system("pip uninstall sonic-platform -y &> /dev/null", 1) + if status: + print "Error: Unable to uninstall BSP sonic-platform whl package" + return status + print "Attemting to install the PDDF sonic_platform wheel package ..." + status, output = log_os_system("pip install "+ SONIC_PLATFORM_BSP_WHL_PKG, 1) + if status: + print "Error: Failed to install {}".format(SONIC_PLATFORM_BSP_WHL_PKG) + return status + else: + print "Successfully installed {} package".format(SONIC_PLATFORM_BSP_WHL_PKG) + else: + # system rebooted in pddf mode + print "System rebooted in PDDF mode, hence keeping the PDDF 2.0 classes" + else: + # pddf whl package doesnt exist + print "Error: PDDF 2.0 classes doesnt exist. PDDF mode can not be enabled" + sys.exit(1) + + # ########################################################################## + # Take a backup of orig fancontrol + if os.path.exists(device_path+"/fancontrol"): + log_os_system("mv "+device_path+"/fancontrol"+" "+device_path+"/fancontrol.bak", 0) + + # Create a link to fancontrol of PDDF + if os.path.exists(device_path+"/pddf/fancontrol") and not os.path.exists(device_path+"/fancontrol"): + shutil.copy(device_path+"/pddf/fancontrol",device_path+"/fancontrol") + + # BMC support + f_sensors="/usr/bin/sensors" + f_sensors_org="/usr/bin/sensors.org" + f_pddf_sensors="/usr/local/bin/pddf_sensors" + if os.path.exists(f_pddf_sensors) is True: + if os.path.exists(f_sensors_org) is False: + shutil.copy(f_sensors, f_sensors_org) + shutil.copy(f_pddf_sensors, f_sensors) + + + return 0 + +def cleanup_pddf_utils(): + device_path = get_path_to_device() + SONIC_PLATFORM_BSP_WHL_PKG = "/".join([device_path, 'sonic_platform-1.0-py2-none-any.whl']) + SONIC_PLATFORM_PDDF_WHL_PKG = "/".join([device_path, 'pddf', 'sonic_platform-1.0-py2-none-any.whl']) + SONIC_PLATFORM_BSP_WHL_PKG_BK = "/".join([device_path, 'sonic_platform-1.0-py2-none-any.whl.orig']) + # ########################################################################## + status, output = log_os_system("pip show sonic-platform > /dev/null 2>&1", 1) + if status: + # PDDF Platform API 2.0 is not supported but system is in PDDF mode, hence PDDF 1.0 plugins are present + device_plugin_path = "/".join([device_path, "plugins"]) + backup_path = "/".join([device_plugin_path, "orig"]) + if os.path.exists(backup_path) is True: + for item in os.listdir(device_plugin_path): + if os.path.isdir(device_plugin_path+"/"+item) is False: + os.remove(device_plugin_path+"/"+item) + + log_os_system("mv "+backup_path+"/*"+" "+device_plugin_path, 1) + os.rmdir(backup_path) + else: + print "\nERR: Unable to locate original device files...\n" + + else: + # PDDF 2.0 apis are supported and PDDF whl package is installed + if os.path.exists(SONIC_PLATFORM_PDDF_WHL_PKG): + if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_BK): + # platform is 2.0 compliant and original bsp 2.0 whl package exist + log_os_system('mv '+SONIC_PLATFORM_BSP_WHL_PKG_BK+' '+SONIC_PLATFORM_BSP_WHL_PKG, 1) + status, output = log_os_system("pip uninstall sonic-platform -y &> /dev/null", 1) + if status: + print "Error: Unable to uninstall PDDF sonic-platform whl package" + return status + print "Attemting to install the BSP sonic_platform wheel package ..." + status, output = log_os_system("pip install "+ SONIC_PLATFORM_BSP_WHL_PKG, 1) + if status: + print "Error: Failed to install {}".format(SONIC_PLATFORM_BSP_WHL_PKG) + return status + else: + print "Successfully installed {} package".format(SONIC_PLATFORM_BSP_WHL_PKG) + else: + # platform doesnt support 2.0 APIs but PDDF is 2.0 based + # remove and uninstall the PDDF whl package + if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG): + os.remove(SONIC_PLATFORM_BSP_WHL_PKG) + status, output = log_os_system("pip uninstall sonic-platform -y &> /dev/null", 1) + if status: + print "Error: Unable to uninstall PDDF sonic-platform whl package" + return status + else: + # something seriously wrong. System is in PDDF mode but pddf whl pkg is not present + print "Error: Fatal error as the system is in PDDF mode but the pddf .whl original is not present" + # ################################################################################################################ + + if os.path.exists(device_path+"/fancontrol"): + os.remove(device_path+"/fancontrol") + + if os.path.exists(device_path+"/fancontrol.bak"): + log_os_system("mv "+device_path+"/fancontrol.bak"+" "+device_path+"/fancontrol", 0) + + # BMC support + f_sensors="/usr/bin/sensors" + f_sensors_org="/usr/bin/sensors.org" + if os.path.exists(f_sensors_org) is True: + shutil.copy(f_sensors_org, f_sensors) + + return 0 + +def create_pddf_log_files(): + if not os.path.exists('/var/log/pddf'): + log_os_system("sudo mkdir /var/log/pddf", 1) + + log_os_system("sudo touch /var/log/pddf/led.txt", 1) + log_os_system("sudo touch /var/log/pddf/psu.txt", 1) + log_os_system("sudo touch /var/log/pddf/fan.txt", 1) + log_os_system("sudo touch /var/log/pddf/xcvr.txt", 1) + log_os_system("sudo touch /var/log/pddf/sysstatus.txt", 1) + log_os_system("sudo touch /var/log/pddf/cpld.txt", 1) + log_os_system("sudo touch /var/log/pddf/cpldmux.txt", 1) + log_os_system("sudo touch /var/log/pddf/client.txt", 1) + log_os_system("sudo touch /var/log/pddf/mux.txt", 1) + +def driver_install(): + global FORCE + + # check for pre_driver_install script + if os.path.exists('/usr/local/bin/pddf_pre_driver_install.sh'): + status, output = log_os_system('/usr/local/bin/pddf_pre_driver_install.sh', 1) + if status: + print "Error: pddf_pre_driver_install script failed with error %d"%status + return status + + log_os_system("depmod", 1) + for i in range(0,len(kos)): + status, output = log_os_system(kos[i], 1) + if status: + print "driver_install() failed with error %d"%status + if FORCE == 0: + return status + + output = config_pddf_utils() + if output: + print "config_pddf_utils() failed with error %d"%output + # check for post_driver_install script + if os.path.exists('/usr/local/bin/pddf_post_driver_install.sh'): + status, output = log_os_system('/usr/local/bin/pddf_post_driver_install.sh', 1) + if status: + print "Error: pddf_post_driver_install script failed with error %d"%status + return status + + + return 0 + +def driver_uninstall(): + global FORCE + + status = cleanup_pddf_utils() + if status: + print "cleanup_pddf_utils() failed with error %d"%status + + for i in range(0,len(kos)): + # if it is in perm_kos, do not remove + if (kos[-(i+1)].split())[-1] in perm_kos or 'i2c-i801' in kos[-(i+1)]: + continue + + rm = kos[-(i+1)].replace("modprobe", "modprobe -rq") + rm = rm.replace("insmod", "rmmod") + status, output = log_os_system(rm, 1) + if status: + print "driver_uninstall() failed with error %d"%status + if FORCE == 0: + return status + return 0 + +def device_install(): + global FORCE + + # check for pre_device_creation script + if os.path.exists('/usr/local/bin/pddf_pre_device_create.sh'): + status, output = log_os_system('/usr/local/bin/pddf_pre_device_create.sh', 1) + if status: + print "Error: pddf_pre_device_create script failed with error %d"%status + return status + + # trigger the pddf_obj script for FAN, PSU, CPLD, MUX, etc + status = pddf_obj.create_pddf_devices() + if status: + print "Error: create_pddf_devices() failed with error %d"%status + if FORCE == 0: + return status + + # check for post_device_create script + if os.path.exists('/usr/local/bin/pddf_post_device_create.sh'): + status, output = log_os_system('/usr/local/bin/pddf_post_device_create.sh', 1) + if status: + print "Error: pddf_post_device_create script failed with error %d"%status + return status + + return + +def device_uninstall(): + global FORCE + # Trigger the paloparse script for deletion of FAN, PSU, OPTICS, CPLD clients + status = pddf_obj.delete_pddf_devices() + if status: + print "Error: delete_pddf_devices() failed with error %d"%status + if FORCE == 0: + return status + return + +def do_install(): + print "Checking system...." + if not os.path.exists('/usr/share/sonic/platform/pddf_support'): + print PROJECT_NAME.upper() +" mode is not enabled" + return + + if driver_check()== False : + print PROJECT_NAME.upper() +" has no PDDF driver installed...." + create_pddf_log_files() + print "Installing ..." + status = driver_install() + if status: + return status + else: + print PROJECT_NAME.upper() +" drivers detected...." + + print "Creating devices ..." + status = device_install() + if status: + return status + + return + +def do_uninstall(): + print "Checking system...." + if not os.path.exists('/usr/share/sonic/platform/pddf_support'): + print PROJECT_NAME.upper() +" mode is not enabled" + return + + + if os.path.exists('/var/log/pddf'): + print "Remove pddf log files....." + log_os_system("sudo rm -rf /var/log/pddf", 1) + + print "Remove all the devices..." + status = device_uninstall() + if status: + return status + + + if driver_check()== False : + print PROJECT_NAME.upper() +" has no PDDF driver installed...." + else: + print "Removing installed driver...." + status = driver_uninstall() + if status: + if FORCE == 0: + return status + return + +def do_switch_pddf(): + try: + import pddf_switch_svc + except ImportError: + print "Unable to find pddf_switch_svc.py. PDDF might not be supported on this platform" + sys.exit() + print "Check the pddf support..." + status = pddf_switch_svc.check_pddf_support() + if not status: + print "PDDF is not supported on this platform" + return status + + + print "Checking system...." + if os.path.exists('/usr/share/sonic/platform/pddf_support'): + print PROJECT_NAME.upper() +" system is already in pddf mode...." + else: + print "Check if the native sonic-platform whl package is installed in the pmon docker" + status, output = log_os_system("docker exec -it pmon pip show sonic-platform", 1) + if not status: + # Need to remove this whl module + status, output = log_os_system("docker exec -it pmon pip uninstall sonic-platform -y", 1) + if not status: + print "Successfully uninstalled the native sonic-platform whl pkg from pmon container" + else: + print "Error: Unable to uninstall the sonic-platform whl pkg from pmon container.\ + Do it manually before moving to nonpddf mode" + return status + print "Stopping the pmon service ..." + status, output = log_os_system("systemctl stop pmon.service", 1) + if status: + print "Pmon stop failed" + if FORCE==0: + return status + + print "Stopping the platform services.." + status = pddf_switch_svc.stop_platform_svc() + if not status: + if FORCE==0: + return status + + print "Creating the pddf_support file..." + if os.path.exists('/usr/share/sonic/platform'): + log_os_system("touch /usr/share/sonic/platform/pddf_support", 1) + else: + print "/usr/share/sonic/platform path doesn't exist. Unable to set pddf mode" + return -1 + + print "Starting the PDDF platform service..." + status = pddf_switch_svc.start_platform_pddf() + if not status: + if FORCE==0: + return status + + print "Restart the pmon service ..." + status, output = log_os_system("systemctl start pmon.service", 1) + if status: + print "Pmon restart failed" + if FORCE==0: + return status + + return + +def do_switch_nonpddf(): + try: + import pddf_switch_svc + except ImportError: + print "Unable to find pddf_switch_svc.py. PDDF might not be supported on this platform" + sys.exit() + print "Checking system...." + if not os.path.exists('/usr/share/sonic/platform/pddf_support'): + print PROJECT_NAME.upper() +" system is already in non-pddf mode...." + else: + print "Check if the sonic-platform whl package is installed in the pmon docker" + status, output = log_os_system("docker exec -it pmon pip show sonic-platform", 1) + if not status: + # Need to remove this whl module + status, output = log_os_system("docker exec -it pmon pip uninstall sonic-platform -y", 1) + if not status: + print "Successfully uninstalled the sonic-platform whl pkg from pmon container" + else: + print "Error: Unable to uninstall the sonic-platform whl pkg from pmon container.\ + Do it manually before moving to nonpddf mode" + return status + print "Stopping the pmon service ..." + status, output = log_os_system("systemctl stop pmon.service", 1) + if status: + print "Stopping pmon service failed" + if FORCE==0: + return status + + print "Stopping the PDDF platform service..." + status = pddf_switch_svc.stop_platform_pddf() + if not status: + if FORCE==0: + return status + + print "Removing the pddf_support file..." + if os.path.exists('/usr/share/sonic/platform'): + log_os_system("rm -f /usr/share/sonic/platform/pddf_support", 1) + else: + print "/usr/share/sonic/platform path doesnt exist. Unable to set non-pddf mode" + return -1 + + print "Starting the platform services..." + status = pddf_switch_svc.start_platform_svc() + if not status: + if FORCE==0: + return status + + print "Restart the pmon service ..." + status, output = log_os_system("systemctl start pmon.service", 1) + if status: + print "Restarting pmon service failed" + if FORCE==0: + return status + + return + +if __name__ == "__main__": + main() diff --git a/platform/pddf/i2c/utils/pddfparse.py b/platform/pddf/i2c/utils/pddfparse.py new file mode 100755 index 0000000000..f9ce8fca0b --- /dev/null +++ b/platform/pddf/i2c/utils/pddfparse.py @@ -0,0 +1,1949 @@ +#!/usr/bin/env python +import argparse +import glob +import json +from jsonschema import validate +import os +import re +import subprocess +import sys +import time +import unicodedata + +bmc_cache={} +cache={} +SONIC_CFGGEN_PATH = '/usr/local/bin/sonic-cfggen' +HWSKU_KEY = 'DEVICE_METADATA.localhost.hwsku' +PLATFORM_KEY = 'DEVICE_METADATA.localhost.platform' + +dirname=os.path.dirname(os.path.realpath(__file__)) + +color_map = { + "STATUS_LED_COLOR_GREEN" : "green", + "STATUS_LED_COLOR_RED" : "red", + "STATUS_LED_COLOR_AMBER" : "amber", + "STATUS_LED_COLOR_BLUE" : "blue", + "STATUS_LED_COLOR_GREEN_BLINK" : "blinking green", + "STATUS_LED_COLOR_RED_BLINK" : "blinking red", + "STATUS_LED_COLOR_AMBER_BLINK" : "blinking amber", + "STATUS_LED_COLOR_BLUE_BLINK" : "blinking blue", + "STATUS_LED_COLOR_OFF" : "off" +} + + + + +class PddfParse(): + def __init__(self): + if not os.path.exists("/usr/share/sonic/platform"): + platform, hwsku = self.get_platform_and_hwsku() + os.symlink("/usr/share/sonic/device/"+platform, "/usr/share/sonic/platform") + + try: + with open('/usr/share/sonic/platform/pddf/pddf-device.json') as f: + self.data = json.load(f) + except IOError: + if os.path.exists('/usr/share/sonic/platform'): + os.unlink("/usr/share/sonic/platform") + raise Exception('PDDF JSON file not found. PDDF is not supported on this platform') + + + self.data_sysfs_obj={} + self.sysfs_obj={} + + + # Returns platform and HW SKU + def get_platform_and_hwsku(self): + try: + proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-H', '-v', PLATFORM_KEY], + stdout=subprocess.PIPE, + shell=False, + stderr=subprocess.STDOUT) + stdout = proc.communicate()[0] + proc.wait() + platform = stdout.rstrip('\n') + + proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-d', '-v', HWSKU_KEY], + stdout=subprocess.PIPE, + shell=False, + stderr=subprocess.STDOUT) + stdout = proc.communicate()[0] + proc.wait() + hwsku = stdout.rstrip('\n') + except OSError, e: + raise OSError("Cannot detect platform") + + return (platform, hwsku) + + ################################################################################################################### + # GENERIC DEFS + ################################################################################################################### + def runcmd(self, cmd): + rc = os.system(cmd) + if rc!=0: + print "%s -- command failed"%cmd + return rc + + def get_dev_idx(self, dev, ops): + parent=dev['dev_info']['virt_parent'] + pdev=self.data[parent] + + return pdev['dev_attr']['dev_idx'] + + + def get_path(self, target, attr): + aa = target + attr + + if aa in cache: + return cache[aa] + + string = None + p = re.search(r'\d+$', target) + if p is None: + for bb in filter(re.compile(target).search,self.data.keys()): + path = self.dev_parse(self.data[bb], { "cmd": "show_attr", "target":bb, "attr":attr }) + if path != "": + string = path + else: + if target in self.data.keys(): + path = self.dev_parse(self.data[target], { "cmd": "show_attr", "target":target, "attr":attr }) + if path != "": + string = path + + + if string is not None: + string = string.rstrip() + + cache[aa]=string + return string + + + def get_device_type(self, key): + if not key in self.data.keys(): + return None + return self.data[key]['dev_info']['device_type'] + + def get_platform(self): + return self.data['PLATFORM'] + + def get_num_psu_fans(self, dev): + if not dev in self.data.keys(): + return 0 + + if not 'num_psu_fans' in self.data[dev]['dev_attr']: + return 0 + + return self.data[dev]['dev_attr']['num_psu_fans'] + + def get_led_path(self): + return ("pddf/devices/led") + + def get_led_cur_state_path(self): + return ("pddf/devices/led/cur_state") + + def get_led_color(self): + color_f="/sys/kernel/pddf/devices/led/cur_state/color" + try: + with open(color_f, 'r') as f: + color = f.read().strip("\r\n") + except IOError: + return ("Error") + + return (color_map[color]) + + ################################################################################################################### + # CREATE DEFS + ################################################################################################################### + def create_device(self, attr, path, ops): + ret = 0 + for key in attr.keys(): + if type(attr[key]) is list: + val = " ".join(attr[key]) + else: + val = attr[key] + + cmd="echo '%s' > /sys/kernel/%s/%s"%(val, path, key) + ret=self.runcmd(cmd) + if ret!=0: + return ret + return ret + + + def create_psu_i2c_device(self, dev, ops): + create_ret = 0 + if dev['i2c']['topo_info']['dev_type'] in self.data['PLATFORM']['pddf_dev_types']['PSU']: + create_ret = self.create_device(dev['i2c']['topo_info'], "pddf/devices/psu/i2c", ops) + if create_ret!=0: + return create_ret + cmd= "echo '%s' > /sys/kernel/pddf/devices/psu/i2c/i2c_name"%(dev['dev_info']['device_name']) + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + cmd= "echo '%s' > /sys/kernel/pddf/devices/psu/i2c/psu_idx"%( self.get_dev_idx(dev, ops)) + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + for attr in dev['i2c']['attr_list']: + create_ret = self.create_device(attr, "pddf/devices/psu/i2c", ops) + if create_ret!=0: + return create_ret + cmd= "echo 'add' > /sys/kernel/pddf/devices/psu/i2c/attr_ops" + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + + cmd = "echo 'add' > /sys/kernel/pddf/devices/psu/i2c/dev_ops" + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + else: + cmd = "echo %s 0x%x > /sys/bus/i2c/devices/i2c-%d/new_device" % (dev['i2c']['topo_info']['dev_type'], + int(dev['i2c']['topo_info']['dev_addr'], 0), int(dev['i2c']['topo_info']['parent_bus'], 0)) + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + + + return create_ret + + + + def create_psu_bmc_device(self, dev, ops): + print "" + + + def create_psu_device(self, dev, ops): + return self.create_psu_i2c_device(dev, ops ) + + def create_fan_device(self, dev, ops): + create_ret = 0 + if dev['i2c']['topo_info']['dev_type'] in self.data['PLATFORM']['pddf_dev_types']['FAN']: + create_ret = self.create_device(dev['i2c']['topo_info'], "pddf/devices/fan/i2c", ops) + if create_ret!=0: + return create_ret + cmd= "echo '%s' > /sys/kernel/pddf/devices/fan/i2c/i2c_name"%(dev['dev_info']['device_name']) + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + create_ret = self.create_device(dev['i2c']['dev_attr'], "pddf/devices/fan/i2c", ops) + if create_ret!=0: + return create_ret + for attr in dev['i2c']['attr_list']: + create_ret = self.create_device(attr, "pddf/devices/fan/i2c", ops) + if create_ret!=0: + return create_ret + cmd= "echo 'add' > /sys/kernel/pddf/devices/fan/i2c/attr_ops" + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + + cmd= "echo 'add' > /sys/kernel/pddf/devices/fan/i2c/dev_ops" + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + else: + cmd= "echo %s 0x%x > /sys/bus/i2c/devices/i2c-%d/new_device" % (dev['i2c']['topo_info']['dev_type'], + int(dev['i2c']['topo_info']['dev_addr'], 0), int(dev['i2c']['topo_info']['parent_bus'], 0)) + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + + return create_ret + + def create_temp_sensor_device(self, dev, ops): + create_ret = 0 + # NO PDDF driver for temp_sensors device + cmd= "echo %s 0x%x > /sys/bus/i2c/devices/i2c-%d/new_device" % (dev['i2c']['topo_info']['dev_type'], + int(dev['i2c']['topo_info']['dev_addr'], 0), int(dev['i2c']['topo_info']['parent_bus'], 0)) + create_ret = self.runcmd(cmd) + return create_ret + + + + + def create_cpld_device(self, dev, ops): + create_ret = 0 + if dev['i2c']['topo_info']['dev_type'] in self.data['PLATFORM']['pddf_dev_types']['CPLD']: + create_ret = self.create_device(dev['i2c']['topo_info'], "pddf/devices/cpld", ops) + if create_ret!=0: + return create_ret + + cmd= "echo '%s' > /sys/kernel/pddf/devices/cpld/i2c_name"%(dev['dev_info']['device_name']) + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + # TODO: If attributes are provided then, use 'self.create_device' for them too + cmd= "echo 'add' > /sys/kernel/pddf/devices/cpld/dev_ops" + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + else: + cmd= "echo %s 0x%x > /sys/bus/i2c/devices/i2c-%d/new_device" % (dev['i2c']['topo_info']['dev_type'], + int(dev['i2c']['topo_info']['dev_addr'], 0), int(dev['i2c']['topo_info']['parent_bus'], 0)) + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + + return create_ret + + def create_cpldmux_device(self, dev, ops): + create_ret = 0 + create_ret = self.create_device(dev['i2c']['topo_info'], "pddf/devices/cpldmux", ops) + if create_ret!=0: + return create_ret + cmd= "echo '%s' > /sys/kernel/pddf/devices/mux/i2c_name"%(dev['dev_info']['device_name']) + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + self.create_device(dev['i2c']['dev_attr'], "pddf/devices/cpldmux", ops) + # Parse channel info + for chan in dev['i2c']['channel']: + self.create_device(chan, "pddf/devices/cpldmux", ops) + cmd="echo 'add' > /sys/kernel/pddf/devices/cpldmux/chan_ops" + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + + cmd= "echo 'add' > /sys/kernel/pddf/devices/cpldmux/dev_ops" + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + + def create_gpio_device(self, dev, ops): + create_ret = 0 + create_ret = self.create_device(dev['i2c']['topo_info'], "pddf/devices/gpio", ops) + if create_ret!=0: + return create_ret + cmd= "echo '%s' > /sys/kernel/pddf/devices/gpio/i2c_name"%(dev['dev_info']['device_name']) + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + create_ret = self.create_device(dev['i2c']['dev_attr'], "pddf/devices/gpio", ops) + if create_ret!=0: + return create_ret + cmd= "echo 'add' > /sys/kernel/pddf/devices/gpio/dev_ops" + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + + time.sleep(2) + base = dev['i2c']['dev_attr']['gpio_base'] + for inst in dev['i2c']['ports']: + if inst['port_num']!="": + port_no = int(base, 16) + int(inst['port_num']) + cmd= "echo %d > /sys/class/gpio/export"%port_no + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + if inst['direction']!="": + cmd= "echo %s >/sys/class/gpio/gpio%d/direction"%(inst['direction'], port_no) + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + if inst['value']!="": + for i in inst['value'].split(','): + cmd= "echo %s >/sys/class/gpio/gpio%d/value"%(i.rstrip(), port_no) + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + + return create_ret + + def create_mux_device(self, dev, ops): + create_ret = 0 + create_ret = self.create_device(dev['i2c']['topo_info'], "pddf/devices/mux", ops) + if create_ret!=0: + return create_ret + cmd= "echo '%s' > /sys/kernel/pddf/devices/mux/i2c_name"%(dev['dev_info']['device_name']) + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + self.create_device(dev['i2c']['dev_attr'], "pddf/devices/mux", ops) + cmd= "echo 'add' > /sys/kernel/pddf/devices/mux/dev_ops" + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + + + def create_xcvr_i2c_device(self, dev, ops): + create_ret = 0 + if dev['i2c']['topo_info']['dev_type'] in self.data['PLATFORM']['pddf_dev_types']['PORT_MODULE']: + self.create_device(dev['i2c']['topo_info'], "pddf/devices/xcvr/i2c", ops) + cmd= "echo '%s' > /sys/kernel/pddf/devices/xcvr/i2c/i2c_name"%(dev['dev_info']['device_name']) + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + cmd="echo '%s' > /sys/kernel/pddf/devices/xcvr/i2c/dev_idx"%( self.get_dev_idx(dev, ops)) + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + for attr in dev['i2c']['attr_list']: + self.create_device(attr, "pddf/devices/xcvr/i2c", ops) + cmd="echo 'add' > /sys/kernel/pddf/devices/xcvr/i2c/attr_ops" + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + + cmd="echo 'add' > /sys/kernel/pddf/devices/xcvr/i2c/dev_ops" + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + else: + cmd="echo %s 0x%x > /sys/bus/i2c/devices/i2c-%d/new_device" % (dev['i2c']['topo_info']['dev_type'], + int(dev['i2c']['topo_info']['dev_addr'], 0), int(dev['i2c']['topo_info']['parent_bus'], 0)) + create_ret = self.runcmd(cmd) + #print "\n" + if create_ret!=0: + return create_ret + # Add port name + port_name_sysfs = '/sys/bus/i2c/devices/{}-00{:02x}/port_name'.format( + int(dev['i2c']['topo_info']['parent_bus'], 0),int(dev['i2c']['topo_info']['dev_addr'], 0)) + + if os.path.exists(port_name_sysfs): + cmd="echo {} > /sys/bus/i2c/devices/{}-00{:02x}/port_name".format( + dev['dev_info']['virt_parent'].lower(), int(dev['i2c']['topo_info']['parent_bus'], 0), + int(dev['i2c']['topo_info']['dev_addr'], 0)) + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + + return create_ret + + def create_xcvr_bmc_device(self, dev, ops): + print "" + + def create_xcvr_device(self, dev, ops): + return self.create_xcvr_i2c_device(dev, ops ) + + def create_sysstatus_device(self, dev, ops): + create_ret = 0 + for attr in dev['attr_list']: + self.create_device(attr, "pddf/devices/sysstatus", ops) + cmd= "echo 'add' > /sys/kernel/pddf/devices/sysstatus/attr_ops" + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + + def create_eeprom_device(self, dev, ops): + create_ret = 0 + if "EEPROM" in self.data['PLATFORM']['pddf_dev_types'] and \ + dev['i2c']['topo_info']['dev_type'] in self.data['PLATFORM']['pddf_dev_types']['EEPROM']: + self.create_device(dev['i2c']['topo_info'], "pddf/devices/eeprom/i2c", ops) + cmd= "echo '%s' > /sys/kernel/pddf/devices/eeprom/i2c/i2c_name"%(dev['dev_info']['device_name']) + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + self.create_device(dev['i2c']['dev_attr'], "pddf/devices/eeprom/i2c", ops) + cmd = "echo 'add' > /sys/kernel/pddf/devices/eeprom/i2c/dev_ops" + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + + else: + cmd= "echo %s 0x%x > /sys/bus/i2c/devices/i2c-%d/new_device" % (dev['i2c']['topo_info']['dev_type'], + int(dev['i2c']['topo_info']['dev_addr'], 0), int(dev['i2c']['topo_info']['parent_bus'], 0)) + create_ret = self.runcmd(cmd) + if create_ret!=0: + return create_ret + + return create_ret + + ################################################################################################################### + # DELETE DEFS + ################################################################################################################### + def delete_eeprom_device(self, dev, ops): + if "EEPROM" in self.data['PLATFORM']['pddf_dev_types'] and \ + dev['i2c']['topo_info']['dev_type'] in self.data['PLATFORM']['pddf_dev_types']['EEPROM']: + cmd= "echo '%s' > /sys/kernel/pddf/devices/eeprom/i2c/i2c_name"%(dev['dev_info']['device_name']) + self.runcmd(cmd) + cmd = "echo 'delete' > /sys/kernel/pddf/devices/eeprom/i2c/dev_ops" + self.runcmd(cmd) + else: + cmd= "echo 0x%x > /sys/bus/i2c/devices/i2c-%d/delete_device" % (int(dev['i2c']['topo_info']['dev_addr'], 0), + int(dev['i2c']['topo_info']['parent_bus'], 0)) + self.runcmd(cmd) + + def delete_sysstatus_device(self, dev, ops): + # NOT A PHYSICAL DEVICE.... rmmod on module would remove all the artifacts + pass + + + def delete_xcvr_i2c_device(self, dev, ops): + if dev['i2c']['topo_info']['dev_type'] in self.data['PLATFORM']['pddf_dev_types']['PORT_MODULE']: + cmd= "echo '%s' > /sys/kernel/pddf/devices/xcvr/i2c/i2c_name"%(dev['dev_info']['device_name']) + self.runcmd(cmd) + cmd="echo 'delete' > /sys/kernel/pddf/devices/xcvr/i2c/dev_ops" + self.runcmd(cmd) + else: + cmd="echo 0x%x > /sys/bus/i2c/devices/i2c-%d/delete_device" % (int(dev['i2c']['topo_info']['dev_addr'], 0), + int(dev['i2c']['topo_info']['parent_bus'], 0)) + self.runcmd(cmd) + + def delete_xcvr_device(self, dev, ops): + self.delete_xcvr_i2c_device(dev, ops) + return + + def delete_gpio_device(self, dev, ops): + cmd= "echo '%s' > /sys/kernel/pddf/devices/gpio/i2c_name"%(dev['dev_info']['device_name']) + self.runcmd(cmd) + cmd= "echo 'delete' > /sys/kernel/pddf/devices/gpio/dev_ops" + self.runcmd(cmd) + + def delete_mux_device(self, dev, ops): + cmd= "echo '%s' > /sys/kernel/pddf/devices/mux/i2c_name"%(dev['dev_info']['device_name']) + self.runcmd(cmd) + cmd= "echo 'delete' > /sys/kernel/pddf/devices/mux/dev_ops" + self.runcmd(cmd) + + def delete_cpld_device(self, dev, ops): + if dev['i2c']['topo_info']['dev_type'] in self.data['PLATFORM']['pddf_dev_types']['CPLD']: + cmd= "echo '%s' > /sys/kernel/pddf/devices/cpld/i2c_name"%(dev['dev_info']['device_name']) + self.runcmd(cmd) + cmd= "echo 'delete' > /sys/kernel/pddf/devices/cpld/dev_ops" + self.runcmd(cmd) + else: + cmd= "echo 0x%x > /sys/bus/i2c/devices/i2c-%d/delete_device" % (int(dev['i2c']['topo_info']['dev_addr'], 0), + int(dev['i2c']['topo_info']['parent_bus'], 0)) + self.runcmd(cmd) + + def delete_cpldmux_device(self, dev, ops): + if dev['i2c']['topo_info']['dev_type'] in self.data['PLATFORM']['pddf_dev_types']['CPLDMUX']: + cmd= "echo '%s' > /sys/kernel/pddf/devices/cpldmux/i2c_name"%(dev['dev_info']['device_name']) + self.runcmd(cmd) + cmd= "echo 'delete' > /sys/kernel/pddf/devices/cpldmux/dev_ops" + self.runcmd(cmd) + + def delete_temp_sensor_device(self, dev, ops): + # NO PDDF driver for temp_sensors device + cmd= "echo 0x%x > /sys/bus/i2c/devices/i2c-%d/delete_device" % (int(dev['i2c']['topo_info']['dev_addr'], 0), + int(dev['i2c']['topo_info']['parent_bus'], 0)) + self.runcmd(cmd) + + def delete_fan_device(self, dev, ops): + if dev['i2c']['topo_info']['dev_type'] in self.data['PLATFORM']['pddf_dev_types']['FAN']: + cmd= "echo '%s' > /sys/kernel/pddf/devices/fan/i2c/i2c_name"%(dev['dev_info']['device_name']) + self.runcmd(cmd) + cmd= "echo 'delete' > /sys/kernel/pddf/devices/fan/i2c/dev_ops" + self.runcmd(cmd) + else: + cmd= "echo 0x%x > /sys/bus/i2c/devices/i2c-%d/delete_device" % (int(dev['i2c']['topo_info']['dev_addr'], 0), + int(dev['i2c']['topo_info']['parent_bus'], 0)) + self.runcmd(cmd) + + + def delete_psu_i2c_device(self, dev, ops): + if dev['i2c']['topo_info']['dev_type'] in self.data['PLATFORM']['pddf_dev_types']['PSU']: + cmd= "echo '%s' > /sys/kernel/pddf/devices/psu/i2c/i2c_name"%(dev['dev_info']['device_name']) + self.runcmd(cmd) + cmd = "echo 'delete' > /sys/kernel/pddf/devices/psu/i2c/dev_ops" + self.runcmd(cmd) + else: + cmd = "echo 0x%x > /sys/bus/i2c/devices/i2c-%d/delete_device" %(int(dev['i2c']['topo_info']['dev_addr'], 0), + int(dev['i2c']['topo_info']['parent_bus'], 0)) + self.runcmd(cmd) + + def delete_psu_device(self, dev, ops): + self.delete_psu_i2c_device(dev, ops ) + return + + + ################################################################################################################### + # SHOW ATTRIBIUTES DEFS + ################################################################################################################### + def is_led_device_configured(self, device_name, attr_name): + if device_name in self.data.keys(): + attr_list=self.data[device_name]['i2c']['attr_list'] + for attr in attr_list: + if attr['attr_name'].strip() == attr_name.strip(): + return (True) + return (False) + + + def show_device_sysfs(self, dev, ops): + parent=dev['dev_info']['device_parent'] + pdev=self.data[parent] + if pdev['dev_info']['device_parent'] == 'SYSTEM': + return "/sys/bus/i2c/devices/"+"i2c-%d"%int(pdev['i2c']['topo_info']['dev_addr'], 0) + return self.show_device_sysfs(pdev, ops) + "/" + "i2c-%d" % int(dev['i2c']['topo_info']['parent_bus'], 0) + + + # This is alid for 'at24' type of EEPROM devices. Only one attribtue 'eeprom' + def show_attr_eeprom_device(self, dev, ops): + str = "" + attr_name=ops['attr'] + attr_list=dev['i2c']['attr_list'] + KEY="eeprom" + dsysfs_path="" + + if not KEY in self.data_sysfs_obj: + self.data_sysfs_obj[KEY]=[] + + for attr in attr_list: + if attr_name == attr['attr_name'] or attr_name == 'all': + if 'drv_attr_name' in attr.keys(): + real_name = attr['drv_attr_name'] + else: + real_name = attr['attr_name'] + + dsysfs_path = self.show_device_sysfs(dev, ops)+"/%d-00%x"%(int(dev['i2c']['topo_info']['parent_bus'],0), + int(dev['i2c']['topo_info']['dev_addr'], 0))+"/%s"%real_name + if not dsysfs_path in self.data_sysfs_obj[KEY]: + self.data_sysfs_obj[KEY].append(dsysfs_path) + str += dsysfs_path+"\n" + return str + + def show_attr_gpio_device(self, dev, ops): + ret = "" + KEY="gpio" + if not KEY in self.data_sysfs_obj: + self.data_sysfs_obj[KEY]=[] + + return ret + + + def show_attr_mux_device(self, dev, ops): + ret = "" + KEY="mux" + if not KEY in self.data_sysfs_obj: + self.data_sysfs_obj[KEY]=[] + + return ret + + def show_attr_psu_i2c_device(self, dev, ops): + target=ops['target'] + attr_name=ops['attr'] + ret = "" + KEY="psu" + dsysfs_path="" + + if not KEY in self.data_sysfs_obj: + self.data_sysfs_obj[KEY]=[] + + if target == 'all' or target == dev['dev_info']['virt_parent'] : + attr_list=dev['i2c']['attr_list'] + for attr in attr_list: + if attr_name == attr['attr_name'] or attr_name == 'all' : + if 'attr_devtype' in attr.keys() and attr['attr_devtype'] == "gpio": + # Check and enable the gpio from class + gpio_dev = self.data[attr['attr_devname']] + base = int(gpio_dev['i2c']['dev_attr']['gpio_base'], 16) + port_num = base + int(attr['attr_offset'], 16) + gpio_name = 'gpio'+str(port_num) + attr_path = '/sys/class/gpio/'+gpio_name+'/value' + if (os.path.exists(attr_path)): + if not attr_path in self.data_sysfs_obj[KEY]: + self.data_sysfs_obj[KEY].append(attr_path) + ret += attr_path + '\n' + else: + if 'drv_attr_name' in attr.keys(): + real_name = attr['drv_attr_name'] + else: + real_name = attr['attr_name'] + + dsysfs_path = self.show_device_sysfs(dev, ops) + \ + "/%d-00%x"%(int(dev['i2c']['topo_info']['parent_bus'], 0), + int(dev['i2c']['topo_info']['dev_addr'], 0)) + \ + "/%s"%real_name + if not dsysfs_path in self.data_sysfs_obj[KEY]: + self.data_sysfs_obj[KEY].append(dsysfs_path) + ret += dsysfs_path+"\n" + return ret + + + def show_attr_psu_device(self, dev, ops): + return self.show_attr_psu_i2c_device(dev, ops ) + + + def show_attr_fan_device(self, dev, ops): + ret_str = "" + attr_name=ops['attr'] + attr_list=dev['i2c']['attr_list'] + KEY="fan" + dsysfs_path="" + + if not KEY in self.data_sysfs_obj: + self.data_sysfs_obj[KEY]=[] + + + for attr in attr_list: + if attr_name == attr['attr_name'] or attr_name == 'all': + if 'drv_attr_name' in attr.keys(): + real_name = attr['drv_attr_name'] + else: + real_name = attr['attr_name'] + + dsysfs_path= self.show_device_sysfs(dev, ops) + \ + "/%d-00%x" %(int(dev['i2c']['topo_info']['parent_bus'], 0), + int(dev['i2c']['topo_info']['dev_addr'], 0)) + \ + "/%s"%real_name + if not dsysfs_path in self.data_sysfs_obj[KEY]: + self.data_sysfs_obj[KEY].append(dsysfs_path) + ret_str += dsysfs_path+"\n" + return ret_str + + # This is only valid for LM75 + def show_attr_temp_sensor_device(self, dev, ops): + ret_str = "" + attr_name=ops['attr'] + attr_list=dev['i2c']['attr_list'] + KEY="temp-sensors" + dsysfs_path="" + + if not KEY in self.data_sysfs_obj: + self.data_sysfs_obj[KEY]=[] + + + for attr in attr_list: + if attr_name == attr['attr_name'] or attr_name == 'all': + path = self.show_device_sysfs(dev, ops) + \ + "/%d-00%x/" %(int(dev['i2c']['topo_info']['parent_bus'], 0), + int(dev['i2c']['topo_info']['dev_addr'], 0)) + if 'drv_attr_name' in attr.keys(): + real_name = attr['drv_attr_name'] + else: + real_name = attr['attr_name'] + + if (os.path.exists(path)): + full_path = glob.glob(path + 'hwmon/hwmon*/' + real_name)[0] + dsysfs_path=full_path + if not dsysfs_path in self.data_sysfs_obj[KEY]: + self.data_sysfs_obj[KEY].append(dsysfs_path) + ret_str += full_path + "\n" + return ret_str + + def show_attr_sysstatus_device(self, dev, ops): + ret = "" + attr_name=ops['attr'] + attr_list=dev['attr_list'] + KEY="sys-status" + dsysfs_path="" + + if not KEY in self.data_sysfs_obj: + self.data_sysfs_obj[KEY]=[] + + + for attr in attr_list: + if attr_name == attr['attr_name'] or attr_name == 'all': + dsysfs_path = "/sys/kernel/pddf/devices/sysstatus/sysstatus_data/" + attr['attr_name'] + if not dsysfs_path in self.data_sysfs_obj[KEY]: + self.data_sysfs_obj[KEY].append(dsysfs_path) + ret += dsysfs_path+"\n" + return ret + + + def show_attr_xcvr_i2c_device(self, dev, ops): + target=ops['target'] + attr_name=ops['attr'] + ret = "" + dsysfs_path = "" + KEY="xcvr" + if not KEY in self.data_sysfs_obj: + self.data_sysfs_obj[KEY]=[] + + if target == 'all' or target == dev['dev_info']['virt_parent'] : + attr_list=dev['i2c']['attr_list'] + for attr in attr_list: + if attr_name == attr['attr_name'] or attr_name == 'all' : + if 'attr_devtype' in attr.keys() and attr['attr_devtype'] == "gpio": + # Check and enable the gpio from class + gpio_dev = self.data[attr['attr_devname']] + base = int(gpio_dev['i2c']['dev_attr']['gpio_base'], 16) + port_num = base + int(attr['attr_offset'], 16) + gpio_name = 'gpio'+str(port_num) + attr_path = '/sys/class/gpio/'+gpio_name+'/value' + if (os.path.exists(attr_path)): + if not attr_path in self.data_sysfs_obj[KEY]: + self.data_sysfs_obj[KEY].append(attr_path) + ret += attr_path + '\n' + else: + if 'drv_attr_name' in attr.keys(): + real_name = attr['drv_attr_name'] + else: + real_name = attr['attr_name'] + + dsysfs_path = self.show_device_sysfs(dev, ops) + \ + "/%d-00%x" %(int(dev['i2c']['topo_info']['parent_bus'], 0), + int(dev['i2c']['topo_info']['dev_addr'], 0)) + \ + "/%s"%real_name + if not dsysfs_path in self.data_sysfs_obj[KEY]: + self.data_sysfs_obj[KEY].append(dsysfs_path) + ret += dsysfs_path+"\n" + return ret + + + def show_attr_xcvr_device(self, dev, ops): + return self.show_attr_xcvr_i2c_device(dev, ops ) + + def show_attr_cpld_device(self, dev, ops): + ret = "" + KEY="cpld" + if not KEY in self.data_sysfs_obj: + self.data_sysfs_obj[KEY]=[] + + return ret + + def show_attr_cpldmux_device(self, dev, ops): + ret = "" + KEY="cpldmux" + if not KEY in self.data_sysfs_obj: + self.data_sysfs_obj[KEY]=[] + + return ret + + + ################################################################################################################### + # SHOW DEFS + ################################################################################################################### + def check_led_cmds(self, key, ops): + name = ops['target']+'_LED' + if (ops['target']=='config' or ops['attr']=='all') or \ + (name==self.data[key]['dev_info']['device_name'] and + ops['attr']==self.data[key]['dev_attr']['index']): + return (True) + else: + return (False) + + def dump_sysfs_obj(self, obj, key_type): + if (key_type == 'keys'): + for key in obj.keys(): + print key + return + + for key in obj: + if (key == key_type or key_type == 'all'): + print key+":" + for entry in obj[key]: + print "\t"+entry + + def add_list_sysfs_obj(self, obj, KEY, list): + for sysfs in list: + if not sysfs in obj[KEY]: + obj[KEY].append(sysfs) + + def sysfs_attr(self, key, value, path, obj, obj_key): + sysfs_path="/sys/kernel/%s/%s"%(path, key) + if not sysfs_path in obj[obj_key]: + obj[obj_key].append(sysfs_path) + + + def sysfs_device(self, attr, path, obj, obj_key): + for key in attr.keys(): + sysfs_path="/sys/kernel/%s/%s"%(path, key) + if not sysfs_path in obj[obj_key]: + obj[obj_key].append(sysfs_path) + + def show_eeprom_device(self, dev, ops): + return + + + def show_mux_device(self, dev, ops): + KEY ='mux' + if not KEY in self.sysfs_obj: + self.sysfs_obj[KEY] = [] + self.sysfs_device(dev['i2c']['topo_info'], "pddf/devices/mux", self.sysfs_obj, KEY) + self.sysfs_device(dev['i2c']['dev_attr'], "pddf/devices/mux", self.sysfs_obj, KEY) + sysfs_path= "/sys/kernel/pddf/devices/mux/dev_ops" + if not sysfs_path in self.sysfs_obj[KEY]: + self.sysfs_obj[KEY].append(sysfs_path) + list=['/sys/kernel/pddf/devices/mux/i2c_type', + '/sys/kernel/pddf/devices/mux/i2c_name', + '/sys/kernel/pddf/devices/mux/error'] + self.add_list_sysfs_obj(self.sysfs_obj, KEY, list) + + def show_gpio_device(self, dev, ops): + KEY ='gpio' + if not KEY in self.sysfs_obj: + self.sysfs_obj[KEY] = [] + self.sysfs_device(dev['i2c']['topo_info'], "pddf/devices/gpio", self.sysfs_obj, KEY) + self.sysfs_device(dev['i2c']['dev_attr'], "pddf/devices/gpio", self.sysfs_obj, KEY) + sysfs_path= "/sys/kernel/pddf/devices/gpio/dev_ops" + if not sysfs_path in self.sysfs_obj[KEY]: + self.sysfs_obj[KEY].append(sysfs_path) + list=['/sys/kernel/pddf/devices/gpio/i2c_type', + '/sys/kernel/pddf/devices/gpio/i2c_name', + '/sys/kernel/pddf/devices/gpio/error'] + self.add_list_sysfs_obj(self.sysfs_obj, KEY, list) + + + def show_psu_i2c_device(self, dev, ops): + KEY ='psu' + path='pddf/devices/psu/i2c' + if dev['i2c']['topo_info']['dev_type'] in self.data['PLATFORM']['pddf_dev_types']['PSU']: + if not KEY in self.sysfs_obj: + self.sysfs_obj[KEY] = [] + self.sysfs_device(dev['i2c']['topo_info'], path, self.sysfs_obj, KEY) + sysfs_path = "/sys/kernel/pddf/devices/psu/i2c/psu_idx" + self.sysfs_obj[KEY].append(sysfs_path) + + for attr in dev['i2c']['attr_list']: + self.sysfs_device(attr, "pddf/devices/psu/i2c", self.sysfs_obj, KEY) + sysfs_path = "/sys/kernel/pddf/devices/psu/i2c/dev_ops" + if not sysfs_path in self.sysfs_obj[KEY]: + self.sysfs_obj[KEY].append(sysfs_path) + list=['/sys/kernel/pddf/devices/psu/i2c/i2c_type', + '/sys/kernel/pddf/devices/fan/i2c/i2c_name', + '/sys/kernel/pddf/devices/psu/i2c/error', + '/sys/kernel/pddf/devices/psu/i2c/attr_ops'] + self.add_list_sysfs_obj(self.sysfs_obj, KEY, list) + + + def show_psu_device(self, dev, ops): + self.show_psu_i2c_device(dev, ops ) + return + + def show_client_device(self): + KEY ='client' + if not KEY in self.sysfs_obj: + self.sysfs_obj[KEY] = [] + list=['/sys/kernel/pddf/devices/showall'] + self.add_list_sysfs_obj(self.sysfs_obj, KEY, list) + + + def show_fan_device(self, dev, ops): + KEY ='fan' + path='pddf/devices/fan/i2c' + if dev['i2c']['topo_info']['dev_type'] in self.data['PLATFORM']['pddf_dev_types']['FAN']: + if not KEY in self.sysfs_obj: + self.sysfs_obj[KEY] = [] + + self.sysfs_device(dev['i2c']['topo_info'], path, self.sysfs_obj, KEY) + self.sysfs_device(dev['i2c']['dev_attr'], path, self.sysfs_obj, KEY) + for attr in dev['i2c']['attr_list']: + self.sysfs_device(attr, path, self.sysfs_obj, KEY) + list=['/sys/kernel/pddf/devices/fan/i2c/i2c_type', + '/sys/kernel/pddf/devices/fan/i2c/i2c_name', + '/sys/kernel/pddf/devices/fan/i2c/error', + '/sys/kernel/pddf/devices/fan/i2c/attr_ops', + '/sys/kernel/pddf/devices/fan/i2c/dev_ops'] + self.add_list_sysfs_obj(self.sysfs_obj, KEY, list) + + + def show_temp_sensor_device(self, dev, ops): + return + + def show_sysstatus_device(self, dev, ops): + KEY ='sysstatus' + if not KEY in self.sysfs_obj: + self.sysfs_obj[KEY] = [] + for attr in dev['attr_list']: + self.sysfs_device(attr, "pddf/devices/sysstatus", self.sysfs_obj, KEY) + sysfs_path= "/sys/kernel/pddf/devices/sysstatus/attr_ops" + if not sysfs_path in self.sysfs_obj[KEY]: + self.sysfs_obj[KEY].append(sysfs_path) + + + def show_xcvr_i2c_device(self, dev, ops): + KEY ='xcvr' + if dev['i2c']['topo_info']['dev_type'] in self.data['PLATFORM']['pddf_dev_types']['PORT_MODULE']: + if not KEY in self.sysfs_obj: + self.sysfs_obj[KEY] = [] + self.sysfs_device(dev['i2c']['topo_info'], "pddf/devices/xcvr/i2c", self.sysfs_obj, KEY) + + for attr in dev['i2c']['attr_list']: + self.sysfs_device(attr, "pddf/devices/xcvr/i2c", self.sysfs_obj, KEY) + sysfs_path = "/sys/kernel/pddf/devices/xcvr/i2c/dev_ops" + if not sysfs_path in self.sysfs_obj[KEY]: + self.sysfs_obj[KEY].append(sysfs_path) + list=['/sys/kernel/pddf/devices/xcvr/i2c/i2c_type', + '/sys/kernel/pddf/devices/xcvr/i2c/i2c_name', + '/sys/kernel/pddf/devices/xcvr/i2c/error', + '/sys/kernel/pddf/devices/xcvr/i2c/attr_ops'] + self.add_list_sysfs_obj(self.sysfs_obj, KEY, list) + + + def show_xcvr_device(self, dev, ops): + self.show_xcvr_i2c_device(dev, ops ) + return + + def show_cpld_device(self, dev, ops): + KEY ='cpld' + if dev['i2c']['topo_info']['dev_type'] in self.data['PLATFORM']['pddf_dev_types']['CPLD']: + if not KEY in self.sysfs_obj: + self.sysfs_obj[KEY] = [] + self.sysfs_device(dev['i2c']['topo_info'], "pddf/devices/cpld", self.sysfs_obj, KEY) + sysfs_path= "/sys/kernel/pddf/devices/cpld/dev_ops" + if not sysfs_path in self.sysfs_obj[KEY]: + self.sysfs_obj[KEY].append(sysfs_path) + list=['/sys/kernel/pddf/devices/cpld/i2c_type', + '/sys/kernel/pddf/devices/cpld/i2c_name', + '/sys/kernel/pddf/devices/cpld/error'] + self.add_list_sysfs_obj(self.sysfs_obj, KEY, list) + + def show_led_platform_device(self, key, ops): + if ops['attr']=='all' or ops['attr']=='PLATFORM': + KEY='platform' + if not KEY in self.sysfs_obj: + self.sysfs_obj[KEY] = [] + path='pddf/devices/platform' + self.sysfs_attr('num_psus', self.data['PLATFORM']['num_psus'], path, self.sysfs_obj, KEY) + self.sysfs_attr('num_fantrays', self.data['PLATFORM']['num_fantrays'], path, self.sysfs_obj, KEY) + + def show_led_device(self, key, ops): + if self.check_led_cmds(key, ops): + KEY='led' + if not KEY in self.sysfs_obj: + self.sysfs_obj[KEY] = [] + path="pddf/devices/led" + for attr in self.data[key]['i2c']['attr_list']: + self.sysfs_attr('device_name', self.data[key]['dev_info']['device_name'],path,self.sysfs_obj,KEY) + self.sysfs_attr('swpld_addr', self.data[key]['dev_info']['device_name'],path,self.sysfs_obj, KEY) + self.sysfs_attr('swpld_addr_offset',self.data[key]['dev_info']['device_name'], + path,self.sysfs_obj, KEY) + self.sysfs_device(self.data[key]['dev_attr'], path, self.sysfs_obj, KEY) + for attr_key in attr.keys(): + attr_path="pddf/devices/led/" + attr['attr_name'] + if (attr_key != 'attr_name' and attr_key != 'swpld_addr' and attr_key != 'swpld_addr_offset'): + self.sysfs_attr(attr_key, attr[attr_key], attr_path, self.sysfs_obj, KEY) + sysfs_path="/sys/kernel/pddf/devices/led/dev_ops" + if not sysfs_path in self.sysfs_obj[KEY]: + self.sysfs_obj[KEY].append(sysfs_path) + list=['/sys/kernel/pddf/devices/led/cur_state/color'] + self.add_list_sysfs_obj(self.sysfs_obj, KEY, list) + + + def validate_xcvr_device(self, dev, ops): + devtype_list = ['optoe1', 'optoe2'] + dev_attribs = ['xcvr_present', 'xcvr_reset', 'xcvr_intr_status', 'xcvr_lpmode'] + ret_val = "xcvr validation failed" + + if dev['i2c']['topo_info']['dev_type'] in devtype_list: + for attr in dev['i2c']['attr_list']: + if 'attr_name' in attr.keys() and 'eeprom' in attr.values(): + ret_val = "xcvr validation success" + else: + print "xcvr validation Failed" + return + + elif dev['i2c']['topo_info']['dev_type'] in self.data['PLATFORM']['pddf_dev_types']['PORT_MODULE']: + for attr in dev['i2c']['attr_list']: + if attr.get("attr_name") in dev_attribs: + ret_val = "Success" + else: + print "xcvr validation Failed" + return + print ret_val + + def validate_eeprom_device(self, dev, ops): + devtype_list = ['24c02'] + dev_access_mode = ['BLOCK', 'BYTE'] + dev_attribs = ['eeprom'] + ret_val = "eeprom failed" + + if dev['i2c']['topo_info']['dev_type'] in devtype_list: + if dev['i2c']['dev_attr']['access_mode'] in dev_access_mode: + for attr in dev['i2c']['attr_list']: + if attr.get("attr_name") in dev_attribs: + ret_val = "eeprom success" + print ret_val + + def validate_mux_device(self, dev, ops): + devtype_list = ['pca9548', 'pca954x'] + dev_channels = ["0", "1", "2", "3", "4", "5", "6", "7"] + ret_val = "mux failed" + + if dev['i2c']['topo_info']['dev_type'] in devtype_list: + for attr in dev['i2c']['channel']: + if attr.get("chn") in dev_channels: + ret_val = "Mux success" + print ret_val + + def validate_cpld_device(self, dev, ops): + devtype_list = ['i2c_cpld'] + ret_val = "cpld failed" + + if dev['i2c']['topo_info']['dev_type'] in devtype_list: + ret_val = "cpld success" + print ret_val + + + def validate_sysstatus_device(self, dev, ops): + dev_attribs = ['board_info', 'cpld1_version', 'power_module_status', 'system_reset5', + 'system_reset6', 'system_reset7', 'misc1', 'cpld2_version', 'cpld3_version' + ] + ret_val = "sysstatus failed" + + if dev['dev_info']['device_type'] == "SYSSTAT": + for attr in dev['attr_list']: + if attr.get("attr_name") in dev_attribs: + ret_val = "sysstatus success" + print ret_val + + def validate_temp_sensor_device(self, dev, ops): + devtype_list = ['lm75'] + dev_attribs = ['temp1_max', 'temp1_max_hyst', 'temp1_input'] + ret_val = "temp sensor failed" + + if dev['dev_info']['device_type'] == "TEMP_SENSOR": + if dev['i2c']['topo_info']['dev_type'] in devtype_list: + for attr in dev['i2c']['attr_list']: + if attr.get("attr_name") in dev_attribs: + ret_val = "tempsensor success" + print ret_val + + def validate_fan_device(self, dev, ops): + ret_val = "fan failed" + + if dev['i2c']['topo_info']['dev_type'] in self.data['PLATFORM']['pddf_dev_types']['FAN']: + if dev['i2c']['dev_attr']['num_fan'] is not None: + ret_val = "fan success" + + print ret_val + + def validate_psu_device(self, dev, ops): + dev_attribs = ['psu_present', 'psu_model_name', 'psu_power_good', 'psu_mfr_id', 'psu_serial_num', + 'psu_fan_dir', 'psu_v_out', 'psu_i_out', 'psu_p_out', 'psu_fan1_speed_rpm' + ] + ret_val = "psu failed" + + if dev['i2c']['topo_info']['dev_type'] in self.data['PLATFORM']['pddf_dev_types']['PSU']: + for attr in dev['i2c']['attr_list']: + if attr.get("attr_name") in dev_attribs: + if attr.get("attr_devaddr") is not None: + if attr.get("attr_offset") is not None: + if attr.get("attr_mask") is not None: + if attr.get("attr_len") is not None: + ret_val = "psu success" + else: + ret_val = "psu failed" + + print ret_val + + ################################################################################################################### + # SPYTEST + ################################################################################################################### + def verify_attr(self, key, attr, path): + node="/sys/kernel/%s/%s"%(path, key) + try: + with open(node, 'r') as f: + status = f.read() + except IOError: + print "PDDF_VERIFY_ERR: IOError: node:%s key:%s"%(node, key) + return + + status=status.rstrip("\n\r") + if attr[key]!=status: + print "PDDF_VERIFY_ERR: node: %s switch:%s"%(node, status) + + def verify_device(self, attr, path, ops): + for key in attr.keys(): + self.verify_attr(key, attr, path) + + + def get_led_device(self, device_name): + self.create_attr('device_name', self.data[device_name]['dev_info']['device_name'], "pddf/devices/led") + self.create_attr('index', self.data[device_name]['dev_attr']['index'], "pddf/devices/led") + cmd="echo 'verify' > /sys/kernel/pddf/devices/led/dev_ops" + self.runcmd(cmd) + + def validate_sysfs_creation(self, obj, validate_type): + dir = '/sys/kernel/pddf/devices/'+validate_type + if (os.path.exists(dir) or validate_type=='client'): + for sysfs in obj[validate_type]: + if(not os.path.exists(sysfs)): + print "[SYSFS FILE] " + sysfs + ": does not exist" + else: + print "[SYSFS DIR] " + dir + ": does not exist" + + def validate_dsysfs_creation(self, obj, validate_type): + if validate_type in obj.keys(): + # There is a possibility that some components dont have any device-self.data attr + if not obj[validate_type]: + print "[SYSFS ATTR] for " + validate_type + ": empty " + else: + for sysfs in obj[validate_type]: + if(not os.path.exists(sysfs)): + print "[SYSFS FILE] " + sysfs + ": does not exist" + else: + print "[SYSFS KEY] for " + validate_type + ": not configured" + + def verify_sysfs_data(self, verify_type): + if (verify_type=='LED'): + for key in self.data.keys(): + if key != 'PLATFORM': + attr=self.data[key]['dev_info'] + if attr['device_type'] == 'LED': + self.get_led_device(key) + self.verify_attr('device_name', self.data[key]['dev_info'], "pddf/devices/led") + self.verify_attr('index', self.data[key]['dev_attr'], "pddf/devices/led") + for attr in self.data[key]['i2c']['attr_list']: + path="pddf/devices/led/" + attr['attr_name'] + for entry in attr.keys(): + if (entry != 'attr_name' and entry != 'swpld_addr' and entry != 'swpld_addr_offset'): + self.verify_attr(entry, attr, path) + if ( entry == 'swpld_addr' or entry == 'swpld_addr_offset'): + self.verify_attr(entry, attr, 'pddf/devices/led') + + + + def schema_validation(self, validate_type): + process_validate_type = 0 + for key in self.data.keys(): + if (key != 'PLATFORM'): + temp_obj={} + schema_list=[] + try: + device_type=self.data[key]["dev_info"]["device_type"] + except Exception as e: + print "dev_info or device_type ERROR: " + key + print e + + if validate_type == 'mismatch': + process_validate_type = 1 + device_type="PSU" + schema_file="/usr/local/bin/schema/FAN.schema" + schema_list.append(schema_file) + elif validate_type == 'missing': + process_validate_type = 1 + schema_file="/usr/local/bin/schema/PLATFORM.schema" + schema_list.append(schema_file) + + elif validate_type == 'empty': + process_validate_type = 1 + if not device_type: + print "Empty device_type for " + key + continue + elif (validate_type=='all' or validate_type==device_type): + process_validate_type = 1 + if "bmc" in self.data[key].keys(): + schema_file="/usr/local/bin/schema/"+device_type + "_BMC.schema" + schema_list.append(schema_file) + + if "i2c" in self.data[key].keys(): + schema_file="/usr/local/bin/schema/"+device_type + ".schema" + schema_list.append(schema_file) + if device_type: + temp_obj[device_type]=self.data[key] + for schema_file in schema_list: + if (os.path.exists(schema_file)): + print "Validate " + schema_file + ";" + key + json_data=json.dumps(temp_obj) + with open(schema_file, 'r') as f: + schema=json.load(f) + try: + validate(temp_obj, schema) + except Exception as e: + print "Validation ERROR: " + schema_file + ";" + key + if validate_type == 'mismatch': + return + else: + print e + else: + print "ERROR Missing File: " + schema_file + if not process_validate_type: + print "device_type: " + validate_type + " not configured" + + def modules_validation(self, validate_type): + kos = [] + supported_type = False + module_validation_status=[] + + if validate_type == "bmc": + kos=['ipmi_devintf', 'ipmi_si', 'ipmi_msghandler'] + validate_type = 'ipmi' + else: + # generate the KOS list from pddf device JSON file + kos.extend(self.data['PLATFORM']['pddf_kos']) + + if 'custom_kos' in self.data['PLATFORM']: + kos.extend(self.data['PLATFORM']['custom_kos']) + + for mod in kos: + if validate_type in mod or validate_type == "pddf": + supported_type=True + cmd = "lsmod | grep " + mod + try: + subprocess.check_output(cmd, shell=True) + except Exception as e: + module_validation_status.append(mod) + if supported_type: + if module_validation_status: + module_validation_status.append(":ERROR not loaded") + print str(module_validation_status)[1:-1] + else: + print "Loaded" + else: + print validate_type + " not configured" + + + + + + ################################################################################################################### + # PARSE DEFS + ################################################################################################################### + def psu_parse(self, dev, ops): + parse_str="" + ret="" + for ifce in dev['i2c']['interface']: + ret=getattr(self, ops['cmd']+"_psu_device")(self.data[ifce['dev']], ops ) + if not ret is None: + if str(ret).isdigit(): + if ret!=0: + # in case if 'create' functions + print "{}_psu_device failed".format(ops['cmd']) + return ret + else: + pass + else: + # in case of 'show_attr' functions + parse_str+=ret + return parse_str + + def fan_parse(self, dev, ops): + parse_str="" + ret=getattr(self, ops['cmd']+"_fan_device")(dev, ops ) + if not ret is None: + if str(ret).isdigit(): + if ret!=0: + # in case if 'create' functions + print "{}_fan_device failed".format(ops['cmd']) + return ret + else: + pass + else: + # in case of 'show_attr' functions + parse_str+=ret + + return parse_str + + def temp_sensor_parse(self, dev, ops): + parse_str="" + ret=getattr(self, ops['cmd']+"_temp_sensor_device")(dev, ops ) + if not ret is None: + if str(ret).isdigit() : + if ret!=0: + # in case if 'create' functions + print "{}_temp_sensor_device failed".format(ops['cmd']) + return ret + else: + pass + else: + # in case of 'show_attr' functions + parse_str+=ret + + return parse_str + + def cpld_parse(self, dev, ops): + parse_str = "" + ret = getattr(self, ops['cmd']+"_cpld_device")(dev, ops) + if not ret is None: + if str(ret).isdigit(): + if ret!=0: + # in case if 'create' functions + print "{}_cpld_device failed".format(ops['cmd']) + return ret + else: + pass + else: + # in case of 'show_attr' functions + parse_str+=ret + + return parse_str + + def cpldmux_parse(self, dev, ops): + parse_str = "" + ret = getattr(self, ops['cmd']+"_cpldmux_device")(dev, ops) + if not ret is None: + if str(ret).isdigit(): + if ret!=0: + # in case if 'create' functions + print "{}_cpldmux_device() cmd failed".format(ops['cmd']) + return ret + else: + pass + else: + parse_str += ret + + for chan in dev['i2c']['channel']: + for device in chan['dev']: + ret = self.dev_parse(self.data[device], ops) + if not ret is None: + if str(ret).isdigit(): + if ret!=0: + # in case if 'create' functions + return ret + else: + pass + else: + parse_str += ret + + return parse_str + + def cpldmux_parse_reverse(self, dev, ops): + parse_str = "" + for chan in reversed(dev['i2c']['channel']): + for device in reversed(chan['dev']): + ret = self.dev_parse(self.data[device], ops) + if not ret is None: + if str(ret).isdigit(): + if ret!=0: + # in case if 'create' functions + return ret + else: + pass + else: + parse_str += ret + + ret = getattr(self, ops['cmd']+"_cpldmux_device")(dev, ops) + if not ret is None: + if str(ret).isdigit(): + if ret!=0: + # in case if 'create' functions + print "{}_cpldmux_device() cmd failed".format(ops['cmd']) + return ret + else: + pass + else: + parse_str += ret + + return parse_str + + + def sysstatus_parse(self, dev,ops): + parse_str = "" + ret = getattr(self, ops['cmd']+"_sysstatus_device")(dev, ops) + if not ret is None: + if str(ret).isdigit(): + if ret!=0: + # in case if 'create' functions + print "{}_sysstatus_device failed".format(ops['cmd']) + return ret + else: + pass + else: + # in case of 'show_attr' functions + parse_str+=ret + + return parse_str + + def gpio_parse(self, dev, ops): + parse_str = "" + ret = getattr(self, ops['cmd']+"_gpio_device")(dev, ops) + if not ret is None: + if str(ret).isdigit(): + if ret!=0: + # in case if 'create' functions + print "{}_temp_sensor_device failed".format(ops['cmd']) + return ret + else: + pass + else: + # in case of 'show_attr' functions + parse_str += ret + + return parse_str + + + def mux_parse(self, dev, ops): + parse_str = "" + ret = getattr(self, ops['cmd']+"_mux_device")(dev, ops) + if not ret is None: + if str(ret).isdigit(): + if ret!=0: + # in case if 'create' functions + print "{}_mux_device() cmd failed".format(ops['cmd']) + return ret + else: + pass + else: + parse_str += ret + + for ch in dev['i2c']['channel']: + ret = self.dev_parse(self.data[ch['dev']], ops) + if not ret is None: + if str(ret).isdigit(): + if ret!=0: + # in case if 'create' functions + return ret + else: + pass + else: + parse_str += ret + return parse_str + + def mux_parse_reverse(self, dev, ops): + parse_str = "" + for ch in reversed(dev['i2c']['channel']): + ret = self.dev_parse(self.data[ch['dev']], ops) + if not ret is None: + if str(ret).isdigit(): + if ret!=0: + # in case if 'create' functions + return ret + else: + pass + else: + parse_str += ret + + ret = getattr(self, ops['cmd']+"_mux_device")(dev, ops) + if not ret is None: + if str(ret).isdigit(): + if ret!=0: + # in case if 'create' functions + print "{}_mux_device() cmd failed".format(ops['cmd']) + return ret + else: + pass + else: + parse_str += ret + + return parse_str + + + def eeprom_parse(self, dev, ops): + parse_str = "" + ret = getattr(self, ops['cmd']+"_eeprom_device")(dev, ops) + if not ret is None: + if str(ret).isdigit(): + if ret!=0: + # in case if 'create' functions + print "{}_eeprom_device() cmd failed".format(ops['cmd']) + return ret + else: + pass + else: + parse_str += ret + + return parse_str + + def optic_parse(self, dev, ops): + parse_str="" + ret="" + for ifce in dev['i2c']['interface']: + ret=getattr(self, ops['cmd']+"_xcvr_device")(self.data[ifce['dev']], ops ) + if not ret is None: + if str(ret).isdigit(): + if ret!=0: + # in case if 'create' functions + print "{}_eeprom_device() cmd failed".format(ops['cmd']) + return ret + else: + pass + else: + parse_str+=ret + return parse_str + + def cpu_parse(self, bus, ops): + parse_str = "" + for dev in bus['i2c']['CONTROLLERS']: + dev1 = self.data[dev['dev']] + for d in dev1['i2c']['DEVICES']: + ret=self.dev_parse(self.data[d['dev']], ops) + if not ret is None: + if str(ret).isdigit(): + if ret!=0: + # in case if 'create' functions + return ret + else: + pass + else: + parse_str += ret + return parse_str + + def cpu_parse_reverse(self, bus, ops): + parse_str = "" + for dev in reversed(bus['i2c']['CONTROLLERS']): + dev1 = self.data[dev['dev']] + for d in reversed(dev1['i2c']['DEVICES']): + ret=self.dev_parse(self.data[d['dev']], ops) + if not ret is None: + if str(ret).isdigit(): + if ret!=0: + # in case if 'create' functions + return ret + else: + pass + else: + parse_str += ret + return parse_str + + + def dev_parse(self, dev, ops): + attr=dev['dev_info'] + if attr['device_type'] == 'CPU': + if ops['cmd']=='delete': + return self.cpu_parse_reverse(dev, ops) + else: + return self.cpu_parse(dev, ops) + + if attr['device_type'] == 'EEPROM': + return self.eeprom_parse(dev, ops) + + if attr['device_type'] == 'MUX': + if ops['cmd']=='delete': + return self.mux_parse_reverse(dev, ops) + else: + return self.mux_parse(dev, ops) + + if attr['device_type'] == 'GPIO': + return self.gpio_parse(dev, ops) + + if attr['device_type'] == 'PSU': + return self.psu_parse(dev, ops) + + if attr['device_type'] == 'FAN': + return self.fan_parse(dev, ops) + + if attr['device_type'] == 'TEMP_SENSOR': + return self.temp_sensor_parse(dev, ops) + + if attr['device_type'] == 'SFP' or attr['device_type'] == 'SFP28' or \ + attr['device_type'] == 'QSFP' or attr['device_type'] == 'QSFP28': + return self.optic_parse(dev, ops) + + if attr['device_type'] == 'CPLD': + return self.cpld_parse(dev, ops) + + if attr['device_type'] == 'CPLDMUX': + if ops['cmd']=='delete': + return self.cpldmux_parse_reverse(dev, ops) + else: + return self.cpldmux_parse(dev, ops) + + if attr['device_type'] == 'SYSSTAT': + return self.sysstatus_parse(dev,ops) + + def is_supported_sysled_state(self, sysled_name, sysled_state): + if not sysled_name in self.data.keys(): + return False, "[FAILED] " + sysled_name + " is not configured" + for attr in self.data[sysled_name]['i2c']['attr_list']: + if attr['attr_name'] == sysled_state: + return True, "[PASS] supported" + return False, "[FAILED]: Invalid color" + + + def create_attr(self, key, value, path): + cmd = "echo '%s' > /sys/kernel/%s/%s"%(value, path, key) + self.runcmd(cmd) + + def create_led_platform_device(self, key, ops): + if ops['attr']=='all' or ops['attr']=='PLATFORM': + path='pddf/devices/platform' + self.create_attr('num_psus', self.data['PLATFORM']['num_psus'], path) + self.create_attr('num_fantrays', self.data['PLATFORM']['num_fantrays'], path) + + def create_led_device(self, key, ops): + if ops['attr']=='all' or ops['attr']==self.data[key]['dev_info']['device_name']: + path="pddf/devices/led" + for attr in self.data[key]['i2c']['attr_list']: + self.create_attr('device_name', self.data[key]['dev_info']['device_name'], path) + self.create_device(self.data[key]['dev_attr'], path, ops) + for attr_key in attr.keys(): + if (attr_key == 'swpld_addr_offset' or attr_key == 'swpld_addr'): + self.create_attr(attr_key, attr[attr_key], path) + elif (attr_key != 'attr_name' and attr_key != 'descr' and + attr_key != 'attr_devtype' and attr_key != 'attr_devname'): + state_path=path+'/state_attr' + self.create_attr(attr_key, attr[attr_key],state_path) + cmd="echo '" + attr['attr_name']+"' > /sys/kernel/pddf/devices/led/dev_ops" + self.runcmd(cmd) + + + + def led_parse(self, ops): + getattr(self, ops['cmd']+"_led_platform_device")("PLATFORM", ops) + for key in self.data.keys(): + if key != 'PLATFORM' and 'dev_info' in self.data[key]: + attr=self.data[key]['dev_info'] + if attr['device_type'] == 'LED': + getattr(self, ops['cmd']+"_led_device")(key, ops) + + + def get_device_list(self, list, type): + for key in self.data.keys(): + if key != 'PLATFORM' and 'dev_info' in self.data[key]: + attr=self.data[key]['dev_info'] + if attr['device_type'] == type: + list.append(self.data[key]) + + + def create_pddf_devices(self): + self.led_parse({ "cmd": "create", "target":"all", "attr":"all" }) + create_ret = 0 + create_ret = self.dev_parse(self.data['SYSTEM'], { "cmd": "create", "target":"all", "attr":"all" } ) + if create_ret!=0: + return create_ret + if 'SYSSTATUS' in self.data: + create_ret = self.dev_parse(self.data['SYSSTATUS'], { "cmd": "create", "target":"all", "attr":"all" } ) + if create_ret!=0: + return create_ret + + def delete_pddf_devices(self): + self.dev_parse(self.data['SYSTEM'], { "cmd": "delete", "target":"all", "attr":"all" } ) + if 'SYSSTATUS' in self.data: + self.dev_parse(self.data['SYSSTATUS'], { "cmd": "delete", "target":"all", "attr":"all" } ) + + def populate_pddf_sysfsobj(self): + self.dev_parse(self.data['SYSTEM'], { "cmd": "show", "target":"all", "attr":"all" } ) + if 'SYSSTATUS' in self.data: + self.dev_parse(self.data['SYSSTATUS'], { "cmd": "show", "target":"all", "attr":"all" } ) + self.led_parse({ "cmd": "show", "target":"all", "attr":"all" }) + self.show_client_device() + + def cli_dump_dsysfs(self, component): + self.dev_parse(self.data['SYSTEM'], { "cmd": "show_attr", "target":"all", "attr":"all" } ) + if 'SYSSTATUS' in self.data: + self.dev_parse(self.data['SYSSTATUS'], { "cmd": "show_attr", "target":"all", "attr":"all" } ) + if component in self.data_sysfs_obj: + return self.data_sysfs_obj[component] + else: + return None + + + def validate_pddf_devices(self, *args): + self.populate_pddf_sysfsobj() + v_ops = { 'cmd': 'validate', 'target':'all', 'attr':'all' } + self.dev_parse(self.data['SYSTEM'], v_ops ) + + ################################################################################################################## + # BMC APIs + ################################################################################################################## + def populate_bmc_cache_db(self, bmc_attr): + bmc_cmd = str(bmc_attr['bmc_cmd']).strip() + + if 'delimiter' in bmc_attr.keys(): + delim = str(bmc_attr['delimiter']).strip() + else: + delim = None + + o_list = subprocess.check_output(bmc_cmd, shell=True).strip().split('\n') + bmc_cache[bmc_cmd]={} + bmc_cache[bmc_cmd]['time']=time.time() + for entry in o_list: + name = entry.split(delim)[0].strip() + bmc_cache[bmc_cmd][name]=entry + + def non_raw_ipmi_get_request(self, bmc_attr): + bmc_db_update_time=1 + value = 'N/A' + bmc_cmd = str(bmc_attr['bmc_cmd']).strip() + field_name = str(bmc_attr['field_name']).strip() + field_pos= int(bmc_attr['field_pos'])-1 + + if 'delimiter' in bmc_attr.keys(): + delim = str(bmc_attr['delimiter']).strip() + else: + delim = None + + if not bmc_cmd in bmc_cache: + self.populate_bmc_cache_db(bmc_attr) + else: + now = time.time() + if (int(now - bmc_cache[bmc_cmd]['time']) > bmc_db_update_time): + self.populate_bmc_cache_db(bmc_attr) + + try: + data=bmc_cache[bmc_cmd][field_name] + value = data.split(delim)[field_pos].strip() + except Exception as e: + pass + + if 'mult' in bmc_attr.keys() and not value.isalpha(): + if value.isalpha(): + value = 0.0 + value = float(value) * float(bmc_attr['mult']) + + return str(value) + + def raw_ipmi_get_request(self, bmc_attr): + value = 'N/A' + cmd = bmc_attr['bmc_cmd'] + " 2>/dev/null" + if bmc_attr['type'] == 'raw': + try: + value = subprocess.check_output(cmd, shell=True).strip() + except Exception as e: + pass + + if value != 'N/A': + value = str(int(value, 16)) + return value + + if bmc_attr['type'] == 'mask': + mask = int(bmc_attr['mask'].encode('utf-8'), 16) + try: + value = subprocess.check_output(cmd, shell=True).strip() + except Exception as e: + pass + + # value should either be '1' or '0' + if value != 'N/A': + value = '1' if bool(int(value, 16) & mask) else '0' + + return value + + if bmc_attr['type'] == 'ascii': + try: + value = subprocess.check_output(cmd, shell=True) + except Exception as e: + pass + + if value != 'N/A': + tmp = ''.join(chr(int(i, 16)) for i in value.split()) + tmp = "".join(i for i in unicode(tmp) if unicodedata.category(i)[0]!="C") + value = str(tmp) + + return (value) + + return value + + def bmc_get_cmd(self, bmc_attr): + if int(bmc_attr['raw']) == 1: + value = self.raw_ipmi_get_request(bmc_attr) + else: + value = self.non_raw_ipmi_get_request(bmc_attr) + return (value) + + def non_raw_ipmi_set_request(self, bmc_attr, val): + value = 'N/A' + # TODO: Implement it + return value + + def raw_ipmi_set_request(self, bmc_attr, val): + value = 'N/A' + # TODO: Implement this + return value + + def bmc_set_cmd(self, bmc_attr, val): + if int(bmc_attr['raw']) == 1: + value = self.raw_ipmi_set_request(bmc_attr, val) + else: + value = self.non_raw_ipmi_set_request(bmc_attr, val) + return (value) + + # bmc-based attr: return attr obj + # non-bmc-based attr: return empty obj + def check_bmc_based_attr(self, device_name, attr_name): + if device_name in self.data.keys(): + if "bmc" in self.data[device_name].keys() and 'ipmitool' in self.data[device_name]['bmc'].keys(): + attr_list = self.data[device_name]['bmc']['ipmitool']['attr_list'] + for attr in attr_list: + if attr['attr_name'].strip() == attr_name.strip(): + return attr + # Required attr_name is not supported in BMC object + return {} + return None + + def get_attr_name_output(self, device_name, attr_name): + bmc_attr = self.check_bmc_based_attr(device_name, attr_name) + output={"mode":"", "status":""} + + if bmc_attr is not None: + if bmc_attr=={}: + return {} + output['mode']="bmc" + output['status']=self.bmc_get_cmd(bmc_attr) + else: + output['mode']="i2c" + node = self.get_path(device_name, attr_name) + if node is None: + return {} + try: + with open(node, 'r') as f: + output['status'] = f.read() + except IOError: + return {} + return output + + def set_attr_name_output(self, device_name, attr_name, val): + bmc_attr = self.check_bmc_based_attr(device_name, attr_name) + output={"mode":"", "status":""} + + if bmc_attr is not None: + if bmc_attr=={}: + return {} + output['mode']="bmc" + output['status']=False # No set operation allowed for BMC attributes as they are handled by BMC itself + else: + output['mode']="i2c" + node = self.get_path(device_name, attr_name) + if node is None: + return {} + try: + with open(node, 'w') as f: + f.write(str(val)) + except IOError: + return {} + + output['status'] = True + + return output + + ################################################################################################################### + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--create", action='store_true', help="create the I2C topology") + parser.add_argument("--sysfs", action='store', nargs="+", help="show access-attributes sysfs for the I2C topology") + parser.add_argument("--dsysfs", action='store', nargs="+", help="show data-attributes sysfs for the I2C topology") + parser.add_argument("--delete", action='store_true', help="Remove all the created I2C clients from topology") + parser.add_argument("--validate", action='store', help="Validate the device specific attribute data elements") + parser.add_argument("--schema", action='store', nargs="+", help="Schema Validation") + parser.add_argument("--modules", action='store', nargs="+", help="Loaded modules validation") + + args = parser.parse_args() + + # Create the object + try: + pddf_obj = PddfParse() + except Exception as e: + print "%s" % str(e) + sys.exit() + + if args.create: + pddf_obj.create_pddf_devices() + + if args.sysfs: + if args.sysfs[0] == 'all': + pddf_obj.populate_pddf_sysfsobj() + if args.sysfs[0] == 'print': + pddf_obj.populate_pddf_sysfsobj() + pddf_obj.dump_sysfs_obj(pddf_obj.sysfs_obj, args.sysfs[1]) + if args.sysfs[0] == 'validate': + pddf_obj.populate_pddf_sysfsobj() + pddf_obj.validate_sysfs_creation(pddf_obj.sysfs_obj, args.sysfs[1]) + if args.sysfs[0] == 'verify': + pddf_obj.verify_sysfs_data(args.sysfs[1]) + + + if args.dsysfs: + if args.dsysfs[0] == 'validate': + pddf_obj.dev_parse(pddf_obj.data['SYSTEM'], { "cmd": "show_attr", "target":"all", "attr":"all" } ) + if 'SYSSTATUS' in pddf_obj.data: + pddf_obj.dev_parse(pddf_obj.data['SYSSTATUS'], { "cmd": "show_attr", "target":"all", "attr":"all" } ) + pddf_obj.validate_dsysfs_creation(pddf_obj.data_sysfs_obj, args.dsysfs[1]) + + elif args.dsysfs[0] == 'print': + pddf_obj.dev_parse(pddf_obj.data['SYSTEM'], { "cmd": "show_attr", "target":"all", "attr":"all" } ) + if 'SYSSTATUS' in pddf_obj.data: + pddf_obj.dev_parse(pddf_obj.data['SYSSTATUS'], { "cmd": "show_attr", "target":"all", "attr":"all" } ) + pddf_obj.dump_sysfs_obj(pddf_obj.data_sysfs_obj, args.dsysfs[1]) + + elif args.dsysfs[0] == 'all': + ret = pddf_obj.dev_parse(pddf_obj.data['SYSTEM'], { "cmd": "show_attr", "target":"all", "attr":"all" } ) + if 'SYSSTATUS' in pddf_obj.data: + ret += pddf_obj.dev_parse(pddf_obj.data['SYSSTATUS'], { "cmd": "show_attr", "target":"all", + "attr":"all" } ) + pddf_obj.dump_sysfs_obj(pddf_obj.data_sysfs_obj, 'all') + else: + pddf_obj.dev_parse(pddf_obj.data[args.dsysfs[0]], { "cmd": "show_attr", "target":args.dsysfs[0], + "attr":args.dsysfs[1] }) + + if args.delete: + pddf_obj.delete_pddf_devices() + + if args.validate: + if args.validate[0] == 'all': + pddf_obj.validate_pddf_devices(args.validate[1:]) + else: + pass + + if args.schema: + pddf_obj.schema_validation(args.schema[0]) + + if args.modules: + pddf_obj.modules_validation(args.modules[0]) + + + +if __name__ == "__main__" : + main() diff --git a/platform/pddf/i2c/utils/schema/CPLD.schema b/platform/pddf/i2c/utils/schema/CPLD.schema new file mode 100644 index 0000000000..c2f8c0de84 --- /dev/null +++ b/platform/pddf/i2c/utils/schema/CPLD.schema @@ -0,0 +1,67 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "CPLD": { + "type": "object", + "properties": { + "dev_info": { + "type": "object", + "properties": { + "device_type": { + "type": "string" + }, + "device_name": { + "type": "string" + }, + "device_parent": { + "type": "string" + } + }, + "required": [ + "device_type", + "device_name", + "device_parent" + ] + }, + "i2c": { + "type": "object", + "properties": { + "topo_info": { + "type": "object", + "properties": { + "parent_bus": { + "type": "string" + }, + "dev_addr": { + "type": "string" + }, + "dev_type": { + "type": "string" + } + }, + "required": [ + "parent_bus", + "dev_addr", + "dev_type" + ] + }, + "dev_attr": { + "type": "object" + } + }, + "required": [ + "topo_info" + ] + } + }, + "required": [ + "dev_info", + "i2c" + ] + } + }, + "required": [ + "CPLD" + ] +} diff --git a/platform/pddf/i2c/utils/schema/CPU.schema b/platform/pddf/i2c/utils/schema/CPU.schema new file mode 100644 index 0000000000..9bb07ae0f6 --- /dev/null +++ b/platform/pddf/i2c/utils/schema/CPU.schema @@ -0,0 +1,80 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "CPU": { + "type": "object", + "properties": { + "dev_info": { + "type": "object", + "properties": { + "device_type": { + "type": "string" + }, + "device_name": { + "type": "string" + }, + "device_parent": { + "type": "null" + } + }, + "required": [ + "device_type", + "device_name", + "device_parent" + ] + }, + "i2c": { + "type": "object", + "properties": { + "CONTROLLERS": { + "type": "array", + "items": [ + { + "type": "object", + "properties": { + "dev_name": { + "type": "string" + }, + "dev": { + "type": "string" + } + }, + "required": [ + "dev_name", + "dev" + ] + }, + { + "type": "object", + "properties": { + "dev_name": { + "type": "string" + }, + "dev": { + "type": "string" + } + }, + "required": [ + "dev_name", + "dev" + ] + } + ] + } + }, + "required": [ + "CONTROLLERS" + ] + } + }, + "required": [ + "dev_info", + "i2c" + ] + } + }, + "required": [ + "CPU" + ] +} diff --git a/platform/pddf/i2c/utils/schema/EEPROM.schema b/platform/pddf/i2c/utils/schema/EEPROM.schema new file mode 100644 index 0000000000..a8e8885e3a --- /dev/null +++ b/platform/pddf/i2c/utils/schema/EEPROM.schema @@ -0,0 +1,93 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "EEPROM": { + "type": "object", + "properties": { + "dev_info": { + "type": "object", + "properties": { + "device_type": { + "type": "string" + }, + "device_name": { + "type": "string" + }, + "device_parent": { + "type": "string" + } + }, + "required": [ + "device_type", + "device_name", + "device_parent" + ] + }, + "i2c": { + "type": "object", + "properties": { + "topo_info": { + "type": "object", + "properties": { + "parent_bus": { + "type": "string" + }, + "dev_addr": { + "type": "string" + }, + "dev_type": { + "type": "string" + } + }, + "required": [ + "parent_bus", + "dev_addr", + "dev_type" + ] + }, + "dev_attr": { + "type": "object", + "properties": { + "access_mode": { + "type": "string" + } + }, + "required": [ + "access_mode" + ] + }, + "attr_list": { + "type": "array", + "items": [ + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + } + }, + "required": [ + "attr_name" + ] + } + ] + } + }, + "required": [ + "topo_info", + "dev_attr", + "attr_list" + ] + } + }, + "required": [ + "dev_info", + "i2c" + ] + } + }, + "required": [ + "EEPROM" + ] +} diff --git a/platform/pddf/i2c/utils/schema/FAN.schema b/platform/pddf/i2c/utils/schema/FAN.schema new file mode 100644 index 0000000000..0690075331 --- /dev/null +++ b/platform/pddf/i2c/utils/schema/FAN.schema @@ -0,0 +1,113 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "FAN": { + "type": "object", + "properties": { + "dev_info": { + "type": "object", + "properties": { + "device_type": { + "type": "string" + }, + "device_name": { + "type": "string" + }, + "device_parent": { + "type": "string" + } + }, + "required": [ + "device_type", + "device_name", + "device_parent" + ] + }, + "i2c": { + "type": "object", + "properties": { + "topo_info": { + "type": "object", + "properties": { + "parent_bus": { + "type": "string" + }, + "dev_addr": { + "type": "string" + }, + "dev_type": { + "type": "string" + } + }, + "required": [ + "parent_bus", + "dev_addr", + "dev_type" + ] + }, + "dev_attr": { + "type": "object", + "properties": { + "num_fantrays": { + "type": "string" + } + }, + "required": [ + "num_fantrays" + ] + }, + "attr_list": { + "type": "array", + "items": [ + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + }, + "attr_devtype": { + "type": "string" + }, + "attr_offset": { + "type": "string" + }, + "attr_mask": { + "type": "string" + }, + "attr_cmpval": { + "type": "string" + }, + "attr_len": { + "type": "string" + } + }, + "required": [ + "attr_name", + "attr_devtype", + "attr_offset", + "attr_mask", + "attr_cmpval", + "attr_len" + ] + } + ] + } + }, + "required": [ + "topo_info", + "dev_attr", + "attr_list" + ] + } + }, + "required": [ + "dev_info", + "i2c" + ] + } + }, + "required": [ + "FAN" + ] +} diff --git a/platform/pddf/i2c/utils/schema/FAN_BMC.schema b/platform/pddf/i2c/utils/schema/FAN_BMC.schema new file mode 100644 index 0000000000..41d774dfa6 --- /dev/null +++ b/platform/pddf/i2c/utils/schema/FAN_BMC.schema @@ -0,0 +1,69 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "FAN": { + "type": "object", + "properties": { + "dev_info": { + "type": "object", + "properties": { + "device_type": { + "type": "string" + } + }, + "required": [ + "device_type" + ] + }, + "bmc": { + "type": "object", + "properties": { + "ipmitool": { + "type": "object", + "properties": { + "attr_list": { + "type": "array", + "items": [ + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + }, + "bmc_cmd": { + "type": "string" + }, + "raw": { + "type": "string" + } + }, + "required": [ + "attr_name", + "bmc_cmd", + "raw" + ] + } + ] + } + }, + "required": [ + "attr_list" + ] + } + }, + "required": [ + "ipmitool" + ] + } + }, + "required": [ + "dev_info", + "bmc" + ] + } + }, + "required": [ + "FAN" + ] +} diff --git a/platform/pddf/i2c/utils/schema/LED.schema b/platform/pddf/i2c/utils/schema/LED.schema new file mode 100644 index 0000000000..04583ee660 --- /dev/null +++ b/platform/pddf/i2c/utils/schema/LED.schema @@ -0,0 +1,120 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "LED": { + "type": "object", + "properties": { + "dev_info": { + "type": "object", + "properties": { + "device_type": { + "type": "string" + }, + "device_name": { + "type": "string" + } + }, + "required": [ + "device_type", + "device_name" + ] + }, + "dev_attr": { + "type": "object", + "properties": { + "index": { + "type": "string" + } + }, + "required": [ + "index" + ] + }, + "i2c": { + "type": "object", + "properties": { + "attr_list": { + "type": "array", + "items": [ + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + }, + "bits": { + "type": "string" + }, + "color": { + "type": "string" + }, + "value": { + "type": "string" + }, + "swpld_addr": { + "type": "string" + }, + "swpld_addr_offset": { + "type": "string" + } + }, + "required": [ + "attr_name", + "bits", + "color", + "value", + "swpld_addr", + "swpld_addr_offset" + ] + }, + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + }, + "bits": { + "type": "string" + }, + "color": { + "type": "string" + }, + "value": { + "type": "string" + }, + "swpld_addr": { + "type": "string" + }, + "swpld_addr_offset": { + "type": "string" + } + }, + "required": [ + "attr_name", + "bits", + "color", + "value", + "swpld_addr", + "swpld_addr_offset" + ] + } + ] + } + }, + "required": [ + "attr_list" + ] + } + }, + "required": [ + "dev_info", + "dev_attr", + "i2c" + ] + } + }, + "required": [ + "LED" + ] +} diff --git a/platform/pddf/i2c/utils/schema/MUX.schema b/platform/pddf/i2c/utils/schema/MUX.schema new file mode 100644 index 0000000000..6ef46e8dd2 --- /dev/null +++ b/platform/pddf/i2c/utils/schema/MUX.schema @@ -0,0 +1,97 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "MUX": { + "type": "object", + "properties": { + "dev_info": { + "type": "object", + "properties": { + "device_type": { + "type": "string" + }, + "device_name": { + "type": "string" + }, + "device_parent": { + "type": "string" + } + }, + "required": [ + "device_type", + "device_name", + "device_parent" + ] + }, + "i2c": { + "type": "object", + "properties": { + "topo_info": { + "type": "object", + "properties": { + "parent_bus": { + "type": "string" + }, + "dev_addr": { + "type": "string" + }, + "dev_type": { + "type": "string" + } + }, + "required": [ + "parent_bus", + "dev_addr", + "dev_type" + ] + }, + "dev_attr": { + "type": "object", + "properties": { + "virt_bus": { + "type": "string" + } + }, + "required": [ + "virt_bus" + ] + }, + "channel": { + "type": "array", + "items": [ + { + "type": "object", + "properties": { + "chn": { + "type": "string" + }, + "dev": { + "type": "string" + } + }, + "required": [ + "chn", + "dev" + ] + } + ] + } + }, + "required": [ + "topo_info", + "dev_attr", + "channel" + ] + } + }, + "required": [ + "dev_info", + "i2c" + ] + } + }, + "required": [ + "MUX" + ] +} diff --git a/platform/pddf/i2c/utils/schema/PSU-PMBUS.schema b/platform/pddf/i2c/utils/schema/PSU-PMBUS.schema new file mode 100644 index 0000000000..6516d23213 --- /dev/null +++ b/platform/pddf/i2c/utils/schema/PSU-PMBUS.schema @@ -0,0 +1,109 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "PSU-PMBUS": { + "type": "object", + "properties": { + "dev_info": { + "type": "object", + "properties": { + "device_type": { + "type": "string" + }, + "device_name": { + "type": "string" + }, + "device_parent": { + "type": "string" + }, + "virt_parent": { + "type": "string" + } + }, + "required": [ + "device_type", + "device_name", + "device_parent", + "virt_parent" + ] + }, + "i2c": { + "type": "object", + "properties": { + "topo_info": { + "type": "object", + "properties": { + "parent_bus": { + "type": "string" + }, + "dev_addr": { + "type": "string" + }, + "dev_type": { + "type": "string" + } + }, + "required": [ + "parent_bus", + "dev_addr", + "dev_type" + ] + }, + "attr_list": { + "type": "array", + "items": [ + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + }, + "attr_devaddr": { + "type": "string" + }, + "attr_devtype": { + "type": "string" + }, + "attr_offset": { + "type": "string" + }, + "attr_mask": { + "type": "string" + }, + "attr_cmpval": { + "type": "string" + }, + "attr_len": { + "type": "string" + } + }, + "required": [ + "attr_name", + "attr_devaddr", + "attr_devtype", + "attr_offset", + "attr_mask", + "attr_cmpval", + "attr_len" + ] + } + ] + } + }, + "required": [ + "topo_info", + "attr_list" + ] + } + }, + "required": [ + "dev_info", + "i2c" + ] + } + }, + "required": [ + "PSU-PMBUS" + ] +} diff --git a/platform/pddf/i2c/utils/schema/PSU.schema b/platform/pddf/i2c/utils/schema/PSU.schema new file mode 100644 index 0000000000..5ed53df457 --- /dev/null +++ b/platform/pddf/i2c/utils/schema/PSU.schema @@ -0,0 +1,81 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "PSU": { + "type": "object", + "properties": { + "dev_info": { + "type": "object", + "properties": { + "device_type": { + "type": "string" + }, + "device_name": { + "type": "string" + }, + "device_parent": { + "type": "string" + } + }, + "required": [ + "device_type", + "device_name", + "device_parent" + ] + }, + "dev_attr": { + "type": "object", + "properties": { + "dev_idx": { + "type": "string" + }, + "num_psu_fans": { + "type": "string" + } + }, + "required": [ + "dev_idx", + "num_psu_fans" + ] + }, + "i2c": { + "type": "object", + "properties": { + "interface": { + "type": "array", + "items": [ + { + "type": "object", + "properties": { + "itf": { + "type": "string" + }, + "dev": { + "type": "string" + } + }, + "required": [ + "itf", + "dev" + ] + } + ] + } + }, + "required": [ + "interface" + ] + } + }, + "required": [ + "dev_info", + "dev_attr", + "i2c" + ] + } + }, + "required": [ + "PSU" + ] +} diff --git a/platform/pddf/i2c/utils/schema/PSU_BMC.schema b/platform/pddf/i2c/utils/schema/PSU_BMC.schema new file mode 100644 index 0000000000..299e79dd78 --- /dev/null +++ b/platform/pddf/i2c/utils/schema/PSU_BMC.schema @@ -0,0 +1,336 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "PSU": { + "type": "object", + "properties": { + "dev_info": { + "type": "object", + "properties": { + "device_type": { + "type": "string" + } + }, + "required": [ + "device_type" + ] + }, + "dev_attr": { + "type": "object", + "properties": { + "dev_idx": { + "type": "string" + }, + "num_psu_fans": { + "type": "string" + } + }, + "required": [ + "dev_idx", + "num_psu_fans" + ] + }, + "bmc": { + "type": "object", + "properties": { + "ipmitool": { + "type": "object", + "properties": { + "attr_list": { + "type": "array", + "items": [ + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + }, + "bmc_cmd": { + "type": "string" + }, + "raw": { + "type": "string" + }, + "field_name": { + "type": "string" + }, + "field_pos": { + "type": "string" + } + }, + "required": [ + "attr_name", + "bmc_cmd", + "raw", + "field_name", + "field_pos" + ] + }, + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + }, + "bmc_cmd": { + "type": "string" + }, + "raw": { + "type": "string" + }, + "type": { + "type": "string" + }, + "mask": { + "type": "string" + } + }, + "required": [ + "attr_name", + "bmc_cmd", + "raw", + "type", + "mask" + ] + }, + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + }, + "bmc_cmd": { + "type": "string" + }, + "raw": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "attr_name", + "bmc_cmd", + "raw", + "type" + ] + }, + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + }, + "bmc_cmd": { + "type": "string" + }, + "raw": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "attr_name", + "bmc_cmd", + "raw", + "type" + ] + }, + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + }, + "bmc_cmd": { + "type": "string" + }, + "raw": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "attr_name", + "bmc_cmd", + "raw", + "type" + ] + }, + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + }, + "bmc_cmd": { + "type": "string" + }, + "raw": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "attr_name", + "bmc_cmd", + "raw", + "type" + ] + }, + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + }, + "bmc_cmd": { + "type": "string" + }, + "raw": { + "type": "string" + }, + "field_name": { + "type": "string" + }, + "field_pos": { + "type": "string" + }, + "mult": { + "type": "string" + } + }, + "required": [ + "attr_name", + "bmc_cmd", + "raw", + "field_name", + "field_pos", + "mult" + ] + }, + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + }, + "bmc_cmd": { + "type": "string" + }, + "raw": { + "type": "string" + }, + "field_name": { + "type": "string" + }, + "field_pos": { + "type": "string" + }, + "mult": { + "type": "string" + } + }, + "required": [ + "attr_name", + "bmc_cmd", + "raw", + "field_name", + "field_pos", + "mult" + ] + }, + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + }, + "bmc_cmd": { + "type": "string" + }, + "raw": { + "type": "string" + }, + "field_name": { + "type": "string" + }, + "field_pos": { + "type": "string" + }, + "mult": { + "type": "string" + } + }, + "required": [ + "attr_name", + "bmc_cmd", + "raw", + "field_name", + "field_pos", + "mult" + ] + }, + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + }, + "bmc_cmd": { + "type": "string" + }, + "raw": { + "type": "string" + }, + "field_name": { + "type": "string" + }, + "field_pos": { + "type": "string" + }, + "mult": { + "type": "string" + } + }, + "required": [ + "attr_name", + "bmc_cmd", + "raw", + "field_name", + "field_pos", + "mult" + ] + } + ] + } + }, + "required": [ + "attr_list" + ] + } + }, + "required": [ + "ipmitool" + ] + } + }, + "required": [ + "dev_info", + "dev_attr", + "bmc" + ] + } + }, + "required": [ + "PSU" + ] +} diff --git a/platform/pddf/i2c/utils/schema/QSFP.schema b/platform/pddf/i2c/utils/schema/QSFP.schema new file mode 100644 index 0000000000..be8e75a9cd --- /dev/null +++ b/platform/pddf/i2c/utils/schema/QSFP.schema @@ -0,0 +1,92 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "QSFP": { + "type": "object", + "properties": { + "dev_info": { + "type": "object", + "properties": { + "device_type": { + "type": "string" + }, + "device_name": { + "type": "string" + }, + "device_parent": { + "type": "string" + } + }, + "required": [ + "device_type", + "device_name", + "device_parent" + ] + }, + "dev_attr": { + "type": "object", + "properties": { + "dev_idx": { + "type": "string" + } + }, + "required": [ + "dev_idx" + ] + }, + "i2c": { + "type": "object", + "properties": { + "interface": { + "type": "array", + "items": [ + { + "type": "object", + "properties": { + "itf": { + "type": "string" + }, + "dev": { + "type": "string" + } + }, + "required": [ + "itf", + "dev" + ] + }, + { + "type": "object", + "properties": { + "itf": { + "type": "string" + }, + "dev": { + "type": "string" + } + }, + "required": [ + "itf", + "dev" + ] + } + ] + } + }, + "required": [ + "interface" + ] + } + }, + "required": [ + "dev_info", + "dev_attr", + "i2c" + ] + } + }, + "required": [ + "QSFP" + ] +} diff --git a/platform/pddf/i2c/utils/schema/SMBUS.schema b/platform/pddf/i2c/utils/schema/SMBUS.schema new file mode 100644 index 0000000000..91429a1d7e --- /dev/null +++ b/platform/pddf/i2c/utils/schema/SMBUS.schema @@ -0,0 +1,128 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "SMBUS": { + "type": "object", + "properties": { + "dev_info": { + "type": "object", + "properties": { + "device_type": { + "type": "string" + }, + "device_name": { + "type": "string" + }, + "device_parent": { + "type": "string" + } + }, + "required": [ + "device_type", + "device_name", + "device_parent" + ] + }, + "i2c": { + "type": "object", + "properties": { + "topo_info": { + "type": "object", + "properties": { + "dev_addr": { + "type": "string" + } + }, + "required": [ + "dev_addr" + ] + }, + "DEVICES": { + "type": "array", + "items": [ + { + "type": "object", + "properties": { + "dev": { + "type": "string" + } + }, + "required": [ + "dev" + ] + }, + { + "type": "object", + "properties": { + "dev": { + "type": "string" + } + }, + "required": [ + "dev" + ] + }, + { + "type": "object", + "properties": { + "dev": { + "type": "string" + } + }, + "required": [ + "dev" + ] + }, + { + "type": "object", + "properties": { + "dev": { + "type": "string" + } + }, + "required": [ + "dev" + ] + }, + { + "type": "object", + "properties": { + "dev": { + "type": "string" + } + }, + "required": [ + "dev" + ] + }, + { + "type": "object", + "properties": { + "dev": { + "type": "string" + } + }, + "required": [ + "dev" + ] + } + ] + } + }, + "required": [ + "topo_info", + "DEVICES" + ] + } + }, + "required": [ + "dev_info", + "i2c" + ] + } + }, + "required": [ + "SMBUS" + ] +} diff --git a/platform/pddf/i2c/utils/schema/SYSSTAT.schema b/platform/pddf/i2c/utils/schema/SYSSTAT.schema new file mode 100644 index 0000000000..d31e10c272 --- /dev/null +++ b/platform/pddf/i2c/utils/schema/SYSSTAT.schema @@ -0,0 +1,285 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "SYSSTAT": { + "type": "object", + "properties": { + "dev_info": { + "type": "object", + "properties": { + "device_type": { + "type": "string" + }, + "device_name": { + "type": "string" + } + }, + "required": [ + "device_type", + "device_name" + ] + }, + "dev_attr": { + "type": "object" + }, + "attr_list": { + "type": "array", + "items": [ + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + }, + "attr_devaddr": { + "type": "string" + }, + "attr_offset": { + "type": "string" + }, + "attr_mask": { + "type": "string" + }, + "attr_len": { + "type": "string" + } + }, + "required": [ + "attr_name", + "attr_devaddr", + "attr_offset", + "attr_mask", + "attr_len" + ] + }, + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + }, + "attr_devaddr": { + "type": "string" + }, + "attr_offset": { + "type": "string" + }, + "attr_mask": { + "type": "string" + }, + "attr_len": { + "type": "string" + } + }, + "required": [ + "attr_name", + "attr_devaddr", + "attr_offset", + "attr_mask", + "attr_len" + ] + }, + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + }, + "attr_devaddr": { + "type": "string" + }, + "attr_offset": { + "type": "string" + }, + "attr_mask": { + "type": "string" + }, + "attr_len": { + "type": "string" + } + }, + "required": [ + "attr_name", + "attr_devaddr", + "attr_offset", + "attr_mask", + "attr_len" + ] + }, + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + }, + "attr_devaddr": { + "type": "string" + }, + "attr_offset": { + "type": "string" + }, + "attr_mask": { + "type": "string" + }, + "attr_len": { + "type": "string" + } + }, + "required": [ + "attr_name", + "attr_devaddr", + "attr_offset", + "attr_mask", + "attr_len" + ] + }, + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + }, + "attr_devaddr": { + "type": "string" + }, + "attr_offset": { + "type": "string" + }, + "attr_mask": { + "type": "string" + }, + "attr_len": { + "type": "string" + } + }, + "required": [ + "attr_name", + "attr_devaddr", + "attr_offset", + "attr_mask", + "attr_len" + ] + }, + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + }, + "attr_devaddr": { + "type": "string" + }, + "attr_offset": { + "type": "string" + }, + "attr_mask": { + "type": "string" + }, + "attr_len": { + "type": "string" + } + }, + "required": [ + "attr_name", + "attr_devaddr", + "attr_offset", + "attr_mask", + "attr_len" + ] + }, + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + }, + "attr_devaddr": { + "type": "string" + }, + "attr_offset": { + "type": "string" + }, + "attr_mask": { + "type": "string" + }, + "attr_len": { + "type": "string" + } + }, + "required": [ + "attr_name", + "attr_devaddr", + "attr_offset", + "attr_mask", + "attr_len" + ] + }, + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + }, + "attr_devaddr": { + "type": "string" + }, + "attr_offset": { + "type": "string" + }, + "attr_mask": { + "type": "string" + }, + "attr_len": { + "type": "string" + } + }, + "required": [ + "attr_name", + "attr_devaddr", + "attr_offset", + "attr_mask", + "attr_len" + ] + }, + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + }, + "attr_devaddr": { + "type": "string" + }, + "attr_offset": { + "type": "string" + }, + "attr_mask": { + "type": "string" + }, + "attr_len": { + "type": "string" + } + }, + "required": [ + "attr_name", + "attr_devaddr", + "attr_offset", + "attr_mask", + "attr_len" + ] + } + ] + } + }, + "required": [ + "dev_info", + "dev_attr", + "attr_list" + ] + } + }, + "required": [ + "SYSSTAT" + ] +} diff --git a/platform/pddf/i2c/utils/schema/TEMP_SENSOR.schema b/platform/pddf/i2c/utils/schema/TEMP_SENSOR.schema new file mode 100644 index 0000000000..0bc2ce8b83 --- /dev/null +++ b/platform/pddf/i2c/utils/schema/TEMP_SENSOR.schema @@ -0,0 +1,102 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "TEMP_SENSOR": { + "type": "object", + "properties": { + "dev_info": { + "type": "object", + "properties": { + "device_type": { + "type": "string" + }, + "device_name": { + "type": "string" + }, + "device_parent": { + "type": "string" + } + }, + "required": [ + "device_type", + "device_parent" + ] + }, + "i2c": { + "type": "object", + "properties": { + "topo_info": { + "type": "object", + "properties": { + "parent_bus": { + "type": "string" + }, + "dev_addr": { + "type": "string" + }, + "dev_type": { + "type": "string" + } + }, + "required": [ + "parent_bus", + "dev_addr", + "dev_type" + ] + }, + "attr_list": { + "type": "array", + "items": [ + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + } + }, + "required": [ + "attr_name" + ] + }, + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + } + }, + "required": [ + "attr_name" + ] + }, + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + } + }, + "required": [ + "attr_name" + ] + } + ] + } + }, + "required": [ + "topo_info", + "attr_list" + ] + } + }, + "required": [ + "dev_info", + "i2c" + ] + } + }, + "required": [ + "TEMP_SENSOR" + ] +} diff --git a/platform/pddf/i2c/utils/schema/TEMP_SENSOR_BMC.schema b/platform/pddf/i2c/utils/schema/TEMP_SENSOR_BMC.schema new file mode 100644 index 0000000000..c8f7c447b7 --- /dev/null +++ b/platform/pddf/i2c/utils/schema/TEMP_SENSOR_BMC.schema @@ -0,0 +1,143 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "TEMP_SENSOR": { + "type": "object", + "properties": { + "dev_info": { + "type": "object", + "properties": { + "device_type": { + "type": "string" + } + }, + "required": [ + "device_type" + ] + }, + "dev_attr": { + "type": "object", + "properties": { + "display_name": { + "type": "string" + } + }, + "required": [ + "display_name" + ] + }, + "bmc": { + "type": "object", + "properties": { + "ipmitool": { + "type": "object", + "properties": { + "attr_list": { + "type": "array", + "items": [ + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + }, + "bmc_cmd": { + "type": "string" + }, + "raw": { + "type": "string" + }, + "field_name": { + "type": "string" + }, + "field_pos": { + "type": "string" + } + }, + "required": [ + "attr_name", + "bmc_cmd", + "raw", + "field_name", + "field_pos" + ] + }, + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + }, + "bmc_cmd": { + "type": "string" + }, + "raw": { + "type": "string" + }, + "field_name": { + "type": "string" + }, + "field_pos": { + "type": "string" + } + }, + "required": [ + "attr_name", + "bmc_cmd", + "raw", + "field_name", + "field_pos" + ] + }, + { + "type": "object", + "properties": { + "attr_name": { + "type": "string" + }, + "bmc_cmd": { + "type": "string" + }, + "raw": { + "type": "string" + }, + "field_name": { + "type": "string" + }, + "field_pos": { + "type": "string" + } + }, + "required": [ + "attr_name", + "bmc_cmd", + "raw", + "field_name", + "field_pos" + ] + } + ] + } + }, + "required": [ + "attr_list" + ] + } + }, + "required": [ + "ipmitool" + ] + } + }, + "required": [ + "dev_info", + "dev_attr", + "bmc" + ] + } + }, + "required": [ + "TEMP_SENSOR" + ] +} diff --git a/platform/pddf/platform-api-pddf-base.dep b/platform/pddf/platform-api-pddf-base.dep new file mode 100644 index 0000000000..9184925b1e --- /dev/null +++ b/platform/pddf/platform-api-pddf-base.dep @@ -0,0 +1,9 @@ + +MPATH := $($(PDDF_PLATFORM_API_BASE_PY2)_SRC_PATH) +DEP_FILES := $(SONIC_COMMON_FILES_LIST) platform/pddf/platform-api-pddf-base.mk platform/pddf/platform-api-pddf-base.dep +DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST) +DEP_FILES += $(shell git ls-files $(MPATH)) + +$(PDDF_PLATFORM_API_BASE_PY2)_CACHE_MODE := GIT_CONTENT_SHA +$(PDDF_PLATFORM_API_BASE_PY2)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST) +$(PDDF_PLATFORM_API_BASE_PY2)_DEP_FILES := $(DEP_FILES) diff --git a/platform/pddf/platform-api-pddf-base.mk b/platform/pddf/platform-api-pddf-base.mk new file mode 100644 index 0000000000..80478d4f3d --- /dev/null +++ b/platform/pddf/platform-api-pddf-base.mk @@ -0,0 +1,15 @@ +#################################################### +# PDDF Generic 2.0 Platform API base classes +#################################################### +PDDF_PLATFORM_API_BASE_VERSION = 1.0 + +export PDDF_PLATFORM_API_BASE_VERSION + +PDDF_PLATFORM_API_BASE_PY2 = sonic_platform_pddf_common-$(PDDF_PLATFORM_API_BASE_VERSION)-py2-none-any.whl +$(PDDF_PLATFORM_API_BASE_PY2)_SRC_PATH = $(PLATFORM_PDDF_PATH)/platform-api-pddf-base +$(PDDF_PLATFORM_API_BASE_PY2)_PYTHON_VERSION = 2 +$(PDDF_PLATFORM_API_BASE_PY2)_DEPENDS = $(SONIC_CONFIG_ENGINE) +SONIC_PYTHON_WHEELS += $(PDDF_PLATFORM_API_BASE_PY2) + +export pddf_platform_api_base_py2_wheel_path="$(addprefix $(PYTHON_WHEELS_PATH)/,$(PDDF_PLATFORM_API_BASE_PY2))" +export PDDF_PLATFORM_API_BASE_PY2 diff --git a/platform/pddf/platform-api-pddf-base/setup.py b/platform/pddf/platform-api-pddf-base/setup.py new file mode 100755 index 0000000000..5f5ac9194c --- /dev/null +++ b/platform/pddf/platform-api-pddf-base/setup.py @@ -0,0 +1,30 @@ + +from setuptools import setup + +setup( + name='sonic-platform-pddf-common', + version='1.0', + description='SONIC platform APIs base (2.0) implementation on PDDF supported platforms', + license='Apache 2.0', + author='SONiC Team', + author_email='linuxnetdev@microsoft.com', + url='https://github.com/Azure/sonic-buildimage', + maintainer='Fuzail Khan', + maintainer_email='fuzail.khan@broadcom.com', + packages=[ + 'sonic_platform_pddf_base', + ], + 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 :: 2.7', + 'Topic :: Utilities', + ], + keywords='sonic SONiC platform PLATFORM', +) diff --git a/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/__init__.py b/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_chassis.py b/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_chassis.py new file mode 100755 index 0000000000..942be25ed1 --- /dev/null +++ b/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_chassis.py @@ -0,0 +1,516 @@ +#!/usr/bin/env python + +############################################################################# +# PDDF +# Module contains an implementation of SONiC Platform Base API and +# provides the platform information +# +############################################################################# + +try: + import sys + from sonic_platform_base.chassis_base import ChassisBase + from sonic_platform.sfp import Sfp + from sonic_platform.psu import Psu + from sonic_platform.fan import Fan + from sonic_platform.thermal import Thermal + from sonic_platform.eeprom import Eeprom +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +class PddfChassis(ChassisBase): + """ + PDDF Generic Chassis class + """ + pddf_obj = {} + plugin_data = {} + + def __init__(self, pddf_data=None, pddf_plugin_data=None): + + ChassisBase.__init__(self) + + self.pddf_obj = pddf_data if pddf_data else None + self.plugin_data = pddf_plugin_data if pddf_plugin_data else None + if not self.pddf_obj or not self.plugin_data: + try: + import pddfparse + import json + self.pddf_obj = pddfparse.PddfParse() + with open('/usr/share/sonic/platform/pddf/pd-plugin.json') as pd: + self.plugin_data = json.load(pd) + except Exception as e: + raise Exception("Error: Unable to load PDDF JSON data - %s" % str(e)) + + self.platform_inventory = self.pddf_obj.get_platform() + + # Initialize EEPROM + self.sys_eeprom = Eeprom(self.pddf_obj, self.plugin_data) + + # FANs + for i in range(self.platform_inventory['num_fantrays']): + for j in range(self.platform_inventory['num_fans_pertray']): + fan = Fan(i, j, self.pddf_obj, self.plugin_data) + self._fan_list.append(fan) + + # PSUs + for i in range(self.platform_inventory['num_psus']): + psu = Psu(i, self.pddf_obj, self.plugin_data) + self._psu_list.append(psu) + + # OPTICs + for index in range(self.platform_inventory['num_ports']): + sfp = Sfp(index, self.pddf_obj, self.plugin_data) + self._sfp_list.append(sfp) + + # THERMALs + for i in range(self.platform_inventory['num_temps']): + thermal = Thermal(i, self.pddf_obj, self.plugin_data) + self._thermal_list.append(thermal) + + # SYSTEM LED Test Cases + """ + #comment out test cases + sys_led_list= { "LOC":0, + "DIAG":0, + "FAN":0, + "SYS":0, + "PSU1":0, + "PSU2":1 + } + + for led in sys_led_list: + color=self.get_system_led(led, sys_led_list[led]) + print color + + self.set_system_led("LOC_LED","STATUS_LED_COLOR_GREEN") + color=self.get_system_led("LOC_LED") + print "Set Green: " + color + self.set_system_led("LOC_LED", "STATUS_LED_COLOR_OFF") + color=self.get_system_led("LOC_LED") + print "Set off: " + color + """ + + + + def get_name(self): + """ + Retrieves the name of the chassis + Returns: + string: The name of the chassis + """ + return self.sys_eeprom.modelstr() + + def get_presence(self): + """ + Retrieves the presence of the chassis + Returns: + bool: True if chassis is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the chassis + Returns: + string: Model/part number of chassis + """ + return self.sys_eeprom.part_number_str() + + def get_serial(self): + """ + Retrieves the serial number of the chassis (Service tag) + Returns: + string: Serial number of chassis + """ + return self.sys_eeprom.serial_str() + + def get_status(self): + """ + Retrieves the operational status of the chassis + Returns: + bool: A boolean value, True if chassis is operating properly + False if not + """ + return True + + 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' + """ + return self.sys_eeprom.base_mac_addr() + + def get_serial_number(self): + """ + Retrieves the hardware serial number for the chassis + + Returns: + A string containing the hardware serial number for this + chassis. + """ + return self.sys_eeprom.serial_number_str() + + def get_system_eeprom_info(self): + """ + Retrieves the full content of system EEPROM information for the chassis + Returns: + A dictionary where keys are the type code defined in + OCP ONIE TlvInfo EEPROM format and values are their corresponding + values. + """ + return self.sys_eeprom.system_eeprom_info() + + def get_reboot_cause(self): + """ + Retrieves the cause of the previous reboot + + Returns: + A tuple (string, string) where the first element is a string + containing the cause of the previous reboot. This string must be + 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. + """ + raise NotImplementedError + + def get_component_name_list(self): + """ + Retrieves a list of the names of components available on the chassis (e.g., BIOS, CPLD, FPGA, etc.) + + Returns: + A list containing the names of components available on the chassis + """ + return self._component_name_list + + def get_firmware_version(self, component_name): + """ + Retrieves platform-specific hardware/firmware versions for chassis + componenets such as BIOS, CPLD, FPGA, etc. + Args: + component_name: A string, the component name. + + Returns: + A string containing platform-specific component versions + """ + raise NotImplementedError + + def install_component_firmware(self, component_name, image_path): + """ + Install firmware to component + Args: + component_name: A string, the component name. + image_path: A string, path to firmware image. + + Returns: + A boolean, True if install was successful, False if not + """ + raise NotImplementedError + + ############################################## + # Module methods + ############################################## + + def get_num_modules(self): + """ + Retrieves the number of modules available on this chassis + + Returns: + An integer, the number of modules available on this chassis + """ + return len(self._module_list) + + def get_all_modules(self): + """ + Retrieves all modules available on this chassis + + Returns: + A list of objects derived from ModuleBase representing all + modules available on this chassis + """ + return self._module_list + + def get_module(self, index): + """ + Retrieves module represented by (0-based) index + + Args: + index: An integer, the index (0-based) of the module to + retrieve + + Returns: + An object dervied from ModuleBase representing the specified + module + """ + module = None + + try: + module = self._module_list[index] + except IndexError: + sys.stderr.write("Module index {} out of range (0-{})\n".format( + index, len(self._module_list)-1)) + + return module + ############################################## + # Fan methods + ############################################## + + def get_num_fans(self): + """ + Retrieves the number of fans available on this chassis + + Returns: + An integer, the number of fan modules available on this chassis + """ + return len(self._fan_list) + + def get_all_fans(self): + """ + Retrieves all fan modules available on this chassis + + Returns: + A list of objects derived from FanBase representing all fan + modules available on this chassis + """ + return self._fan_list + + def get_fan(self, index): + """ + Retrieves fan module represented by (0-based) index + + Args: + index: An integer, the index (0-based) of the fan module to + retrieve + + Returns: + An object dervied from FanBase representing the specified fan + module + """ + fan = None + + try: + fan = self._fan_list[index] + except IndexError: + sys.stderr.write("Fan index {} out of range (0-{})\n".format( + index, len(self._fan_list)-1)) + + return fan + + ############################################## + # PSU methods + ############################################## + + def get_num_psus(self): + """ + Retrieves the number of power supply units available on this chassis + + Returns: + An integer, the number of power supply units available on this + chassis + """ + return len(self._psu_list) + + def get_all_psus(self): + """ + Retrieves all power supply units available on this chassis + + Returns: + A list of objects derived from PsuBase representing all power + supply units available on this chassis + """ + return self._psu_list + + def get_psu(self, index): + """ + Retrieves power supply unit represented by (0-based) index + + Args: + index: An integer, the index (0-based) of the power supply unit to + retrieve + + Returns: + An object dervied from PsuBase representing the specified power + supply unit + """ + psu = None + + try: + psu = self._psu_list[index] + except IndexError: + sys.stderr.write("PSU index {} out of range (0-{})\n".format( + index, len(self._psu_list)-1)) + + return psu + + ############################################## + # THERMAL methods + ############################################## + + def get_num_thermals(self): + """ + Retrieves the number of thermals available on this chassis + + Returns: + An integer, the number of thermals available on this chassis + """ + return len(self._thermal_list) + + def get_all_thermals(self): + """ + Retrieves all thermals available on this chassis + + Returns: + A list of objects derived from ThermalBase representing all thermals + available on this chassis + """ + return self._thermal_list + + def get_thermal(self, index): + """ + Retrieves thermal unit represented by (0-based) index + + Args: + index: An integer, the index (0-based) of the thermal to + retrieve + + Returns: + An object dervied from ThermalBase representing the specified thermal + """ + thermal = None + + try: + thermal = self._thermal_list[index] + except IndexError: + sys.stderr.write("THERMAL index {} out of range (0-{})\n".format( + index, len(self._thermal_list)-1)) + + return thermal + + ############################################## + # SFP methods + ############################################## + + def get_num_sfps(self): + """ + Retrieves the number of sfps available on this chassis + + Returns: + An integer, the number of sfps available on this chassis + """ + return len(self._sfp_list) + + def get_all_sfps(self): + """ + Retrieves all sfps available on this chassis + + Returns: + A list of objects derived from SfpBase representing all sfps + available on this chassis + """ + return self._sfp_list + + def get_sfp(self, index): + """ + Retrieves sfp represented by (0-based) index + + Args: + index: An integer, the index (0-based) of the sfp to retrieve. + The index should be the sequence of a physical port in a chassis, + starting from 0. + For example, 0 for Ethernet0, 1 for Ethernet4 and so on. + + Returns: + An object dervied from SfpBase representing the specified sfp + """ + sfp = None + + try: + sfp = self._sfp_list[index] + except IndexError: + sys.stderr.write("SFP index {} out of range (0-{})\n".format( + index, len(self._sfp_list)-1)) + + return sfp + + ############################################## + # System LED methods + ############################################## + def set_system_led(self, led_device_name, color): + result, msg = self.pddf_obj.is_supported_sysled_state(led_device_name, color); + if result == False: + print msg + return (False) + + index=self.pddf_obj.data[led_device_name]['dev_attr']['index'] + device_name=self.pddf_obj.data[led_device_name]['dev_info']['device_name'] + self.pddf_obj.create_attr('device_name', device_name, self.pddf_obj.get_led_path()) + self.pddf_obj.create_attr('index', index, self.pddf_obj.get_led_path()) + self.pddf_obj.create_attr('color', color, self.pddf_obj.get_led_cur_state_path()) + self.pddf_obj.create_attr('dev_ops', 'set_status', self.pddf_obj.get_led_path()) + return (True) + + + def get_system_led(self, led_device_name): + if (not led_device_name in self.pddf_obj.data.keys()): + status= "[FAILED] " + led_device_name + " is not configured" + return (status) + + index=self.pddf_obj.data[led_device_name]['dev_attr']['index'] + device_name=self.pddf_obj.data[led_device_name]['dev_info']['device_name'] + self.pddf_obj.create_attr('device_name', device_name, self.pddf_obj.get_led_path()) + self.pddf_obj.create_attr('index', index, self.pddf_obj.get_led_path()) + self.pddf_obj.create_attr('dev_ops', 'get_status', self.pddf_obj.get_led_path()) + color=self.pddf_obj.get_led_color() + return (color) + + + ############################################## + # Other methods + ############################################## + + def get_watchdog(self): + """ + Retreives hardware watchdog device on this chassis + + Returns: + An object derived from WatchdogBase representing the hardware + watchdog device + """ + return self._watchdog + + def get_eeprom(self): + """ + Retreives eeprom device on this chassis + + Returns: + An object derived from WatchdogBase representing the hardware + eeprom device + """ + return self.sys_eeprom + + def get_change_event(self, timeout=0): + """ + Returns a nested dictionary containing all devices which have + experienced a change at chassis level + + Args: + timeout: Timeout in milliseconds (optional). If timeout == 0, + this method will block until a change is detected. + Returns: + (bool, dict): + - True if call successful, False if not; + - A nested dictionary where key is a device type, + value is a dictionary with key:value pairs in the format of + {'device_id':'device_event'}, + where device_id is the device ID for this device and + device_event, + status='1' represents device inserted, + status='0' represents device removed. + Ex. {'fan':{'0':'0', '2':'1'}, 'sfp':{'11':'0'}} + indicates that fan 0 has been removed, fan 2 + has been inserted and sfp 11 has been removed. + """ + raise NotImplementedError + diff --git a/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_eeprom.py b/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_eeprom.py new file mode 100644 index 0000000000..95ca7b5746 --- /dev/null +++ b/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_eeprom.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python + +############################################################################# +# PDDF +# +# PDDF syseeprom base class inherited from the base class +############################################################################# + +try: + from sonic_eeprom import eeprom_tlvinfo + import binascii +except ImportError, e: + raise ImportError(str(e) + "- required module not found") + + +class PddfEeprom(eeprom_tlvinfo.TlvInfoDecoder): + _TLV_INFO_MAX_LEN = 256 + pddf_obj = {} + plugin_data = {} + + def __init__(self, pddf_data=None, pddf_plugin_data=None): + if not pddf_data or not pddf_plugin_data: + raise ValueError('PDDF JSON data error') + + self.pddf_obj = pddf_data + self.plugin_data = pddf_plugin_data + + # system EEPROM always has device name EEPROM1 + self.eeprom_path = self.pddf_obj.get_path("EEPROM1", "eeprom") + if self.eeprom_path is None: + return + + super(PddfEeprom, self).__init__(self.eeprom_path, 0, '', True) + self.eeprom_tlv_dict = dict() + try: + self.eeprom_data = self.read_eeprom() + except: + self.eeprom_data = "N/A" + raise RuntimeError("PddfEeprom is not Programmed") + else: + eeprom = self.eeprom_data + + if not self.is_valid_tlvinfo_header(eeprom): + return + + total_length = (ord(eeprom[9]) << 8) | ord(eeprom[10]) + tlv_index = self._TLV_INFO_HDR_LEN + tlv_end = self._TLV_INFO_HDR_LEN + total_length + + while (tlv_index + 2) < len(eeprom) and tlv_index < tlv_end: + if not self.is_valid_tlv(eeprom[tlv_index:]): + break + + tlv = eeprom[tlv_index:tlv_index + 2 + + ord(eeprom[tlv_index + 1])] + code = "0x%02X" % (ord(tlv[0])) + + if ord(tlv[0]) == self._TLV_CODE_VENDOR_EXT: + value = str((ord(tlv[2]) << 24) | (ord(tlv[3]) << 16) | + (ord(tlv[4]) << 8) | ord(tlv[5])) + value += str(tlv[6:6 + ord(tlv[1])]) + else: + name, value = self.decoder(None, tlv) + + self.eeprom_tlv_dict[code] = value + if ord(eeprom[tlv_index]) == self._TLV_CODE_CRC_32: + break + + tlv_index += ord(eeprom[tlv_index+1]) + 2 + + def serial_number_str(self): + (is_valid, results) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_SERIAL_NUMBER) + if not is_valid: + return "N/A" + return results[2] + + def base_mac_addr(self): + (is_valid, t) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_MAC_BASE) + if not is_valid or t[1] != 6: + return super(TlvInfoDecoder, self).switchaddrstr(e) + + return ":".join([binascii.b2a_hex(T) for T in t[2]]) + + def modelstr(self): + (is_valid, results) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_PRODUCT_NAME) + if not is_valid: + return "N/A" + + return results[2] + + def part_number_str(self): + (is_valid, results) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_PART_NUMBER) + if not is_valid: + return "N/A" + + return results[2] + + def serial_str(self): + (is_valid, results) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_SERVICE_TAG) + if not is_valid: + return "N/A" + + return results[2] + + def revision_str(self): + (is_valid, results) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_DEVICE_VERSION) + if not is_valid: + return "N/A" + + return results[2] + + def system_eeprom_info(self): + """ + Returns a dictionary, where keys are the type code defined in + ONIE EEPROM format and values are their corresponding values + found in the system EEPROM. + """ + return self.eeprom_tlv_dict diff --git a/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_fan.py b/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_fan.py new file mode 100755 index 0000000000..f189ca2a4e --- /dev/null +++ b/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_fan.py @@ -0,0 +1,332 @@ +#!/usr/bin/env python + +# All the supported FAN SysFS aattributes are +#- fan_present +#- fan_direction +#- fan_input +#- fan_pwm +#- fan_fault +# where idx is in the range [1-32] +# + +try: + from sonic_platform_base.fan_base import FanBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class PddfFan(FanBase): + """PDDF generic Fan class""" + + pddf_obj = {} + plugin_data = {} + + 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 + if not pddf_data or not pddf_plugin_data: + raise ValueError('PDDF JSON data error') + + self.pddf_obj = pddf_data + self.plugin_data = pddf_plugin_data + self.platform = self.pddf_obj.get_platform() + + if tray_idx<0 or tray_idx>=self.platform['num_fantrays']: + print "Invalid fantray index %d\n"%tray_idx + return + + if fan_idx<0 or fan_idx>=self.platform['num_fans_pertray']: + print "Invalid fan index (within a tray) %d\n"%fan_idx + return + + self.fantray_index = tray_idx+1 + self.fan_index = fan_idx+1 + self.is_psu_fan = is_psu_fan + if self.is_psu_fan: + self.fans_psu_index = psu_index + + def get_name(self): + """ + Retrieves the fan name + Returns: String containing fan-name + """ + if self.is_psu_fan: + return "PSU{}_FAN{}".format(self.fans_psu_index, self.fan_index) + else: + if 'name' in self.plugin_data['FAN']: + return self.plugin_data['FAN']['name'][str(self.fantray_index)] + else: + return "Fantray{}_{}".format(self.fantray_index, self.fan_index) + + def get_presence(self): + if self.is_psu_fan: + return True + else: + idx = (self.fantray_index-1)*self.platform['num_fans_pertray'] + self.fan_index + attr_name = "fan" + str(idx) + "_present" + output = self.pddf_obj.get_attr_name_output("FAN-CTRL", attr_name) + if not output: + return False + + mode = output['mode'] + presence = output['status'].rstrip() + + vmap = self.plugin_data['FAN']['present'][mode]['valmap'] + + if presence in vmap: + status = vmap[presence] + else: + status = False + + return status + + def get_status(self): + speed = self.get_speed() + status = True if (speed != 0) else False + return status + + def get_direction(self): + """ + Retrieves the direction of fan + + Returns: + A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST + depending on fan direction + """ + if self.is_psu_fan: + device = "PSU{}".format(self.fans_psu_index) + output = self.pddf_obj.get_attr_name_output(device, "psu_fan_dir") + if not output: + return False + + mode = output['mode'] + val = output['status'] + + val = val.rstrip() + vmap = self.plugin_data['PSU']['psu_fan_dir'][mode]['valmap'] + + if val in vmap: + direction = vmap[val] + else: + direction = val + + else: + idx = (self.fantray_index-1)*self.platform['num_fans_pertray'] + self.fan_index + attr = "fan" + str(idx) + "_direction" + output = self.pddf_obj.get_attr_name_output("FAN-CTRL", attr) + if not output: + return False + + mode = output['mode'] + val = output['status'] + + val = val.rstrip() + vmap = self.plugin_data['FAN']['direction'][mode]['valmap'] + if val in vmap: + direction = vmap[val] + else: + direction = val + + return direction + + def get_speed(self): + """ + Retrieves the speed of fan as a percentage of full speed + + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + """ + if self.is_psu_fan: + attr = "psu_fan{}_speed_rpm".format(self.fan_index) + device = "PSU{}".format(self.fans_psu_index) + output = self.pddf_obj.get_attr_name_output(device, attr) + if not output: + return 0 + + output['status'] = output['status'].rstrip() + if output['status'].isalpha(): + return 0 + else: + speed = int(output['status']) + + max_speed = int(self.plugin_data['PSU']['PSU_FAN_MAX_SPEED']) + speed_percentage = (speed*100)/max_speed + return speed_percentage + else: + # TODO This calculation should change based on MAX FAN SPEED + idx = (self.fantray_index-1)*self.platform['num_fans_pertray'] + self.fan_index + attr = "fan" + str(idx) + "_pwm" + output = self.pddf_obj.get_attr_name_output("FAN-CTRL", attr) + + if not output: + return 0 + + output['status'] = output['status'].rstrip() + if output['status'].isalpha(): + return 0 + else: + fpwm = int(output['status']) + + pwm_to_dc = eval(self.plugin_data['FAN']['pwm_to_duty_cycle']) + speed_percentage = int(round(pwm_to_dc(fpwm))) + + return speed_percentage + + def get_speed_rpm(self): + """ + Retrieves the speed of fan in RPM + + Returns: + An integer, Speed of fan in RPM + """ + if self.is_psu_fan: + attr = "psu_fan{}_speed_rpm".format(self.fan_index) + device = "PSU{}".format(self.fans_psu_index) + output = self.pddf_obj.get_attr_name_output(device, attr) + if not output: + return 0 + + output['status'] = output['status'].rstrip() + if output['status'].isalpha(): + return 0 + else: + speed = int(float(output['status'])) + + rpm_speed = speed + return rpm_speed + else: + idx = (self.fantray_index-1)*self.platform['num_fans_pertray'] + self.fan_index + attr = "fan" + str(idx) + "_input" + output = self.pddf_obj.get_attr_name_output("FAN-CTRL", attr) + + if output is None: + return 0 + + output['status'] = output['status'].rstrip() + if output['status'].isalpha(): + return 0 + else: + rpm_speed = int(float(output['status'])) + + return rpm_speed + + def get_target_speed(self): + """ + Retrieves the target (expected) speed of the fan + + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + """ + target_speed = 0 + if self.is_psu_fan: + # Target speed not usually supported for PSU fans + target_speed = 0 + else: + idx = (self.fantray_index-1)*self.platform['num_fans_pertray'] + self.fan_index + attr = "fan" + str(idx) + "_pwm" + output = self.pddf_obj.get_attr_name_output("FAN-CTRL", attr) + + if not output: + return 0 + + output['status'] = output['status'].rstrip() + if output['status'].isalpha(): + return 0 + else: + fpwm = int(output['status']) + + pwm_to_dc = eval(self.plugin_data['FAN']['pwm_to_duty_cycle']) + speed_percentage = int(round(pwm_to_dc(fpwm))) + target_speed = speed_percentage + + return target_speed + + 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 + """ + # Fix the speed vairance to 10 percent. If it changes based on platforms, overwrite + # this value in derived pddf fan class + return 10 + + def set_speed(self, speed): + """ + Sets the fan speed + + Args: + speed: An integer, the percentage of full fan speed to set fan to, + in the range 0 (off) to 100 (full speed) + + Returns: + A boolean, True if speed is set successfully, False if not + """ + if self.is_psu_fan: + print "Setting PSU fan speed is not allowed" + return False + else: + if speed<0 or speed>100: + print "Error: Invalid speed %d. Please provide a valid speed percentage"%speed + return False + + if 'duty_cycle_to_pwm' not in self.plugin_data['FAN']: + print "Setting fan speed is not allowed !" + return False + else: + duty_cycle_to_pwm = eval(self.plugin_data['FAN']['duty_cycle_to_pwm']) + pwm = int(round(duty_cycle_to_pwm(speed))) + + + status = False + idx = (self.fantray_index-1)*self.platform['num_fans_pertray'] + self.fan_index + attr = "fan" + str(idx) + "_pwm" + output = self.pddf_obj.set_attr_name_output("FAN-CTRL", attr, pwm) + if not output: + return False + + status = output['status'] + + return status + + def set_status_led(self, color): + index = str(self.fantray_index-1) + led_device_name = "FANTRAY{}".format(self.fantray_index) + "_LED" + + result, msg = self.pddf_obj.is_supported_sysled_state(led_device_name, color); + if result == False: + print msg + return (False) + + + device_name=self.pddf_obj.data[led_device_name]['dev_info']['device_name'] + self.pddf_obj.create_attr('device_name', device_name, self.pddf_obj.get_led_path()) + self.pddf_obj.create_attr('index', index, self.pddf_obj.get_led_path()) + self.pddf_obj.create_attr('color', color, self.pddf_obj.get_led_cur_state_path()) + self.pddf_obj.create_attr('dev_ops', 'set_status', self.pddf_obj.get_led_path()) + return (True) + + + def get_status_led(self): + index = str(self.fantray_index-1) + fan_led_device = "FANTRAY{}".format(self.fantray_index) + "_LED" + + if (not fan_led_device in self.pddf_obj.data.keys()): + # Implement a generic status_led color scheme + if self.get_status(): + return self.STATUS_LED_COLOR_GREEN + else: + return self.STATUS_LED_COLOR_OFF + + device_name=self.pddf_obj.data[fan_led_device]['dev_info']['device_name'] + self.pddf_obj.create_attr('device_name', device_name, self.pddf_obj.get_led_path()) + self.pddf_obj.create_attr('index', index, self.pddf_obj.get_led_path()) + self.pddf_obj.create_attr('dev_ops', 'get_status', self.pddf_obj.get_led_path()) + color=self.pddf_obj.get_led_color() + return (color) + + def dump_sysfs(self): + return self.pddf_obj.cli_dump_dsysfs('fan') diff --git a/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_platform.py b/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_platform.py new file mode 100755 index 0000000000..20b87db999 --- /dev/null +++ b/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_platform.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python + +############################################################################# +# PDDF +# Module contains an implementation of SONiC Platform API and +# provides the platform information +# +############################################################################# + + +try: + import json + import pddfparse + 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 PddfPlatform(PlatformBase): + """ + PDDF Generic Platform class + """ + pddf_data = {} + pddf_plugin_data = {} + def __init__(self): + # Initialize the JSON data + self.pddf_data = pddfparse.PddfParse() + with open('/usr/share/sonic/platform/pddf/pd-plugin.json') as pd: + self.pddf_plugin_data = json.load(pd) + + if not self.pddf_data or not self.pddf_plugin_data: + print "Error: PDDF JSON data is not loaded properly ... Exiting" + raise ValueError + + PlatformBase.__init__(self) + self._chassis = Chassis(self.pddf_data, self.pddf_plugin_data) diff --git a/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_psu.py b/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_psu.py new file mode 100755 index 0000000000..b378be7dad --- /dev/null +++ b/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_psu.py @@ -0,0 +1,298 @@ +#!/usr/bin/env python +# +# All the supported PSU SysFS aattributes are +#- psu_present +#- psu_model_name +#- psu_power_good +#- psu_mfr_id +#- psu_serial_num +#- psu_fan_dir +#- psu_v_out +#- psu_i_out +#- psu_p_out +#- psu_fan1_speed_rpm +# + + +try: + from sonic_platform_base.psu_base import PsuBase + from sonic_platform.fan import Fan +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + + +class PddfPsu(PsuBase): + """PDDF generic PSU class""" + + pddf_obj = {} + plugin_data = {} + + + def __init__(self, index, pddf_data=None, pddf_plugin_data=None): + PsuBase.__init__(self) + if not pddf_data or not pddf_plugin_data: + raise ValueError('PDDF JSON data error') + + self.pddf_obj = pddf_data + self.plugin_data = pddf_plugin_data + self.platform = self.pddf_obj.get_platform() + self.psu_index = index + 1 + + self._fan_list = [] # _fan_list under PsuBase class is a global variable, hence we need to use _fan_list per class instatiation + self.num_psu_fans = int(self.pddf_obj.get_num_psu_fans('PSU{}'.format(index+1))) + for psu_fan_idx in range(self.num_psu_fans): + psu_fan = Fan(0, psu_fan_idx, pddf_data, pddf_plugin_data, True, self.psu_index) + self._fan_list.append(psu_fan) + + def get_num_fans(self): + """ + Retrieves the number of fan modules available on this PSU + + Returns: + An integer, the number of fan modules available on this PSU + """ + return len(self._fan_list) + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + if 'name' in self.plugin_data['PSU']: + return self.plugin_data['PSU']['name'][str(self.psu_index)] + else: + return "PSU{}".format(self.psu_index) + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + status = 0 + device = "PSU{}".format(self.psu_index) + output = self.pddf_obj.get_attr_name_output(device, "psu_present") + if not output: + return False + + mode = output['mode'] + status = output['status'] + + vmap = self.plugin_data['PSU']['psu_present'][mode]['valmap'] + + if status.rstrip('\n') in vmap: + return vmap[status.rstrip('\n')] + else: + return False + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + + Returns: + string: Model/part number of device + """ + device = "PSU{}".format(self.psu_index) + output = self.pddf_obj.get_attr_name_output(device, "psu_model_name") + if not output: + return None + + model = output['status'] + + # strip_non_ascii + stripped = (c for c in model if 0 < ord(c) < 127) + model = ''.join(stripped) + + return model.rstrip('\n') + + def get_serial(self): + """ + Retrieves the serial number of the device + + Returns: + string: Serial number of device + """ + device = "PSU{}".format(self.psu_index) + output = self.pddf_obj.get_attr_name_output(device, "psu_serial_num") + if not output: + return None + + serial = output['status'] + + return serial.rstrip('\n') + + def get_status(self): + """ + Retrieves the operational status of the device + + Returns: + A boolean value, True if device is operating properly, False if not + """ + device = "PSU{}".format(self.psu_index) + + output = self.pddf_obj.get_attr_name_output(device, "psu_power_good") + if not output: + return False + + mode = output['mode'] + status = output ['status'] + + vmap = self.plugin_data['PSU']['psu_power_good'][mode]['valmap'] + + if status.rstrip('\n') in vmap: + return vmap[status.rstrip('\n')] + else: + return False + + def get_mfr_id(self): + """ + Retrieves the manufacturer id of the device + + Returns: + string: Manufacturer Id of device + """ + device = "PSU{}".format(self.psu_index) + output = self.pddf_obj.get_attr_name_output(device, "psu_mfr_id") + if not output: + return None + + mfr = output['status'] + + return mfr.rstrip('\n') + + def get_voltage(self): + """ + Retrieves current PSU voltage output + + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + device = "PSU{}".format(self.psu_index) + output = self.pddf_obj.get_attr_name_output(device, "psu_v_out") + if not output: + return 0.0 + + v_out = output['status'] + + return float(v_out)/1000 + + def get_current(self): + """ + Retrieves present electric current supplied by PSU + + Returns: + A float number, electric current in amperes, + e.g. 15.4 + """ + device = "PSU{}".format(self.psu_index) + output = self.pddf_obj.get_attr_name_output(device, "psu_i_out") + if not output: + return 0.0 + + i_out = output['status'] + + # current in mA + return float(i_out)/1000 + + def get_power(self): + """ + Retrieves current energy supplied by PSU + + Returns: + A float number, the power in watts, + e.g. 302.6 + """ + device = "PSU{}".format(self.psu_index) + output = self.pddf_obj.get_attr_name_output(device, "psu_p_out") + if not output: + return 0.0 + + p_out = output['status'] + + # power is returned in micro watts + return float(p_out)/1000000 + + def get_powergood_status(self): + """ + Retrieves the powergood status of PSU + + Returns: + A boolean, True if PSU has stablized its output voltages and + passed all its internal self-tests, False if not. + """ + return self.get_status() + + def set_status_led(self, color): + index = str(self.psu_index-1) + led_device_name = "PSU{}".format(self.psu_index) + "_LED" + + result, msg = self.pddf_obj.is_supported_sysled_state(led_device_name, color); + if result == False: + print msg + return (False) + + device_name=self.pddf_obj.data[led_device_name]['dev_info']['device_name'] + self.pddf_obj.create_attr('device_name', device_name, self.pddf_obj.get_led_path()) + self.pddf_obj.create_attr('index', index, self.pddf_obj.get_led_path()) + self.pddf_obj.create_attr('color', color, self.pddf_obj.get_led_cur_state_path()) + self.pddf_obj.create_attr('dev_ops', 'set_status', self.pddf_obj.get_led_path()) + return (True) + + def get_status_led(self): + index = str(self.psu_index-1) + psu_led_device = "PSU{}_LED".format(self.psu_index) + if (not psu_led_device in self.pddf_obj.data.keys()): + # Implement a generic status_led color scheme + if self.get_powergood_status(): + return self.STATUS_LED_COLOR_GREEN + else: + return self.STATUS_LED_COLOR_OFF + + device_name=self.pddf_obj.data[psu_led_device]['dev_info']['device_name'] + self.pddf_obj.create_attr('device_name', device_name, self.pddf_obj.get_led_path()) + self.pddf_obj.create_attr('index', index, self.pddf_obj.get_led_path()) + self.pddf_obj.create_attr('dev_ops', 'get_status', self.pddf_obj.get_led_path()) + color=self.pddf_obj.get_led_color() + return (color) + + def get_input_voltage(self): + """ + Retrieves current PSU input voltage + + Returns: + A float number, the input voltage in volts, + e.g. 12.1 + """ + device = "PSU{}".format(self.psu_index) + output = self.pddf_obj.get_attr_name_output(device, "psu_v_in") + if not output: + return 0.0 + + v_in = output['status'] + + return float(v_in)/1000 + + def get_input_current(self): + """ + Retrieves present electric current supplied to the PSU + + Returns: + A float number, electric current in amperes, + e.g. 15.4 + """ + device = "PSU{}".format(self.psu_index) + output = self.pddf_obj.get_attr_name_output(device, "psu_i_in") + if not output: + return 0.0 + + i_in = output['status'] + + # current in mA + return float(i_in)/1000 + + def dump_sysfs(self): + return self.pddf_obj.cli_dump_dsysfs('psu') diff --git a/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_sfp.py b/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_sfp.py new file mode 100755 index 0000000000..856f4c748d --- /dev/null +++ b/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_sfp.py @@ -0,0 +1,1390 @@ +#!/usr/bin/env python + +try: + import time + from ctypes import create_string_buffer + from sonic_platform_base.sfp_base import SfpBase + from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId + from sonic_platform_base.sonic_sfp.sff8436 import sff8436Dom + from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId + from sonic_platform_base.sonic_sfp.sff8472 import sff8472Dom + from sonic_platform_base.sonic_sfp.sff8472 import sffbase + from sonic_platform_base.sonic_sfp.inf8628 import inf8628InterfaceId +except ImportError, e: + raise ImportError (str(e) + "- required module not found") + +# definitions of the offset and width for values in XCVR info eeprom +XCVR_INTFACE_BULK_OFFSET = 0 +XCVR_INTFACE_BULK_WIDTH_QSFP = 20 +XCVR_INTFACE_BULK_WIDTH_SFP = 21 +XCVR_TYPE_OFFSET = 0 +XCVR_TYPE_WIDTH = 1 +XCVR_EXT_TYPE_OFFSET = 1 +XCVR_EXT_TYPE_WIDTH = 1 +XCVR_CONNECTOR_OFFSET = 2 +XCVR_CONNECTOR_WIDTH = 1 +XCVR_COMPLIANCE_CODE_OFFSET = 3 +XCVR_COMPLIANCE_CODE_WIDTH = 8 +XCVR_ENCODING_OFFSET = 11 +XCVR_ENCODING_WIDTH = 1 +XCVR_NBR_OFFSET = 12 +XCVR_NBR_WIDTH = 1 +XCVR_EXT_RATE_SEL_OFFSET = 13 +XCVR_EXT_RATE_SEL_WIDTH = 1 +XCVR_CABLE_LENGTH_OFFSET = 14 +XCVR_CABLE_LENGTH_WIDTH_QSFP = 5 +XCVR_CABLE_LENGTH_WIDTH_SFP = 6 +XCVR_VENDOR_NAME_OFFSET = 20 +XCVR_VENDOR_NAME_WIDTH = 16 +XCVR_VENDOR_OUI_OFFSET = 37 +XCVR_VENDOR_OUI_WIDTH = 3 +XCVR_VENDOR_PN_OFFSET = 40 +XCVR_VENDOR_PN_WIDTH = 16 +XCVR_HW_REV_OFFSET = 56 +XCVR_HW_REV_WIDTH_OSFP = 2 +XCVR_HW_REV_WIDTH_QSFP = 2 +XCVR_HW_REV_WIDTH_SFP = 4 +XCVR_VENDOR_SN_OFFSET = 68 +XCVR_VENDOR_SN_WIDTH = 16 +XCVR_VENDOR_DATE_OFFSET = 84 +XCVR_VENDOR_DATE_WIDTH = 8 +XCVR_DOM_CAPABILITY_OFFSET = 92 +XCVR_DOM_CAPABILITY_WIDTH = 1 + +# definitions of the offset for values in OSFP info eeprom +OSFP_TYPE_OFFSET = 0 +OSFP_VENDOR_NAME_OFFSET = 129 +OSFP_VENDOR_PN_OFFSET = 148 +OSFP_HW_REV_OFFSET = 164 +OSFP_VENDOR_SN_OFFSET = 166 + +#definitions of the offset and width for values in DOM info eeprom +QSFP_DOM_REV_OFFSET = 1 +QSFP_DOM_REV_WIDTH = 1 +QSFP_TEMPE_OFFSET = 22 +QSFP_TEMPE_WIDTH = 2 +QSFP_VOLT_OFFSET = 26 +QSFP_VOLT_WIDTH = 2 +QSFP_CHANNL_MON_OFFSET = 34 +QSFP_CHANNL_MON_WIDTH = 16 +QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH = 24 +QSFP_CONTROL_OFFSET = 86 +QSFP_CONTROL_WIDTH = 8 +QSFP_CHANNL_RX_LOS_STATUS_OFFSET = 3 +QSFP_CHANNL_RX_LOS_STATUS_WIDTH = 1 +QSFP_CHANNL_TX_FAULT_STATUS_OFFSET = 4 +QSFP_CHANNL_TX_FAULT_STATUS_WIDTH = 1 +QSFP_POWEROVERRIDE_OFFSET = 93 +QSFP_POWEROVERRIDE_WIDTH = 1 +QSFP_MODULE_THRESHOLD_OFFSET = 128 +QSFP_MODULE_THRESHOLD_WIDTH = 24 +QSFP_CHANNEL_THRESHOLD_OFFSET = 176 +QSFP_CHANNEL_THRESHOLD_WIDTH = 16 + + +SFP_TEMPE_OFFSET = 96 +SFP_TEMPE_WIDTH = 2 +SFP_VOLT_OFFSET = 98 +SFP_VOLT_WIDTH = 2 +SFP_CHANNL_MON_OFFSET = 100 +SFP_CHANNL_MON_WIDTH = 6 +SFP_MODULE_THRESHOLD_OFFSET = 0 +SFP_MODULE_THRESHOLD_WIDTH = 40 +SFP_CHANNL_THRESHOLD_OFFSET = 112 +SFP_CHANNL_THRESHOLD_WIDTH = 2 +SFP_STATUS_CONTROL_OFFSET = 110 +SFP_STATUS_CONTROL_WIDTH = 1 +SFP_TX_DISABLE_HARD_BIT = 7 +SFP_TX_DISABLE_SOFT_BIT = 6 + + +qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)', + 'Length OM2(m)', 'Length OM1(m)', + 'Length Cable Assembly(m)') + +sfp_cable_length_tup = ('LengthSMFkm-UnitsOfKm', 'LengthSMF(UnitsOf100m)', + 'Length50um(UnitsOf10m)', 'Length62.5um(UnitsOfm)', + 'LengthCable(UnitsOfm)', 'LengthOM3(UnitsOf10m)') + +sfp_compliance_code_tup = ('10GEthernetComplianceCode', 'InfinibandComplianceCode', + 'ESCONComplianceCodes', 'SONETComplianceCodes', + 'EthernetComplianceCodes','FibreChannelLinkLength', + 'FibreChannelTechnology', 'SFP+CableTechnology', + 'FibreChannelTransmissionMedia','FibreChannelSpeed') + +qsfp_compliance_code_tup = ('10/40G Ethernet Compliance Code', 'SONET Compliance codes', + 'SAS/SATA compliance codes', 'Gigabit Ethernet Compliant codes', + 'Fibre Channel link length/Transmitter Technology', + 'Fibre Channel transmission media', 'Fibre Channel Speed') + +PAGE_OFFSET = 0 +KEY_OFFSET = 1 +KEY_WIDTH = 2 +FUNC_NAME = 3 + +INFO_OFFSET = 128 +DOM_OFFSET = 0 +DOM_OFFSET1 = 384 + +class PddfSfp(SfpBase): + """ + PDDF generic Sfp class + """ + + pddf_obj = {} + plugin_data = {} + _port_to_eeprom_mapping = {} + _port_start = 0 + _port_end = 0 + _port_to_type_mapping = {} + _qsfp_ports = [] + _sfp_ports = [] + + # Read out any bytes from any offset + def __read_eeprom_specific_bytes(self, offset, num_bytes): + sysfsfile_eeprom = None + eeprom_raw = [] + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + + try: + sysfsfile_eeprom = open(self.eeprom_path, mode="rb", buffering=0) + sysfsfile_eeprom.seek(offset) + raw = sysfsfile_eeprom.read(num_bytes) + for n in range(0, num_bytes): + eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) + except Exception as e: + print "Error: Unable to open eeprom_path: %s"%(str(e)) + finally: + if sysfsfile_eeprom: + sysfsfile_eeprom.close() + + return eeprom_raw + + def __init__(self, index, pddf_data=None, pddf_plugin_data=None): + if not pddf_data or not pddf_plugin_data: + raise ValueError('PDDF JSON data error') + + self.pddf_obj = pddf_data + self.plugin_data = pddf_plugin_data + + self.platform = self.pddf_obj.get_platform() + + # index is 0-based + self._port_start = 0 + self._port_end = int(self.platform['num_ports']) + if index < self._port_start or index >= self._port_end: + print "Invalid port index %d"%index + return + + self.port_index = index+1 + self.device = 'PORT{}'.format(self.port_index) + self.sfp_type = self.pddf_obj.get_device_type(self.device) + self.is_qsfp_port = True if (self.sfp_type=='QSFP' or self.sfp_type=='QSFP28') else False + self.is_osfp_port = True if (self.sfp_type=='OSFP' or self.sfp_type=='QSFP-DD') else False + self.eeprom_path = self.pddf_obj.get_path(self.device, 'eeprom') + + self.info_dict_keys = ['type', 'hardware_rev', 'serial', 'manufacturer', 'model', 'connector', 'encoding', + 'ext_identifier', 'ext_rateselect_compliance', 'cable_type', 'cable_length', 'nominal_bit_rate', + 'specification_compliance', 'vendor_date', 'vendor_oui', 'application_advertisement'] + + self.dom_dict_keys = ['rx_los', 'tx_fault', 'reset_status', 'power_lpmode', 'tx_disable', 'tx_disable_channel', + 'temperature', 'voltage', 'rx1power', 'rx2power', 'rx3power', 'rx4power', 'tx1bias', 'tx2bias', + 'tx3bias', 'tx4bias', 'tx1power', 'tx2power', 'tx3power', 'tx4power'] + + self.threshold_dict_keys = ['temphighalarm', 'temphighwarning', 'templowalarm', 'templowwarning', + 'vcchighalarm', 'vcchighwarning', 'vcclowalarm', 'vcclowwarning', 'rxpowerhighalarm', + 'rxpowerhighwarning', 'rxpowerlowalarm', 'rxpowerlowwarning', 'txpowerhighalarm', 'txpowerhighwarning', + 'txpowerlowalarm', 'txpowerlowwarning', 'txbiashighalarm', 'txbiashighwarning', 'txbiaslowalarm', + 'txbiaslowwarning'] + + SfpBase.__init__(self) + + def get_transceiver_info(self): + """ + Retrieves transceiver info of this SFP + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + type |1*255VCHAR |type of SFP + hardware_rev |1*255VCHAR |hardware version of SFP + serial |1*255VCHAR |serial number of the SFP + manufacturer |1*255VCHAR |SFP vendor name + model |1*255VCHAR |SFP model name + connector |1*255VCHAR |connector information + encoding |1*255VCHAR |encoding information + ext_identifier |1*255VCHAR |extend identifier + ext_rateselect_compliance |1*255VCHAR |extended rateSelect compliance + cable_length |INT |cable length in m + nominal_bit_rate |INT |nominal bit rate by 100Mbs + specification_compliance |1*255VCHAR |specification compliance + vendor_date |1*255VCHAR |vendor date + vendor_oui |1*255VCHAR |vendor OUI + application_advertisement |1*255VCHAR |supported applications advertisement + ======================================================================== + """ + # check present status + if not self.get_presence(): + return None + + + if self.is_osfp_port: + sfpi_obj = inf8628InterfaceId() + offset = 0 + type_offset = OSFP_TYPE_OFFSET + vendor_rev_width = XCVR_HW_REV_WIDTH_OSFP + hw_rev_offset = OSFP_HW_REV_OFFSET + vendor_name_offset = OSFP_VENDOR_NAME_OFFSET + vendor_pn_offset = OSFP_VENDOR_PN_OFFSET + vendor_sn_offset = OSFP_VENDOR_SN_OFFSET + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_QSFP + sfp_type = 'OSFP' + + elif self.is_qsfp_port: + sfpi_obj = sff8436InterfaceId() + offset = 128 + type_offset = XCVR_TYPE_OFFSET + vendor_rev_width = XCVR_HW_REV_WIDTH_QSFP + hw_rev_offset = XCVR_HW_REV_OFFSET + vendor_name_offset = XCVR_VENDOR_NAME_OFFSET + vendor_pn_offset = XCVR_VENDOR_PN_OFFSET + vendor_sn_offset = XCVR_VENDOR_SN_OFFSET + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_QSFP + sfp_type = 'QSFP' + else: + sfpi_obj = sff8472InterfaceId() + offset = 0 + type_offset = XCVR_TYPE_OFFSET + vendor_rev_width = XCVR_HW_REV_WIDTH_SFP + hw_rev_offset = XCVR_HW_REV_OFFSET + vendor_name_offset = XCVR_VENDOR_NAME_OFFSET + vendor_pn_offset = XCVR_VENDOR_PN_OFFSET + vendor_sn_offset = XCVR_VENDOR_SN_OFFSET + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_SFP + sfp_type = 'SFP' + + if sfpi_obj is None: + return None + + + if self.is_osfp_port: + sfp_type_raw = self.__read_eeprom_specific_bytes((offset + type_offset), XCVR_TYPE_WIDTH) + if sfp_type_raw is not None: + sfp_type_data = sfpi_obj.parse_sfp_type(sfp_type_raw, 0) + sfp_type_abbrv_name = sfpi_obj.parse_sfp_type_abbrv_name(sfp_typ_raw, 0) + else: + sfp_interface_bulk_raw = self.__read_eeprom_specific_bytes((offset + XCVR_INTFACE_BULK_OFFSET), interface_info_bulk_width) + if sfp_interface_bulk_raw is not None: + sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk(sfp_interface_bulk_raw, 0) + + sfp_vendor_oui_raw = self.__read_eeprom_specific_bytes((offset + XCVR_VENDOR_OUI_OFFSET), XCVR_VENDOR_OUI_WIDTH) + if sfp_vendor_oui_raw is not None: + sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui(sfp_vendor_oui_raw, 0) + + sfp_vendor_date_raw = self.__read_eeprom_specific_bytes((offset + XCVR_VENDOR_DATE_OFFSET), XCVR_VENDOR_DATE_WIDTH) + if sfp_vendor_date_raw is not None: + sfp_vendor_date_data = sfpi_obj.parse_vendor_date(sfp_vendor_date_raw, 0) + + + sfp_vendor_name_raw = self.__read_eeprom_specific_bytes( + (offset + vendor_name_offset), XCVR_VENDOR_NAME_WIDTH) + sfp_vendor_name_data = sfpi_obj.parse_vendor_name( + sfp_vendor_name_raw, 0) + + sfp_vendor_pn_raw = self.__read_eeprom_specific_bytes( + (offset + vendor_pn_offset), XCVR_VENDOR_PN_WIDTH) + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn( + sfp_vendor_pn_raw, 0) + + sfp_vendor_rev_raw = self.__read_eeprom_specific_bytes( + (offset + hw_rev_offset), vendor_rev_width) + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev( + sfp_vendor_rev_raw, 0) + + sfp_vendor_sn_raw = self.__read_eeprom_specific_bytes( + (offset + vendor_sn_offset), XCVR_VENDOR_SN_WIDTH) + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn( + sfp_vendor_sn_raw, 0) + + xcvr_info_dict = dict.fromkeys(self.info_dict_keys, 'N/A') + compliance_code_dict = dict() + + if sfp_interface_bulk_data: + xcvr_info_dict['type'] = sfp_interface_bulk_data['data']['type']['value'] + xcvr_info_dict['connector'] = sfp_interface_bulk_data['data']['Connector']['value'] + xcvr_info_dict['encoding'] = sfp_interface_bulk_data['data']['EncodingCodes']['value'] + xcvr_info_dict['ext_identifier'] = sfp_interface_bulk_data['data']['Extended Identifier']['value'] + xcvr_info_dict['ext_rateselect_compliance'] = sfp_interface_bulk_data['data']['RateIdentifier']['value'] + xcvr_info_dict['type_abbrv_name'] = sfp_interface_bulk_data['data']['type_abbrv_name']['value'] + else: + xcvr_info_dict['type'] = sfp_type_data['data']['type']['value'] if sfp_type_data else 'N/A' + xcvr_info_dict['type_abbrv_name'] = sfp_type_abbrv_name['data']['type_abbrv_name']['value'] if sfp_type_abbrv_name else 'N/A' + + xcvr_info_dict['manufacturer'] = sfp_vendor_name_data['data']['Vendor Name']['value'] if sfp_vendor_name_data else 'N/A' + xcvr_info_dict['model'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] if sfp_vendor_pn_data else 'N/A' + xcvr_info_dict['hardware_rev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] if sfp_vendor_rev_data else 'N/A' + xcvr_info_dict['serial'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] if sfp_vendor_sn_data else 'N/A' + xcvr_info_dict['vendor_oui'] = sfp_vendor_oui_data['data']['Vendor OUI']['value'] if sfp_vendor_oui_data else 'N/A' + xcvr_info_dict['vendor_date'] = sfp_vendor_date_data['data']['VendorDataCode(YYYY-MM-DD Lot)']['value'] if sfp_vendor_date_data else 'N/A' + xcvr_info_dict['cable_type'] = "Unknown" + xcvr_info_dict['cable_length'] = "Unknown" + + if sfp_type == 'QSFP': + for key in qsfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + xcvr_info_dict['cable_type'] = key + xcvr_info_dict['cable_length'] = str(sfp_interface_bulk_data['data'][key]['value']) + + for key in qsfp_compliance_code_tup: + if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = sfp_interface_bulk_data['data']['Specification compliance']['value'][key]['value'] + xcvr_info_dict['specification_compliance'] = str(compliance_code_dict) + + nkey='Nominal Bit Rate(100Mbs)' + if nkey in sfp_interface_bulk_data['data']: + xcvr_info_dict['nominal_bit_rate'] = str(sfp_interface_bulk_data['data']['Nominal Bit Rate(100Mbs)']['value']) + else: + xcvr_info_dict['nominal_bit_rate'] = 'N/A' + elif sfp_type == 'OSFP': + pass + else: + for key in sfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + xcvr_info_dict['cable_type'] = key + xcvr_info_dict['cable_length'] = str(sfp_interface_bulk_data['data'][key]['value']) + + for key in sfp_compliance_code_tup: + if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = sfp_interface_bulk_data['data']['Specification compliance']['value'][key]['value'] + xcvr_info_dict['specification_compliance'] = str(compliance_code_dict) + + xcvr_info_dict['nominal_bit_rate'] = str(sfp_interface_bulk_data['data']['NominalSignallingRate(UnitsOf100Mbd)']['value']) + + return xcvr_info_dict + + def get_transceiver_bulk_status(self): + """ + Retrieves transceiver bulk status of this SFP + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + rx_los |BOOLEAN |RX loss-of-signal status, True if has RX los, False if not. + tx_fault |BOOLEAN |TX fault status, True if has TX fault, False if not. + reset_status |BOOLEAN |reset status, True if SFP in reset, False if not. + lp_mode |BOOLEAN |low power mode status, True in lp mode, False if not. + tx_disable |BOOLEAN |TX disable status, True TX disabled, False if not. + tx_disabled_channel |HEX |disabled TX channels in hex, bits 0 to 3 represent channel 0 + | |to channel 3. + temperature |INT |module temperature in Celsius + voltage |INT |supply voltage in mV + txbias |INT |TX Bias Current in mA, n is the channel number, + | |for example, tx2bias stands for tx bias of channel 2. + rxpower |INT |received optical power in mW, n is the channel number, + | |for example, rx2power stands for rx power of channel 2. + txpower |INT |TX output power in mW, n is the channel number, + | |for example, tx2power stands for tx power of channel 2. + ======================================================================== + """ + # check present status + if not self.get_presence(): + return None + + xcvr_dom_info_dict = dict.fromkeys(self.dom_dict_keys, 'N/A') + + if self.is_osfp_port: + # Below part is added to avoid fail xcvrd, shall be implemented later + pass + elif self.is_qsfp_port: + # QSFPs + offset = 0 + offset_xcvr = 128 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + return None + + qsfp_dom_capability_raw = self.__read_eeprom_specific_bytes( + (offset_xcvr + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH) + if qsfp_dom_capability_raw is not None: + qspf_dom_capability_data = sfpi_obj.parse_qsfp_dom_capability( + qsfp_dom_capability_raw, 0) + else: + return None + + dom_temperature_raw = self.__read_eeprom_specific_bytes( (offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) + else: + return None + + dom_voltage_raw = self.__read_eeprom_specific_bytes( (offset + QSFP_VOLT_OFFSET), QSFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + else: + return None + + qsfp_dom_rev_raw = self.__read_eeprom_specific_bytes( (offset + QSFP_DOM_REV_OFFSET), QSFP_DOM_REV_WIDTH) + if qsfp_dom_rev_raw is not None: + qsfp_dom_rev_data = sfpd_obj.parse_sfp_dom_rev(qsfp_dom_rev_raw, 0) + else: + return None + + xcvr_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + xcvr_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + + # The tx_power monitoring is only available on QSFP which compliant with SFF-8636 + # and claimed that it support tx_power with one indicator bit. + dom_channel_monitor_data = {} + qsfp_dom_rev = qsfp_dom_rev_data['data']['dom_rev']['value'] + qsfp_tx_power_support = qspf_dom_capability_data['data']['Tx_power_support']['value'] + if (qsfp_dom_rev[0:8] != 'SFF-8636' or (qsfp_dom_rev[0:8] == 'SFF-8636' and qsfp_tx_power_support != 'on')): + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes((offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) + else: + return None + + xcvr_dom_info_dict['tx1power'] = 'N/A' + xcvr_dom_info_dict['tx2power'] = 'N/A' + xcvr_dom_info_dict['tx3power'] = 'N/A' + xcvr_dom_info_dict['tx4power'] = 'N/A' + else: + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes((offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + else: + return None + + + xcvr_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TX1Power']['value'] + xcvr_dom_info_dict['tx2power'] = dom_channel_monitor_data['data']['TX2Power']['value'] + xcvr_dom_info_dict['tx3power'] = dom_channel_monitor_data['data']['TX3Power']['value'] + xcvr_dom_info_dict['tx4power'] = dom_channel_monitor_data['data']['TX4Power']['value'] + + if dom_channel_monitor_raw: + xcvr_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + xcvr_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + xcvr_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RX1Power']['value'] + xcvr_dom_info_dict['rx2power'] = dom_channel_monitor_data['data']['RX2Power']['value'] + xcvr_dom_info_dict['rx3power'] = dom_channel_monitor_data['data']['RX3Power']['value'] + xcvr_dom_info_dict['rx4power'] = dom_channel_monitor_data['data']['RX4Power']['value'] + xcvr_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TX1Bias']['value'] + xcvr_dom_info_dict['tx2bias'] = dom_channel_monitor_data['data']['TX2Bias']['value'] + xcvr_dom_info_dict['tx3bias'] = dom_channel_monitor_data['data']['TX3Bias']['value'] + xcvr_dom_info_dict['tx4bias'] = dom_channel_monitor_data['data']['TX4Bias']['value'] + + else: + # SFPs + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + + dom_temperature_raw = self.__read_eeprom_specific_bytes( (offset + SFP_TEMPE_OFFSET), SFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) + else: + return None + + dom_voltage_raw = self.__read_eeprom_specific_bytes( (offset + SFP_VOLT_OFFSET), SFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + else: + return None + + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) + else: + return None + + xcvr_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + xcvr_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + xcvr_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RXPower']['value'] + xcvr_dom_info_dict['rx2power'] = 'N/A' + xcvr_dom_info_dict['rx3power'] = 'N/A' + xcvr_dom_info_dict['rx4power'] = 'N/A' + xcvr_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TXBias']['value'] + xcvr_dom_info_dict['tx2bias'] = 'N/A' + xcvr_dom_info_dict['tx3bias'] = 'N/A' + xcvr_dom_info_dict['tx4bias'] = 'N/A' + xcvr_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TXPower']['value'] + xcvr_dom_info_dict['tx2power'] = 'N/A' + xcvr_dom_info_dict['tx3power'] = 'N/A' + xcvr_dom_info_dict['tx4power'] = 'N/A' + + xcvr_dom_info_dict['rx_los'] = self.get_rx_los() + xcvr_dom_info_dict['tx_fault'] = self.get_tx_fault() + xcvr_dom_info_dict['reset_status'] = self.get_reset_status() + xcvr_dom_info_dict['lp_mode'] = self.get_lpmode() + + + return xcvr_dom_info_dict + + def get_transceiver_threshold_info(self): + """ + Retrieves transceiver threshold info of this SFP + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + temphighalarm |FLOAT |High Alarm Threshold value of temperature in Celsius. + templowalarm |FLOAT |Low Alarm Threshold value of temperature in Celsius. + temphighwarning |FLOAT |High Warning Threshold value of temperature in Celsius. + templowwarning |FLOAT |Low Warning Threshold value of temperature in Celsius. + vcchighalarm |FLOAT |High Alarm Threshold value of supply voltage in mV. + vcclowalarm |FLOAT |Low Alarm Threshold value of supply voltage in mV. + vcchighwarning |FLOAT |High Warning Threshold value of supply voltage in mV. + vcclowwarning |FLOAT |Low Warning Threshold value of supply voltage in mV. + rxpowerhighalarm |FLOAT |High Alarm Threshold value of received power in dBm. + rxpowerlowalarm |FLOAT |Low Alarm Threshold value of received power in dBm. + rxpowerhighwarning |FLOAT |High Warning Threshold value of received power in dBm. + rxpowerlowwarning |FLOAT |Low Warning Threshold value of received power in dBm. + txpowerhighalarm |FLOAT |High Alarm Threshold value of transmit power in dBm. + txpowerlowalarm |FLOAT |Low Alarm Threshold value of transmit power in dBm. + txpowerhighwarning |FLOAT |High Warning Threshold value of transmit power in dBm. + txpowerlowwarning |FLOAT |Low Warning Threshold value of transmit power in dBm. + txbiashighalarm |FLOAT |High Alarm Threshold value of tx Bias Current in mA. + txbiaslowalarm |FLOAT |Low Alarm Threshold value of tx Bias Current in mA. + txbiashighwarning |FLOAT |High Warning Threshold value of tx Bias Current in mA. + txbiaslowwarning |FLOAT |Low Warning Threshold value of tx Bias Current in mA. + ======================================================================== + """ + # check present status + if not self.get_presence(): + return None + + xcvr_dom_threshold_info_dict = dict.fromkeys(self.threshold_dict_keys, 'N/A') + + if self.is_osfp_port: + # Below part is added to avoid fail xcvrd, shall be implemented later + pass + elif self.is_qsfp_port: + # QSFPs + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + dom_thres_raw = self.__read_eeprom_specific_bytes(QSFP_MODULE_THRESHOLD_OFFSET, QSFP_MODULE_THRESHOLD_WIDTH) + + if dom_thres_raw: + module_threshold_values = sfpd_obj.parse_module_threshold_values( + dom_thres_raw, 0) + module_threshold_data = module_threshold_values.get('data') + if module_threshold_data: + xcvr_dom_threshold_info_dict['temphighalarm'] = module_threshold_data['TempHighAlarm']['value'] + xcvr_dom_threshold_info_dict['templowalarm'] = module_threshold_data['TempLowAlarm']['value'] + xcvr_dom_threshold_info_dict['temphighwarning'] = module_threshold_data['TempHighWarning']['value'] + xcvr_dom_threshold_info_dict['templowwarning'] = module_threshold_data['TempLowWarning']['value'] + xcvr_dom_threshold_info_dict['vcchighalarm'] = module_threshold_data['VccHighAlarm']['value'] + xcvr_dom_threshold_info_dict['vcclowalarm'] = module_threshold_data['VccLowAlarm']['value'] + xcvr_dom_threshold_info_dict['vcchighwarning'] = module_threshold_data['VccHighWarning']['value'] + xcvr_dom_threshold_info_dict['vcclowwarning'] = module_threshold_data['VccLowWarning']['value'] + + dom_thres_raw = self.__read_eeprom_specific_bytes(QSFP_CHANNEL_THRESHOLD_OFFSET, QSFP_CHANNEL_THRESHOLD_WIDTH) + if dom_thres_raw: + channel_threshold_values = sfpd_obj.parse_channel_threshold_values( + dom_thres_raw, 0) + channel_threshold_data = channel_threshold_values.get('data') + if channel_threshold_data: + xcvr_dom_threshold_info_dict['rxpowerhighalarm'] = channel_threshold_data['RxPowerHighAlarm']['value'] + xcvr_dom_threshold_info_dict['rxpowerlowalarm'] = channel_threshold_data['RxPowerLowAlarm']['value'] + xcvr_dom_threshold_info_dict['rxpowerhighwarning'] = channel_threshold_data['RxPowerHighWarning']['value'] + xcvr_dom_threshold_info_dict['rxpowerlowwarning'] = channel_threshold_data['RxPowerLowWarning']['value'] + xcvr_dom_threshold_info_dict['txpowerhighalarm'] = "0.0dBm" + xcvr_dom_threshold_info_dict['txpowerlowalarm'] = "0.0dBm" + xcvr_dom_threshold_info_dict['txpowerhighwarning'] = "0.0dBm" + xcvr_dom_threshold_info_dict['txpowerlowwarning'] = "0.0dBm" + xcvr_dom_threshold_info_dict['txbiashighalarm'] = channel_threshold_data['TxBiasHighAlarm']['value'] + xcvr_dom_threshold_info_dict['txbiaslowalarm'] = channel_threshold_data['TxBiasLowAlarm']['value'] + xcvr_dom_threshold_info_dict['txbiashighwarning'] = channel_threshold_data['TxBiasHighWarning']['value'] + xcvr_dom_threshold_info_dict['txbiaslowwarning'] = channel_threshold_data['TxBiasLowWarning']['value'] + + else: + # SFPs + sfpd_obj = sff8472Dom() + offset = 256 + eeprom_ifraw = self.__read_eeprom_specific_bytes(0, offset) + sfpi_obj = sff8472InterfaceId(eeprom_ifraw) + cal_type = sfpi_obj.get_calibration_type() + sfpd_obj._calibration_type = cal_type + + dom_module_threshold_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_MODULE_THRESHOLD_OFFSET), SFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is not None: + dom_module_threshold_data = sfpd_obj.parse_alarm_warning_threshold( + dom_module_threshold_raw, 0) + + xcvr_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + xcvr_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + xcvr_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + xcvr_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + xcvr_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VoltageHighAlarm']['value'] + xcvr_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VoltageLowAlarm']['value'] + xcvr_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data[ + 'data']['VoltageHighWarning']['value'] + xcvr_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VoltageLowWarning']['value'] + xcvr_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['BiasHighAlarm']['value'] + xcvr_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['BiasLowAlarm']['value'] + xcvr_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['BiasHighWarning']['value'] + xcvr_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['BiasLowWarning']['value'] + xcvr_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TXPowerHighAlarm']['value'] + xcvr_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TXPowerLowAlarm']['value'] + xcvr_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TXPowerHighWarning']['value'] + xcvr_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TXPowerLowWarning']['value'] + xcvr_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RXPowerHighAlarm']['value'] + xcvr_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RXPowerLowAlarm']['value'] + xcvr_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RXPowerHighWarning']['value'] + xcvr_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RXPowerLowWarning']['value'] + + + + return xcvr_dom_threshold_info_dict + + def get_reset_status(self): + """ + Retrieves the reset status of SFP + Returns: + A Boolean, True if reset enabled, False if disabled + """ + reset_status = None + if not self.get_presence(): + return reset_status + + device = 'PORT{}'.format(self.port_index) + output = self.pddf_obj.get_attr_name_output(device, 'xcvr_reset') + if not output: + return False + + status = int(output['status'].rstrip()) + + if status==1: + reset_status = True + else: + reset_status = False + + return reset_status + + def get_rx_los(self): + """ + Retrieves the RX LOS (lost-of-signal) status of SFP + Returns: + A Boolean, True if SFP has RX LOS, False if not. + Note : RX LOS status is latched until a call to get_rx_los or a reset. + """ + rx_los = None + if not self.get_presence(): + return rx_los + + device = 'PORT{}'.format(self.port_index) + output = self.pddf_obj.get_attr_name_output(device, 'xcvr_rxlos') + + if not output: + # read the values from EEPROM + if self.is_osfp_port: + pass + elif self.is_qsfp_port: + rx_los_list = [] + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + QSFP_CHANNL_RX_LOS_STATUS_OFFSET, QSFP_CHANNL_RX_LOS_STATUS_WIDTH) if self.get_presence() else None + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 16) + rx_los_list.append(rx_los_data & 0x01 != 0) + rx_los_list.append(rx_los_data & 0x02 != 0) + rx_los_list.append(rx_los_data & 0x04 != 0) + rx_los_list.append(rx_los_data & 0x08 != 0) + rx_los = rx_los_list[0] and rx_los_list[1] and rx_los_list[2] and rx_los_list[3] + else: + # SFP ports + status_control_raw = self.__read_eeprom_specific_bytes( + SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH) + if status_control_raw: + data = int(status_control_raw[0], 16) + rx_los = (sffbase().test_bit(data, 1) != 0) + + else: + status = int(output['status'].rstrip()) + + if status==1: + rx_los = True + else: + rx_los = False + + return rx_los + + def get_tx_fault(self): + """ + Retrieves the TX fault status of SFP + Returns: + A Boolean, True if SFP has TX fault, False if not + Note : TX fault status is lached until a call to get_tx_fault or a reset. + """ + tx_fault = None + if not self.get_presence(): + return tx_fault + + device = 'PORT{}'.format(self.port_index) + output = self.pddf_obj.get_attr_name_output(device, 'xcvr_txfault') + + if not output: + # read the values from EEPROM + if self.is_osfp_port: + pass + elif self.is_qsfp_port: + tx_fault_list = [] + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + QSFP_CHANNL_TX_FAULT_STATUS_OFFSET, QSFP_CHANNL_TX_FAULT_STATUS_WIDTH) if self.get_presence() else None + if dom_channel_monitor_raw is not None: + tx_fault_data = int(dom_channel_monitor_raw[0], 16) + tx_fault_list.append(tx_fault_data & 0x01 != 0) + tx_fault_list.append(tx_fault_data & 0x02 != 0) + tx_fault_list.append(tx_fault_data & 0x04 != 0) + tx_fault_list.append(tx_fault_data & 0x08 != 0) + tx_fault = tx_fault_list[0] and tx_fault_list[1] and tx_fault_list[2] and tx_fault_list[3] + else: + # SFP + status_control_raw = self.__read_eeprom_specific_bytes( + SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH) + if status_control_raw: + data = int(status_control_raw[0], 16) + tx_fault = (sffbase().test_bit(data, 2) != 0) + else: + status = int(output['status'].rstrip()) + + if status==1: + tx_fault = True + else: + tx_fault = False + + return tx_fault + + def get_tx_disable(self): + """ + Retrieves the tx_disable status of this SFP + Returns: + A Boolean, True if tx_disable is enabled, False if disabled + """ + tx_disable = False + if not self.get_presence(): + return tx_disable + + device = 'PORT{}'.format(self.port_index) + output = self.pddf_obj.get_attr_name_output(device, 'xcvr_txdisable') + + if not output: + # read the values from EEPROM + if self.is_osfp_port: + return tx_disable + elif self.is_qsfp_port: + tx_disable_list = [] + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return False + + dom_control_raw = self.__read_eeprom_specific_bytes( + QSFP_CONTROL_OFFSET, QSFP_CONTROL_WIDTH) if self.get_presence() else None + if dom_control_raw is not None: + dom_control_data = sfpd_obj.parse_control_bytes(dom_control_raw, 0) + tx_disable_list.append( + 'On' == dom_control_data['data']['TX1Disable']['value']) + tx_disable_list.append( + 'On' == dom_control_data['data']['TX2Disable']['value']) + tx_disable_list.append( + 'On' == dom_control_data['data']['TX3Disable']['value']) + tx_disable_list.append( + 'On' == dom_control_data['data']['TX4Disable']['value']) + + return tx_disable_list + else: + status_control_raw = self.__read_eeprom_specific_bytes( + SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH) + if status_control_raw: + data = int(status_control_raw[0], 16) + tx_disable_hard = (sffbase().test_bit( + data, SFP_TX_DISABLE_HARD_BIT) != 0) + tx_disable_soft = (sffbase().test_bit( + data, SFP_TX_DISABLE_SOFT_BIT) != 0) + tx_disable = tx_disable_hard | tx_disable_soft + + return tx_disable + else: + status = int(output['status'].rstrip()) + + if status==1: + tx_disable = True + else: + tx_disable = False + + return tx_disable + + def get_tx_disable_channel(self): + """ + Retrieves the TX disabled channels in this SFP + Returns: + A hex of 4 bits (bit 0 to bit 3 as channel 0 to channel 3) to represent + TX channels which have been disabled in this SFP. + As an example, a returned value of 0x5 indicates that channel 0 + and channel 2 have been disabled. + """ + if not self.get_presence(): + return 0 + + if self.is_osfp_port: + return 0 + elif self.is_qsfp_port: + tx_disable_list = self.get_tx_disable() + if tx_disable_list is None: + return 0 + tx_disabled = 0 + for i in range(len(tx_disable_list)): + if tx_disable_list[i]: + tx_disabled |= 1 << i + return tx_disabled + else: + # SFP doesnt support this + return 0 + + def get_lpmode(self): + """ + Retrieves the lpmode (low power mode) status of this SFP + Returns: + A Boolean, True if lpmode is enabled, False if disabled + """ + lpmode = False + if not self.get_presence(): + return lpmode + + device = 'PORT{}'.format(self.port_index) + output = self.pddf_obj.get_attr_name_output(device, 'xcvr_lpmode') + + if not output: + # Read from EEPROM + if self.is_osfp_port: + pass + elif self.is_qsfp_port: + try: + eeprom = None + ctype = self.get_connector_type() + if ctype in ['Copper pigtail', 'No separable connector']: + return False + + eeprom = open(self.eeprom_path, "rb") + eeprom.seek(93) + status = ord(eeprom.read(1)) + + if ((status & 0x3) == 0x3): + lpmode = True # Low Power Mode if "Power override" bit is 1 and "Power set" bit is 1 + else: + lpmode = False # High Power Mode if one of the following conditions is matched: + # 1. "Power override" bit is 0 + # 2. "Power override" bit is 1 and "Power set" bit is 0 + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + finally: + if eeprom is not None: + eeprom.close() + time.sleep(0.01) + else: + # SFP + pass + else: + status = int(output['status'].rstrip()) + + if status == 1: + lpmode = True + else: + lpmode = False + + return lpmode + + def get_power_override(self): + """ + Retrieves the power-override status of this SFP + Returns: + A Boolean, True if power-override is enabled, False if disabled + """ + power_override = False + if not self.get_presence(): + return power_override + + + if self.is_osfp_port: + pass + elif self.is_qsfp_port: + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return False + + dom_control_raw = self.__read_eeprom_specific_bytes( + QSFP_CONTROL_OFFSET, QSFP_CONTROL_WIDTH) if self.get_presence() else None + if dom_control_raw is not None: + dom_control_data = sfpd_obj.parse_control_bytes(dom_control_raw, 0) + power_override = ('On' == dom_control_data['data']['PowerOverride']['value']) + else: + # SFP doesnt suppor this + pass + + return power_override + + def get_temperature(self): + """ + Retrieves the temperature of this SFP + Returns: + An integer number of current temperature in Celsius + """ + transceiver_dom_info_dict = self.get_transceiver_bulk_status() + if transceiver_dom_info_dict is not None: + # returns None if temperature is not found in the dictionary + return transceiver_dom_info_dict.get("temperature") + else: + return None + + def get_voltage(self): + """ + Retrieves the supply voltage of this SFP + Returns: + An integer number of supply voltage in mV + """ + transceiver_dom_info_dict = self.get_transceiver_bulk_status() + # returns None if voltage is not found in the dictionary + if transceiver_dom_info_dict is not None: + return transceiver_dom_info_dict.get("voltage") + else: + return None + + def get_tx_bias(self): + """ + Retrieves the TX bias current of this SFP + Returns: + A list of four integer numbers, representing TX bias in mA + for channel 0 to channel 4. + Ex. ['110.09', '111.12', '108.21', '112.09'] + """ + transceiver_dom_info_dict = self.get_transceiver_bulk_status() + if transceiver_dom_info_dict is not None: + tx1_bs = transceiver_dom_info_dict.get("tx1bias", "N/A") + tx2_bs = transceiver_dom_info_dict.get("tx2bias", "N/A") + tx3_bs = transceiver_dom_info_dict.get("tx3bias", "N/A") + tx4_bs = transceiver_dom_info_dict.get("tx4bias", "N/A") + return [tx1_bs, tx2_bs, tx3_bs, tx4_bs] if transceiver_dom_info_dict else [] + else: + return None + + def get_rx_power(self): + """ + Retrieves the received optical power for this SFP + Returns: + A list of four integer numbers, representing received optical + power in mW for channel 0 to channel 4. + Ex. ['1.77', '1.71', '1.68', '1.70'] + """ + transceiver_dom_info_dict = self.get_transceiver_bulk_status() + if transceiver_dom_info_dict is not None: + rx1_pw = transceiver_dom_info_dict.get("rx1power", "N/A") + rx2_pw = transceiver_dom_info_dict.get("rx2power", "N/A") + rx3_pw = transceiver_dom_info_dict.get("rx3power", "N/A") + rx4_pw = transceiver_dom_info_dict.get("rx4power", "N/A") + return [rx1_pw, rx2_pw, rx3_pw, rx4_pw] if transceiver_dom_info_dict else [] + else: + return None + + def get_tx_power(self): + """ + Retrieves the TX power of this SFP + Returns: + A list of four integer numbers, representing TX power in mW + for channel 0 to channel 4. + Ex. ['1.86', '1.86', '1.86', '1.86'] + """ + transceiver_dom_info_dict = self.get_transceiver_bulk_status() + if transceiver_dom_info_dict is not None: + tx1_pw = transceiver_dom_info_dict.get("tx1power", "N/A") + tx2_pw = transceiver_dom_info_dict.get("tx2power", "N/A") + tx3_pw = transceiver_dom_info_dict.get("tx3power", "N/A") + tx4_pw = transceiver_dom_info_dict.get("tx4power", "N/A") + return [tx1_pw, tx2_pw, tx3_pw, tx4_pw] + else: + return None + + def reset(self): + """ + Reset SFP and return all user module settings to their default srate. + Returns: + A boolean, True if successful, False if not + """ + status = False + if not self.get_presence(): + return status + + device = 'PORT{}'.format(self.port_index) + # TODO: Implement a wrapper set function to write the sequence + path = self.pddf_obj.get_path(device, 'xcvr_reset') + + # TODO: put the optic based reset logic using EEPROM + if path is None: + pass + else: + try: + f = open(path, 'r+') + except IOError as e: + return False + + try: + f.seek(0) + f.write('1') + time.sleep(1) + f.seek(0) + f.write('0') + + f.close() + status = True + except IOError as e: + status = False + + return status + + def tx_disable(self, tx_disable): + """ + Disable SFP TX for all channels + Args: + tx_disable : A Boolean, True to enable tx_disable mode, False to disable + tx_disable mode. + Returns: + A boolean, True if tx_disable is set successfully, False if not + """ + # find out a generic implementation of tx_disable for SFP, QSFP and OSFP + status = False + if not self.get_presence(): + return tx_disable + + device = 'PORT{}'.format(self.port_index) + path = self.pddf_obj.get_path(device, 'xcvr_txdisable') + + # TODO: put the optic based reset logic using EEPROM + if path is None: + if self.is_osfp_port: + pass + elif self.is_qsfp_port: + eeprom_f = None + try: + txdisable_ctl = 0xf if tx_disable else 0x0 + buf = create_string_buffer(1) + buf[0] = chr(txdisable_ctl) + # Write to eeprom + eeprom_f = open(self.eeprom_path, "r+b") + eeprom_f.seek(QSFP_CONTROL_OFFSET) + eeprom_f.write(buf[0]) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + finally: + if eeprom_f is not None: + eeprom_f.close() + time.sleep(0.01) + + status = True + else: + status_control_raw = self.__read_eeprom_specific_bytes( + SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH) + if status_control_raw is not None: + # Set bit 6 for Soft TX Disable Select + # 01000000 = 64 and 10111111 = 191 + txdisable_bit = 64 if tx_disable else 191 + status_control = int(status_control_raw[0], 16) + txdisable_ctl = (status_control | txdisable_bit) if tx_disable else ( + status_control & txdisable_bit) + try: + eeprom_f = open(self.eeprom_path, mode="r+b", buffering=0) + buf = create_string_buffer(1) + buf[0] = chr(txdisable_ctl) + # Write to eeprom + eeprom_f.seek(SFP_STATUS_CONTROL_OFFSET) + eeprom_f.write(buf[0]) + except Exception as e: + print("Error: unable to open file: %s" % str(e)) + return False + finally: + if eeprom_f: + eeprom_f.close() + time.sleep(0.01) + status = True + else: + try: + f = open(path, 'r+') + except IOError as e: + return False + + try: + if tx_disable: + f.write('1') + else: + f.write('0') + f.close() + status = True + except IOError as e: + status = False + + return status + + def tx_disable_channel(self, channel, disable): + """ + Sets the tx_disable for specified SFP channels + Args: + channel : A hex of 4 bits (bit 0 to bit 3) which represent channel 0 to 3, + e.g. 0x5 for channel 0 and channel 2. + disable : A boolean, True to disable TX channels specified in channel, + False to enable + Returns: + A boolean, True if successful, False if not + """ + # TODO: find a implementation + status = False + if not self.get_presence(): + return status + + if self.is_osfp_port: + pass + elif self.is_qsfp_port: + eeprom_f = None + try: + channel_state = self.get_tx_disable_channel() + txdisable_ctl = (channel_state | channel) if disable else (channel_state & ~channel) + buf = create_string_buffer(1) + buf[0] = chr(txdisable_ctl) + # Write to eeprom + eeprom_f = open(self.eeprom_path, "r+b") + eeprom_f.seek(QSFP_CONTROL_OFFSET) + eeprom_f.write(buf[0]) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + finally: + if eeprom_f is not None: + eeprom_f.close() + time.sleep(0.01) + status = True + else: + pass + + return status + + def set_lpmode(self, lpmode): + """ + Sets the lpmode (low power mode) of SFP + Args: + lpmode: A Boolean, True to enable lpmode, False to disable it + Note : lpmode can be overridden by set_power_override + Returns: + A boolean, True if lpmode is set successfully, False if not + """ + status = False + if not self.get_presence(): + return status + + device = 'PORT{}'.format(self.port_index) + path = self.pddf_obj.get_path(device, 'xcvr_lpmode') + + # TODO: put the optic based reset logic using EEPROM + if path is None: + if self.is_osfp_port: + pass + elif self.is_qsfp_port: + try: + eeprom_f = None + ctype = self.get_connector_type() + if ctype in ['Copper pigtail', 'No separable connector']: + return False + + # Fill in write buffer + regval = 0x3 if lpmode else 0x1 # 0x3:Low Power Mode, 0x1:High Power Mode + buffer = create_string_buffer(1) + buffer[0] = chr(regval) + + # Write to eeprom + eeprom_f = open(self.eeprom_path, "r+b") + eeprom_f.seek(93) + eeprom_f.write(buffer[0]) + return True + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + finally: + if eeprom_f is not None: + eeprom_f.close() + time.sleep(0.01) + else: + pass + + else: + try: + f = open(path, 'r+') + except IOError as e: + return False + + try: + if lpmode: + f.write('1') + else: + f.write('0') + + f.close() + status = True + except IOError as e: + status = False + + return status + + def set_power_override(self, power_override, power_set): + """ + Sets SFP power level using power_override and power_set + Args: + power_override : + A Boolean, True to override set_lpmode and use power_set + to control SFP power, False to disable SFP power control + through power_override/power_set and use set_lpmode + to control SFP power. + power_set : + Only valid when power_override is True. + A Boolean, True to set SFP to low power mode, False to set + SFP to high power mode. + Returns: + A boolean, True if power-override and power_set are set successfully, + False if not + """ + status = False + if not self.get_presence(): + return status + + if self.is_osfp_port: + pass + elif self.is_qsfp_port: + try: + power_override_bit = 0 + if power_override: + power_override_bit |= 1 << 0 + + power_set_bit = 0 + if power_set: + power_set_bit |= 1 << 1 + + buffer = create_string_buffer(1) + buffer[0] = chr(power_override_bit | power_set_bit) + # Write to eeprom + eeprom_f = open(self.eeprom_path, "r+b") + eeprom_f.seek(QSFP_POWEROVERRIDE_OFFSET) + eeprom_f.write(buffer[0]) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + finally: + if eeprom_f is not None: + eeprom_f.close() + time.sleep(0.01) + return True + else: + pass + + return status + + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + # Name of the port/sfp ? + return 'PORT{}'.format(self.port_index) + + def get_presence(self): + """ + Retrieves the presence of the PSU + Returns: + bool: True if PSU is present, False if not + """ + output = self.pddf_obj.get_attr_name_output(self.device, 'xcvr_present') + if not output: + return False + + mode = output['mode'] + modpres = output['status'].rstrip() + if 'XCVR' in self.plugin_data: + if 'xcvr_present' in self.plugin_data['XCVR']: + ptype = self.sfp_type + vtype = 'valmap-'+ptype + if vtype in self.plugin_data['XCVR']['xcvr_present'][mode]: + vmap = self.plugin_data['XCVR']['xcvr_present'][mode][vtype] + if modpres in vmap: + return vmap[modpres] + else: + return False + # if self.plugin_data doesn't specify anything regarding Transceivers + if modpres == '1': + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + transceiver_dom_info_dict = self.get_transceiver_info() + if transceiver_dom_info_dict is not None: + return transceiver_dom_info_dict.get("model", "N/A") + else: + return None + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + transceiver_dom_info_dict = self.get_transceiver_info() + if transceiver_dom_info_dict is not None: + return transceiver_dom_info_dict.get("serial", "N/A") + else: + return None + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + return self.get_presence() and self.get_transceiver_bulk_status() + + def get_connector_type(self): + """ + Retrieves the device connector type + Returns: + enum: connector_code + """ + transceiver_dom_info_dict = self.get_transceiver_info() + if transceiver_dom_info_dict is not None: + return transceiver_dom_info_dict.get("connector", "N/A") + else: + return None + + def get_transceiver_change_event(self): + """ + TODO: This function need to be implemented + when decide to support monitoring SFP(Xcvrd) + on this platform. + """ + raise NotImplementedError + + def dump_sysfs(self): + return self.pddf_obj.cli_dump_dsysfs('xcvr') diff --git a/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_thermal.py b/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_thermal.py new file mode 100755 index 0000000000..01cd4080db --- /dev/null +++ b/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_thermal.py @@ -0,0 +1,174 @@ +#!/usr/bin/env python + +# All the supported Temperature Sensor SysFS aattributes are +#- temp1_high_crit_threshold +#- temp1_high_threshold +#- temp1_input +#- temp_low_threshold +#- temp1_low_crit_threshold + +try: + from sonic_platform_base.thermal_base import ThermalBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + + +class PddfThermal(ThermalBase): + """PDDF generic Thermal class""" + pddf_obj = {} + plugin_data = {} + + def __init__(self, index, pddf_data=None, pddf_plugin_data=None): + if not pddf_data or not pddf_plugin_data: + raise ValueError('PDDF JSON data error') + + self.pddf_obj = pddf_data + self.plugin_data = pddf_plugin_data + + self.platform = self.pddf_obj.get_platform() + + self.thermal_index = index + 1 + self.thermal_obj_name = "TEMP{}".format(self.thermal_index) + self.thermal_obj = self.pddf_obj.data[self.thermal_obj_name] + + def get_name(self): + if 'dev_attr' in self.thermal_obj.keys(): + if 'display_name' in self.thermal_obj['dev_attr']: + return str(self.thermal_obj['dev_attr']['display_name']) + # In case of errors + return (self.thermal_obj_name) + + def get_temperature(self): + output = self.pddf_obj.get_attr_name_output(self.thermal_obj_name, "temp1_input") + if not output: + return None + + if output['status'].isalpha(): + attr_value = None + else: + attr_value = float(output['status']) + + if output['mode']=='bmc': + return attr_value + else: + return (attr_value/float(1000)) + + + def get_high_threshold(self): + output = self.pddf_obj.get_attr_name_output(self.thermal_obj_name, "temp1_high_threshold") + if not output: + return None + + if output['status'].isalpha(): + attr_value = None + else: + attr_value = float(output['status']) + + if output['mode']=='bmc': + return attr_value + else: + return (attr_value/float(1000)) + + + def get_low_threshold(self): + output = self.pddf_obj.get_attr_name_output(self.thermal_obj_name, "temp1_low_threshold") + if not output: + return None + + if output['status'].isalpha(): + attr_value = None + else: + attr_value = float(output['status']) + + if output['mode']=='bmc': + return attr_value + else: + return (attr_value/float(1000)) + + + def set_high_threshold(self, temperature): + node = self.pddf_obj.get_path(self.thermal_obj_name, "temp1_high_threshold") + if node is None: + print "ERROR %s does not exist"%node + return None + + cmd = "echo '%d' > %s"%(temperature * 1000, node) + os.system(cmd) + + return (True) + + + def set_low_threshold(self, temperature): + node = self.pddf_obj.get_path(self.thermal_obj_name, "temp1_low_threshold") + if node is None: + print "ERROR %s does not exist"%node + return None + cmd = "echo '%d' > %s"%(temperature * 1000, node) + os.system(cmd) + + return (True) + + def get_high_critical_threshold(self): + """ + Retrieves the high critical threshold temperature of thermal + + Returns: + A float number, the high critical threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + output = self.pddf_obj.get_attr_name_output(self.thermal_obj_name, "temp1_high_crit_threshold") + if not output: + return None + + if output['status'].isalpha(): + attr_value = None + else: + attr_value = float(output['status']) + + if output['mode']=='bmc': + return attr_value + else: + return (attr_value/float(1000)) + + + def get_low_critical_threshold(self): + """ + Retrieves the low critical threshold temperature of thermal + + Returns: + A float number, the low critical threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + output = self.pddf_obj.get_attr_name_output(self.thermal_obj_name, "temp1_low_crit_threshold") + if not output: + return None + + if output['status'].isalpha(): + attr_value = None + else: + attr_value = float(output['status']) + + if output['mode']=='bmc': + return attr_value + else: + return (attr_value/float(1000)) + + + # Helper Functions + def get_temp_label(self): + if 'bmc' in self.pddf_obj.data[self.thermal_obj_name].keys(): + return None + else: + if self.thermal_obj_name in self.pddf_obj.data.keys(): + dev= self.pddf_obj.data[self.thermal_obj_name] + topo_info = dev['i2c']['topo_info'] + label="%s-i2c-%d-%x" % (topo_info['dev_type'], int(topo_info['parent_bus'], 0), + int(topo_info['dev_addr'], 0)) + return (label) + else: + return None + + + def dump_sysfs(self): + return self.pddf_obj.cli_dump_dsysfs('temp-sensors') diff --git a/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddfparse.py b/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddfparse.py new file mode 100755 index 0000000000..aa47beaa0f --- /dev/null +++ b/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddfparse.py @@ -0,0 +1,1508 @@ +#!/usr/bin/env python +import glob +import json +from jsonschema import validate +import os +import re +import subprocess +import time +import unicodedata + +bmc_cache={} +cache={} +SONIC_CFGGEN_PATH = '/usr/local/bin/sonic-cfggen' +HWSKU_KEY = 'DEVICE_METADATA.localhost.hwsku' +PLATFORM_KEY = 'DEVICE_METADATA.localhost.platform' + +dirname=os.path.dirname(os.path.realpath(__file__)) + +color_map = { + "STATUS_LED_COLOR_GREEN" : "green", + "STATUS_LED_COLOR_RED" : "red", + "STATUS_LED_COLOR_AMBER" : "amber", + "STATUS_LED_COLOR_BLUE" : "blue", + "STATUS_LED_COLOR_GREEN_BLINK" : "blinking green", + "STATUS_LED_COLOR_RED_BLINK" : "blinking red", + "STATUS_LED_COLOR_AMBER_BLINK" : "blinking amber", + "STATUS_LED_COLOR_BLUE_BLINK" : "blinking blue", + "STATUS_LED_COLOR_OFF" : "off" +} + + +class PddfParse(): + def __init__(self): + if not os.path.exists("/usr/share/sonic/platform"): + self.platform, self.hwsku = self.get_platform_and_hwsku() + os.symlink("/usr/share/sonic/device/"+self.platform, "/usr/share/sonic/platform") + + try: + with open('/usr/share/sonic/platform/pddf/pddf-device.json') as f: + self.data = json.load(f) + except IOError: + if os.path.exists('/usr/share/sonic/platform'): + os.unlink("/usr/share/sonic/platform") + + + self.data_sysfs_obj={} + self.sysfs_obj={} + + + # Returns platform and HW SKU + def get_platform_and_hwsku(self): + try: + proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-H', '-v', PLATFORM_KEY], + stdout=subprocess.PIPE, + shell=False, + stderr=subprocess.STDOUT) + stdout = proc.communicate()[0] + proc.wait() + platform = stdout.rstrip('\n') + + proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-d', '-v', HWSKU_KEY], + stdout=subprocess.PIPE, + shell=False, + stderr=subprocess.STDOUT) + stdout = proc.communicate()[0] + proc.wait() + hwsku = stdout.rstrip('\n') + except OSError, e: + raise OSError("Cannot detect platform") + + return (platform, hwsku) + + ################################################################################################################# + # GENERIC DEFS + ################################################################################################################# + def runcmd(self, cmd): + rc = os.system(cmd) + if rc!=0: + print "%s -- command failed"%cmd + return rc + + def get_dev_idx(self, dev, ops): + parent=dev['dev_info']['virt_parent'] + pdev=self.data[parent] + + return pdev['dev_attr']['dev_idx'] + + + def get_path(self, target, attr): + aa = target + attr + + if aa in cache: + return cache[aa] + + string = None + p = re.search(r'\d+$', target) + if p is None: + for bb in filter(re.compile(target).search,self.data.keys()): + path = self.dev_parse(self.data[bb], { "cmd": "show_attr", "target":bb, "attr":attr }) + if path != "": + string = path + else: + if target in self.data.keys(): + path = self.dev_parse(self.data[target], { "cmd": "show_attr", "target":target, "attr":attr }) + if path != "": + string = path + + + if string is not None: + string = string.rstrip() + + cache[aa]=string + return string + + + def get_device_type(self, key): + if not key in self.data.keys(): + return None + return self.data[key]['dev_info']['device_type'] + + def get_platform(self): + return self.data['PLATFORM'] + + def get_num_psu_fans(self, dev): + if not dev in self.data.keys(): + return 0 + + if not 'num_psu_fans' in self.data[dev]['dev_attr']: + return 0 + + return self.data[dev]['dev_attr']['num_psu_fans'] + + def get_led_path(self): + return ("pddf/devices/led") + + def get_led_cur_state_path(self): + return ("pddf/devices/led/cur_state") + + def get_led_color(self): + color_f="/sys/kernel/pddf/devices/led/cur_state/color" + try: + with open(color_f, 'r') as f: + color = f.read().strip("\r\n") + except IOError: + return ("Error") + + return (color_map[color]) + + + def get_led_color_devtype(self, key): + attr_list=self.data[key]['i2c']['attr_list'] + for attr in attr_list: + if 'attr_devtype' in attr: + return attr['attr_devtype'].strip() + else: + return 'cpld' + + def get_led_color_from_gpio(self, led_device_name): + attr_list=self.data[led_device_name]['i2c']['attr_list'] + attr=attr_list[0] + if ':' in attr['bits']: + bits_list=attr['bits'].split(':') + bits_list.sort(reverse=True) + max_bit=int(bits_list[0]) + else: + max_bit=0 + base_offset=int(attr['swpld_addr_offset'], 16) + value = 0 + bit = 0 + while bit <= max_bit: + offset=base_offset + bit + if 'attr_devname' in attr: + attr_path = self.get_gpio_attr_path(self.data[attr['attr_devname']], hex(offset)) + else: + status= "[FAILED] attr_devname is not configured" + return (status) + if not os.path.exists(attr_path): + status= "[FAILED] {} does not exist".format(attr_path) + return (status) + cmd = 'cat ' + attr_path + gpio_value = subprocess.check_output(cmd, shell=True) + value |= int(gpio_value) << bit + bit += 1 + + for attr in attr_list: + if int(attr['value'].strip(), 16) == value: + return(color_map[attr['attr_name']]) + return (color_map['STATUS_LED_COLOR_OFF']) + + + def get_led_color_from_cpld(self, led_device_name): + index=self.data[led_device_name]['dev_attr']['index'] + device_name=self.data[led_device_name]['dev_info']['device_name'] + self.create_attr('device_name', device_name, self.get_led_path()) + self.create_attr('index', index, self.get_led_path()) + self.create_attr('dev_ops', 'get_status', self.get_led_path()) + return self.get_led_color() + + def set_led_color_from_gpio(self, led_device_name, color): + attr_list=self.data[led_device_name]['i2c']['attr_list'] + for attr in attr_list: + if attr['attr_name'].strip() == color.strip(): + base_offset=int(attr['swpld_addr_offset'], 16) + if ':' in attr['bits']: + bits_list=attr['bits'].split(':') + bits_list.sort(reverse=True) + max_bit = int(bits_list[0]) + else: + max_bit=0 + value=int(attr['value'], 16) + i = 0 + while i <= max_bit: + _value =(value>>i) & 1 + base_offset += i + attr_path = self.get_gpio_attr_path(self.data[attr['attr_devname']], hex(base_offset)) + i += 1 + try: + cmd = "echo {} > {}".format(_value, attr_path) + self.runcmd(cmd) + except Exception as e: + print "Invalid gpio path : " + attr_path + return (False) + return (True) + + def set_led_color_from_cpld(self, led_device_name, color): + index=self.data[led_device_name]['dev_attr']['index'] + device_name=self.data[led_device_name]['dev_info']['device_name'] + self.create_attr('device_name', device_name, self.get_led_path()) + self.create_attr('index', index, self.get_led_path()) + self.create_attr('color', color, self.get_led_cur_state_path()) + self.create_attr('dev_ops', 'set_status', self.get_led_path()) + return (True) + + + def get_system_led_color(self, led_device_name): + if (not led_device_name in self.data.keys()): + status= "[FAILED] " + led_device_name + " is not configured" + return (status) + + type = self.get_led_color_devtype(led_device_name) + + if type == 'gpio': + color = self.get_led_color_from_gpio(led_device_name) + elif type == 'cpld': + color = self.get_led_color_from_cpld(led_device_name) + return color + + def set_system_led_color(self, led_device_name, color): + result, msg = self.is_supported_sysled_state(led_device_name, color); + if result == False: + print msg + return (result) + + type = self.get_led_color_devtype(led_device_name) + + if type == 'gpio': + return (self.set_led_color_from_gpio(led_device_name, color)) + else: + return (self.set_led_color_from_cpld(led_device_name, color)) + + ################################################################################################################### + # SHOW ATTRIBIUTES DEFS + ################################################################################################################### + def is_led_device_configured(self, device_name, attr_name): + if device_name in self.data.keys(): + attr_list=self.data[device_name]['i2c']['attr_list'] + for attr in attr_list: + if attr['attr_name'].strip() == attr_name.strip(): + return (True) + return (False) + + + def show_device_sysfs(self, dev, ops): + parent=dev['dev_info']['device_parent'] + pdev=self.data[parent] + if pdev['dev_info']['device_parent'] == 'SYSTEM': + return "/sys/bus/i2c/devices/"+"i2c-%d"%int(pdev['i2c']['topo_info']['dev_addr'], 0) + return self.show_device_sysfs(pdev, ops) + "/" + "i2c-%d" % int(dev['i2c']['topo_info']['parent_bus'], 0) + + + # This is alid for 'at24' type of EEPROM devices. Only one attribtue 'eeprom' + def show_attr_eeprom_device(self, dev, ops): + str = "" + attr_name=ops['attr'] + attr_list=dev['i2c']['attr_list'] + KEY="eeprom" + dsysfs_path="" + + if not KEY in self.data_sysfs_obj: + self.data_sysfs_obj[KEY]=[] + + for attr in attr_list: + if attr_name == attr['attr_name'] or attr_name == 'all': + if 'drv_attr_name' in attr.keys(): + real_name = attr['drv_attr_name'] + else: + real_name = attr['attr_name'] + + dsysfs_path = self.show_device_sysfs(dev, ops) + \ + "/%d-00%x"%(int(dev['i2c']['topo_info']['parent_bus'], 0), + int(dev['i2c']['topo_info']['dev_addr'], 0)) + \ + "/%s"%real_name + if not dsysfs_path in self.data_sysfs_obj[KEY]: + self.data_sysfs_obj[KEY].append(dsysfs_path) + str += dsysfs_path+"\n" + return str + + def show_attr_gpio_device(self, dev, ops): + ret = "" + KEY="gpio" + if not KEY in self.data_sysfs_obj: + self.data_sysfs_obj[KEY]=[] + + return ret + + + def show_attr_mux_device(self, dev, ops): + ret = "" + KEY="mux" + if not KEY in self.data_sysfs_obj: + self.data_sysfs_obj[KEY]=[] + + return ret + + def get_gpio_attr_path(self, dev, offset): + base = int(dev['i2c']['dev_attr']['gpio_base'], 16) + port_num = base + int(offset, 16) + gpio_name = 'gpio'+str(port_num) + path = '/sys/class/gpio/'+gpio_name+'/value' + return path + + def show_attr_psu_i2c_device(self, dev, ops): + target=ops['target'] + attr_name=ops['attr'] + ret = "" + KEY="psu" + dsysfs_path="" + + if not KEY in self.data_sysfs_obj: + self.data_sysfs_obj[KEY]=[] + + if target == 'all' or target == dev['dev_info']['virt_parent'] : + attr_list=dev['i2c']['attr_list'] + for attr in attr_list: + if attr_name == attr['attr_name'] or attr_name == 'all' : + if 'attr_devtype' in attr.keys() and attr['attr_devtype'] == "gpio": + # Check and enable the gpio from class + attr_path = self.get_gpio_attr_path(self.data[attr['attr_devname']], attr['attr_offset']) + if (os.path.exists(attr_path)): + if not attr_path in self.data_sysfs_obj[KEY]: + self.data_sysfs_obj[KEY].append(attr_path) + ret += attr_path + '\n' + else: + if 'drv_attr_name' in attr.keys(): + real_name = attr['drv_attr_name'] + else: + real_name = attr['attr_name'] + + dsysfs_path = self.show_device_sysfs(dev, ops) + \ + "/%d-00%x" %(int(dev['i2c']['topo_info']['parent_bus'], 0), + int(dev['i2c']['topo_info']['dev_addr'], 0)) + \ + "/%s"%real_name + if not dsysfs_path in self.data_sysfs_obj[KEY]: + self.data_sysfs_obj[KEY].append(dsysfs_path) + ret += dsysfs_path+"\n" + return ret + + + def show_attr_psu_device(self, dev, ops): + return self.show_attr_psu_i2c_device(dev, ops ) + + + def show_attr_fan_device(self, dev, ops): + ret = "" + attr_name=ops['attr'] + attr_list=dev['i2c']['attr_list'] + KEY="fan" + dsysfs_path="" + + if not KEY in self.data_sysfs_obj: + self.data_sysfs_obj[KEY]=[] + + + for attr in attr_list: + if attr_name == attr['attr_name'] or attr_name == 'all': + if 'attr_devtype' in attr.keys() and attr['attr_devtype'] == "gpio": + # Check and enable the gpio from class + attr_path = self.get_gpio_attr_path(self.data[attr['attr_devname']], attr['attr_offset']) + if (os.path.exists(attr_path)): + if not attr_path in self.data_sysfs_obj[KEY]: + self.data_sysfs_obj[KEY].append(attr_path) + ret += attr_path + '\n' + else: + if 'drv_attr_name' in attr.keys(): + real_name = attr['drv_attr_name'] + else: + real_name = attr['attr_name'] + + dsysfs_path= self.show_device_sysfs(dev, ops) + \ + "/%d-00%x" %(int(dev['i2c']['topo_info']['parent_bus'], 0), + int(dev['i2c']['topo_info']['dev_addr'], 0)) + \ + "/%s"%real_name + if not dsysfs_path in self.data_sysfs_obj[KEY]: + self.data_sysfs_obj[KEY].append(dsysfs_path) + ret += dsysfs_path+"\n" + return ret + + # This is only valid for LM75 + def show_attr_temp_sensor_device(self, dev, ops): + str = "" + attr_name=ops['attr'] + attr_list=dev['i2c']['attr_list'] + KEY="temp-sensors" + dsysfs_path="" + + if not KEY in self.data_sysfs_obj: + self.data_sysfs_obj[KEY]=[] + + + for attr in attr_list: + if attr_name == attr['attr_name'] or attr_name == 'all': + path = self.show_device_sysfs(dev, ops)+"/%d-00%x/" %(int(dev['i2c']['topo_info']['parent_bus'], 0), + int(dev['i2c']['topo_info']['dev_addr'], 0)) + if 'drv_attr_name' in attr.keys(): + real_name = attr['drv_attr_name'] + else: + real_name = attr['attr_name'] + + if (os.path.exists(path)): + full_path = glob.glob(path + 'hwmon/hwmon*/' + real_name)[0] + dsysfs_path=full_path + if not dsysfs_path in self.data_sysfs_obj[KEY]: + self.data_sysfs_obj[KEY].append(dsysfs_path) + str += full_path + "\n" + return str + + def show_attr_sysstatus_device(self, dev, ops): + ret = "" + attr_name=ops['attr'] + attr_list=dev['attr_list'] + KEY="sys-status" + dsysfs_path="" + + if not KEY in self.data_sysfs_obj: + self.data_sysfs_obj[KEY]=[] + + + for attr in attr_list: + if attr_name == attr['attr_name'] or attr_name == 'all': + dsysfs_path = "/sys/kernel/pddf/devices/sysstatus/sysstatus_data/" + attr['attr_name'] + if not dsysfs_path in self.data_sysfs_obj[KEY]: + self.data_sysfs_obj[KEY].append(dsysfs_path) + ret += dsysfs_path+"\n" + return ret + + + def show_attr_xcvr_i2c_device(self, dev, ops): + target=ops['target'] + attr_name=ops['attr'] + ret = "" + dsysfs_path = "" + KEY="xcvr" + if not KEY in self.data_sysfs_obj: + self.data_sysfs_obj[KEY]=[] + + if target == 'all' or target == dev['dev_info']['virt_parent'] : + attr_list=dev['i2c']['attr_list'] + for attr in attr_list: + if attr_name == attr['attr_name'] or attr_name == 'all' : + if 'attr_devtype' in attr.keys() and attr['attr_devtype'] == "gpio": + # Check and enable the gpio from class + attr_path = self.get_gpio_attr_path(self.data[attr['attr_devname']], attr['attr_offset']) + if (os.path.exists(attr_path)): + if not attr_path in self.data_sysfs_obj[KEY]: + self.data_sysfs_obj[KEY].append(attr_path) + ret += attr_path + '\n' + else: + if 'drv_attr_name' in attr.keys(): + real_name = attr['drv_attr_name'] + else: + real_name = attr['attr_name'] + + dsysfs_path = self.show_device_sysfs(dev, ops) + \ + "/%d-00%x" %(int(dev['i2c']['topo_info']['parent_bus'], 0), + int(dev['i2c']['topo_info']['dev_addr'], 0)) + \ + "/%s"%real_name + if not dsysfs_path in self.data_sysfs_obj[KEY]: + self.data_sysfs_obj[KEY].append(dsysfs_path) + ret += dsysfs_path+"\n" + return ret + + + def show_attr_xcvr_device(self, dev, ops): + return self.show_attr_xcvr_i2c_device(dev, ops ) + + def show_attr_cpld_device(self, dev, ops): + ret = "" + KEY="cpld" + if not KEY in self.data_sysfs_obj: + self.data_sysfs_obj[KEY]=[] + + return ret + + + ################################################################################################################### + # SHOW DEFS + ################################################################################################################### + def check_led_cmds(self, key, ops): + name = ops['target']+'_LED' + if (ops['target']=='config' or ops['attr']=='all') or \ + (name==self.data[key]['dev_info']['device_name'] and + ops['attr']==self.data[key]['dev_attr']['index']): + return (True) + else: + return (False) + + def dump_sysfs_obj(self, obj, key_type): + if (key_type == 'keys'): + for key in obj.keys(): + print key + return + + for key in obj: + if (key == key_type or key_type == 'all'): + print key+":" + for entry in obj[key]: + print "\t"+entry + + def add_list_sysfs_obj(self, obj, KEY, list): + for sysfs in list: + if not sysfs in obj[KEY]: + obj[KEY].append(sysfs) + + def sysfs_attr(self, key, value, path, obj, obj_key): + sysfs_path="/sys/kernel/%s/%s"%(path, key) + if not sysfs_path in obj[obj_key]: + obj[obj_key].append(sysfs_path) + + + def sysfs_device(self, attr, path, obj, obj_key): + for key in attr.keys(): + sysfs_path="/sys/kernel/%s/%s"%(path, key) + if not sysfs_path in obj[obj_key]: + obj[obj_key].append(sysfs_path) + + def show_eeprom_device(self, dev, ops): + return + + + def show_mux_device(self, dev, ops): + KEY ='mux' + if not KEY in self.sysfs_obj: + self.sysfs_obj[KEY] = [] + self.sysfs_device(dev['i2c']['topo_info'], "pddf/devices/mux", self.sysfs_obj, KEY) + self.sysfs_device(dev['i2c']['dev_attr'], "pddf/devices/mux", self.sysfs_obj, KEY) + sysfs_path= "/sys/kernel/pddf/devices/mux/dev_ops" + if not sysfs_path in self.sysfs_obj[KEY]: + self.sysfs_obj[KEY].append(sysfs_path) + list=['/sys/kernel/pddf/devices/mux/i2c_type', + '/sys/kernel/pddf/devices/mux/i2c_name', + '/sys/kernel/pddf/devices/mux/error'] + self.add_list_sysfs_obj(self.sysfs_obj, KEY, list) + + def show_gpio_device(self, dev, ops): + KEY ='gpio' + if not KEY in self.sysfs_obj: + self.sysfs_obj[KEY] = [] + self.sysfs_device(dev['i2c']['topo_info'], "pddf/devices/gpio", self.sysfs_obj, KEY) + self.sysfs_device(dev['i2c']['dev_attr'], "pddf/devices/gpio", self.sysfs_obj, KEY) + sysfs_path= "/sys/kernel/pddf/devices/gpio/dev_ops" + if not sysfs_path in self.sysfs_obj[KEY]: + self.sysfs_obj[KEY].append(sysfs_path) + list=['/sys/kernel/pddf/devices/gpio/i2c_type', + '/sys/kernel/pddf/devices/gpio/i2c_name', + '/sys/kernel/pddf/devices/gpio/error'] + self.add_list_sysfs_obj(self.sysfs_obj, KEY, list) + + + def show_psu_i2c_device(self, dev, ops): + KEY ='psu' + path='pddf/devices/psu/i2c' + if dev['i2c']['topo_info']['dev_type'] in self.data['PLATFORM']['pddf_dev_types']['PSU']: + if not KEY in self.sysfs_obj: + self.sysfs_obj[KEY] = [] + self.sysfs_device(dev['i2c']['topo_info'], path, self.sysfs_obj, KEY) + sysfs_path = "/sys/kernel/pddf/devices/psu/i2c/psu_idx" + self.sysfs_obj[KEY].append(sysfs_path) + + for attr in dev['i2c']['attr_list']: + self.sysfs_device(attr, "pddf/devices/psu/i2c", self.sysfs_obj, KEY) + sysfs_path = "/sys/kernel/pddf/devices/psu/i2c/dev_ops" + if not sysfs_path in self.sysfs_obj[KEY]: + self.sysfs_obj[KEY].append(sysfs_path) + list=['/sys/kernel/pddf/devices/psu/i2c/i2c_type', + '/sys/kernel/pddf/devices/fan/i2c/i2c_name', + '/sys/kernel/pddf/devices/psu/i2c/error', + '/sys/kernel/pddf/devices/psu/i2c/attr_ops'] + self.add_list_sysfs_obj(self.sysfs_obj, KEY, list) + + + def show_psu_device(self, dev, ops): + self.show_psu_i2c_device(dev, ops ) + return + + def show_client_device(self): + KEY ='client' + if not KEY in self.sysfs_obj: + self.sysfs_obj[KEY] = [] + list=['/sys/kernel/pddf/devices/showall'] + self.add_list_sysfs_obj(self.sysfs_obj, KEY, list) + + + def show_fan_device(self, dev, ops): + KEY ='fan' + path='pddf/devices/fan/i2c' + if dev['i2c']['topo_info']['dev_type'] in self.data['PLATFORM']['pddf_dev_types']['FAN']: + if not KEY in self.sysfs_obj: + self.sysfs_obj[KEY] = [] + + self.sysfs_device(dev['i2c']['topo_info'], path, self.sysfs_obj, KEY) + self.sysfs_device(dev['i2c']['dev_attr'], path, self.sysfs_obj, KEY) + for attr in dev['i2c']['attr_list']: + self.sysfs_device(attr, path, self.sysfs_obj, KEY) + list=['/sys/kernel/pddf/devices/fan/i2c/i2c_type', + '/sys/kernel/pddf/devices/fan/i2c/i2c_name', + '/sys/kernel/pddf/devices/fan/i2c/error', + '/sys/kernel/pddf/devices/fan/i2c/attr_ops', + '/sys/kernel/pddf/devices/fan/i2c/dev_ops'] + self.add_list_sysfs_obj(self.sysfs_obj, KEY, list) + + + def show_temp_sensor_device(self, dev, ops): + return + + def show_sysstatus_device(self, dev, ops): + KEY ='sysstatus' + if not KEY in self.sysfs_obj: + self.sysfs_obj[KEY] = [] + for attr in dev['attr_list']: + self.sysfs_device(attr, "pddf/devices/sysstatus", self.sysfs_obj, KEY) + sysfs_path= "/sys/kernel/pddf/devices/sysstatus/attr_ops" + if not sysfs_path in self.sysfs_obj[KEY]: + self.sysfs_obj[KEY].append(sysfs_path) + + + def show_xcvr_i2c_device(self, dev, ops): + KEY ='xcvr' + if dev['i2c']['topo_info']['dev_type'] in self.data['PLATFORM']['pddf_dev_types']['PORT_MODULE']: + if not KEY in self.sysfs_obj: + self.sysfs_obj[KEY] = [] + self.sysfs_device(dev['i2c']['topo_info'], "pddf/devices/xcvr/i2c", self.sysfs_obj, KEY) + + for attr in dev['i2c']['attr_list']: + self.sysfs_device(attr, "pddf/devices/xcvr/i2c", self.sysfs_obj, KEY) + sysfs_path = "/sys/kernel/pddf/devices/xcvr/i2c/dev_ops" + if not sysfs_path in self.sysfs_obj[KEY]: + self.sysfs_obj[KEY].append(sysfs_path) + list=['/sys/kernel/pddf/devices/xcvr/i2c/i2c_type', + '/sys/kernel/pddf/devices/xcvr/i2c/i2c_name', + '/sys/kernel/pddf/devices/xcvr/i2c/error', + '/sys/kernel/pddf/devices/xcvr/i2c/attr_ops'] + self.add_list_sysfs_obj(self.sysfs_obj, KEY, list) + + + def show_xcvr_device(self, dev, ops): + self.show_xcvr_i2c_device(dev, ops ) + return + + def show_cpld_device(self, dev, ops): + KEY ='cpld' + if dev['i2c']['topo_info']['dev_type'] in self.data['PLATFORM']['pddf_dev_types']['CPLD']: + if not KEY in self.sysfs_obj: + self.sysfs_obj[KEY] = [] + self.sysfs_device(dev['i2c']['topo_info'], "pddf/devices/cpld", self.sysfs_obj, KEY) + sysfs_path= "/sys/kernel/pddf/devices/cpld/dev_ops" + if not sysfs_path in self.sysfs_obj[KEY]: + self.sysfs_obj[KEY].append(sysfs_path) + list=['/sys/kernel/pddf/devices/cpld/i2c_type', + '/sys/kernel/pddf/devices/cpld/i2c_name', + '/sys/kernel/pddf/devices/cpld/error'] + self.add_list_sysfs_obj(self.sysfs_obj, KEY, list) + + def show_led_platform_device(self, key, ops): + if ops['attr']=='all' or ops['attr']=='PLATFORM': + KEY='platform' + if not KEY in self.sysfs_obj: + self.sysfs_obj[KEY] = [] + path='pddf/devices/platform' + self.sysfs_attr('num_psus', self.data['PLATFORM']['num_psus'], path, self.sysfs_obj, KEY) + self.sysfs_attr('num_fantrays', self.data['PLATFORM']['num_fantrays'], path, self.sysfs_obj, KEY) + + def show_led_device(self, key, ops): + if self.check_led_cmds(key, ops): + KEY='led' + if not KEY in self.sysfs_obj: + self.sysfs_obj[KEY] = [] + path="pddf/devices/led" + for attr in self.data[key]['i2c']['attr_list']: + self.sysfs_attr('device_name', self.data[key]['dev_info']['device_name'],path,self.sysfs_obj,KEY) + self.sysfs_attr('swpld_addr', self.data[key]['dev_info']['device_name'],path,self.sysfs_obj,KEY) + self.sysfs_attr('swpld_addr_offset', self.data[key]['dev_info']['device_name'],path, + self.sysfs_obj, KEY) + self.sysfs_device(self.data[key]['dev_attr'], path, self.sysfs_obj, KEY) + for attr_key in attr.keys(): + attr_path="pddf/devices/led/" + attr['attr_name'] + if (attr_key != 'attr_name' and attr_key != 'swpld_addr' and attr_key != 'swpld_addr_offset'): + self.sysfs_attr(attr_key, attr[attr_key], attr_path, self.sysfs_obj, KEY) + sysfs_path="/sys/kernel/pddf/devices/led/dev_ops" + if not sysfs_path in self.sysfs_obj[KEY]: + self.sysfs_obj[KEY].append(sysfs_path) + list=['/sys/kernel/pddf/devices/led/cur_state/color', + '/sys/kernel/pddf/devices/led/cur_state/color_state'] + self.add_list_sysfs_obj(self.sysfs_obj, KEY, list) + + + def validate_xcvr_device(self, dev, ops): + devtype_list = ['optoe1', 'optoe2'] + dev_attribs = ['xcvr_present', 'xcvr_reset', 'xcvr_intr_status', 'xcvr_lpmode'] + ret_val = "xcvr validation failed" + + if dev['i2c']['topo_info']['dev_type'] in devtype_list: + for attr in dev['i2c']['attr_list']: + if 'attr_name' in attr.keys() and 'eeprom' in attr.values(): + ret_val = "xcvr validation success" + else: + print "xcvr validation Failed" + return + + elif dev['i2c']['topo_info']['dev_type'] in self.data['PLATFORM']['pddf_dev_types']['PORT_MODULE']: + for attr in dev['i2c']['attr_list']: + if attr.get("attr_name") in dev_attribs: + ret_val = "Success" + else: + print "xcvr validation Failed" + return + print ret_val + + def validate_eeprom_device(self, dev, ops): + devtype_list = ['24c02'] + dev_access_mode = ['BLOCK', 'BYTE'] + dev_attribs = ['eeprom'] + ret_val = "eeprom failed" + + if dev['i2c']['topo_info']['dev_type'] in devtype_list: + if dev['i2c']['dev_attr']['access_mode'] in dev_access_mode: + for attr in dev['i2c']['attr_list']: + if attr.get("attr_name") in dev_attribs: + ret_val = "eeprom success" + print ret_val + + def validate_mux_device(self, dev, ops): + devtype_list = ['pca9548', 'pca954x'] + dev_channels = ["0", "1", "2", "3", "4", "5", "6", "7"] + ret_val = "mux failed" + + if dev['i2c']['topo_info']['dev_type'] in devtype_list: + for attr in dev['i2c']['channel']: + if attr.get("chn") in dev_channels: + ret_val = "Mux success" + print ret_val + + def validate_cpld_device(self, dev, ops): + devtype_list = ['i2c_cpld'] + ret_val = "cpld failed" + + if dev['i2c']['topo_info']['dev_type'] in devtype_list: + ret_val = "cpld success" + print ret_val + + + def validate_sysstatus_device(self, dev, ops): + dev_attribs = ['board_info', 'cpld1_version', 'power_module_status', 'system_reset5', + 'system_reset6', 'system_reset7', 'misc1', 'cpld2_version', 'cpld3_version' + ] + ret_val = "sysstatus failed" + + if dev['dev_info']['device_type'] == "SYSSTAT": + for attr in dev['attr_list']: + if attr.get("attr_name") in dev_attribs: + ret_val = "sysstatus success" + print ret_val + + def validate_temp_sensor_device(self, dev, ops): + devtype_list = ['lm75'] + dev_attribs = ['temp1_max', 'temp1_max_hyst', 'temp1_input'] + ret_val = "temp sensor failed" + + if dev['dev_info']['device_type'] == "TEMP_SENSOR": + if dev['i2c']['topo_info']['dev_type'] in devtype_list: + for attr in dev['i2c']['attr_list']: + if attr.get("attr_name") in dev_attribs: + ret_val = "tempsensor success" + print ret_val + + def validate_fan_device(self, dev, ops): + ret_val = "fan failed" + + if dev['i2c']['topo_info']['dev_type'] in self.data['PLATFORM']['pddf_dev_types']['FAN']: + if dev['i2c']['dev_attr']['num_fan'] is not None: + ret_val = "fan success" + + print ret_val + + def validate_psu_device(self, dev, ops): + dev_attribs = ['psu_present', 'psu_model_name', 'psu_power_good', 'psu_mfr_id', 'psu_serial_num', + 'psu_fan_dir', 'psu_v_out', 'psu_i_out', 'psu_p_out', 'psu_fan1_speed_rpm' + ] + ret_val = "psu failed" + + if dev['i2c']['topo_info']['dev_type'] in self.data['PLATFORM']['pddf_dev_types']['PSU']: + for attr in dev['i2c']['attr_list']: + if attr.get("attr_name") in dev_attribs: + if attr.get("attr_devaddr") is not None: + if attr.get("attr_offset") is not None: + if attr.get("attr_mask") is not None: + if attr.get("attr_len") is not None: + ret_val = "psu success" + else: + ret_val = "psu failed" + + print ret_val + + ################################################################################################################### + # SPYTEST + ################################################################################################################### + def verify_attr(self, key, attr, path): + node="/sys/kernel/%s/%s"%(path, key) + try: + with open(node, 'r') as f: + status = f.read() + except IOError: + print "PDDF_VERIFY_ERR: IOError: node:%s key:%s"%(node, key) + return + + status=status.rstrip("\n\r") + if attr[key]!=status: + print "PDDF_VERIFY_ERR: node: %s switch:%s"%(node, status) + + def verify_device(self, attr, path, ops): + for key in attr.keys(): + self.verify_attr(key, attr, path) + + + def get_led_device(self, device_name): + self.create_attr('device_name', self.data[device_name]['dev_info']['device_name'], "pddf/devices/led") + self.create_attr('index', self.data[device_name]['dev_attr']['index'], "pddf/devices/led") + cmd="echo 'verify' > /sys/kernel/pddf/devices/led/dev_ops" + self.runcmd(cmd) + + def validate_sysfs_creation(self, obj, validate_type): + dir = '/sys/kernel/pddf/devices/'+validate_type + if (os.path.exists(dir) or validate_type=='client'): + for sysfs in obj[validate_type]: + if(not os.path.exists(sysfs)): + print "[SYSFS FILE] " + sysfs + ": does not exist" + else: + print "[SYSFS DIR] " + dir + ": does not exist" + + def validate_dsysfs_creation(self, obj, validate_type): + if validate_type in obj.keys(): + # There is a possibility that some components dont have any device-self.data attr + if not obj[validate_type]: + print "[SYSFS ATTR] for " + validate_type + ": empty" + else: + for sysfs in obj[validate_type]: + if(not os.path.exists(sysfs)): + print "[SYSFS FILE] " + sysfs + ": does not exist" + else: + print "[SYSFS DIR] " + dir + ": not configured" + + + + def verify_sysfs_data(self, verify_type): + if (verify_type=='LED'): + for key in self.data.keys(): + if key != 'PLATFORM': + attr=self.data[key]['dev_info'] + if attr['device_type'] == 'LED': + self.get_led_device(key) + self.verify_attr('device_name', self.data[key]['dev_info'], "pddf/devices/led") + self.verify_attr('index', self.data[key]['dev_attr'], "pddf/devices/led") + for attr in self.data[key]['i2c']['attr_list']: + path="pddf/devices/led/" + attr['attr_name'] + for entry in attr.keys(): + if (entry != 'attr_name' and entry != 'swpld_addr' and entry != 'swpld_addr_offset'): + self.verify_attr(entry, attr, path) + if ( entry == 'swpld_addr' or entry == 'swpld_addr_offset'): + self.verify_attr(entry, attr, 'pddf/devices/led') + + + + def schema_validation(self, validate_type): + process_validate_type = 0 + for key in self.data.keys(): + if (key != 'PLATFORM'): + temp_obj={} + schema_list=[] + try: + device_type=self.data[key]["dev_info"]["device_type"] + except Exception as e: + print "dev_info or device_type ERROR: " + key + print e + + if validate_type == 'mismatch': + process_validate_type = 1 + device_type="PSU" + schema_file="/usr/local/bin/schema/FAN.schema" + schema_list.append(schema_file) + elif validate_type == 'missing': + process_validate_type = 1 + schema_file="/usr/local/bin/schema/PLATFORM.schema" + schema_list.append(schema_file) + + elif validate_type == 'empty': + process_validate_type = 1 + if not device_type: + print "Empty device_type for " + key + continue + elif (validate_type=='all' or validate_type==device_type): + process_validate_type = 1 + if "bmc" in self.data[key].keys(): + schema_file="/usr/local/bin/schema/"+device_type + "_BMC.schema" + schema_list.append(schema_file) + + if "i2c" in self.data[key].keys(): + schema_file="/usr/local/bin/schema/"+device_type + ".schema" + schema_list.append(schema_file) + if device_type: + temp_obj[device_type]=self.data[key] + for schema_file in schema_list: + if (os.path.exists(schema_file)): + print "Validate " + schema_file + ";" + key + json_data=json.dumps(temp_obj) + with open(schema_file, 'r') as f: + schema=json.load(f) + try: + validate(temp_obj, schema) + except Exception as e: + print "Validation ERROR: " + schema_file + ";" + key + if validate_type == 'mismatch': + return + else: + print e + else: + print "ERROR Missing File: " + schema_file + if not process_validate_type: + print "device_type: " + validate_type + " not configured" + + def modules_validation(self, validate_type): + kos = [] + supported_type = False + module_validation_status=[] + + if validate_type == "bmc": + kos=['ipmi_devintf', 'ipmi_si', 'ipmi_msghandler'] + validate_type = 'ipmi' + else: + # generate the KOS list from pddf device JSON file + kos.extend(self.data['PLATFORM']['pddf_kos']) + + if 'custom_kos' in self.data['PLATFORM']: + kos.extend(self.data['PLATFORM']['custom_kos']) + + for mod in kos: + if validate_type in mod or validate_type == "pddf": + supported_type=True + cmd = "lsmod | grep " + mod + try: + subprocess.check_output(cmd, shell=True) + except Exception as e: + module_validation_status.append(mod) + if supported_type: + if module_validation_status: + module_validation_status.append(":ERROR not loaded") + print str(module_validation_status)[1:-1] + else: + print "Loaded" + else: + print validate_type + " not configured" + + + + ################################################################################################################### + # PARSE DEFS + ################################################################################################################### + def psu_parse(self, dev, ops): + parse_str="" + ret="" + for ifce in dev['i2c']['interface']: + ret=getattr(self, ops['cmd']+"_psu_device")(self.data[ifce['dev']], ops ) + if not ret is None: + if str(ret).isdigit(): + if ret!=0: + # in case if 'create' functions + print "{}_psu_device failed".format(ops['cmd']) + return ret + else: + pass + else: + # in case of 'show_attr' functions + parse_str+=ret + return parse_str + + def fan_parse(self, dev, ops): + parse_str="" + ret=getattr(self, ops['cmd']+"_fan_device")(dev, ops ) + if not ret is None: + if str(ret).isdigit(): + if ret!=0: + # in case if 'create' functions + print "{}_fan_device failed".format(ops['cmd']) + return ret + else: + pass + else: + # in case of 'show_attr' functions + parse_str+=ret + + return parse_str + + def temp_sensor_parse(self, dev, ops): + parse_str="" + ret=getattr(self, ops['cmd']+"_temp_sensor_device")(dev, ops ) + if not ret is None: + if str(ret).isdigit() : + if ret!=0: + # in case if 'create' functions + print "{}_temp_sensor_device failed".format(ops['cmd']) + return ret + else: + pass + else: + # in case of 'show_attr' functions + parse_str+=ret + + return parse_str + + def cpld_parse(self, dev, ops): + parse_str = "" + ret = getattr(self, ops['cmd']+"_cpld_device")(dev, ops) + if not ret is None: + if str(ret).isdigit(): + if ret!=0: + # in case if 'create' functions + print "{}_cpld_device failed".format(ops['cmd']) + return ret + else: + pass + else: + # in case of 'show_attr' functions + parse_str+=ret + + return parse_str + + + + + def sysstatus_parse(self, dev,ops): + parse_str = "" + ret = getattr(self, ops['cmd']+"_sysstatus_device")(dev, ops) + if not ret is None: + if str(ret).isdigit(): + if ret!=0: + # in case if 'create' functions + print "{}_sysstatus_device failed".format(ops['cmd']) + return ret + else: + pass + else: + # in case of 'show_attr' functions + parse_str+=ret + + return parse_str + + def gpio_parse(self, dev, ops): + parse_str = "" + ret = getattr(self, ops['cmd']+"_gpio_device")(dev, ops) + if not ret is None: + if str(ret).isdigit(): + if ret!=0: + # in case if 'create' functions + print "{}_temp_sensor_device failed".format(ops['cmd']) + return ret + else: + pass + else: + # in case of 'show_attr' functions + parse_str += ret + + return parse_str + + + def mux_parse(self, dev, ops): + parse_str = "" + ret = getattr(self, ops['cmd']+"_mux_device")(dev, ops) + if not ret is None: + if str(ret).isdigit(): + if ret!=0: + # in case if 'create' functions + print "{}_mux_device() cmd failed".format(ops['cmd']) + return ret + else: + pass + else: + parse_str += ret + + for ch in dev['i2c']['channel']: + ret = self.dev_parse(self.data[ch['dev']], ops) + if not ret is None: + if str(ret).isdigit(): + if ret!=0: + # in case if 'create' functions + return ret + else: + pass + else: + parse_str += ret + return parse_str + + def mux_parse_reverse(self, dev, ops): + parse_str = "" + for ch in reversed(dev['i2c']['channel']): + ret = self.dev_parse(self.data[ch['dev']], ops) + if not ret is None: + if str(ret).isdigit(): + if ret!=0: + # in case if 'create' functions + return ret + else: + pass + else: + parse_str += ret + + ret = getattr(self, ops['cmd']+"_mux_device")(dev, ops) + if not ret is None: + if str(ret).isdigit(): + if ret!=0: + # in case if 'create' functions + print "{}_mux_device() cmd failed".format(ops['cmd']) + return ret + else: + pass + else: + parse_str += ret + + return parse_str + + + def eeprom_parse(self, dev, ops): + parse_str = "" + ret = getattr(self, ops['cmd']+"_eeprom_device")(dev, ops) + if not ret is None: + if str(ret).isdigit(): + if ret!=0: + # in case if 'create' functions + print "{}_eeprom_device() cmd failed".format(ops['cmd']) + return ret + else: + pass + else: + parse_str += ret + + return parse_str + + def optic_parse(self, dev, ops): + parse_str="" + ret="" + for ifce in dev['i2c']['interface']: + ret=getattr(self, ops['cmd']+"_xcvr_device")(self.data[ifce['dev']], ops ) + if not ret is None: + if str(ret).isdigit(): + if ret!=0: + # in case if 'create' functions + print "{}_eeprom_device() cmd failed".format(ops['cmd']) + return ret + else: + pass + else: + parse_str+=ret + return parse_str + + def cpu_parse(self, bus, ops): + parse_str = "" + for dev in bus['i2c']['CONTROLLERS']: + dev1 = self.data[dev['dev']] + for d in dev1['i2c']['DEVICES']: + ret=self.dev_parse(self.data[d['dev']], ops) + if not ret is None: + if str(ret).isdigit(): + if ret!=0: + # in case if 'create' functions + return ret + else: + pass + else: + parse_str += ret + return parse_str + + def cpu_parse_reverse(self, bus, ops): + parse_str = "" + for dev in reversed(bus['i2c']['CONTROLLERS']): + dev1 = self.data[dev['dev']] + for d in dev1['i2c']['DEVICES']: + ret=self.dev_parse(self.data[d['dev']], ops) + if not ret is None: + if str(ret).isdigit(): + if ret!=0: + # in case if 'create' functions + return ret + else: + pass + else: + parse_str += ret + return parse_str + + + def dev_parse(self, dev, ops): + attr=dev['dev_info'] + if attr['device_type'] == 'CPU': + if ops['cmd']=='delete': + return self.cpu_parse_reverse(dev, ops) + else: + return self.cpu_parse(dev, ops) + + if attr['device_type'] == 'EEPROM': + return self.eeprom_parse(dev, ops) + + if attr['device_type'] == 'MUX': + if ops['cmd']=='delete': + return self.mux_parse_reverse(dev, ops) + else: + return self.mux_parse(dev, ops) + + if attr['device_type'] == 'GPIO': + return self.gpio_parse(dev, ops) + + if attr['device_type'] == 'PSU': + return self.psu_parse(dev, ops) + + if attr['device_type'] == 'FAN': + return self.fan_parse(dev, ops) + + if attr['device_type'] == 'TEMP_SENSOR': + return self.temp_sensor_parse(dev, ops) + + if attr['device_type'] == 'SFP' or attr['device_type'] == 'QSFP' or \ + attr['device_type'] == 'SFP28' or attr['device_type'] == 'QSFP28' or \ + attr['device_type'] == 'QSFP-DD': + return self.optic_parse(dev, ops) + + if attr['device_type'] == 'CPLD': + return self.cpld_parse(dev, ops) + + if attr['device_type'] == 'SYSSTAT': + return self.sysstatus_parse(dev,ops) + + def is_supported_sysled_state(self, sysled_name, sysled_state): + if not sysled_name in self.data.keys(): + return False, "[FAILED] " + sysled_name + " is not configured" + for attr in self.data[sysled_name]['i2c']['attr_list']: + if attr['attr_name'] == sysled_state: + return True, "supported" + return False, "[FAILED]: Invalid color" + + def create_attr(self, key, value, path): + cmd = "echo '%s' > /sys/kernel/%s/%s"%(value, path, key) + self.runcmd(cmd) + + def create_led_platform_device(self, key, ops): + if ops['attr']=='all' or ops['attr']=='PLATFORM': + path='pddf/devices/platform' + self.create_attr('num_psus', self.data['PLATFORM']['num_psus'], path) + self.create_attr('num_fantrays', self.data['PLATFORM']['num_fantrays'], path) + + def create_led_device(self, key, ops): + if ops['attr']=='all' or ops['attr']==self.data[key]['dev_info']['device_name']: + path="pddf/devices/led" + for attr in self.data[key]['i2c']['attr_list']: + self.create_attr('device_name', self.data[key]['dev_info']['device_name'], path) + self.create_device(self.data[key]['dev_attr'], path, ops) + for attr_key in attr.keys(): + if (attr_key == 'swpld_addr_offset' or attr_key == 'swpld_addr'): + self.create_attr(attr_key, attr[attr_key], path) + elif (attr_key != 'attr_name' and attr_key != 'descr' and attr_key != 'attr_devtype' and + attr_key != 'attr_devname'): + state_path=path+'/state_attr' + self.create_attr(attr_key, attr[attr_key],state_path) + cmd="echo '" + attr['attr_name']+"' > /sys/kernel/pddf/devices/led/dev_ops" + self.runcmd(cmd) + + + def led_parse(self, ops): + getattr(self, ops['cmd']+"_led_platform_device")("PLATFORM", ops) + for key in self.data.keys(): + if key != 'PLATFORM' and 'dev_info' in self.data[key]: + attr=self.data[key]['dev_info'] + if attr['device_type'] == 'LED': + getattr(self, ops['cmd']+"_led_device")(key, ops) + + + def get_device_list(self, list, type): + for key in self.data.keys(): + if key != 'PLATFORM' and 'dev_info' in self.data[key]: + attr=self.data[key]['dev_info'] + if attr['device_type'] == type: + list.append(self.data[key]) + + + def create_pddf_devices(self): + self.led_parse({ "cmd": "create", "target":"all", "attr":"all" }) + create_ret = 0 + create_ret = self.dev_parse(self.data['SYSTEM'], { "cmd": "create", "target":"all", "attr":"all" } ) + if create_ret!=0: + return create_ret + if 'SYSSTATUS' in self.data: + create_ret = self.dev_parse(self.data['SYSSTATUS'], { "cmd": "create", "target":"all", "attr":"all" } ) + if create_ret!=0: + return create_ret + + def delete_pddf_devices(self): + self.dev_parse(self.data['SYSTEM'], { "cmd": "delete", "target":"all", "attr":"all" } ) + if 'SYSSTATUS' in self.data: + self.dev_parse(self.data['SYSSTATUS'], { "cmd": "delete", "target":"all", "attr":"all" } ) + + def populate_pddf_sysfsobj(self): + self.dev_parse(self.data['SYSTEM'], { "cmd": "show", "target":"all", "attr":"all" } ) + if 'SYSSTATUS' in self.data: + self.dev_parse(self.data['SYSSTATUS'], { "cmd": "show", "target":"all", "attr":"all" } ) + self.led_parse({ "cmd": "show", "target":"all", "attr":"all" }) + self.show_client_device() + + def cli_dump_dsysfs(self, component): + self.dev_parse(self.data['SYSTEM'], { "cmd": "show_attr", "target":"all", "attr":"all" } ) + if 'SYSSTATUS' in self.data: + self.dev_parse(self.data['SYSSTATUS'], { "cmd": "show_attr", "target":"all", "attr":"all" } ) + if component in self.data_sysfs_obj: + return self.data_sysfs_obj[component] + else: + return None + + + def validate_pddf_devices(self, *args): + self.populate_pddf_sysfsobj() + v_ops = { 'cmd': 'validate', 'target':'all', 'attr':'all' } + self.dev_parse(self.data['SYSTEM'], v_ops ) + + ################################################################################################################### + # BMC APIs + ################################################################################################################### + def populate_bmc_cache_db(self, bmc_attr): + bmc_cmd = str(bmc_attr['bmc_cmd']).strip() + + o_list = subprocess.check_output(bmc_cmd, shell=True).strip().split('\n') + bmc_cache[bmc_cmd]={} + bmc_cache[bmc_cmd]['time']=time.time() + for entry in o_list: + name = entry.split()[0] + bmc_cache[bmc_cmd][name]=entry + + def non_raw_ipmi_get_request(self, bmc_attr): + bmc_db_update_time=1 + value = 'N/A' + bmc_cmd = str(bmc_attr['bmc_cmd']).strip() + field_name = str(bmc_attr['field_name']).strip() + field_pos= int(bmc_attr['field_pos'])-1 + + if not bmc_cmd in bmc_cache: + self.populate_bmc_cache_db(bmc_attr) + else: + now = time.time() + if (int(now - bmc_cache[bmc_cmd]['time']) > bmc_db_update_time): + self.populate_bmc_cache_db(bmc_attr) + + try: + data=bmc_cache[bmc_cmd][field_name] + value = data.split()[field_pos] + except Exception as e: + pass + + if 'mult' in bmc_attr.keys() and not value.isalpha(): + if value.isalpha(): + value = 0.0 + value = float(value) * float(bmc_attr['mult']) + + return str(value) + + def raw_ipmi_get_request(self, bmc_attr): + value = 'N/A' + cmd = bmc_attr['bmc_cmd'] + " 2>/dev/null" + if bmc_attr['type'] == 'raw': + try: + value = subprocess.check_output(cmd, shell=True).strip() + except Exception as e: + pass + + if value != 'N/A': + value = str(int(value, 16)) + return value + + if bmc_attr['type'] == 'mask': + mask = int(bmc_attr['mask'].encode('utf-8'), 16) + try: + value = subprocess.check_output(cmd, shell=True).strip() + except Exception as e: + pass + + if value != 'N/A': + value = str(int(value, 16) & mask) + + return value + + if bmc_attr['type'] == 'ascii': + try: + value = subprocess.check_output(cmd, shell=True) + except Exception as e: + pass + + if value != 'N/A': + tmp = ''.join(chr(int(i, 16)) for i in value.split()) + tmp = "".join(i for i in unicode(tmp) if unicodedata.category(i)[0]!="C") + value = str(tmp) + + return (value) + + return value + + def bmc_get_cmd(self, bmc_attr): + if int(bmc_attr['raw']) == 1: + value = self.raw_ipmi_get_request(bmc_attr) + else: + value = self.non_raw_ipmi_get_request(bmc_attr) + return (value) + + def non_raw_ipmi_set_request(self, bmc_attr, val): + value = 'N/A' + # TODO: Implement it + return value + + def raw_ipmi_set_request(self, bmc_attr, val): + value = 'N/A' + # TODO: Implement this + return value + + def bmc_set_cmd(self, bmc_attr, val): + if int(bmc_attr['raw']) == 1: + value = self.raw_ipmi_set_request(bmc_attr, val) + else: + value = self.non_raw_ipmi_set_request(bmc_attr, val) + return (value) + + # bmc-based attr: return attr obj + # non-bmc-based attr: return empty obj + def check_bmc_based_attr(self, device_name, attr_name): + if device_name in self.data.keys(): + if "bmc" in self.data[device_name].keys() and 'ipmitool' in self.data[device_name]['bmc'].keys(): + attr_list = self.data[device_name]['bmc']['ipmitool']['attr_list'] + for attr in attr_list: + if attr['attr_name'].strip() == attr_name.strip(): + return attr + # Required attr_name is not supported in BMC object + return {} + return None + + def get_attr_name_output(self, device_name, attr_name): + bmc_attr = self.check_bmc_based_attr(device_name, attr_name) + output={"mode":"", "status":""} + + if bmc_attr is not None: + if bmc_attr=={}: + return {} + output['mode']="bmc" + output['status']=self.bmc_get_cmd(bmc_attr) + else: + output['mode']="i2c" + node = self.get_path(device_name, attr_name) + if node is None: + return {} + try: + with open(node, 'r') as f: + output['status'] = f.read() + except IOError: + return {} + return output + + def set_attr_name_output(self, device_name, attr_name, val): + bmc_attr = self.check_bmc_based_attr(device_name, attr_name) + output={"mode":"", "status":""} + + if bmc_attr is not None: + if bmc_attr=={}: + return {} + output['mode']="bmc" + output['status']=False # No set operation allowed for BMC attributes as they are handled by BMC itself + else: + output['mode']="i2c" + node = self.get_path(device_name, attr_name) + if node is None: + return {} + try: + with open(node, 'w') as f: + f.write(str(val)) + except IOError: + return {} + + output['status'] = True + + return output + diff --git a/platform/pddf/platform-api-pddf-base/sonic_platform_ref/__init__.py b/platform/pddf/platform-api-pddf-base/sonic_platform_ref/__init__.py new file mode 100644 index 0000000000..d9a604cf81 --- /dev/null +++ b/platform/pddf/platform-api-pddf-base/sonic_platform_ref/__init__.py @@ -0,0 +1,7 @@ +# All the derived classes for PDDF +__all__ = ["platform", "chassis", "sfp", "psu", "thermal"] + +# Commenting the below code as this just for the reference for the ODMs. +# It can be uncommented when this reference code is used + +#from sonic_platform import * diff --git a/platform/pddf/platform-api-pddf-base/sonic_platform_ref/chassis.py b/platform/pddf/platform-api-pddf-base/sonic_platform_ref/chassis.py new file mode 100644 index 0000000000..72f1858a77 --- /dev/null +++ b/platform/pddf/platform-api-pddf-base/sonic_platform_ref/chassis.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python + +############################################################################# +# PDDF +# Module contains an implementation of SONiC Chassis API +# +############################################################################# + +try: + from sonic_platform_pddf_base.pddf_chassis import PddfChassis +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +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) + + # Provide the functions/variables below for which implementation is to be overwritten diff --git a/platform/pddf/platform-api-pddf-base/sonic_platform_ref/eeprom.py b/platform/pddf/platform-api-pddf-base/sonic_platform_ref/eeprom.py new file mode 100644 index 0000000000..4857895c2a --- /dev/null +++ b/platform/pddf/platform-api-pddf-base/sonic_platform_ref/eeprom.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python + +try: + from sonic_platform_pddf_base.pddf_eeprom import PddfEeprom +except ImportError, 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 diff --git a/platform/pddf/platform-api-pddf-base/sonic_platform_ref/fan.py b/platform/pddf/platform-api-pddf-base/sonic_platform_ref/fan.py new file mode 100644 index 0000000000..027a2f4a61 --- /dev/null +++ b/platform/pddf/platform-api-pddf-base/sonic_platform_ref/fan.py @@ -0,0 +1,17 @@ +#!/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 diff --git a/platform/pddf/platform-api-pddf-base/sonic_platform_ref/platform.py b/platform/pddf/platform-api-pddf-base/sonic_platform_ref/platform.py new file mode 100644 index 0000000000..406b1179ae --- /dev/null +++ b/platform/pddf/platform-api-pddf-base/sonic_platform_ref/platform.py @@ -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 diff --git a/platform/pddf/platform-api-pddf-base/sonic_platform_ref/psu.py b/platform/pddf/platform-api-pddf-base/sonic_platform_ref/psu.py new file mode 100644 index 0000000000..edd747e996 --- /dev/null +++ b/platform/pddf/platform-api-pddf-base/sonic_platform_ref/psu.py @@ -0,0 +1,16 @@ +#!/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""" + + 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 diff --git a/platform/pddf/platform-api-pddf-base/sonic_platform_ref/sfp.py b/platform/pddf/platform-api-pddf-base/sonic_platform_ref/sfp.py new file mode 100644 index 0000000000..9588db5328 --- /dev/null +++ b/platform/pddf/platform-api-pddf-base/sonic_platform_ref/sfp.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python + +try: + from sonic_platform_pddf_base.pddf_sfp import PddfSfp +except ImportError, 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 diff --git a/platform/pddf/platform-api-pddf-base/sonic_platform_ref/thermal.py b/platform/pddf/platform-api-pddf-base/sonic_platform_ref/thermal.py new file mode 100644 index 0000000000..5b829fc26c --- /dev/null +++ b/platform/pddf/platform-api-pddf-base/sonic_platform_ref/thermal.py @@ -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 diff --git a/platform/pddf/platform-modules-pddf.dep b/platform/pddf/platform-modules-pddf.dep new file mode 100644 index 0000000000..19a4bb3447 --- /dev/null +++ b/platform/pddf/platform-modules-pddf.dep @@ -0,0 +1,10 @@ + +MPATH := $($(PDDF_PLATFORM_MODULE)_SRC_PATH) +DEP_FILES := $(SONIC_COMMON_FILES_LIST) platform/pddf/platform-modules-pddf.mk platform/pddf/platform-modules-pddf.dep +DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST) +DEP_FILES += $(shell git ls-files $(MPATH)) + +$(PDDF_PLATFORM_MODULE)_CACHE_MODE := GIT_CONTENT_SHA +$(PDDF_PLATFORM_MODULE)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST) +$(PDDF_PLATFORM_MODULE)_DEP_FILES := $(DEP_FILES) + diff --git a/platform/pddf/platform-modules-pddf.mk b/platform/pddf/platform-modules-pddf.mk new file mode 100644 index 0000000000..5947c18065 --- /dev/null +++ b/platform/pddf/platform-modules-pddf.mk @@ -0,0 +1,12 @@ +# PDDF Generic Platform modules +#################################################### +PDDF_PLATFORM_MODULE_VERSION = 1.1 + +export PDDF_PLATFORM_MODULE_VERSION + +PDDF_PLATFORM_MODULE = sonic-platform-pddf_$(PDDF_PLATFORM_MODULE_VERSION)_amd64.deb +$(PDDF_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PDDF_PATH)/i2c +$(PDDF_PLATFORM_MODULE)_DEPENDS += $(LINUX_HEADERS) $(LINUX_HEADERS_COMMON) +SONIC_DPKG_DEBS += $(PDDF_PLATFORM_MODULE) + +SONIC_STRETCH_DEBS += $(PDDF_PLATFORM_MODULE) diff --git a/platform/pddf/rules.dep b/platform/pddf/rules.dep new file mode 100644 index 0000000000..de40f6e88c --- /dev/null +++ b/platform/pddf/rules.dep @@ -0,0 +1,3 @@ +#DPKG FRK +include $(PLATFORM_PDDF_PATH)/platform-modules-pddf.dep +include $(PLATFORM_PDDF_PATH)/platform-api-pddf-base.dep diff --git a/platform/pddf/rules.mk b/platform/pddf/rules.mk new file mode 100644 index 0000000000..6c2fdfb89b --- /dev/null +++ b/platform/pddf/rules.mk @@ -0,0 +1,3 @@ +include $(PLATFORM_PDDF_PATH)/platform-modules-pddf.mk +include $(PLATFORM_PDDF_PATH)/platform-api-pddf-base.mk + diff --git a/rules/config b/rules/config index 8cffedc4e9..8f486d8170 100644 --- a/rules/config +++ b/rules/config @@ -63,6 +63,10 @@ DEFAULT_PASSWORD = YourPaSsWoRd # Uncomment next line to enable: # INSTALL_DEBUG_TOOLS = y +# SONIC_USE_PDDF_FRAMEWORK - Use PDDF generic drivers and plugins +# Uncomment next line to enable: +SONIC_USE_PDDF_FRAMEWORK = y + # SONIC_ROUTING_STACK - specify the routing-stack being elected to drive SONiC's control-plane. # Supported routing stacks on SONiC are: # routing-stacks: quagga, frr. diff --git a/rules/docker-platform-monitor.mk b/rules/docker-platform-monitor.mk index 75a22425fd..afe27d70e4 100644 --- a/rules/docker-platform-monitor.mk +++ b/rules/docker-platform-monitor.mk @@ -23,6 +23,9 @@ $(DOCKER_PLATFORM_MONITOR)_PYTHON_WHEELS += $(SONIC_PSUD) $(DOCKER_PLATFORM_MONITOR)_PYTHON_WHEELS += $(SONIC_SYSEEPROMD) $(DOCKER_PLATFORM_MONITOR)_PYTHON_WHEELS += $(SONIC_THERMALCTLD) $(DOCKER_PLATFORM_MONITOR)_PYTHON_WHEELS += $(SONIC_XCVRD) +ifeq ($(PDDF_SUPPORT),y) +$(DOCKER_PLATFORM_MONITOR)_PYTHON_WHEELS += $(PDDF_PLATFORM_API_BASE_PY2) +endif $(DOCKER_PLATFORM_MONITOR)_DBG_DEPENDS = $($(DOCKER_CONFIG_ENGINE_BUSTER)_DBG_DEPENDS) $(DOCKER_PLATFORM_MONITOR)_DBG_DEPENDS += $(LIBSWSSCOMMON_DBG) $(LIBSENSORS_DBG) @@ -42,6 +45,7 @@ $(DOCKER_PLATFORM_MONITOR)_CONTAINER_NAME = pmon $(DOCKER_PLATFORM_MONITOR)_RUN_OPT += --privileged -t $(DOCKER_PLATFORM_MONITOR)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro $(DOCKER_PLATFORM_MONITOR)_RUN_OPT += -v /var/run/platform_cache:/var/run/platform_cache:ro +$(DOCKER_PLATFORM_MONITOR)_RUN_OPT += -v /usr/share/sonic/device/pddf:/usr/share/sonic/device/pddf:ro # Mount Arista python library on Aboot images to be used by plugins $(DOCKER_PLATFORM_MONITOR)_aboot_RUN_OPT += -v /usr/lib/python2.7/dist-packages/arista:/usr/lib/python2.7/dist-packages/arista:ro diff --git a/slave.mk b/slave.mk index f7b3636d1a..a959936f1a 100644 --- a/slave.mk +++ b/slave.mk @@ -138,8 +138,21 @@ endif include $(RULES_PATH)/functions + +ifeq ($(SONIC_USE_PDDF_FRAMEWORK),y) +PDDF_SUPPORT = y +else +PDDF_SUPPORT = n +endif +export PDDF_SUPPORT + include $(RULES_PATH)/*.mk ifneq ($(CONFIGURED_PLATFORM), undefined) +ifeq ($(PDDF_SUPPORT), y) +PDDF_DIR = pddf +PLATFORM_PDDF_PATH = platform/$(PDDF_DIR) +include $(PLATFORM_PDDF_PATH)/rules.mk +endif include $(PLATFORM_PATH)/rules.mk endif @@ -237,6 +250,7 @@ $(info "INCLUDE_SFLOW" : "$(INCLUDE_SFLOW)") $(info "INCLUDE_NAT" : "$(INCLUDE_NAT)") $(info "INCLUDE_KUBERNETES" : "$(INCLUDE_KUBERNETES)") $(info "TELEMETRY_WRITABLE" : "$(TELEMETRY_WRITABLE)") +$(info "PDDF_SUPPORT" : "$(PDDF_SUPPORT)") $(info ) else $(info SONiC Build System for $(CONFIGURED_PLATFORM):$(CONFIGURED_ARCH)) @@ -820,6 +834,7 @@ $(addprefix $(TARGET_PATH)/, $(SONIC_INSTALLERS)) : $(TARGET_PATH)/% : \ $(addprefix $(PYTHON_WHEELS_PATH)/,$(SONIC_PLATFORM_COMMON_PY3)) \ $(addprefix $(PYTHON_WHEELS_PATH)/,$(REDIS_DUMP_LOAD_PY2)) \ $(addprefix $(PYTHON_WHEELS_PATH)/,$(SONIC_PLATFORM_API_PY2)) \ + $(if $(findstring y,$(PDDF_SUPPORT)),$(addprefix $(PYTHON_WHEELS_PATH)/,$(PDDF_PLATFORM_API_BASE_PY2))) \ $(addprefix $(PYTHON_WHEELS_PATH)/,$(SONIC_YANG_MODELS_PY3)) \ $(addprefix $(PYTHON_WHEELS_PATH)/,$(SONIC_YANG_MGMT_PY2)) \ $(addprefix $(PYTHON_WHEELS_PATH)/,$(SONIC_YANG_MGMT_PY3)) \ @@ -847,6 +862,7 @@ $(addprefix $(TARGET_PATH)/, $(SONIC_INSTALLERS)) : $(TARGET_PATH)/% : \ export include_sflow="$(INCLUDE_SFLOW)" export include_mgmt_framework="$(INCLUDE_MGMT_FRAMEWORK)" export include_iccpd="$(INCLUDE_ICCPD)" + export pddf_support="$(PDDF_SUPPORT)" export shutdown_bgp_on_start="$(SHUTDOWN_BGP_ON_START)" export include_kubernetes="$(INCLUDE_KUBERNETES)" export enable_pfcwd_on_start="$(ENABLE_PFCWD_ON_START)"