mirror of
				https://github.com/Telecominfraproject/ols-nos.git
				synced 2025-10-31 01:57:48 +00:00 
			
		
		
		
	[Centec][arm64] support new board E530-48s4x and E530-24x2q (#7189)
1. support new board E530-48s4x E530-24x2q 2. optimize platform driver for Centec TsingMa board Co-authored-by: shi lei <shil@centecnetworks.com>
This commit is contained in:
		| @@ -1,27 +1,27 @@ | |||||||
| # name lanes  alias             speed | # name          lanes          alias             index     speed    fec | ||||||
| Ethernet1         0              eth-0-1         10000 | Ethernet0       0              eth-0-1           0         10000    none | ||||||
| Ethernet2         1              eth-0-2         10000 | Ethernet1       1              eth-0-2           1         10000    none | ||||||
| Ethernet3         2              eth-0-3         10000 | Ethernet2       2              eth-0-3           2         10000    none | ||||||
| Ethernet4         3              eth-0-4         10000 | Ethernet3       3              eth-0-4           3         10000    none | ||||||
| Ethernet5         8              eth-0-5         10000 | Ethernet4       8              eth-0-5           4         10000    none | ||||||
| Ethernet6         9              eth-0-6         10000 | Ethernet5       9              eth-0-6           5         10000    none | ||||||
| Ethernet7         10             eth-0-7         10000 | Ethernet6       10             eth-0-7           6         10000    none | ||||||
| Ethernet8         11             eth-0-8         10000 | Ethernet7       11             eth-0-8           7         10000    none | ||||||
| Ethernet9         20             eth-0-9         10000 | Ethernet8       20             eth-0-9           8         10000    none | ||||||
| Ethernet10        21             eth-0-10        10000   | Ethernet9       21             eth-0-10          9         10000    none | ||||||
| Ethernet11        22             eth-0-11        10000 | Ethernet10      22             eth-0-11          10        10000    none | ||||||
| Ethernet12        23             eth-0-12        10000 | Ethernet11      23             eth-0-12          11        10000    none | ||||||
| Ethernet13        12             eth-0-13        10000 | Ethernet12      12             eth-0-13          12        10000    none | ||||||
| Ethernet14        13             eth-0-14        10000 | Ethernet13      13             eth-0-14          13        10000    none | ||||||
| Ethernet15        14             eth-0-15        10000 | Ethernet14      14             eth-0-15          14        10000    none | ||||||
| Ethernet16        15             eth-0-16        10000 | Ethernet15      15             eth-0-16          15        10000    none | ||||||
| Ethernet17        24             eth-0-17        10000 | Ethernet16      24             eth-0-17          16        10000    none | ||||||
| Ethernet18        25             eth-0-18        10000 | Ethernet17      25             eth-0-18          17        10000    none | ||||||
| Ethernet19        26             eth-0-19        10000 | Ethernet18      26             eth-0-19          18        10000    none | ||||||
| Ethernet20        27             eth-0-20        10000 | Ethernet19      27             eth-0-20          19        10000    none | ||||||
| Ethernet21        28             eth-0-21        10000 | Ethernet20      28             eth-0-21          20        10000    none | ||||||
| Ethernet22        29             eth-0-22        10000 | Ethernet21      29             eth-0-22          21        10000    none | ||||||
| Ethernet23        30             eth-0-23        10000 | Ethernet22      30             eth-0-23          22        10000    none | ||||||
| Ethernet24        31             eth-0-24        10000 | Ethernet23      31             eth-0-24          23        10000    none | ||||||
| Ethernet25        61,60,63,62    eth-0-25        100000 | Ethernet24      61,60,63,62    eth-0-25          24        100000   none | ||||||
| Ethernet26        45,44,47,46    eth-0-26        100000 | Ethernet25      45,44,47,46    eth-0-26          25        100000   none | ||||||
|   | |||||||
| @@ -1 +1,12 @@ | |||||||
| # Configuration file generated by pwmconfig, changes will be lost | # Configuration file generated by pwmconfig, changes will be lost | ||||||
|  | INTERVAL=10 | ||||||
|  | DEVPATH=hwmon1=devices/platform/soc/soc:fan-ctc5236 | ||||||
|  | DEVNAME=hwmon1=ctc5236fan | ||||||
|  | FCTEMPS=hwmon1/pwm1=hwmon1/temp1_input hwmon1/pwm2=hwmon1/temp1_input hwmon1/pwm3=hwmon1/temp1_input | ||||||
|  | FCFANS=hwmon1/pwm1=hwmon1/fan1_input hwmon1/pwm2=hwmon1/fan2_input hwmon1/pwm3=hwmon1/fan3_input | ||||||
|  | MINTEMP=hwmon1/pwm1=30 hwmon1/pwm2=30 hwmon1/pwm3=30 | ||||||
|  | MAXTEMP=hwmon1/pwm1=90 hwmon1/pwm2=90 hwmon1/pwm3=90 | ||||||
|  | MINSTART=hwmon1/pwm1=12 hwmon1/pwm2=12 hwmon1/pwm3=12 | ||||||
|  | MINSTOP=hwmon1/pwm1=6 hwmon1/pwm2=6 hwmon1/pwm3=6 | ||||||
|  | MINPWM=hwmon1/pwm1=6 hwmon1/pwm2=6 hwmon1/pwm3=6 | ||||||
|  | MAXPWM=hwmon1/pwm1=18 hwmon1/pwm2=18 hwmon1/pwm3=18 | ||||||
|   | |||||||
| @@ -0,0 +1,8 @@ | |||||||
|  | { | ||||||
|  |         "chassis": { | ||||||
|  |                 "E530-24x2c": { | ||||||
|  |                         "component": { | ||||||
|  |                         } | ||||||
|  |                 } | ||||||
|  |         } | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								device/centec/arm64-centec_e530_24x2c-r0/platform_reboot
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										11
									
								
								device/centec/arm64-centec_e530_24x2c-r0/platform_reboot
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | #!/usr/bin/python | ||||||
|  | import os | ||||||
|  |  | ||||||
|  | def main(): | ||||||
|  |     # reboot the system | ||||||
|  |     os.system('echo 502 > /sys/class/gpio/export') | ||||||
|  |     os.system('echo out > /sys/class/gpio/gpio502/direction') | ||||||
|  |     os.system('echo 1 > /sys/class/gpio/gpio502/value') | ||||||
|  |  | ||||||
|  | if __name__ == "__main__": | ||||||
|  |     main() | ||||||
| @@ -1,3 +1,5 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
| ############################################################################# | ############################################################################# | ||||||
| # Centec E550-24X8Y2C | # Centec E550-24X8Y2C | ||||||
| # | # | ||||||
| @@ -10,7 +12,7 @@ | |||||||
| try: | try: | ||||||
|     from sonic_eeprom import eeprom_tlvinfo |     from sonic_eeprom import eeprom_tlvinfo | ||||||
| except ImportError as e: | except ImportError as e: | ||||||
|     raise ImportError(str(e) + "- required module not found") |     raise ImportError (str(e) + "- required module not found") | ||||||
|  |  | ||||||
|  |  | ||||||
| class board(eeprom_tlvinfo.TlvInfoDecoder): | class board(eeprom_tlvinfo.TlvInfoDecoder): | ||||||
|   | |||||||
| @@ -1,3 +1,4 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
| # | # | ||||||
| # led_control.py | # led_control.py | ||||||
| # | # | ||||||
| @@ -5,37 +6,110 @@ | |||||||
| # | # | ||||||
|  |  | ||||||
| try: | try: | ||||||
|     from sonic_led.led_control_base import LedControlBase |     import os | ||||||
|  |     import re | ||||||
|     import syslog |     import syslog | ||||||
|     from socket import * |     import collections | ||||||
|     from select import * |     from sonic_led.led_control_base import LedControlBase | ||||||
|  |     from sonic_py_common import device_info | ||||||
| except ImportError as e: | except ImportError as e: | ||||||
|     raise ImportError(str(e) + " - required module not found") |     raise ImportError(str(e) + " - required module not found") | ||||||
|  |  | ||||||
|  | USR_SHARE_SONIC_PATH = "/usr/share/sonic" | ||||||
|  | HOST_DEVICE_PATH = USR_SHARE_SONIC_PATH + "/device" | ||||||
|  | CONTAINER_PLATFORM_PATH = USR_SHARE_SONIC_PATH + "/platform" | ||||||
|  |  | ||||||
| def DBG_PRINT(str): | def DBG_PRINT(str): | ||||||
|     syslog.openlog("centec-led") |     syslog.openlog("centec-led") | ||||||
|     syslog.syslog(syslog.LOG_INFO, str) |     syslog.syslog(syslog.LOG_INFO, str) | ||||||
|     syslog.closelog() |     syslog.closelog() | ||||||
|  |  | ||||||
|  |  | ||||||
| class LedControl(LedControlBase): | class LedControl(LedControlBase): | ||||||
|     """Platform specific LED control class""" |     """Platform specific LED control class""" | ||||||
|  |  | ||||||
|  |     # Constructor | ||||||
|  |     def __init__(self): | ||||||
|  |  | ||||||
|  |         self.mac_to_led = { | ||||||
|  |             0:  1, | ||||||
|  |             1:  2, | ||||||
|  |             2:  3, | ||||||
|  |             3:  4, | ||||||
|  |             8:  5, | ||||||
|  |             9:  6, | ||||||
|  |             10: 7, | ||||||
|  |             11: 8, | ||||||
|  |             20: 9, | ||||||
|  |             21:10, | ||||||
|  |             22:11, | ||||||
|  |             23:12, | ||||||
|  |             12:13, | ||||||
|  |             13:14, | ||||||
|  |             14:15, | ||||||
|  |             15:16, | ||||||
|  |             24:17, | ||||||
|  |             25:18, | ||||||
|  |             26:19, | ||||||
|  |             27:20, | ||||||
|  |             28:21, | ||||||
|  |             29:22, | ||||||
|  |             30:23, | ||||||
|  |             31:24, | ||||||
|  |             61:-1, | ||||||
|  |             60:25, | ||||||
|  |             63:-1, | ||||||
|  |             62:-1, | ||||||
|  |             45:-1, | ||||||
|  |             44:26, | ||||||
|  |             47:-1, | ||||||
|  |             46:-1, | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if os.path.isdir(CONTAINER_PLATFORM_PATH): | ||||||
|  |             platform_path = CONTAINER_PLATFORM_PATH | ||||||
|  |         else: | ||||||
|  |             platform = device_info.get_platform() | ||||||
|  |             if platform is None: | ||||||
|  |                 raise | ||||||
|  |             platform_path = os.path.join(HOST_DEVICE_PATH, platform) | ||||||
|  |  | ||||||
|  |         port_config_file = "/".join([platform_path, "E530-24x2c", "port_config.ini"]) | ||||||
|  |         try: | ||||||
|  |             f = open(port_config_file) | ||||||
|  |         except: | ||||||
|  |             raise | ||||||
|  |         for line in f: | ||||||
|  |             line.strip() | ||||||
|  |             if re.search('^#', line) is not None: | ||||||
|  |                 Port_cfg = collections.namedtuple('Port_cfg', line.split()[1:]) | ||||||
|  |                 break | ||||||
|  |         f.close() | ||||||
|  |         f = open(port_config_file) | ||||||
|  |         self._port_cfgs = [Port_cfg(*tuple((line.strip().split()))) | ||||||
|  |                            for line in f if re.search('^#', line) is None] | ||||||
|  |         f.close() | ||||||
|  |  | ||||||
|  |         self.LED_MODE_UP = [11, 11] | ||||||
|  |         self.LED_MODE_DOWN = [7, 7] | ||||||
|  |         self.f_led = "/sys/class/leds/{}/brightness" | ||||||
|  |         self._initDefaultConfig() | ||||||
|  |  | ||||||
|     # Helper method to map SONiC port name to index |     # Helper method to map SONiC port name to index | ||||||
|     def _port_name_to_index(self, port_name): |     def _port_name_to_index(self, port_name): | ||||||
|         # Strip "Ethernet" off port name |         for port_cfg in self._port_cfgs: | ||||||
|         if not port_name.startswith(self.SONIC_PORT_NAME_PREFIX): |             if port_name == port_cfg.name: | ||||||
|             return -1 |                 macs = [int(x) for x in (port_cfg.lanes.split(','))] | ||||||
|  |                 led = self.mac_to_led[min(macs)] | ||||||
|         port_idx = int(port_name[len(self.SONIC_PORT_NAME_PREFIX):]) |                 if led < 0: | ||||||
|         return port_idx |                     return None | ||||||
|  |                 return led | ||||||
|  |         return None | ||||||
|  |  | ||||||
|     def _port_state_to_mode(self, port_idx, state): |     def _port_state_to_mode(self, port_idx, state): | ||||||
|         if state == "up": |         if state == "up": | ||||||
|             return self.LED_MODE_UP[0] if (port_idx < 25) else self.LED_MODE_UP[1] |             return self.LED_MODE_UP[1] if port_idx == 25 or port_idx == 26 else self.LED_MODE_UP[0] | ||||||
|         else: |         else: | ||||||
|             return self.LED_MODE_DOWN[0] if (port_idx < 25) else self.LED_MODE_DOWN[1] |             return self.LED_MODE_DOWN[1] if port_idx == 25 or port_idx == 26 else self.LED_MODE_DOWN[0] | ||||||
|  |  | ||||||
|     def _port_led_mode_update(self, port_idx, ledMode): |     def _port_led_mode_update(self, port_idx, ledMode): | ||||||
|         with open(self.f_led.format("port{}".format(port_idx)), 'w') as led_file: |         with open(self.f_led.format("port{}".format(port_idx)), 'w') as led_file: | ||||||
| @@ -57,11 +131,15 @@ class LedControl(LedControlBase): | |||||||
|             shouldInit = (int(led_file.read()) == 0) |             shouldInit = (int(led_file.read()) == 0) | ||||||
|  |  | ||||||
|         if shouldInit == True: |         if shouldInit == True: | ||||||
|             for idx in range(1, 27): |             for port_cfg in self._port_cfgs: | ||||||
|                 defmode = self._port_state_to_mode(idx, "down") |                 macs = [int(x) for x in (port_cfg.lanes.split(','))] | ||||||
|                 with open(self.f_led.format("port{}".format(idx)), 'w') as led_file: |                 led = self.mac_to_led[min(macs)] | ||||||
|  |                 if led < 0: | ||||||
|  |                     continue | ||||||
|  |                 defmode = self._port_state_to_mode(led, "down") | ||||||
|  |                 with open(self.f_led.format("port{}".format(led)), 'w') as led_file: | ||||||
|                     led_file.write(str(defmode)) |                     led_file.write(str(defmode)) | ||||||
|                     DBG_PRINT("init port{} led to mode={}".format(idx, defmode)) |                     DBG_PRINT("init port{} led to mode={}".format(led, defmode)) | ||||||
|  |  | ||||||
|     def _initDefaultConfig(self): |     def _initDefaultConfig(self): | ||||||
|         DBG_PRINT("start init led") |         DBG_PRINT("start init led") | ||||||
| @@ -72,9 +150,10 @@ class LedControl(LedControlBase): | |||||||
|         DBG_PRINT("init led done") |         DBG_PRINT("init led done") | ||||||
|  |  | ||||||
|     # Concrete implementation of port_link_state_change() method |     # Concrete implementation of port_link_state_change() method | ||||||
|  |  | ||||||
|     def port_link_state_change(self, portname, state): |     def port_link_state_change(self, portname, state): | ||||||
|         port_idx = self._port_name_to_index(portname) |         port_idx = self._port_name_to_index(portname) | ||||||
|  |         if port_idx is None: | ||||||
|  |             return | ||||||
|         ledMode = self._port_state_to_mode(port_idx, state) |         ledMode = self._port_state_to_mode(port_idx, state) | ||||||
|         with open(self.f_led.format("port{}".format(port_idx)), 'r') as led_file: |         with open(self.f_led.format("port{}".format(port_idx)), 'r') as led_file: | ||||||
|             saveMode = int(led_file.read()) |             saveMode = int(led_file.read()) | ||||||
| @@ -84,13 +163,3 @@ class LedControl(LedControlBase): | |||||||
|  |  | ||||||
|         self._port_led_mode_update(port_idx, ledMode) |         self._port_led_mode_update(port_idx, ledMode) | ||||||
|         DBG_PRINT("update {} led mode from {} to {}".format(portname, saveMode, ledMode)) |         DBG_PRINT("update {} led mode from {} to {}".format(portname, saveMode, ledMode)) | ||||||
|  |  | ||||||
|     # Constructor |  | ||||||
|  |  | ||||||
|     def __init__(self): |  | ||||||
|         self.SONIC_PORT_NAME_PREFIX = "Ethernet" |  | ||||||
|         self.LED_MODE_UP = [11, 11] |  | ||||||
|         self.LED_MODE_DOWN = [7, 7] |  | ||||||
|  |  | ||||||
|         self.f_led = "/sys/class/leds/{}/brightness" |  | ||||||
|         self._initDefaultConfig() |  | ||||||
|   | |||||||
| @@ -1,3 +1,5 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
| ############################################################################# | ############################################################################# | ||||||
| # Centec | # Centec | ||||||
| # | # | ||||||
| @@ -9,8 +11,7 @@ | |||||||
| try: | try: | ||||||
|     from sonic_psu.psu_base import PsuBase |     from sonic_psu.psu_base import PsuBase | ||||||
| except ImportError as e: | except ImportError as e: | ||||||
|     raise ImportError(str(e) + "- required module not found") |     raise ImportError (str(e) + "- required module not found") | ||||||
|  |  | ||||||
|  |  | ||||||
| class PsuUtil(PsuBase): | class PsuUtil(PsuBase): | ||||||
|     """Platform-specific PSUutil class""" |     """Platform-specific PSUutil class""" | ||||||
|   | |||||||
| @@ -1,28 +1,117 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
| # sfputil.py | # sfputil.py | ||||||
| # | # | ||||||
| # Platform-specific SFP transceiver interface for SONiC | # Platform-specific SFP transceiver interface for SONiC | ||||||
| # | # | ||||||
|  |  | ||||||
| try: | try: | ||||||
|  |     import os | ||||||
|  |     import re | ||||||
|     import time |     import time | ||||||
|     from socket import * |     import collections | ||||||
|     from select import * |  | ||||||
|     from sonic_sfp.sfputilbase import SfpUtilBase |     from sonic_sfp.sfputilbase import SfpUtilBase | ||||||
|  |     from sonic_py_common import device_info | ||||||
| except ImportError as e: | except ImportError as e: | ||||||
|     raise ImportError("%s - required module not found" % str(e)) |     raise ImportError("%s - required module not found" % str(e)) | ||||||
|  |  | ||||||
|  |  | ||||||
| def DBG_PRINT(str): |  | ||||||
|     print(str + "\n") |  | ||||||
|  |  | ||||||
|  |  | ||||||
| SFP_STATUS_INSERTED = '1' | SFP_STATUS_INSERTED = '1' | ||||||
| SFP_STATUS_REMOVED = '0' | SFP_STATUS_REMOVED = '0' | ||||||
|  | USR_SHARE_SONIC_PATH = "/usr/share/sonic" | ||||||
|  | HOST_DEVICE_PATH = USR_SHARE_SONIC_PATH + "/device" | ||||||
|  | CONTAINER_PLATFORM_PATH = USR_SHARE_SONIC_PATH + "/platform" | ||||||
|  |  | ||||||
| class SfpUtil(SfpUtilBase): | class SfpUtil(SfpUtilBase): | ||||||
|     """Platform-specific SfpUtil class""" |     """Platform-specific SfpUtil class""" | ||||||
|  |  | ||||||
|  |     def __init__(self): | ||||||
|  |         self.mac_to_sfp = { | ||||||
|  |             0:  1, | ||||||
|  |             1:  2, | ||||||
|  |             2:  3, | ||||||
|  |             3:  4, | ||||||
|  |             8:  5, | ||||||
|  |             9:  6, | ||||||
|  |             10: 7, | ||||||
|  |             11: 8, | ||||||
|  |             20: 9, | ||||||
|  |             21:10, | ||||||
|  |             22:11, | ||||||
|  |             23:12, | ||||||
|  |             12:13, | ||||||
|  |             13:14, | ||||||
|  |             14:15, | ||||||
|  |             15:16, | ||||||
|  |             24:17, | ||||||
|  |             25:18, | ||||||
|  |             26:19, | ||||||
|  |             27:20, | ||||||
|  |             28:21, | ||||||
|  |             29:22, | ||||||
|  |             30:23, | ||||||
|  |             31:24, | ||||||
|  |             61:25, | ||||||
|  |             60:25, | ||||||
|  |             63:25, | ||||||
|  |             62:25, | ||||||
|  |             45:26, | ||||||
|  |             44:26, | ||||||
|  |             47:26, | ||||||
|  |             46:26, | ||||||
|  |         } | ||||||
|  |         self.logical = [] | ||||||
|  |         self.physical_to_logical = {} | ||||||
|  |         self.logical_to_physical = {} | ||||||
|  |         self.logical_to_asic = {} | ||||||
|  |         self.data = {'valid':0, 'last':0} | ||||||
|  |         self.f_sfp_present = "/sys/class/sfp/sfp{}/sfp_presence" | ||||||
|  |         self.f_sfp_enable = "/sys/class/sfp/sfp{}/sfp_enable" | ||||||
|  |  | ||||||
|  |         if os.path.isdir(CONTAINER_PLATFORM_PATH): | ||||||
|  |             platform_path = CONTAINER_PLATFORM_PATH | ||||||
|  |         else: | ||||||
|  |             platform = device_info.get_platform() | ||||||
|  |             if platform is None: | ||||||
|  |                 raise | ||||||
|  |             platform_path = os.path.join(HOST_DEVICE_PATH, platform) | ||||||
|  |  | ||||||
|  |         port_config_file = "/".join([platform_path, "E530-24x2c", "port_config.ini"]) | ||||||
|  |         try: | ||||||
|  |             f = open(port_config_file) | ||||||
|  |         except: | ||||||
|  |             raise | ||||||
|  |         for line in f: | ||||||
|  |             line.strip() | ||||||
|  |             if re.search('^#', line) is not None: | ||||||
|  |                 Port_cfg = collections.namedtuple('Port_cfg', line.split()[1:]) | ||||||
|  |                 break | ||||||
|  |         f.close() | ||||||
|  |         f = open(port_config_file) | ||||||
|  |         self._port_cfgs = [Port_cfg(*tuple((line.strip().split()))) | ||||||
|  |                            for line in f if re.search('^#', line) is None] | ||||||
|  |         f.close() | ||||||
|  |  | ||||||
|  |         self.PORT_START = 256 | ||||||
|  |         self.PORT_END = 0 | ||||||
|  |         for port_cfg in self._port_cfgs: | ||||||
|  |             if int(port_cfg.index) <= self.PORT_START: | ||||||
|  |                 self.PORT_START = int(port_cfg.index) | ||||||
|  |             elif int(port_cfg.index) >= self.PORT_END: | ||||||
|  |                 self.PORT_END = int(port_cfg.index) | ||||||
|  |  | ||||||
|  |         self.eeprom_mapping = {} | ||||||
|  |         self.presence = {} | ||||||
|  |         for port_cfg in self._port_cfgs: | ||||||
|  |             sfp_idx = self.mac_to_sfp[int(port_cfg.lanes.split(',')[0])] | ||||||
|  |             if sfp_idx > 0: | ||||||
|  |                 self.eeprom_mapping[int(port_cfg.index)] = "/sys/class/sfp/sfp{}/sfp_eeprom".format(sfp_idx) | ||||||
|  |                 self.logical.append(port_cfg.name) | ||||||
|  |             else: | ||||||
|  |                 self.eeprom_mapping[int(port_cfg.index)] = None | ||||||
|  |             self.presence[int(port_cfg.index)] = False | ||||||
|  |  | ||||||
|  |         SfpUtilBase.__init__(self) | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def port_start(self): |     def port_start(self): | ||||||
|         return self.PORT_START |         return self.PORT_START | ||||||
| @@ -33,11 +122,20 @@ class SfpUtil(SfpUtilBase): | |||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def sfp_base(self): |     def sfp_base(self): | ||||||
|         return self.SFP_BASE |         return self.PORT_START | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def qsfp_ports(self): |     def qsfp_ports(self): | ||||||
|         return list(range(25, self.PORTS_IN_BLOCK + 1)) |         start = 256 | ||||||
|  |         end = 0 | ||||||
|  |         for port_cfg in self._port_cfgs: | ||||||
|  |             sfp_idx = self.mac_to_sfp[int(port_cfg.lanes.split(',')[0])] | ||||||
|  |             if sfp_idx == 25 or sfp_idx == 26: | ||||||
|  |                 if int(port_cfg.index) <= start: | ||||||
|  |                     start = int(port_cfg.index) | ||||||
|  |                 elif int(port_cfg.index) >= end: | ||||||
|  |                     end = int(port_cfg.index) | ||||||
|  |         return range(start, end + 1) | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def port_to_eeprom_mapping(self): |     def port_to_eeprom_mapping(self): | ||||||
| @@ -46,93 +144,32 @@ class SfpUtil(SfpUtilBase): | |||||||
|     def is_logical_port(self, port_name): |     def is_logical_port(self, port_name): | ||||||
|         return True |         return True | ||||||
|  |  | ||||||
|     def get_eeprom_data(self, port): |  | ||||||
|         ret = None |  | ||||||
|         port_num = self.get_logical_to_physical(port)[0] |  | ||||||
|         if port_num < self.port_start or port_num > self.port_end: |  | ||||||
|             return ret |  | ||||||
|         if port_num < self.sfp_base: |  | ||||||
|             return ret |  | ||||||
|         try: |  | ||||||
|             with open(self.eeprom_mapping[port_num], 'r') as eeprom_file: |  | ||||||
|                 ret = eeprom_file.read() |  | ||||||
|         except IOError as e: |  | ||||||
|             DBG_PRINT(str(e)) |  | ||||||
|  |  | ||||||
|         return ret |  | ||||||
|  |  | ||||||
|     # todo |  | ||||||
|     # def _get_port_eeprom_path(self, port_num, devid): |  | ||||||
|     #    pass |  | ||||||
|  |  | ||||||
|     def __init__(self): |  | ||||||
|         self.SONIC_PORT_NAME_PREFIX = "Ethernet" |  | ||||||
|         self.PORT_START = 1 |  | ||||||
|         self.PORT_END = 26 |  | ||||||
|         self.SFP_BASE = 1 |  | ||||||
|         self.PORTS_IN_BLOCK = 26 |  | ||||||
|         self.logical = [] |  | ||||||
|         self.physical_to_logical = {} |  | ||||||
|         self.logical_to_physical = {} |  | ||||||
|  |  | ||||||
|         self.eeprom_mapping = {} |  | ||||||
|         self.f_sfp_present = "/sys/class/sfp/sfp{}/sfp_presence" |  | ||||||
|         self.f_sfp_enable = "/sys/class/sfp/sfp{}/sfp_enable" |  | ||||||
|         for x in range(self.port_start, self.sfp_base): |  | ||||||
|             self.eeprom_mapping[x] = None |  | ||||||
|         for x in range(self.sfp_base, self.port_end + 1): |  | ||||||
|             self.eeprom_mapping[x] = "/sys/class/sfp/sfp{}/sfp_eeprom".format( |  | ||||||
|                 x - self.sfp_base + 1) |  | ||||||
|         self.presence = {} |  | ||||||
|         for x in range(self.sfp_base, self.port_end + 1): |  | ||||||
|             self.presence[x] = False |  | ||||||
|  |  | ||||||
|         SfpUtilBase.__init__(self) |  | ||||||
|  |  | ||||||
|         for x in range(self.sfp_base, self.port_end + 1): |  | ||||||
|             self.logical.append('Ethernet' + str(x)) |  | ||||||
|  |  | ||||||
|     def get_presence(self, port_num): |     def get_presence(self, port_num): | ||||||
|         # Check for invalid port_num |         for port_cfg in self._port_cfgs: | ||||||
|         if port_num < self.port_start or port_num > self.port_end: |             if int(port_cfg.index) == port_num: | ||||||
|             return False |                 sfp_idx = self.mac_to_sfp[int(port_cfg.lanes.split(',')[0])] | ||||||
|         if port_num < self.sfp_base: |                 if sfp_idx >= 0: | ||||||
|             return False |                     try: | ||||||
|         try: |                         with open(self.f_sfp_present.format(sfp_idx), 'r') as sfp_file: | ||||||
|             with open(self.f_sfp_present.format(port_num - self.sfp_base + 1), 'r') as sfp_file: |                             return 1 == int(sfp_file.read()) | ||||||
|                 return 1 == int(sfp_file.read()) |                     except IOError as e: | ||||||
|         except IOError as e: |                         DBG_PRINT(str(e)) | ||||||
|             DBG_PRINT(str(e)) |  | ||||||
|  |  | ||||||
|         return False |         return False | ||||||
|  |  | ||||||
|     def get_low_power_mode(self, port_num): |     def get_low_power_mode(self, port_num): | ||||||
|         # Check for invalid port_num |  | ||||||
|         if port_num < self.port_start or port_num > self.port_end: |  | ||||||
|             return False |  | ||||||
|  |  | ||||||
|         return False |         return False | ||||||
|  |  | ||||||
|     def set_low_power_mode(self, port_num, lpmode): |     def set_low_power_mode(self, port_num, lpmode): | ||||||
|         # Check for invalid port_num |  | ||||||
|         if port_num < self.port_start or port_num > self.port_end: |  | ||||||
|             return False |  | ||||||
|  |  | ||||||
|         return False |         return False | ||||||
|  |  | ||||||
|     def reset(self, port_num): |     def reset(self, port_num): | ||||||
|         # Check for invalid port_num |  | ||||||
|         if port_num < self.port_start or port_num > self.port_end: |  | ||||||
|             return False |  | ||||||
|  |  | ||||||
|         return False |         return False | ||||||
|  |  | ||||||
|     def read_porttab_mappings(self, porttabfile): |     def read_porttab_mappings(self, porttabfile, asic_inst = 0): | ||||||
|         for x in range(self.sfp_base, self.port_end + 1): |         for port_cfg in self._port_cfgs: | ||||||
|             self.logical_to_physical['Ethernet' + str(x)] = [x] |             self.logical_to_physical[port_cfg.name] = [int(port_cfg.index)] | ||||||
|             self.physical_to_logical[x] = ['Ethernet' + str(x)] |             self.logical_to_asic[port_cfg.name] = 0 | ||||||
|  |             self.physical_to_logical[int(port_cfg.index)] = [port_cfg.name] | ||||||
|     data = {'valid': 0, 'last': 0} |  | ||||||
|  |  | ||||||
|     def get_transceiver_change_event(self, timeout=2000): |     def get_transceiver_change_event(self, timeout=2000): | ||||||
|         now = time.time() |         now = time.time() | ||||||
| @@ -140,19 +177,19 @@ class SfpUtil(SfpUtilBase): | |||||||
|  |  | ||||||
|         if timeout < 1000: |         if timeout < 1000: | ||||||
|             timeout = 1000 |             timeout = 1000 | ||||||
|             timeout = (timeout) / float(1000)  # Convert to secs |         timeout = (timeout) / float(1000) # Convert to secs | ||||||
|  |  | ||||||
|         if now < (self.data['last'] + timeout) and self.data['valid']: |         if now < (self.data['last'] + timeout) and self.data['valid']: | ||||||
|             return True, {} |             return True, {} | ||||||
|  |  | ||||||
|         for x in range(self.sfp_base, self.port_end + 1): |         for port_cfg in self._port_cfgs: | ||||||
|             presence = self.get_presence(x) |             presence = self.get_presence(int(port_cfg.index)) | ||||||
|             if presence != self.presence[x]: |             if presence != self.presence[int(port_cfg.index)]: | ||||||
|                 self.presence[x] = presence |                 self.presence[int(port_cfg.index)] = presence | ||||||
|                 if presence: |                 if presence: | ||||||
|                     port_dict[x] = SFP_STATUS_INSERTED |                     port_dict[int(port_cfg.index)] = SFP_STATUS_INSERTED | ||||||
|                 else: |                 else: | ||||||
|                     port_dict[x] = SFP_STATUS_REMOVED |                     port_dict[int(port_cfg.index)] = SFP_STATUS_REMOVED | ||||||
|  |  | ||||||
|         if bool(port_dict): |         if bool(port_dict): | ||||||
|             self.data['last'] = now |             self.data['last'] = now | ||||||
|   | |||||||
| @@ -0,0 +1,3 @@ | |||||||
|  | { | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,70 @@ | |||||||
|  | {# Default values which will be used if no actual configura available #} | ||||||
|  | {% set default_cable = '40m' %} | ||||||
|  | {% set default_ports_num = 54 -%} | ||||||
|  |  | ||||||
|  | {# Port configuration to cable length look-up table #} | ||||||
|  | {# Each record describes mapping of DUT (DUT port) role and neighbor role to cable length #} | ||||||
|  | {# Roles described in the minigraph #} | ||||||
|  | {% set ports2cable = { | ||||||
|  |         'torrouter_server'       : '5m', | ||||||
|  |         'leafrouter_torrouter'   : '40m', | ||||||
|  |         'spinerouter_leafrouter' : '300m' | ||||||
|  |         } | ||||||
|  | %} | ||||||
|  |  | ||||||
|  | {%- macro cable_length(port_name) -%} | ||||||
|  |     {%- set cable_len = [] -%} | ||||||
|  |     {%- for local_port in DEVICE_NEIGHBOR -%} | ||||||
|  |         {%- if local_port == port_name -%} | ||||||
|  |             {%- if DEVICE_NEIGHBOR_METADATA[DEVICE_NEIGHBOR[local_port].name] -%} | ||||||
|  |                 {%- set neighbor = DEVICE_NEIGHBOR_METADATA[DEVICE_NEIGHBOR[local_port].name] -%} | ||||||
|  |                 {%- set neighbor_role = neighbor.type -%} | ||||||
|  |                 {%- set roles1 = switch_role + '_' + neighbor_role %} | ||||||
|  |                 {%- set roles2 = neighbor_role + '_' + switch_role -%} | ||||||
|  |                 {%- set roles1 = roles1 | lower -%} | ||||||
|  |                 {%- set roles2 = roles2 | lower -%} | ||||||
|  |                 {%- if roles1 in ports2cable -%} | ||||||
|  |                     {%- if cable_len.append(ports2cable[roles1]) -%}{%- endif -%} | ||||||
|  |                 {%- elif roles2 in ports2cable -%} | ||||||
|  |                     {%- if cable_len.append(ports2cable[roles2]) -%}{%- endif -%} | ||||||
|  |                 {%- endif -%} | ||||||
|  |             {%- endif -%} | ||||||
|  |         {%- endif -%} | ||||||
|  |     {%- endfor -%} | ||||||
|  |     {%- if cable_len -%} | ||||||
|  |         {{ cable_len.0 }} | ||||||
|  |     {%- else -%} | ||||||
|  |         {{ default_cable }} | ||||||
|  |     {%- endif -%} | ||||||
|  | {% endmacro %} | ||||||
|  |  | ||||||
|  | {%- if DEVICE_METADATA is defined %} | ||||||
|  | {%- set switch_role = DEVICE_METADATA['localhost']['type'] %} | ||||||
|  | {%- endif -%} | ||||||
|  |  | ||||||
|  | {# Generate list of ports if not defined #} | ||||||
|  | {% if PORT is not defined %} | ||||||
|  |     {% set PORT = [] %} | ||||||
|  |     {% for port_idx in range(1,default_ports_num+1) %} | ||||||
|  |         {% if PORT.append("Ethernet%d" % (port_idx)) %}{% endif %} | ||||||
|  |     {% endfor %} | ||||||
|  | {% endif -%} | ||||||
|  |  | ||||||
|  | {% set port_names_list = [] %} | ||||||
|  | {% for port in PORT %} | ||||||
|  |     {%- if port_names_list.append(port) %}{% endif %} | ||||||
|  | {% endfor %} | ||||||
|  | {% set port_names = port_names_list | join(',') -%} | ||||||
|  |  | ||||||
|  | { | ||||||
|  |     "CABLE_LENGTH": { | ||||||
|  |         "AZURE": { | ||||||
|  |     {% for port in PORT %} | ||||||
|  |         {% set cable = cable_length(port) -%} | ||||||
|  |         "{{ port }}": "{{ cable }}"{%- if not loop.last -%},{% endif %} | ||||||
|  |  | ||||||
|  |     {% endfor %} | ||||||
|  |     } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| @@ -0,0 +1,21 @@ | |||||||
|  | # PG lossless profiles. | ||||||
|  | # speed cable size    xon  xoff threshold | ||||||
|  |    1000  5m   34816  18432 16384  0 | ||||||
|  |   10000  5m   34816  18432 16384  0 | ||||||
|  |   25000  5m   34816  18432 16384  0 | ||||||
|  |   40000  5m   34816  18432 16384  0 | ||||||
|  |   50000  5m   34816  18432 16384  0 | ||||||
|  |  100000  5m   36864  18432 18432  0 | ||||||
|  |    1000  40m  36864  18432 18432  0 | ||||||
|  |   10000  40m  36864  18432 18432  0 | ||||||
|  |   25000  40m  39936  18432 21504  0 | ||||||
|  |   40000  40m  41984  18432 23552  0 | ||||||
|  |   50000  40m  41984  18432 23552  0 | ||||||
|  |  100000  40m  54272  18432 35840  0 | ||||||
|  |    1000  300m 49152  18432 30720  0 | ||||||
|  |   10000  300m 49152  18432 30720  0 | ||||||
|  |   25000  300m 71680  18432 53248  0 | ||||||
|  |   40000  300m 94208  18432 75776  0 | ||||||
|  |   50000  300m 94208  18432 75776  0 | ||||||
|  |  100000  300m 184320 18432 165888 0 | ||||||
|  |  | ||||||
| @@ -0,0 +1,27 @@ | |||||||
|  | # name          lanes          alias             index     speed    fec | ||||||
|  | Ethernet0       0              eth-0-1           0         10000    none | ||||||
|  | Ethernet1       1              eth-0-2           1         10000    none | ||||||
|  | Ethernet2       2              eth-0-3           2         10000    none | ||||||
|  | Ethernet3       3              eth-0-4           3         10000    none | ||||||
|  | Ethernet4       8              eth-0-5           4         10000    none | ||||||
|  | Ethernet5       9              eth-0-6           5         10000    none | ||||||
|  | Ethernet6       10             eth-0-7           6         10000    none | ||||||
|  | Ethernet7       11             eth-0-8           7         10000    none | ||||||
|  | Ethernet8       20             eth-0-9           8         10000    none | ||||||
|  | Ethernet9       21             eth-0-10          9         10000    none | ||||||
|  | Ethernet10      22             eth-0-11          10        10000    none | ||||||
|  | Ethernet11      23             eth-0-12          11        10000    none | ||||||
|  | Ethernet12      12             eth-0-13          12        10000    none | ||||||
|  | Ethernet13      13             eth-0-14          13        10000    none | ||||||
|  | Ethernet14      14             eth-0-15          14        10000    none | ||||||
|  | Ethernet15      15             eth-0-16          15        10000    none | ||||||
|  | Ethernet16      24             eth-0-17          16        10000    none | ||||||
|  | Ethernet17      25             eth-0-18          17        10000    none | ||||||
|  | Ethernet18      26             eth-0-19          18        10000    none | ||||||
|  | Ethernet19      27             eth-0-20          19        10000    none | ||||||
|  | Ethernet20      28             eth-0-21          20        10000    none | ||||||
|  | Ethernet21      29             eth-0-22          21        10000    none | ||||||
|  | Ethernet22      30             eth-0-23          22        10000    none | ||||||
|  | Ethernet23      31             eth-0-24          23        10000    none | ||||||
|  | Ethernet24      61,60,63,62    eth-0-25          24        40000    none | ||||||
|  | Ethernet25      45,44,47,46    eth-0-26          25        40000    none | ||||||
| @@ -0,0 +1 @@ | |||||||
|  | {%- include 'qos_config.j2' %} | ||||||
| @@ -0,0 +1,2 @@ | |||||||
|  | SAI_INIT_CONFIG_FILE=/etc/centec/E530-24x2q-chip-profile.txt | ||||||
|  | SAI_HW_PORT_PROFILE_ID_CONFIG_FILE=/etc/centec/E530-24x2q-datapath-cfg.txt | ||||||
							
								
								
									
										1
									
								
								device/centec/arm64-centec_e530_24x2q-r0/default_sku
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								device/centec/arm64-centec_e530_24x2q-r0/default_sku
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | E530-24x2q l2 | ||||||
							
								
								
									
										12
									
								
								device/centec/arm64-centec_e530_24x2q-r0/fancontrol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								device/centec/arm64-centec_e530_24x2q-r0/fancontrol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | # Configuration file generated by pwmconfig, changes will be lost | ||||||
|  | INTERVAL=10 | ||||||
|  | DEVPATH=hwmon1=devices/platform/soc/soc:fan-ctc5236 | ||||||
|  | DEVNAME=hwmon1=ctc5236fan | ||||||
|  | FCTEMPS=hwmon1/pwm1=hwmon1/temp1_input hwmon1/pwm2=hwmon1/temp1_input hwmon1/pwm3=hwmon1/temp1_input | ||||||
|  | FCFANS=hwmon1/pwm1=hwmon1/fan1_input hwmon1/pwm2=hwmon1/fan2_input hwmon1/pwm3=hwmon1/fan3_input | ||||||
|  | MINTEMP=hwmon1/pwm1=30 hwmon1/pwm2=30 hwmon1/pwm3=30 | ||||||
|  | MAXTEMP=hwmon1/pwm1=90 hwmon1/pwm2=90 hwmon1/pwm3=90 | ||||||
|  | MINSTART=hwmon1/pwm1=12 hwmon1/pwm2=12 hwmon1/pwm3=12 | ||||||
|  | MINSTOP=hwmon1/pwm1=6 hwmon1/pwm2=6 hwmon1/pwm3=6 | ||||||
|  | MINPWM=hwmon1/pwm1=6 hwmon1/pwm2=6 hwmon1/pwm3=6 | ||||||
|  | MAXPWM=hwmon1/pwm1=18 hwmon1/pwm2=18 hwmon1/pwm3=18 | ||||||
| @@ -0,0 +1,8 @@ | |||||||
|  | { | ||||||
|  |         "chassis": { | ||||||
|  |                 "E530-24x2q": { | ||||||
|  |                         "component": { | ||||||
|  |                         } | ||||||
|  |                 } | ||||||
|  |         } | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								device/centec/arm64-centec_e530_24x2q-r0/platform_reboot
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										11
									
								
								device/centec/arm64-centec_e530_24x2q-r0/platform_reboot
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | #!/usr/bin/python | ||||||
|  | import os | ||||||
|  |  | ||||||
|  | def main(): | ||||||
|  |     # reboot the system | ||||||
|  |     os.system('echo 502 > /sys/class/gpio/export') | ||||||
|  |     os.system('echo out > /sys/class/gpio/gpio502/direction') | ||||||
|  |     os.system('echo 1 > /sys/class/gpio/gpio502/value') | ||||||
|  |  | ||||||
|  | if __name__ == "__main__": | ||||||
|  |     main() | ||||||
							
								
								
									
										22
									
								
								device/centec/arm64-centec_e530_24x2q-r0/plugins/eeprom.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								device/centec/arm64-centec_e530_24x2q-r0/plugins/eeprom.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | # Centec E550-24X8Y2C | ||||||
|  | # | ||||||
|  | # Platform and model specific eeprom subclass, inherits from the base class, | ||||||
|  | # and provides the followings: | ||||||
|  | # - the eeprom format definition | ||||||
|  | # - specific encoder/decoder if there is special need | ||||||
|  | ############################################################################# | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_eeprom import eeprom_tlvinfo | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError (str(e) + "- required module not found") | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class board(eeprom_tlvinfo.TlvInfoDecoder): | ||||||
|  |  | ||||||
|  |     def __init__(self, name, path, cpld_root, ro): | ||||||
|  |         self.eeprom_path = "/dev/mtd3" | ||||||
|  |         super(board, self).__init__(self.eeprom_path, 0, '', True) | ||||||
							
								
								
									
										165
									
								
								device/centec/arm64-centec_e530_24x2q-r0/plugins/led_control.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								device/centec/arm64-centec_e530_24x2q-r0/plugins/led_control.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,165 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  | # | ||||||
|  | # led_control.py | ||||||
|  | # | ||||||
|  | # Platform-specific LED control functionality for SONiC | ||||||
|  | # | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     import os | ||||||
|  |     import re | ||||||
|  |     import syslog | ||||||
|  |     import collections | ||||||
|  |     from sonic_led.led_control_base import LedControlBase | ||||||
|  |     from sonic_py_common import device_info | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError(str(e) + " - required module not found") | ||||||
|  |  | ||||||
|  | USR_SHARE_SONIC_PATH = "/usr/share/sonic" | ||||||
|  | HOST_DEVICE_PATH = USR_SHARE_SONIC_PATH + "/device" | ||||||
|  | CONTAINER_PLATFORM_PATH = USR_SHARE_SONIC_PATH + "/platform" | ||||||
|  |  | ||||||
|  | def DBG_PRINT(str): | ||||||
|  |     syslog.openlog("centec-led") | ||||||
|  |     syslog.syslog(syslog.LOG_INFO, str) | ||||||
|  |     syslog.closelog() | ||||||
|  |  | ||||||
|  | class LedControl(LedControlBase): | ||||||
|  |     """Platform specific LED control class""" | ||||||
|  |  | ||||||
|  |     # Constructor | ||||||
|  |     def __init__(self): | ||||||
|  |  | ||||||
|  |         self.mac_to_led = { | ||||||
|  |             0:  1, | ||||||
|  |             1:  2, | ||||||
|  |             2:  3, | ||||||
|  |             3:  4, | ||||||
|  |             8:  5, | ||||||
|  |             9:  6, | ||||||
|  |             10: 7, | ||||||
|  |             11: 8, | ||||||
|  |             20: 9, | ||||||
|  |             21:10, | ||||||
|  |             22:11, | ||||||
|  |             23:12, | ||||||
|  |             12:13, | ||||||
|  |             13:14, | ||||||
|  |             14:15, | ||||||
|  |             15:16, | ||||||
|  |             24:17, | ||||||
|  |             25:18, | ||||||
|  |             26:19, | ||||||
|  |             27:20, | ||||||
|  |             28:21, | ||||||
|  |             29:22, | ||||||
|  |             30:23, | ||||||
|  |             31:24, | ||||||
|  |             61:-1, | ||||||
|  |             60:25, | ||||||
|  |             63:-1, | ||||||
|  |             62:-1, | ||||||
|  |             45:-1, | ||||||
|  |             44:26, | ||||||
|  |             47:-1, | ||||||
|  |             46:-1, | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if os.path.isdir(CONTAINER_PLATFORM_PATH): | ||||||
|  |             platform_path = CONTAINER_PLATFORM_PATH | ||||||
|  |         else: | ||||||
|  |             platform = device_info.get_platform() | ||||||
|  |             if platform is None: | ||||||
|  |                 raise | ||||||
|  |             platform_path = os.path.join(HOST_DEVICE_PATH, platform) | ||||||
|  |  | ||||||
|  |         port_config_file = "/".join([platform_path, "E530-24x2q", "port_config.ini"]) | ||||||
|  |         try: | ||||||
|  |             f = open(port_config_file) | ||||||
|  |         except: | ||||||
|  |             raise | ||||||
|  |         for line in f: | ||||||
|  |             line.strip() | ||||||
|  |             if re.search('^#', line) is not None: | ||||||
|  |                 Port_cfg = collections.namedtuple('Port_cfg', line.split()[1:]) | ||||||
|  |                 break | ||||||
|  |         f.close() | ||||||
|  |         f = open(port_config_file) | ||||||
|  |         self._port_cfgs = [Port_cfg(*tuple((line.strip().split()))) | ||||||
|  |                            for line in f if re.search('^#', line) is None] | ||||||
|  |         f.close() | ||||||
|  |  | ||||||
|  |         self.LED_MODE_UP = [11, 11] | ||||||
|  |         self.LED_MODE_DOWN = [7, 7] | ||||||
|  |         self.f_led = "/sys/class/leds/{}/brightness" | ||||||
|  |         self._initDefaultConfig() | ||||||
|  |  | ||||||
|  |     # Helper method to map SONiC port name to index | ||||||
|  |     def _port_name_to_index(self, port_name): | ||||||
|  |         for port_cfg in self._port_cfgs: | ||||||
|  |             if port_name == port_cfg.name: | ||||||
|  |                 macs = [int(x) for x in (port_cfg.lanes.split(','))] | ||||||
|  |                 led = self.mac_to_led[min(macs)] | ||||||
|  |                 if led < 0: | ||||||
|  |                     return None | ||||||
|  |                 return led | ||||||
|  |         return None | ||||||
|  |  | ||||||
|  |     def _port_state_to_mode(self, port_idx, state): | ||||||
|  |         if state == "up": | ||||||
|  |             return self.LED_MODE_UP[1] if port_idx == 25 or port_idx == 26 else self.LED_MODE_UP[0] | ||||||
|  |         else: | ||||||
|  |             return self.LED_MODE_DOWN[1] if port_idx == 25 or port_idx == 26 else self.LED_MODE_DOWN[0] | ||||||
|  |  | ||||||
|  |     def _port_led_mode_update(self, port_idx, ledMode): | ||||||
|  |         with open(self.f_led.format("port{}".format(port_idx)), 'w') as led_file: | ||||||
|  |             led_file.write(str(ledMode)) | ||||||
|  |  | ||||||
|  |     def _initSystemLed(self): | ||||||
|  |         try: | ||||||
|  |             with open(self.f_led.format("system"), 'w') as led_file: | ||||||
|  |                 led_file.write("1") | ||||||
|  |             DBG_PRINT("init system led to normal") | ||||||
|  |             with open(self.f_led.format("idn"), 'w') as led_file: | ||||||
|  |                 led_file.write("1") | ||||||
|  |             DBG_PRINT("init idn led to off") | ||||||
|  |         except IOError as e: | ||||||
|  |             DBG_PRINT(str(e)) | ||||||
|  |  | ||||||
|  |     def _initPanelLed(self): | ||||||
|  |         with open(self.f_led.format("port1"), 'r') as led_file: | ||||||
|  |             shouldInit = (int(led_file.read()) == 0) | ||||||
|  |  | ||||||
|  |         if shouldInit == True: | ||||||
|  |             for port_cfg in self._port_cfgs: | ||||||
|  |                 macs = [int(x) for x in (port_cfg.lanes.split(','))] | ||||||
|  |                 led = self.mac_to_led[min(macs)] | ||||||
|  |                 if led < 0: | ||||||
|  |                     continue | ||||||
|  |                 defmode = self._port_state_to_mode(led, "down") | ||||||
|  |                 with open(self.f_led.format("port{}".format(led)), 'w') as led_file: | ||||||
|  |                     led_file.write(str(defmode)) | ||||||
|  |                     DBG_PRINT("init port{} led to mode={}".format(led, defmode)) | ||||||
|  |  | ||||||
|  |     def _initDefaultConfig(self): | ||||||
|  |         DBG_PRINT("start init led") | ||||||
|  |  | ||||||
|  |         self._initSystemLed() | ||||||
|  |         self._initPanelLed() | ||||||
|  |  | ||||||
|  |         DBG_PRINT("init led done") | ||||||
|  |  | ||||||
|  |     # Concrete implementation of port_link_state_change() method | ||||||
|  |     def port_link_state_change(self, portname, state): | ||||||
|  |         port_idx = self._port_name_to_index(portname) | ||||||
|  |         if port_idx is None: | ||||||
|  |             return | ||||||
|  |         ledMode = self._port_state_to_mode(port_idx, state) | ||||||
|  |         with open(self.f_led.format("port{}".format(port_idx)), 'r') as led_file: | ||||||
|  |             saveMode = int(led_file.read()) | ||||||
|  |  | ||||||
|  |         if ledMode == saveMode: | ||||||
|  |             return | ||||||
|  |  | ||||||
|  |         self._port_led_mode_update(port_idx, ledMode) | ||||||
|  |         DBG_PRINT("update {} led mode from {} to {}".format(portname, saveMode, ledMode)) | ||||||
							
								
								
									
										72
									
								
								device/centec/arm64-centec_e530_24x2q-r0/plugins/psuutil.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								device/centec/arm64-centec_e530_24x2q-r0/plugins/psuutil.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | # Centec | ||||||
|  | # | ||||||
|  | # Module contains an implementation of SONiC PSU Base API and | ||||||
|  | # provides the PSUs status which are available in the platform | ||||||
|  | # | ||||||
|  | ############################################################################# | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_psu.psu_base import PsuBase | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError (str(e) + "- required module not found") | ||||||
|  |  | ||||||
|  | class PsuUtil(PsuBase): | ||||||
|  |     """Platform-specific PSUutil class""" | ||||||
|  |  | ||||||
|  |     def __init__(self): | ||||||
|  |         PsuBase.__init__(self) | ||||||
|  |  | ||||||
|  |         self.psu_path = "/sys/class/psu/psu{}/" | ||||||
|  |         self.psu_presence = "psu_presence" | ||||||
|  |         self.psu_oper_status = "psu_status" | ||||||
|  |  | ||||||
|  |     def get_num_psus(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the number of PSUs available on the device | ||||||
|  |  | ||||||
|  |         :return: An integer, the number of PSUs available on the device | ||||||
|  |         """ | ||||||
|  |         return 2 | ||||||
|  |  | ||||||
|  |     def get_psu_status(self, index): | ||||||
|  |         """ | ||||||
|  |         Retrieves the oprational status of power supply unit (PSU) defined | ||||||
|  |                 by 1-based index <index> | ||||||
|  |  | ||||||
|  |         :param index: An integer, 1-based index of the PSU of which to query status | ||||||
|  |         :return: Boolean, True if PSU is operating properly, False if PSU is faulty | ||||||
|  |         """ | ||||||
|  |         if index is None: | ||||||
|  |             return False | ||||||
|  |  | ||||||
|  |         status = 0 | ||||||
|  |         try: | ||||||
|  |             with open(self.psu_path.format(index) + self.psu_oper_status, 'r') as power_status: | ||||||
|  |                 status = int(power_status.read()) | ||||||
|  |         except IOError: | ||||||
|  |             return False | ||||||
|  |  | ||||||
|  |         return status == 1 | ||||||
|  |  | ||||||
|  |     def get_psu_presence(self, index): | ||||||
|  |         """ | ||||||
|  |         Retrieves the presence status of power supply unit (PSU) defined | ||||||
|  |                 by 1-based index <index> | ||||||
|  |  | ||||||
|  |         :param index: An integer, 1-based index of the PSU of which to query status | ||||||
|  |         :return: Boolean, True if PSU is plugged, False if not | ||||||
|  |         """ | ||||||
|  |         if index is None: | ||||||
|  |             return False | ||||||
|  |  | ||||||
|  |         status = 0 | ||||||
|  |         try: | ||||||
|  |             with open(self.psu_path.format(index) + self.psu_presence, 'r') as presence_status: | ||||||
|  |                 status = int(presence_status.read()) | ||||||
|  |         except IOError: | ||||||
|  |             return False | ||||||
|  |  | ||||||
|  |         return status == 1 | ||||||
							
								
								
									
										200
									
								
								device/centec/arm64-centec_e530_24x2q-r0/plugins/sfputil.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										200
									
								
								device/centec/arm64-centec_e530_24x2q-r0/plugins/sfputil.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,200 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
|  | # sfputil.py | ||||||
|  | # | ||||||
|  | # Platform-specific SFP transceiver interface for SONiC | ||||||
|  | # | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     import os | ||||||
|  |     import re | ||||||
|  |     import time | ||||||
|  |     import collections | ||||||
|  |     from sonic_sfp.sfputilbase import SfpUtilBase | ||||||
|  |     from sonic_py_common import device_info | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError("%s - required module not found" % str(e)) | ||||||
|  |  | ||||||
|  | SFP_STATUS_INSERTED = '1' | ||||||
|  | SFP_STATUS_REMOVED = '0' | ||||||
|  | USR_SHARE_SONIC_PATH = "/usr/share/sonic" | ||||||
|  | HOST_DEVICE_PATH = USR_SHARE_SONIC_PATH + "/device" | ||||||
|  | CONTAINER_PLATFORM_PATH = USR_SHARE_SONIC_PATH + "/platform" | ||||||
|  |  | ||||||
|  | class SfpUtil(SfpUtilBase): | ||||||
|  |     """Platform-specific SfpUtil class""" | ||||||
|  |  | ||||||
|  |     def __init__(self): | ||||||
|  |         self.mac_to_sfp = { | ||||||
|  |             0:  1, | ||||||
|  |             1:  2, | ||||||
|  |             2:  3, | ||||||
|  |             3:  4, | ||||||
|  |             8:  5, | ||||||
|  |             9:  6, | ||||||
|  |             10: 7, | ||||||
|  |             11: 8, | ||||||
|  |             20: 9, | ||||||
|  |             21:10, | ||||||
|  |             22:11, | ||||||
|  |             23:12, | ||||||
|  |             12:13, | ||||||
|  |             13:14, | ||||||
|  |             14:15, | ||||||
|  |             15:16, | ||||||
|  |             24:17, | ||||||
|  |             25:18, | ||||||
|  |             26:19, | ||||||
|  |             27:20, | ||||||
|  |             28:21, | ||||||
|  |             29:22, | ||||||
|  |             30:23, | ||||||
|  |             31:24, | ||||||
|  |             61:25, | ||||||
|  |             60:25, | ||||||
|  |             63:25, | ||||||
|  |             62:25, | ||||||
|  |             45:26, | ||||||
|  |             44:26, | ||||||
|  |             47:26, | ||||||
|  |             46:26, | ||||||
|  |         } | ||||||
|  |         self.logical = [] | ||||||
|  |         self.physical_to_logical = {} | ||||||
|  |         self.logical_to_physical = {} | ||||||
|  |         self.logical_to_asic = {} | ||||||
|  |         self.data = {'valid':0, 'last':0} | ||||||
|  |         self.f_sfp_present = "/sys/class/sfp/sfp{}/sfp_presence" | ||||||
|  |         self.f_sfp_enable = "/sys/class/sfp/sfp{}/sfp_enable" | ||||||
|  |  | ||||||
|  |         if os.path.isdir(CONTAINER_PLATFORM_PATH): | ||||||
|  |             platform_path = CONTAINER_PLATFORM_PATH | ||||||
|  |         else: | ||||||
|  |             platform = device_info.get_platform() | ||||||
|  |             if platform is None: | ||||||
|  |                 raise | ||||||
|  |             platform_path = os.path.join(HOST_DEVICE_PATH, platform) | ||||||
|  |  | ||||||
|  |         port_config_file = "/".join([platform_path, "E530-24x2q", "port_config.ini"]) | ||||||
|  |         try: | ||||||
|  |             f = open(port_config_file) | ||||||
|  |         except: | ||||||
|  |             raise | ||||||
|  |         for line in f: | ||||||
|  |             line.strip() | ||||||
|  |             if re.search('^#', line) is not None: | ||||||
|  |                 Port_cfg = collections.namedtuple('Port_cfg', line.split()[1:]) | ||||||
|  |                 break | ||||||
|  |         f.close() | ||||||
|  |         f = open(port_config_file) | ||||||
|  |         self._port_cfgs = [Port_cfg(*tuple((line.strip().split()))) | ||||||
|  |                            for line in f if re.search('^#', line) is None] | ||||||
|  |         f.close() | ||||||
|  |  | ||||||
|  |         self.PORT_START = 256 | ||||||
|  |         self.PORT_END = 0 | ||||||
|  |         for port_cfg in self._port_cfgs: | ||||||
|  |             if int(port_cfg.index) <= self.PORT_START: | ||||||
|  |                 self.PORT_START = int(port_cfg.index) | ||||||
|  |             elif int(port_cfg.index) >= self.PORT_END: | ||||||
|  |                 self.PORT_END = int(port_cfg.index) | ||||||
|  |  | ||||||
|  |         self.eeprom_mapping = {} | ||||||
|  |         self.presence = {} | ||||||
|  |         for port_cfg in self._port_cfgs: | ||||||
|  |             sfp_idx = self.mac_to_sfp[int(port_cfg.lanes.split(',')[0])] | ||||||
|  |             if sfp_idx > 0: | ||||||
|  |                 self.eeprom_mapping[int(port_cfg.index)] = "/sys/class/sfp/sfp{}/sfp_eeprom".format(sfp_idx) | ||||||
|  |                 self.logical.append(port_cfg.name) | ||||||
|  |             else: | ||||||
|  |                 self.eeprom_mapping[int(port_cfg.index)] = None | ||||||
|  |             self.presence[int(port_cfg.index)] = False | ||||||
|  |  | ||||||
|  |         SfpUtilBase.__init__(self) | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def port_start(self): | ||||||
|  |         return self.PORT_START | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def port_end(self): | ||||||
|  |         return self.PORT_END | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def sfp_base(self): | ||||||
|  |         return self.PORT_START | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def qsfp_ports(self): | ||||||
|  |         start = 256 | ||||||
|  |         end = 0 | ||||||
|  |         for port_cfg in self._port_cfgs: | ||||||
|  |             sfp_idx = self.mac_to_sfp[int(port_cfg.lanes.split(',')[0])] | ||||||
|  |             if sfp_idx == 25 or sfp_idx == 26: | ||||||
|  |                 if int(port_cfg.index) <= start: | ||||||
|  |                     start = int(port_cfg.index) | ||||||
|  |                 elif int(port_cfg.index) >= end: | ||||||
|  |                     end = int(port_cfg.index) | ||||||
|  |         return range(start, end + 1) | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def port_to_eeprom_mapping(self): | ||||||
|  |         return self.eeprom_mapping | ||||||
|  |  | ||||||
|  |     def is_logical_port(self, port_name): | ||||||
|  |         return True | ||||||
|  |  | ||||||
|  |     def get_presence(self, port_num): | ||||||
|  |         for port_cfg in self._port_cfgs: | ||||||
|  |             if int(port_cfg.index) == port_num: | ||||||
|  |                 sfp_idx = self.mac_to_sfp[int(port_cfg.lanes.split(',')[0])] | ||||||
|  |                 if sfp_idx >= 0: | ||||||
|  |                     try: | ||||||
|  |                         with open(self.f_sfp_present.format(sfp_idx), 'r') as sfp_file: | ||||||
|  |                             return 1 == int(sfp_file.read()) | ||||||
|  |                     except IOError as e: | ||||||
|  |                         DBG_PRINT(str(e)) | ||||||
|  |         return False | ||||||
|  |  | ||||||
|  |     def get_low_power_mode(self, port_num): | ||||||
|  |         return False | ||||||
|  |  | ||||||
|  |     def set_low_power_mode(self, port_num, lpmode): | ||||||
|  |         return False | ||||||
|  |  | ||||||
|  |     def reset(self, port_num): | ||||||
|  |         return False | ||||||
|  |  | ||||||
|  |     def read_porttab_mappings(self, porttabfile, asic_inst = 0): | ||||||
|  |         for port_cfg in self._port_cfgs: | ||||||
|  |             self.logical_to_physical[port_cfg.name] = [int(port_cfg.index)] | ||||||
|  |             self.logical_to_asic[port_cfg.name] = 0 | ||||||
|  |             self.physical_to_logical[int(port_cfg.index)] = [port_cfg.name] | ||||||
|  |  | ||||||
|  |     def get_transceiver_change_event(self, timeout=2000): | ||||||
|  |         now = time.time() | ||||||
|  |         port_dict = {} | ||||||
|  |  | ||||||
|  |         if timeout < 1000: | ||||||
|  |             timeout = 1000 | ||||||
|  |         timeout = (timeout) / float(1000) # Convert to secs | ||||||
|  |  | ||||||
|  |         if now < (self.data['last'] + timeout) and self.data['valid']: | ||||||
|  |             return True, {} | ||||||
|  |  | ||||||
|  |         for port_cfg in self._port_cfgs: | ||||||
|  |             presence = self.get_presence(int(port_cfg.index)) | ||||||
|  |             if presence != self.presence[int(port_cfg.index)]: | ||||||
|  |                 self.presence[int(port_cfg.index)] = presence | ||||||
|  |                 if presence: | ||||||
|  |                     port_dict[int(port_cfg.index)] = SFP_STATUS_INSERTED | ||||||
|  |                 else: | ||||||
|  |                     port_dict[int(port_cfg.index)] = SFP_STATUS_REMOVED | ||||||
|  |  | ||||||
|  |         if bool(port_dict): | ||||||
|  |             self.data['last'] = now | ||||||
|  |             self.data['valid'] = 1 | ||||||
|  |             return True, port_dict | ||||||
|  |         else: | ||||||
|  |             time.sleep(0.5) | ||||||
|  |             return True, {} | ||||||
| @@ -0,0 +1,3 @@ | |||||||
|  | { | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,70 @@ | |||||||
|  | {# Default values which will be used if no actual configura available #} | ||||||
|  | {% set default_cable = '40m' %} | ||||||
|  | {% set default_ports_num = 54 -%} | ||||||
|  |  | ||||||
|  | {# Port configuration to cable length look-up table #} | ||||||
|  | {# Each record describes mapping of DUT (DUT port) role and neighbor role to cable length #} | ||||||
|  | {# Roles described in the minigraph #} | ||||||
|  | {% set ports2cable = { | ||||||
|  |         'torrouter_server'       : '5m', | ||||||
|  |         'leafrouter_torrouter'   : '40m', | ||||||
|  |         'spinerouter_leafrouter' : '300m' | ||||||
|  |         } | ||||||
|  | %} | ||||||
|  |  | ||||||
|  | {%- macro cable_length(port_name) -%} | ||||||
|  |     {%- set cable_len = [] -%} | ||||||
|  |     {%- for local_port in DEVICE_NEIGHBOR -%} | ||||||
|  |         {%- if local_port == port_name -%} | ||||||
|  |             {%- if DEVICE_NEIGHBOR_METADATA[DEVICE_NEIGHBOR[local_port].name] -%} | ||||||
|  |                 {%- set neighbor = DEVICE_NEIGHBOR_METADATA[DEVICE_NEIGHBOR[local_port].name] -%} | ||||||
|  |                 {%- set neighbor_role = neighbor.type -%} | ||||||
|  |                 {%- set roles1 = switch_role + '_' + neighbor_role %} | ||||||
|  |                 {%- set roles2 = neighbor_role + '_' + switch_role -%} | ||||||
|  |                 {%- set roles1 = roles1 | lower -%} | ||||||
|  |                 {%- set roles2 = roles2 | lower -%} | ||||||
|  |                 {%- if roles1 in ports2cable -%} | ||||||
|  |                     {%- if cable_len.append(ports2cable[roles1]) -%}{%- endif -%} | ||||||
|  |                 {%- elif roles2 in ports2cable -%} | ||||||
|  |                     {%- if cable_len.append(ports2cable[roles2]) -%}{%- endif -%} | ||||||
|  |                 {%- endif -%} | ||||||
|  |             {%- endif -%} | ||||||
|  |         {%- endif -%} | ||||||
|  |     {%- endfor -%} | ||||||
|  |     {%- if cable_len -%} | ||||||
|  |         {{ cable_len.0 }} | ||||||
|  |     {%- else -%} | ||||||
|  |         {{ default_cable }} | ||||||
|  |     {%- endif -%} | ||||||
|  | {% endmacro %} | ||||||
|  |  | ||||||
|  | {%- if DEVICE_METADATA is defined %} | ||||||
|  | {%- set switch_role = DEVICE_METADATA['localhost']['type'] %} | ||||||
|  | {%- endif -%} | ||||||
|  |  | ||||||
|  | {# Generate list of ports if not defined #} | ||||||
|  | {% if PORT is not defined %} | ||||||
|  |     {% set PORT = [] %} | ||||||
|  |     {% for port_idx in range(1,default_ports_num+1) %} | ||||||
|  |         {% if PORT.append("Ethernet%d" % (port_idx)) %}{% endif %} | ||||||
|  |     {% endfor %} | ||||||
|  | {% endif -%} | ||||||
|  |  | ||||||
|  | {% set port_names_list = [] %} | ||||||
|  | {% for port in PORT %} | ||||||
|  |     {%- if port_names_list.append(port) %}{% endif %} | ||||||
|  | {% endfor %} | ||||||
|  | {% set port_names = port_names_list | join(',') -%} | ||||||
|  |  | ||||||
|  | { | ||||||
|  |     "CABLE_LENGTH": { | ||||||
|  |         "AZURE": { | ||||||
|  |     {% for port in PORT %} | ||||||
|  |         {% set cable = cable_length(port) -%} | ||||||
|  |         "{{ port }}": "{{ cable }}"{%- if not loop.last -%},{% endif %} | ||||||
|  |  | ||||||
|  |     {% endfor %} | ||||||
|  |     } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| @@ -0,0 +1,21 @@ | |||||||
|  | # PG lossless profiles. | ||||||
|  | # speed cable size    xon  xoff threshold | ||||||
|  |    1000  5m   34816  18432 16384  0 | ||||||
|  |   10000  5m   34816  18432 16384  0 | ||||||
|  |   25000  5m   34816  18432 16384  0 | ||||||
|  |   40000  5m   34816  18432 16384  0 | ||||||
|  |   50000  5m   34816  18432 16384  0 | ||||||
|  |  100000  5m   36864  18432 18432  0 | ||||||
|  |    1000  40m  36864  18432 18432  0 | ||||||
|  |   10000  40m  36864  18432 18432  0 | ||||||
|  |   25000  40m  39936  18432 21504  0 | ||||||
|  |   40000  40m  41984  18432 23552  0 | ||||||
|  |   50000  40m  41984  18432 23552  0 | ||||||
|  |  100000  40m  54272  18432 35840  0 | ||||||
|  |    1000  300m 49152  18432 30720  0 | ||||||
|  |   10000  300m 49152  18432 30720  0 | ||||||
|  |   25000  300m 71680  18432 53248  0 | ||||||
|  |   40000  300m 94208  18432 75776  0 | ||||||
|  |   50000  300m 94208  18432 75776  0 | ||||||
|  |  100000  300m 184320 18432 165888 0 | ||||||
|  |  | ||||||
| @@ -0,0 +1,53 @@ | |||||||
|  | # name          lanes          alias             index     speed    fec | ||||||
|  | Ethernet0       0              eth-0-1           0         1000     none | ||||||
|  | Ethernet1       1              eth-0-2           1         1000     none | ||||||
|  | Ethernet2       2              eth-0-3           2         1000     none | ||||||
|  | Ethernet3       3              eth-0-4           3         1000     none | ||||||
|  | Ethernet4       4              eth-0-5           4         1000     none | ||||||
|  | Ethernet5       5              eth-0-6           5         1000     none | ||||||
|  | Ethernet6       6              eth-0-7           6         1000     none | ||||||
|  | Ethernet7       7              eth-0-8           7         1000     none | ||||||
|  | Ethernet8       16             eth-0-9           8         1000     none | ||||||
|  | Ethernet9       17             eth-0-10          9         1000     none | ||||||
|  | Ethernet10      18             eth-0-11          10        1000     none | ||||||
|  | Ethernet11      19             eth-0-12          11        1000     none | ||||||
|  | Ethernet12      20             eth-0-13          12        1000     none | ||||||
|  | Ethernet13      21             eth-0-14          13        1000     none | ||||||
|  | Ethernet14      22             eth-0-15          14        1000     none | ||||||
|  | Ethernet15      23             eth-0-16          15        1000     none | ||||||
|  | Ethernet16      8              eth-0-17          16        1000     none | ||||||
|  | Ethernet17      9              eth-0-18          17        1000     none | ||||||
|  | Ethernet18      10             eth-0-19          18        1000     none | ||||||
|  | Ethernet19      11             eth-0-20          19        1000     none | ||||||
|  | Ethernet20      32             eth-0-21          20        1000     none | ||||||
|  | Ethernet21      33             eth-0-22          21        1000     none | ||||||
|  | Ethernet22      34             eth-0-23          22        1000     none | ||||||
|  | Ethernet23      35             eth-0-24          23        1000     none | ||||||
|  | Ethernet24      36             eth-0-25          24        1000     none | ||||||
|  | Ethernet25      37             eth-0-26          25        1000     none | ||||||
|  | Ethernet26      38             eth-0-27          26        1000     none | ||||||
|  | Ethernet27      39             eth-0-28          27        1000     none | ||||||
|  | Ethernet28      40             eth-0-29          28        1000     none | ||||||
|  | Ethernet29      41             eth-0-30          29        1000     none | ||||||
|  | Ethernet30      42             eth-0-31          30        1000     none | ||||||
|  | Ethernet31      43             eth-0-32          31        1000     none | ||||||
|  | Ethernet32      25             eth-0-33          32        1000     none | ||||||
|  | Ethernet33      24             eth-0-34          33        1000     none | ||||||
|  | Ethernet34      27             eth-0-35          34        1000     none | ||||||
|  | Ethernet35      26             eth-0-36          35        1000     none | ||||||
|  | Ethernet36      13             eth-0-37          36        1000     none | ||||||
|  | Ethernet37      12             eth-0-38          37        1000     none | ||||||
|  | Ethernet38      15             eth-0-39          38        1000     none | ||||||
|  | Ethernet39      14             eth-0-40          39        1000     none | ||||||
|  | Ethernet40      29             eth-0-41          40        1000     none | ||||||
|  | Ethernet41      28             eth-0-42          41        1000     none | ||||||
|  | Ethernet42      31             eth-0-43          42        1000     none | ||||||
|  | Ethernet43      30             eth-0-44          43        1000     none | ||||||
|  | Ethernet44      61             eth-0-45          44        1000     none | ||||||
|  | Ethernet45      60             eth-0-46          45        1000     none | ||||||
|  | Ethernet46      63             eth-0-47          46        1000     none | ||||||
|  | Ethernet47      62             eth-0-48          47        1000     none | ||||||
|  | Ethernet48      44             eth-0-49          48        10000    none | ||||||
|  | Ethernet49      45             eth-0-50          49        10000    none | ||||||
|  | Ethernet50      47             eth-0-51          50        10000    none | ||||||
|  | Ethernet51      46             eth-0-52          51        10000    none | ||||||
| @@ -0,0 +1 @@ | |||||||
|  | {%- include 'qos_config.j2' %} | ||||||
| @@ -0,0 +1,2 @@ | |||||||
|  | SAI_INIT_CONFIG_FILE=/etc/centec/E530-48s4x-chip-profile.txt | ||||||
|  | SAI_HW_PORT_PROFILE_ID_CONFIG_FILE=/etc/centec/E530-48s4x-datapath.txt | ||||||
							
								
								
									
										1
									
								
								device/centec/arm64-centec_e530_48s4x-r0/default_sku
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								device/centec/arm64-centec_e530_48s4x-r0/default_sku
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | E530-48s4x l2 | ||||||
							
								
								
									
										12
									
								
								device/centec/arm64-centec_e530_48s4x-r0/fancontrol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								device/centec/arm64-centec_e530_48s4x-r0/fancontrol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | # Configuration file generated by pwmconfig, changes will be lost | ||||||
|  | INTERVAL=10 | ||||||
|  | DEVPATH=hwmon1=devices/platform/soc/soc:fan-ctc5236 | ||||||
|  | DEVNAME=hwmon1=ctc5236fan | ||||||
|  | FCTEMPS=hwmon1/pwm1=hwmon1/temp1_input hwmon1/pwm2=hwmon1/temp1_input hwmon1/pwm3=hwmon1/temp1_input hwmon1/pwm4=hwmon1/temp1_input | ||||||
|  | FCFANS=hwmon1/pwm1=hwmon1/fan1_input hwmon1/pwm2=hwmon1/fan2_input hwmon1/pwm3=hwmon1/fan3_input hwmon1/pwm4=hwmon1/fan4_input | ||||||
|  | MINTEMP=hwmon1/pwm1=30 hwmon1/pwm2=30 hwmon1/pwm3=30 hwmon1/pwm4=30 | ||||||
|  | MAXTEMP=hwmon1/pwm1=90 hwmon1/pwm2=90 hwmon1/pwm3=90 hwmon1/pwm4=90 | ||||||
|  | MINSTART=hwmon1/pwm1=12 hwmon1/pwm2=12 hwmon1/pwm3=12 hwmon1/pwm4=12 | ||||||
|  | MINSTOP=hwmon1/pwm1=6 hwmon1/pwm2=6 hwmon1/pwm3=6 hwmon1/pwm4=6 | ||||||
|  | MINPWM=hwmon1/pwm1=6 hwmon1/pwm2=6 hwmon1/pwm3=6 hwmon1/pwm4=6 | ||||||
|  | MAXPWM=hwmon1/pwm1=18 hwmon1/pwm2=18 hwmon1/pwm3=18 hwmon1/pwm4=18 | ||||||
| @@ -0,0 +1,8 @@ | |||||||
|  | { | ||||||
|  |         "chassis": { | ||||||
|  |                 "E530-48s4x": { | ||||||
|  |                         "component": { | ||||||
|  |                         } | ||||||
|  |                 } | ||||||
|  |         } | ||||||
|  | } | ||||||
							
								
								
									
										12
									
								
								device/centec/arm64-centec_e530_48s4x-r0/platform_reboot
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										12
									
								
								device/centec/arm64-centec_e530_48s4x-r0/platform_reboot
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | #!/usr/bin/python | ||||||
|  | import os | ||||||
|  |  | ||||||
|  | def main(): | ||||||
|  |     # reboot the system | ||||||
|  |     os.system('modprobe i2c-dev') | ||||||
|  |     os.system('i2cset -y 0 0x36 0x23 0x0') | ||||||
|  |     os.system('sleep 1') | ||||||
|  |     os.system('i2cset -y 0 0x36 0x23 0x3') | ||||||
|  |  | ||||||
|  | if __name__ == "__main__": | ||||||
|  |     main() | ||||||
							
								
								
									
										22
									
								
								device/centec/arm64-centec_e530_48s4x-r0/plugins/eeprom.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								device/centec/arm64-centec_e530_48s4x-r0/plugins/eeprom.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | # Centec E530-48S4X | ||||||
|  | # | ||||||
|  | # Platform and model specific eeprom subclass, inherits from the base class, | ||||||
|  | # and provides the followings: | ||||||
|  | # - the eeprom format definition | ||||||
|  | # - specific encoder/decoder if there is special need | ||||||
|  | ############################################################################# | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_eeprom import eeprom_tlvinfo | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError (str(e) + "- required module not found") | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class board(eeprom_tlvinfo.TlvInfoDecoder): | ||||||
|  |  | ||||||
|  |     def __init__(self, name, path, cpld_root, ro): | ||||||
|  |         self.eeprom_path = "/dev/mtd3" | ||||||
|  |         super(board, self).__init__(self.eeprom_path, 0, '', True) | ||||||
| @@ -0,0 +1,98 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  | # | ||||||
|  | # led_control.py | ||||||
|  | # | ||||||
|  | # Platform-specific LED control functionality for SONiC | ||||||
|  | # | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_led.led_control_base import LedControlBase | ||||||
|  |     import syslog | ||||||
|  |     from socket import * | ||||||
|  |     from select import * | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError(str(e) + " - required module not found") | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def DBG_PRINT(str): | ||||||
|  |     syslog.openlog("centec-led") | ||||||
|  |     syslog.syslog(syslog.LOG_INFO, str) | ||||||
|  |     syslog.closelog() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class LedControl(LedControlBase): | ||||||
|  |     """Platform specific LED control class""" | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     # Helper method to map SONiC port name to index | ||||||
|  |     def _port_name_to_index(self, port_name): | ||||||
|  |         # Strip "Ethernet" off port name | ||||||
|  |         if not port_name.startswith(self.SONIC_PORT_NAME_PREFIX): | ||||||
|  |             return -1 | ||||||
|  |  | ||||||
|  |         port_idx = int(port_name[len(self.SONIC_PORT_NAME_PREFIX):]) | ||||||
|  |         return port_idx + 1 | ||||||
|  |  | ||||||
|  |     def _port_state_to_mode(self, port_idx, state): | ||||||
|  |         if state == "up": | ||||||
|  |             return self.LED_MODE_UP[0] if (port_idx < 49) else self.LED_MODE_UP[1] | ||||||
|  |         else: | ||||||
|  |             return self.LED_MODE_DOWN[0] if (port_idx < 49) else self.LED_MODE_DOWN[1] | ||||||
|  |  | ||||||
|  |     def _port_led_mode_update(self, port_idx, ledMode): | ||||||
|  |         with open(self.f_led.format("port{}".format(port_idx)), 'w') as led_file: | ||||||
|  |             led_file.write(str(ledMode)) | ||||||
|  |  | ||||||
|  |     def _initSystemLed(self): | ||||||
|  |         try: | ||||||
|  |             with open(self.f_led.format("system"), 'w') as led_file: | ||||||
|  |                 led_file.write("3") | ||||||
|  |             DBG_PRINT("init system led to normal") | ||||||
|  |             with open(self.f_led.format("idn"), 'w') as led_file: | ||||||
|  |                 led_file.write("1") | ||||||
|  |             DBG_PRINT("init idn led to off") | ||||||
|  |         except IOError as e: | ||||||
|  |             DBG_PRINT(str(e)) | ||||||
|  |  | ||||||
|  |     def _initPanelLed(self): | ||||||
|  |         with open(self.f_led.format("port1"), 'r') as led_file: | ||||||
|  |             shouldInit = (int(led_file.read()) == 0) | ||||||
|  |  | ||||||
|  |         if shouldInit == True: | ||||||
|  |             for idx in range(1, 53): | ||||||
|  |                 defmode = self._port_state_to_mode(idx, "down") | ||||||
|  |                 with open(self.f_led.format("port{}".format(idx)), 'w') as led_file: | ||||||
|  |                     led_file.write(str(defmode)) | ||||||
|  |                     DBG_PRINT("init port{} led to mode={}".format(idx, defmode)) | ||||||
|  |  | ||||||
|  |     def _initDefaultConfig(self): | ||||||
|  |         DBG_PRINT("start init led") | ||||||
|  |  | ||||||
|  |         self._initSystemLed() | ||||||
|  |         self._initPanelLed() | ||||||
|  |  | ||||||
|  |         DBG_PRINT("init led done") | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     # Concrete implementation of port_link_state_change() method | ||||||
|  |     def port_link_state_change(self, portname, state): | ||||||
|  |         port_idx = self._port_name_to_index(portname) | ||||||
|  |         ledMode = self._port_state_to_mode(port_idx, state) | ||||||
|  |         with open(self.f_led.format("port{}".format(port_idx)), 'r') as led_file: | ||||||
|  |             saveMode = int(led_file.read()) | ||||||
|  |  | ||||||
|  |         if ledMode == saveMode: | ||||||
|  |             return | ||||||
|  |  | ||||||
|  |         self._port_led_mode_update(port_idx, ledMode) | ||||||
|  |         DBG_PRINT("update {} led mode from {} to {}".format(portname, saveMode, ledMode)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     # Constructor | ||||||
|  |     def __init__(self): | ||||||
|  |         self.SONIC_PORT_NAME_PREFIX = "Ethernet" | ||||||
|  |         self.LED_MODE_UP = [5, 6] | ||||||
|  |         self.LED_MODE_DOWN = [7, 7] | ||||||
|  |  | ||||||
|  |         self.f_led = "/sys/class/leds/{}/brightness" | ||||||
|  |         self._initDefaultConfig() | ||||||
							
								
								
									
										72
									
								
								device/centec/arm64-centec_e530_48s4x-r0/plugins/psuutil.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								device/centec/arm64-centec_e530_48s4x-r0/plugins/psuutil.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | # Centec | ||||||
|  | # | ||||||
|  | # Module contains an implementation of SONiC PSU Base API and | ||||||
|  | # provides the PSUs status which are available in the platform | ||||||
|  | # | ||||||
|  | ############################################################################# | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_psu.psu_base import PsuBase | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError (str(e) + "- required module not found") | ||||||
|  |  | ||||||
|  | class PsuUtil(PsuBase): | ||||||
|  |     """Platform-specific PSUutil class""" | ||||||
|  |  | ||||||
|  |     def __init__(self): | ||||||
|  |         PsuBase.__init__(self) | ||||||
|  |  | ||||||
|  |         self.psu_path = "/sys/class/psu/psu{}/" | ||||||
|  |         self.psu_presence = "psu_presence" | ||||||
|  |         self.psu_oper_status = "psu_status" | ||||||
|  |  | ||||||
|  |     def get_num_psus(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the number of PSUs available on the device | ||||||
|  |  | ||||||
|  |         :return: An integer, the number of PSUs available on the device | ||||||
|  |         """ | ||||||
|  |         return 2 | ||||||
|  |  | ||||||
|  |     def get_psu_status(self, index): | ||||||
|  |         """ | ||||||
|  |         Retrieves the oprational status of power supply unit (PSU) defined | ||||||
|  |                 by 1-based index <index> | ||||||
|  |  | ||||||
|  |         :param index: An integer, 1-based index of the PSU of which to query status | ||||||
|  |         :return: Boolean, True if PSU is operating properly, False if PSU is faulty | ||||||
|  |         """ | ||||||
|  |         if index is None: | ||||||
|  |             return False | ||||||
|  |  | ||||||
|  |         status = 0 | ||||||
|  |         try: | ||||||
|  |             with open(self.psu_path.format(index) + self.psu_oper_status, 'r') as power_status: | ||||||
|  |                 status = int(power_status.read()) | ||||||
|  |         except IOError: | ||||||
|  |             return False | ||||||
|  |  | ||||||
|  |         return status == 1 | ||||||
|  |  | ||||||
|  |     def get_psu_presence(self, index): | ||||||
|  |         """ | ||||||
|  |         Retrieves the presence status of power supply unit (PSU) defined | ||||||
|  |                 by 1-based index <index> | ||||||
|  |  | ||||||
|  |         :param index: An integer, 1-based index of the PSU of which to query status | ||||||
|  |         :return: Boolean, True if PSU is plugged, False if not | ||||||
|  |         """ | ||||||
|  |         if index is None: | ||||||
|  |             return False | ||||||
|  |  | ||||||
|  |         status = 0 | ||||||
|  |         try: | ||||||
|  |             with open(self.psu_path.format(index) + self.psu_presence, 'r') as presence_status: | ||||||
|  |                 status = int(presence_status.read()) | ||||||
|  |         except IOError: | ||||||
|  |             return False | ||||||
|  |  | ||||||
|  |         return status == 1 | ||||||
							
								
								
									
										161
									
								
								device/centec/arm64-centec_e530_48s4x-r0/plugins/sfputil.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								device/centec/arm64-centec_e530_48s4x-r0/plugins/sfputil.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,161 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
|  | # sfputil.py | ||||||
|  | # | ||||||
|  | # Platform-specific SFP transceiver interface for SONiC | ||||||
|  | # | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     import time | ||||||
|  |     from socket import * | ||||||
|  |     from select import * | ||||||
|  |     from sonic_sfp.sfputilbase import SfpUtilBase | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError("%s - required module not found" % str(e)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def DBG_PRINT(str): | ||||||
|  |     print(str + "\n") | ||||||
|  |  | ||||||
|  | SFP_STATUS_INSERTED = '1' | ||||||
|  | SFP_STATUS_REMOVED = '0' | ||||||
|  |  | ||||||
|  | class SfpUtil(SfpUtilBase): | ||||||
|  |     """Platform-specific SfpUtil class""" | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def port_start(self): | ||||||
|  |         return self.PORT_START | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def port_end(self): | ||||||
|  |         return self.PORT_END | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def sfp_base(self): | ||||||
|  |         return self.SFP_BASE | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def qsfp_ports(self): | ||||||
|  |         return () | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def port_to_eeprom_mapping(self): | ||||||
|  |         return self.eeprom_mapping | ||||||
|  |  | ||||||
|  |     def is_logical_port(self, port_name): | ||||||
|  |         return True | ||||||
|  |  | ||||||
|  |     def get_eeprom_data(self, port): | ||||||
|  |         ret = None | ||||||
|  |         port_num = self.get_logical_to_physical(port)[0] + 1 | ||||||
|  |         if port_num < self.port_start or port_num > self.port_end: | ||||||
|  |             return ret | ||||||
|  |         if port_num < self.sfp_base: | ||||||
|  |             return ret | ||||||
|  |         try: | ||||||
|  |             with open(self.eeprom_mapping[port_num], 'r') as eeprom_file: | ||||||
|  |                 ret = eeprom_file.read() | ||||||
|  |         except IOError as e: | ||||||
|  |             DBG_PRINT(str(e)) | ||||||
|  |  | ||||||
|  |         return ret | ||||||
|  |  | ||||||
|  |     def __init__(self): | ||||||
|  |         self.SONIC_PORT_NAME_PREFIX = "Ethernet" | ||||||
|  |         self.PORT_START = 0 | ||||||
|  |         self.PORT_END = 51 | ||||||
|  |         self.SFP_BASE = 0 | ||||||
|  |         self.PORTS_IN_BLOCK = 52 | ||||||
|  |         self.logical = [] | ||||||
|  |         self.physical_to_logical = {} | ||||||
|  |         self.logical_to_physical = {} | ||||||
|  |         self.logical_to_asic = {} | ||||||
|  |         self.data = {'valid':0, 'last':0} | ||||||
|  |  | ||||||
|  |         self.eeprom_mapping = {} | ||||||
|  |         self.f_sfp_present = "/sys/class/sfp/sfp{}/sfp_presence" | ||||||
|  |         self.f_sfp_enable = "/sys/class/sfp/sfp{}/sfp_enable" | ||||||
|  |         for x in range(self.port_start, self.sfp_base): | ||||||
|  |             self.eeprom_mapping[x] = None | ||||||
|  |         for x in range(self.sfp_base, self.port_end + 1): | ||||||
|  |             self.eeprom_mapping[x] = "/sys/class/sfp/sfp{}/sfp_eeprom".format(x - self.sfp_base + 1) | ||||||
|  |         self.presence = {} | ||||||
|  |         for x in range(self.sfp_base, self.port_end + 1): | ||||||
|  |             self.presence[x] = False; | ||||||
|  |  | ||||||
|  |         SfpUtilBase.__init__(self) | ||||||
|  |  | ||||||
|  |         for x in range(self.sfp_base, self.port_end + 1): | ||||||
|  |             self.logical.append('Ethernet' + str(x)) | ||||||
|  |  | ||||||
|  |     def get_presence(self, port_num): | ||||||
|  |         # Check for invalid port_num | ||||||
|  |         if port_num < self.port_start or port_num > self.port_end: | ||||||
|  |             return False | ||||||
|  |         if port_num < self.sfp_base: | ||||||
|  |             return False | ||||||
|  |         try: | ||||||
|  |             with open(self.f_sfp_present.format(port_num - self.sfp_base + 1), 'r') as sfp_file: | ||||||
|  |                 return 1 == int(sfp_file.read()) | ||||||
|  |         except IOError as e: | ||||||
|  |             DBG_PRINT(str(e)) | ||||||
|  |  | ||||||
|  |         return False | ||||||
|  |  | ||||||
|  |     def get_low_power_mode(self, port_num): | ||||||
|  |         # Check for invalid port_num | ||||||
|  |         if port_num < self.port_start or port_num > self.port_end: | ||||||
|  |             return False | ||||||
|  |  | ||||||
|  |         return False | ||||||
|  |  | ||||||
|  |     def set_low_power_mode(self, port_num, lpmode): | ||||||
|  |         # Check for invalid port_num | ||||||
|  |         if port_num < self.port_start or port_num > self.port_end: | ||||||
|  |             return False | ||||||
|  |  | ||||||
|  |         return False | ||||||
|  |  | ||||||
|  |     def reset(self, port_num): | ||||||
|  |         # Check for invalid port_num | ||||||
|  |         if port_num < self.port_start or port_num > self.port_end: | ||||||
|  |             return False | ||||||
|  |  | ||||||
|  |         return False | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     def read_porttab_mappings(self, porttabfile, asic_inst = 0): | ||||||
|  |         for x in range(self.sfp_base, self.port_end + 1): | ||||||
|  |             self.logical_to_physical['Ethernet' + str(x)] = [x] | ||||||
|  |             self.logical_to_asic['Ethernet' + str(x)] = 0 | ||||||
|  |             self.physical_to_logical[x] = ['Ethernet' + str(x)] | ||||||
|  |  | ||||||
|  |     def get_transceiver_change_event(self, timeout=2000): | ||||||
|  |         now = time.time() | ||||||
|  |         port_dict = {} | ||||||
|  |  | ||||||
|  |         if timeout < 1000: | ||||||
|  |             timeout = 1000 | ||||||
|  |         timeout = (timeout) / float(1000) # Convert to secs | ||||||
|  |  | ||||||
|  |         if now < (self.data['last'] + timeout) and self.data['valid']: | ||||||
|  |             return True, {} | ||||||
|  |  | ||||||
|  |         for x in range(self.sfp_base, self.port_end + 1): | ||||||
|  |             presence = self.get_presence(x) | ||||||
|  |             if presence != self.presence[x]: | ||||||
|  |                 self.presence[x] = presence | ||||||
|  |                 # index in port_config.ini | ||||||
|  |                 if presence: | ||||||
|  |                     port_dict[x] = SFP_STATUS_INSERTED | ||||||
|  |                 else: | ||||||
|  |                     port_dict[x] = SFP_STATUS_REMOVED | ||||||
|  |  | ||||||
|  |         if bool(port_dict): | ||||||
|  |             self.data['last'] = now | ||||||
|  |             self.data['valid'] = 1 | ||||||
|  |             return True, port_dict | ||||||
|  |         else: | ||||||
|  |             time.sleep(0.5) | ||||||
|  |             return True, {} | ||||||
| @@ -0,0 +1,3 @@ | |||||||
|  | { | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -1,53 +1,53 @@ | |||||||
| # name lanes  alias             speed | # name          lanes          alias             index     speed    fec | ||||||
| Ethernet1         1              eth-0-1         1000 | Ethernet0       1              eth-0-1           0         1000     none | ||||||
| Ethernet2         0              eth-0-2         1000 | Ethernet1       0              eth-0-2           1         1000     none | ||||||
| Ethernet3         3              eth-0-3         1000 | Ethernet2       3              eth-0-3           2         1000     none | ||||||
| Ethernet4         2              eth-0-4         1000 | Ethernet3       2              eth-0-4           3         1000     none | ||||||
| Ethernet5         5              eth-0-5         1000 | Ethernet4       5              eth-0-5           4         1000     none | ||||||
| Ethernet6         4              eth-0-6         1000 | Ethernet5       4              eth-0-6           5         1000     none | ||||||
| Ethernet7         7              eth-0-7         1000 | Ethernet6       7              eth-0-7           6         1000     none | ||||||
| Ethernet8         6              eth-0-8         1000 | Ethernet7       6              eth-0-8           7         1000     none | ||||||
| Ethernet9         17             eth-0-9         1000 | Ethernet8       17             eth-0-9           8         1000     none | ||||||
| Ethernet10        16             eth-0-10        1000   | Ethernet9       16             eth-0-10          9         1000     none | ||||||
| Ethernet11        19             eth-0-11        1000 | Ethernet10      19             eth-0-11          10        1000     none | ||||||
| Ethernet12        18             eth-0-12        1000 | Ethernet11      18             eth-0-12          11        1000     none | ||||||
| Ethernet13        21             eth-0-13        1000 | Ethernet12      21             eth-0-13          12        1000     none | ||||||
| Ethernet14        20             eth-0-14        1000 | Ethernet13      20             eth-0-14          13        1000     none | ||||||
| Ethernet15        23             eth-0-15        1000 | Ethernet14      23             eth-0-15          14        1000     none | ||||||
| Ethernet16        22             eth-0-16        1000 | Ethernet15      22             eth-0-16          15        1000     none | ||||||
| Ethernet17        9              eth-0-17        1000 | Ethernet16      9              eth-0-17          16        1000     none | ||||||
| Ethernet18        8              eth-0-18        1000 | Ethernet17      8              eth-0-18          17        1000     none | ||||||
| Ethernet19        11             eth-0-19        1000 | Ethernet18      11             eth-0-19          18        1000     none | ||||||
| Ethernet20        10             eth-0-20        1000 | Ethernet19      10             eth-0-20          19        1000     none | ||||||
| Ethernet21        33             eth-0-21        1000 | Ethernet20      33             eth-0-21          20        1000     none | ||||||
| Ethernet22        32             eth-0-22        1000 | Ethernet21      32             eth-0-22          21        1000     none | ||||||
| Ethernet23        35             eth-0-23        1000 | Ethernet22      35             eth-0-23          22        1000     none | ||||||
| Ethernet24        34             eth-0-24        1000 | Ethernet23      34             eth-0-24          23        1000     none | ||||||
| Ethernet25        37             eth-0-25        1000 | Ethernet24      37             eth-0-25          24        1000     none | ||||||
| Ethernet26        36             eth-0-26        1000 | Ethernet25      36             eth-0-26          25        1000     none | ||||||
| Ethernet27        39             eth-0-27        1000 | Ethernet26      39             eth-0-27          26        1000     none | ||||||
| Ethernet28        38             eth-0-28        1000 | Ethernet27      38             eth-0-28          27        1000     none | ||||||
| Ethernet29        41             eth-0-29        1000 | Ethernet28      41             eth-0-29          28        1000     none | ||||||
| Ethernet30        40             eth-0-30        1000 | Ethernet29      40             eth-0-30          29        1000     none | ||||||
| Ethernet31        43             eth-0-31        1000 | Ethernet30      43             eth-0-31          30        1000     none | ||||||
| Ethernet32        42             eth-0-32        1000 | Ethernet31      42             eth-0-32          31        1000     none | ||||||
| Ethernet33        25             eth-0-33        1000 | Ethernet32      25             eth-0-33          32        1000     none | ||||||
| Ethernet34        24             eth-0-34        1000 | Ethernet33      24             eth-0-34          33        1000     none | ||||||
| Ethernet35        27             eth-0-35        1000 | Ethernet34      27             eth-0-35          34        1000     none | ||||||
| Ethernet36        26             eth-0-36        1000 | Ethernet35      26             eth-0-36          35        1000     none | ||||||
| Ethernet37        49             eth-0-37        1000 | Ethernet36      49             eth-0-37          36        1000     none | ||||||
| Ethernet38        48             eth-0-38        1000 | Ethernet37      48             eth-0-38          37        1000     none | ||||||
| Ethernet39        51             eth-0-39        1000 | Ethernet38      51             eth-0-39          38        1000     none | ||||||
| Ethernet40        50             eth-0-40        1000 | Ethernet39      50             eth-0-40          39        1000     none | ||||||
| Ethernet41        53             eth-0-41        1000 | Ethernet40      53             eth-0-41          40        1000     none | ||||||
| Ethernet42        52             eth-0-42        1000 | Ethernet41      52             eth-0-42          41        1000     none | ||||||
| Ethernet43        55             eth-0-43        1000 | Ethernet42      55             eth-0-43          42        1000     none | ||||||
| Ethernet44        54             eth-0-44        1000 | Ethernet43      54             eth-0-44          43        1000     none | ||||||
| Ethernet45        57             eth-0-45        1000 | Ethernet44      57             eth-0-45          44        1000     none | ||||||
| Ethernet46        56             eth-0-46        1000 | Ethernet45      56             eth-0-46          45        1000     none | ||||||
| Ethernet47        59             eth-0-47        1000 | Ethernet46      59             eth-0-47          46        1000     none | ||||||
| Ethernet48        58             eth-0-48        1000 | Ethernet47      58             eth-0-48          47        1000     none | ||||||
| Ethernet49        13             eth-0-49        10000 | Ethernet48      13             eth-0-49          48        10000    none | ||||||
| Ethernet50        12             eth-0-50        10000 | Ethernet49      12             eth-0-50          49        10000    none | ||||||
| Ethernet51        15             eth-0-51        10000 | Ethernet50      15             eth-0-51          50        10000    none | ||||||
| Ethernet52        14             eth-0-52        10000 | Ethernet51      14             eth-0-52          51        10000    none | ||||||
|   | |||||||
| @@ -1 +1,12 @@ | |||||||
| # Configuration file generated by pwmconfig, changes will be lost | # Configuration file generated by pwmconfig, changes will be lost | ||||||
|  | INTERVAL=10 | ||||||
|  | DEVPATH=hwmon1=devices/platform/soc/soc:fan-ctc5236 | ||||||
|  | DEVNAME=hwmon1=ctc5236fan | ||||||
|  | FCTEMPS=hwmon1/pwm1=hwmon1/temp1_input hwmon1/pwm2=hwmon1/temp1_input hwmon1/pwm3=hwmon1/temp1_input | ||||||
|  | FCFANS=hwmon1/pwm1=hwmon1/fan1_input hwmon1/pwm2=hwmon1/fan2_input hwmon1/pwm3=hwmon1/fan3_input | ||||||
|  | MINTEMP=hwmon1/pwm1=30 hwmon1/pwm2=30 hwmon1/pwm3=30 | ||||||
|  | MAXTEMP=hwmon1/pwm1=90 hwmon1/pwm2=90 hwmon1/pwm3=90 | ||||||
|  | MINSTART=hwmon1/pwm1=12 hwmon1/pwm2=12 hwmon1/pwm3=12 | ||||||
|  | MINSTOP=hwmon1/pwm1=6 hwmon1/pwm2=6 hwmon1/pwm3=6 | ||||||
|  | MINPWM=hwmon1/pwm1=6 hwmon1/pwm2=6 hwmon1/pwm3=6 | ||||||
|  | MAXPWM=hwmon1/pwm1=18 hwmon1/pwm2=18 hwmon1/pwm3=18 | ||||||
|   | |||||||
| @@ -0,0 +1,8 @@ | |||||||
|  | { | ||||||
|  |         "chassis": { | ||||||
|  |                 "E530-48t4x-p": { | ||||||
|  |                         "component": { | ||||||
|  |                         } | ||||||
|  |                 } | ||||||
|  |         } | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								device/centec/arm64-centec_e530_48t4x_p-r0/platform_reboot
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										11
									
								
								device/centec/arm64-centec_e530_48t4x_p-r0/platform_reboot
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | #!/usr/bin/python | ||||||
|  | import os | ||||||
|  |  | ||||||
|  | def main(): | ||||||
|  |     # reboot the system | ||||||
|  |     os.system('echo 502 > /sys/class/gpio/export') | ||||||
|  |     os.system('echo out > /sys/class/gpio/gpio502/direction') | ||||||
|  |     os.system('echo 1 > /sys/class/gpio/gpio502/value') | ||||||
|  |  | ||||||
|  | if __name__ == "__main__": | ||||||
|  |     main() | ||||||
| @@ -1,3 +1,5 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
| ############################################################################# | ############################################################################# | ||||||
| # Centec E550-24X8Y2C | # Centec E550-24X8Y2C | ||||||
| # | # | ||||||
| @@ -10,7 +12,7 @@ | |||||||
| try: | try: | ||||||
|     from sonic_eeprom import eeprom_tlvinfo |     from sonic_eeprom import eeprom_tlvinfo | ||||||
| except ImportError as e: | except ImportError as e: | ||||||
|     raise ImportError(str(e) + "- required module not found") |     raise ImportError (str(e) + "- required module not found") | ||||||
|  |  | ||||||
|  |  | ||||||
| class board(eeprom_tlvinfo.TlvInfoDecoder): | class board(eeprom_tlvinfo.TlvInfoDecoder): | ||||||
|   | |||||||
| @@ -1,3 +1,5 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  | # | ||||||
| # led_control.py | # led_control.py | ||||||
| # | # | ||||||
| # Platform-specific LED control functionality for SONiC | # Platform-specific LED control functionality for SONiC | ||||||
| @@ -21,6 +23,7 @@ def DBG_PRINT(str): | |||||||
| class LedControl(LedControlBase): | class LedControl(LedControlBase): | ||||||
|     """Platform specific LED control class""" |     """Platform specific LED control class""" | ||||||
|  |  | ||||||
|  |  | ||||||
|     # Helper method to map SONiC port name to index |     # Helper method to map SONiC port name to index | ||||||
|     def _port_name_to_index(self, port_name): |     def _port_name_to_index(self, port_name): | ||||||
|         # Strip "Ethernet" off port name |         # Strip "Ethernet" off port name | ||||||
| @@ -28,7 +31,7 @@ class LedControl(LedControlBase): | |||||||
|             return -1 |             return -1 | ||||||
|  |  | ||||||
|         port_idx = int(port_name[len(self.SONIC_PORT_NAME_PREFIX):]) |         port_idx = int(port_name[len(self.SONIC_PORT_NAME_PREFIX):]) | ||||||
|         return port_idx |         return port_idx + 1 | ||||||
|  |  | ||||||
|     def _port_state_to_mode(self, port_idx, state): |     def _port_state_to_mode(self, port_idx, state): | ||||||
|         if state == "up": |         if state == "up": | ||||||
| @@ -70,8 +73,8 @@ class LedControl(LedControlBase): | |||||||
|  |  | ||||||
|         DBG_PRINT("init led done") |         DBG_PRINT("init led done") | ||||||
|  |  | ||||||
|     # Concrete implementation of port_link_state_change() method |  | ||||||
|  |  | ||||||
|  |     # Concrete implementation of port_link_state_change() method | ||||||
|     def port_link_state_change(self, portname, state): |     def port_link_state_change(self, portname, state): | ||||||
|         port_idx = self._port_name_to_index(portname) |         port_idx = self._port_name_to_index(portname) | ||||||
|         ledMode = self._port_state_to_mode(port_idx, state) |         ledMode = self._port_state_to_mode(port_idx, state) | ||||||
| @@ -84,8 +87,8 @@ class LedControl(LedControlBase): | |||||||
|         self._port_led_mode_update(port_idx, ledMode) |         self._port_led_mode_update(port_idx, ledMode) | ||||||
|         DBG_PRINT("update {} led mode from {} to {}".format(portname, saveMode, ledMode)) |         DBG_PRINT("update {} led mode from {} to {}".format(portname, saveMode, ledMode)) | ||||||
|  |  | ||||||
|     # Constructor |  | ||||||
|  |  | ||||||
|  |     # Constructor | ||||||
|     def __init__(self): |     def __init__(self): | ||||||
|         self.SONIC_PORT_NAME_PREFIX = "Ethernet" |         self.SONIC_PORT_NAME_PREFIX = "Ethernet" | ||||||
|         self.LED_MODE_UP = [2, 11] |         self.LED_MODE_UP = [2, 11] | ||||||
|   | |||||||
| @@ -1,3 +1,5 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
| ############################################################################# | ############################################################################# | ||||||
| # Centec | # Centec | ||||||
| # | # | ||||||
| @@ -9,8 +11,7 @@ | |||||||
| try: | try: | ||||||
|     from sonic_psu.psu_base import PsuBase |     from sonic_psu.psu_base import PsuBase | ||||||
| except ImportError as e: | except ImportError as e: | ||||||
|     raise ImportError(str(e) + "- required module not found") |     raise ImportError (str(e) + "- required module not found") | ||||||
|  |  | ||||||
|  |  | ||||||
| class PsuUtil(PsuBase): | class PsuUtil(PsuBase): | ||||||
|     """Platform-specific PSUutil class""" |     """Platform-specific PSUutil class""" | ||||||
|   | |||||||
| @@ -1,3 +1,5 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
| # sfputil.py | # sfputil.py | ||||||
| # | # | ||||||
| # Platform-specific SFP transceiver interface for SONiC | # Platform-specific SFP transceiver interface for SONiC | ||||||
| @@ -15,6 +17,8 @@ except ImportError as e: | |||||||
| def DBG_PRINT(str): | def DBG_PRINT(str): | ||||||
|     print(str + "\n") |     print(str + "\n") | ||||||
|  |  | ||||||
|  | SFP_STATUS_INSERTED = '1' | ||||||
|  | SFP_STATUS_REMOVED = '0' | ||||||
|  |  | ||||||
| class SfpUtil(SfpUtilBase): | class SfpUtil(SfpUtilBase): | ||||||
|     """Platform-specific SfpUtil class""" |     """Platform-specific SfpUtil class""" | ||||||
| @@ -42,17 +46,9 @@ class SfpUtil(SfpUtilBase): | |||||||
|     def is_logical_port(self, port_name): |     def is_logical_port(self, port_name): | ||||||
|         return True |         return True | ||||||
|  |  | ||||||
|     def get_logical_to_physical(self, port_name): |  | ||||||
|         if not port_name.startswith(self.SONIC_PORT_NAME_PREFIX): |  | ||||||
|             return None |  | ||||||
|  |  | ||||||
|         port_idx = int(port_name[len(self.SONIC_PORT_NAME_PREFIX):]) |  | ||||||
|  |  | ||||||
|         return [port_idx] |  | ||||||
|  |  | ||||||
|     def get_eeprom_data(self, port): |     def get_eeprom_data(self, port): | ||||||
|         ret = None |         ret = None | ||||||
|         port_num = self.get_logical_to_physical(port)[0] |         port_num = self.get_logical_to_physical(port)[0] + 1 | ||||||
|         if port_num < self.port_start or port_num > self.port_end: |         if port_num < self.port_start or port_num > self.port_end: | ||||||
|             return ret |             return ret | ||||||
|         if port_num < self.sfp_base: |         if port_num < self.sfp_base: | ||||||
| @@ -65,16 +61,17 @@ class SfpUtil(SfpUtilBase): | |||||||
|  |  | ||||||
|         return ret |         return ret | ||||||
|  |  | ||||||
|     # todo |  | ||||||
|     # def _get_port_eeprom_path(self, port_num, devid): |  | ||||||
|     #    pass |  | ||||||
|  |  | ||||||
|     def __init__(self): |     def __init__(self): | ||||||
|         self.SONIC_PORT_NAME_PREFIX = "Ethernet" |         self.SONIC_PORT_NAME_PREFIX = "Ethernet" | ||||||
|         self.PORT_START = 1 |         self.PORT_START = 0 | ||||||
|         self.PORT_END = 52 |         self.PORT_END = 51 | ||||||
|         self.SFP_BASE = 49 |         self.SFP_BASE = 48 | ||||||
|         self.PORTS_IN_BLOCK = 52 |         self.PORTS_IN_BLOCK = 52 | ||||||
|  |         self.logical = [] | ||||||
|  |         self.physical_to_logical = {} | ||||||
|  |         self.logical_to_physical = {} | ||||||
|  |         self.logical_to_asic = {} | ||||||
|  |         self.data = {'valid':0, 'last':0} | ||||||
|  |  | ||||||
|         self.eeprom_mapping = {} |         self.eeprom_mapping = {} | ||||||
|         self.f_sfp_present = "/sys/class/sfp/sfp{}/sfp_presence" |         self.f_sfp_present = "/sys/class/sfp/sfp{}/sfp_presence" | ||||||
| @@ -82,14 +79,16 @@ class SfpUtil(SfpUtilBase): | |||||||
|         for x in range(self.port_start, self.sfp_base): |         for x in range(self.port_start, self.sfp_base): | ||||||
|             self.eeprom_mapping[x] = None |             self.eeprom_mapping[x] = None | ||||||
|         for x in range(self.sfp_base, self.port_end + 1): |         for x in range(self.sfp_base, self.port_end + 1): | ||||||
|             self.eeprom_mapping[x] = "/sys/class/sfp/sfp{}/sfp_eeprom".format( |             self.eeprom_mapping[x] = "/sys/class/sfp/sfp{}/sfp_eeprom".format(x - self.sfp_base + 1) | ||||||
|                 x - self.sfp_base + 1) |  | ||||||
|         self.presence = {} |         self.presence = {} | ||||||
|         for x in range(self.sfp_base, self.port_end + 1): |         for x in range(self.sfp_base, self.port_end + 1): | ||||||
|             self.presence[x] = False |             self.presence[x] = False; | ||||||
|  |  | ||||||
|         SfpUtilBase.__init__(self) |         SfpUtilBase.__init__(self) | ||||||
|  |  | ||||||
|  |         for x in range(self.sfp_base, self.port_end + 1): | ||||||
|  |             self.logical.append('Ethernet' + str(x)) | ||||||
|  |  | ||||||
|     def get_presence(self, port_num): |     def get_presence(self, port_num): | ||||||
|         # Check for invalid port_num |         # Check for invalid port_num | ||||||
|         if port_num < self.port_start or port_num > self.port_end: |         if port_num < self.port_start or port_num > self.port_end: | ||||||
| @@ -125,13 +124,38 @@ class SfpUtil(SfpUtilBase): | |||||||
|  |  | ||||||
|         return False |         return False | ||||||
|  |  | ||||||
|     def get_transceiver_change_event(self, timeout=0): |  | ||||||
|  |     def read_porttab_mappings(self, porttabfile, asic_inst = 0): | ||||||
|  |         for x in range(self.sfp_base, self.port_end + 1): | ||||||
|  |             self.logical_to_physical['Ethernet' + str(x)] = [x] | ||||||
|  |             self.logical_to_asic['Ethernet' + str(x)] = 0 | ||||||
|  |             self.physical_to_logical[x] = ['Ethernet' + str(x)] | ||||||
|  |  | ||||||
|  |     def get_transceiver_change_event(self, timeout=2000): | ||||||
|  |         now = time.time() | ||||||
|         port_dict = {} |         port_dict = {} | ||||||
|         while True: |  | ||||||
|             for x in range(self.sfp_base, self.port_end + 1): |         if timeout < 1000: | ||||||
|                 presence = self.get_presence(x) |             timeout = 1000 | ||||||
|                 if presence != self.presence[x]: |         timeout = (timeout) / float(1000) # Convert to secs | ||||||
|                     self.presence[x] = presence |  | ||||||
|                     port_dict[x] = presence |         if now < (self.data['last'] + timeout) and self.data['valid']: | ||||||
|                     return True, port_dict |             return True, {} | ||||||
|  |  | ||||||
|  |         for x in range(self.sfp_base, self.port_end + 1): | ||||||
|  |             presence = self.get_presence(x) | ||||||
|  |             if presence != self.presence[x]: | ||||||
|  |                 self.presence[x] = presence | ||||||
|  |                 # index in port_config.ini | ||||||
|  |                 if presence: | ||||||
|  |                     port_dict[x] = SFP_STATUS_INSERTED | ||||||
|  |                 else: | ||||||
|  |                     port_dict[x] = SFP_STATUS_REMOVED | ||||||
|  |  | ||||||
|  |         if bool(port_dict): | ||||||
|  |             self.data['last'] = now | ||||||
|  |             self.data['valid'] = 1 | ||||||
|  |             return True, port_dict | ||||||
|  |         else: | ||||||
|             time.sleep(0.5) |             time.sleep(0.5) | ||||||
|  |             return True, {} | ||||||
|   | |||||||
| @@ -0,0 +1,3 @@ | |||||||
|  | { | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -82,7 +82,7 @@ class SfpUtil(SfpUtilBase): | |||||||
|         try: |         try: | ||||||
|             reg_file = open("/sys/devices/platform/dell-s6000-cpld.0/qsfp_lpmode") |             reg_file = open("/sys/devices/platform/dell-s6000-cpld.0/qsfp_lpmode") | ||||||
|         except IOError as e: |         except IOError as e: | ||||||
|             print "Error: unable to open file: %s" % str(e) |             print("Error: unable to open file: %s" % str(e)) | ||||||
|  |  | ||||||
|         content = reg_file.readline().rstrip() |         content = reg_file.readline().rstrip() | ||||||
|  |  | ||||||
|   | |||||||
| @@ -8,6 +8,8 @@ $(SONIC_ONE_IMAGE)_INSTALLS += $(SYSTEMD_SONIC_GENERATOR) | |||||||
| $(SONIC_ONE_IMAGE)_INSTALLS += $(TSINGMA_BSP_MODULE) | $(SONIC_ONE_IMAGE)_INSTALLS += $(TSINGMA_BSP_MODULE) | ||||||
| $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(CENTEC_E530_48T4X_P_PLATFORM_MODULE) | $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(CENTEC_E530_48T4X_P_PLATFORM_MODULE) | ||||||
| $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(CENTEC_E530_24X2C_PLATFORM_MODULE) | $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(CENTEC_E530_24X2C_PLATFORM_MODULE) | ||||||
|  | $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(CENTEC_E530_48S4X_PLATFORM_MODULE) | ||||||
|  | $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(CENTEC_E530_24X2Q_PLATFORM_MODULE) | ||||||
|  |  | ||||||
| ifeq ($(INSTALL_DEBUG_TOOLS),y) | ifeq ($(INSTALL_DEBUG_TOOLS),y) | ||||||
| $(SONIC_ONE_IMAGE)_DOCKERS += $(SONIC_INSTALL_DOCKER_DBG_IMAGES) | $(SONIC_ONE_IMAGE)_DOCKERS += $(SONIC_INSTALL_DOCKER_DBG_IMAGES) | ||||||
|   | |||||||
| @@ -1,8 +1,10 @@ | |||||||
| # Centec E530-48T4X-P Platform modules | # Centec E530-48T4X-P Platform modules | ||||||
|  |  | ||||||
|  |  | ||||||
| CENTEC_E530_48T4X_P_PLATFORM_MODULE_VERSION =1.1 | CENTEC_E530_48T4X_P_PLATFORM_MODULE_VERSION =1.3 | ||||||
| CENTEC_E530_24X2C_PLATFORM_MODULE_VERSION =1.1 | CENTEC_E530_24X2C_PLATFORM_MODULE_VERSION =1.3 | ||||||
|  | CENTEC_E530_48S4X_PLATFORM_MODULE_VERSION =1.3 | ||||||
|  | CENTEC_E530_24X2Q_PLATFORM_MODULE_VERSION =1.3 | ||||||
|  |  | ||||||
| export CENTEC_E530_48T4X_P_PLATFORM_MODULE_VERSION | export CENTEC_E530_48T4X_P_PLATFORM_MODULE_VERSION | ||||||
|  |  | ||||||
| @@ -16,3 +18,11 @@ SONIC_DPKG_DEBS += $(CENTEC_E530_48T4X_P_PLATFORM_MODULE) | |||||||
| CENTEC_E530_24X2C_PLATFORM_MODULE = platform-modules-e530-24x2c_$(CENTEC_E530_24X2C_PLATFORM_MODULE_VERSION)_arm64.deb | CENTEC_E530_24X2C_PLATFORM_MODULE = platform-modules-e530-24x2c_$(CENTEC_E530_24X2C_PLATFORM_MODULE_VERSION)_arm64.deb | ||||||
| $(CENTEC_E530_24X2C_PLATFORM_MODULE)_PLATFORM = arm64-centec_e530_24x2c-r0 | $(CENTEC_E530_24X2C_PLATFORM_MODULE)_PLATFORM = arm64-centec_e530_24x2c-r0 | ||||||
| $(eval $(call add_extra_package,$(CENTEC_E530_48T4X_P_PLATFORM_MODULE),$(CENTEC_E530_24X2C_PLATFORM_MODULE))) | $(eval $(call add_extra_package,$(CENTEC_E530_48T4X_P_PLATFORM_MODULE),$(CENTEC_E530_24X2C_PLATFORM_MODULE))) | ||||||
|  |  | ||||||
|  | CENTEC_E530_48S4X_PLATFORM_MODULE = platform-modules-e530-48s4x_$(CENTEC_E530_48S4X_PLATFORM_MODULE_VERSION)_arm64.deb | ||||||
|  | $(CENTEC_E530_48S4X_PLATFORM_MODULE)_PLATFORM = arm64-centec_e530_48s4x-r0 | ||||||
|  | $(eval $(call add_extra_package,$(CENTEC_E530_48T4X_P_PLATFORM_MODULE),$(CENTEC_E530_48S4X_PLATFORM_MODULE))) | ||||||
|  |  | ||||||
|  | CENTEC_E530_24X2Q_PLATFORM_MODULE = platform-modules-e530-24x2q_$(CENTEC_E530_24X2Q_PLATFORM_MODULE_VERSION)_arm64.deb | ||||||
|  | $(CENTEC_E530_24X2Q_PLATFORM_MODULE)_PLATFORM = arm64-centec_e530_24x2q-r0 | ||||||
|  | $(eval $(call add_extra_package,$(CENTEC_E530_48T4X_P_PLATFORM_MODULE),$(CENTEC_E530_24X2Q_PLATFORM_MODULE))) | ||||||
|   | |||||||
| @@ -4,43 +4,45 @@ | |||||||
|  |  | ||||||
| echo "Preparing for installation ... " | echo "Preparing for installation ... " | ||||||
|  |  | ||||||
| demo_mnt=/mnt |  | ||||||
|  |  | ||||||
| hw_load() { |  | ||||||
|     echo "ext4load mmc 0:2 \$loadaddr onie_uimage" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| create_partition() { | create_partition() { | ||||||
|     echo y | mkfs.ext4 -L CTC-SYSTEM /dev/mmcblk0p1 |     echo y | mkfs.ext4 -L CTC-SYSTEM /dev/mmcblk0p1 | ||||||
| } | } | ||||||
|  |  | ||||||
| mount_partition() { | mount_partition() { | ||||||
|     echo "mount flash" |     echo "mount flash partition" | ||||||
|  |     demo_mnt=/mnt | ||||||
|     mount -t ext4 /dev/mmcblk0p1 $demo_mnt |     mount -t ext4 /dev/mmcblk0p1 $demo_mnt | ||||||
| } | } | ||||||
|  |  | ||||||
| bootloader_menu_config() { | bootloader_menu_config() { | ||||||
|     mkdir -p $demo_mnt/boot |     if [ "$install_env" = "onie" ]; then | ||||||
|     mount -t ext4 /dev/mmcblk0p2 $demo_mnt/boot |         fw_setenv -f nos_bootcmd "test -n \$boot_once && setenv do_boot_once \$boot_once && setenv boot_once && saveenv && run do_boot_once; run boot_next" | ||||||
|      |  | ||||||
|     rm $demo_mnt/boot/centec-e530.itb -rf |  | ||||||
|     cp $demo_mnt/$image_dir/boot/sonic_arm64.fit $demo_mnt/boot/centec-e530.itb |  | ||||||
|     cd $demo_mnt/boot |  | ||||||
|     rm onie_uimage -rf |  | ||||||
|     ln -s centec-e530.itb onie_uimage |  | ||||||
|     cd - |  | ||||||
|     sync |  | ||||||
|     umount -l $demo_mnt/boot |  | ||||||
|  |  | ||||||
|     hw_load_str="$(hw_load)" |         fw_setenv -f sonic_image_1 "ext4load mmc 0:1 \$loadaddr \$sonic_dir_1/boot/sonic_arm64.fit && setenv bootargs quiet console=\$consoledev,\$baudrate root=/dev/mmcblk0p1 rw rootwait rootfstype=ext4 loopfstype=squashfs loop=\$sonic_dir_1/fs.squashfs systemd.unified_cgroup_hierarchy=0 && bootm \$loadaddr" | ||||||
|  |         fw_setenv -f sonic_image_2 "NONE" | ||||||
|  |         fw_setenv -f sonic_dir_1 $image_dir | ||||||
|  |         fw_setenv -f sonic_dir_2 "NONE" | ||||||
|  |         fw_setenv -f sonic_version_1 `echo $image_dir | sed "s/^image-/SONiC-OS-/g"` | ||||||
|  |         fw_setenv -f sonic_version_2 "NONE" | ||||||
|  |  | ||||||
|     (cat <<EOF |         fw_setenv -f boot_next "run sonic_image_1" | ||||||
| hw_load $hw_load_str |     else | ||||||
| copy_img echo "Loading Demo $platform image..." && run hw_load |         running_sonic_revision=`cat /etc/sonic/sonic_version.yml | grep build_version | awk -F \' '{print $2}'` | ||||||
| nos_bootcmd run copy_img && setenv bootargs quiet console=\$consoledev,\$baudrate root=/dev/mmcblk0p1 rw rootwait rootfstype=ext4 loopfstype=squashfs loop=$image_dir/fs.squashfs systemd.unified_cgroup_hierarchy=0 && bootm \$loadaddr |         SONIC_IMAGE_MAX=2 | ||||||
| EOF |         idx=0 | ||||||
|     ) > /tmp/env.txt |         for i in $(seq 1 $SONIC_IMAGE_MAX); do | ||||||
|  |             if [ "`fw_printenv sonic_version_$i 2>/dev/null | awk -F = '{print $2}'`" != "SONiC-OS-$running_sonic_revision" ]; then | ||||||
|  |                 idx=$i | ||||||
|  |                 break | ||||||
|  |             fi | ||||||
|  |         done | ||||||
|  |  | ||||||
|     fw_setenv -f -s /tmp/env.txt |         fw_setenv nos_bootcmd "test -n \$boot_once && setenv do_boot_once \$boot_once && setenv boot_once && saveenv && run do_boot_once; run boot_next" | ||||||
|     fw_setenv -f image_dir $image_dir |  | ||||||
|  |         fw_setenv sonic_image_$idx "ext4load mmc 0:1 \$loadaddr \$sonic_dir_$idx/boot/sonic_arm64.fit && setenv bootargs quiet console=\$consoledev,\$baudrate root=/dev/mmcblk0p1 rw rootwait rootfstype=ext4 loopfstype=squashfs loop=\$sonic_dir_$idx/fs.squashfs systemd.unified_cgroup_hierarchy=0 && bootm \$loadaddr" | ||||||
|  |         fw_setenv sonic_dir_$idx $image_dir | ||||||
|  |         fw_setenv sonic_version_$idx `echo $image_dir | sed "s/^image-/SONiC-OS-/g"` | ||||||
|  |  | ||||||
|  |         fw_setenv boot_next "run sonic_image_$idx" | ||||||
|  |     fi | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| # Centec SAI | # Centec SAI | ||||||
|  |  | ||||||
| export CENTEC_SAI_VERSION = 1.6.3-1 | export CENTEC_SAI_VERSION = 1.7.1-1 | ||||||
| export CENTEC_SAI = libsai_$(CENTEC_SAI_VERSION)_$(PLATFORM_ARCH).deb | export CENTEC_SAI = libsai_$(CENTEC_SAI_VERSION)_$(PLATFORM_ARCH).deb | ||||||
|  |  | ||||||
| $(CENTEC_SAI)_URL = https://github.com/CentecNetworks/sonic-binaries/raw/master/$(PLATFORM_ARCH)/sai/$(CENTEC_SAI) | $(CENTEC_SAI)_URL = https://github.com/CentecNetworks/sonic-binaries/raw/master/$(PLATFORM_ARCH)/sai/$(CENTEC_SAI) | ||||||
|   | |||||||
| @@ -5,11 +5,11 @@ from setuptools import setup | |||||||
| os.listdir | os.listdir | ||||||
|  |  | ||||||
| setup( | setup( | ||||||
|    name='24x2c', |    name='sonic_platform', | ||||||
|    version='1.1', |    version='1.0', | ||||||
|    description='Module to initialize centec e530-24x2c platforms', |    description='Module to initialize centec e530-24x2c platforms', | ||||||
|     |     | ||||||
|    packages=['24x2c'], |    packages=['sonic_platform'], | ||||||
|    package_dir={'24x2c': '24x2c/classes'}, |    package_dir={'sonic_platform': 'sonic_platform'}, | ||||||
| ) | ) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -0,0 +1,3 @@ | |||||||
|  | __all__ = ["platform", "chassis", "sfp", "eeprom", "psu", "thermal", "fan", "fan_drawer"] | ||||||
|  | from . import platform | ||||||
|  |  | ||||||
| @@ -0,0 +1,203 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  | # | ||||||
|  | # Name: chassis.py, version: 1.0 | ||||||
|  | # | ||||||
|  | # Description: Module contains the definitions of SONiC platform APIs  | ||||||
|  | # | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     import os | ||||||
|  |     import re | ||||||
|  |     import collections | ||||||
|  |     from sonic_platform_base.chassis_base import ChassisBase | ||||||
|  |     from sonic_platform.eeprom import Eeprom | ||||||
|  |     from .fan_drawer import FanDrawer | ||||||
|  |     from .thermal import Thermal | ||||||
|  |     from .sfp import Sfp | ||||||
|  |     from .psu import Psu | ||||||
|  |     from sonic_py_common import device_info | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError(str(e) + "- required module not found") | ||||||
|  |  | ||||||
|  | NUM_FAN_TRAY = 1 | ||||||
|  | NUM_THERMAL = 1 | ||||||
|  | NUM_PSU = 2 | ||||||
|  | USR_SHARE_SONIC_PATH = "/usr/share/sonic" | ||||||
|  | HOST_DEVICE_PATH = USR_SHARE_SONIC_PATH + "/device" | ||||||
|  | CONTAINER_PLATFORM_PATH = USR_SHARE_SONIC_PATH + "/platform" | ||||||
|  |  | ||||||
|  | class Chassis(ChassisBase): | ||||||
|  |  | ||||||
|  |     def __init__(self): | ||||||
|  |         ChassisBase.__init__(self) | ||||||
|  |  | ||||||
|  |         if os.path.isdir(CONTAINER_PLATFORM_PATH): | ||||||
|  |             platform_path = CONTAINER_PLATFORM_PATH | ||||||
|  |         else: | ||||||
|  |             platform = device_info.get_platform() | ||||||
|  |             if platform is None: | ||||||
|  |                 raise | ||||||
|  |             platform_path = os.path.join(HOST_DEVICE_PATH, platform) | ||||||
|  |  | ||||||
|  |         port_config_file = "/".join([platform_path, "E530-24x2c", "port_config.ini"]) | ||||||
|  |         try: | ||||||
|  |             f = open(port_config_file) | ||||||
|  |         except: | ||||||
|  |             raise | ||||||
|  |         for line in f: | ||||||
|  |             line.strip() | ||||||
|  |             if re.search('^#', line) is not None: | ||||||
|  |                 Port_cfg = collections.namedtuple('Port_cfg', line.split()[1:]) | ||||||
|  |                 break | ||||||
|  |         f.close() | ||||||
|  |         f = open(port_config_file) | ||||||
|  |         _port_cfgs = [Port_cfg(*tuple((line.strip().split()))) | ||||||
|  |                            for line in f if re.search('^#', line) is None] | ||||||
|  |         f.close() | ||||||
|  |  | ||||||
|  |         # Initialize EEPROM | ||||||
|  |         self._eeprom = Eeprom() | ||||||
|  |         # Initialize FAN | ||||||
|  |         for i in range(NUM_FAN_TRAY): | ||||||
|  |             fandrawer = FanDrawer(i) | ||||||
|  |             self._fan_drawer_list.append(fandrawer) | ||||||
|  |             self._fan_list.extend(fandrawer._fan_list) | ||||||
|  |         # Initialize THERMAL | ||||||
|  |         for index in range(0, NUM_THERMAL): | ||||||
|  |             thermal = Thermal(index) | ||||||
|  |             self._thermal_list.append(thermal) | ||||||
|  |         # Initialize SFP | ||||||
|  |         for port_cfg in _port_cfgs: | ||||||
|  |             sfp = Sfp(int(port_cfg.index)) | ||||||
|  |             self._sfp_list.append(sfp) | ||||||
|  |         # Initialize PSU | ||||||
|  |         for index in range(0, NUM_PSU): | ||||||
|  |             psu = Psu(index + 1) | ||||||
|  |             self._psu_list.append(psu) | ||||||
|  |             | ||||||
|  | ############################################## | ||||||
|  | # Device methods | ||||||
|  | ############################################## | ||||||
|  |  | ||||||
|  |     def get_name(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the name of the chassis | ||||||
|  |         Returns: | ||||||
|  |             string: The name of the chassis | ||||||
|  |         """ | ||||||
|  |         return self._eeprom.modelstr() | ||||||
|  |  | ||||||
|  |     def get_presence(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the presence of the chassis | ||||||
|  |         Returns: | ||||||
|  |             bool: True if chassis is present, False if not | ||||||
|  |         """ | ||||||
|  |         return True | ||||||
|  |  | ||||||
|  |     def get_model(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the model number (or part number) of the chassis | ||||||
|  |         Returns: | ||||||
|  |             string: Model/part number of chassis | ||||||
|  |         """ | ||||||
|  |         return self._eeprom.part_number_str() | ||||||
|  |  | ||||||
|  |     def get_serial(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the serial number of the chassis | ||||||
|  |         Returns: | ||||||
|  |             string: Serial number of chassis | ||||||
|  |         """ | ||||||
|  |         return self._eeprom.serial_number_str() | ||||||
|  |  | ||||||
|  |     def get_status(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the operational status of the chassis | ||||||
|  |         Returns: | ||||||
|  |             bool: A boolean value, True if chassis is operating properly | ||||||
|  |             False if not | ||||||
|  |         """ | ||||||
|  |         return True | ||||||
|  |  | ||||||
|  | ############################################## | ||||||
|  | # Chassis methods | ||||||
|  | ############################################## | ||||||
|  |  | ||||||
|  |     def get_base_mac(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the base MAC address for the chassis | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             A string containing the MAC address in the format | ||||||
|  |             'XX:XX:XX:XX:XX:XX' | ||||||
|  |         """ | ||||||
|  |         return self._eeprom.base_mac_addr() | ||||||
|  |  | ||||||
|  |     def get_serial_number(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the hardware serial number for the chassis | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             A string containing the hardware serial number for this chassis. | ||||||
|  |         """ | ||||||
|  |         return self._eeprom.serial_number_str() | ||||||
|  |  | ||||||
|  |     def get_system_eeprom_info(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the full content of system EEPROM information for the chassis | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             A dictionary where keys are the type code defined in | ||||||
|  |             OCP ONIE TlvInfo EEPROM format and values are their corresponding | ||||||
|  |             values. | ||||||
|  |             Ex. { '0x21':'AG9064', '0x22':'V1.0', '0x23':'AG9064-0109867821', | ||||||
|  |                   '0x24':'001c0f000fcd0a', '0x25':'02/03/2018 16:22:00', | ||||||
|  |                   '0x26':'01', '0x27':'REV01', '0x28':'AG9064-C2358-16G'} | ||||||
|  |         """ | ||||||
|  |         return self._eeprom.system_eeprom_info() | ||||||
|  |  | ||||||
|  |     def get_reboot_cause(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the cause of the previous reboot | ||||||
|  |         Returns: | ||||||
|  |             A tuple (string, string) where the first element is a string | ||||||
|  |             containing the cause of the previous reboot. This string must be | ||||||
|  |             one of the predefined strings in this class. If the first string | ||||||
|  |             is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used | ||||||
|  |             to pass a description of the reboot cause. | ||||||
|  |         """ | ||||||
|  |         return (None, None) | ||||||
|  |  | ||||||
|  |     def get_change_event(self, timeout=2000): | ||||||
|  |         """ | ||||||
|  |         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. | ||||||
|  |         """ | ||||||
|  |         ret, port_dict = self._sfp_list[0].get_transceiver_change_event(timeout) | ||||||
|  |         ret_dict = {"sfp": port_dict} | ||||||
|  |         return ret, ret_dict | ||||||
|  |  | ||||||
|  |     def get_num_psus(self): | ||||||
|  |         return len(self._psu_list) | ||||||
|  |  | ||||||
|  |     def get_psu(self, psu_index): | ||||||
|  |         return self._psu_list[psu_index] | ||||||
| @@ -0,0 +1,111 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  | # | ||||||
|  | # Name: eeprom.py, version: 1.0 | ||||||
|  | # | ||||||
|  | # Description: Module contains the definitions of SONiC platform APIs  | ||||||
|  | # | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_eeprom import eeprom_tlvinfo | ||||||
|  |     import binascii | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError(str(e) + "- required module not found") | ||||||
|  |  | ||||||
|  | class Eeprom(eeprom_tlvinfo.TlvInfoDecoder): | ||||||
|  |  | ||||||
|  |     def __init__(self): | ||||||
|  |         self.__eeprom_path = "/dev/mtd3" | ||||||
|  |         super(Eeprom, self).__init__(self.__eeprom_path, 0, '', True) | ||||||
|  |         self.__eeprom_tlv_dict = dict() | ||||||
|  |         try: | ||||||
|  |             self.open_eeprom() | ||||||
|  |             self.__eeprom_data = self.read_eeprom() | ||||||
|  |         except: | ||||||
|  |             self.__eeprom_data = "N/A" | ||||||
|  |             raise RuntimeError("Eeprom is not Programmed") | ||||||
|  |         else: | ||||||
|  |             eeprom = self.__eeprom_data | ||||||
|  |  | ||||||
|  |             if not self.is_valid_tlvinfo_header(eeprom): | ||||||
|  |                 return | ||||||
|  |  | ||||||
|  |             total_length = (eeprom[9] << 8) | eeprom[10] | ||||||
|  |             tlv_index = self._TLV_INFO_HDR_LEN | ||||||
|  |             tlv_end = self._TLV_INFO_HDR_LEN + total_length | ||||||
|  |  | ||||||
|  |             while (tlv_index + 2) < len(eeprom) and tlv_index < tlv_end: | ||||||
|  |                 if not self.is_valid_tlv(eeprom[tlv_index:]): | ||||||
|  |                     break | ||||||
|  |  | ||||||
|  |                 tlv = eeprom[tlv_index:tlv_index + 2 | ||||||
|  |                              + eeprom[tlv_index + 1]] | ||||||
|  |                 code = "0x%02X" % (tlv[0]) | ||||||
|  |  | ||||||
|  |                 if tlv[0] == self._TLV_CODE_VENDOR_EXT: | ||||||
|  |                     value = str((tlv[2] << 24) | (tlv[3] << 16) | | ||||||
|  |                                 (tlv[4] << 8) | tlv[5]) | ||||||
|  |                     value += str(tlv[6:6 + tlv[1]]) | ||||||
|  |                 else: | ||||||
|  |                     name, value = self.decoder(None, tlv) | ||||||
|  |  | ||||||
|  |                 self.__eeprom_tlv_dict[code] = value | ||||||
|  |                 if eeprom[tlv_index] == self._TLV_CODE_CRC_32: | ||||||
|  |                     break | ||||||
|  |  | ||||||
|  |                 tlv_index += eeprom[tlv_index+1] + 2 | ||||||
|  |  | ||||||
|  |     def serial_number_str(self): | ||||||
|  |         (is_valid, results) = self.get_tlv_field( | ||||||
|  |                          self.__eeprom_data, self._TLV_CODE_SERIAL_NUMBER) | ||||||
|  |         if not is_valid: | ||||||
|  |             return "N/A" | ||||||
|  |         return results[2].decode('ascii') | ||||||
|  |  | ||||||
|  |     def base_mac_addr(self): | ||||||
|  |         (is_valid, t) = self.get_tlv_field( | ||||||
|  |                           self.__eeprom_data, self._TLV_CODE_MAC_BASE) | ||||||
|  |         if not is_valid or t[1] != 6: | ||||||
|  |             return super(TlvInfoDecoder, self).switchaddrstr(e) | ||||||
|  |  | ||||||
|  |         return ":".join([binascii.b2a_hex(T) for T in t[2]]) | ||||||
|  |  | ||||||
|  |     def modelstr(self): | ||||||
|  |         (is_valid, results) = self.get_tlv_field( | ||||||
|  |                         self.__eeprom_data, self._TLV_CODE_PRODUCT_NAME) | ||||||
|  |         if not is_valid: | ||||||
|  |             return "N/A" | ||||||
|  |  | ||||||
|  |         return results[2].decode('ascii') | ||||||
|  |  | ||||||
|  |     def part_number_str(self): | ||||||
|  |         (is_valid, results) = self.get_tlv_field( | ||||||
|  |                     self.__eeprom_data, self._TLV_CODE_PART_NUMBER) | ||||||
|  |         if not is_valid: | ||||||
|  |             return "N/A" | ||||||
|  |  | ||||||
|  |         return results[2].decode('ascii') | ||||||
|  |  | ||||||
|  |     def serial_tag_str(self): | ||||||
|  |         (is_valid, results) = self.get_tlv_field( | ||||||
|  |                     self.__eeprom_data, self._TLV_CODE_SERVICE_TAG) | ||||||
|  |         if not is_valid: | ||||||
|  |             return "N/A" | ||||||
|  |  | ||||||
|  |         return results[2].decode('ascii') | ||||||
|  |  | ||||||
|  |     def revision_str(self): | ||||||
|  |         (is_valid, results) = self.get_tlv_field( | ||||||
|  |                     self.__eeprom_data, self._TLV_CODE_DEVICE_VERSION) | ||||||
|  |         if not is_valid: | ||||||
|  |             return "N/A" | ||||||
|  |  | ||||||
|  |         return results[2].decode('ascii') | ||||||
|  |  | ||||||
|  |     def system_eeprom_info(self): | ||||||
|  |         """ | ||||||
|  |         Returns a dictionary, where keys are the type code defined in | ||||||
|  |         ONIE EEPROM format and values are their corresponding values | ||||||
|  |         found in the system EEPROM. | ||||||
|  |         """ | ||||||
|  |         return self.__eeprom_tlv_dict | ||||||
|  |  | ||||||
| @@ -0,0 +1,186 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | # Celestica | ||||||
|  | # | ||||||
|  | # Module contains an implementation of SONiC Platform Base API and | ||||||
|  | # provides the fan status which are available in the platform | ||||||
|  | # | ||||||
|  | ############################################################################# | ||||||
|  |  | ||||||
|  | import math | ||||||
|  | import os.path | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_platform_base.fan_base import FanBase | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError(str(e) + "- required module not found") | ||||||
|  |  | ||||||
|  | FAN_PATH = "/sys/class/hwmon/hwmon1/" | ||||||
|  | FAN_MAX_PWM = 255 | ||||||
|  | FAN_FAN_PWM = "pwm{}" | ||||||
|  | FAN_FAN_INPUT = "fan{}_input" | ||||||
|  | FAN_MAX_RPM = 9000 | ||||||
|  | FAN_NAME_LIST = ["FAN-1", "FAN-2", "FAN-3", "FAN-4"] | ||||||
|  |  | ||||||
|  | class Fan(FanBase): | ||||||
|  |     """Platform-specific Fan class""" | ||||||
|  |  | ||||||
|  |     def __init__(self, fan_tray_index, fan_index=0): | ||||||
|  |         self.fan_index = fan_index | ||||||
|  |         self.fan_tray_index = fan_tray_index | ||||||
|  |  | ||||||
|  |         FanBase.__init__(self) | ||||||
|  |  | ||||||
|  |     def __read_txt_file(self, file_path): | ||||||
|  |         try: | ||||||
|  |             with open(file_path, 'r') as fd: | ||||||
|  |                 data = fd.read() | ||||||
|  |                 return data.strip() | ||||||
|  |         except IOError: | ||||||
|  |             pass | ||||||
|  |         return "" | ||||||
|  |  | ||||||
|  |     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 __search_file_by_name(self, directory, file_name): | ||||||
|  |         for dirpath, dirnames, files in os.walk(directory): | ||||||
|  |             for name in files: | ||||||
|  |                 file_path = os.path.join(dirpath, name) | ||||||
|  |                 if name in file_name: | ||||||
|  |                     return file_path | ||||||
|  |         return None | ||||||
|  |  | ||||||
|  |     def get_direction(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the direction of fan | ||||||
|  |         Returns: | ||||||
|  |             A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST | ||||||
|  |             depending on fan direction | ||||||
|  |         """ | ||||||
|  |         direction = self.FAN_DIRECTION_EXHAUST | ||||||
|  |         return direction | ||||||
|  |  | ||||||
|  |     def get_speed(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the speed of fan as a percentage of full speed | ||||||
|  |         Returns: | ||||||
|  |             An integer, the percentage of full fan speed, in the range 0 (off) | ||||||
|  |                  to 100 (full speed) | ||||||
|  |  | ||||||
|  |         Note: | ||||||
|  |             speed = pwm_in/255*100 | ||||||
|  |         """ | ||||||
|  |         speed = 0 | ||||||
|  |         fan_speed_sysfs_name = "fan{}_input".format(self.fan_index+1) | ||||||
|  |         fan_speed_sysfs_path = self.__search_file_by_name( | ||||||
|  |             FAN_PATH, fan_speed_sysfs_name) | ||||||
|  |         fan_speed_rpm = self.__read_txt_file(fan_speed_sysfs_path) or 0 | ||||||
|  |         speed = math.ceil(float(fan_speed_rpm) * 100 / FAN_MAX_RPM) | ||||||
|  |  | ||||||
|  |         return int(speed) | ||||||
|  |  | ||||||
|  |     def get_target_speed(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the target (expected) speed of the fan | ||||||
|  |         Returns: | ||||||
|  |             An integer, the percentage of full fan speed, in the range 0 (off) | ||||||
|  |                  to 100 (full speed) | ||||||
|  |  | ||||||
|  |         Note: | ||||||
|  |             speed_pc = pwm_target/255*100 | ||||||
|  |  | ||||||
|  |             0   : when PWM mode is use | ||||||
|  |             pwm : when pwm mode is not use | ||||||
|  |         """ | ||||||
|  |         # target = 0 | ||||||
|  |         # fan_target_sysfs_name = "pwm{}".format(self.fan_index+1) | ||||||
|  |         # fan_target_sysfs_path = self.__search_file_by_name( | ||||||
|  |         #     FAN_PATH, fan_target_sysfs_name) | ||||||
|  |         # fan_target_pwm = self.__read_txt_file(fan_target_sysfs_path) or 0 | ||||||
|  |         # target = math.ceil(float(fan_target_pwm) * 100 / FAN_MAX_PWM) | ||||||
|  |  | ||||||
|  |         # return target | ||||||
|  |         speed = 0 | ||||||
|  |         fan_speed_sysfs_name = "fan{}_input".format(self.fan_index+1) | ||||||
|  |         fan_speed_sysfs_path = self.__search_file_by_name( | ||||||
|  |             FAN_PATH, fan_speed_sysfs_name) | ||||||
|  |         fan_speed_rpm = self.__read_txt_file(fan_speed_sysfs_path) or 0 | ||||||
|  |         speed = math.ceil(float(fan_speed_rpm) * 100 / FAN_MAX_RPM) | ||||||
|  |  | ||||||
|  |         return speed | ||||||
|  |  | ||||||
|  |     def get_speed_tolerance(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the speed tolerance of the fan | ||||||
|  |         Returns: | ||||||
|  |             An integer, the percentage of variance from target speed which is | ||||||
|  |                  considered tolerable | ||||||
|  |         """ | ||||||
|  |         return 10 | ||||||
|  |  | ||||||
|  |     def set_speed(self, speed): | ||||||
|  |         """ | ||||||
|  |         Sets the fan speed | ||||||
|  |         Args: | ||||||
|  |             speed: An integer, the percentage of full fan speed to set fan to, | ||||||
|  |                    in the range 0 (off) to 100 (full speed) | ||||||
|  |         Returns: | ||||||
|  |             A boolean, True if speed is set successfully, False if not | ||||||
|  |  | ||||||
|  |         Note: | ||||||
|  |             Depends on pwm or target mode is selected: | ||||||
|  |             1) pwm = speed_pc * 255             <-- Currently use this mode. | ||||||
|  |             2) target_pwm = speed_pc * 100 / 255 | ||||||
|  |              2.1) set pwm{}_enable to 3 | ||||||
|  |  | ||||||
|  |         """ | ||||||
|  |         pwm = speed * 255 / 100 | ||||||
|  |         fan_target_sysfs_name = "pwm{}".format(self.fan_index+1) | ||||||
|  |         fan_target_sysfs_path = self.__search_file_by_name( | ||||||
|  |             FAN_PATH, fan_target_sysfs_name) | ||||||
|  |         return self.__write_txt_file(fan_target_sysfs_path, int(pwm)) | ||||||
|  |  | ||||||
|  |     def set_status_led(self, color): | ||||||
|  |         """ | ||||||
|  |         Sets the state of the fan module status LED | ||||||
|  |         Args: | ||||||
|  |             color: A string representing the color with which to set the | ||||||
|  |                    fan module status LED | ||||||
|  |         Returns: | ||||||
|  |             bool: always True | ||||||
|  |         """ | ||||||
|  |         return True | ||||||
|  |  | ||||||
|  |     def get_name(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the name of the device | ||||||
|  |             Returns: | ||||||
|  |             string: The name of the device | ||||||
|  |         """ | ||||||
|  |         fan_name = FAN_NAME_LIST[self.fan_index] | ||||||
|  |  | ||||||
|  |         return fan_name | ||||||
|  |  | ||||||
|  |     def get_presence(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the presence of the FAN | ||||||
|  |         Returns: | ||||||
|  |             bool: always True | ||||||
|  |         """ | ||||||
|  |  | ||||||
|  |         return True | ||||||
|  |  | ||||||
|  |     def get_status(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the status of the FAN | ||||||
|  |         Returns: | ||||||
|  |             bool: always True | ||||||
|  |         """ | ||||||
|  |         return True | ||||||
| @@ -0,0 +1,36 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
|  | ######################################################################## | ||||||
|  | # Centec E530 24x2c | ||||||
|  | # | ||||||
|  | # Module contains an implementation of SONiC Platform Base API and | ||||||
|  | # provides the Fan-Drawers' information available in the platform. | ||||||
|  | # | ||||||
|  | ######################################################################## | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_platform_base.fan_drawer_base import FanDrawerBase | ||||||
|  |     from .fan import Fan | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError(str(e) + "- required module not found") | ||||||
|  |  | ||||||
|  | CENTEC_FANS_PER_FANTRAY = 3 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class FanDrawer(FanDrawerBase): | ||||||
|  |     """Centec E530 24x2c Platform-specific Fan class""" | ||||||
|  |  | ||||||
|  |     def __init__(self, fantray_index): | ||||||
|  |  | ||||||
|  |         FanDrawerBase.__init__(self) | ||||||
|  |         self.fantrayindex = fantray_index | ||||||
|  |         for i in range(CENTEC_FANS_PER_FANTRAY): | ||||||
|  |             self._fan_list.append(Fan(fantray_index, i)) | ||||||
|  |  | ||||||
|  |     def get_name(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the fan drawer name | ||||||
|  |         Returns: | ||||||
|  |             string: The name of the device | ||||||
|  |         """ | ||||||
|  |         return "FanTray{}".format(self.fantrayindex) | ||||||
| @@ -0,0 +1,21 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  | # | ||||||
|  | # Name: platform.py, version: 1.0 | ||||||
|  | # | ||||||
|  | # Description: Module contains the definitions of SONiC platform APIs for Centec E530-24X2C | ||||||
|  | # | ||||||
|  |  | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_platform_base.platform_base import PlatformBase | ||||||
|  |     from sonic_platform.chassis import Chassis | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError(str(e) + "- required module not found") | ||||||
|  |   | ||||||
|  |   | ||||||
|  | class Platform(PlatformBase): | ||||||
|  |  | ||||||
|  |     def __init__(self): | ||||||
|  |         PlatformBase.__init__(self) | ||||||
|  |         self._chassis = Chassis() | ||||||
|  |  | ||||||
| @@ -0,0 +1,45 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
|  | from __future__ import print_function | ||||||
|  |  | ||||||
|  | import imp | ||||||
|  | import os | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_platform_base.psu_base import PsuBase | ||||||
|  |     from sonic_py_common import device_info | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError("%s - required module not found" % e) | ||||||
|  |  | ||||||
|  | USR_SHARE_SONIC_PATH = "/usr/share/sonic" | ||||||
|  | HOST_DEVICE_PATH = USR_SHARE_SONIC_PATH + "/device" | ||||||
|  | CONTAINER_PLATFORM_PATH = USR_SHARE_SONIC_PATH + "/platform" | ||||||
|  |  | ||||||
|  | class Psu(PsuBase): | ||||||
|  |     """Centec Platform-specific PSU class""" | ||||||
|  |  | ||||||
|  |     def __init__(self, index): | ||||||
|  |         self._index = index | ||||||
|  |         self._fan_list = [] | ||||||
|  |          | ||||||
|  |         if os.path.isdir(CONTAINER_PLATFORM_PATH): | ||||||
|  |             platform_path = CONTAINER_PLATFORM_PATH | ||||||
|  |         else: | ||||||
|  |             platform = device_info.get_platform() | ||||||
|  |             if platform is None: | ||||||
|  |                 return | ||||||
|  |             platform_path = os.path.join(HOST_DEVICE_PATH, platform) | ||||||
|  |  | ||||||
|  |         module_file = "/".join([platform_path, "plugins", "psuutil.py"]) | ||||||
|  |         module = imp.load_source("psuutil", module_file) | ||||||
|  |         psu_util_class = getattr(module, "PsuUtil") | ||||||
|  |         self._psuutil = psu_util_class() | ||||||
|  |  | ||||||
|  |     def _get_psuutil(self): | ||||||
|  |         return self._psuutil | ||||||
|  |  | ||||||
|  |     def get_presence(self): | ||||||
|  |         return self._get_psuutil().get_psu_presence(self._index) | ||||||
|  |  | ||||||
|  |     def get_powergood_status(self): | ||||||
|  |         return self._get_psuutil().get_psu_status(self._index) | ||||||
| @@ -0,0 +1,102 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
|  | from __future__ import print_function | ||||||
|  |  | ||||||
|  | import imp | ||||||
|  | import os | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_platform_base.sfp_base import SfpBase | ||||||
|  |     from sonic_py_common import device_info | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError("%s - required module not found" % e) | ||||||
|  |  | ||||||
|  | USR_SHARE_SONIC_PATH = "/usr/share/sonic" | ||||||
|  | HOST_DEVICE_PATH = USR_SHARE_SONIC_PATH + "/device" | ||||||
|  | CONTAINER_PLATFORM_PATH = USR_SHARE_SONIC_PATH + "/platform" | ||||||
|  |  | ||||||
|  | class Sfp(SfpBase): | ||||||
|  |     """ | ||||||
|  |     Platform-specific sfp class | ||||||
|  |  | ||||||
|  |     Unimplemented methods: | ||||||
|  |     - get_model | ||||||
|  |     - get_serial | ||||||
|  |     - get_status | ||||||
|  |     - get_transceiver_info | ||||||
|  |     - get_transceiver_bulk_status | ||||||
|  |     - get_transceiver_threshold_info | ||||||
|  |     - get_reset_status | ||||||
|  |     - get_rx_los | ||||||
|  |     - get_tx_fault | ||||||
|  |     - get_tx_disable_channel | ||||||
|  |     - get_power_override | ||||||
|  |     - get_temperature | ||||||
|  |     - get_voltage | ||||||
|  |     - get_tx_bias | ||||||
|  |     - get_rx_power | ||||||
|  |     - get_tx_power | ||||||
|  |     - tx_disable_channel | ||||||
|  |     - set_power_override | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     def __init__(self, index): | ||||||
|  |         self._index = index | ||||||
|  |          | ||||||
|  |         if os.path.isdir(CONTAINER_PLATFORM_PATH): | ||||||
|  |             platform_path = CONTAINER_PLATFORM_PATH | ||||||
|  |         else: | ||||||
|  |             platform = device_info.get_platform() | ||||||
|  |             if platform is None: | ||||||
|  |                 return | ||||||
|  |             platform_path = os.path.join(HOST_DEVICE_PATH, platform) | ||||||
|  |  | ||||||
|  |         module_file = "/".join([platform_path, "plugins", "sfputil.py"]) | ||||||
|  |         module = imp.load_source("sfputil", module_file) | ||||||
|  |         sfp_util_class = getattr(module, "SfpUtil") | ||||||
|  |         self._sfputil = sfp_util_class() | ||||||
|  |  | ||||||
|  |     def get_id(self): | ||||||
|  |         return self._index | ||||||
|  |  | ||||||
|  |     def get_name(self): | ||||||
|  |         return "Ethernet{}".format(self._index) | ||||||
|  |  | ||||||
|  |     def get_lpmode(self): | ||||||
|  |         return False | ||||||
|  |  | ||||||
|  |     def set_lpmode(self, lpmode): | ||||||
|  |         return False | ||||||
|  |  | ||||||
|  |     def get_tx_disable(self): | ||||||
|  |         return False | ||||||
|  |  | ||||||
|  |     def tx_disable(self, tx_disable): | ||||||
|  |          return False | ||||||
|  |  | ||||||
|  |     def reset(self): | ||||||
|  |             pass | ||||||
|  |  | ||||||
|  |     def clear_interrupt(self): | ||||||
|  |         return False | ||||||
|  |  | ||||||
|  |     def get_interrupt_file(self): | ||||||
|  |         return None | ||||||
|  |  | ||||||
|  |     def _get_sfputil(self): | ||||||
|  |         return self._sfputil | ||||||
|  |  | ||||||
|  |     def get_presence(self): | ||||||
|  |         return self._get_sfputil().get_presence(self._index) | ||||||
|  |  | ||||||
|  |     def get_transceiver_info(self): | ||||||
|  |         return self._get_sfputil().get_transceiver_info_dict(self._index) | ||||||
|  |  | ||||||
|  |     def get_transceiver_bulk_status(self): | ||||||
|  |         return self._get_sfputil().get_transceiver_dom_info_dict(self._index) | ||||||
|  |  | ||||||
|  |     def get_transceiver_threshold_info(self): | ||||||
|  |         return self._get_sfputil().get_transceiver_dom_threshold_info_dict(self._index) | ||||||
|  |  | ||||||
|  |     def get_transceiver_change_event(self, timeout): | ||||||
|  |         return self._get_sfputil().get_transceiver_change_event(timeout) | ||||||
| @@ -0,0 +1,118 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | # Celestica | ||||||
|  | # | ||||||
|  | # Thermal contains an implementation of SONiC Platform Base API and | ||||||
|  | # provides the thermal device status which are available in the platform | ||||||
|  | # | ||||||
|  | ############################################################################# | ||||||
|  |  | ||||||
|  | import os | ||||||
|  | import os.path | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_platform_base.thermal_base import ThermalBase | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError(str(e) + "- required module not found") | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Thermal(ThermalBase): | ||||||
|  |     """Platform-specific Thermal class""" | ||||||
|  |  | ||||||
|  |     THERMAL_NAME_LIST = [] | ||||||
|  |     CPUBOARD_SS_PATH = "/sys/class/hwmon/hwmon1" | ||||||
|  |  | ||||||
|  |     def __init__(self, thermal_index): | ||||||
|  |         self.index = thermal_index | ||||||
|  |         self.high_threshold = float(112) | ||||||
|  |  | ||||||
|  |         # Add thermal name | ||||||
|  |         self.THERMAL_NAME_LIST.append("SENSOR-1") | ||||||
|  |  | ||||||
|  |         # Set hwmon path | ||||||
|  |         self.ss_index, self.hwmon_path = 1, self.CPUBOARD_SS_PATH | ||||||
|  |         self.ss_key = self.THERMAL_NAME_LIST[self.index - 1] | ||||||
|  |  | ||||||
|  |     def __read_txt_file(self, file_path): | ||||||
|  |         try: | ||||||
|  |             with open(file_path, 'r') as fd: | ||||||
|  |                 data = fd.read() | ||||||
|  |                 return data.strip() | ||||||
|  |         except IOError: | ||||||
|  |             raise IOError("Unable to open %s file !" % file_path) | ||||||
|  |  | ||||||
|  |     def __get_temp(self, temp_file): | ||||||
|  |         temp_file_path = os.path.join(self.hwmon_path, temp_file) | ||||||
|  |         raw_temp = self.__read_txt_file(temp_file_path) | ||||||
|  |         temp = float(raw_temp)/1000 | ||||||
|  |         return float("{:.3f}".format(temp)) | ||||||
|  |  | ||||||
|  |     def __set_threshold(self, file_name, temperature): | ||||||
|  |         temp_file_path = os.path.join(self.hwmon_path, file_name) | ||||||
|  |         try: | ||||||
|  |             with open(temp_file_path, 'w') as fd: | ||||||
|  |                 fd.write(str(temperature)) | ||||||
|  |             return True | ||||||
|  |         except IOError: | ||||||
|  |             return False | ||||||
|  |  | ||||||
|  |     def get_temperature(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves current temperature reading from thermal | ||||||
|  |         Returns: | ||||||
|  |             A float number of current temperature in Celsius up to nearest thousandth | ||||||
|  |             of one degree Celsius, e.g. 30.125 | ||||||
|  |         """ | ||||||
|  |         temp_file = "temp{}_input".format(self.ss_index) | ||||||
|  |         return self.__get_temp(temp_file) | ||||||
|  |  | ||||||
|  |     def get_high_threshold(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the high threshold temperature of thermal | ||||||
|  |         Returns: | ||||||
|  |             A float number, the high threshold temperature of thermal in Celsius | ||||||
|  |             up to nearest thousandth of one degree Celsius, e.g. 30.125 | ||||||
|  |         """ | ||||||
|  |         return self.high_threshold | ||||||
|  |  | ||||||
|  |     def set_high_threshold(self, temperature): | ||||||
|  |         """ | ||||||
|  |         Sets the high threshold temperature of thermal | ||||||
|  |         Args : | ||||||
|  |             temperature: A float number up to nearest thousandth of one degree Celsius, | ||||||
|  |             e.g. 30.125 | ||||||
|  |         Returns: | ||||||
|  |             A boolean, True if threshold is set successfully, False if not | ||||||
|  |         """ | ||||||
|  |         self.high_threshold = float(temperature) | ||||||
|  |         return True | ||||||
|  |  | ||||||
|  |     def get_name(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the name of the thermal device | ||||||
|  |             Returns: | ||||||
|  |             string: The name of the thermal device | ||||||
|  |         """ | ||||||
|  |         return self.THERMAL_NAME_LIST[self.index] | ||||||
|  |  | ||||||
|  |     def get_presence(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the presence of the PSU | ||||||
|  |         Returns: | ||||||
|  |             bool: True if PSU is present, False if not | ||||||
|  |         """ | ||||||
|  |         temp_file = "temp{}_input".format(self.ss_index) | ||||||
|  |         temp_file_path = os.path.join(self.hwmon_path, temp_file) | ||||||
|  |         return os.path.isfile(temp_file_path) | ||||||
|  |  | ||||||
|  |     def get_status(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the operational status of the device | ||||||
|  |         Returns: | ||||||
|  |             A boolean value, True if device is operating properly, False if not | ||||||
|  |         """ | ||||||
|  |         if not self.get_presence(): | ||||||
|  |             return False | ||||||
|  |  | ||||||
|  |         return True | ||||||
| @@ -0,0 +1 @@ | |||||||
|  | obj-m := centec_e530_24x2q_platform.o | ||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | [Unit] | ||||||
|  | Description=Centec modules init | ||||||
|  | After=local-fs.target | ||||||
|  | Before=syncd.service | ||||||
|  |  | ||||||
|  | [Service] | ||||||
|  | Type=oneshot | ||||||
|  | ExecStart=-/etc/init.d/platform-modules-e530-24x2q start | ||||||
|  | ExecStop=-/etc/init.d/platform-modules-e530-24x2q stop | ||||||
|  | RemainAfterExit=yes | ||||||
|  |  | ||||||
|  | [Install] | ||||||
|  | WantedBy=multi-user.target | ||||||
| @@ -0,0 +1,15 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
|  | import os | ||||||
|  | from setuptools import setup | ||||||
|  | os.listdir | ||||||
|  |  | ||||||
|  | setup( | ||||||
|  |    name='sonic_platform', | ||||||
|  |    version='1.0', | ||||||
|  |    description='Module to initialize centec e530-24x2q platforms', | ||||||
|  |     | ||||||
|  |    packages=['sonic_platform'], | ||||||
|  |    package_dir={'sonic_platform': 'sonic_platform'}, | ||||||
|  | ) | ||||||
|  |  | ||||||
| @@ -0,0 +1,3 @@ | |||||||
|  | __all__ = ["platform", "chassis", "sfp", "eeprom", "psu", "thermal", "fan", "fan_drawer"] | ||||||
|  | from . import platform | ||||||
|  |  | ||||||
| @@ -0,0 +1,203 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  | # | ||||||
|  | # Name: chassis.py, version: 1.0 | ||||||
|  | # | ||||||
|  | # Description: Module contains the definitions of SONiC platform APIs  | ||||||
|  | # | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     import os | ||||||
|  |     import re | ||||||
|  |     import collections | ||||||
|  |     from sonic_platform_base.chassis_base import ChassisBase | ||||||
|  |     from sonic_platform.eeprom import Eeprom | ||||||
|  |     from .fan_drawer import FanDrawer | ||||||
|  |     from .thermal import Thermal | ||||||
|  |     from .sfp import Sfp | ||||||
|  |     from .psu import Psu | ||||||
|  |     from sonic_py_common import device_info | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError(str(e) + "- required module not found") | ||||||
|  |  | ||||||
|  | NUM_FAN_TRAY = 1 | ||||||
|  | NUM_THERMAL = 1 | ||||||
|  | NUM_PSU = 2 | ||||||
|  | USR_SHARE_SONIC_PATH = "/usr/share/sonic" | ||||||
|  | HOST_DEVICE_PATH = USR_SHARE_SONIC_PATH + "/device" | ||||||
|  | CONTAINER_PLATFORM_PATH = USR_SHARE_SONIC_PATH + "/platform" | ||||||
|  |  | ||||||
|  | class Chassis(ChassisBase): | ||||||
|  |  | ||||||
|  |     def __init__(self): | ||||||
|  |         ChassisBase.__init__(self) | ||||||
|  |  | ||||||
|  |         if os.path.isdir(CONTAINER_PLATFORM_PATH): | ||||||
|  |             platform_path = CONTAINER_PLATFORM_PATH | ||||||
|  |         else: | ||||||
|  |             platform = device_info.get_platform() | ||||||
|  |             if platform is None: | ||||||
|  |                 raise | ||||||
|  |             platform_path = os.path.join(HOST_DEVICE_PATH, platform) | ||||||
|  |  | ||||||
|  |         port_config_file = "/".join([platform_path, "E530-24x2q", "port_config.ini"]) | ||||||
|  |         try: | ||||||
|  |             f = open(port_config_file) | ||||||
|  |         except: | ||||||
|  |             raise | ||||||
|  |         for line in f: | ||||||
|  |             line.strip() | ||||||
|  |             if re.search('^#', line) is not None: | ||||||
|  |                 Port_cfg = collections.namedtuple('Port_cfg', line.split()[1:]) | ||||||
|  |                 break | ||||||
|  |         f.close() | ||||||
|  |         f = open(port_config_file) | ||||||
|  |         _port_cfgs = [Port_cfg(*tuple((line.strip().split()))) | ||||||
|  |                            for line in f if re.search('^#', line) is None] | ||||||
|  |         f.close() | ||||||
|  |  | ||||||
|  |         # Initialize EEPROM | ||||||
|  |         self._eeprom = Eeprom() | ||||||
|  |         # Initialize FAN | ||||||
|  |         for i in range(NUM_FAN_TRAY): | ||||||
|  |             fandrawer = FanDrawer(i) | ||||||
|  |             self._fan_drawer_list.append(fandrawer) | ||||||
|  |             self._fan_list.extend(fandrawer._fan_list) | ||||||
|  |         # Initialize THERMAL | ||||||
|  |         for index in range(0, NUM_THERMAL): | ||||||
|  |             thermal = Thermal(index) | ||||||
|  |             self._thermal_list.append(thermal) | ||||||
|  |         # Initialize SFP | ||||||
|  |         for port_cfg in _port_cfgs: | ||||||
|  |             sfp = Sfp(int(port_cfg.index)) | ||||||
|  |             self._sfp_list.append(sfp) | ||||||
|  |         # Initialize PSU | ||||||
|  |         for index in range(0, NUM_PSU): | ||||||
|  |             psu = Psu(index + 1) | ||||||
|  |             self._psu_list.append(psu) | ||||||
|  |             | ||||||
|  | ############################################## | ||||||
|  | # Device methods | ||||||
|  | ############################################## | ||||||
|  |  | ||||||
|  |     def get_name(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the name of the chassis | ||||||
|  |         Returns: | ||||||
|  |             string: The name of the chassis | ||||||
|  |         """ | ||||||
|  |         return self._eeprom.modelstr() | ||||||
|  |  | ||||||
|  |     def get_presence(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the presence of the chassis | ||||||
|  |         Returns: | ||||||
|  |             bool: True if chassis is present, False if not | ||||||
|  |         """ | ||||||
|  |         return True | ||||||
|  |  | ||||||
|  |     def get_model(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the model number (or part number) of the chassis | ||||||
|  |         Returns: | ||||||
|  |             string: Model/part number of chassis | ||||||
|  |         """ | ||||||
|  |         return self._eeprom.part_number_str() | ||||||
|  |  | ||||||
|  |     def get_serial(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the serial number of the chassis | ||||||
|  |         Returns: | ||||||
|  |             string: Serial number of chassis | ||||||
|  |         """ | ||||||
|  |         return self._eeprom.serial_number_str() | ||||||
|  |  | ||||||
|  |     def get_status(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the operational status of the chassis | ||||||
|  |         Returns: | ||||||
|  |             bool: A boolean value, True if chassis is operating properly | ||||||
|  |             False if not | ||||||
|  |         """ | ||||||
|  |         return True | ||||||
|  |  | ||||||
|  | ############################################## | ||||||
|  | # Chassis methods | ||||||
|  | ############################################## | ||||||
|  |  | ||||||
|  |     def get_base_mac(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the base MAC address for the chassis | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             A string containing the MAC address in the format | ||||||
|  |             'XX:XX:XX:XX:XX:XX' | ||||||
|  |         """ | ||||||
|  |         return self._eeprom.base_mac_addr() | ||||||
|  |  | ||||||
|  |     def get_serial_number(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the hardware serial number for the chassis | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             A string containing the hardware serial number for this chassis. | ||||||
|  |         """ | ||||||
|  |         return self._eeprom.serial_number_str() | ||||||
|  |  | ||||||
|  |     def get_system_eeprom_info(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the full content of system EEPROM information for the chassis | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             A dictionary where keys are the type code defined in | ||||||
|  |             OCP ONIE TlvInfo EEPROM format and values are their corresponding | ||||||
|  |             values. | ||||||
|  |             Ex. { '0x21':'AG9064', '0x22':'V1.0', '0x23':'AG9064-0109867821', | ||||||
|  |                   '0x24':'001c0f000fcd0a', '0x25':'02/03/2018 16:22:00', | ||||||
|  |                   '0x26':'01', '0x27':'REV01', '0x28':'AG9064-C2358-16G'} | ||||||
|  |         """ | ||||||
|  |         return self._eeprom.system_eeprom_info() | ||||||
|  |  | ||||||
|  |     def get_reboot_cause(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the cause of the previous reboot | ||||||
|  |         Returns: | ||||||
|  |             A tuple (string, string) where the first element is a string | ||||||
|  |             containing the cause of the previous reboot. This string must be | ||||||
|  |             one of the predefined strings in this class. If the first string | ||||||
|  |             is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used | ||||||
|  |             to pass a description of the reboot cause. | ||||||
|  |         """ | ||||||
|  |         return (None, None) | ||||||
|  |  | ||||||
|  |     def get_change_event(self, timeout=2000): | ||||||
|  |         """ | ||||||
|  |         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. | ||||||
|  |         """ | ||||||
|  |         ret, port_dict = self._sfp_list[0].get_transceiver_change_event(timeout) | ||||||
|  |         ret_dict = {"sfp": port_dict} | ||||||
|  |         return ret, ret_dict | ||||||
|  |  | ||||||
|  |     def get_num_psus(self): | ||||||
|  |         return len(self._psu_list) | ||||||
|  |  | ||||||
|  |     def get_psu(self, psu_index): | ||||||
|  |         return self._psu_list[psu_index] | ||||||
| @@ -0,0 +1,111 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  | # | ||||||
|  | # Name: eeprom.py, version: 1.0 | ||||||
|  | # | ||||||
|  | # Description: Module contains the definitions of SONiC platform APIs  | ||||||
|  | # | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_eeprom import eeprom_tlvinfo | ||||||
|  |     import binascii | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError(str(e) + "- required module not found") | ||||||
|  |  | ||||||
|  | class Eeprom(eeprom_tlvinfo.TlvInfoDecoder): | ||||||
|  |  | ||||||
|  |     def __init__(self): | ||||||
|  |         self.__eeprom_path = "/dev/mtd3" | ||||||
|  |         super(Eeprom, self).__init__(self.__eeprom_path, 0, '', True) | ||||||
|  |         self.__eeprom_tlv_dict = dict() | ||||||
|  |         try: | ||||||
|  |             self.open_eeprom() | ||||||
|  |             self.__eeprom_data = self.read_eeprom() | ||||||
|  |         except: | ||||||
|  |             self.__eeprom_data = "N/A" | ||||||
|  |             raise RuntimeError("Eeprom is not Programmed") | ||||||
|  |         else: | ||||||
|  |             eeprom = self.__eeprom_data | ||||||
|  |  | ||||||
|  |             if not self.is_valid_tlvinfo_header(eeprom): | ||||||
|  |                 return | ||||||
|  |  | ||||||
|  |             total_length = (eeprom[9] << 8) | eeprom[10] | ||||||
|  |             tlv_index = self._TLV_INFO_HDR_LEN | ||||||
|  |             tlv_end = self._TLV_INFO_HDR_LEN + total_length | ||||||
|  |  | ||||||
|  |             while (tlv_index + 2) < len(eeprom) and tlv_index < tlv_end: | ||||||
|  |                 if not self.is_valid_tlv(eeprom[tlv_index:]): | ||||||
|  |                     break | ||||||
|  |  | ||||||
|  |                 tlv = eeprom[tlv_index:tlv_index + 2 | ||||||
|  |                              + eeprom[tlv_index + 1]] | ||||||
|  |                 code = "0x%02X" % (tlv[0]) | ||||||
|  |  | ||||||
|  |                 if tlv[0] == self._TLV_CODE_VENDOR_EXT: | ||||||
|  |                     value = str((tlv[2] << 24) | (tlv[3] << 16) | | ||||||
|  |                                 (tlv[4] << 8) | tlv[5]) | ||||||
|  |                     value += str(tlv[6:6 + tlv[1]]) | ||||||
|  |                 else: | ||||||
|  |                     name, value = self.decoder(None, tlv) | ||||||
|  |  | ||||||
|  |                 self.__eeprom_tlv_dict[code] = value | ||||||
|  |                 if eeprom[tlv_index] == self._TLV_CODE_CRC_32: | ||||||
|  |                     break | ||||||
|  |  | ||||||
|  |                 tlv_index += eeprom[tlv_index+1] + 2 | ||||||
|  |  | ||||||
|  |     def serial_number_str(self): | ||||||
|  |         (is_valid, results) = self.get_tlv_field( | ||||||
|  |                          self.__eeprom_data, self._TLV_CODE_SERIAL_NUMBER) | ||||||
|  |         if not is_valid: | ||||||
|  |             return "N/A" | ||||||
|  |         return results[2].decode('ascii') | ||||||
|  |  | ||||||
|  |     def base_mac_addr(self): | ||||||
|  |         (is_valid, t) = self.get_tlv_field( | ||||||
|  |                           self.__eeprom_data, self._TLV_CODE_MAC_BASE) | ||||||
|  |         if not is_valid or t[1] != 6: | ||||||
|  |             return super(TlvInfoDecoder, self).switchaddrstr(e) | ||||||
|  |  | ||||||
|  |         return ":".join([binascii.b2a_hex(T) for T in t[2]]) | ||||||
|  |  | ||||||
|  |     def modelstr(self): | ||||||
|  |         (is_valid, results) = self.get_tlv_field( | ||||||
|  |                         self.__eeprom_data, self._TLV_CODE_PRODUCT_NAME) | ||||||
|  |         if not is_valid: | ||||||
|  |             return "N/A" | ||||||
|  |  | ||||||
|  |         return results[2].decode('ascii') | ||||||
|  |  | ||||||
|  |     def part_number_str(self): | ||||||
|  |         (is_valid, results) = self.get_tlv_field( | ||||||
|  |                     self.__eeprom_data, self._TLV_CODE_PART_NUMBER) | ||||||
|  |         if not is_valid: | ||||||
|  |             return "N/A" | ||||||
|  |  | ||||||
|  |         return results[2].decode('ascii') | ||||||
|  |  | ||||||
|  |     def serial_tag_str(self): | ||||||
|  |         (is_valid, results) = self.get_tlv_field( | ||||||
|  |                     self.__eeprom_data, self._TLV_CODE_SERVICE_TAG) | ||||||
|  |         if not is_valid: | ||||||
|  |             return "N/A" | ||||||
|  |  | ||||||
|  |         return results[2].decode('ascii') | ||||||
|  |  | ||||||
|  |     def revision_str(self): | ||||||
|  |         (is_valid, results) = self.get_tlv_field( | ||||||
|  |                     self.__eeprom_data, self._TLV_CODE_DEVICE_VERSION) | ||||||
|  |         if not is_valid: | ||||||
|  |             return "N/A" | ||||||
|  |  | ||||||
|  |         return results[2].decode('ascii') | ||||||
|  |  | ||||||
|  |     def system_eeprom_info(self): | ||||||
|  |         """ | ||||||
|  |         Returns a dictionary, where keys are the type code defined in | ||||||
|  |         ONIE EEPROM format and values are their corresponding values | ||||||
|  |         found in the system EEPROM. | ||||||
|  |         """ | ||||||
|  |         return self.__eeprom_tlv_dict | ||||||
|  |  | ||||||
| @@ -0,0 +1,186 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | # Celestica | ||||||
|  | # | ||||||
|  | # Module contains an implementation of SONiC Platform Base API and | ||||||
|  | # provides the fan status which are available in the platform | ||||||
|  | # | ||||||
|  | ############################################################################# | ||||||
|  |  | ||||||
|  | import math | ||||||
|  | import os.path | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_platform_base.fan_base import FanBase | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError(str(e) + "- required module not found") | ||||||
|  |  | ||||||
|  | FAN_PATH = "/sys/class/hwmon/hwmon1/" | ||||||
|  | FAN_MAX_PWM = 255 | ||||||
|  | FAN_FAN_PWM = "pwm{}" | ||||||
|  | FAN_FAN_INPUT = "fan{}_input" | ||||||
|  | FAN_MAX_RPM = 9000 | ||||||
|  | FAN_NAME_LIST = ["FAN-1", "FAN-2", "FAN-3", "FAN-4"] | ||||||
|  |  | ||||||
|  | class Fan(FanBase): | ||||||
|  |     """Platform-specific Fan class""" | ||||||
|  |  | ||||||
|  |     def __init__(self, fan_tray_index, fan_index=0): | ||||||
|  |         self.fan_index = fan_index | ||||||
|  |         self.fan_tray_index = fan_tray_index | ||||||
|  |  | ||||||
|  |         FanBase.__init__(self) | ||||||
|  |  | ||||||
|  |     def __read_txt_file(self, file_path): | ||||||
|  |         try: | ||||||
|  |             with open(file_path, 'r') as fd: | ||||||
|  |                 data = fd.read() | ||||||
|  |                 return data.strip() | ||||||
|  |         except IOError: | ||||||
|  |             pass | ||||||
|  |         return "" | ||||||
|  |  | ||||||
|  |     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 __search_file_by_name(self, directory, file_name): | ||||||
|  |         for dirpath, dirnames, files in os.walk(directory): | ||||||
|  |             for name in files: | ||||||
|  |                 file_path = os.path.join(dirpath, name) | ||||||
|  |                 if name in file_name: | ||||||
|  |                     return file_path | ||||||
|  |         return None | ||||||
|  |  | ||||||
|  |     def get_direction(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the direction of fan | ||||||
|  |         Returns: | ||||||
|  |             A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST | ||||||
|  |             depending on fan direction | ||||||
|  |         """ | ||||||
|  |         direction = self.FAN_DIRECTION_EXHAUST | ||||||
|  |         return direction | ||||||
|  |  | ||||||
|  |     def get_speed(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the speed of fan as a percentage of full speed | ||||||
|  |         Returns: | ||||||
|  |             An integer, the percentage of full fan speed, in the range 0 (off) | ||||||
|  |                  to 100 (full speed) | ||||||
|  |  | ||||||
|  |         Note: | ||||||
|  |             speed = pwm_in/255*100 | ||||||
|  |         """ | ||||||
|  |         speed = 0 | ||||||
|  |         fan_speed_sysfs_name = "fan{}_input".format(self.fan_index+1) | ||||||
|  |         fan_speed_sysfs_path = self.__search_file_by_name( | ||||||
|  |             FAN_PATH, fan_speed_sysfs_name) | ||||||
|  |         fan_speed_rpm = self.__read_txt_file(fan_speed_sysfs_path) or 0 | ||||||
|  |         speed = math.ceil(float(fan_speed_rpm) * 100 / FAN_MAX_RPM) | ||||||
|  |  | ||||||
|  |         return int(speed) | ||||||
|  |  | ||||||
|  |     def get_target_speed(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the target (expected) speed of the fan | ||||||
|  |         Returns: | ||||||
|  |             An integer, the percentage of full fan speed, in the range 0 (off) | ||||||
|  |                  to 100 (full speed) | ||||||
|  |  | ||||||
|  |         Note: | ||||||
|  |             speed_pc = pwm_target/255*100 | ||||||
|  |  | ||||||
|  |             0   : when PWM mode is use | ||||||
|  |             pwm : when pwm mode is not use | ||||||
|  |         """ | ||||||
|  |         # target = 0 | ||||||
|  |         # fan_target_sysfs_name = "pwm{}".format(self.fan_index+1) | ||||||
|  |         # fan_target_sysfs_path = self.__search_file_by_name( | ||||||
|  |         #     FAN_PATH, fan_target_sysfs_name) | ||||||
|  |         # fan_target_pwm = self.__read_txt_file(fan_target_sysfs_path) or 0 | ||||||
|  |         # target = math.ceil(float(fan_target_pwm) * 100 / FAN_MAX_PWM) | ||||||
|  |  | ||||||
|  |         # return target | ||||||
|  |         speed = 0 | ||||||
|  |         fan_speed_sysfs_name = "fan{}_input".format(self.fan_index+1) | ||||||
|  |         fan_speed_sysfs_path = self.__search_file_by_name( | ||||||
|  |             FAN_PATH, fan_speed_sysfs_name) | ||||||
|  |         fan_speed_rpm = self.__read_txt_file(fan_speed_sysfs_path) or 0 | ||||||
|  |         speed = math.ceil(float(fan_speed_rpm) * 100 / FAN_MAX_RPM) | ||||||
|  |  | ||||||
|  |         return speed | ||||||
|  |  | ||||||
|  |     def get_speed_tolerance(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the speed tolerance of the fan | ||||||
|  |         Returns: | ||||||
|  |             An integer, the percentage of variance from target speed which is | ||||||
|  |                  considered tolerable | ||||||
|  |         """ | ||||||
|  |         return 10 | ||||||
|  |  | ||||||
|  |     def set_speed(self, speed): | ||||||
|  |         """ | ||||||
|  |         Sets the fan speed | ||||||
|  |         Args: | ||||||
|  |             speed: An integer, the percentage of full fan speed to set fan to, | ||||||
|  |                    in the range 0 (off) to 100 (full speed) | ||||||
|  |         Returns: | ||||||
|  |             A boolean, True if speed is set successfully, False if not | ||||||
|  |  | ||||||
|  |         Note: | ||||||
|  |             Depends on pwm or target mode is selected: | ||||||
|  |             1) pwm = speed_pc * 255             <-- Currently use this mode. | ||||||
|  |             2) target_pwm = speed_pc * 100 / 255 | ||||||
|  |              2.1) set pwm{}_enable to 3 | ||||||
|  |  | ||||||
|  |         """ | ||||||
|  |         pwm = speed * 255 / 100 | ||||||
|  |         fan_target_sysfs_name = "pwm{}".format(self.fan_index+1) | ||||||
|  |         fan_target_sysfs_path = self.__search_file_by_name( | ||||||
|  |             FAN_PATH, fan_target_sysfs_name) | ||||||
|  |         return self.__write_txt_file(fan_target_sysfs_path, int(pwm)) | ||||||
|  |  | ||||||
|  |     def set_status_led(self, color): | ||||||
|  |         """ | ||||||
|  |         Sets the state of the fan module status LED | ||||||
|  |         Args: | ||||||
|  |             color: A string representing the color with which to set the | ||||||
|  |                    fan module status LED | ||||||
|  |         Returns: | ||||||
|  |             bool: always True | ||||||
|  |         """ | ||||||
|  |         return True | ||||||
|  |  | ||||||
|  |     def get_name(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the name of the device | ||||||
|  |             Returns: | ||||||
|  |             string: The name of the device | ||||||
|  |         """ | ||||||
|  |         fan_name = FAN_NAME_LIST[self.fan_index] | ||||||
|  |  | ||||||
|  |         return fan_name | ||||||
|  |  | ||||||
|  |     def get_presence(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the presence of the FAN | ||||||
|  |         Returns: | ||||||
|  |             bool: always True | ||||||
|  |         """ | ||||||
|  |  | ||||||
|  |         return True | ||||||
|  |  | ||||||
|  |     def get_status(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the status of the FAN | ||||||
|  |         Returns: | ||||||
|  |             bool: always True | ||||||
|  |         """ | ||||||
|  |         return True | ||||||
| @@ -0,0 +1,36 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
|  | ######################################################################## | ||||||
|  | # Centec E530 24x2q | ||||||
|  | # | ||||||
|  | # Module contains an implementation of SONiC Platform Base API and | ||||||
|  | # provides the Fan-Drawers' information available in the platform. | ||||||
|  | # | ||||||
|  | ######################################################################## | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_platform_base.fan_drawer_base import FanDrawerBase | ||||||
|  |     from .fan import Fan | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError(str(e) + "- required module not found") | ||||||
|  |  | ||||||
|  | CENTEC_FANS_PER_FANTRAY = 3 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class FanDrawer(FanDrawerBase): | ||||||
|  |     """Centec E530 24x2q Platform-specific Fan class""" | ||||||
|  |  | ||||||
|  |     def __init__(self, fantray_index): | ||||||
|  |  | ||||||
|  |         FanDrawerBase.__init__(self) | ||||||
|  |         self.fantrayindex = fantray_index | ||||||
|  |         for i in range(CENTEC_FANS_PER_FANTRAY): | ||||||
|  |             self._fan_list.append(Fan(fantray_index, i)) | ||||||
|  |  | ||||||
|  |     def get_name(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the fan drawer name | ||||||
|  |         Returns: | ||||||
|  |             string: The name of the device | ||||||
|  |         """ | ||||||
|  |         return "FanTray{}".format(self.fantrayindex) | ||||||
| @@ -0,0 +1,21 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  | # | ||||||
|  | # Name: platform.py, version: 1.0 | ||||||
|  | # | ||||||
|  | # Description: Module contains the definitions of SONiC platform APIs for Centec E530-24X2Q | ||||||
|  | # | ||||||
|  |  | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_platform_base.platform_base import PlatformBase | ||||||
|  |     from sonic_platform.chassis import Chassis | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError(str(e) + "- required module not found") | ||||||
|  |   | ||||||
|  |   | ||||||
|  | class Platform(PlatformBase): | ||||||
|  |  | ||||||
|  |     def __init__(self): | ||||||
|  |         PlatformBase.__init__(self) | ||||||
|  |         self._chassis = Chassis() | ||||||
|  |  | ||||||
| @@ -0,0 +1,45 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
|  | from __future__ import print_function | ||||||
|  |  | ||||||
|  | import imp | ||||||
|  | import os | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_platform_base.psu_base import PsuBase | ||||||
|  |     from sonic_py_common import device_info | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError("%s - required module not found" % e) | ||||||
|  |  | ||||||
|  | USR_SHARE_SONIC_PATH = "/usr/share/sonic" | ||||||
|  | HOST_DEVICE_PATH = USR_SHARE_SONIC_PATH + "/device" | ||||||
|  | CONTAINER_PLATFORM_PATH = USR_SHARE_SONIC_PATH + "/platform" | ||||||
|  |  | ||||||
|  | class Psu(PsuBase): | ||||||
|  |     """Centec Platform-specific PSU class""" | ||||||
|  |  | ||||||
|  |     def __init__(self, index): | ||||||
|  |         self._index = index | ||||||
|  |         self._fan_list = [] | ||||||
|  |          | ||||||
|  |         if os.path.isdir(CONTAINER_PLATFORM_PATH): | ||||||
|  |             platform_path = CONTAINER_PLATFORM_PATH | ||||||
|  |         else: | ||||||
|  |             platform = device_info.get_platform() | ||||||
|  |             if platform is None: | ||||||
|  |                 return | ||||||
|  |             platform_path = os.path.join(HOST_DEVICE_PATH, platform) | ||||||
|  |  | ||||||
|  |         module_file = "/".join([platform_path, "plugins", "psuutil.py"]) | ||||||
|  |         module = imp.load_source("psuutil", module_file) | ||||||
|  |         psu_util_class = getattr(module, "PsuUtil") | ||||||
|  |         self._psuutil = psu_util_class() | ||||||
|  |  | ||||||
|  |     def _get_psuutil(self): | ||||||
|  |         return self._psuutil | ||||||
|  |  | ||||||
|  |     def get_presence(self): | ||||||
|  |         return self._get_psuutil().get_psu_presence(self._index) | ||||||
|  |  | ||||||
|  |     def get_powergood_status(self): | ||||||
|  |         return self._get_psuutil().get_psu_status(self._index) | ||||||
| @@ -0,0 +1,102 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
|  | from __future__ import print_function | ||||||
|  |  | ||||||
|  | import imp | ||||||
|  | import os | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_platform_base.sfp_base import SfpBase | ||||||
|  |     from sonic_py_common import device_info | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError("%s - required module not found" % e) | ||||||
|  |  | ||||||
|  | USR_SHARE_SONIC_PATH = "/usr/share/sonic" | ||||||
|  | HOST_DEVICE_PATH = USR_SHARE_SONIC_PATH + "/device" | ||||||
|  | CONTAINER_PLATFORM_PATH = USR_SHARE_SONIC_PATH + "/platform" | ||||||
|  |  | ||||||
|  | class Sfp(SfpBase): | ||||||
|  |     """ | ||||||
|  |     Platform-specific sfp class | ||||||
|  |  | ||||||
|  |     Unimplemented methods: | ||||||
|  |     - get_model | ||||||
|  |     - get_serial | ||||||
|  |     - get_status | ||||||
|  |     - get_transceiver_info | ||||||
|  |     - get_transceiver_bulk_status | ||||||
|  |     - get_transceiver_threshold_info | ||||||
|  |     - get_reset_status | ||||||
|  |     - get_rx_los | ||||||
|  |     - get_tx_fault | ||||||
|  |     - get_tx_disable_channel | ||||||
|  |     - get_power_override | ||||||
|  |     - get_temperature | ||||||
|  |     - get_voltage | ||||||
|  |     - get_tx_bias | ||||||
|  |     - get_rx_power | ||||||
|  |     - get_tx_power | ||||||
|  |     - tx_disable_channel | ||||||
|  |     - set_power_override | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     def __init__(self, index): | ||||||
|  |         self._index = index | ||||||
|  |          | ||||||
|  |         if os.path.isdir(CONTAINER_PLATFORM_PATH): | ||||||
|  |             platform_path = CONTAINER_PLATFORM_PATH | ||||||
|  |         else: | ||||||
|  |             platform = device_info.get_platform() | ||||||
|  |             if platform is None: | ||||||
|  |                 return | ||||||
|  |             platform_path = os.path.join(HOST_DEVICE_PATH, platform) | ||||||
|  |  | ||||||
|  |         module_file = "/".join([platform_path, "plugins", "sfputil.py"]) | ||||||
|  |         module = imp.load_source("sfputil", module_file) | ||||||
|  |         sfp_util_class = getattr(module, "SfpUtil") | ||||||
|  |         self._sfputil = sfp_util_class() | ||||||
|  |  | ||||||
|  |     def get_id(self): | ||||||
|  |         return self._index | ||||||
|  |  | ||||||
|  |     def get_name(self): | ||||||
|  |         return "Ethernet{}".format(self._index) | ||||||
|  |  | ||||||
|  |     def get_lpmode(self): | ||||||
|  |         return False | ||||||
|  |  | ||||||
|  |     def set_lpmode(self, lpmode): | ||||||
|  |         return False | ||||||
|  |  | ||||||
|  |     def get_tx_disable(self): | ||||||
|  |         return False | ||||||
|  |  | ||||||
|  |     def tx_disable(self, tx_disable): | ||||||
|  |          return False | ||||||
|  |  | ||||||
|  |     def reset(self): | ||||||
|  |             pass | ||||||
|  |  | ||||||
|  |     def clear_interrupt(self): | ||||||
|  |         return False | ||||||
|  |  | ||||||
|  |     def get_interrupt_file(self): | ||||||
|  |         return None | ||||||
|  |  | ||||||
|  |     def _get_sfputil(self): | ||||||
|  |         return self._sfputil | ||||||
|  |  | ||||||
|  |     def get_presence(self): | ||||||
|  |         return self._get_sfputil().get_presence(self._index) | ||||||
|  |  | ||||||
|  |     def get_transceiver_info(self): | ||||||
|  |         return self._get_sfputil().get_transceiver_info_dict(self._index) | ||||||
|  |  | ||||||
|  |     def get_transceiver_bulk_status(self): | ||||||
|  |         return self._get_sfputil().get_transceiver_dom_info_dict(self._index) | ||||||
|  |  | ||||||
|  |     def get_transceiver_threshold_info(self): | ||||||
|  |         return self._get_sfputil().get_transceiver_dom_threshold_info_dict(self._index) | ||||||
|  |  | ||||||
|  |     def get_transceiver_change_event(self, timeout): | ||||||
|  |         return self._get_sfputil().get_transceiver_change_event(timeout) | ||||||
| @@ -0,0 +1,118 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | # Celestica | ||||||
|  | # | ||||||
|  | # Thermal contains an implementation of SONiC Platform Base API and | ||||||
|  | # provides the thermal device status which are available in the platform | ||||||
|  | # | ||||||
|  | ############################################################################# | ||||||
|  |  | ||||||
|  | import os | ||||||
|  | import os.path | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_platform_base.thermal_base import ThermalBase | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError(str(e) + "- required module not found") | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Thermal(ThermalBase): | ||||||
|  |     """Platform-specific Thermal class""" | ||||||
|  |  | ||||||
|  |     THERMAL_NAME_LIST = [] | ||||||
|  |     CPUBOARD_SS_PATH = "/sys/class/hwmon/hwmon1" | ||||||
|  |  | ||||||
|  |     def __init__(self, thermal_index): | ||||||
|  |         self.index = thermal_index | ||||||
|  |         self.high_threshold = float(112) | ||||||
|  |  | ||||||
|  |         # Add thermal name | ||||||
|  |         self.THERMAL_NAME_LIST.append("SENSOR-1") | ||||||
|  |  | ||||||
|  |         # Set hwmon path | ||||||
|  |         self.ss_index, self.hwmon_path = 1, self.CPUBOARD_SS_PATH | ||||||
|  |         self.ss_key = self.THERMAL_NAME_LIST[self.index - 1] | ||||||
|  |  | ||||||
|  |     def __read_txt_file(self, file_path): | ||||||
|  |         try: | ||||||
|  |             with open(file_path, 'r') as fd: | ||||||
|  |                 data = fd.read() | ||||||
|  |                 return data.strip() | ||||||
|  |         except IOError: | ||||||
|  |             raise IOError("Unable to open %s file !" % file_path) | ||||||
|  |  | ||||||
|  |     def __get_temp(self, temp_file): | ||||||
|  |         temp_file_path = os.path.join(self.hwmon_path, temp_file) | ||||||
|  |         raw_temp = self.__read_txt_file(temp_file_path) | ||||||
|  |         temp = float(raw_temp)/1000 | ||||||
|  |         return float("{:.3f}".format(temp)) | ||||||
|  |  | ||||||
|  |     def __set_threshold(self, file_name, temperature): | ||||||
|  |         temp_file_path = os.path.join(self.hwmon_path, file_name) | ||||||
|  |         try: | ||||||
|  |             with open(temp_file_path, 'w') as fd: | ||||||
|  |                 fd.write(str(temperature)) | ||||||
|  |             return True | ||||||
|  |         except IOError: | ||||||
|  |             return False | ||||||
|  |  | ||||||
|  |     def get_temperature(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves current temperature reading from thermal | ||||||
|  |         Returns: | ||||||
|  |             A float number of current temperature in Celsius up to nearest thousandth | ||||||
|  |             of one degree Celsius, e.g. 30.125 | ||||||
|  |         """ | ||||||
|  |         temp_file = "temp{}_input".format(self.ss_index) | ||||||
|  |         return self.__get_temp(temp_file) | ||||||
|  |  | ||||||
|  |     def get_high_threshold(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the high threshold temperature of thermal | ||||||
|  |         Returns: | ||||||
|  |             A float number, the high threshold temperature of thermal in Celsius | ||||||
|  |             up to nearest thousandth of one degree Celsius, e.g. 30.125 | ||||||
|  |         """ | ||||||
|  |         return self.high_threshold | ||||||
|  |  | ||||||
|  |     def set_high_threshold(self, temperature): | ||||||
|  |         """ | ||||||
|  |         Sets the high threshold temperature of thermal | ||||||
|  |         Args : | ||||||
|  |             temperature: A float number up to nearest thousandth of one degree Celsius, | ||||||
|  |             e.g. 30.125 | ||||||
|  |         Returns: | ||||||
|  |             A boolean, True if threshold is set successfully, False if not | ||||||
|  |         """ | ||||||
|  |         self.high_threshold = float(temperature) | ||||||
|  |         return True | ||||||
|  |  | ||||||
|  |     def get_name(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the name of the thermal device | ||||||
|  |             Returns: | ||||||
|  |             string: The name of the thermal device | ||||||
|  |         """ | ||||||
|  |         return self.THERMAL_NAME_LIST[self.index] | ||||||
|  |  | ||||||
|  |     def get_presence(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the presence of the PSU | ||||||
|  |         Returns: | ||||||
|  |             bool: True if PSU is present, False if not | ||||||
|  |         """ | ||||||
|  |         temp_file = "temp{}_input".format(self.ss_index) | ||||||
|  |         temp_file_path = os.path.join(self.hwmon_path, temp_file) | ||||||
|  |         return os.path.isfile(temp_file_path) | ||||||
|  |  | ||||||
|  |     def get_status(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the operational status of the device | ||||||
|  |         Returns: | ||||||
|  |             A boolean value, True if device is operating properly, False if not | ||||||
|  |         """ | ||||||
|  |         if not self.get_presence(): | ||||||
|  |             return False | ||||||
|  |  | ||||||
|  |         return True | ||||||
| @@ -0,0 +1 @@ | |||||||
|  | obj-m := centec_e530_48s4x_platform.o | ||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | [Unit] | ||||||
|  | Description=Centec modules init | ||||||
|  | After=local-fs.target | ||||||
|  | Before=syncd.service | ||||||
|  |  | ||||||
|  | [Service] | ||||||
|  | Type=oneshot | ||||||
|  | ExecStart=-/etc/init.d/platform-modules-e530-48s4x start | ||||||
|  | ExecStop=-/etc/init.d/platform-modules-e530-48s4x stop | ||||||
|  | RemainAfterExit=yes | ||||||
|  |  | ||||||
|  | [Install] | ||||||
|  | WantedBy=multi-user.target | ||||||
| @@ -0,0 +1,15 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
|  | import os | ||||||
|  | from setuptools import setup | ||||||
|  | os.listdir | ||||||
|  |  | ||||||
|  | setup( | ||||||
|  |    name='sonic_platform', | ||||||
|  |    version='1.0', | ||||||
|  |    description='Module to initialize centec e530-48s4x platforms', | ||||||
|  |     | ||||||
|  |    packages=['sonic_platform'], | ||||||
|  |    package_dir={'sonic_platform': 'sonic_platform'}, | ||||||
|  | ) | ||||||
|  |  | ||||||
| @@ -0,0 +1,3 @@ | |||||||
|  | __all__ = ["platform", "chassis", "sfp", "eeprom", "psu", "thermal", "fan", "fan_drawer"] | ||||||
|  | from . import platform | ||||||
|  |  | ||||||
| @@ -0,0 +1,173 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  | # | ||||||
|  | # Name: chassis.py, version: 1.0 | ||||||
|  | # | ||||||
|  | # Description: Module contains the definitions of SONiC platform APIs  | ||||||
|  | # | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_platform_base.chassis_base import ChassisBase | ||||||
|  |     from sonic_platform.eeprom import Eeprom | ||||||
|  |     from .fan_drawer import FanDrawer | ||||||
|  |     from .thermal import Thermal | ||||||
|  |     from .sfp import Sfp | ||||||
|  |     from .psu import Psu | ||||||
|  |  | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError(str(e) + "- required module not found") | ||||||
|  |  | ||||||
|  | NUM_FAN_TRAY = 1 | ||||||
|  | NUM_THERMAL = 1 | ||||||
|  | NUM_PORT    = 52 | ||||||
|  | NUM_PSU = 2 | ||||||
|  |  | ||||||
|  | class Chassis(ChassisBase): | ||||||
|  |  | ||||||
|  |     def __init__(self): | ||||||
|  |         ChassisBase.__init__(self) | ||||||
|  |         # Initialize EEPROM | ||||||
|  |         self._eeprom = Eeprom() | ||||||
|  |         # Initialize FAN | ||||||
|  |         for i in range(NUM_FAN_TRAY): | ||||||
|  |             fandrawer = FanDrawer(i) | ||||||
|  |             self._fan_drawer_list.append(fandrawer) | ||||||
|  |             self._fan_list.extend(fandrawer._fan_list) | ||||||
|  |         # Initialize THERMAL | ||||||
|  |         for index in range(0, NUM_THERMAL): | ||||||
|  |             thermal = Thermal(index) | ||||||
|  |             self._thermal_list.append(thermal) | ||||||
|  |         # Initialize SFP | ||||||
|  |         for index in range(0, NUM_PORT): | ||||||
|  |             sfp = Sfp(index) | ||||||
|  |             self._sfp_list.append(sfp) | ||||||
|  |         # Initialize PSU | ||||||
|  |         for index in range(0, NUM_PSU): | ||||||
|  |             psu = Psu(index + 1) | ||||||
|  |             self._psu_list.append(psu) | ||||||
|  |             | ||||||
|  | ############################################## | ||||||
|  | # Device methods | ||||||
|  | ############################################## | ||||||
|  |  | ||||||
|  |     def get_name(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the name of the chassis | ||||||
|  |         Returns: | ||||||
|  |             string: The name of the chassis | ||||||
|  |         """ | ||||||
|  |         return self._eeprom.modelstr() | ||||||
|  |  | ||||||
|  |     def get_presence(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the presence of the chassis | ||||||
|  |         Returns: | ||||||
|  |             bool: True if chassis is present, False if not | ||||||
|  |         """ | ||||||
|  |         return True | ||||||
|  |  | ||||||
|  |     def get_model(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the model number (or part number) of the chassis | ||||||
|  |         Returns: | ||||||
|  |             string: Model/part number of chassis | ||||||
|  |         """ | ||||||
|  |         return self._eeprom.part_number_str() | ||||||
|  |  | ||||||
|  |     def get_serial(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the serial number of the chassis | ||||||
|  |         Returns: | ||||||
|  |             string: Serial number of chassis | ||||||
|  |         """ | ||||||
|  |         return self._eeprom.serial_number_str() | ||||||
|  |  | ||||||
|  |     def get_status(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the operational status of the chassis | ||||||
|  |         Returns: | ||||||
|  |             bool: A boolean value, True if chassis is operating properly | ||||||
|  |             False if not | ||||||
|  |         """ | ||||||
|  |         return True | ||||||
|  |  | ||||||
|  | ############################################## | ||||||
|  | # Chassis methods | ||||||
|  | ############################################## | ||||||
|  |  | ||||||
|  |     def get_base_mac(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the base MAC address for the chassis | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             A string containing the MAC address in the format | ||||||
|  |             'XX:XX:XX:XX:XX:XX' | ||||||
|  |         """ | ||||||
|  |         return self._eeprom.base_mac_addr() | ||||||
|  |  | ||||||
|  |     def get_serial_number(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the hardware serial number for the chassis | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             A string containing the hardware serial number for this chassis. | ||||||
|  |         """ | ||||||
|  |         return self._eeprom.serial_number_str() | ||||||
|  |  | ||||||
|  |     def get_system_eeprom_info(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the full content of system EEPROM information for the chassis | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             A dictionary where keys are the type code defined in | ||||||
|  |             OCP ONIE TlvInfo EEPROM format and values are their corresponding | ||||||
|  |             values. | ||||||
|  |             Ex. { '0x21':'AG9064', '0x22':'V1.0', '0x23':'AG9064-0109867821', | ||||||
|  |                   '0x24':'001c0f000fcd0a', '0x25':'02/03/2018 16:22:00', | ||||||
|  |                   '0x26':'01', '0x27':'REV01', '0x28':'AG9064-C2358-16G'} | ||||||
|  |         """ | ||||||
|  |         return self._eeprom.system_eeprom_info() | ||||||
|  |  | ||||||
|  |     def get_reboot_cause(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the cause of the previous reboot | ||||||
|  |         Returns: | ||||||
|  |             A tuple (string, string) where the first element is a string | ||||||
|  |             containing the cause of the previous reboot. This string must be | ||||||
|  |             one of the predefined strings in this class. If the first string | ||||||
|  |             is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used | ||||||
|  |             to pass a description of the reboot cause. | ||||||
|  |         """ | ||||||
|  |         return (None, None) | ||||||
|  |  | ||||||
|  |     def get_change_event(self, timeout=2000): | ||||||
|  |         """ | ||||||
|  |         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. | ||||||
|  |         """ | ||||||
|  |         ret, port_dict = self._sfp_list[0].get_transceiver_change_event(timeout) | ||||||
|  |         ret_dict = {"sfp": port_dict} | ||||||
|  |         return ret, ret_dict | ||||||
|  |  | ||||||
|  |     def get_num_psus(self): | ||||||
|  |         return len(self._psu_list) | ||||||
|  |  | ||||||
|  |     def get_psu(self, psu_index): | ||||||
|  |         return self._psu_list[psu_index] | ||||||
| @@ -0,0 +1,111 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  | # | ||||||
|  | # Name: eeprom.py, version: 1.0 | ||||||
|  | # | ||||||
|  | # Description: Module contains the definitions of SONiC platform APIs  | ||||||
|  | # | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_eeprom import eeprom_tlvinfo | ||||||
|  |     import binascii | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError(str(e) + "- required module not found") | ||||||
|  |  | ||||||
|  | class Eeprom(eeprom_tlvinfo.TlvInfoDecoder): | ||||||
|  |  | ||||||
|  |     def __init__(self): | ||||||
|  |         self.__eeprom_path = "/dev/mtd3" | ||||||
|  |         super(Eeprom, self).__init__(self.__eeprom_path, 0, '', True) | ||||||
|  |         self.__eeprom_tlv_dict = dict() | ||||||
|  |         try: | ||||||
|  |             self.open_eeprom() | ||||||
|  |             self.__eeprom_data = self.read_eeprom() | ||||||
|  |         except: | ||||||
|  |             self.__eeprom_data = "N/A" | ||||||
|  |             raise RuntimeError("Eeprom is not Programmed") | ||||||
|  |         else: | ||||||
|  |             eeprom = self.__eeprom_data | ||||||
|  |  | ||||||
|  |             if not self.is_valid_tlvinfo_header(eeprom): | ||||||
|  |                 return | ||||||
|  |  | ||||||
|  |             total_length = (eeprom[9] << 8) | eeprom[10] | ||||||
|  |             tlv_index = self._TLV_INFO_HDR_LEN | ||||||
|  |             tlv_end = self._TLV_INFO_HDR_LEN + total_length | ||||||
|  |  | ||||||
|  |             while (tlv_index + 2) < len(eeprom) and tlv_index < tlv_end: | ||||||
|  |                 if not self.is_valid_tlv(eeprom[tlv_index:]): | ||||||
|  |                     break | ||||||
|  |  | ||||||
|  |                 tlv = eeprom[tlv_index:tlv_index + 2 | ||||||
|  |                              + eeprom[tlv_index + 1]] | ||||||
|  |                 code = "0x%02X" % (tlv[0]) | ||||||
|  |  | ||||||
|  |                 if tlv[0] == self._TLV_CODE_VENDOR_EXT: | ||||||
|  |                     value = str((tlv[2] << 24) | (tlv[3] << 16) | | ||||||
|  |                                 (tlv[4] << 8) | tlv[5]) | ||||||
|  |                     value += str(tlv[6:6 + tlv[1]]) | ||||||
|  |                 else: | ||||||
|  |                     name, value = self.decoder(None, tlv) | ||||||
|  |  | ||||||
|  |                 self.__eeprom_tlv_dict[code] = value | ||||||
|  |                 if eeprom[tlv_index] == self._TLV_CODE_CRC_32: | ||||||
|  |                     break | ||||||
|  |  | ||||||
|  |                 tlv_index += eeprom[tlv_index+1] + 2 | ||||||
|  |  | ||||||
|  |     def serial_number_str(self): | ||||||
|  |         (is_valid, results) = self.get_tlv_field( | ||||||
|  |                          self.__eeprom_data, self._TLV_CODE_SERIAL_NUMBER) | ||||||
|  |         if not is_valid: | ||||||
|  |             return "N/A" | ||||||
|  |         return results[2].decode('ascii') | ||||||
|  |  | ||||||
|  |     def base_mac_addr(self): | ||||||
|  |         (is_valid, t) = self.get_tlv_field( | ||||||
|  |                           self.__eeprom_data, self._TLV_CODE_MAC_BASE) | ||||||
|  |         if not is_valid or t[1] != 6: | ||||||
|  |             return super(TlvInfoDecoder, self).switchaddrstr(e) | ||||||
|  |  | ||||||
|  |         return ":".join([binascii.b2a_hex(T) for T in t[2]]) | ||||||
|  |  | ||||||
|  |     def modelstr(self): | ||||||
|  |         (is_valid, results) = self.get_tlv_field( | ||||||
|  |                         self.__eeprom_data, self._TLV_CODE_PRODUCT_NAME) | ||||||
|  |         if not is_valid: | ||||||
|  |             return "N/A" | ||||||
|  |  | ||||||
|  |         return results[2].decode('ascii') | ||||||
|  |  | ||||||
|  |     def part_number_str(self): | ||||||
|  |         (is_valid, results) = self.get_tlv_field( | ||||||
|  |                     self.__eeprom_data, self._TLV_CODE_PART_NUMBER) | ||||||
|  |         if not is_valid: | ||||||
|  |             return "N/A" | ||||||
|  |  | ||||||
|  |         return results[2].decode('ascii') | ||||||
|  |  | ||||||
|  |     def serial_tag_str(self): | ||||||
|  |         (is_valid, results) = self.get_tlv_field( | ||||||
|  |                     self.__eeprom_data, self._TLV_CODE_SERVICE_TAG) | ||||||
|  |         if not is_valid: | ||||||
|  |             return "N/A" | ||||||
|  |  | ||||||
|  |         return results[2].decode('ascii') | ||||||
|  |  | ||||||
|  |     def revision_str(self): | ||||||
|  |         (is_valid, results) = self.get_tlv_field( | ||||||
|  |                     self.__eeprom_data, self._TLV_CODE_DEVICE_VERSION) | ||||||
|  |         if not is_valid: | ||||||
|  |             return "N/A" | ||||||
|  |  | ||||||
|  |         return results[2].decode('ascii') | ||||||
|  |  | ||||||
|  |     def system_eeprom_info(self): | ||||||
|  |         """ | ||||||
|  |         Returns a dictionary, where keys are the type code defined in | ||||||
|  |         ONIE EEPROM format and values are their corresponding values | ||||||
|  |         found in the system EEPROM. | ||||||
|  |         """ | ||||||
|  |         return self.__eeprom_tlv_dict | ||||||
|  |  | ||||||
| @@ -0,0 +1,186 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | # Celestica | ||||||
|  | # | ||||||
|  | # Module contains an implementation of SONiC Platform Base API and | ||||||
|  | # provides the fan status which are available in the platform | ||||||
|  | # | ||||||
|  | ############################################################################# | ||||||
|  |  | ||||||
|  | import math | ||||||
|  | import os.path | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_platform_base.fan_base import FanBase | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError(str(e) + "- required module not found") | ||||||
|  |  | ||||||
|  | FAN_PATH = "/sys/class/hwmon/hwmon1/" | ||||||
|  | FAN_MAX_PWM = 255 | ||||||
|  | FAN_FAN_PWM = "pwm{}" | ||||||
|  | FAN_FAN_INPUT = "fan{}_input" | ||||||
|  | FAN_MAX_RPM = 9000 | ||||||
|  | FAN_NAME_LIST = ["FAN-1", "FAN-2", "FAN-3", "FAN-4"] | ||||||
|  |  | ||||||
|  | class Fan(FanBase): | ||||||
|  |     """Platform-specific Fan class""" | ||||||
|  |  | ||||||
|  |     def __init__(self, fan_tray_index, fan_index=0): | ||||||
|  |         self.fan_index = fan_index | ||||||
|  |         self.fan_tray_index = fan_tray_index | ||||||
|  |  | ||||||
|  |         FanBase.__init__(self) | ||||||
|  |  | ||||||
|  |     def __read_txt_file(self, file_path): | ||||||
|  |         try: | ||||||
|  |             with open(file_path, 'r') as fd: | ||||||
|  |                 data = fd.read() | ||||||
|  |                 return data.strip() | ||||||
|  |         except IOError: | ||||||
|  |             pass | ||||||
|  |         return "" | ||||||
|  |  | ||||||
|  |     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 __search_file_by_name(self, directory, file_name): | ||||||
|  |         for dirpath, dirnames, files in os.walk(directory): | ||||||
|  |             for name in files: | ||||||
|  |                 file_path = os.path.join(dirpath, name) | ||||||
|  |                 if name in file_name: | ||||||
|  |                     return file_path | ||||||
|  |         return None | ||||||
|  |  | ||||||
|  |     def get_direction(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the direction of fan | ||||||
|  |         Returns: | ||||||
|  |             A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST | ||||||
|  |             depending on fan direction | ||||||
|  |         """ | ||||||
|  |         direction = self.FAN_DIRECTION_EXHAUST | ||||||
|  |         return direction | ||||||
|  |  | ||||||
|  |     def get_speed(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the speed of fan as a percentage of full speed | ||||||
|  |         Returns: | ||||||
|  |             An integer, the percentage of full fan speed, in the range 0 (off) | ||||||
|  |                  to 100 (full speed) | ||||||
|  |  | ||||||
|  |         Note: | ||||||
|  |             speed = pwm_in/255*100 | ||||||
|  |         """ | ||||||
|  |         speed = 0 | ||||||
|  |         fan_speed_sysfs_name = "fan{}_input".format(self.fan_index+1) | ||||||
|  |         fan_speed_sysfs_path = self.__search_file_by_name( | ||||||
|  |             FAN_PATH, fan_speed_sysfs_name) | ||||||
|  |         fan_speed_rpm = self.__read_txt_file(fan_speed_sysfs_path) or 0 | ||||||
|  |         speed = math.ceil(float(fan_speed_rpm) * 100 / FAN_MAX_RPM) | ||||||
|  |  | ||||||
|  |         return int(speed) | ||||||
|  |  | ||||||
|  |     def get_target_speed(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the target (expected) speed of the fan | ||||||
|  |         Returns: | ||||||
|  |             An integer, the percentage of full fan speed, in the range 0 (off) | ||||||
|  |                  to 100 (full speed) | ||||||
|  |  | ||||||
|  |         Note: | ||||||
|  |             speed_pc = pwm_target/255*100 | ||||||
|  |  | ||||||
|  |             0   : when PWM mode is use | ||||||
|  |             pwm : when pwm mode is not use | ||||||
|  |         """ | ||||||
|  |         # target = 0 | ||||||
|  |         # fan_target_sysfs_name = "pwm{}".format(self.fan_index+1) | ||||||
|  |         # fan_target_sysfs_path = self.__search_file_by_name( | ||||||
|  |         #     FAN_PATH, fan_target_sysfs_name) | ||||||
|  |         # fan_target_pwm = self.__read_txt_file(fan_target_sysfs_path) or 0 | ||||||
|  |         # target = math.ceil(float(fan_target_pwm) * 100 / FAN_MAX_PWM) | ||||||
|  |  | ||||||
|  |         # return target | ||||||
|  |         speed = 0 | ||||||
|  |         fan_speed_sysfs_name = "fan{}_input".format(self.fan_index+1) | ||||||
|  |         fan_speed_sysfs_path = self.__search_file_by_name( | ||||||
|  |             FAN_PATH, fan_speed_sysfs_name) | ||||||
|  |         fan_speed_rpm = self.__read_txt_file(fan_speed_sysfs_path) or 0 | ||||||
|  |         speed = math.ceil(float(fan_speed_rpm) * 100 / FAN_MAX_RPM) | ||||||
|  |  | ||||||
|  |         return speed | ||||||
|  |  | ||||||
|  |     def get_speed_tolerance(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the speed tolerance of the fan | ||||||
|  |         Returns: | ||||||
|  |             An integer, the percentage of variance from target speed which is | ||||||
|  |                  considered tolerable | ||||||
|  |         """ | ||||||
|  |         return 10 | ||||||
|  |  | ||||||
|  |     def set_speed(self, speed): | ||||||
|  |         """ | ||||||
|  |         Sets the fan speed | ||||||
|  |         Args: | ||||||
|  |             speed: An integer, the percentage of full fan speed to set fan to, | ||||||
|  |                    in the range 0 (off) to 100 (full speed) | ||||||
|  |         Returns: | ||||||
|  |             A boolean, True if speed is set successfully, False if not | ||||||
|  |  | ||||||
|  |         Note: | ||||||
|  |             Depends on pwm or target mode is selected: | ||||||
|  |             1) pwm = speed_pc * 255             <-- Currently use this mode. | ||||||
|  |             2) target_pwm = speed_pc * 100 / 255 | ||||||
|  |              2.1) set pwm{}_enable to 3 | ||||||
|  |  | ||||||
|  |         """ | ||||||
|  |         pwm = speed * 255 / 100 | ||||||
|  |         fan_target_sysfs_name = "pwm{}".format(self.fan_index+1) | ||||||
|  |         fan_target_sysfs_path = self.__search_file_by_name( | ||||||
|  |             FAN_PATH, fan_target_sysfs_name) | ||||||
|  |         return self.__write_txt_file(fan_target_sysfs_path, int(pwm)) | ||||||
|  |  | ||||||
|  |     def set_status_led(self, color): | ||||||
|  |         """ | ||||||
|  |         Sets the state of the fan module status LED | ||||||
|  |         Args: | ||||||
|  |             color: A string representing the color with which to set the | ||||||
|  |                    fan module status LED | ||||||
|  |         Returns: | ||||||
|  |             bool: always True | ||||||
|  |         """ | ||||||
|  |         return True | ||||||
|  |  | ||||||
|  |     def get_name(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the name of the device | ||||||
|  |             Returns: | ||||||
|  |             string: The name of the device | ||||||
|  |         """ | ||||||
|  |         fan_name = FAN_NAME_LIST[self.fan_index] | ||||||
|  |  | ||||||
|  |         return fan_name | ||||||
|  |  | ||||||
|  |     def get_presence(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the presence of the FAN | ||||||
|  |         Returns: | ||||||
|  |             bool: always True | ||||||
|  |         """ | ||||||
|  |  | ||||||
|  |         return True | ||||||
|  |  | ||||||
|  |     def get_status(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the status of the FAN | ||||||
|  |         Returns: | ||||||
|  |             bool: always True | ||||||
|  |         """ | ||||||
|  |         return True | ||||||
| @@ -0,0 +1,36 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
|  | ######################################################################## | ||||||
|  | # Centec E530 48s4x | ||||||
|  | # | ||||||
|  | # Module contains an implementation of SONiC Platform Base API and | ||||||
|  | # provides the Fan-Drawers' information available in the platform. | ||||||
|  | # | ||||||
|  | ######################################################################## | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_platform_base.fan_drawer_base import FanDrawerBase | ||||||
|  |     from .fan import Fan | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError(str(e) + "- required module not found") | ||||||
|  |  | ||||||
|  | CENTEC_FANS_PER_FANTRAY = 4 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class FanDrawer(FanDrawerBase): | ||||||
|  |     """Centec E530 48s4x Platform-specific Fan class""" | ||||||
|  |  | ||||||
|  |     def __init__(self, fantray_index): | ||||||
|  |  | ||||||
|  |         FanDrawerBase.__init__(self) | ||||||
|  |         self.fantrayindex = fantray_index | ||||||
|  |         for i in range(CENTEC_FANS_PER_FANTRAY): | ||||||
|  |             self._fan_list.append(Fan(fantray_index, i)) | ||||||
|  |  | ||||||
|  |     def get_name(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the fan drawer name | ||||||
|  |         Returns: | ||||||
|  |             string: The name of the device | ||||||
|  |         """ | ||||||
|  |         return "FanTray{}".format(self.fantrayindex) | ||||||
| @@ -0,0 +1,21 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  | # | ||||||
|  | # Name: platform.py, version: 1.0 | ||||||
|  | # | ||||||
|  | # Description: Module contains the definitions of SONiC platform APIs for Centec E530-48S4X | ||||||
|  | # | ||||||
|  |  | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_platform_base.platform_base import PlatformBase | ||||||
|  |     from sonic_platform.chassis import Chassis | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError(str(e) + "- required module not found") | ||||||
|  |   | ||||||
|  |   | ||||||
|  | class Platform(PlatformBase): | ||||||
|  |  | ||||||
|  |     def __init__(self): | ||||||
|  |         PlatformBase.__init__(self) | ||||||
|  |         self._chassis = Chassis() | ||||||
|  |  | ||||||
| @@ -0,0 +1,45 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
|  | from __future__ import print_function | ||||||
|  |  | ||||||
|  | import imp | ||||||
|  | import os | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_platform_base.psu_base import PsuBase | ||||||
|  |     from sonic_py_common import device_info | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError("%s - required module not found" % e) | ||||||
|  |  | ||||||
|  | USR_SHARE_SONIC_PATH = "/usr/share/sonic" | ||||||
|  | HOST_DEVICE_PATH = USR_SHARE_SONIC_PATH + "/device" | ||||||
|  | CONTAINER_PLATFORM_PATH = USR_SHARE_SONIC_PATH + "/platform" | ||||||
|  |  | ||||||
|  | class Psu(PsuBase): | ||||||
|  |     """Centec Platform-specific PSU class""" | ||||||
|  |  | ||||||
|  |     def __init__(self, index): | ||||||
|  |         self._index = index | ||||||
|  |         self._fan_list = [] | ||||||
|  |          | ||||||
|  |         if os.path.isdir(CONTAINER_PLATFORM_PATH): | ||||||
|  |             platform_path = CONTAINER_PLATFORM_PATH | ||||||
|  |         else: | ||||||
|  |             platform = device_info.get_platform() | ||||||
|  |             if platform is None: | ||||||
|  |                 return | ||||||
|  |             platform_path = os.path.join(HOST_DEVICE_PATH, platform) | ||||||
|  |  | ||||||
|  |         module_file = "/".join([platform_path, "plugins", "psuutil.py"]) | ||||||
|  |         module = imp.load_source("psuutil", module_file) | ||||||
|  |         psu_util_class = getattr(module, "PsuUtil") | ||||||
|  |         self._psuutil = psu_util_class() | ||||||
|  |  | ||||||
|  |     def _get_psuutil(self): | ||||||
|  |         return self._psuutil | ||||||
|  |  | ||||||
|  |     def get_presence(self): | ||||||
|  |         return self._get_psuutil().get_psu_presence(self._index) | ||||||
|  |  | ||||||
|  |     def get_powergood_status(self): | ||||||
|  |         return self._get_psuutil().get_psu_status(self._index) | ||||||
| @@ -0,0 +1,102 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
|  | from __future__ import print_function | ||||||
|  |  | ||||||
|  | import imp | ||||||
|  | import os | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_platform_base.sfp_base import SfpBase | ||||||
|  |     from sonic_py_common import device_info | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError("%s - required module not found" % e) | ||||||
|  |  | ||||||
|  | USR_SHARE_SONIC_PATH = "/usr/share/sonic" | ||||||
|  | HOST_DEVICE_PATH = USR_SHARE_SONIC_PATH + "/device" | ||||||
|  | CONTAINER_PLATFORM_PATH = USR_SHARE_SONIC_PATH + "/platform" | ||||||
|  |  | ||||||
|  | class Sfp(SfpBase): | ||||||
|  |     """ | ||||||
|  |     Platform-specific sfp class | ||||||
|  |  | ||||||
|  |     Unimplemented methods: | ||||||
|  |     - get_model | ||||||
|  |     - get_serial | ||||||
|  |     - get_status | ||||||
|  |     - get_transceiver_info | ||||||
|  |     - get_transceiver_bulk_status | ||||||
|  |     - get_transceiver_threshold_info | ||||||
|  |     - get_reset_status | ||||||
|  |     - get_rx_los | ||||||
|  |     - get_tx_fault | ||||||
|  |     - get_tx_disable_channel | ||||||
|  |     - get_power_override | ||||||
|  |     - get_temperature | ||||||
|  |     - get_voltage | ||||||
|  |     - get_tx_bias | ||||||
|  |     - get_rx_power | ||||||
|  |     - get_tx_power | ||||||
|  |     - tx_disable_channel | ||||||
|  |     - set_power_override | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     def __init__(self, index): | ||||||
|  |         self._index = index | ||||||
|  |          | ||||||
|  |         if os.path.isdir(CONTAINER_PLATFORM_PATH): | ||||||
|  |             platform_path = CONTAINER_PLATFORM_PATH | ||||||
|  |         else: | ||||||
|  |             platform = device_info.get_platform() | ||||||
|  |             if platform is None: | ||||||
|  |                 return | ||||||
|  |             platform_path = os.path.join(HOST_DEVICE_PATH, platform) | ||||||
|  |  | ||||||
|  |         module_file = "/".join([platform_path, "plugins", "sfputil.py"]) | ||||||
|  |         module = imp.load_source("sfputil", module_file) | ||||||
|  |         sfp_util_class = getattr(module, "SfpUtil") | ||||||
|  |         self._sfputil = sfp_util_class() | ||||||
|  |  | ||||||
|  |     def get_id(self): | ||||||
|  |         return self._index | ||||||
|  |  | ||||||
|  |     def get_name(self): | ||||||
|  |         return "Ethernet{}".format(self._index) | ||||||
|  |  | ||||||
|  |     def get_lpmode(self): | ||||||
|  |         return False | ||||||
|  |  | ||||||
|  |     def set_lpmode(self, lpmode): | ||||||
|  |         return False | ||||||
|  |  | ||||||
|  |     def get_tx_disable(self): | ||||||
|  |         return False | ||||||
|  |  | ||||||
|  |     def tx_disable(self, tx_disable): | ||||||
|  |          return False | ||||||
|  |  | ||||||
|  |     def reset(self): | ||||||
|  |             pass | ||||||
|  |  | ||||||
|  |     def clear_interrupt(self): | ||||||
|  |         return False | ||||||
|  |  | ||||||
|  |     def get_interrupt_file(self): | ||||||
|  |         return None | ||||||
|  |  | ||||||
|  |     def _get_sfputil(self): | ||||||
|  |         return self._sfputil | ||||||
|  |  | ||||||
|  |     def get_presence(self): | ||||||
|  |         return self._get_sfputil().get_presence(self._index) | ||||||
|  |  | ||||||
|  |     def get_transceiver_info(self): | ||||||
|  |         return self._get_sfputil().get_transceiver_info_dict(self._index) | ||||||
|  |  | ||||||
|  |     def get_transceiver_bulk_status(self): | ||||||
|  |         return self._get_sfputil().get_transceiver_dom_info_dict(self._index) | ||||||
|  |  | ||||||
|  |     def get_transceiver_threshold_info(self): | ||||||
|  |         return self._get_sfputil().get_transceiver_dom_threshold_info_dict(self._index) | ||||||
|  |  | ||||||
|  |     def get_transceiver_change_event(self, timeout): | ||||||
|  |         return self._get_sfputil().get_transceiver_change_event(timeout) | ||||||
| @@ -0,0 +1,118 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | # Celestica | ||||||
|  | # | ||||||
|  | # Thermal contains an implementation of SONiC Platform Base API and | ||||||
|  | # provides the thermal device status which are available in the platform | ||||||
|  | # | ||||||
|  | ############################################################################# | ||||||
|  |  | ||||||
|  | import os | ||||||
|  | import os.path | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_platform_base.thermal_base import ThermalBase | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError(str(e) + "- required module not found") | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Thermal(ThermalBase): | ||||||
|  |     """Platform-specific Thermal class""" | ||||||
|  |  | ||||||
|  |     THERMAL_NAME_LIST = [] | ||||||
|  |     CPUBOARD_SS_PATH = "/sys/class/hwmon/hwmon1" | ||||||
|  |  | ||||||
|  |     def __init__(self, thermal_index): | ||||||
|  |         self.index = thermal_index | ||||||
|  |         self.high_threshold = float(112) | ||||||
|  |  | ||||||
|  |         # Add thermal name | ||||||
|  |         self.THERMAL_NAME_LIST.append("SENSOR-1") | ||||||
|  |  | ||||||
|  |         # Set hwmon path | ||||||
|  |         self.ss_index, self.hwmon_path = 1, self.CPUBOARD_SS_PATH | ||||||
|  |         self.ss_key = self.THERMAL_NAME_LIST[self.index - 1] | ||||||
|  |  | ||||||
|  |     def __read_txt_file(self, file_path): | ||||||
|  |         try: | ||||||
|  |             with open(file_path, 'r') as fd: | ||||||
|  |                 data = fd.read() | ||||||
|  |                 return data.strip() | ||||||
|  |         except IOError: | ||||||
|  |             raise IOError("Unable to open %s file !" % file_path) | ||||||
|  |  | ||||||
|  |     def __get_temp(self, temp_file): | ||||||
|  |         temp_file_path = os.path.join(self.hwmon_path, temp_file) | ||||||
|  |         raw_temp = self.__read_txt_file(temp_file_path) | ||||||
|  |         temp = float(raw_temp)/1000 | ||||||
|  |         return float("{:.3f}".format(temp)) | ||||||
|  |  | ||||||
|  |     def __set_threshold(self, file_name, temperature): | ||||||
|  |         temp_file_path = os.path.join(self.hwmon_path, file_name) | ||||||
|  |         try: | ||||||
|  |             with open(temp_file_path, 'w') as fd: | ||||||
|  |                 fd.write(str(temperature)) | ||||||
|  |             return True | ||||||
|  |         except IOError: | ||||||
|  |             return False | ||||||
|  |  | ||||||
|  |     def get_temperature(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves current temperature reading from thermal | ||||||
|  |         Returns: | ||||||
|  |             A float number of current temperature in Celsius up to nearest thousandth | ||||||
|  |             of one degree Celsius, e.g. 30.125 | ||||||
|  |         """ | ||||||
|  |         temp_file = "temp{}_input".format(self.ss_index) | ||||||
|  |         return self.__get_temp(temp_file) | ||||||
|  |  | ||||||
|  |     def get_high_threshold(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the high threshold temperature of thermal | ||||||
|  |         Returns: | ||||||
|  |             A float number, the high threshold temperature of thermal in Celsius | ||||||
|  |             up to nearest thousandth of one degree Celsius, e.g. 30.125 | ||||||
|  |         """ | ||||||
|  |         return self.high_threshold | ||||||
|  |  | ||||||
|  |     def set_high_threshold(self, temperature): | ||||||
|  |         """ | ||||||
|  |         Sets the high threshold temperature of thermal | ||||||
|  |         Args : | ||||||
|  |             temperature: A float number up to nearest thousandth of one degree Celsius, | ||||||
|  |             e.g. 30.125 | ||||||
|  |         Returns: | ||||||
|  |             A boolean, True if threshold is set successfully, False if not | ||||||
|  |         """ | ||||||
|  |         self.high_threshold = float(temperature) | ||||||
|  |         return True | ||||||
|  |  | ||||||
|  |     def get_name(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the name of the thermal device | ||||||
|  |             Returns: | ||||||
|  |             string: The name of the thermal device | ||||||
|  |         """ | ||||||
|  |         return self.THERMAL_NAME_LIST[self.index] | ||||||
|  |  | ||||||
|  |     def get_presence(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the presence of the PSU | ||||||
|  |         Returns: | ||||||
|  |             bool: True if PSU is present, False if not | ||||||
|  |         """ | ||||||
|  |         temp_file = "temp{}_input".format(self.ss_index) | ||||||
|  |         temp_file_path = os.path.join(self.hwmon_path, temp_file) | ||||||
|  |         return os.path.isfile(temp_file_path) | ||||||
|  |  | ||||||
|  |     def get_status(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the operational status of the device | ||||||
|  |         Returns: | ||||||
|  |             A boolean value, True if device is operating properly, False if not | ||||||
|  |         """ | ||||||
|  |         if not self.get_presence(): | ||||||
|  |             return False | ||||||
|  |  | ||||||
|  |         return True | ||||||
| @@ -8,16 +8,92 @@ | |||||||
| #include <linux/reboot.h> | #include <linux/reboot.h> | ||||||
| #include <linux/delay.h> | #include <linux/delay.h> | ||||||
| #include <linux/spinlock.h> | #include <linux/spinlock.h> | ||||||
|  | #include <linux/kernel.h> | ||||||
|  | #include <linux/sched.h> | ||||||
|  | #include <asm/irq.h> | ||||||
|  | #include <asm/types.h> | ||||||
|  | #include <asm/io.h> | ||||||
|  | #include <linux/poll.h> | ||||||
|  | #include <linux/wait.h> | ||||||
|  | #include <linux/pci.h> | ||||||
|  | #include <linux/interrupt.h> | ||||||
|  | #include <asm/delay.h> | ||||||
|  | #include <linux/err.h> | ||||||
|  | #include <linux/io.h> | ||||||
|  | #include <linux/of_address.h> | ||||||
|  | #include <linux/of_irq.h> | ||||||
|  | #include <linux/of.h> | ||||||
|  | #include <linux/of_device.h> | ||||||
|  | #include <linux/gpio.h> | ||||||
| 
 | 
 | ||||||
| #define SEP(XXX) 1 | #define SEP(XXX) 1 | ||||||
| #define IS_INVALID_PTR(_PTR_) ((_PTR_ == NULL) || IS_ERR(_PTR_)) |  | ||||||
| #define IS_VALID_PTR(_PTR_) (!IS_INVALID_PTR(_PTR_)) |  | ||||||
| 
 | 
 | ||||||
| #if SEP("defines") | #if SEP("defines") | ||||||
|  | 
 | ||||||
|  | #define CTC_GPIO_BASE         496 | ||||||
|  | int xirq_gpio_0 = 0; | ||||||
|  | int xirq_gpio_1 = 0; | ||||||
|  | int xirq_gpio_6 = 0;  /* add for E530_48S4X EPLD INT0*/ | ||||||
|  | int xirq_gpio_7 = 0;  /* add for E530_48S4X EPLD INT1*/ | ||||||
|  | int xirq_gpio_15 = 0; | ||||||
|  | #define IS_INVALID_PTR(_PTR_) ((_PTR_ == NULL) || IS_ERR(_PTR_)) | ||||||
|  | #define IS_VALID_PTR(_PTR_) (!IS_INVALID_PTR(_PTR_)) | ||||||
| #define SFP_NUM                 4 | #define SFP_NUM                 4 | ||||||
| #define PORT_NUM                (48+SFP_NUM) | #define PORT_NUM                (48+SFP_NUM) | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #if SEP("ctc:pinctl") | ||||||
|  | u8 ctc_gpio_set(u8 gpio_pin, u8 val) | ||||||
|  | { | ||||||
|  |     gpio_set_value_cansleep(gpio_pin + CTC_GPIO_BASE, val); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | u8 ctc_gpio_get(u8 gpio_pin) | ||||||
|  | { | ||||||
|  |     return gpio_get_value_cansleep(gpio_pin + CTC_GPIO_BASE); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | u8 ctc_gpio_direction_config(u8 gpio_pin, u8 dir,u8 default_out) | ||||||
|  | { | ||||||
|  |     return dir ? gpio_direction_input(gpio_pin + CTC_GPIO_BASE) | ||||||
|  |                : gpio_direction_output(gpio_pin + CTC_GPIO_BASE,default_out); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void ctc_pincrtl_init(void) | ||||||
|  | { | ||||||
|  |     /* configure mgmt-phy reset-pin output on product, mgmt-phy release must before this */ | ||||||
|  |     ctc_gpio_direction_config(4, 0, 1); | ||||||
|  |     /* configure power-up pin output on product */ | ||||||
|  |     ctc_gpio_direction_config(6, 0, 0); | ||||||
|  |     /* configure phy interrupt pin input */ | ||||||
|  |     ctc_gpio_direction_config(0, 1, 0); | ||||||
|  |     ctc_gpio_direction_config(1, 1, 0); | ||||||
|  |     /* configure phy reset-pin output, for release phy */ | ||||||
|  |     ctc_gpio_direction_config(5, 0, 1); | ||||||
|  | 
 | ||||||
|  |     return; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void ctc_irq_init(void) | ||||||
|  | { | ||||||
|  |     struct device_node *xnp; | ||||||
|  |     for_each_node_by_type(xnp, "ctc-irq") | ||||||
|  |     { | ||||||
|  |         if (of_device_is_compatible(xnp, "centec,ctc-irq")) | ||||||
|  |         { | ||||||
|  |             xirq_gpio_0 = irq_of_parse_and_map(xnp, 0); | ||||||
|  |             printk(KERN_INFO "ctc-irq GPIO0 IRQ is %d\n", xirq_gpio_0); | ||||||
|  |             xirq_gpio_1 = irq_of_parse_and_map(xnp, 1); | ||||||
|  |             printk(KERN_INFO "ctc-irq GPIO1 IRQ is %d\n", xirq_gpio_1); | ||||||
|  |             xirq_gpio_15 = irq_of_parse_and_map(xnp, 2); | ||||||
|  |             printk(KERN_INFO "ctc-irq GPIO15 IRQ is %d\n", xirq_gpio_15); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| #if SEP("i2c:smbus") | #if SEP("i2c:smbus") | ||||||
| static int e530_48t4x_p_smbus_read_reg(struct i2c_client *client, unsigned char reg, unsigned char* value) | static int e530_48t4x_p_smbus_read_reg(struct i2c_client *client, unsigned char reg, unsigned char* value) | ||||||
| { | { | ||||||
| @@ -966,6 +1042,9 @@ static int e530_48t4x_p_init(void) | |||||||
|     int failed = 0; |     int failed = 0; | ||||||
|      |      | ||||||
|     printk(KERN_ALERT "install e530_48t4x_p board dirver...\n"); |     printk(KERN_ALERT "install e530_48t4x_p board dirver...\n"); | ||||||
|  | 
 | ||||||
|  |     ctc_irq_init(); | ||||||
|  |     ctc_pincrtl_init(); | ||||||
|      |      | ||||||
|     ret = e530_48t4x_p_init_i2c_master(); |     ret = e530_48t4x_p_init_i2c_master(); | ||||||
|     if (ret != 0) |     if (ret != 0) | ||||||
| @@ -5,11 +5,11 @@ from setuptools import setup | |||||||
| os.listdir | os.listdir | ||||||
| 
 | 
 | ||||||
| setup( | setup( | ||||||
|    name='48t4x_p', |    name='sonic_platform', | ||||||
|    version='1.1', |    version='1.0', | ||||||
|    description='Module to initialize centec e530-48t4x-p platforms', |    description='Module to initialize centec e530-48t4x-p platforms', | ||||||
|     |     | ||||||
|    packages=['48t4x_p'], |    packages=['sonic_platform'], | ||||||
|    package_dir={'48t4x_p': '48t4x_p/classes'}, |    package_dir={'sonic_platform': 'sonic_platform'}, | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| @@ -0,0 +1,3 @@ | |||||||
|  | __all__ = ["platform", "chassis", "sfp", "eeprom", "psu", "thermal", "fan", "fan_drawer"] | ||||||
|  | from . import platform | ||||||
|  |  | ||||||
| @@ -0,0 +1,173 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  | # | ||||||
|  | # Name: chassis.py, version: 1.0 | ||||||
|  | # | ||||||
|  | # Description: Module contains the definitions of SONiC platform APIs  | ||||||
|  | # | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_platform_base.chassis_base import ChassisBase | ||||||
|  |     from sonic_platform.eeprom import Eeprom | ||||||
|  |     from .fan_drawer import FanDrawer | ||||||
|  |     from .thermal import Thermal | ||||||
|  |     from .sfp import Sfp | ||||||
|  |     from .psu import Psu | ||||||
|  |  | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError(str(e) + "- required module not found") | ||||||
|  |  | ||||||
|  | NUM_FAN_TRAY = 1 | ||||||
|  | NUM_THERMAL = 1 | ||||||
|  | NUM_PORT    = 52 | ||||||
|  | NUM_PSU = 2 | ||||||
|  |  | ||||||
|  | class Chassis(ChassisBase): | ||||||
|  |  | ||||||
|  |     def __init__(self): | ||||||
|  |         ChassisBase.__init__(self) | ||||||
|  |         # Initialize EEPROM | ||||||
|  |         self._eeprom = Eeprom() | ||||||
|  |         # Initialize FAN | ||||||
|  |         for i in range(NUM_FAN_TRAY): | ||||||
|  |             fandrawer = FanDrawer(i) | ||||||
|  |             self._fan_drawer_list.append(fandrawer) | ||||||
|  |             self._fan_list.extend(fandrawer._fan_list) | ||||||
|  |         # Initialize THERMAL | ||||||
|  |         for index in range(0, NUM_THERMAL): | ||||||
|  |             thermal = Thermal(index) | ||||||
|  |             self._thermal_list.append(thermal) | ||||||
|  |         # Initialize SFP | ||||||
|  |         for index in range(0, NUM_PORT): | ||||||
|  |             sfp = Sfp(index) | ||||||
|  |             self._sfp_list.append(sfp) | ||||||
|  |         # Initialize PSU | ||||||
|  |         for index in range(0, NUM_PSU): | ||||||
|  |             psu = Psu(index + 1) | ||||||
|  |             self._psu_list.append(psu) | ||||||
|  |             | ||||||
|  | ############################################## | ||||||
|  | # Device methods | ||||||
|  | ############################################## | ||||||
|  |  | ||||||
|  |     def get_name(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the name of the chassis | ||||||
|  |         Returns: | ||||||
|  |             string: The name of the chassis | ||||||
|  |         """ | ||||||
|  |         return self._eeprom.modelstr() | ||||||
|  |  | ||||||
|  |     def get_presence(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the presence of the chassis | ||||||
|  |         Returns: | ||||||
|  |             bool: True if chassis is present, False if not | ||||||
|  |         """ | ||||||
|  |         return True | ||||||
|  |  | ||||||
|  |     def get_model(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the model number (or part number) of the chassis | ||||||
|  |         Returns: | ||||||
|  |             string: Model/part number of chassis | ||||||
|  |         """ | ||||||
|  |         return self._eeprom.part_number_str() | ||||||
|  |  | ||||||
|  |     def get_serial(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the serial number of the chassis | ||||||
|  |         Returns: | ||||||
|  |             string: Serial number of chassis | ||||||
|  |         """ | ||||||
|  |         return self._eeprom.serial_number_str() | ||||||
|  |  | ||||||
|  |     def get_status(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the operational status of the chassis | ||||||
|  |         Returns: | ||||||
|  |             bool: A boolean value, True if chassis is operating properly | ||||||
|  |             False if not | ||||||
|  |         """ | ||||||
|  |         return True | ||||||
|  |  | ||||||
|  | ############################################## | ||||||
|  | # Chassis methods | ||||||
|  | ############################################## | ||||||
|  |  | ||||||
|  |     def get_base_mac(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the base MAC address for the chassis | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             A string containing the MAC address in the format | ||||||
|  |             'XX:XX:XX:XX:XX:XX' | ||||||
|  |         """ | ||||||
|  |         return self._eeprom.base_mac_addr() | ||||||
|  |  | ||||||
|  |     def get_serial_number(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the hardware serial number for the chassis | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             A string containing the hardware serial number for this chassis. | ||||||
|  |         """ | ||||||
|  |         return self._eeprom.serial_number_str() | ||||||
|  |  | ||||||
|  |     def get_system_eeprom_info(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the full content of system EEPROM information for the chassis | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             A dictionary where keys are the type code defined in | ||||||
|  |             OCP ONIE TlvInfo EEPROM format and values are their corresponding | ||||||
|  |             values. | ||||||
|  |             Ex. { '0x21':'AG9064', '0x22':'V1.0', '0x23':'AG9064-0109867821', | ||||||
|  |                   '0x24':'001c0f000fcd0a', '0x25':'02/03/2018 16:22:00', | ||||||
|  |                   '0x26':'01', '0x27':'REV01', '0x28':'AG9064-C2358-16G'} | ||||||
|  |         """ | ||||||
|  |         return self._eeprom.system_eeprom_info() | ||||||
|  |  | ||||||
|  |     def get_reboot_cause(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the cause of the previous reboot | ||||||
|  |         Returns: | ||||||
|  |             A tuple (string, string) where the first element is a string | ||||||
|  |             containing the cause of the previous reboot. This string must be | ||||||
|  |             one of the predefined strings in this class. If the first string | ||||||
|  |             is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used | ||||||
|  |             to pass a description of the reboot cause. | ||||||
|  |         """ | ||||||
|  |         return (None, None) | ||||||
|  |  | ||||||
|  |     def get_change_event(self, timeout=2000): | ||||||
|  |         """ | ||||||
|  |         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. | ||||||
|  |         """ | ||||||
|  |         ret, port_dict = self._sfp_list[0].get_transceiver_change_event(timeout) | ||||||
|  |         ret_dict = {"sfp": port_dict} | ||||||
|  |         return ret, ret_dict | ||||||
|  |  | ||||||
|  |     def get_num_psus(self): | ||||||
|  |         return len(self._psu_list) | ||||||
|  |  | ||||||
|  |     def get_psu(self, psu_index): | ||||||
|  |         return self._psu_list[psu_index] | ||||||
| @@ -0,0 +1,111 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  | # | ||||||
|  | # Name: eeprom.py, version: 1.0 | ||||||
|  | # | ||||||
|  | # Description: Module contains the definitions of SONiC platform APIs  | ||||||
|  | # | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_eeprom import eeprom_tlvinfo | ||||||
|  |     import binascii | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError(str(e) + "- required module not found") | ||||||
|  |  | ||||||
|  | class Eeprom(eeprom_tlvinfo.TlvInfoDecoder): | ||||||
|  |  | ||||||
|  |     def __init__(self): | ||||||
|  |         self.__eeprom_path = "/dev/mtd3" | ||||||
|  |         super(Eeprom, self).__init__(self.__eeprom_path, 0, '', True) | ||||||
|  |         self.__eeprom_tlv_dict = dict() | ||||||
|  |         try: | ||||||
|  |             self.open_eeprom() | ||||||
|  |             self.__eeprom_data = self.read_eeprom() | ||||||
|  |         except: | ||||||
|  |             self.__eeprom_data = "N/A" | ||||||
|  |             raise RuntimeError("Eeprom is not Programmed") | ||||||
|  |         else: | ||||||
|  |             eeprom = self.__eeprom_data | ||||||
|  |  | ||||||
|  |             if not self.is_valid_tlvinfo_header(eeprom): | ||||||
|  |                 return | ||||||
|  |  | ||||||
|  |             total_length = (eeprom[9] << 8) | eeprom[10] | ||||||
|  |             tlv_index = self._TLV_INFO_HDR_LEN | ||||||
|  |             tlv_end = self._TLV_INFO_HDR_LEN + total_length | ||||||
|  |  | ||||||
|  |             while (tlv_index + 2) < len(eeprom) and tlv_index < tlv_end: | ||||||
|  |                 if not self.is_valid_tlv(eeprom[tlv_index:]): | ||||||
|  |                     break | ||||||
|  |  | ||||||
|  |                 tlv = eeprom[tlv_index:tlv_index + 2 | ||||||
|  |                              + eeprom[tlv_index + 1]] | ||||||
|  |                 code = "0x%02X" % (tlv[0]) | ||||||
|  |  | ||||||
|  |                 if tlv[0] == self._TLV_CODE_VENDOR_EXT: | ||||||
|  |                     value = str((tlv[2] << 24) | (tlv[3] << 16) | | ||||||
|  |                                 (tlv[4] << 8) | tlv[5]) | ||||||
|  |                     value += str(tlv[6:6 + tlv[1]]) | ||||||
|  |                 else: | ||||||
|  |                     name, value = self.decoder(None, tlv) | ||||||
|  |  | ||||||
|  |                 self.__eeprom_tlv_dict[code] = value | ||||||
|  |                 if eeprom[tlv_index] == self._TLV_CODE_CRC_32: | ||||||
|  |                     break | ||||||
|  |  | ||||||
|  |                 tlv_index += eeprom[tlv_index+1] + 2 | ||||||
|  |  | ||||||
|  |     def serial_number_str(self): | ||||||
|  |         (is_valid, results) = self.get_tlv_field( | ||||||
|  |                          self.__eeprom_data, self._TLV_CODE_SERIAL_NUMBER) | ||||||
|  |         if not is_valid: | ||||||
|  |             return "N/A" | ||||||
|  |         return results[2].decode('ascii') | ||||||
|  |  | ||||||
|  |     def base_mac_addr(self): | ||||||
|  |         (is_valid, t) = self.get_tlv_field( | ||||||
|  |                           self.__eeprom_data, self._TLV_CODE_MAC_BASE) | ||||||
|  |         if not is_valid or t[1] != 6: | ||||||
|  |             return super(TlvInfoDecoder, self).switchaddrstr(e) | ||||||
|  |  | ||||||
|  |         return ":".join([binascii.b2a_hex(T) for T in t[2]]) | ||||||
|  |  | ||||||
|  |     def modelstr(self): | ||||||
|  |         (is_valid, results) = self.get_tlv_field( | ||||||
|  |                         self.__eeprom_data, self._TLV_CODE_PRODUCT_NAME) | ||||||
|  |         if not is_valid: | ||||||
|  |             return "N/A" | ||||||
|  |  | ||||||
|  |         return results[2].decode('ascii') | ||||||
|  |  | ||||||
|  |     def part_number_str(self): | ||||||
|  |         (is_valid, results) = self.get_tlv_field( | ||||||
|  |                     self.__eeprom_data, self._TLV_CODE_PART_NUMBER) | ||||||
|  |         if not is_valid: | ||||||
|  |             return "N/A" | ||||||
|  |  | ||||||
|  |         return results[2].decode('ascii') | ||||||
|  |  | ||||||
|  |     def serial_tag_str(self): | ||||||
|  |         (is_valid, results) = self.get_tlv_field( | ||||||
|  |                     self.__eeprom_data, self._TLV_CODE_SERVICE_TAG) | ||||||
|  |         if not is_valid: | ||||||
|  |             return "N/A" | ||||||
|  |  | ||||||
|  |         return results[2].decode('ascii') | ||||||
|  |  | ||||||
|  |     def revision_str(self): | ||||||
|  |         (is_valid, results) = self.get_tlv_field( | ||||||
|  |                     self.__eeprom_data, self._TLV_CODE_DEVICE_VERSION) | ||||||
|  |         if not is_valid: | ||||||
|  |             return "N/A" | ||||||
|  |  | ||||||
|  |         return results[2].decode('ascii') | ||||||
|  |  | ||||||
|  |     def system_eeprom_info(self): | ||||||
|  |         """ | ||||||
|  |         Returns a dictionary, where keys are the type code defined in | ||||||
|  |         ONIE EEPROM format and values are their corresponding values | ||||||
|  |         found in the system EEPROM. | ||||||
|  |         """ | ||||||
|  |         return self.__eeprom_tlv_dict | ||||||
|  |  | ||||||
| @@ -0,0 +1,186 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | # Celestica | ||||||
|  | # | ||||||
|  | # Module contains an implementation of SONiC Platform Base API and | ||||||
|  | # provides the fan status which are available in the platform | ||||||
|  | # | ||||||
|  | ############################################################################# | ||||||
|  |  | ||||||
|  | import math | ||||||
|  | import os.path | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_platform_base.fan_base import FanBase | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError(str(e) + "- required module not found") | ||||||
|  |  | ||||||
|  | FAN_PATH = "/sys/class/hwmon/hwmon1/" | ||||||
|  | FAN_MAX_PWM = 255 | ||||||
|  | FAN_FAN_PWM = "pwm{}" | ||||||
|  | FAN_FAN_INPUT = "fan{}_input" | ||||||
|  | FAN_MAX_RPM = 9000 | ||||||
|  | FAN_NAME_LIST = ["FAN-1", "FAN-2", "FAN-3", "FAN-4"] | ||||||
|  |  | ||||||
|  | class Fan(FanBase): | ||||||
|  |     """Platform-specific Fan class""" | ||||||
|  |  | ||||||
|  |     def __init__(self, fan_tray_index, fan_index=0): | ||||||
|  |         self.fan_index = fan_index | ||||||
|  |         self.fan_tray_index = fan_tray_index | ||||||
|  |  | ||||||
|  |         FanBase.__init__(self) | ||||||
|  |  | ||||||
|  |     def __read_txt_file(self, file_path): | ||||||
|  |         try: | ||||||
|  |             with open(file_path, 'r') as fd: | ||||||
|  |                 data = fd.read() | ||||||
|  |                 return data.strip() | ||||||
|  |         except IOError: | ||||||
|  |             pass | ||||||
|  |         return "" | ||||||
|  |  | ||||||
|  |     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 __search_file_by_name(self, directory, file_name): | ||||||
|  |         for dirpath, dirnames, files in os.walk(directory): | ||||||
|  |             for name in files: | ||||||
|  |                 file_path = os.path.join(dirpath, name) | ||||||
|  |                 if name in file_name: | ||||||
|  |                     return file_path | ||||||
|  |         return None | ||||||
|  |  | ||||||
|  |     def get_direction(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the direction of fan | ||||||
|  |         Returns: | ||||||
|  |             A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST | ||||||
|  |             depending on fan direction | ||||||
|  |         """ | ||||||
|  |         direction = self.FAN_DIRECTION_EXHAUST | ||||||
|  |         return direction | ||||||
|  |  | ||||||
|  |     def get_speed(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the speed of fan as a percentage of full speed | ||||||
|  |         Returns: | ||||||
|  |             An integer, the percentage of full fan speed, in the range 0 (off) | ||||||
|  |                  to 100 (full speed) | ||||||
|  |  | ||||||
|  |         Note: | ||||||
|  |             speed = pwm_in/255*100 | ||||||
|  |         """ | ||||||
|  |         speed = 0 | ||||||
|  |         fan_speed_sysfs_name = "fan{}_input".format(self.fan_index+1) | ||||||
|  |         fan_speed_sysfs_path = self.__search_file_by_name( | ||||||
|  |             FAN_PATH, fan_speed_sysfs_name) | ||||||
|  |         fan_speed_rpm = self.__read_txt_file(fan_speed_sysfs_path) or 0 | ||||||
|  |         speed = math.ceil(float(fan_speed_rpm) * 100 / FAN_MAX_RPM) | ||||||
|  |  | ||||||
|  |         return int(speed) | ||||||
|  |  | ||||||
|  |     def get_target_speed(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the target (expected) speed of the fan | ||||||
|  |         Returns: | ||||||
|  |             An integer, the percentage of full fan speed, in the range 0 (off) | ||||||
|  |                  to 100 (full speed) | ||||||
|  |  | ||||||
|  |         Note: | ||||||
|  |             speed_pc = pwm_target/255*100 | ||||||
|  |  | ||||||
|  |             0   : when PWM mode is use | ||||||
|  |             pwm : when pwm mode is not use | ||||||
|  |         """ | ||||||
|  |         # target = 0 | ||||||
|  |         # fan_target_sysfs_name = "pwm{}".format(self.fan_index+1) | ||||||
|  |         # fan_target_sysfs_path = self.__search_file_by_name( | ||||||
|  |         #     FAN_PATH, fan_target_sysfs_name) | ||||||
|  |         # fan_target_pwm = self.__read_txt_file(fan_target_sysfs_path) or 0 | ||||||
|  |         # target = math.ceil(float(fan_target_pwm) * 100 / FAN_MAX_PWM) | ||||||
|  |  | ||||||
|  |         # return target | ||||||
|  |         speed = 0 | ||||||
|  |         fan_speed_sysfs_name = "fan{}_input".format(self.fan_index+1) | ||||||
|  |         fan_speed_sysfs_path = self.__search_file_by_name( | ||||||
|  |             FAN_PATH, fan_speed_sysfs_name) | ||||||
|  |         fan_speed_rpm = self.__read_txt_file(fan_speed_sysfs_path) or 0 | ||||||
|  |         speed = math.ceil(float(fan_speed_rpm) * 100 / FAN_MAX_RPM) | ||||||
|  |  | ||||||
|  |         return speed | ||||||
|  |  | ||||||
|  |     def get_speed_tolerance(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the speed tolerance of the fan | ||||||
|  |         Returns: | ||||||
|  |             An integer, the percentage of variance from target speed which is | ||||||
|  |                  considered tolerable | ||||||
|  |         """ | ||||||
|  |         return 10 | ||||||
|  |  | ||||||
|  |     def set_speed(self, speed): | ||||||
|  |         """ | ||||||
|  |         Sets the fan speed | ||||||
|  |         Args: | ||||||
|  |             speed: An integer, the percentage of full fan speed to set fan to, | ||||||
|  |                    in the range 0 (off) to 100 (full speed) | ||||||
|  |         Returns: | ||||||
|  |             A boolean, True if speed is set successfully, False if not | ||||||
|  |  | ||||||
|  |         Note: | ||||||
|  |             Depends on pwm or target mode is selected: | ||||||
|  |             1) pwm = speed_pc * 255             <-- Currently use this mode. | ||||||
|  |             2) target_pwm = speed_pc * 100 / 255 | ||||||
|  |              2.1) set pwm{}_enable to 3 | ||||||
|  |  | ||||||
|  |         """ | ||||||
|  |         pwm = speed * 255 / 100 | ||||||
|  |         fan_target_sysfs_name = "pwm{}".format(self.fan_index+1) | ||||||
|  |         fan_target_sysfs_path = self.__search_file_by_name( | ||||||
|  |             FAN_PATH, fan_target_sysfs_name) | ||||||
|  |         return self.__write_txt_file(fan_target_sysfs_path, int(pwm)) | ||||||
|  |  | ||||||
|  |     def set_status_led(self, color): | ||||||
|  |         """ | ||||||
|  |         Sets the state of the fan module status LED | ||||||
|  |         Args: | ||||||
|  |             color: A string representing the color with which to set the | ||||||
|  |                    fan module status LED | ||||||
|  |         Returns: | ||||||
|  |             bool: always True | ||||||
|  |         """ | ||||||
|  |         return True | ||||||
|  |  | ||||||
|  |     def get_name(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the name of the device | ||||||
|  |             Returns: | ||||||
|  |             string: The name of the device | ||||||
|  |         """ | ||||||
|  |         fan_name = FAN_NAME_LIST[self.fan_index] | ||||||
|  |  | ||||||
|  |         return fan_name | ||||||
|  |  | ||||||
|  |     def get_presence(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the presence of the FAN | ||||||
|  |         Returns: | ||||||
|  |             bool: always True | ||||||
|  |         """ | ||||||
|  |  | ||||||
|  |         return True | ||||||
|  |  | ||||||
|  |     def get_status(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the status of the FAN | ||||||
|  |         Returns: | ||||||
|  |             bool: always True | ||||||
|  |         """ | ||||||
|  |         return True | ||||||
| @@ -0,0 +1,36 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
|  | ######################################################################## | ||||||
|  | # Centec E530 48t4x-p | ||||||
|  | # | ||||||
|  | # Module contains an implementation of SONiC Platform Base API and | ||||||
|  | # provides the Fan-Drawers' information available in the platform. | ||||||
|  | # | ||||||
|  | ######################################################################## | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_platform_base.fan_drawer_base import FanDrawerBase | ||||||
|  |     from .fan import Fan | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError(str(e) + "- required module not found") | ||||||
|  |  | ||||||
|  | CENTEC_FANS_PER_FANTRAY = 3 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class FanDrawer(FanDrawerBase): | ||||||
|  |     """Centec E530 48t4x-p Platform-specific Fan class""" | ||||||
|  |  | ||||||
|  |     def __init__(self, fantray_index): | ||||||
|  |  | ||||||
|  |         FanDrawerBase.__init__(self) | ||||||
|  |         self.fantrayindex = fantray_index | ||||||
|  |         for i in range(CENTEC_FANS_PER_FANTRAY): | ||||||
|  |             self._fan_list.append(Fan(fantray_index, i)) | ||||||
|  |  | ||||||
|  |     def get_name(self): | ||||||
|  |         """ | ||||||
|  |         Retrieves the fan drawer name | ||||||
|  |         Returns: | ||||||
|  |             string: The name of the device | ||||||
|  |         """ | ||||||
|  |         return "FanTray{}".format(self.fantrayindex) | ||||||
| @@ -0,0 +1,21 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  | # | ||||||
|  | # Name: platform.py, version: 1.0 | ||||||
|  | # | ||||||
|  | # Description: Module contains the definitions of SONiC platform APIs for Centec E530-48T4X-P | ||||||
|  | # | ||||||
|  |  | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_platform_base.platform_base import PlatformBase | ||||||
|  |     from sonic_platform.chassis import Chassis | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError(str(e) + "- required module not found") | ||||||
|  |   | ||||||
|  |   | ||||||
|  | class Platform(PlatformBase): | ||||||
|  |  | ||||||
|  |     def __init__(self): | ||||||
|  |         PlatformBase.__init__(self) | ||||||
|  |         self._chassis = Chassis() | ||||||
|  |  | ||||||
| @@ -0,0 +1,45 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
|  | from __future__ import print_function | ||||||
|  |  | ||||||
|  | import imp | ||||||
|  | import os | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from sonic_platform_base.psu_base import PsuBase | ||||||
|  |     from sonic_py_common import device_info | ||||||
|  | except ImportError as e: | ||||||
|  |     raise ImportError("%s - required module not found" % e) | ||||||
|  |  | ||||||
|  | USR_SHARE_SONIC_PATH = "/usr/share/sonic" | ||||||
|  | HOST_DEVICE_PATH = USR_SHARE_SONIC_PATH + "/device" | ||||||
|  | CONTAINER_PLATFORM_PATH = USR_SHARE_SONIC_PATH + "/platform" | ||||||
|  |  | ||||||
|  | class Psu(PsuBase): | ||||||
|  |     """Centec Platform-specific PSU class""" | ||||||
|  |  | ||||||
|  |     def __init__(self, index): | ||||||
|  |         self._index = index | ||||||
|  |         self._fan_list = [] | ||||||
|  |          | ||||||
|  |         if os.path.isdir(CONTAINER_PLATFORM_PATH): | ||||||
|  |             platform_path = CONTAINER_PLATFORM_PATH | ||||||
|  |         else: | ||||||
|  |             platform = device_info.get_platform() | ||||||
|  |             if platform is None: | ||||||
|  |                 return | ||||||
|  |             platform_path = os.path.join(HOST_DEVICE_PATH, platform) | ||||||
|  |  | ||||||
|  |         module_file = "/".join([platform_path, "plugins", "psuutil.py"]) | ||||||
|  |         module = imp.load_source("psuutil", module_file) | ||||||
|  |         psu_util_class = getattr(module, "PsuUtil") | ||||||
|  |         self._psuutil = psu_util_class() | ||||||
|  |  | ||||||
|  |     def _get_psuutil(self): | ||||||
|  |         return self._psuutil | ||||||
|  |  | ||||||
|  |     def get_presence(self): | ||||||
|  |         return self._get_psuutil().get_psu_presence(self._index) | ||||||
|  |  | ||||||
|  |     def get_powergood_status(self): | ||||||
|  |         return self._get_psuutil().get_psu_status(self._index) | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user
	 guxianghong
					guxianghong