diff --git a/device/celestica/x86_64-cel_seastone_2-r0/pmon_daemon_control.json b/device/celestica/x86_64-cel_seastone_2-r0/pmon_daemon_control.json index 294259681a..5e59513ef6 100644 --- a/device/celestica/x86_64-cel_seastone_2-r0/pmon_daemon_control.json +++ b/device/celestica/x86_64-cel_seastone_2-r0/pmon_daemon_control.json @@ -2,5 +2,6 @@ "skip_ledd": true, "skip_xcvrd": false, "skip_psud": false, - "skip_syseepromd": false + "skip_syseepromd": false, + "skip_fancontrol": true } \ No newline at end of file diff --git a/device/celestica/x86_64-cel_seastone_2-r0/sonic_platform_config/chassis.json b/device/celestica/x86_64-cel_seastone_2-r0/sonic_platform_config/chassis.json new file mode 100644 index 0000000000..dfa1a1bddf --- /dev/null +++ b/device/celestica/x86_64-cel_seastone_2-r0/sonic_platform_config/chassis.json @@ -0,0 +1,45 @@ +{ + "eeprom": "/sys/class/i2c-adapter/i2c-0/0-0056/eeprom", + "get_reboot_cause": { + "output_source": "ipmitool", + "command": "ipmitool raw 0x3a 0x0c 0x0 0x2 0x06", + "output_translator": { + "00": "Hardware - Other", + "11": "Hardware - Other", + "22": "Non-Hardware", + "33": "Hardware - Other", + "44": "Non-Hardware", + "55": "Non-Hardware", + "77": "Watchdog", + "88": "Thermal Overload: CPU", + "99": "Thermal Overload: ASIC" + } + }, + "get_reboot_description": { + "output_source": "ipmitool", + "command": "ipmitool raw 0x3a 0x0c 0x0 0x2 0x06", + "output_translator": { + "00": "The last reset is power cycle reset (set register 0xA164)", + "11": "The last reset is Power on reset", + "22": "The last reset is soft-set CPU warm reset", + "33": "The last reset is soft-set CPU cold reset", + "44": "The last reset is CPU warm reset", + "55": "The last reset is CPU cold reset", + "77": "The last reset is watchdog reset", + "88": "The last reset is CPU thermal overload", + "99": "The last reset is ASIC thermal overload" + } + }, + "get_watchdog": { + "output_source": "class", + "host_path": "/usr/share/sonic/device/x86_64-cel_seastone_2-r0/sonic_platform_config/watchdog.py", + "pmon_path": "/usr/share/sonic/platform/sonic_platform_config/watchdog.py", + "class": "Watchdog" + }, + "get_change_event": { + "output_source": "class", + "host_path": "/usr/share/sonic/device/x86_64-cel_seastone_2-r0/sonic_platform_config/event.py", + "pmon_path": "/usr/share/sonic/platform/sonic_platform_config/event.py", + "class": "SfpEvent" + } +} diff --git a/device/celestica/x86_64-cel_seastone_2-r0/sonic_platform_config/component.json b/device/celestica/x86_64-cel_seastone_2-r0/sonic_platform_config/component.json new file mode 100644 index 0000000000..96f646206f --- /dev/null +++ b/device/celestica/x86_64-cel_seastone_2-r0/sonic_platform_config/component.json @@ -0,0 +1,62 @@ +{ + "component_num": 5, + "get_name": { + "output_source": "value_list", + "value_list": [ + "BIOS", + "CPLD_BASEBOARD", + "CPLD_SWITCHBOARD", + "FPGA", + "BMC" + ] + }, + "get_description": { + "output_source": "value_list", + "value_list": [ + "Used to perform hardware initialization during the booting process", + "Used to control the system power & reset, Control FAN, UART Mux etc", + "Used for managing QSFP ports", + "Used for managing I2C, SPI, PCIe etc", + "Used for monitoring and managing whole system" + ] + }, + "get_firmware_version": { + "output_source": "function", + "function": [ + "_get_bios_ver", + "_get_base_cpld_ver", + "_get_sw_cpld_ver", + "_get_fpga_ver", + "_get_bmc_ver" + ] + }, + "_get_bmc_ver": { + "output_source": "ipmitool", + "command": "ipmitool mc info | grep 'Firmware Revision'", + "output_translator": "'{}'.split(':')[-1].strip()" + }, + "_get_bios_ver": { + "output_source": "txt_file", + "path": "/sys/class/dmi/id/bios_version" + }, + "_get_base_cpld_ver": { + "output_source": "hex_version_file", + "num_of_points": 1, + "num_of_bits": 8, + "path": "/sys/devices/platform/baseboard/version" + }, + "_get_sw_cpld_ver": { + "output_source": "hex_version_getreg", + "num_of_points": 1, + "num_of_bits": 8, + "reg_addr": "0x00", + "path": "/sys/devices/platform/switchboard/CPLD1/getreg" + }, + "_get_fpga_ver": { + "output_source": "hex_version_getreg", + "num_of_points": 1, + "num_of_bits": 32, + "reg_addr": "0x00", + "path": "/sys/devices/platform/switchboard/FPGA/getreg" + } +} \ No newline at end of file diff --git a/device/celestica/x86_64-cel_seastone_2-r0/sonic_platform_config/event.py b/device/celestica/x86_64-cel_seastone_2-r0/sonic_platform_config/event.py new file mode 100644 index 0000000000..0153d29418 --- /dev/null +++ b/device/celestica/x86_64-cel_seastone_2-r0/sonic_platform_config/event.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica Seastone2 +# +# SfpEvent contains an implementation of SONiC Platform Base API +# +############################################################################# +try: + import time + import os + from sonic_platform.common import Common +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +PLATFORM_PATH = "/sys/devices/platform/" +SWITCH_BRD_PLATFORM = "switchboard" +POLL_INTERVAL = 1 + + +class SfpEvent: + ''' Listen to insert/remove sfp events ''' + + PORT_INFO_DIR = 'SFF' + PATH_INT_SYSFS = "{0}/{port_name}/{type_prefix}_isr_flags" + PATH_INTMASK_SYSFS = "{0}/{port_name}/{type_prefix}_isr_mask" + PATH_PRS_SYSFS = "{0}/{port_name}/{prs_file_name}" + PRESENT_EN = 0x01 + + def __init__(self, sfp_list): + self.num_sfp = len(sfp_list) + self._api_common = Common() + self._initialize_interrupts() + + def _initialize_interrupts(self): + sfp_info_obj = {} + port_info_path = os.path.join( + PLATFORM_PATH, SWITCH_BRD_PLATFORM, self.PORT_INFO_DIR) + + for index in range(self.num_sfp): + port_num = index + 1 + port_name = "QSFP{}".format(port_num) + port_type = "qsfp" + sysfs_prs_file = "{}_modprs".format(port_type) + + sfp_info_obj[index] = {} + sfp_info_obj[index]['intmask_sysfs'] = self.PATH_INTMASK_SYSFS.format( + port_info_path, + port_name=port_name, + type_prefix=port_type) + + sfp_info_obj[index]['int_sysfs'] = self.PATH_INT_SYSFS.format( + port_info_path, + port_name=port_name, + type_prefix=port_type) + + sfp_info_obj[index]['prs_sysfs'] = self.PATH_PRS_SYSFS.format( + port_info_path, + port_name=port_name, + prs_file_name=sysfs_prs_file) + + self._api_common.write_txt_file( + sfp_info_obj[index]["intmask_sysfs"], hex(self.PRESENT_EN)) + + self.sfp_info_obj = sfp_info_obj + + def _is_port_device_present(self, port_idx): + prs_path = self.sfp_info_obj[port_idx]["prs_sysfs"] + is_present = 1 - int(self._api_common.read_txt_file(prs_path)) + return is_present + + def _update_port_event_object(self, interrup_devices, port_dict): + for port_idx in interrup_devices: + device_id = str(port_idx + 1) + port_dict[device_id] = str(self._is_port_device_present(port_idx)) + return port_dict + + def _clear_event_flag(self, path): + self._api_common.write_txt_file(path, hex(0xff)) + time.sleep(0.1) + self._api_common.write_txt_file(path, hex(0x0)) + + def _check_all_port_interrupt_event(self): + interrupt_devices = {} + for i in range(self.num_sfp): + int_sysfs = self.sfp_info_obj[i]["int_sysfs"] + interrupt_flags = self._api_common.read_txt_file(int_sysfs) + if interrupt_flags != '0x00': + interrupt_devices[i] = 1 + self._clear_event_flag(int_sysfs) + return interrupt_devices + + def get_event(self, timeout): + sleep_time = min( + timeout, POLL_INTERVAL) if timeout != 0 else POLL_INTERVAL + start_milli_time = int(round(time.time() * 1000)) + int_sfp = {} + + while True: + chk_sfp = self._check_all_port_interrupt_event() + int_sfp = self._update_port_event_object( + chk_sfp, int_sfp) if chk_sfp else int_sfp + current_milli_time = int(round(time.time() * 1000)) + if (int_sfp) or \ + (timeout != 0 and current_milli_time - start_milli_time > timeout): + break + + time.sleep(sleep_time) + + change_dict = dict() + change_dict['sfp'] = int_sfp + + return True, change_dict diff --git a/device/celestica/x86_64-cel_seastone_2-r0/sonic_platform_config/fan.json b/device/celestica/x86_64-cel_seastone_2-r0/sonic_platform_config/fan.json new file mode 100644 index 0000000000..724f6edf53 --- /dev/null +++ b/device/celestica/x86_64-cel_seastone_2-r0/sonic_platform_config/fan.json @@ -0,0 +1,200 @@ +{ + "fan_num_per_drawer": 2, + "drawer_num": 4, + "get_name": { + "output_source": "value_list", + "value_list": [ + "Fan1-F", + "Fan1-R", + "Fan2-F", + "Fan2-R", + "Fan3-F", + "Fan3-R", + "Fan4-F", + "Fan4-R" + ] + }, + "get_presence": { + "output_source": "ipmitool", + "command": "ipmitool raw 0x3a 0x03 0x03 {}", + "argument": [ + "0x00", + "0x00", + "0x01", + "0x01", + "0x02", + "0x02", + "0x03", + "0x03" + ], + "output_translator": "True if '00' in '{}' else False" + }, + "get_model": { + "output_source": "ipmitool", + "command": "ipmitool fru list {} | grep 'Board Part Number'", + "argument": [ + "5", + "5", + "6", + "6", + "7", + "7", + "8", + "8" + ], + "output_translator": "'{}'.split()[-1]" + }, + "get_serial": { + "output_source": "ipmitool", + "command": "ipmitool fru list {} | grep 'Board Serial'", + "argument": [ + "5", + "5", + "6", + "6", + "7", + "7", + "8", + "8" + ], + "output_translator": "'{}'.split()[-1]" + }, + "get_direction": { + "output_source": "ipmitool", + "command": "ipmitool fru list {} | grep 'F2B\\|B2F'", + "argument": [ + "5", + "5", + "6", + "6", + "7", + "7", + "8", + "8" + ], + "output_translator": "'intake' if 'B2F' in '{}' else 'exhaust'" + }, + "get_speed": { + "output_source": "ipmitool", + "command": "ipmitool raw 0x04 0x2d {}", + "argument": [ + "0x81", + "0x80", + "0x83", + "0x82", + "0x85", + "0x84", + "0x87", + "0x86" + ], + "output_translator": "int('{}'.split()[0],16)*150", + "max_front": 23000, + "max_rear": 20500 + }, + "get_target_speed": { + "output_source": "value", + "value": "N/A" + }, + "get_speed_tolerance": { + "output_source": "value", + "value": 10 + }, + "set_speed": { + "set_method": "ipmitool", + "input_translator": "hex(int({} * 255 / 100.0))", + "command": "ipmitool raw 0x3a 0x0c 0x00 0x03 {}", + "argument": [ + "0x40 {}", + "0x40 {}", + "0x44 {}", + "0x44 {}", + "0x4c {}", + "0x4c {}", + "0x50 {}", + "0x50 {}" + ] + }, + "set_status_led": { + "set_method": "ipmitool", + "avaliable_input": [ + "off", + "amber", + "green" + ], + "input_translator": { + "off": "0x0", + "amber": "0x1", + "green": "0x2" + }, + "command": "ipmitool raw 0x3a 0x0a {}", + "argument": [ + "0x4 {}", + "0x4 {}", + "0x5 {}", + "0x5 {}", + "0x6 {}", + "0x6 {}", + "0x7 {}", + "0x7 {}" + ] + }, + "get_status_led": { + "output_source": "ipmitool", + "command": "ipmitool raw 0x3a 0x0b {}", + "argument": [ + "0x4", + "0x4", + "0x5", + "0x5", + "0x6", + "0x6", + "0x7", + "0x7" + ], + "output_translator": { + "00": "off", + "01": "amber", + "02": "green" + } + }, + "psu_fan": [ + { + "num_of_fan": 1, + "get_name": { + "output_source": "value_list", + "value_list": [ + "PSU-R-Fan" + ] + }, + "get_speed": { + "output_source": "ipmitool", + "command": "ipmitool raw 0x04 0x2d {}", + "argument": [ + "0x8b" + ], + "output_translator": "int('{}'.split()[0],16)*100", + "max_front": 22600, + "max_rear": 22600 + } + }, + { + "num_of_fan": 1, + "get_name": { + "output_source": "value_list", + "value_list": [ + "PSU-L-Fan" + ] + }, + "get_speed": { + "output_source": "ipmitool", + "command": "ipmitool raw 0x04 0x2d {}", + "argument": [ + "0x8a" + ], + "output_translator": "int('{}'.split()[0],16)*100", + "max_front": 22600, + "max_rear": 22600 + } + } + ] +} \ No newline at end of file diff --git a/device/celestica/x86_64-cel_seastone_2-r0/sonic_platform_config/psu.json b/device/celestica/x86_64-cel_seastone_2-r0/sonic_platform_config/psu.json new file mode 100644 index 0000000000..c3e953c082 --- /dev/null +++ b/device/celestica/x86_64-cel_seastone_2-r0/sonic_platform_config/psu.json @@ -0,0 +1,135 @@ +{ + "psu_num": 2, + "fan_per_psu_num": 1, + "get_name": { + "output_source": "value_list", + "value_list": [ + "PSU-R", + "PSU-L" + ] + }, + "get_power": { + "output_source": "ipmitool", + "command": "ipmitool sdr | grep {}", + "argument": [ + "PSUR_POut", + "PSUL_POut" + ], + "output_translator": "float('{}'.split()[2])" + }, + "get_current": { + "output_source": "ipmitool", + "command": "ipmitool sdr | grep {}", + "argument": [ + "PSUR_COut", + "PSUL_COut" + ], + "output_translator": "float('{}'.split()[2])" + }, + "get_voltage": { + "output_source": "ipmitool", + "command": "ipmitool sdr | grep {}", + "argument": [ + "PSUR_VOut", + "PSUL_VOut" + ], + "output_translator": "float('{}'.split()[2])" + }, + "get_voltage_high_threshold": { + "output_source": "ipmitool", + "command": "ipmitool sensor list | grep {}", + "argument": [ + "PSUR_Temp2", + "PSUL_Temp2" + ], + "output_translator": "float(0 if '{0}'.split()[-3]=='na' else '{0}'.split()[-3])" + }, + "get_voltage_low_threshold": { + "output_source": "ipmitool", + "command": "ipmitool sensor list | grep {}", + "argument": [ + "PSUR_Temp2", + "PSUL_Temp2" + ], + "output_translator": "float(0 if '{0}'.split()[-9]=='na' else '{0}'.split()[-9])" + }, + "get_presence": { + "output_source": "ipmitool", + "command": "ipmitool raw 0x3a 0x0c 0x00 0x2 0x60", + "output_translator": [ + "True if (int('{}', 16) >> 4 & 1) == 0 else False", + "True if (int('{}', 16) >> 5 & 1) == 0 else False" + ] + }, + "get_model": { + "output_source": "ipmitool", + "command": "ipmitool fru list {} | grep 'Product Part Number'", + "argument": [ + "4", + "3" + ], + "output_translator": "'{}'.split()[-1]" + }, + "get_serial": { + "output_source": "ipmitool", + "command": "ipmitool fru list {} | grep 'Product Serial'", + "argument": [ + "4", + "3" + ], + "output_translator": "'{}'.split()[-1]" + }, + "get_powergood_status": { + "output_source": "ipmitool", + "command": "ipmitool raw 0x3a 0x0c 0x0 0x2 0x60", + "output_translator": [ + "True if (int('{}', 16) >> 2 & 1) == 1 else False", + "True if (int('{}', 16) >> 3 & 1) == 1 else False" + ] + }, + "set_status_led": { + "set_method": "ipmitool", + "avaliable_input": [ + "amber" + ], + "input_translator": { + "amber": "0x1" + }, + "command": "ipmitool raw 0x3a 0x0a {}", + "argument": [ + "0x3 {}", + "0x2 {}" + ] + }, + "get_status_led": { + "output_source": "ipmitool", + "command": "ipmitool raw 0x3a 0x0b {}", + "argument": [ + "0x3", + "0x2" + ], + "output_translator": { + "00": "green", + "01": "amber" + }, + "default_output": "off" + }, + "get_temperature": { + "output_source": "ipmitool", + "command": "ipmitool sdr | grep {}", + "argument": [ + "PSUR_Temp2", + "PSUL_Temp2" + ], + "output_translator": "float('{}'.split()[2])" + }, + "get_temperature_high_threshold": { + "output_source": "ipmitool", + "command": "ipmitool sensor list | grep {}", + "argument": [ + "PSUR_Temp2", + "PSUL_Temp2" + ], + "output_translator": "float(0 if '{0}'.split()[-3]=='na' else '{0}'.split()[-3])" + } +} \ No newline at end of file diff --git a/device/celestica/x86_64-cel_seastone_2-r0/sonic_platform_config/sfp.json b/device/celestica/x86_64-cel_seastone_2-r0/sonic_platform_config/sfp.json new file mode 100644 index 0000000000..d77e75e50e --- /dev/null +++ b/device/celestica/x86_64-cel_seastone_2-r0/sonic_platform_config/sfp.json @@ -0,0 +1,106 @@ +{ + "port_num": 32, + "eeprom_path": "/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom", + "port_i2c_mapping": [ + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33 + ], + "get_presence": { + "output_source": "sysfs_value", + "sysfs_path": "/sys/devices/platform/switchboard/SFF/{}/qsfp_modprs", + "argument": "$ref:_port_name", + "output_translator": "False if '{}' == '1' else True" + }, + "get_lpmode": { + "output_source": "sysfs_value", + "sysfs_path": "/sys/devices/platform/switchboard/SFF/{}/qsfp_lpmode", + "argument": "$ref:_port_name", + "output_translator": "True if '{}' == '1' else False" + }, + "get_reset_status": { + "output_source": "sysfs_value", + "sysfs_path": "/sys/devices/platform/switchboard/SFF/{}/qsfp_reset", + "argument": "$ref:_port_name", + "output_translator": "False if '{}' == '1' else True" + }, + "reset": { + "set_method": "sysfs_value", + "write_offset": 0, + "sysfs_path": "/sys/devices/platform/switchboard/SFF/{}/qsfp_reset", + "argument": "$ref:_port_name" + }, + "set_lpmode": { + "set_method": "sysfs_value", + "input_translator": { + "True": "0x1", + "False": "0x0" + }, + "write_offset": 0, + "sysfs_path": "/sys/devices/platform/switchboard/SFF/{}/qsfp_lpmode", + "argument": "$ref:_port_name" + }, + "_port_name": [ + "QSFP1", + "QSFP2", + "QSFP3", + "QSFP4", + "QSFP5", + "QSFP6", + "QSFP7", + "QSFP8", + "QSFP9", + "QSFP10", + "QSFP11", + "QSFP12", + "QSFP13", + "QSFP14", + "QSFP15", + "QSFP16", + "QSFP17", + "QSFP18", + "QSFP19", + "QSFP20", + "QSFP21", + "QSFP22", + "QSFP23", + "QSFP24", + "QSFP25", + "QSFP26", + "QSFP27", + "QSFP28", + "QSFP29", + "QSFP30", + "QSFP31", + "QSFP32" + ] +} \ No newline at end of file diff --git a/device/celestica/x86_64-cel_seastone_2-r0/sonic_platform_config/thermal.json b/device/celestica/x86_64-cel_seastone_2-r0/sonic_platform_config/thermal.json new file mode 100644 index 0000000000..e3dcb7fb92 --- /dev/null +++ b/device/celestica/x86_64-cel_seastone_2-r0/sonic_platform_config/thermal.json @@ -0,0 +1,105 @@ +{ + "thermal_num": 9, + "get_name": { + "output_source": "value_list", + "value_list": [ + "Base_Temp_U5", + "Base_Temp_U7", + "CPU_Temp", + "Switch_Temp_U1", + "Switch_Temp_U18", + "Switch_Temp_U28", + "Switch_Temp_U29", + "Switch_U21_Temp", + "Switch_U33_Temp" + ] + }, + "get_temperature": { + "output_source": "ipmitool", + "command": "ipmitool raw 0x04 0x2D {}", + "argument": [ + "0x1", + "0x2", + "0x7", + "0x3", + "0x4", + "0x5", + "0x6", + "0x56", + "0x4C" + ], + "output_translator": "int('{}'.split()[0],16)" + }, + "get_high_threshold": { + "output_source": "ipmitool", + "command": "ipmitool raw 0x04 0x27 {}", + "argument": [ + "0x1", + "0x2", + "0x7", + "0x3", + "0x4", + "0x5", + "0x6", + "0x56", + "0x4c" + ], + "output_translator": "int('{}'.split()[4], 16)" + }, + "get_low_threshold": { + "output_source": "value", + "value": "N/A" + }, + "set_high_threshold": { + "set_method": "ipmitool", + "command": "ipmitool sensor thresh {}", + "input_translator": "{}", + "argument": [ + "Base_Temp_U5 unc {}", + "Base_Temp_U7 unc {}", + "CPU_Temp unc {}", + "Switch_Temp_U1 unc {}", + "Switch_Temp_U18 unc {}", + "Switch_Temp_U28 unc {}", + "Switch_Temp_U29 unc {}", + "Switch_U21_Temp unc {}", + "Switch_U33_Temp unc {}" + ] + }, + "set_low_threshold": { + "output_source": "ipmitool", + "command": "ipmitool sensor thresh {}", + "input_translator": "{}", + "argument": [ + "Base_Temp_U5 lnc {}", + "Base_Temp_U7 lnc {}", + "CPU_Temp lnc {}", + "Switch_Temp_U1 lnc {}", + "Switch_Temp_U18 lnc {}", + "Switch_Temp_U28 lnc {}", + "Switch_Temp_U29 lnc {}", + "Switch_U21_Temp lnc {}", + "Switch_U33_Temp lnc {}" + ] + }, + "get_high_critical_threshold": { + "output_source": "ipmitool", + "command": "ipmitool raw 0x04 0x27 {}", + "argument": [ + "0x1", + "0x2", + "0x7", + "0x3", + "0x4", + "0x5", + "0x6", + "0x56", + "0x4c" + ], + "output_translator": "int('{}'.split()[5], 16)" + }, + "get_low_critical_threshold": { + "output_source": "value", + "value": "N/A" + } +} \ No newline at end of file diff --git a/device/celestica/x86_64-cel_seastone_2-r0/sonic_platform_config/watchdog.py b/device/celestica/x86_64-cel_seastone_2-r0/sonic_platform_config/watchdog.py new file mode 100644 index 0000000000..70eae5b95b --- /dev/null +++ b/device/celestica/x86_64-cel_seastone_2-r0/sonic_platform_config/watchdog.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica Seastone2 +# +# Watchdog contains an implementation of SONiC Platform Base API +# +############################################################################# +import os +import time + +try: + from sonic_platform_base.watchdog_base import WatchdogBase + from sonic_platform.common import Common +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +PLATFORM_CPLD_PATH = '/sys/devices/platform/baseboard/' +GETREG_FILE = 'getreg' +SETREG_FILE = 'setreg' +WDT_ENABLE_REG = '0xA181' +WDT_TIMER_L_BIT_REG = '0xA182' +WDT_TIMER_M_BIT_REG = '0xA183' +WDT_TIMER_H_BIT_REG = '0xA184' +WDT_KEEP_ALVIVE_REG = '0xA185' +ENABLE_CMD = '0x1' +DISABLE_CMD = '0x0' +WDT_COMMON_ERROR = -1 + + +class Watchdog(WatchdogBase): + + def __init__(self): + self._api_common = Common() + + # Init cpld reg path + self.setreg_path = os.path.join(PLATFORM_CPLD_PATH, SETREG_FILE) + self.getreg_path = os.path.join(PLATFORM_CPLD_PATH, GETREG_FILE) + + # Set default value + self._disable() + self.armed = False + self.timeout = self._gettimeout() + + def _enable(self): + """ + Turn on the watchdog timer + """ + # echo 0xA181 0x1 > /sys/devices/platform/baseboard/setreg + enable_val = '{} {}'.format(WDT_ENABLE_REG, ENABLE_CMD) + return self._api_common.write_txt_file(self.setreg_path, enable_val) + + def _disable(self): + """ + Turn off the watchdog timer + """ + # echo 0xA181 0x0 > /sys/devices/platform/baseboard/setreg + disable_val = '{} {}'.format(WDT_ENABLE_REG, DISABLE_CMD) + return self._api_common.write_txt_file(self.setreg_path, disable_val) + + def _keepalive(self): + """ + Keep alive watchdog timer + """ + # echo 0xA185 0x1 > /sys/devices/platform/baseboard/setreg + enable_val = '{} {}'.format(WDT_KEEP_ALVIVE_REG, ENABLE_CMD) + return self._api_common.write_txt_file(self.setreg_path, enable_val) + + def _get_level_hex(self, sub_hex): + sub_hex_str = sub_hex.replace("x", "0") + return hex(int(sub_hex_str, 16)) + + def _seconds_to_lmh_hex(self, seconds): + ms = seconds*1000 # calculate timeout in ms format + hex_str = hex(ms) + l = self._get_level_hex(hex_str[-2:]) + m = self._get_level_hex(hex_str[-4:-2]) + h = self._get_level_hex(hex_str[-6:-4]) + return (l, m, h) + + def _settimeout(self, seconds): + """ + Set watchdog timer timeout + @param seconds - timeout in seconds + @return is the actual set timeout + """ + # max = 0xffffff = 16777.215 seconds + + (l, m, h) = self._seconds_to_lmh_hex(seconds) + set_h_val = '{} {}'.format(WDT_TIMER_H_BIT_REG, h) + set_m_val = '{} {}'.format(WDT_TIMER_M_BIT_REG, m) + set_l_val = '{} {}'.format(WDT_TIMER_L_BIT_REG, l) + + self._api_common.write_txt_file( + self.setreg_path, set_h_val) # set high bit + self._api_common.write_txt_file( + self.setreg_path, set_m_val) # set med bit + self._api_common.write_txt_file( + self.setreg_path, set_l_val) # set low bit + + return seconds + + def _gettimeout(self): + """ + Get watchdog timeout + @return watchdog timeout + """ + + h_bit = self._api_common.get_reg( + self.getreg_path, WDT_TIMER_H_BIT_REG) + m_bit = self._api_common.get_reg( + self.getreg_path, WDT_TIMER_M_BIT_REG) + l_bit = self._api_common.get_reg( + self.getreg_path, WDT_TIMER_L_BIT_REG) + + hex_time = '0x{}{}{}'.format(h_bit[2:], m_bit[2:], l_bit[2:]) + ms = int(hex_time, 16) + return int(float(ms)/1000) + + ################################################################# + + def arm(self, seconds): + """ + Arm the hardware watchdog with a timeout of seconds. + If the watchdog is currently armed, calling this function will + simply reset the timer to the provided value. If the underlying + hardware does not support the value provided in , this + method should arm the watchdog with the *next greater* available + value. + Returns: + An integer specifying the *actual* number of seconds the watchdog + was armed with. On failure returns -1. + """ + + ret = WDT_COMMON_ERROR + if seconds < 0: + return ret + + try: + if self.timeout != seconds: + self.timeout = self._settimeout(seconds) + + if self.armed: + self._keepalive() + else: + self._enable() + self.armed = True + + ret = self.timeout + self.arm_timestamp = time.time() + except IOError as e: + pass + + return ret + + def disarm(self): + """ + Disarm the hardware watchdog + Returns: + A boolean, True if watchdog is disarmed successfully, False if not + """ + disarmed = False + if self.is_armed(): + try: + self._disable() + self.armed = False + disarmed = True + except IOError: + pass + + return disarmed + + def is_armed(self): + """ + Retrieves the armed state of the hardware watchdog. + Returns: + A boolean, True if watchdog is armed, False if not + """ + + return self.armed + + def get_remaining_time(self): + """ + If the watchdog is armed, retrieve the number of seconds remaining on + the watchdog timer + Returns: + An integer specifying the number of seconds remaining on thei + watchdog timer. If the watchdog is not armed, returns -1. + """ + + return int(self.timeout - (time.time() - self.arm_timestamp)) if self.armed else WDT_COMMON_ERROR diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-seastone2.install b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-seastone2.install index e17b5e9cae..41a381eeb0 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-seastone2.install +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-seastone2.install @@ -1,2 +1,4 @@ seastone2/cfg/seastone2-modules.conf etc/modules-load.d seastone2/systemd/platform-modules-seastone2.service lib/systemd/system +seastone2/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/x86_64-cel_seastone_2-r0 +services/platform_api/platform_api_mgnt.sh usr/local/bin \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-seastone2.postinst b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-seastone2.postinst index 9a8e57cb8e..f232a2cac5 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-seastone2.postinst +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-seastone2.postinst @@ -1,3 +1,5 @@ depmod -a systemctl enable platform-modules-seastone2.service -systemctl start platform-modules-seastone2.service \ No newline at end of file +systemctl start platform-modules-seastone2.service + +/usr/local/bin/platform_api_mgnt.sh install diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/rules b/platform/broadcom/sonic-platform-modules-cel/debian/rules index 0ed48f9fea..a7293e0b67 100755 --- a/platform/broadcom/sonic-platform-modules-cel/debian/rules +++ b/platform/broadcom/sonic-platform-modules-cel/debian/rules @@ -16,6 +16,10 @@ override_dh_auto_build: cd $(MOD_SRC_DIR)/$${mod}; \ python2.7 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \ cd $(MOD_SRC_DIR); \ + if [ $$mod = "seastone2" ]; then \ + cd services/platform_api; \ + python2 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \ + fi \ done) override_dh_auto_install: diff --git a/platform/broadcom/sonic-platform-modules-cel/seastone2/modules/switchboard_fpga.c b/platform/broadcom/sonic-platform-modules-cel/seastone2/modules/switchboard_fpga.c index c7a86e13d3..5918d27f39 100644 --- a/platform/broadcom/sonic-platform-modules-cel/seastone2/modules/switchboard_fpga.c +++ b/platform/broadcom/sonic-platform-modules-cel/seastone2/modules/switchboard_fpga.c @@ -25,7 +25,7 @@ */ #ifndef TEST_MODE -#define MOD_VERSION "2.1.3" +#define MOD_VERSION "2.2.0" #else #define MOD_VERSION "TEST" #endif @@ -51,8 +51,6 @@ #include #include - - static int majorNumber; #define CLASS_NAME "seastone2_fpga" @@ -62,17 +60,16 @@ static int majorNumber; static int smbus_access(struct i2c_adapter *adapter, u16 addr, - unsigned short flags, char rw, u8 cmd, - int size, union i2c_smbus_data *data); + unsigned short flags, char rw, u8 cmd, + int size, union i2c_smbus_data *data); static int fpga_i2c_access(struct i2c_adapter *adapter, u16 addr, - unsigned short flags, char rw, u8 cmd, - int size, union i2c_smbus_data *data); + unsigned short flags, char rw, u8 cmd, + int size, union i2c_smbus_data *data); static int fpgafw_init(void); static void fpgafw_exit(void); - /* ======================================== FPGA PCIe BAR 0 Registers @@ -186,7 +183,6 @@ PORT XCVR 0x00004000 - 0x00004FFF. */ #define INTR_INT_N 5 #define INTR_PRESENT 4 -#define INTR_TXFAULT 2 #define INTR_RXLOS 1 #define INTR_MODABS 0 @@ -201,7 +197,6 @@ PORT XCVR 0x00004000 - 0x00004FFF. */ #define MASK_INT_N 5 #define MASK_PRESENT 4 -#define MASK_TXFAULT 2 #define MASK_RXLOS 1 #define MASK_MODABS 0 @@ -254,6 +249,7 @@ enum { static struct class* fpgafwclass = NULL; ///< The device-driver class struct pointer static struct device* fpgafwdev = NULL; ///< The device-driver device struct pointer +static struct platform_device *seastone2_dev; #define PCI_VENDOR_ID_TEST 0x1af4 @@ -287,7 +283,7 @@ enum PORT_TYPE { SFP }; -struct i2c_switch{ +struct i2c_switch { unsigned char master_bus; // I2C bus number unsigned char switch_addr; // PCA9548 device address, 0xFF if directly connect to a bus. unsigned char channel; // PCA9548 channel number. If the switch_addr is 0xFF, this value is ignored. @@ -303,32 +299,32 @@ struct i2c_dev_data { /* PREDEFINED I2C SWITCH DEVICE TOPOLOGY */ static struct i2c_switch fpga_i2c_bus_dev[] = { /* BUS2 QSFP Exported as virtual bus */ - {I2C_MASTER_CH_2,0x72,0,QSFP,"QSFP1"}, {I2C_MASTER_CH_2,0x72,1,QSFP,"QSFP2"}, - {I2C_MASTER_CH_2,0x72,2,QSFP,"QSFP3"}, {I2C_MASTER_CH_2,0x72,3,QSFP,"QSFP4"}, - {I2C_MASTER_CH_2,0x72,4,QSFP,"QSFP5"}, {I2C_MASTER_CH_2,0x72,5,QSFP,"QSFP6"}, - {I2C_MASTER_CH_2,0x72,6,QSFP,"QSFP7"}, {I2C_MASTER_CH_2,0x72,7,QSFP,"QSFP8"}, - {I2C_MASTER_CH_2,0x73,0,QSFP,"QSFP9"}, {I2C_MASTER_CH_2,0x73,1,QSFP,"QSFP10"}, - {I2C_MASTER_CH_2,0x73,2,QSFP,"QSFP11"},{I2C_MASTER_CH_2,0x73,3,QSFP,"QSFP12"}, - {I2C_MASTER_CH_2,0x73,4,QSFP,"QSFP13"},{I2C_MASTER_CH_2,0x73,5,QSFP,"QSFP14"}, - {I2C_MASTER_CH_2,0x73,6,QSFP,"QSFP15"},{I2C_MASTER_CH_2,0x73,7,QSFP,"QSFP16"}, - {I2C_MASTER_CH_2,0x74,0,QSFP,"QSFP17"},{I2C_MASTER_CH_2,0x74,1,QSFP,"QSFP18"}, - {I2C_MASTER_CH_2,0x74,2,QSFP,"QSFP19"},{I2C_MASTER_CH_2,0x74,3,QSFP,"QSFP20"}, - {I2C_MASTER_CH_2,0x74,4,QSFP,"QSFP21"},{I2C_MASTER_CH_2,0x74,5,QSFP,"QSFP22"}, - {I2C_MASTER_CH_2,0x74,6,QSFP,"QSFP23"},{I2C_MASTER_CH_2,0x74,7,QSFP,"QSFP24"}, - {I2C_MASTER_CH_2,0x75,0,QSFP,"QSFP25"},{I2C_MASTER_CH_2,0x75,1,QSFP,"QSFP26"}, - {I2C_MASTER_CH_2,0x75,2,QSFP,"QSFP27"},{I2C_MASTER_CH_2,0x75,3,QSFP,"QSFP28"}, - {I2C_MASTER_CH_2,0x75,4,QSFP,"QSFP29"},{I2C_MASTER_CH_2,0x75,5,QSFP,"QSFP30"}, - {I2C_MASTER_CH_2,0x75,6,QSFP,"QSFP31"},{I2C_MASTER_CH_2,0x75,7,QSFP,"QSFP32"}, + {I2C_MASTER_CH_2, 0x72, 0, QSFP, "QSFP1"}, {I2C_MASTER_CH_2, 0x72, 1, QSFP, "QSFP2"}, + {I2C_MASTER_CH_2, 0x72, 2, QSFP, "QSFP3"}, {I2C_MASTER_CH_2, 0x72, 3, QSFP, "QSFP4"}, + {I2C_MASTER_CH_2, 0x72, 4, QSFP, "QSFP5"}, {I2C_MASTER_CH_2, 0x72, 5, QSFP, "QSFP6"}, + {I2C_MASTER_CH_2, 0x72, 6, QSFP, "QSFP7"}, {I2C_MASTER_CH_2, 0x72, 7, QSFP, "QSFP8"}, + {I2C_MASTER_CH_2, 0x73, 0, QSFP, "QSFP9"}, {I2C_MASTER_CH_2, 0x73, 1, QSFP, "QSFP10"}, + {I2C_MASTER_CH_2, 0x73, 2, QSFP, "QSFP11"}, {I2C_MASTER_CH_2, 0x73, 3, QSFP, "QSFP12"}, + {I2C_MASTER_CH_2, 0x73, 4, QSFP, "QSFP13"}, {I2C_MASTER_CH_2, 0x73, 5, QSFP, "QSFP14"}, + {I2C_MASTER_CH_2, 0x73, 6, QSFP, "QSFP15"}, {I2C_MASTER_CH_2, 0x73, 7, QSFP, "QSFP16"}, + {I2C_MASTER_CH_2, 0x74, 0, QSFP, "QSFP17"}, {I2C_MASTER_CH_2, 0x74, 1, QSFP, "QSFP18"}, + {I2C_MASTER_CH_2, 0x74, 2, QSFP, "QSFP19"}, {I2C_MASTER_CH_2, 0x74, 3, QSFP, "QSFP20"}, + {I2C_MASTER_CH_2, 0x74, 4, QSFP, "QSFP21"}, {I2C_MASTER_CH_2, 0x74, 5, QSFP, "QSFP22"}, + {I2C_MASTER_CH_2, 0x74, 6, QSFP, "QSFP23"}, {I2C_MASTER_CH_2, 0x74, 7, QSFP, "QSFP24"}, + {I2C_MASTER_CH_2, 0x75, 0, QSFP, "QSFP25"}, {I2C_MASTER_CH_2, 0x75, 1, QSFP, "QSFP26"}, + {I2C_MASTER_CH_2, 0x75, 2, QSFP, "QSFP27"}, {I2C_MASTER_CH_2, 0x75, 3, QSFP, "QSFP28"}, + {I2C_MASTER_CH_2, 0x75, 4, QSFP, "QSFP29"}, {I2C_MASTER_CH_2, 0x75, 5, QSFP, "QSFP30"}, + {I2C_MASTER_CH_2, 0x75, 6, QSFP, "QSFP31"}, {I2C_MASTER_CH_2, 0x75, 7, QSFP, "QSFP32"}, /* BUS1 SFP+ Exported as virtual bus */ - {I2C_MASTER_CH_1,0x72,0,SFP,"SFP1"}, + {I2C_MASTER_CH_1, 0x72, 0, SFP, "SFP1"}, /* BUS3 Switchboard CPLD */ - {I2C_MASTER_CH_3,0xFF,0,NONE,"I2C_3"}, + {I2C_MASTER_CH_3, 0xFF, 0, NONE, "I2C_3"}, }; #define VIRTUAL_I2C_PORT_LENGTH ARRAY_SIZE(fpga_i2c_bus_dev) #define VIRTUAL_I2C_CPLD_INDEX SFF_PORT_TOTAL -struct fpga_device{ +struct fpga_device { /* data mmio region */ void __iomem *data_base_addr; resource_size_t data_mmio_start; @@ -373,82 +369,83 @@ static struct kobject *cpld2 = NULL; static struct device *sff_dev = NULL; /** - * [get_fpga_reg_value description] - * @param dev [description] - * @param devattr [description] - * @param buf [description] - * @return [description] + * Show the value of the register set by 'set_fpga_reg_address' + * If the address is not set by 'set_fpga_reg_address' first, + * The version register is selected by default. + * @param buf register value in hextring + * @return number of bytes read, or an error code */ -static ssize_t get_fpga_reg_value(struct device *dev, struct device_attribute *devattr, - char *buf) +static ssize_t get_fpga_reg_value(struct device *dev, + struct device_attribute *attr, char *buf) { // read data from the address uint32_t data; data = ioread32(fpga_data->fpga_read_addr); - return sprintf(buf,"0x%8.8x\n",data); + return sprintf(buf, "0x%8.8x\n", data); } -/** - * [set_fpga_reg_address description] - * @param dev [description] - * @param devattr [description] - * @param buf [description] - * @param count [description] - * @return [description] - */ -static ssize_t set_fpga_reg_address(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) -{ - uint32_t addr; - char *last; - addr = (uint32_t)strtoul(buf,&last,16); - if(addr == 0 && buf == last){ - return -EINVAL; - } - fpga_data->fpga_read_addr = fpga_dev.data_base_addr+addr; - return count; -} /** - * [get_fpga_scratch description] - * @param dev [description] - * @param devattr [description] - * @param buf [description] - * @return [description] + * Store the register address + * @param buf address wanted to be read value of + * @return number of bytes stored, or an error code */ -static ssize_t get_fpga_scratch(struct device *dev, struct device_attribute *devattr, - char *buf) +static ssize_t set_fpga_reg_address(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - return sprintf(buf,"0x%8.8x\n", ioread32(fpga_dev.data_base_addr+FPGA_SCRATCH) & 0xffffffff); + ssize_t status; + uint32_t addr; + + status = kstrtou32(buf, 0, &addr); + if (status == 0) { + fpga_data->fpga_read_addr = fpga_dev.data_base_addr + addr; + status = count; + } + return status; } + /** - * [set_fpga_scratch description] - * @param dev [description] - * @param devattr [description] - * @param buf [description] - * @param count [description] - * @return [description] + * Show value of fpga scratch register + * @param buf register value in hexstring + * @return number of bytes read, or an error code */ -static ssize_t set_fpga_scratch(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) +static ssize_t get_fpga_scratch(struct device *dev, + struct device_attribute *attr, char *buf) { uint32_t data; - char *last; - data = (uint32_t)strtoul(buf,&last,16); - if(data == 0 && buf == last){ - return -EINVAL; - } - iowrite32(data, fpga_dev.data_base_addr+FPGA_SCRATCH); - return count; + data = ioread32(fpga_dev.data_base_addr + FPGA_SCRATCH); + data &= 0xffffffff; + return sprintf(buf, "0x%8.8x\n", data); } + /** - * [set_fpga_reg_value description] - * @param dev [description] - * @param devattr [description] - * @param buf [description] - * @return [description] + * Store value of fpga scratch register + * @param buf scratch register value passing from user space + * @return number of bytes stored, or an error code */ -static ssize_t set_fpga_reg_value(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) +static ssize_t set_fpga_scratch(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + ssize_t status; + uint32_t data; + + status = kstrtou32(buf, 0, &data); + if (status == 0) { + iowrite32(data, fpga_dev.data_base_addr + FPGA_SCRATCH); + status = count; + } + return status; +} + +/** + * Store a value in a specific register address + * @param buf the value and address in format '0xhhhh 0xhhhhhhhh' + * @return number of bytes sent by user space, or an error code + */ +static ssize_t set_fpga_reg_value(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { //register is 4 bytes uint32_t addr; @@ -457,46 +454,46 @@ static ssize_t set_fpga_reg_value(struct device *dev, struct device_attribute *d char *tok; char clone[count]; char *pclone = clone; - char *last; + ssize_t status; strcpy(clone, buf); mutex_lock(&fpga_data->fpga_lock); tok = strsep((char**)&pclone, " "); - if(tok == NULL){ + if (tok == NULL) { mutex_unlock(&fpga_data->fpga_lock); return -EINVAL; } - addr = (uint32_t)strtoul(tok,&last,16); - if(addr == 0 && tok == last){ + status = kstrtou32(tok, 0, &addr); + if (status != 0) { mutex_unlock(&fpga_data->fpga_lock); return -EINVAL; } tok = strsep((char**)&pclone, " "); - if(tok == NULL){ + if (tok == NULL) { mutex_unlock(&fpga_data->fpga_lock); return -EINVAL; } - value = (uint32_t)strtoul(tok,&last,16); - if(value == 0 && tok == last){ + status = kstrtou32(tok, 0, &value); + if (status != 0) { mutex_unlock(&fpga_data->fpga_lock); return -EINVAL; } tok = strsep((char**)&pclone, " "); - if(tok == NULL){ + if (tok == NULL) { mode = 32; - }else{ - mode = (uint32_t)strtoul(tok,&last,10); - if(mode == 0 && tok == last){ + } else { + status = kstrtou32(tok, 0, &mode); + if (status != 0) { mutex_unlock(&fpga_data->fpga_lock); return -EINVAL; } } - if(mode == 32){ - iowrite32(value, fpga_dev.data_base_addr+addr); - }else if(mode == 8){ - iowrite8(value, fpga_dev.data_base_addr+addr); - }else{ + if (mode == 32) { + iowrite32(value, fpga_dev.data_base_addr + addr); + } else if (mode == 8) { + iowrite8(value, fpga_dev.data_base_addr + addr); + } else { mutex_unlock(&fpga_data->fpga_lock); return -EINVAL; } @@ -513,7 +510,7 @@ static ssize_t ready_show(struct device *dev, struct device_attribute *attr, cha unsigned int REGISTER = FPGA_PORT_XCVR_READY; mutex_lock(&fpga_data->fpga_lock); - data = ioread32(fpga_dev.data_base_addr+REGISTER); + data = ioread32(fpga_dev.data_base_addr + REGISTER); mutex_unlock(&fpga_data->fpga_lock); return sprintf(buf, "%d\n", (data >> 0) & 1U); } @@ -525,409 +522,673 @@ static DEVICE_ATTR( setreg, 0200, NULL , set_fpga_reg_value); static DEVICE_ATTR_RO(ready); static struct attribute *fpga_attrs[] = { - &dev_attr_getreg.attr, - &dev_attr_scratch.attr, - &dev_attr_setreg.attr, - &dev_attr_ready.attr, - NULL, + &dev_attr_getreg.attr, + &dev_attr_scratch.attr, + &dev_attr_setreg.attr, + &dev_attr_ready.attr, + NULL, }; static struct attribute_group fpga_attr_grp = { - .attrs = fpga_attrs, + .attrs = fpga_attrs, }; /* SW CPLDs attributes */ -static ssize_t cpld1_getreg_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t cpld1_getreg_show(struct device *dev, + struct device_attribute *attr, char *buf) { // CPLD register is one byte uint8_t data; - fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX],CPLD1_SLAVE_ADDR,0x00,I2C_SMBUS_READ,fpga_data->cpld1_read_addr,I2C_SMBUS_BYTE_DATA,(union i2c_smbus_data*)&data); - return sprintf(buf,"0x%2.2x\n",data); + int err; + + err = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX], + CPLD1_SLAVE_ADDR, 0x00, + I2C_SMBUS_READ, fpga_data->cpld1_read_addr, + I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data); + + if (err < 0) + return err; + + return sprintf(buf, "0x%2.2x\n", data); } -static ssize_t cpld1_getreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) + +static ssize_t cpld1_getreg_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { + ssize_t status; uint8_t addr; - char *last; - addr = (uint8_t)strtoul(buf,&last,16); - if(addr == 0 && buf == last){ - return -EINVAL; - } - fpga_data->cpld1_read_addr = addr; - return size; -} -struct device_attribute dev_attr_cpld1_getreg = __ATTR(getreg,0600,cpld1_getreg_show,cpld1_getreg_store); -static ssize_t cpld1_scratch_show(struct device *dev, struct device_attribute *attr, char *buf) + status = kstrtou8(buf, 0, &addr); + if (status == 0) { + fpga_data->cpld1_read_addr = addr; + status = count; + } + return status; +} + +static ssize_t cpld1_scratch_show(struct device *dev, + struct device_attribute *attr, char *buf) { // CPLD register is one byte - __u8 data; + uint8_t data; int err; - err = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX],CPLD1_SLAVE_ADDR,0x00,I2C_SMBUS_READ,0x01,I2C_SMBUS_BYTE_DATA,(union i2c_smbus_data*)&data); - if(err < 0) + + err = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX], + CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x01, + I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data); + if (err < 0) return err; - return sprintf(buf, "0x%2.2x\n",data); + + return sprintf(buf, "0x%2.2x\n", data); } -static ssize_t cpld1_scratch_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) + +static ssize_t cpld1_scratch_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { // CPLD register is one byte - __u8 data; - char *last; + uint8_t data; + ssize_t status; int err; - data = (uint8_t)strtoul(buf,&last,16); - if(data == 0 && buf == last){ - return -EINVAL; - } - err = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX],CPLD1_SLAVE_ADDR,0x00,I2C_SMBUS_WRITE,0x01,I2C_SMBUS_BYTE_DATA,(union i2c_smbus_data*)&data); - if(err < 0) - return err; - return size; -} -struct device_attribute dev_attr_cpld1_scratch = __ATTR(scratch,0600,cpld1_scratch_show,cpld1_scratch_store); -static ssize_t cpld1_setreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) + status = kstrtou8(buf, 0, &data); + if (status != 0) { + return status; + } + + err = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX], + CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_WRITE, 0x01, + I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data); + if (err < 0) + return err; + + return count; +} + +static ssize_t cpld1_setreg_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - uint8_t addr,value; + uint8_t addr, value; char *tok; - char clone[size]; + char clone[count]; char *pclone = clone; + ssize_t status; int err; - char *last; strcpy(clone, buf); tok = strsep((char**)&pclone, " "); - if(tok == NULL){ + if (tok == NULL) { return -EINVAL; } - addr = (uint8_t)strtoul(tok,&last,16); - if(addr == 0 && tok == last){ + status = kstrtou8(tok, 0, &addr); + if (status != 0) { return -EINVAL; } tok = strsep((char**)&pclone, " "); - if(tok == NULL){ + if (tok == NULL) { return -EINVAL; } - value = (uint8_t)strtoul(tok,&last,16); - if(value == 0 && tok == last){ + status = kstrtou8(tok, 0, &value); + if (status != 0) { return -EINVAL; } - err = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX],CPLD1_SLAVE_ADDR,0x00,I2C_SMBUS_WRITE,addr,I2C_SMBUS_BYTE_DATA,(union i2c_smbus_data*)&value); - if(err < 0) + err = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX], + CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_WRITE, addr, + I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&value); + if (err < 0) return err; - return size; + return count; } -struct device_attribute dev_attr_cpld1_setreg = __ATTR(setreg,0200,NULL,cpld1_setreg_store); + +struct device_attribute dev_attr_cpld1_getreg = __ATTR(getreg, 0600, cpld1_getreg_show, cpld1_getreg_store); +struct device_attribute dev_attr_cpld1_scratch = __ATTR(scratch, 0600, cpld1_scratch_show, cpld1_scratch_store); +struct device_attribute dev_attr_cpld1_setreg = __ATTR(setreg, 0200, NULL, cpld1_setreg_store); static struct attribute *cpld1_attrs[] = { - &dev_attr_cpld1_getreg.attr, - &dev_attr_cpld1_scratch.attr, - &dev_attr_cpld1_setreg.attr, - NULL, + &dev_attr_cpld1_getreg.attr, + &dev_attr_cpld1_scratch.attr, + &dev_attr_cpld1_setreg.attr, + NULL, }; static struct attribute_group cpld1_attr_grp = { - .attrs = cpld1_attrs, + .attrs = cpld1_attrs, }; -static ssize_t cpld2_getreg_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t cpld2_getreg_show(struct device *dev, + struct device_attribute *attr, char *buf) { // CPLD register is one byte uint8_t data; - fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX],CPLD2_SLAVE_ADDR,0x00,I2C_SMBUS_READ,fpga_data->cpld2_read_addr,I2C_SMBUS_BYTE_DATA,(union i2c_smbus_data*)&data); - return sprintf(buf,"0x%2.2x\n",data); -} -static ssize_t cpld2_getreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) -{ - // CPLD register is one byte - uint32_t addr; - char *last; - addr = (uint8_t)strtoul(buf,&last,16); - if(addr == 0 && buf == last){ - return -EINVAL; - } - fpga_data->cpld2_read_addr = addr; - return size; -} -struct device_attribute dev_attr_cpld2_getreg = __ATTR(getreg,0600,cpld2_getreg_show,cpld2_getreg_store); - -static ssize_t cpld2_scratch_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - // CPLD register is one byte - __u8 data; - int err; - err = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX],CPLD2_SLAVE_ADDR,0x00,I2C_SMBUS_READ,0x01,I2C_SMBUS_BYTE_DATA,(union i2c_smbus_data*)&data); - if(err < 0) - return err; - return sprintf(buf, "0x%2.2x\n",data); -} -static ssize_t cpld2_scratch_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) -{ - // CPLD register is one byte - __u8 data; - char *last; int err; - data = (uint8_t)strtoul(buf,&last,16); - if(data == 0 && buf == last){ + err = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX], + CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, fpga_data->cpld2_read_addr, + I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data); + if (err < 0) + return err; + + return sprintf(buf, "0x%2.2x\n", data); +} + +static ssize_t cpld2_getreg_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + // CPLD register is one byte + uint8_t addr; + ssize_t status; + + status = kstrtou8(buf, 0, &addr); + if (status == 0) { + fpga_data->cpld2_read_addr = addr; + status = count; + } + return status; +} + +static ssize_t cpld2_scratch_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + // CPLD register is one byte + uint8_t data; + int err; + + err = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX], + CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x01, + I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data); + if (err < 0) + return err; + + return sprintf(buf, "0x%2.2x\n", data); +} + +static ssize_t cpld2_scratch_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + // CPLD register is one byte + uint8_t data; + int err; + ssize_t status; + + status = kstrtou8(buf, 0, &data); + if (status != 0) { return -EINVAL; } - err = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX],CPLD2_SLAVE_ADDR,0x00,I2C_SMBUS_WRITE,0x01,I2C_SMBUS_BYTE_DATA,(union i2c_smbus_data*)&data); - if(err < 0) + err = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX], + CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_WRITE, 0x01, + I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data); + if (err < 0) return err; - return size; -} -struct device_attribute dev_attr_cpld2_scratch = __ATTR(scratch,0600,cpld2_scratch_show,cpld2_scratch_store); -static ssize_t cpld2_setreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) + return count; +} + +static ssize_t cpld2_setreg_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - uint8_t addr,value; + uint8_t addr, value; char *tok; - char clone[size]; + char clone[count]; char *pclone = clone; + ssize_t status; int err; - char *last; strcpy(clone, buf); tok = strsep((char**)&pclone, " "); - if(tok == NULL){ + if (tok == NULL) { return -EINVAL; } - addr = (uint8_t)strtoul(tok,&last,16); - if(addr == 0 && tok == last){ + status = kstrtou8(tok, 0, &addr); + if (status != 0) { return -EINVAL; } tok = strsep((char**)&pclone, " "); - if(tok == NULL){ + if (tok == NULL) { return -EINVAL; } - value = (uint8_t)strtoul(tok,&last,16); - if(value == 0 && tok == last){ + status = kstrtou8(tok, 0, &value); + if (status != 0) { return -EINVAL; } - err = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX],CPLD2_SLAVE_ADDR,0x00,I2C_SMBUS_WRITE,addr,I2C_SMBUS_BYTE_DATA,(union i2c_smbus_data*)&value); - if(err < 0) + err = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX], + CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_WRITE, addr, + I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&value); + if (err < 0) return err; - return size; + return count; } -struct device_attribute dev_attr_cpld2_setreg = __ATTR(setreg,0200,NULL,cpld2_setreg_store); + +struct device_attribute dev_attr_cpld2_getreg = __ATTR(getreg, 0600, cpld2_getreg_show, cpld2_getreg_store); +struct device_attribute dev_attr_cpld2_scratch = __ATTR(scratch, 0600, cpld2_scratch_show, cpld2_scratch_store); +struct device_attribute dev_attr_cpld2_setreg = __ATTR(setreg, 0200, NULL, cpld2_setreg_store); static struct attribute *cpld2_attrs[] = { - &dev_attr_cpld2_getreg.attr, - &dev_attr_cpld2_scratch.attr, - &dev_attr_cpld2_setreg.attr, - NULL, + &dev_attr_cpld2_getreg.attr, + &dev_attr_cpld2_scratch.attr, + &dev_attr_cpld2_setreg.attr, + NULL, }; static struct attribute_group cpld2_attr_grp = { - .attrs = cpld2_attrs, + .attrs = cpld2_attrs, }; /* QSFP/SFP+ attributes */ -static ssize_t qsfp_modirq_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t qsfp_modirq_show(struct device *dev, + struct device_attribute *attr, char *buf) { u32 data; struct sff_device_data *dev_data = dev_get_drvdata(dev); unsigned int portid = dev_data->portid; - unsigned int REGISTER = SFF_PORT_STATUS_BASE + (portid-1)*0x10; + unsigned int REGISTER = SFF_PORT_STATUS_BASE + (portid - 1) * 0x10; mutex_lock(&fpga_data->fpga_lock); - data = ioread32(fpga_dev.data_base_addr+REGISTER); + data = ioread32(fpga_dev.data_base_addr + REGISTER); mutex_unlock(&fpga_data->fpga_lock); return sprintf(buf, "%d\n", (data >> STAT_IRQ) & 1U); } DEVICE_ATTR_RO(qsfp_modirq); -static ssize_t qsfp_modprs_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t qsfp_modprs_show(struct device *dev, + struct device_attribute *attr, char *buf) { u32 data; struct sff_device_data *dev_data = dev_get_drvdata(dev); unsigned int portid = dev_data->portid; - unsigned int REGISTER = SFF_PORT_STATUS_BASE + (portid-1)*0x10; + unsigned int REGISTER = SFF_PORT_STATUS_BASE + (portid - 1) * 0x10; mutex_lock(&fpga_data->fpga_lock); - data = ioread32(fpga_dev.data_base_addr+REGISTER); + data = ioread32(fpga_dev.data_base_addr + REGISTER); mutex_unlock(&fpga_data->fpga_lock); return sprintf(buf, "%d\n", (data >> STAT_PRESENT) & 1U); } DEVICE_ATTR_RO(qsfp_modprs); -static ssize_t sfp_txfault_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t sfp_txfault_show(struct device *dev, + struct device_attribute *attr, char *buf) { u32 data; struct sff_device_data *dev_data = dev_get_drvdata(dev); unsigned int portid = dev_data->portid; - unsigned int REGISTER = SFF_PORT_STATUS_BASE + (portid-1)*0x10; + unsigned int REGISTER = SFF_PORT_STATUS_BASE + (portid - 1) * 0x10; mutex_lock(&fpga_data->fpga_lock); - data = ioread32(fpga_dev.data_base_addr+REGISTER); + data = ioread32(fpga_dev.data_base_addr + REGISTER); mutex_unlock(&fpga_data->fpga_lock); return sprintf(buf, "%d\n", (data >> STAT_TXFAULT) & 1U); } DEVICE_ATTR_RO(sfp_txfault); -static ssize_t sfp_rxlos_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t sfp_rxlos_show(struct device *dev, + struct device_attribute *attr, char *buf) { u32 data; struct sff_device_data *dev_data = dev_get_drvdata(dev); unsigned int portid = dev_data->portid; - unsigned int REGISTER = SFF_PORT_STATUS_BASE + (portid-1)*0x10; + unsigned int REGISTER = SFF_PORT_STATUS_BASE + (portid - 1) * 0x10; mutex_lock(&fpga_data->fpga_lock); - data = ioread32(fpga_dev.data_base_addr+REGISTER); + data = ioread32(fpga_dev.data_base_addr + REGISTER); mutex_unlock(&fpga_data->fpga_lock); return sprintf(buf, "%d\n", (data >> STAT_RXLOS) & 1U); } DEVICE_ATTR_RO(sfp_rxlos); -static ssize_t sfp_modabs_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t sfp_modabs_show(struct device *dev, + struct device_attribute *attr, char *buf) { u32 data; struct sff_device_data *dev_data = dev_get_drvdata(dev); unsigned int portid = dev_data->portid; - unsigned int REGISTER = SFF_PORT_STATUS_BASE + (portid-1)*0x10; + unsigned int REGISTER = SFF_PORT_STATUS_BASE + (portid - 1) * 0x10; mutex_lock(&fpga_data->fpga_lock); - data = ioread32(fpga_dev.data_base_addr+REGISTER); + data = ioread32(fpga_dev.data_base_addr + REGISTER); mutex_unlock(&fpga_data->fpga_lock); return sprintf(buf, "%d\n", (data >> STAT_MODABS) & 1U); } DEVICE_ATTR_RO(sfp_modabs); -static ssize_t qsfp_lpmode_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t qsfp_lpmode_show(struct device *dev, + struct device_attribute *attr, char *buf) { u32 data; struct sff_device_data *dev_data = dev_get_drvdata(dev); unsigned int portid = dev_data->portid; - unsigned int REGISTER = SFF_PORT_CTRL_BASE + (portid-1)*0x10; + unsigned int REGISTER = SFF_PORT_CTRL_BASE + (portid - 1) * 0x10; mutex_lock(&fpga_data->fpga_lock); - data = ioread32(fpga_dev.data_base_addr+REGISTER); + data = ioread32(fpga_dev.data_base_addr + REGISTER); mutex_unlock(&fpga_data->fpga_lock); return sprintf(buf, "%d\n", (data >> CTRL_LPMOD) & 1U); } -static ssize_t qsfp_lpmode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +static ssize_t qsfp_lpmode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { ssize_t status; - long value; + uint32_t value; u32 data; struct sff_device_data *dev_data = dev_get_drvdata(dev); unsigned int portid = dev_data->portid; - unsigned int REGISTER = SFF_PORT_CTRL_BASE + (portid-1)*0x10; + unsigned int REGISTER = SFF_PORT_CTRL_BASE + (portid - 1) * 0x10; mutex_lock(&fpga_data->fpga_lock); - status = kstrtol(buf, 0, &value); + status = kstrtou32(buf, 0, &value); if (status == 0) { // check if value is 0 clear - data = ioread32(fpga_dev.data_base_addr+REGISTER); - if(!value) + data = ioread32(fpga_dev.data_base_addr + REGISTER); + if (!value) data = data & ~( (u32)0x1 << CTRL_LPMOD); else data = data | ((u32)0x1 << CTRL_LPMOD); - iowrite32(data,fpga_dev.data_base_addr+REGISTER); - status = size; + iowrite32(data, fpga_dev.data_base_addr + REGISTER); + status = count; } mutex_unlock(&fpga_data->fpga_lock); return status; } DEVICE_ATTR_RW(qsfp_lpmode); -static ssize_t qsfp_reset_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t qsfp_reset_show(struct device *dev, + struct device_attribute *attr, char *buf) { u32 data; struct sff_device_data *dev_data = dev_get_drvdata(dev); unsigned int portid = dev_data->portid; - unsigned int REGISTER = SFF_PORT_CTRL_BASE + (portid-1)*0x10; + unsigned int REGISTER = SFF_PORT_CTRL_BASE + (portid - 1) * 0x10; mutex_lock(&fpga_data->fpga_lock); - data = ioread32(fpga_dev.data_base_addr+REGISTER); + data = ioread32(fpga_dev.data_base_addr + REGISTER); mutex_unlock(&fpga_data->fpga_lock); return sprintf(buf, "%d\n", (data >> CTRL_RST) & 1U); } -static ssize_t qsfp_reset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +static ssize_t qsfp_reset_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { ssize_t status; - long value; + uint32_t value; u32 data; struct sff_device_data *dev_data = dev_get_drvdata(dev); unsigned int portid = dev_data->portid; - unsigned int REGISTER = SFF_PORT_CTRL_BASE + (portid-1)*0x10; + unsigned int REGISTER = SFF_PORT_CTRL_BASE + (portid - 1) * 0x10; mutex_lock(&fpga_data->fpga_lock); - status = kstrtol(buf, 0, &value); + status = kstrtou32(buf, 0, &value); if (status == 0) { // check if value is 0 clear - data = ioread32(fpga_dev.data_base_addr+REGISTER); - if(!value) + data = ioread32(fpga_dev.data_base_addr + REGISTER); + if (!value) data = data & ~( (u32)0x1 << CTRL_RST); else data = data | ((u32)0x1 << CTRL_RST); - iowrite32(data,fpga_dev.data_base_addr+REGISTER); - status = size; + iowrite32(data, fpga_dev.data_base_addr + REGISTER); + status = count; } mutex_unlock(&fpga_data->fpga_lock); return status; } DEVICE_ATTR_RW(qsfp_reset); -static ssize_t sfp_txdisable_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t qsfp_isr_flags_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data; + u8 valid_bits; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + unsigned int REGISTER = SFF_PORT_INT_STATUS_BASE + (portid - 1) * 0x10; + valid_bits = BIT(INTR_INT_N) | BIT(INTR_PRESENT); + + mutex_lock(&fpga_data->fpga_lock); + data = (u8) ioread32(fpga_dev.data_base_addr + REGISTER); + mutex_unlock(&fpga_data->fpga_lock); + + /* + * Unify the return pattern to 2-bit + * [1] : module interrupt + * [0] : presence + */ + data = data & valid_bits; + data = data >> 4; + + return sprintf(buf, "0x%2.2x\n", data); +} + +static ssize_t qsfp_isr_flags_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + ssize_t status; + u32 value; + u8 valid_bits; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + unsigned int REGISTER = SFF_PORT_INT_STATUS_BASE + (portid - 1) * 0x10; + valid_bits = BIT(INTR_INT_N) | BIT(INTR_PRESENT); + + mutex_lock(&fpga_data->fpga_lock); + status = kstrtou32(buf, 0, &value); + if (status == 0) { + value = value << 4; + value = value & valid_bits; + iowrite32(value, fpga_dev.data_base_addr + REGISTER); + status = count; + } + mutex_unlock(&fpga_data->fpga_lock); + return status; +} +DEVICE_ATTR_RW(qsfp_isr_flags); + +static ssize_t qsfp_isr_mask_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u32 data; + u8 valid_bits; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + unsigned int REGISTER = SFF_PORT_INT_MASK_BASE + (portid - 1) * 0x10; + valid_bits = BIT(INTR_INT_N) | BIT(INTR_PRESENT); + + mutex_lock(&fpga_data->fpga_lock); + data = ioread32(fpga_dev.data_base_addr + REGISTER); + mutex_unlock(&fpga_data->fpga_lock); + + /* + * Unify the return pattern to 2-bit + * [1] : module interrupt + * [0] : presence + */ + data = data & valid_bits; + data = data >> 4; + + return sprintf(buf, "0x%2.2x\n", data); +} + +static ssize_t qsfp_isr_mask_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + ssize_t status; + u32 value; + u8 valid_bits; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + unsigned int REGISTER = SFF_PORT_INT_MASK_BASE + (portid - 1) * 0x10; + valid_bits = BIT(INTR_INT_N) | BIT(INTR_PRESENT); + + mutex_lock(&fpga_data->fpga_lock); + status = kstrtou32(buf, 0, &value); + if (status == 0) { + value = value << 4; + value = value & valid_bits; + iowrite32(value, fpga_dev.data_base_addr + REGISTER); + status = count; + } + mutex_unlock(&fpga_data->fpga_lock); + return status; +} +DEVICE_ATTR_RW(qsfp_isr_mask); + +static ssize_t sfp_txdisable_show(struct device *dev, + struct device_attribute *attr, char *buf) { u32 data; struct sff_device_data *dev_data = dev_get_drvdata(dev); unsigned int portid = dev_data->portid; - unsigned int REGISTER = SFF_PORT_CTRL_BASE + (portid-1)*0x10; + unsigned int REGISTER = SFF_PORT_CTRL_BASE + (portid - 1) * 0x10; mutex_lock(&fpga_data->fpga_lock); - data = ioread32(fpga_dev.data_base_addr+REGISTER); + data = ioread32(fpga_dev.data_base_addr + REGISTER); mutex_unlock(&fpga_data->fpga_lock); return sprintf(buf, "%d\n", (data >> CTRL_TXDIS) & 1U); } -static ssize_t sfp_txdisable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +static ssize_t sfp_txdisable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { ssize_t status; long value; u32 data; struct sff_device_data *dev_data = dev_get_drvdata(dev); unsigned int portid = dev_data->portid; - unsigned int REGISTER = SFF_PORT_CTRL_BASE + (portid-1)*0x10; + unsigned int REGISTER = SFF_PORT_CTRL_BASE + (portid - 1) * 0x10; mutex_lock(&fpga_data->fpga_lock); status = kstrtol(buf, 0, &value); if (status == 0) { // check if value is 0 clear - data = ioread32(fpga_dev.data_base_addr+REGISTER); - if(!value) + data = ioread32(fpga_dev.data_base_addr + REGISTER); + if (!value) data = data & ~( (u32)0x1 << CTRL_TXDIS); else data = data | ((u32)0x1 << CTRL_TXDIS); - iowrite32(data,fpga_dev.data_base_addr+REGISTER); - status = size; + iowrite32(data, fpga_dev.data_base_addr + REGISTER); + status = count; } mutex_unlock(&fpga_data->fpga_lock); return status; } DEVICE_ATTR_RW(sfp_txdisable); +static ssize_t sfp_isr_flags_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data; + u8 valid_bits; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + unsigned int REGISTER = SFF_PORT_INT_STATUS_BASE + (portid - 1) * 0x10; + valid_bits = BIT(INTR_RXLOS) | BIT(INTR_MODABS); + + mutex_lock(&fpga_data->fpga_lock); + data = (u8) ioread32(fpga_dev.data_base_addr + REGISTER); + mutex_unlock(&fpga_data->fpga_lock); + + data = data & valid_bits; + + return sprintf(buf, "0x%2.2x\n", data); +} + +static ssize_t sfp_isr_flags_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + ssize_t status; + u32 value; + u8 valid_bits; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + unsigned int REGISTER = SFF_PORT_INT_STATUS_BASE + (portid - 1) * 0x10; + valid_bits = BIT(INTR_INT_N) | BIT(INTR_PRESENT); + + mutex_lock(&fpga_data->fpga_lock); + status = kstrtou32(buf, 0, &value); + if (status == 0) { + value = value & valid_bits; + iowrite32(value, fpga_dev.data_base_addr + REGISTER); + status = count; + } + mutex_unlock(&fpga_data->fpga_lock); + return status; +} +DEVICE_ATTR_RW(sfp_isr_flags); + +static ssize_t sfp_isr_mask_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u32 data; + u8 valid_bits; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + unsigned int REGISTER = SFF_PORT_INT_MASK_BASE + (portid - 1) * 0x10; + valid_bits = BIT(INTR_RXLOS) | BIT(INTR_MODABS); + + mutex_lock(&fpga_data->fpga_lock); + data = ioread32(fpga_dev.data_base_addr + REGISTER); + mutex_unlock(&fpga_data->fpga_lock); + + data = data & valid_bits; + + return sprintf(buf, "0x%2.2x\n", data); +} + +static ssize_t sfp_isr_mask_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + ssize_t status; + u32 value; + u8 valid_bits; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + unsigned int REGISTER = SFF_PORT_INT_MASK_BASE + (portid - 1) * 0x10; + valid_bits = BIT(INTR_RXLOS) | BIT(INTR_MODABS); + + mutex_lock(&fpga_data->fpga_lock); + status = kstrtou32(buf, 0, &value); + if (status == 0) { + value = value & valid_bits; + iowrite32(value, fpga_dev.data_base_addr + REGISTER); + status = count; + } + mutex_unlock(&fpga_data->fpga_lock); + return status; +} +DEVICE_ATTR_RW(sfp_isr_mask); + static struct attribute *sff_attrs[] = { &dev_attr_qsfp_modirq.attr, &dev_attr_qsfp_modprs.attr, &dev_attr_qsfp_lpmode.attr, &dev_attr_qsfp_reset.attr, + &dev_attr_qsfp_isr_flags.attr, + &dev_attr_qsfp_isr_mask.attr, &dev_attr_sfp_txfault.attr, &dev_attr_sfp_rxlos.attr, &dev_attr_sfp_modabs.attr, &dev_attr_sfp_txdisable.attr, + &dev_attr_sfp_isr_flags.attr, + &dev_attr_sfp_isr_mask.attr, NULL, }; static struct attribute_group sff_attr_grp = { - .attrs = sff_attrs, + .attrs = sff_attrs, }; static const struct attribute_group *sff_attr_grps[] = { @@ -936,78 +1197,99 @@ static const struct attribute_group *sff_attr_grps[] = { }; -static ssize_t port_led_mode_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t port_led_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) { // value can be "nomal", "test" - __u8 led_mode_1,led_mode_2; + __u8 led_mode_1, led_mode_2; int err; - err = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX],CPLD1_SLAVE_ADDR,0x00,I2C_SMBUS_READ,0x09,I2C_SMBUS_BYTE_DATA,(union i2c_smbus_data*)&led_mode_1); - if(err < 0) + err = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX], + CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x09, + I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_mode_1); + if (err < 0) return err; - err = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX],CPLD2_SLAVE_ADDR,0x00,I2C_SMBUS_READ,0x09,I2C_SMBUS_BYTE_DATA,(union i2c_smbus_data*)&led_mode_2); - if(err < 0) + err = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX], + CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x09, + I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_mode_2); + if (err < 0) return err; + return sprintf(buf, "%s %s\n", - led_mode_1 ? "test" : "normal", - led_mode_2 ? "test" : "normal"); + led_mode_1 ? "test" : "normal", + led_mode_2 ? "test" : "normal"); } -static ssize_t port_led_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +static ssize_t port_led_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { int status; __u8 led_mode_1; - if(sysfs_streq(buf, "test")){ + if (sysfs_streq(buf, "test")) { led_mode_1 = 0x01; - }else if(sysfs_streq(buf, "normal")){ + } else if (sysfs_streq(buf, "normal")) { led_mode_1 = 0x00; - }else{ + } else { return -EINVAL; } - status = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX],CPLD1_SLAVE_ADDR,0x00, - I2C_SMBUS_WRITE,0x09,I2C_SMBUS_BYTE_DATA,(union i2c_smbus_data*)&led_mode_1); - status = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX],CPLD2_SLAVE_ADDR,0x00, - I2C_SMBUS_WRITE,0x09,I2C_SMBUS_BYTE_DATA,(union i2c_smbus_data*)&led_mode_1); - return size; + status = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX], + CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_WRITE, 0x09, + I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_mode_1); + status = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX], + CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_WRITE, 0x09, + I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_mode_1); + return count; } DEVICE_ATTR_RW(port_led_mode); // Only work when port_led_mode set to 1 -static ssize_t port_led_color_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t port_led_color_show(struct device *dev, + struct device_attribute *attr, char *buf) { // value can be "off", "green", "amber", "both" - __u8 led_color1,led_color2; + __u8 led_color1, led_color2; int err; - err = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX],CPLD1_SLAVE_ADDR,0x00,I2C_SMBUS_READ,0x09,I2C_SMBUS_BYTE_DATA,(union i2c_smbus_data*)&led_color1); - if(err < 0) + err = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX], + CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x0A, + I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_color1); + if (err < 0) return err; - err = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX],CPLD2_SLAVE_ADDR,0x00,I2C_SMBUS_READ,0x09,I2C_SMBUS_BYTE_DATA,(union i2c_smbus_data*)&led_color2); - if(err < 0) + err = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX], + CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x0A, + I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_color2); + if (err < 0) return err; return sprintf(buf, "%s %s\n", - led_color1 == 0x03 ? "off" : led_color1 == 0x02 ? "green" : led_color1 ==0x01 ? "amber": "both", - led_color2 == 0x03 ? "off" : led_color2 == 0x02 ? "green" : led_color2 ==0x01 ? "amber": "both"); + led_color1 == 0x03 ? "off" : led_color1 == 0x02 ? "green" : led_color1 == 0x01 ? "amber" : "both", + led_color2 == 0x03 ? "off" : led_color2 == 0x02 ? "green" : led_color2 == 0x01 ? "amber" : "both"); } -static ssize_t port_led_color_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +static ssize_t port_led_color_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { int status; __u8 led_color; - if(sysfs_streq(buf, "off")){ + if (sysfs_streq(buf, "off")) { led_color = 0x03; - }else if(sysfs_streq(buf, "green")){ + } else if (sysfs_streq(buf, "green")) { led_color = 0x02; - }else if(sysfs_streq(buf, "amber")){ + } else if (sysfs_streq(buf, "amber")) { led_color = 0x01; - }else if(sysfs_streq(buf, "both")){ + } else if (sysfs_streq(buf, "both")) { led_color = 0x00; - }else{ + } else { status = -EINVAL; return status; } - status = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX],CPLD1_SLAVE_ADDR,0x00, - I2C_SMBUS_WRITE,0x0A,I2C_SMBUS_BYTE_DATA,(union i2c_smbus_data*)&led_color); - status = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX],CPLD2_SLAVE_ADDR,0x00, - I2C_SMBUS_WRITE,0x0A,I2C_SMBUS_BYTE_DATA,(union i2c_smbus_data*)&led_color); - return size; + status = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX], + CPLD1_SLAVE_ADDR, 0x00, + I2C_SMBUS_WRITE, 0x0A, I2C_SMBUS_BYTE_DATA, + (union i2c_smbus_data*)&led_color); + status = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX], + CPLD2_SLAVE_ADDR, 0x00, + I2C_SMBUS_WRITE, 0x0A, I2C_SMBUS_BYTE_DATA, + (union i2c_smbus_data*)&led_color); + return count; } DEVICE_ATTR_RW(port_led_color); @@ -1018,10 +1300,10 @@ static struct attribute *sff_led_test[] = { }; static struct attribute_group sff_led_test_grp = { - .attrs = sff_led_test, + .attrs = sff_led_test, }; -static struct device * seastone2_sff_init(int portid){ +static struct device * seastone2_sff_init(int portid) { struct sff_device_data *new_data; struct device *new_device; @@ -1031,9 +1313,11 @@ static struct device * seastone2_sff_init(int portid){ return NULL; } /* The QSFP port ID start from 1 */ - new_data->portid = portid+1; + new_data->portid = portid + 1; new_data->port_type = fpga_i2c_bus_dev[portid].port_type; - new_device = device_create_with_groups(fpgafwclass, sff_dev, MKDEV(0,0), new_data, sff_attr_grps, "%s",fpga_i2c_bus_dev[portid].calling_name); + new_device = device_create_with_groups(fpgafwclass, sff_dev, + MKDEV(0, 0), new_data, sff_attr_grps, "%s", + fpga_i2c_bus_dev[portid].calling_name); if (IS_ERR(new_device)) { printk(KERN_ALERT "Cannot create sff device @port%d", portid); kfree(new_data); @@ -1042,7 +1326,7 @@ static struct device * seastone2_sff_init(int portid){ return new_device; } -static int i2c_wait_ack(struct i2c_adapter *a,unsigned long timeout,int writing){ +static int i2c_wait_ack(struct i2c_adapter *a, unsigned long timeout, int writing) { int error = 0; int Status; @@ -1057,65 +1341,65 @@ static int i2c_wait_ack(struct i2c_adapter *a,unsigned long timeout,int writing) unsigned int master_bus = new_data->pca9548.master_bus; - if(master_bus < I2C_MASTER_CH_1 || master_bus > I2C_MASTER_CH_TOTAL){ + if (master_bus < I2C_MASTER_CH_1 || master_bus > I2C_MASTER_CH_TOTAL) { error = -EINVAL; return error; } - REG_FDR0 = I2C_MASTER_FREQ_1 + (master_bus-1)*0x0100; - REG_CR0 = I2C_MASTER_CTRL_1 + (master_bus-1)*0x0100; - REG_SR0 = I2C_MASTER_STATUS_1 + (master_bus-1)*0x0100; - REG_DR0 = I2C_MASTER_DATA_1 + (master_bus-1)*0x0100; - REG_ID0 = I2C_MASTER_PORT_ID_1 + (master_bus-1)*0x0100; + REG_FDR0 = I2C_MASTER_FREQ_1 + (master_bus - 1) * 0x0100; + REG_CR0 = I2C_MASTER_CTRL_1 + (master_bus - 1) * 0x0100; + REG_SR0 = I2C_MASTER_STATUS_1 + (master_bus - 1) * 0x0100; + REG_DR0 = I2C_MASTER_DATA_1 + (master_bus - 1) * 0x0100; + REG_ID0 = I2C_MASTER_PORT_ID_1 + (master_bus - 1) * 0x0100; - check(pci_bar+REG_SR0); - check(pci_bar+REG_CR0); + check(pci_bar + REG_SR0); + check(pci_bar + REG_CR0); timeout = jiffies + msecs_to_jiffies(timeout); - while(1){ - Status = ioread8(pci_bar+REG_SR0); - if(jiffies > timeout){ - info("Status %2.2X",Status); + while (1) { + Status = ioread8(pci_bar + REG_SR0); + if (jiffies > timeout) { + info("Status %2.2X", Status); info("Error Timeout"); error = -ETIMEDOUT; break; } - if(Status & (1 << I2C_SR_BIT_MIF)){ + if (Status & (1 << I2C_SR_BIT_MIF)) { break; } - if(writing == 0 && (Status & (1<portid; - pci_bar = fpga_dev.data_base_addr; + /* Write the command register */ + dev_data = i2c_get_adapdata(adapter); + portid = dev_data->portid; + pci_bar = fpga_dev.data_base_addr; #ifdef DEBUG_KERN - printk(KERN_INFO "portid %2d|@ 0x%2.2X|f 0x%4.4X|(%d)%-5s| (%d)%-15s|CMD %2.2X " - ,portid,addr,flags,rw,rw == 1 ? "READ ":"WRITE" - ,size, size == 0 ? "QUICK" : - size == 1 ? "BYTE" : - size == 2 ? "BYTE_DATA" : - size == 3 ? "WORD_DATA" : - size == 4 ? "PROC_CALL" : - size == 5 ? "BLOCK_DATA" : - size == 8 ? "I2C_BLOCK_DATA" : "ERROR" - ,cmd); + printk(KERN_INFO "portid %2d|@ 0x%2.2X|f 0x%4.4X|(%d)%-5s| (%d)%-15s|CMD %2.2X " + , portid, addr, flags, rw, rw == 1 ? "READ " : "WRITE" + , size, size == 0 ? "QUICK" : + size == 1 ? "BYTE" : + size == 2 ? "BYTE_DATA" : + size == 3 ? "WORD_DATA" : + size == 4 ? "PROC_CALL" : + size == 5 ? "BLOCK_DATA" : + size == 8 ? "I2C_BLOCK_DATA" : "ERROR" + , cmd); #endif - /* Map the size to what the chip understands */ - switch (size) { - case I2C_SMBUS_QUICK: - case I2C_SMBUS_BYTE: - case I2C_SMBUS_BYTE_DATA: - case I2C_SMBUS_WORD_DATA: - case I2C_SMBUS_BLOCK_DATA: - case I2C_SMBUS_I2C_BLOCK_DATA: - break; - default: - printk(KERN_INFO "Unsupported transaction %d\n", size); - error = -EOPNOTSUPP; - goto Done; - } + /* Map the size to what the chip understands */ + switch (size) { + case I2C_SMBUS_QUICK: + case I2C_SMBUS_BYTE: + case I2C_SMBUS_BYTE_DATA: + case I2C_SMBUS_WORD_DATA: + case I2C_SMBUS_BLOCK_DATA: + case I2C_SMBUS_I2C_BLOCK_DATA: + break; + default: + printk(KERN_INFO "Unsupported transaction %d\n", size); + error = -EOPNOTSUPP; + goto Done; + } - master_bus = dev_data->pca9548.master_bus; + master_bus = dev_data->pca9548.master_bus; - if(master_bus < I2C_MASTER_CH_1 || master_bus > I2C_MASTER_CH_TOTAL){ - error = -ENXIO; - goto Done; - } + if (master_bus < I2C_MASTER_CH_1 || master_bus > I2C_MASTER_CH_TOTAL) { + error = -ENXIO; + goto Done; + } - REG_FDR0 = I2C_MASTER_FREQ_1 + (master_bus-1)*0x0100; - REG_CR0 = I2C_MASTER_CTRL_1 + (master_bus-1)*0x0100; - REG_SR0 = I2C_MASTER_STATUS_1 + (master_bus-1)*0x0100; - REG_DR0 = I2C_MASTER_DATA_1 + (master_bus-1)*0x0100; - REG_ID0 = I2C_MASTER_PORT_ID_1 + (master_bus-1)*0x0100; + REG_FDR0 = I2C_MASTER_FREQ_1 + (master_bus - 1) * 0x0100; + REG_CR0 = I2C_MASTER_CTRL_1 + (master_bus - 1) * 0x0100; + REG_SR0 = I2C_MASTER_STATUS_1 + (master_bus - 1) * 0x0100; + REG_DR0 = I2C_MASTER_DATA_1 + (master_bus - 1) * 0x0100; + REG_ID0 = I2C_MASTER_PORT_ID_1 + (master_bus - 1) * 0x0100; - iowrite8(portid,pci_bar+REG_ID0); + iowrite8(portid, pci_bar + REG_ID0); - ////[S][ADDR/R] - // Clear status register - iowrite8(0,pci_bar+REG_SR0); - iowrite8(1 << I2C_CR_BIT_MIEN | 1 << I2C_CR_BIT_MTX | 1 << I2C_CR_BIT_MSTA ,pci_bar+REG_CR0); - SET_REG_BIT_H(pci_bar+REG_CR0,I2C_CR_BIT_MEN); + ////[S][ADDR/R] + // Clear status register + iowrite8(0, pci_bar + REG_SR0); + iowrite8(1 << I2C_CR_BIT_MIEN | + 1 << I2C_CR_BIT_MTX | + 1 << I2C_CR_BIT_MSTA , pci_bar + REG_CR0); + SET_REG_BIT_H(pci_bar + REG_CR0, I2C_CR_BIT_MEN); - if(rw == I2C_SMBUS_READ && - (size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE)){ - // sent device address with Read mode - iowrite8(addr << 1 | 0x01,pci_bar+REG_DR0); - }else{ - // sent device address with Write mode - iowrite8(addr << 1 | 0x00,pci_bar+REG_DR0); - } + if (rw == I2C_SMBUS_READ && + (size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE)) { + // sent device address with Read mode + iowrite8(addr << 1 | 0x01, pci_bar + REG_DR0); + } else { + // sent device address with Write mode + iowrite8(addr << 1 | 0x00, pci_bar + REG_DR0); + } - info( "MS Start"); + info( "MS Start"); - //// Wait {A} - error = i2c_wait_ack(adapter,12,1); - if(error<0){ - info( "get error %d",error); - goto Done; - } + //// Wait {A} + error = i2c_wait_ack(adapter, 12, 1); + if (error < 0) { + info( "get error %d", error); + goto Done; + } - //// [CMD]{A} - if(size == I2C_SMBUS_BYTE_DATA || + //// [CMD]{A} + if (size == I2C_SMBUS_BYTE_DATA || size == I2C_SMBUS_WORD_DATA || size == I2C_SMBUS_BLOCK_DATA || size == I2C_SMBUS_I2C_BLOCK_DATA || - (size == I2C_SMBUS_BYTE && rw == I2C_SMBUS_WRITE)){ + (size == I2C_SMBUS_BYTE && rw == I2C_SMBUS_WRITE)) { - // sent command code to data register - iowrite8(cmd,pci_bar+REG_DR0); - info( "MS Send CMD 0x%2.2X",cmd); + // sent command code to data register + iowrite8(cmd, pci_bar + REG_DR0); + info( "MS Send CMD 0x%2.2X", cmd); - // Wait {A} - error = i2c_wait_ack(adapter,12,1); - if(error<0){ - info( "get error %d",error); - goto Done; - } + // Wait {A} + error = i2c_wait_ack(adapter, 12, 1); + if (error < 0) { + info( "get error %d", error); + goto Done; } + } - switch(size){ - case I2C_SMBUS_BYTE_DATA: - cnt = 1; break; - case I2C_SMBUS_WORD_DATA: - cnt = 2; break; - case I2C_SMBUS_BLOCK_DATA: - case I2C_SMBUS_I2C_BLOCK_DATA: - /* In block data modes keep number of byte in block[0] */ - cnt = data->block[0]; - break; - default: - cnt = 0; break; + switch (size) { + case I2C_SMBUS_BYTE_DATA: + cnt = 1; break; + case I2C_SMBUS_WORD_DATA: + cnt = 2; break; + case I2C_SMBUS_BLOCK_DATA: + case I2C_SMBUS_I2C_BLOCK_DATA: + /* In block data modes keep number of byte in block[0] */ + cnt = data->block[0]; + break; + default: + cnt = 0; break; + } + + // [CNT] used only block data write + if (size == I2C_SMBUS_BLOCK_DATA && rw == I2C_SMBUS_WRITE) { + + iowrite8(cnt, pci_bar + REG_DR0); + info( "MS Send CNT 0x%2.2X", cnt); + + // Wait {A} + error = i2c_wait_ack(adapter, 12, 1); + if (error < 0) { + info( "get error %d", error); + goto Done; } + } - // [CNT] used only block data write - if(size == I2C_SMBUS_BLOCK_DATA && rw == I2C_SMBUS_WRITE){ - - iowrite8(cnt,pci_bar+REG_DR0); - info( "MS Send CNT 0x%2.2X",cnt); - - // Wait {A} - error = i2c_wait_ack(adapter,12,1); - if(error<0){ - info( "get error %d",error); - goto Done; - } - } - - // [DATA]{A} - if( rw == I2C_SMBUS_WRITE && ( - size == I2C_SMBUS_BYTE || - size == I2C_SMBUS_BYTE_DATA || - size == I2C_SMBUS_WORD_DATA || - size == I2C_SMBUS_BLOCK_DATA || - size == I2C_SMBUS_I2C_BLOCK_DATA - )){ - bid = 0; - info( "MS prepare to sent [%d bytes]",cnt); - if(size == I2C_SMBUS_BLOCK_DATA || size == I2C_SMBUS_I2C_BLOCK_DATA){ - bid=1; // block[0] is cnt; - cnt+=1; // offset from block[0] - } - for(;bidblock[bid],pci_bar+REG_DR0); - info( " Data > %2.2X",data->block[bid]); - // Wait {A} - error = i2c_wait_ack(adapter,12,1); - if(error<0){ - goto Done; - } - } - - } - - // REPEATE START - if( rw == I2C_SMBUS_READ && ( - size == I2C_SMBUS_BYTE_DATA || - size == I2C_SMBUS_WORD_DATA || - size == I2C_SMBUS_BLOCK_DATA || - size == I2C_SMBUS_I2C_BLOCK_DATA - )){ - info( "MS Repeated Start"); - - SET_REG_BIT_L(pci_bar+REG_CR0,I2C_CR_BIT_MEN); - iowrite8(1 << I2C_CR_BIT_MIEN | - 1 << I2C_CR_BIT_MTX | - 1 << I2C_CR_BIT_MSTA | - 1 << I2C_CR_BIT_RSTA ,pci_bar+REG_CR0); - SET_REG_BIT_H(pci_bar+REG_CR0,I2C_CR_BIT_MEN); - - // sent Address with Read mode - iowrite8( addr<<1 | 0x1 ,pci_bar+REG_DR0); - - // Wait {A} - error = i2c_wait_ack(adapter,12,1); - if(error<0){ - goto Done; - } - - } - - if( rw == I2C_SMBUS_READ && ( + // [DATA]{A} + if ( rw == I2C_SMBUS_WRITE && ( size == I2C_SMBUS_BYTE || size == I2C_SMBUS_BYTE_DATA || size == I2C_SMBUS_WORD_DATA || size == I2C_SMBUS_BLOCK_DATA || size == I2C_SMBUS_I2C_BLOCK_DATA - )){ + )) { + bid = 0; + info( "MS prepare to sent [%d bytes]", cnt); + if (size == I2C_SMBUS_BLOCK_DATA || size == I2C_SMBUS_I2C_BLOCK_DATA) { + bid = 1; // block[0] is cnt; + cnt += 1; // offset from block[0] + } + for (; bid < cnt; bid++) { - switch(size){ - case I2C_SMBUS_BYTE: - case I2C_SMBUS_BYTE_DATA: - cnt = 1; break; - case I2C_SMBUS_WORD_DATA: - cnt = 2; break; - case I2C_SMBUS_BLOCK_DATA: - // will be changed after recived first data - cnt = 3; break; - case I2C_SMBUS_I2C_BLOCK_DATA: - cnt = data->block[0]; break; - default: - cnt = 0; break; - } - - bid = 0; - info( "MS Receive"); - - //set to Receive mode - iowrite8(1 << I2C_CR_BIT_MEN | - 1 << I2C_CR_BIT_MIEN | - 1 << I2C_CR_BIT_MSTA , pci_bar+REG_CR0); - - for(bid=-1;bidblock[bid+1] = ioread8(pci_bar+REG_DR0); - }else { - data->block[bid] = ioread8(pci_bar+REG_DR0); - } - info( "DATA IN [%d] %2.2X",bid,data->block[bid]); - - if(size == I2C_SMBUS_BLOCK_DATA && bid == 0){ - cnt = data->block[0] + 1; - } - } + iowrite8(data->block[bid], pci_bar + REG_DR0); + info( " Data > %2.2X", data->block[bid]); + // Wait {A} + error = i2c_wait_ack(adapter, 12, 1); + if (error < 0) { + goto Done; } } - // [P] - SET_REG_BIT_L(pci_bar+REG_CR0,I2C_CR_BIT_MSTA); - info( "MS STOP"); + } + + // REPEATE START + if ( rw == I2C_SMBUS_READ && ( + size == I2C_SMBUS_BYTE_DATA || + size == I2C_SMBUS_WORD_DATA || + size == I2C_SMBUS_BLOCK_DATA || + size == I2C_SMBUS_I2C_BLOCK_DATA + )) { + info( "MS Repeated Start"); + + SET_REG_BIT_L(pci_bar + REG_CR0, I2C_CR_BIT_MEN); + iowrite8(1 << I2C_CR_BIT_MIEN | + 1 << I2C_CR_BIT_MTX | + 1 << I2C_CR_BIT_MSTA | + 1 << I2C_CR_BIT_RSTA , pci_bar + REG_CR0); + SET_REG_BIT_H(pci_bar + REG_CR0, I2C_CR_BIT_MEN); + + // sent Address with Read mode + iowrite8( addr << 1 | 0x1 , pci_bar + REG_DR0); + + // Wait {A} + error = i2c_wait_ack(adapter, 12, 1); + if (error < 0) { + goto Done; + } + + } + + if ( rw == I2C_SMBUS_READ && ( + size == I2C_SMBUS_BYTE || + size == I2C_SMBUS_BYTE_DATA || + size == I2C_SMBUS_WORD_DATA || + size == I2C_SMBUS_BLOCK_DATA || + size == I2C_SMBUS_I2C_BLOCK_DATA + )) { + + switch (size) { + case I2C_SMBUS_BYTE: + case I2C_SMBUS_BYTE_DATA: + cnt = 1; break; + case I2C_SMBUS_WORD_DATA: + cnt = 2; break; + case I2C_SMBUS_BLOCK_DATA: + // will be changed after recived first data + cnt = 3; break; + case I2C_SMBUS_I2C_BLOCK_DATA: + cnt = data->block[0]; break; + default: + cnt = 0; break; + } + + bid = 0; + info( "MS Receive"); + + //set to Receive mode + iowrite8(1 << I2C_CR_BIT_MEN | + 1 << I2C_CR_BIT_MIEN | + 1 << I2C_CR_BIT_MSTA , pci_bar + REG_CR0); + + for (bid = -1; bid < cnt; bid++) { + + // Wait for byte transfer + error = i2c_wait_ack(adapter, 12, 0); + if (error < 0) { + goto Done; + } + + if (bid == cnt - 2) { + info( "SET NAK"); + SET_REG_BIT_H(pci_bar + REG_CR0, I2C_CR_BIT_TXAK); + } + + if (bid < 0) { + ioread8(pci_bar + REG_DR0); + info( "READ Dummy Byte" ); + } else { + + if (bid == cnt - 1) { + info ( "SET STOP in read loop"); + SET_REG_BIT_L(pci_bar + REG_CR0, I2C_CR_BIT_MSTA); + } + if (size == I2C_SMBUS_I2C_BLOCK_DATA) { + // block[0] is read length + data->block[bid + 1] = ioread8(pci_bar + REG_DR0); + } else { + data->block[bid] = ioread8(pci_bar + REG_DR0); + } + info( "DATA IN [%d] %2.2X", bid, data->block[bid]); + + if (size == I2C_SMBUS_BLOCK_DATA && bid == 0) { + cnt = data->block[0] + 1; + } + } + } + } + + // [P] + SET_REG_BIT_L(pci_bar + REG_CR0, I2C_CR_BIT_MSTA); + info( "MS STOP"); Done: - iowrite8(1<= 0){ + while (retry--) { + error = smbus_access(adapter, (u16)(prev_switch), flags, + I2C_SMBUS_WRITE, 0x00, + I2C_SMBUS_BYTE, NULL); + if (error >= 0) { break; - }else{ - dev_dbg(&adapter->dev,"Failed to deselect ch %d of 0x%x, CODE %d\n", prev_ch, prev_switch, error); + } else { + dev_dbg(&adapter->dev, + "Failed to deselect ch %d of 0x%x, CODE %d\n", + prev_ch, prev_switch, error); } } - if(retry < 0){ + if (retry < 0) { goto release_unlock; } // set PCA9548 to current channel retry = 3; - while(retry--){ - error = smbus_access(adapter, switch_addr, flags, I2C_SMBUS_WRITE, 1 << channel, I2C_SMBUS_BYTE, NULL); - if(error >= 0){ + while (retry--) { + error = smbus_access(adapter, switch_addr, flags, + I2C_SMBUS_WRITE, 1 << channel, + I2C_SMBUS_BYTE, NULL); + if (error >= 0) { break; - }else{ - dev_dbg(&adapter->dev,"Failed to deselect ch %d of 0x%x, CODE %d\n", prev_ch, prev_switch, error); + } else { + dev_dbg(&adapter->dev, + "Failed to deselect ch %d of 0x%x, CODE %d\n", + prev_ch, prev_switch, error); } } - if(retry < 0){ + if (retry < 0) { goto release_unlock; } // update lasted port @@ -1473,41 +1767,47 @@ static int fpga_i2c_access(struct i2c_adapter *adapter, u16 addr, if ( prev_ch != channel || prev_switch == 0 ) { // set new PCA9548 at switch_addr to current retry = 3; - while(retry--){ - error = smbus_access(adapter, switch_addr, flags, I2C_SMBUS_WRITE, 1 << channel, I2C_SMBUS_BYTE, NULL); - if(error >= 0){ + while (retry--) { + error = smbus_access(adapter, switch_addr, flags, + I2C_SMBUS_WRITE, 1 << channel, + I2C_SMBUS_BYTE, NULL); + if (error >= 0) { break; - }else{ - dev_dbg(&adapter->dev,"Failed to deselect ch %d of 0x%x, CODE %d\n", prev_ch, prev_switch, error); + } else { + dev_dbg(&adapter->dev, + "Failed to deselect ch %d of 0x%x, CODE %d\n", + prev_ch, prev_switch, error); + } } - } - if(retry < 0){ - goto release_unlock; - } - // update lasted port - fpga_i2c_lasted_access_port[master_bus - 1] = switch_addr << 8 | channel; + if (retry < 0) { + goto release_unlock; + } + // update lasted port + fpga_i2c_lasted_access_port[master_bus - 1] = switch_addr << 8 | channel; } } } // Do SMBus communication error = smbus_access(adapter, addr, flags, rw, cmd, size, data); - if(error < 0){ - dev_dbg( &adapter->dev,"smbus_xfer failed (%d) @ 0x%2.2X|f 0x%4.4X|(%d)%-5s| (%d)%-10s|CMD %2.2X " - , error, addr, flags, rw, rw == 1 ? "READ " : "WRITE" - , size, size == 0 ? "QUICK" : - size == 1 ? "BYTE" : - size == 2 ? "BYTE_DATA" : - size == 3 ? "WORD_DATA" : - size == 4 ? "PROC_CALL" : - size == 5 ? "BLOCK_DATA" : - size == 8 ? "I2C_BLOCK_DATA" : "ERROR" - , cmd); + if (error < 0) { + dev_dbg( &adapter->dev, + "smbus_xfer failed (%d) @ 0x%2.2X|f 0x%4.4X|(%d)%-5s| (%d)%-10s|CMD %2.2X " + , error, addr, flags, rw, rw == 1 ? "READ " : "WRITE" + , size, size == 0 ? "QUICK" : + size == 1 ? "BYTE" : + size == 2 ? "BYTE_DATA" : + size == 3 ? "WORD_DATA" : + size == 4 ? "PROC_CALL" : + size == 5 ? "BLOCK_DATA" : + size == 8 ? "I2C_BLOCK_DATA" : "ERROR" + , cmd); } -release_unlock: +release_unlock: mutex_unlock(&fpga_i2c_master_locks[master_bus - 1]); - dev_dbg(&adapter->dev,"switch ch %d of 0x%x -> ch %d of 0x%x\n", prev_ch, prev_switch, channel, switch_addr); + dev_dbg(&adapter->dev, "switch ch %d of 0x%x -> ch %d of 0x%x\n", + prev_ch, prev_switch, channel, switch_addr); return error; } @@ -1519,11 +1819,11 @@ release_unlock: static u32 fpga_i2c_func(struct i2c_adapter *a) { return I2C_FUNC_SMBUS_QUICK | - I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_BLOCK_DATA| - I2C_FUNC_SMBUS_I2C_BLOCK; + I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA | + I2C_FUNC_SMBUS_I2C_BLOCK; } static const struct i2c_algorithm seastone2_i2c_algorithm = { @@ -1541,7 +1841,8 @@ static const struct i2c_algorithm seastone2_i2c_algorithm = { * When bus_number_offset is -1, created adapter with dynamic bus number. * Otherwise create adapter at i2c bus = bus_number_offset + portid. */ -static struct i2c_adapter * seastone2_i2c_init(struct platform_device *pdev, int portid, int bus_number_offset) +static struct i2c_adapter * seastone2_i2c_init(struct platform_device *pdev, + int portid, int bus_number_offset) { int error; struct i2c_adapter *new_adapter; @@ -1549,8 +1850,9 @@ static struct i2c_adapter * seastone2_i2c_init(struct platform_device *pdev, int void __iomem *i2c_freq_base_reg; new_adapter = kzalloc(sizeof(*new_adapter), GFP_KERNEL); - if (!new_adapter){ - printk(KERN_ALERT "Cannot alloc i2c adapter for %s", fpga_i2c_bus_dev[portid].calling_name); + if (!new_adapter) { + printk(KERN_ALERT "Cannot alloc i2c adapter for %s", + fpga_i2c_bus_dev[portid].calling_name); return NULL; } @@ -1558,15 +1860,16 @@ static struct i2c_adapter * seastone2_i2c_init(struct platform_device *pdev, int new_adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; new_adapter->algo = &seastone2_i2c_algorithm; /* If the bus offset is -1, use dynamic bus number */ - if (bus_number_offset == -1){ + if (bus_number_offset == -1) { new_adapter->nr = -1; - }else{ + } else { new_adapter->nr = bus_number_offset + portid; } new_data = kzalloc(sizeof(*new_data), GFP_KERNEL); - if (!new_data){ - printk(KERN_ALERT "Cannot alloc i2c data for %s", fpga_i2c_bus_dev[portid].calling_name); + if (!new_data) { + printk(KERN_ALERT "Cannot alloc i2c data for %s", + fpga_i2c_bus_dev[portid].calling_name); kzfree(new_adapter); return NULL; } @@ -1575,16 +1878,16 @@ static struct i2c_adapter * seastone2_i2c_init(struct platform_device *pdev, int new_data->pca9548.master_bus = fpga_i2c_bus_dev[portid].master_bus; new_data->pca9548.switch_addr = fpga_i2c_bus_dev[portid].switch_addr; new_data->pca9548.channel = fpga_i2c_bus_dev[portid].channel; - strcpy(new_data->pca9548.calling_name,fpga_i2c_bus_dev[portid].calling_name); + strcpy(new_data->pca9548.calling_name, fpga_i2c_bus_dev[portid].calling_name); snprintf(new_adapter->name, sizeof(new_adapter->name), - "SMBus I2C Adapter PortID: %s", new_data->pca9548.calling_name); + "SMBus I2C Adapter PortID: %s", new_data->pca9548.calling_name); - i2c_freq_base_reg = fpga_dev.data_base_addr+I2C_MASTER_FREQ_1; - iowrite8(0x07,i2c_freq_base_reg+(new_data->pca9548.master_bus-1)*0x100); // 0x07 400kHz - i2c_set_adapdata(new_adapter,new_data); + i2c_freq_base_reg = fpga_dev.data_base_addr + I2C_MASTER_FREQ_1; + iowrite8(0x07, i2c_freq_base_reg + (new_data->pca9548.master_bus - 1) * 0x100); // 0x07 400kHz + i2c_set_adapdata(new_adapter, new_data); error = i2c_add_numbered_adapter(new_adapter); - if(error < 0){ + if (error < 0) { printk(KERN_ALERT "Cannot add i2c adapter %s", new_data->pca9548.calling_name); kzfree(new_adapter); kzfree(new_data); @@ -1594,30 +1897,6 @@ static struct i2c_adapter * seastone2_i2c_init(struct platform_device *pdev, int return new_adapter; }; -// I/O resource need. -static struct resource seastone2_resources[] = { - { - .start = 0x10000000, - .end = 0x10001000, - .flags = IORESOURCE_MEM, - }, -}; - -static void seastone2_dev_release( struct device * dev) -{ - return; -} - -static struct platform_device seastone2_dev = { - .name = DRIVER_NAME, - .id = -1, - .num_resources = ARRAY_SIZE(seastone2_resources), - .resource = seastone2_resources, - .dev = { - .release = seastone2_dev_release, - } -}; - /** * Board info for QSFP/SFP+ eeprom. * Note: Using sff8436 as I2C eeprom driver. @@ -1629,7 +1908,6 @@ static struct i2c_board_info sff8436_eeprom_info[] = { static int seastone2_drv_probe(struct platform_device *pdev) { - struct resource *res; int ret = 0; int portid_count; uint8_t cpld1_version, cpld2_version; @@ -1640,30 +1918,24 @@ static int seastone2_drv_probe(struct platform_device *pdev) BUG_ON(fpgafwclass == NULL); fpga_data = devm_kzalloc(&pdev->dev, sizeof(struct seastone2_fpga_data), - GFP_KERNEL); + GFP_KERNEL); if (!fpga_data) return -ENOMEM; // Set default read address to VERSION - fpga_data->fpga_read_addr = fpga_dev.data_base_addr+FPGA_VERSION; + fpga_data->fpga_read_addr = fpga_dev.data_base_addr + FPGA_VERSION; fpga_data->cpld1_read_addr = 0x00; fpga_data->cpld2_read_addr = 0x00; mutex_init(&fpga_data->fpga_lock); - for(ret=I2C_MASTER_CH_1 ;ret <= I2C_MASTER_CH_TOTAL; ret++){ - mutex_init(&fpga_i2c_master_locks[ret-1]); - } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (unlikely(!res)) { - printk(KERN_ERR "Specified Resource Not Available...\n"); - kzfree(fpga_data); - return -1; + for (ret = I2C_MASTER_CH_1 ; ret <= I2C_MASTER_CH_TOTAL; ret++) { + mutex_init(&fpga_i2c_master_locks[ret - 1]); } fpga = kobject_create_and_add("FPGA", &pdev->dev.kobj); - if (!fpga){ + if (!fpga) { kzfree(fpga_data); return -ENOMEM; } @@ -1677,7 +1949,7 @@ static int seastone2_drv_probe(struct platform_device *pdev) } cpld1 = kobject_create_and_add("CPLD1", &pdev->dev.kobj); - if (!cpld1){ + if (!cpld1) { sysfs_remove_group(fpga, &fpga_attr_grp); kobject_put(fpga); kzfree(fpga_data); @@ -1694,7 +1966,7 @@ static int seastone2_drv_probe(struct platform_device *pdev) } cpld2 = kobject_create_and_add("CPLD2", &pdev->dev.kobj); - if (!cpld2){ + if (!cpld2) { sysfs_remove_group(cpld1, &cpld1_attr_grp); kobject_put(cpld1); sysfs_remove_group(fpga, &fpga_attr_grp); @@ -1714,8 +1986,8 @@ static int seastone2_drv_probe(struct platform_device *pdev) return ret; } - sff_dev = device_create(fpgafwclass, NULL, MKDEV(0,0), NULL, "sff_device"); - if (IS_ERR(sff_dev)){ + sff_dev = device_create(fpgafwclass, NULL, MKDEV(0, 0), NULL, "sff_device"); + if (IS_ERR(sff_dev)) { printk(KERN_ERR "Failed to create sff device\n"); sysfs_remove_group(cpld2, &cpld2_attr_grp); kobject_put(cpld2); @@ -1730,7 +2002,7 @@ static int seastone2_drv_probe(struct platform_device *pdev) ret = sysfs_create_group(&sff_dev->kobj, &sff_led_test_grp); if (ret != 0) { printk(KERN_ERR "Cannot create SFF attributes\n"); - device_destroy(fpgafwclass, MKDEV(0,0)); + device_destroy(fpgafwclass, MKDEV(0, 0)); sysfs_remove_group(cpld2, &cpld2_attr_grp); kobject_put(cpld2); sysfs_remove_group(cpld1, &cpld1_attr_grp); @@ -1741,10 +2013,10 @@ static int seastone2_drv_probe(struct platform_device *pdev) return ret; } - ret = sysfs_create_link(&pdev->dev.kobj,&sff_dev->kobj,"SFF"); - if (ret != 0){ + ret = sysfs_create_link(&pdev->dev.kobj, &sff_dev->kobj, "SFF"); + if (ret != 0) { sysfs_remove_group(&sff_dev->kobj, &sff_led_test_grp); - device_destroy(fpgafwclass, MKDEV(0,0)); + device_destroy(fpgafwclass, MKDEV(0, 0)); sysfs_remove_group(cpld2, &cpld2_attr_grp); kobject_put(cpld2); sysfs_remove_group(cpld1, &cpld1_attr_grp); @@ -1755,27 +2027,27 @@ static int seastone2_drv_probe(struct platform_device *pdev) return ret; } - for(portid_count=0 ; portid_count < VIRTUAL_I2C_PORT_LENGTH ; portid_count++){ + for (portid_count = 0 ; portid_count < VIRTUAL_I2C_PORT_LENGTH ; portid_count++) { fpga_data->i2c_adapter[portid_count] = seastone2_i2c_init(pdev, portid_count, VIRTUAL_I2C_BUS_OFFSET); } /* Init SFF devices */ - for(portid_count=0; portid_count < SFF_PORT_TOTAL; portid_count++){ + for (portid_count = 0; portid_count < SFF_PORT_TOTAL; portid_count++) { struct i2c_adapter *i2c_adap = fpga_data->i2c_adapter[portid_count]; - if(i2c_adap){ + if (i2c_adap) { fpga_data->sff_devices[portid_count] = seastone2_sff_init(portid_count); sff_data = dev_get_drvdata(fpga_data->sff_devices[portid_count]); BUG_ON(sff_data == NULL); - if( sff_data->port_type == QSFP ){ + if ( sff_data->port_type == QSFP ) { fpga_data->sff_i2c_clients[portid_count] = i2c_new_device(i2c_adap, &sff8436_eeprom_info[0]); - }else{ + } else { fpga_data->sff_i2c_clients[portid_count] = i2c_new_device(i2c_adap, &sff8436_eeprom_info[1]); } sff_data = NULL; sysfs_create_link(&fpga_data->sff_devices[portid_count]->kobj, - &fpga_data->sff_i2c_clients[portid_count]->dev.kobj, - "i2c"); + &fpga_data->sff_i2c_clients[portid_count]->dev.kobj, + "i2c"); } } @@ -1785,10 +2057,10 @@ static int seastone2_drv_probe(struct platform_device *pdev) #ifdef TEST_MODE return 0; #endif - fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX],CPLD1_SLAVE_ADDR,0x00, - I2C_SMBUS_READ,0x00,I2C_SMBUS_BYTE_DATA,(union i2c_smbus_data*)&cpld1_version); - fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX],CPLD2_SLAVE_ADDR,0x00, - I2C_SMBUS_READ,0x00,I2C_SMBUS_BYTE_DATA,(union i2c_smbus_data*)&cpld2_version); + fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, + I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&cpld1_version); + fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, + I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&cpld2_version); printk(KERN_INFO "CPLD1 VERSON: %2.2x\n", cpld1_version); printk(KERN_INFO "CPLD2 VERSON: %2.2x\n", cpld2_version); @@ -1809,7 +2081,7 @@ static int seastone2_drv_probe(struct platform_device *pdev) if (prev_i2c_switch != ( (master_bus << 8) | switch_addr) ) { // Found the bus with PCA9548, trying to clear all switch in it. smbus_access(fpga_data->i2c_adapter[portid_count], switch_addr, 0x00, - I2C_SMBUS_WRITE, 0x00, I2C_SMBUS_BYTE, NULL); + I2C_SMBUS_WRITE, 0x00, I2C_SMBUS_BYTE, NULL); prev_i2c_switch = ( master_bus << 8 ) | switch_addr; } } @@ -1822,20 +2094,20 @@ static int seastone2_drv_remove(struct platform_device *pdev) int portid_count; struct sff_device_data *rem_data; - for(portid_count=0; portid_count < SFF_PORT_TOTAL; portid_count++){ - sysfs_remove_link(&fpga_data->sff_devices[portid_count]->kobj,"i2c"); + for (portid_count = 0; portid_count < SFF_PORT_TOTAL; portid_count++) { + sysfs_remove_link(&fpga_data->sff_devices[portid_count]->kobj, "i2c"); i2c_unregister_device(fpga_data->sff_i2c_clients[portid_count]); } - for(portid_count=0 ; portid_count < VIRTUAL_I2C_PORT_LENGTH ; portid_count++){ - if(fpga_data->i2c_adapter[portid_count] != NULL){ - info(KERN_INFO "<%x>",fpga_data->i2c_adapter[portid_count]); + for (portid_count = 0 ; portid_count < VIRTUAL_I2C_PORT_LENGTH ; portid_count++) { + if (fpga_data->i2c_adapter[portid_count] != NULL) { + info(KERN_INFO "<%x>", fpga_data->i2c_adapter[portid_count]); i2c_del_adapter(fpga_data->i2c_adapter[portid_count]); } } - for (portid_count=0; portid_count < SFF_PORT_TOTAL; portid_count++){ - if(fpga_data->sff_devices[portid_count] != NULL){ + for (portid_count = 0; portid_count < SFF_PORT_TOTAL; portid_count++) { + if (fpga_data->sff_devices[portid_count] != NULL) { rem_data = dev_get_drvdata(fpga_data->sff_devices[portid_count]); device_unregister(fpga_data->sff_devices[portid_count]); put_device(fpga_data->sff_devices[portid_count]); @@ -1850,7 +2122,7 @@ static int seastone2_drv_remove(struct platform_device *pdev) kobject_put(fpga); kobject_put(cpld1); kobject_put(cpld2); - device_destroy(fpgafwclass, MKDEV(0,0)); + device_destroy(fpgafwclass, MKDEV(0, 0)); devm_kfree(&pdev->dev, fpga_data); return 0; } @@ -1864,9 +2136,9 @@ static struct platform_driver seastone2_drv = { }; #ifdef TEST_MODE - #define FPGA_PCI_BAR_NUM 2 +#define FPGA_PCI_BAR_NUM 2 #else - #define FPGA_PCI_BAR_NUM 0 +#define FPGA_PCI_BAR_NUM 0 #endif static const struct pci_device_id fpga_id_table[] = { @@ -1885,7 +2157,7 @@ static int fpga_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) if ((err = pci_enable_device(pdev))) { dev_err(dev, "pci_enable_device probe error %d for device %s\n", - err, pci_name(pdev)); + err, pci_name(pdev)); return err; } @@ -1900,28 +2172,32 @@ static int fpga_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) fpga_dev.data_base_addr = pci_iomap(pdev, FPGA_PCI_BAR_NUM, 0); if (!fpga_dev.data_base_addr) { dev_err(dev, "cannot iomap region of size %lu\n", - (unsigned long)fpga_dev.data_mmio_len); + (unsigned long)fpga_dev.data_mmio_len); goto pci_release; } dev_info(dev, "data_mmio iomap base = 0x%lx \n", - (unsigned long)fpga_dev.data_base_addr); + (unsigned long)fpga_dev.data_base_addr); dev_info(dev, "data_mmio_start = 0x%lx data_mmio_len = %lu\n", - (unsigned long)fpga_dev.data_mmio_start, - (unsigned long)fpga_dev.data_mmio_len); + (unsigned long)fpga_dev.data_mmio_start, + (unsigned long)fpga_dev.data_mmio_len); printk(KERN_INFO "FPGA PCIe driver probe OK.\n"); - printk(KERN_INFO "FPGA ioremap registers of size %lu\n",(unsigned long)fpga_dev.data_mmio_len); + printk(KERN_INFO "FPGA ioremap registers of size %lu\n", (unsigned long)fpga_dev.data_mmio_len); printk(KERN_INFO "FPGA Virtual BAR %d at %8.8lx - %8.8lx\n", FPGA_PCI_BAR_NUM, - (unsigned long)fpga_dev.data_base_addr, - (unsigned long)(fpga_dev.data_base_addr + fpga_dev.data_mmio_len)); + (unsigned long)fpga_dev.data_base_addr, + (unsigned long)(fpga_dev.data_base_addr + fpga_dev.data_mmio_len)); printk(KERN_INFO ""); fpga_version = ioread32(fpga_dev.data_base_addr); printk(KERN_INFO "FPGA VERSION : %8.8x\n", fpga_version); - fpgafw_init(); - platform_device_register(&seastone2_dev); + if ((err = fpgafw_init()) < 0) { + goto pci_unmap; + } + seastone2_dev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0); platform_driver_register(&seastone2_drv); return 0; +pci_unmap: + pci_iounmap(pdev, fpga_dev.data_base_addr); pci_release: pci_release_regions(pdev); pci_disable: @@ -1932,7 +2208,7 @@ pci_disable: static void fpga_pci_remove(struct pci_dev *pdev) { platform_driver_unregister(&seastone2_drv); - platform_device_unregister(&seastone2_dev); + platform_device_unregister(seastone2_dev); fpgafw_exit(); pci_iounmap(pdev, fpga_dev.data_base_addr); pci_release_regions(pdev); @@ -1947,7 +2223,7 @@ static struct pci_driver pci_dev_ops = { .id_table = fpga_id_table, }; -enum{ +enum { READREG, WRITEREG }; @@ -1957,7 +2233,8 @@ struct fpga_reg_data { uint32_t value; }; -static long fpgafw_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg){ +static long fpgafw_unlocked_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { int ret = 0; struct fpga_reg_data data; mutex_lock(&fpga_data->fpga_lock); @@ -1966,55 +2243,55 @@ static long fpgafw_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned static uint32_t status_reg; #endif // Switch function to read and write. - switch (cmd){ - case READREG: - if (copy_from_user(&data, (void __user*)arg, sizeof(data)) != 0){ - mutex_unlock(&fpga_data->fpga_lock); - return -EFAULT; - } - data.value = ioread32(fpga_dev.data_base_addr+data.addr); - if (copy_to_user((void __user*)arg ,&data, sizeof(data)) != 0){ - mutex_unlock(&fpga_data->fpga_lock); - return -EFAULT; - } -#ifdef TEST_MODE - if(data.addr == 0x1210){ - switch (status_reg){ - case 0x0000 : status_reg=0x8000; - break; - - case 0x8080 : status_reg=0x80C0; - break; - case 0x80C0 : status_reg=0x80F0; - break; - case 0x80F0 : status_reg=0x80F8; - break; - - } - iowrite32(status_reg,fpga_dev.data_base_addr+0x1210); - } -#endif - - - break; - case WRITEREG: - if (copy_from_user(&data, (void __user*)arg, sizeof(data)) != 0){ - mutex_unlock(&fpga_data->fpga_lock); - return -EFAULT; - } - iowrite32(data.value,fpga_dev.data_base_addr+data.addr); - -#ifdef TEST_MODE - if(data.addr == 0x1204){ - status_reg=0x8080; - iowrite32(status_reg,fpga_dev.data_base_addr+0x1210); - } -#endif - - break; - default: + switch (cmd) { + case READREG: + if (copy_from_user(&data, (void __user*)arg, sizeof(data)) != 0) { mutex_unlock(&fpga_data->fpga_lock); - return -EINVAL; + return -EFAULT; + } + data.value = ioread32(fpga_dev.data_base_addr + data.addr); + if (copy_to_user((void __user*)arg , &data, sizeof(data)) != 0) { + mutex_unlock(&fpga_data->fpga_lock); + return -EFAULT; + } +#ifdef TEST_MODE + if (data.addr == 0x1210) { + switch (status_reg) { + case 0x0000 : status_reg = 0x8000; + break; + + case 0x8080 : status_reg = 0x80C0; + break; + case 0x80C0 : status_reg = 0x80F0; + break; + case 0x80F0 : status_reg = 0x80F8; + break; + + } + iowrite32(status_reg, fpga_dev.data_base_addr + 0x1210); + } +#endif + + + break; + case WRITEREG: + if (copy_from_user(&data, (void __user*)arg, sizeof(data)) != 0) { + mutex_unlock(&fpga_data->fpga_lock); + return -EFAULT; + } + iowrite32(data.value, fpga_dev.data_base_addr + data.addr); + +#ifdef TEST_MODE + if (data.addr == 0x1204) { + status_reg = 0x8080; + iowrite32(status_reg, fpga_dev.data_base_addr + 0x1210); + } +#endif + + break; + default: + mutex_unlock(&fpga_data->fpga_lock); + return -EINVAL; } mutex_unlock(&fpga_data->fpga_lock); return ret; @@ -2027,50 +2304,49 @@ const struct file_operations fpgafw_fops = { }; -static int fpgafw_init(void){ - printk(KERN_INFO "Initializing the switchboard driver\n"); - // Try to dynamically allocate a major number for the device -- more difficult but worth it - majorNumber = register_chrdev(0, DEVICE_NAME, &fpgafw_fops); - if (majorNumber<0){ - printk(KERN_ALERT "Failed to register a major number\n"); - return majorNumber; - } - printk(KERN_INFO "Device registered correctly with major number %d\n", majorNumber); +static int fpgafw_init(void) { + printk(KERN_INFO "Initializing the switchboard driver\n"); + // Try to dynamically allocate a major number for the device -- more difficult but worth it + majorNumber = register_chrdev(0, DEVICE_NAME, &fpgafw_fops); + if (majorNumber < 0) { + printk(KERN_ALERT "Failed to register a major number\n"); + return majorNumber; + } + printk(KERN_INFO "Device registered correctly with major number %d\n", majorNumber); - // Register the device class - fpgafwclass = class_create(THIS_MODULE, CLASS_NAME); - if (IS_ERR(fpgafwclass)){ // Check for error and clean up if there is - unregister_chrdev(majorNumber, DEVICE_NAME); - printk(KERN_ALERT "Failed to register device class\n"); - return PTR_ERR(fpgafwclass); // Correct way to return an error on a pointer - } - printk(KERN_INFO "Device class registered correctly\n"); + // Register the device class + fpgafwclass = class_create(THIS_MODULE, CLASS_NAME); + if (IS_ERR(fpgafwclass)) { // Check for error and clean up if there is + unregister_chrdev(majorNumber, DEVICE_NAME); + printk(KERN_ALERT "Failed to register device class\n"); + return PTR_ERR(fpgafwclass); + } + printk(KERN_INFO "Device class registered correctly\n"); - // Register the device driver - fpgafwdev = device_create(fpgafwclass, NULL, MKDEV(majorNumber, 0), NULL, DEVICE_NAME); - if (IS_ERR(fpgafwdev)){ // Clean up if there is an error - class_destroy(fpgafwclass); // Repeated code but the alternative is goto statements - unregister_chrdev(majorNumber, DEVICE_NAME); - printk(KERN_ALERT "Failed to create the FW upgrade device node\n"); - return PTR_ERR(fpgafwdev); - } - printk(KERN_INFO "FPGA fw upgrade device node created correctly\n"); // Made it! device was initialized - return 0; + // Register the device driver + fpgafwdev = device_create(fpgafwclass, NULL, MKDEV(majorNumber, 0), NULL, DEVICE_NAME); + if (IS_ERR(fpgafwdev)) { // Clean up if there is an error + class_destroy(fpgafwclass); // Repeated code but the alternative is goto statements + unregister_chrdev(majorNumber, DEVICE_NAME); + printk(KERN_ALERT "Failed to create the FW upgrade device node\n"); + return PTR_ERR(fpgafwdev); + } + printk(KERN_INFO "FPGA fw upgrade device node created correctly\n"); // Made it! device was initialized + return 0; } -static void fpgafw_exit(void){ - device_destroy(fpgafwclass, MKDEV(majorNumber, 0)); // remove the device - class_unregister(fpgafwclass); // unregister the device class - class_destroy(fpgafwclass); // remove the device class - unregister_chrdev(majorNumber, DEVICE_NAME); // unregister the major number - printk(KERN_INFO "Goodbye!\n"); +static void fpgafw_exit(void) { + device_destroy(fpgafwclass, MKDEV(majorNumber, 0)); // remove the device + class_destroy(fpgafwclass); // remove the device class + unregister_chrdev(majorNumber, DEVICE_NAME); // unregister the major number + printk(KERN_INFO "Goodbye!\n"); } int seastone2_init(void) { int rc; rc = pci_register_driver(&pci_dev_ops); - if(rc) + if (rc) return rc; return 0; } @@ -2083,7 +2359,7 @@ void seastone2_exit(void) module_init(seastone2_init); module_exit(seastone2_exit); -MODULE_AUTHOR("Pradchaya P. pphuhcar@celestica.com"); -MODULE_DESCRIPTION("Celestica seastone2 platform driver"); +MODULE_AUTHOR("Pradchaya P. "); +MODULE_DESCRIPTION("Celestica Seastone2 switchboard driver"); MODULE_VERSION(MOD_VERSION); MODULE_LICENSE("GPL"); \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/services/platform_api/setup.py b/platform/broadcom/sonic-platform-modules-cel/services/platform_api/setup.py new file mode 100755 index 0000000000..b0c8d1d8c9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/services/platform_api/setup.py @@ -0,0 +1,30 @@ +from setuptools import setup + +setup( + name='sonic-platform', + version='1.0', + description='SONiC platform API implementation on Celestica Platforms', + license='Apache 2.0', + author='SONiC Team', + author_email='linuxnetdev@microsoft.com', + url='https://github.com/Azure/sonic-buildimage', + maintainer='Wirut Getbamrung', + maintainer_email='wgetbumr@celestica.com', + 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 :: 2.7', + 'Topic :: Utilities', + ], + keywords='sonic SONiC platform PLATFORM', +) + diff --git a/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/__init__.py b/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/__init__.py new file mode 100644 index 0000000000..7b86fa12b5 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/__init__.py @@ -0,0 +1,2 @@ +import chassis +import platform diff --git a/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/chassis.py new file mode 100644 index 0000000000..41eff73440 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/chassis.py @@ -0,0 +1,325 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Chassis information which are available in the platform +# +############################################################################# + +try: + import sys + from sonic_platform_base.chassis_base import ChassisBase + from common import Common +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Chassis(ChassisBase): + """Platform-specific Chassis class""" + + CHASSIS_CONFIG = 'chassis.json' + THERMAL_CONFIG = 'thermal.json' + SFP_CONFIG = 'sfp.json' + PSU_CONFIG = 'psu.json' + FAN_CONFIG = 'fan.json' + COMPONENT_CONFIG = 'component.json' + + def __init__(self): + ChassisBase.__init__(self) + self._api_common = Common() + config_path = self._api_common.get_config_path(self.CHASSIS_CONFIG) + self._config = self._api_common.load_json_file(config_path) + + self.sfp_module_initialized = False + self.__initialize_eeprom() + + if not self._api_common.is_host(): + self.__initialize_fan() + self.__initialize_psu() + self.__initialize_thermals() + else: + self.__initialize_components() + + def __initialize_fan(self): + from sonic_platform.fan import Fan + from sonic_platform.fan_drawer import FanDrawer + + fan_config_path = self._api_common.get_config_path(self.FAN_CONFIG) + self._fan_config = self._api_common.load_json_file(fan_config_path) + + if self._fan_config: + fan_index = 0 + for drawer_index in range(0, self._fan_config['drawer_num']): + drawer_fan_list = [] + for index in range(0, self._fan_config['fan_num_per_drawer']): + fan = Fan(fan_index, conf=self._fan_config) + fan_index += 1 + self._fan_list.append(fan) + drawer_fan_list.append(fan) + fan_drawer = FanDrawer(drawer_index, drawer_fan_list) + self._fan_drawer_list.append(fan_drawer) + + def __initialize_sfp(self): + from sonic_platform.sfp import Sfp + + sfp_config_path = self._api_common.get_config_path(self.SFP_CONFIG) + sfp_config = self._api_common.load_json_file(sfp_config_path) + + sfp_index = 0 + for index in range(0, sfp_config['port_num']): + sfp = Sfp(sfp_index, conf=sfp_config) + self._sfp_list.append(sfp) + sfp_index += 1 + self.sfp_module_initialized = True + + def __initialize_psu(self): + from sonic_platform.psu import Psu + + psu_config_path = self._api_common.get_config_path(self.PSU_CONFIG) + psu_config = self._api_common.load_json_file(psu_config_path) + + if psu_config: + psu_index = 0 + for index in range(0, psu_config['psu_num']): + psu = Psu(psu_index, conf=psu_config, + fan_conf=self._fan_config) + psu_index += 1 + self._psu_list.append(psu) + + def __initialize_thermals(self): + from sonic_platform.thermal import Thermal + + thermal_config_path = self._api_common.get_config_path( + self.THERMAL_CONFIG) + thermal_config = self._api_common.load_json_file(thermal_config_path) + + thermal_index = 0 + for index in range(0, thermal_config['thermal_num']): + thermal = Thermal(thermal_index, conf=thermal_config) + thermal_index += 1 + self._thermal_list.append(thermal) + + def __initialize_eeprom(self): + from sonic_platform.eeprom import Tlv + self._eeprom = Tlv(self._config) + + def __initialize_components(self): + from component import Component + + component_config_path = self._api_common.get_config_path( + self.COMPONENT_CONFIG) + component_config = self._api_common.load_json_file( + component_config_path) + + for index in range(0, component_config['component_num']): + component = Component(index, conf=component_config) + self._component_list.append(component) + + 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. + + Avaliable reboot cause: + REBOOT_CAUSE_POWER_LOSS = "Power Loss" + REBOOT_CAUSE_THERMAL_OVERLOAD_CPU = "Thermal Overload: CPU" + REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC = "Thermal Overload: ASIC" + REBOOT_CAUSE_THERMAL_OVERLOAD_OTHER = "Thermal Overload: Other" + REBOOT_CAUSE_INSUFFICIENT_FAN_SPEED = "Insufficient Fan Speed" + REBOOT_CAUSE_WATCHDOG = "Watchdog" + REBOOT_CAUSE_HARDWARE_OTHER = "Hardware - Other" + REBOOT_CAUSE_NON_HARDWARE = "Non-Hardware" + + """ + reboot_cause = self._api_common.get_output( + 0, self._config['get_reboot_cause'], self.REBOOT_CAUSE_HARDWARE_OTHER) + description = self._api_common.get_output( + 0, self._config['get_reboot_description'], 'Unknown') + + return (reboot_cause, description) + + # ############################################################## + # ######################## SFP methods ######################### + # ############################################################## + + def get_num_sfps(self): + """ + Retrieves the number of sfps available on this chassis + Returns: + An integer, the number of sfps available on this chassis + """ + if not self.sfp_module_initialized: + self.__initialize_sfp() + + return len(self._sfp_list) + + def get_all_sfps(self): + """ + Retrieves all sfps available on this chassis + Returns: + A list of objects derived from SfpBase representing all sfps + available on this chassis + """ + if not self.sfp_module_initialized: + self.__initialize_sfp() + + return self._sfp_list + + 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 + + ############################################################## + ###################### Event methods ######################### + ############################################################## + + def get_change_event(self, timeout=0): + """ + Returns a nested dictionary containing all devices which have + experienced a change at chassis level + Args: + timeout: Timeout in milliseconds (optional). If timeout == 0, + this method will block until a change is detected. + Returns: + (bool, dict): + - True if call successful, False if not; + - A nested dictionary where key is a device type, + value is a dictionary with key:value pairs in the format of + {'device_id':'device_event'}, + where device_id is the device ID for this device and + device_event, + status='1' represents device inserted, + status='0' represents device removed. + Ex. {'fan':{'0':'0', '2':'1'}, 'sfp':{'11':'0'}} + indicates that fan 0 has been removed, fan 2 + has been inserted and sfp 11 has been removed. + Specifically for SFP event, besides SFP plug in and plug out, + there are some other error event could be raised from SFP, when + these error happened, SFP eeprom will not be avalaible, XCVRD shall + stop to read eeprom before SFP recovered from error status. + status='2' I2C bus stuck, + status='3' Bad eeprom, + status='4' Unsupported cable, + status='5' High Temperature, + status='6' Bad cable. + """ + + if not self.sfp_module_initialized: + self.__initialize_sfp() + + return self._api_common.get_event(timeout, self._config['get_change_event'], self._sfp_list) + + # ############################################################## + # ###################### Other methods ######################## + # ############################################################## + + def get_watchdog(self): + """ + Retreives hardware watchdog device on this chassis + Returns: + An object derived from WatchdogBase representing the hardware + watchdog device + """ + if self._watchdog is None: + wdt = self._api_common.get_output( + 0, self._config['get_watchdog'], None) + self._watchdog = wdt() + + return self._watchdog + + # ############################################################## + # ###################### Device methods ######################## + # ############################################################## + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return self._api_common.hwsku + + def get_presence(self): + """ + Retrieves the presence of the PSU + Returns: + bool: True if PSU 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 self._eeprom.get_pn() + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return self._eeprom.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 True diff --git a/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/common.py b/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/common.py new file mode 100644 index 0000000000..697308b8c3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/common.py @@ -0,0 +1,283 @@ +import os +import imp +import yaml +import subprocess + +from sonic_py_common import device_info + + +class Common: + + DEVICE_PATH = '/usr/share/sonic/device/' + PMON_PLATFORM_PATH = '/usr/share/sonic/platform/' + CONFIG_DIR = 'sonic_platform_config' + + OUTPUT_SOURCE_IPMI = 'ipmitool' + OUTPUT_SOURCE_GIVEN_LIST = 'value_list' + OUTPUT_SOURCE_GIVEN_VALUE = 'value' + OUTPUT_SOURCE_GIVEN_CLASS = 'class' + OUTPUT_SOURCE_SYSFS = 'sysfs_value' + OUTPUT_SOURCE_FUNC = 'function' + OUTPUT_SOURCE_GIVEN_TXT_FILE = 'txt_file' + OUTPUT_SOURCE_GIVEN_VER_HEX_FILE = 'hex_version_file' + OUTPUT_SOURCE_GIVEN_VER_HEX_ADDR = 'hex_version_getreg' + + SET_METHOD_IPMI = 'ipmitool' + NULL_VAL = 'N/A' + HOST_CHK_CMD = "docker > /dev/null 2>&1" + REF_KEY = '$ref:' + + def __init__(self, conf=None): + self._main_conf = conf + (self.platform, self.hwsku) = device_info.get_platform_and_hwsku() + + def _run_command(self, command): + status = False + output = "" + try: + p = subprocess.Popen( + command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + status, output = True, raw_data.strip() + except Exception: + pass + return status, output + + def _clean_input(self, input, config): + cleaned_input = input + + ai = config.get('avaliable_input') + if ai and input not in ai: + return None + + input_translator = config.get('input_translator') + if type(input_translator) is dict: + cleaned_input = input_translator.get(input) + + elif type(input_translator) is str: + cleaned_input = eval(input_translator.format(input)) + + return cleaned_input + + def _clean_output(self, index, output, config): + output_translator = config.get('output_translator') + + if type(output_translator) is dict: + output = output_translator.get(output) + elif type(output_translator) is str: + output = eval(output_translator.format(output)) + elif type(output_translator) is list: + output = eval(output_translator[index].format(output)) + + return output + + def _ipmi_get(self, index, config): + argument = config.get('argument') + cmd = config['command'].format( + config['argument'][index]) if argument else config['command'] + status, output = self._run_command(cmd) + return output if status else None + + def _sysfs_read(self, index, config): + sysfs_path = config.get('sysfs_path') + argument = config.get('argument', '') + + if self.REF_KEY in argument: + argument = self._main_conf[argument.split(":")[1]] + + if type(argument) is list: + sysfs_path = sysfs_path.format(argument[index]) + + content = "" + try: + content = open(sysfs_path) + content = content.readline().rstrip() + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + return content + + def _sysfs_write(self, index, config, input): + sysfs_path = config.get('sysfs_path') + argument = config.get('argument', '') + + if self.REF_KEY in argument: + argument = self._main_conf[argument.split(":")[1]] + + if type(argument) is list: + sysfs_path = sysfs_path.format(argument[index]) + + write_offset = int(config.get('write_offset', 0)) + output = "" + try: + open_file = open(sysfs_path, "r+") + open_file.seek(write_offset) + open_file.write(input) + open_file.close() + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False, output + return True, output + + def _ipmi_set(self, index, config, input): + arg = config['argument'][index].format(input) + return self._run_command(config['command'].format(arg)) + + def _hex_ver_decode(self, hver, num_of_bits, num_of_points): + ver_list = [] + c_bit = 0 + bin_val = bin(int(hver, 16))[2:].zfill(num_of_bits) + bit_split = num_of_bits / (num_of_points + 1) + for x in range(0, num_of_points+1): + split_bin = bin_val[c_bit:c_bit+bit_split] + ver_list.append(str(int(split_bin, 2))) + c_bit += bit_split + return '.'.join(ver_list) + + def _get_class(self, config): + """ + Retreives value of expected attribute + Returns: + A value of the attribute of object + """ + path = config['host_path'] if self.is_host() else config['pmon_path'] + module = imp.load_source(config['class'], path) + class_ = getattr(module, config['class']) + return class_ + + def get_reg(self, path, reg_addr): + cmd = "echo {1} > {0}; cat {0}".format(path, reg_addr) + status, output = self._run_command(cmd) + return output if status else None + + def read_txt_file(self, path): + with open(path, 'r') as f: + output = f.readline() + return output.strip('\n') + + def write_txt_file(self, file_path, value): + try: + with open(file_path, 'w') as fd: + fd.write(str(value)) + except Exception: + return False + return True + + def is_host(self): + return os.system(self.HOST_CHK_CMD) == 0 + + def load_json_file(self, path): + """ + Retrieves the json object from json file path + + Returns: + A json object + """ + with open(path, 'r') as f: + json_data = yaml.safe_load(f) + + return json_data + + def get_config_path(self, config_name): + """ + Retrieves the path to platform api config directory + + Args: + config_name: A string containing the name of config file. + + Returns: + A string containing the path to json file + """ + return os.path.join(self.DEVICE_PATH, self.platform, self.CONFIG_DIR, config_name) if self.is_host() else os.path.join(self.PMON_PLATFORM_PATH, self.CONFIG_DIR, config_name) + + def get_output(self, index, config, default): + """ + Retrieves the output for each function base on config + + Args: + index: An integer containing the index of device. + config: A dict object containing the configuration of specified function. + default: A string containing the default output of specified function. + + Returns: + A string containing the output of specified function in config + """ + output_source = config.get('output_source') + + if output_source == self.OUTPUT_SOURCE_IPMI: + output = self._ipmi_get(index, config) + + elif output_source == self.OUTPUT_SOURCE_GIVEN_VALUE: + output = config["value"] + + elif output_source == self.OUTPUT_SOURCE_GIVEN_CLASS: + output = self._get_class(config) + + elif output_source == self.OUTPUT_SOURCE_GIVEN_LIST: + output = config["value_list"][index] + + elif output_source == self.OUTPUT_SOURCE_SYSFS: + output = self._sysfs_read(index, config) + + elif output_source == self.OUTPUT_SOURCE_FUNC: + func_conf = self._main_conf[config['function'][index]] + output = self.get_output(index, func_conf, default) + + elif output_source == self.OUTPUT_SOURCE_GIVEN_TXT_FILE: + path = config.get('path') + output = self.read_txt_file(path) + + elif output_source == self.OUTPUT_SOURCE_GIVEN_VER_HEX_FILE: + path = config.get('path') + hex_ver = self.read_txt_file(path) + output = self._hex_ver_decode( + hex_ver, config['num_of_bits'], config['num_of_points']) + + elif output_source == self.OUTPUT_SOURCE_GIVEN_VER_HEX_ADDR: + path = config.get('path') + addr = config.get('reg_addr') + hex_ver = self.get_reg(path, addr) + output = self._hex_ver_decode( + hex_ver, config['num_of_bits'], config['num_of_points']) + + else: + output = default + + return self._clean_output(index, output, config) or default + + def set_output(self, index, input, config): + """ + Sets the output of specified function on config + + Args: + config: A dict object containing the configuration of specified function. + index: An integer containing the index of device. + input: A string containing the input of specified function. + + Returns: + bool: True if set function is successfully, False if not + """ + cleaned_input = self._clean_input(input, config) + if not cleaned_input: + return False + + set_method = config.get('set_method') + if set_method == self.SET_METHOD_IPMI: + output = self._ipmi_set(index, config, cleaned_input)[0] + elif set_method == self.OUTPUT_SOURCE_SYSFS: + output = self._sysfs_write(index, config, cleaned_input)[0] + else: + output = False + + return output + + def get_event(self, timeout, config, sfp_list): + """ + Returns a nested dictionary containing all devices which have + experienced a change at chassis level + + """ + event_class = self._get_class(config) + return event_class(sfp_list).get_event(timeout) diff --git a/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/component.py b/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/component.py new file mode 100644 index 0000000000..958b346232 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/component.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica +# +# Component contains an implementation of SONiC Platform Base API and +# provides the components firmware management function +# +############################################################################# + +try: + from sonic_platform_base.component_base import ComponentBase + from common import Common +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Component(ComponentBase): + """Platform-specific Component class""" + + def __init__(self, component_index, conf): + ComponentBase.__init__(self) + + self._index = component_index + self._config = conf + self._api_common = Common(self._config) + + def get_name(self): + """ + Retrieves the name of the component + Returns: + A string containing the name of the component + """ + default = 'N/A' + config = self._config["get_name"] + return self._api_common.get_output(self._index, config, default) + + def get_description(self): + """ + Retrieves the description of the component + Returns: + A string containing the description of the component + """ + default = 'N/A' + config = self._config["get_description"] + return self._api_common.get_output(self._index, config, default) + + def get_firmware_version(self): + """ + Retrieves the firmware version of the component + Note: the firmware version will be read from HW + Returns: + A string containing the firmware version of the component + """ + default = 'N/A' + config = self._config["get_firmware_version"] + return self._api_common.get_output(self._index, config, default) diff --git a/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/eeprom.py b/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/eeprom.py new file mode 100644 index 0000000000..53306c0034 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/eeprom.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica +# +# Platform and model specific eeprom subclass, inherits from the base class, +# and provides the followings: +# - the eeprom format definition +# - specific encoder/decoder if there is special need +############################################################################# + +try: + import os + import sys + import re + from cStringIO import StringIO + from sonic_platform_base.sonic_eeprom import eeprom_tlvinfo +except ImportError, 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 + DEFAULT_EEPROM_PATH = "/sys/class/i2c-adapter/i2c-12/12-0050/eeprom" + + def __init__(self, conf=None): + eeprom_path = conf.get('eeprom', self.DEFAULT_EEPROM_PATH) + super(Tlv, self).__init__(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/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/fan.py new file mode 100644 index 0000000000..b0ebebccd3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/fan.py @@ -0,0 +1,193 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica +# +# Module contains an implementation of SONiC Platform Base API and +# provides the fan status which are available in the platform +# +############################################################################# + +try: + from sonic_platform_base.fan_base import FanBase + from common import Common +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Fan(FanBase): + """Platform-specific Fan class""" + + def __init__(self, index, is_psu_fan=False, psu_index=0, conf=None): + FanBase.__init__(self) + + self._fan_index = index + self._config = conf + self._api_common = Common() + + self._is_psu_fan = is_psu_fan + if self._is_psu_fan: + self._initialize_psu_fan(psu_index) + + self._name = self.get_name() + + def _initialize_psu_fan(self, psu_index): + self._psu_index = psu_index + self._psu_fan_config = self._config['psu_fan'][self._psu_index] + + def get_direction(self): + """ + Retrieves the direction of fan + Returns: + A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST + depending on fan direction + """ + return self._api_common.get_output(self._fan_index, self._config['get_direction'], self.FAN_DIRECTION_NOT_APPLICABLE) + + 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) + + Note: + speed = pwm_in/255*100 + """ + config = self._config['get_speed'] if not self._is_psu_fan else self._psu_fan_config['get_speed'] + max_rpm = config['max_rear'] if 'R' in self._name else config['max_front'] + raw_speed = self._api_common.get_output( + self._fan_index, config, 0) + + return int(float(raw_speed) / max_rpm * 100.0) + + 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: + 0 : when PWM mode is not in use + pwm : when pwm mode is not use + """ + return self._api_common.get_output(self._fan_index, self._config['get_target_speed'], Common.NULL_VAL) + + 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 self._api_common.get_output(self._fan_index, self._config['get_speed_tolerance'], Common.NULL_VAL) + + 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 + + Note: + Depends on pwm or target mode is selected: + 1) pwm = speed_pc * 255 <-- Currently use this mode. + 2) target_pwm = speed_pc * 100 / 255 + 2.1) set pwm{}_enable to 3 + + ipmitool raw 0x3a 0x0e 0x00 > enable auto fcs + ipmitool raw 0x3a 0x0e 0x01 > disable auto fcs + """ + if speed not in range(1, 101) or self._is_psu_fan: + return False + + return self._api_common.set_output(self._fan_index, speed, self._config['set_speed']) + + 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 + + + Note: Required Manual Control LED mode ('ipmitool raw 0x3a 0x0f 0x2 0x0') + """ + config = self._config['set_status_led'] + avaliable_input = config.get('avaliable_input') + if (avaliable_input and color not in avaliable_input) or self._is_psu_fan: + return False + + return self._api_common.set_output(self._fan_index, color, config) + + 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 + + Note: + STATUS_LED_COLOR_GREEN = "green" + STATUS_LED_COLOR_AMBER = "amber" + STATUS_LED_COLOR_RED = "red" + STATUS_LED_COLOR_OFF = "off" + """ + + default = self.STATUS_LED_COLOR_OFF + + if self._is_psu_fan: + return default + + return self._api_common.get_output(self._fan_index, self._config['get_status_led'], default) + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + config = self._config['get_name'] if not self._is_psu_fan else self._psu_fan_config['get_name'] + return self._api_common.get_output(self._fan_index, config, Common.NULL_VAL) + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if FAN is present, False if not + """ + return self._api_common.get_output(self._fan_index, self._config['get_presence'], False) + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + default = Common.NULL_VAL + if self._is_psu_fan: + return default + return self._api_common.get_output(self._fan_index, self._config['get_model'], default) + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + default = Common.NULL_VAL + if self._is_psu_fan: + return default + return self._api_common.get_output(self._fan_index, self._config['get_serial'], default) + + 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_speed() > 10 diff --git a/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/fan_drawer.py b/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/fan_drawer.py new file mode 100644 index 0000000000..5ef283a105 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/fan_drawer.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica +# +# Module contains an implementation of SONiC Platform Base API and +# provides the fan status which are available in the platform +# +############################################################################# + +try: + from sonic_platform_base.fan_drawer_base import FanDrawerBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class FanDrawer(FanDrawerBase): + + def __init__(self, index, fan_list): + FanDrawerBase.__init__(self) + + self._fan_list = fan_list + self._index = index + 1 + + def set_status_led(self, color): + """ + Sets the state of the fan drawer status LED + Args: + color: A string representing the color with which to set the + fan drawer status LED + Returns: + bool: True if status LED state is set successfully, False if not + """ + return self._fan_list[0].set_status_led(color) + + def get_status_led(self, color): + """ + Gets the state of the fan drawer LED + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + return self._fan_list[0].get_status_led() + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return 'Fan {}'.format(self._index) + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if FAN 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() diff --git a/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/platform.py b/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/platform.py new file mode 100644 index 0000000000..a632de87e7 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/platform.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica +# +# Module contains an implementation of SONiC Platform Base API and +# provides the platform information +# +############################################################################# + +try: + from sonic_platform_base.platform_base import PlatformBase + from sonic_platform.chassis import Chassis +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Platform(PlatformBase): + """Platform-specific Platform class""" + + def __init__(self): + PlatformBase.__init__(self) + self._chassis = Chassis() diff --git a/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/psu.py b/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/psu.py new file mode 100644 index 0000000000..68dfe201d3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/psu.py @@ -0,0 +1,182 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica +# +# Module contains an implementation of SONiC Platform Base API and +# provides the psu status which are available in the platform +# +############################################################################# + +try: + from sonic_platform_base.psu_base import PsuBase + from common import Common +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Psu(PsuBase): + """Platform-specific Fan class""" + + def __init__(self, index, conf=None, fan_conf=None): + PsuBase.__init__(self) + + self._psu_index = index + self._config = conf + self._api_common = Common(self._config) + self._fan_conf = fan_conf + self._initialize_psu_fan() + + def _initialize_psu_fan(self): + from sonic_platform.fan import Fan + + num_fan = self._fan_conf['psu_fan'][self._psu_index]["num_of_fan"] + for fan_index in range(0, num_fan): + fan = Fan(fan_index, is_psu_fan=True, + psu_index=self._psu_index, conf=self._fan_conf) + 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 + """ + return self._api_common.get_output(self._psu_index, self._config['get_voltage'], 0.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 + """ + return self._api_common.get_output(self._psu_index, self._config['get_current'], 0.0) + + def get_power(self): + """ + Retrieves current energy supplied by PSU + + Returns: + A float number, the power in watts, e.g. 302.6 + """ + return self._api_common.get_output(self._psu_index, self._config['get_current'], 0.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._api_common.get_output(self._psu_index, self._config['get_powergood_status'], False) + + def set_status_led(self, color): + """ + Sets the state of the PSU status LED + Note: + Seastone2 CPLD able to set only AMBER color. + This function should be disable auto mode before execute + command: ipmitool raw 0x3a 0x0f 0x02 0x00 + Args: + color: A string representing the color with which to set the + PSU status LED + + Returns: + bool: True if status LED state is set successfully, False if not + """ + return self._api_common.set_output(self._psu_index, color, self._config['set_status_led']) + + def get_status_led(self): + """ + Gets the state of the PSU status LED + Note: + Seastone2 PSU LED got only 2 mode, AMBER and Hardware control mode. + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + return self._api_common.get_output(self._psu_index, self._config['get_status_led'], Common.NULL_VAL) + + 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 + """ + return self._api_common.get_output(self._psu_index, self._config['get_temperature'], 0.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 self._api_common.get_output(self._psu_index, self._config['get_temperature_high_threshold'], 0.0) + + def get_voltage_high_threshold(self): + """ + Retrieves the high threshold PSU voltage output + + Returns: + ucr as float number and return 0 if the BMC output is na. + A float number, the high threshold output voltage in volts, + e.g. 12.1 + """ + return self._api_common.get_output(self._psu_index, self._config['get_voltage_high_threshold'], 0.0) + + def get_voltage_low_threshold(self): + """ + Retrieves the low threshold PSU voltage output + + Returns: + lcr as float number and return 0 if the BMC output is na. + A float number, the low threshold output voltage in volts, + e.g. 12.1 + """ + return self._api_common.get_output(self._psu_index, self._config['get_voltage_low_threshold'], 0.0) + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return self._api_common.get_output(self._psu_index, self._config['get_name'], Common.NULL_VAL) + + def get_presence(self): + """ + Retrieves the presence of the PSU + Returns: + bool: True if PSU is present, False if not + """ + return self._api_common.get_output(self._psu_index, self._config['get_name'], False) + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return self._api_common.get_output(self._psu_index, self._config['get_model'], Common.NULL_VAL) + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return self._api_common.get_output(self._psu_index, self._config['get_serial'], Common.NULL_VAL) + + 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_powergood_status() diff --git a/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/sfp.py new file mode 100644 index 0000000000..17f2756dee --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/sfp.py @@ -0,0 +1,2037 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica +# +# Module contains an implementation of SONiC Platform Base API and +# provides the sfp status which are available in the platform +# +############################################################################# + +import time +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 common import Common +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +# definitions of the offset and width for values in XCVR info eeprom +XCVR_INTFACE_BULK_OFFSET = 0 +XCVR_INTFACE_BULK_WIDTH_QSFP = 20 +XCVR_INTFACE_BULK_WIDTH_SFP = 21 +XCVR_TYPE_OFFSET = 0 +XCVR_TYPE_WIDTH = 1 +XCVR_EXT_TYPE_OFFSET = 1 +XCVR_EXT_TYPE_WIDTH = 1 +XCVR_CONNECTOR_OFFSET = 2 +XCVR_CONNECTOR_WIDTH = 1 +XCVR_COMPLIANCE_CODE_OFFSET = 3 +XCVR_COMPLIANCE_CODE_WIDTH = 8 +XCVR_ENCODING_OFFSET = 11 +XCVR_ENCODING_WIDTH = 1 +XCVR_NBR_OFFSET = 12 +XCVR_NBR_WIDTH = 1 +XCVR_EXT_RATE_SEL_OFFSET = 13 +XCVR_EXT_RATE_SEL_WIDTH = 1 +XCVR_CABLE_LENGTH_OFFSET = 14 +XCVR_CABLE_LENGTH_WIDTH_QSFP = 5 +XCVR_CABLE_LENGTH_WIDTH_SFP = 6 +XCVR_VENDOR_NAME_OFFSET = 20 +XCVR_VENDOR_NAME_WIDTH = 16 +XCVR_VENDOR_OUI_OFFSET = 37 +XCVR_VENDOR_OUI_WIDTH = 3 +XCVR_VENDOR_PN_OFFSET = 40 +XCVR_VENDOR_PN_WIDTH = 16 +XCVR_HW_REV_OFFSET = 56 +XCVR_HW_REV_WIDTH_OSFP = 2 +XCVR_HW_REV_WIDTH_QSFP = 2 +XCVR_HW_REV_WIDTH_SFP = 4 +XCVR_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', 'hardwarerev', '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'] + +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" + + +class Sfp(SfpBase): + """Platform-specific Sfp class""" + + def __init__(self, sfp_index=0, conf=None): + SfpBase.__init__(self) + + self._sfp_index = sfp_index + self._config = conf + self._api_common = Common(self._config) + + self._read_porttab_mappings() + self._dom_capability_detect() + + def _read_porttab_mappings(self): + self._sfputil_helper = SfpUtilHelper() + self._sfputil_helper.read_porttab_mappings( + self._get_path_to_port_config_file()) + + def _get_path_to_port_config_file(self): + host_platform_root_path = '/usr/share/sonic/device' + docker_hwsku_path = '/usr/share/sonic/hwsku' + + host_platform_path = "/".join([host_platform_root_path, + self._api_common.platform]) + hwsku_path = "/".join([host_platform_path, self._api_common.hwsku] + ) if self._api_common.is_host() else docker_hwsku_path + + return "/".join([hwsku_path, "port_config.ini"]) + + def _convert_string_to_num(self, value_str): + if "-inf" in value_str: + return Common.NULL_VAL + elif "Unknown" in value_str: + return Common.NULL_VAL + 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 Common.NULL_VAL + + 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._get_eeprom_path() + try: + sysfsfile_eeprom = open( + sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0) + sysfsfile_eeprom.seek(offset) + raw = sysfsfile_eeprom.read(num_bytes) + for n in range(0, num_bytes): + eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) + except Exception: + pass + finally: + if sysfsfile_eeprom: + sysfsfile_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): + eeprom_path = self._config['eeprom_path'] + port_to_i2c_mapping = self._config['port_i2c_mapping'] + port_eeprom_path = eeprom_path.format( + port_to_i2c_mapping[self._sfp_index]) + + return port_eeprom_path + + def _dom_capability_detect(self): + 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 + + self._detect_sfp_type() + + 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_qsfp_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_qsfp_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_name(self): + """ + Retrieves the human-readable name of a sfp by 1-based index + + Returns: + :param index: An integer, 1-based index of the sfp of which to query status + :return: String, + A string representing the name of the sfp. + """ + return self._sfputil_helper.logical[self._sfp_index] or "Unknown" + + def get_presence(self): + """ + Retrieves the presence of the device + Returns: + bool: True if device is present, False if not + """ + return self._api_common.get_output(self._sfp_index, self._config['get_presence'], 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", Common.NULL_VAL) + + 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", Common.NULL_VAL) + + 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() + + 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, Common.NULL_VAL) + + # 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 None + + 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 None + + 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 None + + 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 None + + 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 None + + 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 None + + 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 None + + 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 None + + 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 None + + 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 None + + 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 None + + 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 None + + 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 None + + 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 None + + 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 None + + 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 None + + 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 None + + 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 None + + 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 None + + 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 None + 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 None + + 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 None + + 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 None + + 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 None + + 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, Common.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) + + 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, Common.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 + """ + return self._api_common.get_output(self._sfp_index, self._config['get_reset_status'], 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. + """ + if not self.dom_supported: + return None + + 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) + + 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: + 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 None + 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. + """ + if not self.dom_supported: + return None + + 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) + + 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: + 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] + """ + if not self.dom_supported: + return None + + 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) + + 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: + 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 None + 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 + """ + return self._api_common.get_output(self._sfp_index, self._config['get_lpmode'], False) + + 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 NotImplementedError + + def get_temperature(self): + """ + Retrieves the temperature of this SFP + Returns: + An integer number of current temperature in Celsius + """ + if not self.dom_supported: + return None + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + 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 + else: + return None + else: + return None + + elif self.sfp_type == QSFP_DD_TYPE: + offset = 0 + + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return None + + 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 + return None + + else: + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + 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 + else: + return None + + def get_voltage(self): + """ + Retrieves the supply voltage of this SFP + Returns: + An integer number of supply voltage in mV + """ + if not self.dom_supported: + return None + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + 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 + else: + return None + return None + + if self.sfp_type == QSFP_DD_TYPE: + offset = 128 + + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return None + + 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 + return None + + else: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + + 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 + else: + return None + + def get_tx_bias(self): + """ + Retrieves the TX bias current of this SFP + Returns: + A list of four integer numbers, representing TX bias in mA + for channel 0 to channel 4. + Ex. ['110.09', '111.12', '108.21', '112.09'] + """ + tx_bias_list = [] + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + 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'])) + + elif self.sfp_type == QSFP_DD_TYPE: + # page 11h + if self.dom_rx_tx_power_bias_supported: + offset = 128 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return None + + 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: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + 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 None + else: + return None + + 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 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + 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 None + else: + return None + + elif self.sfp_type == QSFP_DD_TYPE: + # page 11 + if self.dom_rx_tx_power_bias_supported: + offset = 128 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return None + + 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: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + + 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 None + else: + return None + 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 None + + elif self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + 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 None + else: + return None + + elif self.sfp_type == QSFP_DD_TYPE: + # page 11 + if self.dom_rx_tx_power_bias_supported: + offset = 128 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return None + + 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: + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + + 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 None + else: + return None + 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 + """ + config = self._config['reset'] + # Convert our register value back to a hex string and write back + output1 = self._api_common.set_output(self._sfp_index, "0x0", config) + + # Sleep 1 second to allow it to settle + time.sleep(1) + # Flip the bit back high and write back to the register to take port out of reset + output2 = self._api_common.set_output(self._sfp_index, "0x1", config) + + return True if (output1 and output2) else False + + 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_ctl = 0xf if tx_disable else 0x0 + buffer = create_string_buffer(1) + buffer[0] = chr(tx_disable_ctl) + # Write to eeprom + sysfs_sfp_i2c_client_eeprom_path = self._get_eeprom_path() + sysfsfile_eeprom = open( + sysfs_sfp_i2c_client_eeprom_path, "r+b") + sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + 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: + channel_state = self.get_tx_disable_channel() + tx_enable_mask = [0xe, 0xd, 0xb, 0x7] + tx_disable_mask = [0x1, 0x3, 0x7, 0xf] + tx_disable_ctl = channel_state | tx_disable_mask[ + channel] if disable else channel_state & tx_enable_mask[channel] + buffer = create_string_buffer(1) + buffer[0] = chr(tx_disable_ctl) + # Write to eeprom + sysfs_sfp_i2c_client_eeprom_path = self._get_eeprom_path() + sysfsfile_eeprom = open( + sysfs_sfp_i2c_client_eeprom_path, "r+b") + sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + 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 + """ + return self._api_common.set_output(self._sfp_index, str(lpmode), self._config['set_lpmode']) + + 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 == QSFP_TYPE: + sysfsfile_eeprom = None + try: + power_override_bit = 0 + if power_override: + power_override_bit |= 1 << 0 + + power_set_bit = 0 + if power_set: + power_set_bit |= 1 << 1 + + buffer = create_string_buffer(1) + buffer[0] = chr(power_override_bit | power_set_bit) + # Write to eeprom + sysfs_sfp_i2c_client_eeprom_path = self._get_eeprom_path() + sysfsfile_eeprom = open( + sysfs_sfp_i2c_client_eeprom_path, "r+b") + sysfsfile_eeprom.seek(QSFP_POWEROVERRIDE_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + + return False diff --git a/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/thermal.py b/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/thermal.py new file mode 100644 index 0000000000..714e073db3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/services/platform_api/sonic_platform/thermal.py @@ -0,0 +1,176 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica +# +# Module contains an implementation of SONiC Platform Base API and +# provides the thermal status which are available in the platform +# +############################################################################# + +try: + from sonic_platform_base.thermal_base import ThermalBase + from common import Common +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Thermal(ThermalBase): + """Platform-specific Thermal class""" + + def __init__(self, index, _thermal_index=0, conf=None): + ThermalBase.__init__(self) + + self._thermal_index = index + self._config = conf + self._api_common = Common(self._config) + + def get_name(self): + """ + Retrieves the human-readable name of a thermal sensor by 1-based index + + Returns: + :param index: An integer, 1-based index of the thermal sensor of which to query status + :return: String, + A string representing the name of the thermal sensor. + """ + return self._api_common.get_output(self._thermal_index, self._config['get_name'], Common.NULL_VAL) + + def get_temperature(self): + """ + Retrieves current temperature reading from thermal + + by using command ipmitool raw 0x04 0x2D [address] + + Returns: + A float number of current temperature in Celsius up to nearest thousandth + of one degree Celsius, e.g. 30.125 + """ + output = self._api_common.get_output( + self._thermal_index, self._config['get_temperature'], Common.NULL_VAL) + return float(output) if output != Common.NULL_VAL else output + + 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 + """ + output = self._api_common.get_output( + self._thermal_index, self._config['get_high_threshold'], Common.NULL_VAL) + return float(output) if output != Common.NULL_VAL else output + + def get_low_threshold(self): + """ + Retrieves the low threshold temperature of thermal + + Returns: + lnc as float number and return 0 if the BMC output is na. + A float number, the low threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + output = self._api_common.get_output( + self._thermal_index, self._config['get_low_threshold'], Common.NULL_VAL) + return float(output) if output != Common.NULL_VAL else output + + def set_high_threshold(self, temperature): + """ + Sets the high threshold temperature of thermal + + For AMI BMC device : + use ipmitool command + ipmitool sensor thresh [sensor name] unc [0>= temp_value <=62] + if the current value of unc is 'na' ipmitool can't be set the value + + 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 + """ + output = self._api_common.get_output( + self._thermal_index, self._config['set_high_threshold'], Common.NULL_VAL) + return float(output) if output != Common.NULL_VAL else output + + def set_low_threshold(self, temperature): + """ + Sets the low threshold temperature of thermal + + For AMI BMC device : + use ipmitool command + ipmitool sensor thresh [sensor name] lnc [temp_value] + if the current value of lnc is 'na' ipmitool can't be set the value + + 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 + """ + output = self._api_common.get_output( + self._thermal_index, self._config['set_low_threshold'], Common.NULL_VAL) + return float(output) if output != Common.NULL_VAL else output + + def get_high_critical_threshold(self): + """ + Retrieves the high critical threshold temperature of thermal + + Returns: + ucr as float number and return 0 if the BMC output is na. + A float number, the high critical threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + output = self._api_common.get_output( + self._thermal_index, self._config['get_high_critical_threshold'], Common.NULL_VAL) + return float(output) if output != Common.NULL_VAL else output + + def get_low_critical_threshold(self): + """ + Retrieves the low critical threshold temperature of thermal + + Returns: + lnr as float number and return 0 if the BMC output is na. + A float number, the low critical threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + output = self._api_common.get_output( + self._thermal_index, self._config['get_low_critical_threshold'], Common.NULL_VAL) + return float(output) if output != Common.NULL_VAL else output + + 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 Common.NULL_VAL + + def get_serial(self): + """ + Retrieves the serial number of the device + + Returns: + string: Serial number of device + """ + return Common.NULL_VAL + + 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