diff --git a/device/celestica/x86_64-cel_silverstone-r0/platform.json b/device/celestica/x86_64-cel_silverstone-r0/platform.json new file mode 100644 index 000000000000..eae0ffacc251 --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone-r0/platform.json @@ -0,0 +1,591 @@ +{ + "chassis": { + "name": "Silverstone", + "status_led": { + "controllable": false, + "colors": ["green", "off"] + }, + "components": [ + { + "name": "BIOS" + }, + { + "name": "BMC" + }, + { + "name": "SWITCH_CPLD" + }, + { + "name": "BASE_CPLD" + }, + { + "name": "FPGA" + } + ], + "fans": [ + { + "name": "FAN-1F", + "speed": { + "controllable": false + }, + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + } + }, + { + "name": "FAN-1R", + "speed": { + "controllable": false + }, + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + } + }, + { + "name": "FAN-2F", + "speed": { + "controllable": false + }, + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + } + }, + { + "name": "FAN-2R", + "speed": { + "controllable": false + }, + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + } + }, + { + "name": "FAN-3F", + "speed": { + "controllable": false + }, + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + } + }, + { + "name": "FAN-3R", + "speed": { + "controllable": false + }, + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + } + }, + { + "name": "FAN-4F", + "speed": { + "controllable": false + }, + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + } + }, + { + "name": "FAN-4R", + "speed": { + "controllable": false + }, + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + } + }, + { + "name": "FAN-5F", + "speed": { + "controllable": false + }, + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + } + }, + { + "name": "FAN-5R", + "speed": { + "controllable": false + }, + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + } + }, + { + "name": "FAN-6F", + "speed": { + "controllable": false + }, + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + } + }, + { + "name": "FAN-6R", + "speed": { + "controllable": false + }, + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + } + }, + { + "name": "FAN-7F", + "speed": { + "controllable": false + }, + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + } + }, + { + "name": "FAN-7R", + "speed": { + "controllable": false + }, + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + } + } + ], + "fan_drawers": [ + { + "name": "Drawer1", + "max_consumed_power": false, + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + }, + "fans": [ + { + "name": "FAN-1F", + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + }, + "speed": { + "controllable": false + } + }, + { + "name": "FAN-1R", + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + }, + "speed": { + "controllable": false + } + } + ] + }, + { + "name": "Drawer2", + "max_consumed_power": false, + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + }, + "fans": [ + { + "name": "FAN-2F", + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + }, + "speed": { + "controllable": false + } + }, + { + "name": "FAN-2R", + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + }, + "speed": { + "controllable": false + } + } + ] + }, + { + "name": "Drawer3", + "max_consumed_power": false, + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + }, + "fans": [ + { + "name": "FAN-3F", + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + }, + "speed": { + "controllable": false + } + }, + { + "name": "FAN-3R", + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + }, + "speed": { + "controllable": false + } + } + ] + }, + { + "name": "Drawer4", + "max_consumed_power": false, + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + }, + "fans": [ + { + "name": "FAN-4F", + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + }, + "speed": { + "controllable": false + } + }, + { + "name": "FAN-4R", + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + }, + "speed": { + "controllable": false + } + } + ] + }, + { + "name": "Drawer5", + "max_consumed_power": false, + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + }, + "fans": [ + { + "name": "FAN-5F", + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + }, + "speed": { + "controllable": false + } + }, + { + "name": "FAN-5R", + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + }, + "speed": { + "controllable": false + } + } + ] + }, + { + "name": "Drawer6", + "max_consumed_power": false, + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + }, + "fans": [ + { + "name": "FAN-6F", + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + }, + "speed": { + "controllable": false + } + }, + { + "name": "FAN-6R", + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + }, + "speed": { + "controllable": false + } + } + ] + }, + { + "name": "Drawer7", + "max_consumed_power": false, + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + }, + "fans": [ + { + "name": "FAN-7F", + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + }, + "speed": { + "controllable": false + } + }, + { + "name": "FAN-7R", + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + }, + "speed": { + "controllable": false + } + } + ] + } + ], + "psus": [ + { + "name": "PSU-1", + "current": false, + "power": false, + "max_power": false, + "voltage_high_threshold": false, + "voltage_low_threshold": false, + "temperature": false, + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + }, + "fans": [ + { + "name": "PSU-1 FAN-1", + "speed": { + "controllable": false + }, + "status_led": { + "controllable": false + } + } + ] + }, + { + "name": "PSU-2", + "current": false, + "power": false, + "max_power": false, + "voltage_high_threshold": false, + "voltage_low_threshold": false, + "temperature": false, + "status_led": { + "controllable": false, + "colors": ["green", "amber","off"] + }, + "fans": [ + { + "name": "PSU-2 FAN-1", + "speed": { + "controllable": false + }, + "status_led": { + "controllable": false + } + } + ] + } + ], + "thermals": [ + { + "name": "TEMP_FAN_U52", + "controllable": false, + "low-threshold": false, + "low-crit-threshold": false + }, + { + "name": "TEMP_FAN_U17", + "controllable": false, + "low-threshold": false, + "low-crit-threshold": false + }, + { + "name": "TEMP_SW_U52", + "controllable": false, + "low-threshold": false, + "low-crit-threshold": false + }, + { + "name": "TEMP_SW_U16", + "controllable": false, + "low-threshold": false, + "low-crit-threshold": false + }, + { + "name": "TEMP_BB_U3", + "controllable": false, + "low-threshold": false, + "low-crit-threshold": false + }, + { + "name": "TEMP_CPU", + "controllable": false, + "low-threshold": false, + "low-crit-threshold": false + }, + { + "name": "TEMP_SW_Internal", + "controllable": false, + "low-threshold": false, + "low-crit-threshold": false + }, + { + "name": "SW_U04_Temp", + "controllable": false, + "low-threshold": false, + "low-crit-threshold": false + }, + { + "name": "SW_U14_Temp", + "controllable": false, + "low-threshold": false, + "low-crit-threshold": false + }, + { + "name": "SW_U4403_Temp", + "controllable": false, + "low-threshold": false, + "low-crit-threshold": false + } + ], + "sfps": [ + { + "name": "Ethernet0" + }, + { + "name": "Ethernet4" + }, + { + "name": "Ethernet8" + }, + { + "name": "Ethernet12" + }, + { + "name": "Ethernet16" + }, + { + "name": "Ethernet20" + }, + { + "name": "Ethernet24" + }, + { + "name": "Ethernet28" + }, + { + "name": "Ethernet32" + }, + { + "name": "Ethernet36" + }, + { + "name": "Ethernet40" + }, + { + "name": "Ethernet44" + }, + { + "name": "Ethernet48" + }, + { + "name": "Ethernet52" + }, + { + "name": "Ethernet56" + }, + { + "name": "Ethernet60" + }, + { + "name": "Ethernet64" + }, + { + "name": "Ethernet68" + }, + { + "name": "Ethernet72" + }, + { + "name": "Ethernet76" + }, + { + "name": "Ethernet80" + }, + { + "name": "Ethernet84" + }, + { + "name": "Ethernet88" + }, + { + "name": "Ethernet92" + }, + { + "name": "Ethernet96" + }, + { + "name": "Ethernet100" + }, + { + "name": "Ethernet104" + }, + { + "name": "Ethernet108" + }, + { + "name": "Ethernet112" + }, + { + "name": "Ethernet116" + }, + { + "name": "Ethernet120" + }, + { + "name": "Ethernet124" + } + ] + }, + "interfaces": {} +} \ No newline at end of file diff --git a/device/celestica/x86_64-cel_silverstone-r0/platform_components.json b/device/celestica/x86_64-cel_silverstone-r0/platform_components.json new file mode 100644 index 000000000000..9f9fb789634d --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone-r0/platform_components.json @@ -0,0 +1,13 @@ +{ + "chassis": { + "Silverstone": { + "component": { + "BIOS": {}, + "BMC": {}, + "SWITCH_CPLD": {}, + "BASE_CPLD": {}, + "FPGA": {} + } + } + } +} \ No newline at end of file diff --git a/device/celestica/x86_64-cel_silverstone-r0/plugins/sfputil.py b/device/celestica/x86_64-cel_silverstone-r0/plugins/sfputil.py index c089b42c3638..3e0dac8daf36 100755 --- a/device/celestica/x86_64-cel_silverstone-r0/plugins/sfputil.py +++ b/device/celestica/x86_64-cel_silverstone-r0/plugins/sfputil.py @@ -18,12 +18,46 @@ class SfpUtil(SfpUtilBase): SFP_PORT_START = 33 SFP_PORT_END = 34 - EEPROM_OFFSET = 9 - PORT_INFO_PATH = '/sys/class/silverstone_fpga' + PORT_INFO_PATH = '/sys/devices/platform/cls-xcvr' _port_name = "" _port_to_eeprom_mapping = {} - _port_to_i2cbus_mapping = {} + _port_to_i2cbus_mapping = { + 1: 10, + 2: 11, + 3: 12, + 4: 13, + 5: 14, + 6: 15, + 7: 16, + 8: 17, + 9: 18, + 10: 19, + 11: 20, + 12: 21, + 13: 22, + 14: 23, + 15: 24, + 16: 25, + 17: 26, + 18: 27, + 19: 28, + 20: 29, + 21: 30, + 22: 31, + 23: 32, + 24: 33, + 25: 34, + 26: 35, + 27: 36, + 28: 37, + 29: 38, + 30: 39, + 31: 40, + 32: 41, + 33: 1, + 34: 2 + } @property def port_start(self): @@ -49,7 +83,7 @@ def port_to_eeprom_mapping(self): def port_to_i2cbus_mapping(self): return self._port_to_i2cbus_mapping - def get_port_name(self, port_num): + def _get_port_name(self, port_num): if port_num in self.osfp_ports: self._port_name = "QSFP" + str(port_num - self.OSFP_PORT_START + 1) else: @@ -67,11 +101,8 @@ def get_eeprom_dom_raw(self, port_num): def __init__(self): # Override port_to_eeprom_mapping for class initialization eeprom_path = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom' - - for x in range(self.PORT_START, self.PORT_END+1): - self.port_to_i2cbus_mapping[x] = (x + self.EEPROM_OFFSET) - self.port_to_eeprom_mapping[x] = eeprom_path.format( - x + self.EEPROM_OFFSET) + for k,v in self._port_to_i2cbus_mapping.items(): + self._port_to_eeprom_mapping[k] = eeprom_path.format(v) SfpUtilBase.__init__(self) def get_presence(self, port_num): @@ -80,8 +111,8 @@ def get_presence(self, port_num): return False # Get path for access port presence status - port_name = self.get_port_name(port_num) - sysfs_filename = "qsfp_modprs" if port_num in self.osfp_ports else "sfp_modabs" + port_name = self._get_port_name(port_num) + sysfs_filename = "qsfp_modprsL" if port_num in self.osfp_ports else "sfp_modabs" reg_path = "/".join([self.PORT_INFO_PATH, port_name, sysfs_filename]) # Read status @@ -105,7 +136,7 @@ def get_low_power_mode(self, port_num): return False try: - port_name = self.get_port_name(port_num) + port_name = self._get_port_name(port_num) reg_file = open("/".join([self.PORT_INFO_PATH, port_name, "qsfp_lpmode"])) except IOError as e: @@ -122,12 +153,12 @@ def get_low_power_mode(self, port_num): return True def set_low_power_mode(self, port_num, lpmode): - # Check for invalid QSFP port_num + # Check for invalid port_num if port_num not in self.osfp_ports: return False try: - port_name = self.get_port_name(port_num) + port_name = self._get_port_name(port_num) reg_file = open("/".join([self.PORT_INFO_PATH, port_name, "qsfp_lpmode"]), "r+") except IOError as e: @@ -143,14 +174,14 @@ def set_low_power_mode(self, port_num, lpmode): return True def reset(self, port_num): - # Check for invalid QSFP port_num + # Check for invalid port_num if port_num not in self.osfp_ports: return False try: - port_name = self.get_port_name(port_num) + port_name = self._get_port_name(port_num) reg_file = open("/".join([self.PORT_INFO_PATH, - port_name, "qsfp_reset"]), "w") + port_name, "qsfp_resetL"]), "w") except IOError as e: print("Error: unable to open file: %s" % str(e)) return False @@ -166,7 +197,7 @@ def reset(self, port_num): # Flip the bit back high and write back to the register to take port out of reset try: reg_file = open( - "/".join([self.PORT_INFO_PATH, port_name, "qsfp_reset"]), "w") + "/".join([self.PORT_INFO_PATH, port_name, "qsfp_resetL"]), "w") except IOError as e: print("Error: unable to open file: %s" % str(e)) return False diff --git a/device/celestica/x86_64-cel_silverstone-r0/pmon_daemon_control.json b/device/celestica/x86_64-cel_silverstone-r0/pmon_daemon_control.json index 94592fa8cebc..a08a1e6ea109 100644 --- a/device/celestica/x86_64-cel_silverstone-r0/pmon_daemon_control.json +++ b/device/celestica/x86_64-cel_silverstone-r0/pmon_daemon_control.json @@ -1,3 +1,8 @@ { - "skip_ledd": true + "skip_fancontrol": true, + "skip_ledd": true, + "skip_psud": false, + "skip_syseepromd": false, + "skip_thermalctld": false, + "skip_xcvrd": false } diff --git a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/chassis.py b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/chassis.py index b6f77cbd3dc9..cc19ecef7cb5 100644 --- a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/chassis.py +++ b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/chassis.py @@ -6,20 +6,12 @@ # ############################################################################# -import sys -import re -import os -import subprocess -import json - try: + import sys from sonic_platform_base.chassis_base import ChassisBase - from sonic_platform.component import Component - from sonic_platform.eeprom import Tlv - from sonic_platform.fan import Fan - from sonic_platform.sfp import Sfp - from sonic_platform.psu import Psu - from sonic_platform.thermal import Thermal + from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper + from sonic_py_common import device_info + from .event import SfpEvent from .helper import APIHelper except ImportError as e: raise ImportError(str(e) + "- required module not found") @@ -34,35 +26,71 @@ IPMI_OEM_NETFN = "0x3A" IPMI_GET_REBOOT_CAUSE = "0x03 0x00 0x01 0x06" +IPMI_SET_SYS_LED_CMD = "0x00 0x02 {}" +IPMI_GET_SYS_LED_CMD = "0x00 0x02" + +SYS_LED_OFF_CMD = "0x00" +SYS_LED_GREEN_CMD = "0x01" +SYS_LED_AMBER_CMD = "0x02" + class Chassis(ChassisBase): """Platform-specific Chassis class""" def __init__(self): - self.config_data = {} ChassisBase.__init__(self) - self._eeprom = Tlv() self._api_helper = APIHelper() + self.sfp_module_initialized = False + + self.__initialize_eeprom() + self.is_host = self._api_helper.is_host() + + self.__initialize_fan() + self.__initialize_psu() + self.__initialize_thermals() + self.__initialize_components() - for fant_index in range(0, NUM_FAN_TRAY): - for fan_index in range(0, NUM_FAN): - fan = Fan(fant_index, fan_index) - self._fan_list.append(fan) + def __initialize_sfp(self): + sfputil_helper = SfpUtilHelper() + port_config_file_path = device_info.get_path_to_port_config_file() + sfputil_helper.read_porttab_mappings(port_config_file_path, 0) + from sonic_platform.sfp import Sfp for index in range(0, NUM_SFP): - sfp = Sfp(index) + sfp = Sfp(index, sfputil_helper.logical[index]) self._sfp_list.append(sfp) + self.sfp_module_initialized = True + def __initialize_psu(self): + from sonic_platform.psu import Psu for index in range(0, NUM_PSU): psu = Psu(index) self._psu_list.append(psu) - for index in range(0, NUM_COMPONENT): - component = Component(index) - self._component_list.append(component) + + def __initialize_fan(self): + from sonic_platform.fan_drawer import FanDrawer + for i in range(NUM_FAN_TRAY): + fandrawer = FanDrawer(i) + self._fan_drawer_list.append(fandrawer) + self._fan_list.extend(fandrawer._fan_list) + + def __initialize_thermals(self): + from sonic_platform.thermal import Thermal + # airflow = self.__get_air_flow() for index in range(0, NUM_THERMAL): thermal = Thermal(index) self._thermal_list.append(thermal) + def __initialize_eeprom(self): + from sonic_platform.eeprom import Tlv + self._eeprom = Tlv() + + def __initialize_components(self): + from sonic_platform.component import Component + for index in range(0, NUM_COMPONENT): + component = Component(index) + self._component_list.append(component) + def get_base_mac(self): """ Retrieves the base MAC address for the chassis @@ -129,3 +157,193 @@ def get_reboot_cause(self): }.get(hx_cause, "Unknown reason") return (reboot_cause, description) + + 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. + """ + # SFP event + if not self.sfp_module_initialized: + self.__initialize_sfp() + + status, sfp_event = SfpEvent(self._sfp_list).get_sfp_event(timeout) + return status, sfp_event + + + ############################################################## + ######################## 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 + """ + if not self.sfp_module_initialized: + self.__initialize_sfp() + return super(Chassis, self).get_sfp(index-1) + + ############################################################## + ####################### 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: + from sonic_platform.watchdog import Watchdog + self._watchdog = Watchdog() + + return self._watchdog + + def get_thermal_manager(self): + from .thermal_manager import ThermalManager + return ThermalManager + + ############################################################## + ###################### Device methods ######################## + ############################################################## + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return self._api_helper.hwsku + + def get_presence(self): + """ + Retrieves the presence of the Chassis + Returns: + bool: True if Chassis is present, False if not + """ + return True + + def get_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 + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False + + def set_status_led(self, color): + """ + Sets the state of the PSU status LED + Args: + color: A string representing the color with which to set the PSU status LED + Note: Only support green and off + Returns: + bool: True if status LED state is set successfully, False if not + """ + led_cmd = { + self.STATUS_LED_COLOR_GREEN: SYS_LED_GREEN_CMD, + self.STATUS_LED_COLOR_AMBER: SYS_LED_AMBER_CMD, + self.STATUS_LED_COLOR_OFF: SYS_LED_OFF_CMD + }.get(color) + + status, set_led = self._api_helper.ipmi_raw( + IPMI_OEM_NETFN, IPMI_SET_SYS_LED_CMD.format(led_cmd)) + set_status_led = False if not status else True + + return set_status_led + + def get_status_led(self): + """ + Gets the state of the PSU status LED + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + status, hx_color = self._api_helper.ipmi_raw( + IPMI_OEM_NETFN, IPMI_GET_SYS_LED_CMD) + + status_led = { + "00": self.STATUS_LED_COLOR_OFF, + "01": self.STATUS_LED_COLOR_GREEN, + "02": self.STATUS_LED_COLOR_AMBER, + }.get(hx_color, self.STATUS_LED_COLOR_OFF) + return status_led diff --git a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/component.py b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/component.py index bbbb9f1d458d..866c2d10e3bb 100644 --- a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/component.py +++ b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/component.py @@ -96,6 +96,29 @@ def get_firmware_version(self): return fw_version + def get_available_firmware_version(self, image_path): + """ + Retrieves the available firmware version of the component + Note: the firmware version will be read from image + Args: + image_path: A string, path to firmware image + Returns: + A string containing the available firmware version of the component + """ + return "N/A" + + def get_firmware_update_notification(self, image_path): + """ + Retrieves a notification on what should be done in order to complete + the component firmware update + Args: + image_path: A string, path to firmware image + Returns: + A string containing the component firmware update notification if required. + By default 'None' value will be used, which indicates that no actions are required + """ + return "None" + def install_firmware(self, image_path): """ Install firmware to module @@ -117,3 +140,72 @@ def install_firmware(self, image_path): # print(install_command) status = self._api_helper.run_interactive_command(install_command) return status + + def update_firmware(self, image_path): + """ + Updates firmware of the component + This API performs firmware update: it assumes firmware installation and loading in a single call. + In case platform component requires some extra steps (apart from calling Low Level Utility) + to load the installed firmware (e.g, reboot, power cycle, etc.) - this will be done automatically by API + Args: + image_path: A string, path to firmware image + Raises: + RuntimeError: update failed + """ + return False + + ############################################################## + ###################### Device methods ######################## + ############################################################## + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if FAN is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return 'N/A' + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return 'N/A' + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + return True + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False diff --git a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/eeprom.py b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/eeprom.py index cf3f1a98de20..b0d37d57beac 100644 --- a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/eeprom.py +++ b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/eeprom.py @@ -1,5 +1,5 @@ ############################################################################# -# Celestica Silverstone +# Celestica Seastone-DX010 # # Platform and model specific eeprom subclass, inherits from the base class, # and provides the followings: @@ -8,26 +8,22 @@ ############################################################################# try: - import glob import os import sys import re - from array import array if sys.version_info.major == 3: from io import StringIO else: from cStringIO import StringIO - from sonic_platform_base.sonic_eeprom import eeprom_dts from sonic_platform_base.sonic_eeprom import eeprom_tlvinfo except ImportError as e: raise ImportError(str(e) + "- required module not found") CACHE_ROOT = '/var/cache/sonic/decode-syseeprom' CACHE_FILE = 'syseeprom_cache' -TLV_EEPROM_I2C_BUS = 0 -TLV_EEPROM_I2C_ADDR = 56 +NULL = 'N/A' class Tlv(eeprom_tlvinfo.TlvInfoDecoder): @@ -35,8 +31,7 @@ class Tlv(eeprom_tlvinfo.TlvInfoDecoder): EEPROM_DECODE_HEADLINES = 6 def __init__(self): - self._eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-00{1}/eeprom".format( - TLV_EEPROM_I2C_BUS, TLV_EEPROM_I2C_ADDR) + self._eeprom_path = "/sys/class/i2c-adapter/i2c-12/12-0050/eeprom" super(Tlv, self).__init__(self._eeprom_path, 0, '', True) self._eeprom = self._load_eeprom() @@ -55,7 +50,7 @@ def __parse_output(self, decode_output): value = match.group(3).rstrip('\0') _eeprom_info_dict[idx] = value - except: + except BaseException: pass return _eeprom_info_dict @@ -64,7 +59,7 @@ def _load_eeprom(self): sys.stdout = StringIO() try: self.read_eeprom_db() - except: + except BaseException: decode_output = sys.stdout.getvalue() sys.stdout = original_stdout return self.__parse_output(decode_output) @@ -76,7 +71,7 @@ def _load_eeprom(self): if not os.path.exists(CACHE_ROOT): try: os.makedirs(CACHE_ROOT) - except: + except BaseException: pass # @@ -85,7 +80,7 @@ def _load_eeprom(self): # try: self.set_cache_name(os.path.join(CACHE_ROOT, CACHE_FILE)) - except: + except BaseException: pass e = self.read_eeprom() @@ -94,7 +89,7 @@ def _load_eeprom(self): try: self.update_cache(e) - except: + except BaseException: pass self.decode_eeprom(e) @@ -107,11 +102,40 @@ def _load_eeprom(self): return self.__parse_output(decode_output) + def _valid_tlv(self, eeprom_data): + tlvinfo_type_codes_list = [ + self._TLV_CODE_PRODUCT_NAME, + self._TLV_CODE_PART_NUMBER, + self._TLV_CODE_SERIAL_NUMBER, + self._TLV_CODE_MAC_BASE, + self._TLV_CODE_MANUF_DATE, + self._TLV_CODE_DEVICE_VERSION, + self._TLV_CODE_LABEL_REVISION, + self._TLV_CODE_PLATFORM_NAME, + self._TLV_CODE_ONIE_VERSION, + self._TLV_CODE_MAC_SIZE, + self._TLV_CODE_MANUF_NAME, + self._TLV_CODE_MANUF_COUNTRY, + self._TLV_CODE_VENDOR_NAME, + self._TLV_CODE_DIAG_VERSION, + self._TLV_CODE_SERVICE_TAG, + self._TLV_CODE_VENDOR_EXT, + self._TLV_CODE_CRC_32 + ] + + for code in tlvinfo_type_codes_list: + code_str = "0x{:X}".format(code) + eeprom_data[code_str] = eeprom_data.get(code_str, NULL) + return eeprom_data + def get_eeprom(self): - return self._eeprom + return self._valid_tlv(self._eeprom) + + def get_pn(self): + return self._eeprom.get('0x22', NULL) def get_serial(self): - return self._eeprom.get('0x23', "Undefined.") + return self._eeprom.get('0x23', NULL) def get_mac(self): - return self._eeprom.get('0x24', "Undefined.") + return self._eeprom.get('0x24', NULL) diff --git a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/event.py b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/event.py new file mode 100644 index 000000000000..0ab38f925112 --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/event.py @@ -0,0 +1,53 @@ +try: + import time + from .helper import APIHelper +except ImportError as e: + raise ImportError(repr(e) + " - required module not found") + + +class SfpEvent: + ''' Listen to insert/remove sfp events ''' + + def __init__(self, sfp_list): + self._sfp_list = sfp_list + + sfp_change_event_data = {'valid': 0, 'last': 0, 'present': 0} + + def get_sfp_event(self, timeout=2000): + now = time.time() + port_dict = {} + change_dict = {} + change_dict['sfp'] = port_dict + + if timeout < 1000: + timeout = 1000 + timeout = timeout / float(1000) # Convert to secs + + if now < (self.sfp_change_event_data['last'] + timeout) and self.sfp_change_event_data['valid']: + return True, change_dict + + bitmap = 0 + for sfp in self._sfp_list: + modpres = sfp.get_presence() + i=sfp.port_num-1 + if modpres: + bitmap = bitmap | (1 << i) + + changed_ports = self.sfp_change_event_data['present'] ^ bitmap + if changed_ports: + for sfp in self._sfp_list: + i=sfp.port_num-1 + if (changed_ports & (1 << i)): + if (bitmap & (1 << i)) == 0: + port_dict[i+1] = '0' + else: + port_dict[i+1] = '1' + + + # Update the cache dict + self.sfp_change_event_data['present'] = bitmap + self.sfp_change_event_data['last'] = now + self.sfp_change_event_data['valid'] = 1 + return True, change_dict + else: + return True, change_dict diff --git a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/fan.py b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/fan.py index 1a18eed9c8d5..5d5314fe304d 100644 --- a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/fan.py +++ b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/fan.py @@ -96,7 +96,7 @@ def get_speed(self): max_rpm = MAX_OUTLET if self.fan_index % 2 == 0 else MAX_INLET fan1_ss_start = FAN1_FRONT_SS_ID if self.fan_index % 2 == 0 else FAN1_REAR_SS_ID - ss_id = hex(int(fan1_ss_start, 16) + self.fan_tray_index) if not self.psu_index else hex( + ss_id = hex(int(fan1_ss_start, 16) + self.fan_tray_index) if not self.is_psu_fan else hex( int(PSU_FAN1_FRONT_SS_ID, 16) + self.fan_tray_index) status, raw_ss_read = self._api_helper.ipmi_raw( IPMI_SENSOR_NETFN, IPMI_FAN_SPEED_CMD.format(ss_id)) @@ -120,8 +120,7 @@ def get_target_speed(self): 0 : when PWM mode is use pwm : when pwm mode is not use """ - target = 0 - return target + return "N/A" def get_speed_tolerance(self): """ @@ -224,6 +223,10 @@ def get_status_led(self): return status_led + ############################################################## + ###################### Device methods ######################## + ############################################################## + def get_name(self): """ Retrieves the name of the device @@ -299,3 +302,24 @@ def get_status(self): A boolean value, True if device is operating properly, False if not """ return self.get_presence() and self.get_speed() > 0 + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return (self.fan_tray_index*2 + self.fan_index + 1) \ + if not self.is_psu_fan else (self.fan_index+1) + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True if not self.is_psu_fan else False diff --git a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/fan_drawer.py b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/fan_drawer.py new file mode 100644 index 000000000000..e35ecf65195a --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/fan_drawer.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica +# +# Module contains an implementation of SONiC Platform Base API and +# provides the the Fan-Drawers' information available in the platform +# +############################################################################# + +try: + from sonic_platform_base.fan_drawer_base import FanDrawerBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +NUM_FAN = 2 + + +class FanDrawer(FanDrawerBase): + def __init__(self, fantray_index): + FanDrawerBase.__init__(self) + self._index = fantray_index + 1 + self._init_fan(fantray_index) + + def _init_fan(self, fantray_index): + from sonic_platform.fan import Fan + for index in range(NUM_FAN): + fan = Fan(fantray_index, index) + self._fan_list.append(fan) + + 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=None): + """ + 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() + + ############################################################## + ###################### Device methods ######################## + ############################################################## + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return "Drawer{}".format(self._index) + + def get_presence(self): + """ + Retrieves the presence of the device + Returns: + bool: True if device is present, False if not + """ + return self._fan_list[0].get_presence() + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return self._fan_list[0].get_model() + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return self._fan_list[0].get_serial() + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + return self._fan_list[0].get_status() + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device + Returns: + integer: The 1-based relative physical position in parent device + """ + return self._index + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True diff --git a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/helper.py b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/helper.py index 144d9e154348..140c62c08666 100644 --- a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/helper.py +++ b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/helper.py @@ -3,6 +3,8 @@ import subprocess from mmap import * +from sonic_py_common import device_info + HOST_CHK_CMD = "docker > /dev/null 2>&1" EMPTY_STRING = "" @@ -10,7 +12,7 @@ class APIHelper(): def __init__(self): - pass + (self.platform, self.hwsku) = device_info.get_platform_and_hwsku() def is_host(self): return os.system(HOST_CHK_CMD) == 0 @@ -57,6 +59,28 @@ def read_txt_file(self, file_path): pass return None + def read_one_line_file(self, file_path): + try: + with open(file_path, 'r') as fd: + data = fd.readline() + return data.strip() + except IOError: + pass + return None + + def write_txt_file(self, file_path, value): + try: + with open(file_path, 'w') as fd: + fd.write(str(value)) + except Exception: + return False + return True + + def get_cpld_reg_value(self, getreg_path, register): + cmd = "echo {1} > {0}; cat {0}".format(getreg_path, register) + status, result = self.run_command(cmd) + return result if status else None + def ipmi_raw(self, netfn, cmd): status = True result = "" @@ -95,7 +119,8 @@ def ipmi_set_ss_thres(self, id, threshold_key, value): status = True result = "" try: - cmd = "ipmitool sensor thresh '{}' {} {}".format(str(id), str(threshold_key), str(value)) + cmd = "ipmitool sensor thresh '{}' {} {}".format( + str(id), str(threshold_key), str(value)) p = subprocess.Popen( cmd, shell=True, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) raw_data, err = p.communicate() diff --git a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/psu.py b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/psu.py index 9ad0f1dc9392..701e5eb12bb1 100644 --- a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/psu.py +++ b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/psu.py @@ -6,10 +6,8 @@ # ############################################################################# -import os import re import math -import sonic_platform try: from sonic_platform_base.psu_base import PsuBase @@ -36,12 +34,12 @@ PSU1_VOUT_SS_ID = "0x36" PSU1_COUT_SS_ID = "0x37" PSU1_POUT_SS_ID = "0x38" -PSU1_STATUS_REG = "0x39" +PSU1_STATUS_REG = "0x2f" PSU2_VOUT_SS_ID = "0x40" PSU2_COUT_SS_ID = "0x41" PSU2_POUT_SS_ID = "0x42" -PSU2_STATUS_REG = "0x2f" +PSU2_STATUS_REG = "0x39" PSU1_FRU_ID = 3 @@ -161,6 +159,55 @@ def get_status_led(self): return status_led + # 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 + # """ + # raise NotImplementedError + + # 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 + # """ + # raise NotImplementedError + + # def get_voltage_high_threshold(self): + # """ + # Retrieves the high threshold PSU voltage output + # Returns: + # A float number, the high threshold output voltage in volts, + # e.g. 12.1 + # """ + # raise NotImplementedError + + # def get_voltage_low_threshold(self): + # """ + # Retrieves the low threshold PSU voltage output + # Returns: + # A float number, the low threshold output voltage in volts, + # e.g. 12.1 + # """ + # raise NotImplementedError + + # def get_maximum_supplied_power(self): + # """ + # Retrieves the maximum supplied power by PSU + # Returns: + # A float number, the maximum power output in Watts. + # e.g. 1200.1 + # """ + # raise NotImplementedError + + ############################################################## + ###################### Device methods ######################## + ############################################################## + def get_name(self): """ Retrieves the name of the device @@ -232,10 +279,26 @@ def get_status(self): status, raw_status_read = self._api_helper.ipmi_raw( IPMI_SENSOR_NETFN, IPMI_SS_READ_CMD.format(psu_pstatus_key)) status_byte = self.find_value(raw_status_read) - if status: failure_detected = (int(status_byte, 16) >> 1) & 1 input_lost = (int(status_byte, 16) >> 3) & 1 psu_status = False if (input_lost or failure_detected) else True return psu_status + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True diff --git a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/sfp.py b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/sfp.py index e909416e9081..f71f56e88e6b 100644 --- a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/sfp.py +++ b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/sfp.py @@ -1,31 +1,32 @@ +#!/usr/bin/env python + ############################################################################# # Celestica # # Sfp contains an implementation of SONiC Platform Base API and -# provides the sfp device status which are available in the platform +# provides the sfp status which are available in the platform # ############################################################################# -import os -import time -import subprocess -from ctypes import create_string_buffer try: + import time + import struct from sonic_platform_base.sfp_base import SfpBase - from sonic_platform_base.sonic_eeprom import eeprom_dts 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 sonic_platform_base.sonic_sfp.sff8024 import type_of_media_interface + from .helper import APIHelper + except ImportError as e: raise ImportError(str(e) + "- required module not found") -INFO_OFFSET = 128 -DOM_OFFSET = 0 - # definitions of the offset and width for values in XCVR info eeprom XCVR_INTFACE_BULK_OFFSET = 0 XCVR_INTFACE_BULK_WIDTH_QSFP = 20 @@ -57,6 +58,8 @@ 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 @@ -64,13 +67,49 @@ XCVR_DOM_CAPABILITY_OFFSET = 92 XCVR_DOM_CAPABILITY_WIDTH = 2 +# 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 + +# to improve performance we retrieve all eeprom data via a single ethtool command +# in function get_transceiver_info and get_transceiver_bulk_status +# XCVR_INTERFACE_DATA_SIZE stands for the max size to be read +# this variable is only used by get_transceiver_info. +# please be noted that each time some new value added to the function +# we should make sure that it falls into the area +# [XCVR_INTERFACE_DATA_START, XCVR_INTERFACE_DATA_SIZE] or +# adjust XCVR_INTERFACE_MAX_SIZE to contain the new data +# It's same for [QSFP_DOM_BULK_DATA_START, QSFP_DOM_BULK_DATA_SIZE] and +# [SFP_DOM_BULK_DATA_START, SFP_DOM_BULK_DATA_SIZE] which are used by +# get_transceiver_bulk_status XCVR_INTERFACE_DATA_START = 0 XCVR_INTERFACE_DATA_SIZE = 92 +SFP_MODULE_ADDRA2_OFFSET = 256 +SFP_MODULE_THRESHOLD_OFFSET = 0 +SFP_MODULE_THRESHOLD_WIDTH = 56 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 @@ -79,7 +118,14 @@ OSFP_HW_REV_OFFSET = 164 OSFP_VENDOR_SN_OFFSET = 166 -# Offset for values in QSFP eeprom +# 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 DOM info eeprom QSFP_DOM_REV_OFFSET = 1 QSFP_DOM_REV_WIDTH = 1 QSFP_TEMPE_OFFSET = 22 @@ -113,11 +159,6 @@ 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 @@ -128,29 +169,114 @@ 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 = 26 +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 + +# identifier value of xSFP module which is in the first byte of the EEPROM +# if the identifier value falls into SFP_TYPE_CODE_LIST the module is treated as a SFP module and parsed according to 8472 +# for QSFP_TYPE_CODE_LIST the module is treated as a QSFP module and parsed according to 8436/8636 +# Originally the type (SFP/QSFP) of each module is determined according to the SKU dictionary +# where the type of each FP port is defined. The content of EEPROM is parsed according to its type. +# However, sometimes the SFP module can be fit in an adapter and then pluged into a QSFP port. +# In this case the EEPROM content is in format of SFP but parsed as QSFP, causing failure. +# To resolve that issue the type field of the xSFP module is also fetched so that we can know exectly what type the +# module is. Currently only the following types are recognized as SFP/QSFP module. +# Meanwhile, if the a module's identifier value can't be recognized, it will be parsed according to the SKU dictionary. +# This is because in the future it's possible that some new identifier value which is not regonized but backward compatible +# with the current format and by doing so it can be parsed as much as possible. +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_cable_length_tup = ( + 'LengthSMFkm-UnitsOfKm', 'LengthSMF(UnitsOf100m)', + 'Length50um(UnitsOf10m)', 'Length62.5um(UnitsOfm)', + 'LengthCable(UnitsOfm)', 'LengthOM3(UnitsOf10m)' +) + +sfp_compliance_code_tup = ( + '10GEthernetComplianceCode', 'InfinibandComplianceCode', + 'ESCONComplianceCodes', 'SONETComplianceCodes', + 'EthernetComplianceCodes', 'FibreChannelLinkLength', + 'FibreChannelTechnology', 'SFP+CableTechnology', + 'FibreChannelTransmissionMedia', 'FibreChannelSpeed' +) + +qsfp_compliance_code_tup = ( + '10/40G Ethernet Compliance Code', 'SONET Compliance codes', + 'SAS/SATA compliance codes', 'Gigabit Ethernet Compliant codes', + 'Fibre Channel link length/Transmitter Technology', + 'Fibre Channel transmission media', 'Fibre Channel Speed' +) + +info_dict_keys = [ + 'type', 'hardware_rev', 'serial', 'manufacturer', + 'model', 'connector', 'encoding', 'ext_identifier', + 'ext_rateselect_compliance', 'cable_type', 'cable_length', + 'nominal_bit_rate', 'specification_compliance', 'vendor_date', + 'vendor_oui', 'application_advertisement', 'type_abbrv_name' +] qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)', 'Length OM2(m)', 'Length OM1(m)', 'Length Cable Assembly(m)') -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') +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 = "SFP" QSFP_TYPE = "QSFP" OSFP_TYPE = "OSFP" +QSFP_DD_TYPE = "QSFP_DD" + +NULL_VAL = 'N/A' +I2C_EEPROM_PATH = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom' PORT_START = 1 PORT_END = 34 @@ -165,24 +291,42 @@ class Sfp(SfpBase): """Platform-specific Sfp class""" - # Path to QSFP sysfs - PLATFORM_ROOT_PATH = "/usr/share/sonic/device" - PMON_HWSKU_PATH = "/usr/share/sonic/hwsku" - HOST_CHK_CMD = "docker > /dev/null 2>&1" + def __init__(self, sfp_index=0, sfp_name=None): + SfpBase.__init__(self) - PLATFORM = "x86_64-cel_silverstone-r0" - HWSKU = "Silverstone" + self._index = sfp_index + self.port_num = self._index + 1 + self._api_helper = APIHelper() + self._name = sfp_name + self._port_info_name = self._get_port_info_name() - def __init__(self, sfp_index): - SfpBase.__init__(self) - # Init index - self.index = sfp_index - self.port_num = self.index + 1 - self.dom_supported = False - self.sfp_type, self.port_name = self.__get_sfp_info() - - # Init eeprom path - eeprom_path = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom' + self._read_porttab_mappings() + self._detect_sfp_type() + self._dom_capability_detect() + self._eeprom_path = self._get_eeprom_path() + + def _get_port_info_name(self): + name = "QSFP" + str(self.port_num - OSFP_PORT_START + 1) if self.port_num in range( + OSFP_PORT_START, OSFP_PORT_END+1) else "SFP" + str(self.port_num - SFP_PORT_START + 1) + return name + + 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_helper.platform]) + hwsku_path = "/".join([host_platform_path, self._api_helper.hwsku]) \ + if self._api_helper.is_host() else docker_hwsku_path + + return "/".join([hwsku_path, "port_config.ini"]) + + def _get_eeprom_path(self): self.port_to_eeprom_mapping = {} self.port_to_i2c_mapping = { 1: 10, @@ -220,36 +364,9 @@ def __init__(self, sfp_index): 33: 1, 34: 2 } + return I2C_EEPROM_PATH.format(self.port_to_i2c_mapping.get(self.port_num)) - for x in range(PORT_START, PORT_END + 1): - port_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[x]) - self.port_to_eeprom_mapping[x] = port_eeprom_path - - self.info_dict_keys = ['type', 'hardware_rev', 'serial', 'manufacturer', 'model', 'connector', 'encoding', 'ext_identifier', - 'ext_rateselect_compliance', 'cable_type', 'cable_length', 'nominal_bit_rate', 'specification_compliance', 'vendor_date', 'vendor_oui'] - - self.dom_dict_keys = ['rx_los', 'tx_fault', 'reset_status', 'power_lpmode', 'tx_disable', 'tx_disable_channel', 'temperature', 'voltage', - 'rx1power', 'rx2power', 'rx3power', 'rx4power', 'tx1bias', 'tx2bias', 'tx3bias', 'tx4bias', 'tx1power', 'tx2power', 'tx3power', 'tx4power'] - - self.threshold_dict_keys = ['temphighalarm', 'temphighwarning', 'templowalarm', 'templowwarning', 'vcchighalarm', 'vcchighwarning', 'vcclowalarm', 'vcclowwarning', 'rxpowerhighalarm', 'rxpowerhighwarning', - 'rxpowerlowalarm', 'rxpowerlowwarning', 'txpowerhighalarm', 'txpowerhighwarning', 'txpowerlowalarm', 'txpowerlowwarning', 'txbiashighalarm', 'txbiashighwarning', 'txbiaslowalarm', 'txbiaslowwarning'] - - self._dom_capability_detect() - - def __get_sfp_info(self): - port_num = self.index + PORT_START - sfp_type = OSFP_PORT_START - port_name = "Unknown" - - if port_num >= OSFP_PORT_START and port_num <= OSFP_PORT_END: - sfp_type = OSFP_TYPE - port_name = "QSFP" + str(port_num - OSFP_PORT_START + 1) - elif port_num >= SFP_PORT_START and port_num <= SFP_PORT_END: - sfp_type = SFP_TYPE - port_name = "SFP" + str(port_num - SFP_PORT_START + 1) - return sfp_type, port_name - - def __convert_string_to_num(self, value_str): + def _convert_string_to_num(self, value_str): if "-inf" in value_str: return 'N/A' elif "Unknown" in value_str: @@ -269,37 +386,58 @@ def __convert_string_to_num(self, value_str): else: return 'N/A' - def __is_host(self): - return os.system(self.HOST_CHK_CMD) == 0 - - def __get_path_to_port_config_file(self): - platform_path = "/".join([self.PLATFORM_ROOT_PATH, self.PLATFORM]) - hwsku_path = "/".join([platform_path, self.HWSKU] - ) if self.__is_host() else self.PMON_HWSKU_PATH - return "/".join([hwsku_path, "port_config.ini"]) - - def __read_eeprom_specific_bytes(self, offset, num_bytes): - sysfsfile_eeprom = None + def _read_eeprom_specific_bytes(self, offset, num_bytes): + sysfs_sfp_i2c_client_eeprom_path = self._get_eeprom_path() eeprom_raw = [] + try: + eeprom = open( + sysfs_sfp_i2c_client_eeprom_path, + mode="rb", buffering=0) + except IOError: + return None + for i in range(0, num_bytes): eeprom_raw.append("0x00") - sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.port_num] try: - sysfsfile_eeprom = open( - sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0) - sysfsfile_eeprom.seek(offset) - raw = sysfsfile_eeprom.read(num_bytes) - for n in range(0, num_bytes): - eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) - except: - pass - finally: - if sysfsfile_eeprom: - sysfsfile_eeprom.close() + eeprom.seek(offset) + raw = eeprom.read(num_bytes) + except IOError: + eeprom.close() + return None + + try: + if isinstance(raw, str): + for n in range(0, num_bytes): + eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) + else: + for n in range(0, num_bytes): + eeprom_raw[n] = hex(raw[n])[2:].zfill(2) + + except BaseException: + eeprom.close() + return None + eeprom.close() return eeprom_raw + def _detect_sfp_type(self): + sfp_type = QSFP_TYPE + eeprom_raw = [] + eeprom_raw = self._read_eeprom_specific_bytes( + XCVR_TYPE_OFFSET, XCVR_TYPE_WIDTH) + if eeprom_raw: + if eeprom_raw[0] in SFP_TYPE_CODE_LIST: + self.sfp_type = SFP_TYPE + elif eeprom_raw[0] in QSFP_TYPE_CODE_LIST: + self.sfp_type = QSFP_TYPE + elif eeprom_raw[0] in QSFP_DD_TYPE_CODE_LIST: + self.sfp_type = QSFP_DD_TYPE + else: + self.sfp_type = sfp_type + else: + self.sfp_type = sfp_type + def _dom_capability_detect(self): if not self.get_presence(): self.dom_supported = False @@ -310,22 +448,26 @@ def _dom_capability_detect(self): self.calibration = 0 return - if self.sfp_type == "QSFP": + 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. + # 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) + + 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_raw = self._read_eeprom_specific_bytes( + QSFP_VERSION_COMPLIANCE_OFFSET, + QSFP_VERSION_COMPLIANCE_WIDTH) qsfp_version_compliance = int( qsfp_version_compliance_raw[0], 16) dom_capability = sfpi_obj.parse_dom_capability( @@ -346,7 +488,7 @@ def _dom_capability_detect(self): sfpd_obj = sff8436Dom() if sfpd_obj is None: return None - qsfp_option_value_raw = self.__read_eeprom_specific_bytes( + 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( @@ -365,11 +507,52 @@ def _dom_capability_detect(self): self.calibration = 0 self.qsfp_page3_available = False - elif self.sfp_type == "SFP": + elif self.sfp_type == QSFP_DD_TYPE: + sfpi_obj = qsfp_dd_InterfaceId() + if sfpi_obj is None: + self.dom_supported = False + + offset = 0 + # two types of QSFP-DD cable types supported: Copper and Optical. + qsfp_dom_capability_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_DOM_CAPABILITY_OFFSET_QSFP_DD), XCVR_DOM_CAPABILITY_WIDTH_QSFP_DD) + if qsfp_dom_capability_raw is not None: + self.dom_temp_supported = True + self.dom_volt_supported = True + dom_capability = sfpi_obj.parse_dom_capability( + qsfp_dom_capability_raw, 0) + if dom_capability['data']['Flat_MEM']['value'] == 'Off': + self.dom_supported = True + self.second_application_list = True + self.dom_rx_power_supported = True + self.dom_tx_power_supported = True + self.dom_tx_bias_power_supported = True + self.dom_thresholds_supported = True + # currently set to False becasue Page 11h is not supported by FW + self.dom_rx_tx_power_bias_supported = False + else: + self.dom_supported = False + self.second_application_list = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.dom_tx_bias_power_supported = False + self.dom_thresholds_supported = False + self.dom_rx_tx_power_bias_supported = False + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.dom_tx_bias_power_supported = False + self.dom_thresholds_supported = False + self.dom_rx_tx_power_bias_supported = False + + elif self.sfp_type == SFP_TYPE: sfpi_obj = sff8472InterfaceId() if sfpi_obj is None: return None - sfp_dom_capability_raw = self.__read_eeprom_specific_bytes( + 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) @@ -400,12 +583,32 @@ def _dom_capability_detect(self): self.dom_rx_power_supported = False self.dom_tx_power_supported = False + def _convert_string_to_num(self, value_str): + if "-inf" in value_str: + return 'N/A' + elif "Unknown" in value_str: + return 'N/A' + elif 'dBm' in value_str: + t_str = value_str.rstrip('dBm') + return float(t_str) + elif 'mA' in value_str: + t_str = value_str.rstrip('mA') + return float(t_str) + elif 'C' in value_str: + t_str = value_str.rstrip('C') + return float(t_str) + elif 'Volts' in value_str: + t_str = value_str.rstrip('Volts') + return float(t_str) + else: + return 'N/A' + def 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 @@ -422,12 +625,15 @@ def get_transceiver_info(self): 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(self.info_dict_keys, 'N/A') - if not self.get_presence(): - return transceiver_info_dict + transceiver_info_dict = dict.fromkeys( + info_dict_keys, NULL_VAL) + transceiver_info_dict["specification_compliance"] = '{}' # ToDo: OSFP tranceiver info parsing not fully supported. # in inf8628.py lack of some memory map definition @@ -438,91 +644,232 @@ def get_transceiver_info(self): sfpi_obj = inf8628InterfaceId() if sfpi_obj is None: - return None + return transceiver_info_dict - sfp_type_raw = self.__read_eeprom_specific_bytes( + 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 + return transceiver_info_dict - sfp_vendor_name_raw = self.__read_eeprom_specific_bytes( + 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 + return transceiver_info_dict - sfp_vendor_pn_raw = self.__read_eeprom_specific_bytes( + 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 + return transceiver_info_dict - sfp_vendor_rev_raw = self.__read_eeprom_specific_bytes( + 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 + return transceiver_info_dict - sfp_vendor_sn_raw = self.__read_eeprom_specific_bytes( + 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 + return transceiver_info_dict transceiver_info_dict['type'] = sfp_type_data['data']['type']['value'] transceiver_info_dict['manufacturer'] = sfp_vendor_name_data['data']['Vendor Name']['value'] transceiver_info_dict['model'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] transceiver_info_dict['hardware_rev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] transceiver_info_dict['serial'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] - transceiver_info_dict['vendor_oui'] = 'N/A' - transceiver_info_dict['vendor_date'] = 'N/A' - transceiver_info_dict['connector'] = 'N/A' - transceiver_info_dict['encoding'] = 'N/A' - transceiver_info_dict['ext_identifier'] = 'N/A' - transceiver_info_dict['ext_rateselect_compliance'] = 'N/A' - transceiver_info_dict['cable_type'] = 'N/A' - transceiver_info_dict['cable_length'] = 'N/A' - transceiver_info_dict['specification_compliance'] = 'N/A' - transceiver_info_dict['nominal_bit_rate'] = 'N/A' - else: - if self.sfp_type == QSFP_TYPE: - offset = 128 - vendor_rev_width = XCVR_HW_REV_WIDTH_QSFP - cable_length_width = XCVR_CABLE_LENGTH_WIDTH_QSFP - interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_QSFP - sfp_type = 'QSFP' - - sfpi_obj = sff8436InterfaceId() - if sfpi_obj is None: - print("Error: sfp_object open failed") - return None + elif self.sfp_type == QSFP_TYPE: + offset = 128 + vendor_rev_width = XCVR_HW_REV_WIDTH_QSFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_QSFP + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + + elif self.sfp_type == QSFP_DD_TYPE: + offset = 128 + + sfpi_obj = qsfp_dd_InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + + sfp_type_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_TYPE_OFFSET), XCVR_TYPE_WIDTH) + if sfp_type_raw is not None: + sfp_type_data = sfpi_obj.parse_sfp_type(sfp_type_raw, 0) + sfp_type_abbrv_name_data = sfpi_obj.parse_sfp_type_abbrv_name( + sfp_type_raw, 0) else: - offset = 0 - vendor_rev_width = XCVR_HW_REV_WIDTH_SFP - cable_length_width = XCVR_CABLE_LENGTH_WIDTH_SFP - interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_SFP - sfp_type = 'SFP' - - sfpi_obj = sff8472InterfaceId() - if sfpi_obj is None: - print("Error: sfp_object open failed") - return None - sfp_interface_bulk_raw = self.__read_eeprom_specific_bytes( + return transceiver_info_dict + + sfp_vendor_name_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH) + if sfp_vendor_name_raw is not None: + sfp_vendor_name_data = sfpi_obj.parse_vendor_name( + sfp_vendor_name_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_pn_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH) + if sfp_vendor_pn_raw is not None: + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn( + sfp_vendor_pn_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_rev_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_HW_REV_OFFSET_QSFP_DD), XCVR_HW_REV_WIDTH_QSFP_DD) + if sfp_vendor_rev_raw is not None: + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev( + sfp_vendor_rev_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_sn_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH) + if sfp_vendor_sn_raw is not None: + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn( + sfp_vendor_sn_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_oui_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_VENDOR_OUI_OFFSET), XCVR_VENDOR_OUI_WIDTH) + if sfp_vendor_oui_raw is not None: + sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui( + sfp_vendor_oui_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_date_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_VENDOR_DATE_OFFSET_QSFP_DD), XCVR_VENDOR_DATE_WIDTH_QSFP_DD) + if sfp_vendor_date_raw is not None: + sfp_vendor_date_data = sfpi_obj.parse_vendor_date( + sfp_vendor_date_raw, 0) + else: + return transceiver_info_dict + + sfp_connector_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_CONNECTOR_OFFSET_QSFP_DD), XCVR_CONNECTOR_WIDTH_QSFP_DD) + if sfp_connector_raw is not None: + sfp_connector_data = sfpi_obj.parse_connector( + sfp_connector_raw, 0) + else: + return transceiver_info_dict + + sfp_ext_identifier_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_EXT_TYPE_OFFSET_QSFP_DD), XCVR_EXT_TYPE_WIDTH_QSFP_DD) + if sfp_ext_identifier_raw is not None: + sfp_ext_identifier_data = sfpi_obj.parse_ext_iden( + sfp_ext_identifier_raw, 0) + else: + return transceiver_info_dict + + sfp_cable_len_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_CABLE_LENGTH_OFFSET_QSFP_DD), XCVR_CABLE_LENGTH_WIDTH_QSFP_DD) + if sfp_cable_len_raw is not None: + sfp_cable_len_data = sfpi_obj.parse_cable_len( + sfp_cable_len_raw, 0) + else: + return transceiver_info_dict + + sfp_media_type_raw = self._read_eeprom_specific_bytes( + XCVR_MEDIA_TYPE_OFFSET_QSFP_DD, XCVR_MEDIA_TYPE_WIDTH_QSFP_DD) + if sfp_media_type_raw is not None: + sfp_media_type_dict = sfpi_obj.parse_media_type( + sfp_media_type_raw, 0) + if sfp_media_type_dict is None: + return transceiver_info_dict + + host_media_list = "" + sfp_application_type_first_list = self._read_eeprom_specific_bytes( + (XCVR_FIRST_APPLICATION_LIST_OFFSET_QSFP_DD), XCVR_FIRST_APPLICATION_LIST_WIDTH_QSFP_DD) + if self.second_application_list: + possible_application_count = 15 + sfp_application_type_second_list = self._read_eeprom_specific_bytes( + (XCVR_SECOND_APPLICATION_LIST_OFFSET_QSFP_DD), XCVR_SECOND_APPLICATION_LIST_WIDTH_QSFP_DD) + if sfp_application_type_first_list is not None and sfp_application_type_second_list is not None: + sfp_application_type_list = sfp_application_type_first_list + \ + sfp_application_type_second_list + else: + return transceiver_info_dict + else: + possible_application_count = 8 + if sfp_application_type_first_list is not None: + sfp_application_type_list = sfp_application_type_first_list + else: + return transceiver_info_dict + + for i in range(0, possible_application_count): + if sfp_application_type_list[i * 4] == 'ff': + break + host_electrical, media_interface = sfpi_obj.parse_application( + sfp_media_type_dict, sfp_application_type_list[i * 4], sfp_application_type_list[i * 4 + 1]) + host_media_list = host_media_list + host_electrical + \ + ' - ' + media_interface + '\n\t\t\t\t ' + else: + return transceiver_info_dict + + transceiver_info_dict['type'] = str( + sfp_type_data['data']['type']['value']) + transceiver_info_dict['manufacturer'] = str( + sfp_vendor_name_data['data']['Vendor Name']['value']) + transceiver_info_dict['model'] = str( + sfp_vendor_pn_data['data']['Vendor PN']['value']) + transceiver_info_dict['hardware_rev'] = str( + sfp_vendor_rev_data['data']['Vendor Rev']['value']) + transceiver_info_dict['serial'] = str( + sfp_vendor_sn_data['data']['Vendor SN']['value']) + transceiver_info_dict['vendor_oui'] = str( + sfp_vendor_oui_data['data']['Vendor OUI']['value']) + transceiver_info_dict['vendor_date'] = str( + sfp_vendor_date_data['data']['VendorDataCode(YYYY-MM-DD Lot)']['value']) + transceiver_info_dict['connector'] = str( + sfp_connector_data['data']['Connector']['value']) + transceiver_info_dict['encoding'] = "Not supported for CMIS cables" + transceiver_info_dict['ext_identifier'] = str( + sfp_ext_identifier_data['data']['Extended Identifier']['value']) + transceiver_info_dict['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 + transceiver_info_dict['type_abbrv_name'] = str( + sfp_type_abbrv_name_data['data']['type_abbrv_name']['value']) + transceiver_info_dict['specification_compliance'] = type_of_media_interface[sfp_media_type_raw[0]] + + else: + offset = 0 + vendor_rev_width = XCVR_HW_REV_WIDTH_SFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_SFP + + sfpi_obj = sff8472InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + + if self.sfp_type != QSFP_DD_TYPE: + sfp_interface_bulk_raw = self._read_eeprom_specific_bytes( offset + XCVR_INTERFACE_DATA_START, XCVR_INTERFACE_DATA_SIZE) if sfp_interface_bulk_raw is None: - return None + return transceiver_info_dict start = XCVR_INTFACE_BULK_OFFSET - XCVR_INTERFACE_DATA_START end = start + interface_info_bulk_width @@ -558,6 +905,7 @@ def get_transceiver_info(self): 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'] @@ -570,6 +918,7 @@ def get_transceiver_info(self): 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']: @@ -580,9 +929,16 @@ def get_transceiver_info(self): 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: @@ -628,7 +984,8 @@ def get_transceiver_bulk_status(self): | |for example, tx2power stands for tx power of channel 2. ======================================================================== """ - transceiver_dom_info_dict = dict.fromkeys(self.dom_dict_keys, 'N/A') + transceiver_dom_info_dict = dict.fromkeys( + dom_info_dict_keys, NULL_VAL) if self.sfp_type == OSFP_TYPE: pass @@ -642,7 +999,7 @@ def get_transceiver_bulk_status(self): if sfpd_obj is None: return transceiver_dom_info_dict - dom_data_raw = self.__read_eeprom_specific_bytes( + 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 @@ -652,7 +1009,7 @@ def get_transceiver_bulk_status(self): end = start + QSFP_TEMPE_WIDTH dom_temperature_data = sfpd_obj.parse_temperature( dom_data_raw[start: end], 0) - temp = self.__convert_string_to_num( + temp = self._convert_string_to_num( dom_temperature_data['data']['Temperature']['value']) if temp is not None: transceiver_dom_info_dict['temperature'] = temp @@ -662,7 +1019,7 @@ def get_transceiver_bulk_status(self): end = start + QSFP_VOLT_WIDTH dom_voltage_data = sfpd_obj.parse_voltage( dom_data_raw[start: end], 0) - volt = self.__convert_string_to_num( + volt = self._convert_string_to_num( dom_voltage_data['data']['Vcc']['value']) if volt is not None: transceiver_dom_info_dict['voltage'] = volt @@ -673,23 +1030,23 @@ def get_transceiver_bulk_status(self): dom_data_raw[start: end], 0) if self.dom_tx_power_supported: - transceiver_dom_info_dict['tx1power'] = self.__convert_string_to_num( + transceiver_dom_info_dict['tx1power'] = self._convert_string_to_num( dom_channel_monitor_data['data']['TX1Power']['value']) - transceiver_dom_info_dict['tx2power'] = self.__convert_string_to_num( + transceiver_dom_info_dict['tx2power'] = self._convert_string_to_num( dom_channel_monitor_data['data']['TX2Power']['value']) - transceiver_dom_info_dict['tx3power'] = self.__convert_string_to_num( + transceiver_dom_info_dict['tx3power'] = self._convert_string_to_num( dom_channel_monitor_data['data']['TX3Power']['value']) - transceiver_dom_info_dict['tx4power'] = self.__convert_string_to_num( + transceiver_dom_info_dict['tx4power'] = self._convert_string_to_num( dom_channel_monitor_data['data']['TX4Power']['value']) if self.dom_rx_power_supported: - transceiver_dom_info_dict['rx1power'] = self.__convert_string_to_num( + transceiver_dom_info_dict['rx1power'] = self._convert_string_to_num( dom_channel_monitor_data['data']['RX1Power']['value']) - transceiver_dom_info_dict['rx2power'] = self.__convert_string_to_num( + transceiver_dom_info_dict['rx2power'] = self._convert_string_to_num( dom_channel_monitor_data['data']['RX2Power']['value']) - transceiver_dom_info_dict['rx3power'] = self.__convert_string_to_num( + transceiver_dom_info_dict['rx3power'] = self._convert_string_to_num( dom_channel_monitor_data['data']['RX3Power']['value']) - transceiver_dom_info_dict['rx4power'] = self.__convert_string_to_num( + transceiver_dom_info_dict['rx4power'] = self._convert_string_to_num( dom_channel_monitor_data['data']['RX4Power']['value']) transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TX1Bias']['value'] @@ -697,6 +1054,104 @@ def get_transceiver_bulk_status(self): 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 = self._convert_string_to_num( + 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 = self._convert_string_to_num( + 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 + offset = 512 + dom_data_raw = self._read_eeprom_specific_bytes( + offset + 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(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX1Power']['value'])) + transceiver_dom_info_dict['tx2power'] = str(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX2Power']['value'])) + transceiver_dom_info_dict['tx3power'] = str(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX3Power']['value'])) + transceiver_dom_info_dict['tx4power'] = str(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX4Power']['value'])) + transceiver_dom_info_dict['tx5power'] = str(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX5Power']['value'])) + transceiver_dom_info_dict['tx6power'] = str(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX6Power']['value'])) + transceiver_dom_info_dict['tx7power'] = str(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX7Power']['value'])) + transceiver_dom_info_dict['tx8power'] = str(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX8Power']['value'])) + + if self.dom_rx_power_supported: + transceiver_dom_info_dict['rx1power'] = str(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX1Power']['value'])) + transceiver_dom_info_dict['rx2power'] = str(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX2Power']['value'])) + transceiver_dom_info_dict['rx3power'] = str(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX3Power']['value'])) + transceiver_dom_info_dict['rx4power'] = str(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX4Power']['value'])) + transceiver_dom_info_dict['rx5power'] = str(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX5Power']['value'])) + transceiver_dom_info_dict['rx6power'] = str(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX6Power']['value'])) + transceiver_dom_info_dict['rx7power'] = str(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX7Power']['value'])) + transceiver_dom_info_dict['rx8power'] = str(self._convert_string_to_num( + 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 @@ -707,7 +1162,7 @@ def get_transceiver_bulk_status(self): return transceiver_dom_info_dict sfpd_obj._calibration_type = self.calibration - dom_data_raw = self.__read_eeprom_specific_bytes( + 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 @@ -725,27 +1180,23 @@ def get_transceiver_bulk_status(self): dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( dom_data_raw[start: end], 0) - transceiver_dom_info_dict['temperature'] = self.__convert_string_to_num( + transceiver_dom_info_dict['temperature'] = self._convert_string_to_num( dom_temperature_data['data']['Temperature']['value']) - transceiver_dom_info_dict['voltage'] = self.__convert_string_to_num( + transceiver_dom_info_dict['voltage'] = self._convert_string_to_num( dom_voltage_data['data']['Vcc']['value']) - transceiver_dom_info_dict['rx1power'] = self.__convert_string_to_num( + transceiver_dom_info_dict['rx1power'] = self._convert_string_to_num( dom_channel_monitor_data['data']['RXPower']['value']) - transceiver_dom_info_dict['tx1bias'] = self.__convert_string_to_num( + transceiver_dom_info_dict['tx1bias'] = self._convert_string_to_num( dom_channel_monitor_data['data']['TXBias']['value']) - transceiver_dom_info_dict['tx1power'] = self.__convert_string_to_num( + transceiver_dom_info_dict['tx1power'] = self._convert_string_to_num( dom_channel_monitor_data['data']['TXPower']['value']) - transceiver_dom_info_dict['rx_los'] = self.get_rx_los() - transceiver_dom_info_dict['tx_fault'] = self.get_tx_fault() - transceiver_dom_info_dict['reset_status'] = self.get_reset_status() - transceiver_dom_info_dict['lp_mode'] = self.get_lpmode() - return transceiver_dom_info_dict def get_transceiver_threshold_info(self): """ Retrieves transceiver threshold info of this SFP + Returns: A dict which contains following keys/values : ======================================================================== @@ -774,7 +1225,7 @@ def get_transceiver_threshold_info(self): ======================================================================== """ transceiver_dom_threshold_info_dict = dict.fromkeys( - self.threshold_dict_keys, 'N/A') + threshold_dict_keys, NULL_VAL) if self.sfp_type == OSFP_TYPE: pass @@ -790,7 +1241,7 @@ def get_transceiver_threshold_info(self): if sfpd_obj is None: return transceiver_dom_threshold_info_dict - dom_module_threshold_raw = self.__read_eeprom_specific_bytes( + 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 @@ -798,8 +1249,8 @@ def get_transceiver_threshold_info(self): 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) + 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( @@ -827,6 +1278,49 @@ def get_transceiver_threshold_info(self): 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 @@ -837,8 +1331,8 @@ def get_transceiver_threshold_info(self): 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) + 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) @@ -868,6 +1362,10 @@ def get_transceiver_threshold_info(self): 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): @@ -875,6 +1373,16 @@ def get_reset_status(self): Retrieves the reset status of SFP Returns: A Boolean, True if reset enabled, False if disabled + for QSFP, originally I would like to make use of Initialization complete flag bit + which is at Page a0 offset 6 bit 0 to test whether reset is complete. + However as unit testing was carried out I find this approach may fail because: + 1. we make use of ethtool to read data on I2C bus rather than to read directly + 2. ethtool is unable to access I2C during QSFP module being reset + In other words, whenever the flag is able to be retrived, the value is always be 1 + As a result, it doesn't make sense to retrieve that flag. Just treat successfully + retrieving data as "data ready". + for SFP it seems that there is not flag indicating whether reset succeed. However, + we can also do it in the way for QSFP. """ if not self.dom_supported: return False @@ -884,7 +1392,7 @@ def get_reset_status(self): elif self.sfp_type == QSFP_TYPE: offset = 0 sfpd_obj = sff8436Dom() - dom_module_monitor_raw = self.__read_eeprom_specific_bytes( + dom_module_monitor_raw = self._read_eeprom_specific_bytes( (offset + QSFP_MODULE_MONITOR_OFFSET), QSFP_MODULE_MONITOR_WIDTH) if dom_module_monitor_raw is not None: @@ -894,13 +1402,25 @@ def get_reset_status(self): elif self.sfp_type == SFP_TYPE: offset = 0 sfpd_obj = sff8472Dom() - dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + 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: return True else: return False + elif self.sfp_type == QSFP_DD_TYPE: + offset = 0 + sfpd_obj = qsfp_dd_Dom() + dom_channel_status_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_CHANNL_STATUS_OFFSET), QSFP_DD_CHANNL_STATUS_WIDTH) + + if dom_channel_status_raw is None: + return False + + dom_channel_status_data = sfpd_obj.parse_dom_channel_status( + dom_channel_status_raw, 0) + return dom_channel_status_data['data']['Status']['value'] == 'On' def get_rx_los(self): """ @@ -909,31 +1429,52 @@ def get_rx_los(self): 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) + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_RX_LOS_STATUS_OFFSET), + QSFP_CHANNL_RX_LOS_STATUS_WIDTH) if dom_channel_monitor_raw is not None: rx_los_data = int(dom_channel_monitor_raw[0], 16) rx_los_list.append(rx_los_data & 0x01 != 0) rx_los_list.append(rx_los_data & 0x02 != 0) rx_los_list.append(rx_los_data & 0x04 != 0) rx_los_list.append(rx_los_data & 0x08 != 0) + else: + return [False] * 4 + + elif self.sfp_type == QSFP_DD_TYPE: + # page 11h + if self.dom_rx_tx_power_bias_supported: + offset = 128 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_CHANNL_RX_LOS_STATUS_OFFSET), + QSFP_DD_CHANNL_RX_LOS_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 8) + rx_los_list.append(rx_los_data & 0x01 != 0) + rx_los_list.append(rx_los_data & 0x02 != 0) + rx_los_list.append(rx_los_data & 0x04 != 0) + rx_los_list.append(rx_los_data & 0x08 != 0) + rx_los_list.append(rx_los_data & 0x10 != 0) + rx_los_list.append(rx_los_data & 0x20 != 0) + rx_los_list.append(rx_los_data & 0x40 != 0) + rx_los_list.append(rx_los_data & 0x80 != 0) + else: + return [False] * 8 else: offset = 256 - dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + 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 [False] return rx_los_list def get_tx_fault(self): @@ -943,25 +1484,45 @@ def get_tx_fault(self): 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) + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_TX_FAULT_STATUS_OFFSET), + QSFP_CHANNL_TX_FAULT_STATUS_WIDTH) if dom_channel_monitor_raw is not None: tx_fault_data = int(dom_channel_monitor_raw[0], 16) tx_fault_list.append(tx_fault_data & 0x01 != 0) tx_fault_list.append(tx_fault_data & 0x02 != 0) tx_fault_list.append(tx_fault_data & 0x04 != 0) tx_fault_list.append(tx_fault_data & 0x08 != 0) + else: + return [False] * 4 + elif self.sfp_type == QSFP_DD_TYPE: + # page 11h + if self.dom_rx_tx_power_bias_supported: + offset = 128 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_CHANNL_TX_FAULT_STATUS_OFFSET), + QSFP_DD_CHANNL_TX_FAULT_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_fault_data = int(dom_channel_monitor_raw[0], 8) + tx_fault_list.append(tx_fault_data & 0x01 != 0) + tx_fault_list.append(tx_fault_data & 0x02 != 0) + tx_fault_list.append(tx_fault_data & 0x04 != 0) + tx_fault_list.append(tx_fault_data & 0x08 != 0) + tx_fault_list.append(tx_fault_data & 0x10 != 0) + tx_fault_list.append(tx_fault_data & 0x20 != 0) + tx_fault_list.append(tx_fault_data & 0x40 != 0) + tx_fault_list.append(tx_fault_data & 0x80 != 0) + else: + return [False] * 8 else: offset = 256 - dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + 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) @@ -974,33 +1535,55 @@ def get_tx_disable(self): """ Retrieves the tx_disable status of this SFP Returns: - A Boolean, True if tx_disable is enabled, False if disabled + 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) + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_DISABLE_STATUS_OFFSET), + QSFP_CHANNL_DISABLE_STATUS_WIDTH) if dom_channel_monitor_raw is not None: tx_disable_data = int(dom_channel_monitor_raw[0], 16) tx_disable_list.append(tx_disable_data & 0x01 != 0) tx_disable_list.append(tx_disable_data & 0x02 != 0) tx_disable_list.append(tx_disable_data & 0x04 != 0) tx_disable_list.append(tx_disable_data & 0x08 != 0) + else: + return [False] * 4 + + elif self.sfp_type == QSFP_DD_TYPE: + if self.dom_rx_tx_power_bias_supported: + offset = 128 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_CHANNL_DISABLE_STATUS_OFFSET), + QSFP_DD_CHANNL_DISABLE_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0x01 != 0) + tx_disable_list.append(tx_disable_data & 0x02 != 0) + tx_disable_list.append(tx_disable_data & 0x04 != 0) + tx_disable_list.append(tx_disable_data & 0x08 != 0) + tx_disable_list.append(tx_disable_data & 0x10 != 0) + tx_disable_list.append(tx_disable_data & 0x20 != 0) + tx_disable_list.append(tx_disable_data & 0x40 != 0) + tx_disable_list.append(tx_disable_data & 0x80 != 0) + else: + return [False] * 8 else: offset = 256 - dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + 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 [False] return tx_disable_list def get_tx_disable_channel(self): @@ -1009,7 +1592,7 @@ def get_tx_disable_channel(self): 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 + 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() @@ -1027,12 +1610,9 @@ def get_lpmode(self): Returns: A Boolean, True if lpmode is enabled, False if disabled """ - if self.sfp_type != OSFP_TYPE: - return False - try: reg_file = open( - "/".join([PORT_INFO_PATH, self.port_name, "qsfp_lpmode"])) + "/".join([PORT_INFO_PATH, self._port_info_name, "qsfp_lpmode"])) except IOError as e: print("Error: unable to open file: %s" % str(e)) return False @@ -1058,15 +1638,16 @@ def get_power_override(self): if sfpd_obj is None: return False - dom_control_raw = self.__read_eeprom_specific_bytes( - QSFP_CONTROL_OFFSET, QSFP_CONTROL_WIDTH) if self.get_presence() else None + 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) - power_override = ( - 'On' == dom_control_data['data']['PowerOverride']['value']) + return ('On' == dom_control_data['data']['PowerOverride']) + else: + return False else: - return False + return NotImplementedError def get_temperature(self): """ @@ -1074,8 +1655,61 @@ def get_temperature(self): Returns: An integer number of current temperature in Celsius """ - transceiver_bulk_status = self.get_transceiver_bulk_status() - return transceiver_bulk_status.get("temperature", "N/A") + default = 0.0 + if not self.dom_supported: + return default + + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return default + + if self.dom_temp_supported: + dom_temperature_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature( + dom_temperature_raw, 0) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + + elif self.sfp_type == QSFP_DD_TYPE: + offset = 0 + + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if self.dom_temp_supported: + dom_temperature_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_TEMPE_OFFSET), QSFP_DD_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature( + dom_temperature_raw, 0) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + + else: + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + sfpd_obj._calibration_type = 1 + + dom_temperature_raw = self._read_eeprom_specific_bytes( + (offset + SFP_TEMPE_OFFSET), SFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature( + dom_temperature_raw, 0) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + + return default def get_voltage(self): """ @@ -1083,8 +1717,62 @@ def get_voltage(self): Returns: An integer number of supply voltage in mV """ - transceiver_bulk_status = self.get_transceiver_bulk_status() - return transceiver_bulk_status.get("voltage", "N/A") + default = 0.0 + + if not self.dom_supported: + return default + + if self.sfp_type == QSFP_TYPE: + offset = 0 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return default + + if self.dom_volt_supported: + dom_voltage_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_VOLT_OFFSET), QSFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage( + dom_voltage_raw, 0) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + + if self.sfp_type == QSFP_DD_TYPE: + offset = 128 + + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if self.dom_volt_supported: + dom_voltage_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_VOLT_OFFSET), QSFP_DD_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage( + dom_voltage_raw, 0) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + + else: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + + sfpd_obj._calibration_type = self.calibration + + dom_voltage_raw = self._read_eeprom_specific_bytes( + (offset + SFP_VOLT_OFFSET), SFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + + return default def get_tx_bias(self): """ @@ -1094,12 +1782,87 @@ def get_tx_bias(self): for channel 0 to channel 4. Ex. ['110.09', '111.12', '108.21', '112.09'] """ - transceiver_bulk_status = self.get_transceiver_bulk_status() - tx1_bs = transceiver_bulk_status.get("tx1bias", "N/A") - tx2_bs = transceiver_bulk_status.get("tx2bias", "N/A") - tx3_bs = transceiver_bulk_status.get("tx3bias", "N/A") - tx4_bs = transceiver_bulk_status.get("tx4bias", "N/A") - tx_bias_list = [tx1_bs, tx2_bs, tx3_bs, tx4_bs] + tx_bias_list = [] + if self.sfp_type == QSFP_TYPE: + offset = 0 + default = [0.0] * 4 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return default + + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power( + dom_channel_monitor_raw, 0) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX1Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX2Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX3Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX4Bias']['value'])) + else: + return default + + elif self.sfp_type == QSFP_DD_TYPE: + default = [0.0] * 8 + # page 11h + if self.dom_rx_tx_power_bias_supported: + offset = 128 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if dom_tx_bias_power_supported: + dom_tx_bias_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_TX_BIAS_OFFSET), QSFP_DD_TX_BIAS_WIDTH) + if dom_tx_bias_raw is not None: + dom_tx_bias_data = sfpd_obj.parse_dom_tx_bias( + dom_tx_bias_raw, 0) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX1Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX2Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX3Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX4Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX5Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX6Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX7Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX8Bias']['value'])) + else: + return default + else: + return default + + else: + offset = 256 + default = [0.0] + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + sfpd_obj._calibration_type = self.calibration + + if self.dom_supported: + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( + dom_channel_monitor_raw, 0) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TXBias']['value'])) + else: + return default + else: + return default + return tx_bias_list def get_rx_power(self): @@ -1117,52 +1880,87 @@ def get_rx_power(self): elif self.sfp_type == QSFP_TYPE: offset = 0 - offset_xcvr = 128 - + default = [0.0] * 4 sfpd_obj = sff8436Dom() if sfpd_obj is None: - return None + return default if self.dom_rx_power_supported: - dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + 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( + 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( + 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( + 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( + rx_power_list.append(self._convert_string_to_num( dom_channel_monitor_data['data']['RX4Power']['value'])) else: - return None + return default else: - return None + return default + + elif self.sfp_type == QSFP_DD_TYPE: + default = [0.0] * 8 + # page 11 + if self.dom_rx_tx_power_bias_supported: + offset = 128 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if self.dom_rx_power_supported: + dom_rx_power_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_RX_POWER_OFFSET), QSFP_DD_RX_POWER_WIDTH) + if dom_rx_power_raw is not None: + dom_rx_power_data = sfpd_obj.parse_dom_rx_power( + dom_rx_power_raw, 0) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX1Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX2Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX3Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX4Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX5Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX6Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX7Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX8Power']['value'])) + else: + return default + else: + return default + else: offset = 256 - + default = [0.0] sfpd_obj = sff8472Dom() if sfpd_obj is None: - return None + return default if self.dom_supported: sfpd_obj._calibration_type = self.calibration - dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + 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( + rx_power_list.append(self._convert_string_to_num( dom_channel_monitor_data['data']['RXPower']['value'])) else: - return None + return default else: - return None - + return default return rx_power_list def get_tx_power(self): @@ -1176,54 +1974,95 @@ def get_tx_power(self): tx_power_list = [] if self.sfp_type == OSFP_TYPE: # OSFP not supported on our platform yet. - return None + return tx_power_list elif self.sfp_type == QSFP_TYPE: offset = 0 - offset_xcvr = 128 + default = [0.0] * 4 sfpd_obj = sff8436Dom() if sfpd_obj is None: - return None + return tx_power_list if self.dom_tx_power_supported: - dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( - (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + 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( + 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( + 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( + 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( + tx_power_list.append(self._convert_string_to_num( dom_channel_monitor_data['data']['TX4Power']['value'])) else: - return None + return default else: - return None + return default + + elif self.sfp_type == QSFP_DD_TYPE: + default = [0.0] * 8 + + # page 11 + if self.dom_rx_tx_power_bias_supported: + offset = 128 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if self.dom_tx_power_supported: + dom_tx_power_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_TX_POWER_OFFSET), + QSFP_DD_TX_POWER_WIDTH) + if dom_tx_power_raw is not None: + dom_tx_power_data = sfpd_obj.parse_dom_tx_power( + dom_tx_power_raw, 0) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX1Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX2Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX3Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX4Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX5Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX6Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX7Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX8Power']['value'])) + else: + return default + else: + return default + else: offset = 256 + default = [0.0] sfpd_obj = sff8472Dom() if sfpd_obj is None: - return None + return default if self.dom_supported: sfpd_obj._calibration_type = self.calibration - dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + 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( + tx_power_list.append(self._convert_string_to_num( dom_channel_monitor_data['data']['TXPower']['value'])) else: - return None + return default else: - return None + return default return tx_power_list def reset(self): @@ -1232,12 +2071,9 @@ def reset(self): Returns: A boolean, True if successful, False if not """ - if self.sfp_type != OSFP_TYPE: - return False - try: reg_file = open( - "/".join([PORT_INFO_PATH, self.port_name, "qsfp_resetL"]), "w") + "/".join([PORT_INFO_PATH, self._port_info_name, "qsfp_resetL"]), "w") except IOError as e: print("Error: unable to open file: %s" % str(e)) return False @@ -1253,7 +2089,7 @@ def reset(self): # Flip the bit back high and write back to the register to take port out of reset try: reg_file = open( - "/".join([PORT_INFO_PATH, self.port_name, "qsfp_resetL"]), "w") + "/".join([PORT_INFO_PATH, self._port_info_name, "qsfp_resetL"]), "w") except IOError as e: print("Error: unable to open file: %s" % str(e)) return False @@ -1276,16 +2112,12 @@ def tx_disable(self, tx_disable): 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) + tx_disable_value = 0xf if tx_disable else 0x0 # Write to eeprom - sysfsfile_eeprom = open( - self.port_to_eeprom_mapping[self.port_num], "r+b") + sysfsfile_eeprom = open(self._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)) + sysfsfile_eeprom.write(struct.pack('B', tx_disable_value)) + except IOError: return False finally: if sysfsfile_eeprom is not None: @@ -1308,20 +2140,15 @@ def tx_disable_channel(self, channel, disable): 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) + current_state = self.get_tx_disable_channel() + tx_disable_value = (current_state | channel) if \ + disable else (current_state & (~channel)) + # Write to eeprom - sysfsfile_eeprom = open( - self.port_to_eeprom_mapping[self.port_num], "r+b") + sysfsfile_eeprom = open(self._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)) + sysfsfile_eeprom.write(struct.pack('B', tx_disable_value)) + except IOError: return False finally: if sysfsfile_eeprom is not None: @@ -1339,12 +2166,9 @@ def set_lpmode(self, lpmode): Returns: A boolean, True if lpmode is set successfully, False if not """ - if self.sfp_type != OSFP_TYPE: - return False - try: reg_file = open( - "/".join([PORT_INFO_PATH, self.port_name, "qsfp_lpmode"]), "r+") + "/".join([PORT_INFO_PATH, self._port_info_name, "qsfp_lpmode"]), "r+") except IOError as e: print("Error: unable to open file: %s" % str(e)) return False @@ -1374,44 +2198,37 @@ def set_power_override(self, power_override, power_set): A boolean, True if power-override and power_set are set successfully, False if not """ - if self.sfp_type == QSFP_TYPE: + sysfsfile_eeprom = None + if self.sfp_type == QSFP_TYPE and self.get_presence(): 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 + power_override_bit = 0x1 if power_override else 0 + power_set_bit = 0x2 if power_set else 0 + value = power_override_bit | power_set_bit - buffer = create_string_buffer(1) - buffer[0] = chr(power_override_bit | power_set_bit) # Write to eeprom - sysfsfile_eeprom = open( - self.port_to_eeprom_mapping[self.port_num], "r+b") + sysfsfile_eeprom = open(self._eeprom_path, "r+b") sysfsfile_eeprom.seek(QSFP_POWEROVERRIDE_OFFSET) - sysfsfile_eeprom.write(buffer[0]) + sysfsfile_eeprom.write(struct.pack('B', value)) 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 True return False + ############################################################## + ###################### Device methods ######################## + ############################################################## + def get_name(self): """ Retrieves the name of the device Returns: string: The name of the device """ - sfputil_helper = SfpUtilHelper() - sfputil_helper.read_porttab_mappings( - self.__get_path_to_port_config_file()) - name = sfputil_helper.logical[self.index] or "Unknown" - return name + return self._name def get_presence(self): """ @@ -1420,7 +2237,8 @@ def get_presence(self): bool: True if PSU is present, False if not """ sysfs_filename = "sfp_modabs" if self.sfp_type == SFP_TYPE else "qsfp_modprsL" - reg_path = "/".join([PORT_INFO_PATH, self.port_name, sysfs_filename]) + reg_path = "/".join([PORT_INFO_PATH, + self._port_info_name, sysfs_filename]) # Read status try: @@ -1461,4 +2279,19 @@ def get_status(self): Returns: A boolean value, True if device is operating properly, False if not """ - return self.get_presence() + return self.get_presence() and not self.get_reset_status() + + def get_position_in_parent(self): + """ + Returns: + Temp return 0 + """ + return 0 + + def is_replaceable(self): + """ + Retrieves if replaceable + Returns: + A boolean value, True if replaceable + """ + return True diff --git a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/thermal.py b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/thermal.py index 9ecf12218d50..ab810a594f49 100644 --- a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/thermal.py +++ b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/thermal.py @@ -31,20 +31,34 @@ def __init__(self, thermal_index): self._api_helper = APIHelper() self.index = thermal_index self.THERMAL_LIST = [ - ('TEMP_FAN_U52', 'Fan Tray Middle Temperature Sensor', '0x00'), - ('TEMP_FAN_U17', 'Fan Tray Right Temperature Sensor', '0x01'), - ('TEMP_SW_U52', 'Switchboard Left Inlet Temperature Sensor', '0x02'), - ('TEMP_SW_U16', 'Switchboard Right Inlet Temperature Sensor', '0x03'), - ('TEMP_BB_U3', 'Baseboard Temperature Sensor', '0x04'), - ('TEMP_CPU', 'CPU Internal Temperature Sensor', '0x05'), - ('TEMP_SW_Internal', 'ASIC Internal Temperature Sensor', '0x61'), - ('SW_U04_Temp', 'IR3595 Chip Left Temperature Sensor', '0x4F'), - ('SW_U14_Temp', 'IR3595 Chip Right Temperature Sensor', '0x56'), - ('SW_U4403_Temp', 'IR3584 Chip Temperature Sensor', '0x5D'), + ('TEMP_FAN_U52', 'Fan Tray Middle Temperature Sensor', + '0x00', 'cpu'), + ('TEMP_FAN_U17', 'Fan Tray Right Temperature Sensor', + '0x01', 'cpu'), + ('TEMP_SW_U52', + 'Switchboard Left Inlet Temperature Sensor', '0x02', 'asic'), + ('TEMP_SW_U16', + 'Switchboard Right Inlet Temperature Sensor', '0x03', 'asic'), + ('TEMP_BB_U3', 'Baseboard Temperature Sensor', + '0x04', 'cpu'), + ('TEMP_CPU', 'CPU Internal Temperature Sensor', + '0x05', 'cpu'), + ('TEMP_SW_Internal', 'ASIC Internal Temperature Sensor', + '0x61', 'asic'), + ('SW_U04_Temp', 'IR3595 Chip Left Temperature Sensor', + '0x4F', 'asic'), + ('SW_U14_Temp', 'IR3595 Chip Right Temperature Sensor', + '0x56', 'asic'), + ('SW_U4403_Temp', 'IR3584 Chip Temperature Sensor', + '0x5D', 'asic'), ] self.sensor_id = self.THERMAL_LIST[self.index][0] self.sensor_des = self.THERMAL_LIST[self.index][1] self.sensor_reading_addr = self.THERMAL_LIST[self.index][2] + self.position = self.THERMAL_LIST[self.index][3] + + self.minimum_thermal = self.get_temperature() + self.maximum_thermal = self.get_temperature() def __set_threshold(self, key, value): print('{} {}'.format(key, value)) @@ -97,7 +111,8 @@ def set_high_threshold(self, temperature): Returns: A boolean, True if threshold is set successfully, False if not """ - status, ret_txt = self._api_helper.ipmi_set_ss_thres(self.sensor_id, HIGH_TRESHOLD_SET_KEY, temperature) + status, ret_txt = self._api_helper.ipmi_set_ss_thres( + self.sensor_id, HIGH_TRESHOLD_SET_KEY, temperature) return status def set_low_threshold(self, temperature): @@ -111,6 +126,49 @@ def set_low_threshold(self, temperature): """ return False + def get_high_critical_threshold(self): + """ + Retrieves the high critical threshold temperature of thermal + Returns: + A float number, the high critical threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + high_critical_threshold = 0.0 + status, raw_up_thres_read = self._api_helper.ipmi_raw( + IPMI_SENSOR_NETFN, IPMI_SS_THRESHOLD_CMD.format(self.sensor_reading_addr)) + if status and len(raw_up_thres_read.split()) > 6: + ss_read = raw_up_thres_read.split()[5] + high_critical_threshold = float(int(ss_read, 16)) + return high_critical_threshold + + def get_minimum_recorded(self): + """ + Retrieves the minimum recorded temperature of thermal + Returns: + A float number, the minimum recorded temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + tmp = self.get_temperature() + if tmp < self.minimum_thermal: + self.minimum_thermal = tmp + return self.minimum_thermal + + def get_maximum_recorded(self): + """ + Retrieves the maximum recorded temperature of thermal + Returns: + A float number, the maximum recorded temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + tmp = self.get_temperature() + if tmp > self.maximum_thermal: + self.maximum_thermal = tmp + return self.maximum_thermal + + ############################################################## + ###################### Device methods ######################## + ############################################################## + def get_name(self): """ Retrieves the name of the thermal device @@ -150,3 +208,21 @@ def get_status(self): A boolean value, True if device is operating properly, False if not """ return self.get_presence() + + def is_replaceable(self): + """ + Retrieves whether thermal module is replaceable + Returns: + A boolean value, True if replaceable, False if not + """ + return False + + def get_position_in_parent(self): + """ + Retrieves the thermal position information + Returns: + A int value, 0 represent ASIC thermal, 1 represent CPU thermal info + """ + if self.position == "cpu": + return 1 + return 0 diff --git a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/thermal_manager.py b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/thermal_manager.py new file mode 100644 index 000000000000..5c70ccc80e93 --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/thermal_manager.py @@ -0,0 +1,21 @@ +from sonic_platform_base.sonic_thermal_control.thermal_manager_base import ThermalManagerBase + + +class ThermalManager(ThermalManagerBase): + @classmethod + def initialize(cls): + """ + Initialize thermal manager, including register thermal condition types and thermal action types + and any other vendor specific initialization. + :return: + """ + return True + + @classmethod + def deinitialize(cls): + """ + Destroy thermal manager, including any vendor specific cleanup. The default behavior of this function + is a no-op. + :return: + """ + return True diff --git a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/watchdog.py b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/watchdog.py new file mode 100644 index 000000000000..4d2f6569ce80 --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/watchdog.py @@ -0,0 +1,180 @@ +############################################################################# +# 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 .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +PLATFORM_CPLD_PATH = '/sys/devices/platform/baseboard-lpc/' +GETREG_FILE = 'getreg' +SETREG_FILE = 'setreg' +WDT_TIMER_REG = '0XA181' +WDT_ENABLE_REG = '0xA182' +WDT_KEEP_ALVIVE_REG = '0xA184' +ENABLE_CMD = '0x1' +DISABLE_CMD = '0x0' +WDT_COMMON_ERROR = -1 + + +class Watchdog(WatchdogBase): + + def __init__(self): + WatchdogBase.__init__(self) + + self._api_helper = APIHelper() + + # 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 0xA182 0x1 > /sys/devices/platform/baseboard-lpc/setreg + enable_val = '{} {}'.format(WDT_ENABLE_REG, ENABLE_CMD) + return self._api_helper.write_txt_file(self.setreg_path, enable_val) + + def _disable(self): + """ + Turn off the watchdog timer + """ + # echo 0xA182 0x0 > /sys/devices/platform/baseboard-lpc/setreg + disable_val = '{} {}'.format(WDT_ENABLE_REG, DISABLE_CMD) + return self._api_helper.write_txt_file(self.setreg_path, disable_val) + + def _keepalive(self): + """ + Keep alive watchdog timer + """ + # echo 0xA184 0x1 > /sys/devices/platform/baseboard-lpc/setreg + enable_val = '{} {}'.format(WDT_KEEP_ALVIVE_REG, ENABLE_CMD) + return self._api_helper.write_txt_file(self.setreg_path, enable_val) + + def _settimeout(self, seconds): + """ + Set watchdog timer timeout + @param seconds - timeout in seconds + @return is the actual set timeout + """ + second_int = { + 30: 1, + 60: 2, + 180: 3, + 240: 4, + 300: 5, + 420: 6, + 600: 7, + }.get(seconds) + + self._api_helper.write_txt_file(self.setreg_path, second_int) + return seconds + + def _gettimeout(self): + """ + Get watchdog timeout + @return watchdog timeout + """ + hex_str = self._api_helper.get_cpld_reg_value( + self.getreg_path, WDT_TIMER_REG) + bin_val = bin(int(hex_str, 16))[2:].zfill(3) + + return { + '001': 30, + '010': 60, + '011': 180, + '100': 240, + '101': 300, + '110': 420, + '111': 600 + }.get(bin_val) + + ################################################################# + + 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. + """ + + avaliable_second = [30, 60, 180, 240, 300, 420, 600] + ret = WDT_COMMON_ERROR + + if seconds < 0 or seconds not in avaliable_second: + return ret + + try: + if self.timeout != seconds: + self.timeout = self._settimeout(seconds) + + if self.armed: + self._keepalive() + else: + self._enable() + self.armed = True + print("read armed") + + ret = self.timeout + self.arm_timestamp = time.time() + except IOError as e: + print(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-silverstone.init b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.init index eb003599ec61..0ef11642d41f 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.init +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.init @@ -17,17 +17,36 @@ start) echo -n "Setting up board... " modprobe i2c-dev - modprobe baseboard-lpc - modprobe switchboard - modprobe mc24lc64t modprobe ipmi_devintf + modprobe baseboard-lpc + modprobe cls-switchboard + modprobe xcvr-cls + modprobe switch_cpld - # Instantiate TLV EEPROM device on I801 bus + # Instantiate TLV EEPROM device on I801 bus devname=`cat /sys/bus/i2c/devices/i2c-0/name` if [[ $devname == 'SMBus I801 adapter at '* ]]; then echo 24lc64t 0x56 > /sys/bus/i2c/devices/i2c-0/new_device fi + + # Clear syseeprom cache decode-syseeprom --init 2> /dev/null & + sleep 1 + + # Attach switchboard CPLD i2c device + echo switch_cpld 0x30 > /sys/bus/i2c/devices/i2c-4/new_device + + # Attach Optical Module EEPROM + # use optoe2 for SFP+. + for i in {1..2} + do + echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-$i/new_device + done + # use optoe3 for QSFP-DD. + for i in {10..41} + do + echo optoe3 0x50 > /sys/bus/i2c/devices/i2c-$i/new_device + done /bin/sh /usr/local/bin/platform_api_mgnt.sh init @@ -48,4 +67,4 @@ force-reload|restart) ;; esac -exit 0 \ No newline at end of file +exit 0 diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.install b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.install index 67b433ced85f..6b230af14ea4 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.install +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.install @@ -3,4 +3,5 @@ silverstone/scripts/platform_sensors.py usr/local/bin silverstone/cfg/silverstone-modules.conf etc/modules-load.d silverstone/systemd/platform-modules-silverstone.service lib/systemd/system silverstone/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/x86_64-cel_silverstone-r0 +silverstone/modules/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-cel_silverstone-r0 services/platform_api/platform_api_mgnt.sh usr/local/bin diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/Makefile b/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/Makefile index f6ad4d9ba4d1..fd9b634f94db 100644 --- a/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/Makefile +++ b/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/Makefile @@ -1 +1 @@ -obj-m := baseboard-lpc.o mc24lc64t.o switchboard.o \ No newline at end of file +obj-m := baseboard-lpc.o mc24lc64t.o cls-switchboard.o xcvr-cls.o switch_cpld.o \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/cls-switchboard.c b/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/cls-switchboard.c new file mode 100644 index 000000000000..5c8d9bd0c507 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/cls-switchboard.c @@ -0,0 +1,542 @@ +/* + * cls-switchboard.c - PCI device driver for Silverstone Switch board FPGA. + * + * Author: Pradchaya Phucharoen + * + * Copyright (C) 2019 Celestica Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xcvr-cls.h" + +#define MOD_VERSION "2.1.2" +#define DRV_NAME "cls-switchboard" + +#define I2C_MUX_CHANNEL(_ch, _adap_id, _deselect) \ + [_ch] = { .adap_id = _adap_id, .deselect_on_exit = _deselect } + +#define FPGA_PCIE_DEVICE_ID 0x7021 +#define MMIO_BAR 0 +#define I2C_BUS_OFS 9 + +/* I2C ocore configurations */ +#define OCORE_REGSHIFT 2 +#define OCORE_IP_CLK_khz 62500 +#define OCORE_BUS_CLK_khz 100 +#define OCORE_REG_IO_WIDTH 1 + +/* Optical port xcvr configuration */ +#define XCVR_REG_SHIFT 2 +#define XCVR_NUM_PORT 34 +#define XCVR_PORT_REG_SIZE 0x10 + +/* i2c_bus_config - an i2c-core resource and platform data + * @id - I2C bus device ID, for identification. + * @res - resources for an i2c-core device. + * @num_res - size of the resources. + * @pdata - a platform data of an i2c-core device. + */ +struct i2c_bus_config { + int id; + struct resource *res; + ssize_t num_res; + struct ocores_i2c_platform_data pdata; +}; + +/* switchbrd_priv - switchboard private data */ +struct switchbrd_priv { + unsigned long base; + int num_i2c_bus; + struct platform_device **i2cbuses_pdev; + struct platform_device *regio_pdev; + struct platform_device *spiflash_pdev; + struct platform_device *xcvr_pdev; +}; + +/* I2C bus speed param */ +static int bus_clock_master_1 = 100; +module_param(bus_clock_master_1, int, 0660); +MODULE_PARM_DESC(bus_clock_master_1, + "I2C master 1 bus speed in KHz 50/80/100/200/400"); + +static int bus_clock_master_2 = 100; +module_param(bus_clock_master_2, int, 0660); +MODULE_PARM_DESC(bus_clock_master_2, + "I2C master 2 bus speed in KHz 50/80/100/200/400"); + +static int bus_clock_master_3 = 100; +module_param(bus_clock_master_3, int, 0660); +MODULE_PARM_DESC(bus_clock_master_3, + "I2C master 3 bus speed in KHz 50/80/100/200/400"); + +static int bus_clock_master_4 = 100; +module_param(bus_clock_master_4, int, 0660); +MODULE_PARM_DESC(bus_clock_master_4, + "I2C master 4 bus speed in KHz 50/80/100/200/400"); + +static int bus_clock_master_5 = 100; +module_param(bus_clock_master_5, int, 0660); +MODULE_PARM_DESC(bus_clock_master_5, + "I2C master 5 bus speed in KHz 50/80/100/200/400"); + +// NOTE: Silverstone i2c channel mapping is very wierd!!! +/* PCA9548 channel config on MASTER BUS 3 */ +static struct pca954x_platform_mode i2c_mux_70_modes[] = { + I2C_MUX_CHANNEL(5, I2C_BUS_OFS + 23, true), + I2C_MUX_CHANNEL(6, I2C_BUS_OFS + 26, true), + I2C_MUX_CHANNEL(0, I2C_BUS_OFS + 27, true), + I2C_MUX_CHANNEL(7, I2C_BUS_OFS + 28, true), + I2C_MUX_CHANNEL(2, I2C_BUS_OFS + 29, true), + I2C_MUX_CHANNEL(4, I2C_BUS_OFS + 30, true), + I2C_MUX_CHANNEL(3, I2C_BUS_OFS + 31, true), + I2C_MUX_CHANNEL(1, I2C_BUS_OFS + 32, true), +}; + +static struct pca954x_platform_mode i2c_mux_71_modes[] = { + I2C_MUX_CHANNEL(2, I2C_BUS_OFS + 1, true), + I2C_MUX_CHANNEL(3, I2C_BUS_OFS + 2, true), + I2C_MUX_CHANNEL(0, I2C_BUS_OFS + 3, true), + I2C_MUX_CHANNEL(1, I2C_BUS_OFS + 4, true), + I2C_MUX_CHANNEL(6, I2C_BUS_OFS + 5, true), + I2C_MUX_CHANNEL(5, I2C_BUS_OFS + 6, true), + I2C_MUX_CHANNEL(7, I2C_BUS_OFS + 15, true), + I2C_MUX_CHANNEL(4, I2C_BUS_OFS + 8, true), +}; + +static struct pca954x_platform_mode i2c_mux_72_modes[] = { + I2C_MUX_CHANNEL(1, I2C_BUS_OFS + 17, true), + I2C_MUX_CHANNEL(7, I2C_BUS_OFS + 18, true), + I2C_MUX_CHANNEL(4, I2C_BUS_OFS + 19, true), + I2C_MUX_CHANNEL(0, I2C_BUS_OFS + 20, true), + I2C_MUX_CHANNEL(5, I2C_BUS_OFS + 21, true), + I2C_MUX_CHANNEL(2, I2C_BUS_OFS + 22, true), + I2C_MUX_CHANNEL(3, I2C_BUS_OFS + 25, true), + I2C_MUX_CHANNEL(6, I2C_BUS_OFS + 24, true), +}; + +static struct pca954x_platform_mode i2c_mux_73_modes[] = { + I2C_MUX_CHANNEL(4, I2C_BUS_OFS + 9, true), + I2C_MUX_CHANNEL(3, I2C_BUS_OFS + 10, true), + I2C_MUX_CHANNEL(6, I2C_BUS_OFS + 11, true), + I2C_MUX_CHANNEL(2, I2C_BUS_OFS + 12, true), + I2C_MUX_CHANNEL(1, I2C_BUS_OFS + 13, true), + I2C_MUX_CHANNEL(5, I2C_BUS_OFS + 14, true), + I2C_MUX_CHANNEL(7, I2C_BUS_OFS + 7, true), + I2C_MUX_CHANNEL(0, I2C_BUS_OFS + 16, true), +}; + +static struct pca954x_platform_data om_muxes[] = { + { + .modes = i2c_mux_70_modes, + .num_modes = ARRAY_SIZE(i2c_mux_70_modes), + }, + { + .modes = i2c_mux_71_modes, + .num_modes = ARRAY_SIZE(i2c_mux_71_modes), + }, + { + .modes = i2c_mux_72_modes, + .num_modes = ARRAY_SIZE(i2c_mux_72_modes), + }, + { + .modes = i2c_mux_73_modes, + .num_modes = ARRAY_SIZE(i2c_mux_73_modes), + }, +}; + +/* Optical Module bus 3 i2c muxes info */ +static struct i2c_board_info i2c_info_3[] = { + { + I2C_BOARD_INFO("pca9548", 0x70), + .platform_data = &om_muxes[0], + }, + { + I2C_BOARD_INFO("pca9548", 0x71), + .platform_data = &om_muxes[1], + }, + { + I2C_BOARD_INFO("pca9548", 0x72), + .platform_data = &om_muxes[2], + }, + { + I2C_BOARD_INFO("pca9548", 0x73), + .platform_data = &om_muxes[3], + }, +}; + +/* RESOURCE SEPERATES BY FUNCTION */ +/* Resource IOMEM for i2c bus 1 */ +static struct resource cls_i2c_res_1[] = { + { + .start = 0x800, .end = 0x81F, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for i2c bus 2 */ +static struct resource cls_i2c_res_2[] = { + { + .start = 0x820, .end = 0x83F, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for i2c bus 3 */ +static struct resource cls_i2c_res_3[] = { + { + .start = 0x840, .end = 0x85F, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for i2c bus 4 */ +static struct resource cls_i2c_res_4[] = { + { + .start = 0x860, .end = 0x87F, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for i2c bus 5 */ +static struct resource cls_i2c_res_5[] = { + { + .start = 0x880, .end = 0x89F, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for reg access */ +static struct resource reg_io_res[] = { + { + .start = 0x00, .end = 0xFF, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for spi flash firmware upgrade */ +static struct resource spi_flash_res[] = { + { + .start = 0x1200, .end = 0x121F, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for front panel XCVR */ +static struct resource xcvr_res[] = { + { + .start = 0x4000, .end = 0x421F, + .flags = IORESOURCE_MEM,}, +}; + +static struct i2c_bus_config i2c_bus_configs[] = { + { + .id = 1, + .res = cls_i2c_res_1, + .num_res = ARRAY_SIZE(cls_i2c_res_1), + .pdata = { + .reg_shift = OCORE_REGSHIFT, + .reg_io_width = OCORE_REG_IO_WIDTH, + .clock_khz = OCORE_IP_CLK_khz, + .bus_khz = OCORE_BUS_CLK_khz, + .big_endian = false, + .num_devices = 0, + .devices = NULL, + }, + }, + { + .id = 2, + .res = cls_i2c_res_2, + .num_res = ARRAY_SIZE(cls_i2c_res_2), + .pdata = { + .reg_shift = OCORE_REGSHIFT, + .reg_io_width = OCORE_REG_IO_WIDTH, + .clock_khz = OCORE_IP_CLK_khz, + .bus_khz = OCORE_BUS_CLK_khz, + .big_endian = false, + .num_devices = 0, + .devices = NULL, + }, + }, + { + .id = 3, + .res = cls_i2c_res_3, + .num_res = ARRAY_SIZE(cls_i2c_res_3), + .pdata = { + .reg_shift = OCORE_REGSHIFT, + .reg_io_width = OCORE_REG_IO_WIDTH, + .clock_khz = OCORE_IP_CLK_khz, + .bus_khz = OCORE_BUS_CLK_khz, + .big_endian = false, + .num_devices = ARRAY_SIZE(i2c_info_3), + .devices = i2c_info_3, + }, + }, + { + .id = 4, + .res = cls_i2c_res_4, + .num_res = ARRAY_SIZE(cls_i2c_res_4), + .pdata = { + .reg_shift = OCORE_REGSHIFT, + .reg_io_width = OCORE_REG_IO_WIDTH, + .clock_khz = OCORE_IP_CLK_khz, + .bus_khz = OCORE_BUS_CLK_khz, + .big_endian = false, + .num_devices = 0, + .devices = NULL, + }, + }, + { + .id = 5, + .res = cls_i2c_res_5, + .num_res = ARRAY_SIZE(cls_i2c_res_5), + .pdata = { + .reg_shift = OCORE_REGSHIFT, + .reg_io_width = OCORE_REG_IO_WIDTH, + .clock_khz = OCORE_IP_CLK_khz, + .bus_khz = OCORE_BUS_CLK_khz, + .big_endian = false, + .num_devices = 0, + .devices = NULL, + }, + }, +}; + +/* xcvr front panel mapping */ +static struct port_info front_panel_ports[] = { + {"QSFP1", 1, QSFP}, + {"QSFP2", 2, QSFP}, + {"QSFP3", 3, QSFP}, + {"QSFP4", 4, QSFP}, + {"QSFP5", 5, QSFP}, + {"QSFP6", 6, QSFP}, + {"QSFP7", 7, QSFP}, + {"QSFP8", 8, QSFP}, + {"QSFP9", 9, QSFP}, + {"QSFP10", 10, QSFP}, + {"QSFP11", 11, QSFP}, + {"QSFP12", 12, QSFP}, + {"QSFP13", 13, QSFP}, + {"QSFP14", 14, QSFP}, + {"QSFP15", 15, QSFP}, + {"QSFP16", 16, QSFP}, + {"QSFP17", 17, QSFP}, + {"QSFP18", 18, QSFP}, + {"QSFP19", 19, QSFP}, + {"QSFP20", 20, QSFP}, + {"QSFP21", 21, QSFP}, + {"QSFP22", 22, QSFP}, + {"QSFP23", 23, QSFP}, + {"QSFP24", 24, QSFP}, + {"QSFP25", 25, QSFP}, + {"QSFP26", 26, QSFP}, + {"QSFP27", 27, QSFP}, + {"QSFP28", 28, QSFP}, + {"QSFP29", 29, QSFP}, + {"QSFP30", 30, QSFP}, + {"QSFP31", 31, QSFP}, + {"QSFP32", 32, QSFP}, + {"SFP1", 33, SFP}, + {"SFP2", 34, SFP}, + /* END OF LIST */ +}; + +static struct cls_xcvr_platform_data xcvr_data = { + .port_reg_size = 0x10, + .num_ports = ARRAY_SIZE(front_panel_ports), + .devices = front_panel_ports, +}; + + +// TODO: Add a platform configuration struct, and use probe as a factory, +// so xcvr, fwupgrade device can configured as options. + +static int cls_fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + + struct switchbrd_priv *priv; + struct platform_device **i2cbuses_pdev; + struct platform_device *regio_pdev; + struct platform_device *xcvr_pdev; + unsigned long rstart; + int num_i2c_bus, i; + int err; + + err = pci_enable_device(dev); + if (err){ + dev_err(&dev->dev, "Failed to enable PCI device\n"); + goto err_exit; + } + + /* Check for valid MMIO address */ + rstart = pci_resource_start(dev, MMIO_BAR); + if (!rstart) { + dev_err(&dev->dev, "Switchboard base address uninitialized, " + "check FPGA\n"); + err = -ENODEV; + goto err_disable_device; + } + + dev_dbg(&dev->dev, "BAR%d res: 0x%lx-0x%llx\n", MMIO_BAR, + rstart, pci_resource_end(dev, MMIO_BAR)); + + priv = devm_kzalloc(&dev->dev, + sizeof(struct switchbrd_priv), GFP_KERNEL); + if (!priv){ + err = -ENOMEM; + goto err_disable_device; + } + + pci_set_drvdata(dev, priv); + num_i2c_bus = ARRAY_SIZE(i2c_bus_configs); + i2cbuses_pdev = devm_kzalloc( + &dev->dev, + num_i2c_bus * sizeof(struct platform_device*), + GFP_KERNEL); + + reg_io_res[0].start += rstart; + reg_io_res[0].end += rstart; + + xcvr_res[0].start += rstart; + xcvr_res[0].end += rstart; + + regio_pdev = platform_device_register_resndata( + &dev->dev, "cls-swbrd-io", + -1, + reg_io_res, ARRAY_SIZE(reg_io_res), + NULL, 0); + + if (IS_ERR(regio_pdev)) { + dev_err(&dev->dev, "Failed to register cls-swbrd-io\n"); + err = PTR_ERR(regio_pdev); + goto err_disable_device; + } + + xcvr_pdev = platform_device_register_resndata( + NULL, + "cls-xcvr", + -1, + xcvr_res, + ARRAY_SIZE(xcvr_res), + &xcvr_data, + sizeof(xcvr_data)); + + if (IS_ERR(xcvr_pdev)) { + dev_err(&dev->dev, "Failed to register xcvr node\n"); + err = PTR_ERR(xcvr_pdev); + goto err_unregister_regio; + } + + for(i = 0; i < num_i2c_bus; i++){ + + i2c_bus_configs[i].res[0].start += rstart; + i2c_bus_configs[i].res[0].end += rstart; + + switch (i + 1) { + case 1: + i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_1; + break; + case 2: + i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_2; + break; + case 3: + i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_3; + break; + case 4: + i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_4; + break; + case 5: + i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_5; + break; + default: + i2c_bus_configs[i].pdata.bus_khz = OCORE_BUS_CLK_khz; + } + + dev_dbg(&dev->dev, "i2c-bus.%d: 0x%llx - 0x%llx\n", + i2c_bus_configs[i].id, + i2c_bus_configs[i].res[0].start, + i2c_bus_configs[i].res[0].end); + + i2cbuses_pdev[i] = platform_device_register_resndata( + &dev->dev, "ocores-i2c", + i2c_bus_configs[i].id, + i2c_bus_configs[i].res, + i2c_bus_configs[i].num_res, + &i2c_bus_configs[i].pdata, + sizeof(i2c_bus_configs[i].pdata)); + + if (IS_ERR(i2cbuses_pdev[i])) { + dev_err(&dev->dev, "Failed to register ocores-i2c.%d\n", + i2c_bus_configs[i].id); + err = PTR_ERR(i2cbuses_pdev[i]); + goto err_unregister_ocore; + } + } + + priv->base = rstart; + priv->num_i2c_bus = num_i2c_bus; + priv->i2cbuses_pdev = i2cbuses_pdev; + priv->regio_pdev = regio_pdev; + priv->xcvr_pdev = xcvr_pdev; + return 0; + +err_unregister_ocore: + for(i = 0; i < num_i2c_bus; i++){ + if(priv->i2cbuses_pdev[i]){ + platform_device_unregister(priv->i2cbuses_pdev[i]); + } + } +err_unregister_xcvr: + platform_device_unregister(xcvr_pdev); +err_unregister_regio: + platform_device_unregister(regio_pdev); +err_disable_device: + pci_disable_device(dev); +err_exit: + return err; +} + +static void cls_fpga_remove(struct pci_dev *dev) +{ + int i; + struct switchbrd_priv *priv = pci_get_drvdata(dev); + + for(i = 0; i < priv->num_i2c_bus; i++){ + if(priv->i2cbuses_pdev[i]) + platform_device_unregister(priv->i2cbuses_pdev[i]); + } + platform_device_unregister(priv->xcvr_pdev); + platform_device_unregister(priv->regio_pdev); + pci_disable_device(dev); + return; +}; + +static const struct pci_device_id pci_clsswbrd[] = { + { PCI_VDEVICE(XILINX, FPGA_PCIE_DEVICE_ID) }, + {0, } +}; + +MODULE_DEVICE_TABLE(pci, pci_clsswbrd); + +static struct pci_driver clsswbrd_pci_driver = { + .name = DRV_NAME, + .id_table = pci_clsswbrd, + .probe = cls_fpga_probe, + .remove = cls_fpga_remove, +}; + +module_pci_driver(clsswbrd_pci_driver); + +MODULE_AUTHOR("Pradchaya P."); +MODULE_DESCRIPTION("Celestica Silverstone switchboard driver"); +MODULE_VERSION(MOD_VERSION); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/switch_cpld.c b/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/switch_cpld.c new file mode 100644 index 000000000000..d566ad33fb9e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/switch_cpld.c @@ -0,0 +1,417 @@ +/* + * switch_cpld.c - i2c driver for Silverstone switchboard CPLD1/CPLD2 + * provides sysfs interfaces to access CPLD register and control port LEDs + * + * Author: Budsakol Sirirattanasakul + * + * Copyright (C) 2019 Celestica Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include + +#define CPLD1_ADDR 0x30 +#define CPLD2_ADDR 0x31 + +#define SCRATCH_ADDR 0x01 +#define LED_OPMODE 0x09 +#define LED_TEST 0x0A + +struct switch_cpld_data { + struct mutex lock; + struct i2c_client *client; + struct i2c_client *client2; + uint8_t read_addr; +}; + +static ssize_t getreg_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct switch_cpld_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int value; + + value = i2c_smbus_read_byte_data(client, data->read_addr); + if (value < 0) + return value; + + return sprintf(buf, "0x%.2x\n", value); +} + +static ssize_t getreg_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + uint8_t value; + ssize_t status; + struct switch_cpld_data *data = dev_get_drvdata(dev); + + status = kstrtou8(buf, 0, &value); + if (status != 0) + return status; + + data->read_addr = value; + + return size; +} + +static ssize_t setreg_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + uint8_t addr, value; + ssize_t status; + struct switch_cpld_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + char *tok; + + tok = strsep((char **)&buf, " "); + if (tok == NULL) + return -EINVAL; + status = kstrtou8(tok, 0, &addr); + if (status != 0) + return status; + + tok = strsep((char **)&buf, " "); + if (tok == NULL) + return -EINVAL; + status = kstrtou8(tok, 0, &value); + if (status != 0) + return status; + + status = i2c_smbus_write_byte_data(client, addr, value); + if (status == 0) + status = size; + return status; +} + +static ssize_t scratch_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct switch_cpld_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int value; + + value = i2c_smbus_read_byte_data(client, SCRATCH_ADDR); + if (value < 0) + return value; + + return sprintf(buf, "0x%.2x\n", value); +} + +static ssize_t scratch_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + uint8_t value; + ssize_t status; + struct switch_cpld_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + + status = kstrtou8(buf, 0, &value); + if (status != 0) + return status; + status = i2c_smbus_write_byte_data(client, SCRATCH_ADDR, value); + if (status == 0) + status = size; + return status; +} + +DEVICE_ATTR_RW(getreg); +DEVICE_ATTR_WO(setreg); +DEVICE_ATTR_RW(scratch); + +static struct attribute *switch_cpld_attrs[] = { + &dev_attr_getreg.attr, + &dev_attr_setreg.attr, + &dev_attr_scratch.attr, + NULL, +}; +ATTRIBUTE_GROUPS(switch_cpld); + +static ssize_t port_led_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int led_mode_1, led_mode_2; + struct switch_cpld_data *data = dev_get_drvdata(dev); + struct i2c_client *client1 = data->client; + struct i2c_client *client2 = data->client2; + + led_mode_1 = i2c_smbus_read_byte_data(client1, LED_OPMODE); + if (led_mode_1 < 0) + return led_mode_1; + + led_mode_2 = i2c_smbus_read_byte_data(client2, LED_OPMODE); + if (led_mode_2 < 0) + return led_mode_2; + + return sprintf(buf, "%s %s\n", + 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) +{ + int status; + uint8_t led_mode; + struct switch_cpld_data *data = dev_get_drvdata(dev); + struct i2c_client *client1 = data->client; + struct i2c_client *client2 = data->client2; + + if (sysfs_streq(buf, "test")) + led_mode = 0x01; + else if (sysfs_streq(buf, "normal")) + led_mode = 0x00; + else + return -EINVAL; + + status = i2c_smbus_write_byte_data(client1, LED_OPMODE, led_mode); + if (status != 0) { + return status; + } + + status = i2c_smbus_write_byte_data(client2, LED_OPMODE, led_mode); + if (status != 0) { + return status; + } + + return size; +} + +static ssize_t port_led_color_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int led_color1, led_color2; + struct switch_cpld_data *data = dev_get_drvdata(dev); + struct i2c_client *client1 = data->client; + struct i2c_client *client2 = data->client2; + + led_color1 = i2c_smbus_read_byte_data(client1, LED_TEST); + if (led_color1 < 0) + return led_color1; + + led_color2 = i2c_smbus_read_byte_data(client2, LED_TEST); + if (led_color2 < 0) + return led_color2; + + return sprintf(buf, "%s %s\n", + led_color1 == 0x07 ? "off" : led_color1 == 0x06 ? "green" : led_color1 == 0x05 ? + "red" : led_color1 == 0x04 ? + "yellow" : led_color1 == 0x03 ? "blue" : led_color1 == 0x02 ? "cyan" : + led_color1 == 0x01 ? "magenta" : "white", + led_color2 == 0x07 ? "off" : led_color2 == 0x06 ? "green" : led_color2 == 0x05 ? + "red" : led_color2 == 0x04 ? + "yellow" : led_color2 == 0x03 ? "blue" : led_color2 == 0x02 ? "cyan" : + led_color2 == 0x01 ? "magenta" : "white"); +} + +static ssize_t port_led_color_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int status; + uint8_t led_color; + struct switch_cpld_data *data = dev_get_drvdata(dev); + struct i2c_client *client1 = data->client; + struct i2c_client *client2 = data->client2; + + if (sysfs_streq(buf, "off")) + led_color = 0x07; + else if (sysfs_streq(buf, "green")) + led_color = 0x06; + else if (sysfs_streq(buf, "red")) + led_color = 0x05; + else if (sysfs_streq(buf, "yellow")) + led_color = 0x04; + else if (sysfs_streq(buf, "blue")) + led_color = 0x03; + else if (sysfs_streq(buf, "cyan")) + led_color = 0x02; + else if (sysfs_streq(buf, "magenta")) + led_color = 0x01; + else if (sysfs_streq(buf, "white")) + led_color = 0x00; + else + return -EINVAL; + + status = i2c_smbus_write_byte_data(client1, LED_TEST, led_color); + if (status != 0) { + return status; + } + + status = i2c_smbus_write_byte_data(client2, LED_TEST, led_color); + if (status != 0) { + return status; + } + + return size; +} + +DEVICE_ATTR_RW(port_led_mode); +DEVICE_ATTR_RW(port_led_color); + +static struct attribute *sff_led_attrs[] = { + &dev_attr_port_led_mode.attr, + &dev_attr_port_led_color.attr, + NULL, +}; + +static struct attribute_group sff_led_groups = { + .attrs = sff_led_attrs, +}; + +static int switch_cpld_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int err; + struct switch_cpld_data *drvdata1, *drvdata2; + struct device *hwmon_dev1, *hwmon_dev2; + struct i2c_client *client2; + + if (client->addr != CPLD1_ADDR) { + dev_err(&client->dev, "probe, bad i2c addr: 0x%x\n", + client->addr); + err = -EINVAL; + goto exit; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -EPFNOSUPPORT; + + /* CPLD1 */ + drvdata1 = devm_kzalloc(&client->dev, + sizeof(struct switch_cpld_data), GFP_KERNEL); + + if (!drvdata1) { + err = -ENOMEM; + goto exit; + } + + mutex_init(&drvdata1->lock); + drvdata1->client = client; + drvdata1->read_addr = 0x00; + i2c_set_clientdata(client, drvdata1); + hwmon_dev1 = devm_hwmon_device_register_with_groups(&client->dev, + "CPLD1", + drvdata1, + switch_cpld_groups); + + if (IS_ERR(hwmon_dev1)) { + err = PTR_ERR(hwmon_dev1); + goto exit; + } + + err = sysfs_create_link(&client->dev.kobj, &hwmon_dev1->kobj, "CPLD1"); + if (err) { + goto exit; + } + + /* CPLD2 */ + drvdata2 = devm_kzalloc(&client->dev, + sizeof(struct switch_cpld_data), GFP_KERNEL); + + if (!drvdata2) { + err = -ENOMEM; + goto err_link; + } + + client2 = i2c_new_dummy(client->adapter, CPLD2_ADDR); + if (!client2) { + dev_err(&client->dev, "address 0x%02x unavailable\n", + CPLD2_ADDR); + err = -EADDRINUSE; + goto err_link; + } + + mutex_init(&drvdata2->lock); + drvdata2->read_addr = 0x00; + drvdata2->client = client2; + i2c_set_clientdata(client2, drvdata2); + + /* attach client2 to be client2 of CPLD1 + for later use on port led sysfs */ + drvdata1->client2 = client2; + + hwmon_dev2 = devm_hwmon_device_register_with_groups(&client2->dev, + "CPLD2", + drvdata2, + switch_cpld_groups); + + if (IS_ERR(hwmon_dev2)) { + err = PTR_ERR(hwmon_dev2); + goto err_client2; + } + + err = sysfs_create_link(&client2->dev.kobj, &hwmon_dev2->kobj, "CPLD2"); + if (err) { + goto err_client2; + } + + //port led + err = sysfs_create_group(&client->dev.kobj, &sff_led_groups); + if (err) { + dev_err(&client->dev, + "failed to create sysfs attribute group.\n"); + goto err_link2; + } + + return 0; + +err_link2: + sysfs_remove_link(&client2->dev.kobj, "CPLD2"); + +err_client2: + if (client2) + i2c_unregister_device(client2); + +err_link: + sysfs_remove_link(&client->dev.kobj, "CPLD1"); + +exit: + dev_err(&client->dev, "probe error %d\n", err); + return err; +} + +static int switch_cpld_remove(struct i2c_client *client) +{ + struct switch_cpld_data *data = i2c_get_clientdata(client); + + sysfs_remove_group(&client->dev.kobj, &sff_led_groups); + sysfs_remove_link(&data->client2->dev.kobj, "CPLD2"); + sysfs_remove_link(&client->dev.kobj, "CPLD1"); + i2c_unregister_device(data->client2); + return 0; +} + +static const struct i2c_device_id switch_cpld_ids[] = { + { "switch_cpld", 0x30 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, switch_cpld_ids); + +static struct i2c_driver switch_cpld_driver = { + .driver = { + .name = "switch_cpld", + .owner = THIS_MODULE, + }, + .probe = switch_cpld_probe, + .remove = switch_cpld_remove, + .id_table = switch_cpld_ids, +}; + +module_i2c_driver(switch_cpld_driver); + +MODULE_AUTHOR("Budsakol Sirirattanasakul"); +MODULE_DESCRIPTION("Celestica Silverstone Switchboard CPLD driver"); +MODULE_VERSION("1.0.0"); +MODULE_LICENSE("GPL"); \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/switchboard.c b/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/switchboard.c deleted file mode 100644 index 2ee6c858a8b6..000000000000 --- a/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/switchboard.c +++ /dev/null @@ -1,2106 +0,0 @@ -/* - * switchboard.c - driver for Silverstone Switch board FPGA/CPLD. - * - * Author: Pradchaya Phucharoen - * - * Copyright (C) 2018 Celestica Corp. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * / - * \--sys - * \--devices - * \--platform - * \--silverstone - * |--FPGA - * |--CPLD1 - * |--CPLD2 - * \--SFF - * |--QSFP[1..32] - * \--SFP[1..2] - * - */ - -#ifndef TEST_MODE -#define MOD_VERSION "1.2.0" -#else -#define MOD_VERSION "TEST" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int majorNumber; - -#define CLASS_NAME "silverstone_fpga" -#define DRIVER_NAME "switchboard" -#define FPGA_PCI_NAME "Silverstone_fpga_pci" -#define DEVICE_NAME "fwupgrade" - - -static int smbus_access(struct i2c_adapter *adapter, u16 addr, - 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); - -static int fpgafw_init(void); -static void fpgafw_exit(void); - - -/* -======================================== -FPGA PCIe BAR 0 Registers -======================================== -Misc Control 0x00000000 – 0x000000FF. -I2C_CH1 0x00000100 - 0x00000110 -I2C_CH2 0x00000200 - 0x00000210. -I2C_CH3 0x00000300 - 0x00000310. -I2C_CH4 0x00000400 - 0x00000410. -I2C_CH5 0x00000500 - 0x00000510. -I2C_CH6 0x00000600 - 0x00000610. -I2C_CH7 0x00000700 - 0x00000710. -I2C_CH8 0x00000800 - 0x00000810. -I2C_CH9 0x00000900 - 0x00000910. -I2C_CH10 0x00000A00 - 0x00000A10. -I2C_CH11 0x00000B00 - 0x00000B10. -I2C_CH12 0x00000C00 - 0x00000C10. -I2C_CH13 0x00000D00 - 0x00000D10. -SPI Master 0x00001200 - 0x00001300. -DPLL SPI Master 0x00001320 - 0x0000132F. -PORT XCVR 0x00004000 - 0x00004FFF. -*/ - -/* MISC */ -#define FPGA_VERSION 0x0000 -#define FPGA_VERSION_MJ_MSK 0xff00 -#define FPGA_VERSION_MN_MSK 0x00ff -#define FPGA_SCRATCH 0x0004 -#define FPGA_BROAD_TYPE 0x0008 -#define FPGA_BROAD_REV_MSK 0x0038 -#define FPGA_BROAD_ID_MSK 0x0007 -#define FPGA_PLL_STATUS 0x0014 -#define BMC_I2C_SCRATCH 0x0020 -#define FPGA_SLAVE_CPLD_REST 0x0030 -#define FPGA_PERIPH_RESET_CTRL 0x0034 -#define FPGA_INT_STATUS 0x0040 -#define FPGA_INT_SRC_STATUS 0x0044 -#define FPGA_INT_FLAG 0x0048 -#define FPGA_INT_MASK 0x004c -#define FPGA_MISC_CTRL 0x0050 -#define FPGA_MISC_STATUS 0x0054 -#define FPGA_AVS_VID_STATUS 0x0068 -#define FPGA_PORT_XCVR_READY 0x000c - -/* I2C_MASTER BASE ADDR */ -#define I2C_MASTER_FREQ_1 0x0100 -#define I2C_MASTER_CTRL_1 0x0104 -#define I2C_MASTER_STATUS_1 0x0108 -#define I2C_MASTER_DATA_1 0x010c -#define I2C_MASTER_PORT_ID_1 0x0110 -#define I2C_MASTER_CH_1 1 -#define I2C_MASTER_CH_2 2 -#define I2C_MASTER_CH_3 3 -#define I2C_MASTER_CH_4 4 -#define I2C_MASTER_CH_5 5 -#define I2C_MASTER_CH_6 6 -#define I2C_MASTER_CH_7 7 -#define I2C_MASTER_CH_8 8 -#define I2C_MASTER_CH_9 9 -#define I2C_MASTER_CH_10 10 -#define I2C_MASTER_CH_11 11 -#define I2C_MASTER_CH_12 12 -#define I2C_MASTER_CH_13 13 - -#define I2C_MASTER_CH_TOTAL I2C_MASTER_CH_5 - -/* SPI_MASTER */ -#define SPI_MASTER_WR_EN 0x1200 /* one bit */ -#define SPI_MASTER_WR_DATA 0x1204 /* 32 bits */ -#define SPI_MASTER_CHK_ID 0x1208 /* one bit */ -#define SPI_MASTER_VERIFY 0x120c /* one bit */ -#define SPI_MASTER_STATUS 0x1210 /* 15 bits */ -#define SPI_MASTER_MODULE_RST 0x1214 /* one bit */ - -/* FPGA FRONT PANEL PORT MGMT */ -#define SFF_PORT_CTRL_BASE 0x4000 -#define SFF_PORT_STATUS_BASE 0x4004 -#define SFF_PORT_INT_STATUS_BASE 0x4008 -#define SFF_PORT_INT_MASK_BASE 0x400c - -#define PORT_XCVR_REGISTER_SIZE 0x1000 - -/* PORT CTRL REGISTER -[31:7] RSVD -[6] LPMOD 6 -[5] RSVD -[4] RST 4 -[3:1] RSVD -[0] TXDIS 0 -*/ -#define CTRL_LPMOD 6 -#define CTRL_RST 4 -#define CTRL_TXDIS 0 - -/* PORT STATUS REGISTER -[31:6] RSVD -[5] IRQ 5 -[4] PRESENT 4 -[3] RSVD -[2] TXFAULT 2 -[1] RXLOS 1 -[0] MODABS 0 -*/ -#define STAT_IRQ 5 -#define STAT_PRESENT 4 -#define STAT_TXFAULT 2 -#define STAT_RXLOS 1 -#define STAT_MODABS 0 - -/* PORT INTRPT REGISTER -[31:6] RSVD -[5] INT_N 5 -[4] PRESENT 4 -[3] RSVD -[2] RSVD -[1] RXLOS 1 -[0] MODABS 0 -*/ -#define INTR_INT_N 5 -#define INTR_PRESENT 4 -#define INTR_TXFAULT 2 -#define INTR_RXLOS 1 -#define INTR_MODABS 0 - -/* PORT INT MASK REGISTER -[31:6] RSVD -[5] INT_N 5 -[4] PRESENT 4 -[3] RSVD -[2] RSVD -[1] RXLOS_INT 1 -[0] MODABS 0 -*/ -#define MASK_INT_N 5 -#define MASK_PRESENT 4 -#define MASK_TXFAULT 2 -#define MASK_RXLOS 1 -#define MASK_MODABS 0 - -enum { - I2C_SR_BIT_RXAK = 0, - I2C_SR_BIT_MIF, - I2C_SR_BIT_SRW, - I2C_SR_BIT_BCSTM, - I2C_SR_BIT_MAL, - I2C_SR_BIT_MBB, - I2C_SR_BIT_MAAS, - I2C_SR_BIT_MCF -}; - -enum { - I2C_CR_BIT_BCST = 0, - I2C_CR_BIT_RSTA = 2, - I2C_CR_BIT_TXAK, - I2C_CR_BIT_MTX, - I2C_CR_BIT_MSTA, - I2C_CR_BIT_MIEN, - I2C_CR_BIT_MEN, -}; - -/** - * - * The function is i2c algorithm implement to allow master access to - * correct endpoint devices trough the PCA9548 switch devices. - * - * FPGA I2C Master [mutex resource] - * | - * | - * --------------------------- - * | PCA9548(s) | - * ---1--2--3--4--5--6--7--8-- - * | | | | | | | | - * EEPROM ... EEPROM - * - */ - -#define VIRTUAL_I2C_QSFP_PORT 32 -#define VIRTUAL_I2C_SFP_PORT 2 - -#define SFF_PORT_TOTAL VIRTUAL_I2C_QSFP_PORT + VIRTUAL_I2C_SFP_PORT - -#define VIRTUAL_I2C_BUS_OFFSET 10 -#define CPLD1_SLAVE_ADDR 0x30 -#define CPLD2_SLAVE_ADDR 0x31 - -static struct class* fpgafwclass = NULL; // < The device-driver class struct pointer -static struct device* fpgafwdev = NULL; // < The device-driver device struct pointer - -#define PCI_VENDOR_ID_TEST 0x1af4 - -#ifndef PCI_VENDOR_ID_XILINX -#define PCI_VENDOR_ID_XILINX 0x10EE -#endif - -#define FPGA_PCIE_DEVICE_ID 0x7021 -#define TEST_PCIE_DEVICE_ID 0x1110 - - -#ifdef DEBUG_KERN -#define info(fmt,args...) printk(KERN_INFO "line %3d : "fmt,__LINE__,##args) -#define check(REG) printk(KERN_INFO "line %3d : %-8s = %2.2X",__LINE__,#REG,ioread8(REG)); -#else -#define info(fmt,args...) -#define check(REG) -#endif - -#define GET_REG_BIT(REG,BIT) ((ioread8(REG) >> BIT) & 0x01) -#define SET_REG_BIT_H(REG,BIT) iowrite8(ioread8(REG) | (0x01 << BIT),REG) -#define SET_REG_BIT_L(REG,BIT) iowrite8(ioread8(REG) & ~(0x01 << BIT),REG) - -static struct mutex fpga_i2c_master_locks[I2C_MASTER_CH_TOTAL]; -/* Store lasted switch address and channel */ -static uint16_t fpga_i2c_lasted_access_port[I2C_MASTER_CH_TOTAL]; - -enum PORT_TYPE { - NONE, - QSFP, - SFP -}; - -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. - enum PORT_TYPE port_type; // QSFP/SFP tranceiver port type. - char calling_name[20]; // Calling name. -}; - -struct i2c_dev_data { - int portid; - struct i2c_switch pca9548; -}; - -/* PREDEFINED I2C SWITCH DEVICE TOPOLOGY */ -static struct i2c_switch fpga_i2c_bus_dev[] = { - /* BUS3 QSFP Exported as virtual bus */ - {I2C_MASTER_CH_3, 0x71, 2, QSFP, "QSFP1"}, {I2C_MASTER_CH_3, 0x71, 3, QSFP, "QSFP2"}, - {I2C_MASTER_CH_3, 0x71, 0, QSFP, "QSFP3"}, {I2C_MASTER_CH_3, 0x71, 1, QSFP, "QSFP4"}, - {I2C_MASTER_CH_3, 0x71, 6, QSFP, "QSFP5"}, {I2C_MASTER_CH_3, 0x71, 5, QSFP, "QSFP6"}, - {I2C_MASTER_CH_3, 0x73, 7, QSFP, "QSFP7"}, {I2C_MASTER_CH_3, 0x71, 4, QSFP, "QSFP8"}, - - {I2C_MASTER_CH_3, 0x73, 4, QSFP, "QSFP9"}, {I2C_MASTER_CH_3, 0x73, 3, QSFP, "QSFP10"}, - {I2C_MASTER_CH_3, 0x73, 6, QSFP, "QSFP11"}, {I2C_MASTER_CH_3, 0x73, 2, QSFP, "QSFP12"}, - {I2C_MASTER_CH_3, 0x73, 1, QSFP, "QSFP13"}, {I2C_MASTER_CH_3, 0x73, 5, QSFP, "QSFP14"}, - {I2C_MASTER_CH_3, 0x71, 7, QSFP, "QSFP15"}, {I2C_MASTER_CH_3, 0x73, 0, QSFP, "QSFP16"}, - - {I2C_MASTER_CH_3, 0x72, 1, QSFP, "QSFP17"}, {I2C_MASTER_CH_3, 0x72, 7, QSFP, "QSFP18"}, - {I2C_MASTER_CH_3, 0x72, 4, QSFP, "QSFP19"}, {I2C_MASTER_CH_3, 0x72, 0, QSFP, "QSFP20"}, - {I2C_MASTER_CH_3, 0x72, 5, QSFP, "QSFP21"}, {I2C_MASTER_CH_3, 0x72, 2, QSFP, "QSFP22"}, - {I2C_MASTER_CH_3, 0x70, 5, QSFP, "QSFP23"}, {I2C_MASTER_CH_3, 0x72, 6, QSFP, "QSFP24"}, - - {I2C_MASTER_CH_3, 0x72, 3, QSFP, "QSFP25"}, {I2C_MASTER_CH_3, 0x70, 6, QSFP, "QSFP26"}, - {I2C_MASTER_CH_3, 0x70, 0, QSFP, "QSFP27"}, {I2C_MASTER_CH_3, 0x70, 7, QSFP, "QSFP28"}, - {I2C_MASTER_CH_3, 0x70, 2, QSFP, "QSFP29"}, {I2C_MASTER_CH_3, 0x70, 4, QSFP, "QSFP30"}, - {I2C_MASTER_CH_3, 0x70, 3, QSFP, "QSFP31"}, {I2C_MASTER_CH_3, 0x70, 1, QSFP, "QSFP32"}, - /* BUS1 SFP+ Exported as virtual bus */ - {I2C_MASTER_CH_1, 0xFF, 0, SFP, "SFP1"}, - /* BUS2 SFP+ Exported as virtual bus */ - {I2C_MASTER_CH_2, 0xFF, 0, SFP, "SFP2"}, - /* BUS4 CPLD Access via I2C */ - {I2C_MASTER_CH_4, 0xFF, 0, NONE, "CPLD_S"}, - /* BUS5 CPLD_B */ - {I2C_MASTER_CH_5, 0xFF, 0, NONE, "CPLD_B"}, -}; - -#define VIRTUAL_I2C_PORT_LENGTH ARRAY_SIZE(fpga_i2c_bus_dev) -#define SW_I2C_CPLD_INDEX SFF_PORT_TOTAL - -struct fpga_device { - /* data mmio region */ - void __iomem *data_base_addr; - resource_size_t data_mmio_start; - resource_size_t data_mmio_len; -}; - -static struct fpga_device fpga_dev = { - .data_base_addr = 0, - .data_mmio_start = 0, - .data_mmio_len = 0, -}; - -struct silverstone_fpga_data { - struct device *sff_devices[SFF_PORT_TOTAL]; - struct i2c_client *sff_i2c_clients[SFF_PORT_TOTAL]; - struct i2c_adapter *i2c_adapter[VIRTUAL_I2C_PORT_LENGTH]; - struct mutex fpga_lock; // For FPGA internal lock - void __iomem * fpga_read_addr; - uint8_t cpld1_read_addr; - uint8_t cpld2_read_addr; -}; - -struct sff_device_data { - int portid; - enum PORT_TYPE port_type; -}; - -struct silverstone_fpga_data *fpga_data; - -/* - * Kernel object for other module drivers. - * Other module can use these kobject as a parent. - */ - -static struct kobject *fpga = NULL; -static struct kobject *cpld1 = NULL; -static struct kobject *cpld2 = NULL; - -/** - * Device node in sysfs tree. - */ -static struct device *sff_dev = NULL; - - -static ssize_t version_show(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - u32 version; - - mutex_lock(&fpga_data->fpga_lock); - version = ioread32(fpga_dev.data_base_addr + FPGA_VERSION); - mutex_unlock(&fpga_data->fpga_lock); - return sprintf(buf, "%d.%d\n", version >> 16, version & 0xFFFF); -} - -/** - * 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) -{ - // read data from the address - uint32_t data; - data = ioread32(fpga_data->fpga_read_addr); - return sprintf(buf, "0x%8.8x\n", data); -} -/** - * 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 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; -} -/** - * Show value of fpga scratch register - * @param buf register value in hexstring - * @return number of bytes read, or an error code - */ -static ssize_t get_fpga_scratch(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - return sprintf(buf, "0x%8.8x\n", ioread32(fpga_dev.data_base_addr + FPGA_SCRATCH) & 0xffffffff); -} -/** - * 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_scratch(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) -{ - 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; -} -/** - * 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 *devattr, - const char *buf, size_t count) -{ - // register are 4 bytes - uint32_t addr; - uint32_t value; - uint32_t mode = 8; - char *tok; - char clone[count]; - char *pclone = clone; - char *last; - - strcpy(clone, buf); - - mutex_lock(&fpga_data->fpga_lock); - tok = strsep((char**)&pclone, " "); - if (tok == NULL) { - mutex_unlock(&fpga_data->fpga_lock); - return -EINVAL; - } - addr = (uint32_t)strtoul(tok, &last, 16); - if (addr == 0 && tok == last) { - mutex_unlock(&fpga_data->fpga_lock); - return -EINVAL; - } - tok = strsep((char**)&pclone, " "); - if (tok == NULL) { - mutex_unlock(&fpga_data->fpga_lock); - return -EINVAL; - } - value = (uint32_t)strtoul(tok, &last, 16); - if (value == 0 && tok == last) { - mutex_unlock(&fpga_data->fpga_lock); - return -EINVAL; - } - tok = strsep((char**)&pclone, " "); - if (tok == NULL) { - mode = 32; - } else { - mode = (uint32_t)strtoul(tok, &last, 10); - if (mode == 0 && tok == last) { - 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 { - mutex_unlock(&fpga_data->fpga_lock); - return -EINVAL; - } - mutex_unlock(&fpga_data->fpga_lock); - return count; -} - -/** - * Show FPGA port XCVR ready status - * @param buf 1 if the functin is ready, 0 if not. - * @return number of bytes read, or an error code - */ -static ssize_t ready_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - u32 data; - unsigned int REGISTER = FPGA_PORT_XCVR_READY; - - mutex_lock(&fpga_data->fpga_lock); - data = ioread32(fpga_dev.data_base_addr + REGISTER); - mutex_unlock(&fpga_data->fpga_lock); - return sprintf(buf, "%d\n", (data >> 0) & 1U); -} - -/* FPGA attributes */ -static DEVICE_ATTR( getreg, 0600, get_fpga_reg_value, set_fpga_reg_address); -static DEVICE_ATTR( scratch, 0600, get_fpga_scratch, set_fpga_scratch); -static DEVICE_ATTR( setreg, 0200, NULL , set_fpga_reg_value); -static DEVICE_ATTR_RO(ready); -static DEVICE_ATTR_RO(version); - -static struct attribute *fpga_attrs[] = { - &dev_attr_getreg.attr, - &dev_attr_scratch.attr, - &dev_attr_setreg.attr, - &dev_attr_ready.attr, - &dev_attr_version.attr, - NULL, -}; - -static struct attribute_group fpga_attr_grp = { - .attrs = fpga_attrs, -}; - -static ssize_t cpld1_version_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - u8 version; - int err; - err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], - CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x00, - I2C_SMBUS_BYTE_DATA, - (union i2c_smbus_data *)&version); - if (err < 0) - return err; - return sprintf(buf, "%d.%d\n", version >> 4, version & 0x0F); -} -struct device_attribute dev_attr_cpld1_version = __ATTR(version, 0444, cpld1_version_show , NULL); - -/* SW CPLDs attributes */ -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[SW_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); -} -static ssize_t cpld1_getreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) -{ - 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) -{ - // CPLD register is one byte - __u8 data; - int err; - err = fpga_i2c_access(fpga_data->i2c_adapter[SW_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); -} -static ssize_t cpld1_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) { - return -EINVAL; - } - err = fpga_i2c_access(fpga_data->i2c_adapter[SW_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) -{ - - uint8_t addr, value; - char *tok; - char clone[size]; - char *pclone = clone; - int err; - char *last; - - strcpy(clone, buf); - - tok = strsep((char**)&pclone, " "); - if (tok == NULL) { - return -EINVAL; - } - addr = (uint8_t)strtoul(tok, &last, 16); - if (addr == 0 && tok == last) { - return -EINVAL; - } - tok = strsep((char**)&pclone, " "); - if (tok == NULL) { - return -EINVAL; - } - value = (uint8_t)strtoul(tok, &last, 16); - if (value == 0 && tok == last) { - return -EINVAL; - } - - err = fpga_i2c_access(fpga_data->i2c_adapter[SW_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; -} -struct device_attribute dev_attr_cpld1_setreg = __ATTR(setreg, 0200, NULL, cpld1_setreg_store); - -static struct attribute *cpld1_attrs[] = { - &dev_attr_cpld1_version.attr, - &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, -}; - -static ssize_t cpld2_version_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - u8 version; - int err; - err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], - CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x00, - I2C_SMBUS_BYTE_DATA, - (union i2c_smbus_data *)&version); - if (err < 0) - return err; - return sprintf(buf, "%d.%d\n", version >> 4, version & 0x0F); -} -struct device_attribute dev_attr_cpld2_version = __ATTR(version, 0444, cpld2_version_show , NULL); - -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[SW_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[SW_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) { - return -EINVAL; - } - err = fpga_i2c_access(fpga_data->i2c_adapter[SW_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) -{ - uint8_t addr, value; - char *tok; - char clone[size]; - char *pclone = clone; - int err; - char *last; - - strcpy(clone, buf); - - tok = strsep((char**)&pclone, " "); - if (tok == NULL) { - return -EINVAL; - } - addr = (uint8_t)strtoul(tok, &last, 16); - if (addr == 0 && tok == last) { - return -EINVAL; - } - tok = strsep((char**)&pclone, " "); - if (tok == NULL) { - return -EINVAL; - } - value = (uint8_t)strtoul(tok, &last, 16); - if (value == 0 && tok == last) { - return -EINVAL; - } - - err = fpga_i2c_access(fpga_data->i2c_adapter[SW_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; -} -struct device_attribute dev_attr_cpld2_setreg = __ATTR(setreg, 0200, NULL, cpld2_setreg_store); - -static struct attribute *cpld2_attrs[] = { - &dev_attr_cpld2_version.attr, - &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, -}; - -/* QSFP/SFP+ attributes */ -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; - - mutex_lock(&fpga_data->fpga_lock); - 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) -{ - 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; - - mutex_lock(&fpga_data->fpga_lock); - 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) -{ - 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; - - mutex_lock(&fpga_data->fpga_lock); - 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) -{ - 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; - - mutex_lock(&fpga_data->fpga_lock); - 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) -{ - 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; - - mutex_lock(&fpga_data->fpga_lock); - 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) -{ - 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; - - mutex_lock(&fpga_data->fpga_lock); - 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) -{ - 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; - - mutex_lock(&fpga_data->fpga_lock); - status = kstrtol(buf, 0, &value); - if (status == 0) { - // if value is 0, disable the lpmode - 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; - } - 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) -{ - 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; - - mutex_lock(&fpga_data->fpga_lock); - 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) -{ - 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; - - mutex_lock(&fpga_data->fpga_lock); - status = kstrtol(buf, 0, &value); - if (status == 0) { - // if value is 0, reset signal is low - 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; - } - 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) -{ - 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; - - mutex_lock(&fpga_data->fpga_lock); - 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) -{ - 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; - - 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 = data & ~( (u32)0x1 << CTRL_TXDIS); - else - data = data | ((u32)0x1 << CTRL_TXDIS); - iowrite32(data, fpga_dev.data_base_addr + REGISTER); - status = size; - } - mutex_unlock(&fpga_data->fpga_lock); - return status; -} -DEVICE_ATTR_RW(sfp_txdisable); - -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_sfp_txfault.attr, - &dev_attr_sfp_rxlos.attr, - &dev_attr_sfp_modabs.attr, - &dev_attr_sfp_txdisable.attr, - NULL, -}; - -static struct attribute_group sff_attr_grp = { - .attrs = sff_attrs, -}; - -static const struct attribute_group *sff_attr_grps[] = { - &sff_attr_grp, - NULL -}; - - -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; - int err; - err = fpga_i2c_access(fpga_data->i2c_adapter[SW_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[SW_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"); -} -static ssize_t port_led_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) -{ - int status; - __u8 led_mode_1; - if (sysfs_streq(buf, "test")) { - led_mode_1 = 0x01; - } else if (sysfs_streq(buf, "normal")) { - led_mode_1 = 0x00; - } else { - return -EINVAL; - } - status = fpga_i2c_access(fpga_data->i2c_adapter[SW_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[SW_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, - I2C_SMBUS_WRITE, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_mode_1); - return size; -} -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) -{ - // value can be R/G/B/C/M/Y/W/OFF - __u8 led_color1, led_color2; - int err; - err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_color1); - if (err < 0) - return err; - err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_color2); - if (err < 0) - return err; - return sprintf(buf, "%s %s\n", - led_color1 == 0x07 ? "off" : led_color1 == 0x06 ? "green" : led_color1 == 0x05 ? "red" : led_color1 == 0x04 ? - "yellow" : led_color1 == 0x03 ? "blue" : led_color1 == 0x02 ? "cyan" : led_color1 == 0x01 ? "magenta" : "white", - led_color1 == 0x07 ? "off" : led_color1 == 0x06 ? "green" : led_color1 == 0x05 ? "red" : led_color1 == 0x04 ? - "yellow" : led_color1 == 0x03 ? "blue" : led_color1 == 0x02 ? "cyan" : led_color1 == 0x01 ? "magenta" : "white"); -} - -static ssize_t port_led_color_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) -{ - int status; - __u8 led_color; - if (sysfs_streq(buf, "off")) { - led_color = 0x07; - } else if (sysfs_streq(buf, "green")) { - led_color = 0x06; - } else if (sysfs_streq(buf, "red")) { - led_color = 0x05; - } else if (sysfs_streq(buf, "yellow")) { - led_color = 0x04; - } else if (sysfs_streq(buf, "blue")) { - led_color = 0x03; - } else if (sysfs_streq(buf, "cyan")) { - led_color = 0x02; - } else if (sysfs_streq(buf, "magenta")) { - led_color = 0x01; - } else if (sysfs_streq(buf, "white")) { - led_color = 0x00; - } else { - status = -EINVAL; - return status; - } - status = fpga_i2c_access(fpga_data->i2c_adapter[SW_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[SW_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, - I2C_SMBUS_WRITE, 0x0A, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_color); - return size; -} -DEVICE_ATTR_RW(port_led_color); - -static struct attribute *sff_led_test[] = { - &dev_attr_port_led_mode.attr, - &dev_attr_port_led_color.attr, - NULL, -}; - -static struct attribute_group sff_led_test_grp = { - .attrs = sff_led_test, -}; - -static struct device * silverstone_sff_init(int portid) { - struct sff_device_data *new_data; - struct device *new_device; - - new_data = kzalloc(sizeof(*new_data), GFP_KERNEL); - if (!new_data) { - printk(KERN_ALERT "Cannot alloc sff device data @port%d", portid); - return NULL; - } - /* The QSFP port ID start from 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); - if (IS_ERR(new_device)) { - printk(KERN_ALERT "Cannot create sff device @port%d", portid); - kfree(new_data); - return NULL; - } - return new_device; -} - -static int i2c_wait_ack(struct i2c_adapter *a, unsigned long timeout, int writing) { - int error = 0; - int Status; - - struct i2c_dev_data *new_data = i2c_get_adapdata(a); - void __iomem *pci_bar = fpga_dev.data_base_addr; - - unsigned int REG_FDR0; - unsigned int REG_CR0; - unsigned int REG_SR0; - unsigned int REG_DR0; - unsigned int REG_ID0; - - unsigned int master_bus = new_data->pca9548.master_bus; - - 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; - - 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); - info("Error Timeout"); - error = -ETIMEDOUT; - break; - } - - - if (Status & (1 << I2C_SR_BIT_MIF)) { - break; - } - - if (writing == 0 && (Status & (1 << I2C_SR_BIT_MCF))) { - break; - } - } - Status = ioread8(pci_bar + REG_SR0); - iowrite8(0, pci_bar + REG_SR0); - - if (error < 0) { - info("Status %2.2X", Status); - return error; - } - - if (!(Status & (1 << I2C_SR_BIT_MCF))) { - info("Error Unfinish"); - return -EIO; - } - - if (Status & (1 << I2C_SR_BIT_MAL)) { - info("Error MAL"); - return -EAGAIN; - } - - if (Status & (1 << I2C_SR_BIT_RXAK)) { - info( "SL No Acknowlege"); - if (writing) { - info("Error No Acknowlege"); - iowrite8(1 << I2C_CR_BIT_MEN, pci_bar + REG_CR0); - return -ENXIO; - } - } else { - info( "SL Acknowlege"); - } - - return 0; -} - -static int smbus_access(struct i2c_adapter *adapter, u16 addr, - unsigned short flags, char rw, u8 cmd, - int size, union i2c_smbus_data *data) -{ - int error = 0; - int cnt = 0; - int bid = 0; - struct i2c_dev_data *dev_data; - void __iomem *pci_bar; - unsigned int portid, master_bus; - unsigned int REG_FDR0; - unsigned int REG_CR0; - unsigned int REG_SR0; - unsigned int REG_DR0; - unsigned int REG_ID0; - - /* Write the command register */ - dev_data = i2c_get_adapdata(adapter); - portid = dev_data->portid; - pci_bar = fpga_dev.data_base_addr; - master_bus = dev_data->pca9548.master_bus; - 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; - - if (master_bus < I2C_MASTER_CH_1 || master_bus > I2C_MASTER_CH_TOTAL) { - error = -EINVAL; - goto Done; - } - -#ifdef DEBUG_KERN - printk(KERN_INFO "portid %2d|@ 0x%2.2X|f 0x%4.4X|(%d)%-5s| (%d)%-10s|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" : "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: - break; - default: - printk(KERN_INFO "Unsupported transaction %d\n", size); - error = -EOPNOTSUPP; - goto Done; - } - - 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); - - 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"); - - //// 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 || - size == I2C_SMBUS_WORD_DATA || - size == I2C_SMBUS_BLOCK_DATA || - (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); - - // 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: - // in block data mode keep number of byte in block[0] - cnt = data->block[0]; - break; - default: - cnt = 0; break; - } - - // [CNT] used only bloack 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 - )) { - int bid = 0; - info( "MS prepare to sent [%d bytes]", cnt); - if (size == I2C_SMBUS_BLOCK_DATA ) { - bid = 1; // block[0] is cnt; - cnt += 1; // offset from block[0] - } - for (; bid < cnt; bid++) { - - 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; - } - } - } - - //REPEATE START - if ( rw == I2C_SMBUS_READ && ( - size == I2C_SMBUS_BYTE_DATA || - size == I2C_SMBUS_WORD_DATA || - size == I2C_SMBUS_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 - )) { - - 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; - default: - cnt = 0; break; - } - - 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 {A} - 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); - } - 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); - i2c_wait_ack(adapter, 12, 0); - info( "MS STOP"); - -Done: - iowrite8(1 << I2C_CR_BIT_MEN, pci_bar + REG_CR0); - check(pci_bar + REG_CR0); - check(pci_bar + REG_SR0); -#ifdef DEBUG_KERN - printk(KERN_INFO "END --- Error code %d", error); -#endif - - return error; -} - -/** - * Wrapper of smbus_access access with PCA9548 I2C switch management. - * This function set PCA9548 switches to the proper slave channel. - * Only one channel among switches chip is selected during communication time. - * - * Note: If the bus does not have any PCA9548 on it, the switch_addr must be - * set to 0xFF, it will use normal smbus_access function. - */ -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) -{ - int error = 0; - struct i2c_dev_data *dev_data; - unsigned char master_bus; - unsigned char switch_addr; - unsigned char channel; - uint16_t prev_port = 0; - unsigned char prev_switch; - unsigned char prev_ch; - int retry; - - dev_data = i2c_get_adapdata(adapter); - master_bus = dev_data->pca9548.master_bus; - switch_addr = dev_data->pca9548.switch_addr; - channel = dev_data->pca9548.channel; - - // Acquire the master resource. - mutex_lock(&fpga_i2c_master_locks[master_bus - 1]); - prev_port = fpga_i2c_lasted_access_port[master_bus - 1]; - prev_switch = (unsigned char)(prev_port >> 8) & 0xFF; - prev_ch = (unsigned char)(prev_port & 0xFF); - - if (switch_addr != 0xFF) { - - // Check lasted access switch address on a master - if ( prev_switch != switch_addr && prev_switch != 0 ) { - // reset prev_port PCA9548 chip - retry = 3; - 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); - } - } - 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){ - break; - }else{ - dev_dbg(&adapter->dev,"Failed to select ch %d of 0x%x, CODE %d\n", channel, switch_addr, error); - } - } - if(retry == 0) - goto release_unlock; - // update lasted port - fpga_i2c_lasted_access_port[master_bus - 1] = switch_addr << 8 | channel; - - } else { - // check if channel is also changes - 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){ - break; - }else{ - dev_dbg(&adapter->dev,"Failed to select ch %d of 0x%x, CODE %d\n", channel, switch_addr, error); - } - } - 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); - } - -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); - return error; -} - - - -/** - * A callback function show available smbus functions. - */ -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; -} - -static const struct i2c_algorithm silverstone_i2c_algorithm = { - .smbus_xfer = fpga_i2c_access, - .functionality = fpga_i2c_func, -}; - -/** - * Create virtual I2C bus adapter for switch devices - * @param pdev platform device pointer - * @param portid virtual i2c port id for switch device mapping - * @param bus_number_offset bus offset for virtual i2c adapter in system - * @return i2c adapter. - * - * 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 * silverstone_i2c_init(struct platform_device *pdev, int portid, int bus_number_offset) -{ - int error; - - struct i2c_adapter *new_adapter; - struct i2c_dev_data *new_data; - 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); - return NULL; - } - - new_adapter->owner = THIS_MODULE; - new_adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; - new_adapter->algo = &silverstone_i2c_algorithm; - /* If the bus offset is -1, use dynamic bus number */ - if (bus_number_offset == -1) { - new_adapter->nr = -1; - } 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); - kzfree(new_adapter); - return NULL; - } - - new_data->portid = portid; - 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); - - snprintf(new_adapter->name, sizeof(new_adapter->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); - error = i2c_add_numbered_adapter(new_adapter); - if (error < 0) { - printk(KERN_ALERT "Cannot add i2c adapter %s", new_data->pca9548.calling_name); - kzfree(new_adapter); - kzfree(new_data); - return NULL; - } - - return new_adapter; -}; - -static void silverstone_dev_release( struct device * dev) -{ - return; -} - -static struct platform_device silverstone_dev = { - .name = DRIVER_NAME, - .id = -1, - .num_resources = 0, - .resource = NULL, - .dev = { - .release = silverstone_dev_release, - } -}; - -/** - * Board info for QSFP/SFP+ eeprom. - * Note: Using OOM optoe as I2C eeprom driver. - * https://www.opencompute.org/wiki/Networking/SpecsAndDesigns#Open_Optical_Monitoring - */ -static struct i2c_board_info sff8436_eeprom_info[] = { - { I2C_BOARD_INFO("optoe1", 0x50) }, //For QSFP w/ sff8436 - { I2C_BOARD_INFO("optoe2", 0x50) }, //For SFP+ w/ sff8472 -}; - -static int silverstone_drv_probe(struct platform_device *pdev) -{ - int ret = 0; - int portid_count; - uint8_t cpld1_version, cpld2_version; - uint16_t prev_i2c_switch = 0; - struct sff_device_data *sff_data; - - /* The device class need to be instantiated before this function called */ - BUG_ON(fpgafwclass == NULL); - - fpga_data = devm_kzalloc(&pdev->dev, sizeof(struct silverstone_fpga_data), - 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->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]); - } - - fpga = kobject_create_and_add("FPGA", &pdev->dev.kobj); - if (!fpga) { - kzfree(fpga_data); - return -ENOMEM; - } - - ret = sysfs_create_group(fpga, &fpga_attr_grp); - if (ret != 0) { - printk(KERN_ERR "Cannot create FPGA sysfs attributes\n"); - kobject_put(fpga); - kzfree(fpga_data); - return ret; - } - - cpld1 = kobject_create_and_add("CPLD1", &pdev->dev.kobj); - if (!cpld1) { - sysfs_remove_group(fpga, &fpga_attr_grp); - kobject_put(fpga); - kzfree(fpga_data); - return -ENOMEM; - } - ret = sysfs_create_group(cpld1, &cpld1_attr_grp); - if (ret != 0) { - printk(KERN_ERR "Cannot create CPLD1 sysfs attributes\n"); - kobject_put(cpld1); - sysfs_remove_group(fpga, &fpga_attr_grp); - kobject_put(fpga); - kzfree(fpga_data); - return ret; - } - - cpld2 = kobject_create_and_add("CPLD2", &pdev->dev.kobj); - if (!cpld2) { - sysfs_remove_group(cpld1, &cpld1_attr_grp); - kobject_put(cpld1); - sysfs_remove_group(fpga, &fpga_attr_grp); - kobject_put(fpga); - kzfree(fpga_data); - return -ENOMEM; - } - ret = sysfs_create_group(cpld2, &cpld2_attr_grp); - if (ret != 0) { - printk(KERN_ERR "Cannot create CPLD2 sysfs attributes\n"); - kobject_put(cpld2); - sysfs_remove_group(cpld1, &cpld1_attr_grp); - kobject_put(cpld1); - sysfs_remove_group(fpga, &fpga_attr_grp); - kobject_put(fpga); - kzfree(fpga_data); - return ret; - } - - 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); - sysfs_remove_group(cpld1, &cpld1_attr_grp); - kobject_put(cpld1); - sysfs_remove_group(fpga, &fpga_attr_grp); - kobject_put(fpga); - kzfree(fpga_data); - return PTR_ERR(sff_dev); - } - - 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)); - sysfs_remove_group(cpld2, &cpld2_attr_grp); - kobject_put(cpld2); - sysfs_remove_group(cpld1, &cpld1_attr_grp); - kobject_put(cpld1); - sysfs_remove_group(fpga, &fpga_attr_grp); - kobject_put(fpga); - kzfree(fpga_data); - return ret; - } - - 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)); - sysfs_remove_group(cpld2, &cpld2_attr_grp); - kobject_put(cpld2); - sysfs_remove_group(cpld1, &cpld1_attr_grp); - kobject_put(cpld1); - sysfs_remove_group(fpga, &fpga_attr_grp); - kobject_put(fpga); - kzfree(fpga_data); - return ret; - } - - for (portid_count = 0 ; portid_count < VIRTUAL_I2C_PORT_LENGTH ; portid_count++) { - fpga_data->i2c_adapter[portid_count] = silverstone_i2c_init(pdev, portid_count, VIRTUAL_I2C_BUS_OFFSET); - } - - /* Init SFF devices */ - 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) { - fpga_data->sff_devices[portid_count] = silverstone_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 ) { - fpga_data->sff_i2c_clients[portid_count] = i2c_new_device(i2c_adap, &sff8436_eeprom_info[0]); - } 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"); - } - } - -#ifdef TEST_MODE - return 0; -#endif - fpga_i2c_access(fpga_data->i2c_adapter[SW_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[SW_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, - I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&cpld2_version); - - printk(KERN_INFO "Switch CPLD1 VERSION: %2.2x\n", cpld1_version); - printk(KERN_INFO "Switch CPLD2 VERSION: %2.2x\n", cpld2_version); - - - /* Init I2C buses that has PCA9548 switch device. */ - for (portid_count = 0; portid_count < VIRTUAL_I2C_PORT_LENGTH; portid_count++) { - - struct i2c_dev_data *dev_data; - unsigned char master_bus; - unsigned char switch_addr; - - dev_data = i2c_get_adapdata(fpga_data->i2c_adapter[portid_count]); - master_bus = dev_data->pca9548.master_bus; - switch_addr = dev_data->pca9548.switch_addr; - - if (switch_addr != 0xFF) { - - 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); - prev_i2c_switch = ( master_bus << 8 ) | switch_addr; - } - } - } - return 0; -} - -static int silverstone_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"); - 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]); - 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) { - 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]); - kfree(rem_data); - } - } - - sysfs_remove_group(fpga, &fpga_attr_grp); - sysfs_remove_group(cpld1, &cpld1_attr_grp); - sysfs_remove_group(cpld2, &cpld2_attr_grp); - sysfs_remove_group(&sff_dev->kobj, &sff_led_test_grp); - kobject_put(fpga); - kobject_put(cpld1); - kobject_put(cpld2); - device_destroy(fpgafwclass, MKDEV(0, 0)); - devm_kfree(&pdev->dev, fpga_data); - return 0; -} - -#ifdef TEST_MODE -#define FPGA_PCI_BAR_NUM 2 -#else -#define FPGA_PCI_BAR_NUM 0 -#endif - -static struct platform_driver silverstone_drv = { - .probe = silverstone_drv_probe, - .remove = __exit_p(silverstone_drv_remove), - .driver = { - .name = DRIVER_NAME, - }, -}; - -static const struct pci_device_id fpga_id_table[] = { - { PCI_VDEVICE(XILINX, FPGA_PCIE_DEVICE_ID) }, - { PCI_VDEVICE(TEST, TEST_PCIE_DEVICE_ID) }, - {0, } -}; - -MODULE_DEVICE_TABLE(pci, fpga_id_table); - -static int fpga_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - int err; - struct device *dev = &pdev->dev; - uint32_t fpga_version; - - if ((err = pci_enable_device(pdev))) { - dev_err(dev, "pci_enable_device probe error %d for device %s\n", - err, pci_name(pdev)); - return err; - } - - if ((err = pci_request_regions(pdev, FPGA_PCI_NAME)) < 0) { - dev_err(dev, "pci_request_regions error %d\n", err); - goto pci_disable; - } - - /* bar0: data mmio region */ - fpga_dev.data_mmio_start = pci_resource_start(pdev, FPGA_PCI_BAR_NUM); - fpga_dev.data_mmio_len = pci_resource_len(pdev, FPGA_PCI_BAR_NUM); - 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); - goto pci_release; - } - dev_info(dev, "data_mmio iomap base = 0x%lx \n", - (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); - - 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 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)); - 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(&silverstone_dev); - platform_driver_register(&silverstone_drv); - return 0; - -pci_release: - pci_release_regions(pdev); -pci_disable: - pci_disable_device(pdev); - return -EBUSY; -} - -static void fpga_pci_remove(struct pci_dev *pdev) -{ - platform_driver_unregister(&silverstone_drv); - platform_device_unregister(&silverstone_dev); - fpgafw_exit(); - pci_iounmap(pdev, fpga_dev.data_base_addr); - pci_release_regions(pdev); - pci_disable_device(pdev); - printk(KERN_INFO "FPGA PCIe driver remove OK.\n"); -}; - -static struct pci_driver pci_dev_ops = { - .name = FPGA_PCI_NAME, - .probe = fpga_pci_probe, - .remove = fpga_pci_remove, - .id_table = fpga_id_table, -}; - -enum { - READREG, - WRITEREG -}; - -struct fpga_reg_data { - uint32_t addr; - uint32_t value; -}; - -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); - -#ifdef TEST_MODE - 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: - mutex_unlock(&fpga_data->fpga_lock); - return -EINVAL; - } - mutex_unlock(&fpga_data->fpga_lock); - return ret; -} - - -const struct file_operations fpgafw_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = fpgafw_unlocked_ioctl, -}; - - -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); - } - 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"); - 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"); -} - -int silverstone_init(void) -{ - int rc; - rc = pci_register_driver(&pci_dev_ops); - if (rc) - return rc; - return 0; -} - -void silverstone_exit(void) -{ - pci_unregister_driver(&pci_dev_ops); -} - -module_init(silverstone_init); -module_exit(silverstone_exit); - -MODULE_AUTHOR("Celestica Inc."); -MODULE_DESCRIPTION("Celestica Silverstone platform driver"); -MODULE_VERSION(MOD_VERSION); -MODULE_LICENSE("GPL"); \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/xcvr-cls.c b/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/xcvr-cls.c new file mode 100644 index 000000000000..bc0da613ec8d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/xcvr-cls.c @@ -0,0 +1,520 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * xcvr-cls.c - front panel port control. + * + * Pradchaya Phucharoen + * Copyright (C) 2019 Celestica Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "xcvr-cls.h" + +/* FPGA front panel */ +#define PORT_CTRL 0 +#define PORT_STATUS 0x4 +#define PORT_INT_STATUS 0x8 +#define PORT_INT_MASK 0xC + +/* + * Port control degister + * LPMOD : active high, RW + * RST : active low, RW + * TXDIS : active high, RW +*/ +#define CTRL_LPMOD BIT(6) +#define CTRL_RST_L BIT(4) +#define CTRL_TXDIS BIT(0) + +/* + * Port status register + * IRQ : active low, RO + * PRESENT : active low, RO, for QSFP + * TXFAULT : active high, RO + * RXLOS : active high, RO + * MODABS : active high, RO, for SFP +*/ +#define STAT_IRQ_L BIT(5) +#define STAT_PRESENT_L BIT(4) +#define STAT_TXFAULT BIT(2) +#define STAT_RXLOS BIT(1) +#define STAT_MODABS BIT(0) + +/* + * NOTE: Interrupt and mask must be expose as bitfeild. + * Because the registers of interrupt flags are read-clear. + * + * Port interrupt flag resgister + * INT_N : interrupt flag, set when INT_N is assert. + * PRESENT : interrupt flag, set when QSFP module plugin/plugout. + * RXLOS : interrupt flag, set when rxlos is assert. + * MODABS : interrupt flag, set when SFP module plugin/plugout. +*/ +#define INTR_INT_N BIT(5) +#define INTR_PRESENT BIT(4) +#define INTR_TXFAULT BIT(2) +#define INTR_RXLOS BIT(1) +#define INTR_MODABS BIT(0) + +/* + * Port interrupt mask register + * INT_N : active low + * PRESENT : active low + * RXLOS_INT : active low + * MODABS : active low +*/ +#define MASK_INT_N_L BIT(5) +#define MASK_PRESENT_L BIT(4) +#define MASK_TXFAULT_L BIT(2) +#define MASK_RXLOS_L BIT(1) +#define MASK_MODABS_L BIT(0) + + +/* + * port_data - optical port data + * @xcvr: xcvr memory accessor + * @name: port name + * @index: front panel port index starting from 1 + */ +struct port_data { + struct xcvr_priv *xcvr; + const char *name; + unsigned int index; +}; + +/* + * xcvr_priv - port xcvr private data + * @dev: device for reference + * @base: virtual base address + * @num_ports: number of front panel ports + * @fp_devs: list of front panel port devices + */ +struct xcvr_priv { + struct device* dev; + void __iomem *base; + int port_reg_size; + int num_ports; + struct device **fp_devs; +}; + +static inline void port_setreg(struct xcvr_priv *xcvr, int reg, int index, u8 value) +{ + return iowrite8(value, xcvr->base + reg + (index - 1) * xcvr->port_reg_size); +} + +static inline u8 port_getreg(struct xcvr_priv *xcvr, int reg, int index) +{ + return ioread8(xcvr->base + reg + (index - 1) * xcvr->port_reg_size); +} + +static ssize_t qsfp_modprsL_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data; + struct port_data *port_data = dev_get_drvdata(dev); + unsigned int index = port_data->index; + + data = port_getreg(port_data->xcvr, PORT_STATUS, index); + return sprintf(buf, "%d\n", (data & STAT_PRESENT_L)?1:0); +} + +static ssize_t qsfp_irqL_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data; + struct port_data *port_data = dev_get_drvdata(dev); + unsigned int index = port_data->index; + + data = port_getreg(port_data->xcvr, PORT_STATUS, index); + return sprintf(buf, "%d\n", (data & STAT_IRQ_L)?1:0); +} + +static ssize_t qsfp_lpmode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data; + struct port_data *port_data = dev_get_drvdata(dev); + unsigned int index = port_data->index; + + data = port_getreg(port_data->xcvr, PORT_CTRL, index); + return sprintf(buf, "%d\n", (data & CTRL_LPMOD)?1:0); +} + +static ssize_t qsfp_lpmode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t status; + long value; + u8 data; + struct port_data *port_data = dev_get_drvdata(dev); + unsigned int index = port_data->index; + + status = kstrtol(buf, 0, &value); + if (status == 0) { + data = port_getreg(port_data->xcvr, PORT_CTRL, index); + if (value == 0) + data &= ~CTRL_LPMOD; + else + data |= CTRL_LPMOD; + port_setreg(port_data->xcvr, PORT_CTRL, index, data); + status = size; + } + return status; +} + +static ssize_t qsfp_resetL_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data; + struct port_data *port_data = dev_get_drvdata(dev); + unsigned int index = port_data->index; + + data = port_getreg(port_data->xcvr, PORT_CTRL, index); + return sprintf(buf, "%d\n", (data & CTRL_RST_L)?1:0); +} + +static ssize_t qsfp_resetL_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t status; + long value; + u8 data; + struct port_data *port_data = dev_get_drvdata(dev); + unsigned int index = port_data->index; + + status = kstrtol(buf, 0, &value); + if (status == 0) { + data = port_getreg(port_data->xcvr, PORT_CTRL, index); + if (value == 0) + data &= ~CTRL_RST_L; + else + data |= CTRL_RST_L; + port_setreg(port_data->xcvr, PORT_CTRL, index, data); + status = size; + } + return status; +} + +static ssize_t sfp_modabs_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data; + struct port_data *port_data = dev_get_drvdata(dev); + unsigned int index = port_data->index; + + data = port_getreg(port_data->xcvr, PORT_STATUS, index); + return sprintf(buf, "%d\n", (data & STAT_MODABS)?1:0); +} + +static ssize_t sfp_txfault_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data; + struct port_data *port_data = dev_get_drvdata(dev); + unsigned int index = port_data->index; + + data = port_getreg(port_data->xcvr, PORT_STATUS, index); + return sprintf(buf, "%d\n", (data & STAT_TXFAULT)?1:0); +} + +static ssize_t sfp_rxlos_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data; + struct port_data *port_data = dev_get_drvdata(dev); + unsigned int index = port_data->index; + + data = port_getreg(port_data->xcvr, PORT_STATUS, index); + return sprintf(buf, "%d\n", (data & STAT_RXLOS)?1:0); +} + +static ssize_t sfp_txdisable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data; + struct port_data *port_data = dev_get_drvdata(dev); + unsigned int index = port_data->index; + + data = port_getreg(port_data->xcvr, PORT_CTRL, index); + return sprintf(buf, "%d\n", (data & CTRL_TXDIS)?1:0); +} + +static ssize_t sfp_txdisable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t status; + long value; + u8 data; + struct port_data *port_data = dev_get_drvdata(dev); + unsigned int index = port_data->index; + + status = kstrtol(buf, 0, &value); + if (status == 0) { + data = port_getreg(port_data->xcvr, PORT_CTRL, index); + if (value == 0) + data &= ~CTRL_TXDIS; + else + data |= CTRL_TXDIS; + port_setreg(port_data->xcvr, PORT_CTRL, index, data); + status = size; + } + return status; +} + +static ssize_t interrupt_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data; + struct port_data *port_data = dev_get_drvdata(dev); + unsigned int index = port_data->index; + + data = port_getreg(port_data->xcvr, PORT_INT_STATUS, index); + return sprintf(buf, "0x%2.2x\n", data); +} + +static ssize_t interrupt_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t status; + long value; + struct port_data *port_data = dev_get_drvdata(dev); + unsigned int index = port_data->index; + + status = kstrtoul(buf, 0, &value); + if (status == 0) { + port_setreg(port_data->xcvr, PORT_INT_STATUS, index, value); + status = size; + } + return status; +} + +static ssize_t interrupt_mask_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data; + struct port_data *port_data = dev_get_drvdata(dev); + unsigned int index = port_data->index; + + data = port_getreg(port_data->xcvr, PORT_INT_MASK, index); + return sprintf(buf, "0x%2.2x\n", data); +} + +static ssize_t interrupt_mask_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t status; + long value; + struct port_data *port_data = dev_get_drvdata(dev); + unsigned int index = port_data->index; + + status = kstrtoul(buf, 0, &value); + if (status == 0) { + port_setreg(port_data->xcvr, PORT_INT_MASK, index, value); + status = size; + } + return status; +} + +DEVICE_ATTR_RO(qsfp_modprsL); +DEVICE_ATTR_RO(qsfp_irqL); +DEVICE_ATTR_RW(qsfp_lpmode); +DEVICE_ATTR_RW(qsfp_resetL); + +DEVICE_ATTR_RO(sfp_modabs); +DEVICE_ATTR_RO(sfp_txfault); +DEVICE_ATTR_RO(sfp_rxlos); +DEVICE_ATTR_RW(sfp_txdisable); + +DEVICE_ATTR_RW(interrupt); +DEVICE_ATTR_RW(interrupt_mask); + +/* qsfp_attrs */ +static struct attribute *qsfp_attrs[] = { + &dev_attr_qsfp_modprsL.attr, + &dev_attr_qsfp_lpmode.attr, + &dev_attr_qsfp_resetL.attr, + &dev_attr_interrupt.attr, + &dev_attr_interrupt_mask.attr, + NULL +}; + +/* sfp_attrs */ +static struct attribute *sfp_attrs[] = { + &dev_attr_sfp_modabs.attr, + &dev_attr_sfp_txfault.attr, + &dev_attr_sfp_rxlos.attr, + &dev_attr_sfp_txdisable.attr, + &dev_attr_interrupt.attr, + &dev_attr_interrupt_mask.attr, + NULL +}; + +ATTRIBUTE_GROUPS(qsfp); +ATTRIBUTE_GROUPS(sfp); + +/* A single port device init */ +static struct device* init_port(struct device *dev, + struct xcvr_priv *xcvr, + struct port_info info, + const struct attribute_group **groups) +{ + struct port_data *new_data; + + new_data = devm_kzalloc(dev, sizeof(struct port_data), GFP_KERNEL); + if (!new_data) + return ERR_PTR(-ENOMEM); + + new_data->index = info.index; + new_data->name = info.name; + new_data->xcvr = xcvr; + + return devm_hwmon_device_register_with_groups(dev, + info.name, + new_data, + groups); +} + +static void xcvr_cleanup(struct xcvr_priv *xcvr) +{ + struct device *dev; + struct port_data *data; + int i; + + for (i = 0; i < xcvr->num_ports; i++){ + dev = xcvr->fp_devs[i]; + if (dev == NULL) + continue; + data = dev_get_drvdata(dev); + sysfs_remove_link(&xcvr->dev->kobj, data->name); + } +} + +static int cls_xcvr_probe(struct platform_device *pdev) +{ + + struct xcvr_priv *xcvr; + struct cls_xcvr_platform_data *pdata; + struct resource *res; + int ret; + int i; + + struct device **port_devs; + + xcvr = devm_kzalloc(&pdev->dev, sizeof(struct xcvr_priv), GFP_KERNEL); + if (!xcvr){ + ret = -ENOMEM; + goto err_exit; + } + + dev_set_drvdata(&pdev->dev, xcvr); + + /* mmap resource */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) { + xcvr->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(xcvr->base)){ + ret = PTR_ERR(xcvr->base); + goto err_exit; + } + } + + pdata = dev_get_platdata(&pdev->dev); + xcvr->dev = &pdev->dev; + + if (pdata) { + /* assign pdata */ + xcvr->num_ports = pdata->num_ports; + xcvr->port_reg_size = pdata->port_reg_size; + } + + /* alloc front panel device list */ + port_devs = devm_kzalloc(&pdev->dev, + xcvr->num_ports * sizeof(struct device*), + GFP_KERNEL); + if (!port_devs){ + ret = -ENOMEM; + goto err_exit; + } + + + if (pdata) { + /* create each device attrs group determined by type */ + for (i = 0; i < pdata->num_ports; i++) { + struct device *fp_dev; + + if (pdata->devices[i].type == SFP){ + fp_dev = init_port(&pdev->dev, + xcvr, + pdata->devices[i], + sfp_groups); + }else{ + fp_dev = init_port(&pdev->dev, + xcvr, + pdata->devices[i], + qsfp_groups); + } + if (IS_ERR(fp_dev)) { + dev_err(&pdev->dev, + "Failed to init port %s\n", + pdata->devices[i].name); + ret = PTR_ERR(fp_dev); + goto dev_clean_up; + } + + dev_info(&pdev->dev, + "Register port %s\n", + pdata->devices[i].name); + + WARN(sysfs_create_link(&pdev->dev.kobj, + &fp_dev->kobj, + pdata->devices[i].name), + "can't create symlink to %s\n", pdata->devices[i].name); + port_devs[i] = fp_dev; + fp_dev = NULL; + } + xcvr->fp_devs = port_devs; + } + + return 0; + +dev_clean_up: + xcvr_cleanup(xcvr); +err_exit: + return ret; + +} + + +static int cls_xcvr_remove(struct platform_device *pdev) +{ + struct xcvr_priv *xcvr = dev_get_drvdata(&pdev->dev); + xcvr_cleanup(xcvr); + return 0; +} + + +static struct platform_driver cls_xcvr_driver = { + .probe = cls_xcvr_probe, + .remove = cls_xcvr_remove, + .driver = { + .name = "cls-xcvr", + }, +}; + +module_platform_driver(cls_xcvr_driver); + +MODULE_AUTHOR("Pradchaya Phucharoen"); +MODULE_DESCRIPTION("Celestica xcvr control driver"); +MODULE_VERSION("0.0.1-3"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:cls-xcvr"); \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/xcvr-cls.h b/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/xcvr-cls.h new file mode 100644 index 000000000000..7659a7c0e9cc --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/xcvr-cls.h @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * xcvr-cls.h + * + * Pradchaya Phucharoen + * Copyright (C) 2019 Celestica Corp. + */ + +#ifndef _LINUX_I2C_CLS_H +#define _LINUX_I2C_CLS_H + +enum PORT_TYPE { + NONE = 0, + SFP, + QSFP +}; + +/* + * port_info - optical port info + * @index: front panel port index starting from 1 + * @typr: port type, see *PORT_TYPE* + */ +struct port_info { + const char *name; + unsigned int index; + enum PORT_TYPE type; +}; + +/* + * cls_xcvr_platform_data - port xcvr private data + * @port_reg_size: register range of each port + * @num_ports: number of front panel ports + * @devices: list of front panel port info + */ +struct cls_xcvr_platform_data { + unsigned int port_reg_size; + int num_ports; + struct port_info *devices; +}; + +#endif /* _LINUX_I2C_CLS_H */ \ No newline at end of file