diff --git a/.gitignore b/.gitignore index 49861324aa1..92741be17bc 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,7 @@ rules/config.user # Build artifacts -fsroot/ +fsroot*/ fs.* target/ *.deb diff --git a/device/accton/x86_64-accton_as4630_54npe-r0/Accton-AS4630-54NPE/port_config.ini b/device/accton/x86_64-accton_as4630_54npe-r0/Accton-AS4630-54NPE/port_config.ini new file mode 100644 index 00000000000..f8965dfe41d --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54npe-r0/Accton-AS4630-54NPE/port_config.ini @@ -0,0 +1,55 @@ +# name lanes alias index speed autoneg +Ethernet0 26 thousandE1 1 1000 1 +Ethernet1 25 thousandE2 2 1000 1 +Ethernet2 28 thousandE3 3 1000 1 +Ethernet3 27 thousandE4 4 1000 1 +Ethernet4 30 thousandE5 5 1000 1 +Ethernet5 29 thousandE6 6 1000 1 +Ethernet6 32 thousandE7 7 1000 1 +Ethernet7 31 thousandE8 8 1000 1 +Ethernet8 38 thousandE9 9 1000 1 +Ethernet9 37 thousandE10 10 1000 1 +Ethernet10 40 thousandE11 11 1000 1 +Ethernet11 39 thousandE12 12 1000 1 +Ethernet12 34 thousandE13 13 1000 1 +Ethernet13 33 thousandE14 14 1000 1 +Ethernet14 36 thousandE15 15 1000 1 +Ethernet15 35 thousandE16 16 1000 1 +Ethernet16 46 thousandE17 17 1000 1 +Ethernet17 45 thousandE18 18 1000 1 +Ethernet18 48 thousandE19 19 1000 1 +Ethernet19 47 thousandE20 20 1000 1 +Ethernet20 42 thousandE21 21 1000 1 +Ethernet21 41 thousandE22 22 1000 1 +Ethernet22 44 thousandE23 23 1000 1 +Ethernet23 43 thousandE24 24 1000 1 +Ethernet24 2 thousandE25 25 1000 1 +Ethernet25 1 thousandE26 26 1000 1 +Ethernet26 4 thousandE27 27 1000 1 +Ethernet27 3 thousandE28 28 1000 1 +Ethernet28 6 thousandE29 29 1000 1 +Ethernet29 5 thousandE30 30 1000 1 +Ethernet30 8 thousandE31 31 1000 1 +Ethernet31 7 thousandE32 32 1000 1 +Ethernet32 10 thousandE33 33 1000 1 +Ethernet33 9 thousandE34 34 1000 1 +Ethernet34 12 thousandE35 35 1000 1 +Ethernet35 11 thousandE36 36 1000 1 +Ethernet36 14 thousandE37 37 1000 1 +Ethernet37 13 thousandE38 38 1000 1 +Ethernet38 16 thousandE39 39 1000 1 +Ethernet39 15 thousandE40 40 1000 1 +Ethernet40 18 thousandE41 41 1000 1 +Ethernet41 17 thousandE42 42 1000 1 +Ethernet42 20 thousandE43 43 1000 1 +Ethernet43 19 thousandE44 44 1000 1 +Ethernet44 22 thousandE45 45 1000 1 +Ethernet45 21 thousandE46 46 1000 1 +Ethernet46 24 thousandE47 47 1000 1 +Ethernet47 23 thousandE48 48 1000 1 +Ethernet48 67 twentyfiveGigE49 49 25000 0 +Ethernet49 66 twentyfiveGigE50 50 25000 0 +Ethernet50 65 twentyfiveGigE51 51 25000 0 +Ethernet51 68 twentyfiveGigE52 52 25000 0 +Ethernet52 73,74,75,76 hundredGigE53 53 100000 0 +Ethernet56 69,70,71,72 hundredGigE54 54 100000 0 diff --git a/device/accton/x86_64-accton_as4630_54npe-r0/default_sku b/device/accton/x86_64-accton_as4630_54npe-r0/default_sku new file mode 100644 index 00000000000..86cc1cd9c38 --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54npe-r0/default_sku @@ -0,0 +1 @@ +Accton-AS4630-54NPE t1 diff --git a/device/accton/x86_64-accton_as4630_54npe-r0/installer.conf b/device/accton/x86_64-accton_as4630_54npe-r0/installer.conf new file mode 100644 index 00000000000..925a32fc0c3 --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54npe-r0/installer.conf @@ -0,0 +1,3 @@ +CONSOLE_PORT=0x3f8 +CONSOLE_DEV=0 +CONSOLE_SPEED=115200 diff --git a/device/accton/x86_64-accton_as4630_54npe-r0/platform_asic b/device/accton/x86_64-accton_as4630_54npe-r0/platform_asic new file mode 100644 index 00000000000..96046765276 --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54npe-r0/platform_asic @@ -0,0 +1 @@ +broadcom diff --git a/device/accton/x86_64-accton_as4630_54npe-r0/plugins/eeprom.py b/device/accton/x86_64-accton_as4630_54npe-r0/plugins/eeprom.py new file mode 100755 index 00000000000..e8c87eaefb7 --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54npe-r0/plugins/eeprom.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python + +try: + from sonic_eeprom import eeprom_tlvinfo +except ImportError as 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): + self.eeprom_path = "/sys/bus/i2c/devices/1-0057/eeprom" + super(board, self).__init__(self.eeprom_path, 0, '', True) diff --git a/device/accton/x86_64-accton_as4630_54npe-r0/plugins/psuutil.py b/device/accton/x86_64-accton_as4630_54npe-r0/plugins/psuutil.py new file mode 100755 index 00000000000..a66e5de8bcb --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54npe-r0/plugins/psuutil.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python + +############################################################################# +# Accton +# +# Module contains an implementation of SONiC PSU Base API and +# provides the PSUs status which are available in the platform +# +############################################################################# + +try: + from sonic_psu.psu_base import PsuBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class PsuUtil(PsuBase): + """Platform-specific PSUutil class""" + + def __init__(self): + PsuBase.__init__(self) + + self.psu_path = "/sys/bus/i2c/devices/" + self.psu_presence = "/psu_present" + self.psu_oper_status = "/psu_power_good" + self.psu_mapping = { + 1: "10-0050", + 2: "11-0051", + } + + def get_num_psus(self): + return len(self.psu_mapping) + + def get_psu_status(self, index): + if index is None: + return False + + status = 0 + node = self.psu_path + self.psu_mapping[index] + self.psu_oper_status + try: + with open(node, 'r') as power_status: + status = int(power_status.read()) + except IOError: + return False + + return status == 1 + + def get_psu_presence(self, index): + if index is None: + return False + + status = 0 + node = self.psu_path + self.psu_mapping[index] + self.psu_presence + try: + with open(node, 'r') as presence_status: + status = int(presence_status.read()) + except IOError: + return False + + return status == 1 diff --git a/device/accton/x86_64-accton_as4630_54npe-r0/plugins/sfputil.py b/device/accton/x86_64-accton_as4630_54npe-r0/plugins/sfputil.py new file mode 100755 index 00000000000..c074c51b04d --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54npe-r0/plugins/sfputil.py @@ -0,0 +1,211 @@ +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# + +try: + import sys + import time + from ctypes import create_string_buffer + from sonic_sfp.sfputilbase import SfpUtilBase +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + +SFP_STATUS_INSERTED = '1' +SFP_STATUS_REMOVED = '0' + + +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" + + PORT_START = 49 + PORT_END = 54 + PORTS_IN_BLOCK = 54 + QSFP_START = 53 + + BASE_OOM_PATH = "/sys/bus/i2c/devices/{0}-0050/" + BASE_CPLD_PATH = "/sys/bus/i2c/devices/3-0060/" + + _port_to_is_present = {} + _port_to_lp_mode = {} + + _port_to_eeprom_mapping = {} + _port_to_i2c_mapping = { + 49: [18], + 50: [19], + 51: [20], + 52: [21], + 53: [22], + 54: [23], + } + + @property + def port_start(self): + return self.PORT_START + + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_ports(self): + return range(self.QSFP_START, self.PORTS_IN_BLOCK + 1) + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + def __init__(self): + eeprom_path = self.BASE_OOM_PATH + "eeprom" + for x in range(self.port_start, self.port_end + 1): + self.port_to_eeprom_mapping[x] = eeprom_path.format( + self._port_to_i2c_mapping[x][0]) + SfpUtilBase.__init__(self) + + def get_presence(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + present_path = self.BASE_CPLD_PATH + "module_present_" + str(port_num) + self.__port_to_is_present = present_path + + try: + val_file = open(self.__port_to_is_present) + content = val_file.readline().rstrip() + val_file.close() + except IOError as e: + print("Error: unable to access file: %s" % str(e)) + return False + + if content == "1": + return True + + return False + + def get_low_power_mode(self, port_num): + # Check for invalid port_num + if port_num < self.QSFP_START or port_num > self.port_end: + return False + + try: + eeprom = None + if not self.get_presence(port_num): + return False + eeprom = open(self.port_to_eeprom_mapping[port_num], "rb") + eeprom.seek(93) + lpmode = ord(eeprom.read(1)) + + # if "Power override" bit is 1 and "Power set" bit is 1 + if ((lpmode & 0x3) == 0x3): + return True + + # 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 + else: + return False + + 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) + + def set_low_power_mode(self, port_num, lpmode): + # Check for invalid port_num + if port_num < self.QSFP_START or port_num > self.port_end: + return False + + try: + eeprom = None + if not self.get_presence(port_num): + return False # Port is not present, unable to set the eeprom + + # Fill in write buffer + # 0x3:Low Power Mode, 0x1:High Power Mode + regval = 0x3 if lpmode else 0x1 + + buffer = create_string_buffer(1) + buffer[0] = regval + + # Write to eeprom + eeprom = open(self.port_to_eeprom_mapping[port_num], "r+b") + 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) + + def reset(self, port_num): + if not port_num in self.qsfp_ports: + return False + + path = self.BASE_CPLD_PATH + "module_reset_" + str(port_num) + self.__port_to_mod_rst = path + try: + reg_file = open(self.__port_to_mod_rst, 'r+') + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + #toggle reset + reg_file.seek(0) + reg_file.write('1') + time.sleep(1) + reg_file.seek(0) + reg_file.write('0') + reg_file.close() + return True + + @property + def _get_presence_bitmap(self): + + bits = [] + for x in range(self.port_start, self.port_end + 1): + bits.append(str(int(self.get_presence(x)))) + + rev = "".join(bits[::-1]) + return int(rev, 2) + + data = {'present': 0} + + def get_transceiver_change_event(self, timeout=0): + port_dict = {} + + if timeout == 0: + cd_ms = sys.maxsize + else: + cd_ms = timeout + + # poll per second + while cd_ms > 0: + reg_value = self._get_presence_bitmap + changed_ports = self.data['present'] ^ reg_value + if changed_ports != 0: + break + time.sleep(1) + cd_ms = cd_ms - 1000 + + if changed_ports != 0: + for port in range(self.port_start, self.port_end + 1): + # Mask off the bit corresponding to our port + mask = (1 << (port - self.port_start)) + if changed_ports & mask: + if (reg_value & mask) == 0: + port_dict[port] = SFP_STATUS_REMOVED + else: + port_dict[port] = SFP_STATUS_INSERTED + + # Update cache + self.data['present'] = reg_value + return True, port_dict + else: + return True, {} diff --git a/device/accton/x86_64-accton_as4630_54npe-r0/pmon_daemon_control.json b/device/accton/x86_64-accton_as4630_54npe-r0/pmon_daemon_control.json new file mode 100644 index 00000000000..689def2c1e2 --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54npe-r0/pmon_daemon_control.json @@ -0,0 +1,4 @@ +{ + "skip_ledd": true, + "skip_pcied": true +} diff --git a/device/accton/x86_64-accton_as4630_54npe-r0/sensors.conf b/device/accton/x86_64-accton_as4630_54npe-r0/sensors.conf new file mode 100644 index 00000000000..3af8f045b34 --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54npe-r0/sensors.conf @@ -0,0 +1,40 @@ +# libsensors configuration file for as4630-54npe +# ------------------------------------------------ +# + +bus "i2c-3" "i2c-1-mux (chan_id 1)" +bus "i2c-10" "i2c-2-mux (chan_id 0)" +bus "i2c-11" "i2c-2-mux (chan_id 1)" +bus "i2c-14" "i2c-2-mux (chan_id 4)" +bus "i2c-24" "i2c-3-mux (chan_id 6)" +bus "i2c-25" "i2c-3-mux (chan_id 7)" + + +chip "ype1200am-i2c-*-58" + label in3 "PSU 1 Voltage" + label fan1 "PSU 1 Fan" + label temp1 "PSU 1 Temperature" + label power2 "PSU 1 Power" + label curr2 "PSU 1 Current" + +chip "ype1200am-i2c-*-59" + label in3 "PSU 2 Voltage" + label fan1 "PSU 2 Fan" + label temp1 "PSU 2 Temperature" + label power2 "PSU 2 Power" + label curr2 "PSU 2 Current" + +chip "as4630_54npe_cpld-*" + label fan1 "Fan 1" + label fan2 "Fan 2" + label fan3 "Fan 3" + + +chip "lm77-i2c-*-48" + label temp1 "Main Board Temperature" + +chip "lm75-i2c-*-4a" + label temp1 "Fan Board Temperature" + +chip "lm75-i2c-*-4b" + label temp1 "CPU Board Temperature" diff --git a/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/__init__.py b/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/__init__.py new file mode 100644 index 00000000000..73a7720e897 --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/__init__.py @@ -0,0 +1,2 @@ +__all__ = [ "platform", "chassis", "sfp", "eeprom", "component", "psu", "thermal", "fan", "fan_drawer" ] +from . import platform diff --git a/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/chassis.py b/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/chassis.py new file mode 100644 index 00000000000..ca1f7576c36 --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/chassis.py @@ -0,0 +1,255 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Chassis information which are available in the platform +# +############################################################################# + +import os +import sys + +try: + from sonic_platform_base.chassis_base import ChassisBase + from .helper import APIHelper + from .event import SfpEvent +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +NUM_FAN_TRAY = 3 +NUM_FAN = 2 +NUM_PSU = 2 +NUM_THERMAL = 3 +PORT_START = 49 +PORT_END = 54 +NUM_COMPONENT = 2 +HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/" +PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/" +REBOOT_CAUSE_FILE = "reboot-cause.txt" +PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt" +HOST_CHK_CMD = "which systemctl > /dev/null 2>&1" +SYSLED_FNODE = "/sys/class/leds/diag/brightness" +SYSLED_MODES = { + "0" : "STATUS_LED_COLOR_OFF", + "1" : "STATUS_LED_COLOR_GREEN", + "2" : "STATUS_LED_COLOR_AMBER", + "5" : "STATUS_LED_COLOR_GREEN_BLINK" +} + + +class Chassis(ChassisBase): + """Platform-specific Chassis class""" + + def __init__(self): + ChassisBase.__init__(self) + self._api_helper = APIHelper() + self.is_host = self._api_helper.is_host() + + self.config_data = {} + + self.__initialize_fan() + self.__initialize_psu() + self.__initialize_thermals() + self.__initialize_components() + self.__initialize_sfp() + self.__initialize_eeprom() + + def __initialize_sfp(self): + from sonic_platform.sfp import Sfp + for index in range(0, PORT_END): + sfp = Sfp(index) + self._sfp_list.append(sfp) + self._sfpevent = SfpEvent(self._sfp_list) + self.sfp_module_initialized = True + + def __initialize_fan(self): + from sonic_platform.fan_drawer import FanDrawer + for fant_index in range(NUM_FAN_TRAY): + fandrawer = FanDrawer(fant_index) + self._fan_drawer_list.append(fandrawer) + self._fan_list.extend(fandrawer._fan_list) + + def __initialize_psu(self): + from sonic_platform.psu import Psu + for index in range(0, NUM_PSU): + psu = Psu(index) + self._psu_list.append(psu) + + def __initialize_thermals(self): + from sonic_platform.thermal import Thermal + self._thermal_list.append(Thermal(is_cpu=True)) + for index in range(0, NUM_THERMAL): + thermal = Thermal(index) + self._thermal_list.append(thermal) + + def __initialize_eeprom(self): + from sonic_platform.eeprom import Tlv + self._eeprom = Tlv() + + def __initialize_components(self): + from sonic_platform.component import Component + for index in range(0, NUM_COMPONENT): + component = Component(index) + self._component_list.append(component) + + def __initialize_watchdog(self): + from sonic_platform.watchdog import Watchdog + self._watchdog = Watchdog() + + + def __is_host(self): + return os.system(HOST_CHK_CMD) == 0 + + def __read_txt_file(self, file_path): + try: + with open(file_path, 'r') as fd: + data = fd.read() + return data.strip() + except IOError: + pass + return None + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + + return self._api_helper.hwsku + + def get_presence(self): + """ + Retrieves the presence of the Chassis + Returns: + bool: True if Chassis is present, False if not + """ + return True + + 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 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._eeprom.get_mac() + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return self._eeprom.get_pn() + + def get_serial(self): + """ + Retrieves the hardware serial number for the chassis + Returns: + A string containing the hardware serial number for this chassis. + """ + return self._eeprom.get_serial() + + 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._eeprom.get_eeprom() + + 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. + """ + + reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE) + sw_reboot_cause = self._api_helper.read_txt_file( + reboot_cause_path) or "Unknown" + + + return ('REBOOT_CAUSE_NON_HARDWARE', sw_reboot_cause) + + def get_change_event(self, timeout=0): + # SFP event + if not self.sfp_module_initialized: + self.__initialize_sfp() + return self._sfpevent.get_sfp_event(timeout) + + def get_sfp(self, index): + """ + Retrieves sfp represented by (1-based) index + Args: + index: An integer, the index (1-based) of the sfp to retrieve. + The index should be the sequence of a physical port in a chassis, + starting from 1. + For example, 1 for Ethernet0, 2 for Ethernet4 and so on. + Returns: + An object dervied from SfpBase representing the specified sfp + """ + sfp = None + if not self.sfp_module_initialized: + self.__initialize_sfp() + + try: + # The index will start from 1 + sfp = self._sfp_list[index-1] + except IndexError: + sys.stderr.write("SFP index {} out of range (1-{})\n".format( + index, len(self._sfp_list))) + return sfp + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False + + + def initizalize_system_led(self): + return True + + def get_status_led(self): + val = self._api_helper.read_txt_file(SYSLED_FNODE) + return SYSLED_MODES[val] if val in SYSLED_MODES else "UNKNOWN" + + def set_status_led(self, color): + mode = None + for key, val in SYSLED_MODES.items(): + if val == color: + mode = key + break + if mode is None: + return False + else: + return self._api_helper.write_txt_file(SYSLED_FNODE, mode) + diff --git a/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/component.py b/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/component.py new file mode 100644 index 00000000000..97a15057e09 --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/component.py @@ -0,0 +1,172 @@ +############################################################################# +# Edgecore +# +# Component contains an implementation of SONiC Platform Base API and +# provides the components firmware management function +# +############################################################################# + +import shlex +import subprocess + + +try: + from sonic_platform_base.component_base import ComponentBase + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +CPLD_ADDR_MAPPING = { + "CPLD1": "3-0060" +} +SYSFS_PATH = "/sys/bus/i2c/devices/" +BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version" +COMPONENT_LIST= [ + ("CPLD1", "CPLD 1"), + ("BIOS", "Basic Input/Output System") + +] + +class Component(ComponentBase): + """Platform-specific Component class""" + + DEVICE_TYPE = "component" + + def __init__(self, component_index=0): + self._api_helper=APIHelper() + ComponentBase.__init__(self) + self.index = component_index + self.name = self.get_name() + + def __run_command(self, command): + # Run bash command and print output to stdout + try: + process = subprocess.Popen( + shlex.split(command), stdout=subprocess.PIPE) + while True: + output = process.stdout.readline() + if output == '' and process.poll() is not None: + break + rc = process.poll() + if rc != 0: + return False + except Exception: + return False + return True + + def __get_bios_version(self): + # Retrieves the BIOS firmware version + try: + with open(BIOS_VERSION_PATH, 'r') as fd: + bios_version = fd.read() + return bios_version.strip() + except Exception as e: + return None + + def __get_cpld_version(self): + # Retrieves the CPLD firmware version + cpld_version = dict() + for cpld_name in CPLD_ADDR_MAPPING: + try: + cpld_path = "{}{}{}".format(SYSFS_PATH, CPLD_ADDR_MAPPING[cpld_name], '/version') + cpld_version_raw= self._api_helper.read_txt_file(cpld_path) + cpld_version[cpld_name] = "{}".format(int(cpld_version_raw,16)) + except Exception as e: + print('Get exception when read cpld') + cpld_version[cpld_name] = 'None' + + return cpld_version + + def get_name(self): + """ + Retrieves the name of the component + Returns: + A string containing the name of the component + """ + return COMPONENT_LIST[self.index][0] + + def get_description(self): + """ + Retrieves the description of the component + Returns: + A string containing the description of the component + """ + return COMPONENT_LIST[self.index][1] + + + def get_firmware_version(self): + """ + Retrieves the firmware version of module + Returns: + string: The firmware versions of the module + """ + fw_version = None + if self.name == "BIOS": + fw_version = self.__get_bios_version() + elif "CPLD" in self.name: + cpld_version = self.__get_cpld_version() + fw_version = cpld_version.get(self.name) + + return fw_version + + def install_firmware(self, image_path): + """ + Install firmware to module + Args: + image_path: A string, path to firmware image + Returns: + A boolean, True if install successfully, False if not + """ + raise NotImplementedError + + def get_presence(self): + """ + Retrieves the presence of the device + Returns: + bool: True if device is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return 'N/A' + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return 'N/A' + + 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 True + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False diff --git a/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/eeprom.py b/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/eeprom.py new file mode 100644 index 00000000000..94e9736a1bb --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/eeprom.py @@ -0,0 +1,131 @@ +try: + import os + import sys + import re + if sys.version_info[0] >= 3: + from io import StringIO + else: + from cStringIO import StringIO + + from sonic_platform_base.sonic_eeprom import eeprom_tlvinfo +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +CACHE_ROOT = '/var/cache/sonic/decode-syseeprom' +CACHE_FILE = 'syseeprom_cache' +NULL = 'N/A' + +class Tlv(eeprom_tlvinfo.TlvInfoDecoder): + + EEPROM_DECODE_HEADLINES = 6 + + def __init__(self): + self._eeprom_path = "/sys/bus/i2c/devices/1-0057/eeprom" + super(Tlv, self).__init__(self._eeprom_path, 0, '', True) + self._eeprom = self._load_eeprom() + + def __parse_output(self, decode_output): + decode_output.replace('\0', '') + lines = decode_output.split('\n') + lines = lines[self.EEPROM_DECODE_HEADLINES:] + _eeprom_info_dict = dict() + + for line in lines: + try: + match = re.search( + '(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)([\S]+)', line) + if match is not None: + idx = match.group(1) + value = match.group(3).rstrip('\0') + + _eeprom_info_dict[idx] = value + except Exception: + pass + + return _eeprom_info_dict + + def _load_eeprom(self): + original_stdout = sys.stdout + sys.stdout = StringIO() + try: + self.read_eeprom_db() + except Exception: + decode_output = sys.stdout.getvalue() + sys.stdout = original_stdout + return self.__parse_output(decode_output) + + status = self.check_status() + if 'ok' not in status: + return False + + if not os.path.exists(CACHE_ROOT): + try: + os.makedirs(CACHE_ROOT) + except Exception: + pass + + # + # only the eeprom classes that inherit from eeprom_base + # support caching. Others will work normally + # + try: + self.set_cache_name(os.path.join(CACHE_ROOT, CACHE_FILE)) + except Exception: + pass + + e = self.read_eeprom() + if e is None: + return 0 + + try: + self.update_cache(e) + except Exception: + pass + + self.decode_eeprom(e) + decode_output = sys.stdout.getvalue() + sys.stdout = original_stdout + + (is_valid, valid_crc) = self.is_checksum_valid(e) + if not is_valid: + return False + + return self.__parse_output(decode_output) + + def _valid_tlv(self, eeprom_data): + tlvinfo_type_codes_list = [ + self._TLV_CODE_PRODUCT_NAME, + self._TLV_CODE_PART_NUMBER, + self._TLV_CODE_SERIAL_NUMBER, + self._TLV_CODE_MAC_BASE, + self._TLV_CODE_MANUF_DATE, + self._TLV_CODE_DEVICE_VERSION, + self._TLV_CODE_LABEL_REVISION, + self._TLV_CODE_PLATFORM_NAME, + self._TLV_CODE_ONIE_VERSION, + self._TLV_CODE_MAC_SIZE, + self._TLV_CODE_MANUF_NAME, + self._TLV_CODE_MANUF_COUNTRY, + self._TLV_CODE_VENDOR_NAME, + self._TLV_CODE_DIAG_VERSION, + self._TLV_CODE_SERVICE_TAG, + self._TLV_CODE_VENDOR_EXT, + self._TLV_CODE_CRC_32 + ] + + for code in tlvinfo_type_codes_list: + code_str = "0x{:X}".format(code) + eeprom_data[code_str] = eeprom_data.get(code_str, NULL) + return eeprom_data + + def get_eeprom(self): + return self._valid_tlv(self._eeprom) + + def get_pn(self): + return self._eeprom.get('0x22', NULL) + + def get_serial(self): + return self._eeprom.get('0x23', NULL) + + def get_mac(self): + return self._eeprom.get('0x24', NULL) diff --git a/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/event.py b/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/event.py new file mode 100644 index 00000000000..2d296e5137b --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/event.py @@ -0,0 +1,62 @@ +try: + import time + from .helper import APIHelper + from sonic_py_common.logger import Logger +except ImportError as e: + raise ImportError(repr(e) + " - required module not found") + +POLL_INTERVAL_IN_SEC = 1 + +class SfpEvent: + ''' Listen to insert/remove sfp events ''' + + def __init__(self, sfp_list): + self._api_helper = APIHelper() + self._sfp_list = sfp_list + self._logger = Logger() + self._sfp_change_event_data = {'present': 0} + + def get_presence_bitmap(self): + bitmap = 0 + for sfp in self._sfp_list: + modpres = sfp.get_presence() + i=sfp.port_num-1 + if modpres: + bitmap = bitmap | (1 << i) + return bitmap + + def get_sfp_event(self, timeout=2000): + port_dict = {} + change_dict = {} + change_dict['sfp'] = port_dict + + if timeout < 1000: + cd_ms = 1000 + else: + cd_ms = timeout + + while cd_ms > 0: + bitmap = self.get_presence_bitmap() + changed_ports = self._sfp_change_event_data['present'] ^ bitmap + if changed_ports != 0: + break + time.sleep(POLL_INTERVAL_IN_SEC) + # timeout=0 means wait for event forever + if timeout != 0: + cd_ms = cd_ms - POLL_INTERVAL_IN_SEC * 1000 + + if changed_ports != 0: + for sfp in self._sfp_list: + i=sfp.port_num-1 + if (changed_ports & (1 << i)): + if (bitmap & (1 << i)) == 0: + port_dict[i+1] = '0' + else: + port_dict[i+1] = '1' + + + # Update the cache dict + self._sfp_change_event_data['present'] = bitmap + return True, change_dict + else: + return True, change_dict diff --git a/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/fan.py b/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/fan.py new file mode 100644 index 00000000000..c031a3cf7b9 --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/fan.py @@ -0,0 +1,283 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the fan status which are available in the platform +# +############################################################################# + + + +try: + from sonic_platform_base.fan_base import FanBase + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +PSU_FAN_MAX_RPM = 26688 +SPEED_TOLERANCE = 15 +CPLD_FAN_I2C_PATH = "/sys/bus/i2c/devices/3-0060/fan_" +I2C_PATH ="/sys/bus/i2c/devices/{}-00{}/" +PSU_HWMON_I2C_MAPPING = { + 0: { + "num": 10, + "addr": "58" + }, + 1: { + "num": 11, + "addr": "59" + }, +} + +PSU_CPLD_I2C_MAPPING = { + 0: { + "num": 10, + "addr": "50" + }, + 1: { + "num": 11, + "addr": "51" + }, +} + + +FAN_NAME_LIST = ["FAN-1F", "FAN-1R", "FAN-2F", "FAN-2R", + "FAN-3F", "FAN-3R"] + +class Fan(FanBase): + """Platform-specific Fan class""" + + def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0): + self._api_helper=APIHelper() + self.fan_index = fan_index + self.fan_tray_index = fan_tray_index + self.is_psu_fan = is_psu_fan + + if self.is_psu_fan: + self.psu_index = psu_index + self.psu_i2c_num = PSU_HWMON_I2C_MAPPING[self.psu_index]['num'] + self.psu_i2c_addr = PSU_HWMON_I2C_MAPPING[self.psu_index]['addr'] + self.psu_hwmon_path = I2C_PATH.format( + self.psu_i2c_num, self.psu_i2c_addr) + + self.psu_i2c_num = PSU_CPLD_I2C_MAPPING[self.psu_index]['num'] + self.psu_i2c_addr = PSU_CPLD_I2C_MAPPING[self.psu_index]['addr'] + self.psu_cpld_path = I2C_PATH.format( + self.psu_i2c_num, self.psu_i2c_addr) + + FanBase.__init__(self) + + + 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 not self.is_psu_fan: + dir_str = "{}{}{}".format(CPLD_FAN_I2C_PATH, 'direction_', self.fan_tray_index+1) + val=self._api_helper.read_txt_file(dir_str) + if val is not None: + if int(val, 10)==0:#F2B + direction=self.FAN_DIRECTION_EXHAUST + else: + direction=self.FAN_DIRECTION_INTAKE + else: + direction=self.FAN_DIRECTION_EXHAUST + + else: #For PSU + dir_str = "{}{}".format(self.psu_hwmon_path,'psu_fan_dir') + val=self._api_helper.read_txt_file(dir_str) + if val is not None: + if val=='F2B': + direction=self.FAN_DIRECTION_EXHAUST + else: + direction=self.FAN_DIRECTION_INTAKE + else: + direction=self.FAN_DIRECTION_EXHAUST + + 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) + + """ + speed = 0 + if self.is_psu_fan: + psu_fan_path= "{}{}".format(self.psu_hwmon_path, 'psu_fan1_speed_rpm') + fan_speed_rpm = self._api_helper.read_txt_file(psu_fan_path) + if fan_speed_rpm is not None: + speed = (int(fan_speed_rpm,10))*100/26688 + if speed > 100: + speed=100 + else: + return 0 + elif self.get_presence(): + speed_path = "{}{}".format(CPLD_FAN_I2C_PATH, 'duty_cycle_percentage') + speed=self._api_helper.read_txt_file(speed_path) + if speed is None: + return 0 + return int(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) + + Note: + speed_pc = pwm_target/255*100 + + 0 : when PWM mode is use + pwm : when pwm mode is not use + """ + return self.get_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 + """ + return SPEED_TOLERANCE + + 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 not self.is_psu_fan and self.get_presence(): + speed_path = "{}{}".format(CPLD_FAN_I2C_PATH, 'duty_cycle_percentage') + return self._api_helper.write_txt_file(speed_path, int(speed)) + + return False + + def set_status_led(self, color): + """ + Sets the state of the fan module status LED + Args: + color: A string representing the color with which to set the + fan module status LED + Returns: + bool: True if status LED state is set successfully, False if not + """ + return False #Not supported + + def get_status_led(self): + """ + Gets the state of the fan status LED + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + status=self.get_presence() + if status is None: + return self.STATUS_LED_COLOR_OFF + + return { + 1: self.STATUS_LED_COLOR_GREEN, + 0: self.STATUS_LED_COLOR_RED + }.get(status, self.STATUS_LED_COLOR_OFF) + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + fan_name = FAN_NAME_LIST[self.fan_tray_index*2 + self.fan_index] \ + if not self.is_psu_fan \ + else "PSU-{} FAN-{}".format(self.psu_index+1, self.fan_index+1) + + return fan_name + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if FAN is present, False if not + """ + + + if self.is_psu_fan: + present_path="{}{}".format(self.psu_cpld_path, 'psu_present') + else: + present_path = "{}{}{}".format(CPLD_FAN_I2C_PATH, 'present_', self.fan_tray_index+1) + + val=self._api_helper.read_txt_file(present_path) + if val is not None: + return int(val, 10)==1 + else: + return False + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + if self.is_psu_fan: + psu_fan_path= "{}{}".format(self.psu_hwmon_path, 'psu_fan1_fault') + val=self._api_helper.read_txt_file(psu_fan_path) + if val is not None: + return int(val, 10)==0 + else: + return False + else: + path = "{}{}{}".format(CPLD_FAN_I2C_PATH, 'fault_', self.fan_tray_index+1) + val=self._api_helper.read_txt_file(path) + if val is not None: + return int(val, 10)==0 + else: + return False + + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + + return "N/A" + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return "N/A" + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return (self.fan_tray_index+1) \ + if not self.is_psu_fan else (self.psu_index+1) + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True if not self.is_psu_fan else False diff --git a/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/fan_drawer.py b/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/fan_drawer.py new file mode 100644 index 00000000000..e21163c106c --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/fan_drawer.py @@ -0,0 +1,90 @@ +######################################################################## +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Fan-Drawers' information available in the platform. +# +######################################################################## + +try: + from sonic_platform_base.fan_drawer_base import FanDrawerBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +FANS_PER_FANTRAY = 2 + + +class FanDrawer(FanDrawerBase): + """Platform-specific Fan class""" + + def __init__(self, fantray_index): + + FanDrawerBase.__init__(self) + # FanTray is 0-based in platforms + self.fantrayindex = fantray_index + self.__initialize_fan_drawer() + + + def __initialize_fan_drawer(self): + from sonic_platform.fan import Fan + for i in range(FANS_PER_FANTRAY): + self._fan_list.append(Fan(self.fantrayindex, i)) + + def get_name(self): + """ + Retrieves the fan drawer name + Returns: + string: The name of the device + """ + return "FanTray{}".format(self.fantrayindex+1) + + def get_presence(self): + """ + Retrieves the presence of the device + Returns: + bool: True if device is present, False if not + """ + return self._fan_list[0].get_presence() + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return self._fan_list[0].get_model() + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return self._fan_list[0].get_serial() + + 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._fan_list[0].get_status() + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return (self.fantrayindex+1) + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True diff --git a/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/helper.py b/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/helper.py new file mode 100644 index 00000000000..90436db1525 --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/helper.py @@ -0,0 +1,117 @@ +import os +import struct +import subprocess +from mmap import * +from sonic_py_common import device_info + +HOST_CHK_CMD = "which systemctl > /dev/null 2>&1" +EMPTY_STRING = "" + + +class APIHelper(): + + def __init__(self): + (self.platform, self.hwsku) = device_info.get_platform_and_hwsku() + + def is_host(self): + return os.system(HOST_CHK_CMD) == 0 + + def pci_get_value(self, resource, offset): + status = True + result = "" + try: + fd = os.open(resource, os.O_RDWR) + mm = mmap(fd, 0) + mm.seek(int(offset)) + read_data_stream = mm.read(4) + result = struct.unpack('I', read_data_stream) + except Exception: + status = False + return status, result + + def run_command(self, cmd): + status = True + result = "" + try: + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + except Exception: + status = False + return status, result + + def run_interactive_command(self, cmd): + try: + os.system(cmd) + except Exception: + return False + return True + + def read_txt_file(self, file_path): + try: + with open(file_path, 'r', errors='replace') as fd: + data = fd.read() + return data.strip() + except IOError: + pass + return None + + def write_txt_file(self, file_path, value): + try: + with open(file_path, 'w') as fd: + fd.write(str(value)) + except IOError: + return False + return True + + def ipmi_raw(self, netfn, cmd): + status = True + result = "" + try: + cmd = "ipmitool raw {} {}".format(str(netfn), str(cmd)) + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result + + def ipmi_fru_id(self, id, key=None): + status = True + result = "" + try: + cmd = "ipmitool fru print {}".format(str( + id)) if not key else "ipmitool fru print {0} | grep '{1}' ".format(str(id), str(key)) + + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result + + def ipmi_set_ss_thres(self, id, threshold_key, value): + status = True + result = "" + try: + cmd = "ipmitool sensor thresh '{}' {} {}".format(str(id), str(threshold_key), str(value)) + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result diff --git a/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/platform.py b/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/platform.py new file mode 100644 index 00000000000..2f2c2a447fc --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/platform.py @@ -0,0 +1,21 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the platform information +# +############################################################################# + +try: + from sonic_platform_base.platform_base import PlatformBase + from sonic_platform.chassis import Chassis +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Platform(PlatformBase): + """Platform-specific Platform class""" + + def __init__(self): + PlatformBase.__init__(self) + self._chassis = Chassis() diff --git a/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/psu.py b/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/psu.py new file mode 100644 index 00000000000..70f14129184 --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/psu.py @@ -0,0 +1,269 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the PSUs status which are available in the platform +# +############################################################################# + +#import sonic_platform + +try: + from sonic_platform_base.psu_base import PsuBase + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +I2C_PATH ="/sys/bus/i2c/devices/{0}-00{1}/" + +PSU_NAME_LIST = ["PSU-1", "PSU-2"] +PSU_NUM_FAN = [1, 1] +PSU_HWMON_I2C_MAPPING = { + 0: { + "num": 10, + "addr": "58" + }, + 1: { + "num": 11, + "addr": "59" + }, +} + +PSU_CPLD_I2C_MAPPING = { + 0: { + "num": 10, + "addr": "50" + }, + 1: { + "num": 11, + "addr": "51" + }, +} + +class Psu(PsuBase): + """Platform-specific Psu class""" + + def __init__(self, psu_index=0): + PsuBase.__init__(self) + self.index = psu_index + self._api_helper = APIHelper() + + self.i2c_num = PSU_HWMON_I2C_MAPPING[self.index]["num"] + self.i2c_addr = PSU_HWMON_I2C_MAPPING[self.index]["addr"] + self.hwmon_path = I2C_PATH.format(self.i2c_num, self.i2c_addr) + + self.i2c_num = PSU_CPLD_I2C_MAPPING[self.index]["num"] + self.i2c_addr = PSU_CPLD_I2C_MAPPING[self.index]["addr"] + self.cpld_path = I2C_PATH.format(self.i2c_num, self.i2c_addr) + self.__initialize_fan() + + def __initialize_fan(self): + from sonic_platform.fan import Fan + for fan_index in range(0, PSU_NUM_FAN[self.index]): + fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index) + self._fan_list.append(fan) + + def get_voltage(self): + """ + Retrieves current PSU voltage output + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + vout_path = "{}{}".format(self.hwmon_path, 'psu_v_out') + vout_val=self._api_helper.read_txt_file(vout_path) + if vout_val is not None: + return float(vout_val)/ 1000 + else: + return 0 + + def get_current(self): + """ + Retrieves present electric current supplied by PSU + Returns: + A float number, the electric current in amperes, e.g 15.4 + """ + iout_path = "{}{}".format(self.hwmon_path, 'psu_i_out') + val=self._api_helper.read_txt_file(iout_path) + if val is not None: + return float(val)/1000 + else: + return 0 + + def get_power(self): + """ + Retrieves current energy supplied by PSU + Returns: + A float number, the power in watts, e.g. 302.6 + """ + pout_path = "{}{}".format(self.hwmon_path, 'psu_p_out') + val=self._api_helper.read_txt_file(pout_path) + if val is not None: + return float(val)/1000 + else: + return 0 + + 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): + """ + Sets the state of the PSU status LED + Args: + color: A string representing the color with which to set the PSU status LED + Note: Only support green and off + Returns: + bool: True if status LED state is set successfully, False if not + """ + + return False #Controlled by HW + + def get_status_led(self): + """ + Gets the state of the PSU status LED + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + status=self.get_status() + if status is None: + return self.STATUS_LED_COLOR_OFF + + return { + 1: self.STATUS_LED_COLOR_GREEN, + 0: self.STATUS_LED_COLOR_RED + }.get(status, self.STATUS_LED_COLOR_OFF) + + + def get_temperature(self): + """ + Retrieves current temperature reading from PSU + Returns: + A float number of current temperature in Celsius up to nearest thousandth + of one degree Celsius, e.g. 30.125 + """ + temp_path = "{}{}".format(self.hwmon_path, 'psu_temp1_input') + val=self._api_helper.read_txt_file(temp_path) + if val is not None: + return float(val)/1000 + else: + return 0 + + def get_temperature_high_threshold(self): + """ + Retrieves the high threshold temperature of PSU + Returns: + A float number, the high threshold temperature of PSU in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + return False #Not supported + + def get_voltage_high_threshold(self): + """ + Retrieves the high threshold PSU voltage output + Returns: + A float number, the high threshold output voltage in volts, + e.g. 12.1 + """ + vout_path = "{}{}".format(self.hwmon_path, 'psu_mfr_vout_max') + vout_val=self._api_helper.read_txt_file(vout_path) + if vout_val is not None: + return float(vout_val)/ 1000 + else: + return 0 + + def get_voltage_low_threshold(self): + """ + Retrieves the low threshold PSU voltage output + Returns: + A float number, the low threshold output voltage in volts, + e.g. 12.1 + """ + vout_path = "{}{}".format(self.hwmon_path, 'psu_mfr_vout_min') + vout_val=self._api_helper.read_txt_file(vout_path) + if vout_val is not None: + return float(vout_val)/ 1000 + else: + return 0 + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return PSU_NAME_LIST[self.index] + + def get_presence(self): + """ + Retrieves the presence of the PSU + Returns: + bool: True if PSU is present, False if not + """ + presence_path="{}{}".format(self.cpld_path, 'psu_present') + val=self._api_helper.read_txt_file(presence_path) + if val is not None: + return int(val, 10) == 1 + else: + return 0 + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + power_path="{}{}".format(self.cpld_path, 'psu_power_good') + val=self._api_helper.read_txt_file(power_path) + if val is not None: + return int(val, 10) == 1 + else: + return 0 + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + model_path="{}{}".format(self.cpld_path, 'psu_model_name') + model=self._api_helper.read_txt_file(model_path) + if model is None: + return "N/A" + + return model + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + serial_path="{}{}".format(self.cpld_path, 'psu_serial_number') + serial=self._api_helper.read_txt_file(serial_path) + if serial is None: + return "N/A" + return serial + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device or -1 if cannot determine the position + """ + return self.index+1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True diff --git a/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/sfp.py b/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/sfp.py new file mode 100644 index 00000000000..af6333937ab --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/sfp.py @@ -0,0 +1,1179 @@ +############################################################################# +# Edgecore +# +# Sfp contains an implementation of SONiC Platform Base API and +# provides the sfp device status which are available in the platform +# +############################################################################# + +import os +import time +import sys + +from ctypes import create_string_buffer + +try: + from sonic_platform_base.sfp_base import SfpBase + from sonic_platform_base.sonic_sfp.sff8436 import sff8436Dom + from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId + from sonic_platform_base.sonic_sfp.sff8472 import sff8472Dom + from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId + from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +CPLD_I2C_PATH = "/sys/bus/i2c/devices/3-0060/" + +QSFP_INFO_OFFSET = 128 +QSFP_DOM_OFFSET = 0 + +SFP_INFO_OFFSET = 0 +SFP_DOM_OFFSET = 256 + +XCVR_INTFACE_BULK_OFFSET = 0 +XCVR_INTFACE_BULK_WIDTH_QSFP = 20 +XCVR_INTFACE_BULK_WIDTH_SFP = 21 +XCVR_HW_REV_WIDTH_QSFP = 2 +XCVR_HW_REV_WIDTH_SFP = 4 +XCVR_CABLE_LENGTH_WIDTH_QSFP = 5 +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_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 + +# Offset for values in QSFP 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 + +qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)', + 'Length OM2(m)', 'Length OM1(m)', + 'Length Cable Assembly(m)') + +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') + + +# Offset for values in SFP eeprom +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 + +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') + + +class Sfp(SfpBase): + """Platform-specific Sfp class""" + + # Port number + PORT_START = 49 + PORT_END = 54 + + # Path to sysfs + PLATFORM_ROOT_PATH = "/usr/share/sonic/device" + PMON_HWSKU_PATH = "/usr/share/sonic/hwsku" + HOST_CHK_CMD = "which systemctl > /dev/null 2>&1" + + PLATFORM = "x86_64-accton_as4630_54pe-r0" + HWSKU = "Accton-AS4630-54PE" + + _port_to_i2c_mapping = { + 49: 18, + 50: 19, + 51: 20, + 52: 21, + 53: 22, + 54: 23, + } + + def __init__(self, sfp_index=0): + self._api_helper=APIHelper() + # Init index + self.index = sfp_index + self.port_num = self.index + 1 + # Init eeprom path + eeprom_path = '/sys/bus/i2c/devices/{0}-0050/eeprom' + self.port_to_eeprom_mapping = {} + for x in range(self.PORT_START, self.PORT_END + 1): + self.port_to_eeprom_mapping[x] = eeprom_path.format(self._port_to_i2c_mapping[x]) + + 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', 'type_abbrv_name'] + + 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 _convert_string_to_num(self, value_str): + if "-inf" in value_str: + return 'N/A' + elif "Unknown" in value_str: + return 'N/A' + elif 'dBm' in value_str: + t_str = value_str.rstrip('dBm') + return float(t_str) + elif 'mA' in value_str: + t_str = value_str.rstrip('mA') + return float(t_str) + elif 'C' in value_str: + t_str = value_str.rstrip('C') + return float(t_str) + elif 'Volts' in value_str: + t_str = value_str.rstrip('Volts') + return float(t_str) + else: + return 'N/A' + + def __is_host(self): + return os.system(self.HOST_CHK_CMD) == 0 + + def __get_path_to_port_config_file(self): + platform_path = "/".join([self.PLATFORM_ROOT_PATH, self.PLATFORM]) + hwsku_path = "/".join([platform_path, self.HWSKU] + ) if self.__is_host() else self.PMON_HWSKU_PATH + return "/".join([hwsku_path, "port_config.ini"]) + + 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") + + sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.port_num] + try: + sysfsfile_eeprom = open( + sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0) + sysfsfile_eeprom.seek(offset) + raw = sysfsfile_eeprom.read(num_bytes) + if sys.version_info[0] >= 3: + for n in range(0, num_bytes): + eeprom_raw[n] = hex(raw[n])[2:].zfill(2) + else: + for n in range(0, num_bytes): + eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) + except Exception: + pass + finally: + if sysfsfile_eeprom: + sysfsfile_eeprom.close() + + return eeprom_raw + + 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 self.port_num < 49: + return {} + elif self.port_num < 53: + sfpi_obj = sff8472InterfaceId() #SFP + else: + sfpi_obj = sff8436InterfaceId() #QSFP + if not self.get_presence() or not sfpi_obj: + return {} + + if self.port_num < 53: + offset = SFP_INFO_OFFSET + sfp_interface_bulk_raw = self.__read_eeprom_specific_bytes( + (offset + XCVR_INTFACE_BULK_OFFSET), XCVR_INTFACE_BULK_WIDTH_SFP) + else: + offset = QSFP_INFO_OFFSET + sfp_interface_bulk_raw = self.__read_eeprom_specific_bytes( + (offset + XCVR_INTFACE_BULK_OFFSET), XCVR_INTFACE_BULK_WIDTH_QSFP) + + sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk( + sfp_interface_bulk_raw, 0) + + sfp_vendor_name_raw = self.__read_eeprom_specific_bytes( + (offset + XCVR_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 + XCVR_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH) + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn( + sfp_vendor_pn_raw, 0) + + if self.port_num < 53: + sfp_vendor_rev_raw = self.__read_eeprom_specific_bytes( + (offset + XCVR_HW_REV_OFFSET), XCVR_HW_REV_WIDTH_SFP) + else: + sfp_vendor_rev_raw = self.__read_eeprom_specific_bytes( + (offset + XCVR_HW_REV_OFFSET), XCVR_HW_REV_WIDTH_QSFP) + + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev( + sfp_vendor_rev_raw, 0) + + sfp_vendor_sn_raw = self.__read_eeprom_specific_bytes( + (offset + XCVR_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH) + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn( + sfp_vendor_sn_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) + sfp_vendor_date_data = sfpi_obj.parse_vendor_date( + sfp_vendor_date_raw, 0) + + transceiver_info_dict = dict.fromkeys(self.info_dict_keys, 'N/A') + compliance_code_dict = dict() + + if sfp_interface_bulk_data: + transceiver_info_dict['type'] = sfp_interface_bulk_data['data']['type']['value'] + transceiver_info_dict['connector'] = sfp_interface_bulk_data['data']['Connector']['value'] + transceiver_info_dict['encoding'] = sfp_interface_bulk_data['data']['EncodingCodes']['value'] + transceiver_info_dict['ext_identifier'] = sfp_interface_bulk_data['data']['Extended Identifier']['value'] + transceiver_info_dict['ext_rateselect_compliance'] = sfp_interface_bulk_data['data']['RateIdentifier']['value'] + transceiver_info_dict['type_abbrv_name'] = sfp_interface_bulk_data['data']['type_abbrv_name']['value'] + + transceiver_info_dict['manufacturer'] = sfp_vendor_name_data[ + 'data']['Vendor Name']['value'] if sfp_vendor_name_data else 'N/A' + transceiver_info_dict['model'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] if sfp_vendor_pn_data else 'N/A' + transceiver_info_dict['hardware_rev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] if sfp_vendor_rev_data else 'N/A' + transceiver_info_dict['serial'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] if sfp_vendor_sn_data else 'N/A' + transceiver_info_dict['vendor_oui'] = sfp_vendor_oui_data['data']['Vendor OUI']['value'] if sfp_vendor_oui_data else 'N/A' + transceiver_info_dict['vendor_date'] = sfp_vendor_date_data[ + 'data']['VendorDataCode(YYYY-MM-DD Lot)']['value'] if sfp_vendor_date_data else 'N/A' + transceiver_info_dict['cable_type'] = "Unknown" + transceiver_info_dict['cable_length'] = "Unknown" + + if self.port_num < 53: + for key in sfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_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'] + + transceiver_info_dict['specification_compliance'] = str( + compliance_code_dict) + transceiver_info_dict['nominal_bit_rate'] = str( + sfp_interface_bulk_data['data']['NominalSignallingRate(UnitsOf100Mbd)']['value']) + else: + for key in qsfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_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'] + + transceiver_info_dict['specification_compliance'] = str( + compliance_code_dict) + transceiver_info_dict['nominal_bit_rate'] = str( + sfp_interface_bulk_data['data']['Nominal Bit Rate(100Mbs)']['value']) + + + return transceiver_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 self.port_num < 53: #SFP case + sfpd_obj = sff8472Dom() + if not self.get_presence() or not sfpd_obj: + return {} + + eeprom_ifraw = self.__read_eeprom_specific_bytes(0, SFP_DOM_OFFSET) + sfpi_obj = sff8472InterfaceId(eeprom_ifraw) + cal_type = sfpi_obj.get_calibration_type() + sfpd_obj._calibration_type = cal_type + + offset = SFP_DOM_OFFSET + transceiver_dom_info_dict = dict.fromkeys(self.dom_dict_keys, 'N/A') + 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) + transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + + 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) + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + + 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_voltage_data = sfpd_obj.parse_channel_monitor_params( + dom_channel_monitor_raw, 0) + transceiver_dom_info_dict['tx1power'] = dom_voltage_data['data']['TXPower']['value'] + transceiver_dom_info_dict['rx1power'] = dom_voltage_data['data']['RXPower']['value'] + transceiver_dom_info_dict['tx1bias'] = dom_voltage_data['data']['TXBias']['value'] + + else: #QSFP case + sfpd_obj = sff8436Dom() + sfpi_obj = sff8436InterfaceId() + + if not self.get_presence() or not sfpi_obj or not sfpd_obj: + return {} + + transceiver_dom_info_dict = dict.fromkeys(self.dom_dict_keys, 'N/A') + offset = QSFP_DOM_OFFSET + offset_xcvr = QSFP_INFO_OFFSET + + # QSFP capability byte parse, through this byte can know whether it support tx_power or not. + # TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436, + # need to add more code for determining the capability and version compliance + # in SFF-8636 dom capability definitions evolving with the versions. + 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_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) + transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + + 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) + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + + 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) + qsfp_dom_rev = qsfp_dom_rev_data['data']['dom_rev']['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 = {} + dom_channel_monitor_raw = None + 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: + 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) + transceiver_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TX1Power']['value'] + transceiver_dom_info_dict['tx2power'] = dom_channel_monitor_data['data']['TX2Power']['value'] + transceiver_dom_info_dict['tx3power'] = dom_channel_monitor_data['data']['TX3Power']['value'] + transceiver_dom_info_dict['tx4power'] = dom_channel_monitor_data['data']['TX4Power']['value'] + + if dom_channel_monitor_raw: + transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RX1Power']['value'] + transceiver_dom_info_dict['rx2power'] = dom_channel_monitor_data['data']['RX2Power']['value'] + transceiver_dom_info_dict['rx3power'] = dom_channel_monitor_data['data']['RX3Power']['value'] + transceiver_dom_info_dict['rx4power'] = dom_channel_monitor_data['data']['RX4Power']['value'] + transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TX1Bias']['value'] + transceiver_dom_info_dict['tx2bias'] = dom_channel_monitor_data['data']['TX2Bias']['value'] + transceiver_dom_info_dict['tx3bias'] = dom_channel_monitor_data['data']['TX3Bias']['value'] + transceiver_dom_info_dict['tx4bias'] = dom_channel_monitor_data['data']['TX4Bias']['value'] + #End of else + + + for key in transceiver_dom_info_dict: + transceiver_dom_info_dict[key] = self._convert_string_to_num( + transceiver_dom_info_dict[key]) + + transceiver_dom_info_dict['rx_los'] = self.get_rx_los() + transceiver_dom_info_dict['tx_fault'] = self.get_tx_fault() + transceiver_dom_info_dict['reset_status'] = self.get_reset_status() + transceiver_dom_info_dict['lp_mode'] = self.get_lpmode() + + return transceiver_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 self.port_num < 53: + sfpd_obj = sff8472Dom() + + if not self.get_presence() and not sfpd_obj: + return {} + + eeprom_ifraw = self.__read_eeprom_specific_bytes(0, SFP_DOM_OFFSET) + sfpi_obj = sff8472InterfaceId(eeprom_ifraw) + cal_type = sfpi_obj.get_calibration_type() + sfpd_obj._calibration_type = cal_type + + offset = SFP_DOM_OFFSET + transceiver_dom_threshold_info_dict = dict.fromkeys( + self.threshold_dict_keys, 'N/A') + 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) + + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VoltageHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VoltageLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data[ + 'data']['VoltageHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VoltageLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['BiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['BiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['BiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['BiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TXPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RXPowerLowWarning']['value'] + + for key in transceiver_dom_threshold_info_dict: + transceiver_dom_threshold_info_dict[key] = self._convert_string_to_num( + transceiver_dom_threshold_info_dict[key]) + + return transceiver_dom_threshold_info_dict + + + else: + sfpd_obj = sff8436Dom() + + if not self.get_presence() or not sfpd_obj: + return {} + + transceiver_dom_threshold_dict = dict.fromkeys( + self.threshold_dict_keys, 'N/A') + dom_thres_raw = self.__read_eeprom_specific_bytes( + QSFP_MODULE_THRESHOLD_OFFSET, QSFP_MODULE_THRESHOLD_WIDTH) if self.get_presence() and sfpd_obj else None + + 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: + transceiver_dom_threshold_dict['temphighalarm'] = module_threshold_data['TempHighAlarm']['value'] + transceiver_dom_threshold_dict['templowalarm'] = module_threshold_data['TempLowAlarm']['value'] + transceiver_dom_threshold_dict['temphighwarning'] = module_threshold_data['TempHighWarning']['value'] + transceiver_dom_threshold_dict['templowwarning'] = module_threshold_data['TempLowWarning']['value'] + transceiver_dom_threshold_dict['vcchighalarm'] = module_threshold_data['VccHighAlarm']['value'] + transceiver_dom_threshold_dict['vcclowalarm'] = module_threshold_data['VccLowAlarm']['value'] + transceiver_dom_threshold_dict['vcchighwarning'] = module_threshold_data['VccHighWarning']['value'] + transceiver_dom_threshold_dict['vcclowwarning'] = module_threshold_data['VccLowWarning']['value'] + + dom_thres_raw = self.__read_eeprom_specific_bytes( + QSFP_CHANNEL_THRESHOLD_OFFSET, QSFP_CHANNEL_THRESHOLD_WIDTH) if self.get_presence() and sfpd_obj else None + 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: + transceiver_dom_threshold_dict['rxpowerhighalarm'] = channel_threshold_data['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_dict['rxpowerlowalarm'] = channel_threshold_data['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_dict['rxpowerhighwarning'] = channel_threshold_data['RxPowerHighWarning']['value'] + transceiver_dom_threshold_dict['rxpowerlowwarning'] = channel_threshold_data['RxPowerLowWarning']['value'] + transceiver_dom_threshold_dict['txpowerhighalarm'] = "0.0dBm" + transceiver_dom_threshold_dict['txpowerlowalarm'] = "0.0dBm" + transceiver_dom_threshold_dict['txpowerhighwarning'] = "0.0dBm" + transceiver_dom_threshold_dict['txpowerlowwarning'] = "0.0dBm" + transceiver_dom_threshold_dict['txbiashighalarm'] = channel_threshold_data['TxBiasHighAlarm']['value'] + transceiver_dom_threshold_dict['txbiaslowalarm'] = channel_threshold_data['TxBiasLowAlarm']['value'] + transceiver_dom_threshold_dict['txbiashighwarning'] = channel_threshold_data['TxBiasHighWarning']['value'] + transceiver_dom_threshold_dict['txbiaslowwarning'] = channel_threshold_data['TxBiasLowWarning']['value'] + + for key in transceiver_dom_threshold_dict: + transceiver_dom_threshold_dict[key] = self._convert_string_to_num( + transceiver_dom_threshold_dict[key]) + + return transceiver_dom_threshold_dict + + def get_reset_status(self): + """ + Retrieves the reset status of SFP + Returns: + A Boolean, True if reset enabled, False if disabled + """ + if self.port_num < 53: #Copper port and sfp ports are suported. + return False + + reset_path="{}{}{}".format(CPLD_I2C_PATH , "module_reset_" , str(self.port_num)) + val = self._api_helper.read_txt_file(reset_path) + + if val is not None: + return int(val, 10) == 1 + else: + return False + + 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 = False + + if self.port_num < 49: #Copper port, no sysfs + return False + + if self.port_num < 53: + rx_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_rx_los_', self.port_num) + rx_los=self._api_helper.read_txt_file(rx_path) + if rx_los is None: + return False + #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: + 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] + 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 = False + if self.port_num < 49: #Copper port, no sysfs + return False + + if self.port_num < 53: + tx_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_tx_fault_', self.port_num) + tx_fault=self._api_helper.read_txt_file(tx_path) + if tx_fault is None: + return False + #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: + 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] + + 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 + """ + if self.port_num < 49: #Copper port, no sysfs + return False + + if self.port_num < 53: + tx_disable = False + + tx_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_tx_disable_', self.port_num) + tx_disable=self._api_helper.read_txt_file(tx_path) + + + #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 + if tx_disable is not None: + return tx_disable + else: + return False + + else: + 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 + + 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 self.port_num < 53: + # SFP doesn't support this feature + return False + else: + 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 + + 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 + """ + if self.port_num < 53: + # SFP doesn't support this feature + return False + else: + power_set=self.get_power_set() + power_override = self.get_power_override() + return power_set and power_override + + + def get_power_set(self): + + if self.port_num < 53: + # SFP doesn't support this feature + return False + else: + power_set = False + + 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_set = ( + 'On' == dom_control_data['data']['PowerSet']['value']) + + return power_set + + 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 + """ + if self.port_num < 53: + return False # SFP doesn't support this feature + else: + power_override = False + + + 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']) + + 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() + return transceiver_dom_info_dict.get("temperature", "N/A") + + 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() + return transceiver_dom_info_dict.get("voltage", "N/A") + + 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() + + tx1_bs = transceiver_dom_info_dict.get("tx1bias", "N/A") + if self.port_num < 53: + return [tx1_bs, "N/A", "N/A", "N/A"] if transceiver_dom_info_dict else [] + + 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 [] + + 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() + + rx1_pw = transceiver_dom_info_dict.get("rx1power", "N/A") + if self.port_num < 53: + return [rx1_pw, "N/A", "N/A", "N/A"] if transceiver_dom_info_dict else [] + 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 [] + + 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() + tx1_pw = transceiver_dom_info_dict.get("tx1power", "N/A") + if self.port_num < 53: + return [tx1_pw, "N/A", "N/A", "N/A"] if transceiver_dom_info_dict else [] + 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] + + def reset(self): + """ + Reset SFP and return all user module settings to their default srate. + Returns: + A boolean, True if successful, False if not + """ + # Check for invalid port_num + if self.port_num < 53: #Copper port and sfp ports are not supported. + return False + + reset_path = "{}{}{}".format(CPLD_I2C_PATH, 'module_reset_', self.port_num) + ret = self._api_helper.write_txt_file(reset_path, 1) + if ret is not True: + return ret + + time.sleep(0.01) + ret = self._api_helper.write_txt_file(reset_path, 0) + time.sleep(0.2) + + return ret + + 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 + """ + if self.port_num < 49: #Copper port, no sysfs + return False + + if self.port_num < 53: + tx_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_tx_disable_', self.port_num) + ret = self.__write_txt_file(tx_path, 1 if tx_disable else 0) + if ret is not None: + time.sleep(0.01) + return ret + else: + return False + + else: + if not self.get_presence(): + return False + sysfsfile_eeprom = None + try: + tx_disable_ctl = 0xf if tx_disable else 0x0 + buffer = create_string_buffer(1) + if sys.version_info[0] >= 3: + buffer[0] = tx_disable_ctl + else: + buffer[0] = chr(tx_disable_ctl) + # Write to eeprom + sysfsfile_eeprom = open( + self.port_to_eeprom_mapping[self.port_num], "r+b") + sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) + + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print ('Error: unable to open file: ',str(e)) + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + + 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 + """ + + if self.port_num < 53: + return False # SFP doesn't support this feature + else: + if not self.get_presence(): + return False + + sysfsfile_eeprom = None + try: + channel_state = self.get_tx_disable_channel() + + for i in range(4): + channel_mask = (1 << i) + if not (channel & channel_mask): + continue + + if disable: + channel_state |= channel_mask + else: + channel_state &= ~channel_mask + + buffer = create_string_buffer(1) + if sys.version_info[0] >= 3: + buffer[0] = channel_state + else: + buffer[0] = chr(channel_state) + # Write to eeprom + sysfsfile_eeprom = open( + self.port_to_eeprom_mapping[self.port_num], "r+b") + sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print ('Error: unable to open file: ', str(e)) + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + + 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 + """ + if self.port_num < 53: + return False # SFP doesn't support this feature + else: + if lpmode is True: + self.set_power_override(True, True) + else: + self.set_power_override(False, False) + + return True + + 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 + """ + if self.port_num < 53: + return False # SFP doesn't support this feature + else: + if not self.get_presence(): + return False + try: + power_override_bit = (1 << 0) if power_override else 0 + power_set_bit = (1 << 1) if power_set else (1 << 3) + + buffer = create_string_buffer(1) + if sys.version_info[0] >= 3: + buffer[0] = (power_override_bit | power_set_bit) + else: + buffer[0] = chr(power_override_bit | power_set_bit) + # Write to eeprom + with open(self.port_to_eeprom_mapping[self.port_num], "r+b") as fd: + fd.seek(QSFP_POWEROVERRIDE_OFFSET) + fd.write(buffer[0]) + time.sleep(0.01) + except IOError as e: + print ('Error: unable to open file: ', str(e)) + return False + return True + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + sfputil_helper = SfpUtilHelper() + sfputil_helper.read_porttab_mappings( + self.__get_path_to_port_config_file()) + name = sfputil_helper.logical[self.index] or "Unknown" + return name + + def get_presence(self): + """ + Retrieves the presence of the device + Returns: + bool: True if device is present, False if not + """ + if self.port_num < 49: #Copper port, no sysfs + return False + + present_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_present_', self.port_num) + val=self._api_helper.read_txt_file(present_path) + if val is not None: + return int(val, 10)==1 + else: + return False + + 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() + return transceiver_dom_info_dict.get("model", "N/A") + + 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() + return transceiver_dom_info_dict.get("serial", "N/A") + + 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_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device or -1 if cannot determine the position + """ + return self.port_num + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True diff --git a/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/thermal.py b/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/thermal.py new file mode 100644 index 00000000000..c014e3076a8 --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/thermal.py @@ -0,0 +1,276 @@ +############################################################################# +# Edgecore +# +# Thermal contains an implementation of SONiC Platform Base API and +# provides the thermal device status which are available in the platform +# +############################################################################# + +import os +import os.path +import glob +from collections import namedtuple + +try: + from sonic_platform_base.thermal_base import ThermalBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +Threshold = namedtuple('Threshold', ['high_crit', 'high_err', 'high_warn', + 'low_warn', 'low_err', 'low_crit'], defaults=[0]*6) + +PSU_I2C_PATH = "/sys/bus/i2c/devices/{}-00{}/" +PSU_I2C_MAPPING = { + 0: { + "num": 10, + "addr": "58" + }, + 1: { + "num": 11, + "addr": "59" + }, +} + +PSU_CPLD_I2C_MAPPING = { + 0: { + "num": 10, + "addr": "50" + }, + 1: { + "num": 11, + "addr": "51" + }, +} + + +class Thermal(ThermalBase): + """Platform-specific Thermal class""" + + THERMAL_NAME_LIST = [ + "Main Board Temperature 0x48", + "CPU Board Temperature 0x4B", + "Fan Board Temperature 0x4A" + ] + PSU_THERMAL_NAME_LIST = [ + "PSU 1 Temperature", + "PSU 2 Temperature" + ] + CPU_THERMAL_NAME = "CPU Core temp" + SYSFS_PATH = "/sys/bus/i2c/devices" + + THRESHOLDS = { + 0: Threshold(70.25, 67.25, 64.25), + 1: Threshold(62.875, 59.875, 56.875), + 2: Threshold(68.5, 65.5, 62.5) + } + + def __init__(self, thermal_index=0, is_psu=False, psu_index=0, is_cpu=False): + self.index = thermal_index + self.is_psu = is_psu + self.psu_index = psu_index + self.is_cpu = is_cpu + + if self.is_cpu: + self.cpu_paths = glob.glob('/sys/devices/platform/coretemp.0/hwmon/hwmon*/temp*_input') + self.cpu_path_idx = 0 + + if self.is_psu: + psu_i2c_bus = PSU_I2C_MAPPING[psu_index]["num"] + psu_i2c_addr = PSU_I2C_MAPPING[psu_index]["addr"] + self.psu_hwmon_path = PSU_I2C_PATH.format(psu_i2c_bus, + psu_i2c_addr) + psu_i2c_bus = PSU_CPLD_I2C_MAPPING[psu_index]["num"] + psu_i2c_addr = PSU_CPLD_I2C_MAPPING[psu_index]["addr"] + self.cpld_path = PSU_I2C_PATH.format(psu_i2c_bus, psu_i2c_addr) + + # Set hwmon path + i2c_path = { + 0: "14-0048/hwmon/hwmon*/", + 1: "24-004b/hwmon/hwmon*/", + 2: "25-004a/hwmon/hwmon*/" + }.get(self.index, None) + + self.hwmon_path = "{}/{}".format(self.SYSFS_PATH, i2c_path) + self.ss_key = self.THERMAL_NAME_LIST[self.index] + self.ss_index = 1 + + def __read_txt_file(self, file_path): + for filename in glob.glob(file_path): + try: + with open(filename, 'r') as fd: + data =fd.readline().rstrip() + return data + except IOError as e: + pass + + return None + + def __get_temp(self, temp_file): + if not self.is_psu: + temp_file_path = os.path.join(self.hwmon_path, temp_file) + else: + temp_file_path = temp_file + raw_temp = self.__read_txt_file(temp_file_path) + if raw_temp is not None: + return float(raw_temp)/1000 + else: + return 0 + + def __get_max_temp(self, paths): + max_temp = -1.0 + max_idx = 0 + for i, path in enumerate(paths): + read_temp = self.__get_temp(path) + if(read_temp > max_temp): + max_temp = read_temp + max_idx = i + return max_temp, max_idx + + def __get_cpu_threshold(self, type): + path = self.cpu_paths[self.cpu_path_idx] + high_warn = self.__get_temp(path.replace('_input', '_max')) + if type == 'high_warn': + return high_warn + high_crit = self.__get_temp(path.replace('_input', '_crit')) + if type == 'high_crit': + return high_crit + if type == 'high_err': + return (high_crit + high_warn) / 2 + return 0 # for all low_* thresholds + + def __try_get_threshold(self, type): + if self.is_cpu: + return self.__get_cpu_threshold(type) + + if self.is_psu is True: + raise NotImplementedError # PSU on this model doesn't support this. + + if self.index in self.THRESHOLDS: + return getattr(self.THRESHOLDS[self.index], type) + else: + return None + + def get_temperature(self): + """ + Retrieves current temperature reading from thermal + Returns: + A float number of current temperature in Celsius up to nearest thousandth + of one degree Celsius, e.g. 30.125 + """ + if self.is_cpu: + cpu_temp, self.cpu_path_idx = self.__get_max_temp(self.cpu_paths) + return cpu_temp + + if not self.is_psu: + temp_file = "temp{}_input".format(self.ss_index) + else: + temp_file = self.psu_hwmon_path + "psu_temp1_input" + + return self.__get_temp(temp_file) + + def get_name(self): + """ + Retrieves the name of the thermal device + Returns: + string: The name of the thermal device + """ + if self.is_cpu: + return self.CPU_THERMAL_NAME + if self.is_psu: + return self.PSU_THERMAL_NAME_LIST[self.psu_index] + else: + return self.THERMAL_NAME_LIST[self.index] + + def get_presence(self): + """ + Retrieves the presence of the Thermal + Returns: + bool: True if Thermal is present, False if not + """ + if self.is_cpu: + return True + + if self.is_psu: + val = self.__read_txt_file(self.cpld_path + "psu_present") + return int(val, 10) == 1 + temp_file = "temp{}_input".format(self.ss_index) + temp_file_path = os.path.join(self.hwmon_path, temp_file) + raw_txt = self.__read_txt_file(temp_file_path) + if raw_txt is not None: + return True + else: + return False + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + if self.is_cpu: + return True + + if self.is_psu: + temp_file = self.psu_hwmon_path + "psu_temp_fault" + return self.get_presence() and (not int( + self.__read_txt_file(temp_file))) + + file_str = "temp{}_input".format(self.ss_index) + file_path = os.path.join(self.hwmon_path, file_str) + raw_txt = self.__read_txt_file(file_path) + if raw_txt is None: + return False + else: + return int(raw_txt) != 0 + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + + return "N/A" + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return "N/A" + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Retrieves whether thermal module is replaceable + Returns: + A boolean value, True if replaceable, False if not + """ + return False + + def get_high_critical_threshold(self): + return self.__try_get_threshold('high_crit') + + def get_low_critical_threshold(self): + return self.__try_get_threshold('low_crit') + + def get_high_threshold(self): + return self.__try_get_threshold('high_err') + + def get_low_threshold(self): + return self.__try_get_threshold('low_err') + + def get_high_warning_threshold(self): + return self.__try_get_threshold('high_warn') + + def get_low_warning_threshold(self): + return self.__try_get_threshold('low_warn') diff --git a/device/accton/x86_64-accton_as4630_54npe-r0/system_health_monitoring_config.json b/device/accton/x86_64-accton_as4630_54npe-r0/system_health_monitoring_config.json new file mode 100644 index 00000000000..692d969d061 --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54npe-r0/system_health_monitoring_config.json @@ -0,0 +1,14 @@ +{ + "services_to_ignore": [], + "devices_to_ignore": [ + "asic", + "psu.temperature" + ], + "user_defined_checkers": [], + "polling_interval": 60, + "led_color": { + "fault": "STATUS_LED_COLOR_AMBER", + "normal": "STATUS_LED_COLOR_GREEN", + "booting": "STATUS_LED_COLOR_GREEN_BLINK" + } +} diff --git a/device/accton/x86_64-accton_as4630_54pe-r0/installer.conf b/device/accton/x86_64-accton_as4630_54pe-r0/installer.conf index 925a32fc0c3..735fa7992db 100755 --- a/device/accton/x86_64-accton_as4630_54pe-r0/installer.conf +++ b/device/accton/x86_64-accton_as4630_54pe-r0/installer.conf @@ -1,3 +1,4 @@ CONSOLE_PORT=0x3f8 CONSOLE_DEV=0 CONSOLE_SPEED=115200 +ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="intel_iommu=off modprobe.blacklist=i2c-ismt,i2c_ismt,i2c-i801,i2c_i801" diff --git a/device/accton/x86_64-accton_as4630_54pe-r0/pddf/pd-plugin.json b/device/accton/x86_64-accton_as4630_54pe-r0/pddf/pd-plugin.json new file mode 100644 index 00000000000..0abf66aab7a --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54pe-r0/pddf/pd-plugin.json @@ -0,0 +1,66 @@ +{ + "XCVR": + { + "xcvr_present": + { + "i2c": + { + "valmap-SFP28": {"1":true, "0":false }, + "valmap-QSFP28": {"1":true, "0":false} + } + } + }, + + "PSU": + { + "psu_present": + { + "i2c": + { + "valmap": { "1":true, "0":false } + } + }, + + "psu_power_good": + { + "i2c": + { + "valmap": { "1": true, "0":false } + } + }, + + "psu_fan_dir": + { + "i2c": + { + "valmap": { "F2B":"EXHAUST", "B2F":"INTAKE" } + } + }, + + "PSU_FAN_MAX_SPEED":"18000" + }, + + "FAN": + { + "direction": + { + "i2c": + { + "valmap": {"1":"EXHAUST", "0":"INTAKE"} + } + }, + + "present": + { + "i2c": + { + "valmap": {"1":true, "0":false} + } + }, + + "duty_cycle_to_pwm": "lambda dc: ((dc*100.0)/625)", + + "pwm_to_duty_cycle": "lambda pwm: ((pwm*625.0)/100)" + } + +} diff --git a/device/accton/x86_64-accton_as4630_54pe-r0/pddf/pddf-device.json b/device/accton/x86_64-accton_as4630_54pe-r0/pddf/pddf-device.json new file mode 100644 index 00000000000..37bd3fea286 --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54pe-r0/pddf/pddf-device.json @@ -0,0 +1,638 @@ +{ + "PLATFORM": + { + "num_psus":2, + "num_fantrays":3, + "num_fans_pertray":1, + "num_ports":54, + "num_temps": 3, + "pddf_dev_types": + { + "description":"AS4630 - Below is the list of supported PDDF device types (chip names) for various components. If any component uses some other driver, we will create the client using 'echo > /new_device' method", + "CPLD": + [ + "i2c_cpld" + ], + "PSU": + [ + "psu_eeprom", + "psu_pmbus" + ], + "FAN": + [ + "fan_ctrl", + "fan_eeprom", + "fan_cpld" + ], + "PORT_MODULE": + [ + "pddf_xcvr" + ] + + }, + "std_kos": + [ + "i2c_dev", + "i2c_mux_pca954x", + "optoe" + ], + "description":"kernel modules are loaded while moving to pdf mode, but they should not be unloaded while moving to nonpddf mode.", + "std_perm_kos": + [ + "i2c-i801", + "i2c-ismt" + ], + + "pddf_kos": + [ + "pddf_client_module", + "pddf_cpld_module", + "pddf_cpld_driver", + "pddf_mux_module", + "pddf_xcvr_module", + "pddf_xcvr_driver_module", + "pddf_psu_driver_module", + "pddf_psu_module", + "pddf_fan_driver_module", + "pddf_fan_module", + "pddf_led_module" + ] + }, + + "SYSTEM": + { + "dev_info": {"device_type":"CPU", "device_name":"ROOT_COMPLEX", "device_parent":null}, + "i2c": + { + "CONTROLLERS": + [ + { "dev_name":"i2c-1", "dev":"SMBUS1" } + ] + } + }, + + "SMBUS1": + { + "dev_info": {"device_type": "SMBUS", "device_name": "SMBUS1", "device_parent": "SYSTEM"}, + "i2c": + { + "topo_info": {"dev_addr": "0x1"}, + "DEVICES": + [ + {"dev": "EEPROM1"}, + {"dev": "MUX1"} + ] + } + }, + + + "EEPROM1": + { + "dev_info": {"device_type": "EEPROM", "device_name": "EEPROM1", "device_parent": "SMBUS1"}, + "i2c": + { + "topo_info": {"parent_bus": "0x1", "dev_addr": "0x57", "dev_type": "24c02"}, + "dev_attr": {"access_mode": "BLOCK"}, + "attr_list": [ + {"attr_name": "eeprom"} + ] + } + }, + + "MUX1": + { + "dev_info": { "device_type":"MUX", "device_name":"MUX1", "device_parent":"SMBUS1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x1", "dev_addr":"0x77", "dev_type":"pca9548"}, + "dev_attr": { "virt_bus":"0x2"}, + "channel": + [ + { "chn":"0", "dev":"MUX2" }, + { "chn":"1", "dev":"MUX3" }, + { "chn":"1", "dev":"CPLD1" }, + { "chn":"1", "dev":"FAN-CTRL" } + ] + } + }, + + "MUX2": + { + "dev_info": { "device_type":"MUX", "device_name":"MUX2", "device_parent":"MUX1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2", "dev_addr":"0x71", "dev_type":"pca9548"}, + "dev_attr": { "virt_bus":"0xa"}, + "channel": + [ + { "chn":"0", "dev":"PSU1" }, + { "chn":"1", "dev":"PSU2" }, + { "chn":"4", "dev":"TEMP1" } + ] + } + }, + + "TEMP1" : + { + "dev_info": { "device_type":"TEMP_SENSOR", "device_parent":"MUX2"}, + "dev_attr": { "display_name":"Temp_1"}, + "i2c": + { + "topo_info": { "parent_bus":"0xe", "dev_addr":"0x48", "dev_type":"lm77"}, + "attr_list": + [ + { "attr_name": "temp1_high_crit_threshold", "drv_attr_name":"temp1_crit"}, + { "attr_name": "temp1_crit_hyst"}, + { "attr_name": "temp1_crit_alarm"}, + { "attr_name": "temp1_max_alarm"}, + { "attr_name": "temp1_min_alarm"}, + { "attr_name": "temp1_input"}, + { "attr_name": "temp1_high_threshold", "drv_attr_name":"temp1_max"}, + { "attr_name": "temp1_low_threshold", "drv_attr_name":"temp1_min"}, + { "attr_name": "temp1_max_hyst"}, + { "attr_name": "temp1_min_hyst"} + ] + } + }, + + "MUX3": + { + "dev_info": { "device_type":"MUX", "device_name":"MUX3", "device_parent":"MUX1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x3", "dev_addr":"0x70", "dev_type":"pca9548"}, + "dev_attr": { "virt_bus":"0x12"}, + "channel": + [ + { "chn":"0", "dev":"PORT49" }, + { "chn":"1", "dev":"PORT50" }, + { "chn":"2", "dev":"PORT51" }, + { "chn":"3", "dev":"PORT52" }, + { "chn":"4", "dev":"PORT53" }, + { "chn":"5", "dev":"PORT54" }, + { "chn":"6", "dev":"TEMP2" }, + { "chn":"7", "dev":"TEMP3" } + ] + } + }, + + + "TEMP2" : + { + "dev_info": { "device_type":"TEMP_SENSOR", "device_parent":"MUX3"}, + "dev_attr": { "display_name":"Temp_CPU"}, + + "i2c": + { + "topo_info": { "parent_bus":"0x18", "dev_addr":"0x4b", "dev_type":"lm75"}, + "attr_list": + [ + { "attr_name": "temp1_high_threshold", "drv_attr_name":"temp1_max"}, + { "attr_name": "temp1_max_hyst"}, + { "attr_name": "temp1_input"} + ] + } + }, + + + "TEMP3" : + { + "dev_info": { "device_type":"TEMP_SENSOR", "device_parent":"MUX3"}, + "dev_attr": { "display_name":"Temp_Fan"}, + "i2c": + { + "topo_info": { "parent_bus":"0x19", "dev_addr":"0x4a", "dev_type":"lm75"}, + "attr_list": + [ + { "attr_name": "temp1_high_threshold", "drv_attr_name":"temp1_max"}, + { "attr_name": "temp1_max_hyst"}, + { "attr_name": "temp1_input"} + ] + } + }, + + + "CPLD1": + { + "dev_info": { "device_type":"CPLD", "device_name":"CPLD1", "device_parent":"MUX1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x3", "dev_addr":"0x60", "dev_type":"i2c_cpld"} + } + }, + + + "FAN-CTRL": + { + "dev_info": { "device_type":"FAN", "device_name":"FAN-CTRL", "device_parent":"MUX1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x3", "dev_addr":"0x66", "dev_type":"fan_cpld"}, + "dev_attr": { "num_fantrays":"3"}, + "attr_list": + [ + { "attr_name":"fan1_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x87", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan2_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x87", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan3_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x87", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan1_direction", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x87", "attr_mask":"0x10", "attr_cmpval":"0x10", "attr_len":"1"}, + { "attr_name":"fan2_direction", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x87", "attr_mask":"0x20", "attr_cmpval":"0x20", "attr_len":"1"}, + { "attr_name":"fan3_direction", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x87", "attr_mask":"0x40", "attr_cmpval":"0x40", "attr_len":"1"}, + { "attr_name":"fan1_input", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x88", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"114", "attr_is_divisor":0}, + { "attr_name":"fan2_input", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x89", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"114" , "attr_is_divisor":0}, + { "attr_name":"fan3_input", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x8a", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"114", "attr_is_divisor":0}, + { "attr_name":"fan1_pwm", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x1a", "attr_mask":"0x1F", "attr_len":"1"}, + { "attr_name":"fan2_pwm", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x1a", "attr_mask":"0x1F", "attr_len":"1"}, + { "attr_name":"fan3_pwm", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x1b", "attr_mask":"0x1F", "attr_len":"1"} + ] + } + }, + + + "SYS_LED": + { + "dev_info": { "device_type":"LED", "device_name":"SYS_LED"}, + "dev_attr": { "index":"0"}, + "i2c" : { + "attr_list": + [ + {"attr_name":"STATUS_LED_COLOR_GREEN", "bits" : "7:5", "descr" : "", "value" : "0x1", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x30"}, + {"attr_name":"STATUS_LED_COLOR_GREEN_BLINK", "bits" : "7:5", "descr" : "", "value" : "0x3", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x30"}, + {"attr_name":"STATUS_LED_COLOR_AMBER", "bits" : "7:5", "descr" : "", "value" : "0x4", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x30"}, + {"attr_name":"STATUS_LED_COLOR_AMBER_BLINK", "bits" : "7:5", "descr" : "", "value" : "0x2", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x30"}, + {"attr_name":"STATUS_LED_COLOR_OFF", "bits" : "7:5", "descr" : "", "value" : "0x7", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x30"} + ] + } + }, + + + "PSU1_LED": + { + "dev_info": { "device_type":"LED", "device_name":"PSU_LED"}, + "dev_attr": { "index":"0"}, + "i2c" : { + "attr_list": + [ + {"attr_name":"STATUS_LED_COLOR_GREEN", "bits" : "1:0", "descr" : "", "value" : "0x1", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x30"}, + {"attr_name":"STATUS_LED_COLOR_AMBER", "bits" : "1:0", "descr" : "", "value" : "0x2", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x30"}, + {"attr_name":"STATUS_LED_COLOR_OFF", "bits" : "1:0", "descr" : "", "value" : "0x3", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x30"} + ] + } + }, + + "PSU2_LED": + { + "dev_info": { "device_type":"LED", "device_name":"PSU_LED"}, + "dev_attr": { "index":"1"}, + "i2c" : { + "attr_list": + [ + {"attr_name":"STATUS_LED_COLOR_GREEN", "bits" : "7:6", "descr" : "", "value" : "0x1", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x31"}, + {"attr_name":"STATUS_LED_COLOR_AMBER", "bits" : "7:6", "descr" : "", "value" : "0x2", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x31"}, + {"attr_name":"STATUS_LED_COLOR_OFF", "bits" : "7:6", "descr" : "", "value" : "0x3", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x31"} + ] + } + }, + + "FAN_LED": + { + "dev_info": { "device_type":"LED", "device_name":"FAN_LED"}, + "dev_attr": { "index":"0"}, + "i2c" : { + "attr_list": + [ + {"attr_name":"STATUS_LED_COLOR_GREEN", "bits" : "3:2", "descr" : "", "value" : "0x1", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x31"}, + {"attr_name":"STATUS_LED_COLOR_AMBER", "bits" : "3:2", "descr" : "", "value" : "0x2", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x31"}, + {"attr_name":"STATUS_LED_COLOR_OFF", "bits" : "3:2", "descr" : "", "value" : "0x3", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x31"} + ] + } + }, + + "PSU1": + { + "dev_info": { "device_type":"PSU", "device_name":"PSU1", "device_parent":"MUX2"}, + "dev_attr": { "dev_idx":"1", "num_psu_fans": "1"}, + "i2c": + { + "interface": + [ + { "itf":"pmbus", "dev":"PSU1-PMBUS" }, + { "itf":"eeprom", "dev":"PSU1-EEPROM" } + ] + + } + }, + + "PSU1-PMBUS": + { + "dev_info": { "device_type":"PSU-PMBUS", "device_name":"PSU1-PMBUS", "device_parent":"MUX2", "virt_parent":"PSU1"}, + "i2c": + { + "topo_info":{ "parent_bus":"0xa", "dev_addr":"0x58", "dev_type":"psu_pmbus"}, + "attr_list": + [ + { "attr_name":"psu_mfr_id", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0X99", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"10" }, + { "attr_name":"psu_fan_dir", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0xc3", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"5"}, + { "attr_name":"psu_v_out", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x8b", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_i_out", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x8c", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_p_out", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x96", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_fan1_speed_rpm", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x90", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_temp1_input", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x8d", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"} + ] + } + }, + + "PSU1-EEPROM": + { + "dev_info": { "device_type":"PSU-EEPROM", "device_name":"PSU1-EEPROM", "device_parent":"MUX2", "virt_parent":"PSU1"}, + "i2c": + { + "topo_info":{ "parent_bus":"0xa", "dev_addr":"0x50", "dev_type":"psu_eeprom"}, + "attr_list": + [ + { "attr_name":"psu_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x22", "attr_mask":"0x20", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"psu_model_name", "attr_devaddr":"0x50", "attr_devtype":"eeprom", "attr_offset":"0x20", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"12" }, + { "attr_name":"psu_power_good", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x22", "attr_mask":"0x40", "attr_cmpval":"0x40", "attr_len":"1"}, + { "attr_name":"psu_serial_num", "attr_devaddr":"0x50", "attr_devtype":"eeprom", "attr_offset":"0x35", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"19" } + ] + } + }, + + + "PSU2": + { + "dev_info": { "device_type":"PSU", "device_name":"PSU2", "device_parent":"MUX2" }, + "dev_attr": { "dev_idx":"2", "num_psu_fans":"1"}, + "i2c": + { + "interface": + [ + { "itf":"pmbus", "dev":"PSU2-PMBUS"}, + { "itf":"eeprom", "dev":"PSU2-EEPROM"} + ] + } + + }, + + "PSU2-PMBUS": + { + "dev_info": {"device_type":"PSU-PMBUS", "device_name":"PSU2-PMBUS", "device_parent":"MUX2", "virt_parent":"PSU2"}, + "i2c": + { + "topo_info": { "parent_bus":"0xb", "dev_addr":"0x59", "dev_type":"psu_pmbus"}, + "attr_list": + [ + { "attr_name":"psu_mfr_id", "attr_devaddr":"0x59", "attr_devtype":"pmbus", "attr_offset":"0X99", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"10" }, + { "attr_name":"psu_fan_dir", "attr_devaddr":"0x59", "attr_devtype":"pmbus", "attr_offset":"0xc3", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"5"}, + { "attr_name":"psu_v_out", "attr_devaddr":"0x59", "attr_devtype":"pmbus", "attr_offset":"0x8b", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_i_out", "attr_devaddr":"0x59", "attr_devtype":"pmbus", "attr_offset":"0x8c", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_p_out", "attr_devaddr":"0x59", "attr_devtype":"pmbus", "attr_offset":"0x96", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_fan1_speed_rpm", "attr_devaddr":"0x59", "attr_devtype":"pmbus", "attr_offset":"0x90", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_temp1_input", "attr_devaddr":"0x59", "attr_devtype":"pmbus", "attr_offset":"0x8d", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"} + ] + } + }, + + "PSU2-EEPROM": + { + "dev_info": {"device_type":"PSU-EEPROM", "device_name":"PSU2-EEPROM", "device_parent":"MUX2", "virt_parent":"PSU2"}, + "i2c": + { + "topo_info": { "parent_bus":"0xb", "dev_addr":"0x51", "dev_type":"psu_eeprom"}, + "attr_list": + [ + { "attr_name":"psu_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x22", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"psu_model_name", "attr_devaddr":"0x51", "attr_devtype":"eeprom", "attr_offset":"0x20", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"12" }, + { "attr_name":"psu_power_good", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x22", "attr_mask":"0x4", "attr_cmpval":"0x4", "attr_len":"1"}, + { "attr_name":"psu_serial_num", "attr_devaddr":"0x51", "attr_devtype":"eeprom", "attr_offset":"0x35", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"19" } + ] + } + }, + + "PORT49": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT49", "device_parent":"MUX3"}, + "dev_attr": { "dev_idx":"49"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT49-EEPROM" }, + { "itf":"control", "dev":"PORT49-CTRL" } + ] + } + }, + "PORT49-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT49-EEPROM", "device_parent":"MUX3", "virt_parent":"PORT49"}, + "i2c": + { + "topo_info": { "parent_bus":"0x12", "dev_addr":"0x50", "dev_type":"optoe2"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT49-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT49-CTRL", "device_parent":"MUX3", "virt_parent":"PORT49"}, + "i2c": + { + "topo_info": { "parent_bus":"0x12", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x05", "attr_mask":"0x6", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT50": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT50", "device_parent":"MUX3"}, + "dev_attr": { "dev_idx":"50"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT50-EEPROM" }, + { "itf":"control", "dev":"PORT50-CTRL" } + ] + } + }, + "PORT50-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT50-EEPROM", "device_parent":"MUX3", "virt_parent":"PORT50"}, + "i2c": + { + "topo_info": { "parent_bus":"0x13", "dev_addr":"0x50", "dev_type":"optoe2"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT50-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT50-CTRL", "device_parent":"MUX3", "virt_parent":"PORT50"}, + "i2c": + { + "topo_info": { "parent_bus":"0x13", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x05", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT51": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT51", "device_parent":"MUX3"}, + "dev_attr": { "dev_idx":"51"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT51-EEPROM" }, + { "itf":"control", "dev":"PORT51-CTRL" } + ] + } + }, + "PORT51-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT51-EEPROM", "device_parent":"MUX3", "virt_parent":"PORT51"}, + "i2c": + { + "topo_info": { "parent_bus":"0x14", "dev_addr":"0x50", "dev_type":"optoe2"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT51-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT51-CTRL", "device_parent":"MUX3", "virt_parent":"PORT51"}, + "i2c": + { + "topo_info": { "parent_bus":"0x14", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x06", "attr_mask":"0x6", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + "PORT52": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT52", "device_parent":"MUX3"}, + "dev_attr": { "dev_idx":"52"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT52-EEPROM" }, + { "itf":"control", "dev":"PORT52-CTRL" } + ] + } + }, + "PORT52-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT52-EEPROM", "device_parent":"MUX3", "virt_parent":"PORT52"}, + "i2c": + { + "topo_info": { "parent_bus":"0x15", "dev_addr":"0x50", "dev_type":"optoe2"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT52-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT52-CTRL", "device_parent":"MUX3", "virt_parent":"PORT52"}, + "i2c": + { + "topo_info": { "parent_bus":"0x15", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x06", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT53": + { + "dev_info": { "device_type":"QSFP28", "device_name":"PORT53", "device_parent":"MUX3"}, + "dev_attr": { "dev_idx":"53"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT53-EEPROM" }, + { "itf":"control", "dev":"PORT53-CTRL" } + ] + } + }, + "PORT53-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT53-EEPROM", "device_parent":"MUX3", "virt_parent":"PORT53"}, + "i2c": + { + "topo_info": { "parent_bus":"0x16", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT53-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT53-CTRL", "device_parent":"MUX3", "virt_parent":"PORT53"}, + "i2c": + { + "topo_info": { "parent_bus":"0x16", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x21", "attr_mask":"0x0", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT54": + { + "dev_info": { "device_type":"QSFP28", "device_name":"PORT54", "device_parent":"MUX3"}, + "dev_attr": { "dev_idx":"54"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT54-EEPROM" }, + { "itf":"control", "dev":"PORT54-CTRL" } + ] + } + }, + "PORT54-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT54-EEPROM", "device_parent":"MUX3", "virt_parent":"PORT54"}, + "i2c": + { + "topo_info": { "parent_bus":"0x17", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT54-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT54-CTRL", "device_parent":"MUX3", "virt_parent":"PORT54"}, + "i2c": + { + "topo_info": { "parent_bus":"0x17", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x21", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + } + +} diff --git a/device/accton/x86_64-accton_as4630_54pe-r0/pddf_support b/device/accton/x86_64-accton_as4630_54pe-r0/pddf_support new file mode 100644 index 00000000000..e69de29bb2d diff --git a/device/accton/x86_64-accton_as4630_54pe-r0/pmon_daemon_control.json b/device/accton/x86_64-accton_as4630_54pe-r0/pmon_daemon_control.json index 584a14b9d94..a3b204e20d8 100644 --- a/device/accton/x86_64-accton_as4630_54pe-r0/pmon_daemon_control.json +++ b/device/accton/x86_64-accton_as4630_54pe-r0/pmon_daemon_control.json @@ -1,5 +1,5 @@ { "skip_ledd": true, - "skip_thermalctld": true + "skip_pcied": true } diff --git a/device/accton/x86_64-accton_as4630_54pe-r0/system_health_monitoring_config.json b/device/accton/x86_64-accton_as4630_54pe-r0/system_health_monitoring_config.json new file mode 100644 index 00000000000..61f624ee34c --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54pe-r0/system_health_monitoring_config.json @@ -0,0 +1,17 @@ +{ + "services_to_ignore": [], + "devices_to_ignore": [ + "asic", + "psu.voltage", + "psu.temperature", + "PSU1_FAN1.speed", + "PSU2_FAN1.speed" + ], + "user_defined_checkers": [], + "polling_interval": 60, + "led_color": { + "fault": "STATUS_LED_COLOR_AMBER", + "normal": "STATUS_LED_COLOR_GREEN", + "booting": "STATUS_LED_COLOR_GREEN_BLINK" + } +} diff --git a/device/accton/x86_64-accton_as5812_54x-r0/installer.conf b/device/accton/x86_64-accton_as5812_54x-r0/installer.conf index 14404194ef5..d0ed16575e7 100644 --- a/device/accton/x86_64-accton_as5812_54x-r0/installer.conf +++ b/device/accton/x86_64-accton_as5812_54x-r0/installer.conf @@ -1,3 +1,4 @@ CONSOLE_PORT=0x2f8 CONSOLE_DEV=1 CONSOLE_SPEED=115200 +ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="modprobe.blacklist=i2c-ismt,i2c_ismt,i2c-i801,i2c_i801" diff --git a/device/accton/x86_64-accton_as5812_54x-r0/pmon_daemon_control.json b/device/accton/x86_64-accton_as5812_54x-r0/pmon_daemon_control.json index 584a14b9d94..a3b204e20d8 100644 --- a/device/accton/x86_64-accton_as5812_54x-r0/pmon_daemon_control.json +++ b/device/accton/x86_64-accton_as5812_54x-r0/pmon_daemon_control.json @@ -1,5 +1,5 @@ { "skip_ledd": true, - "skip_thermalctld": true + "skip_pcied": true } diff --git a/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/__init__.py b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/__init__.py new file mode 100644 index 00000000000..73a7720e897 --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/__init__.py @@ -0,0 +1,2 @@ +__all__ = [ "platform", "chassis", "sfp", "eeprom", "component", "psu", "thermal", "fan", "fan_drawer" ] +from . import platform diff --git a/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/chassis.py b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/chassis.py new file mode 100644 index 00000000000..05749e90959 --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/chassis.py @@ -0,0 +1,260 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Chassis information which are available in the platform +# +############################################################################# + +import os +import sys + +try: + from sonic_platform_base.chassis_base import ChassisBase + from .helper import APIHelper + from .event import SfpEvent +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +NUM_FAN_TRAY = 5 +NUM_FAN = 2 +NUM_PSU = 2 +NUM_THERMAL = 3 +PORT_END = 54 +QSFP_PORT_START = 49 +QSFP_PORT_END = 54 +NUM_COMPONENT = 4 +HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/" +PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/" +REBOOT_CAUSE_FILE = "reboot-cause.txt" +PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt" +HOST_CHK_CMD = "which systemctl > /dev/null 2>&1" +SYSLED_FNODE= "/sys/class/leds/accton_as5812_54x_led::diag/brightness" + +SYSLED_MODES = { + "0" : "STATUS_LED_COLOR_OFF", + "1" : "STATUS_LED_COLOR_GREEN", + "2" : "STATUS_LED_COLOR_AMBER" +} + + +class Chassis(ChassisBase): + """Platform-specific Chassis class""" + + def __init__(self): + ChassisBase.__init__(self) + self._api_helper = APIHelper() + self.is_host = self._api_helper.is_host() + + self.config_data = {} + + self.__initialize_fan() + self.__initialize_psu() + self.__initialize_thermals() + self.__initialize_components() + self.__initialize_sfp() + self.__initialize_eeprom() + + def __initialize_sfp(self): + from sonic_platform.sfp import Sfp + self.QSFP_PORT_START = QSFP_PORT_START + self.QSFP_PORT_END = QSFP_PORT_END + for index in range(0, PORT_END): + if index in range(self.QSFP_PORT_START-1, self.QSFP_PORT_END): + sfp_module = Sfp(index, 'QSFP') + else: + sfp_module = Sfp(index, 'SFP') + self._sfp_list.append(sfp_module) + + self._sfpevent = SfpEvent(self._sfp_list) + self.sfp_module_initialized = True + + def __initialize_fan(self): + from sonic_platform.fan_drawer import FanDrawer + for fant_index in range(NUM_FAN_TRAY): + fandrawer = FanDrawer(fant_index) + self._fan_drawer_list.append(fandrawer) + self._fan_list.extend(fandrawer._fan_list) + + def __initialize_psu(self): + from sonic_platform.psu import Psu + for index in range(0, NUM_PSU): + psu = Psu(index) + self._psu_list.append(psu) + + def __initialize_thermals(self): + from sonic_platform.thermal import Thermal + for index in range(0, NUM_THERMAL): + thermal = Thermal(index) + self._thermal_list.append(thermal) + + def __initialize_eeprom(self): + from sonic_platform.eeprom import Tlv + self._eeprom = Tlv() + + def __initialize_components(self): + from sonic_platform.component import Component + for index in range(0, NUM_COMPONENT): + component = Component(index) + self._component_list.append(component) + + def __initialize_watchdog(self): + from sonic_platform.watchdog import Watchdog + self._watchdog = Watchdog() + + + def __is_host(self): + return os.system(HOST_CHK_CMD) == 0 + + def __read_txt_file(self, file_path): + try: + with open(file_path, 'r') as fd: + data = fd.read() + return data.strip() + except IOError: + pass + return None + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return self._eeprom.get_product_name() + + def get_presence(self): + """ + Retrieves the presence of the Chassis + Returns: + bool: True if Chassis is present, False if not + """ + return True + + 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 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._eeprom.get_mac() + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return self._eeprom.get_pn() + + def get_serial(self): + """ + Retrieves the hardware serial number for the chassis + Returns: + A string containing the hardware serial number for this chassis. + """ + return self._eeprom.get_serial() + + 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._eeprom.get_eeprom() + + 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. + """ + + reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE) + sw_reboot_cause = self._api_helper.read_txt_file( + reboot_cause_path) or "Unknown" + + + return ('REBOOT_CAUSE_NON_HARDWARE', sw_reboot_cause) + + def get_change_event(self, timeout=0): + # SFP event + if not self.sfp_module_initialized: + self.__initialize_sfp() + return self._sfpevent.get_sfp_event(timeout) + + def get_sfp(self, index): + """ + Retrieves sfp represented by (1-based) index + Args: + index: An integer, the index (1-based) of the sfp to retrieve. + The index should be the sequence of a physical port in a chassis, + starting from 1. + For example, 1 for Ethernet0, 2 for Ethernet4 and so on. + Returns: + An object dervied from SfpBase representing the specified sfp + """ + sfp = None + if not self.sfp_module_initialized: + self.__initialize_sfp() + + try: + # The index will start from 1 + sfp = self._sfp_list[index-1] + except IndexError: + sys.stderr.write("SFP index {} out of range (1-{})\n".format( + index, len(self._sfp_list))) + return sfp + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False + + + def initizalize_system_led(self): + return True + + def get_status_led(self): + val = self._api_helper.read_txt_file(SYSLED_FNODE) + return SYSLED_MODES[val] if val in SYSLED_MODES else "UNKNOWN" + + def set_status_led(self, color): + mode = None + for key, val in SYSLED_MODES.items(): + if val == color: + mode = key + break + if mode is None: + return False + else: + return self._api_helper.write_txt_file(SYSLED_FNODE, mode) + diff --git a/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/component.py b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/component.py new file mode 100644 index 00000000000..f4f601ede6d --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/component.py @@ -0,0 +1,180 @@ +############################################################################# +# Edgecore +# +# Component contains an implementation of SONiC Platform Base API and +# provides the components firmware management function +# +############################################################################# + +import shlex +import subprocess + + +try: + from sonic_platform_base.component_base import ComponentBase + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +CPLD_ADDR_MAPPING = { + "CPLD1": "0-0060", + "CPLD2": "0-0061", + "CPLD3": "0-0062", +} +SYSFS_PATH = "/sys/bus/i2c/devices/" +BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version" +COMPONENT_LIST= [ + ("CPLD1", "CPLD 1"), + ("CPLD2", "CPLD 2"), + ("CPLD3", "CPLD 3"), + ("BIOS", "Basic Input/Output System") + +] +COMPONENT_DES_LIST = ["CPLD","Basic Input/Output System"] + + +class Component(ComponentBase): + """Platform-specific Component class""" + + DEVICE_TYPE = "component" + + def __init__(self, component_index=0): + self._api_helper=APIHelper() + ComponentBase.__init__(self) + self.index = component_index + self.name = self.get_name() + + + def __run_command(self, command): + # Run bash command and print output to stdout + try: + process = subprocess.Popen( + shlex.split(command), stdout=subprocess.PIPE) + while True: + output = process.stdout.readline() + if output == '' and process.poll() is not None: + break + rc = process.poll() + if rc != 0: + return False + except Exception: + return False + return True + + def __get_bios_version(self): + # Retrieves the BIOS firmware version + try: + with open(BIOS_VERSION_PATH, 'r') as fd: + bios_version = fd.read() + return bios_version.strip() + except Exception as e: + print('Get exception when read bios') + return None + + def __get_cpld_version(self): + # Retrieves the CPLD firmware version + cpld_version = dict() + for cpld_name in CPLD_ADDR_MAPPING: + try: + cpld_path = "{}{}{}".format(SYSFS_PATH, CPLD_ADDR_MAPPING[cpld_name], '/version') + cpld_version_raw= self._api_helper.read_txt_file(cpld_path) + cpld_version[cpld_name] = "{}".format(int(cpld_version_raw,16)) + except Exception as e: + print('Get exception when read cpld') + cpld_version[cpld_name] = 'None' + + return cpld_version + + def get_name(self): + """ + Retrieves the name of the component + Returns: + A string containing the name of the component + """ + return COMPONENT_LIST[self.index][0] + + def get_description(self): + """ + Retrieves the description of the component + Returns: + A string containing the description of the component + """ + return COMPONENT_LIST[self.index][1] + + + def get_firmware_version(self): + """ + Retrieves the firmware version of module + Returns: + string: The firmware versions of the module + """ + fw_version = None + if self.name == "BIOS": + fw_version = self.__get_bios_version() + elif "CPLD" in self.name: + cpld_version = self.__get_cpld_version() + fw_version = cpld_version.get(self.name) + + return fw_version + + def install_firmware(self, image_path): + """ + Install firmware to module + Args: + image_path: A string, path to firmware image + Returns: + A boolean, True if install successfully, False if not + """ + raise NotImplementedError + + def get_presence(self): + """ + Retrieves the presence of the device + Returns: + bool: True if device is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return 'N/A' + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return 'N/A' + + 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 True + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False diff --git a/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/eeprom.py b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/eeprom.py new file mode 100644 index 00000000000..bc9041d56b5 --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/eeprom.py @@ -0,0 +1,134 @@ +try: + import os + import sys + import re + if sys.version_info[0] >= 3: + from io import StringIO + else: + from cStringIO import StringIO + + from sonic_platform_base.sonic_eeprom import eeprom_tlvinfo +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +CACHE_ROOT = '/var/cache/sonic/decode-syseeprom' +CACHE_FILE = 'syseeprom_cache' +NULL = 'N/A' + +class Tlv(eeprom_tlvinfo.TlvInfoDecoder): + + EEPROM_DECODE_HEADLINES = 6 + + def __init__(self): + self._eeprom_path = "/sys/bus/i2c/devices/1-0057/eeprom" + super(Tlv, self).__init__(self._eeprom_path, 0, '', True) + self._eeprom = self._load_eeprom() + + def __parse_output(self, decode_output): + decode_output.replace('\0', '') + lines = decode_output.split('\n') + lines = lines[self.EEPROM_DECODE_HEADLINES:] + _eeprom_info_dict = dict() + + for line in lines: + try: + match = re.search( + '(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)([\S]+)', line) + if match is not None: + idx = match.group(1) + value = match.group(3).rstrip('\0') + + _eeprom_info_dict[idx] = value + except Exception: + pass + + return _eeprom_info_dict + + def _load_eeprom(self): + original_stdout = sys.stdout + sys.stdout = StringIO() + try: + self.read_eeprom_db() + except Exception: + decode_output = sys.stdout.getvalue() + sys.stdout = original_stdout + return self.__parse_output(decode_output) + + status = self.check_status() + if 'ok' not in status: + return False + + if not os.path.exists(CACHE_ROOT): + try: + os.makedirs(CACHE_ROOT) + except Exception: + pass + + # + # only the eeprom classes that inherit from eeprom_base + # support caching. Others will work normally + # + try: + self.set_cache_name(os.path.join(CACHE_ROOT, CACHE_FILE)) + except Exception: + pass + + e = self.read_eeprom() + if e is None: + return 0 + + try: + self.update_cache(e) + except Exception: + pass + + self.decode_eeprom(e) + decode_output = sys.stdout.getvalue() + sys.stdout = original_stdout + + (is_valid, valid_crc) = self.is_checksum_valid(e) + if not is_valid: + return False + + return self.__parse_output(decode_output) + + def _valid_tlv(self, eeprom_data): + tlvinfo_type_codes_list = [ + self._TLV_CODE_PRODUCT_NAME, + self._TLV_CODE_PART_NUMBER, + self._TLV_CODE_SERIAL_NUMBER, + self._TLV_CODE_MAC_BASE, + self._TLV_CODE_MANUF_DATE, + self._TLV_CODE_DEVICE_VERSION, + self._TLV_CODE_LABEL_REVISION, + self._TLV_CODE_PLATFORM_NAME, + self._TLV_CODE_ONIE_VERSION, + self._TLV_CODE_MAC_SIZE, + self._TLV_CODE_MANUF_NAME, + self._TLV_CODE_MANUF_COUNTRY, + self._TLV_CODE_VENDOR_NAME, + self._TLV_CODE_DIAG_VERSION, + self._TLV_CODE_SERVICE_TAG, + self._TLV_CODE_VENDOR_EXT, + self._TLV_CODE_CRC_32 + ] + + for code in tlvinfo_type_codes_list: + code_str = "0x{:X}".format(code) + eeprom_data[code_str] = eeprom_data.get(code_str, NULL) + return eeprom_data + + def get_eeprom(self): + return self._valid_tlv(self._eeprom) + + def get_pn(self): + return self._eeprom.get('0x22', NULL) + + def get_serial(self): + return self._eeprom.get('0x23', NULL) + + def get_mac(self): + return self._eeprom.get('0x24', NULL) + + def get_product_name(self): + return self._eeprom.get('0x21', NULL) diff --git a/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/event.py b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/event.py new file mode 100644 index 00000000000..2d296e5137b --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/event.py @@ -0,0 +1,62 @@ +try: + import time + from .helper import APIHelper + from sonic_py_common.logger import Logger +except ImportError as e: + raise ImportError(repr(e) + " - required module not found") + +POLL_INTERVAL_IN_SEC = 1 + +class SfpEvent: + ''' Listen to insert/remove sfp events ''' + + def __init__(self, sfp_list): + self._api_helper = APIHelper() + self._sfp_list = sfp_list + self._logger = Logger() + self._sfp_change_event_data = {'present': 0} + + def get_presence_bitmap(self): + bitmap = 0 + for sfp in self._sfp_list: + modpres = sfp.get_presence() + i=sfp.port_num-1 + if modpres: + bitmap = bitmap | (1 << i) + return bitmap + + def get_sfp_event(self, timeout=2000): + port_dict = {} + change_dict = {} + change_dict['sfp'] = port_dict + + if timeout < 1000: + cd_ms = 1000 + else: + cd_ms = timeout + + while cd_ms > 0: + bitmap = self.get_presence_bitmap() + changed_ports = self._sfp_change_event_data['present'] ^ bitmap + if changed_ports != 0: + break + time.sleep(POLL_INTERVAL_IN_SEC) + # timeout=0 means wait for event forever + if timeout != 0: + cd_ms = cd_ms - POLL_INTERVAL_IN_SEC * 1000 + + if changed_ports != 0: + for sfp in self._sfp_list: + i=sfp.port_num-1 + if (changed_ports & (1 << i)): + if (bitmap & (1 << i)) == 0: + port_dict[i+1] = '0' + else: + port_dict[i+1] = '1' + + + # Update the cache dict + self._sfp_change_event_data['present'] = bitmap + return True, change_dict + else: + return True, change_dict diff --git a/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/fan.py b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/fan.py new file mode 100644 index 00000000000..711b5b94993 --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/fan.py @@ -0,0 +1,291 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the fan status which are available in the platform +# +############################################################################# + +import logging + +try: + from sonic_platform_base.fan_base import FanBase + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +SPEED_TOLERANCE = 15 +CPLD_FAN_PATH = "/sys/bus/platform/devices/as5812_54x_fan/fan" +I2C_PATH ="/sys/bus/i2c/devices/{}-00{}/" +PSU_HWMON_I2C_MAPPING = { + 0: { + "num": 57, + "addr": "3c" + }, + 1: { + "num": 58, + "addr": "3f" + }, +} + + +PSU_CPLD_I2C_MAPPING = { + 0: { + "num": 57, + "addr": "38" + }, + 1: { + "num": 58, + "addr": "3b" + }, +} + + + +FAN_NAME_LIST = ["FAN-1F", "FAN-1R", "FAN-2F", "FAN-2R", + "FAN-3F", "FAN-3R", "FAN-4F", "FAN-4R", + "FAN-5F", "FAN-5R"] + +class Fan(FanBase): + """Platform-specific Fan class""" + + def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0): + self._api_helper=APIHelper() + self.fan_index = fan_index + self.fan_tray_index = fan_tray_index + self.is_psu_fan = is_psu_fan + #logging.debug('fan_index=%d, fan_tray_index=%d, is_psu_fan=%d',fan_tray_index, fan_index, is_psu_fan) + if self.is_psu_fan: + self.psu_index = psu_index + self.psu_i2c_num = PSU_HWMON_I2C_MAPPING[self.psu_index]['num'] + self.psu_i2c_addr = PSU_HWMON_I2C_MAPPING[self.psu_index]['addr'] + self.psu_hwmon_path = I2C_PATH.format( + self.psu_i2c_num, self.psu_i2c_addr) + + self.psu_i2c_num = PSU_CPLD_I2C_MAPPING[self.psu_index]['num'] + self.psu_i2c_addr = PSU_CPLD_I2C_MAPPING[self.psu_index]['addr'] + self.psu_cpld_path = I2C_PATH.format( + self.psu_i2c_num, self.psu_i2c_addr) + + FanBase.__init__(self) + + logging.basicConfig(level=logging.DEBUG) + + 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 not self.is_psu_fan: + dir_str = "{}{}{}".format(CPLD_FAN_PATH, self.fan_tray_index+1, '_direction') + val=self._api_helper.read_txt_file(dir_str) + if val is not None: + if int(val, 10)==0: + direction=self.FAN_DIRECTION_EXHAUST + else: + direction=self.FAN_DIRECTION_INTAKE + else: + direction=self.FAN_DIRECTION_EXHAUST + else: #For PSU + dir_str = "{}{}".format(self.psu_hwmon_path,'psu_fan_dir') + + val=self._api_helper.read_txt_file(dir_str) + #logging.debug('dir_str=%s, val=%s', dir_str, val) + if val is not None: + if val=='F2B': + direction=self.FAN_DIRECTION_EXHAUST + else: + direction=self.FAN_DIRECTION_INTAKE + else: + direction=self.FAN_DIRECTION_EXHAUST + + 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) + + """ + speed = 0 + if self.is_psu_fan: + psu_fan_path= "{}{}".format(self.psu_hwmon_path, 'psu_fan1_speed_rpm') + fan_speed_rpm = self._api_helper.read_txt_file(psu_fan_path) + if fan_speed_rpm is not None: + speed = (int(fan_speed_rpm,10))*100/26688 + if speed > 100: + speed=100 + else: + return 0 + elif self.get_presence(): + speed_path = "{}{}{}".format(CPLD_FAN_PATH, self.fan_tray_index+1, '_duty_cycle_percentage') + speed=self._api_helper.read_txt_file(speed_path) + if speed is None: + return 0 + + return int(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) + + Note: + speed_pc = pwm_target/255*100 + + 0 : when PWM mode is use + pwm : when pwm mode is not use + """ + return self.get_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 + """ + return SPEED_TOLERANCE + + 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 not self.is_psu_fan and self.get_presence(): + speed_path = "{}{}{}".format(CPLD_FAN_PATH, self.fan_tray_index+1, '_duty_cycle_percentage') + return self._api_helper.write_txt_file(speed_path, int(speed)) + + return False + + def set_status_led(self, color): + """ + Sets the state of the fan module status LED + Args: + color: A string representing the color with which to set the + fan module status LED + Returns: + bool: True if status LED state is set successfully, False if not + """ + return False #Not supported + + def get_status_led(self): + """ + Gets the state of the fan status LED + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + status=self.get_presence() + if status is None: + return self.STATUS_LED_COLOR_OFF + + return { + 1: self.STATUS_LED_COLOR_GREEN, + 0: self.STATUS_LED_COLOR_RED + }.get(status, self.STATUS_LED_COLOR_OFF) + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + fan_name = FAN_NAME_LIST[self.fan_tray_index*2 + self.fan_index] \ + if not self.is_psu_fan \ + else "PSU-{} FAN-{}".format(self.psu_index+1, self.fan_index+1) + + return fan_name + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if FAN is present, False if not + """ + + + if self.is_psu_fan: + present_path="{}{}".format(self.psu_cpld_path, 'psu_present') + else: + present_path = "{}{}{}".format(CPLD_FAN_PATH, self.fan_tray_index+1, '_speed_rpm') + + val=self._api_helper.read_txt_file(present_path) + if val is not None: + return int(val, 10)!=0 + else: + return False + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + if self.is_psu_fan: + psu_fan_path= "{}{}".format(self.psu_hwmon_path, 'psu_fan1_fault') + val=self._api_helper.read_txt_file(psu_fan_path) + if val is not None: + return int(val, 10)==0 + else: + return False + else: + path = "{}{}{}".format(CPLD_FAN_PATH, self.fan_tray_index+1, '_fault') + val=self._api_helper.read_txt_file(path) + if val is not None: + return int(val, 10)==0 + else: + return False + + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + + return "N/A" + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return "N/A" + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return (self.fan_index+1) \ + if not self.is_psu_fan else (self.psu_index+1) + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True if not self.is_psu_fan else False + diff --git a/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/fan_drawer.py b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/fan_drawer.py new file mode 100644 index 00000000000..17d339ee55f --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/fan_drawer.py @@ -0,0 +1,90 @@ +######################################################################## +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Fan-Drawers' information available in the platform. +# +######################################################################## + +try: + from sonic_platform_base.fan_drawer_base import FanDrawerBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +FANS_PER_FANTRAY = 2 + + +class FanDrawer(FanDrawerBase): + """Platform-specific Fan class""" + + def __init__(self, fantray_index): + + FanDrawerBase.__init__(self) + # FanTray is 0-based in platforms + self.fantrayindex = fantray_index + self.__initialize_fan_drawer() + + + def __initialize_fan_drawer(self): + from sonic_platform.fan import Fan + for i in range(FANS_PER_FANTRAY): + self._fan_list.append(Fan(self.fantrayindex, i)) + + def get_name(self): + """ + Retrieves the fan drawer name + Returns: + string: The name of the device + """ + return "FanTray{}".format(self.fantrayindex+1) + + def get_presence(self): + """ + Retrieves the presence of the device + Returns: + bool: True if device is present, False if not + """ + return self._fan_list[0].get_presence() + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return self._fan_list[0].get_model() + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return self._fan_list[0].get_serial() + + 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._fan_list[0].get_status() + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return (self.fantrayindex+1) + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True diff --git a/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/helper.py b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/helper.py new file mode 100644 index 00000000000..b124ca29f0d --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/helper.py @@ -0,0 +1,117 @@ +import os +import struct +import subprocess +from mmap import * +from sonic_py_common import device_info + +HOST_CHK_CMD = "docker > /dev/null 2>&1" +EMPTY_STRING = "" + + +class APIHelper(): + + def __init__(self): + (self.platform, self.hwsku) = device_info.get_platform_and_hwsku() + + def is_host(self): + return os.system(HOST_CHK_CMD) == 0 + + def pci_get_value(self, resource, offset): + status = True + result = "" + try: + fd = os.open(resource, os.O_RDWR) + mm = mmap(fd, 0) + mm.seek(int(offset)) + read_data_stream = mm.read(4) + result = struct.unpack('I', read_data_stream) + except Exception: + status = False + return status, result + + def run_command(self, cmd): + status = True + result = "" + try: + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + except Exception: + status = False + return status, result + + def run_interactive_command(self, cmd): + try: + os.system(cmd) + except Exception: + return False + return True + + def read_txt_file(self, file_path): + try: + with open(file_path, 'r', errors='replace') as fd: + data = fd.read() + return data.strip() + except IOError: + pass + return None + + def write_txt_file(self, file_path, value): + try: + with open(file_path, 'w') as fd: + fd.write(str(value)) + except IOError: + return False + return True + + def ipmi_raw(self, netfn, cmd): + status = True + result = "" + try: + cmd = "ipmitool raw {} {}".format(str(netfn), str(cmd)) + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result + + def ipmi_fru_id(self, id, key=None): + status = True + result = "" + try: + cmd = "ipmitool fru print {}".format(str( + id)) if not key else "ipmitool fru print {0} | grep '{1}' ".format(str(id), str(key)) + + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result + + def ipmi_set_ss_thres(self, id, threshold_key, value): + status = True + result = "" + try: + cmd = "ipmitool sensor thresh '{}' {} {}".format(str(id), str(threshold_key), str(value)) + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result diff --git a/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/platform.py b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/platform.py new file mode 100644 index 00000000000..2f2c2a447fc --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/platform.py @@ -0,0 +1,21 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the platform information +# +############################################################################# + +try: + from sonic_platform_base.platform_base import PlatformBase + from sonic_platform.chassis import Chassis +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Platform(PlatformBase): + """Platform-specific Platform class""" + + def __init__(self): + PlatformBase.__init__(self) + self._chassis = Chassis() diff --git a/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/psu.py b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/psu.py new file mode 100644 index 00000000000..14debeb9767 --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/psu.py @@ -0,0 +1,263 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the PSUs status which are available in the platform +# +############################################################################# + +#import sonic_platform + +try: + from sonic_platform_base.psu_base import PsuBase + from sonic_platform.thermal import Thermal + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +I2C_PATH ="/sys/bus/i2c/devices/{0}-00{1}/" + +PSU_NAME_LIST = ["PSU-1", "PSU-2"] +PSU_NUM_FAN = [1, 1] +PSU_HWMON_I2C_MAPPING = { + 0: { + "num": 57, + "addr": "3c" + }, + 1: { + "num": 58, + "addr": "3f" + }, +} + +PSU_CPLD_I2C_MAPPING = { + 0: { + "num": 57, + "addr": "38" + }, + 1: { + "num": 58, + "addr": "3b" + }, +} + +class Psu(PsuBase): + """Platform-specific Psu class""" + + def __init__(self, psu_index=0): + PsuBase.__init__(self) + self.index = psu_index + self._api_helper = APIHelper() + + self.i2c_num = PSU_HWMON_I2C_MAPPING[self.index]["num"] + self.i2c_addr = PSU_HWMON_I2C_MAPPING[self.index]["addr"] + self.hwmon_path = I2C_PATH.format(self.i2c_num, self.i2c_addr) + + self.i2c_num = PSU_CPLD_I2C_MAPPING[self.index]["num"] + self.i2c_addr = PSU_CPLD_I2C_MAPPING[self.index]["addr"] + self.cpld_path = I2C_PATH.format(self.i2c_num, self.i2c_addr) + self.__initialize_fan() + + def __initialize_fan(self): + from sonic_platform.fan import Fan + for fan_index in range(0, PSU_NUM_FAN[self.index]): + fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index) + self._fan_list.append(fan) + + self._thermal_list.append(Thermal(is_psu=True, psu_index=self.index)) + + def get_voltage(self): + """ + Retrieves current PSU voltage output + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + vout_path = "{}{}".format(self.hwmon_path, 'psu_v_out') + vout_val=self._api_helper.read_txt_file(vout_path) + if vout_val is not None: + return float(vout_val)/ 1000 + else: + return 0 + + def get_current(self): + """ + Retrieves present electric current supplied by PSU + Returns: + A float number, the electric current in amperes, e.g 15.4 + """ + iout_path = "{}{}".format(self.hwmon_path, 'psu_i_out') + val=self._api_helper.read_txt_file(iout_path) + if val is not None: + return float(val)/1000 + else: + return 0 + + def get_power(self): + """ + Retrieves current energy supplied by PSU + Returns: + A float number, the power in watts, e.g. 302.6 + """ + pout_path = "{}{}".format(self.hwmon_path, 'psu_p_out') + val=self._api_helper.read_txt_file(pout_path) + if val is not None: + return float(val)/1000 + else: + return 0 + + 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): + """ + Sets the state of the PSU status LED + Args: + color: A string representing the color with which to set the PSU status LED + Note: Only support green and off + Returns: + bool: True if status LED state is set successfully, False if not + """ + + return False #Controlled by HW + + def get_status_led(self): + """ + Gets the state of the PSU status LED + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + status=self.get_status() + if status is None: + return self.STATUS_LED_COLOR_OFF + + return { + 1: self.STATUS_LED_COLOR_GREEN, + 0: self.STATUS_LED_COLOR_RED + }.get(status, self.STATUS_LED_COLOR_OFF) + + def get_temperature(self): + """ + Retrieves current temperature reading from PSU + Returns: + A float number of current temperature in Celsius up to nearest thousandth + of one degree Celsius, e.g. 30.125 + """ + temp_path = "{}{}".format(self.hwmon_path, 'psu_temp1_input') + val=self._api_helper.read_txt_file(temp_path) + if val is not None: + return float(val)/1000 + else: + return 0 + + def get_temperature_high_threshold(self): + """ + Retrieves the high threshold temperature of PSU + Returns: + A float number, the high threshold temperature of PSU in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + return False #Not supported + + def get_voltage_high_threshold(self): + """ + Retrieves the high threshold PSU voltage output + Returns: + A float number, the high threshold output voltage in volts, + e.g. 12.1 + """ + return 14.72 + + def get_voltage_low_threshold(self): + """ + Retrieves the low threshold PSU voltage output + Returns: + A float number, the low threshold output voltage in volts, + e.g. 12.1 + """ + return 7.68 + + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return PSU_NAME_LIST[self.index] + + def get_presence(self): + """ + Retrieves the presence of the PSU + Returns: + bool: True if PSU is present, False if not + """ + presence_path="{}{}".format(self.cpld_path, 'psu_present') + val=self._api_helper.read_txt_file(presence_path) + if val is not None: + return int(val, 10) == 1 + else: + return 0 + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + power_path="{}{}".format(self.cpld_path, 'psu_power_good') + val=self._api_helper.read_txt_file(power_path) + if val is not None: + return int(val, 10) == 1 + else: + return 0 + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + model_path="{}{}".format(self.cpld_path, 'psu_model_name') + model=self._api_helper.read_txt_file(model_path) + + if model is None: + return "N/A" + return model + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + serial_path="{}{}".format(self.cpld_path, 'psu_serial_number') + serial=self._api_helper.read_txt_file(serial_path) + + if serial is None: + return "N/A" + return serial + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device or -1 if cannot determine the position + """ + return self.index+1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True diff --git a/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/sfp.py b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/sfp.py new file mode 100644 index 00000000000..eb13f871c66 --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/sfp.py @@ -0,0 +1,2327 @@ +############################################################################# +# Edgecore +# +# Sfp contains an implementation of SONiC Platform Base API and +# provides the sfp device status which are available in the platform +# +############################################################################# + +import os +import sys +import time +import struct + +from ctypes import create_string_buffer + +try: + from sonic_platform_base.sfp_base import SfpBase + from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId + from sonic_platform_base.sonic_sfp.sff8472 import sff8472Dom + from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId + from sonic_platform_base.sonic_sfp.sff8436 import sff8436Dom + from sonic_platform_base.sonic_sfp.inf8628 import inf8628InterfaceId + from sonic_platform_base.sonic_sfp.qsfp_dd import qsfp_dd_InterfaceId + from sonic_platform_base.sonic_sfp.qsfp_dd import qsfp_dd_Dom + from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +#Edge-core definitions +CPLD_ADDR_MAPPING = { + 0: { + "bus": 0, + "addr": "61" + }, # port 1-24 + 1: { + "bus": 0, + "addr": "62" + }, # port 25-54 +} +CPLD_I2C_PATH = "/sys/bus/i2c/devices/{}-00{}/" + +# 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_CC_BASE_OFFSET= 63 +XCVR_EXT_SPECIFICATION_COMPLIANCE_OFFSET = 64 +XCVR_EXT_SPECIFICATION_COMPLIANCE_WIDTH = 1 +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 = 2 + +XCVR_INTERFACE_DATA_START = 0 +XCVR_INTERFACE_DATA_SIZE = 92 + +QSFP_DOM_BULK_DATA_START = 22 +QSFP_DOM_BULK_DATA_SIZE = 36 +SFP_DOM_BULK_DATA_START = 96 +SFP_DOM_BULK_DATA_SIZE = 10 +QSFP_DD_DOM_BULK_DATA_START = 14 +QSFP_DD_DOM_BULK_DATA_SIZE = 4 + +# 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 for values in QSFP_DD info eeprom +QSFP_DD_TYPE_OFFSET = 0 +QSFP_DD_VENDOR_NAME_OFFSET = 1 +QSFP_DD_VENDOR_PN_OFFSET = 20 +QSFP_DD_VENDOR_SN_OFFSET = 38 +QSFP_DD_VENDOR_OUI_OFFSET = 17 + +# definitions of the offset and width for values in XCVR_QSFP_DD info eeprom +XCVR_EXT_TYPE_OFFSET_QSFP_DD = 72 +XCVR_EXT_TYPE_WIDTH_QSFP_DD = 2 +XCVR_CONNECTOR_OFFSET_QSFP_DD = 75 +XCVR_CONNECTOR_WIDTH_QSFP_DD = 1 +XCVR_CABLE_LENGTH_OFFSET_QSFP_DD = 74 +XCVR_CABLE_LENGTH_WIDTH_QSFP_DD = 1 +XCVR_HW_REV_OFFSET_QSFP_DD = 36 +XCVR_HW_REV_WIDTH_QSFP_DD = 2 +XCVR_VENDOR_DATE_OFFSET_QSFP_DD = 54 +XCVR_VENDOR_DATE_WIDTH_QSFP_DD = 8 +XCVR_DOM_CAPABILITY_OFFSET_QSFP_DD = 2 +XCVR_DOM_CAPABILITY_WIDTH_QSFP_DD = 1 +XCVR_MEDIA_TYPE_OFFSET_QSFP_DD = 85 +XCVR_MEDIA_TYPE_WIDTH_QSFP_DD = 1 +XCVR_FIRST_APPLICATION_LIST_OFFSET_QSFP_DD = 86 +XCVR_FIRST_APPLICATION_LIST_WIDTH_QSFP_DD = 32 +XCVR_SECOND_APPLICATION_LIST_OFFSET_QSFP_DD = 351 +XCVR_SECOND_APPLICATION_LIST_WIDTH_QSFP_DD = 28 + +# Offset for values in QSFP 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_VERSION_COMPLIANCE_OFFSET = 1 +QSFP_VERSION_COMPLIANCE_WIDTH = 2 +QSFP_CHANNL_MON_OFFSET = 34 +QSFP_CHANNL_MON_WIDTH = 16 +QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH = 24 +QSFP_CHANNL_DISABLE_STATUS_OFFSET = 86 +QSFP_CHANNL_DISABLE_STATUS_WIDTH = 1 +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_CONTROL_OFFSET = 86 +QSFP_CONTROL_WIDTH = 8 +QSFP_MODULE_MONITOR_OFFSET = 0 +QSFP_MODULE_MONITOR_WIDTH = 9 +QSFP_POWEROVERRIDE_OFFSET = 93 +QSFP_POWEROVERRIDE_WIDTH = 1 +QSFP_POWEROVERRIDE_BIT = 0 +QSFP_POWERSET_BIT = 1 +QSFP_OPTION_VALUE_OFFSET = 192 +QSFP_OPTION_VALUE_WIDTH = 4 +QSFP_MODULE_UPPER_PAGE3_START = 384 +QSFP_MODULE_THRESHOLD_OFFSET = 128 +QSFP_MODULE_THRESHOLD_WIDTH = 24 +QSFP_CHANNL_THRESHOLD_OFFSET = 176 +QSFP_CHANNL_THRESHOLD_WIDTH = 24 + +SFP_MODULE_ADDRA2_OFFSET = 256 +SFP_MODULE_THRESHOLD_OFFSET = 0 +SFP_MODULE_THRESHOLD_WIDTH = 56 +SFP_CHANNL_THRESHOLD_OFFSET = 112 +SFP_CHANNL_THRESHOLD_WIDTH = 2 + +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_CHANNL_STATUS_OFFSET = 110 +SFP_CHANNL_STATUS_WIDTH = 1 + +QSFP_DD_TEMPE_OFFSET = 14 +QSFP_DD_TEMPE_WIDTH = 2 +QSFP_DD_VOLT_OFFSET = 16 +QSFP_DD_VOLT_WIDTH = 2 +QSFP_DD_TX_BIAS_OFFSET = 42 +QSFP_DD_TX_BIAS_WIDTH = 16 +QSFP_DD_RX_POWER_OFFSET = 58 +QSFP_DD_RX_POWER_WIDTH = 16 +QSFP_DD_TX_POWER_OFFSET = 26 +QSFP_DD_TX_POWER_WIDTH = 16 +QSFP_DD_CHANNL_MON_OFFSET = 154 +QSFP_DD_CHANNL_MON_WIDTH = 48 +QSFP_DD_CHANNL_DISABLE_STATUS_OFFSET = 86 +QSFP_DD_CHANNL_DISABLE_STATUS_WIDTH = 1 +QSFP_DD_CHANNL_RX_LOS_STATUS_OFFSET = 19 +QSFP_DD_CHANNL_RX_LOS_STATUS_WIDTH = 1 +QSFP_DD_CHANNL_TX_FAULT_STATUS_OFFSET = 7 +QSFP_DD_CHANNL_TX_FAULT_STATUS_WIDTH = 1 +QSFP_DD_MODULE_THRESHOLD_OFFSET = 0 +QSFP_DD_MODULE_THRESHOLD_WIDTH = 72 +QSFP_DD_CHANNL_STATUS_OFFSET = 26 +QSFP_DD_CHANNL_STATUS_WIDTH = 1 + + +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' +) + +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', 'type_abbrv_name' +] + +qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)', + 'Length OM2(m)', 'Length OM1(m)', + 'Length Cable Assembly(m)') + +dom_info_dict_keys = [ + 'rx_los', 'tx_fault', 'reset_status', 'lp_mode', + 'tx_disable', 'tx_disable_channel', 'temperature', 'voltage', + 'rx1power', 'rx2power', 'rx3power', 'rx4power', + 'rx5power', 'rx6power', 'rx7power', 'rx8power', + 'tx1bias', 'tx2bias', 'tx3bias', 'tx4bias', + 'tx5bias', 'tx6bias', 'tx7bias', 'tx8bias', + 'tx1power', 'tx2power', 'tx3power', 'tx4power', + 'tx5power', 'tx6power', 'tx7power', 'tx8power'] + +threshold_dict_keys = [ + 'temphighalarm', 'temphighwarning', + 'templowalarm', 'templowwarning', + 'vcchighalarm', 'vcchighwarning', + 'vcclowalarm', 'vcclowwarning', + 'rxpowerhighalarm', 'rxpowerhighwarning', + 'rxpowerlowalarm', 'rxpowerlowwarning', + 'txpowerhighalarm', 'txpowerhighwarning', + 'txpowerlowalarm', 'txpowerlowwarning', + 'txbiashighalarm', 'txbiashighwarning', + 'txbiaslowalarm', 'txbiaslowwarning'] + +SFP_TYPE_CODE_LIST = [ + '03' # SFP/SFP+/SFP28 +] +QSFP_TYPE_CODE_LIST = [ + '0d', # QSFP+ or later + '11' # QSFP28 or later +] +QSFP_DD_TYPE_CODE_LIST = [ + '18' # QSFP-DD Double Density 8X Pluggable Transceiver +] + +SFP_TYPE = "SFP" +QSFP_TYPE = "QSFP" +OSFP_TYPE = "OSFP" +QSFP_DD_TYPE = "QSFP_DD" + +NULL_VAL = 'N/A' + +I2C_EEPROM_PATH = '/sys/bus/i2c/devices/{0}-0050/eeprom' + + +class Sfp(SfpBase): + """Platform-specific Sfp class""" + # Path to sysfs + PLATFORM_ROOT_PATH = "/usr/share/sonic/device" + PMON_HWSKU_PATH = "/usr/share/sonic/hwsku" + HOST_CHK_CMD = "which systemctl > /dev/null 2>&1" + PLATFORM = "x86_64-accton_as5812_54x-r0" + HWSKU = "Accton-AS5812-54X" + + _port_to_i2c_mapping = { + 1: 2, + 2: 3, + 3: 4, + 4: 5, + 5: 6, + 6: 7, + 7: 8, + 8: 9, + 9: 10, + 10:11 , + 11:12, + 12:13, + 13:14, + 14:15, + 15:16, + 16:17, + 17:18, + 18:19, + 19:20, + 20:21, + 21:22, + 22:23, + 23:24, + 24:25, + 25:26, + 26:27, + 27:28, + 28:29, + 29:30, + 30:31, + 31:32, + 32:33, + 33:34, + 34:35, + 35:36, + 36:37, + 37:38, + 38:39, + 39:40, + 40:41, + 41:42, + 42:43, + 43:44, + 44:45, + 45:46, + 46:47, + 47:48, + 48:49, + 49:50, + 50:52, + 51:54, + 52:51, + 53:53, + 54:55, + + } + + def __init__(self, sfp_index=0, sfp_name=None): + self._api_helper=APIHelper() + self._index = sfp_index + self.port_num = self._index + 1 + self._name = sfp_name + self._eeprom_path = self._get_eeprom_path() + + cpld_idx = 1 if self.port_num > 24 else 0 + + self.bus = CPLD_ADDR_MAPPING[cpld_idx]["bus"] + self.addr = CPLD_ADDR_MAPPING[cpld_idx]["addr"] + self.i2c_cpld_path = CPLD_I2C_PATH.format(self.bus,self.addr) + + self._dom_capability_detect() + + SfpBase.__init__(self) + + def __is_host(self): + return os.system(self.HOST_CHK_CMD) == 0 + + def __get_path_to_port_config_file(self): + platform_path = "/".join([self.PLATFORM_ROOT_PATH, self.PLATFORM]) + hwsku_path = "/".join([platform_path, self.HWSKU] + ) if self.__is_host() else self.PMON_HWSKU_PATH + return "/".join([hwsku_path, "port_config.ini"]) + + def _convert_string_to_num(self, value_str): + if "-inf" in value_str: + return 'N/A' + elif "Unknown" in value_str: + return 'N/A' + elif 'dBm' in value_str: + t_str = value_str.rstrip('dBm') + return float(t_str) + elif 'mA' in value_str: + t_str = value_str.rstrip('mA') + return float(t_str) + elif 'C' in value_str: + t_str = value_str.rstrip('C') + return float(t_str) + elif 'Volts' in value_str: + t_str = value_str.rstrip('Volts') + return float(t_str) + else: + return 'N/A' + + def _read_eeprom_specific_bytes(self, offset, num_bytes): + sysfs_sfp_i2c_client_eeprom_path = self._get_eeprom_path() + eeprom_raw = [] + try: + eeprom = open( + sysfs_sfp_i2c_client_eeprom_path, + mode="rb", buffering=0) + except IOError: + return None + + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + + try: + eeprom.seek(offset) + raw = eeprom.read(num_bytes) + except IOError: + eeprom.close() + return None + + try: + if isinstance(raw, str): + for n in range(0, num_bytes): + eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) + else: + for n in range(0, num_bytes): + eeprom_raw[n] = hex(raw[n])[2:].zfill(2) + + except BaseException: + eeprom.close() + return None + + eeprom.close() + return eeprom_raw + + def _detect_sfp_type(self): + sfp_type = QSFP_TYPE + eeprom_raw = [] + eeprom_raw = self._read_eeprom_specific_bytes( + XCVR_TYPE_OFFSET, XCVR_TYPE_WIDTH) + if eeprom_raw: + if eeprom_raw[0] in SFP_TYPE_CODE_LIST: + self.sfp_type = SFP_TYPE + elif eeprom_raw[0] in QSFP_TYPE_CODE_LIST: + self.sfp_type = QSFP_TYPE + elif eeprom_raw[0] in QSFP_DD_TYPE_CODE_LIST: + self.sfp_type = QSFP_DD_TYPE + else: + self.sfp_type = sfp_type + else: + self.sfp_type = sfp_type + + def _get_eeprom_path(self): + port_eeprom_path = I2C_EEPROM_PATH.format(self._port_to_i2c_mapping[self.port_num]) + return port_eeprom_path + + def _dom_capability_detect(self): + self._detect_sfp_type() + + if not self.get_presence(): + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + return + + if self.sfp_type == QSFP_TYPE: + self.calibration = 1 + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + self.dom_supported = False + offset = 128 + + # QSFP capability byte parse, + # through this byte can know whether it support tx_power or not. + # TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436, + # need to add more code for determining the capability and version compliance + # in SFF-8636 dom capability definitions evolving with the versions. + + qsfp_dom_capability_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_DOM_CAPABILITY_OFFSET), + XCVR_DOM_CAPABILITY_WIDTH) + if qsfp_dom_capability_raw is not None: + qsfp_version_compliance_raw = self._read_eeprom_specific_bytes( + QSFP_VERSION_COMPLIANCE_OFFSET, + QSFP_VERSION_COMPLIANCE_WIDTH) + qsfp_version_compliance = int( + qsfp_version_compliance_raw[0], 16) + dom_capability = sfpi_obj.parse_dom_capability( + qsfp_dom_capability_raw, 0) + if qsfp_version_compliance >= 0x08: + self.dom_temp_supported = dom_capability['data']['Temp_support']['value'] == 'On' + self.dom_volt_supported = dom_capability['data']['Voltage_support']['value'] == 'On' + self.dom_rx_power_supported = dom_capability['data']['Rx_power_support']['value'] == 'On' + self.dom_tx_power_supported = dom_capability['data']['Tx_power_support']['value'] == 'On' + else: + self.dom_temp_supported = True + self.dom_volt_supported = True + self.dom_rx_power_supported = dom_capability['data']['Rx_power_support']['value'] == 'On' + self.dom_tx_power_supported = True + + self.dom_supported = True + self.calibration = 1 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + qsfp_option_value_raw = self._read_eeprom_specific_bytes( + QSFP_OPTION_VALUE_OFFSET, QSFP_OPTION_VALUE_WIDTH) + if qsfp_option_value_raw is not None: + optional_capability = sfpd_obj.parse_option_params( + qsfp_option_value_raw, 0) + self.dom_tx_disable_supported = optional_capability[ + 'data']['TxDisable']['value'] == 'On' + dom_status_indicator = sfpd_obj.parse_dom_status_indicator( + qsfp_version_compliance_raw, 1) + self.qsfp_page3_available = dom_status_indicator['data']['FlatMem']['value'] == 'Off' + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + self.qsfp_page3_available = False + + elif self.sfp_type == QSFP_DD_TYPE: + sfpi_obj = qsfp_dd_InterfaceId() + if sfpi_obj is None: + self.dom_supported = False + + offset = 0 + # two types of QSFP-DD cable types supported: Copper and Optical. + qsfp_dom_capability_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_DOM_CAPABILITY_OFFSET_QSFP_DD), XCVR_DOM_CAPABILITY_WIDTH_QSFP_DD) + if qsfp_dom_capability_raw is not None: + self.dom_temp_supported = True + self.dom_volt_supported = True + dom_capability = sfpi_obj.parse_dom_capability( + qsfp_dom_capability_raw, 0) + if dom_capability['data']['Flat_MEM']['value'] == 'Off': + self.dom_supported = True + self.second_application_list = True + self.dom_rx_power_supported = True + self.dom_tx_power_supported = True + self.dom_tx_bias_power_supported = True + self.dom_thresholds_supported = True + # currently set to False becasue Page 11h is not supported by FW + self.dom_rx_tx_power_bias_supported = False + else: + self.dom_supported = False + self.second_application_list = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.dom_tx_bias_power_supported = False + self.dom_thresholds_supported = False + self.dom_rx_tx_power_bias_supported = False + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.dom_tx_bias_power_supported = False + self.dom_thresholds_supported = False + self.dom_rx_tx_power_bias_supported = False + + elif self.sfp_type == SFP_TYPE: + sfpi_obj = sff8472InterfaceId() + if sfpi_obj is None: + return None + sfp_dom_capability_raw = self._read_eeprom_specific_bytes( + XCVR_DOM_CAPABILITY_OFFSET, XCVR_DOM_CAPABILITY_WIDTH) + if sfp_dom_capability_raw is not None: + sfp_dom_capability = int(sfp_dom_capability_raw[0], 16) + self.dom_supported = (sfp_dom_capability & 0x40 != 0) + if self.dom_supported: + self.dom_temp_supported = True + self.dom_volt_supported = True + self.dom_rx_power_supported = True + self.dom_tx_power_supported = True + if sfp_dom_capability & 0x20 != 0: + self.calibration = 1 + elif sfp_dom_capability & 0x10 != 0: + self.calibration = 2 + else: + self.calibration = 0 + else: + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + self.dom_tx_disable_supported = ( + int(sfp_dom_capability_raw[1], 16) & 0x40 != 0) + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + + 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 + ================================================================================ + """ + + transceiver_info_dict = {} + compliance_code_dict = {} + transceiver_info_dict = dict.fromkeys( + info_dict_keys, NULL_VAL) + transceiver_info_dict["specification_compliance"] = '{}' + + # ToDo: OSFP tranceiver info parsing not fully supported. + # in inf8628.py lack of some memory map definition + # will be implemented when the inf8628 memory map ready + if self.sfp_type == OSFP_TYPE: + offset = 0 + vendor_rev_width = XCVR_HW_REV_WIDTH_OSFP + + sfpi_obj = inf8628InterfaceId() + if sfpi_obj is None: + return transceiver_info_dict + + sfp_type_raw = self._read_eeprom_specific_bytes( + (offset + OSFP_TYPE_OFFSET), XCVR_TYPE_WIDTH) + if sfp_type_raw is not None: + sfp_type_data = sfpi_obj.parse_sfp_type(sfp_type_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_name_raw = self._read_eeprom_specific_bytes( + (offset + OSFP_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH) + if sfp_vendor_name_raw is not None: + sfp_vendor_name_data = sfpi_obj.parse_vendor_name( + sfp_vendor_name_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_pn_raw = self._read_eeprom_specific_bytes( + (offset + OSFP_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH) + if sfp_vendor_pn_raw is not None: + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn( + sfp_vendor_pn_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_rev_raw = self._read_eeprom_specific_bytes( + (offset + OSFP_HW_REV_OFFSET), vendor_rev_width) + if sfp_vendor_rev_raw is not None: + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev( + sfp_vendor_rev_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_sn_raw = self._read_eeprom_specific_bytes( + (offset + OSFP_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH) + if sfp_vendor_sn_raw is not None: + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn( + sfp_vendor_sn_raw, 0) + else: + return transceiver_info_dict + + transceiver_info_dict['type'] = sfp_type_data['data']['type']['value'] + transceiver_info_dict['manufacturer'] = sfp_vendor_name_data['data']['Vendor Name']['value'] + transceiver_info_dict['model'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] + transceiver_info_dict['hardware_rev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] + transceiver_info_dict['serial'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] + + elif self.sfp_type == QSFP_TYPE: + offset = 128 + vendor_rev_width = XCVR_HW_REV_WIDTH_QSFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_QSFP + + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + + elif self.sfp_type == QSFP_DD_TYPE: + offset = 128 + + sfpi_obj = qsfp_dd_InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + + sfp_type_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_TYPE_OFFSET), XCVR_TYPE_WIDTH) + if sfp_type_raw is not None: + sfp_type_data = sfpi_obj.parse_sfp_type(sfp_type_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_name_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH) + if sfp_vendor_name_raw is not None: + sfp_vendor_name_data = sfpi_obj.parse_vendor_name( + sfp_vendor_name_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_pn_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH) + if sfp_vendor_pn_raw is not None: + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn( + sfp_vendor_pn_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_rev_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_HW_REV_OFFSET_QSFP_DD), XCVR_HW_REV_WIDTH_QSFP_DD) + if sfp_vendor_rev_raw is not None: + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev( + sfp_vendor_rev_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_sn_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH) + if sfp_vendor_sn_raw is not None: + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn( + sfp_vendor_sn_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_oui_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_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) + else: + return transceiver_info_dict + + sfp_vendor_date_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_VENDOR_DATE_OFFSET_QSFP_DD), XCVR_VENDOR_DATE_WIDTH_QSFP_DD) + if sfp_vendor_date_raw is not None: + sfp_vendor_date_data = sfpi_obj.parse_vendor_date( + sfp_vendor_date_raw, 0) + else: + return transceiver_info_dict + + sfp_connector_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_CONNECTOR_OFFSET_QSFP_DD), XCVR_CONNECTOR_WIDTH_QSFP_DD) + if sfp_connector_raw is not None: + sfp_connector_data = sfpi_obj.parse_connector( + sfp_connector_raw, 0) + else: + return transceiver_info_dict + + sfp_ext_identifier_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_EXT_TYPE_OFFSET_QSFP_DD), XCVR_EXT_TYPE_WIDTH_QSFP_DD) + if sfp_ext_identifier_raw is not None: + sfp_ext_identifier_data = sfpi_obj.parse_ext_iden( + sfp_ext_identifier_raw, 0) + else: + return transceiver_info_dict + + sfp_cable_len_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_CABLE_LENGTH_OFFSET_QSFP_DD), XCVR_CABLE_LENGTH_WIDTH_QSFP_DD) + if sfp_cable_len_raw is not None: + sfp_cable_len_data = sfpi_obj.parse_cable_len( + sfp_cable_len_raw, 0) + else: + return transceiver_info_dict + + sfp_media_type_raw = self._read_eeprom_specific_bytes( + XCVR_MEDIA_TYPE_OFFSET_QSFP_DD, XCVR_MEDIA_TYPE_WIDTH_QSFP_DD) + if sfp_media_type_raw is not None: + sfp_media_type_dict = sfpi_obj.parse_media_type( + sfp_media_type_raw, 0) + if sfp_media_type_dict is None: + return transceiver_info_dict + + host_media_list = "" + sfp_application_type_first_list = self._read_eeprom_specific_bytes( + (XCVR_FIRST_APPLICATION_LIST_OFFSET_QSFP_DD), XCVR_FIRST_APPLICATION_LIST_WIDTH_QSFP_DD) + if self.second_application_list: + possible_application_count = 15 + sfp_application_type_second_list = self._read_eeprom_specific_bytes( + (XCVR_SECOND_APPLICATION_LIST_OFFSET_QSFP_DD), XCVR_SECOND_APPLICATION_LIST_WIDTH_QSFP_DD) + if sfp_application_type_first_list is not None and sfp_application_type_second_list is not None: + sfp_application_type_list = sfp_application_type_first_list + \ + sfp_application_type_second_list + else: + return transceiver_info_dict + else: + possible_application_count = 8 + if sfp_application_type_first_list is not None: + sfp_application_type_list = sfp_application_type_first_list + else: + return transceiver_info_dict + + for i in range(0, possible_application_count): + if sfp_application_type_list[i * 4] == 'ff': + break + host_electrical, media_interface = sfpi_obj.parse_application( + sfp_media_type_dict, sfp_application_type_list[i * 4], sfp_application_type_list[i * 4 + 1]) + host_media_list = host_media_list + host_electrical + \ + ' - ' + media_interface + '\n\t\t\t\t ' + else: + return transceiver_info_dict + + transceiver_info_dict['type'] = str( + sfp_type_data['data']['type']['value']) + transceiver_info_dict['manufacturer'] = str( + sfp_vendor_name_data['data']['Vendor Name']['value']) + transceiver_info_dict['model'] = str( + sfp_vendor_pn_data['data']['Vendor PN']['value']) + transceiver_info_dict['hardware_rev'] = str( + sfp_vendor_rev_data['data']['Vendor Rev']['value']) + transceiver_info_dict['serial'] = str( + sfp_vendor_sn_data['data']['Vendor SN']['value']) + transceiver_info_dict['vendor_oui'] = str( + sfp_vendor_oui_data['data']['Vendor OUI']['value']) + transceiver_info_dict['vendor_date'] = str( + sfp_vendor_date_data['data']['VendorDataCode(YYYY-MM-DD Lot)']['value']) + transceiver_info_dict['connector'] = str( + sfp_connector_data['data']['Connector']['value']) + transceiver_info_dict['encoding'] = "Not supported for CMIS cables" + transceiver_info_dict['ext_identifier'] = str( + sfp_ext_identifier_data['data']['Extended Identifier']['value']) + transceiver_info_dict['ext_rateselect_compliance'] = "Not supported for CMIS cables" + transceiver_info_dict['specification_compliance'] = "Not supported for CMIS cables" + transceiver_info_dict['cable_type'] = "Length Cable Assembly(m)" + transceiver_info_dict['cable_length'] = str( + sfp_cable_len_data['data']['Length Cable Assembly(m)']['value']) + transceiver_info_dict['nominal_bit_rate'] = "Not supported for CMIS cables" + transceiver_info_dict['application_advertisement'] = host_media_list + + else: + offset = 0 + vendor_rev_width = XCVR_HW_REV_WIDTH_SFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_SFP + + sfpi_obj = sff8472InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + + if self.sfp_type != QSFP_DD_TYPE: + sfp_interface_bulk_raw = self._read_eeprom_specific_bytes( + offset + XCVR_INTERFACE_DATA_START, XCVR_INTERFACE_DATA_SIZE) + if sfp_interface_bulk_raw is None: + return transceiver_info_dict + + start = XCVR_INTFACE_BULK_OFFSET - XCVR_INTERFACE_DATA_START + end = start + interface_info_bulk_width + sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk( + sfp_interface_bulk_raw[start: end], 0) + + start = XCVR_VENDOR_NAME_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_NAME_WIDTH + sfp_vendor_name_data = sfpi_obj.parse_vendor_name( + sfp_interface_bulk_raw[start: end], 0) + + start = XCVR_VENDOR_PN_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_PN_WIDTH + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn( + sfp_interface_bulk_raw[start: end], 0) + + start = XCVR_HW_REV_OFFSET - XCVR_INTERFACE_DATA_START + end = start + vendor_rev_width + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev( + sfp_interface_bulk_raw[start: end], 0) + + start = XCVR_VENDOR_SN_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_SN_WIDTH + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn( + sfp_interface_bulk_raw[start: end], 0) + + start = XCVR_VENDOR_OUI_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_OUI_WIDTH + sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui( + sfp_interface_bulk_raw[start: end], 0) + + start = XCVR_VENDOR_DATE_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_DATE_WIDTH + sfp_vendor_date_data = sfpi_obj.parse_vendor_date( + sfp_interface_bulk_raw[start: end], 0) + + transceiver_info_dict['type'] = sfp_interface_bulk_data['data']['type']['value'] + transceiver_info_dict['manufacturer'] = sfp_vendor_name_data['data']['Vendor Name']['value'] + transceiver_info_dict['model'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] + transceiver_info_dict['hardware_rev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] + transceiver_info_dict['serial'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] + transceiver_info_dict['vendor_oui'] = sfp_vendor_oui_data['data']['Vendor OUI']['value'] + transceiver_info_dict['vendor_date'] = sfp_vendor_date_data[ + 'data']['VendorDataCode(YYYY-MM-DD Lot)']['value'] + transceiver_info_dict['connector'] = sfp_interface_bulk_data['data']['Connector']['value'] + transceiver_info_dict['encoding'] = sfp_interface_bulk_data['data']['EncodingCodes']['value'] + transceiver_info_dict['ext_identifier'] = sfp_interface_bulk_data['data']['Extended Identifier']['value'] + transceiver_info_dict['ext_rateselect_compliance'] = sfp_interface_bulk_data['data']['RateIdentifier']['value'] + transceiver_info_dict['type_abbrv_name'] = sfp_interface_bulk_data['data']['type_abbrv_name']['value'] + + if self.sfp_type == QSFP_TYPE: + for key in qsfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_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'] + sfp_ext_specification_compliance_raw = self._read_eeprom_specific_bytes( + offset + XCVR_EXT_SPECIFICATION_COMPLIANCE_OFFSET, XCVR_EXT_SPECIFICATION_COMPLIANCE_WIDTH) + if sfp_ext_specification_compliance_raw is not None: + sfp_ext_specification_compliance_data = sfpi_obj.parse_ext_specification_compliance( + sfp_ext_specification_compliance_raw[0: 1], 0) + if sfp_ext_specification_compliance_data['data']['Extended Specification compliance']['value'] != "Unspecified": + compliance_code_dict['Extended Specification compliance'] = sfp_ext_specification_compliance_data[ + 'data']['Extended Specification compliance']['value'] + transceiver_info_dict['specification_compliance'] = str( + compliance_code_dict) + transceiver_info_dict['nominal_bit_rate'] = str( + sfp_interface_bulk_data['data']['Nominal Bit Rate(100Mbs)']['value']) + else: + for key in sfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_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'] + transceiver_info_dict['specification_compliance'] = str( + compliance_code_dict) + + transceiver_info_dict['nominal_bit_rate'] = str( + sfp_interface_bulk_data['data']['NominalSignallingRate(UnitsOf100Mbd)']['value']) + + return transceiver_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. + ======================================================================== + """ + transceiver_dom_info_dict = dict.fromkeys( + dom_info_dict_keys, NULL_VAL) + + if self.sfp_type == OSFP_TYPE: + pass + + elif self.sfp_type == QSFP_TYPE: + if not self.dom_supported: + return transceiver_dom_info_dict + + offset = 0 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return transceiver_dom_info_dict + + dom_data_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DOM_BULK_DATA_START), QSFP_DOM_BULK_DATA_SIZE) + if dom_data_raw is None: + return transceiver_dom_info_dict + + if self.dom_temp_supported: + start = QSFP_TEMPE_OFFSET - QSFP_DOM_BULK_DATA_START + end = start + QSFP_TEMPE_WIDTH + dom_temperature_data = sfpd_obj.parse_temperature( + dom_data_raw[start: end], 0) + temp = dom_temperature_data['data']['Temperature']['value'] + if temp is not None: + transceiver_dom_info_dict['temperature'] = temp + + if self.dom_volt_supported: + start = QSFP_VOLT_OFFSET - QSFP_DOM_BULK_DATA_START + end = start + QSFP_VOLT_WIDTH + dom_voltage_data = sfpd_obj.parse_voltage( + dom_data_raw[start: end], 0) + volt = dom_voltage_data['data']['Vcc']['value'] + if volt is not None: + transceiver_dom_info_dict['voltage'] = volt + + start = QSFP_CHANNL_MON_OFFSET - QSFP_DOM_BULK_DATA_START + end = start + QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power( + dom_data_raw[start: end], 0) + + if self.dom_tx_power_supported: + transceiver_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TX1Power']['value'] + transceiver_dom_info_dict['tx2power'] = dom_channel_monitor_data['data']['TX2Power']['value'] + transceiver_dom_info_dict['tx3power'] = dom_channel_monitor_data['data']['TX3Power']['value'] + transceiver_dom_info_dict['tx4power'] = dom_channel_monitor_data['data']['TX4Power']['value'] + + if self.dom_rx_power_supported: + transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RX1Power']['value'] + transceiver_dom_info_dict['rx2power'] = dom_channel_monitor_data['data']['RX2Power']['value'] + transceiver_dom_info_dict['rx3power'] = dom_channel_monitor_data['data']['RX3Power']['value'] + transceiver_dom_info_dict['rx4power'] = dom_channel_monitor_data['data']['RX4Power']['value'] + + transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TX1Bias']['value'] + transceiver_dom_info_dict['tx2bias'] = dom_channel_monitor_data['data']['TX2Bias']['value'] + transceiver_dom_info_dict['tx3bias'] = dom_channel_monitor_data['data']['TX3Bias']['value'] + transceiver_dom_info_dict['tx4bias'] = dom_channel_monitor_data['data']['TX4Bias']['value'] + + elif self.sfp_type == QSFP_DD_TYPE: + + offset = 0 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return transceiver_dom_info_dict + + dom_data_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_DOM_BULK_DATA_START), QSFP_DD_DOM_BULK_DATA_SIZE) + if dom_data_raw is None: + return transceiver_dom_info_dict + + if self.dom_temp_supported: + start = QSFP_DD_TEMPE_OFFSET - QSFP_DD_DOM_BULK_DATA_START + end = start + QSFP_DD_TEMPE_WIDTH + dom_temperature_data = sfpd_obj.parse_temperature( + dom_data_raw[start: end], 0) + temp = dom_temperature_data['data']['Temperature']['value'] + if temp is not None: + transceiver_dom_info_dict['temperature'] = temp + + if self.dom_volt_supported: + start = QSFP_DD_VOLT_OFFSET - QSFP_DD_DOM_BULK_DATA_START + end = start + QSFP_DD_VOLT_WIDTH + dom_voltage_data = sfpd_obj.parse_voltage( + dom_data_raw[start: end], 0) + volt = dom_voltage_data['data']['Vcc']['value'] + if volt is not None: + transceiver_dom_info_dict['voltage'] = volt + + if self.dom_rx_tx_power_bias_supported: + # page 11h + dom_data_raw = self._read_eeprom_specific_bytes( + (QSFP_DD_CHANNL_MON_OFFSET), QSFP_DD_CHANNL_MON_WIDTH) + if dom_data_raw is None: + return transceiver_dom_info_dict + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( + dom_data_raw, 0) + + if self.dom_tx_power_supported: + transceiver_dom_info_dict['tx1power'] = str( + dom_channel_monitor_data['data']['TX1Power']['value']) + transceiver_dom_info_dict['tx2power'] = str( + dom_channel_monitor_data['data']['TX2Power']['value']) + transceiver_dom_info_dict['tx3power'] = str( + dom_channel_monitor_data['data']['TX3Power']['value']) + transceiver_dom_info_dict['tx4power'] = str( + dom_channel_monitor_data['data']['TX4Power']['value']) + transceiver_dom_info_dict['tx5power'] = str( + dom_channel_monitor_data['data']['TX5Power']['value']) + transceiver_dom_info_dict['tx6power'] = str( + dom_channel_monitor_data['data']['TX6Power']['value']) + transceiver_dom_info_dict['tx7power'] = str( + dom_channel_monitor_data['data']['TX7Power']['value']) + transceiver_dom_info_dict['tx8power'] = str( + dom_channel_monitor_data['data']['TX8Power']['value']) + + if self.dom_rx_power_supported: + transceiver_dom_info_dict['rx1power'] = str( + dom_channel_monitor_data['data']['RX1Power']['value']) + transceiver_dom_info_dict['rx2power'] = str( + dom_channel_monitor_data['data']['RX2Power']['value']) + transceiver_dom_info_dict['rx3power'] = str( + dom_channel_monitor_data['data']['RX3Power']['value']) + transceiver_dom_info_dict['rx4power'] = str( + dom_channel_monitor_data['data']['RX4Power']['value']) + transceiver_dom_info_dict['rx5power'] = str( + dom_channel_monitor_data['data']['RX5Power']['value']) + transceiver_dom_info_dict['rx6power'] = str( + dom_channel_monitor_data['data']['RX6Power']['value']) + transceiver_dom_info_dict['rx7power'] = str( + dom_channel_monitor_data['data']['RX7Power']['value']) + transceiver_dom_info_dict['rx8power'] = str( + dom_channel_monitor_data['data']['RX8Power']['value']) + + if self.dom_tx_bias_power_supported: + transceiver_dom_info_dict['tx1bias'] = str( + dom_channel_monitor_data['data']['TX1Bias']['value']) + transceiver_dom_info_dict['tx2bias'] = str( + dom_channel_monitor_data['data']['TX2Bias']['value']) + transceiver_dom_info_dict['tx3bias'] = str( + dom_channel_monitor_data['data']['TX3Bias']['value']) + transceiver_dom_info_dict['tx4bias'] = str( + dom_channel_monitor_data['data']['TX4Bias']['value']) + transceiver_dom_info_dict['tx5bias'] = str( + dom_channel_monitor_data['data']['TX5Bias']['value']) + transceiver_dom_info_dict['tx6bias'] = str( + dom_channel_monitor_data['data']['TX6Bias']['value']) + transceiver_dom_info_dict['tx7bias'] = str( + dom_channel_monitor_data['data']['TX7Bias']['value']) + transceiver_dom_info_dict['tx8bias'] = str( + dom_channel_monitor_data['data']['TX8Bias']['value']) + + return transceiver_dom_info_dict + + else: + if not self.dom_supported: + return transceiver_dom_info_dict + + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return transceiver_dom_info_dict + sfpd_obj._calibration_type = self.calibration + + dom_data_raw = self._read_eeprom_specific_bytes( + (offset + SFP_DOM_BULK_DATA_START), SFP_DOM_BULK_DATA_SIZE) + if dom_data_raw is None: + return transceiver_dom_info_dict + + start = SFP_TEMPE_OFFSET - SFP_DOM_BULK_DATA_START + end = start + SFP_TEMPE_WIDTH + dom_temperature_data = sfpd_obj.parse_temperature( + dom_data_raw[start: end], 0) + + start = SFP_VOLT_OFFSET - SFP_DOM_BULK_DATA_START + end = start + SFP_VOLT_WIDTH + dom_voltage_data = sfpd_obj.parse_voltage( + dom_data_raw[start: end], 0) + + start = SFP_CHANNL_MON_OFFSET - SFP_DOM_BULK_DATA_START + end = start + SFP_CHANNL_MON_WIDTH + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( + dom_data_raw[start: end], 0) + + transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RXPower']['value'] + transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TXBias']['value'] + transceiver_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TXPower']['value'] + + transceiver_dom_info_dict['lp_mode'] = self.get_lpmode() + transceiver_dom_info_dict['reset_status'] = self.get_reset_status() + transceiver_dom_info_dict['tx_disable'] = self.get_tx_disable() + transceiver_dom_info_dict['tx_disabled_channel'] = self.get_tx_disable_channel( + ) + + for key in transceiver_dom_info_dict: + val = transceiver_dom_info_dict[key] + transceiver_dom_info_dict[key] = self._convert_string_to_num( + val) if type(val) is str else val + + return transceiver_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. + ======================================================================== + """ + transceiver_dom_threshold_info_dict = dict.fromkeys( + threshold_dict_keys, NULL_VAL) + + if self.sfp_type == OSFP_TYPE: + pass + + elif self.sfp_type == QSFP_TYPE: + if not self.dom_supported or not self.qsfp_page3_available: + return transceiver_dom_threshold_info_dict + + # Dom Threshold data starts from offset 384 + # Revert offset back to 0 once data is retrieved + offset = QSFP_MODULE_UPPER_PAGE3_START + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return transceiver_dom_threshold_info_dict + + dom_module_threshold_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_MODULE_THRESHOLD_OFFSET), QSFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is None: + return transceiver_dom_threshold_info_dict + + dom_module_threshold_data = sfpd_obj.parse_module_threshold_values( + dom_module_threshold_raw, 0) + + dom_channel_threshold_raw = self._read_eeprom_specific_bytes((offset + QSFP_CHANNL_THRESHOLD_OFFSET), + QSFP_CHANNL_THRESHOLD_WIDTH) + if dom_channel_threshold_raw is None: + return transceiver_dom_threshold_info_dict + dom_channel_threshold_data = sfpd_obj.parse_channel_threshold_values( + dom_channel_threshold_raw, 0) + + # Threshold Data + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VccHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VccHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VccLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VccLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_channel_threshold_data['data']['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_channel_threshold_data['data']['RxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_channel_threshold_data['data']['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_channel_threshold_data['data']['RxPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_channel_threshold_data['data']['TxBiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_channel_threshold_data['data']['TxBiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_channel_threshold_data['data']['TxBiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_channel_threshold_data['data']['TxBiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_channel_threshold_data['data']['TxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_channel_threshold_data['data']['TxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_channel_threshold_data['data']['TxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_channel_threshold_data['data']['TxPowerLowWarning']['value'] + + elif self.sfp_type == QSFP_DD_TYPE: + if not self.dom_supported: + return transceiver_dom_threshold_info_dict + + if not self.dom_thresholds_supported: + return transceiver_dom_threshold_info_dict + + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return transceiver_dom_threshold_info_dict + + # page 02 + offset = 384 + dom_module_threshold_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_MODULE_THRESHOLD_OFFSET), QSFP_DD_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is None: + return transceiver_dom_threshold_info_dict + + dom_module_threshold_data = sfpd_obj.parse_module_threshold_values( + dom_module_threshold_raw, 0) + + # Threshold Data + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VccHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VccHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VccLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VccLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RxPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['TxBiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['TxBiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['TxBiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['TxBiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TxPowerLowWarning']['value'] + + else: + offset = SFP_MODULE_ADDRA2_OFFSET + + if not self.dom_supported: + return transceiver_dom_threshold_info_dict + + sfpd_obj = sff8472Dom(None, self.calibration) + if sfpd_obj is None: + return transceiver_dom_threshold_info_dict + + 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) + else: + return transceiver_dom_threshold_info_dict + + # Threshold Data + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VoltageHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VoltageLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data[ + 'data']['VoltageHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VoltageLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['BiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['BiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['BiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['BiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TXPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RXPowerLowWarning']['value'] + + for key in transceiver_dom_threshold_info_dict: + transceiver_dom_threshold_info_dict[key] = self._convert_string_to_num( + transceiver_dom_threshold_info_dict[key]) + + return transceiver_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 + """ + if not self.get_presence(): + return False + + if 49 <= self.port_num <= 54: + reset_path = "{}{}{}".format(self.i2c_cpld_path, '/module_reset_', self.port_num) + else: + return False + + val = self._api_helper.read_txt_file(reset_path) + if val is not None: + return int(val, 10)==1 + else: + return False + + 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_list = [] + + if self.sfp_type == OSFP_TYPE: + return None + elif self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_RX_LOS_STATUS_OFFSET), + QSFP_CHANNL_RX_LOS_STATUS_WIDTH) + 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) + else: + return [False] * 4 + + elif self.sfp_type == QSFP_DD_TYPE: + # page 11h + if self.dom_rx_tx_power_bias_supported: + offset = 128 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_CHANNL_RX_LOS_STATUS_OFFSET), + QSFP_DD_CHANNL_RX_LOS_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 8) + 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_list.append(rx_los_data & 0x10 != 0) + rx_los_list.append(rx_los_data & 0x20 != 0) + rx_los_list.append(rx_los_data & 0x40 != 0) + rx_los_list.append(rx_los_data & 0x80 != 0) + else: + return [False] * 8 + else: # SFP_TYPE + offset = 256 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH) + 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 & 0x02 != 0) + else: + return [False] + return rx_los_list + + 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_list = [] + + if self.sfp_type == OSFP_TYPE: + return None + elif self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_TX_FAULT_STATUS_OFFSET), + QSFP_CHANNL_TX_FAULT_STATUS_WIDTH) + 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) + else: + return [False] * 4 + elif self.sfp_type == QSFP_DD_TYPE: + # page 11h + if self.dom_rx_tx_power_bias_supported: + offset = 128 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_CHANNL_TX_FAULT_STATUS_OFFSET), + QSFP_DD_CHANNL_TX_FAULT_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_fault_data = int(dom_channel_monitor_raw[0], 8) + 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_list.append(tx_fault_data & 0x10 != 0) + tx_fault_list.append(tx_fault_data & 0x20 != 0) + tx_fault_list.append(tx_fault_data & 0x40 != 0) + tx_fault_list.append(tx_fault_data & 0x80 != 0) + else: + return [False] * 8 + else: # SFP_TYPE + offset = 256 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH) + 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 & 0x04 != 0) + else: + return [False] + return tx_fault_list + + def get_tx_disable(self): + """ + Retrieves the tx_disable status of this SFP + Returns: + A list of boolean values, representing the TX disable status + of each available channel, value is True if SFP channel + is TX disabled, False if not. + E.g., for a tranceiver with four channels: [False, False, True, False] + """ + tx_disable_list = [] + if self.sfp_type == OSFP_TYPE: + return None + elif self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_DISABLE_STATUS_OFFSET), + QSFP_CHANNL_DISABLE_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0x01 != 0) + tx_disable_list.append(tx_disable_data & 0x02 != 0) + tx_disable_list.append(tx_disable_data & 0x04 != 0) + tx_disable_list.append(tx_disable_data & 0x08 != 0) + else: + return [False] * 4 + + elif self.sfp_type == QSFP_DD_TYPE: + if self.dom_rx_tx_power_bias_supported: + offset = 128 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_CHANNL_DISABLE_STATUS_OFFSET), + QSFP_DD_CHANNL_DISABLE_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0x01 != 0) + tx_disable_list.append(tx_disable_data & 0x02 != 0) + tx_disable_list.append(tx_disable_data & 0x04 != 0) + tx_disable_list.append(tx_disable_data & 0x08 != 0) + tx_disable_list.append(tx_disable_data & 0x10 != 0) + tx_disable_list.append(tx_disable_data & 0x20 != 0) + tx_disable_list.append(tx_disable_data & 0x40 != 0) + tx_disable_list.append(tx_disable_data & 0x80 != 0) + else: + return [False] * 8 + else: # SFP_TYPE + offset = 256 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0xC0 != 0) + else: + return [False] + return tx_disable_list + + 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. + """ + 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 + + 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 + """ + if self.sfp_type == SFP_TYPE: + # SFP doesn't support this feature + return False + else: + try: + eeprom = None + + if not self.get_presence(): + return False + # Write to eeprom + port_eeprom_path = I2C_EEPROM_PATH.format(self._port_to_i2c_mapping[self.port_num]) + + eeprom = open(port_eeprom_path, "rb") + eeprom.seek(QSFP_POWEROVERRIDE_OFFSET) + 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: + # 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 + return False + 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) + + def get_power_set(self): + + if self.sfp_type == SFP_TYPE: + # SFP doesn't support this feature + return False + else: + power_set = False + + 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_set = ( + 'On' == dom_control_data['data']['PowerSet']['value']) + + return power_set + + 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 + """ + if self.sfp_type == QSFP_TYPE: + offset = 0 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return False + + dom_control_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_CONTROL_OFFSET), QSFP_CONTROL_WIDTH) + if dom_control_raw is not None: + dom_control_data = sfpd_obj.parse_control_bytes( + dom_control_raw, 0) + return ('On' == dom_control_data['data']['PowerOverride']['value']) + else: + return False + else: + return NotImplementedError + + def get_temperature(self): + """ + Retrieves the temperature of this SFP + Returns: + An integer number of current temperature in Celsius + """ + default = 0.0 + if not self.dom_supported: + return default + + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return default + + if self.dom_temp_supported: + 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) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + + elif self.sfp_type == QSFP_DD_TYPE: + offset = 0 + + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if self.dom_temp_supported: + dom_temperature_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_TEMPE_OFFSET), QSFP_DD_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature( + dom_temperature_raw, 0) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + + else: + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + sfpd_obj._calibration_type = 1 + + 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) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + + return default + + def get_voltage(self): + """ + Retrieves the supply voltage of this SFP + Returns: + An integer number of supply voltage in mV + """ + default = 0.0 + + if not self.dom_supported: + return default + + if self.sfp_type == QSFP_TYPE: + offset = 0 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return default + + if self.dom_volt_supported: + 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) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + + if self.sfp_type == QSFP_DD_TYPE: + offset = 128 + + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if self.dom_volt_supported: + dom_voltage_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_VOLT_OFFSET), QSFP_DD_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage( + dom_voltage_raw, 0) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + + else: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + + sfpd_obj._calibration_type = self.calibration + + 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) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + + return default + + 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'] + """ + tx_bias_list = [] + if self.sfp_type == QSFP_TYPE: + offset = 0 + default = [0.0] * 4 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return default + + 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) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX1Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX2Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX3Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX4Bias']['value'])) + else: + return default + + elif self.sfp_type == QSFP_DD_TYPE: + default = [0.0] * 8 + # page 11h + if self.dom_rx_tx_power_bias_supported: + offset = 128 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if dom_tx_bias_power_supported: + dom_tx_bias_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_TX_BIAS_OFFSET), QSFP_DD_TX_BIAS_WIDTH) + if dom_tx_bias_raw is not None: + dom_tx_bias_data = sfpd_obj.parse_dom_tx_bias( + dom_tx_bias_raw, 0) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX1Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX2Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX3Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX4Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX5Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX6Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX7Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX8Bias']['value'])) + else: + return default + else: + return default + + else: + offset = 256 + default = [0.0] + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + sfpd_obj._calibration_type = self.calibration + + if self.dom_supported: + 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) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TXBias']['value'])) + else: + return default + else: + return default + + return tx_bias_list + + 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'] + """ + rx_power_list = [] + if self.sfp_type == OSFP_TYPE: + # OSFP not supported on our platform yet. + return None + + elif self.sfp_type == QSFP_TYPE: + offset = 0 + default = [0.0] * 4 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return default + + if self.dom_rx_power_supported: + 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) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX1Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX2Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX3Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX4Power']['value'])) + else: + return default + else: + return default + + elif self.sfp_type == QSFP_DD_TYPE: + default = [0.0] * 8 + # page 11 + if self.dom_rx_tx_power_bias_supported: + offset = 128 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if self.dom_rx_power_supported: + dom_rx_power_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_RX_POWER_OFFSET), QSFP_DD_RX_POWER_WIDTH) + if dom_rx_power_raw is not None: + dom_rx_power_data = sfpd_obj.parse_dom_rx_power( + dom_rx_power_raw, 0) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX1Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX2Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX3Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX4Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX5Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX6Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX7Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX8Power']['value'])) + else: + return default + else: + return default + + else: + offset = 256 + default = [0.0] + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + + if self.dom_supported: + sfpd_obj._calibration_type = self.calibration + + 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) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RXPower']['value'])) + else: + return default + else: + return default + return rx_power_list + + 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'] + """ + tx_power_list = [] + if self.sfp_type == OSFP_TYPE: + # OSFP not supported on our platform yet. + return tx_power_list + + elif self.sfp_type == QSFP_TYPE: + offset = 0 + default = [0.0] * 4 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return tx_power_list + + if self.dom_tx_power_supported: + 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) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX1Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX2Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX3Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX4Power']['value'])) + else: + return default + else: + return default + + elif self.sfp_type == QSFP_DD_TYPE: + default = [0.0] * 8 + + # page 11 + if self.dom_rx_tx_power_bias_supported: + offset = 128 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if self.dom_tx_power_supported: + dom_tx_power_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_TX_POWER_OFFSET), + QSFP_DD_TX_POWER_WIDTH) + if dom_tx_power_raw is not None: + dom_tx_power_data = sfpd_obj.parse_dom_tx_power( + dom_tx_power_raw, 0) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX1Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX2Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX3Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX4Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX5Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX6Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX7Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX8Power']['value'])) + else: + return default + else: + return default + + else: + offset = 256 + default = [0.0] + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + + if self.dom_supported: + sfpd_obj._calibration_type = self.calibration + + 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) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TXPower']['value'])) + else: + return default + else: + return default + return tx_power_list + + def reset(self): + """ + Reset SFP and return all user module settings to their default srate. + Returns: + A boolean, True if successful, False if not + """ + # Check for invalid port_num + + if not self.get_presence(): + return False + + if 49 <= self.port_num <= 54: + reset_path = "{}{}{}".format(self.i2c_cpld_path, 'module_reset_', self.port_num) + else: + return False + + ret = self._api_helper.write_txt_file(reset_path, 1) #sysfs 1: enable reset + if ret is not True: + return ret + + time.sleep(0.2) + ret = self._api_helper.write_txt_file(reset_path, 0) #sysfs 1: disable reset + time.sleep(0.2) + + return ret + + 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 + """ + if self.sfp_type == QSFP_TYPE: + sysfsfile_eeprom = None + try: + tx_disable_value = 0xf if tx_disable else 0x0 + # Write to eeprom + sysfsfile_eeprom = open(self._eeprom_path, "r+b") + sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) + sysfsfile_eeprom.write(struct.pack('B', tx_disable_value)) + except IOError: + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + + elif self.sfp_type == SFP_TYPE: + disable_path = "{}{}{}".format(self.i2c_cpld_path, 'module_tx_disable_', self.port_num) + tx_disable_value = 1 if tx_disable else 0 + ret = self._api_helper.write_txt_file(disable_path, tx_disable_value) #sysfs 1: disable tx + if ret is not True: + return ret + + return False + + 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 + """ + if self.sfp_type == QSFP_TYPE: + sysfsfile_eeprom = None + try: + current_state = self.get_tx_disable_channel() + tx_disable_value = (current_state | channel) if \ + disable else (current_state & (~channel)) + + # Write to eeprom + sysfsfile_eeprom = open(self._eeprom_path, "r+b") + sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) + sysfsfile_eeprom.write(struct.pack('B', tx_disable_value)) + except IOError: + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + + return False + + 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 + """ + if self.sfp_type == SFP_TYPE: + return False # SFP doesn't support this feature + else: + if not self.get_presence(): + return False + + if lpmode: + self.set_power_override(True, True) + else: + self.set_power_override(True, False) + + return True + + 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 + """ + if self.sfp_type == SFP_TYPE: + return False # SFP doesn't support this feature + else: + if not self.get_presence(): + return False + try: + power_override_bit = (1 << 0) if power_override else 0 + power_set_bit = (1 << 1) if power_set else (1 << 3) + + buffer = create_string_buffer(1) + if sys.version_info[0] >= 3: + buffer[0] = (power_override_bit | power_set_bit) + else: + buffer[0] = chr(power_override_bit | power_set_bit) + # Write to eeprom + port_eeprom_path = I2C_EEPROM_PATH.format(self._port_to_i2c_mapping[self.port_num]) + with open(port_eeprom_path, "r+b") as fd: + fd.seek(QSFP_POWEROVERRIDE_OFFSET) + fd.write(buffer[0]) + time.sleep(0.01) + except Exception as e: + print ('Error: unable to open file: ', str(e)) + return False + return True + + ############################################################## + ###################### Device methods ######################## + ############################################################## + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + sfputil_helper = SfpUtilHelper() + sfputil_helper.read_porttab_mappings( + self.__get_path_to_port_config_file()) + name = sfputil_helper.logical[self._index] or "Unknown" + return name + + def get_presence(self): + """ + Retrieves the presence of the device + Returns: + bool: True if device is present, False if not + """ + val = self._api_helper.read_txt_file( + self.i2c_cpld_path + "module_present_" + str(self.port_num)) + + if val is not None: + return int(val, 10)==1 + else: + return False + + + 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() + return transceiver_dom_info_dict.get("model", "N/A") + + 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() + return transceiver_dom_info_dict.get("serial", "N/A") + + 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 not self.get_reset_status() + + def get_cc_base(self): + if self.sfp_type == SFP_TYPE: + get_data = self._read_eeprom_specific_bytes( + 0, 63) if self.get_presence() else None + if get_data is None: + return False + + get_sum=0 + for i in range(0, 63): + get_sum=get_sum + int(get_data[i], 16) + + ccb= get_sum & 0xff + + ccb_data = self._read_eeprom_specific_bytes( + XCVR_CC_BASE_OFFSET, 2) if self.get_presence() else None + + + if int(ccb_data[0], 16) == ccb: + return True + else: + return False + elif self.sfp_type == QSFP_TYPE or self.sfp_type == QSFP_DD_TYPE: + offset=128 + get_data = self._read_eeprom_specific_bytes( + offset, 63) if self.get_presence() else None + if get_data is None: + return False + + get_sum=0 + for i in range(0, 63): + get_sum=get_sum + int(get_data[i], 16) + + ccb= get_sum & 0xff + + ccb_data = self._read_eeprom_specific_bytes( + offset + XCVR_CC_BASE_OFFSET, 2) if self.get_presence() else None + + + if int(ccb_data[0], 16) == ccb: + return True + else: + return False + + + return False + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return self.port_num + + def is_replaceable(self): + """ + Retrieves if replaceable + Returns: + A boolean value, True if replaceable + """ + return True diff --git a/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/thermal.py b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/thermal.py new file mode 100644 index 00000000000..e54bc1fd702 --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/thermal.py @@ -0,0 +1,234 @@ +############################################################################# +# Edgecore +# +# Thermal contains an implementation of SONiC Platform Base API and +# provides the thermal device status which are available in the platform +# +############################################################################# + +import os +import os.path +import glob + +try: + from sonic_platform_base.thermal_base import ThermalBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +PSU_I2C_PATH = "/sys/bus/i2c/devices/{}-00{}/" +PSU_HWMON_I2C_MAPPING = { + 0: { + "num": 57, + "addr": "3c" + }, + 1: { + "num": 58, + "addr": "3f" + }, +} + +PSU_CPLD_I2C_MAPPING = { + 0: { + "num": 57, + "addr": "38" + }, + 1: { + "num": 58, + "addr": "3b" + }, +} + +THERMAL_NAME_LIST = ["Temp sensor 1", "Temp sensor 2", + "Temp sensor 3"] + +PSU_THERMAL_NAME_LIST = ["PSU-1 temp sensor 1", "PSU-2 temp sensor 2"] + +SYSFS_PATH = "/sys/bus/i2c/devices" + +class Thermal(ThermalBase): + """Platform-specific Thermal class""" + + def __init__(self, thermal_index=0, is_psu=False, psu_index=0): + self.index = thermal_index + self.is_psu = is_psu + self.psu_index = psu_index + + if self.is_psu: + psu_i2c_bus = PSU_HWMON_I2C_MAPPING[psu_index]["num"] + psu_i2c_addr = PSU_HWMON_I2C_MAPPING[psu_index]["addr"] + self.psu_hwmon_path = PSU_I2C_PATH.format(psu_i2c_bus, + psu_i2c_addr) + psu_i2c_bus = PSU_CPLD_I2C_MAPPING[psu_index]["num"] + psu_i2c_addr = PSU_CPLD_I2C_MAPPING[psu_index]["addr"] + self.cpld_path = PSU_I2C_PATH.format(psu_i2c_bus, psu_i2c_addr) + + # Set hwmon path + i2c_path = { + 0: "61-0048/hwmon/hwmon*/", + 1: "62-0049/hwmon/hwmon*/", + 2: "63-004a/hwmon/hwmon*/" + }.get(self.index, None) + + self.hwmon_path = "{}/{}".format(SYSFS_PATH, i2c_path) + self.ss_key = THERMAL_NAME_LIST[self.index] + self.ss_index = 1 + + def __read_txt_file(self, file_path): + for filename in glob.glob(file_path): + try: + with open(filename, 'r') as fd: + data =fd.readline().rstrip() + return data + except IOError as e: + pass + + return None + + def __get_temp(self, temp_file): + if not self.is_psu: + temp_file_path = os.path.join(self.hwmon_path, temp_file) + else: + temp_file_path = temp_file + raw_temp = self.__read_txt_file(temp_file_path) + if raw_temp is not None: + return float(raw_temp)/1000 + else: + return 0 + + def __set_threshold(self, file_name, temperature): + if self.is_psu: + return True + temp_file_path = os.path.join(self.hwmon_path, file_name) + for filename in glob.glob(temp_file_path): + try: + with open(filename, 'w') as fd: + fd.write(str(temperature)) + return True + except IOError as e: + print("IOError") + return False + + + + def get_temperature(self): + """ + Retrieves current temperature reading from thermal + Returns: + A float number of current temperature in Celsius up to nearest thousandth + of one degree Celsius, e.g. 30.125 + """ + if not self.is_psu: + temp_file = "temp{}_input".format(self.ss_index) + else: + temp_file = self.psu_hwmon_path + "psu_temp1_input" + + return self.__get_temp(temp_file) + + def get_high_threshold(self): + """ + Retrieves the high threshold temperature of thermal + Returns: + A float number, the high threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + if self.is_psu: + return 80 + + temp_file = "temp{}_max".format(self.ss_index) + return self.__get_temp(temp_file) + + def set_high_threshold(self, temperature): + """ + Sets the high threshold temperature of thermal + Args : + temperature: A float number up to nearest thousandth of one degree Celsius, + e.g. 30.125 + Returns: + A boolean, True if threshold is set successfully, False if not + """ + temp_file = "temp{}_max".format(self.ss_index) + temperature = temperature *1000 + self.__set_threshold(temp_file, temperature) + + return True + + def get_name(self): + """ + Retrieves the name of the thermal device + Returns: + string: The name of the thermal device + """ + if self.is_psu: + return PSU_THERMAL_NAME_LIST[self.psu_index] + else: + return THERMAL_NAME_LIST[self.index] + + def get_presence(self): + """ + Retrieves the presence of the Thermal + Returns: + bool: True if Thermal is present, False if not + """ + if self.is_psu: + val = self.__read_txt_file(self.cpld_path + "psu_present") + return int(val, 10) == 1 + temp_file = "temp{}_input".format(self.ss_index) + temp_file_path = os.path.join(self.hwmon_path, temp_file) + raw_txt = self.__read_txt_file(temp_file_path) + if raw_txt is not None: + return True + else: + return False + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + if self.is_psu: + temp_file = self.psu_hwmon_path + "psu_temp_fault" + return self.get_presence() and (not int( + self.__read_txt_file(temp_file))) + + file_str = "temp{}_input".format(self.ss_index) + file_path = os.path.join(self.hwmon_path, file_str) + raw_txt = self.__read_txt_file(file_path) + if raw_txt is None: + return False + else: + return int(raw_txt) != 0 + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + + return "N/A" + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return "N/A" + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device or -1 if cannot determine the position + """ + return self.index+1 + + def is_replaceable(self): + """ + Retrieves whether thermal module is replaceable + Returns: + A boolean value, True if replaceable, False if not + """ + return False diff --git a/device/accton/x86_64-accton_as5812_54x-r0/system_health_monitoring_config.json b/device/accton/x86_64-accton_as5812_54x-r0/system_health_monitoring_config.json new file mode 100644 index 00000000000..5f3b3b07e73 --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/system_health_monitoring_config.json @@ -0,0 +1,15 @@ +{ + "services_to_ignore": [], + "devices_to_ignore": [ + "asic", + "psu.temperature" + + ], + "user_defined_checkers": [], + "polling_interval": 60, + "led_color": { + "fault": "STATUS_LED_COLOR_AMBER", + "normal": "STATUS_LED_COLOR_GREEN", + "booting": "STATUS_LED_COLOR_GREEN" + } +} diff --git a/device/accton/x86_64-accton_as5835_54t-r0/Accton-AS5835-54T/port_config.ini b/device/accton/x86_64-accton_as5835_54t-r0/Accton-AS5835-54T/port_config.ini index 119fe814fee..bb594d7a6fd 100755 --- a/device/accton/x86_64-accton_as5835_54t-r0/Accton-AS5835-54T/port_config.ini +++ b/device/accton/x86_64-accton_as5835_54t-r0/Accton-AS5835-54T/port_config.ini @@ -48,8 +48,8 @@ Ethernet45 73 tenGigE46 46 10000 Ethernet46 76 tenGigE47 47 10000 Ethernet47 75 tenGigE48 48 10000 Ethernet48 37,38,39,40 hundredGigE49 49 100000 -Ethernet52 29,30,31,32 hundredGigE50 53 100000 -Ethernet56 33,34,35,36 hundredGigE51 57 100000 -Ethernet60 49,50,51,52 hundredGigE52 61 100000 -Ethernet64 45,46,47,48 hundredGigE53 65 100000 -Ethernet68 41,42,43,44 hundredGigE54 69 100000 +Ethernet52 29,30,31,32 hundredGigE50 50 100000 +Ethernet56 33,34,35,36 hundredGigE51 51 100000 +Ethernet60 49,50,51,52 hundredGigE52 52 100000 +Ethernet64 45,46,47,48 hundredGigE53 53 100000 +Ethernet68 41,42,43,44 hundredGigE54 54 100000 diff --git a/device/accton/x86_64-accton_as5835_54t-r0/pddf/pd-plugin.json b/device/accton/x86_64-accton_as5835_54t-r0/pddf/pd-plugin.json new file mode 100644 index 00000000000..fdb48b032c7 --- /dev/null +++ b/device/accton/x86_64-accton_as5835_54t-r0/pddf/pd-plugin.json @@ -0,0 +1,67 @@ +{ + + "XCVR": + { + "xcvr_present": + { + "i2c": + { + "valmap-SFP": {"1":true, "0":false }, + "valmap-SFP28": {"1":true, "0":false }, + "valmap-QSFP28": {"1":true, "0":false} + } + } + }, + "PSU": + { + "psu_present": + { + "i2c": + { + "valmap": { "1":true, "0":false } + } + }, + + "psu_power_good": + { + "i2c": + { + "valmap": { "1": true, "0":false } + } + }, + + "psu_fan_dir": + { + "i2c": + { + "valmap": { "F2B":"EXHAUST", "B2F":"INTAKE" } + } + }, + + "PSU_FAN_MAX_SPEED":"18000" + }, + + "FAN": + { + "direction": + { + "i2c": + { + "valmap": {"1":"INTAKE", "0":"EXHAUST"} + } + }, + + "present": + { + "i2c": + { + "valmap": {"1":true, "0":false} + } + }, + + "duty_cycle_to_pwm": "lambda dc: (dc/5)", + + "pwm_to_duty_cycle": "lambda pwm: (pwm*5)" + } + +} diff --git a/device/accton/x86_64-accton_as5835_54t-r0/pddf/pddf-device.json b/device/accton/x86_64-accton_as5835_54t-r0/pddf/pddf-device.json new file mode 100644 index 00000000000..5c8ee2acc00 --- /dev/null +++ b/device/accton/x86_64-accton_as5835_54t-r0/pddf/pddf-device.json @@ -0,0 +1,690 @@ +{ + "PLATFORM": + { + "num_psus":2, + "num_fantrays":5, + "num_fans_pertray":2, + "num_ports":54, + "num_temps": 4, + "pddf_dev_types": + { + "description":"AS5835-54T - Below is the list of supported PDDF device types (chip names) for various components. If any component uses some other driver, we will create the client using 'echo > /new_device' method", + "CPLD": + [ + "i2c_cpld" + ], + "PSU": + [ + "psu_eeprom", + "psu_pmbus" + ], + "FAN": + [ + "fan_ctrl", + "fan_eeprom" + ], + "PORT_MODULE": + [ + "pddf_xcvr" + ] + }, + "std_kos": + [ + "i2c-i801", + "i2c-ismt", + "i2c_dev", + "i2c_mux_pca954x", + "optoe" + ], + "pddf_kos": + [ + "pddf_client_module", + "pddf_cpld_module", + "pddf_cpld_driver", + "pddf_mux_module", + "pddf_xcvr_module", + "pddf_xcvr_driver_module", + "pddf_psu_driver_module", + "pddf_psu_module", + "pddf_fan_driver_module", + "pddf_fan_module", + "pddf_led_module", + "pddf_sysstatus_module" + ], + "custom_kos": + [ + "pddf_custom_psu" + ] + }, + + "SYSTEM": + { + "dev_info": {"device_type":"CPU", "device_name":"ROOT_COMPLEX", "device_parent":null}, + "i2c": + { + "CONTROLLERS": + [ + { "dev_name":"i2c-1", "dev":"SMBUS1" } + ] + } + }, + + "SMBUS1": + { + "dev_info": {"device_type": "SMBUS", "device_name": "SMBUS1", "device_parent": "SYSTEM"}, + "i2c": + { + "topo_info": {"dev_addr": "0x1"}, + "DEVICES": + [ + {"dev": "EEPROM1"}, + {"dev": "CPU_CPLD"}, + {"dev": "MUX1"} + ] + } + }, + + "EEPROM1": + { + "dev_info": {"device_type": "EEPROM", "device_name": "EEPROM1", "device_parent": "SMBUS1"}, + "i2c": + { + "topo_info": {"parent_bus": "0x1", "dev_addr": "0x57", "dev_type": "24c02"}, + "dev_attr": {"access_mode": "BLOCK"}, + "attr_list": [ + {"attr_name": "eeprom"} + ] + } + }, + + "CPU_CPLD": + { + "dev_info": { "device_type":"CPLD", "device_name":"CPU_CPLD", "device_parent":"SMBUS1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x1", "dev_addr":"0x65", "dev_type":"i2c_cpld"}, + "dev_attr": { } + } + }, + + "MUX1": + { + "dev_info": { "device_type":"MUX", "device_name":"MUX1", "device_parent":"SMBUS1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x1", "dev_addr":"0x77", "dev_type":"pca9548"}, + "dev_attr": { "virt_bus":"0x2"}, + "channel": + [ + { "chn":"0", "dev":"MUX2" }, + { "chn":"0", "dev":"MUX3" }, + { "chn":"0", "dev":"MUX4" }, + { "chn":"1", "dev":"CPLD1" }, + { "chn":"1", "dev":"CPLD2" }, + { "chn":"1", "dev":"CPLD3" }, + { "chn":"1", "dev":"FAN-CTRL" } + ] + } + }, + + "CPLD1": + { + "dev_info": { "device_type":"CPLD", "device_name":"CPLD1", "device_parent":"MUX1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x3", "dev_addr":"0x60", "dev_type":"i2c_cpld"}, + "dev_attr":{} + } + }, + "CPLD2": + { + "dev_info": { "device_type":"CPLD", "device_name":"CPLD2", "device_parent":"MUX1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x3", "dev_addr":"0x61", "dev_type":"i2c_cpld"}, + "dev_attr":{} + } + }, + "CPLD3": + { + "dev_info": { "device_type":"CPLD", "device_name":"CPLD3", "device_parent":"MUX1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x3", "dev_addr":"0x62", "dev_type":"i2c_cpld"}, + "dev_attr":{} + } + }, + "FAN-CTRL": + { + "dev_info": { "device_type":"FAN", "device_name":"FAN-CTRL", "device_parent":"MUX1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x3", "dev_addr":"0x63", "dev_type":"fan_ctrl"}, + "dev_attr": { "num_fantrays":"5"}, + "attr_list": + [ + { "attr_name":"fan1_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x02", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan2_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x02", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan3_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x02", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan4_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x02", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan5_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x02", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan6_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x02", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan7_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x02", "attr_mask":"0x8", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan8_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x02", "attr_mask":"0x8", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan9_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x02", "attr_mask":"0x10", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan10_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x02","attr_mask":"0x10", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan1_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x03", "attr_mask":"0x1", "attr_cmpval":"0x1", "attr_len":"1"}, + { "attr_name":"fan2_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x03", "attr_mask":"0x1", "attr_cmpval":"0x1", "attr_len":"1"}, + { "attr_name":"fan3_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x03", "attr_mask":"0x2", "attr_cmpval":"0x2", "attr_len":"1"}, + { "attr_name":"fan4_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x03", "attr_mask":"0x2", "attr_cmpval":"0x2", "attr_len":"1"}, + { "attr_name":"fan5_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x03", "attr_mask":"0x4", "attr_cmpval":"0x4", "attr_len":"1"}, + { "attr_name":"fan6_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x03", "attr_mask":"0x4", "attr_cmpval":"0x4", "attr_len":"1"}, + { "attr_name":"fan7_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x03", "attr_mask":"0x8", "attr_cmpval":"0x8", "attr_len":"1"}, + { "attr_name":"fan8_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x03", "attr_mask":"0x8", "attr_cmpval":"0x8", "attr_len":"1"}, + { "attr_name":"fan9_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x03", "attr_mask":"0x10", "attr_cmpval":"0x10", "attr_len":"1"}, + { "attr_name":"fan10_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x03", "attr_mask":"0x10", "attr_cmpval":"0x10", "attr_len":"1"}, + { "attr_name":"fan1_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x07", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"150", "attr_is_divisor":0}, + { "attr_name":"fan2_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x0C", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"150", "attr_is_divisor":0}, + { "attr_name":"fan3_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x08", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"150", "attr_is_divisor":0}, + { "attr_name":"fan4_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x0D", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"150", "attr_is_divisor":0}, + { "attr_name":"fan5_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x09", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"150", "attr_is_divisor":0}, + { "attr_name":"fan6_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x0E", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"150", "attr_is_divisor":0}, + { "attr_name":"fan7_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x0A", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"150" , "attr_is_divisor":0}, + { "attr_name":"fan8_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x0F", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"150" , "attr_is_divisor":0}, + { "attr_name":"fan9_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x0B", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"150" , "attr_is_divisor":0}, + { "attr_name":"fan10_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x10", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"150" , "attr_is_divisor":0}, + { "attr_name":"fan1_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x06", "attr_mask":"0x1F", "attr_len":"1" }, + { "attr_name":"fan2_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x06", "attr_mask":"0x1F", "attr_len":"1" }, + { "attr_name":"fan3_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x06", "attr_mask":"0x1F", "attr_len":"1" }, + { "attr_name":"fan4_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x06", "attr_mask":"0x1F", "attr_len":"1" }, + { "attr_name":"fan5_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x06", "attr_mask":"0x1F", "attr_len":"1" }, + { "attr_name":"fan6_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x06", "attr_mask":"0x1F", "attr_len":"1" }, + { "attr_name":"fan7_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x06", "attr_mask":"0x1F", "attr_len":"1" }, + { "attr_name":"fan8_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x06", "attr_mask":"0x1F", "attr_len":"1" }, + { "attr_name":"fan9_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x06", "attr_mask":"0x1F", "attr_len":"1" }, + { "attr_name":"fan10_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x06", "attr_mask":"0x1F", "attr_len":"1" } + ] + } + }, + + + "MUX2": + { + "dev_info": { "device_type":"MUX", "device_name":"MUX2", "device_parent":"MUX1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2", "dev_addr":"0x70", "dev_type":"pca9548"}, + "dev_attr": { "virt_bus":"0xa"}, + "channel": + [ + { "chn":"1", "dev":"PSU1" }, + { "chn":"2", "dev":"PSU2" } + ] + } + }, + "PSU1": + { + "dev_info": { "device_type":"PSU", "device_name":"PSU1", "device_parent":"MUX2"}, + "dev_attr": { "dev_idx":"1", "num_psu_fans": "1"}, + "i2c": + { + "interface": + [ + { "itf":"pmbus", "dev":"PSU1-PMBUS" }, + { "itf":"eeprom", "dev":"PSU1-EEPROM" } + ] + } + }, + + "PSU1-PMBUS": + { + "dev_info": { "device_type":"PSU-PMBUS", "device_name":"PSU1-PMBUS", "device_parent":"MUX2", "virt_parent":"PSU1"}, + "i2c": + { + "topo_info":{ "parent_bus":"0xb", "dev_addr":"0x58", "dev_type":"psu_pmbus"}, + "attr_list": + [ + { "attr_name":"psu_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x2", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"psu_model_name", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x9a", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"10" }, + { "attr_name":"psu_power_good", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x2", "attr_mask":"0x2", "attr_cmpval":"0x2", "attr_len":"1"}, + { "attr_name":"psu_mfr_id", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0X99", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"10" }, + { "attr_name":"psu_fan_dir", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0xc3", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"5"}, + { "attr_name":"psu_v_out", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x8b", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_i_out", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x8c", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_p_out", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x96", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_fan1_speed_rpm", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x90", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"} + ] + } + }, + + "PSU1-EEPROM": + { + "dev_info": { "device_type":"PSU-EEPROM", "device_name":"PSU1-EEPROM", "device_parent":"MUX2", "virt_parent":"PSU1"}, + "i2c": + { + "topo_info":{ "parent_bus":"0xb", "dev_addr":"0x50", "dev_type":"psu_eeprom"}, + "attr_list": + [ + { "attr_name":"psu_serial_num", "attr_devaddr":"0x50", "attr_devtype":"eeprom", "attr_offset":"0x35", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"19" } + ] + } + }, + + "PSU2": + { + "dev_info": { "device_type":"PSU", "device_name":"PSU2", "device_parent":"MUX2" }, + "dev_attr": { "dev_idx":"2", "num_psu_fans":"1"}, + "i2c": + { + "interface": + [ + { "itf":"pmbus", "dev":"PSU2-PMBUS"}, + { "itf":"eeprom", "dev":"PSU2-EEPROM" } + ] + } + }, + + "PSU2-PMBUS": + { + "dev_info": {"device_type":"PSU-PMBUS", "device_name":"PSU2-PMBUS", "device_parent":"MUX2", "virt_parent":"PSU2"}, + "i2c": + { + "topo_info": { "parent_bus":"0xc", "dev_addr":"0x5b", "dev_type":"psu_pmbus"}, + "attr_list": + [ + { "attr_name":"psu_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x2", "attr_mask":"0x10", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"psu_model_name", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x9a", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"10" }, + { "attr_name":"psu_power_good", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x2", "attr_mask":"0x20", "attr_cmpval":"0x20", "attr_len":"1"}, + { "attr_name":"psu_mfr_id", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0X99", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"10" }, + { "attr_name":"psu_fan_dir", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0xc3", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"5"}, + { "attr_name":"psu_v_out", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x8b", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_i_out", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x8c", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_p_out", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x96", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_fan1_speed_rpm", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x90", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"} + ] + } + }, + + "PSU2-EEPROM": + { + "dev_info": { "device_type":"PSU-EEPROM", "device_name":"PSU2-EEPROM", "device_parent":"MUX2", "virt_parent":"PSU2"}, + "i2c": + { + "topo_info":{ "parent_bus":"0xc", "dev_addr":"0x53", "dev_type":"psu_eeprom"}, + "attr_list": + [ + { "attr_name":"psu_serial_num", "attr_devaddr":"0x53", "attr_devtype":"eeprom", "attr_offset":"0x35", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"19" } + ] + } + }, + + + "MUX4": + { + "dev_info": { "device_type":"MUX", "device_name":"MUX4", "device_parent":"MUX1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2", "dev_addr":"0x71", "dev_type":"pca9548"}, + "dev_attr": { "virt_bus":"0x1a"}, + "channel": + [ + { "chn":"0", "dev":"TEMP1" }, + { "chn":"1", "dev":"TEMP2" }, + { "chn":"2", "dev":"TEMP3" }, + { "chn":"3", "dev":"TEMP4" } + ] + } + }, + + "TEMP1" : + { + "dev_info": { "device_type":"TEMP_SENSOR", "device_name":"TEMP1", "device_parent":"MUX4"}, + "i2c": + { + "topo_info": { "parent_bus":"0x1a", "dev_addr":"0x4B", "dev_type":"lm75"}, + "attr_list": + [ + { "attr_name": "temp1_high_threshold", "drv_attr_name":"temp1_max"}, + { "attr_name": "temp1_max_hyst"}, + { "attr_name": "temp1_input"} + ] + } + }, + "TEMP2" : + { + "dev_info": { "device_type":"TEMP_SENSOR", "device_name":"TEMP2", "device_parent":"MUX4"}, + "i2c": + { + "topo_info": { "parent_bus":"0x1b", "dev_addr":"0x4C", "dev_type":"lm75"}, + "attr_list": + [ + { "attr_name": "temp1_high_threshold", "drv_attr_name":"temp1_max"}, + { "attr_name": "temp1_max_hyst"}, + { "attr_name": "temp1_input"} + ] + } + }, + "TEMP3" : + { + "dev_info": { "device_type":"TEMP_SENSOR", "device_name":"TEMP3", "device_parent":"MUX4"}, + "i2c": + { + "topo_info": { "parent_bus":"0x1c", "dev_addr":"0x49", "dev_type":"lm75"}, + "attr_list": + [ + { "attr_name": "temp1_high_threshold", "drv_attr_name":"temp1_max"}, + { "attr_name": "temp1_max_hyst"}, + { "attr_name": "temp1_input"} + ] + } + }, + "TEMP4" : + { + "dev_info": { "device_type":"TEMP_SENSOR", "device_name":"TEMP4", "device_parent":"MUX4"}, + "i2c": + { + "topo_info": { "parent_bus":"0x1d", "dev_addr":"0x4A", "dev_type":"lm75"}, + "attr_list": + [ + { "attr_name": "temp1_high_threshold", "drv_attr_name":"temp1_max"}, + { "attr_name": "temp1_max_hyst"}, + { "attr_name": "temp1_input"} + ] + } + }, + "MUX3": + { + "dev_info": { "device_type":"MUX", "device_name":"MUX3", "device_parent":"MUX1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2", "dev_addr":"0x72", "dev_type":"pca9548"}, + "dev_attr": { "virt_bus":"0x12"}, + "channel": + [ + { "chn":"0", "dev":"PORT51" }, + { "chn":"1", "dev":"PORT54" }, + { "chn":"2", "dev":"PORT49" }, + { "chn":"3", "dev":"PORT50" }, + { "chn":"4", "dev":"PORT52" }, + { "chn":"5", "dev":"PORT53" } + ] + } + }, + + "PORT51": + { + "dev_info": { "device_type":"QSFP28", "device_name":"PORT51", "device_parent":"MUX3"}, + "dev_attr": { "dev_idx":"51"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT51-EEPROM" }, + { "itf":"control", "dev":"PORT51-CTRL" } + ] + } + }, + "PORT51-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT51-EEPROM", "device_parent":"MUX3", "virt_parent":"PORT51"}, + "i2c": + { + "topo_info": { "parent_bus":"0x12", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT51-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT51-CTRL", "device_parent":"MUX3", "virt_parent":"PORT51"}, + "i2c": + { + "topo_info": { "parent_bus":"0x12", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x14", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x15", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x13", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_lpmode", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x16", "attr_mask":"0x2", "attr_cmpval":"0x4", "attr_len":"1"} + + ] + } + }, + + "PORT54": + { + "dev_info": { "device_type":"QSFP28", "device_name":"PORT54", "device_parent":"MUX3"}, + "dev_attr": { "dev_idx":"54"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT54-EEPROM" }, + { "itf":"control", "dev":"PORT54-CTRL" } + ] + } + }, + "PORT54-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT54-EEPROM", "device_parent":"MUX3", "virt_parent":"PORT54"}, + "i2c": + { + "topo_info": { "parent_bus":"0x13", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT54-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT54-CTRL", "device_parent":"MUX3", "virt_parent":"PORT54"}, + "i2c": + { + "topo_info": { "parent_bus":"0x13", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x14", "attr_mask":"0x5", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x15", "attr_mask":"0x5", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x13", "attr_mask":"0x5", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_lpmode", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x16", "attr_mask":"0x5", "attr_cmpval":"0x20", "attr_len":"1"} + ] + } + }, + + "PORT49": + { + "dev_info": { "device_type":"QSFP28", "device_name":"PORT49", "device_parent":"MUX3"}, + "dev_attr": { "dev_idx":"49"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT49-EEPROM" }, + { "itf":"control", "dev":"PORT49-CTRL" } + ] + } + }, + "PORT49-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT49-EEPROM", "device_parent":"MUX3", "virt_parent":"PORT49"}, + "i2c": + { + "topo_info": { "parent_bus":"0x14", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT49-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT49-CTRL", "device_parent":"MUX3", "virt_parent":"PORT49"}, + "i2c": + { + "topo_info": { "parent_bus":"0x14", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x14", "attr_mask":"0x0", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x15", "attr_mask":"0x0", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x62", "attr_devtype":"cpld","attr_devname":"CPLD3", "attr_offset":"0x13", "attr_mask":"0x0", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_lpmode", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x16", "attr_mask":"0x0", "attr_cmpval":"0x1", "attr_len":"1"} + ] + } + }, + + "PORT50": + { + "dev_info": { "device_type":"QSFP28", "device_name":"PORT50", "device_parent":"MUX3"}, + "dev_attr": { "dev_idx":"50"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT50-EEPROM" }, + { "itf":"control", "dev":"PORT50-CTRL" } + ] + } + }, + "PORT50-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT50-EEPROM", "device_parent":"MUX3", "virt_parent":"PORT50"}, + "i2c": + { + "topo_info": { "parent_bus":"0x15", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + + "PORT50-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT50-CTRL", "device_parent":"MUX3", "virt_parent":"PORT50"}, + "i2c": + { + "topo_info": { "parent_bus":"0x15", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x14", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x15", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x62", "attr_devtype":"cpld","attr_devname":"CPLD3", "attr_offset":"0x13", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_lpmode", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x16", "attr_mask":"0x1", "attr_cmpval":"0x2", "attr_len":"1"} + ] + } + }, + + "PORT52": + { + "dev_info": { "device_type":"QSFP28", "device_name":"PORT52", "device_parent":"MUX3"}, + "dev_attr": { "dev_idx":"52"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT52-EEPROM" }, + { "itf":"control", "dev":"PORT52-CTRL" } + ] + } + }, + "PORT52-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT52-EEPROM", "device_parent":"MUX3", "virt_parent":"PORT52"}, + "i2c": + { + "topo_info": { "parent_bus":"0x16", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT52-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT52-CTRL", "device_parent":"MUX3", "virt_parent":"PORT52"}, + "i2c": + { + "topo_info": { "parent_bus":"0x16", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x14", "attr_mask":"0x3", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x15", "attr_mask":"0x3", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x13", "attr_mask":"0x3", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_lpmode", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x16", "attr_mask":"0x3", "attr_cmpval":"0x8", "attr_len":"1"} + ] + } + }, + + "PORT53": + { + "dev_info": { "device_type":"QSFP28", "device_name":"PORT53", "device_parent":"MUX3"}, + "dev_attr": { "dev_idx":"53"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT53-EEPROM" }, + { "itf":"control", "dev":"PORT53-CTRL" } + ] + } + }, + "PORT53-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT53-EEPROM", "device_parent":"MUX3", "virt_parent":"PORT53"}, + "i2c": + { + "topo_info": { "parent_bus":"0x17", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT53-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT53-CTRL", "device_parent":"MUX3", "virt_parent":"PORT53"}, + "i2c": + { + "topo_info": { "parent_bus":"0x17", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x14", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x15", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x13", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_lpmode", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x16", "attr_mask":"0x4", "attr_cmpval":"0x10", "attr_len":"1"} + ] + } + }, + + "LOC_LED": + { + "dev_info": { "device_type":"LED", "device_name":"LOC_LED"}, + "dev_attr": { "index":"0"}, + "i2c" : + { + "attr_list": + [ + {"attr_name":"STATUS_LED_COLOR_AMBER", "descr": "Amber" , "bits" : "5:4", "value" : "0x0", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x0A"}, + {"attr_name":"STATUS_LED_COLOR_OFF", "descr": "Off" , "bits" : "5:4", "value" : "0x1", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x0A"} + + ] + } + }, + "DIAG_LED": + { + "dev_info": { "device_type":"LED", "device_name":"DIAG_LED"}, + "dev_attr": { "index":"0"}, + "i2c" : + { + "attr_list": + [ + {"attr_name":"STATUS_LED_COLOR_GREEN", "descr": "Green" , "bits" : "3:2", "value" : "0x2", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x0A"}, + {"attr_name":"STATUS_LED_COLOR_AMBER", "descr": "Amber" , "bits" : "3:2", "value" : "0x1", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x0A"}, + {"attr_name":"STATUS_LED_COLOR_OFF", "descr": "Off" , "bits" : "3:2", "value" : "0x3", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x0A"} + ] + } + } +} diff --git a/device/accton/x86_64-accton_as5835_54t-r0/pddf_support b/device/accton/x86_64-accton_as5835_54t-r0/pddf_support new file mode 100644 index 00000000000..e69de29bb2d diff --git a/device/accton/x86_64-accton_as5835_54t-r0/pmon_daemon_control.json b/device/accton/x86_64-accton_as5835_54t-r0/pmon_daemon_control.json index 584a14b9d94..a3b204e20d8 100644 --- a/device/accton/x86_64-accton_as5835_54t-r0/pmon_daemon_control.json +++ b/device/accton/x86_64-accton_as5835_54t-r0/pmon_daemon_control.json @@ -1,5 +1,5 @@ { "skip_ledd": true, - "skip_thermalctld": true + "skip_pcied": true } diff --git a/device/accton/x86_64-accton_as5835_54t-r0/system_health_monitoring_config.json b/device/accton/x86_64-accton_as5835_54t-r0/system_health_monitoring_config.json new file mode 100644 index 00000000000..53b14bec17b --- /dev/null +++ b/device/accton/x86_64-accton_as5835_54t-r0/system_health_monitoring_config.json @@ -0,0 +1,17 @@ +{ + "services_to_ignore": [], + "devices_to_ignore": [ + "asic", + "psu.voltage", + "psu.temperature", + "PSU1_FAN1.speed", + "PSU2_FAN1.speed" + ], + "user_defined_checkers": [], + "polling_interval": 60, + "led_color": { + "fault": "STATUS_LED_COLOR_AMBER", + "normal": "STATUS_LED_COLOR_GREEN", + "booting": "STATUS_LED_COLOR_OFF" + } +} diff --git a/device/accton/x86_64-accton_as5835_54x-r0/installer.conf b/device/accton/x86_64-accton_as5835_54x-r0/installer.conf index 925a32fc0c3..40074bddd13 100644 --- a/device/accton/x86_64-accton_as5835_54x-r0/installer.conf +++ b/device/accton/x86_64-accton_as5835_54x-r0/installer.conf @@ -1,3 +1,4 @@ CONSOLE_PORT=0x3f8 CONSOLE_DEV=0 CONSOLE_SPEED=115200 +ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="modprobe.blacklist=i2c-ismt,i2c_ismt,i2c-i801,i2c_i801" diff --git a/device/accton/x86_64-accton_as5835_54x-r0/pddf/pd-plugin.json b/device/accton/x86_64-accton_as5835_54x-r0/pddf/pd-plugin.json new file mode 100644 index 00000000000..1b0deef952d --- /dev/null +++ b/device/accton/x86_64-accton_as5835_54x-r0/pddf/pd-plugin.json @@ -0,0 +1,66 @@ +{ + + "XCVR": + { + "xcvr_present": + { + "i2c": + { + "valmap-SFP28": {"1":true, "0":false }, + "valmap-QSFP28": {"1":true, "0":false} + } + } + }, + "PSU": + { + "psu_present": + { + "i2c": + { + "valmap": { "1":true, "0":false } + } + }, + + "psu_power_good": + { + "i2c": + { + "valmap": { "1": true, "0":false } + } + }, + + "psu_fan_dir": + { + "i2c": + { + "valmap": { "F2B":"EXHAUST", "B2F":"INTAKE" } + } + }, + + "PSU_FAN_MAX_SPEED":"18000" + }, + + "FAN": + { + "direction": + { + "i2c": + { + "valmap": {"1":"INTAKE", "0":"EXHAUST"} + } + }, + + "present": + { + "i2c": + { + "valmap": {"1":true, "0":false} + } + }, + + "duty_cycle_to_pwm": "lambda dc: (dc/5)", + + "pwm_to_duty_cycle": "lambda pwm: (pwm*5)" + } + +} diff --git a/device/accton/x86_64-accton_as5835_54x-r0/pddf/pddf-device.json b/device/accton/x86_64-accton_as5835_54x-r0/pddf/pddf-device.json new file mode 100644 index 00000000000..a97d4a472c1 --- /dev/null +++ b/device/accton/x86_64-accton_as5835_54x-r0/pddf/pddf-device.json @@ -0,0 +1,2814 @@ +{ + "PLATFORM": + { + "num_psus":2, + "num_fantrays":5, + "num_fans_pertray":2, + "num_ports":54, + "num_temps": 4, + "pddf_dev_types": + { + "description":"AS5835-54X - Below is the list of supported PDDF device types (chip names) for various components. If any component uses some other driver, we will create the client using 'echo > /new_device' method", + "CPLD": + [ + "i2c_cpld" + ], + "PSU": + [ + "psu_eeprom", + "psu_pmbus" + ], + "FAN": + [ + "fan_ctrl", + "fan_eeprom" + ], + "PORT_MODULE": + [ + "pddf_xcvr" + ] + }, + "std_kos": + [ + "i2c-i801", + "i2c-ismt", + "i2c_dev", + "i2c_mux_pca954x", + "optoe" + ], + "pddf_kos": + [ + "pddf_client_module", + "pddf_cpld_module", + "pddf_cpld_driver", + "pddf_mux_module", + "pddf_xcvr_module", + "pddf_xcvr_driver_module", + "pddf_psu_driver_module", + "pddf_psu_module", + "pddf_fan_driver_module", + "pddf_fan_module", + "pddf_led_module", + "pddf_sysstatus_module" + ], + "custom_kos": + [ + "pddf_custom_psu" + ] + + }, + + "SYSTEM": + { + "dev_info": {"device_type":"CPU", "device_name":"ROOT_COMPLEX", "device_parent":null}, + "i2c": + { + "CONTROLLERS": + [ + { "dev_name":"i2c-1", "dev":"SMBUS1" } + ] + } + }, + + "SMBUS1": + { + "dev_info": {"device_type": "SMBUS", "device_name": "SMBUS1", "device_parent": "SYSTEM"}, + "i2c": + { + "topo_info": {"dev_addr": "0x1"}, + "DEVICES": + [ + {"dev": "EEPROM1"}, + {"dev": "CPU_CPLD"}, + {"dev": "MUX1"} + ] + } + }, + + "EEPROM1": + { + "dev_info": {"device_type": "EEPROM", "device_name": "EEPROM1", "device_parent": "SMBUS1"}, + "i2c": + { + "topo_info": {"parent_bus": "0x1", "dev_addr": "0x57", "dev_type": "24c02"}, + "dev_attr": {"access_mode": "BLOCK"}, + "attr_list": [ + {"attr_name": "eeprom"} + ] + } + }, + + "CPU_CPLD": + { + "dev_info": { "device_type":"CPLD", "device_name":"CPU_CPLD", "device_parent":"SMBUS1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x1", "dev_addr":"0x65", "dev_type":"i2c_cpld"}, + "dev_attr": { } + } + }, + + "MUX1": + { + "dev_info": { "device_type":"MUX", "device_name":"MUX1", "device_parent":"SMBUS1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x1", "dev_addr":"0x77", "dev_type":"pca9548"}, + "dev_attr": { "virt_bus":"0x2"}, + "channel": + [ + { "chn":"0", "dev":"MUX2" }, + { "chn":"0", "dev":"MUX3" }, + { "chn":"0", "dev":"MUX4" }, + { "chn":"1", "dev":"CPLD1" }, + { "chn":"1", "dev":"CPLD2" }, + { "chn":"1", "dev":"CPLD3" }, + { "chn":"1", "dev":"FAN-CTRL" }, + { "chn":"1", "dev":"MUX5" } + ] + } + }, + "MUX2": + { + "dev_info": { "device_type":"MUX", "device_name":"MUX2", "device_parent":"MUX1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2", "dev_addr":"0x70", "dev_type":"pca9548"}, + "dev_attr": { "virt_bus":"0xa"}, + "channel": + [ + { "chn":"1", "dev":"PSU1" }, + { "chn":"2", "dev":"PSU2" } + ] + } + }, + + "PSU1": + { + "dev_info": { "device_type":"PSU", "device_name":"PSU1", "device_parent":"MUX2"}, + "dev_attr": { "dev_idx":"1", "num_psu_fans": "1"}, + "i2c": + { + "interface": + [ + { "itf":"pmbus", "dev":"PSU1-PMBUS" }, + { "itf":"eeprom", "dev":"PSU1-EEPROM" } + ] + } + }, + + "PSU1-PMBUS": + { + "dev_info": { "device_type":"PSU-PMBUS", "device_name":"PSU1-PMBUS", "device_parent":"MUX2", "virt_parent":"PSU1"}, + "i2c": + { + "topo_info":{ "parent_bus":"0xb", "dev_addr":"0x58", "dev_type":"psu_pmbus"}, + "attr_list": + [ + { "attr_name":"psu_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x2", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"psu_model_name", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x9a", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"10" }, + { "attr_name":"psu_power_good", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x2", "attr_mask":"0x2", "attr_cmpval":"0x2", "attr_len":"1"}, + { "attr_name":"psu_mfr_id", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0X99", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"10" }, + { "attr_name":"psu_fan_dir", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0xc3", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"5"}, + { "attr_name":"psu_v_out", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x8b", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_i_out", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x8c", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_p_out", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x96", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_fan1_speed_rpm", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x90", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"} + ] + } + }, + + "PSU1-EEPROM": + { + "dev_info": { "device_type":"PSU-EEPROM", "device_name":"PSU1-EEPROM", "device_parent":"MUX2", "virt_parent":"PSU1"}, + "i2c": + { + "topo_info":{ "parent_bus":"0xb", "dev_addr":"0x50", "dev_type":"psu_eeprom"}, + "attr_list": + [ + { "attr_name":"psu_serial_num", "attr_devaddr":"0x50", "attr_devtype":"eeprom", "attr_offset":"0x35", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"19" } + ] + } + }, + + "PSU2": + { + "dev_info": { "device_type":"PSU", "device_name":"PSU2", "device_parent":"MUX2" }, + "dev_attr": { "dev_idx":"2", "num_psu_fans":"1"}, + "i2c": + { + "interface": + [ + { "itf":"pmbus", "dev":"PSU2-PMBUS"}, + { "itf":"eeprom", "dev":"PSU2-EEPROM" } + ] + } + }, + + "PSU2-PMBUS": + { + "dev_info": {"device_type":"PSU-PMBUS", "device_name":"PSU2-PMBUS", "device_parent":"MUX2", "virt_parent":"PSU2"}, + "i2c": + { + "topo_info": { "parent_bus":"0xc", "dev_addr":"0x5b", "dev_type":"psu_pmbus"}, + "attr_list": + [ + { "attr_name":"psu_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x2", "attr_mask":"0x10", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"psu_model_name", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x9a", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"10" }, + { "attr_name":"psu_power_good", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x2", "attr_mask":"0x20", "attr_cmpval":"0x20", "attr_len":"1"}, + { "attr_name":"psu_mfr_id", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0X99", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"10" }, + { "attr_name":"psu_fan_dir", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0xc3", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"5"}, + { "attr_name":"psu_v_out", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x8b", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_i_out", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x8c", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_p_out", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x96", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_fan1_speed_rpm", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x90", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"} + ] + } + }, + + "PSU2-EEPROM": + { + "dev_info": { "device_type":"PSU-EEPROM", "device_name":"PSU2-EEPROM", "device_parent":"MUX2", "virt_parent":"PSU2"}, + "i2c": + { + "topo_info":{ "parent_bus":"0xc", "dev_addr":"0x53", "dev_type":"psu_eeprom"}, + "attr_list": + [ + { "attr_name":"psu_serial_num", "attr_devaddr":"0x53", "attr_devtype":"eeprom", "attr_offset":"0x35", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"19" } + ] + } + }, + "MUX3": + { + "dev_info": { "device_type":"MUX", "device_name":"MUX3", "device_parent":"MUX1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2", "dev_addr":"0x72", "dev_type":"pca9548"}, + "dev_attr": { "virt_bus":"0x12"}, + "channel": + [ + { "chn":"0", "dev":"PORT51" }, + { "chn":"1", "dev":"PORT54" }, + { "chn":"2", "dev":"PORT49" }, + { "chn":"3", "dev":"PORT50" }, + { "chn":"4", "dev":"PORT52" }, + { "chn":"5", "dev":"PORT53" } + ] + } + }, + + "PORT51": + { + "dev_info": { "device_type":"QSFP28", "device_name":"PORT51", "device_parent":"MUX3"}, + "dev_attr": { "dev_idx":"51"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT51-EEPROM" }, + { "itf":"control", "dev":"PORT51-CTRL" } + ] + } + }, + "PORT51-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT51-EEPROM", "device_parent":"MUX3", "virt_parent":"PORT51"}, + "i2c": + { + "topo_info": { "parent_bus":"0x12", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT51-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT51-CTRL", "device_parent":"MUX3", "virt_parent":"PORT51"}, + "i2c": + { + "topo_info": { "parent_bus":"0x12", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x14", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3","attr_offset":"0x15", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3","attr_offset":"0x13", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_lpmode", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x16", "attr_mask":"0x2", "attr_cmpval":"0x4", "attr_len":"1"} + ] + } + }, + + "PORT54": + { + "dev_info": { "device_type":"QSFP28", "device_name":"PORT54", "device_parent":"MUX3"}, + "dev_attr": { "dev_idx":"54"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT54-EEPROM" }, + { "itf":"control", "dev":"PORT54-CTRL" } + ] + } + }, + "PORT54-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT54-EEPROM", "device_parent":"MUX3", "virt_parent":"PORT54"}, + "i2c": + { + "topo_info": { "parent_bus":"0x13", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT54-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT54-CTRL", "device_parent":"MUX3", "virt_parent":"PORT54"}, + "i2c": + { + "topo_info": { "parent_bus":"0x13", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3","attr_offset":"0x14", "attr_mask":"0x5", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3","attr_offset":"0x15", "attr_mask":"0x5", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3","attr_offset":"0x13", "attr_mask":"0x5", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_lpmode", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x16", "attr_mask":"0x5", "attr_cmpval":"0x20", "attr_len":"1"} + ] + } + }, + + "PORT49": + { + "dev_info": { "device_type":"QSFP28", "device_name":"PORT49", "device_parent":"MUX3"}, + "dev_attr": { "dev_idx":"49"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT49-EEPROM" }, + { "itf":"control", "dev":"PORT49-CTRL" } + ] + } + }, + "PORT49-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT49-EEPROM", "device_parent":"MUX3", "virt_parent":"PORT49"}, + "i2c": + { + "topo_info": { "parent_bus":"0x14", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT49-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT49-CTRL", "device_parent":"MUX3", "virt_parent":"PORT49"}, + "i2c": + { + "topo_info": { "parent_bus":"0x14", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x14", "attr_mask":"0x0", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x15", "attr_mask":"0x0", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x13", "attr_mask":"0x0", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_lpmode", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x16", "attr_mask":"0x0", "attr_cmpval":"0x1", "attr_len":"1"} + ] + } + }, + + "PORT50": + { + "dev_info": { "device_type":"QSFP28", "device_name":"PORT50", "device_parent":"MUX3"}, + "dev_attr": { "dev_idx":"50"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT50-EEPROM" }, + { "itf":"control", "dev":"PORT50-CTRL" } + ] + } + }, + "PORT50-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT50-EEPROM", "device_parent":"MUX3", "virt_parent":"PORT50"}, + "i2c": + { + "topo_info": { "parent_bus":"0x15", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + + "PORT50-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT50-CTRL", "device_parent":"MUX3", "virt_parent":"PORT50"}, + "i2c": + { + "topo_info": { "parent_bus":"0x15", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x14", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x15", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x13", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_lpmode", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3","attr_offset":"0x16", "attr_mask":"0x1", "attr_cmpval":"0x2", "attr_len":"1"} + ] + } + }, + + "PORT52": + { + "dev_info": { "device_type":"QSFP28", "device_name":"PORT52", "device_parent":"MUX3"}, + "dev_attr": { "dev_idx":"52"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT52-EEPROM" }, + { "itf":"control", "dev":"PORT52-CTRL" } + ] + } + }, + "PORT52-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT52-EEPROM", "device_parent":"MUX3", "virt_parent":"PORT52"}, + "i2c": + { + "topo_info": { "parent_bus":"0x16", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT52-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT52-CTRL", "device_parent":"MUX3", "virt_parent":"PORT52"}, + "i2c": + { + "topo_info": { "parent_bus":"0x16", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x14", "attr_mask":"0x3", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x15", "attr_mask":"0x3", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x62", "attr_devtype":"cpld","attr_devname":"CPLD3", "attr_offset":"0x13", "attr_mask":"0x3", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_lpmode", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x16", "attr_mask":"0x3", "attr_cmpval":"0x8", "attr_len":"1"} + ] + } + }, + + "PORT53": + { + "dev_info": { "device_type":"QSFP28", "device_name":"PORT53", "device_parent":"MUX3"}, + "dev_attr": { "dev_idx":"53"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT53-EEPROM" }, + { "itf":"control", "dev":"PORT53-CTRL" } + ] + } + }, + "PORT53-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT53-EEPROM", "device_parent":"MUX3", "virt_parent":"PORT53"}, + "i2c": + { + "topo_info": { "parent_bus":"0x17", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT53-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT53-CTRL", "device_parent":"MUX3", "virt_parent":"PORT53"}, + "i2c": + { + "topo_info": { "parent_bus":"0x17", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3","attr_offset":"0x14", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x15", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x62", "attr_devtype":"cpld","attr_devname":"CPLD3", "attr_offset":"0x13", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_lpmode", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3","attr_offset":"0x16", "attr_mask":"0x4", "attr_cmpval":"0x10", "attr_len":"1"} + ] + } + }, + + + "CPLD1": + { + "dev_info": { "device_type":"CPLD", "device_name":"CPLD1", "device_parent":"MUX1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x3", "dev_addr":"0x60", "dev_type":"i2c_cpld"}, + "dev_attr":{} + } + }, + "CPLD2": + { + "dev_info": { "device_type":"CPLD", "device_name":"CPLD2", "device_parent":"MUX1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x3", "dev_addr":"0x61", "dev_type":"i2c_cpld"}, + "dev_attr":{} + } + }, + "CPLD3": + { + "dev_info": { "device_type":"CPLD", "device_name":"CPLD3", "device_parent":"MUX1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x3", "dev_addr":"0x62", "dev_type":"i2c_cpld"}, + "dev_attr":{} + } + }, + + "FAN-CTRL": + { + "dev_info": { "device_type":"FAN", "device_name":"FAN-CTRL", "device_parent":"MUX1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x3", "dev_addr":"0x63", "dev_type":"fan_ctrl"}, + "dev_attr": { "num_fantrays":"5"}, + "attr_list": + [ + { "attr_name":"fan1_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x02", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan2_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x02", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan3_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x02", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan4_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x02", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan5_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x02", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan6_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x02", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan7_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x02", "attr_mask":"0x8", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan8_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x02", "attr_mask":"0x8", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan9_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x02", "attr_mask":"0x10", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan10_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x02","attr_mask":"0x10", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan1_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x03", "attr_mask":"0x1", "attr_cmpval":"0x1", "attr_len":"1"}, + { "attr_name":"fan2_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x03", "attr_mask":"0x1", "attr_cmpval":"0x1", "attr_len":"1"}, + { "attr_name":"fan3_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x03", "attr_mask":"0x2", "attr_cmpval":"0x2", "attr_len":"1"}, + { "attr_name":"fan4_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x03", "attr_mask":"0x2", "attr_cmpval":"0x2", "attr_len":"1"}, + { "attr_name":"fan5_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x03", "attr_mask":"0x4", "attr_cmpval":"0x4", "attr_len":"1"}, + { "attr_name":"fan6_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x03", "attr_mask":"0x4", "attr_cmpval":"0x4", "attr_len":"1"}, + { "attr_name":"fan7_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x03", "attr_mask":"0x8", "attr_cmpval":"0x8", "attr_len":"1"}, + { "attr_name":"fan8_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x03", "attr_mask":"0x8", "attr_cmpval":"0x8", "attr_len":"1"}, + { "attr_name":"fan9_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x03", "attr_mask":"0x10", "attr_cmpval":"0x10", "attr_len":"1"}, + { "attr_name":"fan10_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x03", "attr_mask":"0x10", "attr_cmpval":"0x10", "attr_len":"1"}, + { "attr_name":"fan1_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x07", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"150", "attr_is_divisor":0}, + { "attr_name":"fan2_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x0C", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"150", "attr_is_divisor":0}, + { "attr_name":"fan3_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x08", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"150", "attr_is_divisor":0}, + { "attr_name":"fan4_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x0D", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"150", "attr_is_divisor":0}, + { "attr_name":"fan5_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x09", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"150", "attr_is_divisor":0}, + { "attr_name":"fan6_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x0E", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"150", "attr_is_divisor":0}, + { "attr_name":"fan7_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x0A", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"150" , "attr_is_divisor":0}, + { "attr_name":"fan8_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x0F", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"150" , "attr_is_divisor":0}, + { "attr_name":"fan9_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x0B", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"150" , "attr_is_divisor":0}, + { "attr_name":"fan10_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x10", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"150" , "attr_is_divisor":0}, + { "attr_name":"fan1_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x06", "attr_mask":"0x1F", "attr_len":"1" }, + { "attr_name":"fan2_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x06", "attr_mask":"0x1F", "attr_len":"1" }, + { "attr_name":"fan3_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x06", "attr_mask":"0x1F", "attr_len":"1" }, + { "attr_name":"fan4_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x06", "attr_mask":"0x1F", "attr_len":"1" }, + { "attr_name":"fan5_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x06", "attr_mask":"0x1F", "attr_len":"1" }, + { "attr_name":"fan6_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x06", "attr_mask":"0x1F", "attr_len":"1" }, + { "attr_name":"fan7_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x06", "attr_mask":"0x1F", "attr_len":"1" }, + { "attr_name":"fan8_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x06", "attr_mask":"0x1F", "attr_len":"1" }, + { "attr_name":"fan9_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x06", "attr_mask":"0x1F", "attr_len":"1" }, + { "attr_name":"fan10_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x06", "attr_mask":"0x1F", "attr_len":"1" } + ] + } + }, + + "MUX4": + { + "dev_info": { "device_type":"MUX", "device_name":"MUX4", "device_parent":"MUX1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2", "dev_addr":"0x71", "dev_type":"pca9548"}, + "dev_attr": { "virt_bus":"0x1a"}, + "channel": + [ + { "chn":"0", "dev":"TEMP1" }, + { "chn":"1", "dev":"TEMP2" }, + { "chn":"2", "dev":"TEMP3" }, + { "chn":"3", "dev":"TEMP4" } + ] + } + }, + + "TEMP1" : + { + "dev_info": { "device_type":"TEMP_SENSOR", "device_name":"TEMP1", "device_parent":"MUX4"}, + "i2c": + { + "topo_info": { "parent_bus":"0x1a", "dev_addr":"0x4B", "dev_type":"lm75"}, + "attr_list": + [ + { "attr_name": "temp1_high_threshold", "drv_attr_name":"temp1_max"}, + { "attr_name": "temp1_max_hyst"}, + { "attr_name": "temp1_input"} + ] + } + }, + "TEMP2" : + { + "dev_info": { "device_type":"TEMP_SENSOR", "device_name":"TEMP2", "device_parent":"MUX4"}, + "i2c": + { + "topo_info": { "parent_bus":"0x1b", "dev_addr":"0x4C", "dev_type":"lm75"}, + "attr_list": + [ + { "attr_name": "temp1_high_threshold", "drv_attr_name":"temp1_max"}, + { "attr_name": "temp1_max_hyst"}, + { "attr_name": "temp1_input"} + ] + } + }, + "TEMP3" : + { + "dev_info": { "device_type":"TEMP_SENSOR", "device_name":"TEMP3", "device_parent":"MUX4"}, + "i2c": + { + "topo_info": { "parent_bus":"0x1c", "dev_addr":"0x49", "dev_type":"lm75"}, + "attr_list": + [ + { "attr_name": "temp1_high_threshold", "drv_attr_name":"temp1_max"}, + { "attr_name": "temp1_max_hyst"}, + { "attr_name": "temp1_input"} + ] + } + }, + "TEMP4" : + { + "dev_info": { "device_type":"TEMP_SENSOR", "device_name":"TEMP4", "device_parent":"MUX4"}, + "i2c": + { + "topo_info": { "parent_bus":"0x1d", "dev_addr":"0x4A", "dev_type":"lm75"}, + "attr_list": + [ + { "attr_name": "temp1_high_threshold", "drv_attr_name":"temp1_max"}, + { "attr_name": "temp1_max_hyst"}, + { "attr_name": "temp1_input"} + ] + } + }, + + "SYSSTATUS": + { + "dev_info":{ "device_type":"SYSSTAT", "device_name":"SYSSTATUS"}, + "dev_attr":{ }, + "attr_list": + [ + + { "attr_name":"board_info","attr_devaddr":"0x60", "attr_offset":"0x0","attr_mask":"0xff","attr_len":"0x1"}, + { "attr_name":"cpld1_version","attr_devaddr":"0x60","attr_offset":"0x1","attr_mask":"0xff","attr_len":"0x1"}, + { "attr_name":"cpld2_version","attr_devaddr":"0x61","attr_offset":"0x1","attr_mask":"0xff","attr_len":"0x1"}, + { "attr_name":"cpld3version","attr_devaddr":"0x62","attr_offset":"0x1","attr_mask":"0xff","attr_len":"0x1"}, + { "attr_name":"fan_cpld_version","attr_devaddr":"0x63","attr_offset":"0x1","attr_mask":"0xff","attr_len":"0x1"} + + ] + }, + + "MUX5": + { + "dev_info": { "device_type":"MUX", "device_name":"MUX5", "device_parent":"MUX1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x3", "dev_addr":"0x70", "dev_type":"pca9548"}, + "dev_attr": { "virt_bus":"0x22"}, + "channel": + [ + { "chn":"0", "dev":"MUX6" }, + { "chn":"1", "dev":"MUX7" }, + { "chn":"2", "dev":"MUX8" }, + { "chn":"3", "dev":"MUX9" }, + { "chn":"4", "dev":"MUX10" }, + { "chn":"5", "dev":"MUX11" } + ] + } + }, + "MUX6": + { + "dev_info": { "device_type":"MUX", "device_name":"MUX6", "device_parent":"MUX5"}, + "i2c": + { + "topo_info": { "parent_bus":"0x22", "dev_addr":"0x71", "dev_type":"pca9548"}, + "dev_attr": { "virt_bus":"0x2a"}, + "channel": + [ + { "chn":"0", "dev":"PORT1" }, + { "chn":"1", "dev":"PORT2" }, + { "chn":"2", "dev":"PORT3" }, + { "chn":"3", "dev":"PORT4" }, + { "chn":"4", "dev":"PORT5" }, + { "chn":"5", "dev":"PORT6" }, + { "chn":"6", "dev":"PORT7" }, + { "chn":"7", "dev":"PORT8" } + ] + } + }, + "MUX7": + { + "dev_info": { "device_type":"MUX", "device_name":"MUX7", "device_parent":"MUX5"}, + "i2c": + { + "topo_info": { "parent_bus":"0x23", "dev_addr":"0x72", "dev_type":"pca9548"}, + "dev_attr": { "virt_bus":"0x32"}, + "channel": + [ + { "chn":"0", "dev":"PORT9" }, + { "chn":"1", "dev":"PORT10" }, + { "chn":"2", "dev":"PORT11" }, + { "chn":"3", "dev":"PORT12" }, + { "chn":"4", "dev":"PORT13" }, + { "chn":"5", "dev":"PORT14" }, + { "chn":"6", "dev":"PORT15" }, + { "chn":"7", "dev":"PORT16" } + ] + } + }, + "MUX8": + { + "dev_info": { "device_type":"MUX", "device_name":"MUX8", "device_parent":"MUX5"}, + "i2c": + { + "topo_info": { "parent_bus":"0x24", "dev_addr":"0x73", "dev_type":"pca9548"}, + "dev_attr": { "virt_bus":"0x3a"}, + "channel": + [ + { "chn":"0", "dev":"PORT17" }, + { "chn":"1", "dev":"PORT18" }, + { "chn":"2", "dev":"PORT19" }, + { "chn":"3", "dev":"PORT20" }, + { "chn":"4", "dev":"PORT21" }, + { "chn":"5", "dev":"PORT22" }, + { "chn":"6", "dev":"PORT23" }, + { "chn":"7", "dev":"PORT24" } + ] + } + }, + "MUX9": + { + "dev_info": { "device_type":"MUX", "device_name":"MUX9", "device_parent":"MUX5"}, + "i2c": + { + "topo_info": { "parent_bus":"0x25", "dev_addr":"0x74", "dev_type":"pca9548"}, + "dev_attr": { "virt_bus":"0x42"}, + "channel": + [ + { "chn":"0", "dev":"PORT25" }, + { "chn":"1", "dev":"PORT26" }, + { "chn":"2", "dev":"PORT27" }, + { "chn":"3", "dev":"PORT28" }, + { "chn":"4", "dev":"PORT29" }, + { "chn":"5", "dev":"PORT30" }, + { "chn":"6", "dev":"PORT31" }, + { "chn":"7", "dev":"PORT32" } + ] + } + }, + "MUX10": + { + "dev_info": { "device_type":"MUX", "device_name":"MUX10", "device_parent":"MUX5"}, + "i2c": + { + "topo_info": { "parent_bus":"0x26", "dev_addr":"0x75", "dev_type":"pca9548"}, + "dev_attr": { "virt_bus":"0x4a"}, + "channel": + [ + { "chn":"0", "dev":"PORT33" }, + { "chn":"1", "dev":"PORT34" }, + { "chn":"2", "dev":"PORT35" }, + { "chn":"3", "dev":"PORT36" }, + { "chn":"4", "dev":"PORT37" }, + { "chn":"5", "dev":"PORT38" }, + { "chn":"6", "dev":"PORT39" }, + { "chn":"7", "dev":"PORT40" } + ] + } + }, + "MUX11": + { + "dev_info": { "device_type":"MUX", "device_name":"MUX11", "device_parent":"MUX5"}, + "i2c": + { + "topo_info": { "parent_bus":"0x27", "dev_addr":"0x76", "dev_type":"pca9548"}, + "dev_attr": { "virt_bus":"0x52"}, + "channel": + [ + { "chn":"0", "dev":"PORT41" }, + { "chn":"1", "dev":"PORT42" }, + { "chn":"2", "dev":"PORT43" }, + { "chn":"3", "dev":"PORT44" }, + { "chn":"4", "dev":"PORT45" }, + { "chn":"5", "dev":"PORT46" }, + { "chn":"6", "dev":"PORT47" }, + { "chn":"7", "dev":"PORT48" } + ] + } + }, + + "PORT1": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT1", "device_parent":"MUX6"}, + "dev_attr": { "dev_idx":"1"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT1-EEPROM" }, + { "itf":"control", "dev":"PORT1-CTRL" } + ] + } + }, + "PORT1-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT1-EEPROM", "device_parent":"MUX6", "virt_parent":"PORT1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2a", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT1-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT1-CTRL", "device_parent":"MUX6", "virt_parent":"PORT1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2a", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x8", "attr_mask":"0x0", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0D", "attr_mask":"0x0", "attr_cmpval":"0x1", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x12", "attr_mask":"0x0", "attr_cmpval":"0x1", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x17", "attr_mask":"0x0", "attr_cmpval":"0x1", "attr_len":"1"} + ] + } + }, + + "PORT2": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT2", "device_parent":"MUX6"}, + "dev_attr": { "dev_idx":"2"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT2-EEPROM" }, + { "itf":"control", "dev":"PORT2-CTRL" } + ] + } + }, + "PORT2-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT2-EEPROM", "device_parent":"MUX6", "virt_parent":"PORT2"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2b", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT2-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT2-CTRL", "device_parent":"MUX6", "virt_parent":"PORT2"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2b", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x8", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0D", "attr_mask":"0x1", "attr_cmpval":"0x2", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x12", "attr_mask":"0x1", "attr_cmpval":"0x2", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x17", "attr_mask":"0x1", "attr_cmpval":"0x2", "attr_len":"1"} + ] + } + }, + + "PORT3": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT3", "device_parent":"MUX6"}, + "dev_attr": { "dev_idx":"3"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT3-EEPROM" }, + { "itf":"control", "dev":"PORT3-CTRL" } + ] + } + }, + "PORT3-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT3-EEPROM", "device_parent":"MUX6", "virt_parent":"PORT3"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2c", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT3-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT3-CTRL", "device_parent":"MUX6", "virt_parent":"PORT3"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2c", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x8", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0D", "attr_mask":"0x2", "attr_cmpval":"0x4", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x12", "attr_mask":"0x2", "attr_cmpval":"0x4", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x17", "attr_mask":"0x2", "attr_cmpval":"0x4", "attr_len":"1"} + ] + } + }, + + "PORT4": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT4", "device_parent":"MUX6"}, + "dev_attr": { "dev_idx":"4"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT4-EEPROM" }, + { "itf":"control", "dev":"PORT4-CTRL" } + ] + } + }, + "PORT4-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT4-EEPROM", "device_parent":"MUX6", "virt_parent":"PORT4"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2d", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT4-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT4-CTRL", "device_parent":"MUX6", "virt_parent":"PORT4"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2d", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x8", "attr_mask":"0x3", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0D", "attr_mask":"0x3", "attr_cmpval":"0x8", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x12", "attr_mask":"0x3", "attr_cmpval":"0x8", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x17", "attr_mask":"0x3", "attr_cmpval":"0x8", "attr_len":"1"} + ] + } + }, + + "PORT5": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT5", "device_parent":"MUX6"}, + "dev_attr": { "dev_idx":"5"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT5-EEPROM" }, + { "itf":"control", "dev":"PORT5-CTRL" } + ] + } + }, + "PORT5-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT5-EEPROM", "device_parent":"MUX6", "virt_parent":"PORT5"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2e", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT5-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT5-CTRL", "device_parent":"MUX6", "virt_parent":"PORT5"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2e", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x8", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0D", "attr_mask":"0x4", "attr_cmpval":"0x10", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x12", "attr_mask":"0x4", "attr_cmpval":"0x10", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x17", "attr_mask":"0x4", "attr_cmpval":"0x10", "attr_len":"1"} + ] + } + }, + + "PORT6": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT6", "device_parent":"MUX6"}, + "dev_attr": { "dev_idx":"6"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT6-EEPROM" }, + { "itf":"control", "dev":"PORT6-CTRL" } + ] + } + }, + "PORT6-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT6-EEPROM", "device_parent":"MUX6", "virt_parent":"PORT6"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2f", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT6-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT6-CTRL", "device_parent":"MUX6", "virt_parent":"PORT6"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2f", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x8", "attr_mask":"0x5", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0D", "attr_mask":"0x5", "attr_cmpval":"0x20", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x12", "attr_mask":"0x5", "attr_cmpval":"0x20", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x17", "attr_mask":"0x5", "attr_cmpval":"0x20", "attr_len":"1"} + ] + } + }, + + "PORT7": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT7", "device_parent":"MUX6"}, + "dev_attr": { "dev_idx":"7"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT7-EEPROM" }, + { "itf":"control", "dev":"PORT7-CTRL" } + ] + } + }, + "PORT7-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT7-EEPROM", "device_parent":"MUX6", "virt_parent":"PORT7"}, + "i2c": + { + "topo_info": { "parent_bus":"0x30", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT7-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT7-CTRL", "device_parent":"MUX6", "virt_parent":"PORT7"}, + "i2c": + { + "topo_info": { "parent_bus":"0x30", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x8", "attr_mask":"0x6", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0D", "attr_mask":"0x6", "attr_cmpval":"0x40", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x12", "attr_mask":"0x6", "attr_cmpval":"0x40", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x17", "attr_mask":"0x6", "attr_cmpval":"0x40", "attr_len":"1"} + ] + } + }, + + "PORT8": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT8", "device_parent":"MUX6"}, + "dev_attr": { "dev_idx":"8"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT8-EEPROM" }, + { "itf":"control", "dev":"PORT8-CTRL" } + ] + } + }, + "PORT8-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT8-EEPROM", "device_parent":"MUX6", "virt_parent":"PORT8"}, + "i2c": + { + "topo_info": { "parent_bus":"0x31", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT8-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT8-CTRL", "device_parent":"MUX6", "virt_parent":"PORT8"}, + "i2c": + { + "topo_info": { "parent_bus":"0x31", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x8", "attr_mask":"0x7", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0D", "attr_mask":"0x7", "attr_cmpval":"0x80", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x12", "attr_mask":"0x7", "attr_cmpval":"0x80", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x17", "attr_mask":"0x7", "attr_cmpval":"0x80", "attr_len":"1"} + ] + } + }, + + "PORT9": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT9", "device_parent":"MUX7"}, + "dev_attr": { "dev_idx":"9"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT9-EEPROM" }, + { "itf":"control", "dev":"PORT9-CTRL" } + ] + } + }, + "PORT9-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT9-EEPROM", "device_parent":"MUX7", "virt_parent":"PORT9"}, + "i2c": + { + "topo_info": { "parent_bus":"0x32", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT9-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT9-CTRL", "device_parent":"MUX7", "virt_parent":"PORT9"}, + "i2c": + { + "topo_info": { "parent_bus":"0x32", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x09", "attr_mask":"0x0", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0E", "attr_mask":"0x0", "attr_cmpval":"0x1", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x13", "attr_mask":"0x0", "attr_cmpval":"0x1", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x18", "attr_mask":"0x0", "attr_cmpval":"0x1", "attr_len":"1"} + ] + } + }, + + "PORT10": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT10", "device_parent":"MUX7"}, + "dev_attr": { "dev_idx":"10"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT10-EEPROM" }, + { "itf":"control", "dev":"PORT10-CTRL" } + ] + } + }, + "PORT10-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT10-EEPROM", "device_parent":"MUX7", "virt_parent":"PORT10"}, + "i2c": + { + "topo_info": { "parent_bus":"0x33", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT10-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT10-CTRL", "device_parent":"MUX7", "virt_parent":"PORT10"}, + "i2c": + { + "topo_info": { "parent_bus":"0x33", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x09", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0E", "attr_mask":"0x1", "attr_cmpval":"0x2", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x13", "attr_mask":"0x1", "attr_cmpval":"0x2", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x18", "attr_mask":"0x1", "attr_cmpval":"0x2", "attr_len":"1"} + ] + } + }, + + "PORT11": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT11", "device_parent":"MUX7"}, + "dev_attr": { "dev_idx":"11"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT11-EEPROM" }, + { "itf":"control", "dev":"PORT11-CTRL" } + ] + } + }, + "PORT11-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT11-EEPROM", "device_parent":"MUX7", "virt_parent":"PORT11"}, + "i2c": + { + "topo_info": { "parent_bus":"0x34", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT11-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT11-CTRL", "device_parent":"MUX7", "virt_parent":"PORT11"}, + "i2c": + { + "topo_info": { "parent_bus":"0x34", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x09", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0E", "attr_mask":"0x2", "attr_cmpval":"0x4", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x13", "attr_mask":"0x2", "attr_cmpval":"0x4", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x18", "attr_mask":"0x2", "attr_cmpval":"0x4", "attr_len":"1"} + ] + } + }, + + "PORT12": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT12", "device_parent":"MUX7"}, + "dev_attr": { "dev_idx":"12"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT12-EEPROM" }, + { "itf":"control", "dev":"PORT12-CTRL" } + ] + } + }, + "PORT12-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT12-EEPROM", "device_parent":"MUX7", "virt_parent":"PORT12"}, + "i2c": + { + "topo_info": { "parent_bus":"0x35", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT12-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT12-CTRL", "device_parent":"MUX7", "virt_parent":"PORT12"}, + "i2c": + { + "topo_info": { "parent_bus":"0x35", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x09", "attr_mask":"0x3", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0E", "attr_mask":"0x3", "attr_cmpval":"0x8", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x13", "attr_mask":"0x3", "attr_cmpval":"0x8", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x18", "attr_mask":"0x3", "attr_cmpval":"0x8", "attr_len":"1"} + ] + } + }, + + "PORT13": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT13", "device_parent":"MUX7"}, + "dev_attr": { "dev_idx":"13"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT13-EEPROM" }, + { "itf":"control", "dev":"PORT13-CTRL" } + ] + } + }, + "PORT13-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT13-EEPROM", "device_parent":"MUX7", "virt_parent":"PORT13"}, + "i2c": + { + "topo_info": { "parent_bus":"0x36", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT13-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT13-CTRL", "device_parent":"MUX7", "virt_parent":"PORT13"}, + "i2c": + { + "topo_info": { "parent_bus":"0x36", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x09", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0E", "attr_mask":"0x4", "attr_cmpval":"0x10", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x13", "attr_mask":"0x4", "attr_cmpval":"0x10", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x18", "attr_mask":"0x4", "attr_cmpval":"0x10", "attr_len":"1"} + ] + } + }, + + "PORT14": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT14", "device_parent":"MUX7"}, + "dev_attr": { "dev_idx":"14"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT14-EEPROM" }, + { "itf":"control", "dev":"PORT14-CTRL" } + ] + } + }, + "PORT14-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT14-EEPROM", "device_parent":"MUX7", "virt_parent":"PORT14"}, + "i2c": + { + "topo_info": { "parent_bus":"0x37", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT14-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT14-CTRL", "device_parent":"MUX7", "virt_parent":"PORT14"}, + "i2c": + { + "topo_info": { "parent_bus":"0x37", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x09", "attr_mask":"0x5", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0E", "attr_mask":"0x5", "attr_cmpval":"0x20", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x13", "attr_mask":"0x5", "attr_cmpval":"0x20", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x18", "attr_mask":"0x5", "attr_cmpval":"0x20", "attr_len":"1"} + ] + } + }, + + "PORT15": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT15", "device_parent":"MUX7"}, + "dev_attr": { "dev_idx":"15"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT15-EEPROM" }, + { "itf":"control", "dev":"PORT15-CTRL" } + ] + } + }, + "PORT15-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT15-EEPROM", "device_parent":"MUX7", "virt_parent":"PORT15"}, + "i2c": + { + "topo_info": { "parent_bus":"0x38", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT15-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT15-CTRL", "device_parent":"MUX7", "virt_parent":"PORT15"}, + "i2c": + { + "topo_info": { "parent_bus":"0x38", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x09", "attr_mask":"0x6", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0E", "attr_mask":"0x6", "attr_cmpval":"0x40", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x13", "attr_mask":"0x6", "attr_cmpval":"0x40", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x18", "attr_mask":"0x6", "attr_cmpval":"0x40", "attr_len":"1"} + ] + } + }, + + "PORT16": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT16", "device_parent":"MUX7"}, + "dev_attr": { "dev_idx":"16"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT16-EEPROM" }, + { "itf":"control", "dev":"PORT16-CTRL" } + ] + } + }, + "PORT16-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT16-EEPROM", "device_parent":"MUX7", "virt_parent":"PORT16"}, + "i2c": + { + "topo_info": { "parent_bus":"0x39", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT16-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT16-CTRL", "device_parent":"MUX7", "virt_parent":"PORT16"}, + "i2c": + { + "topo_info": { "parent_bus":"0x39", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x09", "attr_mask":"0x7", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0E", "attr_mask":"0x7", "attr_cmpval":"0x80", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x13", "attr_mask":"0x7", "attr_cmpval":"0x80", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x18", "attr_mask":"0x7", "attr_cmpval":"0x80", "attr_len":"1"} + ] + } + }, + + "PORT17": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT17", "device_parent":"MUX8"}, + "dev_attr": { "dev_idx":"17"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT17-EEPROM" }, + { "itf":"control", "dev":"PORT17-CTRL" } + ] + } + }, + "PORT17-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT17-EEPROM", "device_parent":"MUX8", "virt_parent":"PORT17"}, + "i2c": + { + "topo_info": { "parent_bus":"0x3a", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT17-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT17-CTRL", "device_parent":"MUX8", "virt_parent":"PORT17"}, + "i2c": + { + "topo_info": { "parent_bus":"0x3a", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0A", "attr_mask":"0x0", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0F", "attr_mask":"0x0", "attr_cmpval":"0x1", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x14", "attr_mask":"0x0", "attr_cmpval":"0x1", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x19", "attr_mask":"0x0", "attr_cmpval":"0x1", "attr_len":"1"} + ] + } + }, + + "PORT18": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT18", "device_parent":"MUX8"}, + "dev_attr": { "dev_idx":"18"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT18-EEPROM" }, + { "itf":"control", "dev":"PORT18-CTRL" } + ] + } + }, + "PORT18-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT18-EEPROM", "device_parent":"MUX8", "virt_parent":"PORT18"}, + "i2c": + { + "topo_info": { "parent_bus":"0x3b", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT18-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT18-CTRL", "device_parent":"MUX8", "virt_parent":"PORT18"}, + "i2c": + { + "topo_info": { "parent_bus":"0x3b", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0A", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0F", "attr_mask":"0x1", "attr_cmpval":"0x2", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x14", "attr_mask":"0x1", "attr_cmpval":"0x2", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x19", "attr_mask":"0x1", "attr_cmpval":"0x2", "attr_len":"1"} + ] + } + }, + + "PORT19": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT19", "device_parent":"MUX8"}, + "dev_attr": { "dev_idx":"19"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT19-EEPROM" }, + { "itf":"control", "dev":"PORT19-CTRL" } + ] + } + }, + "PORT19-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT19-EEPROM", "device_parent":"MUX8", "virt_parent":"PORT19"}, + "i2c": + { + "topo_info": { "parent_bus":"0x3c", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT19-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT19-CTRL", "device_parent":"MUX8", "virt_parent":"PORT19"}, + "i2c": + { + "topo_info": { "parent_bus":"0x3c", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0A", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0F", "attr_mask":"0x2", "attr_cmpval":"0x4", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x14", "attr_mask":"0x2", "attr_cmpval":"0x4", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x19", "attr_mask":"0x2", "attr_cmpval":"0x4", "attr_len":"1"} + ] + } + }, + + "PORT20": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT20", "device_parent":"MUX8"}, + "dev_attr": { "dev_idx":"20"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT20-EEPROM" }, + { "itf":"control", "dev":"PORT20-CTRL" } + ] + } + }, + "PORT20-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT20-EEPROM", "device_parent":"MUX8", "virt_parent":"PORT20"}, + "i2c": + { + "topo_info": { "parent_bus":"0x3d", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT20-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT20-CTRL", "device_parent":"MUX8", "virt_parent":"PORT20"}, + "i2c": + { + "topo_info": { "parent_bus":"0x3d", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0A", "attr_mask":"0x3", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0F", "attr_mask":"0x3", "attr_cmpval":"0x8", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x14", "attr_mask":"0x3", "attr_cmpval":"0x8", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x19", "attr_mask":"0x3", "attr_cmpval":"0x8", "attr_len":"1"} + ] + } + }, + + "PORT21": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT21", "device_parent":"MUX8"}, + "dev_attr": { "dev_idx":"21"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT21-EEPROM" }, + { "itf":"control", "dev":"PORT21-CTRL" } + ] + } + }, + "PORT21-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT21-EEPROM", "device_parent":"MUX8", "virt_parent":"PORT21"}, + "i2c": + { + "topo_info": { "parent_bus":"0x3e", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT21-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT21-CTRL", "device_parent":"MUX8", "virt_parent":"PORT21"}, + "i2c": + { + "topo_info": { "parent_bus":"0x3e", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0A", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0F", "attr_mask":"0x4", "attr_cmpval":"0x10", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x14", "attr_mask":"0x4", "attr_cmpval":"0x10", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x19", "attr_mask":"0x4", "attr_cmpval":"0x10", "attr_len":"1"} + ] + } + }, + + "PORT22": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT22", "device_parent":"MUX8"}, + "dev_attr": { "dev_idx":"22"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT22-EEPROM" }, + { "itf":"control", "dev":"PORT22-CTRL" } + ] + } + }, + "PORT22-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT22-EEPROM", "device_parent":"MUX8", "virt_parent":"PORT22"}, + "i2c": + { + "topo_info": { "parent_bus":"0x3f", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT22-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT22-CTRL", "device_parent":"MUX8", "virt_parent":"PORT22"}, + "i2c": + { + "topo_info": { "parent_bus":"0x3f", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0A", "attr_mask":"0x5", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0F", "attr_mask":"0x5", "attr_cmpval":"0x20", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x14", "attr_mask":"0x5", "attr_cmpval":"0x20", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x19", "attr_mask":"0x5", "attr_cmpval":"0x20", "attr_len":"1"} + ] + } + }, + + "PORT23": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT23", "device_parent":"MUX8"}, + "dev_attr": { "dev_idx":"23"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT23-EEPROM" }, + { "itf":"control", "dev":"PORT23-CTRL" } + ] + } + }, + "PORT23-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT23-EEPROM", "device_parent":"MUX8", "virt_parent":"PORT23"}, + "i2c": + { + "topo_info": { "parent_bus":"0x40", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT23-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT23-CTRL", "device_parent":"MUX8", "virt_parent":"PORT23"}, + "i2c": + { + "topo_info": { "parent_bus":"0x40", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0A", "attr_mask":"0x6", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0F", "attr_mask":"0x6", "attr_cmpval":"0x40", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x14", "attr_mask":"0x6", "attr_cmpval":"0x40", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x19", "attr_mask":"0x6", "attr_cmpval":"0x40", "attr_len":"1"} + ] + } + }, + + "PORT24": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT24", "device_parent":"MUX8"}, + "dev_attr": { "dev_idx":"24"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT24-EEPROM" }, + { "itf":"control", "dev":"PORT24-CTRL" } + ] + } + }, + "PORT24-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT24-EEPROM", "device_parent":"MUX8", "virt_parent":"PORT24"}, + "i2c": + { + "topo_info": { "parent_bus":"0x41", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT24-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT24-CTRL", "device_parent":"MUX8", "virt_parent":"PORT24"}, + "i2c": + { + "topo_info": { "parent_bus":"0x41", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0A", "attr_mask":"0x7", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0F", "attr_mask":"0x7", "attr_cmpval":"0x80", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x14", "attr_mask":"0x7", "attr_cmpval":"0x80", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x19", "attr_mask":"0x7", "attr_cmpval":"0x80", "attr_len":"1"} + ] + } + }, + + "PORT25": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT25", "device_parent":"MUX9"}, + "dev_attr": { "dev_idx":"25"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT25-EEPROM" }, + { "itf":"control", "dev":"PORT25-CTRL" } + ] + } + }, + "PORT25-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT25-EEPROM", "device_parent":"MUX9", "virt_parent":"PORT25"}, + "i2c": + { + "topo_info": { "parent_bus":"0x42", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT25-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT25-CTRL", "device_parent":"MUX9", "virt_parent":"PORT25"}, + "i2c": + { + "topo_info": { "parent_bus":"0x42", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2","attr_offset":"0x0B", "attr_mask":"0x0", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2","attr_offset":"0x10", "attr_mask":"0x0", "attr_cmpval":"0x1", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2","attr_offset":"0x15", "attr_mask":"0x0", "attr_cmpval":"0x1", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2","attr_offset":"0x1A", "attr_mask":"0x0", "attr_cmpval":"0x1", "attr_len":"1"} + ] + } + }, + + "PORT26": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT26", "device_parent":"MUX9"}, + "dev_attr": { "dev_idx":"26"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT26-EEPROM" }, + { "itf":"control", "dev":"PORT26-CTRL" } + ] + } + }, + "PORT26-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT26-EEPROM", "device_parent":"MUX9", "virt_parent":"PORT26"}, + "i2c": + { + "topo_info": { "parent_bus":"0x43", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT26-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT26-CTRL", "device_parent":"MUX9", "virt_parent":"PORT26"}, + "i2c": + { + "topo_info": { "parent_bus":"0x43", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2","attr_offset":"0x0B", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2","attr_offset":"0x10", "attr_mask":"0x1", "attr_cmpval":"0x2", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2","attr_offset":"0x15", "attr_mask":"0x1", "attr_cmpval":"0x2", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2","attr_offset":"0x1A", "attr_mask":"0x1", "attr_cmpval":"0x2", "attr_len":"1"} + ] + } + }, + + "PORT27": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT27", "device_parent":"MUX9"}, + "dev_attr": { "dev_idx":"27"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT27-EEPROM" }, + { "itf":"control", "dev":"PORT27-CTRL" } + ] + } + }, + "PORT27-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT27-EEPROM", "device_parent":"MUX9", "virt_parent":"PORT27"}, + "i2c": + { + "topo_info": { "parent_bus":"0x44", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT27-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT27-CTRL", "device_parent":"MUX9", "virt_parent":"PORT27"}, + "i2c": + { + "topo_info": { "parent_bus":"0x44", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2","attr_offset":"0x0B", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2","attr_offset":"0x10", "attr_mask":"0x2", "attr_cmpval":"0x4", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld","attr_devname":"CPLD2", "attr_offset":"0x15", "attr_mask":"0x2", "attr_cmpval":"0x4", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2","attr_offset":"0x1A", "attr_mask":"0x2", "attr_cmpval":"0x4", "attr_len":"1"} + ] + } + }, + + "PORT28": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT28", "device_parent":"MUX9"}, + "dev_attr": { "dev_idx":"28"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT28-EEPROM" }, + { "itf":"control", "dev":"PORT28-CTRL" } + ] + } + }, + "PORT28-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT28-EEPROM", "device_parent":"MUX9", "virt_parent":"PORT28"}, + "i2c": + { + "topo_info": { "parent_bus":"0x45", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT28-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT28-CTRL", "device_parent":"MUX9", "virt_parent":"PORT28"}, + "i2c": + { + "topo_info": { "parent_bus":"0x45", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2","attr_offset":"0x0B", "attr_mask":"0x3", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2","attr_offset":"0x10", "attr_mask":"0x3", "attr_cmpval":"0x8", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2","attr_offset":"0x15", "attr_mask":"0x3", "attr_cmpval":"0x8", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2","attr_offset":"0x1A", "attr_mask":"0x3", "attr_cmpval":"0x8", "attr_len":"1"} + ] + } + }, + + "PORT29": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT29", "device_parent":"MUX9"}, + "dev_attr": { "dev_idx":"29"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT29-EEPROM" }, + { "itf":"control", "dev":"PORT29-CTRL" } + ] + } + }, + "PORT29-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT29-EEPROM", "device_parent":"MUX9", "virt_parent":"PORT29"}, + "i2c": + { + "topo_info": { "parent_bus":"0x46", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT29-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT29-CTRL", "device_parent":"MUX9", "virt_parent":"PORT29"}, + "i2c": + { + "topo_info": { "parent_bus":"0x46", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2","attr_offset":"0x0B", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2","attr_offset":"0x10", "attr_mask":"0x4", "attr_cmpval":"0x10", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2","attr_offset":"0x15", "attr_mask":"0x4", "attr_cmpval":"0x10", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2","attr_offset":"0x1A", "attr_mask":"0x4", "attr_cmpval":"0x10", "attr_len":"1"} + ] + } + }, + + "PORT30": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT30", "device_parent":"MUX9"}, + "dev_attr": { "dev_idx":"30"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT30-EEPROM" }, + { "itf":"control", "dev":"PORT30-CTRL" } + ] + } + }, + "PORT30-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT30-EEPROM", "device_parent":"MUX9", "virt_parent":"PORT30"}, + "i2c": + { + "topo_info": { "parent_bus":"0x47", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT30-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT30-CTRL", "device_parent":"MUX9", "virt_parent":"PORT30"}, + "i2c": + { + "topo_info": { "parent_bus":"0x47", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0B", "attr_mask":"0x5", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x10", "attr_mask":"0x5", "attr_cmpval":"0x20", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld","attr_devname":"CPLD2", "attr_offset":"0x15", "attr_mask":"0x5", "attr_cmpval":"0x20", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x1A", "attr_mask":"0x5", "attr_cmpval":"0x20", "attr_len":"1"} + ] + } + }, + + "PORT31": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT31", "device_parent":"MUX9"}, + "dev_attr": { "dev_idx":"31"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT31-EEPROM" }, + { "itf":"control", "dev":"PORT31-CTRL" } + ] + } + }, + "PORT31-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT31-EEPROM", "device_parent":"MUX9", "virt_parent":"PORT31"}, + "i2c": + { + "topo_info": { "parent_bus":"0x48", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT31-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT31-CTRL", "device_parent":"MUX9", "virt_parent":"PORT31"}, + "i2c": + { + "topo_info": { "parent_bus":"0x48", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2","attr_offset":"0x0B", "attr_mask":"0x6", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2","attr_offset":"0x10", "attr_mask":"0x6", "attr_cmpval":"0x40", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2","attr_offset":"0x15", "attr_mask":"0x6", "attr_cmpval":"0x40", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2","attr_offset":"0x1A", "attr_mask":"0x6", "attr_cmpval":"0x40", "attr_len":"1"} + ] + } + }, + + "PORT32": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT32", "device_parent":"MUX9"}, + "dev_attr": { "dev_idx":"32"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT32-EEPROM" }, + { "itf":"control", "dev":"PORT32-CTRL" } + ] + } + }, + "PORT32-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT32-EEPROM", "device_parent":"MUX9", "virt_parent":"PORT32"}, + "i2c": + { + "topo_info": { "parent_bus":"0x49", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT32-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT32-CTRL", "device_parent":"MUX9", "virt_parent":"PORT32"}, + "i2c": + { + "topo_info": { "parent_bus":"0x49", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0B", "attr_mask":"0x7", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x10", "attr_mask":"0x7", "attr_cmpval":"0x80", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld","attr_devname":"CPLD2", "attr_offset":"0x15", "attr_mask":"0x7", "attr_cmpval":"0x80", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x1A", "attr_mask":"0x7", "attr_cmpval":"0x80", "attr_len":"1"} + ] + } + }, + + "PORT33": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT33", "device_parent":"MUX10"}, + "dev_attr": { "dev_idx":"33"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT33-EEPROM" }, + { "itf":"control", "dev":"PORT33-CTRL" } + ] + } + }, + "PORT33-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT33-EEPROM", "device_parent":"MUX10", "virt_parent":"PORT33"}, + "i2c": + { + "topo_info": { "parent_bus":"0x4a", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT33-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT33-CTRL", "device_parent":"MUX10", "virt_parent":"PORT33"}, + "i2c": + { + "topo_info": { "parent_bus":"0x4a", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0C", "attr_mask":"0x0", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x11", "attr_mask":"0x0", "attr_cmpval":"0x1", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x16", "attr_mask":"0x0", "attr_cmpval":"0x1", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x1B", "attr_mask":"0x0", "attr_cmpval":"0x1", "attr_len":"1"} + ] + } + }, + + "PORT34": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT34", "device_parent":"MUX10"}, + "dev_attr": { "dev_idx":"34"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT34-EEPROM" }, + { "itf":"control", "dev":"PORT34-CTRL" } + ] + } + }, + "PORT34-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT34-EEPROM", "device_parent":"MUX10", "virt_parent":"PORT34"}, + "i2c": + { + "topo_info": { "parent_bus":"0x4b", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT34-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT34-CTRL", "device_parent":"MUX10", "virt_parent":"PORT34"}, + "i2c": + { + "topo_info": { "parent_bus":"0x4b", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0C", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x11", "attr_mask":"0x1", "attr_cmpval":"0x2", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x16", "attr_mask":"0x1", "attr_cmpval":"0x2", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x1B", "attr_mask":"0x1", "attr_cmpval":"0x2", "attr_len":"1"} + ] + } + }, + + "PORT35": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT35", "device_parent":"MUX10"}, + "dev_attr": { "dev_idx":"35"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT35-EEPROM" }, + { "itf":"control", "dev":"PORT35-CTRL" } + ] + } + }, + "PORT35-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT35-EEPROM", "device_parent":"MUX10", "virt_parent":"PORT35"}, + "i2c": + { + "topo_info": { "parent_bus":"0x4c", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT35-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT35-CTRL", "device_parent":"MUX10", "virt_parent":"PORT35"}, + "i2c": + { + "topo_info": { "parent_bus":"0x4c", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0C", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x11", "attr_mask":"0x2", "attr_cmpval":"0x4", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x16", "attr_mask":"0x2", "attr_cmpval":"0x4", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x1B", "attr_mask":"0x2", "attr_cmpval":"0x4", "attr_len":"1"} + ] + } + }, + + "PORT36": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT36", "device_parent":"MUX10"}, + "dev_attr": { "dev_idx":"36"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT36-EEPROM" }, + { "itf":"control", "dev":"PORT36-CTRL" } + ] + } + }, + "PORT36-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT36-EEPROM", "device_parent":"MUX10", "virt_parent":"PORT36"}, + "i2c": + { + "topo_info": { "parent_bus":"0x4d", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT36-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT36-CTRL", "device_parent":"MUX10", "virt_parent":"PORT36"}, + "i2c": + { + "topo_info": { "parent_bus":"0x4d", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0C", "attr_mask":"0x3", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x11", "attr_mask":"0x3", "attr_cmpval":"0x8", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x16", "attr_mask":"0x3", "attr_cmpval":"0x8", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x1B", "attr_mask":"0x3", "attr_cmpval":"0x8", "attr_len":"1"} + ] + } + }, + + "PORT37": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT37", "device_parent":"MUX10"}, + "dev_attr": { "dev_idx":"37"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT37-EEPROM" }, + { "itf":"control", "dev":"PORT37-CTRL" } + ] + } + }, + "PORT37-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT37-EEPROM", "device_parent":"MUX10", "virt_parent":"PORT37"}, + "i2c": + { + "topo_info": { "parent_bus":"0x4e", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT37-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT37-CTRL", "device_parent":"MUX10", "virt_parent":"PORT37"}, + "i2c": + { + "topo_info": { "parent_bus":"0x4e", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0C", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x11", "attr_mask":"0x4", "attr_cmpval":"0x10", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x16", "attr_mask":"0x4", "attr_cmpval":"0x10", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x1B", "attr_mask":"0x4", "attr_cmpval":"0x10", "attr_len":"1"} + ] + } + }, + + "PORT38": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT38", "device_parent":"MUX10"}, + "dev_attr": { "dev_idx":"38"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT38-EEPROM" }, + { "itf":"control", "dev":"PORT38-CTRL" } + ] + } + }, + "PORT38-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT38-EEPROM", "device_parent":"MUX10", "virt_parent":"PORT38"}, + "i2c": + { + "topo_info": { "parent_bus":"0x4f", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT38-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT38-CTRL", "device_parent":"MUX10", "virt_parent":"PORT38"}, + "i2c": + { + "topo_info": { "parent_bus":"0x4f", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x0C", "attr_mask":"0x5", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x11", "attr_mask":"0x5", "attr_cmpval":"0x20", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x16", "attr_mask":"0x5", "attr_cmpval":"0x20", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x61", "attr_devtype":"cpld", "attr_devname":"CPLD2", "attr_offset":"0x1B", "attr_mask":"0x5", "attr_cmpval":"0x20", "attr_len":"1"} + ] + } + }, + + "PORT39": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT39", "device_parent":"MUX10"}, + "dev_attr": { "dev_idx":"39"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT39-EEPROM" }, + { "itf":"control", "dev":"PORT39-CTRL" } + ] + } + }, + "PORT39-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT39-EEPROM", "device_parent":"MUX10", "virt_parent":"PORT39"}, + "i2c": + { + "topo_info": { "parent_bus":"0x50", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT39-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT39-CTRL", "device_parent":"MUX10", "virt_parent":"PORT39"}, + "i2c": + { + "topo_info": { "parent_bus":"0x50", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x06", "attr_mask":"0x0", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x09", "attr_mask":"0x0", "attr_cmpval":"0x1", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x0C", "attr_mask":"0x0", "attr_cmpval":"0x1", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x0F", "attr_mask":"0x0", "attr_cmpval":"0x1", "attr_len":"1"} + ] + } + }, + + "PORT40": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT40", "device_parent":"MUX10"}, + "dev_attr": { "dev_idx":"40"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT40-EEPROM" }, + { "itf":"control", "dev":"PORT40-CTRL" } + ] + } + }, + "PORT40-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT40-EEPROM", "device_parent":"MUX10", "virt_parent":"PORT40"}, + "i2c": + { + "topo_info": { "parent_bus":"0x51", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT40-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT40-CTRL", "device_parent":"MUX10", "virt_parent":"PORT40"}, + "i2c": + { + "topo_info": { "parent_bus":"0x51", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x06", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x09", "attr_mask":"0x1", "attr_cmpval":"0x2", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x0C", "attr_mask":"0x1", "attr_cmpval":"0x2", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x0F", "attr_mask":"0x1", "attr_cmpval":"0x2", "attr_len":"1"} + ] + } + }, + + "PORT41": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT41", "device_parent":"MUX11"}, + "dev_attr": { "dev_idx":"41"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT41-EEPROM" }, + { "itf":"control", "dev":"PORT41-CTRL" } + ] + } + }, + "PORT41-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT41-EEPROM", "device_parent":"MUX11", "virt_parent":"PORT41"}, + "i2c": + { + "topo_info": { "parent_bus":"0x52", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT41-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT41-CTRL", "device_parent":"MUX11", "virt_parent":"PORT41"}, + "i2c": + { + "topo_info": { "parent_bus":"0x52", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x06", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x09", "attr_mask":"0x2", "attr_cmpval":"0x4", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x0C", "attr_mask":"0x2", "attr_cmpval":"0x4", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x0F", "attr_mask":"0x2", "attr_cmpval":"0x4", "attr_len":"1"} + ] + } + }, + + "PORT42": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT42", "device_parent":"MUX11"}, + "dev_attr": { "dev_idx":"42"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT42-EEPROM" }, + { "itf":"control", "dev":"PORT42-CTRL" } + ] + } + }, + "PORT42-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT42-EEPROM", "device_parent":"MUX11", "virt_parent":"PORT42"}, + "i2c": + { + "topo_info": { "parent_bus":"0x53", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT42-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT42-CTRL", "device_parent":"MUX11", "virt_parent":"PORT42"}, + "i2c": + { + "topo_info": { "parent_bus":"0x53", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x06", "attr_mask":"0x3", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x09", "attr_mask":"0x3", "attr_cmpval":"0x8", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x0C", "attr_mask":"0x3", "attr_cmpval":"0x8", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x0F", "attr_mask":"0x3", "attr_cmpval":"0x8", "attr_len":"1"} + ] + } + }, + + "PORT43": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT43", "device_parent":"MUX11"}, + "dev_attr": { "dev_idx":"43"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT43-EEPROM" }, + { "itf":"control", "dev":"PORT43-CTRL" } + ] + } + }, + "PORT43-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT43-EEPROM", "device_parent":"MUX11", "virt_parent":"PORT43"}, + "i2c": + { + "topo_info": { "parent_bus":"0x54", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT43-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT43-CTRL", "device_parent":"MUX11", "virt_parent":"PORT43"}, + "i2c": + { + "topo_info": { "parent_bus":"0x54", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3","attr_offset":"0x06", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3","attr_offset":"0x09", "attr_mask":"0x4", "attr_cmpval":"0x10", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3","attr_offset":"0x0C", "attr_mask":"0x4", "attr_cmpval":"0x10", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3","attr_offset":"0x0F", "attr_mask":"0x4", "attr_cmpval":"0x10", "attr_len":"1"} + ] + } + }, + + "PORT44": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT44", "device_parent":"MUX11"}, + "dev_attr": { "dev_idx":"44"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT44-EEPROM" }, + { "itf":"control", "dev":"PORT44-CTRL" } + ] + } + }, + "PORT44-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT44-EEPROM", "device_parent":"MUX11", "virt_parent":"PORT44"}, + "i2c": + { + "topo_info": { "parent_bus":"0x55", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT44-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT44-CTRL", "device_parent":"MUX11", "virt_parent":"PORT44"}, + "i2c": + { + "topo_info": { "parent_bus":"0x55", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x06", "attr_mask":"0x5", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x09", "attr_mask":"0x5", "attr_cmpval":"0x20", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x0C", "attr_mask":"0x5", "attr_cmpval":"0x20", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x0F", "attr_mask":"0x5", "attr_cmpval":"0x20", "attr_len":"1"} + ] + } + }, + + "PORT45": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT45", "device_parent":"MUX11"}, + "dev_attr": { "dev_idx":"45"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT45-EEPROM" }, + { "itf":"control", "dev":"PORT45-CTRL" } + ] + } + }, + "PORT45-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT45-EEPROM", "device_parent":"MUX11", "virt_parent":"PORT45"}, + "i2c": + { + "topo_info": { "parent_bus":"0x56", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT45-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT45-CTRL", "device_parent":"MUX11", "virt_parent":"PORT45"}, + "i2c": + { + "topo_info": { "parent_bus":"0x56", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x06", "attr_mask":"0x6", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x09", "attr_mask":"0x6", "attr_cmpval":"0x40", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x0C", "attr_mask":"0x6", "attr_cmpval":"0x40", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x0F", "attr_mask":"0x6", "attr_cmpval":"0x40", "attr_len":"1"} + ] + } + }, + + "PORT46": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT46", "device_parent":"MUX11"}, + "dev_attr": { "dev_idx":"46"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT46-EEPROM" }, + { "itf":"control", "dev":"PORT46-CTRL" } + ] + } + }, + "PORT46-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT46-EEPROM", "device_parent":"MUX11", "virt_parent":"PORT46"}, + "i2c": + { + "topo_info": { "parent_bus":"0x57", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT46-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT46-CTRL", "device_parent":"MUX11", "virt_parent":"PORT46"}, + "i2c": + { + "topo_info": { "parent_bus":"0x57", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x06", "attr_mask":"0x7", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x09", "attr_mask":"0x7", "attr_cmpval":"0x80", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x0C", "attr_mask":"0x7", "attr_cmpval":"0x80", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x0F", "attr_mask":"0x7", "attr_cmpval":"0x80", "attr_len":"1"} + ] + } + }, + + "PORT47": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT47", "device_parent":"MUX11"}, + "dev_attr": { "dev_idx":"47"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT47-EEPROM" }, + { "itf":"control", "dev":"PORT47-CTRL" } + ] + } + }, + "PORT47-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT47-EEPROM", "device_parent":"MUX11", "virt_parent":"PORT47"}, + "i2c": + { + "topo_info": { "parent_bus":"0x58", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT47-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT47-CTRL", "device_parent":"MUX11", "virt_parent":"PORT47"}, + "i2c": + { + "topo_info": { "parent_bus":"0x58", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x07", "attr_mask":"0x0", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x0A", "attr_mask":"0x0", "attr_cmpval":"0x1", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x0D", "attr_mask":"0x0", "attr_cmpval":"0x1", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x10", "attr_mask":"0x0", "attr_cmpval":"0x1", "attr_len":"1"} + ] + } + }, + + "PORT48": + { + "dev_info": { "device_type":"SFP28", "device_name":"PORT48", "device_parent":"MUX11"}, + "dev_attr": { "dev_idx":"48"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT48-EEPROM" }, + { "itf":"control", "dev":"PORT48-CTRL" } + ] + } + }, + "PORT48-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT48-EEPROM", "device_parent":"MUX11", "virt_parent":"PORT48"}, + "i2c": + { + "topo_info": { "parent_bus":"0x59", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT48-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT48-CTRL", "device_parent":"MUX11", "virt_parent":"PORT48"}, + "i2c": + { + "topo_info": { "parent_bus":"0x59", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x07", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_txfault", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x0A", "attr_mask":"0x1", "attr_cmpval":"0x2", "attr_len":"1"}, + { "attr_name":"xcvr_txdisable", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x0D", "attr_mask":"0x1", "attr_cmpval":"0x2", "attr_len":"1"}, + { "attr_name":"xcvr_rxlos", "attr_devaddr":"0x62", "attr_devtype":"cpld", "attr_devname":"CPLD3", "attr_offset":"0x10", "attr_mask":"0x1", "attr_cmpval":"0x2", "attr_len":"1"} + ] + } + }, + + "LOC_LED": + { + "dev_info": { "device_type":"LED", "device_name":"LOC_LED"}, + "dev_attr": { "index":"0"}, + "i2c" : + { + "attr_list": + [ + {"attr_name":"STATUS_LED_COLOR_AMBER", "descr": "" , "bits" : "5:4", "value" : "0x0", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x0A"}, + {"attr_name":"STATUS_LED_COLOR_OFF", "descr": "" , "bits" : "5:4", "value" : "0x1", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x0A"} + + ] + } + }, + "DIAG_LED": + { + "dev_info": { "device_type":"LED", "device_name":"DIAG_LED"}, + "dev_attr": { "index":"0"}, + "i2c" : + { + "attr_list": + [ + {"attr_name":"STATUS_LED_COLOR_GREEN", "descr": "" , "bits" : "3:2", "value" : "0x2", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x0A"}, + {"attr_name":"STATUS_LED_COLOR_AMBER", "descr": "" , "bits" : "3:2", "value" : "0x1", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x0A"}, + {"attr_name":"STATUS_LED_COLOR_OFF", "descr": "" , "bits" : "3:2", "value" : "0x3", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x0A"} + ] + } + } +} diff --git a/device/accton/x86_64-accton_as5835_54x-r0/pddf_support b/device/accton/x86_64-accton_as5835_54x-r0/pddf_support new file mode 100644 index 00000000000..e69de29bb2d diff --git a/device/accton/x86_64-accton_as5835_54x-r0/pmon_daemon_control.json b/device/accton/x86_64-accton_as5835_54x-r0/pmon_daemon_control.json index 584a14b9d94..a3b204e20d8 100644 --- a/device/accton/x86_64-accton_as5835_54x-r0/pmon_daemon_control.json +++ b/device/accton/x86_64-accton_as5835_54x-r0/pmon_daemon_control.json @@ -1,5 +1,5 @@ { "skip_ledd": true, - "skip_thermalctld": true + "skip_pcied": true } diff --git a/device/accton/x86_64-accton_as5835_54x-r0/system_health_monitoring_config.json b/device/accton/x86_64-accton_as5835_54x-r0/system_health_monitoring_config.json new file mode 100644 index 00000000000..53b14bec17b --- /dev/null +++ b/device/accton/x86_64-accton_as5835_54x-r0/system_health_monitoring_config.json @@ -0,0 +1,17 @@ +{ + "services_to_ignore": [], + "devices_to_ignore": [ + "asic", + "psu.voltage", + "psu.temperature", + "PSU1_FAN1.speed", + "PSU2_FAN1.speed" + ], + "user_defined_checkers": [], + "polling_interval": 60, + "led_color": { + "fault": "STATUS_LED_COLOR_AMBER", + "normal": "STATUS_LED_COLOR_GREEN", + "booting": "STATUS_LED_COLOR_OFF" + } +} diff --git a/device/accton/x86_64-accton_as7326_56x-r0/pddf/pddf-device.json b/device/accton/x86_64-accton_as7326_56x-r0/pddf/pddf-device.json index 78be7f2b61c..8967606429a 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/pddf/pddf-device.json +++ b/device/accton/x86_64-accton_as7326_56x-r0/pddf/pddf-device.json @@ -49,6 +49,10 @@ "pddf_fan_module", "pddf_led_module", "pddf_sysstatus_module" + ], + "custom_kos": + [ + "pddf_custom_psu" ] }, @@ -181,7 +185,8 @@ { "interface": [ - { "itf":"pmbus", "dev":"PSU2-PMBUS"} + { "itf":"pmbus", "dev":"PSU2-PMBUS"}, + { "itf":"eeprom", "dev":"PSU2-EEPROM" } ] } }, @@ -195,10 +200,8 @@ "attr_list": [ { "attr_name":"psu_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x2", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, - { "attr_name":"psu_model_name", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x9a", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"10" }, { "attr_name":"psu_power_good", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x2", "attr_mask":"0x4", "attr_cmpval":"0x4", "attr_len":"1"}, { "attr_name":"psu_mfr_id", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0X99", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"10" }, - { "attr_name":"psu_serial_num", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x9e", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"20" }, { "attr_name":"psu_fan_dir", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0xc3", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"5"}, { "attr_name":"psu_v_out", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x8b", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, { "attr_name":"psu_i_out", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x8c", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, @@ -208,7 +211,21 @@ ] } }, - + + "PSU2-EEPROM": + { + "dev_info": { "device_type":"PSU-EEPROM", "device_name":"PSU2-EEPROM", "device_parent":"MUX2", "virt_parent":"PSU2"}, + "i2c": + { + "topo_info":{ "parent_bus":"0xd", "dev_addr":"0x53", "dev_type":"psu_eeprom"}, + "attr_list": + [ + { "attr_name":"psu_model_name", "attr_devaddr":"0x53", "attr_devtype":"eeprom", "attr_offset":"0x15", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"11" }, + { "attr_name":"psu_serial_num", "attr_devaddr":"0x53", "attr_devtype":"eeprom", "attr_offset":"0x2e", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"17" } + + ] + } + }, "PSU1": { "dev_info": { "device_type":"PSU", "device_name":"PSU1", "device_parent":"MUX3" }, @@ -217,7 +234,8 @@ { "interface": [ - { "itf":"pmbus", "dev":"PSU1-PMBUS"} + { "itf":"pmbus", "dev":"PSU1-PMBUS"}, + { "itf":"eeprom", "dev":"PSU1-EEPROM" } ] } }, @@ -230,11 +248,9 @@ "topo_info": { "parent_bus":"0x11", "dev_addr":"0x59", "dev_type":"psu_pmbus"}, "attr_list": [ - { "attr_name":"psu_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x2", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, - { "attr_name":"psu_model_name", "attr_devaddr":"0x59", "attr_devtype":"pmbus", "attr_offset":"0x9a", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"10" }, + { "attr_name":"psu_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x2", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, { "attr_name":"psu_power_good", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x2", "attr_mask":"0x8", "attr_cmpval":"0x8", "attr_len":"1"}, { "attr_name":"psu_mfr_id", "attr_devaddr":"0x59", "attr_devtype":"pmbus", "attr_offset":"0X99", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"10" }, - { "attr_name":"psu_serial_num", "attr_devaddr":"0x59", "attr_devtype":"pmbus", "attr_offset":"0x9e", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"20" }, { "attr_name":"psu_fan_dir", "attr_devaddr":"0x59", "attr_devtype":"pmbus", "attr_offset":"0xc3", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"5"}, { "attr_name":"psu_v_out", "attr_devaddr":"0x59", "attr_devtype":"pmbus", "attr_offset":"0x8b", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, { "attr_name":"psu_i_out", "attr_devaddr":"0x59", "attr_devtype":"pmbus", "attr_offset":"0x8c", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, @@ -244,7 +260,19 @@ ] } }, - + "PSU1-EEPROM": + { + "dev_info": { "device_type":"PSU-EEPROM", "device_name":"PSU1-EEPROM", "device_parent":"MUX2", "virt_parent":"PSU1"}, + "i2c": + { + "topo_info":{ "parent_bus":"0x11", "dev_addr":"0x51", "dev_type":"psu_eeprom"}, + "attr_list": + [ + { "attr_name":"psu_model_name", "attr_devaddr":"0x51", "attr_devtype":"eeprom", "attr_offset":"0x15", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"11" }, + { "attr_name":"psu_serial_num", "attr_devaddr":"0x51", "attr_devtype":"eeprom", "attr_offset":"0x2e", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"17" } + ] + } + }, "CPLD1": { "dev_info": { "device_type":"CPLD", "device_name":"CPLD1", "device_parent":"MUX3"}, diff --git a/device/accton/x86_64-accton_as7535_32xb-r0/Accton-AS7535-32XB/port_config.ini b/device/accton/x86_64-accton_as7535_32xb-r0/Accton-AS7535-32XB/port_config.ini new file mode 100644 index 00000000000..8afc10e8169 --- /dev/null +++ b/device/accton/x86_64-accton_as7535_32xb-r0/Accton-AS7535-32XB/port_config.ini @@ -0,0 +1,31 @@ +# name lanes alias index speed +Ethernet0 0 twentyfiveGigE1 1 25000 +Ethernet1 1 twentyfiveGigE2 2 25000 +Ethernet2 2 twentyfiveGigE3 3 25000 +Ethernet3 3 twentyfiveGigE4 4 25000 +Ethernet4 4 twentyfiveGigE5 5 25000 +Ethernet5 5 twentyfiveGigE6 6 25000 +Ethernet6 6 twentyfiveGigE7 7 25000 +Ethernet7 7 twentyfiveGigE8 8 25000 +Ethernet8 8 twentyfiveGigE9 9 25000 +Ethernet9 9 twentyfiveGigE10 10 25000 +Ethernet10 10 twentyfiveGigE11 11 25000 +Ethernet11 11 twentyfiveGigE12 12 25000 +Ethernet12 12 twentyfiveGigE13 13 25000 +Ethernet13 13 twentyfiveGigE14 14 25000 +Ethernet14 14 twentyfiveGigE15 15 25000 +Ethernet15 15 twentyfiveGigE16 16 25000 +Ethernet16 16 twentyfiveGigE17 17 25000 +Ethernet17 17 twentyfiveGigE18 18 25000 +Ethernet18 18 twentyfiveGigE19 19 25000 +Ethernet19 19 twentyfiveGigE20 20 25000 +Ethernet20 20 twentyfiveGigE21 21 25000 +Ethernet21 21 twentyfiveGigE22 22 25000 +Ethernet22 22 twentyfiveGigE23 23 25000 +Ethernet23 23 twentyfiveGigE24 24 25000 +Ethernet24 24 twentyfiveGigE25 25 25000 +Ethernet25 25 twentyfiveGigE26 26 25000 +Ethernet26 27,28,29,30 hundredGigE27 27 100000 +Ethernet30 31,32,33,34,35,36,37,38 fourHundredGigE28 28 400000 +Ethernet38 39,40,41,42 hundredGigE29 29 100000 +Ethernet42 43,44,45,46,47,48,49,50 fourHundredGigE30 30 400000 diff --git a/device/accton/x86_64-accton_as7535_32xb-r0/Accton-AS7535-32XB/sai.profile b/device/accton/x86_64-accton_as7535_32xb-r0/Accton-AS7535-32XB/sai.profile new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/device/accton/x86_64-accton_as7535_32xb-r0/Accton-AS7535-32XB/sai.profile @@ -0,0 +1 @@ + diff --git a/device/accton/x86_64-accton_as7535_32xb-r0/default_sku b/device/accton/x86_64-accton_as7535_32xb-r0/default_sku new file mode 100644 index 00000000000..00ab1f94d9e --- /dev/null +++ b/device/accton/x86_64-accton_as7535_32xb-r0/default_sku @@ -0,0 +1 @@ +Accton-AS7535-32XB t1 diff --git a/device/accton/x86_64-accton_as7535_32xb-r0/installer.conf b/device/accton/x86_64-accton_as7535_32xb-r0/installer.conf new file mode 100644 index 00000000000..1b578bec17e --- /dev/null +++ b/device/accton/x86_64-accton_as7535_32xb-r0/installer.conf @@ -0,0 +1,4 @@ +CONSOLE_PORT=0x3f8 +CONSOLE_DEV=0 +CONSOLE_SPEED=115200 +ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="modprobe.blacklist=ast,ipmi_msghandler,ipmi_ssif,ipmi_si,ipmi_devintf" diff --git a/device/accton/x86_64-accton_as7535_32xb-r0/platform_asic b/device/accton/x86_64-accton_as7535_32xb-r0/platform_asic new file mode 100644 index 00000000000..96046765276 --- /dev/null +++ b/device/accton/x86_64-accton_as7535_32xb-r0/platform_asic @@ -0,0 +1 @@ +broadcom diff --git a/device/accton/x86_64-accton_as7535_32xb-r0/plugins/eeprom.py b/device/accton/x86_64-accton_as7535_32xb-r0/plugins/eeprom.py new file mode 100644 index 00000000000..498be7bfd0f --- /dev/null +++ b/device/accton/x86_64-accton_as7535_32xb-r0/plugins/eeprom.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python + +try: + from sonic_eeprom import eeprom_tlvinfo +except ImportError as 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): + self.eeprom_path = "/sys/bus/i2c/devices/0-0057/eeprom" + super(board, self).__init__(self.eeprom_path, 0, '', True) diff --git a/device/accton/x86_64-accton_as7535_32xb-r0/plugins/psuutil.py b/device/accton/x86_64-accton_as7535_32xb-r0/plugins/psuutil.py new file mode 100644 index 00000000000..23849a777a2 --- /dev/null +++ b/device/accton/x86_64-accton_as7535_32xb-r0/plugins/psuutil.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python + +############################################################################# +# Accton +# +# Module contains an implementation of SONiC PSU Base API and +# provides the PSUs status which are available in the platform +# +############################################################################# + +try: + from sonic_psu.psu_base import PsuBase +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + +class PsuUtil(PsuBase): + """Platform-specific PSUutil class""" + + def __init__(self): + PsuBase.__init__(self) + + self.psu_path = "/sys/devices/platform/as7535_32xb_psu/psu" + self.psu_presence = "_present" + self.psu_oper_status = "_power_good" + self.psu_mapping = { + 1: "1", + 2: "2" + } + + def get_num_psus(self): + return len(self.psu_mapping) + + def get_psu_status(self, index): + if index is None: + return False + + status = 0 + node = self.psu_path + self.psu_mapping[index]+self.psu_oper_status + try: + with open(node, 'r') as power_status: + status = int(power_status.read()) + except IOError: + return False + + return status == 1 + + def get_psu_presence(self, index): + if index is None: + return False + + status = 0 + node = self.psu_path + self.psu_mapping[index] + self.psu_presence + try: + with open(node, 'r') as presence_status: + status = int(presence_status.read()) + except IOError: + return False + + return status == 1 diff --git a/device/accton/x86_64-accton_as7535_32xb-r0/plugins/sfputil.py b/device/accton/x86_64-accton_as7535_32xb-r0/plugins/sfputil.py new file mode 100644 index 00000000000..8b41692dd28 --- /dev/null +++ b/device/accton/x86_64-accton_as7535_32xb-r0/plugins/sfputil.py @@ -0,0 +1,238 @@ +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# + +try: + import sys + import time + from ctypes import create_string_buffer + from sonic_sfp.sfputilbase import SfpUtilBase +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + +SFP_STATUS_INSERTED = '1' +SFP_STATUS_REMOVED = '0' + +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" + + PORT_START = 1 + PORT_END = 30 + QSFP_PORT_START = 27 + QSFP_PORT_END = 30 + CPLD_FMT = '/sys/bus/i2c/devices/{bus}-00{addr}/' + + _port_to_eeprom_mapping = {} + _port_to_i2c_mapping = { + 1: 25, + 2: 26, + 3: 27, + 4: 28, + 5: 29, + 6: 30, + 7: 31, + 8: 32, + 9: 33, + 10: 34, + 11: 35, + 12: 36, + 13: 37, + 14: 38, + 15: 39, + 16: 40, + 17: 41, + 18: 42, + 19: 43, + 20: 44, + 21: 45, + 22: 46, + 23: 47, + 24: 48, + 25: 49, + 26: 50, + 27: 23, + 28: 21, + 29: 24, + 30: 22 + } + + @property + def port_start(self): + return self.PORT_START + + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_port_start(self): + return self.QSFP_PORT_START + + @property + def qsfp_port_end(self): + return self.QSFP_PORT_END + + @property + def qsfp_ports(self): + return range(self.QSFP_PORT_START, self.QSFP_PORT_END + 1) + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + def __init__(self): + eeprom_path = '/sys/bus/i2c/devices/{0}-0050/eeprom' + for x in range(self.port_start, self.port_end+1): + self.port_to_eeprom_mapping[x] = eeprom_path.format( + self._port_to_i2c_mapping[x]) + + SfpUtilBase.__init__(self) + + def get_cpld_path(self, port_num): + return self.CPLD_FMT.format(bus=str(12), addr=str(61)) + + def get_presence(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + content = None + port_ps = self.get_cpld_path(port_num) + 'module_present_{0}'.format(port_num) + + try: + with open(port_ps) as val_file: + content = val_file.readline().rstrip() + except IOError as e: + print('GET. unable to open file: %s', str(e)) + return False + + # content is a string, either "0" or "1" + return content == "1" + + def get_low_power_mode(self, port_num): + if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end: + return False + + if not self.get_presence(port_num): + return False + + try: + eeprom = open(self.port_to_eeprom_mapping[port_num], mode="rb", buffering=0) + eeprom.seek(93) + lpmode = ord(eeprom.read(1)) + + if not (lpmode & 0x1): # 'Power override' bit is 0 + return False # Default High Power Mode + else: + if ((lpmode & 0x2) == 0x2): + return True # Low Power Mode if "Power set" bit is 1 + else: + return False # High Power Mode if "Power set" bit is 0 + except IOError as e: + print ('Error: unable to open file: ', str(e)) + return False + finally: + if eeprom is not None: + eeprom.close() + time.sleep(0.01) + + def set_low_power_mode(self, port_num, lpmode): + if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end: + return False + + try: + eeprom = None + + if not self.get_presence(port_num): + return False # Port is not present, unable to set the eeprom + + # Fill in write buffer + regval = 0x3 if lpmode else 0x1 # 0x3:Low Power Mode, 0x1:High Power Mode + buffer = create_string_buffer(1) + if sys.version_info[0] >= 3: + buffer[0] = regval + else: + buffer[0] = chr(regval) + + # Write to eeprom + eeprom = open(self.port_to_eeprom_mapping[port_num], mode="r+b", buffering=0) + eeprom.seek(93) + eeprom.write(buffer[0]) + return True + except IOError as e: + print ('Error: unable to open file: ', str(e)) + return False + finally: + if eeprom is not None: + eeprom.close() + time.sleep(0.01) + + def reset(self, port_num): + # Check for invalid port_num + if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end: + return False + + port_ps = self.get_cpld_path(port_num) + 'module_reset_{0}'.format(port_num) + + try: + reg_file = open(port_ps, mode="w") + except IOError as e: + print ('Error: unable to open file: ', str(e)) + return False + + #toggle reset + reg_file.seek(0) + reg_file.write('1') + time.sleep(0.2) + reg_file.seek(0) + reg_file.write('0') + reg_file.close() + + return True + + @property + def get_transceiver_status(self): + bitmap = 0 + + for port in range(self.port_start, self.port_end+1): + if not self.get_presence(port): + continue + bitmap |= (1 << (port - self.port_start)) + + return bitmap + + data = {'valid': 0, 'last': 0, 'present': 0} + + def get_transceiver_change_event(self, timeout=2000): + now = time.time() + port_dict = {} + port = 0 + + if timeout < 1000: + timeout = 1000 + timeout = (timeout) / float(1000) # Convert to secs + + if now < (self.data['last'] + timeout) and self.data['valid']: + return True, {} + + reg_value = self.get_transceiver_status + changed_ports = self.data['present'] ^ reg_value + if changed_ports: + for port in range(self.port_start, self.port_end+1): + # Mask off the bit corresponding to our port + fp_port = port + mask = (1 << (fp_port - 1)) + if changed_ports & mask: + if (reg_value & mask) == 0: + port_dict[port] = SFP_STATUS_REMOVED + else: + port_dict[port] = SFP_STATUS_INSERTED + + # Update cache + self.data['present'] = reg_value + self.data['last'] = now + self.data['valid'] = 1 + return True, port_dict + else: + return True, {} diff --git a/device/accton/x86_64-accton_as7535_32xb-r0/pmon_daemon_control.json b/device/accton/x86_64-accton_as7535_32xb-r0/pmon_daemon_control.json new file mode 100644 index 00000000000..c3f1249dd12 --- /dev/null +++ b/device/accton/x86_64-accton_as7535_32xb-r0/pmon_daemon_control.json @@ -0,0 +1,5 @@ +{ + "skip_ledd": true, + "skip_pcied": true, + "skip_thermalctld": true +} diff --git a/device/accton/x86_64-accton_as7712_32x-r0/pddf/pd-plugin.json b/device/accton/x86_64-accton_as7712_32x-r0/pddf/pd-plugin.json new file mode 100644 index 00000000000..4d253635cc9 --- /dev/null +++ b/device/accton/x86_64-accton_as7712_32x-r0/pddf/pd-plugin.json @@ -0,0 +1,54 @@ +{ + "PSU": + { + "psu_present": + { + "i2c": + { + "valmap": { "1":true, "0":false } + } + }, + + "psu_power_good": + { + "i2c": + { + "valmap": { "1": true, "0":false } + } + }, + + "psu_fan_dir": + { + "i2c": + { + "valmap": { "F2B":"EXHAUST", "B2F":"INTAKE" } + } + }, + + "PSU_FAN_MAX_SPEED":"18000" + }, + + "FAN": + { + "direction": + { + "i2c": + { + "valmap": {"1":"EXHAUST", "0":"INTAKE"} + } + }, + + "present": + { + "i2c": + { + "valmap": {"1":true, "0":false} + } + }, + + "duty_cycle_to_pwm": "lambda dc: ((dc*100.0)/625 - 1)", + + "pwm_to_duty_cycle": "lambda pwm: math.ceil(((pwm+1)*625.0)/100)" + } + +} diff --git a/device/accton/x86_64-accton_as7712_32x-r0/pddf/pddf-device.json b/device/accton/x86_64-accton_as7712_32x-r0/pddf/pddf-device.json new file mode 100644 index 00000000000..e84d3d23950 --- /dev/null +++ b/device/accton/x86_64-accton_as7712_32x-r0/pddf/pddf-device.json @@ -0,0 +1,1792 @@ +{ + "PLATFORM": + { + "num_psus":2, + "num_fantrays":6, + "num_fans_pertray":2, + "num_ports":32, + "num_temps": 4, + "pddf_dev_types": + { + "description":"AS7712 - Below is the list of supported PDDF device types (chip names) for various components. If any component uses some other driver, we will create the client using 'echo > /new_device' method", + "CPLD": + [ + "i2c_cpld" + ], + "PSU": + [ + "psu_eeprom", + "psu_pmbus" + ], + "FAN": + [ + "fan_ctrl", + "fan_eeprom" + ], + "PORT_MODULE": + [ + "pddf_xcvr" + ] + + }, + "std_kos": + [ + "i2c-ismt", + "i2c-i801", + "i2c_dev", + "i2c_mux_pca954x", + "optoe" + ], + "pddf_kos": + [ + "pddf_client_module", + "pddf_cpld_module", + "pddf_cpld_driver", + "pddf_mux_module", + "pddf_xcvr_module", + "pddf_xcvr_driver_module", + "pddf_psu_driver_module", + "pddf_psu_module", + "pddf_fan_driver_module", + "pddf_fan_module", + "pddf_led_module", + "pddf_sysstatus_module" + ] + }, + + "SYSTEM": + { + "dev_info": {"device_type":"CPU", "device_name":"ROOT_COMPLEX", "device_parent":null}, + "i2c": + { + "CONTROLLERS": + [ + { "dev_name":"i2c-1", "dev":"SMBUS1" }, + { "dev_name":"i2c-0", "dev":"SMBUS0" } + ] + } + }, + + "SMBUS0": + { + "dev_info": {"device_type": "SMBUS", "device_name": "SMBUS0", "device_parent": "SYSTEM"}, + "i2c": + { + "topo_info": {"dev_addr": "0x0"}, + "DEVICES": + [ + {"dev": "EEPROM1"}, + {"dev": "MUX2"}, + {"dev": "MUX3"}, + {"dev": "MUX4"}, + {"dev": "MUX5"}, + {"dev": "MUX6"} + ] + } + }, + + "SMBUS1": + { + "dev_info": {"device_type": "SMBUS", "device_name": "SMBUS1", "device_parent": "SYSTEM"}, + "i2c": + { + "topo_info": {"dev_addr": "0x1"}, + "DEVICES": + [ + {"dev": "MUX1"} + ] + } + }, + "EEPROM1": + { + "dev_info": {"device_type": "EEPROM", "device_name": "EEPROM1", "device_parent": "SMBUS0"}, + "i2c": + { + "topo_info": {"parent_bus": "0x0", "dev_addr": "0x57", "dev_type": "24c02"}, + "dev_attr": {"access_mode": "BLOCK"}, + "attr_list": [ + {"attr_name": "eeprom"} + ] + } + }, + + "MUX1": + { + "dev_info": { "device_type":"MUX", "device_name":"MUX1", "device_parent":"SMBUS1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x1", "dev_addr":"0x76", "dev_type":"pca9548"}, + "dev_attr": { "virt_bus":"0x2"}, + "channel": + [ + { "chn":"0", "dev":"FAN-CTRL" }, + { "chn":"1", "dev":"TEMP1" }, + { "chn":"1", "dev":"TEMP2" }, + { "chn":"1", "dev":"TEMP3" }, + { "chn":"1", "dev":"TEMP4" }, + { "chn":"2", "dev":"CPLD1" }, + { "chn":"3", "dev":"CPLD2" }, + { "chn":"4", "dev":"CPLD3" } + ] + } + }, + + "MUX2": + { + "dev_info": { "device_type":"MUX", "device_name":"MUX2", "device_parent":"SMBUS0"}, + "i2c": + { + "topo_info": { "parent_bus":"0x0", "dev_addr":"0x71", "dev_type":"pca9548"}, + "dev_attr": { "virt_bus":"0xa"}, + "channel": + [ + { "chn":"0", "dev":"PSU2" }, + { "chn":"1", "dev":"PSU1" } + ] + } + }, + + "FAN-CTRL": + { + "dev_info": { "device_type":"FAN", "device_name":"FAN-CTRL", "device_parent":"MUX1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2", "dev_addr":"0x66", "dev_type":"fan_ctrl"}, + "dev_attr": { "num_fantrays":"6"}, + "attr_list": + [ + { "attr_name":"fan1_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x0F", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan2_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x0F", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan3_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x0F", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan4_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x0F", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan5_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x0F", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan6_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x0F", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan7_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x0F", "attr_mask":"0x8", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan8_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x0F", "attr_mask":"0x8", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan9_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x0F", "attr_mask":"0x10", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan10_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x0F", "attr_mask":"0x10", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan11_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x0F", "attr_mask":"0x20", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan12_present", "attr_devtype":"FAN-CTRL", "attr_offset":"0x0F", "attr_mask":"0x20", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"fan1_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x10", "attr_mask":"0x1", "attr_cmpval":"0x1", "attr_len":"1"}, + { "attr_name":"fan2_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x10", "attr_mask":"0x1", "attr_cmpval":"0x1", "attr_len":"1"}, + { "attr_name":"fan3_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x10", "attr_mask":"0x2", "attr_cmpval":"0x2", "attr_len":"1"}, + { "attr_name":"fan4_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x10", "attr_mask":"0x2", "attr_cmpval":"0x2", "attr_len":"1"}, + { "attr_name":"fan5_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x10", "attr_mask":"0x4", "attr_cmpval":"0x4", "attr_len":"1"}, + { "attr_name":"fan6_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x10", "attr_mask":"0x4", "attr_cmpval":"0x4", "attr_len":"1"}, + { "attr_name":"fan7_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x10", "attr_mask":"0x8", "attr_cmpval":"0x8", "attr_len":"1"}, + { "attr_name":"fan8_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x10", "attr_mask":"0x8", "attr_cmpval":"0x8", "attr_len":"1"}, + { "attr_name":"fan9_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x10", "attr_mask":"0x10", "attr_cmpval":"0x10", "attr_len":"1"}, + { "attr_name":"fan10_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x10", "attr_mask":"0x10", "attr_cmpval":"0x10", "attr_len":"1"}, + { "attr_name":"fan11_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x10", "attr_mask":"0x20", "attr_cmpval":"0x20", "attr_len":"1"}, + { "attr_name":"fan12_direction", "attr_devtype":"FAN-CTRL", "attr_offset":"0x10", "attr_mask":"0x20", "attr_cmpval":"0x20", "attr_len":"1"}, + { "attr_name":"fan1_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x12", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"100", "attr_is_divisor":0}, + { "attr_name":"fan2_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x22", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"100" , "attr_is_divisor":0}, + { "attr_name":"fan3_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x13", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"100", "attr_is_divisor":0}, + { "attr_name":"fan4_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x23", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"100" , "attr_is_divisor":0}, + { "attr_name":"fan5_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x14", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"100", "attr_is_divisor":0}, + { "attr_name":"fan6_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x24", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"100" , "attr_is_divisor":0}, + { "attr_name":"fan7_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x15", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"100", "attr_is_divisor":0}, + { "attr_name":"fan8_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x25", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"100" , "attr_is_divisor":0}, + { "attr_name":"fan9_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x16", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"100", "attr_is_divisor":0}, + { "attr_name":"fan10_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x26", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"100" , "attr_is_divisor":0}, + { "attr_name":"fan11_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x17", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"100", "attr_is_divisor":0}, + { "attr_name":"fan12_input", "attr_devtype":"FAN-CTRL", "attr_offset":"0x27", "attr_mask":"0xFF", "attr_len":"1", "attr_mult":"100" , "attr_is_divisor":0}, + { "attr_name":"fan1_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x11", "attr_mask":"0x0F", "attr_len":"1" }, + { "attr_name":"fan2_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x11", "attr_mask":"0x0F", "attr_len":"1" }, + { "attr_name":"fan3_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x11", "attr_mask":"0x0F", "attr_len":"1" }, + { "attr_name":"fan4_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x11", "attr_mask":"0x0F", "attr_len":"1" }, + { "attr_name":"fan5_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x11", "attr_mask":"0x0F", "attr_len":"1" }, + { "attr_name":"fan6_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x11", "attr_mask":"0x0F", "attr_len":"1" }, + { "attr_name":"fan7_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x11", "attr_mask":"0x0F", "attr_len":"1" }, + { "attr_name":"fan8_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x11", "attr_mask":"0x0F", "attr_len":"1" }, + { "attr_name":"fan9_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x11", "attr_mask":"0x0F", "attr_len":"1" }, + { "attr_name":"fan10_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x11", "attr_mask":"0x0F", "attr_len":"1" }, + { "attr_name":"fan11_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x11", "attr_mask":"0x0F", "attr_len":"1" }, + { "attr_name":"fan12_pwm", "attr_devtype":"FAN-CTRL", "attr_offset":"0x11", "attr_mask":"0x0F", "attr_len":"1" } + ] + } + }, + + "TEMP1" : + { + "dev_info": { "device_type":"TEMP_SENSOR", "device_name":"TEMP1", "device_parent":"MUX1"}, + "dev_attr": { "display_name":"Temp_1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x3", "dev_addr":"0x48", "dev_type":"lm75"}, + "attr_list": + [ + { "attr_name": "temp1_high_threshold", "drv_attr_name":"temp1_max"}, + { "attr_name": "temp1_max_hyst"}, + { "attr_name": "temp1_input"} + ] + } + }, + + "TEMP2" : + { + "dev_info": { "device_type":"TEMP_SENSOR", "device_name":"TEMP2", "device_parent":"MUX1"}, + "dev_attr": { "display_name":"Temp_2"}, + "i2c": + { + "topo_info": { "parent_bus":"0x3", "dev_addr":"0x49", "dev_type":"lm75"}, + "attr_list": + [ + { "attr_name": "temp1_high_threshold", "drv_attr_name":"temp1_max"}, + { "attr_name": "temp1_max_hyst"}, + { "attr_name": "temp1_input"} + ] + } + }, + + "TEMP3" : + { + "dev_info": { "device_type":"TEMP_SENSOR", "device_name":"TEMP3", "device_parent":"MUX1"}, + "dev_attr": { "display_name":"Temp_3"}, + "i2c": + { + "topo_info": { "parent_bus":"0x3", "dev_addr":"0x4a", "dev_type":"lm75"}, + "attr_list": + [ + { "attr_name": "temp1_high_threshold", "drv_attr_name":"temp1_max"}, + { "attr_name": "temp1_max_hyst"}, + { "attr_name": "temp1_input"} + ] + } + }, + + "TEMP4" : + { + "dev_info": { "device_type":"TEMP_SENSOR", "device_name":"TEMP4", "device_parent":"MUX1"}, + "dev_attr": { "display_name":"Temp_CPU"}, + "i2c": + { + "topo_info": { "parent_bus":"0x3", "dev_addr":"0x4b", "dev_type":"lm75"}, + "attr_list": + [ + { "attr_name": "temp1_high_threshold", "drv_attr_name":"temp1_max"}, + { "attr_name": "temp1_max_hyst"}, + { "attr_name": "temp1_input"} + ] + } + }, + + "CPLD1": + { + "dev_info": { "device_type":"CPLD", "device_name":"CPLD1", "device_parent":"MUX1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x4", "dev_addr":"0x60", "dev_type":"i2c_cpld"}, + "dev_attr":{} + } + }, + + "CPLD2": + { + "dev_info": { "device_type":"CPLD", "device_name":"CPLD2", "device_parent":"MUX1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x5", "dev_addr":"0x62", "dev_type":"i2c_cpld"}, + "dev_attr": { } + } + }, + + "CPLD3": + { + "dev_info": { "device_type":"CPLD", "device_name":"CPLD3", "device_parent":"MUX1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x6", "dev_addr":"0x64", "dev_type":"i2c_cpld"}, + "dev_attr": { } + } + }, + + "SYSSTATUS": + { + "dev_info":{ "device_type":"SYSSTAT", "device_name":"SYSSTATUS"}, + "dev_attr":{ }, + "attr_list": + [ + + { "attr_name":"board_info","attr_devaddr":"0x60", "attr_offset":"0x0","attr_mask":"0xf","attr_len":"0x1"}, + { "attr_name":"cpld1_version","attr_devaddr":"0x60","attr_offset":"0x1","attr_mask":"0xff","attr_len":"0x1"}, + { "attr_name":"power_module_status","attr_devaddr":"0x60","attr_offset":"0x2","attr_mask":"0x2f","attr_len":"0x1"}, + { "attr_name":"system_reset5","attr_devaddr":"0x60","attr_offset":"0x8","attr_mask":"0xff","attr_len":"0x1"}, + { "attr_name":"system_reset6","attr_devaddr":"0x60","attr_offset":"0x9","attr_mask":"0xff","attr_len":"0x1"}, + { "attr_name":"system_reset7","attr_devaddr":"0x60","attr_offset":"0xa","attr_mask":"0xff","attr_len":"0x1"}, + { "attr_name":"misc1","attr_devaddr":"0x60","attr_offset":"0x48","attr_mask":"0xff","attr_len":"0x1"}, + { "attr_name":"cpld2_version","attr_devaddr":"0x62","attr_offset":"0x1","attr_mask":"0xff","attr_len":"0x1"}, + { "attr_name":"cpld3_version","attr_devaddr":"0x64","attr_offset":"0x1","attr_mask":"0xff","attr_len":"0x1"} + + ] + }, + + + "PSU1": + { + "dev_info": { "device_type":"PSU", "device_name":"PSU1", "device_parent":"MUX2"}, + "dev_attr": { "dev_idx":"1", "num_psu_fans": "1"}, + "i2c": + { + "interface": + [ + { "itf":"pmbus", "dev":"PSU1-PMBUS" } + ] + + } + }, + + "PSU1-PMBUS": + { + "dev_info": { "device_type":"PSU-PMBUS", "device_name":"PSU1-PMBUS", "device_parent":"MUX2", "virt_parent":"PSU1"}, + "i2c": + { + "topo_info":{ "parent_bus":"0xb", "dev_addr":"0x5b", "dev_type":"psu_pmbus"}, + "attr_list": + [ + { "attr_name":"psu_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x2", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"psu_model_name", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x9a", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"9" }, + { "attr_name":"psu_power_good", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x2", "attr_mask":"0x28", "attr_cmpval":"0x28", "attr_len":"1"}, + { "attr_name":"psu_mfr_id", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0X99", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"10" }, + { "attr_name":"psu_serial_num", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x9e", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"20" }, + { "attr_name":"psu_fan_dir", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0xc3", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"5"}, + { "attr_name":"psu_v_out", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x8b", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_i_out", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x8c", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_p_out", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x96", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_fan1_speed_rpm", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x90", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_temp1_input", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x8d", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"} + ] + } + }, + + "PSU2": + { + "dev_info": { "device_type":"PSU", "device_name":"PSU2", "device_parent":"MUX2" }, + "dev_attr": { "dev_idx":"2", "num_psu_fans":"1"}, + "i2c": + { + "interface": + [ + { "itf":"pmbus", "dev":"PSU2-PMBUS"} + ] + } + + }, + + "PSU2-PMBUS": + { + "dev_info": {"device_type":"PSU-PMBUS", "device_name":"PSU2-PMBUS", "device_parent":"MUX2", "virt_parent":"PSU2"}, + "i2c": + { + "topo_info": { "parent_bus":"0xa", "dev_addr":"0x58", "dev_type":"psu_pmbus"}, + "attr_list": + [ + { "attr_name":"psu_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x2", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"psu_model_name", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x9a", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"9" }, + { "attr_name":"psu_power_good", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x2", "attr_mask":"0x14", "attr_cmpval":"0x14", "attr_len":"1"}, + { "attr_name":"psu_mfr_id", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0X99", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"10" }, + { "attr_name":"psu_serial_num", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x9e", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"20" }, + { "attr_name":"psu_fan_dir", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0xc3", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"5"}, + { "attr_name":"psu_v_out", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x8b", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_i_out", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x8c", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_p_out", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x96", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_fan1_speed_rpm", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x90", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_temp1_input", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x8d", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"} + ] + } + }, + + "MUX3": + { + "dev_info": { "device_type":"MUX", "device_name":"MUX3", "device_parent":"SMBUS0"}, + "i2c": + { + "topo_info": { "parent_bus":"0x0", "dev_addr":"0x72", "dev_type":"pca9548"}, + "dev_attr": { "virt_bus":"0x12"}, + "channel": + [ + { "chn":"0", "dev":"PORT9" }, + { "chn":"1", "dev":"PORT10" }, + { "chn":"2", "dev":"PORT11" }, + { "chn":"3", "dev":"PORT12" }, + { "chn":"4", "dev":"PORT1" }, + { "chn":"5", "dev":"PORT2" }, + { "chn":"6", "dev":"PORT3" }, + { "chn":"7", "dev":"PORT4" } + ] + } + }, + + "MUX4": + { + "dev_info": { "device_type":"MUX", "device_name":"MUX4", "device_parent":"SMBUS0"}, + "i2c": + { + "topo_info": { "parent_bus":"0x0", "dev_addr":"0x73", "dev_type":"pca9548"}, + "dev_attr": { "virt_bus":"0x1a"}, + "channel": + [ + { "chn":"0", "dev":"PORT6" }, + { "chn":"1", "dev":"PORT5" }, + { "chn":"2", "dev":"PORT8" }, + { "chn":"3", "dev":"PORT7" }, + { "chn":"4", "dev":"PORT13" }, + { "chn":"5", "dev":"PORT14" }, + { "chn":"6", "dev":"PORT15" }, + { "chn":"7", "dev":"PORT16" } + ] + } + }, + + "MUX5": + { + "dev_info": { "device_type":"MUX", "device_name":"MUX5", "device_parent":"SMBUS0"}, + "i2c": + { + "topo_info": { "parent_bus":"0x0", "dev_addr":"0x74", "dev_type":"pca9548"}, + "dev_attr": { "virt_bus":"0x22"}, + "channel": + [ + { "chn":"0", "dev":"PORT17" }, + { "chn":"1", "dev":"PORT18" }, + { "chn":"2", "dev":"PORT19" }, + { "chn":"3", "dev":"PORT20" }, + { "chn":"4", "dev":"PORT25" }, + { "chn":"5", "dev":"PORT26" }, + { "chn":"6", "dev":"PORT27" }, + { "chn":"7", "dev":"PORT28" } + ] + } + }, + + "MUX6": + { + "dev_info": { "device_type":"MUX", "device_name":"MUX6", "device_parent":"SMBUS0"}, + "i2c": + { + "topo_info": { "parent_bus":"0x0", "dev_addr":"0x75", "dev_type":"pca9548"}, + "dev_attr": { "virt_bus":"0x2a"}, + "channel": + [ + { "chn":"0", "dev":"PORT29" }, + { "chn":"1", "dev":"PORT30" }, + { "chn":"2", "dev":"PORT31" }, + { "chn":"3", "dev":"PORT32" }, + { "chn":"4", "dev":"PORT21" }, + { "chn":"5", "dev":"PORT22" }, + { "chn":"6", "dev":"PORT23" }, + { "chn":"7", "dev":"PORT24" } + ] + } + }, + + "LOC_LED": + { + "dev_info": { "device_type":"LED", "device_name":"LOC_LED"}, + "dev_attr": { "index":"0"}, + "i2c" : { + "attr_list": + [ + {"attr_name":"STATUS_LED_COLOR_BLUE", "bits" : "7", "descr" : "", "value" : "0x0", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x41"}, + {"attr_name":"STATUS_LED_COLOR_OFF", "bits" : "7", "descr" : "", "value" : "0x1", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x41"} + ] + } + }, + + "DIAG_LED": + { + "dev_info": { "device_type":"LED", "device_name":"DIAG_LED"}, + "dev_attr": { "index":"0"}, + "i2c" : { + "attr_list": + [ + {"attr_name":"STATUS_LED_COLOR_GREEN", "bits" : "1:0", "descr" : "", "value" : "0x2", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x41"}, + {"attr_name":"STATUS_LED_COLOR_RED", "bits" : "1:0", "descr" : "", "value" : "0x1", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x41"}, + {"attr_name":"STATUS_LED_COLOR_OFF", "bits" : "1:0", "descr" : "", "value" : "0x3", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x41"} + ] + } + + }, + + + "PORT1": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT1", "device_parent":"MUX3"}, + "dev_attr": { "dev_idx":"1"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT1-EEPROM" }, + { "itf":"control", "dev":"PORT1-CTRL" } + ] + } + }, + "PORT1-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT1-EEPROM", "device_parent":"MUX3", "virt_parent":"PORT1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x16", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT1-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT1-CTRL", "device_parent":"MUX3", "virt_parent":"PORT1"}, + "i2c": + { + "topo_info": { "parent_bus":"0x16", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x30", "attr_mask":"0x0", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x04", "attr_mask":"0x0", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x10", "attr_mask":"0x0", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT2": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT2", "device_parent":"MUX3"}, + "dev_attr": { "dev_idx":"2"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT2-EEPROM" }, + { "itf":"control", "dev":"PORT2-CTRL" } + ] + } + }, + "PORT2-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT2-EEPROM", "device_parent":"MUX3", "virt_parent":"PORT2"}, + "i2c": + { + "topo_info": { "parent_bus":"0x17", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT2-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT2-CTRL", "device_parent":"MUX3", "virt_parent":"PORT2"}, + "i2c": + { + "topo_info": { "parent_bus":"0x17", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x30", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x04", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x10", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT3": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT3", "device_parent":"MUX3"}, + "dev_attr": { "dev_idx":"3"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT3-EEPROM" }, + { "itf":"control", "dev":"PORT3-CTRL" } + ] + } + }, + "PORT3-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT3-EEPROM", "device_parent":"MUX3", "virt_parent":"PORT3"}, + "i2c": + { + "topo_info": { "parent_bus":"0x18", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT3-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT3-CTRL", "device_parent":"MUX3", "virt_parent":"PORT3"}, + "i2c": + { + "topo_info": { "parent_bus":"0x18", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x30", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x04", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x10", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT4": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT4", "device_parent":"MUX3"}, + "dev_attr": { "dev_idx":"4"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT4-EEPROM" }, + { "itf":"control", "dev":"PORT4-CTRL" } + ] + } + }, + "PORT4-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT4-EEPROM", "device_parent":"MUX3", "virt_parent":"PORT4"}, + "i2c": + { + "topo_info": { "parent_bus":"0x19", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT4-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT4-CTRL", "device_parent":"MUX3", "virt_parent":"PORT4"}, + "i2c": + { + "topo_info": { "parent_bus":"0x19", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x30", "attr_mask":"0x3", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x04", "attr_mask":"0x3", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x10", "attr_mask":"0x3", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT5": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT5", "device_parent":"MUX4"}, + "dev_attr": { "dev_idx":"5"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT5-EEPROM" }, + { "itf":"control", "dev":"PORT5-CTRL" } + ] + } + }, + "PORT5-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT5-EEPROM", "device_parent":"MUX4", "virt_parent":"PORT5"}, + "i2c": + { + "topo_info": { "parent_bus":"0x1b", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT5-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT5-CTRL", "device_parent":"MUX4", "virt_parent":"PORT5"}, + "i2c": + { + "topo_info": { "parent_bus":"0x1b", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x30", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x04", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x10", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT6": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT6", "device_parent":"MUX4"}, + "dev_attr": { "dev_idx":"6"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT6-EEPROM" }, + { "itf":"control", "dev":"PORT6-CTRL" } + ] + } + }, + "PORT6-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT6-EEPROM", "device_parent":"MUX4", "virt_parent":"PORT6"}, + "i2c": + { + "topo_info": { "parent_bus":"0x1a", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT6-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT6-CTRL", "device_parent":"MUX4", "virt_parent":"PORT6"}, + "i2c": + { + "topo_info": { "parent_bus":"0x1a", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x30", "attr_mask":"0x5", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x04", "attr_mask":"0x5", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x10", "attr_mask":"0x5", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT7": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT7", "device_parent":"MUX4"}, + "dev_attr": { "dev_idx":"7"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT7-EEPROM" }, + { "itf":"control", "dev":"PORT7-CTRL" } + ] + } + }, + "PORT7-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT7-EEPROM", "device_parent":"MUX4", "virt_parent":"PORT7"}, + "i2c": + { + "topo_info": { "parent_bus":"0x1d", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT7-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT7-CTRL", "device_parent":"MUX4", "virt_parent":"PORT7"}, + "i2c": + { + "topo_info": { "parent_bus":"0x1d", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x30", "attr_mask":"0x6", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x04", "attr_mask":"0x6", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x10", "attr_mask":"0x6", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT8": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT8", "device_parent":"MUX4"}, + "dev_attr": { "dev_idx":"8"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT8-EEPROM" }, + { "itf":"control", "dev":"PORT8-CTRL" } + ] + } + }, + "PORT8-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT8-EEPROM", "device_parent":"MUX4", "virt_parent":"PORT8"}, + "i2c": + { + "topo_info": { "parent_bus":"0x1c", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT8-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT8-CTRL", "device_parent":"MUX4", "virt_parent":"PORT8"}, + "i2c": + { + "topo_info": { "parent_bus":"0x1c", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x30", "attr_mask":"0x7", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x04", "attr_mask":"0x7", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x10", "attr_mask":"0x7", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT9": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT9", "device_parent":"MUX3"}, + "dev_attr": { "dev_idx":"9"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT9-EEPROM" }, + { "itf":"control", "dev":"PORT9-CTRL" } + ] + } + }, + "PORT9-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT9-EEPROM", "device_parent":"MUX3", "virt_parent":"PORT9"}, + "i2c": + { + "topo_info": { "parent_bus":"0x12", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT9-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT9-CTRL", "device_parent":"MUX3", "virt_parent":"PORT9"}, + "i2c": + { + "topo_info": { "parent_bus":"0x12", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x31", "attr_mask":"0x0", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x05", "attr_mask":"0x0", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x11", "attr_mask":"0x0", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT10": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT10", "device_parent":"MUX3"}, + "dev_attr": { "dev_idx":"10"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT10-EEPROM" }, + { "itf":"control", "dev":"PORT10-CTRL" } + ] + } + }, + "PORT10-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT10-EEPROM", "device_parent":"MUX3", "virt_parent":"PORT10"}, + "i2c": + { + "topo_info": { "parent_bus":"0x13", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT10-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT10-CTRL", "device_parent":"MUX3", "virt_parent":"PORT10"}, + "i2c": + { + "topo_info": { "parent_bus":"0x13", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x31", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x05", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x11", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT11": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT11", "device_parent":"MUX3"}, + "dev_attr": { "dev_idx":"11"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT11-EEPROM" }, + { "itf":"control", "dev":"PORT11-CTRL" } + ] + } + }, + "PORT11-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT11-EEPROM", "device_parent":"MUX3", "virt_parent":"PORT11"}, + "i2c": + { + "topo_info": { "parent_bus":"0x14", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT11-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT11-CTRL", "device_parent":"MUX3", "virt_parent":"PORT11"}, + "i2c": + { + "topo_info": { "parent_bus":"0x14", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x31", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x05", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x11", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT12": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT12", "device_parent":"MUX3"}, + "dev_attr": { "dev_idx":"12"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT12-EEPROM" }, + { "itf":"control", "dev":"PORT12-CTRL" } + ] + } + }, + "PORT12-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT12-EEPROM", "device_parent":"MUX3", "virt_parent":"PORT12"}, + "i2c": + { + "topo_info": { "parent_bus":"0x15", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT12-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT12-CTRL", "device_parent":"MUX3", "virt_parent":"PORT12"}, + "i2c": + { + "topo_info": { "parent_bus":"0x15", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x31", "attr_mask":"0x3", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x05", "attr_mask":"0x3", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x11", "attr_mask":"0x3", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT13": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT13", "device_parent":"MUX4"}, + "dev_attr": { "dev_idx":"13"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT13-EEPROM" }, + { "itf":"control", "dev":"PORT13-CTRL" } + ] + } + }, + "PORT13-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT13-EEPROM", "device_parent":"MUX4", "virt_parent":"PORT13"}, + "i2c": + { + "topo_info": { "parent_bus":"0x1e", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT13-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT13-CTRL", "device_parent":"MUX4", "virt_parent":"PORT13"}, + "i2c": + { + "topo_info": { "parent_bus":"0x1e", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x31", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x05", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x11", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT14": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT14", "device_parent":"MUX4"}, + "dev_attr": { "dev_idx":"14"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT14-EEPROM" }, + { "itf":"control", "dev":"PORT14-CTRL" } + ] + } + }, + "PORT14-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT14-EEPROM", "device_parent":"MUX4", "virt_parent":"PORT14"}, + "i2c": + { + "topo_info": { "parent_bus":"0x1f", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT14-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT14-CTRL", "device_parent":"MUX4", "virt_parent":"PORT14"}, + "i2c": + { + "topo_info": { "parent_bus":"0x1f", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x31", "attr_mask":"0x5", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x05", "attr_mask":"0x5", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x11", "attr_mask":"0x5", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT15": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT15", "device_parent":"MUX4"}, + "dev_attr": { "dev_idx":"15"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT15-EEPROM" }, + { "itf":"control", "dev":"PORT15-CTRL" } + ] + } + }, + "PORT15-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT15-EEPROM", "device_parent":"MUX4", "virt_parent":"PORT15"}, + "i2c": + { + "topo_info": { "parent_bus":"0x20", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT15-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT15-CTRL", "device_parent":"MUX4", "virt_parent":"PORT15"}, + "i2c": + { + "topo_info": { "parent_bus":"0x20", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x31", "attr_mask":"0x6", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x05", "attr_mask":"0x6", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x11", "attr_mask":"0x6", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT16": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT16", "device_parent":"MUX4"}, + "dev_attr": { "dev_idx":"16"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT16-EEPROM" }, + { "itf":"control", "dev":"PORT16-CTRL" } + ] + } + }, + "PORT16-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT16-EEPROM", "device_parent":"MUX4", "virt_parent":"PORT16"}, + "i2c": + { + "topo_info": { "parent_bus":"0x21", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT16-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT16-CTRL", "device_parent":"MUX4", "virt_parent":"PORT16"}, + "i2c": + { + "topo_info": { "parent_bus":"0x21", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x31", "attr_mask":"0x7", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x05", "attr_mask":"0x7", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x11", "attr_mask":"0x7", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT17": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT17", "device_parent":"MUX5"}, + "dev_attr": { "dev_idx":"17"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT17-EEPROM" }, + { "itf":"control", "dev":"PORT17-CTRL" } + ] + } + }, + "PORT17-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT17-EEPROM", "device_parent":"MUX5", "virt_parent":"PORT17"}, + "i2c": + { + "topo_info": { "parent_bus":"0x22", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT17-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT17-CTRL", "device_parent":"MUX5", "virt_parent":"PORT17"}, + "i2c": + { + "topo_info": { "parent_bus":"0x22", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x32", "attr_mask":"0x0", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x06", "attr_mask":"0x0", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x12", "attr_mask":"0x0", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT18": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT18", "device_parent":"MUX5"}, + "dev_attr": { "dev_idx":"18"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT18-EEPROM" }, + { "itf":"control", "dev":"PORT18-CTRL" } + ] + } + }, + "PORT18-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT18-EEPROM", "device_parent":"MUX5", "virt_parent":"PORT18"}, + "i2c": + { + "topo_info": { "parent_bus":"0x23", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT18-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT18-CTRL", "device_parent":"MUX5", "virt_parent":"PORT18"}, + "i2c": + { + "topo_info": { "parent_bus":"0x23", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x32", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x06", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x12", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT19": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT19", "device_parent":"MUX5"}, + "dev_attr": { "dev_idx":"19"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT19-EEPROM" }, + { "itf":"control", "dev":"PORT19-CTRL" } + ] + } + }, + "PORT19-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT19-EEPROM", "device_parent":"MUX5", "virt_parent":"PORT19"}, + "i2c": + { + "topo_info": { "parent_bus":"0x24", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT19-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT19-CTRL", "device_parent":"MUX5", "virt_parent":"PORT19"}, + "i2c": + { + "topo_info": { "parent_bus":"0x24", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x32", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x06", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x12", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT20": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT20", "device_parent":"MUX5"}, + "dev_attr": { "dev_idx":"20"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT20-EEPROM" }, + { "itf":"control", "dev":"PORT20-CTRL" } + ] + } + }, + "PORT20-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT20-EEPROM", "device_parent":"MUX5", "virt_parent":"PORT20"}, + "i2c": + { + "topo_info": { "parent_bus":"0x25", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT20-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT20-CTRL", "device_parent":"MUX5", "virt_parent":"PORT20"}, + "i2c": + { + "topo_info": { "parent_bus":"0x25", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x32", "attr_mask":"0x3", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x06", "attr_mask":"0x3", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x12", "attr_mask":"0x3", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT21": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT21", "device_parent":"MUX6"}, + "dev_attr": { "dev_idx":"21"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT21-EEPROM" }, + { "itf":"control", "dev":"PORT21-CTRL" } + ] + } + }, + "PORT21-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT21-EEPROM", "device_parent":"MUX6", "virt_parent":"PORT21"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2e", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT21-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT21-CTRL", "device_parent":"MUX6", "virt_parent":"PORT21"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2e", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x32", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x06", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x12", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT22": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT22", "device_parent":"MUX6"}, + "dev_attr": { "dev_idx":"22"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT22-EEPROM" }, + { "itf":"control", "dev":"PORT22-CTRL" } + ] + } + }, + "PORT22-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT22-EEPROM", "device_parent":"MUX6", "virt_parent":"PORT22"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2f", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT22-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT22-CTRL", "device_parent":"MUX6", "virt_parent":"PORT22"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2f", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x32", "attr_mask":"0x5", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x06", "attr_mask":"0x5", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x12", "attr_mask":"0x5", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT23": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT23", "device_parent":"MUX6"}, + "dev_attr": { "dev_idx":"23"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT23-EEPROM" }, + { "itf":"control", "dev":"PORT23-CTRL" } + ] + } + }, + "PORT23-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT23-EEPROM", "device_parent":"MUX6", "virt_parent":"PORT23"}, + "i2c": + { + "topo_info": { "parent_bus":"0x30", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT23-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT23-CTRL", "device_parent":"MUX6", "virt_parent":"PORT23"}, + "i2c": + { + "topo_info": { "parent_bus":"0x30", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x32", "attr_mask":"0x6", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x06", "attr_mask":"0x6", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x12", "attr_mask":"0x6", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT24": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT24", "device_parent":"MUX6"}, + "dev_attr": { "dev_idx":"24"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT24-EEPROM" }, + { "itf":"control", "dev":"PORT24-CTRL" } + ] + } + }, + "PORT24-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT24-EEPROM", "device_parent":"MUX6", "virt_parent":"PORT24"}, + "i2c": + { + "topo_info": { "parent_bus":"0x31", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT24-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT24-CTRL", "device_parent":"MUX6", "virt_parent":"PORT24"}, + "i2c": + { + "topo_info": { "parent_bus":"0x31", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x32", "attr_mask":"0x7", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x06", "attr_mask":"0x7", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x12", "attr_mask":"0x7", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT25": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT25", "device_parent":"MUX5"}, + "dev_attr": { "dev_idx":"25"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT25-EEPROM" }, + { "itf":"control", "dev":"PORT25-CTRL" } + ] + } + }, + "PORT25-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT25-EEPROM", "device_parent":"MUX5", "virt_parent":"PORT25"}, + "i2c": + { + "topo_info": { "parent_bus":"0x26", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT25-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT25-CTRL", "device_parent":"MUX5", "virt_parent":"PORT25"}, + "i2c": + { + "topo_info": { "parent_bus":"0x26", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x33", "attr_mask":"0x0", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x07", "attr_mask":"0x0", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x13", "attr_mask":"0x0", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT26": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT26", "device_parent":"MUX5"}, + "dev_attr": { "dev_idx":"26"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT26-EEPROM" }, + { "itf":"control", "dev":"PORT26-CTRL" } + ] + } + }, + "PORT26-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT26-EEPROM", "device_parent":"MUX5", "virt_parent":"PORT26"}, + "i2c": + { + "topo_info": { "parent_bus":"0x27", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT26-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT26-CTRL", "device_parent":"MUX5", "virt_parent":"PORT26"}, + "i2c": + { + "topo_info": { "parent_bus":"0x27", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x33", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x07", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x13", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT27": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT27", "device_parent":"MUX5"}, + "dev_attr": { "dev_idx":"27"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT27-EEPROM" }, + { "itf":"control", "dev":"PORT27-CTRL" } + ] + } + }, + "PORT27-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT27-EEPROM", "device_parent":"MUX5", "virt_parent":"PORT27"}, + "i2c": + { + "topo_info": { "parent_bus":"0x28", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT27-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT27-CTRL", "device_parent":"MUX5", "virt_parent":"PORT27"}, + "i2c": + { + "topo_info": { "parent_bus":"0x28", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x33", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x07", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x13", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT28": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT28", "device_parent":"MUX5"}, + "dev_attr": { "dev_idx":"28"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT28-EEPROM" }, + { "itf":"control", "dev":"PORT28-CTRL" } + ] + } + }, + "PORT28-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT28-EEPROM", "device_parent":"MUX5", "virt_parent":"PORT28"}, + "i2c": + { + "topo_info": { "parent_bus":"0x29", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT28-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT28-CTRL", "device_parent":"MUX5", "virt_parent":"PORT28"}, + "i2c": + { + "topo_info": { "parent_bus":"0x29", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x33", "attr_mask":"0x3", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x07", "attr_mask":"0x3", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x13", "attr_mask":"0x3", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT29": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT29", "device_parent":"MUX6"}, + "dev_attr": { "dev_idx":"29"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT29-EEPROM" }, + { "itf":"control", "dev":"PORT29-CTRL" } + ] + } + }, + "PORT29-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT29-EEPROM", "device_parent":"MUX6", "virt_parent":"PORT29"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2a", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT29-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT29-CTRL", "device_parent":"MUX6", "virt_parent":"PORT29"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2a", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x33", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x07", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x13", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT30": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT30", "device_parent":"MUX6"}, + "dev_attr": { "dev_idx":"30"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT30-EEPROM" }, + { "itf":"control", "dev":"PORT30-CTRL" } + ] + } + }, + "PORT30-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT30-EEPROM", "device_parent":"MUX6", "virt_parent":"PORT30"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2b", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT30-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT30-CTRL", "device_parent":"MUX6", "virt_parent":"PORT30"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2b", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x33", "attr_mask":"0x5", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x07", "attr_mask":"0x5", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x13", "attr_mask":"0x5", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT31": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT31", "device_parent":"MUX6"}, + "dev_attr": { "dev_idx":"31"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT31-EEPROM" }, + { "itf":"control", "dev":"PORT31-CTRL" } + ] + } + }, + "PORT31-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT31-EEPROM", "device_parent":"MUX6", "virt_parent":"PORT31"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2c", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT31-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT31-CTRL", "device_parent":"MUX6", "virt_parent":"PORT31"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2c", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x33", "attr_mask":"0x6", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x07", "attr_mask":"0x6", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x13", "attr_mask":"0x6", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + }, + + "PORT32": + { + "dev_info": { "device_type":"QSFP", "device_name":"PORT32", "device_parent":"MUX6"}, + "dev_attr": { "dev_idx":"32"}, + "i2c": + { + "interface": + [ + { "itf":"eeprom", "dev":"PORT32-EEPROM" }, + { "itf":"control", "dev":"PORT32-CTRL" } + ] + } + }, + "PORT32-EEPROM": + { + "dev_info": { "device_type":"", "device_name":"PORT32-EEPROM", "device_parent":"MUX6", "virt_parent":"PORT32"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2d", "dev_addr":"0x50", "dev_type":"optoe1"}, + "attr_list": + [ + { "attr_name":"eeprom"} + ] + } + }, + "PORT32-CTRL": + { + "dev_info": { "device_type":"", "device_name":"PORT32-CTRL", "device_parent":"MUX6", "virt_parent":"PORT32"}, + "i2c": + { + "topo_info": { "parent_bus":"0x2d", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, + "attr_list": + [ + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x33", "attr_mask":"0x7", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x07", "attr_mask":"0x7", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x13", "attr_mask":"0x7", "attr_cmpval":"0x0", "attr_len":"1"} + ] + } + } + +} diff --git a/device/accton/x86_64-accton_as7712_32x-r0/pddf_support b/device/accton/x86_64-accton_as7712_32x-r0/pddf_support new file mode 100644 index 00000000000..e69de29bb2d diff --git a/device/accton/x86_64-accton_as7712_32x-r0/pmon_daemon_control.json b/device/accton/x86_64-accton_as7712_32x-r0/pmon_daemon_control.json index 584a14b9d94..59bdebeb4b5 100644 --- a/device/accton/x86_64-accton_as7712_32x-r0/pmon_daemon_control.json +++ b/device/accton/x86_64-accton_as7712_32x-r0/pmon_daemon_control.json @@ -1,5 +1,5 @@ { "skip_ledd": true, - "skip_thermalctld": true + "skip_thermalctld": true, + "skip_pcied": true } - diff --git a/device/accton/x86_64-accton_as7726_32x-r0/pddf/pddf-device.json b/device/accton/x86_64-accton_as7726_32x-r0/pddf/pddf-device.json index 8a4caec2772..aac3268c9e0 100644 --- a/device/accton/x86_64-accton_as7726_32x-r0/pddf/pddf-device.json +++ b/device/accton/x86_64-accton_as7726_32x-r0/pddf/pddf-device.json @@ -50,6 +50,10 @@ "pddf_fan_module", "pddf_led_module", "pddf_sysstatus_module" + ], + "custom_kos": + [ + "pddf_custom_psu" ] }, @@ -1631,7 +1635,8 @@ { "interface": [ - { "itf":"pmbus", "dev":"PSU2-PMBUS"} + { "itf":"pmbus", "dev":"PSU2-PMBUS"}, + { "itf":"eeprom","dev":"PSU2-EEPROM" } ] } }, @@ -1644,19 +1649,31 @@ "topo_info": { "parent_bus":"0x31", "dev_addr":"0x58", "dev_type":"psu_pmbus"}, "attr_list": [ - { "attr_name":"psu_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x2", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, - { "attr_name":"psu_model_name", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x9a", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"10" }, + { "attr_name":"psu_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x2", "attr_mask":"0x1", "attr_cmpval":"0x0", "attr_len":"1"}, { "attr_name":"psu_power_good", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x2", "attr_mask":"0x14", "attr_cmpval":"0x14", "attr_len":"1"}, - { "attr_name":"psu_mfr_id", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0X99", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"10" }, - { "attr_name":"psu_serial_num", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x9e", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"20" }, + { "attr_name":"psu_mfr_id", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0X99", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"10" }, { "attr_name":"psu_fan_dir", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0xc3", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"5"}, { "attr_name":"psu_v_out", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x8b", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, { "attr_name":"psu_i_out", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x8c", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, { "attr_name":"psu_p_out", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x96", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, - { "attr_name":"psu_fan1_speed_rpm", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x90", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"} + { "attr_name":"psu_fan1_speed_rpm", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x90", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_temp1_input", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x8d", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"} ] } }, + "PSU2-EEPROM": + { + "dev_info": { "device_type":"PSU-EEPROM", "device_name":"PSU1-EEPROM", "device_parent":"MUX7", "virt_parent":"PSU2"}, + "i2c": + { + "topo_info":{ "parent_bus":"0x31", "dev_addr":"0x50", "dev_type":"psu_eeprom"}, + "attr_list": + [ + { "attr_name":"psu_model_name", "attr_devaddr":"0x50", "attr_devtype":"eeprom", "attr_offset":"0x15", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"11" }, + { "attr_name":"psu_serial_num", "attr_devaddr":"0x50", "attr_devtype":"eeprom", "attr_offset":"0x2e", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"17" } + ] + } + }, "PSU1": { @@ -1666,7 +1683,8 @@ { "interface": [ - { "itf":"pmbus", "dev":"PSU1-PMBUS" } + { "itf":"pmbus", "dev":"PSU1-PMBUS" }, + { "itf":"eeprom","dev":"PSU1-EEPROM" } ] } }, @@ -1679,20 +1697,31 @@ "topo_info":{ "parent_bus":"0x32", "dev_addr":"0x5b", "dev_type":"psu_pmbus"}, "attr_list": [ - { "attr_name":"psu_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x2", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, - { "attr_name":"psu_model_name", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x9a", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"10" }, + { "attr_name":"psu_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x2", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, { "attr_name":"psu_power_good", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x2", "attr_mask":"0x28", "attr_cmpval":"0x28", "attr_len":"1"}, - { "attr_name":"psu_mfr_id", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0X99", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"10" }, - { "attr_name":"psu_serial_num", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x9e", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"20" }, + { "attr_name":"psu_mfr_id", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0X99", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"10" }, { "attr_name":"psu_fan_dir", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0xc3", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"5"}, { "attr_name":"psu_v_out", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x8b", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, { "attr_name":"psu_i_out", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x8c", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, { "attr_name":"psu_p_out", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x96", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, - { "attr_name":"psu_fan1_speed_rpm", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x90", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"} + { "attr_name":"psu_fan1_speed_rpm", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x90", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_temp1_input", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x8d", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"} ] } }, - + "PSU1-EEPROM": + { + "dev_info": { "device_type":"PSU-EEPROM", "device_name":"PSU1-EEPROM", "device_parent":"MUX7", "virt_parent":"PSU1"}, + "i2c": + { + "topo_info":{ "parent_bus":"0x32", "dev_addr":"0x53", "dev_type":"psu_eeprom"}, + "attr_list": + [ + { "attr_name":"psu_model_name", "attr_devaddr":"0x53", "attr_devtype":"eeprom", "attr_offset":"0x15", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"11" }, + { "attr_name":"psu_serial_num", "attr_devaddr":"0x53", "attr_devtype":"eeprom", "attr_offset":"0x2e", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"17" } + ] + } + }, "FAN-CTRL": { "dev_info": { "device_type":"FAN", "device_name":"FAN-CTRL", "device_parent":"MUX7"}, @@ -1762,7 +1791,7 @@ "dev_info": { "device_type":"TEMP_SENSOR", "device_name":"TEMP1", "device_parent":"MUX7"}, "i2c": { - "topo_info": { "parent_bus":"0x37", "dev_addr":"0x4c", "dev_type":"lm75"}, + "topo_info": { "parent_bus":"0x36", "dev_addr":"0x4c", "dev_type":"lm75"}, "attr_list": [ { "attr_name": "temp1_high_threshold", "drv_attr_name":"temp1_max"}, @@ -1825,7 +1854,7 @@ "topo_info": { "parent_bus":"0x37", "dev_addr":"0x4b", "dev_type":"lm75"}, "attr_list": [ - { "attr_name": "temp1_max"}, + { "attr_name": "temp1_high_threshold", "drv_attr_name":"temp1_max"}, { "attr_name": "temp1_max_hyst"}, { "attr_name": "temp1_input"} ] @@ -1860,8 +1889,8 @@ "i2c" : { "attr_list": [ - {"attr_name":"blue", "descr" : "Blue", "bits" : "7", "value" : "0x0", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x41"}, - {"attr_name":"off", "descr" : "Off", "bits" : "7", "value" : "0x1", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x41"} + {"attr_name":"STATUS_LED_COLOR_BLUE", "descr" : "", "bits" : "7", "value" : "0x0", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x41"}, + {"attr_name":"STATUS_LED_COLOR_OFF", "descr" : "", "bits" : "7", "value" : "0x1", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x41"} ] } }, @@ -1873,9 +1902,9 @@ "i2c" : { "attr_list": [ - {"attr_name":"green", "descr" : "Green", "bits" : "1:0", "value" : "0x2", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x41"}, - {"attr_name":"red", "descr" : "Red" ,"bits" : "1:0", "value" : "0x1", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x41"}, - {"attr_name":"off", "descr" : "Off" ,"bits" : "1:0", "value" : "0x3", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x41"} + {"attr_name":"STATUS_LED_COLOR_GREEN", "descr" : "", "bits" : "1:0", "value" : "0x2", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x41"}, + {"attr_name":"STATUS_LED_COLOR_RED", "descr" : "" ,"bits" : "1:0", "value" : "0x1", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x41"}, + {"attr_name":"STATUS_LED_COLOR_OFF", "descr" : "" ,"bits" : "1:0", "value" : "0x3", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x41"} ] } diff --git a/device/accton/x86_64-accton_as7726_32x-r0/pmon_daemon_control.json b/device/accton/x86_64-accton_as7726_32x-r0/pmon_daemon_control.json index 584a14b9d94..0d3f1fb4561 100644 --- a/device/accton/x86_64-accton_as7726_32x-r0/pmon_daemon_control.json +++ b/device/accton/x86_64-accton_as7726_32x-r0/pmon_daemon_control.json @@ -1,5 +1,6 @@ { "skip_ledd": true, + "skip_pcied": true, "skip_thermalctld": true } diff --git a/device/accton/x86_64-accton_as7816_64x-r0/plugins/psuutil.py b/device/accton/x86_64-accton_as7816_64x-r0/plugins/psuutil.py index b05cf3e477a..7a7d92ec908 100755 --- a/device/accton/x86_64-accton_as7816_64x-r0/plugins/psuutil.py +++ b/device/accton/x86_64-accton_as7816_64x-r0/plugins/psuutil.py @@ -28,6 +28,24 @@ def __init__(self): 2: "9-0050", } + def get_psu_mapping(self, index): + if index is None: + return False + + for id in self.psu_mapping: + node = self.psu_path + self.psu_mapping[id] + "/name" + + try: + with open(node, 'r') as psu_name_fd: + psu_name = psu_name_fd.read() + except IOError: + return False + + if psu_name.find("as7816_64x_psu" + str(index)) != -1: + return self.psu_mapping[id] + + return str() + def get_num_psus(self): return len(self.psu_mapping) @@ -36,7 +54,7 @@ def get_psu_status(self, index): return False status = 0 - node = self.psu_path + self.psu_mapping[index]+self.psu_oper_status + node = self.psu_path + self.get_psu_mapping(index) + self.psu_oper_status try: with open(node, 'r') as power_status: status = int(power_status.read()) @@ -50,7 +68,7 @@ def get_psu_presence(self, index): return False status = 0 - node = self.psu_path + self.psu_mapping[index] + self.psu_presence + node = self.psu_path + self.get_psu_mapping(index) + self.psu_presence try: with open(node, 'r') as presence_status: status = int(presence_status.read()) diff --git a/device/accton/x86_64-accton_as7926_40xfb-r0/Accton-AS7926-40XFB/port_config.ini b/device/accton/x86_64-accton_as7926_40xfb-r0/Accton-AS7926-40XFB/port_config.ini new file mode 100644 index 00000000000..5de221e6e61 --- /dev/null +++ b/device/accton/x86_64-accton_as7926_40xfb-r0/Accton-AS7926-40XFB/port_config.ini @@ -0,0 +1,56 @@ +# name lanes alias index speed +Ethernet0 0,1 hundredGigE1 1 100000 +Ethernet2 2,3 hundredGigE2 2 100000 +Ethernet4 4,5 hundredGigE3 3 100000 +Ethernet6 6,7 hundredGigE4 4 100000 +Ethernet8 8,9 hundredGigE5 5 100000 +Ethernet10 10,11 hundredGigE6 6 100000 +Ethernet12 12,13 hundredGigE7 7 100000 +Ethernet14 14,15 hundredGigE8 8 100000 +Ethernet16 16,17 hundredGigE9 9 100000 +Ethernet18 18,19 hundredGigE10 10 100000 +Ethernet20 20,21 hundredGigE11 11 100000 +Ethernet22 22,23 hundredGigE12 12 100000 +Ethernet24 24,25 hundredGigE13 13 100000 +Ethernet26 26,27 hundredGigE14 14 100000 +Ethernet28 28,29 hundredGigE15 15 100000 +Ethernet30 30,31 hundredGigE16 16 100000 +Ethernet32 32,33 hundredGigE17 17 100000 +Ethernet34 34,35 hundredGigE18 18 100000 +Ethernet36 36,37 hundredGigE19 19 100000 +Ethernet38 38,39 hundredGigE20 20 100000 +Ethernet40 40,41 hundredGigE21 21 100000 +Ethernet42 42,43 hundredGigE22 22 100000 +Ethernet44 44,45 hundredGigE23 23 100000 +Ethernet46 46,47 hundredGigE24 24 100000 +Ethernet48 88,89 hundredGigE25 25 100000 +Ethernet50 90,91 hundredGigE26 26 100000 +Ethernet52 92,93 hundredGigE27 27 100000 +Ethernet54 94,95 hundredGigE28 28 100000 +Ethernet56 80,81 hundredGigE29 29 100000 +Ethernet58 82,83 hundredGigE30 30 100000 +Ethernet60 84,85 hundredGigE31 31 100000 +Ethernet62 86,87 hundredGigE32 32 100000 +Ethernet64 72,73 hundredGigE33 33 100000 +Ethernet66 74,75 hundredGigE34 34 100000 +Ethernet68 76,77 hundredGigE35 35 100000 +Ethernet70 78,79 hundredGigE36 36 100000 +Ethernet72 64,65 hundredGigE37 37 100000 +Ethernet74 66,67 hundredGigE38 38 100000 +Ethernet76 68,69 hundredGigE39 39 100000 +Ethernet78 70,71 hundredGigE40 40 100000 +Ethernet80 96,97 hundredGigE41 41 100000 +Ethernet82 98,99 hundredGigE42 42 100000 +Ethernet84 100,101 hundredGigE43 43 100000 +Ethernet86 102,103 hundredGigE44 44 100000 +Ethernet88 104,105 hundredGigE45 45 100000 +Ethernet90 106,107 hundredGigE46 46 100000 +Ethernet92 108,109 hundredGigE47 47 100000 +Ethernet94 110,111 hundredGigE48 48 100000 +Ethernet96 112,113 hundredGigE49 49 100000 +Ethernet98 114,115 hundredGigE50 50 100000 +Ethernet100 116,117 hundredGigE51 51 100000 +Ethernet102 118,119 hundredGigE52 52 100000 +Ethernet104 120,121 hundredGigE53 53 100000 +Ethernet105 122 twentyfiveGigE54 54 25000 +Ethernet106 123 twentyfiveGigE55 55 25000 \ No newline at end of file diff --git a/device/accton/x86_64-accton_as7926_40xfb-r0/Accton-AS7926-40XFB/sai.profile b/device/accton/x86_64-accton_as7926_40xfb-r0/Accton-AS7926-40XFB/sai.profile new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/device/accton/x86_64-accton_as7926_40xfb-r0/Accton-AS7926-40XFB/sai.profile @@ -0,0 +1 @@ + diff --git a/device/accton/x86_64-accton_as7926_40xfb-r0/default_sku b/device/accton/x86_64-accton_as7926_40xfb-r0/default_sku new file mode 100644 index 00000000000..b309e8863af --- /dev/null +++ b/device/accton/x86_64-accton_as7926_40xfb-r0/default_sku @@ -0,0 +1 @@ +Accton-AS7926-40XFB t1 diff --git a/device/accton/x86_64-accton_as7926_40xfb-r0/installer.conf b/device/accton/x86_64-accton_as7926_40xfb-r0/installer.conf new file mode 100644 index 00000000000..cdb2b5679ee --- /dev/null +++ b/device/accton/x86_64-accton_as7926_40xfb-r0/installer.conf @@ -0,0 +1,4 @@ +CONSOLE_PORT=0x3f8 +CONSOLE_DEV=0 +CONSOLE_SPEED=115200 +ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="pcie_aspm=off intel_iommu=off modprobe.blacklist=ast,ipmi_msghandler,ipmi_ssif,ipmi_si,ipmi_devintf" diff --git a/device/accton/x86_64-accton_as7926_40xfb-r0/platform_asic b/device/accton/x86_64-accton_as7926_40xfb-r0/platform_asic new file mode 100644 index 00000000000..96046765276 --- /dev/null +++ b/device/accton/x86_64-accton_as7926_40xfb-r0/platform_asic @@ -0,0 +1 @@ +broadcom diff --git a/device/accton/x86_64-accton_as7926_40xfb-r0/plugins/eeprom.py b/device/accton/x86_64-accton_as7926_40xfb-r0/plugins/eeprom.py new file mode 100644 index 00000000000..117153a905c --- /dev/null +++ b/device/accton/x86_64-accton_as7926_40xfb-r0/plugins/eeprom.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python + +try: + from sonic_eeprom import eeprom_tlvinfo +except ImportError as 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): + self.eeprom_path = "/sys/devices/platform/as7926_40xfb_sys/eeprom" + super(board, self).__init__(self.eeprom_path, 0, '', True) diff --git a/device/accton/x86_64-accton_as7926_40xfb-r0/plugins/psuutil.py b/device/accton/x86_64-accton_as7926_40xfb-r0/plugins/psuutil.py new file mode 100644 index 00000000000..d32384376c1 --- /dev/null +++ b/device/accton/x86_64-accton_as7926_40xfb-r0/plugins/psuutil.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python + +############################################################################# +# Accton +# +# Module contains an implementation of SONiC PSU Base API and +# provides the PSUs status which are available in the platform +# +############################################################################# + +try: + from sonic_psu.psu_base import PsuBase +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + +class PsuUtil(PsuBase): + """Platform-specific PSUutil class""" + + def __init__(self): + PsuBase.__init__(self) + + self.psu_path = "/sys/devices/platform/as7926_40xfb_psu/psu" + self.psu_presence = "_present" + self.psu_oper_status = "_power_good" + self.psu_mapping = { + 1: "1", + 2: "2" + } + + def get_num_psus(self): + return len(self.psu_mapping) + + def get_psu_status(self, index): + if index is None: + return False + + status = 0 + node = self.psu_path + self.psu_mapping[index]+self.psu_oper_status + try: + with open(node, 'r') as power_status: + status = int(power_status.read()) + except IOError: + return False + + return status == 1 + + def get_psu_presence(self, index): + if index is None: + return False + + status = 0 + node = self.psu_path + self.psu_mapping[index] + self.psu_presence + try: + with open(node, 'r') as presence_status: + status = int(presence_status.read()) + except IOError: + return False + + return status == 1 diff --git a/device/accton/x86_64-accton_as7926_40xfb-r0/plugins/sfputil.py b/device/accton/x86_64-accton_as7926_40xfb-r0/plugins/sfputil.py new file mode 100644 index 00000000000..0ab40397f92 --- /dev/null +++ b/device/accton/x86_64-accton_as7926_40xfb-r0/plugins/sfputil.py @@ -0,0 +1,273 @@ +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# + +try: + import sys + import time + from ctypes import create_string_buffer + from sonic_sfp.sfputilbase import SfpUtilBase +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + +SFP_STATUS_INSERTED = '1' +SFP_STATUS_REMOVED = '0' + +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" + + PORT_START = 1 + PORT_END = 55 + QSFP_PORT_START = 1 + QSFP_PORT_END = 53 + CPLD_FMT = '/sys/bus/i2c/devices/{bus}-00{addr}/' + + _port_to_eeprom_mapping = {} + _port_to_i2c_mapping = { + 1: 33, + 2: 34, + 3: 37, + 4: 38, + 5: 41, + 6: 42, + 7: 45, + 8: 46, + 9: 49, + 10: 50, + 11: 53, + 12: 54, + 13: 57, + 14: 58, + 15: 61, + 16: 62, + 17: 65, + 18: 66, + 19: 69, + 20: 70, + 21: 35, + 22: 36, + 23: 39, + 24: 40, + 25: 43, + 26: 44, + 27: 47, + 28: 48, + 29: 51, + 30: 52, + 31: 55, + 32: 56, + 33: 59, + 34: 60, + 35: 63, + 36: 64, + 37: 67, + 38: 68, + 39: 71, + 40: 72, + 41: 93, + 42: 84, + 43: 83, + 44: 82, + 45: 81, + 46: 86, + 47: 85, + 48: 88, + 49: 87, + 50: 90, + 51: 89, + 52: 92, + 53: 91, + 54: 30, + 55: 31 + } + + @property + def port_start(self): + return self.PORT_START + + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_port_start(self): + return self.QSFP_PORT_START + + @property + def qsfp_port_end(self): + return self.QSFP_PORT_END + + @property + def qsfp_ports(self): + return range(self.QSFP_PORT_START, self.QSFP_PORT_END + 1) + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + def __init__(self): + eeprom_path = '/sys/bus/i2c/devices/{0}-0050/eeprom' + for x in range(self.port_start, self.port_end+1): + self.port_to_eeprom_mapping[x] = eeprom_path.format( + self._port_to_i2c_mapping[x]) + + SfpUtilBase.__init__(self) + + def get_cpld_path(self, port_num): + if ((1 <= port_num <= 10) or (21 <= port_num <= 30) or (54 <= port_num <= 55)): + return self.CPLD_FMT.format(bus=str(12), addr=str(62)) + elif ((11 <= port_num <= 20) or (31 <= port_num <= 40)): + return self.CPLD_FMT.format(bus=str(13), addr=str(63)) + elif (41 <= port_num <= 53): + return self.CPLD_FMT.format(bus=str(76), addr=str(64)) + + return str() + + def get_presence(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + port_ps = self.get_cpld_path(port_num) + 'module_present_{0}'.format(port_num) + + try: + val_file = open(port_ps) + except IOError as e: + print ('Error: unable to open file: ', str(e)) + return False + + content = val_file.readline().rstrip() + val_file.close() + + # content is a string, either "0" or "1" + return content == "1" + + def get_low_power_mode(self, port_num): + if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end: + return False + + if not self.get_presence(port_num): + return False + + try: + eeprom = None + + eeprom = open(self.port_to_eeprom_mapping[port_num], mode="rb", buffering=0) + eeprom.seek(93) + lpmode = ord(eeprom.read(1)) + + if not (lpmode & 0x1): # 'Power override' bit is 0 + return False # Default High Power Mode + else: + if ((lpmode & 0x2) == 0x2): + return True # Low Power Mode if "Power set" bit is 1 + else: + return False # High Power Mode if "Power set" bit is 0 + except IOError as e: + print ('Error: unable to open file: ', str(e)) + return False + finally: + if eeprom is not None: + eeprom.close() + time.sleep(0.01) + + def set_low_power_mode(self, port_num, lpmode): + if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end: + return False + + try: + eeprom = None + + if not self.get_presence(port_num): + return False # Port is not present, unable to set the eeprom + + # Fill in write buffer + regval = 0x3 if lpmode else 0x1 # 0x3:Low Power Mode, 0x1:High Power Mode + buffer = create_string_buffer(1) + if sys.version_info[0] >= 3: + buffer[0] = regval + else: + buffer[0] = chr(regval) + + # Write to eeprom + eeprom = open(self.port_to_eeprom_mapping[port_num], mode="r+b", buffering=0) + eeprom.seek(93) + eeprom.write(buffer[0]) + return True + except IOError as e: + print ('Error: unable to open file: ', str(e)) + return False + finally: + if eeprom is not None: + eeprom.close() + time.sleep(0.01) + + def reset(self, port_num): + # Check for invalid port_num + if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end: + return False + + port_ps = self.get_cpld_path(port_num) + 'module_reset_{0}'.format(port_num) + + try: + reg_file = open(port_ps, mode="w") + except IOError as e: + print ('Error: unable to open file: ', str(e)) + return False + + #toggle reset + reg_file.seek(0) + reg_file.write('1') + time.sleep(1) + reg_file.seek(0) + reg_file.write('0') + reg_file.close() + + return True + + @property + def get_transceiver_status(self): + bitmap = 0 + + for port in range(self.port_start, self.port_end+1): + if not self.get_presence(port): + continue + bitmap |= (1 << (port - self.port_start)) + + return bitmap + + data = {'valid': 0, 'last': 0, 'present': 0} + + def get_transceiver_change_event(self, timeout=2000): + now = time.time() + port_dict = {} + port = 0 + + if timeout < 1000: + timeout = 1000 + timeout = (timeout) / float(1000) # Convert to secs + + if now < (self.data['last'] + timeout) and self.data['valid']: + return True, {} + + reg_value = self.get_transceiver_status + changed_ports = self.data['present'] ^ reg_value + if changed_ports: + for port in range(self.port_start, self.port_end+1): + # Mask off the bit corresponding to our port + fp_port = port + mask = (1 << (fp_port - 1)) + if changed_ports & mask: + if (reg_value & mask) == 0: + port_dict[port] = SFP_STATUS_REMOVED + else: + port_dict[port] = SFP_STATUS_INSERTED + + # Update cache + self.data['present'] = reg_value + self.data['last'] = now + self.data['valid'] = 1 + return True, port_dict + else: + return True, {} diff --git a/device/accton/x86_64-accton_as7926_40xfb-r0/pmon_daemon_control.json b/device/accton/x86_64-accton_as7926_40xfb-r0/pmon_daemon_control.json new file mode 100644 index 00000000000..0d3f1fb4561 --- /dev/null +++ b/device/accton/x86_64-accton_as7926_40xfb-r0/pmon_daemon_control.json @@ -0,0 +1,6 @@ +{ + "skip_ledd": true, + "skip_pcied": true, + "skip_thermalctld": true +} + diff --git a/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/__init__.py b/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/__init__.py new file mode 100644 index 00000000000..706e2313249 --- /dev/null +++ b/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/__init__.py @@ -0,0 +1,2 @@ +__all__ = ['chassis', 'eeprom', 'platform', 'psu', 'sfp', 'thermal', 'fan', 'fan_drawer'] +from . import platform diff --git a/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/chassis.py b/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/chassis.py new file mode 100644 index 00000000000..86b574304a1 --- /dev/null +++ b/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/chassis.py @@ -0,0 +1,211 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Chassis information which are available in the platform +# +############################################################################# + +import os + +try: + from sonic_platform_base.chassis_base import ChassisBase + from .helper import APIHelper + from .event import SfpEvent +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +NUM_FAN_TRAY = 5 +NUM_FAN = 2 +NUM_PSU = 2 +NUM_THERMAL = 10 +NUM_QSFP = 53 +PORT_START = 1 +PORT_END = 55 +QSFP_PORT_START = 0 +QSFP_PORT_END = 52 +NUM_COMPONENT = 4 +HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/" +PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/" +REBOOT_CAUSE_FILE = "reboot-cause.txt" +PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt" +HOST_CHK_CMD = "which systemctl > /dev/null 2>&1" + + +class Chassis(ChassisBase): + """Platform-specific Chassis class""" + + def __init__(self): + ChassisBase.__init__(self) + self._api_helper = APIHelper() + self.is_host = self._api_helper.is_host() + + self.config_data = {} + + self.__initialize_fan() + self.__initialize_psu() + self.__initialize_thermals() + self.__initialize_components() + self.__initialize_sfp() + self.__initialize_eeprom() + + def __initialize_sfp(self): + from sonic_platform.sfp import Sfp + + self.QSFP_PORT_START = QSFP_PORT_START + self.QSFP_PORT_END = QSFP_PORT_END + for index in range(0, PORT_END): + if index in range(self.QSFP_PORT_START, self.QSFP_PORT_END + 1): + sfp_module = Sfp(index, 'QSFP') + else: + sfp_module = Sfp(index, 'SFP') + self._sfp_list.append(sfp_module) + self.sfp_module_initialized = True + + def __initialize_fan(self): + from sonic_platform.fan_drawer import FanDrawer + for fant_index in range(NUM_FAN_TRAY): + fandrawer = FanDrawer(fant_index) + self._fan_drawer_list.append(fandrawer) + self._fan_list.extend(fandrawer._fan_list) + + def __initialize_psu(self): + from sonic_platform.psu import Psu + for index in range(0, NUM_PSU): + psu = Psu(index) + self._psu_list.append(psu) + + def __initialize_thermals(self): + from sonic_platform.thermal import Thermal + for index in range(0, NUM_THERMAL): + thermal = Thermal(index) + self._thermal_list.append(thermal) + + def __initialize_eeprom(self): + from sonic_platform.eeprom import Tlv + self._eeprom = Tlv() + + def __initialize_components(self): + from sonic_platform.component import Component + for index in range(0, NUM_COMPONENT): + component = Component(index) + self._component_list.append(component) + + def __initialize_watchdog(self): + from sonic_platform.watchdog import Watchdog + self._watchdog = Watchdog() + + + def __is_host(self): + return os.system(HOST_CHK_CMD) == 0 + + def __read_txt_file(self, file_path): + try: + with open(file_path, 'r') as fd: + return fd.read().strip() + except IOError: + pass + return None + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + + return self._api_helper.hwsku + + def get_presence(self): + """ + Retrieves the presence of the Chassis + Returns: + bool: True if Chassis is present, False if not + """ + return True + + 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 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._eeprom.get_mac() + + 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._eeprom.get_serial() + + 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._eeprom.get_eeprom() + + 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. + """ + + reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE) + sw_reboot_cause = self._api_helper.read_txt_file( + reboot_cause_path) or "Unknown" + + + return ('REBOOT_CAUSE_NON_HARDWARE', sw_reboot_cause) + + def get_sfp(self, index): + """ + Retrieves sfp represented by (1-based) index + Args: + index: An integer, the index (1-based) of the sfp to retrieve. + The index should be the sequence of a physical port in a chassis, + starting from 1. + For example, 1 for Ethernet0, 2 for Ethernet4 and so on. + Returns: + An object dervied from SfpBase representing the specified sfp + """ + sfp = None + if not self.sfp_module_initialized: + self.__initialize_sfp() + + try: + # The index will start from 1 + sfp = self._sfp_list[index-1] + except IndexError: + sys.stderr.write("SFP index {} out of range (1-{})\n".format( + index, len(self._sfp_list))) + return sfp + + def get_change_event(self, timeout=0): + # SFP event + if not self.sfp_module_initialized: + self.__initialize_sfp() + + status, sfp_event = SfpEvent(self._sfp_list).get_sfp_event(timeout) + + return status, sfp_event diff --git a/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/component.py b/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/component.py new file mode 100644 index 00000000000..f8525a94445 --- /dev/null +++ b/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/component.py @@ -0,0 +1,122 @@ +############################################################################# +# Edgecore +# +# Component contains an implementation of SONiC Platform Base API and +# provides the components firmware management function +# +############################################################################# + +import shlex +import subprocess + +try: + from sonic_platform_base.component_base import ComponentBase + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +CPLD_ADDR_MAPPING = { + "CPLD1": "12-0062", + "CPLD2": "13-0063", + "CPLD3": "76-0064", +} +SYSFS_PATH = "/sys/bus/i2c/devices/" +BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version" +COMPONENT_LIST= [ + ("CPLD1", "CPLD 1"), + ("CPLD2", "CPLD 2"), + ("CPLD3", "CPLD 3"), + ("BIOS", "Basic Input/Output System") + +] + +class Component(ComponentBase): + """Platform-specific Component class""" + + DEVICE_TYPE = "component" + + def __init__(self, component_index=0): + self._api_helper=APIHelper() + ComponentBase.__init__(self) + self.index = component_index + self.name = self.get_name() + + def __run_command(self, command): + # Run bash command and print output to stdout + try: + process = subprocess.Popen( + shlex.split(command), stdout=subprocess.PIPE) + while True: + output = process.stdout.readline() + if output == '' and process.poll() is not None: + break + rc = process.poll() + if rc != 0: + return False + except Exception: + return False + return True + + def __get_bios_version(self): + # Retrieves the BIOS firmware version + try: + with open(BIOS_VERSION_PATH, 'r') as fd: + bios_version = fd.read() + return bios_version.strip() + except Exception as e: + return None + + def __get_cpld_version(self): + # Retrieves the CPLD firmware version + cpld_version = dict() + for cpld_name in CPLD_ADDR_MAPPING: + try: + cpld_path = "{}{}{}".format(SYSFS_PATH, CPLD_ADDR_MAPPING[cpld_name], '/version') + cpld_version_raw= self._api_helper.read_txt_file(cpld_path) + cpld_version[cpld_name] = "{}".format(int(cpld_version_raw,10)) + except Exception as e: + print('Get exception when read cpld (%s)', cpld_path) + cpld_version[cpld_name] = 'None' + + return cpld_version + + def get_name(self): + """ + Retrieves the name of the component + Returns: + A string containing the name of the component + """ + return COMPONENT_LIST[self.index][0] + + def get_description(self): + """ + Retrieves the description of the component + Returns: + A string containing the description of the component + """ + return COMPONENT_LIST[self.index][1] + + def get_firmware_version(self): + """ + Retrieves the firmware version of module + Returns: + string: The firmware versions of the module + """ + fw_version = None + if self.name == "BIOS": + fw_version = self.__get_bios_version() + elif "CPLD" in self.name: + cpld_version = self.__get_cpld_version() + fw_version = cpld_version.get(self.name) + + return fw_version + + def install_firmware(self, image_path): + """ + Install firmware to module + Args: + image_path: A string, path to firmware image + Returns: + A boolean, True if install successfully, False if not + """ + raise NotImplementedError diff --git a/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/eeprom.py b/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/eeprom.py new file mode 100644 index 00000000000..602f8cfb883 --- /dev/null +++ b/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/eeprom.py @@ -0,0 +1,102 @@ +try: + import os + import sys + import re + if sys.version_info[0] >= 3: + from io import StringIO + else: + from cStringIO import StringIO + + from sonic_platform_base.sonic_eeprom import eeprom_tlvinfo +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +CACHE_ROOT = '/var/cache/sonic/decode-syseeprom' +CACHE_FILE = 'syseeprom_cache' + + +class Tlv(eeprom_tlvinfo.TlvInfoDecoder): + + EEPROM_DECODE_HEADLINES = 6 + + def __init__(self): + self._eeprom_path = "/sys/devices/platform/as7926_40xfb_sys/eeprom" + super(Tlv, self).__init__(self._eeprom_path, 0, '', True) + self._eeprom = self._load_eeprom() + + def __parse_output(self, decode_output): + decode_output.replace('\0', '') + lines = decode_output.split('\n') + lines = lines[self.EEPROM_DECODE_HEADLINES:] + _eeprom_info_dict = dict() + + for line in lines: + try: + match = re.search( + '(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)([\S]+)', line) + if match is not None: + idx = match.group(1) + value = match.group(3).rstrip('\0') + + _eeprom_info_dict[idx] = value + except Exception: + pass + + return _eeprom_info_dict + + def _load_eeprom(self): + original_stdout = sys.stdout + sys.stdout = StringIO() + try: + self.read_eeprom_db() + except Exception: + decode_output = sys.stdout.getvalue() + sys.stdout = original_stdout + return self.__parse_output(decode_output) + + status = self.check_status() + if 'ok' not in status: + return False + + if not os.path.exists(CACHE_ROOT): + try: + os.makedirs(CACHE_ROOT) + except Exception: + pass + + # + # only the eeprom classes that inherit from eeprom_base + # support caching. Others will work normally + # + try: + self.set_cache_name(os.path.join(CACHE_ROOT, CACHE_FILE)) + except Exception: + pass + + e = self.read_eeprom() + if e is None: + return 0 + + try: + self.update_cache(e) + except Exception: + pass + + self.decode_eeprom(e) + decode_output = sys.stdout.getvalue() + sys.stdout = original_stdout + + (is_valid, valid_crc) = self.is_checksum_valid(e) + if not is_valid: + return False + + return self.__parse_output(decode_output) + + def get_eeprom(self): + return self._eeprom + + def get_serial(self): + return self._eeprom.get('0x23', "Undefined.") + + def get_mac(self): + return self._eeprom.get('0x24', "Undefined.") diff --git a/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/event.py b/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/event.py new file mode 100644 index 00000000000..4681d8ab7e6 --- /dev/null +++ b/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/event.py @@ -0,0 +1,55 @@ +try: + import time + from .helper import APIHelper + from sonic_py_common.logger import Logger +except ImportError as e: + raise ImportError(repr(e) + " - required module not found") + + +class SfpEvent: + ''' Listen to insert/remove sfp events ''' + + def __init__(self, sfp_list): + self._api_helper = APIHelper() + self._sfp_list = sfp_list + self._logger = Logger() + + sfp_change_event_data = {'valid': 0, 'last': 0, 'present': 0} + def get_sfp_event(self, timeout=2000): + now = time.time() + port_dict = {} + change_dict = {} + change_dict['sfp'] = port_dict + + if timeout < 1000: + timeout = 1000 + timeout = timeout / float(1000) # Convert to secs + + if now < (self.sfp_change_event_data['last'] + timeout) and self.sfp_change_event_data['valid']: + return True, change_dict + + bitmap = 0 + for sfp in self._sfp_list: + modpres = sfp.get_presence() + i=sfp._port_num-1 + if modpres: + bitmap = bitmap | (1 << i) + + changed_ports = self.sfp_change_event_data['present'] ^ bitmap + if changed_ports: + for sfp in self._sfp_list: + i=sfp._port_num-1 + if (changed_ports & (1 << i)): + if (bitmap & (1 << i)) == 0: + port_dict[i+1] = '0' + else: + port_dict[i+1] = '1' + + + # Update the cache dict + self.sfp_change_event_data['present'] = bitmap + self.sfp_change_event_data['last'] = now + self.sfp_change_event_data['valid'] = 1 + return True, change_dict + else: + return True, change_dict diff --git a/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/fan.py b/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/fan.py new file mode 100644 index 00000000000..0d189320260 --- /dev/null +++ b/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/fan.py @@ -0,0 +1,184 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the fan status which are available in the platform +# +############################################################################# + + +try: + from sonic_platform_base.fan_base import FanBase + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +PSU_FAN_MAX_RPM = 25500 + +CPLD_I2C_PATH = "/sys/devices/platform/as7926_40xfb_fan/fan" +PSU_HWMON_I2C_PATH ="/sys/devices/platform/as7926_40xfb_psu/psu{}" + +class Fan(FanBase): + """Platform-specific Fan class""" + + def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0): + self._api_helper=APIHelper() + self.fan_index = fan_index + self.fan_tray_index = fan_tray_index + self.is_psu_fan = is_psu_fan + if self.is_psu_fan: + self.psu_index = psu_index + self.psu_hwmon_path = PSU_HWMON_I2C_PATH.format(self.psu_index+1) + + FanBase.__init__(self) + + + 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 not self.is_psu_fan: + dir_str = "{}{}{}".format(CPLD_I2C_PATH, self.fan_tray_index+1, '_dir') + val = self._api_helper.read_txt_file(dir_str) + if val is not None: + if val == 'F2B': #F2B + direction = self.FAN_DIRECTION_EXHAUST + else: + direction = self.FAN_DIRECTION_INTAKE + else: + direction = self.FAN_DIRECTION_EXHAUST + + else: #For PSU + direction = self.FAN_DIRECTION_EXHAUST + + 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) + + """ + speed = 0 + if self.is_psu_fan: + psu_fan_path = "{}{}".format(self.psu_hwmon_path, '_fan1_input') + fan_speed_rpm = self._api_helper.read_txt_file(psu_fan_path) + if fan_speed_rpm is not None: + speed = (int(fan_speed_rpm, 10)) * 100 / PSU_FAN_MAX_RPM + if speed > 100: + speed = 100 + else: + return 0 + + elif self.get_presence(): + input_path = "{}{}{}".format(CPLD_I2C_PATH, self.fan_tray_index+1, '_input') + input = self._api_helper.read_txt_file(input_path) + + target_path = "{}{}{}".format(CPLD_I2C_PATH, self.fan_tray_index+1, '_target') + target = self._api_helper.read_txt_file(target_path) + + if input is None or target is None: + return 0 + + speed = (int(input) * self.get_target_speed()) / int(target) + + return int(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) + + Note: + speed_pc = pwm_target/255*100 + + 0 : when PWM mode is use + pwm : when pwm mode is not use + """ + speed = 0 + if self.is_psu_fan: + psu_fan_path = "{}{}".format(self.psu_hwmon_path, '_fan1_input') + fan_speed_rpm = self._api_helper.read_txt_file(psu_fan_path) + if fan_speed_rpm is not None: + speed = (int(fan_speed_rpm, 10)) * 100 / PSU_FAN_MAX_RPM + if speed > 100: + speed = 100 + else: + return 0 + else: + speed_path = "{}{}{}".format(CPLD_I2C_PATH, self.fan_tray_index+1, '_pwm') + speed = self._api_helper.read_txt_file(speed_path) + if speed is None: + return 0 + + return int(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 + """ + speed = 0 + if not self.is_psu_fan: + speed_path = "{}{}{}".format(CPLD_I2C_PATH, self.fan_tray_index+1, '_tolerance') + speed = self._api_helper.read_txt_file(speed_path) + if speed is None: + return 0 + + return int(speed) + + 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 not self.is_psu_fan and self.get_presence(): + speed_path = "{}{}{}".format(CPLD_I2C_PATH, self.fan_tray_index+1, '_pwm') + return self._api_helper.write_txt_file(speed_path, int(speed)) + + return False + + def set_status_led(self, color): + """ + Sets the state of the fan module status LED + Args: + color: A string representing the color with which to set the + fan module status LED + Returns: + bool: True if status LED state is set successfully, False if not + """ + return False #Not supported + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if FAN is present, False if not + """ + present_path = "{}{}{}".format(CPLD_I2C_PATH, self.fan_tray_index+1, '_present') + val=self._api_helper.read_txt_file(present_path) + + if not self.is_psu_fan: + if val is not None: + return int(val, 10)==1 + else: + return False + else: + return True diff --git a/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/fan_drawer.py b/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/fan_drawer.py new file mode 100644 index 00000000000..c7fe049edb5 --- /dev/null +++ b/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/fan_drawer.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python + +######################################################################## +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Fan-Drawers' information available in the platform. +# +######################################################################## + +try: + from sonic_platform_base.fan_drawer_base import FanDrawerBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +FANS_PER_FANTRAY = 2 + + +class FanDrawer(FanDrawerBase): + """Platform-specific Fan class""" + + def __init__(self, fantray_index): + FanDrawerBase.__init__(self) + self.fantrayindex = fantray_index + + # FanTray is 0-based in platforms + self.__initialize_fan() + + def __initialize_fan(self): + from sonic_platform.fan import Fan + + for i in range(FANS_PER_FANTRAY): + self._fan_list.append(Fan(self.fantrayindex, i)) + + def get_name(self): + """ + Retrieves the fan drawer name + Returns: + string: The name of the device + """ + return "FanTray{}".format(self.fantrayindex) + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True diff --git a/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/helper.py b/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/helper.py new file mode 100644 index 00000000000..4cd60ac9061 --- /dev/null +++ b/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/helper.py @@ -0,0 +1,117 @@ +import os +import struct +import subprocess +from mmap import * +from sonic_py_common import device_info + +HOST_CHK_CMD = "docker > /dev/null 2>&1" +EMPTY_STRING = "" + + +class APIHelper(): + + def __init__(self): + (self.platform, self.hwsku) = device_info.get_platform_and_hwsku() + + def is_host(self): + return os.system(HOST_CHK_CMD) == 0 + + def pci_get_value(self, resource, offset): + status = True + result = "" + try: + fd = os.open(resource, os.O_RDWR) + mm = mmap(fd, 0) + mm.seek(int(offset)) + read_data_stream = mm.read(4) + result = struct.unpack('I', read_data_stream) + except Exception: + status = False + return status, result + + def run_command(self, cmd): + status = True + result = "" + try: + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + except Exception: + status = False + return status, result + + def run_interactive_command(self, cmd): + try: + os.system(cmd) + except Exception: + return False + return True + + def read_txt_file(self, file_path): + try: + with open(file_path, 'r') as fd: + data = fd.read() + return data.strip() + except IOError: + pass + return None + + def write_txt_file(self, file_path, value): + try: + with open(file_path, 'w') as fd: + fd.write(str(value)) + except IOError: + return False + return True + + def ipmi_raw(self, netfn, cmd): + status = True + result = "" + try: + cmd = "ipmitool raw {} {}".format(str(netfn), str(cmd)) + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result + + def ipmi_fru_id(self, id, key=None): + status = True + result = "" + try: + cmd = "ipmitool fru print {}".format(str( + id)) if not key else "ipmitool fru print {0} | grep '{1}' ".format(str(id), str(key)) + + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result + + def ipmi_set_ss_thres(self, id, threshold_key, value): + status = True + result = "" + try: + cmd = "ipmitool sensor thresh '{}' {} {}".format(str(id), str(threshold_key), str(value)) + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result diff --git a/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/platform.py b/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/platform.py new file mode 100644 index 00000000000..2f2c2a447fc --- /dev/null +++ b/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/platform.py @@ -0,0 +1,21 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the platform information +# +############################################################################# + +try: + from sonic_platform_base.platform_base import PlatformBase + from sonic_platform.chassis import Chassis +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Platform(PlatformBase): + """Platform-specific Platform class""" + + def __init__(self): + PlatformBase.__init__(self) + self._chassis = Chassis() diff --git a/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/psu.py b/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/psu.py new file mode 100644 index 00000000000..7d1224c225d --- /dev/null +++ b/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/psu.py @@ -0,0 +1,239 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the PSUs status which are available in the platform +# +############################################################################# + +#import sonic_platform + +try: + from sonic_platform_base.psu_base import PsuBase + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +HWMON_I2C_PATH ="/sys/devices/platform/as7926_40xfb_psu/psu{}" + +PSU_NAME_LIST = ["PSU-1", "PSU-2"] +PSU_NUM_FAN = [1, 1] + +class Psu(PsuBase): + """Platform-specific Psu class""" + + def __init__(self, psu_index=0): + PsuBase.__init__(self) + self._api_helper = APIHelper() + self.index = psu_index + self.hwmon_path = HWMON_I2C_PATH.format(self.index+1) + self.__initialize_fan() + + def __initialize_fan(self): + from sonic_platform.fan import Fan + for fan_index in range(0, PSU_NUM_FAN[self.index]): + fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index) + self._fan_list.append(fan) + + def get_voltage(self): + """ + Retrieves current PSU voltage output + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + vout_path = "{}{}".format(self.hwmon_path, '_vout') + vout_val=self._api_helper.read_txt_file(vout_path) + if vout_val is not None: + return float(vout_val)/1000 + else: + return 0 + def get_current(self): + """ + Retrieves present electric current supplied by PSU + Returns: + A float number, the electric current in amperes, e.g 15.4 + """ + iout_path = "{}{}".format(self.hwmon_path, '_iout') + val=self._api_helper.read_txt_file(iout_path) + if val is not None: + return float(val)/1000 + else: + return 0 + + def get_power(self): + """ + Retrieves current energy supplied by PSU + Returns: + A float number, the power in watts, e.g. 302.6 + """ + pout_path = "{}{}".format(self.hwmon_path, '_pout') + val=self._api_helper.read_txt_file(pout_path) + if val is not None: + return float(val)/1000 + else: + return 0 + + 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): + """ + Sets the state of the PSU status LED + Args: + color: A string representing the color with which to set the PSU status LED + Note: Only support green and off + Returns: + bool: True if status LED state is set successfully, False if not + """ + + return False #Controlled by HW + + def get_status_led(self): + """ + Gets the state of the PSU status LED + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + + if self.get_status(): + return True + else: + return False + + def get_temperature(self): + """ + Retrieves current temperature reading from PSU + Returns: + A float number of current temperature in Celsius up to nearest thousandth + of one degree Celsius, e.g. 30.125 + """ + temp_path = "{}{}".format(self.hwmon_path, '_temp1_input') + val=self._api_helper.read_txt_file(temp_path) + if val is not None: + return float(val)/1000 + else: + return 0 + + def get_temperature_high_threshold(self): + """ + Retrieves the high threshold temperature of PSU + Returns: + A float number, the high threshold temperature of PSU in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + temp_path = "{}{}".format(self.hwmon_path, '_temp1_input_max') + val=self._api_helper.read_txt_file(temp_path) + if val is not None: + return float(val)/1000 + else: + return 0 + + def get_voltage_high_threshold(self): + """ + Retrieves the high threshold PSU voltage output + Returns: + A float number, the high threshold output voltage in volts, + e.g. 12.1 + """ + vout_path = "{}{}".format(self.hwmon_path, '_vout_max') + vout_val=self._api_helper.read_txt_file(vout_path) + if vout_val is not None: + return float(vout_val)/1000 + else: + return 0 + + def get_voltage_low_threshold(self): + """ + Retrieves the low threshold PSU voltage output + Returns: + A float number, the low threshold output voltage in volts, + e.g. 12.1 + """ + vout_path = "{}{}".format(self.hwmon_path, '_vout_min') + vout_val=self._api_helper.read_txt_file(vout_path) + if vout_val is not None: + return float(vout_val)/1000 + else: + return 0 + + def get_maximum_supplied_power(self): + """ + Retrieves the maximum supplied power by PSU + Returns: + A float number, the maximum power output in Watts. + e.g. 1200.1 + """ + pout_path = "{}{}".format(self.hwmon_path, '_pout_max') + val=self._api_helper.read_txt_file(pout_path) + if val is not None: + return float(val)/1000 + else: + return 0 + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return PSU_NAME_LIST[self.index] + + def get_presence(self): + """ + Retrieves the presence of the PSU + Returns: + bool: True if PSU is present, False if not + """ + presence_path="{}{}".format(self.hwmon_path, '_present') + val=self._api_helper.read_txt_file(presence_path) + if val is not None: + return int(val, 10) == 1 + else: + return 0 + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + power_path="{}{}".format(self.hwmon_path, '_power_good') + val=self._api_helper.read_txt_file(power_path) + if val is not None: + return int(val, 10) == 1 + else: + return 0 + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + model_path="{}{}".format(self.hwmon_path, '_model') + model=self._api_helper.read_txt_file(model_path) + + if model is None: + return "N/A" + return model + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + serial_path="{}{}".format(self.hwmon_path, '_serial') + serial=self._api_helper.read_txt_file(serial_path) + + if serial is None: + return "N/A" + return serial diff --git a/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/sfp.py b/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/sfp.py new file mode 100644 index 00000000000..8f7173cd1ca --- /dev/null +++ b/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/sfp.py @@ -0,0 +1,2299 @@ +############################################################################# +# Accton +# +# Sfp contains an implementation of SONiC Platform Base API and +# provides the sfp device status which are available in the platform +# +############################################################################# + +import os +import sys +import time +import struct + +from ctypes import create_string_buffer + +try: + from sonic_platform_base.sfp_base import SfpBase + from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId + from sonic_platform_base.sonic_sfp.sff8472 import sff8472Dom + from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId + from sonic_platform_base.sonic_sfp.sff8436 import sff8436Dom + from sonic_platform_base.sonic_sfp.inf8628 import inf8628InterfaceId + from sonic_platform_base.sonic_sfp.qsfp_dd import qsfp_dd_InterfaceId + from sonic_platform_base.sonic_sfp.qsfp_dd import qsfp_dd_Dom + from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +#Edge-core definitions +CPLD2_I2C_PATH = "/sys/bus/i2c/devices/12-0062/" +CPLD3_I2C_PATH = "/sys/bus/i2c/devices/13-0063/" +CPLD4_I2C_PATH = "/sys/bus/i2c/devices/76-0064/" + +# 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_EXT_SPECIFICATION_COMPLIANCE_OFFSET = 64 +XCVR_EXT_SPECIFICATION_COMPLIANCE_WIDTH = 1 +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 = 2 + +XCVR_INTERFACE_DATA_START = 0 +XCVR_INTERFACE_DATA_SIZE = 92 + +QSFP_DOM_BULK_DATA_START = 22 +QSFP_DOM_BULK_DATA_SIZE = 36 +SFP_DOM_BULK_DATA_START = 96 +SFP_DOM_BULK_DATA_SIZE = 10 +QSFP_DD_DOM_BULK_DATA_START = 14 +QSFP_DD_DOM_BULK_DATA_SIZE = 4 + +# 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 for values in QSFP_DD info eeprom +QSFP_DD_TYPE_OFFSET = 0 +QSFP_DD_VENDOR_NAME_OFFSET = 1 +QSFP_DD_VENDOR_PN_OFFSET = 20 +QSFP_DD_VENDOR_SN_OFFSET = 38 +QSFP_DD_VENDOR_OUI_OFFSET = 17 + +# definitions of the offset and width for values in XCVR_QSFP_DD info eeprom +XCVR_EXT_TYPE_OFFSET_QSFP_DD = 72 +XCVR_EXT_TYPE_WIDTH_QSFP_DD = 2 +XCVR_CONNECTOR_OFFSET_QSFP_DD = 75 +XCVR_CONNECTOR_WIDTH_QSFP_DD = 1 +XCVR_CABLE_LENGTH_OFFSET_QSFP_DD = 74 +XCVR_CABLE_LENGTH_WIDTH_QSFP_DD = 1 +XCVR_HW_REV_OFFSET_QSFP_DD = 36 +XCVR_HW_REV_WIDTH_QSFP_DD = 2 +XCVR_VENDOR_DATE_OFFSET_QSFP_DD = 54 +XCVR_VENDOR_DATE_WIDTH_QSFP_DD = 8 +XCVR_DOM_CAPABILITY_OFFSET_QSFP_DD = 2 +XCVR_DOM_CAPABILITY_WIDTH_QSFP_DD = 1 +XCVR_MEDIA_TYPE_OFFSET_QSFP_DD = 85 +XCVR_MEDIA_TYPE_WIDTH_QSFP_DD = 1 +XCVR_FIRST_APPLICATION_LIST_OFFSET_QSFP_DD = 86 +XCVR_FIRST_APPLICATION_LIST_WIDTH_QSFP_DD = 32 +XCVR_SECOND_APPLICATION_LIST_OFFSET_QSFP_DD = 351 +XCVR_SECOND_APPLICATION_LIST_WIDTH_QSFP_DD = 28 + +# Offset for values in QSFP 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_VERSION_COMPLIANCE_OFFSET = 1 +QSFP_VERSION_COMPLIANCE_WIDTH = 2 +QSFP_CHANNL_MON_OFFSET = 34 +QSFP_CHANNL_MON_WIDTH = 16 +QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH = 24 +QSFP_CHANNL_DISABLE_STATUS_OFFSET = 86 +QSFP_CHANNL_DISABLE_STATUS_WIDTH = 1 +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_CONTROL_OFFSET = 86 +QSFP_CONTROL_WIDTH = 8 +QSFP_MODULE_MONITOR_OFFSET = 0 +QSFP_MODULE_MONITOR_WIDTH = 9 +QSFP_POWEROVERRIDE_OFFSET = 93 +QSFP_POWEROVERRIDE_WIDTH = 1 +QSFP_POWEROVERRIDE_BIT = 0 +QSFP_POWERSET_BIT = 1 +QSFP_OPTION_VALUE_OFFSET = 192 +QSFP_OPTION_VALUE_WIDTH = 4 +QSFP_MODULE_UPPER_PAGE3_START = 384 +QSFP_MODULE_THRESHOLD_OFFSET = 128 +QSFP_MODULE_THRESHOLD_WIDTH = 24 +QSFP_CHANNL_THRESHOLD_OFFSET = 176 +QSFP_CHANNL_THRESHOLD_WIDTH = 24 + +SFP_MODULE_ADDRA2_OFFSET = 256 +SFP_MODULE_THRESHOLD_OFFSET = 0 +SFP_MODULE_THRESHOLD_WIDTH = 56 +SFP_CHANNL_THRESHOLD_OFFSET = 112 +SFP_CHANNL_THRESHOLD_WIDTH = 2 + +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_CHANNL_STATUS_OFFSET = 110 +SFP_CHANNL_STATUS_WIDTH = 1 + +QSFP_DD_TEMPE_OFFSET = 14 +QSFP_DD_TEMPE_WIDTH = 2 +QSFP_DD_VOLT_OFFSET = 16 +QSFP_DD_VOLT_WIDTH = 2 +QSFP_DD_TX_BIAS_OFFSET = 42 +QSFP_DD_TX_BIAS_WIDTH = 16 +QSFP_DD_RX_POWER_OFFSET = 58 +QSFP_DD_RX_POWER_WIDTH = 16 +QSFP_DD_TX_POWER_OFFSET = 26 +QSFP_DD_TX_POWER_WIDTH = 16 +QSFP_DD_CHANNL_MON_OFFSET = 154 +QSFP_DD_CHANNL_MON_WIDTH = 48 +QSFP_DD_CHANNL_DISABLE_STATUS_OFFSET = 86 +QSFP_DD_CHANNL_DISABLE_STATUS_WIDTH = 1 +QSFP_DD_CHANNL_RX_LOS_STATUS_OFFSET = 19 +QSFP_DD_CHANNL_RX_LOS_STATUS_WIDTH = 1 +QSFP_DD_CHANNL_TX_FAULT_STATUS_OFFSET = 7 +QSFP_DD_CHANNL_TX_FAULT_STATUS_WIDTH = 1 +QSFP_DD_MODULE_THRESHOLD_OFFSET = 0 +QSFP_DD_MODULE_THRESHOLD_WIDTH = 72 +QSFP_DD_CHANNL_STATUS_OFFSET = 26 +QSFP_DD_CHANNL_STATUS_WIDTH = 1 + + +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' +) + +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', 'type_abbrv_name' +] + +qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)', + 'Length OM2(m)', 'Length OM1(m)', + 'Length Cable Assembly(m)') + +dom_info_dict_keys = [ + 'rx_los', 'tx_fault', 'reset_status', 'lp_mode', + 'tx_disable', 'tx_disable_channel', 'temperature', 'voltage', + 'rx1power', 'rx2power', 'rx3power', 'rx4power', + 'rx5power', 'rx6power', 'rx7power', 'rx8power', + 'tx1bias', 'tx2bias', 'tx3bias', 'tx4bias', + 'tx5bias', 'tx6bias', 'tx7bias', 'tx8bias', + 'tx1power', 'tx2power', 'tx3power', 'tx4power', + 'tx5power', 'tx6power', 'tx7power', 'tx8power'] + +threshold_dict_keys = [ + 'temphighalarm', 'temphighwarning', + 'templowalarm', 'templowwarning', + 'vcchighalarm', 'vcchighwarning', + 'vcclowalarm', 'vcclowwarning', + 'rxpowerhighalarm', 'rxpowerhighwarning', + 'rxpowerlowalarm', 'rxpowerlowwarning', + 'txpowerhighalarm', 'txpowerhighwarning', + 'txpowerlowalarm', 'txpowerlowwarning', + 'txbiashighalarm', 'txbiashighwarning', + 'txbiaslowalarm', 'txbiaslowwarning'] + +SFP_TYPE_CODE_LIST = [ + '03' # SFP/SFP+/SFP28 +] +QSFP_TYPE_CODE_LIST = [ + '0d', # QSFP+ or later + '11' # QSFP28 or later +] +QSFP_DD_TYPE_CODE_LIST = [ + '18' # QSFP-DD Double Density 8X Pluggable Transceiver +] + +SFP_TYPE = "SFP" +QSFP_TYPE = "QSFP" +OSFP_TYPE = "OSFP" +QSFP_DD_TYPE = "QSFP_DD" + +NULL_VAL = 'N/A' + +#PORT_START = 1 +#PORT_END = 34 +#QSFP_PORT_START = 1 +#QSFP_PORT_END = 32 + +#SFP_I2C_START = 17 +I2C_EEPROM_PATH = '/sys/bus/i2c/devices/{0}-0050/eeprom' + + +class Sfp(SfpBase): + """Platform-specific Sfp class""" + HOST_CHK_CMD = "docker > /dev/null 2>&1" + PLATFORM = "x86_64-accton_as7926_40xfb-r0" + HWSKU = "Accton-AS7926-40XFB" + + # Path to sysfs + PLATFORM_ROOT_PATH = "/usr/share/sonic/device" + PMON_HWSKU_PATH = "/usr/share/sonic/hwsku" + + CPLD2_PORT_START = 1 + CPLD2_PORT_END = 16 + CPLD3_PORT_START = 17 + CPLD3_PORT_END = 32 + #PRS_PATH = "/sys/devices/platform/dx010_cpld/qsfp_modprs" + + _port_to_i2c_mapping = { + 1: [33], + 2: [34], + 3: [37], + 4: [38], + 5: [41], + 6: [42], + 7: [45], + 8: [46], + 9: [49], + 10: [50], + 11: [53], + 12: [54], + 13: [57], + 14: [58], + 15: [61], + 16: [62], + 17: [65], + 18: [66], + 19: [69], + 20: [70], + 21: [35], + 22: [36], + 23: [39], + 24: [40], + 25: [43], + 26: [44], + 27: [47], + 28: [48], + 29: [51], + 30: [52], + 31: [55], + 32: [56], + 33: [59], + 34: [60], + 35: [63], + 36: [64], + 37: [67], + 38: [68], + 39: [71], + 40: [72], + 41: [93], + 42: [84], + 43: [83], + 44: [82], + 45: [81], + 46: [86], + 47: [85], + 48: [88], + 49: [87], + 50: [90], + 51: [89], + 52: [92], + 53: [91], + 54: [30], + 55: [31], + } + + def __init__(self, sfp_index=0, sfp_name=None): + + self._index = sfp_index + self._port_num = self._index + 1 + self._api_helper = APIHelper() + self._name = sfp_name + self._eeprom_path = self._get_eeprom_path() + + self._dom_capability_detect() + SfpBase.__init__(self) + + def __write_txt_file(self, file_path, value): + try: + reg_file = open(file_path, "w") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + reg_file.write(str(value)) + reg_file.close() + + return True + + def __is_host(self): + return os.system(self.HOST_CHK_CMD) == 0 + + def __get_path_to_port_config_file(self): + platform_path = "/".join([self.PLATFORM_ROOT_PATH, self.PLATFORM]) + hwsku_path = "/".join([platform_path, self.HWSKU] + ) if self.__is_host() else self.PMON_HWSKU_PATH + return "/".join([hwsku_path, "port_config.ini"]) + + def _convert_string_to_num(self, value_str): + if "-inf" in value_str: + return 'N/A' + elif "Unknown" in value_str: + return 'N/A' + elif 'dBm' in value_str: + t_str = value_str.rstrip('dBm') + return float(t_str) + elif 'mA' in value_str: + t_str = value_str.rstrip('mA') + return float(t_str) + elif 'C' in value_str: + t_str = value_str.rstrip('C') + return float(t_str) + elif 'Volts' in value_str: + t_str = value_str.rstrip('Volts') + return float(t_str) + else: + return 'N/A' + + def _read_eeprom_specific_bytes(self, offset, num_bytes): + sysfs_sfp_i2c_client_eeprom_path = self._get_eeprom_path() + eeprom_raw = [] + try: + eeprom = open( + sysfs_sfp_i2c_client_eeprom_path, + mode="rb", buffering=0) + except IOError: + return None + + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + + try: + eeprom.seek(offset) + raw = eeprom.read(num_bytes) + except IOError: + eeprom.close() + return None + + try: + if isinstance(raw, str): + for n in range(0, num_bytes): + eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) + else: + for n in range(0, num_bytes): + eeprom_raw[n] = hex(raw[n])[2:].zfill(2) + + except BaseException: + eeprom.close() + return None + + eeprom.close() + return eeprom_raw + + def _detect_sfp_type(self): + sfp_type = QSFP_TYPE + eeprom_raw = [] + eeprom_raw = self._read_eeprom_specific_bytes( + XCVR_TYPE_OFFSET, XCVR_TYPE_WIDTH) + if eeprom_raw: + if eeprom_raw[0] in SFP_TYPE_CODE_LIST: + self.sfp_type = SFP_TYPE + elif eeprom_raw[0] in QSFP_TYPE_CODE_LIST: + self.sfp_type = QSFP_TYPE + elif eeprom_raw[0] in QSFP_DD_TYPE_CODE_LIST: + self.sfp_type = QSFP_DD_TYPE + else: + self.sfp_type = sfp_type + else: + self.sfp_type = sfp_type + + def _get_eeprom_path(self): + port_eeprom_path = I2C_EEPROM_PATH.format(self._port_to_i2c_mapping[self._port_num][0]) + return port_eeprom_path + + def _dom_capability_detect(self): + self._detect_sfp_type() + + if not self.get_presence(): + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + return + + if self.sfp_type == QSFP_TYPE: + self.calibration = 1 + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + self.dom_supported = False + offset = 128 + + # QSFP capability byte parse, + # through this byte can know whether it support tx_power or not. + # TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436, + # need to add more code for determining the capability and version compliance + # in SFF-8636 dom capability definitions evolving with the versions. + + qsfp_dom_capability_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_DOM_CAPABILITY_OFFSET), + XCVR_DOM_CAPABILITY_WIDTH) + if qsfp_dom_capability_raw is not None: + qsfp_version_compliance_raw = self._read_eeprom_specific_bytes( + QSFP_VERSION_COMPLIANCE_OFFSET, + QSFP_VERSION_COMPLIANCE_WIDTH) + qsfp_version_compliance = int( + qsfp_version_compliance_raw[0], 16) + dom_capability = sfpi_obj.parse_dom_capability( + qsfp_dom_capability_raw, 0) + if qsfp_version_compliance >= 0x08: + self.dom_temp_supported = dom_capability['data']['Temp_support']['value'] == 'On' + self.dom_volt_supported = dom_capability['data']['Voltage_support']['value'] == 'On' + self.dom_rx_power_supported = dom_capability['data']['Rx_power_support']['value'] == 'On' + self.dom_tx_power_supported = dom_capability['data']['Tx_power_support']['value'] == 'On' + else: + self.dom_temp_supported = True + self.dom_volt_supported = True + self.dom_rx_power_supported = dom_capability['data']['Rx_power_support']['value'] == 'On' + self.dom_tx_power_supported = True + + self.dom_supported = True + self.calibration = 1 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + qsfp_option_value_raw = self._read_eeprom_specific_bytes( + QSFP_OPTION_VALUE_OFFSET, QSFP_OPTION_VALUE_WIDTH) + if qsfp_option_value_raw is not None: + optional_capability = sfpd_obj.parse_option_params( + qsfp_option_value_raw, 0) + self.dom_tx_disable_supported = optional_capability[ + 'data']['TxDisable']['value'] == 'On' + dom_status_indicator = sfpd_obj.parse_dom_status_indicator( + qsfp_version_compliance_raw, 1) + self.qsfp_page3_available = dom_status_indicator['data']['FlatMem']['value'] == 'Off' + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + self.qsfp_page3_available = False + + elif self.sfp_type == QSFP_DD_TYPE: + sfpi_obj = qsfp_dd_InterfaceId() + if sfpi_obj is None: + self.dom_supported = False + + offset = 0 + # two types of QSFP-DD cable types supported: Copper and Optical. + qsfp_dom_capability_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_DOM_CAPABILITY_OFFSET_QSFP_DD), XCVR_DOM_CAPABILITY_WIDTH_QSFP_DD) + if qsfp_dom_capability_raw is not None: + self.dom_temp_supported = True + self.dom_volt_supported = True + dom_capability = sfpi_obj.parse_dom_capability( + qsfp_dom_capability_raw, 0) + if dom_capability['data']['Flat_MEM']['value'] == 'Off': + self.dom_supported = True + self.second_application_list = True + self.dom_rx_power_supported = True + self.dom_tx_power_supported = True + self.dom_tx_bias_power_supported = True + self.dom_thresholds_supported = True + # currently set to False becasue Page 11h is not supported by FW + self.dom_rx_tx_power_bias_supported = False + else: + self.dom_supported = False + self.second_application_list = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.dom_tx_bias_power_supported = False + self.dom_thresholds_supported = False + self.dom_rx_tx_power_bias_supported = False + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.dom_tx_bias_power_supported = False + self.dom_thresholds_supported = False + self.dom_rx_tx_power_bias_supported = False + + elif self.sfp_type == SFP_TYPE: + sfpi_obj = sff8472InterfaceId() + if sfpi_obj is None: + return None + sfp_dom_capability_raw = self._read_eeprom_specific_bytes( + XCVR_DOM_CAPABILITY_OFFSET, XCVR_DOM_CAPABILITY_WIDTH) + if sfp_dom_capability_raw is not None: + sfp_dom_capability = int(sfp_dom_capability_raw[0], 16) + self.dom_supported = (sfp_dom_capability & 0x40 != 0) + if self.dom_supported: + self.dom_temp_supported = True + self.dom_volt_supported = True + self.dom_rx_power_supported = True + self.dom_tx_power_supported = True + if sfp_dom_capability & 0x20 != 0: + self.calibration = 1 + elif sfp_dom_capability & 0x10 != 0: + self.calibration = 2 + else: + self.calibration = 0 + else: + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + self.dom_tx_disable_supported = ( + int(sfp_dom_capability_raw[1], 16) & 0x40 != 0) + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + + 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 + ================================================================================ + """ + + transceiver_info_dict = {} + compliance_code_dict = {} + transceiver_info_dict = dict.fromkeys( + info_dict_keys, NULL_VAL) + transceiver_info_dict["specification_compliance"] = '{}' + + # ToDo: OSFP tranceiver info parsing not fully supported. + # in inf8628.py lack of some memory map definition + # will be implemented when the inf8628 memory map ready + if self.sfp_type == OSFP_TYPE: + offset = 0 + vendor_rev_width = XCVR_HW_REV_WIDTH_OSFP + + sfpi_obj = inf8628InterfaceId() + if sfpi_obj is None: + return transceiver_info_dict + + sfp_type_raw = self._read_eeprom_specific_bytes( + (offset + OSFP_TYPE_OFFSET), XCVR_TYPE_WIDTH) + if sfp_type_raw is not None: + sfp_type_data = sfpi_obj.parse_sfp_type(sfp_type_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_name_raw = self._read_eeprom_specific_bytes( + (offset + OSFP_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH) + if sfp_vendor_name_raw is not None: + sfp_vendor_name_data = sfpi_obj.parse_vendor_name( + sfp_vendor_name_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_pn_raw = self._read_eeprom_specific_bytes( + (offset + OSFP_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH) + if sfp_vendor_pn_raw is not None: + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn( + sfp_vendor_pn_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_rev_raw = self._read_eeprom_specific_bytes( + (offset + OSFP_HW_REV_OFFSET), vendor_rev_width) + if sfp_vendor_rev_raw is not None: + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev( + sfp_vendor_rev_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_sn_raw = self._read_eeprom_specific_bytes( + (offset + OSFP_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH) + if sfp_vendor_sn_raw is not None: + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn( + sfp_vendor_sn_raw, 0) + else: + return transceiver_info_dict + + transceiver_info_dict['type'] = sfp_type_data['data']['type']['value'] + transceiver_info_dict['manufacturer'] = sfp_vendor_name_data['data']['Vendor Name']['value'] + transceiver_info_dict['model'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] + transceiver_info_dict['hardware_rev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] + transceiver_info_dict['serial'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] + + elif self.sfp_type == QSFP_TYPE: + offset = 128 + vendor_rev_width = XCVR_HW_REV_WIDTH_QSFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_QSFP + + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + + elif self.sfp_type == QSFP_DD_TYPE: + offset = 128 + + sfpi_obj = qsfp_dd_InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + + sfp_type_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_TYPE_OFFSET), XCVR_TYPE_WIDTH) + if sfp_type_raw is not None: + sfp_type_data = sfpi_obj.parse_sfp_type(sfp_type_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_name_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH) + if sfp_vendor_name_raw is not None: + sfp_vendor_name_data = sfpi_obj.parse_vendor_name( + sfp_vendor_name_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_pn_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH) + if sfp_vendor_pn_raw is not None: + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn( + sfp_vendor_pn_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_rev_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_HW_REV_OFFSET_QSFP_DD), XCVR_HW_REV_WIDTH_QSFP_DD) + if sfp_vendor_rev_raw is not None: + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev( + sfp_vendor_rev_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_sn_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH) + if sfp_vendor_sn_raw is not None: + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn( + sfp_vendor_sn_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_oui_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_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) + else: + return transceiver_info_dict + + sfp_vendor_date_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_VENDOR_DATE_OFFSET_QSFP_DD), XCVR_VENDOR_DATE_WIDTH_QSFP_DD) + if sfp_vendor_date_raw is not None: + sfp_vendor_date_data = sfpi_obj.parse_vendor_date( + sfp_vendor_date_raw, 0) + else: + return transceiver_info_dict + + sfp_connector_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_CONNECTOR_OFFSET_QSFP_DD), XCVR_CONNECTOR_WIDTH_QSFP_DD) + if sfp_connector_raw is not None: + sfp_connector_data = sfpi_obj.parse_connector( + sfp_connector_raw, 0) + else: + return transceiver_info_dict + + sfp_ext_identifier_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_EXT_TYPE_OFFSET_QSFP_DD), XCVR_EXT_TYPE_WIDTH_QSFP_DD) + if sfp_ext_identifier_raw is not None: + sfp_ext_identifier_data = sfpi_obj.parse_ext_iden( + sfp_ext_identifier_raw, 0) + else: + return transceiver_info_dict + + sfp_cable_len_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_CABLE_LENGTH_OFFSET_QSFP_DD), XCVR_CABLE_LENGTH_WIDTH_QSFP_DD) + if sfp_cable_len_raw is not None: + sfp_cable_len_data = sfpi_obj.parse_cable_len( + sfp_cable_len_raw, 0) + else: + return transceiver_info_dict + + sfp_media_type_raw = self._read_eeprom_specific_bytes( + XCVR_MEDIA_TYPE_OFFSET_QSFP_DD, XCVR_MEDIA_TYPE_WIDTH_QSFP_DD) + if sfp_media_type_raw is not None: + sfp_media_type_dict = sfpi_obj.parse_media_type( + sfp_media_type_raw, 0) + if sfp_media_type_dict is None: + return transceiver_info_dict + + host_media_list = "" + sfp_application_type_first_list = self._read_eeprom_specific_bytes( + (XCVR_FIRST_APPLICATION_LIST_OFFSET_QSFP_DD), XCVR_FIRST_APPLICATION_LIST_WIDTH_QSFP_DD) + if self.second_application_list: + possible_application_count = 15 + sfp_application_type_second_list = self._read_eeprom_specific_bytes( + (XCVR_SECOND_APPLICATION_LIST_OFFSET_QSFP_DD), XCVR_SECOND_APPLICATION_LIST_WIDTH_QSFP_DD) + if sfp_application_type_first_list is not None and sfp_application_type_second_list is not None: + sfp_application_type_list = sfp_application_type_first_list + \ + sfp_application_type_second_list + else: + return transceiver_info_dict + else: + possible_application_count = 8 + if sfp_application_type_first_list is not None: + sfp_application_type_list = sfp_application_type_first_list + else: + return transceiver_info_dict + + for i in range(0, possible_application_count): + if sfp_application_type_list[i * 4] == 'ff': + break + host_electrical, media_interface = sfpi_obj.parse_application( + sfp_media_type_dict, sfp_application_type_list[i * 4], sfp_application_type_list[i * 4 + 1]) + host_media_list = host_media_list + host_electrical + \ + ' - ' + media_interface + '\n\t\t\t\t ' + else: + return transceiver_info_dict + + transceiver_info_dict['type'] = str( + sfp_type_data['data']['type']['value']) + transceiver_info_dict['manufacturer'] = str( + sfp_vendor_name_data['data']['Vendor Name']['value']) + transceiver_info_dict['model'] = str( + sfp_vendor_pn_data['data']['Vendor PN']['value']) + transceiver_info_dict['hardware_rev'] = str( + sfp_vendor_rev_data['data']['Vendor Rev']['value']) + transceiver_info_dict['serial'] = str( + sfp_vendor_sn_data['data']['Vendor SN']['value']) + transceiver_info_dict['vendor_oui'] = str( + sfp_vendor_oui_data['data']['Vendor OUI']['value']) + transceiver_info_dict['vendor_date'] = str( + sfp_vendor_date_data['data']['VendorDataCode(YYYY-MM-DD Lot)']['value']) + transceiver_info_dict['connector'] = str( + sfp_connector_data['data']['Connector']['value']) + transceiver_info_dict['encoding'] = "Not supported for CMIS cables" + transceiver_info_dict['ext_identifier'] = str( + sfp_ext_identifier_data['data']['Extended Identifier']['value']) + transceiver_info_dict['ext_rateselect_compliance'] = "Not supported for CMIS cables" + transceiver_info_dict['specification_compliance'] = "Not supported for CMIS cables" + transceiver_info_dict['cable_type'] = "Length Cable Assembly(m)" + transceiver_info_dict['cable_length'] = str( + sfp_cable_len_data['data']['Length Cable Assembly(m)']['value']) + transceiver_info_dict['nominal_bit_rate'] = "Not supported for CMIS cables" + transceiver_info_dict['application_advertisement'] = host_media_list + + else: + offset = 0 + vendor_rev_width = XCVR_HW_REV_WIDTH_SFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_SFP + + sfpi_obj = sff8472InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + + if self.sfp_type != QSFP_DD_TYPE: + sfp_interface_bulk_raw = self._read_eeprom_specific_bytes( + offset + XCVR_INTERFACE_DATA_START, XCVR_INTERFACE_DATA_SIZE) + if sfp_interface_bulk_raw is None: + return transceiver_info_dict + + start = XCVR_INTFACE_BULK_OFFSET - XCVR_INTERFACE_DATA_START + end = start + interface_info_bulk_width + sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk( + sfp_interface_bulk_raw[start: end], 0) + + start = XCVR_VENDOR_NAME_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_NAME_WIDTH + sfp_vendor_name_data = sfpi_obj.parse_vendor_name( + sfp_interface_bulk_raw[start: end], 0) + + start = XCVR_VENDOR_PN_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_PN_WIDTH + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn( + sfp_interface_bulk_raw[start: end], 0) + + start = XCVR_HW_REV_OFFSET - XCVR_INTERFACE_DATA_START + end = start + vendor_rev_width + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev( + sfp_interface_bulk_raw[start: end], 0) + + start = XCVR_VENDOR_SN_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_SN_WIDTH + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn( + sfp_interface_bulk_raw[start: end], 0) + + start = XCVR_VENDOR_OUI_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_OUI_WIDTH + sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui( + sfp_interface_bulk_raw[start: end], 0) + + start = XCVR_VENDOR_DATE_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_DATE_WIDTH + sfp_vendor_date_data = sfpi_obj.parse_vendor_date( + sfp_interface_bulk_raw[start: end], 0) + + transceiver_info_dict['type'] = sfp_interface_bulk_data['data']['type']['value'] + transceiver_info_dict['manufacturer'] = sfp_vendor_name_data['data']['Vendor Name']['value'] + transceiver_info_dict['model'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] + transceiver_info_dict['hardware_rev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] + transceiver_info_dict['serial'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] + transceiver_info_dict['vendor_oui'] = sfp_vendor_oui_data['data']['Vendor OUI']['value'] + transceiver_info_dict['vendor_date'] = sfp_vendor_date_data[ + 'data']['VendorDataCode(YYYY-MM-DD Lot)']['value'] + transceiver_info_dict['connector'] = sfp_interface_bulk_data['data']['Connector']['value'] + transceiver_info_dict['encoding'] = sfp_interface_bulk_data['data']['EncodingCodes']['value'] + transceiver_info_dict['ext_identifier'] = sfp_interface_bulk_data['data']['Extended Identifier']['value'] + transceiver_info_dict['ext_rateselect_compliance'] = sfp_interface_bulk_data['data']['RateIdentifier']['value'] + + if self.sfp_type == QSFP_TYPE: + for key in qsfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_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'] + sfp_ext_specification_compliance_raw = self._read_eeprom_specific_bytes( + offset + XCVR_EXT_SPECIFICATION_COMPLIANCE_OFFSET, XCVR_EXT_SPECIFICATION_COMPLIANCE_WIDTH) + if sfp_ext_specification_compliance_raw is not None: + sfp_ext_specification_compliance_data = sfpi_obj.parse_ext_specification_compliance( + sfp_ext_specification_compliance_raw[0: 1], 0) + if sfp_ext_specification_compliance_data['data']['Extended Specification compliance']['value'] != "Unspecified": + compliance_code_dict['Extended Specification compliance'] = sfp_ext_specification_compliance_data[ + 'data']['Extended Specification compliance']['value'] + transceiver_info_dict['specification_compliance'] = str( + compliance_code_dict) + transceiver_info_dict['nominal_bit_rate'] = str( + sfp_interface_bulk_data['data']['Nominal Bit Rate(100Mbs)']['value']) + else: + for key in sfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_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'] + transceiver_info_dict['specification_compliance'] = str( + compliance_code_dict) + + transceiver_info_dict['nominal_bit_rate'] = str( + sfp_interface_bulk_data['data']['NominalSignallingRate(UnitsOf100Mbd)']['value']) + + return transceiver_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. + ======================================================================== + """ + transceiver_dom_info_dict = dict.fromkeys( + dom_info_dict_keys, NULL_VAL) + + if self.sfp_type == OSFP_TYPE: + pass + + elif self.sfp_type == QSFP_TYPE: + if not self.dom_supported: + return transceiver_dom_info_dict + + offset = 0 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return transceiver_dom_info_dict + + dom_data_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DOM_BULK_DATA_START), QSFP_DOM_BULK_DATA_SIZE) + if dom_data_raw is None: + return transceiver_dom_info_dict + + if self.dom_temp_supported: + start = QSFP_TEMPE_OFFSET - QSFP_DOM_BULK_DATA_START + end = start + QSFP_TEMPE_WIDTH + dom_temperature_data = sfpd_obj.parse_temperature( + dom_data_raw[start: end], 0) + temp = dom_temperature_data['data']['Temperature']['value'] + if temp is not None: + transceiver_dom_info_dict['temperature'] = temp + + if self.dom_volt_supported: + start = QSFP_VOLT_OFFSET - QSFP_DOM_BULK_DATA_START + end = start + QSFP_VOLT_WIDTH + dom_voltage_data = sfpd_obj.parse_voltage( + dom_data_raw[start: end], 0) + volt = dom_voltage_data['data']['Vcc']['value'] + if volt is not None: + transceiver_dom_info_dict['voltage'] = volt + + start = QSFP_CHANNL_MON_OFFSET - QSFP_DOM_BULK_DATA_START + end = start + QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power( + dom_data_raw[start: end], 0) + + if self.dom_tx_power_supported: + transceiver_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TX1Power']['value'] + transceiver_dom_info_dict['tx2power'] = dom_channel_monitor_data['data']['TX2Power']['value'] + transceiver_dom_info_dict['tx3power'] = dom_channel_monitor_data['data']['TX3Power']['value'] + transceiver_dom_info_dict['tx4power'] = dom_channel_monitor_data['data']['TX4Power']['value'] + + if self.dom_rx_power_supported: + transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RX1Power']['value'] + transceiver_dom_info_dict['rx2power'] = dom_channel_monitor_data['data']['RX2Power']['value'] + transceiver_dom_info_dict['rx3power'] = dom_channel_monitor_data['data']['RX3Power']['value'] + transceiver_dom_info_dict['rx4power'] = dom_channel_monitor_data['data']['RX4Power']['value'] + + transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TX1Bias']['value'] + transceiver_dom_info_dict['tx2bias'] = dom_channel_monitor_data['data']['TX2Bias']['value'] + transceiver_dom_info_dict['tx3bias'] = dom_channel_monitor_data['data']['TX3Bias']['value'] + transceiver_dom_info_dict['tx4bias'] = dom_channel_monitor_data['data']['TX4Bias']['value'] + + elif self.sfp_type == QSFP_DD_TYPE: + + offset = 0 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return transceiver_dom_info_dict + + dom_data_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_DOM_BULK_DATA_START), QSFP_DD_DOM_BULK_DATA_SIZE) + if dom_data_raw is None: + return transceiver_dom_info_dict + + if self.dom_temp_supported: + start = QSFP_DD_TEMPE_OFFSET - QSFP_DD_DOM_BULK_DATA_START + end = start + QSFP_DD_TEMPE_WIDTH + dom_temperature_data = sfpd_obj.parse_temperature( + dom_data_raw[start: end], 0) + temp = dom_temperature_data['data']['Temperature']['value'] + if temp is not None: + transceiver_dom_info_dict['temperature'] = temp + + if self.dom_volt_supported: + start = QSFP_DD_VOLT_OFFSET - QSFP_DD_DOM_BULK_DATA_START + end = start + QSFP_DD_VOLT_WIDTH + dom_voltage_data = sfpd_obj.parse_voltage( + dom_data_raw[start: end], 0) + volt = dom_voltage_data['data']['Vcc']['value'] + if volt is not None: + transceiver_dom_info_dict['voltage'] = volt + + if self.dom_rx_tx_power_bias_supported: + # page 11h + dom_data_raw = self._read_eeprom_specific_bytes( + (QSFP_DD_CHANNL_MON_OFFSET), QSFP_DD_CHANNL_MON_WIDTH) + if dom_data_raw is None: + return transceiver_dom_info_dict + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( + dom_data_raw, 0) + + if self.dom_tx_power_supported: + transceiver_dom_info_dict['tx1power'] = str( + dom_channel_monitor_data['data']['TX1Power']['value']) + transceiver_dom_info_dict['tx2power'] = str( + dom_channel_monitor_data['data']['TX2Power']['value']) + transceiver_dom_info_dict['tx3power'] = str( + dom_channel_monitor_data['data']['TX3Power']['value']) + transceiver_dom_info_dict['tx4power'] = str( + dom_channel_monitor_data['data']['TX4Power']['value']) + transceiver_dom_info_dict['tx5power'] = str( + dom_channel_monitor_data['data']['TX5Power']['value']) + transceiver_dom_info_dict['tx6power'] = str( + dom_channel_monitor_data['data']['TX6Power']['value']) + transceiver_dom_info_dict['tx7power'] = str( + dom_channel_monitor_data['data']['TX7Power']['value']) + transceiver_dom_info_dict['tx8power'] = str( + dom_channel_monitor_data['data']['TX8Power']['value']) + + if self.dom_rx_power_supported: + transceiver_dom_info_dict['rx1power'] = str( + dom_channel_monitor_data['data']['RX1Power']['value']) + transceiver_dom_info_dict['rx2power'] = str( + dom_channel_monitor_data['data']['RX2Power']['value']) + transceiver_dom_info_dict['rx3power'] = str( + dom_channel_monitor_data['data']['RX3Power']['value']) + transceiver_dom_info_dict['rx4power'] = str( + dom_channel_monitor_data['data']['RX4Power']['value']) + transceiver_dom_info_dict['rx5power'] = str( + dom_channel_monitor_data['data']['RX5Power']['value']) + transceiver_dom_info_dict['rx6power'] = str( + dom_channel_monitor_data['data']['RX6Power']['value']) + transceiver_dom_info_dict['rx7power'] = str( + dom_channel_monitor_data['data']['RX7Power']['value']) + transceiver_dom_info_dict['rx8power'] = str( + dom_channel_monitor_data['data']['RX8Power']['value']) + + if self.dom_tx_bias_power_supported: + transceiver_dom_info_dict['tx1bias'] = str( + dom_channel_monitor_data['data']['TX1Bias']['value']) + transceiver_dom_info_dict['tx2bias'] = str( + dom_channel_monitor_data['data']['TX2Bias']['value']) + transceiver_dom_info_dict['tx3bias'] = str( + dom_channel_monitor_data['data']['TX3Bias']['value']) + transceiver_dom_info_dict['tx4bias'] = str( + dom_channel_monitor_data['data']['TX4Bias']['value']) + transceiver_dom_info_dict['tx5bias'] = str( + dom_channel_monitor_data['data']['TX5Bias']['value']) + transceiver_dom_info_dict['tx6bias'] = str( + dom_channel_monitor_data['data']['TX6Bias']['value']) + transceiver_dom_info_dict['tx7bias'] = str( + dom_channel_monitor_data['data']['TX7Bias']['value']) + transceiver_dom_info_dict['tx8bias'] = str( + dom_channel_monitor_data['data']['TX8Bias']['value']) + + return transceiver_dom_info_dict + + else: + if not self.dom_supported: + return transceiver_dom_info_dict + + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return transceiver_dom_info_dict + sfpd_obj._calibration_type = self.calibration + + dom_data_raw = self._read_eeprom_specific_bytes( + (offset + SFP_DOM_BULK_DATA_START), SFP_DOM_BULK_DATA_SIZE) + if dom_data_raw is None: + return transceiver_dom_info_dict + + start = SFP_TEMPE_OFFSET - SFP_DOM_BULK_DATA_START + end = start + SFP_TEMPE_WIDTH + dom_temperature_data = sfpd_obj.parse_temperature( + dom_data_raw[start: end], 0) + + start = SFP_VOLT_OFFSET - SFP_DOM_BULK_DATA_START + end = start + SFP_VOLT_WIDTH + dom_voltage_data = sfpd_obj.parse_voltage( + dom_data_raw[start: end], 0) + + start = SFP_CHANNL_MON_OFFSET - SFP_DOM_BULK_DATA_START + end = start + SFP_CHANNL_MON_WIDTH + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( + dom_data_raw[start: end], 0) + + transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RXPower']['value'] + transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TXBias']['value'] + transceiver_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TXPower']['value'] + + transceiver_dom_info_dict['lp_mode'] = self.get_lpmode() + transceiver_dom_info_dict['reset_status'] = self.get_reset_status() + transceiver_dom_info_dict['tx_disable'] = self.get_tx_disable() + transceiver_dom_info_dict['tx_disabled_channel'] = self.get_tx_disable_channel( + ) + + for key in transceiver_dom_info_dict: + val = transceiver_dom_info_dict[key] + transceiver_dom_info_dict[key] = self._convert_string_to_num( + val) if type(val) is str else val + + return transceiver_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. + ======================================================================== + """ + transceiver_dom_threshold_info_dict = dict.fromkeys( + threshold_dict_keys, NULL_VAL) + + if self.sfp_type == OSFP_TYPE: + pass + + elif self.sfp_type == QSFP_TYPE: + if not self.dom_supported or not self.qsfp_page3_available: + return transceiver_dom_threshold_info_dict + + # Dom Threshold data starts from offset 384 + # Revert offset back to 0 once data is retrieved + offset = QSFP_MODULE_UPPER_PAGE3_START + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return transceiver_dom_threshold_info_dict + + dom_module_threshold_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_MODULE_THRESHOLD_OFFSET), QSFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is None: + return transceiver_dom_threshold_info_dict + + dom_module_threshold_data = sfpd_obj.parse_module_threshold_values( + dom_module_threshold_raw, 0) + + dom_channel_threshold_raw = self._read_eeprom_specific_bytes((offset + QSFP_CHANNL_THRESHOLD_OFFSET), + QSFP_CHANNL_THRESHOLD_WIDTH) + if dom_channel_threshold_raw is None: + return transceiver_dom_threshold_info_dict + dom_channel_threshold_data = sfpd_obj.parse_channel_threshold_values( + dom_channel_threshold_raw, 0) + + # Threshold Data + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VccHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VccHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VccLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VccLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_channel_threshold_data['data']['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_channel_threshold_data['data']['RxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_channel_threshold_data['data']['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_channel_threshold_data['data']['RxPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_channel_threshold_data['data']['TxBiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_channel_threshold_data['data']['TxBiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_channel_threshold_data['data']['TxBiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_channel_threshold_data['data']['TxBiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_channel_threshold_data['data']['TxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_channel_threshold_data['data']['TxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_channel_threshold_data['data']['TxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_channel_threshold_data['data']['TxPowerLowWarning']['value'] + + elif self.sfp_type == QSFP_DD_TYPE: + if not self.dom_supported: + return transceiver_dom_threshold_info_dict + + if not self.dom_thresholds_supported: + return transceiver_dom_threshold_info_dict + + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return transceiver_dom_threshold_info_dict + + # page 02 + offset = 384 + dom_module_threshold_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_MODULE_THRESHOLD_OFFSET), QSFP_DD_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is None: + return transceiver_dom_threshold_info_dict + + dom_module_threshold_data = sfpd_obj.parse_module_threshold_values( + dom_module_threshold_raw, 0) + + # Threshold Data + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VccHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VccHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VccLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VccLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RxPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['TxBiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['TxBiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['TxBiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['TxBiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TxPowerLowWarning']['value'] + + else: + offset = SFP_MODULE_ADDRA2_OFFSET + + if not self.dom_supported: + return transceiver_dom_threshold_info_dict + + sfpd_obj = sff8472Dom(None, self.calibration) + if sfpd_obj is None: + return transceiver_dom_threshold_info_dict + + 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) + else: + return transceiver_dom_threshold_info_dict + + # Threshold Data + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VoltageHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VoltageLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data[ + 'data']['VoltageHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VoltageLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['BiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['BiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['BiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['BiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TXPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RXPowerLowWarning']['value'] + + for key in transceiver_dom_threshold_info_dict: + transceiver_dom_threshold_info_dict[key] = self._convert_string_to_num( + transceiver_dom_threshold_info_dict[key]) + + return transceiver_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 + """ + if not self.get_presence(): + return False + + if 1 <= self._port_num <= 10 or 21 <= self._port_num <= 30: + reset_path = "{}{}{}".format(CPLD2_I2C_PATH, '/module_reset_', self._port_num) + elif 11 <= self._port_num <= 20 or 31 <= self._port_num <= 40: + reset_path = "{}{}{}".format(CPLD3_I2C_PATH, '/module_reset_', self._port_num) + elif 41 <= self._port_num <= 53: + reset_path = "{}{}{}".format(CPLD4_I2C_PATH, '/module_reset_', self._port_num) + else: + return False + + val = self._api_helper.read_txt_file(reset_path) + if val is not None: + return int(val, 10)==1 + else: + return False + + 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_list = [] + + if self.sfp_type == OSFP_TYPE: + return None + elif self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_RX_LOS_STATUS_OFFSET), + QSFP_CHANNL_RX_LOS_STATUS_WIDTH) + 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) + else: + return [False] * 4 + + elif self.sfp_type == QSFP_DD_TYPE: + # page 11h + if self.dom_rx_tx_power_bias_supported: + offset = 128 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_CHANNL_RX_LOS_STATUS_OFFSET), + QSFP_DD_CHANNL_RX_LOS_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 8) + 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_list.append(rx_los_data & 0x10 != 0) + rx_los_list.append(rx_los_data & 0x20 != 0) + rx_los_list.append(rx_los_data & 0x40 != 0) + rx_los_list.append(rx_los_data & 0x80 != 0) + else: + return [False] * 8 + else: # SFP_TYPE + offset = 256 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH) + 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 & 0x02 != 0) + else: + return [False] + return rx_los_list + + 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_list = [] + + if self.sfp_type == OSFP_TYPE: + return None + elif self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_TX_FAULT_STATUS_OFFSET), + QSFP_CHANNL_TX_FAULT_STATUS_WIDTH) + 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) + else: + return [False] * 4 + elif self.sfp_type == QSFP_DD_TYPE: + # page 11h + if self.dom_rx_tx_power_bias_supported: + offset = 128 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_CHANNL_TX_FAULT_STATUS_OFFSET), + QSFP_DD_CHANNL_TX_FAULT_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_fault_data = int(dom_channel_monitor_raw[0], 8) + 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_list.append(tx_fault_data & 0x10 != 0) + tx_fault_list.append(tx_fault_data & 0x20 != 0) + tx_fault_list.append(tx_fault_data & 0x40 != 0) + tx_fault_list.append(tx_fault_data & 0x80 != 0) + else: + return [False] * 8 + else: # SFP_TYPE + offset = 256 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH) + 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 & 0x04 != 0) + else: + return None + return tx_fault_list + + def get_tx_disable(self): + """ + Retrieves the tx_disable status of this SFP + Returns: + A list of boolean values, representing the TX disable status + of each available channel, value is True if SFP channel + is TX disabled, False if not. + E.g., for a tranceiver with four channels: [False, False, True, False] + """ + tx_disable_list = [] + if self.sfp_type == OSFP_TYPE: + return None + elif self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_DISABLE_STATUS_OFFSET), + QSFP_CHANNL_DISABLE_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0x01 != 0) + tx_disable_list.append(tx_disable_data & 0x02 != 0) + tx_disable_list.append(tx_disable_data & 0x04 != 0) + tx_disable_list.append(tx_disable_data & 0x08 != 0) + else: + return [False] * 4 + + elif self.sfp_type == QSFP_DD_TYPE: + if self.dom_rx_tx_power_bias_supported: + offset = 128 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_CHANNL_DISABLE_STATUS_OFFSET), + QSFP_DD_CHANNL_DISABLE_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0x01 != 0) + tx_disable_list.append(tx_disable_data & 0x02 != 0) + tx_disable_list.append(tx_disable_data & 0x04 != 0) + tx_disable_list.append(tx_disable_data & 0x08 != 0) + tx_disable_list.append(tx_disable_data & 0x10 != 0) + tx_disable_list.append(tx_disable_data & 0x20 != 0) + tx_disable_list.append(tx_disable_data & 0x40 != 0) + tx_disable_list.append(tx_disable_data & 0x80 != 0) + else: + return [False] * 8 + else: # SFP_TYPE + offset = 256 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0xC0 != 0) + else: + return [False] + return tx_disable_list + + 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. + """ + 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 + + 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 + """ + if self._port_num > 32: + # SFP doesn't support this feature + return False + else: + try: + eeprom = None + + if not self.get_presence(): + return False + # Write to eeprom + port_eeprom_path = I2C_EEPROM_PATH.format(self._port_to_i2c_mapping[self._port_num][0]) + + eeprom = open(port_eeprom_path, "rb", buffering=0) + eeprom.seek(QSFP_POWEROVERRIDE_OFFSET) + 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: + # 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 + return False + 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) + + def get_power_set(self): + + if self._port_num > 32: + # SFP doesn't support this feature + return False + else: + power_set = False + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return False + + dom_control_raw = self._read_eeprom_specific_bytes( + QSFP_POWEROVERRIDE_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_set = ( + 'On' == dom_control_data['data']['PowerSet']['value']) + + return power_set + + 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 + """ + if self.sfp_type == QSFP_TYPE: + offset = 0 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return False + + dom_control_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_CONTROL_OFFSET), QSFP_CONTROL_WIDTH) + if dom_control_raw is not None: + dom_control_data = sfpd_obj.parse_control_bytes( + dom_control_raw, 0) + return ('On' == dom_control_data['data']['PowerOverride']) + else: + return False + else: + return NotImplementedError + + def get_temperature(self): + """ + Retrieves the temperature of this SFP + Returns: + An integer number of current temperature in Celsius + """ + default = 0.0 + if not self.dom_supported: + return default + + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return default + + if self.dom_temp_supported: + 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) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + + elif self.sfp_type == QSFP_DD_TYPE: + offset = 0 + + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if self.dom_temp_supported: + dom_temperature_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_TEMPE_OFFSET), QSFP_DD_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature( + dom_temperature_raw, 0) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + + else: + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + sfpd_obj._calibration_type = 1 + + 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) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + + return default + + def get_voltage(self): + """ + Retrieves the supply voltage of this SFP + Returns: + An integer number of supply voltage in mV + """ + default = 0.0 + + if not self.dom_supported: + return default + + if self.sfp_type == QSFP_TYPE: + offset = 0 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return default + + if self.dom_volt_supported: + 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) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + + if self.sfp_type == QSFP_DD_TYPE: + offset = 128 + + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if self.dom_volt_supported: + dom_voltage_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_VOLT_OFFSET), QSFP_DD_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage( + dom_voltage_raw, 0) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + + else: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + + sfpd_obj._calibration_type = self.calibration + + 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) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + + return default + + 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'] + """ + tx_bias_list = [] + if self.sfp_type == QSFP_TYPE: + offset = 0 + default = [0.0] * 4 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return default + + 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) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX1Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX2Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX3Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX4Bias']['value'])) + else: + return default + + elif self.sfp_type == QSFP_DD_TYPE: + default = [0.0] * 8 + # page 11h + if self.dom_rx_tx_power_bias_supported: + offset = 128 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if dom_tx_bias_power_supported: + dom_tx_bias_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_TX_BIAS_OFFSET), QSFP_DD_TX_BIAS_WIDTH) + if dom_tx_bias_raw is not None: + dom_tx_bias_data = sfpd_obj.parse_dom_tx_bias( + dom_tx_bias_raw, 0) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX1Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX2Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX3Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX4Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX5Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX6Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX7Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX8Bias']['value'])) + else: + return default + else: + return default + + else: + offset = 256 + default = [0.0] + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + sfpd_obj._calibration_type = self.calibration + + if self.dom_supported: + 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) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TXBias']['value'])) + else: + return default + else: + return default + + return tx_bias_list + + 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'] + """ + rx_power_list = [] + if self.sfp_type == OSFP_TYPE: + # OSFP not supported on our platform yet. + return None + + elif self.sfp_type == QSFP_TYPE: + offset = 0 + default = [0.0] * 4 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return default + + if self.dom_rx_power_supported: + 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) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX1Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX2Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX3Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX4Power']['value'])) + else: + return default + else: + return default + + elif self.sfp_type == QSFP_DD_TYPE: + default = [0.0] * 8 + # page 11 + if self.dom_rx_tx_power_bias_supported: + offset = 128 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if self.dom_rx_power_supported: + dom_rx_power_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_RX_POWER_OFFSET), QSFP_DD_RX_POWER_WIDTH) + if dom_rx_power_raw is not None: + dom_rx_power_data = sfpd_obj.parse_dom_rx_power( + dom_rx_power_raw, 0) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX1Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX2Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX3Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX4Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX5Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX6Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX7Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX8Power']['value'])) + else: + return default + else: + return default + + else: + offset = 256 + default = [0.0] + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + + if self.dom_supported: + sfpd_obj._calibration_type = self.calibration + + 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) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RXPower']['value'])) + else: + return default + else: + return default + return rx_power_list + + 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'] + """ + tx_power_list = [] + if self.sfp_type == OSFP_TYPE: + # OSFP not supported on our platform yet. + return tx_power_list + + elif self.sfp_type == QSFP_TYPE: + offset = 0 + default = [0.0] * 4 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return tx_power_list + + if self.dom_tx_power_supported: + 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) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX1Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX2Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX3Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX4Power']['value'])) + else: + return default + else: + return default + + elif self.sfp_type == QSFP_DD_TYPE: + default = [0.0] * 8 + + # page 11 + if self.dom_rx_tx_power_bias_supported: + offset = 128 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if self.dom_tx_power_supported: + dom_tx_power_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_TX_POWER_OFFSET), + QSFP_DD_TX_POWER_WIDTH) + if dom_tx_power_raw is not None: + dom_tx_power_data = sfpd_obj.parse_dom_tx_power( + dom_tx_power_raw, 0) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX1Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX2Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX3Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX4Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX5Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX6Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX7Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX8Power']['value'])) + else: + return default + else: + return default + + else: + offset = 256 + default = [0.0] + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + + if self.dom_supported: + sfpd_obj._calibration_type = self.calibration + + 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) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TXPower']['value'])) + else: + return default + else: + return default + return tx_power_list + + def reset(self): + """ + Reset SFP and return all user module settings to their default srate. + Returns: + A boolean, True if successful, False if not + """ + # Check for invalid port_num + + if not self.get_presence(): + return False + + if 1 <= self._port_num <= 10 or 21 <= self._port_num <= 30: + reset_path = "{}{}{}".format(CPLD2_I2C_PATH, '/module_reset_', self._port_num) + elif 11 <= self._port_num <= 20 or 31 <= self._port_num <= 40: + reset_path = "{}{}{}".format(CPLD3_I2C_PATH, '/module_reset_', self._port_num) + elif 41 <= self._port_num <= 53: + reset_path = "{}{}{}".format(CPLD4_I2C_PATH, '/module_reset_', self._port_num) + else: + return False + + ret = self._api_helper.write_txt_file(reset_path, 1) #sysfs 1: enable reset + if ret is not True: + return ret + + time.sleep(0.2) + ret = self._api_helper.write_txt_file(reset_path, 0) #sysfs 1: disable reset + time.sleep(0.2) + + return ret + + 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 + """ + if self.sfp_type == QSFP_TYPE: + sysfsfile_eeprom = None + try: + tx_disable_value = 0xf if tx_disable else 0x0 + # Write to eeprom + sysfsfile_eeprom = open(self._eeprom_path, "r+b") + sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) + sysfsfile_eeprom.write(struct.pack('B', tx_disable_value)) + except IOError: + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + elif self.sfp_type == SFP_TYPE: + disable_path = "{}{}{}".format(CPLD2_I2C_PATH, '/module_tx_disable_', self._port_num) + tx_disable_value = 1 if tx_disable else 0 + ret = self._api_helper.write_txt_file(disable_path, tx_disable_value) #sysfs 1: disable tx + if ret is not True: + return ret + + return False + + 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 + """ + if self.sfp_type == QSFP_TYPE: + sysfsfile_eeprom = None + try: + current_state = self.get_tx_disable_channel() + tx_disable_value = (current_state | channel) if \ + disable else (current_state & (~channel)) + + # Write to eeprom + sysfsfile_eeprom = open(self._eeprom_path, "r+b") + sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) + sysfsfile_eeprom.write(struct.pack('B', tx_disable_value)) + except IOError: + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + + return False + + 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 + """ + if 54 <= self._port_num <= 55: + return False # SFP doesn't support this feature + else: + if not self.get_presence(): + return False + + if lpmode is True: + self.set_power_override(True, True) + else: + self.set_power_override(True, False) + + return True + + 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 + """ + if 54 <= self._port_num <= 55: + return False # SFP doesn't support this feature + else: + if not self.get_presence(): + return False + try: + power_override_bit = (1 << 0) if power_override else 0 + power_set_bit = (1 << 1) if power_set else (1 << 3) + + buffer = create_string_buffer(1) + if sys.version_info[0] >= 3: + buffer[0] = (power_override_bit | power_set_bit) + else: + buffer[0] = chr(power_override_bit | power_set_bit) + # Write to eeprom + port_eeprom_path = I2C_EEPROM_PATH.format(self._port_to_i2c_mapping[self._port_num][0]) + with open(port_eeprom_path, "r+b") as fd: + fd.seek(QSFP_POWEROVERRIDE_OFFSET) + fd.write(buffer[0]) + time.sleep(0.01) + except Exception as e: + print ('Error: unable to open file: ', str(e)) + return False + return True + + ############################################################## + ###################### Device methods ######################## + ############################################################## + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + sfputil_helper = SfpUtilHelper() + sfputil_helper.read_porttab_mappings( + self.__get_path_to_port_config_file()) + name = sfputil_helper.logical[self._index] or "Unknown" + return name + + def get_presence(self): + """ + Retrieves the presence of the device + Returns: + bool: True if device is present, False if not + """ + if 1 <= self._port_num <= 10 or 21 <= self._port_num <= 30 or 54 <= self._port_num <= 55: + present_path = "{}{}{}".format(CPLD2_I2C_PATH, '/module_present_', self._port_num) + elif 11 <= self._port_num <= 20 or 31 <= self._port_num <= 40: + present_path = "{}{}{}".format(CPLD3_I2C_PATH, '/module_present_', self._port_num) + elif 41 <= self._port_num <= 53: + present_path = "{}{}{}".format(CPLD4_I2C_PATH, '/module_present_', self._port_num) + else: + return False + + val=self._api_helper.read_txt_file(present_path) + if val is not None: + return int(val, 10)==1 + else: + return False + + + 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() + return transceiver_dom_info_dict.get("model", "N/A") + + 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() + return transceiver_dom_info_dict.get("serial", "N/A") + + 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 not self.get_reset_status() + + def get_position_in_parent(self): + """ + Returns: + Temp return 0 + """ + return 0 + + def is_replaceable(self): + """ + Retrieves if replaceable + Returns: + A boolean value, True if replaceable + """ + return True diff --git a/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/thermal.py b/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/thermal.py new file mode 100644 index 00000000000..efe0f2829b1 --- /dev/null +++ b/device/accton/x86_64-accton_as7926_40xfb-r0/sonic_platform/thermal.py @@ -0,0 +1,143 @@ +############################################################################# +# Edgecore +# +# Thermal contains an implementation of SONiC Platform Base API and +# provides the thermal device status which are available in the platform +# +############################################################################# + +import os +import os.path +import glob + +try: + from sonic_platform_base.thermal_base import ThermalBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Thermal(ThermalBase): + """Platform-specific Thermal class""" + + THERMAL_NAME_LIST = [] + SYSFS_PATH = "/sys/devices/platform/as7926_40xfb_thermal/" + + def __init__(self, thermal_index=0): + self.index = thermal_index + # Add thermal name + self.THERMAL_NAME_LIST.append("Temp sensor 1") + self.THERMAL_NAME_LIST.append("Temp sensor 2") + self.THERMAL_NAME_LIST.append("Temp sensor 3") + self.THERMAL_NAME_LIST.append("Temp sensor 4") + self.THERMAL_NAME_LIST.append("Temp sensor 5") + self.THERMAL_NAME_LIST.append("Temp sensor 6") + self.THERMAL_NAME_LIST.append("Temp sensor 7") + self.THERMAL_NAME_LIST.append("Temp sensor 8") + self.THERMAL_NAME_LIST.append("Temp sensor 9") + self.THERMAL_NAME_LIST.append("Temp sensor 10") + + self.hwmon_path = self.SYSFS_PATH + self.ss_key = self.THERMAL_NAME_LIST[self.index] + self.ss_index = self.index + 1 + + def __read_txt_file(self, file_path): + for filename in glob.glob(file_path): + try: + with open(filename, 'r') as fd: + data =fd.readline().rstrip() + return data + except IOError as e: + pass + + return None + + def __get_temp(self, temp_file): + temp_file_path = os.path.join(self.hwmon_path, temp_file) + raw_temp = self.__read_txt_file(temp_file_path) + if raw_temp is not None: + return float(raw_temp)/1000 + else: + return 0 + + + def __set_threshold(self, file_name, temperature): + temp_file_path = os.path.join(self.hwmon_path, file_name) + for filename in glob.glob(temp_file_path): + try: + with open(filename, 'w') as fd: + fd.write(str(temperature)) + return True + except IOError as e: + print("IOError") + + def get_temperature(self): + """ + Retrieves current temperature reading from thermal + Returns: + A float number of current temperature in Celsius up to nearest thousandth + of one degree Celsius, e.g. 30.125 + """ + temp_file = "temp{}_input".format(self.ss_index) + return self.__get_temp(temp_file) + + def get_high_threshold(self): + """ + Retrieves the high threshold temperature of thermal + Returns: + A float number, the high threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + temp_file = "temp{}_max".format(self.ss_index) + return self.__get_temp(temp_file) + + def set_high_threshold(self, temperature): + """ + Sets the high threshold temperature of thermal + Args : + temperature: A float number up to nearest thousandth of one degree Celsius, + e.g. 30.125 + Returns: + A boolean, True if threshold is set successfully, False if not + """ + temp_file = "temp{}_max".format(self.ss_index) + temperature = temperature *1000 + self.__set_threshold(temp_file, temperature) + + return True + + def get_name(self): + """ + Retrieves the name of the thermal device + Returns: + string: The name of the thermal device + """ + return self.THERMAL_NAME_LIST[self.index] + + def get_presence(self): + """ + Retrieves the presence of the Thermal + Returns: + bool: True if Thermal is present, False if not + """ + temp_file = "temp{}_input".format(self.ss_index) + temp_file_path = os.path.join(self.hwmon_path, temp_file) + raw_txt = self.__read_txt_file(temp_file_path) + if raw_txt is not None: + return True + else: + return False + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + + file_str = "temp{}_input".format(self.ss_index) + file_path = os.path.join(self.hwmon_path, file_str) + raw_txt = self.__read_txt_file(file_path) + if raw_txt is None: + return False + else: + return int(raw_txt) != 0 diff --git a/device/accton/x86_64-accton_as9726_32d-r0/plugins/sfputil.py b/device/accton/x86_64-accton_as9726_32d-r0/plugins/sfputil.py index 2a365815cab..b297a1a1ddd 100755 --- a/device/accton/x86_64-accton_as9726_32d-r0/plugins/sfputil.py +++ b/device/accton/x86_64-accton_as9726_32d-r0/plugins/sfputil.py @@ -5,7 +5,6 @@ try: import time - from ctypes import create_string_buffer from sonic_sfp.sfputilbase import SfpUtilBase except ImportError as e: raise ImportError("%s - required module not found" % str(e)) @@ -125,61 +124,45 @@ def get_presence(self, port_num): def get_low_power_mode(self, port_num): if port_num > self.QSFP_PORT_END: #sfp not support lpmode return False - try: - eeprom = None - - if not self.get_presence(port_num): - return False - eeprom = open(self.port_to_eeprom_mapping[port_num], "rb") - 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: - # 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 - return False + if port_num <= 16: + lpmode_path = self.BASE_CPLD2_PATH + "module_lpmode_" + str(port_num) + else: + lpmode_path = self.BASE_CPLD3_PATH + "module_lpmode_" + str(port_num) + try: + val_file = open(lpmode_path) + content = val_file.readline().rstrip() + val_file.close() 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) + if content == "0": + return True + + return False + def set_low_power_mode(self, port_num, lpmode): # Check for invalid port_num if port_num > self.QSFP_PORT_END: #sfp not support lpmode: return False + if not self.get_presence(port_num): + return False # Port is not present, unable to set lpmode + + if port_num <= 16: + lpmode_path = self.BASE_CPLD2_PATH + "module_lpmode_" + str(port_num) + else: + lpmode_path = self.BASE_CPLD3_PATH + "module_lpmode_" + str(port_num) + + self.__port_to_mod_lpmode = lpmode_path + + if lpmode is True: + ret = self.__write_txt_file(self.__port_to_mod_lpmode, 0) #sysfs 1: enable lpmode + else: + ret = self.__write_txt_file(self.__port_to_mod_lpmode, 1) #sysfs 1: disable lpmode + + return ret - try: - eeprom = None - if not self.get_presence(port_num): - return False # Port is not present, unable to set the eeprom - - # Fill in write buffer - # 0x3:Low Power Mode. "Power override" bit is 1 and "Power set" bit is 1 - # 0x9:High Power Mode. "Power override" bit is 1 ,"Power set" bit is 0 and "High Power Class Enable" bit is 1 - regval = 0x3 if lpmode else 0x9 - - buffer = create_string_buffer(1) - buffer[0] = regval - - # Write to eeprom - eeprom = open(self.port_to_eeprom_mapping[port_num], "r+b") - 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) def reset(self, port_num): if port_num > self.QSFP_PORT_END: #sfp not support lpmode: diff --git a/device/accton/x86_64-accton_as9726_32d-r0/pmon_daemon_control.json b/device/accton/x86_64-accton_as9726_32d-r0/pmon_daemon_control.json index 584a14b9d94..a3b204e20d8 100644 --- a/device/accton/x86_64-accton_as9726_32d-r0/pmon_daemon_control.json +++ b/device/accton/x86_64-accton_as9726_32d-r0/pmon_daemon_control.json @@ -1,5 +1,5 @@ { "skip_ledd": true, - "skip_thermalctld": true + "skip_pcied": true } diff --git a/device/accton/x86_64-accton_as9726_32d-r0/sensors.conf b/device/accton/x86_64-accton_as9726_32d-r0/sensors.conf new file mode 100644 index 00000000000..4945c760606 --- /dev/null +++ b/device/accton/x86_64-accton_as9726_32d-r0/sensors.conf @@ -0,0 +1,56 @@ +# libsensors configuration file for as9726-32d +# ------------------------------------------------ +# + +bus "i2c-14" "i2c-1-mux (chan_id 5)" +bus "i2c-9" "i2c-1-mux (chan_id 0)" +bus "i2c-15" "i2c-1-mux (chan_id 6)" + + +chip "ym2401-i2c-*-58" + label in3 "PSU 1 Voltage" + label fan1 "PSU 1 Fan" + label temp1 "PSU 1 Temperature" + label power2 "PSU 1 Power" + label curr2 "PSU 1 Current" + +chip "ym2401-i2c-*-59" + label in3 "PSU 2 Voltage" + label fan1 "PSU 2 Fan" + label temp1 "PSU 2 Temperature" + label power2 "PSU 2 Power" + label curr2 "PSU 2 Current" + + +chip "as9726_32d_fan-*" + label fan1 "Fan 1 Front" + label fan2 "Fan 2 Front" + label fan3 "Fan 3 Front" + label fan4 "Fan 4 Front" + label fan5 "Fan 5 Front" + label fan6 "Fan 6 Front" + label fan11 "Fan 1 Rear" + label fan12 "Fan 2 Rear" + label fan13 "Fan 3 Rear" + label fan14 "Fan 4 Rear" + label fan15 "Fan 5 Rear" + label fan16 "Fan 6 Rear" + + +chip "lm75-i2c-*-48" + label temp1 "Main Board Temperature" + +chip "lm75-i2c-*-49" + label temp1 "Main Board Temperature" + +chip "lm75-i2c-*-4a" + label temp1 "Main Board Temperature" + +chip "lm75-i2c-*-4b" + label temp1 "CPU Board Temperature" + +chip "lm75-i2c-*-4c" + label temp1 "OCXO Temperature" + +chip "lm75-i2c-*-4f" + label temp1 "Main Board Temperature" diff --git a/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/__init__.py b/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/__init__.py index a18a2a2d2a3..cbd0cd4831e 100644 --- a/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/__init__.py +++ b/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/__init__.py @@ -1,2 +1,2 @@ -__all__ = ['chassis', 'eeprom', 'platform', 'psu', 'sfp', 'thermal', 'fan'] +__all__ = [ "platform", "chassis", "sfp", "eeprom", "component", "psu", "thermal", "fan", "fan_drawer" ] from . import platform diff --git a/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/chassis.py b/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/chassis.py index 7eb9601d8b5..4aefc39bce2 100644 --- a/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/chassis.py +++ b/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/chassis.py @@ -7,17 +7,19 @@ ############################################################################# import os +import sys try: from sonic_platform_base.chassis_base import ChassisBase from .helper import APIHelper + from .event import SfpEvent except ImportError as e: raise ImportError(str(e) + "- required module not found") NUM_FAN_TRAY = 6 NUM_FAN = 2 NUM_PSU = 2 -NUM_THERMAL = 3 +NUM_THERMAL = 6 NUM_QSFP = 32 PORT_START = 1 PORT_END = 34 @@ -62,11 +64,11 @@ def __initialize_sfp(self): self.sfp_module_initialized = True def __initialize_fan(self): - from sonic_platform.fan import Fan - for fant_index in range(0, NUM_FAN_TRAY): - for fan_index in range(0, NUM_FAN): - fan = Fan(fant_index, fan_index) - self._fan_list.append(fan) + from sonic_platform.fan_drawer import FanDrawer + for fant_index in range(NUM_FAN_TRAY): + fandrawer = FanDrawer(fant_index) + self._fan_drawer_list.append(fandrawer) + self._fan_list.extend(fandrawer._fan_list) def __initialize_psu(self): from sonic_platform.psu import Psu @@ -76,6 +78,7 @@ def __initialize_psu(self): def __initialize_thermals(self): from sonic_platform.thermal import Thermal + self._thermal_list.append(Thermal(is_cpu=True)) for index in range(0, NUM_THERMAL): thermal = Thermal(index) self._thermal_list.append(thermal) @@ -141,7 +144,15 @@ def get_base_mac(self): """ return self._eeprom.get_mac() - def get_serial_number(self): + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return self._eeprom.get_pn() + + def get_serial(self): """ Retrieves the hardware serial number for the chassis Returns: @@ -177,6 +188,15 @@ def get_reboot_cause(self): return ('REBOOT_CAUSE_NON_HARDWARE', sw_reboot_cause) + def get_change_event(self, timeout=0): + # SFP event + if not self.sfp_module_initialized: + self.__initialize_sfp() + + status, sfp_event = SfpEvent(self._sfp_list).get_sfp_event(timeout) + + return status, sfp_event + def get_sfp(self, index): """ Retrieves sfp represented by (1-based) index @@ -199,3 +219,29 @@ def get_sfp(self, index): sys.stderr.write("SFP index {} out of range (1-{})\n".format( index, len(self._sfp_list))) return sfp + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False + + def initizalize_system_led(self): + return True + + def get_status_led(self): + return "ControlledByFPGA" + + def set_status_led(self, color): + return True diff --git a/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/component.py b/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/component.py index c34da704432..e4118c41809 100644 --- a/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/component.py +++ b/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/component.py @@ -119,3 +119,55 @@ def install_firmware(self, image_path): A boolean, True if install successfully, False if not """ raise NotImplementedError + + def get_presence(self): + """ + Retrieves the presence of the device + Returns: + bool: True if device is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return 'N/A' + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return 'N/A' + + 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 True + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False diff --git a/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/eeprom.py b/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/eeprom.py index 7bf2bb58d19..87355d8e0f9 100644 --- a/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/eeprom.py +++ b/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/eeprom.py @@ -95,6 +95,9 @@ def _load_eeprom(self): def get_eeprom(self): return self._eeprom + def get_pn(self): + return self._eeprom.get('0x22', "Undefined.") + def get_serial(self): return self._eeprom.get('0x23', "Undefined.") diff --git a/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/event.py b/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/event.py new file mode 100644 index 00000000000..f20f8df51aa --- /dev/null +++ b/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/event.py @@ -0,0 +1,55 @@ +try: + import time + from .helper import APIHelper + from sonic_py_common.logger import Logger +except ImportError as e: + raise ImportError(repr(e) + " - required module not found") + + +class SfpEvent: + ''' Listen to insert/remove sfp events ''' + + def __init__(self, sfp_list): + self._api_helper = APIHelper() + self._sfp_list = sfp_list + self._logger = Logger() + + sfp_change_event_data = {'valid': 0, 'last': 0, 'present': 0} + def get_sfp_event(self, timeout=2000): + now = time.time() + port_dict = {} + change_dict = {} + change_dict['sfp'] = port_dict + + if timeout < 1000: + timeout = 1000 + timeout = timeout / float(1000) # Convert to secs + + if now < (self.sfp_change_event_data['last'] + timeout) and self.sfp_change_event_data['valid']: + return True, change_dict + + bitmap = 0 + for sfp in self._sfp_list: + modpres = sfp.get_presence() + i=sfp.port_num-1 + if modpres: + bitmap = bitmap | (1 << i) + + changed_ports = self.sfp_change_event_data['present'] ^ bitmap + if changed_ports: + for sfp in self._sfp_list: + i=sfp.port_num-1 + if (changed_ports & (1 << i)): + if (bitmap & (1 << i)) == 0: + port_dict[i+1] = '0' + else: + port_dict[i+1] = '1' + + + # Update the cache dict + self.sfp_change_event_data['present'] = bitmap + self.sfp_change_event_data['last'] = now + self.sfp_change_event_data['valid'] = 1 + return True, change_dict + else: + return True, change_dict diff --git a/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/fan.py b/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/fan.py index a42bdba3bd7..f0bae8fc8c8 100644 --- a/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/fan.py +++ b/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/fan.py @@ -13,10 +13,10 @@ raise ImportError(str(e) + "- required module not found") PSU_FAN_MAX_RPM = 26688 - -CPLD_I2C_PATH = "/sys/bus/i2c/devices/14-0066/fan_" -PSU_HWMON_I2C_PATH ="/sys/bus/i2c/devices/{}-00{}/" -PSU_I2C_MAPPING = { +SPEED_TOLERANCE = 15 +CPLD_FAN_I2C_PATH = "/sys/bus/i2c/devices/14-0066/fan" +I2C_PATH ="/sys/bus/i2c/devices/{}-00{}/" +PSU_HWMON_I2C_MAPPING = { 0: { "num": 9, "addr": "58" @@ -27,6 +27,20 @@ }, } +PSU_CPLD_I2C_MAPPING = { + 0: { + "num": 9, + "addr": "50" + }, + 1: { + "num": 9, + "addr": "51" + }, +} + +FAN_NAME_LIST = ["FAN-1F", "FAN-1R", "FAN-2F", "FAN-2R", + "FAN-3F", "FAN-3R", "FAN-4F", "FAN-4R", + "FAN-5F", "FAN-5R", "FAN-6F", "FAN-6R"] class Fan(FanBase): """Platform-specific Fan class""" @@ -39,9 +53,14 @@ def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0): if self.is_psu_fan: self.psu_index = psu_index - self.psu_i2c_num = PSU_I2C_MAPPING[self.psu_index]['num'] - self.psu_i2c_addr = PSU_I2C_MAPPING[self.psu_index]['addr'] - self.psu_hwmon_path = PSU_HWMON_I2C_PATH.format( + self.psu_i2c_num = PSU_HWMON_I2C_MAPPING[self.psu_index]['num'] + self.psu_i2c_addr = PSU_HWMON_I2C_MAPPING[self.psu_index]['addr'] + self.psu_hwmon_path = I2C_PATH.format( + self.psu_i2c_num, self.psu_i2c_addr) + + self.psu_i2c_num = PSU_CPLD_I2C_MAPPING[self.psu_index]['num'] + self.psu_i2c_addr = PSU_CPLD_I2C_MAPPING[self.psu_index]['addr'] + self.psu_cpld_path = I2C_PATH.format( self.psu_i2c_num, self.psu_i2c_addr) FanBase.__init__(self) @@ -57,10 +76,10 @@ def get_direction(self): if not self.is_psu_fan: - dir_str = "{}{}{}".format(CPLD_I2C_PATH, 'direction_', self.fan_tray_index) + dir_str = "{}{}{}".format(CPLD_FAN_I2C_PATH, self.fan_tray_index+1, '_direction') val=self._api_helper.read_txt_file(dir_str) if val is not None: - if val==0:#F2B + if int(val, 10)==0:#F2B direction=self.FAN_DIRECTION_EXHAUST else: direction=self.FAN_DIRECTION_INTAKE @@ -93,13 +112,13 @@ def get_speed(self): psu_fan_path= "{}{}".format(self.psu_hwmon_path, 'psu_fan1_speed_rpm') fan_speed_rpm = self._api_helper.read_txt_file(psu_fan_path) if fan_speed_rpm is not None: - speed = (int(fan_speed_rpm,10))*100/26688 + speed = (int(fan_speed_rpm,10))*100/PSU_FAN_MAX_RPM if speed > 100: speed=100 else: return 0 elif self.get_presence(): - speed_path = "{}{}".format(CPLD_I2C_PATH, 'duty_cycle_percentage') + speed_path = "{}{}".format(CPLD_FAN_I2C_PATH, '_duty_cycle_percentage') speed=self._api_helper.read_txt_file(speed_path) if speed is None: return 0 @@ -116,7 +135,7 @@ def get_target_speed(self): 0 : when PWM mode is use pwm : when pwm mode is not use """ - return False #Not supported + return self.get_speed() def get_speed_tolerance(self): """ @@ -125,7 +144,7 @@ def get_speed_tolerance(self): An integer, the percentage of variance from target speed which is considered tolerable """ - return False #Not supported + return SPEED_TOLERANCE def set_speed(self, speed): """ @@ -138,7 +157,7 @@ def set_speed(self, speed): """ if not self.is_psu_fan and self.get_presence(): - speed_path = "{}{}".format(CPLD_I2C_PATH, 'duty_cycle_percentage') + speed_path = "{}{}".format(CPLD_FAN_I2C_PATH, '_duty_cycle_percentage') return self._api_helper.write_txt_file(speed_path, int(speed)) return False @@ -154,18 +173,105 @@ def set_status_led(self, color): """ return False #Not supported + def get_status_led(self): + """ + Gets the state of the fan status LED + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + status=self.get_presence() + if status is None: + return self.STATUS_LED_COLOR_OFF + + return { + 1: self.STATUS_LED_COLOR_GREEN, + 0: self.STATUS_LED_COLOR_RED + }.get(status, self.STATUS_LED_COLOR_OFF) + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + fan_name = FAN_NAME_LIST[self.fan_tray_index*2 + self.fan_index] \ + if not self.is_psu_fan \ + else "PSU-{} FAN-{}".format(self.psu_index+1, self.fan_index+1) + + return fan_name + def get_presence(self): """ Retrieves the presence of the FAN Returns: bool: True if FAN is present, False if not """ - present_path = "{}{}{}".format(CPLD_I2C_PATH, 'present_', self.fan_index+1) - val=self._api_helper.read_txt_file(present_path) if not self.is_psu_fan: + present_path = "{}{}{}".format(CPLD_FAN_I2C_PATH, self.fan_tray_index+1, '_present') + val=self._api_helper.read_txt_file(present_path) if val is not None: return int(val, 10)==1 else: return False else: return True + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + if self.is_psu_fan: + psu_fan_path= "{}{}".format(self.psu_hwmon_path, 'psu_fan1_fault') + val=self._api_helper.read_txt_file(psu_fan_path) + if val is not None: + return int(val, 10)==0 + else: + return False + else: + path = "{}{}{}".format(CPLD_FAN_I2C_PATH, self.fan_tray_index+1, '_fault') + val=self._api_helper.read_txt_file(path) + if val is not None: + return int(val, 10)==0 + else: + return False + + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + + return "N/A" + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return "N/A" + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return (self.fan_tray_index+1) \ + if not self.is_psu_fan else (self.psu_index+1) + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True if not self.is_psu_fan else False diff --git a/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/fan_drawer.py b/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/fan_drawer.py new file mode 100644 index 00000000000..e21163c106c --- /dev/null +++ b/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/fan_drawer.py @@ -0,0 +1,90 @@ +######################################################################## +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Fan-Drawers' information available in the platform. +# +######################################################################## + +try: + from sonic_platform_base.fan_drawer_base import FanDrawerBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +FANS_PER_FANTRAY = 2 + + +class FanDrawer(FanDrawerBase): + """Platform-specific Fan class""" + + def __init__(self, fantray_index): + + FanDrawerBase.__init__(self) + # FanTray is 0-based in platforms + self.fantrayindex = fantray_index + self.__initialize_fan_drawer() + + + def __initialize_fan_drawer(self): + from sonic_platform.fan import Fan + for i in range(FANS_PER_FANTRAY): + self._fan_list.append(Fan(self.fantrayindex, i)) + + def get_name(self): + """ + Retrieves the fan drawer name + Returns: + string: The name of the device + """ + return "FanTray{}".format(self.fantrayindex+1) + + def get_presence(self): + """ + Retrieves the presence of the device + Returns: + bool: True if device is present, False if not + """ + return self._fan_list[0].get_presence() + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return self._fan_list[0].get_model() + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return self._fan_list[0].get_serial() + + 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._fan_list[0].get_status() + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return (self.fantrayindex+1) + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True diff --git a/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/helper.py b/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/helper.py index 4cd60ac9061..b124ca29f0d 100644 --- a/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/helper.py +++ b/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/helper.py @@ -51,7 +51,7 @@ def run_interactive_command(self, cmd): def read_txt_file(self, file_path): try: - with open(file_path, 'r') as fd: + with open(file_path, 'r', errors='replace') as fd: data = fd.read() return data.strip() except IOError: diff --git a/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/psu.py b/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/psu.py index 0ccd83faf57..3fc3a673236 100644 --- a/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/psu.py +++ b/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/psu.py @@ -8,7 +8,7 @@ try: from sonic_platform_base.psu_base import PsuBase - #from sonic_platform.fan import Fan + from sonic_platform.thermal import Thermal from .helper import APIHelper except ImportError as e: raise ImportError(str(e) + "- required module not found") @@ -56,13 +56,6 @@ def __init__(self, psu_index=0): self.i2c_addr = PSU_CPLD_I2C_MAPPING[self.index]["addr"] self.cpld_path = I2C_PATH.format(self.i2c_num, self.i2c_addr) self.__initialize_fan() - ''' - for fan_index in range(0, PSU_NUM_FAN[self.index]): - #def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0): - #fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index) - fan = Fan(fan_index, 0, True, self.index) - self._fan_list.append(fan) - ''' def __initialize_fan(self): from sonic_platform.fan import Fan @@ -70,6 +63,8 @@ def __initialize_fan(self): fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index) self._fan_list.append(fan) + self._thermal_list.append(Thermal(is_psu=True, psu_index=self.index)) + def get_voltage(self): """ Retrieves current PSU voltage output @@ -137,8 +132,16 @@ def get_status_led(self): Returns: A string, one of the predefined STATUS_LED_COLOR_* strings above """ + status_ps=self.get_presence() #present + status=self.get_status() #power good - return False #Controlled by HW + if status is None or status_ps is False: + return self.STATUS_LED_COLOR_OFF + + return { + 1: self.STATUS_LED_COLOR_GREEN, + 0: self.STATUS_LED_COLOR_AMBER + }.get(status, self.STATUS_LED_COLOR_OFF) def get_temperature(self): """ @@ -224,3 +227,46 @@ def get_status(self): return int(val, 10) == 1 else: return 0 + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + model_path="{}{}".format(self.cpld_path, 'psu_model_name') + model=self._api_helper.read_txt_file(model_path) + + if model is None: + return "N/A" + return model + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + serial_path="{}{}".format(self.cpld_path, 'psu_serial_number') + serial=self._api_helper.read_txt_file(serial_path) + + if serial is None: + return "N/A" + return serial + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device or -1 if cannot determine the position + """ + return self.index+1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True diff --git a/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/sfp.py b/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/sfp.py index 6cefc2a29a4..887c1d904a9 100644 --- a/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/sfp.py +++ b/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/sfp.py @@ -1502,37 +1502,20 @@ def get_lpmode(self): Returns: A Boolean, True if lpmode is enabled, False if disabled """ - if self._port_num > 32: + if self._port_num > 32: # SFP doesn't support this feature return False + + if self._port_num <= 16: + lpmode_path = "{}{}{}".format(CPLD2_I2C_PATH, '/module_lpmode_', self._port_num) else: - try: - eeprom = None - - if not self.get_presence(): - return False - # Write to eeprom - port_to_i2c_mapping = SFP_I2C_START + self._index - port_eeprom_path = I2C_EEPROM_PATH.format(port_to_i2c_mapping) - - eeprom = open(port_eeprom_path, "rb") - eeprom.seek(QSFP_POWEROVERRIDE_OFFSET) - 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: - # 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 - return False - 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) + lpmode_path = "{}{}{}".format(CPLD3_I2C_PATH, '/module_lpmode_', self._port_num) + + val=self._api_helper.read_txt_file(lpmode_path) + if val is not None: + return int(val, 10)==0 + else: + return False def get_power_set(self): @@ -2095,12 +2078,17 @@ def set_lpmode(self, lpmode): if not self.get_presence(): return False - if lpmode is True: - self.set_power_override(True, True) + if self._port_num <= self.CPLD2_PORT_END: + lpmode_path = "{}{}{}".format(CPLD2_I2C_PATH, 'module_lpmode_', self._port_num) else: - self.set_power_override(True, False) + lpmode_path = "{}{}{}".format(CPLD3_I2C_PATH, 'module_lpmode_', self._port_num) - return True + if lpmode is True: + ret = self.__write_txt_file(lpmode_path, 0) #enable lpmode + else: + ret = self.__write_txt_file(lpmode_path, 1) #disable lpmode + + return ret def set_power_override(self, power_override, power_set): """ @@ -2158,7 +2146,7 @@ def get_name(self): sfputil_helper = SfpUtilHelper() sfputil_helper.read_porttab_mappings( self.__get_path_to_port_config_file()) - name = sfputil_helper.logical[self.index] or "Unknown" + name = sfputil_helper.logical[self._index] or "Unknown" return name def get_presence(self): @@ -2207,10 +2195,12 @@ def get_status(self): def get_position_in_parent(self): """ + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned Returns: - Temp return 0 + integer: The 1-based relative physical position in parent device or -1 if cannot determine the position """ - return 0 + return self.port_num def is_replaceable(self): """ diff --git a/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/thermal.py b/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/thermal.py index 1a811719dea..a474399fa9e 100644 --- a/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/thermal.py +++ b/device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/thermal.py @@ -1,5 +1,5 @@ ############################################################################# -# Accton +# Edgecore # # Thermal contains an implementation of SONiC Platform Base API and # provides the thermal device status which are available in the platform @@ -9,43 +9,107 @@ import os import os.path import glob +from collections import namedtuple try: from sonic_platform_base.thermal_base import ThermalBase except ImportError as e: raise ImportError(str(e) + "- required module not found") +Threshold = namedtuple('Threshold', ['high_crit', 'high_err', 'high_warn', + 'low_warn', 'low_err', 'low_crit'], defaults=[0]*6) + +PSU_I2C_PATH = "/sys/bus/i2c/devices/{}-00{}/" + +PSU_HWMON_I2C_MAPPING = { + 0: { + "num": 9, + "addr": "58" + }, + 1: { + "num": 9, + "addr": "59" + }, +} + +PSU_CPLD_I2C_MAPPING = { + 0: { + "num": 9, + "addr": "50" + }, + 1: { + "num": 9, + "addr": "51" + }, +} + +THERMAL_NAME_LIST = ("Main Board 0x48", "Main Board 0x49", "Main Board 0x4A", + "CPU Board 0x4B", "OCXO 0x4C", "Main Board 0x4F") + +PSU_THERMAL_NAME_LIST = ("PSU-1 temp sensor 1", "PSU-2 temp sensor 1") +CPU_THERMAL_NAME = "CPU Core temp" + +SYSFS_PATH = "/sys/bus/i2c/devices" + +def is_fan_dir_F2B(): + from sonic_platform.platform import Platform + fan = Platform().get_chassis().get_fan(0) + return fan.get_direction().lower() == fan.FAN_DIRECTION_EXHAUST + class Thermal(ThermalBase): """Platform-specific Thermal class""" - THERMAL_NAME_LIST = [] - SYSFS_PATH = "/sys/bus/i2c/devices" + _thresholds_F2B = { + 0: Threshold(77.0, 72.0, 67.0), + 1: Threshold(75.0, 70.0, 65.0), + 2: Threshold(74.0, 69.0, 64.0), + 3: Threshold(77.0, 72.0, 67.0), + 4: Threshold(72.0, 67.0, 62.0), + 5: Threshold(74.0, 69.0, 64.0) + } + _thresholds_B2F = { + 0: Threshold(67.9, 62.9, 57.9), + 1: Threshold(61.9, 56.9, 51.9), + 2: Threshold(58.9, 53.9, 48.9), + 3: Threshold(51.8, 46.8, 41.8), + 4: Threshold(63.9, 58.9, 55.9), + 5: Threshold(58.5, 53.5, 48.5) + } + _thresholds = None - def __init__(self, thermal_index=0): - self.THERMAL_NAME_LIST = [] - self.SYSFS_PATH = "/sys/bus/i2c/devices" + def __init__(self, thermal_index=0, is_psu=False, psu_index=0, is_cpu=False): self.index = thermal_index - # Add thermal name - self.THERMAL_NAME_LIST.append("Temp sensor 1") - self.THERMAL_NAME_LIST.append("Temp sensor 2") - self.THERMAL_NAME_LIST.append("Temp sensor 3") - self.THERMAL_NAME_LIST.append("Temp sensor 4") - self.THERMAL_NAME_LIST.append("Temp sensor 5") - self.THERMAL_NAME_LIST.append("Temp sensor 6") + self.is_psu = is_psu + self.psu_index = psu_index + self.is_cpu = is_cpu + + if self.is_cpu: + self.cpu_paths = glob.glob('/sys/devices/platform/coretemp.0/hwmon/hwmon*/temp*_input') + self.cpu_path_idx = 0 + + if self.is_psu: + psu_i2c_bus = PSU_HWMON_I2C_MAPPING[psu_index]["num"] + psu_i2c_addr = PSU_HWMON_I2C_MAPPING[psu_index]["addr"] + self.psu_hwmon_path = PSU_I2C_PATH.format(psu_i2c_bus, + psu_i2c_addr) + psu_i2c_bus = PSU_CPLD_I2C_MAPPING[psu_index]["num"] + psu_i2c_addr = PSU_CPLD_I2C_MAPPING[psu_index]["addr"] + self.cpld_path = PSU_I2C_PATH.format(psu_i2c_bus, psu_i2c_addr) + # Set hwmon path i2c_path = { - 0: "15-0048/hwmon/hwmon*/", - 1: "15-0049/hwmon/hwmon*/", - 2: "15-004a/hwmon/hwmon*/", - 3: "15-004b/hwmon/hwmon*/", - 4: "15-004c/hwmon/hwmon*/", + 0: "15-0048/hwmon/hwmon*/", + 1: "15-0049/hwmon/hwmon*/", + 2: "15-004a/hwmon/hwmon*/", + 3: "15-004b/hwmon/hwmon*/", + 4: "15-004c/hwmon/hwmon*/", 5: "15-004f/hwmon/hwmon*/" }.get(self.index, None) - self.hwmon_path = "{}/{}".format(self.SYSFS_PATH, i2c_path) - self.ss_key = self.THERMAL_NAME_LIST[self.index] + self.hwmon_path = "{}/{}".format(SYSFS_PATH, i2c_path) + self.ss_key = THERMAL_NAME_LIST[self.index] self.ss_index = 1 def __read_txt_file(self, file_path): @@ -60,22 +124,52 @@ def __read_txt_file(self, file_path): return None def __get_temp(self, temp_file): - temp_file_path = os.path.join(self.hwmon_path, temp_file) + if not self.is_psu: + temp_file_path = os.path.join(self.hwmon_path, temp_file) + else: + temp_file_path = temp_file raw_temp = self.__read_txt_file(temp_file_path) if raw_temp is not None: return float(raw_temp)/1000 else: return 0 - def __set_threshold(self, file_name, temperature): - temp_file_path = os.path.join(self.hwmon_path, file_name) - for filename in glob.glob(temp_file_path): - try: - with open(filename, 'w') as fd: - fd.write(str(temperature)) - return True - except IOError as e: - print("IOError") + def __get_max_temp(self, paths): + max_temp = -1.0 + max_idx = 0 + for i, path in enumerate(paths): + read_temp = self.__get_temp(path) + if(read_temp > max_temp): + max_temp = read_temp + max_idx = i + return max_temp, max_idx + + def __get_cpu_threshold(self, type): + path = self.cpu_paths[self.cpu_path_idx] + high_warn = self.__get_temp(path.replace('_input', '_max')) + if type == 'high_warn': + return high_warn + high_crit = self.__get_temp(path.replace('_input', '_crit')) + if type == 'high_crit': + return high_crit + if type == 'high_err': + return (high_crit + high_warn) / 2 + return 0 # for all low_* thresholds + + def _try_get_threshold(self, type): + if self.is_psu is True: + return None + + if self._thresholds is None: + self._thresholds = self._thresholds_F2B if is_fan_dir_F2B() else self._thresholds_B2F + + if self.is_cpu: + return self.__get_cpu_threshold(type) + + if self.index in self._thresholds: + return getattr(self._thresholds[self.index], type) + else: + return None def get_temperature(self): @@ -85,41 +179,29 @@ def get_temperature(self): A float number of current temperature in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ - temp_file = "temp{}_input".format(self.ss_index) - return self.__get_temp(temp_file) + if self.is_cpu: + cpu_temp, self.cpu_path_idx = self.__get_max_temp(self.cpu_paths) + return cpu_temp - def get_high_threshold(self): - """ - Retrieves the high threshold temperature of thermal - Returns: - A float number, the high threshold temperature of thermal in Celsius - up to nearest thousandth of one degree Celsius, e.g. 30.125 - """ - temp_file = "temp{}_max".format(self.ss_index) + if not self.is_psu: + temp_file = "temp{}_input".format(self.ss_index) + else: + temp_file = self.psu_hwmon_path + "psu_temp1_input" return self.__get_temp(temp_file) - def set_high_threshold(self, temperature): - """ - Sets the high threshold temperature of thermal - Args : - temperature: A float number up to nearest thousandth of one degree Celsius, - e.g. 30.125 - Returns: - A boolean, True if threshold is set successfully, False if not - """ - temp_file = "temp{}_max".format(self.ss_index) - temperature = temperature *1000 - self.__set_threshold(temp_file, temperature) - - return True - def get_name(self): """ Retrieves the name of the thermal device Returns: string: The name of the thermal device """ - return self.THERMAL_NAME_LIST[self.index] + if self.is_cpu: + return CPU_THERMAL_NAME + + if self.is_psu: + return PSU_THERMAL_NAME_LIST[self.psu_index] + else: + return THERMAL_NAME_LIST[self.index] def get_presence(self): """ @@ -127,6 +209,12 @@ def get_presence(self): Returns: bool: True if Thermal is present, False if not """ + if self.is_cpu: + return True + + if self.is_psu: + val = self.__read_txt_file(self.cpld_path + "psu_present") + return int(val, 10) == 1 temp_file = "temp{}_input".format(self.ss_index) temp_file_path = os.path.join(self.hwmon_path, temp_file) raw_txt = self.__read_txt_file(temp_file_path) @@ -141,6 +229,13 @@ def get_status(self): Returns: A boolean value, True if device is operating properly, False if not """ + if self.is_cpu: + return True + + if self.is_psu: + temp_file = self.psu_hwmon_path + "psu_temp_fault" + return self.get_presence() and (not int( + self.__read_txt_file(temp_file))) file_str = "temp{}_input".format(self.ss_index) file_path = os.path.join(self.hwmon_path, file_str) @@ -149,3 +244,55 @@ def get_status(self): return False else: return int(raw_txt) != 0 + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + + return "N/A" + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return "N/A" + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Retrieves whether thermal module is replaceable + Returns: + A boolean value, True if replaceable, False if not + """ + return False + + def get_high_critical_threshold(self): + return self._try_get_threshold('high_crit') + + def get_low_critical_threshold(self): + return self._try_get_threshold('low_crit') + + def get_high_threshold(self): + return self._try_get_threshold('high_err') + + def get_low_threshold(self): + return self._try_get_threshold('low_err') + + def get_high_warning_threshold(self): + return self._try_get_threshold('high_warn') + + def get_low_warning_threshold(self): + return self._try_get_threshold('low_warn') diff --git a/device/accton/x86_64-accton_as9726_32d-r0/system_health_monitoring_config.json b/device/accton/x86_64-accton_as9726_32d-r0/system_health_monitoring_config.json new file mode 100644 index 00000000000..ee6fe350a44 --- /dev/null +++ b/device/accton/x86_64-accton_as9726_32d-r0/system_health_monitoring_config.json @@ -0,0 +1,14 @@ +{ + "services_to_ignore": [], + "devices_to_ignore": [ + "asic", + "psu.temperature" + ], + "user_defined_checkers": [], + "polling_interval": 60, + "led_color": { + "fault": "ControlledByFPGA", + "normal": "ControlledByFPGA", + "booting": "ControlledByFPGA" + } +} diff --git a/device/accton/x86_64-accton_minipack-r0/Accton-MINIPACK/port_config.ini b/device/accton/x86_64-accton_minipack-r0/Accton-MINIPACK/port_config.ini index cc8e7cbad5f..d339515a1b0 100755 --- a/device/accton/x86_64-accton_minipack-r0/Accton-MINIPACK/port_config.ini +++ b/device/accton/x86_64-accton_minipack-r0/Accton-MINIPACK/port_config.ini @@ -1,129 +1,129 @@ # name lanes alias index -Ethernet1 5,6 onehundredGigE1 0 -Ethernet2 7,8 onehundredGigE2 1 -Ethernet3 1,2 onehundredGigE3 2 -Ethernet4 3,4 onehundredGigE4 3 -Ethernet5 37,38 onehundredGigE5 4 -Ethernet6 39,40 onehundredGigE6 5 -Ethernet7 33,34 onehundredGigE7 6 -Ethernet8 35,36 onehundredGigE8 7 -Ethernet9 69,70 onehundredGigE9 8 -Ethernet10 71,72 onehundredGigE10 9 -Ethernet11 65,66 onehundredGigE11 10 -Ethernet12 67,68 onehundredGigE12 11 -Ethernet13 101,102 onehundredGigE13 12 -Ethernet14 103,104 onehundredGigE14 13 -Ethernet15 97,98 onehundredGigE15 14 -Ethernet16 99,100 onehundredGigE16 15 -Ethernet17 13,14 onehundredGigE17 16 -Ethernet18 15,16 onehundredGigE18 17 -Ethernet19 9,10 onehundredGigE19 18 -Ethernet20 11,12 onehundredGigE20 19 -Ethernet21 45,46 onehundredGigE21 20 -Ethernet22 47,48 onehundredGigE22 21 -Ethernet23 41,42 onehundredGigE23 22 -Ethernet24 43,44 onehundredGigE24 23 -Ethernet25 77,78 onehundredGigE25 24 -Ethernet26 79,80 onehundredGigE26 25 -Ethernet27 73,74 onehundredGigE27 26 -Ethernet28 75,76 onehundredGigE28 27 -Ethernet29 109,110 onehundredGigE29 28 -Ethernet30 111,112 onehundredGigE30 29 -Ethernet31 105,106 onehundredGigE31 30 -Ethernet32 107,108 onehundredGigE32 31 -Ethernet33 21,22 onehundredGigE33 32 -Ethernet34 23,24 onehundredGigE34 33 -Ethernet35 17,18 onehundredGigE35 34 -Ethernet36 19,20 onehundredGigE36 35 -Ethernet37 53,54 onehundredGigE37 36 -Ethernet38 55,56 onehundredGigE38 37 -Ethernet39 49,50 onehundredGigE39 38 -Ethernet40 51,52 onehundredGigE40 39 -Ethernet41 85,86 onehundredGigE41 40 -Ethernet42 87,88 onehundredGigE42 41 -Ethernet43 81,82 onehundredGigE43 42 -Ethernet44 83,84 onehundredGigE44 43 -Ethernet45 117,118 onehundredGigE45 44 -Ethernet46 119,120 onehundredGigE46 45 -Ethernet47 113,114 onehundredGigE47 46 -Ethernet48 115,116 onehundredGigE48 47 -Ethernet49 29,30 onehundredGigE49 48 -Ethernet50 31,32 onehundredGigE50 49 -Ethernet51 25,26 onehundredGigE51 50 -Ethernet52 27,28 onehundredGigE52 51 -Ethernet53 61,62 onehundredGigE53 52 -Ethernet54 63,64 onehundredGigE54 53 -Ethernet55 57,58 onehundredGigE55 54 -Ethernet56 59,60 onehundredGigE56 55 -Ethernet57 93,94 onehundredGigE57 56 -Ethernet58 95,96 onehundredGigE58 57 -Ethernet59 89,90 onehundredGigE59 58 -Ethernet60 91,92 onehundredGigE60 59 -Ethernet61 125,126 onehundredGigE61 60 -Ethernet62 127,128 onehundredGigE62 61 -Ethernet63 121,122 onehundredGigE63 62 -Ethernet64 123,124 onehundredGigE64 63 -Ethernet65 133,134 onehundredGigE65 64 -Ethernet66 135,136 onehundredGigE66 65 -Ethernet67 129,130 onehundredGigE67 66 -Ethernet68 131,132 onehundredGigE68 67 -Ethernet69 165,166 onehundredGigE69 68 -Ethernet70 167,168 onehundredGigE70 69 -Ethernet71 161,162 onehundredGigE71 70 -Ethernet72 163,164 onehundredGigE72 71 -Ethernet73 197,198 onehundredGigE73 72 -Ethernet74 199,200 onehundredGigE74 73 -Ethernet75 193,194 onehundredGigE75 74 -Ethernet76 195,196 onehundredGigE76 75 -Ethernet77 229,230 onehundredGigE77 76 -Ethernet78 231,232 onehundredGigE78 77 -Ethernet79 225,226 onehundredGigE79 78 -Ethernet80 227,228 onehundredGigE80 79 -Ethernet81 141,142 onehundredGigE81 80 -Ethernet82 143,144 onehundredGigE82 81 -Ethernet83 137,138 onehundredGigE83 82 -Ethernet84 139,140 onehundredGigE84 83 -Ethernet85 173,174 onehundredGigE85 84 -Ethernet86 175,176 onehundredGigE86 85 -Ethernet87 169,170 onehundredGigE87 86 -Ethernet88 171,172 onehundredGigE88 87 -Ethernet89 205,206 onehundredGigE89 88 -Ethernet90 207,208 onehundredGigE90 89 -Ethernet91 201,202 onehundredGigE91 90 -Ethernet92 203,204 onehundredGigE92 91 -Ethernet93 237,238 onehundredGigE93 92 -Ethernet94 239,240 onehundredGigE94 93 -Ethernet95 233,234 onehundredGigE95 94 -Ethernet96 235,236 onehundredGigE96 95 -Ethernet97 149,150 onehundredGigE97 96 -Ethernet98 151,152 onehundredGigE98 97 -Ethernet99 145,146 onehundredGigE99 98 -Ethernet100 147,148 onehundredGigE100 99 -Ethernet101 181,182 onehundredGigE101 100 -Ethernet102 183,184 onehundredGigE102 101 -Ethernet103 177,178 onehundredGigE103 102 -Ethernet104 179,180 onehundredGigE104 103 -Ethernet105 213,214 onehundredGigE105 104 -Ethernet106 215,216 onehundredGigE106 105 -Ethernet107 209,210 onehundredGigE107 106 -Ethernet108 211,212 onehundredGigE108 107 -Ethernet109 245,246 onehundredGigE109 108 -Ethernet110 247,248 onehundredGigE110 109 -Ethernet111 241,242 onehundredGigE111 110 -Ethernet112 243,244 onehundredGigE112 111 -Ethernet113 157,158 onehundredGigE113 112 -Ethernet114 159,160 onehundredGigE114 113 -Ethernet115 153,154 onehundredGigE115 114 -Ethernet116 155,156 onehundredGigE116 115 -Ethernet117 189,190 onehundredGigE117 116 -Ethernet118 191,192 onehundredGigE118 117 -Ethernet119 185,186 onehundredGigE119 118 -Ethernet120 187,188 onehundredGigE120 119 -Ethernet121 221,222 onehundredGigE121 120 -Ethernet122 223,224 onehundredGigE122 121 -Ethernet123 217,218 onehundredGigE123 122 -Ethernet124 219,220 onehundredGigE124 123 -Ethernet125 253,254 onehundredGigE125 124 -Ethernet126 255,256 onehundredGigE126 125 -Ethernet127 249,250 onehundredGigE127 126 -Ethernet128 251,252 onehundredGigE128 127 +Ethernet1 5,6 onehundredGigE1 1 +Ethernet2 7,8 onehundredGigE2 2 +Ethernet3 1,2 onehundredGigE3 3 +Ethernet4 3,4 onehundredGigE4 4 +Ethernet5 37,38 onehundredGigE5 5 +Ethernet6 39,40 onehundredGigE6 6 +Ethernet7 33,34 onehundredGigE7 7 +Ethernet8 35,36 onehundredGigE8 8 +Ethernet9 69,70 onehundredGigE9 9 +Ethernet10 71,72 onehundredGigE10 10 +Ethernet11 65,66 onehundredGigE11 11 +Ethernet12 67,68 onehundredGigE12 12 +Ethernet13 101,102 onehundredGigE13 13 +Ethernet14 103,104 onehundredGigE14 14 +Ethernet15 97,98 onehundredGigE15 15 +Ethernet16 99,100 onehundredGigE16 16 +Ethernet17 13,14 onehundredGigE17 17 +Ethernet18 15,16 onehundredGigE18 18 +Ethernet19 9,10 onehundredGigE19 19 +Ethernet20 11,12 onehundredGigE20 20 +Ethernet21 45,46 onehundredGigE21 21 +Ethernet22 47,48 onehundredGigE22 22 +Ethernet23 41,42 onehundredGigE23 23 +Ethernet24 43,44 onehundredGigE24 24 +Ethernet25 77,78 onehundredGigE25 25 +Ethernet26 79,80 onehundredGigE26 26 +Ethernet27 73,74 onehundredGigE27 27 +Ethernet28 75,76 onehundredGigE28 28 +Ethernet29 109,110 onehundredGigE29 29 +Ethernet30 111,112 onehundredGigE30 30 +Ethernet31 105,106 onehundredGigE31 31 +Ethernet32 107,108 onehundredGigE32 32 +Ethernet33 21,22 onehundredGigE33 33 +Ethernet34 23,24 onehundredGigE34 34 +Ethernet35 17,18 onehundredGigE35 35 +Ethernet36 19,20 onehundredGigE36 36 +Ethernet37 53,54 onehundredGigE37 37 +Ethernet38 55,56 onehundredGigE38 38 +Ethernet39 49,50 onehundredGigE39 39 +Ethernet40 51,52 onehundredGigE40 40 +Ethernet41 85,86 onehundredGigE41 41 +Ethernet42 87,88 onehundredGigE42 42 +Ethernet43 81,82 onehundredGigE43 43 +Ethernet44 83,84 onehundredGigE44 44 +Ethernet45 117,118 onehundredGigE45 45 +Ethernet46 119,120 onehundredGigE46 46 +Ethernet47 113,114 onehundredGigE47 47 +Ethernet48 115,116 onehundredGigE48 48 +Ethernet49 29,30 onehundredGigE49 49 +Ethernet50 31,32 onehundredGigE50 50 +Ethernet51 25,26 onehundredGigE51 51 +Ethernet52 27,28 onehundredGigE52 52 +Ethernet53 61,62 onehundredGigE53 53 +Ethernet54 63,64 onehundredGigE54 54 +Ethernet55 57,58 onehundredGigE55 55 +Ethernet56 59,60 onehundredGigE56 56 +Ethernet57 93,94 onehundredGigE57 57 +Ethernet58 95,96 onehundredGigE58 58 +Ethernet59 89,90 onehundredGigE59 59 +Ethernet60 91,92 onehundredGigE60 60 +Ethernet61 125,126 onehundredGigE61 61 +Ethernet62 127,128 onehundredGigE62 62 +Ethernet63 121,122 onehundredGigE63 63 +Ethernet64 123,124 onehundredGigE64 64 +Ethernet65 133,134 onehundredGigE65 65 +Ethernet66 135,136 onehundredGigE66 66 +Ethernet67 129,130 onehundredGigE67 67 +Ethernet68 131,132 onehundredGigE68 68 +Ethernet69 165,166 onehundredGigE69 69 +Ethernet70 167,168 onehundredGigE70 70 +Ethernet71 161,162 onehundredGigE71 71 +Ethernet72 163,164 onehundredGigE72 72 +Ethernet73 197,198 onehundredGigE73 73 +Ethernet74 199,200 onehundredGigE74 74 +Ethernet75 193,194 onehundredGigE75 75 +Ethernet76 195,196 onehundredGigE76 76 +Ethernet77 229,230 onehundredGigE77 77 +Ethernet78 231,232 onehundredGigE78 78 +Ethernet79 225,226 onehundredGigE79 79 +Ethernet80 227,228 onehundredGigE80 80 +Ethernet81 141,142 onehundredGigE81 81 +Ethernet82 143,144 onehundredGigE82 82 +Ethernet83 137,138 onehundredGigE83 83 +Ethernet84 139,140 onehundredGigE84 84 +Ethernet85 173,174 onehundredGigE85 85 +Ethernet86 175,176 onehundredGigE86 86 +Ethernet87 169,170 onehundredGigE87 87 +Ethernet88 171,172 onehundredGigE88 88 +Ethernet89 205,206 onehundredGigE89 89 +Ethernet90 207,208 onehundredGigE90 90 +Ethernet91 201,202 onehundredGigE91 91 +Ethernet92 203,204 onehundredGigE92 92 +Ethernet93 237,238 onehundredGigE93 93 +Ethernet94 239,240 onehundredGigE94 94 +Ethernet95 233,234 onehundredGigE95 95 +Ethernet96 235,236 onehundredGigE96 96 +Ethernet97 149,150 onehundredGigE97 97 +Ethernet98 151,152 onehundredGigE98 98 +Ethernet99 145,146 onehundredGigE99 99 +Ethernet100 147,148 onehundredGigE100 100 +Ethernet101 181,182 onehundredGigE101 101 +Ethernet102 183,184 onehundredGigE102 102 +Ethernet103 177,178 onehundredGigE103 103 +Ethernet104 179,180 onehundredGigE104 104 +Ethernet105 213,214 onehundredGigE105 105 +Ethernet106 215,216 onehundredGigE106 106 +Ethernet107 209,210 onehundredGigE107 107 +Ethernet108 211,212 onehundredGigE108 108 +Ethernet109 245,246 onehundredGigE109 109 +Ethernet110 247,248 onehundredGigE110 110 +Ethernet111 241,242 onehundredGigE111 111 +Ethernet112 243,244 onehundredGigE112 112 +Ethernet113 157,158 onehundredGigE113 113 +Ethernet114 159,160 onehundredGigE114 114 +Ethernet115 153,154 onehundredGigE115 115 +Ethernet116 155,156 onehundredGigE116 116 +Ethernet117 189,190 onehundredGigE117 117 +Ethernet118 191,192 onehundredGigE118 118 +Ethernet119 185,186 onehundredGigE119 119 +Ethernet120 187,188 onehundredGigE120 120 +Ethernet121 221,222 onehundredGigE121 121 +Ethernet122 223,224 onehundredGigE122 122 +Ethernet123 217,218 onehundredGigE123 123 +Ethernet124 219,220 onehundredGigE124 124 +Ethernet125 253,254 onehundredGigE125 125 +Ethernet126 255,256 onehundredGigE126 126 +Ethernet127 249,250 onehundredGigE127 127 +Ethernet128 251,252 onehundredGigE128 128 diff --git a/device/accton/x86_64-accton_minipack-r0/pmon_daemon_control.json b/device/accton/x86_64-accton_minipack-r0/pmon_daemon_control.json index 584a14b9d94..a3b204e20d8 100644 --- a/device/accton/x86_64-accton_minipack-r0/pmon_daemon_control.json +++ b/device/accton/x86_64-accton_minipack-r0/pmon_daemon_control.json @@ -1,5 +1,5 @@ { "skip_ledd": true, - "skip_thermalctld": true + "skip_pcied": true } diff --git a/device/accton/x86_64-accton_minipack-r0/sonic_platform/__init__.py b/device/accton/x86_64-accton_minipack-r0/sonic_platform/__init__.py new file mode 100644 index 00000000000..73a7720e897 --- /dev/null +++ b/device/accton/x86_64-accton_minipack-r0/sonic_platform/__init__.py @@ -0,0 +1,2 @@ +__all__ = [ "platform", "chassis", "sfp", "eeprom", "component", "psu", "thermal", "fan", "fan_drawer" ] +from . import platform diff --git a/device/accton/x86_64-accton_minipack-r0/sonic_platform/chassis.py b/device/accton/x86_64-accton_minipack-r0/sonic_platform/chassis.py new file mode 100644 index 00000000000..bf4c8051399 --- /dev/null +++ b/device/accton/x86_64-accton_minipack-r0/sonic_platform/chassis.py @@ -0,0 +1,241 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Chassis information which are available in the platform +# +############################################################################# + +import os +import sys + +try: + from sonic_platform_base.chassis_base import ChassisBase + from .helper import APIHelper + from .event import SfpEvent +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +NUM_FAN_TRAY = 8 +NUM_FAN = 2 +NUM_PSU = 4 +NUM_THERMAL = 8 +PORT_END = 128 +NUM_COMPONENT = 1 +HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/" +PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/" +REBOOT_CAUSE_FILE = "reboot-cause.txt" +PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt" +HOST_CHK_CMD = "which systemctl > /dev/null 2>&1" + +class Chassis(ChassisBase): + """Platform-specific Chassis class""" + + def __init__(self): + ChassisBase.__init__(self) + self._api_helper = APIHelper() + self.is_host = self._api_helper.is_host() + + self.config_data = {} + + self.__initialize_fan() + self.__initialize_psu() + self.__initialize_thermals() + self.__initialize_components() + self.__initialize_sfp() + self.__initialize_eeprom() + + def __initialize_sfp(self): + from sonic_platform.sfp import Sfp + from minipack.fpgautil import FpgaUtil + import fbfpgaio + pim = FpgaUtil() + pim.init_pim_fpga() + + for index in range(0, PORT_END): + sfp_module = Sfp(index, 'QSFP') + self._sfp_list.append(sfp_module) + + self._sfpevent = SfpEvent(self._sfp_list) + self.sfp_module_initialized = True + + def __initialize_fan(self): + from sonic_platform.fan_drawer import FanDrawer + for fant_index in range(NUM_FAN_TRAY): + fandrawer = FanDrawer(fant_index) + self._fan_drawer_list.append(fandrawer) + self._fan_list.extend(fandrawer._fan_list) + + def __initialize_psu(self): + from sonic_platform.psu import Psu + for index in range(0, NUM_PSU): + psu = Psu(index) + self._psu_list.append(psu) + + def __initialize_thermals(self): + from sonic_platform.thermal import Thermal + for index in range(0, NUM_THERMAL): + thermal = Thermal(index) + self._thermal_list.append(thermal) + + def __initialize_eeprom(self): + from sonic_platform.eeprom import Tlv + self._eeprom = Tlv() + + def __initialize_components(self): + from sonic_platform.component import Component + for index in range(0, NUM_COMPONENT): + component = Component(index) + self._component_list.append(component) + + def __initialize_watchdog(self): + from sonic_platform.watchdog import Watchdog + self._watchdog = Watchdog() + + + def __is_host(self): + return os.system(HOST_CHK_CMD) == 0 + + def __read_txt_file(self, file_path): + try: + with open(file_path, 'r') as fd: + data = fd.read() + return data.strip() + except IOError: + pass + return None + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return self._eeprom.get_product_name() + + def get_presence(self): + """ + Retrieves the presence of the Chassis + Returns: + bool: True if Chassis is present, False if not + """ + return True + + 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 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._eeprom.get_mac() + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return self._eeprom.get_pn() + + def get_serial(self): + """ + Retrieves the hardware serial number for the chassis + Returns: + A string containing the hardware serial number for this chassis. + """ + return self._eeprom.get_serial() + + 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._eeprom.get_eeprom() + + 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. + """ + + reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE) + sw_reboot_cause = self._api_helper.read_txt_file( + reboot_cause_path) or "Unknown" + + + return ('REBOOT_CAUSE_NON_HARDWARE', sw_reboot_cause) + + def get_change_event(self, timeout=0): + # SFP event + if not self.sfp_module_initialized: + self.__initialize_sfp() + return self._sfpevent.get_sfp_event(timeout) + + def get_sfp(self, index): + """ + Retrieves sfp represented by (1-based) index + Args: + index: An integer, the index (1-based) of the sfp to retrieve. + The index should be the sequence of a physical port in a chassis, + starting from 1. + For example, 1 for Ethernet0, 2 for Ethernet4 and so on. + Returns: + An object dervied from SfpBase representing the specified sfp + """ + sfp = None + if not self.sfp_module_initialized: + self.__initialize_sfp() + + try: + # The index will start from 1 + sfp = self._sfp_list[index-1] + except IndexError: + sys.stderr.write("SFP index {} out of range (1-{})\n".format( + index, len(self._sfp_list))) + return sfp + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False + + + def initizalize_system_led(self): + return True + + def get_status_led(self): + return "ControlledByBMC" + + def set_status_led(self, color): + return True + diff --git a/device/accton/x86_64-accton_minipack-r0/sonic_platform/component.py b/device/accton/x86_64-accton_minipack-r0/sonic_platform/component.py new file mode 100644 index 00000000000..59ebe7f31cb --- /dev/null +++ b/device/accton/x86_64-accton_minipack-r0/sonic_platform/component.py @@ -0,0 +1,156 @@ +############################################################################# +# Edgecore +# +# Component contains an implementation of SONiC Platform Base API and +# provides the components firmware management function +# +############################################################################# + +import shlex +import subprocess + + +try: + from sonic_platform_base.component_base import ComponentBase + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version" +COMPONENT_LIST= [ + ("BIOS", "Basic Input/Output System") + +] +COMPONENT_DES_LIST = ["Basic Input/Output System"] + + +class Component(ComponentBase): + """Platform-specific Component class""" + + DEVICE_TYPE = "component" + + def __init__(self, component_index=0): + self._api_helper=APIHelper() + ComponentBase.__init__(self) + self.index = component_index + self.name = self.get_name() + + + def __run_command(self, command): + # Run bash command and print output to stdout + try: + process = subprocess.Popen( + shlex.split(command), stdout=subprocess.PIPE) + while True: + output = process.stdout.readline() + if output == '' and process.poll() is not None: + break + rc = process.poll() + if rc != 0: + return False + except Exception: + return False + return True + + def __get_bios_version(self): + # Retrieves the BIOS firmware version + try: + with open(BIOS_VERSION_PATH, 'r') as fd: + bios_version = fd.read() + return bios_version.strip() + except Exception as e: + print('Get exception when read bios') + return None + + def get_name(self): + """ + Retrieves the name of the component + Returns: + A string containing the name of the component + """ + return COMPONENT_LIST[self.index][0] + + def get_description(self): + """ + Retrieves the description of the component + Returns: + A string containing the description of the component + """ + return COMPONENT_LIST[self.index][1] + + + def get_firmware_version(self): + """ + Retrieves the firmware version of module + Returns: + string: The firmware versions of the module + """ + fw_version = None + if self.name == "BIOS": + fw_version = self.__get_bios_version() + else: + fw_version = "None" + + return fw_version + + def install_firmware(self, image_path): + """ + Install firmware to module + Args: + image_path: A string, path to firmware image + Returns: + A boolean, True if install successfully, False if not + """ + raise NotImplementedError + + def get_presence(self): + """ + Retrieves the presence of the device + Returns: + bool: True if device is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return 'N/A' + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return 'N/A' + + 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 True + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False diff --git a/device/accton/x86_64-accton_minipack-r0/sonic_platform/eeprom.py b/device/accton/x86_64-accton_minipack-r0/sonic_platform/eeprom.py new file mode 100644 index 00000000000..180be75454d --- /dev/null +++ b/device/accton/x86_64-accton_minipack-r0/sonic_platform/eeprom.py @@ -0,0 +1,134 @@ +try: + import os + import sys + import re + if sys.version_info[0] >= 3: + from io import StringIO + else: + from cStringIO import StringIO + + from sonic_platform_base.sonic_eeprom import eeprom_tlvinfo +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +CACHE_ROOT = '/var/cache/sonic/decode-syseeprom' +CACHE_FILE = 'syseeprom_cache' +NULL = 'N/A' + +class Tlv(eeprom_tlvinfo.TlvInfoDecoder): + + EEPROM_DECODE_HEADLINES = 6 + + def __init__(self): + self._eeprom_path = "/sys/bus/i2c/devices/1-0057/eeprom" + super(Tlv, self).__init__(self._eeprom_path, 0x200, '', True) + self._eeprom = self._load_eeprom() + + def __parse_output(self, decode_output): + decode_output.replace('\0', '') + lines = decode_output.split('\n') + lines = lines[self.EEPROM_DECODE_HEADLINES:] + _eeprom_info_dict = dict() + + for line in lines: + try: + match = re.search( + '(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)([\S]+)', line) + if match is not None: + idx = match.group(1) + value = match.group(3).rstrip('\0') + + _eeprom_info_dict[idx] = value + except Exception: + pass + + return _eeprom_info_dict + + def _load_eeprom(self): + original_stdout = sys.stdout + sys.stdout = StringIO() + try: + self.read_eeprom_db() + except Exception: + decode_output = sys.stdout.getvalue() + sys.stdout = original_stdout + return self.__parse_output(decode_output) + + status = self.check_status() + if 'ok' not in status: + return False + + if not os.path.exists(CACHE_ROOT): + try: + os.makedirs(CACHE_ROOT) + except Exception: + pass + + # + # only the eeprom classes that inherit from eeprom_base + # support caching. Others will work normally + # + try: + self.set_cache_name(os.path.join(CACHE_ROOT, CACHE_FILE)) + except Exception: + pass + + e = self.read_eeprom() + if e is None: + return 0 + + try: + self.update_cache(e) + except Exception: + pass + + self.decode_eeprom(e) + decode_output = sys.stdout.getvalue() + sys.stdout = original_stdout + + (is_valid, valid_crc) = self.is_checksum_valid(e) + if not is_valid: + return False + + return self.__parse_output(decode_output) + + def _valid_tlv(self, eeprom_data): + tlvinfo_type_codes_list = [ + self._TLV_CODE_PRODUCT_NAME, + self._TLV_CODE_PART_NUMBER, + self._TLV_CODE_SERIAL_NUMBER, + self._TLV_CODE_MAC_BASE, + self._TLV_CODE_MANUF_DATE, + self._TLV_CODE_DEVICE_VERSION, + self._TLV_CODE_LABEL_REVISION, + self._TLV_CODE_PLATFORM_NAME, + self._TLV_CODE_ONIE_VERSION, + self._TLV_CODE_MAC_SIZE, + self._TLV_CODE_MANUF_NAME, + self._TLV_CODE_MANUF_COUNTRY, + self._TLV_CODE_VENDOR_NAME, + self._TLV_CODE_DIAG_VERSION, + self._TLV_CODE_SERVICE_TAG, + self._TLV_CODE_VENDOR_EXT, + self._TLV_CODE_CRC_32 + ] + + for code in tlvinfo_type_codes_list: + code_str = "0x{:X}".format(code) + eeprom_data[code_str] = eeprom_data.get(code_str, NULL) + return eeprom_data + + def get_eeprom(self): + return self._valid_tlv(self._eeprom) + + def get_pn(self): + return self._eeprom.get('0x22', NULL) + + def get_serial(self): + return self._eeprom.get('0x23', NULL) + + def get_mac(self): + return self._eeprom.get('0x24', NULL) + + def get_product_name(self): + return self._eeprom.get('0x21', NULL) diff --git a/device/accton/x86_64-accton_minipack-r0/sonic_platform/event.py b/device/accton/x86_64-accton_minipack-r0/sonic_platform/event.py new file mode 100644 index 00000000000..722b7c04a1c --- /dev/null +++ b/device/accton/x86_64-accton_minipack-r0/sonic_platform/event.py @@ -0,0 +1,78 @@ +try: + import time + from .helper import APIHelper + from sonic_py_common.logger import Logger + from minipack.fpgautil import FpgaUtil +except ImportError as e: + raise ImportError(repr(e) + " - required module not found") + +POLL_INTERVAL_IN_SEC = 1 + +class SfpEvent: + ''' Listen to insert/remove sfp events ''' + + def __init__(self, sfp_list): + self._api_helper = APIHelper() + self._sfp_list = sfp_list + self._logger = Logger() + self._sfp_change_event_data = {'present': 0} + + def get_presence_bitmap(self): + bitmap = 0 + for sfp in self._sfp_list: + modpres = sfp.get_presence() + i=sfp.port_num-1 + if modpres: + bitmap = bitmap | (1 << i) + return bitmap + + def get_sfp_event(self, timeout=2000): + pim = FpgaUtil() + start_time = time.time() + port_dict = {} + change_dict = {} + change_dict['sfp'] = port_dict + forever = False + + if timeout == 0: + forever = True + elif timeout > 0: + timeout = timeout / float(1000) # Convert to secs + else: + print("get_transceiver_change_event:Invalid timeout value", timeout) + return False, {} + + end_time = start_time + timeout + if start_time > end_time: + print('get_transceiver_change_event:' + 'time wrap / invalid timeout value', timeout) + + return False, {} # Time wrap or possibly incorrect timeout + + while timeout >= 0: + change_status = 0 + check_dict = pim.get_qsfp_interrupt() + present = 0 + for key, value in check_dict.items(): + if value == 1: + present = pim.get_qsfp_presence(key) + change_status = 1 + if present: + port_dict[key+1] = '1' + else: + port_dict[key+1] = '0' + + if change_status: + return True, change_dict + if forever: + time.sleep(1) + else: + timeout = end_time - time.time() + if timeout >= 1: + time.sleep(1) # We poll at 1 second granularity + else: + if timeout > 0: + time.sleep(timeout) + return True, change_dict + print("get_evt_change_event: Should not reach here.") + return False, {} \ No newline at end of file diff --git a/device/accton/x86_64-accton_minipack-r0/sonic_platform/fan.py b/device/accton/x86_64-accton_minipack-r0/sonic_platform/fan.py new file mode 100644 index 00000000000..407caf63589 --- /dev/null +++ b/device/accton/x86_64-accton_minipack-r0/sonic_platform/fan.py @@ -0,0 +1,235 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the fan status which are available in the platform +# +############################################################################# + +import logging + +try: + from sonic_platform_base.fan_base import FanBase + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +SPEED_TOLERANCE = 15 +DEVICE_PATH ="/sys/bus/platform/devices/minipack_psensor/" + + +FAN_NAME_LIST = ["FAN-1F", "FAN-1R", "FAN-2F", "FAN-2R", + "FAN-3F", "FAN-3R", "FAN-4F", "FAN-4R", + "FAN-5F", "FAN-5R", "FAN-6F", "FAN-6R", + "FAN-7F", "FAN-7R", "FAN-8F", "FAN-8R",] + +class Fan(FanBase): + """Platform-specific Fan class""" + + def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0): + self._api_helper=APIHelper() + self.fan_index = fan_index + self.fan_tray_index = fan_tray_index + self.psu_index=psu_index + self.is_psu_fan = is_psu_fan + self.hwmon_path = DEVICE_PATH + + FanBase.__init__(self) + + logging.basicConfig(level=logging.DEBUG) + + 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 not self.is_psu_fan: + direction=self.FAN_DIRECTION_INTAKE + else: + direction=self.FAN_DIRECTION_INTAKE + 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) + + """ + speed = 0 + if self.is_psu_fan: + psu_fan_path = "{}{}{}{}".format(self.hwmon_path, "psu", self.psu_index+1, '_fan_speed') + fan_speed_rpm = self._api_helper.read_txt_file(psu_fan_path) + if fan_speed_rpm is not None: + speed = (int(fan_speed_rpm,10))*100/26688 + if speed > 100: + speed=100 + else: + return 0 + elif self.get_presence(): # 50%==3000 + speed_path = "{}{}{}{}".format(self.hwmon_path, "fan", self.fan_tray_index+1, '_input') + speed_input=self._api_helper.read_txt_file(speed_path) + if speed_input is None: + return 0 + else: + speed=int(speed_input, 10)*100/6000 + if speed > 100: + speed=100 + + return int(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) + + Note: + speed_pc = pwm_target/255*100 + + 0 : when PWM mode is use + pwm : when pwm mode is not use + """ + return self.get_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 + """ + return SPEED_TOLERANCE + + 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 + + """ + return False + + def set_status_led(self, color): + """ + Sets the state of the fan module status LED + Args: + color: A string representing the color with which to set the + fan module status LED + Returns: + bool: True if status LED state is set successfully, False if not + """ + return False #Not supported + + def get_status_led(self): + """ + Gets the state of the fan status LED + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + status=self.get_presence() + if status is None: + return self.STATUS_LED_COLOR_OFF + + return { + 1: self.STATUS_LED_COLOR_GREEN, + 0: self.STATUS_LED_COLOR_RED + }.get(status, self.STATUS_LED_COLOR_OFF) + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + fan_name = FAN_NAME_LIST[self.fan_tray_index*2 + self.fan_index] \ + if not self.is_psu_fan \ + else "PSU-{} FAN-{}".format(self.psu_index+1, self.fan_index+1) + + return fan_name + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if FAN is present, False if not + """ + + if self.is_psu_fan: + present_path="{}{}{}{}".format(self.hwmon_path, 'psu', self.psu_index+1, '_fan_speed') + else: + present_path = "{}{}{}{}".format(self.hwmon_path, "fan", self.fan_tray_index+1, '_input') + val=self._api_helper.read_txt_file(present_path) + if val is not None and int(val, 10)!=0: + return True + else: + return False + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + if self.is_psu_fan: + psu_fan_path="{}{}{}{}".format(self.hwmon_path, "psu", self.psu_index+1, '_fan_speed') + + val=self._api_helper.read_txt_file(psu_fan_path) + if val is not None: + return int(val, 10)!=0 + else: + return False + else: + path="{}{}{}{}".format(self.hwmon_path, "fan", self.fan_tray_index+1, '_input') + val=self._api_helper.read_txt_file(path) + if val is not None: + return int(val, 10)!=0 + else: + return False + + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + + return "N/A" + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return "N/A" + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return (self.fan_index+1) \ + if not self.is_psu_fan else (self.psu_index+1) + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True if not self.is_psu_fan else False + diff --git a/device/accton/x86_64-accton_minipack-r0/sonic_platform/fan_drawer.py b/device/accton/x86_64-accton_minipack-r0/sonic_platform/fan_drawer.py new file mode 100644 index 00000000000..17d339ee55f --- /dev/null +++ b/device/accton/x86_64-accton_minipack-r0/sonic_platform/fan_drawer.py @@ -0,0 +1,90 @@ +######################################################################## +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Fan-Drawers' information available in the platform. +# +######################################################################## + +try: + from sonic_platform_base.fan_drawer_base import FanDrawerBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +FANS_PER_FANTRAY = 2 + + +class FanDrawer(FanDrawerBase): + """Platform-specific Fan class""" + + def __init__(self, fantray_index): + + FanDrawerBase.__init__(self) + # FanTray is 0-based in platforms + self.fantrayindex = fantray_index + self.__initialize_fan_drawer() + + + def __initialize_fan_drawer(self): + from sonic_platform.fan import Fan + for i in range(FANS_PER_FANTRAY): + self._fan_list.append(Fan(self.fantrayindex, i)) + + def get_name(self): + """ + Retrieves the fan drawer name + Returns: + string: The name of the device + """ + return "FanTray{}".format(self.fantrayindex+1) + + def get_presence(self): + """ + Retrieves the presence of the device + Returns: + bool: True if device is present, False if not + """ + return self._fan_list[0].get_presence() + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return self._fan_list[0].get_model() + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return self._fan_list[0].get_serial() + + 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._fan_list[0].get_status() + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return (self.fantrayindex+1) + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True diff --git a/device/accton/x86_64-accton_minipack-r0/sonic_platform/helper.py b/device/accton/x86_64-accton_minipack-r0/sonic_platform/helper.py new file mode 100644 index 00000000000..ce4499848f8 --- /dev/null +++ b/device/accton/x86_64-accton_minipack-r0/sonic_platform/helper.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python3 +import os +import struct +import subprocess +from mmap import * +from sonic_py_common import device_info + +HOST_CHK_CMD = "which systemctl > /dev/null 2>&1" +EMPTY_STRING = "" + +class APIHelper(): + + def __init__(self): + (self.platform, self.hwsku) = device_info.get_platform_and_hwsku() + + def is_host(self): + return os.system(HOST_CHK_CMD) == 0 + + def pci_get_value(self, resource, offset): + status = True + result = "" + try: + fd = os.open(resource, os.O_RDWR) + mm = mmap(fd, 0) + mm.seek(int(offset)) + read_data_stream = mm.read(4) + result = struct.unpack('I', read_data_stream) + except Exception: + status = False + return status, result + + def run_command(self, cmd): + status = True + result = "" + try: + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + except Exception: + status = False + return status, result + + def run_interactive_command(self, cmd): + try: + os.system(cmd) + except Exception: + return False + return True + + def read_txt_file(self, file_path): + try: + with open(file_path, 'r', errors='replace') as fd: + data = fd.read() + return data.strip() + except IOError: + pass + return None + + def write_txt_file(self, file_path, value): + try: + with open(file_path, 'w') as fd: + fd.write(str(value)) + except IOError: + return False + return True + + def ipmi_raw(self, netfn, cmd): + status = True + result = "" + try: + cmd = "ipmitool raw {} {}".format(str(netfn), str(cmd)) + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result + + def ipmi_fru_id(self, id, key=None): + status = True + result = "" + try: + cmd = "ipmitool fru print {}".format(str( + id)) if not key else "ipmitool fru print {0} | grep '{1}' ".format(str(id), str(key)) + + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result + + def ipmi_set_ss_thres(self, id, threshold_key, value): + status = True + result = "" + try: + cmd = "ipmitool sensor thresh '{}' {} {}".format(str(id), str(threshold_key), str(value)) + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result diff --git a/device/accton/x86_64-accton_minipack-r0/sonic_platform/platform.py b/device/accton/x86_64-accton_minipack-r0/sonic_platform/platform.py new file mode 100644 index 00000000000..2f2c2a447fc --- /dev/null +++ b/device/accton/x86_64-accton_minipack-r0/sonic_platform/platform.py @@ -0,0 +1,21 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the platform information +# +############################################################################# + +try: + from sonic_platform_base.platform_base import PlatformBase + from sonic_platform.chassis import Chassis +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Platform(PlatformBase): + """Platform-specific Platform class""" + + def __init__(self): + PlatformBase.__init__(self) + self._chassis = Chassis() diff --git a/device/accton/x86_64-accton_minipack-r0/sonic_platform/psu.py b/device/accton/x86_64-accton_minipack-r0/sonic_platform/psu.py new file mode 100644 index 00000000000..640735cdf46 --- /dev/null +++ b/device/accton/x86_64-accton_minipack-r0/sonic_platform/psu.py @@ -0,0 +1,234 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the PSUs status which are available in the platform +# +############################################################################# + +#import sonic_platform + +try: + from sonic_platform_base.psu_base import PsuBase + from sonic_platform.thermal import Thermal + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +DEVICE_PATH ="/sys/bus/platform/devices/minipack_psensor/" + +PSU_NAME_LIST = ["PSU-1", "PSU-2", "PSU-3", "PSU-4"] +PSU_NUM_FAN = [1, 1, 1, 1] + +class Psu(PsuBase): + """Platform-specific Psu class""" + + def __init__(self, psu_index=0): + PsuBase.__init__(self) + self.index = psu_index + self._api_helper = APIHelper() + self.hwmon_path = DEVICE_PATH + self.__initialize_fan() + + def __initialize_fan(self): + from sonic_platform.fan import Fan + for fan_index in range(0, PSU_NUM_FAN[self.index]): + fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index) + self._fan_list.append(fan) + + self._thermal_list.append(Thermal(is_psu=True, psu_index=self.index)) + + def get_voltage(self): + """ + Retrieves current PSU voltage output + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + vout_path = "{}{}{}{}".format(self.hwmon_path, 'in', (self.index+1)*2, '_input' ) + vout_val=self._api_helper.read_txt_file(vout_path) + if vout_val is not None: + return float(vout_val)/ 1000 + else: + return 0 + + def get_current(self): + """ + Retrieves present electric current supplied by PSU + Returns: + A float number, the electric current in amperes, e.g 15.4 + """ + iout_path = "{}{}{}{}".format(self.hwmon_path, 'curr', (self.index+1)*2, '_input' ) + val=self._api_helper.read_txt_file(iout_path) + if val is not None: + return float(val)/1000 + else: + return 0 + + def get_power(self): + """ + Retrieves current energy supplied by PSU + Returns: + A float number, the power in watts, e.g. 302.6 + """ + pout_path = "{}{}{}{}".format(self.hwmon_path, 'power', (self.index+1)*2, '_input' ) + val=self._api_helper.read_txt_file(pout_path) + if val is not None: + return float(val)/1000000 + else: + return 0 + + 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): + """ + Sets the state of the PSU status LED + Args: + color: A string representing the color with which to set the PSU status LED + Note: Only support green and off + Returns: + bool: True if status LED state is set successfully, False if not + """ + + return False #Controlled by HW + + def get_status_led(self): + """ + Gets the state of the PSU status LED + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + status=self.get_status() + if status is None: + return self.STATUS_LED_COLOR_OFF + + return { + 1: self.STATUS_LED_COLOR_GREEN, + 0: self.STATUS_LED_COLOR_RED + }.get(status, self.STATUS_LED_COLOR_OFF) + + def get_temperature(self): + """ + Retrieves current temperature reading from PSU + Returns: + A float number of current temperature in Celsius up to nearest thousandth + of one degree Celsius, e.g. 30.125 + """ + temp_path = "{}{}{}{}".format(self.hwmon_path, 'psu', self.index+1, '_temp_input') + val=self._api_helper.read_txt_file(temp_path) + if val is not None: + return float(val)/1000 + else: + return 0 + + def get_temperature_high_threshold(self): + """ + Retrieves the high threshold temperature of PSU + Returns: + A float number, the high threshold temperature of PSU in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + return False #Not supported + + def get_voltage_high_threshold(self): + """ + Retrieves the high threshold PSU voltage output + Returns: + A float number, the high threshold output voltage in volts, + e.g. 12.1 + """ + return 14.00 + + def get_voltage_low_threshold(self): + """ + Retrieves the low threshold PSU voltage output + Returns: + A float number, the low threshold output voltage in volts, + e.g. 12.1 + """ + return 10.00 + + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return PSU_NAME_LIST[self.index] + + def get_presence(self): + """ + Retrieves the presence of the PSU + Returns: + bool: True if PSU is present, False if not + """ + val=self.get_serial() + if val is not None: + return True + else: + return False + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + power_path="{}{}{}{}".format(self.hwmon_path, 'power', (self.index+1)*2, '_input' ) + val=self._api_helper.read_txt_file(power_path) + if val is not None and int(val)!=0: + return True + else: + return False + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + model_path="{}{}{}{}".format(self.hwmon_path, 'psu' , (self.index+1) ,'_model_name') + model=self._api_helper.read_txt_file(model_path) + + if model is None: + return "N/A" + return model + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + serial_path="{}{}{}{}".format(self.hwmon_path, 'psu' , self.index+1 ,'_serial_num') + serial=self._api_helper.read_txt_file(serial_path) + + if serial is None: + return "N/A" + return serial + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device or -1 if cannot determine the position + """ + return self.index+1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True diff --git a/device/accton/x86_64-accton_minipack-r0/sonic_platform/sfp.py b/device/accton/x86_64-accton_minipack-r0/sonic_platform/sfp.py new file mode 100644 index 00000000000..280c0059da0 --- /dev/null +++ b/device/accton/x86_64-accton_minipack-r0/sonic_platform/sfp.py @@ -0,0 +1,2209 @@ +############################################################################# +# Edgecore +# +# Sfp contains an implementation of SONiC Platform Base API and +# provides the sfp device status which are available in the platform +# +############################################################################# + +import os +import sys +import time +import struct + +from ctypes import create_string_buffer + +try: + from sonic_platform_base.sfp_base import SfpBase + from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId + from sonic_platform_base.sonic_sfp.sff8472 import sff8472Dom + from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId + from sonic_platform_base.sonic_sfp.sff8436 import sff8436Dom + from sonic_platform_base.sonic_sfp.inf8628 import inf8628InterfaceId + from sonic_platform_base.sonic_sfp.qsfp_dd import qsfp_dd_InterfaceId + from sonic_platform_base.sonic_sfp.qsfp_dd import qsfp_dd_Dom + from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper + from .helper import APIHelper + from minipack.fpgautil import FpgaUtil +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +#Edge-core definitions + +# 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_EXT_SPECIFICATION_COMPLIANCE_OFFSET = 64 +XCVR_EXT_SPECIFICATION_COMPLIANCE_WIDTH = 1 +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 = 2 + +XCVR_INTERFACE_DATA_START = 0 +XCVR_INTERFACE_DATA_SIZE = 92 + +QSFP_DOM_BULK_DATA_START = 22 +QSFP_DOM_BULK_DATA_SIZE = 36 +SFP_DOM_BULK_DATA_START = 96 +SFP_DOM_BULK_DATA_SIZE = 10 +QSFP_DD_DOM_BULK_DATA_START = 14 +QSFP_DD_DOM_BULK_DATA_SIZE = 4 + +# 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 for values in QSFP_DD info eeprom +QSFP_DD_TYPE_OFFSET = 0 +QSFP_DD_VENDOR_NAME_OFFSET = 1 +QSFP_DD_VENDOR_PN_OFFSET = 20 +QSFP_DD_VENDOR_SN_OFFSET = 38 +QSFP_DD_VENDOR_OUI_OFFSET = 17 + +# definitions of the offset and width for values in XCVR_QSFP_DD info eeprom +XCVR_EXT_TYPE_OFFSET_QSFP_DD = 72 +XCVR_EXT_TYPE_WIDTH_QSFP_DD = 2 +XCVR_CONNECTOR_OFFSET_QSFP_DD = 75 +XCVR_CONNECTOR_WIDTH_QSFP_DD = 1 +XCVR_CABLE_LENGTH_OFFSET_QSFP_DD = 74 +XCVR_CABLE_LENGTH_WIDTH_QSFP_DD = 1 +XCVR_HW_REV_OFFSET_QSFP_DD = 36 +XCVR_HW_REV_WIDTH_QSFP_DD = 2 +XCVR_VENDOR_DATE_OFFSET_QSFP_DD = 54 +XCVR_VENDOR_DATE_WIDTH_QSFP_DD = 8 +XCVR_DOM_CAPABILITY_OFFSET_QSFP_DD = 2 +XCVR_DOM_CAPABILITY_WIDTH_QSFP_DD = 1 +XCVR_MEDIA_TYPE_OFFSET_QSFP_DD = 85 +XCVR_MEDIA_TYPE_WIDTH_QSFP_DD = 1 +XCVR_FIRST_APPLICATION_LIST_OFFSET_QSFP_DD = 86 +XCVR_FIRST_APPLICATION_LIST_WIDTH_QSFP_DD = 32 +XCVR_SECOND_APPLICATION_LIST_OFFSET_QSFP_DD = 351 +XCVR_SECOND_APPLICATION_LIST_WIDTH_QSFP_DD = 28 + +# Offset for values in QSFP 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_VERSION_COMPLIANCE_OFFSET = 1 +QSFP_VERSION_COMPLIANCE_WIDTH = 2 +QSFP_CHANNL_MON_OFFSET = 34 +QSFP_CHANNL_MON_WIDTH = 16 +QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH = 24 +QSFP_CHANNL_DISABLE_STATUS_OFFSET = 86 +QSFP_CHANNL_DISABLE_STATUS_WIDTH = 1 +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_CONTROL_OFFSET = 86 +QSFP_CONTROL_WIDTH = 8 +QSFP_MODULE_MONITOR_OFFSET = 0 +QSFP_MODULE_MONITOR_WIDTH = 9 +QSFP_POWEROVERRIDE_OFFSET = 93 +QSFP_POWEROVERRIDE_WIDTH = 1 +QSFP_POWEROVERRIDE_BIT = 0 +QSFP_POWERSET_BIT = 1 +QSFP_OPTION_VALUE_OFFSET = 192 +QSFP_OPTION_VALUE_WIDTH = 4 +QSFP_MODULE_UPPER_PAGE3_START = 384 +QSFP_MODULE_THRESHOLD_OFFSET = 128 +QSFP_MODULE_THRESHOLD_WIDTH = 24 +QSFP_CHANNL_THRESHOLD_OFFSET = 176 +QSFP_CHANNL_THRESHOLD_WIDTH = 24 + +SFP_MODULE_ADDRA2_OFFSET = 256 +SFP_MODULE_THRESHOLD_OFFSET = 0 +SFP_MODULE_THRESHOLD_WIDTH = 56 +SFP_CHANNL_THRESHOLD_OFFSET = 112 +SFP_CHANNL_THRESHOLD_WIDTH = 2 + +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_CHANNL_STATUS_OFFSET = 110 +SFP_CHANNL_STATUS_WIDTH = 1 + +QSFP_DD_TEMPE_OFFSET = 14 +QSFP_DD_TEMPE_WIDTH = 2 +QSFP_DD_VOLT_OFFSET = 16 +QSFP_DD_VOLT_WIDTH = 2 +QSFP_DD_TX_BIAS_OFFSET = 42 +QSFP_DD_TX_BIAS_WIDTH = 16 +QSFP_DD_RX_POWER_OFFSET = 58 +QSFP_DD_RX_POWER_WIDTH = 16 +QSFP_DD_TX_POWER_OFFSET = 26 +QSFP_DD_TX_POWER_WIDTH = 16 +QSFP_DD_CHANNL_MON_OFFSET = 154 +QSFP_DD_CHANNL_MON_WIDTH = 48 +QSFP_DD_CHANNL_DISABLE_STATUS_OFFSET = 86 +QSFP_DD_CHANNL_DISABLE_STATUS_WIDTH = 1 +QSFP_DD_CHANNL_RX_LOS_STATUS_OFFSET = 19 +QSFP_DD_CHANNL_RX_LOS_STATUS_WIDTH = 1 +QSFP_DD_CHANNL_TX_FAULT_STATUS_OFFSET = 7 +QSFP_DD_CHANNL_TX_FAULT_STATUS_WIDTH = 1 +QSFP_DD_MODULE_THRESHOLD_OFFSET = 0 +QSFP_DD_MODULE_THRESHOLD_WIDTH = 72 +QSFP_DD_CHANNL_STATUS_OFFSET = 26 +QSFP_DD_CHANNL_STATUS_WIDTH = 1 + + +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' +) + +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', 'type_abbrv_name' +] + +qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)', + 'Length OM2(m)', 'Length OM1(m)', + 'Length Cable Assembly(m)') + +dom_info_dict_keys = [ + 'rx_los', 'tx_fault', 'reset_status', 'lp_mode', + 'tx_disable', 'tx_disable_channel', 'temperature', 'voltage', + 'rx1power', 'rx2power', 'rx3power', 'rx4power', + 'rx5power', 'rx6power', 'rx7power', 'rx8power', + 'tx1bias', 'tx2bias', 'tx3bias', 'tx4bias', + 'tx5bias', 'tx6bias', 'tx7bias', 'tx8bias', + 'tx1power', 'tx2power', 'tx3power', 'tx4power', + 'tx5power', 'tx6power', 'tx7power', 'tx8power'] + +threshold_dict_keys = [ + 'temphighalarm', 'temphighwarning', + 'templowalarm', 'templowwarning', + 'vcchighalarm', 'vcchighwarning', + 'vcclowalarm', 'vcclowwarning', + 'rxpowerhighalarm', 'rxpowerhighwarning', + 'rxpowerlowalarm', 'rxpowerlowwarning', + 'txpowerhighalarm', 'txpowerhighwarning', + 'txpowerlowalarm', 'txpowerlowwarning', + 'txbiashighalarm', 'txbiashighwarning', + 'txbiaslowalarm', 'txbiaslowwarning'] + +SFP_TYPE_CODE_LIST = [ + '03' # SFP/SFP+/SFP28 +] +QSFP_TYPE_CODE_LIST = [ + '0d', # QSFP+ or later + '11' # QSFP28 or later +] +QSFP_DD_TYPE_CODE_LIST = [ + '18' # QSFP-DD Double Density 8X Pluggable Transceiver +] + +SFP_TYPE = "SFP" +QSFP_TYPE = "QSFP" +OSFP_TYPE = "OSFP" +QSFP_DD_TYPE = "QSFP_DD" + +NULL_VAL = 'N/A' + +#from port0_eeprom to port127_eeprom +I2C_EEPROM_PATH = "/usr/local/bin/minipack_qsfp/port{0}_eeprom" + +class Sfp(SfpBase): + """Platform-specific Sfp class""" + # Path to sysfs + PLATFORM_ROOT_PATH = "/usr/share/sonic/device" + PMON_HWSKU_PATH = "/usr/share/sonic/hwsku" + HOST_CHK_CMD = "which systemctl > /dev/null 2>&1" + PLATFORM = "x86_64-accton_minipack-r0" + HWSKU = "Accton-MINIPACK" + + def __init__(self, sfp_index=0, sfp_name=None): + self._api_helper=APIHelper() + self._index = sfp_index + self.port_num = self._index + 1 + self._name = sfp_name + self._eeprom_path = self._get_eeprom_path() + #pim = FpgaUtil() + #pim.init_pim_fpga() + #self._dom_capability_detect() + + SfpBase.__init__(self) + + def __is_host(self): + return os.system(self.HOST_CHK_CMD) == 0 + + def __get_path_to_port_config_file(self): + platform_path = "/".join([self.PLATFORM_ROOT_PATH, self.PLATFORM]) + hwsku_path = "/".join([platform_path, self.HWSKU] + ) if self.__is_host() else self.PMON_HWSKU_PATH + return "/".join([hwsku_path, "port_config.ini"]) + + def _convert_string_to_num(self, value_str): + if "-inf" in value_str: + return 'N/A' + elif "Unknown" in value_str: + return 'N/A' + elif 'dBm' in value_str: + t_str = value_str.rstrip('dBm') + return float(t_str) + elif 'mA' in value_str: + t_str = value_str.rstrip('mA') + return float(t_str) + elif 'C' in value_str: + t_str = value_str.rstrip('C') + return float(t_str) + elif 'Volts' in value_str: + t_str = value_str.rstrip('Volts') + return float(t_str) + else: + return 'N/A' + + def _read_eeprom_specific_bytes(self, offset, num_bytes): + sysfs_sfp_i2c_client_eeprom_path = self._get_eeprom_path() + eeprom_raw = [] + try: + eeprom = open( + sysfs_sfp_i2c_client_eeprom_path, + mode="rb", buffering=0) + except IOError: + return None + + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + + try: + eeprom.seek(offset) + raw = eeprom.read(num_bytes) + except IOError: + eeprom.close() + return None + + try: + if isinstance(raw, str): + for n in range(0, num_bytes): + eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) + else: + for n in range(0, num_bytes): + eeprom_raw[n] = hex(raw[n])[2:].zfill(2) + + except BaseException: + eeprom.close() + return None + + eeprom.close() + return eeprom_raw + + def _detect_sfp_type(self): + sfp_type = QSFP_TYPE + eeprom_raw = [] + eeprom_raw = self._read_eeprom_specific_bytes( + XCVR_TYPE_OFFSET, XCVR_TYPE_WIDTH) + if eeprom_raw: + if eeprom_raw[0] in SFP_TYPE_CODE_LIST: + self.sfp_type = SFP_TYPE + elif eeprom_raw[0] in QSFP_TYPE_CODE_LIST: + self.sfp_type = QSFP_TYPE + elif eeprom_raw[0] in QSFP_DD_TYPE_CODE_LIST: + self.sfp_type = QSFP_DD_TYPE + else: + self.sfp_type = sfp_type + else: + self.sfp_type = sfp_type + + def _get_eeprom_path(self): + #print("Check _get_eeprom_path") + port_eeprom_path = I2C_EEPROM_PATH.format(self.port_num-1) + return port_eeprom_path + + def _dom_capability_detect(self): + self._detect_sfp_type() + + if not self.get_presence(): + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + return + + if self.sfp_type == QSFP_TYPE: + self.calibration = 1 + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + self.dom_supported = False + offset = 128 + + # QSFP capability byte parse, + # through this byte can know whether it support tx_power or not. + # TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436, + # need to add more code for determining the capability and version compliance + # in SFF-8636 dom capability definitions evolving with the versions. + + qsfp_dom_capability_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_DOM_CAPABILITY_OFFSET), + XCVR_DOM_CAPABILITY_WIDTH) + if qsfp_dom_capability_raw is not None: + qsfp_version_compliance_raw = self._read_eeprom_specific_bytes( + QSFP_VERSION_COMPLIANCE_OFFSET, + QSFP_VERSION_COMPLIANCE_WIDTH) + qsfp_version_compliance = int( + qsfp_version_compliance_raw[0], 16) + dom_capability = sfpi_obj.parse_dom_capability( + qsfp_dom_capability_raw, 0) + if qsfp_version_compliance >= 0x08: + self.dom_temp_supported = dom_capability['data']['Temp_support']['value'] == 'On' + self.dom_volt_supported = dom_capability['data']['Voltage_support']['value'] == 'On' + self.dom_rx_power_supported = dom_capability['data']['Rx_power_support']['value'] == 'On' + self.dom_tx_power_supported = dom_capability['data']['Tx_power_support']['value'] == 'On' + else: + self.dom_temp_supported = True + self.dom_volt_supported = True + self.dom_rx_power_supported = dom_capability['data']['Rx_power_support']['value'] == 'On' + self.dom_tx_power_supported = True + + self.dom_supported = True + self.calibration = 1 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + qsfp_option_value_raw = self._read_eeprom_specific_bytes( + QSFP_OPTION_VALUE_OFFSET, QSFP_OPTION_VALUE_WIDTH) + if qsfp_option_value_raw is not None: + optional_capability = sfpd_obj.parse_option_params( + qsfp_option_value_raw, 0) + self.dom_tx_disable_supported = optional_capability[ + 'data']['TxDisable']['value'] == 'On' + dom_status_indicator = sfpd_obj.parse_dom_status_indicator( + qsfp_version_compliance_raw, 1) + self.qsfp_page3_available = dom_status_indicator['data']['FlatMem']['value'] == 'Off' + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + self.qsfp_page3_available = False + + elif self.sfp_type == QSFP_DD_TYPE: + sfpi_obj = qsfp_dd_InterfaceId() + if sfpi_obj is None: + self.dom_supported = False + + offset = 0 + # two types of QSFP-DD cable types supported: Copper and Optical. + qsfp_dom_capability_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_DOM_CAPABILITY_OFFSET_QSFP_DD), XCVR_DOM_CAPABILITY_WIDTH_QSFP_DD) + if qsfp_dom_capability_raw is not None: + self.dom_temp_supported = True + self.dom_volt_supported = True + dom_capability = sfpi_obj.parse_dom_capability( + qsfp_dom_capability_raw, 0) + if dom_capability['data']['Flat_MEM']['value'] == 'Off': + self.dom_supported = True + self.second_application_list = True + self.dom_rx_power_supported = True + self.dom_tx_power_supported = True + self.dom_tx_bias_power_supported = True + self.dom_thresholds_supported = True + # currently set to False becasue Page 11h is not supported by FW + self.dom_rx_tx_power_bias_supported = False + else: + self.dom_supported = False + self.second_application_list = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.dom_tx_bias_power_supported = False + self.dom_thresholds_supported = False + self.dom_rx_tx_power_bias_supported = False + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.dom_tx_bias_power_supported = False + self.dom_thresholds_supported = False + self.dom_rx_tx_power_bias_supported = False + + elif self.sfp_type == SFP_TYPE: + sfpi_obj = sff8472InterfaceId() + if sfpi_obj is None: + return None + sfp_dom_capability_raw = self._read_eeprom_specific_bytes( + XCVR_DOM_CAPABILITY_OFFSET, XCVR_DOM_CAPABILITY_WIDTH) + if sfp_dom_capability_raw is not None: + sfp_dom_capability = int(sfp_dom_capability_raw[0], 16) + self.dom_supported = (sfp_dom_capability & 0x40 != 0) + if self.dom_supported: + self.dom_temp_supported = True + self.dom_volt_supported = True + self.dom_rx_power_supported = True + self.dom_tx_power_supported = True + if sfp_dom_capability & 0x20 != 0: + self.calibration = 1 + elif sfp_dom_capability & 0x10 != 0: + self.calibration = 2 + else: + self.calibration = 0 + else: + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + self.dom_tx_disable_supported = ( + int(sfp_dom_capability_raw[1], 16) & 0x40 != 0) + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + + 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 + ================================================================================ + """ + + transceiver_info_dict = {} + compliance_code_dict = {} + transceiver_info_dict = dict.fromkeys( + info_dict_keys, NULL_VAL) + transceiver_info_dict["specification_compliance"] = '{}' + + # If some port is not inserted module when xcvrd do _init_(), it will not get port_type from eeprom. + # So its defaut type is QSFP. But user can insert QSFP-DD to the port later + # So we need to check port before access port eeporm. + self._dom_capability_detect() + + # ToDo: OSFP tranceiver info parsing not fully supported. + # in inf8628.py lack of some memory map definition + # will be implemented when the inf8628 memory map ready + if self.sfp_type == OSFP_TYPE: + offset = 0 + vendor_rev_width = XCVR_HW_REV_WIDTH_OSFP + + sfpi_obj = inf8628InterfaceId() + if sfpi_obj is None: + return transceiver_info_dict + + sfp_type_raw = self._read_eeprom_specific_bytes( + (offset + OSFP_TYPE_OFFSET), XCVR_TYPE_WIDTH) + if sfp_type_raw is not None: + sfp_type_data = sfpi_obj.parse_sfp_type(sfp_type_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_name_raw = self._read_eeprom_specific_bytes( + (offset + OSFP_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH) + if sfp_vendor_name_raw is not None: + sfp_vendor_name_data = sfpi_obj.parse_vendor_name( + sfp_vendor_name_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_pn_raw = self._read_eeprom_specific_bytes( + (offset + OSFP_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH) + if sfp_vendor_pn_raw is not None: + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn( + sfp_vendor_pn_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_rev_raw = self._read_eeprom_specific_bytes( + (offset + OSFP_HW_REV_OFFSET), vendor_rev_width) + if sfp_vendor_rev_raw is not None: + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev( + sfp_vendor_rev_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_sn_raw = self._read_eeprom_specific_bytes( + (offset + OSFP_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH) + if sfp_vendor_sn_raw is not None: + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn( + sfp_vendor_sn_raw, 0) + else: + return transceiver_info_dict + + transceiver_info_dict['type'] = sfp_type_data['data']['type']['value'] + transceiver_info_dict['manufacturer'] = sfp_vendor_name_data['data']['Vendor Name']['value'] + transceiver_info_dict['model'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] + transceiver_info_dict['hardware_rev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] + transceiver_info_dict['serial'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] + + elif self.sfp_type == QSFP_TYPE: + offset = 128 + vendor_rev_width = XCVR_HW_REV_WIDTH_QSFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_QSFP + + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + + elif self.sfp_type == QSFP_DD_TYPE: + offset = 128 + + sfpi_obj = qsfp_dd_InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + + sfp_type_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_TYPE_OFFSET), XCVR_TYPE_WIDTH) + if sfp_type_raw is not None: + sfp_type_data = sfpi_obj.parse_sfp_type(sfp_type_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_name_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH) + if sfp_vendor_name_raw is not None: + sfp_vendor_name_data = sfpi_obj.parse_vendor_name( + sfp_vendor_name_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_pn_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH) + if sfp_vendor_pn_raw is not None: + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn( + sfp_vendor_pn_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_rev_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_HW_REV_OFFSET_QSFP_DD), XCVR_HW_REV_WIDTH_QSFP_DD) + if sfp_vendor_rev_raw is not None: + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev( + sfp_vendor_rev_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_sn_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH) + if sfp_vendor_sn_raw is not None: + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn( + sfp_vendor_sn_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_oui_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_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) + else: + return transceiver_info_dict + + sfp_vendor_date_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_VENDOR_DATE_OFFSET_QSFP_DD), XCVR_VENDOR_DATE_WIDTH_QSFP_DD) + if sfp_vendor_date_raw is not None: + sfp_vendor_date_data = sfpi_obj.parse_vendor_date( + sfp_vendor_date_raw, 0) + else: + return transceiver_info_dict + + sfp_connector_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_CONNECTOR_OFFSET_QSFP_DD), XCVR_CONNECTOR_WIDTH_QSFP_DD) + if sfp_connector_raw is not None: + sfp_connector_data = sfpi_obj.parse_connector( + sfp_connector_raw, 0) + else: + return transceiver_info_dict + + sfp_ext_identifier_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_EXT_TYPE_OFFSET_QSFP_DD), XCVR_EXT_TYPE_WIDTH_QSFP_DD) + if sfp_ext_identifier_raw is not None: + sfp_ext_identifier_data = sfpi_obj.parse_ext_iden( + sfp_ext_identifier_raw, 0) + else: + return transceiver_info_dict + + sfp_cable_len_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_CABLE_LENGTH_OFFSET_QSFP_DD), XCVR_CABLE_LENGTH_WIDTH_QSFP_DD) + if sfp_cable_len_raw is not None: + sfp_cable_len_data = sfpi_obj.parse_cable_len( + sfp_cable_len_raw, 0) + else: + return transceiver_info_dict + + sfp_media_type_raw = self._read_eeprom_specific_bytes( + XCVR_MEDIA_TYPE_OFFSET_QSFP_DD, XCVR_MEDIA_TYPE_WIDTH_QSFP_DD) + if sfp_media_type_raw is not None: + sfp_media_type_dict = sfpi_obj.parse_media_type( + sfp_media_type_raw, 0) + if sfp_media_type_dict is None: + return transceiver_info_dict + + host_media_list = "" + sfp_application_type_first_list = self._read_eeprom_specific_bytes( + (XCVR_FIRST_APPLICATION_LIST_OFFSET_QSFP_DD), XCVR_FIRST_APPLICATION_LIST_WIDTH_QSFP_DD) + if self.second_application_list: + possible_application_count = 15 + sfp_application_type_second_list = self._read_eeprom_specific_bytes( + (XCVR_SECOND_APPLICATION_LIST_OFFSET_QSFP_DD), XCVR_SECOND_APPLICATION_LIST_WIDTH_QSFP_DD) + if sfp_application_type_first_list is not None and sfp_application_type_second_list is not None: + sfp_application_type_list = sfp_application_type_first_list + \ + sfp_application_type_second_list + else: + return transceiver_info_dict + else: + possible_application_count = 8 + if sfp_application_type_first_list is not None: + sfp_application_type_list = sfp_application_type_first_list + else: + return transceiver_info_dict + + for i in range(0, possible_application_count): + if sfp_application_type_list[i * 4] == 'ff': + break + host_electrical, media_interface = sfpi_obj.parse_application( + sfp_media_type_dict, sfp_application_type_list[i * 4], sfp_application_type_list[i * 4 + 1]) + host_media_list = host_media_list + host_electrical + \ + ' - ' + media_interface + '\n\t\t\t\t ' + else: + return transceiver_info_dict + + transceiver_info_dict['type'] = str( + sfp_type_data['data']['type']['value']) + transceiver_info_dict['manufacturer'] = str( + sfp_vendor_name_data['data']['Vendor Name']['value']) + transceiver_info_dict['model'] = str( + sfp_vendor_pn_data['data']['Vendor PN']['value']) + transceiver_info_dict['hardware_rev'] = str( + sfp_vendor_rev_data['data']['Vendor Rev']['value']) + transceiver_info_dict['serial'] = str( + sfp_vendor_sn_data['data']['Vendor SN']['value']) + transceiver_info_dict['vendor_oui'] = str( + sfp_vendor_oui_data['data']['Vendor OUI']['value']) + transceiver_info_dict['vendor_date'] = str( + sfp_vendor_date_data['data']['VendorDataCode(YYYY-MM-DD Lot)']['value']) + transceiver_info_dict['connector'] = str( + sfp_connector_data['data']['Connector']['value']) + transceiver_info_dict['encoding'] = "Not supported for CMIS cables" + transceiver_info_dict['ext_identifier'] = str( + sfp_ext_identifier_data['data']['Extended Identifier']['value']) + transceiver_info_dict['ext_rateselect_compliance'] = "Not supported for CMIS cables" + transceiver_info_dict['specification_compliance'] = "Not supported for CMIS cables" + transceiver_info_dict['cable_type'] = "Length Cable Assembly(m)" + transceiver_info_dict['cable_length'] = str( + sfp_cable_len_data['data']['Length Cable Assembly(m)']['value']) + transceiver_info_dict['nominal_bit_rate'] = "Not supported for CMIS cables" + transceiver_info_dict['application_advertisement'] = host_media_list + + else: + offset = 0 + vendor_rev_width = XCVR_HW_REV_WIDTH_SFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_SFP + + sfpi_obj = sff8472InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + + if self.sfp_type != QSFP_DD_TYPE: + sfp_interface_bulk_raw = self._read_eeprom_specific_bytes( + offset + XCVR_INTERFACE_DATA_START, XCVR_INTERFACE_DATA_SIZE) + if sfp_interface_bulk_raw is None: + return transceiver_info_dict + + start = XCVR_INTFACE_BULK_OFFSET - XCVR_INTERFACE_DATA_START + end = start + interface_info_bulk_width + sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk( + sfp_interface_bulk_raw[start: end], 0) + + start = XCVR_VENDOR_NAME_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_NAME_WIDTH + sfp_vendor_name_data = sfpi_obj.parse_vendor_name( + sfp_interface_bulk_raw[start: end], 0) + + start = XCVR_VENDOR_PN_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_PN_WIDTH + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn( + sfp_interface_bulk_raw[start: end], 0) + + start = XCVR_HW_REV_OFFSET - XCVR_INTERFACE_DATA_START + end = start + vendor_rev_width + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev( + sfp_interface_bulk_raw[start: end], 0) + + start = XCVR_VENDOR_SN_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_SN_WIDTH + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn( + sfp_interface_bulk_raw[start: end], 0) + + start = XCVR_VENDOR_OUI_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_OUI_WIDTH + sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui( + sfp_interface_bulk_raw[start: end], 0) + + start = XCVR_VENDOR_DATE_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_DATE_WIDTH + sfp_vendor_date_data = sfpi_obj.parse_vendor_date( + sfp_interface_bulk_raw[start: end], 0) + + transceiver_info_dict['type'] = sfp_interface_bulk_data['data']['type']['value'] + transceiver_info_dict['manufacturer'] = sfp_vendor_name_data['data']['Vendor Name']['value'] + transceiver_info_dict['model'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] + transceiver_info_dict['hardware_rev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] + transceiver_info_dict['serial'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] + transceiver_info_dict['vendor_oui'] = sfp_vendor_oui_data['data']['Vendor OUI']['value'] + transceiver_info_dict['vendor_date'] = sfp_vendor_date_data[ + 'data']['VendorDataCode(YYYY-MM-DD Lot)']['value'] + transceiver_info_dict['connector'] = sfp_interface_bulk_data['data']['Connector']['value'] + transceiver_info_dict['encoding'] = sfp_interface_bulk_data['data']['EncodingCodes']['value'] + transceiver_info_dict['ext_identifier'] = sfp_interface_bulk_data['data']['Extended Identifier']['value'] + transceiver_info_dict['ext_rateselect_compliance'] = sfp_interface_bulk_data['data']['RateIdentifier']['value'] + transceiver_info_dict['type_abbrv_name'] = sfp_interface_bulk_data['data']['type_abbrv_name']['value'] + + if self.sfp_type == QSFP_TYPE: + for key in qsfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_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'] + sfp_ext_specification_compliance_raw = self._read_eeprom_specific_bytes( + offset + XCVR_EXT_SPECIFICATION_COMPLIANCE_OFFSET, XCVR_EXT_SPECIFICATION_COMPLIANCE_WIDTH) + if sfp_ext_specification_compliance_raw is not None: + sfp_ext_specification_compliance_data = sfpi_obj.parse_ext_specification_compliance( + sfp_ext_specification_compliance_raw[0: 1], 0) + if sfp_ext_specification_compliance_data['data']['Extended Specification compliance']['value'] != "Unspecified": + compliance_code_dict['Extended Specification compliance'] = sfp_ext_specification_compliance_data[ + 'data']['Extended Specification compliance']['value'] + transceiver_info_dict['specification_compliance'] = str( + compliance_code_dict) + transceiver_info_dict['nominal_bit_rate'] = str( + sfp_interface_bulk_data['data']['Nominal Bit Rate(100Mbs)']['value']) + else: + for key in sfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_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'] + transceiver_info_dict['specification_compliance'] = str( + compliance_code_dict) + + transceiver_info_dict['nominal_bit_rate'] = str( + sfp_interface_bulk_data['data']['NominalSignallingRate(UnitsOf100Mbd)']['value']) + + return transceiver_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. + ======================================================================== + """ + transceiver_dom_info_dict = dict.fromkeys( + dom_info_dict_keys, NULL_VAL) + + if self.sfp_type == OSFP_TYPE: + pass + + elif self.sfp_type == QSFP_TYPE: + if not self.dom_supported: + return transceiver_dom_info_dict + + offset = 0 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return transceiver_dom_info_dict + + dom_data_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DOM_BULK_DATA_START), QSFP_DOM_BULK_DATA_SIZE) + if dom_data_raw is None: + return transceiver_dom_info_dict + + if self.dom_temp_supported: + start = QSFP_TEMPE_OFFSET - QSFP_DOM_BULK_DATA_START + end = start + QSFP_TEMPE_WIDTH + dom_temperature_data = sfpd_obj.parse_temperature( + dom_data_raw[start: end], 0) + temp = dom_temperature_data['data']['Temperature']['value'] + if temp is not None: + transceiver_dom_info_dict['temperature'] = temp + + if self.dom_volt_supported: + start = QSFP_VOLT_OFFSET - QSFP_DOM_BULK_DATA_START + end = start + QSFP_VOLT_WIDTH + dom_voltage_data = sfpd_obj.parse_voltage( + dom_data_raw[start: end], 0) + volt = dom_voltage_data['data']['Vcc']['value'] + if volt is not None: + transceiver_dom_info_dict['voltage'] = volt + + start = QSFP_CHANNL_MON_OFFSET - QSFP_DOM_BULK_DATA_START + end = start + QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power( + dom_data_raw[start: end], 0) + + if self.dom_tx_power_supported: + transceiver_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TX1Power']['value'] + transceiver_dom_info_dict['tx2power'] = dom_channel_monitor_data['data']['TX2Power']['value'] + transceiver_dom_info_dict['tx3power'] = dom_channel_monitor_data['data']['TX3Power']['value'] + transceiver_dom_info_dict['tx4power'] = dom_channel_monitor_data['data']['TX4Power']['value'] + + if self.dom_rx_power_supported: + transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RX1Power']['value'] + transceiver_dom_info_dict['rx2power'] = dom_channel_monitor_data['data']['RX2Power']['value'] + transceiver_dom_info_dict['rx3power'] = dom_channel_monitor_data['data']['RX3Power']['value'] + transceiver_dom_info_dict['rx4power'] = dom_channel_monitor_data['data']['RX4Power']['value'] + + transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TX1Bias']['value'] + transceiver_dom_info_dict['tx2bias'] = dom_channel_monitor_data['data']['TX2Bias']['value'] + transceiver_dom_info_dict['tx3bias'] = dom_channel_monitor_data['data']['TX3Bias']['value'] + transceiver_dom_info_dict['tx4bias'] = dom_channel_monitor_data['data']['TX4Bias']['value'] + + elif self.sfp_type == QSFP_DD_TYPE: + + offset = 0 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return transceiver_dom_info_dict + + dom_data_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_DOM_BULK_DATA_START), QSFP_DD_DOM_BULK_DATA_SIZE) + if dom_data_raw is None: + return transceiver_dom_info_dict + + if self.dom_temp_supported: + start = QSFP_DD_TEMPE_OFFSET - QSFP_DD_DOM_BULK_DATA_START + end = start + QSFP_DD_TEMPE_WIDTH + dom_temperature_data = sfpd_obj.parse_temperature( + dom_data_raw[start: end], 0) + temp = dom_temperature_data['data']['Temperature']['value'] + if temp is not None: + transceiver_dom_info_dict['temperature'] = temp + + if self.dom_volt_supported: + start = QSFP_DD_VOLT_OFFSET - QSFP_DD_DOM_BULK_DATA_START + end = start + QSFP_DD_VOLT_WIDTH + dom_voltage_data = sfpd_obj.parse_voltage( + dom_data_raw[start: end], 0) + volt = dom_voltage_data['data']['Vcc']['value'] + if volt is not None: + transceiver_dom_info_dict['voltage'] = volt + + if self.dom_rx_tx_power_bias_supported: + # page 11h + dom_data_raw = self._read_eeprom_specific_bytes( + (QSFP_DD_CHANNL_MON_OFFSET), QSFP_DD_CHANNL_MON_WIDTH) + if dom_data_raw is None: + return transceiver_dom_info_dict + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( + dom_data_raw, 0) + + if self.dom_tx_power_supported: + transceiver_dom_info_dict['tx1power'] = str( + dom_channel_monitor_data['data']['TX1Power']['value']) + transceiver_dom_info_dict['tx2power'] = str( + dom_channel_monitor_data['data']['TX2Power']['value']) + transceiver_dom_info_dict['tx3power'] = str( + dom_channel_monitor_data['data']['TX3Power']['value']) + transceiver_dom_info_dict['tx4power'] = str( + dom_channel_monitor_data['data']['TX4Power']['value']) + transceiver_dom_info_dict['tx5power'] = str( + dom_channel_monitor_data['data']['TX5Power']['value']) + transceiver_dom_info_dict['tx6power'] = str( + dom_channel_monitor_data['data']['TX6Power']['value']) + transceiver_dom_info_dict['tx7power'] = str( + dom_channel_monitor_data['data']['TX7Power']['value']) + transceiver_dom_info_dict['tx8power'] = str( + dom_channel_monitor_data['data']['TX8Power']['value']) + + if self.dom_rx_power_supported: + transceiver_dom_info_dict['rx1power'] = str( + dom_channel_monitor_data['data']['RX1Power']['value']) + transceiver_dom_info_dict['rx2power'] = str( + dom_channel_monitor_data['data']['RX2Power']['value']) + transceiver_dom_info_dict['rx3power'] = str( + dom_channel_monitor_data['data']['RX3Power']['value']) + transceiver_dom_info_dict['rx4power'] = str( + dom_channel_monitor_data['data']['RX4Power']['value']) + transceiver_dom_info_dict['rx5power'] = str( + dom_channel_monitor_data['data']['RX5Power']['value']) + transceiver_dom_info_dict['rx6power'] = str( + dom_channel_monitor_data['data']['RX6Power']['value']) + transceiver_dom_info_dict['rx7power'] = str( + dom_channel_monitor_data['data']['RX7Power']['value']) + transceiver_dom_info_dict['rx8power'] = str( + dom_channel_monitor_data['data']['RX8Power']['value']) + + if self.dom_tx_bias_power_supported: + transceiver_dom_info_dict['tx1bias'] = str( + dom_channel_monitor_data['data']['TX1Bias']['value']) + transceiver_dom_info_dict['tx2bias'] = str( + dom_channel_monitor_data['data']['TX2Bias']['value']) + transceiver_dom_info_dict['tx3bias'] = str( + dom_channel_monitor_data['data']['TX3Bias']['value']) + transceiver_dom_info_dict['tx4bias'] = str( + dom_channel_monitor_data['data']['TX4Bias']['value']) + transceiver_dom_info_dict['tx5bias'] = str( + dom_channel_monitor_data['data']['TX5Bias']['value']) + transceiver_dom_info_dict['tx6bias'] = str( + dom_channel_monitor_data['data']['TX6Bias']['value']) + transceiver_dom_info_dict['tx7bias'] = str( + dom_channel_monitor_data['data']['TX7Bias']['value']) + transceiver_dom_info_dict['tx8bias'] = str( + dom_channel_monitor_data['data']['TX8Bias']['value']) + + return transceiver_dom_info_dict + + else: + if not self.dom_supported: + return transceiver_dom_info_dict + + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return transceiver_dom_info_dict + sfpd_obj._calibration_type = self.calibration + + dom_data_raw = self._read_eeprom_specific_bytes( + (offset + SFP_DOM_BULK_DATA_START), SFP_DOM_BULK_DATA_SIZE) + if dom_data_raw is None: + return transceiver_dom_info_dict + + start = SFP_TEMPE_OFFSET - SFP_DOM_BULK_DATA_START + end = start + SFP_TEMPE_WIDTH + dom_temperature_data = sfpd_obj.parse_temperature( + dom_data_raw[start: end], 0) + + start = SFP_VOLT_OFFSET - SFP_DOM_BULK_DATA_START + end = start + SFP_VOLT_WIDTH + dom_voltage_data = sfpd_obj.parse_voltage( + dom_data_raw[start: end], 0) + + start = SFP_CHANNL_MON_OFFSET - SFP_DOM_BULK_DATA_START + end = start + SFP_CHANNL_MON_WIDTH + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( + dom_data_raw[start: end], 0) + + transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RXPower']['value'] + transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TXBias']['value'] + transceiver_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TXPower']['value'] + + transceiver_dom_info_dict['lp_mode'] = self.get_lpmode() + transceiver_dom_info_dict['reset_status'] = self.get_reset_status() + transceiver_dom_info_dict['tx_disable'] = self.get_tx_disable() + transceiver_dom_info_dict['tx_disabled_channel'] = self.get_tx_disable_channel( + ) + + for key in transceiver_dom_info_dict: + val = transceiver_dom_info_dict[key] + transceiver_dom_info_dict[key] = self._convert_string_to_num( + val) if type(val) is str else val + + return transceiver_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. + ======================================================================== + """ + transceiver_dom_threshold_info_dict = dict.fromkeys( + threshold_dict_keys, NULL_VAL) + + if self.sfp_type == OSFP_TYPE: + pass + + elif self.sfp_type == QSFP_TYPE: + if not self.dom_supported or not self.qsfp_page3_available: + return transceiver_dom_threshold_info_dict + + # Dom Threshold data starts from offset 384 + # Revert offset back to 0 once data is retrieved + offset = QSFP_MODULE_UPPER_PAGE3_START + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return transceiver_dom_threshold_info_dict + + dom_module_threshold_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_MODULE_THRESHOLD_OFFSET), QSFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is None: + return transceiver_dom_threshold_info_dict + + dom_module_threshold_data = sfpd_obj.parse_module_threshold_values( + dom_module_threshold_raw, 0) + + dom_channel_threshold_raw = self._read_eeprom_specific_bytes((offset + QSFP_CHANNL_THRESHOLD_OFFSET), + QSFP_CHANNL_THRESHOLD_WIDTH) + if dom_channel_threshold_raw is None: + return transceiver_dom_threshold_info_dict + dom_channel_threshold_data = sfpd_obj.parse_channel_threshold_values( + dom_channel_threshold_raw, 0) + + # Threshold Data + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VccHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VccHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VccLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VccLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_channel_threshold_data['data']['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_channel_threshold_data['data']['RxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_channel_threshold_data['data']['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_channel_threshold_data['data']['RxPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_channel_threshold_data['data']['TxBiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_channel_threshold_data['data']['TxBiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_channel_threshold_data['data']['TxBiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_channel_threshold_data['data']['TxBiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_channel_threshold_data['data']['TxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_channel_threshold_data['data']['TxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_channel_threshold_data['data']['TxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_channel_threshold_data['data']['TxPowerLowWarning']['value'] + + elif self.sfp_type == QSFP_DD_TYPE: + if not self.dom_supported: + return transceiver_dom_threshold_info_dict + + if not self.dom_thresholds_supported: + return transceiver_dom_threshold_info_dict + + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return transceiver_dom_threshold_info_dict + + # page 02 + offset = 384 + dom_module_threshold_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_MODULE_THRESHOLD_OFFSET), QSFP_DD_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is None: + return transceiver_dom_threshold_info_dict + + dom_module_threshold_data = sfpd_obj.parse_module_threshold_values( + dom_module_threshold_raw, 0) + + # Threshold Data + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VccHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VccHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VccLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VccLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RxPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['TxBiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['TxBiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['TxBiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['TxBiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TxPowerLowWarning']['value'] + + else: + offset = SFP_MODULE_ADDRA2_OFFSET + + if not self.dom_supported: + return transceiver_dom_threshold_info_dict + + sfpd_obj = sff8472Dom(None, self.calibration) + if sfpd_obj is None: + return transceiver_dom_threshold_info_dict + + 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) + else: + return transceiver_dom_threshold_info_dict + + # Threshold Data + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VoltageHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VoltageLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data[ + 'data']['VoltageHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VoltageLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['BiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['BiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['BiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['BiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TXPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RXPowerLowWarning']['value'] + + for key in transceiver_dom_threshold_info_dict: + transceiver_dom_threshold_info_dict[key] = self._convert_string_to_num( + transceiver_dom_threshold_info_dict[key]) + + return transceiver_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 + """ + if not self.get_presence(): + return True #FPGA SPEC:It is set to 1 if the corresponding QSFP is not present + + pim=FpgaUtil() + val=pim.get_reset(self.port_num-1) + if val is not None: + return val==1 + else: + return False + + 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_list = [] + + if self.sfp_type == OSFP_TYPE: + return None + elif self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_RX_LOS_STATUS_OFFSET), + QSFP_CHANNL_RX_LOS_STATUS_WIDTH) + 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) + else: + return [False] * 4 + + elif self.sfp_type == QSFP_DD_TYPE: + # page 11h + if self.dom_rx_tx_power_bias_supported: + offset = 128 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_CHANNL_RX_LOS_STATUS_OFFSET), + QSFP_DD_CHANNL_RX_LOS_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 8) + 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_list.append(rx_los_data & 0x10 != 0) + rx_los_list.append(rx_los_data & 0x20 != 0) + rx_los_list.append(rx_los_data & 0x40 != 0) + rx_los_list.append(rx_los_data & 0x80 != 0) + else: + return [False] * 8 + else: # SFP_TYPE + offset = 256 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH) + 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 & 0x02 != 0) + else: + return [False] + return rx_los_list + + 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_list = [] + + if self.sfp_type == OSFP_TYPE: + return None + elif self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_TX_FAULT_STATUS_OFFSET), + QSFP_CHANNL_TX_FAULT_STATUS_WIDTH) + 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) + else: + return [False] * 4 + elif self.sfp_type == QSFP_DD_TYPE: + # page 11h + if self.dom_rx_tx_power_bias_supported: + offset = 128 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_CHANNL_TX_FAULT_STATUS_OFFSET), + QSFP_DD_CHANNL_TX_FAULT_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_fault_data = int(dom_channel_monitor_raw[0], 8) + 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_list.append(tx_fault_data & 0x10 != 0) + tx_fault_list.append(tx_fault_data & 0x20 != 0) + tx_fault_list.append(tx_fault_data & 0x40 != 0) + tx_fault_list.append(tx_fault_data & 0x80 != 0) + else: + return [False] * 8 + else: # SFP_TYPE + offset = 256 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH) + 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 & 0x04 != 0) + else: + return [False] + return tx_fault_list + + def get_tx_disable(self): + """ + Retrieves the tx_disable status of this SFP + Returns: + A list of boolean values, representing the TX disable status + of each available channel, value is True if SFP channel + is TX disabled, False if not. + E.g., for a tranceiver with four channels: [False, False, True, False] + """ + tx_disable_list = [] + if self.sfp_type == OSFP_TYPE: + return None + elif self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_DISABLE_STATUS_OFFSET), + QSFP_CHANNL_DISABLE_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0x01 != 0) + tx_disable_list.append(tx_disable_data & 0x02 != 0) + tx_disable_list.append(tx_disable_data & 0x04 != 0) + tx_disable_list.append(tx_disable_data & 0x08 != 0) + else: + return [False] * 4 + + elif self.sfp_type == QSFP_DD_TYPE: + if self.dom_rx_tx_power_bias_supported: + offset = 128 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_CHANNL_DISABLE_STATUS_OFFSET), + QSFP_DD_CHANNL_DISABLE_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0x01 != 0) + tx_disable_list.append(tx_disable_data & 0x02 != 0) + tx_disable_list.append(tx_disable_data & 0x04 != 0) + tx_disable_list.append(tx_disable_data & 0x08 != 0) + tx_disable_list.append(tx_disable_data & 0x10 != 0) + tx_disable_list.append(tx_disable_data & 0x20 != 0) + tx_disable_list.append(tx_disable_data & 0x40 != 0) + tx_disable_list.append(tx_disable_data & 0x80 != 0) + else: + return [False] * 8 + else: # SFP_TYPE + offset = 256 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0xC0 != 0) + else: + return [False] + return tx_disable_list + + 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. + """ + 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 + + 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 + """ + pim = FpgaUtil() + return pim.get_low_power_mode(self.port_num-1)==1 + + def get_power_set(self): + + if self.sfp_type == SFP_TYPE: + # SFP doesn't support this feature + return False + else: + power_set = False + + 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_set = ( + 'On' == dom_control_data['data']['PowerSet']['value']) + + return power_set + + 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 + """ + if self.sfp_type == QSFP_TYPE: + offset = 0 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return False + + dom_control_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_CONTROL_OFFSET), QSFP_CONTROL_WIDTH) + if dom_control_raw is not None: + dom_control_data = sfpd_obj.parse_control_bytes( + dom_control_raw, 0) + return ('On' == dom_control_data['data']['PowerOverride']['value']) + else: + return False + else: + return NotImplementedError + + def get_temperature(self): + """ + Retrieves the temperature of this SFP + Returns: + An integer number of current temperature in Celsius + """ + default = 0.0 + if not self.dom_supported: + return default + + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return default + + if self.dom_temp_supported: + 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) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + + elif self.sfp_type == QSFP_DD_TYPE: + offset = 0 + + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if self.dom_temp_supported: + dom_temperature_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_TEMPE_OFFSET), QSFP_DD_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature( + dom_temperature_raw, 0) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + + else: + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + sfpd_obj._calibration_type = 1 + + 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) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + + return default + + def get_voltage(self): + """ + Retrieves the supply voltage of this SFP + Returns: + An integer number of supply voltage in mV + """ + default = 0.0 + + if not self.dom_supported: + return default + + if self.sfp_type == QSFP_TYPE: + offset = 0 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return default + + if self.dom_volt_supported: + 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) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + + if self.sfp_type == QSFP_DD_TYPE: + offset = 128 + + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if self.dom_volt_supported: + dom_voltage_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_VOLT_OFFSET), QSFP_DD_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage( + dom_voltage_raw, 0) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + + else: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + + sfpd_obj._calibration_type = self.calibration + + 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) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + + return default + + 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'] + """ + tx_bias_list = [] + if self.sfp_type == QSFP_TYPE: + offset = 0 + default = [0.0] * 4 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return default + + 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) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX1Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX2Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX3Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX4Bias']['value'])) + else: + return default + + elif self.sfp_type == QSFP_DD_TYPE: + default = [0.0] * 8 + # page 11h + if self.dom_rx_tx_power_bias_supported: + offset = 128 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if dom_tx_bias_power_supported: + dom_tx_bias_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_TX_BIAS_OFFSET), QSFP_DD_TX_BIAS_WIDTH) + if dom_tx_bias_raw is not None: + dom_tx_bias_data = sfpd_obj.parse_dom_tx_bias( + dom_tx_bias_raw, 0) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX1Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX2Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX3Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX4Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX5Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX6Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX7Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX8Bias']['value'])) + else: + return default + else: + return default + + else: + offset = 256 + default = [0.0] + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + sfpd_obj._calibration_type = self.calibration + + if self.dom_supported: + 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) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TXBias']['value'])) + else: + return default + else: + return default + + return tx_bias_list + + 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'] + """ + rx_power_list = [] + if self.sfp_type == OSFP_TYPE: + # OSFP not supported on our platform yet. + return None + + elif self.sfp_type == QSFP_TYPE: + offset = 0 + default = [0.0] * 4 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return default + + if self.dom_rx_power_supported: + 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) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX1Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX2Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX3Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX4Power']['value'])) + else: + return default + else: + return default + + elif self.sfp_type == QSFP_DD_TYPE: + default = [0.0] * 8 + # page 11 + if self.dom_rx_tx_power_bias_supported: + offset = 128 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if self.dom_rx_power_supported: + dom_rx_power_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_RX_POWER_OFFSET), QSFP_DD_RX_POWER_WIDTH) + if dom_rx_power_raw is not None: + dom_rx_power_data = sfpd_obj.parse_dom_rx_power( + dom_rx_power_raw, 0) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX1Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX2Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX3Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX4Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX5Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX6Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX7Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX8Power']['value'])) + else: + return default + else: + return default + + else: + offset = 256 + default = [0.0] + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + + if self.dom_supported: + sfpd_obj._calibration_type = self.calibration + + 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) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RXPower']['value'])) + else: + return default + else: + return default + return rx_power_list + + 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'] + """ + tx_power_list = [] + if self.sfp_type == OSFP_TYPE: + # OSFP not supported on our platform yet. + return tx_power_list + + elif self.sfp_type == QSFP_TYPE: + offset = 0 + default = [0.0] * 4 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return tx_power_list + + if self.dom_tx_power_supported: + 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) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX1Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX2Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX3Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX4Power']['value'])) + else: + return default + else: + return default + + elif self.sfp_type == QSFP_DD_TYPE: + default = [0.0] * 8 + + # page 11 + if self.dom_rx_tx_power_bias_supported: + offset = 128 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if self.dom_tx_power_supported: + dom_tx_power_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_TX_POWER_OFFSET), + QSFP_DD_TX_POWER_WIDTH) + if dom_tx_power_raw is not None: + dom_tx_power_data = sfpd_obj.parse_dom_tx_power( + dom_tx_power_raw, 0) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX1Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX2Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX3Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX4Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX5Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX6Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX7Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX8Power']['value'])) + else: + return default + else: + return default + + else: + offset = 256 + default = [0.0] + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + + if self.dom_supported: + sfpd_obj._calibration_type = self.calibration + + 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) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TXPower']['value'])) + else: + return default + else: + return default + return tx_power_list + + def reset(self): + """ + Reset SFP and return all user module settings to their default srate. + Returns: + A boolean, True if successful, False if not + """ + # Check for invalid port_num + if not self.get_presence(): + return False + + pim = FpgaUtil() + time.sleep(0.2) + pim.reset(self.port_num-1) + time.sleep(0.2) + return True + + 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 + """ + if self.sfp_type == QSFP_TYPE: + sysfsfile_eeprom = None + try: + tx_disable_value = 0xf if tx_disable else 0x0 + # Write to eeprom + sysfsfile_eeprom = open(self._eeprom_path, "r+b") + sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) + sysfsfile_eeprom.write(struct.pack('B', tx_disable_value)) + except IOError: + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + + elif self.sfp_type == SFP_TYPE: + disable_path = "{}{}{}".format(self.i2c_cpld_path, 'module_tx_disable_', self.port_num) + tx_disable_value = 1 if tx_disable else 0 + ret = self._api_helper.write_txt_file(disable_path, tx_disable_value) #sysfs 1: disable tx + if ret is not True: + return ret + + return False + + 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 + """ + if self.sfp_type == QSFP_TYPE: + sysfsfile_eeprom = None + try: + current_state = self.get_tx_disable_channel() + tx_disable_value = (current_state | channel) if \ + disable else (current_state & (~channel)) + + # Write to eeprom + sysfsfile_eeprom = open(self._eeprom_path, "r+b") + sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) + sysfsfile_eeprom.write(struct.pack('B', tx_disable_value)) + except IOError: + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + + return False + + 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 + """ + pim = FpgaUtil() + pim.set_low_power_mode(self.port_num-1, lpmode) + return True + + 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 + """ + if self.sfp_type == SFP_TYPE: + return False # SFP doesn't support this feature + else: + if not self.get_presence(): + return False + try: + power_override_bit = (1 << 0) if power_override else 0 + power_set_bit = (1 << 1) if power_set else (1 << 3) + + buffer = create_string_buffer(1) + if sys.version_info[0] >= 3: + buffer[0] = (power_override_bit | power_set_bit) + else: + buffer[0] = chr(power_override_bit | power_set_bit) + # Write to eeprom + port_eeprom_path = I2C_EEPROM_PATH.format(self.port_num-1) + with open(port_eeprom_path, "r+b") as fd: + fd.seek(QSFP_POWEROVERRIDE_OFFSET) + fd.write(buffer[0]) + time.sleep(0.01) + except Exception as e: + print ('Error: unable to open file: ', str(e)) + return False + return True + + ############################################################## + ###################### Device methods ######################## + ############################################################## + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + sfputil_helper = SfpUtilHelper() + sfputil_helper.read_porttab_mappings( + self.__get_path_to_port_config_file()) + name = sfputil_helper.logical[self._index] or "Unknown" + return name + + def get_presence(self): + """ + Retrieves the presence of the device + Returns: + bool: True if device is present, False if not + """ + #print("Check get_presence, self.port_num=%d" %(self.port_num)) + #self._dom_capability_detect() + pim = FpgaUtil() + + status = pim.get_qsfp_presence(self.port_num-1) + #print("Port=%d , presence=%d"%(self.port_num, status)) + if status is not None: + return status==1 + else: + return False + + 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() + return transceiver_dom_info_dict.get("model", "N/A") + + 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() + return transceiver_dom_info_dict.get("serial", "N/A") + + 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 not self.get_reset_status() + + def get_cc_base(self): + if self.sfp_type == SFP_TYPE: + get_data = self._read_eeprom_specific_bytes( + 0, 63) if self.get_presence() else None + if get_data is None: + return False + + get_sum=0 + for i in range(0, 63): + get_sum=get_sum + int(get_data[i], 16) + + ccb= get_sum & 0xff + + ccb_data = self._read_eeprom_specific_bytes( + XCVR_CC_BASE_OFFSET, 2) if self.get_presence() else None + + + if int(ccb_data[0], 16) == ccb: + return True + else: + return False + elif self.sfp_type == QSFP_TYPE or self.sfp_type == QSFP_DD_TYPE: + offset=128 + get_data = self._read_eeprom_specific_bytes( + offset, 63) if self.get_presence() else None + if get_data is None: + return False + + get_sum=0 + for i in range(0, 63): + get_sum=get_sum + int(get_data[i], 16) + + ccb= get_sum & 0xff + + ccb_data = self._read_eeprom_specific_bytes( + offset + XCVR_CC_BASE_OFFSET, 2) if self.get_presence() else None + + + if int(ccb_data[0], 16) == ccb: + return True + else: + return False + + return False + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return self.port_num + + def is_replaceable(self): + """ + Retrieves if replaceable + Returns: + A boolean value, True if replaceable + """ + return True diff --git a/device/accton/x86_64-accton_minipack-r0/sonic_platform/thermal.py b/device/accton/x86_64-accton_minipack-r0/sonic_platform/thermal.py new file mode 100644 index 00000000000..317a2aab1cc --- /dev/null +++ b/device/accton/x86_64-accton_minipack-r0/sonic_platform/thermal.py @@ -0,0 +1,155 @@ +############################################################################# +# Edgecore +# +# Thermal contains an implementation of SONiC Platform Base API and +# provides the thermal device status which are available in the platform +# +############################################################################# +import glob + +try: + from sonic_platform_base.thermal_base import ThermalBase + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +DEVICE_PATH ="/sys/bus/platform/devices/minipack_psensor/" + +THERMAL_NAME_LIST = ["Temp sensor 1", "Temp sensor 2", + "Temp sensor 3", "Temp sensor 4", + "Temp sensor 5", "Temp sensor 6", + "Temp sensor 7", "Temp sensor 8",] + +PSU_THERMAL_NAME_LIST = ["PSU-1 temp sensor 1", "PSU-2 temp sensor 1", + "PSU-3 temp sensor 1", "PSU-4 temp sensor 1"] + +class Thermal(ThermalBase): + """Platform-specific Thermal class""" + + def __init__(self, thermal_index=0, is_psu=False, psu_index=0): + self.index = thermal_index + self.is_psu = is_psu + self.psu_index = psu_index + self.hwmon_path = DEVICE_PATH + self._api_helper = APIHelper() + + self.ss_key = THERMAL_NAME_LIST[self.index] + self.ss_index = 1 + + def __read_txt_file(self, file_path): + for filename in glob.glob(file_path): + try: + with open(filename, 'r') as fd: + data =fd.readline().rstrip() + return data + except IOError as e: + pass + + return None + + def __get_temp(self, temp_file): + + raw_temp=self._api_helper.read_txt_file(temp_file) + if raw_temp is not None: + return float(raw_temp)/1000 + else: + return 0 + + def __set_threshold(self, file_name, temperature): + + return False + + def get_temperature(self): + """ + Retrieves current temperature reading from thermal + Returns: + A float number of current temperature in Celsius up to nearest thousandth + of one degree Celsius, e.g. 30.125 + """ + if not self.is_psu: + temp_path = "{}{}{}{}".format(self.hwmon_path, 'temp', self.index+1, '_input') + else: + temp_path = "{}{}{}{}".format(self.hwmon_path, 'psu', self.psu_index+1, '_temp_input') + + return self.__get_temp(temp_path) + + def get_high_threshold(self): + """ + Retrieves the high threshold temperature of thermal + Returns: + A float number, the high threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + return 80 + + def set_high_threshold(self, temperature): + """ + Sets the high threshold temperature of thermal + Args : + temperature: A float number up to nearest thousandth of one degree Celsius, + e.g. 30.125 + Returns: + A boolean, True if threshold is set successfully, False if not + """ + return False + + def get_name(self): + """ + Retrieves the name of the thermal device + Returns: + string: The name of the thermal device + """ + if self.is_psu: + return PSU_THERMAL_NAME_LIST[self.psu_index] + else: + return THERMAL_NAME_LIST[self.index] + + def get_presence(self): + """ + Retrieves the presence of the Thermal + Returns: + bool: True if Thermal is present, False if not + """ + return self.get_temperature()!=0 + + 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_temperature()!=0 + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + + return "N/A" + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return "N/A" + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device or -1 if cannot determine the position + """ + return self.index+1 + + def is_replaceable(self): + """ + Retrieves whether thermal module is replaceable + Returns: + A boolean value, True if replaceable, False if not + """ + return False diff --git a/device/accton/x86_64-accton_minipack-r0/system_health_monitoring_config.json b/device/accton/x86_64-accton_minipack-r0/system_health_monitoring_config.json new file mode 100644 index 00000000000..a1099b81c97 --- /dev/null +++ b/device/accton/x86_64-accton_minipack-r0/system_health_monitoring_config.json @@ -0,0 +1,14 @@ +{ + "services_to_ignore": [], + "devices_to_ignore": [ + "asic", + "psu.temperature" + ], + "user_defined_checkers": [], + "polling_interval": 60, + "led_color": { + "fault": "ControlledByBMC", + "normal": "ControlledByBMC", + "booting": "ControlledByBMC" + } +} diff --git a/platform/broadcom/one-image.mk b/platform/broadcom/one-image.mk index 4405070460a..19170709f6b 100644 --- a/platform/broadcom/one-image.mk +++ b/platform/broadcom/one-image.mk @@ -35,6 +35,7 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \ $(ACCTON_AS7726_32X_PLATFORM_MODULE) \ $(ACCTON_AS4630_54PE_PLATFORM_MODULE) \ $(ACCTON_AS4630_54TE_PLATFORM_MODULE) \ + $(ACCTON_AS4630_54NPE_PLATFORM_MODULE) \ $(ACCTON_MINIPACK_PLATFORM_MODULE) \ $(ACCTON_AS5812_54X_PLATFORM_MODULE) \ $(ACCTON_AS5812_54T_PLATFORM_MODULE) \ @@ -44,6 +45,8 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \ $(ACCTON_AS5835_54T_PLATFORM_MODULE) \ $(ACCTON_AS7312_54XS_PLATFORM_MODULE) \ $(ACCTON_AS7315_27XB_PLATFORM_MODULE) \ + $(ACCTON_AS7926_40XFB_PLATFORM_MODULE) \ + $(ACCTON_AS7535_32XB_PLATFORM_MODULE) \ $(INVENTEC_D7032Q28B_PLATFORM_MODULE) \ $(INVENTEC_D7054Q28B_PLATFORM_MODULE) \ $(INVENTEC_D7264Q28B_PLATFORM_MODULE) \ diff --git a/platform/broadcom/platform-modules-accton.mk b/platform/broadcom/platform-modules-accton.mk index 1e2bfdcf82d..6f65d87f56e 100755 --- a/platform/broadcom/platform-modules-accton.mk +++ b/platform/broadcom/platform-modules-accton.mk @@ -11,6 +11,7 @@ ACCTON_AS6712_32X_PLATFORM_MODULE_VERSION = 1.1 ACCTON_AS7726_32X_PLATFORM_MODULE_VERSION = 1.1 ACCTON_AS4630_54PE_PLATFORM_MODULE_VERSION = 1.1 ACCTON_AS4630_54TE_PLATFORM_MODULE_VERSION = 1.1 +ACCTON_AS4630_54NPE_PLATFORM_MODULE_VERSION = 1.1 ACCTON_MINIPACK_PLATFORM_MODULE_VERSION = 1.1 ACCTON_AS5812_54X_PLATFORM_MODULE_VERSION = 1.1 ACCTON_AS5812_54T_PLATFORM_MODULE_VERSION = 1.1 @@ -20,6 +21,8 @@ ACCTON_AS9726_32D_PLATFORM_MODULE_VERSION = 1.1 ACCTON_AS5835_54T_PLATFORM_MODULE_VERSION = 1.1 ACCTON_AS7312_54XS_PLATFORM_MODULE_VERSION = 1.1 ACCTON_AS7315_27XB_PLATFORM_MODULE_VERSION = 1.1 +ACCTON_AS7926_40XFB_PLATFORM_MODULE_VERSION = 1.1 +ACCTON_AS7535_32XB_PLATFORM_MODULE_VERSION = 1.1 export ACCTON_AS7712_32X_PLATFORM_MODULE_VERSION export ACCTON_AS5712_54X_PLATFORM_MODULE_VERSION @@ -32,6 +35,7 @@ export ACCTON_AS6712_32X_PLATFORM_MODULE_VERSION export ACCTON_AS7726_32X_PLATFORM_MODULE_VERSION export ACCTON_AS4630_54PE_PLATFORM_MODULE_VERSION export ACCTON_AS4630_54TE_PLATFORM_MODULE_VERSION +export ACCTON_AS4630_54NPE_PLATFORM_MODULE_VERSION export ACCTON_MINIPACK_PLATFORM_MODULE_VERSION export ACCTON_AS5812_54X_PLATFORM_MODULE_VERSION export ACCTON_AS5812_54T_PLATFORM_MODULE_VERSION @@ -41,6 +45,8 @@ export ACCTON_AS9726_32D_PLATFORM_MODULE_VERSION export ACCTON_AS5835_54T_PLATFORM_MODULE_VERSION export ACCTON_AS7312_54XS_PLATFORM_MODULE_VERSION export ACCTON_AS7315_27XB_PLATFORM_MODULE_VERSION +export ACCTON_AS7926_40XFB_PLATFORM_MODULE_VERSION +export ACCTON_AS7535_32XB_PLATFORM_MODULE_VERSION ACCTON_AS7712_32X_PLATFORM_MODULE = sonic-platform-accton-as7712-32x_$(ACCTON_AS7712_32X_PLATFORM_MODULE_VERSION)_amd64.deb $(ACCTON_AS7712_32X_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-accton @@ -92,6 +98,10 @@ ACCTON_AS4630_54TE_PLATFORM_MODULE = sonic-platform-accton-as4630-54te_$(ACCTON_ $(ACCTON_AS4630_54TE_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as4630_54te-r0 $(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS4630_54TE_PLATFORM_MODULE))) +ACCTON_AS4630_54NPE_PLATFORM_MODULE = sonic-platform-accton-as4630-54npe_$(ACCTON_AS4630_54NPE_PLATFORM_MODULE_VERSION)_amd64.deb +$(ACCTON_AS4630_54NPE_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as4630_54npe-r0 +$(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS4630_54NPE_PLATFORM_MODULE))) + ACCTON_MINIPACK_PLATFORM_MODULE = sonic-platform-accton-minipack_$(ACCTON_MINIPACK_PLATFORM_MODULE_VERSION)_amd64.deb $(ACCTON_MINIPACK_PLATFORM_MODULE)_PLATFORM = x86_64-accton_minipack-r0 $(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_MINIPACK_PLATFORM_MODULE))) @@ -123,3 +133,11 @@ $(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS ACCTON_AS7315_27XB_PLATFORM_MODULE = sonic-platform-accton-as7315-27xb_$(ACCTON_AS7315_27XB_PLATFORM_MODULE_VERSION)_amd64.deb $(ACCTON_AS7315_27XB_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as7315_27xb-r0 $(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS7315_27XB_PLATFORM_MODULE))) + +ACCTON_AS7926_40XFB_PLATFORM_MODULE = sonic-platform-accton-as7926-40xfb_$(ACCTON_AS7926_40XFB_PLATFORM_MODULE_VERSION)_amd64.deb +$(ACCTON_AS7926_40XFB_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as7926_40xfb-r0 +$(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS7926_40XFB_PLATFORM_MODULE))) + +ACCTON_AS7535_32XB_PLATFORM_MODULE = sonic-platform-accton-as7535-32xb_$(ACCTON_AS7535_32XB_PLATFORM_MODULE_VERSION)_amd64.deb +$(ACCTON_AS7535_32XB_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as7535_32xb-r0 +$(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS7535_32XB_PLATFORM_MODULE))) diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/classes/__init__.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/classes/__init__.py new file mode 100755 index 00000000000..e69de29bb2d diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/classes/fanutil.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/classes/fanutil.py new file mode 100755 index 00000000000..10a83fc7725 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/classes/fanutil.py @@ -0,0 +1,213 @@ +#!/usr/bin/env python +# Copyright (c) 2019 Edgecore Networks Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +# +# THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT +# LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS +# FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. +# +# See the Apache Version 2.0 License for specific language governing +# permissions and limitations under the License. +# +# ------------------------------------------------------------------ +# HISTORY: +# mm/dd/yyyy (A.D.) +# 10/24/2019:Jostar craete for as4630_54npe +# ------------------------------------------------------------------ + +try: + import logging +except ImportError as e: + raise ImportError('%s - required module not found' % str(e)) + + +class FanUtil(object): + """Platform-specific FanUtil class""" + + FAN_NUM_ON_MAIN_BROAD = 3 + FAN_NUM_1_IDX = 1 + FAN_NUM_2_IDX = 2 + FAN_NUM_3_IDX = 3 + + FAN_NODE_NUM_OF_MAP = 4 + FAN_NODE_FAULT_IDX_OF_MAP = 1 + FAN_NODE_DIR_IDX_OF_MAP = 2 + FAN_NODE_PRESENT_IDX_OF_MAP = 3 + FAN_NODE_SPEED_IDX_OF_MAP = 4 + + BASE_VAL_PATH = '/sys/bus/i2c/devices/3-0060/{0}' + FAN_DUTY_PATH = '/sys/bus/i2c/devices/3-0060/fan_duty_cycle_percentage' + + """ Dictionary where + key1 = fan id index (integer) starting from 1 + key2 = fan node index (interger) starting from 1 + value = path to fan device file (string) """ + _fan_device_path_mapping = {} + + _fan_device_node_mapping = { + (FAN_NUM_1_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan_fault_1', + (FAN_NUM_1_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan_direction_1', + (FAN_NUM_1_IDX, FAN_NODE_PRESENT_IDX_OF_MAP): 'fan_present_1', + (FAN_NUM_1_IDX, FAN_NODE_SPEED_IDX_OF_MAP): 'fan1_input', + + + (FAN_NUM_2_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan_fault_2', + (FAN_NUM_2_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan_direction_2', + (FAN_NUM_2_IDX, FAN_NODE_PRESENT_IDX_OF_MAP): 'fan_present_2', + (FAN_NUM_2_IDX, FAN_NODE_SPEED_IDX_OF_MAP): 'fan2_input', + + (FAN_NUM_3_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan_fault_3', + (FAN_NUM_3_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan_direction_3', + (FAN_NUM_3_IDX, FAN_NODE_PRESENT_IDX_OF_MAP): 'fan_present_3', + (FAN_NUM_3_IDX, FAN_NODE_SPEED_IDX_OF_MAP): 'fan3_input', + } + + def _get_fan_device_node(self, fan_num, node_num): + return self._fan_device_node_mapping[(fan_num, node_num)] + + def _get_fan_node_val(self, fan_num, node_num): + if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD: + logging.debug('GET. Parameter error. fan_num:%d', fan_num) + return None + + if node_num < self.FAN_NODE_FAULT_IDX_OF_MAP or node_num > self.FAN_NODE_NUM_OF_MAP: + logging.debug('GET. Parameter error. node_num:%d', node_num) + return None + + device_path = self.get_fan_device_path(fan_num, node_num) + + try: + val_file = open(device_path, 'r') + except IOError as e: + logging.error('GET. unable to open file: %s', str(e)) + return None + + content = val_file.readline().rstrip() + if content == '': + logging.debug('GET. content is NULL. device_path:%s', device_path) + return None + + try: + val_file.close() + except Exception: + logging.debug( + 'GET. unable to close file. device_path:%s', + device_path) + return None + + return int(content) + + def _set_fan_node_val(self, fan_num, node_num, val): + if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD: + logging.debug('GET. Parameter error. fan_num:%d', fan_num) + return None + + if node_num < self.FAN_NODE_FAULT_IDX_OF_MAP or node_num > self.FAN_NODE_NUM_OF_MAP: + logging.debug('GET. Parameter error. node_num:%d', node_num) + return None + + content = str(val) + if content == '': + logging.debug('GET. content is NULL. device_path:%s', device_path) + return None + + device_path = self.get_fan_device_path(fan_num, node_num) + try: + val_file = open(device_path, 'w') + except IOError as e: + logging.error('GET. unable to open file: %s', str(e)) + return None + + val_file.write(content) + + try: + val_file.close() + except Exception: + logging.debug( + 'GET. unable to close file. device_path:%s', + device_path) + return None + + return True + + def __init__(self): + fan_path = self.BASE_VAL_PATH + for fan_num in range( + self.FAN_NUM_1_IDX, + self.FAN_NUM_ON_MAIN_BROAD + 1): + for node_num in range( + self.FAN_NODE_FAULT_IDX_OF_MAP, + self.FAN_NODE_NUM_OF_MAP + 1): + self._fan_device_path_mapping[(fan_num, node_num)] = fan_path.format( + self._fan_device_node_mapping[(fan_num, node_num)]) + + def get_size_node_map(self): + return len(self._fan_device_node_mapping) + + def get_fan_device_path(self, fan_num, node_num): + return self._fan_device_path_mapping[(fan_num, node_num)] + + def get_fan_fault(self, fan_num): + return self._get_fan_node_val(fan_num, self.FAN_NODE_FAULT_IDX_OF_MAP) + + def get_fan_present(self, fan_num): + return self._get_fan_node_val( + fan_num, self.FAN_NODE_PRESENT_IDX_OF_MAP) + + def get_fan_dir(self, fan_num): + return self._get_fan_node_val(fan_num, self.FAN_NODE_DIR_IDX_OF_MAP) + + def get_fan_duty_cycle(self): + try: + val_file = open(self.FAN_DUTY_PATH) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = val_file.readline().rstrip() + val_file.close() + + return int(content) + + def set_fan_duty_cycle(self, val): + try: + fan_file = open(self.FAN_DUTY_PATH, 'r+') + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + fan_file.write(str(val)) + fan_file.close() + return True + + def get_fan_speed(self, fan_num): + return self._get_fan_node_val(fan_num, self.FAN_NODE_SPEED_IDX_OF_MAP) + + def get_fan_status(self, fan_num): + if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD: + logging.debug('GET. Parameter error. fan_num, %d', fan_num) + return None + if self.get_fan_fault( + fan_num) == 0 and self.get_fan_present(fan_num) > 0: + return 1 + else: + logging.debug('GET. FAN fault. fan_num, %d', fan_num) + return 0 + + +def main(): + fan = FanUtil() + logging.debug('fan_duty_cycle=%d', fan.get_fan_duty_cycle()) + for i in range(1, 4): + logging.debug('fan-%d speed=%d', i, fan.get_fan_speed(i)) + logging.debug('fan-%d present=%d', i, fan.get_fan_present(i)) + logging.debug('fan-%d fault=%d', i, fan.get_fan_fault(i)) + logging.debug('fan-%d status=%d', i, fan.get_fan_status(i)) + + +if __name__ == '__main__': + main() diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/classes/thermalutil.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/classes/thermalutil.py new file mode 100755 index 00000000000..9c393ec911b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/classes/thermalutil.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python +# Copyright (c) 2019 Edgecore Networks Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +# +# THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT +# LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS +# FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. +# +# See the Apache Version 2.0 License for specific language governing +# permissions and limitations under the License. +# +# ------------------------------------------------------------------ +# HISTORY: +# mm/dd/yyyy (A.D.) +# 10/24/2019:Jostar craete for as4630_54npe +# ------------------------------------------------------------------ + +try: + import logging + import glob +except ImportError as e: + raise ImportError('%s - required module not found' % str(e)) + + +class ThermalUtil(object): + """Platform-specific ThermalUtil class""" + THERMAL_NUM_MAX = 4 + THERMAL_NUM_1_IDX = 1 + THERMAL_NUM_2_IDX = 2 + THERMAL_NUM_3_IDX = 3 + THERMAL_NUM_4_IDX = 4 + + """ Dictionary where + key1 = thermal id index (integer) starting from 1 + value = path to fan device file (string) """ + + thermal_sysfspath = { + THERMAL_NUM_1_IDX: ["/sys/bus/i2c/devices/14-0048/hwmon/hwmon*/temp1_input"], + THERMAL_NUM_2_IDX: ["/sys/bus/i2c/devices/24-004b/hwmon/hwmon*/temp1_input"], + THERMAL_NUM_3_IDX: ["/sys/bus/i2c/devices/25-004a/hwmon/hwmon*/temp1_input"], + THERMAL_NUM_4_IDX: ["/sys/class/hwmon/hwmon1/temp1_input"], + } + + def _get_thermal_val(self, thermal_num): + if thermal_num < self.THERMAL_NUM_1_IDX or thermal_num > self.THERMAL_NUM_MAX: + logging.debug('GET. Parameter error. thermal_num, %d', thermal_num) + return None + + device_path = self.get_thermal_path(thermal_num) + for filename in glob.glob(device_path): + try: + val_file = open(filename, 'r') + except IOError as e: + logging.error('GET. unable to open file: %s', str(e)) + return None + content = val_file.readline().rstrip() + if content == '': + logging.debug( + 'GET. content is NULL. device_path:%s', + device_path) + return None + try: + val_file.close() + except BaseException: + logging.debug( + 'GET. unable to close file. device_path:%s', + device_path) + return None + + return int(content) + + return 0 + + def get_num_thermals(self): + return self.THERMAL_NUM_MAX + + def get_size_path_map(self): + return len(self.thermal_sysfspath) + + def get_thermal_path(self, thermal_num): + return self.thermal_sysfspath[thermal_num][0] diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/modules/Makefile b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/modules/Makefile new file mode 100644 index 00000000000..d4b6b29c8a7 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/modules/Makefile @@ -0,0 +1,19 @@ +ifneq ($(KERNELRELEASE),) +obj-m:= x86-64-accton-as4630-54npe-cpld.o x86-64-accton-as4630-54npe-psu.o \ + x86-64-accton-as4630-54npe-leds.o ym2651y.o + +else +ifeq (,$(KERNEL_SRC)) +#$(error KERNEL_SRC is not defined) +KVERSION=3.16.0-8-amd64 +KERNEL_DIR = /usr/src/linux-headers-$(KVERSION)/ +KERNELDIR:=$(KERNEL_DIR) +else +KERNELDIR:=$(KERNEL_SRC) +endif +PWD:=$(shell pwd) +default: + $(MAKE) -C $(KERNELDIR) M=$(PWD) modules +clean: + rm -rf *.o *.mod.o *.mod.o *.mod.c *.ko .*cmd .tmp_versions Module.markers Module.symvers modules.order +endif diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/modules/x86-64-accton-as4630-54npe-cpld.c b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/modules/x86-64-accton-as4630-54npe-cpld.c new file mode 100644 index 00000000000..719b6017209 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/modules/x86-64-accton-as4630-54npe-cpld.c @@ -0,0 +1,911 @@ +/* + * Copyright (C) Jostar yang + * + * This module supports the accton cpld that hold the channel select + * mechanism for other i2c slave devices, such as SFP. + * This includes the: + * Accton as4630_54npe CPLD + * + * Based on: + * pca954x.c from Kumar Gala + * Copyright (C) 2006 + * + * Based on: + * pca954x.c from Ken Harrenstien + * Copyright (C) 2004 Google, Inc. (Ken Harrenstien) + * + * Based on: + * i2c-virtual_cb.c from Brian Kuschak + * and + * pca9540.c from Jean Delvare . + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define I2C_RW_RETRY_COUNT 10 +#define I2C_RW_RETRY_INTERVAL 60 /* ms */ +#define FAN_DUTY_CYCLE_REG_MASK 0x1F +#define FAN_MAX_DUTY_CYCLE 100 +#define FAN_REG_VAL_TO_SPEED_RPM_STEP 114 // R.P.M value = read value x3.79*60/2 + +#define NUM_THERMAL_SENSORS (3) /* Get sum of this number of sensors.*/ +#define THERMAL_SENSORS_ADDRS {0x48, 0x4a, 0x4b} + +static LIST_HEAD(cpld_client_list); +static struct mutex list_lock; + +struct cpld_client_node { + struct i2c_client *client; + struct list_head list; +}; + +enum cpld_type { + as4630_54npe_cpld, +}; +enum fan_id { + FAN1_ID, + FAN2_ID, + FAN3_ID, +}; + +static const u8 fan_reg[] = { + 0x87, /* fan status, fan direction */ + 0x1A, /* fan PWM(for fan1 ,fan2) */ + 0x1B, /* fan PWM(for fan1 ,fan2) */ + 0x88, /* front fan1 speed(rpm) */ + 0x89, /* front fan2 speed(rpm) */ + 0x8A, /* front fan3 speed(rpm) */ + 0x20, /*fan fault*/ +}; + +struct as4630_54npe_cpld_data { + enum cpld_type type; + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 reg_fan_val[ARRAY_SIZE(fan_reg)]; /* Register value */ + int system_temp; /*In unit of mini-Celsius*/ + int sensors_found; +}; + + + +static const struct i2c_device_id as4630_54npe_cpld_id[] = { + { "as4630_54npe_cpld", as4630_54npe_cpld}, + { } +}; +MODULE_DEVICE_TABLE(i2c, as4630_54npe_cpld_id); + +#define TRANSCEIVER_RESET_ATTR_ID(index) MODULE_RESET_##index +#define TRANSCEIVER_LPMODE_ATTR_ID(index) MODULE_LPMODE_##index +#define TRANSCEIVER_PRESENT_ATTR_ID(index) MODULE_PRESENT_##index +#define TRANSCEIVER_TXDISABLE_ATTR_ID(index) MODULE_TXDISABLE_##index +#define TRANSCEIVER_RXLOS_ATTR_ID(index) MODULE_RXLOS_##index +#define TRANSCEIVER_TXFAULT_ATTR_ID(index) MODULE_TXFAULT_##index +#define FAN_SPEED_RPM_ATTR_ID(index) FAN_SPEED_RPM_##index +#define FAN_DIRECTION_ID(index) FAN_DIRECTION_##index +#define FAN_PRESENT_ATTR_ID(index) FAN_PRESENT_##index +#define FAN_FAULT_ATTR_ID(index) FAN_FAULT_##index + +enum as4630_54npe_cpld_sysfs_attributes { + CPLD_VERSION, + ACCESS, + /* transceiver attributes */ + TRANSCEIVER_RXLOS_ATTR_ID(49), + TRANSCEIVER_RXLOS_ATTR_ID(50), + TRANSCEIVER_RXLOS_ATTR_ID(51), + TRANSCEIVER_RXLOS_ATTR_ID(52), + TRANSCEIVER_TXFAULT_ATTR_ID(49), + TRANSCEIVER_TXFAULT_ATTR_ID(50), + TRANSCEIVER_TXFAULT_ATTR_ID(51), + TRANSCEIVER_TXFAULT_ATTR_ID(52), + TRANSCEIVER_PRESENT_ATTR_ID(49), + TRANSCEIVER_PRESENT_ATTR_ID(50), + TRANSCEIVER_PRESENT_ATTR_ID(51), + TRANSCEIVER_PRESENT_ATTR_ID(52), + TRANSCEIVER_PRESENT_ATTR_ID(53), + TRANSCEIVER_PRESENT_ATTR_ID(54), + TRANSCEIVER_RESET_ATTR_ID(53), + TRANSCEIVER_RESET_ATTR_ID(54), + TRANSCEIVER_LPMODE_ATTR_ID(53), + TRANSCEIVER_LPMODE_ATTR_ID(54), + TRANSCEIVER_TXDISABLE_ATTR_ID(49), + TRANSCEIVER_TXDISABLE_ATTR_ID(50), + TRANSCEIVER_TXDISABLE_ATTR_ID(51), + TRANSCEIVER_TXDISABLE_ATTR_ID(52), + FAN_PRESENT_ATTR_ID(1), + FAN_PRESENT_ATTR_ID(2), + FAN_PRESENT_ATTR_ID(3), + FAN_SPEED_RPM_ATTR_ID(1), + FAN_SPEED_RPM_ATTR_ID(2), + FAN_SPEED_RPM_ATTR_ID(3), + FAN_DIRECTION_ID(1), + FAN_DIRECTION_ID(2), + FAN_DIRECTION_ID(3), + FAN_FAULT_ATTR_ID(1), + FAN_FAULT_ATTR_ID(2), + FAN_FAULT_ATTR_ID(3), + FAN_DUTY_CYCLE_PERCENTAGE, +}; + +/* sysfs attributes for hwmon + */ +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t set_qsfp(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t access(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t show_version(struct device *dev, struct device_attribute *da, + char *buf); +static int as4630_54npe_cpld_read_internal(struct i2c_client *client, u8 reg); +static int as4630_54npe_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value); + +/*fan sysfs*/ +static struct as4630_54npe_cpld_data *as4630_54npe_fan_update_device(struct device *dev); +static ssize_t fan_show_value(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t set_duty_cycle(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); + +/* transceiver attributes */ +#define DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, show_status, NULL, MODULE_PRESENT_##index); \ + static SENSOR_DEVICE_ATTR(module_tx_disable_##index, S_IRUGO | S_IWUSR, show_status, set_tx_disable, MODULE_TXDISABLE_##index); \ + static SENSOR_DEVICE_ATTR(module_rx_los_##index, S_IRUGO, show_status, NULL, MODULE_RXLOS_##index); \ + static SENSOR_DEVICE_ATTR(module_tx_fault_##index, S_IRUGO, show_status, NULL, MODULE_TXFAULT_##index); + +#define DECLARE_SFP_TRANSCEIVER_ATTR(index) \ + &sensor_dev_attr_module_present_##index.dev_attr.attr, \ + &sensor_dev_attr_module_tx_disable_##index.dev_attr.attr, \ + &sensor_dev_attr_module_rx_los_##index.dev_attr.attr, \ + &sensor_dev_attr_module_tx_fault_##index.dev_attr.attr + +#define DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_lpmode_##index, S_IRUGO | S_IWUSR, show_status, set_qsfp, MODULE_LPMODE_##index); \ + static SENSOR_DEVICE_ATTR(module_reset_##index, S_IRUGO | S_IWUSR, show_status, set_qsfp, MODULE_RESET_##index); \ + static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, show_status, NULL, MODULE_PRESENT_##index); + +#define DECLARE_QSFP_TRANSCEIVER_ATTR(index) \ + &sensor_dev_attr_module_lpmode_##index.dev_attr.attr, \ + &sensor_dev_attr_module_reset_##index.dev_attr.attr, \ + &sensor_dev_attr_module_present_##index.dev_attr.attr + + +#define DECLARE_FAN_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan_present_##index, S_IRUGO, fan_show_value, NULL, FAN_PRESENT_##index); \ + static SENSOR_DEVICE_ATTR(fan_fault_##index, S_IRUGO, fan_show_value, NULL, FAN_FAULT_##index); \ + static SENSOR_DEVICE_ATTR(fan_speed_rpm_##index, S_IRUGO, fan_show_value, NULL, FAN_SPEED_RPM_##index); \ + static SENSOR_DEVICE_ATTR(fan##index##_input, S_IRUGO, fan_show_value, NULL, FAN_SPEED_RPM_##index);\ + static SENSOR_DEVICE_ATTR(fan_direction_##index, S_IRUGO, fan_show_value, NULL, FAN_DIRECTION_##index); + +#define DECLARE_FAN_ATTR(index) \ + &sensor_dev_attr_fan_present_##index.dev_attr.attr, \ + &sensor_dev_attr_fan_fault_##index.dev_attr.attr, \ + &sensor_dev_attr_fan_speed_rpm_##index.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_input.dev_attr.attr, \ + &sensor_dev_attr_fan_direction_##index.dev_attr.attr + +#define DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan_duty_cycle_percentage, S_IWUSR | S_IRUGO, fan_show_value, set_duty_cycle, FAN_DUTY_CYCLE_PERCENTAGE); +#define DECLARE_FAN_DUTY_CYCLE_ATTR(index) &sensor_dev_attr_fan_duty_cycle_percentage.dev_attr.attr + + +static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, NULL, CPLD_VERSION); +static SENSOR_DEVICE_ATTR(access, S_IWUSR, NULL, access, ACCESS); + + + +/* transceiver attributes */ +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(49); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(50); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(51); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(52); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(53); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(54); +/* fan attributes */ +DECLARE_FAN_SENSOR_DEV_ATTR(1); +DECLARE_FAN_SENSOR_DEV_ATTR(2); +DECLARE_FAN_SENSOR_DEV_ATTR(3); +DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR(1); + +static struct attribute *as4630_54npe_cpld_attributes[] = { + &sensor_dev_attr_version.dev_attr.attr, + &sensor_dev_attr_access.dev_attr.attr, + DECLARE_SFP_TRANSCEIVER_ATTR(49), + DECLARE_SFP_TRANSCEIVER_ATTR(50), + DECLARE_SFP_TRANSCEIVER_ATTR(51), + DECLARE_SFP_TRANSCEIVER_ATTR(52), + DECLARE_QSFP_TRANSCEIVER_ATTR(53), + DECLARE_QSFP_TRANSCEIVER_ATTR(54), + DECLARE_FAN_ATTR(1), + DECLARE_FAN_ATTR(2), + DECLARE_FAN_ATTR(3), + DECLARE_FAN_DUTY_CYCLE_ATTR(1), + NULL +}; + +static const struct attribute_group as4630_54npe_cpld_group = { + .attrs = as4630_54npe_cpld_attributes, +}; + + +static ssize_t show_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 as4630_54npe_cpld_data *data = i2c_get_clientdata(client); + int status = 0; + u8 reg = 0, mask = 0, revert = 0; + + switch (attr->index) + { + case MODULE_RXLOS_49 ... MODULE_RXLOS_50: + reg=0x5; + mask = 0x1<< (attr->index==MODULE_RXLOS_49?4:0); + break; + case MODULE_TXFAULT_49 ... MODULE_TXFAULT_50: + reg=0x5; + mask=0x1 << (attr->index==MODULE_TXFAULT_49?5:1); + break; + case MODULE_PRESENT_49 ... MODULE_PRESENT_50: + reg=0x5; + mask=0x1 << (attr->index==MODULE_PRESENT_49?6:2); + break; + case MODULE_TXDISABLE_49 ... MODULE_TXDISABLE_50: + reg=0x5; + mask=0x1 << (attr->index==MODULE_TXDISABLE_49?7:3); + break; + + case MODULE_RXLOS_51 ... MODULE_RXLOS_52: + reg=0x6; + mask = 0x1<< (attr->index==MODULE_RXLOS_51?4:0); + break; + case MODULE_TXFAULT_51 ... MODULE_TXFAULT_52: + reg=0x6; + mask=0x1 << (attr->index==MODULE_TXFAULT_51?5:1); + break; + case MODULE_PRESENT_51 ... MODULE_PRESENT_52: + reg=0x6; + mask=0x1 << (attr->index==MODULE_PRESENT_51?6:2); + break; + case MODULE_TXDISABLE_51 ... MODULE_TXDISABLE_52: + reg=0x6; + mask=0x1 << (attr->index==MODULE_TXDISABLE_51?7:3); + break; + case MODULE_PRESENT_53 ... MODULE_PRESENT_54: + reg=0x21; + mask=0x1 << (attr->index==MODULE_PRESENT_53?0:4); + break; + case MODULE_RESET_53 ... MODULE_RESET_54: + reg=0x21; + mask=0x1 << (attr->index==MODULE_RESET_53?3:7); + revert = 1; + break; + case MODULE_LPMODE_53 ... MODULE_LPMODE_54: + reg = 0x21; + mask = 0x1 << (attr->index==MODULE_LPMODE_53?2:6); + revert = 0; + break; + default: + return 0; + } + + if( attr->index >= MODULE_PRESENT_49 && attr->index <= MODULE_PRESENT_54 ) + { + revert = 1; + } + + mutex_lock(&data->update_lock); + status = as4630_54npe_cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", revert ? !(status & mask) : !!(status & mask)); + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t set_qsfp(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 as4630_54npe_cpld_data *data = i2c_get_clientdata(client); + long disable; + int status; + u8 reg = 0, mask = 0, revert = 0; + + status = kstrtol(buf, 10, &disable); + if (status) { + return status; + } + reg = 0x21; + switch (attr->index) + { + case MODULE_RESET_53 ... MODULE_RESET_54: + mask=0x1 << (attr->index==MODULE_RESET_53?3:7); + revert = 1; + break; + case MODULE_LPMODE_53 ... MODULE_LPMODE_54: + mask=0x1 << (attr->index==MODULE_LPMODE_53?2:6); + revert = 0; + break; + default: + return 0; + } + + disable = revert ? disable : !disable; + /* Read current status */ + mutex_lock(&data->update_lock); + status = as4630_54npe_cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + if (disable) { + status &= ~mask; + } + else { + status |= mask; + } + status = as4630_54npe_cpld_write_internal(client, reg, status); + if (unlikely(status < 0)) { + goto exit; + } + + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t set_tx_disable(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 as4630_54npe_cpld_data *data = i2c_get_clientdata(client); + long disable; + int status; + u8 reg = 0, mask = 0; + + status = kstrtol(buf, 10, &disable); + if (status) { + return status; + } + reg = 0x9; + switch (attr->index) + { + case MODULE_TXDISABLE_49 ... MODULE_TXDISABLE_50: + reg=0x5; + mask=0x1 << (attr->index==MODULE_TXDISABLE_49?7:3); + break; + case MODULE_TXDISABLE_51 ... MODULE_TXDISABLE_52: + reg=0x6; + mask=0x1 << (attr->index==MODULE_TXDISABLE_51?7:3); + break; + + default: + return 0; + } + + /* Read current status */ + mutex_lock(&data->update_lock); + status = as4630_54npe_cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + /* Update tx_disable status */ + if (!disable) { + status &= ~mask; + } + else { + status |= mask; + } + status = as4630_54npe_cpld_write_internal(client, reg, status); + if (unlikely(status < 0)) { + goto exit; + } + + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t access(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int status; + u32 addr, val; + struct i2c_client *client = to_i2c_client(dev); + struct as4630_54npe_cpld_data *data = i2c_get_clientdata(client); + + if (sscanf(buf, "0x%x 0x%x", &addr, &val) != 2) { + return -EINVAL; + } + + if (addr > 0xFF || val > 0xFF) { + return -EINVAL; + } + + mutex_lock(&data->update_lock); + status = as4630_54npe_cpld_write_internal(client, addr, val); + if (unlikely(status < 0)) { + goto exit; + } + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static void as4630_54npe_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 as4630_54npe_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 ssize_t show_version(struct device *dev, struct device_attribute *attr, char *buf) +{ + int val = 0; + struct i2c_client *client = to_i2c_client(dev); + + val = i2c_smbus_read_byte_data(client, 0x1); + + if (val < 0) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x1) err %d\n", client->addr, val); + } + + return sprintf(buf, "%d\n", val); +} + +/* fan utility functions + */ +static u32 reg_val_to_duty_cycle(u8 reg_val) +{ + reg_val &= FAN_DUTY_CYCLE_REG_MASK; + return ((u32)(reg_val) * 625)/ 100; +} + +static u8 duty_cycle_to_reg_val(u8 duty_cycle) +{ + return ((u32)duty_cycle * 100 / 625); +} + +static u32 reg_val_to_speed_rpm(u8 reg_val) +{ + return (u32)reg_val * FAN_REG_VAL_TO_SPEED_RPM_STEP; +} + +static ssize_t set_duty_cycle(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int error, value; + struct i2c_client *client = to_i2c_client(dev); + + error = kstrtoint(buf, 10, &value); + if (error) + return error; + + if (value < 0 || value > FAN_MAX_DUTY_CYCLE) + return -EINVAL; + + as4630_54npe_cpld_write_internal(client, fan_reg[1], duty_cycle_to_reg_val(value)); + as4630_54npe_cpld_write_internal(client, fan_reg[2], duty_cycle_to_reg_val(value)); + return count; +} + +static u8 reg_val_to_direction(u8 reg_val, enum fan_id id) +{ + u8 mask = (1 << (4 + id)); + + reg_val &= mask; + + return reg_val ? 0 : 1; +} + +static u8 reg_val_to_is_present(u8 reg_val, enum fan_id id) +{ + u8 mask = (1 << id); + + reg_val &= mask; + + return reg_val ? 0 : 1; +} + +static u8 is_fan_fault(struct as4630_54npe_cpld_data *data, enum fan_id id) +{ + u8 ret = 1; + + if(id > FAN3_ID) + return 1; + /* Check if the speed of front or rear fan is ZERO, + */ + if (reg_val_to_speed_rpm(data->reg_fan_val[id+3])) + { + + ret = 0; + } + + return ret; +} + + +static ssize_t fan_show_value(struct device *dev, struct device_attribute *da, + char *buf) +{ + u32 duty_cycle; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct as4630_54npe_cpld_data *data = as4630_54npe_fan_update_device(dev); + ssize_t ret = 0; + + if (data->valid) { + switch (attr->index) + { + case FAN_PRESENT_1: + case FAN_PRESENT_2: + case FAN_PRESENT_3: + ret = sprintf(buf, "%d\n", + reg_val_to_is_present(data->reg_fan_val[0], + attr->index - FAN_PRESENT_1)); + break; + case FAN_DUTY_CYCLE_PERCENTAGE: + duty_cycle = reg_val_to_duty_cycle(data->reg_fan_val[1]); + ret = sprintf(buf, "%u\n", duty_cycle); + break; + case FAN_SPEED_RPM_1: + case FAN_SPEED_RPM_2: + case FAN_SPEED_RPM_3: + ret = sprintf(buf, "%u\n", reg_val_to_speed_rpm(data->reg_fan_val[attr->index-FAN_SPEED_RPM_1+3])); + break; + case FAN_FAULT_1: + case FAN_FAULT_2: + case FAN_FAULT_3: + ret = sprintf(buf, "%d\n", is_fan_fault(data, attr->index - FAN_FAULT_1)); + break; + case FAN_DIRECTION_1: + case FAN_DIRECTION_2: + case FAN_DIRECTION_3: + ret = sprintf(buf, "%d\n", + reg_val_to_direction(data->reg_fan_val[0], + attr->index - FAN_DIRECTION_1)); + break; + default: + break; + } + } + + return ret; +} + +static struct as4630_54npe_cpld_data *as4630_54npe_fan_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as4630_54npe_cpld_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || + !data->valid) { + int i; + + dev_dbg(&client->dev, "Starting as4630_54npe_fan update\n"); + data->valid = 0; + + /* Update fan data + */ + for (i = 0; i < ARRAY_SIZE(data->reg_fan_val); i++) { + int status = as4630_54npe_cpld_read_internal(client, fan_reg[i]); + if (status < 0) { + data->valid = 0; + mutex_unlock(&data->update_lock); + dev_dbg(&client->dev, "reg 0x%x, err %d\n", fan_reg[i], status); + return data; + } + else { + data->reg_fan_val[i] = status & 0xff; + } + } + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + +/* +static ssize_t show_power(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as4630_54npe_cpld_data *data = i2c_get_clientdata(client); + int status = 0; + u8 reg = 0, mask = 0; + + reg=0xc; + mask=0x2; + mutex_lock(&data->update_lock); + status = as4630_54npe_cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", !(status & mask)); + +exit: + mutex_unlock(&data->update_lock); + return status; +} +*/ +/* + * I2C init/probing/exit functions + */ +static int as4630_54npe_cpld_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); + struct as4630_54npe_cpld_data *data; + int ret = -ENODEV; +// int status; + const struct attribute_group *group = NULL; + + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) + goto exit; + + data = kzalloc(sizeof(struct as4630_54npe_cpld_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + data->type = id->driver_data; + + /* Register sysfs hooks */ + switch (data->type) + { + case as4630_54npe_cpld: + group = &as4630_54npe_cpld_group; + break; + default: + break; + } + + if (group) + { + ret = sysfs_create_group(&client->dev.kobj, group); + if (ret) { + goto exit_free; + } + } + + as4630_54npe_cpld_add_client(client); + + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + ret = PTR_ERR(data->hwmon_dev); + goto exit_free; + } + + + return 0; + +exit_free: + kfree(data); +exit: + return ret; +} + +static int as4630_54npe_cpld_remove(struct i2c_client *client) +{ + struct as4630_54npe_cpld_data *data = i2c_get_clientdata(client); + const struct attribute_group *group = NULL; + + as4630_54npe_cpld_remove_client(client); + + /* Remove sysfs hooks */ + switch (data->type) + { + case as4630_54npe_cpld: + group = &as4630_54npe_cpld_group; + break; + default: + break; + } + + if (group) { + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, group); + } + + + kfree(data); + + return 0; +} + +static int as4630_54npe_cpld_read_internal(struct i2c_client *client, u8 reg) +{ + int status = 0, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_read_byte_data(client, reg); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + return status; +} + +static int as4630_54npe_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value) +{ + int status = 0, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_write_byte_data(client, reg, value); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + return status; +} + +int as4630_54npe_cpld_read(unsigned short cpld_addr, u8 reg) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int ret = -EPERM; + + 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 = as4630_54npe_cpld_read_internal(cpld_node->client, reg); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(as4630_54npe_cpld_read); + +int as4630_54npe_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 = as4630_54npe_cpld_write_internal(cpld_node->client, reg, value); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(as4630_54npe_cpld_write); + +static struct i2c_driver as4630_54npe_cpld_driver = { + .driver = { + .name = "as4630_54npe_cpld", + .owner = THIS_MODULE, + }, + .probe = as4630_54npe_cpld_probe, + .remove = as4630_54npe_cpld_remove, + .id_table = as4630_54npe_cpld_id, +}; + +static int __init as4630_54npe_cpld_init(void) +{ + mutex_init(&list_lock); + return i2c_add_driver(&as4630_54npe_cpld_driver); +} + +static void __exit as4630_54npe_cpld_exit(void) +{ + i2c_del_driver(&as4630_54npe_cpld_driver); +} + +MODULE_AUTHOR("Jostar Yang "); +MODULE_DESCRIPTION("Accton I2C CPLD driver"); +MODULE_LICENSE("GPL"); + +module_init(as4630_54npe_cpld_init); +module_exit(as4630_54npe_cpld_exit); diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/modules/x86-64-accton-as4630-54npe-leds.c b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/modules/x86-64-accton-as4630-54npe-leds.c new file mode 100644 index 00000000000..1e1d060b6f7 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/modules/x86-64-accton-as4630-54npe-leds.c @@ -0,0 +1,579 @@ +/* + * A LED driver for the accton_as4630_54npe_led + * + * Copyright (C) 2014 Accton Technology Corporation. + * Brandon Chuang + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/*#define DEBUG*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +extern int as4630_54npe_cpld_read (unsigned short cpld_addr, u8 reg); +extern int as4630_54npe_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); + +#define DRVNAME "accton_as4630_54npe_led" + +struct accton_as4630_54npe_led_data { + struct platform_device *pdev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 reg_val[2]; /* only 1 register*/ +}; + +static struct accton_as4630_54npe_led_data *ledctl = NULL; + +/* LED related data + */ + +#define LED_CNTRLER_I2C_ADDRESS (0x60) + +#define LED_TYPE_DIAG_REG_MASK (0x20|0x40|0x80) +#define LED_MODE_DIAG_GREEN_VALUE (0x20) +#define LED_MODE_DIAG_GREEN_BLINK_VALUE (0x60) +#define LED_MODE_DIAG_AMBER_VALUE (0x80) /*It's yellow actually. Green+Red=Yellow*/ +#define LED_MODE_DIAG_OFF_VALUE (0x0) + +#define LED_TYPE_PRI_REG_MASK (0x8|0x4) +#define LED_MODE_PRI_GREEN_VALUE 0x4 +#define LED_MODE_PRI_AMBER_VALUE 0x8 +#define LED_MODE_PRI_OFF_VALUE 0x0 + +#define LED_TYPE_POE_REG_MASK (0x2|0x1) +#define LED_MODE_POE_GREEN_VALUE 0x1 +#define LED_MODE_POE_AMBER_VALUE 0x2 +#define LED_MODE_POE_OFF_VALUE 0x3 + +#define LED_TYPE_STK1_REG_MASK 0x20 +#define LED_MODE_STK1_GREEN_VALUE 0x0 +#define LED_MODE_STK1_OFF_VALUE 0x20 + +#define LED_TYPE_STK2_REG_MASK 0x10 +#define LED_MODE_STK2_GREEN_VALUE 0x0 +#define LED_MODE_STK2_OFF_VALUE 0x10 + +#define LED_TYPE_FAN_REG_MASK (0x8|0x4) +#define LED_MODE_FAN_AMBER_VALUE 0x8 +#define LED_MODE_FAN_GREEN_VALUE 0x4 +#define LED_MODE_FAN_OFF_VALUE (0xC) + +#define LED_TYPE_PSU2_REG_MASK (0x80|0x40) +#define LED_MODE_PSU2_AMBER_VALUE 0x80 +#define LED_MODE_PSU2_GREEN_VALUE 0x40 +#define LED_MODE_PSU2_OFF_VALUE (0xC0) + +#define LED_TYPE_PSU1_REG_MASK (0x2|0x1) +#define LED_MODE_PSU1_AMBER_VALUE 0x2 +#define LED_MODE_PSU1_GREEN_VALUE 0x1 +#define LED_MODE_PSU1_OFF_VALUE (0x3) + +enum led_type { + LED_TYPE_DIAG, + LED_TYPE_PRI, + LED_TYPE_POE, + LED_TYPE_STK1, + LED_TYPE_STK2, + LED_TYPE_FAN, + LED_TYPE_PSU1, + LED_TYPE_PSU2 +}; + +struct led_reg { + u32 types; + u8 reg_addr; +}; + +static const struct led_reg led_reg_map[] = { + {(1<update_lock); + + if (time_after(jiffies, ledctl->last_updated + HZ + HZ / 2) + || !ledctl->valid) { + int i; + + dev_dbg(&ledctl->pdev->dev, "Starting accton_as4630_54npe_led update\n"); + + /* Update LED data + */ + for (i = 0; i < ARRAY_SIZE(ledctl->reg_val); i++) { + int status = accton_as4630_54npe_led_read_value(led_reg_map[i].reg_addr); + + if (status < 0) { + ledctl->valid = 0; + dev_dbg(&ledctl->pdev->dev, "reg %d, err %d\n", led_reg_map[i].reg_addr, status); + goto exit; + } + else + { + ledctl->reg_val[i] = status; + } + } + + ledctl->last_updated = jiffies; + ledctl->valid = 1; + } + +exit: + mutex_unlock(&ledctl->update_lock); +} + +static void accton_as4630_54npe_led_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode, + enum led_type type) +{ + int reg_val; + u8 reg ; + mutex_lock(&ledctl->update_lock); + + if( !accton_getLedReg(type, ®)) + { + dev_dbg(&ledctl->pdev->dev, "Not match item for %d.\n", type); + } + + + reg_val = accton_as4630_54npe_led_read_value(reg); + if (reg_val < 0) { + dev_dbg(&ledctl->pdev->dev, "reg %d, err %d\n", reg, reg_val); + goto exit; + } + reg_val = led_light_mode_to_reg_val(type, led_light_mode, reg_val); + + accton_as4630_54npe_led_write_value(reg, reg_val); + + /* to prevent the slow-update issue */ + ledctl->valid = 0; + +exit: + mutex_unlock(&ledctl->update_lock); +} + + +static void accton_as4630_54npe_led_diag_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + accton_as4630_54npe_led_set(led_cdev, led_light_mode, LED_TYPE_DIAG); +} + +static enum led_brightness accton_as4630_54npe_led_diag_get(struct led_classdev *cdev) +{ + accton_as4630_54npe_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_DIAG, ledctl->reg_val[0]); +} + +static void accton_as4630_54npe_led_pri_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + accton_as4630_54npe_led_set(led_cdev, led_light_mode, LED_TYPE_PRI); +} + +static enum led_brightness accton_as4630_54npe_led_pri_get(struct led_classdev *cdev) +{ + accton_as4630_54npe_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_PRI, ledctl->reg_val[0]); +} + +static void accton_as4630_54npe_led_poe_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + accton_as4630_54npe_led_set(led_cdev, led_light_mode, LED_TYPE_POE); +} + +static enum led_brightness accton_as4630_54npe_led_poe_get(struct led_classdev *cdev) +{ + accton_as4630_54npe_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_POE, ledctl->reg_val[1]); +} + + +static void accton_as4630_54npe_led_stk1_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + accton_as4630_54npe_led_set(led_cdev, led_light_mode, LED_TYPE_STK1); +} + +static enum led_brightness accton_as4630_54npe_led_stk1_get(struct led_classdev *cdev) +{ + accton_as4630_54npe_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_STK1, ledctl->reg_val[1]); +} + +static void accton_as4630_54npe_led_stk2_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + accton_as4630_54npe_led_set(led_cdev, led_light_mode, LED_TYPE_STK2); +} + +static enum led_brightness accton_as4630_54npe_led_stk2_get(struct led_classdev *cdev) +{ + accton_as4630_54npe_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_STK2, ledctl->reg_val[1]); +} + +static void accton_as4630_54npe_led_fan_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + accton_as4630_54npe_led_set(led_cdev, led_light_mode, LED_TYPE_FAN); +} + +static enum led_brightness accton_as4630_54npe_led_fan_get(struct led_classdev *cdev) +{ + accton_as4630_54npe_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_FAN, ledctl->reg_val[1]); +} + +static void accton_as4630_54npe_led_psu1_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + accton_as4630_54npe_led_set(led_cdev, led_light_mode, LED_TYPE_PSU1); +} + +static enum led_brightness accton_as4630_54npe_led_psu1_get(struct led_classdev *cdev) +{ + accton_as4630_54npe_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_PSU1, ledctl->reg_val[0]); +} + +static void accton_as4630_54npe_led_psu2_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + accton_as4630_54npe_led_set(led_cdev, led_light_mode, LED_TYPE_PSU2); +} + +static enum led_brightness accton_as4630_54npe_led_psu2_get(struct led_classdev *cdev) +{ + accton_as4630_54npe_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_PSU2, ledctl->reg_val[1]); +} + +static struct led_classdev accton_as4630_54npe_leds[] = { + [LED_TYPE_DIAG] = { + .name = "diag", + .default_trigger = "unused", + .brightness_set = accton_as4630_54npe_led_diag_set, + .brightness_get = accton_as4630_54npe_led_diag_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_GREEN_BLINK, + }, + [LED_TYPE_PRI] = { + .name = "pri", + .default_trigger = "unused", + .brightness_set = accton_as4630_54npe_led_pri_set, + .brightness_get = accton_as4630_54npe_led_pri_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AMBER, + }, + [LED_TYPE_POE] = { + .name = "poe", + .default_trigger = "unused", + .brightness_set = accton_as4630_54npe_led_poe_set, + .brightness_get = accton_as4630_54npe_led_poe_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AMBER, + }, + [LED_TYPE_STK1] = { + .name = "stk1", + .default_trigger = "unused", + .brightness_set = accton_as4630_54npe_led_stk1_set, + .brightness_get = accton_as4630_54npe_led_stk1_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_GREEN, + }, + [LED_TYPE_STK2] = { + .name = "stk2", + .default_trigger = "unused", + .brightness_set = accton_as4630_54npe_led_stk2_set, + .brightness_get = accton_as4630_54npe_led_stk2_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_GREEN, + }, + [LED_TYPE_FAN] = { + .name = "fan", + .default_trigger = "unused", + .brightness_set = accton_as4630_54npe_led_fan_set, + .brightness_get = accton_as4630_54npe_led_fan_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_PSU1] = { + .name = "psu1", + .default_trigger = "unused", + .brightness_set = accton_as4630_54npe_led_psu1_set, + .brightness_get = accton_as4630_54npe_led_psu1_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_PSU2] = { + .name = "psu2", + .default_trigger = "unused", + .brightness_set = accton_as4630_54npe_led_psu2_set, + .brightness_get = accton_as4630_54npe_led_psu2_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, +}; + +static int accton_as4630_54npe_led_suspend(struct platform_device *dev, + pm_message_t state) +{ + int i = 0; + + for (i = 0; i < ARRAY_SIZE(accton_as4630_54npe_leds); i++) { + led_classdev_suspend(&accton_as4630_54npe_leds[i]); + } + + return 0; +} + +static int accton_as4630_54npe_led_resume(struct platform_device *dev) +{ + int i = 0; + + for (i = 0; i < ARRAY_SIZE(accton_as4630_54npe_leds); i++) { + led_classdev_resume(&accton_as4630_54npe_leds[i]); + } + + return 0; +} + +static int accton_as4630_54npe_led_probe(struct platform_device *pdev) +{ + int ret, i; + + for (i = 0; i < ARRAY_SIZE(accton_as4630_54npe_leds); i++) { + ret = led_classdev_register(&pdev->dev, &accton_as4630_54npe_leds[i]); + + if (ret < 0) + break; + } + + /* Check if all LEDs were successfully registered */ + if (i != ARRAY_SIZE(accton_as4630_54npe_leds)) { + int j; + + /* only unregister the LEDs that were successfully registered */ + for (j = 0; j < i; j++) { + led_classdev_unregister(&accton_as4630_54npe_leds[i]); + } + } + + return ret; +} + +static int accton_as4630_54npe_led_remove(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(accton_as4630_54npe_leds); i++) { + led_classdev_unregister(&accton_as4630_54npe_leds[i]); + } + + return 0; +} + +static struct platform_driver accton_as4630_54npe_led_driver = { + .probe = accton_as4630_54npe_led_probe, + .remove = accton_as4630_54npe_led_remove, + .suspend = accton_as4630_54npe_led_suspend, + .resume = accton_as4630_54npe_led_resume, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +static int __init accton_as4630_54npe_led_init(void) +{ + int ret; + + ret = platform_driver_register(&accton_as4630_54npe_led_driver); + if (ret < 0) { + goto exit; + } + + ledctl = kzalloc(sizeof(struct accton_as4630_54npe_led_data), GFP_KERNEL); + if (!ledctl) { + ret = -ENOMEM; + platform_driver_unregister(&accton_as4630_54npe_led_driver); + goto exit; + } + + mutex_init(&ledctl->update_lock); + + ledctl->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(ledctl->pdev)) { + ret = PTR_ERR(ledctl->pdev); + platform_driver_unregister(&accton_as4630_54npe_led_driver); + kfree(ledctl); + goto exit; + } + +exit: + return ret; +} + +static void __exit accton_as4630_54npe_led_exit(void) +{ + platform_device_unregister(ledctl->pdev); + platform_driver_unregister(&accton_as4630_54npe_led_driver); + kfree(ledctl); +} + +module_init(accton_as4630_54npe_led_init); +module_exit(accton_as4630_54npe_led_exit); + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("accton_as4630_54npe_led driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/modules/x86-64-accton-as4630-54npe-psu.c b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/modules/x86-64-accton-as4630-54npe-psu.c new file mode 100644 index 00000000000..43d60e855f6 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/modules/x86-64-accton-as4630-54npe-psu.c @@ -0,0 +1,332 @@ +/* + * An hwmon driver for accton as4630_54npe Power Module + * + * Copyright (C) 2014 Accton Technology Corporation. + * Brandon Chuang + * + * Based on ad7414.c + * Copyright 2006 Stefan Roese , DENX Software Engineering + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_MODEL_NAME 20 +#define MAX_SERIAL_NUMBER 19 + +static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_string(struct device *dev, struct device_attribute *da, char *buf); +static int as4630_54npe_psu_read_block(struct i2c_client *client, u8 command, u8 *data,int data_len); +extern int as4630_54npe_cpld_read(unsigned short cpld_addr, u8 reg); + +/* Addresses scanned + */ +static const unsigned short normal_i2c[] = { 0x50, 0x51, I2C_CLIENT_END }; + +/* Each client has this additional data + */ +struct as4630_54npe_psu_data { + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 index; /* PSU index */ + u8 status; /* Status(present/power_good) register read from CPLD */ + char model_name[MAX_MODEL_NAME]; /* Model name, read from eeprom */ + char serial_number[MAX_SERIAL_NUMBER]; +}; + +static struct as4630_54npe_psu_data *as4630_54npe_psu_update_device(struct device *dev); + +enum as4630_54npe_psu_sysfs_attributes { + PSU_PRESENT, + PSU_MODEL_NAME, + PSU_POWER_GOOD, + PSU_SERIAL_NUMBER +}; + +/* sysfs attributes for hwmon + */ +static SENSOR_DEVICE_ATTR(psu_present, S_IRUGO, show_status, NULL, PSU_PRESENT); +static SENSOR_DEVICE_ATTR(psu_model_name, S_IRUGO, show_string, NULL, PSU_MODEL_NAME); +static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_status, NULL, PSU_POWER_GOOD); +static SENSOR_DEVICE_ATTR(psu_serial_number, S_IRUGO, show_string, NULL, PSU_SERIAL_NUMBER); + + +static struct attribute *as4630_54npe_psu_attributes[] = { + &sensor_dev_attr_psu_present.dev_attr.attr, + &sensor_dev_attr_psu_model_name.dev_attr.attr, + &sensor_dev_attr_psu_power_good.dev_attr.attr, + &sensor_dev_attr_psu_serial_number.dev_attr.attr, + NULL +}; + +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct as4630_54npe_psu_data *data = as4630_54npe_psu_update_device(dev); + u8 status = 0; + + if (attr->index == PSU_PRESENT) { + if(data->index==0) + status = !( (data->status >> 5) & 0x1); + else + status = !( (data->status >> 1) & 0x1); + } + else { /* PSU_POWER_GOOD */ + if(data->index==0) + status = ( (data->status >> 6) & 0x1); + else + status = ( (data->status >> 2) & 0x1); + } + + return sprintf(buf, "%d\n", status); +} + +static ssize_t show_string(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct as4630_54npe_psu_data *data = as4630_54npe_psu_update_device(dev); + char *ptr = NULL; + + if (!data->valid) { + return -EIO; + } + + switch (attr->index) { + case PSU_MODEL_NAME: + ptr = data->model_name; + break; + case PSU_SERIAL_NUMBER: + ptr = data->serial_number; + break; + default: + return -EINVAL; + } + + return sprintf(buf, "%s\n", ptr); +} + +static const struct attribute_group as4630_54npe_psu_group = { + .attrs = as4630_54npe_psu_attributes, +}; + +static int as4630_54npe_psu_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + struct as4630_54npe_psu_data *data; + int status; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) { + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(struct as4630_54npe_psu_data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + data->valid = 0; + data->index = dev_id->driver_data; + mutex_init(&data->update_lock); + + dev_info(&client->dev, "chip found\n"); + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &as4630_54npe_psu_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); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &as4630_54npe_psu_group); +exit_free: + kfree(data); +exit: + + return status; +} + +static int as4630_54npe_psu_remove(struct i2c_client *client) +{ + struct as4630_54npe_psu_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &as4630_54npe_psu_group); + kfree(data); + + return 0; +} + +enum psu_index +{ + as4630_54npe_psu1, + as4630_54npe_psu2 +}; + +static const struct i2c_device_id as4630_54npe_psu_id[] = { + { "as4630_54npe_psu1", as4630_54npe_psu1 }, + { "as4630_54npe_psu2", as4630_54npe_psu2 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, as4630_54npe_psu_id); + +static struct i2c_driver as4630_54npe_psu_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "as4630_54npe_psu", + }, + .probe = as4630_54npe_psu_probe, + .remove = as4630_54npe_psu_remove, + .id_table = as4630_54npe_psu_id, + .address_list = normal_i2c, +}; + +static int as4630_54npe_psu_read_block(struct i2c_client *client, u8 command, u8 *data, + int data_len) +{ + int result = 0; + int retry_count = 5; + + while (retry_count) { + retry_count--; + + result = i2c_smbus_read_i2c_block_data(client, command, data_len, data); + + if (unlikely(result < 0)) { + msleep(10); + continue; + } + + if (unlikely(result != data_len)) { + result = -EIO; + msleep(10); + continue; + } + + result = 0; + break; + } + + return result; +} + +static struct as4630_54npe_psu_data *as4630_54npe_psu_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as4630_54npe_psu_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + int status; + int power_good = 0; + + dev_dbg(&client->dev, "Starting as4630_54npe update\n"); + + /* Read psu status */ + status = as4630_54npe_cpld_read(0x60, 0x22); + if (status < 0) { + dev_dbg(&client->dev, "cpld reg 0x60 err %d\n", status); + } + else { + data->status = status; + } + + /* Read model name */ + memset(data->model_name, 0, sizeof(data->model_name)); + memset(data->serial_number, 0, sizeof(data->serial_number)); + power_good = (data->status >> (data->index==0? 6:2)) & 0x1; + + if (power_good) { + status = as4630_54npe_psu_read_block(client, 0x20, data->model_name, + ARRAY_SIZE(data->model_name)-1); + if (status < 0) { + data->model_name[0] = '\0'; + dev_dbg(&client->dev, "unable to read model name from (0x%x)\n", client->addr); + } + else if(!strncmp(data->model_name, "YPEB1200", strlen("YPEB1200"))) + { + if (data->model_name[9]=='A' && data->model_name[10]=='M') + { + data->model_name[8]='A'; + data->model_name[9]='M'; + data->model_name[strlen("YPEB1200AM")]='\0'; + } + else + data->model_name[strlen("YPEB1200")]='\0'; + } + else + { + data->model_name[ARRAY_SIZE(data->model_name)-1] = '\0'; + } + /* Read from offset 0x35 ~ 0x46 (18 bytes) */ + status = as4630_54npe_psu_read_block(client, 0x35,data->serial_number, MAX_SERIAL_NUMBER); + if (status < 0) + { + data->serial_number[0] = '\0'; + dev_dbg(&client->dev, "unable to read model name from (0x%x) offset(0x35)\n", client->addr); + } + if (!strncmp(data->model_name, "YPEB1200AM", strlen("YPEB1200AM"))) /*for YPEB1200AM, SN length=18*/ + { + data->serial_number[MAX_SERIAL_NUMBER-1]='\0'; + } + else + data->serial_number[MAX_SERIAL_NUMBER-2]='\0'; + + } + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + +module_i2c_driver(as4630_54npe_psu_driver); + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("as4630_54npe_psu driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/modules/ym2651y.c b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/modules/ym2651y.c new file mode 120000 index 00000000000..f4d67640ccc --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/modules/ym2651y.c @@ -0,0 +1 @@ +../../common/modules/ym2651y.c \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/service/as4630-54npe-platform-handle-mgmt-interface.service b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/service/as4630-54npe-platform-handle-mgmt-interface.service new file mode 100644 index 00000000000..cf04736cd2d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/service/as4630-54npe-platform-handle-mgmt-interface.service @@ -0,0 +1,11 @@ +[Unit] +Description=Accton AS4630-54NPE Platform handle management interface service +After=sysinit.target + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/local/bin/handle_mgmt_interface.sh + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/service/as4630-54npe-platform-monitor-fan.service b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/service/as4630-54npe-platform-monitor-fan.service new file mode 100644 index 00000000000..fb6068f1ceb --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/service/as4630-54npe-platform-monitor-fan.service @@ -0,0 +1,16 @@ +[Unit] +Description=Accton AS4630-54NPE Platform Monitoring FAN service +Before=pmon.service +After=as4630-54npe-platform-monitor.service +DefaultDependencies=no + +[Service] +ExecStart=/usr/local/bin/accton_as4630_54npe_monitor_fan.py +KillSignal=SIGKILL +SuccessExitStatus=SIGKILL + +# Resource Limitations +LimitCORE=infinity + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/service/as4630-54npe-platform-monitor-psu.service b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/service/as4630-54npe-platform-monitor-psu.service new file mode 100644 index 00000000000..072d0ab7f7c --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/service/as4630-54npe-platform-monitor-psu.service @@ -0,0 +1,16 @@ +[Unit] +Description=Accton AS4630-54NPE Platform Monitoring PSU service +Before=pmon.service +After=as4630-54npe-platform-monitor.service +DefaultDependencies=no + +[Service] +ExecStart=/usr/local/bin/accton_as4630_54npe_monitor_psu.py +KillSignal=SIGKILL +SuccessExitStatus=SIGKILL + +# Resource Limitations +LimitCORE=infinity + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/service/as4630-54npe-platform-monitor.service b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/service/as4630-54npe-platform-monitor.service new file mode 100644 index 00000000000..bf5a4550a3d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/service/as4630-54npe-platform-monitor.service @@ -0,0 +1,17 @@ +[Unit] +Description=Accton AS4630-54NPE Platform Monitoring service +Before=pmon.service +After=sysinit.target +DefaultDependencies=no + +[Service] +ExecStartPre=/usr/local/bin/accton_as4630_54npe_util.py install +ExecStart=/usr/local/bin/accton_as4630_54npe_monitor.py +KillSignal=SIGKILL +SuccessExitStatus=SIGKILL + +# Resource Limitations +LimitCORE=infinity + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/setup.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/setup.py new file mode 100755 index 00000000000..4478be58ce3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/setup.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python + +import os +from setuptools import setup +os.listdir + +setup( + name='as4630_54npe', + version='1.0', + description='Module to initialize Accton AS4630-54NPE platforms', + + packages=['as4630_54npe'], + package_dir={'as4630_54npe': 'as4630-54npe/classes'}, +) diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/sonic_platform_setup.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/sonic_platform_setup.py new file mode 100644 index 00000000000..e9fc2314a75 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/sonic_platform_setup.py @@ -0,0 +1,34 @@ +from setuptools import setup + +DEVICE_NAME = 'accton' +HW_SKU = 'x86_64-accton_as4630_54npe-r0' + +setup( + name='sonic-platform', + version='1.0', + description='SONiC platform API implementation on Accton Platforms', + license='Apache 2.0', + author='SONiC Team', + author_email='linuxnetdev@microsoft.com', + url='https://github.com/Azure/sonic-buildimage', + maintainer='Jostar Yang', + maintainer_email='jostar_yang@accton.com', + packages=[ + 'sonic_platform', + ], + package_dir={ + 'sonic_platform': '../../../../device/{}/{}/sonic_platform'.format(DEVICE_NAME, HW_SKU)}, + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Environment :: Plugins', + 'Intended Audience :: Developers', + 'Intended Audience :: Information Technology', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: Apache Software License', + 'Natural Language :: English', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: Python :: 3.7', + 'Topic :: Utilities', + ], + keywords='sonic SONiC platform PLATFORM', +) diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/utils/README b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/utils/README new file mode 100644 index 00000000000..48e7b6a4750 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/utils/README @@ -0,0 +1,66 @@ +Copyright (C) 2019 Accton Networks, Inc. + +This program is free software: you can redistribute it and/or modify +It under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +All Linux kernel code is licensed under the GPLv1. All other code is +licensed under the GPLv3. Please see the LICENSE file for copies of +both licenses. + +The code for integacting with Accton AS4630-54npe has 2 parts, +kernel drivers and operational script. +The kernel drivers of peripherals are under module/ directory. +1. These drivers are at module dir. +2. A operational script, accton_as4630_util.py, for device initializatian and + peripheral accessing should be installed at /usr/bin. + Run "accton_as4630_util.py install" to install drivers. + +To initialize the system, run "accton_as4630_util.py install". +To clean up the drivers & devices, run "accton_as4630_util.py clean". +To dump information of sensors, run "accton_as4630_util.py show". +To dump SFP EEPROM, run "accton_as4630_util.py sff". +To set fan speed, run "accton_as4630_util.py set fan". +To enable/disable SFP emission, run "accton_as4630_util.py set sfp". +To set system LEDs' color, run "accton_as4630_util.py set led" +For more information, run "accton_as4630_util.py --help". + +==================================================================== +Besides applying accton_as4630_util.py to access peripherals, you can +access peripherals by sysfs nodes directly after the installation is run. + +System LED: + There are 5 system LEDs at the lower-left corner of front panel. + They are loc, diag, fan, ps1, and ps2. + The sysfs interface color mappings are as follows: + Brightness: + 0 => off + 1 => green + 2 => amber + 3 => red + 4 => blue + But not all colors are available for each LED. + +Fan Control: + There are 10 fans inside 5 fan modules. + All fans share 1 duty setting, ranged from 0~100. + +Thermal sensers: + 3 temperature sensors are controlled by the lm75 kernel modules. + +PSUs: + There 2 power supplies slot at the left/right side of the back. + Once if a PSU is not plugged, the status of it is shown failed. + +There are 48 SFP+ and 6 QSFP modules are equipped. +Before operating on PSU and QSFP+, please make sure it is well plugged. +Otherwise, operation is going to fail. diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/utils/accton_as4630_54npe_monitor.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/utils/accton_as4630_54npe_monitor.py new file mode 100755 index 00000000000..e05f96432b8 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/utils/accton_as4630_54npe_monitor.py @@ -0,0 +1,261 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -* +# Copyright (c) 2019 Edgecore Networks Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +# +# THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT +# LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS +# FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. +# +# See the Apache Version 2.0 License for specific language governing +# permissions and limitations under the License. +# +# HISTORY: +# mm/dd/yyyy (A.D.)# +# 10/24/2019:Jostar create for as4630_54npe thermal plan +# ------------------------------------------------------------------ + +try: + import sys + import getopt + import logging + import logging.config + import logging.handlers + import time + import commands + from as4630_54npe.fanutil import FanUtil + from as4630_54npe.thermalutil import ThermalUtil +except ImportError as e: + raise ImportError('%s - required module not found' % str(e)) + +# Deafults +VERSION = '1.0' +FUNCTION_NAME = '/usr/local/bin/accton_as4630_54npe_monitor' + + +# Temperature Policy +# If any fan fail , please set fan speed register to 16 +# The max value of fan speed register is 14 +# LM77(48)+LM75(4B)+LM75(4A) > 140, Set 10 +# LM77(48)+LM75(4B)+LM75(4A) > 150, Set 12 +# LM77(48)+LM75(4B)+LM75(4A) > 160, Set 14 +# LM77(48)+LM75(4B)+LM75(4A) < 140, Set 8 +# LM77(48)+LM75(4B)+LM75(4A) < 150, Set 10 +# LM77(48)+LM75(4B)+LM75(4A) < 160, Set 12 +# Reset DUT:LM77(48)>=70C +# +class switch(object): + def __init__(self, value): + self.value = value + self.fall = False + + def __iter__(self): + """Return the match method once, then stop""" + yield self.match + raise StopIteration + + def match(self, *args): + """Indicate whether or not to enter a case suite""" + if self.fall or not args: + return True + elif self.value in args: # changed for v1.5, see below + self.fall = True + return True + else: + return False + + +fan_policy_state = 0 +fan_fail = 0 +alarm_state = 0 # 0->default or clear, 1-->alarm detect +test_temp = 0 +test_temp_list = [0, 0, 0] +temp_test_data = 0 +test_temp_revert = 0 +# Make a class we can use to capture stdout and sterr in the log + + +class device_monitor(object): + # static temp var + temp = 0 + new_pwm = 0 + pwm = 0 + ori_pwm = 0 + default_pwm = 0x4 + + def __init__(self, log_file, log_level): + """Needs a logger and a logger level.""" + # set up logging to file + logging.basicConfig( + filename=log_file, + filemode='w', + level=log_level, + format='[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s', + datefmt='%H:%M:%S') + # set up logging to console + if log_level == logging.DEBUG: + console = logging.StreamHandler() + console.setLevel(log_level) + formatter = logging.Formatter( + '%(name)-12s: %(levelname)-8s %(message)s') + console.setFormatter(formatter) + logging.getLogger('').addHandler(console) + + sys_handler = logging.handlers.SysLogHandler( + address='/dev/log') + sys_handler.setLevel(logging.WARNING) + logging.getLogger('').addHandler(sys_handler) + + def get_state_from_fan_policy(self, temp, policy): + state = 0 + for i in range(0, len(policy)): + if (temp > policy[i][2]): # temp_down + if temp <= policy[i][3]: # temp_up + state = i + + return state + + def manage_fans(self): + global fan_policy_state + global fan_fail + global test_temp + global test_temp_list + global alarm_state + global temp_test_data + global test_temp_revert + LEVEL_FAN_MIN = 0 + LEVEL_FAN_NORMAL = 1 + LEVEL_FAN_MID = 2 + LEVEL_FAN_HIGH = 3 + LEVEL_TEMP_CRITICAL = 4 + fan_policy = { + LEVEL_FAN_MIN: [50, 8, 0, 140000], + LEVEL_FAN_NORMAL: [62, 10, 140000, 150000], + LEVEL_FAN_MID: [75, 12, 150000, 160000], + LEVEL_FAN_HIGH: [88, 14, 160000, 240000], + LEVEL_TEMP_CRITICAL: [100, 16, 240000, 300000], + } + temp = [0, 0, 0] + thermal = ThermalUtil() + fan = FanUtil() + ori_duty_cycle = fan.get_fan_duty_cycle() + new_duty_cycle = 0 + + if test_temp == 0: + for i in range(0, 3): + temp[i] = thermal._get_thermal_val(i + 1) + if temp[i] == 0 or temp[i] is None: + logging.warning("Get temp-%d fail", i) + return False + else: + if test_temp_revert == 0: + temp_test_data = temp_test_data + 2000 + else: + temp_test_data = temp_test_data - 2000 + + for i in range(0, 3): + temp[i] = test_temp_list[i] + temp_test_data + fan_fail = 0 + + temp_val = 0 + for i in range(0, 3): + if temp[i] is None: + break + temp_val += temp[i] + + # Check Fan status + for i in range(fan.FAN_NUM_1_IDX, fan.FAN_NUM_ON_MAIN_BROAD + 1): + if fan.get_fan_status(i) == 0: + new_pwm = 100 + logging.warning('Fan_%d fail, set pwm to 100', i) + if test_temp == 0: + fan_fail = 1 + fan.set_fan_duty_cycle(new_pwm) + break + else: + fan_fail = 0 + + ori_state = fan_policy_state + fan_policy_state = self.get_state_from_fan_policy(temp_val, fan_policy) + + if fan_policy_state > LEVEL_TEMP_CRITICAL or fan_policy_state < LEVEL_FAN_MIN: + logging.error("Get error fan current_state\n") + return 0 + + # Decision : Decide new fan pwm percent. + if fan_fail == 0 and ori_duty_cycle != fan_policy[fan_policy_state][0]: + new_duty_cycle = fan_policy[fan_policy_state][0] + fan.set_fan_duty_cycle(new_duty_cycle) + + if temp[0] >= 70000: # LM75-48 + # critical case*/ + logging.critical( + 'Alarm-Critical for temperature critical is detected, reset DUT') + cmd_str = "i2cset -y -f 3 0x60 0x4 0xE4" + time.sleep(2) + commands.getstatusoutput(cmd_str) + + #logging.debug('ori_state=%d, current_state=%d, temp_val=%d\n\n',ori_state, fan_policy_state, temp_val) + + if ori_state < LEVEL_FAN_HIGH: + if fan_policy_state >= LEVEL_FAN_HIGH: + if alarm_state == 0: + logging.warning('Alarm for temperature high is detected') + alarm_state = 1 + + if fan_policy_state < LEVEL_FAN_MID: + if alarm_state == 1: + logging.info('Alarm for temperature high is cleared') + alarm_state = 0 + + return True + + +def main(argv): + log_file = '%s.log' % FUNCTION_NAME + log_level = logging.INFO + global test_temp + if len(sys.argv) != 1: + try: + opts, args = getopt.getopt(argv, 'hdlt:', ['lfile=']) + except getopt.GetoptError: + print 'Usage: %s [-d] [-l ]' % sys.argv[0] + return 0 + for opt, arg in opts: + if opt == '-h': + print 'Usage: %s [-d] [-l ]' % sys.argv[0] + return 0 + elif opt in ('-d', '--debug'): + log_level = logging.DEBUG + elif opt in ('-l', '--lfile'): + log_file = arg + + if sys.argv[1] == '-t': + if len(sys.argv) != 5: + print "temp test, need input three temp" + return 0 + + i = 0 + for x in range(2, 5): + test_temp_list[i] = int(sys.argv[x]) * 1000 + i = i + 1 + test_temp = 1 + log_level = logging.DEBUG + print test_temp_list + + fan = FanUtil() + fan.set_fan_duty_cycle(50) + print "set default fan speed to 50%" + monitor = device_monitor(log_file, log_level) + # Loop forever, doing something useful hopefully: + while True: + monitor.manage_fans() + time.sleep(10) # 10sec + + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/utils/accton_as4630_54npe_monitor_fan.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/utils/accton_as4630_54npe_monitor_fan.py new file mode 100755 index 00000000000..806af197ec5 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/utils/accton_as4630_54npe_monitor_fan.py @@ -0,0 +1,186 @@ +#!/usr/bin/env python +# +# Copyright (C) 2018 Accton Technology Corporation +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# ------------------------------------------------------------------ +# HISTORY: +# mm/dd/yyyy (A.D.) +# 5/15/2019: Jostar create for as4630-54npe +# ------------------------------------------------------------------ + +try: + import sys + import getopt + import logging + import logging.config + import logging.handlers + import time # this is only being used as part of the example + +except ImportError as e: + raise ImportError('%s - required module not found' % str(e)) + +# Deafults +VERSION = '1.0' +FUNCTION_NAME = '/usr/local/bin/accton_as4630_54npe_monitor_fan' + + +class switch(object): + def __init__(self, value): + self.value = value + self.fall = False + + def __iter__(self): + """Return the match method once, then stop""" + yield self.match + raise StopIteration + + def match(self, *args): + """Indicate whether or not to enter a case suite""" + if self.fall or not args: + return True + elif self.value in args: # changed for v1.5, see below + self.fall = True + return True + else: + return False + + +fan_state = [2, 2, 2, 2] # init state=2, insert=1, remove=0 +fan_status_state = [2, 2, 2, 2] # init state=2, fault=1, normal=0 +# Make a class we can use to capture stdout and sterr in the log + + +class device_monitor(object): + + def __init__(self, log_file, log_level): + + self.fan_num = 3 + self.fan_path = "/sys/bus/i2c/devices/3-0060/" + self.present = { + 0: "fan_present_1", + 1: "fan_present_2", + 2: "fan_present_3", + } + + self.fault = { + 0: "fan_fault_1", + 1: "fan_fault_2", + 2: "fan_fault_3", + } + + """Needs a logger and a logger level.""" + # set up logging to file + logging.basicConfig( + filename=log_file, + filemode='w', + level=log_level, + format='[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s', + datefmt='%H:%M:%S') + + # set up logging to console + if log_level == logging.DEBUG: + console = logging.StreamHandler() + console.setLevel(logging.DEBUG) + formatter = logging.Formatter( + '%(name)-12s: %(levelname)-8s %(message)s') + console.setFormatter(formatter) + logging.getLogger('').addHandler(console) + + sys_handler = logging.handlers.SysLogHandler(address='/dev/log') + # sys_handler.setLevel(logging.WARNING) + sys_handler.setLevel(logging.INFO) + logging.getLogger('').addHandler(sys_handler) + + #logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level) + + def manage_fan(self): + + FAN_STATE_REMOVE = 0 + FAN_STATE_INSERT = 1 + + FAN_STATUS_FAULT = 1 + FAN_STATUS_NORMAL = 0 + + global fan_state + global fan_status_state + + for idx in range(0, self.fan_num): + node = self.fan_path + self.present[idx] + try: + val_file = open(node) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + content = val_file.readline().rstrip() + val_file.close() + # content is a string, either "0" or "1" + if content == "1": + if fan_state[idx] != 1: + fan_state[idx] = FAN_STATE_INSERT + logging.info("FAN-%d present is detected", idx + 1) + else: + if fan_state[idx] != 0: + fan_state[idx] = FAN_STATE_REMOVE + logging.warning( + "Alarm for FAN-%d absent is detected", idx + 1) + + for idx in range(0, self.fan_num): + node = self.fan_path + self.fault[idx] + try: + val_file = open(node) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + content = val_file.readline().rstrip() + val_file.close() + # content is a string, either "0" or "1" + if content == "1": + if fan_status_state[idx] != FAN_STATUS_FAULT: + if fan_state[idx] == FAN_STATE_INSERT: + logging.warning( + "Alarm for FAN-%d failed is detected", idx + 1) + fan_status_state[idx] = FAN_STATUS_FAULT + else: + fan_status_state[idx] = FAN_STATUS_NORMAL + + return True + + +def main(argv): + log_file = '%s.log' % FUNCTION_NAME + log_level = logging.INFO + if len(sys.argv) != 1: + try: + opts, args = getopt.getopt(argv, 'hdl:', ['lfile=']) + except getopt.GetoptError: + print 'Usage: %s [-d] [-l ]' % sys.argv[0] + return 0 + for opt, arg in opts: + if opt == '-h': + print 'Usage: %s [-d] [-l ]' % sys.argv[0] + return 0 + elif opt in ('-d', '--debug'): + log_level = logging.DEBUG + elif opt in ('-l', '--lfile'): + log_file = arg + monitor = device_monitor(log_file, log_level) + while True: + monitor.manage_fan() + time.sleep(3) + + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/utils/accton_as4630_54npe_monitor_psu.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/utils/accton_as4630_54npe_monitor_psu.py new file mode 100755 index 00000000000..6646709e04e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/utils/accton_as4630_54npe_monitor_psu.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python +# +# Copyright (C) 2018 Accton Technology Corporation +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# ------------------------------------------------------------------ +# HISTORY: +# mm/dd/yyyy (A.D.) +# 5/15/2019: Jostar create for as4630-54npe +# ------------------------------------------------------------------ + +try: + import sys + import getopt + import logging + import logging.config + import logging.handlers + import time # this is only being used as part of the example +except ImportError as e: + raise ImportError('%s - required module not found' % str(e)) + +# Deafults +VERSION = '1.0' +FUNCTION_NAME = '/usr/local/bin/accton_as4630_54npe_monitor_psu' + + +psu_state = [2, 2] +psu_status_state = [2, 2] +# Make a class we can use to capture stdout and sterr in the log + + +class device_monitor(object): + + def __init__(self, log_file, log_level): + + self.psu_num = 2 + self.psu_path = "/sys/bus/i2c/devices/" + self.presence = "/psu_present" + self.oper_status = "/psu_power_good" + self.mapping = { + 0: "10-0050", + 1: "11-0051", + } + + """Needs a logger and a logger level.""" + # set up logging to file + logging.basicConfig( + filename=log_file, + filemode='w', + level=log_level, + format='[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s', + datefmt='%H:%M:%S') + # set up logging to console + + if log_level == logging.DEBUG: + console = logging.StreamHandler() + console.setLevel(log_level) + formatter = logging.Formatter( + '%(name)-12s: %(levelname)-8s %(message)s') + console.setFormatter(formatter) + logging.getLogger('').addHandler(console) + + sys_handler = logging.handlers.SysLogHandler(address='/dev/log') + # sys_handler.setLevel(logging.WARNING) + sys_handler.setLevel(logging.INFO) + logging.getLogger('').addHandler(sys_handler) + + #logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level) + + def manage_psu(self): + + PSU_STATE_REMOVE = 0 + PSU_STATE_INSERT = 1 + + PSU_STATUS_NO_POWER = 0 + PSU_STATUS_POWER_GOOD = 1 + PSU_STATUS_IDLE = 2 + + global psu_state + + for idx in range(0, self.psu_num): + node = self.psu_path + self.mapping[idx] + self.presence + try: + val_file = open(node) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + content = val_file.readline().rstrip() + val_file.close() + # content is a string, either "0" or "1" + if content == "1": + if psu_state[idx] != 1: + psu_state[idx] = PSU_STATE_INSERT + logging.info("PSU-%d present is detected", idx + 1) + # psu_status_state[idx]=PSU_STATUS_POWER_GOOD #when insert, + # assume power is good. If no_power, next code will find + # it. + else: + if psu_state[idx] != 0: + psu_state[idx] = PSU_STATE_REMOVE + logging.warning( + "Alarm for PSU-%d absent is detected", idx + 1) + psu_status_state[idx] = PSU_STATUS_IDLE + + for idx in range(0, self.psu_num): + node = self.psu_path + self.mapping[idx] + self.oper_status + try: + val_file = open(node) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + content = val_file.readline().rstrip() + val_file.close() + # content is a string, either "0" or "1" + if content == "0": + if psu_status_state[idx] != PSU_STATUS_NO_POWER: + if psu_state[idx] == PSU_STATE_INSERT: + logging.warning( + "Alarm for PSU-%d failed is detected", idx + 1) + psu_status_state[idx] = PSU_STATUS_NO_POWER + else: + if psu_state[idx] == PSU_STATE_INSERT: + if psu_status_state[idx] != PSU_STATUS_POWER_GOOD: + logging.info("PSU-%d power_good is detected", idx + 1) + psu_status_state[idx] = PSU_STATUS_POWER_GOOD + + return True + + +def main(argv): + log_file = '%s.log' % FUNCTION_NAME + log_level = logging.INFO + if len(sys.argv) != 1: + try: + opts, args = getopt.getopt(argv, 'hdl:', ['lfile=']) + except getopt.GetoptError: + print 'Usage: %s [-d] [-l ]' % sys.argv[0] + return 0 + for opt, arg in opts: + if opt == '-h': + print 'Usage: %s [-d] [-l ]' % sys.argv[0] + return 0 + elif opt in ('-d', '--debug'): + log_level = logging.DEBUG + elif opt in ('-l', '--lfile'): + log_file = arg + monitor = device_monitor(log_file, log_level) + # Loop forever, doing something useful hopefully: + while True: + monitor.manage_psu() + time.sleep(3) + + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/utils/accton_as4630_54npe_util.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/utils/accton_as4630_54npe_util.py new file mode 100755 index 00000000000..c83b772c5a3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/utils/accton_as4630_54npe_util.py @@ -0,0 +1,388 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2016 Accton Networks, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +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 +""" +import subprocess +import getopt +import sys +import logging +import time +import os + +PROJECT_NAME = 'as4630_54npe' +version = '0.0.1' +verbose = False +DEBUG = False +args = [] +ALL_DEVICE = {} + +i2c_prefix = '/sys/bus/i2c/devices/' +''' +i2c_bus = {'fan': ['54-0066'], + 'thermal': ['54-004c', '55-0048', '55-0049', '55-004a', '55-004b'], + 'psu': ['49-0050', '50-0053'], + 'sfp': ['-0050']} +i2c_nodes = {'fan': ['present', 'front_speed_rpm', 'rear_speed_rpm'], + 'thermal': ['hwmon/hwmon*/temp1_input'], + 'psu': ['psu_present ', 'psu_power_good'], + 'sfp': ['module_present_ ', 'module_tx_disable_']} +''' +sfp_map = [18, 19, 20, 21, 22, 23] + +mknod = [ + 'echo pca9548 0x77 > /sys/bus/i2c/devices/i2c-1/new_device', + 'echo pca9548 0x71 > /sys/bus/i2c/devices/i2c-2/new_device', + 'echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-3/new_device', + + 'echo as4630_54npe_cpld 0x60 > /sys/bus/i2c/devices/i2c-3/new_device', + + 'echo lm77 0x48 > /sys/bus/i2c/devices/i2c-14/new_device', + 'echo lm75 0x4a > /sys/bus/i2c/devices/i2c-25/new_device', + 'echo lm75 0x4b > /sys/bus/i2c/devices/i2c-24/new_device', + + + # PSU-1 + 'echo as4630_54npe_psu1 0x50 > /sys/bus/i2c/devices/i2c-10/new_device', + 'echo ype1200am 0x58 > /sys/bus/i2c/devices/i2c-10/new_device', + + # PSU-2 + 'echo as4630_54npe_psu2 0x51> /sys/bus/i2c/devices/i2c-11/new_device', + 'echo ype1200am 0x59 > /sys/bus/i2c/devices/i2c-11/new_device', + + # EERPOM + 'echo 24c02 0x57 > /sys/bus/i2c/devices/i2c-1/new_device', +] + +# Disable CPLD debug mode +cpld_set = [ + 'i2cset -y -f 3 0x60 0x2a 0xff', + 'i2cset -y -f 3 0x60 0x2b 0xff', + 'i2cset -y -f 3 0x60 0x86 0x89' +] + +FORCE = 0 +logging.basicConfig(filename= PROJECT_NAME+'.log', filemode='w',level=logging.DEBUG) +logging.basicConfig(level=logging.INFO) + + +if DEBUG == True: + print(sys.argv[0]) + print('ARGV :', sys.argv[1:]) + + +def main(): + global DEBUG + global args + global FORCE + + 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)) + + 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: + print("TEST") + logging.info('no option') + for arg in args: + if arg == 'install': + do_install() + elif arg == 'clean': + do_uninstall() + elif arg == 'api': + do_sonic_platform_install() + elif arg == 'api_clean': + do_sonic_platform_clean() + 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("[ACCTON DBG]: ",txt) + return + +def log_os_system(cmd, show): + logging.info('Run :' + cmd) + output = "" + status, output = subprocess.getstatusoutput(cmd) + my_log(cmd +" with result:" + str(status)) + #my_log ("cmd:" + cmd) + #my_log (" output:"+output) + if status: + logging.info('Failed :'+cmd) + if show: + print('Failed :'+cmd) + return status, output + +def driver_inserted(): + ret, lsmod = log_os_system("ls /sys/module/*accton*", 0) + logging.info('mods:'+lsmod) + if ret : + return False + else : + return True + +#'modprobe cpr_4011_4mxx', + +kos = [ + 'depmod -ae', + 'modprobe i2c_dev', + 'modprobe i2c_mux_pca954x', + 'modprobe ym2651y', + 'modprobe x86_64_accton_as4630_54npe_cpld', + 'modprobe x86_64_accton_as4630_54npe_leds', + 'modprobe x86_64_accton_as4630_54npe_psu', + 'modprobe optoe'] + +def driver_install(): + global FORCE + + log_os_system("lsmod|grep i2c_ismt", 1) + my_log("rmmond i2cismt") + log_os_system("rmmod i2c_ismt", 1) + log_os_system("rmmod i2c_i801", 1) + log_os_system("modprobe i2c-i801", 1) + time.sleep(1) + log_os_system("modprobe i2c-ismt", 1) + + + for i in range(0, len(kos)): + status, output = log_os_system(kos[i], 1) + if status: + if FORCE == 0: + return status + + print("Done driver_install") + + return 0 + +def driver_uninstall(): + global FORCE + for i in range(0, len(kos)): + rm = kos[-(i + 1)].replace("modprobe", "modprobe -rq") + lst = rm.split(" ") + + if len(lst) > 3: + del(lst[3]) + rm = " ".join(lst) + status, output = log_os_system(rm, 1) + if status: + if FORCE == 0: + return status + return 0 + +def device_install(): + global FORCE + + for i in range(0, len(mknod)): + # for pca954x need times to built new i2c buses + if mknod[i].find('pca954') != -1: + time.sleep(2) + + status, output = log_os_system(mknod[i], 1) + if status: + print(output) + if FORCE == 0: + return status + + # set all pca954x idle_disconnect + cmd = 'echo -2 | tee /sys/bus/i2c/drivers/pca954x/*-00*/idle_state' + status, output = log_os_system(cmd, 1) + if status: + print(output) + if FORCE == 0: + return status + + for i in range(0, len(sfp_map)): + if(i < 4): + opt = 'optoe2' + else: + opt = 'optoe1' + status, output = log_os_system("echo " + str(opt) + " 0x50 > /sys/bus/i2c/devices/i2c-" + + str(sfp_map[i]) + "/new_device", 1) + if status: + print(output) + if FORCE == 0: + return status + + status, output = log_os_system("echo port" + str(i + 49) +" > /sys/bus/i2c/devices/" + + str(sfp_map[i]) + "-0050/port_name", 1) + if status: + print(output) + if FORCE == 0: + return status + + print("Done device_install") + + return + +def device_uninstall(): + global FORCE + + for i in range(0, len(sfp_map)): + target = "/sys/bus/i2c/devices/i2c-" + str(sfp_map[i]) + "/delete_device" + status, output = log_os_system("echo 0x50 > " + target, 1) + if status: + print(output) + if FORCE == 0: + return status + + nodelist = mknod + + for i in range(len(nodelist)): + target = nodelist[-(i+1)] + temp = target.split() + del temp[1] + temp[-1] = temp[-1].replace('new_device', 'delete_device') + status, output = log_os_system(" ".join(temp), 1) + if status: + print(output) + if FORCE == 0: + return status + + return + +def system_ready(): + if driver_inserted() == False: + return False + if not device_exist(): + print("not device_exist()") + return False + return True + +PLATFORM_ROOT_PATH = '/usr/share/sonic/device' +PLATFORM_API2_WHL_FILE_PY3 ='sonic_platform-1.0-py3-none-any.whl' +def do_sonic_platform_install(): + device_path = "{}{}{}{}".format(PLATFORM_ROOT_PATH, '/x86_64-accton_', PROJECT_NAME, '-r0') + SONIC_PLATFORM_BSP_WHL_PKG_PY3 = "/".join([device_path, PLATFORM_API2_WHL_FILE_PY3]) + + #Check API2.0 on py whl file + status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0) + if status: + if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_PY3): + status, output = log_os_system("pip3 install "+ SONIC_PLATFORM_BSP_WHL_PKG_PY3, 1) + if status: + print("Error: Failed to install {}".format(PLATFORM_API2_WHL_FILE_PY3)) + return status + else: + print("Successfully installed {} package".format(PLATFORM_API2_WHL_FILE_PY3)) + else: + print('{} is not found'.format(PLATFORM_API2_WHL_FILE_PY3)) + else: + print('{} has installed'.format(PLATFORM_API2_WHL_FILE_PY3)) + + return + +def do_sonic_platform_clean(): + status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0) + if status: + print('{} does not install, not need to uninstall'.format(PLATFORM_API2_WHL_FILE_PY3)) + + else: + status, output = log_os_system("pip3 uninstall sonic-platform -y", 0) + if status: + print('Error: Failed to uninstall {}'.format(PLATFORM_API2_WHL_FILE_PY3)) + return status + else: + print('{} is uninstalled'.format(PLATFORM_API2_WHL_FILE_PY3)) + + + return + +def do_install(): + if driver_inserted() == False: + status = driver_install() + if status: + if FORCE == 0: + return status + else: + print(PROJECT_NAME.upper()+" drivers detected....") + if not device_exist(): + status = device_install() + if status: + if FORCE == 0: + return status + else: + print(PROJECT_NAME.upper()+" devices detected....") + + for i in range(len(cpld_set)): + status, output = log_os_system(cpld_set[i], 1) + if status: + if FORCE == 0: + return status + + do_sonic_platform_install() + return + +def do_uninstall(): + if not device_exist(): + print(PROJECT_NAME.upper() + " has no device installed....") + else: + print("Removing device....") + status = device_uninstall() + if status: + if FORCE == 0: + return status + + if driver_inserted() == False : + print(PROJECT_NAME.upper() + " has no driver installed....") + else: + print("Removing installed driver....") + status = driver_uninstall() + if status: + if FORCE == 0: + return status + + do_sonic_platform_clean() + return + +def device_exist(): + ret1, log = log_os_system("ls "+i2c_prefix+"*0077", 0) + ret2, log = log_os_system("ls "+i2c_prefix+"i2c-2", 0) + return not(ret1 or ret2) + +if __name__ == "__main__": + main() diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/utils/handle_mgmt_interface.sh b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/utils/handle_mgmt_interface.sh new file mode 100755 index 00000000000..52ff6935482 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54npe/utils/handle_mgmt_interface.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +#Due to the hardware design, as4630-54npe use "eth2" instead of "eth0" as management interface. +#Rename netdev "eth0" and "eth2" to swap original "eth2" to "eth0". +ifconfig eth0 down +ip link set eth0 name eth3 +ip link set eth2 name eth0 +ifconfig eth0 up diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/x86-64-accton-as4630-54pe-cpld.c b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/x86-64-accton-as4630-54pe-cpld.c index f7a438feed7..92cc3142b7e 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/x86-64-accton-as4630-54pe-cpld.c +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/x86-64-accton-as4630-54pe-cpld.c @@ -571,11 +571,11 @@ static ssize_t set_duty_cycle(struct device *dev, struct device_attribute *da, static u8 reg_val_to_direction(u8 reg_val, enum fan_id id) { - u8 mask = (1 << id); + u8 mask = (1 << (id+4)); reg_val &= mask; - return reg_val ? 1 : 0; + return reg_val ? 0 : 1; } static u8 reg_val_to_is_present(u8 reg_val, enum fan_id id) diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/x86-64-accton-as4630-54pe-leds.c b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/x86-64-accton-as4630-54pe-leds.c old mode 100755 new mode 100644 index 34c22fd82aa..e758dd5cc47 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/x86-64-accton-as4630-54pe-leds.c +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/x86-64-accton-as4630-54pe-leds.c @@ -64,7 +64,7 @@ static struct accton_as4630_54pe_led_data *ledctl = NULL; #define LED_TYPE_POE_REG_MASK (0x2|0x1) #define LED_MODE_POE_GREEN_VALUE 0x1 #define LED_MODE_POE_AMBER_VALUE 0x2 -#define LED_MODE_POE_OFF_VALUE 0x0 +#define LED_MODE_POE_OFF_VALUE 0x3 #define LED_TYPE_STK1_REG_MASK 0x20 #define LED_MODE_STK1_GREEN_VALUE 0x0 @@ -74,20 +74,20 @@ static struct accton_as4630_54pe_led_data *ledctl = NULL; #define LED_MODE_STK2_GREEN_VALUE 0x0 #define LED_MODE_STK2_OFF_VALUE 0x10 -#define LED_TYPE_FAN_REG_MASK (0x20|0x10) -#define LED_MODE_FAN_AMBER_VALUE 0x20 -#define LED_MODE_FAN_GREEN_VALUE 0x10 -#define LED_MODE_FAN_OFF_VALUE (0x0) +#define LED_TYPE_FAN_REG_MASK (0x8|0x4) +#define LED_MODE_FAN_AMBER_VALUE 0x8 +#define LED_MODE_FAN_GREEN_VALUE 0x4 +#define LED_MODE_FAN_OFF_VALUE (0xC) -#define LED_TYPE_PSU2_REG_MASK (0x8|0x4) -#define LED_MODE_PSU2_AMBER_VALUE 0x8 -#define LED_MODE_PSU2_GREEN_VALUE 0x4 -#define LED_MODE_PSU2_OFF_VALUE (0x0) +#define LED_TYPE_PSU2_REG_MASK (0x80|0x40) +#define LED_MODE_PSU2_AMBER_VALUE 0x80 +#define LED_MODE_PSU2_GREEN_VALUE 0x40 +#define LED_MODE_PSU2_OFF_VALUE (0xC0) #define LED_TYPE_PSU1_REG_MASK (0x2|0x1) #define LED_MODE_PSU1_AMBER_VALUE 0x2 #define LED_MODE_PSU1_GREEN_VALUE 0x1 -#define LED_MODE_PSU1_OFF_VALUE (0x0) +#define LED_MODE_PSU1_OFF_VALUE (0x3) enum led_type { LED_TYPE_DIAG, @@ -106,8 +106,8 @@ struct led_reg { }; static const struct led_reg led_reg_map[] = { - {(1<reg_val[0]); + return led_reg_val_to_light_mode(LED_TYPE_FAN, ledctl->reg_val[1]); } static void accton_as4630_54pe_led_psu1_set(struct led_classdev *led_cdev, @@ -395,7 +395,7 @@ static void accton_as4630_54pe_led_psu2_set(struct led_classdev *led_cdev, static enum led_brightness accton_as4630_54pe_led_psu2_get(struct led_classdev *cdev) { accton_as4630_54pe_led_update(); - return led_reg_val_to_light_mode(LED_TYPE_PSU2, ledctl->reg_val[0]); + return led_reg_val_to_light_mode(LED_TYPE_PSU2, ledctl->reg_val[1]); } static struct led_classdev accton_as4630_54pe_leds[] = { @@ -405,7 +405,7 @@ static struct led_classdev accton_as4630_54pe_leds[] = { .brightness_set = accton_as4630_54pe_led_diag_set, .brightness_get = accton_as4630_54pe_led_diag_get, .flags = LED_CORE_SUSPENDRESUME, - .max_brightness = LED_MODE_GREEN, + .max_brightness = LED_MODE_GREEN_BLINK, }, [LED_TYPE_PRI] = { .name = "pri", diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/x86-64-accton-as4630-54pe-psu.c b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/x86-64-accton-as4630-54pe-psu.c index 3d197210e35..edcbc265856 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/x86-64-accton-as4630-54pe-psu.c +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/x86-64-accton-as4630-54pe-psu.c @@ -276,7 +276,7 @@ static struct as4630_54pe_psu_data *as4630_54pe_psu_update_device(struct device /* Read model name */ memset(data->model_name, 0, sizeof(data->model_name)); memset(data->serial_number, 0, sizeof(data->serial_number)); - power_good = (data->status >> (3-data->index) & 0x1); + power_good = (data->status >> (data->index==0? 6:2)) & 0x1; if (power_good) { status = as4630_54pe_psu_read_block(client, 0x20, data->model_name, diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/service/as4630-54pe-pddf-platform-monitor.service b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/service/as4630-54pe-pddf-platform-monitor.service new file mode 100644 index 00000000000..99bca2684f4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/service/as4630-54pe-pddf-platform-monitor.service @@ -0,0 +1,16 @@ +[Unit] +Description=Accton AS4630-54PE Platform Monitoring service +Before=pmon.service +After=pddf-platform-init.service +DefaultDependencies=no + +[Service] +ExecStart=/usr/local/bin/accton_as4630_54pe_pddf_monitor.py +KillSignal=SIGKILL +SuccessExitStatus=SIGKILL + +# Resource Limitations +LimitCORE=infinity + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/service/pddf-platform-init.service b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/service/pddf-platform-init.service new file mode 120000 index 00000000000..0fd9f25b6c5 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/service/pddf-platform-init.service @@ -0,0 +1 @@ +../../../../pddf/i2c/service/pddf-platform-init.service \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/__init__.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/__init__.py new file mode 100644 index 00000000000..f0201e71779 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/__init__.py @@ -0,0 +1,3 @@ +# All the derived classes for PDDF +__all__ = ["platform", "chassis", "sfp", "psu", "thermal"] +from . import platform diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/chassis.py new file mode 100644 index 00000000000..1dfca24ab32 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/chassis.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python + +############################################################################# +# PDDF +# Module contains an implementation of SONiC Chassis API +# +############################################################################# + +try: + import sys + from sonic_platform_pddf_base.pddf_chassis import PddfChassis + from .event import SfpEvent +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +NUM_COMPONENT = 2 + +class Chassis(PddfChassis): + """ + PDDF Platform-specific Chassis class + """ + + SYSLED_DEV_NAME = "SYS_LED" + + def __init__(self, pddf_data=None, pddf_plugin_data=None): + PddfChassis.__init__(self, pddf_data, pddf_plugin_data) + self.__initialize_components() + self._sfpevent = SfpEvent(self.get_all_sfps()) + + def __initialize_components(self): + from sonic_platform.component import Component + for index in range(NUM_COMPONENT): + component = Component(index) + self._component_list.append(component) + + # Provide the functions/variables below for which implementation is to be overwritten + def get_change_event(self, timeout=0): + return self._sfpevent.get_sfp_event(timeout) + + def get_sfp(self, index): + """ + Retrieves sfp represented by (1-based) index + + Args: + index: An integer, the index (1-based) of the sfp to retrieve. + The index should be the sequence of a physical port in a chassis, + starting from 1. + For example, 1 for Ethernet0, 2 for Ethernet4 and so on. + + Returns: + An object derived from SfpBase representing the specified sfp + """ + sfp = None + + try: + # The index will start from 1 + sfp = self._sfp_list[index-1] + except IndexError: + sys.stderr.write("SFP index {} out of range (1-{})\n".format( + index, len(self._sfp_list))) + return sfp + + def initizalize_system_led(self): + return + + def get_status_led(self): + return self.get_system_led(self.SYSLED_DEV_NAME) + + def set_status_led(self, color): + return self.set_system_led(self.SYSLED_DEV_NAME, color) diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/component.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/component.py new file mode 100644 index 00000000000..22696341523 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/component.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python + +############################################################################# +# +# Module contains an implementation of SONiC Platform Base API and +# provides the component information (such as CPLD, FPGA, BIOS etc) which are available in the platform +# +############################################################################# + +try: + import subprocess + from sonic_platform_base.component_base import ComponentBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version" +#COMPONENT_NAME_LIST = ["CPLD1"] +COMPONENT_LIST = [ + ("CPLD1", "CPLD 1"), + ("BIOS", "Basic Input/Output System") +] + +class Component(ComponentBase): + """Platform-specific Component class""" + + + def __init__(self, component_index): + self.index = component_index + self.name = self.get_name() + self.cpld_mapping = { + 0: ['3', '0x60'] + } + + + def get_name(self): + """ + Retrieves the name of the component + Returns: + A string containing the name of the component + """ + return COMPONENT_LIST[self.index][0] + + def get_description(self): + """ + Retrieves the description of the component + Returns: + A string containing the description of the component + """ + return COMPONENT_LIST[self.index][1] + + def __get_bios_version(self): + # Retrieves the BIOS firmware version + try: + with open(BIOS_VERSION_PATH, 'r') as fd: + bios_version = fd.read() + return bios_version.strip() + except Exception as e: + return None + + def get_firmware_version(self): + """ + Retrieves the firmware version of module + Returns: + string: The firmware versions of the module + """ + fw_version = None + if self.name == "BIOS": + fw_version = self.__get_bios_version() + elif "CPLD" in self.name: + cmd = "i2cget -f -y {0} {1} 0x1".format(self.cpld_mapping[self.index][0], self.cpld_mapping[self.index][1]) + status, value = subprocess.getstatusoutput(cmd) + if not status: + fw_version = value.rstrip() + + return fw_version + + def install_firmware(self, image_path): + """ + Install firmware to module + Args: + image_path: A string, path to firmware image + Returns: + A boolean, True if install successfully, False if not + """ + raise NotImplementedError diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/eeprom.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/eeprom.py new file mode 100644 index 00000000000..a87ecc9f6fe --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/eeprom.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python + +try: + from sonic_platform_pddf_base.pddf_eeprom import PddfEeprom +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Eeprom(PddfEeprom): + + def __init__(self, pddf_data=None, pddf_plugin_data=None): + PddfEeprom.__init__(self, pddf_data, pddf_plugin_data) + + # Provide the functions/variables below for which implementation is to be overwritten diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/event.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/event.py new file mode 100644 index 00000000000..d5dac6d7f7e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/event.py @@ -0,0 +1,60 @@ +try: + import time + from sonic_py_common.logger import Logger +except ImportError as e: + raise ImportError(repr(e) + " - required module not found") + +POLL_INTERVAL_IN_SEC = 1 + +class SfpEvent: + ''' Listen to insert/remove sfp events ''' + + def __init__(self, sfp_list): + self._sfp_list = sfp_list + self._logger = Logger() + self._sfp_change_event_data = {'present': 0} + + def get_presence_bitmap(self): + bitmap = 0 + for sfp in self._sfp_list: + modpres = sfp.get_presence() + i=sfp.get_position_in_parent() - 1 + if modpres: + bitmap = bitmap | (1 << i) + return bitmap + + def get_sfp_event(self, timeout=2000): + port_dict = {} + change_dict = {} + change_dict['sfp'] = port_dict + + if timeout < 1000: + cd_ms = 1000 + else: + cd_ms = timeout + + while cd_ms > 0: + bitmap = self.get_presence_bitmap() + changed_ports = self._sfp_change_event_data['present'] ^ bitmap + if changed_ports != 0: + break + time.sleep(POLL_INTERVAL_IN_SEC) + # timeout=0 means wait for event forever + if timeout != 0: + cd_ms = cd_ms - POLL_INTERVAL_IN_SEC * 1000 + + if changed_ports != 0: + for sfp in self._sfp_list: + i=sfp.get_position_in_parent() - 1 + if (changed_ports & (1 << i)): + if (bitmap & (1 << i)) == 0: + port_dict[i+1] = '0' + else: + port_dict[i+1] = '1' + + + # Update the cache dict + self._sfp_change_event_data['present'] = bitmap + return True, change_dict + else: + return True, change_dict diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/fan.py new file mode 100644 index 00000000000..ef8deaffb6f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/fan.py @@ -0,0 +1,48 @@ +#!/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 + # Since AS4630 psu_fan airflow direction cant be read from sysfs, it is fixed as 'F2B' or 'Exhaust' + 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: + direction = self.FAN_DIRECTION_EXHAUST + + 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 + diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/platform.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/platform.py new file mode 100644 index 00000000000..406b1179ae1 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/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/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/psu.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/psu.py new file mode 100644 index 00000000000..f002f5e0394 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/psu.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +# + + +try: + from sonic_platform_pddf_base.pddf_psu import PddfPsu +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + + +class Psu(PddfPsu): + """PDDF Platform-Specific PSU class""" + + PLATFORM_PSU_CAPACITY = 1200 + + def __init__(self, index, pddf_data=None, pddf_plugin_data=None): + PddfPsu.__init__(self, index, pddf_data, pddf_plugin_data) + + # Provide the functions/variables below for which implementation is to be overwritten + def get_capacity(self): + """ + Gets the capacity (maximum output power) of the PSU in watts + + Returns: + An integer, the capacity of PSU + """ + return (self.PLATFORM_PSU_CAPACITY) + + def get_type(self): + """ + Gets the type of the PSU + + Returns: + A string, the type of PSU (AC/DC) + """ + ptype = "AC" + # Currently the platform supports only AC type of PSUs + #try: + #import sonic_platform.platform + #ch=sonic_platform.platform.Platform().get_chassis() + #e=ch.sys_eeprom.read_eeprom() + #ret, prod_name = ch.sys_eeprom.get_tlv_field(e,0x21) + #if ret: + #prod_name = prod_name[2] + ##print("Product name is {}".format(prod_name)) + #if '48V' in prod_name: + #ptype = 'DC' + #except Exception as e: + #print("Error while trying to read syseeprom to get PSU type") + + return ptype diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/sfp.py new file mode 100644 index 00000000000..c9fb07d6364 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/sfp.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python + +try: + from sonic_platform_pddf_base.pddf_sfp import PddfSfp +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + + +class Sfp(PddfSfp): + """ + PDDF Platform-Specific Sfp class + """ + + def __init__(self, index, pddf_data=None, pddf_plugin_data=None): + PddfSfp.__init__(self, index, pddf_data, pddf_plugin_data) + + # Provide the functions/variables below for which implementation is to be overwritten + def get_position_in_parent(self): + """Retrieves 1-based relative physical position in parent device.""" + return self.port_index diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/thermal.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/thermal.py new file mode 100644 index 00000000000..5b829fc26ca --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/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/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/watchdog.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/watchdog.py new file mode 100644 index 00000000000..fe8554f6ec7 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/watchdog.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python + +############################################################################# +# +# Module contains an implementation of platform specific watchdog API's +# +############################################################################# + +try: + from sonic_platform_pddf_base.pddf_watchdog import PddfWatchdog +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Watchdog(PddfWatchdog): + """ + PDDF Platform-specific Chassis class + """ + + def __init__(self): + PddfWatchdog.__init__(self) + self.timeout = 180 + + # Provide the functions/variables below for which implementation is to be overwritten diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform_setup.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform_setup.py new file mode 100644 index 00000000000..59dad237f3b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform_setup.py @@ -0,0 +1,25 @@ +from setuptools import setup + +setup( + name='sonic-platform', + version='1.0', + description='SONiC platform API implementation on Accton Platforms using PDDF', + license='Apache 2.0', + author='SONiC Team', + author_email='linuxnetdev@microsoft.com', + url='https://github.com/Azure/sonic-buildimage', + packages=['sonic_platform'], + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Environment :: Plugins', + 'Intended Audience :: Developers', + 'Intended Audience :: Information Technology', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: Apache Software License', + 'Natural Language :: English', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: Python :: 3.7', + 'Topic :: Utilities', + ], + keywords='sonic SONiC platform PLATFORM', +) diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_pddf_monitor.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_pddf_monitor.py new file mode 100755 index 00000000000..d9299b96a3b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_pddf_monitor.py @@ -0,0 +1,332 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -* +# Copyright (c) 2019 Edgecore Networks Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +# +# THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT +# LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS +# FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. +# +# See the Apache Version 2.0 License for specific language governing +# permissions and limitations under the License. +# +# HISTORY: +# mm/dd/yyyy (A.D.)# +# 10/24/2019:Jostar create for as4630_54pe thermal plan +# ------------------------------------------------------------------ + +try: + import os + import sys + import getopt + import subprocess + import logging + import logging.handlers + import time + from sonic_platform import platform +except ImportError as e: + raise ImportError('%s - required module not found' % str(e)) + +# Deafults +VERSION = '1.0' +FUNCTION_NAME = '/usr/local/bin/accton_as4630_54pe_pddf_monitor' + + + + + +# Temperature Policy +# If any fan fail , please set fan speed register to 16 +# The max value of fan speed register is 14 +# LM77(48)+LM75(4B)+LM75(4A) > 140, Set 10 +# LM77(48)+LM75(4B)+LM75(4A) > 150, Set 12 +# LM77(48)+LM75(4B)+LM75(4A) > 160, Set 14 +# LM77(48)+LM75(4B)+LM75(4A) < 140, Set 8 +# LM77(48)+LM75(4B)+LM75(4A) < 150, Set 10 +# LM77(48)+LM75(4B)+LM75(4A) < 160, Set 12 +# Reset DUT:LM77(48)>=70C +# +class switch(object): + def __init__(self, value): + self.value = value + self.fall = False + + def __iter__(self): + """Return the match method once, then stop""" + yield self.match + raise StopIteration + + def match(self, *args): + """Indicate whether or not to enter a case suite""" + if self.fall or not args: + return True + elif self.value in args: # changed for v1.5, see below + self.fall = True + return True + else: + return False + + +def as4630_54pe_set_fan_speed(pwm): + # This platform has 2 fans controlled by one register on CPLD and 3rd fan by another register + # Hence, we need to change the speed for all + if pwm < 0 or pwm > 100: + print("Error: Wrong duty cycle value %d" % (pwm)) + platform_chassis.get_fan(0).set_speed(pwm) + platform_chassis.get_fan(2).set_speed(pwm) + + return 0 + + +fan_policy_state = 0 +fan_fail = 0 +fan_fail_list = [0, 0, 0] +alarm_state = 0 # 0->default or clear, 1-->alarm detect +test_temp = 0 +simulate_temp_decline = 0 +test_temp_list = [0, 0, 0] +temp_test_data = 0 +test_temp_revert = 0 +platform_chassis = None +# Make a class we can use to capture stdout and sterr in the log + + +class device_monitor(object): + # static temp var + temp = 0 + new_pwm = 0 + pwm = 0 + ori_pwm = 0 + default_pwm = 0x4 + + def __init__(self, log_file, log_level): + """Needs a logger and a logger level.""" + # set up logging to file + logging.basicConfig( + filename=log_file, + filemode='w', + level=log_level, + format='[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s', + datefmt='%H:%M:%S' + ) + # set up logging to console + if log_level == logging.DEBUG: + console = logging.StreamHandler() + console.setLevel(log_level) + formatter = logging.Formatter('%(asctime)-15s %(name)-12s: %(levelname)-8s %(message)s') + console.setFormatter(formatter) + logging.getLogger('').addHandler(console) + + sys_handler = logging.handlers.SysLogHandler(address='/dev/log') + sys_handler.setLevel(logging.WARNING) + logging.getLogger('').addHandler(sys_handler) + + def get_state_from_fan_policy(self, temp, policy): + state = 0 + for i in range(0, len(policy)): + if (temp > policy[i][2]): # temp_down + if temp <= policy[i][3]: # temp_up + state = i + + return state + + def manage_fans(self): + global fan_policy_state + global fan_fail + global fan_fail_list + global test_temp + global simulate_temp_decline + global test_temp_list + global alarm_state + global temp_test_data + global test_temp_revert + global platform_chassis + NUM_FANS = 3 + LEVEL_FAN_MIN = 0 + LEVEL_FAN_NORMAL = 1 + LEVEL_FAN_MID = 2 + LEVEL_FAN_HIGH = 3 + LEVEL_TEMP_CRITICAL = 4 + fan_policy = { + LEVEL_FAN_MIN: [50, 8, 0, 140000], + LEVEL_FAN_NORMAL: [62, 10, 140000, 150000], + LEVEL_FAN_MID: [75, 12, 150000, 160000], + LEVEL_FAN_HIGH: [88, 14, 160000, 240000], + LEVEL_TEMP_CRITICAL: [100, 16, 240000, 300000], + } + temp = [0, 0, 0] + + #thermal = ThermalUtil() + #fan = FanUtil() + # Supposedly all the fans are set with same duty cycle + ori_duty_cycle = platform_chassis.get_fan(0).get_speed() + new_duty_cycle = 0 + + if test_temp == 0: + for i in range(0, 3): + temp[i] = platform_chassis.get_thermal(i).get_temperature() + if temp[i] == 0.0 or temp[i] is None: + + logging.warning("Get temp-%d fail", i) + return False + temp[i] = int(temp[i]*1000) + else: + if test_temp_revert == 0: + temp_test_data = temp_test_data+2000 + else: + if temp_test_data > 0: + temp_test_data = temp_test_data-2000 + else: + # Stop the simulation + sys.exit('Simulation Ends !') + + for i in range(0, 3): + temp[i] = test_temp_list[i]+temp_test_data + fan_fail = 0 + + temp_val = 0 + for i in range(0, 3): + if temp[i] is None: + break + temp_val += temp[i] + + # Check Fan status + for i in range(NUM_FANS): + if not platform_chassis.get_fan(i).get_status(): + if test_temp == 0: + fan_fail = 1 + if fan_fail_list[i] == 0: + fan_fail_list[i] = 1 + else: + if fan_fail_list[i] == 1: + fan_fail_list[i] = 0 + + if sum(fan_fail_list) == NUM_FANS: + # Critical: Either all the fans are faulty or they are removed, shutdown the system + logging.critical('Alarm for all fan faulty/absent is detected') + logging.critical("Alarm for all fan faulty/absent is detected, reset DUT") + cmd_str = "i2cset -y -f 3 0x60 0x4 0xE4" + time.sleep(2) + subprocess.getstatusoutput('sync; sync; sync') + subprocess.getstatusoutput(cmd_str) + elif sum(fan_fail_list) != 0: + # Set the 100% speed only for first fan failure detection + logging.warning('Fan_{} failed, set remaining fan speed to 100%'.format( + ' Fan_'.join(str(item+1) for item, val in enumerate(fan_fail_list) if val == 1))) + new_pwm = 100 + as4630_54pe_set_fan_speed(new_pwm) + else: + fan_fail = 0 + + ori_state = fan_policy_state + fan_policy_state = self.get_state_from_fan_policy(temp_val, fan_policy) + + if fan_policy_state > LEVEL_TEMP_CRITICAL or fan_policy_state < LEVEL_FAN_MIN: + logging.error("Get error fan current_state\n") + return 0 + + # Decision : Decide new fan pwm percent. + if fan_fail == 0 and ori_duty_cycle != fan_policy[fan_policy_state][0]: + new_duty_cycle = fan_policy[fan_policy_state][0] + as4630_54pe_set_fan_speed(new_duty_cycle) + if test_temp == 1: + time.sleep(3) + status, output = subprocess.getstatusoutput('pddf_fanutil getspeed') + logging.debug('\n%s\n', output) + + if temp[0] >= 70000: # LM77-48 + # critical case*/ + logging.critical('Alarm for temperature critical is detected') + logging.critical("Alarm-Critical for temperature critical is detected, reset DUT") + # Update the reboot cause file to reflect that critical temperature + # has been crossed. Upon next boot, the contents of this file will + # be used to determine the cause of the previous reboot + status, output = subprocess.getstatusoutput( + 'echo "Thermal Overload: Other" > /host/reboot-cause/reboot-cause.txt') + status, output = subprocess.getstatusoutput( + 'echo "System rebooted because alarm for critical temperature (70 C) is detected [Time: $(eval date)]" >> /host/reboot-cause/reboot-cause.txt') + if status: + logging.warning('Reboot cause file not updated. {}'.format(output)) + + cmd_str = "i2cset -y -f 3 0x60 0x4 0xE4" + subprocess.getstatusoutput('sync; sync; sync') + time.sleep(3) + subprocess.getstatusoutput(cmd_str) + + logging.debug('ori_state=%d, current_state=%d, temp_val=%d\n\n', ori_state, fan_policy_state, temp_val) + + if ori_state < LEVEL_FAN_HIGH: + if fan_policy_state >= LEVEL_FAN_HIGH: + if alarm_state == 0: + logging.warning('Alarm for temperature high is detected') + alarm_state = 1 + # Add a mechanism to decrease the test_temp values + if simulate_temp_decline == 1: + logging.info('Temperature decline simulation is ON. Testing temperature will decrease now') + test_temp_revert = 1 + + if fan_policy_state < LEVEL_FAN_MID: + if alarm_state == 1: + logging.warning('Alarm for temperature high is cleared') + alarm_state = 0 + + return True + + +def main(argv): + # Check if PDDF mode is enabled + if not os.path.exists('/usr/share/sonic/platform/pddf_support'): + print("PDDF mode is not enabled") + return 0 + + log_file = '%s.log' % FUNCTION_NAME + log_level = logging.INFO + global test_temp + global simulate_temp_decline + if len(sys.argv) != 1: + try: + opts, args = getopt.getopt(argv, 'hdlt:', ['lfile=']) + except getopt.GetoptError: + print('Usage: %s [-d] [-l ]' % sys.argv[0]) + return 0 + for opt, arg in opts: + if opt == '-h': + print('Usage: %s [-d] [-l ]' % sys.argv[0]) + return 0 + elif opt in ('-d', '--debug'): + log_level = logging.DEBUG + elif opt in ('-l', '--lfile'): + log_file = arg + + if sys.argv[1] == '-t': + if len(sys.argv) != 6: + print("temp test, need input temp decline option and three temp values") + return 0 + + i = 0 + simulate_temp_decline = int(sys.argv[2]) + for x in range(3, 6): + test_temp_list[i] = int(sys.argv[x])*1000 + i = i+1 + test_temp = 1 + log_level = logging.DEBUG + print(test_temp_list) + + global platform_chassis + platform_chassis = platform.Platform().get_chassis() + + as4630_54pe_set_fan_speed(50) + + monitor = device_monitor(log_file, log_level) + # Loop forever, doing something useful hopefully: + while True: + monitor.manage_fans() + time.sleep(10) # 10sec + + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_util.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_util.py index f0081b33b2c..e4bae3da74d 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_util.py +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_util.py @@ -167,6 +167,8 @@ def driver_inserted(): kos = [ 'depmod -ae', 'modprobe i2c_dev', +'modprobe i2c_i801', +'modprobe i2c_ismt', 'modprobe i2c_mux_pca954x force_deselect_on_exit=1', 'modprobe ym2651y', 'modprobe x86_64_accton_as4630_54pe_cpld', @@ -176,17 +178,7 @@ def driver_inserted(): def driver_install(): global FORCE - - ret=log_os_system("lsmod|grep i2c_ismt",1) - my_log("rmmond i2cismt") - log_os_system("rmmod i2c_ismt", 1) - log_os_system("rmmod i2c_i801", 1) - log_os_system("modprobe i2c-i801", 1) - time.sleep(1) - log_os_system("modprobe i2c-ismt", 1) - - - + for i in range(0,len(kos)): status, output = log_os_system(kos[i], 1) if status: diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/pddf_post_device_create.sh b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/pddf_post_device_create.sh new file mode 100755 index 00000000000..cb545920632 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/pddf_post_device_create.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +set_pca_mux_idle_disconnect() +{ + echo -2 | tee /sys/bus/i2c/drivers/pca954x/*-00*/idle_state >& /dev/null + if [ $? -ne 0 ]; then + echo "Fail to set pca954x mux idle disconnect" + exit 2 + fi +} + +echo "Setting LED MAC Mode.." +i2cset -y -f 3 0x60 0x2a 0xff +i2cset -y -f 3 0x60 0x2b 0xff +i2cset -y -f 3 0x60 0x86 0x89 +echo "Setting LED MAC Mode..DONE" +# Turn off STK1 and STK2 LED. Bit5:4 to 0x11 +#i2cset -y -f 3 0x60 0xb5 +stk_val=$(i2cget -y -f 3 0x60 0x31) +new_val=$((${stk_val}|0x30)) +i2cset -y -f 3 0x60 0x31 ${new_val} +echo "STK LEDs are turned off successfully" + +set_pca_mux_idle_disconnect diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/pddf_switch_svc.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/pddf_switch_svc.py new file mode 100755 index 00000000000..5a505e19f19 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/pddf_switch_svc.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python +# Script to stop and start the respective platforms default services. +# This will be used while switching the pddf->non-pddf mode and vice versa + +import commands + +def check_pddf_support(): + return True + +def stop_platform_svc(): + status, output = commands.getstatusoutput("systemctl disable as4630-54pe-platform-monitor-fan.service") + if status: + print "Disable as4630-54pe-platform-monitor-fan.service failed %d"%status + return False + status, output = commands.getstatusoutput("systemctl stop as4630-54pe-platform-monitor-fan.service") + if status: + print "Stop as4630-54pe-platform-monitor-fan.service failed %d"%status + return False + + status, output = commands.getstatusoutput("systemctl disable as4630-54pe-platform-monitor-psu.service") + if status: + print "Disable as4630-54pe-platform-monitor-psu.service failed %d"%status + return False + status, output = commands.getstatusoutput("systemctl stop as4630-54pe-platform-monitor-psu.service") + if status: + print "Stop as4630-54pe-platform-monitor-psu.service failed %d"%status + return False + + status, output = commands.getstatusoutput("systemctl disable as4630-54pe-platform-monitor.service") + if status: + print "Disable as4630-54pe-platform-monitor.service failed %d"%status + return False + status, output = commands.getstatusoutput("systemctl stop as4630-54pe-platform-monitor.service") + if status: + print "Stop as4630-54pe-platform-monitor.service failed %d"%status + return False + + status, output = commands.getstatusoutput("/usr/local/bin/accton_as4630_54pe_util.py clean") + if status: + print "accton_as4630_54pe_util.py clean command failed %d"%status + return False + + # HACK , stop the pddf-platform-init service if it is active + status, output = commands.getstatusoutput("systemctl stop pddf-platform-init.service") + if status: + print "Stop pddf-platform-init.service along with other platform serives failed %d"%status + return False + status, output = commands.getstatusoutput("systemctl stop as4630-54pe-pddf-platform-monitor.service") + if status: + print "Stop as4630-54pe-pddf-platform-monitor.service along with other platform serives failed %d"%status + return False + + return True + +def start_platform_svc(): + status, output = commands.getstatusoutput("/usr/local/bin/accton_as4630_54pe_util.py install") + if status: + print "accton_as4630_54pe_util.py install command failed %d"%status + return False + + status, output = commands.getstatusoutput("systemctl enable as4630-54pe-platform-monitor-fan.service") + if status: + print "Enable as4630-54pe-platform-monitor-fan.service failed %d"%status + return False + status, output = commands.getstatusoutput("systemctl start as4630-54pe-platform-monitor-fan.service") + if status: + print "Start as4630-54pe-platform-monitor-fan.service failed %d"%status + return False + + status, output = commands.getstatusoutput("systemctl enable as4630-54pe-platform-monitor-psu.service") + if status: + print "Enable as4630-54pe-platform-monitor-psu.service failed %d"%status + return False + status, output = commands.getstatusoutput("systemctl start as4630-54pe-platform-monitor-psu.service") + if status: + print "Start as4630-54pe-platform-monitor-psu.service failed %d"%status + return False + + status, output = commands.getstatusoutput("systemctl enable as4630-54pe-platform-monitor.service") + if status: + print "Enable as4630-54pe-platform-monitor.service failed %d"%status + return False + status, output = commands.getstatusoutput("systemctl start as4630-54pe-platform-monitor.service") + if status: + print "Start as4630-54pe-platform-monitor.service failed %d"%status + return False + + return True + +def start_platform_pddf(): + status, output = commands.getstatusoutput("systemctl start pddf-platform-init.service") + if status: + print "Start pddf-platform-init.service failed %d"%status + return False + status, output = commands.getstatusoutput("systemctl start as4630-54pe-pddf-platform-monitor.service") + if status: + print "Start as4630-54pe-pddf-platform-monitor.service failed %d"%status + return False + + return True + +def stop_platform_pddf(): + status, output = commands.getstatusoutput("systemctl stop pddf-platform-init.service") + if status: + print "Stop pddf-platform-init.service failed %d"%status + return False + status, output = commands.getstatusoutput("systemctl stop as4630-54pe-pddf-platform-monitor.service") + if status: + print "Stop as4630-54pe-pddf-platform-monitor.service failed %d"%status + return False + + return True + +def main(): + pass + +if __name__ == "__main__": + main() diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54te/modules/x86-64-accton-as4630-54te-cpld.c b/platform/broadcom/sonic-platform-modules-accton/as4630-54te/modules/x86-64-accton-as4630-54te-cpld.c index 98b855329c6..549cd1dbad1 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54te/modules/x86-64-accton-as4630-54te-cpld.c +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54te/modules/x86-64-accton-as4630-54te-cpld.c @@ -96,6 +96,8 @@ static const struct i2c_device_id as4630_54te_cpld_id[] = { }; MODULE_DEVICE_TABLE(i2c, as4630_54te_cpld_id); +#define TRANSCEIVER_RESET_ATTR_ID(index) MODULE_RESET_##index +#define TRANSCEIVER_LPMODE_ATTR_ID(index) MODULE_LPMODE_##index #define TRANSCEIVER_PRESENT_ATTR_ID(index) MODULE_PRESENT_##index #define TRANSCEIVER_TXDISABLE_ATTR_ID(index) MODULE_TXDISABLE_##index #define TRANSCEIVER_RXLOS_ATTR_ID(index) MODULE_RXLOS_##index @@ -123,6 +125,10 @@ enum as4630_54te_cpld_sysfs_attributes { TRANSCEIVER_PRESENT_ATTR_ID(52), TRANSCEIVER_PRESENT_ATTR_ID(53), TRANSCEIVER_PRESENT_ATTR_ID(54), + TRANSCEIVER_RESET_ATTR_ID(53), + TRANSCEIVER_RESET_ATTR_ID(54), + TRANSCEIVER_LPMODE_ATTR_ID(53), + TRANSCEIVER_LPMODE_ATTR_ID(54), TRANSCEIVER_TXDISABLE_ATTR_ID(49), TRANSCEIVER_TXDISABLE_ATTR_ID(50), TRANSCEIVER_TXDISABLE_ATTR_ID(51), @@ -148,6 +154,8 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf); static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, const char *buf, size_t count); +static ssize_t set_qsfp(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); static ssize_t access(struct device *dev, struct device_attribute *da, const char *buf, size_t count); static ssize_t show_version(struct device *dev, struct device_attribute *da, @@ -180,9 +188,13 @@ static ssize_t get_sys_temp(struct device *dev, struct device_attribute *da, cha &sensor_dev_attr_module_tx_fault_##index.dev_attr.attr #define DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_lpmode_##index, S_IRUGO | S_IWUSR, show_status, set_qsfp, MODULE_LPMODE_##index); \ + static SENSOR_DEVICE_ATTR(module_reset_##index, S_IRUGO | S_IWUSR, show_status, set_qsfp, MODULE_RESET_##index); \ static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, show_status, NULL, MODULE_PRESENT_##index); #define DECLARE_QSFP_TRANSCEIVER_ATTR(index) \ + &sensor_dev_attr_module_lpmode_##index.dev_attr.attr, \ + &sensor_dev_attr_module_reset_##index.dev_attr.attr, \ &sensor_dev_attr_module_present_##index.dev_attr.attr @@ -273,7 +285,7 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, break; case MODULE_TXDISABLE_49 ... MODULE_TXDISABLE_50: reg=0x5; - mask=0x1 << (attr->index==MODULE_TXFAULT_49?7:3); + mask=0x1 << (attr->index==MODULE_TXDISABLE_49?7:3); break; case MODULE_RXLOS_51 ... MODULE_RXLOS_52: @@ -290,12 +302,22 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, break; case MODULE_TXDISABLE_51 ... MODULE_TXDISABLE_52: reg=0x6; - mask=0x1 << (attr->index==MODULE_TXFAULT_51?7:3); + mask=0x1 << (attr->index==MODULE_TXDISABLE_51?7:3); break; case MODULE_PRESENT_53 ... MODULE_PRESENT_54: reg=0x21; mask=0x1 << (attr->index==MODULE_PRESENT_53?0:4); break; + case MODULE_RESET_53 ... MODULE_RESET_54: + reg=0x21; + mask=0x1 << (attr->index==MODULE_RESET_53?3:7); + revert = 1; + break; + case MODULE_LPMODE_53 ... MODULE_LPMODE_54: + reg = 0x21; + mask = 0x1 << (attr->index==MODULE_LPMODE_53?2:6); + revert = 0; + break; default: return 0; } @@ -319,6 +341,61 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, return status; } +static ssize_t set_qsfp(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 as4630_54te_cpld_data *data = i2c_get_clientdata(client); + long disable; + int status; + u8 reg = 0, mask = 0, revert = 0; + + status = kstrtol(buf, 10, &disable); + if (status) { + return status; + } + reg = 0x21; + switch (attr->index) + { + case MODULE_RESET_53 ... MODULE_RESET_54: + mask=0x1 << (attr->index==MODULE_RESET_53?3:7); + revert = 1; + break; + case MODULE_LPMODE_53 ... MODULE_LPMODE_54: + mask=0x1 << (attr->index==MODULE_LPMODE_53?2:6); + revert = 0; + break; + default: + return 0; + } + + disable = revert ? disable : !disable; + /* Read current status */ + mutex_lock(&data->update_lock); + status = as4630_54te_cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + if (disable) { + status &= ~mask; + } + else { + status |= mask; + } + status = as4630_54te_cpld_write_internal(client, reg, status); + if (unlikely(status < 0)) { + goto exit; + } + + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, const char *buf, size_t count) { @@ -338,11 +415,11 @@ static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, { case MODULE_TXDISABLE_49 ... MODULE_TXDISABLE_50: reg=0x5; - mask=0x1 << (attr->index==MODULE_TXFAULT_49?7:3); + mask=0x1 << (attr->index==MODULE_TXDISABLE_49?7:3); break; case MODULE_TXDISABLE_51 ... MODULE_TXDISABLE_52: reg=0x6; - mask=0x1 << (attr->index==MODULE_TXFAULT_51?7:3); + mask=0x1 << (attr->index==MODULE_TXDISABLE_51?7:3); break; default: @@ -357,10 +434,10 @@ static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, } /* Update tx_disable status */ if (disable) { - status &= ~mask; + status |= mask; } else { - status |= mask; + status &= ~mask; } status = as4630_54te_cpld_write_internal(client, reg, status); if (unlikely(status < 0)) { @@ -498,11 +575,11 @@ static ssize_t set_duty_cycle(struct device *dev, struct device_attribute *da, static u8 reg_val_to_direction(u8 reg_val, enum fan_id id) { - u8 mask = (1 << id); + u8 mask = (1 << (4 + id)); reg_val &= mask; - return reg_val ? 1 : 0; + return reg_val ? 0 : 1; } static u8 reg_val_to_is_present(u8 reg_val, enum fan_id id) diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54te/modules/x86-64-accton-as4630-54te-leds.c b/platform/broadcom/sonic-platform-modules-accton/as4630-54te/modules/x86-64-accton-as4630-54te-leds.c index f4e2668348f..81cb78b1900 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54te/modules/x86-64-accton-as4630-54te-leds.c +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54te/modules/x86-64-accton-as4630-54te-leds.c @@ -64,7 +64,7 @@ static struct accton_as4630_54te_led_data *ledctl = NULL; #define LED_TYPE_POE_REG_MASK (0x2|0x1) #define LED_MODE_POE_GREEN_VALUE 0x1 #define LED_MODE_POE_AMBER_VALUE 0x2 -#define LED_MODE_POE_OFF_VALUE 0x0 +#define LED_MODE_POE_OFF_VALUE 0x3 #define LED_TYPE_STK1_REG_MASK 0x20 #define LED_MODE_STK1_GREEN_VALUE 0x0 @@ -74,20 +74,20 @@ static struct accton_as4630_54te_led_data *ledctl = NULL; #define LED_MODE_STK2_GREEN_VALUE 0x0 #define LED_MODE_STK2_OFF_VALUE 0x10 -#define LED_TYPE_FAN_REG_MASK (0x20|0x10) -#define LED_MODE_FAN_AMBER_VALUE 0x20 -#define LED_MODE_FAN_GREEN_VALUE 0x10 -#define LED_MODE_FAN_OFF_VALUE (0x0) +#define LED_TYPE_FAN_REG_MASK (0x8|0x4) +#define LED_MODE_FAN_AMBER_VALUE 0x8 +#define LED_MODE_FAN_GREEN_VALUE 0x4 +#define LED_MODE_FAN_OFF_VALUE (0xC) -#define LED_TYPE_PSU2_REG_MASK (0x8|0x4) -#define LED_MODE_PSU2_AMBER_VALUE 0x8 -#define LED_MODE_PSU2_GREEN_VALUE 0x4 -#define LED_MODE_PSU2_OFF_VALUE (0x0) +#define LED_TYPE_PSU2_REG_MASK (0x80|0x40) +#define LED_MODE_PSU2_AMBER_VALUE 0x80 +#define LED_MODE_PSU2_GREEN_VALUE 0x40 +#define LED_MODE_PSU2_OFF_VALUE (0xC0) #define LED_TYPE_PSU1_REG_MASK (0x2|0x1) #define LED_MODE_PSU1_AMBER_VALUE 0x2 #define LED_MODE_PSU1_GREEN_VALUE 0x1 -#define LED_MODE_PSU1_OFF_VALUE (0x0) +#define LED_MODE_PSU1_OFF_VALUE (0x3) enum led_type { LED_TYPE_DIAG, @@ -106,8 +106,8 @@ struct led_reg { }; static const struct led_reg led_reg_map[] = { - {(1<reg_val[0]); + return led_reg_val_to_light_mode(LED_TYPE_FAN, ledctl->reg_val[1]); } static void accton_as4630_54te_led_psu1_set(struct led_classdev *led_cdev, @@ -395,7 +395,7 @@ static void accton_as4630_54te_led_psu2_set(struct led_classdev *led_cdev, static enum led_brightness accton_as4630_54te_led_psu2_get(struct led_classdev *cdev) { accton_as4630_54te_led_update(); - return led_reg_val_to_light_mode(LED_TYPE_PSU2, ledctl->reg_val[0]); + return led_reg_val_to_light_mode(LED_TYPE_PSU2, ledctl->reg_val[1]); } static struct led_classdev accton_as4630_54te_leds[] = { @@ -405,7 +405,7 @@ static struct led_classdev accton_as4630_54te_leds[] = { .brightness_set = accton_as4630_54te_led_diag_set, .brightness_get = accton_as4630_54te_led_diag_get, .flags = LED_CORE_SUSPENDRESUME, - .max_brightness = LED_MODE_GREEN, + .max_brightness = LED_MODE_GREEN_BLINK, }, [LED_TYPE_PRI] = { .name = "pri", diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54te/modules/x86-64-accton-as4630-54te-psu.c b/platform/broadcom/sonic-platform-modules-accton/as4630-54te/modules/x86-64-accton-as4630-54te-psu.c index 3a99f19a9cd..b7640eaab11 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54te/modules/x86-64-accton-as4630-54te-psu.c +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54te/modules/x86-64-accton-as4630-54te-psu.c @@ -91,7 +91,6 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, struct as4630_54te_psu_data *data = as4630_54te_psu_update_device(dev); u8 status = 0; - //printk("data->status=0x%x, attr->index=%d,data->index=%d \n", data->status, attr->index, data->index); if (attr->index == PSU_PRESENT) { if(data->index==0) status = !( (data->status >> 5) & 0x1); @@ -267,7 +266,7 @@ static struct as4630_54te_psu_data *as4630_54te_psu_update_device(struct device /* Read psu status */ status = as4630_54te_cpld_read(0x60, 0x22); - //printk("status=0x%x in %s\n", status, __FUNCTION__); + if (status < 0) { dev_dbg(&client->dev, "cpld reg 0x60 err %d\n", status); } @@ -278,29 +277,37 @@ static struct as4630_54te_psu_data *as4630_54te_psu_update_device(struct device /* Read model name */ memset(data->model_name, 0, sizeof(data->model_name)); memset(data->serial_number, 0, sizeof(data->serial_number)); - power_good = (data->status >> (3-data->index) & 0x1); + power_good = (data->status >> (data->index==0? 6:2)) & 0x1; if (power_good) { status = as4630_54te_psu_read_block(client, 0x20, data->model_name, - ARRAY_SIZE(data->model_name)-1); + ARRAY_SIZE(data->model_name)-1); + if (status < 0) { data->model_name[0] = '\0'; dev_dbg(&client->dev, "unable to read model name from (0x%x)\n", client->addr); printk("unable to read model name from (0x%x)\n", client->addr); } - else { - data->model_name[ARRAY_SIZE(data->model_name)-1] = '\0'; + else if(!strncmp(data->model_name, "YM-1151D", strlen("YM-1151D"))) + { + data->model_name[strlen("YM-1151D")]='\0'; } - /* Read from offset 0x2e ~ 0x3d (16 bytes) */ - status = as4630_54te_psu_read_block(client, 0x35,data->serial_number, MAX_SERIAL_NUMBER); + else + { + data->model_name[ARRAY_SIZE(data->model_name)-1] = '\0'; + } + /* Read from offset 0x2e ~ 0x3f (16 bytes) */ + status = as4630_54te_psu_read_block(client, 0x2e,data->serial_number, MAX_SERIAL_NUMBER); if (status < 0) { data->serial_number[0] = '\0'; dev_dbg(&client->dev, "unable to read model name from (0x%x) offset(0x2e)\n", client->addr); printk("unable to read model name from (0x%x) offset(0x2e)\n", client->addr); } + data->serial_number[MAX_SERIAL_NUMBER-1]='\0'; + } data->last_updated = jiffies; diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/accton_as5812_54x_psu.c b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/accton_as5812_54x_psu.c index 2c6b5f492a9..925a71c6340 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/accton_as5812_54x_psu.c +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/accton_as5812_54x_psu.c @@ -38,16 +38,18 @@ #define PSU_STATUS_I2C_ADDR 0x60 #define PSU_STATUS_I2C_REG_OFFSET 0x2 - +#define MAX_SERIAL_NUMBER 15 #define IS_POWER_GOOD(id, value) (!!(value & BIT(id*4 + 1))) #define IS_PRESENT(id, value) (!(value & BIT(id*4))) static ssize_t show_index(struct device *dev, struct device_attribute *da, char *buf); static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf); static ssize_t show_model_name(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_serial_number(struct device *dev, struct device_attribute *da, char *buf); static int as5812_54x_psu_read_block(struct i2c_client *client, u8 command, u8 *data,int data_len); extern int as5812_54x_cpld_read(unsigned short cpld_addr, u8 reg); static int as5812_54x_psu_model_name_get(struct device *dev); +static int as5812_54x_psu_serial_number_get(struct device *dev); /* Addresses scanned */ @@ -63,6 +65,7 @@ struct as5812_54x_psu_data { u8 index; /* PSU index */ u8 status; /* Status(present/power_good) register read from CPLD */ char model_name[14]; /* Model name, read from eeprom */ + char serial_number[MAX_SERIAL_NUMBER]; /* serial number, read from eeprom */ }; static struct as5812_54x_psu_data *as5812_54x_psu_update_device(struct device *dev); @@ -71,7 +74,9 @@ enum as5812_54x_psu_sysfs_attributes { PSU_INDEX, PSU_PRESENT, PSU_MODEL_NAME, - PSU_POWER_GOOD + PSU_POWER_GOOD, + PSU_SERIAL_NUMBER, + }; /* sysfs attributes for hwmon @@ -80,12 +85,14 @@ static SENSOR_DEVICE_ATTR(psu_index, S_IRUGO, show_index, NULL, PSU_IND static SENSOR_DEVICE_ATTR(psu_present, S_IRUGO, show_status, NULL, PSU_PRESENT); static SENSOR_DEVICE_ATTR(psu_model_name, S_IRUGO, show_model_name,NULL, PSU_MODEL_NAME); static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_status, NULL, PSU_POWER_GOOD); +static SENSOR_DEVICE_ATTR(psu_serial_number, S_IRUGO, show_serial_number,NULL, PSU_SERIAL_NUMBER); static struct attribute *as5812_54x_psu_attributes[] = { &sensor_dev_attr_psu_index.dev_attr.attr, &sensor_dev_attr_psu_present.dev_attr.attr, &sensor_dev_attr_psu_model_name.dev_attr.attr, &sensor_dev_attr_psu_power_good.dev_attr.attr, + &sensor_dev_attr_psu_serial_number.dev_attr.attr, NULL }; @@ -139,6 +146,26 @@ static ssize_t show_model_name(struct device *dev, struct device_attribute *da, return sprintf(buf, "%s\n", data->model_name); } +static ssize_t show_serial_number(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct as5812_54x_psu_data *data = as5812_54x_psu_update_device(dev); + + if (!data->valid) { + return 0; + } + + if (!IS_POWER_GOOD(data->index, data->status)) { + return 0; + } + + if (as5812_54x_psu_serial_number_get(dev) < 0) { + return -ENXIO; + } + + return sprintf(buf, "%s\n", data->serial_number); +} + static const struct attribute_group as5812_54x_psu_group = { .attrs = as5812_54x_psu_attributes, }; @@ -316,6 +343,31 @@ static int as5812_54x_psu_model_name_get(struct device *dev) return -ENODATA; } +static int as5812_54x_psu_serial_number_get(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as5812_54x_psu_data *data = i2c_get_clientdata(client); + int i, status; + + memset(data->serial_number, 0, sizeof(data->serial_number)); + status = as5812_54x_psu_read_block(client, 0x47, + data->serial_number, MAX_SERIAL_NUMBER); + + if (status < 0) { + data->model_name[0] = '\0'; + dev_dbg(&client->dev, "unable to read serial from (0x%x) offset(0x%x)\n", + client->addr, 0x47); + return status; + } + else { + data->serial_number[MAX_SERIAL_NUMBER] = '\0'; + return 0; + } + + return -ENODATA; +} + + static struct as5812_54x_psu_data *as5812_54x_psu_update_device(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/cpr_4011_4mxx.c b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/cpr_4011_4mxx.c deleted file mode 100755 index 30bea914d58..00000000000 --- a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/cpr_4011_4mxx.c +++ /dev/null @@ -1,400 +0,0 @@ -/* - * An hwmon driver for the CPR-4011-4Mxx Redundant Power Module - * - * Copyright (C) Brandon Chuang - * - * Based on ad7414.c - * Copyright 2006 Stefan Roese , DENX Software Engineering - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#if 0 -#define DEBUG -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MAX_FAN_DUTY_CYCLE 100 - -/* Addresses scanned - */ -static const unsigned short normal_i2c[] = { 0x3c, 0x3d, 0x3e, 0x3f, I2C_CLIENT_END }; - -/* Each client has this additional data - */ -struct cpr_4011_4mxx_data { - struct device *hwmon_dev; - struct mutex update_lock; - char valid; /* !=0 if registers are valid */ - unsigned long last_updated; /* In jiffies */ - u8 vout_mode; /* Register value */ - u16 v_in; /* Register value */ - u16 v_out; /* Register value */ - u16 i_in; /* Register value */ - u16 i_out; /* Register value */ - u16 p_in; /* Register value */ - u16 p_out; /* Register value */ - u16 temp_input[2]; /* Register value */ - u8 fan_fault; /* Register value */ - u16 fan_duty_cycle[2]; /* Register value */ - u16 fan_speed[2]; /* Register value */ -}; - -static ssize_t show_linear(struct device *dev, struct device_attribute *da, char *buf); -static ssize_t show_fan_fault(struct device *dev, struct device_attribute *da, char *buf); -static ssize_t show_vout(struct device *dev, struct device_attribute *da, char *buf); -static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *da, const char *buf, size_t count); -static int cpr_4011_4mxx_write_word(struct i2c_client *client, u8 reg, u16 value); -static struct cpr_4011_4mxx_data *cpr_4011_4mxx_update_device(struct device *dev); - -enum cpr_4011_4mxx_sysfs_attributes { - PSU_V_IN, - PSU_V_OUT, - PSU_I_IN, - PSU_I_OUT, - PSU_P_IN, - PSU_P_OUT, - PSU_TEMP1_INPUT, - PSU_FAN1_FAULT, - PSU_FAN1_DUTY_CYCLE, - PSU_FAN1_SPEED, -}; - -/* sysfs attributes for hwmon - */ -static SENSOR_DEVICE_ATTR(psu_v_in, S_IRUGO, show_linear, NULL, PSU_V_IN); -static SENSOR_DEVICE_ATTR(psu_v_out, S_IRUGO, show_vout, NULL, PSU_V_OUT); -static SENSOR_DEVICE_ATTR(psu_i_in, S_IRUGO, show_linear, NULL, PSU_I_IN); -static SENSOR_DEVICE_ATTR(psu_i_out, S_IRUGO, show_linear, NULL, PSU_I_OUT); -static SENSOR_DEVICE_ATTR(psu_p_in, S_IRUGO, show_linear, NULL, PSU_P_IN); -static SENSOR_DEVICE_ATTR(psu_p_out, S_IRUGO, show_linear, NULL, PSU_P_OUT); -static SENSOR_DEVICE_ATTR(psu_temp1_input, S_IRUGO, show_linear, NULL, PSU_TEMP1_INPUT); -static SENSOR_DEVICE_ATTR(psu_fan1_fault, S_IRUGO, show_fan_fault, NULL, PSU_FAN1_FAULT); -static SENSOR_DEVICE_ATTR(psu_fan1_duty_cycle_percentage, S_IWUSR | S_IRUGO, show_linear, set_fan_duty_cycle, PSU_FAN1_DUTY_CYCLE); -static SENSOR_DEVICE_ATTR(psu_fan1_speed_rpm, S_IRUGO, show_linear, NULL, PSU_FAN1_SPEED); - -static struct attribute *cpr_4011_4mxx_attributes[] = { - &sensor_dev_attr_psu_v_in.dev_attr.attr, - &sensor_dev_attr_psu_v_out.dev_attr.attr, - &sensor_dev_attr_psu_i_in.dev_attr.attr, - &sensor_dev_attr_psu_i_out.dev_attr.attr, - &sensor_dev_attr_psu_p_in.dev_attr.attr, - &sensor_dev_attr_psu_p_out.dev_attr.attr, - &sensor_dev_attr_psu_temp1_input.dev_attr.attr, - &sensor_dev_attr_psu_fan1_fault.dev_attr.attr, - &sensor_dev_attr_psu_fan1_duty_cycle_percentage.dev_attr.attr, - &sensor_dev_attr_psu_fan1_speed_rpm.dev_attr.attr, - NULL -}; - -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; -} - -static ssize_t set_fan_duty_cycle(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 cpr_4011_4mxx_data *data = i2c_get_clientdata(client); - int nr = (attr->index == PSU_FAN1_DUTY_CYCLE) ? 0 : 1; - long speed; - int error; - - error = kstrtol(buf, 10, &speed); - if (error) - return error; - - if (speed < 0 || speed > MAX_FAN_DUTY_CYCLE) - return -EINVAL; - - mutex_lock(&data->update_lock); - data->fan_duty_cycle[nr] = speed; - cpr_4011_4mxx_write_word(client, 0x3B + nr, data->fan_duty_cycle[nr]); - mutex_unlock(&data->update_lock); - - return count; -} - -static ssize_t show_linear(struct device *dev, struct device_attribute *da, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct cpr_4011_4mxx_data *data = cpr_4011_4mxx_update_device(dev); - - u16 value = 0; - int exponent, mantissa; - int multiplier = 1000; - - switch (attr->index) { - case PSU_V_IN: - value = data->v_in; - break; - case PSU_I_IN: - value = data->i_in; - break; - case PSU_I_OUT: - value = data->i_out; - break; - case PSU_P_IN: - value = data->p_in; - break; - case PSU_P_OUT: - value = data->p_out; - break; - case PSU_TEMP1_INPUT: - value = data->temp_input[0]; - break; - case PSU_FAN1_DUTY_CYCLE: - multiplier = 1; - value = data->fan_duty_cycle[0]; - break; - case PSU_FAN1_SPEED: - multiplier = 1; - value = data->fan_speed[0]; - break; - default: - break; - } - - exponent = two_complement_to_int(value >> 11, 5, 0x1f); - mantissa = two_complement_to_int(value & 0x7ff, 11, 0x7ff); - - return (exponent >= 0) ? sprintf(buf, "%d\n", (mantissa << exponent) * multiplier) : - sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); -} - -static ssize_t show_fan_fault(struct device *dev, struct device_attribute *da, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct cpr_4011_4mxx_data *data = cpr_4011_4mxx_update_device(dev); - - u8 shift = (attr->index == PSU_FAN1_FAULT) ? 7 : 6; - - return sprintf(buf, "%d\n", data->fan_fault >> shift); -} - -static ssize_t show_vout(struct device *dev, struct device_attribute *da, - char *buf) -{ - struct cpr_4011_4mxx_data *data = cpr_4011_4mxx_update_device(dev); - int exponent, mantissa; - int multiplier = 1000; - - exponent = two_complement_to_int(data->vout_mode, 5, 0x1f); - mantissa = data->v_out; - - return (exponent > 0) ? sprintf(buf, "%d\n", (mantissa << exponent) * multiplier) : - sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); -} - -static const struct attribute_group cpr_4011_4mxx_group = { - .attrs = cpr_4011_4mxx_attributes, -}; - -static int cpr_4011_4mxx_probe(struct i2c_client *client, - const struct i2c_device_id *dev_id) -{ - struct cpr_4011_4mxx_data *data; - int status; - - if (!i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) { - status = -EIO; - goto exit; - } - - data = kzalloc(sizeof(struct cpr_4011_4mxx_data), GFP_KERNEL); - if (!data) { - status = -ENOMEM; - goto exit; - } - - i2c_set_clientdata(client, data); - data->valid = 0; - mutex_init(&data->update_lock); - - dev_info(&client->dev, "chip found\n"); - - /* Register sysfs hooks */ - status = sysfs_create_group(&client->dev.kobj, &cpr_4011_4mxx_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); - - return 0; - -exit_remove: - sysfs_remove_group(&client->dev.kobj, &cpr_4011_4mxx_group); -exit_free: - kfree(data); -exit: - - return status; -} - -static int cpr_4011_4mxx_remove(struct i2c_client *client) -{ - struct cpr_4011_4mxx_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &cpr_4011_4mxx_group); - kfree(data); - - return 0; -} - -static const struct i2c_device_id cpr_4011_4mxx_id[] = { - { "cpr_4011_4mxx", 0 }, - {} -}; -MODULE_DEVICE_TABLE(i2c, cpr_4011_4mxx_id); - -static struct i2c_driver cpr_4011_4mxx_driver = { - .class = I2C_CLASS_HWMON, - .driver = { - .name = "cpr_4011_4mxx", - }, - .probe = cpr_4011_4mxx_probe, - .remove = cpr_4011_4mxx_remove, - .id_table = cpr_4011_4mxx_id, - .address_list = normal_i2c, -}; - -static int cpr_4011_4mxx_read_byte(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -static int cpr_4011_4mxx_read_word(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_word_data(client, reg); -} - -static int cpr_4011_4mxx_write_word(struct i2c_client *client, u8 reg, u16 value) -{ - return i2c_smbus_write_word_data(client, reg, value); -} - -struct reg_data_byte { - u8 reg; - u8 *value; -}; - -struct reg_data_word { - u8 reg; - u16 *value; -}; - -static struct cpr_4011_4mxx_data *cpr_4011_4mxx_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct cpr_4011_4mxx_data *data = i2c_get_clientdata(client); - - mutex_lock(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - int i, status; - struct reg_data_byte regs_byte[] = { {0x20, &data->vout_mode}, - {0x81, &data->fan_fault}}; - struct reg_data_word regs_word[] = { {0x88, &data->v_in}, - {0x8b, &data->v_out}, - {0x89, &data->i_in}, - {0x8c, &data->i_out}, - {0x96, &data->p_out}, - {0x97, &data->p_in}, - {0x8d, &(data->temp_input[0])}, - {0x8e, &(data->temp_input[1])}, - {0x3b, &(data->fan_duty_cycle[0])}, - {0x3c, &(data->fan_duty_cycle[1])}, - {0x90, &(data->fan_speed[0])}, - {0x91, &(data->fan_speed[1])}}; - - dev_dbg(&client->dev, "Starting cpr_4011_4mxx update\n"); - - /* Read byte data */ - for (i = 0; i < ARRAY_SIZE(regs_byte); i++) { - status = cpr_4011_4mxx_read_byte(client, regs_byte[i].reg); - - if (status < 0) { - dev_dbg(&client->dev, "reg %d, err %d\n", - regs_byte[i].reg, status); - } - else { - *(regs_byte[i].value) = status; - } - } - - /* Read word data */ - for (i = 0; i < ARRAY_SIZE(regs_word); i++) { - status = cpr_4011_4mxx_read_word(client, regs_word[i].reg); - - if (status < 0) { - dev_dbg(&client->dev, "reg %d, err %d\n", - regs_word[i].reg, status); - } - else { - *(regs_word[i].value) = status; - } - } - - data->last_updated = jiffies; - data->valid = 1; - } - - mutex_unlock(&data->update_lock); - - return data; -} - -static int __init cpr_4011_4mxx_init(void) -{ - return i2c_add_driver(&cpr_4011_4mxx_driver); -} - -static void __exit cpr_4011_4mxx_exit(void) -{ - i2c_del_driver(&cpr_4011_4mxx_driver); -} - -MODULE_AUTHOR("Brandon Chuang "); -MODULE_DESCRIPTION("CPR_4011_4MXX driver"); -MODULE_LICENSE("GPL"); - -module_init(cpr_4011_4mxx_init); -module_exit(cpr_4011_4mxx_exit); diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/cpr_4011_4mxx.c b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/cpr_4011_4mxx.c new file mode 120000 index 00000000000..fd43cc1f1c7 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/cpr_4011_4mxx.c @@ -0,0 +1 @@ +../../common/modules/cpr_4011_4mxx.c \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/ym2651y.c b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/ym2651y.c deleted file mode 100755 index 519530387e2..00000000000 --- a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/ym2651y.c +++ /dev/null @@ -1,683 +0,0 @@ -/* - * An hwmon driver for the 3Y Power YM-2651Y Power Module - * - * Copyright (C) 2014 Accton Technology Corporation. - * Brandon Chuang - * - * Based on ad7414.c - * Copyright 2006 Stefan Roese , DENX Software Engineering - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#if 0 -#define DEBUG -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MAX_FAN_DUTY_CYCLE 100 - -/* Addresses scanned - */ -static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; - -enum chips { - YM2651, - YM2401, -}; - -/* Each client has this additional data - */ -struct ym2651y_data { - struct device *hwmon_dev; - struct mutex update_lock; - char valid; /* !=0 if registers are valid */ - unsigned long last_updated; /* In jiffies */ - u8 chip; /* chip id */ - u8 capability; /* Register value */ - u16 status_word; /* Register value */ - u8 fan_fault; /* Register value */ - u8 over_temp; /* Register value */ - u16 v_out; /* Register value */ - u16 i_out; /* Register value */ - u16 p_out; /* Register value */ - u8 vout_mode; /* Register value */ - u16 temp; /* Register value */ - u16 fan_speed; /* Register value */ - u16 fan_duty_cycle[2]; /* Register value */ - u8 fan_dir[5]; /* Register value */ - u8 pmbus_revision; /* Register value */ - u8 mfr_id[10]; /* Register value */ - u8 mfr_model[16]; /* Register value */ - u8 mfr_revsion[3]; /* Register value */ - u16 mfr_vin_min; /* Register value */ - u16 mfr_vin_max; /* Register value */ - u16 mfr_iin_max; /* Register value */ - u16 mfr_iout_max; /* Register value */ - u16 mfr_pin_max; /* Register value */ - u16 mfr_pout_max; /* Register value */ - u16 mfr_vout_min; /* Register value */ - u16 mfr_vout_max; /* Register value */ -}; - -static ssize_t show_byte(struct device *dev, struct device_attribute *da, - char *buf); -static ssize_t show_word(struct device *dev, struct device_attribute *da, - char *buf); -static ssize_t show_linear(struct device *dev, struct device_attribute *da, - char *buf); -static ssize_t show_vout(struct device *dev, struct device_attribute *da, char *buf); -static ssize_t show_fan_fault(struct device *dev, struct device_attribute *da, - char *buf); -static ssize_t show_over_temp(struct device *dev, struct device_attribute *da, - char *buf); -static ssize_t show_ascii(struct device *dev, struct device_attribute *da, - char *buf); -static struct ym2651y_data *ym2651y_update_device(struct device *dev); -static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *da, - const char *buf, size_t count); -static int ym2651y_write_word(struct i2c_client *client, u8 reg, u16 value); - -enum ym2651y_sysfs_attributes { - PSU_POWER_ON = 0, - PSU_TEMP_FAULT, - PSU_POWER_GOOD, - PSU_FAN1_FAULT, - PSU_FAN_DIRECTION, - PSU_OVER_TEMP, - PSU_V_OUT, - PSU_I_OUT, - PSU_P_OUT, - PSU_TEMP1_INPUT, - PSU_FAN1_SPEED, - PSU_FAN1_DUTY_CYCLE, - PSU_PMBUS_REVISION, - PSU_MFR_ID, - PSU_MFR_MODEL, - PSU_MFR_REVISION, - PSU_MFR_VIN_MIN, - PSU_MFR_VIN_MAX, - PSU_MFR_VOUT_MIN, - PSU_MFR_VOUT_MAX, - PSU_MFR_IIN_MAX, - PSU_MFR_IOUT_MAX, - PSU_MFR_PIN_MAX, - PSU_MFR_POUT_MAX -}; - -/* sysfs attributes for hwmon - */ -static SENSOR_DEVICE_ATTR(psu_power_on, S_IRUGO, show_word, NULL, PSU_POWER_ON); -static SENSOR_DEVICE_ATTR(psu_temp_fault, S_IRUGO, show_word, NULL, PSU_TEMP_FAULT); -static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_word, NULL, PSU_POWER_GOOD); -static SENSOR_DEVICE_ATTR(psu_fan1_fault, S_IRUGO, show_fan_fault, NULL, PSU_FAN1_FAULT); -static SENSOR_DEVICE_ATTR(psu_over_temp, S_IRUGO, show_over_temp, NULL, PSU_OVER_TEMP); -static SENSOR_DEVICE_ATTR(psu_v_out, S_IRUGO, show_vout, NULL, PSU_V_OUT); -static SENSOR_DEVICE_ATTR(psu_i_out, S_IRUGO, show_linear, NULL, PSU_I_OUT); -static SENSOR_DEVICE_ATTR(psu_p_out, S_IRUGO, show_linear, NULL, PSU_P_OUT); -static SENSOR_DEVICE_ATTR(psu_temp1_input, S_IRUGO, show_linear, NULL, PSU_TEMP1_INPUT); -static SENSOR_DEVICE_ATTR(psu_fan1_speed_rpm, S_IRUGO, show_linear, NULL, PSU_FAN1_SPEED); -static SENSOR_DEVICE_ATTR(psu_fan1_duty_cycle_percentage, S_IWUSR | S_IRUGO, show_linear, set_fan_duty_cycle, PSU_FAN1_DUTY_CYCLE); -static SENSOR_DEVICE_ATTR(psu_fan_dir, S_IRUGO, show_ascii, NULL, PSU_FAN_DIRECTION); -static SENSOR_DEVICE_ATTR(psu_pmbus_revision,S_IRUGO, show_byte, NULL, PSU_PMBUS_REVISION); -static SENSOR_DEVICE_ATTR(psu_mfr_id, S_IRUGO, show_ascii, NULL, PSU_MFR_ID); -static SENSOR_DEVICE_ATTR(psu_mfr_model, S_IRUGO, show_ascii, NULL, PSU_MFR_MODEL); -static SENSOR_DEVICE_ATTR(psu_mfr_revision, S_IRUGO, show_ascii, NULL, PSU_MFR_REVISION); -static SENSOR_DEVICE_ATTR(psu_mfr_vin_min, S_IRUGO, show_linear, NULL, PSU_MFR_VIN_MIN); -static SENSOR_DEVICE_ATTR(psu_mfr_vin_max, S_IRUGO, show_linear, NULL, PSU_MFR_VIN_MAX); -static SENSOR_DEVICE_ATTR(psu_mfr_vout_min, S_IRUGO, show_linear, NULL, PSU_MFR_VOUT_MIN); -static SENSOR_DEVICE_ATTR(psu_mfr_vout_max, S_IRUGO, show_linear, NULL, PSU_MFR_VOUT_MAX); -static SENSOR_DEVICE_ATTR(psu_mfr_iin_max, S_IRUGO, show_linear, NULL, PSU_MFR_IIN_MAX); -static SENSOR_DEVICE_ATTR(psu_mfr_iout_max, S_IRUGO, show_linear, NULL, PSU_MFR_IOUT_MAX); -static SENSOR_DEVICE_ATTR(psu_mfr_pin_max, S_IRUGO, show_linear, NULL, PSU_MFR_PIN_MAX); -static SENSOR_DEVICE_ATTR(psu_mfr_pout_max, S_IRUGO, show_linear, NULL, PSU_MFR_POUT_MAX); - -static struct attribute *ym2651y_attributes[] = { - &sensor_dev_attr_psu_power_on.dev_attr.attr, - &sensor_dev_attr_psu_temp_fault.dev_attr.attr, - &sensor_dev_attr_psu_power_good.dev_attr.attr, - &sensor_dev_attr_psu_fan1_fault.dev_attr.attr, - &sensor_dev_attr_psu_over_temp.dev_attr.attr, - &sensor_dev_attr_psu_v_out.dev_attr.attr, - &sensor_dev_attr_psu_i_out.dev_attr.attr, - &sensor_dev_attr_psu_p_out.dev_attr.attr, - &sensor_dev_attr_psu_temp1_input.dev_attr.attr, - &sensor_dev_attr_psu_fan1_speed_rpm.dev_attr.attr, - &sensor_dev_attr_psu_fan1_duty_cycle_percentage.dev_attr.attr, - &sensor_dev_attr_psu_fan_dir.dev_attr.attr, - &sensor_dev_attr_psu_pmbus_revision.dev_attr.attr, - &sensor_dev_attr_psu_mfr_id.dev_attr.attr, - &sensor_dev_attr_psu_mfr_model.dev_attr.attr, - &sensor_dev_attr_psu_mfr_revision.dev_attr.attr, - &sensor_dev_attr_psu_mfr_vin_min.dev_attr.attr, - &sensor_dev_attr_psu_mfr_vin_max.dev_attr.attr, - &sensor_dev_attr_psu_mfr_pout_max.dev_attr.attr, - &sensor_dev_attr_psu_mfr_iin_max.dev_attr.attr, - &sensor_dev_attr_psu_mfr_pin_max.dev_attr.attr, - &sensor_dev_attr_psu_mfr_vout_min.dev_attr.attr, - &sensor_dev_attr_psu_mfr_vout_max.dev_attr.attr, - &sensor_dev_attr_psu_mfr_iout_max.dev_attr.attr, - NULL -}; - -static ssize_t show_byte(struct device *dev, struct device_attribute *da, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct ym2651y_data *data = ym2651y_update_device(dev); - - if (!data->valid) { - return 0; - } - - return (attr->index == PSU_PMBUS_REVISION) ? sprintf(buf, "%d\n", data->pmbus_revision) : - sprintf(buf, "0\n"); -} - -static ssize_t show_word(struct device *dev, struct device_attribute *da, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct ym2651y_data *data = ym2651y_update_device(dev); - u16 status = 0; - - if (!data->valid) { - return 0; - } - - switch (attr->index) { - case PSU_POWER_ON: /* psu_power_on, low byte bit 6 of status_word, 0=>ON, 1=>OFF */ - status = (data->status_word & 0x40) ? 0 : 1; - break; - case PSU_TEMP_FAULT: /* psu_temp_fault, low byte bit 2 of status_word, 0=>Normal, 1=>temp fault */ - status = (data->status_word & 0x4) >> 2; - break; - case PSU_POWER_GOOD: /* psu_power_good, high byte bit 3 of status_word, 0=>OK, 1=>FAIL */ - status = (data->status_word & 0x800) ? 0 : 1; - break; - } - - return sprintf(buf, "%d\n", status); -} - -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; -} - -static ssize_t set_fan_duty_cycle(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 ym2651y_data *data = i2c_get_clientdata(client); - int nr = (attr->index == PSU_FAN1_DUTY_CYCLE) ? 0 : 1; - long speed; - int error; - - error = kstrtol(buf, 10, &speed); - if (error) - return error; - - if (speed < 0 || speed > MAX_FAN_DUTY_CYCLE) - return -EINVAL; - - mutex_lock(&data->update_lock); - data->fan_duty_cycle[nr] = speed; - ym2651y_write_word(client, 0x3B + nr, data->fan_duty_cycle[nr]); - mutex_unlock(&data->update_lock); - - return count; -} - -static ssize_t show_linear(struct device *dev, struct device_attribute *da, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct ym2651y_data *data = ym2651y_update_device(dev); - - u16 value = 0; - int exponent, mantissa; - int multiplier = 1000; - - if (!data->valid) { - return 0; - } - - switch (attr->index) { - case PSU_V_OUT: - value = data->v_out; - break; - case PSU_I_OUT: - value = data->i_out; - break; - case PSU_P_OUT: - value = data->p_out; - break; - case PSU_TEMP1_INPUT: - value = data->temp; - break; - case PSU_FAN1_SPEED: - value = data->fan_speed; - multiplier = 1; - break; - case PSU_FAN1_DUTY_CYCLE: - value = data->fan_duty_cycle[0]; - multiplier = 1; - break; - case PSU_MFR_VIN_MIN: - value = data->mfr_vin_min; - break; - case PSU_MFR_VIN_MAX: - value = data->mfr_vin_max; - break; - case PSU_MFR_VOUT_MIN: - value = data->mfr_vout_min; - break; - case PSU_MFR_VOUT_MAX: - value = data->mfr_vout_max; - break; - case PSU_MFR_PIN_MAX: - value = data->mfr_pin_max; - break; - case PSU_MFR_POUT_MAX: - value = data->mfr_pout_max; - break; - case PSU_MFR_IOUT_MAX: - value = data->mfr_iout_max; - break; - case PSU_MFR_IIN_MAX: - value = data->mfr_iin_max; - break; - } - - exponent = two_complement_to_int(value >> 11, 5, 0x1f); - mantissa = two_complement_to_int(value & 0x7ff, 11, 0x7ff); - - return (exponent >= 0) ? sprintf(buf, "%d\n", (mantissa << exponent) * multiplier) : - sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); -} - -static ssize_t show_fan_fault(struct device *dev, struct device_attribute *da, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct ym2651y_data *data = ym2651y_update_device(dev); - u8 shift; - - if (!data->valid) { - return 0; - } - - shift = (attr->index == PSU_FAN1_FAULT) ? 7 : 6; - - return sprintf(buf, "%d\n", data->fan_fault >> shift); -} - -static ssize_t show_over_temp(struct device *dev, struct device_attribute *da, - char *buf) -{ - struct ym2651y_data *data = ym2651y_update_device(dev); - - if (!data->valid) { - return 0; - } - - return sprintf(buf, "%d\n", data->over_temp >> 7); -} - -static ssize_t show_ascii(struct device *dev, struct device_attribute *da, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct ym2651y_data *data = ym2651y_update_device(dev); - u8 *ptr = NULL; - - if (!data->valid) { - return 0; - } - - switch (attr->index) { - case PSU_FAN_DIRECTION: /* psu_fan_dir */ - ptr = data->fan_dir + 1; /* Skip the first byte since it is the length of string. */ - break; - case PSU_MFR_ID: /* psu_mfr_id */ - ptr = data->mfr_id + 1; /* The first byte is the count byte of string. */; - break; - case PSU_MFR_MODEL: /* psu_mfr_model */ - ptr = data->mfr_model + 1; /* The first byte is the count byte of string. */ - break; - case PSU_MFR_REVISION: /* psu_mfr_revision */ - ptr = data->mfr_revsion + 1; /* The first byte is the count byte of string. */ - break; - default: - return 0; - } - - return sprintf(buf, "%s\n", ptr); -} - -static ssize_t show_vout_by_mode(struct device *dev, struct device_attribute *da, - char *buf) -{ - struct ym2651y_data *data = ym2651y_update_device(dev); - int exponent, mantissa; - int multiplier = 1000; - - if (!data->valid) { - return 0; - } - - exponent = two_complement_to_int(data->vout_mode, 5, 0x1f); - mantissa = data->v_out; - - return (exponent > 0) ? sprintf(buf, "%d\n", (mantissa << exponent) * multiplier) : - sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); -} - -static ssize_t show_vout(struct device *dev, struct device_attribute *da, - char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - struct ym2651y_data *data = i2c_get_clientdata(client); - - if (data->chip == YM2401) { - return show_vout_by_mode(dev, da, buf); - } - - return show_linear(dev, da, buf); -} - -static const struct attribute_group ym2651y_group = { - .attrs = ym2651y_attributes, -}; - -static int ym2651y_probe(struct i2c_client *client, - const struct i2c_device_id *dev_id) -{ - struct ym2651y_data *data; - int status; - - if (!i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_I2C_BLOCK)) { - status = -EIO; - goto exit; - } - - data = kzalloc(sizeof(struct ym2651y_data), GFP_KERNEL); - if (!data) { - status = -ENOMEM; - goto exit; - } - - i2c_set_clientdata(client, data); - mutex_init(&data->update_lock); - data->chip = dev_id->driver_data; - dev_info(&client->dev, "chip found\n"); - - /* Register sysfs hooks */ - status = sysfs_create_group(&client->dev.kobj, &ym2651y_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); - - return 0; - -exit_remove: - sysfs_remove_group(&client->dev.kobj, &ym2651y_group); -exit_free: - kfree(data); -exit: - - return status; -} - -static int ym2651y_remove(struct i2c_client *client) -{ - struct ym2651y_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &ym2651y_group); - kfree(data); - - return 0; -} - -static const struct i2c_device_id ym2651y_id[] = { - { "ym2651", YM2651 }, - { "ym2401", YM2401 }, - {} -}; -MODULE_DEVICE_TABLE(i2c, ym2651y_id); - -static struct i2c_driver ym2651y_driver = { - .class = I2C_CLASS_HWMON, - .driver = { - .name = "ym2651", - }, - .probe = ym2651y_probe, - .remove = ym2651y_remove, - .id_table = ym2651y_id, - .address_list = normal_i2c, -}; - -static int ym2651y_read_byte(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -static int ym2651y_read_word(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_word_data(client, reg); -} - -static int ym2651y_write_word(struct i2c_client *client, u8 reg, u16 value) -{ - return i2c_smbus_write_word_data(client, reg, value); -} - -static int ym2651y_read_block(struct i2c_client *client, u8 command, u8 *data, - int data_len) -{ - int result = i2c_smbus_read_i2c_block_data(client, command, data_len, data); - - if (unlikely(result < 0)) - goto abort; - if (unlikely(result != data_len)) { - result = -EIO; - goto abort; - } - - result = 0; - -abort: - return result; -} - -struct reg_data_byte { - u8 reg; - u8 *value; -}; - -struct reg_data_word { - u8 reg; - u16 *value; -}; - -static struct ym2651y_data *ym2651y_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct ym2651y_data *data = i2c_get_clientdata(client); - - mutex_lock(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - int i, status, length; - u8 command, buf; - struct reg_data_byte regs_byte[] = { {0x19, &data->capability}, - {0x20, &data->vout_mode}, - {0x7d, &data->over_temp}, - {0x81, &data->fan_fault}, - {0x98, &data->pmbus_revision}}; - struct reg_data_word regs_word[] = { {0x79, &data->status_word}, - {0x8b, &data->v_out}, - {0x8c, &data->i_out}, - {0x96, &data->p_out}, - {0x8d, &data->temp}, - {0x3b, &(data->fan_duty_cycle[0])}, - {0x3c, &(data->fan_duty_cycle[1])}, - {0x90, &data->fan_speed}, - {0xa0, &data->mfr_vin_min}, - {0xa1, &data->mfr_vin_max}, - {0xa2, &data->mfr_iin_max}, - {0xa3, &data->mfr_pin_max}, - {0xa4, &data->mfr_vout_min}, - {0xa5, &data->mfr_vout_max}, - {0xa6, &data->mfr_iout_max}, - {0xa7, &data->mfr_pout_max}}; - - dev_dbg(&client->dev, "Starting ym2651 update\n"); - data->valid = 0; - - /* Read byte data */ - for (i = 0; i < ARRAY_SIZE(regs_byte); i++) { - status = ym2651y_read_byte(client, regs_byte[i].reg); - - if (status < 0) { - dev_dbg(&client->dev, "reg %d, err %d\n", - regs_byte[i].reg, status); - goto exit; - } - else { - *(regs_byte[i].value) = status; - } - } - - /* Read word data */ - for (i = 0; i < ARRAY_SIZE(regs_word); i++) { - status = ym2651y_read_word(client, regs_word[i].reg); - - if (status < 0) { - dev_dbg(&client->dev, "reg %d, err %d\n", - regs_word[i].reg, status); - goto exit; - } - else { - *(regs_word[i].value) = status; - } - } - - /* Read fan_direction */ - command = 0xC3; - status = ym2651y_read_block(client, command, data->fan_dir, - ARRAY_SIZE(data->fan_dir)-1); - data->fan_dir[ARRAY_SIZE(data->fan_dir)-1] = '\0'; - - if (status < 0) { - dev_dbg(&client->dev, "reg %d, err %d\n", command, status); - goto exit; - } - - /* Read mfr_id */ - command = 0x99; - status = ym2651y_read_block(client, command, data->mfr_id, - ARRAY_SIZE(data->mfr_id)-1); - data->mfr_id[ARRAY_SIZE(data->mfr_id)-1] = '\0'; - - if (status < 0) { - dev_dbg(&client->dev, "reg %d, err %d\n", command, status); - goto exit; - } - - /* Read mfr_model */ - command = 0x9a; - length = 1; - - /* Read first byte to determine the length of data */ - status = ym2651y_read_block(client, command, &buf, length); - if (status < 0) { - dev_dbg(&client->dev, "reg %d, err %d\n", command, status); - goto exit; - } - - status = ym2651y_read_block(client, command, data->mfr_model, buf+1); - data->mfr_model[buf+1] = '\0'; - - if (status < 0) { - dev_dbg(&client->dev, "reg %d, err %d\n", command, status); - goto exit; - } - - /* Read mfr_revsion */ - command = 0x9b; - status = ym2651y_read_block(client, command, data->mfr_revsion, - ARRAY_SIZE(data->mfr_revsion)-1); - data->mfr_revsion[ARRAY_SIZE(data->mfr_revsion)-1] = '\0'; - - if (status < 0) { - dev_dbg(&client->dev, "reg %d, err %d\n", command, status); - goto exit; - } - - data->last_updated = jiffies; - data->valid = 1; - } - -exit: - mutex_unlock(&data->update_lock); - - return data; -} - -static int __init ym2651y_init(void) -{ - return i2c_add_driver(&ym2651y_driver); -} - -static void __exit ym2651y_exit(void) -{ - i2c_del_driver(&ym2651y_driver); -} - -MODULE_AUTHOR("Brandon Chuang "); -MODULE_DESCRIPTION("3Y Power YM-2651Y driver"); -MODULE_LICENSE("GPL"); - -module_init(ym2651y_init); -module_exit(ym2651y_exit); - diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/ym2651y.c b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/ym2651y.c new file mode 120000 index 00000000000..f4d67640ccc --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/ym2651y.c @@ -0,0 +1 @@ +../../common/modules/ym2651y.c \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/sonic_platform_setup.py b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/sonic_platform_setup.py new file mode 100644 index 00000000000..9a5c95c4143 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/sonic_platform_setup.py @@ -0,0 +1,34 @@ +from setuptools import setup + +DEVICE_NAME = 'accton' +HW_SKU = 'x86_64-accton_as5812_54x-r0' + +setup( + name='sonic-platform', + version='1.0', + description='SONiC platform API implementation on Accton Platforms', + license='Apache 2.0', + author='SONiC Team', + author_email='linuxnetdev@microsoft.com', + url='https://github.com/Azure/sonic-buildimage', + maintainer='Jostar Yang', + maintainer_email='jostar_yang@edge-core.com', + packages=[ + 'sonic_platform', + ], + package_dir={ + 'sonic_platform': '../../../../device/{}/{}/sonic_platform'.format(DEVICE_NAME, HW_SKU)}, + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Environment :: Plugins', + 'Intended Audience :: Developers', + 'Intended Audience :: Information Technology', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: Apache Software License', + 'Natural Language :: English', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: Python :: 3.7', + 'Topic :: Utilities', + ], + keywords='sonic SONiC platform PLATFORM', +) diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/utils/accton_as5812_util.py b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/utils/accton_as5812_util.py index 05ebcb42069..0710d3547e9 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/utils/accton_as5812_util.py +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/utils/accton_as5812_util.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # # Copyright (C) 2016 Accton Networks, Inc. # @@ -24,9 +24,6 @@ command: install : install drivers and generate related sysfs nodes clean : uninstall drivers and remove related sysfs nodes - show : show all systen status - sff : dump SFP eeprom - set : change board setting with fan|led|sfp """ import os @@ -34,7 +31,6 @@ import getopt import sys import logging -import re import time PROJECT_NAME = 'as5812_54x' @@ -46,38 +42,12 @@ DEVICE_NO = {'led':5, 'fan1':1, 'fan2':1,'fan3':1,'fan4':1,'fan5':1,'thermal':3, 'psu':2, 'sfp':54} -led_prefix ='/sys/devices/platform/as5812_54x_led/leds/accton_'+PROJECT_NAME+'_led::' -fan_prefix ='/sys/devices/platform/as5812_54x_' -hwmon_types = {'led': ['diag','fan','loc','psu1','psu2'], - 'fan1': ['fan'], - 'fan2': ['fan'], - 'fan3': ['fan'], - 'fan4': ['fan'], - 'fan5': ['fan'], - } -hwmon_nodes = {'led': ['brightness'] , - 'fan1': ['fan1_duty_cycle_percentage', 'fan1_fault', 'fan1_speed_rpm', 'fan1_direction', 'fanr1_fault', 'fanr1_speed_rpm'], - 'fan2': ['fan2_duty_cycle_percentage','fan2_fault', 'fan2_speed_rpm', 'fan2_direction', 'fanr2_fault', 'fanr2_speed_rpm'], - 'fan3': ['fan3_duty_cycle_percentage','fan3_fault', 'fan3_speed_rpm', 'fan3_direction', 'fanr3_fault', 'fanr3_speed_rpm'], - 'fan4': ['fan4_duty_cycle_percentage','fan4_fault', 'fan4_speed_rpm', 'fan4_direction', 'fanr4_fault', 'fanr4_speed_rpm'], - 'fan5': ['fan5_duty_cycle_percentage','fan5_fault', 'fan5_speed_rpm', 'fan5_direction', 'fanr5_fault', 'fanr5_speed_rpm'], - } -hwmon_prefix ={'led': led_prefix, - 'fan1': fan_prefix, - 'fan2': fan_prefix, - 'fan3': fan_prefix, - 'fan4': fan_prefix, - 'fan5': fan_prefix, - } - i2c_prefix = '/sys/bus/i2c/devices/' +''' i2c_bus = {'thermal': ['61-0048','62-0049', '63-004a'] , 'psu': ['57-0050','58-0053'], 'sfp': ['-0050']} -i2c_nodes = { - 'thermal': ['hwmon/hwmon*/temp1_input'] , - 'psu': ['psu_present ', 'psu_power_good'] , - 'sfp': ['sfp_is_present ', 'sfp_tx_disable']} +''' QSFP_START = 48 @@ -101,11 +71,13 @@ 'echo as5812_54x_psu1 0x38 > /sys/bus/i2c/devices/i2c-57/new_device', 'echo cpr_4011_4mxx 0x3c > /sys/bus/i2c/devices/i2c-57/new_device', 'echo as5812_54x_psu1 0x50 > /sys/bus/i2c/devices/i2c-57/new_device', +'echo ym2401 0x58 > /sys/bus/i2c/devices/i2c-57/new_device', # PSU-2 'echo as5812_54x_psu2 0x3b > /sys/bus/i2c/devices/i2c-58/new_device', 'echo cpr_4011_4mxx 0x3f > /sys/bus/i2c/devices/i2c-58/new_device', 'echo as5812_54x_psu2 0x53 > /sys/bus/i2c/devices/i2c-58/new_device', +'echo ym2401 0x5b > /sys/bus/i2c/devices/i2c-58/new_device', 'echo lm75 0x48 > /sys/bus/i2c/devices/i2c-61/new_device', 'echo lm75 0x49 > /sys/bus/i2c/devices/i2c-62/new_device', @@ -125,11 +97,13 @@ 'echo as5812_54x_psu1 0x38 > /sys/bus/i2c/devices/i2c-57/new_device', 'echo cpr_4011_4mxx 0x3c > /sys/bus/i2c/devices/i2c-57/new_device', 'echo as5812_54x_psu1 0x50 > /sys/bus/i2c/devices/i2c-57/new_device', +'echo ym2401 0x58 > /sys/bus/i2c/devices/i2c-57/new_device', # PSU-2 'echo as5812_54x_psu2 0x3b > /sys/bus/i2c/devices/i2c-58/new_device', 'echo cpr_4011_4mxx 0x3f > /sys/bus/i2c/devices/i2c-58/new_device', 'echo as5812_54x_psu2 0x53 > /sys/bus/i2c/devices/i2c-58/new_device', +'echo ym2401 0x5b > /sys/bus/i2c/devices/i2c-58/new_device', 'echo lm75 0x48 > /sys/bus/i2c/devices/i2c-61/new_device', 'echo lm75 0x49 > /sys/bus/i2c/devices/i2c-62/new_device', @@ -181,22 +155,10 @@ def main(): do_install() elif arg == 'clean': do_uninstall() - elif arg == 'show': - device_traversal() - elif arg == 'sff': - if len(args)!=2: - show_eeprom_help() - elif int(args[1]) ==0 or int(args[1]) > DEVICE_NO['sfp']: - show_eeprom_help() - else: - show_eeprom(args[1]) - return - elif arg == 'set': - if len(args)<3: - show_set_help() - else: - set_device(args[1:]) - return + elif arg == 'api': + do_sonic_platform_install() + elif arg == 'api_clean': + do_sonic_platform_clean() else: show_help() @@ -207,18 +169,6 @@ def show_help(): print(__doc__ % {'scriptName' : sys.argv[0].split("/")[-1]}) sys.exit(0) -def show_set_help(): - cmd = sys.argv[0].split("/")[-1]+ " " + args[0] - print(cmd +" [led|sfp|fan]") - print(" use \""+ cmd + " led 0-4 \" to set led color") - print(" use \""+ cmd + " fan 0-100\" to set fan duty percetage") - print(" use \""+ cmd + " sfp 1-48 {0|1}\" to set sfp# tx_disable") - sys.exit(0) - -def show_eeprom_help(): - cmd = sys.argv[0].split("/")[-1]+ " " + args[0] - print(" use \""+ cmd + " 1-54 \" to dump sfp# eeprom") - sys.exit(0) def my_log(txt): if DEBUG == True: @@ -252,7 +202,9 @@ def driver_inserted(): kos = [ 'depmod -ae', 'modprobe i2c_dev', -'modprobe i2c_mux_pca954x force_deselect_on_exit=1', +'modprobe i2c_mux_pca954x', +'modprobe i2c_i801', +'modprobe i2c_ismt', 'modprobe optoe', 'modprobe i2c-mux-accton_as5812_54x_cpld', 'modprobe cpr_4011_4mxx', @@ -268,6 +220,9 @@ def driver_install(): if status: if FORCE == 0: return status + + print("Done driver_install") + return 0 def driver_uninstall(): @@ -335,6 +290,14 @@ def device_install(): if FORCE == 0: return status + # set all pca954x idle_disconnect + cmd = 'echo -2 | tee /sys/bus/i2c/drivers/pca954x/*-00*/idle_state' + status, output = log_os_system(cmd, 1) + if status: + print(output) + if FORCE == 0: + return status + for i in range(0,len(sfp_map)): if i < QSFP_START: status, output =log_os_system("echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/new_device", 1) @@ -349,6 +312,8 @@ def device_install(): print(output) if FORCE == 0: return status + + print("Done device_install") return @@ -389,6 +354,45 @@ def system_ready(): return False return True + +PLATFORM_ROOT_PATH = '/usr/share/sonic/device' +PLATFORM_API2_WHL_FILE_PY3 ='sonic_platform-1.0-py3-none-any.whl' +def do_sonic_platform_install(): + device_path = "{}{}{}{}".format(PLATFORM_ROOT_PATH, '/x86_64-accton_', PROJECT_NAME, '-r0') + SONIC_PLATFORM_BSP_WHL_PKG_PY3 = "/".join([device_path, PLATFORM_API2_WHL_FILE_PY3]) + + #Check API2.0 on py whl file + status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0) + if status: + if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_PY3): + status, output = log_os_system("pip3 install "+ SONIC_PLATFORM_BSP_WHL_PKG_PY3, 1) + if status: + print("Error: Failed to install {}".format(PLATFORM_API2_WHL_FILE_PY3)) + return status + else: + print("Successfully installed {} package".format(PLATFORM_API2_WHL_FILE_PY3)) + else: + print('{} is not found'.format(PLATFORM_API2_WHL_FILE_PY3)) + else: + print('{} has installed'.format(PLATFORM_API2_WHL_FILE_PY3)) + + return + +def do_sonic_platform_clean(): + status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0) + if status: + print('{} does not install, not need to uninstall'.format(PLATFORM_API2_WHL_FILE_PY3)) + + else: + status, output = log_os_system("pip3 uninstall sonic-platform -y", 0) + if status: + print('Error: Failed to uninstall {}'.format(PLATFORM_API2_WHL_FILE_PY3)) + return status + else: + print('{} is uninstalled'.format(PLATFORM_API2_WHL_FILE_PY3)) + + return + def do_install(): print("Checking system....") if driver_inserted() == False: @@ -407,6 +411,8 @@ def do_install(): return status else: print(PROJECT_NAME.upper()+" devices detected....") + do_sonic_platform_install() + return def do_uninstall(): @@ -428,93 +434,10 @@ def do_uninstall(): if status: if FORCE == 0: return status + do_sonic_platform_clean() return -def devices_info(): - global DEVICE_NO - global ALL_DEVICE - global i2c_bus, hwmon_types - for key in DEVICE_NO: - ALL_DEVICE[key]= {} - for i in range(0,DEVICE_NO[key]): - ALL_DEVICE[key][key+str(i+1)] = [] - - for key in i2c_bus: - buses = i2c_bus[key] - nodes = i2c_nodes[key] - for i in range(0,len(buses)): - for j in range(0,len(nodes)): - if 'fan' == key: - for k in range(0,DEVICE_NO[key]): - node = key+str(k+1) - path = i2c_prefix+ buses[i]+"/fan"+str(k+1)+"_"+ nodes[j] - my_log(node+": "+ path) - ALL_DEVICE[key][node].append(path) - elif 'sfp' == key: - for k in range(0,DEVICE_NO[key]): - node = key+str(k+1) - path = i2c_prefix+ str(sfp_map[k])+ buses[i]+"/"+ nodes[j] - my_log(node+": "+ path) - ALL_DEVICE[key][node].append(path) - else: - node = key+str(i+1) - path = i2c_prefix+ buses[i]+"/"+ nodes[j] - my_log(node+": "+ path) - ALL_DEVICE[key][node].append(path) - - for key in hwmon_types: - itypes = hwmon_types[key] - nodes = hwmon_nodes[key] - for i in range(0,len(itypes)): - for j in range(0,len(nodes)): - node = key+"_"+itypes[i] - path = hwmon_prefix[key]+ itypes[i]+"/"+ nodes[j] - my_log(node+": "+ path) - ALL_DEVICE[key][ key+str(i+1)].append(path) - - #show dict all in the order - if DEBUG == True: - for i in sorted(ALL_DEVICE.keys()): - print((i+": ")) - for j in sorted(ALL_DEVICE[i].keys()): - print((" "+j)) - for k in (ALL_DEVICE[i][j]): - print((" "+" "+k)) - return - -def show_eeprom(index): - if system_ready()==False: - print("System's not ready.") - print("Please install first!") - return - - if len(ALL_DEVICE)==0: - devices_info() - node = ALL_DEVICE['sfp'] ['sfp'+str(index)][0] - node = node.replace(node.split("/")[-1], 'eeprom') - # check if got hexdump command in current environment - ret, log = log_os_system("which hexdump", 0) - ret, log2 = log_os_system("which busybox hexdump", 0) - if len(log): - hex_cmd = 'hexdump' - elif len(log2): - hex_cmd = ' busybox hexdump' - else: - log = 'Failed : no hexdump cmd!!' - logging.info(log) - print(log) - return 1 - - print(node + ":") - ret, log = log_os_system("cat "+node+"| "+hex_cmd+" -C", 1) - if ret==0: - print(log) - else: - print("**********device no found**********") - return - - def get_cpld_path(index): order = get_i2c_order() if order !=0 : @@ -546,124 +469,6 @@ def get_path_sfp_presence(port_index): dev = cpld_p+"module_present_"+str(port_index) return True, dev - -def set_device(args): - global DEVICE_NO - global ALL_DEVICE - if system_ready()==False: - print("System's not ready.") - print("Please install first!") - return - - if len(ALL_DEVICE)==0: - devices_info() - - if args[0]=='led': - if int(args[1])>4: - show_set_help() - return - #print ALL_DEVICE['led'] - for i in range(0,len(ALL_DEVICE['led'])): - for k in (ALL_DEVICE['led']['led'+str(i+1)]): - ret, log = log_os_system("echo "+args[1]+" >"+k, 1) - if ret: - return ret - elif args[0]=='fan': - if int(args[1])>100: - show_set_help() - return - #print ALL_DEVICE['fan'] - #fan1~6 is all fine, all fan share same setting - node = ALL_DEVICE['fan1'] ['fan11'][0] - node = node.replace(node.split("/")[-1], 'fan1_duty_cycle_percentage') - ret, log = log_os_system("cat "+ node, 1) - if ret==0: - print(("Previous fan duty: " + log.strip() +"%")) - ret, log = log_os_system("echo "+args[1]+" >"+node, 1) - if ret==0: - print(("Current fan duty: " + args[1] +"%")) - return ret - elif args[0]=='sfp': - #if int(args[1])> DEVICE_NO[args[0]] or int(args[1])==0: - #There no tx_disable for QSFP port - if int(args[1]) > QSFP_START or int(args[1])==0: - show_set_help() - return - if len(args)<2: - show_set_help() - return - - if int(args[2])>1: - show_set_help() - return - - port_index = int(args[1]) - ret, dev = get_path_sfp_tx_dis(port_index) - if ret == False: - return False - else: - ret, log = log_os_system("echo "+args[2]+" >"+ dev, 1) - return ret - return - -#get digits inside a string. -#Ex: 31 for "sfp31" -def get_value(input): - digit = re.findall('\d+', input) - return int(digit[0]) - -def print_1_device_traversal(i, j, k): - ret, log = log_os_system("cat "+k, 0) - func = k.split("/")[-1].strip() - func = re.sub(j+'_','',func,1) - func = re.sub(i.lower()+'_','',func,1) - if ret==0: - return func+"="+log+" " - else: - return func+"="+"X"+" " - -def device_traversal(): - if system_ready()==False: - print("System's not ready.") - print("Please install first!") - return - - if len(ALL_DEVICE)==0: - devices_info() - for i in sorted(ALL_DEVICE.keys()): - print("============================================") - print((i.upper()+": ")) - print("============================================") - - for j in sorted(list(ALL_DEVICE[i].keys()), key=get_value): - print(" "+j+":", end=' ') - if i == 'sfp': - port_index = int(list(filter(str.isdigit, j))) - for k in (ALL_DEVICE[i][j]): - if k.find('tx_disable')!= -1: - ret, k = get_path_sfp_tx_dis(port_index) - if ret == False: - continue - log = print_1_device_traversal(i, j, k) - print(log, end=' ') - if k.find('present')!= -1: - ret, k = get_path_sfp_presence(port_index) - if ret == False: - continue - log = print_1_device_traversal(i, j, k) - print(log, end=' ') - - else: - for k in (ALL_DEVICE[i][j]): - log = print_1_device_traversal(i, j, k) - print(log, end=' ') - print() - print("----------------------------------------------------------------") - - - print() - return - def device_exist(): ret1, log = log_os_system("ls "+i2c_prefix+"*0070", 0) ret2, log = log_os_system("ls "+i2c_prefix+"i2c-2", 0) diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/modules/Makefile b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/modules/Makefile index 887ac3189ce..efc76e21dca 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/modules/Makefile +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/modules/Makefile @@ -1,7 +1,7 @@ ifneq ($(KERNELRELEASE),) obj-m:= accton_as5835_54t_cpld.o accton_as5835_54t_psu.o \ accton_as5835_54t_fan.o accton_as5835_54t_leds.o \ - ym2651y.o + ym2651y.o pddf_custom_psu.o else ifeq (,$(KERNEL_SRC)) diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/modules/pddf_custom_psu.c b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/modules/pddf_custom_psu.c new file mode 100644 index 00000000000..e9356b28907 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/modules/pddf_custom_psu.c @@ -0,0 +1,123 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../../../pddf/i2c/modules/include/pddf_psu_defs.h" + +ssize_t pddf_show_custom_psu_v_out(struct device *dev, struct device_attribute *da, char *buf); +extern PSU_SYSFS_ATTR_DATA access_psu_v_out; + +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; +} + +static u8 psu_get_vout_mode(struct i2c_client *client) +{ + u8 status = 0, retry = 10; + uint8_t offset = 0x20; // VOUT_MODE + + while (retry) { + status = i2c_smbus_read_byte_data((struct i2c_client *)client, offset); + if (unlikely(status < 0)) { + msleep(60); + retry--; + continue; + } + break; + } + + if (status < 0) + { + printk(KERN_ERR "%s: Get PSU Vout mode failed\n", __func__); + return 0; + } + else + { + /*printk(KERN_ERR "%s: vout_mode reg value 0x%x\n", __func__, status);*/ + return status; + } +} + +static u16 psu_get_v_out(struct i2c_client *client) +{ + u16 status = 0, retry = 10; + uint8_t offset = 0x8b; // READ_VOUT + + 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) + { + printk(KERN_ERR "%s: Get PSU Vout failed\n", __func__); + return 0; + } + else + { + /*printk(KERN_ERR "%s: vout reg value 0x%x\n", __func__, status);*/ + return status; + } +} + +ssize_t pddf_show_custom_psu_v_out(struct device *dev, struct device_attribute *da, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + int exponent, mantissa; + int multiplier = 1000; + + u16 value = psu_get_v_out(client); + u8 vout_mode = psu_get_vout_mode(client); + + if ((vout_mode >> 5) == 0) + exponent = two_complement_to_int(vout_mode & 0x1f, 5, 0x1f); + else + { + printk(KERN_ERR "%s: Only support linear mode for vout mode\n", __func__); + exponent = 0; + } + mantissa = value; + if (exponent >= 0) + return sprintf(buf, "%d\n", (mantissa << exponent) * multiplier); + else + return sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); +} + + + +static int __init pddf_custom_psu_init(void) +{ + access_psu_v_out.show = pddf_show_custom_psu_v_out; + access_psu_v_out.do_get = NULL; + return 0; +} + +static void __exit pddf_custom_psu_exit(void) +{ + return; +} + +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("pddf custom psu api"); +MODULE_LICENSE("GPL"); + +module_init(pddf_custom_psu_init); +module_exit(pddf_custom_psu_exit); + diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/service/as5835-54t-pddf-platform-monitor.service b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/service/as5835-54t-pddf-platform-monitor.service new file mode 100644 index 00000000000..517f29eab4d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/service/as5835-54t-pddf-platform-monitor.service @@ -0,0 +1,16 @@ +[Unit] +Description=Accton AS5835-54T Platform Monitoring service +Before=pmon.service +After=pddf-platform-init.service +DefaultDependencies=no + +[Service] +ExecStart=/usr/local/bin/accton_as5835_54t_pddf_monitor.py +KillSignal=SIGKILL +SuccessExitStatus=SIGKILL + +# Resource Limitations +LimitCORE=infinity + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/service/pddf-platform-init.service b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/service/pddf-platform-init.service new file mode 120000 index 00000000000..0fd9f25b6c5 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/service/pddf-platform-init.service @@ -0,0 +1 @@ +../../../../pddf/i2c/service/pddf-platform-init.service \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/__init__.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/__init__.py new file mode 100644 index 00000000000..cdc3b813f64 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/__init__.py @@ -0,0 +1,3 @@ +# All the derived classes for PDDF +__all__ = ["platform", "chassis", "sfp", "psu", "thermal", "fan"] +from . import platform diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/chassis.py new file mode 100644 index 00000000000..8a98bf8326f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/chassis.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python + +############################################################################# +# PDDF +# Module contains an implementation of SONiC Chassis API +# +############################################################################# + +try: + import sys + from sonic_platform_pddf_base.pddf_chassis import PddfChassis + from .event import SfpEvent +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +NUM_COMPONENT = 4 + +class Chassis(PddfChassis): + """ + PDDF Platform-specific Chassis class + """ + + SYSLED_DEV_NAME = "DIAG_LED" + + def __init__(self, pddf_data=None, pddf_plugin_data=None): + PddfChassis.__init__(self, pddf_data, pddf_plugin_data) + self.__initialize_components() + self._sfpevent = SfpEvent(self.get_all_sfps()) + + def __initialize_components(self): + from sonic_platform.component import Component + for index in range(NUM_COMPONENT): + component = Component(index) + self._component_list.append(component) + + # Provide the functions/variables below for which implementation is to be overwritten + def get_change_event(self, timeout=0): + return self._sfpevent.get_sfp_event(timeout) + + def get_sfp(self, index): + """ + Retrieves sfp represented by (1-based) index + + Args: + index: An integer, the index (1-based) of the sfp to retrieve. + The index should be the sequence of a physical port in a chassis, + starting from 1. + For example, 1 for Ethernet0, 2 for Ethernet4 and so on. + + Returns: + An object derived from SfpBase representing the specified sfp + """ + sfp = None + + try: + # The index will start from 1 + sfp = self._sfp_list[index-1] + except IndexError: + sys.stderr.write("SFP index {} out of range (1-{})\n".format( + index, len(self._sfp_list))) + return sfp + + def initizalize_system_led(self): + return + + def get_status_led(self): + return self.get_system_led(self.SYSLED_DEV_NAME) + + def set_status_led(self, color): + return self.set_system_led(self.SYSLED_DEV_NAME, color) diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/component.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/component.py new file mode 100644 index 00000000000..7d043f7dae1 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/component.py @@ -0,0 +1,115 @@ +############################################################################# +# +# Component contains an implementation of SONiC Platform Base API and +# provides the components firmware management function +# +############################################################################# + +try: + import subprocess + from sonic_platform_base.component_base import ComponentBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +CPLD_ADDR_MAPPING = { + "CPLD1": ['3', '0x60'], + "CPLD2": ['3', '0x61'], + "CPLD3": ['3', '0x62'] +} +SYSFS_PATH = "/sys/bus/i2c/devices/" +BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version" +COMPONENT_LIST= [ + ("CPLD1", "CPLD 1"), + ("CPLD2", "CPLD 2"), + ("CPLD3", "CPLD 3"), + ("BIOS", "Basic Input/Output System") + +] + +class Component(ComponentBase): + """Platform-specific Component class""" + + DEVICE_TYPE = "component" + + def __init__(self, component_index=0): + self.index = component_index + self.name = self.get_name() + + def __run_command(self, command): + # Run bash command and print output to stdout + try: + process = subprocess.Popen( + shlex.split(command), stdout=subprocess.PIPE) + while True: + output = process.stdout.readline() + if output == '' and process.poll() is not None: + break + rc = process.poll() + if rc != 0: + return False + except Exception: + return False + return True + + def __get_bios_version(self): + # Retrieves the BIOS firmware version + try: + with open(BIOS_VERSION_PATH, 'r') as fd: + bios_version = fd.read() + return bios_version.strip() + except Exception as e: + return None + + def __get_cpld_version(self): + # Retrieves the CPLD firmware version + cpld_version = dict() + for cpld_name in CPLD_ADDR_MAPPING: + cmd = "i2cget -f -y {0} {1} 0x1".format(CPLD_ADDR_MAPPING[cpld_name][0], CPLD_ADDR_MAPPING[cpld_name][1]) + status, value = subprocess.getstatusoutput(cmd) + if not status: + cpld_version_raw = value.rstrip() + cpld_version[cpld_name] = "{}".format(int(cpld_version_raw,16)) + + return cpld_version + + def get_name(self): + """ + Retrieves the name of the component + Returns: + A string containing the name of the component + """ + return COMPONENT_LIST[self.index][0] + + def get_description(self): + """ + Retrieves the description of the component + Returns: + A string containing the description of the component + """ + return COMPONENT_LIST[self.index][1] + + def get_firmware_version(self): + """ + Retrieves the firmware version of module + Returns: + string: The firmware versions of the module + """ + fw_version = None + + if self.name == "BIOS": + fw_version = self.__get_bios_version() + elif "CPLD" in self.name: + cpld_version = self.__get_cpld_version() + fw_version = cpld_version.get(self.name) + + return fw_version + + def install_firmware(self, image_path): + """ + Install firmware to module + Args: + image_path: A string, path to firmware image + Returns: + A boolean, True if install successfully, False if not + """ + raise NotImplementedError diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/eeprom.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/eeprom.py new file mode 100644 index 00000000000..a87ecc9f6fe --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/eeprom.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python + +try: + from sonic_platform_pddf_base.pddf_eeprom import PddfEeprom +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Eeprom(PddfEeprom): + + def __init__(self, pddf_data=None, pddf_plugin_data=None): + PddfEeprom.__init__(self, pddf_data, pddf_plugin_data) + + # Provide the functions/variables below for which implementation is to be overwritten diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/event.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/event.py new file mode 100644 index 00000000000..d5dac6d7f7e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/event.py @@ -0,0 +1,60 @@ +try: + import time + from sonic_py_common.logger import Logger +except ImportError as e: + raise ImportError(repr(e) + " - required module not found") + +POLL_INTERVAL_IN_SEC = 1 + +class SfpEvent: + ''' Listen to insert/remove sfp events ''' + + def __init__(self, sfp_list): + self._sfp_list = sfp_list + self._logger = Logger() + self._sfp_change_event_data = {'present': 0} + + def get_presence_bitmap(self): + bitmap = 0 + for sfp in self._sfp_list: + modpres = sfp.get_presence() + i=sfp.get_position_in_parent() - 1 + if modpres: + bitmap = bitmap | (1 << i) + return bitmap + + def get_sfp_event(self, timeout=2000): + port_dict = {} + change_dict = {} + change_dict['sfp'] = port_dict + + if timeout < 1000: + cd_ms = 1000 + else: + cd_ms = timeout + + while cd_ms > 0: + bitmap = self.get_presence_bitmap() + changed_ports = self._sfp_change_event_data['present'] ^ bitmap + if changed_ports != 0: + break + time.sleep(POLL_INTERVAL_IN_SEC) + # timeout=0 means wait for event forever + if timeout != 0: + cd_ms = cd_ms - POLL_INTERVAL_IN_SEC * 1000 + + if changed_ports != 0: + for sfp in self._sfp_list: + i=sfp.get_position_in_parent() - 1 + if (changed_ports & (1 << i)): + if (bitmap & (1 << i)) == 0: + port_dict[i+1] = '0' + else: + port_dict[i+1] = '1' + + + # Update the cache dict + self._sfp_change_event_data['present'] = bitmap + return True, change_dict + else: + return True, change_dict diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/fan.py new file mode 100644 index 00000000000..ef25008dba5 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/fan.py @@ -0,0 +1,48 @@ +#!/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 + # Since psu_fan airflow direction cant be read from sysfs, it is fixed as 'F2B' or 'intake' + 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: + direction = self.FAN_DIRECTION_INTAKE + + 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 + diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/platform.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/platform.py new file mode 100644 index 00000000000..406b1179ae1 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/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/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/psu.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/psu.py new file mode 100644 index 00000000000..a2a33020655 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/psu.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python +# + + +try: + from sonic_platform_pddf_base.pddf_psu import PddfPsu +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + + +class Psu(PddfPsu): + """PDDF Platform-Specific PSU class""" + + PLATFORM_PSU_CAPACITY = 1200 + + def __init__(self, index, pddf_data=None, pddf_plugin_data=None): + PddfPsu.__init__(self, index, pddf_data, pddf_plugin_data) + + # Provide the functions/variables below for which implementation is to be overwritten + def get_maximum_supplied_power(self): + """ + Retrieves the maximum supplied power by PSU (or PSU capacity) + Returns: + A float number, the maximum power output in Watts. + e.g. 1200.1 + """ + return float(self.PLATFORM_PSU_CAPACITY) + + def get_capacity(self): + """ + Gets the capacity (maximum output power) of the PSU in watts + + Returns: + An integer, the capacity of PSU + """ + return (self.PLATFORM_PSU_CAPACITY) + + def get_type(self): + """ + Gets the type of the PSU + Returns: + A string, the type of PSU (AC/DC) + """ + return "AC" diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/sfp.py new file mode 100644 index 00000000000..c9fb07d6364 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/sfp.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python + +try: + from sonic_platform_pddf_base.pddf_sfp import PddfSfp +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + + +class Sfp(PddfSfp): + """ + PDDF Platform-Specific Sfp class + """ + + def __init__(self, index, pddf_data=None, pddf_plugin_data=None): + PddfSfp.__init__(self, index, pddf_data, pddf_plugin_data) + + # Provide the functions/variables below for which implementation is to be overwritten + def get_position_in_parent(self): + """Retrieves 1-based relative physical position in parent device.""" + return self.port_index diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/thermal.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/thermal.py new file mode 100644 index 00000000000..5b829fc26ca --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/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/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/watchdog.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/watchdog.py new file mode 100644 index 00000000000..88660b1a1fa --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform/watchdog.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python + +############################################################################# +# +# Module contains an implementation of platform specific watchdog API's +# +############################################################################# + +try: + from sonic_platform_pddf_base.pddf_watchdog import PddfWatchdog +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +class Watchdog(PddfWatchdog): + """ + PDDF Platform-specific Chassis class + """ + + def __init__(self): + PddfWatchdog.__init__(self) + self.timeout= 180 + + # Provide the functions/variables below for which implementation is to be overwritten diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform_setup.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform_setup.py new file mode 100644 index 00000000000..22bd354ea68 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/sonic_platform_setup.py @@ -0,0 +1,25 @@ +from setuptools import setup + +setup( + name='sonic-platform', + version='1.0', + description='SONiC platform API implementation on Accton Platforms', + license='Apache 2.0', + author='SONiC Team', + author_email='linuxnetdev@microsoft.com', + url='https://github.com/Azure/sonic-buildimage', + packages=['sonic_platform'], + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Environment :: Plugins', + 'Intended Audience :: Developers', + 'Intended Audience :: Information Technology', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: Apache Software License', + 'Natural Language :: English', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: Python :: 3.7', + 'Topic :: Utilities', + ], + keywords='sonic SONiC platform PLATFORM', +) diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/utils/accton_as5835_54t_pddf_monitor.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/utils/accton_as5835_54t_pddf_monitor.py new file mode 100755 index 00000000000..88ca087b338 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/utils/accton_as5835_54t_pddf_monitor.py @@ -0,0 +1,236 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2019 Accton Technology Corporation +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# ------------------------------------------------------------------ +# HISTORY: +# mm/dd/yyyy (A.D.) +# 05/29/2019: Brandon Chuang, changed for as5835-54t. +# 08/03/2020: Jostar Yang, change to call PDDF API . +# ------------------------------------------------------------------ + +try: + import sys, getopt + import logging + import logging.config + import time + import signal + from sonic_platform import platform +except ImportError as e: + raise ImportError('%s - required module not found' % str(e)) + +# Deafults +VERSION = '1.0' +FUNCTION_NAME = 'accton_as5835_54t_pddf_monitor' +DUTY_MAX = 100 + +platform_chassis = None + +test_temp = 0 +test_temp_list = [0, 0, 0, 0] +test_temp_revert=0 +temp_test_data=0 + +# Make a class we can use to capture stdout and sterr in the log +class accton_as5835_54t_monitor(object): + # static temp var + _ori_temp = 0 + _new_perc = 0 + + def __init__(self, log_file, log_level): + """Needs a logger and a logger level.""" + # set up logging to file + logging.basicConfig( + filename=log_file, + filemode='w', + level=log_level, + format= '[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s', + datefmt='%H:%M:%S' + ) + + # set up logging to console + if log_level == logging.DEBUG: + console = logging.StreamHandler() + console.setLevel(log_level) + formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') + console.setFormatter(formatter) + logging.getLogger('').addHandler(console) + + logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level) + + def manage_fans(self): + global platform_chassis + global test_temp_list + global temp_test_data + global test_temp + + THERMAL_NUM_MAX=4 + FAN_LEV1_UP_TEMP = 57700 # temperature + FAN_LEV1_SPEED_PERC = DUTY_MAX # percentage*/ + + FAN_LEV2_UP_TEMP = 53000 + FAN_LEV2_DOWN_TEMP = 52700 + FAN_LEV2_SPEED_PERC = 80 + + FAN_LEV3_UP_TEMP = 49500 + FAN_LEV3_DOWN_TEMP = 47700 + FAN_LEV3_SPEED_PERC = 65 + + FAN_LEV4_DOWN_TEMP = 42700 + FAN_LEV4_SPEED_PERC = 40 + + FAN_NUM=2 + FAN_TRAY_NUM=5 + + if test_temp_revert==0: + temp_test_data=temp_test_data+2000 + else: + temp_test_data=temp_test_data-2000 + + if test_temp==0: + temp2=platform_chassis.get_thermal(1).get_temperature()*1000 + if temp2 is None: + return False + + temp3=platform_chassis.get_thermal(2).get_temperature()*1000 + if temp3 is None: + return False + + new_temp = (temp2 + temp3) / 2 + else: + thermal_val=[0,0,0,0] + for i in range (THERMAL_NUM_MAX): + thermal_val[i]=test_temp_list[i] + thermal_val[i]= thermal_val[i] + temp_test_data + + + new_temp = (thermal_val[1] + thermal_val[2])/2 + logging.debug("Test case:thermal_val[1]=%d, thermal_val[2]=%d, get new_temp=%d", thermal_val[1], thermal_val[2],new_temp) + + for x in range(FAN_TRAY_NUM * FAN_NUM): + fan_stat=True + if not platform_chassis.get_fan(x).get_status() or not platform_chassis.get_fan(x).get_speed_rpm(): + self._new_perc = FAN_LEV1_SPEED_PERC + logging.debug('INFO. SET new_perc to %d (FAN fault. fan_num:%d)', self._new_perc, x+1) + fan_stat=False + break + logging.debug('INFO. fan_stat is True (fan_num:%d)', x+1) + + if fan_stat==True: + diff = new_temp - self._ori_temp + if diff == 0: + logging.debug('INFO. RETURN. THERMAL temp not changed. %d / %d (new_temp / ori_temp)', new_temp, self._ori_temp) + return True + else: + if diff >= 0: + is_up = True + logging.debug('INFO. THERMAL temp UP %d / %d (new_temp / ori_temp)', new_temp, self._ori_temp) + else: + is_up = False + logging.debug('INFO. THERMAL temp DOWN %d / %d (new_temp / ori_temp)', new_temp, self._ori_temp) + + if is_up is True: + if new_temp >= FAN_LEV1_UP_TEMP: + self._new_perc = FAN_LEV1_SPEED_PERC + elif new_temp >= FAN_LEV2_UP_TEMP: + self._new_perc = FAN_LEV2_SPEED_PERC + elif new_temp >= FAN_LEV3_UP_TEMP: + self._new_perc = FAN_LEV3_SPEED_PERC + else: + self._new_perc = FAN_LEV4_SPEED_PERC + logging.debug('INFO. SET. FAN_SPEED as %d (new THERMAL temp:%d)', self._new_perc, new_temp) + else: + if new_temp <= FAN_LEV4_DOWN_TEMP: + self._new_perc = FAN_LEV4_SPEED_PERC + elif new_temp <= FAN_LEV3_DOWN_TEMP: + self._new_perc = FAN_LEV3_SPEED_PERC + elif new_temp <= FAN_LEV2_DOWN_TEMP: + self._new_perc = FAN_LEV2_SPEED_PERC + else: + self._new_perc = FAN_LEV1_SPEED_PERC + logging.debug('INFO. SET. FAN_SPEED as %d (new THERMAL temp:%d)', self._new_perc, new_temp) + + cur_perc= platform_chassis.get_fan(0).get_speed() + if cur_perc == self._new_perc: + logging.debug('INFO. RETURN. FAN speed not changed. %d / %d (new_perc / ori_perc)', self._new_perc, cur_perc) + return True + + set_stat = platform_chassis.get_fan(0).set_speed(self._new_perc) + if set_stat is True: + logging.debug('INFO: PASS. set_fan_duty_cycle (%d)', self._new_perc) + else: + logging.debug('INFO: FAIL. set_fan_duty_cycle (%d)', self._new_perc) + + logging.debug('INFO: GET. ori_perc is %d. ori_temp is %d', cur_perc, self._ori_temp) + self._ori_temp = new_temp + logging.debug('INFO: UPDATE. ori_perc to %d. ori_temp to %d', cur_perc, self._ori_temp) + + return True + +def handler(signum, frame): + logging.debug('INFO:Cause signal %d, set fan speed max.', signum) + platform_chassis.get_fan(0).set_speed(DUTY_MAX) + sys.exit(0) + +def main(argv): + global test_temp + + log_file = '%s.log' % FUNCTION_NAME + log_level = logging.INFO + if len(sys.argv) != 1: + try: + opts, args = getopt.getopt(argv,'hdlt:',['lfile=']) + except getopt.GetoptError: + print('Usage: %s [-d] [-l ]' % sys.argv[0]) + return 0 + for opt, arg in opts: + if opt == '-h': + print('Usage: %s [-d] [-l ]' % sys.argv[0]) + return 0 + elif opt in ('-d', '--debug'): + log_level = logging.DEBUG + elif opt in ('-l', '--lfile'): + log_file = arg + + if sys.argv[1]== '-t': + if len(sys.argv)!=6: + print("temp test, need input 4 temp") + return 0 + i=0 + for x in range(2, 6): + test_temp_list[i]= int(sys.argv[x])*1000 + i=i+1 + test_temp = 1 + log_level = logging.DEBUG + print(test_temp_list) + + global platform_chassis + platform_chassis = platform.Platform().get_chassis() + + #for i in range(4): + # print("temp-%d=%d"%(i+1, platform_chassis.get_thermal(i).get_temperature()*1000)) + + signal.signal(signal.SIGINT, handler) + signal.signal(signal.SIGTERM, handler) + monitor = accton_as5835_54t_monitor(log_file, log_level) + + # Loop forever, doing something useful hopefully: + while True: + monitor.manage_fans() + time.sleep(10) + +if __name__ == '__main__': + main(sys.argv[1:]) \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/utils/pddf_post_device_create.sh b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/utils/pddf_post_device_create.sh new file mode 100755 index 00000000000..cb6763a3ce0 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/utils/pddf_post_device_create.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +set_qsfp_reset_to_normal_state() +{ + i2cset -y -f 3 0x62 0x15 0x3f &>/dev/null +} + +set_system_led_diag_loc_to_off() +{ + i2cset -y -f 3 0x60 0xa 0x1c &>/dev/null +} + +set_pca_mux_idle_disconnect() +{ + echo -2 | tee /sys/bus/i2c/drivers/pca954x/*-00*/idle_state >& /dev/null + if [ $? -ne 0 ]; then + echo "Fail to set pca954x mux idle disconnect" + exit 2 + fi +} + +set_qsfp_reset_to_normal_state +set_system_led_diag_loc_to_off +set_pca_mux_idle_disconnect diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/utils/pddf_switch_svc.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/utils/pddf_switch_svc.py new file mode 100755 index 00000000000..bc9dfa9d741 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/utils/pddf_switch_svc.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python +# Script to stop and start the respective platforms default services. +# This will be used while switching the pddf->non-pddf mode and vice versa +import commands + +def check_pddf_support(): + return True + +def stop_platform_svc(): + + status, output = commands.getstatusoutput("systemctl stop as5835-54t-platform-monitor-fan.service") + if status: + print "Stop as5835-54t-platform-fan.service failed %d"%status + return False + + status, output = commands.getstatusoutput("systemctl stop as5835-54t-platform-monitor-psu.service") + if status: + print "Stop as5835-54t-platform-psu.service failed %d"%status + return False + + status, output = commands.getstatusoutput("systemctl stop as5835-54t-platform-monitor.service") + if status: + print "Stop as5835-54t-platform-init.service failed %d"%status + return False + status, output = commands.getstatusoutput("systemctl disable as5835-54t-platform-monitor.service") + if status: + print "Disable as5835-54t-platform-monitor.service failed %d"%status + return False + + status, output = commands.getstatusoutput("/usr/local/bin/accton_as5835_54t_util.py clean") + if status: + print "accton_as5835_54t_util.py clean command failed %d"%status + return False + + # HACK , stop the pddf-platform-init service if it is active + status, output = commands.getstatusoutput("systemctl stop pddf-platform-init.service") + if status: + print "Stop pddf-platform-init.service along with other platform serives failed %d"%status + return False + + return True + +def start_platform_svc(): + status, output = commands.getstatusoutput("/usr/local/bin/accton_as5835_54t_util.py install") + if status: + print "accton_as5835_54t_util.py install command failed %d"%status + return False + + status, output = commands.getstatusoutput("systemctl enable as5835-54t-platform-monitor.service") + if status: + print "Enable as5835-54t-platform-monitor.service failed %d"%status + return False + status, output = commands.getstatusoutput("systemctl start as5835-54t-platform-monitor-fan.service") + if status: + print "Start as5835-54t-platform-monitor-fan.service failed %d"%status + return False + + status, output = commands.getstatusoutput("systemctl start as5835-54t-platform-monitor-psu.service") + if status: + print "Start as5835-54t-platform-monitor-psu.service failed %d"%status + return False + + return True + +def start_platform_pddf(): + status, output = commands.getstatusoutput("systemctl start pddf-platform-init.service") + if status: + print "Start pddf-platform-init.service failed %d"%status + return False + + return True + +def stop_platform_pddf(): + status, output = commands.getstatusoutput("systemctl stop pddf-platform-init.service") + if status: + print "Stop pddf-platform-init.service failed %d"%status + return False + + return True + +def main(): + pass + +if __name__ == "__main__": + main() + diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54x/service/as5835-54x-pddf-platform-monitor.service b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/service/as5835-54x-pddf-platform-monitor.service new file mode 100644 index 00000000000..ddd8d6abbbb --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/service/as5835-54x-pddf-platform-monitor.service @@ -0,0 +1,16 @@ +[Unit] +Description=Accton AS5835-54X Platform Monitoring service +Before=pmon.service +After=pddf-platform-init.service +DefaultDependencies=no + +[Service] +ExecStart=/usr/local/bin/accton_as5835_54x_pddf_monitor.py +KillSignal=SIGKILL +SuccessExitStatus=SIGKILL + +# Resource Limitations +LimitCORE=infinity + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54x/service/pddf-platform-init.service b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/service/pddf-platform-init.service new file mode 120000 index 00000000000..0fd9f25b6c5 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/service/pddf-platform-init.service @@ -0,0 +1 @@ +../../../../pddf/i2c/service/pddf-platform-init.service \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/__init__.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/__init__.py new file mode 100644 index 00000000000..cdc3b813f64 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/__init__.py @@ -0,0 +1,3 @@ +# All the derived classes for PDDF +__all__ = ["platform", "chassis", "sfp", "psu", "thermal", "fan"] +from . import platform diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/chassis.py new file mode 100644 index 00000000000..8a98bf8326f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/chassis.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python + +############################################################################# +# PDDF +# Module contains an implementation of SONiC Chassis API +# +############################################################################# + +try: + import sys + from sonic_platform_pddf_base.pddf_chassis import PddfChassis + from .event import SfpEvent +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +NUM_COMPONENT = 4 + +class Chassis(PddfChassis): + """ + PDDF Platform-specific Chassis class + """ + + SYSLED_DEV_NAME = "DIAG_LED" + + def __init__(self, pddf_data=None, pddf_plugin_data=None): + PddfChassis.__init__(self, pddf_data, pddf_plugin_data) + self.__initialize_components() + self._sfpevent = SfpEvent(self.get_all_sfps()) + + def __initialize_components(self): + from sonic_platform.component import Component + for index in range(NUM_COMPONENT): + component = Component(index) + self._component_list.append(component) + + # Provide the functions/variables below for which implementation is to be overwritten + def get_change_event(self, timeout=0): + return self._sfpevent.get_sfp_event(timeout) + + def get_sfp(self, index): + """ + Retrieves sfp represented by (1-based) index + + Args: + index: An integer, the index (1-based) of the sfp to retrieve. + The index should be the sequence of a physical port in a chassis, + starting from 1. + For example, 1 for Ethernet0, 2 for Ethernet4 and so on. + + Returns: + An object derived from SfpBase representing the specified sfp + """ + sfp = None + + try: + # The index will start from 1 + sfp = self._sfp_list[index-1] + except IndexError: + sys.stderr.write("SFP index {} out of range (1-{})\n".format( + index, len(self._sfp_list))) + return sfp + + def initizalize_system_led(self): + return + + def get_status_led(self): + return self.get_system_led(self.SYSLED_DEV_NAME) + + def set_status_led(self, color): + return self.set_system_led(self.SYSLED_DEV_NAME, color) diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/component.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/component.py new file mode 100644 index 00000000000..7d043f7dae1 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/component.py @@ -0,0 +1,115 @@ +############################################################################# +# +# Component contains an implementation of SONiC Platform Base API and +# provides the components firmware management function +# +############################################################################# + +try: + import subprocess + from sonic_platform_base.component_base import ComponentBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +CPLD_ADDR_MAPPING = { + "CPLD1": ['3', '0x60'], + "CPLD2": ['3', '0x61'], + "CPLD3": ['3', '0x62'] +} +SYSFS_PATH = "/sys/bus/i2c/devices/" +BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version" +COMPONENT_LIST= [ + ("CPLD1", "CPLD 1"), + ("CPLD2", "CPLD 2"), + ("CPLD3", "CPLD 3"), + ("BIOS", "Basic Input/Output System") + +] + +class Component(ComponentBase): + """Platform-specific Component class""" + + DEVICE_TYPE = "component" + + def __init__(self, component_index=0): + self.index = component_index + self.name = self.get_name() + + def __run_command(self, command): + # Run bash command and print output to stdout + try: + process = subprocess.Popen( + shlex.split(command), stdout=subprocess.PIPE) + while True: + output = process.stdout.readline() + if output == '' and process.poll() is not None: + break + rc = process.poll() + if rc != 0: + return False + except Exception: + return False + return True + + def __get_bios_version(self): + # Retrieves the BIOS firmware version + try: + with open(BIOS_VERSION_PATH, 'r') as fd: + bios_version = fd.read() + return bios_version.strip() + except Exception as e: + return None + + def __get_cpld_version(self): + # Retrieves the CPLD firmware version + cpld_version = dict() + for cpld_name in CPLD_ADDR_MAPPING: + cmd = "i2cget -f -y {0} {1} 0x1".format(CPLD_ADDR_MAPPING[cpld_name][0], CPLD_ADDR_MAPPING[cpld_name][1]) + status, value = subprocess.getstatusoutput(cmd) + if not status: + cpld_version_raw = value.rstrip() + cpld_version[cpld_name] = "{}".format(int(cpld_version_raw,16)) + + return cpld_version + + def get_name(self): + """ + Retrieves the name of the component + Returns: + A string containing the name of the component + """ + return COMPONENT_LIST[self.index][0] + + def get_description(self): + """ + Retrieves the description of the component + Returns: + A string containing the description of the component + """ + return COMPONENT_LIST[self.index][1] + + def get_firmware_version(self): + """ + Retrieves the firmware version of module + Returns: + string: The firmware versions of the module + """ + fw_version = None + + if self.name == "BIOS": + fw_version = self.__get_bios_version() + elif "CPLD" in self.name: + cpld_version = self.__get_cpld_version() + fw_version = cpld_version.get(self.name) + + return fw_version + + def install_firmware(self, image_path): + """ + Install firmware to module + Args: + image_path: A string, path to firmware image + Returns: + A boolean, True if install successfully, False if not + """ + raise NotImplementedError diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/eeprom.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/eeprom.py new file mode 100644 index 00000000000..a87ecc9f6fe --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/eeprom.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python + +try: + from sonic_platform_pddf_base.pddf_eeprom import PddfEeprom +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Eeprom(PddfEeprom): + + def __init__(self, pddf_data=None, pddf_plugin_data=None): + PddfEeprom.__init__(self, pddf_data, pddf_plugin_data) + + # Provide the functions/variables below for which implementation is to be overwritten diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/event.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/event.py new file mode 100644 index 00000000000..d5dac6d7f7e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/event.py @@ -0,0 +1,60 @@ +try: + import time + from sonic_py_common.logger import Logger +except ImportError as e: + raise ImportError(repr(e) + " - required module not found") + +POLL_INTERVAL_IN_SEC = 1 + +class SfpEvent: + ''' Listen to insert/remove sfp events ''' + + def __init__(self, sfp_list): + self._sfp_list = sfp_list + self._logger = Logger() + self._sfp_change_event_data = {'present': 0} + + def get_presence_bitmap(self): + bitmap = 0 + for sfp in self._sfp_list: + modpres = sfp.get_presence() + i=sfp.get_position_in_parent() - 1 + if modpres: + bitmap = bitmap | (1 << i) + return bitmap + + def get_sfp_event(self, timeout=2000): + port_dict = {} + change_dict = {} + change_dict['sfp'] = port_dict + + if timeout < 1000: + cd_ms = 1000 + else: + cd_ms = timeout + + while cd_ms > 0: + bitmap = self.get_presence_bitmap() + changed_ports = self._sfp_change_event_data['present'] ^ bitmap + if changed_ports != 0: + break + time.sleep(POLL_INTERVAL_IN_SEC) + # timeout=0 means wait for event forever + if timeout != 0: + cd_ms = cd_ms - POLL_INTERVAL_IN_SEC * 1000 + + if changed_ports != 0: + for sfp in self._sfp_list: + i=sfp.get_position_in_parent() - 1 + if (changed_ports & (1 << i)): + if (bitmap & (1 << i)) == 0: + port_dict[i+1] = '0' + else: + port_dict[i+1] = '1' + + + # Update the cache dict + self._sfp_change_event_data['present'] = bitmap + return True, change_dict + else: + return True, change_dict diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/fan.py new file mode 100644 index 00000000000..a5b5f5ba4df --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/fan.py @@ -0,0 +1,48 @@ +#!/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 + # Since AS4630 psu_fan airflow direction cant be read from sysfs, it is fixed as 'F2B' or 'intake' + 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: + direction = self.FAN_DIRECTION_EXHAUST + + 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 + diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/platform.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/platform.py new file mode 100644 index 00000000000..406b1179ae1 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/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/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/psu.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/psu.py new file mode 100644 index 00000000000..a2a33020655 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/psu.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python +# + + +try: + from sonic_platform_pddf_base.pddf_psu import PddfPsu +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + + +class Psu(PddfPsu): + """PDDF Platform-Specific PSU class""" + + PLATFORM_PSU_CAPACITY = 1200 + + def __init__(self, index, pddf_data=None, pddf_plugin_data=None): + PddfPsu.__init__(self, index, pddf_data, pddf_plugin_data) + + # Provide the functions/variables below for which implementation is to be overwritten + def get_maximum_supplied_power(self): + """ + Retrieves the maximum supplied power by PSU (or PSU capacity) + Returns: + A float number, the maximum power output in Watts. + e.g. 1200.1 + """ + return float(self.PLATFORM_PSU_CAPACITY) + + def get_capacity(self): + """ + Gets the capacity (maximum output power) of the PSU in watts + + Returns: + An integer, the capacity of PSU + """ + return (self.PLATFORM_PSU_CAPACITY) + + def get_type(self): + """ + Gets the type of the PSU + Returns: + A string, the type of PSU (AC/DC) + """ + return "AC" diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/sfp.py new file mode 100644 index 00000000000..c9fb07d6364 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/sfp.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python + +try: + from sonic_platform_pddf_base.pddf_sfp import PddfSfp +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + + +class Sfp(PddfSfp): + """ + PDDF Platform-Specific Sfp class + """ + + def __init__(self, index, pddf_data=None, pddf_plugin_data=None): + PddfSfp.__init__(self, index, pddf_data, pddf_plugin_data) + + # Provide the functions/variables below for which implementation is to be overwritten + def get_position_in_parent(self): + """Retrieves 1-based relative physical position in parent device.""" + return self.port_index diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/thermal.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/thermal.py new file mode 100644 index 00000000000..5b829fc26ca --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/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/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/watchdog.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/watchdog.py new file mode 100644 index 00000000000..88660b1a1fa --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform/watchdog.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python + +############################################################################# +# +# Module contains an implementation of platform specific watchdog API's +# +############################################################################# + +try: + from sonic_platform_pddf_base.pddf_watchdog import PddfWatchdog +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +class Watchdog(PddfWatchdog): + """ + PDDF Platform-specific Chassis class + """ + + def __init__(self): + PddfWatchdog.__init__(self) + self.timeout= 180 + + # Provide the functions/variables below for which implementation is to be overwritten diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform_setup.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform_setup.py index a775511c643..22bd354ea68 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform_setup.py +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/sonic_platform_setup.py @@ -1,8 +1,5 @@ from setuptools import setup -DEVICE_NAME = 'accton' -HW_SKU = 'x86_64-accton_as5835_54x-r0' - setup( name='sonic-platform', version='1.0', @@ -11,13 +8,7 @@ author='SONiC Team', author_email='linuxnetdev@microsoft.com', url='https://github.com/Azure/sonic-buildimage', - maintainer='Jostar Yang', - maintainer_email='jostar_yang@accton.com', - packages=[ - 'sonic_platform', - ], - package_dir={ - 'sonic_platform': '../../../../device/{}/{}/sonic_platform'.format(DEVICE_NAME, HW_SKU)}, + packages=['sonic_platform'], classifiers=[ 'Development Status :: 3 - Alpha', 'Environment :: Plugins', diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54x/utils/accton_as5835_54x_pddf_monitor.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/utils/accton_as5835_54x_pddf_monitor.py new file mode 100755 index 00000000000..8beb335b4ce --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/utils/accton_as5835_54x_pddf_monitor.py @@ -0,0 +1,241 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2019 Accton Technology Corporation +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# ------------------------------------------------------------------ +# HISTORY: +# mm/dd/yyyy (A.D.) +# 05/29/2019: Brandon Chuang, changed for as5835-54x. +# 08/03/2020: Jostar Yang, change to call PDDF API . +# ------------------------------------------------------------------ + +try: + import sys, getopt + import logging + import logging.config + import time + import signal + from sonic_platform import platform +except ImportError as e: + raise ImportError('%s - required module not found' % str(e)) + +# Deafults +VERSION = '1.0' +FUNCTION_NAME = 'accton_as5835_54x_monitor' +DUTY_MAX = 100 + +platform_chassis = None + +test_temp = 0 +test_temp_list = [0, 0, 0, 0] +test_temp_revert=0 +temp_test_data=0 + +# Make a class we can use to capture stdout and sterr in the log +class accton_as5835_54x_monitor(object): + # static temp var + _ori_temp = 0 + _new_perc = 0 + + def __init__(self, log_file, log_level): + """Needs a logger and a logger level.""" + # set up logging to file + logging.basicConfig( + filename=log_file, + filemode='w', + level=log_level, + format= '[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s', + datefmt='%H:%M:%S' + ) + + # set up logging to console + if log_level == logging.DEBUG: + console = logging.StreamHandler() + console.setLevel(log_level) + formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') + console.setFormatter(formatter) + logging.getLogger('').addHandler(console) + + logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level) + + def manage_fans(self): + global platform_chassis + global test_temp_list + global temp_test_data + global test_temp + + THERMAL_NUM_MAX=4 + FAN_LEV1_UP_TEMP = 57700 # temperature + FAN_LEV1_SPEED_PERC = DUTY_MAX # percentage*/ + + FAN_LEV2_UP_TEMP = 53000 + FAN_LEV2_DOWN_TEMP = 52700 + FAN_LEV2_SPEED_PERC = 80 + + FAN_LEV3_UP_TEMP = 49500 + FAN_LEV3_DOWN_TEMP = 47700 + FAN_LEV3_SPEED_PERC = 65 + + FAN_LEV4_DOWN_TEMP = 42700 + FAN_LEV4_SPEED_PERC = 40 + + FAN_NUM=2 + FAN_TRAY_NUM=5 + + if test_temp_revert==0: + temp_test_data=temp_test_data+2000 + else: + temp_test_data=temp_test_data-2000 + + if test_temp==0: + temp2=platform_chassis.get_thermal(1).get_temperature()*1000 + if temp2 is None: + return False + + temp3=platform_chassis.get_thermal(2).get_temperature()*1000 + if temp3 is None: + return False + + new_temp = (temp2 + temp3) / 2 + else: + thermal_val=[0,0,0,0] + for i in range (THERMAL_NUM_MAX): + thermal_val[i]=test_temp_list[i] + thermal_val[i]= thermal_val[i] + temp_test_data + + + new_temp = (thermal_val[1] + thermal_val[2])/2 + logging.debug("Test case:thermal_val[1]=%d, thermal_val[2]=%d, get new_temp=%d", thermal_val[1], thermal_val[2],new_temp) + + for x in range(FAN_TRAY_NUM * FAN_NUM): + #fan_stat = platform_chassis.get_fan(x).get_status() or not platform_chassis.get_fan(x).get_speed_rpm() + + #if fan_stat is None: + # return False + #if fan_stat is False: + fan_stat=True + if not platform_chassis.get_fan(x).get_status() or not platform_chassis.get_fan(x).get_speed_rpm(): + self._new_perc = FAN_LEV1_SPEED_PERC + logging.debug('INFO. SET new_perc to %d (FAN fault. fan_num:%d)', self._new_perc, x+1) + fan_stat=False + break + logging.debug('INFO. fan_stat is True (fan_num:%d)', x+1) + + if fan_stat==True: + diff = new_temp - self._ori_temp + if diff == 0: + logging.debug('INFO. RETURN. THERMAL temp not changed. %d / %d (new_temp / ori_temp)', new_temp, self._ori_temp) + return True + else: + if diff >= 0: + is_up = True + logging.debug('INFO. THERMAL temp UP %d / %d (new_temp / ori_temp)', new_temp, self._ori_temp) + else: + is_up = False + logging.debug('INFO. THERMAL temp DOWN %d / %d (new_temp / ori_temp)', new_temp, self._ori_temp) + + if is_up is True: + if new_temp >= FAN_LEV1_UP_TEMP: + self._new_perc = FAN_LEV1_SPEED_PERC + elif new_temp >= FAN_LEV2_UP_TEMP: + self._new_perc = FAN_LEV2_SPEED_PERC + elif new_temp >= FAN_LEV3_UP_TEMP: + self._new_perc = FAN_LEV3_SPEED_PERC + else: + self._new_perc = FAN_LEV4_SPEED_PERC + logging.debug('INFO. SET. FAN_SPEED as %d (new THERMAL temp:%d)', self._new_perc, new_temp) + else: + if new_temp <= FAN_LEV4_DOWN_TEMP: + self._new_perc = FAN_LEV4_SPEED_PERC + elif new_temp <= FAN_LEV3_DOWN_TEMP: + self._new_perc = FAN_LEV3_SPEED_PERC + elif new_temp <= FAN_LEV2_DOWN_TEMP: + self._new_perc = FAN_LEV2_SPEED_PERC + else: + self._new_perc = FAN_LEV1_SPEED_PERC + logging.debug('INFO. SET. FAN_SPEED as %d (new THERMAL temp:%d)', self._new_perc, new_temp) + + cur_perc= platform_chassis.get_fan(0).get_speed() + #cur_perc = fan.get_fan_duty_cycle() + if cur_perc == self._new_perc: + logging.debug('INFO. RETURN. FAN speed not changed. %d / %d (new_perc / ori_perc)', self._new_perc, cur_perc) + return True + + #set_stat = fan.set_fan_duty_cycle(self._new_perc) + set_stat = platform_chassis.get_fan(0).set_speed(self._new_perc) + if set_stat is True: + logging.debug('INFO: PASS. set_fan_duty_cycle (%d)', self._new_perc) + else: + logging.debug('INFO: FAIL. set_fan_duty_cycle (%d)', self._new_perc) + + logging.debug('INFO: GET. ori_perc is %d. ori_temp is %d', cur_perc, self._ori_temp) + self._ori_temp = new_temp + logging.debug('INFO: UPDATE. ori_perc to %d. ori_temp to %d', cur_perc, self._ori_temp) + + return True + +def handler(signum, frame): + logging.debug('INFO:Cause signal %d, set fan speed max.', signum) + platform_chassis.get_fan(0).set_speed(DUTY_MAX) + sys.exit(0) + +def main(argv): + global test_temp + + log_file = '%s.log' % FUNCTION_NAME + log_level = logging.INFO + if len(sys.argv) != 1: + try: + opts, args = getopt.getopt(argv,'hdlt:',['lfile=']) + except getopt.GetoptError: + print 'Usage: %s [-d] [-l ]' % sys.argv[0] + return 0 + for opt, arg in opts: + if opt == '-h': + print 'Usage: %s [-d] [-l ]' % sys.argv[0] + return 0 + elif opt in ('-d', '--debug'): + log_level = logging.DEBUG + elif opt in ('-l', '--lfile'): + log_file = arg + + if sys.argv[1]== '-t': + if len(sys.argv)!=6: + print "temp test, need input 4 temp" + return 0 + i=0 + for x in range(2, 6): + test_temp_list[i]= int(sys.argv[x])*1000 + i=i+1 + test_temp = 1 + log_level = logging.DEBUG + print test_temp_list + + global platform_chassis + platform_chassis = platform.Platform().get_chassis() + + + signal.signal(signal.SIGINT, handler) + signal.signal(signal.SIGTERM, handler) + monitor = accton_as5835_54x_monitor(log_file, log_level) + + # Loop forever, doing something useful hopefully: + while True: + monitor.manage_fans() + time.sleep(10) + +if __name__ == '__main__': + main(sys.argv[1:]) \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54x/utils/pddf_post_device_create.sh b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/utils/pddf_post_device_create.sh new file mode 100755 index 00000000000..3dd6f7c61e2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/utils/pddf_post_device_create.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +set_qsfp_reset_to_normal_state() +{ + i2cset -y -f 3 0x62 0x15 0x3f &>/dev/null +} + + +set_sfp_tx_disable_to_disable() +{ + i2cset -y -f 3 0x61 0x12 0x0 &>/dev/null + i2cset -y -f 3 0x61 0x13 0x0 &>/dev/null + i2cset -y -f 3 0x61 0x14 0x0 &>/dev/null + i2cset -y -f 3 0x61 0x15 0x0 &>/dev/null + i2cset -y -f 3 0x61 0x16 0x0 &>/dev/null + i2cset -y -f 3 0x62 0xc 0x0 &>/dev/null + i2cset -y -f 3 0x62 0xd 0x0 &>/dev/null +} + +set_system_led_diag_loc_to_off() +{ + i2cset -y -f 3 0x60 0xa 0x1c &>/dev/null +} + +set_pca_mux_idle_disconnect() +{ + echo -2 | tee /sys/bus/i2c/drivers/pca954x/*-00*/idle_state >& /dev/null + if [ $? -ne 0 ]; then + echo "Fail to set pca954x mux idle disconnect" + exit 2 + fi +} + +set_qsfp_reset_to_normal_state +set_sfp_tx_disable_to_disable +set_system_led_diag_loc_to_off +set_pca_mux_idle_disconnect diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54x/utils/pddf_switch_svc.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/utils/pddf_switch_svc.py new file mode 100755 index 00000000000..e070eb8212c --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54x/utils/pddf_switch_svc.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python +# Script to stop and start the respective platforms default services. +# This will be used while switching the pddf->non-pddf mode and vice versa +import commands + +def check_pddf_support(): + return True + +def stop_platform_svc(): + + status, output = commands.getstatusoutput("systemctl stop as5835-54x-platform-monitor-fan.service") + if status: + print "Stop as5835-54x-platform-fan.service failed %d"%status + return False + + status, output = commands.getstatusoutput("systemctl stop as5835-54x-platform-monitor-psu.service") + if status: + print "Stop as5835-54x-platform-psu.service failed %d"%status + return False + + status, output = commands.getstatusoutput("systemctl stop as5835-54x-platform-monitor.service") + if status: + print "Stop as5835-54x-platform-init.service failed %d"%status + return False + status, output = commands.getstatusoutput("systemctl disable as5835-54x-platform-monitor.service") + if status: + print "Disable as5835-54x-platform-monitor.service failed %d"%status + return False + + status, output = commands.getstatusoutput("/usr/local/bin/accton_as5835_54x_util.py clean") + if status: + print "accton_as5835_54x_util.py clean command failed %d"%status + return False + + # HACK , stop the pddf-platform-init service if it is active + status, output = commands.getstatusoutput("systemctl stop pddf-platform-init.service") + if status: + print "Stop pddf-platform-init.service along with other platform serives failed %d"%status + return False + + return True + +def start_platform_svc(): + status, output = commands.getstatusoutput("/usr/local/bin/accton_as5835_54x_util.py install") + if status: + print "accton_as5835_54x_util.py install command failed %d"%status + return False + + status, output = commands.getstatusoutput("systemctl enable as5835-54x-platform-monitor.service") + if status: + print "Enable as5835-54x-platform-monitor.service failed %d"%status + return False + status, output = commands.getstatusoutput("systemctl start as5835-54x-platform-monitor-fan.service") + if status: + print "Start as5835-54x-platform-monitor-fan.service failed %d"%status + return False + + status, output = commands.getstatusoutput("systemctl start as5835-54x-platform-monitor-psu.service") + if status: + print "Start as5835-54x-platform-monitor-psu.service failed %d"%status + return False + + return True + +def start_platform_pddf(): + status, output = commands.getstatusoutput("systemctl start pddf-platform-init.service") + if status: + print "Start pddf-platform-init.service failed %d"%status + return False + + return True + +def stop_platform_pddf(): + status, output = commands.getstatusoutput("systemctl stop pddf-platform-init.service") + if status: + print "Stop pddf-platform-init.service failed %d"%status + return False + + return True + +def main(): + pass + +if __name__ == "__main__": + main() + diff --git a/platform/broadcom/sonic-platform-modules-accton/as7326-56x/modules/Makefile b/platform/broadcom/sonic-platform-modules-accton/as7326-56x/modules/Makefile index 85c066571c2..cc0802f32c9 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as7326-56x/modules/Makefile +++ b/platform/broadcom/sonic-platform-modules-accton/as7326-56x/modules/Makefile @@ -1,7 +1,11 @@ ifneq ($(KERNELRELEASE),) obj-m:= accton_i2c_cpld.o \ accton_as7326_56x_fan.o accton_as7326_56x_leds.o \ - accton_as7326_56x_psu.o ym2651y.o + accton_as7326_56x_psu.o ym2651y.o \ + pddf_custom_psu.o + +CFLAGS_pddf_custom_psu.o := -I$(M)/../../../../pddf/i2c/modules/include +KBUILD_EXTRA_SYMBOLS := $(M)/../../../../pddf/i2c/Module.symvers.PDDF else ifeq (,$(KERNEL_SRC)) diff --git a/platform/broadcom/sonic-platform-modules-accton/as7326-56x/modules/accton_as7326_56x_fan.c b/platform/broadcom/sonic-platform-modules-accton/as7326-56x/modules/accton_as7326_56x_fan.c index 606019f3ea4..691942c2cd1 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as7326-56x/modules/accton_as7326_56x_fan.c +++ b/platform/broadcom/sonic-platform-modules-accton/as7326-56x/modules/accton_as7326_56x_fan.c @@ -48,7 +48,6 @@ static ssize_t set_duty_cycle(struct device *dev, struct device_attribute *da, static ssize_t get_enable(struct device *dev, struct device_attribute *da, char *buf); static ssize_t set_enable(struct device *dev, struct device_attribute *da, const char *buf, size_t count); -static ssize_t get_sys_temp(struct device *dev, struct device_attribute *da, char *buf); extern int accton_i2c_cpld_read(unsigned short cpld_addr, u8 reg); extern int accton_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); @@ -150,12 +149,6 @@ enum sysfs_fan_attributes { &sensor_dev_attr_pwm##index.dev_attr.attr, \ &sensor_dev_attr_pwm##index##_enable.dev_attr.attr -#define DECLARE_FAN_SYSTEM_TEMP_SENSOR_DEV_ATTR() \ - static SENSOR_DEVICE_ATTR(sys_temp, S_IRUGO, get_sys_temp, NULL, FAN_DUTY_CYCLE_PERCENTAGE) - -#define DECLARE_FAN_SYSTEM_TEMP_ATTR() &sensor_dev_attr_sys_temp.dev_attr.attr - - #define DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(index) \ static SENSOR_DEVICE_ATTR(fan##index##_present, S_IRUGO, fan_show_value, NULL, FAN##index##_PRESENT) #define DECLARE_FAN_PRESENT_ATTR(index) &sensor_dev_attr_fan##index##_present.dev_attr.attr @@ -200,8 +193,6 @@ DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(5); DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(6); /* 1 fan duty cycle attribute in this platform */ DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR(1); -/* System temperature for fancontrol */ -DECLARE_FAN_SYSTEM_TEMP_SENSOR_DEV_ATTR(); static struct attribute *as7326_56x_fan_attributes[] = { /* fan related attributes */ @@ -230,7 +221,6 @@ static struct attribute *as7326_56x_fan_attributes[] = { DECLARE_FAN_DIRECTION_ATTR(5), DECLARE_FAN_DIRECTION_ATTR(6), DECLARE_FAN_DUTY_CYCLE_ATTR(1), - DECLARE_FAN_SYSTEM_TEMP_ATTR(), NULL }; @@ -451,55 +441,55 @@ static int get_temp_file_path( } /*File read the dev file at user space.*/ -static int read_devfile_temp1_input( - struct device *dev, - int bus_nr, - unsigned short addr, - struct device *hwmon_dev, - int *miniCelsius) -{ - struct file *sfd; - char buffer[96]; - char devfile[96]; - int rc, status; - int rdlen, value; - mm_segment_t old_fs; - - rc = 0; - get_temp_file_path(bus_nr, addr, hwmon_dev, devfile, sizeof(devfile)); - sfd = filp_open(devfile, O_RDONLY, 0); - if (IS_ERR(sfd)) { - pr_err("Failed to open file(%s)#%d\r\n", devfile, __LINE__); - return -ENOENT; - } - dev_dbg(dev, "Found device:%s\n",devfile); - - if(!(sfd->f_op) || !(sfd->f_op->read) ) { - pr_err("file %s cann't readable ?\n",devfile); - return -ENOENT; - } - - old_fs = get_fs(); - set_fs(KERNEL_DS); - rdlen = sfd->f_op->read(sfd, buffer, sizeof(buffer), &sfd->f_pos); - if (rdlen == 0) { - pr_err( "File(%s) empty!\n", devfile); - rc = -EIO; - goto exit; - } - status = sscanf(buffer, "%d", &value); - if (status != 1) { - rc = -EIO; - goto exit; - } - *miniCelsius = value; - dev_dbg(dev,"found sensors: %d @i2c %d-%04x\n", value, bus_nr, addr); - -exit: - set_fs(old_fs); - filp_close(sfd, 0); - return rc; -} +// static int read_devfile_temp1_input( +// struct device *dev, +// int bus_nr, +// unsigned short addr, +// struct device *hwmon_dev, +// int *miniCelsius) +// { +// struct file *sfd; +// char buffer[96]; +// char devfile[96]; +// int rc, status; +// int rdlen, value; +// mm_segment_t old_fs; + +// rc = 0; +// get_temp_file_path(bus_nr, addr, hwmon_dev, devfile, sizeof(devfile)); +// sfd = filp_open(devfile, O_RDONLY, 0); +// if (IS_ERR(sfd)) { +// pr_err("Failed to open file(%s)#%d\r\n", devfile, __LINE__); +// return -ENOENT; +// } +// dev_dbg(dev, "Found device:%s\n",devfile); + +// if(!(sfd->f_op) || !(sfd->f_op->read) ) { +// pr_err("file %s cann't readable ?\n",devfile); +// return -ENOENT; +// } + +// old_fs = get_fs(); +// set_fs(KERNEL_DS); +// rdlen = sfd->f_op->read(sfd, buffer, sizeof(buffer), &sfd->f_pos); +// if (rdlen == 0) { +// pr_err( "File(%s) empty!\n", devfile); +// rc = -EIO; +// goto exit; +// } +// status = sscanf(buffer, "%d", &value); +// if (status != 1) { +// rc = -EIO; +// goto exit; +// } +// *miniCelsius = value; +// dev_dbg(dev,"found sensors: %d @i2c %d-%04x\n", value, bus_nr, addr); + +// exit: +// set_fs(old_fs); +// filp_close(sfd, 0); +// return rc; +// } static u8 is_lm75_data_due(struct i2c_client *client) { @@ -535,79 +525,79 @@ static bool lm75_addr_mached(unsigned short addr) return 0; } -static int _find_lm75_device(struct device *dev, void *data) -{ - struct device_driver *driver; - struct as7326_56x_fan_data *prv = data; - char *driver_name = THERMAL_SENSORS_DRIVER; - - driver = dev->driver; - if (driver && driver->name && - strcmp(driver->name, driver_name) == 0) - { - struct i2c_client *client; - client = to_i2c_client(dev); - if (client) - { - /*cannot use "struct i2c_adapter *adap = to_i2c_adapter(dev);"*/ - struct i2c_adapter *adap = client->adapter; - int miniCelsius = 0; - - if (! lm75_addr_mached(client->addr)) - { - return 0; - } - - if (!adap) { - return -ENXIO; - } - - /* If the data is not updated, read them from devfile - to drive them updateing data from chip.*/ - if (is_lm75_data_due(client)) - { - struct device *hwmon_dev; - - hwmon_dev = get_hwmon_dev(client); - if(0 == read_devfile_temp1_input(dev, adap->nr, - client->addr, hwmon_dev, &miniCelsius)) - { - prv->system_temp += miniCelsius; - prv->sensors_found++; - } - - } - else - { - get_lm75_temp(client, &miniCelsius); - prv->system_temp += miniCelsius; - prv->sensors_found++; - - } - } - } - return 0; -} +// static int _find_lm75_device(struct device *dev, void *data) +// { +// struct device_driver *driver; +// struct as7326_56x_fan_data *prv = data; +// char *driver_name = THERMAL_SENSORS_DRIVER; + +// driver = dev->driver; +// if (driver && driver->name && +// strcmp(driver->name, driver_name) == 0) +// { +// struct i2c_client *client; +// client = to_i2c_client(dev); +// if (client) +// { +// /*cannot use "struct i2c_adapter *adap = to_i2c_adapter(dev);"*/ +// struct i2c_adapter *adap = client->adapter; +// int miniCelsius = 0; + +// if (! lm75_addr_mached(client->addr)) +// { +// return 0; +// } + +// if (!adap) { +// return -ENXIO; +// } + +// /* If the data is not updated, read them from devfile +// to drive them updateing data from chip.*/ +// if (is_lm75_data_due(client)) +// { +// struct device *hwmon_dev; + +// hwmon_dev = get_hwmon_dev(client); +// if(0 == read_devfile_temp1_input(dev, adap->nr, +// client->addr, hwmon_dev, &miniCelsius)) +// { +// prv->system_temp += miniCelsius; +// prv->sensors_found++; +// } + +// } +// else +// { +// get_lm75_temp(client, &miniCelsius); +// prv->system_temp += miniCelsius; +// prv->sensors_found++; + +// } +// } +// } +// return 0; +// } /*Find all lm75 devices and return sum of temperatures.*/ -static ssize_t get_sys_temp(struct device *dev, struct device_attribute *da, - char *buf) -{ - ssize_t ret = 0; - struct as7326_56x_fan_data *data = as7326_56x_fan_update_device(dev); - - data->system_temp=0; - data->sensors_found=0; - i2c_for_each_dev(data, _find_lm75_device); - if (NUM_THERMAL_SENSORS != data->sensors_found) - { - dev_dbg(dev,"only %d of %d temps are found\n", - data->sensors_found, NUM_THERMAL_SENSORS); - data->system_temp = INT_MAX; - } - ret = sprintf(buf, "%d\n",data->system_temp); - return ret; -} +// static ssize_t get_sys_temp(struct device *dev, struct device_attribute *da, +// char *buf) +// { +// ssize_t ret = 0; +// struct as7326_56x_fan_data *data = as7326_56x_fan_update_device(dev); + +// data->system_temp=0; +// data->sensors_found=0; +// i2c_for_each_dev(data, _find_lm75_device); +// if (NUM_THERMAL_SENSORS != data->sensors_found) +// { +// dev_dbg(dev,"only %d of %d temps are found\n", +// data->sensors_found, NUM_THERMAL_SENSORS); +// data->system_temp = INT_MAX; +// } +// ret = sprintf(buf, "%d\n",data->system_temp); +// return ret; +// } static ssize_t fan_show_value(struct device *dev, struct device_attribute *da, char *buf) diff --git a/platform/broadcom/sonic-platform-modules-accton/as7326-56x/modules/accton_as7326_56x_leds.c b/platform/broadcom/sonic-platform-modules-accton/as7326-56x/modules/accton_as7326_56x_leds.c index 7214ae55d3f..ed98daf2011 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as7326-56x/modules/accton_as7326_56x_leds.c +++ b/platform/broadcom/sonic-platform-modules-accton/as7326-56x/modules/accton_as7326_56x_leds.c @@ -146,7 +146,7 @@ static int accton_getLedReg(enum led_type type, u8 *reg) int i; for (i = 0; i < ARRAY_SIZE(led_reg_map); i++) { - if(led_reg_map[i].types ==type)) { + if(led_reg_map[i].types ==type) { *reg = led_reg_map[i].reg_addr; return 0; } diff --git a/platform/broadcom/sonic-platform-modules-accton/as7326-56x/modules/accton_as7326_56x_psu.c b/platform/broadcom/sonic-platform-modules-accton/as7326-56x/modules/accton_as7326_56x_psu.c index 8c2ece6200f..9dbd061c9e4 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as7326-56x/modules/accton_as7326_56x_psu.c +++ b/platform/broadcom/sonic-platform-modules-accton/as7326-56x/modules/accton_as7326_56x_psu.c @@ -34,8 +34,10 @@ #include #include +#define MAX_MODEL_NAME 16 +#define MAX_SERIAL_NUMBER 18 static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf); -static ssize_t show_model_name(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_string(struct device *dev, struct device_attribute *da, char *buf); static int as7326_56x_psu_read_block(struct i2c_client *client, u8 command, u8 *data,int data_len); extern int as7326_56x_cpld_read(unsigned short cpld_addr, u8 reg); @@ -52,7 +54,8 @@ struct as7326_56x_psu_data { unsigned long last_updated; /* In jiffies */ u8 index; /* PSU index */ u8 status; /* Status(present/power_good) register read from CPLD */ - char model_name[9]; /* Model name, read from eeprom */ + char model_name[MAX_MODEL_NAME+1]; /* Model name, read from eeprom */ + char serial_number[MAX_SERIAL_NUMBER+1]; }; static struct as7326_56x_psu_data *as7326_56x_psu_update_device(struct device *dev); @@ -60,18 +63,21 @@ static struct as7326_56x_psu_data *as7326_56x_psu_update_device(struct device *d enum as7326_56x_psu_sysfs_attributes { PSU_PRESENT, PSU_MODEL_NAME, + PSU_SERIAL_NUMBER, PSU_POWER_GOOD }; /* sysfs attributes for hwmon */ static SENSOR_DEVICE_ATTR(psu_present, S_IRUGO, show_status, NULL, PSU_PRESENT); -static SENSOR_DEVICE_ATTR(psu_model_name, S_IRUGO, show_model_name,NULL, PSU_MODEL_NAME); +static SENSOR_DEVICE_ATTR(psu_model_name, S_IRUGO, show_string, NULL, PSU_MODEL_NAME); +static SENSOR_DEVICE_ATTR(psu_serial_number, S_IRUGO, show_string, NULL, PSU_SERIAL_NUMBER); static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_status, NULL, PSU_POWER_GOOD); static struct attribute *as7326_56x_psu_attributes[] = { &sensor_dev_attr_psu_present.dev_attr.attr, &sensor_dev_attr_psu_model_name.dev_attr.attr, + &sensor_dev_attr_psu_serial_number.dev_attr.attr, &sensor_dev_attr_psu_power_good.dev_attr.attr, NULL }; @@ -83,6 +89,10 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, struct as7326_56x_psu_data *data = as7326_56x_psu_update_device(dev); u8 status = 0; + if (!data->valid) { + return -EIO; + } + if (attr->index == PSU_PRESENT) { status = !(data->status >> (1-data->index) & 0x1); } @@ -93,12 +103,27 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, return sprintf(buf, "%d\n", status); } -static ssize_t show_model_name(struct device *dev, struct device_attribute *da, - char *buf) +static ssize_t show_string(struct device *dev, struct device_attribute *da, + char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct as7326_56x_psu_data *data = as7326_56x_psu_update_device(dev); + char *ptr = NULL; - return sprintf(buf, "%s\n", data->model_name); + if (!data->valid) { + return -EIO; + } + + if (attr->index == PSU_MODEL_NAME) { + ptr = data->model_name; + } + else if (attr->index == PSU_SERIAL_NUMBER) { + ptr = data->serial_number; + } + else { + return -EIO; + } + return sprintf(buf, "%s\n", ptr); } static const struct attribute_group as7326_56x_psu_group = { @@ -219,6 +244,112 @@ static int as7326_56x_psu_read_block(struct i2c_client *client, u8 command, u8 * return result; } +enum psu_type { + PSU_TYPE_AC_110V, + PSU_TYPE_DC_48V, + PSU_TYPE_DC_12V, + PSU_TYPE_AC_ACBEL_FSF019, + PSU_TYPE_AC_ACBEL_FSF045 +}; + +struct model_name_info { + enum psu_type type; + u8 offset; + u8 length; + char* model_name; +}; + +struct serial_number_info { + enum psu_type type; + u8 offset; + u8 length; + char* serial_number; +}; + +struct model_name_info models[] = { + {PSU_TYPE_AC_110V, 0x20, 8, "YM-2651Y"}, + {PSU_TYPE_DC_48V, 0x20, 8, "YM-2651V"}, + {PSU_TYPE_DC_12V, 0x00, 11, "PSU-12V-750"}, + {PSU_TYPE_AC_ACBEL_FSF019, 0x15, 10, "FSF019-"}, + {PSU_TYPE_AC_ACBEL_FSF045, 0x15, 10, "FSF045-"} +}; + +struct serial_number_info serials[] = { + {PSU_TYPE_AC_110V, 0x2e, 18, "YM-2651Y"}, + {PSU_TYPE_DC_48V, 0x2e, 18, "YM-2651V"}, + {PSU_TYPE_DC_12V, 0x2e, 18, "PSU-12V-750"}, + {PSU_TYPE_AC_ACBEL_FSF019, 0x2e, 16, "FSF019-"}, + {PSU_TYPE_AC_ACBEL_FSF045, 0x2e, 16, "FSF045-"} +}; + +static int as7326_56x_psu_model_name_get(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as7326_56x_psu_data *data = i2c_get_clientdata(client); + int i, status; + + for (i = 0; i < ARRAY_SIZE(models); i++) { + memset(data->model_name, 0, sizeof(data->model_name)); + + status = as7326_56x_psu_read_block(client, models[i].offset, + data->model_name, models[i].length); + if (status < 0) { + data->model_name[0] = '\0'; + dev_dbg(&client->dev, "unable to read model name from (0x%x) offset(0x%x)\n", + client->addr, models[i].offset); + return status; + } + else { + data->model_name[models[i].length] = '\0'; + } + + /* Determine if the model name is known, if not, read next index + */ + if (strncmp(data->model_name, models[i].model_name, strlen(models[i].model_name)) == 0) { + return 0; + } + else { + data->model_name[0] = '\0'; + } + } + + return -ENODATA; +} + +static int as7326_56x_psu_serial_number_get(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as7326_56x_psu_data *data = i2c_get_clientdata(client); + int i, status; + + for (i = 0; i < ARRAY_SIZE(models); i++) { + memset(data->serial_number, 0, sizeof(data->serial_number)); + + status = as7326_56x_psu_read_block(client, serials[i].offset, + data->serial_number, serials[i].length); + if (status < 0) { + data->serial_number[0] = '\0'; + dev_dbg(&client->dev, "unable to read serial_number from (0x%x) offset(0x%x)\n", + client->addr, serials[i].offset); + return status; + } + else { + data->serial_number[serials[i].length] = '\0'; + } + + /* Determine if the model name is known, if not, read next index + */ + if (strncmp(data->model_name, models[i].model_name, strlen(models[i].model_name)) == 0) { + return 0; + } + else { + data->serial_number[0] = '\0'; + } + } + + return -ENODATA; +} + static struct as7326_56x_psu_data *as7326_56x_psu_update_device(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); @@ -231,6 +362,7 @@ static struct as7326_56x_psu_data *as7326_56x_psu_update_device(struct device *d int status; int power_good = 0; + data->valid = 0; dev_dbg(&client->dev, "Starting as7326_56x update\n"); /* Read psu status */ @@ -238,6 +370,7 @@ static struct as7326_56x_psu_data *as7326_56x_psu_update_device(struct device *d if (status < 0) { dev_dbg(&client->dev, "cpld reg 0x60 err %d\n", status); + goto exit; } else { data->status = status; @@ -245,18 +378,15 @@ static struct as7326_56x_psu_data *as7326_56x_psu_update_device(struct device *d /* Read model name */ memset(data->model_name, 0, sizeof(data->model_name)); + memset(data->serial_number, 0, sizeof(data->serial_number)); power_good = (data->status >> (3-data->index) & 0x1); if (power_good) { - status = as7326_56x_psu_read_block(client, 0x20, data->model_name, - ARRAY_SIZE(data->model_name)-1); - - if (status < 0) { - data->model_name[0] = '\0'; - dev_dbg(&client->dev, "unable to read model name from (0x%x)\n", client->addr); + if (as7326_56x_psu_model_name_get(dev) < 0) { + goto exit; } - else { - data->model_name[ARRAY_SIZE(data->model_name)-1] = '\0'; + if (as7326_56x_psu_serial_number_get(dev) < 0) { + goto exit; } } @@ -264,6 +394,7 @@ static struct as7326_56x_psu_data *as7326_56x_psu_update_device(struct device *d data->valid = 1; } +exit: mutex_unlock(&data->update_lock); return data; diff --git a/platform/broadcom/sonic-platform-modules-accton/as7326-56x/modules/accton_i2c_cpld.c b/platform/broadcom/sonic-platform-modules-accton/as7326-56x/modules/accton_i2c_cpld.c index 70d9a66affd..a67d6607ed3 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as7326-56x/modules/accton_i2c_cpld.c +++ b/platform/broadcom/sonic-platform-modules-accton/as7326-56x/modules/accton_i2c_cpld.c @@ -760,7 +760,7 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, return 0; } - if (attr->index >= MODULE_PRESENT_1 && attr->index <= MODULE_PRESENT_56) { + if (attr->index >= MODULE_PRESENT_1 && attr->index <= MODULE_PRESENT_58) { revert = 1; } diff --git a/platform/broadcom/sonic-platform-modules-accton/as7326-56x/modules/pddf_custom_psu.c b/platform/broadcom/sonic-platform-modules-accton/as7326-56x/modules/pddf_custom_psu.c new file mode 100644 index 00000000000..4e3d4af3ef3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7326-56x/modules/pddf_custom_psu.c @@ -0,0 +1,229 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pddf_psu_defs.h" + +ssize_t pddf_get_custom_psu_model_name(struct device *dev, struct device_attribute *da, char *buf); +ssize_t pddf_get_custom_psu_serial_num(struct device *dev, struct device_attribute *da, char *buf); +extern PSU_SYSFS_ATTR_DATA access_psu_model_name; +extern PSU_SYSFS_ATTR_DATA access_psu_serial_num; + +#define MAX_MODEL_NAME 16 +#define MAX_SERIAL_NUMBER 19 + +enum psu_type { + PSU_TYPE_AC_110V, + PSU_TYPE_DC_48V, + PSU_TYPE_DC_12V, + PSU_TYPE_AC_ACBEL_FSF019 +}; + +struct model_name_info { + enum psu_type type; + u8 offset; + u8 length; + u8 chk_length; + char* model_name; +}; + +struct serial_number_info { + enum psu_type type; + u8 offset; + u8 length; + u8 chk_length; + char* serial_number; +}; + +struct model_name_info models[] = { +{PSU_TYPE_AC_110V, 0x20, 8, 8, "YM-2651Y"}, +{PSU_TYPE_DC_48V, 0x20, 8, 8, "YM-2651V"}, +{PSU_TYPE_DC_12V, 0x00, 11, 11, "PSU-12V-750"}, +{PSU_TYPE_AC_ACBEL_FSF019, 0x15, 10, 7, "FSF019-"} + +}; + +struct serial_number_info serials[] = { +{PSU_TYPE_AC_110V, 0x35, 18, 18, "YM-2651Y"}, +{PSU_TYPE_DC_48V, 0x2e, 18, 18, "YM-2651V"}, +{PSU_TYPE_DC_12V, 0x2e, 18, 18, "PSU-12V-750"}, +{PSU_TYPE_AC_ACBEL_FSF019, 0x2e, 16, 16, "FSF019-"} + +}; + +struct pddf_psu_data { + char model_name[MAX_MODEL_NAME+1]; + char serial_number[MAX_SERIAL_NUMBER+1]; +}; + + +static int pddf_psu_read_block(struct i2c_client *client, u8 command, u8 *data, + int data_len) +{ + int result = 0; + int retry_count = 10; + + while (retry_count) { + retry_count--; + + result = i2c_smbus_read_i2c_block_data(client, command, data_len, data); + + if (unlikely(result < 0)) { + msleep(10); + continue; + } + + if (unlikely(result != data_len)) { + result = -EIO; + msleep(10); + continue; + } + + result = 0; + break; + } + + return result; +} + +ssize_t pddf_get_custom_psu_serial_num(struct device *dev, struct device_attribute *da, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct pddf_psu_data data; + char sub_type[4]; + int i, status; + + for (i = 0; i < ARRAY_SIZE(models); i++) { + memset(data.serial_number, 0, sizeof(data.serial_number)); + + status = pddf_psu_read_block(client, models[i].offset, + data.model_name, models[i].length); + if (status < 0) { + data.model_name[0] = '\0'; + dev_dbg(&client->dev, "unable to read model name from (0x%x) offset(0x%x)\n", + client->addr, models[i].offset); + return status; + } + else { + data.model_name[models[i].length] = '\0'; + } + + /* Determine if the model name is known, if not, read next index + */ + if (strncmp(data.model_name, models[i].model_name, models[i].chk_length) == 0) { + /*For YM-2651Y BR. BR use offset-0x2e to store SN. + *B01R use offset-0x35 to store store SN. Default use 0x35 for YM-2651Y + */ + if(!strncmp(models[i].model_name, "YM-2651Y", sizeof(models[i].model_name))) + { + memset(sub_type, 0, sizeof(sub_type)); + status = pddf_psu_read_block(client, 0x29, + sub_type, sizeof(sub_type)); + + if (status < 0) { + data.serial_number[0] = '\0'; + dev_dbg(&client->dev, "unable to read sub_type from (0x%x) offset(0x%x)\n", + client->addr, 0x29); + return status; + } + else + { + if(!strncmp(sub_type,"BR" , 2)) + { + serials[i].offset=0x2e; + } + } + } + + status = pddf_psu_read_block(client, serials[i].offset, + data.serial_number, serials[i].length); + + if (status < 0) { + data.serial_number[0] = '\0'; + dev_dbg(&client->dev, "unable to read serial num from (0x%x) offset(0x%x)\n", + client->addr, serials[i].offset); + return status; + } + else { + data.serial_number[serials[i].length] = '\0'; + return sprintf(buf, "%s\n", data.serial_number); + } + + return 0; + } + else { + data.serial_number[0] = '\0'; + } + } + + return -ENODATA; + + +} + +ssize_t pddf_get_custom_psu_model_name(struct device *dev, struct device_attribute *da, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct pddf_psu_data data; + int i, status; + + for (i = 0; i < ARRAY_SIZE(models); i++) { + memset(data.model_name, 0, sizeof(data.model_name)); + + status = pddf_psu_read_block(client, models[i].offset, + data.model_name, models[i].length); + if (status < 0) { + data.model_name[0] = '\0'; + dev_dbg(&client->dev, "unable to read model name from (0x%x) offset(0x%x)\n", + client->addr, models[i].offset); + return status; + } + else { + data.model_name[models[i].length] = '\0'; + } + + /* Determine if the model name is known, if not, read next index + */ + if (strncmp(data.model_name, models[i].model_name, models[i].chk_length) == 0) { + return sprintf(buf, "%s\n", data.model_name); + } + else { + data.model_name[0] = '\0'; + } + } + + return -ENODATA; + +} + +static int __init pddf_custom_psu_init(void) +{ + access_psu_serial_num.show = pddf_get_custom_psu_serial_num; + access_psu_serial_num.do_get = NULL; + + access_psu_model_name.show = pddf_get_custom_psu_model_name; + access_psu_model_name.do_get = NULL; + + return 0; +} + +static void __exit pddf_custom_psu_exit(void) +{ + printk(KERN_ERR "pddf_custom_psu_exit\n"); + return; +} + +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("pddf custom psu api"); +MODULE_LICENSE("GPL"); + +module_init(pddf_custom_psu_init); +module_exit(pddf_custom_psu_exit); + diff --git a/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/classes/__init__.py b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/classes/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/modules/Makefile b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/modules/Makefile new file mode 100644 index 00000000000..9ea424e4eba --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/modules/Makefile @@ -0,0 +1,17 @@ +ifneq ($(KERNELRELEASE),) +obj-m:= x86-64-accton-as7535-32xb-cpld.o x86-64-accton-as7535-32xb-fan.o \ + x86-64-accton-as7535-32xb-leds.o x86-64-accton-as7535-32xb-psu.o \ + x86-64-accton-as7535-32xb-thermal.o + +else +ifeq (,$(KERNEL_SRC)) +$(error KERNEL_SRC is not defined) +else +KERNELDIR:=$(KERNEL_SRC) +endif +PWD:=$(shell pwd) +default: + $(MAKE) -C $(KERNELDIR) M=$(PWD) modules +clean: + rm -rf *.o *.mod.o *.mod.o *.ko .*cmd .tmp_versions Module.markers Module.symvers modules.order +endif diff --git a/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/modules/x86-64-accton-as7535-32xb-cpld.c b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/modules/x86-64-accton-as7535-32xb-cpld.c new file mode 100644 index 00000000000..5145ae519f8 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/modules/x86-64-accton-as7535-32xb-cpld.c @@ -0,0 +1,805 @@ +/* + * A hwmon driver for the as7535_32xb_cpld + * + * Copyright (C) 2019 Edgecore Networks Corporation. + * Jostar Yang + * + * Based on ad7414.c + * Copyright 2006 Stefan Roese , DENX Software Engineering + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as7535_32xb_cpld" + +static LIST_HEAD(cpld_client_list); +static struct mutex list_lock; + +struct cpld_client_node { + struct i2c_client *client; + struct list_head list; +}; + +enum cpld_type { + as7535_32xb_cpld1, + as7535_32xb_fpga, +}; + +#define I2C_RW_RETRY_COUNT 10 +#define I2C_RW_RETRY_INTERVAL 60 /* ms */ + +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t set_control(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t access(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t show_version(struct device *dev, struct device_attribute *da, + char *buf); + +struct as7535_32xb_cpld_data { + struct mutex update_lock; + u8 index; /* CPLD index */ +}; + +/* Addresses scanned for as7535_32xb_cpld + */ +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +#define TRANSCEIVER_PRESENT_ATTR_ID(index) MODULE_PRESENT_##index +#define TRANSCEIVER_RESET_ATTR_ID(index) MODULE_RESET_##index +#define TRANSCEIVER_RXLOS_ATTR_ID(index) MODULE_RXLOS_##index +#define TRANSCEIVER_TXFAULT_ATTR_ID(index) MODULE_TXFAULT_##index +#define TRANSCEIVER_TXDISABLE_ATTR_ID(index) MODULE_TXDISABLE_##index + +enum as7535_32xb_cpld_sysfs_attributes { + /* transceiver attributes */ + TRANSCEIVER_PRESENT_ATTR_ID(1), + TRANSCEIVER_PRESENT_ATTR_ID(2), + TRANSCEIVER_PRESENT_ATTR_ID(3), + TRANSCEIVER_PRESENT_ATTR_ID(4), + TRANSCEIVER_PRESENT_ATTR_ID(5), + TRANSCEIVER_PRESENT_ATTR_ID(6), + TRANSCEIVER_PRESENT_ATTR_ID(7), + TRANSCEIVER_PRESENT_ATTR_ID(8), + TRANSCEIVER_PRESENT_ATTR_ID(9), + TRANSCEIVER_PRESENT_ATTR_ID(10), + TRANSCEIVER_PRESENT_ATTR_ID(11), + TRANSCEIVER_PRESENT_ATTR_ID(12), + TRANSCEIVER_PRESENT_ATTR_ID(13), + TRANSCEIVER_PRESENT_ATTR_ID(14), + TRANSCEIVER_PRESENT_ATTR_ID(15), + TRANSCEIVER_PRESENT_ATTR_ID(16), + TRANSCEIVER_PRESENT_ATTR_ID(17), + TRANSCEIVER_PRESENT_ATTR_ID(18), + TRANSCEIVER_PRESENT_ATTR_ID(19), + TRANSCEIVER_PRESENT_ATTR_ID(20), + TRANSCEIVER_PRESENT_ATTR_ID(21), + TRANSCEIVER_PRESENT_ATTR_ID(22), + TRANSCEIVER_PRESENT_ATTR_ID(23), + TRANSCEIVER_PRESENT_ATTR_ID(24), + TRANSCEIVER_PRESENT_ATTR_ID(25), + TRANSCEIVER_PRESENT_ATTR_ID(26), + TRANSCEIVER_PRESENT_ATTR_ID(28), + TRANSCEIVER_PRESENT_ATTR_ID(30), + TRANSCEIVER_PRESENT_ATTR_ID(27), + TRANSCEIVER_PRESENT_ATTR_ID(29), + TRANSCEIVER_TXDISABLE_ATTR_ID(1), + TRANSCEIVER_TXDISABLE_ATTR_ID(2), + TRANSCEIVER_TXDISABLE_ATTR_ID(3), + TRANSCEIVER_TXDISABLE_ATTR_ID(4), + TRANSCEIVER_TXDISABLE_ATTR_ID(5), + TRANSCEIVER_TXDISABLE_ATTR_ID(6), + TRANSCEIVER_TXDISABLE_ATTR_ID(7), + TRANSCEIVER_TXDISABLE_ATTR_ID(8), + TRANSCEIVER_TXDISABLE_ATTR_ID(9), + TRANSCEIVER_TXDISABLE_ATTR_ID(10), + TRANSCEIVER_TXDISABLE_ATTR_ID(11), + TRANSCEIVER_TXDISABLE_ATTR_ID(12), + TRANSCEIVER_TXDISABLE_ATTR_ID(13), + TRANSCEIVER_TXDISABLE_ATTR_ID(14), + TRANSCEIVER_TXDISABLE_ATTR_ID(15), + TRANSCEIVER_TXDISABLE_ATTR_ID(16), + TRANSCEIVER_TXDISABLE_ATTR_ID(17), + TRANSCEIVER_TXDISABLE_ATTR_ID(18), + TRANSCEIVER_TXDISABLE_ATTR_ID(19), + TRANSCEIVER_TXDISABLE_ATTR_ID(20), + TRANSCEIVER_TXDISABLE_ATTR_ID(21), + TRANSCEIVER_TXDISABLE_ATTR_ID(22), + TRANSCEIVER_TXDISABLE_ATTR_ID(23), + TRANSCEIVER_TXDISABLE_ATTR_ID(24), + TRANSCEIVER_TXDISABLE_ATTR_ID(25), + TRANSCEIVER_TXDISABLE_ATTR_ID(26), + TRANSCEIVER_RXLOS_ATTR_ID(1), + TRANSCEIVER_RXLOS_ATTR_ID(2), + TRANSCEIVER_RXLOS_ATTR_ID(3), + TRANSCEIVER_RXLOS_ATTR_ID(4), + TRANSCEIVER_RXLOS_ATTR_ID(5), + TRANSCEIVER_RXLOS_ATTR_ID(6), + TRANSCEIVER_RXLOS_ATTR_ID(7), + TRANSCEIVER_RXLOS_ATTR_ID(8), + TRANSCEIVER_RXLOS_ATTR_ID(9), + TRANSCEIVER_RXLOS_ATTR_ID(10), + TRANSCEIVER_RXLOS_ATTR_ID(11), + TRANSCEIVER_RXLOS_ATTR_ID(12), + TRANSCEIVER_RXLOS_ATTR_ID(13), + TRANSCEIVER_RXLOS_ATTR_ID(14), + TRANSCEIVER_RXLOS_ATTR_ID(15), + TRANSCEIVER_RXLOS_ATTR_ID(16), + TRANSCEIVER_RXLOS_ATTR_ID(17), + TRANSCEIVER_RXLOS_ATTR_ID(18), + TRANSCEIVER_RXLOS_ATTR_ID(19), + TRANSCEIVER_RXLOS_ATTR_ID(20), + TRANSCEIVER_RXLOS_ATTR_ID(21), + TRANSCEIVER_RXLOS_ATTR_ID(22), + TRANSCEIVER_RXLOS_ATTR_ID(23), + TRANSCEIVER_RXLOS_ATTR_ID(24), + TRANSCEIVER_RXLOS_ATTR_ID(25), + TRANSCEIVER_RXLOS_ATTR_ID(26), + TRANSCEIVER_TXFAULT_ATTR_ID(1), + TRANSCEIVER_TXFAULT_ATTR_ID(2), + TRANSCEIVER_TXFAULT_ATTR_ID(3), + TRANSCEIVER_TXFAULT_ATTR_ID(4), + TRANSCEIVER_TXFAULT_ATTR_ID(5), + TRANSCEIVER_TXFAULT_ATTR_ID(6), + TRANSCEIVER_TXFAULT_ATTR_ID(7), + TRANSCEIVER_TXFAULT_ATTR_ID(8), + TRANSCEIVER_TXFAULT_ATTR_ID(9), + TRANSCEIVER_TXFAULT_ATTR_ID(10), + TRANSCEIVER_TXFAULT_ATTR_ID(11), + TRANSCEIVER_TXFAULT_ATTR_ID(12), + TRANSCEIVER_TXFAULT_ATTR_ID(13), + TRANSCEIVER_TXFAULT_ATTR_ID(14), + TRANSCEIVER_TXFAULT_ATTR_ID(15), + TRANSCEIVER_TXFAULT_ATTR_ID(16), + TRANSCEIVER_TXFAULT_ATTR_ID(17), + TRANSCEIVER_TXFAULT_ATTR_ID(18), + TRANSCEIVER_TXFAULT_ATTR_ID(19), + TRANSCEIVER_TXFAULT_ATTR_ID(20), + TRANSCEIVER_TXFAULT_ATTR_ID(21), + TRANSCEIVER_TXFAULT_ATTR_ID(22), + TRANSCEIVER_TXFAULT_ATTR_ID(23), + TRANSCEIVER_TXFAULT_ATTR_ID(24), + TRANSCEIVER_TXFAULT_ATTR_ID(25), + TRANSCEIVER_TXFAULT_ATTR_ID(26), + TRANSCEIVER_RESET_ATTR_ID(28), + TRANSCEIVER_RESET_ATTR_ID(30), + TRANSCEIVER_RESET_ATTR_ID(27), + TRANSCEIVER_RESET_ATTR_ID(29), + MODULE_PRESENT_ALL, + CPLD_VERSION, + FPGA_VER_MAJOR, + FPGA_VER_MINOR, + ACCESS, +}; + +/* sysfs attributes for hwmon + */ + +/* qsfp transceiver attributes */ +#define DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, show_status, \ + NULL, MODULE_PRESENT_##index); \ + static SENSOR_DEVICE_ATTR(module_reset_##index, S_IRUGO | S_IWUSR, \ + show_status, set_control, MODULE_RESET_##index) +#define DECLARE_QSFP28_TRANSCEIVER_ATTR(index) \ + &sensor_dev_attr_module_present_##index.dev_attr.attr, \ + &sensor_dev_attr_module_reset_##index.dev_attr.attr + +#define DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, \ + show_status, NULL, MODULE_PRESENT_##index); \ + static SENSOR_DEVICE_ATTR(module_reset_##index, S_IRUGO | S_IWUSR, \ + show_status, set_control, MODULE_RESET_##index) +#define DECLARE_QSFPDD_TRANSCEIVER_ATTR(index) \ + &sensor_dev_attr_module_present_##index.dev_attr.attr, \ + &sensor_dev_attr_module_reset_##index.dev_attr.attr + +/* sfp transceiver attributes */ +#define DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, show_status, \ + NULL, MODULE_PRESENT_##index); \ + static SENSOR_DEVICE_ATTR(module_tx_disable_##index, S_IRUGO | S_IWUSR, \ + show_status, set_tx_disable, \ + MODULE_TXDISABLE_##index); \ + static SENSOR_DEVICE_ATTR(module_tx_fault_##index, S_IRUGO, show_status, \ + NULL, MODULE_TXFAULT_##index); \ + static SENSOR_DEVICE_ATTR(module_rx_los_##index, S_IRUGO, show_status, \ + NULL, MODULE_RXLOS_##index) + +#define DECLARE_SFP_TRANSCEIVER_ATTR(index) \ + &sensor_dev_attr_module_present_##index.dev_attr.attr, \ + &sensor_dev_attr_module_tx_disable_##index.dev_attr.attr, \ + &sensor_dev_attr_module_tx_fault_##index.dev_attr.attr, \ + &sensor_dev_attr_module_rx_los_##index.dev_attr.attr + +static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, NULL, CPLD_VERSION); +static SENSOR_DEVICE_ATTR(fpga_ver_major, S_IRUGO, show_version, NULL, + FPGA_VER_MAJOR); +static SENSOR_DEVICE_ATTR(fpga_ver_minor, S_IRUGO, show_version, NULL, + FPGA_VER_MINOR); +static SENSOR_DEVICE_ATTR(access, S_IWUSR, NULL, access, ACCESS); + +/* transceiver attributes */ +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(1); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(2); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(3); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(4); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(5); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(6); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(7); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(8); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(9); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(10); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(11); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(12); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(13); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(14); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(15); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(16); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(17); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(18); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(19); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(20); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(21); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(22); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(23); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(24); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(25); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(26); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(27); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(28); +DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(29); +DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(30); + +static struct attribute *as7535_32xb_cpld1_attributes[] = { + /* transceiver attributes */ + DECLARE_SFP_TRANSCEIVER_ATTR(1), + DECLARE_SFP_TRANSCEIVER_ATTR(2), + DECLARE_SFP_TRANSCEIVER_ATTR(3), + DECLARE_SFP_TRANSCEIVER_ATTR(4), + DECLARE_SFP_TRANSCEIVER_ATTR(5), + DECLARE_SFP_TRANSCEIVER_ATTR(6), + DECLARE_SFP_TRANSCEIVER_ATTR(7), + DECLARE_SFP_TRANSCEIVER_ATTR(8), + DECLARE_SFP_TRANSCEIVER_ATTR(9), + DECLARE_SFP_TRANSCEIVER_ATTR(10), + DECLARE_SFP_TRANSCEIVER_ATTR(11), + DECLARE_SFP_TRANSCEIVER_ATTR(12), + DECLARE_SFP_TRANSCEIVER_ATTR(13), + DECLARE_SFP_TRANSCEIVER_ATTR(14), + DECLARE_SFP_TRANSCEIVER_ATTR(15), + DECLARE_SFP_TRANSCEIVER_ATTR(16), + DECLARE_SFP_TRANSCEIVER_ATTR(17), + DECLARE_SFP_TRANSCEIVER_ATTR(18), + DECLARE_SFP_TRANSCEIVER_ATTR(19), + DECLARE_SFP_TRANSCEIVER_ATTR(20), + DECLARE_SFP_TRANSCEIVER_ATTR(21), + DECLARE_SFP_TRANSCEIVER_ATTR(22), + DECLARE_SFP_TRANSCEIVER_ATTR(23), + DECLARE_SFP_TRANSCEIVER_ATTR(24), + DECLARE_SFP_TRANSCEIVER_ATTR(25), + DECLARE_SFP_TRANSCEIVER_ATTR(26), + DECLARE_QSFP28_TRANSCEIVER_ATTR(27), + DECLARE_QSFP28_TRANSCEIVER_ATTR(28), + DECLARE_QSFPDD_TRANSCEIVER_ATTR(29), + DECLARE_QSFPDD_TRANSCEIVER_ATTR(30), + &sensor_dev_attr_version.dev_attr.attr, + &sensor_dev_attr_access.dev_attr.attr, + NULL +}; + +static struct attribute *as7535_32xb_fpga_attributes[] = { + &sensor_dev_attr_fpga_ver_major.dev_attr.attr, + &sensor_dev_attr_fpga_ver_minor.dev_attr.attr, + &sensor_dev_attr_access.dev_attr.attr, + NULL +}; + +static const struct attribute_group as7535_32xb_cpld1_group = { + .attrs = as7535_32xb_cpld1_attributes, +}; + +static const struct attribute_group as7535_32xb_fpga_group = { + .attrs = as7535_32xb_fpga_attributes, +}; + +static const struct attribute_group* cpld_groups[] = { + &as7535_32xb_cpld1_group, + &as7535_32xb_fpga_group, +}; + +int as7535_32xb_cpld_read(int bus_num, unsigned short cpld_addr, u8 reg) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int ret = -EPERM; + + 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 + && cpld_node->client->adapter->nr == bus_num) { + ret = i2c_smbus_read_byte_data(cpld_node->client, reg); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(as7535_32xb_cpld_read); + +int as7535_32xb_cpld_write(int bus_num, 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 + && cpld_node->client->adapter->nr == bus_num) { + ret = i2c_smbus_write_byte_data(cpld_node->client, reg, value); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(as7535_32xb_cpld_write); + +static ssize_t show_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 as7535_32xb_cpld_data *data = i2c_get_clientdata(client); + int status = 0; + u8 reg = 0, mask = 0, invert = 0; + + switch (attr->index) { + case MODULE_PRESENT_1 ... MODULE_PRESENT_8: + invert = 1; + reg = 0x11; + mask = 0x1 << (attr->index - MODULE_PRESENT_1); + break; + case MODULE_PRESENT_9 ... MODULE_PRESENT_16: + invert = 1; + reg = 0x12; + mask = 0x1 << (attr->index - MODULE_PRESENT_9); + break; + case MODULE_PRESENT_17 ... MODULE_PRESENT_24: + invert = 1; + reg = 0x13; + mask = 0x1 << (attr->index - MODULE_PRESENT_17); + break; + case MODULE_PRESENT_25 ... MODULE_PRESENT_26: + invert = 1; + reg = 0x14; + mask = 0x1 << (attr->index - MODULE_PRESENT_25); + break; + case MODULE_PRESENT_28 ... MODULE_PRESENT_29: + invert = 1; + reg = 0x10; + mask = 0x1 << (attr->index - MODULE_PRESENT_28); + break; + case MODULE_TXDISABLE_1 ... MODULE_TXDISABLE_8: + reg = 0xA; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_1); + break; + case MODULE_TXDISABLE_9 ... MODULE_TXDISABLE_16: + reg = 0xB; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_9); + break; + case MODULE_TXDISABLE_17 ... MODULE_TXDISABLE_24: + reg = 0xC; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_17); + break; + case MODULE_TXDISABLE_25 ... MODULE_TXDISABLE_26: + reg = 0xD; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_25); + break; + case MODULE_TXFAULT_1 ... MODULE_TXFAULT_8: + reg = 0x15; + mask = 0x1 << (attr->index - MODULE_TXFAULT_1); + break; + case MODULE_TXFAULT_9 ... MODULE_TXFAULT_16: + reg = 0x16; + mask = 0x1 << (attr->index - MODULE_TXFAULT_9); + break; + case MODULE_TXFAULT_17 ... MODULE_TXFAULT_24: + reg = 0x17; + mask = 0x1 << (attr->index - MODULE_TXFAULT_17); + break; + case MODULE_TXFAULT_25 ... MODULE_TXFAULT_26: + reg = 0x18; + mask = 0x1 << (attr->index - MODULE_TXFAULT_25); + break; + case MODULE_RXLOS_1 ... MODULE_RXLOS_8: + reg = 0x21; + mask = 0x1 << (attr->index - MODULE_RXLOS_1); + break; + case MODULE_RXLOS_9 ... MODULE_RXLOS_16: + reg = 0x22; + mask = 0x1 << (attr->index - MODULE_RXLOS_9); + break; + case MODULE_RXLOS_17 ... MODULE_RXLOS_24: + reg = 0x23; + mask = 0x1 << (attr->index - MODULE_RXLOS_17); + break; + case MODULE_RXLOS_25 ... MODULE_RXLOS_26: + reg = 0x24; + mask = 0x1 << (attr->index - MODULE_RXLOS_25); + break; + case MODULE_RESET_28 ... MODULE_RESET_29: + invert = 1; + reg = 0x8; + mask = 0x1 << (attr->index - MODULE_RESET_28); + break; + default: + return -ENXIO; + } + + mutex_lock(&data->update_lock); + + status = as7535_32xb_cpld_read(12, 0x61, reg); + if (unlikely(status < 0)) + goto exit; + + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", invert? !(status & mask): !!(status & mask)); + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t set_tx_disable(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 as7535_32xb_cpld_data *data = i2c_get_clientdata(client); + long disable; + int status, val; + u8 reg = 0, mask = 0; + + status = kstrtol(buf, 10, &disable); + if (status) + return status; + + switch (attr->index) { + case MODULE_TXDISABLE_1 ... MODULE_TXDISABLE_8: + reg = 0xA; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_1); + break; + case MODULE_TXDISABLE_9 ... MODULE_TXDISABLE_16: + reg = 0xB; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_9); + break; + case MODULE_TXDISABLE_17 ... MODULE_TXDISABLE_24: + reg = 0xC; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_17); + break; + case MODULE_TXDISABLE_25 ... MODULE_TXDISABLE_26: + reg = 0xD; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_25); + break; + default: + return 0; + } + /* Read current status */ + mutex_lock(&data->update_lock); + val = as7535_32xb_cpld_read(12, 0x61, reg); + if (unlikely(status < 0)) + goto exit; + + /* Update tx_disable status */ + if (disable) + val |= mask; + else + val &= ~mask; + + status = as7535_32xb_cpld_write(12, 0x61, reg, val); + if (unlikely(status < 0)) + goto exit; + + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t set_control(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 as7535_32xb_cpld_data *data = i2c_get_clientdata(client); + long reset; + int status; + u8 reg = 0, mask = 0; + + status = kstrtol(buf, 10, &reset); + if (status) + return status; + + switch (attr->index) { + case MODULE_RESET_28 ... MODULE_RESET_29: + reg = 0x8; + mask = 0x1 << (attr->index - MODULE_RESET_28); + break; + default: + return -ENXIO; + } + + mutex_lock(&data->update_lock); + /* Read current status */ + status = as7535_32xb_cpld_read(12, 0x61, reg); + if (unlikely(status < 0)) + goto exit; + + /* Update reset status */ + if (reset) + status &= ~mask; + else + status |= mask; + + status = as7535_32xb_cpld_write(12, 0x61, reg, status); + if (unlikely(status < 0)) + goto exit; + + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static void as7535_32xb_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 as7535_32xb_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 ssize_t access(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int status; + u32 reg, val; + struct i2c_client *client = to_i2c_client(dev); + struct as7535_32xb_cpld_data *data = i2c_get_clientdata(client); + + if (sscanf(buf, "0x%x 0x%x", ®, &val) != 2) + return -EINVAL; + + if (reg > 0xFF || val > 0xFF) + return -EINVAL; + + mutex_lock(&data->update_lock); + + status = as7535_32xb_cpld_write(12, 0x61, reg, val); + if (unlikely(status < 0)) + goto exit; + + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t show_version(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 as7535_32xb_cpld_data *data = i2c_get_clientdata(client); + int status = 0; + u8 bus, addr, reg; + + switch (attr->index) { + case CPLD_VERSION: + bus = 12; + addr = 0x61; + reg = 0x1; + break; + case FPGA_VER_MAJOR: + bus = 11; + addr = 0x60; + reg = 0x1; + break; + case FPGA_VER_MINOR: + bus = 11; + addr = 0x60; + reg = 0x2; + break; + default: + return -ENXIO; + } + + mutex_lock(&data->update_lock); + + status = as7535_32xb_cpld_read(bus, addr, reg); + if (unlikely(status < 0)) { + mutex_unlock(&data->update_lock); + goto exit; + } + + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", status); +exit: + return status; +} + + +static int as7535_32xb_cpld_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + int status; + struct as7535_32xb_cpld_data *data = NULL; + + 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; + } + + data = kzalloc(sizeof(struct as7535_32xb_cpld_data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + data->index = dev_id->driver_data; + mutex_init(&data->update_lock); + dev_info(&client->dev, "chip found\n"); + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, cpld_groups[data->index]); + if (status) + goto exit_free; + + as7535_32xb_cpld_add_client(client); + + dev_info(&client->dev, "%s: cpld '%s'\n", + dev_name(&client->dev), client->name); + + return 0; + +exit_free: + kfree(data); +exit: + + return status; +} + +static int as7535_32xb_cpld_remove(struct i2c_client *client) +{ + struct as7535_32xb_cpld_data *data = i2c_get_clientdata(client); + + sysfs_remove_group(&client->dev.kobj, cpld_groups[data->index]); + kfree(data); + as7535_32xb_cpld_remove_client(client); + + return 0; +} + +static const struct i2c_device_id as7535_32xb_cpld_id[] = { + { "as7535_32xb_cpld1", as7535_32xb_cpld1 }, + { "as7535_32xb_fpga", as7535_32xb_fpga }, + {} +}; +MODULE_DEVICE_TABLE(i2c, as7535_32xb_cpld_id); + +static struct i2c_driver as7535_32xb_cpld_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = DRVNAME, + }, + .probe = as7535_32xb_cpld_probe, + .remove = as7535_32xb_cpld_remove, + .id_table = as7535_32xb_cpld_id, + .address_list = normal_i2c, +}; + +static int __init as7535_32xb_cpld_init(void) +{ + mutex_init(&list_lock); + return i2c_add_driver(&as7535_32xb_cpld_driver); +} + +static void __exit as7535_32xb_cpld_exit(void) +{ + i2c_del_driver(&as7535_32xb_cpld_driver); +} + +module_init(as7535_32xb_cpld_init); +module_exit(as7535_32xb_cpld_exit); + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("as7535_32xb_cpld driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/modules/x86-64-accton-as7535-32xb-fan.c b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/modules/x86-64-accton-as7535-32xb-fan.c new file mode 100644 index 00000000000..19a640fe298 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/modules/x86-64-accton-as7535-32xb-fan.c @@ -0,0 +1,683 @@ +/* + * Copyright (C) Brandon Chuang + * + * + * Based on: + * pca954x.c from Kumar Gala + * Copyright (C) 2006 + * + * Based on: + * pca954x.c from Ken Harrenstien + * Copyright (C) 2004 Google, Inc. (Ken Harrenstien) + * + * Based on: + * i2c-virtual_cb.c from Brian Kuschak + * and + * pca9540.c from Jean Delvare . + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as7535_32xb_fan" +#define ACCTON_IPMI_NETFN 0x34 +#define IPMI_FAN_READ_CMD 0x14 +#define IPMI_FAN_WRITE_CMD 0x15 +#define IPMI_FAN_READ_RPM_CMD 0x20 +#define IPMI_TIMEOUT (5 * HZ) +#define IPMI_ERR_RETRY_TIMES 1 +#define IPMI_FAN_REG_READ_CMD 0x20 +#define IPMI_FAN_REG_WRITE_CMD 0x21 + +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); +static ssize_t set_fan(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t show_fan(struct device *dev, struct device_attribute *attr, + char *buf); +static ssize_t show_version(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_dir(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_threshold(struct device *dev, struct device_attribute *da, + char *buf); +static int as7535_32xb_fan_probe(struct platform_device *pdev); +static int as7535_32xb_fan_remove(struct platform_device *pdev); + +enum fan_id { + FAN_1, + FAN_2, + FAN_3, + FAN_4, + FAN_5, + FAN_6, + NUM_OF_FAN, + NUM_OF_FAN_MODULE = NUM_OF_FAN/2 +}; + +enum fan_data_index { + FAN_PRESENT, + FAN_PWM, + FAN_SPEED0, + FAN_SPEED1, + FAN_DATA_COUNT, + + FAN_TARGET_SPEED0 = 0, + FAN_TARGET_SPEED1, + FAN_SPEED_TOLERANCE, + FAN_SPEED_DATA_COUNT +}; + +struct ipmi_data { + struct completion read_complete; + struct ipmi_addr address; + struct ipmi_user *user; + int interface; + + struct kernel_ipmi_msg tx_message; + long tx_msgid; + + void *rx_msg_data; + unsigned short rx_msg_len; + unsigned char rx_result; + int rx_recv_type; + + struct ipmi_user_hndl ipmi_hndlrs; +}; + +struct as7535_32xb_fan_data { + struct platform_device *pdev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + /* 4 bytes for each fan, the last 2 bytes is fan dir */ + unsigned char ipmi_resp[NUM_OF_FAN * FAN_DATA_COUNT + 2]; + unsigned char ipmi_resp_cpld; + unsigned char ipmi_resp_speed[NUM_OF_FAN * FAN_SPEED_DATA_COUNT]; + struct ipmi_data ipmi; + unsigned char ipmi_tx_data[3]; /* 0: FAN id, 1: 0x02, 2: PWM */ +}; + +struct as7535_32xb_fan_data *data = NULL; + +static struct platform_driver as7535_32xb_fan_driver = { + .probe = as7535_32xb_fan_probe, + .remove = as7535_32xb_fan_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +#define FAN_PRESENT_ATTR_ID(index) FAN##index##_PRESENT +#define FAN_PWM_ATTR_ID(index) FAN##index##_PWM +#define FAN_RPM_ATTR_ID(index) FAN##index##_INPUT +#define FAN_DIR_ATTR_ID(index) FAN##index##_DIR +#define FAN_RPM_TARGET_ATTR_ID(index) FAN##index##_TARGET +#define FAN_RPM_TOLERANCE_ATTR_ID(index) FAN##index##_TOLERANCE + +#define FAN_ATTR(fan_id) \ + FAN_PRESENT_ATTR_ID(fan_id), \ + FAN_PWM_ATTR_ID(fan_id), \ + FAN_RPM_ATTR_ID(fan_id), \ + FAN_DIR_ATTR_ID(fan_id) + +#define FAN_RPM_THRESHOLD_ATTR(fan_id) \ + FAN_RPM_TARGET_ATTR_ID(fan_id), \ + FAN_RPM_TOLERANCE_ATTR_ID(fan_id) + +enum as7535_32xb_fan_sysfs_attrs { + FAN_ATTR(1), + FAN_ATTR(2), + FAN_ATTR(3), + FAN_ATTR(4), + FAN_ATTR(5), + FAN_ATTR(6), + NUM_OF_FAN_ATTR, + FAN_VERSION, + NUM_OF_PER_FAN_ATTR = (NUM_OF_FAN_ATTR/NUM_OF_FAN), + FAN_RPM_THRESHOLD_ATTR(1), + FAN_RPM_THRESHOLD_ATTR(2), + FAN_RPM_THRESHOLD_ATTR(3), + FAN_RPM_THRESHOLD_ATTR(4), + FAN_RPM_THRESHOLD_ATTR(5), + FAN_RPM_THRESHOLD_ATTR(6) +}; + +/* fan attributes */ +#define DECLARE_FAN_VER_SENSOR_DEVICE_ATTR() \ + static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, NULL, FAN_VERSION) +#define DECLARE_FAN_VER_ATTR() \ + &sensor_dev_attr_version.dev_attr.attr + +#define DECLARE_FAN_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_present, S_IRUGO, show_fan, NULL, \ + FAN##index##_PRESENT); \ + static SENSOR_DEVICE_ATTR(fan##index##_pwm, S_IWUSR | S_IRUGO, show_fan, \ + set_fan, FAN##index##_PWM); \ + static SENSOR_DEVICE_ATTR(fan##index##_input, S_IRUGO, show_fan, NULL, \ + FAN##index##_INPUT); \ + static SENSOR_DEVICE_ATTR(fan##index##_dir, S_IRUGO, show_dir, NULL, \ + FAN##index##_DIR); \ + static SENSOR_DEVICE_ATTR(fan##index##_target, S_IRUGO, show_threshold, \ + NULL, FAN##index##_TARGET); \ + static SENSOR_DEVICE_ATTR(fan##index##_tolerance, S_IRUGO, show_threshold, \ + NULL, FAN##index##_TOLERANCE) + +#define DECLARE_FAN_ATTR(index) \ + &sensor_dev_attr_fan##index##_present.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_pwm.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_input.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_dir.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_target.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_tolerance.dev_attr.attr + +DECLARE_FAN_SENSOR_DEVICE_ATTR(1); +DECLARE_FAN_SENSOR_DEVICE_ATTR(2); +DECLARE_FAN_SENSOR_DEVICE_ATTR(3); +DECLARE_FAN_SENSOR_DEVICE_ATTR(4); +DECLARE_FAN_SENSOR_DEVICE_ATTR(5); +DECLARE_FAN_SENSOR_DEVICE_ATTR(6); +DECLARE_FAN_VER_SENSOR_DEVICE_ATTR(); + +static struct attribute *as7535_32xb_fan_attributes[] = { + /* fan attributes */ + DECLARE_FAN_ATTR(1), + DECLARE_FAN_ATTR(2), + DECLARE_FAN_ATTR(3), + DECLARE_FAN_ATTR(4), + DECLARE_FAN_ATTR(5), + DECLARE_FAN_ATTR(6), + DECLARE_FAN_VER_ATTR(), + NULL +}; + +static const struct attribute_group as7535_32xb_fan_group = { + .attrs = as7535_32xb_fan_attributes, +}; + +/* Functions to talk to the IPMI layer */ + +/* Initialize IPMI address, message buffers and user data */ +static int init_ipmi_data(struct ipmi_data *ipmi, int iface, + struct device *dev) +{ + int err; + + init_completion(&ipmi->read_complete); + + /* Initialize IPMI address */ + ipmi->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + ipmi->address.channel = IPMI_BMC_CHANNEL; + ipmi->address.data[0] = 0; + ipmi->interface = iface; + + /* Initialize message buffers */ + ipmi->tx_msgid = 0; + ipmi->tx_message.netfn = ACCTON_IPMI_NETFN; + + ipmi->ipmi_hndlrs.ipmi_recv_hndl = ipmi_msg_handler; + + /* Create IPMI messaging interface user */ + err = ipmi_create_user(ipmi->interface, &ipmi->ipmi_hndlrs, + ipmi, &ipmi->user); + if (err < 0) { + dev_err(dev, "Unable to register user with IPMI " + "interface %d\n", ipmi->interface); + return -EACCES; + } + + return 0; +} + +/* Send an IPMI command */ +static int _ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int err; + + ipmi->tx_message.cmd = cmd; + ipmi->tx_message.data = tx_data; + ipmi->tx_message.data_len = tx_len; + ipmi->rx_msg_data = rx_data; + ipmi->rx_msg_len = rx_len; + + err = ipmi_validate_addr(&ipmi->address, sizeof(ipmi->address)); + if (err) + goto addr_err; + + ipmi->tx_msgid++; + err = ipmi_request_settime(ipmi->user, &ipmi->address, ipmi->tx_msgid, + &ipmi->tx_message, ipmi, 0, 0, 0); + if (err) + goto ipmi_req_err; + + err = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); + if (!err) + goto ipmi_timeout_err; + + return 0; + +ipmi_timeout_err: + err = -ETIMEDOUT; + dev_err(&data->pdev->dev, "request_timeout=%x\n", err); + return err; +ipmi_req_err: + dev_err(&data->pdev->dev, "request_settime=%x\n", err); + return err; +addr_err: + dev_err(&data->pdev->dev, "validate_addr=%x\n", err); + return err; +} + +/* Send an IPMI command with retry */ +static int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int status = 0, retry = 0; + + for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { + status = _ipmi_send_message(ipmi, cmd, tx_data, tx_len, rx_data, rx_len); + if (unlikely(status != 0)) { + dev_err(&data->pdev->dev, "ipmi_send_message_%d err status(%d)\r\n", + retry, status); + continue; + } + + if (unlikely(ipmi->rx_result != 0)) { + dev_err(&data->pdev->dev, "ipmi_send_message_%d err result(%d)\r\n", + retry, ipmi->rx_result); + continue; + } + + break; + } + + return status; +} + +/* Dispatch IPMI messages to callers */ +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) +{ + unsigned short rx_len; + struct ipmi_data *ipmi = user_msg_data; + + if (msg->msgid != ipmi->tx_msgid) { + dev_err(&data->pdev->dev, "Mismatch between received msgid " + "(%02x) and transmitted msgid (%02x)!\n", + (int)msg->msgid, + (int)ipmi->tx_msgid); + ipmi_free_recv_msg(msg); + return; + } + + ipmi->rx_recv_type = msg->recv_type; + if (msg->msg.data_len > 0) + ipmi->rx_result = msg->msg.data[0]; + else + ipmi->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE; + + if (msg->msg.data_len > 1) { + rx_len = msg->msg.data_len - 1; + if (ipmi->rx_msg_len < rx_len) + rx_len = ipmi->rx_msg_len; + ipmi->rx_msg_len = rx_len; + memcpy(ipmi->rx_msg_data, msg->msg.data + 1, ipmi->rx_msg_len); + } else + ipmi->rx_msg_len = 0; + + ipmi_free_recv_msg(msg); + complete(&ipmi->read_complete); +} + +static struct as7535_32xb_fan_data *as7535_32xb_fan_update_device(void) +{ + int status = 0; + + if (time_before(jiffies, data->last_updated + HZ * 5) && data->valid) + return data; + + data->valid = 0; + status = ipmi_send_message(&data->ipmi, IPMI_FAN_READ_CMD, NULL, 0, + data->ipmi_resp, sizeof(data->ipmi_resp)); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + data->ipmi_tx_data[0] = IPMI_FAN_READ_RPM_CMD; + status = ipmi_send_message(&data->ipmi, IPMI_FAN_READ_CMD, + data->ipmi_tx_data, 1, + data->ipmi_resp_speed, + sizeof(data->ipmi_resp_speed)); + + data->last_updated = jiffies; + data->valid = 1; + +exit: + return data; +} + +static ssize_t show_fan(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + unsigned char fid = attr->index / NUM_OF_PER_FAN_ATTR; + int value = 0; + int index = 0; + int present = 0; + int error = 0; + + mutex_lock(&data->update_lock); + + data = as7535_32xb_fan_update_device(); + if (!data->valid) { + error = -EIO; + goto exit; + } + + index = fid * FAN_DATA_COUNT; /* base index */ + present = !!data->ipmi_resp[index + FAN_PRESENT]; + + switch (attr->index) { + case FAN1_PRESENT: + case FAN2_PRESENT: + case FAN3_PRESENT: + case FAN4_PRESENT: + case FAN5_PRESENT: + case FAN6_PRESENT: + value = present; + break; + case FAN1_PWM: + case FAN2_PWM: + case FAN3_PWM: + case FAN4_PWM: + case FAN5_PWM: + case FAN6_PWM: + index = (fid % NUM_OF_FAN_MODULE) * FAN_DATA_COUNT; + value = (data->ipmi_resp[index + FAN_PWM] + 1) * 625 / 100; + break; + case FAN1_INPUT: + case FAN2_INPUT: + case FAN3_INPUT: + case FAN4_INPUT: + case FAN5_INPUT: + case FAN6_INPUT: + value = (int)data->ipmi_resp[index + FAN_SPEED0] | + (int)data->ipmi_resp[index + FAN_SPEED1] << 8; + break; + default: + error = -EINVAL; + goto exit; + } + + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", present ? value : 0); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static ssize_t set_fan(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + long pwm; + int status; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + unsigned char fid = attr->index / NUM_OF_PER_FAN_ATTR; + + status = kstrtol(buf, 10, &pwm); + if (status) + return status; + + pwm = (pwm * 100) / 625 - 1; /* Convert pwm to register value */ + + mutex_lock(&data->update_lock); + + /* Send IPMI write command */ + data->ipmi_tx_data[0] = (fid % NUM_OF_FAN_MODULE) + 1; + data->ipmi_tx_data[1] = 0x02; + data->ipmi_tx_data[2] = pwm; + status = ipmi_send_message(&data->ipmi, IPMI_FAN_WRITE_CMD, + data->ipmi_tx_data, sizeof(data->ipmi_tx_data), + NULL, 0); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + /* Update pwm to ipmi_resp buffer to prevent from the impact of lazy update */ + data->ipmi_resp[fid * FAN_DATA_COUNT + FAN_PWM] = pwm; + status = count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static struct as7535_32xb_fan_data *as7535_32xb_fan_update_cpld_ver(void) +{ + int status = 0; + + data->valid = 0; + data->ipmi_tx_data[0] = 0x66; + status = ipmi_send_message(&data->ipmi, IPMI_FAN_REG_READ_CMD, + data->ipmi_tx_data, 1, + &data->ipmi_resp_cpld, + sizeof(data->ipmi_resp_cpld)); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + data->last_updated = jiffies; + data->valid = 1; + +exit: + return data; +} + +static ssize_t show_version(struct device *dev, struct device_attribute *da, + char *buf) +{ + unsigned char value = 0; + int error = 0; + + mutex_lock(&data->update_lock); + + data = as7535_32xb_fan_update_cpld_ver(); + if (!data->valid) { + error = -EIO; + goto exit; + } + + value = data->ipmi_resp_cpld; + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", value); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static ssize_t show_dir(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + unsigned char fid = (attr->index / NUM_OF_PER_FAN_ATTR); + int value = 0; + int index = 0; + int present = 0; + int error = 0; + + mutex_lock(&data->update_lock); + + data = as7535_32xb_fan_update_device(); + if (!data->valid) { + error = -EIO; + goto exit; + } + + index = fid * FAN_DATA_COUNT; /* base index */ + present = !!data->ipmi_resp[index + FAN_PRESENT]; + + value = data->ipmi_resp[40] | (data->ipmi_resp[41] << 8); + mutex_unlock(&data->update_lock); + + if (!present) + return sprintf(buf, "0\n"); + else + return sprintf(buf, "%s\n", + (value & BIT(fid % NUM_OF_FAN_MODULE)) ? "B2F" : "F2B"); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static ssize_t show_threshold(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + int value = 0; + int error = 0; + + mutex_lock(&data->update_lock); + + data = as7535_32xb_fan_update_device(); + if (!data->valid) { + error = -EIO; + goto exit; + } + + switch (attr->index) { + case FAN1_TARGET: + case FAN2_TARGET: + case FAN3_TARGET: + case FAN4_TARGET: + case FAN5_TARGET: + case FAN6_TARGET: + value = (int)data->ipmi_resp_speed[FAN_TARGET_SPEED0] | + (int)data->ipmi_resp_speed[FAN_TARGET_SPEED1] << 8; + break; + case FAN1_TOLERANCE: + case FAN2_TOLERANCE: + case FAN3_TOLERANCE: + case FAN4_TOLERANCE: + case FAN5_TOLERANCE: + case FAN6_TOLERANCE: + value = (int)data->ipmi_resp_speed[FAN_SPEED_TOLERANCE]; + break; + default: + error = -EINVAL; + goto exit; + } + + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", value); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static int as7535_32xb_fan_probe(struct platform_device *pdev) +{ + int status = -1; + + /* Register sysfs hooks */ + status = sysfs_create_group(&pdev->dev.kobj, &as7535_32xb_fan_group); + if (status) + return status; + + dev_info(&pdev->dev, "device created\n"); + + return 0; +} + +static int as7535_32xb_fan_remove(struct platform_device *pdev) +{ + sysfs_remove_group(&pdev->dev.kobj, &as7535_32xb_fan_group); + + return 0; +} + +static int __init as7535_32xb_fan_init(void) +{ + int ret; + + data = kzalloc(sizeof(struct as7535_32xb_fan_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto alloc_err; + } + + mutex_init(&data->update_lock); + data->valid = 0; + + ret = platform_driver_register(&as7535_32xb_fan_driver); + if (ret < 0) + goto dri_reg_err; + + data->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(data->pdev)) { + ret = PTR_ERR(data->pdev); + goto dev_reg_err; + } + + /* Set up IPMI interface */ + ret = init_ipmi_data(&data->ipmi, 0, &data->pdev->dev); + if (ret) + goto ipmi_err; + + return 0; + +ipmi_err: + platform_device_unregister(data->pdev); +dev_reg_err: + platform_driver_unregister(&as7535_32xb_fan_driver); +dri_reg_err: + kfree(data); +alloc_err: + return ret; +} + +static void __exit as7535_32xb_fan_exit(void) +{ + ipmi_destroy_user(data->ipmi.user); + platform_device_unregister(data->pdev); + platform_driver_unregister(&as7535_32xb_fan_driver); + kfree(data); +} + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("as7535_32xb_fan driver"); +MODULE_LICENSE("GPL"); + +module_init(as7535_32xb_fan_init); +module_exit(as7535_32xb_fan_exit); diff --git a/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/modules/x86-64-accton-as7535-32xb-leds.c b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/modules/x86-64-accton-as7535-32xb-leds.c new file mode 100644 index 00000000000..7bf44eebeed --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/modules/x86-64-accton-as7535-32xb-leds.c @@ -0,0 +1,536 @@ +/* + * Copyright (C) Brandon Chuang + * + * Based on: + * pca954x.c from Kumar Gala + * Copyright (C) 2006 + * + * Based on: + * pca954x.c from Ken Harrenstien + * Copyright (C) 2004 Google, Inc. (Ken Harrenstien) + * + * Based on: + * i2c-virtual_cb.c from Brian Kuschak + * and + * pca9540.c from Jean Delvare . + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as7535_32xb_led" +#define ACCTON_IPMI_NETFN 0x34 +#define IPMI_LED_READ_CMD 0x1A +#define IPMI_LED_WRITE_CMD 0x1B +#define IPMI_TIMEOUT (5 * HZ) +#define IPMI_ERR_RETRY_TIMES 1 + +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); +static ssize_t set_led(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t show_led(struct device *dev, struct device_attribute *attr, + char *buf); +static int as7535_32xb_led_probe(struct platform_device *pdev); +static int as7535_32xb_led_remove(struct platform_device *pdev); + +struct ipmi_data { + struct completion read_complete; + struct ipmi_addr address; + struct ipmi_user *user; + int interface; + + struct kernel_ipmi_msg tx_message; + long tx_msgid; + + void *rx_msg_data; + unsigned short rx_msg_len; + unsigned char rx_result; + int rx_recv_type; + + struct ipmi_user_hndl ipmi_hndlrs; +}; + +struct as7535_32xb_led_data { + struct platform_device *pdev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + unsigned char ipmi_resp[5]; /* 0:Loc 1:Diag 2:Gnss 3:Fan 4:Psu */ + struct ipmi_data ipmi; +}; + +struct as7535_32xb_led_data *data = NULL; + +static struct platform_driver as7535_32xb_led_driver = { + .probe = as7535_32xb_led_probe, + .remove = as7535_32xb_led_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +enum ipmi_led_light_mode { + IPMI_LED_MODE_OFF, + IPMI_LED_MODE_RED = 2, + IPMI_LED_MODE_RED_BLINKING = 3, + IPMI_LED_MODE_GREEN = 4, + IPMI_LED_MODE_GREEN_BLINKING = 5, + IPMI_LED_MODE_BLUE = 8, + IPMI_LED_MODE_BLUE_BLINKING = 9, + IPMI_LED_MODE_CYAN = 0xC, + IPMI_LED_MODE_WHITE = 0xE, + IPMI_LED_MODE_AMBER = 0x10, + IPMI_LED_MODE_ORANGE = 0x20, +}; + +enum led_light_mode { + LED_MODE_OFF, + LED_MODE_RED = 10, + LED_MODE_RED_BLINKING = 11, + LED_MODE_ORANGE = 12, + LED_MODE_ORANGE_BLINKING = 13, + LED_MODE_YELLOW = 14, + LED_MODE_YELLOW_BLINKING = 15, + LED_MODE_GREEN = 16, + LED_MODE_GREEN_BLINKING = 17, + LED_MODE_BLUE = 18, + LED_MODE_BLUE_BLINKING = 19, + LED_MODE_PURPLE = 20, + LED_MODE_PURPLE_BLINKING = 21, + LED_MODE_AUTO = 22, + LED_MODE_AUTO_BLINKING = 23, + LED_MODE_WHITE = 24, + LED_MODE_WHITE_BLINKING = 25, + LED_MODE_CYAN = 26, + LED_MODE_CYAN_BLINKING = 27, + LED_MODE_UNKNOWN = 99 +}; + +enum as7535_32xb_led_sysfs_attrs { + LED_LOC, + LED_DIAG, + LED_GNSS, + LED_FAN, + LED_PSU +}; + +static SENSOR_DEVICE_ATTR(led_loc, S_IWUSR | S_IRUGO, show_led, set_led, + LED_LOC); +static SENSOR_DEVICE_ATTR(led_diag, S_IWUSR | S_IRUGO, show_led, set_led, + LED_DIAG); +static SENSOR_DEVICE_ATTR(led_gnss, S_IWUSR | S_IRUGO, show_led, set_led, + LED_GNSS); +static SENSOR_DEVICE_ATTR(led_fan, S_IWUSR | S_IRUGO, show_led, set_led, + LED_FAN); +static SENSOR_DEVICE_ATTR(led_psu, S_IWUSR | S_IRUGO, show_led, set_led, + LED_PSU); + +static struct attribute *as7535_32xb_led_attributes[] = { + &sensor_dev_attr_led_loc.dev_attr.attr, + &sensor_dev_attr_led_diag.dev_attr.attr, + &sensor_dev_attr_led_gnss.dev_attr.attr, + &sensor_dev_attr_led_fan.dev_attr.attr, + &sensor_dev_attr_led_psu.dev_attr.attr, + NULL +}; + +static const struct attribute_group as7535_32xb_led_group = { + .attrs = as7535_32xb_led_attributes, +}; + +/* Functions to talk to the IPMI layer */ + +/* Initialize IPMI address, message buffers and user data */ +static int init_ipmi_data(struct ipmi_data *ipmi, int iface, + struct device *dev) +{ + int err; + + init_completion(&ipmi->read_complete); + + /* Initialize IPMI address */ + ipmi->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + ipmi->address.channel = IPMI_BMC_CHANNEL; + ipmi->address.data[0] = 0; + ipmi->interface = iface; + + /* Initialize message buffers */ + ipmi->tx_msgid = 0; + ipmi->tx_message.netfn = ACCTON_IPMI_NETFN; + + ipmi->ipmi_hndlrs.ipmi_recv_hndl = ipmi_msg_handler; + + /* Create IPMI messaging interface user */ + err = ipmi_create_user(ipmi->interface, &ipmi->ipmi_hndlrs, + ipmi, &ipmi->user); + if (err < 0) { + dev_err(dev, "Unable to register user with IPMI " + "interface %d\n", ipmi->interface); + return -EACCES; + } + + return 0; +} + +/* Send an IPMI command */ +static int _ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int err; + + ipmi->tx_message.cmd = cmd; + ipmi->tx_message.data = tx_data; + ipmi->tx_message.data_len = tx_len; + ipmi->rx_msg_data = rx_data; + ipmi->rx_msg_len = rx_len; + + err = ipmi_validate_addr(&ipmi->address, sizeof(ipmi->address)); + if (err) + goto addr_err; + + ipmi->tx_msgid++; + err = ipmi_request_settime(ipmi->user, &ipmi->address, ipmi->tx_msgid, + &ipmi->tx_message, ipmi, 0, 0, 0); + if (err) + goto ipmi_req_err; + + err = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); + if (!err) + goto ipmi_timeout_err; + + return 0; + +ipmi_timeout_err: + err = -ETIMEDOUT; + dev_err(&data->pdev->dev, "request_timeout=%x\n", err); + return err; +ipmi_req_err: + dev_err(&data->pdev->dev, "request_settime=%x\n", err); + return err; +addr_err: + dev_err(&data->pdev->dev, "validate_addr=%x\n", err); + return err; +} + +/* Send an IPMI command with retry */ +static int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int status = 0, retry = 0; + + for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { + status = _ipmi_send_message(ipmi, cmd, tx_data, tx_len, rx_data, rx_len); + if (unlikely(status != 0)) { + dev_err(&data->pdev->dev, "ipmi_send_message_%d err status(%d)\r\n", + retry, status); + continue; + } + + if (unlikely(ipmi->rx_result != 0)) { + dev_err(&data->pdev->dev, "ipmi_send_message_%d err result(%d)\r\n", + retry, ipmi->rx_result); + continue; + } + + break; + } + + return status; +} + +/* Dispatch IPMI messages to callers */ +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) +{ + unsigned short rx_len; + struct ipmi_data *ipmi = user_msg_data; + + if (msg->msgid != ipmi->tx_msgid) { + dev_err(&data->pdev->dev, "Mismatch between received msgid " + "(%02x) and transmitted msgid (%02x)!\n", + (int)msg->msgid, + (int)ipmi->tx_msgid); + ipmi_free_recv_msg(msg); + return; + } + + ipmi->rx_recv_type = msg->recv_type; + if (msg->msg.data_len > 0) + ipmi->rx_result = msg->msg.data[0]; + else + ipmi->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE; + + if (msg->msg.data_len > 1) { + rx_len = msg->msg.data_len - 1; + if (ipmi->rx_msg_len < rx_len) + rx_len = ipmi->rx_msg_len; + ipmi->rx_msg_len = rx_len; + memcpy(ipmi->rx_msg_data, msg->msg.data + 1, ipmi->rx_msg_len); + } else + ipmi->rx_msg_len = 0; + + ipmi_free_recv_msg(msg); + complete(&ipmi->read_complete); +} + +static struct as7535_32xb_led_data *as7535_32xb_led_update_device(void) +{ + int status = 0; + + if (time_before(jiffies, data->last_updated + HZ * 5) && data->valid) { + return data; + } + + data->valid = 0; + status = ipmi_send_message(&data->ipmi, IPMI_LED_READ_CMD, NULL, 0, + data->ipmi_resp, sizeof(data->ipmi_resp)); + if (unlikely(status != 0)) { + goto exit; + } + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + data->last_updated = jiffies; + data->valid = 1; + +exit: + return data; +} + +static ssize_t show_led(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + int value = 0; + int error = 0; + + mutex_lock(&data->update_lock); + + data = as7535_32xb_led_update_device(); + if (!data->valid) { + error = -EIO; + goto exit; + } + + switch (data->ipmi_resp[attr->index]) { + case IPMI_LED_MODE_OFF: + value = LED_MODE_OFF; + break; + case IPMI_LED_MODE_RED: + value = LED_MODE_RED; + break; + case IPMI_LED_MODE_RED_BLINKING: + value = LED_MODE_RED_BLINKING; + break; + case IPMI_LED_MODE_GREEN: + value = LED_MODE_GREEN; + break; + case IPMI_LED_MODE_GREEN_BLINKING: + value = LED_MODE_GREEN_BLINKING; + break; + case IPMI_LED_MODE_BLUE: + value = LED_MODE_BLUE; + break; + case IPMI_LED_MODE_BLUE_BLINKING: + value = LED_MODE_BLUE_BLINKING; + break; + case IPMI_LED_MODE_CYAN: + value = LED_MODE_CYAN; + break; + case IPMI_LED_MODE_WHITE: + value = LED_MODE_WHITE; + break; + case IPMI_LED_MODE_AMBER: + value = LED_MODE_YELLOW; + break; + case IPMI_LED_MODE_ORANGE: + value = LED_MODE_ORANGE; + break; + default: + error = -EINVAL; + goto exit; + } + + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", value); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static ssize_t set_led(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + long mode; + int status; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + + status = kstrtol(buf, 10, &mode); + if (status) + return status; + + mutex_lock(&data->update_lock); + + data = as7535_32xb_led_update_device(); + if (!data->valid) { + status = -EIO; + goto exit; + } + + data->ipmi_resp[0] = attr->index + 1; + + switch (mode) { + case LED_MODE_OFF: + data->ipmi_resp[1] = IPMI_LED_MODE_OFF; + break; + case LED_MODE_RED: + data->ipmi_resp[1] = IPMI_LED_MODE_RED; + break; + case LED_MODE_RED_BLINKING: + data->ipmi_resp[1] = IPMI_LED_MODE_RED_BLINKING; + break; + case LED_MODE_GREEN: + data->ipmi_resp[1] = IPMI_LED_MODE_GREEN; + break; + case LED_MODE_GREEN_BLINKING: + data->ipmi_resp[1] = IPMI_LED_MODE_GREEN_BLINKING; + break; + case LED_MODE_BLUE: + data->ipmi_resp[1] = IPMI_LED_MODE_BLUE; + break; + case LED_MODE_BLUE_BLINKING: + data->ipmi_resp[1] = IPMI_LED_MODE_BLUE_BLINKING; + break; + case LED_MODE_CYAN: + data->ipmi_resp[1] = IPMI_LED_MODE_CYAN; + break; + case LED_MODE_WHITE: + data->ipmi_resp[1] = IPMI_LED_MODE_WHITE; + break; + case LED_MODE_YELLOW: + data->ipmi_resp[1] = IPMI_LED_MODE_AMBER; + break; + case LED_MODE_ORANGE: + data->ipmi_resp[1] = IPMI_LED_MODE_ORANGE; + break; + default: + status = -EINVAL; + goto exit; + } + + /* Send IPMI write command */ + status = ipmi_send_message(&data->ipmi, IPMI_LED_WRITE_CMD, + data->ipmi_resp, 2, NULL, 0); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + status = count; + data->valid = 0; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static int as7535_32xb_led_probe(struct platform_device *pdev) +{ + int status = -1; + + /* Register sysfs hooks */ + status = sysfs_create_group(&pdev->dev.kobj, &as7535_32xb_led_group); + if (status) + goto exit; + + dev_info(&pdev->dev, "device created\n"); + + return 0; + +exit: + return status; +} + +static int as7535_32xb_led_remove(struct platform_device *pdev) +{ + sysfs_remove_group(&pdev->dev.kobj, &as7535_32xb_led_group); + + return 0; +} + +static int __init as7535_32xb_led_init(void) +{ + int ret; + + data = kzalloc(sizeof(struct as7535_32xb_led_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto alloc_err; + } + + mutex_init(&data->update_lock); + data->valid = 0; + + ret = platform_driver_register(&as7535_32xb_led_driver); + if (ret < 0) + goto dri_reg_err; + + data->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(data->pdev)) { + ret = PTR_ERR(data->pdev); + goto dev_reg_err; + } + + /* Set up IPMI interface */ + ret = init_ipmi_data(&data->ipmi, 0, &data->pdev->dev); + if (ret) + goto ipmi_err; + + return 0; + +ipmi_err: + platform_device_unregister(data->pdev); +dev_reg_err: + platform_driver_unregister(&as7535_32xb_led_driver); +dri_reg_err: + kfree(data); +alloc_err: + return ret; +} + +static void __exit as7535_32xb_led_exit(void) +{ + ipmi_destroy_user(data->ipmi.user); + platform_device_unregister(data->pdev); + platform_driver_unregister(&as7535_32xb_led_driver); + kfree(data); +} + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("as7535_32xb_led driver"); +MODULE_LICENSE("GPL"); + +module_init(as7535_32xb_led_init); +module_exit(as7535_32xb_led_exit); diff --git a/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/modules/x86-64-accton-as7535-32xb-psu.c b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/modules/x86-64-accton-as7535-32xb-psu.c new file mode 100644 index 00000000000..4aa6f2bc6d2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/modules/x86-64-accton-as7535-32xb-psu.c @@ -0,0 +1,1000 @@ +/* + * Copyright (C) Brandon Chuang + * Based on: + * pca954x.c from Kumar Gala + * Copyright (C) 2006 + * + * Based on: + * pca954x.c from Ken Harrenstien + * Copyright (C) 2004 Google, Inc. (Ken Harrenstien) + * + * Based on: + * i2c-virtual_cb.c from Brian Kuschak + * and + * pca9540.c from Jean Delvare . + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as7535_32xb_psu" +#define ACCTON_IPMI_NETFN 0x34 +#define IPMI_PSU_READ_CMD 0x16 +#define IPMI_PSU_MODEL_NAME_CMD 0x10 +#define IPMI_PSU_SERIAL_NUM_CMD 0x11 +#define IPMI_PSU_FAN_DIR_CMD 0x13 +#define IPMI_PSU_INFO_CMD 0x20 +#define IPMI_TIMEOUT (5 * HZ) +#define IPMI_ERR_RETRY_TIMES 1 +#define IPMI_MODEL_SERIAL_LEN 32 +#define IPMI_FAN_DIR_LEN 3 + +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); +static ssize_t show_psu(struct device *dev, struct device_attribute *attr, + char *buf); +static ssize_t show_psu_info(struct device *dev, struct device_attribute *attr, + char *buf); +static ssize_t show_string(struct device *dev, struct device_attribute *attr, + char *buf); +static int as7535_32xb_psu_probe(struct platform_device *pdev); +static int as7535_32xb_psu_remove(struct platform_device *pdev); + +enum psu_id { + PSU_1, + PSU_2, + NUM_OF_PSU +}; + +enum psu_data_index { + PSU_PRESENT = 0, + PSU_TEMP_FAULT, + PSU_POWER_GOOD_CPLD, + PSU_POWER_GOOD_PMBUS, + PSU_OVER_VOLTAGE, + PSU_OVER_CURRENT, + PSU_POWER_ON, + PSU_VIN0, + PSU_VIN1, + PSU_VIN2, + PSU_VOUT0, + PSU_VOUT1, + PSU_VOUT2, + PSU_IIN0, + PSU_IIN1, + PSU_IIN2, + PSU_IOUT0, + PSU_IOUT1, + PSU_IOUT2, + PSU_PIN0, + PSU_PIN1, + PSU_PIN2, + PSU_PIN3, + PSU_POUT0, + PSU_POUT1, + PSU_POUT2, + PSU_POUT3, + PSU_TEMP1_0, + PSU_TEMP1_1, + PSU_TEMP2_0, + PSU_TEMP2_1, + PSU_TEMP3_0, + PSU_TEMP3_1, + PSU_FAN0, + PSU_FAN1, + PSU_VOUT_MODE, + PSU_STATUS_COUNT, + PSU_MODEL = 0, + PSU_SERIAL = 0, + PSU_TEMP1_MAX0 = 2, + PSU_TEMP1_MAX1, + PSU_TEMP1_MIN0, + PSU_TEMP1_MIN1, + PSU_TEMP2_MAX0, + PSU_TEMP2_MAX1, + PSU_TEMP2_MIN0, + PSU_TEMP2_MIN1, + PSU_TEMP3_MAX0, + PSU_TEMP3_MAX1, + PSU_TEMP3_MIN0, + PSU_TEMP3_MIN1, + PSU_VIN_UPPER_CRIT0, + PSU_VIN_UPPER_CRIT1, + PSU_VIN_UPPER_CRIT2, + PSU_VIN_MAX0, + PSU_VIN_MAX1, + PSU_VIN_MAX2, + PSU_VIN_MIN0, + PSU_VIN_MIN1, + PSU_VIN_MIN2, + PSU_VIN_LOWER_CRIT0, + PSU_VIN_LOWER_CRIT1, + PSU_VIN_LOWER_CRIT2, + PSU_VOUT_MAX0, + PSU_VOUT_MAX1, + PSU_VOUT_MAX2, + PSU_VOUT_MIN0, + PSU_VOUT_MIN1, + PSU_VOUT_MIN2, + PSU_IIN_MAX0, + PSU_IIN_MAX1, + PSU_IIN_MAX2, + PSU_IOUT_MAX0, + PSU_IOUT_MAX1, + PSU_IOUT_MAX2, + PSU_PIN_MAX0, + PSU_PIN_MAX1, + PSU_PIN_MAX2, + PSU_PIN_MAX3, + PSU_POUT_MAX0, + PSU_POUT_MAX1, + PSU_POUT_MAX2, + PSU_POUT_MAX3, + PSU_INFO_COUNT +}; + +struct ipmi_data { + struct completion read_complete; + struct ipmi_addr address; + struct ipmi_user *user; + int interface; + + struct kernel_ipmi_msg tx_message; + long tx_msgid; + + void *rx_msg_data; + unsigned short rx_msg_len; + unsigned char rx_result; + int rx_recv_type; + + struct ipmi_user_hndl ipmi_hndlrs; +}; + +struct ipmi_psu_resp_data { + unsigned char status[PSU_STATUS_COUNT]; + unsigned char info[PSU_INFO_COUNT]; + char serial[IPMI_MODEL_SERIAL_LEN+1]; + char model[IPMI_MODEL_SERIAL_LEN+1]; + char fandir[IPMI_FAN_DIR_LEN+1]; +}; + +struct as7535_32xb_psu_data { + struct platform_device *pdev; + struct mutex update_lock; + char valid[3]; /* != 0 if registers are valid, 0: PSU1, 1: PSU2 */ + unsigned long last_updated[3]; /* In jiffies, 0: PSU1, 1: PSU2 */ + struct ipmi_data ipmi; + struct ipmi_psu_resp_data ipmi_resp[3]; /* 0: PSU1, 1: PSU2 */ + unsigned char ipmi_tx_data[2]; +}; + +struct as7535_32xb_psu_data *data = NULL; + +static struct platform_driver as7535_32xb_psu_driver = { + .probe = as7535_32xb_psu_probe, + .remove = as7535_32xb_psu_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +#define PSU_PRESENT_ATTR_ID(index) PSU##index##_PRESENT +#define PSU_POWERGOOD_ATTR_ID(index) PSU##index##_POWER_GOOD +#define PSU_VIN_ATTR_ID(index) PSU##index##_VIN +#define PSU_VOUT_ATTR_ID(index) PSU##index##_VOUT +#define PSU_IIN_ATTR_ID(index) PSU##index##_IIN +#define PSU_IOUT_ATTR_ID(index) PSU##index##_IOUT +#define PSU_PIN_ATTR_ID(index) PSU##index##_PIN +#define PSU_POUT_ATTR_ID(index) PSU##index##_POUT +#define PSU_MODEL_ATTR_ID(index) PSU##index##_MODEL +#define PSU_SERIAL_ATTR_ID(index) PSU##index##_SERIAL +#define PSU_TEMP1_INPUT_ATTR_ID(index) PSU##index##_TEMP1_INPUT +#define PSU_TEMP2_INPUT_ATTR_ID(index) PSU##index##_TEMP2_INPUT +#define PSU_TEMP3_INPUT_ATTR_ID(index) PSU##index##_TEMP3_INPUT +#define PSU_FAN_INPUT_ATTR_ID(index) PSU##index##_FAN_INPUT +#define PSU_FAN_DIR_ATTR_ID(index) PSU##index##_FAN_DIR + +#define PSU_TEMP1_INPUT_MAX_ATTR_ID(index) PSU##index##_TEMP1_INPUT_MAX +#define PSU_TEMP1_INPUT_MIN_ATTR_ID(index) PSU##index##_TEMP1_INPUT_MIN +#define PSU_TEMP2_INPUT_MAX_ATTR_ID(index) PSU##index##_TEMP2_INPUT_MAX +#define PSU_TEMP2_INPUT_MIN_ATTR_ID(index) PSU##index##_TEMP2_INPUT_MIN +#define PSU_TEMP3_INPUT_MAX_ATTR_ID(index) PSU##index##_TEMP3_INPUT_MAX +#define PSU_TEMP3_INPUT_MIN_ATTR_ID(index) PSU##index##_TEMP3_INPUT_MIN +#define PSU_VIN_MAX_ATTR_ID(index) PSU##index##_VIN_MAX +#define PSU_VIN_MIN_ATTR_ID(index) PSU##index##_VIN_MIN +#define PSU_VIN_UPPER_CRIT_ATTR_ID(index) PSU##index##_VIN_UPPER_CRIT +#define PSU_VIN_LOWER_CRIT_ATTR_ID(index) PSU##index##_VIN_LOWER_CRIT +#define PSU_VOUT_MAX_ATTR_ID(index) PSU##index##_VOUT_MAX +#define PSU_VOUT_MIN_ATTR_ID(index) PSU##index##_VOUT_MIN +#define PSU_IIN_MAX_ATTR_ID(index) PSU##index##_IIN_MAX +#define PSU_IOUT_MAX_ATTR_ID(index) PSU##index##_IOUT_MAX +#define PSU_PIN_MAX_ATTR_ID(index) PSU##index##_PIN_MAX +#define PSU_POUT_MAX_ATTR_ID(index) PSU##index##_POUT_MAX + +#define PSU_ATTR(psu_id) \ + PSU_PRESENT_ATTR_ID(psu_id), \ + PSU_POWERGOOD_ATTR_ID(psu_id), \ + PSU_VIN_ATTR_ID(psu_id), \ + PSU_VOUT_ATTR_ID(psu_id), \ + PSU_IIN_ATTR_ID(psu_id), \ + PSU_IOUT_ATTR_ID(psu_id), \ + PSU_PIN_ATTR_ID(psu_id), \ + PSU_POUT_ATTR_ID(psu_id), \ + PSU_MODEL_ATTR_ID(psu_id), \ + PSU_SERIAL_ATTR_ID(psu_id), \ + PSU_TEMP1_INPUT_ATTR_ID(psu_id), \ + PSU_TEMP2_INPUT_ATTR_ID(psu_id), \ + PSU_TEMP3_INPUT_ATTR_ID(psu_id), \ + PSU_FAN_INPUT_ATTR_ID(psu_id), \ + PSU_FAN_DIR_ATTR_ID(psu_id), \ + PSU_TEMP1_INPUT_MAX_ATTR_ID(psu_id), \ + PSU_TEMP1_INPUT_MIN_ATTR_ID(psu_id), \ + PSU_TEMP2_INPUT_MAX_ATTR_ID(psu_id), \ + PSU_TEMP2_INPUT_MIN_ATTR_ID(psu_id), \ + PSU_TEMP3_INPUT_MAX_ATTR_ID(psu_id), \ + PSU_TEMP3_INPUT_MIN_ATTR_ID(psu_id), \ + PSU_VIN_MAX_ATTR_ID(psu_id), \ + PSU_VIN_MIN_ATTR_ID(psu_id), \ + PSU_VIN_UPPER_CRIT_ATTR_ID(psu_id), \ + PSU_VIN_LOWER_CRIT_ATTR_ID(psu_id), \ + PSU_VOUT_MAX_ATTR_ID(psu_id), \ + PSU_VOUT_MIN_ATTR_ID(psu_id), \ + PSU_IIN_MAX_ATTR_ID(psu_id), \ + PSU_IOUT_MAX_ATTR_ID(psu_id), \ + PSU_PIN_MAX_ATTR_ID(psu_id), \ + PSU_POUT_MAX_ATTR_ID(psu_id) + +enum as7535_32xb_psu_sysfs_attrs { + /* psu attributes */ + PSU_ATTR(1), + PSU_ATTR(2), + NUM_OF_PSU_ATTR, + NUM_OF_PER_PSU_ATTR = (NUM_OF_PSU_ATTR/NUM_OF_PSU) +}; + +/* psu attributes */ +#define DECLARE_PSU_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(psu##index##_present, S_IRUGO, show_psu, NULL, \ + PSU##index##_PRESENT); \ + static SENSOR_DEVICE_ATTR(psu##index##_power_good, S_IRUGO, show_psu, NULL,\ + PSU##index##_POWER_GOOD); \ + static SENSOR_DEVICE_ATTR(psu##index##_vin, S_IRUGO, show_psu, NULL, \ + PSU##index##_VIN); \ + static SENSOR_DEVICE_ATTR(psu##index##_vout, S_IRUGO, show_psu, NULL, \ + PSU##index##_VOUT); \ + static SENSOR_DEVICE_ATTR(psu##index##_iin, S_IRUGO, show_psu, NULL, \ + PSU##index##_IIN); \ + static SENSOR_DEVICE_ATTR(psu##index##_iout, S_IRUGO, show_psu, NULL, \ + PSU##index##_IOUT); \ + static SENSOR_DEVICE_ATTR(psu##index##_pin, S_IRUGO, show_psu, NULL, \ + PSU##index##_PIN); \ + static SENSOR_DEVICE_ATTR(psu##index##_pout, S_IRUGO, show_psu, NULL, \ + PSU##index##_POUT); \ + static SENSOR_DEVICE_ATTR(psu##index##_model, S_IRUGO, show_string, NULL, \ + PSU##index##_MODEL); \ + static SENSOR_DEVICE_ATTR(psu##index##_serial, S_IRUGO, show_string, NULL,\ + PSU##index##_SERIAL);\ + static SENSOR_DEVICE_ATTR(psu##index##_temp1_input, S_IRUGO, show_psu,NULL,\ + PSU##index##_TEMP1_INPUT); \ + static SENSOR_DEVICE_ATTR(psu##index##_temp2_input, S_IRUGO, show_psu,NULL,\ + PSU##index##_TEMP2_INPUT); \ + static SENSOR_DEVICE_ATTR(psu##index##_temp3_input, S_IRUGO, show_psu,NULL,\ + PSU##index##_TEMP3_INPUT); \ + static SENSOR_DEVICE_ATTR(psu##index##_fan1_input, S_IRUGO, show_psu, NULL,\ + PSU##index##_FAN_INPUT); \ + static SENSOR_DEVICE_ATTR(psu##index##_fan_dir, S_IRUGO, show_string, NULL,\ + PSU##index##_FAN_DIR); \ + static SENSOR_DEVICE_ATTR(psu##index##_temp1_input_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_TEMP1_INPUT_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_temp1_input_min, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_TEMP1_INPUT_MIN); \ + static SENSOR_DEVICE_ATTR(psu##index##_temp2_input_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_TEMP2_INPUT_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_temp2_input_min, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_TEMP2_INPUT_MIN); \ + static SENSOR_DEVICE_ATTR(psu##index##_temp3_input_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_TEMP3_INPUT_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_temp3_input_min, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_TEMP3_INPUT_MIN); \ + static SENSOR_DEVICE_ATTR(psu##index##_vin_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_VIN_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_vin_min, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_VIN_MIN); \ + static SENSOR_DEVICE_ATTR(psu##index##_vin_upper_crit, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_VIN_UPPER_CRIT); \ + static SENSOR_DEVICE_ATTR(psu##index##_vin_lower_crit, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_VIN_LOWER_CRIT); \ + static SENSOR_DEVICE_ATTR(psu##index##_vout_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_VOUT_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_vout_min, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_VOUT_MIN); \ + static SENSOR_DEVICE_ATTR(psu##index##_iin_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_IIN_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_iout_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_IOUT_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_pin_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_PIN_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_pout_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_POUT_MAX) + +#define DECLARE_PSU_ATTR(index) \ + &sensor_dev_attr_psu##index##_present.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_power_good.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_vin.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_vout.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_iin.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_iout.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_pin.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_pout.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_model.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_serial.dev_attr.attr,\ + &sensor_dev_attr_psu##index##_temp1_input.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_temp2_input.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_temp3_input.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_fan1_input.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_fan_dir.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_temp1_input_max.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_temp1_input_min.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_temp2_input_max.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_temp2_input_min.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_temp3_input_max.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_temp3_input_min.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_vin_max.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_vin_min.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_vin_upper_crit.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_vin_lower_crit.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_vout_max.dev_attr.attr,\ + &sensor_dev_attr_psu##index##_vout_min.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_iin_max.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_iout_max.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_pin_max.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_pout_max.dev_attr.attr + +DECLARE_PSU_SENSOR_DEVICE_ATTR(1); +DECLARE_PSU_SENSOR_DEVICE_ATTR(2); + +static struct attribute *as7535_32xb_psu_attributes[] = { + /* psu attributes */ + DECLARE_PSU_ATTR(1), + DECLARE_PSU_ATTR(2), + NULL +}; + +static const struct attribute_group as7535_32xb_psu_group = { + .attrs = as7535_32xb_psu_attributes, +}; + +/* Functions to talk to the IPMI layer */ + +/* Initialize IPMI address, message buffers and user data */ +static int init_ipmi_data(struct ipmi_data *ipmi, int iface, + struct device *dev) +{ + int err; + + init_completion(&ipmi->read_complete); + + /* Initialize IPMI address */ + ipmi->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + ipmi->address.channel = IPMI_BMC_CHANNEL; + ipmi->address.data[0] = 0; + ipmi->interface = iface; + + /* Initialize message buffers */ + ipmi->tx_msgid = 0; + ipmi->tx_message.netfn = ACCTON_IPMI_NETFN; + + ipmi->ipmi_hndlrs.ipmi_recv_hndl = ipmi_msg_handler; + + /* Create IPMI messaging interface user */ + err = ipmi_create_user(ipmi->interface, &ipmi->ipmi_hndlrs, + ipmi, &ipmi->user); + if (err < 0) { + dev_err(dev, "Unable to register user with IPMI " + "interface %d\n", ipmi->interface); + return -EACCES; + } + + return 0; +} + +/* Send an IPMI command */ +static int _ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int err; + + ipmi->tx_message.cmd = cmd; + ipmi->tx_message.data = tx_data; + ipmi->tx_message.data_len = tx_len; + ipmi->rx_msg_data = rx_data; + ipmi->rx_msg_len = rx_len; + + err = ipmi_validate_addr(&ipmi->address, sizeof(ipmi->address)); + if (err) + goto addr_err; + + ipmi->tx_msgid++; + err = ipmi_request_settime(ipmi->user, &ipmi->address, ipmi->tx_msgid, + &ipmi->tx_message, ipmi, 0, 0, 0); + if (err) + goto ipmi_req_err; + + err = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); + if (!err) + goto ipmi_timeout_err; + + return 0; + +ipmi_timeout_err: + err = -ETIMEDOUT; + dev_err(&data->pdev->dev, "request_timeout=%x\n", err); + return err; +ipmi_req_err: + dev_err(&data->pdev->dev, "request_settime=%x\n", err); + return err; +addr_err: + dev_err(&data->pdev->dev, "validate_addr=%x\n", err); + return err; +} + +/* Send an IPMI command with retry */ +static int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int status = 0, retry = 0; + + for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { + status = _ipmi_send_message(ipmi, cmd, tx_data, tx_len, rx_data, rx_len); + if (unlikely(status != 0)) { + dev_err(&data->pdev->dev, "ipmi_send_message_%d err status(%d)\r\n", + retry, status); + continue; + } + + if (unlikely(ipmi->rx_result != 0)) { + dev_err(&data->pdev->dev, "ipmi_send_message_%d err result(%d)\r\n", + retry, ipmi->rx_result); + continue; + } + + break; + } + + return status; +} + +/* Dispatch IPMI messages to callers */ +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) +{ + unsigned short rx_len; + struct ipmi_data *ipmi = user_msg_data; + + if (msg->msgid != ipmi->tx_msgid) { + dev_err(&data->pdev->dev, "Mismatch between received msgid " + "(%02x) and transmitted msgid (%02x)!\n", + (int)msg->msgid, + (int)ipmi->tx_msgid); + ipmi_free_recv_msg(msg); + return; + } + + ipmi->rx_recv_type = msg->recv_type; + if (msg->msg.data_len > 0) + ipmi->rx_result = msg->msg.data[0]; + else + ipmi->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE; + + if (msg->msg.data_len > 1) { + rx_len = msg->msg.data_len - 1; + if (ipmi->rx_msg_len < rx_len) + rx_len = ipmi->rx_msg_len; + ipmi->rx_msg_len = rx_len; + memcpy(ipmi->rx_msg_data, msg->msg.data + 1, ipmi->rx_msg_len); + } else + ipmi->rx_msg_len = 0; + + ipmi_free_recv_msg(msg); + complete(&ipmi->read_complete); +} + +static struct as7535_32xb_psu_data *as7535_32xb_psu_update_device(struct device_attribute *da) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + unsigned char pid = attr->index / NUM_OF_PER_PSU_ATTR; + int status = 0; + + if (time_before(jiffies, data->last_updated[pid] + HZ * 5) && data->valid[pid]) + return data; + + data->valid[pid] = 0; + /* To be compatible for older BMC firmware */ + data->ipmi_resp[pid].status[PSU_VOUT_MODE] = 0xff; + + /* Get status from ipmi */ + data->ipmi_tx_data[0] = pid + 1; /* PSU ID base id for ipmi start from 1 */ + status = ipmi_send_message(&data->ipmi, IPMI_PSU_READ_CMD, + data->ipmi_tx_data, 1, + data->ipmi_resp[pid].status, + sizeof(data->ipmi_resp[pid].status)); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + /* Get model name from ipmi */ + data->ipmi_tx_data[1] = IPMI_PSU_MODEL_NAME_CMD; + status = ipmi_send_message(&data->ipmi, IPMI_PSU_READ_CMD, + data->ipmi_tx_data, 2, + data->ipmi_resp[pid].model, + sizeof(data->ipmi_resp[pid].model) - 1); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + /* Get serial number from ipmi */ + data->ipmi_tx_data[1] = IPMI_PSU_SERIAL_NUM_CMD; + status = ipmi_send_message(&data->ipmi, IPMI_PSU_READ_CMD, + data->ipmi_tx_data, 2, + data->ipmi_resp[pid].serial, + sizeof(data->ipmi_resp[pid].serial) - 1); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + /* Get fan direction from ipmi */ + data->ipmi_tx_data[1] = IPMI_PSU_FAN_DIR_CMD; + status = ipmi_send_message(&data->ipmi, IPMI_PSU_READ_CMD, + data->ipmi_tx_data, 2, + data->ipmi_resp[pid].fandir, + sizeof(data->ipmi_resp[pid].fandir) - 1); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + /* Get capability from ipmi */ + data->ipmi_tx_data[1] = IPMI_PSU_INFO_CMD; + status = ipmi_send_message(&data->ipmi, IPMI_PSU_READ_CMD, + data->ipmi_tx_data, 2, + data->ipmi_resp[pid].info, + sizeof(data->ipmi_resp[pid].info)); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + data->last_updated[pid] = jiffies; + data->valid[pid] = 1; + +exit: + return data; +} + +#define VALIDATE_PRESENT_RETURN(id) \ +do { \ + if (data->ipmi_resp[id].status[PSU_PRESENT] == 0) { \ + mutex_unlock(&data->update_lock); \ + return -ENXIO; \ + } \ +} while (0) + +static ssize_t show_psu(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + unsigned char pid = attr->index / NUM_OF_PER_PSU_ATTR; + u32 value = 0; + int present = 0; + int error = 0; + int multiplier = 1000; + + mutex_lock(&data->update_lock); + + data = as7535_32xb_psu_update_device(da); + if (!data->valid[pid]) { + error = -EIO; + goto exit; + } + + present = !!(data->ipmi_resp[pid].status[PSU_PRESENT]); + + switch (attr->index) { + case PSU1_PRESENT: + case PSU2_PRESENT: + value = present; + break; + case PSU1_POWER_GOOD: + case PSU2_POWER_GOOD: + VALIDATE_PRESENT_RETURN(pid); + value = data->ipmi_resp[pid].status[PSU_POWER_GOOD_PMBUS]; + break; + case PSU1_IIN: + case PSU2_IIN: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].status[PSU_IIN0] | + (u32)data->ipmi_resp[pid].status[PSU_IIN1] << 8 | + (u32)data->ipmi_resp[pid].status[PSU_IIN2] << 16); + break; + case PSU1_IOUT: + case PSU2_IOUT: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].status[PSU_IOUT0] | + (u32)data->ipmi_resp[pid].status[PSU_IOUT1] << 8 | + (u32)data->ipmi_resp[pid].status[PSU_IOUT2] << 16); + break; + case PSU1_VIN: + case PSU2_VIN: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].status[PSU_VIN0] | + (u32)data->ipmi_resp[pid].status[PSU_VIN1] << 8 | + (u32)data->ipmi_resp[pid].status[PSU_VIN2] << 16); + break; + case PSU1_VOUT: + case PSU2_VOUT: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].status[PSU_VOUT0] | + (u32)data->ipmi_resp[pid].status[PSU_VOUT1] << 8 | + (u32)data->ipmi_resp[pid].status[PSU_VOUT2] << 16); + break; + case PSU1_PIN: + case PSU2_PIN: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].status[PSU_PIN0] | + (u32)data->ipmi_resp[pid].status[PSU_PIN1] << 8 | + (u32)data->ipmi_resp[pid].status[PSU_PIN2] << 16 | + (u32)data->ipmi_resp[pid].status[PSU_PIN3] << 24); + value /= 1000; // Convert to milliwatt + break; + case PSU1_POUT: + case PSU2_POUT: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].status[PSU_POUT0] | + (u32)data->ipmi_resp[pid].status[PSU_POUT1] << 8 | + (u32)data->ipmi_resp[pid].status[PSU_POUT2] << 16 | + (u32)data->ipmi_resp[pid].status[PSU_POUT3] << 24); + value /= 1000; // Convert to milliwatt + break; + case PSU1_TEMP1_INPUT: + case PSU2_TEMP1_INPUT: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].status[PSU_TEMP1_0] | + (u32)data->ipmi_resp[pid].status[PSU_TEMP1_1] << 8); + value *= 1000; // Convert to millidegree Celsius + break; + case PSU1_TEMP2_INPUT: + case PSU2_TEMP2_INPUT: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].status[PSU_TEMP2_0] | + (u32)data->ipmi_resp[pid].status[PSU_TEMP2_1] << 8); + value *= 1000; // Convert to millidegree Celsius + break; + case PSU1_TEMP3_INPUT: + case PSU2_TEMP3_INPUT: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].status[PSU_TEMP3_0] | + (u32)data->ipmi_resp[pid].status[PSU_TEMP3_1] << 8); + value *= 1000; // Convert to millidegree Celsius + break; + case PSU1_FAN_INPUT: + case PSU2_FAN_INPUT: + VALIDATE_PRESENT_RETURN(pid); + multiplier = 1; + value = ((u32)data->ipmi_resp[pid].status[PSU_FAN0] | + (u32)data->ipmi_resp[pid].status[PSU_FAN1] << 8); + break; + default: + error = -EINVAL; + goto exit; + } + + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", present ? value : 0); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static ssize_t show_psu_info(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + unsigned char pid = attr->index / NUM_OF_PER_PSU_ATTR; + s32 value = 0; + int present = 0; + int error = 0; + + mutex_lock(&data->update_lock); + + data = as7535_32xb_psu_update_device(da); + if (!data->valid[pid]) { + error = -EIO; + goto exit; + } + + present = !!(data->ipmi_resp[pid].status[PSU_PRESENT]); + + switch (attr->index) { + case PSU1_TEMP1_INPUT_MAX: + case PSU2_TEMP1_INPUT_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = (s16)((u16)data->ipmi_resp[pid].info[PSU_TEMP1_MAX0] | + (u16)data->ipmi_resp[pid].info[PSU_TEMP1_MAX1] << 8); + value *= 1000; // Convert to millidegree Celsius + break; + case PSU1_TEMP1_INPUT_MIN: + case PSU2_TEMP1_INPUT_MIN: + VALIDATE_PRESENT_RETURN(pid); + value = (s16)((u16)data->ipmi_resp[pid].info[PSU_TEMP1_MIN0] | + (u16)data->ipmi_resp[pid].info[PSU_TEMP1_MIN1] << 8); + value *= 1000; // Convert to millidegree Celsius + break; + case PSU1_TEMP2_INPUT_MAX: + case PSU2_TEMP2_INPUT_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = (s16)((u16)data->ipmi_resp[pid].info[PSU_TEMP2_MAX0] | + (u16)data->ipmi_resp[pid].info[PSU_TEMP2_MAX1] << 8); + value *= 1000; // Convert to millidegree Celsius + break; + case PSU1_TEMP2_INPUT_MIN: + case PSU2_TEMP2_INPUT_MIN: + VALIDATE_PRESENT_RETURN(pid); + value = (s16)((u16)data->ipmi_resp[pid].info[PSU_TEMP2_MIN0] | + (u16)data->ipmi_resp[pid].info[PSU_TEMP2_MIN1] << 8); + value *= 1000; // Convert to millidegree Celsius + break; + case PSU1_TEMP3_INPUT_MAX: + case PSU2_TEMP3_INPUT_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = (s16)((u16)data->ipmi_resp[pid].info[PSU_TEMP3_MAX0] | + (u16)data->ipmi_resp[pid].info[PSU_TEMP3_MAX1] << 8); + value *= 1000; // Convert to millidegree Celsius + break; + case PSU1_TEMP3_INPUT_MIN: + case PSU2_TEMP3_INPUT_MIN: + VALIDATE_PRESENT_RETURN(pid); + value = (s16)((u16)data->ipmi_resp[pid].info[PSU_TEMP3_MIN0] | + (u16)data->ipmi_resp[pid].info[PSU_TEMP3_MIN1] << 8); + value *= 1000; // Convert to millidegree Celsius + break; + case PSU1_VIN_UPPER_CRIT: + case PSU2_VIN_UPPER_CRIT: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_VIN_UPPER_CRIT0] | + (u32)data->ipmi_resp[pid].info[PSU_VIN_UPPER_CRIT1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_VIN_UPPER_CRIT2] << 16); + break; + case PSU1_VIN_LOWER_CRIT: + case PSU2_VIN_LOWER_CRIT: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_VIN_LOWER_CRIT0] | + (u32)data->ipmi_resp[pid].info[PSU_VIN_LOWER_CRIT1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_VIN_LOWER_CRIT2] << 16); + break; + case PSU1_VIN_MAX: + case PSU2_VIN_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_VIN_MAX0] | + (u32)data->ipmi_resp[pid].info[PSU_VIN_MAX1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_VIN_MAX2] << 16); + break; + case PSU1_VIN_MIN: + case PSU2_VIN_MIN: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_VIN_MIN0] | + (u32)data->ipmi_resp[pid].info[PSU_VIN_MIN1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_VIN_MIN2] << 16); + break; + case PSU1_VOUT_MAX: + case PSU2_VOUT_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_VOUT_MAX0] | + (u32)data->ipmi_resp[pid].info[PSU_VOUT_MAX1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_VOUT_MAX2] << 16); + break; + case PSU1_VOUT_MIN: + case PSU2_VOUT_MIN: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_VOUT_MIN0] | + (u32)data->ipmi_resp[pid].info[PSU_VOUT_MIN1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_VOUT_MIN2] << 16); + break; + case PSU1_IIN_MAX: + case PSU2_IIN_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_IIN_MAX0] | + (u32)data->ipmi_resp[pid].info[PSU_IIN_MAX1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_IIN_MAX2] << 16); + break; + case PSU1_IOUT_MAX: + case PSU2_IOUT_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_IOUT_MAX0] | + (u32)data->ipmi_resp[pid].info[PSU_IOUT_MAX1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_IOUT_MAX2] << 16); + break; + case PSU1_PIN_MAX: + case PSU2_PIN_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_PIN_MAX0] | + (u32)data->ipmi_resp[pid].info[PSU_PIN_MAX1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_PIN_MAX2] << 16 | + (u32)data->ipmi_resp[pid].info[PSU_PIN_MAX3] << 24); + value /= 1000; // Convert to milliwatt + break; + case PSU1_POUT_MAX: + case PSU2_POUT_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_POUT_MAX0] | + (u32)data->ipmi_resp[pid].info[PSU_POUT_MAX1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_POUT_MAX2] << 16 | + (u32)data->ipmi_resp[pid].info[PSU_POUT_MAX3] << 24); + value /= 1000; // Convert to milliwatt + break; + default: + error = -EINVAL; + goto exit; + } + + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", present ? value : 0); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static ssize_t show_string(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + unsigned char pid = attr->index / NUM_OF_PER_PSU_ATTR; + char *str = NULL; + int error = 0; + + mutex_lock(&data->update_lock); + + data = as7535_32xb_psu_update_device(da); + if (!data->valid[pid]) { + error = -EIO; + goto exit; + } + + switch (attr->index) { + case PSU1_MODEL: + case PSU2_MODEL: + VALIDATE_PRESENT_RETURN(pid); + str = data->ipmi_resp[pid].model; + break; + case PSU1_SERIAL: + case PSU2_SERIAL: + VALIDATE_PRESENT_RETURN(pid); + str = data->ipmi_resp[pid].serial; + break; + case PSU1_FAN_DIR: + case PSU2_FAN_DIR: + VALIDATE_PRESENT_RETURN(pid); + str = data->ipmi_resp[pid].fandir; + break; + default: + error = -EINVAL; + goto exit; + } + + mutex_unlock(&data->update_lock); + return sprintf(buf, "%s\n", str); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static int as7535_32xb_psu_probe(struct platform_device *pdev) +{ + int status = -1; + + /* Register sysfs hooks */ + status = sysfs_create_group(&pdev->dev.kobj, &as7535_32xb_psu_group); + if (status) + return status; + + dev_info(&pdev->dev, "device created\n"); + + return 0; +} + +static int as7535_32xb_psu_remove(struct platform_device *pdev) +{ + sysfs_remove_group(&pdev->dev.kobj, &as7535_32xb_psu_group); + return 0; +} + +static int __init as7535_32xb_psu_init(void) +{ + int ret; + + data = kzalloc(sizeof(struct as7535_32xb_psu_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto alloc_err; + } + + mutex_init(&data->update_lock); + + ret = platform_driver_register(&as7535_32xb_psu_driver); + if (ret < 0) + goto dri_reg_err; + + data->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(data->pdev)) { + ret = PTR_ERR(data->pdev); + goto dev_reg_err; + } + + /* Set up IPMI interface */ + ret = init_ipmi_data(&data->ipmi, 0, &data->pdev->dev); + if (ret) + goto ipmi_err; + + return 0; + +ipmi_err: + platform_device_unregister(data->pdev); +dev_reg_err: + platform_driver_unregister(&as7535_32xb_psu_driver); +dri_reg_err: + kfree(data); +alloc_err: + return ret; +} + +static void __exit as7535_32xb_psu_exit(void) +{ + ipmi_destroy_user(data->ipmi.user); + platform_device_unregister(data->pdev); + platform_driver_unregister(&as7535_32xb_psu_driver); + kfree(data); +} + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("as7535_32xb_psu driver"); +MODULE_LICENSE("GPL"); + +module_init(as7535_32xb_psu_init); +module_exit(as7535_32xb_psu_exit); diff --git a/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/modules/x86-64-accton-as7535-32xb-thermal.c b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/modules/x86-64-accton-as7535-32xb-thermal.c new file mode 100644 index 00000000000..7eaa82d1359 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/modules/x86-64-accton-as7535-32xb-thermal.c @@ -0,0 +1,430 @@ +/* + * Copyright (C) Brandon Chuang + * + * Based on: + * pca954x.c from Kumar Gala + * Copyright (C) 2006 + * + * Based on: + * pca954x.c from Ken Harrenstien + * Copyright (C) 2004 Google, Inc. (Ken Harrenstien) + * + * Based on: + * i2c-virtual_cb.c from Brian Kuschak + * and + * pca9540.c from Jean Delvare . + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as7535_32xb_thermal" +#define ACCTON_IPMI_NETFN 0x34 +#define IPMI_THERMAL_READ_CMD 0x12 + +#define IPMI_TIMEOUT (5 * HZ) +#define IPMI_ERR_RETRY_TIMES 1 + +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, + char *buf); +static ssize_t set_max(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static int as7535_32xb_thermal_probe(struct platform_device *pdev); +static int as7535_32xb_thermal_remove(struct platform_device *pdev); + +enum temp_data_index { + TEMP_ADDR, + TEMP_FAULT, + TEMP_INPUT, + TEMP_DATA_COUNT +}; + +struct ipmi_data { + struct completion read_complete; + struct ipmi_addr address; + struct ipmi_user *user; + int interface; + + struct kernel_ipmi_msg tx_message; + long tx_msgid; + + void *rx_msg_data; + unsigned short rx_msg_len; + unsigned char rx_result; + int rx_recv_type; + + struct ipmi_user_hndl ipmi_hndlrs; +}; + +struct as7535_32xb_thermal_data { + struct platform_device *pdev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + char ipmi_resp[36]; /* 3 bytes for each thermal */ + struct ipmi_data ipmi; + unsigned char ipmi_tx_data[2]; /* 0: thermal id, 1: temp */ + char temp_max[12]; +}; + +struct as7535_32xb_thermal_data *data = NULL; + +static struct platform_driver as7535_32xb_thermal_driver = { + .probe = as7535_32xb_thermal_probe, + .remove = as7535_32xb_thermal_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +enum as7535_32xb_thermal_sysfs_attrs { + TEMP1_INPUT, // 0x4B + TEMP2_INPUT, // 0x4C tmp43 local + TEMP3_INPUT, // 0x4C tmp43 remote + TEMP4_INPUT, // 0x4D lm75 + TEMP5_INPUT, // 0x4E lm75 + TEMP6_INPUT, // 0x4F lm75 + TEMP1_MAX, + TEMP2_MAX, + TEMP3_MAX, + TEMP4_MAX, + TEMP5_MAX, + TEMP6_MAX +}; + +// Read only temp_input +#define DECLARE_THERMAL_SENSOR_DEVICE_ATTR_R(index) \ + static SENSOR_DEVICE_ATTR(temp##index##_input, S_IRUGO, show_temp, \ + NULL, TEMP##index##_INPUT); \ + static SENSOR_DEVICE_ATTR(temp##index##_max, S_IWUSR | S_IRUGO, show_temp,\ + set_max, TEMP##index##_MAX) + +#define DECLARE_THERMAL_ATTR(index) \ + &sensor_dev_attr_temp##index##_input.dev_attr.attr, \ + &sensor_dev_attr_temp##index##_max.dev_attr.attr + +DECLARE_THERMAL_SENSOR_DEVICE_ATTR_R(1); +DECLARE_THERMAL_SENSOR_DEVICE_ATTR_R(2); +DECLARE_THERMAL_SENSOR_DEVICE_ATTR_R(3); +DECLARE_THERMAL_SENSOR_DEVICE_ATTR_R(4); +DECLARE_THERMAL_SENSOR_DEVICE_ATTR_R(5); +DECLARE_THERMAL_SENSOR_DEVICE_ATTR_R(6); + +static struct attribute *as7535_32xb_thermal_attributes[] = { + DECLARE_THERMAL_ATTR(1), + DECLARE_THERMAL_ATTR(2), + DECLARE_THERMAL_ATTR(3), + DECLARE_THERMAL_ATTR(4), + DECLARE_THERMAL_ATTR(5), + DECLARE_THERMAL_ATTR(6), + NULL +}; + +static const struct attribute_group as7535_32xb_thermal_group = { + .attrs = as7535_32xb_thermal_attributes, +}; + +/* Functions to talk to the IPMI layer */ + +/* Initialize IPMI address, message buffers and user data */ +static int init_ipmi_data(struct ipmi_data *ipmi, int iface, + struct device *dev) +{ + int err; + + init_completion(&ipmi->read_complete); + + /* Initialize IPMI address */ + ipmi->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + ipmi->address.channel = IPMI_BMC_CHANNEL; + ipmi->address.data[0] = 0; + ipmi->interface = iface; + + /* Initialize message buffers */ + ipmi->tx_msgid = 0; + ipmi->tx_message.netfn = ACCTON_IPMI_NETFN; + + ipmi->ipmi_hndlrs.ipmi_recv_hndl = ipmi_msg_handler; + + /* Create IPMI messaging interface user */ + err = ipmi_create_user(ipmi->interface, &ipmi->ipmi_hndlrs, + ipmi, &ipmi->user); + if (err < 0) { + dev_err(dev, "Unable to register user with IPMI " + "interface %d\n", ipmi->interface); + return -EACCES; + } + + return 0; +} + +/* Send an IPMI command */ +static int _ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int err; + + ipmi->tx_message.cmd = cmd; + ipmi->tx_message.data = tx_data; + ipmi->tx_message.data_len = tx_len; + ipmi->rx_msg_data = rx_data; + ipmi->rx_msg_len = rx_len; + + err = ipmi_validate_addr(&ipmi->address, sizeof(ipmi->address)); + if (err) + goto addr_err; + + ipmi->tx_msgid++; + err = ipmi_request_settime(ipmi->user, &ipmi->address, ipmi->tx_msgid, + &ipmi->tx_message, ipmi, 0, 0, 0); + if (err) + goto ipmi_req_err; + + err = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); + if (!err) + goto ipmi_timeout_err; + + return 0; + +ipmi_timeout_err: + err = -ETIMEDOUT; + dev_err(&data->pdev->dev, "request_timeout=%x\n", err); + return err; +ipmi_req_err: + dev_err(&data->pdev->dev, "request_settime=%x\n", err); + return err; +addr_err: + dev_err(&data->pdev->dev, "validate_addr=%x\n", err); + return err; +} + +/* Send an IPMI command with retry */ +static int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int status = 0, retry = 0; + + for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { + status = _ipmi_send_message(ipmi, cmd, tx_data, tx_len, rx_data, rx_len); + if (unlikely(status != 0)) { + dev_err(&data->pdev->dev, "ipmi cmd(%x) err status(%d)\r\n", + cmd, status); + continue; + } + + if (unlikely(ipmi->rx_result != 0)) { + dev_err(&data->pdev->dev, "ipmi cmd(%x) err result(%d)\r\n", + cmd, ipmi->rx_result); + continue; + } + + break; + } + + return status; +} + +/* Dispatch IPMI messages to callers */ +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) +{ + unsigned short rx_len; + struct ipmi_data *ipmi = user_msg_data; + + if (msg->msgid != ipmi->tx_msgid) { + dev_err(&data->pdev->dev, "Mismatch between received msgid " + "(%02x) and transmitted msgid (%02x)!\n", + (int)msg->msgid, + (int)ipmi->tx_msgid); + ipmi_free_recv_msg(msg); + return; + } + + ipmi->rx_recv_type = msg->recv_type; + if (msg->msg.data_len > 0) + ipmi->rx_result = msg->msg.data[0]; + else + ipmi->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE; + + if (msg->msg.data_len > 1) { + rx_len = msg->msg.data_len - 1; + if (ipmi->rx_msg_len < rx_len) + rx_len = ipmi->rx_msg_len; + ipmi->rx_msg_len = rx_len; + memcpy(ipmi->rx_msg_data, msg->msg.data + 1, ipmi->rx_msg_len); + } else + ipmi->rx_msg_len = 0; + + ipmi_free_recv_msg(msg); + complete(&ipmi->read_complete); +} + +static ssize_t show_temp(struct device *dev, struct device_attribute *da, + char *buf) +{ + int status = 0; + int index = 0; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + + mutex_lock(&data->update_lock); + + if (attr->index >= TEMP1_MAX && attr->index <= TEMP6_MAX) { + int max = data->temp_max[attr->index - TEMP1_MAX]; + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", max * 1000); + } + + if (time_after(jiffies, data->last_updated + HZ * 5) || !data->valid) { + data->valid = 0; + + status = ipmi_send_message(&data->ipmi, IPMI_THERMAL_READ_CMD, NULL, 0, + data->ipmi_resp, sizeof(data->ipmi_resp)); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + data->last_updated = jiffies; + data->valid = 1; + } + + /* Get temp fault status */ + index = attr->index * TEMP_DATA_COUNT + TEMP_FAULT; + if (unlikely(data->ipmi_resp[index] == 0)) { + status = -EIO; + goto exit; + } + + /* Get temperature in degree celsius */ + index = attr->index * TEMP_DATA_COUNT + TEMP_INPUT; + status = ((s8)data->ipmi_resp[index]) * 1000; + + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", status); + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t set_max(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + long temp; + int status; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + + status = kstrtol(buf, 10, &temp); + if (status) + return status; + + if (temp > 127 || temp < -128) + return -EINVAL; + + mutex_lock(&data->update_lock); + data->temp_max[attr->index-TEMP1_MAX] = temp; + status = count; + mutex_unlock(&data->update_lock); + + return status; +} + +static int as7535_32xb_thermal_probe(struct platform_device *pdev) +{ + int status = -1; + + /* Register sysfs hooks */ + status = sysfs_create_group(&pdev->dev.kobj, &as7535_32xb_thermal_group); + if (status) + return status; + + dev_info(&pdev->dev, "device created\n"); + + return 0; +} + +static int as7535_32xb_thermal_remove(struct platform_device *pdev) +{ + sysfs_remove_group(&pdev->dev.kobj, &as7535_32xb_thermal_group); + return 0; +} + +static int __init as7535_32xb_thermal_init(void) +{ + int ret; + int i = 0; + + data = kzalloc(sizeof(struct as7535_32xb_thermal_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto alloc_err; + } + + mutex_init(&data->update_lock); + data->valid = 0; + + ret = platform_driver_register(&as7535_32xb_thermal_driver); + if (ret < 0) + goto dri_reg_err; + + data->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(data->pdev)) { + ret = PTR_ERR(data->pdev); + goto dev_reg_err; + } + + /* Set up IPMI interface */ + ret = init_ipmi_data(&data->ipmi, 0, &data->pdev->dev); + if (ret) + goto ipmi_err; + + for (i = 0; i < ARRAY_SIZE(data->temp_max); i++) { + data->temp_max[i] = 70; /* default high threshold */ + } + + return 0; + +ipmi_err: + platform_device_unregister(data->pdev); +dev_reg_err: + platform_driver_unregister(&as7535_32xb_thermal_driver); +dri_reg_err: + kfree(data); +alloc_err: + return ret; +} + +static void __exit as7535_32xb_thermal_exit(void) +{ + ipmi_destroy_user(data->ipmi.user); + platform_device_unregister(data->pdev); + platform_driver_unregister(&as7535_32xb_thermal_driver); + kfree(data); +} + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("as7535_32xb_thermal driver"); +MODULE_LICENSE("GPL"); + +module_init(as7535_32xb_thermal_init); +module_exit(as7535_32xb_thermal_exit); diff --git a/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/service/as7535-32xb-platform-monitor.service b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/service/as7535-32xb-platform-monitor.service new file mode 100644 index 00000000000..edbe5350eae --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/service/as7535-32xb-platform-monitor.service @@ -0,0 +1,18 @@ +[Unit] +Description=Accton AS7535-32XB Platform Monitoring service +Before=pmon.service +After=sysinit.target +DefaultDependencies=no + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/accton_as7535_32xb_util.py install +KillSignal=SIGKILL +SuccessExitStatus=SIGKILL +TimeoutSec=300 + +# Resource Limitations +LimitCORE=infinity + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/setup.py b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/setup.py new file mode 100644 index 00000000000..3952be74287 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/setup.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python + +import os +from setuptools import setup +os.listdir + +setup( + name='as7535_32xb', + version='1.0', + description='Module to initialize Accton AS7535-32XB platforms', + + packages=['as7535_32xb'], + package_dir={'as7535_32xb': 'as7535-32xb/classes'}, +) diff --git a/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/__init__.py b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/__init__.py new file mode 100644 index 00000000000..706e2313249 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/__init__.py @@ -0,0 +1,2 @@ +__all__ = ['chassis', 'eeprom', 'platform', 'psu', 'sfp', 'thermal', 'fan', 'fan_drawer'] +from . import platform diff --git a/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/chassis.py new file mode 100644 index 00000000000..729fc3d1934 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/chassis.py @@ -0,0 +1,235 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Chassis information which are available in the platform +# +############################################################################# + +import os + +try: + from sonic_platform_base.chassis_base import ChassisBase + from .helper import APIHelper + from .event import SfpEvent +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +NUM_FAN_TRAY = 6 +NUM_FAN = 1 +NUM_PSU = 2 +NUM_THERMAL = 6 +PORT_START = 1 +PORT_END = 30 +QSFP_PORT_START = 27 +QSFP_PORT_END = 30 +NUM_COMPONENT = 4 +HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/" +PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/" +REBOOT_CAUSE_FILE = "reboot-cause.txt" +PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt" +HOST_CHK_CMD = "which systemctl > /dev/null 2>&1" + + +class Chassis(ChassisBase): + """Platform-specific Chassis class""" + + def __init__(self): + ChassisBase.__init__(self) + self._api_helper = APIHelper() + self.is_host = self._api_helper.is_host() + + self.config_data = {} + + self.__initialize_fan() + self.__initialize_psu() + self.__initialize_thermals() + self.__initialize_components() + self.__initialize_sfp() + self.__initialize_eeprom() + + def __initialize_sfp(self): + from sonic_platform.sfp import Sfp + + self.QSFP_PORT_START = QSFP_PORT_START + self.QSFP_PORT_END = QSFP_PORT_END + for index in range(0, PORT_END): + if index in range(self.QSFP_PORT_START, self.QSFP_PORT_END + 1): + sfp_module = Sfp(index, 'QSFP') + else: + sfp_module = Sfp(index, 'SFP') + self._sfp_list.append(sfp_module) + self.sfp_module_initialized = True + + def __initialize_fan(self): + from sonic_platform.fan_drawer import FanDrawer + for fant_index in range(NUM_FAN_TRAY): + fandrawer = FanDrawer(fant_index) + self._fan_drawer_list.append(fandrawer) + self._fan_list.extend(fandrawer._fan_list) + + def __initialize_psu(self): + from sonic_platform.psu import Psu + for index in range(0, NUM_PSU): + psu = Psu(index) + self._psu_list.append(psu) + + def __initialize_thermals(self): + from sonic_platform.thermal import Thermal + for index in range(0, NUM_THERMAL): + thermal = Thermal(index) + self._thermal_list.append(thermal) + + def __initialize_eeprom(self): + from sonic_platform.eeprom import Tlv + self._eeprom = Tlv() + + def __initialize_components(self): + from sonic_platform.component import Component + for index in range(0, NUM_COMPONENT): + component = Component(index) + self._component_list.append(component) + + def __initialize_watchdog(self): + from sonic_platform.watchdog import Watchdog + self._watchdog = Watchdog() + + + def __is_host(self): + return os.system(HOST_CHK_CMD) == 0 + + def __read_txt_file(self, file_path): + try: + with open(file_path, 'r') as fd: + return fd.read().strip() + except IOError: + pass + return None + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + + return self._api_helper.hwsku + + def get_presence(self): + """ + Retrieves the presence of the Chassis + Returns: + bool: True if Chassis is present, False if not + """ + return True + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent + device or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether Chassis is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False + + 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 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._eeprom.get_mac() + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return self._eeprom.get_pn() + + def get_serial(self): + """ + Retrieves the hardware serial number for the chassis + Returns: + A string containing the hardware serial number for this chassis. + """ + return self._eeprom.get_serial() + + 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._eeprom.get_eeprom() + + 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. + """ + + reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE) + sw_reboot_cause = self._api_helper.read_txt_file( + reboot_cause_path) or "Unknown" + + + return ('REBOOT_CAUSE_NON_HARDWARE', sw_reboot_cause) + + def get_change_event(self, timeout=0): + # SFP event + if not self.sfp_module_initialized: + self.__initialize_sfp() + + status, sfp_event = SfpEvent(self._sfp_list).get_sfp_event(timeout) + + return status, sfp_event + + def get_sfp(self, index): + """ + Retrieves sfp represented by (1-based) index + Args: + index: An integer, the index (1-based) of the sfp to retrieve. + The index should be the sequence of a physical port in a chassis, + starting from 1. + For example, 1 for Ethernet0, 2 for Ethernet4 and so on. + Returns: + An object dervied from SfpBase representing the specified sfp + """ + sfp = None + if not self.sfp_module_initialized: + self.__initialize_sfp() + + try: + # The index will start from 1 + sfp = self._sfp_list[index-1] + except IndexError: + sys.stderr.write("SFP index {} out of range (1-{})\n".format( + index, len(self._sfp_list))) + return sfp diff --git a/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/component.py b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/component.py new file mode 100644 index 00000000000..96b4a69c022 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/component.py @@ -0,0 +1,150 @@ +############################################################################# +# Edgecore +# +# Component contains an implementation of SONiC Platform Base API and +# provides the components firmware management function +# +############################################################################# + +import shlex +import subprocess + +try: + from sonic_platform_base.component_base import ComponentBase + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +CPLD_PATH_MAPPING = { + "MAIN_CPLD": "/sys/bus/i2c/devices/12-0061/version", + "FAN_CPLD": "/sys/devices/platform/as7535_32xb_fan/version", +} + +FPGA_PATH_MAPPING = { + "FPGA_MAJOR": "/sys/bus/i2c/devices/11-0060/fpga_ver_major", + "FPGA_MINOR": "/sys/bus/i2c/devices/11-0060/fpga_ver_minor", +} + +BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version" +COMPONENT_LIST= [ + ("MAIN_FPGA", "Main board FPGA"), + ("MAIN_CPLD", "Main board CPLD"), + ("FAN_CPLD", "Fan board CPLD"), + ("BIOS", "Basic Input/Output System") +] + +class Component(ComponentBase): + """Platform-specific Component class""" + + DEVICE_TYPE = "component" + + def __init__(self, component_index=0): + self._api_helper=APIHelper() + ComponentBase.__init__(self) + self.index = component_index + self.name = self.get_name() + + def __run_command(self, command): + # Run bash command and print output to stdout + try: + process = subprocess.Popen( + shlex.split(command), stdout=subprocess.PIPE) + while True: + output = process.stdout.readline() + if output == '' and process.poll() is not None: + break + rc = process.poll() + if rc != 0: + return False + except Exception: + return False + return True + + def __get_bios_version(self): + # Retrieves the BIOS firmware version + try: + with open(BIOS_VERSION_PATH, 'r') as fd: + return fd.read().strip() + except Exception as e: + print('Get exception when read bios') + return None + + def __get_cpld_version(self): + # Retrieves the CPLD firmware version + cpld_version = dict() + for cpld_name in CPLD_PATH_MAPPING: + try: + cpld_path = "{}".format(CPLD_PATH_MAPPING[cpld_name]) + cpld_version_raw= self._api_helper.read_txt_file(cpld_path) + cpld_version[cpld_name] = "{:x}".format(int(cpld_version_raw,10)) + except Exception as e: + print('Get exception when read cpld (%s)', cpld_path) + cpld_version[cpld_name] = 'None' + + return cpld_version + + def __get_fpga_version(self): + # Retrieves the CPLD firmware version + fpga_version = dict() + for fpga_name in FPGA_PATH_MAPPING: + try: + fpga_path = "{}".format(FPGA_PATH_MAPPING[fpga_name]) + fpga_version_raw= self._api_helper.read_txt_file(fpga_path) + fpga_version[fpga_name] = "{:x}".format(int(fpga_version_raw,10)) + except Exception as e: + print('Get exception when read cpld (%s)', fpga_path) + fpga_version[fpga_name] = 'None' + + return "{}.{}".format(fpga_version["FPGA_MAJOR"], fpga_version["FPGA_MINOR"]) + + def get_name(self): + """ + Retrieves the name of the component + Returns: + A string containing the name of the component + """ + return COMPONENT_LIST[self.index][0] + + def get_description(self): + """ + Retrieves the description of the component + Returns: + A string containing the description of the component + """ + return COMPONENT_LIST[self.index][1] + + def get_firmware_version(self): + """ + Retrieves the firmware version of module + Returns: + string: The firmware versions of the module + """ + fw_version = None + if self.name == "BIOS": + fw_version = self.__get_bios_version() + elif "CPLD" in self.name: + cpld_version = self.__get_cpld_version() + fw_version = cpld_version.get(self.name) + elif "FPGA" in self.name: + fw_version = self.__get_fpga_version() + + return fw_version + + def install_firmware(self, image_path): + """ + Install firmware to module + Args: + image_path: A string, path to firmware image + Returns: + A boolean, True if install successfully, False if not + """ + raise NotImplementedError + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent + device or -1 if cannot determine the position + """ + return -1 diff --git a/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/eeprom.py b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/eeprom.py new file mode 100644 index 00000000000..cb4b8bd9588 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/eeprom.py @@ -0,0 +1,131 @@ +try: + import os + import sys + import re + if sys.version_info[0] >= 3: + from io import StringIO + else: + from cStringIO import StringIO + + from sonic_platform_base.sonic_eeprom import eeprom_tlvinfo +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +CACHE_ROOT = '/var/cache/sonic/decode-syseeprom' +CACHE_FILE = 'syseeprom_cache' +NULL = 'N/A' + +class Tlv(eeprom_tlvinfo.TlvInfoDecoder): + + EEPROM_DECODE_HEADLINES = 6 + + def __init__(self): + self._eeprom_path = "/sys/bus/i2c/devices/0-0057/eeprom" + super(Tlv, self).__init__(self._eeprom_path, 0, '', True) + self._eeprom = self._load_eeprom() + + def __parse_output(self, decode_output): + decode_output.replace('\0', '') + lines = decode_output.split('\n') + lines = lines[self.EEPROM_DECODE_HEADLINES:] + _eeprom_info_dict = dict() + + for line in lines: + try: + match = re.search( + '(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)([\S]+)', line) + if match is not None: + idx = match.group(1) + value = match.group(3).rstrip('\0') + + _eeprom_info_dict[idx] = value + except Exception: + pass + + return _eeprom_info_dict + + def _load_eeprom(self): + original_stdout = sys.stdout + sys.stdout = StringIO() + try: + self.read_eeprom_db() + except Exception: + decode_output = sys.stdout.getvalue() + sys.stdout = original_stdout + return self.__parse_output(decode_output) + + status = self.check_status() + if 'ok' not in status: + return False + + if not os.path.exists(CACHE_ROOT): + try: + os.makedirs(CACHE_ROOT) + except Exception: + pass + + # + # only the eeprom classes that inherit from eeprom_base + # support caching. Others will work normally + # + try: + self.set_cache_name(os.path.join(CACHE_ROOT, CACHE_FILE)) + except Exception: + pass + + e = self.read_eeprom() + if e is None: + return 0 + + try: + self.update_cache(e) + except Exception: + pass + + self.decode_eeprom(e) + decode_output = sys.stdout.getvalue() + sys.stdout = original_stdout + + (is_valid, valid_crc) = self.is_checksum_valid(e) + if not is_valid: + return False + + return self.__parse_output(decode_output) + + def _valid_tlv(self, eeprom_data): + tlvinfo_type_codes_list = [ + self._TLV_CODE_PRODUCT_NAME, + self._TLV_CODE_PART_NUMBER, + self._TLV_CODE_SERIAL_NUMBER, + self._TLV_CODE_MAC_BASE, + self._TLV_CODE_MANUF_DATE, + self._TLV_CODE_DEVICE_VERSION, + self._TLV_CODE_LABEL_REVISION, + self._TLV_CODE_PLATFORM_NAME, + self._TLV_CODE_ONIE_VERSION, + self._TLV_CODE_MAC_SIZE, + self._TLV_CODE_MANUF_NAME, + self._TLV_CODE_MANUF_COUNTRY, + self._TLV_CODE_VENDOR_NAME, + self._TLV_CODE_DIAG_VERSION, + self._TLV_CODE_SERVICE_TAG, + self._TLV_CODE_VENDOR_EXT, + self._TLV_CODE_CRC_32 + ] + + for code in tlvinfo_type_codes_list: + code_str = "0x{:X}".format(code) + eeprom_data[code_str] = eeprom_data.get(code_str, NULL) + return eeprom_data + + def get_eeprom(self): + return self._valid_tlv(self._eeprom) + + def get_pn(self): + return self._eeprom.get('0x22', NULL) + + def get_serial(self): + return self._eeprom.get('0x23', NULL) + + def get_mac(self): + return self._eeprom.get('0x24', NULL) diff --git a/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/event.py b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/event.py new file mode 100644 index 00000000000..f26c5a4bc4f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/event.py @@ -0,0 +1,55 @@ +try: + import time + from .helper import APIHelper + from sonic_py_common.logger import Logger +except ImportError as e: + raise ImportError(repr(e) + " - required module not found") + + +class SfpEvent: + ''' Listen to insert/remove sfp events ''' + + def __init__(self, sfp_list): + self._api_helper = APIHelper() + self._sfp_list = sfp_list + self._logger = Logger() + + sfp_change_event_data = {'valid': 0, 'last': 0, 'present': 0} + def get_sfp_event(self, timeout=2000): + now = time.time() + port_dict = {} + change_dict = {} + change_dict['sfp'] = port_dict + + if timeout < 1000: + timeout = 1000 + timeout = timeout / float(1000) # Convert to secs + + if now < (self.sfp_change_event_data['last'] + timeout) and self.sfp_change_event_data['valid']: + return True, change_dict + + bitmap = 0 + for sfp in self._sfp_list: + modpres = sfp.get_presence() + i = sfp.port_num-1 + if modpres: + bitmap = bitmap | (1 << i) + + changed_ports = self.sfp_change_event_data['present'] ^ bitmap + if changed_ports: + for sfp in self._sfp_list: + i = sfp.port_num-1 + if (changed_ports & (1 << i)): + if (bitmap & (1 << i)) == 0: + port_dict[i+1] = '0' + else: + port_dict[i+1] = '1' + + + # Update the cache dict + self.sfp_change_event_data['present'] = bitmap + self.sfp_change_event_data['last'] = now + self.sfp_change_event_data['valid'] = 1 + return True, change_dict + else: + return True, change_dict diff --git a/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/fan.py new file mode 100644 index 00000000000..cedfa2967a3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/fan.py @@ -0,0 +1,282 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the fan status which are available in the platform +# +############################################################################# + + +try: + from sonic_platform_base.fan_base import FanBase + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +PSU_FAN_MAX_RPM = 25500 + +CPLD_I2C_PATH = "/sys/devices/platform/as7535_32xb_fan/fan" +PSU_HWMON_I2C_PATH ="/sys/devices/platform/as7535_32xb_psu/psu{}" +FAN_NAME_LIST = ["FAN-1", "FAN-2", "FAN-3", "FAN-4", "FAN-5", "FAN-6"] + +class Fan(FanBase): + """Platform-specific Fan class""" + + def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0): + self._api_helper = APIHelper() + self.fan_index = fan_index + self.fan_tray_index = fan_tray_index + self.is_psu_fan = is_psu_fan + if self.is_psu_fan: + self.psu_index = psu_index + self.psu_hwmon_path = PSU_HWMON_I2C_PATH.format(self.psu_index+1) + + FanBase.__init__(self) + + + 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 not self.is_psu_fan: + dir_str = "{}{}{}".format(CPLD_I2C_PATH, self.fan_tray_index+1, '_dir') + val = self._api_helper.read_txt_file(dir_str) + if val is not None: + if val == 'F2B': #F2B + direction = self.FAN_DIRECTION_EXHAUST + else: + direction = self.FAN_DIRECTION_INTAKE + else: + direction = self.FAN_DIRECTION_EXHAUST + + else: #For PSU + dir_str = "{}{}".format(self.psu_hwmon_path,'psu_fan_dir') + + val=self._api_helper.read_txt_file(dir_str) + + if val is not None: + if val=='F2B': + direction=self.FAN_DIRECTION_EXHAUST + else: + direction=self.FAN_DIRECTION_INTAKE + else: + direction=self.FAN_DIRECTION_EXHAUST + + 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) + + """ + speed = 0 + if self.is_psu_fan: + psu_fan_path = "{}{}".format(self.psu_hwmon_path, '_fan1_input') + fan_speed_rpm = self._api_helper.read_txt_file(psu_fan_path) + if fan_speed_rpm is not None: + speed = (int(fan_speed_rpm, 10)) * 100 / PSU_FAN_MAX_RPM + if speed > 100: + speed = 100 + else: + return 0 + + elif self.get_presence(): + input_path = "{}{}{}".format(CPLD_I2C_PATH, self.fan_tray_index+1, '_input') + input = self._api_helper.read_txt_file(input_path) + + target_path = "{}{}{}".format(CPLD_I2C_PATH, self.fan_tray_index+1, '_target') + target = self._api_helper.read_txt_file(target_path) + + if input is None or target is None: + return 0 + + speed = (int(input) * self.get_target_speed()) / int(target) + + return int(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) + + Note: + speed_pc = pwm_target/255*100 + + 0 : when PWM mode is use + pwm : when pwm mode is not use + """ + speed = 0 + if self.is_psu_fan: + psu_fan_path = "{}{}".format(self.psu_hwmon_path, '_fan1_input') + fan_speed_rpm = self._api_helper.read_txt_file(psu_fan_path) + if fan_speed_rpm is not None: + speed = (int(fan_speed_rpm, 10)) * 100 / PSU_FAN_MAX_RPM + if speed > 100: + speed = 100 + else: + return 0 + else: + speed_path = "{}{}{}".format(CPLD_I2C_PATH, self.fan_tray_index+1, '_pwm') + speed = self._api_helper.read_txt_file(speed_path) + if speed is None: + return 0 + + return int(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 + """ + speed = 0 + if not self.is_psu_fan: + speed_path = "{}{}{}".format(CPLD_I2C_PATH, self.fan_tray_index+1, '_tolerance') + speed = self._api_helper.read_txt_file(speed_path) + if speed is None: + return 0 + + return int(speed) + + 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 not self.is_psu_fan and self.get_presence(): + speed_path = "{}{}{}".format(CPLD_I2C_PATH, self.fan_tray_index+1, '_pwm') + return self._api_helper.write_txt_file(speed_path, int(speed)) + + return False + + def set_status_led(self, color): + """ + Sets the state of the fan module status LED + Args: + color: A string representing the color with which to set the + fan module status LED + Returns: + bool: True if status LED state is set successfully, False if not + """ + return False #Not supported + + def get_status_led(self): + """ + Gets the state of the fan status LED + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + status=self.get_presence() + if status is None: + return self.STATUS_LED_COLOR_OFF + + return { + 1: self.STATUS_LED_COLOR_GREEN, + 0: self.STATUS_LED_COLOR_RED + }.get(status, self.STATUS_LED_COLOR_OFF) + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + fan_name = FAN_NAME_LIST[self.fan_tray_index + self.fan_index] \ + if not self.is_psu_fan \ + else "PSU-{} FAN-{}".format(self.psu_index+1, self.fan_index+1) + + return fan_name + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if FAN is present, False if not + """ + present_path = "{}{}{}".format(CPLD_I2C_PATH, self.fan_tray_index+1, '_present') + val=self._api_helper.read_txt_file(present_path) + + if not self.is_psu_fan: + if val is not None: + return int(val, 10)==1 + else: + return False + else: + return True + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + if self.is_psu_fan: + psu_fan_path= "{}{}".format(self.psu_hwmon_path, 'psu_fan1_fault') + val=self._api_helper.read_txt_file(psu_fan_path) + if val is not None: + return int(val, 10)==0 + else: + return False + else: + path = "{}{}{}".format(CPLD_I2C_PATH, self.fan_tray_index+1, '_fault') + val=self._api_helper.read_txt_file(path) + if val is not None: + return int(val, 10)==0 + else: + return False + + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + + return "N/A" + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return "N/A" + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True if not self.is_psu_fan else False + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return (self.fan_tray_index+1) \ + if not self.is_psu_fan else (self.psu_index+1) diff --git a/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/fan_drawer.py b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/fan_drawer.py new file mode 100644 index 00000000000..8b4c179da22 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/fan_drawer.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python + +######################################################################## +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Fan-Drawers' information available in the platform. +# +######################################################################## + +try: + from sonic_platform_base.fan_drawer_base import FanDrawerBase + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +FANS_PER_FANTRAY = 1 +CPLD_I2C_PATH = "/sys/devices/platform/as7535_32xb_fan/fan" + +class FanDrawer(FanDrawerBase): + """Platform-specific Fan class""" + + def __init__(self, fantray_index): + self._api_helper = APIHelper() + FanDrawerBase.__init__(self) + self.fantrayindex = fantray_index + + # FanTray is 0-based in platforms + self.__initialize_fan() + + def __initialize_fan(self): + from sonic_platform.fan import Fan + + for i in range(FANS_PER_FANTRAY): + self._fan_list.append(Fan(self.fantrayindex, i)) + + def get_name(self): + """ + Retrieves the fan drawer name + Returns: + string: The name of the device + """ + return "FanTray-{}".format(self.fantrayindex) + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if FAN is present, False if not + """ + present_path = "{}{}{}".format(CPLD_I2C_PATH, self.fantrayindex+1, '_present') + val=self._api_helper.read_txt_file(present_path) + + if val is not None: + return int(val, 10)==1 + + return False + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return self.fantrayindex+1 diff --git a/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/helper.py b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/helper.py new file mode 100644 index 00000000000..4cd60ac9061 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/helper.py @@ -0,0 +1,117 @@ +import os +import struct +import subprocess +from mmap import * +from sonic_py_common import device_info + +HOST_CHK_CMD = "docker > /dev/null 2>&1" +EMPTY_STRING = "" + + +class APIHelper(): + + def __init__(self): + (self.platform, self.hwsku) = device_info.get_platform_and_hwsku() + + def is_host(self): + return os.system(HOST_CHK_CMD) == 0 + + def pci_get_value(self, resource, offset): + status = True + result = "" + try: + fd = os.open(resource, os.O_RDWR) + mm = mmap(fd, 0) + mm.seek(int(offset)) + read_data_stream = mm.read(4) + result = struct.unpack('I', read_data_stream) + except Exception: + status = False + return status, result + + def run_command(self, cmd): + status = True + result = "" + try: + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + except Exception: + status = False + return status, result + + def run_interactive_command(self, cmd): + try: + os.system(cmd) + except Exception: + return False + return True + + def read_txt_file(self, file_path): + try: + with open(file_path, 'r') as fd: + data = fd.read() + return data.strip() + except IOError: + pass + return None + + def write_txt_file(self, file_path, value): + try: + with open(file_path, 'w') as fd: + fd.write(str(value)) + except IOError: + return False + return True + + def ipmi_raw(self, netfn, cmd): + status = True + result = "" + try: + cmd = "ipmitool raw {} {}".format(str(netfn), str(cmd)) + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result + + def ipmi_fru_id(self, id, key=None): + status = True + result = "" + try: + cmd = "ipmitool fru print {}".format(str( + id)) if not key else "ipmitool fru print {0} | grep '{1}' ".format(str(id), str(key)) + + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result + + def ipmi_set_ss_thres(self, id, threshold_key, value): + status = True + result = "" + try: + cmd = "ipmitool sensor thresh '{}' {} {}".format(str(id), str(threshold_key), str(value)) + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result diff --git a/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/platform.py b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/platform.py new file mode 100644 index 00000000000..2f2c2a447fc --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/platform.py @@ -0,0 +1,21 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the platform information +# +############################################################################# + +try: + from sonic_platform_base.platform_base import PlatformBase + from sonic_platform.chassis import Chassis +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Platform(PlatformBase): + """Platform-specific Platform class""" + + def __init__(self): + PlatformBase.__init__(self) + self._chassis = Chassis() diff --git a/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/psu.py b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/psu.py new file mode 100644 index 00000000000..d78d29d598d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/psu.py @@ -0,0 +1,263 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the PSUs status which are available in the platform +# +############################################################################# + +#import sonic_platform + +try: + from sonic_platform_base.psu_base import PsuBase + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +HWMON_I2C_PATH ="/sys/devices/platform/as7535_32xb_psu/psu{}" + +PSU_NAME_LIST = ["PSU-1", "PSU-2"] +PSU_NUM_FAN = [1, 1] + +class Psu(PsuBase): + """Platform-specific Psu class""" + + def __init__(self, psu_index=0): + PsuBase.__init__(self) + self._api_helper = APIHelper() + self.index = psu_index + self.hwmon_path = HWMON_I2C_PATH.format(self.index+1) + self.__initialize_fan() + + def __initialize_fan(self): + from sonic_platform.fan import Fan + for fan_index in range(0, PSU_NUM_FAN[self.index]): + fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index) + self._fan_list.append(fan) + + def get_voltage(self): + """ + Retrieves current PSU voltage output + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + vout_path = "{}{}".format(self.hwmon_path, '_vout') + vout_val=self._api_helper.read_txt_file(vout_path) + if vout_val is not None: + return float(vout_val)/1000 + else: + return 0 + + def get_current(self): + """ + Retrieves present electric current supplied by PSU + Returns: + A float number, the electric current in amperes, e.g 15.4 + """ + iout_path = "{}{}".format(self.hwmon_path, '_iout') + val=self._api_helper.read_txt_file(iout_path) + if val is not None: + return float(val)/1000 + else: + return 0 + + def get_power(self): + """ + Retrieves current energy supplied by PSU + Returns: + A float number, the power in watts, e.g. 302.6 + """ + pout_path = "{}{}".format(self.hwmon_path, '_pout') + val=self._api_helper.read_txt_file(pout_path) + if val is not None: + return float(val)/1000 + else: + return 0 + + 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): + """ + Sets the state of the PSU status LED + Args: + color: A string representing the color with which to set the PSU status LED + Note: Only support green and off + Returns: + bool: True if status LED state is set successfully, False if not + """ + + return False #Controlled by HW + + def get_status_led(self): + """ + Gets the state of the fan status LED + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + status=self.get_presence() + if status is None: + return self.STATUS_LED_COLOR_OFF + + return { + 1: self.STATUS_LED_COLOR_GREEN, + 0: self.STATUS_LED_COLOR_RED + }.get(status, self.STATUS_LED_COLOR_OFF) + + def get_temperature(self): + """ + Retrieves current temperature reading from PSU + Returns: + A float number of current temperature in Celsius up to nearest thousandth + of one degree Celsius, e.g. 30.125 + """ + temp_path = "{}{}".format(self.hwmon_path, '_temp1_input') + val=self._api_helper.read_txt_file(temp_path) + if val is not None: + return float(val)/1000 + else: + return 0 + + def get_temperature_high_threshold(self): + """ + Retrieves the high threshold temperature of PSU + Returns: + A float number, the high threshold temperature of PSU in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + temp_path = "{}{}".format(self.hwmon_path, '_temp1_input_max') + val=self._api_helper.read_txt_file(temp_path) + if val is not None: + return float(val)/1000 + else: + return 0 + + def get_voltage_high_threshold(self): + """ + Retrieves the high threshold PSU voltage output + Returns: + A float number, the high threshold output voltage in volts, + e.g. 12.1 + """ + vout_path = "{}{}".format(self.hwmon_path, '_vout_max') + vout_val=self._api_helper.read_txt_file(vout_path) + if vout_val is not None: + return float(vout_val)/1000 + else: + return 0 + + def get_voltage_low_threshold(self): + """ + Retrieves the low threshold PSU voltage output + Returns: + A float number, the low threshold output voltage in volts, + e.g. 12.1 + """ + vout_path = "{}{}".format(self.hwmon_path, '_vout_min') + vout_val=self._api_helper.read_txt_file(vout_path) + if vout_val is not None: + return float(vout_val)/1000 + else: + return 0 + + def get_maximum_supplied_power(self): + """ + Retrieves the maximum supplied power by PSU + Returns: + A float number, the maximum power output in Watts. + e.g. 1200.1 + """ + pout_path = "{}{}".format(self.hwmon_path, '_pout_max') + val=self._api_helper.read_txt_file(pout_path) + if val is not None: + return float(val)/1000 + else: + return 0 + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return PSU_NAME_LIST[self.index] + + def get_presence(self): + """ + Retrieves the presence of the PSU + Returns: + bool: True if PSU is present, False if not + """ + presence_path="{}{}".format(self.hwmon_path, '_present') + val=self._api_helper.read_txt_file(presence_path) + if val is not None: + return int(val, 10) == 1 + else: + return 0 + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + power_path="{}{}".format(self.hwmon_path, '_power_good') + val=self._api_helper.read_txt_file(power_path) + if val is not None: + return int(val, 10) == 1 + else: + return False + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + model_path="{}{}".format(self.hwmon_path, '_model') + model=self._api_helper.read_txt_file(model_path) + + if model is None: + return "N/A" + return model + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + serial_path="{}{}".format(self.hwmon_path, '_serial') + serial=self._api_helper.read_txt_file(serial_path) + + if serial is None: + return "N/A" + return serial + + def is_replaceable(self): + """ + Indicate whether Chassis is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return self.index+1 diff --git a/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/sfp.py new file mode 100644 index 00000000000..6cd1364ceba --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/sfp.py @@ -0,0 +1,2253 @@ +############################################################################# +# Accton +# +# Sfp contains an implementation of SONiC Platform Base API and +# provides the sfp device status which are available in the platform +# +############################################################################# + +import os +import sys +import time +import struct + +from ctypes import create_string_buffer + +try: + from sonic_platform_base.sfp_base import SfpBase + from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId + from sonic_platform_base.sonic_sfp.sff8472 import sff8472Dom + from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId + from sonic_platform_base.sonic_sfp.sff8436 import sff8436Dom + from sonic_platform_base.sonic_sfp.inf8628 import inf8628InterfaceId + from sonic_platform_base.sonic_sfp.qsfp_dd import qsfp_dd_InterfaceId + from sonic_platform_base.sonic_sfp.qsfp_dd import qsfp_dd_Dom + from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +#Edge-core definitions +CPLD1_I2C_PATH = "/sys/bus/i2c/devices/12-0061/" + +# 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_EXT_SPECIFICATION_COMPLIANCE_OFFSET = 64 +XCVR_EXT_SPECIFICATION_COMPLIANCE_WIDTH = 1 +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 = 2 + +XCVR_INTERFACE_DATA_START = 0 +XCVR_INTERFACE_DATA_SIZE = 92 + +QSFP_DOM_BULK_DATA_START = 22 +QSFP_DOM_BULK_DATA_SIZE = 36 +SFP_DOM_BULK_DATA_START = 96 +SFP_DOM_BULK_DATA_SIZE = 10 +QSFP_DD_DOM_BULK_DATA_START = 14 +QSFP_DD_DOM_BULK_DATA_SIZE = 4 + +# 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 for values in QSFP_DD info eeprom +QSFP_DD_TYPE_OFFSET = 0 +QSFP_DD_VENDOR_NAME_OFFSET = 1 +QSFP_DD_VENDOR_PN_OFFSET = 20 +QSFP_DD_VENDOR_SN_OFFSET = 38 +QSFP_DD_VENDOR_OUI_OFFSET = 17 + +# definitions of the offset and width for values in XCVR_QSFP_DD info eeprom +XCVR_EXT_TYPE_OFFSET_QSFP_DD = 72 +XCVR_EXT_TYPE_WIDTH_QSFP_DD = 2 +XCVR_CONNECTOR_OFFSET_QSFP_DD = 75 +XCVR_CONNECTOR_WIDTH_QSFP_DD = 1 +XCVR_CABLE_LENGTH_OFFSET_QSFP_DD = 74 +XCVR_CABLE_LENGTH_WIDTH_QSFP_DD = 1 +XCVR_HW_REV_OFFSET_QSFP_DD = 36 +XCVR_HW_REV_WIDTH_QSFP_DD = 2 +XCVR_VENDOR_DATE_OFFSET_QSFP_DD = 54 +XCVR_VENDOR_DATE_WIDTH_QSFP_DD = 8 +XCVR_DOM_CAPABILITY_OFFSET_QSFP_DD = 2 +XCVR_DOM_CAPABILITY_WIDTH_QSFP_DD = 1 +XCVR_MEDIA_TYPE_OFFSET_QSFP_DD = 85 +XCVR_MEDIA_TYPE_WIDTH_QSFP_DD = 1 +XCVR_FIRST_APPLICATION_LIST_OFFSET_QSFP_DD = 86 +XCVR_FIRST_APPLICATION_LIST_WIDTH_QSFP_DD = 32 +XCVR_SECOND_APPLICATION_LIST_OFFSET_QSFP_DD = 351 +XCVR_SECOND_APPLICATION_LIST_WIDTH_QSFP_DD = 28 + +# Offset for values in QSFP 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_VERSION_COMPLIANCE_OFFSET = 1 +QSFP_VERSION_COMPLIANCE_WIDTH = 2 +QSFP_CHANNL_MON_OFFSET = 34 +QSFP_CHANNL_MON_WIDTH = 16 +QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH = 24 +QSFP_CHANNL_DISABLE_STATUS_OFFSET = 86 +QSFP_CHANNL_DISABLE_STATUS_WIDTH = 1 +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_CONTROL_OFFSET = 86 +QSFP_CONTROL_WIDTH = 8 +QSFP_MODULE_MONITOR_OFFSET = 0 +QSFP_MODULE_MONITOR_WIDTH = 9 +QSFP_POWEROVERRIDE_OFFSET = 93 +QSFP_POWEROVERRIDE_WIDTH = 1 +QSFP_POWEROVERRIDE_BIT = 0 +QSFP_POWERSET_BIT = 1 +QSFP_OPTION_VALUE_OFFSET = 192 +QSFP_OPTION_VALUE_WIDTH = 4 +QSFP_MODULE_UPPER_PAGE3_START = 384 +QSFP_MODULE_THRESHOLD_OFFSET = 128 +QSFP_MODULE_THRESHOLD_WIDTH = 24 +QSFP_CHANNL_THRESHOLD_OFFSET = 176 +QSFP_CHANNL_THRESHOLD_WIDTH = 24 + +SFP_MODULE_ADDRA2_OFFSET = 256 +SFP_MODULE_THRESHOLD_OFFSET = 0 +SFP_MODULE_THRESHOLD_WIDTH = 56 +SFP_CHANNL_THRESHOLD_OFFSET = 112 +SFP_CHANNL_THRESHOLD_WIDTH = 2 + +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_CHANNL_STATUS_OFFSET = 110 +SFP_CHANNL_STATUS_WIDTH = 1 + +QSFP_DD_TEMPE_OFFSET = 14 +QSFP_DD_TEMPE_WIDTH = 2 +QSFP_DD_VOLT_OFFSET = 16 +QSFP_DD_VOLT_WIDTH = 2 +QSFP_DD_TX_BIAS_OFFSET = 42 +QSFP_DD_TX_BIAS_WIDTH = 16 +QSFP_DD_RX_POWER_OFFSET = 58 +QSFP_DD_RX_POWER_WIDTH = 16 +QSFP_DD_TX_POWER_OFFSET = 26 +QSFP_DD_TX_POWER_WIDTH = 16 +QSFP_DD_CHANNL_MON_OFFSET = 154 +QSFP_DD_CHANNL_MON_WIDTH = 48 +QSFP_DD_CHANNL_DISABLE_STATUS_OFFSET = 86 +QSFP_DD_CHANNL_DISABLE_STATUS_WIDTH = 1 +QSFP_DD_CHANNL_RX_LOS_STATUS_OFFSET = 19 +QSFP_DD_CHANNL_RX_LOS_STATUS_WIDTH = 1 +QSFP_DD_CHANNL_TX_FAULT_STATUS_OFFSET = 7 +QSFP_DD_CHANNL_TX_FAULT_STATUS_WIDTH = 1 +QSFP_DD_MODULE_THRESHOLD_OFFSET = 0 +QSFP_DD_MODULE_THRESHOLD_WIDTH = 72 +QSFP_DD_CHANNL_STATUS_OFFSET = 26 +QSFP_DD_CHANNL_STATUS_WIDTH = 1 + + +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' +) + +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', 'type_abbrv_name' +] + +qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)', + 'Length OM2(m)', 'Length OM1(m)', + 'Length Cable Assembly(m)') + +dom_info_dict_keys = [ + 'rx_los', 'tx_fault', 'reset_status', 'lp_mode', + 'tx_disable', 'tx_disable_channel', 'temperature', 'voltage', + 'rx1power', 'rx2power', 'rx3power', 'rx4power', + 'rx5power', 'rx6power', 'rx7power', 'rx8power', + 'tx1bias', 'tx2bias', 'tx3bias', 'tx4bias', + 'tx5bias', 'tx6bias', 'tx7bias', 'tx8bias', + 'tx1power', 'tx2power', 'tx3power', 'tx4power', + 'tx5power', 'tx6power', 'tx7power', 'tx8power'] + +threshold_dict_keys = [ + 'temphighalarm', 'temphighwarning', + 'templowalarm', 'templowwarning', + 'vcchighalarm', 'vcchighwarning', + 'vcclowalarm', 'vcclowwarning', + 'rxpowerhighalarm', 'rxpowerhighwarning', + 'rxpowerlowalarm', 'rxpowerlowwarning', + 'txpowerhighalarm', 'txpowerhighwarning', + 'txpowerlowalarm', 'txpowerlowwarning', + 'txbiashighalarm', 'txbiashighwarning', + 'txbiaslowalarm', 'txbiaslowwarning'] + +SFP_TYPE_CODE_LIST = [ + '03' # SFP/SFP+/SFP28 +] +QSFP_TYPE_CODE_LIST = [ + '0d', # QSFP+ or later + '11' # QSFP28 or later +] +QSFP_DD_TYPE_CODE_LIST = [ + '18' # QSFP-DD Double Density 8X Pluggable Transceiver +] + +SFP_TYPE = "SFP" +QSFP_TYPE = "QSFP" +OSFP_TYPE = "OSFP" +QSFP_DD_TYPE = "QSFP_DD" + +NULL_VAL = 'N/A' + +I2C_EEPROM_PATH = '/sys/bus/i2c/devices/{0}-0050/eeprom' + + +class Sfp(SfpBase): + """Platform-specific Sfp class""" + HOST_CHK_CMD = "docker > /dev/null 2>&1" + PLATFORM = "x86_64-accton_as7535_32xb-r0" + HWSKU = "Accton-AS7535-32XB" + + # Path to sysfs + PLATFORM_ROOT_PATH = "/usr/share/sonic/device" + PMON_HWSKU_PATH = "/usr/share/sonic/hwsku" + + _port_to_i2c_mapping = { + 1: [25], + 2: [26], + 3: [27], + 4: [28], + 5: [29], + 6: [30], + 7: [31], + 8: [32], + 9: [33], + 10: [34], + 11: [35], + 12: [36], + 13: [37], + 14: [38], + 15: [39], + 16: [40], + 17: [41], + 18: [42], + 19: [43], + 20: [44], + 21: [45], + 22: [46], + 23: [47], + 24: [48], + 25: [49], + 26: [50], + 27: [23], + 28: [21], + 29: [24], + 30: [22], + } + + def __init__(self, sfp_index=0, sfp_name=None): + + self._index = sfp_index + self.port_num = self._index + 1 + self._api_helper = APIHelper() + self._name = sfp_name + self._eeprom_path = self._get_eeprom_path() + + self._dom_capability_detect() + SfpBase.__init__(self) + + def __write_txt_file(self, file_path, value): + try: + reg_file = open(file_path, "w") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + reg_file.write(str(value)) + reg_file.close() + + return True + + def __is_host(self): + return os.system(self.HOST_CHK_CMD) == 0 + + def __get_path_to_port_config_file(self): + platform_path = "/".join([self.PLATFORM_ROOT_PATH, self.PLATFORM]) + hwsku_path = "/".join([platform_path, self.HWSKU] + ) if self.__is_host() else self.PMON_HWSKU_PATH + return "/".join([hwsku_path, "port_config.ini"]) + + def _convert_string_to_num(self, value_str): + if "-inf" in value_str: + return 'N/A' + elif "Unknown" in value_str: + return 'N/A' + elif 'dBm' in value_str: + t_str = value_str.rstrip('dBm') + return float(t_str) + elif 'mA' in value_str: + t_str = value_str.rstrip('mA') + return float(t_str) + elif 'C' in value_str: + t_str = value_str.rstrip('C') + return float(t_str) + elif 'Volts' in value_str: + t_str = value_str.rstrip('Volts') + return float(t_str) + else: + return 'N/A' + + def _read_eeprom_specific_bytes(self, offset, num_bytes): + sysfs_sfp_i2c_client_eeprom_path = self._get_eeprom_path() + eeprom_raw = [] + try: + eeprom = open( + sysfs_sfp_i2c_client_eeprom_path, + mode="rb", buffering=0) + except IOError: + return None + + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + + try: + eeprom.seek(offset) + raw = eeprom.read(num_bytes) + except IOError: + eeprom.close() + return None + + try: + if isinstance(raw, str): + for n in range(0, num_bytes): + eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) + else: + for n in range(0, num_bytes): + eeprom_raw[n] = hex(raw[n])[2:].zfill(2) + + except BaseException: + eeprom.close() + return None + + eeprom.close() + return eeprom_raw + + def _detect_sfp_type(self): + sfp_type = QSFP_TYPE + eeprom_raw = [] + eeprom_raw = self._read_eeprom_specific_bytes( + XCVR_TYPE_OFFSET, XCVR_TYPE_WIDTH) + if eeprom_raw: + if eeprom_raw[0] in SFP_TYPE_CODE_LIST: + self.sfp_type = SFP_TYPE + elif eeprom_raw[0] in QSFP_TYPE_CODE_LIST: + self.sfp_type = QSFP_TYPE + elif eeprom_raw[0] in QSFP_DD_TYPE_CODE_LIST: + self.sfp_type = QSFP_DD_TYPE + else: + self.sfp_type = sfp_type + else: + self.sfp_type = sfp_type + + def _get_eeprom_path(self): + port_eeprom_path = I2C_EEPROM_PATH.format(self._port_to_i2c_mapping[self.port_num][0]) + return port_eeprom_path + + def _dom_capability_detect(self): + self._detect_sfp_type() + + if not self.get_presence(): + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + return + + if self.sfp_type == QSFP_TYPE: + self.calibration = 1 + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + self.dom_supported = False + offset = 128 + + # QSFP capability byte parse, + # through this byte can know whether it support tx_power or not. + # TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436, + # need to add more code for determining the capability and version compliance + # in SFF-8636 dom capability definitions evolving with the versions. + + qsfp_dom_capability_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_DOM_CAPABILITY_OFFSET), + XCVR_DOM_CAPABILITY_WIDTH) + if qsfp_dom_capability_raw is not None: + qsfp_version_compliance_raw = self._read_eeprom_specific_bytes( + QSFP_VERSION_COMPLIANCE_OFFSET, + QSFP_VERSION_COMPLIANCE_WIDTH) + qsfp_version_compliance = int( + qsfp_version_compliance_raw[0], 16) + dom_capability = sfpi_obj.parse_dom_capability( + qsfp_dom_capability_raw, 0) + if qsfp_version_compliance >= 0x08: + self.dom_temp_supported = dom_capability['data']['Temp_support']['value'] == 'On' + self.dom_volt_supported = dom_capability['data']['Voltage_support']['value'] == 'On' + self.dom_rx_power_supported = dom_capability['data']['Rx_power_support']['value'] == 'On' + self.dom_tx_power_supported = dom_capability['data']['Tx_power_support']['value'] == 'On' + else: + self.dom_temp_supported = True + self.dom_volt_supported = True + self.dom_rx_power_supported = dom_capability['data']['Rx_power_support']['value'] == 'On' + self.dom_tx_power_supported = True + + self.dom_supported = True + self.calibration = 1 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + qsfp_option_value_raw = self._read_eeprom_specific_bytes( + QSFP_OPTION_VALUE_OFFSET, QSFP_OPTION_VALUE_WIDTH) + if qsfp_option_value_raw is not None: + optional_capability = sfpd_obj.parse_option_params( + qsfp_option_value_raw, 0) + self.dom_tx_disable_supported = optional_capability[ + 'data']['TxDisable']['value'] == 'On' + dom_status_indicator = sfpd_obj.parse_dom_status_indicator( + qsfp_version_compliance_raw, 1) + self.qsfp_page3_available = dom_status_indicator['data']['FlatMem']['value'] == 'Off' + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + self.qsfp_page3_available = False + + elif self.sfp_type == QSFP_DD_TYPE: + sfpi_obj = qsfp_dd_InterfaceId() + if sfpi_obj is None: + self.dom_supported = False + + offset = 0 + # two types of QSFP-DD cable types supported: Copper and Optical. + qsfp_dom_capability_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_DOM_CAPABILITY_OFFSET_QSFP_DD), XCVR_DOM_CAPABILITY_WIDTH_QSFP_DD) + if qsfp_dom_capability_raw is not None: + self.dom_temp_supported = True + self.dom_volt_supported = True + dom_capability = sfpi_obj.parse_dom_capability( + qsfp_dom_capability_raw, 0) + if dom_capability['data']['Flat_MEM']['value'] == 'Off': + self.dom_supported = True + self.second_application_list = True + self.dom_rx_power_supported = True + self.dom_tx_power_supported = True + self.dom_tx_bias_power_supported = True + self.dom_thresholds_supported = True + # currently set to False becasue Page 11h is not supported by FW + self.dom_rx_tx_power_bias_supported = False + else: + self.dom_supported = False + self.second_application_list = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.dom_tx_bias_power_supported = False + self.dom_thresholds_supported = False + self.dom_rx_tx_power_bias_supported = False + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.dom_tx_bias_power_supported = False + self.dom_thresholds_supported = False + self.dom_rx_tx_power_bias_supported = False + + elif self.sfp_type == SFP_TYPE: + sfpi_obj = sff8472InterfaceId() + if sfpi_obj is None: + return None + sfp_dom_capability_raw = self._read_eeprom_specific_bytes( + XCVR_DOM_CAPABILITY_OFFSET, XCVR_DOM_CAPABILITY_WIDTH) + if sfp_dom_capability_raw is not None: + sfp_dom_capability = int(sfp_dom_capability_raw[0], 16) + self.dom_supported = (sfp_dom_capability & 0x40 != 0) + if self.dom_supported: + self.dom_temp_supported = True + self.dom_volt_supported = True + self.dom_rx_power_supported = True + self.dom_tx_power_supported = True + if sfp_dom_capability & 0x20 != 0: + self.calibration = 1 + elif sfp_dom_capability & 0x10 != 0: + self.calibration = 2 + else: + self.calibration = 0 + else: + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + self.dom_tx_disable_supported = ( + int(sfp_dom_capability_raw[1], 16) & 0x40 != 0) + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + + 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 + ================================================================================ + """ + + transceiver_info_dict = {} + compliance_code_dict = {} + transceiver_info_dict = dict.fromkeys( + info_dict_keys, NULL_VAL) + transceiver_info_dict["specification_compliance"] = '{}' + + # ToDo: OSFP tranceiver info parsing not fully supported. + # in inf8628.py lack of some memory map definition + # will be implemented when the inf8628 memory map ready + if self.sfp_type == OSFP_TYPE: + offset = 0 + vendor_rev_width = XCVR_HW_REV_WIDTH_OSFP + + sfpi_obj = inf8628InterfaceId() + if sfpi_obj is None: + return transceiver_info_dict + + sfp_type_raw = self._read_eeprom_specific_bytes( + (offset + OSFP_TYPE_OFFSET), XCVR_TYPE_WIDTH) + if sfp_type_raw is not None: + sfp_type_data = sfpi_obj.parse_sfp_type(sfp_type_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_name_raw = self._read_eeprom_specific_bytes( + (offset + OSFP_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH) + if sfp_vendor_name_raw is not None: + sfp_vendor_name_data = sfpi_obj.parse_vendor_name( + sfp_vendor_name_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_pn_raw = self._read_eeprom_specific_bytes( + (offset + OSFP_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH) + if sfp_vendor_pn_raw is not None: + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn( + sfp_vendor_pn_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_rev_raw = self._read_eeprom_specific_bytes( + (offset + OSFP_HW_REV_OFFSET), vendor_rev_width) + if sfp_vendor_rev_raw is not None: + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev( + sfp_vendor_rev_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_sn_raw = self._read_eeprom_specific_bytes( + (offset + OSFP_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH) + if sfp_vendor_sn_raw is not None: + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn( + sfp_vendor_sn_raw, 0) + else: + return transceiver_info_dict + + transceiver_info_dict['type'] = sfp_type_data['data']['type']['value'] + transceiver_info_dict['manufacturer'] = sfp_vendor_name_data['data']['Vendor Name']['value'] + transceiver_info_dict['model'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] + transceiver_info_dict['hardware_rev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] + transceiver_info_dict['serial'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] + + elif self.sfp_type == QSFP_TYPE: + offset = 128 + vendor_rev_width = XCVR_HW_REV_WIDTH_QSFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_QSFP + + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + + elif self.sfp_type == QSFP_DD_TYPE: + offset = 128 + + sfpi_obj = qsfp_dd_InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + + sfp_type_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_TYPE_OFFSET), XCVR_TYPE_WIDTH) + if sfp_type_raw is not None: + sfp_type_data = sfpi_obj.parse_sfp_type(sfp_type_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_name_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH) + if sfp_vendor_name_raw is not None: + sfp_vendor_name_data = sfpi_obj.parse_vendor_name( + sfp_vendor_name_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_pn_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH) + if sfp_vendor_pn_raw is not None: + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn( + sfp_vendor_pn_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_rev_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_HW_REV_OFFSET_QSFP_DD), XCVR_HW_REV_WIDTH_QSFP_DD) + if sfp_vendor_rev_raw is not None: + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev( + sfp_vendor_rev_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_sn_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH) + if sfp_vendor_sn_raw is not None: + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn( + sfp_vendor_sn_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_oui_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_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) + else: + return transceiver_info_dict + + sfp_vendor_date_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_VENDOR_DATE_OFFSET_QSFP_DD), XCVR_VENDOR_DATE_WIDTH_QSFP_DD) + if sfp_vendor_date_raw is not None: + sfp_vendor_date_data = sfpi_obj.parse_vendor_date( + sfp_vendor_date_raw, 0) + else: + return transceiver_info_dict + + sfp_connector_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_CONNECTOR_OFFSET_QSFP_DD), XCVR_CONNECTOR_WIDTH_QSFP_DD) + if sfp_connector_raw is not None: + sfp_connector_data = sfpi_obj.parse_connector( + sfp_connector_raw, 0) + else: + return transceiver_info_dict + + sfp_ext_identifier_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_EXT_TYPE_OFFSET_QSFP_DD), XCVR_EXT_TYPE_WIDTH_QSFP_DD) + if sfp_ext_identifier_raw is not None: + sfp_ext_identifier_data = sfpi_obj.parse_ext_iden( + sfp_ext_identifier_raw, 0) + else: + return transceiver_info_dict + + sfp_cable_len_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_CABLE_LENGTH_OFFSET_QSFP_DD), XCVR_CABLE_LENGTH_WIDTH_QSFP_DD) + if sfp_cable_len_raw is not None: + sfp_cable_len_data = sfpi_obj.parse_cable_len( + sfp_cable_len_raw, 0) + else: + return transceiver_info_dict + + sfp_media_type_raw = self._read_eeprom_specific_bytes( + XCVR_MEDIA_TYPE_OFFSET_QSFP_DD, XCVR_MEDIA_TYPE_WIDTH_QSFP_DD) + if sfp_media_type_raw is not None: + sfp_media_type_dict = sfpi_obj.parse_media_type( + sfp_media_type_raw, 0) + if sfp_media_type_dict is None: + return transceiver_info_dict + + host_media_list = "" + sfp_application_type_first_list = self._read_eeprom_specific_bytes( + (XCVR_FIRST_APPLICATION_LIST_OFFSET_QSFP_DD), XCVR_FIRST_APPLICATION_LIST_WIDTH_QSFP_DD) + if self.second_application_list: + possible_application_count = 15 + sfp_application_type_second_list = self._read_eeprom_specific_bytes( + (XCVR_SECOND_APPLICATION_LIST_OFFSET_QSFP_DD), XCVR_SECOND_APPLICATION_LIST_WIDTH_QSFP_DD) + if sfp_application_type_first_list is not None and sfp_application_type_second_list is not None: + sfp_application_type_list = sfp_application_type_first_list + \ + sfp_application_type_second_list + else: + return transceiver_info_dict + else: + possible_application_count = 8 + if sfp_application_type_first_list is not None: + sfp_application_type_list = sfp_application_type_first_list + else: + return transceiver_info_dict + + for i in range(0, possible_application_count): + if sfp_application_type_list[i * 4] == 'ff': + break + host_electrical, media_interface = sfpi_obj.parse_application( + sfp_media_type_dict, sfp_application_type_list[i * 4], sfp_application_type_list[i * 4 + 1]) + host_media_list = host_media_list + host_electrical + \ + ' - ' + media_interface + '\n\t\t\t\t ' + else: + return transceiver_info_dict + + transceiver_info_dict['type'] = str( + sfp_type_data['data']['type']['value']) + transceiver_info_dict['manufacturer'] = str( + sfp_vendor_name_data['data']['Vendor Name']['value']) + transceiver_info_dict['model'] = str( + sfp_vendor_pn_data['data']['Vendor PN']['value']) + transceiver_info_dict['hardware_rev'] = str( + sfp_vendor_rev_data['data']['Vendor Rev']['value']) + transceiver_info_dict['serial'] = str( + sfp_vendor_sn_data['data']['Vendor SN']['value']) + transceiver_info_dict['vendor_oui'] = str( + sfp_vendor_oui_data['data']['Vendor OUI']['value']) + transceiver_info_dict['vendor_date'] = str( + sfp_vendor_date_data['data']['VendorDataCode(YYYY-MM-DD Lot)']['value']) + transceiver_info_dict['connector'] = str( + sfp_connector_data['data']['Connector']['value']) + transceiver_info_dict['encoding'] = "Not supported for CMIS cables" + transceiver_info_dict['ext_identifier'] = str( + sfp_ext_identifier_data['data']['Extended Identifier']['value']) + transceiver_info_dict['ext_rateselect_compliance'] = "Not supported for CMIS cables" + transceiver_info_dict['specification_compliance'] = "Not supported for CMIS cables" + transceiver_info_dict['cable_type'] = "Length Cable Assembly(m)" + transceiver_info_dict['cable_length'] = str( + sfp_cable_len_data['data']['Length Cable Assembly(m)']['value']) + transceiver_info_dict['nominal_bit_rate'] = "Not supported for CMIS cables" + transceiver_info_dict['application_advertisement'] = host_media_list + + else: + offset = 0 + vendor_rev_width = XCVR_HW_REV_WIDTH_SFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_SFP + + sfpi_obj = sff8472InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + + if self.sfp_type != QSFP_DD_TYPE: + sfp_interface_bulk_raw = self._read_eeprom_specific_bytes( + offset + XCVR_INTERFACE_DATA_START, XCVR_INTERFACE_DATA_SIZE) + if sfp_interface_bulk_raw is None: + return transceiver_info_dict + + start = XCVR_INTFACE_BULK_OFFSET - XCVR_INTERFACE_DATA_START + end = start + interface_info_bulk_width + sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk( + sfp_interface_bulk_raw[start: end], 0) + + start = XCVR_VENDOR_NAME_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_NAME_WIDTH + sfp_vendor_name_data = sfpi_obj.parse_vendor_name( + sfp_interface_bulk_raw[start: end], 0) + + start = XCVR_VENDOR_PN_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_PN_WIDTH + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn( + sfp_interface_bulk_raw[start: end], 0) + + start = XCVR_HW_REV_OFFSET - XCVR_INTERFACE_DATA_START + end = start + vendor_rev_width + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev( + sfp_interface_bulk_raw[start: end], 0) + + start = XCVR_VENDOR_SN_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_SN_WIDTH + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn( + sfp_interface_bulk_raw[start: end], 0) + + start = XCVR_VENDOR_OUI_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_OUI_WIDTH + sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui( + sfp_interface_bulk_raw[start: end], 0) + + start = XCVR_VENDOR_DATE_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_DATE_WIDTH + sfp_vendor_date_data = sfpi_obj.parse_vendor_date( + sfp_interface_bulk_raw[start: end], 0) + + transceiver_info_dict['type'] = sfp_interface_bulk_data['data']['type']['value'] + transceiver_info_dict['manufacturer'] = sfp_vendor_name_data['data']['Vendor Name']['value'] + transceiver_info_dict['model'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] + transceiver_info_dict['hardware_rev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] + transceiver_info_dict['serial'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] + transceiver_info_dict['vendor_oui'] = sfp_vendor_oui_data['data']['Vendor OUI']['value'] + transceiver_info_dict['vendor_date'] = sfp_vendor_date_data[ + 'data']['VendorDataCode(YYYY-MM-DD Lot)']['value'] + transceiver_info_dict['connector'] = sfp_interface_bulk_data['data']['Connector']['value'] + transceiver_info_dict['encoding'] = sfp_interface_bulk_data['data']['EncodingCodes']['value'] + transceiver_info_dict['ext_identifier'] = sfp_interface_bulk_data['data']['Extended Identifier']['value'] + transceiver_info_dict['ext_rateselect_compliance'] = sfp_interface_bulk_data['data']['RateIdentifier']['value'] + + if self.sfp_type == QSFP_TYPE: + for key in qsfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_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'] + sfp_ext_specification_compliance_raw = self._read_eeprom_specific_bytes( + offset + XCVR_EXT_SPECIFICATION_COMPLIANCE_OFFSET, XCVR_EXT_SPECIFICATION_COMPLIANCE_WIDTH) + if sfp_ext_specification_compliance_raw is not None: + sfp_ext_specification_compliance_data = sfpi_obj.parse_ext_specification_compliance( + sfp_ext_specification_compliance_raw[0: 1], 0) + if sfp_ext_specification_compliance_data['data']['Extended Specification compliance']['value'] != "Unspecified": + compliance_code_dict['Extended Specification compliance'] = sfp_ext_specification_compliance_data[ + 'data']['Extended Specification compliance']['value'] + transceiver_info_dict['specification_compliance'] = str( + compliance_code_dict) + transceiver_info_dict['nominal_bit_rate'] = str( + sfp_interface_bulk_data['data']['Nominal Bit Rate(100Mbs)']['value']) + else: + for key in sfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_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'] + transceiver_info_dict['specification_compliance'] = str( + compliance_code_dict) + + transceiver_info_dict['nominal_bit_rate'] = str( + sfp_interface_bulk_data['data']['NominalSignallingRate(UnitsOf100Mbd)']['value']) + + return transceiver_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. + ======================================================================== + """ + transceiver_dom_info_dict = dict.fromkeys( + dom_info_dict_keys, NULL_VAL) + + if self.sfp_type == OSFP_TYPE: + pass + + elif self.sfp_type == QSFP_TYPE: + if not self.dom_supported: + return transceiver_dom_info_dict + + offset = 0 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return transceiver_dom_info_dict + + dom_data_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DOM_BULK_DATA_START), QSFP_DOM_BULK_DATA_SIZE) + if dom_data_raw is None: + return transceiver_dom_info_dict + + if self.dom_temp_supported: + start = QSFP_TEMPE_OFFSET - QSFP_DOM_BULK_DATA_START + end = start + QSFP_TEMPE_WIDTH + dom_temperature_data = sfpd_obj.parse_temperature( + dom_data_raw[start: end], 0) + temp = dom_temperature_data['data']['Temperature']['value'] + if temp is not None: + transceiver_dom_info_dict['temperature'] = temp + + if self.dom_volt_supported: + start = QSFP_VOLT_OFFSET - QSFP_DOM_BULK_DATA_START + end = start + QSFP_VOLT_WIDTH + dom_voltage_data = sfpd_obj.parse_voltage( + dom_data_raw[start: end], 0) + volt = dom_voltage_data['data']['Vcc']['value'] + if volt is not None: + transceiver_dom_info_dict['voltage'] = volt + + start = QSFP_CHANNL_MON_OFFSET - QSFP_DOM_BULK_DATA_START + end = start + QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power( + dom_data_raw[start: end], 0) + + if self.dom_tx_power_supported: + transceiver_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TX1Power']['value'] + transceiver_dom_info_dict['tx2power'] = dom_channel_monitor_data['data']['TX2Power']['value'] + transceiver_dom_info_dict['tx3power'] = dom_channel_monitor_data['data']['TX3Power']['value'] + transceiver_dom_info_dict['tx4power'] = dom_channel_monitor_data['data']['TX4Power']['value'] + + if self.dom_rx_power_supported: + transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RX1Power']['value'] + transceiver_dom_info_dict['rx2power'] = dom_channel_monitor_data['data']['RX2Power']['value'] + transceiver_dom_info_dict['rx3power'] = dom_channel_monitor_data['data']['RX3Power']['value'] + transceiver_dom_info_dict['rx4power'] = dom_channel_monitor_data['data']['RX4Power']['value'] + + transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TX1Bias']['value'] + transceiver_dom_info_dict['tx2bias'] = dom_channel_monitor_data['data']['TX2Bias']['value'] + transceiver_dom_info_dict['tx3bias'] = dom_channel_monitor_data['data']['TX3Bias']['value'] + transceiver_dom_info_dict['tx4bias'] = dom_channel_monitor_data['data']['TX4Bias']['value'] + + elif self.sfp_type == QSFP_DD_TYPE: + + offset = 0 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return transceiver_dom_info_dict + + dom_data_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_DOM_BULK_DATA_START), QSFP_DD_DOM_BULK_DATA_SIZE) + if dom_data_raw is None: + return transceiver_dom_info_dict + + if self.dom_temp_supported: + start = QSFP_DD_TEMPE_OFFSET - QSFP_DD_DOM_BULK_DATA_START + end = start + QSFP_DD_TEMPE_WIDTH + dom_temperature_data = sfpd_obj.parse_temperature( + dom_data_raw[start: end], 0) + temp = dom_temperature_data['data']['Temperature']['value'] + if temp is not None: + transceiver_dom_info_dict['temperature'] = temp + + if self.dom_volt_supported: + start = QSFP_DD_VOLT_OFFSET - QSFP_DD_DOM_BULK_DATA_START + end = start + QSFP_DD_VOLT_WIDTH + dom_voltage_data = sfpd_obj.parse_voltage( + dom_data_raw[start: end], 0) + volt = dom_voltage_data['data']['Vcc']['value'] + if volt is not None: + transceiver_dom_info_dict['voltage'] = volt + + if self.dom_rx_tx_power_bias_supported: + # page 11h + dom_data_raw = self._read_eeprom_specific_bytes( + (QSFP_DD_CHANNL_MON_OFFSET), QSFP_DD_CHANNL_MON_WIDTH) + if dom_data_raw is None: + return transceiver_dom_info_dict + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( + dom_data_raw, 0) + + if self.dom_tx_power_supported: + transceiver_dom_info_dict['tx1power'] = str( + dom_channel_monitor_data['data']['TX1Power']['value']) + transceiver_dom_info_dict['tx2power'] = str( + dom_channel_monitor_data['data']['TX2Power']['value']) + transceiver_dom_info_dict['tx3power'] = str( + dom_channel_monitor_data['data']['TX3Power']['value']) + transceiver_dom_info_dict['tx4power'] = str( + dom_channel_monitor_data['data']['TX4Power']['value']) + transceiver_dom_info_dict['tx5power'] = str( + dom_channel_monitor_data['data']['TX5Power']['value']) + transceiver_dom_info_dict['tx6power'] = str( + dom_channel_monitor_data['data']['TX6Power']['value']) + transceiver_dom_info_dict['tx7power'] = str( + dom_channel_monitor_data['data']['TX7Power']['value']) + transceiver_dom_info_dict['tx8power'] = str( + dom_channel_monitor_data['data']['TX8Power']['value']) + + if self.dom_rx_power_supported: + transceiver_dom_info_dict['rx1power'] = str( + dom_channel_monitor_data['data']['RX1Power']['value']) + transceiver_dom_info_dict['rx2power'] = str( + dom_channel_monitor_data['data']['RX2Power']['value']) + transceiver_dom_info_dict['rx3power'] = str( + dom_channel_monitor_data['data']['RX3Power']['value']) + transceiver_dom_info_dict['rx4power'] = str( + dom_channel_monitor_data['data']['RX4Power']['value']) + transceiver_dom_info_dict['rx5power'] = str( + dom_channel_monitor_data['data']['RX5Power']['value']) + transceiver_dom_info_dict['rx6power'] = str( + dom_channel_monitor_data['data']['RX6Power']['value']) + transceiver_dom_info_dict['rx7power'] = str( + dom_channel_monitor_data['data']['RX7Power']['value']) + transceiver_dom_info_dict['rx8power'] = str( + dom_channel_monitor_data['data']['RX8Power']['value']) + + if self.dom_tx_bias_power_supported: + transceiver_dom_info_dict['tx1bias'] = str( + dom_channel_monitor_data['data']['TX1Bias']['value']) + transceiver_dom_info_dict['tx2bias'] = str( + dom_channel_monitor_data['data']['TX2Bias']['value']) + transceiver_dom_info_dict['tx3bias'] = str( + dom_channel_monitor_data['data']['TX3Bias']['value']) + transceiver_dom_info_dict['tx4bias'] = str( + dom_channel_monitor_data['data']['TX4Bias']['value']) + transceiver_dom_info_dict['tx5bias'] = str( + dom_channel_monitor_data['data']['TX5Bias']['value']) + transceiver_dom_info_dict['tx6bias'] = str( + dom_channel_monitor_data['data']['TX6Bias']['value']) + transceiver_dom_info_dict['tx7bias'] = str( + dom_channel_monitor_data['data']['TX7Bias']['value']) + transceiver_dom_info_dict['tx8bias'] = str( + dom_channel_monitor_data['data']['TX8Bias']['value']) + + return transceiver_dom_info_dict + + else: + if not self.dom_supported: + return transceiver_dom_info_dict + + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return transceiver_dom_info_dict + sfpd_obj._calibration_type = self.calibration + + dom_data_raw = self._read_eeprom_specific_bytes( + (offset + SFP_DOM_BULK_DATA_START), SFP_DOM_BULK_DATA_SIZE) + if dom_data_raw is None: + return transceiver_dom_info_dict + + start = SFP_TEMPE_OFFSET - SFP_DOM_BULK_DATA_START + end = start + SFP_TEMPE_WIDTH + dom_temperature_data = sfpd_obj.parse_temperature( + dom_data_raw[start: end], 0) + + start = SFP_VOLT_OFFSET - SFP_DOM_BULK_DATA_START + end = start + SFP_VOLT_WIDTH + dom_voltage_data = sfpd_obj.parse_voltage( + dom_data_raw[start: end], 0) + + start = SFP_CHANNL_MON_OFFSET - SFP_DOM_BULK_DATA_START + end = start + SFP_CHANNL_MON_WIDTH + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( + dom_data_raw[start: end], 0) + + transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RXPower']['value'] + transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TXBias']['value'] + transceiver_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TXPower']['value'] + + transceiver_dom_info_dict['lp_mode'] = self.get_lpmode() + transceiver_dom_info_dict['reset_status'] = self.get_reset_status() + transceiver_dom_info_dict['tx_disable'] = self.get_tx_disable() + transceiver_dom_info_dict['tx_disabled_channel'] = self.get_tx_disable_channel( + ) + + for key in transceiver_dom_info_dict: + val = transceiver_dom_info_dict[key] + transceiver_dom_info_dict[key] = self._convert_string_to_num( + val) if type(val) is str else val + + return transceiver_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. + ======================================================================== + """ + transceiver_dom_threshold_info_dict = dict.fromkeys( + threshold_dict_keys, NULL_VAL) + + if self.sfp_type == OSFP_TYPE: + pass + + elif self.sfp_type == QSFP_TYPE: + if not self.dom_supported or not self.qsfp_page3_available: + return transceiver_dom_threshold_info_dict + + # Dom Threshold data starts from offset 384 + # Revert offset back to 0 once data is retrieved + offset = QSFP_MODULE_UPPER_PAGE3_START + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return transceiver_dom_threshold_info_dict + + dom_module_threshold_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_MODULE_THRESHOLD_OFFSET), QSFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is None: + return transceiver_dom_threshold_info_dict + + dom_module_threshold_data = sfpd_obj.parse_module_threshold_values( + dom_module_threshold_raw, 0) + + dom_channel_threshold_raw = self._read_eeprom_specific_bytes((offset + QSFP_CHANNL_THRESHOLD_OFFSET), + QSFP_CHANNL_THRESHOLD_WIDTH) + if dom_channel_threshold_raw is None: + return transceiver_dom_threshold_info_dict + dom_channel_threshold_data = sfpd_obj.parse_channel_threshold_values( + dom_channel_threshold_raw, 0) + + # Threshold Data + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VccHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VccHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VccLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VccLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_channel_threshold_data['data']['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_channel_threshold_data['data']['RxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_channel_threshold_data['data']['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_channel_threshold_data['data']['RxPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_channel_threshold_data['data']['TxBiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_channel_threshold_data['data']['TxBiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_channel_threshold_data['data']['TxBiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_channel_threshold_data['data']['TxBiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_channel_threshold_data['data']['TxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_channel_threshold_data['data']['TxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_channel_threshold_data['data']['TxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_channel_threshold_data['data']['TxPowerLowWarning']['value'] + + elif self.sfp_type == QSFP_DD_TYPE: + if not self.dom_supported: + return transceiver_dom_threshold_info_dict + + if not self.dom_thresholds_supported: + return transceiver_dom_threshold_info_dict + + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return transceiver_dom_threshold_info_dict + + # page 02 + offset = 384 + dom_module_threshold_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_MODULE_THRESHOLD_OFFSET), QSFP_DD_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is None: + return transceiver_dom_threshold_info_dict + + dom_module_threshold_data = sfpd_obj.parse_module_threshold_values( + dom_module_threshold_raw, 0) + + # Threshold Data + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VccHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VccHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VccLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VccLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RxPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['TxBiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['TxBiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['TxBiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['TxBiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TxPowerLowWarning']['value'] + + else: + offset = SFP_MODULE_ADDRA2_OFFSET + + if not self.dom_supported: + return transceiver_dom_threshold_info_dict + + sfpd_obj = sff8472Dom(None, self.calibration) + if sfpd_obj is None: + return transceiver_dom_threshold_info_dict + + 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) + else: + return transceiver_dom_threshold_info_dict + + # Threshold Data + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VoltageHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VoltageLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data[ + 'data']['VoltageHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VoltageLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['BiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['BiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['BiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['BiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TXPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RXPowerLowWarning']['value'] + + for key in transceiver_dom_threshold_info_dict: + transceiver_dom_threshold_info_dict[key] = self._convert_string_to_num( + transceiver_dom_threshold_info_dict[key]) + + return transceiver_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 + """ + if not self.get_presence(): + return False + + if 27 <= self.port_num <= 30: + reset_path = "{}{}{}".format(CPLD1_I2C_PATH, '/module_reset_', self.port_num) + else: + return False + + val = self._api_helper.read_txt_file(reset_path) + if val is not None: + return int(val, 10)==1 + else: + return False + + 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_list = [] + + if self.sfp_type == OSFP_TYPE: + return None + elif self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_RX_LOS_STATUS_OFFSET), + QSFP_CHANNL_RX_LOS_STATUS_WIDTH) + 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) + else: + return [False] * 4 + + elif self.sfp_type == QSFP_DD_TYPE: + # page 11h + if self.dom_rx_tx_power_bias_supported: + offset = 128 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_CHANNL_RX_LOS_STATUS_OFFSET), + QSFP_DD_CHANNL_RX_LOS_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 8) + 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_list.append(rx_los_data & 0x10 != 0) + rx_los_list.append(rx_los_data & 0x20 != 0) + rx_los_list.append(rx_los_data & 0x40 != 0) + rx_los_list.append(rx_los_data & 0x80 != 0) + else: + return [False] * 8 + else: # SFP_TYPE + offset = 256 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH) + 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 & 0x02 != 0) + else: + return [False] + return rx_los_list + + 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_list = [] + + if self.sfp_type == OSFP_TYPE: + return None + elif self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_TX_FAULT_STATUS_OFFSET), + QSFP_CHANNL_TX_FAULT_STATUS_WIDTH) + 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) + else: + return [False] * 4 + elif self.sfp_type == QSFP_DD_TYPE: + # page 11h + if self.dom_rx_tx_power_bias_supported: + offset = 128 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_CHANNL_TX_FAULT_STATUS_OFFSET), + QSFP_DD_CHANNL_TX_FAULT_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_fault_data = int(dom_channel_monitor_raw[0], 8) + 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_list.append(tx_fault_data & 0x10 != 0) + tx_fault_list.append(tx_fault_data & 0x20 != 0) + tx_fault_list.append(tx_fault_data & 0x40 != 0) + tx_fault_list.append(tx_fault_data & 0x80 != 0) + else: + return [False] * 8 + else: # SFP_TYPE + offset = 256 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH) + 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 & 0x04 != 0) + else: + return None + return tx_fault_list + + def get_tx_disable(self): + """ + Retrieves the tx_disable status of this SFP + Returns: + A list of boolean values, representing the TX disable status + of each available channel, value is True if SFP channel + is TX disabled, False if not. + E.g., for a tranceiver with four channels: [False, False, True, False] + """ + tx_disable_list = [] + if self.sfp_type == OSFP_TYPE: + return None + elif self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_DISABLE_STATUS_OFFSET), + QSFP_CHANNL_DISABLE_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0x01 != 0) + tx_disable_list.append(tx_disable_data & 0x02 != 0) + tx_disable_list.append(tx_disable_data & 0x04 != 0) + tx_disable_list.append(tx_disable_data & 0x08 != 0) + else: + return [False] * 4 + + elif self.sfp_type == QSFP_DD_TYPE: + if self.dom_rx_tx_power_bias_supported: + offset = 128 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_CHANNL_DISABLE_STATUS_OFFSET), + QSFP_DD_CHANNL_DISABLE_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0x01 != 0) + tx_disable_list.append(tx_disable_data & 0x02 != 0) + tx_disable_list.append(tx_disable_data & 0x04 != 0) + tx_disable_list.append(tx_disable_data & 0x08 != 0) + tx_disable_list.append(tx_disable_data & 0x10 != 0) + tx_disable_list.append(tx_disable_data & 0x20 != 0) + tx_disable_list.append(tx_disable_data & 0x40 != 0) + tx_disable_list.append(tx_disable_data & 0x80 != 0) + else: + return [False] * 8 + else: # SFP_TYPE + offset = 256 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0xC0 != 0) + else: + return [False] + return tx_disable_list + + 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. + """ + 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 + + 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 + """ + if self.sfp_type == SFP_TYPE: + # SFP doesn't support this feature + return False + else: + try: + eeprom = None + + if not self.get_presence(): + return False + # Write to eeprom + port_eeprom_path = I2C_EEPROM_PATH.format(self._port_to_i2c_mapping[self.port_num][0]) + + eeprom = open(port_eeprom_path, "rb") + eeprom.seek(QSFP_POWEROVERRIDE_OFFSET) + 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: + # 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 + return False + 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) + + def get_power_set(self): + + if self.sfp_type == SFP_TYPE: + # SFP doesn't support this feature + return False + else: + power_set = False + + 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_set = ( + 'On' == dom_control_data['data']['PowerSet']['value']) + + return power_set + + 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 + """ + if self.sfp_type == QSFP_TYPE: + offset = 0 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return False + + dom_control_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_CONTROL_OFFSET), QSFP_CONTROL_WIDTH) + if dom_control_raw is not None: + dom_control_data = sfpd_obj.parse_control_bytes( + dom_control_raw, 0) + return ('On' == dom_control_data['data']['PowerOverride']['value']) + else: + return False + else: + return NotImplementedError + + def get_temperature(self): + """ + Retrieves the temperature of this SFP + Returns: + An integer number of current temperature in Celsius + """ + default = 0.0 + if not self.dom_supported: + return default + + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return default + + if self.dom_temp_supported: + 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) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + + elif self.sfp_type == QSFP_DD_TYPE: + offset = 0 + + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if self.dom_temp_supported: + dom_temperature_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_TEMPE_OFFSET), QSFP_DD_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature( + dom_temperature_raw, 0) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + + else: + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + sfpd_obj._calibration_type = 1 + + 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) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + + return default + + def get_voltage(self): + """ + Retrieves the supply voltage of this SFP + Returns: + An integer number of supply voltage in mV + """ + default = 0.0 + + if not self.dom_supported: + return default + + if self.sfp_type == QSFP_TYPE: + offset = 0 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return default + + if self.dom_volt_supported: + 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) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + + if self.sfp_type == QSFP_DD_TYPE: + offset = 128 + + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if self.dom_volt_supported: + dom_voltage_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_VOLT_OFFSET), QSFP_DD_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage( + dom_voltage_raw, 0) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + + else: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + + sfpd_obj._calibration_type = self.calibration + + 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) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + + return default + + 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'] + """ + tx_bias_list = [] + if self.sfp_type == QSFP_TYPE: + offset = 0 + default = [0.0] * 4 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return default + + 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) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX1Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX2Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX3Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX4Bias']['value'])) + else: + return default + + elif self.sfp_type == QSFP_DD_TYPE: + default = [0.0] * 8 + # page 11h + if self.dom_rx_tx_power_bias_supported: + offset = 128 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if dom_tx_bias_power_supported: + dom_tx_bias_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_TX_BIAS_OFFSET), QSFP_DD_TX_BIAS_WIDTH) + if dom_tx_bias_raw is not None: + dom_tx_bias_data = sfpd_obj.parse_dom_tx_bias( + dom_tx_bias_raw, 0) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX1Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX2Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX3Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX4Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX5Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX6Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX7Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX8Bias']['value'])) + else: + return default + else: + return default + + else: + offset = 256 + default = [0.0] + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + sfpd_obj._calibration_type = self.calibration + + if self.dom_supported: + 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) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TXBias']['value'])) + else: + return default + else: + return default + + return tx_bias_list + + 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'] + """ + rx_power_list = [] + if self.sfp_type == OSFP_TYPE: + # OSFP not supported on our platform yet. + return None + + elif self.sfp_type == QSFP_TYPE: + offset = 0 + default = [0.0] * 4 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return default + + if self.dom_rx_power_supported: + 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) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX1Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX2Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX3Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX4Power']['value'])) + else: + return default + else: + return default + + elif self.sfp_type == QSFP_DD_TYPE: + default = [0.0] * 8 + # page 11 + if self.dom_rx_tx_power_bias_supported: + offset = 128 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if self.dom_rx_power_supported: + dom_rx_power_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_RX_POWER_OFFSET), QSFP_DD_RX_POWER_WIDTH) + if dom_rx_power_raw is not None: + dom_rx_power_data = sfpd_obj.parse_dom_rx_power( + dom_rx_power_raw, 0) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX1Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX2Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX3Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX4Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX5Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX6Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX7Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX8Power']['value'])) + else: + return default + else: + return default + + else: + offset = 256 + default = [0.0] + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + + if self.dom_supported: + sfpd_obj._calibration_type = self.calibration + + 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) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RXPower']['value'])) + else: + return default + else: + return default + return rx_power_list + + 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'] + """ + tx_power_list = [] + if self.sfp_type == OSFP_TYPE: + # OSFP not supported on our platform yet. + return tx_power_list + + elif self.sfp_type == QSFP_TYPE: + offset = 0 + default = [0.0] * 4 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return tx_power_list + + if self.dom_tx_power_supported: + 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) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX1Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX2Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX3Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX4Power']['value'])) + else: + return default + else: + return default + + elif self.sfp_type == QSFP_DD_TYPE: + default = [0.0] * 8 + + # page 11 + if self.dom_rx_tx_power_bias_supported: + offset = 128 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if self.dom_tx_power_supported: + dom_tx_power_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_TX_POWER_OFFSET), + QSFP_DD_TX_POWER_WIDTH) + if dom_tx_power_raw is not None: + dom_tx_power_data = sfpd_obj.parse_dom_tx_power( + dom_tx_power_raw, 0) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX1Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX2Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX3Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX4Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX5Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX6Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX7Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX8Power']['value'])) + else: + return default + else: + return default + + else: + offset = 256 + default = [0.0] + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + + if self.dom_supported: + sfpd_obj._calibration_type = self.calibration + + 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) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TXPower']['value'])) + else: + return default + else: + return default + return tx_power_list + + def reset(self): + """ + Reset SFP and return all user module settings to their default srate. + Returns: + A boolean, True if successful, False if not + """ + # Check for invalid port_num + + if not self.get_presence(): + return False + + if 27 <= self.port_num <= 30: + reset_path = "{}{}{}".format(CPLD1_I2C_PATH, '/module_reset_', self.port_num) + else: + return False + + ret = self._api_helper.write_txt_file(reset_path, 1) #sysfs 1: enable reset + if ret is not True: + return ret + + time.sleep(0.2) + ret = self._api_helper.write_txt_file(reset_path, 0) #sysfs 1: disable reset + time.sleep(0.2) + + return ret + + 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 + """ + if self.sfp_type == QSFP_TYPE: + sysfsfile_eeprom = None + try: + tx_disable_value = 0xf if tx_disable else 0x0 + # Write to eeprom + sysfsfile_eeprom = open(self._eeprom_path, "r+b") + sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) + sysfsfile_eeprom.write(struct.pack('B', tx_disable_value)) + except IOError: + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + elif self.sfp_type == SFP_TYPE: + disable_path = "{}{}{}".format(CPLD1_I2C_PATH, '/module_tx_disable_', self.port_num) + tx_disable_value = 1 if tx_disable else 0 + ret = self._api_helper.write_txt_file(disable_path, tx_disable_value) #sysfs 1: disable tx + if ret is not True: + return ret + + return False + + 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 + """ + if self.sfp_type == QSFP_TYPE: + sysfsfile_eeprom = None + try: + current_state = self.get_tx_disable_channel() + tx_disable_value = (current_state | channel) if \ + disable else (current_state & (~channel)) + + # Write to eeprom + sysfsfile_eeprom = open(self._eeprom_path, "r+b") + sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) + sysfsfile_eeprom.write(struct.pack('B', tx_disable_value)) + except IOError: + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + + return False + + 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 + """ + if self.sfp_type == SFP_TYPE: + return False # SFP doesn't support this feature + else: + if not self.get_presence(): + return False + + if lpmode: + self.set_power_override(True, True) + else: + self.set_power_override(True, False) + + return True + + 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 + """ + if self.sfp_type == SFP_TYPE: + return False # SFP doesn't support this feature + else: + if not self.get_presence(): + return False + try: + power_override_bit = (1 << 0) if power_override else 0 + power_set_bit = (1 << 1) if power_set else (1 << 3) + + buffer = create_string_buffer(1) + if sys.version_info[0] >= 3: + buffer[0] = (power_override_bit | power_set_bit) + else: + buffer[0] = chr(power_override_bit | power_set_bit) + # Write to eeprom + port_eeprom_path = I2C_EEPROM_PATH.format(self._port_to_i2c_mapping[self.port_num][0]) + with open(port_eeprom_path, "r+b") as fd: + fd.seek(QSFP_POWEROVERRIDE_OFFSET) + fd.write(buffer[0]) + time.sleep(0.01) + except Exception as e: + print ('Error: unable to open file: ', str(e)) + return False + return True + + ############################################################## + ###################### Device methods ######################## + ############################################################## + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + sfputil_helper = SfpUtilHelper() + sfputil_helper.read_porttab_mappings( + self.__get_path_to_port_config_file()) + name = sfputil_helper.logical[self._index] or "Unknown" + return name + + def get_presence(self): + """ + Retrieves the presence of the device + Returns: + bool: True if device is present, False if not + """ + if 1 <= self.port_num <= 30: + present_path = "{}{}{}".format(CPLD1_I2C_PATH, '/module_present_', self.port_num) + else: + return False + + val=self._api_helper.read_txt_file(present_path) + if val is not None: + return int(val, 10)==1 + else: + return False + + + 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() + return transceiver_dom_info_dict.get("model", "N/A") + + 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() + return transceiver_dom_info_dict.get("serial", "N/A") + + 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 not self.get_reset_status() + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return self.port_num + + def is_replaceable(self): + """ + Retrieves if replaceable + Returns: + A boolean value, True if replaceable + """ + return True diff --git a/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/thermal.py b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/thermal.py new file mode 100644 index 00000000000..fac07b78e25 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform/thermal.py @@ -0,0 +1,152 @@ +############################################################################# +# Edgecore +# +# Thermal contains an implementation of SONiC Platform Base API and +# provides the thermal device status which are available in the platform +# +############################################################################# + +import os +import os.path +import glob + +try: + from sonic_platform_base.thermal_base import ThermalBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Thermal(ThermalBase): + """Platform-specific Thermal class""" + + THERMAL_NAME_LIST = [] + SYSFS_PATH = "/sys/devices/platform/as7535_32xb_thermal/" + + def __init__(self, thermal_index=0): + self.index = thermal_index + # Add thermal name + self.THERMAL_NAME_LIST.append("Temp sensor 1") + self.THERMAL_NAME_LIST.append("Temp sensor 2") + self.THERMAL_NAME_LIST.append("Temp sensor 3") + self.THERMAL_NAME_LIST.append("Temp sensor 4") + self.THERMAL_NAME_LIST.append("Temp sensor 5") + self.THERMAL_NAME_LIST.append("Temp sensor 6") + + self.hwmon_path = self.SYSFS_PATH + self.ss_key = self.THERMAL_NAME_LIST[self.index] + self.ss_index = self.index + 1 + + def __read_txt_file(self, file_path): + for filename in glob.glob(file_path): + try: + with open(filename, 'r') as fd: + data =fd.readline().rstrip() + return data + except IOError as e: + pass + + return None + + def __get_temp(self, temp_file): + temp_file_path = os.path.join(self.hwmon_path, temp_file) + raw_temp = self.__read_txt_file(temp_file_path) + if raw_temp is not None: + return float(raw_temp)/1000 + else: + return 0 + + + def __set_threshold(self, file_name, temperature): + temp_file_path = os.path.join(self.hwmon_path, file_name) + for filename in glob.glob(temp_file_path): + try: + with open(filename, 'w') as fd: + fd.write(str(temperature)) + return True + except IOError as e: + print("IOError") + return False + + def get_temperature(self): + """ + Retrieves current temperature reading from thermal + Returns: + A float number of current temperature in Celsius up to nearest thousandth + of one degree Celsius, e.g. 30.125 + """ + temp_file = "temp{}_input".format(self.ss_index) + return self.__get_temp(temp_file) + + def get_high_threshold(self): + """ + Retrieves the high threshold temperature of thermal + Returns: + A float number, the high threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + temp_file = "temp{}_max".format(self.ss_index) + return self.__get_temp(temp_file) + + def set_high_threshold(self, temperature): + """ + Sets the high threshold temperature of thermal + Args : + temperature: A float number up to nearest thousandth of one degree Celsius, + e.g. 30.125 + Returns: + A boolean, True if threshold is set successfully, False if not + """ + temp_file = "temp{}_max".format(self.ss_index) + temperature = int(temperature / 1) + self.__set_threshold(temp_file, temperature) + + return True + + def get_name(self): + """ + Retrieves the name of the thermal device + Returns: + string: The name of the thermal device + """ + return self.THERMAL_NAME_LIST[self.index] + + def get_presence(self): + """ + Retrieves the presence of the Thermal + Returns: + bool: True if Thermal is present, False if not + """ + temp_file = "temp{}_input".format(self.ss_index) + temp_file_path = os.path.join(self.hwmon_path, temp_file) + raw_txt = self.__read_txt_file(temp_file_path) + if raw_txt is not None: + return True + else: + return False + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + + file_str = "temp{}_input".format(self.ss_index) + file_path = os.path.join(self.hwmon_path, file_str) + raw_txt = self.__read_txt_file(file_path) + if raw_txt is None: + return False + else: + return int(raw_txt) != 0 + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return self.index+1 diff --git a/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform_setup.py b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform_setup.py new file mode 100644 index 00000000000..22bd354ea68 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/sonic_platform_setup.py @@ -0,0 +1,25 @@ +from setuptools import setup + +setup( + name='sonic-platform', + version='1.0', + description='SONiC platform API implementation on Accton Platforms', + license='Apache 2.0', + author='SONiC Team', + author_email='linuxnetdev@microsoft.com', + url='https://github.com/Azure/sonic-buildimage', + packages=['sonic_platform'], + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Environment :: Plugins', + 'Intended Audience :: Developers', + 'Intended Audience :: Information Technology', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: Apache Software License', + 'Natural Language :: English', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: Python :: 3.7', + 'Topic :: Utilities', + ], + keywords='sonic SONiC platform PLATFORM', +) diff --git a/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/utils/accton_as7535_32xb_util.py b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/utils/accton_as7535_32xb_util.py new file mode 100755 index 00000000000..e92c483215f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7535-32xb/utils/accton_as7535_32xb_util.py @@ -0,0 +1,382 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2019 Accton Networks, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +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 + show : show all systen status + sff : dump SFP eeprom + set : change board setting with fan|led|sfp +""" + +import subprocess +import getopt +import sys +import logging +import time +import os + +PROJECT_NAME = 'as7535_32xb' +DEBUG = False +ARGS = [] +FORCE = 0 + +def main(): + global DEBUG + global ARGS + global FORCE + + if len(sys.argv) < 2: + return 0 + + (options, ARGS) = getopt.getopt(sys.argv[1:], 'hdf', + ['help','debug', 'force']) + if DEBUG == True: + print(options) + print(ARGS) + print(len(sys.argv)) + + for arg in ARGS: + if arg == 'install': + do_install() + elif arg == 'clean': + do_uninstall() + elif arg == 'api': + do_sonic_platform_install() + elif arg == 'api_clean': + do_sonic_platform_clean() + return 0 + + +def log_os_system(cmd, show): + logging.info('Run :' + cmd) + status, output = subprocess.getstatusoutput(cmd) + if status: + logging.info('Failed :' + cmd) + if show: + print('Failed :' + cmd) + return (status, output) + + +def driver_check(): + ret, lsmod = log_os_system("ls /sys/module/*accton*", 0) + logging.info('mods:'+lsmod) + if ret : + return False + else : + return True + +ipmi_ko = [ +'modprobe ipmi_msghandler', +'modprobe ipmi_ssif', +'modprobe ipmi_si', +'modprobe ipmi_devintf', +] + +ATTEMPTS = 5 + +def init_ipmi_dev_intf(): + attempts = ATTEMPTS + interval = 3 + + while attempts: + for i in range(0, len(ipmi_ko)): + subprocess.getstatusoutput(ipmi_ko[i]) + + if os.path.exists('/dev/ipmi0') or os.path.exists('/dev/ipmidev/0'): + return (0, (ATTEMPTS - attempts) * interval) + + for i in reversed(range(0, len(ipmi_ko))): + rm = ipmi_ko[i].replace("modprobe", "modprobe -rq") + subprocess.getstatusoutput(rm) + + attempts -= 1 + time.sleep(interval) + + return (1, ATTEMPTS * interval) + +def init_ipmi_oem_cmd(): + attempts = ATTEMPTS + interval = 3 + + while attempts: + status, output = subprocess.getstatusoutput('ipmitool raw 0x34 0x95') + if status: + attempts -= 1 + time.sleep(interval) + continue + + return (0, (ATTEMPTS - attempts) * interval) + + return (1, ATTEMPTS * interval) + +def init_ipmi(): + attempts = ATTEMPTS + interval = 60 + + while attempts: + attempts -= 1 + + (status, elapsed_dev) = init_ipmi_dev_intf() + if status: + time.sleep(interval - elapsed_dev) + continue + + (status, elapsed_oem) = init_ipmi_oem_cmd() + if status: + time.sleep(interval - elapsed_dev - elapsed_oem) + continue + + print('IPMI dev interface is ready.') + return 0 + + print('Failed to initialize IPMI dev interface') + return 1 + +kos = [ +'depmod -ae', +'modprobe i2c_dev', +'modprobe i2c_mux_pca954x', +'modprobe x86-64-accton-as7535-32xb-cpld', +'modprobe x86-64-accton-as7535-32xb-fan', +'modprobe x86-64-accton-as7535-32xb-thermal', +'modprobe x86-64-accton-as7535-32xb-leds', +'modprobe x86-64-accton-as7535-32xb-psu', +'modprobe optoe'] + +def driver_install(): + global FORCE + + status = init_ipmi() + if status: + if FORCE == 0: + return status + + for i in range(0,len(kos)): + status, output = log_os_system(kos[i], 1) + if status: + if FORCE == 0: + return status + return 0 + +def driver_uninstall(): + global FORCE + for i in reversed(range(0,len(kos))): + rm = kos[i].replace("modprobe", "modprobe -rq") + rm = rm.replace("insmod", "rmmod") + lst = rm.split(" ") + if len(lst) > 3: + del(lst[3]) + rm = " ".join(lst) + status, output = log_os_system(rm, 1) + if status: + if FORCE == 0: + return status + return 0 + +i2c_prefix = '/sys/bus/i2c/devices/' +sfp_map = [25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 23, 21, 24, 22] + +mknod =[ +'echo 24c02 0x57 > /sys/bus/i2c/devices/i2c-0/new_device', +'echo pca9548 0x77 > /sys/bus/i2c/devices/i2c-0/new_device', +'echo pca9548 0x76 > /sys/bus/i2c/devices/i2c-1/new_device', +'echo pca9548 0x73 > /sys/bus/i2c/devices/i2c-9/new_device', +'echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-17/new_device', +'echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-18/new_device', +'echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-19/new_device', +'echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-20/new_device', +'echo as7535_32xb_fpga 0x60 > /sys/bus/i2c/devices/i2c-11/new_device', +'echo as7535_32xb_cpld1 0x61 > /sys/bus/i2c/devices/i2c-12/new_device', +] + +def device_install(): + global FORCE + + for i in range(0, len(mknod)): + (status, output) = log_os_system(mknod[i], 1) + if status: + print(output) + if FORCE == 0: + return status + + # for pca954x need times to built new i2c buses + if mknod[i].find('pca954') != -1: + time.sleep(2) + + # set all pca954x idle_disconnect + cmd = 'echo -2 | tee /sys/bus/i2c/drivers/pca954x/*-00*/idle_state' + status, output = log_os_system(cmd, 1) + if status: + print(output) + if FORCE == 0: + return status + + for i in range(27, 31): + status, output =log_os_system("echo 0 > /sys/bus/i2c/devices/12-0061/module_reset_"+str(i), 1) + if status: + print(output) + if FORCE == 0: + return status + + for i in range(0,len(sfp_map)): + status + output + + if (i <= 25): + status, output =log_os_system("echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/new_device", 1) + else: + status, output =log_os_system("echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/new_device", 1) + + if status: + print(output) + if FORCE == 0: + return status + + path = "/sys/bus/i2c/devices/{0}-0050/port_name" + status, output =log_os_system("echo port{0} > ".format(i+1)+path.format(sfp_map[i]), 1) + if status: + print(output) + if FORCE == 0: + return status + return + +def device_uninstall(): + global FORCE + + for i in range(0, len(sfp_map)): + target = '/sys/bus/i2c/devices/i2c-' + str(sfp_map[i]) \ + + '/delete_device' + (status, output) = log_os_system('echo 0x50 > ' + target, 1) + if status: + print(output) + if FORCE == 0: + return status + nodelist = mknod + + for i in range(len(nodelist)): + target = nodelist[-(i + 1)] + temp = target.split() + del temp[1] + temp[-1] = temp[-1].replace('new_device', 'delete_device') + (status, output) = log_os_system(' '.join(temp), 1) + if status: + print(output) + if FORCE == 0: + return status + + return + +PLATFORM_ROOT_PATH = '/usr/share/sonic/device' +PLATFORM_API2_WHL_FILE_PY3 ='sonic_platform-1.0-py3-none-any.whl' +def do_sonic_platform_install(): + device_path = "{}{}{}{}".format(PLATFORM_ROOT_PATH, '/x86_64-accton_', PROJECT_NAME, '-r0') + SONIC_PLATFORM_BSP_WHL_PKG_PY3 = "/".join([device_path, PLATFORM_API2_WHL_FILE_PY3]) + + #Check API2.0 on py whl file + status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0) + if status: + if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_PY3): + status, output = log_os_system("pip3 install "+ SONIC_PLATFORM_BSP_WHL_PKG_PY3, 1) + if status: + print("Error: Failed to install {}".format(PLATFORM_API2_WHL_FILE_PY3)) + return status + else: + print("Successfully installed {} package".format(PLATFORM_API2_WHL_FILE_PY3)) + else: + print('{} is not found'.format(PLATFORM_API2_WHL_FILE_PY3)) + else: + print('{} has installed'.format(PLATFORM_API2_WHL_FILE_PY3)) + +def do_sonic_platform_clean(): + status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0) + if status: + print('{} does not install, not need to uninstall'.format(PLATFORM_API2_WHL_FILE_PY3)) + + else: + status, output = log_os_system("pip3 uninstall sonic-platform -y", 0) + if status: + print('Error: Failed to uninstall {}'.format(PLATFORM_API2_WHL_FILE_PY3)) + return status + else: + print('{} is uninstalled'.format(PLATFORM_API2_WHL_FILE_PY3)) + + return + +def do_install(): + print('Checking system....') + if driver_check() is False: + print('No driver, installing....') + status = driver_install() + if status: + if FORCE == 0: + return status + else: + print(PROJECT_NAME.upper() + ' drivers detected....') + + if not device_exist(): + print('No device, installing....') + status = device_install() + if status: + if FORCE == 0: + return status + else: + print(PROJECT_NAME.upper() + ' devices detected....') + + do_sonic_platform_install() + + return + +def do_uninstall(): + print('Checking system....') + if not device_exist(): + print(PROJECT_NAME.upper() + ' has no device installed....') + else: + print('Removing device....') + status = device_uninstall() + if status and FORCE == 0: + return status + + if driver_check() is False: + print(PROJECT_NAME.upper() + ' has no driver installed....') + else: + print('Removing installed driver....') + status = driver_uninstall() + if status and FORCE == 0: + return status + + do_sonic_platform_clean() + + return None + +def device_exist(): + ret1 = log_os_system('ls ' + i2c_prefix + '*0077', 0) + ret2 = log_os_system('ls ' + i2c_prefix + 'i2c-2', 0) + return not (ret1[0] or ret2[0]) + + +if __name__ == '__main__': + main() diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/modules/accton_as7712_32x_fan.c b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/modules/accton_as7712_32x_fan.c index 73dd36c2883..a5bb839927f 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/modules/accton_as7712_32x_fan.c +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/modules/accton_as7712_32x_fan.c @@ -55,6 +55,7 @@ static ssize_t get_sys_temp(struct device *dev, struct device_attribute *da, cha */ static const u8 fan_reg[] = { 0x0F, /* fan 1-6 present status */ + 0x10, /* fan 1-6 direction(0:B2F 1:F2B) */ 0x11, /* fan PWM(for all fan) */ 0x12, /* front fan 1 speed(rpm) */ 0x13, /* front fan 2 speed(rpm) */ @@ -93,6 +94,7 @@ enum fan_id { enum sysfs_fan_attributes { FAN_PRESENT_REG, + FAN_DIRECTION_REG, FAN_DUTY_CYCLE_PERCENTAGE, /* Only one CPLD register to control duty cycle for all fans */ FAN1_FRONT_SPEED_RPM, FAN2_FRONT_SPEED_RPM, @@ -106,6 +108,12 @@ enum sysfs_fan_attributes { FAN4_REAR_SPEED_RPM, FAN5_REAR_SPEED_RPM, FAN6_REAR_SPEED_RPM, + FAN1_DIRECTION, + FAN2_DIRECTION, + FAN3_DIRECTION, + FAN4_DIRECTION, + FAN5_DIRECTION, + FAN6_DIRECTION, FAN1_PRESENT, FAN2_PRESENT, FAN3_PRESENT, @@ -182,6 +190,13 @@ DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(3); DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(4); DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(5); DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(6); +/* 6 fan direction attribute in this platform */ +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(1); +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(2); +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(3); +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(4); +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(5); +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(6); /* 1 fan duty cycle attribute in this platform */ DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR(1); /* System temperature for fancontrol */ @@ -207,6 +222,12 @@ static struct attribute *as7712_32x_fan_attributes[] = { DECLARE_FAN_PRESENT_ATTR(4), DECLARE_FAN_PRESENT_ATTR(5), DECLARE_FAN_PRESENT_ATTR(6), + DECLARE_FAN_DIRECTION_ATTR(1), + DECLARE_FAN_DIRECTION_ATTR(2), + DECLARE_FAN_DIRECTION_ATTR(3), + DECLARE_FAN_DIRECTION_ATTR(4), + DECLARE_FAN_DIRECTION_ATTR(5), + DECLARE_FAN_DIRECTION_ATTR(6), DECLARE_FAN_DUTY_CYCLE_ATTR(1), DECLARE_FAN_SYSTEM_TEMP_ATTR(), NULL @@ -243,7 +264,14 @@ static u32 reg_val_to_speed_rpm(u8 reg_val) { return (u32)reg_val * FAN_REG_VAL_TO_SPEED_RPM_STEP; } +static u8 reg_val_to_direction(u8 reg_val, enum fan_id id) +{ + u8 mask = (1 << id); + + reg_val &= mask; + return reg_val ? 1 : 0; +} static u8 reg_val_to_is_present(u8 reg_val, enum fan_id id) { u8 mask = (1 << id); @@ -485,6 +513,16 @@ static ssize_t fan_show_value(struct device *dev, struct device_attribute *da, case FAN6_FAULT: ret = sprintf(buf, "%d\n", is_fan_fault(data, attr->index - FAN1_FAULT)); break; + case FAN1_DIRECTION: + case FAN2_DIRECTION: + case FAN3_DIRECTION: + case FAN4_DIRECTION: + case FAN5_DIRECTION: + case FAN6_DIRECTION: + ret = sprintf(buf, "%d\n", + reg_val_to_direction(data->reg_val[FAN_DIRECTION_REG], + attr->index - FAN1_DIRECTION)); + break; default: break; } diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/modules/accton_as7712_32x_psu.c b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/modules/accton_as7712_32x_psu.c index 233aef78e09..7c611015cf8 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/modules/accton_as7712_32x_psu.c +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/modules/accton_as7712_32x_psu.c @@ -34,8 +34,9 @@ #include #include +#define MAX_MODEL_NAME 16 static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf); -static ssize_t show_model_name(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_string(struct device *dev, struct device_attribute *da, char *buf); static int as7712_32x_psu_read_block(struct i2c_client *client, u8 command, u8 *data,int data_len); extern int accton_i2c_cpld_read(unsigned short cpld_addr, u8 reg); @@ -52,7 +53,7 @@ struct as7712_32x_psu_data { unsigned long last_updated; /* In jiffies */ u8 index; /* PSU index */ u8 status; /* Status(present/power_good) register read from CPLD */ - char model_name[9]; /* Model name, read from eeprom */ + char model_name[MAX_MODEL_NAME+1]; /* Model name, read from eeprom */ }; static struct as7712_32x_psu_data *as7712_32x_psu_update_device(struct device *dev); @@ -66,7 +67,7 @@ enum as7712_32x_psu_sysfs_attributes { /* sysfs attributes for hwmon */ static SENSOR_DEVICE_ATTR(psu_present, S_IRUGO, show_status, NULL, PSU_PRESENT); -static SENSOR_DEVICE_ATTR(psu_model_name, S_IRUGO, show_model_name,NULL, PSU_MODEL_NAME); +static SENSOR_DEVICE_ATTR(psu_model_name, S_IRUGO, show_string, NULL, PSU_MODEL_NAME); static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_status, NULL, PSU_POWER_GOOD); static struct attribute *as7712_32x_psu_attributes[] = { @@ -83,6 +84,10 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, struct as7712_32x_psu_data *data = as7712_32x_psu_update_device(dev); u8 status = 0; + if (!data->valid) { + return -EIO; + } + if (attr->index == PSU_PRESENT) { status = !(data->status >> (1-data->index) & 0x1); } @@ -93,12 +98,24 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, return sprintf(buf, "%d\n", status); } -static ssize_t show_model_name(struct device *dev, struct device_attribute *da, +static ssize_t show_string(struct device *dev, struct device_attribute *da, char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct as7712_32x_psu_data *data = as7712_32x_psu_update_device(dev); - - return sprintf(buf, "%s\n", data->model_name); + char *ptr = NULL; + + if (!data->valid) { + return -EIO; + } + + if (attr->index == PSU_MODEL_NAME) { + ptr = data->model_name; + } + else { + return -EIO; + } + return sprintf(buf, "%s\n", ptr); } static const struct attribute_group as7712_32x_psu_group = { @@ -219,6 +236,63 @@ static int as7712_32x_psu_read_block(struct i2c_client *client, u8 command, u8 * return result; } +enum psu_type { + PSU_TYPE_AC_110V, + PSU_TYPE_DC_48V, + PSU_TYPE_DC_12V, + PSU_TYPE_AC_ACBEL_FSF019, + PSU_TYPE_AC_ACBEL_FSF045 +}; + +struct model_name_info { + enum psu_type type; + u8 offset; + u8 length; + char* model_name; +}; + +struct model_name_info models[] = { + {PSU_TYPE_AC_110V, 0x20, 8, "YM-2651Y"}, + {PSU_TYPE_DC_48V, 0x20, 8, "YM-2651V"}, + {PSU_TYPE_DC_12V, 0x00, 11, "PSU-12V-750"}, + {PSU_TYPE_AC_ACBEL_FSF019, 0x15, 10, "FSF019-"}, + {PSU_TYPE_AC_ACBEL_FSF045, 0x15, 10, "FSF045-"} +}; + +static int as7712_32x_psu_model_name_get(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as7712_32x_psu_data *data = i2c_get_clientdata(client); + int i, status; + + for (i = 0; i < ARRAY_SIZE(models); i++) { + memset(data->model_name, 0, sizeof(data->model_name)); + + status = as7712_32x_psu_read_block(client, models[i].offset, + data->model_name, models[i].length); + if (status < 0) { + data->model_name[0] = '\0'; + dev_dbg(&client->dev, "unable to read model name from (0x%x) offset(0x%x)\n", + client->addr, models[i].offset); + return status; + } + else { + data->model_name[models[i].length] = '\0'; + } + + /* Determine if the model name is known, if not, read next index + */ + if (strncmp(data->model_name, models[i].model_name, strlen(models[i].model_name)) == 0) { + return 0; + } + else { + data->model_name[0] = '\0'; + } + } + + return -ENODATA; +} + static struct as7712_32x_psu_data *as7712_32x_psu_update_device(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); @@ -231,6 +305,7 @@ static struct as7712_32x_psu_data *as7712_32x_psu_update_device(struct device *d int status; int power_good = 0; + data->valid = 0; dev_dbg(&client->dev, "Starting as7712_32x update\n"); /* Read psu status */ @@ -238,6 +313,7 @@ static struct as7712_32x_psu_data *as7712_32x_psu_update_device(struct device *d if (status < 0) { dev_dbg(&client->dev, "cpld reg 0x60 err %d\n", status); + goto exit; } else { data->status = status; @@ -248,15 +324,8 @@ static struct as7712_32x_psu_data *as7712_32x_psu_update_device(struct device *d power_good = (data->status >> (3-data->index) & 0x1); if (power_good) { - status = as7712_32x_psu_read_block(client, 0x20, data->model_name, - ARRAY_SIZE(data->model_name)-1); - - if (status < 0) { - data->model_name[0] = '\0'; - dev_dbg(&client->dev, "unable to read model name from (0x%x)\n", client->addr); - } - else { - data->model_name[ARRAY_SIZE(data->model_name)-1] = '\0'; + if (as7712_32x_psu_model_name_get(dev) < 0) { + goto exit; } } @@ -264,6 +333,7 @@ static struct as7712_32x_psu_data *as7712_32x_psu_update_device(struct device *d data->valid = 1; } +exit: mutex_unlock(&data->update_lock); return data; diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/modules/leds-accton_as7712_32x.c b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/modules/leds-accton_as7712_32x.c index a3238d4b161..83a75a94f1f 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/modules/leds-accton_as7712_32x.c +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/modules/leds-accton_as7712_32x.c @@ -505,7 +505,7 @@ static struct led_classdev accton_as7712_32x_leds[] = { .brightness_set = accton_as7712_32x_led_diag_set, .brightness_get = accton_as7712_32x_led_diag_get, .flags = LED_CORE_SUSPENDRESUME, - .max_brightness = LED_MODE_RED, + .max_brightness = LED_MODE_GREEN, }, [LED_TYPE_LOC] = { .name = "accton_as7712_32x_led::loc", diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/service/as7712-pddf-platform-monitor.service b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/service/as7712-pddf-platform-monitor.service new file mode 100644 index 00000000000..d0bd9940a34 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/service/as7712-pddf-platform-monitor.service @@ -0,0 +1,16 @@ +[Unit] +Description=Accton AS7712 Platform Monitoring service +Before=pmon.service +After=pddf-platform-init.service +DefaultDependencies=no + +[Service] +ExecStart=/usr/local/bin/accton_as7712_pddf_monitor.py +KillSignal=SIGKILL +SuccessExitStatus=SIGKILL + +# Resource Limitations +LimitCORE=infinity + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/service/pddf-platform-init.service b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/service/pddf-platform-init.service new file mode 120000 index 00000000000..0fd9f25b6c5 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/service/pddf-platform-init.service @@ -0,0 +1 @@ +../../../../pddf/i2c/service/pddf-platform-init.service \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/__init__.py b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/__init__.py new file mode 100644 index 00000000000..f0201e71779 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/__init__.py @@ -0,0 +1,3 @@ +# All the derived classes for PDDF +__all__ = ["platform", "chassis", "sfp", "psu", "thermal"] +from . import platform diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/chassis.py new file mode 100644 index 00000000000..d2edce41166 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/chassis.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python + +############################################################################# +# PDDF +# Module contains an implementation of SONiC Chassis API +# +############################################################################# + +try: + import sys + from sonic_platform_pddf_base.pddf_chassis import PddfChassis + from .event import SfpEvent +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +NUM_COMPONENT = 4 + +class Chassis(PddfChassis): + """ + PDDF Platform-specific Chassis class + """ + + def __init__(self, pddf_data=None, pddf_plugin_data=None): + PddfChassis.__init__(self, pddf_data, pddf_plugin_data) + self.__initialize_components() + self._sfpevent = SfpEvent(self.get_all_sfps()) + + def __initialize_components(self): + from sonic_platform.component import Component + for index in range(NUM_COMPONENT): + component = Component(index) + self._component_list.append(component) + + # Provide the functions/variables below for which implementation is to be overwritten + def get_change_event(self, timeout=0): + return self._sfpevent.get_sfp_event(timeout) + + def get_sfp(self, index): + """ + Retrieves sfp represented by (1-based) index + + Args: + index: An integer, the index (1-based) of the sfp to retrieve. + The index should be the sequence of a physical port in a chassis, + starting from 1. + For example, 1 for Ethernet0, 2 for Ethernet4 and so on. + + Returns: + An object derived from SfpBase representing the specified sfp + """ + sfp = None + + try: + # The index will start from 1 + sfp = self._sfp_list[index-1] + except IndexError: + sys.stderr.write("SFP index {} out of range (1-{})\n".format( + index, len(self._sfp_list))) + return sfp diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/component.py b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/component.py new file mode 100644 index 00000000000..148584216fc --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/component.py @@ -0,0 +1,115 @@ +############################################################################# +# +# Component contains an implementation of SONiC Platform Base API and +# provides the components firmware management function +# +############################################################################# + +try: + import subprocess + from sonic_platform_base.component_base import ComponentBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +CPLD_ADDR_MAPPING = { + "CPLD1": ['4', '0x60'], + "CPLD2": ['5', '0x62'], + "CPLD3": ['6', '0x64'] +} +SYSFS_PATH = "/sys/bus/i2c/devices/" +BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version" +COMPONENT_LIST= [ + ("CPLD1", "CPLD 1"), + ("CPLD2", "CPLD 2"), + ("CPLD3", "CPLD 3"), + ("BIOS", "Basic Input/Output System") + +] + +class Component(ComponentBase): + """Platform-specific Component class""" + + DEVICE_TYPE = "component" + + def __init__(self, component_index=0): + self.index = component_index + self.name = self.get_name() + + def __run_command(self, command): + # Run bash command and print output to stdout + try: + process = subprocess.Popen( + shlex.split(command), stdout=subprocess.PIPE) + while True: + output = process.stdout.readline() + if output == '' and process.poll() is not None: + break + rc = process.poll() + if rc != 0: + return False + except Exception: + return False + return True + + def __get_bios_version(self): + # Retrieves the BIOS firmware version + try: + with open(BIOS_VERSION_PATH, 'r') as fd: + bios_version = fd.read() + return bios_version.strip() + except Exception as e: + return None + + def __get_cpld_version(self): + # Retrieves the CPLD firmware version + cpld_version = dict() + for cpld_name in CPLD_ADDR_MAPPING: + cmd = "i2cget -f -y {0} {1} 0x1".format(CPLD_ADDR_MAPPING[cpld_name][0], CPLD_ADDR_MAPPING[cpld_name][1]) + status, value = subprocess.getstatusoutput(cmd) + if not status: + cpld_version_raw = value.rstrip() + cpld_version[cpld_name] = "{}".format(int(cpld_version_raw,16)) + + return cpld_version + + def get_name(self): + """ + Retrieves the name of the component + Returns: + A string containing the name of the component + """ + return COMPONENT_LIST[self.index][0] + + def get_description(self): + """ + Retrieves the description of the component + Returns: + A string containing the description of the component + """ + return COMPONENT_LIST[self.index][1] + + def get_firmware_version(self): + """ + Retrieves the firmware version of module + Returns: + string: The firmware versions of the module + """ + fw_version = None + + if self.name == "BIOS": + fw_version = self.__get_bios_version() + elif "CPLD" in self.name: + cpld_version = self.__get_cpld_version() + fw_version = cpld_version.get(self.name) + + return fw_version + + def install_firmware(self, image_path): + """ + Install firmware to module + Args: + image_path: A string, path to firmware image + Returns: + A boolean, True if install successfully, False if not + """ + raise NotImplementedError diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/eeprom.py b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/eeprom.py new file mode 100644 index 00000000000..a87ecc9f6fe --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/eeprom.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python + +try: + from sonic_platform_pddf_base.pddf_eeprom import PddfEeprom +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Eeprom(PddfEeprom): + + def __init__(self, pddf_data=None, pddf_plugin_data=None): + PddfEeprom.__init__(self, pddf_data, pddf_plugin_data) + + # Provide the functions/variables below for which implementation is to be overwritten diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/event.py b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/event.py new file mode 100644 index 00000000000..d5dac6d7f7e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/event.py @@ -0,0 +1,60 @@ +try: + import time + from sonic_py_common.logger import Logger +except ImportError as e: + raise ImportError(repr(e) + " - required module not found") + +POLL_INTERVAL_IN_SEC = 1 + +class SfpEvent: + ''' Listen to insert/remove sfp events ''' + + def __init__(self, sfp_list): + self._sfp_list = sfp_list + self._logger = Logger() + self._sfp_change_event_data = {'present': 0} + + def get_presence_bitmap(self): + bitmap = 0 + for sfp in self._sfp_list: + modpres = sfp.get_presence() + i=sfp.get_position_in_parent() - 1 + if modpres: + bitmap = bitmap | (1 << i) + return bitmap + + def get_sfp_event(self, timeout=2000): + port_dict = {} + change_dict = {} + change_dict['sfp'] = port_dict + + if timeout < 1000: + cd_ms = 1000 + else: + cd_ms = timeout + + while cd_ms > 0: + bitmap = self.get_presence_bitmap() + changed_ports = self._sfp_change_event_data['present'] ^ bitmap + if changed_ports != 0: + break + time.sleep(POLL_INTERVAL_IN_SEC) + # timeout=0 means wait for event forever + if timeout != 0: + cd_ms = cd_ms - POLL_INTERVAL_IN_SEC * 1000 + + if changed_ports != 0: + for sfp in self._sfp_list: + i=sfp.get_position_in_parent() - 1 + if (changed_ports & (1 << i)): + if (bitmap & (1 << i)) == 0: + port_dict[i+1] = '0' + else: + port_dict[i+1] = '1' + + + # Update the cache dict + self._sfp_change_event_data['present'] = bitmap + return True, change_dict + else: + return True, change_dict diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/fan.py new file mode 100644 index 00000000000..34019ac9918 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/fan.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python + + +try: + from sonic_platform_pddf_base.pddf_fan import PddfFan +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Fan(PddfFan): + """PDDF Platform-Specific Fan class""" + + def __init__(self, tray_idx, fan_idx=0, pddf_data=None, pddf_plugin_data=None, is_psu_fan=False, psu_index=0): + # idx is 0-based + PddfFan.__init__(self, tray_idx, fan_idx, pddf_data, pddf_plugin_data, is_psu_fan, psu_index) + + # Provide the functions/variables below for which implementation is to be overwritten e.g. + #def get_name(self): + ## Since AS7712 has two fans in a tray, modifying this function to return proper name + #if self.is_psu_fan: + #return "PSU_FAN{}".format(self.fan_index) + #else: + #return "Fantray{}_{}".format(self.fantray_index, {1:'Front', 2:'Rear'}.get(self.fan_index,'none')) + diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/platform.py b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/platform.py new file mode 100644 index 00000000000..406b1179ae1 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/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/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/psu.py b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/psu.py new file mode 100644 index 00000000000..2450957e256 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/psu.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +# + + +try: + from sonic_platform_pddf_base.pddf_psu import PddfPsu +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + + +class Psu(PddfPsu): + """PDDF Platform-Specific PSU class""" + + PLATFORM_PSU_CAPACITY = 650 + + def __init__(self, index, pddf_data=None, pddf_plugin_data=None): + PddfPsu.__init__(self, index, pddf_data, pddf_plugin_data) + + # Provide the functions/variables below for which implementation is to be overwritten + def get_capacity(self): + """ + Gets the capacity (maximum output power) of the PSU in watts + + Returns: + An integer, the capacity of PSU + """ + return (self.PLATFORM_PSU_CAPACITY) + + def get_type(self): + """ + Gets the type of the PSU + + Returns: + A string, the type of PSU (AC/DC) + """ + ptype = "AC" + # Currently the platform supports only AC type of PSUs + try: + import sonic_platform.platform + ch=sonic_platform.platform.Platform().get_chassis() + e=ch.sys_eeprom.read_eeprom() + ret, prod_name = ch.sys_eeprom.get_tlv_field(e,0x21) + if ret: + prod_name = prod_name[2].decode('ascii') + #print "Product name is {}".format(prod_name) + if '48V' in prod_name: + ptype = 'DC' + except Exception as e: + print("Error while trying to read syseeprom to get PSU type - {}".format(repr(e))) + + return ptype diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/sfp.py new file mode 100644 index 00000000000..c9fb07d6364 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/sfp.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python + +try: + from sonic_platform_pddf_base.pddf_sfp import PddfSfp +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + + +class Sfp(PddfSfp): + """ + PDDF Platform-Specific Sfp class + """ + + def __init__(self, index, pddf_data=None, pddf_plugin_data=None): + PddfSfp.__init__(self, index, pddf_data, pddf_plugin_data) + + # Provide the functions/variables below for which implementation is to be overwritten + def get_position_in_parent(self): + """Retrieves 1-based relative physical position in parent device.""" + return self.port_index diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/thermal.py b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/thermal.py new file mode 100644 index 00000000000..5b829fc26ca --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/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/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/watchdog.py b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/watchdog.py new file mode 100644 index 00000000000..fe8554f6ec7 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/watchdog.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python + +############################################################################# +# +# Module contains an implementation of platform specific watchdog API's +# +############################################################################# + +try: + from sonic_platform_pddf_base.pddf_watchdog import PddfWatchdog +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Watchdog(PddfWatchdog): + """ + PDDF Platform-specific Chassis class + """ + + def __init__(self): + PddfWatchdog.__init__(self) + self.timeout = 180 + + # Provide the functions/variables below for which implementation is to be overwritten diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform_setup.py b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform_setup.py new file mode 100644 index 00000000000..59dad237f3b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform_setup.py @@ -0,0 +1,25 @@ +from setuptools import setup + +setup( + name='sonic-platform', + version='1.0', + description='SONiC platform API implementation on Accton Platforms using PDDF', + license='Apache 2.0', + author='SONiC Team', + author_email='linuxnetdev@microsoft.com', + url='https://github.com/Azure/sonic-buildimage', + packages=['sonic_platform'], + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Environment :: Plugins', + 'Intended Audience :: Developers', + 'Intended Audience :: Information Technology', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: Apache Software License', + 'Natural Language :: English', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: Python :: 3.7', + 'Topic :: Utilities', + ], + keywords='sonic SONiC platform PLATFORM', +) diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/utils/accton_as7712_pddf_monitor.py b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/utils/accton_as7712_pddf_monitor.py new file mode 100755 index 00000000000..34d74876d87 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/utils/accton_as7712_pddf_monitor.py @@ -0,0 +1,264 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2017 Accton Technology Corporation +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# ------------------------------------------------------------------ +# HISTORY: +# mm/dd/yyyy (A.D.) +# 11/13/2017: Polly Hsu, Create +# ------------------------------------------------------------------ + +try: + import sys + import getopt + import logging + import logging.config + import logging.handlers + import signal + import time # this is only being used as part of the example + import subprocess + from sonic_platform import platform +except ImportError as e: + raise ImportError('%s - required module not found' % str(e)) + +# Deafults +VERSION = '1.0' +FUNCTION_NAME = 'accton_as7712_monitor' +DUTY_MAX = 100 + +fan_state = [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2] # init state=2, insert=1, remove=0 +# For AC power Front to Back : +# If any fan fail, please fan speed register to 15 +# The max value of Fan speed register is 9 +# [LM75(48) + LM75(49) + LM75(4A)] > 174 => set Fan speed value from 4 to 5 +# [LM75(48) + LM75(49) + LM75(4A)] > 182 => set Fan speed value from 5 to 7 +# [LM75(48) + LM75(49) + LM75(4A)] > 190 => set Fan speed value from 7 to 9 +# +# [LM75(48) + LM75(49) + LM75(4A)] < 170 => set Fan speed value from 5 to 4 +# [LM75(48) + LM75(49) + LM75(4A)] < 178 => set Fan speed value from 7 to 5 +# [LM75(48) + LM75(49) + LM75(4A)] < 186 => set Fan speed value from 9 to 7 +# +# +# For AC power Back to Front : +# If any fan fail, please fan speed register to 15 +# The max value of Fan speed register is 10 +# [LM75(48) + LM75(49) + LM75(4A)] > 140 => set Fan speed value from 4 to 5 +# [LM75(48) + LM75(49) + LM75(4A)] > 150 => set Fan speed value from 5 to 7 +# [LM75(48) + LM75(49) + LM75(4A)] > 160 => set Fan speed value from 7 to 10 +# +# [LM75(48) + LM75(49) + LM75(4A)] < 135 => set Fan speed value from 5 to 4 +# [LM75(48) + LM75(49) + LM75(4A)] < 145 => set Fan speed value from 7 to 5 +# [LM75(48) + LM75(49) + LM75(4A)] < 155 => set Fan speed value from 10 to 7 +# + +# 2.If no matched fan speed is found from the policy, +# use FAN_DUTY_CYCLE_MIN as default speed +# Get current temperature +# 4.Decision 3: Decide new fan speed depend on fan direction/current fan speed/temperature + + +def as7712_set_fan_duty_cycle(dc): + # PWM register is same for all the FANs + if dc < 0 or dc > 100: + print("Error: Wrong duty cycle value %d" % (dc)) + return -1 + + platform_chassis.get_fan(0).set_speed(dc) + + return 0 + + +# Make a class we can use to capture stdout and sterr in the log +platform_chassis = None + + +class accton_as7712_monitor(object): + # static temp var + _ori_temp = 0 + _new_perc = 0 + _ori_perc = 0 + + llog = logging.getLogger("["+FUNCTION_NAME+"]") + + def __init__(self, log_console, log_file): + """Needs a logger and a logger level.""" + + formatter = logging.Formatter('%(name)s %(message)s') + sys_handler = logging.handlers.SysLogHandler(address='/dev/log') + sys_handler.setFormatter(formatter) + sys_handler.ident = 'common' + sys_handler.setLevel(logging.WARNING) # only fatal for syslog + self.llog.addHandler(sys_handler) + self.llog.setLevel(logging.DEBUG) + + if log_file: + fh = logging.FileHandler(log_file) + fh.setLevel(logging.INFO) + formatter = logging.Formatter('%(asctime)-15s %(name)s %(message)s') + fh.setFormatter(formatter) + self.llog.addHandler(fh) + + # set up logging to console + if log_console: + console = logging.StreamHandler() + console.setLevel(logging.DEBUG) # For debugging + formatter = logging.Formatter('%(asctime)-15s %(name)s %(message)s') + console.setFormatter(formatter) + self.llog.addHandler(console) + + def manage_fans(self): + fan_policy_f2b = { + 0: [32, 0, 174000], + 1: [38, 170000, 182000], + 2: [50, 178000, 190000], + 3: [63, 186000, 0], + } + fan_policy_b2f = { + 0: [32, 0, 140000], + 1: [38, 135000, 150000], + 2: [50, 145000, 160000], + 3: [69, 155000, 0], + } + + global fan_state + global platform_chassis + FAN_STATE_REMOVE = 0 + FAN_STATE_INSERT = 1 + + get_temp = 0 + for t in range(0, 3): + get_temp = get_temp + platform_chassis.get_thermal(t).get_temperature()*1000 + + cur_duty_cycle = 0 + + for x in range(platform_chassis.get_num_fans()): + fan_status = platform_chassis.get_fan(x).get_status() + fan_present = platform_chassis.get_fan(x).get_presence() + + if fan_present == 1: + if fan_state[x] != 1: + fan_state[x] = FAN_STATE_INSERT + #self.llog.debug("FAN-%d present is detected", x) + else: + if fan_state[x] != 0: + fan_state[x] = FAN_STATE_REMOVE + self.llog.warning("Alarm for FAN-%d absent is detected", x) + + if fan_status is None: + self.llog.warning('SET new_perc to %d (FAN stauts is None. fan_num:%d)', DUTY_MAX, x) + as7712_set_fan_duty_cycle(DUTY_MAX) + + if fan_status is False: + self.llog.warning('SET new_perc to %d (FAN fault. fan_num:%d)', DUTY_MAX, x) + as7712_set_fan_duty_cycle(DUTY_MAX) + + #self.llog.debug('INFO. fan_status is True (fan_num:%d)', x) + + # Determine the current fan duty cycle from a working fan + if not cur_duty_cycle: + cur_duty_cycle = platform_chassis.get_fan(x).get_speed() + + if fan_status is not None and fan_status is not False: + # Assuming all the fans have the same direction + fan_dir = platform_chassis.get_fan(0).get_direction() + if fan_dir == 1: + policy = fan_policy_f2b + else: + policy = fan_policy_b2f + + new_duty_cycle = cur_duty_cycle + + for x in range(0, 4): + if x == 4: + as7712_set_fan_duty_cycle(policy[0][0]) + break + + if get_temp > policy[x][2] and x != 3: + new_duty_cycle = policy[x+1][0] + self.llog.debug('THERMAL temp UP, temp %d > %d , new_duty_cycle=%d', + get_temp, policy[x][2], new_duty_cycle) + elif get_temp < policy[x][1]: + new_duty_cycle = policy[x-1][0] + self.llog.debug('THERMAL temp down, temp %d < %d , new_duty_cycle=%d', + get_temp, policy[x][1], new_duty_cycle) + break + + if new_duty_cycle == cur_duty_cycle: + return True + else: + if (new_duty_cycle == policy[3][0]) and (cur_duty_cycle < policy[3][0]): + self.llog.warning('Alarm for temperature high is detected') + elif (new_duty_cycle < policy[3][0]) and (cur_duty_cycle == policy[3][0]): + self.llog.warning('Alarm for temperature high is cleared') + else: + pass + + self.llog.debug('set new_duty_cycle=%d (old dc: %d)', new_duty_cycle, cur_duty_cycle) + as7712_set_fan_duty_cycle(new_duty_cycle) + + return True + + +def sig_handler(signum, frame): + logging.critical('INFO:Cause signal %d, set fan speed max.', signum) + as7712_set_fan_duty_cycle(DUTY_MAX) + sys.exit(0) + + +def main(argv): + + log_console = 0 + log_file = "" + + if len(sys.argv) != 1: + try: + opts, args = getopt.getopt(argv, 'hdl') + except getopt.GetoptError: + print('Usage: %s [-d] [-l]' % sys.argv[0]) + return 0 + for opt, arg in opts: + if opt == '-h': + print('Usage: %s [-d] [-l]' % sys.argv[0]) + return 0 + elif opt in ('-d'): + log_console = 1 + elif opt in ('-l'): + log_file = '%s.log' % sys.argv[0] + + signal.signal(signal.SIGINT, sig_handler) + signal.signal(signal.SIGTERM, sig_handler) + + global platform_chassis + platform_chassis = platform.Platform().get_chassis() + + # Disable the fan watchdog + status, output = subprocess.getstatusoutput('i2cset -f -y 2 0x66 0x33 0x0') + if status: + print("Error: Unable to disable fan speed watchdog") + + # Set any smaple speed of 100% + as7712_set_fan_duty_cycle(100) + + # Start the monitoring + monitor = accton_as7712_monitor(log_console, log_file) + # Loop forever, doing something useful hopefully: + while True: + monitor.manage_fans() + time.sleep(10) + + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/utils/pddf_post_device_create.sh b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/utils/pddf_post_device_create.sh new file mode 100755 index 00000000000..9cd521be0a0 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/utils/pddf_post_device_create.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +set_pca_mux_idle_disconnect() +{ + echo -2 | tee /sys/bus/i2c/drivers/pca954x/*-00*/idle_state >& /dev/null + if [ $? -ne 0 ]; then + echo "Fail to set pca954x mux idle disconnect" + exit 2 + fi +} + +set_pca_mux_idle_disconnect diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/utils/pddf_switch_svc.py b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/utils/pddf_switch_svc.py new file mode 100755 index 00000000000..3ed3f7604e7 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/utils/pddf_switch_svc.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python +# Script to stop and start the respective platforms default services. +# This will be used while switching the pddf->non-pddf mode and vice versa +import commands + +def check_pddf_support(): + return True + +def stop_platform_svc(): + status, output = commands.getstatusoutput("systemctl stop as7712-platform-init.service") + if status: + print("Stop as7712-platform-init.service failed %d"%status) + return False + status, output = commands.getstatusoutput("systemctl disable as7712-platform-init.service") + if status: + print("Disable as7712-platform-init.service failed %d"%status) + return False + + status, output = commands.getstatusoutput("/usr/local/bin/accton_as7712_util.py clean") + if status: + print("accton_as7712_util.py clean command failed %d"%status) + return False + + # HACK , stop the pddf-platform-init service if it is active + status, output = commands.getstatusoutput("systemctl stop pddf-platform-init.service") + if status: + print("Stop pddf-platform-init.service along with other platform serives failed %d"%status) + return False + + return True + +def start_platform_svc(): + status, output = commands.getstatusoutput("/usr/local/bin/accton_as7712_util.py install") + if status: + print("accton_as7712_util.py install command failed %d"%status) + return False + + status, output = commands.getstatusoutput("systemctl enable as7712-platform-init.service") + if status: + print("Enable as7712-platform-init.service failed %d"%status) + return False + status, output = commands.getstatusoutput("systemctl start as7712-platform-init.service") + if status: + print("Start as7712-platform-init.service failed %d"%status) + return False + + return True + +def start_platform_pddf(): + status, output = commands.getstatusoutput("systemctl start pddf-platform-init.service") + if status: + print("Start pddf-platform-init.service failed %d"%status) + return False + + return True + +def stop_platform_pddf(): + status, output = commands.getstatusoutput("systemctl stop pddf-platform-init.service") + if status: + print("Stop pddf-platform-init.service failed %d"%status) + return False + + return True + +def main(): + pass + +if __name__ == "__main__": + main() + diff --git a/platform/broadcom/sonic-platform-modules-accton/as7716-32x/modules/accton_as7716_32x_psu.c b/platform/broadcom/sonic-platform-modules-accton/as7716-32x/modules/accton_as7716_32x_psu.c index 78a58b820b2..7f5d8c2c8cc 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as7716-32x/modules/accton_as7716_32x_psu.c +++ b/platform/broadcom/sonic-platform-modules-accton/as7716-32x/modules/accton_as7716_32x_psu.c @@ -248,7 +248,9 @@ static int as7716_32x_psu_read_block(struct i2c_client *client, u8 command, u8 * enum psu_type { PSU_TYPE_AC_110V, PSU_TYPE_DC_48V, - PSU_TYPE_DC_12V + PSU_TYPE_DC_12V, + PSU_TYPE_AC_ACBEL_FSF019, + PSU_TYPE_AC_ACBEL_FSF045 }; struct model_name_info { @@ -259,9 +261,11 @@ struct model_name_info { }; struct model_name_info models[] = { -{PSU_TYPE_AC_110V, 0x20, 8, "YM-2651Y"}, -{PSU_TYPE_DC_48V, 0x20, 8, "YM-2651V"}, -{PSU_TYPE_DC_12V, 0x00, 11, "PSU-12V-750"}, + {PSU_TYPE_AC_110V, 0x20, 8, "YM-2651Y"}, + {PSU_TYPE_DC_48V, 0x20, 8, "YM-2651V"}, + {PSU_TYPE_DC_12V, 0x00, 11, "PSU-12V-750"}, + {PSU_TYPE_AC_ACBEL_FSF019, 0x15, 10, "FSF019-"}, + {PSU_TYPE_AC_ACBEL_FSF045, 0x15, 10, "FSF045-"} }; static int as7716_32x_psu_model_name_get(struct device *dev) @@ -287,7 +291,7 @@ static int as7716_32x_psu_model_name_get(struct device *dev) /* Determine if the model name is known, if not, read next index */ - if (strncmp(data->model_name, models[i].model_name, models[i].length) == 0) { + if (strncmp(data->model_name, models[i].model_name, strlen(models[i].model_name)) == 0) { return 0; } else { diff --git a/platform/broadcom/sonic-platform-modules-accton/as7726-32x/modules/Makefile b/platform/broadcom/sonic-platform-modules-accton/as7726-32x/modules/Makefile index 5b5e6912c56..141202e9a2f 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as7726-32x/modules/Makefile +++ b/platform/broadcom/sonic-platform-modules-accton/as7726-32x/modules/Makefile @@ -1,6 +1,7 @@ ifneq ($(KERNELRELEASE),) obj-m:= accton_as7726_32x_cpld.o accton_as7726_32x_fan.o \ - accton_as7726_32x_leds.o accton_as7726_32x_psu.o ym2651y.o + accton_as7726_32x_leds.o accton_as7726_32x_psu.o ym2651y.o \ + pddf_custom_psu.o else ifeq (,$(KERNEL_SRC)) diff --git a/platform/broadcom/sonic-platform-modules-accton/as7726-32x/modules/accton_as7726_32x_psu.c b/platform/broadcom/sonic-platform-modules-accton/as7726-32x/modules/accton_as7726_32x_psu.c index f4da01e86d9..3736cc8da0b 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as7726-32x/modules/accton_as7726_32x_psu.c +++ b/platform/broadcom/sonic-platform-modules-accton/as7726-32x/modules/accton_as7726_32x_psu.c @@ -34,8 +34,10 @@ #include #include +#define MAX_MODEL_NAME 16 +#define MAX_SERIAL_NUMBER 18 static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf); -static ssize_t show_model_name(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_string(struct device *dev, struct device_attribute *da, char *buf); static int as7726_32x_psu_read_block(struct i2c_client *client, u8 command, u8 *data,int data_len); extern int as7726_32x_cpld_read(unsigned short cpld_addr, u8 reg); @@ -52,7 +54,8 @@ struct as7726_32x_psu_data { unsigned long last_updated; /* In jiffies */ u8 index; /* PSU index */ u8 status; /* Status(present/power_good) register read from CPLD */ - char model_name[9]; /* Model name, read from eeprom */ + char model_name[MAX_MODEL_NAME+1]; /* Model name, read from eeprom */ + char serial_number[MAX_SERIAL_NUMBER+1]; }; static struct as7726_32x_psu_data *as7726_32x_psu_update_device(struct device *dev); @@ -60,18 +63,21 @@ static struct as7726_32x_psu_data *as7726_32x_psu_update_device(struct device *d enum as7726_32x_psu_sysfs_attributes { PSU_PRESENT, PSU_MODEL_NAME, + PSU_SERIAL_NUMBER, PSU_POWER_GOOD }; /* sysfs attributes for hwmon */ static SENSOR_DEVICE_ATTR(psu_present, S_IRUGO, show_status, NULL, PSU_PRESENT); -static SENSOR_DEVICE_ATTR(psu_model_name, S_IRUGO, show_model_name,NULL, PSU_MODEL_NAME); +static SENSOR_DEVICE_ATTR(psu_model_name, S_IRUGO, show_string, NULL, PSU_MODEL_NAME); +static SENSOR_DEVICE_ATTR(psu_serial_number, S_IRUGO, show_string, NULL, PSU_SERIAL_NUMBER); static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_status, NULL, PSU_POWER_GOOD); static struct attribute *as7726_32x_psu_attributes[] = { &sensor_dev_attr_psu_present.dev_attr.attr, &sensor_dev_attr_psu_model_name.dev_attr.attr, + &sensor_dev_attr_psu_serial_number.dev_attr.attr, &sensor_dev_attr_psu_power_good.dev_attr.attr, NULL }; @@ -83,6 +89,10 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, struct as7726_32x_psu_data *data = as7726_32x_psu_update_device(dev); u8 status = 0; + if (!data->valid) { + return -EIO; + } + if (attr->index == PSU_PRESENT) { status = !(data->status >> (1-data->index) & 0x1); } @@ -93,12 +103,27 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, return sprintf(buf, "%d\n", status); } -static ssize_t show_model_name(struct device *dev, struct device_attribute *da, - char *buf) +static ssize_t show_string(struct device *dev, struct device_attribute *da, + char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct as7726_32x_psu_data *data = as7726_32x_psu_update_device(dev); + char *ptr = NULL; - return sprintf(buf, "%s\n", data->model_name); + if (!data->valid) { + return -EIO; + } + + if (attr->index == PSU_MODEL_NAME) { + ptr = data->model_name; + } + else if (attr->index == PSU_SERIAL_NUMBER) { + ptr = data->serial_number; + } + else { + return -EIO; + } + return sprintf(buf, "%s\n", ptr); } static const struct attribute_group as7726_32x_psu_group = { @@ -219,6 +244,112 @@ static int as7726_32x_psu_read_block(struct i2c_client *client, u8 command, u8 * return result; } +enum psu_type { + PSU_TYPE_AC_110V, + PSU_TYPE_DC_48V, + PSU_TYPE_DC_12V, + PSU_TYPE_AC_ACBEL_FSF019, + PSU_TYPE_AC_ACBEL_FSF045 +}; + +struct model_name_info { + enum psu_type type; + u8 offset; + u8 length; + char* model_name; +}; + +struct serial_number_info { + enum psu_type type; + u8 offset; + u8 length; + char* serial_number; +}; +struct model_name_info models[] = { + {PSU_TYPE_AC_110V, 0x20, 8, "YM-2651Y"}, + {PSU_TYPE_DC_48V, 0x20, 8, "YM-2651V"}, + {PSU_TYPE_DC_12V, 0x00, 11, "PSU-12V-750"}, + {PSU_TYPE_AC_ACBEL_FSF019, 0x15, 10, "FSF019-"}, + {PSU_TYPE_AC_ACBEL_FSF045, 0x15, 10, "FSF045-"} +}; + +struct serial_number_info serials[] = { + {PSU_TYPE_AC_110V, 0x2e, 18, "YM-2651Y"}, + {PSU_TYPE_DC_48V, 0x2e, 18, "YM-2651V"}, + {PSU_TYPE_DC_12V, 0x2e, 18, "PSU-12V-750"}, + {PSU_TYPE_AC_ACBEL_FSF019, 0x2e, 16, "FSF019-"}, + {PSU_TYPE_AC_ACBEL_FSF045, 0x2e, 16, "FSF045-"} +}; + + +static int as7726_32x_psu_model_name_get(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as7726_32x_psu_data *data = i2c_get_clientdata(client); + int i, status; + + for (i = 0; i < ARRAY_SIZE(models); i++) { + memset(data->model_name, 0, sizeof(data->model_name)); + + status = as7726_32x_psu_read_block(client, models[i].offset, + data->model_name, models[i].length); + if (status < 0) { + data->model_name[0] = '\0'; + dev_dbg(&client->dev, "unable to read model name from (0x%x) offset(0x%x)\n", + client->addr, models[i].offset); + return status; + } + else { + data->model_name[models[i].length] = '\0'; + } + + /* Determine if the model name is known, if not, read next index + */ + if (strncmp(data->model_name, models[i].model_name, strlen(models[i].model_name)) == 0) { + return 0; + } + else { + data->model_name[0] = '\0'; + } + } + + return -ENODATA; +} + +static int as7726_32x_psu_serial_number_get(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as7726_32x_psu_data *data = i2c_get_clientdata(client); + int i, status; + + for (i = 0; i < ARRAY_SIZE(models); i++) { + memset(data->serial_number, 0, sizeof(data->serial_number)); + + status = as7726_32x_psu_read_block(client, serials[i].offset, + data->serial_number, serials[i].length); + if (status < 0) { + data->serial_number[0] = '\0'; + dev_dbg(&client->dev, "unable to read serial_number from (0x%x) offset(0x%x)\n", + client->addr, serials[i].offset); + return status; + } + else { + data->serial_number[serials[i].length] = '\0'; + } + + /* Determine if the model name is known, if not, read next index + */ + if (strncmp(data->model_name, models[i].model_name, strlen(models[i].model_name)) == 0) { + return 0; + } + else { + data->serial_number[0] = '\0'; + } + } + + return -ENODATA; +} + static struct as7726_32x_psu_data *as7726_32x_psu_update_device(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); @@ -231,6 +362,7 @@ static struct as7726_32x_psu_data *as7726_32x_psu_update_device(struct device *d int status; int power_good = 0; + data->valid = 0; dev_dbg(&client->dev, "Starting as7726_32x update\n"); /* Read psu status */ @@ -238,6 +370,7 @@ static struct as7726_32x_psu_data *as7726_32x_psu_update_device(struct device *d if (status < 0) { dev_dbg(&client->dev, "cpld reg 0x60 err %d\n", status); + goto exit; } else { data->status = status; @@ -245,17 +378,15 @@ static struct as7726_32x_psu_data *as7726_32x_psu_update_device(struct device *d /* Read model name */ memset(data->model_name, 0, sizeof(data->model_name)); + memset(data->serial_number, 0, sizeof(data->serial_number)); power_good = (data->status >> (3-data->index) & 0x1); if (power_good) { - status = as7726_32x_psu_read_block(client, 0x20, data->model_name, - ARRAY_SIZE(data->model_name)-1); - if (status < 0) { - data->model_name[0] = '\0'; - dev_dbg(&client->dev, "unable to read model name from (0x%x)\n", client->addr); + if (as7726_32x_psu_model_name_get(dev) < 0) { + goto exit; } - else { - data->model_name[ARRAY_SIZE(data->model_name)-1] = '\0'; + if (as7726_32x_psu_serial_number_get(dev) < 0) { + goto exit; } } @@ -263,6 +394,7 @@ static struct as7726_32x_psu_data *as7726_32x_psu_update_device(struct device *d data->valid = 1; } +exit: mutex_unlock(&data->update_lock); return data; diff --git a/platform/broadcom/sonic-platform-modules-accton/as7726-32x/modules/pddf_custom_psu.c b/platform/broadcom/sonic-platform-modules-accton/as7726-32x/modules/pddf_custom_psu.c new file mode 100644 index 00000000000..44a2ba8bef5 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7726-32x/modules/pddf_custom_psu.c @@ -0,0 +1,204 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../../../pddf/i2c/modules/include/pddf_psu_defs.h" + +ssize_t pddf_get_custom_psu_model_name(struct device *dev, struct device_attribute *da, char *buf); +ssize_t pddf_get_custom_psu_serial_num(struct device *dev, struct device_attribute *da, char *buf); +extern PSU_SYSFS_ATTR_DATA access_psu_model_name; +extern PSU_SYSFS_ATTR_DATA access_psu_serial_num; + +#define MAX_MODEL_NAME 16 +#define MAX_SERIAL_NUMBER 19 + +enum psu_type { + PSU_TYPE_AC_110V, + PSU_TYPE_DC_48V, + PSU_TYPE_DC_12V, + PSU_TYPE_AC_ACBEL_FSF019 +}; + +struct model_name_info { + enum psu_type type; + u8 offset; + u8 length; + u8 chk_length; + char* model_name; +}; + +struct serial_number_info { + enum psu_type type; + u8 offset; + u8 length; + u8 chk_length; + char* serial_number; +}; + +struct model_name_info models[] = { +{PSU_TYPE_AC_110V, 0x20, 8, 8, "YM-2651Y"}, +{PSU_TYPE_DC_48V, 0x20, 8, 8, "YM-2651V"}, +{PSU_TYPE_DC_12V, 0x00, 11, 11, "PSU-12V-750"}, +{PSU_TYPE_AC_ACBEL_FSF019, 0x15, 10, 7, "FSF019-"} + +}; + +struct serial_number_info serials[] = { +{PSU_TYPE_AC_110V, 0x2e, 18, 18, "YM-2651Y"}, +{PSU_TYPE_DC_48V, 0x2e, 18, 18, "YM-2651V"}, +{PSU_TYPE_DC_12V, 0x2e, 18, 18, "PSU-12V-750"}, +{PSU_TYPE_AC_ACBEL_FSF019, 0x2e, 16, 16, "FSF019-"} + +}; + +struct pddf_psu_data { + char model_name[MAX_MODEL_NAME+1]; + char serial_number[MAX_SERIAL_NUMBER+1]; +}; + + +static int pddf_psu_read_block(struct i2c_client *client, u8 command, u8 *data, + int data_len) +{ + int result = 0; + int retry_count = 10; + + while (retry_count) { + retry_count--; + + result = i2c_smbus_read_i2c_block_data(client, command, data_len, data); + + if (unlikely(result < 0)) { + msleep(10); + continue; + } + + if (unlikely(result != data_len)) { + result = -EIO; + msleep(10); + continue; + } + + result = 0; + break; + } + + return result; +} + +ssize_t pddf_get_custom_psu_serial_num(struct device *dev, struct device_attribute *da, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct pddf_psu_data data; + int i, status; + + for (i = 0; i < ARRAY_SIZE(models); i++) { + memset(data.serial_number, 0, sizeof(data.serial_number)); + + status = pddf_psu_read_block(client, models[i].offset, + data.model_name, models[i].length); + if (status < 0) { + data.model_name[0] = '\0'; + dev_dbg(&client->dev, "unable to read model name from (0x%x) offset(0x%x)\n", + client->addr, models[i].offset); + return status; + } + else { + data.model_name[models[i].length] = '\0'; + } + + /* Determine if the model name is known, if not, read next index + */ + if (strncmp(data.model_name, models[i].model_name, models[i].chk_length) == 0) { + status = pddf_psu_read_block(client, serials[i].offset, + data.serial_number, serials[i].length); + + if (status < 0) { + data.serial_number[0] = '\0'; + dev_dbg(&client->dev, "unable to read serial num from (0x%x) offset(0x%x)\n", + client->addr, serials[i].offset); + return status; + } + else { + data.serial_number[serials[i].length] = '\0'; + return sprintf(buf, "%s\n", data.serial_number); + } + + return 0; + } + else { + data.serial_number[0] = '\0'; + } + } + + return -ENODATA; + + +} + +ssize_t pddf_get_custom_psu_model_name(struct device *dev, struct device_attribute *da, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct pddf_psu_data data; + int i, status; + + for (i = 0; i < ARRAY_SIZE(models); i++) { + memset(data.model_name, 0, sizeof(data.model_name)); + + status = pddf_psu_read_block(client, models[i].offset, + data.model_name, models[i].length); + if (status < 0) { + data.model_name[0] = '\0'; + dev_dbg(&client->dev, "unable to read model name from (0x%x) offset(0x%x)\n", + client->addr, models[i].offset); + return status; + } + else { + data.model_name[models[i].length] = '\0'; + } + + /* Determine if the model name is known, if not, read next index + */ + if (strncmp(data.model_name, models[i].model_name, models[i].chk_length) == 0) { + return sprintf(buf, "%s\n", data.model_name); + } + else { + data.model_name[0] = '\0'; + } + } + + return -ENODATA; + +} + +static int __init pddf_custom_psu_init(void) +{ + access_psu_serial_num.show = pddf_get_custom_psu_serial_num; + access_psu_serial_num.do_get = NULL; + + access_psu_model_name.show = pddf_get_custom_psu_model_name; + access_psu_model_name.do_get = NULL; + + return 0; +} + +static void __exit pddf_custom_psu_exit(void) +{ + printk(KERN_ERR "pddf_custom_psu_exit\n"); + return; +} + +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("pddf custom psu api"); +MODULE_LICENSE("GPL"); + +module_init(pddf_custom_psu_init); +module_exit(pddf_custom_psu_exit); + diff --git a/platform/broadcom/sonic-platform-modules-accton/as7816-64x/modules/x86-64-accton-as7816-64x-psu.c b/platform/broadcom/sonic-platform-modules-accton/as7816-64x/modules/x86-64-accton-as7816-64x-psu.c index cdc535347dc..b1e37d613bc 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as7816-64x/modules/x86-64-accton-as7816-64x-psu.c +++ b/platform/broadcom/sonic-platform-modules-accton/as7816-64x/modules/x86-64-accton-as7816-64x-psu.c @@ -40,6 +40,7 @@ #define IS_POWER_GOOD(id, value) (!!(value & BIT(2+id))) #define IS_PRESENT(id, value) (!(value & BIT(id))) +static ssize_t show_id(struct device *dev, struct device_attribute *da, char *buf); static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf); static struct as7816_64x_psu_data *as7816_64x_psu_update_device(struct device *dev); extern int accton_i2c_cpld_read (u8 cpld_addr, u8 reg); @@ -61,17 +62,20 @@ struct as7816_64x_psu_data { enum as7816_64x_psu_sysfs_attributes { PSU_PRESENT, - PSU_POWER_GOOD + PSU_POWER_GOOD, + CPLD_ID }; /* sysfs attributes for hwmon */ static SENSOR_DEVICE_ATTR(psu_present, S_IRUGO, show_status, NULL, PSU_PRESENT); static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_status, NULL, PSU_POWER_GOOD); +static SENSOR_DEVICE_ATTR(cpld_id, S_IRUGO, show_id, NULL, CPLD_ID); static struct attribute *as7816_64x_psu_attributes[] = { &sensor_dev_attr_psu_present.dev_attr.attr, &sensor_dev_attr_psu_power_good.dev_attr.attr, + &sensor_dev_attr_cpld_id.dev_attr.attr, NULL }; @@ -100,6 +104,36 @@ static const struct attribute_group as7816_64x_psu_group = { .attrs = as7816_64x_psu_attributes, }; +static ssize_t show_id(struct device *dev, struct device_attribute *da, char *buf) +{ + int i = 0; + u8 cpld_id[3] = {0}; + struct i2c_client *client = to_i2c_client(dev); + struct as7816_64x_psu_data *data = i2c_get_clientdata(client); + int status = 0; + + mutex_lock(&data->update_lock); + for (i = 0; i < ARRAY_SIZE(cpld_id)-1; i++) { + status = accton_i2c_cpld_read(PSU_STATUS_I2C_ADDR, 0xfd+i); + if (unlikely(status < 0)) { + goto exit; + } + + cpld_id[i] = status; + } + mutex_unlock(&data->update_lock); + + if (cpld_id[0] == 0xff && cpld_id[1] == 0xff) { + return sprintf(buf, "NULL\n"); + } + + return sprintf(buf, "%s\n", cpld_id); + +exit: + mutex_unlock(&data->update_lock); + return status; +} + static int as7816_64x_psu_probe(struct i2c_client *client, const struct i2c_device_id *dev_id) { diff --git a/platform/broadcom/sonic-platform-modules-accton/as7816-64x/utils/accton_as7816_util.py b/platform/broadcom/sonic-platform-modules-accton/as7816-64x/utils/accton_as7816_util.py index 525f2786647..54781528d02 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as7816-64x/utils/accton_as7816_util.py +++ b/platform/broadcom/sonic-platform-modules-accton/as7816-64x/utils/accton_as7816_util.py @@ -118,6 +118,43 @@ def ir3570_check(): return -1 return ret +def psu_index_check(): + version = 0 + CPLD1_VERSION="/sys/bus/i2c/devices/19-0060/version" + try: + with open(CPLD1_VERSION, 'r') as cpld_version: + version = int(cpld_version.read()) + except IOError: + return False + + cpld_id = "NULL" + CPLD1_ID="/sys/bus/i2c/devices/10-0053/cpld_id" + if os.path.exists(CPLD1_ID): + try: + with open(CPLD1_ID, 'r') as cpld_id_fd: + cpld_id = cpld_id_fd.read() + except IOError: + return False + + at_found = 0 + if cpld_id.find("AT") != -1: + at_found = 1 + elif (version == 5) and (cpld_id.find("NULL") != -1): + at_found = 1 + + if (at_found): + log_os_system('echo 0x53 > /sys/bus/i2c/devices/i2c-10/delete_device', 1) + log_os_system('echo 0x50 > /sys/bus/i2c/devices/i2c-9/delete_device', 1) + log_os_system('echo as7816_64x_psu1 0x50 > /sys/bus/i2c/devices/i2c-9/new_device', 1) + log_os_system('echo as7816_64x_psu2 0x53 > /sys/bus/i2c/devices/i2c-10/new_device', 1) + + return True + +def show_eeprom_help(): + cmd = sys.argv[0].split("/")[-1]+ " " + args[0] + print " use \""+ cmd + " 1-64 \" to dump sfp# eeprom" + sys.exit(0) + def my_log(txt): if DEBUG == True: print(("[ROY]"+txt)) @@ -252,6 +289,8 @@ def device_install(): if FORCE == 0: return status + psu_index_check() + for i in range(0,len(sfp_map)): path = "/sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/new_device" status, output =log_os_system("echo optoe1 0x50 > " + path, 1) diff --git a/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/classes/__init__.py b/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/classes/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/modules/Makefile b/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/modules/Makefile new file mode 100644 index 00000000000..c470d836c36 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/modules/Makefile @@ -0,0 +1,17 @@ +ifneq ($(KERNELRELEASE),) +obj-m:= x86-64-accton-as7926-40xfb-cpld.o x86-64-accton-as7926-40xfb-fan.o \ + x86-64-accton-as7926-40xfb-leds.o x86-64-accton-as7926-40xfb-psu.o \ + x86-64-accton-as7926-40xfb-thermal.o x86-64-accton-as7926-40xfb-sys.o + +else +ifeq (,$(KERNEL_SRC)) +$(error KERNEL_SRC is not defined) +else +KERNELDIR:=$(KERNEL_SRC) +endif +PWD:=$(shell pwd) +default: + $(MAKE) -C $(KERNELDIR) M=$(PWD) modules +clean: + rm -rf *.o *.mod.o *.mod.o *.ko .*cmd .tmp_versions Module.markers Module.symvers modules.order +endif diff --git a/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/modules/x86-64-accton-as7926-40xfb-cpld.c b/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/modules/x86-64-accton-as7926-40xfb-cpld.c new file mode 100644 index 00000000000..7ea45b7438b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/modules/x86-64-accton-as7926-40xfb-cpld.c @@ -0,0 +1,1017 @@ +/* + * A hwmon driver for the as7926_40xfb_cpld + * + * Copyright (C) 2019 Edgecore Networks Corporation. + * Jostar Yang + * + * Based on ad7414.c + * Copyright 2006 Stefan Roese , DENX Software Engineering + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as7926_40xfb_cpld" + +static LIST_HEAD(cpld_client_list); +static struct mutex list_lock; + +struct cpld_client_node { + struct i2c_client *client; + struct list_head list; +}; + +enum cpld_type { + as7926_40xfb_cpld2, + as7926_40xfb_cpld3, + as7926_40xfb_cpld4, +}; + +#define I2C_RW_RETRY_COUNT 10 +#define I2C_RW_RETRY_INTERVAL 60 /* ms */ + +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_present_all(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t set_control(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t access(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t show_version(struct device *dev, struct device_attribute *da, + char *buf); + +struct as7926_40xfb_cpld_data { + struct device *hwmon_dev; + struct mutex update_lock; + u8 index; /* CPLD index */ +}; + +/* Addresses scanned for as7926_40xfb_cpld + */ +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +#define TRANSCEIVER_PRESENT_ATTR_ID(index) MODULE_PRESENT_##index +#define TRANSCEIVER_RESET_ATTR_ID(index) MODULE_RESET_##index +#define TRANSCEIVER_TXDISABLE_ATTR_ID(index) MODULE_TXDISABLE_##index +#define TRANSCEIVER_RXLOS_ATTR_ID(index) MODULE_RXLOS_##index + +enum as7926_40xfb_cpld_sysfs_attributes { + /* transceiver attributes */ + TRANSCEIVER_PRESENT_ATTR_ID(1), + TRANSCEIVER_PRESENT_ATTR_ID(2), + TRANSCEIVER_PRESENT_ATTR_ID(21), + TRANSCEIVER_PRESENT_ATTR_ID(22), + TRANSCEIVER_PRESENT_ATTR_ID(3), + TRANSCEIVER_PRESENT_ATTR_ID(4), + TRANSCEIVER_PRESENT_ATTR_ID(23), + TRANSCEIVER_PRESENT_ATTR_ID(24), + TRANSCEIVER_PRESENT_ATTR_ID(5), + TRANSCEIVER_PRESENT_ATTR_ID(6), + TRANSCEIVER_PRESENT_ATTR_ID(25), + TRANSCEIVER_PRESENT_ATTR_ID(26), + TRANSCEIVER_PRESENT_ATTR_ID(7), + TRANSCEIVER_PRESENT_ATTR_ID(8), + TRANSCEIVER_PRESENT_ATTR_ID(27), + TRANSCEIVER_PRESENT_ATTR_ID(28), + TRANSCEIVER_PRESENT_ATTR_ID(9), + TRANSCEIVER_PRESENT_ATTR_ID(10), + TRANSCEIVER_PRESENT_ATTR_ID(29), + TRANSCEIVER_PRESENT_ATTR_ID(30), + TRANSCEIVER_PRESENT_ATTR_ID(11), + TRANSCEIVER_PRESENT_ATTR_ID(12), + TRANSCEIVER_PRESENT_ATTR_ID(31), + TRANSCEIVER_PRESENT_ATTR_ID(32), + TRANSCEIVER_PRESENT_ATTR_ID(13), + TRANSCEIVER_PRESENT_ATTR_ID(14), + TRANSCEIVER_PRESENT_ATTR_ID(33), + TRANSCEIVER_PRESENT_ATTR_ID(34), + TRANSCEIVER_PRESENT_ATTR_ID(15), + TRANSCEIVER_PRESENT_ATTR_ID(16), + TRANSCEIVER_PRESENT_ATTR_ID(35), + TRANSCEIVER_PRESENT_ATTR_ID(36), + TRANSCEIVER_PRESENT_ATTR_ID(17), + TRANSCEIVER_PRESENT_ATTR_ID(18), + TRANSCEIVER_PRESENT_ATTR_ID(37), + TRANSCEIVER_PRESENT_ATTR_ID(38), + TRANSCEIVER_PRESENT_ATTR_ID(19), + TRANSCEIVER_PRESENT_ATTR_ID(20), + TRANSCEIVER_PRESENT_ATTR_ID(39), + TRANSCEIVER_PRESENT_ATTR_ID(40), + TRANSCEIVER_PRESENT_ATTR_ID(41), + TRANSCEIVER_PRESENT_ATTR_ID(42), + TRANSCEIVER_PRESENT_ATTR_ID(43), + TRANSCEIVER_PRESENT_ATTR_ID(44), + TRANSCEIVER_PRESENT_ATTR_ID(45), + TRANSCEIVER_PRESENT_ATTR_ID(46), + TRANSCEIVER_PRESENT_ATTR_ID(47), + TRANSCEIVER_PRESENT_ATTR_ID(48), + TRANSCEIVER_PRESENT_ATTR_ID(49), + TRANSCEIVER_PRESENT_ATTR_ID(50), + TRANSCEIVER_PRESENT_ATTR_ID(51), + TRANSCEIVER_PRESENT_ATTR_ID(52), + TRANSCEIVER_PRESENT_ATTR_ID(53), + TRANSCEIVER_RESET_ATTR_ID(1), + TRANSCEIVER_RESET_ATTR_ID(2), + TRANSCEIVER_RESET_ATTR_ID(21), + TRANSCEIVER_RESET_ATTR_ID(22), + TRANSCEIVER_RESET_ATTR_ID(3), + TRANSCEIVER_RESET_ATTR_ID(4), + TRANSCEIVER_RESET_ATTR_ID(23), + TRANSCEIVER_RESET_ATTR_ID(24), + TRANSCEIVER_RESET_ATTR_ID(5), + TRANSCEIVER_RESET_ATTR_ID(6), + TRANSCEIVER_RESET_ATTR_ID(25), + TRANSCEIVER_RESET_ATTR_ID(26), + TRANSCEIVER_RESET_ATTR_ID(7), + TRANSCEIVER_RESET_ATTR_ID(8), + TRANSCEIVER_RESET_ATTR_ID(27), + TRANSCEIVER_RESET_ATTR_ID(28), + TRANSCEIVER_RESET_ATTR_ID(9), + TRANSCEIVER_RESET_ATTR_ID(10), + TRANSCEIVER_RESET_ATTR_ID(29), + TRANSCEIVER_RESET_ATTR_ID(30), + TRANSCEIVER_RESET_ATTR_ID(11), + TRANSCEIVER_RESET_ATTR_ID(12), + TRANSCEIVER_RESET_ATTR_ID(31), + TRANSCEIVER_RESET_ATTR_ID(32), + TRANSCEIVER_RESET_ATTR_ID(13), + TRANSCEIVER_RESET_ATTR_ID(14), + TRANSCEIVER_RESET_ATTR_ID(33), + TRANSCEIVER_RESET_ATTR_ID(34), + TRANSCEIVER_RESET_ATTR_ID(15), + TRANSCEIVER_RESET_ATTR_ID(16), + TRANSCEIVER_RESET_ATTR_ID(35), + TRANSCEIVER_RESET_ATTR_ID(36), + TRANSCEIVER_RESET_ATTR_ID(17), + TRANSCEIVER_RESET_ATTR_ID(18), + TRANSCEIVER_RESET_ATTR_ID(37), + TRANSCEIVER_RESET_ATTR_ID(38), + TRANSCEIVER_RESET_ATTR_ID(19), + TRANSCEIVER_RESET_ATTR_ID(20), + TRANSCEIVER_RESET_ATTR_ID(39), + TRANSCEIVER_RESET_ATTR_ID(40), + TRANSCEIVER_RESET_ATTR_ID(41), + TRANSCEIVER_RESET_ATTR_ID(42), + TRANSCEIVER_RESET_ATTR_ID(43), + TRANSCEIVER_RESET_ATTR_ID(44), + TRANSCEIVER_RESET_ATTR_ID(45), + TRANSCEIVER_RESET_ATTR_ID(46), + TRANSCEIVER_RESET_ATTR_ID(47), + TRANSCEIVER_RESET_ATTR_ID(48), + TRANSCEIVER_RESET_ATTR_ID(49), + TRANSCEIVER_RESET_ATTR_ID(50), + TRANSCEIVER_RESET_ATTR_ID(51), + TRANSCEIVER_RESET_ATTR_ID(52), + TRANSCEIVER_RESET_ATTR_ID(53), + TRANSCEIVER_PRESENT_ATTR_ID(54), + TRANSCEIVER_PRESENT_ATTR_ID(55), + TRANSCEIVER_TXDISABLE_ATTR_ID(54), + TRANSCEIVER_TXDISABLE_ATTR_ID(55), + TRANSCEIVER_RXLOS_ATTR_ID(54), + TRANSCEIVER_RXLOS_ATTR_ID(55), + MODULE_PRESENT_ALL, + CPLD_VERSION, + ACCESS, +}; + +/* sysfs attributes for hwmon + */ + +/* qsfp transceiver attributes */ +#define DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, show_status, \ + NULL, MODULE_PRESENT_##index); \ + static SENSOR_DEVICE_ATTR(module_reset_##index, S_IRUGO | S_IWUSR, \ + show_status, set_control, MODULE_RESET_##index) +#define DECLARE_QSFP28_TRANSCEIVER_ATTR(index) \ + &sensor_dev_attr_module_present_##index.dev_attr.attr, \ + &sensor_dev_attr_module_reset_##index.dev_attr.attr + +#define DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, \ + show_status, NULL, MODULE_PRESENT_##index); \ + static SENSOR_DEVICE_ATTR(module_reset_##index, S_IRUGO | S_IWUSR, \ + show_status, set_control, MODULE_RESET_##index) +#define DECLARE_QSFPDD_TRANSCEIVER_ATTR(index) \ + &sensor_dev_attr_module_present_##index.dev_attr.attr, \ + &sensor_dev_attr_module_reset_##index.dev_attr.attr + +/* sfp transceiver attributes */ +#define DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, show_status, \ + NULL, MODULE_PRESENT_##index); \ + static SENSOR_DEVICE_ATTR(module_tx_disable_##index, S_IRUGO | S_IWUSR, \ + show_status, set_tx_disable, \ + MODULE_TXDISABLE_##index); \ + static SENSOR_DEVICE_ATTR(module_rx_los_##index, S_IRUGO, show_status, \ + NULL, MODULE_RXLOS_##index) + +#define DECLARE_SFP_TRANSCEIVER_ATTR(index) \ + &sensor_dev_attr_module_present_##index.dev_attr.attr, \ + &sensor_dev_attr_module_tx_disable_##index.dev_attr.attr, \ + &sensor_dev_attr_module_rx_los_##index.dev_attr.attr + +static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, NULL, CPLD_VERSION); +static SENSOR_DEVICE_ATTR(access, S_IWUSR, NULL, access, ACCESS); +static SENSOR_DEVICE_ATTR(module_present_all, S_IRUGO, show_present_all, \ + NULL, MODULE_PRESENT_ALL); + +/* transceiver attributes */ +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(1); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(2); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(3); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(4); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(5); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(6); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(7); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(8); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(9); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(10); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(11); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(12); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(13); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(14); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(15); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(16); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(17); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(18); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(19); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(20); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(21); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(22); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(23); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(24); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(25); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(26); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(27); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(28); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(29); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(30); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(31); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(32); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(33); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(34); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(35); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(36); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(37); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(38); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(39); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(40); +DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(41); +DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(42); +DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(43); +DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(44); +DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(45); +DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(46); +DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(47); +DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(48); +DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(49); +DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(50); +DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(51); +DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(52); +DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(53); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(54); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(55); + +static struct attribute *as7926_40xfb_cpld2_attributes[] = { + /* transceiver attributes */ + DECLARE_QSFP28_TRANSCEIVER_ATTR(1), + DECLARE_QSFP28_TRANSCEIVER_ATTR(2), + DECLARE_QSFP28_TRANSCEIVER_ATTR(3), + DECLARE_QSFP28_TRANSCEIVER_ATTR(4), + DECLARE_QSFP28_TRANSCEIVER_ATTR(5), + DECLARE_QSFP28_TRANSCEIVER_ATTR(6), + DECLARE_QSFP28_TRANSCEIVER_ATTR(7), + DECLARE_QSFP28_TRANSCEIVER_ATTR(8), + DECLARE_QSFP28_TRANSCEIVER_ATTR(9), + DECLARE_QSFP28_TRANSCEIVER_ATTR(10), + DECLARE_QSFP28_TRANSCEIVER_ATTR(21), + DECLARE_QSFP28_TRANSCEIVER_ATTR(22), + DECLARE_QSFP28_TRANSCEIVER_ATTR(23), + DECLARE_QSFP28_TRANSCEIVER_ATTR(24), + DECLARE_QSFP28_TRANSCEIVER_ATTR(25), + DECLARE_QSFP28_TRANSCEIVER_ATTR(26), + DECLARE_QSFP28_TRANSCEIVER_ATTR(27), + DECLARE_QSFP28_TRANSCEIVER_ATTR(28), + DECLARE_QSFP28_TRANSCEIVER_ATTR(29), + DECLARE_QSFP28_TRANSCEIVER_ATTR(30), + DECLARE_SFP_TRANSCEIVER_ATTR(54), + DECLARE_SFP_TRANSCEIVER_ATTR(55), + &sensor_dev_attr_module_present_all.dev_attr.attr, + &sensor_dev_attr_version.dev_attr.attr, + &sensor_dev_attr_access.dev_attr.attr, + NULL +}; + +static struct attribute *as7926_40xfb_cpld3_attributes[] = { + DECLARE_QSFP28_TRANSCEIVER_ATTR(11), + DECLARE_QSFP28_TRANSCEIVER_ATTR(12), + DECLARE_QSFP28_TRANSCEIVER_ATTR(13), + DECLARE_QSFP28_TRANSCEIVER_ATTR(14), + DECLARE_QSFP28_TRANSCEIVER_ATTR(15), + DECLARE_QSFP28_TRANSCEIVER_ATTR(16), + DECLARE_QSFP28_TRANSCEIVER_ATTR(17), + DECLARE_QSFP28_TRANSCEIVER_ATTR(18), + DECLARE_QSFP28_TRANSCEIVER_ATTR(19), + DECLARE_QSFP28_TRANSCEIVER_ATTR(20), + DECLARE_QSFP28_TRANSCEIVER_ATTR(31), + DECLARE_QSFP28_TRANSCEIVER_ATTR(32), + DECLARE_QSFP28_TRANSCEIVER_ATTR(33), + DECLARE_QSFP28_TRANSCEIVER_ATTR(34), + DECLARE_QSFP28_TRANSCEIVER_ATTR(35), + DECLARE_QSFP28_TRANSCEIVER_ATTR(36), + DECLARE_QSFP28_TRANSCEIVER_ATTR(37), + DECLARE_QSFP28_TRANSCEIVER_ATTR(38), + DECLARE_QSFP28_TRANSCEIVER_ATTR(39), + DECLARE_QSFP28_TRANSCEIVER_ATTR(40), + &sensor_dev_attr_module_present_all.dev_attr.attr, + &sensor_dev_attr_version.dev_attr.attr, + &sensor_dev_attr_access.dev_attr.attr, + NULL +}; + +static struct attribute *as7926_40xfb_cpld4_attributes[] = { + DECLARE_QSFPDD_TRANSCEIVER_ATTR(41), + DECLARE_QSFPDD_TRANSCEIVER_ATTR(42), + DECLARE_QSFPDD_TRANSCEIVER_ATTR(43), + DECLARE_QSFPDD_TRANSCEIVER_ATTR(44), + DECLARE_QSFPDD_TRANSCEIVER_ATTR(45), + DECLARE_QSFPDD_TRANSCEIVER_ATTR(46), + DECLARE_QSFPDD_TRANSCEIVER_ATTR(47), + DECLARE_QSFPDD_TRANSCEIVER_ATTR(48), + DECLARE_QSFPDD_TRANSCEIVER_ATTR(49), + DECLARE_QSFPDD_TRANSCEIVER_ATTR(50), + DECLARE_QSFPDD_TRANSCEIVER_ATTR(51), + DECLARE_QSFPDD_TRANSCEIVER_ATTR(52), + DECLARE_QSFPDD_TRANSCEIVER_ATTR(53), + &sensor_dev_attr_module_present_all.dev_attr.attr, + &sensor_dev_attr_version.dev_attr.attr, + &sensor_dev_attr_access.dev_attr.attr, + NULL +}; + +static const struct attribute_group as7926_40xfb_cpld2_group = { + .attrs = as7926_40xfb_cpld2_attributes, +}; + +static const struct attribute_group as7926_40xfb_cpld3_group = { + .attrs = as7926_40xfb_cpld3_attributes, +}; + +static const struct attribute_group as7926_40xfb_cpld4_group = { + .attrs = as7926_40xfb_cpld4_attributes, +}; + +static const struct attribute_group* cpld_groups[] = { + &as7926_40xfb_cpld2_group, + &as7926_40xfb_cpld3_group, + &as7926_40xfb_cpld4_group, +}; + +int as7926_40xfb_cpld_read(int bus_num, unsigned short cpld_addr, u8 reg) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int ret = -EPERM; + + 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 + && cpld_node->client->adapter->nr == bus_num) { + ret = i2c_smbus_read_byte_data(cpld_node->client, reg); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(as7926_40xfb_cpld_read); + +int as7926_40xfb_cpld_write(int bus_num, 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 + && cpld_node->client->adapter->nr == bus_num) { + ret = i2c_smbus_write_byte_data(cpld_node->client, reg, value); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(as7926_40xfb_cpld_write); + +static ssize_t show_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 as7926_40xfb_cpld_data *data = i2c_get_clientdata(client); + int status = 0; + u8 reg = 0, mask = 0, invert = 1; + + switch (attr->index) { + case MODULE_PRESENT_1 ... MODULE_PRESENT_2: + case MODULE_PRESENT_3 ... MODULE_PRESENT_4: + case MODULE_PRESENT_21 ... MODULE_PRESENT_22: + case MODULE_PRESENT_23 ... MODULE_PRESENT_24: + reg = 0x10; + mask = 0x1 << (attr->index - MODULE_PRESENT_1); + break; + case MODULE_PRESENT_5 ... MODULE_PRESENT_6: + case MODULE_PRESENT_7 ... MODULE_PRESENT_8: + case MODULE_PRESENT_25 ... MODULE_PRESENT_26: + case MODULE_PRESENT_27 ... MODULE_PRESENT_28: + reg = 0x11; + mask = 0x1 << (attr->index - MODULE_PRESENT_5); + break; + case MODULE_PRESENT_9 ... MODULE_PRESENT_10: + case MODULE_PRESENT_29 ... MODULE_PRESENT_30: + reg = 0x12; + mask = 0x1 << (attr->index - MODULE_PRESENT_9); + break; + case MODULE_PRESENT_11 ... MODULE_PRESENT_12: + case MODULE_PRESENT_13 ... MODULE_PRESENT_14: + case MODULE_PRESENT_31 ... MODULE_PRESENT_32: + case MODULE_PRESENT_33 ... MODULE_PRESENT_34: + reg = 0x10; + mask = 0x1 << (attr->index - MODULE_PRESENT_11); + break; + case MODULE_PRESENT_15 ... MODULE_PRESENT_16: + case MODULE_PRESENT_17 ... MODULE_PRESENT_18: + case MODULE_PRESENT_35 ... MODULE_PRESENT_36: + case MODULE_PRESENT_37 ... MODULE_PRESENT_38: + reg = 0x11; + mask = 0x1 << (attr->index - MODULE_PRESENT_15); + break; + case MODULE_PRESENT_19 ... MODULE_PRESENT_20: + case MODULE_PRESENT_39 ... MODULE_PRESENT_40: + reg = 0x12; + mask = 0x1 << (attr->index - MODULE_PRESENT_19); + break; + case MODULE_PRESENT_41 ... MODULE_PRESENT_48: /*QSFP-DD*/ + reg = 0x50; + mask = 0x1 << (attr->index - MODULE_PRESENT_41); + break; + case MODULE_PRESENT_49 ... MODULE_PRESENT_53: /*QSFP-DD*/ + reg = 0x51; + mask = 0x1 << (attr->index - MODULE_PRESENT_49); + break; + case MODULE_RESET_1 ... MODULE_RESET_2: + case MODULE_RESET_3 ... MODULE_RESET_4: + case MODULE_RESET_21 ... MODULE_RESET_22: + case MODULE_RESET_23 ... MODULE_RESET_24: + reg = 0x8; + mask = 0x1 << (attr->index - MODULE_RESET_1); + break; + case MODULE_RESET_5 ... MODULE_RESET_6: + case MODULE_RESET_7 ... MODULE_RESET_8: + case MODULE_RESET_25 ... MODULE_RESET_26: + case MODULE_RESET_27 ... MODULE_RESET_28: + reg = 0x9; + mask = 0x1 << (attr->index - MODULE_RESET_5); + break; + case MODULE_RESET_9 ... MODULE_RESET_10: + case MODULE_RESET_29 ... MODULE_RESET_30: + reg = 0xA; + mask = 0x1 << (attr->index - MODULE_RESET_9); + break; + case MODULE_RESET_11 ... MODULE_RESET_12: + case MODULE_RESET_13 ... MODULE_RESET_14: + case MODULE_RESET_31 ... MODULE_RESET_32: + case MODULE_RESET_33 ... MODULE_RESET_34: + reg = 0x8; + mask = 0x1 << (attr->index - MODULE_RESET_11); + break; + case MODULE_RESET_15 ... MODULE_RESET_16: + case MODULE_RESET_17 ... MODULE_RESET_18: + case MODULE_RESET_35 ... MODULE_RESET_36: + case MODULE_RESET_37 ... MODULE_RESET_38: + reg = 0x9; + mask = 0x1 << (attr->index - MODULE_RESET_15); + break; + case MODULE_RESET_19 ... MODULE_RESET_20: + case MODULE_RESET_39 ... MODULE_RESET_40: + reg = 0xA; + mask = 0x1 << (attr->index - MODULE_RESET_19); + break; + case MODULE_RESET_41 ... MODULE_RESET_48: /*QSFP-DD*/ + reg = 0xA; + mask = 0x1 << (attr->index - MODULE_RESET_41); + break; + case MODULE_RESET_49 ... MODULE_RESET_53: /*QSFP-DD*/ + reg = 0xB; + mask = 0x1 << (attr->index - MODULE_RESET_49); + break; + case MODULE_PRESENT_54 ... MODULE_PRESENT_55: + reg = 0x13; + mask = 0x1 << (attr->index - MODULE_PRESENT_54); + break; + case MODULE_TXDISABLE_54 ... MODULE_TXDISABLE_55: + reg = 0xB; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_54); + invert=0; + break; + case MODULE_RXLOS_54 ... MODULE_RXLOS_55: + reg = 0x23; + mask = 0x1 << (attr->index - MODULE_RXLOS_54); + invert=0; + break; + default: + return -ENXIO; + } + + mutex_lock(&data->update_lock); + switch(data->index) { + /* Port 1-20, 41-42 present statuus: read from i2c bus number '12' + and CPLD slave address 0x62 */ + case as7926_40xfb_cpld2: status = as7926_40xfb_cpld_read(12, 0x62, reg); + break; + /* Port 21-40 present statuus: read from i2c bus number '13' + and CPLD slave address 0x63 */ + case as7926_40xfb_cpld3: status = as7926_40xfb_cpld_read(13, 0x63, reg); + break; + /* Port 41-53 plug-unplug read from i2c bus number '76' + and CPLD slave address 0x64 */ + case as7926_40xfb_cpld4: status = as7926_40xfb_cpld_read(76, 0x64, reg); + break; + default: status = -ENXIO; + break; + } + + if (unlikely(status < 0)) + goto exit; + + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", invert? !(status & mask): !!(status & mask)); + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t show_present_all(struct device *dev, struct device_attribute *da, + char *buf) +{ + int i, status; + u8 values[4] = { 0 }; + u8 regs_cpld2[] = { 0x10, 0x11, 0x12, 0x13 }; + u8 regs_cpld3[] = { 0x10, 0x11, 0x12 }; + u8 regs_cpld4[] = { 0x50, 0x51 }; + u8 *regs[] = { NULL, regs_cpld2, regs_cpld3, regs_cpld4 }; + u8 size[] = { 0, ARRAY_SIZE(regs_cpld2), + ARRAY_SIZE(regs_cpld3),ARRAY_SIZE(regs_cpld3) }; + u8 bus[] = { 0, 12, 13, 76 }; + u8 addr[] = { 0, 0x62, 0x63, 0x64 }; + struct i2c_client *client = to_i2c_client(dev); + struct as7926_40xfb_cpld_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + for (i = 0; i < size[data->index]; i++) { + status = as7926_40xfb_cpld_read(bus[data->index], + addr[data->index], regs[data->index][i]); + if (status < 0) + goto exit; + + values[i] = ~(u8)status; + } + + mutex_unlock(&data->update_lock); + + switch(data->index) { + case as7926_40xfb_cpld2: + return sprintf(buf, "%.2x %.2x %.2x %.2x\n", + values[0], values[1], values[2]&0xF, values[3] & 0x3); + case as7926_40xfb_cpld3: + return sprintf(buf, "%.2x %.2x %.2x\n", + values[0], values[1], (values[2] & 0xF)); + case as7926_40xfb_cpld4: + return sprintf(buf, "%.2x %.2x\n", values[0], (values[1] & 0x1F)); + default: + return -EINVAL; + } + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t set_tx_disable(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 as7926_40xfb_cpld_data *data = i2c_get_clientdata(client); + long disable; + int status, val; + u8 reg = 0, mask = 0; + + status = kstrtol(buf, 10, &disable); + if (status) + return status; + + reg = 0xB; + switch (attr->index) { + case MODULE_TXDISABLE_54: + mask = 0x1; + break; + case MODULE_TXDISABLE_55: + mask = 0x2; + break; + default: + return 0; + } + /* Read current status */ + mutex_lock(&data->update_lock); + val = as7926_40xfb_cpld_read(12, 0x62, reg); + if (unlikely(status < 0)) + goto exit; + + /* Update tx_disable status */ + if (disable) + val |= mask; + else + val &= ~mask; + + status = as7926_40xfb_cpld_write(12, 0x62, reg, val); + if (unlikely(status < 0)) + goto exit; + + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t set_control(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 as7926_40xfb_cpld_data *data = i2c_get_clientdata(client); + long reset; + int status, bus, addr; + u8 reg = 0, mask = 0; + + status = kstrtol(buf, 10, &reset); + if (status) + return status; + + switch (attr->index) { + case MODULE_RESET_1 ... MODULE_RESET_2: + case MODULE_RESET_3 ... MODULE_RESET_4: + case MODULE_RESET_21 ... MODULE_RESET_22: + case MODULE_RESET_23 ... MODULE_RESET_24: + reg = 0x8; + mask = 0x1 << (attr->index - MODULE_RESET_1); + break; + case MODULE_RESET_5 ... MODULE_RESET_6: + case MODULE_RESET_7 ... MODULE_RESET_8: + case MODULE_RESET_25 ... MODULE_RESET_26: + case MODULE_RESET_27 ... MODULE_RESET_28: + reg = 0x9; + mask = 0x1 << (attr->index - MODULE_RESET_5); + break; + case MODULE_RESET_9 ... MODULE_RESET_10: + case MODULE_RESET_29 ... MODULE_RESET_30: + reg = 0xA; + mask = 0x1 << (attr->index - MODULE_RESET_9); + break; + case MODULE_RESET_11 ... MODULE_RESET_12: + case MODULE_RESET_13 ... MODULE_RESET_14: + case MODULE_RESET_31 ... MODULE_RESET_32: + case MODULE_RESET_33 ... MODULE_RESET_34: + reg = 0x8; + mask = 0x1 << (attr->index - MODULE_RESET_11); + break; + case MODULE_RESET_15 ... MODULE_RESET_16: + case MODULE_RESET_17 ... MODULE_RESET_18: + case MODULE_RESET_35 ... MODULE_RESET_36: + case MODULE_RESET_37 ... MODULE_RESET_38: + reg = 0x9; + mask = 0x1 << (attr->index - MODULE_RESET_15); + break; + case MODULE_RESET_19 ... MODULE_RESET_20: + case MODULE_RESET_39 ... MODULE_RESET_40: + reg = 0xA; + mask = 0x1 << (attr->index - MODULE_RESET_19); + break; + case MODULE_RESET_41 ... MODULE_RESET_48: /*QSFP-DD*/ + reg = 0xA; + mask = 0x1 << (attr->index - MODULE_RESET_41); + break; + case MODULE_RESET_49 ... MODULE_RESET_53: /*QSFP-DD*/ + reg = 0xB; + mask = 0x1 << (attr->index - MODULE_RESET_49); + break; + default: + return -ENXIO; + } + + mutex_lock(&data->update_lock); + switch(data->index) { + /* Port 1-20, 41-42 present statuus: read from i2c bus number '12' + and CPLD slave address 0x62 */ + case as7926_40xfb_cpld2: + bus = 12; + addr = 0x62; + break; + /* Port 21-40 present statuus: read from i2c bus number '13' + and CPLD slave address 0x63 */ + case as7926_40xfb_cpld3: + bus = 13; + addr = 0x63; + break; + /* Port 41-53 plug-unplug read from i2c bus number '76' + and CPLD slave address 0x64 */ + case as7926_40xfb_cpld4: + bus = 76; + addr = 0x64; + break; + default: status = -ENXIO; + goto exit; + } + + /* Read current status */ + status = as7926_40xfb_cpld_read(bus, addr, reg); + if (unlikely(status < 0)) + goto exit; + + /* Update reset status */ + if (reset) + status &= ~mask; + else + status |= mask; + + status = as7926_40xfb_cpld_write(bus, addr, reg, status); + if (unlikely(status < 0)) + goto exit; + + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static void as7926_40xfb_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 as7926_40xfb_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 ssize_t access(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int status; + u32 reg, val; + struct i2c_client *client = to_i2c_client(dev); + struct as7926_40xfb_cpld_data *data = i2c_get_clientdata(client); + + if (sscanf(buf, "0x%x 0x%x", ®, &val) != 2) + return -EINVAL; + + if (reg > 0xFF || val > 0xFF) + return -EINVAL; + + mutex_lock(&data->update_lock); + switch(data->index) { + case as7926_40xfb_cpld2: status = as7926_40xfb_cpld_write(12,0x62, reg, val); + break; + case as7926_40xfb_cpld3: status = as7926_40xfb_cpld_write(13,0x63, reg, val); + break; + case as7926_40xfb_cpld4: status = as7926_40xfb_cpld_write(76,0x64, reg, val); + break; + default: status = -ENXIO; + break; + } + + if (unlikely(status < 0)) + goto exit; + + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t show_version(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as7926_40xfb_cpld_data *data = i2c_get_clientdata(client); + int status = 0; + + mutex_lock(&data->update_lock); + switch(data->index) { + case as7926_40xfb_cpld2: status = as7926_40xfb_cpld_read(12,0x62, 0x1); + break; + case as7926_40xfb_cpld3: status = as7926_40xfb_cpld_read(13,0x63, 0x1); + break; + case as7926_40xfb_cpld4: status = as7926_40xfb_cpld_read(76,0x64, 0x1); + break; + default: status = -1; + break; + } + + if (unlikely(status < 0)) { + mutex_unlock(&data->update_lock); + goto exit; + } + + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", status); +exit: + return status; +} + + +static int as7926_40xfb_cpld_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + int status; + struct as7926_40xfb_cpld_data *data = NULL; + + 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; + } + + data = kzalloc(sizeof(struct as7926_40xfb_cpld_data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + data->index = dev_id->driver_data; + mutex_init(&data->update_lock); + dev_info(&client->dev, "chip found\n"); + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, cpld_groups[data->index]); + if (status) + goto exit_free; + + data->hwmon_dev = hwmon_device_register_with_info(&client->dev, DRVNAME, NULL, NULL, NULL); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + as7926_40xfb_cpld_add_client(client); + + dev_info(&client->dev, "%s: cpld '%s'\n", + dev_name(data->hwmon_dev), client->name); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, cpld_groups[data->index]); +exit_free: + kfree(data); +exit: + + return status; +} + +static int as7926_40xfb_cpld_remove(struct i2c_client *client) +{ + struct as7926_40xfb_cpld_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, cpld_groups[data->index]); + kfree(data); + as7926_40xfb_cpld_remove_client(client); + + return 0; +} + +static const struct i2c_device_id as7926_40xfb_cpld_id[] = { + { "as7926_40xfb_cpld2", as7926_40xfb_cpld2 }, + { "as7926_40xfb_cpld3", as7926_40xfb_cpld3 }, + { "as7926_40xfb_cpld4", as7926_40xfb_cpld4 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, as7926_40xfb_cpld_id); + +static struct i2c_driver as7926_40xfb_cpld_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = DRVNAME, + }, + .probe = as7926_40xfb_cpld_probe, + .remove = as7926_40xfb_cpld_remove, + .id_table = as7926_40xfb_cpld_id, + .address_list = normal_i2c, +}; + +static int __init as7926_40xfb_cpld_init(void) +{ + mutex_init(&list_lock); + return i2c_add_driver(&as7926_40xfb_cpld_driver); +} + +static void __exit as7926_40xfb_cpld_exit(void) +{ + i2c_del_driver(&as7926_40xfb_cpld_driver); +} + +module_init(as7926_40xfb_cpld_init); +module_exit(as7926_40xfb_cpld_exit); + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("as7926_40xfb_cpld driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/modules/x86-64-accton-as7926-40xfb-fan.c b/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/modules/x86-64-accton-as7926-40xfb-fan.c new file mode 100644 index 00000000000..0d33835be75 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/modules/x86-64-accton-as7926-40xfb-fan.c @@ -0,0 +1,733 @@ +/* + * Copyright (C) Brandon Chuang + * + * + * Based on: + * pca954x.c from Kumar Gala + * Copyright (C) 2006 + * + * Based on: + * pca954x.c from Ken Harrenstien + * Copyright (C) 2004 Google, Inc. (Ken Harrenstien) + * + * Based on: + * i2c-virtual_cb.c from Brian Kuschak + * and + * pca9540.c from Jean Delvare . + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as7926_40xfb_fan" +#define ACCTON_IPMI_NETFN 0x34 +#define IPMI_FAN_READ_CMD 0x14 +#define IPMI_FAN_WRITE_CMD 0x15 +#define IPMI_FAN_READ_RPM_CMD 0x20 +#define IPMI_TIMEOUT (5 * HZ) +#define IPMI_ERR_RETRY_TIMES 1 +#define IPMI_FAN_REG_READ_CMD 0x20 +#define IPMI_FAN_REG_WRITE_CMD 0x21 + +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); +static ssize_t set_fan(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t show_fan(struct device *dev, struct device_attribute *attr, + char *buf); +static ssize_t show_version(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_dir(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_threshold(struct device *dev, struct device_attribute *da, + char *buf); +static int as7926_40xfb_fan_probe(struct platform_device *pdev); +static int as7926_40xfb_fan_remove(struct platform_device *pdev); + +enum fan_id { + FAN_1, + FAN_2, + FAN_3, + FAN_4, + FAN_5, + FAN_6, + FAN_7, + FAN_8, + FAN_9, + FAN_10, + NUM_OF_FAN, + NUM_OF_FAN_MODULE = NUM_OF_FAN/2 +}; + +enum fan_data_index { + FAN_PRESENT, + FAN_PWM, + FAN_SPEED0, + FAN_SPEED1, + FAN_DATA_COUNT, + + FAN_TARGET_SPEED0 = 0, + FAN_TARGET_SPEED1, + FAN_SPEED_TOLERANCE, + FAN_SPEED_DATA_COUNT +}; + +struct ipmi_data { + struct completion read_complete; + struct ipmi_addr address; + struct ipmi_user *user; + int interface; + + struct kernel_ipmi_msg tx_message; + long tx_msgid; + + void *rx_msg_data; + unsigned short rx_msg_len; + unsigned char rx_result; + int rx_recv_type; + + struct ipmi_user_hndl ipmi_hndlrs; +}; + +struct as7926_40xfb_fan_data { + struct platform_device *pdev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + /* 4 bytes for each fan, the last 2 bytes is fan dir */ + unsigned char ipmi_resp[NUM_OF_FAN * FAN_DATA_COUNT + 2]; + unsigned char ipmi_resp_cpld; + unsigned char ipmi_resp_speed[NUM_OF_FAN * FAN_SPEED_DATA_COUNT]; + struct ipmi_data ipmi; + unsigned char ipmi_tx_data[3]; /* 0: FAN id, 1: 0x02, 2: PWM */ +}; + +struct as7926_40xfb_fan_data *data = NULL; + +static struct platform_driver as7926_40xfb_fan_driver = { + .probe = as7926_40xfb_fan_probe, + .remove = as7926_40xfb_fan_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +#define FAN_PRESENT_ATTR_ID(index) FAN##index##_PRESENT +#define FAN_PWM_ATTR_ID(index) FAN##index##_PWM +#define FAN_RPM_ATTR_ID(index) FAN##index##_INPUT +#define FAN_DIR_ATTR_ID(index) FAN##index##_DIR +#define FAN_RPM_TARGET_ATTR_ID(index) FAN##index##_TARGET +#define FAN_RPM_TOLERANCE_ATTR_ID(index) FAN##index##_TOLERANCE + +#define FAN_ATTR(fan_id) \ + FAN_PRESENT_ATTR_ID(fan_id), \ + FAN_PWM_ATTR_ID(fan_id), \ + FAN_RPM_ATTR_ID(fan_id), \ + FAN_DIR_ATTR_ID(fan_id) + +#define FAN_RPM_THRESHOLD_ATTR(fan_id) \ + FAN_RPM_TARGET_ATTR_ID(fan_id), \ + FAN_RPM_TOLERANCE_ATTR_ID(fan_id) + +enum as7926_40xfb_fan_sysfs_attrs { + FAN_ATTR(1), + FAN_ATTR(2), + FAN_ATTR(3), + FAN_ATTR(4), + FAN_ATTR(5), + FAN_ATTR(6), + FAN_ATTR(7), + FAN_ATTR(8), + FAN_ATTR(9), + FAN_ATTR(10), + NUM_OF_FAN_ATTR, + FAN_VERSION, + NUM_OF_PER_FAN_ATTR = (NUM_OF_FAN_ATTR/NUM_OF_FAN), + FAN_RPM_THRESHOLD_ATTR(1), + FAN_RPM_THRESHOLD_ATTR(2), + FAN_RPM_THRESHOLD_ATTR(3), + FAN_RPM_THRESHOLD_ATTR(4), + FAN_RPM_THRESHOLD_ATTR(5), + FAN_RPM_THRESHOLD_ATTR(6), + FAN_RPM_THRESHOLD_ATTR(7), + FAN_RPM_THRESHOLD_ATTR(8), + FAN_RPM_THRESHOLD_ATTR(9), + FAN_RPM_THRESHOLD_ATTR(10), +}; + +/* fan attributes */ +#define DECLARE_FAN_VER_SENSOR_DEVICE_ATTR() \ + static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, NULL, FAN_VERSION) +#define DECLARE_FAN_VER_ATTR() \ + &sensor_dev_attr_version.dev_attr.attr + +#define DECLARE_FAN_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_present, S_IRUGO, show_fan, NULL, \ + FAN##index##_PRESENT); \ + static SENSOR_DEVICE_ATTR(fan##index##_pwm, S_IWUSR | S_IRUGO, show_fan, \ + set_fan, FAN##index##_PWM); \ + static SENSOR_DEVICE_ATTR(fan##index##_input, S_IRUGO, show_fan, NULL, \ + FAN##index##_INPUT); \ + static SENSOR_DEVICE_ATTR(fan##index##_dir, S_IRUGO, show_dir, NULL, \ + FAN##index##_DIR); \ + static SENSOR_DEVICE_ATTR(fan##index##_target, S_IRUGO, show_threshold, \ + NULL, FAN##index##_TARGET); \ + static SENSOR_DEVICE_ATTR(fan##index##_tolerance, S_IRUGO, show_threshold, \ + NULL, FAN##index##_TOLERANCE) + +#define DECLARE_FAN_ATTR(index) \ + &sensor_dev_attr_fan##index##_present.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_pwm.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_input.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_dir.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_target.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_tolerance.dev_attr.attr + +DECLARE_FAN_SENSOR_DEVICE_ATTR(1); +DECLARE_FAN_SENSOR_DEVICE_ATTR(2); +DECLARE_FAN_SENSOR_DEVICE_ATTR(3); +DECLARE_FAN_SENSOR_DEVICE_ATTR(4); +DECLARE_FAN_SENSOR_DEVICE_ATTR(5); +DECLARE_FAN_SENSOR_DEVICE_ATTR(6); +DECLARE_FAN_SENSOR_DEVICE_ATTR(7); +DECLARE_FAN_SENSOR_DEVICE_ATTR(8); +DECLARE_FAN_SENSOR_DEVICE_ATTR(9); +DECLARE_FAN_SENSOR_DEVICE_ATTR(10); +DECLARE_FAN_VER_SENSOR_DEVICE_ATTR(); + +static struct attribute *as7926_40xfb_fan_attributes[] = { + /* fan attributes */ + DECLARE_FAN_ATTR(1), + DECLARE_FAN_ATTR(2), + DECLARE_FAN_ATTR(3), + DECLARE_FAN_ATTR(4), + DECLARE_FAN_ATTR(5), + DECLARE_FAN_ATTR(6), + DECLARE_FAN_ATTR(7), + DECLARE_FAN_ATTR(8), + DECLARE_FAN_ATTR(9), + DECLARE_FAN_ATTR(10), + DECLARE_FAN_VER_ATTR(), + NULL +}; + +static const struct attribute_group as7926_40xfb_fan_group = { + .attrs = as7926_40xfb_fan_attributes, +}; + +/* Functions to talk to the IPMI layer */ + +/* Initialize IPMI address, message buffers and user data */ +static int init_ipmi_data(struct ipmi_data *ipmi, int iface, + struct device *dev) +{ + int err; + + init_completion(&ipmi->read_complete); + + /* Initialize IPMI address */ + ipmi->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + ipmi->address.channel = IPMI_BMC_CHANNEL; + ipmi->address.data[0] = 0; + ipmi->interface = iface; + + /* Initialize message buffers */ + ipmi->tx_msgid = 0; + ipmi->tx_message.netfn = ACCTON_IPMI_NETFN; + + ipmi->ipmi_hndlrs.ipmi_recv_hndl = ipmi_msg_handler; + + /* Create IPMI messaging interface user */ + err = ipmi_create_user(ipmi->interface, &ipmi->ipmi_hndlrs, + ipmi, &ipmi->user); + if (err < 0) { + dev_err(dev, "Unable to register user with IPMI " + "interface %d\n", ipmi->interface); + return -EACCES; + } + + return 0; +} + +/* Send an IPMI command */ +static int _ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int err; + + ipmi->tx_message.cmd = cmd; + ipmi->tx_message.data = tx_data; + ipmi->tx_message.data_len = tx_len; + ipmi->rx_msg_data = rx_data; + ipmi->rx_msg_len = rx_len; + + err = ipmi_validate_addr(&ipmi->address, sizeof(ipmi->address)); + if (err) + goto addr_err; + + ipmi->tx_msgid++; + err = ipmi_request_settime(ipmi->user, &ipmi->address, ipmi->tx_msgid, + &ipmi->tx_message, ipmi, 0, 0, 0); + if (err) + goto ipmi_req_err; + + err = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); + if (!err) + goto ipmi_timeout_err; + + return 0; + +ipmi_timeout_err: + err = -ETIMEDOUT; + dev_err(&data->pdev->dev, "request_timeout=%x\n", err); + return err; +ipmi_req_err: + dev_err(&data->pdev->dev, "request_settime=%x\n", err); + return err; +addr_err: + dev_err(&data->pdev->dev, "validate_addr=%x\n", err); + return err; +} + +/* Send an IPMI command with retry */ +static int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int status = 0, retry = 0; + + for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { + status = _ipmi_send_message(ipmi, cmd, tx_data, tx_len, rx_data, rx_len); + if (unlikely(status != 0)) { + dev_err(&data->pdev->dev, "ipmi_send_message_%d err status(%d)\r\n", + retry, status); + continue; + } + + if (unlikely(ipmi->rx_result != 0)) { + dev_err(&data->pdev->dev, "ipmi_send_message_%d err result(%d)\r\n", + retry, ipmi->rx_result); + continue; + } + + break; + } + + return status; +} + +/* Dispatch IPMI messages to callers */ +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) +{ + unsigned short rx_len; + struct ipmi_data *ipmi = user_msg_data; + + if (msg->msgid != ipmi->tx_msgid) { + dev_err(&data->pdev->dev, "Mismatch between received msgid " + "(%02x) and transmitted msgid (%02x)!\n", + (int)msg->msgid, + (int)ipmi->tx_msgid); + ipmi_free_recv_msg(msg); + return; + } + + ipmi->rx_recv_type = msg->recv_type; + if (msg->msg.data_len > 0) + ipmi->rx_result = msg->msg.data[0]; + else + ipmi->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE; + + if (msg->msg.data_len > 1) { + rx_len = msg->msg.data_len - 1; + if (ipmi->rx_msg_len < rx_len) + rx_len = ipmi->rx_msg_len; + ipmi->rx_msg_len = rx_len; + memcpy(ipmi->rx_msg_data, msg->msg.data + 1, ipmi->rx_msg_len); + } else + ipmi->rx_msg_len = 0; + + ipmi_free_recv_msg(msg); + complete(&ipmi->read_complete); +} + +static struct as7926_40xfb_fan_data *as7926_40xfb_fan_update_device(void) +{ + int status = 0; + + if (time_before(jiffies, data->last_updated + HZ * 5) && data->valid) + return data; + + data->valid = 0; + status = ipmi_send_message(&data->ipmi, IPMI_FAN_READ_CMD, NULL, 0, + data->ipmi_resp, sizeof(data->ipmi_resp)); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + data->ipmi_tx_data[0] = IPMI_FAN_READ_RPM_CMD; + status = ipmi_send_message(&data->ipmi, IPMI_FAN_READ_CMD, + data->ipmi_tx_data, 1, + data->ipmi_resp_speed, + sizeof(data->ipmi_resp_speed)); + + data->last_updated = jiffies; + data->valid = 1; + +exit: + return data; +} + +static ssize_t show_fan(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + unsigned char fid = attr->index / NUM_OF_PER_FAN_ATTR; + int value = 0; + int index = 0; + int present = 0; + int error = 0; + + mutex_lock(&data->update_lock); + + data = as7926_40xfb_fan_update_device(); + if (!data->valid) { + error = -EIO; + goto exit; + } + + index = fid * FAN_DATA_COUNT; /* base index */ + present = !!data->ipmi_resp[index + FAN_PRESENT]; + + 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: + value = present; + break; + 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: + index = (fid % NUM_OF_FAN_MODULE) * FAN_DATA_COUNT; + value = (data->ipmi_resp[index + FAN_PWM] + 1) * 625 / 100; + break; + 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: + value = (int)data->ipmi_resp[index + FAN_SPEED0] | + (int)data->ipmi_resp[index + FAN_SPEED1] << 8; + break; + default: + error = -EINVAL; + goto exit; + } + + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", present ? value : 0); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static ssize_t set_fan(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + long pwm; + int status; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + unsigned char fid = attr->index / NUM_OF_PER_FAN_ATTR; + + status = kstrtol(buf, 10, &pwm); + if (status) + return status; + + pwm = (pwm * 100) / 625 - 1; /* Convert pwm to register value */ + + mutex_lock(&data->update_lock); + + /* Send IPMI write command */ + data->ipmi_tx_data[0] = (fid % NUM_OF_FAN_MODULE) + 1; + data->ipmi_tx_data[1] = 0x02; + data->ipmi_tx_data[2] = pwm; + status = ipmi_send_message(&data->ipmi, IPMI_FAN_WRITE_CMD, + data->ipmi_tx_data, sizeof(data->ipmi_tx_data), + NULL, 0); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + /* Update pwm to ipmi_resp buffer to prevent from the impact of lazy update */ + data->ipmi_resp[fid * FAN_DATA_COUNT + FAN_PWM] = pwm; + status = count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static struct as7926_40xfb_fan_data *as7926_40xfb_fan_update_cpld_ver(void) +{ + int status = 0; + + data->valid = 0; + data->ipmi_tx_data[0] = 0x66; + status = ipmi_send_message(&data->ipmi, IPMI_FAN_REG_READ_CMD, + data->ipmi_tx_data, 1, + &data->ipmi_resp_cpld, + sizeof(data->ipmi_resp_cpld)); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + data->last_updated = jiffies; + data->valid = 1; + +exit: + return data; +} + +static ssize_t show_version(struct device *dev, struct device_attribute *da, + char *buf) +{ + unsigned char value = 0; + int error = 0; + + mutex_lock(&data->update_lock); + + data = as7926_40xfb_fan_update_cpld_ver(); + if (!data->valid) { + error = -EIO; + goto exit; + } + + value = data->ipmi_resp_cpld; + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", value); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static ssize_t show_dir(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + unsigned char fid = (attr->index / NUM_OF_PER_FAN_ATTR); + int value = 0; + int index = 0; + int present = 0; + int error = 0; + + mutex_lock(&data->update_lock); + + data = as7926_40xfb_fan_update_device(); + if (!data->valid) { + error = -EIO; + goto exit; + } + + index = fid * FAN_DATA_COUNT; /* base index */ + present = !!data->ipmi_resp[index + FAN_PRESENT]; + + value = data->ipmi_resp[40] | (data->ipmi_resp[41] << 8); + mutex_unlock(&data->update_lock); + + if (!present) + return sprintf(buf, "0\n"); + else + return sprintf(buf, "%s\n", + (value & BIT(fid % NUM_OF_FAN_MODULE)) ? "B2F" : "F2B"); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static ssize_t show_threshold(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + int value = 0; + int index = 0; + int error = 0; + + mutex_lock(&data->update_lock); + + data = as7926_40xfb_fan_update_device(); + if (!data->valid) { + error = -EIO; + goto exit; + } + + switch (attr->index) { + case FAN1_TARGET: + case FAN2_TARGET: + case FAN3_TARGET: + case FAN4_TARGET: + case FAN5_TARGET: + value = (int)data->ipmi_resp_speed[FAN_TARGET_SPEED0] | + (int)data->ipmi_resp_speed[FAN_TARGET_SPEED1] << 8; + break; + case FAN6_TARGET: + case FAN7_TARGET: + case FAN8_TARGET: + case FAN9_TARGET: + case FAN10_TARGET: + index = NUM_OF_FAN_MODULE * FAN_SPEED_DATA_COUNT; + value = (int)data->ipmi_resp_speed[index + FAN_TARGET_SPEED0] | + (int)data->ipmi_resp_speed[index + FAN_TARGET_SPEED1] << 8; + break; + case FAN1_TOLERANCE: + case FAN2_TOLERANCE: + case FAN3_TOLERANCE: + case FAN4_TOLERANCE: + case FAN5_TOLERANCE: + value = (int)data->ipmi_resp_speed[FAN_SPEED_TOLERANCE]; + break; + case FAN6_TOLERANCE: + case FAN7_TOLERANCE: + case FAN8_TOLERANCE: + case FAN9_TOLERANCE: + case FAN10_TOLERANCE: + index = NUM_OF_FAN_MODULE * FAN_SPEED_DATA_COUNT; + value = (int)data->ipmi_resp_speed[index + FAN_SPEED_TOLERANCE]; + break; + default: + error = -EINVAL; + goto exit; + } + + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", value); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static int as7926_40xfb_fan_probe(struct platform_device *pdev) +{ + int status = -1; + + /* Register sysfs hooks */ + status = sysfs_create_group(&pdev->dev.kobj, &as7926_40xfb_fan_group); + if (status) + goto exit; + + dev_info(&pdev->dev, "device created\n"); + + return 0; + +exit: + return status; +} + +static int as7926_40xfb_fan_remove(struct platform_device *pdev) +{ + sysfs_remove_group(&pdev->dev.kobj, &as7926_40xfb_fan_group); + + return 0; +} + +static int __init as7926_40xfb_fan_init(void) +{ + int ret; + + data = kzalloc(sizeof(struct as7926_40xfb_fan_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto alloc_err; + } + + mutex_init(&data->update_lock); + data->valid = 0; + + ret = platform_driver_register(&as7926_40xfb_fan_driver); + if (ret < 0) + goto dri_reg_err; + + data->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(data->pdev)) { + ret = PTR_ERR(data->pdev); + goto dev_reg_err; + } + + /* Set up IPMI interface */ + ret = init_ipmi_data(&data->ipmi, 0, &data->pdev->dev); + if (ret) + goto ipmi_err; + + return 0; + +ipmi_err: + platform_device_unregister(data->pdev); +dev_reg_err: + platform_driver_unregister(&as7926_40xfb_fan_driver); +dri_reg_err: + kfree(data); +alloc_err: + return ret; +} + +static void __exit as7926_40xfb_fan_exit(void) +{ + ipmi_destroy_user(data->ipmi.user); + platform_device_unregister(data->pdev); + platform_driver_unregister(&as7926_40xfb_fan_driver); + kfree(data); +} + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("as7926_40xfb fan driver"); +MODULE_LICENSE("GPL"); + +module_init(as7926_40xfb_fan_init); +module_exit(as7926_40xfb_fan_exit); diff --git a/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/modules/x86-64-accton-as7926-40xfb-leds.c b/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/modules/x86-64-accton-as7926-40xfb-leds.c new file mode 100644 index 00000000000..28b32c4e7ee --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/modules/x86-64-accton-as7926-40xfb-leds.c @@ -0,0 +1,504 @@ +/* + * Copyright (C) Brandon Chuang + * + * Based on: + * pca954x.c from Kumar Gala + * Copyright (C) 2006 + * + * Based on: + * pca954x.c from Ken Harrenstien + * Copyright (C) 2004 Google, Inc. (Ken Harrenstien) + * + * Based on: + * i2c-virtual_cb.c from Brian Kuschak + * and + * pca9540.c from Jean Delvare . + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as7926_40xfb_led" +#define ACCTON_IPMI_NETFN 0x34 +#define IPMI_LED_READ_CMD 0x1A +#define IPMI_LED_WRITE_CMD 0x1B +#define IPMI_TIMEOUT (5 * HZ) +#define IPMI_ERR_RETRY_TIMES 1 + +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); +static ssize_t set_led(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t show_led(struct device *dev, struct device_attribute *attr, + char *buf); +static int as7926_40xfb_led_probe(struct platform_device *pdev); +static int as7926_40xfb_led_remove(struct platform_device *pdev); + +struct ipmi_data { + struct completion read_complete; + struct ipmi_addr address; + struct ipmi_user *user; + int interface; + + struct kernel_ipmi_msg tx_message; + long tx_msgid; + + void *rx_msg_data; + unsigned short rx_msg_len; + unsigned char rx_result; + int rx_recv_type; + + struct ipmi_user_hndl ipmi_hndlrs; +}; + +struct as7926_40xfb_led_data { + struct platform_device *pdev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + unsigned char ipmi_resp[4]; /* 0:PSU 1:FAN 2:DIAG 3:LOC */ + struct ipmi_data ipmi; +}; + +struct as7926_40xfb_led_data *data = NULL; + +static struct platform_driver as7926_40xfb_led_driver = { + .probe = as7926_40xfb_led_probe, + .remove = as7926_40xfb_led_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +enum ipmi_led_light_mode { + IPMI_LED_MODE_OFF, + IPMI_LED_MODE_RED = 2, + IPMI_LED_MODE_RED_BLINKING = 3, + IPMI_LED_MODE_GREEN = 4, + IPMI_LED_MODE_GREEN_BLINKING = 5, + IPMI_LED_MODE_BLUE = 8, + IPMI_LED_MODE_BLUE_BLINKING = 9, +}; + +enum led_light_mode { + LED_MODE_OFF, + LED_MODE_RED = 10, + LED_MODE_RED_BLINKING = 11, + LED_MODE_ORANGE = 12, + LED_MODE_ORANGE_BLINKING = 13, + LED_MODE_YELLOW = 14, + LED_MODE_YELLOW_BLINKING = 15, + LED_MODE_GREEN = 16, + LED_MODE_GREEN_BLINKING = 17, + LED_MODE_BLUE = 18, + LED_MODE_BLUE_BLINKING = 19, + LED_MODE_PURPLE = 20, + LED_MODE_PURPLE_BLINKING = 21, + LED_MODE_AUTO = 22, + LED_MODE_AUTO_BLINKING = 23, + LED_MODE_WHITE = 24, + LED_MODE_WHITE_BLINKING = 25, + LED_MODE_CYAN = 26, + LED_MODE_CYAN_BLINKING = 27, + LED_MODE_UNKNOWN = 99 +}; + +enum as7926_40xfb_led_sysfs_attrs { + LED_PSU, + LED_LOC, + LED_DIAG, + LED_FAN +}; + +static SENSOR_DEVICE_ATTR(led_loc, S_IWUSR | S_IRUGO, show_led, set_led, + LED_LOC); +static SENSOR_DEVICE_ATTR(led_diag, S_IWUSR | S_IRUGO, show_led, set_led, + LED_DIAG); +static SENSOR_DEVICE_ATTR(led_psu, S_IRUGO, show_led, NULL, LED_PSU); +static SENSOR_DEVICE_ATTR(led_fan, S_IRUGO, show_led, NULL, LED_FAN); + +static struct attribute *as7926_40xfb_led_attributes[] = { + &sensor_dev_attr_led_loc.dev_attr.attr, + &sensor_dev_attr_led_diag.dev_attr.attr, + &sensor_dev_attr_led_psu.dev_attr.attr, + &sensor_dev_attr_led_fan.dev_attr.attr, + NULL +}; + +static const struct attribute_group as7926_40xfb_led_group = { + .attrs = as7926_40xfb_led_attributes, +}; + +/* Functions to talk to the IPMI layer */ + +/* Initialize IPMI address, message buffers and user data */ +static int init_ipmi_data(struct ipmi_data *ipmi, int iface, + struct device *dev) +{ + int err; + + init_completion(&ipmi->read_complete); + + /* Initialize IPMI address */ + ipmi->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + ipmi->address.channel = IPMI_BMC_CHANNEL; + ipmi->address.data[0] = 0; + ipmi->interface = iface; + + /* Initialize message buffers */ + ipmi->tx_msgid = 0; + ipmi->tx_message.netfn = ACCTON_IPMI_NETFN; + + ipmi->ipmi_hndlrs.ipmi_recv_hndl = ipmi_msg_handler; + + /* Create IPMI messaging interface user */ + err = ipmi_create_user(ipmi->interface, &ipmi->ipmi_hndlrs, + ipmi, &ipmi->user); + if (err < 0) { + dev_err(dev, "Unable to register user with IPMI " + "interface %d\n", ipmi->interface); + return -EACCES; + } + + return 0; +} + +/* Send an IPMI command */ +static int _ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int err; + + ipmi->tx_message.cmd = cmd; + ipmi->tx_message.data = tx_data; + ipmi->tx_message.data_len = tx_len; + ipmi->rx_msg_data = rx_data; + ipmi->rx_msg_len = rx_len; + + err = ipmi_validate_addr(&ipmi->address, sizeof(ipmi->address)); + if (err) + goto addr_err; + + ipmi->tx_msgid++; + err = ipmi_request_settime(ipmi->user, &ipmi->address, ipmi->tx_msgid, + &ipmi->tx_message, ipmi, 0, 0, 0); + if (err) + goto ipmi_req_err; + + err = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); + if (!err) + goto ipmi_timeout_err; + + return 0; + +ipmi_timeout_err: + err = -ETIMEDOUT; + dev_err(&data->pdev->dev, "request_timeout=%x\n", err); + return err; +ipmi_req_err: + dev_err(&data->pdev->dev, "request_settime=%x\n", err); + return err; +addr_err: + dev_err(&data->pdev->dev, "validate_addr=%x\n", err); + return err; +} + +/* Send an IPMI command with retry */ +static int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int status = 0, retry = 0; + + for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { + status = _ipmi_send_message(ipmi, cmd, tx_data, tx_len, rx_data, rx_len); + if (unlikely(status != 0)) { + dev_err(&data->pdev->dev, "ipmi_send_message_%d err status(%d)\r\n", + retry, status); + continue; + } + + if (unlikely(ipmi->rx_result != 0)) { + dev_err(&data->pdev->dev, "ipmi_send_message_%d err result(%d)\r\n", + retry, ipmi->rx_result); + continue; + } + + break; + } + + return status; +} + +/* Dispatch IPMI messages to callers */ +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) +{ + unsigned short rx_len; + struct ipmi_data *ipmi = user_msg_data; + + if (msg->msgid != ipmi->tx_msgid) { + dev_err(&data->pdev->dev, "Mismatch between received msgid " + "(%02x) and transmitted msgid (%02x)!\n", + (int)msg->msgid, + (int)ipmi->tx_msgid); + ipmi_free_recv_msg(msg); + return; + } + + ipmi->rx_recv_type = msg->recv_type; + if (msg->msg.data_len > 0) + ipmi->rx_result = msg->msg.data[0]; + else + ipmi->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE; + + if (msg->msg.data_len > 1) { + rx_len = msg->msg.data_len - 1; + if (ipmi->rx_msg_len < rx_len) + rx_len = ipmi->rx_msg_len; + ipmi->rx_msg_len = rx_len; + memcpy(ipmi->rx_msg_data, msg->msg.data + 1, ipmi->rx_msg_len); + } else + ipmi->rx_msg_len = 0; + + ipmi_free_recv_msg(msg); + complete(&ipmi->read_complete); +} + +static struct as7926_40xfb_led_data *as7926_40xfb_led_update_device(void) +{ + int status = 0; + + if (time_before(jiffies, data->last_updated + HZ * 5) && data->valid) { + return data; + } + + data->valid = 0; + status = ipmi_send_message(&data->ipmi, IPMI_LED_READ_CMD, NULL, 0, + data->ipmi_resp, sizeof(data->ipmi_resp)); + if (unlikely(status != 0)) { + goto exit; + } + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + data->last_updated = jiffies; + data->valid = 1; + +exit: + return data; +} + +static ssize_t show_led(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + int value = 0; + int error = 0; + + if (attr->index == LED_PSU || attr->index == LED_FAN) + return sprintf(buf, "%d\n", LED_MODE_AUTO); + + mutex_lock(&data->update_lock); + + data = as7926_40xfb_led_update_device(); + if (!data->valid) { + error = -EIO; + goto exit; + } + + switch (data->ipmi_resp[attr->index]) { + case IPMI_LED_MODE_OFF: + value = LED_MODE_OFF; + break; + case IPMI_LED_MODE_RED: + value = LED_MODE_RED; + break; + case IPMI_LED_MODE_RED_BLINKING: + value = LED_MODE_RED_BLINKING; + break; + case IPMI_LED_MODE_GREEN: + value = LED_MODE_GREEN; + break; + case IPMI_LED_MODE_GREEN_BLINKING: + value = LED_MODE_GREEN_BLINKING; + break; + case IPMI_LED_MODE_BLUE: + value = LED_MODE_BLUE; + break; + case IPMI_LED_MODE_BLUE_BLINKING: + value = LED_MODE_BLUE_BLINKING; + break; + default: + error = -EINVAL; + goto exit; + } + + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", value); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static ssize_t set_led(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + long mode; + int status; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + + status = kstrtol(buf, 10, &mode); + if (status) + return status; + + mutex_lock(&data->update_lock); + + data = as7926_40xfb_led_update_device(); + if (!data->valid) { + status = -EIO; + goto exit; + } + + data->ipmi_resp[0] = attr->index + 1; + + switch (mode) { + case LED_MODE_OFF: + data->ipmi_resp[1] = IPMI_LED_MODE_OFF; + break; + case LED_MODE_RED: + data->ipmi_resp[1] = IPMI_LED_MODE_RED; + break; + case LED_MODE_RED_BLINKING: + data->ipmi_resp[1] = IPMI_LED_MODE_RED_BLINKING; + break; + case LED_MODE_GREEN: + data->ipmi_resp[1] = IPMI_LED_MODE_GREEN; + break; + case LED_MODE_GREEN_BLINKING: + data->ipmi_resp[1] = IPMI_LED_MODE_GREEN_BLINKING; + break; + case LED_MODE_BLUE: + data->ipmi_resp[1] = IPMI_LED_MODE_BLUE; + break; + case LED_MODE_BLUE_BLINKING: + data->ipmi_resp[1] = IPMI_LED_MODE_BLUE_BLINKING; + break; + default: + status = -EINVAL; + goto exit; + } + + /* Send IPMI write command */ + status = ipmi_send_message(&data->ipmi, IPMI_LED_WRITE_CMD, + data->ipmi_resp, 2, NULL, 0); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + status = count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static int as7926_40xfb_led_probe(struct platform_device *pdev) +{ + int status = -1; + + /* Register sysfs hooks */ + status = sysfs_create_group(&pdev->dev.kobj, &as7926_40xfb_led_group); + if (status) + goto exit; + + dev_info(&pdev->dev, "device created\n"); + + return 0; + +exit: + return status; +} + +static int as7926_40xfb_led_remove(struct platform_device *pdev) +{ + sysfs_remove_group(&pdev->dev.kobj, &as7926_40xfb_led_group); + + return 0; +} + +static int __init as7926_40xfb_led_init(void) +{ + int ret; + + data = kzalloc(sizeof(struct as7926_40xfb_led_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto alloc_err; + } + + mutex_init(&data->update_lock); + data->valid = 0; + + ret = platform_driver_register(&as7926_40xfb_led_driver); + if (ret < 0) + goto dri_reg_err; + + data->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(data->pdev)) { + ret = PTR_ERR(data->pdev); + goto dev_reg_err; + } + + /* Set up IPMI interface */ + ret = init_ipmi_data(&data->ipmi, 0, &data->pdev->dev); + if (ret) + goto ipmi_err; + + return 0; + +ipmi_err: + platform_device_unregister(data->pdev); +dev_reg_err: + platform_driver_unregister(&as7926_40xfb_led_driver); +dri_reg_err: + kfree(data); +alloc_err: + return ret; +} + +static void __exit as7926_40xfb_led_exit(void) +{ + ipmi_destroy_user(data->ipmi.user); + platform_device_unregister(data->pdev); + platform_driver_unregister(&as7926_40xfb_led_driver); + kfree(data); +} + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("AS7926 40XFB led driver"); +MODULE_LICENSE("GPL"); + +module_init(as7926_40xfb_led_init); +module_exit(as7926_40xfb_led_exit); diff --git a/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/modules/x86-64-accton-as7926-40xfb-psu.c b/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/modules/x86-64-accton-as7926-40xfb-psu.c new file mode 100644 index 00000000000..a07ad4cbfa2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/modules/x86-64-accton-as7926-40xfb-psu.c @@ -0,0 +1,914 @@ +/* + * Copyright (C) Brandon Chuang + * Based on: + * pca954x.c from Kumar Gala + * Copyright (C) 2006 + * + * Based on: + * pca954x.c from Ken Harrenstien + * Copyright (C) 2004 Google, Inc. (Ken Harrenstien) + * + * Based on: + * i2c-virtual_cb.c from Brian Kuschak + * and + * pca9540.c from Jean Delvare . + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as7926_40xfb_psu" +#define ACCTON_IPMI_NETFN 0x34 +#define IPMI_PSU_READ_CMD 0x16 +#define IPMI_PSU_MODEL_NAME_CMD 0x10 +#define IPMI_PSU_SERIAL_NUM_CMD 0x11 +#define IPMI_PSU_FAN_DIR_CMD 0x13 +#define IPMI_PSU_INFO_CMD 0x20 +#define IPMI_TIMEOUT (5 * HZ) +#define IPMI_ERR_RETRY_TIMES 1 +#define IPMI_MODEL_SERIAL_LEN 32 +#define IPMI_FAN_DIR_LEN 3 + +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); +static ssize_t show_psu(struct device *dev, struct device_attribute *attr, + char *buf); +static ssize_t show_psu_info(struct device *dev, struct device_attribute *attr, + char *buf); +static ssize_t show_string(struct device *dev, struct device_attribute *attr, + char *buf); +static int as7926_40xfb_psu_probe(struct platform_device *pdev); +static int as7926_40xfb_psu_remove(struct platform_device *pdev); + +enum psu_id { + PSU_1, + PSU_2, + NUM_OF_PSU +}; + +enum psu_data_index { + PSU_PRESENT = 0, + PSU_TEMP_FAULT, + PSU_POWER_GOOD_CPLD, + PSU_POWER_GOOD_PMBUS, + PSU_OVER_VOLTAGE, + PSU_OVER_CURRENT, + PSU_POWER_ON, + PSU_VIN0, + PSU_VIN1, + PSU_VIN2, + PSU_VOUT0, + PSU_VOUT1, + PSU_VOUT2, + PSU_IIN0, + PSU_IIN1, + PSU_IIN2, + PSU_IOUT0, + PSU_IOUT1, + PSU_IOUT2, + PSU_PIN0, + PSU_PIN1, + PSU_PIN2, + PSU_PIN3, + PSU_POUT0, + PSU_POUT1, + PSU_POUT2, + PSU_POUT3, + PSU_TEMP0, + PSU_TEMP1, + PSU_FAN0, + PSU_FAN1, + PSU_VOUT_MODE, + PSU_STATUS_COUNT, + PSU_MODEL = 0, + PSU_SERIAL = 0, + PSU_TEMP_MAX0 = 2, + PSU_TEMP_MAX1, + PSU_TEMP_MIN0, + PSU_TEMP_MIN1, + PSU_VIN_UPPER_CRIT0, + PSU_VIN_UPPER_CRIT1, + PSU_VIN_UPPER_CRIT2, + PSU_VIN_MAX0, + PSU_VIN_MAX1, + PSU_VIN_MAX2, + PSU_VIN_MIN0, + PSU_VIN_MIN1, + PSU_VIN_MIN2, + PSU_VIN_LOWER_CRIT0, + PSU_VIN_LOWER_CRIT1, + PSU_VIN_LOWER_CRIT2, + PSU_VOUT_MAX0, + PSU_VOUT_MAX1, + PSU_VOUT_MAX2, + PSU_VOUT_MIN0, + PSU_VOUT_MIN1, + PSU_VOUT_MIN2, + PSU_IIN_MAX0, + PSU_IIN_MAX1, + PSU_IIN_MAX2, + PSU_IOUT_MAX0, + PSU_IOUT_MAX1, + PSU_IOUT_MAX2, + PSU_PIN_MAX0, + PSU_PIN_MAX1, + PSU_PIN_MAX2, + PSU_PIN_MAX3, + PSU_POUT_MAX0, + PSU_POUT_MAX1, + PSU_POUT_MAX2, + PSU_POUT_MAX3, +}; + +struct ipmi_data { + struct completion read_complete; + struct ipmi_addr address; + struct ipmi_user *user; + int interface; + + struct kernel_ipmi_msg tx_message; + long tx_msgid; + + void *rx_msg_data; + unsigned short rx_msg_len; + unsigned char rx_result; + int rx_recv_type; + + struct ipmi_user_hndl ipmi_hndlrs; +}; + +struct ipmi_psu_resp_data { + unsigned char status[32]; + unsigned char info[38]; + char serial[IPMI_MODEL_SERIAL_LEN+1]; + char model[IPMI_MODEL_SERIAL_LEN+1]; + char fandir[IPMI_FAN_DIR_LEN+1]; +}; + +struct as7926_40xfb_psu_data { + struct platform_device *pdev; + struct mutex update_lock; + char valid[3]; /* != 0 if registers are valid, 0: PSU1, 1: PSU2 */ + unsigned long last_updated[3]; /* In jiffies, 0: PSU1, 1: PSU2 */ + struct ipmi_data ipmi; + struct ipmi_psu_resp_data ipmi_resp[3]; /* 0: PSU1, 1: PSU2 */ + unsigned char ipmi_tx_data[2]; +}; + +struct as7926_40xfb_psu_data *data = NULL; + +static struct platform_driver as7926_40xfb_psu_driver = { + .probe = as7926_40xfb_psu_probe, + .remove = as7926_40xfb_psu_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +#define PSU_PRESENT_ATTR_ID(index) PSU##index##_PRESENT +#define PSU_POWERGOOD_ATTR_ID(index) PSU##index##_POWER_GOOD +#define PSU_VIN_ATTR_ID(index) PSU##index##_VIN +#define PSU_VOUT_ATTR_ID(index) PSU##index##_VOUT +#define PSU_IIN_ATTR_ID(index) PSU##index##_IIN +#define PSU_IOUT_ATTR_ID(index) PSU##index##_IOUT +#define PSU_PIN_ATTR_ID(index) PSU##index##_PIN +#define PSU_POUT_ATTR_ID(index) PSU##index##_POUT +#define PSU_MODEL_ATTR_ID(index) PSU##index##_MODEL +#define PSU_SERIAL_ATTR_ID(index) PSU##index##_SERIAL +#define PSU_TEMP_INPUT_ATTR_ID(index) PSU##index##_TEMP_INPUT +#define PSU_FAN_INPUT_ATTR_ID(index) PSU##index##_FAN_INPUT +#define PSU_FAN_DIR_ATTR_ID(index) PSU##index##_FAN_DIR + +#define PSU_TEMP_INPUT_MAX_ATTR_ID(index) PSU##index##_TEMP_INPUT_MAX +#define PSU_TEMP_INPUT_MIN_ATTR_ID(index) PSU##index##_TEMP_INPUT_MIN +#define PSU_VIN_MAX_ATTR_ID(index) PSU##index##_VIN_MAX +#define PSU_VIN_MIN_ATTR_ID(index) PSU##index##_VIN_MIN +#define PSU_VIN_UPPER_CRIT_ATTR_ID(index) PSU##index##_VIN_UPPER_CRIT +#define PSU_VIN_LOWER_CRIT_ATTR_ID(index) PSU##index##_VIN_LOWER_CRIT +#define PSU_VOUT_MAX_ATTR_ID(index) PSU##index##_VOUT_MAX +#define PSU_VOUT_MIN_ATTR_ID(index) PSU##index##_VOUT_MIN +#define PSU_IIN_MAX_ATTR_ID(index) PSU##index##_IIN_MAX +#define PSU_IOUT_MAX_ATTR_ID(index) PSU##index##_IOUT_MAX +#define PSU_PIN_MAX_ATTR_ID(index) PSU##index##_PIN_MAX +#define PSU_POUT_MAX_ATTR_ID(index) PSU##index##_POUT_MAX + +#define PSU_ATTR(psu_id) \ + PSU_PRESENT_ATTR_ID(psu_id), \ + PSU_POWERGOOD_ATTR_ID(psu_id), \ + PSU_VIN_ATTR_ID(psu_id), \ + PSU_VOUT_ATTR_ID(psu_id), \ + PSU_IIN_ATTR_ID(psu_id), \ + PSU_IOUT_ATTR_ID(psu_id), \ + PSU_PIN_ATTR_ID(psu_id), \ + PSU_POUT_ATTR_ID(psu_id), \ + PSU_MODEL_ATTR_ID(psu_id), \ + PSU_SERIAL_ATTR_ID(psu_id), \ + PSU_TEMP_INPUT_ATTR_ID(psu_id), \ + PSU_FAN_INPUT_ATTR_ID(psu_id), \ + PSU_FAN_DIR_ATTR_ID(psu_id), \ + PSU_TEMP_INPUT_MAX_ATTR_ID(psu_id), \ + PSU_TEMP_INPUT_MIN_ATTR_ID(psu_id), \ + PSU_VIN_MAX_ATTR_ID(psu_id), \ + PSU_VIN_MIN_ATTR_ID(psu_id), \ + PSU_VIN_UPPER_CRIT_ATTR_ID(psu_id), \ + PSU_VIN_LOWER_CRIT_ATTR_ID(psu_id), \ + PSU_VOUT_MAX_ATTR_ID(psu_id), \ + PSU_VOUT_MIN_ATTR_ID(psu_id), \ + PSU_IIN_MAX_ATTR_ID(psu_id), \ + PSU_IOUT_MAX_ATTR_ID(psu_id), \ + PSU_PIN_MAX_ATTR_ID(psu_id), \ + PSU_POUT_MAX_ATTR_ID(psu_id) + +enum as7926_40xfb_psu_sysfs_attrs { + /* psu attributes */ + PSU_ATTR(1), + PSU_ATTR(2), + NUM_OF_PSU_ATTR, + NUM_OF_PER_PSU_ATTR = (NUM_OF_PSU_ATTR/NUM_OF_PSU) +}; + +/* psu attributes */ +#define DECLARE_PSU_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(psu##index##_present, S_IRUGO, show_psu, NULL, \ + PSU##index##_PRESENT); \ + static SENSOR_DEVICE_ATTR(psu##index##_power_good, S_IRUGO, show_psu, NULL,\ + PSU##index##_POWER_GOOD); \ + static SENSOR_DEVICE_ATTR(psu##index##_vin, S_IRUGO, show_psu, NULL, \ + PSU##index##_VIN); \ + static SENSOR_DEVICE_ATTR(psu##index##_vout, S_IRUGO, show_psu, NULL, \ + PSU##index##_VOUT); \ + static SENSOR_DEVICE_ATTR(psu##index##_iin, S_IRUGO, show_psu, NULL, \ + PSU##index##_IIN); \ + static SENSOR_DEVICE_ATTR(psu##index##_iout, S_IRUGO, show_psu, NULL, \ + PSU##index##_IOUT); \ + static SENSOR_DEVICE_ATTR(psu##index##_pin, S_IRUGO, show_psu, NULL, \ + PSU##index##_PIN); \ + static SENSOR_DEVICE_ATTR(psu##index##_pout, S_IRUGO, show_psu, NULL, \ + PSU##index##_POUT); \ + static SENSOR_DEVICE_ATTR(psu##index##_model, S_IRUGO, show_string, NULL, \ + PSU##index##_MODEL); \ + static SENSOR_DEVICE_ATTR(psu##index##_serial, S_IRUGO, show_string, NULL,\ + PSU##index##_SERIAL);\ + static SENSOR_DEVICE_ATTR(psu##index##_temp1_input, S_IRUGO, show_psu,NULL,\ + PSU##index##_TEMP_INPUT); \ + static SENSOR_DEVICE_ATTR(psu##index##_fan1_input, S_IRUGO, show_psu, NULL,\ + PSU##index##_FAN_INPUT); \ + static SENSOR_DEVICE_ATTR(psu##index##_fan_dir, S_IRUGO, show_string, NULL,\ + PSU##index##_FAN_DIR); \ + static SENSOR_DEVICE_ATTR(psu##index##_temp1_input_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_TEMP_INPUT_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_temp1_input_min, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_TEMP_INPUT_MIN); \ + static SENSOR_DEVICE_ATTR(psu##index##_vin_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_VIN_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_vin_min, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_VIN_MIN); \ + static SENSOR_DEVICE_ATTR(psu##index##_vin_upper_crit, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_VIN_UPPER_CRIT); \ + static SENSOR_DEVICE_ATTR(psu##index##_vin_lower_crit, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_VIN_LOWER_CRIT); \ + static SENSOR_DEVICE_ATTR(psu##index##_vout_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_VOUT_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_vout_min, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_VOUT_MIN); \ + static SENSOR_DEVICE_ATTR(psu##index##_iin_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_IIN_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_iout_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_IOUT_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_pin_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_PIN_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_pout_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_POUT_MAX) + +#define DECLARE_PSU_ATTR(index) \ + &sensor_dev_attr_psu##index##_present.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_power_good.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_vin.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_vout.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_iin.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_iout.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_pin.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_pout.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_model.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_serial.dev_attr.attr,\ + &sensor_dev_attr_psu##index##_temp1_input.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_fan1_input.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_fan_dir.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_temp1_input_max.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_temp1_input_min.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_vin_max.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_vin_min.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_vin_upper_crit.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_vin_lower_crit.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_vout_max.dev_attr.attr,\ + &sensor_dev_attr_psu##index##_vout_min.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_iin_max.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_iout_max.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_pin_max.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_pout_max.dev_attr.attr + +DECLARE_PSU_SENSOR_DEVICE_ATTR(1); +DECLARE_PSU_SENSOR_DEVICE_ATTR(2); + +static struct attribute *as7926_40xfb_psu_attributes[] = { + /* psu attributes */ + DECLARE_PSU_ATTR(1), + DECLARE_PSU_ATTR(2), + NULL +}; + +static const struct attribute_group as7926_40xfb_psu_group = { + .attrs = as7926_40xfb_psu_attributes, +}; + +/* Functions to talk to the IPMI layer */ + +/* Initialize IPMI address, message buffers and user data */ +static int init_ipmi_data(struct ipmi_data *ipmi, int iface, + struct device *dev) +{ + int err; + + init_completion(&ipmi->read_complete); + + /* Initialize IPMI address */ + ipmi->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + ipmi->address.channel = IPMI_BMC_CHANNEL; + ipmi->address.data[0] = 0; + ipmi->interface = iface; + + /* Initialize message buffers */ + ipmi->tx_msgid = 0; + ipmi->tx_message.netfn = ACCTON_IPMI_NETFN; + + ipmi->ipmi_hndlrs.ipmi_recv_hndl = ipmi_msg_handler; + + /* Create IPMI messaging interface user */ + err = ipmi_create_user(ipmi->interface, &ipmi->ipmi_hndlrs, + ipmi, &ipmi->user); + if (err < 0) { + dev_err(dev, "Unable to register user with IPMI " + "interface %d\n", ipmi->interface); + return -EACCES; + } + + return 0; +} + +/* Send an IPMI command */ +static int _ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int err; + + ipmi->tx_message.cmd = cmd; + ipmi->tx_message.data = tx_data; + ipmi->tx_message.data_len = tx_len; + ipmi->rx_msg_data = rx_data; + ipmi->rx_msg_len = rx_len; + + err = ipmi_validate_addr(&ipmi->address, sizeof(ipmi->address)); + if (err) + goto addr_err; + + ipmi->tx_msgid++; + err = ipmi_request_settime(ipmi->user, &ipmi->address, ipmi->tx_msgid, + &ipmi->tx_message, ipmi, 0, 0, 0); + if (err) + goto ipmi_req_err; + + err = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); + if (!err) + goto ipmi_timeout_err; + + return 0; + +ipmi_timeout_err: + err = -ETIMEDOUT; + dev_err(&data->pdev->dev, "request_timeout=%x\n", err); + return err; +ipmi_req_err: + dev_err(&data->pdev->dev, "request_settime=%x\n", err); + return err; +addr_err: + dev_err(&data->pdev->dev, "validate_addr=%x\n", err); + return err; +} + +/* Send an IPMI command with retry */ +static int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int status = 0, retry = 0; + + for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { + status = _ipmi_send_message(ipmi, cmd, tx_data, tx_len, rx_data, rx_len); + if (unlikely(status != 0)) { + dev_err(&data->pdev->dev, "ipmi_send_message_%d err status(%d)\r\n", + retry, status); + continue; + } + + if (unlikely(ipmi->rx_result != 0)) { + dev_err(&data->pdev->dev, "ipmi_send_message_%d err result(%d)\r\n", + retry, ipmi->rx_result); + continue; + } + + break; + } + + return status; +} + +/* Dispatch IPMI messages to callers */ +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) +{ + unsigned short rx_len; + struct ipmi_data *ipmi = user_msg_data; + + if (msg->msgid != ipmi->tx_msgid) { + dev_err(&data->pdev->dev, "Mismatch between received msgid " + "(%02x) and transmitted msgid (%02x)!\n", + (int)msg->msgid, + (int)ipmi->tx_msgid); + ipmi_free_recv_msg(msg); + return; + } + + ipmi->rx_recv_type = msg->recv_type; + if (msg->msg.data_len > 0) + ipmi->rx_result = msg->msg.data[0]; + else + ipmi->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE; + + if (msg->msg.data_len > 1) { + rx_len = msg->msg.data_len - 1; + if (ipmi->rx_msg_len < rx_len) + rx_len = ipmi->rx_msg_len; + ipmi->rx_msg_len = rx_len; + memcpy(ipmi->rx_msg_data, msg->msg.data + 1, ipmi->rx_msg_len); + } else + ipmi->rx_msg_len = 0; + + ipmi_free_recv_msg(msg); + complete(&ipmi->read_complete); +} + +static struct as7926_40xfb_psu_data *as7926_40xfb_psu_update_device(struct device_attribute *da) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + unsigned char pid = attr->index / NUM_OF_PER_PSU_ATTR; + int status = 0; + + if (time_before(jiffies, data->last_updated[pid] + HZ * 5) && data->valid[pid]) + return data; + + data->valid[pid] = 0; + /* To be compatible for older BMC firmware */ + data->ipmi_resp[pid].status[PSU_VOUT_MODE] = 0xff; + + /* Get status from ipmi */ + data->ipmi_tx_data[0] = pid + 1; /* PSU ID base id for ipmi start from 1 */ + status = ipmi_send_message(&data->ipmi, IPMI_PSU_READ_CMD, + data->ipmi_tx_data, 1, + data->ipmi_resp[pid].status, + sizeof(data->ipmi_resp[pid].status)); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + /* Get model name from ipmi */ + data->ipmi_tx_data[1] = IPMI_PSU_MODEL_NAME_CMD; + status = ipmi_send_message(&data->ipmi, IPMI_PSU_READ_CMD, + data->ipmi_tx_data, 2, + data->ipmi_resp[pid].model, + sizeof(data->ipmi_resp[pid].model) - 1); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + /* Get serial number from ipmi */ + data->ipmi_tx_data[1] = IPMI_PSU_SERIAL_NUM_CMD; + status = ipmi_send_message(&data->ipmi, IPMI_PSU_READ_CMD, + data->ipmi_tx_data, 2, + data->ipmi_resp[pid].serial, + sizeof(data->ipmi_resp[pid].serial) - 1); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + /* Get fan direction from ipmi */ + data->ipmi_tx_data[1] = IPMI_PSU_FAN_DIR_CMD; + status = ipmi_send_message(&data->ipmi, IPMI_PSU_READ_CMD, + data->ipmi_tx_data, 2, + data->ipmi_resp[pid].fandir, + sizeof(data->ipmi_resp[pid].fandir) - 1); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + /* Get capability from ipmi */ + data->ipmi_tx_data[1] = IPMI_PSU_INFO_CMD; + status = ipmi_send_message(&data->ipmi, IPMI_PSU_READ_CMD, + data->ipmi_tx_data, 2, + data->ipmi_resp[pid].info, + sizeof(data->ipmi_resp[pid].info)); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + data->last_updated[pid] = jiffies; + data->valid[pid] = 1; + +exit: + return data; +} + +#define VALIDATE_PRESENT_RETURN(id) \ +do { \ + if (data->ipmi_resp[id].status[PSU_PRESENT] == 0) { \ + mutex_unlock(&data->update_lock); \ + return -ENXIO; \ + } \ +} while (0) + +static ssize_t show_psu(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + unsigned char pid = attr->index / NUM_OF_PER_PSU_ATTR; + u32 value = 0; + int present = 0; + int error = 0; + int multiplier = 1000; + + mutex_lock(&data->update_lock); + + data = as7926_40xfb_psu_update_device(da); + if (!data->valid[pid]) { + error = -EIO; + goto exit; + } + + present = !!(data->ipmi_resp[pid].status[PSU_PRESENT]); + + switch (attr->index) { + case PSU1_PRESENT: + case PSU2_PRESENT: + value = present; + break; + case PSU1_POWER_GOOD: + case PSU2_POWER_GOOD: + VALIDATE_PRESENT_RETURN(pid); + value = data->ipmi_resp[pid].status[PSU_POWER_GOOD_PMBUS]; + break; + case PSU1_IIN: + case PSU2_IIN: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].status[PSU_IIN0] | + (u32)data->ipmi_resp[pid].status[PSU_IIN1] << 8 | + (u32)data->ipmi_resp[pid].status[PSU_IIN2] << 16); + break; + case PSU1_IOUT: + case PSU2_IOUT: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].status[PSU_IOUT0] | + (u32)data->ipmi_resp[pid].status[PSU_IOUT1] << 8 | + (u32)data->ipmi_resp[pid].status[PSU_IOUT2] << 16); + break; + case PSU1_VIN: + case PSU2_VIN: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].status[PSU_VIN0] | + (u32)data->ipmi_resp[pid].status[PSU_VIN1] << 8 | + (u32)data->ipmi_resp[pid].status[PSU_VIN2] << 16); + break; + case PSU1_VOUT: + case PSU2_VOUT: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].status[PSU_VOUT0] | + (u32)data->ipmi_resp[pid].status[PSU_VOUT1] << 8 | + (u32)data->ipmi_resp[pid].status[PSU_VOUT2] << 16); + break; + case PSU1_PIN: + case PSU2_PIN: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].status[PSU_PIN0] | + (u32)data->ipmi_resp[pid].status[PSU_PIN1] << 8 | + (u32)data->ipmi_resp[pid].status[PSU_PIN2] << 16 | + (u32)data->ipmi_resp[pid].status[PSU_PIN3] << 24); + value /= 1000; // Convert to milliwatt + break; + case PSU1_POUT: + case PSU2_POUT: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].status[PSU_POUT0] | + (u32)data->ipmi_resp[pid].status[PSU_POUT1] << 8 | + (u32)data->ipmi_resp[pid].status[PSU_POUT2] << 16 | + (u32)data->ipmi_resp[pid].status[PSU_POUT3] << 24); + value /= 1000; // Convert to milliwatt + break; + case PSU1_TEMP_INPUT: + case PSU2_TEMP_INPUT: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].status[PSU_TEMP0] | + (u32)data->ipmi_resp[pid].status[PSU_TEMP1] << 8); + break; + case PSU1_FAN_INPUT: + case PSU2_FAN_INPUT: + VALIDATE_PRESENT_RETURN(pid); + multiplier = 1; + value = ((u32)data->ipmi_resp[pid].status[PSU_FAN0] | + (u32)data->ipmi_resp[pid].status[PSU_FAN1] << 8); + break; + default: + error = -EINVAL; + goto exit; + } + + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", present ? value : 0); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static ssize_t show_psu_info(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + unsigned char pid = attr->index / NUM_OF_PER_PSU_ATTR; + u32 value = 0; + int present = 0; + int error = 0; + + mutex_lock(&data->update_lock); + + data = as7926_40xfb_psu_update_device(da); + if (!data->valid[pid]) { + error = -EIO; + goto exit; + } + + present = !!(data->ipmi_resp[pid].status[PSU_PRESENT]); + + switch (attr->index) { + case PSU1_TEMP_INPUT_MAX: + case PSU2_TEMP_INPUT_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_TEMP_MAX0] | + (u32)data->ipmi_resp[pid].info[PSU_TEMP_MAX1] << 8); + break; + case PSU1_TEMP_INPUT_MIN: + case PSU2_TEMP_INPUT_MIN: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_TEMP_MIN0] | + (u32)data->ipmi_resp[pid].info[PSU_TEMP_MIN1] << 8); + break; + case PSU1_VIN_UPPER_CRIT: + case PSU2_VIN_UPPER_CRIT: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_VIN_UPPER_CRIT0] | + (u32)data->ipmi_resp[pid].info[PSU_VIN_UPPER_CRIT1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_VIN_UPPER_CRIT2] << 16); + break; + case PSU1_VIN_LOWER_CRIT: + case PSU2_VIN_LOWER_CRIT: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_VIN_LOWER_CRIT0] | + (u32)data->ipmi_resp[pid].info[PSU_VIN_LOWER_CRIT1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_VIN_LOWER_CRIT2] << 16); + break; + case PSU1_VIN_MAX: + case PSU2_VIN_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_VIN_MAX0] | + (u32)data->ipmi_resp[pid].info[PSU_VIN_MAX1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_VIN_MAX2] << 16); + break; + case PSU1_VIN_MIN: + case PSU2_VIN_MIN: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_VIN_MIN0] | + (u32)data->ipmi_resp[pid].info[PSU_VIN_MIN1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_VIN_MIN2] << 16); + break; + case PSU1_VOUT_MAX: + case PSU2_VOUT_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_VOUT_MAX0] | + (u32)data->ipmi_resp[pid].info[PSU_VOUT_MAX1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_VOUT_MAX2] << 16); + break; + case PSU1_VOUT_MIN: + case PSU2_VOUT_MIN: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_VOUT_MIN0] | + (u32)data->ipmi_resp[pid].info[PSU_VOUT_MIN1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_VOUT_MIN2] << 16); + break; + case PSU1_IIN_MAX: + case PSU2_IIN_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_IIN_MAX0] | + (u32)data->ipmi_resp[pid].info[PSU_IIN_MAX1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_IIN_MAX2] << 16); + break; + case PSU1_IOUT_MAX: + case PSU2_IOUT_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_IOUT_MAX0] | + (u32)data->ipmi_resp[pid].info[PSU_IOUT_MAX1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_IOUT_MAX2] << 16); + break; + case PSU1_PIN_MAX: + case PSU2_PIN_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_PIN_MAX0] | + (u32)data->ipmi_resp[pid].info[PSU_PIN_MAX1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_PIN_MAX2] << 16 | + (u32)data->ipmi_resp[pid].info[PSU_PIN_MAX3] << 24); + value /= 1000; // Convert to milliwatt + break; + case PSU1_POUT_MAX: + case PSU2_POUT_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_POUT_MAX0] | + (u32)data->ipmi_resp[pid].info[PSU_POUT_MAX1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_POUT_MAX2] << 16 | + (u32)data->ipmi_resp[pid].info[PSU_POUT_MAX3] << 24); + value /= 1000; // Convert to milliwatt + break; + default: + error = -EINVAL; + goto exit; + } + + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", present ? value : 0); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static ssize_t show_string(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + unsigned char pid = attr->index / NUM_OF_PER_PSU_ATTR; + char *str = NULL; + int error = 0; + + mutex_lock(&data->update_lock); + + data = as7926_40xfb_psu_update_device(da); + if (!data->valid[pid]) { + error = -EIO; + goto exit; + } + + switch (attr->index) { + case PSU1_MODEL: + case PSU2_MODEL: + VALIDATE_PRESENT_RETURN(pid); + str = data->ipmi_resp[pid].model; + break; + case PSU1_SERIAL: + case PSU2_SERIAL: + VALIDATE_PRESENT_RETURN(pid); + str = data->ipmi_resp[pid].serial; + break; + case PSU1_FAN_DIR: + case PSU2_FAN_DIR: + VALIDATE_PRESENT_RETURN(pid); + str = data->ipmi_resp[pid].fandir; + break; + default: + error = -EINVAL; + goto exit; + } + + mutex_unlock(&data->update_lock); + return sprintf(buf, "%s\n", str); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static int as7926_40xfb_psu_probe(struct platform_device *pdev) +{ + int status = -1; + + /* Register sysfs hooks */ + status = sysfs_create_group(&pdev->dev.kobj, &as7926_40xfb_psu_group); + if (status) + goto exit; + + dev_info(&pdev->dev, "device created\n"); + + return 0; + +exit: + return status; +} + +static int as7926_40xfb_psu_remove(struct platform_device *pdev) +{ + sysfs_remove_group(&pdev->dev.kobj, &as7926_40xfb_psu_group); + return 0; +} + +static int __init as7926_40xfb_psu_init(void) +{ + int ret; + + data = kzalloc(sizeof(struct as7926_40xfb_psu_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto alloc_err; + } + + mutex_init(&data->update_lock); + + ret = platform_driver_register(&as7926_40xfb_psu_driver); + if (ret < 0) + goto dri_reg_err; + + data->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(data->pdev)) { + ret = PTR_ERR(data->pdev); + goto dev_reg_err; + } + + /* Set up IPMI interface */ + ret = init_ipmi_data(&data->ipmi, 0, &data->pdev->dev); + if (ret) + goto ipmi_err; + + return 0; + +ipmi_err: + platform_device_unregister(data->pdev); +dev_reg_err: + platform_driver_unregister(&as7926_40xfb_psu_driver); +dri_reg_err: + kfree(data); +alloc_err: + return ret; +} + +static void __exit as7926_40xfb_psu_exit(void) +{ + ipmi_destroy_user(data->ipmi.user); + platform_device_unregister(data->pdev); + platform_driver_unregister(&as7926_40xfb_psu_driver); + kfree(data); +} + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("as7926_40xfb_psu driver"); +MODULE_LICENSE("GPL"); + +module_init(as7926_40xfb_psu_init); +module_exit(as7926_40xfb_psu_exit); diff --git a/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/modules/x86-64-accton-as7926-40xfb-sys.c b/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/modules/x86-64-accton-as7926-40xfb-sys.c new file mode 100644 index 00000000000..21d8b283efa --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/modules/x86-64-accton-as7926-40xfb-sys.c @@ -0,0 +1,388 @@ +/* + * Copyright (C) Brandon Chuang + * + * Based on: + * pca954x.c from Kumar Gala + * Copyright (C) 2006 + * + * Based on: + * pca954x.c from Ken Harrenstien + * Copyright (C) 2004 Google, Inc. (Ken Harrenstien) + * + * Based on: + * i2c-virtual_cb.c from Brian Kuschak + * and + * pca9540.c from Jean Delvare . + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as7926_40xfb_sys" +#define ACCTON_IPMI_NETFN 0x34 + +#define IPMI_SYSEEPROM_READ_CMD 0x18 +#define IPMI_TIMEOUT (5 * HZ) +#define IPMI_ERR_RETRY_TIMES 1 +#define IPMI_READ_MAX_LEN 128 + +#define EEPROM_NAME "eeprom" +#define EEPROM_SIZE 256 /* 256 byte eeprom */ + +static int as7926_40xfb_sys_probe(struct platform_device *pdev); +static int as7926_40xfb_sys_remove(struct platform_device *pdev); +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); + +struct ipmi_data { + struct completion read_complete; + struct ipmi_addr address; + struct ipmi_user *user; + int interface; + + struct kernel_ipmi_msg tx_message; + long tx_msgid; + + void *rx_msg_data; + unsigned short rx_msg_len; + unsigned char rx_result; + int rx_recv_type; + + struct ipmi_user_hndl ipmi_hndlrs; +}; + +struct as7926_40xfb_sys_data { + struct platform_device *pdev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + struct ipmi_data ipmi; + unsigned char ipmi_resp_eeprom[EEPROM_SIZE]; + unsigned char ipmi_tx_data[2]; + struct bin_attribute eeprom; /* eeprom data */ +}; + +struct as7926_40xfb_sys_data *data = NULL; + +static struct platform_driver as7926_40xfb_sys_driver = { + .probe = as7926_40xfb_sys_probe, + .remove = as7926_40xfb_sys_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +/* Functions to talk to the IPMI layer */ + +/* Initialize IPMI address, message buffers and user data */ +static int init_ipmi_data(struct ipmi_data *ipmi, int iface, + struct device *dev) +{ + int err; + + init_completion(&ipmi->read_complete); + + /* Initialize IPMI address */ + ipmi->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + ipmi->address.channel = IPMI_BMC_CHANNEL; + ipmi->address.data[0] = 0; + ipmi->interface = iface; + + /* Initialize message buffers */ + ipmi->tx_msgid = 0; + ipmi->tx_message.netfn = ACCTON_IPMI_NETFN; + + ipmi->ipmi_hndlrs.ipmi_recv_hndl = ipmi_msg_handler; + + /* Create IPMI messaging interface user */ + err = ipmi_create_user(ipmi->interface, &ipmi->ipmi_hndlrs, + ipmi, &ipmi->user); + if (err < 0) { + dev_err(dev, "Unable to register user with IPMI " + "interface %d\n", ipmi->interface); + return -EACCES; + } + + return 0; +} + +/* Send an IPMI command */ +static int _ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int err; + + ipmi->tx_message.cmd = cmd; + ipmi->tx_message.data = tx_data; + ipmi->tx_message.data_len = tx_len; + ipmi->rx_msg_data = rx_data; + ipmi->rx_msg_len = rx_len; + + err = ipmi_validate_addr(&ipmi->address, sizeof(ipmi->address)); + if (err) + goto addr_err; + + ipmi->tx_msgid++; + err = ipmi_request_settime(ipmi->user, &ipmi->address, ipmi->tx_msgid, + &ipmi->tx_message, ipmi, 0, 0, 0); + if (err) + goto ipmi_req_err; + + err = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); + if (!err) + goto ipmi_timeout_err; + + return 0; + +ipmi_timeout_err: + err = -ETIMEDOUT; + dev_err(&data->pdev->dev, "request_timeout=%x\n", err); + return err; +ipmi_req_err: + dev_err(&data->pdev->dev, "request_settime=%x\n", err); + return err; +addr_err: + dev_err(&data->pdev->dev, "validate_addr=%x\n", err); + return err; +} + +/* Send an IPMI command with retry */ +static int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int status = 0, retry = 0; + + for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { + status = _ipmi_send_message(ipmi, cmd, tx_data, tx_len, rx_data, rx_len); + if (unlikely(status != 0)) { + dev_err(&data->pdev->dev, "ipmi_send_message_%d err status(%d)\r\n", retry, status); + continue; + } + + if (unlikely(ipmi->rx_result != 0)) { + dev_err(&data->pdev->dev, "ipmi_send_message_%d err rx_result(%d)\r\n", retry, ipmi->rx_result); + continue; + } + + break; + } + + return status; +} + +/* Dispatch IPMI messages to callers */ +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) +{ + unsigned short rx_len; + struct ipmi_data *ipmi = user_msg_data; + + if (msg->msgid != ipmi->tx_msgid) { + dev_err(&data->pdev->dev, "Mismatch between received msgid " + "(%02x) and transmitted msgid (%02x)!\n", + (int)msg->msgid, + (int)ipmi->tx_msgid); + ipmi_free_recv_msg(msg); + return; + } + + ipmi->rx_recv_type = msg->recv_type; + if (msg->msg.data_len > 0) + ipmi->rx_result = msg->msg.data[0]; + else + ipmi->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE; + + if (msg->msg.data_len > 1) { + rx_len = msg->msg.data_len - 1; + if (ipmi->rx_msg_len < rx_len) + rx_len = ipmi->rx_msg_len; + ipmi->rx_msg_len = rx_len; + memcpy(ipmi->rx_msg_data, msg->msg.data + 1, ipmi->rx_msg_len); + } else + ipmi->rx_msg_len = 0; + + ipmi_free_recv_msg(msg); + complete(&ipmi->read_complete); +} + +static ssize_t sys_eeprom_read(loff_t off, char *buf, size_t count) +{ + int status = 0; + unsigned char length = 0; + + if ((off + count) > EEPROM_SIZE) { + return -EINVAL; + } + + length = (count >= IPMI_READ_MAX_LEN) ? IPMI_READ_MAX_LEN : count; + data->ipmi_tx_data[0] = (off & 0xff); + data->ipmi_tx_data[1] = length; + status = ipmi_send_message(&data->ipmi, IPMI_SYSEEPROM_READ_CMD, + data->ipmi_tx_data, sizeof(data->ipmi_tx_data), + data->ipmi_resp_eeprom + off, length); + if (unlikely(status != 0)) { + goto exit; + } + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + status = length; /* Read length */ + memcpy(buf, data->ipmi_resp_eeprom + off, length); + +exit: + return status; +} + +static ssize_t sysfs_bin_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + ssize_t retval = 0; + + if (unlikely(!count)) { + return count; + } + + /* + * Read data from chip, protecting against concurrent updates + * from this host + */ + mutex_lock(&data->update_lock); + + while (count) { + ssize_t status; + + status = sys_eeprom_read(off, buf, count); + if (status <= 0) { + if (retval == 0) { + retval = status; + } + break; + } + + buf += status; + off += status; + count -= status; + retval += status; + } + + mutex_unlock(&data->update_lock); + return retval; + +} + +static int sysfs_eeprom_init(struct kobject *kobj, struct bin_attribute *eeprom) +{ + sysfs_bin_attr_init(eeprom); + eeprom->attr.name = EEPROM_NAME; + eeprom->attr.mode = S_IRUGO; + eeprom->read = sysfs_bin_read; + eeprom->write = NULL; + eeprom->size = EEPROM_SIZE; + + /* Create eeprom file */ + return sysfs_create_bin_file(kobj, eeprom); +} + +static int sysfs_eeprom_cleanup(struct kobject *kobj, struct bin_attribute *eeprom) +{ + sysfs_remove_bin_file(kobj, eeprom); + return 0; +} + +static int as7926_40xfb_sys_probe(struct platform_device *pdev) +{ + int status = -1; + + /* Register sysfs hooks */ + status = sysfs_eeprom_init(&pdev->dev.kobj, &data->eeprom); + if (status) { + goto exit; + } + + dev_info(&pdev->dev, "device created\n"); + + return 0; + +exit: + return status; +} + +static int as7926_40xfb_sys_remove(struct platform_device *pdev) +{ + sysfs_eeprom_cleanup(&pdev->dev.kobj, &data->eeprom); + + return 0; +} + +static int __init as7926_40xfb_sys_init(void) +{ + int ret; + + data = kzalloc(sizeof(struct as7926_40xfb_sys_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto alloc_err; + } + + mutex_init(&data->update_lock); + + ret = platform_driver_register(&as7926_40xfb_sys_driver); + if (ret < 0) { + goto dri_reg_err; + } + + data->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(data->pdev)) { + ret = PTR_ERR(data->pdev); + goto dev_reg_err; + } + + /* Set up IPMI interface */ + ret = init_ipmi_data(&data->ipmi, 0, &data->pdev->dev); + if (ret) + goto ipmi_err; + + return 0; + +ipmi_err: + platform_device_unregister(data->pdev); +dev_reg_err: + platform_driver_unregister(&as7926_40xfb_sys_driver); +dri_reg_err: + kfree(data); +alloc_err: + return ret; +} + +static void __exit as7926_40xfb_sys_exit(void) +{ + ipmi_destroy_user(data->ipmi.user); + platform_device_unregister(data->pdev); + platform_driver_unregister(&as7926_40xfb_sys_driver); + kfree(data); +} + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("as7926_40xfb_sys driver"); +MODULE_LICENSE("GPL"); + +module_init(as7926_40xfb_sys_init); +module_exit(as7926_40xfb_sys_exit); diff --git a/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/modules/x86-64-accton-as7926-40xfb-thermal.c b/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/modules/x86-64-accton-as7926-40xfb-thermal.c new file mode 100644 index 00000000000..40d74e89103 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/modules/x86-64-accton-as7926-40xfb-thermal.c @@ -0,0 +1,450 @@ +/* + * Copyright (C) Brandon Chuang + * + * Based on: + * pca954x.c from Kumar Gala + * Copyright (C) 2006 + * + * Based on: + * pca954x.c from Ken Harrenstien + * Copyright (C) 2004 Google, Inc. (Ken Harrenstien) + * + * Based on: + * i2c-virtual_cb.c from Brian Kuschak + * and + * pca9540.c from Jean Delvare . + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as7926_40xfb_thermal" +#define THERMAL_COUNT 10 +#define ACCTON_IPMI_NETFN 0x34 +#define IPMI_THERMAL_READ_CMD 0x12 +#define IPMI_THERMAL_WRITE_CMD 0x13 + +#define IPMI_TIMEOUT (5 * HZ) +#define IPMI_ERR_RETRY_TIMES 1 + +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, + char *buf); +static ssize_t set_max(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static int as7926_40xfb_thermal_probe(struct platform_device *pdev); +static int as7926_40xfb_thermal_remove(struct platform_device *pdev); + +enum temp_data_index { + TEMP_ADDR, + TEMP_FAULT, + TEMP_INPUT, + TEMP_DATA_COUNT +}; + +struct ipmi_data { + struct completion read_complete; + struct ipmi_addr address; + struct ipmi_user *user; + int interface; + + struct kernel_ipmi_msg tx_message; + long tx_msgid; + + void *rx_msg_data; + unsigned short rx_msg_len; + unsigned char rx_result; + int rx_recv_type; + + struct ipmi_user_hndl ipmi_hndlrs; +}; + +struct as7926_40xfb_thermal_data { + struct platform_device *pdev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + char ipmi_resp[THERMAL_COUNT*TEMP_DATA_COUNT];/* 3 bytes for each thermal */ + struct ipmi_data ipmi; + unsigned char ipmi_tx_data[2]; /* 0: thermal id, 1: temp */ + char temp_max[THERMAL_COUNT]; +}; + +struct as7926_40xfb_thermal_data *data = NULL; + +static struct platform_driver as7926_40xfb_thermal_driver = { + .probe = as7926_40xfb_thermal_probe, + .remove = as7926_40xfb_thermal_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +enum as7926_40xfb_thermal_sysfs_attrs { + TEMP1_INPUT, + TEMP2_INPUT, + TEMP3_INPUT, + TEMP4_INPUT, + TEMP5_INPUT, + TEMP6_INPUT, + TEMP7_INPUT, + TEMP8_INPUT, + TEMP9_INPUT, + TEMP10_INPUT, + TEMP1_MAX, + TEMP2_MAX, + TEMP3_MAX, + TEMP4_MAX, + TEMP5_MAX, + TEMP6_MAX, + TEMP7_MAX, + TEMP8_MAX, + TEMP9_MAX, + TEMP10_MAX, +}; + +#define DECLARE_THERMAL_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(temp##index##_input, S_IRUGO, show_temp, \ + NULL, TEMP##index##_INPUT); \ + static SENSOR_DEVICE_ATTR(temp##index##_max, S_IWUSR | S_IRUGO, show_temp,\ + set_max, TEMP##index##_MAX) + +#define DECLARE_THERMAL_ATTR(index) \ + &sensor_dev_attr_temp##index##_input.dev_attr.attr, \ + &sensor_dev_attr_temp##index##_max.dev_attr.attr + +DECLARE_THERMAL_SENSOR_DEVICE_ATTR(1); +DECLARE_THERMAL_SENSOR_DEVICE_ATTR(2); +DECLARE_THERMAL_SENSOR_DEVICE_ATTR(3); +DECLARE_THERMAL_SENSOR_DEVICE_ATTR(4); +DECLARE_THERMAL_SENSOR_DEVICE_ATTR(5); +DECLARE_THERMAL_SENSOR_DEVICE_ATTR(6); +DECLARE_THERMAL_SENSOR_DEVICE_ATTR(7); +DECLARE_THERMAL_SENSOR_DEVICE_ATTR(8); +DECLARE_THERMAL_SENSOR_DEVICE_ATTR(9); +DECLARE_THERMAL_SENSOR_DEVICE_ATTR(10); + +static struct attribute *as7926_40xfb_thermal_attributes[] = { + DECLARE_THERMAL_ATTR(1), + DECLARE_THERMAL_ATTR(2), + DECLARE_THERMAL_ATTR(3), + DECLARE_THERMAL_ATTR(4), + DECLARE_THERMAL_ATTR(5), + DECLARE_THERMAL_ATTR(6), + DECLARE_THERMAL_ATTR(7), + DECLARE_THERMAL_ATTR(8), + DECLARE_THERMAL_ATTR(9), + DECLARE_THERMAL_ATTR(10), + NULL +}; + +static const struct attribute_group as7926_40xfb_thermal_group = { + .attrs = as7926_40xfb_thermal_attributes, +}; + +/* Functions to talk to the IPMI layer */ + +/* Initialize IPMI address, message buffers and user data */ +static int init_ipmi_data(struct ipmi_data *ipmi, int iface, + struct device *dev) +{ + int err; + + init_completion(&ipmi->read_complete); + + /* Initialize IPMI address */ + ipmi->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + ipmi->address.channel = IPMI_BMC_CHANNEL; + ipmi->address.data[0] = 0; + ipmi->interface = iface; + + /* Initialize message buffers */ + ipmi->tx_msgid = 0; + ipmi->tx_message.netfn = ACCTON_IPMI_NETFN; + + ipmi->ipmi_hndlrs.ipmi_recv_hndl = ipmi_msg_handler; + + /* Create IPMI messaging interface user */ + err = ipmi_create_user(ipmi->interface, &ipmi->ipmi_hndlrs, + ipmi, &ipmi->user); + if (err < 0) { + dev_err(dev, "Unable to register user with IPMI " + "interface %d\n", ipmi->interface); + return -EACCES; + } + + return 0; +} + +/* Send an IPMI command */ +static int _ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int err; + + ipmi->tx_message.cmd = cmd; + ipmi->tx_message.data = tx_data; + ipmi->tx_message.data_len = tx_len; + ipmi->rx_msg_data = rx_data; + ipmi->rx_msg_len = rx_len; + + err = ipmi_validate_addr(&ipmi->address, sizeof(ipmi->address)); + if (err) + goto addr_err; + + ipmi->tx_msgid++; + err = ipmi_request_settime(ipmi->user, &ipmi->address, ipmi->tx_msgid, + &ipmi->tx_message, ipmi, 0, 0, 0); + if (err) + goto ipmi_req_err; + + err = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); + if (!err) + goto ipmi_timeout_err; + + return 0; + +ipmi_timeout_err: + err = -ETIMEDOUT; + dev_err(&data->pdev->dev, "request_timeout=%x\n", err); + return err; +ipmi_req_err: + dev_err(&data->pdev->dev, "request_settime=%x\n", err); + return err; +addr_err: + dev_err(&data->pdev->dev, "validate_addr=%x\n", err); + return err; +} + +/* Send an IPMI command with retry */ +static int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int status = 0, retry = 0; + + for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { + status = _ipmi_send_message(ipmi, cmd, tx_data, tx_len, rx_data, rx_len); + if (unlikely(status != 0)) { + dev_err(&data->pdev->dev, "ipmi_send_message_%d err status(%d)\r\n", + retry, status); + continue; + } + + if (unlikely(ipmi->rx_result != 0)) { + dev_err(&data->pdev->dev, "ipmi_send_message_%d err result(%d)\r\n", + retry, ipmi->rx_result); + continue; + } + + break; + } + + return status; +} + +/* Dispatch IPMI messages to callers */ +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) +{ + unsigned short rx_len; + struct ipmi_data *ipmi = user_msg_data; + + if (msg->msgid != ipmi->tx_msgid) { + dev_err(&data->pdev->dev, "Mismatch between received msgid " + "(%02x) and transmitted msgid (%02x)!\n", + (int)msg->msgid, + (int)ipmi->tx_msgid); + ipmi_free_recv_msg(msg); + return; + } + + ipmi->rx_recv_type = msg->recv_type; + if (msg->msg.data_len > 0) + ipmi->rx_result = msg->msg.data[0]; + else + ipmi->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE; + + if (msg->msg.data_len > 1) { + rx_len = msg->msg.data_len - 1; + if (ipmi->rx_msg_len < rx_len) + rx_len = ipmi->rx_msg_len; + ipmi->rx_msg_len = rx_len; + memcpy(ipmi->rx_msg_data, msg->msg.data + 1, ipmi->rx_msg_len); + } else + ipmi->rx_msg_len = 0; + + ipmi_free_recv_msg(msg); + complete(&ipmi->read_complete); +} + +static ssize_t show_temp(struct device *dev, struct device_attribute *da, + char *buf) +{ + int status = 0; + int index = 0; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + + mutex_lock(&data->update_lock); + + if (attr->index >= TEMP1_MAX && attr->index <= TEMP10_MAX) { + int max = data->temp_max[attr->index-TEMP1_MAX]; + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", max * 1000); + } + + if (time_after(jiffies, data->last_updated + HZ * 5) || !data->valid) { + data->valid = 0; + + status = ipmi_send_message(&data->ipmi, IPMI_THERMAL_READ_CMD, NULL, 0, + data->ipmi_resp, sizeof(data->ipmi_resp)); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + data->last_updated = jiffies; + data->valid = 1; + } + + /* Get temp fault status */ + index = attr->index * TEMP_DATA_COUNT + TEMP_FAULT; + if (unlikely(data->ipmi_resp[index] == 0)) { + status = -EIO; + goto exit; + } + + /* Get temperature in degree celsius */ + index = attr->index * TEMP_DATA_COUNT + TEMP_INPUT; + status = ((s8)data->ipmi_resp[index]) * 1000; + + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", status); + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t set_max(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + long temp; + int status; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + + status = kstrtol(buf, 10, &temp); + if (status) + return status; + + if (temp > 127 || temp < -128) + return -EINVAL; + + mutex_lock(&data->update_lock); + data->temp_max[attr->index-TEMP1_MAX] = temp; + status = count; + mutex_unlock(&data->update_lock); + + return status; +} + +static int as7926_40xfb_thermal_probe(struct platform_device *pdev) +{ + int status = -1; + + /* Register sysfs hooks */ + status = sysfs_create_group(&pdev->dev.kobj, &as7926_40xfb_thermal_group); + if (status) + goto exit; + + dev_info(&pdev->dev, "device created\n"); + + return 0; + +exit: + return status; +} + +static int as7926_40xfb_thermal_remove(struct platform_device *pdev) +{ + sysfs_remove_group(&pdev->dev.kobj, &as7926_40xfb_thermal_group); + + return 0; +} + +static int __init as7926_40xfb_thermal_init(void) +{ + int ret; + int i = 0; + + data = kzalloc(sizeof(struct as7926_40xfb_thermal_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto alloc_err; + } + + mutex_init(&data->update_lock); + data->valid = 0; + + ret = platform_driver_register(&as7926_40xfb_thermal_driver); + if (ret < 0) + goto dri_reg_err; + + data->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(data->pdev)) { + ret = PTR_ERR(data->pdev); + goto dev_reg_err; + } + + /* Set up IPMI interface */ + ret = init_ipmi_data(&data->ipmi, 0, &data->pdev->dev); + if (ret) + goto ipmi_err; + + for (i = 0; i < ARRAY_SIZE(data->temp_max); i++) { + data->temp_max[i] = 70; /* default high threshold */ + } + + return 0; + +ipmi_err: + platform_device_unregister(data->pdev); +dev_reg_err: + platform_driver_unregister(&as7926_40xfb_thermal_driver); +dri_reg_err: + kfree(data); +alloc_err: + return ret; +} + +static void __exit as7926_40xfb_thermal_exit(void) +{ + ipmi_destroy_user(data->ipmi.user); + platform_device_unregister(data->pdev); + platform_driver_unregister(&as7926_40xfb_thermal_driver); + kfree(data); +} + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("AS7926 40xfb Thermal driver"); +MODULE_LICENSE("GPL"); + +module_init(as7926_40xfb_thermal_init); +module_exit(as7926_40xfb_thermal_exit); diff --git a/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/service/as7926-40xfb-platform-monitor.service b/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/service/as7926-40xfb-platform-monitor.service new file mode 100644 index 00000000000..24cbb0da4b3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/service/as7926-40xfb-platform-monitor.service @@ -0,0 +1,18 @@ +[Unit] +Description=Accton AS7926-40XFB Platform Monitoring service +Before=pmon.service +After=sysinit.target +DefaultDependencies=no + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/accton_as7926_40xfb_util.py install +KillSignal=SIGKILL +SuccessExitStatus=SIGKILL +TimeoutSec=300 + +# Resource Limitations +LimitCORE=infinity + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/setup.py b/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/setup.py new file mode 100644 index 00000000000..c548b8abd22 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/setup.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python + +import os +from setuptools import setup +os.listdir + +setup( + name='as7926_40xfb', + version='1.0', + description='Module to initialize Accton AS7926-40XFB platforms', + + packages=['as7926_40xfb'], + package_dir={'as7926_40xfb': 'as7926-40xfb/classes'}, +) + diff --git a/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/sonic_platform_setup.py b/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/sonic_platform_setup.py new file mode 100644 index 00000000000..64a27d187fe --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/sonic_platform_setup.py @@ -0,0 +1,34 @@ +from setuptools import setup + +DEVICE_NAME = 'accton' +HW_SKU = 'x86_64-accton_as7926_40xfb-r0' + +setup( + name='sonic-platform', + version='1.0', + description='SONiC platform API implementation on Accton Platforms', + license='Apache 2.0', + author='SONiC Team', + author_email='linuxnetdev@microsoft.com', + url='https://github.com/Azure/sonic-buildimage', + maintainer='Brandon Chuang', + maintainer_email='brandon_chuang@edge-core.com', + packages=[ + 'sonic_platform', + ], + package_dir={ + 'sonic_platform': '../../../../device/{}/{}/sonic_platform'.format(DEVICE_NAME, HW_SKU)}, + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Environment :: Plugins', + 'Intended Audience :: Developers', + 'Intended Audience :: Information Technology', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: Apache Software License', + 'Natural Language :: English', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: Python :: 3.7', + 'Topic :: Utilities', + ], + keywords='sonic SONiC platform PLATFORM', +) diff --git a/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/utils/accton_as7926_40xfb_util.py b/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/utils/accton_as7926_40xfb_util.py new file mode 100755 index 00000000000..8bc0fac818b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7926-40xfb/utils/accton_as7926_40xfb_util.py @@ -0,0 +1,706 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2019 Accton Networks, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +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 + show : show all systen status + sff : dump SFP eeprom + set : change board setting with fan|led|sfp +""" + +import subprocess +import getopt +import sys +import logging +import re +import time +import os + +PROJECT_NAME = 'as7926_40xfb' +version = '0.1.0' +verbose = False +DEBUG = False +ARGS = [] +ALL_DEVICE = {} +DEVICE_NO = { + 'led': 4, + 'fan': 5, + 'thermal': 12, + 'psu': 2, + 'sfp': 55, + } +FORCE = 0 + +# logging.basicConfig(filename= PROJECT_NAME+'.log', filemode='w',level=logging.DEBUG) +# logging.basicConfig(level=logging.INFO) + +if DEBUG == True: + print(sys.argv[0]) + print('ARGV :', sys.argv[1:]) + + +def main(): + global DEBUG + global ARGS + global FORCE + + 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)) + + 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 == 'api': + do_sonic_platform_install() + elif arg == 'api_clean': + do_sonic_platform_clean() + elif arg == 'show': + device_traversal() + elif arg == 'sff': + if len(ARGS) != 2: + show_eeprom_help() + elif int(ARGS[1]) == 0 or int(ARGS[1]) > DEVICE_NO['sfp']: + show_eeprom_help() + else: + show_eeprom(ARGS[1]) + return + elif arg == 'set': + if len(ARGS) < 3: + show_set_help() + else: + set_device(ARGS[1:]) + return + else: + show_help() + return 0 + + +def show_help(): + print(__doc__ % {'scriptName': sys.argv[0].split('/')[-1]}) + sys.exit(0) + +def show_set_help(): + cmd = sys.argv[0].split('/')[-1] + ' ' + ARGS[0] + print(cmd + ' [led|sfp|fan]') + print(' use "' + cmd + ' led 0/10/16/17/18 " to set led color') + print(' use "' + cmd + ' fan 0-100" to set fan duty percetage') + print(' use "' + cmd + ' sfp 54-55 {0|1}" to set sfp# tx_disable') + sys.exit(0) + + +def show_eeprom_help(): + cmd = sys.argv[0].split('/')[-1] + ' ' + ARGS[0] + print(' use "' + cmd + ' 1-54 " to dump sfp# eeprom') + sys.exit(0) + + +def my_log(txt): + if DEBUG == True: + print('[DBG]' + txt) + return + + +def log_os_system(cmd, show): + logging.info('Run :' + cmd) + status, output = subprocess.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("ls /sys/module/*accton*", 0) + logging.info('mods:'+lsmod) + if ret : + return False + else : + return True + +ipmi_ko = [ +'modprobe ipmi_msghandler', +'modprobe ipmi_ssif', +'modprobe ipmi_si', +'modprobe ipmi_devintf', +] + +ATTEMPTS = 5 + +def init_ipmi_dev_intf(): + attempts = ATTEMPTS + interval = 3 + + while attempts: + for i in range(0, len(ipmi_ko)): + subprocess.getstatusoutput(ipmi_ko[i]) + + if os.path.exists('/dev/ipmi0') or os.path.exists('/dev/ipmidev/0'): + return (0, (ATTEMPTS - attempts) * interval) + + for i in reversed(range(0, len(ipmi_ko))): + rm = ipmi_ko[i].replace("modprobe", "modprobe -rq") + subprocess.getstatusoutput(rm) + + attempts -= 1 + time.sleep(interval) + + return (1, ATTEMPTS * interval) + +def init_ipmi_oem_cmd(): + attempts = ATTEMPTS + interval = 3 + + while attempts: + status, output = subprocess.getstatusoutput('ipmitool raw 0x34 0x95') + if status: + attempts -= 1 + time.sleep(interval) + continue + + return (0, (ATTEMPTS - attempts) * interval) + + return (1, ATTEMPTS * interval) + +def init_ipmi(): + attempts = ATTEMPTS + interval = 60 + + while attempts: + attempts -= 1 + + (status, elapsed_dev) = init_ipmi_dev_intf() + if status: + time.sleep(interval - elapsed_dev) + continue + + (status, elapsed_oem) = init_ipmi_oem_cmd() + if status: + time.sleep(interval - elapsed_dev - elapsed_oem) + continue + + print('IPMI dev interface is ready.') + return 0 + + print('Failed to initialize IPMI dev interface') + return 1 + +kos = [ +'depmod -ae', +'modprobe i2c_dev', +'modprobe i2c_mux_pca954x', +'modprobe x86-64-accton-as7926-40xfb-cpld', +'modprobe x86-64-accton-as7926-40xfb-fan', +'modprobe x86-64-accton-as7926-40xfb-thermal', +'modprobe x86-64-accton-as7926-40xfb-leds', +'modprobe x86-64-accton-as7926-40xfb-psu', +'modprobe x86-64-accton-as7926-40xfb-sys', +'modprobe optoe'] + +def driver_install(): + global FORCE + + status = init_ipmi() + if status: + if FORCE == 0: + return status + + for i in range(0,len(kos)): + status, output = log_os_system(kos[i], 1) + if status: + if FORCE == 0: + return status + return 0 + +def driver_uninstall(): + global FORCE + for i in reversed(range(0,len(kos))): + rm = kos[i].replace("modprobe", "modprobe -rq") + rm = rm.replace("insmod", "rmmod") + lst = rm.split(" ") + if len(lst) > 3: + del(lst[3]) + rm = " ".join(lst) + status, output = log_os_system(rm, 1) + if status: + if FORCE == 0: + return status + return 0 + +led_prefix ='/sys/devices/platform/as7926_40xfb_led/'+PROJECT_NAME+'_led::' + +hwmon_types = {'led': ['diag','fan','loc','psu']} +hwmon_prefix ={'led': led_prefix} + +i2c_prefix = '/sys/bus/i2c/devices/' +i2c_bus = {'sfp': ['-0050']} +i2c_nodes = { + 'fan': ['present', 'front_speed_rpm', 'rear_speed_rpm'], + 'psu': ['psu_present ', 'psu_power_good'] , + 'sfp': ['module_present_'] + } + +sfp_map = [33, 34, 37, 38, 41, 42, 45, 46, 49, 50, + 53, 54, 57, 58, 61, 62, 65, 66, 69, 70, + 35, 36, 39, 40, 43, 44, 47, 48, 51, 52, + 55, 56, 59, 60, 63, 64, 67, 68, 71, 72, + 93, 84, 83, 82, 81, 86, 85, 88, 87, 90, + 89, 92, 91, 30, 31] + +qsfp_start = 1 + +mknod =[ +'echo pca9548 0x77 > /sys/bus/i2c/devices/i2c-0/new_device', +'echo pca9548 0x76 > /sys/bus/i2c/devices/i2c-1/new_device', +'echo pca9548 0x72 > /sys/bus/i2c/devices/i2c-2/new_device', +'echo pca9548 0x73 > /sys/bus/i2c/devices/i2c-9/new_device', +'echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-25/new_device', +'echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-26/new_device', +'echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-27/new_device', +'echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-28/new_device', +'echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-29/new_device', +'echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-1/new_device', +'echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-73/new_device', +'echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-74/new_device', +'echo as7926_40xfb_cpld2 0x62 > /sys/bus/i2c/devices/i2c-12/new_device', +'echo as7926_40xfb_cpld3 0x63 > /sys/bus/i2c/devices/i2c-13/new_device', +'echo as7926_40xfb_cpld4 0x64 > /sys/bus/i2c/devices/i2c-76/new_device', +] + +def device_install(): + global FORCE + + for i in range(0, len(mknod)): + (status, output) = log_os_system(mknod[i], 1) + if status: + print(output) + if FORCE == 0: + return status + + # for pca954x need times to built new i2c buses + if mknod[i].find('pca954') != -1: + time.sleep(2) + + # set all pca954x idle_disconnect + cmd = 'echo -2 | tee /sys/bus/i2c/drivers/pca954x/*-00*/idle_state' + status, output = log_os_system(cmd, 1) + if status: + print(output) + if FORCE == 0: + return status + + for i in range(1, 11): + status, output =log_os_system("echo 0 > /sys/bus/i2c/devices/12-0062/module_reset_"+str(i), 1) + if status: + print(output) + if FORCE == 0: + return status + + for i in range(21, 31): + status, output =log_os_system("echo 0 > /sys/bus/i2c/devices/12-0062/module_reset_"+str(i), 1) + if status: + print(output) + if FORCE == 0: + return status + + for i in range(11, 21): + status, output =log_os_system("echo 0 > /sys/bus/i2c/devices/13-0063/module_reset_"+str(i), 1) + if status: + print(output) + if FORCE == 0: + return status + + for i in range(31, 41): + status, output =log_os_system("echo 0 > /sys/bus/i2c/devices/13-0063/module_reset_"+str(i), 1) + if status: + print(output) + if FORCE == 0: + return status + + for i in range(41, 54): + status, output =log_os_system("echo 0 > /sys/bus/i2c/devices/76-0064/module_reset_"+str(i), 1) + if status: + print(output) + if FORCE == 0: + return status + + for i in range(0,len(sfp_map)): + status + output + + if (i <= 52): + status, output =log_os_system("echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/new_device", 1) + else: + status, output =log_os_system("echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/new_device", 1) + + if status: + print(output) + if FORCE == 0: + return status + path = "/sys/bus/i2c/devices/{0}-0050/port_name" + status, output =log_os_system("echo port{0} > ".format(i+1)+path.format(sfp_map[i]), 1) + if status: + print(output) + if FORCE == 0: + return status + return + +def device_uninstall(): + global FORCE + + for i in range(0, len(sfp_map)): + target = '/sys/bus/i2c/devices/i2c-' + str(sfp_map[i]) \ + + '/delete_device' + (status, output) = log_os_system('echo 0x50 > ' + target, 1) + if status: + print(output) + if FORCE == 0: + return status + nodelist = mknod + + for i in range(len(nodelist)): + target = nodelist[-(i + 1)] + temp = target.split() + del temp[1] + temp[-1] = temp[-1].replace('new_device', 'delete_device') + (status, output) = log_os_system(' '.join(temp), 1) + if status: + print(output) + if FORCE == 0: + return status + + return + + +def system_ready(): + if driver_check() is False: + return False + if not device_exist(): + return False + return True + +PLATFORM_ROOT_PATH = '/usr/share/sonic/device' +PLATFORM_API2_WHL_FILE_PY3 ='sonic_platform-1.0-py3-none-any.whl' +def do_sonic_platform_install(): + device_path = "{}{}{}{}".format(PLATFORM_ROOT_PATH, '/x86_64-accton_', PROJECT_NAME, '-r0') + SONIC_PLATFORM_BSP_WHL_PKG_PY3 = "/".join([device_path, PLATFORM_API2_WHL_FILE_PY3]) + + #Check API2.0 on py whl file + status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0) + if status: + if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_PY3): + status, output = log_os_system("pip3 install "+ SONIC_PLATFORM_BSP_WHL_PKG_PY3, 1) + if status: + print("Error: Failed to install {}".format(PLATFORM_API2_WHL_FILE_PY3)) + return status + else: + print("Successfully installed {} package".format(PLATFORM_API2_WHL_FILE_PY3)) + else: + print('{} is not found'.format(PLATFORM_API2_WHL_FILE_PY3)) + else: + print('{} has installed'.format(PLATFORM_API2_WHL_FILE_PY3)) + +def do_sonic_platform_clean(): + status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0) + if status: + print('{} does not install, not need to uninstall'.format(PLATFORM_API2_WHL_FILE_PY3)) + + else: + status, output = log_os_system("pip3 uninstall sonic-platform -y", 0) + if status: + print('Error: Failed to uninstall {}'.format(PLATFORM_API2_WHL_FILE_PY3)) + return status + else: + print('{} is uninstalled'.format(PLATFORM_API2_WHL_FILE_PY3)) + + return + +def do_install(): + print('Checking system....') + if driver_check() is False: + print('No driver, installing....') + status = driver_install() + if status: + if FORCE == 0: + return status + else: + print(PROJECT_NAME.upper() + ' drivers detected....') + if not device_exist(): + print('No device, installing....') + status = device_install() + if status: + if FORCE == 0: + return status + else: + print(PROJECT_NAME.upper() + ' devices detected....') + + do_sonic_platform_install() + + return + + +def do_uninstall(): + print('Checking system....') + if not device_exist(): + print(PROJECT_NAME.upper() + ' has no device installed....') + else: + print('Removing device....') + status = device_uninstall() + if status and FORCE == 0: + return status + + if driver_check() is False: + print(PROJECT_NAME.upper() + ' has no driver installed....') + else: + print('Removing installed driver....') + status = driver_uninstall() + if status and FORCE == 0: + return status + + do_sonic_platform_clean() + + return None + + +def devices_info(): + global DEVICE_NO + global ALL_DEVICE + global i2c_bus, hwmon_types + for key in DEVICE_NO: + ALL_DEVICE[key] = {} + for i in range(0, DEVICE_NO[key]): + ALL_DEVICE[key][key + str(i + 1)] = [] + + for key in i2c_bus: + buses = i2c_bus[key] + nodes = i2c_nodes[key] + for i in range(0, len(buses)): + for j in range(0, len(nodes)): + if 'fan' == key: + for k in range(0, DEVICE_NO[key]): + node = key + str(k + 1) + path = i2c_prefix + buses[i] + '/fan' + str(k + + 1) + '_' + nodes[j] + my_log(node + ': ' + path) + ALL_DEVICE[key][node].append(path) + elif 'sfp' == key: + for k in range(0, DEVICE_NO[key]): + if k in range(24) or k in range(48, 52): + fmt = i2c_prefix + '5-0062/{0}_{1}' + else: + fmt = i2c_prefix + '6-0064/{0}_{1}' + node = key + str(k + 1) + path = fmt.format(nodes[j], k + 1) + my_log(node + ': ' + path) + ALL_DEVICE[key][node].append(path) + else: + node = key + str(i + 1) + path = i2c_prefix + buses[i] + '/' + nodes[j] + my_log(node + ': ' + path) + ALL_DEVICE[key][node].append(path) + + for key in hwmon_types: + itypes = hwmon_types[key] + for i in range(0, len(itypes)): + for j in range(0, len(nodes)): + node = key + '_' + itypes[i] + path = hwmon_prefix[key] + itypes[i] + my_log(node + ': ' + path) + ALL_DEVICE[key][key + str(i + 1)].append(path) + + # show dict all in the order + if DEBUG == True: + for i in sorted(ALL_DEVICE.keys()): + print(i + ': ') + for j in sorted(ALL_DEVICE[i].keys()): + print(' ' + j) + for k in ALL_DEVICE[i][j]: + print(' ' + ' ' + k) + return + + +def show_eeprom(index): + if system_ready() is False: + print('Systems not ready.') + print('Please install first!') + return + + if len(ALL_DEVICE) == 0: + devices_info() + node = ALL_DEVICE['sfp']['sfp' + str(index)][0] + node = node.replace(node.split('/')[-1], 'sfp_eeprom') + + # check if got hexdump command in current environment + (ret, log) = log_os_system('which hexdump', 0) + (ret, log2) = log_os_system('which busybox hexdump', 0) + if log: + hex_cmd = 'hexdump' + elif log2: + hex_cmd = ' busybox hexdump' + else: + log = 'Failed : no hexdump cmd!!' + logging.info(log) + print(log) + return 1 + + print(node + ':') + (ret, log) = log_os_system('cat ' + node + '| ' + hex_cmd + ' -C', + 1) + if ret == 0: + print(log) + else: + print( '**********device no found**********') + return + + +def set_device(args): + global DEVICE_NO + global ALL_DEVICE + if system_ready() is False: + print('System is not ready.') + print('Please install first!') + return + + if not ALL_DEVICE: + devices_info() + + if args[0] == 'led': + if int(args[1]) > 4: + show_set_help() + return + + # print ALL_DEVICE['led'] + for i in range(0, len(ALL_DEVICE['led'])): + for k in ALL_DEVICE['led']['led' + str(i + 1)]: + ret = log_os_system('echo ' + args[1] + ' >' + k, 1) + if ret[0]: + return ret[0] + elif args[0] == 'fan': + if int(args[1]) > 100: + show_set_help() + return + + # print ALL_DEVICE['fan'] + # fan1~6 is all fine, all fan share same setting + + node = ALL_DEVICE['fan']['fan1'][0] + node = node.replace(node.split('/')[-1], + 'fan_duty_cycle_percentage') + (ret, log) = log_os_system('cat ' + node, 1) + if ret == 0: + print('Previous fan duty: ' + log.strip() + '%') + ret = log_os_system('echo ' + args[1] + ' >' + node, 1) + if ret[0] == 0: + print('Current fan duty: ' + args[1] + '%') + return ret + elif args[0] == 'sfp': + if int(args[1]) > qsfp_start or int(args[1]) == 0: + show_set_help() + return + if len(args) < 2: + show_set_help() + return + + if int(args[2]) > 1: + show_set_help() + return + + # print ALL_DEVICE[args[0]] + + for i in range(len(ALL_DEVICE[args[0]])): + for j in ALL_DEVICE[args[0]][args[0] + str(args[1])]: + if j.find('tx_disable') != -1: + ret = log_os_system('echo ' + args[2] + ' >' + j, 1) + if ret[0]: + return ret[0] + + return + + +# get digits inside a string. +# Ex: get 31 from "sfp31" +def get_value(i): + digit = re.findall('\d+', i) + return int(digit[0]) + + +def device_traversal(): + if system_ready() is False: + print("System is not ready.") + print('Please install first!') + return + + if not ALL_DEVICE: + devices_info() + for i in sorted(ALL_DEVICE.keys()): + print('============================================') + print(i.upper() + ': ') + print('============================================') + for j in sorted(ALL_DEVICE[i].keys(), key=get_value): + print(' ' + j + ':',) + for k in ALL_DEVICE[i][j]: + (ret, log) = log_os_system('cat ' + k, 0) + func = k.split('/')[-1].strip() + func = re.sub(j + '_', '', func, 1) + func = re.sub(i.lower() + '_', '', func, 1) + if ret == 0: + print(func + '=' + log + ' ',) + else: + print(func + '=' + 'X' + ' ',) + print() + print('----------------------------------------------------------------') + print() + return + + +def device_exist(): + ret1 = log_os_system('ls ' + i2c_prefix + '*0077', 0) + ret2 = log_os_system('ls ' + i2c_prefix + 'i2c-2', 0) + return not (ret1[0] or ret2[0]) + + +if __name__ == '__main__': + main() diff --git a/platform/broadcom/sonic-platform-modules-accton/as9716-32d/modules/Makefile b/platform/broadcom/sonic-platform-modules-accton/as9716-32d/modules/Makefile index 7bb532a1f53..e6344b6a608 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as9716-32d/modules/Makefile +++ b/platform/broadcom/sonic-platform-modules-accton/as9716-32d/modules/Makefile @@ -2,7 +2,10 @@ ifneq ($(KERNELRELEASE),) obj-m:= accton_as9716_32d_cpld.o accton_as9716_32d_fan.o \ accton_as9716_32d_leds.o accton_as9716_32d_psu.o accton_i2c_psu.o \ pddf_custom_psu.o - + +CFLAGS_pddf_custom_psu.o := -I$(M)/../../../../pddf/i2c/modules/include +KBUILD_EXTRA_SYMBOLS := $(M)/../../../../pddf/i2c/Module.symvers.PDDF + else ifeq (,$(KERNEL_SRC)) #$(error KERNEL_SRC is not defined) diff --git a/platform/broadcom/sonic-platform-modules-accton/as9716-32d/modules/accton_as9716_32d_fan.c b/platform/broadcom/sonic-platform-modules-accton/as9716-32d/modules/accton_as9716_32d_fan.c index 4d2433e7981..6fbbc2e1276 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as9716-32d/modules/accton_as9716_32d_fan.c +++ b/platform/broadcom/sonic-platform-modules-accton/as9716-32d/modules/accton_as9716_32d_fan.c @@ -42,7 +42,7 @@ static struct as9716_32d_fan_data *as9716_32d_fan_update_device(struct device *d static ssize_t fan_show_value(struct device *dev, struct device_attribute *da, char *buf); static ssize_t set_duty_cycle(struct device *dev, struct device_attribute *da, const char *buf, size_t count); -static ssize_t get_sys_temp(struct device *dev, struct device_attribute *da, char *buf); +// static ssize_t get_sys_temp(struct device *dev, struct device_attribute *da, char *buf); /* fan related data, the index should match sysfs_fan_attributes */ @@ -138,10 +138,10 @@ enum sysfs_fan_attributes { static SENSOR_DEVICE_ATTR(fan##index##_duty_cycle_percentage, S_IWUSR | S_IRUGO, fan_show_value, set_duty_cycle, FAN##index##_DUTY_CYCLE_PERCENTAGE) #define DECLARE_FAN_DUTY_CYCLE_ATTR(index) &sensor_dev_attr_fan##index##_duty_cycle_percentage.dev_attr.attr -#define DECLARE_FAN_SYSTEM_TEMP_SENSOR_DEV_ATTR() \ - static SENSOR_DEVICE_ATTR(sys_temp, S_IRUGO, get_sys_temp, NULL, FAN_DUTY_CYCLE_PERCENTAGE) +// #define DECLARE_FAN_SYSTEM_TEMP_SENSOR_DEV_ATTR() \ +// static SENSOR_DEVICE_ATTR(sys_temp, S_IRUGO, get_sys_temp, NULL, FAN_DUTY_CYCLE_PERCENTAGE) -#define DECLARE_FAN_SYSTEM_TEMP_ATTR() &sensor_dev_attr_sys_temp.dev_attr.attr +// #define DECLARE_FAN_SYSTEM_TEMP_ATTR() &sensor_dev_attr_sys_temp.dev_attr.attr #define DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(index) \ static SENSOR_DEVICE_ATTR(fan##index##_present, S_IRUGO, fan_show_value, NULL, FAN##index##_PRESENT) @@ -189,7 +189,7 @@ DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(6); /* 1 fan duty cycle attribute in this platform */ DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR(); /* System temperature for fancontrol */ -DECLARE_FAN_SYSTEM_TEMP_SENSOR_DEV_ATTR(); +// DECLARE_FAN_SYSTEM_TEMP_SENSOR_DEV_ATTR(); static struct attribute *as9716_32d_fan_attributes[] = { /* fan related attributes */ @@ -218,7 +218,7 @@ static struct attribute *as9716_32d_fan_attributes[] = { DECLARE_FAN_DIRECTION_ATTR(5), DECLARE_FAN_DIRECTION_ATTR(6), DECLARE_FAN_DUTY_CYCLE_ATTR(), - DECLARE_FAN_SYSTEM_TEMP_ATTR(), + // DECLARE_FAN_SYSTEM_TEMP_ATTR(), NULL }; @@ -409,55 +409,55 @@ static int get_temp_file_path( } /*File read the dev file at user space.*/ -static int read_devfile_temp1_input( - struct device *dev, - int bus_nr, - unsigned short addr, - struct device *hwmon_dev, - int *miniCelsius) -{ - struct file *sfd; - char buffer[96]; - char devfile[96]; - int rc, status; - int rdlen, value; - mm_segment_t old_fs; - - rc = 0; - get_temp_file_path(bus_nr, addr, hwmon_dev, devfile, sizeof(devfile)); - sfd = filp_open(devfile, O_RDONLY, 0); - if (IS_ERR(sfd)) { - pr_err("Failed to open file(%s)#%d\r\n", devfile, __LINE__); - return -ENOENT; - } - dev_dbg(dev, "Found device:%s\n",devfile); - - if(!(sfd->f_op) || !(sfd->f_op->read) ) { - pr_err("file %s cann't readable ?\n",devfile); - return -ENOENT; - } - - old_fs = get_fs(); - set_fs(KERNEL_DS); - rdlen = sfd->f_op->read(sfd, buffer, sizeof(buffer), &sfd->f_pos); - if (rdlen == 0) { - pr_err( "File(%s) empty!\n", devfile); - rc = -EIO; - goto exit; - } - status = sscanf(buffer, "%d", &value); - if (status != 1) { - rc = -EIO; - goto exit; - } - *miniCelsius = value; - dev_dbg(dev,"found sensors: %d @i2c %d-%04x\n", value, bus_nr, addr); - -exit: - set_fs(old_fs); - filp_close(sfd, 0); - return rc; -} +// static int read_devfile_temp1_input( +// struct device *dev, +// int bus_nr, +// unsigned short addr, +// struct device *hwmon_dev, +// int *miniCelsius) +// { +// struct file *sfd; +// char buffer[96]; +// char devfile[96]; +// int rc, status; +// int rdlen, value; +// mm_segment_t old_fs; + +// rc = 0; +// get_temp_file_path(bus_nr, addr, hwmon_dev, devfile, sizeof(devfile)); +// sfd = filp_open(devfile, O_RDONLY, 0); +// if (IS_ERR(sfd)) { +// pr_err("Failed to open file(%s)#%d\r\n", devfile, __LINE__); +// return -ENOENT; +// } +// dev_dbg(dev, "Found device:%s\n",devfile); + +// if(!(sfd->f_op) || !(sfd->f_op->read) ) { +// pr_err("file %s cann't readable ?\n",devfile); +// return -ENOENT; +// } + +// old_fs = get_fs(); +// set_fs(KERNEL_DS); +// rdlen = sfd->f_op->read(sfd, buffer, sizeof(buffer), &sfd->f_pos); +// if (rdlen == 0) { +// pr_err( "File(%s) empty!\n", devfile); +// rc = -EIO; +// goto exit; +// } +// status = sscanf(buffer, "%d", &value); +// if (status != 1) { +// rc = -EIO; +// goto exit; +// } +// *miniCelsius = value; +// dev_dbg(dev,"found sensors: %d @i2c %d-%04x\n", value, bus_nr, addr); + +// exit: +// set_fs(old_fs); +// filp_close(sfd, 0); +// return rc; +// } static u8 is_lm75_data_due(struct i2c_client *client) { @@ -493,79 +493,79 @@ static bool lm75_addr_mached(unsigned short addr) return 0; } -static int _find_lm75_device(struct device *dev, void *data) -{ - struct device_driver *driver; - struct as9716_32d_fan_data *prv = data; - char *driver_name = THERMAL_SENSORS_DRIVER; - - driver = dev->driver; - if (driver && driver->name && - strcmp(driver->name, driver_name) == 0) - { - struct i2c_client *client; - client = to_i2c_client(dev); - if (client) - { - /*cannot use "struct i2c_adapter *adap = to_i2c_adapter(dev);"*/ - struct i2c_adapter *adap = client->adapter; - int miniCelsius = 0; - - if (! lm75_addr_mached(client->addr)) - { - return 0; - } - - if (!adap) { - return -ENXIO; - } - - /* If the data is not updated, read them from devfile - to drive them updateing data from chip.*/ - if (is_lm75_data_due(client)) - { - struct device *hwmon_dev; - - hwmon_dev = get_hwmon_dev(client); - if(0 == read_devfile_temp1_input(dev, adap->nr, - client->addr, hwmon_dev, &miniCelsius)) - { - prv->system_temp += miniCelsius; - prv->sensors_found++; - } - - } - else - { - get_lm75_temp(client, &miniCelsius); - prv->system_temp += miniCelsius; - prv->sensors_found++; - - } - } - } - return 0; -} +// static int _find_lm75_device(struct device *dev, void *data) +// { +// struct device_driver *driver; +// struct as9716_32d_fan_data *prv = data; +// char *driver_name = THERMAL_SENSORS_DRIVER; + +// driver = dev->driver; +// if (driver && driver->name && +// strcmp(driver->name, driver_name) == 0) +// { +// struct i2c_client *client; +// client = to_i2c_client(dev); +// if (client) +// { +// /*cannot use "struct i2c_adapter *adap = to_i2c_adapter(dev);"*/ +// struct i2c_adapter *adap = client->adapter; +// int miniCelsius = 0; + +// if (! lm75_addr_mached(client->addr)) +// { +// return 0; +// } + +// if (!adap) { +// return -ENXIO; +// } + +// /* If the data is not updated, read them from devfile +// to drive them updateing data from chip.*/ +// if (is_lm75_data_due(client)) +// { +// struct device *hwmon_dev; + +// hwmon_dev = get_hwmon_dev(client); +// if(0 == read_devfile_temp1_input(dev, adap->nr, +// client->addr, hwmon_dev, &miniCelsius)) +// { +// prv->system_temp += miniCelsius; +// prv->sensors_found++; +// } + +// } +// else +// { +// get_lm75_temp(client, &miniCelsius); +// prv->system_temp += miniCelsius; +// prv->sensors_found++; + +// } +// } +// } +// return 0; +// } /*Find all lm75 devices and return sum of temperatures.*/ -static ssize_t get_sys_temp(struct device *dev, struct device_attribute *da, - char *buf) -{ - ssize_t ret = 0; - struct as9716_32d_fan_data *data = as9716_32d_fan_update_device(dev); - - data->system_temp=0; - data->sensors_found=0; - i2c_for_each_dev(data, _find_lm75_device); - if (NUM_THERMAL_SENSORS != data->sensors_found) - { - dev_dbg(dev,"only %d of %d temps are found\n", - data->sensors_found, NUM_THERMAL_SENSORS); - data->system_temp = INT_MAX; - } - ret = sprintf(buf, "%d\n",data->system_temp); - return ret; -} +// static ssize_t get_sys_temp(struct device *dev, struct device_attribute *da, +// char *buf) +// { +// ssize_t ret = 0; +// struct as9716_32d_fan_data *data = as9716_32d_fan_update_device(dev); + +// data->system_temp=0; +// data->sensors_found=0; +// i2c_for_each_dev(data, _find_lm75_device); +// if (NUM_THERMAL_SENSORS != data->sensors_found) +// { +// dev_dbg(dev,"only %d of %d temps are found\n", +// data->sensors_found, NUM_THERMAL_SENSORS); +// data->system_temp = INT_MAX; +// } +// ret = sprintf(buf, "%d\n",data->system_temp); +// return ret; +// } static ssize_t fan_show_value(struct device *dev, struct device_attribute *da, char *buf) diff --git a/platform/broadcom/sonic-platform-modules-accton/as9716-32d/modules/accton_as9716_32d_psu.c b/platform/broadcom/sonic-platform-modules-accton/as9716-32d/modules/accton_as9716_32d_psu.c index 06e8e23c3c5..28ea8898366 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as9716-32d/modules/accton_as9716_32d_psu.c +++ b/platform/broadcom/sonic-platform-modules-accton/as9716-32d/modules/accton_as9716_32d_psu.c @@ -35,7 +35,7 @@ #include #define MAX_MODEL_NAME 16 -#define MAX_SERIAL_NUMBER 19 +#define MAX_SERIAL_NUMBER 20 static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf); static ssize_t show_string(struct device *dev, struct device_attribute *da, char *buf); @@ -280,18 +280,45 @@ static struct as9716_32d_psu_data *as9716_32d_psu_update_device(struct device *d data->model_name[0] = '\0'; dev_dbg(&client->dev, "unable to read model name from (0x%x)\n", client->addr); } - else { - data->model_name[ARRAY_SIZE(data->model_name)-1] = '\0'; + else + { + if (!strncmp(data->model_name, "FSH082", strlen("FSH082"))) + { + data->model_name[strlen("FSH082")]='\0'; + } + else if (!strncmp(data->model_name, "YESM1300", strlen("YESM1300"))) + { + if (data->model_name[9]=='A' && data->model_name[10]=='M') + { + data->model_name[8]='A'; + data->model_name[9]='M'; + data->model_name[strlen("YESM1300AM")]='\0'; + } + else + data->model_name[strlen("YESM1300")]='\0'; + } + else if (!strncmp(data->model_name, "YM-2651Y", strlen("YM-2651Y"))) + { + data->model_name[strlen("YM-2651Y")]='\0'; + } + else + data->model_name[ARRAY_SIZE(data->model_name)-1] = '\0'; } - /* Read from offset 0x2e ~ 0x3d (16 bytes) */ - status = as9716_32d_psu_read_block(client, 0x2e,data->serial_number, MAX_SERIAL_NUMBER); + /* Read from offset 0x35 ~ 0x47 */ + status = as9716_32d_psu_read_block(client, 0x35,data->serial_number, MAX_SERIAL_NUMBER); if (status < 0) { data->serial_number[0] = '\0'; dev_dbg(&client->dev, "unable to read model name from (0x%x) offset(0x2e)\n", client->addr); } - data->serial_number[MAX_SERIAL_NUMBER-1]='\0'; + if (!strncmp(data->model_name, "YESM1300AM", strlen("YESM1300AM"))) /*for YESM1300AM, SN length=19*/ + { + data->serial_number[MAX_SERIAL_NUMBER-1]='\0'; + } + else /*for FSH082, SN length=18*/ + data->serial_number[MAX_SERIAL_NUMBER-2]='\0'; + } data->last_updated = jiffies; @@ -308,4 +335,3 @@ module_i2c_driver(as9716_32d_psu_driver); MODULE_AUTHOR("Jostar Yang "); MODULE_DESCRIPTION("as9716_32d_psu driver"); MODULE_LICENSE("GPL"); - diff --git a/platform/broadcom/sonic-platform-modules-accton/as9716-32d/modules/pddf_custom_psu.c b/platform/broadcom/sonic-platform-modules-accton/as9716-32d/modules/pddf_custom_psu.c index 9c4dd7f6613..1171731cc8b 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as9716-32d/modules/pddf_custom_psu.c +++ b/platform/broadcom/sonic-platform-modules-accton/as9716-32d/modules/pddf_custom_psu.c @@ -9,7 +9,7 @@ #include #include #include -#include "../../../../pddf/i2c/modules/include/pddf_psu_defs.h" +#include "pddf_psu_defs.h" ssize_t pddf_show_custom_psu_v_out(struct device *dev, struct device_attribute *da, char *buf); extern PSU_SYSFS_ATTR_DATA access_psu_v_out; diff --git a/platform/broadcom/sonic-platform-modules-accton/as9716-32d/utils/accton_as9716_32d_monitor.py b/platform/broadcom/sonic-platform-modules-accton/as9716-32d/utils/accton_as9716_32d_monitor.py index f0eb95d97f8..194883497ef 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as9716-32d/utils/accton_as9716_32d_monitor.py +++ b/platform/broadcom/sonic-platform-modules-accton/as9716-32d/utils/accton_as9716_32d_monitor.py @@ -13,9 +13,9 @@ # # See the Apache Version 2.0 License for specific language governing # permissions and limitations under the License. -# +# # HISTORY: -# mm/dd/yyyy (A.D.)# +# mm/dd/yyyy (A.D.)# # 8/27/2019:Jostar create for as9716_32d thermal plan # ------------------------------------------------------------------ @@ -42,12 +42,12 @@ class switch(object): def __init__(self, value): self.value = value self.fall = False - + def __iter__(self): """Return the match method once, then stop""" yield self.match raise StopIteration - + def match(self, *args): """Indicate whether or not to enter a case suite""" if self.fall or not args: @@ -77,7 +77,7 @@ def match(self, *args): # LM75-5(0X4E)<=40.75 # LM75-6(0X4F)<=42.1 # CPU board -# Core<=44 +# Core<=44 # LM75-1(0X4B)<=35 # When fan_policy_state=LEVEL_FAN_MID, meet with below case, Fan duty_cycle will be 100%(LEVEL_FAN_DAX) @@ -89,9 +89,9 @@ def match(self, *args): # LM75-5(0X4E)>=45.1 # LM75-6(0X4F)>=46.75 # (CPU board) -# Core>=48 +# Core>=48 # LM75-1(0X4B)>=38.5 - + # 2. For AFO: # At default, FAN duty_cycle was 100%(LEVEL_FAN_MAX). If all below case meet with, set to 75%(LEVEL_FAN_MID). # (MB board) @@ -116,7 +116,7 @@ def match(self, *args): # (CPU board) # Core<=57 # LM75-1(0X4B)<=36.6 - + # When fan_speed 50%(LEVEL_FAN_DEF). # Meet with below case, Fan duty_cycle will be 75%(LEVEL_FAN_MID) # (MB board) @@ -193,7 +193,7 @@ def power_off_dut(): # Return 0: Not full load def check_psu_loading(): psu_power_status=[1, 1] - + psu_power_good = { 2: "/sys/bus/i2c/devices/10-0051/psu_power_good", 1: "/sys/bus/i2c/devices/9-0050/psu_power_good", @@ -206,7 +206,7 @@ def check_psu_loading(): 2: "/sys/bus/i2c/devices/10-0059/psu_p_out", 1: "/sys/bus/i2c/devices/9-0058/psu_p_out", } - + check_psu_watt=0 for i in range(1,3): node = psu_power_good[i] @@ -215,11 +215,11 @@ def check_psu_loading(): status = int(power_status.read()) except IOError: return None - + psu_power_status[i-1]=int(status) if status==0: - check_psu_watt=1 - + check_psu_watt=1 + if check_psu_watt: for i in range(1,3): if psu_power_status[i-1]==1: @@ -230,11 +230,11 @@ def check_psu_loading(): status = int(power_status.read()) except IOError: return None - + psu_p_in= int(status) if psu_p_in/1000 > 800: return True - + node = psu_power_out[i] try: with open(node, 'r') as power_status: @@ -246,8 +246,8 @@ def check_psu_loading(): return True else: return False - - + + return False fan_policy_state=0 @@ -269,7 +269,7 @@ class device_monitor(object): new_duty_cycle = 0 duty_cycle=0 ori_duty_cycle = 0 - + def __init__(self, log_file, log_level): """Needs a logger and a logger level.""" @@ -290,13 +290,13 @@ def __init__(self, log_file, log_level): logging.getLogger('').addHandler(console) sys_handler = handler = logging.handlers.SysLogHandler(address = '/dev/log') - sys_handler.setLevel(logging.WARNING) + sys_handler.setLevel(logging.WARNING) logging.getLogger('').addHandler(sys_handler) #logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level) - - + + def manage_fans(self): - + global fan_policy_state global fan_policy_alarm global send_yellow_alarm @@ -307,18 +307,18 @@ def manage_fans(self): global test_temp_list global temp_test_data global test_temp_revert - + CHECK_TIMES=3 - + LEVEL_FAN_INIT=0 LEVEL_FAN_MIN=1 - LEVEL_FAN_MID=2 + LEVEL_FAN_MID=2 LEVEL_FAN_MAX=3 LEVEL_FAN_DEF=LEVEL_FAN_MAX LEVEL_FAN_YELLOW_ALARM=4 LEVEL_FAN_RED_ALARM=5 LEVEL_FAN_SHUTDOWN=6 - + fan_policy_f2b = { #AFO LEVEL_FAN_MIN: [50, 0x7], LEVEL_FAN_MID: [75, 0xb], @@ -328,58 +328,58 @@ def manage_fans(self): LEVEL_FAN_MID: [75, 0xb], LEVEL_FAN_MAX: [100, 0xf] } - + afi_thermal_spec={ "mid_to_max_temp":[61500, 51500, 49400, 49400, 45100, 46750, 48000, 38500], - "max_to_mid_temp":[57000, 47300, 45000, 45100, 40750, 42100, 44000, 35000] + "max_to_mid_temp":[57000, 47300, 45000, 45100, 40750, 42100, 44000, 35000] } afo_thermal_spec={ "min_to_mid_temp": [70000, 66000, 68000, 62000, 62000, 67000, 77000, 50000], "mid_to_max_temp": [67000, 62000, 65000, 59000, 58500, 63000, 69000, 49000], "max_to_mid_temp": [59000, 53500, 55300, 50300, 50000, 52500, 59000, 41100], "mid_to_min_temp": [55800, 50500, 51100, 47600, 45750, 50100, 57000, 36600], - "max_to_yellow_alarm": [68000, 64000, 65000, 61000, 60000, 64000, 70000, 68000], - "yellow_to_red_alarm": [72000, 68000, 69000, 65000, 64000, 68000, 74000, 72000], - "red_alarm_to_shutdown": [77000, 73000, 74000, 70000, 69000, 73000, 79000, 77000] + "max_to_yellow_alarm": [68000, 64000, 65000, 61000, 60000, 64000, 70000, 68000], + "yellow_to_red_alarm": [72000, 68000, 69000, 65000, 64000, 68000, 74000, 72000], + "red_alarm_to_shutdown": [77000, 73000, 74000, 70000, 69000, 73000, 79000, 77000] } - thermal_val=[0,0,0,0,0,0,0,0] + thermal_val=[0,0,0,0,0,0,0,0] max_to_mid=0 mid_to_min=0 - + fan = FanUtil() if fan_policy_state==LEVEL_FAN_INIT: fan_policy_state=LEVEL_FAN_MAX #This is default state logging.debug("fan_policy_state=LEVEL_FAN_MAX") return - + count_check=count_check+1 if count_check < CHECK_TIMES: return else: count_check=0 - + thermal = ThermalUtil() fan_dir=1 fan_dir=fan.get_fan_dir(1) - + if fan_dir==1: # AFI fan_thermal_spec = afi_thermal_spec fan_policy=fan_policy_b2f elif fan_dir==0: # AFO fan_thermal_spec = afo_thermal_spec - fan_policy=fan_policy_f2b + fan_policy=fan_policy_f2b else: logging.debug( "NULL case") - + ori_duty_cycle=fan.get_fan_duty_cycle() new_duty_cycle=0 if test_temp_revert==0: temp_test_data=temp_test_data+2000 - else: + else: temp_test_data=temp_test_data-2000 - + if test_temp==0: for i in range (thermal.THERMAL_NUM_1_IDX, thermal.THERMAL_NUM_MAX+1): thermal_val[i-1]=thermal._get_thermal_val(i) @@ -387,12 +387,12 @@ def manage_fans(self): for i in range (thermal.THERMAL_NUM_1_IDX, thermal.THERMAL_NUM_MAX+1): thermal_val[i-1]=test_temp_list[i-1] thermal_val[i-1]= thermal_val[i-1] + temp_test_data - + fan_fail=0 - + ori_state=fan_policy_state; current_state=fan_policy_state; - + if fan_dir==1: #AFI for i in range (0, thermal.THERMAL_NUM_MAX): if ori_state==LEVEL_FAN_MID: @@ -403,7 +403,7 @@ def manage_fans(self): else: if (thermal_val[i] <= fan_thermal_spec["max_to_mid_temp"][i]): max_to_mid=max_to_mid+1 - + if max_to_mid==thermal.THERMAL_NUM_MAX and fan_policy_state==LEVEL_FAN_MAX: current_state=LEVEL_FAN_MID logging.debug("current_state=LEVEL_FAN_MID") @@ -422,12 +422,12 @@ def manage_fans(self): current_state=LEVEL_FAN_MID logging.debug("psu_full_load, set current_state=LEVEL_FAN_MID") if thermal_val[i] >= fan_thermal_spec["min_to_mid_temp"][i]: - current_state=LEVEL_FAN_MID - + current_state=LEVEL_FAN_MID + else: if thermal_val[i] <= fan_thermal_spec["max_to_mid_temp"][i] : max_to_mid=max_to_mid+1 - if fan_policy_alarm==0: + if fan_policy_alarm==0: if thermal_val[i] >= fan_thermal_spec["max_to_yellow_alarm"][i]: if send_yellow_alarm==0: logging.warning('Alarm-Yellow for temperature high is detected') @@ -441,11 +441,11 @@ def manage_fans(self): send_red_alarm=1 elif fan_policy_alarm==LEVEL_FAN_RED_ALARM: if thermal_val[i] >= fan_thermal_spec["red_alarm_to_shutdown"][i]: - logging.critical('Alarm-Critical for temperature high is detected, shutdown DUT') + logging.critical('Alarm-Critical for temperature high is detected, shutdown DUT') fan_policy_alarm=LEVEL_FAN_SHUTDOWN time.sleep(2) power_off_dut() - + if max_to_mid==thermal.THERMAL_NUM_MAX and ori_state==LEVEL_FAN_MAX: current_state=LEVEL_FAN_MID if fan_policy_alarm!=0: @@ -455,17 +455,17 @@ def manage_fans(self): send_red_alarm=0 test_temp_revert=0 logging.debug("current_state=LEVEL_FAN_MID") - + if mid_to_min==thermal.THERMAL_NUM_MAX and ori_state==LEVEL_FAN_MID: if psu_full_load==0: current_state=LEVEL_FAN_MIN logging.debug("current_state=LEVEL_FAN_MIN") - + #Check Fan status for i in range (fan.FAN_NUM_1_IDX, fan.FAN_NUM_ON_MAIN_BROAD+1): if fan.get_fan_status(i)==0: new_duty_cycle=100 - logging.debug('fan_%d fail, set duty_cycle to 100',i) + logging.debug('fan_%d fail, set duty_cycle to 100',i) if test_temp==0: fan_fail=1 fan.set_fan_duty_cycle(new_duty_cycle) @@ -502,8 +502,8 @@ def main(argv): elif opt in ('-d', '--debug'): log_level = logging.DEBUG elif opt in ('-l', '--lfile'): - log_file = arg - + log_file = arg + if sys.argv[1]== '-t': if len(sys.argv)!=10: print("temp test, need input 8 temp") @@ -515,7 +515,7 @@ def main(argv): test_temp = 1 log_level = logging.DEBUG print(test_temp_list) - + fan = FanUtil() fan.set_fan_duty_cycle(100) monitor = device_monitor(log_file, log_level) @@ -523,8 +523,8 @@ def main(argv): while True: monitor.manage_fans() time.sleep(10) - + if __name__ == '__main__': main(sys.argv[1:]) - + diff --git a/platform/broadcom/sonic-platform-modules-accton/as9726-32d/modules/x86-64-accton-as9726-32d-cpld.c b/platform/broadcom/sonic-platform-modules-accton/as9726-32d/modules/x86-64-accton-as9726-32d-cpld.c index 096d1384b65..b1a2d031581 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as9726-32d/modules/x86-64-accton-as9726-32d-cpld.c +++ b/platform/broadcom/sonic-platform-modules-accton/as9726-32d/modules/x86-64-accton-as9726-32d-cpld.c @@ -72,6 +72,7 @@ MODULE_DEVICE_TABLE(i2c, as9726_32d_cpld_id); #define TRANSCEIVER_RXLOS_ATTR_ID(index) MODULE_RXLOS_##index #define TRANSCEIVER_TXFAULT_ATTR_ID(index) MODULE_TXFAULT_##index #define TRANSCEIVER_RESET_ATTR_ID(index) MODULE_RESET_##index +#define TRANSCEIVER_LPMODE_ATTR_ID(index) MODULE_LPMODE_##index #define CPLD_INTR_ATTR_ID(index) CPLD_INTR_##index enum as9726_32d_cpld_sysfs_attributes { @@ -150,6 +151,38 @@ enum as9726_32d_cpld_sysfs_attributes { TRANSCEIVER_RESET_ATTR_ID(30), TRANSCEIVER_RESET_ATTR_ID(31), TRANSCEIVER_RESET_ATTR_ID(32), + TRANSCEIVER_LPMODE_ATTR_ID(1), + TRANSCEIVER_LPMODE_ATTR_ID(2), + TRANSCEIVER_LPMODE_ATTR_ID(3), + TRANSCEIVER_LPMODE_ATTR_ID(4), + TRANSCEIVER_LPMODE_ATTR_ID(5), + TRANSCEIVER_LPMODE_ATTR_ID(6), + TRANSCEIVER_LPMODE_ATTR_ID(7), + TRANSCEIVER_LPMODE_ATTR_ID(8), + TRANSCEIVER_LPMODE_ATTR_ID(9), + TRANSCEIVER_LPMODE_ATTR_ID(10), + TRANSCEIVER_LPMODE_ATTR_ID(11), + TRANSCEIVER_LPMODE_ATTR_ID(12), + TRANSCEIVER_LPMODE_ATTR_ID(13), + TRANSCEIVER_LPMODE_ATTR_ID(14), + TRANSCEIVER_LPMODE_ATTR_ID(15), + TRANSCEIVER_LPMODE_ATTR_ID(16), + TRANSCEIVER_LPMODE_ATTR_ID(17), + TRANSCEIVER_LPMODE_ATTR_ID(18), + TRANSCEIVER_LPMODE_ATTR_ID(19), + TRANSCEIVER_LPMODE_ATTR_ID(20), + TRANSCEIVER_LPMODE_ATTR_ID(21), + TRANSCEIVER_LPMODE_ATTR_ID(22), + TRANSCEIVER_LPMODE_ATTR_ID(23), + TRANSCEIVER_LPMODE_ATTR_ID(24), + TRANSCEIVER_LPMODE_ATTR_ID(25), + TRANSCEIVER_LPMODE_ATTR_ID(26), + TRANSCEIVER_LPMODE_ATTR_ID(27), + TRANSCEIVER_LPMODE_ATTR_ID(28), + TRANSCEIVER_LPMODE_ATTR_ID(29), + TRANSCEIVER_LPMODE_ATTR_ID(30), + TRANSCEIVER_LPMODE_ATTR_ID(31), + TRANSCEIVER_LPMODE_ATTR_ID(32), CPLD_INTR_ATTR_ID(1), CPLD_INTR_ATTR_ID(2), CPLD_INTR_ATTR_ID(3), @@ -173,6 +206,10 @@ static ssize_t get_mode_reset(struct device *dev, struct device_attribute *da, char *buf); static ssize_t set_mode_reset(struct device *dev, struct device_attribute *da, const char *buf, size_t count); +static ssize_t get_mode_lpmode(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t set_mode_lpmode(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); static int as9726_32d_cpld_read_internal(struct i2c_client *client, u8 reg); static int as9726_32d_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value); @@ -201,6 +238,10 @@ static int as9726_32d_cpld_write_internal(struct i2c_client *client, u8 reg, u8 static SENSOR_DEVICE_ATTR(cpld_intr_##index, S_IRUGO, show_interrupt, NULL, CPLD_INTR_##index) #define DECLARE_CPLD_INTR_ATTR(index) &sensor_dev_attr_cpld_intr_##index.dev_attr.attr +/*lpmode*/ +#define DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_lpmode_##index, S_IWUSR | S_IRUGO, get_mode_lpmode, set_mode_lpmode, MODULE_LPMODE_##index) +#define DECLARE_TRANSCEIVER_LPMODE_ATTR(index) &sensor_dev_attr_module_lpmode_##index.dev_attr.attr static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, NULL, CPLD_VERSION); @@ -278,6 +319,38 @@ DECLARE_CPLD_DEVICE_INTR_ATTR(1); DECLARE_CPLD_DEVICE_INTR_ATTR(2); DECLARE_CPLD_DEVICE_INTR_ATTR(3); DECLARE_CPLD_DEVICE_INTR_ATTR(4); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(1); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(2); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(3); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(4); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(5); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(6); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(7); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(8); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(9); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(10); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(11); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(12); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(13); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(14); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(15); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(16); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(17); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(18); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(19); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(20); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(21); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(22); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(23); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(24); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(25); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(26); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(27); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(28); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(29); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(30); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(31); +DECLARE_TRANSCEIVER_LPMODE_SENSOR_DEVICE_ATTR(32); @@ -326,6 +399,22 @@ static struct attribute *as9726_32d_cpld2_attributes[] = { DECLARE_TRANSCEIVER_RESET_ATTR(14), DECLARE_TRANSCEIVER_RESET_ATTR(15), DECLARE_TRANSCEIVER_RESET_ATTR(16), + DECLARE_TRANSCEIVER_LPMODE_ATTR(1), + DECLARE_TRANSCEIVER_LPMODE_ATTR(2), + DECLARE_TRANSCEIVER_LPMODE_ATTR(3), + DECLARE_TRANSCEIVER_LPMODE_ATTR(4), + DECLARE_TRANSCEIVER_LPMODE_ATTR(5), + DECLARE_TRANSCEIVER_LPMODE_ATTR(6), + DECLARE_TRANSCEIVER_LPMODE_ATTR(7), + DECLARE_TRANSCEIVER_LPMODE_ATTR(8), + DECLARE_TRANSCEIVER_LPMODE_ATTR(9), + DECLARE_TRANSCEIVER_LPMODE_ATTR(10), + DECLARE_TRANSCEIVER_LPMODE_ATTR(11), + DECLARE_TRANSCEIVER_LPMODE_ATTR(12), + DECLARE_TRANSCEIVER_LPMODE_ATTR(13), + DECLARE_TRANSCEIVER_LPMODE_ATTR(14), + DECLARE_TRANSCEIVER_LPMODE_ATTR(15), + DECLARE_TRANSCEIVER_LPMODE_ATTR(16), DECLARE_CPLD_INTR_ATTR(1), DECLARE_CPLD_INTR_ATTR(2), NULL @@ -374,6 +463,22 @@ static struct attribute *as9726_32d_cpld3_attributes[] = { DECLARE_TRANSCEIVER_RESET_ATTR(30), DECLARE_TRANSCEIVER_RESET_ATTR(31), DECLARE_TRANSCEIVER_RESET_ATTR(32), + DECLARE_TRANSCEIVER_LPMODE_ATTR(17), + DECLARE_TRANSCEIVER_LPMODE_ATTR(18), + DECLARE_TRANSCEIVER_LPMODE_ATTR(19), + DECLARE_TRANSCEIVER_LPMODE_ATTR(20), + DECLARE_TRANSCEIVER_LPMODE_ATTR(21), + DECLARE_TRANSCEIVER_LPMODE_ATTR(22), + DECLARE_TRANSCEIVER_LPMODE_ATTR(23), + DECLARE_TRANSCEIVER_LPMODE_ATTR(24), + DECLARE_TRANSCEIVER_LPMODE_ATTR(25), + DECLARE_TRANSCEIVER_LPMODE_ATTR(26), + DECLARE_TRANSCEIVER_LPMODE_ATTR(27), + DECLARE_TRANSCEIVER_LPMODE_ATTR(28), + DECLARE_TRANSCEIVER_LPMODE_ATTR(29), + DECLARE_TRANSCEIVER_LPMODE_ATTR(30), + DECLARE_TRANSCEIVER_LPMODE_ATTR(31), + DECLARE_TRANSCEIVER_LPMODE_ATTR(32), DECLARE_CPLD_INTR_ATTR(3), DECLARE_CPLD_INTR_ATTR(4), NULL @@ -647,6 +752,116 @@ static ssize_t show_version(struct device *dev, struct device_attribute *attr, c return sprintf(buf, "0x%x\n", val); } +static ssize_t get_mode_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); + struct as9726_32d_cpld_data *data = i2c_get_clientdata(client); + int status = 0; + u8 reg = 0, mask = 0; + + switch (attr->index) { + case MODULE_LPMODE_1 ... MODULE_LPMODE_8: + reg = 0x60; + mask = 0x1 << (attr->index - MODULE_LPMODE_1); + break; + case MODULE_LPMODE_9 ... MODULE_LPMODE_16: + reg = 0x61; + mask = 0x1 << (attr->index - MODULE_LPMODE_9); + break; + case MODULE_LPMODE_17 ... MODULE_LPMODE_24: + reg = 0x60; + mask = 0x1 << (attr->index - MODULE_LPMODE_17); + break; + case MODULE_LPMODE_25 ... MODULE_LPMODE_32: + reg = 0x61; + mask = 0x1 << (attr->index - MODULE_LPMODE_25); + break; + default: + return 0; + } + + mutex_lock(&data->update_lock); + status = as9726_32d_cpld_read_internal(client, reg); + + if (unlikely(status < 0)) { + goto exit; + } + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\r\n", !(status & mask)); + +exit: + mutex_unlock(&data->update_lock); + return status; + +} + +static ssize_t set_mode_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 as9726_32d_cpld_data *data = i2c_get_clientdata(client); + long lpmode; + int status=0, val, error; + u8 reg = 0, mask = 0; + + error = kstrtol(buf, 10, &lpmode); + if (error) { + return error; + } + + switch (attr->index) { + case MODULE_LPMODE_1 ... MODULE_LPMODE_8: + reg = 0x60; + mask = 0x1 << (attr->index - MODULE_LPMODE_1); + break; + case MODULE_LPMODE_9 ... MODULE_LPMODE_16: + reg = 0x61; + mask = 0x1 << (attr->index - MODULE_LPMODE_9); + break; + case MODULE_LPMODE_17 ... MODULE_LPMODE_24: + reg = 0x60; + mask = 0x1 << (attr->index - MODULE_LPMODE_17); + break; + case MODULE_LPMODE_25 ... MODULE_LPMODE_32: + reg = 0x61; + mask = 0x1 << (attr->index - MODULE_LPMODE_25); + break; + default: + return 0; + } + mutex_lock(&data->update_lock); + + status = as9726_32d_cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + + /* Update lp_mode status */ + if (lpmode) + { + val = status&(~mask); + } + else + { + val =status | (mask); + } + + status = as9726_32d_cpld_write_internal(client, reg, val); + if (unlikely(status < 0)) { + goto exit; + } + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + static ssize_t get_mode_reset(struct device *dev, struct device_attribute *da, char *buf) { @@ -769,7 +984,7 @@ static int as9726_32d_cpld_probe(struct i2c_client *client, struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); struct as9726_32d_cpld_data *data; int ret = -ENODEV; - int status; + int status; const struct attribute_group *group = NULL; if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) diff --git a/platform/broadcom/sonic-platform-modules-accton/as9726-32d/modules/x86-64-accton-as9726-32d-psu.c b/platform/broadcom/sonic-platform-modules-accton/as9726-32d/modules/x86-64-accton-as9726-32d-psu.c index cdf11f503d6..a75a0b1307a 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as9726-32d/modules/x86-64-accton-as9726-32d-psu.c +++ b/platform/broadcom/sonic-platform-modules-accton/as9726-32d/modules/x86-64-accton-as9726-32d-psu.c @@ -94,15 +94,15 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, //printk("data->status=0x%x, attr->index=%d,data->index=%d \n", data->status, attr->index, data->index); if (attr->index == PSU_PRESENT) { if(data->index==0) - status = !( (data->status) & 0x1); - else status = !( (data->status >> 1) & 0x1); + else + status = !( (data->status) & 0x1); } else { /* PSU_POWER_GOOD */ if(data->index==0) - status = ( (data->status >> 2) & 0x1); + status = ( (data->status >> 3) & 0x1); else - status = ( (data->status >> 3) & 0x1); + status = ( (data->status >> 2) & 0x1); } return sprintf(buf, "%d\n", status); diff --git a/platform/broadcom/sonic-platform-modules-accton/as9726-32d/modules/ym2651y.c b/platform/broadcom/sonic-platform-modules-accton/as9726-32d/modules/ym2651y.c index 63488d2c6c7..ea5628d8724 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as9726-32d/modules/ym2651y.c +++ b/platform/broadcom/sonic-platform-modules-accton/as9726-32d/modules/ym2651y.c @@ -77,6 +77,7 @@ struct ym2651y_data { u16 mfr_pout_max; /* Register value */ u16 mfr_vout_min; /* Register value */ u16 mfr_vout_max; /* Register value */ + u16 mfr_temp_max; /* Register value */ }; static ssize_t show_vout(struct device *dev, struct device_attribute *da, @@ -123,7 +124,8 @@ enum ym2651y_sysfs_attributes { PSU_MFR_IIN_MAX, PSU_MFR_IOUT_MAX, PSU_MFR_PIN_MAX, - PSU_MFR_POUT_MAX + PSU_MFR_POUT_MAX, + PSU_MFR_TEMP1_MAX }; /* sysfs attributes for hwmon @@ -152,6 +154,7 @@ static SENSOR_DEVICE_ATTR(psu_mfr_iin_max, S_IRUGO, show_linear, NULL, PSU_MFR static SENSOR_DEVICE_ATTR(psu_mfr_iout_max, S_IRUGO, show_linear, NULL, PSU_MFR_IOUT_MAX); static SENSOR_DEVICE_ATTR(psu_mfr_pin_max, S_IRUGO, show_linear, NULL, PSU_MFR_PIN_MAX); static SENSOR_DEVICE_ATTR(psu_mfr_pout_max, S_IRUGO, show_linear, NULL, PSU_MFR_POUT_MAX); +static SENSOR_DEVICE_ATTR(psu_mfr_temp1_max, S_IRUGO, show_linear, NULL, PSU_MFR_TEMP1_MAX); /*Duplicate nodes for lm-sensors.*/ static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_vout, NULL, PSU_V_OUT); @@ -160,6 +163,7 @@ static SENSOR_DEVICE_ATTR(power2_input, S_IRUGO, show_linear, NULL, PSU_P_OUT static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_linear, NULL, PSU_TEMP1_INPUT); static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_linear, NULL, PSU_FAN1_SPEED); static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_word, NULL, PSU_TEMP_FAULT); +static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_linear, NULL, PSU_MFR_TEMP1_MAX); static struct attribute *ym2651y_attributes[] = { &sensor_dev_attr_psu_power_on.dev_attr.attr, @@ -186,6 +190,7 @@ static struct attribute *ym2651y_attributes[] = { &sensor_dev_attr_psu_mfr_vout_min.dev_attr.attr, &sensor_dev_attr_psu_mfr_vout_max.dev_attr.attr, &sensor_dev_attr_psu_mfr_iout_max.dev_attr.attr, + &sensor_dev_attr_psu_mfr_temp1_max.dev_attr.attr, /*Duplicate nodes for lm-sensors.*/ &sensor_dev_attr_curr2_input.dev_attr.attr, &sensor_dev_attr_in3_input.dev_attr.attr, @@ -193,6 +198,7 @@ static struct attribute *ym2651y_attributes[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_fan1_input.dev_attr.attr, &sensor_dev_attr_temp1_fault.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, NULL }; @@ -319,6 +325,9 @@ static ssize_t show_linear(struct device *dev, struct device_attribute *da, case PSU_MFR_IIN_MAX: value = data->mfr_iin_max; break; + case PSU_MFR_TEMP1_MAX: + value = data->mfr_temp_max; + break; } exponent = two_complement_to_int(value >> 11, 5, 0x1f); @@ -587,7 +596,8 @@ static struct ym2651y_data *ym2651y_update_device(struct device *dev) {0xa4, &data->mfr_vout_min}, {0xa5, &data->mfr_vout_max}, {0xa6, &data->mfr_iout_max}, - {0xa7, &data->mfr_pout_max} + {0xa7, &data->mfr_pout_max}, + {0xc0, &data->mfr_temp_max} }; dev_dbg(&client->dev, "Starting ym2651 update\n"); diff --git a/platform/broadcom/sonic-platform-modules-accton/as9726-32d/utils/accton_as9726_32d_util.py b/platform/broadcom/sonic-platform-modules-accton/as9726-32d/utils/accton_as9726_32d_util.py index 1dd3c0b467d..2581ddda7d4 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as9726-32d/utils/accton_as9726_32d_util.py +++ b/platform/broadcom/sonic-platform-modules-accton/as9726-32d/utils/accton_as9726_32d_util.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # # Copyright (C) 2016 Accton Networks, Inc. # @@ -24,16 +24,11 @@ command: install : install drivers and generate related sysfs nodes clean : uninstall drivers and remove related sysfs nodes - show : show all systen status - sfp : dump SFP eeprom - set : change board setting with fan|sfp """ - import subprocess import getopt import sys import logging -import re import time import os @@ -43,81 +38,8 @@ DEBUG = False args = [] ALL_DEVICE = {} -DEVICE_NO = { - 'fan1': 3, - 'fan2': 3, - 'fan3': 3, - 'fan4': 3, - 'fan5': 3, - 'fan6': 3, - 'thermal': 6, - 'psu': 2, - 'sfp': 34} - -fan_prefix = '/sys/devices/platform/as9726_32d_' -hwmon_types = {'fan1': ['fan'], - 'fan2': ['fan'], - 'fan3': ['fan'], - 'fan4': ['fan'], - 'fan5': ['fan'], - 'fan6': ['fan'], - } -hwmon_nodes = { - 'fan1': [ - 'fan_duty_cycle_percentage', - 'fan1_fault', - 'fan1_front_speed_rpm', - 'fan1_direction', - 'fan1_rear_speed_rpm'], - 'fan2': [ - 'fan_duty_cycle_percentage', - 'fan2_fault', - 'fan2_front_speed_rpm', - 'fan2_direction', - 'fan2_rear_speed_rpm'], - 'fan3': [ - 'fan_duty_cycle_percentage', - 'fan3_fault', - 'fan3_front_speed_rpm', - 'fan3_direction', - 'fan3_rear_speed_rpm'], - 'fan4': [ - 'fan4_duty_cycle_percentage', - 'fan4_fault', - 'fan4_front_speed_rpm', - 'fan4_direction', - 'fan4_rear_speed_rpm'], - 'fan5': [ - 'fan_duty_cycle_percentage', - 'fan5_fault', - 'fan5_front_speed_rpm', - 'fan5_direction', - 'fan5_rear_speed_rpm'], - 'fan6': [ - 'fan_duty_cycle_percentage', - 'fan6_fault', - 'fan6_front_speed_rpm', - 'fan6_direction', - 'fan6_rear_speed_rpm'], -} -hwmon_prefix = {'fan1': fan_prefix, - 'fan2': fan_prefix, - 'fan3': fan_prefix, - 'fan4': fan_prefix, - 'fan5': fan_prefix, - 'fan6': fan_prefix, - } i2c_prefix = '/sys/bus/i2c/devices/' -i2c_bus = {'fan': ['14-0066'], - 'thermal': ['15-0048', '15-0049', '15-004a', '15-004b', '15-004c', '15-004f'], - 'psu': ['9-0050', '9-0051'], - 'sfp': ['10-0061', '10-0062']} -i2c_nodes = {'fan': ['present', 'front_speed_rpm', 'rear_speed_rpm'], - 'thermal': ['hwmon/hwmon*/temp1_input'], - 'psu': ['psu_present ', 'psu_power_good'], - 'sfp': ['module_present_', 'module_tx_disable_']} - sfp_map = [17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, @@ -193,7 +115,6 @@ def main(): elif opt in ('-f', '--force'): FORCE = 1 else: - print("TEST") logging.info('no option') for arg in args: if arg == 'install': @@ -202,24 +123,8 @@ def main(): do_uninstall() elif arg == 'api': do_sonic_platform_install() - elif arg == 'api_clean': + elif arg == 'api_clean': do_sonic_platform_clean() - elif arg == 'show': - device_traversal() - elif arg == 'sff': - if len(args) != 2: - show_eeprom_help() - elif int(args[1]) == 0 or int(args[1]) > DEVICE_NO['sfp']: - show_eeprom_help() - else: - show_eeprom(args[1]) - return - elif arg == 'set': - if len(args) < 3: - show_set_help() - else: - set_device(args[1:]) - return else: show_help() @@ -230,21 +135,6 @@ def show_help(): print(__doc__ % {'scriptName': sys.argv[0].split("/")[-1]}) sys.exit(0) - -def show_set_help(): - cmd = sys.argv[0].split("/")[-1] + " " + args[0] - print(cmd + " [sfp|fan]") - print(" use \"" + cmd + " fan 0-100\" to set fan duty percetage") - print(" use \"" + cmd + " sfp 33-34 {0|1}\" to set sfp# tx_disable") - sys.exit(0) - - -def show_eeprom_help(): - cmd = sys.argv[0].split("/")[-1] + " " + args[0] - print(" use \"" + cmd + " 1-32 \" to dump sfp# eeprom") - sys.exit(0) - - def my_log(txt): if DEBUG: print("[ACCTON DBG]: " + txt) @@ -302,7 +192,6 @@ def driver_uninstall(): for i in range(0, len(kos)): rm = kos[-(i + 1)].replace("modprobe", "modprobe -rq") lst = rm.split(" ") - print("lst=%s" % lst) if len(lst) > 3: del(lst[3]) rm = " ".join(lst) @@ -409,7 +298,7 @@ def do_sonic_platform_install(): #Check API2.0 on py whl file status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0) if status: - if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_PY3): + if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_PY3): status, output = log_os_system("pip3 install "+ SONIC_PLATFORM_BSP_WHL_PKG_PY3, 1) if status: print("Error: Failed to install {}".format(PLATFORM_API2_WHL_FILE_PY3)) @@ -418,17 +307,17 @@ def do_sonic_platform_install(): print("Successfully installed {} package".format(PLATFORM_API2_WHL_FILE_PY3)) else: print(('{} is not found'.format(PLATFORM_API2_WHL_FILE_PY3))) - else: + else: print(('{} has installed'.format(PLATFORM_API2_WHL_FILE_PY3))) - return + return def do_sonic_platform_clean(): - status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0) + status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0) if status: print(('{} does not install, not need to uninstall'.format(PLATFORM_API2_WHL_FILE_PY3))) - else: + else: status, output = log_os_system("pip3 uninstall sonic-platform -y", 0) if status: print(('Error: Failed to uninstall {}'.format(PLATFORM_API2_WHL_FILE_PY3))) @@ -455,12 +344,6 @@ def do_install(): else: print(PROJECT_NAME.upper() + " devices detected....") -# for i in range(len(cpld_set)): -# status, output = log_os_system(cpld_set[i], 1) -# if status: -# if FORCE == 0: -# return status - do_sonic_platform_install() return @@ -489,196 +372,6 @@ def do_uninstall(): return - -def devices_info(): - global DEVICE_NO - global ALL_DEVICE - global i2c_bus, hwmon_types - for key in DEVICE_NO: - ALL_DEVICE[key] = {} - for i in range(0, DEVICE_NO[key]): - ALL_DEVICE[key][key + str(i + 1)] = [] - - for key in i2c_bus: - buses = i2c_bus[key] - nodes = i2c_nodes[key] - for i in range(0, len(buses)): - for j in range(0, len(nodes)): - if 'fan' == key: - for k in range(0, 6): - node = key + str(k + 1) - path = i2c_prefix + \ - buses[i] + "/fan" + str(k + 1) + "_" + nodes[j] - my_log(node + ": " + path) - ALL_DEVICE[key + str(k + 1)][node + str(j + 1)].append(path) - elif 'sfp' == key: - for k in range(0, DEVICE_NO[key]): - node = key + str(k + 1) - if k < 16 and i==0 and j==0: - path = i2c_prefix + \ - str(buses[0] + "/" + nodes[j] + str(k+1)) - my_log(node + ": " + path) - ALL_DEVICE[key][node].append(path) - if k >= 16 and i==1 and j==0: - path = i2c_prefix + \ - str(buses[1] + "/" + nodes[j] + str(k+1)) - my_log(node + ": " + path) - ALL_DEVICE[key][node].append(path) - if k >= 32 and i==1 and j==1: - path = i2c_prefix + \ - str(buses[1] + "/" + nodes[j] + str(k+1)) - my_log(node + ": " + path) - ALL_DEVICE[key][node].append(path) - else: - node = key + str(i + 1) - path = i2c_prefix + buses[i] + "/" + nodes[j] - my_log(node + ": " + path) - ALL_DEVICE[key][node].append(path) - - #for key in hwmon_types: - # itypes = hwmon_types[key] - # nodes = hwmon_nodes[key] - # for i in range(0, len(itypes)): - # for j in range(0, len(nodes)): - # node = key + "_" + itypes[i] - # path = hwmon_prefix[key] + itypes[i] + "/" + nodes[j] - # my_log(node + ": " + path) - # ALL_DEVICE[key][key + str(i + 1)].append(path) - - # show dict all in the order - if DEBUG: - for i in sorted(ALL_DEVICE.keys()): - print((i + ": ")) - for j in sorted(ALL_DEVICE[i].keys()): - print((" " + j)) - for k in (ALL_DEVICE[i][j]): - print((" " + " " + k)) - return - - -def show_eeprom(index): - if system_ready() == False: - print("System's not ready.") - print("Please install first!") - return - - if len(ALL_DEVICE) == 0: - devices_info() - node = ALL_DEVICE['sfp']['sfp' + str(index)][0] - node = node.replace(node.split("/")[-1], 'eeprom') - sfp_node = str(sfp_map[int(index)-1]) + '-0050' - node = node.replace(node.split("/")[-2], sfp_node) - # check if got hexdump command in current environment - ret, log = log_os_system("which hexdump", 0) - ret, log2 = log_os_system("which busybox hexdump", 0) - if len(log): - hex_cmd = 'hexdump' - elif len(log2): - hex_cmd = ' busybox hexdump' - else: - log = 'Failed : no hexdump cmd!!' - logging.info(log) - print(log) - return 1 - print("node=%s" % node) - print(node + ":") - ret, log = log_os_system("cat " + node + "| " + hex_cmd + " -C", 1) - if ret == 0: - print(log) - else: - print("**********device no found**********") - return - - -def set_device(args): - global DEVICE_NO - global ALL_DEVICE - if system_ready() == False: - print("System's not ready.") - print("Please install first!") - return - - if len(ALL_DEVICE) == 0: - devices_info() - - if args[0] == 'fan': - if int(args[1]) > 100: - show_set_help() - return - #print ALL_DEVICE['fan'] - # fan1~6 is all fine, all fan share same setting - node = ALL_DEVICE['fan1']['fan11'][0] - node = node.replace(node.split("/")[-1], 'fan_duty_cycle_percentage') - ret, log = log_os_system("cat " + node, 1) - if ret == 0: - print(("Previous fan duty: " + log.strip() + "%")) - ret, log = log_os_system("echo " + args[1] + " >" + node, 1) - if ret == 0: - print(("Current fan duty: " + args[1] + "%")) - return ret - elif args[0] == 'sfp': - if int(args[1]) > DEVICE_NO[args[0]] or int(args[1]) < DEVICE_NO[args[0]]-1: #33-34 - show_set_help() - return - if len(args)<3 or len(args)>4: #len(args)=3 - show_set_help() - return - if int(args[2])>1 or int(args[2])<0: #0|1 - show_set_help() - return - - #print ALL_DEVICE[args[0]] - for i in range(0, len(ALL_DEVICE[args[0]])): - for j in ALL_DEVICE[args[0]][args[0] + str(args[1])]: - if j.find('tx_disable') != -1: - ret, log = log_os_system("echo " + args[2] + " >" + j, 1) - if ret: - return ret - else: - show_set_help() - - return - -# get digits inside a string. -# Ex: 31 for "sfp31" - - -def get_value(input): - digit = re.findall(r'\d+', input) - return int(digit[0]) - - -def device_traversal(): - if system_ready() == False: - print("System's not ready.") - print("Please install first!") - return - - if len(ALL_DEVICE) == 0: - devices_info() - for i in sorted(ALL_DEVICE.keys()): - print("============================================") - print((i.upper() + ": ")) - print("============================================") - - for j in sorted(list(ALL_DEVICE[i].keys()), key=get_value): - print(" " + j + ":", end=' ') - for k in (ALL_DEVICE[i][j]): - ret, log = log_os_system("cat " + k, 0) - func = k.split("/")[-1].strip() - func = re.sub(j + '_', '', func, 1) - func = re.sub(i.lower() + '_', '', func, 1) - if ret == 0: - print(func + "=" + log + " ", end=' ') - else: - print(func + "=" + "X" + " ", end=' ') - print() - print("----------------------------------------------------------------") - - print() - return - - def device_exist(): ret1, log = log_os_system("ls " + i2c_prefix + "*0077", 0) ret2, log = log_os_system("ls " + i2c_prefix + "i2c-2", 0) diff --git a/platform/broadcom/sonic-platform-modules-accton/common/modules/accton_i2c_cpld.c b/platform/broadcom/sonic-platform-modules-accton/common/modules/accton_i2c_cpld.c index 03e528ef8d5..867399718a8 100755 --- a/platform/broadcom/sonic-platform-modules-accton/common/modules/accton_i2c_cpld.c +++ b/platform/broadcom/sonic-platform-modules-accton/common/modules/accton_i2c_cpld.c @@ -475,7 +475,8 @@ static ssize_t set_1bit(struct device *dev, struct device_attribute *devattr, cpld_bit = sensor->mask; mutex_lock(&data->update_lock); value = cpld_read_internal(client, reg); - if (unlikely(status < 0)) { + if (unlikely(value < 0)) { + status = value; goto exit; } diff --git a/platform/broadcom/sonic-platform-modules-accton/common/modules/ym2651y.c b/platform/broadcom/sonic-platform-modules-accton/common/modules/ym2651y.c index 5834b1d4ef8..26f5815ef4a 100755 --- a/platform/broadcom/sonic-platform-modules-accton/common/modules/ym2651y.c +++ b/platform/broadcom/sonic-platform-modules-accton/common/modules/ym2651y.c @@ -42,7 +42,7 @@ enum chips { YM2651, YM2401, YM2851, - YPEB1200AM + YPEB1200AM }; /* Each client has this additional data @@ -66,8 +66,9 @@ struct ym2651y_data { u16 fan_duty_cycle[2]; /* Register value */ u8 fan_dir[4]; /* Register value */ u8 pmbus_revision; /* Register value */ + u8 mfr_serial[21]; /* Register value */ u8 mfr_id[10]; /* Register value */ - u8 mfr_model[10]; /* Register value */ + u8 mfr_model[16]; /* Register value */ u8 mfr_revsion[3]; /* Register value */ u16 mfr_vin_min; /* Register value */ u16 mfr_vin_max; /* Register value */ @@ -116,6 +117,7 @@ enum ym2651y_sysfs_attributes { PSU_MFR_ID, PSU_MFR_MODEL, PSU_MFR_REVISION, + PSU_MFR_SERIAL, PSU_MFR_VIN_MIN, PSU_MFR_VIN_MAX, PSU_MFR_VOUT_MIN, @@ -144,6 +146,7 @@ static SENSOR_DEVICE_ATTR(psu_pmbus_revision, S_IRUGO, show_byte, NULL, PSU_PM static SENSOR_DEVICE_ATTR(psu_mfr_id, S_IRUGO, show_ascii, NULL, PSU_MFR_ID); static SENSOR_DEVICE_ATTR(psu_mfr_model, S_IRUGO, show_ascii, NULL, PSU_MFR_MODEL); static SENSOR_DEVICE_ATTR(psu_mfr_revision, S_IRUGO, show_ascii, NULL, PSU_MFR_REVISION); +static SENSOR_DEVICE_ATTR(psu_mfr_serial, S_IRUGO, show_ascii, NULL, PSU_MFR_SERIAL); static SENSOR_DEVICE_ATTR(psu_mfr_vin_min, S_IRUGO, show_linear, NULL, PSU_MFR_VIN_MIN); static SENSOR_DEVICE_ATTR(psu_mfr_vin_max, S_IRUGO, show_linear, NULL, PSU_MFR_VIN_MAX); static SENSOR_DEVICE_ATTR(psu_mfr_vout_min, S_IRUGO, show_linear, NULL, PSU_MFR_VOUT_MIN); @@ -178,6 +181,7 @@ static struct attribute *ym2651y_attributes[] = { &sensor_dev_attr_psu_mfr_id.dev_attr.attr, &sensor_dev_attr_psu_mfr_model.dev_attr.attr, &sensor_dev_attr_psu_mfr_revision.dev_attr.attr, + &sensor_dev_attr_psu_mfr_serial.dev_attr.attr, &sensor_dev_attr_psu_mfr_vin_min.dev_attr.attr, &sensor_dev_attr_psu_mfr_vin_max.dev_attr.attr, &sensor_dev_attr_psu_mfr_pout_max.dev_attr.attr, @@ -362,14 +366,17 @@ static ssize_t show_ascii(struct device *dev, struct device_attribute *da, } ptr = data->fan_dir; break; + case PSU_MFR_SERIAL: /* psu_mfr_serial */ + ptr = data->mfr_serial+1; /* The first byte is the count byte of string. */ + break; case PSU_MFR_ID: /* psu_mfr_id */ - ptr = data->mfr_id; + ptr = data->mfr_id+1; /* The first byte is the count byte of string. */ break; case PSU_MFR_MODEL: /* psu_mfr_model */ - ptr = data->mfr_model; + ptr = data->mfr_model+1; /* The first byte is the count byte of string. */ break; case PSU_MFR_REVISION: /* psu_mfr_revision */ - ptr = data->mfr_revsion; + ptr = data->mfr_revsion+1; break; default: return 0; @@ -561,8 +568,8 @@ static struct ym2651y_data *ym2651y_update_device(struct device *dev) if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || !data->valid) { - int i, status; - u8 command; + int i, status, length; + u8 command, buf; u8 fan_dir[5] = {0}; struct reg_data_byte regs_byte[] = { {0x19, &data->capability}, {0x20, &data->vout_mode}, @@ -599,6 +606,7 @@ static struct ym2651y_data *ym2651y_update_device(struct device *dev) dev_dbg(&client->dev, "reg %d, err %d\n", regs_byte[i].reg, status); *(regs_byte[i].value) = 0; + goto exit; } else { *(regs_byte[i].value) = status; @@ -614,6 +622,7 @@ static struct ym2651y_data *ym2651y_update_device(struct device *dev) dev_dbg(&client->dev, "reg %d, err %d\n", regs_word[i].reg, status); *(regs_word[i].value) = 0; + goto exit; } else { *(regs_word[i].value) = status; @@ -626,11 +635,29 @@ static struct ym2651y_data *ym2651y_update_device(struct device *dev) if (status < 0) { dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + goto exit; } strncpy(data->fan_dir, fan_dir+1, ARRAY_SIZE(data->fan_dir)-1); data->fan_dir[ARRAY_SIZE(data->fan_dir)-1] = '\0'; + /* Read mfr_serial */ + command = 0x9e; + length = 1; + /* Read first byte to determine the length of data */ + status = ym2651y_read_block(client, command, &buf, length); + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + goto exit; + } + status = ym2651y_read_block(client, command, data->mfr_serial, buf+1); + data->mfr_serial[buf+1] = '\0'; + if (status < 0) + { + dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + goto exit; + } + /* Read mfr_id */ command = 0x99; status = ym2651y_read_block(client, command, data->mfr_id, @@ -638,16 +665,28 @@ static struct ym2651y_data *ym2651y_update_device(struct device *dev) data->mfr_id[ARRAY_SIZE(data->mfr_id)-1] = '\0'; if (status < 0) + { dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + goto exit; + } /* Read mfr_model */ command = 0x9a; - status = ym2651y_read_block(client, command, data->mfr_model, - ARRAY_SIZE(data->mfr_model)-1); - data->mfr_model[ARRAY_SIZE(data->mfr_model)-1] = '\0'; + length = 1; + /* Read first byte to determine the length of data */ + status = ym2651y_read_block(client, command, &buf, length); + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + goto exit; + } + status = ym2651y_read_block(client, command, data->mfr_model, buf+1); + data->mfr_model[buf+1] = '\0'; if (status < 0) + { dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + goto exit; + } /* Read mfr_revsion */ command = 0x9b; @@ -656,12 +695,16 @@ static struct ym2651y_data *ym2651y_update_device(struct device *dev) data->mfr_revsion[ARRAY_SIZE(data->mfr_revsion)-1] = '\0'; if (status < 0) + { dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + goto exit; + } data->last_updated = jiffies; data->valid = 1; } +exit: mutex_unlock(&data->update_lock); return data; diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/control b/platform/broadcom/sonic-platform-modules-accton/debian/control index 4410a2f0779..cd1f605e31d 100755 --- a/platform/broadcom/sonic-platform-modules-accton/debian/control +++ b/platform/broadcom/sonic-platform-modules-accton/debian/control @@ -49,6 +49,10 @@ Package: sonic-platform-accton-as4630-54te Architecture: amd64 Description: kernel modules for platform devices such as fan, led, sfp +Package: sonic-platform-accton-as4630-54npe +Architecture: amd64 +Description: kernel modules for platform devices such as fan, led, sfp + Package: sonic-platform-accton-minipack Architecture: amd64 Description: kernel modules for platform devices such as fan, led, sfp @@ -84,3 +88,11 @@ Description: kernel modules for platform devices such as fan, led, sfp Package: sonic-platform-accton-as7315-27xb Architecture: amd64 Description: kernel modules for platform devices such as fan, led, sfp + +Package: sonic-platform-accton-as7926-40xfb +Architecture: amd64 +Description: kernel modules for platform devices such as fan, led, sfp + +Package: sonic-platform-accton-as7535-32xb +Architecture: amd64 +Description: kernel modules for platform devices such as fan, led, sfp diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/rules b/platform/broadcom/sonic-platform-modules-accton/debian/rules index 8cd7611bb6e..e87aad35da9 100755 --- a/platform/broadcom/sonic-platform-modules-accton/debian/rules +++ b/platform/broadcom/sonic-platform-modules-accton/debian/rules @@ -22,6 +22,9 @@ MOD_SRC_DIR:= $(shell pwd) MODULE_DIRS := as7712-32x as5712-54x as7816-64x as7716-32x as7716-32xb as7312-54x MODULE_DIRS += as7326-56x as6712-32x as7726-32x as4630-54pe as4630-54te minipack as5812-54x MODULE_DIRS += as5835-54x as9716-32d as9726-32d as5835-54t as7312-54xs as7315-27xb as5812-54t +MODULE_DIRS += as4630-54npe +MODULE_DIRS += as7926-40xfb +MODULE_DIRS += as7535-32xb MODULE_DIR := modules UTILS_DIR := utils SERVICE_DIR := service @@ -45,6 +48,12 @@ build: $(PYTHON3) sonic_platform_setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}; \ echo "Finished makig whl package for $$mod"; \ fi; \ + if [ -f fpga_setup.py ]; then\ + $(PYTHON) fpga_setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}; \ + mv $(MOD_SRC_DIR)/$${mod}/minipack_platform_fpga-1.0-cp2*.whl $(MOD_SRC_DIR)/$${mod}/minipack_platform_fpga-1.0-py2-none-any.whl; \ + $(PYTHON3) fpga_setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}; \ + mv $(MOD_SRC_DIR)/$${mod}/minipack_platform_fpga-1.0-cp3*.whl $(MOD_SRC_DIR)/$${mod}/minipack_platform_fpga-1.0-py3-none-any.whl; \ + fi;\ cd $(MOD_SRC_DIR); \ done) diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as4630-54npe.install b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as4630-54npe.install new file mode 100644 index 00000000000..5d02074e411 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as4630-54npe.install @@ -0,0 +1 @@ +as4630-54npe/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_as4630_54npe-r0 diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as4630-54pe.install b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as4630-54pe.install new file mode 100644 index 00000000000..4ba26bed262 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as4630-54pe.install @@ -0,0 +1 @@ +as4630-54pe/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_as4630_54pe-r0/pddf diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as4630-54pe.postinst b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as4630-54pe.postinst new file mode 100644 index 00000000000..23bebd3b295 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as4630-54pe.postinst @@ -0,0 +1,8 @@ +# Special arrangement to make PDDF mode default +# Disable monitor, monitor-fan, monitor-psu (not enabling them would imply they will be disabled by default) +# Enable pddf-platform-monitor +depmod -a +systemctl enable pddf-platform-init.service +systemctl start pddf-platform-init.service +systemctl enable as4630-54pe-pddf-platform-monitor.service +systemctl start as4630-54pe-pddf-platform-monitor.service diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as5812-54x.install b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as5812-54x.install new file mode 100644 index 00000000000..f6851a43a57 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as5812-54x.install @@ -0,0 +1,3 @@ +as5812-54x/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_as5812_54x-r0 + + diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as5835-54t.install b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as5835-54t.install new file mode 100644 index 00000000000..e7d3232907b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as5835-54t.install @@ -0,0 +1 @@ +as5835-54t/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_as5835_54t-r0/pddf diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as5835-54t.postinst b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as5835-54t.postinst new file mode 100644 index 00000000000..178b4d73628 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as5835-54t.postinst @@ -0,0 +1,9 @@ +# Special arrangement to make PDDF mode default +# Disable monitor, monitor-fan, monitor-psu (not enabling them would imply they will be disabled by default) +# Enable pddf-platform-monitor +depmod -a +systemctl enable pddf-platform-init.service +systemctl start pddf-platform-init.service +systemctl enable as5835-54t-pddf-platform-monitor.service +systemctl start as5835-54t-pddf-platform-monitor.service + diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as5835-54x.install b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as5835-54x.install index d108eb582c3..a234273ab74 100644 --- a/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as5835-54x.install +++ b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as5835-54x.install @@ -1,2 +1 @@ -as5835-54x/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_as5835_54x-r0 - +as5835-54x/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_as5835_54x-r0/pddf diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as5835-54x.postinst b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as5835-54x.postinst new file mode 100644 index 00000000000..c478bcac28a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as5835-54x.postinst @@ -0,0 +1,9 @@ +# Special arrangement to make PDDF mode default +# Disable monitor, monitor-fan, monitor-psu (not enabling them would imply they will be disabled by default) +# Enable pddf-platform-monitor +depmod -a +depmod -a +systemctl enable pddf-platform-init.service +systemctl start pddf-platform-init.service +systemctl enable as5835-54x-pddf-platform-monitor.service +systemctl start as5835-54x-pddf-platform-monitor.service diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as7535-32xb.install b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as7535-32xb.install new file mode 100644 index 00000000000..4eab94fd8ca --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as7535-32xb.install @@ -0,0 +1 @@ +as7535-32xb/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_as7535_32xb-r0 diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as7712-32x.install b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as7712-32x.install new file mode 100644 index 00000000000..7236da0e9ae --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as7712-32x.install @@ -0,0 +1 @@ +as7712-32x/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_as7712_32x-r0/pddf diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as7712-32x.postinst b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as7712-32x.postinst new file mode 100644 index 00000000000..4a393ec7035 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as7712-32x.postinst @@ -0,0 +1,8 @@ +# Special arrangement to make PDDF mode default +# Disable monitor, monitor-fan, monitor-psu (not enabling them would imply they will be disabled by default) +# Enable pddf-platform-monitor +depmod -a +systemctl enable pddf-platform-init.service +systemctl start pddf-platform-init.service +systemctl enable as7712-pddf-platform-monitor.service +systemctl start as7712-pddf-platform-monitor.service diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as7926-40xfb.install b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as7926-40xfb.install new file mode 100644 index 00000000000..fb1c2230ac9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as7926-40xfb.install @@ -0,0 +1,2 @@ +as7926-40xfb/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_as7926_40xfb-r0 + diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-minipack.install b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-minipack.install new file mode 100644 index 00000000000..b0534a7b839 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-minipack.install @@ -0,0 +1,3 @@ +minipack/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_minipack-r0 +minipack/minipack_platform_fpga-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_minipack-r0 + diff --git a/platform/broadcom/sonic-platform-modules-accton/minipack/classes/pimutil.py b/platform/broadcom/sonic-platform-modules-accton/minipack/classes/fpgautil.py old mode 100755 new mode 100644 similarity index 92% rename from platform/broadcom/sonic-platform-modules-accton/minipack/classes/pimutil.py rename to platform/broadcom/sonic-platform-modules-accton/minipack/classes/fpgautil.py index 05b68202be3..2371af4ebb8 --- a/platform/broadcom/sonic-platform-modules-accton/minipack/classes/pimutil.py +++ b/platform/broadcom/sonic-platform-modules-accton/minipack/classes/fpgautil.py @@ -18,23 +18,9 @@ # 5/29/2019: Jostar create for minipack # ----------------------------------------------------------- try: - import os - import sys, getopt - import subprocess - import click - import imp - import logging - import logging.config - import logging.handlers - import types import time # this is only being used as part of the example - import traceback - from tabulate import tabulate import fbfpgaio - import re import time - from select import select - #from ctypes import fbfpgaio except ImportError as e: raise ImportError('%s - required module not found' % str(e)) @@ -109,7 +95,7 @@ "dom_control_config": 0x410, "dom_global_status": 0x414, "dom_data": 0x4000, - + "mdio": { "config": 0x0200, @@ -158,7 +144,7 @@ def pim_io(pim, offset, data=None): def show_pim_present(): pim_status = fpga_io(iob["pim_status"]) - + header = "PIM # " status_str = " " for shift in range(0,8): @@ -198,40 +184,42 @@ def show_qsfp_present_status(pim_num): #pim_index start from 0 to 7 #port_index start from 0 to 127. Each 16-port is to one pim card. -class PimUtil(object): +class FpgaUtil(object): PORT_START = 0 PORT_END = 127 + PIM_START = 0 + PIM_END = 7 def __init__(self): self.value=1 def __del__(self): self.value=0 - + def init_pim_fpga(self): - init_resources() - + init_resources() + def release_pim_fpga(self): release_resources() def get_pim_by_port(self, port_num): if port_num < self.PORT_START or port_num > self.PORT_END: return False - pim_num=port_num/16 + pim_num=port_num//16 return True, pim_num+1 - + def get_onepimport_by_port(self, port_num): if port_num < self.PORT_START or port_num > self.PORT_END: return False if port_num < 16: return True, port_num else: - return True, port_num%16 + return True, port_num%16 def get_pim_presence(self, pim_num): - if pim_num <0 or pim_num > 7: - return 0 + if pim_num < self.PIM_START or pim_num > self.PIM_END: + return False pim_status = fpga_io(iob["pim_status"]) status = pim_status & (0x10000 << pim_num) if status: @@ -241,7 +229,7 @@ def get_pim_presence(self, pim_num): #return code=0:100G. return code=1:400G def get_pim_board_id(self, pim_num): - if pim_num <0 or pim_num > 7: + if pim_num < self.PIM_START or pim_num > self.PIM_END: return False board_id = fpga_io(dom_base[pim_num+1]+dom["revision"]) board_id = board_id & 0x1 @@ -252,7 +240,7 @@ def get_pim_board_id(self, pim_num): def get_pim_status(self, pim_num): - if pim_num <0 or pim_num > 7: + if pim_num < self.PIM_START or pim_num > self.PIM_END: return 0xFF power_status =0 #device_power_bad_status @@ -278,20 +266,20 @@ def get_pim_status(self, pim_num): return power_status #path=0:MDIO path is set on TH3. path=1:MDIO path is set on FPGA. def set_pim_mdio_source_sel(self, pim_num, path): - if pim_num <0 or pim_num > 7: + if pim_num < self.PIM_START or pim_num > self.PIM_END: return False status= pim_io(pim_num+1, dom["mdio"]["source_sel"]) - + if path==1: status = status | 0x2 else: status = status & 0xfffffffd - + pim_io(pim_num+1, dom["mdio"]["source_sel"], status) return True #retrun code=0, path is TH3. retrun code=1, path is FPGA def get_pim_mdio_source_sel(sefl, pim_num): - if pim_num <0 or pim_num > 7: + if pim_num < self.PIM_START or pim_num > self.PIM_END: return False path= pim_io(pim_num+1, dom["mdio"]["source_sel"]) path = path & 0x2 @@ -302,7 +290,7 @@ def get_pim_mdio_source_sel(sefl, pim_num): #This api will set mdio path to MAC side.(At default, mdio path is set to FPGA side). def pim_init(self, pim_num): - if pim_num <0 or pim_num > 7: + if pim_num < self.PIM_START or pim_num > self.PIM_END: return False status=self.set_pim_mdio_source_sel(pim_num, 0) #put init phy cmd here @@ -319,13 +307,13 @@ def get_pim_change_event(self, timeout=0): elif timeout > 0: timeout = timeout / float(1000) # Convert to secs else: - print("get_transceiver_change_event:Invalid timeout value", timeout) + print("get_transceiver_change_event:Invalid timeout value=%d"%(timeout)) return False, {} end_time = start_time + timeout if start_time > end_time: print('get_transceiver_change_event:' \ - 'time wrap / invalid timeout value', timeout) + 'time wrap / invalid timeout value=%d'%timeout) return False, {} # Time wrap or possibly incorrect timeout @@ -372,17 +360,17 @@ def get_pim_max_number(self): #color:0=amber, 1=blue #contrl:off(0),on(1), flash(2) def set_pim_led(self, pim_num, color, control): - if pim_num <0 or pim_num > 7: + if pim_num < self.PIM_START or pim_num > self.PIM_END: return False - + led_val=fpga_io(dom_base[pim_num+1]+dom["system_led"]) - + if color==1: led_val = led_val | (0x8000 | 0x4000) #blue elif color==0: led_val = (led_val & ( ~ 0x8000)) | 0x4000 #amber else: - print("Set RGB control to Green1") + led_val = led_val & (~ 0x4000) led_val = led_val & (~ 0xfff) led_val = led_val | 0x0f0 #B.G.R Birghtness, set to Green @@ -394,9 +382,9 @@ def set_pim_led(self, pim_num, color, control): led_val = led_val | 0x1000 #On else: led_val = led_val | 0x3000 #Flash - + fpga_io(dom_base[pim_num+1]+dom["system_led"], led_val) - + def get_qsfp_presence(self, port_num): #xlate port to get pim_num status, pim_num=self.get_pim_by_port(port_num) @@ -417,12 +405,12 @@ def get_qsfp_presence(self, port_num): #return code: low_power(1) or high_power(0) def get_low_power_mode(self, port_num): status, pim_num=self.get_pim_by_port(port_num) - + if status==0: return False else: lp_mode = fpga_io(dom_base[pim_num]+dom["qsfp_lp_mode"]) - + status, shift=self.get_onepimport_by_port(port_num) if status==0: return False @@ -488,6 +476,19 @@ def reset(self, port_num): val = val & (~(0x1 << shift)) fpga_io(dom_base[pim]+dom["qsfp_reset"], val) return True + + def get_reset(self, port_num): + status, pim=self.get_pim_by_port(port_num) + if status==0: + return False + + val=fpga_io(dom_base[pim]+dom["qsfp_reset"]) + status, shift=self.get_onepimport_by_port(port_num) + + if val & (0x1 << shift): + return 1 + else: + return 0 #color:white(0), blue(1),red(2), orange(3),green(4) def set_port_led(self, port_num, color, control): @@ -534,7 +535,7 @@ def get_port_led(self, port_num): control=1 else: control=0 - + color = led_val & 0x1C if color==0: color=0 #white @@ -547,12 +548,12 @@ def get_port_led(self, port_num): elif color==0x1C: color=4 #green - print("color=%d, control=%d"%(color, control)) + return color, control - + def main(argv): - init_resources() - pim=PimUtil() + init_resources() + pim=FpgaUtil() print("Test Board ID") for x in range(0,8): val=pim.get_pim_board_id(x) @@ -561,17 +562,25 @@ def main(argv): print("100G board") else: print("400G board") - + print("Test pim presence") for x in range(0,8): pres=pim.get_pim_presence(x) - print("pim=%d, presence=%d"%(x, pres)) - + print("pim=%d, presence=%d"%(x, pres) ) + print("Test pim status") for x in range(0,8): power_status=pim.get_pim_status(x) print("pim=%d power_status=0x%x"%(x, power_status)) + print("Test port status") + for x in range(0,16): + pres=pim.get_qsfp_presence(x) + print("port=%d, presence=%d"%(x, pres)) + #for x in range(0, 16): + # pim.get_reset(x) + + release_resources() if __name__ == '__main__': diff --git a/platform/broadcom/sonic-platform-modules-accton/minipack/fpga_setup.py b/platform/broadcom/sonic-platform-modules-accton/minipack/fpga_setup.py new file mode 100644 index 00000000000..2e3ec845ba3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/minipack/fpga_setup.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python + +import os +from setuptools import setup, Extension +os.listdir + +module1 = Extension("fbfpgaio", sources = ["lib/fbfpgaiomodule.c"]) + +setup( + name='minipack_platform_fpga', + version='1.0', + description='Module to initialize Accton MiniPack platforms', + + packages=['minipack'], + package_dir={'minipack': 'classes'}, + ext_modules=[module1], + +) + diff --git a/platform/broadcom/sonic-platform-modules-accton/minipack/lib/fbfpgaiomodule.c b/platform/broadcom/sonic-platform-modules-accton/minipack/lib/fbfpgaiomodule.c index f5f8c8235fc..87976532352 100755 --- a/platform/broadcom/sonic-platform-modules-accton/minipack/lib/fbfpgaiomodule.c +++ b/platform/broadcom/sonic-platform-modules-accton/minipack/lib/fbfpgaiomodule.c @@ -1,3 +1,4 @@ +/* # Copyright (c) 2019 Edgecore Networks Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -11,6 +12,7 @@ # # See the Apache Version 2.0 License for specific language governing # permissions and limitations under the License. +*/ #include #include @@ -38,21 +40,21 @@ static PyObject *fbfpgaio_hw_init(PyObject *self) IDEBUG("[ERROR] %s: open hw resource node\n", __func__); return Py_False; } - + IDEBUG("[PASS] %s: open hw resource node\n", __func__); /* Mapping hardware resource */ io_base = mmap(NULL, FPGA_RESOURCE_LENGTH, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_NORESERVE, hw_handle, 0); if (io_base == MAP_FAILED) { IDEBUG("[ERROR] %s: mapping resource node\n", __func__); - perror("map_failed"); + perror("map_failed"); fprintf(stderr,"%d %s\\n",errno,strerror(errno)); return Py_False; } - + IDEBUG("[PASS] %s: mapping resource node\n", __func__); - return Py_True; + return Py_True; } static PyObject *fbfpgaio_hw_release(PyObject *self) @@ -69,7 +71,7 @@ static PyObject *fbfpgaio_hw_release(PyObject *self) } IDEBUG("[ERROR] %s: unmapping resource node\n", __func__); - return Py_False; + return Py_False; } static PyObject *fbfpgaio_hw_io(PyObject *self, PyObject *args) @@ -119,13 +121,6 @@ static char docstr[] = "\ In reading operation: data which is read from FPGA\n\ In writing operation: None\n"; -#if PY_MAJOR_VERSION < 3 -PyMODINIT_FUNC -initfbfpgaio(void) -{ - (void) Py_InitModule3("fbfpgaio", FbfpgaMethods, docstr); -} -#else static struct PyModuleDef FbfpgaModule = { PyModuleDef_HEAD_INIT, @@ -140,5 +135,5 @@ PyInit_fbfpgaio(void) { return PyModule_Create(&FbfpgaModule); } -#endif + diff --git a/platform/broadcom/sonic-platform-modules-accton/minipack/modules/minipack_psensor.c b/platform/broadcom/sonic-platform-modules-accton/minipack/modules/minipack_psensor.c index 3155b2b27c4..52ae543892c 100755 --- a/platform/broadcom/sonic-platform-modules-accton/minipack/modules/minipack_psensor.c +++ b/platform/broadcom/sonic-platform-modules-accton/minipack/modules/minipack_psensor.c @@ -62,7 +62,8 @@ MODULE_PARM_DESC(poll_interval, "Time interval for data polling, in unit of seco #define CHASSIS_LED_COUNT (2) #define CHASSIS_PSU_VOUT_COUNT (1) /*V output only.*/ #define CHASSIS_PSU_VOUT_INDEX (1) /*V output start index.*/ - +#define MAX_MODEL_NAME 21 +#define MAX_SERIAL_NUMBER 19 #define ATTR_ALLOC_EXTRA 1 /*For last attribute which is NUll.*/ #define ATTR_NAME_SIZE 24 @@ -102,6 +103,14 @@ enum sensor_type_e { SENSOR_TYPE_PSU2, SENSOR_TYPE_PSU3, SENSOR_TYPE_PSU4, + SENSOR_TYPE_PSU1_MODEL, + SENSOR_TYPE_PSU2_MODEL, + SENSOR_TYPE_PSU3_MODEL, + SENSOR_TYPE_PSU4_MODEL, + SENSOR_TYPE_PSU1_SERIAL, + SENSOR_TYPE_PSU2_SERIAL, + SENSOR_TYPE_PSU3_SERIAL, + SENSOR_TYPE_PSU4_SERIAL, SENSOR_TYPE_MAX, }; @@ -113,6 +122,14 @@ enum sysfs_attributes_index { INDEX_PSU2_START = SENSOR_TYPE_PSU2 *ATTR_TYPE_INDEX_GAP, INDEX_PSU3_START = SENSOR_TYPE_PSU3 *ATTR_TYPE_INDEX_GAP, INDEX_PSU4_START = SENSOR_TYPE_PSU4 *ATTR_TYPE_INDEX_GAP, + INDEX_PSU1_MODEL = SENSOR_TYPE_PSU1_MODEL *ATTR_TYPE_INDEX_GAP, + INDEX_PSU2_MODEL = SENSOR_TYPE_PSU2_MODEL *ATTR_TYPE_INDEX_GAP, + INDEX_PSU3_MODEL = SENSOR_TYPE_PSU3_MODEL *ATTR_TYPE_INDEX_GAP, + INDEX_PSU4_MODEL = SENSOR_TYPE_PSU4_MODEL *ATTR_TYPE_INDEX_GAP, + INDEX_PSU1_SERIAL = SENSOR_TYPE_PSU1_SERIAL *ATTR_TYPE_INDEX_GAP, + INDEX_PSU2_SERIAL = SENSOR_TYPE_PSU2_SERIAL *ATTR_TYPE_INDEX_GAP, + INDEX_PSU3_SERIAL = SENSOR_TYPE_PSU3_SERIAL *ATTR_TYPE_INDEX_GAP, + INDEX_PSU4_SERIAL = SENSOR_TYPE_PSU4_SERIAL *ATTR_TYPE_INDEX_GAP, INDEX_NAME = SENSOR_TYPE_MAX *ATTR_TYPE_INDEX_GAP, }; @@ -123,6 +140,9 @@ enum sysfs_attributes_index { #define PMBUS_READ_IOUT 0x8C #define PMBUS_READ_POUT 0x96 #define PMBUS_READ_PIN 0x97 +#define PMBUS_READ_FAN 0x90 +#define PMBUS_READ_TEMP 0x8D + #define PMBUS_REG_START PMBUS_READ_VIN #define PMBUS_REG_END PMBUS_READ_PIN @@ -134,6 +154,8 @@ enum psu_data_e { PSU_DATA_IOUT, PSU_DATA_PIN, PSU_DATA_POUT, + PSU_DATA_FAN, + PSU_DATA_TEMP, PSU_DATA_MAX, }; @@ -147,6 +169,8 @@ struct pmbus_reg_t { [PSU_DATA_IOUT] = {PMBUS_READ_IOUT, false}, [PSU_DATA_PIN ] = {PMBUS_READ_PIN, true}, [PSU_DATA_POUT] = {PMBUS_READ_POUT, true}, + [PSU_DATA_FAN] = {PMBUS_READ_FAN, false}, + [PSU_DATA_TEMP] = {PMBUS_READ_TEMP, false}, }; struct sensor_data { @@ -154,6 +178,8 @@ struct sensor_data { int fan_rpm[MAX_FAN_COUNT]; int fan_rpm_dn[MAX_FAN_COUNT]; int psu_data [MAX_PSU_COUNT][PSU_DATA_MAX]; + int psu_model [MAX_PSU_COUNT][MAX_MODEL_NAME]; + int psu_serial [MAX_PSU_COUNT][MAX_SERIAL_NUMBER]; int led_bright[CHASSIS_LED_COUNT]; }; @@ -225,6 +251,10 @@ static struct attr_pattern psu##index##_curr = {CHASSIS_PSU_CHAR_COUNT, \ CHASSIS_PSU_CHAR_COUNT*index, "curr","_input", S_IRUGO, _attr_show, NULL}; \ static struct attr_pattern psu##index##_pwr = {CHASSIS_PSU_CHAR_COUNT, \ CHASSIS_PSU_CHAR_COUNT*index, "power","_input", S_IRUGO, _attr_show, NULL}; \ +static struct attr_pattern psu##index##_fan_speed = {1, \ +1*index, "psu","_fan_speed", S_IRUGO, _attr_show, NULL}; \ +static struct attr_pattern psu##index##_temp_input = {1, \ +1*index, "psu","_temp_input", S_IRUGO, _attr_show, NULL}; \ static struct attr_pattern psu##index##_vmax = {CHASSIS_PSU_VOUT_COUNT, \ CHASSIS_PSU_CHAR_COUNT*index + 1, "in","_max", S_IRUGO, show_psu_vout_max, NULL};\ static struct attr_pattern psu##index##_vmin = {CHASSIS_PSU_VOUT_COUNT, \ @@ -232,7 +262,21 @@ CHASSIS_PSU_CHAR_COUNT*index + 1, "in","_min", S_IRUGO, show_psu_vout_min, NULL} #define DECLARE_PSU_ATTR(index) \ &psu##index##_vin, &psu##index##_curr, &psu##index##_pwr, \ - &psu##index##_vmax, &psu##index##_vmin + &psu##index##_fan_speed, &psu##index##_temp_input ,&psu##index##_vmax, &psu##index##_vmin + +#define DECLARE_PSU_MODEL_NAME_SENSOR_DEVICE_ATTR(index) \ +static struct attr_pattern psu##index##_model_name = {1, \ +1*index, "psu","_model_name", S_IRUGO, _attr_show, NULL}; + +#define DECLARE_PSU_MODEL_NAME_ATTR(index) \ + &psu##index##_model_name + +#define DECLARE_PSU_SERIAL_NUMBER_SENSOR_DEVICE_ATTR(index) \ +static struct attr_pattern psu##index##_serial_name = {1, \ +1*index, "psu","_serial_num", S_IRUGO, _attr_show, NULL}; + +#define DECLARE_PSU_SERIAL_NUMBER_ATTR(index) \ + &psu##index##_serial_name DECLARE_PSU_SENSOR_DEVICE_ATTR(0); @@ -240,6 +284,15 @@ DECLARE_PSU_SENSOR_DEVICE_ATTR(1); DECLARE_PSU_SENSOR_DEVICE_ATTR(2); DECLARE_PSU_SENSOR_DEVICE_ATTR(3); +DECLARE_PSU_MODEL_NAME_SENSOR_DEVICE_ATTR(0); +DECLARE_PSU_MODEL_NAME_SENSOR_DEVICE_ATTR(1); +DECLARE_PSU_MODEL_NAME_SENSOR_DEVICE_ATTR(2); +DECLARE_PSU_MODEL_NAME_SENSOR_DEVICE_ATTR(3); + +DECLARE_PSU_SERIAL_NUMBER_SENSOR_DEVICE_ATTR(0); +DECLARE_PSU_SERIAL_NUMBER_SENSOR_DEVICE_ATTR(1); +DECLARE_PSU_SERIAL_NUMBER_SENSOR_DEVICE_ATTR(2); +DECLARE_PSU_SERIAL_NUMBER_SENSOR_DEVICE_ATTR(3); static char tty_cmd[SENSOR_TYPE_MAX][TTY_CMD_MAX_LEN] = { @@ -259,6 +312,14 @@ static char tty_cmd[SENSOR_TYPE_MAX][TTY_CMD_MAX_LEN] = { "i2cdump -y -f -r "\ __stringify(PMBUS_REG_START)"-" __stringify(PMBUS_REG_END)\ " 56 0x58 w\r", + "i2cdump -y -f 49 0x59 s 0x9a|tail -n +2|cut -c56-\r", + "i2cdump -y -f 48 0x58 s 0x9a|tail -n +2|cut -c56-\r", + "i2cdump -y -f 57 0x59 s 0x9a|tail -n +2|cut -c56-\r", + "i2cdump -y -f 56 0x58 s 0x9a|tail -n +2|cut -c56-\r", + "i2cdump -y -f 49 0x59 s 0x9e|tail -n +2|cut -c56-\r", + "i2cdump -y -f 48 0x58 s 0x9e|tail -n +2|cut -c56-\r", + "i2cdump -y -f 57 0x59 s 0x9e|tail -n +2|cut -c56-\r", + "i2cdump -y -f 56 0x58 s 0x9e|tail -n +2|cut -c56-\r", }; static struct attr_pattern temp_in = @@ -305,6 +366,31 @@ struct sensor_set model_ssets[SENSOR_TYPE_MAX] = { PSU_DATA_MAX, INDEX_PSU4_START, tty_cmd[SENSOR_TYPE_PSU4], TTY_PMBUS_INTERVAL, {DECLARE_PSU_ATTR(3), NULL}, }, + { 1, INDEX_PSU1_MODEL, tty_cmd[SENSOR_TYPE_PSU1_MODEL], + TTY_PMBUS_INTERVAL, {DECLARE_PSU_MODEL_NAME_ATTR(0), NULL}, + }, + { 1, INDEX_PSU2_MODEL, tty_cmd[SENSOR_TYPE_PSU2_MODEL], + TTY_PMBUS_INTERVAL, {DECLARE_PSU_MODEL_NAME_ATTR(1), NULL}, + }, + { 1, INDEX_PSU3_MODEL, tty_cmd[SENSOR_TYPE_PSU3_MODEL], + TTY_PMBUS_INTERVAL, {DECLARE_PSU_MODEL_NAME_ATTR(2), NULL}, + }, + { 1, INDEX_PSU4_MODEL, tty_cmd[SENSOR_TYPE_PSU4_MODEL], + TTY_PMBUS_INTERVAL, {DECLARE_PSU_MODEL_NAME_ATTR(3), NULL}, + }, + { 1, INDEX_PSU1_SERIAL, tty_cmd[SENSOR_TYPE_PSU1_SERIAL], + TTY_PMBUS_INTERVAL, {DECLARE_PSU_SERIAL_NUMBER_ATTR(0), NULL}, + }, + { 1, INDEX_PSU2_SERIAL, tty_cmd[SENSOR_TYPE_PSU2_SERIAL], + TTY_PMBUS_INTERVAL, {DECLARE_PSU_SERIAL_NUMBER_ATTR(1), NULL}, + }, + { 1, INDEX_PSU3_SERIAL, tty_cmd[SENSOR_TYPE_PSU3_SERIAL], + TTY_PMBUS_INTERVAL, {DECLARE_PSU_SERIAL_NUMBER_ATTR(2), NULL}, + }, + { 1, INDEX_PSU4_SERIAL, tty_cmd[SENSOR_TYPE_PSU4_SERIAL], + TTY_PMBUS_INTERVAL, {DECLARE_PSU_SERIAL_NUMBER_ATTR(3), NULL}, + }, + }; static struct minipack_data *mp_data = NULL; @@ -810,6 +896,29 @@ static int get_pmbus_regs_partial(int *in, int in_cnt, int *out, int *out_cnt) return 0; } +static int extract_psu_str(int type, char *buf, int *out, int len) +{ + char *ptr; + int cnt, x, i; + int index; + struct minipack_data *data = mp_data; + + ptr = buf; + + i=0; + for (x = 0; x < strlen(ptr); x++) { + if(ptr[x] > 0x7A || ptr[x] <0x1E) + continue; + + out[i]=ptr[x]; + i++; + if(i==(len-2)) + break; + } + out[len-1]=0x0; + + return 0; +} static int comm2BMC(enum sensor_type_e type, int *out, int out_cnt) { @@ -853,6 +962,18 @@ static int comm2BMC(enum sensor_type_e type, int *out, int out_cnt) get_pmbus_regs_partial(reg, total, out, &out_cnt); break; } + case SENSOR_TYPE_PSU1_MODEL: + case SENSOR_TYPE_PSU2_MODEL: + case SENSOR_TYPE_PSU3_MODEL: + case SENSOR_TYPE_PSU4_MODEL: + ret=extract_psu_str(type, ptr, out, MAX_MODEL_NAME); + break; + case SENSOR_TYPE_PSU1_SERIAL: + case SENSOR_TYPE_PSU2_SERIAL: + case SENSOR_TYPE_PSU3_SERIAL: + case SENSOR_TYPE_PSU4_SERIAL: + ret=extract_psu_str(type ,ptr, out, MAX_SERIAL_NUMBER); + break; default: return -EINVAL; } @@ -882,6 +1003,18 @@ static int get_type_data ( case SENSOR_TYPE_PSU4: *out = &data->psu_data[type-SENSOR_TYPE_PSU1][index]; break; + case SENSOR_TYPE_PSU1_MODEL: + case SENSOR_TYPE_PSU2_MODEL: + case SENSOR_TYPE_PSU3_MODEL: + case SENSOR_TYPE_PSU4_MODEL: + *out = &data->psu_model[type-SENSOR_TYPE_PSU1_MODEL][index]; + break; + case SENSOR_TYPE_PSU1_SERIAL: + case SENSOR_TYPE_PSU2_SERIAL: + case SENSOR_TYPE_PSU3_SERIAL: + case SENSOR_TYPE_PSU4_SERIAL: + *out = &data->psu_serial[type-SENSOR_TYPE_PSU1_SERIAL][index]; + break; default: return -EINVAL; } @@ -942,6 +1075,10 @@ static ssize_t _attr_show(struct device *dev, struct device_attribute *da, struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct sensor_data* data; int *out = NULL; + int i; + struct minipack_data *mdata = mp_data; + char model_name[MAX_MODEL_NAME]; + char serial_number[MAX_SERIAL_NUMBER]; enum sensor_type_e type; type = attr->index / ATTR_TYPE_INDEX_GAP; @@ -958,6 +1095,35 @@ static ssize_t _attr_show(struct device *dev, struct device_attribute *da, if( index > count) return -EINVAL; + + if(type >=SENSOR_TYPE_PSU1_MODEL && type <=SENSOR_TYPE_PSU4_MODEL) + { + for(i=0; i=SENSOR_TYPE_PSU1_SERIAL && type <=SENSOR_TYPE_PSU4_SERIAL) + { + + for(i=0; i. -# -# Description: -# Due to adoption of optoe drivers, sideband signals of SFPs are moved -# into cpld drivers. Add a new dict, cpld_of_module, for mapping this -# attributes to corresponding cpld nodes. -# - """ Usage: %(scriptName)s [options] command object @@ -32,17 +25,13 @@ command: install : install drivers and generate related sysfs nodes clean : uninstall drivers and remove related sysfs nodes - show : show all systen status - sff : dump SFP eeprom - set : change board setting with led|sfp """ - import subprocess import getopt import sys import logging -import re import time +import os PROJECT_NAME = 'minipack' version = '0.2.0' @@ -50,24 +39,11 @@ DEBUG = False args = [] ALL_DEVICE = {} -DEVICE_NO = {'led':5, 'psu':2, 'sfp':32} - - -led_prefix ='' -hwmon_types = {'led': ['diag','loc'], - } -hwmon_nodes = {'led': ['brightness'] , - } -hwmon_prefix ={'led': led_prefix, - } i2c_prefix = '/sys/bus/i2c/devices/' i2c_bus = { 'psu': ['35-0038','36-003b'], 'sfp': ['-0050']} -i2c_nodes = { - 'psu': ['psu_present ', 'psu_power_good'] , - 'sfp': ['module_present_', 'sfp_tx_disable']} NO_QSFP = 128 @@ -123,6 +99,10 @@ def main(): do_install() elif arg == 'clean': do_uninstall() + elif arg == 'api': + do_minipack_fpga_install() + elif arg == 'api_clean': + do_minipack_fpga_clean() elif arg == 'show': device_traversal() elif arg == 'sff': @@ -149,18 +129,6 @@ def show_help(): print(__doc__ % {'scriptName' : sys.argv[0].split("/")[-1]}) sys.exit(0) -def show_set_help(): - cmd = sys.argv[0].split("/")[-1]+ " " + args[0] - print(cmd +" [led|sfp]") - print(" use \""+ cmd + " led 0-4 \" to set led color") - print(" use \""+ cmd + " sfp 1-32 {0|1}\" to set sfp# tx_disable") - sys.exit(0) - -def show_eeprom_help(): - cmd = sys.argv[0].split("/")[-1]+ " " + args[0] - print(" use \""+ cmd + " 1-54 \" to dump sfp# eeprom") - sys.exit(0) - def my_log(txt): if DEBUG == True: print("[ACCTON DBG]: "+txt) @@ -193,11 +161,12 @@ def driver_inserted(): kos = [ 'depmod -ae', 'modprobe i2c_dev', -'modprobe i2c_mux_pca954x force_deselect_on_exit=1', +'modprobe i2c_mux_pca954x', 'modprobe optoe', 'modprobe minipack_psensor'] def driver_install(): + global FORCE for i in range(0,len(kos)): status, output = log_os_system(kos[i], 1) if status: @@ -206,6 +175,7 @@ def driver_install(): return 0 def driver_uninstall(): + global FORCE for i in range(0,len(kos)): #remove parameter if any rm = kos[-(i+1)] @@ -225,7 +195,7 @@ def driver_uninstall(): def sfp_map(index): port = index + 1 - base = ((port-1)/8*8) + 10 + base = ((port-1)//8*8) + 10 index = (port - 1) % 8 index = 7 - index if (index%2): @@ -236,6 +206,7 @@ def sfp_map(index): return bus def device_install(): + global FORCE for i in range(0,len(mknod)): #for pca932x need times to built new i2c buses if mknod[i].find('pca954') != -1: @@ -247,6 +218,14 @@ def device_install(): if FORCE == 0: return status + # set all pca954x idle_disconnect + cmd = 'echo -2 | tee /sys/bus/i2c/drivers/pca954x/*-00*/idle_state' + status, output = log_os_system(cmd, 1) + if status: + print(output) + if FORCE == 0: + return status + rm_cmd="rm -rf /usr/local/bin/minipack_qsfp > /dev/null 2>&1" log_os_system(rm_cmd, 1) mk_cmd= "mkdir /usr/local/bin/minipack_qsfp" @@ -255,6 +234,7 @@ def device_install(): return def device_uninstall(): + global FORCE nodelist = mknod for i in range(len(nodelist)): target = nodelist[-(i+1)] @@ -276,7 +256,45 @@ def system_ready(): return False return True +PLATFORM_ROOT_PATH = '/usr/share/sonic/device' +MINIPACK_FPGA_WHL_FILE_PY3 ='minipack_platform_fpga-1.0-py3-none-any.whl' +def do_minipack_fpga_install(): + device_path = "{}{}{}{}".format(PLATFORM_ROOT_PATH, '/x86_64-accton_', PROJECT_NAME, '-r0') + MINIPACK_FPGA_BSP_WHL_PKG_PY3 = "/".join([device_path, MINIPACK_FPGA_WHL_FILE_PY3]) + + status, output = log_os_system("pip3 show minipack-platform-fpga > /dev/null 2>&1", 0) + if status: + if os.path.exists(MINIPACK_FPGA_BSP_WHL_PKG_PY3): + status, output = log_os_system("pip3 install "+ MINIPACK_FPGA_BSP_WHL_PKG_PY3, 1) + if status: + print("Error: Failed to install {}".format(MINIPACK_FPGA_WHL_FILE_PY3)) + return status + else: + print("Successfully installed {} package".format(MINIPACK_FPGA_WHL_FILE_PY3)) + else: + print('{} is not found'.format(MINIPACK_FPGA_WHL_FILE_PY3)) + else: + print('{} has installed'.format(MINIPACK_FPGA_WHL_FILE_PY3)) + + return + +def do_minipack_fpga_clean(): + status, output = log_os_system("pip3 show minipack-platform-fpga > /dev/null 2>&1", 0) + if status: + print('{} does not install, not need to uninstall'.format(MINIPACK_FPGA_WHL_FILE_PY3)) + + else: + status, output = log_os_system("pip3 uninstall minipack-platform-fpga -y", 0) + if status: + print('Error: Failed to uninstall {}'.format(MINIPACK_FPGA_WHL_FILE_PY3)) + return status + else: + print('{} is uninstalled'.format(MINIPACK_FPGA_WHL_FILE_PY3)) + + return + def do_install(): + global FORCE print("Checking system....") if driver_inserted() == False: print("No driver, installing....") @@ -293,10 +311,13 @@ def do_install(): if FORCE == 0: return status else: - print(PROJECT_NAME.upper()+" devices detected....") + print( PROJECT_NAME.upper()+" devices detected....") + + do_minipack_fpga_install() return def do_uninstall(): + global FORCE print("Checking system....") if not device_exist(): print(PROJECT_NAME.upper() +" has no device installed....") @@ -316,165 +337,9 @@ def do_uninstall(): if FORCE == 0: return status + do_minipack_fpga_clean() return -def devices_info(): - global DEVICE_NO - global ALL_DEVICE - global i2c_bus, hwmon_types - for key in DEVICE_NO: - ALL_DEVICE[key]= {} - for i in range(0,DEVICE_NO[key]): - ALL_DEVICE[key][key+str(i+1)] = [] - - for key in i2c_bus: - buses = i2c_bus[key] - nodes = i2c_nodes[key] - for i in range(0,len(buses)): - for j in range(0,len(nodes)): - if 'sfp' == key: - for k in range(0,DEVICE_NO[key]): - bus = 1 - node = key+str(k+1) - path = i2c_prefix + str(bus) + lk + "/"+ nodes[j] + str(k+1) - my_log(node+": "+ path) - ALL_DEVICE[key][node].append(path) - else: - node = key+str(i+1) - path = i2c_prefix+ buses[i]+"/"+ nodes[j] - my_log(node+": "+ path) - ALL_DEVICE[key][node].append(path) - - for key in hwmon_types: - itypes = hwmon_types[key] - nodes = hwmon_nodes[key] - for i in range(0,len(itypes)): - for j in range(0,len(nodes)): - node = key+"_"+itypes[i] - path = hwmon_prefix[key]+ itypes[i]+"/"+ nodes[j] - my_log(node+": "+ path) - ALL_DEVICE[key][ key+str(i+1)].append(path) - - #show dict all in the order - if DEBUG == True: - for i in sorted(ALL_DEVICE.keys()): - print((i+": ")) - for j in sorted(ALL_DEVICE[i].keys()): - print((" "+j)) - for k in (ALL_DEVICE[i][j]): - print((" "+" "+k)) - return - -def show_eeprom(index): - if system_ready()==False: - print("System's not ready.") - print("Please install first!") - return - - if len(ALL_DEVICE)==0: - devices_info() - node = ALL_DEVICE['sfp'] ['sfp'+str(index)][0] - node = node.replace(node.split("/")[-1], 'eeprom') - # check if got hexdump command in current environment - ret, log = log_os_system("which hexdump", 0) - ret, log2 = log_os_system("which busybox hexdump", 0) - if len(log): - hex_cmd = 'hexdump' - elif len(log2): - hex_cmd = ' busybox hexdump' - else: - log = 'Failed : no hexdump cmd!!' - logging.info(log) - print(log) - return 1 - - print(node + ":") - ret, log = log_os_system("cat "+node+"| "+hex_cmd+" -C", 1) - if ret==0: - print(log) - else: - print("**********device no found**********") - return - -def set_device(args): - global DEVICE_NO - global ALL_DEVICE - if system_ready()==False: - print("System's not ready.") - print("Please install first!") - return - - if len(ALL_DEVICE)==0: - devices_info() - - if args[0]=='led': - if int(args[1])>4: - show_set_help() - return - #print ALL_DEVICE['led'] - for i in range(0,len(ALL_DEVICE['led'])): - for k in (ALL_DEVICE['led']['led'+str(i+1)]): - ret, log = log_os_system("echo "+args[1]+" >"+k, 1) - if ret: - return ret - elif args[0]=='sfp': - if int(args[1])> DEVICE_NO[args[0]] or int(args[1])==0: - show_set_help() - return - if len(args)<2: - show_set_help() - return - - if int(args[2])>1: - show_set_help() - return - - #print ALL_DEVICE[args[0]] - for i in range(0,len(ALL_DEVICE[args[0]])): - for j in ALL_DEVICE[args[0]][args[0]+str(args[1])]: - if j.find('tx_disable')!= -1: - ret, log = log_os_system("echo "+args[2]+" >"+ j, 1) - if ret: - return ret - - return - -#get digits inside a string. -#Ex: 31 for "sfp31" -def get_value(input): - digit = re.findall('\d+', input) - return int(digit[0]) - -def device_traversal(): - if system_ready()==False: - print("System's not ready.") - print("Please install first!") - return - - if len(ALL_DEVICE)==0: - devices_info() - for i in sorted(ALL_DEVICE.keys()): - print("============================================") - print((i.upper()+": ")) - print("============================================") - - for j in sorted(list(ALL_DEVICE[i].keys()), key=get_value): - print(" "+j+":", end=' ') - for k in (ALL_DEVICE[i][j]): - ret, log = log_os_system("cat "+k, 0) - func = k.split("/")[-1].strip() - func = re.sub(j+'_','',func,1) - func = re.sub(i.lower()+'_','',func,1) - if ret==0: - print(func+"="+log+" ", end=' ') - else: - print(func+"="+"X"+" ", end=' ') - print() - print("----------------------------------------------------------------") - - - print() - return def device_exist(): ret1, log = log_os_system("ls "+i2c_prefix+"*0070", 0) diff --git a/platform/broadcom/sonic-platform-modules-accton/minipack/utils/setup_qsfp_eeprom.py b/platform/broadcom/sonic-platform-modules-accton/minipack/utils/setup_qsfp_eeprom.py index 5ef6a4107e3..0ba1a03f8d2 100755 --- a/platform/broadcom/sonic-platform-modules-accton/minipack/utils/setup_qsfp_eeprom.py +++ b/platform/broadcom/sonic-platform-modules-accton/minipack/utils/setup_qsfp_eeprom.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # # Copyright (c) 2019 Edgecore Networks Corporation # @@ -29,9 +29,8 @@ import logging.handlers import types import time # this is only being used as part of the example - import traceback - from tabulate import tabulate - from minipack.pimutil import PimUtil + import traceback + from minipack.fpgautil import FpgaUtil except ImportError as e: raise ImportError('%s - required module not found' % str(e)) @@ -57,7 +56,7 @@ oom_i2c_bus_table=1 -pim_dev=PimUtil() +pim_dev=FpgaUtil() # Deafults VERSION = '1.0' @@ -82,7 +81,7 @@ def log_os_system(cmd): def qsfp_map_bus(idx): port = idx + 1 - base = ((port-1)/8*8) + 10 + base = ((port-1)//8*8) + 10 idx = (port - 1) % 8 idx = 7 - idx if (idx%2): @@ -91,23 +90,23 @@ def qsfp_map_bus(idx): idx = idx +1 bus = base + idx return bus - + def pca9548_sysfs(i2c_bus, create): - if create==1: + if create==1: cmdl = "echo pca9548 0x%x > /sys/bus/i2c/devices/i2c-%d/new_device" else: - cmdl = "echo 0x%x > /sys/bus/i2c/devices/i2c-%d/delete_device" - + cmdl = "echo 0x%x > /sys/bus/i2c/devices/i2c-%d/delete_device" + cmdm = cmdl % (0x72, i2c_bus) - status1, output =log_os_system(cmdm) + status1, output =log_os_system(cmdm) cmdm = cmdl % (0x71, i2c_bus) status2, output =log_os_system(cmdm) return (status1 | status2) -def qsfp_eeprom_sys(pim_idx, i2c_bus_order, create): +def qsfp_eeprom_sys(pim_idx, i2c_bus_order, create): # initialize multiplexer for 8 PIMs - global port_use_i2c_bus + global port_use_i2c_bus start_port=pim_idx*16 end_port = (pim_idx+1)*16 start_bus=(i2c_bus_order-1)*16 @@ -123,18 +122,18 @@ def qsfp_eeprom_sys(pim_idx, i2c_bus_order, create): return 1 status, output =log_os_system( "echo port"+str(k+1)+" > /sys/bus/i2c/devices/"+str(bus)+"-0050/port_name") - + status, output =log_os_system( "ln -s -f /sys/bus/i2c/devices/"+str(bus)+"-0050/eeprom" + " /usr/local/bin/minipack_qsfp/port" + str(k) + "_eeprom") if status: print(output) return 1 - else: + else: status, output =log_os_system( "echo 0x50 > /sys/bus/i2c/devices/i2c-"+str(bus)+"/delete_device") if status: print(output) - + k=k+1 return 0 @@ -149,31 +148,31 @@ def set_pim_port_use_bus(pim_idx): global pim_port_use_bus global oom_i2c_bus_table - + if pim_port_use_bus[pim_idx]!=0: return 0 - + pim_port_use_bus[pim_idx]=oom_i2c_bus_table oom_i2c_bus_table=oom_i2c_bus_table+1 - + return pim_port_use_bus[pim_idx] - + def del_pim_port_use_bus(pim_idx): global oom_i2c_bus_table - + oom_i2c_bus_table=oom_i2c_bus_table-1 pim_port_use_bus[pim_idx]=0 - -def device_remove(): - cmd1 = "echo 0x%x > /sys/bus/i2c/devices/i2c-%d/delete_device" - - for bus in range(2, 10): + +def device_remove(): + cmd1 = "echo 0x%x > /sys/bus/i2c/devices/i2c-%d/delete_device" + + for bus in range(2, 10): #ret=check_pca_active(0x72, bus) #if ret==0: - - cmdm= cmd1 % (0x72, bus) + + cmdm= cmd1 % (0x72, bus) status, output = subprocess.getstatusoutput(cmdm) print("Remove %d-0072 i2c device"%bus) cmdm= cmd1 % (0x71, bus) @@ -183,13 +182,13 @@ def device_remove(): cmd="rm -f /usr/local/bin/minipack_qsfp/port*" status, output=log_os_system(cmd) return status - + class device_monitor(object): - + PIM_STATE_REMOVE = 0 PIM_STATE_INSERT = 1 - PIM_STATE_IDLE=2 - + PIM_STATE_IDLE=2 + def __init__(self, log_file, log_level): """Needs a logger and a logger level.""" # set up logging to file @@ -209,7 +208,7 @@ def __init__(self, log_file, log_level): logging.getLogger('').addHandler(console) sys_handler = handler = logging.handlers.SysLogHandler(address = '/dev/log') - sys_handler.setLevel(logging.WARNING) + sys_handler.setLevel(logging.WARNING) logging.getLogger('').addHandler(sys_handler) #logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level) @@ -217,7 +216,7 @@ def __init__(self, log_file, log_level): def manage_pim(self): global pim_dev global pim_state - + for pim_idx in range(PIM_MIN, PIM_MAX): presence=pim_dev.get_pim_presence(pim_idx) if presence==1: @@ -228,19 +227,19 @@ def manage_pim(self): logging.info("pim_state[%d] PIM_STATE_INSERT", pim_idx); pim_state[pim_idx]=self.PIM_STATE_INSERT continue - + logging.info ("pim_idx=%d oom use i2c_bus_order=%d", pim_idx, i2c_bus_order) ready=0 retry_limit=100 retry_count=0 - while retry_count < retry_limit: + while retry_count < retry_limit: ret=check_pca_active(0x72, pim_idx+2) if ret==0: ready=1 - break + break retry_count=retry_count+1 time.sleep(0.2) - + if ready==1: status=pca9548_sysfs(pim_idx+2, 1) if status: @@ -250,28 +249,28 @@ def manage_pim(self): status=qsfp_eeprom_sys(pim_idx,i2c_bus_order, 1) if status: status=pca9548_sysfs(pim_idx+2, 0) #del pca i2c device, give up set oom at this time. - del_pim_port_use_bus(pim_idx) + del_pim_port_use_bus(pim_idx) continue #ret_2=check_pca_active(0x72, pim_idx+2) #ret_1=check_pca_active(0x71, pim_idx+2) - + pim_state[pim_idx]=self.PIM_STATE_INSERT logging.info("pim_state[%d] PIM_STATE_INSERT", pim_idx); else: print("retry check 100 times for check pca addr") del_pim_port_use_bus(pim_idx) else: - if pim_state[pim_idx]==self.PIM_STATE_INSERT: + if pim_state[pim_idx]==self.PIM_STATE_INSERT: #pca9548_sysfs(pim_idx+2, 0) pim_state[pim_idx]=self.PIM_STATE_REMOVE logging.info("pim_state[%d] PIM_STATE_REMOVE", pim_idx); - + def main(argv): log_file = '%s.log' % FUNCTION_NAME log_level = logging.INFO remove_dev=0 cpu_pca_i2c_ready=0 - + if len(sys.argv) != 1: try: opts, args = getopt.getopt(argv,'hdlr',['lfile=']) @@ -288,14 +287,14 @@ def main(argv): log_file = arg elif opt in ('-r', '--remove'): remove_dev=1 - + if remove_dev==1: device_remove() return 0 monitor = device_monitor(log_file, log_level) global pim_dev pim_dev.init_pim_fpga() - + while cpu_pca_i2c_ready==0: status=check_pca_active(0x70, 1) time.sleep(0.5) @@ -303,7 +302,7 @@ def main(argv): cpu_pca_i2c_ready=1 print("Make sure CPU pca i2c device is ready") break - + while True: monitor.manage_pim() time.sleep(2)